* $Revision$
* $Date$
* @author Jan Hauer <hauer@tkn.tu-berlin.de>
+ * @author: Jasper Buesch <buesch@tkn.tu-berlin.de>
* ========================================================================
*/
interface FrameTx[uint8_t client];
interface WriteBeaconField as PendingAddrWrite;
interface Notify<bool> as PendingAddrSpecUpdated;
+ interface Get<ieee154_txframe_t*> as GetIndirectTxFrame;
interface Purge;
}
uses
interface FrameTx as CoordCapTx;
interface FrameRx as DataRequestRx;
interface MLME_GET;
- interface FrameUtility;
+ interface IEEE154Frame;
interface Timer<TSymbolIEEE802154> as IndirectTxTimeout;
interface TimeCalc;
interface Leds;
- interface Ieee802154Debug as Debug;
}
}
implementation
uint8_t m_numTableEntries;
uint8_t m_numShortPending;
uint8_t m_numExtPending;
+ ieee154_txframe_t m_emptyDataFrame;
+ ieee154_metadata_t m_emptyDataFrameMetadata;
+ ieee154_header_t m_emptyDataFrameHeader;
+
task void tryCoordCapTxTask();
void tryCoordCapTx();
+ void transmitEmptyDataFrame(message_t* dataRequestFrame);
command error_t Reset.init()
{
m_numTableEntries = 0;
m_numShortPending = 0;
m_numExtPending = 0;
+
+ m_emptyDataFrame.header = &m_emptyDataFrameHeader;
+ m_emptyDataFrame.metadata = &m_emptyDataFrameMetadata;
+ m_emptyDataFrame.payload = &m_numExtPending; // dummy (payloadLen is always 0)
+ m_emptyDataFrame.payloadLen = 0;
+ m_emptyDataFrame.client = 0; // unlock
return SUCCESS;
}
- uint32_t getPersistenceTime()
+ uint32_t getPersistenceTimeSymbols()
{
- uint32_t persistenceTime;
- persistenceTime = call MLME_GET.macTransactionPersistenceTime();
- persistenceTime *= IEEE154_aBaseSuperframeDuration;
- persistenceTime *= ((uint16_t) 1) << call MLME_GET.macBeaconOrder();
- return persistenceTime;
+ // transform macTransactionPersistenceTime PIB attribute
+ // from "unit periods" to symbols (cf. page 166)
+ uint32_t unitPeriod;
+ ieee154_macBeaconOrder_t BO = call MLME_GET.macBeaconOrder();
+
+ if (BO <= 14) {
+ unitPeriod = IEEE154_aBaseSuperframeDuration;
+ unitPeriod *= ((uint16_t) 1) << BO;
+ } else
+ unitPeriod = IEEE154_aBaseSuperframeDuration;
+ return unitPeriod * call MLME_GET.macTransactionPersistenceTime();
}
command ieee154_status_t Purge.purge(uint8_t msduHandle)
{
- return IEEE154_INVALID_HANDLE; // TODO
+ uint8_t i = 0;
+ for (i=0; i<NUM_MAX_PENDING; i++) {
+ if ((m_txFrameTable[i]->handle == msduHandle) && (m_client != m_txFrameTable[i]->client) ){
+ ieee154_txframe_t *purgedFrame;
+ purgedFrame = m_txFrameTable[i];
+ m_txFrameTable[i] = NULL;
+ m_numTableEntries -= 1;
+ signal Purge.purgeDone(purgedFrame, IEEE154_PURGED);
+ return IEEE154_SUCCESS;
+ }
+ }
+ return IEEE154_INVALID_HANDLE;
}
command uint8_t PendingAddrWrite.write(uint8_t *pendingAddrField, uint8_t maxlen)
{
- // write the pending addr field (inside the beacon frame)
+ // writes the pending addr field (inside the beacon frame)
uint8_t i, j, k=0;
uint8_t *longAdrPtr[NUM_MAX_PENDING];
nxle_uint16_t *adrPtr;
return 0;
pendingAddrField[0] = 0;
adrPtr = (nxle_uint16_t *) &pendingAddrField[1];
- for (i=0; i<NUM_MAX_PENDING; i++){
+ for (i=0; i<NUM_MAX_PENDING; i++) {
if (!m_txFrameTable[i])
continue;
txFrame = m_txFrameTable[i];
- if ((txFrame->header->mhr[MHR_INDEX_FC2] & FC2_DEST_MODE_MASK) == FC2_DEST_MODE_SHORT){
+ if ((txFrame->header->mhr[MHR_INDEX_FC2] & FC2_DEST_MODE_MASK) == FC2_DEST_MODE_SHORT) {
*adrPtr++ = *((nxle_uint16_t*) &txFrame->header->mhr[MHR_INDEX_ADDRESS + sizeof(ieee154_macPANId_t)]);
} else if ((txFrame->header->mhr[MHR_INDEX_FC2] & FC2_DEST_MODE_MASK) == FC2_DEST_MODE_EXTENDED)
longAdrPtr[k++] = &(txFrame->header->mhr[MHR_INDEX_ADDRESS + sizeof(ieee154_macPANId_t)]);
for (j=0; j<8; j++)
pendingAddrField[1 + 2*m_numShortPending + i*8 + j] = longAdrPtr[i][j];
pendingAddrField[0] = m_numShortPending | (m_numExtPending << 4);
- call Debug.log(LEVEL_INFO, IndirectTxP_BEACON_ASSEMBLY, len,0,0);
return len;
}
command ieee154_status_t FrameTx.transmit[uint8_t client](ieee154_txframe_t *txFrame)
{
- // send a frame through indirect transmission
+ // sends a frame using indirect transmission
uint8_t i;
- if (m_numTableEntries >= NUM_MAX_PENDING){
- call Debug.log(LEVEL_IMPORTANT, IndirectTxP_OVERFLOW, 0,0,0);
+ if (m_numTableEntries >= NUM_MAX_PENDING) {
+ dbg_serial("IndirectTxP", "Overflow\n");
return IEEE154_TRANSACTION_OVERFLOW;
}
txFrame->client = client;
else if ((txFrame->header->mhr[MHR_INDEX_FC2] & FC2_DEST_MODE_MASK) == FC2_DEST_MODE_EXTENDED)
m_numExtPending++;
if (!call IndirectTxTimeout.isRunning())
- call IndirectTxTimeout.startOneShot(getPersistenceTime());
- call Debug.log(LEVEL_INFO, IndirectTxP_NOTIFIED, 0,0,0);
+ call IndirectTxTimeout.startOneShot(getPersistenceTimeSymbols());
+ dbg_serial("IndirectTxP", "Preparing a transmission.\n");
signal PendingAddrSpecUpdated.notify(TRUE);
return IEEE154_SUCCESS;
}
{
uint8_t i, j, srcAddressMode, dstAddressMode, *src;
uint8_t *mhr = MHR(frame);
- uint8_t destMode = (mhr[1] & FC2_DEST_MODE_MASK);
+ uint8_t destMode = (mhr[MHR_INDEX_FC2] & FC2_DEST_MODE_MASK);
+ ieee154_txframe_t *dataResponseFrame = NULL;
// received a data request frame from a device
// have we got some pending data for it ?
- if (!m_numTableEntries)
- return frame;
- srcAddressMode = (mhr[1] & FC2_SRC_MODE_MASK);
+ srcAddressMode = (mhr[MHR_INDEX_FC2] & FC2_SRC_MODE_MASK);
if (!(srcAddressMode & FC2_SRC_MODE_SHORT))
return frame; // no source address
src = mhr + MHR_INDEX_ADDRESS;
src += 4;
else if (destMode == FC2_DEST_MODE_EXTENDED)
src += 10;
- if (!((mhr[0] & FC1_PAN_ID_COMPRESSION) && (mhr[1] & FC2_DEST_MODE_SHORT)))
+ if (!((mhr[MHR_INDEX_FC1] & FC1_PAN_ID_COMPRESSION) && (mhr[MHR_INDEX_FC2] & FC2_DEST_MODE_SHORT)))
src += 2;
- for (i=0; i<NUM_MAX_PENDING; i++){
- if (!m_txFrameTable[i])
+ for (i=0; i<NUM_MAX_PENDING; i++) {
+ if (m_txFrameTable[i] == NULL)
continue;
else {
- dstAddressMode = (m_txFrameTable[i]->header->mhr[1] & FC2_DEST_MODE_MASK);
+ dstAddressMode = (m_txFrameTable[i]->header->mhr[MHR_INDEX_FC2] & FC2_DEST_MODE_MASK);
if ((dstAddressMode << 4) != srcAddressMode)
continue;
else {
uint8_t *dst = &(m_txFrameTable[i]->header->mhr[MHR_INDEX_ADDRESS]) + 2;
uint8_t len = ((srcAddressMode == FC2_SRC_MODE_SHORT) ? 2 : 8);
for (j=0; j<len; j++)
- if (*dst != *src)
- break;
- if (j==len)
- break; // match! break from outer loop
+ if (dst[j] != src[j])
+ break; // no match!
+ if (j==len) { // match!
+ if (dataResponseFrame == NULL)
+ dataResponseFrame = m_txFrameTable[i];
+ else // got even more than one frame for this device: set pending flag
+ dataResponseFrame->header->mhr[MHR_INDEX_FC1] |= FC1_FRAME_PENDING;
+ }
}
}
}
- call Debug.log(LEVEL_INFO, IndirectTxP_REQUESTED, NUM_MAX_PENDING-i,i,*src);
- if (i != NUM_MAX_PENDING){
+ if (dataResponseFrame != NULL) {
// found a matching frame, mark it for transmission
- m_txFrameTable[i]->client |= SEND_THIS_FRAME;
+ dbg_serial("IndirectTxP", "We have data for this device, trying to transmit...\n");
+ dataResponseFrame->client |= SEND_THIS_FRAME;
post tryCoordCapTxTask();
} else {
- // TODO: send an empty data frame to the device
+ dbg_serial("IndirectTxP", "We don't have data for this device, sending an empty frame...\n");
+ transmitEmptyDataFrame(frame);
}
return frame;
}
+ void transmitEmptyDataFrame(message_t* dataRequestFrame)
+ {
+ // the cast in the next line is dangerous -> this is only a temporary workaround!
+ // (until the new T2 message buffer abstraction is available)
+ message_t *emptyDataMsg = (message_t *) m_emptyDataFrame.header;
+ ieee154_address_t dstAddr;
+ uint16_t dstPanID;
+
+ if (m_emptyDataFrame.client != 0)
+ return; // locked (already transmitting an empty data frame)
+ if (call IEEE154Frame.getSrcAddr(dataRequestFrame, &dstAddr) != IEEE154_SUCCESS ||
+ call IEEE154Frame.getSrcPANId(dataRequestFrame, &dstPanID) != IEEE154_SUCCESS)
+ return;
+ call IEEE154Frame.setAddressingFields(emptyDataMsg,
+ call IEEE154Frame.getDstAddrMode(dataRequestFrame), // will become srcAddrMode
+ call IEEE154Frame.getSrcAddrMode(dataRequestFrame), // will become dstAddrMode
+ dstPanID,
+ &dstAddr,
+ NULL //security
+ );
+ MHR(&m_emptyDataFrame)[MHR_INDEX_FC1] |= FC1_FRAMETYPE_DATA;
+ m_emptyDataFrame.headerLen = call IEEE154Frame.getHeaderLength(emptyDataMsg);
+ m_emptyDataFrame.client = 1; // lock
+ if (call CoordCapTx.transmit(&m_emptyDataFrame) != IEEE154_SUCCESS)
+ m_emptyDataFrame.client = 0; // unlock
+ }
+
void tryCoordCapTx()
{
// iterate over the queued frames and transmit them in the CAP
// (if they are marked for transmission)
uint8_t i;
- if (!m_pendingTxFrame && m_numTableEntries){
+ if (m_pendingTxFrame == NULL && m_numTableEntries) {
for (i=0; i<NUM_MAX_PENDING; i++)
- if (m_txFrameTable[i] && (m_txFrameTable[i]->client & SEND_THIS_FRAME)){
- // TODO: set frame pending bit, if there's more data for this destination
+ if (m_txFrameTable[i] && (m_txFrameTable[i]->client & SEND_THIS_FRAME)) {
m_pendingTxFrame = m_txFrameTable[i];
m_client = m_txFrameTable[i]->client;
- if (call CoordCapTx.transmit(m_txFrameTable[i]) == IEEE154_SUCCESS){
- call Debug.log(LEVEL_INFO, IndirectTxP_SEND_NOW, 0,0,0);
+ if (call CoordCapTx.transmit(m_txFrameTable[i]) == IEEE154_SUCCESS) {
+ dbg_serial("IndirectTxP", "Started a transmission.\n");
} else {
- m_pendingTxFrame = 0;
+ m_pendingTxFrame = NULL;
post tryCoordCapTxTask();
}
return; // done - wait for txDone
{
// a transaction has expired
uint32_t now = call IndirectTxTimeout.getNow(), dt=0;
- uint32_t persistenceTime = getPersistenceTime();
+ uint32_t persistenceTime = getPersistenceTimeSymbols();
uint8_t i;
for (i=0; i<NUM_MAX_PENDING; i++)
- if (m_txFrameTable[i] && m_txFrameTable[i] != m_pendingTxFrame){
- if (call TimeCalc.hasExpired(m_txFrameTable[i]->metadata->timestamp, persistenceTime)){
+ if (m_txFrameTable[i] && m_txFrameTable[i] != m_pendingTxFrame) {
+ if (call TimeCalc.hasExpired(m_txFrameTable[i]->metadata->timestamp, persistenceTime)) {
ieee154_txframe_t *txFrame = m_txFrameTable[i];
txFrame->client &= ~SEND_THIS_FRAME;
m_txFrameTable[i] = NULL;
m_numExtPending--;
signal FrameTx.transmitDone[txFrame->client](txFrame, IEEE154_TRANSACTION_EXPIRED);
signal PendingAddrSpecUpdated.notify(TRUE);
- } else if (call TimeCalc.timeElapsed(m_txFrameTable[i]->metadata->timestamp, now) > dt){
+ } else if (call TimeCalc.timeElapsed(m_txFrameTable[i]->metadata->timestamp, now) > dt) {
dt = call TimeCalc.timeElapsed(m_txFrameTable[i]->metadata->timestamp, now);
}
}
- if (dt != 0){
+ if (dt != 0) {
if (dt > persistenceTime)
dt = persistenceTime;
call IndirectTxTimeout.startOneShot(persistenceTime - dt);
event void CoordCapTx.transmitDone(ieee154_txframe_t *txFrame, ieee154_status_t status)
{
uint8_t i;
- // TODO: if CSMA-CA algorithm failed, then frame shall remain in transaction queue
+ // TODO: if CSMA-CA algorithm failed, then frame shall still remain in transaction queue
+ dbg_serial("IndirectTxP", "transmitDone(), status: %lu\n", (uint32_t) status);
+
+ if (txFrame == &m_emptyDataFrame) {
+ m_emptyDataFrame.client = 0; // unlock
+ return;
+ }
for (i=0; i<NUM_MAX_PENDING; i++)
- if (m_txFrameTable[i] == txFrame){
+ if (m_txFrameTable[i] == txFrame) {
m_txFrameTable[i] = NULL; // slot is now empty
break;
}
m_numExtPending--;
signal FrameTx.transmitDone[txFrame->client](txFrame, status);
post tryCoordCapTxTask();
- call Debug.log(LEVEL_INFO, IndirectTxP_SEND_DONE, status,m_numTableEntries,0);
}
- command error_t PendingAddrSpecUpdated.enable(){return FAIL;}
- command error_t PendingAddrSpecUpdated.disable(){return FAIL;}
- default event void FrameTx.transmitDone[uint8_t client](ieee154_txframe_t *txFrame, ieee154_status_t status){}
+ command ieee154_txframe_t* GetIndirectTxFrame.get() { return m_pendingTxFrame;}
+ command error_t PendingAddrSpecUpdated.enable() {return FAIL;}
+ command error_t PendingAddrSpecUpdated.disable() {return FAIL;}
+ default event void PendingAddrSpecUpdated.notify( bool val ) {return;}
+ default event void FrameTx.transmitDone[uint8_t client](ieee154_txframe_t *txFrame, ieee154_status_t status) {}
}