ESPHome 2026.4.0-dev
Loading...
Searching...
No Matches
modbus_helpers.cpp
Go to the documentation of this file.
1#include "modbus_helpers.h"
2#include "esphome/core/log.h"
3
5
6static const char *const TAG = "modbus_helpers";
7
8void number_to_payload(std::vector<uint16_t> &data, int64_t value, SensorValueType value_type) {
9 switch (value_type) {
12 data.push_back(value & 0xFFFF);
13 break;
17 data.push_back((value & 0xFFFF0000) >> 16);
18 data.push_back(value & 0xFFFF);
19 break;
23 data.push_back(value & 0xFFFF);
24 data.push_back((value & 0xFFFF0000) >> 16);
25 break;
28 data.push_back((value & 0xFFFF000000000000) >> 48);
29 data.push_back((value & 0xFFFF00000000) >> 32);
30 data.push_back((value & 0xFFFF0000) >> 16);
31 data.push_back(value & 0xFFFF);
32 break;
35 data.push_back(value & 0xFFFF);
36 data.push_back((value & 0xFFFF0000) >> 16);
37 data.push_back((value & 0xFFFF00000000) >> 32);
38 data.push_back((value & 0xFFFF000000000000) >> 48);
39 break;
40 default:
41 ESP_LOGE(TAG, "Invalid data type for modbus number to payload conversion: %d", static_cast<uint16_t>(value_type));
42 break;
43 }
44}
45
46int64_t payload_to_number(const std::vector<uint8_t> &data, SensorValueType sensor_value_type, uint8_t offset,
47 uint32_t bitmask) {
48 int64_t value = 0; // int64_t because it can hold signed and unsigned 32 bits
49
50 if (offset > data.size()) {
51 ESP_LOGE(TAG, "not enough data for value");
52 return value;
53 }
54
55 size_t size = data.size() - offset;
56 bool error = false;
57 switch (sensor_value_type) {
59 if (size >= 2) {
61 bitmask); // default is 0xFFFF ;
62 } else {
63 error = true;
64 }
65 break;
68 if (size >= 4) {
69 value = get_data<uint32_t>(data, offset);
70 value = mask_and_shift_by_rightbit((uint32_t) value, bitmask);
71 } else {
72 error = true;
73 }
74 break;
77 if (size >= 4) {
78 value = get_data<uint32_t>(data, offset);
79 value = static_cast<uint32_t>(value & 0xFFFF) << 16 | (value & 0xFFFF0000) >> 16;
80 value = mask_and_shift_by_rightbit((uint32_t) value, bitmask);
81 } else {
82 error = true;
83 }
84 break;
86 if (size >= 2) {
88 bitmask); // default is 0xFFFF ;
89 } else {
90 error = true;
91 }
92 break;
94 if (size >= 4) {
95 value = mask_and_shift_by_rightbit(get_data<int32_t>(data, offset), bitmask);
96 } else {
97 error = true;
98 }
99 break;
101 if (size >= 4) {
102 value = get_data<uint32_t>(data, offset);
103 // Currently the high word is at the low position
104 // the sign bit is therefore at low before the switch
105 uint32_t sign_bit = (value & 0x8000) << 16;
107 static_cast<int32_t>(((value & 0x7FFF) << 16 | (value & 0xFFFF0000) >> 16) | sign_bit), bitmask);
108 } else {
109 error = true;
110 }
111 } break;
114 // Ignore bitmask for QWORD
115 if (size >= 8) {
116 value = get_data<uint64_t>(data, offset);
117 } else {
118 error = true;
119 }
120 break;
123 // Ignore bitmask for QWORD
124 if (size >= 8) {
125 uint64_t tmp = get_data<uint64_t>(data, offset);
126 value = (tmp << 48) | (tmp >> 48) | ((tmp & 0xFFFF0000) << 16) | ((tmp >> 16) & 0xFFFF0000);
127 } else {
128 error = true;
129 }
130 } break;
132 default:
133 break;
134 }
135 if (error)
136 ESP_LOGE(TAG, "not enough data for value");
137 return value;
138}
139} // namespace esphome::modbus::helpers
T get_data(const std::vector< uint8_t > &data, size_t buffer_offset)
Extract data from modbus response buffer.
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...
int64_t payload_to_number(const std::vector< uint8_t > &data, SensorValueType sensor_value_type, uint8_t offset, uint32_t bitmask)
Convert vector<uint8_t> response payload to number.
void number_to_payload(std::vector< uint16_t > &data, int64_t value, SensorValueType value_type)
Convert float value to vector<uint16_t> suitable for sending.
size_t size
Definition helpers.h:1082
static void uint32_t