📄 rf230layerp.nc
字号:
/* * Copyright (c) 2007, Vanderbilt University * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice, the following * two paragraphs and the author appear in all copies of this software. * * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Author: Miklos Maroti */#include <RF230.h>#include <HplRF230.h>#include <Tasklet.h>#include <RadioAssert.h>#include <TimeSyncMessage.h>module RF230LayerP{ provides { interface Init as PlatformInit @exactlyonce(); interface Init as SoftwareInit @exactlyonce(); interface RadioState; interface RadioSend; interface RadioReceive; interface RadioCCA; } uses { interface GeneralIO as SELN; interface Resource as SpiResource; interface SpiByte; interface HplRF230; interface GeneralIO as SLP_TR; interface GeneralIO as RSTN; interface GpioCapture as IRQ; interface BusyWait<TMicro, uint16_t>; interface PacketField<uint8_t> as PacketLinkQuality; interface PacketField<uint8_t> as PacketTransmitPower; interface PacketField<uint8_t> as PacketRSSI; interface PacketField<uint8_t> as PacketTimeSyncOffset; interface PacketTimeStamp<TRF230, uint32_t>; interface LocalTime<TRF230>; interface RF230Config; interface Tasklet; interface RadioAlarm;#ifdef RF230_DEBUG interface DiagMsg;#endif }}implementation{/*----------------- STATE -----------------*/ tasklet_norace uint8_t state; enum { STATE_P_ON = 0, STATE_SLEEP = 1, STATE_SLEEP_2_TRX_OFF = 2, STATE_TRX_OFF = 3, STATE_TRX_OFF_2_RX_ON = 4, STATE_RX_ON = 5, STATE_BUSY_TX_2_RX_ON = 6, STATE_PLL_ON_2_RX_ON = 7, }; tasklet_norace uint8_t cmd; enum { CMD_NONE = 0, // the state machine has stopped CMD_TURNOFF = 1, // goto SLEEP state CMD_STANDBY = 2, // goto TRX_OFF state CMD_TURNON = 3, // goto RX_ON state CMD_TRANSMIT = 4, // currently transmitting a message CMD_RECEIVE = 5, // currently receiving a message CMD_CCA = 6, // performing clear chanel assesment CMD_CHANNEL = 7, // changing the channel CMD_SIGNAL_DONE = 8, // signal the end of the state transition CMD_DOWNLOAD = 9, // download the received message }; norace bool radioIrq; tasklet_norace uint8_t txPower; tasklet_norace uint8_t channel; tasklet_norace message_t* rxMsg; message_t rxMsgBuffer; uint16_t capturedTime; // the current time when the last interrupt has occured tasklet_norace uint8_t rssiClear; tasklet_norace uint8_t rssiBusy;/*----------------- REGISTER -----------------*/ inline void writeRegister(uint8_t reg, uint8_t value) { ASSERT( call SpiResource.isOwner() ); ASSERT( reg == (reg & RF230_CMD_REGISTER_MASK) ); call SELN.clr(); call HplRF230.spiSplitWrite(RF230_CMD_REGISTER_WRITE | reg); call HplRF230.spiSplitReadWrite(value); call HplRF230.spiSplitRead(); call SELN.set(); } inline uint8_t readRegister(uint8_t reg) { ASSERT( call SpiResource.isOwner() ); ASSERT( reg == (reg & RF230_CMD_REGISTER_MASK) ); call SELN.clr(); call HplRF230.spiSplitWrite(RF230_CMD_REGISTER_READ | reg); call HplRF230.spiSplitReadWrite(0); reg = call HplRF230.spiSplitRead(); call SELN.set(); return reg; }/*----------------- ALARM -----------------*/ enum { SLEEP_WAKEUP_TIME = (uint16_t)(880 * RF230_ALARM_MICROSEC), CCA_REQUEST_TIME = (uint16_t)(140 * RF230_ALARM_MICROSEC), TX_SFD_DELAY = (uint16_t)(176 * RF230_ALARM_MICROSEC), RX_SFD_DELAY = (uint16_t)(8 * RF230_ALARM_MICROSEC), }; tasklet_async event void RadioAlarm.fired() { if( state == STATE_SLEEP_2_TRX_OFF ) state = STATE_TRX_OFF; else if( cmd == CMD_CCA ) { uint8_t cca; ASSERT( state == STATE_RX_ON ); cmd = CMD_NONE; cca = readRegister(RF230_TRX_STATUS); ASSERT( (cca & RF230_TRX_STATUS_MASK) == RF230_RX_ON ); signal RadioCCA.done( (cca & RF230_CCA_DONE) ? ((cca & RF230_CCA_STATUS) ? SUCCESS : EBUSY) : FAIL ); } else ASSERT(FALSE); // make sure the rest of the command processing is called call Tasklet.schedule(); }/*----------------- INIT -----------------*/ command error_t PlatformInit.init() { call SELN.makeOutput(); call SELN.set(); call SLP_TR.makeOutput(); call SLP_TR.clr(); call RSTN.makeOutput(); call RSTN.set(); rxMsg = &rxMsgBuffer; // these are just good approximates rssiClear = 0; rssiBusy = 90; return SUCCESS; } command error_t SoftwareInit.init() { // for powering up the radio return call SpiResource.request(); } void initRadio() { call BusyWait.wait(510); call RSTN.clr(); call SLP_TR.clr(); call BusyWait.wait(6); call RSTN.set(); writeRegister(RF230_TRX_CTRL_0, RF230_TRX_CTRL_0_VALUE); writeRegister(RF230_TRX_STATE, RF230_TRX_OFF); call BusyWait.wait(510); writeRegister(RF230_IRQ_MASK, RF230_IRQ_TRX_UR | RF230_IRQ_PLL_LOCK | RF230_IRQ_TRX_END | RF230_IRQ_RX_START); writeRegister(RF230_CCA_THRES, RF230_CCA_THRES_VALUE); writeRegister(RF230_PHY_TX_PWR, RF230_TX_AUTO_CRC_ON | RF230_TX_PWR_DEFAULT); txPower = RF230_TX_PWR_DEFAULT; channel = call RF230Config.getDefaultChannel() & RF230_CHANNEL_MASK; writeRegister(RF230_PHY_CC_CCA, RF230_CCA_MODE_VALUE | channel); call SLP_TR.set(); state = STATE_SLEEP; }/*----------------- SPI -----------------*/ event void SpiResource.granted() { call SELN.makeOutput(); call SELN.set(); if( state == STATE_P_ON ) { initRadio(); call SpiResource.release(); } else call Tasklet.schedule(); } bool isSpiAcquired() { if( call SpiResource.isOwner() ) return TRUE; if( call SpiResource.immediateRequest() == SUCCESS ) { call SELN.makeOutput(); call SELN.set(); return TRUE; } call SpiResource.request(); return FALSE; }/*----------------- CHANNEL -----------------*/ tasklet_async command error_t RadioState.setChannel(uint8_t c) { c &= RF230_CHANNEL_MASK; if( cmd != CMD_NONE ) return EBUSY; else if( channel == c ) return EALREADY; channel = c; cmd = CMD_CHANNEL; call Tasklet.schedule(); return SUCCESS; } inline void changeChannel() { ASSERT( cmd == CMD_CHANNEL ); ASSERT( state == STATE_SLEEP || state == STATE_TRX_OFF || state == STATE_RX_ON ); if( isSpiAcquired() ) { writeRegister(RF230_PHY_CC_CCA, RF230_CCA_MODE_VALUE | channel); if( state == STATE_RX_ON ) state = STATE_TRX_OFF_2_RX_ON; else cmd = CMD_SIGNAL_DONE; } }/*----------------- TURN ON/OFF -----------------*/ inline void changeState() { if( (cmd == CMD_STANDBY || cmd == CMD_TURNON) && state == STATE_SLEEP && call RadioAlarm.isFree() ) { call SLP_TR.clr(); call RadioAlarm.wait(SLEEP_WAKEUP_TIME); state = STATE_SLEEP_2_TRX_OFF; } else if( cmd == CMD_TURNON && state == STATE_TRX_OFF && isSpiAcquired() ) { ASSERT( ! radioIrq ); readRegister(RF230_IRQ_STATUS); // clear the interrupt register call IRQ.captureRisingEdge(); writeRegister(RF230_TRX_STATE, RF230_RX_ON); state = STATE_TRX_OFF_2_RX_ON; } else if( (cmd == CMD_TURNOFF || cmd == CMD_STANDBY) && state == STATE_RX_ON && isSpiAcquired() ) { writeRegister(RF230_TRX_STATE, RF230_FORCE_TRX_OFF); call IRQ.disable(); radioIrq = FALSE; state = STATE_TRX_OFF; } if( cmd == CMD_TURNOFF && state == STATE_TRX_OFF ) { call SLP_TR.set(); state = STATE_SLEEP; cmd = CMD_SIGNAL_DONE; } else if( cmd == CMD_STANDBY && state == STATE_TRX_OFF ) cmd = CMD_SIGNAL_DONE; } tasklet_async command error_t RadioState.turnOff() { if( cmd != CMD_NONE ) return EBUSY; else if( state == STATE_SLEEP ) return EALREADY; cmd = CMD_TURNOFF; call Tasklet.schedule(); return SUCCESS; } tasklet_async command error_t RadioState.standby() { if( cmd != CMD_NONE || (state == STATE_SLEEP && ! call RadioAlarm.isFree()) ) return EBUSY; else if( state == STATE_TRX_OFF ) return EALREADY; cmd = CMD_STANDBY; call Tasklet.schedule(); return SUCCESS; } tasklet_async command error_t RadioState.turnOn() { if( cmd != CMD_NONE || (state == STATE_SLEEP && ! call RadioAlarm.isFree()) ) return EBUSY; else if( state == STATE_RX_ON ) return EALREADY; cmd = CMD_TURNON; call Tasklet.schedule(); return SUCCESS; } default tasklet_async event void RadioState.done() { }/*----------------- TRANSMIT -----------------*/ tasklet_async command error_t RadioSend.send(message_t* msg) { uint16_t time; uint8_t length; uint8_t* data; uint8_t header; uint32_t time32; void* timesync; if( cmd != CMD_NONE || state != STATE_RX_ON || ! isSpiAcquired() || radioIrq ) return EBUSY; length = (call PacketTransmitPower.isSet(msg) ? call PacketTransmitPower.get(msg) : RF230_DEF_RFPOWER) & RF230_TX_PWR_MASK; if( length != txPower ) { txPower = length;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -