三菱PLC slmp(mc)协议

//对于三菱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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值