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 34using namespace upm; 35 36 37NRF24L01::NRF24L01 (uint8_t cs, uint8_t ce) 38 : m_csnPinCtx(cs), m_cePinCtx(ce), m_spi(0) 39{ 40 init (cs, ce); 41} 42 43void 44NRF24L01::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 65void 66NRF24L01::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 81void 82NRF24L01::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 110void 111NRF24L01::send () { 112 send (m_txBuffer); 113} 114 115void 116NRF24L01::setSourceAddress (uint8_t * addr) { 117 ceLow (); 118 writeRegister (RX_ADDR_P0, addr, ADDR_LEN); 119 ceHigh (); 120} 121 122void 123NRF24L01::setDestinationAddress (uint8_t * addr) { 124 writeRegister (TX_ADDR, addr, ADDR_LEN); 125} 126 127void 128NRF24L01::setBroadcastAddress (uint8_t * addr) { 129 writeRegister (RX_ADDR_P1, addr, ADDR_LEN); 130} 131 132void 133NRF24L01::setPayload (uint8_t payload) { 134 m_payload = payload; 135} 136 137#ifdef JAVACALLBACK 138void 139NRF24L01::setDataReceivedHandler (Callback *call_obj) 140{ 141 callback_obj = call_obj; 142 dataReceivedHandler = &generic_callback; 143} 144#else 145void 146NRF24L01::setDataReceivedHandler (funcPtrVoidVoid handler) 147{ 148 dataReceivedHandler = handler; 149} 150#endif 151 152bool 153NRF24L01::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 165bool 166NRF24L01::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 180void 181NRF24L01::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 200uint8_t 201NRF24L01::getStatus() { 202 return getRegister (STATUS); 203} 204 205bool 206NRF24L01::rxFifoEmpty () { 207 uint8_t fifoStatus = getRegister (FIFO_STATUS); 208 return (fifoStatus & (1 << RX_EMPTY)); 209} 210 211void 212NRF24L01::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 220void 221NRF24L01::rxFlushBuffer () { 222 sendCommand (FLUSH_RX); 223} 224 225void 226NRF24L01::txPowerUp () { 227 m_ptx = 1; 228 setRegister (CONFIG, _CONFIG | ( (1 << PWR_UP) | (0 << PRIM_RX) )); 229} 230 231void 232NRF24L01::powerDown(){ 233 ceLow (); 234 setRegister (CONFIG, _CONFIG); 235} 236 237void 238NRF24L01::setChannel (uint8_t channel) { 239 m_channel = channel; 240 setRegister (RF_CH, channel); 241} 242 243void 244NRF24L01::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 268uint8_t 269NRF24L01::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 295mraa::Result 296NRF24L01::ceHigh () { 297 return m_cePinCtx.write(HIGH); 298} 299 300mraa::Result 301NRF24L01::ceLow () { 302 return m_cePinCtx.write(LOW); 303} 304 305mraa::Result 306NRF24L01::csOn () { 307 return m_csnPinCtx.write(LOW); 308} 309 310mraa::Result 311NRF24L01::csOff () { 312 return m_csnPinCtx.write(HIGH); 313} 314 315void 316NRF24L01::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 327void 328NRF24L01::txFlushBuffer () { 329 sendCommand (FLUSH_TX); 330} 331 332void 333NRF24L01::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 369void 370NRF24L01::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 408void 409NRF24L01::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 422void 423NRF24L01::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 430uint8_t 431NRF24L01::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 442void 443NRF24L01::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 450void 451NRF24L01::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 458void 459NRF24L01::sendCommand (uint8_t cmd) { 460 csOn (); 461 m_spi.writeByte(cmd); 462 csOff (); 463} 464 465void 466NRF24L01::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 486void 487NRF24L01::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 501void 502NRF24L01::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 521uint8_t 522NRF24L01::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