initial
This commit is contained in:
29
libraries/ArduinoModbus/src/ArduinoModbus.h
Normal file
29
libraries/ArduinoModbus/src/ArduinoModbus.h
Normal 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
|
424
libraries/ArduinoModbus/src/ModbusClient.cpp
Normal file
424
libraries/ArduinoModbus/src/ModbusClient.cpp
Normal 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);
|
||||
}
|
||||
}
|
230
libraries/ArduinoModbus/src/ModbusClient.h
Normal file
230
libraries/ArduinoModbus/src/ModbusClient.h
Normal 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
|
60
libraries/ArduinoModbus/src/ModbusRTUClient.cpp
Normal file
60
libraries/ArduinoModbus/src/ModbusRTUClient.cpp
Normal 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;
|
49
libraries/ArduinoModbus/src/ModbusRTUClient.h
Normal file
49
libraries/ArduinoModbus/src/ModbusRTUClient.h
Normal 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
|
73
libraries/ArduinoModbus/src/ModbusRTUServer.cpp
Normal file
73
libraries/ArduinoModbus/src/ModbusRTUServer.cpp
Normal 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;
|
55
libraries/ArduinoModbus/src/ModbusRTUServer.h
Normal file
55
libraries/ArduinoModbus/src/ModbusRTUServer.h
Normal 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
|
329
libraries/ArduinoModbus/src/ModbusServer.cpp
Normal file
329
libraries/ArduinoModbus/src/ModbusServer.cpp
Normal 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;
|
||||
}
|
||||
}
|
150
libraries/ArduinoModbus/src/ModbusServer.h
Normal file
150
libraries/ArduinoModbus/src/ModbusServer.h
Normal 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
|
54
libraries/ArduinoModbus/src/ModbusTCPClient.cpp
Normal file
54
libraries/ArduinoModbus/src/ModbusTCPClient.cpp
Normal 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();
|
||||
}
|
64
libraries/ArduinoModbus/src/ModbusTCPClient.h
Normal file
64
libraries/ArduinoModbus/src/ModbusTCPClient.h
Normal 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
|
73
libraries/ArduinoModbus/src/ModbusTCPServer.cpp
Normal file
73
libraries/ArduinoModbus/src/ModbusTCPServer.cpp
Normal 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;
|
||||
}
|
57
libraries/ArduinoModbus/src/ModbusTCPServer.h
Normal file
57
libraries/ArduinoModbus/src/ModbusTCPServer.h
Normal 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
|
252
libraries/ArduinoModbus/src/libmodbus/modbus-data.c
Normal file
252
libraries/ArduinoModbus/src/libmodbus/modbus-data.c
Normal 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);
|
||||
}
|
129
libraries/ArduinoModbus/src/libmodbus/modbus-private.h
Normal file
129
libraries/ArduinoModbus/src/libmodbus/modbus-private.h
Normal 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 */
|
85
libraries/ArduinoModbus/src/libmodbus/modbus-rtu-private.h
Normal file
85
libraries/ArduinoModbus/src/libmodbus/modbus-rtu-private.h
Normal 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 */
|
1409
libraries/ArduinoModbus/src/libmodbus/modbus-rtu.cpp
Normal file
1409
libraries/ArduinoModbus/src/libmodbus/modbus-rtu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
48
libraries/ArduinoModbus/src/libmodbus/modbus-rtu.h
Normal file
48
libraries/ArduinoModbus/src/libmodbus/modbus-rtu.h
Normal 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 */
|
56
libraries/ArduinoModbus/src/libmodbus/modbus-tcp-private.h
Normal file
56
libraries/ArduinoModbus/src/libmodbus/modbus-tcp-private.h
Normal 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 */
|
1061
libraries/ArduinoModbus/src/libmodbus/modbus-tcp.cpp
Normal file
1061
libraries/ArduinoModbus/src/libmodbus/modbus-tcp.cpp
Normal file
File diff suppressed because it is too large
Load Diff
79
libraries/ArduinoModbus/src/libmodbus/modbus-tcp.h
Normal file
79
libraries/ArduinoModbus/src/libmodbus/modbus-tcp.h
Normal 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 */
|
53
libraries/ArduinoModbus/src/libmodbus/modbus-version.h
Normal file
53
libraries/ArduinoModbus/src/libmodbus/modbus-version.h
Normal 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 */
|
1927
libraries/ArduinoModbus/src/libmodbus/modbus.c
Normal file
1927
libraries/ArduinoModbus/src/libmodbus/modbus.c
Normal file
File diff suppressed because it is too large
Load Diff
289
libraries/ArduinoModbus/src/libmodbus/modbus.h
Normal file
289
libraries/ArduinoModbus/src/libmodbus/modbus.h
Normal 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 */
|
Reference in New Issue
Block a user