pyxcp 0.22.35__tar.gz → 0.23.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyxcp might be problematic. Click here for more details.

Files changed (125) hide show
  1. {pyxcp-0.22.35 → pyxcp-0.23.1}/PKG-INFO +1 -1
  2. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyproject.toml +1 -4
  3. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/__init__.py +1 -1
  4. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/config/__init__.py +12 -2
  5. pyxcp-0.23.1/pyxcp/daq_stim/scheduler.cpp +62 -0
  6. pyxcp-0.23.1/pyxcp/examples/xcp_user_supplied_driver.py +44 -0
  7. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/scripts/xcp_info.py +1 -3
  8. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/transport/can.py +131 -16
  9. pyxcp-0.22.35/pyxcp/daq_stim/scheduler.cpp +0 -28
  10. pyxcp-0.22.35/pyxcp/examples/xcp_user_supplied_driver.py +0 -54
  11. {pyxcp-0.22.35 → pyxcp-0.23.1}/CMakeLists.txt +0 -0
  12. {pyxcp-0.22.35 → pyxcp-0.23.1}/LICENSE +0 -0
  13. {pyxcp-0.22.35 → pyxcp-0.23.1}/README.md +0 -0
  14. {pyxcp-0.22.35 → pyxcp-0.23.1}/build_ext.py +0 -0
  15. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/EtasCANMonitoring.a2l +0 -0
  16. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/EtasCANMonitoring.aml +0 -0
  17. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/XCP_Common.aml +0 -0
  18. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/XCPonCAN.aml +0 -0
  19. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/XCPonEth.aml +0 -0
  20. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/XCPonFlx.aml +0 -0
  21. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/XCPonSxI.aml +0 -0
  22. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/XCPonUSB.aml +0 -0
  23. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/ifdata_CAN.a2l +0 -0
  24. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/ifdata_Eth.a2l +0 -0
  25. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/ifdata_Flx.a2l +0 -0
  26. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/ifdata_SxI.a2l +0 -0
  27. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/aml/ifdata_USB.a2l +0 -0
  28. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/asam/__init__.py +0 -0
  29. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/asam/types.py +0 -0
  30. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/asamkeydll.c +0 -0
  31. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/asamkeydll.sh +0 -0
  32. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/checksum.py +0 -0
  33. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/cmdline.py +0 -0
  34. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/config/legacy.py +0 -0
  35. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/constants.py +0 -0
  36. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/cpp_ext/__init__.py +0 -0
  37. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/cpp_ext/bin.hpp +0 -0
  38. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/cpp_ext/blockmem.hpp +0 -0
  39. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/cpp_ext/daqlist.hpp +0 -0
  40. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/cpp_ext/event.hpp +0 -0
  41. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/cpp_ext/extension_wrapper.cpp +0 -0
  42. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/cpp_ext/helper.hpp +0 -0
  43. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/cpp_ext/mcobject.hpp +0 -0
  44. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/cpp_ext/tsqueue.hpp +0 -0
  45. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/daq_stim/__init__.py +0 -0
  46. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/daq_stim/optimize/__init__.py +0 -0
  47. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/daq_stim/optimize/binpacking.py +0 -0
  48. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/daq_stim/scheduler.hpp +0 -0
  49. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/daq_stim/stim.cpp +0 -0
  50. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/daq_stim/stim.hpp +0 -0
  51. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/daq_stim/stim_wrapper.cpp +0 -0
  52. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/dllif.py +0 -0
  53. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/errormatrix.py +0 -0
  54. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/conf_can.toml +0 -0
  55. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/conf_can_user.toml +0 -0
  56. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/conf_can_vector.json +0 -0
  57. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/conf_can_vector.toml +0 -0
  58. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/conf_eth.toml +0 -0
  59. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/conf_nixnet.json +0 -0
  60. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/conf_socket_can.toml +0 -0
  61. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/conf_sxi.json +0 -0
  62. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/conf_sxi.toml +0 -0
  63. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/run_daq.py +0 -0
  64. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/xcp_policy.py +0 -0
  65. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/xcp_read_benchmark.py +0 -0
  66. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/xcp_skel.py +0 -0
  67. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/xcp_unlock.py +0 -0
  68. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/xcphello.py +0 -0
  69. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/examples/xcphello_recorder.py +0 -0
  70. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/master/__init__.py +0 -0
  71. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/master/errorhandler.py +0 -0
  72. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/master/master.py +0 -0
  73. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/py.typed +0 -0
  74. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/__init__.py +0 -0
  75. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/build_clang.cmd +0 -0
  76. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/build_clang.sh +0 -0
  77. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/build_gcc.cmd +0 -0
  78. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/build_gcc.sh +0 -0
  79. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/build_gcc_arm.sh +0 -0
  80. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/converter/__init__.py +0 -0
  81. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/lz4.c +0 -0
  82. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/lz4.h +0 -0
  83. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/lz4hc.c +0 -0
  84. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/lz4hc.h +0 -0
  85. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/mio.hpp +0 -0
  86. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/reader.hpp +0 -0
  87. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/reco.py +0 -0
  88. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/recorder.rst +0 -0
  89. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/rekorder.cpp +0 -0
  90. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/rekorder.hpp +0 -0
  91. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/setup.py +0 -0
  92. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/test_reko.py +0 -0
  93. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/unfolder.hpp +0 -0
  94. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/wrap.cpp +0 -0
  95. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/recorder/writer.hpp +0 -0
  96. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/scripts/__init__.py +0 -0
  97. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/scripts/pyxcp_probe_can_drivers.py +0 -0
  98. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/scripts/xcp_examples.py +0 -0
  99. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/scripts/xcp_fetch_a2l.py +0 -0
  100. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/scripts/xcp_id_scanner.py +0 -0
  101. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/scripts/xcp_profile.py +0 -0
  102. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/scripts/xmraw_converter.py +0 -0
  103. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/stim/__init__.py +0 -0
  104. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/tests/test_asam_types.py +0 -0
  105. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/tests/test_binpacking.py +0 -0
  106. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/tests/test_can.py +0 -0
  107. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/tests/test_checksum.py +0 -0
  108. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/tests/test_daq.py +0 -0
  109. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/tests/test_daq_opt.py +0 -0
  110. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/tests/test_frame_padding.py +0 -0
  111. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/tests/test_master.py +0 -0
  112. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/tests/test_transport.py +0 -0
  113. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/tests/test_utils.py +0 -0
  114. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/timing.py +0 -0
  115. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/transport/__init__.py +0 -0
  116. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/transport/base.py +0 -0
  117. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/transport/base_transport.hpp +0 -0
  118. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/transport/eth.py +0 -0
  119. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/transport/sxi.py +0 -0
  120. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/transport/transport_wrapper.cpp +0 -0
  121. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/transport/usb_transport.py +0 -0
  122. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/types.py +0 -0
  123. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/utils.py +0 -0
  124. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/vector/__init__.py +0 -0
  125. {pyxcp-0.22.35 → pyxcp-0.23.1}/pyxcp/vector/map.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pyxcp
3
- Version: 0.22.35
3
+ Version: 0.23.1
4
4
  Summary: Universal Calibration Protocol for Python
5
5
  License: LGPLv3
6
6
  Keywords: automotive,ecu,xcp,asam,autosar
@@ -37,7 +37,7 @@ dynamic = ["license", "readme", "authors", "requires-python", "description", "cl
37
37
  [tool.poetry]
38
38
  authors = ["Christoph Schueler <cpu.gems@googlemail.com>"]
39
39
  name = "pyxcp"
40
- version = "0.22.35"
40
+ version = "0.23.1"
41
41
  readme = "README.md"
42
42
  description = "Universal Calibration Protocol for Python"
43
43
  keywords = ["automotive", "ecu", "xcp", "asam", "autosar"]
@@ -173,9 +173,6 @@ build = "cp3{10,11,12,13,14}-*"
173
173
  skip = ["*_i686", "*-musllinux*"]
174
174
  build-frontend = "build"
175
175
 
176
- [tool.cibuildwheel.windows]
177
- archs = ["AMD64"]
178
-
179
176
  [tool.pyright]
180
177
  include = ["pyxcp", "build_ext.py"]
181
178
  ignore = ["pyxcp/recorder/converter/**", "pyxcp/recorder/simdjson/**","pyxcp/recorder/mio/**", "pyxcp/recorder/lz4/**"]
@@ -17,4 +17,4 @@ tb_install(show_locals=True, max_frames=3) # Install custom exception handler.
17
17
 
18
18
  # if you update this manually, do not forget to update
19
19
  # .bumpversion.cfg and pyproject.toml.
20
- __version__ = "0.22.35"
20
+ __version__ = "0.23.1"
@@ -490,6 +490,12 @@ If set, the `app_name` does not have to be previously defined in
490
490
  )
491
491
 
492
492
 
493
+ class CanCustom(Configurable, CanBase):
494
+ """ """
495
+
496
+ interface_name = "custom"
497
+
498
+
493
499
  class Virtual(Configurable, CanBase):
494
500
  """ """
495
501
 
@@ -542,11 +548,13 @@ CAN_INTERFACE_MAP = {
542
548
  "usb2can": Usb2Can,
543
549
  "vector": Vector,
544
550
  "virtual": Virtual,
551
+ "custom": CanCustom,
545
552
  }
546
553
 
547
554
 
548
555
  class Can(Configurable):
549
- VALID_INTERFACES = can.interfaces.VALID_INTERFACES
556
+ VALID_INTERFACES = set(can.interfaces.VALID_INTERFACES)
557
+ VALID_INTERFACES.add("custom")
550
558
 
551
559
  interface = Enum(
552
560
  values=VALID_INTERFACES, default_value=None, allow_none=True, help="CAN interface supported by python-can"
@@ -605,6 +613,7 @@ timing-related parameters.
605
613
  classes = List(
606
614
  [
607
615
  CanAlystii,
616
+ CanCustom,
608
617
  CanTact,
609
618
  Etas,
610
619
  Gs_Usb,
@@ -640,6 +649,7 @@ timing-related parameters.
640
649
  " {type(self.interface).__name__} {self.interface}."
641
650
  )
642
651
  self.canalystii = CanAlystii(config=self.config, parent=self)
652
+ self.cancustom = CanCustom(config=self.config, parent=self)
643
653
  self.cantact = CanTact(config=self.config, parent=self)
644
654
  self.etas = Etas(config=self.config, parent=self)
645
655
  self.gs_usb = Gs_Usb(config=self.config, parent=self)
@@ -798,7 +808,7 @@ class Transport(Configurable):
798
808
  allow_none=True,
799
809
  help="Choose one of the supported XCP transport layers.",
800
810
  ).tag(config=True)
801
- create_daq_timestamps = Bool(False, help="Record time of frame reception or set timestamp to 0.").tag(config=True)
811
+ create_daq_timestamps = Bool(True, help="Record time of frame reception or set timestamp to 0.").tag(config=True)
802
812
  timeout = Float(
803
813
  2.0,
804
814
  help="""raise `XcpTimeoutError` after `timeout` seconds
@@ -0,0 +1,62 @@
1
+ #include "scheduler.hpp"
2
+
3
+ #if defined(_WIN32)
4
+
5
+ #include <cstdio>
6
+ #include <cstdint>
7
+
8
+ VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired) {
9
+ if (lpParam == nullptr) {
10
+ std::printf("TimerRoutine lpParam is NULL\n");
11
+ return;
12
+ }
13
+
14
+ const auto* param = static_cast<const int*>(lpParam);
15
+ std::printf("Timer routine called. Parameter is %d.\n", *param);
16
+
17
+ if (TimerOrWaitFired) {
18
+ std::printf("The wait timed out.\n");
19
+ } else {
20
+ std::printf("The wait event was signaled.\n");
21
+ }
22
+ }
23
+
24
+ #endif // _WIN32
25
+
26
+ // Vectorized multiply implementation with bounds checking
27
+ namespace {
28
+ constexpr size_t VECTOR_SIZE = 4;
29
+ }
30
+
31
+ #if defined(_M_X64) || defined(_M_IX86) || defined(__SSE__)
32
+ #include <xmmintrin.h>
33
+
34
+ void mul4_vectorized(float* ptr) {
35
+ if (ptr == nullptr) return;
36
+
37
+ __m128 f = _mm_loadu_ps(ptr);
38
+ f = _mm_mul_ps(f, f);
39
+ _mm_storeu_ps(ptr, f);
40
+ }
41
+
42
+ #elif defined(_M_ARM64) || defined(__ARM_NEON)
43
+ #include <arm_neon.h>
44
+
45
+ void mul4_vectorized(float* ptr) {
46
+ if (ptr == nullptr) return;
47
+
48
+ float32x4_t f = vld1q_f32(ptr);
49
+ f = vmulq_f32(f, f);
50
+ vst1q_f32(ptr, f);
51
+ }
52
+
53
+ #else
54
+ // Scalar fallback
55
+ void mul4_vectorized(float* ptr) {
56
+ if (ptr == nullptr) return;
57
+
58
+ for (size_t i = 0; i < VECTOR_SIZE; ++i) {
59
+ ptr[i] *= ptr[i];
60
+ }
61
+ }
62
+ #endif
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env python
2
+
3
+ from typing import Dict, List, Optional
4
+
5
+ import can
6
+
7
+ from pyxcp.cmdline import ArgumentParser
8
+ from pyxcp.transport.can import CanInterfaceBase
9
+
10
+
11
+ class CustomCANInterface(CanInterfaceBase):
12
+
13
+ def init(self):
14
+ """Initialize the CAN interface here."""
15
+
16
+ def set_filters(self, filters):
17
+ print(f"set_filters({filters})")
18
+ self._filters = filters
19
+
20
+ def recv(self, timeout: Optional[float] = None) -> Optional[can.message.Message]:
21
+ """Receive CAN frames."""
22
+ return can.message.Message()
23
+
24
+ def send(self, msg: can.message.Message):
25
+ """Send CAN frames."""
26
+ print(f"send({msg})")
27
+
28
+ @property
29
+ def filters(self):
30
+ """Return the current CAN filters."""
31
+ return self._filters
32
+
33
+ @property
34
+ def state(self):
35
+ """Return the current state of the CAN interface."""
36
+ return can.BusState.ACTIVE
37
+
38
+
39
+ custom_interface = CustomCANInterface()
40
+
41
+ ap = ArgumentParser(description="User supplied CAN driver.")
42
+ with ap.run(transport_layer_interface=custom_interface) as x:
43
+ x.connect()
44
+ x.disconnect()
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
 
3
- """XCP info/exploration tool.
4
- """
3
+ """XCP info/exploration tool."""
5
4
 
6
5
  from pprint import pprint
7
6
 
@@ -21,7 +20,6 @@ def getPagInfo(x):
21
20
  for i in range(pag.maxSegments):
22
21
  segment = {}
23
22
  status, std_info = x.try_command(x.getSegmentInfo, 0x01, i, 0, 0)
24
- std_info = x.getSegmentInfo(0x01, i, 2, 0)
25
23
  if status == TryCommandResult.OK:
26
24
  segment["maxPages"] = std_info.maxPages
27
25
  segment["addressExtension"] = std_info.addressExtension
@@ -1,13 +1,20 @@
1
1
  #!/usr/bin/env python
2
- """
3
- """
2
+ """ """
4
3
 
5
4
  import functools
6
5
  import operator
6
+ from abc import ABC, abstractmethod
7
7
  from bisect import bisect_left
8
- from typing import Any, Dict, Optional, Type
9
-
10
- from can import CanError, CanInitializationError, Message, detect_available_configs
8
+ from enum import IntEnum
9
+ from typing import Any, Dict, List, Optional, Union
10
+
11
+ from can import (
12
+ BusState,
13
+ CanError,
14
+ CanInitializationError,
15
+ Message,
16
+ detect_available_configs,
17
+ )
11
18
  from can.bus import BusABC
12
19
  from can.interface import _get_class_for_interface
13
20
  from rich.console import Console
@@ -27,6 +34,55 @@ MAX_DLC_CLASSIC = 8
27
34
  CAN_FD_DLCS = (12, 16, 20, 24, 32, 48, 64) # Discrete CAN-FD DLCs in case DLC > 8.
28
35
 
29
36
 
37
+ class FilterState(IntEnum):
38
+ REJECT_ALL = 0
39
+ ACCEPT_ALL = 1
40
+ FILTERING = 2
41
+
42
+
43
+ class SoftwareFilter:
44
+ """Additional CAN filters in software."""
45
+
46
+ def __init__(self) -> None:
47
+ self.filters = None
48
+ self.reject_all()
49
+
50
+ def set_filters(self, filters: List[Dict]) -> None:
51
+ self.filters = filters
52
+ self.filtering()
53
+
54
+ def reject_all(self) -> None:
55
+ self.filter_state = FilterState.REJECT_ALL
56
+
57
+ def accept_all(self) -> None:
58
+ self.filter_state = FilterState.ACCEPT_ALL
59
+
60
+ def filtering(self) -> None:
61
+ self.filter_state = FilterState.FILTERING
62
+
63
+ @property
64
+ def state(self) -> FilterState:
65
+ return self.filter_state
66
+
67
+ def accept(self, msg: Message) -> bool:
68
+ """
69
+ Based on: https://github.com/hardbyte/python-can/blob/bc248e8aaf96280a574c06e8e7d2778a67f091e3/can/bus.py#L430
70
+ """
71
+ if self.filter_state == FilterState.REJECT_ALL:
72
+ return False
73
+ elif self.filter_state == FilterState.ACCEPT_ALL or self.filters is None:
74
+ return True
75
+ for filter in self.filters:
76
+ if "extended" in filter:
77
+ if filter["extended"] != msg.is_extended_id:
78
+ continue
79
+ can_id = filter["can_id"]
80
+ can_mask = filter["can_mask"]
81
+ if (can_id ^ msg.arbitration_id) & can_mask == 0:
82
+ return True
83
+ return False
84
+
85
+
30
86
  class IdentifierOutOfRangeError(Exception):
31
87
  """Signals an identifier greater then :obj:`MAX_11_BIT_IDENTIFIER` or :obj:`MAX_29_BIT_IDENTIFIER`."""
32
88
 
@@ -235,32 +291,47 @@ class PythonCanWrapper:
235
291
  self.interface_name: str = interface_name
236
292
  self.timeout: int = timeout
237
293
  self.parameters = parameters
238
- self.can_interface_class: Type[BusABC] = _get_class_for_interface(self.interface_name)
294
+ if not self.parent.has_user_supplied_interface:
295
+ self.can_interface_class = _get_class_for_interface(self.interface_name)
296
+ else:
297
+ self.can_interface_class = None
239
298
  self.can_interface: BusABC
240
299
  self.connected: bool = False
300
+ self.software_filter = SoftwareFilter()
301
+ self.saved_filters = []
241
302
 
242
- def connect(self):
303
+ def connect(self) -> None:
243
304
  if self.connected:
244
305
  return
245
306
  can_filters = []
246
307
  can_filters.append(self.parent.can_id_slave.create_filter_from_id()) # Primary CAN filter.
247
- if self.parent.has_user_supplied_interface:
248
- self.can_interface = self.parent.transport_layer_interface
249
- else:
250
- self.can_interface = self.can_interface_class(interface=self.interface_name, **self.parameters)
251
308
  if self.parent.daq_identifier:
252
309
  # Add filters for DAQ identifiers.
253
310
  for daq_id in self.parent.daq_identifier:
254
311
  can_filters.append(daq_id.create_filter_from_id())
255
- self.can_interface.set_filters(can_filters)
312
+ if self.parent.has_user_supplied_interface:
313
+ self.saved_filters = self.parent.transport_layer_interface.filters
314
+ if self.saved_filters:
315
+ merged_filters = can_filters[::]
316
+ for fltr in self.saved_filters:
317
+ if fltr not in merged_filters:
318
+ merged_filters.append(fltr)
319
+ self.can_interface = self.parent.transport_layer_interface
320
+ self.can_interface.set_filters(merged_filters)
321
+ self.software_filter.set_filters(can_filters) # Filter unwanted traffic.
322
+ else:
323
+ self.can_interface = self.can_interface_class(interface=self.interface_name, can_filters=can_filters, **self.parameters)
324
+ self.software_filter.accept_all()
256
325
  self.parent.logger.info(f"XCPonCAN - Using Interface: '{self.can_interface!s}'")
257
326
  self.parent.logger.info(f"XCPonCAN - Filters used: {self.can_interface.filters}")
258
327
  self.parent.logger.info(f"XCPonCAN - State: {self.can_interface.state!s}")
259
328
  self.connected = True
260
329
 
261
- def close(self):
330
+ def close(self) -> None:
262
331
  if self.connected and not self.parent.has_user_supplied_interface:
263
332
  self.can_interface.shutdown()
333
+ if self.saved_filters:
334
+ self.can_interface.set_filters(self.saved_filters)
264
335
  self.connected = False
265
336
 
266
337
  def transmit(self, payload: bytes) -> None:
@@ -282,6 +353,8 @@ class PythonCanWrapper:
282
353
  else:
283
354
  if frame is None or not len(frame.data):
284
355
  return None # Timeout condition.
356
+ if not self.software_filter.accept(frame):
357
+ return None # Filter out unwanted traffic.
285
358
  extended = frame.is_extended_id
286
359
  identifier = Identifier.make_identifier(frame.arbitration_id, extended)
287
360
  return Frame(
@@ -326,9 +399,14 @@ class Can(BaseTransport):
326
399
  self.daq_identifier.append(Identifier(daq_id))
327
400
  self.max_dlc_required = self.config.max_dlc_required
328
401
  self.padding_value = self.config.padding_value
329
- self.interface_name = self.config.interface
330
- self.interface_configuration = detect_available_configs(interfaces=[self.interface_name])
331
- parameters = self.get_interface_parameters()
402
+ if transport_layer_interface is None:
403
+ self.interface_name = self.config.interface
404
+ self.interface_configuration = detect_available_configs(interfaces=[self.interface_name])
405
+ parameters = self.get_interface_parameters()
406
+ else:
407
+ self.interface_name = "custom"
408
+ # print("TRY GET PARAMs", self.get_interface_parameters())
409
+ parameters = {}
332
410
  self.can_interface = PythonCanWrapper(self, self.interface_name, config.timeout, **parameters)
333
411
  self.logger.info(f"XCPonCAN - Interface-Type: {self.interface_name!r} Parameters: {list(parameters.items())}")
334
412
  self.logger.info(
@@ -439,3 +517,40 @@ def calculate_filter(ids: list):
439
517
  cmask = functools.reduce(operator.or_, raw_ids) ^ cfilter
440
518
  cmask ^= 0x1FFFFFFF if any_extended_ids else 0x7FF
441
519
  return (cfilter, cmask)
520
+
521
+
522
+ class CanInterfaceBase(ABC):
523
+ """
524
+ Base class for custom CAN interfaces.
525
+ This is basically a subset of python-CANs `BusABC`.
526
+ """
527
+
528
+ @abstractmethod
529
+ def set_filters(self, filters: Optional[List[Dict[str, Union[int, bool]]]] = None) -> None:
530
+ """Apply filtering to all messages received by this Bus.
531
+
532
+ filters:
533
+ A list of dictionaries, each containing a 'can_id', 'can_mask', and 'extended' field, e.g.:
534
+ [{"can_id": 0x11, "can_mask": 0x21, "extended": False}]
535
+ """
536
+
537
+ @abstractmethod
538
+ def recv(self, timeout: Optional[float] = None) -> Optional[Message]:
539
+ """Block waiting for a message from the Bus."""
540
+
541
+ @abstractmethod
542
+ def send(self, msg: Message) -> None:
543
+ """Transmit a message to the CAN bus."""
544
+
545
+ @property
546
+ @abstractmethod
547
+ def filters(self) -> Optional[List[Dict[str, Union[int, bool]]]]:
548
+ """Modify the filters of this bus."""
549
+
550
+ @property
551
+ @abstractmethod
552
+ def state(self) -> BusState:
553
+ """Return the current state of the hardware."""
554
+
555
+ def __repr__(self):
556
+ return f"{self.__class__.__name__}"
@@ -1,28 +0,0 @@
1
-
2
- #include "scheduler.hpp"
3
-
4
- #if defined(_WIN32)
5
-
6
- VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired) {
7
- if (lpParam == NULL) {
8
- printf("TimerRoutine lpParam is NULL\n");
9
- } else {
10
- // lpParam points to the argument; in this case it is an int
11
-
12
- printf("Timer routine called. Parameter is %d.\n", *(int*)lpParam);
13
- if (TimerOrWaitFired) {
14
- printf("The wait timed out.\n");
15
- } else {
16
- printf("The wait event was signaled.\n");
17
- }
18
- }
19
- }
20
-
21
- #include <xmmintrin.h>
22
-
23
- void mul4_vectorized(float* ptr) {
24
- __m128 f = _mm_loadu_ps(ptr);
25
- f = _mm_mul_ps(f, f);
26
- _mm_storeu_ps(ptr, f);
27
- }
28
- #endif
@@ -1,54 +0,0 @@
1
- #!/usr/bin/env python
2
- """User supplied CAN driver.
3
-
4
- Run as:
5
-
6
- .. code-block:: shell
7
-
8
- python xcp_user_supplied_driver.py -c conf_can_user.toml
9
- """
10
- from pyxcp.cmdline import ArgumentParser
11
- from pyxcp.transport.can import CanInterfaceBase
12
-
13
-
14
- class MyCI(CanInterfaceBase):
15
- """
16
-
17
- Relevant options in your configuration file (e.g. conf_can_user.toml):
18
-
19
- TRANSPORT = "CAN"
20
- CAN_DRIVER = "MyCI" # The name of your custom driver class.
21
-
22
- """
23
-
24
- def init(self, parent, receive_callback):
25
- self.parent = parent
26
-
27
- def connect(self):
28
- pass
29
-
30
- def close(self):
31
- pass
32
-
33
- def get_timestamp_resolution(self):
34
- pass
35
-
36
- def read(self):
37
- pass
38
-
39
- def transmit(self, payload: bytes):
40
- print("\tTX-PAYLOAD", payload)
41
-
42
-
43
- ap = ArgumentParser(description="User supplied CAN driver.")
44
- with ap.run() as x:
45
- x.connect()
46
- x.disconnect()
47
-
48
- """
49
- This do-nothing example will output
50
-
51
- TX-PAYLOAD b'\xff\x00'
52
-
53
- and then timeout (0xff is the service code for CONNECT_REQ).
54
- """
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes