From 435d86dc449111bad74ed41aad34ac9ee0d81df4 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sat, 22 Feb 2025 20:12:06 +0100
Subject: [PATCH 01/34] Add basic implementation for can bridge
---
can/bridge.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++
pyproject.toml | 1 +
2 files changed, 48 insertions(+)
create mode 100644 can/bridge.py
diff --git a/can/bridge.py b/can/bridge.py
new file mode 100644
index 000000000..0a5921e0b
--- /dev/null
+++ b/can/bridge.py
@@ -0,0 +1,47 @@
+"""
+Creates a bridge between two CAN busses.
+
+This will connect to two CAN busses. Messages received on one
+bus will be sent to the other bus and vice versa.
+"""
+
+import argparse
+import errno
+import sys
+from datetime import datetime
+
+from .logger import _create_base_argument_parser, _create_bus, _parse_additional_config
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser(description="Bridge two CAN busses.")
+
+ _create_base_argument_parser(parser)
+
+ parser.add_argument(
+ "--error-frames",
+ help="Also send error frames to the interface.",
+ action="store_true",
+ )
+
+ # print help message when no arguments were given
+ if len(sys.argv) < 2:
+ parser.print_help(sys.stderr)
+ raise SystemExit(errno.EINVAL)
+
+ results, unknown_args = parser.parse_known_args()
+ additional_config = _parse_additional_config([*results.extra_args, *unknown_args])
+
+ verbosity = results.verbosity
+
+ error_frames = results.error_frames
+
+ with _create_bus(results, **additional_config) as bus_a
+ with _create_bus(results, **additional_config) as bus_b
+ print(f"CAN Bridge (Started on {datetime.now()})")
+
+ print(f"CAN Bridge (Stopped on {datetime.now()})")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/pyproject.toml b/pyproject.toml
index d41bf6e22..fd4461d61 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -51,6 +51,7 @@ can_logconvert = "can.logconvert:main"
can_logger = "can.logger:main"
can_player = "can.player:main"
can_viewer = "can.viewer:main"
+can_bridge = "can.bridge:main"
[project.urls]
homepage = "https://github.com/hardbyte/python-can"
From 7ec1f52cf5493da8b4271215eec9aa01b4c94cf9 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sat, 22 Feb 2025 21:16:54 +0100
Subject: [PATCH 02/34] Implement basic configuration parsing
---
can/bridge.py | 80 ++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 66 insertions(+), 14 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 0a5921e0b..3c6709876 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -8,36 +8,88 @@
import argparse
import errno
import sys
+import logging
from datetime import datetime
from .logger import _create_base_argument_parser, _create_bus, _parse_additional_config
-def main() -> None:
- parser = argparse.ArgumentParser(description="Bridge two CAN busses.")
+LOG = logging.getLogger(__name__)
+
+
+def get_config_list(it, separator, conf):
+ while True:
+ el = next(it)
+ if el == separator:
+ break
+ else:
+ conf.append(el)
+
+
+def split_configurations(arg_list, separator='--'):
+ general = []
+ conf_a = []
+ conf_b = []
+
+ it = iter(arg_list)
+ try:
+ get_config_list(it, separator, conf_a)
+ get_config_list(it, separator, conf_b)
+
+ # When we reached this point we found two separators so we have
+ # a general config. We will treate the first config as general
+ general = conf_a
+ conf_a = conf_b
+ get_config_list(it, separator, conf_b)
- _create_base_argument_parser(parser)
+ # When we reached this point we found three separators so this is
+ # an error.
+ raise Exception("To many configurations")
+ except StopIteration:
+ LOG.debug("All configurations were split")
- parser.add_argument(
- "--error-frames",
- help="Also send error frames to the interface.",
- action="store_true",
+ return general, conf_a, conf_b
+
+
+def main() -> None:
+ general_parser = argparse.ArgumentParser()
+ general_parser.add_argument(
+ "-v",
+ action="count",
+ dest="verbosity",
+ help="""How much information do you want to see at the command line?
+ You can add several of these e.g., -vv is DEBUG""",
+ default=2,
)
+ bus_parser = argparse.ArgumentParser(description="Bridge two CAN busses.")
+
+ _create_base_argument_parser(bus_parser)
+
+ parser = argparse.ArgumentParser(description="Bridge two CAN busses.")
+ parser.add_argument('configs', nargs=argparse.REMAINDER)
+
# print help message when no arguments were given
if len(sys.argv) < 2:
- parser.print_help(sys.stderr)
+ bus_parser.print_help(sys.stderr)
raise SystemExit(errno.EINVAL)
- results, unknown_args = parser.parse_known_args()
- additional_config = _parse_additional_config([*results.extra_args, *unknown_args])
+ args = sys.argv[1:]
+ general, conf_a, conf_b = split_configurations(args)
+
+ g_results = general_parser.parse_args(general)
+ verbosity = g_results.verbosity
- verbosity = results.verbosity
+ a_results, a_unknown_args = bus_parser.parse_known_args(conf_a)
+ a_additional_config = _parse_additional_config([*a_results.extra_args, *a_unknown_args])
+ a_results.__dict__['verbosity'] = verbosity
- error_frames = results.error_frames
+ b_results, b_unknown_args = bus_parser.parse_known_args(conf_b)
+ b_additional_config = _parse_additional_config([*b_results.extra_args, *b_unknown_args])
+ b_results.__dict__['verbosity'] = verbosity
- with _create_bus(results, **additional_config) as bus_a
- with _create_bus(results, **additional_config) as bus_b
+ with _create_bus(a_results, **a_additional_config) as bus_a:
+ with _create_bus(b_results, **b_additional_config) as bus_b:
print(f"CAN Bridge (Started on {datetime.now()})")
print(f"CAN Bridge (Stopped on {datetime.now()})")
From 441c4da0e238ef5ab7ca2b49dd2bb4aadd211cf9 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sat, 22 Feb 2025 21:25:11 +0100
Subject: [PATCH 03/34] Add implementation for bridge
---
can/bridge.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/can/bridge.py b/can/bridge.py
index 3c6709876..cb957f0db 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -8,11 +8,14 @@
import argparse
import errno
import sys
+import time
import logging
from datetime import datetime
from .logger import _create_base_argument_parser, _create_bus, _parse_additional_config
+import can
+
LOG = logging.getLogger(__name__)
@@ -90,7 +93,13 @@ def main() -> None:
with _create_bus(a_results, **a_additional_config) as bus_a:
with _create_bus(b_results, **b_additional_config) as bus_b:
+ reader_a = can.RedirectReader(bus_b)
+ reader_b = can.RedirectReader(bus_a)
+ notifier_a = can.Notifier(bus_a, [reader_a])
+ notifier_b = can.Notifier(bus_b, [reader_b])
print(f"CAN Bridge (Started on {datetime.now()})")
+ while True:
+ time.sleep(1)
print(f"CAN Bridge (Stopped on {datetime.now()})")
From e599f0e4dcf1a87cde8fef37cda33eecdb199bb8 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sat, 22 Feb 2025 21:26:15 +0100
Subject: [PATCH 04/34] Improve exit handling
---
can/bridge.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index cb957f0db..057813bef 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -98,8 +98,11 @@ def main() -> None:
notifier_a = can.Notifier(bus_a, [reader_a])
notifier_b = can.Notifier(bus_b, [reader_b])
print(f"CAN Bridge (Started on {datetime.now()})")
- while True:
- time.sleep(1)
+ try:
+ while True:
+ time.sleep(1)
+ except KeyboardInterrupt:
+ pass
print(f"CAN Bridge (Stopped on {datetime.now()})")
From 7b18bc676c3c2ae3593515af16d94620dc6ecd0a Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sat, 22 Feb 2025 21:35:01 +0100
Subject: [PATCH 05/34] Add debug logging
---
can/bridge.py | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/can/bridge.py b/can/bridge.py
index 057813bef..24f4f0e20 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -80,6 +80,9 @@ def main() -> None:
args = sys.argv[1:]
general, conf_a, conf_b = split_configurations(args)
+ LOG.debug("General configuration: %s", general)
+ LOG.debug("Bus A configuration: %s", conf_a)
+ LOG.debug("Bus B configuration: %s", conf_b)
g_results = general_parser.parse_args(general)
verbosity = g_results.verbosity
@@ -91,6 +94,11 @@ def main() -> None:
b_additional_config = _parse_additional_config([*b_results.extra_args, *b_unknown_args])
b_results.__dict__['verbosity'] = verbosity
+ LOG.debug("General configuration results: %s", g_results)
+ LOG.debug("Bus A configuration results: %s", a_results)
+ LOG.debug("Bus A additional configuration results: %s", a_additional_config)
+ LOG.debug("Bus B configuration results: %s", b_results)
+ LOG.debug("Bus B additional configuration results: %s", b_additional_config)
with _create_bus(a_results, **a_additional_config) as bus_a:
with _create_bus(b_results, **b_additional_config) as bus_b:
reader_a = can.RedirectReader(bus_b)
From 9e3c66631189765908c0d7678ac8193c27e3d622 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sat, 22 Feb 2025 21:50:12 +0100
Subject: [PATCH 06/34] Add error handling for wrong arguments
---
can/bridge.py | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 24f4f0e20..3d17faa2e 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -20,6 +20,10 @@
LOG = logging.getLogger(__name__)
+class UserError(Exception):
+ pass
+
+
def get_config_list(it, separator, conf):
while True:
el = next(it)
@@ -34,9 +38,11 @@ def split_configurations(arg_list, separator='--'):
conf_a = []
conf_b = []
+ found_sep = False
it = iter(arg_list)
try:
get_config_list(it, separator, conf_a)
+ found_sep = True
get_config_list(it, separator, conf_b)
# When we reached this point we found two separators so we have
@@ -47,9 +53,11 @@ def split_configurations(arg_list, separator='--'):
# When we reached this point we found three separators so this is
# an error.
- raise Exception("To many configurations")
+ raise UserError("To many configurations")
except StopIteration:
LOG.debug("All configurations were split")
+ if not found_sep:
+ raise UserError("Missing separator")
return general, conf_a, conf_b
@@ -78,7 +86,13 @@ def main() -> None:
raise SystemExit(errno.EINVAL)
args = sys.argv[1:]
- general, conf_a, conf_b = split_configurations(args)
+ try:
+ general, conf_a, conf_b = split_configurations(args)
+ except UserError as exc:
+ print("Error while processing arguments:")
+ print(exc)
+ print("")
+ raise SystemExit(errno.EINVAL)
LOG.debug("General configuration: %s", general)
LOG.debug("Bus A configuration: %s", conf_a)
From 8e4bd93d18adffd3932ad03ce7edd18965ef3164 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sat, 22 Feb 2025 21:54:07 +0100
Subject: [PATCH 07/34] Use stderr
---
can/bridge.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 3d17faa2e..10ee9bd88 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -89,9 +89,8 @@ def main() -> None:
try:
general, conf_a, conf_b = split_configurations(args)
except UserError as exc:
- print("Error while processing arguments:")
- print(exc)
- print("")
+ print(f"Error while processing arguments: {exc}",
+ file=sys.stderr)
raise SystemExit(errno.EINVAL)
LOG.debug("General configuration: %s", general)
From 52703d7c94687f4540e8fdf78a50d066d678ba85 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sat, 22 Feb 2025 22:03:35 +0100
Subject: [PATCH 08/34] Add custom usage
---
can/bridge.py | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/can/bridge.py b/can/bridge.py
index 10ee9bd88..e40c3f0b3 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -17,6 +17,23 @@
import can
+USAGE = """
+usage: can_bridge [{general config} --] {can A config} -- {can B config}
+
+Bridge two CAN busses.
+
+Both can busses will be connected so that messages from bus A will be sent on bus B and messages on bus B will be sent to bus A. The busses are separated by a `--`
+
+positional arguments:
+ {general config} The configuration for this program excluding the config for each bus. Can be omitted
+ {can A config} The configuration for the first bus
+ {can B config} The configuration for the second bus
+
+Example usage:
+ can_bridge -i socketcan -c can0 -- -i socketcan can1
+ can_bridge -vvv -- -i socketcan -c can0 -- -i socketcan can1
+"""
+
LOG = logging.getLogger(__name__)
@@ -82,7 +99,7 @@ def main() -> None:
# print help message when no arguments were given
if len(sys.argv) < 2:
- bus_parser.print_help(sys.stderr)
+ print(USAGE, file=sys.stderr)
raise SystemExit(errno.EINVAL)
args = sys.argv[1:]
From 0435e17cf7a3b98ead4725a7267608c6ea6e08ea Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sat, 22 Feb 2025 22:07:36 +0100
Subject: [PATCH 09/34] Add bus configuration info
---
can/bridge.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index e40c3f0b3..8e0ee40e1 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -32,6 +32,8 @@
Example usage:
can_bridge -i socketcan -c can0 -- -i socketcan can1
can_bridge -vvv -- -i socketcan -c can0 -- -i socketcan can1
+
+Type `can_bridge help_bus` for information about single bus configuration.
"""
LOG = logging.getLogger(__name__)
@@ -106,8 +108,11 @@ def main() -> None:
try:
general, conf_a, conf_b = split_configurations(args)
except UserError as exc:
- print(f"Error while processing arguments: {exc}",
- file=sys.stderr)
+ if len(args) == 1 and args[0] == 'help_bus':
+ bus_parser.print_help(sys.stderr)
+ else:
+ print(f"Error while processing arguments: {exc}",
+ file=sys.stderr)
raise SystemExit(errno.EINVAL)
LOG.debug("General configuration: %s", general)
From 8da0ab3f8c43ee5180d469c76e42d060d3bddeba Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 10:54:47 +0100
Subject: [PATCH 10/34] Code format
---
can/bridge.py | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 8e0ee40e1..8a6b270c8 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -52,7 +52,7 @@ def get_config_list(it, separator, conf):
conf.append(el)
-def split_configurations(arg_list, separator='--'):
+def split_configurations(arg_list, separator="--"):
general = []
conf_a = []
conf_b = []
@@ -97,7 +97,7 @@ def main() -> None:
_create_base_argument_parser(bus_parser)
parser = argparse.ArgumentParser(description="Bridge two CAN busses.")
- parser.add_argument('configs', nargs=argparse.REMAINDER)
+ parser.add_argument("configs", nargs=argparse.REMAINDER)
# print help message when no arguments were given
if len(sys.argv) < 2:
@@ -108,11 +108,10 @@ def main() -> None:
try:
general, conf_a, conf_b = split_configurations(args)
except UserError as exc:
- if len(args) == 1 and args[0] == 'help_bus':
+ if len(args) == 1 and args[0] == "help_bus":
bus_parser.print_help(sys.stderr)
else:
- print(f"Error while processing arguments: {exc}",
- file=sys.stderr)
+ print(f"Error while processing arguments: {exc}", file=sys.stderr)
raise SystemExit(errno.EINVAL)
LOG.debug("General configuration: %s", general)
@@ -122,12 +121,16 @@ def main() -> None:
verbosity = g_results.verbosity
a_results, a_unknown_args = bus_parser.parse_known_args(conf_a)
- a_additional_config = _parse_additional_config([*a_results.extra_args, *a_unknown_args])
- a_results.__dict__['verbosity'] = verbosity
+ a_additional_config = _parse_additional_config(
+ [*a_results.extra_args, *a_unknown_args]
+ )
+ a_results.__dict__["verbosity"] = verbosity
b_results, b_unknown_args = bus_parser.parse_known_args(conf_b)
- b_additional_config = _parse_additional_config([*b_results.extra_args, *b_unknown_args])
- b_results.__dict__['verbosity'] = verbosity
+ b_additional_config = _parse_additional_config(
+ [*b_results.extra_args, *b_unknown_args]
+ )
+ b_results.__dict__["verbosity"] = verbosity
LOG.debug("General configuration results: %s", g_results)
LOG.debug("Bus A configuration results: %s", a_results)
From 9fa9395f934a382ab932c659a6e5d5216210b082 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 11:03:07 +0100
Subject: [PATCH 11/34] Add exception for prints for can_bridge
---
pyproject.toml | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyproject.toml b/pyproject.toml
index fd4461d61..2f434cb09 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -167,6 +167,7 @@ ignore = [
]
"can/logger.py" = ["T20"] # flake8-print
"can/player.py" = ["T20"] # flake8-print
+"can/bridge.py" = ["T20"] # flake8-print
[tool.ruff.lint.isort]
known-first-party = ["can"]
From 3e3dd9ecae01abff1873a7dde14c9d867cb7ba6c Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 11:05:02 +0100
Subject: [PATCH 12/34] Add from to exception in exception
---
can/bridge.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 8a6b270c8..65bd25664 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -76,7 +76,7 @@ def split_configurations(arg_list, separator="--"):
except StopIteration:
LOG.debug("All configurations were split")
if not found_sep:
- raise UserError("Missing separator")
+ raise UserError("Missing separator") from None
return general, conf_a, conf_b
@@ -112,7 +112,7 @@ def main() -> None:
bus_parser.print_help(sys.stderr)
else:
print(f"Error while processing arguments: {exc}", file=sys.stderr)
- raise SystemExit(errno.EINVAL)
+ raise SystemExit(errno.EINVAL) from exc
LOG.debug("General configuration: %s", general)
LOG.debug("Bus A configuration: %s", conf_a)
From 1f2de7d6b2cd9b53edf2c084ac0be463e09c74da Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 11:05:19 +0100
Subject: [PATCH 13/34] Remove assignment to unused variable
---
can/bridge.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 65bd25664..992c96ee5 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -141,8 +141,8 @@ def main() -> None:
with _create_bus(b_results, **b_additional_config) as bus_b:
reader_a = can.RedirectReader(bus_b)
reader_b = can.RedirectReader(bus_a)
- notifier_a = can.Notifier(bus_a, [reader_a])
- notifier_b = can.Notifier(bus_b, [reader_b])
+ can.Notifier(bus_a, [reader_a])
+ can.Notifier(bus_b, [reader_b])
print(f"CAN Bridge (Started on {datetime.now()})")
try:
while True:
From ac6e4dbae83b9c13b3dc70cd7833d240db9abc09 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 11:06:45 +0100
Subject: [PATCH 14/34] Shorten line length
---
can/bridge.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 992c96ee5..5a4a16d21 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -22,10 +22,12 @@
Bridge two CAN busses.
-Both can busses will be connected so that messages from bus A will be sent on bus B and messages on bus B will be sent to bus A. The busses are separated by a `--`
+Both can busses will be connected so that messages from bus A will be sent on
+bus B and messages on bus B will be sent to bus A. The busses are separated by a `--`
positional arguments:
- {general config} The configuration for this program excluding the config for each bus. Can be omitted
+ {general config} The configuration for this program excluding
+ the config for each bus. Can be omitted
{can A config} The configuration for the first bus
{can B config} The configuration for the second bus
From 0fcea6483c881886830990f2ad6ffcf5512d707e Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 11:10:33 +0100
Subject: [PATCH 15/34] Organize imports
---
can/bridge.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 5a4a16d21..e9f51c1d4 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -7,15 +7,14 @@
import argparse
import errno
+import logging
import sys
import time
-import logging
from datetime import datetime
-from .logger import _create_base_argument_parser, _create_bus, _parse_additional_config
-
import can
+from .logger import _create_base_argument_parser, _create_bus, _parse_additional_config
USAGE = """
usage: can_bridge [{general config} --] {can A config} -- {can B config}
From d37af871c1d5e8e976aedeca67890d84025e7e7e Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 11:12:35 +0100
Subject: [PATCH 16/34] Remove unnecessary else
---
can/bridge.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index e9f51c1d4..6833af8af 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -49,8 +49,8 @@ def get_config_list(it, separator, conf):
el = next(it)
if el == separator:
break
- else:
- conf.append(el)
+
+ conf.append(el)
def split_configurations(arg_list, separator="--"):
From 6b0378ec4c7f71abcf9e6e0759b3e6f1feee8702 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 11:18:58 +0100
Subject: [PATCH 17/34] Add documentation for new script
---
doc/scripts.rst | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/doc/scripts.rst b/doc/scripts.rst
index 2d59b7528..281391162 100644
--- a/doc/scripts.rst
+++ b/doc/scripts.rst
@@ -57,6 +57,21 @@ The full usage page can be seen below:
:shell:
+can.bridge
+----------
+
+A small application that can be used to connect two can busses:
+
+.. command-output:: python -m can.bridge -h
+ :shell:
+
+
+Example call:
+::
+
+ python -m can.bridge -i socketcan -c can0 -- -i socketcan -c can1
+
+
can.logconvert
--------------
From 28c80bdb078069b5acfa6f3a065113dbd5b6a442 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 11:25:08 +0100
Subject: [PATCH 18/34] Add handling for -h and help sub command
Necessary for generation of documentation
---
can/bridge.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 6833af8af..a2cbfd4aa 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -109,8 +109,12 @@ def main() -> None:
try:
general, conf_a, conf_b = split_configurations(args)
except UserError as exc:
- if len(args) == 1 and args[0] == "help_bus":
- bus_parser.print_help(sys.stderr)
+ if len(args) >= 1:
+ if args[0] == "-h" or args[0] == "help":
+ print(USAGE)
+ raise SystemExit()
+ elif args[0] == "help_bus":
+ bus_parser.print_help(sys.stderr)
else:
print(f"Error while processing arguments: {exc}", file=sys.stderr)
raise SystemExit(errno.EINVAL) from exc
From c780e8ad5c00d2a95217e2e8da3ec15064499623 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 11:27:24 +0100
Subject: [PATCH 19/34] Add from none to exception
---
can/bridge.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/can/bridge.py b/can/bridge.py
index a2cbfd4aa..130ed46c6 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -112,7 +112,7 @@ def main() -> None:
if len(args) >= 1:
if args[0] == "-h" or args[0] == "help":
print(USAGE)
- raise SystemExit()
+ raise SystemExit() from None
elif args[0] == "help_bus":
bus_parser.print_help(sys.stderr)
else:
From de20baf367f21be972b5e7940c0adf2b4c15893e Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 18:34:02 +0100
Subject: [PATCH 20/34] Fix typo busses to bus
---
can/bridge.py | 14 +++++++-------
doc/scripts.rst | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 130ed46c6..0b42d525f 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -1,7 +1,7 @@
"""
-Creates a bridge between two CAN busses.
+Creates a bridge between two CAN buses.
-This will connect to two CAN busses. Messages received on one
+This will connect to two CAN buses. Messages received on one
bus will be sent to the other bus and vice versa.
"""
@@ -19,10 +19,10 @@
USAGE = """
usage: can_bridge [{general config} --] {can A config} -- {can B config}
-Bridge two CAN busses.
+Bridge two CAN buses.
-Both can busses will be connected so that messages from bus A will be sent on
-bus B and messages on bus B will be sent to bus A. The busses are separated by a `--`
+Both can buses will be connected so that messages from bus A will be sent on
+bus B and messages on bus B will be sent to bus A. The buses are separated by a `--`
positional arguments:
{general config} The configuration for this program excluding
@@ -93,11 +93,11 @@ def main() -> None:
default=2,
)
- bus_parser = argparse.ArgumentParser(description="Bridge two CAN busses.")
+ bus_parser = argparse.ArgumentParser(description="Bridge two CAN buses.")
_create_base_argument_parser(bus_parser)
- parser = argparse.ArgumentParser(description="Bridge two CAN busses.")
+ parser = argparse.ArgumentParser(description="Bridge two CAN buses.")
parser.add_argument("configs", nargs=argparse.REMAINDER)
# print help message when no arguments were given
diff --git a/doc/scripts.rst b/doc/scripts.rst
index 281391162..47555bf87 100644
--- a/doc/scripts.rst
+++ b/doc/scripts.rst
@@ -60,7 +60,7 @@ The full usage page can be seen below:
can.bridge
----------
-A small application that can be used to connect two can busses:
+A small application that can be used to connect two can buses:
.. command-output:: python -m can.bridge -h
:shell:
From 5a17ef6d01b57abcff4d06d588788e66c0699cf0 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 18:48:55 +0100
Subject: [PATCH 21/34] Add type annotations
---
can/bridge.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 0b42d525f..12d04ca9d 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -11,6 +11,9 @@
import sys
import time
from datetime import datetime
+from typing import (
+ Iterator,
+)
import can
@@ -44,7 +47,7 @@ class UserError(Exception):
pass
-def get_config_list(it, separator, conf):
+def get_config_list(it: Iterator[str], separator: str, conf) -> None:
while True:
el = next(it)
if el == separator:
@@ -53,7 +56,9 @@ def get_config_list(it, separator, conf):
conf.append(el)
-def split_configurations(arg_list, separator="--"):
+def split_configurations(
+ arg_list: list[str], separator: str = "--"
+) -> (list, list, list):
general = []
conf_a = []
conf_b = []
From d81dbab363912229224dce4e00cc8bc7ea60c78e Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 18:52:36 +0100
Subject: [PATCH 22/34] Fix type annotations
---
can/bridge.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 12d04ca9d..3300a50a7 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -13,6 +13,7 @@
from datetime import datetime
from typing import (
Iterator,
+ List,
)
import can
@@ -47,7 +48,7 @@ class UserError(Exception):
pass
-def get_config_list(it: Iterator[str], separator: str, conf) -> None:
+def get_config_list(it: Iterator[str], separator: str, conf: list) -> None:
while True:
el = next(it)
if el == separator:
@@ -57,7 +58,7 @@ def get_config_list(it: Iterator[str], separator: str, conf) -> None:
def split_configurations(
- arg_list: list[str], separator: str = "--"
+ arg_list: List[str], separator: str = "--"
) -> (list, list, list):
general = []
conf_a = []
From 2e8652f2462e065385f07c843d34112482f6c7a2 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 18:55:41 +0100
Subject: [PATCH 23/34] Fix type annotations again
---
can/bridge.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/can/bridge.py b/can/bridge.py
index 3300a50a7..50da299a3 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -14,6 +14,7 @@
from typing import (
Iterator,
List,
+ Tuple,
)
import can
@@ -59,10 +60,10 @@ def get_config_list(it: Iterator[str], separator: str, conf: list) -> None:
def split_configurations(
arg_list: List[str], separator: str = "--"
-) -> (list, list, list):
+) -> Tuple[list, list, list]:
general = []
- conf_a = []
- conf_b = []
+ conf_a: List[str] = []
+ conf_b: List[str] = []
found_sep = False
it = iter(arg_list)
From 3d707610d959caadff299c01238c1af0cd097efa Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 19:47:03 +0100
Subject: [PATCH 24/34] Add --help to get help
---
can/bridge.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/can/bridge.py b/can/bridge.py
index 50da299a3..bbae0a3e1 100644
--- a/can/bridge.py
+++ b/can/bridge.py
@@ -117,7 +117,7 @@ def main() -> None:
general, conf_a, conf_b = split_configurations(args)
except UserError as exc:
if len(args) >= 1:
- if args[0] == "-h" or args[0] == "help":
+ if args[0] == "-h" or args[0] == "--help" or args[0] == "help":
print(USAGE)
raise SystemExit() from None
elif args[0] == "help_bus":
From e883a4e793ff57d4fa5a88790ef6bf5736117214 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 19:47:17 +0100
Subject: [PATCH 25/34] Add basic print help test
---
test/test_scripts.py | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/test/test_scripts.py b/test/test_scripts.py
index 9d8c059cf..c1a6c082d 100644
--- a/test/test_scripts.py
+++ b/test/test_scripts.py
@@ -98,6 +98,20 @@ def _import(self):
return module
+class TestBridgeScript(CanScriptTest):
+ def _commands(self):
+ commands = [
+ "python -m can.bridge --help",
+ "can_bridge --help",
+ ]
+ return commands
+
+ def _import(self):
+ import can.bridge as module
+
+ return module
+
+
class TestLogconvertScript(CanScriptTest):
def _commands(self):
commands = [
From e32b5d66ab5300f1b17cd3aaed9bb5f8415f1add Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 19:52:55 +0100
Subject: [PATCH 26/34] Add basic test file for bridge script
---
test/test_bridge.py | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
create mode 100644 test/test_bridge.py
diff --git a/test/test_bridge.py b/test/test_bridge.py
new file mode 100644
index 000000000..43fb96e06
--- /dev/null
+++ b/test/test_bridge.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+"""
+This module tests the functions inside of bridge.py
+"""
+
+import unittest
+from unittest import mock
+from unittest.mock import Mock
+
+import can
+import can.bridge
+
+
+class TestBridgeScriptModule(unittest.TestCase):
+ def setUp(self) -> None:
+ # Patch VirtualBus object
+ patcher_virtual_bus = mock.patch("can.interfaces.virtual.VirtualBus", spec=True)
+ self.MockVirtualBus = patcher_virtual_bus.start()
+ self.addCleanup(patcher_virtual_bus.stop)
+ self.mock_virtual_bus = self.MockVirtualBus.return_value
+ self.mock_virtual_bus.shutdown = Mock()
+
+ self.testmsg = can.Message(
+ arbitration_id=0xC0FFEE, data=[0, 25, 0, 1, 3, 1, 4, 1], is_extended_id=True
+ )
+
+ def assert_successfull_cleanup(self):
+ self.MockVirtualBus.assert_called_once()
+ self.mock_virtual_bus.shutdown.assert_called_once()
+
+
+if __name__ == "__main__":
+ unittest.main()
From 74556a1717d5e9042147b43039851b5804ab23e8 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 20:16:02 +0100
Subject: [PATCH 27/34] Add very basic test
---
test/test_bridge.py | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/test/test_bridge.py b/test/test_bridge.py
index 43fb96e06..bd857b071 100644
--- a/test/test_bridge.py
+++ b/test/test_bridge.py
@@ -4,6 +4,7 @@
This module tests the functions inside of bridge.py
"""
+import sys
import unittest
from unittest import mock
from unittest.mock import Mock
@@ -21,13 +22,26 @@ def setUp(self) -> None:
self.mock_virtual_bus = self.MockVirtualBus.return_value
self.mock_virtual_bus.shutdown = Mock()
+ # Patch time sleep object
+ patcher_sleep = mock.patch("can.io.player.time.sleep", spec=True)
+ self.MockSleep = patcher_sleep.start()
+ self.addCleanup(patcher_sleep.stop)
+
self.testmsg = can.Message(
arbitration_id=0xC0FFEE, data=[0, 25, 0, 1, 3, 1, 4, 1], is_extended_id=True
)
+ self.busargs = ["-i", "virtual"]
+
def assert_successfull_cleanup(self):
- self.MockVirtualBus.assert_called_once()
- self.mock_virtual_bus.shutdown.assert_called_once()
+ self.MockVirtualBus.assert_called()
+
+ def test_bridge_no_config(self):
+ self.MockSleep.side_effect = KeyboardInterrupt
+ sys.argv = [sys.argv[0], *self.busargs, "--", *self.busargs]
+ can.bridge.main()
+
+ self.assert_successfull_cleanup()
if __name__ == "__main__":
From 8a04304c901264e98af3256412d66bd4fa16058d Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 20:20:56 +0100
Subject: [PATCH 28/34] Add different channels for virtual bus
---
test/test_bridge.py | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/test/test_bridge.py b/test/test_bridge.py
index bd857b071..3189d18b7 100644
--- a/test/test_bridge.py
+++ b/test/test_bridge.py
@@ -38,7 +38,16 @@ def assert_successfull_cleanup(self):
def test_bridge_no_config(self):
self.MockSleep.side_effect = KeyboardInterrupt
- sys.argv = [sys.argv[0], *self.busargs, "--", *self.busargs]
+ sys.argv = [
+ sys.argv[0],
+ *self.busargs,
+ "-c",
+ "can_a",
+ "--",
+ *self.busargs,
+ "-c",
+ "can_b",
+ ]
can.bridge.main()
self.assert_successfull_cleanup()
From 05f3f03dfddbf8c4438fca2abf312fb99973240f Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 20:28:39 +0100
Subject: [PATCH 29/34] Add assert for call to exit
---
test/test_bridge.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/test_bridge.py b/test/test_bridge.py
index 3189d18b7..b17030aff 100644
--- a/test/test_bridge.py
+++ b/test/test_bridge.py
@@ -20,7 +20,7 @@ def setUp(self) -> None:
self.MockVirtualBus = patcher_virtual_bus.start()
self.addCleanup(patcher_virtual_bus.stop)
self.mock_virtual_bus = self.MockVirtualBus.return_value
- self.mock_virtual_bus.shutdown = Mock()
+ self.mock_virtual_bus.__enter__ = Mock(return_value=self.mock_virtual_bus)
# Patch time sleep object
patcher_sleep = mock.patch("can.io.player.time.sleep", spec=True)
@@ -35,6 +35,7 @@ def setUp(self) -> None:
def assert_successfull_cleanup(self):
self.MockVirtualBus.assert_called()
+ self.assertEqual(2, len(self.mock_virtual_bus.__exit__.mock_calls))
def test_bridge_no_config(self):
self.MockSleep.side_effect = KeyboardInterrupt
From 6bfcae9f8425c7c40f6de6ad5d106169aaa6371f Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Sun, 23 Feb 2025 20:33:11 +0100
Subject: [PATCH 30/34] Patch correct function
---
test/test_bridge.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/test_bridge.py b/test/test_bridge.py
index b17030aff..c57b5768b 100644
--- a/test/test_bridge.py
+++ b/test/test_bridge.py
@@ -23,7 +23,7 @@ def setUp(self) -> None:
self.mock_virtual_bus.__enter__ = Mock(return_value=self.mock_virtual_bus)
# Patch time sleep object
- patcher_sleep = mock.patch("can.io.player.time.sleep", spec=True)
+ patcher_sleep = mock.patch("can.bridge.time.sleep", spec=True)
self.MockSleep = patcher_sleep.start()
self.addCleanup(patcher_sleep.stop)
From 6ffc7d418862eedcb86e4ad490bcc44892d3f408 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Mon, 24 Feb 2025 21:20:16 +0100
Subject: [PATCH 31/34] test
---
test/test_bridge.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/test_bridge.py b/test/test_bridge.py
index c57b5768b..973f98e93 100644
--- a/test/test_bridge.py
+++ b/test/test_bridge.py
@@ -49,9 +49,9 @@ def test_bridge_no_config(self):
"-c",
"can_b",
]
- can.bridge.main()
+ #can.bridge.main()
- self.assert_successfull_cleanup()
+ #self.assert_successfull_cleanup()
if __name__ == "__main__":
From 036e25c99802572f7424dd33d5d066a37cc82773 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Mon, 24 Feb 2025 21:23:59 +0100
Subject: [PATCH 32/34] fjkdf
---
test/test_bridge.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/test_bridge.py b/test/test_bridge.py
index 973f98e93..df5a10a94 100644
--- a/test/test_bridge.py
+++ b/test/test_bridge.py
@@ -49,7 +49,7 @@ def test_bridge_no_config(self):
"-c",
"can_b",
]
- #can.bridge.main()
+ can.bridge.main()
#self.assert_successfull_cleanup()
From e8f03ed2f191901608f3ed2d26b0def81cd53586 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Mon, 24 Feb 2025 21:27:42 +0100
Subject: [PATCH 33/34] once again -.-
---
test/test_bridge.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/test_bridge.py b/test/test_bridge.py
index df5a10a94..c57b5768b 100644
--- a/test/test_bridge.py
+++ b/test/test_bridge.py
@@ -51,7 +51,7 @@ def test_bridge_no_config(self):
]
can.bridge.main()
- #self.assert_successfull_cleanup()
+ self.assert_successfull_cleanup()
if __name__ == "__main__":
From 8df35aa43e1fd5bd563fe9c6ce2b0c94cd554864 Mon Sep 17 00:00:00 2001
From: Peter Kessen
Date: Mon, 24 Feb 2025 21:32:40 +0100
Subject: [PATCH 34/34] Try snakecase
---
test/test_bridge.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/test_bridge.py b/test/test_bridge.py
index c57b5768b..11e645ede 100644
--- a/test/test_bridge.py
+++ b/test/test_bridge.py
@@ -33,7 +33,7 @@ def setUp(self) -> None:
self.busargs = ["-i", "virtual"]
- def assert_successfull_cleanup(self):
+ def assertSuccessfullCleanup(self):
self.MockVirtualBus.assert_called()
self.assertEqual(2, len(self.mock_virtual_bus.__exit__.mock_calls))
@@ -51,7 +51,7 @@ def test_bridge_no_config(self):
]
can.bridge.main()
- self.assert_successfull_cleanup()
+ self.assertSuccessfullCleanup()
if __name__ == "__main__":