1 /*
2  * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
3  * Copyright (c) 2014 Intel Corporation.
4  * BLE Beaconing based on http://dmitry.gr/index.php?r=05.Projects&proj=11.%20Bluetooth%20LE%20fakery
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include <iostream>
27 #include <unistd.h>
28 #include <string>
29 #include <stdexcept>
30 #include <stdlib.h>
31 
32 #include "nrf24l01.h"
33 
34 using namespace upm;
35 
36 
NRF24L01(uint8_t cs,uint8_t ce)37 NRF24L01::NRF24L01 (uint8_t cs, uint8_t ce)
38                             : m_csnPinCtx(cs), m_cePinCtx(ce), m_spi(0)
39 {
40     init (cs, ce);
41 }
42 
43 void
init(uint8_t chip_select,uint8_t chip_enable)44 NRF24L01::init (uint8_t chip_select, uint8_t chip_enable) {
45     mraa::Result error = mraa::SUCCESS;
46 
47     m_csn       = chip_select;
48     m_ce        = chip_enable;
49     m_channel   = 99;
50 
51     error = m_csnPinCtx.dir(mraa::DIR_OUT);
52     if (error != mraa::SUCCESS) {
53         mraa::printError (error);
54     }
55 
56     error = m_cePinCtx.dir(mraa::DIR_OUT);
57     if (error != mraa::SUCCESS) {
58         mraa::printError (error);
59     }
60 
61     ceLow();
62     csOff ();
63 }
64 
65 void
configure()66 NRF24L01::configure () {
67     /* Set RF channel */
68     setRegister (RF_CH, m_channel);
69 
70     /* Set length of incoming payload */
71     setRegister (RX_PW_P0, m_payload);
72 
73     /* Set length of incoming payload for broadcast */
74     setRegister (RX_PW_P1, m_payload);
75 
76     /* Start receiver */
77     rxPowerUp ();
78     rxFlushBuffer ();
79 }
80 
81 void
send(uint8_t * value)82 NRF24L01::send (uint8_t * value) {
83     uint8_t status;
84     status = getStatus();
85 
86     while (m_ptx) {
87         status = getStatus();
88 
89         if((status & ((1 << TX_DS)  | (1 << MAX_RT)))){
90             m_ptx = 0;
91             break;
92         }
93     } // Wait until last paket is send
94 
95     ceLow ();
96     txPowerUp (); // Set to transmitter mode , Power up
97     txFlushBuffer ();
98 
99     csOn ();
100     m_spi.writeByte(W_TX_PAYLOAD); // Write cmd to write payload
101     writeBytes (value, NULL, m_payload); // Write payload
102     csOff ();
103     ceHigh(); // Start transmission
104 
105     while (dataSending ()) { }
106 
107     usleep (10000);
108 }
109 
110 void
send()111 NRF24L01::send () {
112     send (m_txBuffer);
113 }
114 
115 void
setSourceAddress(uint8_t * addr)116 NRF24L01::setSourceAddress (uint8_t * addr) {
117     ceLow ();
118     writeRegister (RX_ADDR_P0, addr, ADDR_LEN);
119     ceHigh ();
120 }
121 
122 void
setDestinationAddress(uint8_t * addr)123 NRF24L01::setDestinationAddress (uint8_t * addr) {
124     writeRegister (TX_ADDR, addr, ADDR_LEN);
125 }
126 
127 void
setBroadcastAddress(uint8_t * addr)128 NRF24L01::setBroadcastAddress (uint8_t * addr) {
129     writeRegister (RX_ADDR_P1, addr, ADDR_LEN);
130 }
131 
132 void
setPayload(uint8_t payload)133 NRF24L01::setPayload (uint8_t payload) {
134     m_payload = payload;
135 }
136 
137 #ifdef JAVACALLBACK
138 void
setDataReceivedHandler(Callback * call_obj)139 NRF24L01::setDataReceivedHandler (Callback *call_obj)
140 {
141     callback_obj = call_obj;
142     dataReceivedHandler = &generic_callback;
143 }
144 #else
145 void
setDataReceivedHandler(funcPtrVoidVoid handler)146 NRF24L01::setDataReceivedHandler (funcPtrVoidVoid handler)
147 {
148     dataReceivedHandler = handler;
149 }
150 #endif
151 
152 bool
dataReady()153 NRF24L01::dataReady () {
154     /* See note in getData() function - just checking RX_DR isn't good enough */
155     uint8_t status = getStatus();
156     /* We can short circuit on RX_DR, but if it's not set, we still need
157      * to check the FIFO for any pending packets */
158     if ( status & (1 << RX_DR) ) {
159         return 1;
160     }
161 
162     return !rxFifoEmpty();
163 }
164 
165 bool
dataSending()166 NRF24L01::dataSending () {
167     uint8_t status;
168     if(m_ptx)   { // Sending mode.
169         status = getStatus();
170         /* if sending successful (TX_DS) or max retries exceded (MAX_RT). */
171         if((status & ((1 << TX_DS)  | (1 << MAX_RT)))){
172             rxPowerUp ();
173             return false;
174         }
175         return true;
176     }
177     return false;
178 }
179 
180 void
getData(uint8_t * data)181 NRF24L01::getData (uint8_t * data)  {
182     csOn ();
183     /* Send cmd to read rx payload */
184     m_spi.writeByte(R_RX_PAYLOAD);
185     /* Read payload */
186     writeBytes (data, data, m_payload);
187     csOff ();
188     /* NVI: per product spec, p 67, note c:
189      * "The RX_DR IRQ is asserted by a new packet arrival event. The procedure
190      * for handling this interrupt should be: 1) read payload through SPI,
191      * 2) clear RX_DR IRQ, 3) read FIFO_STATUS to check if there are more
192      * payloads available in RX FIFO, 4) if there are more data in RX FIFO,
193      * repeat from step 1)."
194      * So if we're going to clear RX_DR here, we need to check the RX FIFO
195      * in the dataReady() function */
196     /* Reset status register */
197     setRegister (STATUS, (1<<RX_DR));
198 }
199 
200 uint8_t
getStatus()201 NRF24L01::getStatus() {
202     return getRegister (STATUS);
203 }
204 
205 bool
rxFifoEmpty()206 NRF24L01::rxFifoEmpty () {
207     uint8_t fifoStatus = getRegister (FIFO_STATUS);
208     return (fifoStatus & (1 << RX_EMPTY));
209 }
210 
211 void
rxPowerUp()212 NRF24L01::rxPowerUp () {
213     m_ptx = 0;
214     ceLow ();
215     setRegister (CONFIG, _CONFIG | ( (1 << PWR_UP) | (1 << PRIM_RX) ));
216     ceHigh ();
217     setRegister (STATUS, (1 << TX_DS) | (1 << MAX_RT));
218 }
219 
220 void
rxFlushBuffer()221 NRF24L01::rxFlushBuffer () {
222     sendCommand (FLUSH_RX);
223 }
224 
225 void
txPowerUp()226 NRF24L01::txPowerUp () {
227     m_ptx = 1;
228     setRegister (CONFIG, _CONFIG | ( (1 << PWR_UP) | (0 << PRIM_RX) ));
229 }
230 
231 void
powerDown()232 NRF24L01::powerDown(){
233     ceLow ();
234     setRegister (CONFIG, _CONFIG);
235 }
236 
237 void
setChannel(uint8_t channel)238 NRF24L01::setChannel (uint8_t channel) {
239     m_channel = channel;
240     setRegister (RF_CH, channel);
241 }
242 
243 void
setPower(power_t power)244 NRF24L01::setPower (power_t power) {
245     uint8_t setupRegisterData = 0;
246 
247     switch (power) {
248         case NRF_0DBM:
249             m_power = 3;
250         break;
251         case NRF_6DBM:
252             m_power = 2;
253         break;
254         case NRF_12DBM:
255             m_power = 1;
256         break;
257         case NRF_18DBM:
258             m_power = 0;
259         break;
260     }
261 
262     setupRegisterData = getRegister (RF_SETUP); // Read current value.
263     setupRegisterData &= 0xFC; // Erase the old value;
264     setupRegisterData |= (m_power & 0x3);
265     setRegister (RF_SETUP, setupRegisterData); // Write the new value.
266 }
267 
268 uint8_t
setSpeedRate(speed_rate_t rate)269 NRF24L01::setSpeedRate (speed_rate_t rate) {
270     uint8_t setupRegisterData = 0;
271 
272     setupRegisterData = getRegister (RF_SETUP); // Read current value.
273     setupRegisterData &= ~((1 << RF_DR_LOW) | (1 << RF_DR_HIGH));
274 
275     switch (rate) {
276         case NRF_250KBPS:
277             setupRegisterData |= (1 << RF_DR_LOW) ;
278         break;
279         case NRF_1MBPS:
280         break;
281         case NRF_2MBPS:
282             setupRegisterData |= (1 << RF_DR_HIGH);
283         break;
284     }
285 
286     setRegister (RF_SETUP, setupRegisterData); // Write the new value.
287 
288     if (setupRegisterData == getRegister (RF_SETUP)) {
289         return 0x0;
290     }
291 
292     return 0x1;
293 }
294 
295 mraa::Result
ceHigh()296 NRF24L01::ceHigh () {
297     return m_cePinCtx.write(HIGH);
298 }
299 
300 mraa::Result
ceLow()301 NRF24L01::ceLow () {
302     return m_cePinCtx.write(LOW);
303 }
304 
305 mraa::Result
csOn()306 NRF24L01::csOn () {
307     return m_csnPinCtx.write(LOW);
308 }
309 
310 mraa::Result
csOff()311 NRF24L01::csOff () {
312     return m_csnPinCtx.write(HIGH);
313 }
314 
315 void
pollListener()316 NRF24L01::pollListener() {
317     if (dataReady()) {
318         getData (m_rxBuffer);
319 #ifdef JAVACALLBACK
320         dataReceivedHandler (callback_obj); /* let know that data arrived */
321 #else
322         dataReceivedHandler (); /* let know that data arrived */
323 #endif
324     }
325 }
326 
327 void
txFlushBuffer()328 NRF24L01::txFlushBuffer () {
329     sendCommand (FLUSH_TX);
330 }
331 
332 void
setBeaconingMode()333 NRF24L01::setBeaconingMode () {
334     setRegister (CONFIG,     0x12); // on, no crc, int on RX/TX done
335     setRegister (EN_AA,      0x00); // no auto-acknowledge
336     setRegister (EN_RXADDR,  0x00); // no RX
337     setRegister (SETUP_AW,   0x02); // 5-byte address
338     setRegister (SETUP_RETR, 0x00); // no auto-retransmit
339     setRegister (RF_SETUP,   0x06); // 1MBps at 0dBm
340     setRegister (STATUS,     0x3E); // clear various flags
341     setRegister (DYNPD,      0x00); // no dynamic payloads
342     setRegister (FEATURE,    0x00); // no features
343     setRegister (RX_PW_P0,   32);   // always RX 32 bytes
344     setRegister (EN_RXADDR,  0x01); // RX on pipe 0
345 
346     uint8_t addr[4] = { swapbits(0x8E), swapbits(0x89), swapbits(0xBE), swapbits(0xD6)};
347     writeRegister (TX_ADDR,     addr, 4);
348     writeRegister (RX_ADDR_P0,  addr, 4);
349 
350     uint8_t index = 0;
351     m_bleBuffer[index++] = 0x42;        // PDU type, given address is random
352     m_bleBuffer[index++] = 0x1B;        // 6+3+2+16 = 27 bytes of payload
353 
354     m_bleBuffer[index++] = BLE_MAC_0;
355     m_bleBuffer[index++] = BLE_MAC_1;
356     m_bleBuffer[index++] = BLE_MAC_2;
357     m_bleBuffer[index++] = BLE_MAC_3;
358     m_bleBuffer[index++] = BLE_MAC_4;
359     m_bleBuffer[index++] = BLE_MAC_5;
360 
361     m_bleBuffer[index++] = 2;           // flags (LE-only, limited discovery mode)
362     m_bleBuffer[index++] = 0x01;
363     m_bleBuffer[index++] = 0x05;
364 
365     m_bleBuffer[index++] = 17;
366     m_bleBuffer[index++] = 0x08;
367 }
368 
369 void
sendBeaconingMsg(uint8_t * msg)370 NRF24L01::sendBeaconingMsg (uint8_t * msg) {
371     const uint8_t   chRf[] = {2, 26,80};
372     const uint8_t   chLe[] = {37,38,39};
373     uint8_t         index = BLE_PAYLOAD_OFFSET + 16;
374 
375     memcpy (&m_bleBuffer[BLE_PAYLOAD_OFFSET], msg, 16);
376     m_bleBuffer[index++] = 0x55;
377     m_bleBuffer[index++] = 0x55;
378     m_bleBuffer[index++] = 0x55;
379 
380     uint8_t channel = 0;
381     while (++channel != sizeof(chRf)) {
382         setRegister (RF_CH,     chRf[channel]);
383         setRegister (STATUS,    0x6E);          //clear flags
384 
385         blePacketEncode (m_bleBuffer, index, chLe[channel]);
386 
387         sendCommand (FLUSH_TX); // Clear RX Fifo
388         sendCommand (FLUSH_RX); // Clear TX Fifo
389 
390         csOn ();
391         m_spi.writeByte(W_TX_PAYLOAD);        // Write cmd to write payload
392         writeBytes (m_bleBuffer, NULL, 32);     // Write payload
393         csOff ();
394 
395         setRegister (CONFIG, 0x12);             // tx on
396         ceHigh ();                              // Start transmission
397         usleep (10000);
398         ceLow ();
399     }
400 }
401 
402 /*
403  * ---------------
404  * PRIVATE SECTION
405  * ---------------
406  */
407 
408 void
writeBytes(uint8_t * dataout,uint8_t * datain,uint8_t len)409 NRF24L01::writeBytes (uint8_t * dataout, uint8_t * datain, uint8_t len) {
410     if(len > MAX_BUFFER){
411         len = MAX_BUFFER;
412     }
413     for (uint8_t i = 0; i < len; i++) {
414         if (datain != NULL) {
415             datain[i] = m_spi.writeByte(dataout[i]);
416         } else {
417             m_spi.writeByte(dataout[i]);
418         }
419     }
420 }
421 
422 void
setRegister(uint8_t reg,uint8_t value)423 NRF24L01::setRegister (uint8_t reg, uint8_t value) {
424     csOn ();
425     m_spi.writeByte(W_REGISTER | (REGISTER_MASK & reg));
426     m_spi.writeByte(value);
427     csOff ();
428 }
429 
430 uint8_t
getRegister(uint8_t reg)431 NRF24L01::getRegister (uint8_t reg) {
432     uint8_t data = 0;
433 
434     csOn ();
435     m_spi.writeByte(R_REGISTER | (REGISTER_MASK & reg));
436     data = m_spi.writeByte(data);
437     csOff ();
438 
439     return data;
440 }
441 
442 void
readRegister(uint8_t reg,uint8_t * value,uint8_t len)443 NRF24L01::readRegister (uint8_t reg, uint8_t * value, uint8_t len) {
444     csOn ();
445     m_spi.writeByte(R_REGISTER | (REGISTER_MASK & reg));
446     writeBytes (value, value, len);
447     csOff ();
448 }
449 
450 void
writeRegister(uint8_t reg,uint8_t * value,uint8_t len)451 NRF24L01::writeRegister (uint8_t reg, uint8_t * value, uint8_t len) {
452     csOn ();
453     m_spi.writeByte(W_REGISTER | (REGISTER_MASK & reg));
454     writeBytes (value, NULL, len);
455     csOff ();
456 }
457 
458 void
sendCommand(uint8_t cmd)459 NRF24L01::sendCommand (uint8_t cmd) {
460     csOn ();
461     m_spi.writeByte(cmd);
462     csOff ();
463 }
464 
465 void
bleCrc(const uint8_t * data,uint8_t len,uint8_t * dst)466 NRF24L01::bleCrc (const uint8_t* data, uint8_t len, uint8_t* dst) {
467     uint8_t v, t, d;
468     while(len--) {
469         d = *data++;
470         for(v = 0; v < 8; v++, d >>= 1){
471             t = dst[0] >> 7;
472             dst[0] <<= 1;
473             if(dst[1] & 0x80) dst[0] |= 1;
474             dst[1] <<= 1;
475             if(dst[2] & 0x80) dst[1] |= 1;
476             dst[2] <<= 1;
477 
478             if(t != (d & 1)) {
479                 dst[2] ^= 0x5B;
480                 dst[1] ^= 0x06;
481             }
482         }
483     }
484 }
485 
486 void
bleWhiten(uint8_t * data,uint8_t len,uint8_t whitenCoeff)487 NRF24L01::bleWhiten (uint8_t* data, uint8_t len, uint8_t whitenCoeff) {
488     uint8_t  m;
489     while(len--) {
490         for(m = 1; m; m <<= 1) {
491             if(whitenCoeff & 0x80){
492                 whitenCoeff ^= 0x11;
493                 (*data) ^= m;
494             }
495             whitenCoeff <<= 1;
496         }
497         data++;
498     }
499 }
500 
501 void
blePacketEncode(uint8_t * packet,uint8_t len,uint8_t chan)502 NRF24L01::blePacketEncode(uint8_t* packet, uint8_t len, uint8_t chan) {
503     if(len > MAX_BUFFER){
504         len = MAX_BUFFER;
505     }
506 
507     //length is of packet, including crc. pre-populate crc in packet with initial crc value!
508     uint8_t i, dataLen = len - 3;
509 
510     bleCrc(packet, dataLen, packet + dataLen);
511     for(i = 0; i < 3; i++, dataLen++) {
512         packet[dataLen] = swapbits(packet[dataLen]);
513     }
514 
515     bleWhiten(packet, len, (swapbits(chan) | 2));
516     for(i = 0; i < len; i++) {
517         packet[i] = swapbits(packet[i]);
518     }
519 }
520 
521 uint8_t
swapbits(uint8_t a)522 NRF24L01::swapbits(uint8_t a) {
523     uint8_t v = 0;
524 
525     if(a & 0x80) v |= 0x01;
526     if(a & 0x40) v |= 0x02;
527     if(a & 0x20) v |= 0x04;
528     if(a & 0x10) v |= 0x08;
529     if(a & 0x08) v |= 0x10;
530     if(a & 0x04) v |= 0x20;
531     if(a & 0x02) v |= 0x40;
532     if(a & 0x01) v |= 0x80;
533 
534     return v;
535 }
536