//对于三菱PLC,可参考mx component5.0(详见以前的文章)通讯
//本文自写解析协议。
//本文在 c++ builder平台和FX5U调试成功
#ifndef _SlmpProtocolClient_
#define _SlmpProtocolClient_
#include <winsock2.h>
#include <stdlib.h>
#include <iostream>
#include <string>
// using System.Net.Socket;
class SlmpProtocolClient
{
public:
SlmpProtocolClient();
~SlmpProtocolClient();
public :
int Open() ;
int Close();
int ReadDRegister(short address, short len, unsigned short* short_array);
int ReadMBit(short adress, short len, unsigned short* short_array);
int WriteDRegister(short address, unsigned short short_value);
int WriteMBit(short address, unsigned short short_value);
void init2();
public :
bool Connected;
private:
WSADATA wsaData;
sockaddr_in sockAddr;
SOCKET sock;
std::string tipstr[20], tipstr2[20];
void GetHighLowByte(const short addrss, unsigned char& HByte, unsigned char& LByte);
};
#endif
#include "SlmpProtocolClient.h"
//#include <winsock2.h> //
SlmpProtocolClient::SlmpProtocolClient()
{
init2();
}
void SlmpProtocolClient::init2() {
tipstr[0] = "固定";
tipstr[1] = "----";
tipstr[2] = "----";
tipstr[3] = "----";
tipstr[4] = "----";
tipstr[5] = "----";
tipstr[6] = "固定";
tipstr[7] = "长度L";
tipstr[8] = "长度H";
tipstr[9] = " 结束代码L";
tipstr[10] = " 结束代码H";
tipstr[11] = " DXXXn-L";
tipstr[12] = " DXXXn-H";
tipstr[13] = " DXXXn+1-L";
tipstr[14] = " DXXXn+1-H";
tipstr[15] = " DXXXn+2-L";
tipstr[16] = " DXXXn+2-H";
tipstr2[0] = "固定";
tipstr2[1] = "----";
tipstr2[2] = "----";
tipstr2[3] = "----";
tipstr2[4] = "----";
tipstr2[5] = "----";
tipstr2[6] = "固定";
tipstr2[7] = "长度L";
tipstr2[8] = "长度H";
tipstr2[9] = " 结束代码L";
tipstr2[10] = " 结束代码H";
tipstr2[11] = " Mn | Mn + 1";
tipstr2[12] = " MXXX2n+2| MXXXn + 3";
tipstr2[13] = " MXXXn+4| MXXXn + 5";
}
SlmpProtocolClient::~SlmpProtocolClient()
{
Close();
}
int SlmpProtocolClient::Close()
{
closesocket(sock);
//终止使用 DLL
WSACleanup();
Connected=false;
return 0;
}
int SlmpProtocolClient::Open()
{
WSAStartup(MAKEWORD(2, 2), &wsaData);
//创建套接字
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//向服务器发起请求
memset(&sockAddr, 0, sizeof(sockAddr)); //每个字节都用0填充
sockAddr.sin_family = PF_INET;
sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
//sockAddr.sin_addr.s_addr = inet_addr("192.168.10.150");
sockAddr.sin_port = htons(1234);
// sockAddr.sin_port = htons(4999);
int ret=connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
if (ret==0) {
Connected=true;
}
return ret;
}
int SlmpProtocolClient::ReadDRegister(short address,short len, unsigned short * short_array)
{
SYSTEMTIME sys, sy2;
int a = 0;
char* str = new char[30];
while (a <1)
{
/* GetLocalTime(&sys);
std::cout << sys.wSecond << ":" << sys.wMilliseconds << std::endl;*/
//50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 64 00 00 A8 14 00
str[0] = 0x50;//本行开始的7行固定
str[1] = 0x00;
str[2] = 0x00;
str[3] = 0xFF;
str[4] = 0xFF;
str[5] = 0x03;
str[6] = 0x00;//本行及以上固定
str[7] = 0x0C;//长度L字节
str[8] = 0x00;//长度H字节
str[9] = 0x10;//监视定时器L
str[10] = 0x00;//监视定时器H
str[11] = 0x01;//CMD-批量读取-L
str[12] = 0x04;//CMD-批量读取-H
str[13] = 0x00;//子CMD-L
str[14] = 0x00;//子CMD-H
//str[15] = 0x64;//开始地址-L
//str[16] = 0x00;//开始地址-Middle
//str[15] = 0x40;//开始地址-L
//str[16] = 0x01;//开始地址-Middle
unsigned char hByte, lByte;
GetHighLowByte(address, hByte, lByte);
str[15] = lByte;//开始地址-L
str[16] = hByte;//开始地址-Middle
str[17] = 0x00;//开始地址-H
str[18] = 0xA8;//表示D点
unsigned char hByte2, lByte2;
//str[19] = 0x03;//读取长度-L
//str[20] = 0x00;//读取长度-H
GetHighLowByte(len, hByte2, lByte2);
str[19] = lByte2;//读取长度-L
str[20] = hByte2;//读取长度-H
send(sock, str, 21, NULL);//读取D寄存器的发送报文的长度=21字节
// Sleep(1);
//接收服务器传回的数据
char szBuffer[MAXBYTE] = { 0 };
int m;
m=recv(sock, szBuffer, MAXBYTE, NULL);
//输出接收到的数据
//printf("Message form server: %s\n", szBuffer);
//printf("Message form server:\n ");
/* for (size_t i = 0; i < 13; i++)
{
if ((unsigned char)szBuffer[i] < 16)
{
printf("0%x ", (unsigned char)szBuffer[i]);
}
else
{
printf("%x ", (unsigned char)szBuffer[i]);
}
std::cout << "--" << tipstr[i] << std::endl;
}*/
//读出的放在数组里,以下按数组的索引号从0开始说明含义
// szBuffer[0]:0xD0,--固定
// szBuffer[1]:0X00,--固定
// szBuffer[2]:0X00,--固定
// szBuffer[3]:0XFF,--固定
// szBuffer[4]:0XFF,--固定
// szBuffer[5]:0X03,--固定
// szBuffer[6]:0X00,--固定
// szBuffer[7]:响应数据长L字节,如读1个字:0x04,2字:0x06,三个字0x08,依次类推
// szBuffer[8]:响应数据长高字节
// --------从szBuffer[9]开始计算长度-----
// szBuffer[9]:0x00,--结束代码,如不为0则异常
// szBuffer[10]:0x00,--结束代码,如不为0则异常
// szBuffer[11]:Dn的L字节
// szBuffer[12]:Dn的H字节
// szBuffer[13]:Dn+1的L字节
// szBuffer[14]:Dn+1的H字节
// szBuffer[15]:Dn+2的L字节
// szBuffer[16]:Dn+2的H字节
// 接收完成后,第一步先看结束代码是否为0,如为0,进行下一步,否则丢弃数据了
// 第二步判断响应数据长是否等于2*字数+2,如相等,进行下一步
// 第三步从szBuffer[11]开始取几个字的数据,注意高低字节,如Dn=256*szBuffer[12]+szBuffer[11]
short end_code= 256 * (unsigned char)szBuffer[10] + (unsigned char)szBuffer[9];
if (end_code != 0)
{
return -1;
}
short response_len= 256 * (unsigned char)szBuffer[8] + (unsigned char)szBuffer[7];
if (response_len!=(len*2+2))
{
return -1;
}
for (size_t i = 0; i < len; i++)
{
*(short_array+i) = 256 * (unsigned char)szBuffer[12+i*2] + (unsigned char)szBuffer[11+i*2];
//std::cout << "读到的第"<<i+1<<"个字=" << *short_array << std::endl;
}
/*std::cout << "读到的第1个字=" << 256 * (unsigned char)szBuffer[12] + (unsigned char)szBuffer[11] << std::endl;
std::cout << "第2个字=" << 256 * (unsigned char)szBuffer[14] + (unsigned char)szBuffer[13] << std::endl;
std::cout << "第3个字=" << 256 * szBuffer[16] + szBuffer[15] << std::endl;*/
/*GetLocalTime(&sy2);
std::cout << std::endl;
std::cout << sy2.wSecond << ":" << sy2.wMilliseconds << std::endl;
std::cout << std::endl;*/
a++;
// Sleep(1);
}
delete[] str;
return 0;
}
int SlmpProtocolClient::WriteDRegister(short address, unsigned short short_value)
{
SYSTEMTIME sys, sy2;
int a = 0;
char* str = new char[30];
while (a < 1)
{
GetLocalTime(&sys);
std::cout << sys.wSecond << ":" << sys.wMilliseconds << std::endl;
//50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 64 00 00 A8 14 00
str[0] = 0x50;//本行开始的7行固定
str[1] = 0x00;
str[2] = 0x00;
str[3] = 0xFF;
str[4] = 0xFF;
str[5] = 0x03;
str[6] = 0x00;//本行及以上固定
//str[7] = 0x12;//长度L字节--------写三个字0x12,写2个字,0x10,写一个字,0X0E
str[7] = 0x0E;//长度L字节--------写三个字0x12,写2个字,0x10,写一个字,0X0E
str[8] = 0x00;//长度H字节--------
str[9] = 0x10;//监视定时器L
str[10] = 0x00;//监视定时器H
str[11] = 0x01;//CMD-批量写-L
str[12] = 0x14;//CMD-批量写-H
str[13] = 0x00;//子CMD-L
str[14] = 0x00;//子CMD-H
//str[15] = 0x64;//开始地址-L-----变化
//str[16] = 0x00;//开始地址-Middle-----变化
unsigned char hByte, lByte;
GetHighLowByte(address, hByte, lByte);
str[15] = lByte;//开始地址-L
str[16] = hByte;//开始地址-Middle
str[17] = 0x00;//开始地址-H-----变化
str[18] = 0xA8;//表示D点
//str[19] = 0x03;//写入长度-L-------变化
str[19] = 0x01;//写入长度-L-------变化
str[20] = 0x00;//写入长度-H-------变化
//str[21] = 0x0C;//写入Dn-L-------变化
//str[22] = 0x00;//写入Dn-H-------变化
unsigned char hByte2, lByte2;
GetHighLowByte(short_value, hByte2, lByte2);
str[21] = lByte2;//读取长度-L
str[22] = hByte2;//读取长度-H
//str[23] = 0x0D;//写入Dn+1-L-------变化
//str[24] = 0x00;//写入Dn+1-H-------变化
//str[25] = 0x0E;//写入Dn+2-L-------变化
//str[26] = 0x00;//写入Dn+2-H-------变化
//"00 FF FF 03 00 0C 00 10 00 01 04 00 00 64 00 00 A8 01 00
//send(sock, str, strlen(str) + sizeof(char), NULL);
send(sock, str, 23, NULL);//-------------注意长度,写3个字:len=27,2个字:len=25,1个字:len=23
// Sleep(20);
//接收服务器传回的数据
char szBuffer[MAXBYTE] = { 0 };
recv(sock, szBuffer, MAXBYTE, NULL);
// PLC反馈: D0 00 00 FF FF 03 00 02 00 00 00 (00:14:55:188)
//输出接收到的数据
//printf("Message form server: %s\n", szBuffer);
if (0xD0 != (unsigned char)(szBuffer[0]) ) return 1;
if (0x02 != (unsigned char)szBuffer[7]) return 2;
if (0 != szBuffer[9]) return 3;
if (0 != szBuffer[10]) return 4;
/* GetLocalTime(&sy2);
std::cout << std::endl;
std::cout << sy2.wSecond << ":" << sy2.wMilliseconds << std::endl;
std::cout << std::endl;*/
a++;
Sleep(1);
}
delete[] str;
return 0;
}
int SlmpProtocolClient::ReadMBit(short address, short len, unsigned short* short_array)
{
SYSTEMTIME sys, sy2;
int a = 0;
char* str = new char[30];
unsigned short temp;
unsigned short q;
unsigned short m;
unsigned short n;
unsigned short k;
m = len % 16;
n = (m==0)? (len - m) / 16:(len - m) / 16+1;
while (a < 1)
{
// GetLocalTime(&sys);
//std::cout << sys.wSecond << ":" << sys.wMilliseconds << std::endl;
//50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 64 00 00 A8 14 00
str[0] = 0x50;//本行开始的7行固定
str[1] = 0x00;
str[2] = 0x00;
str[3] = 0xFF;
str[4] = 0xFF;
str[5] = 0x03;
str[6] = 0x00;//本行及以上固定
str[7] = 0x0C;//长度L字节
str[8] = 0x00;//长度H字节
str[9] = 0x10;//监视定时器L
str[10] = 0x00;//监视定时器H
str[11] = 0x01;//CMD-批量读取-L
str[12] = 0x04;//CMD-批量读取-H
str[13] = 0x00;//子CMD-L
str[14] = 0x00;//子CMD-H
//str[15] = 0x64;//开始地址-L---变化
//str[16] = 0x00;//开始地址-Middle---变化
unsigned char hByte, lByte;
GetHighLowByte(address, hByte, lByte);
str[15] = lByte;//开始地址-L
str[16] = hByte;//开始地址-Middle
str[17] = 0x00;//开始地址-H---变化
str[18] = 0x90;//表示M点
unsigned char hByte2, lByte2;
//str[19] = 0x03;//读取长度-L
//str[20] = 0x00;//读取长度-H
GetHighLowByte(n, hByte2, lByte2);
str[19] = lByte2;//读取长度-L
str[20] = hByte2;//读取长度-H
send(sock, str, 21, NULL);// /读取M的发送报文的长度=21字节
// Sleep(20);
//接收服务器传回的数据
char szBuffer[MAXBYTE] = { 0 };
recv(sock, szBuffer, MAXBYTE, NULL);
//输出接收到的数据
//printf("Message form server: %s\n", szBuffer);
/* printf("Message form server:\n ");
for (int i = 0; i < 13; i++)
{
if ((unsigned char)szBuffer[i] < 16)
{
printf("0%x ", (unsigned char)szBuffer[i]);
}
else
{
printf("%x ", (unsigned char)szBuffer[i]);
}
std::cout << tipstr2[i] << std::endl;
}
GetLocalTime(&sy2);*/
//读出的放在数组里,以下按数组的索引号从0开始说明含义
// szBuffer[0]:0xD0,--固定
// szBuffer[1]:0X00,--固定
// szBuffer[2]:0X00,--固定
// szBuffer[3]:0XFF,--固定
// szBuffer[4]:0XFF,--固定
// szBuffer[5]:0X03,--固定
// szBuffer[6]:0X00,--固定
// szBuffer[7]:响应数据长L字节,如读<=16:0x04,2字:0x06,三个字0x08,依次类推
// szBuffer[8]:响应数据长高字节
// --------从szBuffer[9]开始计算长度-----
// szBuffer[9]:0x00,--结束代码,如不为0则异常
// szBuffer[10]:0x00,--结束代码,如不为0则异常
// szBuffer[11]:Mn~M(n+7)
// szBuffer[12]:M(n+8)~M(n+15)
// 接收完成后,第一步先看结束代码是否为0,如为0,进行下一步,否则丢弃数据了
// 第二步判断响应数据长是否等于2*字数,如相等,进行下一步
// 第三步从szBuffer[11]开始取几个字的数据,注意高低字节,
//如Mn= szBuffer[12]& 0x01,Mn(n+1)= szBuffer[12]& 0x02,M(n+15)= szBuffer[13]& 0x80,Mn(n+1)= szBuffer[12]& 0x02,
short end_code = 256 * (unsigned char)szBuffer[10] + (unsigned char)szBuffer[9];
if (end_code != 0)
{
return -1;
}
short response_len = 256 * (unsigned char)szBuffer[8] + (unsigned char)szBuffer[7];
if (response_len != (n * 2 + 2))
{
return -1;
}
k = 0;
unsigned u;
for (size_t i = 0; i <n; i++)
{
temp = 256 * (unsigned char)szBuffer[12 + i * 2] + (unsigned char)szBuffer[11 + i * 2];
u = temp;
for (size_t j = 0; j< 16; j++)
{
short_array[k] =( ((u & 1) == 0) ? 0 : 1);
u = u >> 1;
k++;
if (k>=len)
{
break;
}
}
}
/* unsigned short temp = 256 * (unsigned char)szBuffer[12] + (unsigned char)szBuffer[11];
bool b;
for (int i = 0; i < 16; i++)
{
b = (temp == 1) ? true : false;
std::cout << "第" << i + 1 << "位:" << b << std::endl;
temp = temp >> 1;
}*/
/* std::cout << std::endl;
std::cout << sy2.wSecond << ":" << sy2.wMilliseconds << std::endl;
std::cout << std::endl;*/
// delete[] str;
a++;
Sleep(1);
}
delete[] str;
return 0;
}
int SlmpProtocolClient::WriteMBit(short address, unsigned short short_value)
{
//SYSTEMTIME sys, sy2;
int a = 0;
char* str = new char[30];
while (a < 1)
{/*
GetLocalTime(&sys);
std::cout << sys.wSecond << ":" << sys.wMilliseconds << std::endl;*/
//50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 64 00 00 A8 14 00
str[0] = 0x50;//本行开始的7行固定
str[1] = 0x00;
str[2] = 0x00;
str[3] = 0xFF;
str[4] = 0xFF;
str[5] = 0x03;
str[6] = 0x00;//本行及以上固定
str[7] = 0x0D;//长度L字节--------写三个字0x12,写2个字,0x10,写一个字,0X0E
str[8] = 0x00;//长度H字节--------
str[9] = 0x10;//监视定时器L
str[10] = 0x00;//监视定时器H
str[11] = 0x01;//CMD-批量写-L
str[12] = 0x14;//CMD-批量写-H
str[13] = 0x01;//子CMD-L
str[14] = 0x00;//子CMD-H
//str[15] = 0x64;//开始地址-L-----变化
//str[16] = 0x00;//开始地址-Middle-----变化
unsigned char hByte, lByte;
GetHighLowByte(address, hByte, lByte);
str[15] = lByte;//开始地址-L
str[16] = hByte;//开始地址-Middle
str[17] = 0x00;//开始地址-H-----变化
str[18] = 0x90;//表示M点
str[19] = 0x01;//写入长度-L-------变化
str[20] = 0x00;//写入长度-H-------变化
str[21] = ((short_value==0)?0x00:0x10);//写入Mn,M(n+1)-------变化
//str[22] = 0x00;//写入M(n+2),M(n+3)------变化
//"50 00 00 FF FF 03 00 0D 00 10 00 01 14 01 00 64 00 00 90 01 00 10
//send(sock, str, strlen(str) + sizeof(char), NULL);
send(sock, str, 22, NULL);//-------------注意长度,写3个字:len=27,2个字:len=25,1个字:len=23
// Sleep(20);
//接收服务器传回的数据
char szBuffer[MAXBYTE] = { 0 };
recv(sock, szBuffer, MAXBYTE, NULL);
//输出接收到的数据
//printf("Message form server: %s\n", szBuffer);
/* printf("Message form server:\n ");
for (size_t i = 0; i < 11; i++)
{
if ((unsigned char)szBuffer[i] < 16)
{
printf("0%x ", (unsigned char)szBuffer[i]);
}
else
{
printf("%x ", (unsigned char)szBuffer[i]);
}
std::cout << "--" << tipstr[i] << std::endl;
}
GetLocalTime(&sy2);
std::cout << std::endl;
std::cout << sy2.wSecond << ":" << sy2.wMilliseconds << std::endl;
std::cout << std::endl;*/
// PLC反馈: D0 00 00 FF FF 03 00 02 00 00 00 (00:14:55:188)
//输出接收到的数据
//printf("Message form server: %s\n", szBuffer);
if (0xD0 != (unsigned char)(szBuffer[0])) return 1;
if (0x02 != (unsigned char)szBuffer[7]) return 2;
if (0 != szBuffer[9]) return 3;
if (0 != szBuffer[10]) return 4;
a++;
Sleep(1);
}
delete[] str;
return 0;
}
void SlmpProtocolClient::GetHighLowByte(const short addrss, unsigned char & HByte, unsigned char & LByte)
{
LByte = addrss % 256;
HByte = (addrss - LByte) / 256;
}