diff --git a/libcanard/canard.c b/libcanard/canard.c index 863de50..eadf27c 100644 --- a/libcanard/canard.c +++ b/libcanard/canard.c @@ -1238,6 +1238,30 @@ int8_t canardRxUnsubscribe(CanardInstance* const ins, return out; } +int8_t canardRxHasSubscription(CanardInstance* const ins, + const CanardTransferKind transfer_kind, + const CanardPortID port_id) +{ + int8_t out = -CANARD_ERROR_INVALID_ARGUMENT; + const size_t tk = (size_t) transfer_kind; + if ((ins != NULL) && (tk < CANARD_NUM_TRANSFER_KINDS)) + { + CanardPortID port_id_mutable = port_id; + const CanardRxSubscription* const sub = (const CanardRxSubscription*) (void*) + cavlSearch(&ins->rx_subscriptions[tk], &port_id_mutable, &rxSubscriptionPredicateOnPortID, NULL); + if (sub != NULL) + { + CANARD_ASSERT(sub->port_id == port_id); + out = 1; + } + else + { + out = 0; + } + } + return out; +} + CanardFilter canardMakeFilterForSubject(const CanardPortID subject_id) { CanardFilter out = {0}; diff --git a/libcanard/canard.h b/libcanard/canard.h index 0f1b5a7..9cdcfce 100644 --- a/libcanard/canard.h +++ b/libcanard/canard.h @@ -649,6 +649,10 @@ int8_t canardRxUnsubscribe(CanardInstance* const ins, const CanardTransferKind transfer_kind, const CanardPortID port_id); +int8_t canardRxHasSubscription(CanardInstance* const ins, + const CanardTransferKind transfer_kind, + const CanardPortID port_id); + /// Utilities for generating CAN controller hardware acceptance filter configurations /// to accept specific subjects, services, or nodes. /// diff --git a/tests/helpers.hpp b/tests/helpers.hpp index 618f3c8..7e4ba20 100644 --- a/tests/helpers.hpp +++ b/tests/helpers.hpp @@ -200,6 +200,11 @@ class Instance return canardRxUnsubscribe(&canard_, transfer_kind, port_id); } + [[nodiscard]] auto rxHasSubscription(const CanardTransferKind transfer_kind, const CanardPortID port_id) + { + return canardRxHasSubscription(&canard_, transfer_kind, port_id); + } + /// The items are sorted by port-ID. [[nodiscard]] auto getSubs(const CanardTransferKind tk) const -> std::vector { diff --git a/tests/test_public_rx.cpp b/tests/test_public_rx.cpp index 932d654..4f45c3a 100644 --- a/tests/test_public_rx.cpp +++ b/tests/test_public_rx.cpp @@ -49,8 +49,11 @@ TEST_CASE("RxBasic0") // Create a message subscription. CanardRxSubscription sub_msg{}; + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(1 == ins.rxSubscribe(CanardTransferKindMessage, 0b0110011001100, 32, 2'000'000, sub_msg)); // New. + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(0 == ins.rxSubscribe(CanardTransferKindMessage, 0b0110011001100, 16, 1'000'000, sub_msg)); // Replaced. + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(ins.getMessageSubs().at(0) == &sub_msg); REQUIRE(ins.getMessageSubs().at(0)->port_id == 0b0110011001100); REQUIRE(ins.getMessageSubs().at(0)->extent == 16); @@ -61,7 +64,9 @@ TEST_CASE("RxBasic0") // Create a request subscription. CanardRxSubscription sub_req{}; + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindRequest, 0b0000110011)); REQUIRE(1 == ins.rxSubscribe(CanardTransferKindRequest, 0b0000110011, 20, 3'000'000, sub_req)); + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindRequest, 0b0000110011)); REQUIRE(ins.getMessageSubs().at(0) == &sub_msg); REQUIRE(ins.getResponseSubs().empty()); REQUIRE(ins.getRequestSubs().at(0) == &sub_req); @@ -72,7 +77,9 @@ TEST_CASE("RxBasic0") // Create a response subscription. CanardRxSubscription sub_res{}; + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindResponse, 0b0000111100)); REQUIRE(1 == ins.rxSubscribe(CanardTransferKindResponse, 0b0000111100, 10, 100'000, sub_res)); + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindResponse, 0b0000111100)); REQUIRE(ins.getMessageSubs().at(0) == &sub_msg); REQUIRE(ins.getResponseSubs().at(0) == &sub_res); REQUIRE(ins.getResponseSubs().at(0)->port_id == 0b0000111100); @@ -83,7 +90,9 @@ TEST_CASE("RxBasic0") // Create a second response subscription. It will come before the one we added above due to lower port-ID. CanardRxSubscription sub_res2{}; + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindResponse, 0b0000000000)); REQUIRE(1 == ins.rxSubscribe(CanardTransferKindResponse, 0b0000000000, 10, 1'000, sub_res2)); + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindResponse, 0b0000000000)); REQUIRE(ins.getMessageSubs().at(0) == &sub_msg); REQUIRE(ins.getResponseSubs().at(0) == &sub_res2); REQUIRE(ins.getResponseSubs().at(0)->port_id == 0b0000000000); @@ -165,8 +174,11 @@ TEST_CASE("RxBasic0") REQUIRE(ins.getAllocator().getTotalAllocatedAmount() == (3 * sizeof(RxSession) + 16 + 20)); // Destroy the message subscription and the buffer to free up memory. + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(1 == ins.rxUnsubscribe(CanardTransferKindMessage, 0b0110011001100)); + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(0 == ins.rxUnsubscribe(CanardTransferKindMessage, 0b0110011001100)); // Repeat, nothing to do. + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(ins.getAllocator().getNumAllocatedFragments() == 4); REQUIRE(ins.getAllocator().getTotalAllocatedAmount() == (2 * sizeof(RxSession) + 16 + 20)); ins.getAllocator().deallocate(msg_payload); @@ -198,12 +210,21 @@ TEST_CASE("RxBasic0") REQUIRE(subscription == nullptr); // Unsubscribe. + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindRequest, 0b0000110011)); REQUIRE(1 == ins.rxUnsubscribe(CanardTransferKindRequest, 0b0000110011)); + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindRequest, 0b0000110011)); REQUIRE(0 == ins.rxUnsubscribe(CanardTransferKindRequest, 0b0000110011)); + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindRequest, 0b0000110011)); + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindResponse, 0b0000111100)); REQUIRE(1 == ins.rxUnsubscribe(CanardTransferKindResponse, 0b0000111100)); + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindResponse, 0b0000111100)); REQUIRE(0 == ins.rxUnsubscribe(CanardTransferKindResponse, 0b0000111100)); + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindResponse, 0b0000111100)); + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindResponse, 0b0000000000)); REQUIRE(1 == ins.rxUnsubscribe(CanardTransferKindResponse, 0b0000000000)); + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindResponse, 0b0000000000)); REQUIRE(0 == ins.rxUnsubscribe(CanardTransferKindResponse, 0b0000000000)); + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindResponse, 0b0000000000)); } TEST_CASE("RxAnonymous") @@ -239,7 +260,9 @@ TEST_CASE("RxAnonymous") void* const my_user_reference = &ins; CanardRxSubscription sub_msg{}; sub_msg.user_reference = my_user_reference; + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(1 == ins.rxSubscribe(CanardTransferKindMessage, 0b0110011001100, 16, 2'000'000, sub_msg)); // New. + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); // Accepted anonymous message. subscription = nullptr; @@ -358,7 +381,9 @@ TEST_CASE("Issue189") // https://github.com/OpenCyphal/libcanard/issues/189 // Create a message subscription. CanardRxSubscription sub_msg{}; + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(1 == ins.rxSubscribe(CanardTransferKindMessage, 0b0110011001100, 50, 1'000'000, sub_msg)); + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(ins.getMessageSubs().at(0) == &sub_msg); REQUIRE(ins.getMessageSubs().at(0)->port_id == 0b0110011001100); REQUIRE(ins.getMessageSubs().at(0)->extent == 50); @@ -465,7 +490,9 @@ TEST_CASE("Issue212") // Create a message subscription with the transfer-ID timeout of just one microsecond. CanardRxSubscription sub_msg{}; + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(1 == ins.rxSubscribe(CanardTransferKindMessage, 0b0110011001100, 50, 1, sub_msg)); + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(ins.getMessageSubs().at(0) == &sub_msg); REQUIRE(ins.getMessageSubs().at(0)->port_id == 0b0110011001100); REQUIRE(ins.getMessageSubs().at(0)->extent == 50); @@ -569,7 +596,9 @@ TEST_CASE("RxFixedTIDWithSmallTimeout") // Create a message subscription with the transfer-ID timeout of just five microseconds. CanardRxSubscription sub_msg{}; + REQUIRE(0 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(1 == ins.rxSubscribe(CanardTransferKindMessage, 0b0110011001100, 50, 5, sub_msg)); + REQUIRE(1 == ins.rxHasSubscription(CanardTransferKindMessage, 0b0110011001100)); REQUIRE(ins.getMessageSubs().at(0) == &sub_msg); REQUIRE(ins.getMessageSubs().at(0)->port_id == 0b0110011001100); REQUIRE(ins.getMessageSubs().at(0)->extent == 50);