hil2.hil2
1from typing import Optional 2 3import logging 4import os 5 6import cantools.database.can.database as cantools_db 7 8from . import action 9from . import can_helper 10from . import component 11from . import dut_cons 12from . import hil_errors 13from . import net_map 14from . import test_device 15 16 17class Hil2: 18 # Init ----------------------------------------------------------------------------# 19 def __init__( 20 self, 21 test_config_path: str, 22 device_config_fpath: str, 23 net_map_path: Optional[str] = None, 24 can_dbc_fpath: Optional[str] = None, 25 ): 26 """ 27 :param test_config_path: The path to the test configuration JSON file 28 :param device_config_fpath: The path to the device configuration JSON folder 29 :param net_map_path: The path to the net map (exported from Altium) file 30 (optional) 31 :param can_dbc_path: The path to the CAN DBC folder (optional) 32 """ 33 self._test_device_manager: test_device.TestDeviceManager = ( 34 test_device.TestDeviceManager.from_json( 35 test_config_path, device_config_fpath 36 ) 37 ) 38 self._dut_cons: dut_cons.DutCons = dut_cons.DutCons.from_json(test_config_path) 39 self._maybe_net_map: Optional[net_map.NetMap] = ( 40 None if net_map_path is None else net_map.NetMap.from_csv(net_map_path) 41 ) 42 self._can_dbcs: Optional[dict[str, cantools_db.Database]] = ( 43 None 44 if can_dbc_fpath is None 45 else can_helper.load_can_dbcs(os.path.join(can_dbc_fpath)) 46 ) 47 # Components that need to be "shutdown" when HIL2 exits 48 self._shutdown_components: dict[ 49 net_map.BoardNet, component.ShutdownableComponent 50 ] = {} 51 52 # Context -------------------------------------------------------------------------# 53 def __enter__(self): 54 return self 55 56 def __exit__(self, exc_type, exc_value, _traceback): 57 if exc_type is not None: 58 logging.critical(f"Hil2 exiting due to exception: {exc_value}") 59 60 self.close() 61 self._test_device_manager.close() 62 return False 63 64 # Soft close ----------------------------------------------------------------------# 65 def close(self) -> None: 66 """ 67 'Shutdown' all the componets (hiZ currently configured outputs) 68 """ 69 for comp in self._shutdown_components.values(): 70 comp.shutdown() 71 self._shutdown_components.clear() 72 73 # Map -----------------------------------------------------------------------------# 74 def _map_to_hil_device_con(self, board: str, net: str) -> dut_cons.HilDutCon: 75 """ 76 Map a DUT connection (board/net or hil device/port) to a HIL device connection. 77 If the board is a hil device (ex: 'RearTester'), return the corresponding HIL 78 device connection. 79 Otherwise, try to map from the test board and net name ('Dashboard'/'BRK_STAT') 80 to the HIL device/port it is connected to. 81 82 :param board: The name of the board (DUT board or HIL device) 83 :param net: The name of the net (DUT net name or HIL device port) 84 :return: The corresponding HIL device connection 85 """ 86 maybe_hil_dut_con = self._test_device_manager.maybe_hil_con_from_net(board, net) 87 match (self._maybe_net_map, maybe_hil_dut_con): 88 case (None, None): 89 error_msg = ( 90 "No HIL device connection found for board/net, and no " 91 "net map available to resolve: " 92 f"({board}, {net})" 93 ) 94 raise hil_errors.ConnectionError(error_msg) 95 case (net_map, None): 96 net_map_entry = net_map.get_entry(board, net) 97 dut_con = dut_cons.DutCon( 98 net_map_entry.component, net_map_entry.designator 99 ) 100 return self._dut_cons.get_hil_device_connection(board, dut_con) 101 case (None, hil_dut_con): 102 return hil_dut_con 103 case _: 104 error_msg = ( 105 "Multiple methods to resolve HIL device connection for " 106 "board/net found; ambiguous: " 107 f"({board}, {net})" 108 ) 109 raise hil_errors.ConnectionError(error_msg) 110 111 # DO ------------------------------------------------------------------------------# 112 def set_do(self, board: str, net: str, value: bool) -> None: 113 """ 114 Sets the digital output value. 115 116 :param board: The name of the board (DUT board or HIL device) 117 :param net: The name of the net (DUT net name or HIL device port) 118 :param value: The value to set the digital output to (low = false, high = true) 119 """ 120 _ = self.do(board, net) # Ensure component is registered to shutdown 121 self._test_device_manager.do_action( 122 action.SetDo(value), self._map_to_hil_device_con(board, net) 123 ) 124 125 def hiZ_do(self, board: str, net: str) -> None: 126 """ 127 Sets the digital output to high impedance (HiZ) mode. 128 129 :param board: The name of the board (DUT board or HIL device) 130 :param net: The name of the net (DUT net name or HIL device port) 131 """ 132 _ = self.do(board, net) # Ensure component is registered to shutdown 133 self._test_device_manager.do_action( 134 action.HiZDo(), self._map_to_hil_device_con(board, net) 135 ) 136 137 def do(self, board: str, net: str) -> component.DO: 138 """ 139 Create a DO component which has shortcuts to the set and HiZ functions. 140 141 :param board: The name of the board (DUT board or HIL device) 142 :param net: The name of the net (DUT net name or HIL device port) 143 :return: The corresponding DO component 144 """ 145 comp = component.DO( 146 set_fn=lambda value: self.set_do(board, net, value), 147 hiZ_fn=lambda: self.hiZ_do(board, net), 148 ) 149 self._shutdown_components[net_map.BoardNet(board, net)] = comp 150 return comp 151 152 # DI ------------------------------------------------------------------------------# 153 def get_di(self, board: str, net: str) -> bool: 154 """ 155 Gets the digital input value. 156 157 :param board: The name of the board (DUT board or HIL device) 158 :param net: The name of the net (DUT net name or HIL device port) 159 :return: The digital input value 160 """ 161 return self._test_device_manager.do_action( 162 action.GetDi(), self._map_to_hil_device_con(board, net) 163 ) 164 165 def di(self, board: str, net: str) -> component.DI: 166 """ 167 Create a DI component which has shortcuts to the get function. 168 169 :param board: The name of the board (DUT board or HIL device) 170 :param net: The name of the net (DUT net name or HIL device port) 171 :return: The corresponding DI component 172 """ 173 return component.DI(get_fn=lambda: self.get_di(board, net)) 174 175 # AO ------------------------------------------------------------------------------# 176 def set_ao(self, board: str, net: str, value: float) -> None: 177 """ 178 Sets the analog output value. 179 180 :param board: The name of the board (DUT board or HIL device) 181 :param net: The name of the net (DUT net name or HIL device port) 182 :param value: The value to set the analog output to in volts 183 """ 184 _ = self.ao(board, net) # Ensure component is registered to shutdown 185 self._test_device_manager.do_action( 186 action.SetAo(value), self._map_to_hil_device_con(board, net) 187 ) 188 189 def hiZ_ao(self, board: str, net: str) -> None: 190 """ 191 Sets the analog output to high impedance (HiZ) mode. 192 193 :param board: The name of the board (DUT board or HIL device) 194 :param net: The name of the net (DUT net name or HIL device port) 195 """ 196 _ = self.ao(board, net) # Ensure component is registered to shutdown 197 self._test_device_manager.do_action( 198 action.HiZAo(), self._map_to_hil_device_con(board, net) 199 ) 200 201 def ao(self, board: str, net: str) -> component.AO: 202 """ 203 Create an AO component which has shortcuts to the set and HiZ functions. 204 205 :param board: The name of the board (DUT board or HIL device) 206 :param net: The name of the net (DUT net name or HIL device port) 207 :return: The corresponding AO component 208 """ 209 comp = component.AO( 210 set_fn=lambda value: self.set_ao(board, net, value), 211 hiZ_fn=lambda: self.hiZ_ao(board, net), 212 ) 213 self._shutdown_components[net_map.BoardNet(board, net)] = comp 214 return comp 215 216 # AI ------------------------------------------------------------------------------# 217 def get_ai(self, board: str, net: str) -> float: 218 """ 219 Gets the analog input value. 220 221 :param board: The name of the board (DUT board or HIL device) 222 :param net: The name of the net (DUT net name or HIL device port) 223 :return: The analog input value in volts. 224 """ 225 return self._test_device_manager.do_action( 226 action.GetAi(), self._map_to_hil_device_con(board, net) 227 ) 228 229 def ai(self, board: str, net: str) -> component.AI: 230 """ 231 Create an AI component which has shortcuts to the get function. 232 233 :param board: The name of the board (DUT board or HIL device) 234 :param net: The name of the net (DUT net name or HIL device port) 235 """ 236 return component.AI(get_fn=lambda: self.get_ai(board, net)) 237 238 # POT -----------------------------------------------------------------------------# 239 def set_pot(self, board: str, net: str, value: float) -> None: 240 """ 241 Sets the potentiometer value. 242 243 :param board: The name of the board (DUT board or HIL device) 244 :param net: The name of the net (DUT net name or HIL device port) 245 :param value: The value to set the potentiometer to in ohms 246 """ 247 self._test_device_manager.do_action( 248 action.SetPot(value), self._map_to_hil_device_con(board, net) 249 ) 250 251 def pot(self, board: str, net: str) -> component.POT: 252 """ 253 Create a POT component which has shortcuts to the set function. 254 255 :param board: The name of the board (DUT board or HIL device) 256 :param net: The name of the net (DUT net name or HIL device port) 257 :return: The corresponding POT component 258 """ 259 return component.POT(set_fn=lambda value: self.set_pot(board, net, value)) 260 261 # CAN -----------------------------------------------------------------------------# 262 def send_can( 263 self, hil_board: str, can_bus: str, signal: str | int, data: dict 264 ) -> None: 265 """ 266 Send a CAN message out from a HIL device/can bus. 267 268 :param hil_board: The name of the HIL board 269 :param can_bus: The name of the CAN bus (ex: 'VCAN') 270 :param signal: The signal identifier or message id 271 :param data: The data to send. Will be encoded to raw bytes 272 """ 273 match self._can_dbcs: 274 case None: 275 raise hil_errors.ConfigurationError("CAN DBC not configured") 276 case can_dbcs: 277 self._test_device_manager.do_action( 278 action.SendCan(signal, data, can_dbcs), 279 self._test_device_manager.maybe_hil_con_from_net( 280 hil_board, can_bus 281 ), 282 ) 283 284 def get_last_can( 285 self, hil_board: str, can_bus: str, signal: Optional[str | int] = None 286 ) -> Optional[can_helper.CanMessage]: 287 """ 288 Gets the last received CAN message on a HIL device/can bus. 289 290 :param hil_board: The name of the HIL board 291 :param can_bus: The name of the CAN bus (ex: 'VCAN') 292 :param signal: The signal identifier or message id. If not specified, the last 293 message for any signal will be returned. 294 :return: The last received CAN message or None if not found 295 """ 296 match self._can_dbcs: 297 case None: 298 raise hil_errors.ConfigurationError("CAN DBC not configured") 299 case can_dbcs: 300 return self._test_device_manager.do_action( 301 action.GetLastCan(signal, can_dbcs), 302 self._test_device_manager.maybe_hil_con_from_net( 303 hil_board, can_bus 304 ), 305 ) 306 307 def get_all_can( 308 self, hil_board: str, can_bus: str, signal: Optional[str | int] = None 309 ) -> list[can_helper.CanMessage]: 310 """ 311 Gets all received CAN messages on a HIL device/can bus. 312 313 :param hil_board: The name of the HIL board 314 :param can_bus: The name of the CAN bus (ex: 'VCAN') 315 :param signal: The signal identifier or message id. If not specified, all 316 messages for any signal will be returned. 317 :return: A list of all received CAN messages 318 """ 319 match self._can_dbcs: 320 case None: 321 raise hil_errors.ConfigurationError("CAN DBC not configured") 322 case can_dbcs: 323 return self._test_device_manager.do_action( 324 action.GetAllCan(signal, can_dbcs), 325 self._test_device_manager.maybe_hil_con_from_net( 326 hil_board, can_bus 327 ), 328 ) 329 330 def clear_can( 331 self, hil_board: str, can_bus: str, signal: Optional[str | int] = None 332 ) -> None: 333 """ 334 Clears the received CAN messages on a HIL device/can bus. 335 336 :param hil_board: The name of the HIL board 337 :param can_bus: The name of the CAN bus (ex: 'VCAN') 338 :param signal: The signal identifier or message id. If not specified, all 339 messages for any signal will be cleared. 340 """ 341 match self._can_dbcs: 342 case None: 343 raise hil_errors.ConfigurationError("CAN DBC not configured") 344 case can_dbcs: 345 self._test_device_manager.do_action( 346 action.ClearCan(signal, can_dbcs), 347 self._test_device_manager.maybe_hil_con_from_net( 348 hil_board, can_bus 349 ), 350 ) 351 352 def can(self, hil_board: str, can_bus: str) -> component.CAN: 353 """ 354 Gets the CAN component for a specific HIL board and CAN bus which has shortcuts 355 to the send, get last, get all, and clear functions. 356 357 :param hil_board: The name of the HIL board 358 :param can_bus: The name of the CAN bus (ex: 'VCAN') 359 :return: The corresponding CAN component 360 """ 361 return component.CAN( 362 lambda signal, data: self.send_can(hil_board, can_bus, signal, data), 363 lambda signal: self.get_last_can(hil_board, can_bus, signal), 364 lambda signal: self.get_all_can(hil_board, can_bus, signal), 365 lambda signal: self.clear_can(hil_board, can_bus, signal), 366 )
18class Hil2: 19 # Init ----------------------------------------------------------------------------# 20 def __init__( 21 self, 22 test_config_path: str, 23 device_config_fpath: str, 24 net_map_path: Optional[str] = None, 25 can_dbc_fpath: Optional[str] = None, 26 ): 27 """ 28 :param test_config_path: The path to the test configuration JSON file 29 :param device_config_fpath: The path to the device configuration JSON folder 30 :param net_map_path: The path to the net map (exported from Altium) file 31 (optional) 32 :param can_dbc_path: The path to the CAN DBC folder (optional) 33 """ 34 self._test_device_manager: test_device.TestDeviceManager = ( 35 test_device.TestDeviceManager.from_json( 36 test_config_path, device_config_fpath 37 ) 38 ) 39 self._dut_cons: dut_cons.DutCons = dut_cons.DutCons.from_json(test_config_path) 40 self._maybe_net_map: Optional[net_map.NetMap] = ( 41 None if net_map_path is None else net_map.NetMap.from_csv(net_map_path) 42 ) 43 self._can_dbcs: Optional[dict[str, cantools_db.Database]] = ( 44 None 45 if can_dbc_fpath is None 46 else can_helper.load_can_dbcs(os.path.join(can_dbc_fpath)) 47 ) 48 # Components that need to be "shutdown" when HIL2 exits 49 self._shutdown_components: dict[ 50 net_map.BoardNet, component.ShutdownableComponent 51 ] = {} 52 53 # Context -------------------------------------------------------------------------# 54 def __enter__(self): 55 return self 56 57 def __exit__(self, exc_type, exc_value, _traceback): 58 if exc_type is not None: 59 logging.critical(f"Hil2 exiting due to exception: {exc_value}") 60 61 self.close() 62 self._test_device_manager.close() 63 return False 64 65 # Soft close ----------------------------------------------------------------------# 66 def close(self) -> None: 67 """ 68 'Shutdown' all the componets (hiZ currently configured outputs) 69 """ 70 for comp in self._shutdown_components.values(): 71 comp.shutdown() 72 self._shutdown_components.clear() 73 74 # Map -----------------------------------------------------------------------------# 75 def _map_to_hil_device_con(self, board: str, net: str) -> dut_cons.HilDutCon: 76 """ 77 Map a DUT connection (board/net or hil device/port) to a HIL device connection. 78 If the board is a hil device (ex: 'RearTester'), return the corresponding HIL 79 device connection. 80 Otherwise, try to map from the test board and net name ('Dashboard'/'BRK_STAT') 81 to the HIL device/port it is connected to. 82 83 :param board: The name of the board (DUT board or HIL device) 84 :param net: The name of the net (DUT net name or HIL device port) 85 :return: The corresponding HIL device connection 86 """ 87 maybe_hil_dut_con = self._test_device_manager.maybe_hil_con_from_net(board, net) 88 match (self._maybe_net_map, maybe_hil_dut_con): 89 case (None, None): 90 error_msg = ( 91 "No HIL device connection found for board/net, and no " 92 "net map available to resolve: " 93 f"({board}, {net})" 94 ) 95 raise hil_errors.ConnectionError(error_msg) 96 case (net_map, None): 97 net_map_entry = net_map.get_entry(board, net) 98 dut_con = dut_cons.DutCon( 99 net_map_entry.component, net_map_entry.designator 100 ) 101 return self._dut_cons.get_hil_device_connection(board, dut_con) 102 case (None, hil_dut_con): 103 return hil_dut_con 104 case _: 105 error_msg = ( 106 "Multiple methods to resolve HIL device connection for " 107 "board/net found; ambiguous: " 108 f"({board}, {net})" 109 ) 110 raise hil_errors.ConnectionError(error_msg) 111 112 # DO ------------------------------------------------------------------------------# 113 def set_do(self, board: str, net: str, value: bool) -> None: 114 """ 115 Sets the digital output value. 116 117 :param board: The name of the board (DUT board or HIL device) 118 :param net: The name of the net (DUT net name or HIL device port) 119 :param value: The value to set the digital output to (low = false, high = true) 120 """ 121 _ = self.do(board, net) # Ensure component is registered to shutdown 122 self._test_device_manager.do_action( 123 action.SetDo(value), self._map_to_hil_device_con(board, net) 124 ) 125 126 def hiZ_do(self, board: str, net: str) -> None: 127 """ 128 Sets the digital output to high impedance (HiZ) mode. 129 130 :param board: The name of the board (DUT board or HIL device) 131 :param net: The name of the net (DUT net name or HIL device port) 132 """ 133 _ = self.do(board, net) # Ensure component is registered to shutdown 134 self._test_device_manager.do_action( 135 action.HiZDo(), self._map_to_hil_device_con(board, net) 136 ) 137 138 def do(self, board: str, net: str) -> component.DO: 139 """ 140 Create a DO component which has shortcuts to the set and HiZ functions. 141 142 :param board: The name of the board (DUT board or HIL device) 143 :param net: The name of the net (DUT net name or HIL device port) 144 :return: The corresponding DO component 145 """ 146 comp = component.DO( 147 set_fn=lambda value: self.set_do(board, net, value), 148 hiZ_fn=lambda: self.hiZ_do(board, net), 149 ) 150 self._shutdown_components[net_map.BoardNet(board, net)] = comp 151 return comp 152 153 # DI ------------------------------------------------------------------------------# 154 def get_di(self, board: str, net: str) -> bool: 155 """ 156 Gets the digital input value. 157 158 :param board: The name of the board (DUT board or HIL device) 159 :param net: The name of the net (DUT net name or HIL device port) 160 :return: The digital input value 161 """ 162 return self._test_device_manager.do_action( 163 action.GetDi(), self._map_to_hil_device_con(board, net) 164 ) 165 166 def di(self, board: str, net: str) -> component.DI: 167 """ 168 Create a DI component which has shortcuts to the get function. 169 170 :param board: The name of the board (DUT board or HIL device) 171 :param net: The name of the net (DUT net name or HIL device port) 172 :return: The corresponding DI component 173 """ 174 return component.DI(get_fn=lambda: self.get_di(board, net)) 175 176 # AO ------------------------------------------------------------------------------# 177 def set_ao(self, board: str, net: str, value: float) -> None: 178 """ 179 Sets the analog output value. 180 181 :param board: The name of the board (DUT board or HIL device) 182 :param net: The name of the net (DUT net name or HIL device port) 183 :param value: The value to set the analog output to in volts 184 """ 185 _ = self.ao(board, net) # Ensure component is registered to shutdown 186 self._test_device_manager.do_action( 187 action.SetAo(value), self._map_to_hil_device_con(board, net) 188 ) 189 190 def hiZ_ao(self, board: str, net: str) -> None: 191 """ 192 Sets the analog output to high impedance (HiZ) mode. 193 194 :param board: The name of the board (DUT board or HIL device) 195 :param net: The name of the net (DUT net name or HIL device port) 196 """ 197 _ = self.ao(board, net) # Ensure component is registered to shutdown 198 self._test_device_manager.do_action( 199 action.HiZAo(), self._map_to_hil_device_con(board, net) 200 ) 201 202 def ao(self, board: str, net: str) -> component.AO: 203 """ 204 Create an AO component which has shortcuts to the set and HiZ functions. 205 206 :param board: The name of the board (DUT board or HIL device) 207 :param net: The name of the net (DUT net name or HIL device port) 208 :return: The corresponding AO component 209 """ 210 comp = component.AO( 211 set_fn=lambda value: self.set_ao(board, net, value), 212 hiZ_fn=lambda: self.hiZ_ao(board, net), 213 ) 214 self._shutdown_components[net_map.BoardNet(board, net)] = comp 215 return comp 216 217 # AI ------------------------------------------------------------------------------# 218 def get_ai(self, board: str, net: str) -> float: 219 """ 220 Gets the analog input value. 221 222 :param board: The name of the board (DUT board or HIL device) 223 :param net: The name of the net (DUT net name or HIL device port) 224 :return: The analog input value in volts. 225 """ 226 return self._test_device_manager.do_action( 227 action.GetAi(), self._map_to_hil_device_con(board, net) 228 ) 229 230 def ai(self, board: str, net: str) -> component.AI: 231 """ 232 Create an AI component which has shortcuts to the get function. 233 234 :param board: The name of the board (DUT board or HIL device) 235 :param net: The name of the net (DUT net name or HIL device port) 236 """ 237 return component.AI(get_fn=lambda: self.get_ai(board, net)) 238 239 # POT -----------------------------------------------------------------------------# 240 def set_pot(self, board: str, net: str, value: float) -> None: 241 """ 242 Sets the potentiometer value. 243 244 :param board: The name of the board (DUT board or HIL device) 245 :param net: The name of the net (DUT net name or HIL device port) 246 :param value: The value to set the potentiometer to in ohms 247 """ 248 self._test_device_manager.do_action( 249 action.SetPot(value), self._map_to_hil_device_con(board, net) 250 ) 251 252 def pot(self, board: str, net: str) -> component.POT: 253 """ 254 Create a POT component which has shortcuts to the set function. 255 256 :param board: The name of the board (DUT board or HIL device) 257 :param net: The name of the net (DUT net name or HIL device port) 258 :return: The corresponding POT component 259 """ 260 return component.POT(set_fn=lambda value: self.set_pot(board, net, value)) 261 262 # CAN -----------------------------------------------------------------------------# 263 def send_can( 264 self, hil_board: str, can_bus: str, signal: str | int, data: dict 265 ) -> None: 266 """ 267 Send a CAN message out from a HIL device/can bus. 268 269 :param hil_board: The name of the HIL board 270 :param can_bus: The name of the CAN bus (ex: 'VCAN') 271 :param signal: The signal identifier or message id 272 :param data: The data to send. Will be encoded to raw bytes 273 """ 274 match self._can_dbcs: 275 case None: 276 raise hil_errors.ConfigurationError("CAN DBC not configured") 277 case can_dbcs: 278 self._test_device_manager.do_action( 279 action.SendCan(signal, data, can_dbcs), 280 self._test_device_manager.maybe_hil_con_from_net( 281 hil_board, can_bus 282 ), 283 ) 284 285 def get_last_can( 286 self, hil_board: str, can_bus: str, signal: Optional[str | int] = None 287 ) -> Optional[can_helper.CanMessage]: 288 """ 289 Gets the last received CAN message on a HIL device/can bus. 290 291 :param hil_board: The name of the HIL board 292 :param can_bus: The name of the CAN bus (ex: 'VCAN') 293 :param signal: The signal identifier or message id. If not specified, the last 294 message for any signal will be returned. 295 :return: The last received CAN message or None if not found 296 """ 297 match self._can_dbcs: 298 case None: 299 raise hil_errors.ConfigurationError("CAN DBC not configured") 300 case can_dbcs: 301 return self._test_device_manager.do_action( 302 action.GetLastCan(signal, can_dbcs), 303 self._test_device_manager.maybe_hil_con_from_net( 304 hil_board, can_bus 305 ), 306 ) 307 308 def get_all_can( 309 self, hil_board: str, can_bus: str, signal: Optional[str | int] = None 310 ) -> list[can_helper.CanMessage]: 311 """ 312 Gets all received CAN messages on a HIL device/can bus. 313 314 :param hil_board: The name of the HIL board 315 :param can_bus: The name of the CAN bus (ex: 'VCAN') 316 :param signal: The signal identifier or message id. If not specified, all 317 messages for any signal will be returned. 318 :return: A list of all received CAN messages 319 """ 320 match self._can_dbcs: 321 case None: 322 raise hil_errors.ConfigurationError("CAN DBC not configured") 323 case can_dbcs: 324 return self._test_device_manager.do_action( 325 action.GetAllCan(signal, can_dbcs), 326 self._test_device_manager.maybe_hil_con_from_net( 327 hil_board, can_bus 328 ), 329 ) 330 331 def clear_can( 332 self, hil_board: str, can_bus: str, signal: Optional[str | int] = None 333 ) -> None: 334 """ 335 Clears the received CAN messages on a HIL device/can bus. 336 337 :param hil_board: The name of the HIL board 338 :param can_bus: The name of the CAN bus (ex: 'VCAN') 339 :param signal: The signal identifier or message id. If not specified, all 340 messages for any signal will be cleared. 341 """ 342 match self._can_dbcs: 343 case None: 344 raise hil_errors.ConfigurationError("CAN DBC not configured") 345 case can_dbcs: 346 self._test_device_manager.do_action( 347 action.ClearCan(signal, can_dbcs), 348 self._test_device_manager.maybe_hil_con_from_net( 349 hil_board, can_bus 350 ), 351 ) 352 353 def can(self, hil_board: str, can_bus: str) -> component.CAN: 354 """ 355 Gets the CAN component for a specific HIL board and CAN bus which has shortcuts 356 to the send, get last, get all, and clear functions. 357 358 :param hil_board: The name of the HIL board 359 :param can_bus: The name of the CAN bus (ex: 'VCAN') 360 :return: The corresponding CAN component 361 """ 362 return component.CAN( 363 lambda signal, data: self.send_can(hil_board, can_bus, signal, data), 364 lambda signal: self.get_last_can(hil_board, can_bus, signal), 365 lambda signal: self.get_all_can(hil_board, can_bus, signal), 366 lambda signal: self.clear_can(hil_board, can_bus, signal), 367 )
20 def __init__( 21 self, 22 test_config_path: str, 23 device_config_fpath: str, 24 net_map_path: Optional[str] = None, 25 can_dbc_fpath: Optional[str] = None, 26 ): 27 """ 28 :param test_config_path: The path to the test configuration JSON file 29 :param device_config_fpath: The path to the device configuration JSON folder 30 :param net_map_path: The path to the net map (exported from Altium) file 31 (optional) 32 :param can_dbc_path: The path to the CAN DBC folder (optional) 33 """ 34 self._test_device_manager: test_device.TestDeviceManager = ( 35 test_device.TestDeviceManager.from_json( 36 test_config_path, device_config_fpath 37 ) 38 ) 39 self._dut_cons: dut_cons.DutCons = dut_cons.DutCons.from_json(test_config_path) 40 self._maybe_net_map: Optional[net_map.NetMap] = ( 41 None if net_map_path is None else net_map.NetMap.from_csv(net_map_path) 42 ) 43 self._can_dbcs: Optional[dict[str, cantools_db.Database]] = ( 44 None 45 if can_dbc_fpath is None 46 else can_helper.load_can_dbcs(os.path.join(can_dbc_fpath)) 47 ) 48 # Components that need to be "shutdown" when HIL2 exits 49 self._shutdown_components: dict[ 50 net_map.BoardNet, component.ShutdownableComponent 51 ] = {}
Parameters
- test_config_path: The path to the test configuration JSON file
- device_config_fpath: The path to the device configuration JSON folder
- net_map_path: The path to the net map (exported from Altium) file (optional)
- can_dbc_path: The path to the CAN DBC folder (optional)
66 def close(self) -> None: 67 """ 68 'Shutdown' all the componets (hiZ currently configured outputs) 69 """ 70 for comp in self._shutdown_components.values(): 71 comp.shutdown() 72 self._shutdown_components.clear()
'Shutdown' all the componets (hiZ currently configured outputs)
113 def set_do(self, board: str, net: str, value: bool) -> None: 114 """ 115 Sets the digital output value. 116 117 :param board: The name of the board (DUT board or HIL device) 118 :param net: The name of the net (DUT net name or HIL device port) 119 :param value: The value to set the digital output to (low = false, high = true) 120 """ 121 _ = self.do(board, net) # Ensure component is registered to shutdown 122 self._test_device_manager.do_action( 123 action.SetDo(value), self._map_to_hil_device_con(board, net) 124 )
Sets the digital output value.
Parameters
- board: The name of the board (DUT board or HIL device)
- net: The name of the net (DUT net name or HIL device port)
- value: The value to set the digital output to (low = false, high = true)
126 def hiZ_do(self, board: str, net: str) -> None: 127 """ 128 Sets the digital output to high impedance (HiZ) mode. 129 130 :param board: The name of the board (DUT board or HIL device) 131 :param net: The name of the net (DUT net name or HIL device port) 132 """ 133 _ = self.do(board, net) # Ensure component is registered to shutdown 134 self._test_device_manager.do_action( 135 action.HiZDo(), self._map_to_hil_device_con(board, net) 136 )
Sets the digital output to high impedance (HiZ) mode.
Parameters
- board: The name of the board (DUT board or HIL device)
- net: The name of the net (DUT net name or HIL device port)
138 def do(self, board: str, net: str) -> component.DO: 139 """ 140 Create a DO component which has shortcuts to the set and HiZ functions. 141 142 :param board: The name of the board (DUT board or HIL device) 143 :param net: The name of the net (DUT net name or HIL device port) 144 :return: The corresponding DO component 145 """ 146 comp = component.DO( 147 set_fn=lambda value: self.set_do(board, net, value), 148 hiZ_fn=lambda: self.hiZ_do(board, net), 149 ) 150 self._shutdown_components[net_map.BoardNet(board, net)] = comp 151 return comp
Create a DO component which has shortcuts to the set and HiZ functions.
Parameters
- board: The name of the board (DUT board or HIL device)
- net: The name of the net (DUT net name or HIL device port)
Returns
The corresponding DO component
154 def get_di(self, board: str, net: str) -> bool: 155 """ 156 Gets the digital input value. 157 158 :param board: The name of the board (DUT board or HIL device) 159 :param net: The name of the net (DUT net name or HIL device port) 160 :return: The digital input value 161 """ 162 return self._test_device_manager.do_action( 163 action.GetDi(), self._map_to_hil_device_con(board, net) 164 )
Gets the digital input value.
Parameters
- board: The name of the board (DUT board or HIL device)
- net: The name of the net (DUT net name or HIL device port)
Returns
The digital input value
166 def di(self, board: str, net: str) -> component.DI: 167 """ 168 Create a DI component which has shortcuts to the get function. 169 170 :param board: The name of the board (DUT board or HIL device) 171 :param net: The name of the net (DUT net name or HIL device port) 172 :return: The corresponding DI component 173 """ 174 return component.DI(get_fn=lambda: self.get_di(board, net))
Create a DI component which has shortcuts to the get function.
Parameters
- board: The name of the board (DUT board or HIL device)
- net: The name of the net (DUT net name or HIL device port)
Returns
The corresponding DI component
177 def set_ao(self, board: str, net: str, value: float) -> None: 178 """ 179 Sets the analog output value. 180 181 :param board: The name of the board (DUT board or HIL device) 182 :param net: The name of the net (DUT net name or HIL device port) 183 :param value: The value to set the analog output to in volts 184 """ 185 _ = self.ao(board, net) # Ensure component is registered to shutdown 186 self._test_device_manager.do_action( 187 action.SetAo(value), self._map_to_hil_device_con(board, net) 188 )
Sets the analog output value.
Parameters
- board: The name of the board (DUT board or HIL device)
- net: The name of the net (DUT net name or HIL device port)
- value: The value to set the analog output to in volts
190 def hiZ_ao(self, board: str, net: str) -> None: 191 """ 192 Sets the analog output to high impedance (HiZ) mode. 193 194 :param board: The name of the board (DUT board or HIL device) 195 :param net: The name of the net (DUT net name or HIL device port) 196 """ 197 _ = self.ao(board, net) # Ensure component is registered to shutdown 198 self._test_device_manager.do_action( 199 action.HiZAo(), self._map_to_hil_device_con(board, net) 200 )
Sets the analog output to high impedance (HiZ) mode.
Parameters
- board: The name of the board (DUT board or HIL device)
- net: The name of the net (DUT net name or HIL device port)
202 def ao(self, board: str, net: str) -> component.AO: 203 """ 204 Create an AO component which has shortcuts to the set and HiZ functions. 205 206 :param board: The name of the board (DUT board or HIL device) 207 :param net: The name of the net (DUT net name or HIL device port) 208 :return: The corresponding AO component 209 """ 210 comp = component.AO( 211 set_fn=lambda value: self.set_ao(board, net, value), 212 hiZ_fn=lambda: self.hiZ_ao(board, net), 213 ) 214 self._shutdown_components[net_map.BoardNet(board, net)] = comp 215 return comp
Create an AO component which has shortcuts to the set and HiZ functions.
Parameters
- board: The name of the board (DUT board or HIL device)
- net: The name of the net (DUT net name or HIL device port)
Returns
The corresponding AO component
218 def get_ai(self, board: str, net: str) -> float: 219 """ 220 Gets the analog input value. 221 222 :param board: The name of the board (DUT board or HIL device) 223 :param net: The name of the net (DUT net name or HIL device port) 224 :return: The analog input value in volts. 225 """ 226 return self._test_device_manager.do_action( 227 action.GetAi(), self._map_to_hil_device_con(board, net) 228 )
Gets the analog input value.
Parameters
- board: The name of the board (DUT board or HIL device)
- net: The name of the net (DUT net name or HIL device port)
Returns
The analog input value in volts.
230 def ai(self, board: str, net: str) -> component.AI: 231 """ 232 Create an AI component which has shortcuts to the get function. 233 234 :param board: The name of the board (DUT board or HIL device) 235 :param net: The name of the net (DUT net name or HIL device port) 236 """ 237 return component.AI(get_fn=lambda: self.get_ai(board, net))
Create an AI component which has shortcuts to the get function.
Parameters
- board: The name of the board (DUT board or HIL device)
- net: The name of the net (DUT net name or HIL device port)
240 def set_pot(self, board: str, net: str, value: float) -> None: 241 """ 242 Sets the potentiometer value. 243 244 :param board: The name of the board (DUT board or HIL device) 245 :param net: The name of the net (DUT net name or HIL device port) 246 :param value: The value to set the potentiometer to in ohms 247 """ 248 self._test_device_manager.do_action( 249 action.SetPot(value), self._map_to_hil_device_con(board, net) 250 )
Sets the potentiometer value.
Parameters
- board: The name of the board (DUT board or HIL device)
- net: The name of the net (DUT net name or HIL device port)
- value: The value to set the potentiometer to in ohms
252 def pot(self, board: str, net: str) -> component.POT: 253 """ 254 Create a POT component which has shortcuts to the set function. 255 256 :param board: The name of the board (DUT board or HIL device) 257 :param net: The name of the net (DUT net name or HIL device port) 258 :return: The corresponding POT component 259 """ 260 return component.POT(set_fn=lambda value: self.set_pot(board, net, value))
Create a POT component which has shortcuts to the set function.
Parameters
- board: The name of the board (DUT board or HIL device)
- net: The name of the net (DUT net name or HIL device port)
Returns
The corresponding POT component
263 def send_can( 264 self, hil_board: str, can_bus: str, signal: str | int, data: dict 265 ) -> None: 266 """ 267 Send a CAN message out from a HIL device/can bus. 268 269 :param hil_board: The name of the HIL board 270 :param can_bus: The name of the CAN bus (ex: 'VCAN') 271 :param signal: The signal identifier or message id 272 :param data: The data to send. Will be encoded to raw bytes 273 """ 274 match self._can_dbcs: 275 case None: 276 raise hil_errors.ConfigurationError("CAN DBC not configured") 277 case can_dbcs: 278 self._test_device_manager.do_action( 279 action.SendCan(signal, data, can_dbcs), 280 self._test_device_manager.maybe_hil_con_from_net( 281 hil_board, can_bus 282 ), 283 )
Send a CAN message out from a HIL device/can bus.
Parameters
- hil_board: The name of the HIL board
- can_bus: The name of the CAN bus (ex: 'VCAN')
- signal: The signal identifier or message id
- data: The data to send. Will be encoded to raw bytes
285 def get_last_can( 286 self, hil_board: str, can_bus: str, signal: Optional[str | int] = None 287 ) -> Optional[can_helper.CanMessage]: 288 """ 289 Gets the last received CAN message on a HIL device/can bus. 290 291 :param hil_board: The name of the HIL board 292 :param can_bus: The name of the CAN bus (ex: 'VCAN') 293 :param signal: The signal identifier or message id. If not specified, the last 294 message for any signal will be returned. 295 :return: The last received CAN message or None if not found 296 """ 297 match self._can_dbcs: 298 case None: 299 raise hil_errors.ConfigurationError("CAN DBC not configured") 300 case can_dbcs: 301 return self._test_device_manager.do_action( 302 action.GetLastCan(signal, can_dbcs), 303 self._test_device_manager.maybe_hil_con_from_net( 304 hil_board, can_bus 305 ), 306 )
Gets the last received CAN message on a HIL device/can bus.
Parameters
- hil_board: The name of the HIL board
- can_bus: The name of the CAN bus (ex: 'VCAN')
- signal: The signal identifier or message id. If not specified, the last message for any signal will be returned.
Returns
The last received CAN message or None if not found
308 def get_all_can( 309 self, hil_board: str, can_bus: str, signal: Optional[str | int] = None 310 ) -> list[can_helper.CanMessage]: 311 """ 312 Gets all received CAN messages on a HIL device/can bus. 313 314 :param hil_board: The name of the HIL board 315 :param can_bus: The name of the CAN bus (ex: 'VCAN') 316 :param signal: The signal identifier or message id. If not specified, all 317 messages for any signal will be returned. 318 :return: A list of all received CAN messages 319 """ 320 match self._can_dbcs: 321 case None: 322 raise hil_errors.ConfigurationError("CAN DBC not configured") 323 case can_dbcs: 324 return self._test_device_manager.do_action( 325 action.GetAllCan(signal, can_dbcs), 326 self._test_device_manager.maybe_hil_con_from_net( 327 hil_board, can_bus 328 ), 329 )
Gets all received CAN messages on a HIL device/can bus.
Parameters
- hil_board: The name of the HIL board
- can_bus: The name of the CAN bus (ex: 'VCAN')
- signal: The signal identifier or message id. If not specified, all messages for any signal will be returned.
Returns
A list of all received CAN messages
331 def clear_can( 332 self, hil_board: str, can_bus: str, signal: Optional[str | int] = None 333 ) -> None: 334 """ 335 Clears the received CAN messages on a HIL device/can bus. 336 337 :param hil_board: The name of the HIL board 338 :param can_bus: The name of the CAN bus (ex: 'VCAN') 339 :param signal: The signal identifier or message id. If not specified, all 340 messages for any signal will be cleared. 341 """ 342 match self._can_dbcs: 343 case None: 344 raise hil_errors.ConfigurationError("CAN DBC not configured") 345 case can_dbcs: 346 self._test_device_manager.do_action( 347 action.ClearCan(signal, can_dbcs), 348 self._test_device_manager.maybe_hil_con_from_net( 349 hil_board, can_bus 350 ), 351 )
Clears the received CAN messages on a HIL device/can bus.
Parameters
- hil_board: The name of the HIL board
- can_bus: The name of the CAN bus (ex: 'VCAN')
- signal: The signal identifier or message id. If not specified, all messages for any signal will be cleared.
353 def can(self, hil_board: str, can_bus: str) -> component.CAN: 354 """ 355 Gets the CAN component for a specific HIL board and CAN bus which has shortcuts 356 to the send, get last, get all, and clear functions. 357 358 :param hil_board: The name of the HIL board 359 :param can_bus: The name of the CAN bus (ex: 'VCAN') 360 :return: The corresponding CAN component 361 """ 362 return component.CAN( 363 lambda signal, data: self.send_can(hil_board, can_bus, signal, data), 364 lambda signal: self.get_last_can(hil_board, can_bus, signal), 365 lambda signal: self.get_all_can(hil_board, can_bus, signal), 366 lambda signal: self.clear_can(hil_board, can_bus, signal), 367 )
Gets the CAN component for a specific HIL board and CAN bus which has shortcuts to the send, get last, get all, and clear functions.
Parameters
- hil_board: The name of the HIL board
- can_bus: The name of the CAN bus (ex: 'VCAN')
Returns
The corresponding CAN component