📄 mac_tx_engine.c
字号:
//
// DESCRIPTION:
// Schedules the active packet for transmission ASAP. This function is only used in a beacon
// network. If the packet cannot be transmitted, a flag is set to indicate that the transmission
// should continue after the next receive beacon, or after the "locate beacon" timeout.
//-------------------------------------------------------------------------------------------------------
BYTE mtxSetStartupTime(void) {
INT32 bosLeft;
UINT8 randomBackoff;
MAC_TX_PACKET *pPacket = mtxInfo.pPacket;
#if MAC_OPT_FFD
// If this is an indirect packet, then make sure that it still is requested!
if ((pPacket->txOptions & TX_OPT_INDIRECT) && !pPacket->requested) return MTX_SST_INDIRECT_PACKET_TOO_LATE;
#endif
// Calculate the random backoff period
if (pPacket->txMode & MTX_MODE_USE_CSMACA_BM) {
randomBackoff = msupGetRandomByte() & (BM(mtxInfo.be) - 1);
} else {
randomBackoff = 0;
}
// Calculate the number of FULL backoff slots left in the CAP (including the two/three periods required to prepare for transmission
if (mpib.macSuperframeOrder == 15) {
bosLeft = 0;
} else if (mbcnInfo.lastSfSpec.battLifeExt && pPacket->toCoord) {
// <----------------- The CAP duration -----------------> <------- Used CAP ------> < Delay + overhead + duration >
bosLeft = (mbcnInfo.beaconDuration + mpib.macBattLifeExtPeriods) - (mtimInfo.bosCounter + 1) - (randomBackoff + 2 + 1) - 5;
} else {
// <- The CAP duration > <------- Used CAP ------> <-------- Delay + overhead + duration --------> <-- Beacon margin -->
bosLeft = msupCalcCapDuration() - (mtimInfo.bosCounter + 1) - (randomBackoff + 2 + mtxInfo.pPacket->duration) - mbcnGetBeaconMargin() - 5;
}
// Subtract an extra backoff period if slotted CSMA-CA is used (2 CCA checks instead of 1)
if (pPacket->slotted) bosLeft--;
// Default values...
mtxInfo.searchForBeacon = FALSE;
mtxInfo.waitForBeacon = FALSE;
// Is there enough time to transmit in this CAP (are we really in the CAP)?
if (bosLeft > 0) {
if (!mtxStartAfterDelay(randomBackoff)) return MTX_SST_RESOURCE_SHORTAGE;
} else {
// CSMA-CA should not be resumed in the next superframe for indirect packets!
if (pPacket->txOptions & TX_OPT_INDIRECT) {
return MTX_SST_INDIRECT_PACKET_TOO_LATE;
// For direct packets: Wait for the beacon, and search for it if beacon tracking is not enabled
} else {
if (!mtimSetCallback(mtxLocateBeaconTimeout, msupCalcBeaconInterval())) return MTX_SST_RESOURCE_SHORTAGE;
mtxInfo.waitForBeacon = TRUE;
mtxInfo.randomBackoff = randomBackoff;
// If beacons are not being tracked, then try to locate one before transmitting
// Note: If beacon tracking is stopped, but searchForBeacon = TRUE, then RX must not be turned off!
if (!(mbcnInfo.trackBeacon || GET_MF(MF_TRANSMIT_BEACON))) {
mrxIncrOnCounter();
mtxInfo.searchForBeacon = TRUE;
}
}
}
return MTX_SST_SUCCESS;
} // csmaSetStartupTime
//-------------------------------------------------------------------------------------------------------
// void mtxResumeAfterBeacon(void)
//
// DESCRIPTION:
// Resumes transmission after the beacon has been received, if there is a sufficient number of
// backoff slot left in the CAP.
//-------------------------------------------------------------------------------------------------------
void mtxResumeAfterBeaconCallback(void) {
//MAC_TX_PACKET *pPacket = mbcnInfo.pTxPacket;
//MAC_TX_PACKET *pPacket = mtxInfo.pPacket;
mtimInfo.bosCounter = mbcnInfo.beaconDuration + 2;
mschAddTask(mschReserveTask(), MAC_TASK_PRI_MEDIUM, mtxResumeAfterBeaconTask, 0);
}
void mtxResumeAfterBeaconTask(MAC_TASK_INFO *pTask) { mtxResumeAfterBeacon(); mschRemoveTask(pTask->priority, MSCH_KEEP_TASK_IN_PROGRESS_BM); }
void mtxResumeAfterBeacon(void) {
INT32 capLeft;
INT32 capRequired;
if (mtxInfo.waitForBeacon) {
// Cancel the beacon location timeout
mtimCancelCallback(mtxLocateBeaconTimeout);
// Calculate the CAP duration (number of backoff slots)
if (mbcnInfo.lastSfSpec.battLifeExt) {
// <----------------- The CAP duration -----------------> <------ Used CAP ------->
capLeft = (mbcnInfo.beaconDuration + mpib.macBattLifeExtPeriods) - (mtimInfo.bosCounter + 1);
capRequired = mtxInfo.randomBackoff + 2 + 1 + !!mtxInfo.pPacket->slotted;
} else {
// <- The CAP duration > <------ Used CAP -------> <-- Beacon margin -->
capLeft = msupCalcCapDuration() - (mtimInfo.bosCounter + 1) - mbcnGetBeaconMargin();
capRequired = mtxInfo.randomBackoff + 2 + mtxInfo.pPacket->duration + !!mtxInfo.pPacket->slotted;
}
// Enough time left in the CAP to transmit now?
if (capLeft >= capRequired) {
if (mtxInfo.searchForBeacon) {
mtxInfo.searchForBeacon = FALSE;
mrxDecrOnCounter();
}
mtxInfo.waitForBeacon = FALSE;
mtxStartAfterDelay(msupGetRandomByte() & (BM(mtxInfo.be) - 1));
//mtxCreateStartTask();
// Or do we have to wait for another beacon?
} else {
// Subtract the number of backoff periods left in the CAP (we cannot subtract mpib.macBattLifeExtPeriods
// and transmit when mtxInfo.randomBackoff became zero or negative!)
if (capLeft > 0) {
mtxInfo.randomBackoff = MAX(0, mtxInfo.randomBackoff - capLeft);
}
}
}
} // mtxResumeAfterBeacon
//-------------------------------------------------------------------------------------------------------
// void mtxPacketTimeout(void)
//
// DESCRIPTION:
// Transmission timeout:
// Ack.req = TRUE:
//-------------------------------------------------------------------------------------------------------
void mtxPacketTimeout(void) {
// Turn off RX (turned on by mtxStartTransmission(...))
mrxDecrOnCounter();
// For packets transmitted using mtxScheduleTransmission(...)
if (mtxInfo.status == MTX_STATUS_TRANSMISSION_STARTED) {
if (mtxInfo.pPacket->txOptions & TX_OPT_ACK_REQ) {
mtxInfo.status = MTX_STATUS_ACK_TIMEOUT;
} else {
mtxInfo.status = MTX_STATUS_TX_FINISHED;
}
}
} // mtxPacketTimeout
//-------------------------------------------------------------------------------------------------------
// void mtxScheduleTransmission(MAC_TASK_INFO *pTask)
//
// DESCRIPTION:
// This task is created to start a transmission. The task is responsible for setting up the CSMA-CA
// mechanism, scheduling the transmission, and handle the result when the packet timeout is trigged.
// Note: Periodically transmitted beacons bypass this task and uses mtxStartTransmission directly.
//-------------------------------------------------------------------------------------------------------
void mtxScheduleTransmission(MAC_TASK_INFO *pTask) {
MAC_TX_PACKET *pPacket = (MAC_TX_PACKET*) pTask->taskData;
MAC_TX_PACKET *indirectpPacket;
switch (pTask->state) {
case MTX_STATE_INIT_TRANSMISSION:
ENABLE_FIFOP_INT();
// Reschedule this task if we're in scan mode and the "scan related" flag is not set on this packet
if ((macInfo.state & MAC_STATE_SCAN_BM) && !(pPacket->txMode & MTX_MODE_SCAN_RELATED_BM)) {
mschRescheduleTask(pTask, MTX_STATE_INIT_TRANSMISSION);
}
// Set the TX engine packet pointer
mtxInfo.pPacket = pPacket;
#if MAC_OPT_FFD
//If data frame and packet in inderect quee set pending frame bit in outgoing frame.
if (( (pPacket->pHeader[0] & FRAME_TYPE_BM)== FT_DATA) && (miqInfo.firstIndirectPacket != NO_PACKET))
{
//Find out if we have any inderect packets to in memmory to this node..
if ((pPacket->pHeader[1] & DEST_ADDR_BM) == DEST_ADDR_EXT)
{
indirectpPacket = miqFindIndirectPacket((ADDRESS *) &pPacket->pHeader[5], TRUE);//(ADDRESS *pDestAddr, BOOL isExtAddr);
}
else
{
indirectpPacket = miqFindIndirectPacket((ADDRESS *) &pPacket->pHeader[5], FALSE);//(ADDRESS *pDestAddr, BOOL isExtAddr);
}
if (indirectpPacket != NULL)
{
pPacket->pHeader[0] |= FRAME_PENDING_BM;
}
}
#endif
// No break here!
case MTX_STATE_INIT_CSMACA:
// Reset CSMA-CA parameters
mtxInfo.nb = 0;
mtxInfo.be = mpib.macMinBE;
pPacket->slotted = !((mpib.macBeaconOrder == 15) || (pPacket->txMode & MTX_MODE_FORCE_UNSLOTTED_BM));
if (pPacket->slotted && mpib.macBattLifeExt) {
mtxInfo.be = MIN(2, mtxInfo.be);
}
pTask->state = MTX_STATE_SET_STARTUP_TIME;
break;
case MTX_STATE_SET_STARTUP_TIME:
// In a non-beacon network: Start the transmission with or without a random delay (CSMA-CA)
if (!pPacket->slotted) {
if (pPacket->txMode & MTX_MODE_USE_CSMACA_BM) {
mtxStartAfterDelay(msupGetRandomByte() & (BM(mtxInfo.be) - 1));
} else {
mtxCreateStartTask();
}
pTask->state = MTX_STATE_WAIT;
mtxInfo.status = MTX_STATUS_WAITING;
// In a beacon network: Calculate and set the startup time
} else {
switch (mtxSetStartupTime()) {
case MTX_SST_SUCCESS:
// The startup time has been set -> proceed to the next state
pTask->state = MTX_STATE_WAIT;
mtxInfo.status = MTX_STATUS_WAITING;
break;
case MTX_SST_RESOURCE_SHORTAGE:
// Repeat this step if there's a temporary shortage on resources (timers and tasks)
break;
case MTX_SST_INDIRECT_PACKET_TOO_LATE:
#if MAC_OPT_FFD
// We have not even tried to transmit the packet in this superframe -> no changes...
if (!mtxInfo.nb) {
miqSetRequested(pPacket, FALSE);
pPacket->transmissionStarted = FALSE;
mschRemoveTask(pTask->priority, MSCH_KEEP_TASK_IN_PROGRESS_BM);
// We've had at least one channel access failure... (we don't get here because of NO_ACK)
} else {
if (pPacket->retriesLeft) {
pTask->state = MTX_STATE_WAIT;
mtxInfo.status = MTX_STATUS_CHANNEL_ACCESS_FAILURE;
} else {
mtxFinishTransmission(CHANNEL_ACCESS_FAILURE, pPacket, pTask);
}
}
#endif
break;
}
break;
}
break;
case MTX_STATE_WAIT:
ENABLE_FIFOP_INT();
switch (mtxInfo.status) {
case MTX_STATUS_WAITING:
case MTX_STATUS_TRANSMISSION_STARTED:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -