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(ð);
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