From 582951be628b9161bbf1af4c56b010aad4cec08e Mon Sep 17 00:00:00 2001 From: JTrantow Date: Tue, 10 Mar 2026 11:05:41 -0500 Subject: [PATCH 1/3] Issue#3849 fix backported to 2.9 Fixes calc_ifdelay() for baud > 19200 that was setting bit timing delays incorrectly leading to a variety of communication problems. Fixes ENOMSG error handling that was locking up modbus communication. --- src/hal/drivers/mesa-hostmot2/hm2_modbus.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/hm2_modbus.c b/src/hal/drivers/mesa-hostmot2/hm2_modbus.c index 6d5a81fd064..b51f23e1e8a 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_modbus.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_modbus.c @@ -374,23 +374,27 @@ static void setup_icdelay(hm2_modbus_inst_t *inst, unsigned baudrate, unsigned p inst->hal->icdelay = inst->maxicharbits; } +#define HARDWARE_MAX_DELAY (1020) //!< Maximum ifdelay in number of bits limited by hardware. +#define HARDWARE_BAUD_LIMIT ((HARDWARE_MAX_DELAY*100000-99999)/175) //!< Baud that limits out the hardware ifdelay. // -// Calculate the inter-frame delay time: +// Calculate the inter-frame delay time in units of numbers of bits. +// Returns: +// - HARDWARE_MAX_DELAY bits if baud > HARDWARE_BAUD_LIMIT // - 3.5 chars if baudrate <= 19200 -// - 1750 microseconds if baudrate > 19200 +// - 1750 microseconds worth of bits when baudrate > 19200 and <= HARDWARE_BAUD_LIMIT // static unsigned calc_ifdelay(hm2_modbus_inst_t *inst, unsigned baudrate, unsigned parity, unsigned stopbits) { - if(baudrate > 582000) { + if(baudrate > HARDWARE_BAUD_LIMIT) { MSG_WARN("%s: warning: Baudrate > 582000 will make inter-frame timer overflow. Setting to maximum.\n", inst->name); - return 1020; + return HARDWARE_MAX_DELAY; } // calculation works for baudrates less than ~24 Mbit/s - if(baudrate <= 19200) + if(baudrate > 19200) return (175u * baudrate + 99999u) / 100000u; unsigned bits = 1 + 8 + (parity ? 1 : 0) + (stopbits > 1 ? 2 : 1); - return (bits * 35 + 9) / 10; // Bit-times * 3.5 rounded up + return (bits * 35 + 9) / 10; // Ceil of bits in 3.5 characters. } // @@ -1053,8 +1057,6 @@ static void process(void *arg, long period) inst->name, inst->cmdidx, HM2_PKTUART_RCR_ICHARBITS_VAL(frsize), inst->maxicharbits); set_error(inst, ENOMSG); - force_resend(inst); - break; } inst->rxdata[0] = 0; // This will fail the parse packet if the read did not resolve r = hm2_pktuart_queue_read_data(inst->uart, inst->rxdata, HM2_PKTUART_RCR_NBYTES_VAL(frsize)); From cbd8d0944bab20d2dbec137e448509f72e9e1353 Mon Sep 17 00:00:00 2001 From: JTrantow Date: Tue, 10 Mar 2026 14:46:17 -0500 Subject: [PATCH 2/3] Back to original voodoo caused by conflating modbus timing calculation with pktuart hardware implementation. (175u * baudrate + 99999u) / 100000u; could be implemented as (7u * baudrate + 3999(/4000; which would improve the calculation range but doesn't matter because already screening out large baud rates. --- src/hal/drivers/mesa-hostmot2/hm2_modbus.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/hm2_modbus.c b/src/hal/drivers/mesa-hostmot2/hm2_modbus.c index b51f23e1e8a..90b76f179c2 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_modbus.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_modbus.c @@ -374,24 +374,20 @@ static void setup_icdelay(hm2_modbus_inst_t *inst, unsigned baudrate, unsigned p inst->hal->icdelay = inst->maxicharbits; } -#define HARDWARE_MAX_DELAY (1020) //!< Maximum ifdelay in number of bits limited by hardware. -#define HARDWARE_BAUD_LIMIT ((HARDWARE_MAX_DELAY*100000-99999)/175) //!< Baud that limits out the hardware ifdelay. // -// Calculate the inter-frame delay time in units of numbers of bits. -// Returns: -// - HARDWARE_MAX_DELAY bits if baud > HARDWARE_BAUD_LIMIT +// Calculate the inter-frame delay time: // - 3.5 chars if baudrate <= 19200 -// - 1750 microseconds worth of bits when baudrate > 19200 and <= HARDWARE_BAUD_LIMIT +// - 1750 microseconds if baudrate > 19200 // static unsigned calc_ifdelay(hm2_modbus_inst_t *inst, unsigned baudrate, unsigned parity, unsigned stopbits) { - if(baudrate > HARDWARE_BAUD_LIMIT) { + if(baudrate > 582000) { MSG_WARN("%s: warning: Baudrate > 582000 will make inter-frame timer overflow. Setting to maximum.\n", inst->name); - return HARDWARE_MAX_DELAY; + return 1020; } // calculation works for baudrates less than ~24 Mbit/s - if(baudrate > 19200) + if(19200 < baudrate) return (175u * baudrate + 99999u) / 100000u; unsigned bits = 1 + 8 + (parity ? 1 : 0) + (stopbits > 1 ? 2 : 1); return (bits * 35 + 9) / 10; // Ceil of bits in 3.5 characters. From 2b20cd19630930710b4df9f1cf9d11fca3eba499 Mon Sep 17 00:00:00 2001 From: JTrantow Date: Wed, 11 Mar 2026 08:01:12 -0500 Subject: [PATCH 3/3] Fix msg and reverse (baudrate > 19200). --- src/hal/drivers/mesa-hostmot2/hm2_modbus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/hm2_modbus.c b/src/hal/drivers/mesa-hostmot2/hm2_modbus.c index 90b76f179c2..6754dbd775a 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_modbus.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_modbus.c @@ -387,7 +387,7 @@ static unsigned calc_ifdelay(hm2_modbus_inst_t *inst, unsigned baudrate, unsigne } // calculation works for baudrates less than ~24 Mbit/s - if(19200 < baudrate) + if(baudrate > 19200) return (175u * baudrate + 99999u) / 100000u; unsigned bits = 1 + 8 + (parity ? 1 : 0) + (stopbits > 1 ? 2 : 1); return (bits * 35 + 9) / 10; // Ceil of bits in 3.5 characters. @@ -1049,7 +1049,7 @@ static void process(void *arg, long period) break; } if(inst->maxicharbits && HM2_PKTUART_RCR_ICHARBITS_VAL(frsize) > inst->maxicharbits) { - MSG_WARN("%s: warning: reply to command %u had too long inter-character delay (%u > %u), dropping\n", + MSG_WARN("%s: warning: reply to command %u had too long inter-character delay (%u > %u), trying to interpret\n", inst->name, inst->cmdidx, HM2_PKTUART_RCR_ICHARBITS_VAL(frsize), inst->maxicharbits); set_error(inst, ENOMSG);