forked from hardbyte/python-can
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.py
More file actions
91 lines (69 loc) · 2.87 KB
/
utils.py
File metadata and controls
91 lines (69 loc) · 2.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
"""
Defines common socketcan functions.
"""
from typing import cast, Iterable, Optional
import can.typechecking as typechecking
import logging
import os
import errno
import struct
import subprocess
import re
from can.interfaces.socketcan.constants import CAN_EFF_FLAG
log = logging.getLogger(__name__)
def pack_filters(can_filters: Optional[typechecking.CanFilters] = None) -> bytes:
if can_filters is None:
# Pass all messages
can_filters = [{"can_id": 0, "can_mask": 0}]
can_filter_fmt = "={}I".format(2 * len(can_filters))
filter_data = []
for can_filter in can_filters:
can_id = can_filter["can_id"]
can_mask = can_filter["can_mask"]
if "extended" in can_filter:
can_filter = cast(typechecking.CanFilterExtended, can_filter)
# Match on either 11-bit OR 29-bit messages instead of both
can_mask |= CAN_EFF_FLAG
if can_filter["extended"]:
can_id |= CAN_EFF_FLAG
filter_data.append(can_id)
filter_data.append(can_mask)
return struct.pack(can_filter_fmt, *filter_data)
_PATTERN_CAN_INTERFACE = re.compile(r"v?can\d+")
def find_available_interfaces() -> Iterable[str]:
"""Returns the names of all open can/vcan interfaces using
the ``ip link list`` command. If the lookup fails, an error
is logged to the console and an empty list is returned.
:rtype: an iterable of :class:`str`
"""
try:
# it might be good to add "type vcan", but that might (?) exclude physical can devices
command = ["ip", "-o", "link", "list", "up"]
output = subprocess.check_output(command, universal_newlines=True)
except Exception as e: # subprocess.CalledProcessError was too specific
log.error("failed to fetch opened can devices: %s", e)
return []
else:
# log.debug("find_available_interfaces(): output=\n%s", output)
# output contains some lines like "1: vcan42: <NOARP,UP,LOWER_UP> ..."
# extract the "vcan42" of each line
interface_names = [line.split(": ", 3)[1] for line in output.splitlines()]
log.debug("find_available_interfaces(): detected: %s", interface_names)
return filter(_PATTERN_CAN_INTERFACE.match, interface_names)
def error_code_to_str(code: int) -> str:
"""
Converts a given error code (errno) to a useful and human readable string.
:param int code: a possibly invalid/unknown error code
:rtype: str
:returns: a string explaining and containing the given error code, or a string
explaining that the errorcode is unknown if that is the case
"""
try:
name = errno.errorcode[code]
except KeyError:
name = "UNKNOWN"
try:
description = os.strerror(code)
except ValueError:
description = "no description available"
return "{} (errno {}): {}".format(name, code, description)