文章主题 

在开发一个 ZWave Device 的过程中,对 COMAND CLASS(单词太长了,后面就简写为 CC 啦) 的处理是最基本、最重要的工作。这篇文章以最最简单的 CC:COMMNAD_CLASS_BASIC 为例子,来拆解、分析应用层对它的处理流程。

内容导航 

  • 接收指令

  • 处理指令

  • 发送数据

 接收指令  

1. 指令接口函数

我们就以一个最简单的场景为示例:网关 G 发送指令:COMMNAD_CLASS_BASIC 给设备 D。这个 CC 包含 3 个 COMMAND,分别是: BASIC_GET, BASIC_REPORT, BASIC_SET,官方提供的文档里对这 3 个命令有详细解释。(这里要说一句:官方的文档太 TMD 的多了,多的看不过来!)

先上图1:

是不是太乱了,有点接受不了啊?将就着看吧,我已经尽最大努力了,如果你会 PS,可以教教我。

也就是上图中标记0的地方,看起来是不是这些数据结构挺挺长、挺吓人的?!其实 C 语言开发中,我觉得核心就是数据结构和算法,其中数据结构又决定了算法。在分析 ZWave 代码的过程中,有很大一部分就是分析数据结构,当然了这是我的观点。

图中标记1是返回值的定义,它是一个枚举类型。

图中标记2是参数 rxOpt 的数据结构,它是一个结构体,这里结构体里面关于 NODE_ID 的解释可以看一下源代码,比较简单。

图中标记3是参数 pCmd 的数据结构,这里是重点:这是一个[共用体],简单的说,就是内存中的一块地址空间,你可以按照不同的组织方式去理解其中保存的内容。

2. 关于 C 语言的共用体/共同体/union

刚才的藐视似乎有点拗口,举个栗子,比如:有一块地址空间一共有 4 个字节的容量:

  • 你可以定义一个指针 char *p, p 指向这个地址空间的首地址 A,然后你就可以读取或者写入一 char 类型的数据;然后移动指针 p 到第二个字节的位置 A+1,读取或者写入另一 char 类型的数据;再然后是第三个字节的地址 A+2;再然后是第四个字节的地址 A+3。

  • 你也可以定义一个指针 int *p,指针 p 指向这个地址空间的首地址 A,此时,你可以直接读取/写入一个 4 字节的 int 型数据。

理解了上面的内容,那么对 ZWave 指令部分的处理可以说就理解一半了。回到参数 pCmd,当设备D 接收到不同的 CC 指令时,这个指针所指向的地址空间就保存了不同的数据(什么?这个地址空间是在哪里分配的?我也不知道。可以肯定的是协议层为我们准备好的,应用开发者不用操心这个事情)。至于如何解析这些指令,当然是参考官方提供的文档,其中详细说明了每一个 CC 所对应的指令中,每一个字节,每一个 bit 代表什么意思。

注意:在这个地址空间中,开头2个字节的意思一定是确定的,也就是图1中标记5列出的:cmdClass 和 cmd。

所以,在这个指令接收函数中,首先通过

pCmd->ZW_Common.cmdClass

来判断该指令是哪一个 COMMAND CLASS。也就是说,pCmd 理解成:这个指针指向了 ZW_COMMON_FRAME 这个结构体。所以,我们就知道了当前的指令是:COMMAND_CLASS_BASIC,从而进入了第一个 case 中调用处理函数:

handleCommandClassBasic()

处理指令  

handleCommandClassBasic( ) 函数位于 ApplicationHandlers 文件夹下面,这里应该说是官方为了降低开发者的难度,把所有 CC 的处理逻辑的共性提取出来。

继续上图:图2。

好像比图1更乱了?!真的是尽力了。

这个函数首先判断指令是 COMMAND_CLASS_BASIC 中的哪一个 COMMAND: BASIC_SET or BASIC_GET。

1. BASIC_SET

看到没?参数 pCmd 又指向了另一个数据结构,即图中标记1处的 ZW_BASIC_SET_V2_FRAME。如果这里没有明白,需要回到上面再重新理解一下。

首先检查了参数 value 的范围,BYTE 的类型是通过 typedef 定义的,本质上是 unsigned char。ZWave 对 Basic Value 允许的范围是 0x00~0x63, 以及 0xFF,反正是代表不同的意思了。

然后调用函数 handleBasicSetCommand。 这个函数是什么鬼?在哪里? 原来这个函数是需要开发者自己实现的,官方已经替你在 CommandClassBasic.h 中声明了这个函数是外部的,也就是需要开发者实现的。

可以看到,传递了2个参数:

  • pCmd->ZW_BasicSetFrame.value

  • rxOpt->destNode.endpoint

第一个参数是设置的 value,第二个参数是说这个value是用来设置哪一个 EndPoint 的,比如接收指令的设备是一个有4个插孔的排插,那么每一个插孔就是一个 EndPoint。当然,如果当设备就是一个灯泡,那么这个 EndPoint 就等于0。

2. BASIC_GET

从字面上理解:就是发出指令的网关G要从接收指令的设备D获取一些信息,比如灯泡的亮度,那么设备D就要把当前的亮度值发送给网关G。于是,这里的处理流程是:

2.1 申请地址空间

申请的这块地址空间赋值给 pTxBuf,待会需要发送的数据就往这个地址放,图中标记2的地方。先看一下文件 ZW-tx_mutex.c 中一个重要的结构体变量:

static MUTEX myMutex;

这个 MUTEX 结构体定义在图中标记3处,也就是说,在系统的数据区域,默认定义了一块内存地址,专门用于在发送数据时使用。正因为这块地址空间是共用的,所以每个时刻只能有一个人使用,所以使用互斥量来保护这块地址空间。

简言之:谁先抢到谁先用(上锁),用完之后要归还(解锁)。

2.2 设置发送者、接收者参数

RxToTxOptions(rxOpt, &pTxOptionsEx);这个函数的作用就是:设置接收数据的nodeId 好 endpoint等参数, 发送者(也就是当前设备自己)的 sourceEndpoint, 以及其他一些安全上属性,都是从 rxOpt中复制而来。此时,设备D变成了发送者,网关G就编程了接受者。

注意这个函数中的2个静态变量:txOptionsEx, destNode。

2.3 往第一步得到的内存地址空间填数据

至于需要填哪些数据,看文档!

COMMAND_CLASS_BASIC 的 BASIC_GET 需要返回3个数据:

  • currentValue

  • targetValue

  • duration

    这3个数据都是由开发者定义的3个函数提供,至于这几个值代表什么意思,就需要开发者根据所开发的具体产品类型来决定了。拿灯泡做栗子,当前亮度是50,目标亮度是80,还需要5秒钟达到目标亮度值。

2.4 发送数据

所有的数据发送都是调用函数Transport_SendResponseEP,传递的几个参数格式都是固定的,如果继续跟进到这个函数里,又是一个天地,特别是涉及到 MultiChannel 部分,也是比较复杂,以后再单独拿出来分析。

别忘了,发送完成之后,调用了函数 FreeResponseBuffer,把申请的内存地址空间释放掉,这里并不是 free掉,而只是解锁一下,对系统说:谢谢,我已经使用结束了,现在别人可以申请使用了。

总结  

到这里,COMMAND_CLASS_BASIC 的分析过程就结束了,其他的 COMMAND CLASS 执行流程是完全一样的,有区别的地方就在于不同 CC 携带了不同的数据结构,当然,最开头的2个字节永远是固定的:cmdClass 和 cmd。

请容忍我再啰嗦两句啊。

ZWave 的开发博大精深,文档更是数不胜数。我进入 ZWave 的开发时间不长,以上分析过程难免会存在一些理解上的错误,希望没让您误入歧途。另外,知识的学习都是螺旋式的,不能追求一下子把所有相关的东西都理解正确,只要能满足当前的开发需求就可以了,循序渐进的提高、进步,最后就一定能够得到真经。

ZWave对 COMAND CLASS 的处理流程相关推荐

  1. c专家编程/c陷阱_编程中的进取陷阱

    c专家编程/c陷阱 "Gumption traps" are a term introduced by Robert M. Pirsig in Chapter 26 of Zen ...

  2. Z-Wave技术与zipgateway源码剖析

    1 Z-Wave简介 1.1 什么是Z-Wave技术 Z-Wave是一种新兴的基于射频的.低成本.低功耗.高可靠.适于网络的短距离无线通信技术.工作频带为908.42MHz(美国)~868.42MHz ...

  3. ENode 2.0 - 深入分析ENode的内部实现流程和关键地方的幂等设计

    前言 ENode是一个基于消息的架构,使用ENode开发的系统,每个环节都是处理消息,处理完后产生新的消息.本篇文章我想详细分析一下ENode框架内部是如何实现整个消息处理流程的.为了更好的理解我后面 ...

  4. M 平台按键强制升级流程分析

    mstar 平台升级流程主要是在mboot 开机过程中进行,检测不通的触发条件从而进入升级流程.我们首先熟悉一个mboot的 启动流程. 启动流程 汇编部分不通方案也大致相同,我们主要以C部分启动流程 ...

  5. 15款奔驰C200的车载系统语言,汽车遇到互联网(16):体验奔驰COMAND系统

    版权声明:本文版权为网易汽车所有,转载请注明出处. 网易汽车9月25日报道 在此前车联网的系列体验中,编辑相继体验了宝马iDrive系统和奥迪的MMI系统.而作为德系传统豪车品牌"BBA&q ...

  6. Z-WAVE TIME AND DATE BASICS ZWAVE网络中的时间管理

    Z-WAVE TIME ANDDATE BASICS  qq:380939960 在Z-Wave网络中,如果设备需要显示时间或者做一些基于时间的控制操作时,它需要知道当前时间.此时设备可以通过Time ...

  7. 怎么着手开发一个Zwave产品?

    开发一个zwave的工作: 1).选择设备工作地区 2).选择设备类型 3).选择角色类型 4).最小规格 5).完成基础功能和额外功能 6).完整规格(硬件需求文档,角色类型,设备类型功能,附加功能 ...

  8. ZWave 中的消息队列机制

    文章主题 文章主题   在我们的日常编程中,对消息队列的需求非常常见,使用一个简洁.高效的消息队列编程模型,对于代码逻辑的清晰性,对于事件处理的高效率来说,是非常重要的.这篇文章就来看看 ZWave ...

  9. ios app版本更新流程及问题总结

    ** ios app版本更新流程 ** 由于我是接手别人的项目进行上架,没有相关证书,描述文件或者p12文件,而且项目的发布证书也快要到期了,所以我新建发布证书ios_distribution.cer ...

最新文章

  1. 智慧农场基本情况交流会议记录
  2. 修改 ASP.NET 请求队列的限制
  3. oracle的操作大全,Oracle数据库操作大全(六)Oracle中操作数据
  4. JavaScript Debug 之 Console
  5. python连乘函数_Python常用的几种常用的内置函数
  6. linux线程调度与rtos,实时Linux和RTOS的基本特性及技术进行比较
  7. Android 中 liblog 和 libcutils 的编译 trick
  8. android classloader双亲托付模式
  9. @PropertySource 解析 yml 配置文件,自定义解析 yaml 工厂类
  10. 微软更新服务器ip地址,微软承认Windows 10更新导致路由等本地IP地址打不开
  11. 运行深度学习代码时报错RuntimeError: CUDA out of memory. Tried to allocate 482.00 MiB
  12. 米勒拉宾素数测试模板
  13. html 防网页假死,htmlweb开发:防止浏览器假死的方法.doc
  14. 如何给Word重新排页码
  15. 您所说的话:您如何与Bacn打交道
  16. C++grammer开篇
  17. Python ROS键盘控制机械臂
  18. STM32H747AGI6技术、STM32H747AII6规格、STM32H747BGT6产品概述
  19. 【协作MIMO+非规则LDPC】协作MIMO系统上,中继协作解码转发策略和编码协作策略,采用非规则LDPC编码
  20. 时隔一个月,讯飞星火大模型 V1.5 发布:星火 APP 登场,综合能力三大升级!

热门文章

  1. linux进程snprintf函数功能,linux 之 snprintf函数用法
  2. 对Revit 2014如何使用FME Revit Exporter
  3. android面试必看书籍,花三分钟看完这篇文章你就懂了
  4. android 文字添加阴影,android中给TextView或许Button的文字添加阴影效果
  5. java 保险管理系统_保险管理系统
  6. 审计署发布五家金融机构资产审计报告
  7. css超实用 可爱小图标
  8. E. GukiZ and GukiZiana
  9. 行列式按行(列)展开定理——6种行列式的展开方式
  10. 朝鲜“局域网”探秘:看着就不寒而栗!