defaultlplp.nc
来自「tinyos-2.x.rar」· NC 代码 · 共 416 行
NC
416 行
/*
* Copyright (c) 2005-2006 Rincon Research Corporation
* 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 Rincon Research Corporation 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
* RINCON RESEARCH OR ITS 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
*/
/**
* Low Power Listening for the CC2420. This component is responsible for
* delivery of an LPL packet, and for turning off the radio when the radio
* has run out of tasks.
*
* The PowerCycle component is responsible for duty cycling the radio
* and performing receive detections.
*
* @author David Moss
*/
#include "Lpl.h"
#include "DefaultLpl.h"
#include "AM.h"
module DefaultLplP {
provides {
interface Init;
interface LowPowerListening;
interface Send;
interface Receive;
}
uses {
interface Send as SubSend;
interface CC2420Transmit as Resend;
interface RadioBackoff;
interface Receive as SubReceive;
interface SplitControl as SubControl;
interface PowerCycle;
interface CC2420PacketBody;
interface PacketAcknowledgements;
interface State as SendState;
interface State as RadioPowerState;
interface State as SplitControlState;
interface Timer<TMilli> as OffTimer;
interface Timer<TMilli> as SendDoneTimer;
interface Random;
interface Leds;
interface SystemLowPowerListening;
}
}
implementation {
/** The message currently being sent */
norace message_t *currentSendMsg;
/** The length of the current send message */
uint8_t currentSendLen;
/** TRUE if the radio is duty cycling and not always on */
bool dutyCycling;
/**
* Radio Power State
*/
enum {
S_OFF, // off by default
S_TURNING_ON,
S_ON,
S_TURNING_OFF,
};
/**
* Send States
*/
enum {
S_IDLE,
S_SENDING,
};
enum {
ONE_MESSAGE = 0,
};
/***************** Prototypes ***************/
task void send();
task void resend();
task void startRadio();
task void stopRadio();
void initializeSend();
void startOffTimer();
/***************** Init Commands ***************/
command error_t Init.init() {
dutyCycling = FALSE;
return SUCCESS;
}
/***************** LowPowerListening Commands ***************/
/**
* Set this this node's radio wakeup interval, in milliseconds.
* Once every interval, the node will sleep and perform an Rx check
* on the radio. Setting the wakeup interval to 0 will keep the radio
* always on.
*
* @param intervalMs the length of this node's wakeup interval, in [ms]
*/
command void LowPowerListening.setLocalWakeupInterval(uint16_t intervalMs) {
call PowerCycle.setSleepInterval(intervalMs);
}
/**
* @return the local node's wakeup interval, in [ms]
*/
command uint16_t LowPowerListening.getLocalWakeupInterval() {
return call PowerCycle.getSleepInterval();
}
/**
* Configure this outgoing message so it can be transmitted to a neighbor mote
* with the specified wakeup interval.
* @param msg Pointer to the message that will be sent
* @param intervalMs The receiving node's wakeup interval, in [ms]
*/
command void LowPowerListening.setRemoteWakeupInterval(message_t *msg,
uint16_t intervalMs) {
(call CC2420PacketBody.getMetadata(msg))->rxInterval = intervalMs;
}
/**
* @return the destination node's wakeup interval configured in this message
*/
command uint16_t LowPowerListening.getRemoteWakeupInterval(message_t *msg) {
return (call CC2420PacketBody.getMetadata(msg))->rxInterval;
}
/***************** Send Commands ***************/
/**
* Each call to this send command gives the message a single
* DSN that does not change for every copy of the message
* sent out. For messages that are not acknowledged, such as
* a broadcast address message, the receiving end does not
* signal receive() more than once for that message.
*/
command error_t Send.send(message_t *msg, uint8_t len) {
if(call SplitControlState.getState() == S_OFF) {
// Everything is off right now, start SplitControl and try again
return EOFF;
}
if(call SendState.requestState(S_LPL_SENDING) == SUCCESS) {
currentSendMsg = msg;
currentSendLen = len;
// In case our off timer is running...
call OffTimer.stop();
call SendDoneTimer.stop();
if(call RadioPowerState.getState() == S_ON) {
initializeSend();
return SUCCESS;
} else {
post startRadio();
}
return SUCCESS;
}
return EBUSY;
}
command error_t Send.cancel(message_t *msg) {
if(currentSendMsg == msg) {
call SendState.toIdle();
call SendDoneTimer.stop();
startOffTimer();
return call SubSend.cancel(msg);
}
return FAIL;
}
command uint8_t Send.maxPayloadLength() {
return call SubSend.maxPayloadLength();
}
command void *Send.getPayload(message_t* msg, uint8_t len) {
return call SubSend.getPayload(msg, len);
}
/***************** RadioBackoff Events ****************/
async event void RadioBackoff.requestInitialBackoff(message_t *msg) {
if((call CC2420PacketBody.getMetadata(msg))->rxInterval
> ONE_MESSAGE) {
call RadioBackoff.setInitialBackoff( call Random.rand16()
% (0x4 * CC2420_BACKOFF_PERIOD) + CC2420_MIN_BACKOFF);
}
}
async event void RadioBackoff.requestCongestionBackoff(message_t *msg) {
if((call CC2420PacketBody.getMetadata(msg))->rxInterval
> ONE_MESSAGE) {
call RadioBackoff.setCongestionBackoff( call Random.rand16()
% (0x3 * CC2420_BACKOFF_PERIOD) + CC2420_MIN_BACKOFF);
}
}
async event void RadioBackoff.requestCca(message_t *msg) {
}
/***************** DutyCycle Events ***************/
/**
* A transmitter was detected. You must now take action to
* turn the radio off when the transaction is complete.
*/
event void PowerCycle.detected() {
// At this point, the duty cycling has been disabled temporary
// and it will be this component's job to turn the radio back off
// Wait long enough to see if we actually receive a packet, which is
// just a little longer in case there is more than one lpl transmitter on
// the channel.
startOffTimer();
}
/***************** SubControl Events ***************/
event void SubControl.startDone(error_t error) {
if(!error) {
call RadioPowerState.forceState(S_ON);
if(call SendState.getState() == S_LPL_FIRST_MESSAGE
|| call SendState.getState() == S_LPL_SENDING) {
initializeSend();
}
}
}
event void SubControl.stopDone(error_t error) {
if(!error) {
if(call SendState.getState() == S_LPL_FIRST_MESSAGE
|| call SendState.getState() == S_LPL_SENDING) {
// We're in the middle of sending a message; start the radio back up
post startRadio();
} else {
call OffTimer.stop();
call SendDoneTimer.stop();
}
}
}
/***************** SubSend Events ***************/
event void SubSend.sendDone(message_t* msg, error_t error) {
switch(call SendState.getState()) {
case S_LPL_SENDING:
if(call SendDoneTimer.isRunning()) {
if(!call PacketAcknowledgements.wasAcked(msg)) {
post resend();
return;
}
}
break;
case S_LPL_CLEAN_UP:
/**
* We include this state so upper layers can't send a different message
* before the last message gets done sending
*/
break;
default:
break;
}
call SendState.toIdle();
call SendDoneTimer.stop();
startOffTimer();
signal Send.sendDone(msg, error);
}
/***************** SubReceive Events ***************/
/**
* If the received message is new, we signal the receive event and
* start the off timer. If the last message we received had the same
* DSN as this message, then the chances are pretty good
* that this message should be ignored, especially if the destination address
* as the broadcast address
*/
event message_t *SubReceive.receive(message_t* msg, void* payload,
uint8_t len) {
startOffTimer();
return signal Receive.receive(msg, payload, len);
}
/***************** Timer Events ****************/
event void OffTimer.fired() {
/*
* Only stop the radio if the radio is supposed to be off permanently
* or if the duty cycle is on and our sleep interval is not 0
*/
if(call SplitControlState.getState() == S_OFF
|| (call PowerCycle.getSleepInterval() > 0
&& call SplitControlState.getState() != S_OFF
&& call SendState.getState() == S_LPL_NOT_SENDING)) {
post stopRadio();
}
}
/**
* When this timer is running, that means we're sending repeating messages
* to a node that is receive check duty cycling.
*/
event void SendDoneTimer.fired() {
if(call SendState.getState() == S_LPL_SENDING) {
// The next time SubSend.sendDone is signaled, send is complete.
call SendState.forceState(S_LPL_CLEAN_UP);
}
}
/***************** Resend Events ****************/
/**
* Signal that a message has been sent
*
* @param p_msg message to send.
* @param error notifaction of how the operation went.
*/
async event void Resend.sendDone( message_t* p_msg, error_t error ) {
// This is actually caught by SubSend.sendDone
}
/***************** Tasks ***************/
task void send() {
if(call SubSend.send(currentSendMsg, currentSendLen) != SUCCESS) {
post send();
}
}
task void resend() {
if(call Resend.resend(TRUE) != SUCCESS) {
post resend();
}
}
task void startRadio() {
if(call SubControl.start() != SUCCESS) {
post startRadio();
}
}
task void stopRadio() {
if(call SendState.getState() == S_LPL_NOT_SENDING) {
if(call SubControl.stop() != SUCCESS) {
post stopRadio();
}
}
}
/***************** Functions ***************/
void initializeSend() {
if(call LowPowerListening.getRemoteWakeupInterval(currentSendMsg)
> ONE_MESSAGE) {
if((call CC2420PacketBody.getHeader(currentSendMsg))->dest == IEEE154_BROADCAST_ADDR) {
call PacketAcknowledgements.noAck(currentSendMsg);
} else {
// Send it repetitively within our transmit window
call PacketAcknowledgements.requestAck(currentSendMsg);
}
call SendDoneTimer.startOneShot(
call LowPowerListening.getRemoteWakeupInterval(currentSendMsg) + 20);
}
post send();
}
void startOffTimer() {
call OffTimer.startOneShot(call SystemLowPowerListening.getDelayAfterReceive());
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?