📄 beacontransmitp.nc
字号:
// The realignment frame will be transmitted immediately after
// the next beacon - the result will be signalled in
// RealignmentBeaconEnabledTx.transmitDone(). Only then the superframe
// structure is updated and MLME_START.confirm signalled.
m_requestBitmap |= REQUEST_REALIGNMENT_DONE_PENDING; // lock
}
} else {
// send realignment frame in unslotted csma-ca now
if (call RealignmentNonBeaconEnabledTx.transmit(realignmentFrame) != IEEE154_SUCCESS) {
m_requestBitmap = 0;
call GetSetRealignmentFrame.set(realignmentFrame);
signal MLME_START.confirm(IEEE154_TRANSACTION_OVERFLOW);
} else {
// A realignment frame will be transmitted now, the result will
// be signalled in RealignmentNonBeaconEnabledTx.transmitDone(). Only
// then the superframe structure is updated and MLME_START.confirm
// signalled.
m_requestBitmap |= REQUEST_REALIGNMENT_DONE_PENDING; // lock
}
}
return;
}
// (2) update internal state
m_startTime = m_updateStartTime;
m_txOneBeaconImmediately = FALSE;
m_previousBeaconInterval = 0;
if (m_startTime) {
memcpy(&m_lastBeaconTxRefTime, call IncomingSF.sfStartTimeRef(), sizeof(ieee154_timestamp_t));
m_lastBeaconTxTime = call IncomingSF.sfStartTime();
} else {
// no StartTime defined by next higher layer - but
// if a realignment frame was transmitted, the next
// beacon tx time must take the old BI into consideration
if (m_requestBitmap & REQUEST_REALIGNMENT_DONE_PENDING)
m_previousBeaconInterval = m_beaconInterval;
else
m_txOneBeaconImmediately = TRUE;
}
m_beaconOrder = m_updateBeaconOrder;
m_superframeOrder = m_updateSuperframeOrder;
if (m_beaconOrder < 15) {
m_beaconInterval = ((uint32_t) 1 << m_updateBeaconOrder) * IEEE154_aBaseSuperframeDuration;
} else {
m_beaconInterval = 0;
}
m_dt = m_beaconInterval;
m_txState = S_TX_IDLE;
m_bsn = call MLME_GET.macBSN()+1;
m_battLifeExtPeriods = call MLME_GET.macBattLifeExtPeriods();
// (3) update PIB
call MLME_SET.macBeaconOrder(m_beaconOrder);
call SetMacSuperframeOrder.set(m_superframeOrder);
call MLME_SET.macPANId(m_updatePANId);
call MLME_SET.phyCurrentChannel(m_updateLogicalChannel);
if (m_beaconOrder < 15)
call MLME_SET.macBattLifeExt(m_updateBatteryLifeExtension);
call SetMacPanCoordinator.set(m_updatePANCoordinator);
// (4) assemble beacon header and payload
shortAddress = call MLME_GET.macShortAddress();
isShortAddr = (shortAddress != 0xFFFE);
m_beaconFrame.header->mhr[MHR_INDEX_FC1] = FC1_FRAMETYPE_BEACON;
m_beaconFrame.header->mhr[MHR_INDEX_FC2] = isShortAddr ? FC2_SRC_MODE_SHORT : FC2_SRC_MODE_EXTENDED;
offset = MHR_INDEX_ADDRESS;
*((nxle_uint16_t*) &m_beaconFrame.header->mhr[offset]) = m_updatePANId;
offset += sizeof(ieee154_macPANId_t);
if (isShortAddr) {
*((nxle_uint16_t*) &m_beaconFrame.header->mhr[offset]) = shortAddress;
offset += sizeof(ieee154_macShortAddress_t);
} else {
call FrameUtility.copyLocalExtendedAddressLE(&m_beaconFrame.header->mhr[offset]);
offset += 8;
}
m_beaconFrame.headerLen = offset;
m_payloadState |= MODIFIED_SPECS_MASK; // update beacon payload
signal BeaconPayloadUpdateTimer.fired(); // assemble initial beacon payload
if (m_beaconOrder < 15) {
// beacon-enabled PAN, signal confirm after next
// beacon has been transmitted (see MSC, Fig. 38)
m_requestBitmap = REQUEST_CONFIRM_PENDING;
} else {
// beaconless PAN, we're done
m_requestBitmap = 0;
signal MLME_START.confirm(IEEE154_SUCCESS);
}
}
task void signalGrantedTask()
{
signal RadioToken.granted();
}
event void RadioToken.granted()
{
dbg_serial("BeaconSynchronizeP","Token granted.\n");
if (m_requestBitmap & REQUEST_REALIGNMENT_DONE_PENDING) {
// very unlikely: we have not yet received a done()
// event after sending out a realignment frame
dbg_serial("BeaconTransmitP", "Realignment pending (request: %lu) !\n", (uint32_t) m_requestBitmap);
post signalGrantedTask(); // spin
return;
} else if (m_requestBitmap & REQUEST_UPDATE_SF) {
dbg_serial("BeaconTransmitP","Putting new superframe spec into operation\n");
m_requestBitmap &= ~REQUEST_UPDATE_SF;
continueStartRequest();
}
nextRound();
}
void nextRound()
{
if (call RadioOff.isOff())
prepareBeaconTransmission();
else
ASSERT(call RadioOff.off() == SUCCESS); // will continue in prepareBeaconTransmission()
}
async event void RadioToken.transferredFrom(uint8_t fromClientID)
{
dbg_serial("BeaconSynchronizeP","Token transferred, will Tx beacon in %lu\n",
(uint32_t) ((m_lastBeaconTxTime + m_dt) - call BeaconSendAlarm.getNow()));
if (m_requestBitmap & (REQUEST_REALIGNMENT_DONE_PENDING | REQUEST_UPDATE_SF))
post signalGrantedTask(); // need to be in sync context
else
nextRound();
}
async event void RadioOff.offDone()
{
prepareBeaconTransmission();
}
void prepareBeaconTransmission()
{
if (m_txState == S_TX_LOCKED) {
// have not had time to finish processing the last sent beacon
dbg_serial("BeaconTransmitP", "Token was returned too fast!\n");
post signalGrantedTask();
} else if (m_beaconOrder == 15) {
// we're not sending any beacons!?
dbg_serial("BeaconTransmitP", "Stop sending beacons.\n");
call RadioToken.release();
} else {
// get ready for next beacon transmission
atomic {
uint32_t delay = IEEE154_RADIO_TX_DELAY;
m_txState = S_TX_WAITING;
if (m_txOneBeaconImmediately) {
// transmit the beacon now
dbg_serial("BeaconTransmitP", "Sending a beacon immediately.\n");
signal BeaconSendAlarm.fired();
return;
} else if (m_startTime != 0) {
// a new sf spec was put into operation, with a user-defined StartTime
// here m_lastBeaconTxTime is actually the last time a beacon was received
dbg_serial("BeaconTransmitP", "First beacon to be sent at %lu.\n", m_startTime);
m_dt = m_startTime;
m_startTime = 0;
} else if (m_previousBeaconInterval != 0) {
// a new sf spec was put into operation, after a realignment frame
// broadcast; the next beacon time should still be calculated using the
// old BI (one last time)
dbg_serial("BeaconTransmitP", "Sending beacon after realignment dt=%lu.\n", m_previousBeaconInterval);
m_dt = m_previousBeaconInterval;
m_previousBeaconInterval = 0;
if (m_requestBitmap & REQUEST_CONFIRM_PENDING) {
// only now the next higher layer is to be informed
m_requestBitmap &= ~REQUEST_CONFIRM_PENDING;
post signalStartConfirmSuccessTask();
}
}
// The next beacon should be transmitted at time m_lastBeaconTxTime + m_dt, where m_dt
// is typically the beacon interval. First we check if we're still in time.
while (call TimeCalc.hasExpired(m_lastBeaconTxTime, m_dt)) {
// too late, we need to skip a beacon!
dbg_serial("BeaconTransmitP", "Skipping a beacon: scheduled=%lu, now=%lu.\n",
(uint32_t) m_lastBeaconTxTime + m_dt, (uint32_t) call BeaconSendAlarm.getNow());
m_dt += m_beaconInterval;
}
if (!call TimeCalc.hasExpired(m_lastBeaconTxTime - delay, m_dt)) {
// don't load the beacon frame in the radio just yet - rather set a timer and
// give the next higher layer the chance to modify the beacon payload
call BeaconSendAlarm.startAt(m_lastBeaconTxTime - delay, m_dt);
} else
signal BeaconSendAlarm.fired();
}
}
}
task void signalStartConfirmSuccessTask()
{
signal MLME_START.confirm(SUCCESS);
}
async event void BeaconSendAlarm.fired()
{
// start/schedule beacon transmission
ieee154_timestamp_t *timestamp = &m_lastBeaconTxRefTime;
m_txState = S_TX_LOCKED;
if (call IsBroadcastReady.getNow())
m_beaconFrame.header->mhr[MHR_INDEX_FC1] |= FC1_FRAME_PENDING;
else
m_beaconFrame.header->mhr[MHR_INDEX_FC1] &= ~FC1_FRAME_PENDING;
m_beaconFrame.header->mhr[MHR_INDEX_SEQNO] = m_bsn; // update beacon seqno
if (m_txOneBeaconImmediately) {
m_txOneBeaconImmediately = FALSE;
timestamp = NULL;
}
call BeaconTx.transmit(&m_beaconFrame, timestamp, m_dt);
dbg_serial("BeaconTransmitP","Beacon Tx scheduled for %lu.\n", (uint32_t) (*timestamp + m_dt));
}
async event void BeaconTx.transmitDone(ieee154_txframe_t *frame, const ieee154_timestamp_t *timestamp, error_t result)
{
// The beacon frame was transmitted, i.e. the CAP has just started
// update the state then pass the token on to the next component
uint8_t gtsFieldLength;
ASSERT(result == SUCCESS); // must succeed, we're sending without CCA or ACK request
if (timestamp != NULL) {
m_lastBeaconTxTime = frame->metadata->timestamp;
memcpy(&m_lastBeaconTxRefTime, timestamp, sizeof(ieee154_timestamp_t));
m_dt = m_beaconInterval; // transmit the next beacon at m_lastBeaconTxTime + m_dt
dbg_serial("BeaconTransmitP", "Beacon Tx success at %lu\n", (uint32_t) m_lastBeaconTxTime);
} else {
// Timestamp is invalid; this is bad. We need the beacon timestamp for the
// slotted CSMA-CA, because it defines the slot reference time. We can't use this superframe
// TODO: check if this was the initial beacon (then m_lastBeaconTxRefTime is invalid)
dbg_serial("BeaconTransmitP", "Invalid timestamp!\n");
m_dt += m_beaconInterval;
call RadioToken.request();
call RadioToken.release();
return;
}
// update superframe-related variables
m_numGtsSlots =
(frame->payload[BEACON_INDEX_GTS_SPEC] & GTS_DESCRIPTOR_COUNT_MASK) >> GTS_DESCRIPTOR_COUNT_OFFSET;
gtsFieldLength = 1 + ((m_numGtsSlots > 0) ? 1 + m_numGtsSlots * 3: 0);
m_numCapSlots =
((frame->payload[BEACON_INDEX_SF_SPEC2] & SF_SPEC2_FINAL_CAPSLOT_MASK) >> SF_SPEC2_FINAL_CAPSLOT_OFFSET) + 1;
m_sfSlotDuration =
(((uint32_t) 1) << ((frame->payload[BEACON_INDEX_SF_SPEC1] & SF_SPEC1_SO_MASK) >> SF_SPEC1_SO_OFFSET)) *
IEEE154_aBaseSlotDuration;
if (frame->header->mhr[MHR_INDEX_FC1] & FC1_FRAME_PENDING)
m_framePendingBit = TRUE;
else
m_framePendingBit = FALSE;
memcpy(m_gtsField, &frame->payload[BEACON_INDEX_GTS_SPEC], gtsFieldLength);
if (frame->payload[BEACON_INDEX_SF_SPEC2] & SF_SPEC2_BATT_LIFE_EXT) {
// BLE is active; calculate the time offset from slot 0
m_battLifeExtDuration = IEEE154_SHR_DURATION +
(frame->headerLen + frame->payloadLen + 2) * IEEE154_SYMBOLS_PER_OCTET;
if (frame->headerLen + frame->payloadLen + 2 > IEEE154_aMaxSIFSFrameSize)
m_battLifeExtDuration += IEEE154_MIN_LIFS_PERIOD;
else
m_battLifeExtDuration += IEEE154_MIN_SIFS_PERIOD;
m_battLifeExtDuration = m_battLifeExtDuration + m_battLifeExtPeriods * 20;
} else
m_battLifeExtDuration = 0;
// we pass on the token now, but make a reservation to get it back
// to transmit the next beacon (at the start of the next superframe)
call RadioToken.request();
call RadioToken.transferTo(RADIO_CLIENT_COORDBROADCAST);
post txDoneTask();
}
task void txDoneTask()
{
call MLME_SET.macBSN(m_bsn++);
call SetMacBeaconTxTime.set(m_lastBeaconTxTime); // start of slot0, ie. first preamble byte of beacon
call BeaconPayloadUpdateTimer.startOneShotAt(m_lastBeaconTxTime,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -