diff --git a/drivers/can/can_handlers.c b/drivers/can/can_handlers.c index 208eadce4d6..4fa1f47ef7f 100644 --- a/drivers/can/can_handlers.c +++ b/drivers/can/can_handlers.c @@ -81,21 +81,24 @@ static inline void z_vrfy_can_remove_rx_filter(const struct device *dev, int fil #include static inline -enum can_state z_vrfy_can_get_state(const struct device *dev, - struct can_bus_err_cnt *err_cnt) +int z_vrfy_can_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); - if (err_cnt) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(err_cnt, sizeof(err_cnt))); + if (state != NULL) { + Z_OOPS(Z_SYSCALL_MEMORY_WRITE(state, sizeof(enum can_state))); } - return z_impl_can_get_state(dev, err_cnt); + if (err_cnt != NULL) { + Z_OOPS(Z_SYSCALL_MEMORY_WRITE(err_cnt, sizeof(struct can_bus_err_cnt))); + } + + return z_impl_can_get_state(dev, state, err_cnt); } #include - #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY static inline int z_vrfy_can_recover(const struct device *dev, k_timeout_t timeout) diff --git a/drivers/can/can_loopback.c b/drivers/can/can_loopback.c index 67e7ecd7ff0..cb3f189ee94 100644 --- a/drivers/can/can_loopback.c +++ b/drivers/can/can_loopback.c @@ -212,17 +212,21 @@ int can_loopback_set_timing(const struct device *dev, return 0; } -static enum can_state can_loopback_get_state(const struct device *dev, - struct can_bus_err_cnt *err_cnt) +static int can_loopback_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { ARG_UNUSED(dev); + if (state != NULL) { + *state = CAN_ERROR_ACTIVE; + } + if (err_cnt) { err_cnt->tx_err_cnt = 0; err_cnt->rx_err_cnt = 0; } - return CAN_ERROR_ACTIVE; + return 0; } #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY diff --git a/drivers/can/can_mcan.c b/drivers/can/can_mcan.c index 7fe39ff1027..9178eaf8f3a 100644 --- a/drivers/can/can_mcan.c +++ b/drivers/can/can_mcan.c @@ -451,7 +451,7 @@ static void can_mcan_state_change_handler(const struct can_mcan_config *cfg, const can_state_change_callback_t cb = data->state_change_cb; void *cb_data = data->state_change_cb_data; - state = can_mcan_get_state(cfg, &err_cnt); + (void)can_mcan_get_state(cfg, &state, &err_cnt); if (cb != NULL) { cb(state, err_cnt, cb_data); @@ -642,30 +642,32 @@ void can_mcan_line_1_isr(const struct can_mcan_config *cfg, CAN_MCAN_IR_RF0L | CAN_MCAN_IR_RF1L)); } -enum can_state can_mcan_get_state(const struct can_mcan_config *cfg, - struct can_bus_err_cnt *err_cnt) +int can_mcan_get_state(const struct can_mcan_config *cfg, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { struct can_mcan_reg *can = cfg->can; - err_cnt->rx_err_cnt = (can->ecr & CAN_MCAN_ECR_TEC_MSK) << - CAN_MCAN_ECR_TEC_POS; - - err_cnt->tx_err_cnt = (can->ecr & CAN_MCAN_ECR_REC_MSK) << - CAN_MCAN_ECR_REC_POS; - - if (can->psr & CAN_MCAN_PSR_BO) { - return CAN_BUS_OFF; + if (state != NULL) { + if (can->psr & CAN_MCAN_PSR_BO) { + *state = CAN_BUS_OFF; + } else if (can->psr & CAN_MCAN_PSR_EP) { + *state = CAN_ERROR_PASSIVE; + } else if (can->psr & CAN_MCAN_PSR_EW) { + *state = CAN_ERROR_WARNING; + } else { + *state = CAN_ERROR_ACTIVE; + } } - if (can->psr & CAN_MCAN_PSR_EP) { - return CAN_ERROR_PASSIVE; + if (err_cnt != NULL) { + err_cnt->rx_err_cnt = (can->ecr & CAN_MCAN_ECR_TEC_MSK) << + CAN_MCAN_ECR_TEC_POS; + + err_cnt->tx_err_cnt = (can->ecr & CAN_MCAN_ECR_REC_MSK) << + CAN_MCAN_ECR_REC_POS; } - if (can->psr & CAN_MCAN_PSR_EW) { - return CAN_ERROR_WARNING; - } - - return CAN_ERROR_ACTIVE; + return 0; } #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY diff --git a/drivers/can/can_mcan.h b/drivers/can/can_mcan.h index 0e0bd6e9608..dd8cce64a13 100644 --- a/drivers/can/can_mcan.h +++ b/drivers/can/can_mcan.h @@ -238,7 +238,7 @@ int can_mcan_add_rx_filter(struct can_mcan_data *data, void can_mcan_remove_rx_filter(struct can_mcan_data *data, struct can_mcan_msg_sram *msg_ram, int filter_id); -enum can_state can_mcan_get_state(const struct can_mcan_config *cfg, - struct can_bus_err_cnt *err_cnt); +int can_mcan_get_state(const struct can_mcan_config *cfg, enum can_state *state, + struct can_bus_err_cnt *err_cnt); #endif /* ZEPHYR_DRIVERS_CAN_MCAN_H_ */ diff --git a/drivers/can/can_mcp2515.c b/drivers/can/can_mcp2515.c index 3fbae2f5163..d538f4105dd 100644 --- a/drivers/can/can_mcp2515.c +++ b/drivers/can/can_mcp2515.c @@ -649,8 +649,8 @@ static void mcp2515_tx_done(const struct device *dev, uint8_t tx_idx) k_sem_give(&dev_data->tx_sem); } -static enum can_state mcp2515_get_state(const struct device *dev, - struct can_bus_err_cnt *err_cnt) +static int mcp2515_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { uint8_t eflg; uint8_t err_cnt_buf[2]; @@ -659,34 +659,34 @@ static enum can_state mcp2515_get_state(const struct device *dev, ret = mcp2515_cmd_read_reg(dev, MCP2515_ADDR_EFLG, &eflg, sizeof(eflg)); if (ret < 0) { LOG_ERR("Failed to read error register [%d]", ret); - return CAN_BUS_UNKNOWN; + return -EIO; } - if (err_cnt) { + if (state != NULL) { + if (eflg & MCP2515_EFLG_TXBO) { + *state = CAN_BUS_OFF; + } else if ((eflg & MCP2515_EFLG_RXEP) || (eflg & MCP2515_EFLG_TXEP)) { + *state = CAN_ERROR_PASSIVE; + } else if (eflg & MCP2515_EFLG_EWARN) { + *state = CAN_ERROR_WARNING; + } else { + *state = CAN_ERROR_ACTIVE; + } + } + + if (err_cnt != NULL) { ret = mcp2515_cmd_read_reg(dev, MCP2515_ADDR_TEC, err_cnt_buf, sizeof(err_cnt_buf)); if (ret < 0) { LOG_ERR("Failed to read error counters [%d]", ret); - return CAN_BUS_UNKNOWN; + return -EIO; } err_cnt->tx_err_cnt = err_cnt_buf[0]; err_cnt->rx_err_cnt = err_cnt_buf[1]; } - if (eflg & MCP2515_EFLG_TXBO) { - return CAN_BUS_OFF; - } - - if ((eflg & MCP2515_EFLG_RXEP) || (eflg & MCP2515_EFLG_TXEP)) { - return CAN_ERROR_PASSIVE; - } - - if (eflg & MCP2515_EFLG_EWARN) { - return CAN_ERROR_WARNING; - } - - return CAN_ERROR_ACTIVE; + return 0; } static void mcp2515_handle_errors(const struct device *dev) @@ -696,8 +696,13 @@ static void mcp2515_handle_errors(const struct device *dev) void *state_change_cb_data = dev_data->state_change_cb_data; enum can_state state; struct can_bus_err_cnt err_cnt; + int err; - state = mcp2515_get_state(dev, state_change_cb ? &err_cnt : NULL); + err = mcp2515_get_state(dev, &state, state_change_cb ? &err_cnt : NULL); + if (err != 0) { + LOG_ERR("Failed to get CAN controller state [%d]", err); + return; + } if (state_change_cb && dev_data->old_state != state) { dev_data->old_state = state; diff --git a/drivers/can/can_mcux_flexcan.c b/drivers/can/can_mcux_flexcan.c index 60af25fac5e..499c1c809a8 100644 --- a/drivers/can/can_mcux_flexcan.c +++ b/drivers/can/can_mcux_flexcan.c @@ -316,32 +316,33 @@ static int mcux_get_tx_alloc(struct mcux_flexcan_data *data) return alloc >= MCUX_FLEXCAN_MAX_TX ? -1 : alloc; } -static enum can_state mcux_flexcan_get_state(const struct device *dev, - struct can_bus_err_cnt *err_cnt) +static int mcux_flexcan_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { const struct mcux_flexcan_config *config = dev->config; uint64_t status_flags; + if (state != NULL) { + status_flags = FLEXCAN_GetStatusFlags(config->base); + + if ((status_flags & CAN_ESR1_FLTCONF(2)) != 0U) { + *state = CAN_BUS_OFF; + } else if ((status_flags & CAN_ESR1_FLTCONF(1)) != 0U) { + *state = CAN_ERROR_PASSIVE; + } else if ((status_flags & + (kFLEXCAN_TxErrorWarningFlag | kFLEXCAN_RxErrorWarningFlag)) != 0) { + *state = CAN_ERROR_WARNING; + } else { + *state = CAN_ERROR_ACTIVE; + } + } + if (err_cnt != NULL) { FLEXCAN_GetBusErrCount(config->base, &err_cnt->tx_err_cnt, &err_cnt->rx_err_cnt); } - status_flags = FLEXCAN_GetStatusFlags(config->base); - - if ((status_flags & CAN_ESR1_FLTCONF(2)) != 0U) { - return CAN_BUS_OFF; - } - - if ((status_flags & CAN_ESR1_FLTCONF(1)) != 0U) { - return CAN_ERROR_PASSIVE; - } - - if ((status_flags & (kFLEXCAN_TxErrorWarningFlag | kFLEXCAN_RxErrorWarningFlag)) != 0) { - return CAN_ERROR_WARNING; - } - - return CAN_ERROR_ACTIVE; + return 0; } static int mcux_flexcan_send(const struct device *dev, @@ -352,6 +353,7 @@ static int mcux_flexcan_send(const struct device *dev, const struct mcux_flexcan_config *config = dev->config; struct mcux_flexcan_data *data = dev->data; flexcan_mb_transfer_t xfer; + enum can_state state; status_t status; int alloc; @@ -360,7 +362,8 @@ static int mcux_flexcan_send(const struct device *dev, return -EINVAL; } - if (mcux_flexcan_get_state(dev, NULL) == CAN_BUS_OFF) { + (void)mcux_flexcan_get_state(dev, &state, NULL); + if (state == CAN_BUS_OFF) { LOG_DBG("Transmit failed, bus-off"); return -ENETDOWN; } @@ -470,10 +473,12 @@ static void mcux_flexcan_set_state_change_callback(const struct device *dev, int mcux_flexcan_recover(const struct device *dev, k_timeout_t timeout) { const struct mcux_flexcan_config *config = dev->config; - int ret = 0; + enum can_state state; uint64_t start_time; + int ret = 0; - if (mcux_flexcan_get_state(dev, NULL) != CAN_BUS_OFF) { + (void)mcux_flexcan_get_state(dev, &state, NULL); + if (state != CAN_BUS_OFF) { return 0; } @@ -481,11 +486,15 @@ int mcux_flexcan_recover(const struct device *dev, k_timeout_t timeout) config->base->CTRL1 &= ~CAN_CTRL1_BOFFREC_MASK; if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { - while (mcux_flexcan_get_state(dev, NULL) == CAN_BUS_OFF) { + (void)mcux_flexcan_get_state(dev, &state, NULL); + + while (state == CAN_BUS_OFF) { if (!K_TIMEOUT_EQ(timeout, K_FOREVER) && k_uptime_ticks() - start_time >= timeout.ticks) { ret = -EAGAIN; } + + (void)mcux_flexcan_get_state(dev, &state, NULL); } } @@ -556,7 +565,7 @@ static inline void mcux_flexcan_transfer_error_status(const struct device *dev, LOG_DBG("RX CRC error (error 0x%016llx)", error); } - state = mcux_flexcan_get_state(dev, &err_cnt); + (void)mcux_flexcan_get_state(dev, &state, &err_cnt); if (data->state != state) { data->state = state; @@ -745,7 +754,8 @@ static int mcux_flexcan_init(const struct device *dev) #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY config->base->CTRL1 |= CAN_CTRL1_BOFFREC_MASK; #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ - data->state = mcux_flexcan_get_state(dev, NULL); + + (void)mcux_flexcan_get_state(dev, &data->state, NULL); return 0; } diff --git a/drivers/can/can_mcux_mcan.c b/drivers/can/can_mcux_mcan.c index 12962348fca..4fcedc6b53f 100644 --- a/drivers/can/can_mcux_mcan.c +++ b/drivers/can/can_mcux_mcan.c @@ -72,12 +72,12 @@ static void mcux_mcan_remove_rx_filter(const struct device *dev, int filter_id) can_mcan_remove_rx_filter(&data->mcan, &data->msg_ram, filter_id); } -static enum can_state mcux_mcan_get_state(const struct device *dev, - struct can_bus_err_cnt *err_cnt) +static int mcux_mcan_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { const struct mcux_mcan_config *config = dev->config; - return can_mcan_get_state(&config->mcan, err_cnt); + return can_mcan_get_state(&config->mcan, state, err_cnt); } static void mcux_mcan_set_state_change_callback(const struct device *dev, diff --git a/drivers/can/can_rcar.c b/drivers/can/can_rcar.c index f4aacbe3f38..d8699d40457 100644 --- a/drivers/can/can_rcar.c +++ b/drivers/can/can_rcar.c @@ -671,16 +671,21 @@ static void can_rcar_set_state_change_callback(const struct device *dev, data->state_change_cb_data = user_data; } -static enum can_state can_rcar_get_state(const struct device *dev, - struct can_bus_err_cnt *err_cnt) +static int can_rcar_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { const struct can_rcar_cfg *config = DEV_CAN_CFG(dev); struct can_rcar_data *data = DEV_CAN_DATA(dev); + if (state != NULL) { + *state = data->state; + } + if (err_cnt != NULL) { can_rcar_get_error_count(config, err_cnt); } - return data->state; + + return 0; } #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY diff --git a/drivers/can/can_sam.c b/drivers/can/can_sam.c index cc0a9b3ae8f..32cf6ec89bc 100644 --- a/drivers/can/can_sam.c +++ b/drivers/can/can_sam.c @@ -71,12 +71,13 @@ static int can_sam_init(const struct device *dev) return ret; } -static enum can_state can_sam_get_state(const struct device *dev, struct can_bus_err_cnt *err_cnt) +static int can_sam_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { const struct can_sam_config *cfg = dev->config; const struct can_mcan_config *mcan_cfg = &cfg->mcan_cfg; - return can_mcan_get_state(mcan_cfg, err_cnt); + return can_mcan_get_state(mcan_cfg, state, err_cnt); } static int can_sam_send(const struct device *dev, const struct zcan_frame *frame, diff --git a/drivers/can/can_stm32.c b/drivers/can/can_stm32.c index 7a72c839cba..e1f4c904252 100644 --- a/drivers/can/can_stm32.c +++ b/drivers/can/can_stm32.c @@ -551,33 +551,32 @@ static void can_stm32_set_state_change_callback(const struct device *dev, } } -static enum can_state can_stm32_get_state(const struct device *dev, - struct can_bus_err_cnt *err_cnt) +static int can_stm32_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { const struct can_stm32_config *cfg = dev->config; CAN_TypeDef *can = cfg->can; - if (err_cnt) { + if (state != NULL) { + if (can->ESR & CAN_ESR_BOFF) { + *state = CAN_BUS_OFF; + } else if (can->ESR & CAN_ESR_EPVF) { + *state = CAN_ERROR_PASSIVE; + } else if (can->ESR & CAN_ESR_EWGF) { + *state = CAN_ERROR_WARNING; + } else { + *state = CAN_ERROR_ACTIVE; + } + } + + if (err_cnt != NULL) { err_cnt->tx_err_cnt = ((can->ESR & CAN_ESR_TEC) >> CAN_ESR_TEC_Pos); err_cnt->rx_err_cnt = ((can->ESR & CAN_ESR_REC) >> CAN_ESR_REC_Pos); } - if (can->ESR & CAN_ESR_BOFF) { - return CAN_BUS_OFF; - } - - if (can->ESR & CAN_ESR_EPVF) { - return CAN_ERROR_PASSIVE; - } - - if (can->ESR & CAN_ESR_EWGF) { - return CAN_ERROR_WARNING; - } - - return CAN_ERROR_ACTIVE; - + return 0; } #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY diff --git a/drivers/can/can_stm32fd.c b/drivers/can/can_stm32fd.c index b7a285178ce..c34fa8ec17d 100644 --- a/drivers/can/can_stm32fd.c +++ b/drivers/can/can_stm32fd.c @@ -90,13 +90,13 @@ static int can_stm32fd_init(const struct device *dev) return ret; } -static enum can_state can_stm32fd_get_state(const struct device *dev, - struct can_bus_err_cnt *err_cnt) +static int can_stm32fd_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { const struct can_stm32fd_config *cfg = dev->config; const struct can_mcan_config *mcan_cfg = &cfg->mcan_cfg; - return can_mcan_get_state(mcan_cfg, err_cnt); + return can_mcan_get_state(mcan_cfg, state, err_cnt); } static int can_stm32fd_send(const struct device *dev, const struct zcan_frame *frame, diff --git a/drivers/can/can_stm32h7.c b/drivers/can/can_stm32h7.c index 3e648ed0c9c..e810d59705c 100644 --- a/drivers/can/can_stm32h7.c +++ b/drivers/can/can_stm32h7.c @@ -120,12 +120,12 @@ static int can_stm32h7_init(const struct device *dev) return 0; } -static enum can_state can_stm32h7_get_state(const struct device *dev, - struct can_bus_err_cnt *err_cnt) +static int can_stm32h7_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { const struct can_stm32h7_config *cfg = dev->config; - return can_mcan_get_state(&cfg->mcan_cfg, err_cnt); + return can_mcan_get_state(&cfg->mcan_cfg, state, err_cnt); } static int can_stm32h7_send(const struct device *dev, diff --git a/include/drivers/can.h b/include/drivers/can.h index b179aa5df54..8d69bf8d4ca 100644 --- a/include/drivers/can.h +++ b/include/drivers/can.h @@ -104,8 +104,6 @@ enum can_state { CAN_ERROR_PASSIVE, /** Bus-off state (RX/TX error count >= 256). */ CAN_BUS_OFF, - /** Bus state unknown. */ - CAN_BUS_UNKNOWN }; /** @@ -347,8 +345,8 @@ typedef int (*can_recover_t)(const struct device *dev, k_timeout_t timeout); * @brief Callback API upon getting the CAN controller state * See @a can_get_state() for argument description */ -typedef enum can_state (*can_get_state_t)(const struct device *dev, - struct can_bus_err_cnt *err_cnt); +typedef int (*can_get_state_t)(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt); /** * @typedef can_set_state_change_callback_t @@ -826,19 +824,21 @@ static inline int z_impl_can_get_max_filters(const struct device *dev, enum can_ * controller. * * @param dev Pointer to the device structure for the driver instance. + * @param[out] state Pointer to the state destination enum or NULL. * @param[out] err_cnt Pointer to the err_cnt destination structure or NULL. * - * @retval state + * @retval 0 If successful. + * @retval -EIO General input/output error, failed to get state. */ -__syscall enum can_state can_get_state(const struct device *dev, - struct can_bus_err_cnt *err_cnt); +__syscall int can_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt); -static inline enum can_state z_impl_can_get_state(const struct device *dev, - struct can_bus_err_cnt *err_cnt) +static inline int z_impl_can_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) { const struct can_driver_api *api = (const struct can_driver_api *)dev->api; - return api->get_state(dev, err_cnt); + return api->get_state(dev, state, err_cnt); } /** diff --git a/modules/canopennode/CO_driver.c b/modules/canopennode/CO_driver.c index e04514f9aea..25eeb041186 100644 --- a/modules/canopennode/CO_driver.c +++ b/modules/canopennode/CO_driver.c @@ -406,6 +406,7 @@ void CO_CANverifyErrors(CO_CANmodule_t *CANmodule) enum can_state state; uint8_t rx_overflows; uint32_t errors; + int err; /* * TODO: Zephyr lacks an API for reading the rx mailbox @@ -413,7 +414,11 @@ void CO_CANverifyErrors(CO_CANmodule_t *CANmodule) */ rx_overflows = 0; - state = can_get_state(CANmodule->dev, &err_cnt); + err = can_get_state(CANmodule->dev, &state, &err_cnt); + if (err != 0) { + LOG_ERR("failed to get CAN controller state (err %d)", err); + return; + } errors = ((uint32_t)err_cnt.tx_err_cnt << 16) | ((uint32_t)err_cnt.rx_err_cnt << 8) | diff --git a/samples/drivers/can/src/main.c b/samples/drivers/can/src/main.c index 75c15bde1a8..e7037807928 100644 --- a/samples/drivers/can/src/main.c +++ b/samples/drivers/can/src/main.c @@ -127,9 +127,16 @@ void poll_state_thread(void *unused1, void *unused2, void *unused3) struct can_bus_err_cnt err_cnt_prev = {0, 0}; enum can_state state_prev = CAN_ERROR_ACTIVE; enum can_state state; + int err; while (1) { - state = can_get_state(can_dev, &err_cnt); + err = can_get_state(can_dev, &state, &err_cnt); + if (err != 0) { + printk("Failed to get CAN controller state: %d", err); + k_sleep(K_MSEC(100)); + continue; + } + if (err_cnt.tx_err_cnt != err_cnt_prev.tx_err_cnt || err_cnt.rx_err_cnt != err_cnt_prev.rx_err_cnt || state_prev != state) {