# ============================================================================= # DISCLAIMER # ----------------------------------------------------------------------------- # This script is provided as-is and is **not** part of any official Acroname # API or SDK. It is for illustrative or utility purposes only. # # There are no guarantees of correctness, compatibility, or ongoing support. # This code may change at any time without notice. # # Use at your own risk. # ============================================================================= class PDMessageHeader: def __init__(self, msgHeaderVal=0): # Initialize with the full 16-bit message header value self.msgHeaderVal = msgHeaderVal @property def messageType(self): # Extract the 5-bit message type (bits 0-4) return self.msgHeaderVal & 0x1F @messageType.setter def messageType(self, value): # Set the 5-bit message type (bits 0-4) self.msgHeaderVal = (self.msgHeaderVal & ~0x1F) | (value & 0x1F) @property def portDataRole(self): # Extract the 1-bit port data role (bit 5) return (self.msgHeaderVal >> 5) & 0x01 @portDataRole.setter def portDataRole(self, value): # Set the 1-bit port data role (bit 5) self.msgHeaderVal = (self.msgHeaderVal & ~(0x01 << 5)) | ((value & 0x01) << 5) @property def specRevision(self): # Extract the 2-bit spec revision (bits 6-7) return (self.msgHeaderVal >> 6) & 0x03 @specRevision.setter def specRevision(self, value): # Set the 2-bit spec revision (bits 6-7) self.msgHeaderVal = (self.msgHeaderVal & ~(0x03 << 6)) | ((value & 0x03) << 6) @property def portPowerRoleOrCablePlug(self): # Extract the 1-bit port power role or cable plug (bit 8) return (self.msgHeaderVal >> 8) & 0x01 @portPowerRoleOrCablePlug.setter def portPowerRoleOrCablePlug(self, value): # Set the 1-bit port power role or cable plug (bit 8) self.msgHeaderVal = (self.msgHeaderVal & ~(0x01 << 8)) | ((value & 0x01) << 8) @property def messageID(self): # Extract the 3-bit message ID (bits 9-11) return (self.msgHeaderVal >> 9) & 0x07 @messageID.setter def messageID(self, value): # Set the 3-bit message ID (bits 9-11) self.msgHeaderVal = (self.msgHeaderVal & ~(0x07 << 9)) | ((value & 0x07) << 9) @property def numOfDataObjs(self): # Extract the 3-bit number of data objects (bits 12-14) return (self.msgHeaderVal >> 12) & 0x07 @numOfDataObjs.setter def numOfDataObjs(self, value): # Set the 3-bit number of data objects (bits 12-14) self.msgHeaderVal = (self.msgHeaderVal & ~(0x07 << 12)) | ((value & 0x07) << 12) @property def extended(self): # Extract the 1-bit extended flag (bit 15) return (self.msgHeaderVal >> 15) & 0x01 @extended.setter def extended(self, value): # Set the 1-bit extended flag (bit 15) self.msgHeaderVal = (self.msgHeaderVal & ~(0x01 << 15)) | ((value & 0x01) << 15) def __repr__(self): return (f"PDMessageHeader(messageType={self.messageType}, portDataRole={self.portDataRole}, " f"specRevision={self.specRevision}, portPowerRoleOrCablePlug={self.portPowerRoleOrCablePlug}, " f"messageID={self.messageID}, numOfDataObjs={self.numOfDataObjs}, extended={self.extended})") class PDExtendedMessageHeader: def __init__(self, extendedMsgHeaderVal=0): # Initialize with the full 16-bit extended message header value self.extendedMsgHeaderVal = extendedMsgHeaderVal @property def dataSize(self): # Extract the 9-bit data size (bits 0-8) return self.extendedMsgHeaderVal & 0x1FF @dataSize.setter def dataSize(self, value): # Set the 9-bit data size (bits 0-8) self.extendedMsgHeaderVal = (self.extendedMsgHeaderVal & ~0x1FF) | (value & 0x1FF) @property def reserved(self): # Extract the 1-bit reserved (bit 9) return (self.extendedMsgHeaderVal >> 9) & 0x01 @reserved.setter def reserved(self, value): # Set the 1-bit reserved (bit 9) self.extendedMsgHeaderVal = (self.extendedMsgHeaderVal & ~(0x01 << 9)) | ((value & 0x01) << 9) @property def requestChunk(self): # Extract the 1-bit request chunk (bit 10) return (self.extendedMsgHeaderVal >> 10) & 0x01 @requestChunk.setter def requestChunk(self, value): # Set the 1-bit request chunk (bit 10) self.extendedMsgHeaderVal = (self.extendedMsgHeaderVal & ~(0x01 << 10)) | ((value & 0x01) << 10) @property def chunkNumber(self): # Extract the 4-bit chunk number (bits 11-14) return (self.extendedMsgHeaderVal >> 11) & 0x0F @chunkNumber.setter def chunkNumber(self, value): # Set the 4-bit chunk number (bits 11-14) self.extendedMsgHeaderVal = (self.extendedMsgHeaderVal & ~(0x0F << 11)) | ((value & 0x0F) << 11) @property def chunked(self): # Extract the 1-bit chunked flag (bit 15) return (self.extendedMsgHeaderVal >> 15) & 0x01 @chunked.setter def chunked(self, value): # Set the 1-bit chunked flag (bit 15) self.extendedMsgHeaderVal = (self.extendedMsgHeaderVal & ~(0x01 << 15)) | ((value & 0x01) << 15) def __repr__(self): return (f"PDExtendedMessageHeader(dataSize={self.dataSize}, reserved={self.reserved}, " f"requestChunk={self.requestChunk}, chunkNumber={self.chunkNumber}, chunked={self.chunked})") class BatteryInfoBitFields: def __init__(self): self._invalidBatteryRef = 0 self._batteryIsPresent = 0 self._batteryChargingStatus = 0 self._reserved = 0 # Getters and setters for the bitfields @property def invalid_battery_ref(self): return self._invalidBatteryRef @invalid_battery_ref.setter def invalid_battery_ref(self, value): if value in [0, 1]: self._invalidBatteryRef = value else: raise ValueError("Invalid Battery Reference must be 0 or 1.") @property def battery_is_present(self): return self._batteryIsPresent @battery_is_present.setter def battery_is_present(self, value): if value in [0, 1]: self._batteryIsPresent = value else: raise ValueError("Battery Is Present must be 0 or 1.") @property def battery_charging_status(self): return self._batteryChargingStatus @battery_charging_status.setter def battery_charging_status(self, value): if 0 <= value <= 3: self._batteryChargingStatus = value else: raise ValueError("Battery Charging Status must be between 0 and 3.") @property def reserved(self): return self._reserved @reserved.setter def reserved(self, value): if 0 <= value <= 15: self._reserved = value else: raise ValueError("Reserved (bitfields) must be between 0 and 15.") class PDBatteryStatusDataObject: def __init__(self): self._reserved = 0 self._batteryInfoBitFields = BatteryInfoBitFields() self._batteryPC = 0 # Getters and setters for the fields @property def reserved(self): return self._reserved @reserved.setter def reserved(self, value): if 0 <= value <= 255: # 8-bit value self._reserved = value else: raise ValueError("Reserved must be between 0 and 255.") @property def battery_info_bit_fields(self): return self._batteryInfoBitFields @property def battery_pc(self): return self._batteryPC @battery_pc.setter def battery_pc(self, value): if 0 <= value <= 65535: # 16-bit value self._batteryPC = value else: raise ValueError("Battery PC must be between 0 and 65535.") def __str__(self): return (f"Reserved (8-bit): {self._reserved}\n" f"Invalid Battery Ref: {self._batteryInfoBitFields.invalid_battery_ref}\n" f"Battery Is Present: {self._batteryInfoBitFields.battery_is_present}\n" f"Battery Charging Status: {self._batteryInfoBitFields.battery_charging_status}\n" f"Reserved (bitfields, 4-bit): {self._batteryInfoBitFields.reserved}\n" f"Battery PC: {self._batteryPC}") # Function to decode rule into PDBatteryStatusDataObject def rule_to_battery_status_data_object(rule): bsdo_rule = PDBatteryStatusDataObject() # Decode the 8-bit reserved field bsdo_rule.reserved = (rule >> 0) & 0xFF # Decode the bitfields from the byte at bit 8 bsdo_rule.battery_info_bit_fields.invalid_battery_ref = (rule >> 8) & 0x1 bsdo_rule.battery_info_bit_fields.battery_is_present = (rule >> 9) & 0x1 bsdo_rule.battery_info_bit_fields.battery_charging_status = (rule >> 10) & 0x3 bsdo_rule.battery_info_bit_fields.reserved = (rule >> 12) & 0xF # Decode the 16-bit batteryPC field bsdo_rule.battery_pc = (rule >> 16) & 0xFFFF return bsdo_rule