hitl_tester.modules.bms.adc_plate
Provides controls for various hardware.
(c) 2020-2024 TurnAround Factor, Inc.
#
CUI DISTRIBUTION CONTROL
Controlled by: DLA J68 R&D SBIP
CUI Category: Small Business Research and Technology
Distribution/Dissemination Controls: PROTECTED BY SBIR DATA RIGHTS
POC: GOV SBIP Program Manager Denise Price, 571-767-0111
Distribution authorized to U.S. Government Agencies only, to protect information not owned by the
U.S. Government and protected by a contractor’s ‘limited rights’ statement, or received with the understanding that
it is not routinely transmitted outside the U.S. Government (determination made September 14, 2024). Other requests
for this document shall be referred to ACOR DLA Logistics Operations (J-68), 8725 John J. Kingman Rd., Suite 4317,
Fort Belvoir, VA 22060-6221
#
SBIR DATA RIGHTS
Contract No.:SP4701-23-C-0083
Contractor Name: TurnAround Factor, Inc.
Contractor Address: 10365 Wood Park Ct. Suite 313 / Ashland, VA 23005
Expiration of SBIR Data Rights Period: September 24, 2029
The Government's rights to use, modify, reproduce, release, perform, display, or disclose technical data or computer
software marked with this legend are restricted during the period shown as provided in paragraph (b)(4) of the Rights
in Noncommercial Technical Data and Computer Software--Small Business Innovative Research (SBIR) Program clause
contained in the above identified contract. No restrictions apply after the expiration date shown above. Any
reproduction of technical data, computer software, or portions thereof marked with this legend must also reproduce
the markings.
1""" 2Provides controls for various hardware. 3 4# (c) 2020-2024 TurnAround Factor, Inc. 5# 6# CUI DISTRIBUTION CONTROL 7# Controlled by: DLA J68 R&D SBIP 8# CUI Category: Small Business Research and Technology 9# Distribution/Dissemination Controls: PROTECTED BY SBIR DATA RIGHTS 10# POC: GOV SBIP Program Manager Denise Price, 571-767-0111 11# Distribution authorized to U.S. Government Agencies only, to protect information not owned by the 12# U.S. Government and protected by a contractor’s ‘limited rights’ statement, or received with the understanding that 13# it is not routinely transmitted outside the U.S. Government (determination made September 14, 2024). Other requests 14# for this document shall be referred to ACOR DLA Logistics Operations (J-68), 8725 John J. Kingman Rd., Suite 4317, 15# Fort Belvoir, VA 22060-6221 16# 17# SBIR DATA RIGHTS 18# Contract No.:SP4701-23-C-0083 19# Contractor Name: TurnAround Factor, Inc. 20# Contractor Address: 10365 Wood Park Ct. Suite 313 / Ashland, VA 23005 21# Expiration of SBIR Data Rights Period: September 24, 2029 22# The Government's rights to use, modify, reproduce, release, perform, display, or disclose technical data or computer 23# software marked with this legend are restricted during the period shown as provided in paragraph (b)(4) of the Rights 24# in Noncommercial Technical Data and Computer Software--Small Business Innovative Research (SBIR) Program clause 25# contained in the above identified contract. No restrictions apply after the expiration date shown above. Any 26# reproduction of technical data, computer software, or portions thereof marked with this legend must also reproduce 27# the markings. 28""" 29 30from __future__ import annotations 31 32from dataclasses import dataclass, fields 33from enum import Enum 34from typing_extensions import Self 35 36import pytest 37 38from hitl_tester.modules.bms_types import BMSFlags, SuppressExceptions 39from hitl_tester.modules.file_lock import RFileLock 40 41if hasattr(pytest, "flags") and isinstance(pytest.flags, BMSFlags) and pytest.flags.dry_run: 42 from hitl_tester.modules.bms.pseudo_hardware import ADC 43else: 44 import piplates.ADCplate as ADC # type: ignore[no-redef] 45 46 47class ADCInput(str, Enum): 48 """ 49 The ADC plate can support a combination of eight ground referenced single ended inputs or four, 50 true differential inputs. A differential input is the combination of two single ended inputs. 51 """ 52 53 DIFFERENTIAL = "D" 54 SINGLE = "S" 55 56 57@dataclass 58class Pins: 59 """Make pin management easier.""" 60 61 address: int 62 pin: int 63 pin_type: ADCInput 64 65 def __iter__(self): 66 """Allows unpacking with *.""" 67 return iter(tuple(getattr(self, field.name) for field in fields(self))) 68 69 70class ADCPlate: 71 """ADC Pi-Plate access.""" 72 73 _instance: Self | None = None 74 75 def __new__(cls): 76 """Make ADCPlate a singleton.""" 77 cls._instance = cls._instance or super().__new__(cls) 78 return cls._instance 79 80 def __init__(self): 81 if ( 82 hasattr(pytest, "flags") 83 and isinstance(pytest.flags, BMSFlags) 84 and not (pytest.flags.doc_generation or pytest.flags.dry_run) 85 ): 86 configs = pytest.flags.config.get("adc_board", {}) 87 if configs: 88 cells_board_address = configs["cells_board_address"] 89 misc_board_address = configs["misc_board_address"] 90 91 self.cell_pins = Pins(cells_board_address, 0, ADCInput.DIFFERENTIAL) 92 self.cell_ids = range(1, 5) 93 self.battery_pins = Pins(misc_board_address, 0, ADCInput.SINGLE) 94 self.terminal_pins = Pins(misc_board_address, 1, ADCInput.SINGLE) 95 self.thermister_1_pins = Pins(misc_board_address, 1, ADCInput.DIFFERENTIAL) 96 self.thermister_2_pins = Pins(misc_board_address, 2, ADCInput.DIFFERENTIAL) 97 self.heater_pins = Pins(misc_board_address, 6, ADCInput.SINGLE) 98 99 self._lock = RFileLock("piplate") 100 101 def measure(self, board_address: int, channel: int, input_type: ADCInput) -> float: 102 """Measure an input on the ADC plate.""" 103 with SuppressExceptions(), self._lock: 104 ADC.setMODE(board_address, "ADV") # Advanced mode 105 ADC.configINPUT(board_address, f"{input_type.value}{channel}", 7, True) 106 return ADC.readSINGLE(board_address, f"{input_type.value}{channel}") or 0.0 107 return 0.0 108 109 def cell_volts(self, cell_id: int) -> float: 110 """Measure cell voltage (ID 0 to 3).""" 111 self.cell_pins.pin = cell_id - 1 112 return self.measure(*self.cell_pins) 113 114 @property 115 def battery_volts(self) -> float: 116 """Measure battery voltage (cells combined).""" 117 return self.measure(*self.battery_pins) 118 119 @property 120 def terminal_volts(self) -> float: 121 """Measure terminal voltage.""" 122 return self.measure(*self.terminal_pins) 123 124 @property 125 def thermistor_1_volts(self) -> float: 126 """Measure thermistor 1 voltage.""" 127 return self.measure(*self.thermister_1_pins) 128 129 @property 130 def thermistor_2_volts(self) -> float: 131 """Measure thermistor 2 voltage.""" 132 return self.measure(*self.thermister_2_pins) 133 134 @property 135 def heater_volts(self) -> float: 136 """Measure heater voltage.""" 137 return self.measure(*self.heater_pins)
class
ADCInput(builtins.str, enum.Enum):
48class ADCInput(str, Enum): 49 """ 50 The ADC plate can support a combination of eight ground referenced single ended inputs or four, 51 true differential inputs. A differential input is the combination of two single ended inputs. 52 """ 53 54 DIFFERENTIAL = "D" 55 SINGLE = "S"
The ADC plate can support a combination of eight ground referenced single ended inputs or four, true differential inputs. A differential input is the combination of two single ended inputs.
DIFFERENTIAL =
<ADCInput.DIFFERENTIAL: 'D'>
SINGLE =
<ADCInput.SINGLE: 'S'>
Inherited Members
- enum.Enum
- name
- value
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
@dataclass
class
Pins:
58@dataclass 59class Pins: 60 """Make pin management easier.""" 61 62 address: int 63 pin: int 64 pin_type: ADCInput 65 66 def __iter__(self): 67 """Allows unpacking with *.""" 68 return iter(tuple(getattr(self, field.name) for field in fields(self)))
Make pin management easier.
Pins( address: int, pin: int, pin_type: ADCInput)
pin_type: ADCInput
class
ADCPlate:
71class ADCPlate: 72 """ADC Pi-Plate access.""" 73 74 _instance: Self | None = None 75 76 def __new__(cls): 77 """Make ADCPlate a singleton.""" 78 cls._instance = cls._instance or super().__new__(cls) 79 return cls._instance 80 81 def __init__(self): 82 if ( 83 hasattr(pytest, "flags") 84 and isinstance(pytest.flags, BMSFlags) 85 and not (pytest.flags.doc_generation or pytest.flags.dry_run) 86 ): 87 configs = pytest.flags.config.get("adc_board", {}) 88 if configs: 89 cells_board_address = configs["cells_board_address"] 90 misc_board_address = configs["misc_board_address"] 91 92 self.cell_pins = Pins(cells_board_address, 0, ADCInput.DIFFERENTIAL) 93 self.cell_ids = range(1, 5) 94 self.battery_pins = Pins(misc_board_address, 0, ADCInput.SINGLE) 95 self.terminal_pins = Pins(misc_board_address, 1, ADCInput.SINGLE) 96 self.thermister_1_pins = Pins(misc_board_address, 1, ADCInput.DIFFERENTIAL) 97 self.thermister_2_pins = Pins(misc_board_address, 2, ADCInput.DIFFERENTIAL) 98 self.heater_pins = Pins(misc_board_address, 6, ADCInput.SINGLE) 99 100 self._lock = RFileLock("piplate") 101 102 def measure(self, board_address: int, channel: int, input_type: ADCInput) -> float: 103 """Measure an input on the ADC plate.""" 104 with SuppressExceptions(), self._lock: 105 ADC.setMODE(board_address, "ADV") # Advanced mode 106 ADC.configINPUT(board_address, f"{input_type.value}{channel}", 7, True) 107 return ADC.readSINGLE(board_address, f"{input_type.value}{channel}") or 0.0 108 return 0.0 109 110 def cell_volts(self, cell_id: int) -> float: 111 """Measure cell voltage (ID 0 to 3).""" 112 self.cell_pins.pin = cell_id - 1 113 return self.measure(*self.cell_pins) 114 115 @property 116 def battery_volts(self) -> float: 117 """Measure battery voltage (cells combined).""" 118 return self.measure(*self.battery_pins) 119 120 @property 121 def terminal_volts(self) -> float: 122 """Measure terminal voltage.""" 123 return self.measure(*self.terminal_pins) 124 125 @property 126 def thermistor_1_volts(self) -> float: 127 """Measure thermistor 1 voltage.""" 128 return self.measure(*self.thermister_1_pins) 129 130 @property 131 def thermistor_2_volts(self) -> float: 132 """Measure thermistor 2 voltage.""" 133 return self.measure(*self.thermister_2_pins) 134 135 @property 136 def heater_volts(self) -> float: 137 """Measure heater voltage.""" 138 return self.measure(*self.heater_pins)
ADC Pi-Plate access.
ADCPlate()
76 def __new__(cls): 77 """Make ADCPlate a singleton.""" 78 cls._instance = cls._instance or super().__new__(cls) 79 return cls._instance
Make ADCPlate a singleton.
102 def measure(self, board_address: int, channel: int, input_type: ADCInput) -> float: 103 """Measure an input on the ADC plate.""" 104 with SuppressExceptions(), self._lock: 105 ADC.setMODE(board_address, "ADV") # Advanced mode 106 ADC.configINPUT(board_address, f"{input_type.value}{channel}", 7, True) 107 return ADC.readSINGLE(board_address, f"{input_type.value}{channel}") or 0.0 108 return 0.0
Measure an input on the ADC plate.
def
cell_volts(self, cell_id: int) -> float:
110 def cell_volts(self, cell_id: int) -> float: 111 """Measure cell voltage (ID 0 to 3).""" 112 self.cell_pins.pin = cell_id - 1 113 return self.measure(*self.cell_pins)
Measure cell voltage (ID 0 to 3).
battery_volts: float
115 @property 116 def battery_volts(self) -> float: 117 """Measure battery voltage (cells combined).""" 118 return self.measure(*self.battery_pins)
Measure battery voltage (cells combined).
terminal_volts: float
120 @property 121 def terminal_volts(self) -> float: 122 """Measure terminal voltage.""" 123 return self.measure(*self.terminal_pins)
Measure terminal voltage.
thermistor_1_volts: float
125 @property 126 def thermistor_1_volts(self) -> float: 127 """Measure thermistor 1 voltage.""" 128 return self.measure(*self.thermister_1_pins)
Measure thermistor 1 voltage.