nrf24l01 :: Added NRF module with examples.
[contrib/upm.git] / src / nrf24l01 / nrf24l01.cxx
1 /*
2  * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
3  * Copyright (c) 2014 Intel Corporation.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 #include <iostream>
26 #include <unistd.h>
27
28 #include "nrf24l01.h"
29
30 using namespace upm;
31
32 NRF24l01::NRF24l01 (uint8_t cs) {
33         maa_init();
34         nrfInitModule (cs, 8);
35 }
36
37 NRF24l01::~NRF24l01 () {
38         maa_result_t error = MAA_SUCCESS;
39         error = maa_spi_stop(m_spi);
40         if (error != MAA_SUCCESS) {
41         maa_result_print(error);
42     }
43         error = maa_gpio_close (m_cePinCtx);
44     if (error != MAA_SUCCESS) {
45         maa_result_print(error);
46     }
47         error = maa_gpio_close (m_csnPinCtx);
48     if (error != MAA_SUCCESS) {
49         maa_result_print(error);
50     }
51 }
52
53 void 
54 NRF24l01::nrfInitModule (uint8_t chip_select, uint8_t chip_enable) {
55         maa_result_t error = MAA_SUCCESS;
56
57         m_csn           = chip_select;
58         m_ce            = chip_enable;
59         m_channel       = 1;
60
61         m_csnPinCtx = maa_gpio_init (m_csn);
62         if (m_csnPinCtx == NULL) {
63         fprintf (stderr, "Are you sure that pin%d you requested is valid on your platform?", m_csn);
64                 exit (1);
65         }
66         
67         m_cePinCtx = maa_gpio_init (m_ce);
68         if (m_cePinCtx == NULL) {
69         fprintf (stderr, "Are you sure that pin%d you requested is valid on your platform?", m_ce);
70                 exit (1);
71         }
72         
73         error = maa_gpio_dir (m_csnPinCtx, MAA_GPIO_OUT);
74     if (error != MAA_SUCCESS) {
75         maa_result_print (error);
76     }
77
78         error = maa_gpio_dir (m_cePinCtx, MAA_GPIO_OUT);
79     if (error != MAA_SUCCESS) {
80         maa_result_print (error);
81     }
82         
83         nrfCELow ();
84         m_spi = maa_spi_init (0);
85 }
86
87 void 
88 NRF24l01::nrfConfigModule() {
89         /* Set RF channel */
90         nrfConfigRegister (RF_CH, m_channel);
91
92         /* Set length of incoming payload */
93         nrfConfigRegister (RX_PW_P0, m_payload);
94         nrfConfigRegister (RX_PW_P1, m_payload);
95         /* Set length of incoming payload for broadcast */
96         nrfConfigRegister (RX_PW_P2, m_payload);
97         
98         /* Start receiver */
99         nrfPowerUpRX ();
100         nrfFlushRX ();
101 }
102
103 /* Clocks only one byte into the given MiRF register */
104 void 
105 NRF24l01::nrfConfigRegister(uint8_t reg, uint8_t value) {
106         nrfCSOn ();
107         maa_spi_write (m_spi, W_REGISTER | (REGISTER_MASK & reg));
108         maa_spi_write (m_spi, value);
109         nrfCSOff ();
110 }
111
112 void 
113 NRF24l01::nrfPowerUpRX() {
114         m_ptx = 0;
115         nrfCELow();
116         nrfConfigRegister(CONFIG, mirf_CONFIG | ( (1<<PWR_UP) | (1<<PRIM_RX) ) );
117         nrfCEHigh();
118         nrfConfigRegister(STATUS,(1 << TX_DS) | (1 << MAX_RT)); 
119 }
120
121 void 
122 NRF24l01::nrfFlushRX() {
123         nrfCSOn ();
124         maa_spi_write (m_spi, FLUSH_RX);
125         nrfCSOff ();
126 }
127
128 /* Sets the receiving address */
129 void 
130 NRF24l01::nrfSetRXaddr(uint8_t * addr) {
131         nrfCELow();
132         nrfWriteRegister(RX_ADDR_P1, addr, mirf_ADDR_LEN);
133         nrfCEHigh();
134 }
135
136 /* Sets the transmitting address */
137 void 
138 NRF24l01::nrfSetTXaddr(uint8_t * addr)
139 {
140         /* RX_ADDR_P0 must be set to the sending addr for auto ack to work. */
141         nrfWriteRegister (RX_ADDR_P0, addr, mirf_ADDR_LEN);
142         nrfWriteRegister (TX_ADDR, addr, mirf_ADDR_LEN);
143 }
144
145 /* The broadcast address should be 0xFFFFF */
146 void 
147 NRF24l01::nrfSetBroadcastAddr (uint8_t * addr) {
148         nrfCELow ();
149         nrfWriteRegister (RX_ADDR_P2, addr, mirf_ADDR_LEN);
150         nrfCEHigh ();
151 }
152
153 void 
154 NRF24l01::nrfSetPayload (uint8_t load) {
155         m_payload = load;
156 }
157
158 void 
159 NRF24l01::nrfWriteRegister(uint8_t reg, uint8_t * value, uint8_t len) 
160 {
161         nrfCSOn ();
162         maa_spi_write (m_spi, W_REGISTER | (REGISTER_MASK & reg));
163         nrfTransmitSync(value, len);
164         nrfCSOff ();
165 }
166
167 void 
168 NRF24l01::nrfTransmitSync(uint8_t *dataout, uint8_t len){
169         uint8_t i;
170         for(i = 0; i < len; i++) {
171                 maa_spi_write (m_spi, dataout[i]);
172         }
173 }
174
175 /* Checks if data is available for reading */
176 bool 
177 NRF24l01::nrfDataReady() {
178         uint8_t status = nrfGetStatus();
179         if ( status & (1 << RX_DR) ) {
180                 return 1;
181         }
182         
183         return !nrfRXFifoEmpty();
184 }
185
186 uint8_t 
187 NRF24l01::nrfGetStatus () {
188         uint8_t rv;
189         nrfReadRegister (STATUS, &rv, 1);
190         return rv;
191 }
192
193 /* Reads an array of bytes from the given start position in the MiRF registers. */
194 void 
195 NRF24l01::nrfReadRegister (uint8_t reg, uint8_t * value, uint8_t len)
196 {
197         nrfCSOn ();
198         maa_spi_write (m_spi, R_REGISTER | (REGISTER_MASK & reg));
199         nrfTransferSync (value, value, len);
200         nrfCSOff ();
201 }
202
203 void 
204 NRF24l01::nrfTransferSync (uint8_t *dataout,uint8_t *datain,uint8_t len) {
205         uint8_t i;
206         for(i = 0;i < len;i++) {
207                 datain[i] = maa_spi_write (m_spi, dataout[i]);
208         }
209 }
210
211 bool 
212 NRF24l01::nrfRXFifoEmpty () {
213         uint8_t fifo_status;
214         nrfReadRegister (FIFO_STATUS, &fifo_status, sizeof(fifo_status));
215         return (fifo_status & (1 << RX_EMPTY));
216 }
217
218 /* Reads payload bytes into data array */
219 void 
220 NRF24l01::nrfGetData (uint8_t * data) 
221 {
222         nrfCSOn ();
223         /* Send cmd to read rx payload */
224         maa_spi_write (m_spi, R_RX_PAYLOAD);
225         /* Read payload */
226         nrfTransferSync(data, data, m_payload);
227         nrfCSOff ();
228         nrfConfigRegister(STATUS, (1<<RX_DR));
229 }
230
231 /* Sends a data package to the default address. Be sure to send the correct
232  * amount of bytes as configured as payload on the receiver. */
233 void 
234 NRF24l01::nrfSend(uint8_t * value) {
235         uint8_t status;
236         status = nrfGetStatus();
237
238         while (m_ptx) {
239                 status = nrfGetStatus();
240
241                 if((status & ((1 << TX_DS)  | (1 << MAX_RT)))){
242                         m_ptx = 0;
243                         break;
244                 }
245         } // Wait until last paket is send
246
247         nrfCELow();
248         nrfPowerUpTX();                                                 // Set to transmitter mode , Power up
249         nrfCSOn ();
250         maa_spi_write (m_spi, FLUSH_TX);                // Write cmd to flush tx fifo
251         nrfCSOff ();
252         
253         nrfCSOn ();
254         maa_spi_write (m_spi, W_TX_PAYLOAD);    // Write cmd to write payload
255         nrfTransmitSync(value, m_payload);              // Write payload
256         nrfCSOff ();
257         nrfCEHigh();                                                    // Start transmission
258 }
259
260 void 
261 NRF24l01::nrfSend () {
262         nrfSend (m_txBuffer);
263 }
264
265 bool 
266 NRF24l01::nrfIsSending () {
267         uint8_t status;
268         if (m_ptx)      { // Sending mode.
269                 status = nrfGetStatus();
270                 /* if sending successful (TX_DS) or max retries exceded (MAX_RT). */
271                 if((status & ((1 << TX_DS)  | (1 << MAX_RT)))){
272                         nrfPowerUpRX();
273                         return false; 
274                 }
275                 return true;
276         }
277         return false;
278 }
279
280 void 
281 NRF24l01::nrfPowerUpTX () {
282         m_ptx = 1;
283         nrfConfigRegister (CONFIG, mirf_CONFIG | ( (1<<PWR_UP) | (0<<PRIM_RX) ) );
284 }
285
286 void 
287 NRF24l01::nrfPowerDown () {
288         nrfCELow ();
289         nrfConfigRegister (CONFIG, mirf_CONFIG);
290 }
291
292 maa_result_t 
293 NRF24l01::nrfCEHigh () {
294         return maa_gpio_write (m_cePinCtx, HIGH);
295 }
296
297 maa_result_t 
298 NRF24l01::nrfCELow () {
299         return maa_gpio_write (m_cePinCtx, LOW);
300 }
301
302 maa_result_t 
303 NRF24l01::nrfCSOn () {
304         return maa_gpio_write (m_csnPinCtx, LOW);
305 }
306
307 maa_result_t 
308 NRF24l01::nrfCSOff () {
309         return maa_gpio_write (m_csnPinCtx, HIGH);
310 }
311
312 void 
313 NRF24l01::nrfListenForChannel() {
314         if(!nrfIsSending() && nrfDataReady()) {
315                 nrfGetData(m_rxBuffer);
316                 dataRecievedHandler(); /* let know that data arrived */
317         }
318 }
319