1.1.0版本
This commit is contained in:
6
UniTAP/dev/ports/modules/pdc/__init__.py
Normal file
6
UniTAP/dev/ports/modules/pdc/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from .pdo import Pdo
|
||||
from .pdc_types import ExternalResistance, InternalResistance, ContractTypePriority, DifferentialPair, \
|
||||
CableControlOrientation, DRPTryMode, USB3Mode, PDMode, PdcDeviceRole, FrSwapCurrent, PowerRole, CCPullUp
|
||||
from .pdo_types import PdoSide, PeakCurrent, PdoTypeEnum, FixedPdoSink, FixedPdoSource, BatteryPdo, VariablePdo
|
||||
from .pdc_dp_alt_mode import PinAssignment
|
||||
from .pdc_dpam_types import PinAssignmentModes, DPAMVersion
|
||||
111
UniTAP/dev/ports/modules/pdc/pdc_bus_status.py
Normal file
111
UniTAP/dev/ports/modules/pdc/pdc_bus_status.py
Normal file
@@ -0,0 +1,111 @@
|
||||
from .pdc_io import PDCPortIO
|
||||
|
||||
|
||||
class BusElectricalStatus:
|
||||
|
||||
"""
|
||||
Class `BusElectricalStatus` contains information about current BUU Electrical status.
|
||||
- Get VBus voltage `vbus_voltage`, type `int`.
|
||||
- Get VBus current `vbus_current`, type `int`.
|
||||
- Get CC1 voltage `cc1_voltage`, type `int`.
|
||||
- Get CC2 voltage `cc2_voltage`, type `int`.
|
||||
- Get VCONN voltage `vconn_voltage`, type `int`.
|
||||
- Get VCONN current `vconn_current`, type `int`.
|
||||
- Get SBU-1 voltage `sbu_1_voltage`, type `int`.
|
||||
- Get SBU-2 voltage `sbu_2_voltage`, type `int`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
self.__io = pdc_io
|
||||
|
||||
@property
|
||||
def vbus_voltage(self) -> int:
|
||||
"""
|
||||
Returns current VBus voltage.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__io.read_adc_vbus_status()[0]
|
||||
|
||||
@property
|
||||
def vbus_current(self) -> int:
|
||||
"""
|
||||
Returns current VBus current.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__io.read_adc_vbus_status()[1]
|
||||
|
||||
@property
|
||||
def cc1_voltage(self) -> int:
|
||||
"""
|
||||
Returns current CC1 voltage.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__io.read_adc_vbus_status()[2]
|
||||
|
||||
@property
|
||||
def cc2_voltage(self) -> int:
|
||||
"""
|
||||
Returns current CC2 voltage.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__io.read_adc_vbus_status()[3]
|
||||
|
||||
@property
|
||||
def vconn_voltage(self) -> int:
|
||||
"""
|
||||
Returns current VCONN voltage.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__io.read_adc_vbus_status()[4]
|
||||
|
||||
@property
|
||||
def vconn_current(self) -> int:
|
||||
"""
|
||||
Returns current VCONN current.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__io.read_adc_vbus_status()[5]
|
||||
|
||||
@property
|
||||
def sbu_1_voltage(self) -> int:
|
||||
"""
|
||||
Returns current SBU-1 voltage.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__io.read_adc_vbus_status()[6]
|
||||
|
||||
@property
|
||||
def sbu_2_voltage(self) -> int:
|
||||
"""
|
||||
Returns current SBU-2 voltage.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__io.read_adc_vbus_status()[7]
|
||||
|
||||
def __str__(self) -> str:
|
||||
electrical_status = self.__io.read_adc_vbus_status()
|
||||
return f"Bus Electrical Status\n" \
|
||||
f"VBus current: {electrical_status[0]}\n" \
|
||||
f"VBus voltage: {electrical_status[1]}\n" \
|
||||
f"CC1 voltage: {electrical_status[2]}\n" \
|
||||
f"CC2 voltage: {electrical_status[3]}\n" \
|
||||
f"VCONN voltage: {electrical_status[4]}\n" \
|
||||
f"VCONN current: {electrical_status[5]}\n" \
|
||||
f"SBU-1 voltage: {electrical_status[6]}\n" \
|
||||
f"SBU-2 voltage: {electrical_status[7]}\n"
|
||||
340
UniTAP/dev/ports/modules/pdc/pdc_capabilities.py
Normal file
340
UniTAP/dev/ports/modules/pdc/pdc_capabilities.py
Normal file
@@ -0,0 +1,340 @@
|
||||
from .pdc_io import PDCPortIO, PDCControlCommand, HWControlCommand
|
||||
from .pdc_types import PdcDeviceRole, CCPullUp, DRPTryMode, USB3Mode, PowerRole
|
||||
from .pdc_utils import support_or_not
|
||||
|
||||
|
||||
class PcdCapsStatus:
|
||||
|
||||
"""
|
||||
Class `PcdCapsStatus` contains information about PDC capabilities.
|
||||
- Get initial device role `initial_role`, type `PdcDeviceRole`.
|
||||
- Get data device role `data_role`, type `PdcDeviceRole`.
|
||||
- Get power device role `power_role`, type `PowerRole`.
|
||||
- Get Cable Control Pull Up `cc_pull_up`, type `CCPullUp`.
|
||||
- Get current behavior, DRP try mode `behavior`, type `DRPTryMode`.
|
||||
- Get state of PR Swap `pr_swap`, type `bool`.
|
||||
- Get state of DR Swap `dr_swap`, type `bool`.
|
||||
- Get state of FR Swap `fr_swap`, type `bool`.
|
||||
- Get state of VCONN Swap `vconn_swap`, type `bool`.
|
||||
- Get state of Debug accessory `debug_accessory`, type `bool`.
|
||||
- Get state of Audio accessory `audio_accessory`, type `bool`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
self.__io = pdc_io
|
||||
|
||||
def initial_role(self) -> PdcDeviceRole:
|
||||
"""
|
||||
Returns current initial role.
|
||||
|
||||
Returns:
|
||||
object of `PdcDeviceRole` type
|
||||
"""
|
||||
return PdcDeviceRole(self.__io.read_pdc_state().dev_role)
|
||||
|
||||
def data_role(self) -> PdcDeviceRole:
|
||||
"""
|
||||
Returns current data role.
|
||||
|
||||
Returns:
|
||||
object of `PdcDeviceRole` type
|
||||
"""
|
||||
return PdcDeviceRole(self.__io.read_pdc_status().data_role)
|
||||
|
||||
def power_role(self) -> PowerRole:
|
||||
"""
|
||||
Returns current power role.
|
||||
|
||||
Returns:
|
||||
object of `PowerRole` type
|
||||
"""
|
||||
return PowerRole(self.__io.read_pdc_status().power_role)
|
||||
|
||||
def cc_pull_up(self) -> CCPullUp:
|
||||
"""
|
||||
Returns current cable control pull up.
|
||||
|
||||
Returns:
|
||||
object of `CCPullUp` type
|
||||
"""
|
||||
return CCPullUp(self.__io.read_pdc_state().cc_pull_up)
|
||||
|
||||
def behavior(self) -> DRPTryMode:
|
||||
"""
|
||||
Returns current behavior of DPR mode.
|
||||
|
||||
Returns:
|
||||
object of `DRPTryMode` type
|
||||
"""
|
||||
return DRPTryMode(self.__io.read_pdc_state().drp_try_mode)
|
||||
|
||||
def pr_swap(self) -> bool:
|
||||
"""
|
||||
Returns current state of PR Swap.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__io.read_pdc_state().pr_swap_en)
|
||||
|
||||
def dr_swap(self) -> bool:
|
||||
"""
|
||||
Returns current state of DR Swap.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__io.read_pdc_state().dr_swap_en)
|
||||
|
||||
def fr_swap(self) -> bool:
|
||||
"""
|
||||
Returns current state of FR Swap.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__io.read_pdc_state().fr_swap_en)
|
||||
|
||||
def vconn_swap(self) -> bool:
|
||||
"""
|
||||
Returns current state of VCONN Swap.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__io.read_pdc_state().vconn_swap_en)
|
||||
|
||||
def debug_accessory(self) -> bool:
|
||||
"""
|
||||
Returns current state of Debug accessory.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__io.read_pdc_state().dbg_accessory)
|
||||
|
||||
def audio_accessory(self) -> bool:
|
||||
"""
|
||||
Returns current state of Audio accessory.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__io.read_pdc_state().aud_accessory)
|
||||
|
||||
def __str__(self):
|
||||
status = self.__io.read_pdc_state()
|
||||
return f"PDC Capabilities:\n" \
|
||||
f"Initial role: {PdcDeviceRole(status.dev_role).name}\n" \
|
||||
f"Power role: {self.power_role().name}\n" \
|
||||
f"Data role: {self.data_role().name}\n" \
|
||||
f"CC Pull-Up: {CCPullUp(status.cc_pull_up).name}\n" \
|
||||
f"Try behavior: {DRPTryMode(status.drp_try_mode).name}\n" \
|
||||
f"PR Swap enabled: {support_or_not(status.pr_swap_en)}\n" \
|
||||
f"DR Swap enabled: {support_or_not(status.dr_swap_en)}\n" \
|
||||
f"FR Swap enabled: {support_or_not(status.fr_swap_en)}\n" \
|
||||
f"VCONN Swap enabled: {support_or_not(status.vconn_swap_en)}\n" \
|
||||
f"Debug accessory enabled: {support_or_not(status.dbg_accessory)}\n" \
|
||||
f"Audio accessory enabled: {support_or_not(status.aud_accessory)}\n"
|
||||
|
||||
|
||||
class PcdCapsStatus340(PcdCapsStatus):
|
||||
|
||||
"""
|
||||
Class `PcdCapsStatus340` inherited of class`PcdCapsStatus` allows working with PDC.
|
||||
Class `PcdCapsStatus340` has all the `PcdCapsStatus` functionality.
|
||||
- Get state of USB 2.0 mode `usb20_mode`, type `bool`.
|
||||
- Get state of UCd 3.0 mode `usb30_mode`, type `USB3Mode`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
super().__init__(pdc_io)
|
||||
|
||||
def usb20_mode(self) -> bool:
|
||||
"""
|
||||
Returns current state of USB 2.0 mode.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__io.read_pdc_state().usb2_enabled)
|
||||
|
||||
def usb30_mode(self) -> USB3Mode:
|
||||
"""
|
||||
Returns current state of USB 3.0 mode.
|
||||
|
||||
Returns:
|
||||
object of `USB3Mode` type
|
||||
"""
|
||||
return USB3Mode(self.__io.read_pdc_state().usb30_mode)
|
||||
|
||||
def __str__(self):
|
||||
status = self.__io.read_pdc_state()
|
||||
return f"PDC Capabilities:" \
|
||||
f"Initial role: {PdcDeviceRole(status.dev_role).name}\n" \
|
||||
f"CC Pull-Up: {CCPullUp(status.cc_pull_up).name}\n" \
|
||||
f"Try behavior: {DRPTryMode(status.drp_try_mode).name}\n" \
|
||||
f"USB 2 enabled: {support_or_not(status.usb2_enabled)}\n" \
|
||||
f"USB 3: {USB3Mode(status.usb30_mode).name}\n" \
|
||||
f"PR Swap enabled: {support_or_not(status.pr_swap_en)}\n" \
|
||||
f"DR Swap enabled: {support_or_not(status.dr_swap_en)}\n" \
|
||||
f"FR Swap enabled: {support_or_not(status.fr_swap_en)}\n" \
|
||||
f"VCONN Swap enabled: {support_or_not(status.vconn_swap_en)}\n" \
|
||||
f"Debug accessory enabled: {support_or_not(status.dbg_accessory)}\n" \
|
||||
f"Audio accessory enabled: {support_or_not(status.aud_accessory)}\n"
|
||||
|
||||
|
||||
class PdcCapabilities:
|
||||
|
||||
"""
|
||||
Class `PdcCapabilities` allows controlling PDC capabilities.
|
||||
- Set device initial role `set_initial_role`.
|
||||
- Enable/Disable PR Swap `enable_pr_swap`.
|
||||
- Enable/Disable DR Swap `enable_dr_swap`.
|
||||
- Enable/Disable FR Swap `enable_fr_swap`.
|
||||
- Enable/Disable VCONN Swap `enable_vconn_swap`.
|
||||
- Set CC Pull Up `cc_pull_up`.
|
||||
- Set DPR try mode behavior `try_behavior`.
|
||||
- Enable/Disable Debug accessory `enable_debug_accessory`.
|
||||
- Enable/Disable Audio accessory `enable_audio_accessory`.
|
||||
"""
|
||||
|
||||
__device_role = {PdcDeviceRole.DFP: PDCControlCommand.SetDataRoleDFP,
|
||||
PdcDeviceRole.UFP: PDCControlCommand.SetDataRoleUFP,
|
||||
PdcDeviceRole.DRP: PDCControlCommand.SetDataRoleDRP}
|
||||
|
||||
__cc_pull_up = {CCPullUp.Current_05_09A: PDCControlCommand.PullCCLineToDefault,
|
||||
CCPullUp.Current_1_5A: PDCControlCommand.PullCCLineTo1_5A,
|
||||
CCPullUp.Current_3A: PDCControlCommand.PullCCLineTo3_0A}
|
||||
|
||||
__behavior = {DRPTryMode.PureDRP: PDCControlCommand.SetDataRoleDRP,
|
||||
DRPTryMode.DRP_try_SNK: PDCControlCommand.SetDataRoleDRP_SNK_Support,
|
||||
DRPTryMode.DRP_try_SRC: PDCControlCommand.SetDataRoleDRP_SRC_Support}
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
self.__io = pdc_io
|
||||
self.__status = PcdCapsStatus(self.__io)
|
||||
|
||||
@property
|
||||
def status(self) -> PcdCapsStatus:
|
||||
"""
|
||||
Returns current PDC Capabilities status.
|
||||
|
||||
Returns:
|
||||
object of `PcdCapsStatus` type
|
||||
"""
|
||||
return self.__status
|
||||
|
||||
def set_initial_role(self, role: PdcDeviceRole):
|
||||
"""
|
||||
Set device initial role.
|
||||
|
||||
Args:
|
||||
role (`PdcDeviceRole`)
|
||||
"""
|
||||
self.__io.write_pdc_command(self.__device_role.get(role))
|
||||
|
||||
def enable_pr_swap(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable PR Swap.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self.__io.write_pdc_command(PDCControlCommand.EnablePRSwap if enable else PDCControlCommand.DisablePRSwap)
|
||||
|
||||
def enable_dr_swap(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable DR Swap.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self.__io.write_pdc_command(PDCControlCommand.EnableDRSwap if enable else PDCControlCommand.DisableDRSwap)
|
||||
|
||||
def enable_fr_swap(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable FR Swap.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self.__io.write_pdc_command(PDCControlCommand.EnableFRSwap if enable else PDCControlCommand.DisableFRSwap)
|
||||
|
||||
def enable_vconn_swap(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable VCONN Swap.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self.__io.write_pdc_command(PDCControlCommand.EnableVconnSwap if enable else PDCControlCommand.DisableVconnSwap)
|
||||
|
||||
def cc_pull_up(self, cc_pull_up: CCPullUp):
|
||||
"""
|
||||
Set Cable Control Pull Up.
|
||||
|
||||
Args:
|
||||
cc_pull_up (`CCPullUp`)
|
||||
"""
|
||||
self.__io.write_pdc_command(self.__cc_pull_up.get(cc_pull_up))
|
||||
|
||||
def try_behavior(self, behavior: DRPTryMode):
|
||||
"""
|
||||
Set DRP try mode behavior.
|
||||
|
||||
Args:
|
||||
behavior (`DRPTryMode`)
|
||||
"""
|
||||
self.__io.write_pdc_command(self.__behavior.get(behavior))
|
||||
|
||||
def enable_debug_accessory(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable Debug Accessory.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self.__io.write_pdc_command(PDCControlCommand.EnableDebugAccessorySupport if enable else
|
||||
PDCControlCommand.EnableDebugAccessorySupport)
|
||||
|
||||
def enable_audio_accessory(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable Audio Accessory.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self.__io.write_pdc_command(PDCControlCommand.EnableAudioAccessorySupport if enable else
|
||||
PDCControlCommand.DisableAudioAccessorySupport)
|
||||
|
||||
|
||||
class PdcCapabilities340(PdcCapabilities):
|
||||
|
||||
"""
|
||||
Class `PdcCapabilities340` inherited of class`PdcCapabilities` allows working with PDC.
|
||||
Class `PdcCapabilities340` has all the `PdcCapabilities` functionality.
|
||||
- Enable/Disable USB 2.0 bypass `usb_2_bypass_function`.
|
||||
- Enable/Disable USB 3.0 bypass `usb_3_bypass_function`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
super().__init__(pdc_io)
|
||||
|
||||
def usb_2_bypass_function(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable USB 2.0 bypass.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self.__io.write_hw_command(HWControlCommand.Enable20PHY if enable else HWControlCommand.Disable20PHY)
|
||||
|
||||
def usb_3_bypass_function(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable USB 3.0 bypass.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self.__io.write_hw_command(HWControlCommand.Enable30PHY if enable else HWControlCommand.Disable30PHY)
|
||||
253
UniTAP/dev/ports/modules/pdc/pdc_contract_control.py
Normal file
253
UniTAP/dev/ports/modules/pdc/pdc_contract_control.py
Normal file
@@ -0,0 +1,253 @@
|
||||
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'}"
|
||||
268
UniTAP/dev/ports/modules/pdc/pdc_controls.py
Normal file
268
UniTAP/dev/ports/modules/pdc/pdc_controls.py
Normal file
@@ -0,0 +1,268 @@
|
||||
import warnings
|
||||
from typing import Optional
|
||||
|
||||
from UniTAP.utils import function_scheduler
|
||||
from .pdc_io import PDCPortIO, PDCControlCommand, HWControlCommand
|
||||
from .pdc_types import CableControlOrientation, DifferentialPair
|
||||
|
||||
|
||||
class PdcControlsBase:
|
||||
|
||||
"""
|
||||
Class `PdcControlsBase` allows controlling some PDC commands:
|
||||
- Send PR Swap `send_pr_swap`.
|
||||
- Send DR Swap `send_dr_swap`.
|
||||
- Send FR Swap `send_fr_swap`.
|
||||
- Send VCONN Swap `send_vconn_swap`.
|
||||
- Change cable control orientation `orientation`.
|
||||
- Attach/DeAttach `attach`.
|
||||
- Enable/Disable auto negotiate power contract `enable_auto_negotiate_power_contract`.
|
||||
- Enable/Disable communication capable as PD Sink `communication_capable_as_pd_sink`.
|
||||
- Enable/Disable communication capable as PD Source `communication_capable_as_pd_source`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
self.__io = pdc_io
|
||||
self.__caps = self.__io.read_pdc_caps()
|
||||
|
||||
def send_pr_swap(self):
|
||||
"""
|
||||
Send Power Role swap. It will be necessary to manually check that the changes have been made.
|
||||
"""
|
||||
self.__io.write_pdc_command(PDCControlCommand.TogglePowerRole)
|
||||
|
||||
def send_dr_swap(self):
|
||||
"""
|
||||
Send Dual Role swap. It will be necessary to manually check that the changes have been made.
|
||||
"""
|
||||
self.__io.write_pdc_command(PDCControlCommand.ToggleDataRole)
|
||||
|
||||
def send_fr_swap(self):
|
||||
"""
|
||||
Send Fast Role swap. It will be necessary to manually check that the changes have been made.
|
||||
"""
|
||||
if self.__caps.fr_swap:
|
||||
self.__io.write_pdc_command(PDCControlCommand.FastRoleSwap)
|
||||
else:
|
||||
warnings.warn("Do not support Fast Role Swap.")
|
||||
|
||||
def send_vconn_swap(self):
|
||||
"""
|
||||
Send VCONN Role swap. It will be necessary to manually check that the changes have been made.
|
||||
"""
|
||||
self.__io.write_pdc_command(PDCControlCommand.SwapVconn)
|
||||
|
||||
@property
|
||||
def orientation(self) -> Optional[CableControlOrientation]:
|
||||
if self.__io.read_hw_status().et_cable:
|
||||
if self.__io.read_hw_status().cc1_closed:
|
||||
return CableControlOrientation.CC1
|
||||
elif self.__io.read_hw_status().cc2_closed:
|
||||
return CableControlOrientation.CC2
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
|
||||
@orientation.setter
|
||||
def orientation(self, orientation: CableControlOrientation):
|
||||
"""
|
||||
Change cable control orientation.
|
||||
|
||||
Args:
|
||||
orientation (`CableControlOrientation`)
|
||||
"""
|
||||
if self.__io.read_hw_status().et_cable:
|
||||
self.__io.write_hw_command(HWControlCommand.SetCableFlipToOn
|
||||
if orientation == CableControlOrientation.CC2 else
|
||||
HWControlCommand.SetCableFlipToOff)
|
||||
else:
|
||||
warnings.warn("Unigraf ET cable is not connected. Cannot switch cable control orientation.")
|
||||
|
||||
def enable_auto_negotiate_power_contract(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable auto negotiate power contract.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
caps = self.__io.read_pdc_contract_control()
|
||||
caps.auto_negotate = enable
|
||||
self.__io.write_pdc_contract_control(caps)
|
||||
|
||||
def communication_capable_as_pd_sink(self, capable: bool):
|
||||
"""
|
||||
Enable/Disable communication capable as PD Sink.
|
||||
|
||||
Args:
|
||||
capable (`bool`)
|
||||
"""
|
||||
self.enable_auto_negotiate_power_contract(capable)
|
||||
pdo = self.__io.read_local_spr_source_pdo()
|
||||
vdo = self.__io.read_tx_id_vdo()
|
||||
if isinstance(vdo, list):
|
||||
if capable:
|
||||
vdo[0] |= 1 << 30
|
||||
else:
|
||||
vdo[0] &= ~(1 << 30)
|
||||
self.__io.write_tx_id_vdo(vdo)
|
||||
if isinstance(pdo, list):
|
||||
if capable:
|
||||
pdo[0].data |= 1 << 26
|
||||
else:
|
||||
pdo[0].data &= ~(1 << 26)
|
||||
self.__io.write_local_spr_source_pdo([v.data for v in pdo])
|
||||
|
||||
def communication_capable_as_pd_source(self, capable: bool):
|
||||
"""
|
||||
Enable/Disable communication capable as PD Source.
|
||||
|
||||
Args:
|
||||
capable (`bool`)
|
||||
"""
|
||||
pdo = self.__io.read_local_spr_source_pdo()
|
||||
vdo = self.__io.read_tx_id_vdo()
|
||||
if isinstance(vdo, list):
|
||||
if capable:
|
||||
vdo[0] |= 1 << 31
|
||||
else:
|
||||
vdo[0] &= ~(1 << 31)
|
||||
self.__io.write_tx_id_vdo(vdo)
|
||||
if isinstance(pdo, list):
|
||||
if capable:
|
||||
pdo[0].data |= 1 << 26
|
||||
else:
|
||||
pdo[0].data &= ~(1 << 26)
|
||||
self.__io.write_local_spr_source_pdo([v.data for v in pdo])
|
||||
|
||||
|
||||
class PdcControls340(PdcControlsBase):
|
||||
|
||||
"""
|
||||
Class `PdcControls340` inherited from class `PdcControlsBase`.
|
||||
Class `PdcControls340` allows controlling additional commands.
|
||||
Also has all the `PdcControlsBase` functionality.
|
||||
- Reconnect device `reconnect`.
|
||||
- Reset device `reset`.
|
||||
- Set ET cable different pairs `et_cable_diff_pairs`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
super().__init__(pdc_io)
|
||||
self.__io = pdc_io
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset device.
|
||||
"""
|
||||
self.__io.write_hw_command(HWControlCommand.ResetPDController)
|
||||
|
||||
def attach(self, attach: bool):
|
||||
"""
|
||||
Attach/DeAttach device.
|
||||
"""
|
||||
self.__io.write_hw_command(HWControlCommand.ConnectCCLines if attach else HWControlCommand.DisconnectCCLines)
|
||||
|
||||
def reconnect(self):
|
||||
"""
|
||||
Reconnect device.
|
||||
|
||||
Returns:
|
||||
result of reconnection, type `bool`.
|
||||
"""
|
||||
self.__io.write_hw_command(HWControlCommand.RePlugCable)
|
||||
|
||||
def is_reconnect_success(__io):
|
||||
return self.__io.read_pdc_status().cable_plug != 0
|
||||
|
||||
return function_scheduler(is_reconnect_success, self.__io, interval=1, timeout=10)
|
||||
|
||||
def et_cable_diff_pairs(self, differential_pair: DifferentialPair):
|
||||
"""
|
||||
Set ET cable different pairs.
|
||||
|
||||
Args:
|
||||
differential_pair (`DifferentialPair`)
|
||||
"""
|
||||
self.__io.write_hw_command(HWControlCommand.SetNewETCableMode if differential_pair.OnePair else
|
||||
HWControlCommand.SetOldETCableMode)
|
||||
|
||||
|
||||
class PdcControls424(PdcControlsBase):
|
||||
|
||||
"""
|
||||
Class `PdcControls424` inherited from class `PdcControlsBase`.
|
||||
Class `PdcControls424` allows controlling additional commands.
|
||||
Also has all the `PdcControlsBase` functionality.
|
||||
- Reconnect device `reconnect`.
|
||||
- Reset device `reset`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
super().__init__(pdc_io)
|
||||
self.__io = pdc_io
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset device.
|
||||
"""
|
||||
self.__io.write_hw_command(HWControlCommand.ResetPDController)
|
||||
|
||||
def reconnect(self) -> bool:
|
||||
"""
|
||||
Reconnect device.
|
||||
|
||||
Returns:
|
||||
result of reconnection, type `bool`.
|
||||
"""
|
||||
self.__io.write_pdc_command(PDCControlCommand.SimulateReConnect)
|
||||
|
||||
def is_reconnect_success(__io):
|
||||
return self.__io.read_pdc_status().cable_plug != 0
|
||||
|
||||
return function_scheduler(is_reconnect_success, self.__io, interval=1, timeout=10)
|
||||
|
||||
|
||||
class PdcControls500(PdcControlsBase):
|
||||
|
||||
"""
|
||||
Class `PdcControls500` inherited from class `PdcControlsBase`.
|
||||
Class `PdcControls500` allows controlling additional commands.
|
||||
Also has all the `PdcControlsBase` functionality.
|
||||
- Reconnect device `reconnect`.
|
||||
- Enable/Disable internal resistance 10 Ohm `enable_internal_load_10_ohm`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
super().__init__(pdc_io)
|
||||
self.__io = pdc_io
|
||||
|
||||
def reconnect(self) -> bool:
|
||||
"""
|
||||
Reconnect device.
|
||||
|
||||
Returns:
|
||||
result of reconnection, type `bool`.
|
||||
"""
|
||||
self.__io.write_hw_command(HWControlCommand.RePlugCable)
|
||||
|
||||
def is_reconnect_success(__io):
|
||||
return self.__io.read_pdc_status().cable_plug != 0
|
||||
|
||||
return function_scheduler(is_reconnect_success, self.__io, interval=1, timeout=10)
|
||||
|
||||
def attach(self, attach: bool):
|
||||
"""
|
||||
Attach/DeAttach device.
|
||||
"""
|
||||
self.__io.write_hw_command(HWControlCommand.ConnectCCLines if attach else HWControlCommand.DisconnectCCLines)
|
||||
|
||||
def enable_internal_load_10_ohm(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable internal resistance 10 Ohm.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self.__io.write_hw_command(HWControlCommand.EnableIntLoad_10_ohm if enable else
|
||||
HWControlCommand.DisableIntLoad_10_ohm)
|
||||
491
UniTAP/dev/ports/modules/pdc/pdc_dp_alt_mode.py
Normal file
491
UniTAP/dev/ports/modules/pdc/pdc_dp_alt_mode.py
Normal file
@@ -0,0 +1,491 @@
|
||||
import warnings
|
||||
|
||||
from UniTAP.dev.ports.modules.pdc.pdc_dpam_types import DPAMVersion
|
||||
from .pdc_io import PDCPortIO, DPAMCommand
|
||||
from .pdc_private_dpam_types import PinAssignmentModes, DISCDpSignaling, DISCCapability
|
||||
from .pdc_utils import support_or_not
|
||||
|
||||
|
||||
class PinAssignment:
|
||||
|
||||
"""
|
||||
Class `PinAssignment` allows enabling and disabling assignment.
|
||||
- Enable/Disable mode C 4 lanes `c_4_lanes`, type `bool`.
|
||||
- Enable/Disable mode D 2 lanes `d_2_lanes`, type `bool`.
|
||||
- Enable/Disable mode E 4 lanes `e_4_lanes`, type `bool`.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.__c_4_lanes = False
|
||||
self.__d_2_lanes = False
|
||||
self.__e_4_lanes = False
|
||||
|
||||
@property
|
||||
def c_4_lanes(self) -> bool:
|
||||
"""
|
||||
Returns state of C 4 lanes mode.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return self.__c_4_lanes
|
||||
|
||||
@c_4_lanes.setter
|
||||
def c_4_lanes(self, enable: bool):
|
||||
self.__c_4_lanes = enable
|
||||
|
||||
@property
|
||||
def d_2_lanes(self) -> bool:
|
||||
"""
|
||||
Returns state of D 2 lanes mode.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return self.__d_2_lanes
|
||||
|
||||
@d_2_lanes.setter
|
||||
def d_2_lanes(self, enable: bool):
|
||||
self.__d_2_lanes = enable
|
||||
|
||||
@property
|
||||
def e_4_lanes(self) -> bool:
|
||||
"""
|
||||
Returns state of E 4 lanes mode.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return self.__e_4_lanes
|
||||
|
||||
@e_4_lanes.setter
|
||||
def e_4_lanes(self, enable: bool):
|
||||
self.__e_4_lanes = enable
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"C 4 lanes: {self.c_4_lanes}\n" \
|
||||
f"D 2 lanes: {self.d_2_lanes}\n" \
|
||||
f"E 4 lanes: {self.e_4_lanes}\n"
|
||||
|
||||
|
||||
class DutDpAltModeStatus:
|
||||
|
||||
"""
|
||||
Class `DutDpAltModeStatus` describes DUT DP Alt mode status.
|
||||
- Get DUT connection state `dut_connection`, type `str`.
|
||||
- Get DUT multi-function state `dut_multi_function`, type `bool`.
|
||||
- Get DUT power low state `dut_power_low`, type `bool`.
|
||||
"""
|
||||
|
||||
__dut_connection_status = {DISCCapability.Reserved: "No connection",
|
||||
DISCCapability.DPF_D_capable: "DFP_D is connected",
|
||||
DISCCapability.UFP_D_capable: "UFP_D is connected",
|
||||
DISCCapability.UFP_D_and_DPF_D: "Both DFP_D and UFP_D are connected"}
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
self.__io = pdc_io
|
||||
|
||||
@property
|
||||
def dut_connection(self) -> str:
|
||||
"""
|
||||
Returns DUT connection state.
|
||||
|
||||
Returns:
|
||||
object of `str` type.
|
||||
"""
|
||||
return self.__dut_connection_status.get(DISCCapability(self.__io.read_dpam_recv().connection))
|
||||
|
||||
@property
|
||||
def dut_multi_function(self) -> bool:
|
||||
"""
|
||||
Returns DUT multi-function state.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return bool(self.__io.read_dpam_recv().multi_func)
|
||||
|
||||
@property
|
||||
def dut_power_low(self) -> bool:
|
||||
"""
|
||||
Returns DUT power low state.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return bool(self.__io.read_dpam_recv().power_low)
|
||||
|
||||
def __str__(self):
|
||||
return f"DUT Alt mode: {self.dut_connection}\n" \
|
||||
f"DUT Multi-function preferred: {support_or_not(self.dut_multi_function)}\n" \
|
||||
f"DUT Power low: {'Low power or DP support disabled' if self.dut_power_low else 'Normal operation'}\n"
|
||||
|
||||
|
||||
class TeDpAltModeStatus:
|
||||
|
||||
"""
|
||||
Class `DutDpAltModeStatus` describes TE DP Alt mode status.
|
||||
- Get active state `te_active`, type `bool`.
|
||||
- Get DISC signaling DP v1.3 state, type `bool`.
|
||||
- Get DISC signaling USB Gen 2 state, type `bool`.
|
||||
- Get PIN assignment, type `PinAssignmentModes`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
self.__io = pdc_io
|
||||
|
||||
@property
|
||||
def te_active(self) -> bool:
|
||||
"""
|
||||
Returns active state.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return bool(self.__io.read_pdc_status().cable_plug)
|
||||
|
||||
@property
|
||||
def te_select_dp_1_3(self) -> bool:
|
||||
"""
|
||||
Returns DISC signaling DP v1.3 state.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return self.__io.read_dpam_config().signaling == DISCDpSignaling.Dp_v13
|
||||
|
||||
@property
|
||||
def te_select_usb_gen2(self) -> bool:
|
||||
"""
|
||||
Returns DISC signaling USB Gen 2 state.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return self.__io.read_dpam_config().signaling == DISCDpSignaling.Gen2
|
||||
|
||||
@property
|
||||
def te_pin_assignment(self) -> PinAssignmentModes:
|
||||
"""
|
||||
Returns PIN assignment.
|
||||
|
||||
Returns:
|
||||
object of `PinAssignmentModes` type.
|
||||
"""
|
||||
|
||||
return PinAssignmentModes(self.__io.read_dpam_config().pin_assign)
|
||||
|
||||
def __str__(self):
|
||||
return f"TE Status Active: {support_or_not(self.te_active)}\n" \
|
||||
f"TE Select DP v1.3: {self.te_select_dp_1_3}\n" \
|
||||
f"TE Select USB gen2: {self.te_select_usb_gen2}\n" \
|
||||
f"TE Pin Assignment: {self.te_pin_assignment.name}\n"
|
||||
|
||||
|
||||
class DpAltModeStatus:
|
||||
"""
|
||||
Class `DpAltModeStatus` describes DP Alt mode status.
|
||||
- Get DUT DP Alt mode status `dut_dp_alt_mode`, type `DutDpAltModeStatus`.
|
||||
- Get TE DP Alt mode status, type `TeDpAltModeStatus`.
|
||||
- Get support state of DISC Signaling DP v13 `support_dp_1_3`, type `bool`.
|
||||
- Get support state of DISC Signaling USB Gen2 `support_usb_gen2`, type `bool`.
|
||||
- Get support state of DFP D `support_dfp_d`, type `bool`.
|
||||
- Get support state of UFP D `support_ufp_d`, type `bool`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
self.__io = pdc_io
|
||||
self.__dut_dp_alt_mode = DutDpAltModeStatus(self.__io)
|
||||
self.__te_dp_alt_mode = TeDpAltModeStatus(self.__io)
|
||||
|
||||
@property
|
||||
def support_dp_1_3(self) -> bool:
|
||||
"""
|
||||
Returns support state of DISC Signaling DP v13.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return self.__io.read_dpam_disc_modes().signaling == DISCDpSignaling.Dp_v13
|
||||
|
||||
@property
|
||||
def support_usb_gen2(self) -> bool:
|
||||
"""
|
||||
Returns support state of DISC Signaling USB Gen2.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return self.__io.read_dpam_disc_modes().signaling == DISCDpSignaling.Gen2
|
||||
|
||||
@property
|
||||
def support_dfp_d(self) -> bool:
|
||||
"""
|
||||
Returns support state of DFP D.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return DISCCapability(self.__io.read_dpam_disc_modes().capability) in [DISCCapability.DPF_D_capable,
|
||||
DISCCapability.UFP_D_and_DPF_D]
|
||||
|
||||
@property
|
||||
def support_ufp_d(self) -> bool:
|
||||
"""
|
||||
Returns support state of UFP D.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return DISCCapability(self.__io.read_dpam_disc_modes().capability) in [DISCCapability.UFP_D_capable,
|
||||
DISCCapability.UFP_D_and_DPF_D]
|
||||
|
||||
def multifunction_preferred(self) -> bool:
|
||||
"""
|
||||
Returns state of multifunction preferred.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return self.__io.read_dpam_caps2()
|
||||
|
||||
def auto_enter(self) -> bool:
|
||||
"""
|
||||
Returns state of auto enter.
|
||||
|
||||
Returns:
|
||||
object of `bool` type.
|
||||
"""
|
||||
return self.__io.read_dpam_state().auto_dpam != 0
|
||||
|
||||
@property
|
||||
def dut_dp_alt_mode(self) -> DutDpAltModeStatus:
|
||||
"""
|
||||
Returns DUT DP Alt mode status.
|
||||
|
||||
Returns:
|
||||
object of `DutDpAltModeStatus` type.
|
||||
"""
|
||||
return self.__dut_dp_alt_mode
|
||||
|
||||
@property
|
||||
def te_dp_alt_mode(self) -> TeDpAltModeStatus:
|
||||
"""
|
||||
Returns TE DP Alt mode status.
|
||||
|
||||
Returns:
|
||||
object of `TeDpAltModeStatus` type.
|
||||
"""
|
||||
return self.__te_dp_alt_mode
|
||||
|
||||
def __str__(self):
|
||||
return f"Supports DP v1.3: {support_or_not(self.support_dp_1_3)}\n" \
|
||||
f"Supports USB gen2: {support_or_not(self.support_usb_gen2)}\n" \
|
||||
f"Multifunction preferred: {support_or_not(self.multifunction_preferred())}\n" \
|
||||
f"Auto enter: {support_or_not(self.auto_enter())}\n" \
|
||||
f"Pin Assignment supported:\n" \
|
||||
f" - Support DFP_D: {support_or_not(self.support_dfp_d)}\n" \
|
||||
f" - Support UFP_D: {support_or_not(self.support_ufp_d)}\n" \
|
||||
f"{self.__dut_dp_alt_mode.__str__()}" \
|
||||
f"{self.__te_dp_alt_mode.__str__()}"
|
||||
|
||||
|
||||
class DpAltModeBase:
|
||||
|
||||
"""
|
||||
Class `DpAltModeBase` describes basic DP Alt mode functionality.
|
||||
- Get DP Alt mode status `status`, type `DpAltModeStatus`.
|
||||
- Enter to 2 lane mode `enter_2_lane`.
|
||||
- Enter to 4 lane mode `enter_4_lane`.
|
||||
- Exit from DP Alt mode `exit`.
|
||||
- Disable DP Alt mode `disable`.
|
||||
- Enable/Disable auto enter to DP Alt mode `auto_enter`.
|
||||
- Enable/Disable multifunction preferred `multifunction_preferred`.
|
||||
- Enable/Disable align Dp and USB Data role `align_dp_and_usb_data_role`.
|
||||
- Set and get UFP caps `ufp_caps`, type `PinAssignment`.
|
||||
- Set and get DFP caps `dfp_caps`, type `PinAssignment`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
self._io = pdc_io
|
||||
self.__caps = self._io.read_pdc_caps()
|
||||
self.__status = DpAltModeStatus(pdc_io)
|
||||
|
||||
@property
|
||||
def status(self) -> DpAltModeStatus:
|
||||
"""
|
||||
Returns DP Alt mode status.
|
||||
|
||||
Returns:
|
||||
object of `DpAltModeStatus` type.
|
||||
"""
|
||||
return self.__status
|
||||
|
||||
def enter_2_lane(self):
|
||||
"""
|
||||
Enter to 2 lane mode.
|
||||
"""
|
||||
self._io.write_dpam_control(DPAMCommand.EnterDPAM2lanes)
|
||||
|
||||
def enter_4_lane(self):
|
||||
"""
|
||||
Enter to 4 lane mode.
|
||||
"""
|
||||
self._io.write_dpam_control(DPAMCommand.EnterDPAM4lanes)
|
||||
|
||||
def exit(self):
|
||||
"""
|
||||
Exit from DP Alt mode.
|
||||
"""
|
||||
self._io.write_dpam_control(DPAMCommand.ExitDPAM)
|
||||
|
||||
def disable(self):
|
||||
"""
|
||||
Disable DP Alt mode.
|
||||
"""
|
||||
self._io.write_dpam_control(DPAMCommand.DisableDPAM)
|
||||
|
||||
def auto_enter(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable auto enter to DP Alt mode.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self._io.write_dpam_control(DPAMCommand.AutoEnterDPAM if enable else DPAMCommand.ManualDPAM)
|
||||
|
||||
def multifunction_preferred(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable multifunction preferred.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self._io.write_dpam_control(DPAMCommand.SetMFPreferredFlag if enable else DPAMCommand.ClearMFPreferredFlag)
|
||||
|
||||
def align_dp_and_usb_data_role(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable align Dp and USB Data role.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
if self.__caps.align_dp_usb:
|
||||
self._io.write_dpam_control(DPAMCommand.SetAlignDpCUsb if enable else DPAMCommand.ClearAlignDpCUsb)
|
||||
self._io.write_dpam_control(DPAMCommand.SetAlignDpDUsb if enable else DPAMCommand.ClearAlignDpDUsb)
|
||||
self._io.write_dpam_control(DPAMCommand.SetAlignDpEUsb if enable else DPAMCommand.ClearAlignDpEUsb)
|
||||
else:
|
||||
warnings.warn("Align DP and USB data role is not supported.")
|
||||
|
||||
@property
|
||||
def ufp_caps(self) -> PinAssignment:
|
||||
"""
|
||||
Returns current UFP caps.
|
||||
|
||||
Returns:
|
||||
object of `PinAssignment`
|
||||
"""
|
||||
caps = self._io.read_dpam_caps()
|
||||
pin_assignment = PinAssignment()
|
||||
pin_assignment.c_4_lanes = ((caps.ufp_assign >> 2 & 1) != 0)
|
||||
pin_assignment.d_2_lanes = ((caps.ufp_assign >> 3 & 1) != 0)
|
||||
pin_assignment.e_4_lanes = ((caps.ufp_assign >> 4 & 1) != 0)
|
||||
return pin_assignment
|
||||
|
||||
@ufp_caps.setter
|
||||
def ufp_caps(self, ufp_caps: PinAssignment):
|
||||
caps = self._io.read_dpam_caps()
|
||||
if ufp_caps.c_4_lanes:
|
||||
caps.ufp_assign |= PinAssignmentModes.C_4lanes.value
|
||||
else:
|
||||
caps.ufp_assign &= ~PinAssignmentModes.C_4lanes.value
|
||||
if ufp_caps.d_2_lanes:
|
||||
caps.ufp_assign |= PinAssignmentModes.D_2lanes.value
|
||||
else:
|
||||
caps.ufp_assign &= ~PinAssignmentModes.D_2lanes.value
|
||||
if ufp_caps.e_4_lanes:
|
||||
caps.ufp_assign |= PinAssignmentModes.E_4lanes.value
|
||||
else:
|
||||
caps.ufp_assign &= ~PinAssignmentModes.E_4lanes.value
|
||||
self._io.write_dpam_caps(caps)
|
||||
|
||||
@property
|
||||
def dfp_caps(self) -> PinAssignment:
|
||||
"""
|
||||
Returns current DFP caps.
|
||||
|
||||
Returns:
|
||||
object of `PinAssignment`
|
||||
"""
|
||||
caps = self._io.read_dpam_caps()
|
||||
pin_assignment = PinAssignment()
|
||||
pin_assignment.c_4_lanes = ((caps.ufp_assign >> 2 & 1) != 0)
|
||||
pin_assignment.d_2_lanes = ((caps.ufp_assign >> 3 & 1) != 0)
|
||||
pin_assignment.e_4_lanes = ((caps.ufp_assign >> 4 & 1) != 0)
|
||||
return pin_assignment
|
||||
|
||||
@dfp_caps.setter
|
||||
def dfp_caps(self, dfp_caps: PinAssignment):
|
||||
caps = self._io.read_dpam_caps()
|
||||
if dfp_caps.c_4_lanes:
|
||||
caps.dfp_assign |= PinAssignmentModes.C_4lanes.value
|
||||
else:
|
||||
caps.dfp_assign &= ~PinAssignmentModes.C_4lanes.value
|
||||
if dfp_caps.d_2_lanes:
|
||||
caps.dfp_assign |= PinAssignmentModes.D_2lanes.value
|
||||
else:
|
||||
caps.dfp_assign &= ~PinAssignmentModes.D_2lanes.value
|
||||
if dfp_caps.e_4_lanes:
|
||||
caps.dfp_assign |= PinAssignmentModes.E_4lanes.value
|
||||
else:
|
||||
caps.dfp_assign &= ~PinAssignmentModes.E_4lanes.value
|
||||
self._io.write_dpam_caps(caps)
|
||||
|
||||
@property
|
||||
def version(self) -> DPAMVersion:
|
||||
return DPAMVersion(self._io.read_dpam_caps().dpam_version)
|
||||
|
||||
|
||||
class DpAltMode500(DpAltModeBase):
|
||||
|
||||
"""
|
||||
Class `DpAltMode500` inherited from class `DpAltModeBase`.
|
||||
Class `DpAltMode500` allows controlling additional commands.
|
||||
Also has all the `DpAltModeBase` functionality.
|
||||
- Enable/Disable DP 2.1 Alt mode `enable_dp21`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
super().__init__(pdc_io)
|
||||
|
||||
def enable_dp21(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable DP 2.1 Alt mode.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self._io.write_dpam_control(DPAMCommand.EnableDPAM2_1 if enable else DPAMCommand.DisableDPAM2_1)
|
||||
|
||||
|
||||
class DpAltMode340(DpAltModeBase):
|
||||
|
||||
"""
|
||||
Class `DpAltMode340` inherited from class `DpAltModeBase`.
|
||||
Class `DpAltMode340` allows controlling additional commands.
|
||||
Also has all the `DpAltModeBase` functionality.
|
||||
- Enable/Disable DP to Type-C cable adapter mode `dp_to_type_c_cable_adapter_mode`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
super().__init__(pdc_io)
|
||||
|
||||
def dp_to_type_c_cable_adapter_mode(self, enable: bool):
|
||||
"""
|
||||
Enable/Disable DP to Type-C cable adapter mode.
|
||||
|
||||
Args:
|
||||
enable (`bool`)
|
||||
"""
|
||||
self._io.write_dpam_control(DPAMCommand.EnableDPtoTypeCAdapter if enable else
|
||||
DPAMCommand.DisableDPtoTypeCAdapter)
|
||||
43
UniTAP/dev/ports/modules/pdc/pdc_dpam_types.py
Normal file
43
UniTAP/dev/ports/modules/pdc/pdc_dpam_types.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from enum import IntEnum
|
||||
|
||||
|
||||
class DISCCapability(IntEnum):
|
||||
"""
|
||||
Class `DISCCapability` contains all possible variants of DISC capability.
|
||||
"""
|
||||
Reserved = 0
|
||||
UFP_D_capable = 1
|
||||
DPF_D_capable = 2
|
||||
UFP_D_and_DPF_D = 3
|
||||
|
||||
|
||||
class DISCDpSignaling(IntEnum):
|
||||
"""
|
||||
Class `DISCDpSignaling` contains all possible variants of signaling.
|
||||
"""
|
||||
Unspecified = 0
|
||||
Dp_v13 = 1
|
||||
Gen2 = 2
|
||||
|
||||
|
||||
class PinAssignmentModes(IntEnum):
|
||||
"""
|
||||
Class `PinAssignmentModes` contains all possible variants of pin assignment.
|
||||
"""
|
||||
NotSupported = 0x00
|
||||
A_4_2lanes = 0x01
|
||||
B_2_1lanes = 0x02
|
||||
C_4lanes = 0x04
|
||||
D_2lanes = 0x08
|
||||
E_4lanes = 0x10
|
||||
F_2lanes_USB_GEN1 = 0x20
|
||||
|
||||
|
||||
class DPAMVersion(IntEnum):
|
||||
"""
|
||||
Class `PinAssignmentModes` contains all possible variants of DP Alt mode version.
|
||||
"""
|
||||
V_20_or_Earlier = 0
|
||||
V_21_or_Higher = 1
|
||||
Reserved = 2
|
||||
Reserved2 = 3
|
||||
115
UniTAP/dev/ports/modules/pdc/pdc_io.py
Normal file
115
UniTAP/dev/ports/modules/pdc/pdc_io.py
Normal file
@@ -0,0 +1,115 @@
|
||||
from UniTAP.libs.lib_tsi.tsi_io import PortIO
|
||||
from UniTAP.libs.lib_tsi.tsi_private_types import *
|
||||
from .pdc_private_dpam_types import DPAMCaps, DPAMState, DPAMCommand, DPAMConfig, DPAMDiscModes, DPAMRecv
|
||||
from .pdc_private_types import HWControlCommand, HWStatus, HWCaps, PDCStatus, PDCControlCommand, PDCState, PDCCaps, \
|
||||
PDCContractInfo
|
||||
from .pdo_private_types import PdoUnion
|
||||
|
||||
|
||||
class PDCPortIO:
|
||||
|
||||
def __init__(self, port_io: PortIO):
|
||||
self.__io = port_io
|
||||
self.write_adc_control()
|
||||
|
||||
def write_dpam_caps(self, caps: DPAMCaps):
|
||||
self.__io.set(TSI_PDC_DPAM_CAPS, caps.value(), c_uint32)
|
||||
|
||||
def read_dpam_caps(self) -> DPAMCaps:
|
||||
return self.__io.get(TSI_PDC_DPAM_CAPS, DPAMCaps)[1]
|
||||
|
||||
def read_dpam_caps2(self) -> bool:
|
||||
return (self.__io.get(TSI_PDC_DPAM_CAPS2, c_uint32)[1] & 0x1) != 0
|
||||
|
||||
def read_dpam_state(self) -> DPAMState:
|
||||
return self.__io.get(TSI_PDC_DPAM_STATE_R, DPAMState)[1]
|
||||
|
||||
def write_dpam_control(self, command: DPAMCommand):
|
||||
self.__io.set(TSI_PDC_DPAM_CONTROL_W, command.value, c_uint32)
|
||||
|
||||
def read_dpam_config(self) -> DPAMConfig:
|
||||
return self.__io.get(TSI_PDC_DPAM_CONFIG_R, DPAMConfig)[1]
|
||||
|
||||
def read_dpam_disc_modes(self) -> DPAMDiscModes:
|
||||
return self.__io.get(TSI_PDC_DPAM_DISC_MODES_R, DPAMDiscModes)[1]
|
||||
|
||||
def read_dpam_recv(self) -> DPAMRecv:
|
||||
return self.__io.get(TSI_PDC_DPAM_RECV_STS_R, DPAMRecv)[1]
|
||||
|
||||
def write_hw_command(self, command: HWControlCommand):
|
||||
self.__io.set(TSI_PDC_HW_CONTROL_W, command.value, c_uint32)
|
||||
|
||||
def read_hw_status(self) -> HWStatus:
|
||||
return self.__io.get(TSI_PDC_HW_STATUS_R, HWStatus)[1]
|
||||
|
||||
def read_hw_caps(self) -> HWCaps:
|
||||
return self.__io.get(TSI_PDC_HW_CAPS_R, HWCaps)[1]
|
||||
|
||||
def read_pdc_status(self) -> PDCStatus:
|
||||
return self.__io.get(TSI_PDC_STATUS_R, PDCStatus)[1]
|
||||
|
||||
def write_pdc_command(self, command: PDCControlCommand):
|
||||
self.__io.set(TSI_PDC_CONTROL, command.value, c_uint32)
|
||||
|
||||
def read_pdc_state(self) -> PDCState:
|
||||
return self.__io.get(TSI_PDC_STATE, PDCState)[1]
|
||||
|
||||
def read_pdc_caps(self) -> PDCCaps:
|
||||
return self.__io.get(TSI_PDC_CAPS, PDCCaps)[1]
|
||||
|
||||
def write_pdc_contract_control(self, caps: PDCContractInfo):
|
||||
self.__io.set(TSI_USBC_PWR_CONTRACT_CONTROL, caps.value(), c_uint32)
|
||||
|
||||
def read_pdc_contract_control(self) -> PDCContractInfo:
|
||||
return self.__io.get(TSI_USBC_PWR_CONTRACT_CONTROL, PDCContractInfo)[1]
|
||||
|
||||
def read_local_spr_source_pdo(self) -> list:
|
||||
return self.__io.get(TSI_USBC_PWR_LOCAL_SOURCE_PDO, PdoUnion, self.read_hw_caps().pdo_count)[1]
|
||||
|
||||
def write_local_spr_source_pdo(self, data: list):
|
||||
self.__io.set(TSI_USBC_PWR_LOCAL_SOURCE_PDO, data, c_uint32, len(data))
|
||||
|
||||
def read_local_spr_sink_pdo(self) -> list:
|
||||
return self.__io.get(TSI_USBC_PWR_LOCAL_SINK_PDO, PdoUnion, self.read_hw_caps().pdo_count)[1]
|
||||
|
||||
def write_local_spr_sink_pdo(self, data: list):
|
||||
self.__io.set(TSI_USBC_PWR_LOCAL_SINK_PDO, data, c_uint32, len(data))
|
||||
|
||||
def read_tx_id_vdo_count(self) -> int:
|
||||
return self.__io.get(TSI_PDC_TX_ID_VDO_CNT, c_uint32)[1]
|
||||
|
||||
def read_tx_id_vdo(self) -> list:
|
||||
return self.__io.get(TSI_PDC_TX_ID_VDO, c_uint32, self.read_tx_id_vdo_count())[1]
|
||||
|
||||
def write_tx_id_vdo(self, data: list):
|
||||
self.__io.set(TSI_PDC_TX_ID_VDO, data, c_uint32, len(data))
|
||||
|
||||
def read_contract_data(self) -> list:
|
||||
return self.__io.get(TSI_PDC_CONTRACT_DATA, c_uint32, 4)[1]
|
||||
|
||||
def write_contract_data(self, data: list):
|
||||
self.__io.set(TSI_PDC_CONTRACT_DATA, data, c_uint32, len(data))
|
||||
|
||||
def read_power_contract_select(self) -> int:
|
||||
return self.__io.get(TSI_USBC_PWR_CONTRACT_SELECT, c_uint32)[1]
|
||||
|
||||
def write_power_contract_select(self, index: int):
|
||||
self.__io.set(TSI_USBC_PWR_CONTRACT_SELECT, index, c_uint32)
|
||||
|
||||
def read_resistance(self) -> int:
|
||||
return self.__io.get(TSI_USBC_RESISTANCE_CONTROL, c_uint32)[1]
|
||||
|
||||
def write_resistance(self, resistance: int):
|
||||
self.__io.set(TSI_USBC_RESISTANCE_CONTROL, resistance, c_uint32)
|
||||
|
||||
def read_adc_vbus_status(self) -> list:
|
||||
return self.__io.get(TSI_ADC_VBUS_VOLTAGE_R, c_uint32, TSI_ADC_BLOCK_SIZE_WORDS)[1]
|
||||
|
||||
def read_internal_resistance(self) -> int:
|
||||
return self.__io.get(TSI_USBC_INT_RESISTANCE_STATUS_R, c_uint32)[1]
|
||||
|
||||
def read_external_resistance(self) -> int:
|
||||
return self.__io.get(TSI_USBC_EXT_RESISTANCE_STATUS_R, c_uint32)[1]
|
||||
|
||||
def write_adc_control(self):
|
||||
self.__io.set(TSI_W_USBC_ADC_CTRL, 1, c_uint32)
|
||||
144
UniTAP/dev/ports/modules/pdc/pdc_power_sink.py
Normal file
144
UniTAP/dev/ports/modules/pdc/pdc_power_sink.py
Normal file
@@ -0,0 +1,144 @@
|
||||
import copy
|
||||
|
||||
from .pdc_io import PDCPortIO
|
||||
from .pdc_utils import load_pdo, save_pdo
|
||||
from .pdo_types import FixedPdoSink, BatteryPdo, VariablePdo, PdoTypeEnum, PdoSide
|
||||
from .pdo import Pdo
|
||||
from .pdo_utils import get_pdo_value
|
||||
from typing import List
|
||||
|
||||
|
||||
class PowerSink:
|
||||
|
||||
"""
|
||||
Class `PowerSink` contains information about PDO's on Sink side.
|
||||
- Get PDO count `pdo_count`, type `int`.
|
||||
- Set and get PDO list, `set_pdo_list`, `get_pdo_list`, type `list` with `Pdo`.
|
||||
- Set and get PDO by index, `set_pdo_by_index`, `get_pdo_by_index`, type `Pdo`.
|
||||
- Save information about PDO's to file, `save_pdo`.
|
||||
- Load information about PDO's from file, `load_pdo`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
self.__io = pdc_io
|
||||
self.__pdo_count = self.__io.read_hw_caps().pdo_count
|
||||
self.__pdo_list = self.__read_pdo()
|
||||
|
||||
def __read_pdo(self) -> List[Pdo]:
|
||||
pdo_list = []
|
||||
values = self.__io.read_local_spr_sink_pdo()
|
||||
for i in range(self.__pdo_count):
|
||||
if PdoTypeEnum(values[i].brief_info.pdo_type) == PdoTypeEnum.Fixed and values[i].data > 0:
|
||||
pdo_list.append(Pdo(pdo=FixedPdoSink(values[i].fixed_pdo_sink, disable=False), side=PdoSide.Sink))
|
||||
elif PdoTypeEnum(values[i].brief_info.pdo_type) == PdoTypeEnum.Fixed and values[i].data == 0:
|
||||
pdo_list.append(Pdo(pdo=FixedPdoSink(values[i].fixed_pdo_sink, disable=True), side=PdoSide.Sink))
|
||||
elif PdoTypeEnum(values[i].brief_info.pdo_type) == PdoTypeEnum.Battery:
|
||||
pdo_list.append(Pdo(pdo=BatteryPdo(values[i].battery_pdo), side=PdoSide.Sink))
|
||||
elif PdoTypeEnum(values[i].brief_info.pdo_type) == PdoTypeEnum.Variable:
|
||||
pdo_list.append(Pdo(pdo=VariablePdo(values[i].variable_pdo), side=PdoSide.Sink))
|
||||
return pdo_list
|
||||
|
||||
def __write_pdo(self) -> List[int]:
|
||||
pdo_list = []
|
||||
for index, item in enumerate(self.__pdo_list):
|
||||
if index == 0:
|
||||
pdo_list.append(get_pdo_value(item.get_pdo_as_selected_type(FixedPdoSink)))
|
||||
elif item.pdo_type != PdoTypeEnum.Disabled:
|
||||
pdo_list.append(get_pdo_value(item.pdo_object))
|
||||
else:
|
||||
pdo_list.append(0)
|
||||
return pdo_list
|
||||
|
||||
@property
|
||||
def pdo_count(self) -> int:
|
||||
"""
|
||||
Returns current pdo count.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__pdo_count
|
||||
|
||||
def set_pdo_list(self, pdo_list: List[Pdo]):
|
||||
"""
|
||||
Set new Pdo list.
|
||||
|
||||
Args:
|
||||
pdo_list (`list` with 'Pdo')
|
||||
"""
|
||||
self.__pdo_list = copy.deepcopy(pdo_list)
|
||||
self.__io.write_local_spr_sink_pdo(self.__write_pdo())
|
||||
|
||||
def set_pdo_by_index(self, pdo_object, index: int):
|
||||
"""
|
||||
Set new Pdo by index.
|
||||
|
||||
Args:
|
||||
pdo_object ('Pdo')
|
||||
index (`int`)
|
||||
"""
|
||||
if not 0 <= index < self.__pdo_count:
|
||||
raise ValueError(f"Incorrect PDO index. Supported PDO amount: {self.__pdo_count}")
|
||||
self.__pdo_list[index] = copy.deepcopy(pdo_object)
|
||||
self.__io.write_local_spr_sink_pdo(self.__write_pdo())
|
||||
|
||||
def get_pdo_list(self, read_from_device: bool = False) -> List[Pdo]:
|
||||
"""
|
||||
Returns current pdo list.
|
||||
|
||||
Args:
|
||||
read_from_device (`bool`)
|
||||
|
||||
Returns:
|
||||
object of `list` type with `Pdo`.
|
||||
"""
|
||||
if read_from_device:
|
||||
self.__pdo_list = self.__read_pdo()
|
||||
return copy.deepcopy(self.__pdo_list)
|
||||
|
||||
def get_pdo_by_index(self, index: int, read_from_device: bool = False) -> Pdo:
|
||||
"""
|
||||
Returns current pdo by index.
|
||||
|
||||
Args:
|
||||
index (`int`)
|
||||
read_from_device (`bool`)
|
||||
|
||||
Returns:
|
||||
object of `Pdo` type.
|
||||
"""
|
||||
if read_from_device:
|
||||
self.__pdo_list = self.__read_pdo()
|
||||
if not 0 <= index < self.__pdo_count:
|
||||
raise ValueError(f"Incorrect PDO index. Supported PDO amount: {self.__pdo_count}")
|
||||
return copy.deepcopy(self.__pdo_list[index])
|
||||
|
||||
def save_pdo(self, path: str):
|
||||
"""
|
||||
Save information about PDO's to file.
|
||||
Supported formats:
|
||||
- txt
|
||||
- json
|
||||
|
||||
Args:
|
||||
path (`str`)
|
||||
"""
|
||||
save_pdo(path, self.__pdo_list, False)
|
||||
|
||||
def load_pdo(self, path: str):
|
||||
"""
|
||||
Load information about PDO's from file.
|
||||
Supported formats:
|
||||
- txt
|
||||
- json
|
||||
|
||||
Args:
|
||||
path (`str`)
|
||||
"""
|
||||
self.__pdo_list = load_pdo(path, False)
|
||||
|
||||
def __str__(self) -> str:
|
||||
pdo_status = ""
|
||||
for index, item in enumerate(self.__pdo_list):
|
||||
pdo_status += f"PDO {index}\n{item.pdo_object.__str__()}\n"
|
||||
return f"Power Sink\n{pdo_status}\n"
|
||||
152
UniTAP/dev/ports/modules/pdc/pdc_power_source.py
Normal file
152
UniTAP/dev/ports/modules/pdc/pdc_power_source.py
Normal file
@@ -0,0 +1,152 @@
|
||||
import copy
|
||||
|
||||
from .pdc_io import PDCPortIO
|
||||
from .pdc_private_types import PDCControlCommand
|
||||
from .pdc_utils import load_pdo, save_pdo
|
||||
from .pdo_types import FixedPdoSource, BatteryPdo, VariablePdo, PdoTypeEnum, PdoSide
|
||||
from .pdo import Pdo
|
||||
from .pdo_utils import get_pdo_value
|
||||
from typing import List
|
||||
|
||||
|
||||
class PowerSource:
|
||||
|
||||
"""
|
||||
Class `PowerSource` contains information about PDO's on Source side.
|
||||
- Get PDO count `pdo_count`, type `int`.
|
||||
- Set and get PDO list, `set_pdo_list`, `get_pdo_list`, type `list` with `Pdo`.
|
||||
- Set and get PDO by index, `set_pdo_by_index`, `get_pdo_by_index`, type `Pdo`.
|
||||
- Send Source PDO's, `send_pdo`.
|
||||
- Save information about PDO's to file, `save_pdo`.
|
||||
- Load information about PDO's from file, `load_pdo`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdc_io: PDCPortIO):
|
||||
self.__io = pdc_io
|
||||
self.__pdo_count = self.__io.read_hw_caps().pdo_count
|
||||
self.__pdo_list = self.__read_pdo()
|
||||
|
||||
def __read_pdo(self) -> List[Pdo]:
|
||||
pdo_list = []
|
||||
values = self.__io.read_local_spr_source_pdo()
|
||||
for i in range(self.__pdo_count):
|
||||
if PdoTypeEnum(values[i].brief_info.pdo_type) == PdoTypeEnum.Fixed and values[i].data > 0:
|
||||
pdo_list.append(Pdo(pdo=FixedPdoSource(values[i].fixed_pdo_source, disable=False), side=PdoSide.Source))
|
||||
elif PdoTypeEnum(values[i].brief_info.pdo_type) == PdoTypeEnum.Fixed and values[i].data == 0:
|
||||
pdo_list.append(Pdo(pdo=FixedPdoSource(values[i].fixed_pdo_source, disable=True), side=PdoSide.Source))
|
||||
elif PdoTypeEnum(values[i].brief_info.pdo_type) == PdoTypeEnum.Battery:
|
||||
pdo_list.append(Pdo(pdo=BatteryPdo(values[i].battery_pdo), side=PdoSide.Source))
|
||||
elif PdoTypeEnum(values[i].brief_info.pdo_type) == PdoTypeEnum.Variable:
|
||||
pdo_list.append(Pdo(pdo=VariablePdo(values[i].variable_pdo), side=PdoSide.Source))
|
||||
return pdo_list
|
||||
|
||||
def __write_pdo(self) -> List[int]:
|
||||
pdo_list = []
|
||||
for index, item in enumerate(self.__pdo_list):
|
||||
if index == 0:
|
||||
pdo_list.append(get_pdo_value(item.get_pdo_as_selected_type(FixedPdoSource)))
|
||||
elif item.pdo_type != PdoTypeEnum.Disabled:
|
||||
pdo_list.append(get_pdo_value(item.pdo_object))
|
||||
else:
|
||||
pdo_list.append(0)
|
||||
return pdo_list
|
||||
|
||||
@property
|
||||
def pdo_count(self) -> int:
|
||||
"""
|
||||
Returns current pdo count.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__pdo_count
|
||||
|
||||
def send_pdo(self):
|
||||
"""
|
||||
Send Source PDO's.
|
||||
"""
|
||||
self.__io.write_pdc_command(PDCControlCommand.SendSourceCaps)
|
||||
|
||||
def get_pdo_list(self, read_from_device: bool = False) -> List[Pdo]:
|
||||
"""
|
||||
Returns current pdo list.
|
||||
|
||||
Args:
|
||||
read_from_device (`bool`)
|
||||
|
||||
Returns:
|
||||
object of `list` type with `Pdo`.
|
||||
"""
|
||||
if read_from_device:
|
||||
self.__pdo_list = self.__read_pdo()
|
||||
return copy.deepcopy(self.__pdo_list)
|
||||
|
||||
def get_pdo_by_index(self, index: int, read_from_device: bool = False):
|
||||
"""
|
||||
Returns current pdo by index.
|
||||
|
||||
Args:
|
||||
index (`int`)
|
||||
read_from_device (`bool`)
|
||||
|
||||
Returns:
|
||||
object of `Pdo` type.
|
||||
"""
|
||||
if read_from_device:
|
||||
self.__pdo_list = self.__read_pdo()
|
||||
if not 0 <= index < self.__pdo_count:
|
||||
raise ValueError(f"Incorrect PDO index. Supported PDO amount: {self.__pdo_count}")
|
||||
return copy.deepcopy(self.__pdo_list[index])
|
||||
|
||||
def set_pdo_list(self, pdo_list: List[Pdo]):
|
||||
"""
|
||||
Set new Pdo list.
|
||||
|
||||
Args:
|
||||
pdo_list (`list` with 'Pdo')
|
||||
"""
|
||||
self.__pdo_list = copy.deepcopy(pdo_list)
|
||||
self.__io.write_local_spr_source_pdo(self.__write_pdo())
|
||||
|
||||
def set_pdo_by_index(self, pdo_object, index: int):
|
||||
"""
|
||||
Set new Pdo by index.
|
||||
|
||||
Args:
|
||||
pdo_object ('Pdo')
|
||||
index (`int`)
|
||||
"""
|
||||
if not 0 <= index < self.__pdo_count:
|
||||
raise ValueError(f"Incorrect PDO index. Supported PDO amount: {self.__pdo_count}")
|
||||
self.__pdo_list[index] = copy.deepcopy(pdo_object)
|
||||
self.__io.write_local_spr_source_pdo(self.__write_pdo())
|
||||
|
||||
def save_pdo(self, path: str):
|
||||
"""
|
||||
Save information about PDO's to file.
|
||||
Supported formats:
|
||||
- txt
|
||||
- json
|
||||
|
||||
Args:
|
||||
path (`str`)
|
||||
"""
|
||||
save_pdo(path, self.__pdo_list, True)
|
||||
|
||||
def load_pdo(self, path: str):
|
||||
"""
|
||||
Load information about PDO's from file.
|
||||
Supported formats:
|
||||
- txt
|
||||
- json
|
||||
|
||||
Args:
|
||||
path (`str`)
|
||||
"""
|
||||
self.__pdo_list = load_pdo(path, True)
|
||||
|
||||
def __str__(self) -> str:
|
||||
pdo_status = ""
|
||||
for index, item in enumerate(self.__pdo_list):
|
||||
pdo_status += f"PDO {index}\n{item.pdo_object.__str__()}\n"
|
||||
return f"Power Source\n{pdo_status}\n"
|
||||
104
UniTAP/dev/ports/modules/pdc/pdc_private_dpam_types.py
Normal file
104
UniTAP/dev/ports/modules/pdc/pdc_private_dpam_types.py
Normal file
@@ -0,0 +1,104 @@
|
||||
from ctypes import Structure, c_uint32
|
||||
from enum import IntEnum
|
||||
from .pdc_dpam_types import DISCCapability, DISCDpSignaling, PinAssignmentModes
|
||||
|
||||
|
||||
class DPAMCommand(IntEnum):
|
||||
DoesNothing = 0x00
|
||||
AutoEnterDPAM = 0x01
|
||||
EnterDPAM2lanes = 0x02
|
||||
EnterDPAM4lanes = 0x03
|
||||
ExitDPAM = 0x04
|
||||
DisableDPAM = 0x05
|
||||
ManualDPAM = 0x06
|
||||
DisableDPtoTypeCAdapter = 0x08
|
||||
EnableDPtoTypeCAdapter = 0x09
|
||||
ClearMFPreferredFlag = 0x0E
|
||||
SetMFPreferredFlag = 0x0F
|
||||
ClearAlignDpCUsb = 0x30
|
||||
SetAlignDpCUsb = 0x31
|
||||
ClearAlignDpDUsb = 0x32
|
||||
SetAlignDpDUsb = 0x33
|
||||
ClearAlignDpEUsb = 0x34
|
||||
SetAlignDpEUsb = 0x35
|
||||
EnableDPAM2_1 = 0x38
|
||||
DisableDPAM2_1 = 0x39
|
||||
|
||||
|
||||
class DPAMCaps(Structure):
|
||||
_fields_ = [
|
||||
('', c_uint32, 8),
|
||||
('dfp_assign', c_uint32, 8),
|
||||
('ufp_assign', c_uint32, 8),
|
||||
('', c_uint32, 6),
|
||||
('dpam_version', c_uint32, 2)
|
||||
]
|
||||
|
||||
def value(self) -> int:
|
||||
return self.dfp_assign << 8 | self.dfp_assign << 16 | self.dpam_version << 30
|
||||
|
||||
|
||||
class DPAMState(Structure):
|
||||
_fields_ = [
|
||||
('auto_dpam', c_uint32, 1),
|
||||
('dpam_enable', c_uint32, 1),
|
||||
('adapter_mode', c_uint32, 1),
|
||||
('', c_uint32, 1),
|
||||
('align_dp_c_usb', c_uint32, 1),
|
||||
('align_dp_d_usb', c_uint32, 1),
|
||||
('align_dp_e_usb', c_uint32, 1),
|
||||
('', c_uint32, 25)
|
||||
]
|
||||
|
||||
|
||||
class DPAMConfig(Structure):
|
||||
_fields_ = [
|
||||
('config', c_uint32, 2),
|
||||
('signaling', c_uint32, 4),
|
||||
('', c_uint32, 2),
|
||||
('pin_assign', c_uint32, 8),
|
||||
('', c_uint32, 10),
|
||||
('uhbr_13_5_support', c_uint32, 1),
|
||||
('', c_uint32, 1),
|
||||
('cable_active_component', c_uint32, 2),
|
||||
('dpam_version', c_uint32, 2)
|
||||
]
|
||||
|
||||
|
||||
class DPAMDiscModes(Structure):
|
||||
_fields_ = [
|
||||
('capability', c_uint32, 2),
|
||||
('signaling', c_uint32, 4),
|
||||
('dp_placement', c_uint32, 1),
|
||||
('usb_signaling', c_uint32, 1),
|
||||
('dfp_assign', c_uint32, 8),
|
||||
('ufp_assign', c_uint32, 8),
|
||||
('', c_uint32, 6),
|
||||
('dpam_version', c_uint32, 2)
|
||||
]
|
||||
|
||||
@property
|
||||
def capability(self) -> DISCCapability:
|
||||
return DISCCapability(self.capability)
|
||||
|
||||
@property
|
||||
def signaling(self) -> DISCDpSignaling:
|
||||
return DISCDpSignaling(self.signaling)
|
||||
|
||||
|
||||
class DPAMRecv(Structure):
|
||||
_fields_ = [
|
||||
('connection', c_uint32, 2),
|
||||
('power_low', c_uint32, 1),
|
||||
('enable', c_uint32, 1),
|
||||
('multi_func', c_uint32, 1),
|
||||
('usb_cfg_rq', c_uint32, 1),
|
||||
('exit_rq', c_uint32, 1),
|
||||
('hpd_state', c_uint32, 1),
|
||||
('hpd_irq', c_uint32, 1),
|
||||
('no_dpam_suspend', c_uint32, 1),
|
||||
]
|
||||
|
||||
@property
|
||||
def connection(self) -> DISCCapability:
|
||||
return DISCCapability(self.capability)
|
||||
227
UniTAP/dev/ports/modules/pdc/pdc_private_types.py
Normal file
227
UniTAP/dev/ports/modules/pdc/pdc_private_types.py
Normal file
@@ -0,0 +1,227 @@
|
||||
from ctypes import Structure, c_uint32, c_uint64
|
||||
from enum import IntEnum
|
||||
from .pdc_types import CCPullUp, ContractTypePriority, DRPTryMode, USB3Mode, PdcDeviceRole, PDMode
|
||||
|
||||
|
||||
class HWControlCommand(IntEnum):
|
||||
DoNothing = 0x00
|
||||
ToggleCableFlip = 0x01
|
||||
SetCableFlipToOff = 0x02
|
||||
SetCableFlipToOn = 0x03
|
||||
EnableUSBDeviceCharger = 0x04
|
||||
DisableUSBDeviceCharger = 0x05
|
||||
SwitchToHostMode = 0x06
|
||||
SwitchToDeviceMode = 0x07
|
||||
Enable20PHY = 0x08
|
||||
Disable20PHY = 0x09
|
||||
Enable20PHYDeviceModeEnableCharger = 0x0A
|
||||
Enable20PHYHostModeDisableCharger = 0x0B
|
||||
Disable20PHYDisableCharger = 0x0C
|
||||
DisableIntLoad_5_5_ohm = 0x0E
|
||||
EnableIntLoad_5_5_ohm = 0x0F
|
||||
DisableIntLoad_3_5_ohm = 0x10
|
||||
EnableIntLoad_3_5_ohm = 0x11
|
||||
DisableIntLoad_10_ohm = 0x12
|
||||
EnableIntLoad_10_ohm = 0x13
|
||||
DisconnectCCLines = 0x14
|
||||
ConnectCCLines = 0x15
|
||||
RePlugCable = 0x16
|
||||
SetNewETCableMode = 0x18
|
||||
SetOldETCableMode = 0x19
|
||||
Enable30PHY = 0x1A
|
||||
Disable30PHY = 0x1B
|
||||
ResetPDController = 0x1C
|
||||
|
||||
|
||||
class PDCControlCommand(IntEnum):
|
||||
DoNothing = 0x00
|
||||
ToggleDataRole = 0x01
|
||||
SetDataRoleUFP = 0x02
|
||||
SetDataRoleDFP = 0x03
|
||||
SwapVconn = 0x04
|
||||
TogglePowerRole = 0x05
|
||||
FastRoleSwap = 0x06
|
||||
HardReset = 0x07
|
||||
SimulateReConnect = 0x0A
|
||||
PullCCLineToDefault = 0x0C
|
||||
PullCCLineTo1_5A = 0x0D
|
||||
PullCCLineTo3_0A = 0x0E
|
||||
SetDataRoleDRP = 0x14
|
||||
SetDataRoleDRP_SNK_Support = 0x15
|
||||
SetDataRoleDRP_SRC_Support = 0x16
|
||||
DisableUSB3 = 0x18
|
||||
EnableUSB3_gen1 = 0x19
|
||||
EnableUSB3_gen2 = 0x1A
|
||||
DisableUSB2 = 0x1C
|
||||
EnableUSB2 = 0x1D
|
||||
DisableVconnSwap = 0x1E
|
||||
EnableVconnSwap = 0x1F
|
||||
DisablePRSwap = 0x20
|
||||
EnablePRSwap = 0x21
|
||||
DisableDRSwap = 0x22
|
||||
EnableDRSwap = 0x23
|
||||
DisableDebugAccessorySupport = 0x24
|
||||
EnableDebugAccessorySupport = 0x25
|
||||
DisableAudioAccessorySupport = 0x26
|
||||
EnableAudioAccessorySupport = 0x27
|
||||
DisableFRSwap = 0x28
|
||||
EnableFRSwap = 0x29
|
||||
SetFRSwapNoSupported = 0x2A
|
||||
SetFRSwapUSBPower = 0x2B
|
||||
SetFRSwap1_5A_5V = 0x2C
|
||||
SetFRSwap3A_5V = 0x2C
|
||||
EnableEPRasPowerSink = 0x2E
|
||||
DisableEPRasPowerSink = 0x2F
|
||||
EnableEPRAutoEnter = 0x30
|
||||
DisableEPRAutoEnter = 0x31
|
||||
InitiateEPRModeEnter = 0x32
|
||||
InitiateEPRModeExit = 0x33
|
||||
EnableRejectEPRModeEnter = 0x34
|
||||
DisableRejectEPRModeEnter = 0x35
|
||||
SendSourceCaps = 0x41
|
||||
|
||||
|
||||
class HWCaps(Structure):
|
||||
_fields_ = [
|
||||
('', c_uint32, 1),
|
||||
('et_board', c_uint32, 1),
|
||||
('', c_uint32, 2),
|
||||
('pdo_count', c_uint32, 4),
|
||||
('', c_uint32, 24)
|
||||
]
|
||||
|
||||
|
||||
class HWStatus(Structure):
|
||||
_fields_ = [
|
||||
('cable_flip', c_uint32, 1),
|
||||
('ext_power', c_uint32, 1),
|
||||
('charger', c_uint32, 1),
|
||||
('usb_mode', c_uint32, 1),
|
||||
('usb_20_phy', c_uint32, 1),
|
||||
('et_cable', c_uint32, 1),
|
||||
('int_3_5_ohm', c_uint32, 1),
|
||||
('int_10_ohm', c_uint32, 1),
|
||||
('cc1_closed', c_uint32, 1),
|
||||
('cc2_closed', c_uint32, 1),
|
||||
('int_5_5_ohm', c_uint32, 1),
|
||||
('et_cable_mode', c_uint32, 1),
|
||||
('usb_30_phy', c_uint32, 1),
|
||||
('int_3_5_ovp', c_uint32, 1),
|
||||
('int_10_ovp', c_uint32, 1),
|
||||
('int_5_5_ovp', c_uint32, 1),
|
||||
('', c_uint32, 13),
|
||||
('pdc_fault', c_uint32, 1),
|
||||
('', c_uint32, 1),
|
||||
('pdc_reset', c_uint32, 1)
|
||||
]
|
||||
|
||||
|
||||
class PDCStatus(Structure):
|
||||
_fields_ = [
|
||||
('cable_plug', c_uint64, 1),
|
||||
('cable_orientation', c_uint64, 1),
|
||||
('power_role', c_uint64, 1),
|
||||
('data_role', c_uint64, 1),
|
||||
('rmt_snk_pdo', c_uint64, 1),
|
||||
('rmt_src_pdo', c_uint64, 1),
|
||||
('pwr_contract', c_uint64, 1),
|
||||
('rmt_svid', c_uint64, 1),
|
||||
('vconn_enabled', c_uint64, 1),
|
||||
('emarked_cable', c_uint64, 1),
|
||||
('dp_alt_mode', c_uint64, 1),
|
||||
('usb_device', c_uint64, 1),
|
||||
('usb_host', c_uint64, 1),
|
||||
('usb_2_conn', c_uint64, 1),
|
||||
('usb_3_conn', c_uint64, 1),
|
||||
('sop_identity', c_uint64, 1),
|
||||
('current', c_uint64, 2),
|
||||
('adc_data', c_uint64, 1),
|
||||
('am_sw_inprog', c_uint64, 1),
|
||||
('pullup_sence', c_uint64, 2),
|
||||
('rx_identity', c_uint64, 1),
|
||||
('', c_uint64, 6),
|
||||
('pdc_fault', c_uint64, 1),
|
||||
('', c_uint64, 2),
|
||||
('rx_sink_pdp', c_uint64, 1),
|
||||
('rx_source_pdp', c_uint64, 1),
|
||||
('rx_snk_epr_pdo', c_uint64, 1),
|
||||
('rx_src_epr_pdo', c_uint64, 1),
|
||||
('', c_uint64, 28)
|
||||
]
|
||||
|
||||
|
||||
class PDCState(Structure):
|
||||
_fields_ = [
|
||||
('cc_pull_up', c_uint32, 2),
|
||||
('dev_role', c_uint32, 2),
|
||||
('pd_mode', c_uint32, 2),
|
||||
('usb30_mode', c_uint32, 2),
|
||||
('usb2_enabled', c_uint32, 1),
|
||||
('vconn_swap_en', c_uint32, 1),
|
||||
('pr_swap_en', c_uint32, 1),
|
||||
('dr_swap_en', c_uint32, 1),
|
||||
('dbg_accessory', c_uint32, 1),
|
||||
('aud_accessory', c_uint32, 1),
|
||||
('fr_swap_en', c_uint32, 1),
|
||||
('', c_uint32, 1),
|
||||
('drp_try_mode', c_uint32, 2),
|
||||
('', c_uint32, 2),
|
||||
('epr_snk_en', c_uint32, 1),
|
||||
('epr_auto_enter_en', c_uint32, 1),
|
||||
('epr_mode', c_uint32, 1),
|
||||
('epr_enter_en', c_uint32, 1),
|
||||
]
|
||||
|
||||
@property
|
||||
def cc_pull_up(self) -> CCPullUp:
|
||||
return CCPullUp(self.cc_pull_up)
|
||||
|
||||
@property
|
||||
def dev_role(self) -> PdcDeviceRole:
|
||||
return PdcDeviceRole(self.dev_role)
|
||||
|
||||
@property
|
||||
def pd_mode(self) -> PDMode:
|
||||
return PDMode(self.pd_mode)
|
||||
|
||||
@property
|
||||
def usb30_mode(self) -> USB3Mode:
|
||||
return USB3Mode(self.usb30_mode)
|
||||
|
||||
@property
|
||||
def drp_try_mode(self) -> DRPTryMode:
|
||||
return DRPTryMode(self.drp_try_mode)
|
||||
|
||||
|
||||
class PDCCaps(Structure):
|
||||
_fields_ = [
|
||||
('try_snk', c_uint32, 1),
|
||||
('try_src', c_uint32, 1),
|
||||
('fr_swap', c_uint32, 1),
|
||||
('cable_sim', c_uint32, 1),
|
||||
('ext_sink_pc', c_uint32, 1),
|
||||
('align_dp_usb', c_uint32, 1),
|
||||
('', c_uint32, 16)
|
||||
]
|
||||
|
||||
|
||||
class PDCContractInfo(Structure):
|
||||
_fields_ = [
|
||||
('auto_negotate', c_uint32, 1),
|
||||
('use_battery_pdo', c_uint32, 1),
|
||||
('use_variable_pdo', c_uint32, 1),
|
||||
('comm_capable', c_uint32, 1),
|
||||
('type_priority', c_uint32, 2),
|
||||
('no_usb_suspend', c_uint32, 1),
|
||||
('give_back_flag', c_uint32, 1),
|
||||
('auto_min_power', c_uint32, 1),
|
||||
('', c_uint32, 6),
|
||||
('min_power', c_uint32, 10),
|
||||
('', c_uint32, 5),
|
||||
('manual', c_uint32, 1),
|
||||
]
|
||||
|
||||
def value(self) -> int:
|
||||
return self.auto_negotate | self.use_battery_pdo << 1 | self.use_variable_pdo << 2 | self.comm_capable << 3 | \
|
||||
self.type_priority << 4 | self.no_usb_suspend << 6 | self.give_back_flag << 7 | \
|
||||
self.auto_min_power << 8 | self.min_power << 15 | self.manual << 31
|
||||
125
UniTAP/dev/ports/modules/pdc/pdc_types.py
Normal file
125
UniTAP/dev/ports/modules/pdc/pdc_types.py
Normal file
@@ -0,0 +1,125 @@
|
||||
from enum import IntEnum
|
||||
|
||||
|
||||
class CCPullUp(IntEnum):
|
||||
"""
|
||||
Class `CCPullUp` contains all possible variants of CC Pull Up.
|
||||
"""
|
||||
Current_05_09A = 0
|
||||
Current_1_5A = 1
|
||||
Current_3A = 2
|
||||
Unknown = 3
|
||||
|
||||
|
||||
class PowerRole(IntEnum):
|
||||
"""
|
||||
Class `PowerRole` contains all possible variants of device power role.
|
||||
"""
|
||||
Source = 0
|
||||
Sink = 1
|
||||
|
||||
|
||||
class FrSwapCurrent(IntEnum):
|
||||
"""
|
||||
Class `FrSwapCurrent` contains all possible variants of FR Swap current.
|
||||
"""
|
||||
Disable = 0
|
||||
EnableDefaultUSBPower = 1
|
||||
Enable_1_5A_5V = 2
|
||||
Enable_3A_5V = 3
|
||||
|
||||
|
||||
class PdcDeviceRole(IntEnum):
|
||||
"""
|
||||
Class `PdcDeviceRole` contains all possible variants of PDC device role.
|
||||
"""
|
||||
UFP = 0
|
||||
DFP = 1
|
||||
DRP = 2
|
||||
Unknown = 3
|
||||
|
||||
|
||||
class PDMode(IntEnum):
|
||||
"""
|
||||
Class `PDMode` contains all possible variants of PD modes.
|
||||
"""
|
||||
NormalPD = 0
|
||||
LegacyUSBSource = 1
|
||||
LegacyUSBSink = 2
|
||||
Unknown = 3
|
||||
|
||||
|
||||
class USB3Mode(IntEnum):
|
||||
"""
|
||||
Class `USB3Mode` contains all possible variants of USB-3 modes.
|
||||
"""
|
||||
Disabled = 0
|
||||
EnabledGen1 = 1
|
||||
EnabledGen2 = 2
|
||||
Unknown = 3
|
||||
|
||||
|
||||
class DRPTryMode(IntEnum):
|
||||
"""
|
||||
Class `DRPTryMode` contains all possible variants of DRP behavior modes.
|
||||
"""
|
||||
PureDRP = 0
|
||||
DRP_try_SNK = 1
|
||||
DRP_try_SRC = 2
|
||||
Unknown = 3
|
||||
|
||||
|
||||
class CableControlOrientation(IntEnum):
|
||||
"""
|
||||
Class `CableControlOrientation` contains all possible variants of orientation.
|
||||
"""
|
||||
CC1 = 0
|
||||
CC2 = 1
|
||||
|
||||
|
||||
class DifferentialPair(IntEnum):
|
||||
"""
|
||||
Class `DifferentialPair` contains all possible variants of differential pairs.
|
||||
"""
|
||||
OnePair = 0
|
||||
TwoPair = 1
|
||||
|
||||
|
||||
class ContractTypePriority(IntEnum):
|
||||
"""
|
||||
Class `ContractTypePriority` contains all possible variants of contract type priority.
|
||||
"""
|
||||
HigherCurrent = 0
|
||||
HigherVoltage = 1
|
||||
HigherPower = 2
|
||||
Unknown = 3
|
||||
|
||||
|
||||
class InternalResistance(IntEnum):
|
||||
"""
|
||||
Class `InternalResistance` contains all possible variants of internal resistance.
|
||||
"""
|
||||
Disable = 1
|
||||
Resistance_10_Ohm = 40001
|
||||
Resistance_5_5_Ohm = 22001
|
||||
Resistance_3_55_Ohm = 14161
|
||||
Resistance_3_5_Ohm = 14001
|
||||
Resistance_2_6_Ohm = 10361
|
||||
Resistance_2_14_Ohm = 8521
|
||||
Resistance_1_76_Ohm = 7001
|
||||
|
||||
|
||||
class ExternalResistance(IntEnum):
|
||||
"""
|
||||
Class `ExternalResistance` contains all possible variants of external resistance.
|
||||
"""
|
||||
Disable = 3
|
||||
Resistance_13_9_Ohm = 55603
|
||||
Resistance_10_6_Ohm = 42403
|
||||
Resistance_9_1_Ohm = 36403
|
||||
Resistance_7_6_Ohm = 30403
|
||||
Resistance_6_6_Ohm = 26403
|
||||
Resistance_5_6_Ohm = 22403
|
||||
Resistance_4_6_Ohm = 18403
|
||||
Resistance_3_6_Ohm = 14403
|
||||
Resistance_1_8_Ohm = 7203
|
||||
72
UniTAP/dev/ports/modules/pdc/pdc_utils.py
Normal file
72
UniTAP/dev/ports/modules/pdc/pdc_utils.py
Normal file
@@ -0,0 +1,72 @@
|
||||
import warnings
|
||||
import os
|
||||
import json
|
||||
|
||||
from UniTAP.dev.ports.modules.pdc.pdo import Pdo
|
||||
from UniTAP.dev.ports.modules.pdc.pdo_utils import get_pdo_value
|
||||
from UniTAP.dev.ports.modules.pdc.pdo_types import *
|
||||
from UniTAP.dev.ports.modules.pdc.pdo_private_types import PdoUnion
|
||||
|
||||
|
||||
def support_or_not(value) -> str:
|
||||
return "Yes" if bool(value) else "No"
|
||||
|
||||
|
||||
def save_pdo(path: str, pdo_list: list, source: bool):
|
||||
filename, file_extension = os.path.splitext(path)
|
||||
if file_extension.find('.txt') != -1:
|
||||
file = open(path, 'w')
|
||||
file.write("TSI_USBC_PWR_LOCAL_SOURCE_PDO\n" if source else "TSI_USBC_PWR_LOCAL_SINK_PDO\n")
|
||||
file.write("1\n")
|
||||
file.write(str(len(pdo_list) * 4))
|
||||
for pdo in pdo_list:
|
||||
file.write(str(get_pdo_value(pdo.get_pdo_object())))
|
||||
file.close()
|
||||
elif file_extension.find('.json') != -1:
|
||||
values = {}
|
||||
for index, pdo in enumerate(pdo_list):
|
||||
values.update({f"EPR{index}": get_pdo_value(pdo.get_pdo_object())})
|
||||
with open(path, "w") as outfile:
|
||||
json.dump(values, outfile)
|
||||
else:
|
||||
warnings.warn(f"Unsupported file format: {file_extension}. "
|
||||
f"Please, select file format from available variants: 'txt', 'json'")
|
||||
|
||||
|
||||
def load_pdo(path: str, source: bool) -> list:
|
||||
if os.path.exists(path):
|
||||
raise ValueError(f"Incorrect path {path} to file. Path does not exist.")
|
||||
filename, file_extension = os.path.splitext(path)
|
||||
pdo_list = []
|
||||
if file_extension.find('.txt') != -1:
|
||||
file = open(path, 'r')
|
||||
data = file.read().split("\n")
|
||||
for index, line in enumerate(data):
|
||||
if index >= 3:
|
||||
fill_list(int(line), pdo_list, source)
|
||||
file.close()
|
||||
elif file_extension.find('.json') != -1:
|
||||
with open(path, "r", encoding='utf-8') as read_file:
|
||||
data = json.load(read_file)
|
||||
keys = list(data.keys())
|
||||
for index, key in enumerate(keys):
|
||||
fill_list(int(data.get(key)), pdo_list, source)
|
||||
else:
|
||||
raise ValueError(f"Unsupported file format: {file_extension}. "
|
||||
f"Please, select file format from available variants: 'txt', 'json'")
|
||||
return pdo_list
|
||||
|
||||
|
||||
def fill_list(data, pdo_list, source):
|
||||
pdo_data = PdoUnion(data)
|
||||
pdo_type = PdoTypeEnum(pdo_data.brief_info.pdo_type)
|
||||
if pdo_type == PdoTypeEnum.Fixed:
|
||||
pdo_list.append(Pdo(pdo=FixedPdoSource(pdo_data.fixed_pdo_source) if source else
|
||||
FixedPdoSink(pdo_data.fixed_pdo_sink),
|
||||
side=PdoSide.Source if source else PdoSide.Sink))
|
||||
elif pdo_type == PdoTypeEnum.Battery:
|
||||
pdo_list.append(Pdo(pdo=BatteryPdo(pdo_data.battery_pdo),
|
||||
side=PdoSide.Source if source else PdoSide.Sink))
|
||||
elif pdo_type == PdoTypeEnum.Variable:
|
||||
pdo_list.append(Pdo(pdo=VariablePdo(pdo_data.variable_pdo),
|
||||
side=PdoSide.Source if source else PdoSide.Sink))
|
||||
99
UniTAP/dev/ports/modules/pdc/pdo.py
Normal file
99
UniTAP/dev/ports/modules/pdc/pdo.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from typing import Type
|
||||
|
||||
from UniTAP.dev.ports.modules.pdc.pdo_utils import interpret_pdo_value
|
||||
from UniTAP.dev.ports.modules.pdc.pdo_types import PdoSide, PdoType, FixedPdoSink, FixedPdoSource, BatteryPdo, \
|
||||
VariablePdo, PdoTypeEnum
|
||||
|
||||
|
||||
class Pdo:
|
||||
|
||||
"""
|
||||
Class `Pdo` describes power delivery object in PDC module. Contains information about side of PDO `PdoSide` and
|
||||
main PDO data. May have one of the available type `PdoType`: `FixedPdoSink`, `FixedPdoSource`, `BatteryPdo`,
|
||||
`VariablePdo`.
|
||||
- Get PDO type `pdo_type`, type of `PdoTypeEnum`.
|
||||
- Get PDO side `pdo_side`, type of `PdoSide`.
|
||||
- Set and get main PDO object `pdo_object`, type of `PdoType`.
|
||||
- Get pdo object as selected PDO type `PdoType` `get_pdo_as_selected_type`, type of `PdoType`.
|
||||
- Convert (interpret) from one PDO type to another `interpret_pdo_as_selected_type`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdo: PdoType, side: PdoSide):
|
||||
self.__pdo = pdo
|
||||
self.__side = side
|
||||
|
||||
@property
|
||||
def pdo_type(self) -> PdoTypeEnum:
|
||||
"""
|
||||
Returns current PDO type.
|
||||
|
||||
Returns:
|
||||
object of `PdoTypeEnum` type
|
||||
"""
|
||||
return self.__pdo.pdo_type
|
||||
|
||||
@property
|
||||
def pdo_side(self) -> PdoSide:
|
||||
"""
|
||||
Returns current PDO side.
|
||||
|
||||
Returns:
|
||||
object of `PdoSide` type
|
||||
"""
|
||||
return self.__side
|
||||
|
||||
@property
|
||||
def pdo_object(self) -> PdoType:
|
||||
"""
|
||||
Returns current PDO object.
|
||||
|
||||
Returns:
|
||||
object of `PdoType` type
|
||||
"""
|
||||
return self.__pdo
|
||||
|
||||
@pdo_object.setter
|
||||
def pdo_object(self, pdo: PdoType):
|
||||
self.__pdo = pdo
|
||||
|
||||
def disable_pdo(self):
|
||||
"""
|
||||
Disable PDO. Will be filled with zeros.
|
||||
"""
|
||||
self.__pdo = FixedPdoSink(disable=True) if self.__side == PdoSide.Sink else FixedPdoSource(disable=True)
|
||||
|
||||
def get_pdo_as_selected_type(self, pdo: Type[PdoType]) -> PdoType:
|
||||
"""
|
||||
Returns PDO object as selected new PDO type.
|
||||
|
||||
Args:
|
||||
pdo (`PdoType`) - type of PDO
|
||||
|
||||
Returns:
|
||||
object of `PdoType` type
|
||||
"""
|
||||
self.interpret_pdo_as_selected_type(pdo)
|
||||
return self.__pdo
|
||||
|
||||
def interpret_pdo_as_selected_type(self, pdo: Type[PdoType]):
|
||||
"""
|
||||
Convert (interpret) from one PDO type to another.
|
||||
|
||||
Args:
|
||||
pdo (`PdoType`) - type of PDO
|
||||
"""
|
||||
if pdo == FixedPdoSink and self.__side == PdoSide.Sink:
|
||||
self.__pdo = FixedPdoSink(interpret_pdo_value(self.__pdo, pdo))
|
||||
elif pdo == FixedPdoSource and self.__side == PdoSide.Source:
|
||||
self.__pdo = FixedPdoSource(interpret_pdo_value(self.__pdo, pdo))
|
||||
elif pdo == BatteryPdo:
|
||||
self.__pdo = BatteryPdo(interpret_pdo_value(self.__pdo, pdo))
|
||||
elif pdo == VariablePdo:
|
||||
self.__pdo = VariablePdo(interpret_pdo_value(self.__pdo, pdo))
|
||||
else:
|
||||
raise ValueError(f"Incorrect PDO type: {pdo}. Available types: BatteryPdo, VariablePdo, "
|
||||
f"{'FixedPdoSink' if self.__side == PdoSide.Sink else 'FixedPdoSource'}")
|
||||
|
||||
def __str__(self):
|
||||
return f'PDO type: {self.pdo_type.name}\n' \
|
||||
f'{self.__pdo.__str__()}'
|
||||
74
UniTAP/dev/ports/modules/pdc/pdo_private_types.py
Normal file
74
UniTAP/dev/ports/modules/pdc/pdo_private_types.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from typing import TypeVar
|
||||
from ctypes import Structure, Union, c_uint32
|
||||
|
||||
|
||||
class FixedPdoSourceStruct(Structure):
|
||||
_fields_ = [
|
||||
('max_current', c_uint32, 10),
|
||||
('voltage', c_uint32, 10),
|
||||
('peak_current', c_uint32, 2),
|
||||
('', c_uint32, 3),
|
||||
('dual_data_role', c_uint32, 1),
|
||||
('usb_communication_capable', c_uint32, 1),
|
||||
('externally_powered', c_uint32, 1),
|
||||
('usb_suspend_supported', c_uint32, 1),
|
||||
('dual_power_role_capable', c_uint32, 1),
|
||||
('pdo_type', c_uint32, 2),
|
||||
]
|
||||
|
||||
|
||||
class FixedPdoSinkStruct(Structure):
|
||||
_fields_ = [
|
||||
('oper_current', c_uint32, 10),
|
||||
('voltage', c_uint32, 10),
|
||||
('', c_uint32, 5),
|
||||
('dual_data_role', c_uint32, 1),
|
||||
('usb_communication_capable', c_uint32, 1),
|
||||
('externally_powered', c_uint32, 1),
|
||||
('usb_suspend_supported', c_uint32, 1),
|
||||
('dual_power_role_capable', c_uint32, 1),
|
||||
('pdo_type', c_uint32, 2),
|
||||
]
|
||||
|
||||
|
||||
class VariablePdoStruct(Structure):
|
||||
_fields_ = [
|
||||
('max_current', c_uint32, 10),
|
||||
('min_voltage', c_uint32, 10),
|
||||
('max_voltage', c_uint32, 10),
|
||||
('pdo_type', c_uint32, 2),
|
||||
]
|
||||
|
||||
|
||||
class BatteryPdoStruct(Structure):
|
||||
_fields_ = [
|
||||
('max_power', c_uint32, 10),
|
||||
('min_voltage', c_uint32, 10),
|
||||
('max_voltage', c_uint32, 10),
|
||||
('pdo_type', c_uint32, 2),
|
||||
]
|
||||
|
||||
|
||||
class PdoBriefInfo(Structure):
|
||||
_fields_ = [
|
||||
('data', c_uint32, 30),
|
||||
('pdo_type', c_uint32, 2)
|
||||
]
|
||||
|
||||
|
||||
class PdoUnion(Union):
|
||||
_fields_ = [
|
||||
('data', c_uint32),
|
||||
('brief_info', PdoBriefInfo),
|
||||
('fixed_pdo_source', FixedPdoSourceStruct),
|
||||
('fixed_pdo_sink', FixedPdoSinkStruct),
|
||||
('variable_pdo', VariablePdoStruct),
|
||||
('battery_pdo', BatteryPdoStruct)
|
||||
]
|
||||
|
||||
|
||||
PdoTypeStruct = TypeVar("PdoTypeStruct",
|
||||
FixedPdoSinkStruct,
|
||||
FixedPdoSourceStruct,
|
||||
BatteryPdoStruct,
|
||||
VariablePdoStruct)
|
||||
488
UniTAP/dev/ports/modules/pdc/pdo_types.py
Normal file
488
UniTAP/dev/ports/modules/pdc/pdo_types.py
Normal file
@@ -0,0 +1,488 @@
|
||||
from enum import IntEnum
|
||||
from typing import TypeVar
|
||||
from .pdo_private_types import FixedPdoSourceStruct, FixedPdoSinkStruct, BatteryPdoStruct, VariablePdoStruct
|
||||
|
||||
|
||||
class PdoTypeEnum(IntEnum):
|
||||
"""
|
||||
Class `PdoTypeEnum` contains all possible variants of PDO types.
|
||||
"""
|
||||
Fixed = 0
|
||||
Battery = 1
|
||||
Variable = 2
|
||||
Disabled = 3
|
||||
Mandatory = 4
|
||||
|
||||
|
||||
class PdoSide(IntEnum):
|
||||
"""
|
||||
Class `PdoTypeEnum` contains all possible variants of PDO side.
|
||||
"""
|
||||
Sink = 0
|
||||
Source = 1
|
||||
|
||||
|
||||
class PeakCurrent(IntEnum):
|
||||
"""
|
||||
Class `PdoTypeEnum` contains all possible variants of peak current for PDO.
|
||||
"""
|
||||
Percent_100 = 0
|
||||
Percent_110 = 1
|
||||
Percent_125 = 2
|
||||
Percent_150 = 3
|
||||
|
||||
|
||||
class FixedPdoSource:
|
||||
|
||||
"""
|
||||
Class `FixedPdoSource` contains information about Fixed PDO on Source side.
|
||||
- Set and get maximum current `max_current`, type `int`.
|
||||
- Set and get voltage `voltage`, type `int`.
|
||||
- Set and get peak_current `peak_current`, type `PeakCurrent`.
|
||||
- Set and get dual data role flag `dual_data_role`, type `bool`.
|
||||
- Set and get usb communication flag `usb_communication`, type `bool`.
|
||||
- Set and get unconstrained power flag `unconstrained_power`, type `bool`.
|
||||
- Set and get higher capability flag `higher_capability`, type `bool`.
|
||||
- Set and get dual power role flag `dual_power_role`, type `bool`.
|
||||
- Get PDO type `pdo_type`, type `PdoTypeEnum`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdo: FixedPdoSourceStruct = FixedPdoSourceStruct(0), disable=False):
|
||||
self.__max_current = pdo.max_current * 10
|
||||
self.__voltage = pdo.voltage * 50
|
||||
self.__peak_current = PeakCurrent(pdo.peak_current)
|
||||
self.__dual_data_role = pdo.dual_data_role
|
||||
self.__usb_communication = pdo.usb_communication_capable
|
||||
self.__unconstrained_power = pdo.externally_powered
|
||||
self.__higher_capability = pdo.usb_suspend_supported
|
||||
self.__dual_power_role = pdo.dual_power_role_capable
|
||||
self.__type = PdoTypeEnum.Disabled if disable else PdoTypeEnum.Fixed
|
||||
|
||||
@property
|
||||
def max_current(self) -> int:
|
||||
"""
|
||||
Returns maximum current.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__max_current
|
||||
|
||||
@max_current.setter
|
||||
def max_current(self, max_current: int):
|
||||
self.__max_current = max_current
|
||||
|
||||
@property
|
||||
def voltage(self) -> int:
|
||||
"""
|
||||
Returns voltage.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__voltage
|
||||
|
||||
@voltage.setter
|
||||
def voltage(self, voltage: int):
|
||||
self.__voltage = voltage
|
||||
|
||||
@property
|
||||
def peak_current(self) -> PeakCurrent:
|
||||
"""
|
||||
Returns peak current.
|
||||
|
||||
Returns:
|
||||
object of `PeakCurrent` type
|
||||
"""
|
||||
return self.__peak_current
|
||||
|
||||
@peak_current.setter
|
||||
def peak_current(self, peak_current: PeakCurrent):
|
||||
self.__peak_current = peak_current
|
||||
|
||||
@property
|
||||
def dual_data_role(self) -> bool:
|
||||
"""
|
||||
Returns flag of dual data role.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__dual_data_role)
|
||||
|
||||
@dual_data_role.setter
|
||||
def dual_data_role(self, dual_data_role: bool):
|
||||
self.__dual_data_role = dual_data_role
|
||||
|
||||
@property
|
||||
def usb_communication(self) -> bool:
|
||||
"""
|
||||
Returns flag of usb communication.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__usb_communication)
|
||||
|
||||
@usb_communication.setter
|
||||
def usb_communication(self, usb_communication: bool):
|
||||
self.__usb_communication = usb_communication
|
||||
|
||||
@property
|
||||
def unconstrained_power(self) -> bool:
|
||||
"""
|
||||
Returns flag of unconstrained power.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__unconstrained_power)
|
||||
|
||||
@unconstrained_power.setter
|
||||
def unconstrained_power(self, unconstrained_power: bool):
|
||||
self.__unconstrained_power = unconstrained_power
|
||||
|
||||
@property
|
||||
def higher_capability(self) -> bool:
|
||||
"""
|
||||
Returns flag of higher capability.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__higher_capability)
|
||||
|
||||
@higher_capability.setter
|
||||
def higher_capability(self, higher_capability: bool):
|
||||
self.__higher_capability = higher_capability
|
||||
|
||||
@property
|
||||
def dual_power_role(self) -> bool:
|
||||
"""
|
||||
Returns flag of dual power role.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__dual_power_role)
|
||||
|
||||
@dual_power_role.setter
|
||||
def dual_power_role(self, dual_power_role: bool):
|
||||
self.__dual_power_role = dual_power_role
|
||||
|
||||
@property
|
||||
def pdo_type(self) -> PdoTypeEnum:
|
||||
"""
|
||||
Returns flag of PDO type.
|
||||
|
||||
Returns:
|
||||
object of `PdoTypeEnum` type
|
||||
"""
|
||||
return self.__type
|
||||
|
||||
def __str__(self):
|
||||
return f"Max Current: {self.__max_current}\n" \
|
||||
f"Voltage: {self.__voltage}\n" \
|
||||
f"Peak Current: {self.__peak_current.name}\n" \
|
||||
f"Dual Role: {'Yes' if self.__dual_data_role else 'No'}\n" \
|
||||
f"USB Communication: {'Yes' if self.__usb_communication else 'No'}\n" \
|
||||
f"Unconstrained Power: {'Yes' if self.__unconstrained_power else 'No'}\n" \
|
||||
f"Higher capability: {'Yes' if self.__higher_capability else 'No'}\n" \
|
||||
f"Dual Power role: {'Yes' if self.__dual_power_role else 'No'}\n"
|
||||
|
||||
|
||||
class VariablePdo:
|
||||
|
||||
"""
|
||||
Class `VariablePdo` contains information about Fixed PDO on Sink and Source side.
|
||||
- Set and get maximum current `max_current`, type `int`.
|
||||
- Set and get minimum voltage `min_voltage`, type `int`.
|
||||
- Set and get maximum voltage `max_voltage`, type `bool`.
|
||||
- Get PDO type `pdo_type`, type `PdoTypeEnum`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdo: VariablePdoStruct = VariablePdoStruct(0)):
|
||||
self.__max_current = pdo.max_current * 10
|
||||
self.__min_voltage = pdo.min_voltage * 50
|
||||
self.__max_voltage = pdo.max_voltage * 50
|
||||
self.__type = PdoTypeEnum.Variable
|
||||
|
||||
@property
|
||||
def max_current(self) -> int:
|
||||
"""
|
||||
Returns maximum current.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__max_current
|
||||
|
||||
@max_current.setter
|
||||
def max_current(self, max_current: int):
|
||||
self.__max_current = max_current
|
||||
|
||||
@property
|
||||
def min_voltage(self) -> int:
|
||||
"""
|
||||
Returns minimum voltage.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__min_voltage
|
||||
|
||||
@min_voltage.setter
|
||||
def min_voltage(self, min_voltage: int):
|
||||
self.__min_voltage = min_voltage
|
||||
|
||||
@property
|
||||
def max_voltage(self) -> int:
|
||||
"""
|
||||
Returns maximum voltage.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__max_voltage
|
||||
|
||||
@max_voltage.setter
|
||||
def max_voltage(self, max_voltage: int):
|
||||
self.__max_voltage = max_voltage
|
||||
|
||||
@property
|
||||
def pdo_type(self) -> PdoTypeEnum:
|
||||
"""
|
||||
Returns flag of PDO type.
|
||||
|
||||
Returns:
|
||||
object of `PdoTypeEnum` type
|
||||
"""
|
||||
return self.__type
|
||||
|
||||
def __str__(self):
|
||||
return f"Max Current: {self.__max_current}\n" \
|
||||
f"Min Voltage: {self.__min_voltage}\n" \
|
||||
f"Max Voltage: {self.__max_voltage}"
|
||||
|
||||
|
||||
class BatteryPdo:
|
||||
|
||||
"""
|
||||
Class `BatteryPdo` contains information about Fixed PDO on Sink and Source side.
|
||||
- Set and get maximum power `max_power`, type `int`.
|
||||
- Set and get minimum voltage `min_voltage`, type `int`.
|
||||
- Set and get maximum voltage `max_voltage`, type `bool`.
|
||||
- Get PDO type `pdo_type`, type `PdoTypeEnum`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdo: BatteryPdoStruct = BatteryPdoStruct(0)):
|
||||
self.__max_power = pdo.max_power * 250
|
||||
self.__min_voltage = pdo.min_voltage * 50
|
||||
self.__max_voltage = pdo.max_voltage * 50
|
||||
self.__type = PdoTypeEnum.Battery
|
||||
|
||||
@property
|
||||
def max_power(self) -> int:
|
||||
"""
|
||||
Returns maximum power.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__max_power
|
||||
|
||||
@max_power.setter
|
||||
def max_power(self, max_power: int):
|
||||
self.__max_power = max_power
|
||||
|
||||
@property
|
||||
def min_voltage(self) -> int:
|
||||
"""
|
||||
Returns minimum voltage.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__min_voltage
|
||||
|
||||
@min_voltage.setter
|
||||
def min_voltage(self, min_voltage: int):
|
||||
self.__min_voltage = min_voltage
|
||||
|
||||
@property
|
||||
def max_voltage(self) -> int:
|
||||
"""
|
||||
Returns maximum voltage.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__max_voltage
|
||||
|
||||
@max_voltage.setter
|
||||
def max_voltage(self, max_voltage: int):
|
||||
self.__max_voltage = max_voltage
|
||||
|
||||
@property
|
||||
def pdo_type(self) -> PdoTypeEnum:
|
||||
"""
|
||||
Returns flag of PDO type.
|
||||
|
||||
Returns:
|
||||
object of `PdoTypeEnum` type
|
||||
"""
|
||||
return self.__type
|
||||
|
||||
def __str__(self):
|
||||
return f"Max power: {self.__max_power}\n" \
|
||||
f"Min Voltage: {self.__min_voltage}\n" \
|
||||
f"Max Voltage: {self.__max_voltage}"
|
||||
|
||||
|
||||
class FixedPdoSink:
|
||||
|
||||
"""
|
||||
Class `FixedPdoSink` contains information about Fixed PDO on Sink side.
|
||||
- Set and get maximum current `max_current`, type `int`.
|
||||
- Set and get voltage `voltage`, type `int`.
|
||||
- Set and get dual data role flag `dual_data_role`, type `bool`.
|
||||
- Set and get usb communication flag `usb_communication`, type `bool`.
|
||||
- Set and get unconstrained power flag `unconstrained_power`, type `bool`.
|
||||
- Set and get higher capability flag `higher_capability`, type `bool`.
|
||||
- Set and get dual power role flag `dual_power_role`, type `bool`.
|
||||
- Get PDO type `pdo_type`, type `PdoTypeEnum`.
|
||||
"""
|
||||
|
||||
def __init__(self, pdo: FixedPdoSinkStruct = FixedPdoSinkStruct(0), disable=False):
|
||||
self.__oper_current = pdo.oper_current * 10
|
||||
self.__voltage = pdo.voltage * 50
|
||||
self.__dual_data_role = bool(pdo.dual_data_role)
|
||||
self.__usb_communication = bool(pdo.usb_communication_capable)
|
||||
self.__unconstrained_power = bool(pdo.externally_powered)
|
||||
self.__higher_capability = bool(pdo.usb_suspend_supported)
|
||||
self.__dual_power_role = bool(pdo.dual_power_role_capable)
|
||||
self.__type = PdoTypeEnum.Disabled if disable else PdoTypeEnum.Fixed
|
||||
|
||||
@property
|
||||
def oper_current(self) -> int:
|
||||
"""
|
||||
Returns operation current.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__oper_current
|
||||
|
||||
@oper_current.setter
|
||||
def oper_current(self, oper_current: int):
|
||||
self.__oper_current = oper_current
|
||||
|
||||
@property
|
||||
def voltage(self) -> int:
|
||||
"""
|
||||
Returns voltage.
|
||||
|
||||
Returns:
|
||||
object of `int` type
|
||||
"""
|
||||
return self.__voltage
|
||||
|
||||
@voltage.setter
|
||||
def voltage(self, voltage: int):
|
||||
self.__voltage = voltage
|
||||
|
||||
@property
|
||||
def dual_data_role(self) -> bool:
|
||||
"""
|
||||
Returns flag of dual data role.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__dual_data_role)
|
||||
|
||||
@dual_data_role.setter
|
||||
def dual_data_role(self, dual_data_role: bool):
|
||||
self.__dual_data_role = dual_data_role
|
||||
|
||||
@property
|
||||
def usb_communication(self) -> bool:
|
||||
"""
|
||||
Returns flag of usb communication.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__usb_communication)
|
||||
|
||||
@usb_communication.setter
|
||||
def usb_communication(self, usb_communication: bool):
|
||||
self.__usb_communication = usb_communication
|
||||
|
||||
@property
|
||||
def unconstrained_power(self) -> bool:
|
||||
"""
|
||||
Returns flag of unconstrained power.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__unconstrained_power)
|
||||
|
||||
@unconstrained_power.setter
|
||||
def unconstrained_power(self, unconstrained_power: bool):
|
||||
self.__unconstrained_power = unconstrained_power
|
||||
|
||||
@property
|
||||
def higher_capability(self) -> bool:
|
||||
"""
|
||||
Returns flag of higher capability.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__higher_capability)
|
||||
|
||||
@higher_capability.setter
|
||||
def higher_capability(self, higher_capability: bool):
|
||||
self.__higher_capability = higher_capability
|
||||
|
||||
@property
|
||||
def dual_power_role(self) -> bool:
|
||||
"""
|
||||
Returns flag of dual power role.
|
||||
|
||||
Returns:
|
||||
object of `bool` type
|
||||
"""
|
||||
return bool(self.__dual_power_role)
|
||||
|
||||
@dual_power_role.setter
|
||||
def dual_power_role(self, dual_power_role: bool):
|
||||
self.__dual_power_role = dual_power_role
|
||||
|
||||
@property
|
||||
def pdo_type(self) -> PdoTypeEnum:
|
||||
"""
|
||||
Returns flag of PDO type.
|
||||
|
||||
Returns:
|
||||
object of `PdoTypeEnum` type
|
||||
"""
|
||||
return self.__type
|
||||
|
||||
def __str__(self):
|
||||
return f"Oper Current: {self.__oper_current}\n" \
|
||||
f"Voltage: {self.__voltage}\n" \
|
||||
f"Dual Role: {'Yes' if self.__dual_data_role else 'No'}\n" \
|
||||
f"USB Communication: {'Yes' if self.__usb_communication else 'No'}\n" \
|
||||
f"Unconstrained Power: {'Yes' if self.__unconstrained_power else 'No'}\n" \
|
||||
f"Higher capability: {'Yes' if self.__higher_capability else 'No'}\n" \
|
||||
f"Dual Power role: {'Yes' if self.__dual_power_role else 'No'}\n"
|
||||
|
||||
|
||||
PdoType = TypeVar("PdoType",
|
||||
FixedPdoSink,
|
||||
FixedPdoSource,
|
||||
BatteryPdo,
|
||||
VariablePdo)
|
||||
31
UniTAP/dev/ports/modules/pdc/pdo_utils.py
Normal file
31
UniTAP/dev/ports/modules/pdc/pdo_utils.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from UniTAP.dev.ports.modules.pdc.pdo_private_types import *
|
||||
from UniTAP.dev.ports.modules.pdc.pdo_types import *
|
||||
|
||||
|
||||
def get_pdo_value(pdo: PdoType) -> int:
|
||||
if isinstance(pdo, FixedPdoSink):
|
||||
value = int(pdo.oper_current / 10) | (int(pdo.voltage / 50) << 10) | (pdo.dual_data_role << 25) | (pdo.usb_communication << 26) | \
|
||||
(pdo.unconstrained_power << 27) | (pdo.higher_capability << 28) | (pdo.dual_power_role << 29)
|
||||
return value
|
||||
elif isinstance(pdo, FixedPdoSource):
|
||||
value = int(pdo.max_current / 10) | (int(pdo.voltage / 50) << 10) | (pdo.peak_current.value << 20) | (pdo.dual_data_role << 25) | \
|
||||
(pdo.usb_communication << 26) | (pdo.unconstrained_power << 27) | (pdo.higher_capability << 28) | \
|
||||
pdo.dual_power_role << 29
|
||||
return value
|
||||
elif isinstance(pdo, BatteryPdo):
|
||||
value = int(pdo.max_power / 250) | (int(pdo.min_voltage / 50) << 10) | (int(pdo.max_voltage / 50) << 20) | (1 << 30)
|
||||
return value
|
||||
elif isinstance(pdo, VariablePdo):
|
||||
value = int(pdo.max_current / 10) | (int(pdo.min_voltage / 50) << 10) | (int(pdo.max_voltage / 50) << 20) | (2 << 30)
|
||||
return value
|
||||
|
||||
|
||||
def interpret_pdo_value(old_type: PdoType, new_type: PdoType) -> PdoTypeStruct:
|
||||
if new_type == FixedPdoSink:
|
||||
return PdoUnion(get_pdo_value(old_type)).fixed_pdo_sink
|
||||
elif new_type == FixedPdoSource:
|
||||
return PdoUnion(get_pdo_value(old_type)).fixed_pdo_source
|
||||
elif new_type == BatteryPdo:
|
||||
return PdoUnion(get_pdo_value(old_type)).battery_pdo
|
||||
elif new_type == VariablePdo:
|
||||
return PdoUnion(get_pdo_value(old_type)).variable_pdo
|
||||
Reference in New Issue
Block a user