Mbed modbus TCP slave 和ubuntu modbusTCP client 程序

modbus TCP 协议

modbus TCP 协议使用TCP 协议发送和接收modbus 消息。modbus TCP 消息结构如下,在modbus 消息的前面,添加了6个字节的头:

Transaction Id Protocol Length Unit Address Message
2 Bytes 2 Bytes 2 Bytes 1 Byte N Bytes

Transaction Id :是本次交互的ID

protocol :为0 表示modbusTCP 协议。

length :后面的字节数

unit Address 是设备地址

message 是modbus PDU

Modbus PDU

Modbus Read Coils (01)

请求

Offset Length Description Values
0 Byte Function Code 01
2 Word First coil address 0000h - FFFFh
4 Word Coil count 0001 - 07D0h

响应

Offset Length Description Values
0 Byte Function Code 01
1 Byte Byte Count (CoilCount + 7) / 8
2 N Bytes Coil data ...

Modbus Read Discrete Inputs (02)

请求

Offset Length Description Values
0 Byte Function Code 02
2 Word First input address 0000h - FFFFh
4 Word Input count 0001 - 07D0h

响应

Offset Length Description Values
0 Byte Function Code 02
1 Byte Byte Count (InputCount + 7) / 8
2 N Bytes Input data

...

 Modbus Read Holding Registers (03)

请求

Offset Length Description Values
0 Byte Function Code 03
2 Word First input address 0000h - FFFFh
4 Word Register count 0001 - 007Dh

 响应

Offset Length Description Values
0 Byte Function Code 03
1 Byte Byte Count RegisterCount * 2
2 N Bytes Register data ...

 Modbus Read Input Registers (04)

请求

Offset Length Description Values
0 Byte Function Code 04
2 Word First input address 0000h - FFFFh
4 Word Register count 0001 - 007Dh

 响应

Offset Length Description Values
0 Byte Function Code 04
1 Byte Byte Count RegisterCount * 2
2 N Bytes Register data ...

 Modbus Write Single Coil (05)

请求

Offset Length Description Values
0 Byte Function Code 05
2 Word First coil address 0000h - FFFFh
4 Word Coil value 0x0000 or 0xFF00

 响应

Offset Length Description Values
0 Byte Function Code 05
2 Word First coil address 0000h - FFFFh
4 Word Coil value 0x0000 or 0xFF00

 Modbus Write Single Register (06)

请求

Offset Length Description Values
0 Byte Function Code 06
2 Word First register address 0000h - FFFFh
4 Word Register value 0000h - FFFFh

响应

Offset Length Description Values
0 Byte Function Code 06
2 Word First register address 0000h - FFFFh
4 Word Register value 0000h - FFFFh

Modbus Write Multiple Registers (16) 

请求

Offset Length Description Values
0 Byte Function Code 10h
2 Word First register address 0000h - FFFFh
4 Word Register Count 0000h - 007Bh
5 Byte Byte Count 0000h - 007Bh
6 N Words Register values ...

响应

Offset Length Description Values
0 Byte Function Code 10h
2 Word First register address 0000h - FFFFh
4 Word Register Count 0000h - 007Bh

 实验项目

我们编写了Mbed OS/STM32F429 上面的Modbus TCP server  和ubuntu OS 上的modbusTCP client。事实上TCP/IP 的server/client 和modbusTCP的master 和slave 的概念是容易混淆的。TCP的 server相当于modbus的slave.

Mbed OS/STM32F429 上modbusTCP Slave 的实现

#include "mbed.h"
#include "EthernetInterface.h"
static const char*          mbedIp       = "192.168.31.112";  //IP
static const char*          mbedMask     = "255.255.255.0";  // Mask
static const char*          mbedGateway  = "192.168.0.1";    //Gateway
#define MODBUS_PORT 8888
///Function Code
#define     READ_COILS        0x01
#define     READ_INPUT_BITS   0x02
#define     READ_REGS         0x03
#define     READ_INPUT_REGS   0x04
#define     WRITE_COIL        0x05
#define     WRITE_REG         0x06
#define     WRITE_COILS       0x0F
#define     WRITE_REGS        0x10
DigitalOut led(PC_6);
uint8_t rbuffer[128];
uint8_t tbuffer[128];
uint16_t internal_register[512];
uint8_t coils[8];
uint16_t msg_id;
uint8_t slaveid;
uint8_t func;
int  modbus_response(uint8_t func,uint16_t address,uint16_t amount ,uint16_t *value);
int modbus_recieve(int length)
{   uint16_t address;
    msg_id=(rbuffer[0]<<8)|rbuffer[1];
    slaveid=rbuffer[6];
    func=rbuffer[7];
    address=(rbuffer[8]<<8)|rbuffer[9];
     if(func == WRITE_COIL || func == WRITE_REG) {
         uint16_t value=(rbuffer[10]<<8)|rbuffer[11];
         if (address<16){
         internal_register[address]=value;
         printf("func:%2x address:%4x value:%4x",func ,address,value);
         uint16_t amount=0;
        return  modbus_response(func,address,amount,internal_register);     
             }
         } else  if(func == WRITE_REGS){
             uint16_t amount=(rbuffer[10]<<8)|rbuffer[11];
               printf("func:%2x address:%4x amount:%4x",func ,address,amount);
             for (int i=0;i<amount;i++){
                 internal_register[address+i]=(rbuffer[13+i*2]<<8)|rbuffer[14+i*2];
                 }
            return   modbus_response(func,address,amount,NULL);   
             } else  if(func == READ_COILS || func == READ_INPUT_BITS) {
                    uint16_t amount=(rbuffer[10]<<8)|rbuffer[11];
                   printf("func:%2x address:%4x amount:%4x",func ,address,amount);
                 return    modbus_response(func,address,amount,internal_register);   
                 
             } else if(func == READ_REGS || func == READ_INPUT_REGS) {
                      uint16_t amount=(rbuffer[10]<<8)|rbuffer[11];
                    printf("func:%2x address:%4x amount:%4x",func ,address,amount);  
                    return  modbus_response(func,address,amount,internal_register);    
               }
         
   return 0;
}
 
    
int  modbus_response(uint8_t func,uint16_t address,uint16_t amount ,uint16_t *value){
        tbuffer[0]=(uint8_t) msg_id >> 8u;
        tbuffer[1]=(uint8_t) (msg_id & 0x00FFu);
        tbuffer[2]=0;
        tbuffer[3]=0;
        tbuffer[4]=0;
        tbuffer[6]=(uint8_t) slaveid;
        tbuffer[7] = (uint8_t) func;
        tbuffer[8]=(uint8_t) address>> 8u;
         tbuffer[9]=(uint8_t) (address & 0x00FFu);
    if(func == WRITE_COIL || func == WRITE_REG) {
         tbuffer[5] = 6;
        tbuffer[10] = (uint8_t) (value[0] >> 8u);
        tbuffer[11] = (uint8_t) (value[0] & 0x00FFu);
        return 12;
        } else if(func == WRITE_REGS){
            tbuffer[5] = 6;
        tbuffer[10] = (uint8_t) (amount >> 8u);
        tbuffer[11] = (uint8_t) (amount & 0x00FFu);
            return 12;
        } else if(func == READ_COILS || func == READ_INPUT_BITS) {
        tbuffer[5] = 6;
         uint8_t byte_count=(uint8_t) ((amount+7)/8);
         tbuffer[8]=byte_count;
      for (int i=0;i<byte_count;i++)
         tbuffer[9+i]=coils[i];
        return 9+byte_count;
    } else if(func == READ_REGS||READ_INPUT_REGS){
        tbuffer[5] = (uint8_t) (7 + 2 * amount);
        tbuffer[8] = (uint8_t) (amount*2);
        for(int i = 0; i < amount; i++) {
           tbuffer[9+ 2 * i] = (uint8_t) (value[i] >> 8u);
           tbuffer[10 + 2 * i] = (uint8_t) (value[i] & 0x00FFu);
          
        }
        return (9+amount*2);
    } 
    return 0;
    }
int main()
{
   printf("Modbus Server example\n\r");
    
    EthernetInterface eth;
     eth.set_network(mbedIp,mbedMask,mbedGateway);
    eth.connect();   
    printf("The Server IP address is '%s'\n\r", eth.get_ip_address());  
    TCPServer srv(&eth);     
    srv.bind(MODBUS_PORT);   
    srv.listen();   
    while(true){
        TCPSocket client;
        SocketAddress client_addr;
        char *buffer = "Hello TCP client!\r\n";    
        srv.accept(&client, &client_addr);      
        printf("Accepted %s:%d\n\r", client_addr.get_ip_address(), 
                    client_addr.get_port());   
     while(1){
     //   int rlen=srv.recvfrom(NULL,rbuffer, sizeof rbuffer); 
      int rlen =client.recvfrom(&client_addr,rbuffer, sizeof rbuffer); 
        if (rlen>0)
        {
        printf("length:%d\n",rlen);
         int tlen=  modbus_recieve(rlen);    
         if (tlen>0)                               
        client.send(tbuffer, tlen);
        }
    
        }
          
      }
      
    }

Ubuntu OS 上Client 的实现

modbusClient.cpp

#include<stdlib.h>
#include "modbus.h"
#include<stdio.h>
#include<iostream>
#include<sys/types.h>
using namespace std;
int main(int argc, char **argv)
{
 
    // create a modbus object
    modbus mb = modbus("192.168.31.112", 8888);
    // set slave id
    mb.modbus_set_slave_id(1);

    // connect with the server
    if (mb.modbus_connect()){   
    while(1){
    // write single reg                 function 0x06    
      mb.modbus_write_register(0x00,8); 
       // read input registers             function 0x04
    uint16_t read_input_regs[1];
    mb.modbus_read_input_registers(0x00, 1, read_input_regs);
    cout << "read_input_regs:"<<read_input_regs[0]<<endl;
   sleep(1);
    }
     };
 
}

modbus.h

//
// Created by Fanzhe on 5/28/2017.
//

#ifndef MODBUSPP_MODBUS_H
#define MODBUSPP_MODBUS_H

#include <cstring>
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>


#define MAX_MSG_LENGTH 260

///Function Code
#define     READ_COILS        0x01
#define     READ_INPUT_BITS   0x02
#define     READ_REGS         0x03
#define     READ_INPUT_REGS   0x04
#define     WRITE_COIL        0x05
#define     WRITE_REG         0x06
#define     WRITE_COILS       0x0F
#define     WRITE_REGS        0x10

///Exception Codes

#define    EX_ILLEGAL_FUNCTION  0x01 // Function Code not Supported
#define    EX_ILLEGAL_ADDRESS   0x02 // Output Address not exists
#define    EX_ILLEGAL_VALUE     0x03 // Output Value not in Range
#define    EX_SERVER_FAILURE    0x04 // Slave Deive Fails to process request
#define    EX_ACKNOWLEDGE       0x05 // Service Need Long Time to Execute
#define    EX_SERVER_BUSY       0x06 // Server Was Unable to Accept MB Request PDU
#define    EX_NEGATIVE_ACK      0x07
#define    EX_MEM_PARITY_PROB   0x08
#define    EX_GATEWAY_PROBLEMP  0x0A // Gateway Path not Available
#define    EX_GATEWYA_PROBLEMF  0x0B // Target Device Failed to Response
#define    EX_BAD_DATA          0XFF // Bad Data lenght or Address

#define    BAD_CON              -1

/// Modbus Operator Class
/**
 * Modbus Operator Class
 * Providing networking support and mobus operation support.
 */
class modbus {
private:
    bool _connected{};
    uint16_t PORT{};
    int _socket{};
    uint _msg_id{};
    int _slaveid{};
    std::string HOST;

    struct sockaddr_in _server{};


    inline void modbus_build_request(uint8_t *to_send, uint address, int func) const;

    int modbus_read(int address, uint amount, int func);
    int modbus_write(int address, uint amount, int func, const uint16_t *value);

    inline ssize_t modbus_send(uint8_t *to_send, int length);
    inline ssize_t modbus_receive(uint8_t *buffer) const;

    void modbuserror_handle(const uint8_t *msg, int func);

    inline void set_bad_con();
    inline void set_bad_input();


public:
    bool err{};
    int err_no{};
    std::string error_msg;




    modbus(std::string host, uint16_t port);
    ~modbus();

    bool modbus_connect();
    void modbus_close() const;

    void modbus_set_slave_id(int id);

    int  modbus_read_coils(int address, int amount, bool* buffer);
    int  modbus_read_input_bits(int address, int amount, bool* buffer);
    int  modbus_read_holding_registers(int address, int amount, uint16_t *buffer);
    int  modbus_read_input_registers(int address, int amount, uint16_t *buffer);

    int  modbus_write_coil(int address, const bool& to_write);
    int  modbus_write_register(int address, const uint16_t& value);
    int  modbus_write_coils(int address, int amount, const bool *value);
    int  modbus_write_registers(int address, int amount, const uint16_t *value);


};


/**
 * Main Constructor of Modbus Connector Object
 * @param host IP Address of Host
 * @param port Port for the TCP Connection
 * @return     A Modbus Connector Object
 */
modbus::modbus(std::string host, uint16_t port=502) {
    HOST = host;
    PORT = port;
    _slaveid = 1;
    _msg_id = 1;
    _connected = false;
    err = false;
    err_no = 0;
    error_msg = "";
}



/**
 * Destructor of Modbus Connector Object
 */
modbus::~modbus(void) = default;


/**
 * Modbus Slave ID Setter
 * @param id  ID of the Modbus Server Slave
 */
void modbus::modbus_set_slave_id(int id) {
    _slaveid = id;
}



/**
 * Build up a Modbus/TCP Connection
 * @return   If A Connection Is Successfully Built
 */
bool modbus::modbus_connect() {
    if(HOST.empty() || PORT == 0) {
        std::cout << "Missing Host and Port" << std::endl;
        return false;
    } else {
        std::cout << "Found Proper Host "<< HOST << " and Port " <<PORT <<std::endl;
    }

    _socket = socket(AF_INET, SOCK_STREAM, 0);
    if(_socket == -1) {
        std::cout <<"Error Opening Socket" <<std::endl;
        return false;
    } else {
        std::cout <<"Socket Opened Successfully" << std::endl;
    }

    struct timeval timeout{};
    timeout.tv_sec  = 20;  // after 20 seconds connect() will timeout
    timeout.tv_usec = 0;
    setsockopt(_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
    setsockopt(_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

    _server.sin_family = AF_INET;
    _server.sin_addr.s_addr = inet_addr(HOST.c_str());
    _server.sin_port = htons(PORT);

    if (connect(_socket, (struct sockaddr*)&_server, sizeof(_server)) < 0) {
        std::cout<< "Connection Error" << std::endl;
        return false;
    }

    std::cout<< "Connected" <<std::endl;
    _connected = true;
    return true;
}


/**
 * Close the Modbus/TCP Connection
 */
void modbus::modbus_close() const {
    close(_socket);
    std::cout <<"Socket Closed" <<std::endl;
}


/**
 * Modbus Request Builder
 * @param to_send   Message Buffer to Be Sent
 * @param address   Reference Address
 * @param func      Modbus Functional Code
 */
void modbus::modbus_build_request(uint8_t *to_send, uint address, int func) const {
    to_send[0] = (uint8_t) _msg_id >> 8u;
    to_send[1] = (uint8_t) (_msg_id & 0x00FFu);
    to_send[2] = 0;
    to_send[3] = 0;
    to_send[4] = 0;
    to_send[6] = (uint8_t) _slaveid;
    to_send[7] = (uint8_t) func;
    to_send[8] = (uint8_t) (address >> 8u);
    to_send[9] = (uint8_t) (address & 0x00FFu);
}


/**
 * Write Request Builder and Sender
 * @param address   Reference Address
 * @param amount    Amount of data to be Written
 * @param func      Modbus Functional Code
 * @param value     Data to Be Written
 */
int modbus::modbus_write(int address, uint amount, int func, const uint16_t *value) {
    int status = 0;
    if(func == WRITE_COIL || func == WRITE_REG) {
        uint8_t to_send[12];
        modbus_build_request(to_send, address, func);
        to_send[5] = 6;
        to_send[10] = (uint8_t) (value[0] >> 8u);
        to_send[11] = (uint8_t) (value[0] & 0x00FFu);
        status = modbus_send(to_send, 12);
    } else if(func == WRITE_REGS){
        uint8_t to_send[13 + 2 * amount];
        modbus_build_request(to_send, address, func);
        to_send[5] = (uint8_t) (7 + 2 * amount);
        to_send[10] = (uint8_t) (amount >> 8u);
        to_send[11] = (uint8_t) (amount & 0x00FFu);
        to_send[12] = (uint8_t) (2 * amount);
        for(int i = 0; i < amount; i++) {
            to_send[13 + 2 * i] = (uint8_t) (value[i] >> 8u);
            to_send[14 + 2 * i] = (uint8_t) (value[i] & 0x00FFu);
        }
        status = modbus_send(to_send, 13 + 2 * amount);
    } else if(func == WRITE_COILS) {
        uint8_t to_send[14 + (amount -1) / 8 ];
        modbus_build_request(to_send, address, func);
        to_send[5] = (uint8_t) (7 + (amount + 7) / 8);
        to_send[10] = (uint8_t) (amount >> 8u);
        to_send[11] = (uint8_t) (amount & 0x00FFu);
        to_send[12] = (uint8_t) ((amount + 7) / 8);
        for(int i = 0; i < (amount+7)/8; i++)
            to_send[13 + i] = 0; // init needed before summing!
        for(int i = 0; i < amount; i++) {
            to_send[13 + i/8] += (uint8_t) (value[i] << (i % 8u));
        }
        status = modbus_send(to_send, 14 + (amount - 1) / 8);
    }
    return status;

}


/**
 * Read Request Builder and Sender
 * @param address   Reference Address
 * @param amount    Amount of Data to Read
 * @param func      Modbus Functional Code
 */
int modbus::modbus_read(int address, uint amount, int func){
    uint8_t to_send[12];
    modbus_build_request(to_send, address, func);
    to_send[5] = 6;
    to_send[10] = (uint8_t) (amount >> 8u);
    to_send[11] = (uint8_t) (amount & 0x00FFu);
    return modbus_send(to_send, 12);
}


/**
 * Read Holding Registers
 * MODBUS FUNCTION 0x03
 * @param address    Reference Address
 * @param amount     Amount of Registers to Read
 * @param buffer     Buffer to Store Data Read from Registers
 */
int modbus::modbus_read_holding_registers(int address, int amount, uint16_t *buffer) {
    if(_connected) {
        if(amount > 65535 || address > 65535) {
            set_bad_input();
            return EX_BAD_DATA;
        }
        modbus_read(address, amount, READ_REGS);
        uint8_t to_rec[MAX_MSG_LENGTH];
        ssize_t k = modbus_receive(to_rec);
        if (k == -1) {
            set_bad_con();
            return BAD_CON;
        }
        modbuserror_handle(to_rec, READ_REGS);
        if(err) return err_no;
        for(uint i = 0; i < amount; i++) {
            buffer[i] = ((uint16_t)to_rec[9u + 2u * i]) << 8u;
            buffer[i] += (uint16_t) to_rec[10u + 2u * i];
        }
        return 0;
    } else {
        set_bad_con();
        return BAD_CON;
    }
}


/**
 * Read Input Registers
 * MODBUS FUNCTION 0x04
 * @param address     Reference Address
 * @param amount      Amount of Registers to Read
 * @param buffer      Buffer to Store Data Read from Registers
 */
int modbus::modbus_read_input_registers(int address, int amount, uint16_t *buffer) {
    if(_connected){
        if(amount > 65535 || address > 65535) {
            set_bad_input();
            return EX_BAD_DATA;
        }
        modbus_read(address, amount, READ_INPUT_REGS);
        uint8_t to_rec[MAX_MSG_LENGTH];
        ssize_t k = modbus_receive(to_rec);
        if (k == -1) {
            set_bad_con();
            return BAD_CON;
        }
        modbuserror_handle(to_rec, READ_INPUT_REGS);
        if(err) return err_no;
        for(uint i = 0; i < amount; i++) {
            buffer[i] = ((uint16_t)to_rec[9u + 2u * i]) << 8u;
            buffer[i] += (uint16_t) to_rec[10u + 2u * i];
        }
        return 0;
    } else {
        set_bad_con();
        return BAD_CON;
    }
}


/**
 * Read Coils
 * MODBUS FUNCTION 0x01
 * @param address     Reference Address
 * @param amount      Amount of Coils to Read
 * @param buffer      Buffer to Store Data Read from Coils
 */
int modbus::modbus_read_coils(int address, int amount, bool *buffer) {
    if(_connected) {
        if(amount > 2040 || address > 65535) {
            set_bad_input();
            return EX_BAD_DATA;
        }
        modbus_read(address, amount, READ_COILS);
        uint8_t to_rec[MAX_MSG_LENGTH];
        ssize_t k = modbus_receive(to_rec);
        if (k == -1) {
            set_bad_con();
            return BAD_CON;
        }
        modbuserror_handle(to_rec, READ_COILS);
        if(err) return err_no;
        for(uint i = 0; i < amount; i++) {
            buffer[i] = (bool) ((to_rec[9u + i / 8u] >> (i % 8u)) & 1u);
        }
        return 0;
    } else {
        set_bad_con();
        return BAD_CON;
    }
}


/**
 * Read Input Bits(Discrete Data)
 * MODBUS FUNCITON 0x02
 * @param address   Reference Address
 * @param amount    Amount of Bits to Read
 * @param buffer    Buffer to store Data Read from Input Bits
 */
int modbus::modbus_read_input_bits(int address, int amount, bool* buffer) {
    if(_connected) {
        if(amount > 2040 || address > 65535) {
            set_bad_input();
            return EX_BAD_DATA;
        }
        modbus_read(address, amount, READ_INPUT_BITS);
        uint8_t to_rec[MAX_MSG_LENGTH];
        ssize_t k = modbus_receive(to_rec);
        if (k == -1) {
            set_bad_con();
            return BAD_CON;
        }
        if(err) return err_no;
        for(uint i = 0; i < amount; i++) {
            buffer[i] = (bool) ((to_rec[9u + i / 8u] >> (i % 8u)) & 1u);
        }
        modbuserror_handle(to_rec, READ_INPUT_BITS);
        return 0;
    } else {
        return BAD_CON;
    }
}


/**
 * Write Single Coils
 * MODBUS FUNCTION 0x05
 * @param address    Reference Address
 * @param to_write   Value to be Written to Coil
 */
int modbus::modbus_write_coil(int address, const bool& to_write) {
    if(_connected) {
        if(address > 65535) {
            set_bad_input();
            return EX_BAD_DATA;
        }
        int value = to_write * 0xFF00;
        modbus_write(address, 1, WRITE_COIL, (uint16_t *)&value);
        uint8_t to_rec[MAX_MSG_LENGTH];
        ssize_t k = modbus_receive(to_rec);
        if (k == -1) {
            set_bad_con();
            return BAD_CON;
        }
        modbuserror_handle(to_rec, WRITE_COIL);
        if(err) return err_no;
        return 0;
    } else {
        set_bad_con();
        return BAD_CON;
    }
}


/**
 * Write Single Register
 * FUCTION 0x06
 * @param address   Reference Address
 * @param value     Value to Be Written to Register
 */
int modbus::modbus_write_register(int address, const uint16_t& value) {
    if(_connected) {
        if(address > 65535) {
            set_bad_input();
            return EX_BAD_DATA;
        }
        modbus_write(address, 1, WRITE_REG, &value);
        uint8_t to_rec[MAX_MSG_LENGTH];
        ssize_t k = modbus_receive(to_rec);
        if (k == -1) {
            set_bad_con();
            return BAD_CON;
        }
        modbuserror_handle(to_rec, WRITE_COIL);
        if(err) return err_no;
        return 0;
    } else {
        set_bad_con();
        return BAD_CON;
    }
}


/**
 * Write Multiple Coils
 * MODBUS FUNCTION 0x0F
 * @param address  Reference Address
 * @param amount   Amount of Coils to Write
 * @param value    Values to Be Written to Coils
 */
int modbus::modbus_write_coils(int address, int amount, const bool *value) {
    if(_connected) {
        if(address > 65535 || amount > 65535) {
            set_bad_input();
            return EX_BAD_DATA;
        }
        uint16_t temp[amount];
        for(int i = 0; i < amount; i++) {
            temp[i] = (uint16_t)value[i];
        }
        modbus_write(address, amount, WRITE_COILS, temp);
        uint8_t to_rec[MAX_MSG_LENGTH];
        ssize_t k = modbus_receive(to_rec);
        if (k == -1) {
            set_bad_con();
            return BAD_CON;
        }
        modbuserror_handle(to_rec, WRITE_COILS);
        if(err) return err_no;
        return 0;
    } else {
        set_bad_con();
        return BAD_CON;
    }
}


/**
 * Write Multiple Registers
 * MODBUS FUNCION 0x10
 * @param address Reference Address
 * @param amount  Amount of Value to Write
 * @param value   Values to Be Written to the Registers
 */
int modbus::modbus_write_registers(int address, int amount, const uint16_t *value) {
    if(_connected) {
        if(address > 65535 || amount > 65535) {
            set_bad_input();
            return EX_BAD_DATA;
        }
        modbus_write(address, amount, WRITE_REGS, value);
        uint8_t to_rec[MAX_MSG_LENGTH];
        ssize_t k = modbus_receive(to_rec);
        if (k == -1) {
            set_bad_con();
            return BAD_CON;
        }
        modbuserror_handle(to_rec, WRITE_REGS);
        if(err) return err_no;
        return 0;
    } else {
        set_bad_con();
        return BAD_CON;
    }
}


/**
 * Data Sender
 * @param to_send Request to Be Sent to Server
 * @param length  Length of the Request
 * @return        Size of the request
 */
ssize_t modbus::modbus_send(uint8_t *to_send, int length) {
    _msg_id++;
    return send(_socket, to_send, (size_t)length, 0);
}


/**
 * Data Receiver
 * @param buffer Buffer to Store the Data Retrieved
 * @return       Size of Incoming Data
 */
ssize_t modbus::modbus_receive(uint8_t *buffer) const {
    return recv(_socket, (char *) buffer, 1024, 0);
}

void modbus::set_bad_con() {
    err = true;
    error_msg = "BAD CONNECTION";
}


void modbus::set_bad_input() {
    err = true;
    error_msg = "BAD FUNCTION INPUT";
}

/**
 * Error Code Handler
 * @param msg   Message Received from the Server
 * @param func  Modbus Functional Code
 */
void modbus::modbuserror_handle(const uint8_t *msg, int func) {
    if(msg[7] == func + 0x80) {
        err = true;
        switch(msg[8]){
            case EX_ILLEGAL_FUNCTION:
                error_msg = "1 Illegal Function";
                break;
            case EX_ILLEGAL_ADDRESS:
                error_msg = "2 Illegal Address";
                break;
            case EX_ILLEGAL_VALUE:
                error_msg = "3 Illegal Value";
                break;
            case EX_SERVER_FAILURE:
                error_msg = "4 Server Failure";
                break;
            case EX_ACKNOWLEDGE:
                error_msg = "5 Acknowledge";
                break;
            case EX_SERVER_BUSY:
                error_msg = "6 Server Busy";
                break;
            case EX_NEGATIVE_ACK:
                error_msg = "7 Negative Acknowledge";
                break;
            case EX_MEM_PARITY_PROB:
                error_msg = "8 Memory Parity Problem";
                break;
            case EX_GATEWAY_PROBLEMP:
                error_msg = "10 Gateway Path Unavailable";
                break;
            case EX_GATEWYA_PROBLEMF:
                error_msg = "11 Gateway Target Device Failed to Respond";
                break;
            default:
                error_msg = "UNK";
                break;
        }
    }
    err = false;
    error_msg = "NO ERR";
}

#endif //MODBUSPP_MODBUS_H

猜你喜欢

转载自blog.csdn.net/yaojiawan/article/details/106951157
今日推荐