Homepage GitHub

Configure Can Acceptance Filters in multi thread app

Hi!

I am building a Node and SubNode application, similar to example in repo.
Does it matter in what thread the configureCanAcceptanceFilters() is called, assuming all subscribers etc. has been setup in each thread at the point of function call?

Regards

You have an interesting edge case. You will need to configure your acceptance filters manually.

Invoking configureCanAcceptanceFilters() in the sub-node will have no effect and result in ErrDriver. This is because the required CAN acceptance filter configuration functionality is not implemented in the virtual driver (the following code is taken from the Multithreading tutorial):

    /**
     * Stubs for uavcan::ICanDriver. Will be invoked by the sub-node.
     * These methods are meaningless for a virtual interface.
     */
    std::int16_t configureFilters(const uavcan::CanFilterConfig*, std::uint16_t) override { return -uavcan::ErrDriver; }
    std::uint16_t getNumFilters() const override { return 0; }

Invocation of configureCanAcceptanceFilters() on the physical node will succeed, but the method will not be aware about the subscriptions implemented in the virtual node because it is separated at a very low level of abstraction and the subscription information is not shared between the physical node and the virtual node. As a result, the applied acceptance filter configuration may reject CAN frames that are needed for the virtual node.

What you need is to take the subscription list from both nodes (physical and virtual) and compute the acceptance filter configuration from that yourself. Basically you need to repeat this loop once per node:

Makes sense!

Very good, thanks for the info. I will try…

Kind regards

This solution seems to work.

In subnode thread I manually create CanFilterConfig, as above, and sends the configs to main node thread via queue:

const TransferListener* p = node->getDispatcher().getListOfMessageListeners().get();
while (p != UAVCAN_NULLPTR)
{
    CanFilterConfig cfg;
    cfg.id = (static_cast<uint32_t>(p->getDataTypeDescriptor().getID().get()) << 8) | CanFrame::FlagEFF;
					cfg.mask = 0xFFFF80 | CanFrame::FlagEFF | CanFrame::FlagRTR | CanFrame::FlagERR;
					thread_exchange.filter.push(cfg); //Mutex protected queue					
					p = p->getNextListNode();
}

The above snippet is executed when sub node has subscribed to all broadcasts needed and setup the provided services.

In the main thread, before main loop, a config is setup

CanAcceptanceFilterConfigurator main_node_conf(*node);
main_node_conf.computeConfiguration();

In the main loop, the queue is pop:ed and filter is added:

if(thread_exchange.filter.pop(filter))
{
    main_node_conf.addFilterConfig(filter);
    main_node_conf.applyConfiguration();
}

As I understand, addFilterCOnfig() and applyConfiguration() shall be enough? Even if new subscribers or services are added later?

Regards

This should be OK.