Beispiel #1
0
    def from_bytes(cls, source_bytes: bytes):
        data = bytearray(source_bytes)
        tag = data.pop(0)
        if tag != cls.TAG:
            raise ValueError(
                f"Tag for GET request is not correct. Got {tag}, should be {cls.TAG}"
            )

        type_choice = enums.GetRequestType(data.pop(0))
        if type_choice is not enums.GetRequestType.WITH_LIST:
            raise ValueError(
                "The data for the GetRequest is not for a GetRequestWithList")
        invoke_id_and_priority = InvokeIdAndPriority.from_bytes(
            data.pop(0).to_bytes(1, "big"))

        number_of_items = data.pop(0)
        cosem_atts = list()
        for i in range(0, number_of_items):
            # Not really happy with the format of this but it works fine.
            c = cosem.CosemAttributeWithSelection.from_bytes(data)
            cosem_atts.append(c)
            data = data[len(c.to_bytes()):]

        return cls(
            cosem_attributes_with_selection=cosem_atts,
            invoke_id_and_priority=invoke_id_and_priority,
        )
Beispiel #2
0
    def from_bytes(cls, source_bytes: bytes):
        data = bytearray(source_bytes)
        tag = data.pop(0)
        if tag != cls.TAG:
            raise ValueError(
                f"Tag for SetRequest is not correct. Got {tag}, should be {cls.TAG}"
            )

        type_choice = enums.SetRequestType(data.pop(0))
        if type_choice is not enums.SetRequestType.NORMAL:
            raise ValueError("The type of the SetRequest is not for a SetRequestNormal")

        invoke_id_and_priority = InvokeIdAndPriority.from_bytes(
            data.pop(0).to_bytes(1, "big")
        )
        cosem_attribute = cosem.CosemAttribute.from_bytes(data[:9])
        data = data[9:]

        has_access_selection = bool(data.pop(0))
        if has_access_selection:
            raise NotImplementedError("Selective access on SET is not implemented")
        else:
            access_selection = None

        return cls(
            cosem_attribute=cosem_attribute,
            data=bytes(data),
            access_selection=access_selection,
            invoke_id_and_priority=invoke_id_and_priority,
        )
Beispiel #3
0
    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:
            raise ValueError(f"ActionResponse has data and should not be a "
                             f"ActionResponseNormal")

        return cls(invoke_id_and_priority=invoke_id_and_priority,
                   status=status)
Beispiel #4
0
    def from_bytes(cls, source_bytes: bytes):
        data = bytearray(source_bytes)
        tag = data.pop(0)
        if tag != cls.TAG:
            raise ValueError(
                f"Tag for GET request is not correct. Got {tag}, should be {cls.TAG}"
            )

        type_choice = enums.GetRequestType(data.pop(0))
        if type_choice is not enums.GetRequestType.NORMAL:
            raise ValueError(
                "The data for the GetRequest is not for a GetRequestNormal")

        invoke_id_and_priority = InvokeIdAndPriority.from_bytes(
            data.pop(0).to_bytes(1, "big"))

        cosem_attribute_data = data[:9]
        cosem_attribute = cosem.CosemAttribute.from_bytes(cosem_attribute_data)
        data = data[9:]
        has_access_selection = bool(data.pop(0))
        if has_access_selection:
            access_selection = selective_access.AccessDescriptorFactory.from_bytes(
                data)
        else:
            access_selection = None

        return cls(
            cosem_attribute=cosem_attribute,
            invoke_id_and_priority=invoke_id_and_priority,
            access_selection=access_selection,
        )
Beispiel #5
0
    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 != 0:
            raise ValueError(
                f"The data choice is not 0 to indicate data but: {choice}")

        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")

        return cls(bytes(data), block_number, invoke_id_and_priority)
Beispiel #6
0
    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)
Beispiel #7
0
    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 the correct tag for an ActionRequest, should "
                f"be {cls.TAG}")
        request_type = enumerations.ActionType(data.pop(0))

        if request_type != enumerations.ActionType.NORMAL:
            raise ValueError(
                f"Bytes are not representing a ActionRequestNormal. Action type "
                f"is {request_type}")
        invoke_id_and_priority = InvokeIdAndPriority.from_bytes(
            data.pop(0).to_bytes(1, "big"))
        cosem_method = cosem.CosemMethod.from_bytes(data[:9])
        has_data = bool(data[9])
        if has_data:
            request_data = data[10:]
        else:
            request_data = None

        return cls(
            cosem_method=cosem_method,
            data=request_data,
            invoke_id_and_priority=invoke_id_and_priority,
        )
Beispiel #8
0
    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)
Beispiel #9
0
    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")
Beispiel #10
0
class ActionResponseNormalWithError(AbstractXDlmsApdu):
    TAG: ClassVar[int] = 199
    ACTION_TYPE: ClassVar[
        enumerations.ActionType] = enumerations.ActionType.NORMAL

    status: enumerations.ActionResultStatus
    error: enumerations.DataAccessResult
    invoke_id_and_priority: InvokeIdAndPriority = attr.ib(
        default=InvokeIdAndPriority(0, True, True))

    def to_bytes(self):
        out = bytearray()
        out.append(self.TAG)
        out.append(self.ACTION_TYPE.value)
        out.extend(self.invoke_id_and_priority.to_bytes())
        out.append(self.status.value)

        out.extend(b"\x01")
        out.extend(b"\x01")  # data result data (error) choice
        out.append(self.error.value)

        return bytes(out)

    @classmethod
    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)
Beispiel #11
0
class ActionResponseNormalWithData(AbstractXDlmsApdu):
    TAG: ClassVar[int] = 199
    ACTION_TYPE: ClassVar[
        enumerations.ActionType] = enumerations.ActionType.NORMAL

    status: enumerations.ActionResultStatus
    data: bytes = attr.ib(default=None)
    invoke_id_and_priority: InvokeIdAndPriority = attr.ib(
        default=InvokeIdAndPriority(0, True, True))

    def to_bytes(self):
        out = bytearray()
        out.append(self.TAG)
        out.append(self.ACTION_TYPE.value)
        out.extend(self.invoke_id_and_priority.to_bytes())
        out.append(self.status.value)
        out.extend(b"\x01")  # has data
        out.extend(b"\x00")  # data result choice
        out.extend(self.data)
        return bytes(out)

    @classmethod
    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_result = data.pop(0) == 0
            if not data_is_result:
                raise ValueError(
                    "Data is not a ActionResponseNormalWithData, maybe a "
                    "ActionResponseNormalWithError")
            response_data = data

        else:
            raise ValueError(
                f"ActionResponseNormalWithData does not contain any data. "
                f"Should probably be an ActionResponseNormal")

        return cls(
            invoke_id_and_priority=invoke_id_and_priority,
            status=status,
            data=response_data,
        )
Beispiel #12
0
class ActionRequestNormal(AbstractXDlmsApdu):
    TAG: ClassVar[int] = 195
    ACTION_TYPE: ClassVar[
        enumerations.ActionType] = enumerations.ActionType.NORMAL

    cosem_method: cosem.CosemMethod = attr.ib(
        validator=attr.validators.instance_of(cosem.CosemMethod))
    data: Optional[bytes] = attr.ib(default=None)
    invoke_id_and_priority: InvokeIdAndPriority = attr.ib(
        default=InvokeIdAndPriority(0, True, True),
        validator=attr.validators.instance_of(InvokeIdAndPriority),
    )

    def to_bytes(self):
        out = bytearray()
        out.append(self.TAG)
        out.append(self.ACTION_TYPE.value)
        out.extend(self.invoke_id_and_priority.to_bytes())
        out.extend(self.cosem_method.to_bytes())
        if self.data:
            out.append(0x01)
            out.extend(self.data)
        else:
            out.append(0x00)
        return bytes(out)

    @classmethod
    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 the correct tag for an ActionRequest, should "
                f"be {cls.TAG}")
        request_type = enumerations.ActionType(data.pop(0))

        if request_type != enumerations.ActionType.NORMAL:
            raise ValueError(
                f"Bytes are not representing a ActionRequestNormal. Action type "
                f"is {request_type}")
        invoke_id_and_priority = InvokeIdAndPriority.from_bytes(
            data.pop(0).to_bytes(1, "big"))
        cosem_method = cosem.CosemMethod.from_bytes(data[:9])
        has_data = bool(data[9])
        if has_data:
            request_data = data[10:]
        else:
            request_data = None

        return cls(
            cosem_method=cosem_method,
            data=request_data,
            invoke_id_and_priority=invoke_id_and_priority,
        )
Beispiel #13
0
    def from_bytes(cls, source_bytes: bytes):
        data = bytearray(source_bytes)
        tag = data.pop(0)
        if tag != cls.TAG:
            raise ValueError(
                f"Tag for GET request is not correct. Got {tag}, should be {cls.TAG}"
            )

        type_choice = enums.GetRequestType(data.pop(0))
        if type_choice is not enums.GetRequestType.NEXT:
            raise ValueError(
                "The data for the GetRequest is not for a GetRequestNext")
        invoke_id_and_priority = InvokeIdAndPriority.from_bytes(
            data.pop(0).to_bytes(1, "big"))
        assert len(data) == 4  # should only be block number left.
        block_number = int.from_bytes(data, "big")
        return cls(block_number, invoke_id_and_priority)
Beispiel #14
0
class ActionResponseNormal(AbstractXDlmsApdu):
    TAG: ClassVar[int] = 199
    ACTION_TYPE: ClassVar[
        enumerations.ActionType] = enumerations.ActionType.NORMAL

    status: enumerations.ActionResultStatus
    invoke_id_and_priority: InvokeIdAndPriority = attr.ib(
        default=InvokeIdAndPriority(0, True, True))

    def to_bytes(self):
        out = bytearray()
        out.append(self.TAG)
        out.append(self.ACTION_TYPE.value)
        out.extend(self.invoke_id_and_priority.to_bytes())
        out.append(self.status.value)
        out.extend(b"\x00")

        return bytes(out)

    @classmethod
    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:
            raise ValueError(f"ActionResponse has data and should not be a "
                             f"ActionResponseNormal")

        return cls(invoke_id_and_priority=invoke_id_and_priority,
                   status=status)
Beispiel #15
0
    def from_bytes(cls, source_bytes: bytes):
        data = bytearray(source_bytes)
        tag = data.pop(0)
        if tag != cls.TAG:
            raise ValueError("Not a GetResponse APDU")
        response_type = data.pop(0)
        if response_type != cls.RESPONSE_TYPE:
            raise ValueError("Not a GetResponseWithList Apdu")

        invoke_id_and_priority = InvokeIdAndPriority.from_bytes(
            data.pop(0).to_bytes(1, "big"))

        # List of Get-Data-Response.
        list_length = data.pop(0)
        dlms_data = cls.parse_list_response(data, list_length)

        return cls(invoke_id_and_priority=invoke_id_and_priority,
                   response_data=dlms_data)
Beispiel #16
0
    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 != 0:
            raise ValueError(
                f"The data choice is not 0 to indicate data but: {choice}")

        return cls(bytes(data), invoke_id_and_priority)
Beispiel #17
0
    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)
Beispiel #18
0
    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_result = data.pop(0) == 0
            if not data_is_result:
                raise ValueError(
                    "Data is not a ActionResponseNormalWithData, maybe a "
                    "ActionResponseNormalWithError")
            response_data = data

        else:
            raise ValueError(
                f"ActionResponseNormalWithData does not contain any data. "
                f"Should probably be an ActionResponseNormal")

        return cls(
            invoke_id_and_priority=invoke_id_and_priority,
            status=status,
            data=response_data,
        )