/*---------------------------------------------------------------------------*/ int cc2420_init(void) { uint16_t reg; { int s = splhigh(); cc2420_arch_init(); /* Initalize ports and SPI. */ CC2420_DISABLE_FIFOP_INT(); CC2420_FIFOP_INT_INIT(); splx(s); } /* Turn on voltage regulator and reset. */ SET_VREG_ACTIVE(); BUSYWAIT_UNTIL(0, RTIMER_SECOND / 100); SET_RESET_ACTIVE(); BUSYWAIT_UNTIL(0, RTIMER_SECOND / 100); SET_RESET_INACTIVE(); BUSYWAIT_UNTIL(0, RTIMER_SECOND / 100); pan = 0xffff; addr = 0x0000; BUSYWAIT_UNTIL(0, RTIMER_SECOND / 100); powerup(); configure(); flushrx(); process_start(&cc2420_process, NULL); return 1; }
/*---------------------------------------------------------------------------*/ static int spirit_radio_off(void) { PRINTF("Spirit1: ->off\n"); if(spirit_on == ON) { /* Disables the mcu to get IRQ from the SPIRIT1 */ IRQ_DISABLE(); /* first stop rx/tx */ spirit1_strobe(SPIRIT1_STROBE_SABORT); /* Clear any pending irqs */ SpiritIrqClearStatus(); BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_READY, 5 * RTIMER_SECOND/1000); if(SPIRIT1_STATUS() != SPIRIT1_STATE_READY) { PRINTF("Spirit1: failed off->ready\n"); return 1; } /* Puts the SPIRIT1 in STANDBY */ spirit1_strobe(SPIRIT1_STROBE_STANDBY); BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_STANDBY, 5 * RTIMER_SECOND/1000); if(SPIRIT1_STATUS() != SPIRIT1_STATE_STANDBY) { PRINTF("Spirit1: failed off->stdby\n"); return 1; } spirit_on = OFF; CLEAR_TXBUF(); CLEAR_RXBUF(); } PRINTF("Spirit1: off.\n"); return 0; }
/*---------------------------------------------------------------------------*/ int cc2520_set_channel(int c) { uint16_t f; GET_LOCK(); /* * Subtract the base channel (11), multiply by 5, which is the * channel spacing. 357 is 2405-2048 and 0x4000 is LOCK_THR = 1. */ channel = c; f = MIN_CHANNEL + ((channel - MIN_CHANNEL) * CHANNEL_SPACING); /* * Writing RAM requires crystal oscillator to be stable. */ BUSYWAIT_UNTIL((status() & (BV(CC2520_XOSC16M_STABLE))), RTIMER_SECOND / 10); /* Wait for any transmission to end. */ BUSYWAIT_UNTIL(!(status() & BV(CC2520_TX_ACTIVE)), RTIMER_SECOND / 10); /* Define radio channel (between 11 and 25) */ setreg(CC2520_FREQCTRL, f); /* If we are in receive mode, we issue an SRXON command to ensure that the VCO is calibrated. */ if(receive_on) { strobe(CC2520_INS_SRXON); } RELEASE_LOCK(); return 1; }
/*---------------------------------------------------------------------------*/ int cc2420_set_channel(int c) { uint16_t f; GET_LOCK(); /* * Subtract the base channel (11), multiply by 5, which is the * channel spacing. 357 is 2405-2048 and 0x4000 is LOCK_THR = 1. */ channel = c; f = 5 * (c - 11) + 357 + 0x4000; /* * Writing RAM requires crystal oscillator to be stable. */ BUSYWAIT_UNTIL((status() & (BV(CC2420_XOSC16M_STABLE))), RTIMER_SECOND / 10); /* Wait for any transmission to end. */ BUSYWAIT_UNTIL(!(status() & BV(CC2420_TX_ACTIVE)), RTIMER_SECOND / 10); setreg(CC2420_FSCTRL, f); /* If we are in receive mode, we issue an SRXON command to ensure that the VCO is calibrated. */ if(receive_on) { strobe(CC2420_SRXON); } RELEASE_LOCK(); return 1; }
/*---------------------------------------------------------------------------*/ static int spirit_radio_on(void) { PRINTF("Spirit1: on\n"); if(spirit_on == OFF) { IRQ_DISABLE(); /* ensure we are in READY state as we go from there to Rx */ spirit1_strobe(SPIRIT1_STROBE_READY); BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_READY, 5 * RTIMER_SECOND/1000); if(SPIRIT1_STATUS() != SPIRIT1_STATE_READY) { PRINTF("Spirit1: failed to turn on\n"); panic_ra(4); return 1; } /* now we go to Rx */ spirit1_strobe(SPIRIT1_STROBE_RX); BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 5 * RTIMER_SECOND/1000); if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX) { PRINTF("Spirit1: failed to enter rx\n"); panic_ra(5); return 1; } /* Enables the mcu to get IRQ from the SPIRIT1 */ IRQ_ENABLE(); spirit_on = ON; } return 0; }
/*---------------------------------------------------------------------------*/ 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; }
/*---------------------------------------------------------------------------*/ void cc2520_set_pan_addr(unsigned pan, unsigned addr, const uint8_t *ieee_addr) { uint8_t tmp[2]; GET_LOCK(); /* * Writing RAM requires crystal oscillator to be stable. */ BUSYWAIT_UNTIL(status() & (BV(CC2520_XOSC16M_STABLE)), RTIMER_SECOND / 10); tmp[0] = pan & 0xff; tmp[1] = pan >> 8; CC2520_WRITE_RAM(&tmp, CC2520RAM_PANID, 2); tmp[0] = addr & 0xff; tmp[1] = addr >> 8; CC2520_WRITE_RAM(&tmp, CC2520RAM_SHORTADDR, 2); if(ieee_addr != NULL) { int f; uint8_t tmp_addr[8]; // LSB first, MSB last for 802.15.4 addresses in CC2520 for (f = 0; f < 8; f++) { tmp_addr[7 - f] = ieee_addr[f]; } CC2520_WRITE_RAM(tmp_addr, CC2520RAM_IEEEADDR, 8); } RELEASE_LOCK(); }
/*---------------------------------------------------------------------------*/ void cc1200_arch_init(void) { SPI_InitHighFreq(1); CC1200_CLK_ALT_MODE; CC1200_MISO_ALT_MODE; CC1200_MOSI_ALT_MODE; /* First leave RESET high */ CC1200_RESET_OUTPUT; CC1200_RESET_SET; /* Initialize CSn, enable CSn and then wait for MISO to go low*/ SPI_WAITFORTx_BEFORE(); /* Configure GPIOx */ CC1200_GDO2_INPUT_FLOAT; CC1200_GDO0_INPUT_FLOAT; /* Leave CSn as default */ cc1200_arch_spi_deselect(); /* Ensure MISO is high */ BUSYWAIT_UNTIL( CC1200_MISO_GET(), RTIMER_SECOND / 10); }
/*---------------------------------------------------------------------------*/ int cc2520_rssi(void) { int rssi; int radio_was_off = 0; if(locked) { return 0; } GET_LOCK(); if(!receive_on) { radio_was_off = 1; cc2520_on(); } BUSYWAIT_UNTIL(status() & BV(CC2520_RSSI_VALID), RTIMER_SECOND / 100); rssi = (int)((signed char)getreg(CC2520_RSSI)); if(radio_was_off) { cc2520_off(); } RELEASE_LOCK(); return rssi; }
/*---------------------------------------------------------------------------*/ void cc1200_arch_init(void) { /* First leave RESET high */ GPIO_SOFTWARE_CONTROL(CC1200_RESET_PORT_BASE, CC1200_RESET_PIN_MASK); GPIO_SET_OUTPUT(CC1200_RESET_PORT_BASE, CC1200_RESET_PIN_MASK); ioc_set_over(CC1200_RESET_PORT, CC1200_RESET_PIN, IOC_OVERRIDE_OE); GPIO_SET_PIN(CC1200_RESET_PORT_BASE, CC1200_RESET_PIN_MASK); /* Initialize CSn, enable CSn and then wait for MISO to go low*/ spix_cs_init(CC1200_SPI_CSN_PORT, CC1200_SPI_CSN_PIN); /* Initialize SPI */ spix_init(CC1200_SPI_INSTANCE); /* Configure GPIOx */ GPIO_SOFTWARE_CONTROL(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK); GPIO_SET_INPUT(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK); GPIO_SOFTWARE_CONTROL(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK); GPIO_SET_INPUT(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK); /* Leave CSn as default */ cc1200_arch_spi_deselect(); /* Ensure MISO is high */ BUSYWAIT_UNTIL( GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK), RTIMER_SECOND / 10); }
/*---------------------------------------------------------------------------*/ void cc1200_arch_spi_select(void) { /* Set CSn to low (0) */ GPIO_CLR_PIN(CC1200_SPI_CSN_PORT_BASE, CC1200_SPI_CSN_PIN_MASK); /* The MISO pin should go low before chip is fully enabled. */ BUSYWAIT_UNTIL( GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK) == 0, RTIMER_SECOND / 100); }
/*---------------------------------------------------------------------------*/ void cc1200_arch_spi_select(void) { /* Set CSn to low (0) */ CC1200_CSN_CLR; /* The MISO pin should go low before chip is fully enabled. */ BUSYWAIT_UNTIL( CC1200_MISO_GET() == 0, RTIMER_SECOND / 100); }
static void on(void) { CC2520_ENABLE_FIFOP_INT(); strobe(CC2520_INS_SRXON); BUSYWAIT_UNTIL(status() & (BV(CC2520_XOSC16M_STABLE)), RTIMER_SECOND / 100); ENERGEST_ON(ENERGEST_TYPE_LISTEN); receive_on = 1; }
/*---------------------------------------------------------------------------*/ static int spirit_radio_channel_clear(void) { float rssi_value; /* Local variable used to memorize the SPIRIT1 state */ uint8_t spirit_state = ON; PRINTF("CHANNEL CLEAR IN\n"); if(spirit_on == OFF) { /* Wakes up the SPIRIT1 */ spirit_radio_on(); spirit_state = OFF; } /* */ IRQ_DISABLE(); spirit1_strobe(SPIRIT1_STROBE_SABORT); /* SpiritCmdStrobeSabort();*/ SpiritIrqClearStatus(); IRQ_ENABLE(); { rtimer_clock_t timeout = RTIMER_NOW() + 5 * RTIMER_SECOND/1000; do { SpiritRefreshStatus(); } while((g_xStatus.MC_STATE != MC_STATE_READY) && (RTIMER_NOW() < timeout)); if(RTIMER_NOW() < timeout) { return 1; } } /* Stores the RSSI value */ rssi_value = SpiritQiGetRssidBm(); /* Puts the SPIRIT1 in its previous state */ if(spirit_state==OFF) { spirit_radio_off(); } else { spirit1_strobe(SPIRIT1_STROBE_RX); /* SpiritCmdStrobeRx();*/ BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 5 * RTIMER_SECOND/1000); } PRINTF("CHANNEL CLEAR OUT\n"); /* Checks the RSSI value with the threshold */ if(rssi_value<CCA_THRESHOLD) { return 0; } else { return 1; } }
bool amb8420SetDstAddress(uint8_t dstAddress) { bool ok; Handle_t handle; RPRINTF("set dst addr to %#02x\n", dstAddress); // disable radio rx/tx AMB8420ModeContext_t ctx; AMB8420_ENTER_STANDBY_MODE(ctx); // better be safe than sorry - treat 0 as broadcast too if (dstAddress == 0) dstAddress = 0xff; // Wait for device to become ready AMB8420_WAIT_FOR_RTS_READY(ok); if (!ok) goto end; // PRINTF("set dst, tar=%u\n", TAR); // ATOMIC_START_TIMESAVE(handle); AMB8420_SERIAL_CAPTURE(ok); commandInProgress = AMB8420_CMD_SET_DESTADDR_REQ; serialSendByte(AMB8420_UART_ID, AMB8420_START_DELIMITER); serialSendByte(AMB8420_UART_ID, AMB8420_CMD_SET_DESTADDR_REQ); serialSendByte(AMB8420_UART_ID, 0x1); serialSendByte(AMB8420_UART_ID, dstAddress); serialSendByte(AMB8420_UART_ID, AMB8420_START_DELIMITER ^ AMB8420_CMD_SET_DESTADDR_REQ ^ 0x1 ^ dstAddress); AMB8420_SERIAL_FREE(); // ATOMIC_END_TIMESAVE(handle); // PRINTF("end set dst, tar=%u\n", TAR); // wait for reply INTERRUPT_ENABLED_START(handle); BUSYWAIT_UNTIL(!commandInProgress, TIMER_100_MS, ok); // if (commandInProgress) PRINTF("set dst addr: command wait fail\n"); INTERRUPT_ENABLED_END(handle); // if (!ok) goto end; // Wait for device to become ready AMB8420_WAIT_FOR_RTS_READY(ok); end: AMB8420_RESTORE_MODE(ctx); // PRINTF(" ok = %d\n", (int)ok); // if (!ok) amb8420Reset(); return ok; }
/*---------------------------------------------------------------------------*/ static void flushrx(void) { restart_input(); LOCK_SPI(); if(state() == CC1101_STATE_RXFIFO_OVERFLOW) { strobe(CC1101_SFRX); } strobe(CC1101_SIDLE); BUSYWAIT_UNTIL((state() == CC1101_STATE_IDLE), RTIMER_SECOND / 10); strobe(CC1101_SFRX); strobe(CC1101_SRX); RELEASE_SPI(); }
/*---------------------------------------------------------------------------*/ static int spirit_radio_transmit(unsigned short payload_len) { /* This function blocks until the packet has been transmitted */ rtimer_clock_t rtimer_txdone, rtimer_rxack; PRINTF("TRANSMIT IN\n"); if(!packet_is_prepared) { return RADIO_TX_ERR; } /* Stores the length of the packet to send */ /* Others spirit_radio_prepare will be in hold */ spirit_txbuf[0] = payload_len; /* Puts the SPIRIT1 in TX state */ receiving_packet = 0; SpiritSetReadyState(); spirit1_strobe(SPIRIT1_STROBE_TX); just_got_an_ack = 0; BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_TX, 5 * RTIMER_SECOND/1000); BUSYWAIT_UNTIL(SPIRIT1_STATUS() != SPIRIT1_STATE_TX, 50 * RTIMER_SECOND/1000); /* Reset radio - needed for immediate RX of ack */ CLEAR_TXBUF(); CLEAR_RXBUF(); SpiritIrqClearStatus(); spirit1_strobe(SPIRIT1_STROBE_SABORT); BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_READY, 1 * RTIMER_SECOND/1000); spirit1_strobe(SPIRIT1_STROBE_READY); BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_READY, 1 * RTIMER_SECOND/1000); spirit1_strobe(SPIRIT1_STROBE_RX); BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 1 * RTIMER_SECOND/1000); #if NULLRDC_CONF_802154_AUTOACK if (wants_an_ack) { rtimer_txdone = RTIMER_NOW(); BUSYWAIT_UNTIL(just_got_an_ack, 15 * RTIMER_SECOND/1000); rtimer_rxack = RTIMER_NOW(); if(just_got_an_ack) { ACKPRINTF("debug_ack: ack received after %u/%u ticks\n", (uint32_t)(rtimer_rxack - rtimer_txdone), 15 * RTIMER_SECOND/1000); } else { ACKPRINTF("debug_ack: no ack received\n"); } } #endif /* NULLRDC_CONF_802154_AUTOACK */ PRINTF("TRANSMIT OUT\n"); CLEAR_TXBUF(); packet_is_prepared = 0; return RADIO_TX_OK; }
static void on(void) { if(completely_off) { completely_off = 0; powerup(); configure(); } CC2420_ENABLE_FIFOP_INT(); strobe(CC2420_SRXON); BUSYWAIT_UNTIL(status() & (BV(CC2420_XOSC16M_STABLE)), RTIMER_SECOND / 100); ENERGEST_ON(ENERGEST_TYPE_LISTEN); receive_on = 1; }
static void off(void) { /* PRINTF("off\n");*/ receive_on = 0; /* Wait for transmission to end before turning radio off. */ BUSYWAIT_UNTIL(!(status() & BV(CC2520_TX_ACTIVE)), RTIMER_SECOND / 10); ENERGEST_OFF(ENERGEST_TYPE_LISTEN); strobe(CC2520_INS_SRFOFF); CC2520_DISABLE_FIFOP_INT(); if(!CC2520_FIFOP_IS_1) { flushrx(); } }
static void configure(void) { uint16_t reg; BUSYWAIT_UNTIL(status() & (BV(CC2420_XOSC16M_STABLE)), RTIMER_SECOND / 100); /* Turn on/off automatic packet acknowledgment and address decoding. */ reg = getreg(CC2420_MDMCTRL0); #if CC2420_CONF_AUTOACK reg |= AUTOACK | ADR_DECODE; #else reg &= ~(AUTOACK | ADR_DECODE); #endif /* CC2420_CONF_AUTOACK */ setreg(CC2420_MDMCTRL0, reg); /* Set transmission turnaround time to the lower setting (8 symbols = 0.128 ms) instead of the default (12 symbols = 0.192 ms). */ /* reg = getreg(CC2420_TXCTRL); reg &= ~(1 << 13); setreg(CC2420_TXCTRL, reg);*/ /* Change default values as recomended in the data sheet, */ /* correlation threshold = 20, RX bandpass filter = 1.3uA. */ setreg(CC2420_MDMCTRL1, CORR_THR(20)); reg = getreg(CC2420_RXCTRL1); reg |= RXBPF_LOCUR; setreg(CC2420_RXCTRL1, reg); /* Set the FIFOP threshold to maximum. */ setreg(CC2420_IOCFG0, FIFOP_THR(127)); /* Turn off "Security enable" (page 32). */ reg = getreg(CC2420_SECCTRL0); reg &= ~RXFIFO_PROTECTION; setreg(CC2420_SECCTRL0, reg); cc2420_set_pan_addr(pan, addr, NULL); cc2420_set_channel(channel); flushrx(); }
/*---------------------------------------------------------------------------*/ static int spirit_radio_prepare(const void *payload, unsigned short payload_len) { PRINTF("Spirit1: prep %u\n", payload_len); packet_is_prepared = 0; /* Checks if the payload length is supported */ if(payload_len > MAX_PACKET_LEN) { return RADIO_TX_ERR; } /* Waits the end of a still running spirit_radio_transmit */ BUSYWAIT_UNTIL(IS_TXBUF_EMPTY(), TX_WAIT_PCKT_PERIOD * RTIMER_SECOND/1000); if(!IS_TXBUF_EMPTY()) { PRINTF("PREPARE OUT ERR\n"); return RADIO_TX_ERR; } /* Should we delay for an ack? */ #if NULLRDC_CONF_802154_AUTOACK frame802154_t info154; wants_an_ack = 0; if(payload_len > ACK_LEN && frame802154_parse((char*)payload, payload_len, &info154) != 0) { if(info154.fcf.frame_type == FRAME802154_DATAFRAME && info154.fcf.ack_required != 0) { wants_an_ack = 1; } } #endif /* NULLRDC_CONF_802154_AUTOACK */ /* Sets the length of the packet to send */ spirit1_strobe(SPIRIT1_STROBE_FTX); SpiritPktBasicSetPayloadLength(payload_len); SpiritSpiWriteLinearFifo(payload_len, (uint8_t *)payload); PRINTF("PREPARE OUT\n"); packet_is_prepared = 1; return RADIO_TX_OK; }
/*---------------------------------------------------------------------------*/ void ST_RadioReceiveIsrCallback(uint8_t *packet, boolean ackFramePendingSet, uint32_t time, uint16_t errors, int8_t rssi) { LED_RX_ON(); PRINTF("stm32w: incomming packet received\n"); receiving_packet = 0; /* Copy packet into the buffer. It is better to do this here. */ if(add_to_rxbuf(packet)) { process_poll(&stm32w_radio_process); last_rssi = rssi; } LED_RX_OFF(); GET_LOCK(); is_transmit_ack = 1; /* Wait for sending ACK */ BUSYWAIT_UNTIL(!is_transmit_ack, RTIMER_SECOND / 1500); RELEASE_LOCK(); }
/** * \brief perform a clear channel assessment * \retval >0 Channel is clear * \retval 0 Channel is not clear */ int rf233_channel_clear(void) { uint8_t regsave; int was_off = 0; if(rf233_status() != STATE_RX_ON) { /* CCA can only be performed in RX state */ was_off = 1; RF233_COMMAND(TRXCMD_RX_ON); } delay_us(200); /* request a CCA, storing the channel number (set with the same reg) */ regsave = trx_reg_read(RF233_REG_PHY_CC_CCA); regsave |= PHY_CC_CCA_DO_CCA | PHY_CC_CCA_MODE_CS_OR_ED; trx_reg_write(RF233_REG_PHY_CC_CCA, regsave); BUSYWAIT_UNTIL(trx_reg_read(RF233_REG_TRX_STATUS) & TRX_CCA_DONE, RTIMER_SECOND / 1000); //regsave = rf233_status(); regsave = trx_reg_read(RF233_REG_TRX_STATUS); /* return to previous state */ if(was_off) { RF233_COMMAND(TRXCMD_TRX_OFF); } #if NULLRDC_CONF_802154_AUTOACK_HW else{ RF233_COMMAND(TRXCMD_RX_AACK_ON); } #endif /* check CCA */ if((regsave & TRX_CCA_DONE) && (regsave & TRX_CCA_STATUS)) { PRINTF("RF233: CCA 1\r\n"); return 1; } PRINTF("RF233: CCA 0\r\n"); return 0; }
/*---------------------------------------------------------------------------*/ static int cc2520_cca(void) { int cca; int radio_was_off = 0; /* If the radio is locked by an underlying thread (because we are being invoked through an interrupt), we preted that the coast is clear (i.e., no packet is currently being transmitted by a neighbor). */ if(locked) { return 1; } GET_LOCK(); if(!receive_on) { radio_was_off = 1; cc2520_on(); } /* Make sure that the radio really got turned on. */ if(!receive_on) { RELEASE_LOCK(); if(radio_was_off) { cc2520_off(); } return 1; } BUSYWAIT_UNTIL(status() & BV(CC2520_RSSI_VALID), RTIMER_SECOND / 100); cca = CC2520_CCA_IS_1; if(radio_was_off) { cc2520_off(); } RELEASE_LOCK(); return cca; }
/** * \brief prepare a frame and the radio for immediate transmission * \param payload Pointer to data to copy/send * \param payload_len length of data to copy * \return Returns success/fail, refer to radio.h for explanation */ int rf233_prepare(const void *payload, unsigned short payload_len) { #if DEBUG_PRINTDATA int i; #endif /* DEBUG_PRINTDATA */ uint8_t templen; uint8_t radio_status; uint8_t data[130]; #if USE_HW_FCS_CHECK /* Add length of the FCS (2 bytes) */ templen = payload_len + 2; #else /* USE_HW_FCS_CHECK */ /* FCS is assumed to already be included in the payload */ templen = payload_len; #endif /* USE_HW_FCS_CHECK */ //data = templen; /* for(i = 0; i < templen; i++) { data++; data =(uint8_t *)(payload + i); }*/ //memcpy(data,&templen,1); data[0] = templen; memcpy(&data[1],payload,templen); //data--; #if DEBUG_PRINTDATA PRINTF("RF233 prepare (%u/%u): 0x", payload_len, templen); for(i = 0; i < templen; i++) { PRINTF("%02x", *(uint8_t *)(payload + i)); } PRINTF("\r\n"); #endif /* DEBUG_PRINTDATA */ PRINTF("RF233: prepare %u\r\n", payload_len); if(payload_len > MAX_PACKET_LEN) { PRINTF("RF233: error, frame too large to tx\r\n"); return RADIO_TX_ERR; } /* check that the FIFO is clear to access */ radio_status=rf233_status(); #if NULLRDC_CONF_802154_AUTOACK_HW if(radio_status == STATE_BUSY_RX_AACK || radio_status == STATE_BUSY_TX_ARET) { PRINTF("RF233: TRX buffer unavailable: prep when %s\r\n", radio_status == STATE_BUSY_RX_AACK ? "rx" : "tx"); #else if(radio_status == STATE_BUSY_RX || radio_status == STATE_BUSY_TX) { PRINTF("RF233: TRX buffer unavailable: prep when %s\r\n", radio_status == STATE_BUSY_RX? "rx" : "tx"); #endif return RADIO_TX_ERR; } /* Write packet to TX FIFO. */ PRINTF("RF233 len = %u\r\n", payload_len); trx_frame_write((uint8_t *)data, templen+1); return RADIO_TX_OK; } /*---------------------------------------------------------------------------*/ /** * \brief Transmit a frame already put in the radio with 'prepare' * \param payload_len Length of the frame to send * \return Returns success/fail, refer to radio.h for explanation */ int rf233_transmit(unsigned short payload_len) { static uint8_t status_now; PRINTF("RF233: tx %u\r\n", payload_len); /* prepare for TX */ status_now = rf233_status(); //status_now = trx_reg_read(RF233_REG_TRX_RPC); #if NULLRDC_CONF_802154_AUTOACK_HW if(status_now == STATE_BUSY_RX_AACK || status_now == STATE_BUSY_TX_ARET) { #else if(status_now == STATE_BUSY_RX || status_now == STATE_BUSY_TX) { #endif PRINTF("RF233: collision, was receiving 0x%02X\r\n",status_now); /* NOTE: to avoid loops */ return RADIO_TX_ERR;; // return RADIO_TX_COLLISION; } if(status_now != STATE_PLL_ON) { /* prepare for going to state TX, should take max 80 us */ //RF233_COMMAND(TRXCMD_PLL_ON); trx_reg_write(RF233_REG_TRX_STATE,0x09); // BUSYWAIT_UNTIL(trx_reg_read(RF233_REG_TRX_STATUS) == STATE_PLL_ON, 1 * RTIMER_SECOND/1000); //delay_ms(10); //status_now = trx_reg_read(RF233_REG_TRX_STATE); do { status_now = trx_bit_read(0x01, 0x1F, 0); } while (status_now == 0x1f); } if(rf233_status() != STATE_PLL_ON) { /* failed moving into PLL_ON state, gracefully try to recover */ PRINTF("RF233: failed going to PLLON\r\n"); RF233_COMMAND(TRXCMD_PLL_ON); /* try again */ static uint8_t state; state = rf233_status(); if(state != STATE_PLL_ON) { /* give up and signal big fail (should perhaps reset radio core instead?) */ PRINTF("RF233: graceful recovery (in tx) failed, giving up. State: 0x%02X\r\n", rf233_status()); return RADIO_TX_ERR; } } /* perform transmission */ ENERGEST_OFF(ENERGEST_TYPE_LISTEN); ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); #if NULLRDC_CONF_802154_AUTOACK_HW RF233_COMMAND(TRXCMD_TX_ARET_ON); #endif RF233_COMMAND(TRXCMD_TX_START); flag_transmit=1; //delay_ms(5); //printf("RTIMER value %d",RTIMER_NOW()); #if !NULLRDC_CONF_802154_AUTOACK_HW BUSYWAIT_UNTIL(rf233_status() == STATE_BUSY_TX, RTIMER_SECOND/2000); // printf("RTIMER value1 %d",RTIMER_NOW()); // printf("\r\nSTATE_BUSY_TX"); BUSYWAIT_UNTIL(rf233_status() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); // printf("RTIMER value2 %d",RTIMER_NOW()); #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); ENERGEST_ON(ENERGEST_TYPE_LISTEN); #if !NULLRDC_CONF_802154_AUTOACK_HW if(rf233_status() != STATE_PLL_ON) { // something has failed PRINTF("RF233: radio fatal err after tx\r\n"); radiocore_hard_recovery(); return RADIO_TX_ERR; } RF233_COMMAND(TRXCMD_RX_ON); #else BUSYWAIT_UNTIL(ack_status == 1, 10 * RTIMER_SECOND/1000); if((ack_status)) { // printf("\r\nrf233 sent\r\n "); ack_status=0; // printf("\nACK received"); return RADIO_TX_OK; } else { // printf("\nNOACK received"); return RADIO_TX_NOACK; } #endif PRINTF("RF233: tx ok\r\n"); return RADIO_TX_OK; } /*---------------------------------------------------------------------------*/ /** * \brief Send data: first prepares, then transmits * \param payload Pointer to data to copy/send * \param payload_len length of data to copy * \return Returns success/fail, refer to radio.h for explanation */ int rf233_send(const void *payload, unsigned short payload_len) { PRINTF("RF233: send %u\r\n", payload_len); if(rf233_prepare(payload, payload_len) == RADIO_TX_ERR) { return RADIO_TX_ERR; } return rf233_transmit(payload_len); } /*---------------------------------------------------------------------------*/ /** * \brief read a received frame out of the radio buffer * \param buf pointer to where to copy received data * \param bufsize Maximum size we can copy into bufsize * \return Returns length of data read (> 0) if successful * \retval -1 Failed, was transmitting so FIFO is invalid * \retval -2 Failed, rx timed out (stuck in rx?) * \retval -3 Failed, too large frame for buffer * \retval -4 Failed, CRC/FCS failed (if USE_HW_FCS_CHECK is true) */ int rf233_read(void *buf, unsigned short bufsize) { // uint8_t radio_state; uint8_t ed; /* frame metadata */ uint8_t frame_len = 0; uint8_t len = 0; int rssi; #if DEBUG_PRINTDATA uint8_t tempreadlen; #endif /* DEBUG_PRINTDATA */ if(pending_frame == 0) { return 0; } pending_frame = 0; /* / * check that data in FIFO is valid * / radio_state = RF233_STATUS(); if(radio_state == STATE_BUSY_TX) { / * data is invalid, bail out * / PRINTF("RF233: read while in BUSY_TX ie invalid, dropping.\n"); return -1; } if(radio_state == STATE_BUSY_RX) { / * still receiving - data is invalid, wait for it to finish * / PRINTF("RF233: read while BUSY_RX, waiting.\n"); BUSYWAIT_UNTIL(RF233_STATUS() != STATE_BUSY_RX, 10 * RTIMER_SECOND/1000); if(RF233_STATUS() == STATE_BUSY_RX) { PRINTF("RF233: timed out, still BUSY_RX, dropping.\n"); return -2; } } */ /* get length of data in FIFO */ trx_frame_read(&frame_len, 1); #if DEBUG_PRINTDATA tempreadlen = frame_len; #endif /* DEBUG_PRINTDATA */ if(frame_len == 1) { frame_len = 0; } len = frame_len; #if USE_HW_FCS_CHECK /* FCS has already been stripped */ len = frame_len - 2; #endif /* USE_HW_FCS_CHECK */ if(frame_len == 0) { return 0; } if(len > bufsize) { /* too large frame for the buffer, drop */ PRINTF("RF233: too large frame for buffer, dropping (%u > %u).\r\n", frame_len, bufsize); flush_buffer(); return -3; } PRINTF("RF233 read %u B\r\n", frame_len); /* read out the data into the buffer, disregarding the length and metadata bytes */ trx_sram_read(1,(uint8_t *)buf, len); #if DEBUG_PRINTDATA { int k; PRINTF("RF233: Read frame (%u/%u): ", tempreadlen, frame_len); for(k = 0; k < frame_len; k++) { PRINTF("%02x", *((uint8_t *)buf + k)); } PRINTF("\r\n"); } #endif /* DEBUG_PRINTDATA */ /* * Energy level during reception, ranges from 0x00 to 0x53 (=83d) with a * resolution of 1dB and accuracy of +/- 5dB. 0xFF means invalid measurement. * 0x00 means <= RSSI(base_val), which is -91dBm (typ). See datasheet 12.7. * Ergo, real RSSI is (ed-91) dBm or less. */ #define RSSI_OFFSET (91) ed = trx_reg_read(RF233_REG_PHY_ED_LEVEL); rssi = (int) ed - RSSI_OFFSET; packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi); flush_buffer(); /* #if USE_HW_FCS_CHECK { uint8_t crc_ok; / * frame metadata * / crc_ok = rf233_arch_read_reg(RF233_REG_PHY_RSSI) & PHY_RSSI_CRC_VALID; if(crc_ok == 0) { / * CRC/FCS fail, drop * / PRINTF("RF233: CRC/FCS fail, dropping.\n"); flush_buffer(); return -4; } } #endif / * USE_HW_FCS_CHECK * /*/ return len; }
/*---------------------------------------------------------------------------*/ static int spirit_radio_init(void) { PRINTF("RADIO INIT IN\n"); SpiritSpiInit(); /* Configure radio shut-down (SDN) pin and activate radio */ SdkEvalM2SGpioInit(M2S_GPIO_SDN, M2S_MODE_GPIO_OUT); /* Configures the SPIRIT1 library */ SpiritRadioSetXtalFrequency(XTAL_FREQUENCY); SpiritManagementSetVersion(SPIRIT1_VERSION); SpiritGeneralSetSpiritVersion(SPIRIT1_VERSION); SpiritManagementSetXtalFrequency(XTAL_FREQUENCY); /* wake up to READY state */ /* weirdly enough, this *should* actually *set* the pin, not clear it! The pins is declared as GPIO_pin13 == 0x2000 */ M2S_GPIO_SDN_PORT->BSRRL = M2S_GPIO_SDN_PIN; /* GPIOC->BSRRL = M2S_GPIO_SDN_PIN;*/ GPIO_ResetBits(M2S_GPIO_SDN_PORT, M2S_GPIO_SDN_PIN); /* wait minimum 1.5 ms to allow SPIRIT1 a proper boot-up sequence */ BUSYWAIT_UNTIL(0, 3 * RTIMER_SECOND/2000); /* Soft reset of core */ spirit1_strobe(SPIRIT1_STROBE_SRES); /* SpiritCmdStrobeSres();*/ /* Configures the SPIRIT1 radio part */ SRadioInit xRadioInit = { XTAL_FREQUENCY, XTAL_OFFSET_PPM, BASE_FREQUENCY, CHANNEL_SPACE, CHANNEL_NUMBER, MODULATION_SELECT, DATARATE, FREQ_DEVIATION, BANDWIDTH }; SpiritRadioInit(&xRadioInit); SpiritRadioSetPALeveldBm(0,POWER_DBM); SpiritRadioSetPALevelMaxIndex(0); /* Configures the SPIRIT1 packet handler part*/ PktBasicInit xBasicInit = { PREAMBLE_LENGTH, SYNC_LENGTH, SYNC_WORD, LENGTH_TYPE, LENGTH_WIDTH, CRC_MODE, CONTROL_LENGTH, EN_ADDRESS, EN_FEC, EN_WHITENING }; SpiritPktBasicInit(&xBasicInit); /* Enable the following interrupt sources, routed to GPIO */ SpiritIrqDeInit(NULL); SpiritIrqClearStatus(); SpiritIrq(TX_DATA_SENT, S_ENABLE); SpiritIrq(RX_DATA_READY,S_ENABLE); SpiritIrq(VALID_SYNC,S_ENABLE); SpiritIrq(RX_DATA_DISC, S_ENABLE); SpiritIrq(TX_FIFO_ERROR, S_ENABLE); SpiritIrq(RX_FIFO_ERROR, S_ENABLE); /* Configure Spirit1 */ SpiritRadioPersistenRx(S_ENABLE); SpiritQiSetSqiThreshold(SQI_TH_0); SpiritQiSqiCheck(S_ENABLE); SpiritQiSetRssiThresholddBm(CCA_THRESHOLD); SpiritTimerSetRxTimeoutStopCondition(SQI_ABOVE_THRESHOLD); SET_INFINITE_RX_TIMEOUT(); SpiritRadioAFCFreezeOnSync(S_ENABLE); /* Puts the SPIRIT1 in STANDBY mode (125us -> rx/tx) */ spirit1_strobe(SPIRIT1_STROBE_STANDBY); /* SpiritCmdStrobeCommand(SPIRIT1_STROBE_STANDBY);*/ /* SpiritCmdStrobeStandby();*/ spirit_on = OFF; CLEAR_RXBUF(); CLEAR_TXBUF(); /* Initializes the mcu pin as input, used for IRQ */ SdkEvalM2SGpioInit(M2S_GPIO_0, M2S_MODE_EXTI_IN); SdkEvalM2SGpioInit(M2S_GPIO_1, M2S_MODE_EXTI_IN); SdkEvalM2SGpioInit(M2S_GPIO_2, M2S_MODE_EXTI_IN); SdkEvalM2SGpioInit(M2S_GPIO_3, M2S_MODE_EXTI_IN); /* Configure the radio to route the IRQ signal to its GPIO 3 */ SpiritGpioInit(&(SGpioInit){SPIRIT_GPIO_3, SPIRIT_GPIO_MODE_DIGITAL_OUTPUT_LP, SPIRIT_GPIO_DIG_OUT_IRQ}); process_start(&spirit_radio_process, NULL); PRINTF("Spirit1 init done\n"); return 0; }
PROCESS_THREAD(spirit_radio_process, ev, data) { PROCESS_BEGIN(); PRINTF("Spirit1: process started\n"); while(1) { int len; PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); PRINTF("Spirit1: polled\n"); packetbuf_clear(); len = spirit_radio_read(packetbuf_dataptr(), PACKETBUF_SIZE); if(len > 0) { #if NULLRDC_CONF_802154_AUTOACK /* Check if the packet has an ACK request */ frame802154_t info154; if(len > ACK_LEN && frame802154_parse((char*)packetbuf_dataptr(), len, &info154) != 0) { if(info154.fcf.frame_type == FRAME802154_DATAFRAME && info154.fcf.ack_required != 0 && rimeaddr_cmp((rimeaddr_t *)&info154.dest_addr, &rimeaddr_node_addr)) { /* Send an ACK packet */ uint8_t ack_frame[ACK_LEN] = { FRAME802154_ACKFRAME, 0x00, info154.seq }; spirit1_strobe(SPIRIT1_STROBE_FTX); SpiritPktBasicSetPayloadLength((uint16_t) ACK_LEN); SpiritSpiWriteLinearFifo((uint16_t) ACK_LEN, (uint8_t *) ack_frame); SpiritSetReadyState(); spirit1_strobe(SPIRIT1_STROBE_TX); BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_TX, 1 * RTIMER_SECOND/1000); BUSYWAIT_UNTIL(SPIRIT1_STATUS() != SPIRIT1_STATE_TX, 1 * RTIMER_SECOND/1000); ACKPRINTF("debug_ack: sent ack %d\n", ack_frame[2]); } } #endif /* NULLRDC_CONF_802154_AUTOACK */ packetbuf_set_datalen(len); NETSTACK_RDC.input(); } if(!IS_RXBUF_EMPTY()){ process_poll(&spirit_radio_process); } if(interrupt_callback_wants_poll) { spirit1_interrupt_callback(); if(SPIRIT1_STATUS() == SPIRIT1_STATE_READY) { spirit1_strobe(SPIRIT1_STROBE_RX); BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 1 * RTIMER_SECOND/1000); } } } PROCESS_END(); }
/** * \brief prepare a frame and the radio for immediate transmission * \param payload Pointer to data to copy/send * \param payload_len length of data to copy * \return Returns success/fail, refer to radio.h for explanation */ static int rf212_prepare(const void *payload, unsigned short payload_len) { #if DEBUG_PRINTDATA int i; #endif /* DEBUG_PRINTDATA */ uint8_t templen; uint8_t radio_status; uint8_t data[130]; #if USE_HW_FCS_CHECK /* Add length of the FCS (2 bytes) */ templen = payload_len + 2; #else /* USE_HW_FCS_CHECK */ /* FCS is assumed to already be included in the payload */ templen = payload_len; #endif /* USE_HW_FCS_CHECK */ data[0] = templen; memcpy(&data[1],payload,templen); #if DEBUG_PRINTDATA PRINTF("RF212 prepare (%u/%u): 0x", payload_len, templen); for(i = 0; i < templen; i++) { PRINTF("%02x", *(uint8_t *)(payload + i)); } PRINTF("\n"); #endif /* DEBUG_PRINTDATA */ PRINTF("RF212: prepare %u\n", payload_len); if(payload_len > MAX_PACKET_LEN) { PRINTF("RF212: error, frame too large to tx\n"); return RADIO_TX_ERR; } /* check that the FIFO is clear to access */ radio_status = rf212_status(); #if NULLRDC_CONF_802154_AUTOACK_HW if(radio_status == STATE_BUSY_RX_AACK || radio_status == STATE_BUSY_TX_ARET) { PRINTF("RF212B: TRX buffer unavailable: prep when %s\n", radio_status == STATE_BUSY_RX_AACK ? "rx" : "tx"); #else if(radio_status == STATE_BUSY_RX || radio_status == STATE_BUSY_TX) { PRINTF("RF212B: TRX buffer unavailable: prep when %s\n", radio_status == STATE_BUSY_RX? "rx" : "tx"); #endif return RADIO_TX_ERR; } /* Write packet to TX FIFO. */ PRINTF("RF212 len = %u\n", payload_len); trx_frame_write((uint8_t *)data, templen+1); return RADIO_TX_OK; } /*---------------------------------------------------------------------------*/ /** * \brief Transmit a frame already put in the radio with 'prepare' * \param payload_len Length of the frame to send * \return Returns success/fail, refer to radio.h for explanation */ static int rf212_transmit(unsigned short payload_len) { uint8_t status_now;//,temp; PRINTF("RF212: tx %u\n", payload_len); /* prepare for TX */ status_now = rf212_status(); #if NULLRDC_CONF_802154_AUTOACK_HW if(status_now == STATE_BUSY_RX_AACK || status_now == STATE_BUSY_TX_ARET) { #else if(status_now == STATE_BUSY_RX || status_now == STATE_BUSY_TX) { #endif PRINTF("RF212: collision, was receiving\n"); /* NOTE: to avoid loops */ return RADIO_TX_ERR; // return RADIO_TX_COLLISION; } if(status_now != STATE_PLL_ON) { /* prepare for going to state TX, should take max 80 us */ //RF212_COMMAND(TRXCMD_PLL_ON); trx_reg_write(RF212_REG_TRX_STATE,0x09); do { status_now = trx_bit_read(0x01, 0x1F, 0); } while (status_now == 0x1f); //BUSYWAIT_UNTIL(RF212_STATUS() == STATE_PLL_ON, 1 * RTIMER_SECOND/1000); } if(rf212_status() != STATE_PLL_ON) { /* failed moving into PLL_ON state, gracefully try to recover */ PRINTF("RF212: failed going to PLLON\n"); RF212_COMMAND(TRXCMD_PLL_ON); /* try again */ if(rf212_status() != STATE_PLL_ON) { /* give up and signal big fail (should perhaps reset radio core instead?) */ PRINTF("RF212: graceful recovery (in tx) failed, giving up. State: 0x%02X\n", RF212_STATUS()); return RADIO_TX_ERR; } } /* perform transmission */ ENERGEST_OFF(ENERGEST_TYPE_LISTEN); ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); #if NULLRDC_CONF_802154_AUTOACK_HW RF212_COMMAND(TRXCMD_TX_ARET_ON); #endif RF212_COMMAND(TRXCMD_TX_START); flag_transmit=1; #if !NULLRDC_CONF_802154_AUTOACK_HW BUSYWAIT_UNTIL(RF212_STATUS() == STATE_BUSY_TX, RTIMER_SECOND/2000); BUSYWAIT_UNTIL(RF212_STATUS() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); #if (DATA_RATE==BPSK_20||BPSK_40||OQPSK_SIN_RC_100) BUSYWAIT_UNTIL(RF212_STATUS() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); BUSYWAIT_UNTIL(RF212_STATUS() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); BUSYWAIT_UNTIL(RF212_STATUS() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); #endif #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); ENERGEST_ON(ENERGEST_TYPE_LISTEN); #if !NULLRDC_CONF_802154_AUTOACK_HW if(RF212_STATUS() != STATE_PLL_ON) { /* something has failed */ printf("RF212: radio fatal err after tx\n"); radiocore_hard_recovery(); return RADIO_TX_ERR; } // printf("#RTIMER_SECOND"); RF212_COMMAND(TRXCMD_RX_ON); #else BUSYWAIT_UNTIL(ack_status == 1, 10 * RTIMER_SECOND/1000); if((ack_status)) { // printf("\r\nrf233 sent\r\n "); ack_status=0; // printf("\nACK received"); return RADIO_TX_OK; } else { // printf("\nNOACK received"); return RADIO_TX_NOACK; } #endif PRINTF("RF212: tx ok\n"); return RADIO_TX_OK; } void goto_sleep(void) { port_pin_set_output_level(AT86RFX_SLP_PIN, true); }
/*---------------------------------------------------------------------------*/ 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 cc2520_init(void) { { int s = splhigh(); cc2520_arch_init(); /* Initalize ports and SPI. */ CC2520_DISABLE_FIFOP_INT(); CC2520_FIFOP_INT_INIT(); splx(s); } SET_VREG_INACTIVE(); clock_delay(250); /* Turn on voltage regulator and reset. */ SET_VREG_ACTIVE(); clock_delay(250); SET_RESET_ACTIVE(); clock_delay(127); SET_RESET_INACTIVE(); clock_delay(125); /* Turn on the crystal oscillator. */ strobe(CC2520_INS_SXOSCON); clock_delay(125); BUSYWAIT_UNTIL(status() & (BV(CC2520_XOSC16M_STABLE)), RTIMER_SECOND / 100); /* Change default values as recommended in the data sheet, */ /* correlation threshold = 20, RX bandpass filter = 1.3uA.*/ setreg(CC2520_TXCTRL, 0x94); setreg(CC2520_TXPOWER, 0x13); // Output power 1 dBm /* valeurs de TXPOWER 0x03 -> -18 dBm 0x2C -> -7 dBm 0x88 -> -4 dBm 0x81 -> -2 dBm 0x32 -> 0 dBm 0x13 -> 1 dBm 0x32 -> 0 dBm 0x13 -> 1 dBm 0xAB -> 2 dBm 0xF2 -> 3 dBm 0xF7 -> 5 dBm */ setreg(CC2520_CCACTRL0, 0xF8); // CCA treshold -80dBm // Recommended RX settings setreg(CC2520_MDMCTRL0, 0x84); // Controls modem setreg(CC2520_MDMCTRL1, 0x14); // Controls modem setreg(CC2520_RXCTRL, 0x3F); // Adjust currents in RX related analog modules setreg(CC2520_FSCTRL, 0x5A); // Adjust currents in synthesizer. setreg(CC2520_FSCAL1, 0x2B); // Adjust currents in VCO setreg(CC2520_AGCCTRL1, 0x11); // Adjust target value for AGC control loop setreg(CC2520_AGCCTRL2, 0xEB); // Disable external clock setreg(CC2520_EXTCLOCK, 0x00); // Tune ADC performance setreg(CC2520_ADCTEST0, 0x10); setreg(CC2520_ADCTEST1, 0x0E); setreg(CC2520_ADCTEST2, 0x03); /* Set auto CRC on frame. */ #if CC2520_CONF_AUTOACK setreg(CC2520_FRMCTRL0, AUTOCRC | AUTOACK); setreg(CC2520_FRMFILT0, FRAME_MAX_VERSION|FRAME_FILTER_ENABLE); #else /* setreg(CC2520_FRMCTRL0, 0x60); */ setreg(CC2520_FRMCTRL0, AUTOCRC); /* Disable filter on @ (remove if you want to address specific wismote) */ setreg(CC2520_FRMFILT0, 0x00); #endif /* CC2520_CONF_AUTOACK */ /* SET_RXENMASK_ON_TX */ setreg(CC2520_FRMCTRL1, 1); /* Set FIFOP threshold to maximum .*/ setreg(CC2520_FIFOPCTRL, FIFOP_THR(0x7F)); cc2520_set_pan_addr(0xffff, 0x0000, NULL); cc2520_set_channel(26); flushrx(); process_start(&cc2520_process, NULL); return 1; }