Files
pqAutomationApp/UniTAP/dev/ports/modules/pdc/pdc_contract_control.py

254 lines
9.9 KiB
Python
Raw Permalink Normal View History

2026-04-16 16:51:05 +08:00
import math
import warnings
from .pdc_io import PDCPortIO, PDCControlCommand
from .pdc_utils import support_or_not
from .pdc_types import FrSwapCurrent, ContractTypePriority, InternalResistance, ExternalResistance
from typing import Union
class PowerContractControlBase:
"""
Class `PowerContractControlBase` allows setting and getting field related with power contract.
- Set and get Give Back flag `give_back_flag`, type `bool`.
- Set and get No USB suspend `no_usb_suspend`, type `bool`.
- Set and get PDO type priority `pdo_type_priority`, type `ContractTypePriority`.
- Set and get Maximum operation current `max_operation_current`, type `int`.
- Set FW Swap required current `fw_swap_required_current`, type `FrSwapCurrent`.
"""
__fr_swap_current = {FrSwapCurrent.Disable: PDCControlCommand.SetFRSwapNoSupported,
FrSwapCurrent.EnableDefaultUSBPower: PDCControlCommand.SetFRSwapUSBPower,
FrSwapCurrent.Enable_1_5A_5V: PDCControlCommand.SetFRSwap1_5A_5V,
FrSwapCurrent.Enable_3A_5V: PDCControlCommand.SetFRSwap3A_5V}
def __init__(self, pdc_io: PDCPortIO):
self._io = pdc_io
self.__caps = self._io.read_pdc_caps()
self.__pdo_count = self._io.read_hw_caps().pdo_count
@property
def give_back_flag(self) -> bool:
"""
Returns state of Give back flag.
Returns:
object of `bool` type
"""
return self._io.read_pdc_contract_control().give_back_flag != 0
@give_back_flag.setter
def give_back_flag(self, enable: bool):
data = self._io.read_pdc_contract_control()
data.give_back_flag = int(enable)
self._io.write_pdc_contract_control(data)
@property
def no_usb_suspend(self) -> bool:
"""
Returns state of No USB suspend flag.
Returns:
object of `bool` type
"""
return self._io.read_pdc_contract_control().no_usb_suspend != 0
@no_usb_suspend.setter
def no_usb_suspend(self, enable: bool):
data = self._io.read_pdc_contract_control()
data.no_usb_suspend = int(enable)
self._io.write_pdc_contract_control(data)
def fw_swap_required_current(self, fr_swap_current: FrSwapCurrent):
"""
Set FW Swap required current.
Args:
fr_swap_current (`FrSwapCurrent`)
"""
if self.__caps.fr_swap:
self._io.write_pdc_command(self.__fr_swap_current.get(fr_swap_current))
else:
warnings.warn("Do not support Fast Role Swap.")
@property
def pdo_type_priority(self) -> ContractTypePriority:
"""
Returns current PDO Type priority.
Returns:
object of `ContractTypePriority` type
"""
return ContractTypePriority(self._io.read_pdc_contract_control().type_priority)
@pdo_type_priority.setter
def pdo_type_priority(self, type_priority: ContractTypePriority):
data = self._io.read_pdc_contract_control()
data.type_priority = type_priority.value
self._io.write_pdc_contract_control(data)
@property
def max_operation_current(self) -> int:
"""
Returns current value of maximum operation current.
Returns:
object of `int` type
"""
data = self._io.read_contract_data()
return data[3] & 0x03FF
@max_operation_current.setter
def max_operation_current(self, current: int):
if current < 0:
raise ValueError(f"Incorrect current {current}. Must be more than 0.")
data = self._io.read_contract_data()
data[3] = (data[3] & 0xFFFFFC00) | (current & 0x03FF)
self._io.write_contract_data(data)
def established(self) -> bool:
"""
Returns state of power contract (established or not).
Returns:
object of `bool` type
"""
return self._io.read_pdc_status().pwr_contract == 1
def __str__(self) -> str:
return f"Power Contract Control\n" \
f"Give Back flag active: {support_or_not(self.give_back_flag)}\n" \
f"No USB suspend flag active: {support_or_not(self.no_usb_suspend)}\n" \
f"Contract type priority: {self.pdo_type_priority.name}\n" \
f"Max operation current: {self.max_operation_current} mA"
class PowerContractControl340(PowerContractControlBase):
"""
Class `PowerContractControl340` inherited from class `PowerContractControlBase`.
Class `PowerContractControl340` allows setting and getting internal and external resistance,
index of power contract.
Also has all the `PowerContractControlBase` functionality.
- Set and get flag Selecting power contract by index `selecting_by_index`, type `bool`.
- Set and get index of power contract `index_of_power_contract`, type `int`.
- Set and get internal resistance `internal_resistance`, type `int` or `InternalResistance`.
- Set and get external resistance `external_resistance`, type `int` or `ExternalResistance`.
"""
__internal_resistance = {10000: InternalResistance.Resistance_10_Ohm,
5500: InternalResistance.Resistance_5_5_Ohm,
3550: InternalResistance.Resistance_3_55_Ohm,
3500: InternalResistance.Resistance_3_5_Ohm,
2600: InternalResistance.Resistance_2_6_Ohm,
2140: InternalResistance.Resistance_2_14_Ohm,
1760: InternalResistance.Resistance_1_76_Ohm}
__external_resistance = {13900: ExternalResistance.Resistance_13_9_Ohm,
10600: ExternalResistance.Resistance_10_6_Ohm,
9100: ExternalResistance.Resistance_9_1_Ohm,
7600: ExternalResistance.Resistance_7_6_Ohm,
6600: ExternalResistance.Resistance_6_6_Ohm,
5600: ExternalResistance.Resistance_5_6_Ohm,
4600: ExternalResistance.Resistance_4_6_Ohm,
3600: ExternalResistance.Resistance_3_6_Ohm,
1800: ExternalResistance.Resistance_1_8_Ohm}
def __init__(self, pdc_io: PDCPortIO):
super().__init__(pdc_io)
@property
def selecting_by_index(self) -> bool:
"""
Returns state of Selecting by index flag.
Returns:
object of `bool` type
"""
return self._io.read_pdc_contract_control().manual != 0
@selecting_by_index.setter
def selecting_by_index(self, enable: bool):
data = self._io.read_pdc_contract_control()
data.manual = enable
self._io.write_pdc_contract_control(data)
@property
def index_of_power_contract(self) -> int:
"""
Returns index of current power contract.
Returns:
object of `int` type
"""
if not self._io.read_pdc_contract_control().manual:
return self._io.read_power_contract_select()
else:
warnings.warn("Negotiate power contract automatically disabled. "
"Please, enable (use function 'enable_selecting_by_index'.)")
return -1
@index_of_power_contract.setter
def index_of_power_contract(self, index: int):
if not self._io.read_pdc_contract_control().manual:
if index < 0:
raise ValueError(f"Incorrect index {index} of power contract. "
f"Must be between 0 and {self.__pdo_count}.")
self._io.write_power_contract_select(index)
else:
warnings.warn("Negotiate power contract automatically disabled. "
"Please, enable (use function 'enable_selecting_by_index'.)")
@property
def internal_resistance(self) -> Union[InternalResistance, int]:
"""
Returns internal resistance.
Returns:
object of `int` or `InternalResistance` type
"""
res = self._io.read_internal_resistance()
for key in self.__internal_resistance.keys():
if math.fabs(res - key) < 50:
return self.__internal_resistance.get(key)
return res
@internal_resistance.setter
def internal_resistance(self, resistance: InternalResistance):
self._io.write_resistance(resistance.value)
@property
def external_resistance(self) -> Union[ExternalResistance, int]:
"""
Returns external resistance.
Returns:
object of `int` or `ExternalResistance` type
"""
if self._io.read_hw_status().ext_power:
res = self._io.read_external_resistance()
for key in self.__external_resistance.keys():
if math.fabs(res - key) < 50:
return self.__external_resistance.get(key)
return res
else:
return ExternalResistance.Disable
@external_resistance.setter
def external_resistance(self, resistance: ExternalResistance):
if self._io.read_hw_status().ext_power:
self._io.write_resistance(resistance.value)
else:
warnings.warn("Does not enabled external power. Please, attach external power device.")
def __str__(self) -> str:
return f"Power Contract Control\n" \
f"Give Back flag active: {support_or_not(self.give_back_flag)}\n" \
f"No USB suspend flag active: {support_or_not(self.no_usb_suspend)}\n" \
f"Contract type priority: {self.pdo_type_priority.name}\n" \
f"Max operation current: {self.max_operation_current} mA\n" \
f"Internal resistance: {self.internal_resistance} Om\n" \
f"External resistance: {self.external_resistance} Om\n" \
f"Selecting power contract by index flag active: {support_or_not(self.selecting_by_index)}\n" \
f"Power contract index: {self.index_of_power_contract if self.selecting_by_index else '0'}"