Contiki 2.5
stm32w-radio.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, STMicroelectronics.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following
12  * disclaimer in the documentation and/or other materials provided
13  * with the distribution.
14  * 3. The name of the author may not be used to endorse or promote
15  * products derived from this software without specific prior
16  * written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * This file is part of the Contiki OS
31  *
32  * $Id: stm32w-radio.c,v 1.2 2010/10/27 14:05:23 salvopitru Exp $
33  */
34 /*---------------------------------------------------------------------------*/
35 /**
36 * \file
37 * Machine dependent STM32W radio code.
38 * \author
39 * Salvatore Pitrulli
40 */
41 /*---------------------------------------------------------------------------*/
42 
43 #include PLATFORM_HEADER
44 #include "hal/error.h"
45 #include "hal/hal.h"
46 
47 #include "contiki.h"
48 
49 #include "net/mac/frame802154.h"
50 
51 #include "dev/stm32w-radio.h"
52 #include "net/netstack.h"
53 
54 #include "net/packetbuf.h"
55 #include "net/rime/rimestats.h"
56 
57 
58 
59 #define DEBUG 0
60 #include "dev/leds.h"
61 #define LED_ACTIVITY 0
62 
63 
64 #if DEBUG > 0
65 #include <stdio.h>
66 #define PRINTF(...) printf(__VA_ARGS__)
67 #else
68 #define PRINTF(...) do {} while (0)
69 #endif
70 
71 #if LED_ACTIVITY
72 #define LED_TX_ON() leds_on(LEDS_GREEN)
73 #define LED_TX_OFF() leds_off(LEDS_GREEN)
74 #define LED_RX_ON() leds_on(LEDS_RED)
75 #define LED_RX_OFF() leds_off(LEDS_RED)
76 #else
77 #define LED_TX_ON()
78 #define LED_TX_OFF()
79 #define LED_RX_ON()
80 #define LED_RX_OFF()
81 #endif
82 
83 #ifndef MAC_RETRIES
84 #define MAC_RETRIES 1
85 #endif
86 
87 #if MAC_RETRIES
88 
89  int8_t mac_retries_left;
90 
91  #define INIT_RETRY_CNT() (mac_retries_left = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS))
92  #define DEC_RETRY_CNT() (mac_retries_left--)
93  #define RETRY_CNT_GTZ() (mac_retries_left > 0)
94 
95 #else
96 
97  #define INIT_RETRY_CNT()
98  #define DEC_RETRY_CNT()
99  #define RETRY_CNT_GTZ() 0
100 
101 #endif
102 
103 
104 /* If set to 1, a send() returns only after the packet has been transmitted.
105  This is necessary if you use the x-mac module, for example. */
106 #ifndef RADIO_WAIT_FOR_PACKET_SENT
107 #define RADIO_WAIT_FOR_PACKET_SENT 1
108 #endif
109 
110 #define TO_PREV_STATE() { \
111  if(onoroff == OFF){ \
112  ST_RadioSleep(); \
113  ENERGEST_OFF(ENERGEST_TYPE_LISTEN); \
114  } \
115  }
116 
117 const RadioTransmitConfig radioTransmitConfig = {
118  TRUE, // waitForAck;
119  TRUE, // checkCca; // Set to FALSE with low-power MACs.
120  4, // ccaAttemptMax;
121  2, // backoffExponentMin;
122  6, // backoffExponentMax;
123  TRUE // appendCrc;
124 };
125 
126 /*
127  * The buffers which hold incoming data.
128  */
129 #ifndef RADIO_RXBUFS
130 #define RADIO_RXBUFS 1
131 #endif
132 
133 static uint8_t stm32w_rxbufs[RADIO_RXBUFS][STM32W_MAX_PACKET_LEN+1]; // +1 because of the first byte, which will contain the length of the packet.
134 
135 #if RADIO_RXBUFS > 1
136 static volatile int8_t first = -1, last=0;
137 #else
138 static const int8_t first=0, last=0;
139 #endif
140 
141 #if RADIO_RXBUFS > 1
142  #define CLEAN_RXBUFS() do{first = -1; last = 0;}while(0)
143  #define RXBUFS_EMPTY() (first == -1)
144 
145 int RXBUFS_FULL(){
146 
147  int8_t first_tmp = first;
148  return first_tmp == last;
149 }
150 
151 #else /* RADIO_RXBUFS > 1 */
152  #define CLEAN_RXBUFS() (stm32w_rxbufs[0][0] = 0)
153  #define RXBUFS_EMPTY() (stm32w_rxbufs[0][0] == 0)
154  #define RXBUFS_FULL() (stm32w_rxbufs[0][0] != 0)
155 #endif /* RADIO_RXBUFS > 1 */
156 
157 static uint8_t __attribute__(( aligned(2) )) stm32w_txbuf[STM32W_MAX_PACKET_LEN+1];
158 
159 
160 #define CLEAN_TXBUF() (stm32w_txbuf[0] = 0)
161 #define TXBUF_EMPTY() (stm32w_txbuf[0] == 0)
162 
163 #define CHECKSUM_LEN 2
164 
165 /*
166  * The transceiver state.
167  */
168 #define ON 0
169 #define OFF 1
170 
171 static volatile uint8_t onoroff = OFF;
172 static uint8_t receiving_packet = 0;
173 static s8 last_rssi;
174 static volatile StStatus last_tx_status;
175 
176 /*---------------------------------------------------------------------------*/
177 PROCESS(stm32w_radio_process, "STM32W radio driver");
178 /*---------------------------------------------------------------------------*/
179 
180 static int stm32w_radio_init(void);
181 static int stm32w_radio_prepare(const void *payload, unsigned short payload_len);
182 static int stm32w_radio_transmit(unsigned short payload_len);
183 static int stm32w_radio_send(const void *data, unsigned short len);
184 static int stm32w_radio_read(void *buf, unsigned short bufsize);
185 static int stm32w_radio_channel_clear(void);
186 static int stm32w_radio_receiving_packet(void);
187 static int stm32w_radio_pending_packet(void);
188 static int stm32w_radio_on(void);
189 static int stm32w_radio_off(void);
190 
191 static int add_to_rxbuf(uint8_t * src);
192 static int read_from_rxbuf(void * dest, unsigned short len);
193 
194 
195 const struct radio_driver stm32w_radio_driver =
196  {
197  stm32w_radio_init,
198  stm32w_radio_prepare,
199  stm32w_radio_transmit,
200  stm32w_radio_send,
201  stm32w_radio_read,
202  stm32w_radio_channel_clear,
203  stm32w_radio_receiving_packet,
204  stm32w_radio_pending_packet,
205  stm32w_radio_on,
206  stm32w_radio_off,
207  };
208 /*---------------------------------------------------------------------------*/
209 static int stm32w_radio_init(void)
210 {
211 
212  // A channel needs also to be setted.
213  ST_RadioSetChannel(RF_CHANNEL);
214 
215  // Initialize radio (analog section, digital baseband and MAC).
216  // Leave radio powered up in non-promiscuous rx mode.
217  ST_RadioInit(ST_RADIO_POWER_MODE_OFF);
218  onoroff = OFF;
219  ST_RadioSetNodeId(STM32W_NODE_ID); // To be deleted.
220  ST_RadioSetPanId(IEEE802154_PANID);
221 
222  CLEAN_RXBUFS();
223  CLEAN_TXBUF();
224 
225  process_start(&stm32w_radio_process, NULL);
226 
227  return 0;
228 }
229 /*---------------------------------------------------------------------------*/
230 int stm32w_radio_set_channel(u8_t channel)
231 {
232  if (ST_RadioSetChannel(channel) == ST_SUCCESS)
233  return 0;
234  else
235  return 1;
236 }
237 /*---------------------------------------------------------------------------*/
238 static int wait_for_tx(void){
239 
240  struct timer t;
241 
242  timer_set(&t, CLOCK_SECOND/10);
243  while(!TXBUF_EMPTY()){
244  if(timer_expired(&t)){
245  PRINTF("stm32w: tx buffer full.\r\n");
246  return 1;
247  }
248  /* Put CPU in sleep mode. */
249  halSleepWithOptions(SLEEPMODE_IDLE,0);
250  }
251  return 0;
252 }
253 /*---------------------------------------------------------------------------*/
254 static int stm32w_radio_prepare(const void *payload, unsigned short payload_len)
255 {
256  if(payload_len > STM32W_MAX_PACKET_LEN){
257  PRINTF("stm32w: payload length=%d is too long.\r\n", payload_len);
258  return RADIO_TX_ERR;
259  }
260 
261 #if !RADIO_WAIT_FOR_PACKET_SENT
262  /* Check if the txbuf is empty.
263  * Wait for a finite time.
264  * This sould not occur if we wait for the end of transmission in stm32w_radio_transmit().
265  */
266  if(wait_for_tx()){
267  PRINTF("stm32w: tx buffer full.\r\n");
268  return RADIO_TX_ERR;
269  }
270 #endif /* RADIO_WAIT_FOR_PACKET_SENT */
271 
272  /* Copy to the txbuf.
273  * The first byte must be the packet length.
274  */
275  CLEAN_TXBUF();
276  memcpy(stm32w_txbuf + 1, payload, payload_len);
277 
278  return RADIO_TX_OK;
279 
280 }
281 /*---------------------------------------------------------------------------*/
282 static int stm32w_radio_transmit(unsigned short payload_len)
283 {
284  stm32w_txbuf[0] = payload_len + CHECKSUM_LEN;
285 
286  INIT_RETRY_CNT();
287 
288  if(onoroff == OFF){
289  PRINTF("stm32w: Radio is off, turning it on.\r\n");
290  ST_RadioWake();
291  ENERGEST_ON(ENERGEST_TYPE_LISTEN);
292  }
293 
294  LED_TX_ON();
295  if(ST_RadioTransmit(stm32w_txbuf)==ST_SUCCESS){
296 
297  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
298  ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
299 
300  PRINTF("stm32w: sending %d bytes\r\n", payload_len);
301 
302 #if DEBUG > 1
303  for(u8_t c=1; c <= stm32w_txbuf[0]-2; c++){
304  PRINTF("%x:",stm32w_txbuf[c]);
305  }
306  PRINTF("\r\n");
307 #endif
308 
309 #if RADIO_WAIT_FOR_PACKET_SENT
310 
311  if(wait_for_tx()){
312  PRINTF("stm32w: unknown tx error.\r\n");
313  TO_PREV_STATE();
314  LED_TX_OFF();
315  return RADIO_TX_ERR;
316  }
317 
318  TO_PREV_STATE();
319  if(last_tx_status == ST_SUCCESS || last_tx_status == ST_PHY_ACK_RECEIVED){
320  return RADIO_TX_OK;
321  }
322  LED_TX_OFF();
323  return RADIO_TX_ERR;
324 
325 #else /* RADIO_WAIT_FOR_PACKET_SENT */
326 
327  TO_PREV_STATE();
328  LED_TX_OFF();
329  return RADIO_TX_OK;
330 
331 #endif /* RADIO_WAIT_FOR_PACKET_SENT */
332 
333  }
334 
335  TO_PREV_STATE();
336 
337  PRINTF("stm32w: transmission never started.\r\n");
338  /* TODO: Do we have to retransmit? */
339 
340  CLEAN_TXBUF();
341  LED_TX_OFF();
342  return RADIO_TX_ERR;
343 
344 }
345 /*---------------------------------------------------------------------------*/
346 static int stm32w_radio_send(const void *payload, unsigned short payload_len)
347 {
348  if(stm32w_radio_prepare(payload, payload_len) == RADIO_TX_ERR)
349  return RADIO_TX_ERR;
350 
351  return stm32w_radio_transmit(payload_len);
352 
353 }
354 /*---------------------------------------------------------------------------*/
355 static int stm32w_radio_channel_clear(void)
356 {
357  return ST_RadioChannelIsClear();
358 }
359 /*---------------------------------------------------------------------------*/
360 static int stm32w_radio_receiving_packet(void)
361 {
362  return receiving_packet;
363 }
364 /*---------------------------------------------------------------------------*/
365 static int stm32w_radio_pending_packet(void)
366 {
367  return !RXBUFS_EMPTY();
368 }
369 /*---------------------------------------------------------------------------*/
370 static int stm32w_radio_off(void)
371 {
372  /* Any transmit or receive packets in progress are aborted.
373  * Waiting for end of transmission or reception have to be done.
374  */
375  if(onoroff == ON){
376  ST_RadioSleep();
377  onoroff = OFF;
378  CLEAN_TXBUF();
379  CLEAN_RXBUFS();
380 
381  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
382  }
383 
384  return 1;
385 }
386 /*---------------------------------------------------------------------------*/
387 static int stm32w_radio_on(void)
388 {
389  if(onoroff == OFF){
390  ST_RadioWake();
391  onoroff = ON;
392 
393  ENERGEST_ON(ENERGEST_TYPE_LISTEN);
394  }
395 
396  return 1;
397 }
398 /*---------------------------------------------------------------------------*/
399 int stm32w_radio_is_on(void)
400 {
401  return onoroff == ON;
402 }
403 /*---------------------------------------------------------------------------*/
404 
405 
407  boolean ackFramePendingSet,
408  u32 time,
409  u16 errors,
410  s8 rssi)
411 {
412  LED_RX_ON();
413  receiving_packet = 0;
414  /* Copy packet into the buffer. It is better to do this here. */
415  if(add_to_rxbuf(packet)){
416  process_poll(&stm32w_radio_process);
417  last_rssi = rssi;
418  }
419  LED_RX_OFF();
420 }
421 
422 
424  u32 txSyncTime,
425  boolean framePending)
426 {
427 
428  ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
429  ENERGEST_ON(ENERGEST_TYPE_LISTEN);
430  LED_TX_OFF();
431 
432  last_tx_status = status;
433 
434  if(status == ST_SUCCESS || status == ST_PHY_ACK_RECEIVED){
435  CLEAN_TXBUF();
436  }
437  else {
438 
439  if(RETRY_CNT_GTZ()){
440  // Retransmission
441  LED_TX_ON();
442  if(ST_RadioTransmit(stm32w_txbuf)==ST_SUCCESS){
443 
444  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
445  ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
446 
447  PRINTF("stm32w: retransmission.\r\n");
448 
449  DEC_RETRY_CNT();
450  }
451  else {
452  CLEAN_TXBUF();
453  LED_TX_OFF();
454  PRINTF("stm32w: retransmission failed.\r\n");
455  }
456  }
457  else {
458  CLEAN_TXBUF();
459  }
460  }
461 
462  /* Debug outputs. */
463  if(status == ST_SUCCESS || status == ST_PHY_ACK_RECEIVED){
464  PRINTF("TX_END");
465  }
466  else if (status == ST_MAC_NO_ACK_RECEIVED){
467  PRINTF("TX_END_NOACK!!!");
468  }
469  else if (status == ST_PHY_TX_CCA_FAIL){
470  PRINTF("TX_END_CCA!!!");
471  }
472  else if(status == ST_PHY_TX_UNDERFLOW){
473  PRINTF("TX_END_UFL!!!");
474  }
475  else {
476  PRINTF("TX_END_INCOMPL!!!");
477  }
478 }
479 
480 
481 boolean ST_RadioDataPendingShortIdIsrCallback(int16u shortId) {
482  receiving_packet = 1;
483  return FALSE;
484 }
485 
486 boolean ST_RadioDataPendingLongIdIsrCallback(int8u* longId) {
487  receiving_packet = 1;
488  return FALSE;
489 }
490 /*---------------------------------------------------------------------------*/
491 PROCESS_THREAD(stm32w_radio_process, ev, data)
492 {
493  int len;
494 
495  PROCESS_BEGIN();
496 
497  PRINTF("stm32w_radio_process: started\r\n");
498 
499  while(1) {
500 
501  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
502 
503  PRINTF("stm32w_radio_process: calling receiver callback\r\n");
504 
505 #if DEBUG > 1
506  for(u8_t c=1; c <= RCVD_PACKET_LEN; c++){
507  PRINTF("%x",stm32w_rxbuf[c]);
508  }
509  PRINTF("\r\n");
510 #endif
511 
512  packetbuf_clear();
513  len = stm32w_radio_read(packetbuf_dataptr(), PACKETBUF_SIZE);
514  if(len > 0) {
515  packetbuf_set_datalen(len);
516  NETSTACK_RDC.input();
517  }
518  if(!RXBUFS_EMPTY()){
519  // Some data packet still in rx buffer (this happens because process_poll doesn't queue requests),
520  // so stm32w_radio_process need to be called again.
521  process_poll(&stm32w_radio_process);
522  }
523  }
524 
525  PROCESS_END();
526 }
527 /*---------------------------------------------------------------------------*/
528 static int stm32w_radio_read(void *buf, unsigned short bufsize)
529 {
530  return read_from_rxbuf(buf,bufsize);
531 }
532 
533 /*---------------------------------------------------------------------------*/
535 {
536  PRINTF("OVERFLOW\r\n");
537 }
538 /*---------------------------------------------------------------------------*/
539 void ST_RadioSfdSentIsrCallback(u32 sfdSentTime)
540 {
541 }
542 /*---------------------------------------------------------------------------*/
544 {
545 }
546 /*---------------------------------------------------------------------------*/
547 static int add_to_rxbuf(uint8_t * src)
548 {
549  if(RXBUFS_FULL()){
550  return 0;
551  }
552 
553  memcpy(stm32w_rxbufs[last], src, src[0] + 1);
554 #if RADIO_RXBUFS > 1
555  last = (last + 1) % RADIO_RXBUFS;
556  if(first == -1){
557  first = 0;
558  }
559 #endif
560 
561  return 1;
562 }
563 /*---------------------------------------------------------------------------*/
564 static int read_from_rxbuf(void * dest, unsigned short len)
565 {
566 
567  if(RXBUFS_EMPTY()){ // Buffers are all empty
568  return 0;
569  }
570 
571  if(stm32w_rxbufs[first][0] > len){ // Too large packet for dest.
572  len = 0;
573  }
574  else {
575  len = stm32w_rxbufs[first][0];
576  memcpy(dest,stm32w_rxbufs[first]+1,len);
577  packetbuf_set_attr(PACKETBUF_ATTR_RSSI, last_rssi);
578  }
579 
580 #if RADIO_RXBUFS > 1
581  ATOMIC(
582  first = (first + 1) % RADIO_RXBUFS;
583  int first_tmp = first;
584  if(first_tmp == last){
585  CLEAN_RXBUFS();
586  }
587  )
588 #else
589  CLEAN_RXBUFS();
590 #endif
591 
592  return len;
593 }
594 /*---------------------------------------------------------------------------*/
595 short last_packet_rssi(){
596  return last_rssi;
597 }
598