
import abc
from io import BytesIO
from typing import Any, Optional, List, Tuple, Union

from typing_extensions import Self

from ..generator_interface import safe_read_int_from_buffer, PayloadFormatError, PayloadTooShortError
from .typedefs import *
from ..generator_interface import BaltechScriptFrame, BaltechScriptBase
from ..generator_interface import BRPFrame, BRPBase
from ..generator_interface import TemplateFrame, TemplateBase
class Enable(BaltechScriptFrame):
    Code = 0x1
    def __init__(self, EnabledIoPort: IoPort) -> None:
        self.EnabledIoPort = EnabledIoPort
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _EnabledIoPort = IoPort_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        return cls(EnabledIoPort=_EnabledIoPort)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(IoPort_Parser.as_value(self.EnabledIoPort).to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('EnabledIoPort', self.EnabledIoPort))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Disable(BaltechScriptFrame):
    Code = 0x2
    def __init__(self, DisabledIoPort: IoPort) -> None:
        self.DisabledIoPort = DisabledIoPort
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _DisabledIoPort = IoPort_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        return cls(DisabledIoPort=_DisabledIoPort)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(IoPort_Parser.as_value(self.DisabledIoPort).to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('DisabledIoPort', self.DisabledIoPort))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Toggle(BaltechScriptFrame):
    Code = 0x3
    def __init__(self, ToggledIoPort: IoPort, RepeatCount: int, Delay: int) -> None:
        self.ToggledIoPort = ToggledIoPort
        self.RepeatCount = RepeatCount
        self.Delay = Delay
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _ToggledIoPort = IoPort_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        _RepeatCount = safe_read_int_from_buffer(_recv_buffer, 1)
        _Delay = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(ToggledIoPort=_ToggledIoPort, RepeatCount=_RepeatCount, Delay=_Delay)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(IoPort_Parser.as_value(self.ToggledIoPort).to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.RepeatCount.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.Delay.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('ToggledIoPort', self.ToggledIoPort))
        args.append(('RepeatCount', self.RepeatCount))
        args.append(('Delay', self.Delay))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class ToggleInverted(BaltechScriptFrame):
    Code = 0x6
    def __init__(self, InvertedToggledIoPort: IoPort, RepeatCount: int, Delay: int) -> None:
        self.InvertedToggledIoPort = InvertedToggledIoPort
        self.RepeatCount = RepeatCount
        self.Delay = Delay
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _InvertedToggledIoPort = IoPort_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        _RepeatCount = safe_read_int_from_buffer(_recv_buffer, 1)
        _Delay = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(InvertedToggledIoPort=_InvertedToggledIoPort, RepeatCount=_RepeatCount, Delay=_Delay)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(IoPort_Parser.as_value(self.InvertedToggledIoPort).to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.RepeatCount.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.Delay.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('InvertedToggledIoPort', self.InvertedToggledIoPort))
        args.append(('RepeatCount', self.RepeatCount))
        args.append(('Delay', self.Delay))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class DefaultAction(BaltechScriptFrame):
    Code = 0x4
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        return cls()
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class SendCardMsg(BaltechScriptFrame):
    Code = 0x5
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        return cls()
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class SendMsg(BaltechScriptFrame):
    Code = 0x7
    def __init__(self, MsgType: MessageType, MsgId: int, Protocol: ProtocolID) -> None:
        self.MsgType = MsgType
        self.MsgId = MsgId
        self.Protocol = Protocol
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _MsgType = MessageType_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        _MsgId = safe_read_int_from_buffer(_recv_buffer, 1)
        _Protocol = ProtocolID_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        return cls(MsgType=_MsgType, MsgId=_MsgId, Protocol=_Protocol)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(MessageType_Parser.as_value(self.MsgType).to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.MsgId.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(ProtocolID_Parser.as_value(self.Protocol).to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('MsgType', self.MsgType))
        args.append(('MsgId', self.MsgId))
        args.append(('Protocol', self.Protocol))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class SetTimer(BaltechScriptFrame):
    Code = 0xB
    def __init__(self, TimerId: int, TimerValue: int) -> None:
        self.TimerId = TimerId
        self.TimerValue = TimerValue
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _TimerId = safe_read_int_from_buffer(_recv_buffer, 1)
        _TimerValue = safe_read_int_from_buffer(_recv_buffer, 2)
        return cls(TimerId=_TimerId, TimerValue=_TimerValue)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.TimerId.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.TimerValue.to_bytes(length=2, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('TimerId', self.TimerId))
        args.append(('TimerValue', self.TimerValue))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class SetVar(BaltechScriptFrame):
    Code = 0x8
    def __init__(self, VarId: int) -> None:
        self.VarId = VarId
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _VarId = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(VarId=_VarId)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.VarId.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('VarId', self.VarId))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class ClearVar(BaltechScriptFrame):
    Code = 0x9
    def __init__(self, VarId: int) -> None:
        self.VarId = VarId
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _VarId = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(VarId=_VarId)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.VarId.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('VarId', self.VarId))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class AssignVar(BaltechScriptFrame):
    Code = 0xA
    def __init__(self, VarId: int) -> None:
        self.VarId = VarId
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _VarId = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(VarId=_VarId)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.VarId.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('VarId', self.VarId))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class IfIoPort(BaltechScriptFrame):
    Code = 0x44
    def __init__(self, CheckedIoPort: IoPort) -> None:
        self.CheckedIoPort = CheckedIoPort
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _CheckedIoPort = IoPort_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        return cls(CheckedIoPort=_CheckedIoPort)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(IoPort_Parser.as_value(self.CheckedIoPort).to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('CheckedIoPort', self.CheckedIoPort))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class IfVar(BaltechScriptFrame):
    Code = 0x45
    def __init__(self, VarId: int) -> None:
        self.VarId = VarId
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _VarId = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(VarId=_VarId)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.VarId.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('VarId', self.VarId))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class IfProtocolEnabled(BaltechScriptFrame):
    Code = 0x41
    def __init__(self, Protocol: ProtocolID) -> None:
        self.Protocol = Protocol
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _Protocol = ProtocolID_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        return cls(Protocol=_Protocol)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(ProtocolID_Parser.as_value(self.Protocol).to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('Protocol', self.Protocol))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class IfDip(BaltechScriptFrame):
    Code = 0x42
    def __init__(self, DipId: int) -> None:
        self.DipId = DipId
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _DipId = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(DipId=_DipId)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.DipId.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('DipId', self.DipId))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class IfState(BaltechScriptFrame):
    Code = 0x40
    def __init__(self, StateId: int) -> None:
        self.StateId = StateId
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _StateId = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(StateId=_StateId)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.StateId.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('StateId', self.StateId))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Not(BaltechScriptFrame):
    Code = 0x80
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        return cls()
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Or(BaltechScriptFrame):
    Code = 0x81
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        return cls()
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class And(BaltechScriptFrame):
    Code = 0x82
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        return cls()
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class IfTrue(BaltechScriptFrame):
    Code = 0x43
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        return cls()
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Trace(BaltechScriptFrame):
    Code = 0xC
    def __init__(self, LogCode: int) -> None:
        self.LogCode = LogCode
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _LogCode = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(LogCode=_LogCode)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.LogCode.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('LogCode', self.LogCode))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Run(BaltechScriptFrame):
    Code = 0xD
    def __init__(self, EventId: int) -> None:
        self.EventId = EventId
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _EventId = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(EventId=_EventId)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.EventId.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('EventId', self.EventId))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class RunSequence(BaltechScriptFrame):
    Code = 0x13
    def __init__(self, Cmds: List[RunSequenceCmd]) -> None:
        self.Cmds = Cmds
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _Cmds = []  # type: ignore[var-annotated,unused-ignore]
        while not False:
            _CmdCode = RunSequenceCmd_CmdCode_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
            if _CmdCode == "RepeatLoop":
                _RepeatCnt = safe_read_int_from_buffer(_recv_buffer, 1)
            else:
                _RepeatCnt = None
            if _CmdCode == "WaitMs" or _CmdCode == "WaitSec":
                _Param = safe_read_int_from_buffer(_recv_buffer, 1)
            else:
                _Param = None
            if _CmdCode == "EnablePort" or _CmdCode == "DisablePort":
                _SwitchIoPort = IoPort_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
            else:
                _SwitchIoPort = None
            _Cmd = RunSequenceCmd(_CmdCode, _RepeatCnt, _Param, _SwitchIoPort)
            _Cmds.append(_Cmd)
            if _CmdCode == "EndOfSequence":
                break
        return cls(Cmds=_Cmds)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        for _Cmds_Entry in self.Cmds:
            _Cmd = _Cmds_Entry
            if isinstance(_Cmd, dict):
                _Cmd = RunSequenceCmd(**_Cmd)
            _CmdCode, _RepeatCnt, _Param, _SwitchIoPort = _Cmd
            _send_buffer.write(RunSequenceCmd_CmdCode_Parser.as_value(_CmdCode).to_bytes(length=1, byteorder='big'))
            if _CmdCode == "RepeatLoop":
                if _RepeatCnt is None:
                    raise TypeError("missing a required argument: '_RepeatCnt'")
                _send_buffer.write(_RepeatCnt.to_bytes(length=1, byteorder='big'))
            if _CmdCode == "WaitMs" or _CmdCode == "WaitSec":
                if _Param is None:
                    raise TypeError("missing a required argument: '_Param'")
                _send_buffer.write(_Param.to_bytes(length=1, byteorder='big'))
            if _CmdCode == "EnablePort" or _CmdCode == "DisablePort":
                if _SwitchIoPort is None:
                    raise TypeError("missing a required argument: '_SwitchIoPort'")
                _send_buffer.write(IoPort_Parser.as_value(_SwitchIoPort).to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('Cmds', self.Cmds))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class CommandFrame(BRPFrame):
    Code = 0x1
    def __init__(self, CheckSumAlgo: BRP_CommandFrame_CheckSumAlgo, UncompressedLength: bool, UncompressedCmdCode: bool, ExecutionMode: BRP_CommandFrame_ExecutionMode, CmdCode: Optional[int] = None, CmdCodeHigh: Optional[int] = None, CmdCodeLow: Optional[int] = None, *, LengthLow: int, LengthHigh: Optional[int] = None, Payload: bytes, ShortCheckSum: Optional[int] = None, LongCheckSum: Optional[int] = None) -> None:
        self.CheckSumAlgo = CheckSumAlgo
        self.UncompressedLength = UncompressedLength
        self.UncompressedCmdCode = UncompressedCmdCode
        self.ExecutionMode = ExecutionMode
        self.CmdCode = CmdCode
        self.CmdCodeHigh = CmdCodeHigh
        self.CmdCodeLow = CmdCodeLow
        self.LengthLow = LengthLow
        self.LengthHigh = LengthHigh
        self.Payload = Payload
        self.ShortCheckSum = ShortCheckSum
        self.LongCheckSum = LongCheckSum
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _FormatFlags_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _CheckSumAlgo = BRP_CommandFrame_CheckSumAlgo_Parser.as_literal((_FormatFlags_int >> 4) & 0b11)
        _UncompressedLength = bool((_FormatFlags_int >> 3) & 0b1)
        _UncompressedCmdCode = bool((_FormatFlags_int >> 2) & 0b1)
        _ExecutionMode = BRP_CommandFrame_ExecutionMode_Parser.as_literal((_FormatFlags_int >> 0) & 0b11)
        if _UncompressedCmdCode:
            _CmdCode = safe_read_int_from_buffer(_recv_buffer, 2)
        else:
            _CmdCode = None
        if not _UncompressedCmdCode:
            _CompressedCmdCode_int = safe_read_int_from_buffer(_recv_buffer, 1)
            _CmdCodeHigh = (_CompressedCmdCode_int >> 5) & 0b111
            _CmdCodeLow = (_CompressedCmdCode_int >> 0) & 0b11111
        else:
            _CmdCodeHigh = None
            _CmdCodeLow = None
        _LengthLow = safe_read_int_from_buffer(_recv_buffer, 1)
        if _UncompressedLength:
            _LengthHigh = safe_read_int_from_buffer(_recv_buffer, 1)
        else:
            _LengthHigh = None
        _Payload = _recv_buffer.read(0)
        if len(_Payload) != 0:
            raise PayloadTooShortError(0 - len(_Payload))
        if _CheckSumAlgo == "BCC8":
            _ShortCheckSum = safe_read_int_from_buffer(_recv_buffer, 1)
        else:
            _ShortCheckSum = None
        if _CheckSumAlgo == "BCC16" or _CheckSumAlgo == "CRC16":
            _LongCheckSum = safe_read_int_from_buffer(_recv_buffer, 2)
        else:
            _LongCheckSum = None
        return cls(CheckSumAlgo=_CheckSumAlgo, UncompressedLength=_UncompressedLength, UncompressedCmdCode=_UncompressedCmdCode, ExecutionMode=_ExecutionMode, CmdCode=_CmdCode, CmdCodeHigh=_CmdCodeHigh, CmdCodeLow=_CmdCodeLow, LengthLow=_LengthLow, LengthHigh=_LengthHigh, Payload=_Payload, ShortCheckSum=_ShortCheckSum, LongCheckSum=_LongCheckSum)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _var_0000_int = 0
        _var_0000_int |= (BRP_CommandFrame_CheckSumAlgo_Parser.as_value(self.CheckSumAlgo) & 0b11) << 4
        _var_0000_int |= (int(self.UncompressedLength) & 0b1) << 3
        _var_0000_int |= (int(self.UncompressedCmdCode) & 0b1) << 2
        _var_0000_int |= (BRP_CommandFrame_ExecutionMode_Parser.as_value(self.ExecutionMode) & 0b11) << 0
        _send_buffer.write(_var_0000_int.to_bytes(length=1, byteorder='big'))
        if self.UncompressedCmdCode:
            if self.CmdCode is None:
                raise TypeError("missing a required argument: 'self.CmdCode'")
            _send_buffer.write(self.CmdCode.to_bytes(length=2, byteorder='big'))
        if not self.UncompressedCmdCode:
            if self.CmdCodeHigh is None:
                raise TypeError("missing a required argument: 'self.CmdCodeHigh'")
            if self.CmdCodeLow is None:
                raise TypeError("missing a required argument: 'self.CmdCodeLow'")
            _var_0001_int = 0
            _var_0001_int |= (self.CmdCodeHigh & 0b111) << 5
            _var_0001_int |= (self.CmdCodeLow & 0b11111) << 0
            _send_buffer.write(_var_0001_int.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.LengthLow.to_bytes(length=1, byteorder='big'))
        if self.UncompressedLength:
            if self.LengthHigh is None:
                raise TypeError("missing a required argument: 'self.LengthHigh'")
            _send_buffer.write(self.LengthHigh.to_bytes(length=1, byteorder='big'))
        if len(self.Payload) != 0:
            raise ValueError(self.Payload)
        _send_buffer.write(self.Payload)
        if self.CheckSumAlgo == "BCC8":
            if self.ShortCheckSum is None:
                raise TypeError("missing a required argument: 'self.ShortCheckSum'")
            _send_buffer.write(self.ShortCheckSum.to_bytes(length=1, byteorder='big'))
        if self.CheckSumAlgo == "BCC16" or self.CheckSumAlgo == "CRC16":
            if self.LongCheckSum is None:
                raise TypeError("missing a required argument: 'self.LongCheckSum'")
            _send_buffer.write(self.LongCheckSum.to_bytes(length=2, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('CheckSumAlgo', self.CheckSumAlgo))
        args.append(('UncompressedLength', self.UncompressedLength))
        args.append(('UncompressedCmdCode', self.UncompressedCmdCode))
        args.append(('ExecutionMode', self.ExecutionMode))
        if self.CmdCode != None:
            args.append(('CmdCode', self.CmdCode))
        if self.CmdCodeHigh != None:
            args.append(('CmdCodeHigh', self.CmdCodeHigh))
        if self.CmdCodeLow != None:
            args.append(('CmdCodeLow', self.CmdCodeLow))
        args.append(('LengthLow', self.LengthLow))
        if self.LengthHigh != None:
            args.append(('LengthHigh', self.LengthHigh))
        args.append(('Payload', self.Payload))
        if self.ShortCheckSum != None:
            args.append(('ShortCheckSum', self.ShortCheckSum))
        if self.LongCheckSum != None:
            args.append(('LongCheckSum', self.LongCheckSum))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class ResponseFrame(BRPFrame):
    Code = 0x2
    def __init__(self, Failure: bool, CriticialBootStatus: bool, CheckSumAlgo: BRP_ResponseFrame_CheckSumAlgo, UncompressedLength: bool, UncompressedCmdCode: bool, Phase: BRP_ResponseFrame_Phase, CmdCode: Optional[int] = None, CmdCodeHigh: Optional[int] = None, CmdCodeLow: Optional[int] = None, *, LengthLow: int, LengthHigh: Optional[int] = None, StatusCode: Optional[int] = None, Payload: Optional[bytes] = None, ShortCheckSum: Optional[int] = None, LongCheckSum: Optional[int] = None) -> None:
        self.Failure = Failure
        self.CriticialBootStatus = CriticialBootStatus
        self.CheckSumAlgo = CheckSumAlgo
        self.UncompressedLength = UncompressedLength
        self.UncompressedCmdCode = UncompressedCmdCode
        self.Phase = Phase
        self.CmdCode = CmdCode
        self.CmdCodeHigh = CmdCodeHigh
        self.CmdCodeLow = CmdCodeLow
        self.LengthLow = LengthLow
        self.LengthHigh = LengthHigh
        self.StatusCode = StatusCode
        self.Payload = Payload
        self.ShortCheckSum = ShortCheckSum
        self.LongCheckSum = LongCheckSum
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _FormatFlags_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _Failure = bool((_FormatFlags_int >> 7) & 0b1)
        _CriticialBootStatus = bool((_FormatFlags_int >> 6) & 0b1)
        _CheckSumAlgo = BRP_ResponseFrame_CheckSumAlgo_Parser.as_literal((_FormatFlags_int >> 4) & 0b11)
        _UncompressedLength = bool((_FormatFlags_int >> 3) & 0b1)
        _UncompressedCmdCode = bool((_FormatFlags_int >> 2) & 0b1)
        _Phase = BRP_ResponseFrame_Phase_Parser.as_literal((_FormatFlags_int >> 0) & 0b11)
        if _UncompressedCmdCode:
            _CmdCode = safe_read_int_from_buffer(_recv_buffer, 2)
        else:
            _CmdCode = None
        if not _UncompressedCmdCode:
            _CompressedCmdCode_int = safe_read_int_from_buffer(_recv_buffer, 1)
            _CmdCodeHigh = (_CompressedCmdCode_int >> 5) & 0b111
            _CmdCodeLow = (_CompressedCmdCode_int >> 0) & 0b11111
        else:
            _CmdCodeHigh = None
            _CmdCodeLow = None
        _LengthLow = safe_read_int_from_buffer(_recv_buffer, 1)
        if _UncompressedLength:
            _LengthHigh = safe_read_int_from_buffer(_recv_buffer, 1)
        else:
            _LengthHigh = None
        if _Failure:
            _StatusCode = safe_read_int_from_buffer(_recv_buffer, 1)
        else:
            _StatusCode = None
        if not _Failure:
            _Payload = _recv_buffer.read(0)
            if len(_Payload) != 0:
                raise PayloadTooShortError(0 - len(_Payload))
        else:
            _Payload = None
        if _CheckSumAlgo == "BCC8":
            _ShortCheckSum = safe_read_int_from_buffer(_recv_buffer, 1)
        else:
            _ShortCheckSum = None
        if _CheckSumAlgo == "BCC16" or _CheckSumAlgo == "CRC16":
            _LongCheckSum = safe_read_int_from_buffer(_recv_buffer, 2)
        else:
            _LongCheckSum = None
        return cls(Failure=_Failure, CriticialBootStatus=_CriticialBootStatus, CheckSumAlgo=_CheckSumAlgo, UncompressedLength=_UncompressedLength, UncompressedCmdCode=_UncompressedCmdCode, Phase=_Phase, CmdCode=_CmdCode, CmdCodeHigh=_CmdCodeHigh, CmdCodeLow=_CmdCodeLow, LengthLow=_LengthLow, LengthHigh=_LengthHigh, StatusCode=_StatusCode, Payload=_Payload, ShortCheckSum=_ShortCheckSum, LongCheckSum=_LongCheckSum)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _var_0000_int = 0
        _var_0000_int |= (int(self.Failure) & 0b1) << 7
        _var_0000_int |= (int(self.CriticialBootStatus) & 0b1) << 6
        _var_0000_int |= (BRP_ResponseFrame_CheckSumAlgo_Parser.as_value(self.CheckSumAlgo) & 0b11) << 4
        _var_0000_int |= (int(self.UncompressedLength) & 0b1) << 3
        _var_0000_int |= (int(self.UncompressedCmdCode) & 0b1) << 2
        _var_0000_int |= (BRP_ResponseFrame_Phase_Parser.as_value(self.Phase) & 0b11) << 0
        _send_buffer.write(_var_0000_int.to_bytes(length=1, byteorder='big'))
        if self.UncompressedCmdCode:
            if self.CmdCode is None:
                raise TypeError("missing a required argument: 'self.CmdCode'")
            _send_buffer.write(self.CmdCode.to_bytes(length=2, byteorder='big'))
        if not self.UncompressedCmdCode:
            if self.CmdCodeHigh is None:
                raise TypeError("missing a required argument: 'self.CmdCodeHigh'")
            if self.CmdCodeLow is None:
                raise TypeError("missing a required argument: 'self.CmdCodeLow'")
            _var_0001_int = 0
            _var_0001_int |= (self.CmdCodeHigh & 0b111) << 5
            _var_0001_int |= (self.CmdCodeLow & 0b11111) << 0
            _send_buffer.write(_var_0001_int.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.LengthLow.to_bytes(length=1, byteorder='big'))
        if self.UncompressedLength:
            if self.LengthHigh is None:
                raise TypeError("missing a required argument: 'self.LengthHigh'")
            _send_buffer.write(self.LengthHigh.to_bytes(length=1, byteorder='big'))
        if self.Failure:
            if self.StatusCode is None:
                raise TypeError("missing a required argument: 'self.StatusCode'")
            _send_buffer.write(self.StatusCode.to_bytes(length=1, byteorder='big'))
        if not self.Failure:
            if self.Payload is None:
                raise TypeError("missing a required argument: 'self.Payload'")
            if len(self.Payload) != 0:
                raise ValueError(self.Payload)
            _send_buffer.write(self.Payload)
        if self.CheckSumAlgo == "BCC8":
            if self.ShortCheckSum is None:
                raise TypeError("missing a required argument: 'self.ShortCheckSum'")
            _send_buffer.write(self.ShortCheckSum.to_bytes(length=1, byteorder='big'))
        if self.CheckSumAlgo == "BCC16" or self.CheckSumAlgo == "CRC16":
            if self.LongCheckSum is None:
                raise TypeError("missing a required argument: 'self.LongCheckSum'")
            _send_buffer.write(self.LongCheckSum.to_bytes(length=2, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('Failure', self.Failure))
        args.append(('CriticialBootStatus', self.CriticialBootStatus))
        args.append(('CheckSumAlgo', self.CheckSumAlgo))
        args.append(('UncompressedLength', self.UncompressedLength))
        args.append(('UncompressedCmdCode', self.UncompressedCmdCode))
        args.append(('Phase', self.Phase))
        if self.CmdCode != None:
            args.append(('CmdCode', self.CmdCode))
        if self.CmdCodeHigh != None:
            args.append(('CmdCodeHigh', self.CmdCodeHigh))
        if self.CmdCodeLow != None:
            args.append(('CmdCodeLow', self.CmdCodeLow))
        args.append(('LengthLow', self.LengthLow))
        if self.LengthHigh != None:
            args.append(('LengthHigh', self.LengthHigh))
        if self.StatusCode != None:
            args.append(('StatusCode', self.StatusCode))
        if self.Payload != None:
            args.append(('Payload', self.Payload))
        if self.ShortCheckSum != None:
            args.append(('ShortCheckSum', self.ShortCheckSum))
        if self.LongCheckSum != None:
            args.append(('LongCheckSum', self.LongCheckSum))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class EscChar(TemplateFrame):
    Code = 0x1B1B
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        return cls()
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class VarData(TemplateFrame):
    Code = 0x1B01
    def __init__(self, StartPos: int, Len: int, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> None:
        self.StartPos = StartPos
        self.Len = Len
        self.Filters = Filters
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _StartPos = safe_read_int_from_buffer(_recv_buffer, 2)
        _Len = safe_read_int_from_buffer(_recv_buffer, 1)
        _Filters_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _BcdToBin = bool((_Filters_int >> 7) & 0b1)
        _BinToAscii = bool((_Filters_int >> 6) & 0b1)
        _Unpack = bool((_Filters_int >> 5) & 0b1)
        _BinToBcd = bool((_Filters_int >> 4) & 0b1)
        _SwapNibbles = bool((_Filters_int >> 3) & 0b1)
        _Pack = bool((_Filters_int >> 2) & 0b1)
        _AsciiToBin = bool((_Filters_int >> 1) & 0b1)
        _Reverse = bool((_Filters_int >> 0) & 0b1)
        _Filters = TemplateFilter(_BcdToBin, _BinToAscii, _Unpack, _BinToBcd, _SwapNibbles, _Pack, _AsciiToBin, _Reverse)
        return cls(StartPos=_StartPos, Len=_Len, Filters=_Filters)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.StartPos.to_bytes(length=2, byteorder='big'))
        _send_buffer.write(self.Len.to_bytes(length=1, byteorder='big'))
        if isinstance(self.Filters, dict):
            self.Filters = TemplateFilter(**self.Filters)
        self.Filters_int = 0
        self.Filters_int |= (int(self.Filters.BcdToBin) & 0b1) << 7
        self.Filters_int |= (int(self.Filters.BinToAscii) & 0b1) << 6
        self.Filters_int |= (int(self.Filters.Unpack) & 0b1) << 5
        self.Filters_int |= (int(self.Filters.BinToBcd) & 0b1) << 4
        self.Filters_int |= (int(self.Filters.SwapNibbles) & 0b1) << 3
        self.Filters_int |= (int(self.Filters.Pack) & 0b1) << 2
        self.Filters_int |= (int(self.Filters.AsciiToBin) & 0b1) << 1
        self.Filters_int |= (int(self.Filters.Reverse) & 0b1) << 0
        _send_buffer.write(self.Filters_int.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('StartPos', self.StartPos))
        args.append(('Len', self.Len))
        args.append(('Filters', self.Filters))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class VarDataClip(TemplateFrame):
    Code = 0x1B03
    def __init__(self, StartPos: int, Len: int, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> None:
        self.StartPos = StartPos
        self.Len = Len
        self.Filters = Filters
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _StartPos = safe_read_int_from_buffer(_recv_buffer, 2)
        _Len = safe_read_int_from_buffer(_recv_buffer, 1)
        _Filters_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _BcdToBin = bool((_Filters_int >> 7) & 0b1)
        _BinToAscii = bool((_Filters_int >> 6) & 0b1)
        _Unpack = bool((_Filters_int >> 5) & 0b1)
        _BinToBcd = bool((_Filters_int >> 4) & 0b1)
        _SwapNibbles = bool((_Filters_int >> 3) & 0b1)
        _Pack = bool((_Filters_int >> 2) & 0b1)
        _AsciiToBin = bool((_Filters_int >> 1) & 0b1)
        _Reverse = bool((_Filters_int >> 0) & 0b1)
        _Filters = TemplateFilter(_BcdToBin, _BinToAscii, _Unpack, _BinToBcd, _SwapNibbles, _Pack, _AsciiToBin, _Reverse)
        return cls(StartPos=_StartPos, Len=_Len, Filters=_Filters)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.StartPos.to_bytes(length=2, byteorder='big'))
        _send_buffer.write(self.Len.to_bytes(length=1, byteorder='big'))
        if isinstance(self.Filters, dict):
            self.Filters = TemplateFilter(**self.Filters)
        self.Filters_int = 0
        self.Filters_int |= (int(self.Filters.BcdToBin) & 0b1) << 7
        self.Filters_int |= (int(self.Filters.BinToAscii) & 0b1) << 6
        self.Filters_int |= (int(self.Filters.Unpack) & 0b1) << 5
        self.Filters_int |= (int(self.Filters.BinToBcd) & 0b1) << 4
        self.Filters_int |= (int(self.Filters.SwapNibbles) & 0b1) << 3
        self.Filters_int |= (int(self.Filters.Pack) & 0b1) << 2
        self.Filters_int |= (int(self.Filters.AsciiToBin) & 0b1) << 1
        self.Filters_int |= (int(self.Filters.Reverse) & 0b1) << 0
        _send_buffer.write(self.Filters_int.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('StartPos', self.StartPos))
        args.append(('Len', self.Len))
        args.append(('Filters', self.Filters))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class VarDataAlign(TemplateFrame):
    Code = 0x1B05
    def __init__(self, FillByte: int, StartPos: int, Len: int, Alignment: Alignment, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> None:
        self.FillByte = FillByte
        self.StartPos = StartPos
        self.Len = Len
        self.Alignment = Alignment
        self.Filters = Filters
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _FillByte = safe_read_int_from_buffer(_recv_buffer, 1)
        _StartPos = safe_read_int_from_buffer(_recv_buffer, 1)
        _Len = safe_read_int_from_buffer(_recv_buffer, 1)
        _Alignment = Alignment_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        _Filters_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _BcdToBin = bool((_Filters_int >> 7) & 0b1)
        _BinToAscii = bool((_Filters_int >> 6) & 0b1)
        _Unpack = bool((_Filters_int >> 5) & 0b1)
        _BinToBcd = bool((_Filters_int >> 4) & 0b1)
        _SwapNibbles = bool((_Filters_int >> 3) & 0b1)
        _Pack = bool((_Filters_int >> 2) & 0b1)
        _AsciiToBin = bool((_Filters_int >> 1) & 0b1)
        _Reverse = bool((_Filters_int >> 0) & 0b1)
        _Filters = TemplateFilter(_BcdToBin, _BinToAscii, _Unpack, _BinToBcd, _SwapNibbles, _Pack, _AsciiToBin, _Reverse)
        return cls(FillByte=_FillByte, StartPos=_StartPos, Len=_Len, Alignment=_Alignment, Filters=_Filters)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.FillByte.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.StartPos.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.Len.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(Alignment_Parser.as_value(self.Alignment).to_bytes(length=1, byteorder='big'))
        if isinstance(self.Filters, dict):
            self.Filters = TemplateFilter(**self.Filters)
        self.Filters_int = 0
        self.Filters_int |= (int(self.Filters.BcdToBin) & 0b1) << 7
        self.Filters_int |= (int(self.Filters.BinToAscii) & 0b1) << 6
        self.Filters_int |= (int(self.Filters.Unpack) & 0b1) << 5
        self.Filters_int |= (int(self.Filters.BinToBcd) & 0b1) << 4
        self.Filters_int |= (int(self.Filters.SwapNibbles) & 0b1) << 3
        self.Filters_int |= (int(self.Filters.Pack) & 0b1) << 2
        self.Filters_int |= (int(self.Filters.AsciiToBin) & 0b1) << 1
        self.Filters_int |= (int(self.Filters.Reverse) & 0b1) << 0
        _send_buffer.write(self.Filters_int.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('FillByte', self.FillByte))
        args.append(('StartPos', self.StartPos))
        args.append(('Len', self.Len))
        args.append(('Alignment', self.Alignment))
        args.append(('Filters', self.Filters))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Serialnr(TemplateFrame):
    Code = 0x1B02
    def __init__(self, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> None:
        self.Filters = Filters
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _Filters_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _BcdToBin = bool((_Filters_int >> 7) & 0b1)
        _BinToAscii = bool((_Filters_int >> 6) & 0b1)
        _Unpack = bool((_Filters_int >> 5) & 0b1)
        _BinToBcd = bool((_Filters_int >> 4) & 0b1)
        _SwapNibbles = bool((_Filters_int >> 3) & 0b1)
        _Pack = bool((_Filters_int >> 2) & 0b1)
        _AsciiToBin = bool((_Filters_int >> 1) & 0b1)
        _Reverse = bool((_Filters_int >> 0) & 0b1)
        _Filters = TemplateFilter(_BcdToBin, _BinToAscii, _Unpack, _BinToBcd, _SwapNibbles, _Pack, _AsciiToBin, _Reverse)
        return cls(Filters=_Filters)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        if isinstance(self.Filters, dict):
            self.Filters = TemplateFilter(**self.Filters)
        self.Filters_int = 0
        self.Filters_int |= (int(self.Filters.BcdToBin) & 0b1) << 7
        self.Filters_int |= (int(self.Filters.BinToAscii) & 0b1) << 6
        self.Filters_int |= (int(self.Filters.Unpack) & 0b1) << 5
        self.Filters_int |= (int(self.Filters.BinToBcd) & 0b1) << 4
        self.Filters_int |= (int(self.Filters.SwapNibbles) & 0b1) << 3
        self.Filters_int |= (int(self.Filters.Pack) & 0b1) << 2
        self.Filters_int |= (int(self.Filters.AsciiToBin) & 0b1) << 1
        self.Filters_int |= (int(self.Filters.Reverse) & 0b1) << 0
        _send_buffer.write(self.Filters_int.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('Filters', self.Filters))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class SerialnrAlign(TemplateFrame):
    Code = 0x1B06
    def __init__(self, Len: int, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> None:
        self.Len = Len
        self.Filters = Filters
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _Len = safe_read_int_from_buffer(_recv_buffer, 1)
        _Filters_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _BcdToBin = bool((_Filters_int >> 7) & 0b1)
        _BinToAscii = bool((_Filters_int >> 6) & 0b1)
        _Unpack = bool((_Filters_int >> 5) & 0b1)
        _BinToBcd = bool((_Filters_int >> 4) & 0b1)
        _SwapNibbles = bool((_Filters_int >> 3) & 0b1)
        _Pack = bool((_Filters_int >> 2) & 0b1)
        _AsciiToBin = bool((_Filters_int >> 1) & 0b1)
        _Reverse = bool((_Filters_int >> 0) & 0b1)
        _Filters = TemplateFilter(_BcdToBin, _BinToAscii, _Unpack, _BinToBcd, _SwapNibbles, _Pack, _AsciiToBin, _Reverse)
        return cls(Len=_Len, Filters=_Filters)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.Len.to_bytes(length=1, byteorder='big'))
        if isinstance(self.Filters, dict):
            self.Filters = TemplateFilter(**self.Filters)
        self.Filters_int = 0
        self.Filters_int |= (int(self.Filters.BcdToBin) & 0b1) << 7
        self.Filters_int |= (int(self.Filters.BinToAscii) & 0b1) << 6
        self.Filters_int |= (int(self.Filters.Unpack) & 0b1) << 5
        self.Filters_int |= (int(self.Filters.BinToBcd) & 0b1) << 4
        self.Filters_int |= (int(self.Filters.SwapNibbles) & 0b1) << 3
        self.Filters_int |= (int(self.Filters.Pack) & 0b1) << 2
        self.Filters_int |= (int(self.Filters.AsciiToBin) & 0b1) << 1
        self.Filters_int |= (int(self.Filters.Reverse) & 0b1) << 0
        _send_buffer.write(self.Filters_int.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('Len', self.Len))
        args.append(('Filters', self.Filters))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Reconvert(TemplateFrame):
    Code = 0x1B07
    def __init__(self, Len: int, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> None:
        self.Len = Len
        self.Filters = Filters
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _Len = safe_read_int_from_buffer(_recv_buffer, 1)
        _Filters_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _BcdToBin = bool((_Filters_int >> 7) & 0b1)
        _BinToAscii = bool((_Filters_int >> 6) & 0b1)
        _Unpack = bool((_Filters_int >> 5) & 0b1)
        _BinToBcd = bool((_Filters_int >> 4) & 0b1)
        _SwapNibbles = bool((_Filters_int >> 3) & 0b1)
        _Pack = bool((_Filters_int >> 2) & 0b1)
        _AsciiToBin = bool((_Filters_int >> 1) & 0b1)
        _Reverse = bool((_Filters_int >> 0) & 0b1)
        _Filters = TemplateFilter(_BcdToBin, _BinToAscii, _Unpack, _BinToBcd, _SwapNibbles, _Pack, _AsciiToBin, _Reverse)
        return cls(Len=_Len, Filters=_Filters)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.Len.to_bytes(length=1, byteorder='big'))
        if isinstance(self.Filters, dict):
            self.Filters = TemplateFilter(**self.Filters)
        self.Filters_int = 0
        self.Filters_int |= (int(self.Filters.BcdToBin) & 0b1) << 7
        self.Filters_int |= (int(self.Filters.BinToAscii) & 0b1) << 6
        self.Filters_int |= (int(self.Filters.Unpack) & 0b1) << 5
        self.Filters_int |= (int(self.Filters.BinToBcd) & 0b1) << 4
        self.Filters_int |= (int(self.Filters.SwapNibbles) & 0b1) << 3
        self.Filters_int |= (int(self.Filters.Pack) & 0b1) << 2
        self.Filters_int |= (int(self.Filters.AsciiToBin) & 0b1) << 1
        self.Filters_int |= (int(self.Filters.Reverse) & 0b1) << 0
        _send_buffer.write(self.Filters_int.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('Len', self.Len))
        args.append(('Filters', self.Filters))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class CutNibbles(TemplateFrame):
    Code = 0x1B04
    def __init__(self, StartNibble: int, NibbleCount: int) -> None:
        self.StartNibble = StartNibble
        self.NibbleCount = NibbleCount
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _StartNibble = safe_read_int_from_buffer(_recv_buffer, 2)
        _NibbleCount = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(StartNibble=_StartNibble, NibbleCount=_NibbleCount)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.StartNibble.to_bytes(length=2, byteorder='big'))
        _send_buffer.write(self.NibbleCount.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('StartNibble', self.StartNibble))
        args.append(('NibbleCount', self.NibbleCount))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class CutBits(TemplateFrame):
    Code = 0x1B09
    def __init__(self, StartBit: int, BitCount: int, Bitorder: TemplateBitorder) -> None:
        self.StartBit = StartBit
        self.BitCount = BitCount
        self.Bitorder = Bitorder
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _StartBit = safe_read_int_from_buffer(_recv_buffer, 2)
        _BitCount = safe_read_int_from_buffer(_recv_buffer, 1)
        _Bitorder = TemplateBitorder_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        return cls(StartBit=_StartBit, BitCount=_BitCount, Bitorder=_Bitorder)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.StartBit.to_bytes(length=2, byteorder='big'))
        _send_buffer.write(self.BitCount.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(TemplateBitorder_Parser.as_value(self.Bitorder).to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('StartBit', self.StartBit))
        args.append(('BitCount', self.BitCount))
        args.append(('Bitorder', self.Bitorder))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Bcc(TemplateFrame):
    Code = 0x1B08
    def __init__(self, StartPos: int, Len: int, InitValue: int, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> None:
        self.StartPos = StartPos
        self.Len = Len
        self.InitValue = InitValue
        self.Filters = Filters
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _StartPos = safe_read_int_from_buffer(_recv_buffer, 2)
        _Len = safe_read_int_from_buffer(_recv_buffer, 1)
        _InitValue = safe_read_int_from_buffer(_recv_buffer, 1)
        _Filters_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _BcdToBin = bool((_Filters_int >> 7) & 0b1)
        _BinToAscii = bool((_Filters_int >> 6) & 0b1)
        _Unpack = bool((_Filters_int >> 5) & 0b1)
        _BinToBcd = bool((_Filters_int >> 4) & 0b1)
        _SwapNibbles = bool((_Filters_int >> 3) & 0b1)
        _Pack = bool((_Filters_int >> 2) & 0b1)
        _AsciiToBin = bool((_Filters_int >> 1) & 0b1)
        _Reverse = bool((_Filters_int >> 0) & 0b1)
        _Filters = TemplateFilter(_BcdToBin, _BinToAscii, _Unpack, _BinToBcd, _SwapNibbles, _Pack, _AsciiToBin, _Reverse)
        return cls(StartPos=_StartPos, Len=_Len, InitValue=_InitValue, Filters=_Filters)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.StartPos.to_bytes(length=2, byteorder='big'))
        _send_buffer.write(self.Len.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.InitValue.to_bytes(length=1, byteorder='big'))
        if isinstance(self.Filters, dict):
            self.Filters = TemplateFilter(**self.Filters)
        self.Filters_int = 0
        self.Filters_int |= (int(self.Filters.BcdToBin) & 0b1) << 7
        self.Filters_int |= (int(self.Filters.BinToAscii) & 0b1) << 6
        self.Filters_int |= (int(self.Filters.Unpack) & 0b1) << 5
        self.Filters_int |= (int(self.Filters.BinToBcd) & 0b1) << 4
        self.Filters_int |= (int(self.Filters.SwapNibbles) & 0b1) << 3
        self.Filters_int |= (int(self.Filters.Pack) & 0b1) << 2
        self.Filters_int |= (int(self.Filters.AsciiToBin) & 0b1) << 1
        self.Filters_int |= (int(self.Filters.Reverse) & 0b1) << 0
        _send_buffer.write(self.Filters_int.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('StartPos', self.StartPos))
        args.append(('Len', self.Len))
        args.append(('InitValue', self.InitValue))
        args.append(('Filters', self.Filters))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class ContinueTmpl(TemplateFrame):
    Code = 0x1B10
    def __init__(self, TemplateValueId: int) -> None:
        self.TemplateValueId = TemplateValueId
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _TemplateValueId = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(TemplateValueId=_TemplateValueId)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.TemplateValueId.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('TemplateValueId', self.TemplateValueId))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Encrypt(TemplateFrame):
    Code = 0x1B0A
    def __init__(self, Len: int, CryptoMode: Template_Encrypt_CryptoMode, Key: int) -> None:
        self.Len = Len
        self.CryptoMode = CryptoMode
        self.Key = Key
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _Len = safe_read_int_from_buffer(_recv_buffer, 1)
        _CryptoMode = Template_Encrypt_CryptoMode_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        _Key = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(Len=_Len, CryptoMode=_CryptoMode, Key=_Key)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.Len.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(Template_Encrypt_CryptoMode_Parser.as_value(self.CryptoMode).to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.Key.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('Len', self.Len))
        args.append(('CryptoMode', self.CryptoMode))
        args.append(('Key', self.Key))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class ReaderSerialnr(TemplateFrame):
    Code = 0x1B0B
    def __init__(self, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> None:
        self.Filters = Filters
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _Filters_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _BcdToBin = bool((_Filters_int >> 7) & 0b1)
        _BinToAscii = bool((_Filters_int >> 6) & 0b1)
        _Unpack = bool((_Filters_int >> 5) & 0b1)
        _BinToBcd = bool((_Filters_int >> 4) & 0b1)
        _SwapNibbles = bool((_Filters_int >> 3) & 0b1)
        _Pack = bool((_Filters_int >> 2) & 0b1)
        _AsciiToBin = bool((_Filters_int >> 1) & 0b1)
        _Reverse = bool((_Filters_int >> 0) & 0b1)
        _Filters = TemplateFilter(_BcdToBin, _BinToAscii, _Unpack, _BinToBcd, _SwapNibbles, _Pack, _AsciiToBin, _Reverse)
        return cls(Filters=_Filters)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        if isinstance(self.Filters, dict):
            self.Filters = TemplateFilter(**self.Filters)
        self.Filters_int = 0
        self.Filters_int |= (int(self.Filters.BcdToBin) & 0b1) << 7
        self.Filters_int |= (int(self.Filters.BinToAscii) & 0b1) << 6
        self.Filters_int |= (int(self.Filters.Unpack) & 0b1) << 5
        self.Filters_int |= (int(self.Filters.BinToBcd) & 0b1) << 4
        self.Filters_int |= (int(self.Filters.SwapNibbles) & 0b1) << 3
        self.Filters_int |= (int(self.Filters.Pack) & 0b1) << 2
        self.Filters_int |= (int(self.Filters.AsciiToBin) & 0b1) << 1
        self.Filters_int |= (int(self.Filters.Reverse) & 0b1) << 0
        _send_buffer.write(self.Filters_int.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('Filters', self.Filters))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class CardCounter(TemplateFrame):
    Code = 0x1B0C
    def __init__(self, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> None:
        self.Filters = Filters
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _Filters_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _BcdToBin = bool((_Filters_int >> 7) & 0b1)
        _BinToAscii = bool((_Filters_int >> 6) & 0b1)
        _Unpack = bool((_Filters_int >> 5) & 0b1)
        _BinToBcd = bool((_Filters_int >> 4) & 0b1)
        _SwapNibbles = bool((_Filters_int >> 3) & 0b1)
        _Pack = bool((_Filters_int >> 2) & 0b1)
        _AsciiToBin = bool((_Filters_int >> 1) & 0b1)
        _Reverse = bool((_Filters_int >> 0) & 0b1)
        _Filters = TemplateFilter(_BcdToBin, _BinToAscii, _Unpack, _BinToBcd, _SwapNibbles, _Pack, _AsciiToBin, _Reverse)
        return cls(Filters=_Filters)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        if isinstance(self.Filters, dict):
            self.Filters = TemplateFilter(**self.Filters)
        self.Filters_int = 0
        self.Filters_int |= (int(self.Filters.BcdToBin) & 0b1) << 7
        self.Filters_int |= (int(self.Filters.BinToAscii) & 0b1) << 6
        self.Filters_int |= (int(self.Filters.Unpack) & 0b1) << 5
        self.Filters_int |= (int(self.Filters.BinToBcd) & 0b1) << 4
        self.Filters_int |= (int(self.Filters.SwapNibbles) & 0b1) << 3
        self.Filters_int |= (int(self.Filters.Pack) & 0b1) << 2
        self.Filters_int |= (int(self.Filters.AsciiToBin) & 0b1) << 1
        self.Filters_int |= (int(self.Filters.Reverse) & 0b1) << 0
        _send_buffer.write(self.Filters_int.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('Filters', self.Filters))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Scramble(TemplateFrame):
    Code = 0x1B0D
    def __init__(self, Len: int, NoRepeat: bool, PadZero: bool, AlignRight: bool, SourceSubBlockBits: int, BitMap: List[Template_Scramble_BitMap_Entry], Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> None:
        self.Len = Len
        self.NoRepeat = NoRepeat
        self.PadZero = PadZero
        self.AlignRight = AlignRight
        self.SourceSubBlockBits = SourceSubBlockBits
        self.BitMap = BitMap
        self.Filters = Filters
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _Len = safe_read_int_from_buffer(_recv_buffer, 1)
        _ScrambleOptions_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _NoRepeat = bool((_ScrambleOptions_int >> 2) & 0b1)
        _PadZero = bool((_ScrambleOptions_int >> 1) & 0b1)
        _AlignRight = bool((_ScrambleOptions_int >> 0) & 0b1)
        _SourceSubBlockBits = safe_read_int_from_buffer(_recv_buffer, 1)
        _BitMap_len = safe_read_int_from_buffer(_recv_buffer, 1)
        _BitMap = []  # type: ignore[var-annotated,unused-ignore]
        while not len(_BitMap) >= _BitMap_len:
            _var_0000_int = safe_read_int_from_buffer(_recv_buffer, 1)
            _Invert = bool((_var_0000_int >> 7) & 0b1)
            _SrcBitPos = (_var_0000_int >> 0) & 0b1111111
            _BitMap_Entry = Template_Scramble_BitMap_Entry(_Invert, _SrcBitPos)
            _BitMap.append(_BitMap_Entry)
        if len(_BitMap) != _BitMap_len:
            raise PayloadTooShortError(_BitMap_len - len(_BitMap))
        _Filters_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _BcdToBin = bool((_Filters_int >> 7) & 0b1)
        _BinToAscii = bool((_Filters_int >> 6) & 0b1)
        _Unpack = bool((_Filters_int >> 5) & 0b1)
        _BinToBcd = bool((_Filters_int >> 4) & 0b1)
        _SwapNibbles = bool((_Filters_int >> 3) & 0b1)
        _Pack = bool((_Filters_int >> 2) & 0b1)
        _AsciiToBin = bool((_Filters_int >> 1) & 0b1)
        _Reverse = bool((_Filters_int >> 0) & 0b1)
        _Filters = TemplateFilter(_BcdToBin, _BinToAscii, _Unpack, _BinToBcd, _SwapNibbles, _Pack, _AsciiToBin, _Reverse)
        return cls(Len=_Len, NoRepeat=_NoRepeat, PadZero=_PadZero, AlignRight=_AlignRight, SourceSubBlockBits=_SourceSubBlockBits, BitMap=_BitMap, Filters=_Filters)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.Len.to_bytes(length=1, byteorder='big'))
        _var_0000_int = 0
        _var_0000_int |= (int(self.NoRepeat) & 0b1) << 2
        _var_0000_int |= (int(self.PadZero) & 0b1) << 1
        _var_0000_int |= (int(self.AlignRight) & 0b1) << 0
        _send_buffer.write(_var_0000_int.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.SourceSubBlockBits.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(int(len(self.BitMap)).to_bytes(1, byteorder='big'))
        for _BitMap_Entry in self.BitMap:
            _Invert, _SrcBitPos = _BitMap_Entry
            _var_0001_int = 0
            _var_0001_int |= (int(_Invert) & 0b1) << 7
            _var_0001_int |= (_SrcBitPos & 0b1111111) << 0
            _send_buffer.write(_var_0001_int.to_bytes(length=1, byteorder='big'))
        if isinstance(self.Filters, dict):
            self.Filters = TemplateFilter(**self.Filters)
        self.Filters_int = 0
        self.Filters_int |= (int(self.Filters.BcdToBin) & 0b1) << 7
        self.Filters_int |= (int(self.Filters.BinToAscii) & 0b1) << 6
        self.Filters_int |= (int(self.Filters.Unpack) & 0b1) << 5
        self.Filters_int |= (int(self.Filters.BinToBcd) & 0b1) << 4
        self.Filters_int |= (int(self.Filters.SwapNibbles) & 0b1) << 3
        self.Filters_int |= (int(self.Filters.Pack) & 0b1) << 2
        self.Filters_int |= (int(self.Filters.AsciiToBin) & 0b1) << 1
        self.Filters_int |= (int(self.Filters.Reverse) & 0b1) << 0
        _send_buffer.write(self.Filters_int.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('Len', self.Len))
        args.append(('NoRepeat', self.NoRepeat))
        args.append(('PadZero', self.PadZero))
        args.append(('AlignRight', self.AlignRight))
        args.append(('SourceSubBlockBits', self.SourceSubBlockBits))
        args.append(('BitMap', self.BitMap))
        args.append(('Filters', self.Filters))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Mark(TemplateFrame):
    Code = 0x1B0E
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        return cls()
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Strip(TemplateFrame):
    Code = 0x1B0F
    def __init__(self, Len: int, Leading: bool, Middle: bool, Trailing: bool, RemoveChar: int) -> None:
        self.Len = Len
        self.Leading = Leading
        self.Middle = Middle
        self.Trailing = Trailing
        self.RemoveChar = RemoveChar
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _Len = safe_read_int_from_buffer(_recv_buffer, 1)
        _StripOptions_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _Leading = bool((_StripOptions_int >> 2) & 0b1)
        _Middle = bool((_StripOptions_int >> 1) & 0b1)
        _Trailing = bool((_StripOptions_int >> 0) & 0b1)
        _RemoveChar = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(Len=_Len, Leading=_Leading, Middle=_Middle, Trailing=_Trailing, RemoveChar=_RemoveChar)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.Len.to_bytes(length=1, byteorder='big'))
        _var_0000_int = 0
        _var_0000_int |= (int(self.Leading) & 0b1) << 2
        _var_0000_int |= (int(self.Middle) & 0b1) << 1
        _var_0000_int |= (int(self.Trailing) & 0b1) << 0
        _send_buffer.write(_var_0000_int.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.RemoveChar.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('Len', self.Len))
        args.append(('Leading', self.Leading))
        args.append(('Middle', self.Middle))
        args.append(('Trailing', self.Trailing))
        args.append(('RemoveChar', self.RemoveChar))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class IsEqual(TemplateFrame):
    Code = 0x1B12
    def __init__(self, ActionOnSuccess: Template_IsEqual_ActionOnSuccess, ConstData: str) -> None:
        self.ActionOnSuccess = ActionOnSuccess
        self.ConstData = ConstData
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _ActionOnSuccess = Template_IsEqual_ActionOnSuccess_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        _ConstData_bytes = b''
        _ConstData_next_byte = _recv_buffer.read(1)
        while _ConstData_next_byte and _ConstData_next_byte != b'\x00':
            _ConstData_bytes += _ConstData_next_byte
            _ConstData_next_byte = _recv_buffer.read(1)
        if not _ConstData_next_byte:
            raise PayloadFormatError('missing zero-terminator in field ConstData')
        _ConstData = _ConstData_bytes.decode('ascii')
        return cls(ActionOnSuccess=_ActionOnSuccess, ConstData=_ConstData)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(Template_IsEqual_ActionOnSuccess_Parser.as_value(self.ActionOnSuccess).to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.ConstData.encode("ascii"))
        _send_buffer.write(b'\x00')
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('ActionOnSuccess', self.ActionOnSuccess))
        args.append(('ConstData', self.ConstData))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class BitDataEnd(TemplateFrame):
    Code = 0x1B13
    def __init__(self, SrcDataBitOrder: TemplateBitorder) -> None:
        self.SrcDataBitOrder = SrcDataBitOrder
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _SrcDataBitOrder = TemplateBitorder_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        return cls(SrcDataBitOrder=_SrcDataBitOrder)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(TemplateBitorder_Parser.as_value(self.SrcDataBitOrder).to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('SrcDataBitOrder', self.SrcDataBitOrder))
        formatted_args = [repr(args[0][1])]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class ExtractBitField(TemplateFrame):
    Code = 0x1B14
    def __init__(self, SrcFieldStartBit: int, SrcFieldBits: int, Filter: Union[TemplateFilter, TemplateFilter_Dict], DstFieldBytes: int) -> None:
        self.SrcFieldStartBit = SrcFieldStartBit
        self.SrcFieldBits = SrcFieldBits
        self.Filter = Filter
        self.DstFieldBytes = DstFieldBytes
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _SrcFieldStartBit = safe_read_int_from_buffer(_recv_buffer, 2)
        _SrcFieldBits = safe_read_int_from_buffer(_recv_buffer, 1)
        _Filter_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _BcdToBin = bool((_Filter_int >> 7) & 0b1)
        _BinToAscii = bool((_Filter_int >> 6) & 0b1)
        _Unpack = bool((_Filter_int >> 5) & 0b1)
        _BinToBcd = bool((_Filter_int >> 4) & 0b1)
        _SwapNibbles = bool((_Filter_int >> 3) & 0b1)
        _Pack = bool((_Filter_int >> 2) & 0b1)
        _AsciiToBin = bool((_Filter_int >> 1) & 0b1)
        _Reverse = bool((_Filter_int >> 0) & 0b1)
        _Filter = TemplateFilter(_BcdToBin, _BinToAscii, _Unpack, _BinToBcd, _SwapNibbles, _Pack, _AsciiToBin, _Reverse)
        _DstFieldBytes = safe_read_int_from_buffer(_recv_buffer, 1)
        return cls(SrcFieldStartBit=_SrcFieldStartBit, SrcFieldBits=_SrcFieldBits, Filter=_Filter, DstFieldBytes=_DstFieldBytes)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.SrcFieldStartBit.to_bytes(length=2, byteorder='big'))
        _send_buffer.write(self.SrcFieldBits.to_bytes(length=1, byteorder='big'))
        if isinstance(self.Filter, dict):
            self.Filter = TemplateFilter(**self.Filter)
        self.Filter_int = 0
        self.Filter_int |= (int(self.Filter.BcdToBin) & 0b1) << 7
        self.Filter_int |= (int(self.Filter.BinToAscii) & 0b1) << 6
        self.Filter_int |= (int(self.Filter.Unpack) & 0b1) << 5
        self.Filter_int |= (int(self.Filter.BinToBcd) & 0b1) << 4
        self.Filter_int |= (int(self.Filter.SwapNibbles) & 0b1) << 3
        self.Filter_int |= (int(self.Filter.Pack) & 0b1) << 2
        self.Filter_int |= (int(self.Filter.AsciiToBin) & 0b1) << 1
        self.Filter_int |= (int(self.Filter.Reverse) & 0b1) << 0
        _send_buffer.write(self.Filter_int.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.DstFieldBytes.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('SrcFieldStartBit', self.SrcFieldStartBit))
        args.append(('SrcFieldBits', self.SrcFieldBits))
        args.append(('Filter', self.Filter))
        args.append(('DstFieldBytes', self.DstFieldBytes))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Sum(TemplateFrame):
    Code = 0x1B15
    def __init__(self, StartPos: int, Len: int, InitValue: int, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> None:
        self.StartPos = StartPos
        self.Len = Len
        self.InitValue = InitValue
        self.Filters = Filters
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _StartPos = safe_read_int_from_buffer(_recv_buffer, 2)
        _Len = safe_read_int_from_buffer(_recv_buffer, 1)
        _InitValue = safe_read_int_from_buffer(_recv_buffer, 1)
        _Filters_int = safe_read_int_from_buffer(_recv_buffer, 1)
        _BcdToBin = bool((_Filters_int >> 7) & 0b1)
        _BinToAscii = bool((_Filters_int >> 6) & 0b1)
        _Unpack = bool((_Filters_int >> 5) & 0b1)
        _BinToBcd = bool((_Filters_int >> 4) & 0b1)
        _SwapNibbles = bool((_Filters_int >> 3) & 0b1)
        _Pack = bool((_Filters_int >> 2) & 0b1)
        _AsciiToBin = bool((_Filters_int >> 1) & 0b1)
        _Reverse = bool((_Filters_int >> 0) & 0b1)
        _Filters = TemplateFilter(_BcdToBin, _BinToAscii, _Unpack, _BinToBcd, _SwapNibbles, _Pack, _AsciiToBin, _Reverse)
        return cls(StartPos=_StartPos, Len=_Len, InitValue=_InitValue, Filters=_Filters)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.StartPos.to_bytes(length=2, byteorder='big'))
        _send_buffer.write(self.Len.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.InitValue.to_bytes(length=1, byteorder='big'))
        if isinstance(self.Filters, dict):
            self.Filters = TemplateFilter(**self.Filters)
        self.Filters_int = 0
        self.Filters_int |= (int(self.Filters.BcdToBin) & 0b1) << 7
        self.Filters_int |= (int(self.Filters.BinToAscii) & 0b1) << 6
        self.Filters_int |= (int(self.Filters.Unpack) & 0b1) << 5
        self.Filters_int |= (int(self.Filters.BinToBcd) & 0b1) << 4
        self.Filters_int |= (int(self.Filters.SwapNibbles) & 0b1) << 3
        self.Filters_int |= (int(self.Filters.Pack) & 0b1) << 2
        self.Filters_int |= (int(self.Filters.AsciiToBin) & 0b1) << 1
        self.Filters_int |= (int(self.Filters.Reverse) & 0b1) << 0
        _send_buffer.write(self.Filters_int.to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('StartPos', self.StartPos))
        args.append(('Len', self.Len))
        args.append(('InitValue', self.InitValue))
        args.append(('Filters', self.Filters))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class Align(TemplateFrame):
    Code = 0x1B16
    def __init__(self, FillByte: int, DestLen: int, Alignment: Alignment) -> None:
        self.FillByte = FillByte
        self.DestLen = DestLen
        self.Alignment = Alignment
    @classmethod
    def read_from(cls, frame: BytesIO) -> Self:
        _recv_buffer = frame
        _FillByte = safe_read_int_from_buffer(_recv_buffer, 1)
        _DestLen = safe_read_int_from_buffer(_recv_buffer, 1)
        _Alignment = Alignment_Parser.as_literal(safe_read_int_from_buffer(_recv_buffer, 1))
        return cls(FillByte=_FillByte, DestLen=_DestLen, Alignment=_Alignment)
    def __bytes__(self) -> bytes:
        _send_buffer = BytesIO()
        _send_buffer.write(self.FillByte.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(self.DestLen.to_bytes(length=1, byteorder='big'))
        _send_buffer.write(Alignment_Parser.as_value(self.Alignment).to_bytes(length=1, byteorder='big'))
        return _send_buffer.getvalue()
    def __repr__(self) -> str:
        args: List[Tuple[str, Any]] = []
        args.append(('FillByte', self.FillByte))
        args.append(('DestLen', self.DestLen))
        args.append(('Alignment', self.Alignment))
        formatted_args = [f'{name}={repr(value)}' for name, value in args]
        return f'{type(self).__name__}({", ".join(formatted_args)})'
class BaltechScript(BaltechScriptBase, metaclass=abc.ABCMeta):
    """
    Baltech Script is a small language to define simple actions the reader should execute. A Baltech Script consists of one or more commands processed sequentially when the script is run. Usually these actions are assigned to events such as ''card presentation'' or ''I/O port set to low'' in Autoread Mode based readers. Alternatively, the host can execute such a script via protocol using the AR.RunScript command. 
    
    A script has to be stored as a configuration value within the Scripts / Events Key, if it shall be assigned to an event. This configuration Key contains a list of all available configuration Values and the events assigned to them. 
    
    **Script commands are never waiting or delaying execution. If they start a long running process (i.e. Toggle ), this process will be started asynchronously. This means that the script is not waiting until the corresponding command has finished.**
    
    _Example_
    
    The following example describes a scenario in which the Baltech reader runs in Autoread Mode. 
    
      * As long as the reader is waiting for cards, the green LED should be enabled. 
      * On card presentation, the reader should read the card number and send it to the host. 
      * One of the input pins (Input0) shall be used as ''lock signal''. If this pin is set to ''low'', the reader will not send the card number to the host but beep three times (at 1 Hz frequency) and disable the green led while beeping. 
      * As soon as this pin is high again, the ID-engine will continue sending the card number to the host without beeping when detecting a valid card. 
    
    
    
    The script to be executed in case a presented card is deemed valid by the Baltech reader is stored in the Scripts / Events / OnAccepted configuration Value. 
    
    The desired script needs to decide if the pin labeled _Input0_ is low (logical false) or not: 
    
      * If _Input0_ is high (logical true), the script should be stopped and the default action should be executed. The default action for the _OnAccepted_ event is to send the card number to the host. 
      * If _Input0_ is low, the script should toggle the beeper 3 times where the beeper shall be enabled for 500 ms on every beep. Furthermore the red led should be enabled for 3000 ms. 
    
    
    
    This script takes the following form: 
    
      1. IfIoPort Input0 (hex code 44 04) 
      2. DefaultAction (hex code 04) 
      3. IfIoPort Input0 Not (hex code 44 04 80) 
      4. Toggle Beeper 3 5 (hex code 03 02 03 05) 
      5. ToggleInverted GreenLed 1 30 (hex code 06 00 01 1E) 
    
    
    
    A second script is needed to ensure that the green LED is enabled after the reader powers up. As soon as the reader is initialized completely, the host protocol is activated. Thus the Scripts / Events / OnEnabledProtocol event can be used to trigger the second script: 
    
      * Enable GreenLed (hex code 01 00) 
    
    
    
    _Condition Stack_
    
    A condition stack, necessary for conditional execution of parts of a script, is included as a feature of the Baltech Script language. It consists of a list of flags which may be either _false_ (=0) or _true_ (=1). If the topmost flag is _true_ , all subsequent commands will be executed. If the topmost flag is _false_ , none of the subsequent commands is executed, except commands modifying the stack. When a script is started, the condition stack is always empty. Thus, all commands are executed. The following list summarizes all commands modifying the condition stack: 
    
      * All commands starting with _If_ push a new flag onto the top of the stack (IfIoPort, IfVar, IfProtocolEnabled, IfDip, IfState, IfTrue). 
      * Some commands modify the top of the stack (Not, Or, And) 
      * The AssignVar command removes the topmost flag from the stack. 
    
    
    
    The architecture allows an inverse polish notation for complex boolean expressions such as: 
    
    ` If "global state variable 8" is true and "dip switch 3" is off do X `
    
    _Global State Variables_
    
    To save a script's state, 16 so-called global state variables are available. These variables are flags which can be set or cleared within a script. They keep their state even after the execution of a script. Thus, the next script can access the flags set by the previous script. 
    
    Initially, all 16 global state variables are cleared (=0). 
    
    It is possible to modify these global variables via a script or to copy a variable onto the top of the Condition Stack and vice-versa. Please refer to the description of the SetVar, ClearVar, AssignVar and IfVar functions for detailed information.
    """
    CodeMap = {
        0x0001: Enable,
        0x0002: Disable,
        0x0003: Toggle,
        0x0006: ToggleInverted,
        0x0004: DefaultAction,
        0x0005: SendCardMsg,
        0x0007: SendMsg,
        0x000B: SetTimer,
        0x0008: SetVar,
        0x0009: ClearVar,
        0x000A: AssignVar,
        0x0044: IfIoPort,
        0x0045: IfVar,
        0x0041: IfProtocolEnabled,
        0x0042: IfDip,
        0x0040: IfState,
        0x0080: Not,
        0x0081: Or,
        0x0082: And,
        0x0043: IfTrue,
        0x000C: Trace,
        0x000D: Run,
        0x0013: RunSequence,
    }
    def Enable(self, EnabledIoPort: IoPort) -> Self:
        """
        Sets an IoPort to high permanently. 
        
        See also Disable, Toggle or ToggleInverted.
        """
        self.frames.append(Enable(EnabledIoPort=EnabledIoPort))
        return self
    def Disable(self, DisabledIoPort: IoPort) -> Self:
        """
        Sets an IoPort to low permanently. 
        
        See also Enable, Toggle or ToggleInverted.
        """
        self.frames.append(Disable(DisabledIoPort=DisabledIoPort))
        return self
    def Toggle(self, ToggledIoPort: IoPort, RepeatCount: int, Delay: int) -> Self:
        """
        Set _IoPort_ to high, wait Delay/10 seconds, set _IoPort_ to low and wait Delay/10 seconds again. Repeat this _RepeatCount_ times. 
        
        See also Enable, Disable or ToggleInverted.
        """
        self.frames.append(Toggle(ToggledIoPort=ToggledIoPort, RepeatCount=RepeatCount, Delay=Delay))
        return self
    def ToggleInverted(self, InvertedToggledIoPort: IoPort, RepeatCount: int, Delay: int) -> Self:
        """
        Set _IoPort_ to low, wait Delay/10 seconds. Then set _IoPort_ to high and wait Delay/10 seconds again. Repeat this _RepeatCount_ times. This is exactly the inverse behaviour of Toggle and is mainly used to ensure that the IoPort is set to high after finishing toggling. 
        
        See also Enable, Disable or Toggle.
        """
        self.frames.append(ToggleInverted(InvertedToggledIoPort=InvertedToggledIoPort, RepeatCount=RepeatCount, Delay=Delay))
        return self
    def DefaultAction(self, ) -> Self:
        """
        Most events have a "default action", i.e. the action that the firmware performs by default. If you configure a custom action, it will replace the default action. To perform the default action _in addition_ to your custom action, you need to run the _DefaultAction_ command. 
        
        To find out the default action for each event, please see the event value descriptions.
        """
        self.frames.append(DefaultAction())
        return self
    def SendCardMsg(self, ) -> Self:
        """
        **Deprecated! Use SendMsg instead.**
        """
        self.frames.append(SendCardMsg())
        return self
    def SendMsg(self, MsgType: MessageType, MsgId: int, Protocol: ProtocolID) -> Self:
        """
        Sends the message which is stored in Scripts / StaticMessages / SendMessage with Value ID _MsgId_ to the host(s). The message is handled like an event of kind _MsgType_. 
        
        If _Protocol_ is 0, the message is sent to _all_ active protocols. Furthermore it will be transformed by the corresponding PostConvertTemplates. 
        
        If _Protocol_ is a protocol id, the message will be sent to this protocol only and _no_ (PostConvertTemplate-) conversion will be initiated.
        """
        self.frames.append(SendMsg(MsgType=MsgType, MsgId=MsgId, Protocol=Protocol))
        return self
    def SetTimer(self, TimerId: int, TimerValue: int) -> Self:
        """
        Activate/deactivate one of the three Timers. _TimerId_ is the ID of the timer to setup. The reader will wait _TimerValue_ / 10 seconds before starting the corresponding timer event. 
        
        If _TimerValue_ is 0, the timer will be deactivated. This means that the timer event will never be started. 
        
        **The actual expiration time of the timer may vary between _TimerValue_ \\- 100 ms and _TimerValue_ . If you need to ensure a minimum delay before the timer expires, add 100 ms. Example: To guarantee a dalay of at least 200 ms, set _TimerValue_ to 300 ms.**
        """
        self.frames.append(SetTimer(TimerId=TimerId, TimerValue=TimerValue))
        return self
    def SetVar(self, VarId: int) -> Self:
        """
        Set the global variable _VarId_ to True. _VarId_ has to be between 0 and 15.
        """
        self.frames.append(SetVar(VarId=VarId))
        return self
    def ClearVar(self, VarId: int) -> Self:
        """
        Set the global variable _VarId_ to False. _VarId_ has to be between 0 and 15.
        """
        self.frames.append(ClearVar(VarId=VarId))
        return self
    def AssignVar(self, VarId: int) -> Self:
        """
        Set the global variable _VarId_ to the top of the condition stack. _VarId_ has to be between 0 and 15. The top of the condition stack will be removed after assignment. 
        
        **Unlike all other commands, this command is executed in dependency of the second topmost flag on the condition stack, since the topmost flag is needed for the assignment.**
        """
        self.frames.append(AssignVar(VarId=VarId))
        return self
    def IfIoPort(self, CheckedIoPort: IoPort) -> Self:
        """
        Check if the input I/O-port _IoPort_ is currently high. If so, _true_ will be pushed into the top of the condition stack. Otherwise, _false_ will be pushed.
        """
        self.frames.append(IfIoPort(CheckedIoPort=CheckedIoPort))
        return self
    def IfVar(self, VarId: int) -> Self:
        """
        Push the state of global variable _VarId_ onto the top of the condition stack.
        """
        self.frames.append(IfVar(VarId=VarId))
        return self
    def IfProtocolEnabled(self, Protocol: ProtocolID) -> Self:
        """
        Check if _Protocol_ is currently active. If this is the case, True is pushed into the top of the condition stack. Otherwise False is pushed into the top of the condition stack.
        """
        self.frames.append(IfProtocolEnabled(Protocol=Protocol))
        return self
    def IfDip(self, DipId: int) -> Self:
        """
        Reads the state of the dip switch _DipId_ and pushes it into the top of the condition stack.
        """
        self.frames.append(IfDip(DipId=DipId))
        return self
    def IfState(self, StateId: int) -> Self:
        """
        Pushes _StateId_ , onto the top of the Condition Stack. _StateId_ is firmware-dependent if it is a number between 0 and 7. If _StateId_ is between 8 and 15, this command is identical to IfVar.
        """
        self.frames.append(IfState(StateId=StateId))
        return self
    def Not(self, ) -> Self:
        """
        Inverts the top of the condition stack. 
        
        **This command can also be used as ELSE-replacement: "IfVar 1 / Enable GreenLed / Not / Enable RedLed"**
        """
        self.frames.append(Not())
        return self
    def Or(self, ) -> Self:
        """
        Merges the two topmost flags on the condition stack into a single one by OR-ing them.
        """
        self.frames.append(Or())
        return self
    def And(self, ) -> Self:
        """
        Merges the two topmost flags on the condition stack into a single one by AND-ing them.
        """
        self.frames.append(And())
        return self
    def IfTrue(self, ) -> Self:
        """
        Pushes _true_ onto the top of the condition stack.
        """
        self.frames.append(IfTrue())
        return self
    def Trace(self, LogCode: int) -> Self:
        """
        This command can be used for debugging purposes. It outputs _LogCode_ as a 2-digit hex code on the debug interface.
        """
        self.frames.append(Trace(LogCode=LogCode))
        return self
    def Run(self, EventId: int) -> Self:
        """
        Can be used to stop the execution of the currently running script and continue with another script. The _ScriptId_ is the target Value ID within the Scripts / Events Key.
        """
        self.frames.append(Run(EventId=EventId))
        return self
    def RunSequence(self, Cmds: List[RunSequenceCmd]) -> Self:
        """
        This command allows to run complex switch sequences for IO-Ports. A switch sequence can be one or multiple (nested) loops (with separate timing each) that are controlling one or multiple different LEDs. 
        
        A sample for a switch sequence is: 
        
          1. toggle green LED 3 times with 10 Hz frequency
          2. enable red LED for 2 sec
          3. repeat from step 1 four times.
        
        
        
        **Currently it is not possible to run more than one switch sequence at the same time.**
        
        **All parameters of switch sequences (=frequencies, LED ids and repeat count) are static.**
        """
        self.frames.append(RunSequence(Cmds=Cmds))
        return self
class BRP(BRPBase, metaclass=abc.ABCMeta):
    """
    BRP (BALTECH Reader Protocol) is a simple point-to-point protocol (ISO/OSI layer 2) with a client-host architecture. It gives you maximum control over BALTECH readers, allowing you to execute the full range of supported commands. For a detailed description of commands, please refer to the commands reference.
    """
    CodeMap = {
        0x0001: CommandFrame,
        0x0002: ResponseFrame,
    }
    def CommandFrame(self, CheckSumAlgo: BRP_CommandFrame_CheckSumAlgo, UncompressedLength: bool, UncompressedCmdCode: bool, ExecutionMode: BRP_CommandFrame_ExecutionMode, CmdCode: Optional[int] = None, CmdCodeHigh: Optional[int] = None, CmdCodeLow: Optional[int] = None, *, LengthLow: int, LengthHigh: Optional[int] = None, Payload: bytes, ShortCheckSum: Optional[int] = None, LongCheckSum: Optional[int] = None) -> Self:
        """
        A command frame is sent by the host to initiate communication with the reader and invoke a command.
        """
        self.frames.append(CommandFrame(CheckSumAlgo=CheckSumAlgo, UncompressedLength=UncompressedLength, UncompressedCmdCode=UncompressedCmdCode, ExecutionMode=ExecutionMode, CmdCode=CmdCode, CmdCodeHigh=CmdCodeHigh, CmdCodeLow=CmdCodeLow, LengthLow=LengthLow, LengthHigh=LengthHigh, Payload=Payload, ShortCheckSum=ShortCheckSum, LongCheckSum=LongCheckSum))
        return self
    def ResponseFrame(self, Failure: bool, CriticialBootStatus: bool, CheckSumAlgo: BRP_ResponseFrame_CheckSumAlgo, UncompressedLength: bool, UncompressedCmdCode: bool, Phase: BRP_ResponseFrame_Phase, CmdCode: Optional[int] = None, CmdCodeHigh: Optional[int] = None, CmdCodeLow: Optional[int] = None, *, LengthLow: int, LengthHigh: Optional[int] = None, StatusCode: Optional[int] = None, Payload: Optional[bytes] = None, ShortCheckSum: Optional[int] = None, LongCheckSum: Optional[int] = None) -> Self:
        """
        After receiving a command frame, the reader responds with 1 or more response frames, depending on the execution mode. Response frames contain the requested response data or a status code, depending on the result of command execution.
        """
        self.frames.append(ResponseFrame(Failure=Failure, CriticialBootStatus=CriticialBootStatus, CheckSumAlgo=CheckSumAlgo, UncompressedLength=UncompressedLength, UncompressedCmdCode=UncompressedCmdCode, Phase=Phase, CmdCode=CmdCode, CmdCodeHigh=CmdCodeHigh, CmdCodeLow=CmdCodeLow, LengthLow=LengthLow, LengthHigh=LengthHigh, StatusCode=StatusCode, Payload=Payload, ShortCheckSum=ShortCheckSum, LongCheckSum=LongCheckSum))
        return self
class Template(TemplateBase, metaclass=abc.ABCMeta):
    """
    A Template defines a conversation rule how source data (i.e. VHL file) is converted to destination data. It consists of static data, which is copied 1:1 to the destination data and command which are replaced by variable data. 
    
    A TemplateCommand defines an area of variable content within a Template (the rest of the Template is static content, except the byte 0x1B, see _EscChar_ ). 
    
    variable content is fetched from one of the following sources: 
    
      * Part of the Source Data 
      * Serialnumber of the currently presented card (only available on Autoread Rules) 
      * Part of the already generated destination Buffer 
    
    
    
    The variable data that is inserted at the TemplateCommands location depends on the commandbyte that starts the TemplateCommand defintion and the command specific parameter that are following the command. The available commands are listed below (including a description of their parameters). 
    
    ` Template: "HDR" VarData 0001 02 NoFilter "TAIL" Sourcedata: "12345" Destinationdata: "HDR23TAIL" `
    """
    CodeMap = {
        0x1B1B: EscChar,
        0x1B01: VarData,
        0x1B03: VarDataClip,
        0x1B05: VarDataAlign,
        0x1B02: Serialnr,
        0x1B06: SerialnrAlign,
        0x1B07: Reconvert,
        0x1B04: CutNibbles,
        0x1B09: CutBits,
        0x1B08: Bcc,
        0x1B10: ContinueTmpl,
        0x1B0A: Encrypt,
        0x1B0B: ReaderSerialnr,
        0x1B0C: CardCounter,
        0x1B0D: Scramble,
        0x1B0E: Mark,
        0x1B0F: Strip,
        0x1B12: IsEqual,
        0x1B13: BitDataEnd,
        0x1B14: ExtractBitField,
        0x1B15: Sum,
        0x1B16: Align,
    }
    def EscChar(self, ) -> Self:
        """
        To include the Bytecode 0x1B into the static part of the template, this command has to be used. 
        
        ` Template: 12 EscChar 34 Destination data: 12 1B 34 `
        """
        self.frames.append(EscChar())
        return self
    def VarData(self, StartPos: int, Len: int, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> Self:
        """
        Copies the exact _Len_ bytes from source data, beginning at _StartPos_ , to the TemplateCommands location. 
        
        Before the data is inserted, it is converted using the filters specified in _Filters_. 
        
        **
        
          * If source data's length is less than _StartPos_ +_Len_ , the conversion with this template will fail (see also VarDataClip and VarDataAlign ).
          * This command is only supported for Autoread Templates . If used in protocol-specific templates, e.g. Protocols/BrpHid/HostMsgFormatTemplate , VarData works like VarDataClip .
        
        **
        """
        self.frames.append(VarData(StartPos=StartPos, Len=Len, Filters=Filters))
        return self
    def VarDataClip(self, StartPos: int, Len: int, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> Self:
        """
        Is identical to the _VarData_ TemplateCommand, except that it inserts the data also if the source data's length is shorter than _StartPos_ \\+ _Len_. In this case the inserted data will be shorter than _Len_
        
        **For Autoread Templates , this command is supported starting with firmware 1100 v2.20.00.**
        """
        self.frames.append(VarDataClip(StartPos=StartPos, Len=Len, Filters=Filters))
        return self
    def VarDataAlign(self, FillByte: int, StartPos: int, Len: int, Alignment: Alignment, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> Self:
        """
        Copies _Len_ bytes from source data, beginning at _StartPos_ , to the TemplateCommands location. 
        
        Is identical to the _VarData_ TemplateCommand, except that it accepts source data of variable length. It will extend/cut the source data depending on its length. 
        
        ` Template: VarDataAlign "_" 01 04 Right NoFilter Sourcedata: "1234" Destination data: "_234" `
        
        **For Autoread Templates , this command is supported starting with firmware 1100 v2.20.00.**
        """
        self.frames.append(VarDataAlign(FillByte=FillByte, StartPos=StartPos, Len=Len, Alignment=Alignment, Filters=Filters))
        return self
    def Serialnr(self, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> Self:
        """
        This command inserts the serialnumber of the currently processed card at the TemplateCommands location. Before inserting it, the filters in _Filters_ are applied. 
        
        **This command works only in Autoread Templates .**
        
        **The length of this field depends on the cardtype of the card that is presented.**
        """
        self.frames.append(Serialnr(Filters=Filters))
        return self
    def SerialnrAlign(self, Len: int, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> Self:
        """
        This command is identical to _Serialnr_ , except that it extends/cuts the serialnumber's length to match exactly _Len_ before applying the filter.
        """
        self.frames.append(SerialnrAlign(Len=Len, Filters=Filters))
        return self
    def Reconvert(self, Len: int, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> Self:
        """
        Using this command, _Filters_ can be applied again to the last generated Bytes. The size of the block to convert again can be spcified via _Len_ either by specifiying the number of Bytes or by setting it to _0xFF_ and set a marker (see command _Mark_ ). In the latter case all bytes from the marker to the end are reconverted. 
        
        ` Template: "xy15" Reconvert 2 AsciiToBin|BcdToHex|BinToAscii Destination data: "xy0F" `
        """
        self.frames.append(Reconvert(Len=Len, Filters=Filters))
        return self
    def CutNibbles(self, StartNibble: int, NibbleCount: int) -> Self:
        """
        **This command is deprecated. Please use ExtractBitField .**
        
        this command can remove data from the already generated Bytes. It works on nibble (half-byte) level. Thus all parameters are addressing nibbles not bytes. 
        
        _StartNibble_ specifies the address (beginning from the start of the destination data) of the first nibble to remove. _NibbleCount_ specifies the number of nibbles to remove. If an odd number of nibbles is removed, a 0-nibble is inserted into the Least-significant-nibble at the end of destination data. 
        
        ` Template: 12 34 56 CutNibbles 0001 3 Destination data: 15 60 `
        """
        self.frames.append(CutNibbles(StartNibble=StartNibble, NibbleCount=NibbleCount))
        return self
    def CutBits(self, StartBit: int, BitCount: int, Bitorder: TemplateBitorder) -> Self:
        """
        **This command is deprecated. Please use ExtractBitField .**
        
        This command is identical to _CutNibbles_ , but works on bit level instead of nibble level. 
        
        Depending on _Bitorder_ all values are considered as MSB-values or LSB values. In case they are are considered as MSB this means bit position 0 corresponds to byte value 0x80 and bit position 7 corresponds to byte value 0x01. 
        
        **If the number of remaining bits is not multiple of eight, the template will be filled with 0-bits at the end to ensure that the it matches the next byte boundary.**
        
        ` Template: FF 01 CutNibbles 0006 7 Destination data: FC 80 `
        """
        self.frames.append(CutBits(StartBit=StartBit, BitCount=BitCount, Bitorder=Bitorder))
        return self
    def Bcc(self, StartPos: int, Len: int, InitValue: int, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> Self:
        """
        This Command calculates a XOR-8bit-BCC over some bytes of the already generated destination data. The bytes to include into this calculation are specified by _StartPos_ and _Len_ , which are specifying the first byte beginning from the destination data and the number of bytes. 
        
        After all bytes are XORed the InitValue will be XORed to the result. Then all filters specified in _Filters_ will be applied and the result stored at the TemplateCommand location. 
        
        **If a marker is set,_StartPos_ will be ignored and the marker position will be used as start instead (without removing the marker from the marker stack). If furthermore _Len_ is 0xFF, all data up to the end of the destination data will be included in the BCC calculation and the marker will be removed from the marker stack.**
        
        ` Template: 0xFF 0x08 0x10 0xFF Bcc 0001 2 0x40 NoFilter Destination data: 0xFF 0x08 0x10 0xFF 0x58 `
        """
        self.frames.append(Bcc(StartPos=StartPos, Len=Len, InitValue=InitValue, Filters=Filters))
        return self
    def ContinueTmpl(self, TemplateValueId: int) -> Self:
        """
        Since configuration values must not exceed 128 Bytes very complex Templates might not fit within a single value. To overcome this limitation this command allows to extend this template by another one within the same subkey. The value ID of the extension template must be specified in _TemplateValueId_. Use TemplateExt1 or TemplateExt2. 
        
        Theoretically an arbitrary number of values may be concatenated to a single template this way. In practice the only limitation is the maximum size of destination data supported by the firmware.
        """
        self.frames.append(ContinueTmpl(TemplateValueId=TemplateValueId))
        return self
    def Encrypt(self, Len: int, CryptoMode: Template_Encrypt_CryptoMode, Key: int) -> Self:
        """
        This command encrypts the last generated bytes of the destination data. The number of concerned bytes is specified in _Len_ and has to be either the count of bytes or 0xFF, in which case all bytes from the last _Mark_ Command to the end are encrypted. 
        
        The used Cryptoalgorithm is TripleDES. The _Cryptomode_ specifies the used cryptomode. If the number of bytes to encrypt is not a multiple of 8, the missing bytes will be filled with 0 at the end. 
        
        The _Key_ Key specifies a valueid within the subkey where the template is stored. This value contains a 16byte Key, that shall be used for encryption. 
        
        **The _Key_ should be > 0x80 to ensure security (values < 0x80 can be read out)**
        """
        self.frames.append(Encrypt(Len=Len, CryptoMode=CryptoMode, Key=Key))
        return self
    def ReaderSerialnr(self, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> Self:
        """
        Inserts the reader serialnumber as 8 byte decimal ASCII number. Before finally inserting the data, filters specified in _Filters_ will be applied.
        """
        self.frames.append(ReaderSerialnr(Filters=Filters))
        return self
    def CardCounter(self, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> Self:
        """
        Inserts a counter that increases everytime the template is used to convert data (i.e. everytime a card is presented in autoread mode). The counter is inserted as 4 byte binary number that is converted by the specified filters in _Filters_.
        """
        self.frames.append(CardCounter(Filters=Filters))
        return self
    def Scramble(self, Len: int, NoRepeat: bool, PadZero: bool, AlignRight: bool, SourceSubBlockBits: int, BitMap: List[Template_Scramble_BitMap_Entry], Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> Self:
        """
        **This command should only be required in very rare cases. Usually ExtractBitField is a better and much more simpler option.**
        
        Using this command, the bits of the last generated Bytes can be scrambled/inverted in any fashion. The main steps of this command are: 
        
          1. Determine the data that shall be scrambled. Either the last _Len_ bytes are used, or (if _Len_ is 0xFF) all bytes from the last marker (see _Mark_ command) to the end are used. This data is used as source data and will be replaced. 
          2. Split the resulting block into sub-blocks, that all are of length _SourceSubBlockBits_. If _Len_ * 8 is not multiple of _SourceSubBlockBits_ the remaining bits in the source data are ignored by default. Alternatively the ScrambleOptions can be used to set "PadZero". In this case the remaining bits of the source data are extended by 0-bits until the length of the remaining block is _SourceSubBlockBits_ and thus can be processed. 
          3. Every source block is scrambled by generating a destination block. This destination block is of the same size as the _BitMap_ array. _BitMap_ specifies a mapping of source bits to destination bits. This mapping is applied to every source block and results in a corresponding destination block 
          4. The scrambled destination blocks are concatenated again. If the total number of bits in all destination blocks is not a multiple of 8, padding zero bits are appended, until the number of bits is exactly a multiple of 8. 
          5. The filters specified in _Filters_ are applied to the resulting content. 
        
        
        
        The most regular use case of this command is cutting a bitfield out of the source data without the requirement of repetitions. The following command shows a sample, that cuts a field of 4 bits starting at bit index 6 from the source data and converts it to a 4 digit ASCII decimal number. 
        
        ` {optionally some data before scramble} Mark {template to be scrambled} Scramble 0xFF 'scramble all data between Mark and Scramble' NoRepeat 'Do a simple scramble without multiple blocks' 16 'scramble the first 16 bits of {variable-data}' 8 'the scrambled data should be a multiple of 8!' 0x7F 0x7F 0x7F 0x7F 6 7 8 9 '4 leading zeros, then bytes 6-9 of source data' Bin2Bcd|Unpack|Bin2Ascii 'convert data to ASCII decimal' `
        """
        self.frames.append(Scramble(Len=Len, NoRepeat=NoRepeat, PadZero=PadZero, AlignRight=AlignRight, SourceSubBlockBits=SourceSubBlockBits, BitMap=BitMap, Filters=Filters))
        return self
    def Mark(self, ) -> Self:
        """
        This is used as position marker for the commands _Reconvert_ , _Encrypt_ , _Bcc_ , _Strip_ , _Scramble_ , and _Sum_ when they have no _Len_ parameter specified but use 0xFF as length. 
        
        Mark pushes the current position within the destination data onto a internal stack. When one of the above commands (with _Len_ parameter is 0xFF) is detected, it removes the top position from the stack. Then all data from this removed position to the end of the destination data is processed. 
        
        **If one the above commands (with _Len_ parameter is 0xFF) is detected and the internal position stack is empty (No matching _Mark_ command found), all destination data (from byte 0 to the current end) will be processed.**
        
        **The stack size for Mark commands is 4. If more than 4 positions are pushed by Mark commands without removing one from the top of the stack the "oldest" position gets lost. On 12.06.18 the stack size was increased from 2 to 4!**
        
        ` Template: 12 Mark 34 Mark 56 Reconvert UnPack Reconvert Unpack 78 Destination data before first Reconvert: 12 34 56 Destination data after first Reconvert: 12 34 05 06 Destination data after second Reconvert: 12 03 04 00 05 00 06 Destination data after finish: 12 03 04 00 05 00 06 78 `
        """
        self.frames.append(Mark())
        return self
    def Strip(self, Len: int, Leading: bool, Middle: bool, Trailing: bool, RemoveChar: int) -> Self:
        """
        This command removes characters of a specific value. The area to strip is defined by _Len_. Either the last _Len_ bytes are stripped, or (if _Len_ is 0xFF) all bytes from the last marker (see _Mark_ command) to the end are stripped. 
        
        The character to remove can be specfied by RemoveChar (is usually "0"). StripOptions specify if leading or trailing characters shall be removed
        """
        self.frames.append(Strip(Len=Len, Leading=Leading, Middle=Middle, Trailing=Trailing, RemoveChar=RemoveChar))
        return self
    def IsEqual(self, ActionOnSuccess: Template_IsEqual_ActionOnSuccess, ConstData: str) -> Self:
        """
        This command checks if the last converted bytes are equal to _ConstData_. If this is not the case, the conversion of the template is cancelled. 
        
        The number of compared bytes is determined by the length of _ConstData_. This means that the comparing operation is done until _ConstData_ ends with a zero byte. 
        
        **It is strongly recommended to convert the data always to ASCII before comparing it with IsEqual. Otherwise the user had to ensure that "ConstData" contains no zero byte, as it would be interpreted as String terminator.**
        
        If the number of bytes already converted is lower than the length of _ConstData_ , the conversion is cancelled.
        """
        self.frames.append(IsEqual(ActionOnSuccess=ActionOnSuccess, ConstData=ConstData))
        return self
    def BitDataEnd(self, SrcDataBitOrder: TemplateBitorder) -> Self:
        """
        If the source data (i.e. the data to be read from the card) is bitwise organized the Template rendering is split into two phases: 
        
          1. The first phase retrieves the bit data from the data source (i.e. card; usually done by VarData or Serialnr) 
          2. The second phase converts the bit data returned by the first phase into ASCII data (Usually done by ExtractBitField) 
        
        
        
        This command delimits the template for phase one (the template-description before this command) from the template for the second phase (the template-description after this command). The returned result is only the result from phase 2! 
        
        For the rare case that this command does not fulfil your requirements please use Scramble. 
        
        **This commmand must occur at maximum once per template.**
        """
        self.frames.append(BitDataEnd(SrcDataBitOrder=SrcDataBitOrder))
        return self
    def ExtractBitField(self, SrcFieldStartBit: int, SrcFieldBits: int, Filter: Union[TemplateFilter, TemplateFilter_Dict], DstFieldBytes: int) -> Self:
        """
        This command includes a bit field from the source data (phase 1) and converts it into an ASCII number. It can only be used after a preceding phase 1, see BitDataEnd. 
        
        **The resulting number is returned with the most significant digits first. LSB-encoded source data will be converted automatically.**
        
        The following sample cuts bits 1-6, converts them to ASCII, and extends the number to 4 digits. This results in "0016". 
        
        ` 0x5A BitDataEnd Msb ExtractBitField 0001 5 Unpack|BinToAscii 4 `
        
        The next sample shows the difference between the MSB- and the LSB-first encoding. This command outputs "3456" as it is, but by specifying _BitDataEnd Lsb_ instead, we would obtain "5634", since the input is interpreted as "0x78563412". 
        
        ` 0x12345678 BitDataEnd Msb ExtractBitField 0008 16 Unpack|BinToAscii 0 `
        """
        self.frames.append(ExtractBitField(SrcFieldStartBit=SrcFieldStartBit, SrcFieldBits=SrcFieldBits, Filter=Filter, DstFieldBytes=DstFieldBytes))
        return self
    def Sum(self, StartPos: int, Len: int, InitValue: int, Filters: Union[TemplateFilter, TemplateFilter_Dict]) -> Self:
        """
        This command calculates the 8-bit sum over some bytes of the already generated destination data. The bytes to include into this calculation are specified by _StartPos_ and _Len_ , which specify the first byte beginning from the destination data and the number of bytes. 
        
        InitValue will be added to the sum of the specified bytes. Then all filters specified in _Filters_ will be applied and the result will be stored at the TemplateCommand location. 
        
        **If a marker is set,_StartPos_ will be ignored and the marker position will be used as start instead (without removing the marker from the marker stack). If furthermore _Len_ is 0xFF, all data up to the end of the destination data will be included in the calculation and the marker will be removed from the marker stack.**
        
        ` Template: 0xFF 0x08 0x19 0xFF Sum 0001 2 0x40 NoFilter Destination data: 0xFF 0x08 0x19 0xFF 0x61 `
        """
        self.frames.append(Sum(StartPos=StartPos, Len=Len, InitValue=InitValue, Filters=Filters))
        return self
    def Align(self, FillByte: int, DestLen: int, Alignment: Alignment) -> Self:
        """
        This command aligns the last generated bytes of destination data. Depending on the required destination length, data is clipped or extended. 
        
        **If a marker is set, the marker position will be used as the start position for the data to be aligned. Otherwise, all available data will be aligned.**
        
        ` Template: 0x12 0x34 Align 0x00 5 Right Destination data: 0x00 0x00 0x00 0x12 0x34 `
        """
        self.frames.append(Align(FillByte=FillByte, DestLen=DestLen, Alignment=Alignment))
        return self
__all__: list[str] = [
    "BaltechScript",
    "Enable",
    "Disable",
    "Toggle",
    "ToggleInverted",
    "DefaultAction",
    "SendCardMsg",
    "SendMsg",
    "SetTimer",
    "SetVar",
    "ClearVar",
    "AssignVar",
    "IfIoPort",
    "IfVar",
    "IfProtocolEnabled",
    "IfDip",
    "IfState",
    "Not",
    "Or",
    "And",
    "IfTrue",
    "Trace",
    "Run",
    "RunSequence",
    "BRP",
    "CommandFrame",
    "ResponseFrame",
    "Template",
    "EscChar",
    "VarData",
    "VarDataClip",
    "VarDataAlign",
    "Serialnr",
    "SerialnrAlign",
    "Reconvert",
    "CutNibbles",
    "CutBits",
    "Bcc",
    "ContinueTmpl",
    "Encrypt",
    "ReaderSerialnr",
    "CardCounter",
    "Scramble",
    "Mark",
    "Strip",
    "IsEqual",
    "BitDataEnd",
    "ExtractBitField",
    "Sum",
    "Align",
]