X-Git-Url: https://oss.titaniummirror.com/gitweb/?p=tinyos-2.x.git;a=blobdiff_plain;f=tos%2Flib%2Fmac%2Ftkn154%2FScanP.nc;h=f8f44f77925727cc6df711cffad2cba2139c2f51;hp=d5cd2355d1c801a3aa111c6c8bc07bfb72567ec5;hb=e9bfab607e051bae6afb47b44892ce37541d1b44;hpb=adf1de6c009d13b7b52e68535c63b28f59c97400 diff --git a/tos/lib/mac/tkn154/ScanP.nc b/tos/lib/mac/tkn154/ScanP.nc index d5cd2355..f8f44f77 100644 --- a/tos/lib/mac/tkn154/ScanP.nc +++ b/tos/lib/mac/tkn154/ScanP.nc @@ -33,6 +33,10 @@ * ======================================================================== */ +/** + * This module is responsible for channel scanning. + */ + #include "TKN154_MAC.h" module ScanP { @@ -41,6 +45,7 @@ module ScanP interface Init; interface MLME_SCAN; interface MLME_BEACON_NOTIFY; + interface GetNow as IsRadioTokenRequested; } uses { @@ -55,7 +60,7 @@ module ScanP interface Timer as ScanTimer; interface Pool as TxFramePool; interface Pool as TxControlPool; - interface Resource as Token; + interface TransferableResource as RadioToken; interface FrameUtility; interface Leds; } @@ -64,47 +69,48 @@ implementation { enum { MAX_PAYLOAD_SIZE = 1, + LAST_CHANNEL = 26, }; +#define INVALID_CHANNEL_BITMASK 0xFC000000L ieee154_txframe_t *m_txFrame = NULL; uint8_t m_payload[MAX_PAYLOAD_SIZE]; uint8_t m_scanType; uint32_t m_scanChannels; - uint32_t m_unscannedChannels; - ieee154_macAutoRequest_t m_macAutoRequest; - norace uint32_t m_currentChannelBit; norace uint8_t m_currentChannelNum; + bool m_terminateScan; void* m_resultList; uint8_t m_resultListNumEntries; uint8_t m_resultIndex; ieee154_macPANId_t m_PANID; norace uint32_t m_scanDuration; - bool m_busy = FALSE; + norace bool m_busy = FALSE; void nextIteration(); + void continueScanRequest(); task void startTimerTask(); task void nextIterationTask(); command error_t Init.init() { - // triggered by MLME_RESET; remember: Init will not be called - // while this component owns the Token, so the worst case is - // that a MLME_SCAN was accepted (returned IEEE154_SUCCESS) - // but the Token.granted() has not been signalled - if (m_busy){ - m_currentChannelNum = 27; + // triggered by MLME_RESET; Note: Init will not be called + // while this component owns the RadioToken, so the worst case is + // that a MLME_SCAN was accepted (returned IEEE154_SUCCESS) + // but the RadioToken.granted() has not been signalled + if (m_busy) { + m_terminateScan = TRUE; nextIteration(); // signals confirm and resets state } return SUCCESS; } -/* ----------------------- MLME-SCAN ----------------------- */ -/* "The MLME-SCAN.request primitive is used to initiate a channel scan over a - * given list of channels. A device can use a channel scan to measure the - * energy on the channel, search for the coordinator with which it associated, - * or search for all coordinators transmitting beacon frames within the POS of - * the scanning device." (IEEE 802.15.4-2006 Sect. 7.1.11.1) - **/ + /* ----------------------- MLME-SCAN ----------------------- */ + /* "The MLME-SCAN.request primitive is used to initiate a channel scan over a + * given list of channels. A device can use a channel scan to measure the + * energy on the channel, search for the coordinator with which it associated, + * or search for all coordinators transmitting beacon frames within the POS of + * the scanning device." (IEEE 802.15.4-2006 Sect. 7.1.11.1) + **/ command ieee154_status_t MLME_SCAN.request ( uint8_t ScanType, @@ -115,48 +121,48 @@ implementation int8_t* EnergyDetectList, uint8_t PANDescriptorListNumEntries, ieee154_PANDescriptor_t* PANDescriptorList, - ieee154_security_t *security - ) + ieee154_security_t *security) { ieee154_status_t status = IEEE154_SUCCESS; ieee154_phyChannelsSupported_t supportedChannels = call MLME_GET.phyChannelsSupported(); ieee154_txcontrol_t *txControl = NULL; - if (m_busy){ + if (m_busy) { status = IEEE154_SCAN_IN_PROGRESS; - } else if (security && security->SecurityLevel){ + } else if (security && security->SecurityLevel) { status = IEEE154_UNSUPPORTED_SECURITY; - } if ( (ScanType > 3) || (ScanType < 3 && ScanDuration > 14) || - (ChannelPage != IEEE154_SUPPORTED_CHANNELPAGE) || - !(supportedChannels & ScanChannels) || - (EnergyDetectListNumEntries && PANDescriptorListNumEntries) || - (EnergyDetectList != NULL && PANDescriptorList != NULL) || - (EnergyDetectListNumEntries && EnergyDetectList == NULL) || - (PANDescriptorListNumEntries && PANDescriptorList == NULL)) { + } if ((ScanType > 3) || (ScanType < 3 && ScanDuration > 14) || + (ChannelPage != IEEE154_SUPPORTED_CHANNELPAGE) || + !(supportedChannels & ScanChannels) || + ((ScanType != ORPHAN_SCAN) && + ((EnergyDetectListNumEntries && PANDescriptorListNumEntries) || + (EnergyDetectList != NULL && PANDescriptorList != NULL) || + (EnergyDetectListNumEntries && EnergyDetectList == NULL) || + (PANDescriptorListNumEntries && PANDescriptorList == NULL)))) { status = IEEE154_INVALID_PARAMETER; - } else if (ScanType != ENERGY_DETECTION_SCAN && - !(m_txFrame = call TxFramePool.get())) { + } else if ((ScanType == ACTIVE_SCAN || ScanType == ORPHAN_SCAN) && + ((m_txFrame = call TxFramePool.get()) == NULL)) { status = IEEE154_TRANSACTION_OVERFLOW; - } else if (ScanType != ENERGY_DETECTION_SCAN && - !(txControl = call TxControlPool.get())) { + } else if ((ScanType == ACTIVE_SCAN || ScanType == ORPHAN_SCAN) && + ((txControl = call TxControlPool.get()) == NULL)) { call TxFramePool.put(m_txFrame); m_txFrame = NULL; status = IEEE154_TRANSACTION_OVERFLOW; } else { - m_txFrame->header = &txControl->header; - m_txFrame->payload = m_payload; - m_txFrame->metadata = &txControl->metadata; + if (m_txFrame != NULL){ + m_txFrame->header = &txControl->header; + m_txFrame->payload = m_payload; + m_txFrame->metadata = &txControl->metadata; + } m_busy = TRUE; m_scanType = ScanType; m_scanChannels = ScanChannels; m_scanDuration = (((uint32_t) 1 << ScanDuration) + 1) * IEEE154_aBaseSuperframeDuration; - m_macAutoRequest = call MLME_GET.macAutoRequest(); m_PANID = call MLME_GET.macPANId(); - m_unscannedChannels = 0; - m_currentChannelBit = 1; m_currentChannelNum = 0; + m_terminateScan = FALSE; m_resultIndex = 0; - if (ScanType == ENERGY_DETECTION_SCAN){ + if (ScanType == ENERGY_DETECTION_SCAN) { m_resultList = EnergyDetectList; m_resultListNumEntries = EnergyDetectListNumEntries; } else { @@ -165,22 +171,37 @@ implementation } if (m_resultList == NULL) m_resultListNumEntries = 0; - call Token.request(); + call RadioToken.request(); } + dbg_serial("ScanP", "MLME_SCAN.request -> result: %lu\n", (uint32_t) status); return status; } - event void Token.granted() + event void RadioToken.granted() + { + if (call RadioOff.isOff()) + continueScanRequest(); + else + ASSERT(call RadioOff.off() == SUCCESS); + // will continue in continueScanRequest() + } + + task void continueScanRequestTask() + { + continueScanRequest(); + } + + void continueScanRequest() { uint8_t i; ieee154_macPANId_t bcastPANID = 0xFFFF; ieee154_macDSN_t dsn = call MLME_GET.macDSN(); - if (!m_busy){ - call Token.release(); + if (!m_busy) { + call RadioToken.release(); return; } - switch (m_scanType){ + switch (m_scanType) { case ACTIVE_SCAN: // beacon request frame m_txFrame->header->mhr[MHR_INDEX_FC1] = FC1_FRAMETYPE_CMD; @@ -198,14 +219,14 @@ implementation break; case ORPHAN_SCAN: // orphan notification frame - m_scanDuration = call MLME_GET.macResponseWaitTime(); + m_scanDuration = call MLME_GET.macResponseWaitTime() * IEEE154_aBaseSuperframeDuration; m_txFrame->header->mhr[MHR_INDEX_FC1] = FC1_FRAMETYPE_CMD | FC1_PAN_ID_COMPRESSION; m_txFrame->header->mhr[MHR_INDEX_FC2] = FC2_SRC_MODE_EXTENDED | FC2_DEST_MODE_SHORT; m_txFrame->header->mhr[MHR_INDEX_SEQNO] = dsn; call MLME_SET.macDSN(dsn+1); for (i=0; i<4; i++) // broadcast dest PAN ID + broadcast dest addr m_txFrame->header->mhr[MHR_INDEX_ADDRESS + i] = 0xFF; - call FrameUtility.copyLocalExtendedAddressLE((uint8_t*) &(m_txFrame->header[MHR_INDEX_ADDRESS + i])); + call FrameUtility.copyLocalExtendedAddressLE((uint8_t*) &(m_txFrame->header->mhr[MHR_INDEX_ADDRESS + i])); m_txFrame->headerLen = 15; m_payload[0] = CMD_FRAME_ORPHAN_NOTIFICATION; m_txFrame->payloadLen = 1; @@ -216,155 +237,179 @@ implementation void nextIteration() { + ieee154_phyChannelsSupported_t supportedChannels = call MLME_GET.phyChannelsSupported(); + uint32_t currentChannelBit = (uint32_t) 1 << m_currentChannelNum; error_t radioStatus = SUCCESS; - uint32_t supportedChannels = IEEE154_SUPPORTED_CHANNELS; - atomic { - while (!(m_scanChannels & m_currentChannelBit & supportedChannels) && m_currentChannelNum < 27){ - m_unscannedChannels |= m_currentChannelBit; - m_currentChannelBit <<= 1; + + if (!m_terminateScan){ + while (m_currentChannelNum <= LAST_CHANNEL && + !(m_scanChannels & currentChannelBit & supportedChannels)){ m_currentChannelNum++; + currentChannelBit <<= 1; } } - if (m_currentChannelNum < 27) { + + if (m_currentChannelNum <= LAST_CHANNEL && !m_terminateScan) { + // scan the next channel call MLME_SET.phyCurrentChannel(m_currentChannelNum); - switch (m_scanType){ + dbg_serial("ScanP", "Scanning channel %lu...\n", (uint32_t) m_currentChannelNum); + switch (m_scanType) { case PASSIVE_SCAN: - radioStatus = call RadioRx.prepare(); + radioStatus = call RadioRx.enableRx(0, 0); break; - case ACTIVE_SCAN: + case ACTIVE_SCAN: // fall through case ORPHAN_SCAN: - radioStatus = call RadioTx.load(m_txFrame); + radioStatus = call RadioTx.transmit(m_txFrame, NULL, 0); break; case ENERGY_DETECTION_SCAN: radioStatus = call EnergyDetection.start(m_scanDuration); break; } - if (radioStatus != SUCCESS){ - call Leds.led0On(); - } + ASSERT(radioStatus == SUCCESS); } else { - ieee154_status_t result = IEEE154_SUCCESS; // we're done - m_currentChannelBit <<= 1; - while (m_currentChannelBit){ - m_unscannedChannels |= m_currentChannelBit; - m_currentChannelBit <<= 1; - } - m_unscannedChannels &= m_scanChannels; // only channels that were requested - if (m_scanType != ENERGY_DETECTION_SCAN && !m_resultIndex) + ieee154_status_t result = IEEE154_SUCCESS; + uint32_t unscannedChannels = 0; + + if (m_terminateScan){ + // Scan operation terminated because the max. + // number of PAN descriptors/ED samples was reached. + // Check if there are channels that were unscanned. + // In active/passive scan we consider a channel + // unscanned if it was not completely scanned. + if (m_scanType == PASSIVE_SCAN || m_scanType == ACTIVE_SCAN) + currentChannelBit >>= 1; // last (partially) scanned channel + while (!(currentChannelBit & INVALID_CHANNEL_BITMASK) && + (m_scanChannels & currentChannelBit)){ + unscannedChannels |= currentChannelBit; + currentChannelBit <<= 1; + } + if (unscannedChannels) // some channels were not (completely) scanned + result = IEEE154_LIMIT_REACHED; + } else if (m_scanType != ENERGY_DETECTION_SCAN && !m_resultIndex) result = IEEE154_NO_BEACON; + if (m_scanType == PASSIVE_SCAN || m_scanType == ACTIVE_SCAN) call MLME_SET.macPANId(m_PANID); - if (m_txFrame != NULL){ + if (m_txFrame != NULL) { call TxControlPool.put((ieee154_txcontrol_t*) ((uint8_t*) m_txFrame->header - offsetof(ieee154_txcontrol_t, header))); call TxFramePool.put(m_txFrame); } m_txFrame = NULL; - if (call Token.isOwner()) - call Token.release(); + if (call RadioToken.isOwner()) + call RadioToken.release(); m_busy = FALSE; + dbg_serial("ScanP", "MLME_SCAN.confirm()\n"); signal MLME_SCAN.confirm ( result, m_scanType, IEEE154_SUPPORTED_CHANNELPAGE, - m_unscannedChannels, + unscannedChannels, (m_scanType == ENERGY_DETECTION_SCAN) ? m_resultIndex : 0, - (m_scanType == ENERGY_DETECTION_SCAN) ? (uint8_t*) m_resultList : NULL, + (m_scanType == ENERGY_DETECTION_SCAN) ? (int8_t*) m_resultList : NULL, ((m_scanType == ACTIVE_SCAN || - m_scanType == PASSIVE_SCAN) && m_macAutoRequest) ? m_resultIndex : 0, + m_scanType == PASSIVE_SCAN) && call MLME_GET.macAutoRequest()) ? m_resultIndex : 0, ((m_scanType == ACTIVE_SCAN || - m_scanType == PASSIVE_SCAN) && m_macAutoRequest) ? (ieee154_PANDescriptor_t*) m_resultList : NULL - ); + m_scanType == PASSIVE_SCAN) && call MLME_GET.macAutoRequest()) ? (ieee154_PANDescriptor_t*) m_resultList : NULL); } + dbg_serial_flush(); + } + + async event void RadioRx.enableRxDone() + { + post startTimerTask(); } -/* ----------------------- EnergyDetection ----------------------- */ + /* ----------------------- EnergyDetection ----------------------- */ event void EnergyDetection.done(error_t status, int8_t EnergyLevel) { if (status == SUCCESS && m_resultListNumEntries) ((uint8_t*) m_resultList)[m_resultIndex++] = EnergyLevel; - else - m_unscannedChannels |= m_currentChannelBit; if (m_resultIndex == m_resultListNumEntries) - m_currentChannelNum = 27; // done - else - m_currentChannelNum++; - call RadioOff.off(); + m_terminateScan = TRUE; // done + if (call RadioOff.off() == EALREADY) + signal RadioOff.offDone(); } -/* ----------------------- Active/Orphan scan ----------------------- */ - - async event void RadioTx.loadDone() - { - call RadioTx.transmit(0, 0, 0, FALSE); - } + /* ----------------------- Active/Orphan scan ----------------------- */ - async event void RadioTx.transmitDone(ieee154_txframe_t *frame, - ieee154_reftime_t *referenceTime, bool ackPendingFlag, error_t error) + async event void RadioTx.transmitDone(ieee154_txframe_t *frame, const ieee154_timestamp_t *timestamp, error_t result) { - if (call RadioRx.prepare() != SUCCESS) // must succeed - call Leds.led0On(); + ASSERT(call RadioRx.enableRx(0, 0) == SUCCESS); } -/* -------- Receive events (for Active/Passive/Orphan scan) -------- */ + /* -------- Receive events (for Active/Passive/Orphan scan) -------- */ - async event void RadioRx.prepareDone() + event message_t* RadioRx.received(message_t *frame, const ieee154_timestamp_t *timestamp) { - call RadioRx.receive(NULL, 0); - post startTimerTask(); - } + if (!m_busy) + return frame; - event message_t* RadioRx.received(message_t *frame, ieee154_reftime_t *timestamp) - { - atomic { - if (!m_busy) - return frame; - if (m_scanType == ORPHAN_SCAN){ - if (!m_resultIndex) - if ((MHR(frame)[0] & FC1_FRAMETYPE_MASK) == FC1_FRAMETYPE_CMD && - ((uint8_t*)call Frame.getPayload(frame))[0] == CMD_FRAME_COORDINATOR_REALIGNMENT){ - m_resultIndex++; - m_currentChannelNum = 27; // terminate scan - call RadioOff.off(); - } - } else if ((((ieee154_header_t*) frame->header)->mhr[0] & FC1_FRAMETYPE_MASK) == FC1_FRAMETYPE_BEACON) { - // PASSIVE_SCAN / ACTIVE_SCAN - if (!m_macAutoRequest) - return signal MLME_BEACON_NOTIFY.indication (frame); - else if (m_resultListNumEntries && m_resultIndex < m_resultListNumEntries && - call BeaconFrame.parsePANDescriptor( - frame, - m_currentChannelNum, - IEEE154_SUPPORTED_CHANNELPAGE, - &((ieee154_PANDescriptor_t*) m_resultList)[m_resultIndex]) == SUCCESS){ - // check uniqueness: both PAN ID and source address must not be in a previously received beacon - uint8_t i; - if (m_resultIndex) - for (i=0; iheader)->mhr[0] & FC1_FRAMETYPE_MASK) == FC1_FRAMETYPE_BEACON) { + + // PASSIVE_SCAN / ACTIVE_SCAN: + // A beacon frame containing a non-empty payload is always signalled + // to the next higher layer (regardless of the value of macAutoRequest); + // when macAutoRequest is set to TRUE, then the beacon is always + // stored in the PAN Descriptor list (see 7.1.11.2.1 - Table 68) + + if (!call MLME_GET.macAutoRequest()) + return signal MLME_BEACON_NOTIFY.indication (frame); + else if (m_resultIndex >= m_resultListNumEntries) { + m_terminateScan = TRUE; + call RadioOff.off(); + } else if (call BeaconFrame.parsePANDescriptor( + frame, + m_currentChannelNum, + IEEE154_SUPPORTED_CHANNELPAGE, + &((ieee154_PANDescriptor_t*) m_resultList)[m_resultIndex]) == SUCCESS) { + + // check uniqueness: PAN ID and source address must + // not be found in a previously received beacon + uint8_t i; + ieee154_PANDescriptor_t* descriptor = (ieee154_PANDescriptor_t*) m_resultList; + + dbg_serial("ScanP", "Received beacon, source: 0x%lx, channel: %lu.\n", + (uint32_t) descriptor[m_resultIndex].CoordAddress.shortAddress, (uint32_t) m_currentChannelNum); + for (i=0; i 0) + return signal MLME_BEACON_NOTIFY.indication (frame); + } // PASSIVE_SCAN / ACTIVE_SCAN return frame; } -/* ----------------------- Common ----------------------- */ + /* ----------------------- Common ----------------------- */ task void startTimerTask() { @@ -378,9 +423,12 @@ implementation async event void RadioOff.offDone() { - m_currentChannelBit <<= 1; - m_currentChannelNum++; - post nextIterationTask(); + if (m_currentChannelNum == 0) + post continueScanRequestTask(); + else { + m_currentChannelNum++; + post nextIterationTask(); + } } task void nextIterationTask() @@ -388,7 +436,9 @@ implementation nextIteration(); } - default event message_t* MLME_BEACON_NOTIFY.indication ( message_t *beaconFrame ){return beaconFrame;} + async command token_requested_t IsRadioTokenRequested.getNow(){ return m_busy;} + async event void RadioToken.transferredFrom(uint8_t id){ ASSERT(0);} + default event message_t* MLME_BEACON_NOTIFY.indication (message_t *beaconFrame) {return beaconFrame;} default event void MLME_SCAN.confirm ( ieee154_status_t status, uint8_t ScanType, @@ -397,6 +447,5 @@ implementation uint8_t EnergyDetectListNumEntries, int8_t* EnergyDetectList, uint8_t PANDescriptorListNumEntries, - ieee154_PANDescriptor_t* PANDescriptorList - ){} + ieee154_PANDescriptor_t* PANDescriptorList) {} }