OpenPLC Runtime项目 Modbus.cpp 详细分析
OpenPLC Runtime项目 Modbus.cpp 文件分析
简述
简述描述了 Modbus.cpp 自身定位,基本概念(我是谁)。在 Openplc Runtime 项目中的作用,服务于哪些模块(我去哪)。
文件注释:Modbus.cpp 具有 OpenPLC 支持的所有 Modbus TCP 功能。
Modbus 基本概念:Modbus 是一种常用的串行通信协议,被广泛应用于工业自动化领域。
定义:由Modicon公司,现施耐德电气 Schineider Electric ,于1979年开发的一种串行通信协议。它最初设计用于可编程逻辑控制器(PLC)之间的通信,但现已成为工业领域通信协议的业界标准,并广泛应用于工业电子设备之间的连接。
核心概念:
- 开放式协议,免费可用。
- 串行通信,支持 RS-232、RS-485、还支持以太网,TCP/IP。
- 主/从架构,主节点(Master)负责启动,从(Slave)节点根据命令执行相应的操作并返回结果。
- 功能码,Modbus 协议定义了一系列功能码,用于指定设备执行不同的操作。
- 读取线圈状态
- 读取输入状态/离散输入,
- 读取保持寄存器
- 读取输入寄存器
- 写单个线圈
- 写单个寄存器
- 支持多种数据格式,
Coil,位,线圈Discrete Inputs,输入状态,离散输入Holding Registers,保持寄存器Input Registers,输入寄存器。
依赖
依赖描述了 Modbus 基于哪些服务层,才能实现自身的功能(我从哪来)。
本节内容主要源于Modbus.cpp代码文件。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "ladder.h"
#include <string.h>
#include "debug.h"
ladder.h作为 OpenPLC Runtime 项目的公共头文件。stdio.h、stdlib.h、string.h常用工具头文件。unistd.h提供操作系统底层功能的访问接口。pthread.h提供多线程支持,锁。debug.h提供了调试用的接口声明,接口实现在 debug.cpp ,由 .st 文件生成。
实现
实现本节描述了 Modbus 自身功能的实现思路和原理(为什么来)。
本节内容主要源于 Modbus.cpp 代码文件。
宏、全局变量
#define MAX_DISCRETE_INPUT 8192
#define MAX_COILS 8192
#define MAX_HOLD_REGS 8192
#define MAX_INP_REGS 1024
#define MIN_16B_RANGE 1024
#define MAX_16B_RANGE 2047
#define MIN_32B_RANGE 2048
#define MAX_32B_RANGE 4095
#define MIN_64B_RANGE 4096
#define MAX_64B_RANGE 8191
下面常量均带有 MAX 开头。
用于设置缓冲区长度,以及遍历的结束条件。
MAX_DISCRETE_INPUT离散输入个数最大值,用于设置离散输入缓冲区长度,以及遍历离散输入缓冲区。MAX_COILS线圈个数最大值,用于设置线圈缓冲区最大值,以及遍历线圈缓冲区。MAX_HOLD_REGS保持寄存器个数最大值,用于设置保持寄存器缓冲区长度,以及遍历保持寄存器缓冲区。MAX_INP_REGS输入寄存器个数最大值,用于设置输入寄存器缓冲区长度,以及遍历输入寄存器缓冲区。
下面常量均带有 RANGE 结尾。
用于 IO 时,作为过滤条件。也用于遍历缓冲区时,作为过滤条件。
MIN_16B_RANGE、MAX_16B_RANGE,限制 16 位的范围。1024-2047,长度为 1024 位,单位为 16B,存在 64 个 16 B。MIN_32B_RANGE、MAX_32B_RANGE,限制 32 位的范围。2048-4095,长度为 2048 位,单位为 32B,存在 64 个 32 B。MIN_64B_RANGE、MAX_64B_RANGE,限制 64 位的范围。4096-8191,长度为 4096 位,单位为 64B,存在 64 个 64 B。
下面常量是 Modbus 定义的状态码,功能码。
检查 buffer 的第 7 个字节是否等于功能码(见图),根据功能码调用相应的函数
Modbus.cpp processModbusMessage 函数。

#define MB_FC_NONE 0
#define MB_FC_READ_COILS 1
#define MB_FC_READ_INPUTS 2
#define MB_FC_READ_HOLDING_REGISTERS 3
#define MB_FC_READ_INPUT_REGISTERS 4
#define MB_FC_WRITE_COIL 5
#define MB_FC_WRITE_REGISTER 6
#define MB_FC_WRITE_MULTIPLE_COILS 15
#define MB_FC_WRITE_MULTIPLE_REGISTERS 16
#define MB_FC_DEBUG_INFO 0x41 // Request debug variables count
#define MB_FC_DEBUG_SET 0x42 // Debug set trace (force variable)
#define MB_FC_DEBUG_GET 0x43 // Debug get trace (read variables)
#define MB_FC_DEBUG_GET_LIST 0x44 // Debug get trace list (read list of variables)
#define MB_FC_DEBUG_GET_MD5 0x45 // Debug get current program MD5
#define MB_FC_ERROR 255
MB_FC_NONE,空MB_FC_READ_COILS,读线圈MB_FC_READ_INPUTS,读离散输入MB_FC_READ_HOLDING_REGISTERS,读保持寄存器MB_FC_READ_INPUT_REGISTERS,读输入寄存器MB_FC_WRITE_COIL,写线圈MB_FC_WRITE_REGISTER,写寄存器MB_FC_WRITE_MULTIPLE_COILS,写多线圈MB_FC_WRITE_MULTIPLE_REGISTERS,写多寄存器MB_FC_DEBUG_INFO,debug 信息MB_FC_DEBUG_GET,debug get trace,疑问:初识未知?,后来回答:显示索引范围内的变量数据。MB_FC_DEBUG_GET_LIST,debug get trace list,疑问:初识未知?,后来回答:响应包括在所提供的索引列表中指定的变量的跟踪数据。MB_FC_DEBUG_SET,debug set trace,MB_FC_DEBUG_GET_MD5,debug get md5,MB_FC_ERROR,错误码相关。
疑问:FC 是什么的简写?,回答:FC 是 Function 缩写,MB 是 Modbus 缩写。
下面宏均以 ERR 开头。
用于错误码设置函数,见下图。
Modbus.cpp ModbusError 函数。

函数显示,错误码设置在 buffer 的 index 为 8 的字节,长度设置为 9。
并且 index 为 7 的字节高位为 1。4 和 5 分别为 0 和 3。
// Modbus error codes,Modbus错误码,
// 同样,设置 buffer 的第 7 个字节的最高位为 1,第 8 位存储错误码
#define ERR_NONE 0
#define ERR_ILLEGAL_FUNCTION 1
#define ERR_ILLEGAL_DATA_ADDRESS 2
#define ERR_ILLEGAL_DATA_VALUE 3
#define ERR_SLAVE_DEVICE_FAILURE 4
#define ERR_SLAVE_DEVICE_BUSY 6
ERR_NONE,无错误ERR_ILLEGAL_FUNCTION,无效函数ERR_ILLEGAL_DATA_ADDRESS,无效数据地址,用于地址越界。ERR_ILLEGAL_DATA_VALUE,无效数据值,用于值溢出或不符合约定。ERR_SLAVE_DEVICE_FAILURE,从设备失败。ERR_SLAVE_DEVICE_BUSY,从设备忙。
下面是宏函数,作为工具函数,仅在 Modbus.cpp 中使用。
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
#define lowByte(w) ((unsigned char) ((w) & 0xff))
#define highByte(w) ((unsigned char) ((w) >> 8))
bitRead按位读bitSet按位写1bitClear按位置0bitWrite按位写0或1lowByte,取低8位highByte取高8位
下面这些宏与 debug 调试相关
#define MB_DEBUG_SUCCESS 0x7E
#define MB_DEBUG_ERROR_OUT_OF_BOUNDS 0x81
#define MB_DEBUG_ERROR_OUT_OF_MEMORY 0x82
#define SAME_ENDIANNESS 0
#define REVERSE_ENDIANNESS 1
#define MAX_MB_FRAME 260
初始化
全局变量声明和分配
// 离散输入缓存区
IEC_BOOL mb_discrete_input[MAX_DISCRETE_INPUT];
// 线圈缓存区
IEC_BOOL mb_coils[MAX_COILS];
// 输入寄存器
IEC_UINT mb_input_regs[MAX_INP_REGS];
// 保持寄存器
IEC_UINT mb_holding_regs[MAX_HOLD_REGS];
int MessageLength;
extern char md5[];
extern unsigned long __tick;
函数实现
函数实现概述
Modbus.cpp 中所有函数分为三种类别:入口函数、核心函数、工具函数。
调用关系依次是外部模块 -> 入口函数 -> 核心函数 -> 工具函数。
入口函数负责转发,接受外部模块的请求,在 OpenPLC rutnime 初始化完成后,进入 Modbus.cpp 文件的所有流量均从入口函数流入(mapUnusedIO 函数调用除外,见下文工具函数说明。),入口函数只有一个 processModbusMessage。经过入口函数的流量,经过功能码的检查,分别转发到不同的核心函数。
核心函数负责业务实现,接受入口函数调用,执行对应于功能码的业务,可能会调用工具函数帮助实现业务。
工具函数负责重复性高的局部功能实现,辅助核心函数完成业务。
入口函数:processModbusMessage。
向 server.cpp 提供服务。server.cpp 作为一个服务器,接受来自client的 TCP 请求,将 message 信息发送到此入口函数中。
核心函数:ModbusError、ReadCoils、ReadDiscreteInputs、ReadHoldingRegisters、ReadInputRegisters、WriteCoil、WriteRegister、WriteMultipleCoils、WriteMultipleRegisters、debugInfo、debugGetTrace、debugGetTraceList、debugSetTrace、debugGetMd5。
核心组件函数均在
processModbusMessage入口函数中,被调用。通过检测功能码,选择调用哪个核心组件函数。
工具函数:word、mapUnusedIO。
用于实现局部功能。
word,将两个字节连接成一个int型,读写线圈、离散输入、输入寄存器、保持寄存器时使用。mapUnusedIO,该函数将内部NULL OpenPLC缓冲区设置为指向Modbus缓冲区上的有效位置。在dnp3.cppdnp3StartServer函数中调用。- 此函数负责 Modbus 缓冲区的初始化启动,Modbus 初始化属于 OpenPLC runtime 启动时业务。
核心函数阅读
入口函数负责转发,工具函数实现局部功能,它们的角色已然明了,不再详细讨论。
本节对若干核心函数进行阅读讨论,搞清楚实现的具体业务,深刻理解 Modbus 协议内部逻辑。
核心函数:ModbusError、ReadCoils、ReadDiscreteInputs、ReadHoldingRegisters、ReadInputRegisters、WriteCoil、WriteRegister、WriteMultipleCoils、WriteMultipleRegisters、debugInfo、debugGetTrace、debugGetTraceList、debugSetTrace、debugGetMd5。
- 通用
ModbusError-
void ModbusError(unsigned char *buffer, int mb_error)
- buffer 为缓冲区,缓冲区定义在 server.cpp 中,在函数上下文持续传递。
unsigned char buffer[NET_BUFFER_SIZE]; - mb_error 为 Modbus 的错误码。
- 函数体负责将错误信息写入缓冲区,缓冲区各个字节存储的值存在格式规范,使用长度为 9 字节的 Modbus 响应报文,存储在 buffer 中,第7个字节的最高位设置为 1,表示错误响应,第8个字节存储错误码。
- 被调用的代码块
- 入口函数检查长度小于 8,
if (bufferSize < 8)。设置错误码为ERR_ILLEGAL_FUNTION,非法函数错误,ModbusError(buffer, ERR_ILLEGAL_FUNCTION);。
- 入口函数检查长度小于 8,
- buffer 为缓冲区,缓冲区定义在 server.cpp 中,在函数上下文持续传递。
- 线圈
ReadCoils-
void ReadCoils(unsigned char *buffer, int bufferSize)
-
buffer,buffer 为缓冲区,缓冲区定义在 server.cpp 中,在函数上下文持续传递。
unsigned char buffer[NET_BUFFER_SIZE]; -
bufferSize,客户端发送给
Server.cpp的消息长度,messageSize = listenToClient(client_fd, buffer); -
函数体负责,
- 非法检查
if (bufferSize < 12),if (ByteDataLength > 255) - 读取 buffer 内容,识别到
start有效数据存储位置的起始下标、CoilDataLength线圈数据长度、ByteDataLength字节数据长度。
Start = word(buffer[8], buffer[9]); CoilDataLength = word(buffer[10], buffer[11]); ByteDataLength = CoilDataLength / 8;- 加锁和解锁,
pthread_mutex_lock(&bufferLock);pthread_mutex_unlock(&bufferLock);- 锁对象
bufferLock在main.cpp定义,在头文件ladder.h额外声明,被Modbus.cpp引用。
- 锁对象
- 加锁临界区负责将
bool_output内容写入buffer,按位依次写入。疑问:bool_output 数据谁写入的? 回答:估计是WriteCoil函数写入的。
for(int i = 0; i < ByteDataLength ; i++) { for(int j = 0; j < 8; j++) { int position = Start + i * 8 + j; if (position < MAX_COILS) { if (bool_output[position/8][position%8] != NULL) { bitWrite(buffer[9 + i], j, *bool_output[position/8][position%8]); } else { bitWrite(buffer[9 + i], j, 0); } } } } - 非法检查
-
被调用的代码块
- 入口函数,
if(buffer[7] == MB_FC_READ_COILS)检查功能码为MB_FC_READ_COILS,Modbus 函数读线圈 ,ReadCoils(buffer, bufferSize);。
- 入口函数,
-
WriteCoil-
void WriteCoil(unsigned char *buffer, int bufferSize)
-
buffer,buffer,buffer 为缓冲区,缓冲区定义在 server.cpp 中,在函数上下文持续传递。unsigned char buffer[NET_BUFFER_SIZE]; -
bufferSize,客户端发送给
Server.cpp的消息长度,messageSize = listenToClient(client_fd, buffer); -
函数体负责设置
bool_output特定位为 0 或 1,- 非法检查,
if (bufferSize < 12),if (Start < MAX_COILS) - 识别起始下标,
Start = word(buffer[8], buffer[9]); - 分配写入值
if (word(buffer[10], buffer[11]) > 0) value = 1; - 加锁解锁,
pthread_mutex_lock(&bufferLock);,pthread_mutex_unlock(&bufferLock); - 临界区中,设置 bool_ouput 特定位的值,
if (bool_output[Start/8][Start%8] != NULL) { *bool_output[Start/8][Start%8] = value; } - 非法检查,
-
被调用的代码块
- 入口函数,
if(buffer[7] == MB_FC_WRITE_COIL),Modbus 函数写线圈,WriteCoil(buffer, bufferSize);。
- 入口函数,
-
WriteMultipleCoils-
void WriteMultipleCoils(unsigned char *buffer, int bufferSize)
buffer,buffer,buffer 为缓冲区,缓冲区定义在 server.cpp 中,在函数上下文持续传递。unsigned char buffer[NET_BUFFER_SIZE];- bufferSize,客户端发送给
Server.cpp的消息长度,messageSize = listenToClient(client_fd, buffer); - 函数体负责将
buffer中有效位循环写入bool_output的特定位,- 非法检查,
if (bufferSize < 12),if ( (bufferSize < (13 + ByteDataLength)) || (buffer[12] != ByteDataLength) ) - 识别
Startbuffer 中有效位起始下标,CoilDataLength线圈数据位长度,ByteDataLength线圈数据字节长度。
Start = word(buffer[8],buffer[9]); CoilDataLength = word(buffer[10],buffer[11]); ByteDataLength = CoilDataLength / 8;- 按规则,准备响应buffer中特定位,
buffer[4] = 0;buffer[5] = 6; - 加锁解锁,
pthread_mutex_lock(&bufferLock);,pthread_mutex_unlock(&bufferLock); - 临界区负责循环写入
bool_output的特定位,
for(int i = 0; i < ByteDataLength ; i++) { for(int j = 0; j < 8; j++) { int position = Start + i * 8 + j; if (position < MAX_COILS) { if (bool_output[position/8][position%8] != NULL) *bool_output[position/8][position%8] = bitRead(buffer[13 + i], j); } } } - 非法检查,
- 被调用代码块,
- 入口函数,
if(buffer[7] == MB_FC_WRITE_MULTIPLE_COILS),WriteMultipleCoils(buffer, bufferSize);
- 入口函数,
-
- 离散输入
- ReadDiscreteInputs
-
void ReadDiscreteInputs(unsigned char *buffer, int bufferSize)
buffer,buffer,buffer 为缓冲区,缓冲区定义在 server.cpp 中,在函数上下文持续传递。unsigned char buffer[NET_BUFFER_SIZE];- bufferSize,客户端发送给
Server.cpp的消息长度,messageSize = listenToClient(client_fd, buffer); - 函数体负责循环按位将
bool_input有效位写入buffer。- 识别局部信息
Start = word(buffer[8],buffer[9]); InputDataLength = word(buffer[10],buffer[11]); ByteDataLength = InputDataLength / 8;- 加解锁,
pthread_mutex_lock(&bufferLock);pthread_mutex_unlock(&bufferLock); - 临界区中循环写入
for(int i = 0; i < ByteDataLength ; i++) { for(int j = 0; j < 8; j++) { int position = Start + i * 8 + j; if (position < MAX_DISCRETE_INPUT) { if (bool_input[position/8][position%8] != NULL) { bitWrite(buffer[9 + i], j, *bool_input[position/8][position%8]); } } } } - 被调用代码块,
- 入口函数,
if(buffer[7] == MB_FC_READ_INPUTS) ReadDiscreteInputs(buffer, bufferSize);。
- 入口函数,
-
- ReadDiscreteInputs
- 寄存器,省略内容重复的部分(buffer、bufferSize参数,加解锁),保留关键内容,便于阅读。
- ReadHoldingRegisters
-
void ReadHoldingRegisters(unsigned char *buffer, int bufferSize)
- 函数体负责循环按字节将
int_memory,dint_memory,lint_memory内容写入buffer,- 识别局部变量,
Start = word(buffer[8],buffer[9]); WordDataLength = word(buffer[10],buffer[11]); ByteDataLength = WordDataLength * 2;- 配置响应buffer格式
buffer[4] = highByte(ByteDataLength + 3); buffer[5] = lowByte(ByteDataLength + 3); //Number of bytes after this one buffer[8] = ByteDataLength; //Number of bytes of data- 临界区负责写入 buffer
// 16 位内存,每次写入 2 个 8 位。 //... buffer[ 9 + i * 2] = highByte(*int_memory[position - MIN_16B_RANGE]); buffer[10 + i * 2] = lowByte(*int_memory[position - MIN_16B_RANGE]); // 32 位内存,写入到 buffer 中,每次写入2 个 8位 // ... uint16_t tempValue = (uint16_t)(*dint_memory[(position - MIN_32B_RANGE)/2] >> 16); buffer[ 9 + i * 2] = highByte(tempValue); buffer[10 + i * 2] = lowByte(tempValue); // ... uint16_t tempValue = (uint16_t)(*dint_memory[(position - MIN_32B_RANGE)/2] & 0xffff); buffer[ 9 + i * 2] = highByte(tempValue); buffer[10 + i * 2] = lowByte(tempValue); // 64 位内存,每次写入 2 个8位 //... uint16_t tempValue = (uint16_t)(*lint_memory[(position - MIN_64B_RANGE)/4] >> 48); buffer[ 9 + i * 2] = highByte(tempValue); buffer[10 + i * 2] = lowByte(tempValue); //... uint16_t tempValue = (uint16_t)((*lint_memory[(position - MIN_64B_RANGE)/4] >> 32) & 0xffff); buffer[ 9 + i * 2] = highByte(tempValue); buffer[10 + i * 2] = lowByte(tempValue); //... uint16_t tempValue = (uint16_t)((*lint_memory[(position - MIN_64B_RANGE)/4] >> 16) & 0xffff); buffer[ 9 + i * 2] = highByte(tempValue); buffer[10 + i * 2] = lowByte(tempValue); //... uint16_t tempValue = (uint16_t)(*lint_memory[(position - MIN_64B_RANGE)/4] & 0xffff); buffer[ 9 + i * 2] = highByte(tempValue); buffer[10 + i * 2] = lowByte(tempValue); - 被调代码块,
- 入口函数,
MB_FC_READ_HOLDING_REGISTERS,
- 入口函数,
-
- ReadInputRegisters
-
void ReadInputRegisters(unsigned char *buffer, int bufferSize)
- 函数体负责循环按字节将
int_input写入buffer,- 识别局部信息
Start = word(buffer[8],buffer[9]); WordDataLength = word(buffer[10],buffer[11]); ByteDataLength = WordDataLength * 2;- 准备响应格式
Start = word(buffer[8],buffer[9]); WordDataLength = word(buffer[10],buffer[11]); ByteDataLength = WordDataLength * 2;- 临界区循环写入
int_input,是buffer[ 9 + i * 2] = highByte(*int_input[position]); buffer[10 + i * 2] = lowByte(*int_input[position]);unsigned short int类型数组。 - 被调用代码块
- 入口函数,
MB_FC_READ_INPUT_REGISTERS
- 入口函数,
-
- WriteRegister,在给定的位置向寄存器写入一个单词。调用者必须持有“ BufferLock”。
-
void WriteRegister(unsigned char *buffer, int bufferSize)
- 函数体负责将
buffer内容写入int_memory、mb_holding_regs、dint_memory、lint_memory,- 识别局部变量,
Start = word(buffer[8],buffer[9])。 - 临界区写入封装函数调用,mb_error = writeToRegisterWithoutLocking(Start, word(buffer[10], buffer[11]));
-
int writeToRegisterWithoutLocking(int position, uint16_t value)
- position,有效位起始位置。
- value,16位数据,需要写入的值。
- return int,错误码,反映执行状态。
// 模拟输出 *int_output[position] = value; // 16 位 *int_memory[position - MIN_16B_RANGE] = value; // 32 位 mb_holding_regs[position] = value; // Overwrite one word of the 32 bit register: // Calculate the bit offset of the word in the 32 bit register. int bit_offset = (1 - ((position - MIN_32B_RANGE) % 2)) * 16; // Mask the word. *dint_memory[(position - MIN_32B_RANGE) / 2] &= ~(((uint32_t) 0xffff) << bit_offset); // Overwrite the word. *dint_memory[(position - MIN_32B_RANGE) / 2] |= ((uint32_t) value) << bit_offset; // 64 位 mb_holding_regs[position] = value; // Overwrite one word of the 64 bit register: // Calculate the bit offset of the word in the 64 bit register. int bit_offset = (3 - ((position - MIN_64B_RANGE) % 4)) * 16; // Mask the word. *lint_memory[(position - MIN_64B_RANGE) / 4] &= ~(((uint64_t) 0xffff) << bit_offset); // Overwrite the word. *lint_memory[(position - MIN_64B_RANGE) / 4] |= ((uint64_t) value) << bit_offset; - 识别局部变量,
- 被调用代码块,
- 入口函数,
MB_FC_WRITE_COIL
- 入口函数,
-
- WriteMultipleRegisters
-
void WriteMultipleRegisters(unsigned char *buffer, int bufferSize)
- 函数体负责循环将
buffer内容写入int_memory、mb_holding_regs、dint_memory、lint_memory- 识别局部变量
Start = word(buffer[8],buffer[9]); WordDataLength = word(buffer[10],buffer[11]); ByteDataLength = WordDataLength * 2;- 准备响应格式
buffer[4] = 0; buffer[5] = 6; //Number of bytes after this one.- 临界区负责循环写入,
传入 16 位数据,写入到for(int i = 0; i < WordDataLength; i++) { int position = Start + i; int error = writeToRegisterWithoutLocking(position, word(buffer[13 + i * 2], buffer[14 + i * 2])); }posistion下标的位置。 - 被调用代码块,
- 入口函数,
MB_FC_WRITE_MULTIPLE_REGISTERS
- 入口函数,
-
- ReadHoldingRegisters
- 调试
- debugInfo,发送DEBUG_INFO功能代码的Modbus响应帧。这个函数为DEBUG_INFO函数代码构造一个Modbus响应帧。响应帧包括PLC程序中定义的变量的数量。
* Modbus Response Frame (DEBUG_INFO): * +-----+-------+-------+ * | MB | Count | Count | * | FC | | | * +-----+-------+-------+ * |0x41 | High | Low | * | | Byte | Byte | * | | | | * +-----+-------+-------+-
void debugInfo(unsigned char *mb_frame)
- 被调用代码,
- 入口函数,
MB_FC_DEBUG_INFO,debugInfo(buffer);。
- 入口函数,
- debugGetTrace,这个函数为DEBUG_GET函数代码构造一个Modbus响应帧。响应帧包括指定索引范围内变量的跟踪数据。
- debugGetTraceList,这个函数为DEBUG_GET_LIST函数代码构造一个Modbus响应帧。响应框架包括在所提供的索引列表中指定的变量的跟踪数据。
- debugSetTrace,这个函数为DEBUG_SET函数代码构造一个Modbus响应帧。响应帧指示set trace命令是否成功,或者是否有错误,比如索引越界。
- debugGetMd5,
浙公网安备 33010602011771号