py_canoe 3.0.4__py3-none-any.whl → 26.0.0__py3-none-any.whl

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.
Files changed (124) hide show
  1. py_canoe/__init__.py +2 -1
  2. py_canoe/canoe.py +910 -0
  3. py_canoe/core/__init__.py +0 -0
  4. py_canoe/core/application.py +170 -0
  5. py_canoe/core/bus.py +301 -0
  6. py_canoe/core/capl.py +59 -0
  7. py_canoe/core/child_elements/__init__.py +0 -0
  8. py_canoe/core/child_elements/application_model.py +24 -0
  9. py_canoe/core/child_elements/application_model_file.py +21 -0
  10. py_canoe/core/child_elements/application_model_files.py +22 -0
  11. py_canoe/core/child_elements/application_model_setup.py +15 -0
  12. py_canoe/core/child_elements/application_models.py +22 -0
  13. py_canoe/core/child_elements/application_socket.py +11 -0
  14. py_canoe/core/child_elements/application_specific_module.py +24 -0
  15. py_canoe/core/child_elements/application_specific_modules.py +16 -0
  16. py_canoe/core/child_elements/audio_interface.py +28 -0
  17. py_canoe/core/child_elements/available_modules.py +22 -0
  18. py_canoe/core/child_elements/basic_module.py +19 -0
  19. py_canoe/core/child_elements/basic_modules.py +16 -0
  20. py_canoe/core/child_elements/c_libraries.py +28 -0
  21. py_canoe/core/child_elements/c_library.py +33 -0
  22. py_canoe/core/child_elements/can_controller.py +74 -0
  23. py_canoe/core/child_elements/capl_function.py +17 -0
  24. py_canoe/core/child_elements/ccp_setup.py +15 -0
  25. py_canoe/core/child_elements/channel.py +20 -0
  26. py_canoe/core/child_elements/channels.py +19 -0
  27. py_canoe/core/child_elements/communication_setup.py +23 -0
  28. py_canoe/core/child_elements/compile_result.py +22 -0
  29. py_canoe/core/child_elements/configured_channel.py +48 -0
  30. py_canoe/core/child_elements/configured_channels.py +21 -0
  31. py_canoe/core/child_elements/configured_module.py +82 -0
  32. py_canoe/core/child_elements/configured_modules.py +61 -0
  33. py_canoe/core/child_elements/connected_modules.py +14 -0
  34. py_canoe/core/child_elements/data_source.py +42 -0
  35. py_canoe/core/child_elements/data_source_file.py +21 -0
  36. py_canoe/core/child_elements/data_source_files.py +22 -0
  37. py_canoe/core/child_elements/data_source_issue.py +22 -0
  38. py_canoe/core/child_elements/data_source_issues.py +16 -0
  39. py_canoe/core/child_elements/data_source_setup.py +17 -0
  40. py_canoe/core/child_elements/data_sources.py +27 -0
  41. py_canoe/core/child_elements/database_setup.py +62 -0
  42. py_canoe/core/child_elements/device.py +34 -0
  43. py_canoe/core/child_elements/devices.py +13 -0
  44. py_canoe/core/child_elements/diagnostic.py +22 -0
  45. py_canoe/core/child_elements/diagnostic_request.py +59 -0
  46. py_canoe/core/child_elements/diagnostic_response.py +34 -0
  47. py_canoe/core/child_elements/diagnostic_responses.py +13 -0
  48. py_canoe/core/child_elements/diagnostics_setup.py +254 -0
  49. py_canoe/core/child_elements/distributed_mode.py +74 -0
  50. py_canoe/core/child_elements/encoding.py +27 -0
  51. py_canoe/core/child_elements/encodings.py +13 -0
  52. py_canoe/core/child_elements/environment_array.py +13 -0
  53. py_canoe/core/child_elements/environment_group.py +22 -0
  54. py_canoe/core/child_elements/environment_info.py +14 -0
  55. py_canoe/core/child_elements/environment_variable.py +55 -0
  56. py_canoe/core/child_elements/fdx_files.py +50 -0
  57. py_canoe/core/child_elements/file_group_data_source.py +17 -0
  58. py_canoe/core/child_elements/general_setup.py +66 -0
  59. py_canoe/core/child_elements/macros_setup.py +52 -0
  60. py_canoe/core/child_elements/mc_ecus.py +428 -0
  61. py_canoe/core/child_elements/measurement_setup.py +269 -0
  62. py_canoe/core/child_elements/modules.py +87 -0
  63. py_canoe/core/child_elements/most_disassembler.py +21 -0
  64. py_canoe/core/child_elements/most_network_interface.py +4 -0
  65. py_canoe/core/child_elements/namespace.py +21 -0
  66. py_canoe/core/child_elements/namespaces.py +19 -0
  67. py_canoe/core/child_elements/network.py +18 -0
  68. py_canoe/core/child_elements/network_adapters.py +13 -0
  69. py_canoe/core/child_elements/nodes.py +119 -0
  70. py_canoe/core/child_elements/open_configuration_result.py +0 -0
  71. py_canoe/core/child_elements/panel_setup.py +97 -0
  72. py_canoe/core/child_elements/participant.py +17 -0
  73. py_canoe/core/child_elements/participants.py +22 -0
  74. py_canoe/core/child_elements/ports.py +81 -0
  75. py_canoe/core/child_elements/replay_collection.py +56 -0
  76. py_canoe/core/child_elements/security_configuration.py +20 -0
  77. py_canoe/core/child_elements/security_setup.py +31 -0
  78. py_canoe/core/child_elements/signals.py +39 -0
  79. py_canoe/core/child_elements/simulation_setup.py +0 -0
  80. py_canoe/core/child_elements/single_file_data_source.py +13 -0
  81. py_canoe/core/child_elements/snippet_setup.py +68 -0
  82. py_canoe/core/child_elements/standalone_mode.py +0 -0
  83. py_canoe/core/child_elements/start_value_list.py +0 -0
  84. py_canoe/core/child_elements/symbol_mappings.py +0 -0
  85. py_canoe/core/child_elements/tcp_ip_stack_setting.py +0 -0
  86. py_canoe/core/child_elements/test_configurations.py +0 -0
  87. py_canoe/core/child_elements/test_environment.py +64 -0
  88. py_canoe/core/child_elements/test_environments.py +26 -0
  89. py_canoe/core/child_elements/test_module.py +213 -0
  90. py_canoe/core/child_elements/test_modules.py +23 -0
  91. py_canoe/core/child_elements/test_setup.py +16 -0
  92. py_canoe/core/child_elements/test_setup_folder_ext.py +36 -0
  93. py_canoe/core/child_elements/test_setup_folders.py +25 -0
  94. py_canoe/core/child_elements/user_files.py +0 -0
  95. py_canoe/core/child_elements/variable.py +144 -0
  96. py_canoe/core/child_elements/variable_events.py +14 -0
  97. py_canoe/core/child_elements/variables.py +29 -0
  98. py_canoe/core/child_elements/variables_file.py +15 -0
  99. py_canoe/core/child_elements/variables_files.py +19 -0
  100. py_canoe/core/child_elements/visual_sequence_setup.py +46 -0
  101. py_canoe/core/child_elements/vt_system.py +83 -0
  102. py_canoe/core/child_elements/vtt_sut_import_result.py +21 -0
  103. py_canoe/core/child_elements/write.py +71 -0
  104. py_canoe/core/child_elements/xcp_setup.py +12 -0
  105. py_canoe/core/configuration.py +509 -0
  106. py_canoe/core/environment.py +59 -0
  107. py_canoe/core/measurement.py +149 -0
  108. py_canoe/core/networks.py +103 -0
  109. py_canoe/core/performance.py +21 -0
  110. py_canoe/core/simulation.py +53 -0
  111. py_canoe/core/system.py +164 -0
  112. py_canoe/core/ui.py +53 -0
  113. py_canoe/core/version.py +54 -0
  114. py_canoe/helpers/__init__.py +0 -0
  115. py_canoe/helpers/common.py +78 -0
  116. {py_canoe-3.0.4.dist-info → py_canoe-26.0.0.dist-info}/METADATA +332 -322
  117. py_canoe-26.0.0.dist-info/RECORD +118 -0
  118. py_canoe-26.0.0.dist-info/WHEEL +4 -0
  119. py_canoe/py_canoe.py +0 -2586
  120. py_canoe/py_canoe_utils/logging_collection.py +0 -345
  121. py_canoe/py_canoe_utils/py_canoe_logger.py +0 -29
  122. py_canoe-3.0.4.dist-info/LICENSE +0 -21
  123. py_canoe-3.0.4.dist-info/RECORD +0 -8
  124. py_canoe-3.0.4.dist-info/WHEEL +0 -4
File without changes
@@ -0,0 +1,170 @@
1
+ from pathlib import Path
2
+
3
+ import win32com.client
4
+ import win32com.client.gencache
5
+
6
+ from py_canoe.core.bus import Bus
7
+ from py_canoe.core.capl import Capl
8
+ from py_canoe.core.configuration import Configuration
9
+ from py_canoe.core.environment import Environment
10
+ from py_canoe.core.measurement import Measurement
11
+ from py_canoe.core.networks import Networks
12
+ from py_canoe.core.system import System
13
+ from py_canoe.core.ui import Ui
14
+ from py_canoe.core.version import Version
15
+ from py_canoe.helpers.common import DoEventsUntil, logger
16
+
17
+
18
+ class ApplicationEvents:
19
+ def __init__(self) -> None:
20
+ self.OPENED: bool = False
21
+ self.QUIT: bool = False
22
+ self.CANOE_CFG_FULLNAME: str = ""
23
+
24
+ def OnOpen(self, fullname: str) -> None:
25
+ self.CANOE_CFG_FULLNAME = fullname
26
+ self.OPENED = True
27
+
28
+ def OnQuit(self) -> None:
29
+ self.QUIT = True
30
+
31
+
32
+ class Application:
33
+ def __init__(self) -> None:
34
+ self.bus_types = {'CAN': 1, 'J1939': 2, 'TTP': 4, 'LIN': 5, 'MOST': 6, 'Kline': 14}
35
+ self.com_object = None
36
+ self.application_events = None
37
+ self.bus: Bus = None
38
+ self.capl: Capl = None
39
+ self.configuration: Configuration = None
40
+ self.environment: Environment = None
41
+ self.measurement: Measurement = None
42
+ self.system: System = None
43
+ self.ui: Ui = None
44
+ self.version: Version = None
45
+ self.capl_function_objects = object()
46
+ self.user_capl_functions = tuple()
47
+
48
+ @property
49
+ def full_name(self) -> str:
50
+ return self.com_object.FullName
51
+
52
+ @property
53
+ def name(self) -> str:
54
+ return self.com_object.Name
55
+
56
+ @property
57
+ def path(self) -> str:
58
+ return self.com_object.Path
59
+
60
+ @property
61
+ def visible(self) -> bool:
62
+ return self.com_object.Visible
63
+
64
+ @visible.setter
65
+ def visible(self, visible: bool) -> None:
66
+ self.com_object.Visible = visible
67
+
68
+ def _common_between_pre_and_post_cfg_open(self) -> None:
69
+ self.bus = Bus(self)
70
+ self.capl = Capl(self)
71
+ self.configuration = Configuration(self)
72
+ self.environment = Environment(self)
73
+ self.networks = Networks(self)
74
+ self.system = System(self)
75
+ self.ui = Ui(self)
76
+ self.version = Version(self)
77
+
78
+ def _launch_application(self) -> None:
79
+ try:
80
+ # We use gencache.EnsureDispatch to connect to the CANoe COM object.
81
+ # This is preferred over Dispatch or DispatchEx for a few reasons:
82
+ # 1. It connects to a running instance of CANoe if one exists, and
83
+ # starts a new instance if one is not running. This is the desired
84
+ # behavior for both attaching to an existing session and starting a new one.
85
+ # 2. It enables early binding by generating a static proxy in the gencache,
86
+ # which can improve performance.
87
+ # DispatchEx is not used because it would always start a new instance,
88
+ # which is not what we want for the 'attach' functionality.
89
+ self.com_object = win32com.client.gencache.EnsureDispatch("CANoe.Application")
90
+ self.application_events = win32com.client.WithEvents(self.com_object, ApplicationEvents)
91
+ self.measurement = Measurement(self)
92
+ self.capl_function_objects = lambda: self.measurement.measurement_events.CAPL_FUNCTION_OBJECTS
93
+ self.measurement.measurement_events.CAPL_FUNCTION_NAMES = self.user_capl_functions
94
+ self._common_between_pre_and_post_cfg_open()
95
+ except Exception as e:
96
+ logger.error(f"❌ Failed to launch CANoe application: {e}")
97
+ raise
98
+
99
+ def _setup_post_configuration_loading(self) -> None:
100
+ try:
101
+ self._common_between_pre_and_post_cfg_open()
102
+ self.networks.fetch_diagnostic_devices()
103
+ self.configuration.fetch_test_modules()
104
+ except Exception as e:
105
+ logger.error(f"❌ Error initializing objects after loading configuration: {e}")
106
+
107
+ def new(self, auto_save: bool = False, prompt_user: bool = False, timeout: int = 5) -> bool:
108
+ """Create a new empty CANoe configuration."""
109
+ self._launch_application()
110
+ status = False
111
+ try:
112
+ logger.info("📢 Opening new empty CANoe configuration...")
113
+ self.com_object.New(auto_save, prompt_user)
114
+ status = DoEventsUntil(lambda: self.application_events.OPENED, timeout, "New CANoe configuration")
115
+ if status:
116
+ logger.info("📢 New empty CANoe configuration Opened 🎉")
117
+ self._setup_post_configuration_loading()
118
+ except Exception as e:
119
+ logger.error(f"❌ Error creating new configuration: {e}")
120
+ status = False
121
+ finally:
122
+ return status
123
+
124
+ def open(self, canoe_cfg: str | Path, visible: bool = True, auto_save: bool = True, prompt_user: bool = False, timeout: int = 5) -> bool:
125
+ """Open an existing CANoe configuration."""
126
+ self._launch_application()
127
+ status = False
128
+ try:
129
+ self.visible = visible
130
+ logger.info("📢 Opening CANoe configuration ...")
131
+ self.com_object.Open(canoe_cfg, auto_save, prompt_user)
132
+ status = DoEventsUntil(lambda: self.application_events.OPENED, timeout, "Open CANoe configuration")
133
+ if status:
134
+ logger.info(f"📢 CANoe Configuration {canoe_cfg} Opened 🎉")
135
+ self._setup_post_configuration_loading()
136
+ except Exception as e:
137
+ logger.error(f"❌ Error opening configuration: {e}")
138
+ status = False
139
+ finally:
140
+ return status
141
+
142
+ def quit(self, timeout: int = 5) -> bool:
143
+ """Quit CANoe and clean up COM references."""
144
+ status = False
145
+ try:
146
+ self.configuration.modified = False
147
+ self.com_object.Quit()
148
+ status = DoEventsUntil(lambda: self.application_events.QUIT, timeout, "Quit CANoe application")
149
+ if status:
150
+ logger.info("📢 CANoe Application Quit Successfully 🎉")
151
+ except Exception as e:
152
+ logger.error(f"❌ Error during CANoe quit: {e}")
153
+ status = False
154
+ finally:
155
+ return status
156
+
157
+ def attach_to_active_application(self) -> bool:
158
+ """Attach to a active instance of the CANoe application."""
159
+ try:
160
+ self._launch_application()
161
+ if self.com_object:
162
+ logger.info("📢 Successfully attached to active CANoe application 🎉")
163
+ self._setup_post_configuration_loading()
164
+ return True
165
+ else:
166
+ logger.error("❌ Failed to attach to active CANoe application")
167
+ return False
168
+ except Exception as e:
169
+ logger.error(f"❌ Error attaching to active CANoe application: {e}")
170
+ return False
py_canoe/core/bus.py ADDED
@@ -0,0 +1,301 @@
1
+ from typing import Union
2
+
3
+ from py_canoe.core.child_elements.channels import Channels
4
+ from py_canoe.core.child_elements.database_setup import Databases
5
+ from py_canoe.core.child_elements.nodes import Nodes
6
+ from py_canoe.core.child_elements.ports import Ports
7
+ from py_canoe.core.child_elements.replay_collection import ReplayCollection
8
+ from py_canoe.core.child_elements.security_configuration import SecurityConfiguration
9
+ from py_canoe.core.child_elements.signals import Signal
10
+ from py_canoe.helpers.common import logger
11
+
12
+
13
+ class Bus:
14
+ """
15
+ The Bus object represents a bus of the CANoe application.
16
+ """
17
+ def __init__(self, app):
18
+ self.app = app
19
+ self.com_object = self.set_bus('CAN')
20
+ self.VALUE_TABLE_SIGNAL_IS_ONLINE = {
21
+ True: "measurement is running and the signal has been received.",
22
+ False: "The signal is not online."
23
+ }
24
+ self.VALUE_TABLE_SIGNAL_STATE = {
25
+ 0: "The default value of the signal is returned.",
26
+ 1: "The measurement is not running. The value set by the application is returned.",
27
+ 2: "The measurement is not running. The value of the last measurement is returned.",
28
+ 3: "The signal has been received in the current measurement. The current value is returned."
29
+ }
30
+
31
+ def set_bus(self, bus_type: str = 'CAN'):
32
+ try:
33
+ self.com_object = self.app.com_object.GetBus(bus_type)
34
+ except Exception as e:
35
+ logger.error(f"❌ Error retrieving {bus_type} bus: {e}")
36
+ finally:
37
+ return self.com_object
38
+
39
+ @property
40
+ def active(self) -> bool:
41
+ return self.com_object.Active
42
+
43
+ @property
44
+ def baudrate(self) -> int:
45
+ return self.com_object.Baudrate()
46
+
47
+ @baudrate.setter
48
+ def baudrate(self, value: int):
49
+ self.com_object.SetBaudrate(value)
50
+
51
+ @property
52
+ def channels(self) -> 'Channels':
53
+ return Channels(self.com_object.Channels)
54
+
55
+ @property
56
+ def databases(self) -> 'Databases':
57
+ return Databases(self.com_object.Databases)
58
+
59
+ @property
60
+ def name(self) -> str:
61
+ return self.com_object.Name
62
+
63
+ @name.setter
64
+ def name(self, name: str):
65
+ self.com_object.Name = name
66
+
67
+ @property
68
+ def nodes(self) -> 'Nodes':
69
+ return Nodes(self.com_object.Nodes)
70
+
71
+ @property
72
+ def ports(self) -> 'Ports':
73
+ return Ports(self.com_object.Port)
74
+
75
+ @property
76
+ def ports_of_channel(self) -> 'Ports':
77
+ return Ports(self.com_object.PortsOfChannel)
78
+
79
+ @property
80
+ def replay_collection(self) -> 'ReplayCollection':
81
+ return ReplayCollection(self.com_object.ReplayCollection)
82
+
83
+ @property
84
+ def security_configuration(self) -> 'SecurityConfiguration':
85
+ return SecurityConfiguration(self.com_object.SecurityConfiguration)
86
+
87
+ def get_signal(self, channel: int, message: str, signal: str) -> Signal:
88
+ return Signal(self.com_object.GetSignal(channel, message, signal))
89
+
90
+ def get_j1939_signal(self, channel: int, message: str, signal: str, source_address: int, destination_address: int) -> Signal:
91
+ return Signal(self.com_object.GetJ1939Signal(channel, message, signal, source_address, destination_address))
92
+
93
+ def get_bus_databases_info(self, bus: str = 'CAN') -> dict:
94
+ try:
95
+ bus_type = bus.upper()
96
+ if bus_type not in self.app.bus_types:
97
+ logger.error(f"❌ Invalid bus type '{bus_type}'. Supported types: {', '.join(self.app.bus_types)}")
98
+ return {}
99
+ databases_info = {}
100
+ self.set_bus(bus_type)
101
+ for db_obj in self.com_object.Databases:
102
+ info = {
103
+ 'full_name': getattr(db_obj, 'FullName', None),
104
+ 'path': getattr(db_obj, 'Path', None),
105
+ 'name': getattr(db_obj, 'Name', None),
106
+ 'channel': getattr(db_obj, 'Channel', None),
107
+ 'com_obj': db_obj,
108
+ }
109
+ databases_info[info['name']] = info
110
+ logger.info(f'📜 {bus_type} bus databases information:')
111
+ for db_name, db_info in databases_info.items():
112
+ logger.info(f" {db_name}:")
113
+ for key, value in db_info.items():
114
+ logger.info(f" {key}: {value}")
115
+ return databases_info
116
+ except Exception as e:
117
+ logger.error(f"❌ Error retrieving {bus} bus databases information: {e}")
118
+ return {}
119
+
120
+ def get_bus_nodes_info(self, bus: str = 'CAN') -> dict:
121
+ try:
122
+ bus_type = bus.upper()
123
+ if bus_type not in self.app.bus_types:
124
+ logger.error(f"❌ Invalid bus type '{bus_type}'. Supported types: {', '.join(self.app.bus_types)}")
125
+ return {}
126
+ nodes_info = {}
127
+ self.set_bus(bus_type)
128
+ for node_obj in self.com_object.Nodes:
129
+ info = {
130
+ 'full_name': getattr(node_obj, 'FullName', None),
131
+ 'path': getattr(node_obj, 'Path', None),
132
+ 'name': getattr(node_obj, 'Name', None),
133
+ 'active': getattr(node_obj, 'Active', None),
134
+ 'com_obj': node_obj,
135
+ }
136
+ nodes_info[info['name']] = info
137
+ logger.info(f'📜 {bus_type} bus nodes information:')
138
+ for node_name, node_info in nodes_info.items():
139
+ logger.info(f" {node_name}:")
140
+ for key, value in node_info.items():
141
+ logger.info(f" {key}: {value}")
142
+ return nodes_info
143
+ except Exception as e:
144
+ logger.error(f"❌ Error retrieving {bus} bus nodes information: {e}")
145
+ return {}
146
+
147
+ def get_signal_value(self, bus: str, channel: int, message: str, signal: str, raw_value: bool = False) -> Union[int, float, None]:
148
+ try:
149
+ bus_type = bus.upper()
150
+ if bus_type not in self.app.bus_types:
151
+ logger.error(f"❌ Invalid bus type '{bus_type}'. Supported types: {', '.join(self.app.bus_types)}")
152
+ return None
153
+ self.set_bus(bus_type)
154
+ signal_obj = self.get_signal(channel, message, signal)
155
+ value = signal_obj.raw_value if raw_value else signal_obj.value
156
+ logger.info(f"🚦Signal({signal_obj.full_name}) value = {value}")
157
+ return value
158
+ except Exception as e:
159
+ logger.error(f"❌ Error retrieving {bus} bus signal value: {e}")
160
+ return None
161
+
162
+ def set_signal_value(self, bus: str, channel: int, message: str, signal: str, value: Union[int, float], raw_value: bool = False) -> bool:
163
+ try:
164
+ bus_type = bus.upper()
165
+ if bus_type not in self.app.bus_types:
166
+ logger.error(f"❌ Invalid bus type '{bus_type}'. Supported types: {', '.join(self.app.bus_types)}")
167
+ return False
168
+ self.set_bus(bus_type)
169
+ signal_obj = self.get_signal(channel, message, signal)
170
+ if raw_value:
171
+ signal_obj.raw_value = int(value)
172
+ else:
173
+ signal_obj.value = value
174
+ logger.info(f"🚦Signal({signal_obj.full_name}) value set to {value}")
175
+ return True
176
+ except Exception as e:
177
+ logger.error(f"❌ Error setting {bus} bus signal value: {e}")
178
+ return False
179
+
180
+ def get_signal_full_name(self, bus: str, channel: int, message: str, signal: str) -> Union[str, None]:
181
+ try:
182
+ bus_type = bus.upper()
183
+ if bus_type not in self.app.bus_types:
184
+ logger.error(f"❌ Invalid bus type '{bus_type}'. Supported types: {', '.join(self.app.bus_types)}")
185
+ return None
186
+ self.set_bus(bus_type)
187
+ signal_obj = self.get_signal(channel, message, signal)
188
+ full_name = signal_obj.full_name
189
+ logger.info(f'🚦Signal full name = {full_name}')
190
+ return full_name
191
+ except Exception as e:
192
+ logger.error(f"❌ Error retrieving {bus} bus signal full name: {e}")
193
+ return None
194
+
195
+ def check_signal_online(self, bus: str, channel: int, message: str, signal: str) -> bool:
196
+ try:
197
+ bus_type = bus.upper()
198
+ if bus_type not in self.app.bus_types:
199
+ logger.error(f"❌ Invalid bus type '{bus_type}'. Supported types: {', '.join(self.app.bus_types)}")
200
+ return False
201
+ self.set_bus(bus_type)
202
+ signal_obj = self.get_signal(channel, message, signal)
203
+ is_online = signal_obj.is_online
204
+ logger.info(f'🚦Signal({signal_obj.full_name}) is online ?: {is_online} ({self.VALUE_TABLE_SIGNAL_IS_ONLINE[is_online]})')
205
+ return is_online
206
+ except Exception as e:
207
+ logger.error(f"❌ Error checking {bus} bus signal online status: {e}")
208
+ return False
209
+
210
+ def check_signal_state(self, bus: str, channel: int, message: str, signal: str) -> int:
211
+ try:
212
+ bus_type = bus.upper()
213
+ if bus_type not in self.app.bus_types:
214
+ logger.error(f"❌ Invalid bus type '{bus_type}'. Supported types: {', '.join(self.app.bus_types)}")
215
+ return -1
216
+ self.set_bus(bus_type)
217
+ signal_obj = self.get_signal(channel, message, signal)
218
+ state = signal_obj.state
219
+ logger.info(f'🚦Signal({signal_obj.full_name}) state: {state} ({self.VALUE_TABLE_SIGNAL_STATE[state]})')
220
+ return state
221
+ except Exception as e:
222
+ logger.error(f"❌ Error checking {bus} bus signal state: {e}")
223
+ return -1
224
+
225
+ def get_j1939_signal_value(self, bus: str, channel: int, message: str, signal: str, source_addr: int, dest_addr: int, raw_value=False) -> Union[float, int, None]:
226
+ try:
227
+ bus_type = bus.upper()
228
+ if bus_type not in self.app.bus_types:
229
+ logger.error(f"❌ Invalid bus type '{bus_type}'. Supported types: {', '.join(self.app.bus_types)}")
230
+ return None
231
+ self.set_bus(bus_type)
232
+ signal_obj = self.get_j1939_signal(channel, message, signal, source_addr, dest_addr)
233
+ signal_value = signal_obj.raw_value if raw_value else signal_obj.value
234
+ logger.info(f'🚦J1939 Signal({signal_obj.full_name}) value = {signal_value}')
235
+ return signal_value
236
+ except Exception as e:
237
+ logger.error(f"❌ Error retrieving J1939 bus signal value: {e}")
238
+ return None
239
+
240
+ def set_j1939_signal_value(self, bus: str, channel: int, message: str, signal: str, source_addr: int, dest_addr: int, value: Union[float, int], raw_value: bool = False) -> bool:
241
+ try:
242
+ bus_type = bus.upper()
243
+ if bus_type not in self.app.bus_types:
244
+ logger.error(f"❌ Invalid bus type '{bus_type}'. Supported types: {', '.join(self.app.bus_types)}")
245
+ return False
246
+ self.set_bus(bus_type)
247
+ signal_obj = self.get_j1939_signal(channel, message, signal, source_addr, dest_addr)
248
+ if raw_value:
249
+ signal_obj.raw_value = int(value)
250
+ else:
251
+ signal_obj.value = value
252
+ logger.info(f'🚦J1939 Signal({signal_obj.full_name}) value set to {value}')
253
+ return True
254
+ except Exception as e:
255
+ logger.error(f"❌ Error setting J1939 bus signal value: {e}")
256
+ return False
257
+
258
+ def get_j1939_signal_full_name(self, bus: str, channel: int, message: str, signal: str, source_addr: int, dest_addr: int) -> Union[str, None]:
259
+ try:
260
+ bus_type = bus.upper()
261
+ if bus_type not in self.app.bus_types:
262
+ logger.error(f"❌ Invalid bus type '{bus_type}'. Supported types: {', '.join(self.app.bus_types)}")
263
+ return None
264
+ self.set_bus(bus_type)
265
+ signal_obj = self.get_j1939_signal(channel, message, signal, source_addr, dest_addr)
266
+ full_name = signal_obj.full_name
267
+ logger.info(f'🚦J1939 Signal full name = {full_name}')
268
+ return full_name
269
+ except Exception as e:
270
+ logger.error(f"❌ Error retrieving J1939 bus signal full name: {e}")
271
+ return None
272
+
273
+ def check_j1939_signal_online(self, bus: str, channel: int, message: str, signal: str, source_addr: int, dest_addr: int) -> bool:
274
+ try:
275
+ bus_type = bus.upper()
276
+ if bus_type not in self.app.bus_types:
277
+ logger.error(f"❌ Invalid bus type '{bus_type}'. Supported types: {', '.join(self.app.bus_types)}")
278
+ return False
279
+ self.set_bus(bus_type)
280
+ signal_obj = self.get_j1939_signal(channel, message, signal, source_addr, dest_addr)
281
+ is_online = signal_obj.is_online
282
+ logger.info(f'🚦J1939 Signal({signal_obj.full_name}) is online ?: {is_online} ({self.VALUE_TABLE_SIGNAL_IS_ONLINE[is_online]})')
283
+ return is_online
284
+ except Exception as e:
285
+ logger.error(f"❌ Error checking J1939 bus signal online status: {e}")
286
+ return False
287
+
288
+ def check_j1939_signal_state(self, bus: str, channel: int, message: str, signal: str, source_addr: int, dest_addr: int) -> int:
289
+ try:
290
+ bus_type = bus.upper()
291
+ if bus_type not in self.app.bus_types:
292
+ logger.error(f"❌ Invalid bus type '{bus_type}'. Supported types: {', '.join(self.app.bus_types)}")
293
+ return -1
294
+ self.set_bus(bus_type)
295
+ signal_obj = self.get_j1939_signal(channel, message, signal, source_addr, dest_addr)
296
+ state = signal_obj.state
297
+ logger.info(f'🚦J1939 Signal({signal_obj.full_name}) state: {state} ({self.VALUE_TABLE_SIGNAL_STATE[state]})')
298
+ return state
299
+ except Exception as e:
300
+ logger.error(f"❌ Error checking J1939 bus signal state: {e}")
301
+ return -1
py_canoe/core/capl.py ADDED
@@ -0,0 +1,59 @@
1
+ from typing import Union
2
+
3
+ from py_canoe.helpers.common import logger
4
+ from py_canoe.helpers.common import wait
5
+
6
+ from py_canoe.core.child_elements.capl_function import CaplFunction
7
+ from py_canoe.core.child_elements.compile_result import CompileResult
8
+
9
+
10
+ class Capl:
11
+ """
12
+ The CAPL object allows to compile all nodes (CAPL, .NET, XML) in the configuration. Additionally it represents the CAPL functions available in the CAPL programs.
13
+ Please note that only user-defined CAPL functions can be accessed.
14
+ """
15
+ def __init__(self, app):
16
+ self.com_object = app.com_object.CAPL
17
+ self.capl_function_objects = lambda: app.measurement.measurement_events.CAPL_FUNCTION_OBJECTS
18
+
19
+ @property
20
+ def compile_result(self) -> 'CompileResult':
21
+ return CompileResult(self.com_object.CompileResult)
22
+
23
+ def compile(self, wait_time: Union[int, float] = 5) -> Union['CompileResult', None]:
24
+ try:
25
+ self.com_object.Compile()
26
+ wait(wait_time)
27
+ compile_result = self.compile_result
28
+ logger.info(f'🧑‍💻 compiled all CAPL nodes. result={compile_result.result}')
29
+ return compile_result
30
+ except Exception as e:
31
+ logger.error(f"❌ Error compiling CAPL nodes: {e}")
32
+ return None
33
+
34
+ def get_function(self, name: str) -> Union['CaplFunction', None]:
35
+ if name in self.capl_function_objects():
36
+ return self.capl_function_objects()[name]
37
+ else:
38
+ logger.warning(f'⚠️ CAPL function "{name}" not found/registered.')
39
+ return None
40
+
41
+ def call_capl_function(self, name: str, *arguments) -> bool:
42
+ try:
43
+ capl_function = self.get_function(name)
44
+ if capl_function:
45
+ if len(arguments) != capl_function.parameter_count:
46
+ logger.warning(f"⚠️ Not enough arguments provided for CAPL function '{name}'.")
47
+ return False
48
+ else:
49
+ if len(arguments) > 0:
50
+ capl_function.call(*arguments)
51
+ else:
52
+ capl_function.call()
53
+ return True
54
+ else:
55
+ logger.warning(f"⚠️ CAPL function '{name}' not found.")
56
+ return False
57
+ except Exception as e:
58
+ logger.error(f"❌ Error calling CAPL function '{name}': {e}")
59
+ return False
File without changes
@@ -0,0 +1,24 @@
1
+ import win32com.client
2
+
3
+ from py_canoe.core.child_elements.application_model_files import ApplicationModelFiles
4
+ from py_canoe.core.child_elements.participants import Participants
5
+
6
+
7
+ class ApplicationModel:
8
+ """
9
+ Represents a single application model.
10
+ """
11
+ def __init__(self, com_object) -> None:
12
+ self.com_object = win32com.client.Dispatch(com_object)
13
+
14
+ @property
15
+ def application_model_files(self) -> 'ApplicationModelFiles':
16
+ return ApplicationModelFiles(self.com_object.ApplicationModelFiles)
17
+
18
+ @property
19
+ def is_active(self) -> bool:
20
+ return self.com_object.IsActive
21
+
22
+ @property
23
+ def participants(self) -> 'Participants':
24
+ return Participants(self.com_object.Participants)
@@ -0,0 +1,21 @@
1
+ import win32com.client
2
+
3
+
4
+ class ApplicationModelFile:
5
+ """
6
+ Represents a file associated with an application model.
7
+ """
8
+ def __init__(self, com_object) -> None:
9
+ self.com_object = win32com.client.Dispatch(com_object)
10
+
11
+ @property
12
+ def full_name(self) -> str:
13
+ return self.com_object.FullName
14
+
15
+ @property
16
+ def name(self) -> str:
17
+ return self.com_object.Name
18
+
19
+ @property
20
+ def path(self) -> str:
21
+ return self.com_object.Path
@@ -0,0 +1,22 @@
1
+ from py_canoe.core.child_elements.application_model_file import ApplicationModelFile
2
+
3
+
4
+ class ApplicationModelFiles:
5
+ """
6
+ Collection of ApplicationModelFile objects (immutable).
7
+ """
8
+ def __init__(self, com_object) -> None:
9
+ self.com_object = com_object
10
+
11
+ @property
12
+ def count(self) -> int:
13
+ return self.com_object.Count
14
+
15
+ def item(self, index: int) -> 'ApplicationModelFile':
16
+ return ApplicationModelFile(self.com_object.Item(index))
17
+
18
+ def add(self, application_model_file_path: str) -> 'ApplicationModelFile':
19
+ self.com_object.Add(application_model_file_path)
20
+
21
+ def remove(self, index: int):
22
+ self.com_object.Remove(index)
@@ -0,0 +1,15 @@
1
+ import win32com.client
2
+
3
+ from py_canoe.core.child_elements.application_models import ApplicationModels
4
+
5
+
6
+ class ApplicationModelSetup:
7
+ """
8
+ Provides access to the application model management API.
9
+ """
10
+ def __init__(self, com_object) -> None:
11
+ self.com_object = com_object
12
+
13
+ @property
14
+ def application_models(self) -> 'ApplicationModels':
15
+ return ApplicationModels(self.com_object.ApplicationModels)
@@ -0,0 +1,22 @@
1
+ from py_canoe.core.child_elements.application_model import ApplicationModel
2
+
3
+
4
+ class ApplicationModels:
5
+ """
6
+ Collection of ApplicationModel objects.
7
+ """
8
+ def __init__(self, com_object) -> None:
9
+ self.com_object = com_object
10
+
11
+ @property
12
+ def count(self) -> int:
13
+ return self.com_object.Count
14
+
15
+ def item(self, index: int) -> 'ApplicationModel':
16
+ return ApplicationModel(self.com_object.Item(index))
17
+
18
+ def add(self, file_path: str) -> 'ApplicationModel':
19
+ return ApplicationModel(self.com_object.Add(file_path))
20
+
21
+ def remove(self, index: int):
22
+ self.com_object.Remove(index)
@@ -0,0 +1,11 @@
1
+ class ApplicationSocket:
2
+ def __init__(self, com_object):
3
+ self.com_object = com_object
4
+
5
+ @property
6
+ def bus_registry(self) -> bytearray:
7
+ return self.com_object.BusRegistry
8
+
9
+ @property
10
+ def fb_lock_list(self) -> bytearray:
11
+ return self.com_object.FBlockList
@@ -0,0 +1,24 @@
1
+ import win32com.client
2
+
3
+
4
+ class ApplicationSpecificModule:
5
+ """
6
+ Represents an application specific VT System module (e.g., VT7900 with application board or UserFPGA).
7
+ """
8
+ def __init__(self, app_specific_module_com_obj):
9
+ self.com_object = win32com.client.Dispatch(app_specific_module_com_obj)
10
+
11
+ @property
12
+ def name(self) -> str:
13
+ """The name of the module. For User FPGA, includes project name."""
14
+ return self.com_object.Name
15
+
16
+ @property
17
+ def base_type(self) -> int:
18
+ """The basic module type (e.g. 1004)."""
19
+ return self.com_object.BaseType
20
+
21
+ @property
22
+ def id(self) -> int:
23
+ """The unique ID of this application specific module."""
24
+ return self.com_object.ID