Not quite. See, we have two kinds of communication: messages and services. Messages can be published and subscribed to; services can be invoked (or called) and provided (or served). You can’t “publish” a service call or “subscribe” to a service, it doesn’t make sense. In Libcanard, there is a bit of an implementation-specific terminology mishap: it uses “subscribe” in the sense of “tell the library that the application wants to receive this kind of transfers”; the mishap is because I couldn’t find a better word to use. Maybe I should have used “listen” instead, like canardRxListen
? I wonder if we should change it.
So if you want to provide a service, you tell the library to receive service request transfers, like this:
// Configure the library to listen for register access service requests.
CanardRxSubscription srv_register_access;
(void) canardRxSubscribe(&canard,
CanardTransferKindRequest,
RegisterAccessServiceID,
1024U, // Larger buffers are OK.
CANARD_DEFAULT_TRANSFER_ID_TIMEOUT_USEC,
&srv_register_access);
Then you handle the calls like this:
// Process received frames, if any.
CanardFrame rxf;
uint8_t buffer[64];
while (socketcanPop(sock, &rxf, sizeof(buffer), buffer, 1000) > 0) // Error handling not implemented
{
CanardTransfer transfer;
if (canardRxAccept(&canard, &rxf, 0, &transfer))
{
if ((transfer.transfer_kind == CanardTransferKindRequest) &&
(transfer.port_id == RegisterAccessServiceID))
{
handleRegisterAccess(&canard, &transfer);
}
free((void*) transfer.payload);
}
}
static void handleRegisterAccess(CanardInstance* const canard, const CanardTransfer* const request_transfer)
{
<... business logic not shown ...>
// Send the response back. Make sure to re-use the same priority and transfer-ID.
CanardTransfer response_transfer = *request_transfer;
response_transfer.transfer_kind = CanardTransferKindResponse;
response_transfer.payload_size = response_size;
response_transfer.payload = response;
(void) canardTxPush(canard, &response_transfer);
}
When invoking a service, you inverse the logic: listen for service response transfers and emit service request transfers. When receiving the responses, match them by their transfer-ID value.
The examples above have been copy-pasted from this demo: Automatic configuration of port identifiers