1 | /*
|
2 | Copyright (c) 2011 by Ernst Buchmann
|
3 |
|
4 | Code based on the work of Stefan Engelke and Brennan Ball
|
5 |
|
6 | Permission is hereby granted, free of charge, to any person
|
7 | obtaining a copy of this software and associated documentation
|
8 | files (the "Software"), to deal in the Software without
|
9 | restriction, including without limitation the rights to use, copy,
|
10 | modify, merge, publish, distribute, sublicense, and/or sell copies
|
11 | of the Software, and to permit persons to whom the Software is
|
12 | furnished to do so, subject to 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
|
21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
24 | DEALINGS IN THE SOFTWARE.
|
25 |
|
26 |
|
27 | */
|
28 |
|
29 | #include "wl_module.h"
|
30 | #include "nRF24L01.h"
|
31 | #include "spi.h"
|
32 | #include <avr/io.h>
|
33 | #include <avr/interrupt.h>
|
34 | #include <util/delay.h>
|
35 |
|
36 | // Defines for setting the wl_module registers for transmitting or receiving mode
|
37 | #define TX_POWERUP wl_module_config_register(CONFIG, wl_module_CONFIG | ( (1<<PWR_UP) | (0<<PRIM_RX) ) )
|
38 | #define RX_POWERUP wl_module_config_register(CONFIG, wl_module_CONFIG | ( (1<<PWR_UP) | (1<<PRIM_RX) ) )
|
39 |
|
40 |
|
41 | // Flag which denotes transmitting mode
|
42 | volatile uint8_t PTX;
|
43 |
|
44 | void wl_module_init()
|
45 | // Initializes pins and interrupt to communicate with the wl_module
|
46 | // Should be called in the early initializing phase at startup.
|
47 | {
|
48 | // Define CSN and CE as Output and set them to default
|
49 | DDRB |= ((1<<CSN)|(1<<CE));
|
50 | wl_module_CE_lo;
|
51 | wl_module_CSN_hi;
|
52 |
|
53 |
|
54 | // Initialize spi module
|
55 | spi_init();
|
56 | }
|
57 |
|
58 |
|
59 | void wl_module_config()
|
60 | // Sets the important registers in the wl-module and powers the module
|
61 | // in receiving mode
|
62 | {
|
63 | // Set RF channel
|
64 | wl_module_config_register(RF_CH,wl_module_CH);
|
65 | // Set data speed & Output Power configured in wl_module.h
|
66 | wl_module_config_register(RF_SETUP,wl_module_RF_SETUP);
|
67 | // Set length of incoming payload
|
68 | wl_module_config_register(RX_PW_P0, wl_module_PAYLOAD);
|
69 |
|
70 | // Start receiver
|
71 | PTX = 0; // Start in receiving mode
|
72 | RX_POWERUP; // Power up in receiving mode
|
73 | wl_module_CE_hi; // Listening for pakets
|
74 | }
|
75 |
|
76 | extern void wl_module_rx_config()
|
77 | // Sets the important registers in the wl-module and powers the module
|
78 | // in receiving mode
|
79 | {
|
80 | uint8_t data[5];
|
81 | // Set RF channel
|
82 | wl_module_config_register(RF_CH,wl_module_CH);
|
83 | // Set data speed & Output Power configured in wl_module.h
|
84 | wl_module_config_register(RF_SETUP,wl_module_RF_SETUP);
|
85 | //Enable all RX Data-Pipes
|
86 | wl_module_config_register(EN_RXADDR, EN_RXADDR_ERX_ALL);
|
87 | //Set RX_Address Pipe 0
|
88 | data[0]= data[1]= data[2]= data[3]= data[4]= RX_ADDR_P0_B0_DEFAULT_VAL;
|
89 | wl_module_set_rx_addr(data, 5, 0);
|
90 | //Set RX_Address Pipe 1
|
91 | data[0]= data[1]= data[2]= data[3]= data[4]= RX_ADDR_P1_B0_DEFAULT_VAL;
|
92 | wl_module_set_rx_addr(data, 5, 1);
|
93 | //Set RX_Address Pipe 2-5
|
94 | data[0]=RX_ADDR_P2_DEFAULT_VAL;
|
95 | wl_module_set_rx_addr(data, 1, 2);
|
96 | data[0]=RX_ADDR_P3_DEFAULT_VAL;
|
97 | wl_module_set_rx_addr(data, 1, 3);
|
98 | data[0]=RX_ADDR_P4_DEFAULT_VAL;
|
99 | wl_module_set_rx_addr(data, 1, 4);
|
100 | data[0]=RX_ADDR_P5_DEFAULT_VAL;
|
101 | wl_module_set_rx_addr(data, 1, 5);
|
102 | // Set length of incoming payload
|
103 | wl_module_config_register(RX_PW_P0, wl_module_PAYLOAD);
|
104 | wl_module_config_register(RX_PW_P1, wl_module_PAYLOAD);
|
105 | wl_module_config_register(RX_PW_P2, wl_module_PAYLOAD);
|
106 | wl_module_config_register(RX_PW_P3, wl_module_PAYLOAD);
|
107 | wl_module_config_register(RX_PW_P4, wl_module_PAYLOAD);
|
108 | wl_module_config_register(RX_PW_P5, wl_module_PAYLOAD);
|
109 |
|
110 |
|
111 | // Start receiver
|
112 | PTX = 0; // Start in receiving mode
|
113 | RX_POWERUP; // Power up in receiving mode
|
114 | wl_module_CE_hi; // Listening for pakets
|
115 | }
|
116 |
|
117 | // Sets the wl-module as one of the six sender. Define for every sender a unique Number (wl_module_TX_NR_x)
|
118 | // when you call this Function.
|
119 | // Each TX will get a TX-Address corresponding to the RX-Device.
|
120 | // RX_Address_Pipe_0 must be the same as the TX-Address
|
121 | extern void wl_module_tx_config(uint8_t tx_nr)
|
122 | {
|
123 | uint8_t tx_addr[5];
|
124 |
|
125 | // Set RF channel
|
126 | wl_module_config_register(RF_CH,wl_module_CH);
|
127 | // Set data speed & Output Power configured in wl_module.h
|
128 | wl_module_config_register(RF_SETUP,wl_module_RF_SETUP);
|
129 | //Config the CONFIG Register (Mask IRQ, CRC, etc)
|
130 | wl_module_config_register(CONFIG, wl_module_CONFIG);
|
131 | // Set length of incoming payload
|
132 | wl_module_config_register(RX_PW_P0, wl_module_PAYLOAD);
|
133 |
|
134 | wl_module_config_register(SETUP_RETR,(SETUP_RETR_ARD_750 | SETUP_RETR_ARC_15));
|
135 |
|
136 | //set the TX address for the pipe with the same number as the iteration
|
137 | switch(tx_nr)
|
138 | {
|
139 | case 0: //setup TX address as default RX address for pipe 0 (E7:E7:E7:E7:E7)
|
140 | tx_addr[0] = tx_addr[1] = tx_addr[2] = tx_addr[3] = tx_addr[4] = RX_ADDR_P0_B0_DEFAULT_VAL;
|
141 | wl_module_set_TADDR(tx_addr);
|
142 | wl_module_set_RADDR(tx_addr);
|
143 | break;
|
144 | case 1: //setup TX address as default RX address for pipe 1 (C2:C2:C2:C2:C2)
|
145 | tx_addr[0] = tx_addr[1] = tx_addr[2] = tx_addr[3] = tx_addr[4] = RX_ADDR_P1_B0_DEFAULT_VAL;
|
146 | wl_module_set_TADDR(tx_addr);
|
147 | wl_module_set_RADDR(tx_addr);
|
148 | break;
|
149 | case 2: //setup TX address as default RX address for pipe 2 (C2:C2:C2:C2:C3)
|
150 | tx_addr[1] = tx_addr[2] = tx_addr[3] = tx_addr[4] = RX_ADDR_P1_B0_DEFAULT_VAL;
|
151 | tx_addr[0] = RX_ADDR_P2_DEFAULT_VAL;
|
152 | wl_module_set_TADDR(tx_addr);
|
153 | wl_module_set_RADDR(tx_addr);
|
154 | break;
|
155 | case 3: //setup TX address as default RX address for pipe 3 (C2:C2:C2:C2:C4)
|
156 | tx_addr[1] = tx_addr[2] = tx_addr[3] = tx_addr[4] = RX_ADDR_P1_B0_DEFAULT_VAL;
|
157 | tx_addr[0] = RX_ADDR_P3_DEFAULT_VAL;
|
158 | wl_module_set_TADDR(tx_addr);
|
159 | wl_module_set_RADDR(tx_addr);
|
160 | break;
|
161 | case 4: //setup TX address as default RX address for pipe 4 (C2:C2:C2:C2:C5)
|
162 | tx_addr[1] = tx_addr[2] = tx_addr[3] = tx_addr[4] = RX_ADDR_P1_B0_DEFAULT_VAL;
|
163 | tx_addr[0] = RX_ADDR_P4_DEFAULT_VAL;
|
164 | wl_module_set_TADDR(tx_addr);
|
165 | wl_module_set_RADDR(tx_addr);
|
166 | break;
|
167 | case 5: //setup TX address as default RX address for pipe 5 (C2:C2:C2:C2:C6)
|
168 | tx_addr[1] = tx_addr[2] = tx_addr[3] = tx_addr[4] = RX_ADDR_P1_B0_DEFAULT_VAL;
|
169 | tx_addr[0] = RX_ADDR_P5_DEFAULT_VAL;
|
170 | wl_module_set_TADDR(tx_addr);
|
171 | wl_module_set_RADDR(tx_addr);
|
172 | break;
|
173 | }
|
174 |
|
175 | PTX =0;
|
176 | TX_POWERUP;
|
177 | /*
|
178 | // Start receiver
|
179 | PTX = 0; // Start in receiving mode
|
180 | RX_POWERUP; // Power up in receiving mode
|
181 | wl_module_CE_hi; // Listening for pakets
|
182 | */
|
183 | }
|
184 |
|
185 | //sets the TX address in the TX_ADDR register
|
186 | //unsigned char * address is the actual address to be used. It should be sized
|
187 | // according to the tx_addr length specified to the nrf24l01.
|
188 | //unsigned int len is the length of the address. Its value should be specified
|
189 | // according to the tx_addr length specified to the nrf24l01.
|
190 | extern void wl_module_set_tx_addr(uint8_t * address, uint8_t len)
|
191 | {
|
192 | wl_module_write_register(TX_ADDR, address, len);
|
193 | }
|
194 |
|
195 | //sets up the 24L01 as a transmitter
|
196 | //this function takes the existing contents of the CONFIG register and simply
|
197 | // clears the PRIM_RX bit in the CONFIG register.
|
198 | //note: if the read value of the CONFIG register already has the PRIM_RX bit cleared, this
|
199 | // function exits in order to not make an unecessary register write.
|
200 | extern void wl_module_set_as_tx()
|
201 | {
|
202 | unsigned char config;
|
203 |
|
204 | wl_module_read_register(CONFIG, &config, 1);
|
205 |
|
206 | if((config & CONFIG_PRIM_RX) == 0)
|
207 | return;
|
208 |
|
209 | config &= (~CONFIG_PRIM_RX);
|
210 |
|
211 | wl_module_write_register(CONFIG, &config, 1);
|
212 |
|
213 | wl_module_CE_lo;
|
214 | }
|
215 |
|
216 | //powers down the 24L01
|
217 | //this function takes the existing contents of the CONFIG register and simply
|
218 | // clears the PWR_UP bit in the CONFIG register.
|
219 | //note: if the read value of the CONFIG register already has the PWR_UP bit cleared, this
|
220 | // function exits in order to not make an unecessary register write.
|
221 | extern void wl_module_power_down()
|
222 | {
|
223 | unsigned char config;
|
224 |
|
225 | wl_module_read_register(CONFIG, &config, 1);
|
226 |
|
227 | if((config & CONFIG_PWR_UP) == 0)
|
228 | return;
|
229 |
|
230 | config &= (~CONFIG_PWR_UP);
|
231 |
|
232 | wl_module_write_register(CONFIG, &config, 1);
|
233 |
|
234 | wl_module_CE_lo;
|
235 | }
|
236 |
|
237 | //sets the RX address in the RX_ADDR register that is offset by rxpipenum
|
238 | //unsigned char * address is the actual address to be used. It should be sized
|
239 | // according to the rx_addr length that is being filled.
|
240 | //unsigned int len is the length of the address. Its value should be specified
|
241 | // according to the rx_addr length specified to the nrf24l01.
|
242 | //unsigned char rxpipenum is the pipe number (zero to five) whose address is being
|
243 | // specified. If an invalid address (greater than five) is supplied, the function
|
244 | // does nothing.
|
245 | extern void wl_module_set_rx_addr(uint8_t * address, uint8_t len, uint8_t rxpipenum)
|
246 | {
|
247 | if(rxpipenum > 5)
|
248 | return;
|
249 |
|
250 | wl_module_write_register(RX_ADDR_P0 + rxpipenum, address, len);
|
251 | }
|
252 |
|
253 | extern void wl_module_get_rx_addr(uint8_t *data, uint8_t rxpipenum, uint8_t len)
|
254 | {
|
255 |
|
256 | if((rxpipenum > 5))
|
257 | return;
|
258 |
|
259 | wl_module_read_register(RX_ADDR_P0 + rxpipenum, data, len);
|
260 |
|
261 |
|
262 | }
|
263 |
|
264 | //sets the RX payload width on the pipe offset by rxpipenum
|
265 | //unsigned char payloadwidth is the length of the payload for the pipe referenced in
|
266 | // rxpipenum. It must be less than or equal to 32. If an invalid payload width is
|
267 | // specified, the function does nothing.
|
268 | //unsigned char rxpipenum is the pipe number (zero to five) whose address is being
|
269 | // specified. If an invalid address (greater than five) is supplied, the function
|
270 | // does nothing.
|
271 | extern void wl_module_set_rx_pw(unsigned char payloadwidth, unsigned char rxpipenum)
|
272 | {
|
273 | if((rxpipenum > 5) || (payloadwidth > 32))
|
274 | return;
|
275 |
|
276 | wl_module_write_register(RX_PW_P0 + rxpipenum, &payloadwidth, 1);
|
277 | }
|
278 |
|
279 | //gets the RX payload width on the pipe offset by rxpipenum
|
280 | //unsigned char rxpipenum is the pipe number (zero to five) whose address is being
|
281 | // specified. If an invalid address (greater than five) is supplied, the function
|
282 | // does nothing.
|
283 | extern uint8_t wl_module_get_rx_pw(uint8_t rxpipenum)
|
284 | {
|
285 | unsigned char data;
|
286 |
|
287 | if((rxpipenum > 5))
|
288 | return 0;
|
289 |
|
290 | wl_module_read_register(RX_PW_P0 + rxpipenum, &data, 1);
|
291 |
|
292 | return data;
|
293 | }
|
294 |
|
295 | //returns the current pipe in the 24L01's STATUS register
|
296 | extern uint8_t wl_module_get_rx_pipe()
|
297 | {
|
298 | return wl_module_get_rx_pipe_from_status(wl_module_get_status());
|
299 | }
|
300 |
|
301 | extern uint8_t wl_module_get_rx_pipe_from_status(uint8_t status)
|
302 | {
|
303 | return ((status & 0xE) >> 1);
|
304 | }
|
305 |
|
306 | void wl_module_set_RADDR(uint8_t * adr)
|
307 | // Sets the receiving address
|
308 | {
|
309 | wl_module_CE_lo;
|
310 | wl_module_write_register(RX_ADDR_P0,adr,5);
|
311 | wl_module_CE_hi;
|
312 | }
|
313 |
|
314 | void wl_module_set_TADDR(uint8_t * adr)
|
315 | // Sets the transmitting address
|
316 | {
|
317 | wl_module_write_register(TX_ADDR, adr,5);
|
318 | }
|
319 |
|
320 |
|
321 |
|
322 | extern uint8_t wl_module_data_ready()
|
323 | // Checks if data is available for reading
|
324 | {
|
325 | if (PTX) return 0;
|
326 | uint8_t status;
|
327 | // Read wl_module status
|
328 | wl_module_CSN_lo; // Pull down chip select
|
329 | status = spi_fast_shift(NOP); // Read status register
|
330 | wl_module_CSN_hi; // Pull up chip select
|
331 | return status & (1<<RX_DR);
|
332 | }
|
333 |
|
334 | //returns true if TX_EMPTY bit in FIFO_STATUS register is set, false otherwise
|
335 | extern uint8_t wl_module_fifo_tx_empty()
|
336 | {
|
337 | uint8_t data;
|
338 |
|
339 | wl_module_read_register(FIFO_STATUS, &data, 1);
|
340 |
|
341 |
|
342 | return (data & FIFO_STATUS_TX_EMPTY);
|
343 | }
|
344 |
|
345 | //returns true if RX_EMPTY bit in FIFO_STATUS register is set, false otherwise
|
346 | extern uint8_t wl_module_fifo_rx_empty()
|
347 | {
|
348 | uint8_t data;
|
349 |
|
350 | wl_module_read_register(FIFO_STATUS, &data, 1);
|
351 |
|
352 | return (data & FIFO_STATUS_RX_EMPTY);
|
353 | }
|
354 |
|
355 | //returns the current RF channel in RF_CH register
|
356 | extern uint8_t wl_module_get_rf_ch()
|
357 | {
|
358 | uint8_t data;
|
359 |
|
360 | wl_module_read_register(RF_CH, &data, 1);
|
361 |
|
362 | return data;
|
363 | }
|
364 |
|
365 | //returns the current RF_SETUP Register
|
366 | extern uint8_t wl_module_get_rf_setup()
|
367 | {
|
368 | uint8_t data;
|
369 |
|
370 | wl_module_read_register(RF_SETUP, &data, 1);
|
371 |
|
372 | return data;
|
373 | }
|
374 |
|
375 | //returns the current PLOS_CNT value in OBSERVE_TX register
|
376 | extern uint8_t wl_module_get_plos_cnt()
|
377 | {
|
378 | uint8_t data;
|
379 |
|
380 | wl_module_read_register(OBSERVE_TX, &data, 1);
|
381 |
|
382 | return ((data & OBSERVE_TX_PLOS_CNT) >> 4);
|
383 | }
|
384 |
|
385 | //returns the current ARC_CNT value in OBSERVE_TX register
|
386 | extern uint8_t wl_module_get_arc_cnt()
|
387 | {
|
388 | uint8_t data;
|
389 |
|
390 | wl_module_read_register(OBSERVE_TX, &data, 1);
|
391 |
|
392 | return (data & OBSERVE_TX_ARC_CNT);
|
393 | }
|
394 |
|
395 | //return the value of the status register
|
396 | extern uint8_t wl_module_get_status()
|
397 | {
|
398 | return wl_module_get_one_byte(NOP);
|
399 | }
|
400 |
|
401 | extern uint8_t wl_module_get_rx_pipe_reading_status()
|
402 | {
|
403 | uint8_t pipe;
|
404 | pipe = wl_module_get_one_byte(NOP);
|
405 | return ((pipe & 0x0E) >> 1);
|
406 | }
|
407 |
|
408 | extern uint8_t wl_module_get_one_byte(uint8_t command)
|
409 | {
|
410 | uint8_t status;
|
411 |
|
412 | wl_module_CSN_lo;
|
413 | status = spi_fast_shift(command);
|
414 | wl_module_CSN_hi;
|
415 |
|
416 | return status;
|
417 |
|
418 | }
|
419 |
|
420 | extern uint8_t wl_module_get_data(uint8_t * data)
|
421 | // Reads wl_module_PAYLOAD bytes into data array
|
422 | {
|
423 | uint8_t status;
|
424 | wl_module_CSN_lo; // Pull down chip select
|
425 | status = spi_fast_shift( R_RX_PAYLOAD ); // Send cmd to read rx payload
|
426 | spi_transfer_sync(data,data,wl_module_PAYLOAD); // Read payload
|
427 | wl_module_CSN_hi; // Pull up chip select
|
428 | wl_module_config_register(STATUS,(1<<RX_DR)); // Reset status register
|
429 | return status;
|
430 | }
|
431 |
|
432 | void wl_module_config_register(uint8_t reg, uint8_t value)
|
433 | // Clocks only one byte into the given wl-module register
|
434 | {
|
435 | wl_module_CSN_lo;
|
436 | spi_fast_shift(W_REGISTER | (REGISTER_MASK & reg));
|
437 | spi_fast_shift(value);
|
438 | wl_module_CSN_hi;
|
439 | }
|
440 |
|
441 | void wl_module_read_register(uint8_t reg, uint8_t * value, uint8_t len)
|
442 | // Reads an array of bytes from the given start position in the wl-module registers.
|
443 | {
|
444 | wl_module_CSN_lo;
|
445 | spi_fast_shift(R_REGISTER | (REGISTER_MASK & reg));
|
446 | spi_transfer_sync(value,value,len);
|
447 | wl_module_CSN_hi;
|
448 | }
|
449 |
|
450 | void wl_module_write_register(uint8_t reg, uint8_t * value, uint8_t len)
|
451 | // Writes an array of bytes into inte the wl-module registers.
|
452 | {
|
453 | wl_module_CSN_lo;
|
454 | spi_fast_shift(W_REGISTER | (REGISTER_MASK & reg));
|
455 | spi_transmit_sync(value,len);
|
456 | wl_module_CSN_hi;
|
457 | }
|
458 |
|
459 |
|
460 | void wl_module_send(uint8_t * value, uint8_t len)
|
461 | // Sends a data package to the default address. Be sure to send the correct
|
462 | // amount of bytes as configured as payload on the receiver.
|
463 | {
|
464 | while (PTX) {} // Wait until last paket is send
|
465 |
|
466 | wl_module_CE_lo;
|
467 |
|
468 | PTX = 1; // Set to transmitter mode
|
469 | TX_POWERUP; // Power up
|
470 |
|
471 | wl_module_CSN_lo; // Pull down chip select
|
472 | spi_fast_shift( FLUSH_TX ); // Write cmd to flush tx fifo
|
473 | wl_module_CSN_hi; // Pull up chip select
|
474 |
|
475 | wl_module_CSN_lo; // Pull down chip select
|
476 | spi_fast_shift( W_TX_PAYLOAD ); // Write cmd to write payload
|
477 | spi_transmit_sync(value,len); // Write payload
|
478 | wl_module_CSN_hi; // Pull up chip select
|
479 |
|
480 | wl_module_CE_hi; // Start transmission
|
481 | _delay_us(20); // Grünes Modul funktioniert nicht mit 10µs delay
|
482 | wl_module_CE_lo;
|
483 | }
|