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