Skip to content

Commit

Permalink
add acceptance filter configuration helper
Browse files Browse the repository at this point in the history
  • Loading branch information
coderkalyan committed Jul 19, 2021
1 parent 2a11617 commit 78400b0
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 0 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,22 @@ my_transfer->payload_size = sizeof(buffer);
result = canardTxPush(&ins, &my_transfer);
```
A simple API for generating CAN hardware acceptance filter configurations is also provided.
Acceptance filters are generated in an extended 29-bit ID + mask scheme and can be used to minimize the number of irrelevant transfers processed in software.
```c
// Generate an acceptance filter to receive only uavcan.node.Heartbeat.1.0 messages (fixed port ID 7509):
CanardAcceptanceFilterConfig heartbeat_config = canardMakeAcceptanceFilterConfigForSubject(7509);
CanardAcceptanceFilterConfig register_access_config = canardMakeAcceptanceFilterConfigForService(384, ins.node_id);
// You can also combine the two filter configurations into one (may also accept in other messages).
// This allows consolidating a large set of configurations to fit the number of hardware filters.
// For more information on the optimal subset of configurations to consolidate to minimize wasted CPU,
// see the UAVCAN specification.
CanardAcceptanceFilterConfig combined_config = canardConsolidateAcceptanceFilterConfigs(&heartbeat_config, &register_access_config);
configureHardwareFilters(combined_config.extended_can_id, combined_config.extended_mask);
```

Full API specification is available in the documentation.
If you find the examples to be unclear or incorrect, please, open a ticket.

Expand Down
30 changes: 30 additions & 0 deletions libcanard/canard.c
Original file line number Diff line number Diff line change
Expand Up @@ -1099,3 +1099,33 @@ int8_t canardRxUnsubscribe(CanardInstance* const ins,
}
return out;
}

CanardAcceptanceFilterConfig canardMakeAcceptanceFilterConfigForSubject(const CanardPortID subject_id)
{
CanardAcceptanceFilterConfig out = {0};

out.extended_can_id = subject_id << OFFSET_SUBJECT_ID;
out.extended_mask = FLAG_SERVICE_NOT_MESSAGE | FLAG_RESERVED_07 | (CANARD_SUBJECT_ID_MAX << OFFSET_SUBJECT_ID);

return out;
}

CanardAcceptanceFilterConfig canardMakeAcceptanceFilterConfigForService(const CanardPortID service_id, const CanardNodeID local_node_id)
{
CanardAcceptanceFilterConfig out = {0};

out.extended_can_id = FLAG_SERVICE_NOT_MESSAGE | (service_id << OFFSET_SERVICE_ID) | (local_node_id << OFFSET_DST_NODE_ID);
out.extended_mask = FLAG_SERVICE_NOT_MESSAGE | FLAG_RESERVED_23 | (CANARD_SERVICE_ID_MAX << OFFSET_SERVICE_ID) | (CANARD_NODE_ID_MAX << OFFSET_DST_NODE_ID);

return out;
}

CanardAcceptanceFilterConfig canardConsolidateAcceptanceFilterConfigs(const CanardAcceptanceFilterConfig *a, const CanardAcceptanceFilterConfig *b)
{
CanardAcceptanceFilterConfig out = {0};

out.extended_mask = a->extended_mask & b->extended_mask & ~(a->extended_can_id ^ b->extended_can_id);
out.extended_can_id = a->extended_can_id & out.extended_mask;

return out;
}
47 changes: 47 additions & 0 deletions libcanard/canard.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,19 @@ struct CanardInstance
struct CanardInternalTxQueueItem* _tx_queue;
};

/// CAN acceptance filter configuration with an extended 29-bit ID utilizing an ID + mask filter scheme.
/// Filter configuration can be programmed into a CAN controller to filter out irrelevant messages in hardware.
/// This allows the software application to reduce CPU load spent on processing irrelevant messages.
typedef struct CanardAcceptanceFilterConfig {
/// 29-bit extended ID. Defines the extended CAN ID to filter incoming frames against.
/// The bits above 29-th shall be zero.
uint32_t extended_can_id;
/// 29-bit extended mask. Defines the bitmask used to enable/disable bits used to filter messages.
/// Only bits that are enabled are compared to the extended_can_id for filtering.
/// The bits above 29-th shall be zero.
uint32_t extended_mask;
} CanardAcceptanceFilterConfig;

/// Construct a new library instance.
/// The default values will be assigned as specified in the structure field documentation.
/// If any of the pointers are NULL, the behavior is undefined.
Expand Down Expand Up @@ -622,6 +635,40 @@ int8_t canardRxUnsubscribe(CanardInstance* const ins,
const CanardTransferKind transfer_kind,
const CanardPortID port_id);


/// Generate an acceptance filter configuration to accept a specific subject ID.
///
/// Complex applications will likely subscribe to more subject IDs than there are
/// acceptance filters available in the CAN hardware. In this case, the application
/// should implement filter consolidation. See canardConsolidateAcceptanceFilterConfigs()
/// as well as the UAVCAN specification for details.
CanardAcceptanceFilterConfig canardMakeAcceptanceFilterConfigForSubject(const CanardPortID subject_id);

/// Generate an acceptance filter configuration to accept a specific service.
///
/// Complex applications will likely subscribe to more subject IDs than there are
/// acceptance filters available in the CAN hardware. In this case, the application
/// should implement filter consolidation. See canardConsolidateAcceptanceFilterConfigs()
/// as well as the UAVCAN specification for details.
CanardAcceptanceFilterConfig canardMakeAcceptanceFilterConfigForService(const CanardPortID service_id, const CanardNodeID local_node_id);

/// Consolidate two acceptance filter configurations into a single configuration.
///
/// Complex applications will likely subscribe to more subject IDs than there are
/// acceptance filters available in the CAN hardware. In this case, the application
/// should implement filter consolidation. While this may make it impossible to create
/// a 'perfect' filter that only accepts desired subject IDs, the application should apply
/// consolidation in a manner that minimizes the number of undesired messages that pass
/// through the hardware acceptance filters and require software filtering (implemented by canardRxSubscribe).
///
/// While optimal choice of filter consildation is a function of the number of available hardware filters,
/// the set of transfers needed by the application, and the expected frequency of occurence
/// of all possible distinct transfers on the bus, it is possible to generate a quasi-optimal configuration
/// if information about the frequency of occurence of different transfers is not known.
/// For details, see the "Automatic hardware acceptance filter configuration" note under the UAVCAN/CAN section
/// in the Transport Layer chapter of the UAVCAN specification.
CanardAcceptanceFilterConfig canardConsolidateAcceptanceFilterConfigs(const CanardAcceptanceFilterConfig *a, const CanardAcceptanceFilterConfig *b);

#ifdef __cplusplus
}
#endif
Expand Down

0 comments on commit 78400b0

Please sign in to comment.