Files
Eric F d398a6ced2 Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
2026-06-08 00:38:27 -04:00

119 lines
3.8 KiB
C++

// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Pionix GmbH and Contributors to EVerest
/*
This is a tiny and fast modbus RTU implementation
*/
#ifndef TINY_MODBUS_RTU
#define TINY_MODBUS_RTU
#include <chrono>
#include <ostream>
#include <stdexcept>
#include <stdint.h>
#include <termios.h>
#include <everest/gpio/gpio.hpp>
#include <everest/logging.hpp>
namespace tiny_modbus {
constexpr int DEVICE_ADDRESS_POS = 0x00;
constexpr int FUNCTION_CODE_POS = 0x01;
constexpr int REQ_TX_FIRST_REGISTER_ADDR_POS = 0x02;
constexpr int REQ_TX_QUANTITY_POS = 0x04;
constexpr int REQ_TX_SINGLE_REG_PAYLOAD_POS = 0x04;
constexpr int REQ_TX_MULTIPLE_REG_BYTE_COUNT_POS = 0x06;
constexpr int RES_RX_LEN_POS = 0x02;
constexpr int RES_RX_START_OF_PAYLOAD = 0x03;
constexpr int RES_TX_START_OF_PAYLOAD = 0x02;
constexpr int RES_EXCEPTION_CODE = 0x02;
constexpr int MODBUS_MAX_REPLY_SIZE = 255 + 6;
constexpr int MODBUS_MIN_REPLY_SIZE = 5;
constexpr int MODBUS_BASE_PAYLOAD_SIZE = 8;
enum class Parity : uint8_t {
NONE = 0,
ODD = 1,
EVEN = 2
};
enum FunctionCode : uint8_t {
READ_COILS = 0x01,
READ_DISCRETE_INPUTS = 0x02,
READ_MULTIPLE_HOLDING_REGISTERS = 0x03,
READ_INPUT_REGISTERS = 0x04,
WRITE_SINGLE_COIL = 0x05,
WRITE_SINGLE_HOLDING_REGISTER = 0x06,
WRITE_MULTIPLE_COILS = 0x0F,
WRITE_MULTIPLE_HOLDING_REGISTERS = 0x10,
};
std::string FunctionCode_to_string(FunctionCode fc);
std::string FunctionCode_to_string_with_hex(FunctionCode fc);
std::ostream& operator<<(std::ostream& os, const FunctionCode& fc);
class TinyModbusException : public std::runtime_error {
using std::runtime_error::runtime_error;
};
class TimeoutException : public TinyModbusException {
using TinyModbusException::TinyModbusException;
};
class ShortPacketException : public TinyModbusException {
using TinyModbusException::TinyModbusException;
};
class AddressMismatchException : public TinyModbusException {
using TinyModbusException::TinyModbusException;
};
class FunctionCodeMismatchException : public TinyModbusException {
using TinyModbusException::TinyModbusException;
};
class ChecksumErrorException : public TinyModbusException {
using TinyModbusException::TinyModbusException;
};
class IncompletePacketException : public TinyModbusException {
using TinyModbusException::TinyModbusException;
};
class OddByteCountException : public TinyModbusException {
using TinyModbusException::TinyModbusException;
};
class ModbusException : public TinyModbusException {
using TinyModbusException::TinyModbusException;
};
class TinyModbusRTU {
public:
~TinyModbusRTU();
bool open_device(const std::string& device, int baud, bool ignore_echo,
const Everest::GpioSettings& rxtx_gpio_settings, const Parity parity, bool rtscts,
std::chrono::milliseconds initial_timeout, std::chrono::milliseconds within_message_timeout);
std::vector<uint16_t> txrx(uint8_t device_address, FunctionCode function, uint16_t first_register_address,
uint16_t register_quantity, uint16_t chunk_size, bool wait_for_reply = true,
std::vector<uint16_t> request = std::vector<uint16_t>());
private:
// Serial interface
int fd{-1};
bool ignore_echo{false};
std::vector<uint16_t> txrx_impl(uint8_t device_address, FunctionCode function, uint16_t first_register_address,
uint16_t register_quantity, bool wait_for_reply = true,
std::vector<uint16_t> request = std::vector<uint16_t>());
int read_reply(uint8_t* rxbuf, int rxbuf_len);
Everest::Gpio rxtx_gpio;
std::chrono::milliseconds initial_timeout;
std::chrono::milliseconds within_message_timeout;
};
} // namespace tiny_modbus
#endif