| | |
| | | #include <sstream> |
| | | #include <unordered_map> |
| | | |
| | | // 连接参数 |
| | | #define PLC_MAX_RETRY 3 // 最大重试次数:在与PLC通信时,如果发生通信错误,将最多重试3次 |
| | | #define PLC_TIMEOUT 500 // 超时时间(毫秒):每次通信操作的超时等待时间为500毫秒 |
| | | // 连接参数 |
| | | #define PLC_MAX_RETRY 3 // 最大重试次数:在与PLC通信时,如果发生通信错误,将最多重试3次 |
| | | #define PLC_TIMEOUT 500 // 超时时间(毫秒):每次通信操作的超时等待时间为500毫秒 |
| | | |
| | | /* |
| | | * 网络通道:指定通信所使用的网络通道号,通常在多通道通信中设置 |
| | | * 51 到 54 是 MELSECNET/H 的 1-4 通道 |
| | | * 81 到 84 是 CC-Link 的 1-4 通道 |
| | | * 151 到 154 是 CC-Link IE 控制器网络的 1-4 通道 |
| | | * 181 到 184 是 CC-Link IE 现场网络的 1-4 通道 |
| | | * 281 到 284 是 CC-Link IE TSN 网络的 1-4 通道 |
| | | * 网络通道:指定通信所使用的网络通道号,通常在多通道通信中设置 |
| | | * 51 到 54 是 MELSECNET/H 的 1-4 通道 |
| | | * 81 到 84 是 CC-Link 的 1-4 通道 |
| | | * 151 到 154 是 CC-Link IE 控制器网络的 1-4 通道 |
| | | * 181 到 184 是 CC-Link IE 现场网络的 1-4 通道 |
| | | * 281 到 284 是 CC-Link IE TSN 网络的 1-4 通道 |
| | | **/ |
| | | #define MELSECNET_CHANNEL(x) (50 + (x)) // x 范围:1~4 |
| | | #define CC_LINK_CHANNEL(x) (80 + (x)) // x 范围:1~4 |
| | | #define CC_LINK_IE_CONTROL_CHANNEL(x) (150 + (x)) // x 范围:1~4 |
| | | #define CC_LINK_IE_FIELD_CHANNEL(x) (180 + (x)) // x 范围:1~4 |
| | | #define CC_LINK_IE_TSN_CHANNEL(x) (280 + (x)) // x 范围:1~4 |
| | | #define MELSECNET_CHANNEL(x) (50 + (x)) // x 范围:1~4 |
| | | #define CC_LINK_CHANNEL(x) (80 + (x)) // x 范围:1~4 |
| | | #define CC_LINK_IE_CONTROL_CHANNEL(x) (150 + (x)) // x 范围:1~4 |
| | | #define CC_LINK_IE_FIELD_CHANNEL(x) (180 + (x)) // x 范围:1~4 |
| | | #define CC_LINK_IE_TSN_CHANNEL(x) (280 + (x)) // x 范围:1~4 |
| | | |
| | | // 自定义错误码 |
| | | #define ERROR_CODE_UNKNOWN 0x00010000 // 未知 |
| | | #define ERROR_CODE_NOT_CONNECTED 0x00020000 // 未连接 |
| | | #define ERROR_CODE_INVALID_PARAM 0x00030000 // 参数无效 |
| | | #define ERROR_CODE_INVALID_DATA 0x00040000 // 数据无效 |
| | | #define ERROR_CODE_STATION_OUT_OF_RANGE 0x00050000 // 站号超出范围 |
| | | #define ERROR_CODE_GROUP_OUT_OF_RANGE 0x00060000 // 组号超出范围 |
| | | #define ERROR_CODE_NETWORK_OUT_OF_RANGE 0x00070000 // 网络号超出范围 |
| | | // 自定义错误码 |
| | | #define ERROR_CODE_UNKNOWN 0x00010000 // δ֪ |
| | | #define ERROR_CODE_NOT_CONNECTED 0x00020000 // 未连接 |
| | | #define ERROR_CODE_INVALID_PARAM 0x00030000 // 参数无效 |
| | | #define ERROR_CODE_INVALID_DATA 0x00040000 // 数据无效 |
| | | #define ERROR_CODE_STATION_OUT_OF_RANGE 0x00050000 // 站号超出范围 |
| | | #define ERROR_CODE_GROUP_OUT_OF_RANGE 0x00060000 // 组号超出范围 |
| | | #define ERROR_CODE_NETWORK_OUT_OF_RANGE 0x00070000 // 网络号超出范围 |
| | | |
| | | // 板块类型 |
| | | // 板块类型 |
| | | enum class BoardType { |
| | | UNKNOWN = -1, // 未知类型 |
| | | UNKNOWN = -1, // 未知类型 |
| | | MELSECNET_H = MELSECNET_CHANNEL(1), // MELSECNET/H |
| | | CC_LINK_VER_2 = CC_LINK_CHANNEL(1), // CC-Link Ver. 2 |
| | | CC_LINK_IE_CONTROL = CC_LINK_IE_CONTROL_CHANNEL(1), // CC-Link IE 控制网络 |
| | | CC_LINK_IE_FIELD = CC_LINK_IE_FIELD_CHANNEL(1), // CC-Link IE 现场网络 |
| | | CC_LINK_IE_CONTROL = CC_LINK_IE_CONTROL_CHANNEL(1), // CC-Link IE 控制网络 |
| | | CC_LINK_IE_FIELD = CC_LINK_IE_FIELD_CHANNEL(1), // CC-Link IE 现场网络 |
| | | CC_LINK_IE_TSN = CC_LINK_IE_TSN_CHANNEL(1) // CC-Link IE TSN |
| | | }; |
| | | |
| | | // 软元件类型枚举 |
| | | // 软元件类型枚举 |
| | | enum class DeviceType { |
| | | /* |
| | | * ER、LX、LY、LB、LW、LSB、LSW和SPG软元件都是范围型 |
| | | * ER:DevER0~256 |
| | | * LX:DevLX1~255,DevLX(x) (DevX*1000+(x)) |
| | | * LY:DevLY1~255,DevLY(x) (DevY*1000+(x)) |
| | | * LB:DevLB1~255,DevLB(x) (DevB*1000+(x)) |
| | | * LW:DevLW1~255,DevLW(x) (DevW*1000+(x)) |
| | | * LSB:DevLSB1~255,DevLSB(x) (DevQSB*1000+(x)) |
| | | * LSW:DevLSW1~255,DevLSW(x) (DevQSW*1000+(x)) |
| | | * SPG:DevSPG0~255,DevSPG(x) (29*1000+(x)) |
| | | * 扩展文件寄存器代码指定(10进制数)的后3位数及软元件名指定的数值中,应指定块No.(0~256) |
| | | * 链接直接软元件代码指定(10进制数)的后3位数及软元件名指定的数值中,应指定网络No.(1~255) |
| | | * 智能功能模块软元件代码指定(10进制数)的后3位数及软元件名指定的数值中,应指定(起始I/ONo.÷16)的值 |
| | | * 扩展文件寄存器和链接直接软元件在随机读取(mdRandR、mdRandREx)函数中,即使指定实际不存在的软元件也有可能正常结束 |
| | | * MAIL和MAILMC在SEND功能及RECV功能中,与软元件访问一样,指定各功能对应的软元件类型,进行数据的发送(mdSend、mdSendEx)或数据的读取(mdReceive、mdReceiveEx) |
| | | * ER、LX、LY、LB、LW、LSB、LSW和SPG软元件都是范围型 |
| | | * ER:DevER0~256 |
| | | * LX:DevLX1~255,DevLX(x) (DevX*1000+(x)) |
| | | * LY:DevLY1~255,DevLY(x) (DevY*1000+(x)) |
| | | * LB:DevLB1~255,DevLB(x) (DevB*1000+(x)) |
| | | * LW:DevLW1~255,DevLW(x) (DevW*1000+(x)) |
| | | * LSB:DevLSB1~255,DevLSB(x) (DevQSB*1000+(x)) |
| | | * LSW:DevLSW1~255,DevLSW(x) (DevQSW*1000+(x)) |
| | | * SPG:DevSPG0~255,DevSPG(x) (29*1000+(x)) |
| | | * 扩展文件寄存器代码指定(10进制数)的后3位数及软元件名指定的数值中,应指定块No.(0~256) |
| | | * 链接直接软元件代码指定(10进制数)的后3位数及软元件名指定的数值中,应指定网络No.(1~255) |
| | | * 智能功能模块软元件代码指定(10进制数)的后3位数及软元件名指定的数值中,应指定(起始I/ONo.÷16)的值 |
| | | * 扩展文件寄存器和链接直接软元件在随机读取(mdRandR、mdRandREx)函数中,即使指定实际不存在的软元件也有可能正常结束 |
| | | * MAIL和MAILMC在SEND功能及RECV功能中,与软元件访问一样,指定各功能对应的软元件类型,进行数据的发送(mdSend、mdSendEx)或数据的读取(mdReceive、mdReceiveEx) |
| | | **/ |
| | | |
| | | X = 0x0001, // 输入 (位) |
| | | Y = 0x0002, // 输出 (位) |
| | | L = 0x0003, // 锁存继电器 (位) |
| | | M = 0x0004, // 内部继电器 (位) |
| | | SM = 0x0005, // 特殊继电器 (位) |
| | | F = 0x0006, // 报警器 (位) |
| | | TT = 0x0007, // 定时器 (触点) (位) |
| | | TC = 0x0008, // 计数器 (线圈) (位) |
| | | CT = 0x0009, // 计数器 (触点) (位) |
| | | CC = 0x000A, // 计数器 (线圈) (字) |
| | | TN = 0x000B, // 定时器 (当前值) (字) |
| | | CN = 0x000C, // 计数器 (当前值) (字) |
| | | D = 0x000D, // 数据寄存器 (字) |
| | | SD = 0x000E, // 特殊寄存器 (字) |
| | | TM = 0x000F, // 定时器 (设置值主) (字) |
| | | TS = 0x0010, // 定时器 (设置值主1) (字) |
| | | TS2 = 0x3E82, // 定时器 (设置值主2) (字) |
| | | TS3 = 0x3E83, // 定时器 (设置值主3) (字) |
| | | CM = 0x0011, // 计数器 (设置值主) (字) |
| | | CS = 0x0012, // 计数器 (设置值主1) (字) |
| | | CS2 = 0x4652, // 计数器 (设置值主2) (字) |
| | | CS3 = 0x4653, // 计数器 (设置值主3) (字) |
| | | A = 0x0013, // 累加器 (字) |
| | | Z = 0x0014, // 变址寄存器 (字) |
| | | V = 0x0015, // 变址寄存器 (字) |
| | | R = 0x0016, // 文件寄存器 (块切换方式) (字) |
| | | ER = 0x55F0, // 扩展文件寄存器 (块切换方式) (0x55F0~0x56F0) (字) (在随机读取(mdRandR、mdRandREx)函数中,即使指定实际不存在的软元件也有可能正常结束。(读取数据不正确。)) |
| | | ZR = 0x00DC, // 文件寄存器 (连号访问方式) (字) |
| | | B = 0x0017, // 链接继电器 (位) |
| | | W = 0x0018, // 链接寄存器 (字) |
| | | QSB = 0x0019, // 链接特殊继电器 (位) |
| | | STT = 0x001A, // 累计定时器 (触点) (位) |
| | | STC = 0x001B, // 累计定时器 (线圈) (位) |
| | | QSW = 0x001C, // 链接特殊寄存器 (字) |
| | | QV = 0x001E, // 变址继电器 (位) |
| | | MRB = 0x0021, // 随机访问缓冲 (字) |
| | | STN = 0x0023, // 累计定时器 (当前值) (字) |
| | | LZ = 0x0026, // 超长变址寄存器 (双字) |
| | | RD = 0x0027, // 刷新数据寄存器 (字) |
| | | LTT = 0x0029, // 超长定时器 (触点) (位) |
| | | LTC = 0x002A, // 超长定时器 (线圈) (位) |
| | | LTN = 0x002B, // 超长定时器 (当前值) (双字) |
| | | LCT = 0x002C, // 超长计数器 (触点) (位) |
| | | LCC = 0x002D, // 超长计数器 (线圈) (位) |
| | | LCN = 0x002E, // 超长计数器 (当前值) (双字) |
| | | LSTT = 0x002F, // 超长累计定时器 (触点) (位) |
| | | LSTC = 0x0030, // 超长累计定时器 (线圈) (位) |
| | | LSTN = 0x0031, // 超长累计定时器 (当前值) (双字) |
| | | SPB = 0x0032, // 缓冲存储器 (字) |
| | | MAIL = 0x0065, // 特殊软元件类型:邮件类型 (10进制 101) |
| | | MAILMC = 0x0066, // 特殊软元件类型:无确认邮件 (10进制 102) |
| | | LX = 0x03E8, // 链接直接软元件 (链接输入) (0x03E9~0x04E7) (位) |
| | | LY = 0x07D0, // 链接直接软元件 (链接输出) (0x07D1~0x08CF) (位) |
| | | LB = 0x59D8, // 链接直接软元件 (链接继电器) (0x59D9~0x5AD7) (位) |
| | | LW = 0x5DC0, // 链接直接软元件 (链接寄存器) (0x5DC1~0x5EBF) (字) |
| | | LSB = 0x61A8, // 链接直接软元件 (链接特殊继电器) (0x61A9~0x62A7) (位) |
| | | LSW = 0x6D60, // 链接直接软元件 (链接特殊寄存器) (0x6D61~0x6E5F) (字) |
| | | SPG = 0x7147, // 智能功能模块软元件 (0x7148~0x7247) (字) |
| | | X = 0x0001, // 输入 (位) |
| | | Y = 0x0002, // 输出 (位) |
| | | L = 0x0003, // 锁存继电器 (位) |
| | | M = 0x0004, // 内部继电器 (位) |
| | | SM = 0x0005, // 特殊继电器 (位) |
| | | F = 0x0006, // 报警器 (位) |
| | | TT = 0x0007, // 定时器 (触点) (位) |
| | | TC = 0x0008, // 计数器 (线圈) (位) |
| | | CT = 0x0009, // 计数器 (触点) (位) |
| | | CC = 0x000A, // 计数器 (线圈) (字) |
| | | TN = 0x000B, // 定时器 (当前值) (字) |
| | | CN = 0x000C, // 计数器 (当前值) (字) |
| | | D = 0x000D, // 数据寄存器 (字) |
| | | SD = 0x000E, // 特殊寄存器 (字) |
| | | TM = 0x000F, // 定时器 (设置值主) (字) |
| | | TS = 0x0010, // 定时器 (设置值主1) (字) |
| | | TS2 = 0x3E82, // 定时器 (设置值主2) (字) |
| | | TS3 = 0x3E83, // 定时器 (设置值主3) (字) |
| | | CM = 0x0011, // 计数器 (设置值主) (字) |
| | | CS = 0x0012, // 计数器 (设置值主1) (字) |
| | | CS2 = 0x4652, // 计数器 (设置值主2) (字) |
| | | CS3 = 0x4653, // 计数器 (设置值主3) (字) |
| | | A = 0x0013, // 累加器 (字) |
| | | Z = 0x0014, // 变址寄存器 (字) |
| | | V = 0x0015, // 变址寄存器 (字) |
| | | R = 0x0016, // 文件寄存器 (块切换方式) (字) |
| | | ER = 0x55F0, // 扩展文件寄存器 (块切换方式) (0x55F0~0x56F0) (字) (在随机读取(mdRandR、mdRandREx)函数中,即使指定实际不存在的软元件也有可能正常结束。(读取数据不正确。)) |
| | | ZR = 0x00DC, // 文件寄存器 (连号访问方式) (字) |
| | | B = 0x0017, // 链接继电器 (位) |
| | | W = 0x0018, // 链接寄存器 (字) |
| | | QSB = 0x0019, // 链接特殊继电器 (位) |
| | | STT = 0x001A, // 累计定时器 (触点) (位) |
| | | STC = 0x001B, // 累计定时器 (线圈) (位) |
| | | QSW = 0x001C, // 链接特殊寄存器 (字) |
| | | QV = 0x001E, // 变址继电器 (位) |
| | | MRB = 0x0021, // 随机访问缓冲 (字) |
| | | STN = 0x0023, // 累计定时器 (当前值) (字) |
| | | LZ = 0x0026, // 超长变址寄存器 (双字) |
| | | RD = 0x0027, // 刷新数据寄存器 (字) |
| | | LTT = 0x0029, // 超长定时器 (触点) (位) |
| | | LTC = 0x002A, // 超长定时器 (线圈) (位) |
| | | LTN = 0x002B, // 超长定时器 (当前值) (双字) |
| | | LCT = 0x002C, // 超长计数器 (触点) (位) |
| | | LCC = 0x002D, // 超长计数器 (线圈) (位) |
| | | LCN = 0x002E, // 超长计数器 (当前值) (双字) |
| | | LSTT = 0x002F, // 超长累计定时器 (触点) (位) |
| | | LSTC = 0x0030, // 超长累计定时器 (线圈) (位) |
| | | LSTN = 0x0031, // 超长累计定时器 (当前值) (双字) |
| | | SPB = 0x0032, // 缓冲存储器 (字) |
| | | MAIL = 0x0065, // 特殊软元件类型:邮件类型 (10进制 101) |
| | | MAILMC = 0x0066, // 特殊软元件类型:无确认邮件 (10进制 102) |
| | | LX = 0x03E8, // 链接直接软元件 (链接输入) (0x03E9~0x04E7) (位) |
| | | LY = 0x07D0, // 链接直接软元件 (链接输出) (0x07D1~0x08CF) (位) |
| | | LB = 0x59D8, // 链接直接软元件 (链接继电器) (0x59D9~0x5AD7) (位) |
| | | LW = 0x5DC0, // 链接直接软元件 (链接寄存器) (0x5DC1~0x5EBF) (字) |
| | | LSB = 0x61A8, // 链接直接软元件 (链接特殊继电器) (0x61A9~0x62A7) (位) |
| | | LSW = 0x6D60, // 链接直接软元件 (链接特殊寄存器) (0x6D61~0x6E5F) (字) |
| | | SPG = 0x7147, // 智能功能模块软元件 (0x7148~0x7247) (字) |
| | | }; |
| | | |
| | | // 数据类型 |
| | | // 数据类型 |
| | | enum class DataType { |
| | | BIT = 1, // 位 (1位) |
| | | WORD = 2, // 字 (16位) |
| | | DWORD = 4 // 双字 (32位) |
| | | BIT = 1, // λ (1λ) |
| | | WORD = 2, // 字 (16位) |
| | | DWORD = 4 // 双字 (32位) |
| | | }; |
| | | |
| | | // 控制代码 |
| | | // 控制代码 |
| | | enum class ControlCode { |
| | | RUN = 0, // 远程 RUN |
| | | STOP = 1, // 远程 STOP |
| | | PAUSE = 2 // 远程 PAUSE |
| | | RUN = 0, // 远程 RUN |
| | | STOP = 1, // 远程 STOP |
| | | PAUSE = 2 // 远程 PAUSE |
| | | }; |
| | | |
| | | // 版本信息 |
| | | // 版本信息 |
| | | struct BoardVersion { |
| | | char fixedValue[2]; // 固定值 |
| | | char checksum[2]; // 校验和 |
| | | char swVersion[2]; // 软件版本 |
| | | char date[6]; // 日期 (格式 YYMMDD) |
| | | uint32_t reserved; // 保留区域 (4 字节) |
| | | char swModel[16]; // 软件型号 |
| | | char hwModel[16]; // 硬件型号 |
| | | char twoPortMemory[2]; // 两端口存储器占用容量 |
| | | char twoPortAttribute[2]; // 两端口属性 |
| | | char availableBias[2]; // 可使用偏置 |
| | | char moduleType[10]; // 机型类型 |
| | | char fixedValue[2]; // 固定值 |
| | | char checksum[2]; // 校验和 |
| | | char swVersion[2]; // 软件版本 |
| | | char date[6]; // 日期 (格式 YYMMDD) |
| | | uint32_t reserved; // 保留区域 (4 字节) |
| | | char swModel[16]; // 软件型号 |
| | | char hwModel[16]; // 硬件型号 |
| | | char twoPortMemory[2]; // 两端口存储器占用容量 |
| | | char twoPortAttribute[2]; // 两端口属性 |
| | | char availableBias[2]; // 可使用偏置 |
| | | char moduleType[10]; // 机型类型 |
| | | |
| | | // 输出结构体内容为字符串 (便于调试) |
| | | // 输出结构体内容为字符串 (便于调试) |
| | | std::string toString() const { |
| | | std::ostringstream oss; |
| | | oss << "Fixed Value: " << fixedValue[0] << fixedValue[1] << "\n" |
| | |
| | | } |
| | | }; |
| | | |
| | | // 站点标识符,默认使用本站 |
| | | // 站点标识符,默认使用本站 |
| | | struct StationIdentifier { |
| | | /* |
| | | * [Network No.] |
| | | * 0 表示本站 |
| | | * 1~239 表示普通网络号 |
| | | * 0 表示本站 |
| | | * 1~239 表示普通网络号 |
| | | **/ |
| | | |
| | | /* |
| | | * [Station No.] |
| | | * MELSECNET/H:1~64 表示其他站点,255 表示本站 |
| | | * CC-Link 系列网络的范围类似,区别在于站号的取值范围 |
| | | * MELSECNET/H:1~64 表示其他站点,255 表示本站 |
| | | * CC-Link 系列网络的范围类似,区别在于站号的取值范围 |
| | | * MELSECNET/H : 1~64(Other stations),255(Own station) |
| | | * CC-Link : 0~63(Other stations),255(Own station) |
| | | * CC-Link IE Controller : 1~120(Other stations),255(Own station) |
| | |
| | | **/ |
| | | |
| | | /* |
| | | * 高 8 位(网络号): 指定设备所属的网络 |
| | | * 低 8 位(站点号): 指定设备在网络中的编号 |
| | | * 用一个参数传递设备的网络号和站点号时: nSt = station.nStNo | ((station.nNetNo << 8) & 0xFF00); |
| | | * 高 8 位(网络号): 指定设备所属的网络 |
| | | * 低 8 位(站点号): 指定设备在网络中的编号 |
| | | * 用一个参数传递设备的网络号和站点号时: nSt = station.nStNo | ((station.nNetNo << 8) & 0xFF00); |
| | | **/ |
| | | |
| | | short nNetNo = 0; // 网络编号:PLC所连接的网络编号,0表示默认网络 |
| | | short nStNo = 255; // 站点编号:指定与PLC连接的站点编号,255通常表示广播或所有站点 |
| | | short nNetNo = 0; // 网络编号:PLC所连接的网络编号,0表示默认网络 |
| | | short nStNo = 255; // 站点编号:指定与PLC连接的站点编号,255通常表示广播或所有站点 |
| | | |
| | | // 自定义构造函数,覆盖默认值 |
| | | // 自定义构造函数,覆盖默认值 |
| | | explicit StationIdentifier(const short net, const short st) : nNetNo(net), nStNo(st) {} |
| | | |
| | | // 将“网络号”和“站点号”组合成一个最终编码 |
| | | StationIdentifier() |
| | | { |
| | | nNetNo = 0; |
| | | nStNo = 255; |
| | | } |
| | | |
| | | // 将“网络号”和“站点号”组合成一个最终编码 |
| | | short StationIdentifier::toNetworkStationCode() const { |
| | | return static_cast<short>(nStNo | ((nNetNo << 8) & 0xFF00)); |
| | | } |
| | | |
| | | // 重载 < 运算符(用于排序或比较,通常用于 map 或 set 中作为 key) |
| | | // 重载 < 运算符(用于排序或比较,通常用于 map 或 set 中作为 key) |
| | | bool operator<(const StationIdentifier& other) const { |
| | | return std::tie(nNetNo, nStNo) < |
| | | std::tie(other.nNetNo, other.nStNo); |
| | | } |
| | | |
| | | // 重载 == 运算符(用于相等比较) |
| | | // 重载 == 运算符(用于相等比较) |
| | | bool operator==(const StationIdentifier& other) const { |
| | | return std::tie(nNetNo, nStNo) == |
| | | std::tie(other.nNetNo, other.nStNo); |
| | | } |
| | | |
| | | // 重载 = 运算符(用于赋值) |
| | | // 重载 = 运算符(用于赋值) |
| | | StationIdentifier& operator=(const StationIdentifier& other) { |
| | | if (this != &other) { |
| | | nNetNo = other.nNetNo; |
| | |
| | | } |
| | | }; |
| | | |
| | | // 板状态 |
| | | // 板状态 |
| | | struct BoardStatus { |
| | | short nStationValue = 0; // 站号的设备值 (buf[0]) |
| | | short nGroupValue = 0; // 组 No. 的设备值 (buf[1]) |
| | | short nNetworkValue = 0; // 网络 No. 的设备值 (buf[2]) |
| | | short nReserved1 = 0; // 保留字段 (buf[3]) |
| | | short nReserved2 = 0; // 保留字段 (buf[4]) |
| | | short nReserved3 = 0; // 保留字段 (buf[5]) |
| | | short nStationValue = 0; // 站号的设备值 (buf[0]) |
| | | short nGroupValue = 0; // 组 No. 的设备值 (buf[1]) |
| | | short nNetworkValue = 0; // 网络 No. 的设备值 (buf[2]) |
| | | short nReserved1 = 0; // 保留字段 (buf[3]) |
| | | short nReserved2 = 0; // 保留字段 (buf[4]) |
| | | short nReserved3 = 0; // 保留字段 (buf[5]) |
| | | |
| | | // 将数组映射到结构体 |
| | | // 将数组映射到结构体 |
| | | static BoardStatus fromBuffer(const short buf[6]) { |
| | | return { |
| | | buf[0], |
| | |
| | | }; |
| | | } |
| | | |
| | | // 将结构体内容映射到数组 |
| | | // 将结构体内容映射到数组 |
| | | void toBuffer(short buf[6]) const { |
| | | buf[0] = nStationValue; |
| | | buf[1] = nGroupValue; |
| | |
| | | buf[5] = nReserved3; |
| | | } |
| | | |
| | | // 调试输出 |
| | | // 调试输出 |
| | | std::string toString() const { |
| | | std::ostringstream oss; |
| | | oss << "Station Value: " << nStationValue << "\n" |
| | |
| | | } |
| | | }; |
| | | |
| | | // 事件详情 |
| | | // 事件详情 |
| | | struct EventDetails { |
| | | short nEventNo; // 发生的事件号 |
| | | std::array<short, 4> details; // 存储事件详情信息 |
| | | short nEventNo; // 发生的事件号 |
| | | std::array<short, 4> details; // 存储事件详情信息 |
| | | |
| | | // 解析事件详情,返回格式化字符串 |
| | | // 解析事件详情,返回格式化字符串 |
| | | std::string toString() const { |
| | | std::ostringstream oss; |
| | | oss << "Details[0]: " << details[0] << ", " |
| | |
| | | } |
| | | }; |
| | | |
| | | // SoftElement 结构体定义 |
| | | // SoftElement 结构体定义 |
| | | struct SoftElement { |
| | | short nType; // 软元件类型 |
| | | short nElementCount; // 点数 |
| | | long nStartNo; // 起始软元件编号 |
| | | short nType; // 软元件类型 |
| | | short nElementCount; // 点数 |
| | | long nStartNo; // 起始软元件编号 |
| | | }; |
| | | |
| | | // 错误信息 |
| | | // 错误信息 |
| | | struct ErrorInfo { |
| | | int nErrorCode = 0; // 错误码 |
| | | std::string strErrorMessageCn; // 中文描述 |
| | | std::string strErrorMessageEn; // 英文描述 |
| | | int nErrorCode = 0; // 错误码 |
| | | std::string strErrorMessageCn; // 中文描述 |
| | | std::string strErrorMessageEn; // 英文描述 |
| | | |
| | | // 将结构体序列化为字符串 |
| | | // 将结构体序列化为字符串 |
| | | std::string toString() const { |
| | | std::ostringstream oss; |
| | | oss << nErrorCode << "|" << strErrorMessageCn << "|" << strErrorMessageEn; |
| | | return oss.str(); |
| | | } |
| | | |
| | | // 从字符串反序列化为结构体 |
| | | // 从字符串反序列化为结构体 |
| | | static ErrorInfo fromString(const std::string& line) { |
| | | ErrorInfo info; |
| | | std::istringstream iss(line); |
| | | std::string token; |
| | | |
| | | // 使用分隔符 "|" 解析字符串 |
| | | // 使用分隔符 "|" 解析字符串 |
| | | std::getline(iss, token, '|'); |
| | | info.nErrorCode = std::stoi(token); |
| | | |
| | |
| | | } |
| | | }; |
| | | |
| | | using BitContainer = std::vector<bool>; // 每个元素存储 1 位 |
| | | using WordContainer = std::vector<uint16_t>; // 每个元素存储 16 位 |
| | | using DWordContainer = std::vector<uint32_t>; // 每个元素存储 32 位 |
| | | using BitContainer = std::vector<bool>; // 每个元素存储 1 位 |
| | | using WordContainer = std::vector<uint16_t>; // 每个元素存储 16 位 |
| | | using DWordContainer = std::vector<uint32_t>; // 每个元素存储 32 位 |
| | | |
| | | // CPerformanceMelsec 类声明 |
| | | // CPerformanceMelsec 类声明 |
| | | class CPerformanceMelsec { |
| | | public: |
| | | // 获取最近的错误信息 |
| | | // 获取最近的错误信息 |
| | | std::string GetLastError() const; |
| | | |
| | | // 错误信息加载与保存接口 |
| | | static bool LoadErrorInfoFromFile(const std::string& filename); // 从文件加载错误信息 |
| | | static bool SaveErrorInfoToFile(const std::string& filename); // 保存错误信息到文件 |
| | | // 错误信息加载与保存接口 |
| | | static bool LoadErrorInfoFromFile(const std::string& filename); // 从文件加载错误信息 |
| | | static bool SaveErrorInfoToFile(const std::string& filename); // 保存错误信息到文件 |
| | | |
| | | // 连接/断开 |
| | | // 连接/断开 |
| | | int Connect(short nChannel, short nMode = -1); |
| | | int Disconnect(); |
| | | |
| | | // 初始化可编程控制器软元件信息表 |
| | | // 初始化可编程控制器软元件信息表 |
| | | int InitializeController(); |
| | | |
| | | // 获取版本信息 |
| | | // 获取版本信息 |
| | | int GetBoardVersion(BoardVersion& version); |
| | | |
| | | // 板复位 |
| | | // 板复位 |
| | | int BoardReset(); |
| | | |
| | | // 板LED读取 |
| | | // 板LED读取 |
| | | int ReadBoardLed(std::vector<short>& vecLedBuffer); |
| | | |
| | | // 读取目标站点CPU类型 |
| | | // 读取目标站点CPU类型 |
| | | int ReadCPUCode(const StationIdentifier& station, short& nCPUCode); |
| | | |
| | | // 板模式获取/设置 |
| | | // 板模式获取/设置 |
| | | int SetBoardMode(short nMode); |
| | | int GetBoardMode(short& nMode); |
| | | |
| | | // 获取板状态 |
| | | // 获取板状态 |
| | | int GetBoardStatus(BoardStatus& status); |
| | | |
| | | // 读写数据 |
| | | int ReadData(const StationIdentifier& station, short nDevType, short nDevNo, short nSize, std::vector<short>& vecData); |
| | | // 读写数据 |
| | | int ReadData(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, std::vector<short>& vecData); |
| | | int ReadBitData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nBitCount, BitContainer& vecData); |
| | | int ReadWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nWordCount, WordContainer& vecData); |
| | | int ReadDWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nDWordCount, DWordContainer& vecData); |
| | | int WriteData(const StationIdentifier& station, short nDevType, short nDevNo, short nSize, short* pData); |
| | | int WriteData(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, short* pData); |
| | | int WriteBitData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, const BitContainer& vecData); |
| | | int WriteWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, const WordContainer& vecData); |
| | | int WriteDWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, const DWordContainer& vecData); |
| | | |
| | | // 扩展读写数据 |
| | | // 扩展读写数据 |
| | | long ReadDataEx(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, std::vector<char>& vecData); |
| | | long ReadBitDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nBitCount, BitContainer& vecData); |
| | | long ReadWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nWordCount, WordContainer& vecData); |
| | | long ReadDWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nDWordCount, DWordContainer& vecData); |
| | | long WriteDataEx(const StationIdentifier& station, long nDevType, long nDevNo, const std::vector<char>& vecData); |
| | | long WriteBitDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const BitContainer& vecData); |
| | | long WriteWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const WordContainer& vecData); |
| | | long WriteDWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const DWordContainer& vecData); |
| | | |
| | | // 扩展软元件随机读写(支持多个软元件) |
| | | // 扩展软元件随机读写(支持多个软元件) |
| | | long ReadRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, std::vector<char>& vecData); |
| | | long WriteRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, const std::vector<char>& vecData); |
| | | |
| | | // 远程设备站/远程站的缓冲存储器读写 |
| | | // 远程设备站/远程站的缓冲存储器读写 |
| | | long ReadRemoteBuffer(const StationIdentifier& station, long nOffset, long nSize, std::vector<char>& vecData); |
| | | long WriteRemoteBuffer(const StationIdentifier& station, long nOffset, const std::vector<char>& vecData); |
| | | long ReadRemoteBufferByIp(const std::string& strIP, long nOffset, long nSize, std::vector<char>& vecData); |
| | | long WriteRemoteBufferByIp(const std::string& strIP, long nOffset, const std::vector<char>& vecData); |
| | | |
| | | // 设置/复位对象站的指定位软元件 |
| | | // 设置/复位对象站的指定位软元件 |
| | | int SetBitDevice(const StationIdentifier& station, DeviceType enDevType, short nDevNo); |
| | | int ResetBitDevice(const StationIdentifier& station, DeviceType enDevType, short enDevNo); |
| | | |
| | | // 扩展设置/复位对象站的指定位软元件 |
| | | // 扩展设置/复位对象站的指定位软元件 |
| | | long SetBitDeviceEx(const StationIdentifier& station, long nDevType, long nDevNo); |
| | | long ResetBitDeviceEx(const StationIdentifier& station, long nDevType, long nDevNo); |
| | | |
| | | // 执行对象站的CPU |
| | | // 执行对象站的CPU |
| | | int ControlCPU(const StationIdentifier& station, ControlCode enControlCode); |
| | | |
| | | // 事件等待,vecEventNumbers[0, 64],nTimeoutMs[-1, 2147483647] |
| | | // 同时发生了多个事件的情况下,首先检测出其中一个事件。 再次执行了本函数的情况下检测出其它事件。 |
| | | // 事件等待,vecEventNumbers[0, 64],nTimeoutMs[-1, 2147483647] |
| | | // 同时发生了多个事件的情况下,首先检测出其中一个事件。 再次执行了本函数的情况下检测出其它事件。 |
| | | int WaitForBoardEvent(std::vector<short> vecEventNumbers, int nTimeoutMs, EventDetails& details); |
| | | |
| | | private: |
| | | // 锁定与解锁(多线程同步保护) |
| | | // 锁定与解锁(多线程同步保护) |
| | | void Lock() { m_mtx.lock(); } |
| | | void Unlock() { m_mtx.unlock(); } |
| | | |
| | | protected: |
| | | // 构造函数/析构函数 |
| | | // 构造函数/析构函数 |
| | | explicit CPerformanceMelsec(BoardType enBoardType); |
| | | virtual ~CPerformanceMelsec(); |
| | | |
| | | // 辅助函数 |
| | | void UpdateLastError(int nCode); // 更新最近的错误信息 |
| | | int ValidateStation(const StationIdentifier& station) const; // 检查连接状态和站点参数有效性 |
| | | // 辅助函数 |
| | | void UpdateLastError(int nCode); // 更新最近的错误信息 |
| | | int ValidateStation(const StationIdentifier& station) const; // 检查连接状态和站点参数有效性 |
| | | int ValidateStationAndSize(const StationIdentifier& station, short nCount) const; |
| | | |
| | | // 静态辅助函数 |
| | | static void Delay(unsigned int nDelayMs); // 延时,并且转发窗口消息 |
| | | static BoardType FindBoardTypeByChannel(int nChannel); // 查找板块类型 |
| | | static short CombineStation(const StationIdentifier& station); // 合并网络号和站点号 |
| | | static short CalculateDeviceType(const StationIdentifier& station, DeviceType enDevType); // 计算软元件类型 |
| | | // 静态辅助函数 |
| | | static void Delay(unsigned int nDelayMs); // 延时,并且转发窗口消息 |
| | | static BoardType FindBoardTypeByChannel(int nChannel); // 查找板块类型 |
| | | static short CombineStation(const StationIdentifier& station); // 合并网络号和站点号 |
| | | static short CalculateDeviceType(const StationIdentifier& station, DeviceType enDevType); // 计算软元件类型 |
| | | |
| | | // IP转换 |
| | | // IP转换 |
| | | static bool ConvertIpStringToUint32(const std::string& strIP, uint32_t& nIP); |
| | | |
| | | // 容器转换 |
| | | // 容器转换 |
| | | static void ConvertCharToShort(const std::vector<char>& vecChar, std::vector<short>& vecShort); |
| | | static void ConvertShortToChar(const std::vector<short>& vecShort, std::vector<char>& vecChar); |
| | | static void ConvertUint8ToShort(const std::vector<uint8_t>& vecUint8, std::vector<short>& vecShort); |
| | |
| | | static void ConvertUint32ToShort(const std::vector<uint32_t>& vecUint32, std::vector<short>& vecShort); |
| | | static void ConvertShortToUint32(const std::vector<short>& vecShort, std::vector<uint32_t>& vecUint32); |
| | | |
| | | // 模板辅助函数 |
| | | // 模板辅助函数 |
| | | template <typename T> |
| | | int ValidateStationAndData(const StationIdentifier& station, const std::vector<T>& vecData); |
| | | |
| | |
| | | template <typename T, typename U> |
| | | void ConvertHighToLow(const std::vector<T>& vecHigh, std::vector<U>& vecLow); |
| | | |
| | | // 成员变量 |
| | | std::mutex m_mtx; // 互斥锁保护 |
| | | BoardType m_enBoardType; // 板块类型 |
| | | long m_nPath; // 通信路径 |
| | | std::atomic<bool> m_bConnected; // 是否已连接 |
| | | std::string m_strLastError; // 最近一次错误信息 |
| | | // 成员变量 |
| | | std::mutex m_mtx; // 互斥锁保护 |
| | | BoardType m_enBoardType; // 板块类型 |
| | | long m_nPath; // 通信路径 |
| | | std::atomic<bool> m_bConnected; // 是否已连接 |
| | | std::string m_strLastError; // 最近一次错误信息 |
| | | |
| | | // 静态成员变量 |
| | | static std::unordered_map<int, std::string> m_mapError; // 错误码映射表 |
| | | // 静态成员变量 |
| | | static std::unordered_map<int, std::string> m_mapError; // 错误码映射表 |
| | | }; |
| | | |
| | | #endif // PERFORMANCE_MELSEC_H |