如果已经将上面介绍的SECS/GEM开发要点掌握了,那么我们就可以进入“RapidSecs基础库”的实际开发了。首先明确一下基础库的目标:支持E5(SECSII)、E37(HSMS),开发语言为C++。这两个协议也是后继E30、E40、E90等等一系列协议的基础。
首先,基础库的功能要如何划分?从对协议的支持来看要支持的协议是E5(HSMS)和E37(SECS-II),那么当然的2个功能模块就是分别对这两个协议的支持。此外,
1) 通信功能模块(HSMS模块)
基础库需要为用户提供通信接口,使其能在不需要了解下层通信结构的情况下与其他设备进行互连,主要功能包括:
2)消息解析功能模块(SECS-II模块)
消息表示功能使软件系统可以识别、表示并创建 SECS-II 标准消息,并为用户开发自定义 SECS-II 消息提供接口,主要功能包括:
各模块功能说明如下:
在进行通信之前,用户应该对 HSMS 通信进行相关配置,这些的参数包括:
(1) 连接模式
连接模式分为主动模式(Active)和被动模式(Passive)两种。HSMS 规定一个 TCP/IP 连接中发起连接的通信实体为主动模式,因此在被动模式下的实体如果试图向远程实体发起一个 TCP 连接将返回模式错误信息。被动模式下的实体只能侦听端口。
(2) 本地 IP 地址和端口
通信实体在设置的本地IP地址和端口侦听连接请求。
(3) 远程IP地址和端口
本地通信实体向远程 IP 地址和端口发起连接请求。
(4) 设备 ID
设备ID是一个16比特整数,其最高位比特必须为0,剩下的15个比特用于在一个网段中唯一的标识一个设备,是只与该设备相关的属性参数。在控制信息中设备ID被全部置 1。
(5) 回复超时 T3
T3 表示等待回复消息的最长时间,默认设置为45秒,精度为1秒。
(6) 连接间隔超时 T5
T5 表示通信实体在一个连接失败之后(连接请求被拒绝或连接断开)发起下一次连接所必须等待的时间,默认设置为10秒,精度为1秒。
(7) 控制会话超时 T6
T6 表示一个控制会话所能开启的最长时间,默认设置为5秒,精度为1秒。
(8) NOT SELECT 状态超时 T7
T7 表示一个连接所能处于NOT SELECT状态的最长时间,默认设置为10秒,精度为 1 秒。
(9) 网络字符超时 T8
T8 表示接收一个消息时单个字符到达的最大时间间隔,默认设置为5秒,精度为1秒。
以上 9 个参数都必须通过接口函数进行读取和改写。
对应的数据结构如下:
typedef struct _RAPID_SECS_CFG
{
unsigned int t3;
unsigned int t5;
unsigned int t6;
unsigned int t7;
unsigned int t8;
unsigned int link_test_interval;
unsigned long local_ip;
unsigned short local_port;
unsigned long remote_ip;
unsigned short remote_port;
unsigned short device_id;
unsigned char mode;
rapid_secs_on_connect pfn_on_connect;
rapid_secs_on_recv_msg pfn_on_recv_message;
rapid_secs_on_recv_raw_data pfn_on_recv_raw_data;
rapid_secs_on_close pfn_on_close;
rapid_secs_on_msg_reply_timeout pfn_on_msg_reply_timeout;
} RAPID_SECS_CFG;
HSMS 从 TCP/IP 连接接收到数据首先由消息解析模块进行消息解析。消息解析模块的作用有三个:
当数据从 TCP/IP 到达,消息解析模块先读取前 4 个字节,如果这 4 个字节的数值小于 10,那么判定格式错误并丢弃该消息。如果该数值大于或等于 10,然后读取接下来的 10 个字节,从中获取消息类型,判断该消息编号是否在等待响应队列中。当该消息是等待中的消息时,停止对应的超时管理计时器,若为控制消息则调用相应的控制函数,若为数据消息则生成一个消息块数据,连同数据内容一起传递给处理函数,也可转换为SML进行显示。
消息块为自定义数据结构,用于向上层协议描述 HSMS 消息头中的相关信息,包括远程实体的设备 ID,消息的 stream 和 function 编号,以及这个消息的会话 ID。基本的消息解析流程如下:
HSMS 通信状态分为 Not-Connected 和 Connected,其中 Connected 状态又分为 Not-Selected 和 Selected 两种。通信状态只能由通信控制函数和定时器来改变,用户只能读取当前通信状态,而不能直接改变其状态。
在不同的状态下系统所能采取的操作不同:
该状态下系统只能进行建立 TCP/IP 连接的操作,例如套接口的初始化,绑定套接口描述字、在某个端口侦听等。所有这些建立 TCP/IP 连接的操作一旦有一个失败都会返回一个建立 TCP/IP 失败类型的错误。
当 TCP/IP 连接建立之后,系统进入 Not-Selected 状态。一旦进入该状态,被动模式下的实体将激活计时器T7,若在T7 超时之前仍未进入Selected状态则将断开TCP/IP连接进入Not-Connected状态。主动模式的实体在该状态下系统只能执行select操作,发送select.req 之后将激活T6计时器,如果在T6超时之前未收到正确的select.rsp消息或者select.rsp的状态位不为0则将断开TCP/IP连接,并激活T5计时器。
实体进入Selected状态表示通信两端的实体已经正式确认连接建立。在这个状态下的实体可以进行数据交换LinkTest操作以及断开连接的 Close操作。在进行数据交换时将开启T3计时器和T8计时器,T3计时器超时将终止对应的会话,T8计时器超时将断开TCP/IP连接。LinkTest用于诊断通信状况,发送linktest.req消息将激活T6计时器,若T6超时将断开TCP/IP连接。separate操作将直接断开TCP/IP连接,可以由主动模式或被动模式下的实体发起。
上述状态下所能进行的操作及涉及到的计时器如下表所示:
状态 |
操作 |
计时器 |
Not-Connected 状态 |
TCP/IP 相关操作 |
|
Not-Selected 状态 |
T7 |
|
|
select操作(主动模式) |
T6 |
Selected 状态 |
数据交换 |
T3,T8 |
|
LinkTest操作 |
T6 |
|
separate操作 |
执行某项操作之前都必须检查通信状态,如果这项操作在当前通信状态下是不允许执行的,那么将返回错误信息。