54 #include "AppHardwareApi.h"
58 #include "PeripheralRegs.h"
60 void vMMAC_SetChannelAndPower(uint8 u8Channel, int8 i8power);
65 #define DEBUG DEBUG_NONE
72 #define CHECKSUM_LEN 2
75 #define MAX_PACKET_DURATION US_TO_RTIMERTICKS((127 + 2) * 32 + RADIO_DELAY_BEFORE_TX)
77 #define MAX_ACK_DURATION US_TO_RTIMERTICKS((3 + 2) * 32 + RADIO_DELAY_BEFORE_TX)
80 #define RADIO_TEST_MODE_HIGH_PWR 1
81 #define RADIO_TEST_MODE_ADVANCED 2
82 #define RADIO_TEST_MODE_DISABLED 0
84 #ifndef RADIO_TEST_MODE
85 #define RADIO_TEST_MODE RADIO_TEST_MODE_DISABLED
89 #ifndef MIRCOMAC_CONF_BUF_NUM
90 #define MIRCOMAC_CONF_BUF_NUM 2
94 #ifndef MICROMAC_CONF_CHANNEL
95 #define MICROMAC_CONF_CHANNEL 26
99 #ifndef MICROMAC_CONF_CCA_THR
100 #define MICROMAC_CONF_CCA_THR 39
103 #if (JENNIC_CHIP == JN5169)
104 #define OUTPUT_POWER_MAX 10
105 #define OUTPUT_POWER_MIN (-32)
106 #define ABS_OUTPUT_POWER_MIN (32)
108 #define OUTPUT_POWER_MAX 0
109 #define OUTPUT_POWER_MIN (-32)
113 #ifndef MICROMAC_CONF_TX_POWER
114 #define MICROMAC_CONF_TX_POWER 0
118 #ifndef MICROMAC_CONF_AUTOACK
119 #define MICROMAC_CONF_AUTOACK 1
124 #ifndef MICROMAC_CONF_ALWAYS_ON
125 #define MICROMAC_CONF_ALWAYS_ON 1
128 #define BUSYWAIT_UNTIL(cond, max_time) \
132 while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) ; \
136 static volatile signed char radio_last_rssi;
137 static volatile uint8_t radio_last_correlation;
140 static volatile uint8_t missed_radio_on_request = 0;
143 static uint8_t poll_mode = 0;
145 static uint8_t frame_filtering = 1;
147 static uint8_t autoack_enabled = MICROMAC_CONF_AUTOACK;
149 static uint8_t send_on_cca = 0;
152 static int current_channel = MICROMAC_CONF_CHANNEL;
156 static int current_tx_power = MICROMAC_CONF_TX_POWER;
159 static uint8_t cca_thershold = MICROMAC_CONF_CCA_THR;
162 static volatile uint8_t tx_in_progress = 0;
164 static volatile uint8_t listen_on = 0;
167 static uint8_t in_ack_transmission = 0;
170 static tsPhyFrame tx_frame_buffer;
173 static tsPhyFrame *rx_frame_buffer;
176 static tsPhyFrame *input_frame_buffer =
NULL;
179 static struct ringbufindex input_ringbuf;
180 static tsPhyFrame input_array[MIRCOMAC_CONF_BUF_NUM];
183 static volatile uint32_t last_packet_timestamp = 0;
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);
199 PROCESS(micromac_radio_process,
"micromac_radio_driver");
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)
210 static rtimer_clock_t
211 get_packet_timestamp(
void)
214 uint32_t t = u32MMAC_GetTime();
215 while(u32MMAC_GetTime() == t);
218 RADIO_TO_RTIMER((uint32_t)(u32MMAC_GetTime() - (u32MMAC_GetRxTime() - 1)));
221 last_packet_timestamp -= US_TO_RTIMERTICKS(8);
222 return last_packet_timestamp;
230 ringbufindex_init(&input_ringbuf, MIRCOMAC_CONF_BUF_NUM);
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");
239 rx_frame_buffer = &input_array[put_index];
241 input_frame_buffer = rx_frame_buffer;
252 tsExtAddr node_long_address;
253 uint16_t node_short_address;
254 static uint8_t is_initialized;
263 vMMAC_EnableInterrupts(
NULL);
264 vMMAC_ConfigureInterruptSources(0);
266 vMMAC_EnableInterrupts(&radio_interrupt_handler);
268 vMMAC_ConfigureRadio();
269 set_channel(current_channel);
270 set_txpower(current_tx_power);
272 vMMAC_GetMacAddress(&node_long_address);
274 node_short_address = (uint16_t)node_long_address.u32L;
275 vMMAC_SetRxAddress(frame802154_get_pan_id(), node_short_address, &node_long_address);
278 vMMAC_SetTxParameters(1, 0, 0, 0);
279 vMMAC_SetCutOffTimer(0,
FALSE);
281 #if RADIO_TEST_MODE == RADIO_TEST_MODE_HIGH_PWR
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
293 vREG_SysWrite(REG_SYS_PWR_CTRL,
294 u32REG_SysRead(REG_SYS_PWR_CTRL) | (1UL << 26UL));
297 if(!is_initialized) {
299 ret = init_software();
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)
315 missed_radio_on_request = 1;
317 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
328 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
338 transmit(
unsigned short payload_len)
341 return RADIO_TX_COLLISION;
347 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
349 ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
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));
357 BUSYWAIT_UNTIL(u32MMAC_PollInterruptSource(E_MMAC_INT_TX_COMPLETE), MAX_PACKET_DURATION);
359 if(in_ack_transmission) {
361 BUSYWAIT_UNTIL(
FALSE, MAX_ACK_DURATION);
364 BUSYWAIT_UNTIL(!tx_in_progress, MAX_PACKET_DURATION);
369 ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
371 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
377 uint32_t tx_error = u32MMAC_GetTxErrors();
380 RIMESTATS_ADD(acktx);
381 }
else if(tx_error & E_MMAC_TXSTAT_ABORTED) {
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);
397 prepare(
const void *payload,
unsigned short payload_len)
407 if(payload_len > 127 || payload ==
NULL) {
411 memcpy(tx_frame_buffer.uPayload.au8Byte, payload, payload_len);
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;
420 tx_frame_buffer.u8PayloadLength = payload_len;
427 send(
const void *payload,
unsigned short payload_len)
429 if(prepare(payload, payload_len) == 0) {
430 return transmit(payload_len);
439 return current_channel;
447 vMMAC_SetChannel(current_channel);
451 is_broadcast_addr(uint8_t mode, uint8_t *
addr)
453 int i = ((mode == FRAME802154_SHORTADDRMODE) ? 2 : 8);
455 if(addr[i] != 0xff) {
468 buffer[0] = FRAME802154_ACKFRAME;
471 buffer[2] = frame->
seq;
472 in_ack_transmission = 1;
473 send(&buffer,
sizeof(buffer));
474 in_ack_transmission = 0;
479 is_packet_for_us(uint8_t *buf,
int len,
int do_send_ack)
487 frame802154_has_panid(&frame.
fcf,
NULL, &has_dest_panid);
489 && frame802154_get_pan_id() != FRAME802154_BROADCASTPANDID
490 && frame.
dest_pid != frame802154_get_pan_id()
491 && frame.
dest_pid != FRAME802154_BROADCASTPANDID) {
497 if(autoack_enabled && result && do_send_ack) {
511 read(
void *buf,
unsigned short bufsize)
514 uint16_t radio_last_rx_crc;
515 uint8_t radio_last_rx_crc_ok = 1;
517 len = input_frame_buffer->u8PayloadLength;
519 if(len <= CHECKSUM_LEN) {
520 input_frame_buffer->u8PayloadLength = 0;
526 uint16_t checksum =
crc16_data(input_frame_buffer->uPayload.au8Byte, len, 0);
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);
535 if(radio_last_rx_crc_ok) {
538 if(frame_filtering &&
539 !is_packet_for_us(input_frame_buffer->uPayload.au8Byte, len, 0)) {
546 bufsize = MIN(len, bufsize);
547 memcpy(buf, input_frame_buffer->uPayload.au8Byte, bufsize);
551 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, radio_last_rssi);
552 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, radio_last_correlation);
559 input_frame_buffer->u8PayloadLength = 0;
566 set_txpower(int8_t power)
568 if(power > OUTPUT_POWER_MAX) {
569 current_tx_power = OUTPUT_POWER_MAX;
571 if(power < OUTPUT_POWER_MIN) {
572 current_tx_power = OUTPUT_POWER_MIN;
574 current_tx_power = power;
577 vMMAC_SetChannelAndPower(current_channel, current_tx_power);
584 #if (JENNIC_CHIP == JN5169)
586 const static int8 power_table [] = {
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;
603 actual_tx_power = power_table[current_tx_power + ABS_OUTPUT_POWER_MIN];
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);
614 actual_tx_power = OUTPUT_POWER_MAX;
617 return (
int)actual_tx_power;
621 get_detected_energy(
void)
623 const uint32 u32Samples = 8;
624 return u8JPT_EnergyDetect(current_channel, u32Samples);
631 return (7 * get_detected_energy() - 1970) / 20;
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);
643 receiving_packet(
void)
645 return bMMAC_RxDetected();
652 return ringbufindex_peek_get(&input_ringbuf) != -1;
654 return u32MMAC_PollInterruptSource(
655 E_MMAC_INT_RX_COMPLETE | E_MMAC_INT_RX_HEADER);
662 bool_t is_channel_busy = bJPT_CCA(current_channel,
663 E_JPT_CCA_MODE_CARRIER_OR_ENERGY,
665 return is_channel_busy ==
FALSE;
669 radio_interrupt_handler(uint32 mac_event)
672 uint8_t overflow = 0;
675 int packet_for_me = 0;
677 if(mac_event & E_MMAC_INT_TX_COMPLETE) {
680 }
else if(mac_event & E_MMAC_INT_RX_COMPLETE) {
681 rx_status = u32MMAC_GetRxErrors();
685 last_packet_timestamp = get_packet_timestamp();
687 if(!poll_mode && (mac_event & E_MMAC_INT_RX_COMPLETE)) {
688 if(rx_frame_buffer->u8PayloadLength > CHECKSUM_LEN) {
689 if(frame_filtering) {
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) {
698 rx_frame_buffer->u8PayloadLength = 0;
703 ringbufindex_put(&input_ringbuf);
705 if((get_index = ringbufindex_peek_get(&input_ringbuf)) != -1) {
706 input_frame_buffer = &input_array[get_index];
711 put_index = ringbufindex_peek_put(&input_ringbuf);
713 if(put_index != -1) {
715 rx_frame_buffer = &input_array[put_index];
718 rx_frame_buffer =
NULL;
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);
734 }
else if(MICROMAC_CONF_ALWAYS_ON
735 && (mac_event & (E_MMAC_INT_TX_COMPLETE | E_MMAC_INT_RX_COMPLETE))) {
750 while((read_index = ringbufindex_peek_get(&input_ringbuf)) != -1) {
751 input_frame_buffer = &input_array[read_index];
758 NETSTACK_RDC.input();
761 ringbufindex_get(&input_ringbuf);
763 input_frame_buffer->u8PayloadLength = 0;
767 if(rx_frame_buffer ==
NULL) {
769 int put_index = ringbufindex_peek_put(&input_ringbuf);
771 if(put_index != -1) {
773 rx_frame_buffer = &input_array[put_index];
775 if(MICROMAC_CONF_ALWAYS_ON || missed_radio_on_request) {
776 missed_radio_on_request = 0;
780 rx_frame_buffer =
NULL;
788 set_frame_filtering(uint8_t enable)
790 frame_filtering = enable;
794 set_autoack(uint8_t enable)
796 autoack_enabled = enable;
800 set_poll_mode(uint8_t enable)
805 vMMAC_EnableInterrupts(
NULL);
806 vMMAC_ConfigureInterruptSources(0);
810 vMMAC_ConfigureInterruptSources(
811 E_MMAC_INT_RX_COMPLETE | E_MMAC_INT_TX_COMPLETE);
812 vMMAC_EnableInterrupts(&radio_interrupt_handler);
817 set_send_on_cca(uint8_t enable)
819 send_on_cca = enable;
822 static radio_result_t
826 return RADIO_RESULT_INVALID_VALUE;
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:
837 if(frame_filtering) {
840 if(autoack_enabled) {
841 *value |= RADIO_RX_MODE_AUTOACK;
844 *value |= RADIO_RX_MODE_POLL_MODE;
846 return RADIO_RESULT_OK;
847 case RADIO_PARAM_TX_MODE:
852 return RADIO_RESULT_OK;
853 case RADIO_PARAM_TXPOWER:
854 *value = get_txpower();
855 return RADIO_RESULT_OK;
856 case RADIO_PARAM_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:
867 return RADIO_RESULT_OK;
868 case RADIO_CONST_CHANNEL_MAX:
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;
878 return RADIO_RESULT_NOT_SUPPORTED;
882 static radio_result_t
886 case RADIO_PARAM_POWER_MODE:
887 if(value == RADIO_POWER_MODE_ON) {
889 return RADIO_RESULT_OK;
891 if(value == RADIO_POWER_MODE_OFF) {
893 return RADIO_RESULT_OK;
895 return RADIO_RESULT_INVALID_VALUE;
896 case RADIO_PARAM_CHANNEL:
897 if(value < 11 || value > 26) {
898 return RADIO_RESULT_INVALID_VALUE;
901 return RADIO_RESULT_OK;
902 case RADIO_PARAM_RX_MODE:
904 RADIO_RX_MODE_AUTOACK | RADIO_RX_MODE_POLL_MODE)) {
905 return RADIO_RESULT_INVALID_VALUE;
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:
913 return RADIO_RESULT_INVALID_VALUE;
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;
923 return RADIO_RESULT_OK;
924 case RADIO_PARAM_CCA_THRESHOLD:
925 cca_thershold = value;
926 return RADIO_RESULT_OK;
928 return RADIO_RESULT_NOT_SUPPORTED;
932 static radio_result_t
933 get_object(radio_param_t param,
void *dest,
size_t size)
935 if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) {
936 if(size !=
sizeof(rtimer_clock_t) || !dest) {
937 return RADIO_RESULT_INVALID_VALUE;
939 *(rtimer_clock_t *)dest = get_packet_timestamp();
941 return RADIO_RESULT_OK;
943 return RADIO_RESULT_NOT_SUPPORTED;
946 static radio_result_t
947 set_object(radio_param_t param,
const void *src,
size_t size)
949 return RADIO_RESULT_NOT_SUPPORTED;
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
void process_poll(struct process *p)
Request a process to be polled.
Header file for the real-time timer module.
uint8_t dest_addr[8]
Destination address.
uint16_t dest_pid
Destination PAN ID.
static uip_ds6_addr_t * addr
Pointer to a router list entry.
frame802154_fcf_t fcf
Frame control field.
#define RTIMER_NOW()
Get the current clock time.
void packetbuf_clear(void)
Clear and reset the packetbuf.
int(* read)(void *buf, unsigned short buf_len)
Read a received packet into a buffer.
int(* prepare)(const void *payload, unsigned short payload_len)
Prepare the radio with a packet to be sent.
#define PROCESS_END()
Define the end of a process.
#define PROCESS(name, strname)
Declare a process.
uint8_t seq
Sequence number.
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
The structure of a device driver for a radio in Contiki.
MICROMAC_RADIO driver header file
int(* pending_packet)(void)
Check if the radio driver has just received a packet.
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.
Header file for the ringbufindex library
int(* off)(void)
Turn the radio off.
#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...
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...
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
int(* on)(void)
Turn the radio on.
int frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
Parses an input frame.
#define RADIO_TX_MODE_SEND_ON_CCA
The radio transmission mode controls whether transmissions should be done using clear channel assessm...
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
uint8_t dest_addr_mode
2 bit.
void process_start(struct process *p, process_data_t data)
Start a process.
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
radio_result_t(* get_value)(radio_param_t param, radio_value_t *value)
Get a radio parameter value.
int(* send)(const void *payload, unsigned short payload_len)
Prepare & transmit a packet.
#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.
linkaddr_t linkaddr_node_addr
The Rime address of the node.
unsigned short crc16_data(const unsigned char *data, int len, unsigned short acc)
Calculate the CRC16 over a data area.
int(* transmit)(unsigned short transmit_len)
Send the packet that has previously been prepared.
Parameters used by the frame802154_create() function.
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.
Header file for the CRC16 calculcation
#define PROCESS_BEGIN()
Define the beginning of a process.