-PLATFORM_INCLUDE?=$(TOSDIR)/platforms/$(PLATFORM)/mac/tkn154/Makefile.include
+PLATFORMS = telosb
+TKN154_PLATFORM_INCLUDE?=$(TOSDIR)/platforms/$(PLATFORM)/mac/tkn154/Makefile.include
CFLAGS += -I$(TOSDIR)/lib/mac/tkn154 \
-I$(TOSDIR)/lib/mac/tkn154/dummies \
PFLAGS += -DIEEE154_EXTENDED_ADDRESS=$(IEEE154_EXTENDED_ADDRESS)
endif
+# parses the PLATFORM variable
include $(MAKERULES)
-PLATFORM?=telosb
-include $(PLATFORM_INCLUDE)
+
+# checks whether the target platform is supported by the application;
+# the application Makefile can define PLATFORMS as a whitespace-separated
+# list of supported platforms
+ifneq ($(PLATFORMS),)
+ ifeq ($(strip $(foreach platform,$(PLATFORMS),$(findstring $(platform),$(PLATFORM)))),)
+ $(error The target platform is not supported by this application - supported platforms are: $(PLATFORMS))
+ endif
+endif
+
+include $(TKN154_PLATFORM_INCLUDE)
components CC2420ReceiveC;
CC2420TransmitP.CC2420Receive -> CC2420ReceiveC;
-
- components CC2420PacketC;
- CC2420TransmitP.CC2420Packet -> CC2420PacketC;
- CC2420TransmitP.CC2420PacketBody -> CC2420PacketC;
}
provides interface CC2420Tx;
/* provides interface RadioBackoff;*/
/* provides interface RadioTimeStamping as TimeStamp;*/
- provides interface ReceiveIndicator as EnergyIndicator;
- provides interface ReceiveIndicator as ByteIndicator;
+/* provides interface ReceiveIndicator as EnergyIndicator;*/
+/* provides interface ReceiveIndicator as ByteIndicator;*/
/* uses interface Alarm<T32khz,uint32_t> as BackoffAlarm;*/
uses interface Alarm<T62500hz,uint32_t> as BackoffAlarm;
- uses interface CC2420Packet;
- uses interface CC2420PacketBody;
uses interface GpioCapture as CaptureSFD;
uses interface GeneralIO as CCA;
uses interface GeneralIO as CSN;
}
/***************** Indicator Commands ****************/
- command bool EnergyIndicator.isReceiving() {
- return !(call CCA.get());
- }
-
- command bool ByteIndicator.isReceiving() {
- bool high;
- atomic high = sfdHigh;
- return high;
- }
+/* command bool EnergyIndicator.isReceiving() {*/
+/* return !(call CCA.get());*/
+/* }*/
+/* */
+/* command bool ByteIndicator.isReceiving() {*/
+/* bool high;*/
+/* atomic high = sfdHigh;*/
+/* return high;*/
+/* }*/
/***************** RadioBackoff Commands ****************/
interface DataRequest;
interface Timer<TSymbolIEEE802154> as ResponseTimeout;
- interface Get<bool> as IsTrackingBeacons;
interface Pool<ieee154_txframe_t> as TxFramePool;
interface Pool<ieee154_txcontrol_t> as TxControlPool;
interface MLME_GET;
interface MLME_SYNC;
interface MLME_BEACON_NOTIFY;
interface MLME_SYNC_LOSS;
- interface Get<bool> as IsTrackingBeacons;
+ interface GetNow<bool> as IsTrackingBeacons;
interface GetNow<uint32_t> as CapStart;
interface GetNow<ieee154_reftime_t*> as CapStartRefTime;
interface GetNow<uint32_t> as CapLen;
interface MLME_GET;
interface MLME_SET;
interface FrameUtility;
+ interface Notify<bool> as FindBeacon;
interface IEEE154BeaconFrame as BeaconFrame;
interface Alarm<TSymbolIEEE802154,uint32_t> as TrackAlarm;
interface RadioRx as BeaconRx;
};
norace bool m_tracking = FALSE;
- norace bool m_updatePending = FALSE;
+ bool m_updatePending = FALSE;
uint8_t m_updateLogicalChannel;
bool m_updateTrackBeacon;
bool m_stopTracking = FALSE;
+ bool m_internalRequest = FALSE;
- norace uint8_t m_numBeaconsLost;
+ uint8_t m_numBeaconsLost;
uint8_t m_coordAddress[8];
message_t m_beaconBuffer;
norace message_t *m_beaconBufferPtr = &m_beaconBuffer;
m_stopTracking = FALSE;
m_updateLogicalChannel = logicalChannel;
m_updateTrackBeacon = trackBeacon;
- atomic m_updatePending = TRUE;
+ m_updatePending = TRUE;
+ m_internalRequest = FALSE;
call Debug.log(LEVEL_INFO,SyncP_RESOURCE_REQUEST, 0, 0, 0);
call Token.request();
}
return IEEE154_SUCCESS;
}
+ event void FindBeacon.notify( bool val )
+ {
+ if (!m_tracking && !m_updatePending){
+ // find a single beacon now (treat this like a user request)
+ m_updateLogicalChannel = call MLME_GET.phyCurrentChannel();
+ m_updateTrackBeacon = FALSE;
+ m_updatePending = TRUE;
+ m_internalRequest = TRUE;
+ call Token.request();
+ }
+ }
+
event void Token.granted()
{
bool missed = FALSE;
m_tracking = FALSE;
call Debug.log(LEVEL_IMPORTANT, SyncP_LOST_SYNC,0,0,0);
call Leds.led2Off();
- signal MLME_SYNC_LOSS.indication(
- IEEE154_BEACON_LOSS,
- call MLME_GET.macPANId(),
- call MLME_GET.phyCurrentChannel(),
- call MLME_GET.phyCurrentPage(),
- NULL // security
- );
+ if (m_internalRequest)
+ call TokenToCap.transfer();
+ else
+ signal MLME_SYNC_LOSS.indication(
+ IEEE154_BEACON_LOSS,
+ call MLME_GET.macPANId(),
+ call MLME_GET.phyCurrentChannel(),
+ call MLME_GET.phyCurrentPage(),
+ NULL // security
+ );
} else
call Token.request(); // make another request again (before giving the token up)
call Debug.log(LEVEL_INFO,SyncP_RELEASE_RESOURCE, 0, 0, 0);
}
}
- command bool IsTrackingBeacons.get(){ return m_tracking;}
+ async command bool IsTrackingBeacons.getNow(){ return m_tracking;}
default event message_t* MLME_BEACON_NOTIFY.indication (message_t* frame){return frame;}
interface WriteBeaconField as GtsInfoWrite;
interface WriteBeaconField as PendingAddrWrite;
interface FrameUtility;
- interface Get<bool> as IsTrackingBeacons;
+ interface GetNow<bool> as IsTrackingBeacons;
interface GetNow<uint32_t> as LastBeaconRxTime;
interface GetNow<ieee154_reftime_t*> as LastBeaconRxRefTime;
interface Ieee802154Debug as Debug;
!(IEEE154_SUPPORTED_CHANNELS & ((uint32_t) 1 << logicalChannel)) ||
(superframeOrder > beaconOrder))
status = IEEE154_INVALID_PARAMETER;
- else if (startTime && !call IsTrackingBeacons.get())
+ else if (startTime && !call IsTrackingBeacons.getNow())
status = IEEE154_TRACKING_OFF;
else if (startTime && 0xFF000000)
status = IEEE154_INVALID_PARAMETER;
interface FrameExtracted as FrameExtracted[uint8_t frameType];
interface FrameTxNow as BroadcastTx;
interface Notify<bool> as WasRxEnabled;
+ interface Notify<bool> as FindBeacon;
}
uses
{
interface GetNow<bool> as IsRxBroadcastPending;
interface GetNow<bool> as IsRxEnableActive;
interface Notify<bool> as RxEnableStateChange;
+ interface GetNow<bool> as IsTrackingBeacons;
interface FrameUtility;
interface RadioTx;
interface RadioRx;
norace ieee154_txframe_t *m_bcastFrame;
norace ieee154_txframe_t *m_lastFrame;
norace ieee154_macMaxBE_t m_BE;
+ norace ieee154_macMaxBE_t m_numCCA;
norace ieee154_macMaxCSMABackoffs_t m_allowedBackoffs;
norace ieee154_macMaxBE_t m_macMaxBE;
norace uint16_t m_backoff;
norace bool m_indirectTxPending = FALSE;
norace bool m_broadcastRxPending;
norace ieee154_macMaxFrameTotalWaitTime_t m_macMaxFrameTotalWaitTime;
+ norace bool m_isBeaconEnabledPAN;
uint16_t generateRandomBackoff(uint8_t BE);
void stopAllAlarms();
signalTxBroadcastDone(m_bcastFrame, IEEE154_TRANSACTION_OVERFLOW);
m_currentFrame = m_lastFrame = m_bcastFrame = NULL;
m_macMaxFrameTotalWaitTime = call MLME_GET.macMaxFrameTotalWaitTime();
+ m_isBeaconEnabledPAN = call IsBeaconEnabledPAN.get();
stopAllAlarms();
return SUCCESS;
}
- async event void TokenTransferred.transferred()
+ event void TokenTransferred.transferred()
{
// we got the token, i.e. CAP has just started
uint32_t actualCapLen = call CapLen.getNow();
- if (actualCapLen < IEEE154_RADIO_GUARD_TIME){
+ if (m_isBeaconEnabledPAN && (DEVICE_ROLE && !call IsTrackingBeacons.getNow())){
+ // rare case: we're on a beacon-enabled PAN, not tracking beacons, searched
+ // and didn't find a beacon for aBaseSuperframeDuration*(2n+1) symbols
+ // -> transmit current frame using unslotted CSMA-CA
+ m_numCCA = 1;
+ signal Token.granted();
+ return;
+ }
+ else if (actualCapLen < IEEE154_RADIO_GUARD_TIME){
call Debug.log(LEVEL_IMPORTANT, CapP_TOO_SHORT, superframeDirection, actualCapLen, IEEE154_RADIO_GUARD_TIME);
call TokenToCfp.transfer();
return;
call CapEndAlarm.startAt(call CapStart.getNow(), actualCapLen);
if (call IsBLEActive.getNow())
call BLEAlarm.startAt(call CapStart.getNow(), call BLELen.getNow());
- call Debug.log(LEVEL_IMPORTANT, CapP_SET_CAP_END, call CapStart.getNow(), actualCapLen, call CapStart.getNow()+ actualCapLen);
+ call Debug.log(LEVEL_IMPORTANT, CapP_SET_CAP_END, call CapStart.getNow(),
+ actualCapLen, call CapStart.getNow()+ actualCapLen);
}
updateState();
}
return IEEE154_TRANSACTION_OVERFLOW;
else {
setCurrentFrame(frame);
- updateState();
+ if (!m_isBeaconEnabledPAN){
+ call Token.request(); // prepare for unslotted CSMA-CA
+ } else {
+ // a beacon must be found before transmitting in a beacon-enabled PAN
+ if (DEVICE_ROLE && !call IsTrackingBeacons.getNow()){
+ signal FindBeacon.notify(TRUE);
+ // we'll receive the Token at latest after aBaseSuperframeDuration*(2n+1) symbols;
+ // if the beacon was not found, then we'll send the frame using unslotted CSMA-CA
+ }
+ updateState();
+ }
return IEEE154_SUCCESS;
}
}
m_BE = call MLME_GET.macMinBE();
if (call MLME_GET.macBattLifeExt() && m_BE > 2)
m_BE = 2;
+ if (m_isBeaconEnabledPAN)
+ m_numCCA = 2;
+ else
+ m_numCCA = 1;
m_transactionTime = IEEE154_SHR_DURATION +
(frame->headerLen + frame->payloadLen) * IEEE154_SYMBOLS_PER_OCTET;
if (frame->header->mhr[0] & FC1_ACK_REQUEST)
return;
m_lock = TRUE; // lock
- // Check 1: has the CAP finished?
- if (call TimeCalc.hasExpired(call CapStart.getNow(), call CapLen.getNow()-IEEE154_RADIO_GUARD_TIME) ||
- !call CapEndAlarm.isRunning()){
+ // Check 1: for beacon-enabled PANs, has the CAP finished?
+ if (m_isBeaconEnabledPAN
+ && (COORD_ROLE || call IsTrackingBeacons.getNow()) // FALSE only if device could't find a beacon
+ && (call TimeCalc.hasExpired(call CapStart.getNow(), call CapLen.getNow()-IEEE154_RADIO_GUARD_TIME) ||
+ !call CapEndAlarm.isRunning())){
if (call RadioOff.isOff()) {
stopAllAlarms(); // may still fire, locked through isOwner()
if (DEVICE_ROLE && m_indirectTxPending)
// Check 8: just make sure the radio is switched off
else {
next = trySwitchOff();
+ if (next == DO_NOTHING && (!m_isBeaconEnabledPAN || (DEVICE_ROLE && !call IsTrackingBeacons.getNow()))){
+ // nothing more to do... just release the Token
+ m_lock = FALSE; // unlock
+ call TokenToCfp.transfer();
+ return;
+
+ }
}
// if there is nothing to do, then we must clear the lock
// in other module variables (m_backoff, etc.)
next_state_t next;
if (call RadioTx.getLoadedFrame() == m_currentFrame){
- // the frame is already loaded -> transmit it now (if there's enough time)
- uint32_t capLen = call CapLen.getNow(), capStart = call CapStart.getNow();
- uint32_t elapsed, totalTime;
- totalTime = IEEE154_RADIO_TX_SEND_DELAY +
- m_backoff - m_backoffElapsed + m_transactionTime + IEEE154_RADIO_GUARD_TIME;
- if (totalTime > capLen)
- totalTime = capLen; // CAP is too short
- elapsed = call TimeCalc.timeElapsed(capStart, call CapEndAlarm.getNow());
- elapsed += (20 - (elapsed % 20)); // round to backoff boundary
- if (!call TimeCalc.hasExpired(capStart, capLen - totalTime)){
- call RadioTx.transmit(call CapStartRefTime.getNow(),
- elapsed + IEEE154_RADIO_TX_SEND_DELAY + m_backoff - m_backoffElapsed,
- 2,
- m_currentFrame->header->mhr[0] & FC1_ACK_REQUEST ? TRUE : FALSE);
- next = WAIT_FOR_TXDONE; // ATTENTION: this will NOT clear the lock
+ // the frame is already loaded -> transmit it now
+ if (m_numCCA == 1){
+ // unslotted CSMA-CA
+ call RadioTx.transmit(NULL, m_backoff, m_numCCA, m_currentFrame->header->mhr[0] & FC1_ACK_REQUEST ? TRUE : FALSE);
+ next = WAIT_FOR_TXDONE; // this will NOT clear the lock
} else {
- // frame does not fit in remaing portion of the CAP
- if (elapsed < call CapLen.getNow()){
- m_backoffElapsed += call CapLen.getNow() - elapsed;
- if (m_backoffElapsed > m_backoff)
- m_backoffElapsed = m_backoff;
+ // slotted CSMA-CA
+ uint32_t capLen = call CapLen.getNow(), capStart = call CapStart.getNow();
+ uint32_t elapsed, totalTime;
+ totalTime = IEEE154_RADIO_TX_SEND_DELAY +
+ m_backoff - m_backoffElapsed + m_transactionTime + IEEE154_RADIO_GUARD_TIME;
+ if (totalTime > capLen)
+ totalTime = capLen; // CAP is too short
+ elapsed = call TimeCalc.timeElapsed(capStart, call CapEndAlarm.getNow());
+ elapsed += (20 - (elapsed % 20)); // round to backoff boundary
+ if (!call TimeCalc.hasExpired(capStart, capLen - totalTime)){
+ call RadioTx.transmit(call CapStartRefTime.getNow(),
+ elapsed + IEEE154_RADIO_TX_SEND_DELAY + m_backoff - m_backoffElapsed,
+ m_numCCA,
+ m_currentFrame->header->mhr[0] & FC1_ACK_REQUEST ? TRUE : FALSE);
+ next = WAIT_FOR_TXDONE; // this will NOT clear the lock
+ } else {
+ // frame does not fit in remaing portion of the CAP
+ if (elapsed < call CapLen.getNow()){
+ m_backoffElapsed += call CapLen.getNow() - elapsed;
+ if (m_backoffElapsed > m_backoff)
+ m_backoffElapsed = m_backoff;
+ }
+ next = SWITCH_OFF;
}
- next = SWITCH_OFF;
}
} else {
// the frame to transmit has not yet been loaded -> load it now
signal WasRxEnabled.notify(TRUE);
}
- async event void TokenRequested.requested() {}
+ bool isUnslottedCSMA_CA()
+ {
+ return (m_numCCA == 1);
+ }
+
+ event void Token.granted()
+ {
+ // the current frame should be transmitted using unslotted CSMA-CA
+ updateState();
+ }
+
+ task void tokenRequestedTask()
+ {
+ signal TokenRequested.requested();
+ }
+
+ async event void TokenRequested.requested()
+ {
+ atomic {
+ if (call Token.isOwner()){
+ if (!m_lock && !(DEVICE_ROLE && m_indirectTxPending) && !(COORD_ROLE && m_bcastFrame))
+ call Token.release();
+ else
+ post tokenRequestedTask();
+ }
+ }
+ }
+
async event void TokenRequested.immediateRequested() {}
- event void Token.granted(){}
default event void CapTx.transmitDone(ieee154_txframe_t *data, ieee154_status_t status){}
default event message_t* FrameRx.received[uint8_t client](message_t* data){return data;}
command error_t WasRxEnabled.enable(){return FAIL;}
command error_t WasRxEnabled.disable(){return FAIL;}
+ command error_t FindBeacon.enable(){return FAIL;}
+ command error_t FindBeacon.disable(){return FAIL;}
}
return (m_realignmentFrame != NULL || m_queueHead != NULL);
}
- async event void TokenTransferred.transferred()
+ event void TokenTransferred.transferred()
{
// CAP has started - are there any broadcast frames to be transmitted?
if (call BeaconFramePendingBit.getNow()){
return IEEE154_INVALID_PARAMETER;
if (call PromiscuousModeGet.get())
return IEEE154_TRANSACTION_OVERFLOW; // must first cancel promiscuous mode!
-
- // nonbeacon-enabled mode is not yet implemented!
- if (PANType != BEACON_ENABLED_PAN)
- return IEEE154_INVALID_PARAMETER;
-
m_setDefaultPIB = SetDefaultPIB;
- m_panType = PANType; // TODO: set this later?
+ m_panType = PANType;
if (!call Token.isOwner())
call Token.request();
return IEEE154_SUCCESS;
This directory contains "TKN15.4", a platform-independent IEEE 802.15.4-2006
-MAC implementation. The code is still under active development, but most of the
-functionality described in the standard is implemented. The MAC itself is
-platform-independent, but it requires (1) a suitable radio driver, (2)
-Alarms/Timers with symbol precision and (3) some "platform glue" code (defining
-guard times, etc.). Currently the only supported platform is TelosB (however:
-without additional hardware support the timing is not standard compliant).
+MAC implementation. The code is in alpha state, under active development, but
+most of the functionality described in the standard is implemented (and
+cursorily tested). The MAC itself is platform-independent, but it requires
+(1) a suitable radio driver, (2) Alarms/Timers with symbol precision and (3)
+some "platform glue" code (defining guard times, etc.). Currently the only
+supported platform is TelosB (however: without additional hardware support on
+TelosB the timing in beacon-enabled mode is not standard compliant).
Status 6/16/08
--------------
missing functionality:
-
- security (not planned)
- GTS (not planned)
-- non-beacon-enabled mode
- PAN ID conflict resolution
- multiple indirect transmissions to the same destination
-- documentation
+
+missing documentation:
+- overview on the architecture of TKN15.4
+- porting TKN15.4 to a new platform
+- ...
Implementation
--------------
interface Timer<TSymbolIEEE802154> as RxEnableTimer;
interface Get<bool> as IsBeaconEnabledPAN;
interface Get<ieee154_macPanCoordinator_t> as IsMacPanCoordinator;
- interface Get<bool> as IsTrackingBeacons;
+ interface GetNow<bool> as IsTrackingBeacons;
interface GetNow<uint32_t> as IncomingSfStart;
interface GetNow<uint32_t> as IncomingBeaconInterval;
interface Get<bool> as IsSendingBeacons;
// for OUTGOING SUPERFRAME
lastBeaconTime = call OutgoingSfStart.getNow();
beaconInterval = call OutgoingBeaconInterval.getNow();
- } else if (call IsTrackingBeacons.get()){
+ } else if (call IsTrackingBeacons.getNow()){
// for INCOMING SUPERFRAME
lastBeaconTime = call IncomingSfStart.getNow();
beaconInterval = call IncomingBeaconInterval.getNow();
BeaconSynchronizeP.MLME_GET -> PibP;
BeaconSynchronizeP.TrackAlarm = Alarm2;
BeaconSynchronizeP.FrameUtility -> PibP;
+ BeaconSynchronizeP.FindBeacon -> DeviceCap.FindBeacon;
+ BeaconSynchronizeP.FindBeacon -> CoordCap.FindBeacon;
BeaconSynchronizeP.Frame -> PibP;
BeaconSynchronizeP.BeaconFrame -> PibP;
BeaconSynchronizeP.BeaconRx -> SyncRadioClient;
CoordCap.FrameRx[FC1_FRAMETYPE_CMD + CMD_FRAME_DISASSOCIATION_NOTIFICATION];
AssociateP.DataRequest -> PollP.DataRequest[ASSOCIATE_CLIENT];
AssociateP.ResponseTimeout = Timer3;
- AssociateP.IsTrackingBeacons -> BeaconSynchronizeP.IsTrackingBeacons;
AssociateP.TxFramePool -> TxFramePoolP;
AssociateP.TxControlPool -> TxControlPoolP;
AssociateP.MLME_GET -> PibP;
DeviceCap.IsRxBroadcastPending -> BeaconSynchronizeP.IsRxBroadcastPending;
DeviceCap.IsRxEnableActive -> RxEnableP.IsRxEnableActive;
DeviceCap.RxEnableStateChange -> RxEnableP.RxEnableStateChange;
+ DeviceCap.IsTrackingBeacons -> BeaconSynchronizeP.IsTrackingBeacons;
DeviceCap.FrameUtility -> PibP;
DeviceCap.RadioTx -> DeviceCapRadioClient;
DeviceCap.RadioRx -> DeviceCapRadioClient;
CoordCap.BLELen -> BeaconTransmitP.BLELen;
CoordCap.IsRxEnableActive -> RxEnableP.IsRxEnableActive;
CoordCap.RxEnableStateChange -> RxEnableP.RxEnableStateChange;
+ CoordCap.IsTrackingBeacons -> BeaconSynchronizeP.IsTrackingBeacons;
CoordCap.FrameUtility -> PibP;
CoordCap.RadioTx -> CoordCapRadioClient;
CoordCap.RadioRx -> CoordCapRadioClient;
RxEnableP.TimeCalc -> PibP.TimeCalc;
RxEnableP.RadioOff -> RxEnableRadioClient;
RxEnableP.RadioPromiscuousMode = RadioPromiscuousMode;
- RxEnableP.WasRxEnabled -> DeviceCap;
- RxEnableP.WasRxEnabled -> CoordCap;
+ RxEnableP.WasRxEnabled -> DeviceCap.WasRxEnabled;
+ RxEnableP.WasRxEnabled -> CoordCap.WasRxEnabled;
RxEnableP.RxEnableTimer = Timer5;
RxEnableP.Debug = Ieee802154Debug[RXENABLE_CLIENT];
async command uint8_t TransferredFrom.getUserId(){ return myUserId;}
- async command void TransferredFrom.transfer()
+ task void TransferredTask()
{
signal ResourceTransferred.transferred();
}
- async command error_t ResourceTransferred.release()
+ async command void TransferredFrom.transfer()
{
- return call ResourceTransferControl.release(myUserId);
+ post TransferredTask();
}
default async command uint8_t TransferTo.getUserId(){ call Leds.led0On(); return 0xFF;}
default async command void TransferTo.transfer(){ call Leds.led0On(); }
+ default event void ResourceTransferred.transferred(){}
}