概述
前言
最近接触芯科的EFR32MG21A020F768型号的zigbee SOC,跑了一下simplicity studio 4.0上自带的ZigBee Minimal Application,顺便加点日志跟一下入网的流程。上电的流程已经有大神分析过,可以大致参考一下,这里只关注入网的流程:
上电流程
正文
我这次编译的是一个router类型设备,上电后自动搜索附近的网关。流程大致如下:
simple-main/simple-main.c
int MAIN(MAIN_FUNCTION_PARAMETERS)
{
halInit();
emberAfMainInit();
return emberAfMain(MAIN_FUNCTION_ARGUMENTS);
}
在return的时候开始应用框架层的初始化
zcl-framework-core/af-main-soc.c
int emberAfMain(MAIN_FUNCTION_PARAMETERS)
{
...
emberAfRunEvents();
}
zcl-framework-core/af-event.c
EmberEventData emAfEvents[] = {
EM_AF_SERVICE_DISCOVERY_EVENTS
#ifdef EMBER_AF_GENERATED_EVENTS
EMBER_AF_GENERATED_EVENTS
#endif
#ifdef EMBER_AF_PLUGIN_FRAGMENTATION
EMBER_AF_FRAGMENTATION_EVENTS
#endif
EMBER_KEY_ESTABLISHMENT_TEST_HARNESS_EVENT
{ NULL, NULL }
};
const char emAfStackEventString[] = "Stack";
// *****************************************************************************
// Functions
// A function used to initialize events for idling
void emAfInitEvents(void)
{
emberTaskEnableIdling(true);
emAfTaskId = emberTaskInit(emAfEvents);
}
void emberAfRunEvents(void)
{
// Don't run events while crypto operation is in progress
// (BUGZID: 12127)
if (emAfIsCryptoOperationInProgress()) {
// DEBUG Bugzid: 11944
emberAfCoreFlush();
return;
}
emberRunTask(emAfTaskId);
}
emberAfRunEvents()函数顾名思义就是开始跑各种的事件,其中就包括我们选择的各种plugin的时候自动生成的回调函数,如下所示
af-gen-event.h
/ EmberEventData structs used to populate the EmberEventData table
#define EMBER_AF_GENERATED_EVENTS
{ &emberAfPluginConnectionManagerPollEventControl, emberAfPluginConnectionManagerPollEventHandler },
{ &emberAfPluginConnectionManagerRebootEventControl, emberAfPluginConnectionManagerRebootEventHandler },
{ &emberAfPluginConnectionManagerRejoinEventControl, emberAfPluginConnectionManagerRejoinEventHandler },
{ &emberAfPluginLedBlinkLed0EventFunctionEventControl, emberAfPluginLedBlinkLed0EventFunctionEventHandler },
{ &emberAfPluginLedBlinkLed1EventFunctionEventControl, emberAfPluginLedBlinkLed1EventFunctionEventHandler },
{ &emberAfPluginManufacturingLibraryCliCheckSendCompleteEventControl, emberAfPluginManufacturingLibraryCliCheckSendCompleteEventHandler },
{ &emberAfPluginNetworkSteeringFinishSteeringEventControl, emberAfPluginNetworkSteeringFinishSteeringEventHandler },
{ &emberAfPluginReportingTickEventControl, emberAfPluginReportingTickEventHandler },
{ &emberAfPluginScanDispatchScanEventControl, emberAfPluginScanDispatchScanEventHandler },
{ &emberAfPluginUpdateTcLinkKeyBeginTcLinkKeyUpdateEventControl, emberAfPluginUpdateTcLinkKeyBeginTcLinkKeyUpdateEventHandler },
1、这里我们先关注emberAfPluginConnectionManagerRebootEventHandler,这个是上电后自动入网的入口函数
connection-manager/connection-manager.c
//------------------------------------------------------------------------------
// Plugin event handlers
//******************************************************************************
// Reboot event. To be called sometime after all system init functions have
// executed. This function will check the network state, and initiate a search
// for new networks to join if the device is not currently on a network.
//******************************************************************************
void emberAfPluginConnectionManagerRebootEventHandler(void)
{
uint8_t shortPollForced;
halCommonGetToken(&shortPollForced, TOKEN_FORCE_SHORT_POLL);
if (shortPollForced) {
emberAfAppPrint("Short poll forced to permanently enabled.");
FORCE_SHORT_POLL();
} else {
UNFORCE_SHORT_POLL();
}
emberEventControlSetInactive(emberAfPluginConnectionManagerRebootEventControl);
if (emberAfNetworkState() == EMBER_NO_NETWORK) {
emberAfPluginConnectionManagerLeaveNetworkCallback();
emberAfPluginConnectionManagerStartSearchForJoinableNetwork();
}
}
通过emberAfNetworkState()函数获取到当前设备没有连接任何网络的时候,就开始调用emberAfPluginConnectionManagerStartSearchForJoinableNetwork()去寻找可加入的网络
2、再看看emberAfPluginConnectionManagerRejoinEventHandler函数,其实做的事情也差不多,最后也调用到emberAfPluginConnectionManagerStartSearchForJoinableNetwork()去入网
connection-manager/connection-manager.c
//******************************************************************************
// Rejoin Event. This event is used to attempt a network rejoin and to verify
// that the parent node has not died.
//******************************************************************************
void emberAfPluginConnectionManagerRejoinEventHandler(void)
{
emberEventControlSetInactive(emberAfPluginConnectionManagerRejoinEventControl);
printNetworkState(emberAfNetworkState());
switch (emberAfNetworkState()) {
case EMBER_NO_NETWORK:
emberAfPluginConnectionManagerStartSearchForJoinableNetwork();
break;
case EMBER_JOINED_NETWORK_NO_PARENT:
// since the sensor is a sleepy end device, perform the secure rejoing
// every 30 minutes until we find a network.
emberAfAppPrintln("Perform and schedule rejoin");
emberEventControlSetDelayMinutes(
emberAfPluginConnectionManagerRejoinEventControl,
REJOIN_TIME_MINUTES);
emberAfStartMoveCallback();
break;
case EMBER_JOINING_NETWORK:
break;
default:
emberAfAppPrintln("No More Rejoin!");
break;
}
}
不过这里不是很明白为什么1、2点最后都调用到emberAfPluginConnectionManagerStartSearchForJoinableNetwork,不过最终的效果就是上电自动开始寻找可加入的网络
connection-manager/connection-manager.c
//------------------------------------------------------------------------------
// Plugin public API function implementations
// *****************************************************************************
// If this is the first search, search only on preferred channels
// Otherwise, search on all channels
// Make sure another attempt occurs in 40 seconds until 20 failures are seen
// If more than 20 network join attempts fail, inform user via callback
// *****************************************************************************
void emberAfPluginConnectionManagerStartSearchForJoinableNetwork(void)
{
if (emberAfMfglibRunning() || emberAfMfglibEnabled()) {
return;
}
if (networkJoinAttempts < REJOIN_ATTEMPTS) {
networkJoinAttempts++;
emberAfPluginNetworkSteeringStart();
emberAfPluginConnectionManagerStartNetworkSearchCallback();
// call the event in 40 seconds in case we don't get the stack status
// callback (which will happen if there's no network to join)
emberEventControlSetDelayQS(emberAfPluginConnectionManagerRejoinEventControl,
QS_BETWEEN_JOIN_ATTEMPTS);
} else {
emberAfAppPrintln("Failed to find network to join within %d attempts",
networkJoinAttempts);
emberAfPluginConnectionManagerFinishedCallback(EMBER_NOT_JOINED);
}
}
可以看到,我们的router设备会尝试REJOIN_ATTEMPTS这么多次,去寻找可加入的网络。具体到怎么搜索的流程我们暂时不看了,一旦找到了适合的网络,就会自动入网,我们看看串口打印:
Examining beacon on channel 12 with panId 0x614A
NWK Steering joining 0x614A on channel 12
EMBER_NETWORK_UP 0xBC6E
sched report event for: 0x03E7BED1
NWK Steering stack status 0x90
NWK Steering network joined.
Stack Status Handler: Processing message: len=12 profile=0000 cluster=0013
RX: ZDO, command 0x0013, status: 0x00
Device Announce: 0xBC6E
Processing message: len=11 profile=0104 cluster=0006
可以看到找到的网络的频段为12,PANID为0x614A。当状态发生变化时,比如"EMBER_NETWORK_UP"表示联网,就会走如下流程,修改相关的状态
zcl-framework-core/af-main-soc.c
// *******************************************************************
// Handlers required to use the Ember Stack.
// Called when the stack status changes, usually as a result of an
// attempt to form, join, or leave a network.
void emberStackStatusHandler(EmberStatus status)
{
emberAfPushCallbackNetworkIndex();
emAfStackStatusHandler(status);
emberAfPopNetworkIndex();
}
重点关注emAfStackStatusHandler()
zcl-framework-core/af-main-common.c
void emAfStackStatusHandler(EmberStatus status)
{
...
#ifdef EMBER_AF_GENERATED_PLUGIN_STACK_STATUS_FUNCTION_CALLS
EMBER_AF_GENERATED_PLUGIN_STACK_STATUS_FUNCTION_CALLS
#endif
...
}
又是通过宏定义来定义回调函数
YourProjectName_endpoint_config.h
#define EMBER_AF_GENERATED_PLUGIN_STACK_STATUS_FUNCTION_CALLS
emberAfPluginReportingStackStatusCallback(status);
emberAfPluginNetworkSteeringStackStatusCallback(status);
emberAfPluginConnectionManagerStackStatusCallback(status);
其中,
(1)emberAfPluginReportingStackStatusCallback()会上报设备默认的配置信息
// Generated reporting configuration defaults
#define EMBER_AF_GENERATED_REPORTING_CONFIG_DEFAULTS {
{ EMBER_ZCL_REPORTING_DIRECTION_REPORTED, 1, 0x0006, 0x0000, CLUSTER_MASK_SERVER, 0x0000, 1, 65534, 0 },
}
report的方向、endpoint、cluster ID、attribute Id等等。
(2)emberAfPluginNetworkSteeringStackStatusCallback()函数里面更新一些秘钥信息
(3)emberAfPluginConnectionManagerStackStatusCallback()函数里面没有做太多事情,就是reset一下networkJoinAttempts全局变量
3、最后我们再关注一下emberAfPluginNetworkSteeringFinishSteeringEventHandler()函数
network-steering/network-steering-v2.c
// =============================================================================
// Finish Steering
// At the end of the network steering process, we need to update the
// trust center link key (if we are in a centralized network) and broadcast
// a permit join to extend the network. This process needs to happen after
// we send our device announce and possibly our network timeout request if we
// are an end device.
void emberAfPluginNetworkSteeringFinishSteeringEventHandler(void)
{
...
// Broadcast permit join to extend the network.
// We are done!
status = emberAfPermitJoin(EMBER_AF_PLUGIN_NETWORK_STEERING_COMMISSIONING_TIME_S,
true); // Broadcast permit join?
emberAfCorePrintln("%p: %p: 0x%X",
PLUGIN_NAME,
"Broadcasting permit join",
status);
cleanupAndStop(status);
...
}
1、通过emberAfPermitJoin判断是否被允许入网
zcl-framework-core/af-main-common.c
// Public API
EmberStatus emberAfPermitJoin(uint8_t duration,
bool broadcastMgmtPermitJoin)
{
// Permit joining forever is bad behavior, so we want to limit
// this. If 254 is not enough a re-broadcast should be done later.
if (duration == EMBER_AF_PERMIT_JOIN_FOREVER) {
emberAfAppPrintln("Limiting duration of permit join from forever (255) to 254");
duration = EMBER_AF_PERMIT_JOIN_MAX_TIMEOUT;
}
return emAfPermitJoin(duration,
broadcastMgmtPermitJoin);
}
// Old API that doesn't restrict prevent permit joining forever (255)
EmberStatus emAfPermitJoin(uint8_t duration,
bool broadcastMgmtPermitJoin)
{
EmberStatus status = emberPermitJoining(duration);
emberAfAppPrintln("pJoin for %d sec: 0x%x", duration, status);
if (broadcastMgmtPermitJoin) {
status = broadcastPermitJoin(duration);
}
return status;
从注释可以看到,在等待被允许入网的时间是有限的,一直等下去是一个不好的行为,EMBER_AF_PLUGIN_NETWORK_STEERING_COMMISSIONING_TIME_S这个宏就定义了等待的时间,我这里是180s。
2、最后调用cleanupAndStop()函数完成最后的入网工作
network-steering/network-steering-v2.c
static void cleanupAndStop(EmberStatus status)
{
emberAfCorePrintln("%p Stop. Cleaning up.", PLUGIN_NAME);
emberAfPluginNetworkSteeringCompleteCallback(status,
emAfPluginNetworkSteeringTotalBeacons,
emAfPluginNetworkSteeringJoinAttempts,
emAfPluginNetworkSteeringState);
emAfPluginNetworkSteeringState = EMBER_AF_PLUGIN_NETWORK_STEERING_STATE_NONE;
emAfPluginNetworkSteeringJoinAttempts = 0;
emAfPluginNetworkSteeringTotalBeacons = 0;
emberEventControlSetInactive(finishSteeringEvent);
}
connection-manager/connection-manager.c
/** @brief Complete
*
* This callback is fired when the Network Steering plugin is complete.
*
* @param status On success this will be set to EMBER_SUCCESS to indicate a
* network was joined successfully. On failure this will be the status code of
* the last join or scan attempt. Ver.: always
* @param totalBeacons The total number of 802.15.4 beacons that were heard,
* including beacons from different devices with the same PAN ID. Ver.: always
* @param joinAttempts The number of join attempts that were made to get onto
* an open Zigbee network. Ver.: always
* @param finalState The finishing state of the network steering process. From
* this, one is able to tell on which channel mask and with which key the
* process was complete. Ver.: always
*/
void emberAfPluginNetworkSteeringCompleteCallback(EmberStatus status,
uint8_t totalBeacons,
uint8_t joinAttempts,
uint8_t finalState)
{
emberAfAppPrintln("Network Steering Completed: %p (0x%X)",
(status == EMBER_SUCCESS ? "Join Success" : "FAILED"),
status);
emberAfAppPrintln("Finishing state: 0x%X", finalState);
emberAfAppPrintln("Beacons heard: %dnJoin Attempts: %d", totalBeacons, joinAttempts);
emberAfAppPrintln("Connection Manager: Network Find status %x",
status);
if (status == EMBER_SUCCESS) {
emberEventControlSetInactive(emberAfPluginConnectionManagerRejoinEventControl);
} else {
// delay the rejoin for the retry time in seconds set by plugin option
emberEventControlSetDelayQS(emberAfPluginConnectionManagerRejoinEventControl,
(REJOIN_FAILED_RETRY_TIME_QS));
}
}
入网成功的串口打印如下:
pJoin for 180 sec: 0x00
NWK Steering: Broadcasting permit join: 0x00
NWK Steering Stop. Cleaning up.
Network Steering Completed: Join Success (0x00)
Finishing state: 0x05
Beacons heard: 1
Join Attempts: 1
Connection Manager: Network Find status 00
Processing message: len=11 profile=0104 cluster=0006
结语
同样,断网"EMBER_NETWORK_DOWN"同样调用emberStackStatusHandler()函数,流程可以类似的分析了
最后
以上就是霸气万宝路为你收集整理的芯科ZigBee Minimal Application入网流程分析的全部内容,希望文章能够帮你解决芯科ZigBee Minimal Application入网流程分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复