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.
- py_canoe/__init__.py +2 -1
- py_canoe/canoe.py +910 -0
- py_canoe/core/__init__.py +0 -0
- py_canoe/core/application.py +170 -0
- py_canoe/core/bus.py +301 -0
- py_canoe/core/capl.py +59 -0
- py_canoe/core/child_elements/__init__.py +0 -0
- py_canoe/core/child_elements/application_model.py +24 -0
- py_canoe/core/child_elements/application_model_file.py +21 -0
- py_canoe/core/child_elements/application_model_files.py +22 -0
- py_canoe/core/child_elements/application_model_setup.py +15 -0
- py_canoe/core/child_elements/application_models.py +22 -0
- py_canoe/core/child_elements/application_socket.py +11 -0
- py_canoe/core/child_elements/application_specific_module.py +24 -0
- py_canoe/core/child_elements/application_specific_modules.py +16 -0
- py_canoe/core/child_elements/audio_interface.py +28 -0
- py_canoe/core/child_elements/available_modules.py +22 -0
- py_canoe/core/child_elements/basic_module.py +19 -0
- py_canoe/core/child_elements/basic_modules.py +16 -0
- py_canoe/core/child_elements/c_libraries.py +28 -0
- py_canoe/core/child_elements/c_library.py +33 -0
- py_canoe/core/child_elements/can_controller.py +74 -0
- py_canoe/core/child_elements/capl_function.py +17 -0
- py_canoe/core/child_elements/ccp_setup.py +15 -0
- py_canoe/core/child_elements/channel.py +20 -0
- py_canoe/core/child_elements/channels.py +19 -0
- py_canoe/core/child_elements/communication_setup.py +23 -0
- py_canoe/core/child_elements/compile_result.py +22 -0
- py_canoe/core/child_elements/configured_channel.py +48 -0
- py_canoe/core/child_elements/configured_channels.py +21 -0
- py_canoe/core/child_elements/configured_module.py +82 -0
- py_canoe/core/child_elements/configured_modules.py +61 -0
- py_canoe/core/child_elements/connected_modules.py +14 -0
- py_canoe/core/child_elements/data_source.py +42 -0
- py_canoe/core/child_elements/data_source_file.py +21 -0
- py_canoe/core/child_elements/data_source_files.py +22 -0
- py_canoe/core/child_elements/data_source_issue.py +22 -0
- py_canoe/core/child_elements/data_source_issues.py +16 -0
- py_canoe/core/child_elements/data_source_setup.py +17 -0
- py_canoe/core/child_elements/data_sources.py +27 -0
- py_canoe/core/child_elements/database_setup.py +62 -0
- py_canoe/core/child_elements/device.py +34 -0
- py_canoe/core/child_elements/devices.py +13 -0
- py_canoe/core/child_elements/diagnostic.py +22 -0
- py_canoe/core/child_elements/diagnostic_request.py +59 -0
- py_canoe/core/child_elements/diagnostic_response.py +34 -0
- py_canoe/core/child_elements/diagnostic_responses.py +13 -0
- py_canoe/core/child_elements/diagnostics_setup.py +254 -0
- py_canoe/core/child_elements/distributed_mode.py +74 -0
- py_canoe/core/child_elements/encoding.py +27 -0
- py_canoe/core/child_elements/encodings.py +13 -0
- py_canoe/core/child_elements/environment_array.py +13 -0
- py_canoe/core/child_elements/environment_group.py +22 -0
- py_canoe/core/child_elements/environment_info.py +14 -0
- py_canoe/core/child_elements/environment_variable.py +55 -0
- py_canoe/core/child_elements/fdx_files.py +50 -0
- py_canoe/core/child_elements/file_group_data_source.py +17 -0
- py_canoe/core/child_elements/general_setup.py +66 -0
- py_canoe/core/child_elements/macros_setup.py +52 -0
- py_canoe/core/child_elements/mc_ecus.py +428 -0
- py_canoe/core/child_elements/measurement_setup.py +269 -0
- py_canoe/core/child_elements/modules.py +87 -0
- py_canoe/core/child_elements/most_disassembler.py +21 -0
- py_canoe/core/child_elements/most_network_interface.py +4 -0
- py_canoe/core/child_elements/namespace.py +21 -0
- py_canoe/core/child_elements/namespaces.py +19 -0
- py_canoe/core/child_elements/network.py +18 -0
- py_canoe/core/child_elements/network_adapters.py +13 -0
- py_canoe/core/child_elements/nodes.py +119 -0
- py_canoe/core/child_elements/open_configuration_result.py +0 -0
- py_canoe/core/child_elements/panel_setup.py +97 -0
- py_canoe/core/child_elements/participant.py +17 -0
- py_canoe/core/child_elements/participants.py +22 -0
- py_canoe/core/child_elements/ports.py +81 -0
- py_canoe/core/child_elements/replay_collection.py +56 -0
- py_canoe/core/child_elements/security_configuration.py +20 -0
- py_canoe/core/child_elements/security_setup.py +31 -0
- py_canoe/core/child_elements/signals.py +39 -0
- py_canoe/core/child_elements/simulation_setup.py +0 -0
- py_canoe/core/child_elements/single_file_data_source.py +13 -0
- py_canoe/core/child_elements/snippet_setup.py +68 -0
- py_canoe/core/child_elements/standalone_mode.py +0 -0
- py_canoe/core/child_elements/start_value_list.py +0 -0
- py_canoe/core/child_elements/symbol_mappings.py +0 -0
- py_canoe/core/child_elements/tcp_ip_stack_setting.py +0 -0
- py_canoe/core/child_elements/test_configurations.py +0 -0
- py_canoe/core/child_elements/test_environment.py +64 -0
- py_canoe/core/child_elements/test_environments.py +26 -0
- py_canoe/core/child_elements/test_module.py +213 -0
- py_canoe/core/child_elements/test_modules.py +23 -0
- py_canoe/core/child_elements/test_setup.py +16 -0
- py_canoe/core/child_elements/test_setup_folder_ext.py +36 -0
- py_canoe/core/child_elements/test_setup_folders.py +25 -0
- py_canoe/core/child_elements/user_files.py +0 -0
- py_canoe/core/child_elements/variable.py +144 -0
- py_canoe/core/child_elements/variable_events.py +14 -0
- py_canoe/core/child_elements/variables.py +29 -0
- py_canoe/core/child_elements/variables_file.py +15 -0
- py_canoe/core/child_elements/variables_files.py +19 -0
- py_canoe/core/child_elements/visual_sequence_setup.py +46 -0
- py_canoe/core/child_elements/vt_system.py +83 -0
- py_canoe/core/child_elements/vtt_sut_import_result.py +21 -0
- py_canoe/core/child_elements/write.py +71 -0
- py_canoe/core/child_elements/xcp_setup.py +12 -0
- py_canoe/core/configuration.py +509 -0
- py_canoe/core/environment.py +59 -0
- py_canoe/core/measurement.py +149 -0
- py_canoe/core/networks.py +103 -0
- py_canoe/core/performance.py +21 -0
- py_canoe/core/simulation.py +53 -0
- py_canoe/core/system.py +164 -0
- py_canoe/core/ui.py +53 -0
- py_canoe/core/version.py +54 -0
- py_canoe/helpers/__init__.py +0 -0
- py_canoe/helpers/common.py +78 -0
- {py_canoe-3.0.4.dist-info → py_canoe-26.0.0.dist-info}/METADATA +332 -322
- py_canoe-26.0.0.dist-info/RECORD +118 -0
- py_canoe-26.0.0.dist-info/WHEEL +4 -0
- py_canoe/py_canoe.py +0 -2586
- py_canoe/py_canoe_utils/logging_collection.py +0 -345
- py_canoe/py_canoe_utils/py_canoe_logger.py +0 -29
- py_canoe-3.0.4.dist-info/LICENSE +0 -21
- py_canoe-3.0.4.dist-info/RECORD +0 -8
- 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
|