hardbyte / python-can

The can package provides controller area network support for Python developers
https://python-can.readthedocs.io
GNU Lesser General Public License v3.0
1.27k stars 597 forks source link

pcan interface does not use hardware filtering #400

Open mgiaco opened 6 years ago

mgiaco commented 6 years ago

Hi,

I think it would be great if the pcan driver also supports HW-Filtering. As I found out in the PCAN Basic API Documentation that should be possible.

cheers mathias

christiansandberg commented 6 years ago

If I remember correctly, you specify a range instead of ID and mask, so it won't be portable. That being said, it is not an problem to add interface specific settings if needed.

felixdivo commented 6 years ago

We could also apply a first rough level of filtering on the HW layer, but let recv_internal() return False as the second parameter, which causes the Bus class to apply the finer grained filters on top of that. I dunno whether that's worth the effort though, but it could be more efficient.

mgiaco commented 6 years ago

Okay i understand.

felixdivo commented 6 years ago

@mgiaco Do you want to implement that? Do you need help?

mgiaco commented 5 years ago

@felixdivo I can try it but I am very busy these days so it will take some time.

mipro98 commented 5 months ago

If I remember correctly, you specify a range instead of ID and mask, so it won't be portable. That being said, it is not an problem to add interface specific settings if needed.

That's technically correct when you use the FilterMessages method provided by the PCAN-Basic API. But this is actually only a "convenience" function where they try to calculate an ID+mask given a range of IDs to actually set in hardware [^1] . This can be read on the last page (Appendix D) of their parameter documentation PDF.

[^1]: See chapter 6.4.15 in the datasheet of the actual hardware CAN controller chip inside PCAN devices.

But it's also possible to manually set ID+Filter through the parameter PCAN_ACCEPTANCE_FILTER_11BIT and PCAN_ACCEPTANCE_FILTER_29BIT. This is documented in page 66 of above linked PDF (and also in their API documentation chm file you can download from their website):

This parameter allows the configuration of complex filter patterns, and it is intended for users with extended CAN knowledge. Note that the calculation of mask and code patterns is not a trivial matter. For most applications the use of the function CAN_FilterMessages for setting message reception ranges is more adequate. A simple example on code and mask calculation can be seen in the Appendix D

I tried setting a filter with self.m_objPCANBasic.SetValue(self.m_PcanHandle, PCAN_ACCEPTANCE_FILTER_11BIT, 0x00000XXX00000YYY) (where XXX denote the ID to match and YYY denote the mask). And it "kind of" works but I still got unwanted messages through which still requires the software filter to be active. I might test this more extensively why it is the case. It actually works, the problem was that after enabling the filter, you have to flush the receive buffer to get rid of old messages which don't match the filter.

You can also read out the current mask + filter value set in hardware with GetValue and the same parameter:

result, value = self.m_objPCANBasic.GetValue(self.m_PcanHandle, PCAN_ACCEPTANCE_FILTER_11BIT)
hex_str = format(value, 'x').zfill(8 * 2)
print(f"Acceptance filter: id={hex_str[0:8]} mask={hex_str[8:16]})

With this method, you can also check what id+mask combination FilterMessages actually sets behind the scenes.

And even though some unwanted messages coming through, on a busy bus this hardware filter dramatically improves performance because of many messages not needed to be parsed by the python software "fallback" filter and instead are directly rejected in hardware. In my usecase, with only software filtering, there has often been a delay of 5+ seconds for one message to appear in the application after its reception because of all the other messages on the bus spamming the software filter.