9static const char *
const TAG =
"modbus";
12static constexpr size_t MODBUS_MAX_LOG_BYTES = 64;
26 size_t to_read = std::min(avail,
sizeof(buf));
32 for (
size_t i = 0; i < to_read; i++) {
38 ESP_LOGV(TAG,
"Clearing buffer of %d bytes - parse failed", at);
48 ESP_LOGV(TAG,
"Clearing buffer of %d bytes - timeout", at);
66 ESP_LOGVV(TAG,
"Modbus received Byte %d (0X%x)",
byte,
byte);
71 uint8_t function_code =
raw[1];
77 uint8_t data_len =
raw[2];
78 uint8_t data_offset = 3;
98 uint16_t computed_crc =
crc16(
raw, data_offset + data_len);
99 uint16_t remote_crc = uint16_t(
raw[data_offset + data_len]) | (uint16_t(
raw[data_offset + data_len + 1]) << 8);
101 if (computed_crc != remote_crc)
104 ESP_LOGD(TAG,
"Modbus user-defined function %02X found", function_code);
122 data_len = 2 + 2 + 1 +
raw[6];
143 if (at < data_offset + data_len)
147 if (at == data_offset + data_len)
151 uint16_t computed_crc =
crc16(
raw, data_offset + data_len);
152 uint16_t remote_crc = uint16_t(
raw[data_offset + data_len]) | (uint16_t(
raw[data_offset + data_len + 1]) << 8);
153 if (computed_crc != remote_crc) {
155 ESP_LOGD(TAG,
"Modbus CRC Check failed, but ignored! %02X!=%02X", computed_crc, remote_crc);
157 ESP_LOGW(TAG,
"Modbus CRC Check failed! %02X!=%02X", computed_crc, remote_crc);
162 std::vector<uint8_t> data(this->
rx_buffer_.begin() + data_offset, this->rx_buffer_.begin() + data_offset + data_len);
164 for (
auto *device : this->
devices_) {
165 if (device->address_ ==
address) {
169 ESP_LOGD(TAG,
"Modbus error function code: 0x%X exception: %d", function_code,
raw[2]);
174 ESP_LOGD(TAG,
"Ignoring Modbus error - not expecting a response");
181 device->on_modbus_read_registers(function_code, uint16_t(data[1]) | (uint16_t(data[0]) << 8),
182 uint16_t(data[3]) | (uint16_t(data[2]) << 8));
187 device->on_modbus_write_registers(function_code, data);
192 device->on_modbus_data(data);
198 ESP_LOGW(TAG,
"Got Modbus frame from unknown address 0x%02X! ",
address);
202 ESP_LOGV(TAG,
"Clearing buffer of %d bytes - parse succeeded", at);
210 " Send Wait Time: %d ms\n"
220void Modbus::send(uint8_t
address, uint8_t function_code, uint16_t start_address, uint16_t number_of_entities,
221 uint8_t payload_len,
const uint8_t *payload) {
222 static const size_t MAX_VALUES = 128;
227 ESP_LOGE(TAG,
"send too many values %d max=%zu", number_of_entities, MAX_VALUES);
231 static constexpr size_t ADDR_SIZE = 1;
232 static constexpr size_t FC_SIZE = 1;
233 static constexpr size_t START_ADDR_SIZE = 2;
234 static constexpr size_t NUM_ENTITIES_SIZE = 2;
235 static constexpr size_t BYTE_COUNT_SIZE = 1;
236 static constexpr size_t MAX_PAYLOAD_SIZE = std::numeric_limits<uint8_t>::max();
237 static constexpr size_t CRC_SIZE = 2;
238 static constexpr size_t MAX_FRAME_SIZE =
239 ADDR_SIZE + FC_SIZE + START_ADDR_SIZE + NUM_ENTITIES_SIZE + BYTE_COUNT_SIZE + MAX_PAYLOAD_SIZE + CRC_SIZE;
240 uint8_t data[MAX_FRAME_SIZE];
244 data[
pos++] = function_code;
246 data[
pos++] = start_address >> 8;
247 data[
pos++] = start_address >> 0;
250 data[
pos++] = number_of_entities >> 8;
251 data[
pos++] = number_of_entities >> 0;
255 if (payload !=
nullptr) {
258 data[
pos++] = payload_len;
262 for (
int i = 0; i < payload_len; i++) {
263 data[
pos++] = payload[i];
268 data[
pos++] = crc >> 0;
269 data[
pos++] = crc >> 8;
281#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
290 if (payload.empty()) {
297 auto crc =
crc16(payload.data(), payload.size());
305#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
308 ESP_LOGV(TAG,
"Modbus write raw: %s",
format_hex_pretty_to(hex_buf, payload.data(), payload.size()));
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
virtual void digital_write(bool value)=0
bool parse_modbus_byte_(uint8_t byte)
void send_raw(const std::vector< uint8_t > &payload)
uint8_t waiting_for_response
uint32_t last_modbus_byte_
GPIOPin * flow_control_pin_
std::vector< ModbusDevice * > devices_
float get_setup_priority() const override
void dump_config() override
std::vector< uint8_t > rx_buffer_
void send(uint8_t address, uint8_t function_code, uint16_t start_address, uint16_t number_of_entities, uint8_t payload_len=0, const uint8_t *payload=nullptr)
optional< std::array< uint8_t, N > > read_array()
void write_byte(uint8_t data)
void write_array(const uint8_t *data, size_t len)
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
const float BUS
For communication buses like i2c/spi.
Providing packet encoding functions for exchanging data with a remote host.
uint16_t crc16(const uint8_t *data, uint16_t len, uint16_t crc, uint16_t reverse_poly, bool refin, bool refout)
Calculate a CRC-16 checksum of data with size len.
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
constexpr size_t format_hex_pretty_size(size_t byte_count)
Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0".
uint32_t IRAM_ATTR HOT millis()
Application App
Global storage of Application pointer - only one Application can exist.