如何使用调试模式来设置网络

file
重要说明:之前,我们的Zigbee堆栈是作为Gecko SDK(GSDK)的一部分发布的。现在,Zigbee堆栈作为Simplicity SDK(SiSDK)的一部分发布。随着这一转变,所有名称中包含EMBER的公共Zigbee API、枚举等均已更名。这些更改的过渡指南可以在此处找到。

例如,本文中引用的以下名称在GSDK和SiSDK之间已经发生了变化:

emberJoinNetwork() -> sl_zigbee_join_network()
EmberNetworkParams -> sl_zigbee_network_parameters_t
EMBER_USE_CONFIGURED_NWK_STATE -> SL_ZIGBEE_USE_CONFIGURED_NWK_STATE

调试模式(Commissioning Mode)的主要目的是在不使用标准关联过程的情况下设置网络。

一般的方法是,在一个包含所有所需网络信息的“虚拟”网络中加载所有属性,然后使用调试模式加入一个新的网络。

为了更深入地了解,你需要对协调器(Coordinator)和路由器(Routers)使用emberJoinNetwork()函数。对于终端设备(End Devices),你不能直接使用调试加入方法,因为它们需要父节点。当你以这种方式加入网络时,你需要将emberJoinNetworkEmberNetworkParams.joinMethod设置为"EMBER_USE_CONFIGURED_NWK_STATE",这在GSDK的stack/include/ember-types.h文件和SiSDK的stack/include/sl_zigbee_types.h文件中有所描述。这样做时,你可以通过填写EmberNetworkParameters结构体中剩余的成员(如nwkManagerId、nwkUpdateId和channels)来设置你的设备。

在加入网络之前,你还需要设置初始安全状态。初始安全状态结构体也在stack/include/ember-types.h中定义,并要求你在EmberInitialSecurityBitmask中设置EMBER_HAVE_TRUST_CENTER_EUI64、EMBER_HAVE_PRECONFIGURED_KEYEMBER_HAVE_NETWORK_KEY,并且你需要在EmberInitialSecurityState结构体中提供这些项对应的EUI64和密钥数据。

简而言之,调试模式允许你在没有标准关联过程的情况下,通过预配置的网络参数和安全设置来加入网络。这通常用于初始化网络设置,特别是在设备首次部署或需要快速更换网络环境时。

由于您无法使用此方法与终端设备(End Devices)进行关联,因此最佳方法可能是基于先前已知的参数“强制”终端设备加入特定网络。通过使用EMBER_USE_NWK_REJOIN_HAVE_NWK_KEY作为joinMethod,终端设备可以在已经加入的网络中,与任何可用的父设备执行相当于安全重新加入的操作。

关于emberJoinNetwork()函数和EmberNetworkParameters结构体的信息,请查阅stack/include/network-formation.h文件。

以下代码示例基于EmberZnet 6.7.4版本。请注意,在Zigbee 3.0网络中,如果信任中心没有为加入的设备添加传输链路密钥(通过CLI命令plugin network-creator-security open-with-key来操作),则更新链路密钥将失败。

这意味着,在尝试让终端设备重新加入网络之前,您需要确保信任中心已经准备好接受该设备,并已经设置了必要的密钥和权限。在Zigbee 3.0中,安全性得到了增强,因此网络创建者和信任中心需要执行额外的步骤来确保新设备的安全加入。

此外,对于终端设备来说,由于它们依赖于父设备来转发消息,因此它们不能独立地执行完整的网络形成过程。相反,它们必须找到并加入一个已存在的网络,这通常是通过扫描附近的网络并选择一个信号强度足够且允许它们加入的网络来完成的。在调试模式下,您可以通过预配置网络参数和安全密钥来简化这个过程,但这仍然需要信任中心的配合和授权。

void setupZ3Security(void)
{
  EmberEUI64 TrustCenterEui64;
  EmberKeyData NetworkKey;
  EmberStatus status;
  EmberInitialSecurityState state={0};
  uint8_t PRECONFIGURED_KEY[EMBER_ENCRYPTION_KEY_SIZE] ={ 0x5A, 0x69, 0x67, 0x42, 0x65, 0x65, 0x41, 0x6C,0x6C, 0x69, 0x61, 0x6E, 0x63, 0x65, 0x30, 0x39};
  emberCopyBigEndianEui64Argument(0, TrustCenterEui64);
  emberCopyKeyArgument(1, &NetworkKey);

  state.bitmask = (EMBER_HAVE_PRECONFIGURED_KEY
                   | EMBER_HAVE_NETWORK_KEY
                   | EMBER_HAVE_TRUST_CENTER_EUI64
                   | EMBER_NO_FRAME_COUNTER_RESET
                   );

  MEMCOPY(emberKeyContents(&(state.preconfiguredKey)), &PRECONFIGURED_KEY, EMBER_ENCRYPTION_KEY_SIZE);
  MEMCOPY(emberKeyContents(&(state.networkKey)), &NetworkKey, EMBER_ENCRYPTION_KEY_SIZE);
  MEMCOPY(state.preconfiguredTrustCenterEui64, &TrustCenterEui64,EUI64_SIZE);
  state.networkKeySequenceNumber = 0;
  if ((status = emberSetInitialSecurityState(&state))
      != EMBER_SUCCESS) {
    emberAfCorePrintln("Error: could not setup security: 0x%X", status);
  }
}
void commissioning_join(void)
{
  EmberNetworkParameters networkParams={0};
  networkParams.radioChannel = (uint8_t)emberUnsignedCommandArgument(0);
  networkParams.radioTxPower = (int8_t)emberSignedCommandArgument(1);
  networkParams.panId = (uint16_t)emberUnsignedCommandArgument(2);
  networkParams.joinMethod = EMBER_USE_CONFIGURED_NWK_STATE;
  networkParams.nwkManagerId = 0x0000;
  networkParams.nwkUpdateId = 0;
  emberCopyBigEndianEui64Argument(3,networkParams.extendedPanId);
  EmberStatus status = emberJoinNetwork(EMBER_ROUTER, &networkParams);
  if (EMBER_SUCCESS != status) 
    emberAfCorePrintln("Error: could not join: 0x%X",status);
}
EmberCommandEntry emberAfCustomCommands[] = {
  emberCommandEntryAction("commissioning-setup-security", setupZ3Security, "bb", ""),
  emberCommandEntryAction("commissioning-join", commissioning_join, "usvb", ""),
  emberCommandEntryTerminator()
};