Skip to content

Commit 5d7b725

Browse files
committed
C++: simplify the linked list handling
use a single linked list for message reception, not a list of lists this allows for the creation of new HandlerList handlers at runtime
1 parent e4f3056 commit 5d7b725

File tree

4 files changed

+43
-98
lines changed

4 files changed

+43
-98
lines changed

canard/handler_list.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,20 @@ class HandlerList {
8585
while (entry != nullptr) {
8686
if (transfer.data_type_id == entry->msgid &&
8787
entry->transfer_type == transfer.transfer_type) {
88-
entry->handle_message(transfer);
89-
return;
88+
if (entry->handle_message(transfer) &&
89+
transfer.transfer_type != CanardTransferTypeBroadcast) {
90+
// we only allow one request or response for non-broadcast
91+
break;
92+
}
9093
}
9194
entry = entry->next;
9295
}
9396
}
9497

9598
/// @brief Method to handle a message implemented by the derived class
9699
/// @param transfer transfer object of the request
97-
virtual void handle_message(const CanardRxTransfer& transfer) = 0;
100+
/// @return true if the message is for this consumer
101+
virtual bool handle_message(const CanardRxTransfer& transfer) = 0;
98102

99103
protected:
100104
virtual ~HandlerList() {}
@@ -104,14 +108,20 @@ class HandlerList {
104108
static Canard::Semaphore sem[CANARD_NUM_HANDLERS];
105109
#endif
106110

107-
// add ourselves to the handler list. the caller must be holding the semaphore.
111+
// add ourselves to the handler list
108112
void link(void) NOINLINE_FUNC {
113+
#ifdef WITH_SEMAPHORE
114+
WITH_SEMAPHORE(sem[index]);
115+
#endif
109116
next = head[index];
110117
head[index] = this;
111118
}
112119

113-
// remove ourselves from the handler list. the caller must be holding the semaphore.
120+
// remove ourselves from the handler list
114121
void unlink(void) NOINLINE_FUNC {
122+
#ifdef WITH_SEMAPHORE
123+
WITH_SEMAPHORE(sem[index]);
124+
#endif
115125
HandlerList* entry = head[index];
116126
if (entry == this) {
117127
head[index] = next;

canard/service_client.h

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -41,56 +41,30 @@ class Client : public HandlerList, public Sender {
4141
Sender(_interface),
4242
server_node_id(255),
4343
cb(_cb) {
44-
#ifdef WITH_SEMAPHORE
45-
WITH_SEMAPHORE(sem[index]);
46-
#endif
47-
next = branch_head[index];
48-
branch_head[index] = this;
49-
link(); // link ourselves into the handler list now that we're in the branch list
44+
// link ourselves into the handler list
45+
link();
5046
}
5147

5248
// delete copy constructor and assignment operator
5349
Client(const Client&) = delete;
5450

55-
// destructor, remove the entry from the singly-linked list
51+
// destructor
5652
~Client() NOINLINE_FUNC {
57-
#ifdef WITH_SEMAPHORE
58-
WITH_SEMAPHORE(sem[index]);
59-
#endif
60-
unlink(); // unlink ourselves from the handler list before the branch list
61-
Client<rsptype>* entry = branch_head[index];
62-
if (entry == this) {
63-
branch_head[index] = next;
64-
return;
65-
}
66-
while (entry != nullptr) {
67-
if (entry->next == this) {
68-
entry->next = next;
69-
return;
70-
}
71-
entry = entry->next;
72-
}
53+
// unlink ourselves from the handler list
54+
unlink();
7355
}
7456

7557
/// @brief handles incoming messages
7658
/// @param transfer transfer object of the request
77-
void handle_message(const CanardRxTransfer& transfer) override NOINLINE_FUNC {
59+
bool handle_message(const CanardRxTransfer& transfer) override NOINLINE_FUNC {
7860
rsptype msg {};
79-
if (rsptype::cxx_iface::rsp_decode(&transfer, &msg)) {
80-
// invalid decode
81-
return;
82-
}
83-
84-
// scan through the list of entries for corresponding server node id and transfer id
85-
Client<rsptype>* entry = branch_head[index];
86-
while (entry != nullptr) {
87-
if (entry->server_node_id == transfer.source_node_id
88-
&& entry->transfer_id == transfer.transfer_id) {
89-
entry->cb(transfer, msg);
90-
return;
91-
}
92-
entry = entry->next;
61+
if (server_node_id == transfer.source_node_id &&
62+
transfer_id == transfer.transfer_id &&
63+
!rsptype::cxx_iface::rsp_decode(&transfer, &msg)) {
64+
cb(transfer, msg);
65+
return true;
9366
}
67+
return false;
9468
}
9569

9670
/// @brief makes service request
@@ -139,16 +113,11 @@ class Client : public HandlerList, public Sender {
139113
}
140114

141115
private:
142-
static Client<rsptype>* branch_head[CANARD_NUM_HANDLERS];
143-
Client<rsptype>* next;
144116
uint8_t server_node_id;
145117

146118
uint8_t req_buf[rsptype::cxx_iface::REQ_MAX_SIZE];
147119
Callback<rsptype> &cb;
148120
uint8_t transfer_id;
149121
};
150122

151-
template <typename rsptype>
152-
Client<rsptype> *Client<rsptype>::branch_head[] = {nullptr};
153-
154123
} // namespace Canard

canard/service_server.h

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,33 +41,27 @@ class Server : public HandlerList {
4141
HandlerList(CanardTransferTypeRequest, reqtype::cxx_iface::ID, reqtype::cxx_iface::SIGNATURE, _interface.get_index()),
4242
interface(_interface),
4343
cb(_cb) {
44-
#ifdef WITH_SEMAPHORE
45-
WITH_SEMAPHORE(sem[index]);
46-
#endif
4744
link(); // link ourselves into the handler list
4845
}
4946

5047
// delete copy constructor and assignment operator
5148
Server(const Server&) = delete;
5249

5350
~Server() NOINLINE_FUNC {
54-
#ifdef WITH_SEMAPHORE
55-
WITH_SEMAPHORE(sem[index]);
56-
#endif
5751
unlink(); // unlink ourselves from the handler list
5852
}
5953

6054
/// @brief handles incoming messages
6155
/// @param transfer transfer object of the request
62-
void handle_message(const CanardRxTransfer& transfer) override NOINLINE_FUNC {
56+
/// @return true if message has been handled
57+
bool handle_message(const CanardRxTransfer& transfer) override NOINLINE_FUNC {
6358
reqtype msg {};
64-
if (reqtype::cxx_iface::req_decode(&transfer, &msg)) {
65-
// invalid decode
66-
return;
59+
if (!reqtype::cxx_iface::req_decode(&transfer, &msg)) {
60+
transfer_id = transfer.transfer_id;
61+
cb(transfer, msg);
62+
return true;
6763
}
68-
transfer_id = transfer.transfer_id;
69-
// call the registered callback
70-
cb(transfer, msg);
64+
return false;
7165
}
7266

7367
/// @brief Send a response to the request

canard/subscriber.h

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -41,62 +41,34 @@ class Subscriber : public HandlerList {
4141
Subscriber(Callback<msgtype> &_cb, uint8_t _index) NOINLINE_FUNC :
4242
HandlerList(CanardTransferTypeBroadcast, msgtype::cxx_iface::ID, msgtype::cxx_iface::SIGNATURE, _index),
4343
cb (_cb) {
44-
#ifdef WITH_SEMAPHORE
45-
WITH_SEMAPHORE(sem[index]);
46-
#endif
47-
next = branch_head[index];
48-
branch_head[index] = this;
49-
link(); // link ourselves into the handler list now that we're in the branch list
44+
// link ourselves into the handler list
45+
link();
5046
}
5147

5248
// delete copy constructor and assignment operator
5349
Subscriber(const Subscriber&) = delete;
5450

5551
// destructor, remove the entry from the singly-linked list
5652
~Subscriber() NOINLINE_FUNC {
57-
#ifdef WITH_SEMAPHORE
58-
WITH_SEMAPHORE(sem[index]);
59-
#endif
60-
unlink(); // unlink ourselves from the handler list before the branch list
61-
Subscriber<msgtype>* entry = branch_head[index];
62-
if (entry == this) {
63-
branch_head[index] = next;
64-
return;
65-
}
66-
while (entry != nullptr) {
67-
if (entry->next == this) {
68-
entry->next = next;
69-
return;
70-
}
71-
entry = entry->next;
72-
}
53+
// unlink ourselves from the handler list
54+
unlink();
7355
}
7456

7557
/// @brief parse the message and call the callback
7658
/// @param transfer transfer object
77-
void handle_message(const CanardRxTransfer& transfer) override NOINLINE_FUNC {
59+
bool handle_message(const CanardRxTransfer& transfer) override NOINLINE_FUNC {
7860
msgtype msg {};
79-
if (msgtype::cxx_iface::decode(&transfer, &msg)) {
80-
// invalid decode
81-
return;
82-
}
83-
// call all registered callbacks in one go
84-
Subscriber<msgtype>* entry = branch_head[index];
85-
while (entry != nullptr) {
86-
entry->cb(transfer, msg);
87-
entry = entry->next;
61+
if (!msgtype::cxx_iface::decode(&transfer, &msg)) {
62+
cb(transfer, msg);
63+
return true;
8864
}
65+
return false;
8966
}
9067

9168
private:
92-
Subscriber<msgtype>* next;
93-
static Subscriber<msgtype> *branch_head[CANARD_NUM_HANDLERS];
9469
Callback<msgtype> &cb;
9570
};
9671

97-
template <typename msgtype>
98-
Subscriber<msgtype>* Subscriber<msgtype>::branch_head[] = {nullptr};
99-
10072
template <typename T, typename msgtype>
10173
class SubscriberArgCb {
10274
public:

0 commit comments

Comments
 (0)