diff --git a/cy_can/cy_can.c b/cy_can/cy_can.c index 3c5a340..cc5fcbd 100644 --- a/cy_can/cy_can.c +++ b/cy_can/cy_can.c @@ -273,12 +273,11 @@ static bool v_canard_tx(canard_t* const self, cy_can_t* const owner = (cy_can_t*)self->user_context; const uint_least8_t len = (uint_least8_t)can_data.size; (void)user_context; - (void)deadline; assert(iface_index < owner->iface_count); if (fd && (owner->vtable->tx_fd != NULL)) { - return owner->vtable->tx_fd(owner->user, iface_index, extended_can_id, can_data.data, len); + return owner->vtable->tx_fd(owner->user, deadline, iface_index, extended_can_id, can_data.data, len); } - return owner->vtable->tx_classic(owner->user, iface_index, extended_can_id, can_data.data, len); + return owner->vtable->tx_classic(owner->user, deadline, iface_index, extended_can_id, can_data.data, len); } static bool v_canard_filter(canard_t* const self, const size_t filter_count, const canard_filter_t* const filters) diff --git a/cy_can/cy_can.h b/cy_can/cy_can.h index c8a3d6b..74fc5db 100644 --- a/cy_can/cy_can.h +++ b/cy_can/cy_can.h @@ -39,16 +39,26 @@ typedef struct cy_can_rx_t /// All functions are non-blocking except rx(), which may block up to the specified deadline. typedef struct { - /// Transmit a classic CAN frame (up to 8 bytes) on the given interface. + /// Transmit a classic CAN frame (up to 8 bytes) on the given interface before the given deadline. /// Returns true if the frame should be removed from the upstream TX queue (i.e., if the frame was accepted /// for transmission or if it encountered a fatal failure and no further attempts are needed). /// Returns false if the underlying CAN controller is not ready to accept a new frame (e.g., no free TX mailbox); /// the caller will retry later. - bool (*tx_classic)(void* user, uint_least8_t iface_index, uint32_t can_id, const void* data, uint_least8_t len); - - /// Transmit a CAN FD frame (up to 64 bytes) on the given interface. + bool (*tx_classic)(void* user, + canard_us_t deadline, + uint_least8_t iface_index, + uint32_t can_id, + const void* data, + uint_least8_t len); + + /// Transmit a CAN FD frame (up to 64 bytes) on the given interface before the given deadline. /// Set to NULL if the underlying driver does not support CAN FD; all interfaces share the same FD capability. - bool (*tx_fd)(void* user, uint_least8_t iface_index, uint32_t can_id, const void* data, uint_least8_t len); + bool (*tx_fd)(void* user, + canard_us_t deadline, + uint_least8_t iface_index, + uint32_t can_id, + const void* data, + uint_least8_t len); /// Poll all redundant interfaces for a received frame. Returns true if a frame was received. /// The implementation may block up to the given deadline; baremetal implementations may ignore the deadline diff --git a/cy_can/cy_can_socketcan.c b/cy_can/cy_can_socketcan.c index 2589b57..6a6bc56 100644 --- a/cy_can/cy_can_socketcan.c +++ b/cy_can/cy_can_socketcan.c @@ -55,12 +55,14 @@ static cy_us_t socketcan_now(void) // VTABLE IMPLEMENTATION static bool v_tx_classic(void* const user, + const canard_us_t deadline, const uint_least8_t iface_index, const uint32_t can_id, const void* const data, const uint_least8_t len) { const socketcan_t* const self = (const socketcan_t*)user; + (void)deadline; assert(iface_index < self->iface_count); struct can_frame frame = { .can_id = can_id | CAN_EFF_FLAG, .can_dlc = len }; if ((data != NULL) && (len > 0)) { @@ -71,12 +73,14 @@ static bool v_tx_classic(void* const user, } static bool v_tx_fd(void* const user, + const canard_us_t deadline, const uint_least8_t iface_index, const uint32_t can_id, const void* const data, const uint_least8_t len) { const socketcan_t* const self = (const socketcan_t*)user; + (void)deadline; assert(iface_index < self->iface_count); struct canfd_frame frame = { .can_id = can_id | CAN_EFF_FLAG, .len = len, .flags = CANFD_FDF }; if ((data != NULL) && (len > 0)) { diff --git a/cy_can/tests/test_api_can_pubsub.c b/cy_can/tests/test_api_can_pubsub.c index 687aee9..4acd863 100644 --- a/cy_can/tests/test_api_can_pubsub.c +++ b/cy_can/tests/test_api_can_pubsub.c @@ -158,11 +158,12 @@ static void test_api_can_pubsub_fd_capable_uses_fd_frames(void) TEST_ASSERT_NOT_NULL(pub); can_test_spin_pair(&node, NULL, 4U, spin_slice_us); can_test_node_reset_history(&node); + const cy_us_t deadline = cy_now(node.cy) + (40 * spin_slice_us); - TEST_ASSERT_EQUAL_INT( - CY_OK, cy_publish(pub, cy_now(node.cy) + (40 * spin_slice_us), (cy_bytes_t){ sizeof(payload), payload, NULL })); + TEST_ASSERT_EQUAL_INT(CY_OK, cy_publish(pub, deadline, (cy_bytes_t){ sizeof(payload), payload, NULL })); spin_until_done(&node, sub); TEST_ASSERT_TRUE(node.tx_fd_calls > 0U); + TEST_ASSERT_EQUAL_INT64(deadline, node.last_tx_fd_deadline); { uint8_t received[32]; @@ -200,12 +201,13 @@ static void test_api_can_pubsub_classic_only_emits_no_fd_frames(void) TEST_ASSERT_NOT_NULL(pub); can_test_spin_pair(&node, NULL, 4U, spin_slice_us); can_test_node_reset_history(&node); + const cy_us_t deadline = cy_now(node.cy) + (40 * spin_slice_us); - TEST_ASSERT_EQUAL_INT( - CY_OK, cy_publish(pub, cy_now(node.cy) + (40 * spin_slice_us), (cy_bytes_t){ sizeof(payload), payload, NULL })); + TEST_ASSERT_EQUAL_INT(CY_OK, cy_publish(pub, deadline, (cy_bytes_t){ sizeof(payload), payload, NULL })); spin_until_done(&node, sub); TEST_ASSERT_EQUAL_size_t(0U, node.tx_fd_calls); TEST_ASSERT_TRUE(node.tx_classic_calls > 0U); + TEST_ASSERT_EQUAL_INT64(deadline, node.last_tx_classic_deadline); { const cy_arrival_t arrival = cy_arrival_move(sub); diff --git a/cy_can/tests/test_support.c b/cy_can/tests/test_support.c index d1c327f..758d2ff 100644 --- a/cy_can/tests/test_support.c +++ b/cy_can/tests/test_support.c @@ -189,6 +189,7 @@ static bool tx_common(void* const user, } static bool v_tx_classic(void* const user, + const canard_us_t deadline, const uint_least8_t iface_index, const uint32_t can_id, const void* const data, @@ -198,10 +199,12 @@ static bool v_tx_classic(void* const user, TEST_ASSERT_NOT_NULL(self); TEST_ASSERT_TRUE(len <= 8U); self->tx_classic_calls++; + self->last_tx_classic_deadline = deadline; return tx_common(user, iface_index, can_id, false, data, len); } static bool v_tx_fd(void* const user, + const canard_us_t deadline, const uint_least8_t iface_index, const uint32_t can_id, const void* const data, @@ -211,6 +214,7 @@ static bool v_tx_fd(void* const user, TEST_ASSERT_NOT_NULL(self); TEST_ASSERT_TRUE(len <= 64U); self->tx_fd_calls++; + self->last_tx_fd_deadline = deadline; return tx_common(user, iface_index, can_id, true, data, len); } @@ -454,6 +458,8 @@ void can_test_node_reset_history(can_test_node_t* const self) self->tx_history_count = 0U; self->tx_classic_calls = 0U; self->tx_fd_calls = 0U; + self->last_tx_classic_deadline = 0; + self->last_tx_fd_deadline = 0; self->last_tx_pending_iface_bitmap = 0U; } diff --git a/cy_can/tests/test_support.h b/cy_can/tests/test_support.h index 9da5fcd..152bc01 100644 --- a/cy_can/tests/test_support.h +++ b/cy_can/tests/test_support.h @@ -57,6 +57,8 @@ struct can_test_node_t size_t tx_blocked[CAN_TEST_MAX_IFACES]; size_t tx_classic_calls; size_t tx_fd_calls; + canard_us_t last_tx_classic_deadline; + canard_us_t last_tx_fd_deadline; size_t rx_calls; uint_least8_t last_tx_pending_iface_bitmap; size_t filter_calls;