Package: dcompy
dcompy欢迎前往社区交流：海萤物联网社区简介RPC：Remote Procedure Call，远程过程调用。使用RPC可以让一台计算机的程序程调用另一台计算机的上的程序。RPC通过把网络通讯抽象为远程的过程调用，调用远程的过程就像调用本地的子程序一样方便，从而屏蔽了通讯复杂性，使开发人员可以无需关注网络编程的细节，将更多的时间和精力放在业务逻辑本身的实现上，提高工作效率。DCOM：Device Communication Protocol(DCOM)，设备间通信协议。DCOM是针对物联网使用场景开发的RPC框架，主要有如下特点：协议开销极小仅4字节。物联网很多场景都是几十字节的短帧，RPC协议本身的开销如果过大会导致在这些场景无法应用可以跨语言通信。DCOM协议在设计上与语言无关，无论C，Golang，Python等都可以使用DCOM可以跨通信介质通信。DCOM协议可以工作在以太网，串口，wifi，小无线等一切通信介质之上在海萤物联网中，节点间使用DCOM来通信。本文介绍Python语言开发的DCOM包的使用方法。开源github上的项目地址gitee上的项目地址安装pip install dcompy基础概念查看文档海萤物联网教程：Go SDK基础概念章节。APIdefload(param:LoadParam)"""模块载入"""defregister(protocol:int,rid:int,callback):"""注册DCOM服务回调函数:param protocol: 协议号:param rid: 服务号:param callback: 回调函数.格式: func(pipe: int, src_ia: int, req: bytearray) (bytearray, int):return: 返回值是应答和错误码.错误码为0表示回调成功,否则是错误码"""defreceive(protocol:int,pipe:int,src_ia:int,data:bytearray):"""接收数据.应用模块接收到数据后需调用本函数,本函数接收帧的格式为DCOM协议数据"""defregister(protocol:int,rid:int,callback):"""注册DCOM服务回调函数:param protocol: 协议号:param rid: 服务号:param callback: 回调函数.格式: func(pipe: int, src_ia: int, req: bytearray) (bytearray, int):return: 返回值是应答和错误码.错误码为0表示回调成功,否则是错误码"""defcall(protocol:int,pipe:int,dst_ia:int,rid:int,timeout:int,req:bytearray)->(bytearray,int):"""RPC同步调用:param protocol: 协议号:param pipe: 通信管道:param dst_ia: 目标ia地址:param rid: 服务号:param timeout: 超时时间,单位:ms.为0表示不需要应答:param req: 请求数据.无数据可填bytearray()或者None:return: 返回值是应答字节流和错误码.错误码非SYSTEM_OK表示调用失败"""数据结构classLoadParam:"""载入参数"""def__init__(self):# 块传输帧重试间隔.单位:msself.block_retry_interval=0# 块传输帧重试最大次数self.block_retry_max_num=0# API接口# 是否允许发送.函数原型:func(pipe: int) boolself.is_allow_send=None# type: Callable[[int], bool]# 发送的是DCOM协议数据.函数原型:func(protocol: int, pipe: int, dst_ia: int, bytes: bytearray)self.send=None# type: Callable[[int, int, int, bytearray], None]系统错误码# 系统错误码# 正确值SYSTEM_OK=0# 接收超时SYSTEM_ERROR_RX_TIMEOUT=0x10# 发送超时SYSTEM_ERROR_TX_TIMEOUT=0x11# 内存不足SYSTEM_ERROR_NOT_ENOUGH_MEMORY=0x12# 没有对应的资源IDSYSTEM_ERROR_INVALID_RID=0x13# 块传输校验错误SYSTEM_ERROR_WRONG_BLOCK_CHECK=0x14# 块传输偏移地址错误SYSTEM_ERROR_WRONG_BLOCK_OFFSET=0x15# 参数错误SYSTEM_ERROR_PARAM_INVALID=0x16load：模块载入在使用DCOM前必须要初始化。DCOM支持重传，所以在初始化时需输入重传间隔以及重传最大次数。DCOM与通信介质无关，不同介质可定义不同的管道号。应用程序需要在是否允许发送函数（is_allow_send），以及发送函数（send）中编写不同管道的操作。示例：某节点有两个管道if__name__=='__main__':param=dcompy.LoadParam()param.block_retry_max_num=5param.block_retry_interval=1000param.is_allow_send=is_allow_sendparam.send=senddcompy.load(param)defis_allow_send(pipe:int)->bool:ifpipe==1:returnis_pipe1_allow_send()else:returnis_pipe2_allow_send()defsend(protocol:int,pipe:int,dst_ia:int,data:bytearray):ifpipe==1:pipe1_send(data)else:pipe2_send(data)protocol，dst_ia等字段根据需求处理。receive 接收数据应用程序接收到数据需要调用receive函数，将数据发送给DCOM。示例：某节点有两个管道都可接收defpipe1_receive(data:bytearray):dcom.receive(0,1,0x2140000000000101,data)defpipe2_receive(data:bytearray):dcom.Receive(0,2,0x2140000000000101,data)协议号protocol示例中填写的是0，应用时根据实际场景填写。register：服务注册节点可以通过注册服务开放自身的能力。示例：假设节点2140::101是智能插座，提供控制和读取开关状态两个服务：dcom.register(0,1,control_service)dcom.register(0,2,get_state_service)//control_service控制开关服务//返回值是应答和错误码.错误码为0表示回调成功,否则是错误码defcontrol_service(pipe:int,src_ia:int,req:bytearray)->(bytearray,int):ifreq[0]==0:off()else:on()returnNone,dcom.SystemOK//get_state_service读取开关状态服务//返回值是应答和错误码.错误码为0表示回调成功,否则是错误码defget_state_service(pipe:int,src_ia:int,req:bytearray)->(bytearray,int):returnbytearray([state()]),dcom.SystemOKcall：同步调用defcall(protocol:int,pipe:int,dst_ia:int,rid:int,timeout:int,req:bytearray)->(bytearray,int):"""RPC同步调用:param protocol: 协议号:param pipe: 通信管道:param dst_ia: 目标ia地址:param rid: 服务号:param timeout: 超时时间,单位:ms.为0表示不需要应答:param req: 请求数据.无数据可填bytearray()或者None:return: 返回值是应答字节流和错误码.错误码非SYSTEM_OK表示调用失败"""同步调用会在获取到结果之前阻塞。节点可以通过同步调用，调用目标节点的函数或者服务。timeout字段是超时时间，单位是毫秒。如果目标节点超时未回复，则会调用失败。如果超时时间填0，则表示不需要目标节点回复。示例：2141::102节点控制智能插座2141::101开关状态为开resp,errCode=dcom.call(0,1,0x2140000000000101,3000,bytearray([1]))示例：2141::102节点读取智能插座2141::101开关状态resp,errCode=dcom.call(0,2,0x2140000000000101,3000,None)iferrCode==dcom.SystemOK:print("开关状态:",resp[0])请求和应答数据格式DCOM通信双方发送的数据流都是二进制，请求（req）和应答（resp）的数据类型都是[]uint8。二进制不利于应用处理，所以会将二进制转换为其他数据类型来处理。常用的有以下三种：结构体json字符串在物联网中，硬件节点的资源有限，且大部分都是使用C语言编写代码。所以建议使用C语言结构体来通信。结构体约定使用1字节对齐，小端模式。海萤物联网提供sbc库用来进行C语言结构体和二进制流的转换，详情可以查看文档：海萤物联网教程：sbc：基于python的C语言格式结构体和二进制转换库