本文档仅供学习和研究使用,请勿使用文中的技术源码用于非法用途,任何人造成的任何负面影响,与本人无关.
简介
S7 协议的 TCP/IP 实现依赖于面向块的 ISO 传输服务。S7 协议被封装在 TPKT 和 ISO-COTP 协议中,这使得 PDU(协议数据单元)能够通过 TCP 传送。
它用于 PLC 编程,在 PLC 之间交换数据,从 SCADA(监控和数据采集)系统访问 PLC 数据以及诊断目的。
S7Comm 以太网协议基于 OSI 模型:
layer | Protocol |
---|---|
7 Application Layer | S7 communication |
6 Presentation Layer | S7 communication |
5 Session Layer | S7 communication |
4 Transport Layer | ISO-on-TCP (RFC 1006) |
3 Network Layer | IP |
2 Data Link Layer | Ethernet |
1 Physical Layer | Ethernet |
从 wireshark 协议分级可以看出排列
TPKT,应用层数据传输协议,介于 TCP 和 COTP 协议之间。这是一个传输服务协议,主要用来在 COTP 和 TCP 之间建立桥梁;
COTP,按照维基百科的解释,COTP 是 OSI 7 层协议定义的位于 TCP 之上的协议。COTP 以“Packet”为基本单位来传输数据,这样接收方会得到与发送方具有相同边界的数据;
第7层,S7 communication,这一层和用户数据相关,对 PLC 数据的读取报文在这里完成。
在具体的报文中,TPKT 的作用是包含用户协议(5~7层)的数据长度(字节数);COTP 的作用是定义了数据传输的基本单位(在S7Comm中 PDU TYPE:DT data)。
S7Comm 数据作为 COTP 数据包的 Payload ,第一个字节总是 0×32 作为协议标识符。
S7Comm 协议包含三部分:
- Header
- Parameter
- Data
根据实现的功能不同,S7 comm 协议的结构会有所不同。
S7Comm 的头,定义了该包的类型、参数长度、数据长度等,其结构如图所示:
所以,S7Comm Header 的格式为:
- 0 (unsigned integer, 1 byte): Protocol Id,协议 ID,通常为 0×32;
- 1 (unsigned integer, 1 byte): ROSCTR,PDU type,PDU 的类型,一般有以下值:
- 0×01 - JOB(Request: job with acknowledgement):作业请求。由主设备发送的请求(例如,读/写存储器,读/写块,启动/停止设备,设置通信);
- 0×02 - ACK(acknowledgement without additional field):确认响应,没有数据的简单确认(未遇到过由 S7 300/400 设备发送得);
- 0×03 - ACK_DATA(Response: acknowledgement with additional field):确认数据响应,这个一般都是响应JOB的请求;
- 0×07 - USERDATA:原始协议的扩展,参数字段包含请求/响应 ID(用于编程/调试,读取 SZL,安全功能,时间设置,循环读取…)。
- 2~3 (unsigned integer, 2 bytes): Redundancy Identification (Reserved),冗余数据,通常为 0×0000;
- 4~5 (unsigned integer, 2 bytes): Protocol Data Unit Reference,it’s increased by request event。协议数据单元参考,通过请求事件增加;
- 6~7 (unsigned integer, 2 bytes): Parameter length,the total length (bytes) of parameter part。参数的总长度;
- 8~9 (unsigned integer, 2 bytes): Data length,数据长度。如果读取 PLC 内部数据,此处为 0×0000;对于其他功能,则为 Data 部分的数据长度;
其中最重要的字段就是 ROSCTR,它决定了后续参数的结构
在响应数据包中,还有可能存在错误信息,其错误信息结构为:
- 10 (unsigned integer, 1 bytes): Error class,错误类型:
- 11 (unsigned integer, 1 bytes): Error code,错误代码;
S7Comm 中 Job(作业请求) 和 Ack_Data(确认数据响应) 中的 Parameter 项的第一个字段是 function(功能码),其类型为 Unsigned integer,大小为 1 byte。决定了其余字段的结构、消息的目的。
-
建立通信(Setup communication [0xF0])
建立通信在每个会话开始时被发送,然后可以交换任何其他消息。它用于协商 ACK 队列的大小和最大 PDU 长度,双方声明它们的支持值。ACK 队列的长度决定了可以同时启动而不需要确认的并行作业的数量。PDU 和队列长度字段都是大端。
当 PDU 类型为 Job 时,建立通信功能中 Parameter 的结构,如下图:
具体的 Parameter 结构,如下:
- 1 (Unsigned integer, 1 byte): Parameter part: Reserved byte in communication setup pdu,保留字节;
- 2 (Unsigned integer, 2 bytes): Max AmQ (parallel jobs with ack) calling;
- 3 (Unsigned integer, 2 bytes): Max AmQ (parallel jobs with ack) called;
- 4 (Unsigned integer, 2 bytes): Parameter part: Negotiate PDU length。协商 PDU 长度。
-
读取值(Read Var [0x04])
数据读写操作通过指定变量的存储区域,地址(偏移量)及其大小或类型来执行。
当 PDU 类型为 Job 时,那么其 S7Comm 结构,如下图:
所以,接下来的 Parameter 字段是 item count(项目个数),其类型为 Unsigned integer,大小为 1 byte。
item 的结构如下:
- 0 (Unsigned integer, 1 byte): Variable specification,确定项目结构的主要类型,通常为 0×12,代表变量规范;
- 1 (Unsigned integer, 1 byte): Length of following address specification,本 Item 其余部分的长度;
- 2 (Unsigned integer, 1 byte): Syntax Ids of variable specification,确定寻址模式和其余项目结构的格式;
- 3(Unsigned integer, 1 byte): Transport sizes in item data,确定变量的类型和长度:
- 4~5 (Unsigned integer ,2 byte): Request data length,请求的数据长度;
- 6~7 (Unsigned integer, 2 byte): DB number,DB 模块的编号,如果访问的不是 DB 区域,此处为 0×0000;
- 8 (Unsigned integer, 1 byte):: Area,区域类型:
- 9~11(Unsigned integer, 3 byte): Address,地址。
PDU 类型为 Ack_Data 时,其 S7Comm 的结构,如下图:
其 Parameter 只有 function、item count 两个字段。Data 结构如下:
- 0 (Unsigned integer, 1 byte): Return code,返回代码:
- 1 (Unsigned integer, 1 byte): Transport size,数据的传输尺寸:
- 2~3 (Unsigned integer, 2 bytes): Length,数据的长度;
- 4~4+length (?): Data,数据;
- ? (Unsigned integer, 1 byte): Fill byte,填充字节。
-
写入值(Write Var [0x05])
Write Var 中 Parameter 的结构跟读取值(Read Var[0x04])一样,但是 Write Var 还需写入值,所以 Write Var 比 Read Var 多了一个 Data 项。结构如下:
由此,Data 的结构为:
- 0 (Unsigned integer, 1 byte): Return code,返回代码,这里是未定义,所以为 Reserved(0×00);
- 1 (unsigned integer, 1 byte): Transport size,确定变量的类型和长度:
- 2-3 (unsigned integer, 2 bytes): Length,写入值的数据长度;
- 4 (1 byte): Data,写入的值;
- 5 (unsigned integer, 1 byte): Fill byte,填充字节,如果数据的长度不足 Length 的话,则填充;
PDU 类型为 Ack_Data 时,其 S7Comm 的结构,如下图:
Parameter 也只有 function、item count 两个字段。而 Data 中也只有一个 Return code 字段,其结构如下:
- 0 (Unsigned integer, 1 byte): Return code,返回代码:
-
下载
下载是 Step7 发送块数据给 PLC。在西门子设备上,程序代码和(大部分)程序数据存储在块中,这些块有自己的头和编码格式。
在西门子设备中有8种不同类型的功能块,这些块在上/下载请求中用特殊的ASCII文件名寻址。这个文件名的结构如下:
- 1 (1 byte): File identifier(ASCII),文件标识符。其有_ (Complete Module)、$ (Module header for up-loading)两种文件标识符;
- 2 (2 bytes): Block type,块类型。
- 3 (5 bytes): Block number,块编号;
- 4 (1 byte): Destination filesystem(ASCII),目标的文件系统。其有三种文件系统:
- P (Passive (copied, but not chained) module):被动文件系统
- A (Active embedded module):主动文件系统
- B (Active as well as passive module):既主既被文件系统
例如:文件名为_0A00001P(文件标识是_,块类型为DB,块的编号为00001,目标块的文件系统是P。),用于将DB 1复制到被动文件系统或从被动文件系统复制。
在下载过程中,先是 Step7 向 PLC 发送一个请求下载的 Job,PLC 收到后则回复一个 Ack_Data。在发送完所有字节后,Step7 向 PLC 发送一个下载结束的 Job 来关闭下载会话。时序图如下
下载有3种不同的功能类型:
-
请求下载(Request download [0x1A])
当 PDU 类型为 Job 时,Request download [0x1A] 没有 Data,其 Parameter 的结构,如下
- 1 (1 byte): Function Status,功能码状态;
- 2 (2 bytes): for all unknown bytes in blockcontrol;
- 3 (4 bytes): 无意义,一般为0x00000000;
- 4 (1 byte): filename length,文件名长度;
- 5 (? bytes): filename, default is 9 byte,文件名,长度一般为9个字节;
- 1 (1 byte): File identifier(ASCII),文件标识符。其有_ (Complete Module)、$ (Module header for up-loading)两种文件标识符;
- 2 (2 bytes): Block type,块类型。
- 3 (5 bytes): Block number,块编号;
- 4 (1 byte): Destination filesystem(ASCII),目标的文件系统。其有P(Passive (copied, but not chained) module)、A (Active embedded module)、B (Active as well as passive module)三种文件系统;
- 6 (1 byte): Length part 2 in bytes,参数的第二部分长度,也就是接下来的字段长度;
- 7 (1 byte): Unknown char(ASCII);
- 8 (6 bytes): Length load memory in bytes(ASCII);
- 9 (6 bytes): Length of MC7 code in bytes(ASCII)。
PDU 类型为 Ack_Data 时,Request download [0x1A] 的 Parameter 中只有一个 function。
-
下载块(Download block [0x1B])
下载是 Step7 发送块数据给 PLC。当 PDU 类型为 Job 时,Download block [0x1B] 也没有 Data,其 Parameter 的结构,如下
- 1 (1 byte): Function Status,功能码状态;
- 2 (2 bytes): for all unknown bytes in blockcontrol;
- 3 (4 bytes): 无意义,一般为0x00000000;
- 4 (1 byte): filename length,文件名长度;
- 5 (? bytes): filename, default is 9 byte,文件名,长度一般为9个字节;
- 1 (1 byte): File identifier(ASCII),文件标识符。其有_ (Complete Module)、$ (Module header for up-loading)两种文件标识符;
- 2 (2 bytes): Block type,块类型。
- 3 (5 bytes): Block number,块编号;
- 4 (1 byte): Destination filesystem(ASCII),目标的文件系统。其有P(Passive (copied, but not chained) module)、A (Active embedded module)、B (Active as well as passive module)三种文件系统;
Download block [0x1B] 的 Parameter 与 Request download [0x1A] 的 Parameter 的第一部分相同
那 PDU 类型为 Ack_Data 时,Download block [0x1B] 有 Parameter 和 Data,其 Parameter 的结构,如下
- 1 (1 byte): Function Status,功能码状态;
- 1 (Unsigned integer, 2 bytes): Length,数据长度;
- 2 (Unsigned integer, 2 bytes): Unknown byte(s) in blockcontrol,未知字节;
- 3 (Label,data_length-4 bytes): Data,数据;
-
下载结束(Download ended [0x1C])
当 PDU 类型为 Job 时,Download ended [0x1C] 也没有 Data,其 Parameter 的结构,如下:
- 1 (1 byte): Function Status,功能码状态;
- 2 (2 bytes): for all unknown bytes in blockcontrol;
- 3 (4 bytes): 无意义,一般为 0x00000000;
- 4 (1 byte): filename length,文件名长度;
- 5 (? bytes): filename, default is 9 byte,文件名,长度一般为9个字节;
- 1 (1 byte): File identifier(ASCII),文件标识符。其有_ (Complete Module)、$ (Module header for up-loading)两种文件标识符;
- 2 (2 bytes): Block type,块类型。
- 3 (5 bytes): Block number,块编号;
- 4 (1 byte): Destination filesystem(ASCII),目标的文件系统。其有P(Passive (copied, but not chained) module)、A (Active embedded module)、B (Active as well as passive module)三种文件系统;
PDU 类型为 Ack_Data 时,Download ended [0x1C] 的 Parameter 中只有一个 function。
-
上传
上传是 PLC 发送块数据给 Step7
在上传过程中,先是 Step7 向 PLC 发送一个开始上传的 Job,PLC 收到后则回复一个 Ack_Data,并告诉 Step7 块的长度、上传会话 ID。然后 PLC 继续上传块数据到 Step7,直到 Step7 收到所有字节。最后,Step7 发送结束上传的作业请求来关闭上传会话。时序图如下
上传有3种不同的功能类型
-
开始上传(Start upload [0x1D])
当 PDU 类型为 Job 时,Start upload [0x1D] 没有 Data,其 Parameter 的结构,如下
- 1 (1 byte): Function Status,功能码状态;
- 2 (2 bytes): for all unknown bytes in blockcontrol;
- 3 (4 bytes): 上传的会话ID,此时为0x00000000;
- 4 (1 byte): filename length,文件名长度;
- 5 (? bytes): filename, default is 9 byte,文件名,长度一般为9个字节;
- 1 (1 byte): File identifier(ASCII),文件标识符。其有_ (Complete Module)、$ (Module header for up-loading)两种文件标识符;
- 2 (2 bytes): Block type,块类型。
- 3 (5 bytes): Block number,块编号;
- 4 (1 byte): Destination filesystem(ASCII),目标的文件系统。其有P(Passive (copied, but not chained) module)、A (Active embedded module)、B (Active as well as passive module)三种文件系统;
那 PDU 类型为 Ack_Data 时,Start upload [0x1D] 的 Parameter 的结构,如下
- 1 (1 byte): Function Status,功能码状态;
- 2 (2 bytes): for all unknown bytes in blockcontrol;
- 3 (4 bytes): 上传的会话ID,告诉Step7上传会话ID;
- 4 (Unsigned integer, 1 byte): Blocklengthstring Length;
- 5 (Character string): Blocklength,块的长度;
-
上传(Upload [0x1E])
当 PDU 类型为 Job 时,Upload [0x1E] 也没有 Data,其 Parameter 的结构,如下
- 1 (1 byte): Function Status,功能码状态;
- 2 (2 bytes): for all unknown bytes in blockcontrol;
- 3 (4 bytes): 上传的会话ID,告诉Step7上传会话ID;
PDU 类型为 Ack_Data 时,Upload [0x1E] 有 Parameter 和 Data,其 Parameter 的结构,如下
- 1 (1 byte): Function Status,功能码状态;
- 1 (Unsigned integer, 2 bytes): Length,数据长度;
- 2 (Unsigned integer, 2 bytes): Unknown byte(s) in blockcontrol,未知字节;
- 3 (Label,data_length-4 bytes): Data,数据;
-
上传结束(End upload [0x1F])
上传结束的过程,即为所有数据上传完成后,Step7 发送结束上传的作业请求,PLC 收到后就关闭会话,然后返回一个响应。
当 PDU 类型为 Job 时,End upload [0x1F] 也没有 Data,其 Parameter 的结构,如下
- 1 (1 byte): Function Status,功能码状态;
- 2 (2 bytes): Error code,错误代码:
- 3 (4 bytes): 上传的会话ID,告诉 Step7 上传会话 ID;
那 PDU 类型为 Ack_Data 时,End upload [0x1F] 的 Parameter 中只有一个 function。
-
-
程序调用服务(PI service [0x28])
程序调用是用于在 PLC 执行修改执行/内存状态的日常工作。这些命令可以用于启动或停止 PLC 控制程序、激活或删除程序块。
当 PDU 类型为 Job 时,PI service [0x28] 没有 Data,只有 Parameter,那 Parameter 的结构,如下:
- 1 (7 bytes): Unknown;
- 2 (Unsigned integer, 2 bytes): Parameter block length;
- 3 (?bytes): Parameter block,参数;
- 4 (Unsigned integer, 1 byte):String length,PI service的字符串长度;
- 5 (Character string, ASCII):PI (program invocation) Service name,程序调用服务名。
Parameter 包含两个主要部分:
- 服务名称
- 参数:取决于方法类型,可以将它们看作是它的参数
服务名称及其相关参数的示例:
- _INSE:激活设备上下载的块,参数是块的名称(比如:OB 1)。
- _DELE:从设备的文件系统中删除一个块,该参数也是该块的名称。
- P_PROGRAM:设置设备的运行状态(启动、停止、复位)。
- _GARB:压缩 PLC 内存。
- _MODU:将 ram 复制到 ROM,参数包含文件系统标识符(A/E/P)。
如果服务调用的参数是块的话,那么 Parameter block 的结构如下:
- 1 (1 byte): Number of block;
- 2 (1 byte): Unknown,默认为 0x00;
- 3 (? bytes): filename,文件名:
- 1 (2 bytes, ASCII): Block type,块类型。
- 2 (5 bytes, ASCII): Block number,块编号;
- 3 (1 byte, ASCII): Destination filesystem(ASCII),目标的文件系统。其有 P(Passive (copied, but not chained) module)、A (Active embedded module)、B (Active as well as passive module)三种文件系统;
-
PLC STOP [0x29]
PLC STOP 基本上跟程序调用服务(PI service [0x28])一致,唯一的区别就是它没有 Parameter block,而它的 PI service 为 P_PROGRAM。
UserData 用于编程/调试、读取 SZL、安全功能、时间设置,循环读取等
Parameter 结构如下
- 1 (3 bytes):参数头(Parameter head);
- 2 (1 byte):参数长度(Parameter length),它的可能是8字节或12字节;
- 3 (1 byte):未知定义;
- 4 (1/2 byte,高位):参数类型(Type);
- 5 (1/2 byte,Low nibble):功能组(Function group);
- 6 (1 byte):子功能码(SubFunction);
- 7 (1 byte):序号。
当 PDU 类型为 UserData 时,其 S7Comm 结构,如图所示,图中蓝色部分为 S7Comm 头部,橘色为 Parameter 部分.
-
转换工作模式(Mode-transition [0x0])
当功能组为转换工作模式(Mode-transition)时,请求报文中是没有 Data 部分的,而主要起作用的是子功能码(Subfunction),常见的子功能码有:
- STOP(0x00):STOP 模式;
- Warm Restart(0x01):暖启动;
- RUN(0x02):RUN 模式;
- Hot Restart(0x03):热启动;
- HOLD(0x04):HOLD 模式;
- Cold Restart(0x06):冷启动;
- RUN_R (H-System redundant)(0x09):H-System 冗余运行;
- LINK-UP(0x0B):LINK-UP 模式;
- UPDATE(0x0C):UPDATE 模式。
-
程序员命令(Programmer commands [0x1])
程序员命令(Programmer commands)主要是工程师用于编程或调试,比如:监视/修改变量、读取修改诊断数据。所有的子功能码有:
- 请求诊断数据(Request diag data (Type 1)):0x01;
- 变量表(VarTab):0x02;
- 读取诊断数据(Read diag data):0x0c;
- 移除诊断数据(Remove diag data):0x0e;
- 清除(Erase):0x0f;
- 强制(Forces):0x10;
- 请求诊断数据(Request diag data (Type 2)):0x13;
请求报文和响应报文,如图所示
请求报文的结构如下:
- 1 (1 byte) : 返回码;
- 2 (1 byte) :Transport sizes,指的数据类型,通常有 bit、byte等;
- 3 (2 bytes) : 往后的数据长度;
- 4 (1 byte) : Unknown;
- 5 (1 byte) : 报文类型(type of data),分为请求(0x14)、响应(0x04);
- 6 (2 bytes) : Item count和Item data的长度(Byte count);
- 7 (20bytes) : Unknown;
- 8 (2bytes) : Item 个数;
- 9 (varibalebytes) : Item 1;
- 1 (1 byte) : 区域(Area);
- 2 (1 byte) : 长度(Length (repetition factor));
- 3 (2 bytes) : 模块号(DB number);
- 4 (2 bytes) : 偏移地址(Startaddress)。
- n (varibalebytes) : Item n;
响应报文结构如下:
- 1 (1 byte) : 返回码;
- 2 (1 byte) :数据类型(Transport sizes),通常有 bit、byte 等;
- 3 (2 bytes) : 往后的数据长度;
- 4 (1 byte) : Unknown;
- 5 (1 byte) : 报文类型(type of data),分为请求(0x14)、响应(0x04);
- 6 (2 bytes) : Item count 和 Item data 的长度(Byte count);
- 7 (4bytes) : Unknown;
- 8 (2bytes) : Item 个数;
- 9 (varibalebytes) : Item 1;
- 1 (1 byte) : 返回码;
- 2 (1 byte) :数据类型(Transport sizes),通常有 bit、byte 等;
- 3 (2 bytes) : 往后的数据长度;
- 4 (varibale bytes) : Data。
- n (varibalebytes) : Item n;
-
循环数据(Cyclic data [0x2])
循环数据(Cyclic data)是用于循环读取内存数据、取消订阅循环数据,比如:DB、M 等。所有的子功能码有:
- 0x01:读取内存数据(Memory),比如 DB、M 等;
- 0x04:取消订阅或禁用循环数据(Unsubscribe (disable) cyclic data);
- 0x05:读取内存数据(Memory),跟 0x01 一样,但仅用于 S7-400。
请求报文的 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes),通常有 bit、byte 等;
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (2 bytes) : Item 个数;
- 5 (1byte) : 扫描间隔(Interval timebase);
- 6 (1byte) : 时间间隔(Interval timebase);
- 7 (varibale bytes) : Item 1;
- 1 (1 byte) : Variable specification;
- 2 (1 byte) : 以下规范地址的长度(Length of following address specification);
- 3 (1 byte) : Syntax Id;
- ...(不同的 Syntax Id,则结构不一样。)
- ...
- n (varibale bytes) : Item n;
响应报文的 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (2 bytes) : Item 个数;
- 5 (varibale bytes) : Item 1;
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (varibale bytes) : 数据;
- ...
- n (varibale bytes) : Item n;
-
块功能(Block functions [0x3])
块功能(Block functions)是用于操作块,所有的子功能码有:
-
0x01:列举所有块(List blocks);
在 PLC 中有各种块,比如 DB、OB、FB,可以通过 block functions 中的子功能码 list blocks 进行块的列举
请求报文的 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
响应报文的 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (4 bytes) : Item 1;
- 1 (2 bytes) : 块的类型(Block type);
- 2 (2 bytes) : 块的个数(Block count);
- ...
- n (4 bytes) : Item n;
-
0x02:列举块类型(List blocks of type);
请求报文的 Data 部分中需要携带块类型(Block type)
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (2 bytes):块的类型(Block type)
响应报文 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (4 bytes) : Item 1;
- 1 (2 bytes) : 块编号(Block number);
- 2 (1 byte) : Unknown,可能是块的标记;
- 3 (1 byte) : 语言(Block language)
常见的块语言:
- 0x00:Not defined,未定义;
- 0x01:AWL;
- 0x02:KOP;
- 0x03:FUP;
- 0x04:SCL;
- 0x05:DB;
- 0x06:GRAPH;
- 0x07:SDB;
- 0x08:CPU-DB,是由 PLC 程序创建的 DB 块;
- 0x11:SDB (after overall reset),经常出现在 SDB 1 和 SDB 2中;
- 0x12:SDB (Routing),经常出现在 SDB 999 和 SDB 1000 中;
- 0x29:ENCRYPT,块通过 S7-Block-Privacy 加密;
- ...
- n (4 bytes) : Item n;
-
0x03:读取块的信息(Get block info)。
请求报文的 Data 部分中需要携带块类型(Block type)、块编号(Block number)、文件系统(filesystem),Header、Parameter 结构
请求报文的 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (2 bytes):块的类型(Block type);
- 5 (5 bytes):块编号(Block number);
- 6 (1 byte):文件系统(Filesystem);
响应报文 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (2 bytes):块类型(Block type);
- 5 (2 bytes):信息的长度(Length of Info),以此往后的长度;
- 6 (2 bytes):未知信息(Unknown blockinfo);
- 7 (2 bytes):常数3(Constant 3),一直是 pp;
- 8 (1 byte):未知信息(Unknown byte(s) blockinfo);
- 9 (1 byte):块标志(Block flags);
- 10 (1 byte):语言(Block language);
- 11 (1 byte):字块(Subblk type),常见的字块有:
- 0x08:OB;
- 0x0a:DB;
- 0x0b:SDB;
- 0x0c:FC;
- 0x0d:SFC;
- 0x0e:FB;
- 0x0f:SFB;
- 12 (2 bytes):块编号(Block number);
- 13 (4 bytes):需要的装载存储器大小(Length load memory);
- 14 (4 bytes):安全(Block Security);
- 15 (6 bytes):代码上次修的时间(Code Timestamp);
- 16 (6 bytes):接口上次修的时间戳(Interface Timestamp);
- 17 (2 bytes):SSB长度(SSB length);
- 18 (2 bytes):ADD长度(ADD length);
- 19 (2 bytes):本地数据长度(Localdata length);
- 20 (2 bytes):MC7代码长度(MC7 code length);
- 21 (8 bytes):作者(Author);
- 22 (8 bytes):系列(Family);
- 23 (8 bytes):名称(标题)(Name (Header));
- 24 (1 byte):版本(标题)(Version (Heade);
- 25 (1 byte):未知信息(Unknown byte(s) blockinfo);
- 26 (2 bytes):校验码(Block checksum);
- 27 (4 bytes):预留(Reserved 1);
- 28 (4 bytes):预留(Reserved 2)
-
-
CPU功能(CPU functions [0x4])
CPU 功能(CPU functions)是用于操作块,所有的子功能码有:
- 0x01:读系统状态列表(Read SZL);
- 0x02:消息服务(Message service);
- 0x03:诊断消息(Diagnostic message),PLC 的诊断消息;
- 0x05:ALARM_8 显示(ALARM_8 indication), PLC 使用ALARM_8 SFBs 来显示报警消息;
- 0x06:NOTIFY 显示(NOTIFY indication),PLC 使用 NOTIFY SFBs 来显示 NOTIFY 消息;
- 0x07:ALARM_8 锁定(ALARM_8 lock), 需要通过 HMI/SCADA 锁定ALARM 消息;
- 0x08:ALARM_8 取消锁定(ALARM_8 unlock), 需要通过 HMI/SCADA 取消锁定 ALARM 消息;
- 0x09:SCAN 显示(SCAN indication),PLC 显示 SCAN 消息;
- 0x0b:ALARM 确认(ALARM ack),报警信息已在 HMI/SCADA 中得到确认;
- 0x0c:ALARM 确认显示(ALARM ack indication), 从 CPU 到 HMI 的确认报警显示;
- 0x0d:ALARM 锁定显示(ALARM lock indication),从 CPU 到 HMI 的锁定报警显示;
- 0x0e:ALARM 取消锁定显示(ALARM unlock indication),从 CPU 到 HMI 的取消锁定报警显示;
- 0x11:ALARM_SQ 显示(ALARM_SQ indication),PLC 使用 ALARM_SQ/ALARM_DQ SFCs 来显示 ALARM 消息;
- 0x12:ALARM_S 显示(ALARM_S indication),PLC 使用 ALARM_S/ALARM_D SFCs 来显示 ALARM 消息;
- 0x13:ALARM 查询(ALARM query),HMI/SCADA 查询 ALARM;
- 0x16:NOTIFY_8 显示(NOTIFY_8 indication)。
子功能码有4种不同的功能类型:
-
系统状态列表(SZL)
系统状态列表(德语:System-ZustandsListen,英语:System Status Lists)用于描述可编程逻辑控制器的当前状态。SZL 的内容只能通过信息功能进行读取,而不能修改。换言之,部分列表是虚拟列表,只是在有特殊请求时由 CPU 的操作系统所创建。
只能通过SFC 51 "RDSYSST"读取一个系统状态列表。
系统状态列表包含下列内容的有关信息:
- 系统数据
- CPU 中的模块状态数据
- 模块的诊断数据
- 诊断缓冲区
如果要读取系统状态列表,则需要使用参数 SZL-ID 和 INDEX 指定要读取的内容。比如:读取 PLC 的名称,那 SZL-ID 是 W#16#011C,INDEX 是 W#16#0001
每个部分系统状态列表都有一个编号。可以根据编号输出完整的部分列表或摘录。预定义了可能的部分列表摘录,并由一个数字标识。SZL-ID 由部分列表的编号、部分列表摘录的编号和模块等级组成。
请求报文的 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (2 bytes):SZL-ID;
- 5 (2 bytes):SZL-Index;
响应报文 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (2 bytes):SZL-ID,部分列表摘录的 SZL-ID,以 W#16#xy1C 为例,常见的 SZL-ID 如下:
- W#16#001C:所有组件的标识;
- W#16#011C:一个组件的标识;
- W#16#021C:H系统中一个 CPU 的所有组件的标识;
- W#16#031C:H系统中所有冗余 CPU 的一个组件的标识;
- W#16#0F1C:仅限SSL部分列表报头信息;
- 5 (2 bytes):SZL-Index,不同的 SZL-ID 那 SZL-Index 不一样。以 W#16#011C 和 W#16#031C 的部分列表摘录的组件标识:
- W#16#0001:自动化系统的名称;
- W#16#0002:模块名称;
- W#16#0003:模块的设备标识;
- W#16#0004:版权;
- W#16#0005:模块的序列号;
- W#16#0007:模块类型名称;
- W#16#0008:存储卡的序列号在不能插入存储卡的模块中,不提供数据记录;
- W#16#0009:CPU 模块的制造商和配置文件;
- W#16#000A:模块的 OEM ID(仅限 S7-300);
- W#16#000B:模块的位置指定;
- 6 (2 bytes):部分列表的长度(SZL partial list length in bytes),不同的 SZL-ID 那长度不一样;
- 7 (2 bytes):部分列表的个数(SZL partial list count);
- 8 (34 bytes):SZL 1;
- ...
- n (34 bytes):SZL n;
-
消息服务(Message service)
消息服务(Message service)主要用于订阅事件,比如:切换工作模式事件、系统诊断事件等。
请求报文的 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (1 byte):订阅事件(Subscribed events),常见的事件有:
- 0x01(MODE):切换工作模式;
- 0x02(SYS):系统诊断;
- 0x04(USR):用户定义的诊断消息;
- 0x08:未知;
- 0x10:未知;
- 0x20:未知;
- 0x40:未知;
- 0x80(ALM):程序块消息,附加字段中的消息类型;
- 5 (1 byte):未知(Unknown);
- 6 (varibale bytes):用户名(Username);
响应报文 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (1 byte):订阅的结果:
- n (4 bytes):预留(Reserved 2)
-
诊断消息(Diagnostic message)
诊断消息(Diagnostic message)通常是诊断缓冲区中的数据
请求报文的 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (2 bytes):事件 ID(Event ID);
- 5 (1 byte):优先级(Priority class);
- 6 (1 byte):OB 编号(OB number);
- 7 (2 bytes):DatID;
- 8 (2 bytes):附加信息(Additional information 1);
- 9 (4 bytes):附加信息(Additional information 2);
- 10 (8 bytes):时间戳;
每个事件都分配有事件 ID,而事件 ID 的结构如图
那事件 ID 的内容,包括:
- 0-7位:事件编号(Event Number);
- 8-11位:识别(IDs),标识符用于区分事件的类型。
- 12-15位:事件等级(Event Class)
-
告警消息及告警查询
在这里,把 ALARM_8 显示(0x05)、NOTIFY 显示(0x06)、ALARM_8 锁定(0x07)、ALARM_8 取消锁定(0x08)、SCAN 显示(0x09)、ALARM 确认(0x0b)、ALARM 确认显示(0x0c)、ALARM 锁定显示(0x0d)、ALARM 取消锁定显示(0x0e)、ALARM_SQ 显示(0x11)、ALARM_S 显示(0x12)、ALARM 查询(0x13)、NOTIFY_8 显示(0x16)共13个子功归纳为告警信息。
-
ALARM 查询(0x13)
请求报文的 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (1 byte):功能标识(Function identifier);
- 5 (1 byte):消息对象个数(Number of message objects);
- 6 (varibale byte):Message Object 1;
- 1 (1 byte):Variable specification;
- 2 (1 byte):以下规范地址的长度(Length of following address specification);
- 3 (1 byte):Syntax Id;
- 4 (1 byte):Unknown;
- 5 (1 byte):查询类型(Querytype),类型有:
- 0x01:告警类型(ByAlarmtype);
- 0x03:事件 ID(ByEventID);
- 0x08:Unknown;
- 0x09:Unknown;
- 6 (1 byte):Unknown;
- ...
- ...
响应报文 Data 结构如下:
- 1 (1 byte) : 返回码(Return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (1 byte):功能标识(Function identifier);
- 5 (1 byte):消息对象个数(Number of message objects);
- 6 (1 byte) : 数据传输大小(Transport sizes);
- 7 (2 bytes) : 完整数据长度,也就是以此往后的数据长度;
- 8 (varibale byte):Message Object 1;
- 1 (1 byte) :长度(Length of dataset);
- 2 (2 bytes):Unknown;
- 3 (1 byte):告警类型(Alarmtype);
- 4 (4 bytes):事件 ID;
- 5 (1 byte):Unknown;
- 6 (1 byte):事件状态(EventState);
- 7 (1 byte):AckState going;
- 8 (1 byte):AckState coming;
- ...
- n (varibale byte):Message Object n;
-
ALARM 显示、ALARM 锁定/解锁、ALARM 确认、NOTIFY 显示
往往这类报文都是以PUSH的形式存在, Data 结构如下:
- 1 (1 byte) : 返回码(Return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (8 bytes):事件时间,如果subfunc是0x09,那长度为2 bytes;
- 5 (1 byte):功能标识(Function identifier);
- 6 (1 byte):消息对象个数(Number of message objects);
- 7 (varibale byte):Message Object 1;
- 1 (1 byte):Variable specification;
- 2 (1 byte):长度(Length of following address specification);
- 3 (1 byte):Syntax Id;
- 4 (1 byte):相关值数目(Number of associated values);
- 5 (4 bytes):事件 ID;
6 (1 byte):事件状态(EventState);
7 (1 byte):状态(State);
8 (1 byte):AckState going;
9 (1 byte):AckState coming;
10 (varibale bytes):Associated value 1;
1 (1 byte) : 返回码(Return code);
2 (1 byte) : 数据传输大小(Transport sizes);
3 (2 bytes) : 长度;
4 (varibale bytes):Data;
...
n (varibale bytes):Associated value n;
- ...
- n (varibale byte):Message Object n;
说明:上面标记部分为可变项,不同的子功能则不同。
-
-
安全功能(Security [0x5])
全功能(Security)是用于安全设置,比如:设置 PLC 密码,所有的子功能码有:
- 0x01:PLC 密码(PLC password);
- 0x02:清除密码(Clear PLC password)。
请求报文的 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 数据长度;
- 4 (varibale byte):Data;
响应报文 Data 结构如下:
- 1 (1 byte) : 返回码(Return code);
- 2 (1 byte) : 数据传输大小(Transport sizes);
- 3 (2 bytes) : 以此往后的数据长度;
-
PBC BSEND/BRECV [0x6]
- PBC:Programmable Block Functions,可编程块函数,比如:SFB/FB;
- BSEND/BRCV:到通信伙伴的固定数据块传送。也就是说,在通信伙伴中的接收函数(BRCV)接受该数据之前,数据传送不会结束。
-
时间功能(Time functions [0x7])
时间功能(Time functions)是用于时间设置,比如:设置时间,所有的子功能码有:
- 0x01:读时间(Read clock);
- 0x02:设置时间(Set clock);
- 0x03:读时间(Read clock (following));
- 0x04:设置时间(Set clock)。
读取时间的 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes),通常有 bit、byte 等;
- 3 (2 bytes) : 以此往后的数据长度。 设置时间的 Data 结构如下:
- 1 (1 byte) : 返回码(return code);
- 2 (1 byte) : 数据传输大小(Transport sizes),通常有 bit、byte 等;
- 3 (2 bytes) : 以此往后的数据长度;
- 4 (10 bytes):时间戳。
S7comm 头结构中常见的错误类型,如下表:
Hex | Value | 描述 |
---|---|---|
0x00 | No error | 没有错误 |
0x81 | Application relationship | 应用关系 |
0x82 | Object definition | 对象定义 |
0x83 | No resources available | 没有可用资源 |
0x84 | Error on service processing | 服务处理中错误 |
0x85 | Error on supplies | 请求错误 |
0x87 | Access error | 访问错误 |
常见的 S7Comm 参数中的错误码,如下表:
Hex | Value | 描述 |
---|---|---|
0x0000 | No error | 无错误 |
0x0110 | Invalid block number | 无效的块编号 |
0x0111 | Invalid request length | 无效的请求长度 |
0x0112 | Invalid parameter | 无效参数 |
0x0113 | Invalid block type | 无效的块类型 |
0x0114 | Block not found | 块没有发现 |
0x0115 | Block already exists | 块已经存在 |
0x0116 | Block is write-protected | 块被写保护 |
0x0117 | The block/operating system update is too large | 块太大 |
0x0118 | Invalid block number | 无效的块编号 |
0x0119 | Incorrect password entered | 输入错误的密码 |
0x011A | PG resource error | PG 资源错误 |
0x011B | PLC resource error | PLC 资源错误 |
0x011C | Protocol error | 协议错误 |
当 PDU 类型是 JOB 和 ACK_DATA 时,常见的功能码,如下表:
Hex | Value | 值 |
---|---|---|
0x00 | CPU services | CPU服务 |
0xf0 | Setup communication | 建立通信 |
0x04 | Read Var | 读取值 |
0x05 | Write Var | 写入值 |
0x1a | Request download | 请求下载 |
0x1b | Download block | 下载块 |
0x1c | Download ended | 下载结束 |
0x1d | Start upload | 开始上传 |
0x1e | Upload | 上传 |
0x1f | End upload | 上传结束 |
0x28 | PI-Service | 程序调用服务 |
0x29 | PLC Stop | 关闭 PLC |
UserData 中常见的功能组,如下表:
值 | 功能组 |
---|---|
0x0 | 转换工作模式(Mode-transition) |
0x1 | 工程师命令调试(Programmer commands) |
0x2 | 循环读取(Cyclic data) |
0x3 | 块功能(Block functions) |
0x4 | CPU 功能(CPU functions) |
0x5 | 安全功能(Security) |
0x6 | PBC BSEND/BRECV |
0x7 | 时间功能(Time functions) |
0xf | NC 编程(NC programming) |
PLC 中常见的区域类型,如下表:
Hex | Value | 值 |
---|---|---|
0x03 | System info of 200 family | 200 系列系统信息 |
0x05 | System flags of 200 family | 200 系列系统标志 |
0x06 | Analog inputs of 200 family | 200 系列模拟量输入 |
0x07 | Analog outputs of 200 family | 200 系列模拟量输出 |
0x80 | Direct peripheral access (P) | 直接访问外设 |
0x81 | Inputs (I) | 输入(I) |
0x82 | Outputs (Q) | 输出(Q) |
0x83 | Flags (M) | 内部标志(M) |
0x84 | Data blocks (DB) | 数据块(DB) |
0x85 | Instance data blocks (DI) | 背景数据块(DI) |
0x86 | Local data (L) | 局部变量(L) |
0x87 | Unknown yet (V) | 全局变量(V) |
0x1c | S7 counters (C) | S7 计数器(C) |
0x1d | S7 timers (T) | S7 定时器(T) |
0x1e | IEC counters (200 family) | IEC 计数器(200系列) |
0x1f | IEC timers (200 family) | IEC 定时器(200系列) |
下表是 Item 数据的传输大小:
Hex | 值 | 描述 |
---|---|---|
1 | BIT | 位(1位) |
2 | BYTE | 字节(8位) |
3 | CHAR | 字符(8位) |
4 | WORD | 字(16位) |
5 | INT | 整数(16位) |
6 | DWORD | 双字(32位) |
7 | DINT | 有符号的整数(32位) |
8 | REAL | 浮点数(32位) |
10 | TOD | Time of day(32位) |
11 | TIME | IEC 时间(32位) |
12 | S5TIME | SIMATIC 时间(16位) |
15 | DATE_AND_TIME | 日期和时间 |
28 | COUNTER | 计数器 |
29 | TIMER | 定时器 |
30 | IEC TIMER | IEC 定时器 |
31 | IEC COUNTER | IEC 计数器 |
32 | HS COUNTER | HS 计数器 |
下表是数据部分中的值得传输大小:
Hex | 值 | 描述 |
---|---|---|
0 | NULL | |
3 | BIT | bit access, len is in bits |
4 | BYTE/WORD/DWORD | byte/word/dword access, len is in bits |
5 | INTEGER | integer access, len is in bits |
6 | DINTEGER | integer access, len is in bytes |
7 | REAL | real access, len is in bytes |
9 | OCTET | STRING octet string, len is in bytes |
下表是常见的变量的结构标识:
Hex | 值 | 描述 |
---|---|---|
0x10 | S7ANY | Address data S7-Any pointer-like DB1.DBX10.2 |
0x13 | PBC-R_ID | R_ID for PBC |
0x15 | ALARM_LOCKFREE | Alarm lock/free dataset |
0x16 | ALARM_IND | Alarm indication dataset |
0x19 | ALARM_ACK | Alarm acknowledge message dataset |
0x1a | ALARM_QUERYREQ | Alarm query request dataset |
0x1c | NOTIFY_IND | Notify indication dataset |
0xa2 | DRIVEESANY | seen on Drive ES Starter with routing over S7 |
0xb2 | 1200SYM | Symbolic address mode of S7-1200 |
0xb0 | DBREAD | Kind of DB block read, seen only at an S7-400 |
0x82 | NCK | Sinumerik NCK HMI access |
响应报文中 Data 部分的常见返回码,如下表:
Hex | 值 | 描述 |
---|---|---|
0x00 | Reserved | 未定义,预留 |
0x01 | Hardware error | 硬件错误 |
0x03 | Accessing the object not allowed | 对象不允许访问 |
0x05 | Invalid address | 无效地址,所需的地址超出此 PLC 的极限 |
0x06 | Data type not supported | 数据类型不支持 |
0x07 | Data type inconsistent | 日期类型不一致 |
0x0a | Object does not exist | 对象不存在 |
0xff | Success | 成功 |
在西门子设备中有8种不同类型的功能块:
Hex | 类型 | 描述 |
---|---|---|
0x3038 | OB,ASCII 为'08',组织块 | OB 决定用户程序的结构 |
0x3039 | CMod,ASCII 为'09' | |
0x3041 | DB,ASCII 为'0A',数据块 | DB 是用于存储用户数据的数据区域,除了指定给一个功能块的数据,还可以定义可以被任何块使用的共享数据 |
0x3042 | SDB,ASCII 为'0B',系统和数据块 | 由编程软件自动生成主要存放 PLC 的硬件组态等信息,用户无法直接打开和更改 |
0x3043 | FC,ASCII 为'0C',功能 | FB、FC 本质都是一样的,都相当于子程序,可以被其他程序调用(也可以调用其他子程序),FC 使用的是共享数据块 |
0x3044 | SFC,ASCII 为'0D',系统功能 | SFB 和 SFC 集成在 S7 CPU 中可以让你访问一些重要的系统功能 |
0x3045 | FB,ASCII 为'0E',功能块,带背景数据块 | FB、FC 本质都是一样的,都相当于子程序,可以被其他程序调用(也可以调用其他子程序),FB 使用的是背景数据块 |
0x3046 | SFB,ASCII 为'0F',系统功能块 | SFB 和 SFC 集成在 S7 CPU 中可以让你访问一些重要的系统功能 |
OB、FB、SFB、FC 和 SFC 都包含部分程序,因此也称作逻辑块。每种块类型所允许的块的数量以及块的长度视 CPU 而定。
下表是程序调用服务名称及其相关参数:
服务名 | 描述 |
---|---|
_INSE | PI-Service _INSE (Activates a PLC module) |
_DELE | PI-Service _DELE (Removes module from the PLC's passive file system) |
P_PROGRAM | PI-Service P_PROGRAM (PLC Start / Stop) |
_MODU | PI-Service _MODU (PLC Copy Ram to Rom) |
_GARB | PI-Service _GARB (Compress PLC memory) |
下表是扩展数据中参数类型:
值 | 类型 |
---|---|
0x0 | 推送(Push) |
0x4 | 请求(Request) |
0x8 | 响应(Response) |
0x3 | NC 推送(NC Push) |
0x7 | NC 请求(NC Request) |
0xb | NC 响应(NC Response) |