zoukankan      html  css  js  c++  java
  • ZLL本地局域网通信过程

    Interface_srpcserver

                                                     -----以灯的状态操作位例

    网关与客户端通过Socket API通信,Socket APIsocket_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 ", 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中定义的一个宏定义常数0pBuf[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

    01(开启或关闭)  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-- ");

                       

      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 gatewaysocket_server

    二.   Interface_srpcserver能不能准确移植到STM32

    三.   主机接口能不能准确移植到STM32[c5] 

    四.   主机接口与interface_srpcserver如何实现数据交互


     [c1]如何做的?不同的客户端如何区分的?

     [c2]这个附注加得好,别人就可以更好的学习相关的内容了,以便共同提高。

     [c3]也就是吕慧珍和谢红涛正在做移植的部分。

     [z4]红色字体表示的为Interface_srpcserver主机接口交互部分

     [c5]这部分吕慧珍他们正在做,应该问题不大。





    附件列表

  • 相关阅读:
    CSS3学习手记(7) CSS3装换 3D转换
    CSS3学习手记(6) CSS3装换 2D转换
    CSS3学习手记(5) 渐变
    CSS3学习手记(4) 伪元素
    CSS3学习手记(3) CSS权重
    CSS3学习手记(2) 伪类选择器
    CSS3学习手记(1) 选择器
    HTML5学习手记(二)
    HTML5学习手记(一)
    浏览器远程调试VS
  • 原文地址:https://www.cnblogs.com/star91/p/4888968.html
Copyright © 2011-2022 走看看