254 lines
9.9 KiB
Python
254 lines
9.9 KiB
Python
|
|
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'}"
|