-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMirf.cpp
549 lines (471 loc) · 15.4 KB
/
Mirf.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
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
#include <string.h>
#include <stdlib.h>
#include "Mirf_nRF24L01.h"
#include "Mirf.h"
Nrf24l Mirf = Nrf24l();
//should be run within some timered loop (really often - 10ms)
void Nrf24l::handleRxLoop(void)
{
Timer++; //every time we must increment timer
uint8_t innerCounter = 0;
#ifdef _DEBUG_
//UDR0 = 46; //DEBUG
#endif
//if (inPacketReady == MAX_RX_PACKET_QUEUE) return;
//if there is full queue, return a wait for next turn
while ( dataReady() ) //while something in rx buffer
{
getData( (uint8_t*) &pendingPacket);
if ( (pendingPacket.rxAddr == devAddr) || (pendingPacket.rxAddr == MULTICAST_ADDR) )
{ //is the packet for this device? or multicast
if ( ((PACKET_TYPE)pendingPacket.type == ACK) || ((PACKET_TYPE)pendingPacket.type == ACK_RESP) )
{
//TODO: handle ACK_RESP packet payload.. propably just give it to app as it is
#ifdef _DEBUG_
UDR0 = 60; //DEBUG <
#endif
if ( ((SENDING_STATUS)sendingStatus == WAIT_ACK) && (txQueue[txPosBeg].counter == pendingPacket.counter) ) //ack for sent packet received
{
sendingStatus = 0;
sendResult = 0;
removePacketfromTxQueue();
//remove sent packet from queue
//and add confirmation to confirmed queue
//addConfirmedPacket(pendingPacket.counter);
}
}
else if (pendingPacket.type == PING)
{
createAck((mirfPacket*)&pendingPacket);
}
else
{ //other packets are saved to queue and app has to hadle them
if (inPacketReady != MAX_RX_PACKET_QUEUE) //if queue is not full
{
//last_addr_in = pendingPacket.txAddr;
//last_packetCounter_in = pendingPacket.counter;
memcpy((void*)&rxQueue[rxPosEnd], (mirfPacket*)&pendingPacket, NRF_PAYLOAD_SIZE);
inPacketReady++;
rxPosEnd++;
if (rxPosEnd == MAX_RX_PACKET_QUEUE) rxPosEnd = 0; //queue counted from 0, so on the max number we are already out of array bounds
createAck((mirfPacket*)&pendingPacket);
}
}
}
//we have to have some theoretical limit staying in this function
//because if there were too much incoming packets all the time,
//then this function would never end
innerCounter++;
if (innerCounter == 5) break;
}
}
void Nrf24l::handleTxLoop(void) //probably should be run from main program loop, because can be time consuming in wait for finished tx
{
uint8_t *pPaket;
uint8_t whatToSend = 0; //0 = nothing, 1 = ack, 2 = user packet
//if there is some ack waiting
if (1) //(Timer == TimerNewAttempt)
{
if ( (ackQueueSize > 0) )
{
pPaket = (uint8_t *)&ackQueue[ackPosBeg];
whatToSend = 1;
#ifdef _DEBUG_
//UDR0 = 61; //DEBUG =
#endif
}
else
{
if ( (sendingStatus == IN_FIFO) || (sendingStatus == WAIT_FREE_AIR) ) //new packet in fifo waiting to be sent
{
pPaket = (uint8_t *)&txQueue[txPosBeg];
whatToSend = 2;
#ifdef _DEBUG_
//UDR0 = 62; //DEBUG >
#endif
}
}
}
//this is for sending user packet
if ( whatToSend > 0 ) //new packet in fifo waiting to be sent
{
flushTx();
//write user packet to fifo
nrfSpiWrite(W_TX_PAYLOAD, pPaket, false, NRF_PAYLOAD_SIZE);
if ( 1 ) //getCarrier()==0 ) //no carrier detected (free air/free to send)
{
powerUpTx(); // Set to transmitter mode , Power up
ceHi(); // Start transmission
if ( whatToSend == 1) //remove packet if it was ack
{
removePacketfromAckQueue();
#ifdef _DEBUG_
UDR0 = 61; //DEBUG =
#endif
}
else //if it was not ack packet, then it was for sure user packet
//if ( (whatToSend >> 1) == 1) //if there was also user packet
{
sendingStatus = WAIT_ACK;
ackTimeoutTimer = Timer + MAX_ACK_WAIT_TIME;
}
while ( isSending() ) NOP_ASM //wait for end of transfer and immediately start RX mode
//powerUpRx(); //when 2 or more packets, we have to wait until fifo is empty (while isSending() )
}
/*
//NOT USED NOW (no carrier detection during sending)
else //there is someone already transmitting, wait random time to next try
{
TimerNewAttempt = Timer + 1 + (Timer & 7); //little bit randomize (increment also with lowest 2 bits of timer)
#ifdef _DEBUG_
UDR0 = 46; //DEBUG .
#endif
if (whatToSend == 2)
{
txAttempt++;
sendingStatus = WAIT_FREE_AIR;
}
}
*/
}
/*
//NOT USED NOW (no carrier detection during sending)
//only finite number of attempts to send (when air is full)
if ((txAttempt == MAX_TX_ATTEMPTS) && (sendingStatus == WAIT_FREE_AIR) ) {
sendingStatus = 0; //must be set to 0 to be able to send another packets
sendResult = MAX_ATTEMPTS;
removePacketfromTxQueue();
#ifdef _DEBUG_
UDR0 = 88; //DEBUG X
#endif
}
*/
//check if there was TIMEOUT in waiting for ACK
if ( (SENDING_STATUS)sendingStatus == WAIT_ACK) //check whether timeout waiting for ack occured
{
if (Timer == ackTimeoutTimer)
{
sendingStatus = 0; //must be set to 0 to be able to send another packets
sendResult = TIMEOUT;
removePacketfromTxQueue();
#ifdef _DEBUG_
UDR0 = 94; //DEBUG sipka nahoru
#endif
}
}
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void Nrf24l::readPacket(mirfPacket* paket)
{
if (inPacketReady) {
//we have to temporarily disable timer0 interrupt because no one else could be able to touch
//the packet queue until we are finished
cli();
memcpy(paket, (const void*)&rxQueue[rxPosBeg], NRF_PAYLOAD_SIZE);
inPacketReady--;
rxPosBeg++;
if (rxPosBeg == MAX_RX_PACKET_QUEUE) rxPosBeg = 0; //rxPos could wrap.. and we are going anti clockwise
sei();
}
}
uint8_t Nrf24l::sendPacket(mirfPacket* paket)
{
//another sending in progress, busy -> fail
if ( (sendingStatus > 0) )
{
return 0;
}
if (txQueueSize == MAX_TX_PACKET_QUEUE) return 0;
//set all parameters in packet
cli();
packetCounter++;
if (packetCounter == 0) packetCounter++; //counter cannot be 0
paket->counter = packetCounter;
paket->txAddr = devAddr;
memcpy((void*)&txQueue[txPosEnd], paket, NRF_PAYLOAD_SIZE);
txQueueSize++;
txPosEnd++;
if (txPosEnd == MAX_TX_PACKET_QUEUE) txPosEnd = 0; //queue counted from 0, so on the max number we are already out of array bounds
sendingStatus = 1; //set sign that there is sending packet pending
sendResult = 1;
txAttempt = 1;
sei();
return packetCounter;
}
void Nrf24l::createAck(mirfPacket* paket)
{
if (ackQueueSize == MAX_ACK_PACKET_QUEUE) return;
#ifdef _DEBUG_
//UDR0 = 35; //DEBUG #
#endif
ackQueue[ackPosEnd].txAddr = paket->rxAddr;
ackQueue[ackPosEnd].rxAddr = paket->txAddr;
ackQueue[ackPosEnd].counter = paket->counter;
ackQueue[ackPosEnd].type = ACK;
ackQueueSize++;
ackPosEnd++;
if (ackPosEnd == MAX_ACK_PACKET_QUEUE) ackPosEnd = 0; //queue counted from 0, so on the max number we are already out of array bounds
}
inline void Nrf24l::removePacketfromTxQueue(void)
{
txQueueSize--;
txPosBeg++;
if (txPosBeg == MAX_TX_PACKET_QUEUE) txPosBeg = 0; //rxPos could wrap.. and we are going anti clockwise
}
inline void Nrf24l::removePacketfromAckQueue(void)
{
ackQueueSize--;
ackPosBeg++;
if (ackPosBeg == MAX_ACK_PACKET_QUEUE) ackPosBeg = 0; //rxPos could wrap.. and we are going anti clockwise
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
Nrf24l::Nrf24l() {
//cePin = D9;
//csnPin = D10;
spi = &SPI;
baseConfig = _BV(EN_CRC) & ~_BV(CRCO);
}
void Nrf24l::init()
// Initializes pins to communicate with the MiRF module
// Should be called in the early initializing phase at startup.
{
//pinMode(cePin, OUTPUT);
//pinMode(csnPin, OUTPUT);
DDRB |= 0b00000110;
ceLow();
csnHi();
packetCounter = 0;
channel = DEFAULT_RF_CHANNEL;
devAddr = 0;
// Initialize spi module
spi->begin();
}
void Nrf24l::config()
// Sets the important registers in the MiRF module and powers the module
// in receiving mode
// NB: channel and payload must be set now.
{
configRegister(EN_AA, 0); //disable auto ack
configRegister(EN_RXADDR, (1 << ERX_P0) ); //only pipe 0 receive enabled
configRegister(SETUP_AW, mirf_ADDR_LEN - 2); //hw address width - mirf_ADDR_LEN bytes
//here -2 is for normalising the value (1=3 bytes, 2=4bytes, 3=5bytes; so
configRegister(SETUP_RETR, 0); //auto retransmission off
setRfChannel(DEFAULT_RF_CHANNEL); // Set RF channel
configRegister(RF_SETUP, 0b00100111 ); //250kbit, 0dbm, max gain
configRegister(FEATURE, 0); //dynamic length disabled(1<<EN_DPL) )
configRegister(DYNPD, 0);
// Set length of incoming payload
configRegister(RX_PW_P0, NRF_PAYLOAD_SIZE);
configRegister(RX_PW_P1, NRF_PAYLOAD_SIZE);
setADDR();
// Start receiver
flushRx();
powerUpRx();
}
inline void Nrf24l::setRfChannel(uint8_t new_channel)
{
channel = new_channel;
configRegister(RF_CH, new_channel); // Set RF channel
}
inline uint8_t Nrf24l::getRfChannel(void)
{
return channel;
}
void Nrf24l::setDevAddr(ADDR_TYPE addr)
// sets the unique node address
// is used during decoding of incoming packets (only packets for this address are handled)
// when transmitting packet, this address is used as SENDER adress
{
devAddr = addr;
}
void Nrf24l::setADDR(void)
//sets address for RX and TX in NRF module (both the same)
{
ceLow();
writeRegister(RX_ADDR_P0, (uint8_t*)mirf_ADDR, mirf_ADDR_LEN);
writeRegister(TX_ADDR, (uint8_t*)mirf_ADDR, mirf_ADDR_LEN);
ceHi();
}
bool Nrf24l::dataReady()
// Checks if data is available for reading
{
// See note in getData() function - just checking RX_DR isn't good enough
uint8_t status = getStatus();
// We can short circuit on RX_DR, but if it's not set, we still need
// to check the FIFO for any pending packets
if (status & _BV(RX_DR))
return 1;
return !rxFifoEmpty();
}
bool Nrf24l::rxFifoEmpty(){
uint8_t fifoStatus;
nrfSpiWrite2((R_REGISTER | (REGISTER_MASK & FIFO_STATUS)), &fifoStatus, true, 1);
//readRegister(FIFO_STATUS, &fifoStatus, sizeof(fifoStatus));
return (fifoStatus & _BV(RX_EMPTY));
}
void Nrf24l::getData(uint8_t * data)
// Reads payload bytes into data array
{
nrfSpiWrite2(R_RX_PAYLOAD, data, true, NRF_PAYLOAD_SIZE); // Read payload
// NVI: per product spec, p 67, note c:
// "The RX_DR IRQ is asserted by a new packet arrival event. The procedure
// for handling this interrupt should be: 1) read payload through SPI,
// 2) clear RX_DR IRQ, 3) read FIFO_STATUS to check if there are more
// payloads available in RX FIFO, 4) if there are more data in RX FIFO,
// repeat from step 1)."
// So if we're going to clear RX_DR here, we need to check the RX FIFO
// in the dataReady() function
configRegister(STATUS, _BV(RX_DR)); // Reset status register
}
void Nrf24l::configRegister(uint8_t reg, uint8_t value)
// Clocks only one byte into the given MiRF register
{
writeRegister(reg, &value, 1);
}
void Nrf24l::readRegister(uint8_t reg, uint8_t * value, uint8_t len)
// Reads an array of bytes from the given start position in the MiRF registers.
{
nrfSpiWrite2((R_REGISTER | (REGISTER_MASK & reg)), value, true, len);
//nrfSpiWrite(255, value, true, len);
}
void Nrf24l::writeRegister(uint8_t reg, uint8_t * value, uint8_t len)
// Writes an array of bytes into inte the MiRF registers.
{
nrfSpiWrite((W_REGISTER | (REGISTER_MASK & reg)), value, false, len);
}
/**
* isSending.
*
* Test if chip is still sending.
* When sending has finished return chip to listening.
*
*/
volatile bool Nrf24l::isSending() {
uint8_t status;
if(PTX){
nrfSpiWrite2((R_REGISTER | (REGISTER_MASK & FIFO_STATUS)), &status, true, 1);
/*
* if sending successful (TX_DS) or max retries exceded (MAX_RT).
*/
if( (status & (1 << TX_EMPTY)) ){
powerUpRx();
return false;
}
return true;
}
return false;
}
// volatile bool Nrf24l::isSending() {
// uint8_t status;
// if(PTX){
// status = getStatus();
//
// /*
// * if sending successful (TX_DS) or max retries exceded (MAX_RT).
// */
//
// if((status & ((1 << TX_DS) | (1 << MAX_RT)))){
// powerUpRx();
// return false;
// }
//
// return true;
// }
// return false;
// }
uint8_t Nrf24l::getCarrier(){
//returns true if carrier detected in RX mode
//used before sending packet to determine if air is clear
/* Initialize with NOP so we get the first byte read back. */
uint8_t rv = NOP_CMD;
nrfSpiWrite2((R_REGISTER | (REGISTER_MASK & CD)), &rv, true, 1);
//readRegister(CD, &rv, 1);
return (rv & 1);
}
uint8_t Nrf24l::getStatus(){
/* Initialize with NOP so we get the first byte read back. */
uint8_t rv = NOP_CMD;
nrfSpiWrite((R_REGISTER | (REGISTER_MASK & STATUS)), &rv, true, 1);
//readRegister(STATUS, &rv, 1);
return rv;
}
inline void Nrf24l::flushTx() {
nrfSpiWrite(FLUSH_TX);
//configRegister(STATUS, _BV(TX_DS));
}
void Nrf24l::powerUpRx() {
PTX = 0;
ceLow();
configRegister(CONFIG, baseConfig | _BV(PWR_UP) | _BV(PRIM_RX));
configRegister(STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT));
#ifdef _DEBUG_
UDR0 = 95; //DEBUG _
#endif
ceHi();
}
void Nrf24l::flushRx(){
nrfSpiWrite(FLUSH_RX);
}
void Nrf24l::powerUpTx() {
PTX = 1;
ceLow();
#ifdef _DEBUG_
UDR0 = 33; //DEBUG !
#endif
configRegister(CONFIG, baseConfig | (_BV(PWR_UP) & ~_BV(PRIM_RX)) );
}
void Nrf24l::nrfSpiWrite(uint8_t reg, uint8_t *data, bool readData, uint8_t len) {
csnLow();
spi->transfer(reg);
if (data) {
uint8_t i;
for(i = 0; i < len; ++i) {
uint8_t readValue = spi->transfer(data[i]);
if (readData) {
data[i] = readValue;
}
}
}
csnHi();
}
void Nrf24l::nrfSpiWrite2(uint8_t reg, uint8_t *data, bool readData, uint8_t len) {
csnLow();
spi->transfer(reg);
spi->transfer(255);
if (data) {
uint8_t i;
for(i = 0; i < len; ++i) {
uint8_t readValue = spi->transfer(data[i]);
if (readData) {
data[i] = readValue;
}
}
}
csnHi();
}
inline void Nrf24l::ceHi(){ //PB1
//digitalWrite(cePin,HIGH);
PORTB |= (1<<1);
}
inline void Nrf24l::ceLow(){
//digitalWrite(cePin,LOW);
PORTB &= (~(1<<1));
}
inline void Nrf24l::csnHi(){ //PB2
//digitalWrite(csnPin,HIGH);
PORTB |= (1<<2);
}
inline void Nrf24l::csnLow(){
//digitalWrite(csnPin,LOW);
PORTB &= (~(1<<2));
}
void Nrf24l::powerDown(){
ceLow();
configRegister(CONFIG, baseConfig);
flushRx();
flushTx();
}