forked from karlp/Mrf24j40-arduino-library
-
Notifications
You must be signed in to change notification settings - Fork 3
/
mrf24j.cpp
298 lines (249 loc) · 8.96 KB
/
mrf24j.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/**
* mrf24j.cpp, Karl Palsson, 2011, [email protected]
* modified bsd license / apache license
*/
#include "mrf24j.h"
// essential for obtaining the data frame only
// bytes_MHR = 2 Frame control + 1 sequence number + 2 panid + 2 shortAddr Destination + 2 shortAddr Source
static int bytes_MHR = 9;
static int bytes_FCS = 2; // FCS length = 2
static int bytes_nodata = bytes_MHR + bytes_FCS; // no_data bytes in PHY payload, header length + FCS
static int ignoreBytes = 0; // bytes to ignore, some modules behaviour.
volatile uint8_t flag_got_rx;
volatile uint8_t flag_got_tx;
static rx_info_t rx_info;
static tx_info_t tx_info;
/**
* Constructor MRF24J Object.
* @param pin_reset, @param pin_chip_select, @param pin_interrupt
*/
Mrf24j::Mrf24j(int pin_reset, int pin_chip_select, int pin_interrupt) {
_pin_reset = pin_reset;
_pin_cs = pin_chip_select;
_pin_int = pin_interrupt;
pinMode(_pin_reset, OUTPUT);
pinMode(_pin_cs, OUTPUT);
pinMode(_pin_int, INPUT);
SPI.setBitOrder(MSBFIRST) ;
SPI.setDataMode(SPI_MODE0);
SPI.begin();
}
void Mrf24j::reset(void) {
digitalWrite(_pin_reset, LOW);
delay(10); // just my gut
digitalWrite(_pin_reset, HIGH);
delay(20); // from manual
}
byte Mrf24j::read_short(byte address) {
digitalWrite(_pin_cs, LOW);
// 0 top for short addressing, 0 bottom for read
SPI.transfer(address<<1 & 0b01111110);
byte ret = SPI.transfer(0x00);
digitalWrite(_pin_cs, HIGH);
return ret;
}
byte Mrf24j::read_long(word address) {
digitalWrite(_pin_cs, LOW);
byte ahigh = address >> 3;
byte alow = address << 5;
SPI.transfer(0x80 | ahigh); // high bit for long
SPI.transfer(alow);
byte ret = SPI.transfer(0);
digitalWrite(_pin_cs, HIGH);
return ret;
}
void Mrf24j::write_short(byte address, byte data) {
digitalWrite(_pin_cs, LOW);
// 0 for top short address, 1 bottom for write
SPI.transfer((address<<1 & 0b01111110) | 0x01);
SPI.transfer(data);
digitalWrite(_pin_cs, HIGH);
}
void Mrf24j::write_long(word address, byte data) {
digitalWrite(_pin_cs, LOW);
byte ahigh = address >> 3;
byte alow = address << 5;
SPI.transfer(0x80 | ahigh); // high bit for long
SPI.transfer(alow | 0x10); // last bit for write
SPI.transfer(data);
digitalWrite(_pin_cs, HIGH);
}
word Mrf24j::get_pan(void) {
byte panh = read_short(MRF_PANIDH);
return panh << 8 | read_short(MRF_PANIDL);
}
void Mrf24j::set_pan(word panid) {
write_short(MRF_PANIDH, panid >> 8);
write_short(MRF_PANIDL, panid & 0xff);
}
void Mrf24j::address16_write(word address16) {
write_short(MRF_SADRH, address16 >> 8);
write_short(MRF_SADRL, address16 & 0xff);
}
word Mrf24j::address16_read(void) {
byte a16h = read_short(MRF_SADRH);
return a16h << 8 | read_short(MRF_SADRL);
}
void Mrf24j::send16(word dest16, char const * data, byte const len) {
int i = 0;
write_long(i++, bytes_MHR); // header length
// +ignoreBytes is because some module seems to ignore 2 bytes after the header?!.
// default: ignoreBytes = 0;
write_long(i++, bytes_MHR+ignoreBytes+len);
// 0 | pan compression | ack | no security | no data pending | data frame[3 bits]
write_long(i++, 0b01100001); // first byte of Frame Control
// 16 bit source, 802.15.4 (2003), 16 bit dest,
write_long(i++, 0b10001000); // second byte of frame control
write_long(i++, 1); // sequence number 1
word panid = get_pan();
write_long(i++, panid & 0xff); // dest panid
write_long(i++, panid >> 8);
write_long(i++, dest16 & 0xff); // dest16 low
write_long(i++, dest16 >> 8); // dest16 high
word src16 = address16_read();
write_long(i++, src16 & 0xff); // src16 low
write_long(i++, src16 >> 8); // src16 high
// All testing seems to indicate that the next two bytes are ignored.
//2 bytes on FCS appended by TXMAC
i+=ignoreBytes;
for (int q = 0; q < len; q++) {
write_long(i++, data[q]);
}
// ack on, and go!
write_short(MRF_TXNCON, (1<<MRF_TXNACKREQ | 1<<MRF_TXNTRIG));
}
void Mrf24j::set_interrupts(void) {
// interrupts for rx and tx normal complete
write_short(MRF_INTCON, 0b11110110);
}
/** use the 802.15.4 channel numbers..
*/
void Mrf24j::set_channel(byte channel) {
write_long(MRF_RFCON0, (((channel - 11) << 4) | 0x03));
}
void Mrf24j::init(void) {
/*
// Seems a bit ridiculous when I use reset pin anyway
write_short(MRF_SOFTRST, 0x7); // from manual
while (read_short(MRF_SOFTRST) & 0x7 != 0) {
; // wait for soft reset to finish
}
*/
write_short(MRF_PACON2, 0x98); // – Initialize FIFOEN = 1 and TXONTS = 0x6.
write_short(MRF_TXSTBL, 0x95); // – Initialize RFSTBL = 0x9.
write_long(MRF_RFCON0, 0x03); // – Initialize RFOPT = 0x03.
write_long(MRF_RFCON1, 0x01); // – Initialize VCOOPT = 0x02.
write_long(MRF_RFCON2, 0x80); // – Enable PLL (PLLEN = 1).
write_long(MRF_RFCON6, 0x90); // – Initialize TXFIL = 1 and 20MRECVR = 1.
write_long(MRF_RFCON7, 0x80); // – Initialize SLPCLKSEL = 0x2 (100 kHz Internal oscillator).
write_long(MRF_RFCON8, 0x10); // – Initialize RFVCO = 1.
write_long(MRF_SLPCON1, 0x21); // – Initialize CLKOUTEN = 1 and SLPCLKDIV = 0x01.
// Configuration for nonbeacon-enabled devices (see Section 3.8 “Beacon-Enabled and
// Nonbeacon-Enabled Networks”):
write_short(MRF_BBREG2, 0x80); // Set CCA mode to ED
write_short(MRF_CCAEDTH, 0x60); // – Set CCA ED threshold.
write_short(MRF_BBREG6, 0x40); // – Set appended RSSI value to RXFIFO.
set_interrupts();
set_channel(12);
// max power is by default.. just leave it...
// Set transmitter power - See “REGISTER 2-62: RF CONTROL 3 REGISTER (ADDRESS: 0x203)”.
write_short(MRF_RFCTL, 0x04); // – Reset RF state machine.
write_short(MRF_RFCTL, 0x00); // part 2
delay(1); // delay at least 192usec
}
/**
* Call this from within an interrupt handler connected to the MRFs output
* interrupt pin. It handles reading in any data from the module, and letting it
* continue working.
* Only the most recent data is ever kept.
*/
void Mrf24j::interrupt_handler(void) {
uint8_t last_interrupt = read_short(MRF_INTSTAT);
if (last_interrupt & MRF_I_RXIF) {
flag_got_rx++;
// read out the packet data...
noInterrupts();
rx_disable();
// read start of rxfifo for, has 2 bytes more added by FCS. frame_length = m + n + 2
uint8_t frame_length = read_long(0x300);
// buffer data bytes
int rd_ptr = 0;
// from (0x301 + bytes_MHR) to (0x301 + frame_length - bytes_nodata - 1)
for (int i = 0; i < rx_datalength(); i++) {
rx_info.rx_data[rd_ptr++] = read_long(0x301 + bytes_MHR + i);
}
byte src_l = read_long(0x301 + bytes_MHR - 2); // low
rx_info.src_addr16 = (read_long(0x301 + bytes_MHR - 1) << 8) | src_l; // hi
rx_info.frame_length = frame_length;
// same as datasheet 0x301 + (m + n + 2) <-- frame_length
rx_info.lqi = read_long(0x301 + frame_length);
// same as datasheet 0x301 + (m + n + 3) <-- frame_length + 1
rx_info.rssi = read_long(0x301 + frame_length + 1);
rx_enable();
interrupts();
}
if (last_interrupt & MRF_I_TXNIF) {
flag_got_tx++;
uint8_t tmp = read_short(MRF_TXSTAT);
// 1 means it failed, we want 1 to mean it worked.
tx_info.tx_ok = !(tmp & ~(1 << TXNSTAT));
tx_info.retries = tmp >> 6;
tx_info.channel_busy = (tmp & (1 << CCAFAIL));
}
}
/**
* Call this function periodically, it will invoke your nominated handlers
*/
void Mrf24j::check_flags(void (*rx_handler)(void), void (*tx_handler)(void)){
// TODO - we could check whether the flags are > 1 here, indicating data was lost?
if (flag_got_rx) {
flag_got_rx = 0;
rx_handler();
}
if (flag_got_tx) {
flag_got_tx = 0;
tx_handler();
}
}
/**
* Set RX mode to promiscuous, or normal
*/
void Mrf24j::set_promiscuous(boolean enabled) {
if (enabled) {
write_short(MRF_RXMCR, 0x01);
} else {
write_short(MRF_RXMCR, 0x00);
}
}
rx_info_t * Mrf24j::get_rxinfo(void) {
return &rx_info;
}
tx_info_t * Mrf24j::get_txinfo(void) {
return &tx_info;
}
int Mrf24j::rx_datalength(void) {
return rx_info.frame_length - bytes_nodata;
}
void Mrf24j::set_ignoreBytes(int ib) {
// some modules behaviour
ignoreBytes = ib;
}
/**
* Set PA/LNA external control
*/
void Mrf24j::set_palna(boolean enabled) {
if (enabled) {
write_long(MRF_TESTMODE, 0x07); // Enable PA/LNA on MRF24J40MB module.
}else{
write_long(MRF_TESTMODE, 0x00); // Disable PA/LNA on MRF24J40MB module.
}
}
void Mrf24j::rx_flush(void) {
write_short(MRF_RXFLUSH, 0x01);
}
void Mrf24j::rx_disable(void) {
write_short(MRF_BBREG1, 0x04); // RXDECINV - disable receiver
}
void Mrf24j::rx_enable(void) {
write_short(MRF_BBREG1, 0x00); // RXDECINV - enable receiver
}