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 #pragma once
26 
27 #include <string>
28 #include <mraa/aio.hpp>
29 #include <mraa/common.hpp>
30 
31 #include <mraa/gpio.hpp>
32 
33 #include <mraa/spi.hpp>
34 #include <cstring>
35 
36 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
37 #include "Callback.h"
38 #endif
39 
40 /* Memory Map */
41 #define CONFIG              0x00
42 #define EN_AA               0x01
43 #define EN_RXADDR           0x02
44 #define SETUP_AW            0x03
45 #define SETUP_RETR          0x04
46 #define RF_CH               0x05
47 #define RF_SETUP            0x06
48 #define STATUS              0x07
49 #define OBSERVE_TX          0x08
50 #define CD                  0x09
51 #define RX_ADDR_P0          0x0A
52 #define RX_ADDR_P1          0x0B
53 #define RX_ADDR_P2          0x0C
54 #define RX_ADDR_P3          0x0D
55 #define RX_ADDR_P4          0x0E
56 #define RX_ADDR_P5          0x0F
57 #define TX_ADDR             0x10
58 #define RX_PW_P0            0x11
59 #define RX_PW_P1            0x12
60 #define RX_PW_P2            0x13
61 #define RX_PW_P3            0x14
62 #define RX_PW_P4            0x15
63 #define RX_PW_P5            0x16
64 #define FIFO_STATUS         0x17
65 #define DYNPD               0x1C
66 #define FEATURE             0x1D
67 
68 /* Bit Mnemonics */
69 #define MASK_RX_DR          6
70 #define MASK_TX_DS          5
71 #define MASK_MAX_RT         4
72 #define EN_CRC              3
73 #define CRCO                2
74 #define PWR_UP              1
75 #define PRIM_RX             0
76 #define ENAA_P5             5
77 #define ENAA_P4             4
78 #define ENAA_P3             3
79 #define ENAA_P2             2
80 #define ENAA_P1             1
81 #define ENAA_P0             0
82 #define ERX_P5              5
83 #define ERX_P4              4
84 #define ERX_P3              3
85 #define ERX_P2              2
86 #define ERX_P1              1
87 #define ERX_P0              0
88 #define AW                  0
89 #define ARD                 4
90 #define ARC                 0
91 #define PLL_LOCK            4
92 #define RF_DR               3
93 #define RF_PWR              1
94 #define LNA_HCURR           0
95 #define RX_DR               6
96 #define TX_DS               5
97 #define MAX_RT              4
98 #define RX_P_NO             1
99 #define TX_FULL             0
100 #define PLOS_CNT            4
101 #define ARC_CNT             0
102 #define TX_REUSE            6
103 #define FIFO_FULL           5
104 #define TX_EMPTY            4
105 #define RX_FULL             1
106 #define RX_EMPTY            0
107 
108 /* Instruction Mnemonics */
109 #define R_REGISTER            0x00
110 #define W_REGISTER            0x20
111 #define REGISTER_MASK         0x1F
112 #define R_RX_PAYLOAD          0x61
113 #define W_TX_PAYLOAD          0xA0
114 #define FLUSH_TX              0xE1
115 #define FLUSH_RX              0xE2
116 #define REUSE_TX_PL           0xE3
117 #define NOP                   0xFF
118 
119 #define RF_DR_LOW   5
120 #define RF_DR_HIGH  3
121 #define RF_PWR_LOW  1
122 #define RF_PWR_HIGH 2
123 
124 /* Nrf24l settings */
125 #define ADDR_LEN        5
126 #define _CONFIG         ((1<<EN_CRC) | (0<<CRCO) )
127 
128 #define MAX_BUFFER            32
129 
130 #define HIGH                  1
131 #define LOW                    0
132 
133 /* BLE beaconing */
134 #define BLE_MAC_0           0xEF
135 #define BLE_MAC_1           0xFF
136 #define BLE_MAC_2           0xC0
137 #define BLE_MAC_3           0xAA
138 #define BLE_MAC_4           0x18
139 #define BLE_MAC_5           0x00
140 
141 #define BLE_PAYLOAD_OFFSET  13
142 
143 namespace upm {
144 
145 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
146 typedef void (* funcPtrVoidVoid) (Callback *);
147 #else
148 typedef void (* funcPtrVoidVoid) ();
149 #endif
150 
151 typedef enum {
152     NRF_250KBPS = 0,
153     NRF_1MBPS   = 1,
154     NRF_2MBPS   = 2,
155 } speed_rate_t;
156 
157 typedef enum {
158     NRF_0DBM    = 0,
159     NRF_6DBM    = 1,
160     NRF_12DBM   = 2,
161     NRF_18DBM   = 3,
162 } power_t;
163 
164 /**
165  * @brief NRF24L01 Transceiver library
166  * @defgroup nrf24l01 libupm-nrf24l01
167  * @ingroup seeed sparkfun spi wifi
168  */
169 /**
170  * @library nrf24l01
171  * @sensor nrf24l01
172  * @comname NRF24L01 Transceiver
173  * @type wifi
174  * @man seeed sparkfun
175  * @web http://www.seeedstudio.com/depot/nRF24L01Module-p-1394.html
176  * @con spi
177  *
178  * id
179  * @brief API for the NRF24L01 Transceiver Module
180  *
181  * This module defines the NRF24L01 interface for libnrf24l01
182  *
183  * @image html nrf24l01.jpg
184  * @snippet nrf24l01-receiver.cxx Interesting
185  * @snippet nrf24l01-transmitter.cxx Interesting
186  * @snippet nrf24l01-broadcast.cxx Interesting
187  */
188 class NRF24L01 {
189     public:
190         /**
191          * Instantiates an NRF24l01 object
192          *
193          * @param cs Chip select pin
194          */
195         NRF24L01 (uint8_t cs, uint8_t ce);
196 
197         /**
198          * Returns the name of the component
199          */
name()200         std::string name()
201         {
202             return m_name;
203         }
204 
205         /**
206          * Initializes needed GPIO pins and SPI
207          *
208          * @param chipSelect Sets up the chip select pin
209          * @param chipEnable Sets up the chip enable pin
210          */
211         void    init (uint8_t chipSelect, uint8_t chipEnable);
212 
213         /**
214          * Configures the NRF24L01 transceiver
215          */
216         void    configure ();
217 
218         /**
219          * Sends the buffer data
220          *
221          * @param *value Pointer to the buffer
222          */
223         void    send (uint8_t * value);
224 
225         /**
226          * Sends the data located in an inner bufer; the user must fill the
227          * m_txBuffer buffer
228          */
229         void    send ();
230 
231         /**
232          * Sets a receiving address of the device
233          *
234          * @param addr 5-byte address
235          */
236         void    setSourceAddress (uint8_t * addr);
237 
238         /**
239          * Sets a recipient address. The nrfSend method sends the data buffer
240          * to this address
241          *
242          * @param addr 5-byte address
243          */
244         void    setDestinationAddress (uint8_t * addr);
245 
246         /**
247          * Sets a broadcasting address
248          *
249          * @param addr 5-byte address
250          */
251         void    setBroadcastAddress (uint8_t * addr);
252 
253         /**
254          * Sets the payload size
255          *
256          * @param load Size of the payload (MAX 32)
257          */
258         void    setPayload (uint8_t load);
259 
260 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
261         /**
262          * Sets the handler to be called when data has been
263          * received
264          * @param call_obj Object used for callback - Java
265          */
266         void setDataReceivedHandler (Callback *call_obj);
267 #else
268         /**
269          * Sets the handler to be called when data has been
270          * received
271          * @param handler Handler used for callback
272          */
273         void setDataReceivedHandler (funcPtrVoidVoid handler);
274 #endif
275         /**
276          * Checks if the data has arrived
277          */
278         bool    dataReady ();
279 
280         /**
281          * Checks if the transceiver is in the sending mode
282          */
283         bool    dataSending ();
284 
285         /**
286          * Sinks all the arrived data into a provided buffer
287          *
288          * @param load Size of the payload (MAX 32)
289          */
290         void    getData (uint8_t * data);
291 
292         /**
293          * Checks the transceiver state
294          */
295         uint8_t getStatus ();
296 
297         /**
298          * Checks if the receive stack is empty
299          */
300         bool    rxFifoEmpty ();
301 
302         /**
303          * Powers the receiver up
304          */
305         void    rxPowerUp ();
306 
307         /**
308          * Flushes the receive stack
309          */
310         void    rxFlushBuffer ();
311 
312         /**
313          * Powers the transmitter up
314          */
315         void    txPowerUp ();
316 
317         /**
318          * Powers everything down
319          */
320         void    powerDown ();
321 
322         void    setChannel (uint8_t channel);
323 
324         void    setPower (power_t power);
325 
326         uint8_t setSpeedRate (speed_rate_t rate);
327 
328         /**
329          * Flushes the transmit stack
330          */
331         void    txFlushBuffer ();
332 
333         /**
334          * Pulling the method listening for the arrived data,
335          * dataRecievedHandler is triggered if data arrives
336          */
337         void    pollListener ();
338 
339         /**
340          * Sets the chip enable pin to HIGH
341          */
342         mraa::Result ceHigh ();
343 
344         /**
345          * Sets the chip enable pin to LOW
346          */
347         mraa::Result ceLow ();
348 
349         /**
350          * Sets the chip select pin to LOW
351          */
352         mraa::Result csOn ();
353 
354         /**
355          * Sets the chip select pin to HIGH
356          */
357         mraa::Result csOff ();
358 
359         /**
360          * Configures the NRF24L01 transceiver to behave as a BLE
361          * (Bluetooth Low Energy) beaconing devcie.
362          */
363         void setBeaconingMode ();
364 
365         /**
366          * Beacons the provided message to BLE scanners.
367          *
368          * @param msg Beacons the provided message (max length is 16 bytes)
369          */
370         void sendBeaconingMsg (uint8_t * msg);
371 
372         uint8_t     m_rxBuffer[MAX_BUFFER]; /**< Receive buffer */
373         uint8_t     m_txBuffer[MAX_BUFFER]; /**< Transmit buffer */
374         uint8_t     m_bleBuffer [32];       /**< BLE buffer */
375 
376     private:
377 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
378         /**< Callback object to use for setting the handler from Java */
379         Callback *callback_obj;
380 #endif
381         funcPtrVoidVoid dataReceivedHandler; /**< Data arrived handler */
382 
383         /**
384          * Writes bytes to an SPI device
385          */
386         void    writeBytes (uint8_t * dataout, uint8_t * datain, uint8_t len);
387         /**
388          * Sets the register value on an SPI device [one byte]
389          */
390         void    setRegister (uint8_t reg, uint8_t value);
391         /**
392          * Gets the register value from an SPI device [one byte]
393          */
394         uint8_t getRegister (uint8_t reg);
395         /**
396          * Reads an array of bytes from the given starting position in NRF24L01 registers
397          */
398         void    readRegister (uint8_t reg, uint8_t * value, uint8_t len);
399         /**
400          * Writes an array of bytes into NRF24L01 registers
401          */
402         void    writeRegister (uint8_t reg, uint8_t * value, uint8_t len);
403         /**
404          * Sends a command to NRF24L01
405          */
406         void    sendCommand (uint8_t cmd);
407 
408         void bleCrc (const uint8_t* data, uint8_t len, uint8_t* dst);
409 
410         void bleWhiten (uint8_t* data, uint8_t len, uint8_t whitenCoeff);
411 
412         void blePacketEncode(uint8_t* packet, uint8_t len, uint8_t chan);
413 
414         uint8_t swapbits (uint8_t a);
415 
416         mraa::Spi               m_spi;
417         uint8_t                 m_ce;
418         uint8_t                 m_csn;
419         uint8_t                 m_channel;
420         uint8_t                 m_power;
421         uint8_t                 m_ptx;
422         uint8_t                 m_payload;
423         uint8_t                 m_localAddress[5];
424 
425         mraa::Gpio              m_csnPinCtx;
426         mraa::Gpio              m_cePinCtx;
427 
428         std::string             m_name;
429 };
430 
431 }
432