-
Notifications
You must be signed in to change notification settings - Fork 2
/
Nanoshield_MRF24J40.cpp
318 lines (274 loc) · 9.89 KB
/
Nanoshield_MRF24J40.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
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/**
* This is the library to use the MRF24J40 Nanoshield.
*
* This library is based on the [Mrf24j40-arduino-library](https://github.com/karlp/Mrf24j40-arduino-library) from Karl Palsson.
*
* Original work Copyright (c) 2012, Karl Palsson ([email protected])
* Modified work Copyright (c) 2014 Circuitar
* All rights reserved.
*
* This software is released under a BSD license. See the attached LICENSE file for details.
*/
#include "Nanoshield_MRF24J40.h"
static uint8_t rx_buf[127];
// 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.
static boolean bufPHY = false; // flag to buffer all bytes in PHY Payload, or not
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 for Nanoshield_Mrf24j40 Object.
*/
Nanoshield_MRF24J40::Nanoshield_MRF24J40() {
_pin_cs = A3;
pinMode(_pin_cs, OUTPUT);
SPI.setBitOrder(MSBFIRST) ;
SPI.setDataMode(SPI_MODE0);
SPI.begin();
}
byte Nanoshield_MRF24J40::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 Nanoshield_MRF24J40::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 Nanoshield_MRF24J40::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 Nanoshield_MRF24J40::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 Nanoshield_MRF24J40::get_pan(void) {
byte panh = read_short(MRF_PANIDH);
return panh << 8 | read_short(MRF_PANIDL);
}
void Nanoshield_MRF24J40::set_pan(word panid) {
write_short(MRF_PANIDH, panid >> 8);
write_short(MRF_PANIDL, panid & 0xff);
}
void Nanoshield_MRF24J40::address16_write(word address16) {
write_short(MRF_SADRH, address16 >> 8);
write_short(MRF_SADRL, address16 & 0xff);
}
word Nanoshield_MRF24J40::address16_read(void) {
byte a16h = read_short(MRF_SADRH);
return a16h << 8 | read_short(MRF_SADRL);
}
/**
* Simple send 16, with acks, not much of anything.. assumes src16 and local pan only.
* @param data
*/
void Nanoshield_MRF24J40::send16(word dest16, char * data) {
byte len = strlen(data); // get the length of the char* array
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
write_long(i++, 0b01000001); // first byte of Frame Control (no ACK)
// 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));
write_short(MRF_TXNCON, (1<<MRF_TXNTRIG)); // (no ACK)
}
void Nanoshield_MRF24J40::set_interrupts(void) {
// interrupts for rx and tx normal complete
write_short(MRF_INTCON, 0b11110110);
}
/** use the 802.15.4 channel numbers..
*/
void Nanoshield_MRF24J40::set_channel(byte channel) {
write_long(MRF_RFCON0, (((channel - 11) << 4) | 0x03));
}
void Nanoshield_MRF24J40::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.
write_short(MRF_TRISGPIO, 0x08); // – Set GPIO3 to high to enable PA regulator in Nanoshield_Mrf24j4040MC
write_short(MRF_GPIO, 0x08);
write_long(MRF_TESTMODE, 0x0F); // – Enable PA/LNA control
// 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(15);
// 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 Nanoshield_MRF24J40::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 all bytes in PHY Payload
if(bufPHY){
int rb_ptr = 0;
for (int i = 0; i < frame_length; i++) { // from 0x301 to (0x301 + frame_length -1)
rx_buf[rb_ptr++] = read_long(0x301 + i);
}
}
// 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);
}
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 Nanoshield_MRF24J40::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 Nanoshield_MRF24J40::set_promiscuous(boolean enabled) {
if (enabled) {
write_short(MRF_RXMCR, 0x01);
} else {
write_short(MRF_RXMCR, 0x00);
}
}
rx_info_t * Nanoshield_MRF24J40::get_rxinfo(void) {
return &rx_info;
}
tx_info_t * Nanoshield_MRF24J40::get_txinfo(void) {
return &tx_info;
}
uint8_t * Nanoshield_MRF24J40::get_rxbuf(void) {
return rx_buf;
}
int Nanoshield_MRF24J40::rx_datalength(void) {
return rx_info.frame_length - bytes_nodata;
}
void Nanoshield_MRF24J40::set_ignoreBytes(int ib) {
// some modules behaviour
ignoreBytes = ib;
}
/**
* Set bufPHY flag to buffer all bytes in PHY Payload, or not
*/
void Nanoshield_MRF24J40::set_bufferPHY(boolean bp) {
bufPHY = bp;
}
boolean Nanoshield_MRF24J40::get_bufferPHY(void) {
return bufPHY;
}
/**
* Set PA/LNA external control
*/
void Nanoshield_MRF24J40::set_palna(boolean enabled) {
if (enabled) {
write_long(MRF_TESTMODE, 0x07); // Enable PA/LNA on Nanoshield_Mrf24j4040MB module.
}else{
write_long(MRF_TESTMODE, 0x00); // Disable PA/LNA on Nanoshield_Mrf24j4040MB module.
}
}
void Nanoshield_MRF24J40::rx_flush(void) {
write_short(MRF_RXFLUSH, 0x01);
}
void Nanoshield_MRF24J40::rx_disable(void) {
write_short(MRF_BBREG1, 0x04); // RXDECINV - disable receiver
}
void Nanoshield_MRF24J40::rx_enable(void) {
write_short(MRF_BBREG1, 0x00); // RXDECINV - enable receiver
}