From e43bce73b3299462a309a5325a83965a647877fc Mon Sep 17 00:00:00 2001 From: Adrian Stanea Date: Thu, 23 May 2024 15:35:58 +0300 Subject: [PATCH] Add decoder for AD5593R Signed-off-by: Adrian Stanea --- decoders/ad5593r/__init__.py | 30 ++ decoders/ad5593r/lists.py | 636 +++++++++++++++++++++++++++++++++++ decoders/ad5593r/pd.py | 255 ++++++++++++++ 3 files changed, 921 insertions(+) create mode 100644 decoders/ad5593r/__init__.py create mode 100644 decoders/ad5593r/lists.py create mode 100644 decoders/ad5593r/pd.py diff --git a/decoders/ad5593r/__init__.py b/decoders/ad5593r/__init__.py new file mode 100644 index 00000000..14d6ee18 --- /dev/null +++ b/decoders/ad5593r/__init__.py @@ -0,0 +1,30 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2024 Analog Devices Inc. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see . +## + +''' + The Analog Devices AD5593R is a 12-bit ADC/DAC with 8 channels that + operates over an I2C interface. + + This decoder stacks on top of the 'i2c' PD and decodes the AD5593R operations. + + Details: + https://www.analog.com/media/en/technical-documentation/data-sheets/ad5593r.pdf +''' + +from .pd import Decoder \ No newline at end of file diff --git a/decoders/ad5593r/lists.py b/decoders/ad5593r/lists.py new file mode 100644 index 00000000..03604a84 --- /dev/null +++ b/decoders/ad5593r/lists.py @@ -0,0 +1,636 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2024 Analog Devices Inc. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see . +## + +from dataclasses import dataclass +from typing import Callable, List, Optional, Union + +CONFIG_MODE_BITS_MAP = { + 0b0000: "NOP", + 0b0010: "ADC_SEQ", + 0b0011: "GEN_CTRL_REG", + 0b0100: "ADC_CONFIG", + 0b0101: "DAC_CONFIG", + 0b0110: "PULLDWN_CONFIG", + 0b0111: "LDAC_MODE", + 0b1000: "GPIO_CONFIG", + 0b1001: "GPIO_OUTPUT", + 0b1010: "GPIO_INPUT", + 0b1011: "PD_REF_CTRL", + 0b1100: "GPIO_OPENDRAIN_CONFIG", + 0b1101: "IO_TS_CONFIG", + 0b1111: "SW_RESET", +} + +REG_SEL_RD_MAP = { + 0b0000: "NOP", + 0b0010: "ADC_SEQ", + 0b0011: "GEN_CTRL_REG", + 0b0100: "ADC_CONFIG", + 0b0101: "DAC_CONFIG", + 0b0110: "PULLDWN_CONFIG", + 0b0111: "LDAC mode", + 0b1000: "GPIO_CONFIG", + 0b1001: "GPIO_OUTPUT", + 0b1010: "GPIO_INPUT", + 0b1011: "PD_REF_CTRL", + 0b1100: "GPIO_OPENDRAIN_CONFIG", + 0b1101: "IO_TS_CONFIG", +} + + +# Utility functions: parse register fields +def DAC_chn(x: int) -> str: + return f"DAC{x}" + + +def ADC_chn(x: int) -> str: + return f"ADC{x}" + + +def decimal_to_hex(x: int) -> str: + return f"0x{x:02X}" + + +def empty_str(x: int) -> str: + return "" + + +def disabled_enabled(x: int) -> str: + return ["Disabled", "Enabled"][x] + + +def vref_range(x: int) -> str: + return "0V to {text}".format(text=["Vref", "2xVref"][x]) + + +def bit_indices(num: int): + """Given an number this function extracts the bit indices where the bits are set to 1 and returns them as a string. + LSB has index 0. + """ + res = [] + i = 0 + while num: + if num & 1: + res.append(str(i)) + num >>= 1 + i += 1 + if res: + return ",".join(res) + else: + return "NONE" + + +@dataclass +class Field: + start_bit: int + width: int + name: str + parser: Optional[Callable[[int], str]] + + +@dataclass +class Register: + opcode: Union[str, int] + name: str + fields: List[Field] + + +# Stores register objects which can be retrieved by the opcode as a key. +# The opcode can be extracted from the raw byte. +class RegisterDict(dict): + def __setitem__(self, opcode, register): + if not isinstance(register, Register): + raise ValueError("Value must be an instance of Register") + super().__setitem__(opcode, register) + + def __getitem__(self, opcode): + register = super().__getitem__(opcode) + return register + + def get_pointer_byte_register(self) -> Field: + return Field(start_bit=4, width=4, name="Pointer byte bits", parser=None) + + +# 8b registers used to determine the type of operation to be performed by the AD5593R when subsequent data bytes arrive +POINTER_BYTE_MAP = RegisterDict() + +POINTER_BYTE_MAP[0x00] = Register( + opcode=0x00, + name="CONFIG_MODE_POINTER", + fields=[ + Field( + start_bit=0, + width=4, + name="CONFIG_MODE_BITS", + parser=lambda x: CONFIG_MODE_BITS_MAP.get(x, "UNKNOWN"), + ), + Field( + start_bit=4, + width=4, + name="CONFIG_MODE_SEL", + parser=decimal_to_hex, + ), + ], +) + +POINTER_BYTE_MAP[0x01] = Register( + opcode=0x01, + name="DAC_WR_POINTER", + fields=[ + Field( + start_bit=0, + width=4, + name="DAC_CH_SEL_WR", + parser=DAC_chn, + ), + Field( + start_bit=4, + width=4, + name="DAC_WR_SEL", + parser=decimal_to_hex, + ), + ], +) + +POINTER_BYTE_MAP[0x04] = Register( + opcode=0x04, + name="ADC_RD_POINTER", + fields=[ + Field( + start_bit=0, + width=4, + name="RESERVED", + parser=empty_str, + ), + Field( + start_bit=4, + width=4, + name="ADC_RD_SEL", + parser=decimal_to_hex, + ), + ], +) + +POINTER_BYTE_MAP[0x05] = Register( + opcode=0x05, + name="DAC_RD_POINTER", + fields=[ + Field( + start_bit=0, + width=4, + name="DAC_CH_SEL_RD", + parser=DAC_chn, + ), + Field( + start_bit=4, + width=4, + name="DAC_RD_SEL", + parser=decimal_to_hex, + ), + ], +) + +POINTER_BYTE_MAP[0x06] = Register( + opcode=0x06, + name="GPIO_RD_POINTER", + fields=[ + Field( + start_bit=0, + width=4, + name="RESERVED", + parser=empty_str, + ), + Field( + start_bit=4, + width=4, + name="GPIO_RD_SEL", + parser=decimal_to_hex, + ), + ], +) + +POINTER_BYTE_MAP[0x07] = Register( + opcode=0x07, + name="REG_RD_POINTER", + fields=[ + Field( + start_bit=0, + width=4, + name="DAC_CH_SEL_WR", # Select control register for readback + parser=lambda x: REG_SEL_RD_MAP.get(x, "UNKNOWN"), + ), + Field( + start_bit=4, + width=4, + name="REG_RD_SEL", + parser=decimal_to_hex, + ), + ], +) + + +REGISTER_DESCRIPTOR_MAP = RegisterDict() + +REGISTER_DESCRIPTOR_MAP["NOOP"] = Register( + opcode="NOOP", + name="NOOP", + fields=[ + Field( + start_bit=0, + width=11, + name="No operation", + parser=empty_str, + ), + Field( + start_bit=11, + width=5, + name="RESERVED", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["ADC_SEQ"] = Register( + opcode="ADC_SEQ", + name="ADC_SEQ", + fields=[ + Field( + start_bit=0, + width=8, + name="ADC channels", + parser=bit_indices, + ), + Field( + start_bit=8, + width=1, + name="Temperature Indicator", + parser=disabled_enabled, + ), + Field( + start_bit=9, + width=1, + name="Repeat", + parser=disabled_enabled, + ), + Field( + start_bit=10, + width=6, + name="RESERVED", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["GEN_CTRL_REG"] = Register( + opcode="GEN_CTRL_REG", + name="GEN_CTRL_REG", + fields=[ + Field( + start_bit=0, + width=4, + name="RESERVED", + parser=empty_str, + ), + Field( + start_bit=4, + width=1, + name="DAC_RANGE", + parser=vref_range, + ), + Field( + start_bit=5, + width=1, + name="ADC_RANGE", + parser=vref_range, + ), + Field( + start_bit=6, + width=1, + name="ALL_DAC", + parser=disabled_enabled, + ), + Field( + start_bit=7, + width=1, + name="IO_LOCK", + parser=disabled_enabled, + ), + Field( + start_bit=8, + width=1, + name="ADC_BUF_EN", + parser=disabled_enabled, + ), + Field( + start_bit=9, + width=1, + name="ADC_BUF_PRECH", + parser=disabled_enabled, + ), + Field( + start_bit=10, + width=6, + name="RESERVED", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["ADC_CONFIG"] = Register( + opcode="ADC_CONFIG", + name="ADC_CONFIG", + fields=[ + Field( + start_bit=0, + width=8, + name="ADC input pins", + parser=bit_indices, + ), + Field( + start_bit=8, + width=8, + name="RESERVERD", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["DAC_CONFIG"] = Register( + opcode="DAC_CONFIG", + name="DAC_CONFIG", + fields=[ + Field( + start_bit=0, + width=8, + name="DAC output pins", + parser=bit_indices, + ), + Field( + start_bit=8, + width=8, + name="RESERVERD", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["PULLDWN_CONFIG"] = Register( + opcode="PULLDWN_CONFIG", + name="PULLDWN_CONFIG", + fields=[ + Field( + start_bit=0, + width=8, + name="Weak-pulldown output pins", + parser=bit_indices, + ), + Field( + start_bit=8, + width=8, + name="RESERVERD", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["LDAC_MODE"] = Register( + opcode="LDAC_MODE", + name="LDAC_MODE", + fields=[ + Field( + start_bit=0, + width=2, + name="LDAC_MODE", + parser=decimal_to_hex, + ), + Field( + start_bit=2, + width=14, + name="RESERVERD", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["GPIO_CONFIG"] = Register( + opcode="GPIO_CONFIG", + name="GPIO_CONFIG", + fields=[ + Field( + start_bit=0, + width=8, + name="GPIO output pins", + parser=bit_indices, + ), + Field( + start_bit=8, + width=8, + name="RESERVERD", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["GPIO_OUTPUT"] = Register( + opcode="GPIO_OUTPUT", + name="GPIO_OUTPUT", + fields=[ + Field( + start_bit=0, + width=8, + name="GPIO high pins", + parser=bit_indices, + ), + Field( + start_bit=8, + width=8, + name="RESERVERD", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["GPIO_INPUT"] = Register( + opcode="GPIO_INPUT", + name="GPIO_INPUT", + fields=[ + Field( + start_bit=0, + width=8, + name="GPIO input pins", + parser=bit_indices, + ), + Field( + start_bit=8, + width=8, + name="RESERVERD", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["PD_REF_CTRL"] = Register( + opcode="PD_REF_CTRL", + name="PD_REF_CTRL", + fields=[ + Field( + start_bit=0, + width=8, + name="DAC power-down pins", + parser=bit_indices, + ), + Field( + start_bit=8, + width=1, + name="RESERVED", + parser=empty_str, + ), + Field( + start_bit=9, + width=1, + name="EN_REF", + parser=disabled_enabled, + ), + Field( + start_bit=10, + width=1, + name="PD_ALL", + parser=disabled_enabled, + ), + Field( + start_bit=11, + width=5, + name="RESERVED", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["GPIO_OPENDRAIN_CONFIG"] = Register( + opcode="GPIO_OPENDRAIN_CONFIG", + name="GPIO_OPENDRAIN_CONFIG", + fields=[ + Field( + start_bit=0, + width=8, + name="GPIO open-drain pins", + parser=bit_indices, + ), + Field( + start_bit=8, + width=8, + name="RESERVERD", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["IO_TS_CONFIG"] = Register( + opcode="IO_TS_CONFIG", + name="IO_TS_CONFIG", + fields=[ + Field( + start_bit=0, + width=8, + name="Three-state output pins", + parser=bit_indices, + ), + Field( + start_bit=8, + width=8, + name="RESERVERD", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["SW_RESET"] = Register( + opcode="SW_RESET", + name="SW_RESET", + fields=[ + Field( + start_bit=0, + width=11, + name="Reset command", + parser=decimal_to_hex, + ), + Field( + start_bit=11, + width=5, + name="RESERVERD", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["DAC_WR"] = Register( + opcode="DAC_WR", + name="DAC_WR", + fields=[ + Field(start_bit=0, width=12, name="DAC data", parser=None), + Field( + start_bit=12, + width=4, + name="RESERVERD", + parser=empty_str, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["DAC_DATA_RD"] = Register( + opcode="DAC_DATA_RD", + name="DAC_DATA_RD", + fields=[ + Field(start_bit=0, width=12, name="DAC_DATA", parser=None), + Field( + start_bit=12, + width=3, + name="DAC_ADDR", + parser=DAC_chn, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["ADC_RESULT"] = Register( + opcode="ADC_RESULT", + name="ADC_RESULT", + fields=[ + Field(start_bit=0, width=12, name="ADC_DATA", parser=None), + Field( + start_bit=12, + width=3, + name="ADC_ADDR", + parser=ADC_chn, + ), + ], +) + +REGISTER_DESCRIPTOR_MAP["TMP_SENSE_RESULT"] = Register( + opcode="TMP_SENSE_RESULT", + name="TMP_SENSE_RESULT", + fields=[ + Field(start_bit=0, width=12, name="ADC_DATA", parser=None), + Field( + start_bit=12, + width=4, + name="TMPSENSE_ADDR", + parser=decimal_to_hex, + ), + ], +) diff --git a/decoders/ad5593r/pd.py b/decoders/ad5593r/pd.py new file mode 100644 index 00000000..520dfe30 --- /dev/null +++ b/decoders/ad5593r/pd.py @@ -0,0 +1,255 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2024 Analog Devices Inc. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see . +## + +import sigrokdecode as srd + +from common.srdhelper import SrdIntEnum, bitpack_lsb +from .lists import ( + POINTER_BYTE_MAP, + REGISTER_DESCRIPTOR_MAP, + Field, + Register, +) +from typing import List + + +(OPERATION_WRITE, OPERATION_READ) = range(2) +Ann = SrdIntEnum.from_str("Ann", "REGISTER FIELD POINTER_BYTE SLAVE_ADDR DATA_BYTE WARNING") + + +class Decoder(srd.Decoder): + api_version = 3 + id = "ad5593r" + name = "AD5593R" + longname = "Analog Devices AAD5593" + desc = "Analog Devices AD5593R 12-bit configurable ADC/DAC." + license = "gplv3+" + inputs = ["i2c"] + outputs = [] + tags = ["IC", "Analog/digital"] + options = ({"id": "Vref", "desc": "Reference voltage (V)", "default": 2.5},) + annotations = ( + ("register", "Register"), + ("field", "Field"), + ("ptr_byte", "Pointer Byte"), + ("slave_addr", "Slave Address"), + ("data_byte", "Data Byte"), + ("warning", "Warning"), + ) + annotation_rows = ( + ("packet", "Packets", (Ann.POINTER_BYTE, Ann.SLAVE_ADDR, Ann.WARNING, Ann.DATA_BYTE)), + ("registers", "Registers", (Ann.REGISTER,)), + ("fields", "Fields", (Ann.FIELD,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = "IDLE" + # Delimiter of 8b I2C block + self.ss = -1 + self.es = -1 + # I2C transaction over multiple 8b blocks + self.ss_block = -1 + self.es_block = -1 + # Internal buffer + self.bits = [] + self.IO_operation_type = -1 + # Databyte format which is determined by the pointer byte + self.databyte_register = "" + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putg(self, ss, es, ann_idx, data): + # Annotates a bit field of an I²C packet + self.put(ss, es, self.out_ann, [ann_idx, data]) + + def decode_field(self, bits, name, offset, width, parser=None): + val, (ss, es) = self.bit_slice_to_int(bits, offset, width) + formatted = parser(val) if parser else "{}".format(val) + if formatted is not None and formatted != "": + text = "{name}: {val}".format(name=name, val=formatted) + else: + text = "{name}".format(name=name) + self.putg(ss, es, Ann.FIELD, [text]) + + def handle_slave_addr(self, data): + if data not in (0b0010000, 0b0010001): + ann = "I²C slave is not compatible." + self.putg(self.ss, self.es, Ann.WARNING, [ann]) + else: + ann = ["I²C Slave address", "I²C Slave"] + self.putg(self.ss, self.es, Ann.SLAVE_ADDR, ann) + + def handle_databyte_decode_state(self, register: Register, data: List[int]): + # Handle state and determine how to parse the incomming data byte + if register.name == "CONFIG_MODE_POINTER": + # Only 1 match is expected in the list of fields. Then we extract the field from the list. + CONFIG_MODE_BIT_FIELD = [field for field in register.fields if field.name == "CONFIG_MODE_BITS"][0] + field_val, (_, _) = self.bit_slice_to_int( + data, CONFIG_MODE_BIT_FIELD.start_bit, CONFIG_MODE_BIT_FIELD.width + ) + self.databyte_register = ( + CONFIG_MODE_BIT_FIELD.parser(field_val) if CONFIG_MODE_BIT_FIELD.parser is not None else "UNKNOWN" + ) + if self.databyte_register == "UNKNOWN": + raise ValueError("Unknown CONFIG_MODE_BITS value") + elif register.name == "DAC_WR_POINTER": + self.databyte_register = "DAC_WR" + elif register.name == "ADC_RD_POINTER": + self.databyte_register = "ADC_RESULT" + elif register.name == "DAC_RD_POINTER": + self.databyte_register = "DAC_DATA_RD" + elif register.name == "GPIO_RD_POINTER": + if self.IO_operation_type == OPERATION_WRITE: + self.databyte_register = "GPIO_INPUT" + if self.IO_operation_type == OPERATION_READ: + self.databyte_register = "GPIO_OUTPUT" + elif register.name == "REG_RD_POINTER": + # Only 1 match is expected in the list of fields. Then we extract the filed from the list. + REG_SEL_RD_FIELD = [field for field in register.fields if field.name == "CONFIG_MODE_BITS"][0] + field_val, (_, _) = self.bit_slice_to_int(data, REG_SEL_RD_FIELD.start_bit, REG_SEL_RD_FIELD.width) + self.databyte_register = ( + REG_SEL_RD_FIELD.parser(field_val) if REG_SEL_RD_FIELD.parser is not None else "UNKNOWN" + ) + if self.databyte_register == "UNKNOWN": + raise ValueError("Unknown CONFIG_MODE_BITS value") + + def handle_pointer_byte(self, bits: List): + opcode_field: Field = POINTER_BYTE_MAP.get_pointer_byte_register() + opcode, (_, _) = self.bit_slice_to_int(bits, offset=opcode_field.start_bit, width=opcode_field.width) + self.putg(self.ss, self.es, Ann.POINTER_BYTE, ["Pointer Byte", "Ptr Byte"]) + try: + register: Register = POINTER_BYTE_MAP[opcode] + self.putg(self.ss, self.es, Ann.REGISTER, [register.name]) + # Handle annotations + for field in register.fields: + self.decode_field(bits, field.name, field.start_bit, field.width, field.parser) + self.handle_databyte_decode_state(register, bits) + except Exception as e: + return + + def handle_data_bytes(self, bits: List[int]) -> None: + try: + register: Register = REGISTER_DESCRIPTOR_MAP[self.databyte_register] + self.putg(self.ss_block, self.es_block, Ann.REGISTER, [register.name]) + + for field in register.fields: + self.decode_field(bits, field.name, field.start_bit, field.width, field.parser) + except Exception as e: + return + + def store_bits(self, bits: List[int]): + """ + Bits are stored in the decoder's data buffer in MSB order, index 0 corresponding to the MSB. + This storage order facilitates extension with new 8-bit chunks. + For annotation, we parse from LSB (Least Significant Bit) to MSB, which involves reversing the list again. + """ + copy_bits = bits.copy() + copy_bits.reverse() + self.bits.extend(copy_bits) + + def bit_slice_to_int(self, bits, offset, width): + bits = bits[offset:][:width] # take a slice of the bits + ss, es = bits[-1][1], bits[0][2] + value = bitpack_lsb(bits, 0) + return ( + value, + ( + ss, + es, + ), + ) + + def process_IO_operation(self, bits): + # Extracted from the address slave packet. + LSB, _, _ = bits[0] + return LSB + + def get_start_sample(self, bits, idx=0): + bit, ss, es = bits[idx] + return ss + + def get_end_sample(self, bits, idx=-1): + bit, ss, es = bits[idx] + return es + + def decode(self, ss, es, data): + ptype, pdata = data + + # STOP resets the state machine + if ptype == "STOP": + self.state = "IDLE" + self.bits = [] + return + + # State machine + if self.state == "IDLE": + if ptype not in ("START"): + self.state = "IDLE" + return + self.state = "GET SLAVE ADDR" + elif self.state == "GET SLAVE ADDR": + if ptype == "BITS": + self.ss = self.get_start_sample(pdata, idx=-1) + self.es = self.get_end_sample(pdata, idx=1) + self.IO_operation_type = self.process_IO_operation(pdata) + if ptype in ("ADDRESS READ", "ADDRESS WRITE"): + self.handle_slave_addr(pdata) + if ptype == "ACK" and self.IO_operation_type == OPERATION_WRITE: + self.state = "GET POINTER BYTE" + if ptype == "ACK" and self.IO_operation_type == OPERATION_READ: + self.state = "GET DATA HIGH" + elif self.state == "GET POINTER BYTE": + if ptype == "BITS": + self.ss = self.get_start_sample(pdata, idx=-1) + self.es = self.get_end_sample(pdata, idx=0) + self.store_bits(pdata) + if ptype in ("DATA WRITE", "DATA READ"): + self.bits.reverse() + self.handle_pointer_byte(self.bits) + self.bits = [] + if ptype == "ACK": + self.state = "GET DATA HIGH" + elif self.state == "GET DATA HIGH": + if ptype == "BITS": + self.ss_block = self.get_start_sample(pdata, idx=-1) + self.store_bits(pdata) + if ptype == "ACK": + self.state = "GET DATA LOW" + elif self.state == "GET DATA LOW": + if ptype == "BITS": + self.es_block = self.get_end_sample(pdata, idx=0) + self.putg( + self.ss_block, + self.es_block, + Ann.DATA_BYTE, + [ + "Data Bytes", + ], + ) + self.store_bits(pdata) + self.bits.reverse() + # Decode and clear buffer for repeated data byte packets + self.handle_data_bytes(self.bits) + self.bits = [] + if ptype in ("ACK", "NACK"): + self.state = "GET DATA HIGH"