Home | History | Annotate | Download | only in nrf24l01
      1 /*
      2  * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha (at) 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 
     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
     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
     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
     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
    111 NRF24L01::send () {
    112     send (m_txBuffer);
    113 }
    114 
    115 void
    116 NRF24L01::setSourceAddress (uint8_t * addr) {
    117     ceLow ();
    118     writeRegister (RX_ADDR_P0, addr, ADDR_LEN);
    119     ceHigh ();
    120 }
    121 
    122 void
    123 NRF24L01::setDestinationAddress (uint8_t * addr) {
    124     writeRegister (TX_ADDR, addr, ADDR_LEN);
    125 }
    126 
    127 void
    128 NRF24L01::setBroadcastAddress (uint8_t * addr) {
    129     writeRegister (RX_ADDR_P1, addr, ADDR_LEN);
    130 }
    131 
    132 void
    133 NRF24L01::setPayload (uint8_t payload) {
    134     m_payload = payload;
    135 }
    136 
    137 #ifdef JAVACALLBACK
    138 void
    139 NRF24L01::setDataReceivedHandler (Callback *call_obj)
    140 {
    141     callback_obj = call_obj;
    142     dataReceivedHandler = &generic_callback;
    143 }
    144 #else
    145 void
    146 NRF24L01::setDataReceivedHandler (funcPtrVoidVoid handler)
    147 {
    148     dataReceivedHandler = handler;
    149 }
    150 #endif
    151 
    152 bool
    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
    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
    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
    201 NRF24L01::getStatus() {
    202     return getRegister (STATUS);
    203 }
    204 
    205 bool
    206 NRF24L01::rxFifoEmpty () {
    207     uint8_t fifoStatus = getRegister (FIFO_STATUS);
    208     return (fifoStatus & (1 << RX_EMPTY));
    209 }
    210 
    211 void
    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
    221 NRF24L01::rxFlushBuffer () {
    222     sendCommand (FLUSH_RX);
    223 }
    224 
    225 void
    226 NRF24L01::txPowerUp () {
    227     m_ptx = 1;
    228     setRegister (CONFIG, _CONFIG | ( (1 << PWR_UP) | (0 << PRIM_RX) ));
    229 }
    230 
    231 void
    232 NRF24L01::powerDown(){
    233     ceLow ();
    234     setRegister (CONFIG, _CONFIG);
    235 }
    236 
    237 void
    238 NRF24L01::setChannel (uint8_t channel) {
    239     m_channel = channel;
    240     setRegister (RF_CH, channel);
    241 }
    242 
    243 void
    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
    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
    296 NRF24L01::ceHigh () {
    297     return m_cePinCtx.write(HIGH);
    298 }
    299 
    300 mraa::Result
    301 NRF24L01::ceLow () {
    302     return m_cePinCtx.write(LOW);
    303 }
    304 
    305 mraa::Result
    306 NRF24L01::csOn () {
    307     return m_csnPinCtx.write(LOW);
    308 }
    309 
    310 mraa::Result
    311 NRF24L01::csOff () {
    312     return m_csnPinCtx.write(HIGH);
    313 }
    314 
    315 void
    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
    328 NRF24L01::txFlushBuffer () {
    329     sendCommand (FLUSH_TX);
    330 }
    331 
    332 void
    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
    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
    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
    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
    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
    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
    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
    459 NRF24L01::sendCommand (uint8_t cmd) {
    460     csOn ();
    461     m_spi.writeByte(cmd);
    462     csOff ();
    463 }
    464 
    465 void
    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
    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
    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
    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