📄 xe1205phyp.nc
字号:
/*
* Copyright (c) 2006, Ecole Polytechnique Federale de Lausanne (EPFL),
* Switzerland.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of the Ecole Polytechnique Federale de Lausanne (EPFL)
* 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
* OWNER 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.
*
* ========================================================================
*/
/*
* @author Henri Dubois-Ferriere
*
*/
#include "Timer.h"
module XE1205PhyP {
provides interface XE1205PhyRxTx;
provides interface XE1205PhyRssi;
provides interface Init @atleastonce();
provides interface SplitControl @atleastonce();
uses interface Resource as SpiResourceTX;
uses interface Resource as SpiResourceRX;
uses interface Resource as SpiResourceConfig;
uses interface Resource as SpiResourceRssi;
uses interface XE1205PhySwitch;
uses interface XE1205IrqConf;
uses interface XE1205Fifo;
uses interface XE1205RssiConf;
uses interface XE1205PatternConf;
uses interface GpioInterrupt as Interrupt0;
uses interface GpioInterrupt as Interrupt1;
uses interface Alarm<T32khz,uint16_t> as Alarm32khz16;
#if 0
uses interface GeneralIO as Dpin;
#endif
}
implementation {
#include "xe1205debug.h"
char* txBuf = NULL;
uint8_t rxFrameIndex = 0;
uint8_t rxFrameLen = 0;
uint8_t nextTxLen=0;
uint8_t nextRxLen;
char rxFrame[xe1205_mtu];
uint8_t headerLen = 4;
uint16_t stats_rxOverruns;
enum {
RSSI_RANGE_LOW=1,
RSSI_RANGE_HIGH=2,
RSSI_OFF=0,
};
uint8_t rssiRange = RSSI_OFF;
norace uint8_t rssiL,rssiH;
uint8_t * rLow = &rssiL;
uint8_t * rHigh = &rssiH;
bool enableAck = FALSE;
typedef enum { // remember to update busy() and off(), start(), stop() if states are added
RADIO_LISTEN=0,
RADIO_RX_HEADER=1,
RADIO_RX_PACKET=2,
RADIO_RX_PACKET_LAST=3,
RADIO_TX=4,
RADIO_SLEEP=5,
RADIO_STARTING=6,
RADIO_RSSI=7,
RADIO_RX_ACK=8,
RADIO_TX_ACK=9
} phy_state_t;
phy_state_t state = RADIO_SLEEP;
void armPatternDetect();
////////////////////////////////////////////////////////////////////////////////////
//
// jiffy/microseconds/bytetime conversion functions.
//
////////////////////////////////////////////////////////////////////////////////////
// 1 jiffie = 1/32768 = 30.52us;
// we approximate to 32us for quicker computation and also to account for interrupt/processing overhead.
inline uint32_t usecs_to_jiffies(uint32_t usecs) {
return usecs >> 5;
}
command error_t Init.init()
{
#if 0
call Dpin.makeOutput();
#endif
call XE1205PhySwitch.sleepMode();
call XE1205PhySwitch.antennaOff();
return SUCCESS;
}
task void startDone() {
signal SplitControl.startDone(SUCCESS);
}
event void SpiResourceTX.granted() { }
event void SpiResourceRX.granted() { }
event void SpiResourceConfig.granted() {
armPatternDetect();
call SpiResourceConfig.release();
atomic {
if (state == RADIO_STARTING){
post startDone();
}
if (state == RADIO_RX_ACK) {
enableAck=FALSE;
signal XE1205PhyRxTx.sendFrameDone(FAIL);
}
state = RADIO_LISTEN;
call Interrupt0.enableRisingEdge();
}
}
event void SpiResourceRssi.granted() { }
task void stopDone() {
signal SplitControl.stopDone(SUCCESS);
}
command error_t SplitControl.start()
{
atomic {
if (state == RADIO_LISTEN){ post startDone(); return SUCCESS;}
if (state != RADIO_SLEEP) return EBUSY;
state = RADIO_STARTING;
}
call XE1205PhySwitch.rxMode();
call XE1205PhySwitch.antennaRx();
call Alarm32khz16.start(usecs_to_jiffies(XE1205_Sleep_to_RX_Time));
return SUCCESS;
}
command error_t SplitControl.stop()
{
atomic {
if (!call XE1205PhyRxTx.busy()) {
call XE1205PhySwitch.sleepMode();
call XE1205PhySwitch.antennaOff();
state = RADIO_SLEEP;
call Interrupt0.disable();
call Interrupt1.disable();
post stopDone();
return SUCCESS;
} else return FAIL;
}
}
default event void SplitControl.startDone(error_t error) { }
default event void SplitControl.stopDone(error_t error) { }
default async event void XE1205PhyRssi.rssiDone(uint8_t _rssi) { }
async command bool XE1205PhyRxTx.busy() {
atomic return (state != RADIO_LISTEN &&
state != RADIO_SLEEP);
}
async command bool XE1205PhyRxTx.off() {
atomic return (state == RADIO_SLEEP ||
state == RADIO_STARTING);
}
async command void XE1205PhyRxTx.enableAck(bool onOff) {
atomic enableAck = onOff;
}
void armPatternDetect()
{
// small chance of a pattern arriving right after we arm,
// and IRQ0 hasn't been enabled yet, so we would miss the interrupt
// xxx maybe this can also be addressed with periodic timer?
call XE1205IrqConf.armPatternDetector(TRUE);
call XE1205IrqConf.clearFifoOverrun(TRUE);
}
async command void XE1205PhyRxTx.setRxHeaderLen(uint8_t l)
{
if (l > 8) l = 8;
if (!l) return;
headerLen = l;
}
async command uint8_t XE1205PhyRxTx.getRxHeaderLen() {
return headerLen;
}
void computeNextRxLength()
{
uint8_t n = rxFrameLen - rxFrameIndex;
// for timesync and such, we want the end of the packet to coincide with a fifofull event,
// so that we know precisely when last byte was received
if (n > 16) {
if (n < 32) nextRxLen = n - 15; else nextRxLen = 15;
}
else {
nextRxLen = n;
}
}
async command uint8_t XE1205PhyRssi.readRxRssi() {
return rssiTab[(rssiH<<2) |rssiL];
}
task void rssiDone() {
signal XE1205PhyRssi.rssiDone( rssiTab[(rssiH<<2) |rssiL]);
}
void readRssi() {
if(rssiRange ==RSSI_RANGE_LOW ) {
rssiRange = RSSI_RANGE_HIGH;
call XE1205RssiConf.getRssi(rLow);
call XE1205RssiConf.setRssiRange(TRUE);
call Alarm32khz16.start(usecs_to_jiffies(call XE1205RssiConf.getRssiMeasurePeriod_us()));
} else {
call XE1205RssiConf.getRssi(rHigh);
call XE1205RssiConf.setRssiMode(FALSE);
if(state == RADIO_RSSI) {
armPatternDetect();
call SpiResourceRssi.release();
call Interrupt0.enableRisingEdge();
atomic state = RADIO_LISTEN;
signal XE1205PhyRssi.rssiDone( rssiTab[(rssiH<<2) |rssiL]);
} else { // go on with rx of packet
call Alarm32khz16.start(3000);
}
rssiRange = RSSI_OFF;
}
}
error_t getRssi() {
error_t err;
err = call XE1205RssiConf.setRssiMode(TRUE);
err = ecombine(err,call XE1205RssiConf.setRssiRange(FALSE));
rssiRange=RSSI_RANGE_LOW;
call Alarm32khz16.start(usecs_to_jiffies(call XE1205RssiConf.getRssiMeasurePeriod_us()));
return err;
}
async command error_t XE1205PhyRssi.getRssi() {
error_t err;
atomic {
if (state != RADIO_LISTEN&&rssiRange==RSSI_OFF) return EBUSY;
if (call XE1205PhyRxTx.off()) {
return EOFF;
}
if(call SpiResourceRssi.immediateRequest() != SUCCESS) {
return FAIL;
}
err=getRssi();
if (SUCCESS ==err) {
state = RADIO_RSSI;
}
return err;
}
}
async command error_t XE1205PhyRxTx.sendFrame(char* data, uint8_t frameLen) __attribute__ ((noinline))
{
error_t status;
if (frameLen < 6) return EINVAL;
atomic {
if (state == RADIO_SLEEP) return EOFF;
if (call XE1205PhyRxTx.busy()) return EBUSY;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -