def from_bytes(source_bytes: bytes): data = bytearray(source_bytes) tag = data.pop(0) if tag != GetResponseFactory.TAG: raise ValueError( f"Tag is not correct. Should be {GetResponseFactory.TAG} but is {tag}" ) response_type = enums.GetResponseType(data.pop(0)) invoke_id_and_priority = InvokeIdAndPriority.from_bytes( data.pop(0).to_bytes(1, "big")) if response_type == enums.GetResponseType.NORMAL: # check if it is an error or data response by assesing the choice. choice = data.pop(0) if choice == 0: return GetResponseNormal( invoke_id_and_priority=invoke_id_and_priority, data=bytes(data)) elif choice == 1: assert len(data) == 1 # should only be one byte left. error = enums.DataAccessResult(data.pop(0)) return GetResponseNormalWithError( invoke_id_and_priority=invoke_id_and_priority, error=error) elif response_type == enums.GetResponseType.WITH_BLOCK: last_block = bool(data.pop(0)) block_number = int.from_bytes(data[:4], "big") data = data[4:] choice = data.pop(0) if choice == 0: data_length, data = dlms_cosem.dlms_data.decode_variable_integer( data) if data_length != len(data): raise ValueError( "The octet string in block data is not of the correct length" ) if last_block: return GetResponseLastBlock(bytes(data), block_number, invoke_id_and_priority) else: return GetResponseWithBlock(bytes(data), block_number, invoke_id_and_priority) elif choice == 1: assert len(data) == 1 # should only be one byte left. error = enums.DataAccessResult(data.pop(0)) if last_block: return GetResponseLastBlockWithError( error, block_number, invoke_id_and_priority) else: raise ValueError( "It is not possible to send an error on a " "GetResponseWithBlock. When an error occurs it " "should always be sent in a GetResponseLastBlockWithError" ) elif response_type == enums.GetResponseType.WITH_LIST: return GetResponseWithList.from_bytes(bytes(source_bytes)) else: raise ValueError("Response type is not a valid GetResponse type")
def from_bytes(cls, source_bytes: bytes): data = bytearray(source_bytes) tag = data.pop(0) if tag != cls.TAG: raise ValueError( f"Tag is not correct. Should be {cls.TAG} but is {tag}") response_type = enums.GetResponseType(data.pop(0)) if response_type != cls.RESPONSE_TYPE: raise ValueError( f"The response type byte: {response_type} is not for a GetResponseNormal" ) invoke_id_and_priority = InvokeIdAndPriority.from_bytes( data.pop(0).to_bytes(1, "big")) last_block = bool(data.pop(0)) if not last_block: raise ValueError( f"Last block is not set to true in a GetResponseLastBlock.") block_number = int.from_bytes(data[:4], "big") data = data[4:] choice = data.pop(0) if choice != 1: raise ValueError( f"The data choice is not 1 to indicate error but: {choice}") assert len(data) == 1 error = enums.DataAccessResult(data.pop(0)) return cls(error, block_number, invoke_id_and_priority)
def from_bytes(cls, source_bytes: bytes): data = bytearray(source_bytes) tag = data.pop(0) if tag != cls.TAG: raise ValueError( f"Tag {tag} is not correct for ActionResponse. Should be {cls.TAG}" ) action_type = enumerations.ActionType(data.pop(0)) if action_type != enumerations.ActionType.NORMAL: raise ValueError( f"Bytes are not representing a ActionResponseNormal. Action type " f"is {action_type}") invoke_id_and_priority = InvokeIdAndPriority.from_bytes( data.pop(0).to_bytes(1, "big")) status = enumerations.ActionResultStatus(data.pop(0)) has_data = bool(data.pop(0)) if has_data: data_is_error = data.pop(0) == 1 if not data_is_error: raise ValueError( "Data is not a ActionResponseNormalWithError, maybe a " "ActionResponseNormal") assert len(data) == 1 error = enumerations.DataAccessResult(data.pop(0)) else: raise ValueError("No error data in ActionResponseWithError") return cls(invoke_id_and_priority=invoke_id_and_priority, status=status, error=error)
def parse_list_response(source_bytes: bytes, amount: int): data = bytearray(source_bytes) dlms_data_items = list() for index in range(0, amount): answer_selection = data.pop(0) if answer_selection == 0: # DLMS data parser = dlms_data.DlmsDataParser() obj = parser.parse(data, limit=1) rest = parser.get_buffer_tail() dlms_data_items.append(obj[0]) data = rest elif answer_selection == 1: # Data Access Result dlms_data_items.append(enums.DataAccessResult(data.pop(0))) else: raise ValueError("Not a valid answer selection byte") return dlms_data_items
def from_bytes(cls, source_bytes: bytes): data = bytearray(source_bytes) tag = data.pop(0) if tag != cls.TAG: raise ValueError( f"Tag for SetResponse is not correct. Got {tag}, should be {cls.TAG}" ) type_choice = enums.SetResponseType(data.pop(0)) if type_choice is not enums.SetResponseType.NORMAL: raise ValueError( "The type of the SetResponse is not for a SetResponseNormal" ) invoke_id_and_priority = InvokeIdAndPriority.from_bytes( data.pop(0).to_bytes(1, "big") ) result = enums.DataAccessResult(data.pop(0)) return cls(result=result, invoke_id_and_priority=invoke_id_and_priority)
def from_bytes(cls, source_bytes: bytes): data = bytearray(source_bytes) tag = data.pop(0) if tag != cls.TAG: raise ValueError( f"Tag is not correct. Should be {cls.TAG} but is {tag}") response_type = enums.GetResponseType(data.pop(0)) if response_type != cls.RESPONSE_TYPE: raise ValueError( f"The response type byte: {response_type} is not for a GetResponseNormal" ) invoke_id_and_priority = InvokeIdAndPriority.from_bytes( data.pop(0).to_bytes(1, "big")) choice = data.pop(0) if choice != 1: raise ValueError( f"The data choice is not 1 to indicate error but: {choice}") error = enums.DataAccessResult(data.pop(0)) return cls(error, invoke_id_and_priority)