ZLL本地局域网通信过程
Interface_srpcserver
-----以灯的状态操作位例
网关与客户端通过Socket API通信,Socket API在socket_server.c中实现,socket_server.c中不只实现了网关与客户端的通信,还对客户端进行了简单的管理,如建立客户端列表[c1] ,因为可能有多个客户端连接到同时连接到同一个网关。Socket API是在LwIP的基础上实现的,这一底层通信过程,我们不需要知道它具体怎么实现(但是在具体开发环节中还是需要大量修改和添加功能),只需要知道怎么用Socket API通信。下面就假设网关已经接收到了来自客户端clientFd的命令信息存在*pBuf指向的内存,后面我将介绍网关如何处理这个命令消息。首先调用下面的函数
void RPSC_ProcessIncoming(uint8_t *pBuf, uint32_t clientFd)
功能:处理客户端发送到网关的命令信息
参数:pBuf –网关收到的命令信息
{
rpcsProcessMsg_t func;
func = rpcsProcessIncoming[(pBuf[SRPC_FUNC_ID] & ~(0x80))];
if (func)
{
(*func)(pBuf, clientFd);
}
else
{
printf("Error: no processing function for CMD 0x%x\n", pBuf[SRPC_FUNC_ID]);
}
}
解释:在interface_srpcserver.c的宏定义中定义了这样一个指针函数类型:
typedef uint8_t (*rpcsProcessMsg_t)(uint8_t *pBuf, uint32_t clientFd);
上述定义如果难懂可参考http://zhidao.baidu.com/question/170422609.html[c2]
第一行定义了一个这样的函数指针
第二行pBuf[SRPC_FUNC_ID] & ~(0x80)。这里的SRPC_FUNC_ID是在interface_srpcserver.h中定义的一个宏定义常数0,pBuf[SRPC_FUNC_ID]就是pBuf的第一个字节的值,由SRPC消息格式可知,第一个字节表示CMD ID,即标识网关收到的是哪个命令,如收到的命令为设置灯的状态,则CMD ID为:RPCS_SET_DEV_STATE 0x82(在nterface_srpcserver.h中已定义),0x82& ~(0x80)得到的结果为2,因此func = rpcsProcessIncoming[2],由字符串数组rpcsProcessIncoming[](在interface_srpcserver.c的开始已定义)可知rpcsProcessIncoming[2]即为RPCS_ZLL_setDeviceState,自此我们完成了命令的解析,也就是说我们知道了客户端要求网关来干什么,接下来的if语句 执行 (*func)(pBuf, clientFd);即为上述定义的指针函数,还是以设置灯的状态的命令为例,前面我们已经得到func即为RPCS_ZLL_setDeviceState,因此这里实际上调用的函数为:
static uint8_t RPCS_ZLL_setDeviceState(uint8_t *pBuf, uint32_t clientFd)
|
SRPC消息格式 |
||
|
CMD字节 |
命令长度(N) |
数据 |
|
1字节 |
1字节 |
n个字节 |
接下来顺藤摸瓜,我们看看这个函数,用户通过客户端发送命令想改变灯的状态,这个命令已经被网关接收到了,接下来网关就要通过主机接口[c3] 发送命令给CC2531来控制终端节点,CC2531是不能直接转发处理客户端发送给网关的命令的,因此网关需对命令解析,提取出需要通过串口传递给CC2531的参数,下面这个函数即实现了此功能。在此还是以设置灯的状态命令为例,RPCS_SET_DEV_STATE消息格式如表所示:
|
RPCS_SET_DEV_STATE消息格式 |
||
|
字节 |
描述 |
值 |
|
1 |
命令ID Command ID |
0X82 |
|
1 |
长度 Length |
13 |
|
1 |
地址模式 Address Mode |
1 = 组播或2 =单播 1=groupcast OR 2=unicast |
|
2 |
网络地址 Network Address |
NwkAddr或组ID NwkAddr OR Group ID |
|
6 |
保留的 Reserved |
0 |
|
1 |
端点 Endpoint |
设备端点或为0xFF Devices Endpoint OR 0xFF |
|
2 |
保留的 Reserved |
0 |
|
1 |
状态 State |
0或1(开启或关闭) 0 or 1 (on or off) |
static uint8_t RPCS_ZLL_setDeviceState(uint8_t *pBuf, uint32_t clientFd)
功能:This function exposes an interface to set a devices on/off attribute.
打开一个接口来设置灯的开/关属性
参数:pBuf - incomin messages 网关接收到的命令消息
static uint8_t RPCS_ZLL_setDeviceState(uint8_t *pBuf, uint32_t clientFd)
{
uint8_t endpoint, addrMode;
uint16_t dstAddr;
bool state;
//increment past SRPC header
pBuf+=2;
//由 SRPC消息格式可知命令的前两个字节标识命令的ID及命令的长度,这两个字节是告诉网关该如何处理这个命令,并不需要转发给主机接口,因此指针+2跳过
addrMode = (afAddrMode_t)*pBuf++;
// 由RPCS_SET_DEV_STATE消息格式可知第三个字节标识 地址模式 Address Mode
dstAddr = BUILD_UINT16(pBuf[0], pBuf[1]);
//网络地址由两个字节构成,BUILD_UINT16是在hal_defs.h中定义的一个函数方法,将两个字节组合成一个16位无符号整数
pBuf += Z_EXTADDR_LEN;//指针跳过保留字节,Z_EXTADDR_LEN即为保留字节的个数
endpoint = *pBuf++; //从命令中提取端点ID
// index past panId
pBuf += 2;// 指针跳过两个保留字节
state = (bool)*pBuf; //从命令中提取 状态
// Set light state on/off
参数已经全部从命令中提取出来了,下面就要通过串口发送参数到CC2531,这是通过下面的函数完成的
zllSocSetState(state, dstAddr, endpoint, addrMode);
return 0;
}
zllSocSetState(state, dstAddr, endpoint, addrMode)在
这个函数实现了通过串口发送数据到CC2531的功能,具体实现在zllSocCmd.c中,这个主机[z4] 接口的问题在此不再叙述
以上网关完成了一个完整的命令处理过程,主要由三个函数完成:
void RPSC_ProcessIncoming(uint8_t *pBuf, uint32_t clientFd) 解析命令
static uint8_t RPCS_ZLL_setDeviceState(uint8_t *pBuf, uint32_t clientFd) 提取参数
zllSocSetState(state, dstAddr, endpoint, addrMode); 主机接口发送命令
上面我是以“设置灯的状态”命令为例的,这个功能不需要网关返回数据给客户端,如果客户端发送的命令为“获取灯的状态”,则网关还需将灯的状态信息返回给客户端。前面的过程与上例相同,
void RPSC_ProcessIncoming(uint8_t *pBuf, uint32_t clientFd) 解析命令
static uint8_t RPCS_ZLL_getDeviceState(uint8_t *pBuf, uint32_t clientFd) 提取参数
zllSocGetState(dstAddr, endpoint, addrMode); 主机接口发送命令
假设通过主机接口获得了“灯的状态”存放在变量state中,接下来我们就要将这个状态数据返回给客户端。这是就需要调用函数:
void RPCS_ZLL_CallBack_getStateRsp(uint8_t state, uint16_t srcAddr, uint8_t endpoint, uint32_t clientFd)
{
uint8_t *pSrpcMessage, *pBuf;
//RpcMessage contains function ID param Data Len and param data
pSrpcMessage = malloc(2+ 4);
pBuf = pSrpcMessage; //使两个指针指向同一内存
//Set func ID in RPCS buffer
*pBuf++ = RPCS_GET_DEV_STATE_RSP;
//param size
*pBuf++ = 4;
*pBuf++ = srcAddr & 0xFF;
*pBuf++ = (srcAddr & 0xFF00) >> 8;
*pBuf++ = endpoint;
*pBuf++ = state & 0xFF;
//Store the device that sent the request, for now send to all clients
srpcSendAll(pSrpcMessage);
//printf("RPCS_ZLL_CallBack_addSceneRsp--\n");
return;
}
上面的函数是按照下面的命令格式来装载数据的,最后调用srpcSendAll(pSrpcMessage); 函数将封装好的信息发送给所有客户端
|
RPCS_GET_DEV_STATE_RSP消息格式 |
||
|
字节 |
描述 |
值 |
|
1 |
命令ID Command ID |
0X07 |
|
1 |
长度 Length |
0x4 |
|
2 |
网络地址 Network Address |
0x1234 |
|
1 |
端点 End Point |
0X56 |
|
1 |
状态 state |
0X0 |
srpcSendAll(pSrpcMessage);是通过调用socket_server.c中的
int32 socketSeverSendAllclients(uint8* buf, uint32 len)来实现的
参考Linux gateway远程过程调用设计方法,下面面对的问题主要就是:
一. 在LwIP的基础上能不能实现类似Linux gateway的socket_server;
二. Interface_srpcserver能不能准确移植到STM32中
四. 主机接口与interface_srpcserver如何实现数据交互
[c1]如何做的?不同的客户端如何区分的?
[c2]这个附注加得好,别人就可以更好的学习相关的内容了,以便共同提高。
[c3]也就是吕慧珍和谢红涛正在做移植的部分。
[z4]红色字体表示的为Interface_srpcserver与主机接口交互部分
[c5]这部分吕慧珍他们正在做,应该问题不大。
附件列表
ZLL本地局域网通信过程的更多相关文章
- 网络中两台主机的通信过程(TCP)
两台主机通信有两种情况:1.在同一网段中 2.不在同一网段中 (1.)在同一网段的通信过程 主机在应用层上的操作: TCP/IP协议上tcp的端口对应的各种应用程序,客户机要访问某个应用程序就会要求打 ...
- UDP广域网,局域网通信-原理分析,穿透技术
一.UDP局域网通信. 这个比较简单,关于局域网中的2台或者更多的计算机之间的UDP通信,网络上一大把,直接复制粘贴就可以使用,原理也非常简单.所以,本文不做详细介绍. 二.UDP广域通信(包括路由器 ...
- Binder机制,从Java到C (9. IPC通信过程)
1.一次IPC通信過程的幾個步驟 一次通信过程简单的说有下面5个步骤,第一眼看上去,肯定不知道什么玩意,多看几遍,慢慢看,其实是能理解的. 1. Client将数据封装成Parcel. (前面已经讲过 ...
- BitCoin p2p通信过程
众所周知,Bitcoin是建立在p2p网络上的,但是具体的通信过程一直没有搞懂,所以特意去bitcoin的Developer Guid上去了解了一下.由于本人英文水平有限,理解难免有偏差的地方,希望大 ...
- tcp/ip 卷一 读书笔记(5)arp和rarp 同网段和不同网段之间的通信过程
arp和rarp 同网段和不同网段之间的通信过程 IPv6中已经没有arp rarp协议,所以这里都是IPv4. 链路层使用以太网地址来确定目的地址,应用则常使用ip地址通信 arp协议是指从ip地址 ...
- Android BLE与终端通信(三)——客户端与服务端通信过程以及实现数据通信
Android BLE与终端通信(三)--客户端与服务端通信过程以及实现数据通信 前面的终究只是小知识点,上不了台面,也只能算是起到一个科普的作用,而同步到实际的开发上去,今天就来延续前两篇实现蓝牙主 ...
- Python Web学习笔记之WebSocket 通信过程与实现
一.什么是 WebSocket ? WebSocket 是一种标准协议,用于在客户端和服务端之间进行双向数据传输.但它跟 HTTP 没什么关系,它是基于 TCP 的一种独立实现. 以前客户端想知道服务 ...
- Android BLE与终端通信(三)——client与服务端通信过程以及实现数据通信
Android BLE与终端通信(三)--client与服务端通信过程以及实现数据通信 前面的终究仅仅是小知识点.上不了台面,也仅仅能算是起到一个科普的作用.而同步到实际的开发上去,今天就来延续前两篇 ...
- UDP局域网通信的Java实现及Android平台尝试
局域网通信已经很少被他人所提及了,我曾经还尝试过通过蓝牙构建通信网络,这次有机会尝试UDP局域网通信,在这里把一些基本过程和在Android平台上的问题记录一下. 1. UDP基础知识 1.1 什么是 ...
随机推荐
- VMware12中CentOS7网络设置
VMware提供了三种将虚拟网卡和物理网卡捆绑起来的方式,即桥接(Bridge)模式,网络地址转换(Network Address Transformation, NAT)模式和主机(Host Onl ...
- Centos7 修改SSH 端口
修改/etc/ssh/sshd_config vi /etc/ssh/sshd_config #Port 22 //这行去掉#号,防止配置不好以后不能远程登录,还得去机房修改,等修改以后的端口能使用以 ...
- ACM/ICPC 之 Floyd范例两道(POJ2570-POJ2263)
两道以Floyd算法为解法的范例,第二题如果数据量较大,须采用其他解法 POJ2570-Fiber Network //经典的传递闭包问题,由于只有26个公司可以采用二进制存储 //Time:141M ...
- cairo-1.14.6 static compiler msys mingw32
gtk2.x 静态编译时 需要注意的是 cairo cairo 1.14.x 使用了 mutex , 用动态方式时 DllMain 中调用了 CAIRO_MUTEX_INITIALIZE () 在静态 ...
- Java for LeetCode 236 Lowest Common Ancestor of a Binary Tree
解题思路一: DFS到每个节点的路径,根据路径算出LCA: public class Solution { public TreeNode lowestCommonAncestor(TreeNode ...
- Python~第三方模块
第三方库还有MySQL的驱动:MySQL-python,用于科学计算的NumPy库:numpy,用于生成文本的模板工具Jinja2 模块搜索路径 Windows下: 双\\ sys.path.ap ...
- suse linux 10 下配置vpn服务器(pptp)
一.安装所需的软件包: pptpd-*.rpm ppp-*.rpm pptp-*.rpm 一般情况下系统已经将pptp和ppp包安装好了,所以只需安装pptpd ...
- struts2.0整合json
框架:struts2.0+hibernate2+spring 今天写代码时,需要用到json,我就直接加了两个jar包:json-lib-2.1-jdk15.jar,struts2-json-plug ...
- SQL常用命令整理
1.增加字段 alter table docdsp add dspcodechar(200)2.删除字段 ALTER TABLE table_NAME DROP COLUMNcolum ...
- 在某公司时的java开发环境配置文档
1 开发环境配置 1.1. MyEclipse 配置 1.MyEclipse下载地址:\\server\共享文件\backup\MyEclipse9.0 2.修改工作空间编码为UTF-8,如下图 3 ...