#pragma once #include #include #include // Simple Modbus RTU master focused on function 0x03 (Read Holding Registers). // Transport is byte-stream oriented (USB-serial in this project). typedef struct { uint8_t slave_id; bool disable_crc; } modbus_rtu_master_config_t; typedef struct { modbus_rtu_master_config_t cfg; // RX accumulation uint8_t rx_buf[256]; size_t rx_len; // Pending request tracking bool awaiting_response; uint32_t request_started_ms; uint16_t expected_byte_count; } modbus_rtu_master_t; void modbus_rtu_master_init(modbus_rtu_master_t *m, modbus_rtu_master_config_t cfg); // Builds a Read Holding Registers (0x03) request. // Returns frame length. size_t modbus_rtu_build_read_holding(uint8_t *out, size_t out_cap, uint8_t slave_id, uint16_t start_addr, uint16_t quantity, bool disable_crc); // Feed received bytes into the Modbus parser. void modbus_rtu_feed(modbus_rtu_master_t *m, const uint8_t *data, size_t len); // Returns true when a full response for function 0x03 is present in rx_buf. // If true, `*out_data_offset` points to first data byte, `*out_word_count` is number of 16-bit registers. bool modbus_rtu_try_parse_read_holding_response(modbus_rtu_master_t *m, uint8_t expected_slave_id, uint16_t expected_quantity, size_t *out_data_offset, uint16_t *out_word_count); uint16_t modbus_rtu_get_u16_be(const uint8_t *p); uint16_t modbus_rtu_crc16(const uint8_t *data, size_t len); float modbus_float_dcba(uint16_t w1, uint16_t w2);