• 三菱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;
    }

  • 相关阅读:
    备战蓝桥杯————k个一组反转单链表
    创建型模式-原型模式(五)
    【SSRF-01】服务器端请求伪造漏洞原理及利用实例
    Ubuntu Budgie 22.04 设置中文语言并安装拼音输入法
    Ngunx + Tomcat 负载均衡和动态分离
    【实战案例】——实战渗透某不法网站
    aijs 遍历字典
    李宏毅机器学习笔记(2016年的课程):Support Vector Machine (SVM)
    HCIP第十六天——VLAN,STP和STP角色选举
    PyTorch中的CUDA操作
  • 原文地址:https://blog.csdn.net/weixin_39926429/article/details/125613375