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 c48493c9c83..f01ecab7809 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); @@ -187,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; @@ -205,14 +210,19 @@ 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); 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; @@ -247,6 +257,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 +402,3 @@ 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 596b9e2ba02..6c40735a089 100644 --- a/src/hal/drivers/mesa-hostmot2/inm.c +++ b/src/hal/drivers/mesa-hostmot2/inm.c @@ -419,11 +419,25 @@ 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; + // 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); + } 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 - 1) + / (4 * (divisor + 1) * inst->scanwidth) + 1); + } + } 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 +486,24 @@ 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); + // 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 - 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)); + } } rtapi_u32 fast_scans = hal_get_ui32(inst->hal.param.fast_scans); if (fast_scans > 63) { @@ -659,4 +684,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..9cbf93e1aac 100644 --- a/src/hal/drivers/mesa-hostmot2/inmux.c +++ b/src/hal/drivers/mesa-hostmot2/inmux.c @@ -348,7 +348,21 @@ 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; + // Round up so the normalized rate stays within the divisor limit. + hal_set_ui32(inst->hal.param.scan_rate, + (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 - 1) + / (4 * (divisor + 1) * inst->scanwidth) + 1); + } + } 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 +408,24 @@ 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; + // 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 - 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)); + } } rtapi_u32 fast_scans = hal_get_ui32(inst->hal.param.fast_scans); if (fast_scans > 63) { @@ -557,4 +582,3 @@ void hm2_inmux_print_module(hostmot2_t *hm2) { - 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) { 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])); } } - 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); 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 diff --git a/src/hal/drivers/mesa-hostmot2/uart.c b/src/hal/drivers/mesa-hostmot2/uart.c index 0ca9ed6a5a5..99807b6c540 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,39 @@ 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; + 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, + &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; } @@ -189,30 +195,33 @@ 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; } - 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; } + if (count < 0) return -1; 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) { + if (r <= 0) { HM2_ERR("UART WRITE: hm2->llio->write failure %s\n", name); - return r; + return -1; } c = c + 4; } @@ -223,32 +232,32 @@ 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; } 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){ + if (r <= 0){ HM2_ERR("UART_WRITE: hm2->llio->write failure %s\n", name); - return r; + return -1; }else{ 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){ + if (r <= 0){ HM2_ERR("UART WRITE: hm2->llio->write failure %s\n", name); - return r; + return -1; }else{ return c + 3; } @@ -286,16 +295,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); @@ -311,18 +323,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; @@ -330,9 +342,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; @@ -370,4 +382,3 @@ void hm2_uart_write(hostmot2_t *hm2) { (void)hm2; } - diff --git a/tests/hostmot2/serial/README b/tests/hostmot2/serial/README new file mode 100644 index 00000000000..b28d41a57c1 --- /dev/null +++ b/tests/hostmot2/serial/README @@ -0,0 +1,21 @@ +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 + +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. +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 new file mode 100644 index 00000000000..e936446b4f9 --- /dev/null +++ b/tests/hostmot2/serial/expected @@ -0,0 +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.c b/tests/hostmot2/serial/test.c new file mode 100644 index 00000000000..088001e2db7 --- /dev/null +++ b/tests/hostmot2/serial/test.c @@ -0,0 +1,151 @@ +#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 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 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; +} + +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; + 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; + 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; 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..6df45073c2e --- /dev/null +++ b/tests/hostmot2/serial/test.sh @@ -0,0 +1,20 @@ +#!/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 +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" +"$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"