initial
This commit is contained in:
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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user