Z-Wave 700应用程序框架第四章 - 从零开始一个Z-Wave Plus应用

图片

Z-Wave Plus应用程序的基本功能由设备类型和角色类型定义。为Z-Wave Plus应用程序确定设备类型和角色类型的正确组合是很重要的。  

一旦确定了设备和角色类型,就可以开始应用程序开发。 

1. 创建应用程序文件夹并设置构建环境

1.1 选择要创建的应用程序角色

选择一个现有的软件样本,并修改它以满足您的需求。主要根据角色类型进行选择:  

  • 总是工作终端设备: SwitchOnOff, WallController, PowerStrip  

  • 报告睡眠终端设备: SensorPIR  

  • 侦听睡眠终端装置: DoorLock  

此外,还有一些其他的选择要考虑  

  • Endpoint实现由Power Strip支持。  

  • 关联组在Wall Controller中实现。 

1.2 创建一个新的Simplicity Studio项目

按照以下步骤设置应用程序的工作目录

1.  要对构建环境有一个大致的了解,请参阅[3]以获得更多信息。  

2.  选择其中一个应用程序并在Simplicity studio中创建一个示例项目。  

3. 通过重命名根文件夹,例如<MyApp>,将导入的应用程序重命名为适合应用程序的名称。  

4.  导航到<MyApp>/src文件夹,将.c文件重命名为<MyApp>.c。  

5.  对于任何其他示例,搜索APP_FREQ并将其替换为您正在使用的频率。要了解更多细节,请参考[3]中的第6章。  

6.  构建应用程序以验证更改没有破坏任何内容。也可以将应用程序下载到芯片上,以检查应用程序是否运行无误。 

2. 配置config_app.h

2.1 通用类型、特定类型和设备选项

一个Z-Wave Plus设备必须使用以下两个定义指定一个通用设备类和一个特定设备类:  

  • GENERIC_TYPE

  • SPECIFIC_TYPE

请参考Z-WaveDevelopment Basics和Z-WavePlus v2 Device Type Specification为您的产品选择适当的通用和特定设备类。标识符值在ZW_classcmd.h中定义。  

DEVICE_OPTIONS_MASK是一个位掩码,用于指定一组设备选项。有关详细信息,请参阅ZW_basis_api.h文件。 

2.2 角色类型、节点类型、图标类型、用户图标类型(Z-Wave Plus Info CC)  

角色类型、节点类型、图标类型和用户图标类型都是Z-Wave Plus命令类使用的值。它们使用以下定义进行设置:  

  • APP_ROLE_TYPE 

  • APP_NODE_TYPE 

  • APP_ICON_TYPE 

  • APP_USER_ICON_TYPE

关于在Z-Wave Plus Info CC中使用的图标类型的进一步信息,请参考Z-WavePlus Assigned Icon Types。联系Z-Wave联盟获取新的图标类型。

2.3 Manufacturer Specific CC / 固件更新

Manufacturer specific CC需要定义一些特定于产品的值。有关更多信息,请参阅Z-WaveManagement Command Class Specification中的制造商特定命令类。ZAF使用以下宏来处理这些值 :

  • APP_MANUFACTURER_ID 

  • APP_PRODUCT_TYPE_ID 

  • APP_PRODUCT_ID

固件更新命令类使用以下定义:  

  • APP_FIRMWARE_ID: 固件ID由产品类型ID和产品ID组成。  

制造商和产品ID用于从制造商的角度识别Z-Wave产品。其他应用程序也可以使用这些信息在用户界面上显示公司标识、产品类型、用户指南等。该信息通过Manufacturer Specific C交互,当前分配的制造商ID列在ZW_classcmd.h文件中。

2.4 关联组信息(AGI)

在应用程序中,AGI必须在config_app.h中配置。  

对于Z-Wave Plus产品,生命线组是强制性的。它可以使用以下声明来定义: 

#define AGITABLE_LIFELINE_GROUP \ {<command class X>, <command A>}, \ {<command class Y>, <command B>}, \ {<command class Z>, <command C>}

参考Z-WavePlus v2 Device Type Specification可以了解在生命线组中要使用哪些事件和命令类。命令类和命令的定义可以在ZW_classcmd.h中找到。

如果应用程序没有实现Multi Channel端点,其他组(除了生命线)必须使用以下格式定义:  ​​​​​​​

#define AGITABLE_ROOTDEVICE_GROUPS \ {<profile 1 MSB>, <profile 1 LSB>, {<command class X, command A}, "<group 2 name>"}\ {<profile 2 MSB>, <profile 2 LSB>, {<command class X, command A}, "<group 3 name>"}

如果应用程序实现Multi Channel端点,则必须使用端点组填写AGI定义。多通道端点实现的一个例子是Power Strip应用。​​​​​​​

#define AGITABLE_ROOTDEVICE_GROUPS \ AGITABLE_ENDPOINT_1_GROUPS, \ AGITABLE_ENDPOINT_2_GROUPS, \ AGITABLE_ENDPOINT_3_GROUPS, \ AGITABLE_ENDPOINT_4_GROUPS

AGITABLE_ENDPOINT_X_GROUPS表示端点x的非生命线组。每个端点组都被定义为由AGITABLE_ROOTDEVICE_GROUPS定义的根设备组,但有一个匹配的定义名、其他配置文件、命令类等。​​​​​​​

#define AGITABLE_ENDPOINT_1_GROUPS \ {<profile X MSB>, <profile X LSB>, {<command class>, <command>}, "group name"}, \ {ASSOCIATION_GROUP_INFO_REPORT_PROFILE_CONTROL, ASSOCIATION_GROUP_INFO_REPORT_PROFILE_CONTROL_KEY01, {COMMAND_CLASS_SWITCH_MULTILEVEL_V4, SWITCH_MULTILEVEL_SET_V4}, "Button 1"}

当产品实现Multi Channel端点时,它必须映射到根关联组。根组映射提供向后兼容性,因为不支持Multi Channel的设备必须能够询问根设备支持哪些组。根组映射定义到端点组的根设备映射中的组。 

Root Device Group

Endpoint ID

Endpoint Ggroup ID

Root Device Group 2

Endpoint 1

Endpoint 1 Group 2

Root Device Group 3

Endpoint 2

Endpoint 2 Group 2

下面显示了如何在config_app.h中配置根组映射。根组映射设置的详细信息取决于应用程序。​​​​​​​

#define ASSOCIATION_ROOT_GROUP_MAPPING_CONFIG \ {<ROOT DEVICE GROUP 2>, <ENDPOINT ID 1>, <ENDPOINT GROUP 2>}, \ {<ROOT DEVICE GROUP 3>, <ENDPOINT ID 2>, <ENDPOINT GROUP 2>}

请参考Wall Controller应用程序中的config_app.h文件获取组映射的示例。SensorPIR还显示了AGI是如何设置的。  

组定义用于在应用程序的main源文件中初始化AGI。

2.5 安全

安全级别在config_app.h文件中配置,并定义了REQUESTED_SECURITY_KEYS标志。定义可以在ZW_security_api.h文件中找到。  

开发产品时必须指定应用程序安全级别位。安全级别为默认值No-secure。 

#define REQUESTED_SECURITY_KEYS \ (SECURITY_KEY_S2_UNAUTHENTICATED_BIT|SECURITY_KEY_S0_BIT)

添加功能:  

ApplicationSecureKeysRequested()包含安全密钥标志REQUESTED_SECURITY_KEYS。 

2.3 设置config_rf.h

Tx功率应该通过修改文件config_rf.h来设置,以符合当地监管机构的要求。  

该文件包含2个定义: ​​​​​​​

#define APP_MAX_TX_POWER 0#define APP_MEASURED_0DBM_TX_POWER 33

其中,APP_MEASURED_0DBM_TX_POWER用于在传导环境中将TX功率调谐到0dbm。在旋转过程中,‘APP_MAX_TX_POWER’应该为0 (0dBm)。  

APP_MAX_TX_POWER取值范围为-100 ~ +100 deci dBm (-10dBm ~ +10dBm),用于Tx功率调优完成后,应用框架对Tx功率进行调整。

有效范围是:

100 >= (APP_MAX_TX_POWER + APP_MEASURED_0DBM_TX_POWER) >= -100

要设置最大功率,请使用​​​​​​​

#define APP_MAX_TX_POWER 100#define APP_MEASURED_0DBM_TX_POWER 0

设置TX功率的步骤

a) 将APP_MAX_TX_POWER设置为0,将APP_MEASURED_0DBM_TX_POWER设置为0,编译应用程序。  

b) 使用产品上的这些设置对Tx功率进行测量。重要的是,这是在成品上完成的。  

c) 将APP_MEASURED_0DBM_TX_POWER设置为测量的传导值。  

d) 将“APP_MAX_TX_POWER”设置为产品使用区域所需/允许的Tx功率。  

e) 编译固件。

f) 按照调节限值(步骤d)进行调节辐射测量,例如50deci dBm (5 dBm)。如果调节测量允许再增加1/2db,则将1/2dbm改为55并重新编译。如果一个方向的辐射太高,例如需要少1/2db,那么将其改为45deci dBm并重新编译。

2.4 设置非易失性存储器

所有应用程序都必须打开一个NVM3[18]文件系统,ZAF使用该文件系统在非易失性内存中存储文件。应用程序还可以使用文件系统来存储应用程序特定的文件。通过调用在ZAF_nvm3_app.c中找到的applicationfilesystemit(..)函数来打开文件系统。  

应用文件系统在flash中占用12k字节。为了使文件系统在所有情况下都能正常工作,建议在其中存储的数据不要超过4k字节,包括应用程序特定的文件和ZAF使用的文件。应用程序开发人员不能增加应用程序文件系统的默认大小(NVM3_APP_NVM_SIZE),因为这会使它与用于存储Z-Wave协议文件的区域冲突。  

NVM3文件系统使用RAM中的缓存在flash中存储文件的位置。默认情况下,缓存中的最大文件数设置为10。如果ZAF和应用程序使用的文件总数超过10,则必须相应地增加ZAF_nvm3_app.c中的NVM3_APP_CACHE_SIZE,否则文件系统将大大减慢。 

必须为NVM3文件系统中的每个文件分配一个单独的20位对象密钥,作为文件标识[18]。整数范围0x51000-0x5FFFF已经被保留用作ZAF的文件标识符,并且不能用于特定于应用程序的文件。特定于应用程序的文件最好使用范围为0x00000-0x0FFFF的标识符。

每个示例应用程序都列出了它在一个名为g_aFileDescriptors[]的数组中使用的文件。该列表包含应用程序中ZAF使用的文件标识符和文件大小。一些示例应用程序在列表中还包含特定于应用程序的文件。在启动时,应用程序检查列表中的所有文件是否都在文件系统中。所有应用程序文件系统都必须有一个文件标识符ZAF_FILE_ID_APP_VERSION,该文件包含应用程序的版本号。如果该文件丢失,则认为该文件系统未写入或损坏,从而重新格式化该文件系统,并将所有文件设置为默认值。  

要将特定于应用程序的文件引入到文件系统,只需定义一个尚未使用的新的20位对象键值。一旦使用函数nvm3_writeData()首次写入该文件,该文件将被添加到文件系统中。​​​​​​​

#define FILE_ID_MYNEWFILE (0x00112)typedef struct SMyAppData{ int32_t status; uint8_t vector[10];} SMyAppData;SMyAppData wrtData;wrtData.status = -5;memset(&(wrtData.vector), 0x55, sizeof(wrtData.vector));//This call will create and write a file containing wrtData in the file system.nvm3_writeData(pFileSystemApplication, FILE_ID_MYNEWFILE, &wrtData, sizeof(wrtData));SMyAppData rdData;//This call will read the content of the file to rdData. Please be warned that it is//not possible to read part of the file. If sizeof(rdData) < sizeof(wrtData) above, //the read function will return an error.nvm3_readData(pFileSystemApplication, FILE_ID_MYNEWFILE, &rdData, sizeof(rdData));

建议将默认内容写入函数SetDefaultConfiguration()中特定于应用程序的文件,该函数将在格式化文件系统后调用。 

执行固件更新时,应用程序文件系统的内容保持不变。如果文件标识符保持不变,则仍然可以使用以前固件使用的旧文件。当开发固件的新版本时,需要增加应用程序config_app.h中的APP_VERSION、APP_REVISION或APP_PATCH号,在其中添加新文件或以任何方式更改文件。引导加载程序不接受版本号较低或相同的文件。然后,在新固件的第一次启动时,应用程序将能够通过读取标识符ZAF_FILE_ID_APP_VERSION的文件来识别芯片上的文件系统属于旧版本的固件。

2.5 看门狗使能/禁用

看门狗定时器在应用程序中默认是启用的,如果应用程序任务运行超过1秒而不释放处理器,将重置设备。

为了在开发过程中禁用看门狗,注释掉ApplicationTask函数内部的WDOGn_Enable()函数调用,如下所示:  

注意:看门狗应该总是在生产代码中启用,但可以在调试版本中禁用 ​​​​​​​

static voidApplicationTask(SApplicationHandles* pAppHandles){ // Init DPRINT("Enabling watchdog\n"); WDOGn_Enable(DEFAULT_WDOG, true); <<-- Comment out this line to disable the watchdog

2.6 应用程序源文件

应用程序必须实现一个用于初始化的函数:ApplicationInit(..)。该函数在系统启动时被Z-Wave主函数调用,并获得唤醒原因作为输入参数,请参阅ZW_basis_api.h文件。应用程序特定的硬件初始化,如引脚配置,应该从这个函数完成。配置完成后,函数必须通过调用ZW_UserTask_ApplicationRegisterTask(..)来注册应用程序任务,以便应用程序可以开始运行。

应用程序任务函数ApplicationTask(..)被FreeRTOS注册在准备运行的任务列表中。在软件示例中,ApplicationTask(..)在启动时首先执行特定于应用程序的软件初始化。其中,它使用针对不同类型事件的事件处理程序来配置事件分发功能。随后,它进入无限循环,让事件分发程序处理任何事件。参见9.5节中的描述。FreeRTOS调度器将确保应用程序任务根据其优先级得到处理器时间。 

2.6.1 配置命令类列表

应用程序使用3个命令类列表根据包含状态发送节点信息帧(NIF)。这三个列表定义了以下的​​​​​​​

NIF:  - Not included - Non-securely included - Securely included

以下命令类列表用于节点未被包含或未被安全包含的情况。当包含设备时,Security和Security_2命令类将被ZAF删除。这个命令类列表出现在NIF中: 

static code BYTE cmdClassListNonSecureNotIncluded[]

以下命令类列表在安全包含节点时使用。它表示不安全支持的命令类,即使设备已经安全地包含在内。

static code BYTE cmdClassListNonSecureIncludedSecure[]

以下命令类列表在安全包含节点时使用。它只包含安全支持的命令类。该命令类列表通过安全命令类、支持的安全命令报告命令发布。

static BYTE cmdClassListSecure[]

2.6.2 Endpoint配置

如果您的设备必须实现端点,那么必须在config_app.h文件中设置AGI和关联组映射。在AGI中配置每个端点之后(参见2.4节),必须调用AssociationInitEndpointSupport()而不是AssociationInit()来进行关联组映射。

最后,需要通过调用Transport_AddEndpointSupport()函数为端点初始化传输层。这个函数设置端点的功能和命令类列表。请阅读[13]以获得关于单个端点和聚合端点的更多信息。

void Transport_AddEndpointSupport( EP_FUNCTIONALITY_DATA* pFunctionality, EP_NIF* pList, BYTE sizeList);

2.6.3 多线程应用

Z-Wave应用程序默认运行以下线程:  

  • Z-Wave协议线程,用于执行协议栈  

  • 主应用程序线程用于执行应用程序代码,并作为Z-Wave协议线程的接口。

一个应用程序可以扩展创建额外的FreeRTOS线程\任务。这些线程被称为用户任务,以区别于主应用程序线程(负责与Z-Wave协议线程通信)。 

用户任务是使用ZW_UserTask模块(ZW_UserTask.h)创建的,该模块包含ZW_UserTask_t数据类型的定义和可用api用于创建任务。 

ZW_UserTask_t定义如下:

typedef struct { TaskFunction_t pTaskFunc; char* pTaskName; void* pUserTaskParam; ZW_UserTask_Priority_t priority; ZW_UserTask_Buffer_t* taskBuffer;} ZW_UserTask_t;
  • pTaskFunc是任务执行的函数  

  • pTaskName为任务名称  

  • pUserTaskParam是传递给任务函数的参数指针  

  • priority是任务的优先级。可用的优先级有: 

       > USERTASK_PRIORITY_BACKGROUND  

       > USERTASK_PRIORITY_NORMAL  

       > USERTASK_PRIORITY_HIGHEST 

  • taskBuffer是FreeRTOS处理任务所需的静态分配内存。

以下是可用的api

ReturnCode_t ZW_UserTask_Init(void);
  • ZW_UserTask_Init() 函数用于初始化ZW_UserTask模块。不需要显式地调用它,因为它在引导时已经被调用了。

           > 如果再次调用该函数,它将返回Code_Fail_InvalidState

ReturnCode_t ZW_UserTask_CreateTask(ZW_UserTask_t* task, TaskHandle_t* xHandle);
  • ZW_UserTask_CreateTask() 可以用于创建额外的任务。

          > 此函数需要以下输入参数

             task是指向ZW_UserTask任务参数的指针。  

             xHandle是FreeRTOS返回的任务句柄。

          > 这个函数可以返回以下代码:

             Code_Fail_InvalidState—如果模块还没有初始化。  

             Code_Fail_InvalidOperation—如果已经创建了最大的用户任务。  

             Code_Fail_InvalidParameter—如果优先级设置超出界限或任何输入参数为NULL。  

             Code_Fail_Unknown—如果FreeRTOS创建任务失败。​​​​​​​

bool ZW_UserTask_ApplicationRegisterTask( VOID_CALLBACKFUNC(appTaskFunc)(SApplicationHandles*), uint8_t iZwRxQueueTaskNotificationBitNumber, uint8_t iZwCommandStatusQueueTaskNotificationBitNumber, const SProtocolConfig_t * pProtocolConfig);
  • ZW_UserTask_ApplicationRegisterTask() 用于创建主应用程序线程。关于函数使用和行为的更多详细信息,请参见2.6节。

有关api的更多信息,请参阅ZW_UserTask.h文件。有关可用返回码的详细信息,请参阅ZW_global_definitions.h中定义的ReturnCode_t。  

一个如何使用这些api的例子可以在SensorPIR应用程序中找到(参见SensorPIR.c中的ApplicationInit(…))

2.6.3.1 限制和建议

以下限制和建议适用于用户任务:  

  • 除了主应用程序线程之外,最多可以创建三个用户任务。  

  • UserTask优先级的分配都低于Z-Wave协议线程的优先级(这在定义可用优先级级别的ZW_UserTask模块中强制执行)。  

  • 在FreeRTOS调度程序启动之前必须创建用户任务(使用函数ZW_UserTask_CreateTask),因此,它们的创建只能在ApplicationInit(…)中进行(参见7.6节)。  

  • 没有提供主应用程序线程和用户任务之间的通信。但是,建议使用FreeRTOS队列和事件。

  • 用户任务不能直接与Z-Wave协议线程通信。它们需要使用主应用程序线程作为中介。 

          > 除了电源管理器api,它可以从所有任务中调用。 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Smartlabs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值