This commit is contained in:
2022-12-15 15:26:57 +01:00
commit 0939c32c58
56 changed files with 10650 additions and 0 deletions

View File

@ -0,0 +1,29 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _ARDUINO_MODBUS_H_INCLUDED
#define _ARDUINO_MODBUS_H_INCLUDED
#include "ModbusRTUClient.h"
#include "ModbusRTUServer.h"
#include "ModbusTCPClient.h"
#include "ModbusTCPServer.h"
#endif

View File

@ -0,0 +1,424 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
#include "ModbusClient.h"
ModbusClient::ModbusClient(unsigned long defaultTimeout) :
_mb(NULL),
_timeout(defaultTimeout),
_defaultId(0x00),
_transmissionBegun(false),
_values(NULL),
_available(0),
_read(0),
_availableForWrite(0),
_written(0)
{
}
ModbusClient::~ModbusClient()
{
if (_values != NULL) {
free(_values);
}
if (_mb != NULL) {
modbus_free(_mb);
}
}
int ModbusClient::begin(modbus_t* mb, int defaultId)
{
end();
_mb = mb;
_defaultId = defaultId;
if (_mb == NULL) {
return 0;
}
if (modbus_connect(_mb) != 0) {
modbus_free(_mb);
_mb = NULL;
return 0;
}
_transmissionBegun = false;
_available = 0;
_read = 0;
_availableForWrite = 0;
_written = 0;
modbus_set_error_recovery(_mb, MODBUS_ERROR_RECOVERY_PROTOCOL);
setTimeout(_timeout);
return 1;
}
void ModbusClient::end()
{
if (_values != NULL) {
free(_values);
_values = NULL;
}
if (_mb != NULL) {
modbus_close(_mb);
modbus_free(_mb);
_mb = NULL;
}
}
int ModbusClient::coilRead(int address)
{
return coilRead(_defaultId, address);
}
int ModbusClient::coilRead(int id, int address)
{
uint8_t value;
modbus_set_slave(_mb, id);
if (modbus_read_bits(_mb, address, 1, &value) < 0) {
return -1;
}
return value;
}
int ModbusClient::discreteInputRead(int address)
{
return discreteInputRead(_defaultId, address);
}
int ModbusClient::discreteInputRead(int id, int address)
{
uint8_t value;
modbus_set_slave(_mb, id);
if (modbus_read_input_bits(_mb, address, 1, &value) < 0) {
return -1;
}
return value;
}
long ModbusClient::holdingRegisterRead(int address)
{
return holdingRegisterRead(_defaultId, address);
}
long ModbusClient::holdingRegisterRead(int id, int address)
{
uint16_t value;
modbus_set_slave(_mb, id);
if (modbus_read_registers(_mb, address, 1, &value) < 0) {
return -1;
}
return value;
}
long ModbusClient::inputRegisterRead(int address)
{
return inputRegisterRead(_defaultId, address);
}
long ModbusClient::inputRegisterRead(int id, int address)
{
uint16_t value;
modbus_set_slave(_mb, id);
if (modbus_read_input_registers(_mb, address, 1, &value) < 0) {
return -1;
}
return value;
}
int ModbusClient::coilWrite(int address, uint8_t value)
{
return coilWrite(_defaultId, address, value);
}
int ModbusClient::coilWrite(int id, int address, uint8_t value)
{
modbus_set_slave(_mb, id);
if (modbus_write_bit(_mb, address, value) < 0) {
return 0;
}
return 1;
}
int ModbusClient::holdingRegisterWrite(int address, uint16_t value)
{
return holdingRegisterWrite(_defaultId, address, value);
}
int ModbusClient::holdingRegisterWrite(int id, int address, uint16_t value)
{
modbus_set_slave(_mb, id);
if (modbus_write_register(_mb, address, value) < 0) {
return 0;
}
return 1;
}
int ModbusClient::registerMaskWrite(int address, uint16_t andMask, uint16_t orMask)
{
return registerMaskWrite(_defaultId, address, andMask, orMask);
}
int ModbusClient::registerMaskWrite(int id, int address, uint16_t andMask, uint16_t orMask)
{
modbus_set_slave(_mb, id);
if (modbus_mask_write_register(_mb, address, andMask, orMask) < 0) {
return 0;
}
return 1;
}
int ModbusClient::beginTransmission(int type, int address, int nb)
{
return beginTransmission(_defaultId, type, address, nb);
}
int ModbusClient::beginTransmission(int id, int type, int address, int nb)
{
if ((type != COILS && type != HOLDING_REGISTERS) || nb < 1) {
errno = EINVAL;
return 0;
}
int valueSize = (type == COILS) ? sizeof(uint8_t) : sizeof(uint16_t);
_values = realloc(_values, nb * valueSize);
if (_values == NULL) {
errno = ENOMEM;
return 0;
}
memset(_values, 0x00, nb * valueSize);
_transmissionBegun = true;
_id = id;
_type = type;
_address = address;
_nb = nb;
_available = 0;
_read = 0;
_availableForWrite = nb;
_written = 0;
return 1;
}
int ModbusClient::write(unsigned int value)
{
if (!_transmissionBegun || _availableForWrite <= 0) {
return 0;
}
switch (_type) {
case COILS:
((uint8_t*)_values)[_written++] = value;
_availableForWrite--;
return 1;
case HOLDING_REGISTERS:
((uint16_t*)_values)[_written++] = value;
_availableForWrite--;
return 1;
default:
return 0;
}
return 1;
}
int ModbusClient::endTransmission()
{
if (!_transmissionBegun) {
return 0;
}
int result = -1;
modbus_set_slave(_mb, _id);
switch (_type) {
case COILS:
result = modbus_write_bits(_mb, _address, _nb, (const uint8_t*)_values);
break;
case HOLDING_REGISTERS:
result = modbus_write_registers(_mb, _address, _nb, (const uint16_t*)_values);
break;
default:
return 0;
}
_transmissionBegun = false;
_available = 0;
_read = 0;
_availableForWrite = 0;
_written = 0;
return (result < 0) ? 0 : 1;
}
int ModbusClient::requestFrom(int type, int address, int nb)
{
return requestFrom(_defaultId, type, address, nb);
}
int ModbusClient::requestFrom(int id, int type, int address, int nb)
{
if ((type != COILS && type != DISCRETE_INPUTS && type != HOLDING_REGISTERS && type != INPUT_REGISTERS)
|| (nb < 1)) {
errno = EINVAL;
return 0;
}
int valueSize = (type == COILS || type == DISCRETE_INPUTS) ? sizeof(uint8_t) : sizeof(uint16_t);
_values = realloc(_values, nb * valueSize);
if (_values == NULL) {
errno = ENOMEM;
return 0;
}
int result = -1;
modbus_set_slave(_mb, id);
switch (type) {
case COILS:
result = modbus_read_bits(_mb, address, nb, (uint8_t*)_values);
break;
case DISCRETE_INPUTS:
result = modbus_read_input_bits(_mb, address, nb, (uint8_t*)_values);
break;
case HOLDING_REGISTERS:
result = modbus_read_registers(_mb, address, nb, (uint16_t*)_values);
break;
case INPUT_REGISTERS:
result = modbus_read_input_registers(_mb, address, nb, (uint16_t*)_values);
break;
default:
break;
}
if (result == -1) {
return 0;
}
_transmissionBegun = false;
_type = type;
_available = nb;
_read = 0;
_availableForWrite = 0;
_written = 0;
return nb;
}
int ModbusClient::available()
{
return _available;
}
long ModbusClient::read()
{
if (_available <= 0) {
return -1;
}
long result = -1;
switch (_type) {
case COILS:
case DISCRETE_INPUTS:
result = ((uint8_t*)_values)[_read];
break;
case HOLDING_REGISTERS:
case INPUT_REGISTERS:
result = ((uint16_t*)_values)[_read];
break;
default:
break;
}
if (result != -1) {
_available--;
_read++;
}
return result;
}
const char* ModbusClient::lastError()
{
if (errno == 0) {
return NULL;
}
return modbus_strerror(errno);
}
void ModbusClient::setTimeout(unsigned long ms)
{
_timeout = ms;
if (_mb) {
modbus_set_response_timeout(_mb, _timeout / 1000, (_timeout % 1000) * 1000);
}
}

View File

@ -0,0 +1,230 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MODBUS_CLIENT_H_INCLUDED
#define _MODBUS_CLIENT_H_INCLUDED
extern "C" {
#include "libmodbus/modbus.h"
}
#include <Arduino.h>
#define COILS 0
#define DISCRETE_INPUTS 1
#define HOLDING_REGISTERS 2
#define INPUT_REGISTERS 3
class ModbusClient {
public:
/**
* Perform a "Read Coils" operation for the specified address for a single
* coil.
*
* @param id (slave) id of target, defaults to 0x00 if not specified
* @param address address to use for operation
*
* @return coil value on success, -1 on failure.
*/
int coilRead(int address);
int coilRead(int id, int address);
/**
* Perform a "Read Discrete Inputs" operation for the specified address for a
* single discrete input.
*
* @param id (slave) id of target, defaults to 0x00 if not specified
* @param address address to use for operation
*
* @return discrete input value on success, -1 on failure.
*/
int discreteInputRead(int address);
int discreteInputRead(int id, int address);
/**
* Perform a "Read Holding Registers" operation for a single holding
* register.
*
* @param id (slave) id of target, defaults to 0x00 if not specified
* @param address start address to use for operation
*
* @return holding register value on success, -1 on failure.
*/
long holdingRegisterRead(int address);
long holdingRegisterRead(int id, int address);
/**
* Perform a "Read Input Registers" operation for a single input
* register.
*
* @param id (slave) id of target, defaults to 0x00 if not specified
* @param address address to use for operation
*
* @return input register value on success, -1 on failure.
*/
long inputRegisterRead(int address);
long inputRegisterRead(int id, int address);
/**
* Perform a "Write Single Coil" operation for the specified address and
* value.
*
* @param id (slave) id of target, defaults to 0x00 if not specified
* @param address address to use for operation
* @param value coil value to write
*
* @return 1 on success, 0 on failure.
*/
int coilWrite(int address, uint8_t value);
int coilWrite(int id, int address, uint8_t value);
/**
* Perform a "Write Single Holding Register" operation for the specified
* address and value.
*
* @param id (slave) id of target, defaults to 0x00 if not specified
* @param address address to use for operation
* @param value holding register value to write
*
* @return 1 on success, 0 on failure.
*/
int holdingRegisterWrite(int address, uint16_t value);
int holdingRegisterWrite(int id, int address, uint16_t value);
/**
* Perform a "Mask Write Registers" operation for the specified
* address, AND mask and OR mask.
*
* @param id (slave) id of target, defaults to 0x00 if not specified
* @param address address to use for operation
* @param andMask AND mask to use for operation
* @param orMask OR mask to use for operation
*
* @return 1 on success, 0 on failure.
*/
int registerMaskWrite(int address, uint16_t andMask, uint16_t orMask);
int registerMaskWrite(int id, int address, uint16_t andMask, uint16_t orMask);
/**
* Begin the process of a writing multiple coils or holding registers.
*
* Use write(value) to set the values you want to send, and endTransmission()
* to send request on the wire.
*
* @param id (slave) id of target, defaults to 0x00 if not specified
* @param type type of write to perform, either COILS or HOLDING_REGISTERS
* @param address start address to use for operation
* @param nb number of values to write
*
* @return 1 on success, 0 on failure
*/
int beginTransmission(int type, int address, int nb);
int beginTransmission(int id, int type, int address, int nb);
/**
* Set the values of a write operation started by beginTransmission(...).
*
* @param value value to write
*
* @return 1 on success, 0 on failure
*/
int write(unsigned int value);
/**
* End the process of a writing multiple coils or holding registers.
*
* @return 1 on success, 0 on failure
*/
int endTransmission();
/**
* Read multiple coils, discrete inputs, holding registers, or input
* register values.
*
* Use available() and read() to process the read values.
*
* @param id (slave) id of target, defaults to 0x00 if not specified
* @param type type of read to perform, either COILS, DISCRETE_INPUTS,
* HOLDING_REGISTERS, or INPUT_REGISTERS
* @param address start address to use for operation
* @param nb number of values to read
*
* @return 0 on failure, number of values read on success
*/
int requestFrom(int type, int address, int nb);
int requestFrom(int id, int type, int address,int nb);
/**
* Query the number of values available to read after calling
* requestFrom(...)
*
* @return number of values available for reading use read()
*/
int available();
/**
* Read a value after calling requestFrom(...)
*
* @return -1 on failure, value on success
*/
long read();
/**
* Read the last error reason as a string
*
* @return Last error reason as a C string
*/
const char* lastError();
/**
* Stop the client and clean up
*/
void end();
/**
* Set response timeout (in milliseconds)
*/
void setTimeout(unsigned long ms);
protected:
ModbusClient(unsigned long defaultTimeout);
virtual ~ModbusClient();
int begin(modbus_t* _mb, int defaultId);
private:
modbus_t* _mb;
unsigned long _timeout;
int _defaultId;
bool _transmissionBegun;
int _id;
int _type;
int _address;
int _nb;
void* _values;
int _available;
int _read;
int _availableForWrite;
int _written;
};
#endif

View File

@ -0,0 +1,60 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
extern "C" {
#include "libmodbus/modbus.h"
#include "libmodbus/modbus-rtu.h"
}
#include "ModbusRTUClient.h"
ModbusRTUClientClass::ModbusRTUClientClass() :
ModbusClient(1000)
{
}
ModbusRTUClientClass::ModbusRTUClientClass(RS485Class& rs485) :
ModbusClient(1000), _rs485(&rs485)
{
}
ModbusRTUClientClass::~ModbusRTUClientClass()
{
}
int ModbusRTUClientClass::begin(unsigned long baudrate, uint16_t config)
{
modbus_t* mb = modbus_new_rtu(_rs485, baudrate, config);
if (!ModbusClient::begin(mb, 0x00)) {
return 0;
}
return 1;
}
int ModbusRTUClientClass::begin(RS485Class& rs485, unsigned long baudrate, uint16_t config)
{
_rs485 = &rs485;
return begin(baudrate, config);
}
ModbusRTUClientClass ModbusRTUClient;

View File

@ -0,0 +1,49 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MODBUS_RTU_CLIENT_H_INCLUDED
#define _MODBUS_RTU_CLIENT_H_INCLUDED
#include "ModbusClient.h"
#include <ArduinoRS485.h>
class ModbusRTUClientClass : public ModbusClient {
public:
ModbusRTUClientClass();
ModbusRTUClientClass(RS485Class& rs485);
virtual ~ModbusRTUClientClass();
/**
* Start the Modbus RTU client with the specified parameters
*
* @param baudrate Baud rate to use
* @param config serial config. to use defaults to SERIAL_8N1
*
* Return 1 on success, 0 on failure
*/
int begin(unsigned long baudrate, uint16_t config = SERIAL_8N1);
int begin(RS485Class& rs485, unsigned long baudrate, uint16_t config = SERIAL_8N1);
private:
RS485Class* _rs485; // = &RS485;
};
extern ModbusRTUClientClass ModbusRTUClient;
#endif

View File

@ -0,0 +1,73 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
extern "C" {
#include "libmodbus/modbus.h"
#include "libmodbus/modbus-rtu.h"
}
#include "ModbusRTUServer.h"
ModbusRTUServerClass::ModbusRTUServerClass()
{
}
ModbusRTUServerClass::ModbusRTUServerClass(RS485Class& rs485) : _rs485(&rs485)
{
}
ModbusRTUServerClass::~ModbusRTUServerClass()
{
}
int ModbusRTUServerClass::begin(int id, unsigned long baudrate, uint16_t config)
{
modbus_t* mb = modbus_new_rtu(_rs485, baudrate, config);
if (!ModbusServer::begin(mb, id)) {
return 0;
}
modbus_connect(mb);
return 1;
}
int ModbusRTUServerClass::begin(RS485Class& rs485, int id, unsigned long baudrate, uint16_t config)
{
_rs485 = &rs485;
return begin(id, baudrate, config);
}
int ModbusRTUServerClass::poll()
{
uint8_t request[MODBUS_RTU_MAX_ADU_LENGTH];
int requestLength = modbus_receive(_mb, request);
if (requestLength > 0) {
modbus_reply(_mb, request, requestLength, &_mbMapping);
return 1;
}
return 0;
}
ModbusRTUServerClass ModbusRTUServer;

View File

@ -0,0 +1,55 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MODBUS_RTU_SERVER_H_INCLUDED
#define _MODBUS_RTU_SERVER_H_INCLUDED
#include "ModbusServer.h"
#include <ArduinoRS485.h>
class ModbusRTUServerClass : public ModbusServer {
public:
ModbusRTUServerClass();
ModbusRTUServerClass(RS485Class& rs485);
virtual ~ModbusRTUServerClass();
/**
* Start the Modbus RTU server with the specified parameters
*
* @param id (slave) id of the server
* @param baudrate Baud rate to use
* @param config serial config. to use defaults to SERIAL_8N1
*
* Return 1 on success, 0 on failure
*/
int begin(int id, unsigned long baudrate, uint16_t config = SERIAL_8N1);
int begin(RS485Class& rs485, int id, unsigned long baudrate, uint16_t config = SERIAL_8N1);
/**
* Poll interface for requests
*/
virtual int poll();
private:
RS485Class* _rs485;// = &RS485;
};
extern ModbusRTUServerClass ModbusRTUServer;
#endif

View File

@ -0,0 +1,329 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
#include "ModbusServer.h"
ModbusServer::ModbusServer() :
_mb(NULL)
{
memset(&_mbMapping, 0x00, sizeof(_mbMapping));
}
ModbusServer::~ModbusServer()
{
if (_mbMapping.tab_bits != NULL) {
free(_mbMapping.tab_bits);
}
if (_mbMapping.tab_input_bits != NULL) {
free(_mbMapping.tab_input_bits);
}
if (_mbMapping.tab_input_registers != NULL) {
free(_mbMapping.tab_input_registers);
}
if (_mbMapping.tab_registers != NULL) {
free(_mbMapping.tab_registers);
}
if (_mb != NULL) {
modbus_free(_mb);
}
}
int ModbusServer::configureCoils(int startAddress, int nb)
{
if (startAddress < 0 || nb < 1) {
errno = EINVAL;
return -1;
}
size_t s = sizeof(_mbMapping.tab_bits[0]) * nb;
_mbMapping.tab_bits = (uint8_t*)realloc(_mbMapping.tab_bits, s);
if (_mbMapping.tab_bits == NULL) {
_mbMapping.start_bits = 0;
_mbMapping.nb_bits = 0;
return 0;
}
memset(_mbMapping.tab_bits, 0x00, s);
_mbMapping.start_bits = startAddress;
_mbMapping.nb_bits = nb;
return 1;
}
int ModbusServer::configureDiscreteInputs(int startAddress, int nb)
{
if (startAddress < 0 || nb < 1) {
errno = EINVAL;
return -1;
}
size_t s = sizeof(_mbMapping.tab_input_bits[0]) * nb;
_mbMapping.tab_input_bits = (uint8_t*)realloc(_mbMapping.tab_input_bits, s);
if (_mbMapping.tab_input_bits == NULL) {
_mbMapping.start_input_bits = 0;
_mbMapping.nb_input_bits = 0;
return 0;
}
memset(_mbMapping.tab_input_bits, 0x00, s);
_mbMapping.start_input_bits = startAddress;
_mbMapping.nb_input_bits = nb;
return 1;
}
int ModbusServer::configureHoldingRegisters(int startAddress, int nb)
{
if (startAddress < 0 || nb < 1) {
errno = EINVAL;
return -1;
}
size_t s = sizeof(_mbMapping.tab_registers[0]) * nb;
_mbMapping.tab_registers = (uint16_t*)realloc(_mbMapping.tab_registers, s);
if (_mbMapping.tab_registers == NULL) {
_mbMapping.start_registers = 0;
_mbMapping.nb_registers = 0;
return 0;
}
memset(_mbMapping.tab_registers, 0x00, s);
_mbMapping.start_registers = startAddress;
_mbMapping.nb_registers = nb;
return 1;
}
int ModbusServer::configureInputRegisters(int startAddress, int nb)
{
if (startAddress < 0 || nb < 1) {
errno = EINVAL;
return -1;
}
size_t s = sizeof(_mbMapping.tab_input_registers[0]) * nb;
_mbMapping.tab_input_registers = (uint16_t*)realloc(_mbMapping.tab_input_registers, s);
if (_mbMapping.tab_input_registers == NULL) {
_mbMapping.start_input_registers = 0;
_mbMapping.nb_input_registers = 0;
return 0;
}
memset(_mbMapping.tab_input_registers, 0x00, s);
_mbMapping.start_input_registers = startAddress;
_mbMapping.nb_input_registers = nb;
return 1;
}
int ModbusServer::coilRead(int address)
{
if (_mbMapping.start_bits > address ||
(_mbMapping.start_bits + _mbMapping.nb_bits) < (address + 1)) {
errno = EMBXILADD;
return -1;
}
return _mbMapping.tab_bits[address - _mbMapping.start_bits];
}
int ModbusServer::discreteInputRead(int address)
{
if (_mbMapping.start_input_bits > address ||
(_mbMapping.start_input_bits + _mbMapping.nb_input_bits) < (address + 1)) {
errno = EMBXILADD;
return -1;
}
return _mbMapping.tab_input_bits[address - _mbMapping.start_input_bits];
}
long ModbusServer::holdingRegisterRead(int address)
{
if (_mbMapping.start_registers > address ||
(_mbMapping.start_registers + _mbMapping.nb_registers) < (address + 1)) {
errno = EMBXILADD;
return -1;
}
return _mbMapping.tab_registers[address - _mbMapping.start_registers];
}
long ModbusServer::inputRegisterRead(int address)
{
if (_mbMapping.start_input_registers > address ||
(_mbMapping.start_input_registers + _mbMapping.nb_input_registers) < (address + 1)) {
errno = EMBXILADD;
return -1;
}
return _mbMapping.tab_input_registers[address - _mbMapping.start_input_registers];
}
int ModbusServer::coilWrite(int address, uint8_t value)
{
if (_mbMapping.start_bits > address ||
(_mbMapping.start_bits + _mbMapping.nb_bits) < (address + 1)) {
errno = EMBXILADD;
return 0;
}
_mbMapping.tab_bits[address - _mbMapping.start_bits] = value;
return 1;
}
int ModbusServer::holdingRegisterWrite(int address, uint16_t value)
{
if (_mbMapping.start_registers > address ||
(_mbMapping.start_registers + _mbMapping.nb_registers) < (address + 1)) {
errno = EMBXILADD;
return 0;
}
_mbMapping.tab_registers[address - _mbMapping.start_registers] = value;
return 1;
}
int ModbusServer::registerMaskWrite(int address, uint16_t andMask, uint16_t orMask)
{
long value = holdingRegisterRead(address);
if (value < 0) {
return 0;
}
value &= andMask;
value |= orMask;
if (!holdingRegisterWrite(address, value)) {
return 0;
}
return 1;
}
int ModbusServer::discreteInputWrite(int address, uint8_t value)
{
return writeDiscreteInputs(address, &value, 1);
}
int ModbusServer::writeDiscreteInputs(int address, uint8_t values[], int nb)
{
if (_mbMapping.start_input_bits > address ||
(_mbMapping.start_input_bits + _mbMapping.nb_input_bits) < (address + nb)) {
errno = EMBXILADD;
return 0;
}
memcpy(&_mbMapping.tab_input_bits[address - _mbMapping.start_input_bits], values, sizeof(values[0]) * nb);
return 1;
}
int ModbusServer::inputRegisterWrite(int address, uint16_t value)
{
return writeInputRegisters(address, &value, 1);
}
int ModbusServer::writeInputRegisters(int address, uint16_t values[], int nb)
{
if (_mbMapping.start_input_registers > address ||
(_mbMapping.start_input_registers + _mbMapping.nb_input_registers) < (address + nb)) {
errno = EMBXILADD;
return 0;
}
memcpy(&_mbMapping.tab_input_registers[address - _mbMapping.start_input_registers], values, sizeof(values[0]) * nb);
return 1;
}
int ModbusServer::begin(modbus_t* mb, int id)
{
end();
_mb = mb;
if (_mb == NULL) {
return 0;
}
modbus_set_slave(_mb, id);
return 1;
}
void ModbusServer::end()
{
if (_mbMapping.tab_bits != NULL) {
free(_mbMapping.tab_bits);
}
if (_mbMapping.tab_input_bits != NULL) {
free(_mbMapping.tab_input_bits);
}
if (_mbMapping.tab_input_registers != NULL) {
free(_mbMapping.tab_input_registers);
}
if (_mbMapping.tab_registers != NULL) {
free(_mbMapping.tab_registers);
}
memset(&_mbMapping, 0x00, sizeof(_mbMapping));
if (_mb != NULL) {
modbus_close(_mb);
modbus_free(_mb);
_mb = NULL;
}
}

View File

@ -0,0 +1,150 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MODBUS_SERVER_H_INCLUDED
#define _MODBUS_SERVER_H_INCLUDED
#include <Arduino.h>
extern "C" {
#include "libmodbus/modbus.h"
}
class ModbusServer {
public:
/**
* Configure the servers coils.
*
* @param startAddress start address of coils
* @param nb number of coils to configure
*
* @return 0 on success, 1 on failure
*/
int configureCoils(int startAddress, int nb);
/**
* Configure the servers discrete inputs.
*
* @param startAddress start address of discrete inputs
* @param nb number of discrete inputs to configure
*
* @return 0 on success, 1 on failure
*/
int configureDiscreteInputs(int startAddress, int nb);
/**
* Configure the servers holding registers.
*
* @param startAddress start address of holding registers
* @param nb number of holding registers to configure
*
* @return 0 on success, 1 on failure
*/
int configureHoldingRegisters(int startAddress, int nb);
/**
* Configure the servers input registers.
*
* @param startAddress start address of input registers
* @param nb number of input registers to configure
*
* @return 0 on success, 1 on failure
*/
int configureInputRegisters(int startAddress, int nb);
// same as ModbusClient.h
int coilRead(int address);
int discreteInputRead(int address);
long holdingRegisterRead(int address);
long inputRegisterRead(int address);
int coilWrite(int address, uint8_t value);
int holdingRegisterWrite(int address, uint16_t value);
int registerMaskWrite(int address, uint16_t andMask, uint16_t orMask);
/**
* Write the value of the server's Discrete Input for the specified address
* and value.
*
* @param address address to use for operation
* @param value discrete input value to write
*
* @return 1 on success, 0 on failure.
*/
int discreteInputWrite(int address, uint8_t value);
/**
* Write values to the server's Discrete Inputs for the specified address
* and values.
*
* @param address address to use for operation
* @param values array of discrete inputs values to write
* @param nb number of discrete inputs to write
*
* @return 1 on success, 0 on failure.
*/
int writeDiscreteInputs(int address, uint8_t values[], int nb);
/**
* Write the value of the server's Input Register for the specified address
* and value.
*
* @param address address to use for operation
* @param value input register value to write
*
* @return 1 on success, 0 on failure.
*/
int inputRegisterWrite(int address, uint16_t value);
/**
* Write values to the server's Input Registers for the specified address
* and values.
*
* @param address address to use for operation
* @param values array of input registers values to write
* @param nb number of input registers to write
*
* @return 1 on success, 0 on failure.
*/
int writeInputRegisters(int address, uint16_t values[], int nb);
/**
* Poll for requests
*
* @return 1 on request, 0 on no request.
*/
virtual int poll() = 0;
/**
* Stop the server
*/
void end();
protected:
ModbusServer();
virtual ~ModbusServer();
int begin(modbus_t* _mb, int id);
protected:
modbus_t* _mb;
modbus_mapping_t _mbMapping;
};
#endif

View File

@ -0,0 +1,54 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
extern "C" {
#include "libmodbus/modbus.h"
#include "libmodbus/modbus-tcp.h"
}
#include "ModbusTCPClient.h"
ModbusTCPClient::ModbusTCPClient(Client& client) :
ModbusClient(30 * 1000),
_client(&client)
{
}
ModbusTCPClient::~ModbusTCPClient()
{
}
int ModbusTCPClient::begin(IPAddress ip, uint16_t port)
{
modbus_t* mb = modbus_new_tcp(_client, ip, port);
return ModbusClient::begin(mb, MODBUS_TCP_SLAVE);
}
int ModbusTCPClient::connected()
{
return _client->connected();
}
void ModbusTCPClient::stop()
{
end();
}

View File

@ -0,0 +1,64 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MODBUS_TCP_CLIENT_H_INCLUDED
#define _MODBUS_TCP_CLIENT_H_INCLUDED
#include <Client.h>
#include <IPAddress.h>
#include "ModbusClient.h"
class ModbusTCPClient : public ModbusClient {
public:
/**
* ModbusTCPClient constructor
*
* @param client Client to use for TCP connection
*/
ModbusTCPClient(Client& client);
virtual ~ModbusTCPClient();
/**
* Start the Modbus TCP client with the specified parameters
*
* @param ip IP Address of the Modbus server
* @param port TCP port number of Modbus server, defaults to 502
*
* @return 1 on success, 0 on failure
*/
int begin(IPAddress ip, uint16_t port = 502);
/**
* Query connection status.
*
* @return 1 if connected, 0 if not connected
*/
int connected();
/**
* Disconnect the client.
*/
void stop();
private:
Client* _client;
};
#endif

View File

@ -0,0 +1,73 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
extern "C" {
#include "libmodbus/modbus.h"
#include "libmodbus/modbus-tcp.h"
}
#include "ModbusTCPServer.h"
ModbusTCPServer::ModbusTCPServer() :
_client(NULL)
{
}
ModbusTCPServer::~ModbusTCPServer()
{
}
int ModbusTCPServer::begin(int id)
{
modbus_t* mb = modbus_new_tcp(NULL, IPAddress(0, 0, 0, 0), 0);
if (!ModbusServer::begin(mb, id)) {
return 0;
}
if (modbus_tcp_listen(mb) != 0) {
return 0;
}
return 1;
}
void ModbusTCPServer::accept(Client& client)
{
if (modbus_tcp_accept(_mb, &client) == 0) {
_client = &client;
}
}
int ModbusTCPServer::poll()
{
if (_client != NULL) {
uint8_t request[MODBUS_TCP_MAX_ADU_LENGTH];
int requestLength = modbus_receive(_mb, request);
if (requestLength > 0) {
modbus_reply(_mb, request, requestLength, &_mbMapping);
return 1;
}
}
return 0;
}

View File

@ -0,0 +1,57 @@
/*
This file is part of the ArduinoModbus library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _MODBUS_TCP_SERVER_H_INCLUDED
#define _MODBUS_TCP_SERVER_H_INCLUDED
#include <Client.h>
#include "ModbusServer.h"
class ModbusTCPServer : public ModbusServer {
public:
ModbusTCPServer();
virtual ~ModbusTCPServer();
/**
* Start the Modbus TCP server with the specified parameters
*
* @param id (slave) id of the server, defaults to 0xff (TCP)
*
* Return 1 on success, 0 on failure
*/
int begin(int id = 0xff);
/**
* Accept client connection
*
* @param client client to accept
*/
void accept(Client& client);
/**
* Poll accepted client for requests
*/
virtual int poll();
private:
Client* _client;
};
#endif

View File

@ -0,0 +1,252 @@
/*
* Copyright © 2010-2014 Stéphane Raimbault <stephane.raimbault@gmail.com>
* Copyright © 2018 Arduino SA. All rights reserved.
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include <stdlib.h>
#ifndef _MSC_VER
# include <stdint.h>
#else
# include "stdint.h"
#endif
#include <string.h>
#include <assert.h>
#if defined(_WIN32)
# include <winsock2.h>
#elif defined(ARDUINO)
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define htonl(x) bswap_32(x)
#define htons(x) bswap_16(x)
#define ntohl(x) bswap_32(x)
#define ntohs(x) bswap_16(x)
#else
#define htonl(x) (x)
#define htons(x) (x)
#define ntohl(x) (x)
#define ntohs(x) (x)
#endif
#else
# include <arpa/inet.h>
#endif
#ifndef ARDUINO
#include <config.h>
#endif
#include "modbus.h"
#if defined(HAVE_BYTESWAP_H)
# include <byteswap.h>
#endif
#if defined(__APPLE__)
# include <libkern/OSByteOrder.h>
# define bswap_16 OSSwapInt16
# define bswap_32 OSSwapInt32
# define bswap_64 OSSwapInt64
#endif
#if defined(__GNUC__)
# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ * 10)
# if GCC_VERSION >= 430
// Since GCC >= 4.30, GCC provides __builtin_bswapXX() alternatives so we switch to them
# undef bswap_32
# define bswap_32 __builtin_bswap32
# endif
#endif
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
# define bswap_32 _byteswap_ulong
# define bswap_16 _byteswap_ushort
#endif
#if !defined(__CYGWIN__) && !defined(bswap_16)
#ifndef ARDUINO
# warning "Fallback on C functions for bswap_16"
#endif
static inline uint16_t bswap_16(uint16_t x)
{
return (x >> 8) | (x << 8);
}
#endif
#if !defined(bswap_32)
#ifndef ARDUINO
# warning "Fallback on C functions for bswap_32"
#endif
static inline uint32_t bswap_32(uint32_t x)
{
return (bswap_16(x & 0xffff) << 16) | (bswap_16(x >> 16));
}
#endif
/* Sets many bits from a single byte value (all 8 bits of the byte value are
set) */
void modbus_set_bits_from_byte(uint8_t *dest, int idx, const uint8_t value)
{
int i;
for (i=0; i < 8; i++) {
dest[idx+i] = (value & (1 << i)) ? 1 : 0;
}
}
/* Sets many bits from a table of bytes (only the bits between idx and
idx + nb_bits are set) */
void modbus_set_bits_from_bytes(uint8_t *dest, int idx, unsigned int nb_bits,
const uint8_t *tab_byte)
{
unsigned int i;
int shift = 0;
for (i = idx; i < idx + nb_bits; i++) {
dest[i] = tab_byte[(i - idx) / 8] & (1 << shift) ? 1 : 0;
/* gcc doesn't like: shift = (++shift) % 8; */
shift++;
shift %= 8;
}
}
/* Gets the byte value from many bits.
To obtain a full byte, set nb_bits to 8. */
uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx,
unsigned int nb_bits)
{
unsigned int i;
uint8_t value = 0;
if (nb_bits > 8) {
/* Assert is ignored if NDEBUG is set */
assert(nb_bits < 8);
nb_bits = 8;
}
for (i=0; i < nb_bits; i++) {
value |= (src[idx+i] << i);
}
return value;
}
/* Get a float from 4 bytes (Modbus) without any conversion (ABCD) */
float modbus_get_float_abcd(const uint16_t *src)
{
float f;
uint32_t i;
i = ntohl(((uint32_t)src[0] << 16) + src[1]);
memcpy(&f, &i, sizeof(float));
return f;
}
/* Get a float from 4 bytes (Modbus) in inversed format (DCBA) */
float modbus_get_float_dcba(const uint16_t *src)
{
float f;
uint32_t i;
i = ntohl(bswap_32((((uint32_t)src[0]) << 16) + src[1]));
memcpy(&f, &i, sizeof(float));
return f;
}
/* Get a float from 4 bytes (Modbus) with swapped bytes (BADC) */
float modbus_get_float_badc(const uint16_t *src)
{
float f;
uint32_t i;
#if defined(ARDUINO) && defined(__AVR__)
i = ntohl((uint32_t)((uint32_t)bswap_16(src[0]) << 16) + bswap_16(src[1]));
#else
i = ntohl((uint32_t)(bswap_16(src[0]) << 16) + bswap_16(src[1]));
#endif
memcpy(&f, &i, sizeof(float));
return f;
}
/* Get a float from 4 bytes (Modbus) with swapped words (CDAB) */
float modbus_get_float_cdab(const uint16_t *src)
{
float f;
uint32_t i;
i = ntohl((((uint32_t)src[1]) << 16) + src[0]);
memcpy(&f, &i, sizeof(float));
return f;
}
/* DEPRECATED - Get a float from 4 bytes in sort of Modbus format */
float modbus_get_float(const uint16_t *src)
{
float f;
uint32_t i;
i = (((uint32_t)src[1]) << 16) + src[0];
memcpy(&f, &i, sizeof(float));
return f;
}
/* Set a float to 4 bytes for Modbus w/o any conversion (ABCD) */
void modbus_set_float_abcd(float f, uint16_t *dest)
{
uint32_t i;
memcpy(&i, &f, sizeof(uint32_t));
i = htonl(i);
dest[0] = (uint16_t)(i >> 16);
dest[1] = (uint16_t)i;
}
/* Set a float to 4 bytes for Modbus with byte and word swap conversion (DCBA) */
void modbus_set_float_dcba(float f, uint16_t *dest)
{
uint32_t i;
memcpy(&i, &f, sizeof(uint32_t));
i = bswap_32(htonl(i));
dest[0] = (uint16_t)(i >> 16);
dest[1] = (uint16_t)i;
}
/* Set a float to 4 bytes for Modbus with byte swap conversion (BADC) */
void modbus_set_float_badc(float f, uint16_t *dest)
{
uint32_t i;
memcpy(&i, &f, sizeof(uint32_t));
i = htonl(i);
dest[0] = (uint16_t)bswap_16(i >> 16);
dest[1] = (uint16_t)bswap_16(i & 0xFFFF);
}
/* Set a float to 4 bytes for Modbus with word swap conversion (CDAB) */
void modbus_set_float_cdab(float f, uint16_t *dest)
{
uint32_t i;
memcpy(&i, &f, sizeof(uint32_t));
i = htonl(i);
dest[0] = (uint16_t)i;
dest[1] = (uint16_t)(i >> 16);
}
/* DEPRECATED - Set a float to 4 bytes in a sort of Modbus format! */
void modbus_set_float(float f, uint16_t *dest)
{
uint32_t i;
memcpy(&i, &f, sizeof(uint32_t));
dest[0] = (uint16_t)i;
dest[1] = (uint16_t)(i >> 16);
}

View File

@ -0,0 +1,129 @@
/*
* Copyright © 2010-2012 Stéphane Raimbault <stephane.raimbault@gmail.com>
* Copyright © 2018 Arduino SA. All rights reserved.
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_PRIVATE_H
#define MODBUS_PRIVATE_H
#ifndef _MSC_VER
# include <stdint.h>
#if defined(ARDUINO) && defined(__AVR__)
#define ssize_t unsigned long
#define fd_set void*
struct timeval {
uint32_t tv_sec;
uint32_t tv_usec;
};
#else
# include <sys/time.h>
#endif
#else
# include "stdint.h"
# include <time.h>
typedef int ssize_t;
#endif
#include <sys/types.h>
#ifndef ARDUINO
#include <config.h>
#endif
#include "modbus.h"
MODBUS_BEGIN_DECLS
/* It's not really the minimal length (the real one is report slave ID
* in RTU (4 bytes)) but it's a convenient size to use in RTU or TCP
* communications to read many values or write a single one.
* Maximum between :
* - HEADER_LENGTH_TCP (7) + function (1) + address (2) + number (2)
* - HEADER_LENGTH_RTU (1) + function (1) + address (2) + number (2) + CRC (2)
*/
#define _MIN_REQ_LENGTH 12
#define _REPORT_SLAVE_ID 180
#define _MODBUS_EXCEPTION_RSP_LENGTH 5
/* Timeouts in microsecond (0.5 s) */
#define _RESPONSE_TIMEOUT 500000
#define _BYTE_TIMEOUT 500000
typedef enum {
_MODBUS_BACKEND_TYPE_RTU=0,
_MODBUS_BACKEND_TYPE_TCP
} modbus_backend_type_t;
/*
* ---------- Request Indication ----------
* | Client | ---------------------->| Server |
* ---------- Confirmation Response ----------
*/
typedef enum {
/* Request message on the server side */
MSG_INDICATION,
/* Request message on the client side */
MSG_CONFIRMATION
} msg_type_t;
/* This structure reduces the number of params in functions and so
* optimizes the speed of execution (~ 37%). */
typedef struct _sft {
int slave;
int function;
int t_id;
} sft_t;
typedef struct _modbus_backend {
unsigned int backend_type;
unsigned int header_length;
unsigned int checksum_length;
unsigned int max_adu_length;
int (*set_slave) (modbus_t *ctx, int slave);
int (*build_request_basis) (modbus_t *ctx, int function, int addr,
int nb, uint8_t *req);
int (*build_response_basis) (sft_t *sft, uint8_t *rsp);
int (*prepare_response_tid) (const uint8_t *req, int *req_length);
int (*send_msg_pre) (uint8_t *req, int req_length);
ssize_t (*send) (modbus_t *ctx, const uint8_t *req, int req_length);
int (*receive) (modbus_t *ctx, uint8_t *req);
ssize_t (*recv) (modbus_t *ctx, uint8_t *rsp, int rsp_length);
int (*check_integrity) (modbus_t *ctx, uint8_t *msg,
const int msg_length);
int (*pre_check_confirmation) (modbus_t *ctx, const uint8_t *req,
const uint8_t *rsp, int rsp_length);
int (*connect) (modbus_t *ctx);
void (*close) (modbus_t *ctx);
int (*flush) (modbus_t *ctx);
int (*select) (modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length);
void (*free) (modbus_t *ctx);
} modbus_backend_t;
struct _modbus {
/* Slave address */
int slave;
/* Socket or file descriptor */
int s;
int debug;
int error_recovery;
struct timeval response_timeout;
struct timeval byte_timeout;
const modbus_backend_t *backend;
void *backend_data;
};
void _modbus_init_common(modbus_t *ctx);
void _error_print(modbus_t *ctx, const char *context);
int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type);
#ifndef HAVE_STRLCPY
size_t strlcpy(char *dest, const char *src, size_t dest_size);
#endif
MODBUS_END_DECLS
#endif /* MODBUS_PRIVATE_H */

View File

@ -0,0 +1,85 @@
/*
* Copyright © 2001-2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
* Copyright © 2018 Arduino SA. All rights reserved.
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_RTU_PRIVATE_H
#define MODBUS_RTU_PRIVATE_H
#ifndef _MSC_VER
#include <stdint.h>
#else
#include "stdint.h"
#endif
#if defined(_WIN32)
#include <windows.h>
#elif defined(ARDUINO)
#include <ArduinoRS485.h>
#else
#include <termios.h>
#endif
#define _MODBUS_RTU_HEADER_LENGTH 1
#define _MODBUS_RTU_PRESET_REQ_LENGTH 6
#define _MODBUS_RTU_PRESET_RSP_LENGTH 2
#define _MODBUS_RTU_CHECKSUM_LENGTH 2
#if defined(_WIN32)
#if !defined(ENOTSUP)
#define ENOTSUP WSAEOPNOTSUPP
#endif
/* WIN32: struct containing serial handle and a receive buffer */
#define PY_BUF_SIZE 512
struct win32_ser {
/* File handle */
HANDLE fd;
/* Receive buffer */
uint8_t buf[PY_BUF_SIZE];
/* Received chars */
DWORD n_bytes;
};
#endif /* _WIN32 */
typedef struct _modbus_rtu {
#if defined(ARDUINO)
unsigned long baud;
uint16_t config;
RS485Class* rs485;
#else
/* Device: "/dev/ttyS0", "/dev/ttyUSB0" or "/dev/tty.USA19*" on Mac OS X. */
char *device;
/* Bauds: 9600, 19200, 57600, 115200, etc */
int baud;
/* Data bit */
uint8_t data_bit;
/* Stop bit */
uint8_t stop_bit;
/* Parity: 'N', 'O', 'E' */
char parity;
#if defined(_WIN32)
struct win32_ser w_ser;
DCB old_dcb;
#else
/* Save old termios settings */
struct termios old_tios;
#endif
#if HAVE_DECL_TIOCSRS485
int serial_mode;
#endif
#if HAVE_DECL_TIOCM_RTS
int rts;
int rts_delay;
int onebyte_time;
void (*set_rts) (modbus_t *ctx, int on);
#endif
#endif
/* To handle many slaves on the same link */
int confirmation_to_ignore;
} modbus_rtu_t;
#endif /* MODBUS_RTU_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
/*
* Copyright © 2001-2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
* Copyright © 2018 Arduino SA. All rights reserved.
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_RTU_H
#define MODBUS_RTU_H
#include "modbus.h"
MODBUS_BEGIN_DECLS
/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5
* RS232 / RS485 ADU = 253 bytes + slave (1 byte) + CRC (2 bytes) = 256 bytes
*/
#define MODBUS_RTU_MAX_ADU_LENGTH 256
#ifdef ARDUINO
class RS485Class;
MODBUS_API modbus_t* modbus_new_rtu(RS485Class *rs485, unsigned long baud, uint16_t config);
#else
MODBUS_API modbus_t* modbus_new_rtu(const char *device, int baud, char parity,
int data_bit, int stop_bit);
#define MODBUS_RTU_RS232 0
#define MODBUS_RTU_RS485 1
MODBUS_API int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode);
MODBUS_API int modbus_rtu_get_serial_mode(modbus_t *ctx);
#define MODBUS_RTU_RTS_NONE 0
#define MODBUS_RTU_RTS_UP 1
#define MODBUS_RTU_RTS_DOWN 2
MODBUS_API int modbus_rtu_set_rts(modbus_t *ctx, int mode);
MODBUS_API int modbus_rtu_get_rts(modbus_t *ctx);
MODBUS_API int modbus_rtu_set_custom_rts(modbus_t *ctx, void (*set_rts) (modbus_t *ctx, int on));
MODBUS_API int modbus_rtu_set_rts_delay(modbus_t *ctx, int us);
MODBUS_API int modbus_rtu_get_rts_delay(modbus_t *ctx);
#endif
MODBUS_END_DECLS
#endif /* MODBUS_RTU_H */

View File

@ -0,0 +1,56 @@
/*
* Copyright © 2001-2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
* Copyright © 2018 Arduino SA. All rights reserved.
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_TCP_PRIVATE_H
#define MODBUS_TCP_PRIVATE_H
#ifdef ARDUINO
#include <Arduino.h>
#include <IPAddress.h>
#include <Client.h>
#endif
#define _MODBUS_TCP_HEADER_LENGTH 7
#define _MODBUS_TCP_PRESET_REQ_LENGTH 12
#define _MODBUS_TCP_PRESET_RSP_LENGTH 8
#define _MODBUS_TCP_CHECKSUM_LENGTH 0
/* In both structures, the transaction ID must be placed on first position
to have a quick access not dependant of the TCP backend */
typedef struct _modbus_tcp {
/* Extract from MODBUS Messaging on TCP/IP Implementation Guide V1.0b
(page 23/46):
The transaction identifier is used to associate the future response
with the request. This identifier is unique on each TCP connection. */
uint16_t t_id;
/* TCP port */
int port;
#ifdef ARDUINO
IPAddress ip;
Client* client;
#else
/* IP address */
char ip[16];
#endif
} modbus_tcp_t;
#define _MODBUS_TCP_PI_NODE_LENGTH 1025
#define _MODBUS_TCP_PI_SERVICE_LENGTH 32
typedef struct _modbus_tcp_pi {
/* Transaction ID */
uint16_t t_id;
/* TCP port */
int port;
/* Node */
char node[_MODBUS_TCP_PI_NODE_LENGTH];
/* Service */
char service[_MODBUS_TCP_PI_SERVICE_LENGTH];
} modbus_tcp_pi_t;
#endif /* MODBUS_TCP_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
/*
* Copyright © 2001-2010 Stéphane Raimbault <stephane.raimbault@gmail.com>
* Copyright © 2018 Arduino SA. All rights reserved.
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_TCP_H
#define MODBUS_TCP_H
#ifdef ARDUINO
// check if __has_include ArduinoAPI
#if defined __has_include
# if __has_include("api/ArduinoAPI.h")
#define __NEED_NAMESPACE__
namespace arduino {
# endif
#endif
class Client;
class IPAddress;
#endif
#ifdef __NEED_NAMESPACE__
}
#endif
#include "modbus.h"
MODBUS_BEGIN_DECLS
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Win32 with MinGW, supplement to <errno.h> */
#include <winsock2.h>
#if !defined(ECONNRESET)
#define ECONNRESET WSAECONNRESET
#endif
#if !defined(ECONNREFUSED)
#define ECONNREFUSED WSAECONNREFUSED
#endif
#if !defined(ETIMEDOUT)
#define ETIMEDOUT WSAETIMEDOUT
#endif
#if !defined(ENOPROTOOPT)
#define ENOPROTOOPT WSAENOPROTOOPT
#endif
#if !defined(EINPROGRESS)
#define EINPROGRESS WSAEINPROGRESS
#endif
#endif
#define MODBUS_TCP_DEFAULT_PORT 502
#define MODBUS_TCP_SLAVE 0xFF
/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5
* TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes
*/
#define MODBUS_TCP_MAX_ADU_LENGTH 260
#ifdef ARDUINO
#ifdef __NEED_NAMESPACE__
MODBUS_API modbus_t* modbus_new_tcp(arduino::Client* client, arduino::IPAddress ip_address, int port);
MODBUS_API int modbus_tcp_accept(modbus_t *ctx, arduino::Client* client);
#else
MODBUS_API modbus_t* modbus_new_tcp(Client* client, IPAddress ip_address, int port);
MODBUS_API int modbus_tcp_accept(modbus_t *ctx, Client* client);
#endif
MODBUS_API int modbus_tcp_listen(modbus_t *ctx);
#else
MODBUS_API modbus_t* modbus_new_tcp(const char *ip_address, int port);
MODBUS_API int modbus_tcp_listen(modbus_t *ctx, int nb_connection);
MODBUS_API int modbus_tcp_accept(modbus_t *ctx, int *s);
MODBUS_API modbus_t* modbus_new_tcp_pi(const char *node, const char *service);
MODBUS_API int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection);
MODBUS_API int modbus_tcp_pi_accept(modbus_t *ctx, int *s);
#endif
MODBUS_END_DECLS
#endif /* MODBUS_TCP_H */

View File

@ -0,0 +1,53 @@
/*
* Copyright © 2010-2014 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MODBUS_VERSION_H
#define MODBUS_VERSION_H
/* The major version, (1, if %LIBMODBUS_VERSION is 1.2.3) */
#define LIBMODBUS_VERSION_MAJOR (3)
/* The minor version (2, if %LIBMODBUS_VERSION is 1.2.3) */
#define LIBMODBUS_VERSION_MINOR (1)
/* The micro version (3, if %LIBMODBUS_VERSION is 1.2.3) */
#define LIBMODBUS_VERSION_MICRO (4)
/* The full version, like 1.2.3 */
#define LIBMODBUS_VERSION 3.1.4
/* The full version, in string form (suited for string concatenation)
*/
#define LIBMODBUS_VERSION_STRING "3.1.4"
/* Numerically encoded version, eg. v1.2.3 is 0x010203 */
#define LIBMODBUS_VERSION_HEX ((LIBMODBUS_VERSION_MAJOR << 16) | \
(LIBMODBUS_VERSION_MINOR << 8) | \
(LIBMODBUS_VERSION_MICRO << 0))
/* Evaluates to True if the version is greater than @major, @minor and @micro
*/
#define LIBMODBUS_VERSION_CHECK(major,minor,micro) \
(LIBMODBUS_VERSION_MAJOR > (major) || \
(LIBMODBUS_VERSION_MAJOR == (major) && \
LIBMODBUS_VERSION_MINOR > (minor)) || \
(LIBMODBUS_VERSION_MAJOR == (major) && \
LIBMODBUS_VERSION_MINOR == (minor) && \
LIBMODBUS_VERSION_MICRO >= (micro)))
#endif /* MODBUS_VERSION_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,289 @@
/*
* Copyright © 2001-2013 Stéphane Raimbault <stephane.raimbault@gmail.com>
* Copyright © 2018 Arduino SA. All rights reserved.
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_H
#define MODBUS_H
/* Add this for macros that defined unix flavor */
#if (defined(__unix__) || defined(unix)) && !defined(USG)
#include <sys/param.h>
#endif
#ifndef _MSC_VER
#include <stdint.h>
#else
#include "stdint.h"
#endif
#include "modbus-version.h"
#if defined(_MSC_VER)
# if defined(DLLBUILD)
/* define DLLBUILD when building the DLL */
# define MODBUS_API __declspec(dllexport)
# else
# define MODBUS_API __declspec(dllimport)
# endif
#else
# define MODBUS_API
#endif
#ifdef __cplusplus
# define MODBUS_BEGIN_DECLS extern "C" {
# define MODBUS_END_DECLS }
#else
# define MODBUS_BEGIN_DECLS
# define MODBUS_END_DECLS
#endif
MODBUS_BEGIN_DECLS
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
/* Modbus function codes */
#define MODBUS_FC_READ_COILS 0x01
#define MODBUS_FC_READ_DISCRETE_INPUTS 0x02
#define MODBUS_FC_READ_HOLDING_REGISTERS 0x03
#define MODBUS_FC_READ_INPUT_REGISTERS 0x04
#define MODBUS_FC_WRITE_SINGLE_COIL 0x05
#define MODBUS_FC_WRITE_SINGLE_REGISTER 0x06
#define MODBUS_FC_READ_EXCEPTION_STATUS 0x07
#define MODBUS_FC_WRITE_MULTIPLE_COILS 0x0F
#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
#define MODBUS_FC_REPORT_SLAVE_ID 0x11
#define MODBUS_FC_MASK_WRITE_REGISTER 0x16
#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
#define MODBUS_BROADCAST_ADDRESS 0
/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12)
* Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0)
* (chapter 6 section 11 page 29)
* Quantity of Coils to write (2 bytes): 1 to 1968 (0x7B0)
*/
#define MODBUS_MAX_READ_BITS 2000
#define MODBUS_MAX_WRITE_BITS 1968
/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 3 page 15)
* Quantity of Registers to read (2 bytes): 1 to 125 (0x7D)
* (chapter 6 section 12 page 31)
* Quantity of Registers to write (2 bytes) 1 to 123 (0x7B)
* (chapter 6 section 17 page 38)
* Quantity of Registers to write in R/W registers (2 bytes) 1 to 121 (0x79)
*/
#define MODBUS_MAX_READ_REGISTERS 125
#define MODBUS_MAX_WRITE_REGISTERS 123
#define MODBUS_MAX_WR_WRITE_REGISTERS 121
#define MODBUS_MAX_WR_READ_REGISTERS 125
/* The size of the MODBUS PDU is limited by the size constraint inherited from
* the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256
* bytes). Therefore, MODBUS PDU for serial line communication = 256 - Server
* address (1 byte) - CRC (2 bytes) = 253 bytes.
*/
#define MODBUS_MAX_PDU_LENGTH 253
/* Consequently:
* - RTU MODBUS ADU = 253 bytes + Server address (1 byte) + CRC (2 bytes) = 256
* bytes.
* - TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes.
* so the maximum of both backend in 260 bytes. This size can used to allocate
* an array of bytes to store responses and it will be compatible with the two
* backends.
*/
#define MODBUS_MAX_ADU_LENGTH 260
/* Random number to avoid errno conflicts */
#if defined(ARDUINO) && defined(__AVR__)
#define MODBUS_ENOBASE 11234
#else
#define MODBUS_ENOBASE 112345678
#endif
/* Protocol exceptions */
enum {
MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01,
MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,
MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE,
MODBUS_EXCEPTION_ACKNOWLEDGE,
MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY,
MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE,
MODBUS_EXCEPTION_MEMORY_PARITY,
MODBUS_EXCEPTION_NOT_DEFINED,
MODBUS_EXCEPTION_GATEWAY_PATH,
MODBUS_EXCEPTION_GATEWAY_TARGET,
MODBUS_EXCEPTION_MAX
};
#define EMBXILFUN (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION)
#define EMBXILADD (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS)
#define EMBXILVAL (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE)
#define EMBXSFAIL (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE)
#define EMBXACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_ACKNOWLEDGE)
#define EMBXSBUSY (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY)
#define EMBXNACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE)
#define EMBXMEMPAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_MEMORY_PARITY)
#define EMBXGPATH (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_PATH)
#define EMBXGTAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET)
/* Native libmodbus error codes */
#define EMBBADCRC (EMBXGTAR + 1)
#define EMBBADDATA (EMBXGTAR + 2)
#define EMBBADEXC (EMBXGTAR + 3)
#define EMBUNKEXC (EMBXGTAR + 4)
#define EMBMDATA (EMBXGTAR + 5)
#define EMBBADSLAVE (EMBXGTAR + 6)
extern const unsigned int libmodbus_version_major;
extern const unsigned int libmodbus_version_minor;
extern const unsigned int libmodbus_version_micro;
typedef struct _modbus modbus_t;
typedef struct {
int nb_bits;
int start_bits;
int nb_input_bits;
int start_input_bits;
int nb_input_registers;
int start_input_registers;
int nb_registers;
int start_registers;
uint8_t *tab_bits;
uint8_t *tab_input_bits;
uint16_t *tab_input_registers;
uint16_t *tab_registers;
} modbus_mapping_t;
typedef enum
{
MODBUS_ERROR_RECOVERY_NONE = 0,
MODBUS_ERROR_RECOVERY_LINK = (1<<1),
MODBUS_ERROR_RECOVERY_PROTOCOL = (1<<2)
} modbus_error_recovery_mode;
MODBUS_API int modbus_set_slave(modbus_t* ctx, int slave);
MODBUS_API int modbus_set_error_recovery(modbus_t *ctx, modbus_error_recovery_mode error_recovery);
MODBUS_API int modbus_set_socket(modbus_t *ctx, int s);
MODBUS_API int modbus_get_socket(modbus_t *ctx);
MODBUS_API int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
MODBUS_API int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
MODBUS_API int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
MODBUS_API int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
MODBUS_API int modbus_get_header_length(modbus_t *ctx);
MODBUS_API int modbus_connect(modbus_t *ctx);
MODBUS_API void modbus_close(modbus_t *ctx);
MODBUS_API void modbus_free(modbus_t *ctx);
MODBUS_API int modbus_flush(modbus_t *ctx);
MODBUS_API int modbus_set_debug(modbus_t *ctx, int flag);
MODBUS_API const char *modbus_strerror(int errnum);
MODBUS_API int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
MODBUS_API int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
MODBUS_API int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
MODBUS_API int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
MODBUS_API int modbus_write_bit(modbus_t *ctx, int coil_addr, int status);
MODBUS_API int modbus_write_register(modbus_t *ctx, int reg_addr, int value);
MODBUS_API int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data);
MODBUS_API int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data);
MODBUS_API int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask);
MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb,
const uint16_t *src, int read_addr, int read_nb,
uint16_t *dest);
MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest);
MODBUS_API modbus_mapping_t* modbus_mapping_new_start_address(
unsigned int start_bits, unsigned int nb_bits,
unsigned int start_input_bits, unsigned int nb_input_bits,
unsigned int start_registers, unsigned int nb_registers,
unsigned int start_input_registers, unsigned int nb_input_registers);
MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
int nb_registers, int nb_input_registers);
MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping);
MODBUS_API int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length);
MODBUS_API int modbus_receive(modbus_t *ctx, uint8_t *req);
MODBUS_API int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp);
MODBUS_API int modbus_reply(modbus_t *ctx, const uint8_t *req,
int req_length, modbus_mapping_t *mb_mapping);
MODBUS_API int modbus_reply_exception(modbus_t *ctx, const uint8_t *req,
unsigned int exception_code);
/**
* UTILS FUNCTIONS
**/
#define MODBUS_GET_HIGH_BYTE(data) (((data) >> 8) & 0xFF)
#define MODBUS_GET_LOW_BYTE(data) ((data) & 0xFF)
#define MODBUS_GET_INT64_FROM_INT16(tab_int16, index) \
(((int64_t)tab_int16[(index) ] << 48) + \
((int64_t)tab_int16[(index) + 1] << 32) + \
((int64_t)tab_int16[(index) + 2] << 16) + \
(int64_t)tab_int16[(index) + 3])
#define MODBUS_GET_INT32_FROM_INT16(tab_int16, index) ((tab_int16[(index)] << 16) + tab_int16[(index) + 1])
#define MODBUS_GET_INT16_FROM_INT8(tab_int8, index) ((tab_int8[(index)] << 8) + tab_int8[(index) + 1])
#define MODBUS_SET_INT16_TO_INT8(tab_int8, index, value) \
do { \
tab_int8[(index)] = (value) >> 8; \
tab_int8[(index) + 1] = (value) & 0xFF; \
} while (0)
#define MODBUS_SET_INT32_TO_INT16(tab_int16, index, value) \
do { \
tab_int16[(index) ] = (value) >> 16; \
tab_int16[(index) + 1] = (value); \
} while (0)
#define MODBUS_SET_INT64_TO_INT16(tab_int16, index, value) \
do { \
tab_int16[(index) ] = (value) >> 48; \
tab_int16[(index) + 1] = (value) >> 32; \
tab_int16[(index) + 2] = (value) >> 16; \
tab_int16[(index) + 3] = (value); \
} while (0)
MODBUS_API void modbus_set_bits_from_byte(uint8_t *dest, int idx, const uint8_t value);
MODBUS_API void modbus_set_bits_from_bytes(uint8_t *dest, int idx, unsigned int nb_bits,
const uint8_t *tab_byte);
MODBUS_API uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx, unsigned int nb_bits);
MODBUS_API float modbus_get_float(const uint16_t *src);
MODBUS_API float modbus_get_float_abcd(const uint16_t *src);
MODBUS_API float modbus_get_float_dcba(const uint16_t *src);
MODBUS_API float modbus_get_float_badc(const uint16_t *src);
MODBUS_API float modbus_get_float_cdab(const uint16_t *src);
MODBUS_API void modbus_set_float(float f, uint16_t *dest);
MODBUS_API void modbus_set_float_abcd(float f, uint16_t *dest);
MODBUS_API void modbus_set_float_dcba(float f, uint16_t *dest);
MODBUS_API void modbus_set_float_badc(float f, uint16_t *dest);
MODBUS_API void modbus_set_float_cdab(float f, uint16_t *dest);
#ifndef ARDUINO
#include "modbus-tcp.h"
#include "modbus-rtu.h"
#endif
MODBUS_END_DECLS
#endif /* MODBUS_H */