1. 协议概述
欧姆龙(Omron)是来自日本的知名电子和自控设备制造商,其中、小型PLC在国内市场有较高的占有率,有CJ、CM等系列。PLC可以支持Fins、Host link等协议进行通信。
支持以太网的欧姆龙PLC CPU、以太网通信模块根据型号的不同,一般都会支持FINS(Factory Interface Network Service)协议,一些模块也会支持EtherNet/IP协议。Omron fins协议缺省TCP/UDP端口号为9600。Fins协议封装在TCP/UDP之上,需要注意的是基于TCP的Fins数据包和基于UDP的包在头部上差异较大。协议的具体构造可以参考欧姆龙官方文档。
FINS协议实现了OMRON PLC与上位机以太网通信。Fins基于TCP/UDP的报文的概览如下:
1 |
Fins over TCP |
由上图可知,Fins/TCP实际上是将Fins/UDP报文作为其负载,在其前面加了一个Fins/TCP报头。需要注意的是,Fins/TCP报文中负载即Fins/UDP部分不一定会出现,它可以只有一个简单的Fins/TCP报头。
因此我们先介绍Fins/UDP报文的组成,然后再介绍Fins/TCP结构。
2. 协议详解
2.1 Fins over UDP
基于UDP的Fins协议的结构相对简单,整体结构由报头和数据两部分组成,如下所示:
1 |
Fins over UDP |
其中报头部分为必要组成部分,为固定长度12个字节,数据部分非必现。
2.1.1 Fins/UDP Header
报头部分由11个定长字段组合而成,前面10个字段分别简称为:ICF、RSV、GCT、DNA、DA1、DA2、SNA、SA1、SA2、SID,如下所示:
1 |
0 1 2 6 7 |
上述11个字段中,除最后一个Command Code字段为2个字节外,其余所有字段均只占1个字节。
2.1.2 ICF字段
第一个字段被称为ICF字段(即Information control filed,信息控制字段),1个字节,由4个子字段组成,分述如下:
- 1… …. = Gateway bit,是否使用网关,
0x01
表示使用; - .1.. …. = Data Type bit,数据类型比特位,
0x01
表示为响应,0x00
表示命令; - ..0. …. = Reserved bit,第一个保留比特位,默认置0;
- …0 …. = Reserved bit,第二个保留比特位,默认置0;
- …. 0… = Reserved bit,第三个保留比特位,默认置0;
- …. .0.. = Reserved bit,第四个保留比特位,默认置0;
- …. ..0. = Reserved bit,第五个保留比特位,默认置0;
- …. …1 = Response setting bit,第一个保留比特位响应标志为,
0x01
表示非必需回应,0x00
表示必须进行回应。
2.1.3 RSV字段
第二个字段被称为RSV(即Reserved,保留字段),1个字节,置0x00
。
2.1.4 GCT字段
第三个字段被称为GCT(即Gateway count ,网关计数),1个字节,置为0x02
。
2.1.5 DNA字段
第四个字段被称为DNA(即Destination network adrress,目标网络地址),1个字节,取值如下:
-
00
:表示本地网络; -
0x01
~0x7F
:表示远程网络。
2.1.6 DA1字段
第五个字段被称为DA1(即Destination node number,目标节点编号),1个字节,取值如下:
-
0x01
~0x3E
:SYSMAC LINK
网络中的节点号; -
0x01
~0x7E
:YSMAC NET
网络中的节点号; -
0xFF
: 广播传输。
Omron的官方手册中,该字段只能取上述值,然而网上的实际抓包发现会有其它值出现,被wireshark标记为unknown。
2.1.7 DA2字段
第六个字段被称为DA2(即Destination unit address,目标单元地址),1个字节,取值如下:
-
0x00
:PC(CPU); -
0xFE
: SYSMAC NET Link Unit or SYSMAC LINK Unit connected to network; -
0x10
~0x1F
:CPU总线单元 ,其值等于10 + 单元号(前端面板中配置的单元号)。
Omron的官方手册中,该字段只能取上述值,然而网上的实际抓包发现会有其它值出现,被wireshark标记为unknown。
2.1.8 SNA字段
第七个字段被称为SNA(即Source network address,源网络地址),1个字节,取值及含义同DNA字段。
2.1.9 SA1字段
第八个字段被称为SA1(即Source node number,源节点编号),1个字节,取值及含义同DA1字段。
2.1.10 SA2字段
第九个字段被称为SA2(即Source unit addess,源单元地址),1个字节,取值及含义同DA2字段。
2.1.11 SID字段
第十个字段被称为SID(即Service ID,服务ID**),1个字节,取值0x00
~0xFF
,产生会话的进程的唯一标识。
2.1.12 Command Code字段
这个字段占2个字节,其取值由第一个字节表示的大分类和第二个字节表示的子分类复合而成,取值及其含义如下表:
Command Code | 英文释义 | 中文释义 | |
---|---|---|---|
1st Byte | 2nd Byte | ||
0x01 | 0x01 | MEMORY AREA READ | 内存区域读取 |
0x02 | MEMORY AREA WRITE | 内存区域写入 | |
0x03 | MEMORY AREA FILL | 内存区域填充 | |
0x04 | MULTIPLE MEMORY AREA READ |
多内存区域读取 | |
0x05 | MEMORY AREA TRANSFER | 内存区域传输 | |
0x02 | 0x01 | PARAMETER AREA READ | 参数区域读取 |
0x02 | PARAMETER AREA WRITE | 参数区域写入 | |
0x03 | PARAMETER AREA CLEAR | 参数区域清除 | |
0x20 | DATA LINK TABLE READ | 数据链表读取 | |
0x21 | DATA LINK TABLE WRITE | 内存区域传输 | |
0x03 | 0x04 | PROGRAM AREA PROTECT | 程序区保护 |
0x05 | PROGRAM AREA PROTECT CLEAR | 程序区保护清除 | |
0x06 | PROGRAM AREA READ | 程序区读取 | |
0x07 | PROGRAM AREA WRITE | 程序区写入 | |
0x08 | PROGRAM AREA CLEAR | 程序区清除 | |
0x04 | 0x01 | RUN | 执行 |
0x02 | STOP | 停止 | |
0x03 | RESET | 重置 | |
0x05 | 0x01 | CONTROLLER DATA READ | 控制器数据读取 |
0x02 | CONNECTION DATA READ | 连接数据读取 | |
0x06 | 0x01 | CONTROLLER STATUS READ |
控制器状态读取 |
0x02 | NETWORK STATUS READ | 网络状态读取 | |
0x03 | DATA LINK STATUS READ | 数据连接状态读取 | |
0x20 | CYCLE TIME READ | 循环次数读取 | |
0x07 | 0x01 | CLOCK READ | 时钟读取 |
0x02 | CLOCK WRITE | 时钟写入 | |
0x08 | 0x01 | LOOP-BACK TEST/ INTERNODE ECHO TEST |
环路测试/内部节点响应测试 |
0x02 | BROADCAST TEST RESULTS READ |
广播测试/结果读取 | |
0x03 | BROADCAST TEST DATA SEND |
广播测试数据发送 | |
0x09 | 0x20 | MESSAGE READ | 消息读取 |
MESSAGE CLEAR | 消息清除 | ||
FAL/FALS READ | FAL/FALS读取 | ||
0x0C | 0x01 | ACCESS RIGHT ACQUIRE | 访问权限获取 |
0x02 | ACCESS RIGHT FORCED ACQUIRE |
访问权限强制获取 | |
0x03 | ACCESS RIGHT RELEASE | 访问权限释放 | |
0x21 | 0x01 | ERROR CLEAR | 错误清除 |
0x02 | ERROR LOG READ | 错误日志读取 | |
0x03 | ERROR LOG CLEAR | 错误日志清除 | |
0x22 | 0x01 | FILE NAME READ | 文件名读取 |
0x02 | SINGLE FILE READ | 单文件读取 | |
0x03 | SINGLE FILE WRITE | 单文件写入 | |
0x04 | MEMORY CARD FORMAT | 记忆卡格式化 | |
0x05 | FILE DELETE | 文件删除 | |
0x06 | VOLUME LABEL CREATE/DELETE |
卷标创建/删除 | |
0x07 | FILE COPY | 文件复制 | |
0x08 | FILE NAME CHANGE | 文件名更改 | |
0x09 | FILE DATA CHECK | 文件数据校核 | |
0x0A | MEMORY AREA FILE TRANSFER |
内存区域文件传输 | |
0x0B | PARAMETER AREA FILE TRANSFER/td> |
参数区域文件传输 | |
0x0C | PROGRAM AREA FILE TRANSFER |
程序区域文件传输 | |
0x0F | FILE MEMORY INDEX READ | 文件内存索引读取 | |
0x10 | FILE MEMORY READ | 文件内存块读取 | |
0x11 | FILE MEMORY WRITE | 文件内存块写入 | |
0x23 | 0x01 | FORCED SET/RESET | 强制设置/重置 |
0x02 | FORCED SET/RESET CANCEL |
取消强制设置/重置 | |
0x0A | MULTIPLE FORCED STATUS READ |
多强制状态读取 | |
0x26 | 0x01 | NAME SET | 名称设置 |
0x02 | NAME DELETE | 名称删除 | |
0x03 | NAME READ | 名称读取 |
合计:14个大类,57个子类,共57个Command Code。
2.2 Fins Over TCP
基于TCP的FINS报文结构也不复杂,无非就是一个FINS/TCP头部(必选),加上FINS/UDP报文(可选),如下所示:
1 |
Fins over TCP |
2.2.1 Fins/TCP Header
Fins/TCP的报头与Fins/UDP不同的是,它由4个固定字段和2个可选字段组成,如下所示:
1 |
Fins/TCP Header |
因此Fins/TCP的头部长度范围为[16,24]
字节,每个字段的长度均为固定的4个字节。
2.2.2 Magic字段
第一个字段为Magic Bytes字段,从字面意思看是魔数字段,其ASCII码(0x46494E53
)刚好是FINS这个单词,因此可以推测这个字段的值是恒定的。
2.2.3 Length字段
第二个字段为Length字段,这个字段的值表示其后所有字段(包括可能出现的Fins/UDP包)的总长度,用公式表达为:
Length=len(TCPPAYLOAD)−len(MagicBytes)−len(Length)=len(TCPPAYLOAD)−4−4=len(TCPPAYLOAD)−8(2 - 1)
也就是说,该字段的值等于TCP负载的总长度减去8个字节。
2.2.4 Command字段
第三个字段为Command字段,这个字段表示消息中随附的命令的类型。这个字段的取值直接决定了后续可选的字段Client Node Address、Server Node Address是否出现,具体情况如下所示:
-
0x00000000
:节点地址数据已发送(C->S),此时仅有Client Node Address字段; -
0x00000001
:节点地址数据已发送(S->C),此时Client/Server Node Address字段均出现; - 其它:不会出现上述两个字段。
2.2.5 Error Code字段
第四个字段为Error Code字段,这个字段表示错误代码。根据wireshark源代码所提供的信息,错误代码目前共定义了10种类型,如下所示:
错误码 | 对应含义 |
---|---|
0x00000000 | Normal |
0x00000001 | The header is not ‘FINS’ (ASCII code) |
0x00000002 | The data length is too long |
0x00000003 | The command is not supported |
0x00000020 | All connections are in use |
0x00000021 | The specified node is already connected |
0x00000022 | Attempt to access a protected node from an unspecified IP address |
0x00000023 | The client FINS node address is out of range |
0x00000024 | The same FINS node address is being used by the client and server |
0x00000025 | All the node addresses available for allocation have been used |
2.2.6 Client/Server Node Address字段
这两个字段是Fins/TCP的客户端/服务器建立连接的时候的类似DHCP协议客户端获取IP地址的时候才会出现的,如下所示:
由上可以看出,Fins/TCP协议的客户端/服务器在传输有效的命令数据之前,由客户端先向服务器发送一个包含Client Node Address字段的报文申请节点地址,如下图所示:
类似DHCP协议,由于客户端申请的时候还没有节点地址,因此该字段被置为0x00000000
。
服务器收到客户端请求后,给客户端分配相应的节点地址并通告给客户端,同时在报文中包含服务器自己的节点地址信息,如下所示:
客户端收到服务器的响应报文后,即使用分配的节点地址与服务器进行通信,由此客户端/服务器之间就建立起了有效的长连接。
2.3 Command Data
这个字段是Fins/UDP、Fins/TCP协议的实际负载部分,鉴于其涵盖内容较多(官方手册就有两百多页),目前未对其进行深入解析,后续根据需要再深入解析。