Contiki 3.x
radio.c
1 /**
2  * Copyright (c) 2014, Analog Devices, Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted (subject to the limitations in the
6  * disclaimer below) provided that the following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the
14  * distribution.
15  *
16  * - Neither the name of Analog Devices, Inc. nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
21  * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
22  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
32  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 /**
35  * \author Jim Paris <jim.paris@rigado.com>
36  */
37 
38 #include <string.h>
39 #include <stdint.h>
40 
41 #include <aducrf101-contiki.h>
42 
43 #include "contiki.h"
44 #include "contiki-net.h"
45 #include "net/netstack.h"
46 #include "radio.h"
47 
48 #define MAX_PACKET_LEN 240
49 
50 static uint8_t tx_buf[MAX_PACKET_LEN];
51 
52 #ifndef ADUCRF101_RADIO_BASE_CONFIG
53 #define ADUCRF101_RADIO_BASE_CONFIG DR_38_4kbps_Dev20kHz
54 #endif
55 
56 static RIE_BaseConfigs base_config = ADUCRF101_RADIO_BASE_CONFIG;
57 static int current_channel = 915000000;
58 static int current_power = 31;
59 static int radio_is_on = 0;
60 
61 /*---------------------------------------------------------------------------*/
62 /* Sniffer configuration. We can re-use the CC2538 sniffer application
63  if we also accept CC2538_RF_CONF_SNIFFER. */
64 #ifndef ADUCRF101_RF_CONF_SNIFFER
65 #if CC2538_RF_CONF_SNIFFER
66 #define ADUCRF101_RF_CONF_SNIFFER 1
67 #endif
68 #endif
69 
70 #if ADUCRF101_RF_CONF_SNIFFER
71 #include "dev/uart.h"
72 static const uint8_t magic[] = { 0x53, 0x6E, 0x69, 0x66 }; /* Snif */
73 #endif
74 /*---------------------------------------------------------------------------*/
75 /* "Channel" is really frequency, and can be within the bands:
76  431000000 Hz to 464000000 Hz
77  862000000 Hz to 928000000 Hz
78  */
79 #define MIN_CHANNEL 431000000
80 #define MAX_CHANNEL 928000000
81 static int
82 _set_channel(int freq)
83 {
84  if(freq < 431000000) {
85  freq = 431000000;
86  } else if(freq > 464000000 && freq < 663000000) {
87  freq = 464000000;
88  } else if(freq >= 663000000 && freq < 862000000) {
89  freq = 862000000;
90  } else if(freq > 928000000) {
91  freq = 928000000;
92  }
93  current_channel = freq;
94  if(RadioSetFrequency(freq) != RIE_Success) {
95  return RADIO_RESULT_ERROR;
96  }
97  return RADIO_RESULT_OK;
98 }
99 /*---------------------------------------------------------------------------*/
100 /* "Power" covers both PA type and power level:
101  0 through 15 means single-ended, power level 0 through 15
102  16 through 31 means differential, power level 0 through 15 */
103 #define MIN_POWER 0
104 #define MAX_POWER 31
105 static int
106 _set_power(int power)
107 {
108  RIE_Responses ret;
109  if(power < 0) {
110  power = 0;
111  }
112  if(power > 31) {
113  power = 31;
114  }
115  if(power <= 15) {
116  ret = RadioTxSetPA(SingleEndedPA, power);
117  } else {
118  ret = RadioTxSetPA(DifferentialPA, power - 16);
119  }
120  current_power = power;
121  if(ret != RIE_Success) {
122  return RADIO_RESULT_ERROR;
123  }
124  return RADIO_RESULT_OK;
125 }
126 /*---------------------------------------------------------------------------*/
127 PROCESS(aducrf101_rf_process, "ADuCRF101 RF driver");
128 /*---------------------------------------------------------------------------*/
129 /** Turn the radio on. */
130 static int
131 on(void)
132 {
133  if(radio_is_on) {
134  return 1;
135  }
136 
137  /* Power radio on */
138  if(RadioInit(base_config) != RIE_Success) {
139  return 0;
140  }
141 
142  /* Ensure channel and power are set */
143  if(_set_channel(current_channel) != RADIO_RESULT_OK) {
144  return 0;
145  }
146  if(_set_power(current_power) != RADIO_RESULT_OK) {
147  return 0;
148  }
149 
150  /* Enter receive mode */
152 
153  radio_is_on = 1;
154  return 1;
155 }
156 /*---------------------------------------------------------------------------*/
157 /** Turn the radio off. */
158 static int
159 off(void)
160 {
161  if(!radio_is_on) {
162  return 1;
163  }
164  if(RadioPowerOff() != RIE_Success) {
165  return 0;
166  }
167  radio_is_on = 0;
168  return 1;
169 }
170 /*---------------------------------------------------------------------------*/
171 static int
172 init(void)
173 {
174  off();
175  on();
176  process_start(&aducrf101_rf_process, NULL);
177  return 1;
178 }
179 /*---------------------------------------------------------------------------*/
180 /** Prepare the radio with a packet to be sent. */
181 static int
182 prepare(const void *payload, unsigned short payload_len)
183 {
184  /* Truncate long packets */
185  if(payload_len > MAX_PACKET_LEN) {
186  payload_len = MAX_PACKET_LEN;
187  }
188  memcpy(tx_buf, payload, payload_len);
189  return 0;
190 }
191 /*---------------------------------------------------------------------------*/
192 /** Send the packet that has previously been prepared. */
193 static int
194 transmit(unsigned short transmit_len)
195 {
196  if(!radio_is_on)
197  return RADIO_TX_ERR;
198 
199  /* Transmit the packet */
200  if(transmit_len > MAX_PACKET_LEN) {
201  transmit_len = MAX_PACKET_LEN;
202  }
203  if(RadioTxPacketVariableLen(transmit_len, tx_buf) != RIE_Success) {
204  return RADIO_TX_ERR;
205  }
206  while(!RadioTxPacketComplete())
207  continue;
208 
209  /* Enter receive mode immediately after transmitting a packet */
211 
212  return RADIO_TX_OK;
213 }
214 /*---------------------------------------------------------------------------*/
215 /** Prepare & transmit a packet. */
216 static int
217 send(const void *payload, unsigned short payload_len)
218 {
219  prepare(payload, payload_len);
220  return transmit(payload_len);
221 }
222 /*---------------------------------------------------------------------------*/
223 /** Read a received packet into a buffer. */
224 static int
225 read(void *buf, unsigned short buf_len)
226 {
227  uint8_t packet_len;
228  int8_t rssi;
229 
230  if(!radio_is_on)
231  return 0;
232 
233  if(buf_len > MAX_PACKET_LEN) {
234  buf_len = MAX_PACKET_LEN;
235  }
236 
237  /* Read already-received packet */
238  if(RadioRxPacketRead(buf_len, &packet_len, buf, &rssi) != RIE_Success) {
239  return 0;
240  }
241 
242  if(packet_len > buf_len) {
243  packet_len = buf_len;
244  }
245 
246  /* Re-enter receive mode immediately after receiving a packet */
248 
249 #if ADUCRF101_RF_CONF_SNIFFER
250  uart_put(magic[0]);
251  uart_put(magic[1]);
252  uart_put(magic[2]);
253  uart_put(magic[3]);
254  uart_put(packet_len + 2);
255  for(int i = 0; i < packet_len; i++) {
256  uart_put(((uint8_t *)buf)[i]);
257  }
258  /* FCS value is Wireshark's "TI CC24xx format" option: */
259  uart_put(rssi); /* RSSI */
260  uart_put(0x80); /* CRC is OK, LQI correlation is 0 */
261 #endif
262 
263  return packet_len;
264 }
265 /*---------------------------------------------------------------------------*/
266 /** Perform a Clear-Channel Assessment (CCA) to find out if there is
267  a packet in the air or not. */
268 static int
269 channel_clear(void)
270 {
271  /* Not implemented; assume clear */
272  return 1;
273 }
274 /*---------------------------------------------------------------------------*/
275 /** Check if the radio driver is currently receiving a packet */
276 static int
277 receiving_packet(void)
278 {
279  /* Not implemented; assume no. */
280  return 0;
281 }
282 /*---------------------------------------------------------------------------*/
283 /** Check if the radio driver has just received a packet */
284 static int
285 pending_packet(void)
286 {
287  if(RadioRxPacketAvailable()) {
288  return 1;
289  }
290  return 0;
291 }
292 /*---------------------------------------------------------------------------*/
293 /** Get a radio parameter value. */
294 static radio_result_t
295 get_value(radio_param_t param, radio_value_t *value)
296 {
297  if(!value) {
298  return RADIO_RESULT_INVALID_VALUE;
299  }
300 
301  switch(param) {
302  case RADIO_PARAM_RSSI:
303  {
304  int8_t dbm;
305  if(!radio_is_on || RadioRadioGetRSSI(&dbm) != RIE_Success) {
306  return RADIO_RESULT_ERROR;
307  }
308  *value = dbm;
309  return RADIO_RESULT_OK;
310  }
311 
312  case RADIO_PARAM_CHANNEL:
313  *value = current_channel;
314  return RADIO_RESULT_OK;
315  case RADIO_CONST_CHANNEL_MIN:
316  *value = MIN_CHANNEL;
317  return RADIO_RESULT_OK;
318  case RADIO_CONST_CHANNEL_MAX:
319  *value = MAX_CHANNEL;
320  return RADIO_RESULT_OK;
321 
322  case RADIO_PARAM_TXPOWER:
323  *value = current_power;
324  return RADIO_RESULT_OK;
325  case RADIO_CONST_TXPOWER_MIN:
326  *value = MIN_POWER;
327  return RADIO_RESULT_OK;
328  case RADIO_CONST_TXPOWER_MAX:
329  *value = MAX_POWER;
330  return RADIO_RESULT_OK;
331 
332  default:
333  return RADIO_RESULT_NOT_SUPPORTED;
334  }
335 }
336 /*---------------------------------------------------------------------------*/
337 /** Set a radio parameter value. */
338 static radio_result_t
339 set_value(radio_param_t param, radio_value_t value)
340 {
341  switch(param) {
342  case RADIO_PARAM_CHANNEL:
343  return _set_channel(value);
344 
345  case RADIO_PARAM_TXPOWER:
346  return _set_power(value);
347 
348  default:
349  return RADIO_RESULT_NOT_SUPPORTED;
350  }
351 }
352 /*---------------------------------------------------------------------------*/
353 /**
354  * Get a radio parameter object. The argument 'dest' must point to a
355  * memory area of at least 'size' bytes, and this memory area will
356  * contain the parameter object if the function succeeds.
357  */
358 static radio_result_t
359 get_object(radio_param_t param, void *dest, size_t size)
360 {
361  return RADIO_RESULT_NOT_SUPPORTED;
362 }
363 /*---------------------------------------------------------------------------*/
364 /**
365  * Set a radio parameter object. The memory area referred to by the
366  * argument 'src' will not be accessed after the function returns.
367  */
368 static radio_result_t
369 set_object(radio_param_t param, const void *src, size_t size)
370 {
371  return RADIO_RESULT_NOT_SUPPORTED;
372 }
373 /*---------------------------------------------------------------------------*/
374 /**
375  * \brief Implementation of the ADuCRF101 RF driver process
376  *
377  * This process is started by init(). It waits for events triggered
378  * by packet reception.
379  */
380 PROCESS_THREAD(aducrf101_rf_process, ev, data)
381 {
382  int len;
383  PROCESS_BEGIN();
384 
385  while(1) {
386  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
387 
388  packetbuf_clear();
389  len = read(packetbuf_dataptr(), PACKETBUF_SIZE);
390 
391  if(len > 0) {
393 
394  NETSTACK_RDC.input();
395  }
396  }
397 
398  PROCESS_END();
399 }
400 /*---------------------------------------------------------------------------*/
401 /**
402  * \brief Trigger function called by ADI radio engine upon packet RX.
403  */
404 void
406 {
407  process_poll(&aducrf101_rf_process);
408 }
409 /*---------------------------------------------------------------------------*/
410 const struct radio_driver aducrf101_radio_driver = {
411  .init = init,
412  .prepare = prepare,
413  .transmit = transmit,
414  .send = send,
415  .read = read,
416  .channel_clear = channel_clear,
417  .receiving_packet = receiving_packet,
418  .pending_packet = pending_packet,
419  .on = on,
420  .off = off,
421  .get_value = get_value,
422  .set_value = set_value,
423  .get_object = get_object,
424  .set_object = set_object,
425 };
RIE_BOOL RadioTxPacketComplete(void)
Checks if a packet has finished transmitting.
Definition: radioeng.c:858
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define NULL
The null pointer.
The structure of a device driver for a radio in Contiki.
Definition: radio.h:225
RIE_Responses RadioRxPacketRead(RIE_U8 BufferLen, RIE_U8 *pPktLen, RIE_U8 *pData, RIE_S8 *pRSSIdBm)
Read the packet that was received by the radio.
Definition: radioeng.c:1125
int(* pending_packet)(void)
Check if the radio driver has just received a packet.
Definition: radio.h:249
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio...
Definition: radio.h:88
int(* prepare)(const void *payload, unsigned short payload_len)
Prepare the radio with a packet to be sent.
Definition: radio.h:230
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:200
void aducrf101_rx_packet_hook(void)
Trigger function called by ADI radio engine upon packet RX.
Definition: radio.c:405
int(* send)(const void *payload, unsigned short payload_len)
Prepare &amp; transmit a packet.
Definition: radio.h:236
RIE_BOOL RadioRxPacketAvailable(void)
Checks if a packet has been received.
Definition: radioeng.c:1092
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
Definition: radio.h:246
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
RIE_Responses
Definition: radioeng.h:131
int(* channel_clear)(void)
Perform a Clear-Channel Assessment (CCA) to find out if there is a packet in the air or not...
Definition: radio.h:243
RIE_Responses RadioPowerOff(void)
Shutdown the radio and place it in its lowest power sleep mode.
Definition: radioeng.c:521
RIE_Responses RadioRadioGetRSSI(RIE_S8 *pRSSIdBm)
Return a Received Signal Strength Indicator value.
Definition: radioeng.c:1692
int(* on)(void)
Turn the radio on.
Definition: radio.h:252
radio_result_t(* get_value)(radio_param_t param, radio_value_t *value)
Get a radio parameter value.
Definition: radio.h:258
RIE_Responses RadioSetFrequency(RIE_U32 Frequency)
Set frequency for radio communications.
Definition: radioeng.c:574
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
Definition: radio.h:268
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
int(* transmit)(unsigned short transmit_len)
Send the packet that has previously been prepared.
Definition: radio.h:233
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:77
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
RIE_Responses RadioRxPacketVariableLen(void)
Enter receive mode and wait for a packet to be received.
Definition: radioeng.c:1050
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:65
RIE_Responses RadioTxSetPA(RIE_PATypes PAType, RIE_PAPowerLevel Power)
Set PA Type and the Transmit Power Level for Radio Transmission.
Definition: radioeng.c:879
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:207
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
Definition: radio.h:274
RIE_Responses RadioTxPacketVariableLen(RIE_U8 Len, RIE_U8 *pData)
Transmit a Variable length packet.
Definition: radioeng.c:813
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
RIE_Responses RadioInit(RIE_BaseConfigs BaseConfig)
Initialise the Radio, using specified configuration.
Definition: radioeng.c:396
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
Definition: radio.h:261
int(* read)(void *buf, unsigned short buf_len)
Read a received packet into a buffer.
Definition: radio.h:239
int(* off)(void)
Turn the radio off.
Definition: radio.h:255
Include file for the Contiki low-layer network stack (NETSTACK)
RIE_BaseConfigs
Definition: radioeng.h:62