/* * Copyright (c) 2012, STMicroelectronics. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * */ /*---------------------------------------------------------------------------*/ #include "spirit1.h" #include "spirit1-arch.h" #include "stm32l1xx.h" #include "contiki.h" #include "net/mac/frame802154.h" #include "net/netstack.h" #include "net/packetbuf.h" #include "net/rime/rimestats.h" #include "spirit1-arch.h" #include #include "st-lib.h" /*---------------------------------------------------------------------------*/ /* MGR extern st_lib_spirit_irqs st_lib_x_irq_status; */ extern volatile st_lib_spirit_flag_status rx_timeout; /*---------------------------------------------------------------------------*/ #define XXX_ACK_WORKAROUND 1 /*---------------------------------------------------------------------------*/ #define DEBUG 0 #if DEBUG #include #define PRINTF(...) printf(__VA_ARGS__) #else #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ #define BUSYWAIT_UNTIL(cond, max_time) \ do { \ rtimer_clock_t t0; \ t0 = RTIMER_NOW(); \ while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) ; \ } while(0) /*---------------------------------------------------------------------------*/ #define CLEAR_TXBUF() (spirit_txbuf[0] = 0) #define CLEAR_RXBUF() (spirit_rxbuf[0] = 0) #define IS_TXBUF_EMPTY() (spirit_txbuf[0] == 0) #define IS_RXBUF_EMPTY() (spirit_rxbuf[0] == 0) #define IS_RXBUF_FULL() (spirit_rxbuf[0] != 0) /*---------------------------------------------------------------------------*/ /* transceiver state. */ #define ON 0 #define OFF 1 /*---------------------------------------------------------------------------*/ static volatile unsigned int spirit_on = OFF; static volatile uint8_t receiving_packet = 0; static packetbuf_attr_t last_rssi = 0; /* MGR */ static packetbuf_attr_t last_lqi = 0; /* MGR */ /*---------------------------------------------------------------------------*/ /* * The buffers which hold incoming data. * The +1 because of the first byte, * which will contain the length of the packet. */ static uint8_t spirit_rxbuf[MAX_PACKET_LEN + 1]; static uint8_t spirit_txbuf[MAX_PACKET_LEN + 1 - SPIRIT_MAX_FIFO_LEN]; void st_lib_spirit_management_set_frequency_base(uint32_t); /*---------------------------------------------------------------------------*/ static int just_got_an_ack = 0; /* Interrupt callback just detected an ack */ #if NULLRDC_CONF_802154_AUTOACK #define ACK_LEN 3 static int wants_an_ack = 0; /* The packet sent expects an ack */ /* static int just_got_an_ack = 0; / * Interrupt callback just detected an ack * / */ /* #define ACKPRINTF printf */ #define ACKPRINTF(...) #endif /* NULLRDC_CONF_802154_AUTOACK */ /*---------------------------------------------------------------------------*/ static int packet_is_prepared = 0; /*---------------------------------------------------------------------------*/ PROCESS(spirit_radio_process, "SPIRIT radio driver"); /*---------------------------------------------------------------------------*/ static int spirit_radio_init(void); static int spirit_radio_prepare(const void *payload, unsigned short payload_len); static int spirit_radio_transmit(unsigned short payload_len); static int spirit_radio_send(const void *data, unsigned short len); static int spirit_radio_read(void *buf, unsigned short bufsize); static int spirit_radio_channel_clear(void); static int spirit_radio_receiving_packet(void); static int spirit_radio_pending_packet(void); static int spirit_radio_on(void); static int spirit_radio_off(void); /*---------------------------------------------------------------------------*/ const struct radio_driver spirit_radio_driver = { spirit_radio_init, spirit_radio_prepare, spirit_radio_transmit, spirit_radio_send, spirit_radio_read, spirit_radio_channel_clear, spirit_radio_receiving_packet, spirit_radio_pending_packet, spirit_radio_on, spirit_radio_off, }; /*---------------------------------------------------------------------------*/ void spirit1_printstatus(void) { int s = SPIRIT1_STATUS(); if(s == SPIRIT1_STATE_STANDBY) { printf("spirit1: SPIRIT1_STATE_STANDBY\n"); } else if(s == SPIRIT1_STATE_READY) { printf("spirit1: SPIRIT1_STATE_READY\n"); } else if(s == SPIRIT1_STATE_TX) { printf("spirit1: SPIRIT1_STATE_TX\n"); } else if(s == SPIRIT1_STATE_RX) { printf("spirit1: SPIRIT1_STATE_RX\n"); } else { printf("spirit1: status: %d\n", s); } } /*---------------------------------------------------------------------------*/ /* Strobe a command. The rationale for this is to clean up the messy legacy code. */ static void spirit1_strobe(uint8_t s) { st_lib_spirit_cmd_strobe_command(s); } /*---------------------------------------------------------------------------*/ void spirit_set_ready_state(void) { PRINTF("READY IN\n"); st_lib_spirit_irq_clear_status(); IRQ_DISABLE(); if(SPIRIT1_STATUS() == SPIRIT1_STATE_STANDBY) { spirit1_strobe(SPIRIT1_STROBE_READY); } else if(SPIRIT1_STATUS() == SPIRIT1_STATE_RX) { spirit1_strobe(SPIRIT1_STROBE_SABORT); st_lib_spirit_irq_clear_status(); } IRQ_ENABLE(); PRINTF("READY OUT\n"); } /*---------------------------------------------------------------------------*/ static int spirit_radio_init(void) { PRINTF("RADIO INIT IN\n"); st_lib_spirit_spi_init(); /* Configure radio shut-down (SDN) pin and activate radio */ st_lib_radio_gpio_init(RADIO_GPIO_SDN, RADIO_MODE_GPIO_OUT); /* Configures the SPIRIT1 library */ st_lib_spirit_radio_set_xtal_frequency(XTAL_FREQUENCY); st_lib_spirit_management_set_frequency_base(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 */ RADIO_GPIO_SDN_PORT->BSRR = RADIO_GPIO_SDN_PIN; st_lib_hal_gpio_write_pin(RADIO_GPIO_SDN_PORT, RADIO_GPIO_SDN_PIN, GPIO_PIN_RESET); /* 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); /* Configures the SPIRIT1 radio part */ st_lib_s_radio_init x_radio_init = { /* XTAL_FREQUENCY, */ XTAL_OFFSET_PPM, BASE_FREQUENCY, CHANNEL_SPACE, CHANNEL_NUMBER, MODULATION_SELECT, DATARATE, FREQ_DEVIATION, BANDWIDTH }; st_lib_spirit_radio_init(&x_radio_init); st_lib_spirit_radio_set_xtal_frequency(XTAL_FREQUENCY); st_lib_spirit_radio_set_pa_level_dbm(0, POWER_DBM); st_lib_spirit_radio_set_pa_level_max_index(0); /* Configures the SPIRIT1 packet handler part*/ st_lib_pkt_basic_init x_basic_init = { PREAMBLE_LENGTH, SYNC_LENGTH, SYNC_WORD, LENGTH_TYPE, LENGTH_WIDTH, CRC_MODE, CONTROL_LENGTH, EN_ADDRESS, EN_FEC, EN_WHITENING }; st_lib_spirit_pkt_basic_init(&x_basic_init); /* Enable the following interrupt sources, routed to GPIO */ st_lib_spirit_irq_de_init(NULL); st_lib_spirit_irq_clear_status(); st_lib_spirit_irq(TX_DATA_SENT, S_ENABLE); st_lib_spirit_irq(RX_DATA_READY, S_ENABLE); st_lib_spirit_irq(VALID_SYNC, S_ENABLE); st_lib_spirit_irq(RX_DATA_DISC, S_ENABLE); st_lib_spirit_irq(TX_FIFO_ERROR, S_ENABLE); st_lib_spirit_irq(RX_FIFO_ERROR, S_ENABLE); /* Configure Spirit1 */ st_lib_spirit_radio_persisten_rx(S_ENABLE); st_lib_spirit_qi_set_sqi_threshold(SQI_TH_0); st_lib_spirit_qi_sqi_check(S_ENABLE); st_lib_spirit_qi_set_rssi_threshold_dbm(CCA_THRESHOLD); st_lib_spirit_timer_set_rx_timeout_stop_condition(SQI_ABOVE_THRESHOLD); SET_INFINITE_RX_TIMEOUT(); st_lib_spirit_radio_afc_freeze_on_sync(S_ENABLE); /* Puts the SPIRIT1 in STANDBY mode (125us -> rx/tx) */ spirit1_strobe(SPIRIT1_STROBE_STANDBY); spirit_on = OFF; CLEAR_RXBUF(); CLEAR_TXBUF(); /* Initializes the mcu pin as input, used for IRQ */ st_lib_radio_gpio_init(RADIO_GPIO_IRQ, RADIO_MODE_EXTI_IN); /* Configure the radio to route the IRQ signal to its GPIO 3 */ st_lib_spirit_gpio_init(&(st_lib_s_gpio_init){SPIRIT_GPIO_IRQ, SPIRIT_GPIO_MODE_DIGITAL_OUTPUT_LP, SPIRIT_GPIO_DIG_OUT_IRQ }); process_start(&spirit_radio_process, NULL); PRINTF("Spirit1 init done\n"); return 0; } /*---------------------------------------------------------------------------*/ 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; } /* 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 */ IRQ_DISABLE(); spirit1_strobe(SPIRIT1_STROBE_FTX); st_lib_spirit_pkt_basic_set_payload_length(payload_len); st_lib_spirit_spi_write_linear_fifo(payload_len, (uint8_t *)payload); IRQ_ENABLE(); PRINTF("PREPARE OUT\n"); packet_is_prepared = 1; return RADIO_TX_OK; } /*---------------------------------------------------------------------------*/ 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; spirit_set_ready_state(); spirit1_strobe(SPIRIT1_STROBE_TX); just_got_an_ack = 0; BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_TX, 1 * RTIMER_SECOND / 1000); /* BUSYWAIT_UNTIL(SPIRIT1_STATUS() != SPIRIT1_STATE_TX, 4 * RTIMER_SECOND/1000); //For GFSK with high data rate */ BUSYWAIT_UNTIL(SPIRIT1_STATUS() != SPIRIT1_STATE_TX, 50 * RTIMER_SECOND / 1000); /* For FSK with low data rate */ /* Reset radio - needed for immediate RX of ack */ CLEAR_TXBUF(); CLEAR_RXBUF(); IRQ_DISABLE(); st_lib_spirit_irq_clear_status(); spirit1_strobe(SPIRIT1_STROBE_SABORT); BUSYWAIT_UNTIL(0, RTIMER_SECOND / 2500); 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); IRQ_ENABLE(); #if XXX_ACK_WORKAROUND just_got_an_ack = 1; #endif /* XXX_ACK_WORKAROUND */ #if NULLRDC_CONF_802154_AUTOACK if(wants_an_ack) { rtimer_txdone = RTIMER_NOW(); BUSYWAIT_UNTIL(just_got_an_ack, 2 * 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), 2 * 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; clock_wait(1); return RADIO_TX_OK; } /*---------------------------------------------------------------------------*/ static int spirit_radio_send(const void *payload, unsigned short payload_len) { if(spirit_radio_prepare(payload, payload_len) == RADIO_TX_ERR) { return RADIO_TX_ERR; } return spirit_radio_transmit(payload_len); } /*---------------------------------------------------------------------------*/ static int spirit_radio_read(void *buf, unsigned short bufsize) { PRINTF("READ IN\n"); /* Checks if the RX buffer is empty */ if(IS_RXBUF_EMPTY()) { IRQ_DISABLE(); CLEAR_RXBUF(); spirit1_strobe(SPIRIT1_STROBE_SABORT); BUSYWAIT_UNTIL(0, RTIMER_SECOND / 2500); 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); PRINTF("READ OUT RX BUF EMPTY\n"); IRQ_ENABLE(); return 0; } if(bufsize < spirit_rxbuf[0]) { /* If buf has the correct size */ PRINTF("TOO SMALL BUF\n"); return 0; } else { /* Copies the packet received */ memcpy(buf, spirit_rxbuf + 1, spirit_rxbuf[0]); packetbuf_set_attr(PACKETBUF_ATTR_RSSI, last_rssi); /* MGR */ packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, last_lqi); /* MGR */ bufsize = spirit_rxbuf[0]; CLEAR_RXBUF(); PRINTF("READ OUT\n"); return bufsize; } } /*---------------------------------------------------------------------------*/ 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();*/ st_lib_spirit_irq_clear_status(); IRQ_ENABLE(); { rtimer_clock_t timeout = RTIMER_NOW() + 5 * RTIMER_SECOND / 1000; do { st_lib_spirit_refresh_status(); } while((st_lib_g_x_status.MC_STATE != MC_STATE_READY) && (RTIMER_NOW() < timeout)); if(RTIMER_NOW() < timeout) { return 1; } } /* Stores the RSSI value */ rssi_value = st_lib_spirit_qi_get_rssi_dbm(); /* 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; } } /*---------------------------------------------------------------------------*/ static int spirit_radio_receiving_packet(void) { return receiving_packet; } /*---------------------------------------------------------------------------*/ static int spirit_radio_pending_packet(void) { PRINTF("PENDING PACKET\n"); return !IS_RXBUF_EMPTY(); } /*---------------------------------------------------------------------------*/ 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 */ st_lib_spirit_irq_clear_status(); 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"); spirit1_strobe(SPIRIT1_STROBE_SABORT); BUSYWAIT_UNTIL(0, RTIMER_SECOND / 2500); 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"); while(1) ; /* 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"); while(1) ; /* return 1; */ } /* Enables the mcu to get IRQ from the SPIRIT1 */ IRQ_ENABLE(); spirit_on = ON; } return 0; } /*---------------------------------------------------------------------------*/ static int interrupt_callback_in_progress = 0; static int interrupt_callback_wants_poll = 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 && linkaddr_cmp((linkaddr_t *)&info154.dest_addr, &linkaddr_node_addr)) { #if !XXX_ACK_WORKAROUND /* Send an ACK packet */ uint8_t ack_frame[ACK_LEN] = { FRAME802154_ACKFRAME, 0x00, info154.seq }; IRQ_DISABLE(); spirit1_strobe(SPIRIT1_STROBE_FTX); st_lib_spirit_pkt_basic_set_payload_length((uint16_t)ACK_LEN); st_lib_spirit_spi_write_linear_fifo((uint16_t)ACK_LEN, (uint8_t *)ack_frame); spirit_set_ready_state(); IRQ_ENABLE(); 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 /* !XXX_ACK_WORKAROUND */ } } #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(); } /*---------------------------------------------------------------------------*/ void spirit1_interrupt_callback(void) { #define INTPRINTF(...) /* PRINTF */ st_lib_spirit_irqs x_irq_status; if(spirit_spi_busy() || 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 */ st_lib_spirit_irq_get_status(&x_irq_status); st_lib_spirit_irq_clear_status(); if(x_irq_status.IRQ_RX_FIFO_ERROR) { receiving_packet = 0; interrupt_callback_in_progress = 0; spirit1_strobe(SPIRIT1_STROBE_FRX); return; } if(x_irq_status.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(x_irq_status.IRQ_VALID_SYNC) { INTPRINTF("SYNC\n"); receiving_packet = 1; } /* The IRQ_TX_DATA_SENT notifies the packet received. Puts the SPIRIT1 in RX */ if(x_irq_status.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(x_irq_status.IRQ_RX_DATA_READY) { st_lib_spirit_spi_read_linear_fifo(st_lib_spirit_linear_fifo_read_num_elements_rx_fifo(), &spirit_rxbuf[1]); spirit_rxbuf[0] = st_lib_spirit_pkt_basic_get_received_pkt_length(); spirit1_strobe(SPIRIT1_STROBE_FRX); INTPRINTF("RECEIVED\n"); process_poll(&spirit_radio_process); last_rssi = (packetbuf_attr_t)st_lib_spirit_qi_get_rssi(); /* MGR */ last_lqi = (packetbuf_attr_t)st_lib_spirit_qi_get_lqi(); /* MGR */ 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(x_irq_status.IRQ_RX_DATA_DISC) { /* RX command - to ensure the device will be ready for the next reception */ if(x_irq_status.IRQ_RX_TIMEOUT) { st_lib_spirit_cmd_strobe_flush_rx_fifo(); rx_timeout = SET; } } interrupt_callback_in_progress = 0; } /*---------------------------------------------------------------------------*/