From 1f8381dc3bbf4660dee39face5679987fb8bd06d Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Fri, 9 Oct 2026 18:22:11 -0700 Subject: [PATCH 01/14] hostmot2: validate UART sends and pack bytes without signed shifts --- src/hal/drivers/mesa-hostmot2/uart.c | 37 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/uart.c b/src/hal/drivers/mesa-hostmot2/uart.c index 0ca9ed6a5a5..5061d102d07 100644 --- a/src/hal/drivers/mesa-hostmot2/uart.c +++ b/src/hal/drivers/mesa-hostmot2/uart.c @@ -189,25 +189,28 @@ int hm2_uart_send(char *name, unsigned char data[], int count) static int err_flag = 0; inst = hm2_get_uart(&hm2, name); - if (inst < 0 && !err_flag){ - HM2_ERR_NO_LL("Can not find UART instance %s.\n", name); + if (inst < 0){ + if (!err_flag) + HM2_ERR_NO_LL("Can not find UART instance %s.\n", name); err_flag = 1; - return -1; + return -ENODEV; } - if (hm2->uart.instance[inst].bitrate == 0 && !err_flag){ - HM2_ERR("The selected UART instance %s.\n" - "Has not been configured.\n", name); + if (hm2->uart.instance[inst].bitrate == 0){ + if (!err_flag) + HM2_ERR("The selected UART instance %s.\n" + "Has not been configured.\n", name); err_flag = 1; // don't fill dmesg with junk. - return -1; + return -EINVAL; } + if (count < 0) return -EINVAL; c = 0; err_flag = 0; while (c < count - 3){ - buff = (data[c] + - (data[c+1] << 8) + - (data[c+2] << 16) + - (data[c+3] << 24)); + buff = ((rtapi_u32)data[c] + | ((rtapi_u32)data[c+1] << 8) + | ((rtapi_u32)data[c+2] << 16) + | ((rtapi_u32)data[c+3] << 24)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx4_addr, &buff, sizeof(rtapi_u32)); if (r < 0) { @@ -230,8 +233,8 @@ int hm2_uart_send(char *name, unsigned char data[], int count) return c + 1; } case 2: - buff = (data[c] + - (data[c+1] << 8)); + buff = ((rtapi_u32)data[c] + | ((rtapi_u32)data[c+1] << 8)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx2_addr, &buff, sizeof(rtapi_u32)); if (r < 0){ @@ -241,9 +244,9 @@ int hm2_uart_send(char *name, unsigned char data[], int count) return c + 2; } case 3: - buff = (data[c] + - (data[c+1] << 8) + - (data[c+2] << 16)); + buff = ((rtapi_u32)data[c] + | ((rtapi_u32)data[c+1] << 8) + | ((rtapi_u32)data[c+2] << 16)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx3_addr, &buff, sizeof(rtapi_u32)); if (r < 0){ @@ -286,7 +289,6 @@ int hm2_uart_read(char *name, unsigned char data[]) r = hm2->llio->read(hm2->llio, hm2->uart.instance[inst].rx_fifo_count_addr, &buff, sizeof(rtapi_u32)); - count = buff & 0x1F; c = 0; while (c < count - 3 && c < 16){ @@ -370,4 +372,3 @@ void hm2_uart_write(hostmot2_t *hm2) { (void)hm2; } - From 54043f90a1fc1b3aaedadf80675fefc26f4e3c63 Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Fri, 9 Oct 2026 18:22:11 -0700 Subject: [PATCH 02/14] hostmot2: validate BSPI channels and clock frequency --- src/hal/drivers/mesa-hostmot2/bspi.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/bspi.c b/src/hal/drivers/mesa-hostmot2/bspi.c index c48493c9c83..6e7aa3550c3 100644 --- a/src/hal/drivers/mesa-hostmot2/bspi.c +++ b/src/hal/drivers/mesa-hostmot2/bspi.c @@ -121,6 +121,10 @@ int hm2_tram_add_bspi_frame(char *name, int chan, rtapi_u32 **wbuff, rtapi_u32 * HM2_ERR_NO_LL("Can not find BSPI instance %s.\n", name); return -1; } + if (chan < 0 || chan > 15) { + HM2_ERR("BSPI %s: channel number %i is out of range\n", name, chan); + return -1; + } if (hm2->bspi.instance[i].conf_flag[chan] != true){ HM2_ERR("The selected write channel (%i) on bspi instance %s.\n" "Has not been configured.\n", chan, name); @@ -205,6 +209,10 @@ int hm2_bspi_write_chan(char* name, int chan, rtapi_u32 val) HM2_ERR_NO_LL("Can not find BSPI instance %s.\n", name); return -1; } + if (chan < 0 || chan > 15) { + HM2_ERR("BSPI %s: channel number %i is out of range\n", name, chan); + return -1; + } if (hm2->bspi.instance[i].conf_flag[chan] != true){ HM2_ERR("The selected write channel (%i) on bspi instance %s.\n" "Has not been configured.\n", chan, name); @@ -247,6 +255,10 @@ int hm2_bspi_setup_chan(char *name, int chan, int cs, int bits, double mhz, "BSPI only supports 1-64 bits\n", name, chan, bits); return -1; } + if (mhz <= 0) { + HM2_ERR("BSPI %s: clock frequency must be greater than zero\n", name); + return -1; + } if (delay < 0 || delay > 1e6){ HM2_ERR("The requested frame delay on channel %i of %inS seems " "rather implausible for an SPI device. Exiting.\n", delay, chan); @@ -388,6 +400,3 @@ void hm2_bspi_write(hostmot2_t *hm2) { (void)hm2; } - - - From 77467a993217966758785604802924263cfd1e2c Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Sun, 30 Aug 2026 10:26:59 -0700 Subject: [PATCH 03/14] hostmot2: clamp input scan divisors safely --- src/hal/drivers/mesa-hostmot2/inm.c | 31 ++++++++++++++++++++++----- src/hal/drivers/mesa-hostmot2/inmux.c | 29 +++++++++++++++++++++---- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/inm.c b/src/hal/drivers/mesa-hostmot2/inm.c index 596b9e2ba02..b1033eec68d 100644 --- a/src/hal/drivers/mesa-hostmot2/inm.c +++ b/src/hal/drivers/mesa-hostmot2/inm.c @@ -419,11 +419,24 @@ void hm2_inm_force_write(hostmot2_t *hm2) { for (i = 0; i < hm2->inm.num_instances; i ++) { hm2_inm_instance_t *inst = &hm2->inm.instance[i]; scanrate = inst->scanwidth * hal_get_ui32(inst->hal.param.scan_rate); - if (scanrate > 10000000) { + if (scanrate > 10000000) { scanrate = 10000000; hal_set_ui32(inst->hal.param.scan_rate, scanrate/inst->scanwidth); } - divisor = (hm2->inm.clock_frequency / (4 * scanrate)) - 1; + if (scanrate <= 0) { + divisor = 1023; + hal_set_ui32(inst->hal.param.scan_rate, + (hm2->inm.clock_frequency / 4) / (divisor + 1) + / inst->scanwidth); + } else { + divisor = (hm2->inm.clock_frequency / (4 * scanrate)) - 1; + if (divisor > 1023) { + divisor = 1023; + hal_set_ui32(inst->hal.param.scan_rate, + (hm2->inm.clock_frequency / 4) / (divisor + 1) + / inst->scanwidth); + } + } rtapi_u32 fast_scans = hal_get_ui32(inst->hal.param.fast_scans); if (fast_scans > 63) { fast_scans = hal_set_ui32(inst->hal.param.fast_scans, 63); @@ -472,13 +485,22 @@ void hm2_inm_write(hostmot2_t *hm2) { hal_set_ui32(inst->hal.param.scan_rate, scanrate/inst->scanwidth); HM2_ERR("inm %d scanrate too high, resetting to %d \n", i, hal_get_ui32(inst->hal.param.scan_rate)); } - divisor = (hm2->inm.clock_frequency / (4 * scanrate)) - 1; // bound divisor so we dont splatter into other fields - if ((divisor > 1023 ) | (scanrate == 0 )) { + if (scanrate <= 0) { divisor = 1023; hal_set_ui32(inst->hal.param.scan_rate, (hm2->inm.clock_frequency/4)/(divisor +1) /inst->scanwidth); HM2_ERR("inm %d scanrate too low, resetting to %d \n", i, hal_get_ui32(inst->hal.param.scan_rate)); + } else { + divisor = (hm2->inm.clock_frequency / (4 * scanrate)) - 1; + if (divisor > 1023) { + divisor = 1023; + hal_set_ui32(inst->hal.param.scan_rate, + (hm2->inm.clock_frequency/4)/(divisor +1) + /inst->scanwidth); + HM2_ERR("inm %d scanrate too low, resetting to %d \n", + i, hal_get_ui32(inst->hal.param.scan_rate)); + } } rtapi_u32 fast_scans = hal_get_ui32(inst->hal.param.fast_scans); if (fast_scans > 63) { @@ -659,4 +681,3 @@ void hm2_inm_print_module(hostmot2_t *hm2) { - diff --git a/src/hal/drivers/mesa-hostmot2/inmux.c b/src/hal/drivers/mesa-hostmot2/inmux.c index eee23922016..84e8269adff 100644 --- a/src/hal/drivers/mesa-hostmot2/inmux.c +++ b/src/hal/drivers/mesa-hostmot2/inmux.c @@ -348,7 +348,20 @@ void hm2_inmux_force_write(hostmot2_t *hm2) { muxrate = 5000000; hal_set_ui32(inst->hal.param.scan_rate, muxrate/inst->scanwidth); } - divisor = (hm2->inmux.clock_frequency / (4 * muxrate)) - 1; + if (muxrate <= 0) { + divisor = 1023; + hal_set_ui32(inst->hal.param.scan_rate, + (hm2->inmux.clock_frequency / 4) / (divisor + 1) + / inst->scanwidth); + } else { + divisor = (hm2->inmux.clock_frequency / (4 * muxrate)) - 1; + if (divisor > 1023) { + divisor = 1023; + hal_set_ui32(inst->hal.param.scan_rate, + (hm2->inmux.clock_frequency / 4) / (divisor + 1) + / inst->scanwidth); + } + } rtapi_u32 fast_scans = hal_get_ui32(inst->hal.param.fast_scans); if (fast_scans > 63) { fast_scans = hal_set_ui32(inst->hal.param.fast_scans, 63); @@ -394,13 +407,22 @@ void hm2_inmux_write(hostmot2_t *hm2) { hal_set_ui32(inst->hal.param.scan_rate, muxrate/inst->scanwidth); HM2_ERR("InMux %d scanrate too high, resetting to %d \n", i, hal_get_ui32(inst->hal.param.scan_rate)); } - divisor = (hm2->inmux.clock_frequency / (4 * muxrate)) - 1; // bound divisor so we dont splatter into other fields - if ((divisor > 1023 ) | (muxrate == 0 )) { + if (muxrate <= 0) { divisor = 1023; hal_set_ui32(inst->hal.param.scan_rate, (hm2->inmux.clock_frequency/4) / (divisor +1) / inst->scanwidth); HM2_ERR("InMux %d scanrate too low, resetting to %d \n", i, hal_get_ui32(inst->hal.param.scan_rate)); + } else { + divisor = (hm2->inmux.clock_frequency / (4 * muxrate)) - 1; + if (divisor > 1023) { + divisor = 1023; + hal_set_ui32(inst->hal.param.scan_rate, + (hm2->inmux.clock_frequency/4) / (divisor +1) + / inst->scanwidth); + HM2_ERR("InMux %d scanrate too low, resetting to %d \n", + i, hal_get_ui32(inst->hal.param.scan_rate)); + } } rtapi_u32 fast_scans = hal_get_ui32(inst->hal.param.fast_scans); if (fast_scans > 63) { @@ -557,4 +579,3 @@ void hm2_inmux_print_module(hostmot2_t *hm2) { - From b031eb58961cc68e7f09c44e570ceefd302bedcc Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Fri, 9 Oct 2026 18:22:11 -0700 Subject: [PATCH 04/14] hostmot2: bound connector pin names and correct port diagnostics --- src/hal/drivers/mesa-hostmot2/pins.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/pins.c b/src/hal/drivers/mesa-hostmot2/pins.c index 46a1e8a2ec9..e64ffc79e5d 100644 --- a/src/hal/drivers/mesa-hostmot2/pins.c +++ b/src/hal/drivers/mesa-hostmot2/pins.c @@ -769,7 +769,7 @@ int hm2_read_pin_descriptors(hostmot2_t *hm2) { if (pin->port_num >= hm2->llio->num_ioport_connectors) { HM2_ERR("hm2_read_pin_descriptors: Calculated port number (%d) is " - "invalid\n", pin->port_pin ); + "invalid\n", pin->port_num ); return -EINVAL; } @@ -894,7 +894,9 @@ void hm2_print_pin_usage(hostmot2_t *hm2) { char connector_pin_name[100]; - if (hm2->llio->io_connector_pin_names == NULL) { + if (hm2->llio->io_connector_pin_names == NULL + || (unsigned)i >= (hm2->llio->num_ioport_connectors + * hm2->llio->pins_per_connector)) { snprintf(connector_pin_name, sizeof(connector_pin_name), "%s-%02d", hm2->llio->ioport_connector_name[pin->port_num], pin->port_pin); } else { if (hm2->llio->io_connector_pin_names[i] == NULL) { From e5dedcd08281a94462733e23e05ada18578c2ef1 Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Fri, 9 Oct 2026 18:22:11 -0700 Subject: [PATCH 05/14] hostmot2: reject zero resolver index divisors --- src/hal/drivers/mesa-hostmot2/resolver.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/resolver.c b/src/hal/drivers/mesa-hostmot2/resolver.c index f8c3a064ac2..bf96d4a87bf 100644 --- a/src/hal/drivers/mesa-hostmot2/resolver.c +++ b/src/hal/drivers/mesa-hostmot2/resolver.c @@ -283,6 +283,12 @@ void hm2_resolver_process_tram_read(hostmot2_t *hm2, long period) { for (i = 0; i < hm2->resolver.num_resolvers; i ++) { res = &hm2->resolver.instance[i]; + rtapi_u32 index_div = hal_get_ui32(res->hal.param.index_div); + + if (index_div == 0) { + HM2_ERR("resolver.%02d.index-div == 0, bogus, setting to 1\n", i); + index_div = hal_set_ui32(res->hal.param.index_div, 1); + } scale = hal_get_real(res->hal.param.scale); @@ -326,7 +332,6 @@ void hm2_resolver_process_tram_read(hostmot2_t *hm2, long period) { if ((res->old_reg > hm2->resolver.position_reg[i]) && (res->old_reg - hm2->resolver.position_reg[i] > 0x80000000)){ res->index_cnts++; if (hal_get_bool(res->hal.pin.index_enable)){ - rtapi_u32 index_div = hal_get_ui32(res->hal.param.index_div); int r = (res->index_cnts % index_div); if ((index_div > 1 && r == 1) || (index_div == 1 && r == 0)){ @@ -337,7 +342,8 @@ void hm2_resolver_process_tram_read(hostmot2_t *hm2, long period) { } else if ((res->old_reg < hm2->resolver.position_reg[i]) && (hm2->resolver.position_reg[i] - res->old_reg > 0x80000000)){ res->index_cnts--; - if (hal_get_bool(res->hal.pin.index_enable) && (res->index_cnts % hal_get_ui32(res->hal.param.index_div) == 0)){ + if (hal_get_bool(res->hal.pin.index_enable) + && (res->index_cnts % index_div == 0)){ res->offset = (res->accum - hm2->resolver.position_reg[i] + 0x100000000LL); hal_set_bool(res->hal.pin.index_enable, 0); } @@ -463,4 +469,3 @@ void hm2_resolver_print_module(hostmot2_t *hm2) { (hm2->resolver.velocity_reg[i])); } } - From 510012efc86de779d6e57a99ebd45d713fa53c27 Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Fri, 9 Oct 2026 18:22:11 -0700 Subject: [PATCH 06/14] hostmot2: decode the slowest RPi3 SPI clock divisor --- src/hal/drivers/mesa-hostmot2/spix_rpi3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/spix_rpi3.c b/src/hal/drivers/mesa-hostmot2/spix_rpi3.c index 3e700048af6..22b4b7336b0 100644 --- a/src/hal/drivers/mesa-hostmot2/spix_rpi3.c +++ b/src/hal/drivers/mesa-hostmot2/spix_rpi3.c @@ -850,8 +850,8 @@ static const spix_port_t *rpi3_open(int port, const spix_args_t *args) if(!rpp->spiport) { rpp->clkdivw = spi0_clkdiv_calc(spiclk_base, args->clkw); rpp->clkdivr = spi0_clkdiv_calc(spiclk_base, args->clkr); - ccw = spiclk_base / rpp->clkdivw; - ccr = spiclk_base / rpp->clkdivr; + ccw = spiclk_base / (rpp->clkdivw ? rpp->clkdivw : 65536); + ccr = spiclk_base / (rpp->clkdivr ? rpp->clkdivr : 65536); } else { rpp->clkdivw = spi1_clkdiv_calc(spiclk_base, args->clkw); rpp->clkdivr = spi1_clkdiv_calc(spiclk_base, args->clkr); From c4af04ee57e0f5a32635579d1db49cc71c1aa0dd Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Fri, 9 Oct 2026 18:22:11 -0700 Subject: [PATCH 07/14] hostmot2: clamp negative B and C phase PWM values --- src/hal/drivers/mesa-hostmot2/tp_pwmgen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/tp_pwmgen.c b/src/hal/drivers/mesa-hostmot2/tp_pwmgen.c index fd5fa57530d..396d6fa2abb 100644 --- a/src/hal/drivers/mesa-hostmot2/tp_pwmgen.c +++ b/src/hal/drivers/mesa-hostmot2/tp_pwmgen.c @@ -443,9 +443,9 @@ void hm2_tp_pwmgen_prepare_tram_write(hostmot2_t *hm2) { if (scaled_Avalue > 1.0) scaled_Avalue = 1.0; else if (scaled_Avalue < -1.0) scaled_Avalue = -1.0; if (scaled_Bvalue > 1.0) scaled_Bvalue = 1.0; - else if (scaled_Avalue < -1.0) scaled_Avalue = -1.0; + else if (scaled_Bvalue < -1.0) scaled_Bvalue = -1.0; if (scaled_Cvalue > 1.0) scaled_Cvalue = 1.0; - else if (scaled_Avalue < -1.0) scaled_Avalue = -1.0; + else if (scaled_Cvalue < -1.0) scaled_Cvalue = -1.0; // duty_cycle goes from 0.0 to 1.0, and needs to be puffed out to 10 bits From de916be9f71e90630c1d3b52315e76561b940739 Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Fri, 9 Oct 2026 18:43:31 -0700 Subject: [PATCH 08/14] hostmot2: preserve UART send validation error returns --- src/hal/drivers/mesa-hostmot2/uart.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/uart.c b/src/hal/drivers/mesa-hostmot2/uart.c index 5061d102d07..207ffc49536 100644 --- a/src/hal/drivers/mesa-hostmot2/uart.c +++ b/src/hal/drivers/mesa-hostmot2/uart.c @@ -193,16 +193,16 @@ int hm2_uart_send(char *name, unsigned char data[], int count) if (!err_flag) HM2_ERR_NO_LL("Can not find UART instance %s.\n", name); err_flag = 1; - return -ENODEV; + return -1; } if (hm2->uart.instance[inst].bitrate == 0){ if (!err_flag) HM2_ERR("The selected UART instance %s.\n" "Has not been configured.\n", name); err_flag = 1; // don't fill dmesg with junk. - return -EINVAL; + return -1; } - if (count < 0) return -EINVAL; + if (count < 0) return -1; c = 0; err_flag = 0; From d68621aadbec79cf14ebf41eab6285400799969c Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Fri, 9 Oct 2026 18:46:37 -0700 Subject: [PATCH 09/14] hostmot2: handle UART and BSPI LLIO failures consistently --- docs/src/man/man3/hm2_bspi_write_chan.3.adoc | 2 +- src/hal/drivers/mesa-hostmot2/bspi.c | 6 +- src/hal/drivers/mesa-hostmot2/uart.c | 73 +++++----- tests/hostmot2/serial/README | 19 +++ tests/hostmot2/serial/expected | 2 + tests/hostmot2/serial/test.c | 137 +++++++++++++++++++ tests/hostmot2/serial/test.sh | 16 +++ 7 files changed, 220 insertions(+), 35 deletions(-) create mode 100644 tests/hostmot2/serial/README create mode 100644 tests/hostmot2/serial/expected create mode 100644 tests/hostmot2/serial/test.c create mode 100644 tests/hostmot2/serial/test.sh diff --git a/docs/src/man/man3/hm2_bspi_write_chan.3.adoc b/docs/src/man/man3/hm2_bspi_write_chan.3.adoc index 066f5327f3d..46152f86a4b 100644 --- a/docs/src/man/man3/hm2_bspi_write_chan.3.adoc +++ b/docs/src/man/man3/hm2_bspi_write_chan.3.adoc @@ -33,7 +33,7 @@ Not available in non-realtime components. == RETURN VALUE -Returns 0 on success and -1 on failure. +Returns a positive value on success and -1 on failure. == SEE ALSO diff --git a/src/hal/drivers/mesa-hostmot2/bspi.c b/src/hal/drivers/mesa-hostmot2/bspi.c index 6e7aa3550c3..f01ecab7809 100644 --- a/src/hal/drivers/mesa-hostmot2/bspi.c +++ b/src/hal/drivers/mesa-hostmot2/bspi.c @@ -191,8 +191,9 @@ int hm2_bspi_clear_fifo(char * name) } rtapi_u32 zero = 0; r = hm2->llio->write(hm2->llio, hm2->bspi.instance[i].count_addr, &zero, sizeof(rtapi_u32)); - if (r < 0) { + if (r <= 0) { HM2_ERR("BSPI: hm2->llio->write failure %s\n", name); + return -1; } return r; @@ -219,8 +220,9 @@ int hm2_bspi_write_chan(char* name, int chan, rtapi_u32 val) return -1; } r = hm2->llio->write(hm2->llio, hm2->bspi.instance[i].addr[chan], &buff, sizeof(rtapi_u32)); - if (r < 0) { + if (r <= 0) { HM2_ERR("BSPI: hm2->llio->write failure %s\n", name); + return -1; } return r; diff --git a/src/hal/drivers/mesa-hostmot2/uart.c b/src/hal/drivers/mesa-hostmot2/uart.c index 207ffc49536..19f02354815 100644 --- a/src/hal/drivers/mesa-hostmot2/uart.c +++ b/src/hal/drivers/mesa-hostmot2/uart.c @@ -139,7 +139,7 @@ int hm2_uart_setup(char *name, int bitrate, rtapi_s32 tx_mode, rtapi_s32 rx_mode hostmot2_t *hm2; hm2_uart_instance_t *inst = NULL; rtapi_u32 buff; - int i,r; + int i; i = hm2_get_uart(&hm2, name); if (i < 0){ @@ -149,33 +149,38 @@ int hm2_uart_setup(char *name, int bitrate, rtapi_s32 tx_mode, rtapi_s32 rx_mode inst = &hm2->uart.instance[i]; buff = (rtapi_u32)((bitrate * 1048576.0)/inst->clock_freq); //20 bits in this version - r = 0; if (buff != inst->bitrate){ + rtapi_u32 zero = 0; + if (hm2->llio->write(hm2->llio, inst->rx_bitrate_addr, + &buff, sizeof(buff)) <= 0) goto fail; + if (hm2->llio->write(hm2->llio, inst->tx_bitrate_addr, + &buff, sizeof(buff)) <= 0) goto fail; + // Clear faults and FIFOs before caching the new configuration. + if (hm2->llio->write(hm2->llio, inst->rx_mode_addr, + &zero, sizeof(zero)) <= 0) goto fail; + if (hm2->llio->write(hm2->llio, inst->rx_fifo_count_addr, + &zero, sizeof(zero)) <= 0) goto fail; + if (hm2->llio->write(hm2->llio, inst->tx_fifo_count_addr, + &zero, sizeof(zero)) <= 0) goto fail; inst->bitrate = buff; - r += hm2->llio->write(hm2->llio, inst->rx_bitrate_addr, &buff, sizeof(rtapi_u32)); - r += hm2->llio->write(hm2->llio, inst->tx_bitrate_addr, &buff, sizeof(rtapi_u32)); - buff = 0; - r += hm2->llio->write(hm2->llio, inst->rx_mode_addr, &buff, sizeof(rtapi_u32)); // clear faults - r += hm2->llio->write(hm2->llio, inst->rx_fifo_count_addr, &buff, sizeof(rtapi_u32)); // clear fifo - r += hm2->llio->write(hm2->llio, inst->tx_fifo_count_addr, &buff, sizeof(rtapi_u32)); // clear fifo } if (tx_mode >= 0) { buff = ((rtapi_u32)tx_mode) & 0x7f; - r += hm2->llio->write(hm2->llio, inst->tx_mode_addr, &buff, sizeof(rtapi_u32)); + if (hm2->llio->write(hm2->llio, inst->tx_mode_addr, + &buff, sizeof(buff)) <= 0) goto fail; } if (rx_mode >= 0) { buff = ((rtapi_u32)rx_mode) & 0xff; - r += hm2->llio->write(hm2->llio, inst->rx_mode_addr, &buff, sizeof(rtapi_u32)); + if (hm2->llio->write(hm2->llio, inst->rx_mode_addr, + &buff, sizeof(buff)) <= 0) goto fail; } - - if (r < 0) { - HM2_ERR("UART: hm2->llio->write failure %s\n", name); - return -1; - } - return 0; + +fail: + HM2_ERR("UART: hm2->llio->write failure %s\n", name); + return -1; } @@ -213,9 +218,9 @@ int hm2_uart_send(char *name, unsigned char data[], int count) | ((rtapi_u32)data[c+3] << 24)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx4_addr, &buff, sizeof(rtapi_u32)); - if (r < 0) { + if (r <= 0) { HM2_ERR("UART WRITE: hm2->llio->write failure %s\n", name); - return r; + return -1; } c = c + 4; } @@ -226,9 +231,9 @@ int hm2_uart_send(char *name, unsigned char data[], int count) buff = data[c]; r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx1_addr, &buff, sizeof(rtapi_u32)); - if (r < 0){ + if (r <= 0){ HM2_ERR("UART WRITE: hm2->llio->write failure %s\n", name); - return r; + return -1; }else{ return c + 1; } @@ -237,9 +242,9 @@ int hm2_uart_send(char *name, unsigned char data[], int count) | ((rtapi_u32)data[c+1] << 8)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx2_addr, &buff, sizeof(rtapi_u32)); - if (r < 0){ + if (r <= 0){ HM2_ERR("UART_WRITE: hm2->llio->write failure %s\n", name); - return r; + return -1; }else{ return c + 2; } @@ -249,9 +254,9 @@ int hm2_uart_send(char *name, unsigned char data[], int count) | ((rtapi_u32)data[c+2] << 16)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx3_addr, &buff, sizeof(rtapi_u32)); - if (r < 0){ + if (r <= 0){ HM2_ERR("UART WRITE: hm2->llio->write failure %s\n", name); - return r; + return -1; }else{ return c + 3; } @@ -289,15 +294,19 @@ int hm2_uart_read(char *name, unsigned char data[]) r = hm2->llio->read(hm2->llio, hm2->uart.instance[inst].rx_fifo_count_addr, &buff, sizeof(rtapi_u32)); + if (r <= 0) { + HM2_ERR("UART: hm2->llio->read failure %s\n", name); + return -1; + } count = buff & 0x1F; c = 0; while (c < count - 3 && c < 16){ r = hm2->llio->read(hm2->llio, hm2->uart.instance[inst].rx4_addr, &buff, sizeof(rtapi_u32)); - if (r < 0) { + if (r <= 0) { HM2_ERR("UART: hm2->llio->read failure %s\n", name); - return r; + return -1; } data[c] = (buff & 0x000000FF); @@ -313,18 +322,18 @@ int hm2_uart_read(char *name, unsigned char data[]) case 1: r = hm2->llio->read(hm2->llio, hm2->uart.instance[inst].rx1_addr, &buff, sizeof(rtapi_u32)); - if (r < 0) { + if (r <= 0) { HM2_ERR("UART READ: hm2->llio->read failure %s\n", name); - return r; + return -1; } data[c] = (buff & 0x000000FF); return c + 1; case 2: r = hm2->llio->read(hm2->llio, hm2->uart.instance[inst].rx2_addr, &buff, sizeof(rtapi_u32)); - if (r < 0) { + if (r <= 0) { HM2_ERR("UART READ: hm2->llio->read failure %s\n", name); - return r; + return -1; } data[c] = (buff & 0x000000FF); data[c+1] = (buff & 0x0000FF00) >> 8; @@ -332,9 +341,9 @@ int hm2_uart_read(char *name, unsigned char data[]) case 3: r = hm2->llio->read(hm2->llio, hm2->uart.instance[inst].rx3_addr, &buff, sizeof(rtapi_u32)); - if (r < 0) { + if (r <= 0) { HM2_ERR("UART READ: hm2->llio->read failure %s\n", name); - return r; + return -1; } data[c] = (buff & 0x000000FF); data[c+1] = (buff & 0x0000FF00) >> 8; diff --git a/tests/hostmot2/serial/README b/tests/hostmot2/serial/README new file mode 100644 index 00000000000..3deede8fca2 --- /dev/null +++ b/tests/hostmot2/serial/README @@ -0,0 +1,19 @@ +HostMot2 UART/BSPI software regression tests +========================================== + +Compiles the production drivers with mock LLIO. No hardware is accessed. +Run after configuring/building a run-in-place tree: + + scripts/rip-environment runtests tests/hostmot2/serial + SANITIZERS=address,undefined bash tests/hostmot2/serial/test.sh + +CC can select another C compiler. Sanitizers are optional. +Checks cover repeated invalid UART requests, byte packing, BSPI channel and +clock validation, zero/negative I/O failures, setup retries, and successful +return values. BSPI write/clear success remains positive; failures are -1. +UART setup returns 0 on success; send/read return byte counts. + +Hardware validation remains pending. Record the exact commit, board/firmware, +HAL configuration and results for UART traffic and BSPI peripherals. Other +changes in this PR (INM/INMUX, resolver, pins, SPI clock and PWM) are not +covered by these mocks and require their applicable hardware checks. diff --git a/tests/hostmot2/serial/expected b/tests/hostmot2/serial/expected new file mode 100644 index 00000000000..b94b896a9d5 --- /dev/null +++ b/tests/hostmot2/serial/expected @@ -0,0 +1,2 @@ +PASS: repeated UART errors, 2304 packing cases, BSPI channel and frequency error returns +PASS: UART/BSPI zero and negative I/O failures, setup retries, successful API returns diff --git a/tests/hostmot2/serial/test.c b/tests/hostmot2/serial/test.c new file mode 100644 index 00000000000..e7b99bec280 --- /dev/null +++ b/tests/hostmot2/serial/test.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include "hostmot2.h" +#include "hostmot2-serial.h" + +static hostmot2_t board; +static hm2_lowlevel_io_t llio; +static hm2_uart_instance_t uart; +static hm2_bspi_instance_t bspi; +static unsigned writes, calls, fail_at; +static int failure; +static rtapi_u32 read_count; +static rtapi_u32 words[16]; +static int lookup_result; +int hm2_get_uart(hostmot2_t **hm2, const char *name) { + (void)name; *hm2 = &board; return lookup_result; +} +int hm2_get_bspi(hostmot2_t **hm2, const char *name) { + (void)name; *hm2 = &board; return lookup_result; +} +void rtapi_print_msg(msg_level_t level, const char *fmt, ...) { + (void)level; (void)fmt; +} +int hm2_register_tram_read_region(hostmot2_t *h, rtapi_u16 a, rtapi_u16 s, rtapi_u32 **b) { + (void)h; (void)a; (void)s; (void)b; return 0; +} +int hm2_register_tram_write_region(hostmot2_t *h, rtapi_u16 a, rtapi_u16 s, rtapi_u32 **b) { + (void)h; (void)a; (void)s; (void)b; return 0; +} +static int write_word(hm2_lowlevel_io_t *io, rtapi_u32 a, const void *data, int size) { + (void)io; (void)a; + assert(size == 4 && writes < 16); + calls++; + if (fail_at && calls == fail_at) return failure; + memcpy(&words[writes++], data, 4); + return 1; +} + +static int read_word(hm2_lowlevel_io_t *io, rtapi_u32 addr, void *data, int size) { + (void)io; assert(size == 4); + calls++; + if (fail_at && calls == fail_at) return failure; + rtapi_u32 word = addr == uart.rx_fifo_count_addr ? read_count : 0x42424242; + memcpy(data, &word, 4); + return 1; +} +static void test_failures(void) { + unsigned char data[8] = {0}; + uart.clock_freq = 50000000; + uart.rx_fifo_count_addr = 0x100; + uart.rx1_addr = 0x110; uart.rx2_addr = 0x120; + uart.rx3_addr = 0x130; uart.rx4_addr = 0x140; + llio.read = read_word; + for (unsigned convention = 0; convention < 2; convention++) { + failure = convention ? -EFAULT : 0; + uart.bitrate = 115200; + for (unsigned size = 1; size <= 8; size++) { + for (fail_at = 1; fail_at <= (size + 3) / 4; fail_at++) { + calls = writes = 0; + assert(hm2_uart_send("test", data, size) == -1); + assert(calls == fail_at); + } + read_count = size; + for (fail_at = 1; fail_at <= (size + 3) / 4 + 1; fail_at++) { + calls = 0; + assert(hm2_uart_read("test", data) == -1); + assert(calls == fail_at); + } + } + for (unsigned fail = 1; fail <= 7; fail++) { + uart.bitrate = 0; + fail_at = fail; calls = writes = 0; + assert(hm2_uart_setup("test", 115200, 0, 0) == -1); + assert(calls == fail); + if (fail <= 5) assert(uart.bitrate == 0); + fail_at = 0; calls = writes = 0; + assert(hm2_uart_setup("test", 115200, 0, 0) == 0); + assert(calls == (fail <= 5 ? 7 : 2)); + } + bspi.conf_flag[0] = true; + calls = writes = 0; fail_at = 1; + assert(hm2_bspi_write_chan("test", 0, 0) == -1); + calls = 0; + assert(hm2_bspi_clear_fifo("test") == -1); + } + fail_at = 0; writes = 0; + assert(hm2_bspi_write_chan("test", 0, 0) == 1); + assert(hm2_bspi_clear_fifo("test") == 1); + for (unsigned size = 0; size <= 8; size++) { + read_count = size; + assert(hm2_uart_read("test", data) == (int)size); + for (unsigned i = 0; i < size; i++) assert(data[i] == 0x42); + } + puts("PASS: UART/BSPI zero and negative I/O failures, setup retries, successful API returns"); +} + +int main(void) { + board.llio = &llio; + board.uart.instance = &uart; + board.bspi.instance = &bspi; + llio.write = write_word; + unsigned char data[8] = {0}; + lookup_result = -1; + for (unsigned i = 0; i < 3; i++) assert(hm2_uart_send("test", data, 4) == -1); + lookup_result = 0; + for (unsigned i = 0; i < 3; i++) assert(hm2_uart_send("test", data, 4) == -1); + uart.bitrate = 115200; + assert(hm2_uart_send("test", data, -1) == -1); + assert(writes == 0); + for (unsigned byte = 0; byte <= 255; byte++) { + memset(data, byte, sizeof(data)); + for (unsigned size = 0; size <= 8; size++) { + writes = 0; + assert(hm2_uart_send("test", data, size) == (int)size); + assert(writes == (size + 3) / 4); + for (unsigned i = 0; i < writes; i++) { + rtapi_u32 expected = 0; + for (unsigned j = 0; j < 4 && i * 4 + j < size; j++) + expected |= (rtapi_u32)byte << (j * 8); + assert(words[i] == expected); + } + } + } + int channels[] = {-1, 16, 1000}; + writes = 0; + for (unsigned i = 0; i < sizeof(channels) / sizeof(channels[0]); i++) { + assert(hm2_bspi_write_chan("test", channels[i], 0) == -1); + assert(hm2_tram_add_bspi_frame("test", channels[i], NULL, NULL) == -1); + } + assert(hm2_bspi_setup_chan("test", 0, 0, 8, 0.0, 0, 0, 0, 0, 0, 0) == -1); + assert(hm2_bspi_setup_chan("test", 0, 0, 8, -1.0, 0, 0, 0, 0, 0, 0) == -1); + assert(writes == 0); + puts("PASS: repeated UART errors, 2304 packing cases, BSPI channel and frequency error returns"); + test_failures(); + return 0; +} diff --git a/tests/hostmot2/serial/test.sh b/tests/hostmot2/serial/test.sh new file mode 100644 index 00000000000..9bf8844e5a6 --- /dev/null +++ b/tests/hostmot2/serial/test.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -eu +repo_root=$(cd "$(dirname "$0")/../../.." && pwd) +task_tmp=$(mktemp -d) +trap 'rm -f "$task_tmp/check"; rmdir "$task_tmp"' EXIT +cc=${CC:-cc} +flags=(-O1 -g -fno-strict-aliasing -fwrapv -DRTAPI -DUSPACE -D_GNU_SOURCE + -I"$repo_root/include" -I"$repo_root/src" -I"$repo_root/src/hal/drivers/mesa-hostmot2" + -ffunction-sections -fdata-sections) +if [ -n "${SANITIZERS:-}" ]; then + flags+=("-fsanitize=$SANITIZERS" -fno-sanitize-recover=all) +fi +"$cc" "${flags[@]}" "$repo_root/src/hal/drivers/mesa-hostmot2/uart.c" \ + "$repo_root/src/hal/drivers/mesa-hostmot2/bspi.c" \ + "$repo_root/tests/hostmot2/serial/test.c" -Wl,--gc-sections -o "$task_tmp/check" +"$task_tmp/check" From 74bc083f6aba4a5b04718e51cba2d7ac009f0f5f Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Fri, 9 Oct 2026 19:06:58 -0700 Subject: [PATCH 10/14] hostmot2: round minimum INM and INMUX scan rates up Use integer ceiling when storing clamped scan rates so the following cycle cannot calculate an out-of-range divisor again. Keep the existing control flow and divisor limit. Test startup and runtime clamps, unchanged valid rates, and repeated cycles across all scan widths with three clock frequencies. --- src/hal/drivers/mesa-hostmot2/inm.c | 19 +++--- src/hal/drivers/mesa-hostmot2/inmux.c | 17 +++--- tests/hostmot2/serial/README | 10 ++-- tests/hostmot2/serial/expected | 1 + tests/hostmot2/serial/scanrate-test.c | 83 +++++++++++++++++++++++++++ tests/hostmot2/serial/test.sh | 6 +- 6 files changed, 116 insertions(+), 20 deletions(-) create mode 100644 tests/hostmot2/serial/scanrate-test.c diff --git a/src/hal/drivers/mesa-hostmot2/inm.c b/src/hal/drivers/mesa-hostmot2/inm.c index b1033eec68d..6c40735a089 100644 --- a/src/hal/drivers/mesa-hostmot2/inm.c +++ b/src/hal/drivers/mesa-hostmot2/inm.c @@ -425,16 +425,17 @@ void hm2_inm_force_write(hostmot2_t *hm2) { } if (scanrate <= 0) { divisor = 1023; + // Round up so the normalized rate stays within the divisor limit. hal_set_ui32(inst->hal.param.scan_rate, - (hm2->inm.clock_frequency / 4) / (divisor + 1) - / inst->scanwidth); + (hm2->inm.clock_frequency - 1) + / (4 * (divisor + 1) * inst->scanwidth) + 1); } else { divisor = (hm2->inm.clock_frequency / (4 * scanrate)) - 1; if (divisor > 1023) { divisor = 1023; hal_set_ui32(inst->hal.param.scan_rate, - (hm2->inm.clock_frequency / 4) / (divisor + 1) - / inst->scanwidth); + (hm2->inm.clock_frequency - 1) + / (4 * (divisor + 1) * inst->scanwidth) + 1); } } rtapi_u32 fast_scans = hal_get_ui32(inst->hal.param.fast_scans); @@ -488,16 +489,18 @@ void hm2_inm_write(hostmot2_t *hm2) { // bound divisor so we dont splatter into other fields if (scanrate <= 0) { divisor = 1023; - hal_set_ui32(inst->hal.param.scan_rate, (hm2->inm.clock_frequency/4)/(divisor +1) - /inst->scanwidth); + // Round up so the normalized rate stays within the divisor limit. + hal_set_ui32(inst->hal.param.scan_rate, + (hm2->inm.clock_frequency - 1) + / (4 * (divisor + 1) * inst->scanwidth) + 1); HM2_ERR("inm %d scanrate too low, resetting to %d \n", i, hal_get_ui32(inst->hal.param.scan_rate)); } else { divisor = (hm2->inm.clock_frequency / (4 * scanrate)) - 1; if (divisor > 1023) { divisor = 1023; hal_set_ui32(inst->hal.param.scan_rate, - (hm2->inm.clock_frequency/4)/(divisor +1) - /inst->scanwidth); + (hm2->inm.clock_frequency - 1) + / (4 * (divisor + 1) * inst->scanwidth) + 1); HM2_ERR("inm %d scanrate too low, resetting to %d \n", i, hal_get_ui32(inst->hal.param.scan_rate)); } diff --git a/src/hal/drivers/mesa-hostmot2/inmux.c b/src/hal/drivers/mesa-hostmot2/inmux.c index 84e8269adff..9cbf93e1aac 100644 --- a/src/hal/drivers/mesa-hostmot2/inmux.c +++ b/src/hal/drivers/mesa-hostmot2/inmux.c @@ -350,16 +350,17 @@ void hm2_inmux_force_write(hostmot2_t *hm2) { } if (muxrate <= 0) { divisor = 1023; + // Round up so the normalized rate stays within the divisor limit. hal_set_ui32(inst->hal.param.scan_rate, - (hm2->inmux.clock_frequency / 4) / (divisor + 1) - / inst->scanwidth); + (hm2->inmux.clock_frequency - 1) + / (4 * (divisor + 1) * inst->scanwidth) + 1); } else { divisor = (hm2->inmux.clock_frequency / (4 * muxrate)) - 1; if (divisor > 1023) { divisor = 1023; hal_set_ui32(inst->hal.param.scan_rate, - (hm2->inmux.clock_frequency / 4) / (divisor + 1) - / inst->scanwidth); + (hm2->inmux.clock_frequency - 1) + / (4 * (divisor + 1) * inst->scanwidth) + 1); } } rtapi_u32 fast_scans = hal_get_ui32(inst->hal.param.fast_scans); @@ -410,16 +411,18 @@ void hm2_inmux_write(hostmot2_t *hm2) { // bound divisor so we dont splatter into other fields if (muxrate <= 0) { divisor = 1023; + // Round up so the normalized rate stays within the divisor limit. hal_set_ui32(inst->hal.param.scan_rate, - (hm2->inmux.clock_frequency/4) / (divisor +1) / inst->scanwidth); + (hm2->inmux.clock_frequency - 1) + / (4 * (divisor + 1) * inst->scanwidth) + 1); HM2_ERR("InMux %d scanrate too low, resetting to %d \n", i, hal_get_ui32(inst->hal.param.scan_rate)); } else { divisor = (hm2->inmux.clock_frequency / (4 * muxrate)) - 1; if (divisor > 1023) { divisor = 1023; hal_set_ui32(inst->hal.param.scan_rate, - (hm2->inmux.clock_frequency/4) / (divisor +1) - / inst->scanwidth); + (hm2->inmux.clock_frequency - 1) + / (4 * (divisor + 1) * inst->scanwidth) + 1); HM2_ERR("InMux %d scanrate too low, resetting to %d \n", i, hal_get_ui32(inst->hal.param.scan_rate)); } diff --git a/tests/hostmot2/serial/README b/tests/hostmot2/serial/README index 3deede8fca2..52dfe6aa91a 100644 --- a/tests/hostmot2/serial/README +++ b/tests/hostmot2/serial/README @@ -1,5 +1,5 @@ -HostMot2 UART/BSPI software regression tests -========================================== +HostMot2 UART/BSPI and scan-rate software regression tests +======================================================== Compiles the production drivers with mock LLIO. No hardware is accessed. Run after configuring/building a run-in-place tree: @@ -12,8 +12,10 @@ Checks cover repeated invalid UART requests, byte packing, BSPI channel and clock validation, zero/negative I/O failures, setup retries, and successful return values. BSPI write/clear success remains positive; failures are -1. UART setup returns 0 on success; send/read return byte counts. +INM/INMUX checks cover startup and runtime scan-rate clamping and repeated +cycles at widths 1..32 with three clock frequencies. Hardware validation remains pending. Record the exact commit, board/firmware, -HAL configuration and results for UART traffic and BSPI peripherals. Other -changes in this PR (INM/INMUX, resolver, pins, SPI clock and PWM) are not +HAL configuration and results for UART traffic, BSPI peripherals and +INM/INMUX scan timing. Other changes (resolver, pins, SPI clock and PWM) are not covered by these mocks and require their applicable hardware checks. diff --git a/tests/hostmot2/serial/expected b/tests/hostmot2/serial/expected index b94b896a9d5..e936446b4f9 100644 --- a/tests/hostmot2/serial/expected +++ b/tests/hostmot2/serial/expected @@ -1,2 +1,3 @@ PASS: repeated UART errors, 2304 packing cases, BSPI channel and frequency error returns PASS: UART/BSPI zero and negative I/O failures, setup retries, successful API returns +PASS: INM/INMUX scan-rate bounds, startup/runtime clamps and repeated cycles for widths 1..32 diff --git a/tests/hostmot2/serial/scanrate-test.c b/tests/hostmot2/serial/scanrate-test.c new file mode 100644 index 00000000000..94af866e0c5 --- /dev/null +++ b/tests/hostmot2/serial/scanrate-test.c @@ -0,0 +1,83 @@ +#include +#include +#include "hostmot2.h" + +static unsigned errors, writes; + +void rtapi_print_msg(msg_level_t level, const char *fmt, ...) { + (void)fmt; + if (level == RTAPI_MSG_ERR) errors++; +} + +static int write_word(hm2_lowlevel_io_t *io, rtapi_u32 addr, const void *data, int size) { + (void)io; + (void)addr; + (void)data; + assert(size == sizeof(rtapi_u32)); + writes++; + return 1; +} + +static void test_rate(int mux, int force, unsigned clock, unsigned width, unsigned requested) { + rtapi_uint rate = requested, fast = 1, slow = 1, off = 0; + rtapi_u32 control = 0, mpg = 0, filter = 0; + hm2_lowlevel_io_t llio = {.write = write_word}; + hm2_inm_instance_t inm = {.scanwidth = width}; + hm2_inmux_instance_t inmux = {.scanwidth = width}; + hostmot2_t board = {.llio = &llio}; + board.inm.num_instances = board.inmux.num_instances = 1; + board.inm.clock_frequency = board.inmux.clock_frequency = clock; + board.inm.instance = &inm; + board.inmux.instance = &inmux; + board.inm.control_reg = board.inmux.control_reg = &control; + board.inm.mpg_mode_reg = board.inmux.mpg_mode_reg = &mpg; + board.inm.filter_reg = board.inmux.filter_reg = &filter; + inm.hal.param.scan_rate = inmux.hal.param.scan_rate = (hal_uint_t)&rate; + inm.hal.param.fast_scans = inmux.hal.param.fast_scans = (hal_uint_t)&fast; + inm.hal.param.slow_scans = inmux.hal.param.slow_scans = (hal_uint_t)&slow; + inmux.hal.param.enc0_mode = inmux.hal.param.enc1_mode = + inmux.hal.param.enc2_mode = inmux.hal.param.enc3_mode = (hal_bool_t)&off; + for (unsigned i = 0; i < 32; i++) inmux.hal.pin.slow[i] = (hal_bool_t)&off; + + void (*write)(hostmot2_t *) = mux ? hm2_inmux_write : hm2_inm_write; + void (*force_write)(hostmot2_t *) = mux ? hm2_inmux_force_write : hm2_inm_force_write; + unsigned minimum = (clock + 4096u * width - 1) / (4096u * width); + unsigned expected = requested <= 1 ? minimum : requested; + unsigned divisor = requested <= 1 ? 1023 : clock / (4u * width * requested) - 1; + errors = writes = 0; + (force ? force_write : write)(&board); + assert(hal_get_ui32(inm.hal.param.scan_rate) == expected); + assert(control == ((1u << 5) | (divisor << 6) | (1u << 16) | (1u << 22))); + assert(errors == (!force && requested <= 1 ? 1u : 0u)); + + // A normalized rate must stay in range without repeated diagnostics or writes. + errors = 0; + write(&board); + divisor = clock / (4u * width * expected) - 1; + assert(divisor <= 1023); + assert(control == ((1u << 5) | (divisor << 6) | (1u << 16) | (1u << 22))); + unsigned settled_writes = writes; + for (unsigned cycle = 0; cycle < 5; cycle++) { + write(&board); + assert(hal_get_ui32(inm.hal.param.scan_rate) == expected); + assert(errors == 0 && writes == settled_writes); + } +} + +int main(void) { + const unsigned clocks[] = {32768000, 50000000, 100000000}; + for (int mux = 0; mux <= 1; mux++) { + for (int force = 0; force <= 1; force++) { + for (unsigned c = 0; c < sizeof(clocks) / sizeof(clocks[0]); c++) { + for (unsigned width = 1; width <= 32; width++) { + unsigned minimum = (clocks[c] + 4096u * width - 1) / (4096u * width); + const unsigned rates[] = {0, 1, minimum, 50000}; + for (unsigned r = 0; r < sizeof(rates) / sizeof(rates[0]); r++) + test_rate(mux, force, clocks[c], width, rates[r]); + } + } + } + } + puts("PASS: INM/INMUX scan-rate bounds, startup/runtime clamps and repeated cycles for widths 1..32"); + return 0; +} diff --git a/tests/hostmot2/serial/test.sh b/tests/hostmot2/serial/test.sh index 9bf8844e5a6..6df45073c2e 100644 --- a/tests/hostmot2/serial/test.sh +++ b/tests/hostmot2/serial/test.sh @@ -2,7 +2,7 @@ set -eu repo_root=$(cd "$(dirname "$0")/../../.." && pwd) task_tmp=$(mktemp -d) -trap 'rm -f "$task_tmp/check"; rmdir "$task_tmp"' EXIT +trap 'rm -f "$task_tmp/check" "$task_tmp/scanrates"; rmdir "$task_tmp"' EXIT cc=${CC:-cc} flags=(-O1 -g -fno-strict-aliasing -fwrapv -DRTAPI -DUSPACE -D_GNU_SOURCE -I"$repo_root/include" -I"$repo_root/src" -I"$repo_root/src/hal/drivers/mesa-hostmot2" @@ -14,3 +14,7 @@ fi "$repo_root/src/hal/drivers/mesa-hostmot2/bspi.c" \ "$repo_root/tests/hostmot2/serial/test.c" -Wl,--gc-sections -o "$task_tmp/check" "$task_tmp/check" +"$cc" "${flags[@]}" "$repo_root/src/hal/drivers/mesa-hostmot2/inm.c" \ + "$repo_root/src/hal/drivers/mesa-hostmot2/inmux.c" \ + "$repo_root/tests/hostmot2/serial/scanrate-test.c" -Wl,--gc-sections -o "$task_tmp/scanrates" +"$task_tmp/scanrates" From b9b5a0fa8227511d9a29a3e7b36bcda5ae67b9e0 Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Sat, 10 Oct 2026 09:16:22 -0700 Subject: [PATCH 11/14] hostmot2: invalidate UART rate before reconfiguration --- src/hal/drivers/mesa-hostmot2/uart.c | 1 + tests/hostmot2/serial/README | 2 +- tests/hostmot2/serial/test.c | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/uart.c b/src/hal/drivers/mesa-hostmot2/uart.c index 19f02354815..99807b6c540 100644 --- a/src/hal/drivers/mesa-hostmot2/uart.c +++ b/src/hal/drivers/mesa-hostmot2/uart.c @@ -151,6 +151,7 @@ int hm2_uart_setup(char *name, int bitrate, rtapi_s32 tx_mode, rtapi_s32 rx_mode buff = (rtapi_u32)((bitrate * 1048576.0)/inst->clock_freq); //20 bits in this version if (buff != inst->bitrate){ rtapi_u32 zero = 0; + inst->bitrate = 0; // A partial change invalidates both directions' cached rate. if (hm2->llio->write(hm2->llio, inst->rx_bitrate_addr, &buff, sizeof(buff)) <= 0) goto fail; if (hm2->llio->write(hm2->llio, inst->tx_bitrate_addr, diff --git a/tests/hostmot2/serial/README b/tests/hostmot2/serial/README index 52dfe6aa91a..b28d41a57c1 100644 --- a/tests/hostmot2/serial/README +++ b/tests/hostmot2/serial/README @@ -9,7 +9,7 @@ Run after configuring/building a run-in-place tree: CC can select another C compiler. Sanitizers are optional. Checks cover repeated invalid UART requests, byte packing, BSPI channel and -clock validation, zero/negative I/O failures, setup retries, and successful +clock validation, zero/negative I/O failures, setup retries and rollback, and successful return values. BSPI write/clear success remains positive; failures are -1. UART setup returns 0 on success; send/read return byte counts. INM/INMUX checks cover startup and runtime scan-rate clamping and repeated diff --git a/tests/hostmot2/serial/test.c b/tests/hostmot2/serial/test.c index e7b99bec280..088001e2db7 100644 --- a/tests/hostmot2/serial/test.c +++ b/tests/hostmot2/serial/test.c @@ -11,6 +11,7 @@ static hm2_bspi_instance_t bspi; static unsigned writes, calls, fail_at; static int failure; static rtapi_u32 read_count; +static rtapi_u32 rx_bitrate, tx_bitrate; static rtapi_u32 words[16]; static int lookup_result; int hm2_get_uart(hostmot2_t **hm2, const char *name) { @@ -29,11 +30,13 @@ int hm2_register_tram_write_region(hostmot2_t *h, rtapi_u16 a, rtapi_u16 s, rtap (void)h; (void)a; (void)s; (void)b; return 0; } static int write_word(hm2_lowlevel_io_t *io, rtapi_u32 a, const void *data, int size) { - (void)io; (void)a; + (void)io; assert(size == 4 && writes < 16); calls++; if (fail_at && calls == fail_at) return failure; memcpy(&words[writes++], data, 4); + if (a == uart.rx_bitrate_addr) memcpy(&rx_bitrate, data, 4); + if (a == uart.tx_bitrate_addr) memcpy(&tx_bitrate, data, 4); return 1; } @@ -51,6 +54,7 @@ static void test_failures(void) { uart.rx_fifo_count_addr = 0x100; uart.rx1_addr = 0x110; uart.rx2_addr = 0x120; uart.rx3_addr = 0x130; uart.rx4_addr = 0x140; + uart.rx_bitrate_addr = 0x150; uart.tx_bitrate_addr = 0x160; llio.read = read_word; for (unsigned convention = 0; convention < 2; convention++) { failure = convention ? -EFAULT : 0; @@ -78,6 +82,16 @@ static void test_failures(void) { assert(hm2_uart_setup("test", 115200, 0, 0) == 0); assert(calls == (fail <= 5 ? 7 : 2)); } + for (unsigned fail = 1; fail <= 5; fail++) { + rtapi_u32 original = uart.bitrate; + fail_at = fail; calls = writes = 0; + assert(hm2_uart_setup("test", 230400, 0, 0) == -1); + assert(calls == fail && uart.bitrate == 0); + fail_at = 0; calls = writes = 0; + assert(hm2_uart_setup("test", 115200, 0, 0) == 0); + assert(calls == 7 && uart.bitrate == original); + assert(rx_bitrate == original && tx_bitrate == original); + } bspi.conf_flag[0] = true; calls = writes = 0; fail_at = 1; assert(hm2_bspi_write_chan("test", 0, 0) == -1); From 1ca33cfc8cf04c4f9edf9a0a098a3a28cd910ead Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Mon, 12 Oct 2026 10:33:14 -0700 Subject: [PATCH 12/14] hostmot2: align LLIO checks and test flags --- src/hal/drivers/mesa-hostmot2/bspi.c | 4 ++-- src/hal/drivers/mesa-hostmot2/uart.c | 32 ++++++++++++++-------------- tests/hostmot2/harness.mk | 16 ++++++++++++++ tests/hostmot2/serial/README | 6 ++++-- tests/hostmot2/serial/expected | 2 +- tests/hostmot2/serial/test.c | 22 +++++++++---------- tests/hostmot2/serial/test.sh | 23 +++++++++----------- 7 files changed, 60 insertions(+), 45 deletions(-) create mode 100644 tests/hostmot2/harness.mk diff --git a/src/hal/drivers/mesa-hostmot2/bspi.c b/src/hal/drivers/mesa-hostmot2/bspi.c index f01ecab7809..3b6c7df5921 100644 --- a/src/hal/drivers/mesa-hostmot2/bspi.c +++ b/src/hal/drivers/mesa-hostmot2/bspi.c @@ -191,7 +191,7 @@ int hm2_bspi_clear_fifo(char * name) } rtapi_u32 zero = 0; r = hm2->llio->write(hm2->llio, hm2->bspi.instance[i].count_addr, &zero, sizeof(rtapi_u32)); - if (r <= 0) { + if (!r) { HM2_ERR("BSPI: hm2->llio->write failure %s\n", name); return -1; } @@ -220,7 +220,7 @@ int hm2_bspi_write_chan(char* name, int chan, rtapi_u32 val) return -1; } r = hm2->llio->write(hm2->llio, hm2->bspi.instance[i].addr[chan], &buff, sizeof(rtapi_u32)); - if (r <= 0) { + if (!r) { HM2_ERR("BSPI: hm2->llio->write failure %s\n", name); return -1; } diff --git a/src/hal/drivers/mesa-hostmot2/uart.c b/src/hal/drivers/mesa-hostmot2/uart.c index 99807b6c540..b9c794a03e1 100644 --- a/src/hal/drivers/mesa-hostmot2/uart.c +++ b/src/hal/drivers/mesa-hostmot2/uart.c @@ -153,29 +153,29 @@ int hm2_uart_setup(char *name, int bitrate, rtapi_s32 tx_mode, rtapi_s32 rx_mode rtapi_u32 zero = 0; inst->bitrate = 0; // A partial change invalidates both directions' cached rate. if (hm2->llio->write(hm2->llio, inst->rx_bitrate_addr, - &buff, sizeof(buff)) <= 0) goto fail; + &buff, sizeof(buff)) == 0) goto fail; if (hm2->llio->write(hm2->llio, inst->tx_bitrate_addr, - &buff, sizeof(buff)) <= 0) goto fail; + &buff, sizeof(buff)) == 0) goto fail; // Clear faults and FIFOs before caching the new configuration. if (hm2->llio->write(hm2->llio, inst->rx_mode_addr, - &zero, sizeof(zero)) <= 0) goto fail; + &zero, sizeof(zero)) == 0) goto fail; if (hm2->llio->write(hm2->llio, inst->rx_fifo_count_addr, - &zero, sizeof(zero)) <= 0) goto fail; + &zero, sizeof(zero)) == 0) goto fail; if (hm2->llio->write(hm2->llio, inst->tx_fifo_count_addr, - &zero, sizeof(zero)) <= 0) goto fail; + &zero, sizeof(zero)) == 0) goto fail; inst->bitrate = buff; } if (tx_mode >= 0) { buff = ((rtapi_u32)tx_mode) & 0x7f; if (hm2->llio->write(hm2->llio, inst->tx_mode_addr, - &buff, sizeof(buff)) <= 0) goto fail; + &buff, sizeof(buff)) == 0) goto fail; } if (rx_mode >= 0) { buff = ((rtapi_u32)rx_mode) & 0xff; if (hm2->llio->write(hm2->llio, inst->rx_mode_addr, - &buff, sizeof(buff)) <= 0) goto fail; + &buff, sizeof(buff)) == 0) goto fail; } return 0; @@ -219,7 +219,7 @@ int hm2_uart_send(char *name, unsigned char data[], int count) | ((rtapi_u32)data[c+3] << 24)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx4_addr, &buff, sizeof(rtapi_u32)); - if (r <= 0) { + if (!r) { HM2_ERR("UART WRITE: hm2->llio->write failure %s\n", name); return -1; } @@ -232,7 +232,7 @@ int hm2_uart_send(char *name, unsigned char data[], int count) buff = data[c]; r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx1_addr, &buff, sizeof(rtapi_u32)); - if (r <= 0){ + if (!r){ HM2_ERR("UART WRITE: hm2->llio->write failure %s\n", name); return -1; }else{ @@ -243,7 +243,7 @@ int hm2_uart_send(char *name, unsigned char data[], int count) | ((rtapi_u32)data[c+1] << 8)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx2_addr, &buff, sizeof(rtapi_u32)); - if (r <= 0){ + if (!r){ HM2_ERR("UART_WRITE: hm2->llio->write failure %s\n", name); return -1; }else{ @@ -255,7 +255,7 @@ int hm2_uart_send(char *name, unsigned char data[], int count) | ((rtapi_u32)data[c+2] << 16)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx3_addr, &buff, sizeof(rtapi_u32)); - if (r <= 0){ + if (!r){ HM2_ERR("UART WRITE: hm2->llio->write failure %s\n", name); return -1; }else{ @@ -295,7 +295,7 @@ int hm2_uart_read(char *name, unsigned char data[]) r = hm2->llio->read(hm2->llio, hm2->uart.instance[inst].rx_fifo_count_addr, &buff, sizeof(rtapi_u32)); - if (r <= 0) { + if (!r) { HM2_ERR("UART: hm2->llio->read failure %s\n", name); return -1; } @@ -305,7 +305,7 @@ int hm2_uart_read(char *name, unsigned char data[]) r = hm2->llio->read(hm2->llio, hm2->uart.instance[inst].rx4_addr, &buff, sizeof(rtapi_u32)); - if (r <= 0) { + if (!r) { HM2_ERR("UART: hm2->llio->read failure %s\n", name); return -1; } @@ -323,7 +323,7 @@ int hm2_uart_read(char *name, unsigned char data[]) case 1: r = hm2->llio->read(hm2->llio, hm2->uart.instance[inst].rx1_addr, &buff, sizeof(rtapi_u32)); - if (r <= 0) { + if (!r) { HM2_ERR("UART READ: hm2->llio->read failure %s\n", name); return -1; } @@ -332,7 +332,7 @@ int hm2_uart_read(char *name, unsigned char data[]) case 2: r = hm2->llio->read(hm2->llio, hm2->uart.instance[inst].rx2_addr, &buff, sizeof(rtapi_u32)); - if (r <= 0) { + if (!r) { HM2_ERR("UART READ: hm2->llio->read failure %s\n", name); return -1; } @@ -342,7 +342,7 @@ int hm2_uart_read(char *name, unsigned char data[]) case 3: r = hm2->llio->read(hm2->llio, hm2->uart.instance[inst].rx3_addr, &buff, sizeof(rtapi_u32)); - if (r <= 0) { + if (!r) { HM2_ERR("UART READ: hm2->llio->read failure %s\n", name); return -1; } diff --git a/tests/hostmot2/harness.mk b/tests/hostmot2/harness.mk new file mode 100644 index 00000000000..d9c8a7233a1 --- /dev/null +++ b/tests/hostmot2/harness.mk @@ -0,0 +1,16 @@ +# Used with src/Makefile so mocks inherit the configured realtime build flags. +ifneq ($(BUILD_SYS),uspace) +$(error HostMot2 mock tests require a configured uspace build) +endif + +ifneq ($(SANITIZERS),) +HM2_TEST_SANITIZERS = -fsanitize=$(SANITIZERS) -fno-sanitize-recover=all +endif + +.PHONY: hm2-test +hm2-test: + $(CC) $(OPT) $(DEBUG) $(EXTRA_DEBUG) -DRTAPI \ + $(EXTRA_CFLAGS) $(XENOMAI_EVL_CFLAGS) $(HM2_TEST_SANITIZERS) \ + -I$(BASEPWD)/hal/drivers/mesa-hostmot2 -ffunction-sections -fdata-sections \ + $(TEST_CFLAGS) $(TEST_SOURCES) -Wl,--gc-sections $(TEST_LIBS) \ + $(XENOMAI_EVL_LDFLAGS) $(LDFLAGS) -o "$(TEST_OUTPUT)" diff --git a/tests/hostmot2/serial/README b/tests/hostmot2/serial/README index b28d41a57c1..14c2e553633 100644 --- a/tests/hostmot2/serial/README +++ b/tests/hostmot2/serial/README @@ -7,10 +7,12 @@ Run after configuring/building a run-in-place tree: scripts/rip-environment runtests tests/hostmot2/serial SANITIZERS=address,undefined bash tests/hostmot2/serial/test.sh +Uses the configured realtime compiler and flags from src/Makefile. CC can select another C compiler. Sanitizers are optional. Checks cover repeated invalid UART requests, byte packing, BSPI channel and -clock validation, zero/negative I/O failures, setup retries and rollback, and successful -return values. BSPI write/clear success remains positive; failures are -1. +clock validation, zero-return LLIO failures, setup retries and rollback, and +successful return values. LLIO callbacks use nonzero for success, zero for failure. +BSPI write/clear success remains positive; failures are -1. UART setup returns 0 on success; send/read return byte counts. INM/INMUX checks cover startup and runtime scan-rate clamping and repeated cycles at widths 1..32 with three clock frequencies. diff --git a/tests/hostmot2/serial/expected b/tests/hostmot2/serial/expected index e936446b4f9..793b112e4ac 100644 --- a/tests/hostmot2/serial/expected +++ b/tests/hostmot2/serial/expected @@ -1,3 +1,3 @@ PASS: repeated UART errors, 2304 packing cases, BSPI channel and frequency error returns -PASS: UART/BSPI zero and negative I/O failures, setup retries, successful API returns +PASS: UART/BSPI boolean I/O failures, setup retries and rollback, successful API returns PASS: INM/INMUX scan-rate bounds, startup/runtime clamps and repeated cycles for widths 1..32 diff --git a/tests/hostmot2/serial/test.c b/tests/hostmot2/serial/test.c index 088001e2db7..0bc3f45ef35 100644 --- a/tests/hostmot2/serial/test.c +++ b/tests/hostmot2/serial/test.c @@ -9,7 +9,7 @@ static hm2_lowlevel_io_t llio; static hm2_uart_instance_t uart; static hm2_bspi_instance_t bspi; static unsigned writes, calls, fail_at; -static int failure; +static int io_success = 1; static rtapi_u32 read_count; static rtapi_u32 rx_bitrate, tx_bitrate; static rtapi_u32 words[16]; @@ -33,20 +33,20 @@ static int write_word(hm2_lowlevel_io_t *io, rtapi_u32 a, const void *data, int (void)io; assert(size == 4 && writes < 16); calls++; - if (fail_at && calls == fail_at) return failure; + if (fail_at && calls == fail_at) return 0; memcpy(&words[writes++], data, 4); if (a == uart.rx_bitrate_addr) memcpy(&rx_bitrate, data, 4); if (a == uart.tx_bitrate_addr) memcpy(&tx_bitrate, data, 4); - return 1; + return io_success; } static int read_word(hm2_lowlevel_io_t *io, rtapi_u32 addr, void *data, int size) { (void)io; assert(size == 4); calls++; - if (fail_at && calls == fail_at) return failure; + if (fail_at && calls == fail_at) return 0; rtapi_u32 word = addr == uart.rx_fifo_count_addr ? read_count : 0x42424242; memcpy(data, &word, 4); - return 1; + return io_success; } static void test_failures(void) { unsigned char data[8] = {0}; @@ -56,8 +56,8 @@ static void test_failures(void) { uart.rx3_addr = 0x130; uart.rx4_addr = 0x140; uart.rx_bitrate_addr = 0x150; uart.tx_bitrate_addr = 0x160; llio.read = read_word; - for (unsigned convention = 0; convention < 2; convention++) { - failure = convention ? -EFAULT : 0; + for (unsigned success = 1; success <= 2; success++) { + io_success = success; uart.bitrate = 115200; for (unsigned size = 1; size <= 8; size++) { for (fail_at = 1; fail_at <= (size + 3) / 4; fail_at++) { @@ -97,16 +97,16 @@ static void test_failures(void) { assert(hm2_bspi_write_chan("test", 0, 0) == -1); calls = 0; assert(hm2_bspi_clear_fifo("test") == -1); + fail_at = 0; calls = writes = 0; + assert(hm2_bspi_write_chan("test", 0, 0) == io_success); + assert(hm2_bspi_clear_fifo("test") == io_success); } - fail_at = 0; writes = 0; - assert(hm2_bspi_write_chan("test", 0, 0) == 1); - assert(hm2_bspi_clear_fifo("test") == 1); for (unsigned size = 0; size <= 8; size++) { read_count = size; assert(hm2_uart_read("test", data) == (int)size); for (unsigned i = 0; i < size; i++) assert(data[i] == 0x42); } - puts("PASS: UART/BSPI zero and negative I/O failures, setup retries, successful API returns"); + puts("PASS: UART/BSPI boolean I/O failures, setup retries and rollback, successful API returns"); } int main(void) { diff --git a/tests/hostmot2/serial/test.sh b/tests/hostmot2/serial/test.sh index 6df45073c2e..98ad3c887d3 100644 --- a/tests/hostmot2/serial/test.sh +++ b/tests/hostmot2/serial/test.sh @@ -3,18 +3,15 @@ set -eu repo_root=$(cd "$(dirname "$0")/../../.." && pwd) task_tmp=$(mktemp -d) trap 'rm -f "$task_tmp/check" "$task_tmp/scanrates"; rmdir "$task_tmp"' EXIT -cc=${CC:-cc} -flags=(-O1 -g -fno-strict-aliasing -fwrapv -DRTAPI -DUSPACE -D_GNU_SOURCE - -I"$repo_root/include" -I"$repo_root/src" -I"$repo_root/src/hal/drivers/mesa-hostmot2" - -ffunction-sections -fdata-sections) -if [ -n "${SANITIZERS:-}" ]; then - flags+=("-fsanitize=$SANITIZERS" -fno-sanitize-recover=all) -fi -"$cc" "${flags[@]}" "$repo_root/src/hal/drivers/mesa-hostmot2/uart.c" \ - "$repo_root/src/hal/drivers/mesa-hostmot2/bspi.c" \ - "$repo_root/tests/hostmot2/serial/test.c" -Wl,--gc-sections -o "$task_tmp/check" +make_args=(-s --no-print-directory -C "$repo_root/src" -f Makefile + -f "$repo_root/tests/hostmot2/harness.mk" -o Makefile -o Makefile.inc + TRIVIAL_BUILD=yes) +if [ -n "${CC:-}" ]; then make_args+=("CC=$CC"); fi +make "${make_args[@]}" hm2-test \ + "TEST_SOURCES=hal/drivers/mesa-hostmot2/uart.c hal/drivers/mesa-hostmot2/bspi.c ../tests/hostmot2/serial/test.c" \ + "TEST_OUTPUT=$task_tmp/check" >&2 "$task_tmp/check" -"$cc" "${flags[@]}" "$repo_root/src/hal/drivers/mesa-hostmot2/inm.c" \ - "$repo_root/src/hal/drivers/mesa-hostmot2/inmux.c" \ - "$repo_root/tests/hostmot2/serial/scanrate-test.c" -Wl,--gc-sections -o "$task_tmp/scanrates" +make "${make_args[@]}" hm2-test \ + "TEST_SOURCES=hal/drivers/mesa-hostmot2/inm.c hal/drivers/mesa-hostmot2/inmux.c ../tests/hostmot2/serial/scanrate-test.c" \ + "TEST_OUTPUT=$task_tmp/scanrates" >&2 "$task_tmp/scanrates" From 813d66822423733afa9c7d226dd104db230541f2 Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Sun, 1 Nov 2026 06:21:12 -0800 Subject: [PATCH 13/14] hostmot2: trim packing and drop test harness --- src/hal/drivers/mesa-hostmot2/uart.c | 18 +-- tests/hostmot2/harness.mk | 16 --- tests/hostmot2/serial/README | 23 ---- tests/hostmot2/serial/expected | 3 - tests/hostmot2/serial/scanrate-test.c | 83 -------------- tests/hostmot2/serial/test.c | 151 -------------------------- tests/hostmot2/serial/test.sh | 17 --- 7 files changed, 9 insertions(+), 302 deletions(-) delete mode 100644 tests/hostmot2/harness.mk delete mode 100644 tests/hostmot2/serial/README delete mode 100644 tests/hostmot2/serial/expected delete mode 100644 tests/hostmot2/serial/scanrate-test.c delete mode 100644 tests/hostmot2/serial/test.c delete mode 100644 tests/hostmot2/serial/test.sh diff --git a/src/hal/drivers/mesa-hostmot2/uart.c b/src/hal/drivers/mesa-hostmot2/uart.c index b9c794a03e1..3323fcd1e48 100644 --- a/src/hal/drivers/mesa-hostmot2/uart.c +++ b/src/hal/drivers/mesa-hostmot2/uart.c @@ -213,10 +213,10 @@ int hm2_uart_send(char *name, unsigned char data[], int count) c = 0; err_flag = 0; while (c < count - 3){ - buff = ((rtapi_u32)data[c] - | ((rtapi_u32)data[c+1] << 8) - | ((rtapi_u32)data[c+2] << 16) - | ((rtapi_u32)data[c+3] << 24)); + buff = (data[c] + + (data[c+1] << 8) + + (data[c+2] << 16) + + ((rtapi_u32)data[c+3] << 24)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx4_addr, &buff, sizeof(rtapi_u32)); if (!r) { @@ -239,8 +239,8 @@ int hm2_uart_send(char *name, unsigned char data[], int count) return c + 1; } case 2: - buff = ((rtapi_u32)data[c] - | ((rtapi_u32)data[c+1] << 8)); + buff = (data[c] + + (data[c+1] << 8)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx2_addr, &buff, sizeof(rtapi_u32)); if (!r){ @@ -250,9 +250,9 @@ int hm2_uart_send(char *name, unsigned char data[], int count) return c + 2; } case 3: - buff = ((rtapi_u32)data[c] - | ((rtapi_u32)data[c+1] << 8) - | ((rtapi_u32)data[c+2] << 16)); + buff = (data[c] + + (data[c+1] << 8) + + (data[c+2] << 16)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx3_addr, &buff, sizeof(rtapi_u32)); if (!r){ diff --git a/tests/hostmot2/harness.mk b/tests/hostmot2/harness.mk deleted file mode 100644 index d9c8a7233a1..00000000000 --- a/tests/hostmot2/harness.mk +++ /dev/null @@ -1,16 +0,0 @@ -# Used with src/Makefile so mocks inherit the configured realtime build flags. -ifneq ($(BUILD_SYS),uspace) -$(error HostMot2 mock tests require a configured uspace build) -endif - -ifneq ($(SANITIZERS),) -HM2_TEST_SANITIZERS = -fsanitize=$(SANITIZERS) -fno-sanitize-recover=all -endif - -.PHONY: hm2-test -hm2-test: - $(CC) $(OPT) $(DEBUG) $(EXTRA_DEBUG) -DRTAPI \ - $(EXTRA_CFLAGS) $(XENOMAI_EVL_CFLAGS) $(HM2_TEST_SANITIZERS) \ - -I$(BASEPWD)/hal/drivers/mesa-hostmot2 -ffunction-sections -fdata-sections \ - $(TEST_CFLAGS) $(TEST_SOURCES) -Wl,--gc-sections $(TEST_LIBS) \ - $(XENOMAI_EVL_LDFLAGS) $(LDFLAGS) -o "$(TEST_OUTPUT)" diff --git a/tests/hostmot2/serial/README b/tests/hostmot2/serial/README deleted file mode 100644 index 14c2e553633..00000000000 --- a/tests/hostmot2/serial/README +++ /dev/null @@ -1,23 +0,0 @@ -HostMot2 UART/BSPI and scan-rate software regression tests -======================================================== - -Compiles the production drivers with mock LLIO. No hardware is accessed. -Run after configuring/building a run-in-place tree: - - scripts/rip-environment runtests tests/hostmot2/serial - SANITIZERS=address,undefined bash tests/hostmot2/serial/test.sh - -Uses the configured realtime compiler and flags from src/Makefile. -CC can select another C compiler. Sanitizers are optional. -Checks cover repeated invalid UART requests, byte packing, BSPI channel and -clock validation, zero-return LLIO failures, setup retries and rollback, and -successful return values. LLIO callbacks use nonzero for success, zero for failure. -BSPI write/clear success remains positive; failures are -1. -UART setup returns 0 on success; send/read return byte counts. -INM/INMUX checks cover startup and runtime scan-rate clamping and repeated -cycles at widths 1..32 with three clock frequencies. - -Hardware validation remains pending. Record the exact commit, board/firmware, -HAL configuration and results for UART traffic, BSPI peripherals and -INM/INMUX scan timing. Other changes (resolver, pins, SPI clock and PWM) are not -covered by these mocks and require their applicable hardware checks. diff --git a/tests/hostmot2/serial/expected b/tests/hostmot2/serial/expected deleted file mode 100644 index 793b112e4ac..00000000000 --- a/tests/hostmot2/serial/expected +++ /dev/null @@ -1,3 +0,0 @@ -PASS: repeated UART errors, 2304 packing cases, BSPI channel and frequency error returns -PASS: UART/BSPI boolean I/O failures, setup retries and rollback, successful API returns -PASS: INM/INMUX scan-rate bounds, startup/runtime clamps and repeated cycles for widths 1..32 diff --git a/tests/hostmot2/serial/scanrate-test.c b/tests/hostmot2/serial/scanrate-test.c deleted file mode 100644 index 94af866e0c5..00000000000 --- a/tests/hostmot2/serial/scanrate-test.c +++ /dev/null @@ -1,83 +0,0 @@ -#include -#include -#include "hostmot2.h" - -static unsigned errors, writes; - -void rtapi_print_msg(msg_level_t level, const char *fmt, ...) { - (void)fmt; - if (level == RTAPI_MSG_ERR) errors++; -} - -static int write_word(hm2_lowlevel_io_t *io, rtapi_u32 addr, const void *data, int size) { - (void)io; - (void)addr; - (void)data; - assert(size == sizeof(rtapi_u32)); - writes++; - return 1; -} - -static void test_rate(int mux, int force, unsigned clock, unsigned width, unsigned requested) { - rtapi_uint rate = requested, fast = 1, slow = 1, off = 0; - rtapi_u32 control = 0, mpg = 0, filter = 0; - hm2_lowlevel_io_t llio = {.write = write_word}; - hm2_inm_instance_t inm = {.scanwidth = width}; - hm2_inmux_instance_t inmux = {.scanwidth = width}; - hostmot2_t board = {.llio = &llio}; - board.inm.num_instances = board.inmux.num_instances = 1; - board.inm.clock_frequency = board.inmux.clock_frequency = clock; - board.inm.instance = &inm; - board.inmux.instance = &inmux; - board.inm.control_reg = board.inmux.control_reg = &control; - board.inm.mpg_mode_reg = board.inmux.mpg_mode_reg = &mpg; - board.inm.filter_reg = board.inmux.filter_reg = &filter; - inm.hal.param.scan_rate = inmux.hal.param.scan_rate = (hal_uint_t)&rate; - inm.hal.param.fast_scans = inmux.hal.param.fast_scans = (hal_uint_t)&fast; - inm.hal.param.slow_scans = inmux.hal.param.slow_scans = (hal_uint_t)&slow; - inmux.hal.param.enc0_mode = inmux.hal.param.enc1_mode = - inmux.hal.param.enc2_mode = inmux.hal.param.enc3_mode = (hal_bool_t)&off; - for (unsigned i = 0; i < 32; i++) inmux.hal.pin.slow[i] = (hal_bool_t)&off; - - void (*write)(hostmot2_t *) = mux ? hm2_inmux_write : hm2_inm_write; - void (*force_write)(hostmot2_t *) = mux ? hm2_inmux_force_write : hm2_inm_force_write; - unsigned minimum = (clock + 4096u * width - 1) / (4096u * width); - unsigned expected = requested <= 1 ? minimum : requested; - unsigned divisor = requested <= 1 ? 1023 : clock / (4u * width * requested) - 1; - errors = writes = 0; - (force ? force_write : write)(&board); - assert(hal_get_ui32(inm.hal.param.scan_rate) == expected); - assert(control == ((1u << 5) | (divisor << 6) | (1u << 16) | (1u << 22))); - assert(errors == (!force && requested <= 1 ? 1u : 0u)); - - // A normalized rate must stay in range without repeated diagnostics or writes. - errors = 0; - write(&board); - divisor = clock / (4u * width * expected) - 1; - assert(divisor <= 1023); - assert(control == ((1u << 5) | (divisor << 6) | (1u << 16) | (1u << 22))); - unsigned settled_writes = writes; - for (unsigned cycle = 0; cycle < 5; cycle++) { - write(&board); - assert(hal_get_ui32(inm.hal.param.scan_rate) == expected); - assert(errors == 0 && writes == settled_writes); - } -} - -int main(void) { - const unsigned clocks[] = {32768000, 50000000, 100000000}; - for (int mux = 0; mux <= 1; mux++) { - for (int force = 0; force <= 1; force++) { - for (unsigned c = 0; c < sizeof(clocks) / sizeof(clocks[0]); c++) { - for (unsigned width = 1; width <= 32; width++) { - unsigned minimum = (clocks[c] + 4096u * width - 1) / (4096u * width); - const unsigned rates[] = {0, 1, minimum, 50000}; - for (unsigned r = 0; r < sizeof(rates) / sizeof(rates[0]); r++) - test_rate(mux, force, clocks[c], width, rates[r]); - } - } - } - } - puts("PASS: INM/INMUX scan-rate bounds, startup/runtime clamps and repeated cycles for widths 1..32"); - return 0; -} diff --git a/tests/hostmot2/serial/test.c b/tests/hostmot2/serial/test.c deleted file mode 100644 index 0bc3f45ef35..00000000000 --- a/tests/hostmot2/serial/test.c +++ /dev/null @@ -1,151 +0,0 @@ -#include -#include -#include -#include "hostmot2.h" -#include "hostmot2-serial.h" - -static hostmot2_t board; -static hm2_lowlevel_io_t llio; -static hm2_uart_instance_t uart; -static hm2_bspi_instance_t bspi; -static unsigned writes, calls, fail_at; -static int io_success = 1; -static rtapi_u32 read_count; -static rtapi_u32 rx_bitrate, tx_bitrate; -static rtapi_u32 words[16]; -static int lookup_result; -int hm2_get_uart(hostmot2_t **hm2, const char *name) { - (void)name; *hm2 = &board; return lookup_result; -} -int hm2_get_bspi(hostmot2_t **hm2, const char *name) { - (void)name; *hm2 = &board; return lookup_result; -} -void rtapi_print_msg(msg_level_t level, const char *fmt, ...) { - (void)level; (void)fmt; -} -int hm2_register_tram_read_region(hostmot2_t *h, rtapi_u16 a, rtapi_u16 s, rtapi_u32 **b) { - (void)h; (void)a; (void)s; (void)b; return 0; -} -int hm2_register_tram_write_region(hostmot2_t *h, rtapi_u16 a, rtapi_u16 s, rtapi_u32 **b) { - (void)h; (void)a; (void)s; (void)b; return 0; -} -static int write_word(hm2_lowlevel_io_t *io, rtapi_u32 a, const void *data, int size) { - (void)io; - assert(size == 4 && writes < 16); - calls++; - if (fail_at && calls == fail_at) return 0; - memcpy(&words[writes++], data, 4); - if (a == uart.rx_bitrate_addr) memcpy(&rx_bitrate, data, 4); - if (a == uart.tx_bitrate_addr) memcpy(&tx_bitrate, data, 4); - return io_success; -} - -static int read_word(hm2_lowlevel_io_t *io, rtapi_u32 addr, void *data, int size) { - (void)io; assert(size == 4); - calls++; - if (fail_at && calls == fail_at) return 0; - rtapi_u32 word = addr == uart.rx_fifo_count_addr ? read_count : 0x42424242; - memcpy(data, &word, 4); - return io_success; -} -static void test_failures(void) { - unsigned char data[8] = {0}; - uart.clock_freq = 50000000; - uart.rx_fifo_count_addr = 0x100; - uart.rx1_addr = 0x110; uart.rx2_addr = 0x120; - uart.rx3_addr = 0x130; uart.rx4_addr = 0x140; - uart.rx_bitrate_addr = 0x150; uart.tx_bitrate_addr = 0x160; - llio.read = read_word; - for (unsigned success = 1; success <= 2; success++) { - io_success = success; - uart.bitrate = 115200; - for (unsigned size = 1; size <= 8; size++) { - for (fail_at = 1; fail_at <= (size + 3) / 4; fail_at++) { - calls = writes = 0; - assert(hm2_uart_send("test", data, size) == -1); - assert(calls == fail_at); - } - read_count = size; - for (fail_at = 1; fail_at <= (size + 3) / 4 + 1; fail_at++) { - calls = 0; - assert(hm2_uart_read("test", data) == -1); - assert(calls == fail_at); - } - } - for (unsigned fail = 1; fail <= 7; fail++) { - uart.bitrate = 0; - fail_at = fail; calls = writes = 0; - assert(hm2_uart_setup("test", 115200, 0, 0) == -1); - assert(calls == fail); - if (fail <= 5) assert(uart.bitrate == 0); - fail_at = 0; calls = writes = 0; - assert(hm2_uart_setup("test", 115200, 0, 0) == 0); - assert(calls == (fail <= 5 ? 7 : 2)); - } - for (unsigned fail = 1; fail <= 5; fail++) { - rtapi_u32 original = uart.bitrate; - fail_at = fail; calls = writes = 0; - assert(hm2_uart_setup("test", 230400, 0, 0) == -1); - assert(calls == fail && uart.bitrate == 0); - fail_at = 0; calls = writes = 0; - assert(hm2_uart_setup("test", 115200, 0, 0) == 0); - assert(calls == 7 && uart.bitrate == original); - assert(rx_bitrate == original && tx_bitrate == original); - } - bspi.conf_flag[0] = true; - calls = writes = 0; fail_at = 1; - assert(hm2_bspi_write_chan("test", 0, 0) == -1); - calls = 0; - assert(hm2_bspi_clear_fifo("test") == -1); - fail_at = 0; calls = writes = 0; - assert(hm2_bspi_write_chan("test", 0, 0) == io_success); - assert(hm2_bspi_clear_fifo("test") == io_success); - } - for (unsigned size = 0; size <= 8; size++) { - read_count = size; - assert(hm2_uart_read("test", data) == (int)size); - for (unsigned i = 0; i < size; i++) assert(data[i] == 0x42); - } - puts("PASS: UART/BSPI boolean I/O failures, setup retries and rollback, successful API returns"); -} - -int main(void) { - board.llio = &llio; - board.uart.instance = &uart; - board.bspi.instance = &bspi; - llio.write = write_word; - unsigned char data[8] = {0}; - lookup_result = -1; - for (unsigned i = 0; i < 3; i++) assert(hm2_uart_send("test", data, 4) == -1); - lookup_result = 0; - for (unsigned i = 0; i < 3; i++) assert(hm2_uart_send("test", data, 4) == -1); - uart.bitrate = 115200; - assert(hm2_uart_send("test", data, -1) == -1); - assert(writes == 0); - for (unsigned byte = 0; byte <= 255; byte++) { - memset(data, byte, sizeof(data)); - for (unsigned size = 0; size <= 8; size++) { - writes = 0; - assert(hm2_uart_send("test", data, size) == (int)size); - assert(writes == (size + 3) / 4); - for (unsigned i = 0; i < writes; i++) { - rtapi_u32 expected = 0; - for (unsigned j = 0; j < 4 && i * 4 + j < size; j++) - expected |= (rtapi_u32)byte << (j * 8); - assert(words[i] == expected); - } - } - } - int channels[] = {-1, 16, 1000}; - writes = 0; - for (unsigned i = 0; i < sizeof(channels) / sizeof(channels[0]); i++) { - assert(hm2_bspi_write_chan("test", channels[i], 0) == -1); - assert(hm2_tram_add_bspi_frame("test", channels[i], NULL, NULL) == -1); - } - assert(hm2_bspi_setup_chan("test", 0, 0, 8, 0.0, 0, 0, 0, 0, 0, 0) == -1); - assert(hm2_bspi_setup_chan("test", 0, 0, 8, -1.0, 0, 0, 0, 0, 0, 0) == -1); - assert(writes == 0); - puts("PASS: repeated UART errors, 2304 packing cases, BSPI channel and frequency error returns"); - test_failures(); - return 0; -} diff --git a/tests/hostmot2/serial/test.sh b/tests/hostmot2/serial/test.sh deleted file mode 100644 index 98ad3c887d3..00000000000 --- a/tests/hostmot2/serial/test.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -set -eu -repo_root=$(cd "$(dirname "$0")/../../.." && pwd) -task_tmp=$(mktemp -d) -trap 'rm -f "$task_tmp/check" "$task_tmp/scanrates"; rmdir "$task_tmp"' EXIT -make_args=(-s --no-print-directory -C "$repo_root/src" -f Makefile - -f "$repo_root/tests/hostmot2/harness.mk" -o Makefile -o Makefile.inc - TRIVIAL_BUILD=yes) -if [ -n "${CC:-}" ]; then make_args+=("CC=$CC"); fi -make "${make_args[@]}" hm2-test \ - "TEST_SOURCES=hal/drivers/mesa-hostmot2/uart.c hal/drivers/mesa-hostmot2/bspi.c ../tests/hostmot2/serial/test.c" \ - "TEST_OUTPUT=$task_tmp/check" >&2 -"$task_tmp/check" -make "${make_args[@]}" hm2-test \ - "TEST_SOURCES=hal/drivers/mesa-hostmot2/inm.c hal/drivers/mesa-hostmot2/inmux.c ../tests/hostmot2/serial/scanrate-test.c" \ - "TEST_OUTPUT=$task_tmp/scanrates" >&2 -"$task_tmp/scanrates" From 439d27a2e7b46a925992f5a93d874558c5161bd6 Mon Sep 17 00:00:00 2001 From: joseph calderon Date: Sun, 1 Nov 2026 08:23:35 -0800 Subject: [PATCH 14/14] hostmot2: restore original whitespace --- src/hal/drivers/mesa-hostmot2/bspi.c | 3 +++ src/hal/drivers/mesa-hostmot2/inm.c | 3 ++- src/hal/drivers/mesa-hostmot2/inmux.c | 1 + src/hal/drivers/mesa-hostmot2/resolver.c | 4 ++-- src/hal/drivers/mesa-hostmot2/uart.c | 11 +++++++---- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/bspi.c b/src/hal/drivers/mesa-hostmot2/bspi.c index 3b6c7df5921..7d3d043af10 100644 --- a/src/hal/drivers/mesa-hostmot2/bspi.c +++ b/src/hal/drivers/mesa-hostmot2/bspi.c @@ -402,3 +402,6 @@ void hm2_bspi_write(hostmot2_t *hm2) { (void)hm2; } + + + diff --git a/src/hal/drivers/mesa-hostmot2/inm.c b/src/hal/drivers/mesa-hostmot2/inm.c index 6c40735a089..ecb935cf634 100644 --- a/src/hal/drivers/mesa-hostmot2/inm.c +++ b/src/hal/drivers/mesa-hostmot2/inm.c @@ -419,7 +419,7 @@ void hm2_inm_force_write(hostmot2_t *hm2) { for (i = 0; i < hm2->inm.num_instances; i ++) { hm2_inm_instance_t *inst = &hm2->inm.instance[i]; scanrate = inst->scanwidth * hal_get_ui32(inst->hal.param.scan_rate); - if (scanrate > 10000000) { + if (scanrate > 10000000) { scanrate = 10000000; hal_set_ui32(inst->hal.param.scan_rate, scanrate/inst->scanwidth); } @@ -684,3 +684,4 @@ void hm2_inm_print_module(hostmot2_t *hm2) { + diff --git a/src/hal/drivers/mesa-hostmot2/inmux.c b/src/hal/drivers/mesa-hostmot2/inmux.c index 9cbf93e1aac..833bea8907e 100644 --- a/src/hal/drivers/mesa-hostmot2/inmux.c +++ b/src/hal/drivers/mesa-hostmot2/inmux.c @@ -582,3 +582,4 @@ void hm2_inmux_print_module(hostmot2_t *hm2) { + diff --git a/src/hal/drivers/mesa-hostmot2/resolver.c b/src/hal/drivers/mesa-hostmot2/resolver.c index bf96d4a87bf..74df77a44e6 100644 --- a/src/hal/drivers/mesa-hostmot2/resolver.c +++ b/src/hal/drivers/mesa-hostmot2/resolver.c @@ -342,8 +342,7 @@ void hm2_resolver_process_tram_read(hostmot2_t *hm2, long period) { } else if ((res->old_reg < hm2->resolver.position_reg[i]) && (hm2->resolver.position_reg[i] - res->old_reg > 0x80000000)){ res->index_cnts--; - if (hal_get_bool(res->hal.pin.index_enable) - && (res->index_cnts % index_div == 0)){ + if (hal_get_bool(res->hal.pin.index_enable) && (res->index_cnts % index_div == 0)){ res->offset = (res->accum - hm2->resolver.position_reg[i] + 0x100000000LL); hal_set_bool(res->hal.pin.index_enable, 0); } @@ -469,3 +468,4 @@ void hm2_resolver_print_module(hostmot2_t *hm2) { (hm2->resolver.velocity_reg[i])); } } + diff --git a/src/hal/drivers/mesa-hostmot2/uart.c b/src/hal/drivers/mesa-hostmot2/uart.c index 3323fcd1e48..1e0758545ec 100644 --- a/src/hal/drivers/mesa-hostmot2/uart.c +++ b/src/hal/drivers/mesa-hostmot2/uart.c @@ -177,6 +177,7 @@ int hm2_uart_setup(char *name, int bitrate, rtapi_s32 tx_mode, rtapi_s32 rx_mode if (hm2->llio->write(hm2->llio, inst->rx_mode_addr, &buff, sizeof(buff)) == 0) goto fail; } + return 0; fail: @@ -203,7 +204,7 @@ int hm2_uart_send(char *name, unsigned char data[], int count) } if (hm2->uart.instance[inst].bitrate == 0){ if (!err_flag) - HM2_ERR("The selected UART instance %s.\n" + HM2_ERR("The selected UART instance %s.\n" "Has not been configured.\n", name); err_flag = 1; // don't fill dmesg with junk. return -1; @@ -213,7 +214,7 @@ int hm2_uart_send(char *name, unsigned char data[], int count) c = 0; err_flag = 0; while (c < count - 3){ - buff = (data[c] + + buff = (data[c] + (data[c+1] << 8) + (data[c+2] << 16) + ((rtapi_u32)data[c+3] << 24)); @@ -239,7 +240,7 @@ int hm2_uart_send(char *name, unsigned char data[], int count) return c + 1; } case 2: - buff = (data[c] + + buff = (data[c] + (data[c+1] << 8)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx2_addr, &buff, sizeof(rtapi_u32)); @@ -250,7 +251,7 @@ int hm2_uart_send(char *name, unsigned char data[], int count) return c + 2; } case 3: - buff = (data[c] + + buff = (data[c] + (data[c+1] << 8) + (data[c+2] << 16)); r = hm2->llio->write(hm2->llio, hm2->uart.instance[inst].tx3_addr, @@ -299,6 +300,7 @@ int hm2_uart_read(char *name, unsigned char data[]) HM2_ERR("UART: hm2->llio->read failure %s\n", name); return -1; } + count = buff & 0x1F; c = 0; while (c < count - 3 && c < 16){ @@ -382,3 +384,4 @@ void hm2_uart_write(hostmot2_t *hm2) { (void)hm2; } +