/*---------------------------------------------------------------------------*/ PROCESS_THREAD(micromac_radio_process, ev, data) { PROCESS_BEGIN(); while(1) { PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); /* Pass received packets to upper layer */ int16_t read_index; /* Loop on accessing (without removing) a pending input packet */ while((read_index = ringbufindex_peek_get(&input_ringbuf)) != -1) { input_frame_buffer = &input_array[read_index]; /* Put packet into packetbuf for input callback */ packetbuf_clear(); int len = read(packetbuf_dataptr(), PACKETBUF_SIZE); /* is packet valid? */ if(len > 0) { packetbuf_set_datalen(len); NETSTACK_RDC.input(); } /* Remove packet from ringbuf */ ringbufindex_get(&input_ringbuf); /* Disable further read attempts */ input_frame_buffer->u8PayloadLength = 0; } /* Are we recovering from overflow? */ if(rx_frame_buffer == NULL) { /* get pointer to next input slot */ int put_index = ringbufindex_peek_put(&input_ringbuf); /* is there space? */ if(put_index != -1) { /* move rx_frame_buffer to next empty slot */ rx_frame_buffer = &input_array[put_index]; /* do we need to turn radio on? */ if(MICROMAC_CONF_ALWAYS_ON || missed_radio_on_request) { missed_radio_on_request = 0; on(); } } else { rx_frame_buffer = NULL; } } } PROCESS_END(); }
/* Add packet to neighbor queue. Use same lockfree implementation as ringbuf.c (put is atomic) */ struct tsch_packet * tsch_queue_add_packet(const linkaddr_t *addr, mac_callback_t sent, void *ptr) { struct tsch_neighbor *n = NULL; int16_t put_index = -1; struct tsch_packet *p = NULL; if(!tsch_is_locked()) { n = tsch_queue_add_nbr(addr); if(n != NULL) { put_index = ringbufindex_peek_put(&n->tx_ringbuf); if(put_index != -1) { p = memb_alloc(&packet_memb); if(p != NULL) { /* Enqueue packet */ #ifdef TSCH_CALLBACK_PACKET_READY TSCH_CALLBACK_PACKET_READY(); #endif p->qb = queuebuf_new_from_packetbuf(); if(p->qb != NULL) { p->sent = sent; p->ptr = ptr; p->ret = MAC_TX_DEFERRED; p->transmissions = 0; /* Add to ringbuf (actual add committed through atomic operation) */ n->tx_array[put_index] = p; ringbufindex_put(&n->tx_ringbuf); return p; } else { memb_free(&packet_memb, p); } } } } } PRINTF("TSCH-queue:! add packet failed: %u %p %d %p %p\n", tsch_is_locked(), n, put_index, p, p ? p->qb : NULL); return 0; }
/*---------------------------------------------------------------------------*/ static void radio_interrupt_handler(uint32 mac_event) { uint32_t rx_status; uint8_t overflow = 0; int get_index; int put_index; int packet_for_me = 0; if(mac_event & E_MMAC_INT_TX_COMPLETE) { /* Transmission attempt has finished */ tx_in_progress = 0; } else if(mac_event & E_MMAC_INT_RX_COMPLETE) { rx_status = u32MMAC_GetRxErrors(); /* If rx is successful */ if(rx_status == 0) { /* Save SFD timestamp */ last_packet_timestamp = get_packet_timestamp(); if(!poll_mode && (mac_event & E_MMAC_INT_RX_COMPLETE)) { if(rx_frame_buffer->u8PayloadLength > CHECKSUM_LEN) { if(frame_filtering) { /* Check RX address */ packet_for_me = is_packet_for_us(rx_frame_buffer->uPayload.au8Byte, rx_frame_buffer->u8PayloadLength - CHECKSUM_LEN, 1); } else if(!frame_filtering) { packet_for_me = 1; } } if(!packet_for_me) { /* Prevent reading */ rx_frame_buffer->u8PayloadLength = 0; } else { /* read and cache RSSI and LQI values */ read_last_rssi(); /* Put received frame in queue */ ringbufindex_put(&input_ringbuf); if((get_index = ringbufindex_peek_get(&input_ringbuf)) != -1) { input_frame_buffer = &input_array[get_index]; } process_poll(µmac_radio_process); /* get pointer to next input slot */ put_index = ringbufindex_peek_put(&input_ringbuf); /* is there space? */ if(put_index != -1) { /* move rx_frame_buffer to next empty slot */ rx_frame_buffer = &input_array[put_index]; } else { overflow = 1; rx_frame_buffer = NULL; } } } } else { /* if rx is not successful */ if(rx_status & E_MMAC_RXSTAT_ABORTED) { RIMESTATS_ADD(badsynch); } else if(rx_status & E_MMAC_RXSTAT_ERROR) { RIMESTATS_ADD(badcrc); } else if(rx_status & E_MMAC_RXSTAT_MALFORMED) { RIMESTATS_ADD(toolong); } } } if(overflow) { off(); } else if(MICROMAC_CONF_ALWAYS_ON && (mac_event & (E_MMAC_INT_TX_COMPLETE | E_MMAC_INT_RX_COMPLETE))) { on(); } }
/*---------------------------------------------------------------------------*/ static int init(void) { int put_index; tsExtAddr node_long_address; uint16_t node_short_address; tx_in_progress = 0; u32JPT_Init(); vMMAC_Enable(); /* Enable/disable interrupts */ if(poll_mode) { vMMAC_EnableInterrupts(NULL); vMMAC_ConfigureInterruptSources(0); } else { vMMAC_EnableInterrupts(&radio_interrupt_handler); } vMMAC_ConfigureRadio(); set_channel(MICROMAC_CONF_CHANNEL); set_txpower(MICROMAC_CONF_TX_POWER); vMMAC_GetMacAddress(&node_long_address); /* Short addresses are disabled by default */ node_short_address = (uint16_t)node_long_address.u32L; vMMAC_SetRxAddress(frame802154_get_pan_id(), node_short_address, &node_long_address); /* Disable hardware backoff */ vMMAC_SetTxParameters(1, 0, 0, 0); vMMAC_SetCutOffTimer(0, FALSE); /* Initialize ring buffer and first input packet pointer */ ringbufindex_init(&input_ringbuf, MIRCOMAC_CONF_BUF_NUM); /* get pointer to next input slot */ put_index = ringbufindex_peek_put(&input_ringbuf); if(put_index == -1) { rx_frame_buffer = NULL; printf("micromac_radio init:! no buffer available. Abort init.\n"); off(); return 0; } else { rx_frame_buffer = &input_array[put_index]; } input_frame_buffer = rx_frame_buffer; process_start(µmac_radio_process, NULL); #if RADIO_TEST_MODE == RADIO_TEST_MODE_HIGH_PWR /* Enable high power mode. * In this mode DIO2 goes high during RX * and DIO3 goes high during TX **/ vREG_SysWrite(REG_SYS_PWR_CTRL, u32REG_SysRead(REG_SYS_PWR_CTRL) | REG_SYSCTRL_PWRCTRL_RFRXEN_MASK | REG_SYSCTRL_PWRCTRL_RFTXEN_MASK); #elif RADIO_TEST_MODE == RADIO_TEST_MODE_ADVANCED /* output internal radio status on IO pins. * See Chris@NXP email */ vREG_SysWrite(REG_SYS_PWR_CTRL, u32REG_SysRead(REG_SYS_PWR_CTRL) | (1UL << 26UL)); #endif /* TEST_MODE */ return 1; }