mirror of
https://github.com/espressif/openthread.git
synced 2026-08-18 16:39:52 +00:00
Add support for EnergyScan operation at mac layer. (#580)
This commits makes the following changes: - It add the implementation of energy scan operation at mac layer. - It modifies the `openthread.cpp` to pipe through and expose the energy scan related APIs. - It also fixes the get handler for the property `MAC_SCAN_STATE` in `Ncp` class to return the proper state if an energy scan operation is ongoing.
This commit is contained in:
committed by
Jonathan Hui
parent
9393f468bd
commit
3139e635b8
@@ -325,7 +325,7 @@ typedef void (*otHandleEnergyScanResult)(otEnergyScanResult *aResult, void *aCon
|
||||
* @param[in] aCallbackContext A pointer to application-specific context.
|
||||
*
|
||||
* @retval kThreadError_None Accepted the Energy Scan request.
|
||||
* @retval kThreadError_Busy Already performing an Active Scan.
|
||||
* @retval kThreadError_Busy Could not start the energy scan.
|
||||
*
|
||||
*/
|
||||
ThreadError otEnergyScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration,
|
||||
|
||||
+121
-13
@@ -80,6 +80,7 @@ Mac::Mac(ThreadNetif &aThreadNetif):
|
||||
mKeyManager(aThreadNetif.GetKeyManager()),
|
||||
mMle(aThreadNetif.GetMle()),
|
||||
mNetif(aThreadNetif),
|
||||
mEnergyScanSampleRssiTask(aThreadNetif.GetIp6().mTaskletScheduler, &HandleEnergyScanSampleRssi, this),
|
||||
mWhitelist(),
|
||||
mBlacklist()
|
||||
{
|
||||
@@ -92,12 +93,14 @@ Mac::Mac(ThreadNetif &aThreadNetif):
|
||||
mTransmitAttempts = 0;
|
||||
mTransmitBeacon = false;
|
||||
|
||||
mActiveScanRequest = false;
|
||||
mPendingScanRequest = kScanTypeNone;
|
||||
mScanChannel = kPhyMinChannel;
|
||||
mScanChannels = 0xff;
|
||||
mScanDuration = 0;
|
||||
mScanContext = NULL;
|
||||
mActiveScanHandler = NULL;
|
||||
mActiveScanContext = NULL;
|
||||
mEnergyScanHandler = NULL;
|
||||
mEnergyScanCurrentMaxRssi = kInvalidRssiValue;
|
||||
|
||||
mSendHead = NULL;
|
||||
mSendTail = NULL;
|
||||
@@ -134,13 +137,35 @@ Mac::Mac(ThreadNetif &aThreadNetif):
|
||||
}
|
||||
|
||||
ThreadError Mac::ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext)
|
||||
{
|
||||
ThreadError error;
|
||||
|
||||
SuccessOrExit(error = Scan(kScanTypeActive, aScanChannels, aScanDuration, aContext));
|
||||
mActiveScanHandler = aHandler;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
ThreadError Mac::EnergyScan(uint32_t aScanChannels, uint16_t aScanDuration, EnergyScanHandler aHandler, void *aContext)
|
||||
{
|
||||
ThreadError error;
|
||||
|
||||
SuccessOrExit(error = Scan(kScanTypeEnergy, aScanChannels, aScanDuration, aContext));
|
||||
mEnergyScanHandler = aHandler;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
ThreadError Mac::Scan(ScanType aScanType, uint32_t aScanChannels, uint16_t aScanDuration, void *aContext)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
|
||||
VerifyOrExit(mState != kStateActiveScan && mActiveScanRequest == false, error = kThreadError_Busy);
|
||||
VerifyOrExit((mState != kStateActiveScan) && (mState != kStateEnergyScan) && (mPendingScanRequest == kScanTypeNone),
|
||||
error = kThreadError_Busy);
|
||||
|
||||
mActiveScanHandler = aHandler;
|
||||
mActiveScanContext = aContext;
|
||||
mScanContext = aContext;
|
||||
mScanChannels = (aScanChannels == 0) ? static_cast<uint32_t>(kScanChannelsAll) : aScanChannels;
|
||||
mScanDuration = (aScanDuration == 0) ? static_cast<uint16_t>(kScanDurationDefault) : aScanDuration;
|
||||
|
||||
@@ -155,12 +180,19 @@ ThreadError Mac::ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, Acti
|
||||
|
||||
if (mState == kStateIdle)
|
||||
{
|
||||
mState = kStateActiveScan;
|
||||
StartCsmaBackoff();
|
||||
if (aScanType == kScanTypeActive)
|
||||
{
|
||||
mState = kStateActiveScan;
|
||||
StartCsmaBackoff();
|
||||
}
|
||||
else if (aScanType == kScanTypeEnergy)
|
||||
{
|
||||
StartEnergyScan();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mActiveScanRequest = true;
|
||||
mPendingScanRequest = aScanType;
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -169,7 +201,49 @@ exit:
|
||||
|
||||
bool Mac::IsActiveScanInProgress(void)
|
||||
{
|
||||
return (mState == kStateActiveScan) || mActiveScanRequest;
|
||||
return (mState == kStateActiveScan) || (mPendingScanRequest == kScanTypeActive);
|
||||
}
|
||||
|
||||
bool Mac::IsEnergyScanInProgress(void)
|
||||
{
|
||||
return (mState == kStateEnergyScan) || (mPendingScanRequest == kScanTypeEnergy);
|
||||
}
|
||||
|
||||
void Mac::StartEnergyScan(void)
|
||||
{
|
||||
mState = kStateEnergyScan;
|
||||
mEnergyScanCurrentMaxRssi = kInvalidRssiValue;
|
||||
mAckTimer.Start(mScanDuration);
|
||||
mEnergyScanSampleRssiTask.Post();
|
||||
NextOperation();
|
||||
}
|
||||
|
||||
void Mac::HandleEnergyScanSampleRssi(void *aContext)
|
||||
{
|
||||
Mac *obj = static_cast<Mac *>(aContext);
|
||||
obj->HandleEnergyScanSampleRssi();
|
||||
}
|
||||
|
||||
void Mac::HandleEnergyScanSampleRssi(void)
|
||||
{
|
||||
int8_t rssi;
|
||||
|
||||
VerifyOrExit(mState == kStateEnergyScan, ;);
|
||||
|
||||
rssi = otPlatRadioGetRssi(NULL);
|
||||
|
||||
if (rssi != kInvalidRssiValue)
|
||||
{
|
||||
if ((mEnergyScanCurrentMaxRssi == kInvalidRssiValue) || (rssi > mEnergyScanCurrentMaxRssi))
|
||||
{
|
||||
mEnergyScanCurrentMaxRssi = rssi;
|
||||
}
|
||||
}
|
||||
|
||||
mEnergyScanSampleRssiTask.Post();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadError Mac::RegisterReceiver(Receiver &aReceiver)
|
||||
@@ -329,6 +403,7 @@ void Mac::NextOperation(void)
|
||||
switch (mState)
|
||||
{
|
||||
case kStateActiveScan:
|
||||
case kStateEnergyScan:
|
||||
otPlatRadioReceive(NULL, mScanChannel);
|
||||
break;
|
||||
|
||||
@@ -348,12 +423,17 @@ void Mac::NextOperation(void)
|
||||
|
||||
void Mac::ScheduleNextTransmission(void)
|
||||
{
|
||||
if (mActiveScanRequest)
|
||||
if (mPendingScanRequest == kScanTypeActive)
|
||||
{
|
||||
mActiveScanRequest = false;
|
||||
mPendingScanRequest = kScanTypeNone;
|
||||
mState = kStateActiveScan;
|
||||
StartCsmaBackoff();
|
||||
}
|
||||
else if (mPendingScanRequest == kScanTypeEnergy)
|
||||
{
|
||||
mPendingScanRequest = kScanTypeNone;
|
||||
StartEnergyScan();
|
||||
}
|
||||
else if (mTransmitBeacon)
|
||||
{
|
||||
mTransmitBeacon = false;
|
||||
@@ -634,7 +714,7 @@ void Mac::HandleAckTimer(void)
|
||||
|
||||
if (mScanChannels == 0 || mScanChannel > kPhyMaxChannel)
|
||||
{
|
||||
mActiveScanHandler(mActiveScanContext, NULL);
|
||||
mActiveScanHandler(mScanContext, NULL);
|
||||
ScheduleNextTransmission();
|
||||
ExitNow();
|
||||
}
|
||||
@@ -644,6 +724,34 @@ void Mac::HandleAckTimer(void)
|
||||
StartCsmaBackoff();
|
||||
break;
|
||||
|
||||
case kStateEnergyScan:
|
||||
if (mEnergyScanCurrentMaxRssi != kInvalidRssiValue)
|
||||
{
|
||||
otEnergyScanResult result;
|
||||
|
||||
result.mChannel = mScanChannel;
|
||||
result.mMaxRssi = mEnergyScanCurrentMaxRssi;
|
||||
mEnergyScanHandler(mScanContext, &result);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
mScanChannels >>= 1;
|
||||
mScanChannel++;
|
||||
|
||||
if (mScanChannels == 0 || mScanChannel > kPhyMaxChannel)
|
||||
{
|
||||
mEnergyScanHandler(mScanContext, NULL);
|
||||
ScheduleNextTransmission();
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
while ((mScanChannels & 1) == 0);
|
||||
|
||||
mEnergyScanCurrentMaxRssi = kInvalidRssiValue;
|
||||
mAckTimer.Start(mScanDuration);
|
||||
break;
|
||||
|
||||
case kStateTransmitData:
|
||||
otLogDebgMac("ack timer fired\n");
|
||||
mCounters.mTxTotal++;
|
||||
@@ -981,7 +1089,7 @@ void Mac::ReceiveDoneTask(Frame *aFrame, ThreadError aError)
|
||||
if (aFrame->GetType() == Frame::kFcfFrameBeacon)
|
||||
{
|
||||
mCounters.mRxBeacon++;
|
||||
mActiveScanHandler(mActiveScanContext, aFrame);
|
||||
mActiveScanHandler(mScanContext, aFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+56
-3
@@ -210,6 +210,30 @@ public:
|
||||
*/
|
||||
ThreadError ActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext);
|
||||
|
||||
/**
|
||||
* This function pointer is called during an "Energy Scan" when the result for a channel is ready or the scan
|
||||
* completes.
|
||||
*
|
||||
* @param[in] aResult A valid pointer to the energy scan result information or NULL when the energy scan completes.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
*
|
||||
*/
|
||||
typedef void (*EnergyScanHandler)(void *aContext, otEnergyScanResult *aResult);
|
||||
|
||||
/**
|
||||
* This function starts an IEEE 802.15.4 Energy Scan.
|
||||
*
|
||||
* @param[in] aScanChannels A bit vector indicating on which channels to perform energy scan.
|
||||
* @param[in] aScanDuration The time in milliseconds to spend scanning each channel.
|
||||
* @param[in] aHandler A pointer to a function called to pass on scan result or indicate scan completion.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
*
|
||||
* @retval kThreadError_None Accepted the Energy Scan request.
|
||||
* @retval kThreadError_Busy Could not start the energy scan.
|
||||
*
|
||||
*/
|
||||
ThreadError EnergyScan(uint32_t aScanChannels, uint16_t aScanDuration, EnergyScanHandler aHandler, void *aContext);
|
||||
|
||||
/**
|
||||
* This method indicates whether or not rx-on-when-idle is enabled.
|
||||
*
|
||||
@@ -416,6 +440,12 @@ public:
|
||||
*/
|
||||
bool IsActiveScanInProgress(void);
|
||||
|
||||
/**
|
||||
* This method returns if an energy scan is in progress.
|
||||
*
|
||||
*/
|
||||
bool IsEnergyScanInProgress(void);
|
||||
|
||||
/**
|
||||
* This function registers a callback to provide received raw IEEE 802.15.4 frames.
|
||||
*
|
||||
@@ -462,6 +492,18 @@ public:
|
||||
LinkQualityInfo &GetNoiseFloor(void) { return mNoiseFloor; }
|
||||
|
||||
private:
|
||||
enum ScanType
|
||||
{
|
||||
kScanTypeNone = 0,
|
||||
kScanTypeActive,
|
||||
kScanTypeEnergy,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kInvalidRssiValue = 127
|
||||
};
|
||||
|
||||
void GenerateNonce(const ExtAddress &aAddress, uint32_t aFrameCounter, uint8_t aSecurityLevel, uint8_t *aNonce);
|
||||
void NextOperation(void);
|
||||
void ProcessTransmitSecurity(Frame &aFrame);
|
||||
@@ -471,6 +513,7 @@ private:
|
||||
void SendBeaconRequest(Frame &aFrame);
|
||||
void SendBeacon(Frame &aFrame);
|
||||
void StartBackoff(void);
|
||||
void StartEnergyScan(void);
|
||||
ThreadError HandleMacCommand(Frame &aFrame);
|
||||
|
||||
static void HandleAckTimer(void *aContext);
|
||||
@@ -479,8 +522,11 @@ private:
|
||||
void HandleBeginTransmit(void);
|
||||
static void HandleReceiveTimer(void *aContext);
|
||||
void HandleReceiveTimer(void);
|
||||
static void HandleEnergyScanSampleRssi(void *aContext);
|
||||
void HandleEnergyScanSampleRssi(void);
|
||||
|
||||
void StartCsmaBackoff(void);
|
||||
ThreadError Scan(ScanType aType, uint32_t aScanChannels, uint16_t aScanDuration, void *aContext);
|
||||
|
||||
Tasklet mBeginTransmit;
|
||||
Timer mAckTimer;
|
||||
@@ -507,6 +553,7 @@ private:
|
||||
{
|
||||
kStateIdle = 0,
|
||||
kStateActiveScan,
|
||||
kStateEnergyScan,
|
||||
kStateTransmitBeacon,
|
||||
kStateTransmitData,
|
||||
};
|
||||
@@ -519,12 +566,18 @@ private:
|
||||
uint8_t mTransmitAttempts;
|
||||
bool mTransmitBeacon;
|
||||
|
||||
bool mActiveScanRequest;
|
||||
ScanType mPendingScanRequest;
|
||||
uint8_t mScanChannel;
|
||||
uint32_t mScanChannels;
|
||||
uint16_t mScanDuration;
|
||||
ActiveScanHandler mActiveScanHandler;
|
||||
void *mActiveScanContext;
|
||||
void *mScanContext;
|
||||
union
|
||||
{
|
||||
ActiveScanHandler mActiveScanHandler;
|
||||
EnergyScanHandler mEnergyScanHandler;
|
||||
};
|
||||
int8_t mEnergyScanCurrentMaxRssi;
|
||||
Tasklet mEnergyScanSampleRssiTask;
|
||||
|
||||
LinkQualityInfo mNoiseFloor;
|
||||
|
||||
|
||||
+16
-10
@@ -84,6 +84,7 @@ extern "C" {
|
||||
static otDEFINE_ALIGNED_VAR(sThreadNetifRaw, sizeof(ThreadNetif), uint64_t);
|
||||
|
||||
static void HandleActiveScanResult(void *aContext, Mac::Frame *aFrame);
|
||||
static void HandleEnergyScanResult(void *aContext, otEnergyScanResult *aResult);
|
||||
static void HandleMleDiscover(otActiveScanResult *aResult, void *aContext);
|
||||
|
||||
static otHandleActiveScanResult sActiveScanCallback = NULL;
|
||||
@@ -1063,23 +1064,28 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadError otEnergyScan(otInstance *, uint32_t aScanChannels, uint16_t aScanDuration,
|
||||
ThreadError otEnergyScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration,
|
||||
otHandleEnergyScanResult aCallback, void *aCallbackContext)
|
||||
{
|
||||
sEnergyScanCallback = aCallback;
|
||||
sEnergyScanCallbackContext = aCallbackContext;
|
||||
|
||||
(void)aScanChannels;
|
||||
(void)aScanDuration;
|
||||
|
||||
// TODO: Implement the energy scan at mac layer.
|
||||
|
||||
return kThreadError_NotImplemented;
|
||||
return sThreadNetif->GetMac().EnergyScan(aScanChannels, aScanDuration, &HandleEnergyScanResult, aInstance);
|
||||
}
|
||||
|
||||
bool otIsEnegyScanInProgress(otInstance *)
|
||||
void HandleEnergyScanResult(void *aContext, otEnergyScanResult *aResult)
|
||||
{
|
||||
return false;
|
||||
otInstance *aInstance = static_cast<otInstance *>(aContext);
|
||||
|
||||
sEnergyScanCallback(aResult, sEnergyScanCallbackContext);
|
||||
|
||||
(void)aInstance;
|
||||
}
|
||||
|
||||
|
||||
bool otIsEnergyScanInProgress(otInstance *aInstance)
|
||||
{
|
||||
(void)aInstance;
|
||||
return sThreadNetif->GetMac().IsEnergyScanInProgress();
|
||||
}
|
||||
|
||||
ThreadError otDiscover(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration, uint16_t aPanId,
|
||||
|
||||
+14
-4
@@ -1143,7 +1143,7 @@ ThreadError NcpBase::CommandHandler_RESET(uint8_t header, unsigned int command,
|
||||
// We only get to this point if the
|
||||
// platform doesn't support resetting.
|
||||
// In such a case we fake it.
|
||||
|
||||
|
||||
otThreadStop(mInstance);
|
||||
otInterfaceDown(mInstance);
|
||||
|
||||
@@ -1465,6 +1465,16 @@ ThreadError NcpBase::GetPropertyHandler_MAC_SCAN_STATE(uint8_t header, spinel_pr
|
||||
SPINEL_SCAN_STATE_BEACON
|
||||
);
|
||||
}
|
||||
else if (otIsEnergyScanInProgress(mInstance))
|
||||
{
|
||||
errorCode = SendPropertyUpdate(
|
||||
header,
|
||||
SPINEL_CMD_PROP_VALUE_IS,
|
||||
key,
|
||||
SPINEL_DATATYPE_UINT8_S,
|
||||
SPINEL_SCAN_STATE_ENERGY
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
errorCode = SendPropertyUpdate(
|
||||
@@ -3173,7 +3183,7 @@ ThreadError NcpBase::SetPropertyHandler_STREAM_NET_INSECURE(uint8_t header, spin
|
||||
(void)meta_ptr;
|
||||
(void)meta_len;
|
||||
(void)parsedLength;
|
||||
|
||||
|
||||
errorCode = otAppendMessage(message, frame_ptr, static_cast<uint16_t>(frame_len));
|
||||
}
|
||||
|
||||
@@ -3218,7 +3228,7 @@ ThreadError NcpBase::SetPropertyHandler_STREAM_NET(uint8_t header, spinel_prop_k
|
||||
unsigned int frame_len(0);
|
||||
const uint8_t *meta_ptr(NULL);
|
||||
unsigned int meta_len(0);
|
||||
|
||||
|
||||
// STREAM_NET requires layer 2 security.
|
||||
otMessage message = otNewIp6Message(mInstance, true);
|
||||
|
||||
@@ -3243,7 +3253,7 @@ ThreadError NcpBase::SetPropertyHandler_STREAM_NET(uint8_t header, spinel_prop_k
|
||||
(void)meta_ptr;
|
||||
(void)meta_len;
|
||||
(void)parsedLength;
|
||||
|
||||
|
||||
errorCode = otAppendMessage(message, frame_ptr, static_cast<uint16_t>(frame_len));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user