diff --git a/include/thingset/can.h b/include/thingset/can.h index 78fecac..c58046b 100644 --- a/include/thingset/can.h +++ b/include/thingset/can.h @@ -271,6 +271,7 @@ struct thingset_can #ifdef CONFIG_THINGSET_CAN_CONTROL_REPORTING int64_t next_control_report_time; #endif + struct k_timer timeout_timer; uint8_t node_addr; /** bus or bridge number */ uint8_t route; @@ -358,11 +359,12 @@ int thingset_can_set_item_rx_callback_inst(struct thingset_can *ts_can, * @param ts_can Pointer to the thingset_can context. * @param can_dev Pointer to the CAN device that should be used. * @param bus_number Assigned bus number of this CAN device (ignored if bridge routing is used) + * @param timeout Initialisation timeout. Set to K_FOREVER for no timeout. * * @returns 0 for success or negative errno in case of error */ int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can_dev, - uint8_t bus_number); + uint8_t bus_number, k_timeout_t timeout); #else /* !CONFIG_THINGSET_CAN_MULTIPLE_INSTANCES */ diff --git a/src/can.c b/src/can.c index 8c2d164..88c554c 100644 --- a/src/can.c +++ b/src/can.c @@ -22,9 +22,10 @@ LOG_MODULE_REGISTER(thingset_can, CONFIG_THINGSET_SDK_LOG_LEVEL); extern uint8_t eui64[8]; -#define EVENT_ADDRESS_CLAIM_MSG_SENT 0x01 -#define EVENT_ADDRESS_CLAIMING_FINISHED 0x02 -#define EVENT_ADDRESS_ALREADY_USED 0x03 +#define EVENT_ADDRESS_CLAIM_MSG_SENT BIT(1) +#define EVENT_ADDRESS_CLAIMING_FINISHED BIT(2) +#define EVENT_ADDRESS_ALREADY_USED BIT(3) +#define EVENT_ADDRESS_CLAIM_TIMED_OUT BIT(4) #ifdef CONFIG_THINGSET_CAN_ITEM_RX static const struct can_filter sf_report_filter = { @@ -120,6 +121,13 @@ static void thingset_can_addr_claim_tx_cb(const struct device *dev, int error, v } } +static void thingset_can_addr_discovery_tx_cb(const struct device *dev, int error, void *user_data) +{ + if (error != 0) { + LOG_ERR("Address discovery failed with %d", error); + } +} + static void thingset_can_addr_claim_tx_handler(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); @@ -565,8 +573,14 @@ static void thingset_can_reqresp_sent_callback(int result, void *arg) } } +static void thingset_can_timeout_timer_expired(struct k_timer *timer) +{ + struct thingset_can *ts_can = CONTAINER_OF(timer, struct thingset_can, timeout_timer); + k_event_set(&ts_can->events, EVENT_ADDRESS_CLAIM_TIMED_OUT); +} + int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can_dev, - uint8_t bus_number) + uint8_t bus_number, k_timeout_t timeout) { struct can_frame tx_frame = { .flags = CAN_FRAME_IDE, @@ -586,6 +600,7 @@ int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can #endif k_sem_init(&ts_can->request_response.sem, 1, 1); k_sem_init(&ts_can->report_tx_sem, 0, 1); + k_timer_init(&ts_can->timeout_timer, thingset_can_timeout_timer_expired, NULL); #ifdef CONFIG_THINGSET_SUBSET_LIVE_METRICS k_work_init_delayable(&ts_can->live_reporting_work, thingset_can_live_reporting_handler); @@ -604,6 +619,7 @@ int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can } k_event_init(&ts_can->events); + k_timer_start(&ts_can->timeout_timer, timeout, K_NO_WAIT); #ifdef CONFIG_CAN_FD_MODE can_mode_t supported_modes; @@ -646,11 +662,14 @@ int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can can_add_rx_filter(ts_can->dev, thingset_can_addr_claim_rx_cb, ts_can, &addr_claim_filter); if (filter_id < 0) { LOG_ERR("Unable to add addr_claim filter: %d", filter_id); + k_timer_stop(&ts_can->timeout_timer); return filter_id; } while (1) { - k_event_clear(&ts_can->events, EVENT_ADDRESS_ALREADY_USED); + k_event_clear(&ts_can->events, EVENT_ADDRESS_CLAIM_MSG_SENT + | EVENT_ADDRESS_CLAIMING_FINISHED + | EVENT_ADDRESS_ALREADY_USED); /* send out address discovery frame */ uint8_t rand = sys_rand32_get() & 0xFF; @@ -658,15 +677,17 @@ int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can | THINGSET_CAN_RAND_SET(rand) | THINGSET_CAN_TARGET_SET(ts_can->node_addr) | THINGSET_CAN_SOURCE_SET(THINGSET_CAN_ADDR_ANONYMOUS); tx_frame.dlc = 0; - err = can_send(ts_can->dev, &tx_frame, K_MSEC(10), NULL, NULL); + err = + can_send(ts_can->dev, &tx_frame, K_MSEC(10), thingset_can_addr_discovery_tx_cb, ts_can); if (err != 0) { k_sleep(K_MSEC(100)); continue; } /* wait 500 ms for address claim message from other node */ - uint32_t event = - k_event_wait(&ts_can->events, EVENT_ADDRESS_ALREADY_USED, false, K_MSEC(500)); + uint32_t event = k_event_wait(&ts_can->events, + EVENT_ADDRESS_ALREADY_USED | EVENT_ADDRESS_CLAIM_TIMED_OUT, + false, K_MSEC(500)); if (event & EVENT_ADDRESS_ALREADY_USED) { /* try again with new random node_addr between 0x01 and 0xFD */ ts_can->node_addr = @@ -674,14 +695,26 @@ int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can + sys_rand32_get() % (THINGSET_CAN_ADDR_MAX - THINGSET_CAN_ADDR_MIN); LOG_WRN("Node addr already in use, trying 0x%.2X", ts_can->node_addr); } + else if (event & EVENT_ADDRESS_CLAIM_TIMED_OUT) { + LOG_ERR("Address claim timed out"); + k_timer_stop(&ts_can->timeout_timer); + return -ETIMEDOUT; + } else { struct can_bus_err_cnt err_cnt_before; can_get_state(ts_can->dev, NULL, &err_cnt_before); thingset_sdk_reschedule_work(&ts_can->addr_claim_work, K_NO_WAIT); - event = k_event_wait(&ts_can->events, EVENT_ADDRESS_CLAIM_MSG_SENT, false, K_MSEC(100)); - if (!(event & EVENT_ADDRESS_CLAIM_MSG_SENT)) { + event = k_event_wait(&ts_can->events, + EVENT_ADDRESS_CLAIM_MSG_SENT | EVENT_ADDRESS_CLAIM_TIMED_OUT, + false, K_MSEC(100)); + if (event & EVENT_ADDRESS_CLAIM_TIMED_OUT) { + LOG_ERR("Address claim timed out"); + k_timer_stop(&ts_can->timeout_timer); + return -ETIMEDOUT; + } + else if (!(event & EVENT_ADDRESS_CLAIM_MSG_SENT)) { k_sleep(K_MSEC(100)); continue; } @@ -692,6 +725,7 @@ int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can if (err_cnt_after.tx_err_cnt <= err_cnt_before.tx_err_cnt) { /* address claiming is finished */ k_event_post(&ts_can->events, EVENT_ADDRESS_CLAIMING_FINISHED); + k_timer_stop(&ts_can->timeout_timer); LOG_INF("Using CAN node address 0x%.2X on %s", ts_can->node_addr, ts_can->dev->name); break; @@ -851,7 +885,8 @@ static void thingset_can_thread() int err; LOG_DBG("Initialising ThingSet CAN"); - err = thingset_can_init_inst(&ts_can_single, can_dev, CONFIG_THINGSET_CAN_DEFAULT_ROUTE); + err = thingset_can_init_inst(&ts_can_single, can_dev, CONFIG_THINGSET_CAN_DEFAULT_ROUTE, + K_FOREVER); if (err != 0) { LOG_ERR("Failed to init ThingSet CAN: %d", err); return;