116inline uint8_t
c_to_hex(
char c) {
return (c >=
'A') ? (c >=
'a') ? (c -
'a' + 10) : (c -
'A' + 10) : (c -
'0'); }
127 if (value.length() <
pos * 2 + 2)
169template<
typename T> T
get_data(
const uint8_t *
data,
size_t buffer_offset) {
170 if (
sizeof(T) ==
sizeof(uint8_t)) {
171 return T(
data[buffer_offset]);
173 if (
sizeof(T) ==
sizeof(uint16_t)) {
174 return T((uint16_t(
data[buffer_offset + 0]) << 8) | (uint16_t(
data[buffer_offset + 1]) << 0));
176 if (
sizeof(T) ==
sizeof(
uint32_t)) {
180 if (
sizeof(T) ==
sizeof(uint64_t)) {
184 static_assert(
sizeof(T) ==
sizeof(uint8_t) ||
sizeof(T) ==
sizeof(uint16_t) ||
sizeof(T) ==
sizeof(
uint32_t) ||
185 sizeof(T) ==
sizeof(uint64_t),
186 "Unsupported type size in get_data; only 1, 2, 4, or 8-byte integer types are supported.");
190template<
typename T> T
get_data(
const std::vector<uint8_t> &
data,
size_t buffer_offset) {
203 auto data_byte = bit / 8;
204 return (
data[data_byte] & (1 << (bit % 8))) > 0;
208ESPDEPRECATED(
"Use bit_from_packed() instead. Removed in 2027.2.0",
"2026.8.0")
222 auto result = (mask &
data);
223 if (result == 0 || mask == 0xFFFFFFFF) {
226 for (
size_t pos = 0;
pos <
sizeof(N) << 3;
pos++) {
227 if (
pos < 32 && (mask & (1UL <<
pos)) != 0)
228 return result >>
pos;
240 switch (value_type) {
243 data.push_back(value & 0xFFFF);
248 data.push_back((value & 0xFFFF0000) >> 16);
249 data.push_back(value & 0xFFFF);
254 data.push_back(value & 0xFFFF);
255 data.push_back((value & 0xFFFF0000) >> 16);
259 data.push_back((value & 0xFFFF000000000000) >> 48);
260 data.push_back((value & 0xFFFF00000000) >> 32);
261 data.push_back((value & 0xFFFF0000) >> 16);
262 data.push_back(value & 0xFFFF);
266 data.push_back(value & 0xFFFF);
267 data.push_back((value & 0xFFFF0000) >> 16);
268 data.push_back((value & 0xFFFF00000000) >> 32);
269 data.push_back((value & 0xFFFF000000000000) >> 48);
295ESPDEPRECATED(
"Use the std::span overload returning std::optional<int64_t> instead. Removed in 2027.2.0",
"2026.8.0")
299 return payload_to_number(std::span<const uint8_t>(
data), sensor_value_type, offset, bitmask).value_or(0);
328 uint16_t number_of_entities,
const uint8_t *values =
nullptr,
329 size_t values_len = 0);
337 val = llroundf(value);
340 std::vector<uint16_t>
data;
Minimal static vector - saves memory by avoiding std::vector overhead.
ModbusFunctionCode modbus_register_read_function(ModbusRegisterType reg_type)
bool value_type_is_float(SensorValueType v)
uint8_t server_frame_data_offset(const uint8_t *frame, size_t size)
ModbusFunctionCode modbus_register_write_function(ModbusRegisterType reg_type, bool multiple=false)
uint8_t client_frame_data_offset(const uint8_t *, size_t)
void number_to_payload(Container &data, int64_t value, SensorValueType value_type)
Append the Modbus register words for value to data.
std::span< const uint8_t > data
T get_data(const uint8_t *data, size_t buffer_offset)
Extract data from modbus response buffer.
std::vector< uint16_t > float_to_payload(float value, SensorValueType value_type)
bool is_function_code_read(uint8_t function_code)
bool is_function_code_write(uint8_t function_code)
uint64_t qword_from_hex_str(const std::string &value, uint8_t pos)
Get a qword from a hex string.
uint16_t client_frame_length(const uint8_t *frame, size_t size)
N mask_and_shift_by_rightbit(N data, uint32_t mask)
Extract bits from value and shift right according to the bitmask if the bitmask is 0x00F0 we want the...
uint32_t dword_from_hex_str(const std::string &value, uint8_t pos)
Get a dword from a hex string.
uint8_t byte_from_hex_str(const std::string &value, uint8_t pos)
Get a byte from a hex string byte_from_hex_str("1122", 1) returns uint_8 value 0x22 == 34 byte_from_h...
uint16_t server_frame_length(const uint8_t *frame, size_t size)
void log_unsupported_value_type(SensorValueType value_type)
bool is_function_code_custom(uint8_t function_code)
uint16_t word_from_hex_str(const std::string &value, uint8_t pos)
Get a word from a hex string.
bool bit_from_packed(int bit, std::span< const uint8_t > data)
Extract coil data from modbus response buffer Responses for coil are packed into bytes .
StaticVector< uint8_t, MAX_PDU_SIZE > create_client_pdu(ModbusFunctionCode function_code, uint16_t start_address, uint16_t number_of_entities, const uint8_t *values, size_t values_len)
Create a modbus clinet pdu for reading/writing single/multiple coils/register/inputs.
std::optional< int64_t > registers_to_number(const uint16_t *registers, size_t count, SensorValueType sensor_value_type)
Reconstruct a number from register words (host byte order).
bool is_function_code_exception(uint8_t function_code)
std::optional< int64_t > payload_to_number(const uint8_t *data, size_t size, SensorValueType sensor_value_type, uint8_t offset, uint32_t bitmask)
Convert a raw response payload to a number.
const uint8_t FUNCTION_CODE_MASK
const uint8_t FUNCTION_CODE_EXCEPTION_MASK
@ WRITE_MULTIPLE_REGISTERS
const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_2_INIT
const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_1_INIT
Modbus definitions from specs: https://modbus.org/docs/Modbus_Application_Protocol_V1_1b3....
const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_2_END
const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_1_END
To bit_cast(const From &src)
Convert data between types, without aliasing issues or undefined behaviour.