Skip to content

Commit 4df7d14

Browse files
Implement configure_acceptance_filters for socketcan (#340)
Co-authored-by: Pavel Kirienko <pavel.kirienko@gmail.com>
1 parent 40e1482 commit 4df7d14

File tree

3 files changed

+35
-7
lines changed

3 files changed

+35
-7
lines changed

CHANGELOG.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
Changelog
44
=========
55

6+
v1.19
7+
-----
8+
- Implement configure_acceptance_filters for socketcan.
9+
610
v1.18
711
-----
812
- Add FileClient2 which reports errors by raising exceptions.

pycyphal/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.18.0"
1+
__version__ = "1.19.0"

pycyphal/transport/can/media/socketcan/_socketcan.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,11 @@ def start(self, handler: Media.ReceivedFramesHandler, no_automatic_retransmissio
123123
def configure_acceptance_filters(self, configuration: typing.Sequence[FilterConfiguration]) -> None:
124124
if self._closed:
125125
raise pycyphal.transport.ResourceClosedError(repr(self))
126-
_logger.info(
127-
"%s FIXME: acceptance filter configuration is not yet implemented; please submit patches! "
128-
"Requested configuration: %s",
129-
self,
130-
", ".join(map(str, configuration)),
131-
)
126+
127+
try:
128+
self._sock.setsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER, _pack_filters(configuration)) # type: ignore
129+
except OSError as error:
130+
_logger.error("Setting CAN filters failed: %s", error)
132131

133132
async def send(self, frames: typing.Iterable[Envelope], monotonic_deadline: float) -> int:
134133
num_sent = 0
@@ -366,3 +365,28 @@ def _make_socket(iface_name: str, can_fd: bool, native_frame_size: int) -> socke
366365
raise
367366

368367
return s
368+
369+
370+
def _pack_filters(configuration: typing.Sequence[FilterConfiguration]) -> bytes:
371+
"""Convert a list of filters into a packed structure suitable for setsockopt().
372+
Inspired by python-can sources.
373+
:param configuration: list of CAN filters
374+
:type configuration: typing.Sequence[FilterConfiguration]
375+
:return: packed structure suitable for setsockopt()
376+
:rtype: bytes
377+
"""
378+
379+
can_filter_fmt = f"={2 * len(configuration)}I"
380+
filter_data = []
381+
for can_filter in configuration:
382+
can_id = can_filter.identifier
383+
can_mask = can_filter.mask
384+
if can_filter.format is not None:
385+
# Match on either 11-bit OR 29-bit messages instead of both
386+
can_mask |= _CAN_EFF_FLAG # Not using socket.CAN_EFF_FLAG because it is negative on 32 bit platforms
387+
if can_filter.format == FrameFormat.EXTENDED:
388+
can_id |= _CAN_EFF_FLAG
389+
filter_data.append(can_id)
390+
filter_data.append(can_mask)
391+
392+
return struct.pack(can_filter_fmt, *filter_data)

0 commit comments

Comments
 (0)