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:
Abtin Keshavarzian
2016-09-14 13:40:44 -07:00
committed by Jonathan Hui
parent 9393f468bd
commit 3139e635b8
5 changed files with 208 additions and 31 deletions
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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));
}