基于 C++ 的 IEC60870-5-104 规约的主从站模拟数据通信
基于 C++ 的 IEC60870-5-104 规约的主从站模拟数据通信。包括了报文的组织和解析,以及主从站之间的通信流程。
1. 报文组织与解析
IEC60870-5-104 规约定义了多种类型的帧,包括 U 帧、S 帧和 I 帧。以下是一些关键的报文组织和解析函数。
1.1 U 帧组织
U 帧用于控制链路状态,例如启动和停止数据传输。
void buildUFrame(uint8_t* buffer, uint8_t controlByte) {buffer[0] = 0x68; // 启动字节buffer[1] = 0x04; // 长度buffer[2] = controlByte; // 控制字节buffer[3] = 0x00; // 保留字节buffer[4] = 0x00; // 发送序号buffer[5] = 0x00; // 接收序号
}
1.2 S 帧组织
S 帧用于确认接收到的 I 帧。
void buildSFrame(uint8_t* buffer, uint16_t sendSeq, uint16_t recvSeq) {buffer[0] = 0x68; // 启动字节buffer[1] = 0x04; // 长度buffer[2] = 0x01; // 控制字节buffer[3] = 0x00; // 保留字节buffer[4] = sendSeq & 0xFF; // 发送序号buffer[5] = recvSeq & 0xFF; // 接收序号
}
1.3 I 帧组织
I 帧用于传输应用层数据。
void buildIFrame(uint8_t* buffer, uint16_t sendSeq, uint16_t recvSeq, uint8_t* data, uint16_t dataLen) {buffer[0] = 0x68; // 启动字节buffer[1] = dataLen + 6; // 长度buffer[2] = (sendSeq >> 8) & 0xFF; // 发送序号buffer[3] = sendSeq & 0xFF;buffer[4] = (recvSeq >> 8) & 0xFF; // 接收序号buffer[5] = recvSeq & 0xFF;memcpy(buffer + 6, data, dataLen); // 数据
}
2. 主从站通信流程
主站和从站之间的通信流程包括启动链路、数据传输和停止链路。
2.1 主站启动链路
主站发送 STARTDT 帧,从站响应 STARTDT 帧。
void masterStartLink(uint8_t* buffer) {buildUFrame(buffer, 0x07); // STARTDT
}void slaveRespondStartLink(uint8_t* buffer) {buildUFrame(buffer, 0x0B); // STARTDT 确认
}
2.2 主站发送总召唤命令
主站发送总召唤命令,从站响应总召唤命令。
void masterSendTotalCall(uint8_t* buffer) {uint8_t data[] = {0x65, 0x01, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45};buildIFrame(buffer, 1, 0, data, sizeof(data));
}void slaveRespondTotalCall(uint8_t* buffer) {uint8_t data[] = {0x65, 0x01, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45};buildIFrame(buffer, 1, 1, data, sizeof(data));
}
2.3 主站停止链路
主站发送 STOPDT 帧,从站响应 STOPDT 帧。
void masterStopLink(uint8_t* buffer) {buildUFrame(buffer, 0x13); // STOPDT
}void slaveRespondStopLink(uint8_t* buffer) {buildUFrame(buffer, 0x23); // STOPDT 确认
}
3. 报文解析
解析从站发送的报文,提取数据。
void parseUFrame(uint8_t* buffer) {uint8_t controlByte = buffer[2];if (controlByte == 0x0B) {// 从站确认启动链路} else if (controlByte == 0x23) {// 从站确认停止链路}
}void parseSFrame(uint8_t* buffer) {uint16_t recvSeq = (buffer[4] << 8) | buffer[5];// 处理接收序号
}void parseIFrame(uint8_t* buffer) {uint16_t sendSeq = (buffer[2] << 8) | buffer[3];uint16_t recvSeq = (buffer[4] << 8) | buffer[5];uint16_t dataLen = buffer[1] - 6;uint8_t* data = buffer + 6;// 处理数据
}
4. 主从站模拟
模拟主站和从站之间的通信。
int main() {uint8_t masterBuffer[1024];uint8_t slaveBuffer[1024];// 主站启动链路masterStartLink(masterBuffer);// 从站响应启动链路slaveRespondStartLink(slaveBuffer);// 主站发送总召唤命令masterSendTotalCall(masterBuffer);// 从站响应总召唤命令slaveRespondTotalCall(slaveBuffer);// 主站停止链路masterStopLink(masterBuffer);// 从站响应停止链路slaveRespondStopLink(slaveBuffer);return 0;
}
参考代码 104规约C++实例,主从站模拟数据通信 www.youwenfan/contentcsg/72801.html
通过以上代码,可以实现基于 IEC60870-5-104 规约的主从站模拟数据通信。