/*---------------------------------------------------------------------------*/ static int transmit(unsigned short payload_len) { if(tx_in_progress) { return RADIO_TX_COLLISION; } tx_in_progress = 1; /* Energest */ if(listen_on) { ENERGEST_OFF(ENERGEST_TYPE_LISTEN); } ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); /* Transmit and wait */ vMMAC_StartPhyTransmit(&tx_frame_buffer, E_MMAC_TX_START_NOW | (send_on_cca ? E_MMAC_TX_USE_CCA : E_MMAC_TX_NO_CCA)); if(poll_mode) { BUSYWAIT_UNTIL(u32MMAC_PollInterruptSource(E_MMAC_INT_TX_COMPLETE), MAX_PACKET_DURATION); } else { if(in_ack_transmission) { /* as nested interupts are not possible, the tx flag will never be cleared */ BUSYWAIT_UNTIL(FALSE, MAX_ACK_DURATION); } else { /* wait until the tx flag is cleared */ BUSYWAIT_UNTIL(!tx_in_progress, MAX_PACKET_DURATION); } } /* Energest */ ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); if(listen_on) { ENERGEST_ON(ENERGEST_TYPE_LISTEN); } tx_in_progress = 0; /* Check error code */ int ret; uint32_t tx_error = u32MMAC_GetTxErrors(); if(tx_error == 0) { ret = RADIO_TX_OK; RIMESTATS_ADD(acktx); } else if(tx_error & E_MMAC_TXSTAT_ABORTED) { ret = RADIO_TX_ERR; RIMESTATS_ADD(sendingdrop); } else if(tx_error & E_MMAC_TXSTAT_CCA_BUSY) { ret = RADIO_TX_COLLISION; RIMESTATS_ADD(contentiondrop); } else if(tx_error & E_MMAC_TXSTAT_NO_ACK) { ret = RADIO_TX_NOACK; RIMESTATS_ADD(noacktx); } else { ret = RADIO_TX_ERR; } return ret; }
/*---------------------------------------------------------------------------*/ static int read(void *buf, unsigned short bufsize) { int len = 0; uint16_t radio_last_rx_crc; uint8_t radio_last_rx_crc_ok = 1; len = input_frame_buffer->u8PayloadLength; if(len <= CHECKSUM_LEN) { input_frame_buffer->u8PayloadLength = 0; return 0; } else { len -= CHECKSUM_LEN; /* Check CRC */ #if CRC_SW uint16_t checksum = crc16_data(input_frame_buffer->uPayload.au8Byte, len, 0); radio_last_rx_crc = (uint16_t)(input_frame_buffer->uPayload.au8Byte[len + 1] << (uint16_t)8) | input_frame_buffer->uPayload.au8Byte[len]; radio_last_rx_crc_ok = (checksum == radio_last_rx_crc); if(!radio_last_rx_crc_ok) { RIMESTATS_ADD(badcrc); } #endif /* CRC_SW */ if(radio_last_rx_crc_ok) { /* If we are in poll mode we need to check the frame here */ if(poll_mode) { if(frame_filtering && !is_packet_for_us(input_frame_buffer->uPayload.au8Byte, len, 0)) { len = 0; } else { read_last_rssi(); } } if(len != 0) { bufsize = MIN(len, bufsize); memcpy(buf, input_frame_buffer->uPayload.au8Byte, bufsize); RIMESTATS_ADD(llrx); if(!poll_mode) { /* Not in poll mode: packetbuf should not be accessed in interrupt context */ packetbuf_set_attr(PACKETBUF_ATTR_RSSI, radio_last_rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, radio_last_correlation); } } } else { len = 0; } /* Disable further read attempts */ input_frame_buffer->u8PayloadLength = 0; } return len; }
/*---------------------------------------------------------------------------*/ static int prepare(const void *payload, unsigned short payload_len) { uint8_t i; uint16_t checksum; RIMESTATS_ADD(lltx); if(tx_in_progress) { return 1; } if(payload_len > 127 || payload == NULL) { return 1; } /* Copy payload to (soft) Ttx buffer */ memcpy(tx_frame_buffer.uPayload.au8Byte, payload, payload_len); i = payload_len; #if CRC_SW /* Compute CRC */ checksum = crc16_data(payload, payload_len, 0); tx_frame_buffer.uPayload.au8Byte[i++] = checksum; tx_frame_buffer.uPayload.au8Byte[i++] = (checksum >> 8) & 0xff; tx_frame_buffer.u8PayloadLength = payload_len + CHECKSUM_LEN; #else tx_frame_buffer.u8PayloadLength = payload_len; #endif return 0; }
/*---------------------------------------------------------------------------*/ int runicast_send(struct runicast_conn *c, const rimeaddr_t *receiver, uint8_t max_retransmissions) { int ret; if(runicast_is_transmitting(c)) { PRINTF("%d.%d: runicast: already transmitting\n", rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1]); return 0; } packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, 1); packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_DATA); packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, c->sndnxt); packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, 3); c->max_rxmit = max_retransmissions; c->rxmit = 0; c->is_tx = 1; RIMESTATS_ADD(reliabletx); PRINTF("%d.%d: runicast: sending packet %d\n", rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1], c->sndnxt); ret = stunicast_send_stubborn(&c->c, receiver, REXMIT_TIME); if(!ret) { c->is_tx = 0; } return ret; }
/*---------------------------------------------------------------------------*/ static int cc2520_prepare(const void *payload, unsigned short payload_len) { uint8_t total_len; GET_LOCK(); PRINTF("cc2520: sending %d bytes\n", payload_len); /*int i; for(i = 0; i < payload_len;i++) printf("%x",((uint8_t *) payload)[i]); printf("\n");*/ RIMESTATS_ADD(lltx); /* Wait for any previous transmission to finish. */ /* while(status() & BV(CC2520_TX_ACTIVE));*/ /* Write packet to TX FIFO. */ strobe(CC2520_INS_SFLUSHTX); total_len = payload_len + FOOTER_LEN; CC2520_WRITE_FIFO_BUF(&total_len, 1); CC2520_WRITE_FIFO_BUF(payload, payload_len); RELEASE_LOCK(); return 0; }
/*---------------------------------------------------------------------------*/ static int cc2420_prepare(const void *payload, unsigned short payload_len) { uint8_t total_len; #if CC2420_CONF_CHECKSUM uint16_t checksum; #endif /* CC2420_CONF_CHECKSUM */ GET_LOCK(); PRINTF("cc2420: sending %d bytes\n", payload_len); RIMESTATS_ADD(lltx); /* Wait for any previous transmission to finish. */ /* while(status() & BV(CC2420_TX_ACTIVE));*/ /* Write packet to TX FIFO. */ strobe(CC2420_SFLUSHTX); #if CC2420_CONF_CHECKSUM checksum = crc16_data(payload, payload_len, 0); #endif /* CC2420_CONF_CHECKSUM */ total_len = payload_len + AUX_LEN; CC2420_WRITE_FIFO_BUF(&total_len, 1); CC2420_WRITE_FIFO_BUF(payload, payload_len); #if CC2420_CONF_CHECKSUM CC2420_WRITE_FIFO_BUF(&checksum, CHECKSUM_LEN); #endif /* CC2420_CONF_CHECKSUM */ RELEASE_LOCK(); return 0; }
void uwb_dma_interrupt(void) { /* DMA transaction finished */ if (uwb_fsm == UWB_STATE_RX_LEN_DOWNLOAD) { /* we downloaded the frame length - now download the frame! */ if (ram_rx_buffer[2] > 0) { ram_tx_buffer[0] = CMD_READ_RAM_RX; hal_spi_dma_transfer(ram_tx_buffer, ram_rx_buffer, ram_rx_buffer[2]+3); uwb_fsm = UWB_STATE_RX_FRAME_DOWNLOAD; } else { /* directly poll process to handle zero-length frame */ process_poll(&uwb_process); RIMESTATS_ADD(llrx); uwb_fsm = UWB_STATE_RX_PROCESS_POLLED; } } else if (uwb_fsm == UWB_STATE_RX_FRAME_DOWNLOAD) { /* download complete, poll process */ process_poll(&uwb_process); RIMESTATS_ADD(llrx); uwb_fsm = UWB_STATE_RX_PROCESS_POLLED; } else if (uwb_fsm == USB_STATE_TX_FRAME_UPLOAD) { /* tx frame uploaded, move back to listen state */ /* here we could also implement a mechanism that starts the tx by sending config right away */ uwb_fsm = UWB_STATE_LISTEN; // PRINTF("d1"); } else if (uwb_fsm == USB_STATE_TX_CONFIG_UPLOAD) { /* tx config uploaded, assume the phy is transmitting now */ uwb_fsm = USB_STATE_TX_ACTIVE; /* enable tx-int */ HAL_ENABLE_IRQ1( ); // PRINTF("d2"); } }
/*---------------------------------------------------------------------------*/ int rime_output(struct channel *c) { RIMESTATS_ADD(tx); if(chameleon_create(c)) { packetbuf_compact(); NETSTACK_MAC.send(packet_sent, c); return 1; } return 0; }
/*---------------------------------------------------------------------------*/ static void sent_by_stunicast(struct stunicast_conn *stunicast, int status, int num_tx) { struct runicast_conn *c = (struct runicast_conn *)stunicast; PRINTF("runicast: sent_by_stunicast c->rxmit %d num_tx %d\n", c->rxmit, num_tx); /* Only process data packets, not ACKs. */ if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_DATA) { c->rxmit += 1; if(c->rxmit != 0) { RIMESTATS_ADD(rexmit); PRINTF("%d.%d: runicast: sent_by_stunicast packet %u (%u) resent %u\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], packetbuf_attr(PACKETBUF_ATTR_PACKET_ID), c->sndnxt, c->rxmit); } if(c->rxmit >= c->max_rxmit) { RIMESTATS_ADD(timedout); c->is_tx = 0; stunicast_cancel(&c->c); if(c->u->timedout) { c->u->timedout(c, stunicast_receiver(&c->c), c->rxmit); } c->rxmit = 0; PRINTF("%d.%d: runicast: packet %d timed out\n", rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1], c->sndnxt); c->sndnxt = (c->sndnxt + 1) % (1 << RUNICAST_PACKET_ID_BITS); } else { // int shift; // shift = c->rxmit > 4? 4: c->rxmit; // stunicast_set_timer(&c->c, (REXMIT_TIME) << shift); } } }
static int qsend_packet(void) { if(someone_is_sending) { PRINTF("xmac: should queue packet, now just dropping %d %d %d %d.\n", waiting_for_packet, someone_is_sending, we_are_sending, radio_is_on); if(queued_packet != NULL) { RIMESTATS_ADD(sendingdrop); return 0; } else { #if WITH_QUEUE queued_packet = queuebuf_new_from_rimebuf(); return 1; #else RIMESTATS_ADD(sendingdrop); return 0; #endif } } else { PRINTF("xmac: send immediately.\n"); return send_packet(); } }
/*---------------------------------------------------------------------------*/ static void input(const struct mac_driver *r) { int len; struct rime_sniffer *s; len = rime_mac->read(); if(len > 0) { for(s = list_head(sniffers); s != NULL; s = s->next) { if(s->input_callback != NULL) { s->input_callback(); } } RIMESTATS_ADD(rx); chameleon_input(); } }
/*---------------------------------------------------------------------------*/ static void qsend_packet(mac_callback_t sent, void *ptr) { int ret; if(someone_is_sending) { PRINTF("cxmac: should queue packet, now just dropping %d %d %d %d.\n", waiting_for_packet, someone_is_sending, we_are_sending, radio_is_on); RIMESTATS_ADD(sendingdrop); ret = MAC_TX_COLLISION; } else { PRINTF("cxmac: send immediately.\n"); ret = send_packet(); } mac_call_sent_callback(sent, ptr, ret, 1); }
/*---------------------------------------------------------------------------*/ static int radio_read(void *buf, unsigned short bufsize) { int tmp = simInSize; if (simInSize == 0) { return 0; } if(bufsize < simInSize) { simInSize = 0; /* rx flush */ RIMESTATS_ADD(toolong); return 0; } memcpy(buf, simInDataBuffer, simInSize); simInSize = 0; return tmp; }
/*---------------------------------------------------------------------------*/ static void input(void) { struct rime_sniffer *s; struct channel *c; RIMESTATS_ADD(rx); c = chameleon_parse(); for(s = list_head(sniffers); s != NULL; s = list_item_next(s)) { if(s->input_callback != NULL) { s->input_callback(); } } if(c != NULL) { abc_input(c); } }
/*---------------------------------------------------------------------------*/ void rime_output(void) { struct rime_sniffer *s; RIMESTATS_ADD(tx); packetbuf_compact(); if(rime_mac) { if(rime_mac->send()) { /* Call sniffers, but only if the packet was sent. */ for(s = list_head(sniffers); s != NULL; s = s->next) { if(s->output_callback != NULL) { s->output_callback(); } } } } }
/*---------------------------------------------------------------------------*/ static int send_one_packet(mac_callback_t sent, void *ptr) { int ret; int last_sent_ok = 0; packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); #if DISCOVERY_AWARE_RDC_802154_AUTOACK || DISCOVERY_AWARE_RDC_802154_AUTOACK_HW packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); #endif /* DISCOVERY_AWARE_RDC_802154_AUTOACK || DISCOVERY_AWARE_RDC_802154_AUTOACK_HW */ if (!radio_status) { on(); } if(NETSTACK_FRAMER.create() < 0) { /* Failed to allocate space for headers */ PRINTF("RDC: send failed, too large header\n"); ret = MAC_TX_ERR_FATAL; } else { #ifdef NETSTACK_ENCRYPT NETSTACK_ENCRYPT(); #endif /* NETSTACK_ENCRYPT */ #if DISCOVERY_AWARE_RDC_802154_AUTOACK int is_broadcast; uint8_t dsn; dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff; NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen()); is_broadcast = linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_null); if(NETSTACK_RADIO.receiving_packet() || (!is_broadcast && NETSTACK_RADIO.pending_packet())) { /* Currently receiving a packet over air or the radio has already received a packet that needs to be read before sending with auto ack. */ ret = MAC_TX_COLLISION; } else { if(!is_broadcast) { RIMESTATS_ADD(reliabletx); } switch(NETSTACK_RADIO.transmit(packetbuf_totlen())) { case RADIO_TX_OK: if(is_broadcast) { ret = MAC_TX_OK; } else { rtimer_clock_t wt; /* Check for ack */ wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)) { #if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); #endif /* CONTIKI_TARGET_COOJA */ } ret = MAC_TX_NOACK; if(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet() || NETSTACK_RADIO.channel_clear() == 0) { int len; uint8_t ackbuf[ACK_LEN]; if(AFTER_ACK_DETECTED_WAIT_TIME > 0) { wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTED_WAIT_TIME)) { #if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); #endif /* CONTIKI_TARGET_COOJA */ } } if(NETSTACK_RADIO.pending_packet()) { len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); if(len == ACK_LEN && ackbuf[2] == dsn) { /* Ack received */ RIMESTATS_ADD(ackrx); ret = MAC_TX_OK; } else { /* Not an ack or ack not for us: collision */ ret = MAC_TX_COLLISION; } } } else { PRINTF("RDC tx noack\n"); } } break; case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; default: ret = MAC_TX_ERR; break; } } #else /* ! DISCOVERY_AWARE_RDC_802154_AUTOACK */ switch(NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen())) { case RADIO_TX_OK: ret = MAC_TX_OK; break; case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; case RADIO_TX_NOACK: ret = MAC_TX_NOACK; break; default: ret = MAC_TX_ERR; break; } #endif /* ! DISCOVERY_AWARE_RDC_802154_AUTOACK */ } if (!linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_null) && ret == MAC_TX_OK) { send_flag = 1; to_modifier+=10; } if(ret == MAC_TX_OK) { last_sent_ok = 1; } mac_call_sent_callback(sent, ptr, ret, 1); return last_sent_ok; }
/*---------------------------------------------------------------------------*/ 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 cc2420_transmit(unsigned short payload_len) { int i, txpower; uint8_t total_len; #if CC2420_CONF_CHECKSUM uint16_t checksum; #endif /* CC2420_CONF_CHECKSUM */ GET_LOCK(); txpower = 0; if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { /* Remember the current transmission power */ txpower = cc2420_get_txpower(); /* Set the specified transmission power */ set_txpower(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) - 1); } total_len = payload_len + AUX_LEN; /* The TX FIFO can only hold one packet. Make sure to not overrun * FIFO by waiting for transmission to start here and synchronizing * with the CC2420_TX_ACTIVE check in cc2420_send. * * Note that we may have to wait up to 320 us (20 symbols) before * transmission starts. */ #ifdef TMOTE_SKY #define LOOP_20_SYMBOLS 400 /* 326us (msp430 @ 2.4576MHz) */ #elif __AVR__ #define LOOP_20_SYMBOLS 500 /* XXX */ #endif #if WITH_SEND_CCA strobe(CC2420_SRXON); while(!(status() & BV(CC2420_RSSI_VALID))); strobe(CC2420_STXONCCA); #else /* WITH_SEND_CCA */ strobe(CC2420_STXON); #endif /* WITH_SEND_CCA */ for(i = LOOP_20_SYMBOLS; i > 0; i--) { if(SFD_IS_1) { if(!(status() & BV(CC2420_TX_ACTIVE))) { /* SFD went high but we are not transmitting. This means that we just started receiving a packet, so we drop the transmission. */ return RADIO_TX_ERR; } if(receive_on) { ENERGEST_OFF(ENERGEST_TYPE_LISTEN); } ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); /* We wait until transmission has ended so that we get an accurate measurement of the transmission time.*/ while(status() & BV(CC2420_TX_ACTIVE)); #ifdef ENERGEST_CONF_LEVELDEVICE_LEVELS ENERGEST_OFF_LEVEL(ENERGEST_TYPE_TRANSMIT,cc2420_get_txpower()); #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); if(receive_on) { ENERGEST_ON(ENERGEST_TYPE_LISTEN); } else { /* We need to explicitly turn off the radio, * since STXON[CCA] -> TX_ACTIVE -> RX_ACTIVE */ off(); } if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { /* Restore the transmission power */ set_txpower(txpower & 0xff); } RELEASE_LOCK(); return RADIO_TX_OK; } } /* If we are using WITH_SEND_CCA, we get here if the packet wasn't transmitted because of other channel activity. */ RIMESTATS_ADD(contentiondrop); PRINTF("cc2420: do_send() transmission never started\n"); if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { /* Restore the transmission power */ set_txpower(txpower & 0xff); } RELEASE_LOCK(); return RADIO_TX_ERR; /* Transmission never started! */ }
/*---------------------------------------------------------------------------*/ static int read(void *buf, unsigned short bufsize) { uint8_t i; uint8_t len; uint8_t crc_corr; int8_t rssi; PRINTF("RF: Read\n"); if((REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) == 0) { return 0; } /* Check the length */ len = REG(RFCORE_SFR_RFDATA); /* Check for validity */ if(len > CC2538_RF_MAX_PACKET_LEN) { /* Oops, we must be out of sync. */ PRINTF("RF: bad sync\n"); RIMESTATS_ADD(badsynch); CC2538_RF_CSP_ISFLUSHRX(); return 0; } if(len <= CC2538_RF_MIN_PACKET_LEN) { PRINTF("RF: too short\n"); RIMESTATS_ADD(tooshort); CC2538_RF_CSP_ISFLUSHRX(); return 0; } if(len - CHECKSUM_LEN > bufsize) { PRINTF("RF: too long\n"); RIMESTATS_ADD(toolong); CC2538_RF_CSP_ISFLUSHRX(); return 0; } /* If we reach here, chances are the FIFO is holding a valid frame */ PRINTF("RF: read (0x%02x bytes) = ", len); len -= CHECKSUM_LEN; /* Don't bother with uDMA for short frames (e.g. ACKs) */ if(CC2538_RF_CONF_RX_USE_DMA && len > UDMA_RX_SIZE_THRESHOLD) { PRINTF("<uDMA payload>"); /* Set the transfer destination's end address */ udma_set_channel_dst(CC2538_RF_CONF_RX_DMA_CHAN, (uint32_t)(buf) + len - 1); /* Configure the control word */ udma_set_channel_control_word(CC2538_RF_CONF_RX_DMA_CHAN, UDMA_RX_FLAGS | udma_xfer_size(len)); /* Enabled the RF RX uDMA channel */ udma_channel_enable(CC2538_RF_CONF_RX_DMA_CHAN); /* Trigger the uDMA transfer */ udma_channel_sw_request(CC2538_RF_CONF_RX_DMA_CHAN); /* Wait for the transfer to complete. */ while(udma_channel_get_mode(CC2538_RF_CONF_RX_DMA_CHAN)); } else { for(i = 0; i < len; ++i) { ((unsigned char *)(buf))[i] = REG(RFCORE_SFR_RFDATA); PRINTF("%02x", ((unsigned char *)(buf))[i]); } } /* Read the RSSI and CRC/Corr bytes */ rssi = ((int8_t)REG(RFCORE_SFR_RFDATA)) - RSSI_OFFSET; crc_corr = REG(RFCORE_SFR_RFDATA); PRINTF("%02x%02x\n", (uint8_t)rssi, crc_corr); /* MS bit CRC OK/Not OK, 7 LS Bits, Correlation value */ if(crc_corr & CRC_BIT_MASK) { packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK); RIMESTATS_ADD(llrx); } else { RIMESTATS_ADD(badcrc); PRINTF("RF: Bad CRC\n"); CC2538_RF_CSP_ISFLUSHRX(); return 0; } #if CC2538_RF_CONF_SNIFFER write_byte(magic[0]); write_byte(magic[1]); write_byte(magic[2]); write_byte(magic[3]); write_byte(len + 2); for(i = 0; i < len; ++i) { write_byte(((unsigned char *)(buf))[i]); } write_byte(rssi); write_byte(crc_corr); flush(); #endif /* If FIFOP==1 and FIFO==0 then we had a FIFO overflow at some point. */ if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) { if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFO) { process_poll(&cc2538_rf_process); } else { CC2538_RF_CSP_ISFLUSHRX(); } } return (len); }
/*---------------------------------------------------------------------------*/ static int cc2420_read(void *buf, unsigned short bufsize) { uint8_t footer[2]; uint8_t len; #if CC2420_CONF_CHECKSUM uint16_t checksum; #endif /* CC2420_CONF_CHECKSUM */ if(!CC2420_FIFOP_IS_1) { return 0; } /* if(!pending) { return 0; }*/ pending = 0; GET_LOCK(); cc2420_packets_read++; getrxbyte(&len); if(len > CC2420_MAX_PACKET_LEN) { /* Oops, we must be out of sync. */ flushrx(); RIMESTATS_ADD(badsynch); RELEASE_LOCK(); return 0; } if(len <= AUX_LEN) { flushrx(); RIMESTATS_ADD(tooshort); RELEASE_LOCK(); return 0; } if(len - AUX_LEN > bufsize) { flushrx(); RIMESTATS_ADD(toolong); RELEASE_LOCK(); return 0; } getrxdata(buf, len - AUX_LEN); #if CC2420_CONF_CHECKSUM getrxdata(&checksum, CHECKSUM_LEN); #endif /* CC2420_CONF_CHECKSUM */ getrxdata(footer, FOOTER_LEN); #if CC2420_CONF_CHECKSUM if(checksum != crc16_data(buf, len - AUX_LEN, 0)) { PRINTF("checksum failed 0x%04x != 0x%04x\n", checksum, crc16_data(buf, len - AUX_LEN, 0)); } if(footer[1] & FOOTER1_CRC_OK && checksum == crc16_data(buf, len - AUX_LEN, 0)) { #else if(footer[1] & FOOTER1_CRC_OK) { #endif /* CC2420_CONF_CHECKSUM */ cc2420_last_rssi = footer[0]; cc2420_last_correlation = footer[1] & FOOTER1_CORRELATION; packetbuf_set_attr(PACKETBUF_ATTR_RSSI, cc2420_last_rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, cc2420_last_correlation); RIMESTATS_ADD(llrx); } else { RIMESTATS_ADD(badcrc); len = AUX_LEN; } if(CC2420_FIFOP_IS_1) { if(!CC2420_FIFO_IS_1) { /* Clean up in case of FIFO overflow! This happens for every * full length frame and is signaled by FIFOP = 1 and FIFO = * 0. */ flushrx(); } else { /* Another packet has been received and needs attention. */ process_poll(&cc2420_process); } } RELEASE_LOCK(); if(len < AUX_LEN) { return 0; } return len - AUX_LEN; } /*---------------------------------------------------------------------------*/ void cc2420_set_txpower(uint8_t power) { GET_LOCK(); set_txpower(power); RELEASE_LOCK(); }
/*---------------------------------------------------------------------------*/ static int send_one_packet(struct net_buf *buf, mac_callback_t sent, void *ptr) { int ret; int last_sent_ok = 0; #if NULLRDC_ENABLE_RETRANSMISSIONS rtimer_clock_t target_time; uint8_t tx_attempts = 0; uint8_t max_tx_attempts; if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) > 0) { max_tx_attempts = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS); } else { max_tx_attempts = NULLRDC_MAX_RETRANSMISSIONS + 1; } #endif /* NULLRDC_ENABLE_RETRANSMISSIONS */ packetbuf_set_addr(buf, PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW packetbuf_set_attr(buf, PACKETBUF_ATTR_MAC_ACK, 1); #endif /* NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW */ if(NETSTACK_FRAMER.create_and_secure(buf) < 0) { /* Failed to allocate space for headers */ PRINTF("nullrdc: send failed, too large header\n"); ret = MAC_TX_ERR_FATAL; } else { #if NULLRDC_802154_AUTOACK int is_broadcast; uint8_t dsn; dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff; NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen()); is_broadcast = packetbuf_holds_broadcast(); if(NETSTACK_RADIO.receiving_packet() || (!is_broadcast && NETSTACK_RADIO.pending_packet())) { /* Currently receiving a packet over air or the radio has already received a packet that needs to be read before sending with auto ack. */ ret = MAC_TX_COLLISION; } else { if(!is_broadcast) { RIMESTATS_ADD(reliabletx); } #if NULLRDC_ENABLE_RETRANSMISSIONS while(1) { /* Transmit packet and check status */ tx_attempts++; #endif /* NULLRDC_ENABLE_RETRANSMISSIONS */ switch(NETSTACK_RADIO.transmit(packetbuf_totlen(buf))) { case RADIO_TX_OK: if(is_broadcast) { ret = MAC_TX_OK; } else { rtimer_clock_t wt; /* Check for ack */ wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)) { #if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); #endif /* CONTIKI_TARGET_COOJA */ } ret = MAC_TX_NOACK; if(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet() || NETSTACK_RADIO.channel_clear() == 0) { int len; uint8_t ackbuf[ACK_LEN]; if(AFTER_ACK_DETECTED_WAIT_TIME > 0) { wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTED_WAIT_TIME)) { #if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); #endif /* CONTIKI_TARGET_COOJA */ } } if(NETSTACK_RADIO.pending_packet()) { len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); if(len == ACK_LEN && ackbuf[2] == dsn) { /* Ack received */ RIMESTATS_ADD(ackrx); ret = MAC_TX_OK; } else { /* Not an ack or ack not for us: collision */ ret = MAC_TX_COLLISION; } } } else { PRINTF("nullrdc tx noack\n"); } } break; case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; default: ret = MAC_TX_ERR; break; } #if NULLRDC_ENABLE_RETRANSMISSIONS if(is_broadcast) { #if !NULLRDC_ENABLE_RETRANSMISSIONS_BCAST break; #else /* NULLRDC_ENABLE_RETRANSMISSIONS_BCAST */ if(ret != MAC_TX_COLLISION) { /* Retry broadcast frame only upon collision */ break; } #endif /* NULLRDC_ENABLE_RETRANSMISSIONS_BCAST */ } else { /* Frame is unicast. Do not retry unless NO_ACK or COLLISION */ if((ret != MAC_TX_NOACK) && (ret != MAC_TX_COLLISION)) { break; } } /* Do not retry if max attempts reached. */ if(tx_attempts >= max_tx_attempts) { PRINTF("nullrdc: max tx attempts reached\n"); break; } /* Block-wait before retrying the frame. */ target_time = RTIMER_NOW() + (RTIMER_SECOND * NULLRDC_TX_RETRY_DELAY_MS / 1000); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), target_time)) { /* Wait */ } /* Attempt a new frame (re)transmission */ } #endif /* NULLRDC_ENABLE_RETRANSMISSIONS */ } #else /* ! NULLRDC_802154_AUTOACK */ switch(NETSTACK_RADIO.send(buf, packetbuf_hdrptr(buf), packetbuf_totlen(buf))) { case RADIO_TX_OK: ret = MAC_TX_OK; break; case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; case RADIO_TX_NOACK: ret = MAC_TX_NOACK; break; default: ret = MAC_TX_ERR; break; } #endif /* ! NULLRDC_802154_AUTOACK */ } if(ret == MAC_TX_OK) { last_sent_ok = 1; } #if ! NULLRDC_ENABLE_RETRANSMISSIONS mac_call_sent_callback(buf, sent, ptr, ret, 1); #else mac_call_sent_callback(buf, sent, ptr, ret, tx_attempts); #endif /* !NULLRDC_ENABLE_RETRANSMISSIONS */ return last_sent_ok; }
/*---------------------------------------------------------------------------*/ static int transmit(unsigned short transmit_len) { uint8_t counter; int ret = RADIO_TX_ERR; rtimer_clock_t t0; transmit_len; /* hush the warning */ if(!(rf_flags & RX_ACTIVE)) { t0 = RTIMER_NOW(); on(); rf_flags |= WAS_OFF; while (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ONOFF_TIME)); } if(channel_clear() == CC2530_RF_CCA_BUSY) { RIMESTATS_ADD(contentiondrop); return RADIO_TX_COLLISION; } /* * prepare() double checked that TX_ACTIVE is low. If SFD is high we are * receiving. Abort transmission and bail out with RADIO_TX_COLLISION */ if(FSMSTAT1 & FSMSTAT1_SFD) { RIMESTATS_ADD(contentiondrop); return RADIO_TX_COLLISION; } /* Start the transmission */ RF_TX_LED_ON(); ENERGEST_OFF(ENERGEST_TYPE_LISTEN); ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); CC2530_CSP_ISTXON(); counter = 0; while(!(FSMSTAT1 & FSMSTAT1_TX_ACTIVE) && (counter++ < 3)) { clock_delay_usec(6); } if(!(FSMSTAT1 & FSMSTAT1_TX_ACTIVE)) { PUTSTRING("RF: TX never active.\n"); CC2530_CSP_ISFLUSHTX(); ret = RADIO_TX_ERR; } else { /* Wait for the transmission to finish */ while(FSMSTAT1 & FSMSTAT1_TX_ACTIVE); ret = RADIO_TX_OK; } ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); ENERGEST_ON(ENERGEST_TYPE_LISTEN); if(rf_flags & WAS_OFF){ off(); } RIMESTATS_ADD(lltx); RF_TX_LED_OFF(); /* OK, sent. We are now ready to send more */ return ret; }
/*---------------------------------------------------------------------------*/ static int cc2520_transmit(unsigned short payload_len) { int i, txpower; GET_LOCK(); txpower = 0; if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { /* Remember the current transmission power */ txpower = cc2520_get_txpower(); /* Set the specified transmission power */ set_txpower(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) - 1); } /* The TX FIFO can only hold one packet. Make sure to not overrun * FIFO by waiting for transmission to start here and synchronizing * with the CC2520_TX_ACTIVE check in cc2520_send. * * Note that we may have to wait up to 320 us (20 symbols) before * transmission starts. */ #ifndef CC2520_CONF_SYMBOL_LOOP_COUNT #error CC2520_CONF_SYMBOL_LOOP_COUNT needs to be set!!! #else #define LOOP_20_SYMBOLS CC2520_CONF_SYMBOL_LOOP_COUNT #endif #if WITH_SEND_CCA strobe(CC2520_INS_SRXON); BUSYWAIT_UNTIL(status() & BV(CC2520_RSSI_VALID) , RTIMER_SECOND / 10); strobe(CC2520_INS_STXONCCA); #else /* WITH_SEND_CCA */ strobe(CC2520_INS_STXON); #endif /* WITH_SEND_CCA */ for(i = LOOP_20_SYMBOLS; i > 0; i--) { if(CC2520_SFD_IS_1) { { rtimer_clock_t sfd_timestamp; sfd_timestamp = cc2520_sfd_start_time; if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP) { /* Write timestamp to last two bytes of packet in TXFIFO. */ CC2520_WRITE_RAM(&sfd_timestamp, CC2520RAM_TXFIFO + payload_len - 1, 2); } } if(!(status() & BV(CC2520_TX_ACTIVE))) { /* SFD went high but we are not transmitting. This means that we just started receiving a packet, so we drop the transmission. */ RELEASE_LOCK(); return RADIO_TX_COLLISION; } if(receive_on) { ENERGEST_OFF(ENERGEST_TYPE_LISTEN); } ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); /* We wait until transmission has ended so that we get an accurate measurement of the transmission time.*/ //BUSYWAIT_UNTIL(getreg(CC2520_EXCFLAG0) & TX_FRM_DONE , RTIMER_SECOND / 100); BUSYWAIT_UNTIL(!(status() & BV(CC2520_TX_ACTIVE)), RTIMER_SECOND / 10); #ifdef ENERGEST_CONF_LEVELDEVICE_LEVELS ENERGEST_OFF_LEVEL(ENERGEST_TYPE_TRANSMIT,cc2520_get_txpower()); #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); if(receive_on) { ENERGEST_ON(ENERGEST_TYPE_LISTEN); } else { /* We need to explicitly turn off the radio, * since STXON[CCA] -> TX_ACTIVE -> RX_ACTIVE */ off(); } if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { /* Restore the transmission power */ set_txpower(txpower & 0xff); } RELEASE_LOCK(); return RADIO_TX_OK; } } /* If we are using WITH_SEND_CCA, we get here if the packet wasn't transmitted because of other channel activity. */ RIMESTATS_ADD(contentiondrop); PRINTF("cc2520: do_send() transmission never started\n"); if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { /* Restore the transmission power */ set_txpower(txpower & 0xff); } RELEASE_LOCK(); return RADIO_TX_COLLISION; }
/*---------------------------------------------------------------------------*/ int cc2420_send(const void *payload, unsigned short payload_len) { int i; uint8_t total_len; struct timestamp timestamp; uint16_t checksum; GET_LOCK(); PRINTF("cc2420: sending %d bytes\n", payload_len); RIMESTATS_ADD(lltx); /* Wait for any previous transmission to finish. */ while(status() & BV(CC2420_TX_ACTIVE)); /* Write packet to TX FIFO. */ strobe(CC2420_SFLUSHTX); checksum = crc16_data(payload, payload_len, 0); total_len = payload_len + AUX_LEN; FASTSPI_WRITE_FIFO(&total_len, 1); FASTSPI_WRITE_FIFO(payload, payload_len); FASTSPI_WRITE_FIFO(&checksum, CHECKSUM_LEN); #if CC2420_CONF_TIMESTAMPS timestamp.authority_level = timesynch_authority_level(); timestamp.time = timesynch_time(); FASTSPI_WRITE_FIFO(×tamp, TIMESTAMP_LEN); #endif /* CC2420_CONF_TIMESTAMPS */ /* The TX FIFO can only hold one packet. Make sure to not overrun * FIFO by waiting for transmission to start here and synchronizing * with the CC2420_TX_ACTIVE check in cc2420_send. * * Note that we may have to wait up to 320 us (20 symbols) before * transmission starts. */ #ifdef TMOTE_SKY #define LOOP_20_SYMBOLS 100 /* 326us (msp430 @ 2.4576MHz) */ #elif __AVR__ #define LOOP_20_SYMBOLS 500 /* XXX */ #endif #if WITH_SEND_CCA strobe(CC2420_SRXON); while(!(status() & BV(CC2420_RSSI_VALID))); strobe(CC2420_STXONCCA); #else /* WITH_SEND_CCA */ strobe(CC2420_STXON); #endif /* WITH_SEND_CCA */ for(i = LOOP_20_SYMBOLS; i > 0; i--) { if(SFD_IS_1) { #if CC2420_CONF_TIMESTAMPS rtimer_clock_t txtime = timesynch_time(); #endif /* CC2420_CONF_TIMESTAMPS */ if(receive_on) { ENERGEST_OFF(ENERGEST_TYPE_LISTEN); } ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); /* We wait until transmission has ended so that we get an accurate measurement of the transmission time.*/ while(status() & BV(CC2420_TX_ACTIVE)); #if CC2420_CONF_TIMESTAMPS setup_time_for_transmission = txtime - timestamp.time; if(num_transmissions < 10000) { total_time_for_transmission += timesynch_time() - txtime; total_transmission_len += total_len; num_transmissions++; } #endif /* CC2420_CONF_TIMESTAMPS */ #ifdef ENERGEST_CONF_LEVELDEVICE_LEVELS ENERGEST_OFF_LEVEL(ENERGEST_TYPE_TRANSMIT,cc2420_get_txpower()); #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); if(receive_on) { ENERGEST_ON(ENERGEST_TYPE_LISTEN); } RELEASE_LOCK(); return 0; } } /* If we are using WITH_SEND_CCA, we get here if the packet wasn't transmitted because of other channel activity. */ RIMESTATS_ADD(contentiondrop); PRINTF("cc2420: do_send() transmission never started\n"); RELEASE_LOCK(); return -3; /* Transmission never started! */ }
/*---------------------------------------------------------------------------*/ static int cc2520_read(void *buf, unsigned short bufsize) { uint8_t footer[2]; uint8_t len; if(!CC2520_FIFOP_IS_1) { return 0; } GET_LOCK(); cc2520_packets_read++; getrxbyte(&len); if(len > CC2520_MAX_PACKET_LEN) { /* Oops, we must be out of sync. */ flushrx(); RIMESTATS_ADD(badsynch); RELEASE_LOCK(); return 0; } if(len <= FOOTER_LEN) { flushrx(); RIMESTATS_ADD(tooshort); RELEASE_LOCK(); return 0; } if(len - FOOTER_LEN > bufsize) { flushrx(); RIMESTATS_ADD(toolong); RELEASE_LOCK(); return 0; } getrxdata(buf, len - FOOTER_LEN); getrxdata(footer, FOOTER_LEN); if(footer[1] & FOOTER1_CRC_OK) { cc2520_last_rssi = footer[0]; cc2520_last_correlation = footer[1] & FOOTER1_CORRELATION; packetbuf_set_attr(PACKETBUF_ATTR_RSSI, cc2520_last_rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, cc2520_last_correlation); RIMESTATS_ADD(llrx); } else { RIMESTATS_ADD(badcrc); len = FOOTER_LEN; } if(CC2520_FIFOP_IS_1) { if(!CC2520_FIFO_IS_1) { /* Clean up in case of FIFO overflow! This happens for every * full length frame and is signaled by FIFOP = 1 and FIFO = * 0. */ flushrx(); } else { /* Another packet has been received and needs attention. */ process_poll(&cc2520_process); } } RELEASE_LOCK(); if(len < FOOTER_LEN) { return 0; } return len - FOOTER_LEN; }
/*---------------------------------------------------------------------------*/ int cc2420_read(void *buf, unsigned short bufsize) { uint8_t footer[2]; uint8_t len; uint16_t checksum; struct timestamp t; if(!FIFOP_IS_1) { /* If FIFOP is 0, there is no packet in the RXFIFO. */ return 0; } if(interrupt_time_set) { #if CC2420_CONF_TIMESTAMPS cc2420_time_of_arrival = interrupt_time; #endif /* CC2420_CONF_TIMESTAMPS */ interrupt_time_set = 0; } else { cc2420_time_of_arrival = 0; } cc2420_time_of_departure = 0; GET_LOCK(); getrxbyte(&len); if(len > CC2420_MAX_PACKET_LEN) { /* Oops, we must be out of sync. */ flushrx(); RIMESTATS_ADD(badsynch); RELEASE_LOCK(); return 0; } if(len <= AUX_LEN) { flushrx(); RIMESTATS_ADD(tooshort); RELEASE_LOCK(); return 0; } if(len - AUX_LEN > bufsize) { flushrx(); RIMESTATS_ADD(toolong); RELEASE_LOCK(); return 0; } getrxdata(buf, len - AUX_LEN); getrxdata(&checksum, CHECKSUM_LEN); getrxdata(&t, TIMESTAMP_LEN); getrxdata(footer, FOOTER_LEN); if(footer[1] & FOOTER1_CRC_OK && checksum == crc16_data(buf, len - AUX_LEN, 0)) { cc2420_last_rssi = footer[0]; cc2420_last_correlation = footer[1] & FOOTER1_CORRELATION; RIMESTATS_ADD(llrx); #if CC2420_CONF_TIMESTAMPS cc2420_time_of_departure = t.time + setup_time_for_transmission + (total_time_for_transmission * (len - 2)) / total_transmission_len; cc2420_authority_level_of_sender = t.authority_level; #endif /* CC2420_CONF_TIMESTAMPS */ } else { RIMESTATS_ADD(badcrc); len = AUX_LEN; } /* Clean up in case of FIFO overflow! This happens for every full * length frame and is signaled by FIFOP = 1 and FIFO = 0. */ if(FIFOP_IS_1 && !FIFO_IS_1) { /* printf("cc2420_read: FIFOP_IS_1 1\n");*/ flushrx(); } else if(FIFOP_IS_1) { /* Another packet has been received and needs attention. */ process_poll(&cc2420_process); } RELEASE_LOCK(); if(len < AUX_LEN) { return 0; } return len - AUX_LEN; }
/*---------------------------------------------------------------------------*/ static int read(void *buf, unsigned short bufsize) { uint8_t i; uint8_t len; uint8_t crc_corr; int8_t rssi; PUTSTRING("RF: Read\n"); /* Check the length */ len = RFD; /* Check for validity */ if(len > CC2530_RF_MAX_PACKET_LEN) { /* Oops, we must be out of sync. */ PUTSTRING("RF: bad sync\n"); RIMESTATS_ADD(badsynch); CC2530_CSP_ISFLUSHRX(); return 0; } if(len <= CC2530_RF_MIN_PACKET_LEN) { PUTSTRING("RF: too short\n"); RIMESTATS_ADD(tooshort); CC2530_CSP_ISFLUSHRX(); return 0; } if(len - CHECKSUM_LEN > bufsize) { PUTSTRING("RF: too long\n"); RIMESTATS_ADD(toolong); CC2530_CSP_ISFLUSHRX(); return 0; } #if CC2530_RF_CONF_HEXDUMP /* If we reach here, chances are the FIFO is holding a valid frame */ uart0_writeb(magic[0]); uart0_writeb(magic[1]); uart0_writeb(magic[2]); uart0_writeb(magic[3]); uart0_writeb(len); #endif RF_RX_LED_ON(); PUTSTRING("RF: read (0x"); PUTHEX(len); PUTSTRING(" bytes) = "); len -= CHECKSUM_LEN; for(i = 0; i < len; ++i) { ((unsigned char*)(buf))[i] = RFD; #if CC2530_RF_CONF_HEXDUMP uart0_writeb(((unsigned char*)(buf))[i]); #endif PUTHEX(((unsigned char*)(buf))[i]); } PUTSTRING("\n"); /* Read the RSSI and CRC/Corr bytes */ rssi = ((int8_t) RFD) - 45; crc_corr = RFD; #if CC2530_RF_CONF_HEXDUMP uart0_writeb(rssi); uart0_writeb(crc_corr); #endif /* MS bit CRC OK/Not OK, 7 LS Bits, Correlation value */ if(crc_corr & CRC_BIT_MASK) { packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK); RIMESTATS_ADD(llrx); } else { RIMESTATS_ADD(badcrc); CC2530_CSP_ISFLUSHRX(); RF_RX_LED_OFF(); return 0; } /* If FIFOP==1 and FIFO==0 then we had a FIFO overflow at some point. */ if((FSMSTAT1 & (FSMSTAT1_FIFO | FSMSTAT1_FIFOP)) == FSMSTAT1_FIFOP) { /* * If we reach here means that there might be more intact packets in the * FIFO despite the overflow. This can happen with bursts of small packets. * * Only flush if the FIFO is actually empty. If not, then next pass we will * pick up one more packet or flush due to an error. */ if(!RXFIFOCNT) { CC2530_CSP_ISFLUSHRX(); } } RF_RX_LED_OFF(); return (len); }
/*---------------------------------------------------------------------------*/ static int send_one_packet(mac_callback_t sent, void *ptr) { int ret; int last_sent_ok = 0; packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); if(NETSTACK_FRAMER.create_and_secure() < 0){ /* Failed to allocate space for headers */ PRINTF("nullrdc: send failed, too large header\n"); ret = MAC_TX_ERR_FATAL; }else{ int is_broadcast; uint8_t dsn; dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff; NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen()); is_broadcast = packetbuf_holds_broadcast(); if(NETSTACK_RADIO.receiving_packet() || (!is_broadcast && NETSTACK_RADIO.pending_packet())){ /* Currently receiving a packet over air or the radio has already received a packet that needs to be read before sending with auto ack. */ ret = MAC_TX_COLLISION; }else{ if(!is_broadcast){ RIMESTATS_ADD(reliabletx); } switch(NETSTACK_RADIO.transmit(packetbuf_totlen())){ case RADIO_TX_OK: if(is_broadcast) { ret = MAC_TX_OK; }else{ rtimer_clock_t wt; /* Check for ack */ wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)); ret = MAC_TX_NOACK; if(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet() || NETSTACK_RADIO.channel_clear() == 0){ int len; uint8_t ackbuf[ACK_LEN]; if(AFTER_ACK_DETECTED_WAIT_TIME > 0){ wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTED_WAIT_TIME)); } if(NETSTACK_RADIO.pending_packet()){ len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); if(len == ACK_LEN && ackbuf[2] == dsn){ /* Ack received */ RIMESTATS_ADD(ackrx); ret = MAC_TX_OK; }else{ /* Not an ack or ack not for us: collision */ ret = MAC_TX_COLLISION; } } }else{ PRINTF("nullrdc tx noack\n"); } } break; case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; default: ret = MAC_TX_ERR; break; } } } if(ret == MAC_TX_OK) { last_sent_ok = 1; } mac_call_sent_callback(sent, ptr, ret, 1); return last_sent_ok; }
/*---------------------------------------------------------------------------*/ static void rx_nok_isr(void) { RIMESTATS_ADD(badcrc); PRINTF("RF: Bad CRC\n"); }
/*---------------------------------------------------------------------------*/ static int transmit(unsigned short transmit_len) { uint8_t counter; int ret = RADIO_TX_ERR; rtimer_clock_t t0; uint8_t was_off = 0; PRINTF("RF: Transmit\n"); if(!(rf_flags & RX_ACTIVE)) { t0 = RTIMER_NOW(); on(); was_off = 1; while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ONOFF_TIME)); } if(channel_clear() == CC2538_RF_CCA_BUSY) { RIMESTATS_ADD(contentiondrop); return RADIO_TX_COLLISION; } /* * prepare() double checked that TX_ACTIVE is low. If SFD is high we are * receiving. Abort transmission and bail out with RADIO_TX_COLLISION */ if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_SFD) { RIMESTATS_ADD(contentiondrop); return RADIO_TX_COLLISION; } /* Start the transmission */ ENERGEST_OFF(ENERGEST_TYPE_LISTEN); ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); CC2538_RF_CSP_ISTXON(); counter = 0; while(!((REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE)) && (counter++ < 3)) { clock_delay_usec(6); } if(!(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE)) { PRINTF("RF: TX never active.\n"); CC2538_RF_CSP_ISFLUSHTX(); ret = RADIO_TX_ERR; } else { /* Wait for the transmission to finish */ while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE); ret = RADIO_TX_OK; } ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); ENERGEST_ON(ENERGEST_TYPE_LISTEN); if(was_off) { off(); } RIMESTATS_ADD(lltx); return ret; }