/*---------------------------------------------------------------------------*/ 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; }
/*---------------------------------------------------------------------------*/ 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 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 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; } }
/** * @brief Puts the SPIRIT1 in READY state. * @param None * @retval None */ void SpiritSetReadyState(void) { PRINTF("READY IN\n"); SpiritIrqClearStatus(); IRQ_DISABLE(); if(SPIRIT1_STATUS() == SPIRIT1_STATE_STANDBY) { spirit1_strobe(SPIRIT1_STROBE_READY); /* SpiritCmdStrobeReady();*/ } else if(SPIRIT1_STATUS() == SPIRIT1_STATE_RX) { spirit1_strobe(SPIRIT1_STROBE_SABORT); /* SpiritCmdStrobeSabort();*/ SpiritIrqClearStatus(); } IRQ_ENABLE(); PRINTF("READY OUT\n"); }
/*---------------------------------------------------------------------------*/ 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 spirit1_reset() { /// Turn-off interrupts, send Reset strobe, and wait for reset to finish. spirit1_int_turnoff(RFI_ALL); spirit1_strobe(STROBE(SRES)); spirit1_waitforreset(); }
/*---------------------------------------------------------------------------*/ void spirit1_interrupt_callback(void) { #define INTPRINTF // PRINTF SpiritIrqs xIrqStatus; if (SpiritSPIBusy() || interrupt_callback_in_progress) { process_poll(&spirit_radio_process); interrupt_callback_wants_poll = 1; return; } interrupt_callback_wants_poll = 0; interrupt_callback_in_progress = 1; /* get interrupt source from radio */ SpiritIrqGetStatus(&xIrqStatus); SpiritIrqClearStatus(); if(xIrqStatus.IRQ_RX_FIFO_ERROR) { receiving_packet = 0; interrupt_callback_in_progress = 0; spirit1_strobe(SPIRIT1_STROBE_FRX); return; } if(xIrqStatus.IRQ_TX_FIFO_ERROR) { receiving_packet = 0; interrupt_callback_in_progress = 0; spirit1_strobe(SPIRIT1_STROBE_FTX); return; } /* The IRQ_VALID_SYNC is used to notify a new packet is coming */ if(xIrqStatus.IRQ_VALID_SYNC) { INTPRINTF("SYNC\n"); receiving_packet = 1; } /* The IRQ_TX_DATA_SENT notifies the packet received. Puts the SPIRIT1 in RX */ if(xIrqStatus.IRQ_TX_DATA_SENT) { spirit1_strobe(SPIRIT1_STROBE_RX); /* SpiritCmdStrobeRx();*/ INTPRINTF("SENT\n"); CLEAR_TXBUF(); interrupt_callback_in_progress = 0; return; } /* The IRQ_RX_DATA_READY notifies a new packet arrived */ if(xIrqStatus.IRQ_RX_DATA_READY) { SpiritSpiReadLinearFifo(SpiritLinearFifoReadNumElementsRxFifo(), &spirit_rxbuf[1]); spirit_rxbuf[0] = SpiritPktBasicGetReceivedPktLength(); spirit1_strobe(SPIRIT1_STROBE_FRX); INTPRINTF("RECEIVED\n"); process_poll(&spirit_radio_process); receiving_packet = 0; #if NULLRDC_CONF_802154_AUTOACK if (spirit_rxbuf[0] == ACK_LEN) { /* For debugging purposes we assume this is an ack for us */ just_got_an_ack = 1; } #endif /* NULLRDC_CONF_802154_AUTOACK */ interrupt_callback_in_progress = 0; return; } if(xIrqStatus.IRQ_RX_DATA_DISC) { spirit1_strobe(SPIRIT1_STROBE_FRX); CLEAR_RXBUF(); INTPRINTF("DISC\n"); receiving_packet = 0; } interrupt_callback_in_progress = 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(); }
/*---------------------------------------------------------------------------*/ 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; }