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