36inline uint16_t
Crc16(
const uint8_t* data, std::size_t length)
noexcept {
37 uint16_t crc = 0xFFFF;
38 for (std::size_t i = 0; i < length; ++i) {
39 crc ^=
static_cast<uint16_t
>(data[i]);
40 for (uint8_t b = 0; b < 8; ++b) {
42 crc =
static_cast<uint16_t
>((crc >> 1) ^ 0xA001U);
52inline std::size_t
AppendCrc(uint8_t* frame, std::size_t length)
noexcept {
53 const uint16_t crc =
Crc16(frame, length);
54 frame[length] =
static_cast<uint8_t
>(crc & 0x00FFU);
55 frame[length + 1] =
static_cast<uint8_t
>((crc >> 8) & 0x00FFU);
60inline bool CheckCrc(
const uint8_t* frame, std::size_t length)
noexcept {
61 if (length < 4)
return false;
62 const uint16_t want =
Crc16(frame, length - 2);
63 const uint16_t got =
static_cast<uint16_t
>(frame[length - 2]) |
64 (
static_cast<uint16_t
>(frame[length - 1]) << 8);
77 uint8_t* out, std::size_t out_capacity)
noexcept {
78 if (out_capacity < 8)
return 0;
81 out[2] =
static_cast<uint8_t
>((reg_addr >> 8) & 0xFFU);
82 out[3] =
static_cast<uint8_t
>(reg_addr & 0xFFU);
83 out[4] =
static_cast<uint8_t
>((reg_count >> 8) & 0xFFU);
84 out[5] =
static_cast<uint8_t
>(reg_count & 0xFFU);
92 uint8_t* out, std::size_t out_capacity)
noexcept {
93 if (out_capacity < 8)
return 0;
96 out[2] =
static_cast<uint8_t
>((reg_addr >> 8) & 0xFFU);
97 out[3] =
static_cast<uint8_t
>(reg_addr & 0xFFU);
98 out[4] =
static_cast<uint8_t
>((value >> 8) & 0xFFU);
99 out[5] =
static_cast<uint8_t
>(value & 0xFFU);
107 const uint16_t* regs, uint8_t count,
108 uint8_t* out, std::size_t out_capacity)
noexcept {
109 const std::size_t needed = 9 + count * 2;
110 if (count == 0 || out_capacity < needed)
return 0;
113 out[2] =
static_cast<uint8_t
>((reg_addr >> 8) & 0xFFU);
114 out[3] =
static_cast<uint8_t
>(reg_addr & 0xFFU);
115 out[4] =
static_cast<uint8_t
>((count >> 8) & 0xFFU);
116 out[5] =
static_cast<uint8_t
>(count & 0xFFU);
117 out[6] =
static_cast<uint8_t
>(count * 2);
118 for (uint8_t i = 0; i < count; ++i) {
119 out[7 + i * 2] =
static_cast<uint8_t
>((regs[i] >> 8) & 0xFFU);
120 out[7 + i * 2 + 1] =
static_cast<uint8_t
>(regs[i] & 0xFFU);
152 return (kNumerator + bps - 1U) / bps;
184 uint8_t expected_fn, uint8_t* code)
noexcept {
189 if (frame[0] != expected_addr)
201 uint8_t expected_addr, uint8_t expected_count,
202 uint16_t* regs)
noexcept {
208 const std::size_t byte_count = frame[2];
211 for (uint8_t i = 0; i < expected_count; ++i) {
212 regs[i] = (
static_cast<uint16_t
>(frame[3 + i * 2]) << 8) |
213 static_cast<uint16_t
>(frame[3 + i * 2 + 1]);
221 const uint8_t* request, std::size_t req_len)
noexcept {
226 for (std::size_t i = 0; i < req_len; ++i) {
234 uint8_t expected_addr,
235 uint16_t expected_reg_addr,
236 uint16_t expected_count)
noexcept {
242 const uint16_t got_addr = (
static_cast<uint16_t
>(frame[2]) << 8) | frame[3];
243 const uint16_t got_cnt = (
static_cast<uint16_t
>(frame[4]) << 8) | frame[5];
Modbus-RTU holding-register addresses for Alicat BASIS-2.
Public type definitions for the Alicat BASIS-2 driver.
bool CheckCrc(const uint8_t *frame, std::size_t length) noexcept
Verify the CRC at frame[length-2..length-1] matches the body.
Definition alicat_basis2_modbus.hpp:60
constexpr uint32_t InterFrameGapUs(uint32_t bps) noexcept
Minimum idle time t3.5 between two Modbus-RTU frames, in microseconds.
Definition alicat_basis2_modbus.hpp:145
constexpr uint32_t kFixedGapUs
The fixed t3.5 used above 19200 baud, in microseconds.
Definition alicat_basis2_modbus.hpp:136
bool IsExceptionReply(const uint8_t *frame, std::size_t length) noexcept
Definition alicat_basis2_modbus.hpp:168
std::size_t BuildWriteMultiple(uint8_t unit_addr, uint16_t reg_addr, const uint16_t *regs, uint8_t count, uint8_t *out, std::size_t out_capacity) noexcept
Build a Function-16 (Write Multiple Registers) request.
Definition alicat_basis2_modbus.hpp:105
DriverError ParseReadHolding(const uint8_t *frame, std::size_t length, uint8_t expected_addr, uint8_t expected_count, uint16_t *regs) noexcept
Parse a Function-03 response into regs[].
Definition alicat_basis2_modbus.hpp:200
uint16_t Crc16(const uint8_t *data, std::size_t length) noexcept
Compute the Modbus-RTU CRC-16 over a byte buffer.
Definition alicat_basis2_modbus.hpp:36
DriverError ParseWriteSingleEcho(const uint8_t *frame, std::size_t length, const uint8_t *request, std::size_t req_len) noexcept
Validate the echo of a Function-06 (Write Single) request against the just-sent request.
Definition alicat_basis2_modbus.hpp:220
std::size_t BuildReadHolding(uint8_t unit_addr, uint16_t reg_addr, uint16_t reg_count, uint8_t *out, std::size_t out_capacity) noexcept
Build a Function-03 (Read Holding Registers) request.
Definition alicat_basis2_modbus.hpp:74
std::size_t BuildWriteSingle(uint8_t unit_addr, uint16_t reg_addr, uint16_t value, uint8_t *out, std::size_t out_capacity) noexcept
Build a Function-06 (Write Single Register) request.
Definition alicat_basis2_modbus.hpp:89
constexpr uint32_t InterFrameGapMs(uint32_t bps) noexcept
InterFrameGapUs(bps) rounded up to whole milliseconds (for UartInterface::delay_ms()).
Definition alicat_basis2_modbus.hpp:156
constexpr uint32_t kFixedGapAboveBps
Above this baud rate the spec fixes t3.5 at 1750 us instead of 3.5 character times.
Definition alicat_basis2_modbus.hpp:133
DriverError ParseException(const uint8_t *frame, std::size_t length, uint8_t expected_addr, uint8_t expected_fn, uint8_t *code) noexcept
Parse a 5-byte exception reply (Modbus Application Protocol V1.1b3, section 7).
Definition alicat_basis2_modbus.hpp:183
constexpr uint32_t kRtuBitsPerChar
Bits per RTU character used for the timing: start + 8 data + parity/stop + stop (section 2....
Definition alicat_basis2_modbus.hpp:130
constexpr std::size_t kReplyHeaderLength
Number of reply bytes a receiver reads before it can tell an exception reply (bit 7 of the function c...
Definition alicat_basis2_modbus.hpp:165
DriverError ParseWriteMultipleEcho(const uint8_t *frame, std::size_t length, uint8_t expected_addr, uint16_t expected_reg_addr, uint16_t expected_count) noexcept
Validate the response of a Function-16 (Write Multiple) request.
Definition alicat_basis2_modbus.hpp:233
constexpr std::size_t kExceptionFrameLength
Length of a Modbus-RTU exception reply: address, function | 0x80, exception code, CRC-16.
Definition alicat_basis2_modbus.hpp:161
std::size_t AppendCrc(uint8_t *frame, std::size_t length) noexcept
Append the CRC-16 to frame[length..length+1] and return new length.
Definition alicat_basis2_modbus.hpp:52
constexpr uint8_t ReadHolding
Definition alicat_basis2_registers.hpp:99
constexpr uint8_t WriteMultiple
Definition alicat_basis2_registers.hpp:101
constexpr uint8_t ExceptionMask
Definition alicat_basis2_registers.hpp:102
constexpr uint8_t WriteSingle
Definition alicat_basis2_registers.hpp:100
Definition alicat_basis2.hpp:52
DriverError
Driver-level error codes.
Definition alicat_basis2_types.hpp:39
@ InvalidFrame
Frame too short, wrong function code, etc.
@ BadCrc
CRC-16 mismatch on received Modbus frame.
@ None
Operation succeeded.
@ ResponseMismatch
Echo doesn't match request (function 6/16).
@ ModbusException
Slave returned a Modbus exception PDU.