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'}"