ModbusRTUClient.holdingRegisterWrite -> Invalid argument
o7-machinehum opened this issue · 1 comments
I create the SensorO2 object and then call check() which works great. But then when I call powerOn(), which calls write16 holdingRegisterWrite is erroring out, as _modbusRtuClient.lastError() is returning: [O2] ModbusRTUClient.write Failed: Invalid argument
I've included my .cpp/.h below. Any help or ideas would be very appreciated. I've also tried without the _modbusRtuClient.setTimeout(3000);
Here is the device: https://www.processsensing.com/docs/userguide/UG-004_OXY-LC-User-Guide.pdf
SENSOR_SST_O2_ADDRESS is set to 0x01
If I uncomment out all the code in write16 (using .beginTransmission, .write etc...) and comment out the code that does holdingRegisterWrite I get [O2] ModbusRTUClient.write Failed: Connection timed out I find it stange the read works fine but the write has issues.
Any help is very much appreciated :)
#include "SensorO2.h"
SensorO2::SensorO2(RS485Class* rs485) : _rs485(rs485)
{
init();
};
SensorO2::~SensorO2() {
_modbusRtuClient.end();
}
void SensorO2::init()
{
Serial.printf("pre/post delay: %d, %d\n\r", (int)PRE_DELAY_BR, (int)POST_DELAY_BR);
_rs485->setDelays(
static_cast<int>(PRE_DELAY_BR), static_cast<int>(POST_DELAY_BR)
);
if (_modbusRtuClient.begin(
*_rs485, board::SENSE_MODULE_MODBUS_BUADRATE, SERIAL_8N1
)) {
_available = true;
}
_modbusRtuClient.setTimeout(3000);
}
bool SensorO2::check()
{
uint16_t sn = read16(REGISTER_O2_SN);
if(sn) {
Serial.printf("[O2] Connected to Sensor. SN: %d\n\r", sn);
return true;
}
return false;
}
bool SensorO2::available() { return _available; }
uint8_t SensorO2::getRegtype(uint16_t reg) {
if(reg > 0x7546) {
return HOLDING_REGISTERS;
}
return INPUT_REGISTERS;
}
const uint16_t SensorO2::read16(uint16_t reg) {
uint8_t regtype = getRegtype(reg);
if (!_modbusRtuClient.requestFrom(
board::SENSOR_SST_O2_ADDRESS,
regtype,
reg,
1
)) {
Serial.printf("[O2] Failed to read registers!: %s\n\r", _modbusRtuClient.lastError());
return 0;
}
return(_modbusRtuClient.read());
}
void SensorO2::write16(int reg, uint16_t val) {
uint8_t regtype = getRegtype(reg);
// if (!_modbusRtuClient.beginTransmission(
// board::SENSOR_SST_O2_ADDRESS,
// regtype,
// reg,
// 1
// )) {
// Serial.printf("[O2] modbusRtuClient.beginTransmission Failed: %s\n\r", _modbusRtuClient.lastError());
// return;
// }
// if(!ModbusRTUClient.write(val)){
// Serial.printf("[O2] ModbusRTUClient.write Failed: %s\n\r", _modbusRtuClient.lastError());
// return;
// }
if(!ModbusRTUClient.holdingRegisterWrite(0x01, 0x9C41, 0x01)){
Serial.printf("[O2] ModbusRTUClient.write Failed: %s\n\r", _modbusRtuClient.lastError());
return;
}
// if (!ModbusRTUClient.endTransmission()) {
// Serial.printf("[O2] ModbusRTUClient.endTransmission: %s\n\r", _modbusRtuClient.lastError());
// return;
// }
}
void SensorO2::powerOn() {
Serial.print("[O2] Powering On Sensor\n\r");
write16(SENSOR_ON, 0x01);
Serial.printf("[O2] Powering On :%d, %d\n\r", read16(SENSOR_ON), read16(0x9C42));
}#pragma once
#include <Arduino.h>
#include <ArduinoModbus.h>
#include <ArduinoRS485.h>
#include <stdint.h>
#include "Board.h"
// https://www.processsensing.com/docs/userguide/UG-004_OXY-LC-User-Guide.pdf
class SensorO2 final
{
public:
SensorO2(RS485Class* rs485);
~SensorO2();
void init();
void powerOn();
bool check();
bool available();
float readO2();
private:
bool _available = false;
RS485Class* _rs485;
ModbusRTUClientClass _modbusRtuClient;
float readFloat(uint16_t registerAddress);
const uint16_t read16(uint16_t reg);
void write16(int reg, uint16_t val);
uint8_t getRegtype(uint16_t reg);
// Input Registers
static constexpr uint16_t REGISTER_O2_AVERAGE_FLOAT = 0x7531; // in %
static constexpr uint16_t REGISTER_O2_SN = 0x7545;
// Holding Registers
static constexpr int SENSOR_ON = 0x9C41;
// Calculate preDelay and postDelay in microseconds as per Modbus RTU
// Specification
//
// MODBUS over serial line specification and implementation guide V1.02
// Paragraph 2.5.1.1 MODBUS Message RTU Framing
// https://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf
static constexpr float BIT_DURATION{
1.f / board::SENSE_MODULE_MODBUS_BUADRATE
};
static constexpr float WORDLENGTH{9.6f}; // try also with 10.0f
static constexpr float PRE_DELAY_BR{
BIT_DURATION * WORDLENGTH * 3.5f * 1e6
};
static constexpr float POST_DELAY_BR{
BIT_DURATION * WORDLENGTH * 3.5f * 1e6
};
};Derpppp it can be seen I was using ModbusRTUClient., rather than the object I created.