osd-contiki/platform/stm32nucleo-spirit1/spirit1.c
2015-07-24 16:30:10 +02:00

741 lines
23 KiB
C

/**
******************************************************************************
* @file spirit1.c
* @author System LAB
* @version V1.0.0
* @date 17-June-2015
* @brief Source file for SPIRIT1
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
*
* 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 STMicroelectronics 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#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 <stdio.h>
extern SpiritIrqs xIrqStatus;
extern volatile FlagStatus rx_timeout;
#define XXX_ACK_WORKAROUND 1
/*---------------------------------------------------------------------------*/
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#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;
/*
* 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 SpiritManagementSetFrequencyBase(uint32_t lFBase);
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,
};
/*---------------------------------------------------------------------------*/
/* convienience macro for reading the MC_STATE[1] register from Spirit1, to be used like eg
if(SPIRIT1_STATUS() == SPIRIT1_STATE_READY) {
}
or
BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_READY, RTIMER_SECOND/1000);
*/
/*---------------------------------------------------------------------------*/
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)
{
SpiritCmdStrobeCommand(s);
}
/*---------------------------------------------------------------------------*/
/**
* @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_init(void)
{
PRINTF("RADIO INIT IN\n");
SpiritSpiInit();
/* Configure radio shut-down (SDN) pin and activate radio */
RadioGpioInit(RADIO_GPIO_SDN, RADIO_MODE_GPIO_OUT);
/* Configures the SPIRIT1 library */
SpiritRadioSetXtalFrequency(XTAL_FREQUENCY);
SpiritManagementSetFrequencyBase(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;
HAL_GPIO_WritePin(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 */
SRadioInit xRadioInit = {
// XTAL_FREQUENCY,
XTAL_OFFSET_PPM,
BASE_FREQUENCY,
CHANNEL_SPACE,
CHANNEL_NUMBER,
MODULATION_SELECT,
DATARATE,
FREQ_DEVIATION,
BANDWIDTH
};
SpiritRadioInit(&xRadioInit);
SpiritRadioSetXtalFrequency(XTAL_FREQUENCY);
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);
spirit_on = OFF;
CLEAR_RXBUF();
CLEAR_TXBUF();
/* Initializes the mcu pin as input, used for IRQ */
RadioGpioInit(RADIO_GPIO_IRQ, RADIO_MODE_EXTI_IN);
/* Configure the radio to route the IRQ signal to its GPIO 3 */
SpiritGpioInit(&(SGpioInit){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);
SpiritPktBasicSetPayloadLength(payload_len);
SpiritSpiWriteLinearFifo(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;
SpiritSetReadyState();
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();
SpiritIrqClearStatus();
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]);
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();*/
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;
}
}
/*---------------------------------------------------------------------------*/
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 */
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");
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);
SpiritPktBasicSetPayloadLength((uint16_t) ACK_LEN);
SpiritSpiWriteLinearFifo((uint16_t) ACK_LEN, (uint8_t *) ack_frame);
SpiritSetReadyState();
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
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)
{
/* RX command - to ensure the device will be ready for the next reception */
if(xIrqStatus.IRQ_RX_TIMEOUT)
{
SpiritCmdStrobeFlushRxFifo();
rx_timeout = SET;
}
}
interrupt_callback_in_progress = 0;
}
/*---------------------------------------------------------------------------*/