Contiki 3.x
micromac-radio.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, NXP and SICS Swedish ICT.
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 copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * Contiki driver for NXP JN516X using MMAC interface
36  * \authors
37  * Beshr Al Nahas <beshr@sics.se>
38  * Simon Duquennot <simonduq@sics.se>
39  * Atis Elsts <atis.elsts@sics.se>
40  *
41  */
42 
43 #include <string.h>
44 #include "contiki.h"
45 #include "dev/leds.h"
46 #include "sys/rtimer.h"
47 #include "net/packetbuf.h"
48 #include "net/rime/rimestats.h"
49 #include "net/netstack.h"
50 #include "net/mac/frame802154.h"
51 #include "lib/crc16.h"
52 #include "lib/ringbufindex.h"
53 
54 #include "AppHardwareApi.h"
55 #include "MMAC.h"
56 #include "micromac-radio.h"
57 #include "JPT.h"
58 #include "PeripheralRegs.h"
59 
60 void vMMAC_SetChannelAndPower(uint8 u8Channel, int8 i8power);
61 
62 /* This driver configures the radio in PHY mode and does address decoding
63  * and acknowledging in software. */
64 
65 #define DEBUG DEBUG_NONE
66 #include "net/ip/uip-debug.h"
67 
68 /* Perform CRC check for received packets in SW,
69  * since we use PHY mode which does not calculate CRC in HW */
70 #define CRC_SW 1
71 
72 #define CHECKSUM_LEN 2
73 
74 /* Max packet duration: 5 + 127 + 2 bytes, 32us per byte */
75 #define MAX_PACKET_DURATION US_TO_RTIMERTICKS((127 + 2) * 32 + RADIO_DELAY_BEFORE_TX)
76 /* Max ACK duration: 5 + 3 + 2 bytes */
77 #define MAX_ACK_DURATION US_TO_RTIMERTICKS((3 + 2) * 32 + RADIO_DELAY_BEFORE_TX)
78 
79 /* Test-mode pins output on dev-kit */
80 #define RADIO_TEST_MODE_HIGH_PWR 1
81 #define RADIO_TEST_MODE_ADVANCED 2
82 #define RADIO_TEST_MODE_DISABLED 0
83 
84 #ifndef RADIO_TEST_MODE
85 #define RADIO_TEST_MODE RADIO_TEST_MODE_DISABLED
86 #endif /* RADIO_TEST_MODE */
87 
88 /* The number of input buffers */
89 #ifndef MIRCOMAC_CONF_BUF_NUM
90 #define MIRCOMAC_CONF_BUF_NUM 2
91 #endif /* MIRCOMAC_CONF_BUF_NUM */
92 
93 /* Init radio channel */
94 #ifndef MICROMAC_CONF_CHANNEL
95 #define MICROMAC_CONF_CHANNEL 26
96 #endif
97 
98 /* Default energy level threshold for clear channel detection */
99 #ifndef MICROMAC_CONF_CCA_THR
100 #define MICROMAC_CONF_CCA_THR 39 /* approximately -85 dBm */
101 #endif /* MICROMAC_CONF_CCA_THR */
102 
103 #if (JENNIC_CHIP == JN5169)
104 #define OUTPUT_POWER_MAX 10
105 #define OUTPUT_POWER_MIN (-32)
106 #define ABS_OUTPUT_POWER_MIN (32)
107 #else
108 #define OUTPUT_POWER_MAX 0
109 #define OUTPUT_POWER_MIN (-32)
110 #endif
111 
112 /* Default Tx power [dBm] (between OUTPUT_POWER_MIN and OUTPUT_POWER_MAX) */
113 #ifndef MICROMAC_CONF_TX_POWER
114 #define MICROMAC_CONF_TX_POWER 0
115 #endif
116 
117 /* Autoack */
118 #ifndef MICROMAC_CONF_AUTOACK
119 #define MICROMAC_CONF_AUTOACK 1
120 #endif /* MICROMAC_CONF_AUTOACK */
121 
122 /* Set radio always on for now because this is what Contiki MAC layers
123  * expect. */
124 #ifndef MICROMAC_CONF_ALWAYS_ON
125 #define MICROMAC_CONF_ALWAYS_ON 1
126 #endif /* MICROMAC_CONF_ALWAYS_ON */
127 
128 #define BUSYWAIT_UNTIL(cond, max_time) \
129  do { \
130  rtimer_clock_t t0; \
131  t0 = RTIMER_NOW(); \
132  while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) ; \
133  } while(0)
134 
135 /* Local variables */
136 static volatile signed char radio_last_rssi;
137 static volatile uint8_t radio_last_correlation; /* LQI */
138 
139 /* Did we miss a request to turn the radio on due to overflow? */
140 static volatile uint8_t missed_radio_on_request = 0;
141 
142 /* Poll mode disabled by default */
143 static uint8_t poll_mode = 0;
144 /* (Software) frame filtering enabled by default */
145 static uint8_t frame_filtering = 1;
146 /* (Software) autoack */
147 static uint8_t autoack_enabled = MICROMAC_CONF_AUTOACK;
148 /* CCA before sending? Disabled by default. */
149 static uint8_t send_on_cca = 0;
150 
151 /* Current radio channel */
152 static int current_channel = MICROMAC_CONF_CHANNEL;
153 
154 /* Current set point tx power
155  Actual tx power may be different. Use get_txpower() for actual power */
156 static int current_tx_power = MICROMAC_CONF_TX_POWER;
157 
158 /* an integer between 0 and 255, used only with cca() */
159 static uint8_t cca_thershold = MICROMAC_CONF_CCA_THR;
160 
161 /* Tx in progress? */
162 static volatile uint8_t tx_in_progress = 0;
163 /* Are we currently listening? */
164 static volatile uint8_t listen_on = 0;
165 
166 /* Is the driver currently transmitting a software ACK? */
167 static uint8_t in_ack_transmission = 0;
168 
169 /* TX frame buffer */
170 static tsPhyFrame tx_frame_buffer;
171 
172 /* RX frame buffer */
173 static tsPhyFrame *rx_frame_buffer;
174 
175 /* Frame buffer pointer to read from */
176 static tsPhyFrame *input_frame_buffer = NULL;
177 
178 /* Ringbuffer for received packets in interrupt enabled mode */
179 static struct ringbufindex input_ringbuf;
180 static tsPhyFrame input_array[MIRCOMAC_CONF_BUF_NUM];
181 
182 /* SFD timestamp in RTIMER ticks */
183 static volatile uint32_t last_packet_timestamp = 0;
184 
185 /* Local functions prototypes */
186 static int on(void);
187 static int off(void);
188 static int is_packet_for_us(uint8_t *buf, int len, int do_send_ack);
189 static void set_frame_filtering(uint8_t enable);
190 static rtimer_clock_t get_packet_timestamp(void);
191 static void set_txpower(int8_t power);
192 void set_channel(int c);
193 static void radio_interrupt_handler(uint32 mac_event);
194 static int get_detected_energy(void);
195 static int get_rssi(void);
196 static void read_last_rssi(void);
197 
198 /*---------------------------------------------------------------------------*/
199 PROCESS(micromac_radio_process, "micromac_radio_driver");
200 /*---------------------------------------------------------------------------*/
201 
202 /* Custom Radio parameters */
203 #ifndef RADIO_RX_MODE_POLL_MODE
204 #define RADIO_PARAM_LAST_RSSI 0x80
205 #define RADIO_PARAM_LAST_PACKET_TIMESTAMP 0x81
206 #define RADIO_RX_MODE_POLL_MODE (1 << 2)
207 #endif /* RADIO_RX_MODE_POLL_MODE */
208 
209 /*---------------------------------------------------------------------------*/
210 static rtimer_clock_t
211 get_packet_timestamp(void)
212 {
213  /* Wait for an edge */
214  uint32_t t = u32MMAC_GetTime();
215  while(u32MMAC_GetTime() == t);
216  /* Save SFD timestamp, converted from radio timer to RTIMER */
217  last_packet_timestamp = RTIMER_NOW() -
218  RADIO_TO_RTIMER((uint32_t)(u32MMAC_GetTime() - (u32MMAC_GetRxTime() - 1)));
219  /* The remaining measured error is typically in range 0..16 usec.
220  * Center it around zero, in the -8..+8 usec range. */
221  last_packet_timestamp -= US_TO_RTIMERTICKS(8);
222  return last_packet_timestamp;
223 }
224 /*---------------------------------------------------------------------------*/
225 static int
226 init_software(void)
227 {
228  int put_index;
229  /* Initialize ring buffer and first input packet pointer */
230  ringbufindex_init(&input_ringbuf, MIRCOMAC_CONF_BUF_NUM);
231  /* get pointer to next input slot */
232  put_index = ringbufindex_peek_put(&input_ringbuf);
233  if(put_index == -1) {
234  rx_frame_buffer = NULL;
235  printf("micromac_radio init:! no buffer available. Abort init.\n");
236  off();
237  return 0;
238  } else {
239  rx_frame_buffer = &input_array[put_index];
240  }
241  input_frame_buffer = rx_frame_buffer;
242 
243  process_start(&micromac_radio_process, NULL);
244 
245  return 1;
246 }
247 /*---------------------------------------------------------------------------*/
248 static int
249 init(void)
250 {
251  int ret = 1;
252  tsExtAddr node_long_address;
253  uint16_t node_short_address;
254  static uint8_t is_initialized;
255 
256  tx_in_progress = 0;
257 
258  u32JPT_Init();
259  vMMAC_Enable();
260 
261  /* Enable/disable interrupts */
262  if(poll_mode) {
263  vMMAC_EnableInterrupts(NULL);
264  vMMAC_ConfigureInterruptSources(0);
265  } else {
266  vMMAC_EnableInterrupts(&radio_interrupt_handler);
267  }
268  vMMAC_ConfigureRadio();
269  set_channel(current_channel);
270  set_txpower(current_tx_power);
271 
272  vMMAC_GetMacAddress(&node_long_address);
273  /* Short addresses are disabled by default */
274  node_short_address = (uint16_t)node_long_address.u32L;
275  vMMAC_SetRxAddress(frame802154_get_pan_id(), node_short_address, &node_long_address);
276 
277  /* Disable hardware backoff */
278  vMMAC_SetTxParameters(1, 0, 0, 0);
279  vMMAC_SetCutOffTimer(0, FALSE);
280 
281 #if RADIO_TEST_MODE == RADIO_TEST_MODE_HIGH_PWR
282  /* Enable high power mode.
283  * In this mode DIO2 goes high during RX
284  * and DIO3 goes high during TX
285  **/
286  vREG_SysWrite(REG_SYS_PWR_CTRL,
287  u32REG_SysRead(REG_SYS_PWR_CTRL)
288  | REG_SYSCTRL_PWRCTRL_RFRXEN_MASK
289  | REG_SYSCTRL_PWRCTRL_RFTXEN_MASK);
290 #elif RADIO_TEST_MODE == RADIO_TEST_MODE_ADVANCED
291  /* output internal radio status on IO pins.
292  * See Chris@NXP email */
293  vREG_SysWrite(REG_SYS_PWR_CTRL,
294  u32REG_SysRead(REG_SYS_PWR_CTRL) | (1UL << 26UL));
295 #endif /* TEST_MODE */
296 
297  if(!is_initialized) {
298  is_initialized = 1;
299  ret = init_software();
300  }
301 
302  return ret;
303 }
304 /*---------------------------------------------------------------------------*/
305 static int
306 on(void)
307 {
308  /* No address matching or frame decoding */
309  if(rx_frame_buffer != NULL) {
310  vMMAC_StartPhyReceive(rx_frame_buffer,
311  (uint16_t)(E_MMAC_RX_START_NOW
312  | E_MMAC_RX_NO_FCS_ERROR) /* means: reject FCS errors */
313  );
314  } else {
315  missed_radio_on_request = 1;
316  }
317  ENERGEST_ON(ENERGEST_TYPE_LISTEN);
318  listen_on = 1;
319  return 1;
320 }
321 /*---------------------------------------------------------------------------*/
322 static int
323 off(void)
324 {
325  listen_on = 0;
326  tx_in_progress = 0;
327 
328  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
329 
330  /* The following would be needed with delayed Tx/Rx functions
331  * vMMAC_SetCutOffTimer(0, FALSE);*/
332  vMMAC_RadioOff();
333 
334  return 1;
335 }
336 /*---------------------------------------------------------------------------*/
337 static int
338 transmit(unsigned short payload_len)
339 {
340  if(tx_in_progress) {
341  return RADIO_TX_COLLISION;
342  }
343  tx_in_progress = 1;
344 
345  /* Energest */
346  if(listen_on) {
347  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
348  }
349  ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
350 
351  /* Transmit and wait */
352  vMMAC_StartPhyTransmit(&tx_frame_buffer,
353  E_MMAC_TX_START_NOW |
354  (send_on_cca ? E_MMAC_TX_USE_CCA : E_MMAC_TX_NO_CCA));
355 
356  if(poll_mode) {
357  BUSYWAIT_UNTIL(u32MMAC_PollInterruptSource(E_MMAC_INT_TX_COMPLETE), MAX_PACKET_DURATION);
358  } else {
359  if(in_ack_transmission) {
360  /* as nested interupts are not possible, the tx flag will never be cleared */
361  BUSYWAIT_UNTIL(FALSE, MAX_ACK_DURATION);
362  } else {
363  /* wait until the tx flag is cleared */
364  BUSYWAIT_UNTIL(!tx_in_progress, MAX_PACKET_DURATION);
365  }
366  }
367 
368  /* Energest */
369  ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
370  if(listen_on) {
371  ENERGEST_ON(ENERGEST_TYPE_LISTEN);
372  }
373  tx_in_progress = 0;
374 
375  /* Check error code */
376  int ret;
377  uint32_t tx_error = u32MMAC_GetTxErrors();
378  if(tx_error == 0) {
379  ret = RADIO_TX_OK;
380  RIMESTATS_ADD(acktx);
381  } else if(tx_error & E_MMAC_TXSTAT_ABORTED) {
382  ret = RADIO_TX_ERR;
383  RIMESTATS_ADD(sendingdrop);
384  } else if(tx_error & E_MMAC_TXSTAT_CCA_BUSY) {
385  ret = RADIO_TX_COLLISION;
386  RIMESTATS_ADD(contentiondrop);
387  } else if(tx_error & E_MMAC_TXSTAT_NO_ACK) {
388  ret = RADIO_TX_NOACK;
389  RIMESTATS_ADD(noacktx);
390  } else {
391  ret = RADIO_TX_ERR;
392  }
393  return ret;
394 }
395 /*---------------------------------------------------------------------------*/
396 static int
397 prepare(const void *payload, unsigned short payload_len)
398 {
399  uint8_t i;
400  uint16_t checksum;
401 
402  RIMESTATS_ADD(lltx);
403 
404  if(tx_in_progress) {
405  return 1;
406  }
407  if(payload_len > 127 || payload == NULL) {
408  return 1;
409  }
410  /* Copy payload to (soft) Ttx buffer */
411  memcpy(tx_frame_buffer.uPayload.au8Byte, payload, payload_len);
412  i = payload_len;
413 #if CRC_SW
414  /* Compute CRC */
415  checksum = crc16_data(payload, payload_len, 0);
416  tx_frame_buffer.uPayload.au8Byte[i++] = checksum;
417  tx_frame_buffer.uPayload.au8Byte[i++] = (checksum >> 8) & 0xff;
418  tx_frame_buffer.u8PayloadLength = payload_len + CHECKSUM_LEN;
419 #else
420  tx_frame_buffer.u8PayloadLength = payload_len;
421 #endif
422 
423  return 0;
424 }
425 /*---------------------------------------------------------------------------*/
426 static int
427 send(const void *payload, unsigned short payload_len)
428 {
429  if(prepare(payload, payload_len) == 0) {
430  return transmit(payload_len);
431  } else {
432  return RADIO_TX_ERR;
433  }
434 }
435 /*---------------------------------------------------------------------------*/
436 int
437 get_channel(void)
438 {
439  return current_channel;
440 }
441 /*---------------------------------------------------------------------------*/
442 void
443 set_channel(int c)
444 {
445  current_channel = c;
446  /* will fine tune TX power as well */
447  vMMAC_SetChannel(current_channel);
448 }
449 /*---------------------------------------------------------------------------*/
450 static int
451 is_broadcast_addr(uint8_t mode, uint8_t *addr)
452 {
453  int i = ((mode == FRAME802154_SHORTADDRMODE) ? 2 : 8);
454  while(i-- > 0) {
455  if(addr[i] != 0xff) {
456  return 0;
457  }
458  }
459  return 1;
460 }
461 /*---------------------------------------------------------------------------*/
462 /* Send an ACK */
463 static void
464 send_ack(const frame802154_t *frame)
465 {
466  uint8_t buffer[3];
467  /* FCF: 2 octets */
468  buffer[0] = FRAME802154_ACKFRAME;
469  buffer[1] = 0;
470  /* Seqnum: 1 octets */
471  buffer[2] = frame->seq;
472  in_ack_transmission = 1;
473  send(&buffer, sizeof(buffer));
474  in_ack_transmission = 0;
475 }
476 /*---------------------------------------------------------------------------*/
477 /* Check if a packet is for us */
478 static int
479 is_packet_for_us(uint8_t *buf, int len, int do_send_ack)
480 {
481  frame802154_t frame;
482  int result;
483  uint8_t parsed = frame802154_parse(buf, len, &frame);
484  if(parsed) {
485  if(frame.fcf.dest_addr_mode) {
486  int has_dest_panid;
487  frame802154_has_panid(&frame.fcf, NULL, &has_dest_panid);
488  if(has_dest_panid
489  && frame802154_get_pan_id() != FRAME802154_BROADCASTPANDID
490  && frame.dest_pid != frame802154_get_pan_id()
491  && frame.dest_pid != FRAME802154_BROADCASTPANDID) {
492  /* Packet to another PAN */
493  return 0;
494  }
495  if(!is_broadcast_addr(frame.fcf.dest_addr_mode, frame.dest_addr)) {
496  result = linkaddr_cmp((linkaddr_t *)frame.dest_addr, &linkaddr_node_addr);
497  if(autoack_enabled && result && do_send_ack) {
498  /* this is a unicast frame and sending ACKs is enabled */
499  send_ack(&frame);
500  }
501  return result;
502  }
503  }
504  return 1;
505  } else {
506  return 0;
507  }
508 }
509 /*---------------------------------------------------------------------------*/
510 static int
511 read(void *buf, unsigned short bufsize)
512 {
513  int len = 0;
514  uint16_t radio_last_rx_crc;
515  uint8_t radio_last_rx_crc_ok = 1;
516 
517  len = input_frame_buffer->u8PayloadLength;
518 
519  if(len <= CHECKSUM_LEN) {
520  input_frame_buffer->u8PayloadLength = 0;
521  return 0;
522  } else {
523  len -= CHECKSUM_LEN;
524  /* Check CRC */
525 #if CRC_SW
526  uint16_t checksum = crc16_data(input_frame_buffer->uPayload.au8Byte, len, 0);
527  radio_last_rx_crc =
528  (uint16_t)(input_frame_buffer->uPayload.au8Byte[len + 1] << (uint16_t)8)
529  | input_frame_buffer->uPayload.au8Byte[len];
530  radio_last_rx_crc_ok = (checksum == radio_last_rx_crc);
531  if(!radio_last_rx_crc_ok) {
532  RIMESTATS_ADD(badcrc);
533  }
534 #endif /* CRC_SW */
535  if(radio_last_rx_crc_ok) {
536  /* If we are in poll mode we need to check the frame here */
537  if(poll_mode) {
538  if(frame_filtering &&
539  !is_packet_for_us(input_frame_buffer->uPayload.au8Byte, len, 0)) {
540  len = 0;
541  } else {
542  read_last_rssi();
543  }
544  }
545  if(len != 0) {
546  bufsize = MIN(len, bufsize);
547  memcpy(buf, input_frame_buffer->uPayload.au8Byte, bufsize);
548  RIMESTATS_ADD(llrx);
549  if(!poll_mode) {
550  /* Not in poll mode: packetbuf should not be accessed in interrupt context */
551  packetbuf_set_attr(PACKETBUF_ATTR_RSSI, radio_last_rssi);
552  packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, radio_last_correlation);
553  }
554  }
555  } else {
556  len = 0;
557  }
558  /* Disable further read attempts */
559  input_frame_buffer->u8PayloadLength = 0;
560  }
561 
562  return len;
563 }
564 /*---------------------------------------------------------------------------*/
565 static void
566 set_txpower(int8_t power)
567 {
568  if(power > OUTPUT_POWER_MAX) {
569  current_tx_power = OUTPUT_POWER_MAX;
570  } else {
571  if(power < OUTPUT_POWER_MIN) {
572  current_tx_power = OUTPUT_POWER_MIN;
573  } else {
574  current_tx_power = power;
575  }
576  }
577  vMMAC_SetChannelAndPower(current_channel, current_tx_power);
578 }
579 /*--------------------------------------------------------------------------*/
580 static int
581 get_txpower(void)
582 {
583  int actual_tx_power;
584 #if (JENNIC_CHIP == JN5169)
585  /* Actual tx power value rounded to nearest integer number */
586  const static int8 power_table [] = {
587  -32, -30, -29, -29, /* -32 .. -29 */
588  -28, -28, -28, -28, /* -28 .. -25 */
589  -21, -21, -21, -2, /* -24 .. -21 */
590  -20, -19, -18, -17, /* -20 .. -17 */
591  -17, -17, -17, -10, /* -16 .. -13 */
592  -10, -10, -10, -9, /* -12 .. -09 */
593  -8, -7, -6, -6, /* -08 .. -05 */
594  -6, -6, 1, 1, /* -04 .. -01 */
595  1, 1, 2, 3, /* 00 .. 03 */
596  4, 5, 6, 7, /* 04 .. 07 */
597  9, 9, 10 }; /* 08 .. 10 */
598  if(current_tx_power > OUTPUT_POWER_MAX) {
599  actual_tx_power = OUTPUT_POWER_MAX;
600  } else if(current_tx_power < OUTPUT_POWER_MIN) {
601  actual_tx_power = OUTPUT_POWER_MIN;
602  } else {
603  actual_tx_power = power_table[current_tx_power + ABS_OUTPUT_POWER_MIN];
604  }
605 #else
606  /* Other JN516x chips */
607  if(current_tx_power < (-24)) {
608  actual_tx_power = OUTPUT_POWER_MIN;
609  } else if(current_tx_power < (-12)) {
610  actual_tx_power = (-20);
611  } else if(current_tx_power < 0) {
612  actual_tx_power = (-9);
613  } else {
614  actual_tx_power = OUTPUT_POWER_MAX;
615  }
616 #endif
617  return (int)actual_tx_power;
618 }
619 /*---------------------------------------------------------------------------*/
620 static int
621 get_detected_energy(void)
622 {
623  const uint32 u32Samples = 8;
624  return u8JPT_EnergyDetect(current_channel, u32Samples);
625 }
626 /*---------------------------------------------------------------------------*/
627 static int
628 get_rssi(void)
629 {
630  /* this approximate formula for RSSI is taken from NXP internal docs */
631  return (7 * get_detected_energy() - 1970) / 20;
632 }
633 /*---------------------------------------------------------------------------*/
634 static void
635 read_last_rssi(void)
636 {
637  uint8_t radio_last_rx_energy;
638  radio_last_rx_energy = u8MMAC_GetRxLqi((uint8_t *)&radio_last_correlation);
639  radio_last_rssi = i16JPT_ConvertEnergyTodBm(radio_last_rx_energy);
640 }
641 /*---------------------------------------------------------------------------*/
642 int
643 receiving_packet(void)
644 {
645  return bMMAC_RxDetected();
646 }
647 /*---------------------------------------------------------------------------*/
648 static int
649 pending_packet(void)
650 {
651  if(!poll_mode) {
652  return ringbufindex_peek_get(&input_ringbuf) != -1;
653  } else {
654  return u32MMAC_PollInterruptSource(
655  E_MMAC_INT_RX_COMPLETE | E_MMAC_INT_RX_HEADER);
656  }
657 }
658 /*---------------------------------------------------------------------------*/
659 static int
660 cca(void)
661 {
662  bool_t is_channel_busy = bJPT_CCA(current_channel,
663  E_JPT_CCA_MODE_CARRIER_OR_ENERGY,
664  cca_thershold);
665  return is_channel_busy == FALSE;
666 }
667 /*---------------------------------------------------------------------------*/
668 static void
669 radio_interrupt_handler(uint32 mac_event)
670 {
671  uint32_t rx_status;
672  uint8_t overflow = 0;
673  int get_index;
674  int put_index;
675  int packet_for_me = 0;
676 
677  if(mac_event & E_MMAC_INT_TX_COMPLETE) {
678  /* Transmission attempt has finished */
679  tx_in_progress = 0;
680  } else if(mac_event & E_MMAC_INT_RX_COMPLETE) {
681  rx_status = u32MMAC_GetRxErrors();
682  /* If rx is successful */
683  if(rx_status == 0) {
684  /* Save SFD timestamp */
685  last_packet_timestamp = get_packet_timestamp();
686 
687  if(!poll_mode && (mac_event & E_MMAC_INT_RX_COMPLETE)) {
688  if(rx_frame_buffer->u8PayloadLength > CHECKSUM_LEN) {
689  if(frame_filtering) {
690  /* Check RX address */
691  packet_for_me = is_packet_for_us(rx_frame_buffer->uPayload.au8Byte, rx_frame_buffer->u8PayloadLength - CHECKSUM_LEN, 1);
692  } else if(!frame_filtering) {
693  packet_for_me = 1;
694  }
695  }
696  if(!packet_for_me) {
697  /* Prevent reading */
698  rx_frame_buffer->u8PayloadLength = 0;
699  } else {
700  /* read and cache RSSI and LQI values */
701  read_last_rssi();
702  /* Put received frame in queue */
703  ringbufindex_put(&input_ringbuf);
704 
705  if((get_index = ringbufindex_peek_get(&input_ringbuf)) != -1) {
706  input_frame_buffer = &input_array[get_index];
707  }
708  process_poll(&micromac_radio_process);
709 
710  /* get pointer to next input slot */
711  put_index = ringbufindex_peek_put(&input_ringbuf);
712  /* is there space? */
713  if(put_index != -1) {
714  /* move rx_frame_buffer to next empty slot */
715  rx_frame_buffer = &input_array[put_index];
716  } else {
717  overflow = 1;
718  rx_frame_buffer = NULL;
719  }
720  }
721  }
722  } else { /* if rx is not successful */
723  if(rx_status & E_MMAC_RXSTAT_ABORTED) {
724  RIMESTATS_ADD(badsynch);
725  } else if(rx_status & E_MMAC_RXSTAT_ERROR) {
726  RIMESTATS_ADD(badcrc);
727  } else if(rx_status & E_MMAC_RXSTAT_MALFORMED) {
728  RIMESTATS_ADD(toolong);
729  }
730  }
731  }
732  if(overflow) {
733  off();
734  } else if(MICROMAC_CONF_ALWAYS_ON
735  && (mac_event & (E_MMAC_INT_TX_COMPLETE | E_MMAC_INT_RX_COMPLETE))) {
736  on();
737  }
738 }
739 /*---------------------------------------------------------------------------*/
740 PROCESS_THREAD(micromac_radio_process, ev, data)
741 {
742  PROCESS_BEGIN();
743 
744  while(1) {
745  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
746 
747  /* Pass received packets to upper layer */
748  int16_t read_index;
749  /* Loop on accessing (without removing) a pending input packet */
750  while((read_index = ringbufindex_peek_get(&input_ringbuf)) != -1) {
751  input_frame_buffer = &input_array[read_index];
752  /* Put packet into packetbuf for input callback */
753  packetbuf_clear();
754  int len = read(packetbuf_dataptr(), PACKETBUF_SIZE);
755  /* is packet valid? */
756  if(len > 0) {
758  NETSTACK_RDC.input();
759  }
760  /* Remove packet from ringbuf */
761  ringbufindex_get(&input_ringbuf);
762  /* Disable further read attempts */
763  input_frame_buffer->u8PayloadLength = 0;
764  }
765 
766  /* Are we recovering from overflow? */
767  if(rx_frame_buffer == NULL) {
768  /* get pointer to next input slot */
769  int put_index = ringbufindex_peek_put(&input_ringbuf);
770  /* is there space? */
771  if(put_index != -1) {
772  /* move rx_frame_buffer to next empty slot */
773  rx_frame_buffer = &input_array[put_index];
774  /* do we need to turn radio on? */
775  if(MICROMAC_CONF_ALWAYS_ON || missed_radio_on_request) {
776  missed_radio_on_request = 0;
777  on();
778  }
779  } else {
780  rx_frame_buffer = NULL;
781  }
782  }
783  }
784  PROCESS_END();
785 }
786 /*---------------------------------------------------------------------------*/
787 static void
788 set_frame_filtering(uint8_t enable)
789 {
790  frame_filtering = enable;
791 }
792 /*---------------------------------------------------------------------------*/
793 static void
794 set_autoack(uint8_t enable)
795 {
796  autoack_enabled = enable;
797 }
798 /*---------------------------------------------------------------------------*/
799 static void
800 set_poll_mode(uint8_t enable)
801 {
802  poll_mode = enable;
803  if(poll_mode) {
804  /* Disable interrupts */
805  vMMAC_EnableInterrupts(NULL);
806  vMMAC_ConfigureInterruptSources(0);
807  } else {
808  /* Initialize and enable interrupts */
809  /* TODO: enable E_MMAC_INT_RX_HEADER & filter out frames after header rx */
810  vMMAC_ConfigureInterruptSources(
811  E_MMAC_INT_RX_COMPLETE | E_MMAC_INT_TX_COMPLETE);
812  vMMAC_EnableInterrupts(&radio_interrupt_handler);
813  }
814 }
815 /* Enable or disable CCA before sending */
816 static void
817 set_send_on_cca(uint8_t enable)
818 {
819  send_on_cca = enable;
820 }
821 /*---------------------------------------------------------------------------*/
822 static radio_result_t
823 get_value(radio_param_t param, radio_value_t *value)
824 {
825  if(!value) {
826  return RADIO_RESULT_INVALID_VALUE;
827  }
828  switch(param) {
829  case RADIO_PARAM_POWER_MODE:
830  *value = listen_on || tx_in_progress ? RADIO_POWER_MODE_ON : RADIO_POWER_MODE_OFF;
831  return RADIO_RESULT_OK;
832  case RADIO_PARAM_CHANNEL:
833  *value = get_channel();
834  return RADIO_RESULT_OK;
835  case RADIO_PARAM_RX_MODE:
836  *value = 0;
837  if(frame_filtering) {
839  }
840  if(autoack_enabled) {
841  *value |= RADIO_RX_MODE_AUTOACK;
842  }
843  if(poll_mode) {
844  *value |= RADIO_RX_MODE_POLL_MODE;
845  }
846  return RADIO_RESULT_OK;
847  case RADIO_PARAM_TX_MODE:
848  *value = 0;
849  if(send_on_cca) {
850  *value |= RADIO_TX_MODE_SEND_ON_CCA;
851  }
852  return RADIO_RESULT_OK;
853  case RADIO_PARAM_TXPOWER:
854  *value = get_txpower();
855  return RADIO_RESULT_OK;
856  case RADIO_PARAM_RSSI:
857  *value = get_rssi();
858  return RADIO_RESULT_OK;
859  case RADIO_PARAM_LAST_RSSI:
860  *value = radio_last_rssi;
861  return RADIO_RESULT_OK;
862  case RADIO_PARAM_CCA_THRESHOLD:
863  *value = cca_thershold;
864  return RADIO_RESULT_OK;
865  case RADIO_CONST_CHANNEL_MIN:
866  *value = 11;
867  return RADIO_RESULT_OK;
868  case RADIO_CONST_CHANNEL_MAX:
869  *value = 26;
870  return RADIO_RESULT_OK;
871  case RADIO_CONST_TXPOWER_MIN:
872  *value = OUTPUT_POWER_MIN;
873  return RADIO_RESULT_OK;
874  case RADIO_CONST_TXPOWER_MAX:
875  *value = OUTPUT_POWER_MAX;
876  return RADIO_RESULT_OK;
877  default:
878  return RADIO_RESULT_NOT_SUPPORTED;
879  }
880 }
881 /*---------------------------------------------------------------------------*/
882 static radio_result_t
883 set_value(radio_param_t param, radio_value_t value)
884 {
885  switch(param) {
886  case RADIO_PARAM_POWER_MODE:
887  if(value == RADIO_POWER_MODE_ON) {
888  on();
889  return RADIO_RESULT_OK;
890  }
891  if(value == RADIO_POWER_MODE_OFF) {
892  off();
893  return RADIO_RESULT_OK;
894  }
895  return RADIO_RESULT_INVALID_VALUE;
896  case RADIO_PARAM_CHANNEL:
897  if(value < 11 || value > 26) {
898  return RADIO_RESULT_INVALID_VALUE;
899  }
900  set_channel(value);
901  return RADIO_RESULT_OK;
902  case RADIO_PARAM_RX_MODE:
903  if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER |
904  RADIO_RX_MODE_AUTOACK | RADIO_RX_MODE_POLL_MODE)) {
905  return RADIO_RESULT_INVALID_VALUE;
906  }
907  set_frame_filtering((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0);
908  set_autoack((value & RADIO_RX_MODE_AUTOACK) != 0);
909  set_poll_mode((value & RADIO_RX_MODE_POLL_MODE) != 0);
910  return RADIO_RESULT_OK;
911  case RADIO_PARAM_TX_MODE:
912  if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) {
913  return RADIO_RESULT_INVALID_VALUE;
914  }
915  set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0);
916  return RADIO_RESULT_OK;
917  case RADIO_PARAM_TXPOWER:
918  if(value < OUTPUT_POWER_MIN || value > OUTPUT_POWER_MAX) {
919  return RADIO_RESULT_INVALID_VALUE;
920  /* Find the closest higher PA_LEVEL for the desired output power */
921  }
922  set_txpower(value);
923  return RADIO_RESULT_OK;
924  case RADIO_PARAM_CCA_THRESHOLD:
925  cca_thershold = value;
926  return RADIO_RESULT_OK;
927  default:
928  return RADIO_RESULT_NOT_SUPPORTED;
929  }
930 }
931 /*---------------------------------------------------------------------------*/
932 static radio_result_t
933 get_object(radio_param_t param, void *dest, size_t size)
934 {
935  if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) {
936  if(size != sizeof(rtimer_clock_t) || !dest) {
937  return RADIO_RESULT_INVALID_VALUE;
938  }
939  *(rtimer_clock_t *)dest = get_packet_timestamp();
940 
941  return RADIO_RESULT_OK;
942  }
943  return RADIO_RESULT_NOT_SUPPORTED;
944 }
945 /*---------------------------------------------------------------------------*/
946 static radio_result_t
947 set_object(radio_param_t param, const void *src, size_t size)
948 {
949  return RADIO_RESULT_NOT_SUPPORTED;
950 }
951 /*---------------------------------------------------------------------------*/
952 const struct radio_driver micromac_radio_driver = {
953  init,
954  prepare,
955  transmit,
956  send,
957  read,
958  cca,
961  on,
962  off,
963  get_value,
964  set_value,
965  get_object,
966  set_object
967 };
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:158
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
Header file for the real-time timer module.
uint8_t dest_addr[8]
Destination address.
Definition: frame802154.h:196
uint16_t dest_pid
Destination PAN ID.
Definition: frame802154.h:200
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Definition: uip-nd6.c:124
frame802154_fcf_t fcf
Frame control field.
Definition: frame802154.h:198
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:135
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:76
int(* read)(void *buf, unsigned short buf_len)
Read a received packet into a buffer.
Definition: radio.h:251
int(* prepare)(const void *payload, unsigned short payload_len)
Prepare the radio with a packet to be sent.
Definition: radio.h:242
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
uint8_t seq
Sequence number.
Definition: frame802154.h:199
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:66
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
Definition: radio.h:258
The structure of a device driver for a radio in Contiki.
Definition: radio.h:237
MICROMAC_RADIO driver header file
int(* pending_packet)(void)
Check if the radio driver has just received a packet.
Definition: radio.h:261
Header file for the Rime buffer (packetbuf) management
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
Definition: radio.h:273
Header file for the ringbufindex library
int(* off)(void)
Turn the radio off.
Definition: radio.h:267
#define NULL
The null pointer.
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
802.15.4 frame creation and parsing functions
#define RADIO_RX_MODE_ADDRESS_FILTER
The radio reception mode controls address filtering and automatic transmission of acknowledgements in...
Definition: radio.h:204
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
Definition: radio.h:280
int(* on)(void)
Turn the radio on.
Definition: radio.h:264
int frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
Parses an input frame.
Definition: frame802154.c:465
#define RADIO_TX_MODE_SEND_ON_CCA
The radio transmission mode controls whether transmissions should be done using clear channel assessm...
Definition: radio.h:216
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:151
uint8_t dest_addr_mode
2 bit.
Definition: frame802154.h:155
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
radio_result_t(* get_value)(radio_param_t param, radio_value_t *value)
Get a radio parameter value.
Definition: radio.h:270
int(* send)(const void *payload, unsigned short payload_len)
Prepare & transmit a packet.
Definition: radio.h:248
#define FALSE
An alias for zero, used for clarity.
A set of debugging macros for the IP stack
Header file for Rime statistics
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
Definition: linkaddr.c:66
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
unsigned short crc16_data(const unsigned char *data, int len, unsigned short acc)
Calculate the CRC16 over a data area.
Definition: crc16.c:66
int(* transmit)(unsigned short transmit_len)
Send the packet that has previously been prepared.
Definition: radio.h:245
Parameters used by the frame802154_create() function.
Definition: frame802154.h:192
Include file for the Contiki low-layer network stack (NETSTACK)
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
Definition: radio.h:286
Header file for the CRC16 calculcation
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120