
from saleae.analyzers import AnalyzerFrame
from saleae.data import GraphTimeDelta, GraphTime
from SecondLayerHLAs import SecondLayerAnalyzer
import logging
import sys

# SPD High level analyzer must subclass the Second Layer HLA class
class SPDHla(SecondLayerAnalyzer.SecondLayerHLA):

    SPD_temp_frame = None

    SPD_logger = logging.getLogger("SPD")

    """We will use this initiator to add to the result_types dictionary the new transaction
    types and create the dictionaries for the packet handlers
    """
    def __init__(self):
        """The logger works, however, to see changes on the lvl of the logger on Logic's console,
        the application needs to be restarted. The other types of logging level are DEBUG and INFO.
        """
        logging.basicConfig(level=logging.ERROR, stream=sys.stdout)

        self.SPD_temp_frame = None
        self.read_time_interval = GraphTimeDelta(second = 0, millisecond = 0, microsecond = 5, nanosecond = 0, picosecond = 0)


        # ------------------------ Dictionaries for packet handler  ------------------------ #

        self.write_switcher = {
            0xA0 : self.HUB_write_handler,
            0x90 : self.PMIC_write_handler,
            0x20 : self.TS0_write_handler,
            0x60 : self.TS1_write_handler,
            0xB0 : self.RCD_write_handler,
        }

        self.read_switcher = {
            0xA0 : self.HUB_read_handler,
            0x90 : self.PMIC_read_handler,
            0x20 : self.TS0_read_handler,
            0x60 : self.TS1_read_handler,
            0xB0 : self.RCD_read_handler,
        }
        # --------------------------------------------------------------------------------- #


    # ------------------- SPD Specific CCC commands and result types ---------------------- #
    def update_ccc(self, ccc_dict) -> None:
        ccc_dict[0x61] = 'BC SETHID'
        ccc_dict[0x62] = 'BC DEVCTRL'

        ccc_dict[0xE0] = 'DEVCAP'


    def update_result_types(self, result_types: dict) -> None:

        # ---------------------------- Write Command Data Packets ------------------------- #
        # --------------------------------------------------------------------------------- #

        result_types["Write Command Data Packet SPD HUB"] = {
            'format':  'Write Command Data Packet SPD HUB- DIMM [{{data.Dimm}}] - MemReg [{{data.MemReg}}] - Addresss [{{data.Addresss}}] - Block Addresss [{{data.BlkAddresss}}] - Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Write Command Data Packet SPD HUB- DIMM [{Dimm}] - MemReg [{MemReg}] - Addresss [{Address}] - Block Addresss [{BlkAddresss}] - Payload [{Length}]: [ {Data} ]'
        }

        result_types["Write Command Data Packet TS0"] = {
            'format':  'Write Command Data Packet TS0 - DIMM [{{data.Dimm}}] - Address [{{data.Address}}] - Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Write Command Data Packet TS0 - DIMM [{Dimm}] -  Addresss [{Address}]  - Payload [{Length}]: [ {Data} ]'
        }

        result_types["Write Command Data Packet TS1"] = {
            'format':  'Write Command Data Packet TS1 - DIMM [{{data.Dimm}}] - Address [{{data.Address}}] - Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Write Command Data Packet TS1 - DIMM [{Dimm}] -  Addresss [{Address}]  - Payload [{Length}]: [ {Data} ]'
        }

        result_types["Write Command Data Packet PMIC"] = {
            'format':  'Write Command Data Packet PMIC - DIMM [{{data.Dimm}}] - Address [{{data.Address}}] - Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Write Command Data Packet PMIC - DIMM [{Dimm}] -  Addresss [{Address}]  - Payload [{Length}]: [ {Data} ]'
        }

        result_types["Write Command Data Packet RCD"] = {
            'format':  'Write Command Data Packet RCD - DIMM [{{data.Dimm}}] - Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Write Command Data Packet RCD - DIMM [{Dimm}] - Payload [{Length}]: [ {Data} ]'
        }

        # ------------------------- IBI Header transactions ----------------------------- #

        result_types["Write Command Data Packet SPD HUB, IBI"] = {
            'format':  'Write Command Data Packet SPD HUB, IBI - DIMM [{{data.Dimm}}] - MemReg [{{data.MemReg}}] - Address [{{data.Address}}] - Block Adres [{{data.BlkAddress}}] - Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Write Command Data Packet SPD HUB- DIMM [{Dimm}] - MemReg [{MemReg}] - Addresss [{Address}] - Block Addresss [{BlkAddresss}] - Payload [{Length}]: [ {Data} ]'
        }
        # ------------------------------------------------------------------------------- #

        # ------------------------------------------------------------------------------- #
        # ------------------------------------------------------------------------------- #


        # ---------------------------- Read Command Data Packets ------------------------ #
        # ------------------------------------------------------------------------------- #
        result_types["Read Command Data Packet SPD HUB"] = {
            'format':  'Read Command Data Packet SPD HUB- DIMM [{{data.Dimm}}] - MemReg [{{data.MemReg}}] - Addresss [{{data.Addresss}}] - Block Addresss [{{data.BlkAddresss}}] - Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Read Command Data Packet SPD HUB- DIMM [{Dimm}] - MemReg [{MemReg}] - Addresss [{Address}] - Block Addresss [{BlkAddresss}] - Payload [{Length}]: [ {Data} ]'
        }

        result_types["Read Command to default Address"] = {
            'format':  'Read Command to default Address SPD HUB- DIMM [{{data.Dimm}}] -  Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Read Command to default Address SPD HUB- DIMM [{Dimm}] - Payload [{Length}]: [ {Data} ]'
        }

        result_types["Write Command Data Packet TS0"] = {
            'format':  'Write Command Data Packet TS - DIMM [{{data.Dimm}}] - Addresss [{{data.Addresss}}] - Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Write Command Data Packet TS - DIMM [{Dimm}] -  Addresss [{Address}]  - Payload [{Length}]: [ {Data} ]'
        }

        result_types["Write Command Data Packet TS1"] = {
            'format':  'Write Command Data Packet TS - DIMM [{{data.Dimm}}] - Addresss [{{data.Addresss}}] - Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Write Command Data Packet TS - DIMM [{Dimm}] -  Addresss [{Address}]  - Payload [{Length}]: [ {Data} ]'
        }

        result_types["Read Command Data Packet RCD"] = {
            'format':  'Read Command Data Packet RCD - DIMM [{{data.Dimm}}] - Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Read Command Data Packet RCD - DIMM [{Dimm}] - Payload [{Length}]: [ {Data} ]'
        }

        result_types["Read Command Data Packet PMIC"] = {
            'format':  'Read Command Data Packet PMIC - DIMM [{{data.Dimm}}] - Address [{{data.Address}}] - Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Read Command Data Packet PMIC - DIMM [{Dimm}] -  Addresss [{Address}]  - Payload [{Length}]: [ {Data} ]'
        }

        # ------------------------ IBI Header transactions --------------------------- #

        result_types["Read Command Data Packet SPD HUB, IBI"] = {
            'format':  'Read Command Data Packet SPD HUB, IBI - DIMM [{{data.Dimm}}] - MemReg [{{data.MemReg}}] - Addresss [{{data.Address}}] - Block Addresss [{{data.BlkAddress}}] - Payload [{{data.Length}}]: [ {{data.Data}} ]',
            'console': 'Read Command Data Packet SPD HUB, IBI - DIMM [{Dimm}] - MemReg [{MemReg}] - Addresss [{Address}] - Block Addresss [{BlkAddresss}] - Payload [{Length}]: [ {Data} ]'
        }
        # --------------------------------------------------------------------------------- #

        # --------------------------------------------------------------------------------- #
        # --------------------------------------------------------------------------------- #

    # ---------------------------------------------------------------------------------- #


    # --------------------------------------------------------------------------------- #
    # ------------------------ Instruction and packet decoders ------------------------ #
    # --------------------------------------------------------------------------------- #

    # ------------------------------ Instruction decoder ------------------------------ #
    # --------------------------------------------------------------------------------- #
    """This function will return the frames to be committed:
        > None if no frames are needed to be committed, for example a
        short write so we need to wait if the next transactions is
        an SPD read.
        > A list of frames to commit that will vary between
        one or two
    """
    def instruction_decoder(self, frame: AnalyzerFrame) -> AnalyzerFrame:
        self.SPD_logger.debug("Instruction_decoder")
        # SPD transactions can only be Messages or I3C Transactions frame types
        if (frame.type == "Message") | (frame.type == "I3C Transaction"):
            if frame.data["W/R"][0] == "W":
                return self.analyze_write_command(frame)

            elif frame.data["W/R"][0] == "R":
                return self.analyze_read_command(frame)
            else:
                self.SPD_logger.error("ERROR: Not W or R")
                return frame

        else:
            return frame
    # --------------------------------------------------------------------------------- #
    # --------------------------------------------------------------------------------- #


    # ------------------------ Write, read command analyzers ------------------------ #
    #-------------------------------------------------------------------------------- #
    def analyze_write_command(self, frame: AnalyzerFrame):

        self.SPD_logger.debug("W/R = W")

        """ For the case of a NACK write to a device. Every SPD transaction has at least length 2
        if it is a Message or length 3 if it is an I3C Transaction"""
        if (frame.data["Length"] < 2) | ((frame.data["Length"] < 3) & (frame.type == "I3C Transaction")):

            # We have to check if there was a saved frame, if not, such frame could be lost.
            return_frames = []
            if self.SPD_temp_frame != None:
                return_frames.append(self.SPD_temp_frame)
            self.SPD_temp_frame = None
            return_frames.append(frame)
            return return_frames

        # Convert the data string of the HLA transaction frame to operable int values
        data_array = [int(x, base = 16) for x in (frame.data["Data"]).split(",")]

        '''We use a variable to keep record of the location of the Address byte on the data_array since
        its position is shifted one byte in the I3C Transaction type due to the 0x7E BC byte. It is
        also useful since many conditionals depend on the overall length of the frame which we need to
        add one in the case of an I3C Transaction.
        '''
        address_pointer = 0 if frame.type == "Message" else 1

        # Bitwise shift to take into account that the 0 bit is the W or R flag
        SPDi3c_Address_byte = data_array[address_pointer] << 1
        SPD_device_ID = SPDi3c_Address_byte & 0xF0

        try:
            self.SPD_logger.debug("Calling handler")
            return self.write_switcher[SPD_device_ID](frame, SPDi3c_Address_byte, data_array, address_pointer)

        except :
            # If the i3c Address does not correspond to a SPD device just return the frame and any previous recorded frames
            self.SPD_logger.debug("Unable to call handler")
            return_frames = []
            if self.SPD_temp_frame != None:
                return_frames.append(self.SPD_temp_frame)
            self.SPD_temp_frame = None
            return_frames.append(frame)
            return return_frames



    def analyze_read_command(self, frame: AnalyzerFrame):
        self.SPD_logger.debug("W/R = R")

        # We just need the Addresss byte
        address_pointer = 0 if frame.type == "Message" else  1
        SPDi3c_Address_byte = int((frame.data["Data"]).split(',')[address_pointer], base = 16)

        SPDi3c_Address_byte = SPDi3c_Address_byte  << 1
        SPD_device_ID = SPDi3c_Address_byte & 0xF0

        try:
            self.SPD_logger.debug("Calling handler")
            return self.read_switcher[SPD_device_ID](frame)

        except :
            # If the i3c Address does not correspond to a SPD device just return the frame and any previous recorded frames
            self.SPD_logger.debug("Unable to call handler")
            return_frames = []
            if self.SPD_temp_frame != None:
                return_frames.append(self.SPD_temp_frame)
            self.SPD_temp_frame = None
            return_frames.append(frame)
            return return_frames

    # ------------------------------------------------------------------------------- #
    #-------------------------------------------------------------------------------- #



    #------------------------------ Packet decoders --------------------------------- #
    #-------------------------------------------------------------------------------- #

    #------------------------------ HUB device ---------------------------------------#

    def HUB_write_handler(self, frame: AnalyzerFrame, SPDi3c_Address_byte, data_array, address_pointer):
        if frame.type == "Message":
            new_frame = AnalyzerFrame("Write Command Data Packet SPD HUB", frame.start_time, frame.end_time, {
                "Data": "",
                "Length": 0
            })
        else:
            new_frame = AnalyzerFrame("Write Command Data Packet SPD HUB, IBI", frame.start_time, frame.end_time, {
                "Data": "",
                "Length": 0
            })
        self.SPD_logger.debug("new_frame created")

        # -------------------- Decode SPD information ------------------#
        HID = ((SPDi3c_Address_byte & 0x0F) >> 1)
        new_frame.data["Dimm"] = f"{HID:d}"

        mem_reg_byte = data_array[address_pointer + 1]
        new_frame.data["MemReg"] = f"{((mem_reg_byte & 0x80) >> 7)}"

        """If MemReg = 1, then we need to register de block Address, if not, Address is 6 bits long. Be careful, I2C transactions with MemReg = 1
        can come or not with block Address. We have to check if the frame is long enough (3 or grater) as to contain block Addresss. We add the
        address_pointer as a way to distinguish when the original frame is a Message or a I3C transaction and not concatenate if statements.
        """
        if ((mem_reg_byte & 0x80) == 0x80) & (frame.data["Length"] >= (3 + address_pointer)) :
            #Block Address is made up from 6th bit of the mem_reg_byte and the first four of data_array[2] (third byte of the transaction)
            blkAddress = ((mem_reg_byte & 0x40) >> 6) + ((data_array[address_pointer + 2] << 1) & 0x0F)
            new_frame.data["BlkAddress"] = f"0x{blkAddress:X}"
            new_frame.data["Address"]    = f"0x{(mem_reg_byte & 0x3F):X}"
        else :
            new_frame.data["BlkAddress"] = "None"
            new_frame.data["Address"]    = f"0x{(mem_reg_byte & 0x7F):X}"

        new_frame.data["W/R"]    = "W"
        new_frame.data["Length"] = frame.data["Length"]
        new_frame.data["Data"]   = frame.data["Data"]

        return_frames = []
        # In the case that a short SPD write frame was saved
        if self.SPD_temp_frame is not None:
            return_frames.append(self.SPD_temp_frame)
            self.SPD_temp_frame = None

        """We need to add the address_pointer (which is 0 for message and 1 for I3C transaction) since
        the BC byte (0x7E) adds one to the min length to determine that a transaction is purely an SPD write.
        """
        if frame.data["Length"] > (4 + address_pointer):
            self.SPD_logger.debug(f"Length > {(4 + address_pointer ):d}")
            return_frames.append(new_frame)
            self.SPD_temp_frame = None

        else:
            self.SPD_logger.debug(f"Length <= {(4 + address_pointer ):d}", )
            self.SPD_temp_frame = new_frame

        return return_frames

    def HUB_read_handler(self, frame: AnalyzerFrame):
        self.SPD_logger.debug("R to Hub device")

        """This case is very tricky:
           - First: If there is no temp frame saved or if the R is a I3C transaction we automatically know it is a read to the default Address
           - Second: If temp frame in not None there are two possibilities
                > First: If the temp frame is a write to the SPD HUB then we have to check if the time difference between the W and R is less
                or equal to the read_time_interval:
                    -> In the case it is less, we interpret the W+R as a SPD R transaction
                    -> If it is grater, we interpret the W as an SPD W to HUB and the R as a default Address R to HUB
                > Second: In the case the temp frame is not a write to SPD HUB, we can assume that the W is a SPD W of short length to a local device
                and the R as a default Address SPD R to the HUB device.
        """
        if (self.SPD_temp_frame == None) | (frame.type == "I3C Transaction"):
            return_frames = []
            if self.SPD_temp_frame != None:
                return_frames.append(self.SPD_temp_frame)
            return_frames.append(self.HUB_read_default_Address_handler(frame))
            return return_frames

        elif (self.SPD_temp_frame.type == "Write Command Data Packet SPD HUB") | (self.SPD_temp_frame.type == "Write Command Data Packet SPD HUB, IBI"):

            timeDelta_between_WR = (GraphTime.__sub__(self.SPD_temp_frame.end_time, frame.start_time))
            if GraphTimeDelta.__le__(timeDelta_between_WR, self.read_time_interval):

                if frame.data["Length"] == 1:
                    self.SPD_temp_frame.end_time = frame.end_time
                    return None

                if self.SPD_temp_frame.type == "Write Command Data Packet SPD HUB":
                    new_frame = AnalyzerFrame("Read Command Data Packet SPD HUB", self.SPD_temp_frame.start_time, frame.end_time, {
                        "Data": "",
                        "Length": 0
                    })
                else:
                    new_frame = AnalyzerFrame("Read Command Data Packet SPD HUB, IBI", self.SPD_temp_frame.start_time, frame.end_time, {
                        "Data": "",
                        "Length": 0
                    })
                self.SPD_logger.debug("new_frame created")

                # -------------------- Decode SPD information ------------------#
                new_frame.data["Dimm"]  = self.SPD_temp_frame.data["Dimm"]
                new_frame.data["W/R"]    = "R"
                new_frame.data["MemReg"] = self.SPD_temp_frame.data["MemReg"]

                new_frame.data["BlkAddress"] = self.SPD_temp_frame.data["BlkAddress"]
                new_frame.data["Address"]    = self.SPD_temp_frame.data["Address"]

                new_frame.data["Length"] = frame.data["Length"] + self.SPD_temp_frame.data["Length"]
                new_frame.data["Data"]   = self.SPD_temp_frame.data["Data"] + " " + frame.data["Data"]

                self.SPD_temp_frame = None

                self.SPD_logger.debug("New frame created")
                return new_frame

            else:
                return_frames = []
                return_frames.append(self.SPD_temp_frame)
                return_frames.append(self.HUB_read_default_Address_handler(frame))
                return return_frames

        else:
            return_frames = []
            return_frames.append(self.SPD_temp_frame)
            return_frames.append(self.HUB_read_default_Address_handler(frame))
            return return_frames


    def HUB_read_default_Address_handler(self, frame: AnalyzerFrame):
        new_frame = AnalyzerFrame("Read Command to default Address", frame.start_time, frame.end_time, {
            "Data": "",
            "Length": 0
        })
        address_pointer = 0 if frame.type == "Message" else  1
        SPDi3c_Address_byte = int((frame.data["Data"]).split(',')[address_pointer], base = 16)
        SPDi3c_Address_byte = SPDi3c_Address_byte  << 1

        self.SPD_logger.debug("New frame created")
        HID = ((SPDi3c_Address_byte & 0x0F) >> 1)
        new_frame.data["Dimm"]   = f"{HID:d}"
        new_frame.data["W/R"]    = "R"
        new_frame.data["Length"] = frame.data["Length"]
        new_frame.data["Data"]   = frame.data["Data"]

        self.SPD_temp_frame = None

        return new_frame


    #----------------------------------------------------------------------------------#


    #------------------------------ PMIC device ---------------------------------------#

    def PMIC_write_handler(self, frame: AnalyzerFrame, SPDi3c_Address_byte, data_array, address_pointer):
        self.SPD_logger.debug("W to PMIC")

        new_frame = AnalyzerFrame("Write Command Data Packet PMIC", frame.start_time, frame.end_time, {
            "Data": "",
            "Length": 0
        })
        self.SPD_logger.debug("new_frame created")

        # -------------------- Decode SPD information ------------------#
        HID = ((SPDi3c_Address_byte & 0x0F) >> 1)
        new_frame.data["Dimm"]   = f"{HID:d}"
        new_frame.data["Address"] = f"0x{data_array[address_pointer + 1]:X}"
        new_frame.data["W/R"]    = "W"
        new_frame.data["Length"] = frame.data["Length"]
        new_frame.data["Data"]   = frame.data["Data"]


        return_frames = []
        # In the case that a short SPD write frame was saved
        if self.SPD_temp_frame is not None:
            return_frames.append(self.SPD_temp_frame)
            self.SPD_temp_frame = None

        """We need to add the address_pointer (which is 0 for Message and 1 for I3C transaction) since
        the BC byte (0x7E) adds one to the min length to determine that a transaction is purely an SPD write.
        """
        if frame.data["Length"] > (2 + address_pointer):
            self.SPD_logger.debug(f"Length > {(2 + address_pointer ):d}")
            return_frames.append(new_frame)

        else:
            self.SPD_logger.debug(f"Length > {(2 + address_pointer ):d}")
            self.SPD_temp_frame = new_frame

        return return_frames

    def PMIC_read_handler(self, frame: AnalyzerFrame):
        self.SPD_logger.debug("R to PMIC")

        """This may be repetitive, but necessary to make sure no I3C transaction read is detected
        or we try to decode a read without a previous write.
        """
        if (self.SPD_temp_frame == None) | (frame.type == "I3C Transaction") :
            return frame

        if frame.data["Length"] == 1:
            self.SPD_temp_frame.end_time = frame.end_time
            return None

        new_frame = AnalyzerFrame("Read Command Data Packet PMIC", self.SPD_temp_frame.start_time, frame.end_time, {
            "Data": "",
            "Length": 0
        })
        self.SPD_logger.debug("new_frame created")

        # -------------------- Decode SPD information ------------------#
        # The data of a NACK R to the PMIC is not added to Data or Length
        new_frame.data["Dimm"]   = self.SPD_temp_frame.data["Dimm"]
        new_frame.data["Address"] = self.SPD_temp_frame.data["Address"]
        new_frame.data["W/R"]    = "R"
        new_frame.data["Length"] = self.SPD_temp_frame.data["Length"] + frame.data["Length"]
        new_frame.data["Data"]   = self.SPD_temp_frame.data["Data"] + " " +  frame.data["Data"]

        self.SPD_temp_frame = None

        return new_frame

    #----------------------------------------------------------------------------------#


    #-------------------------------- TS device ---------------------------------------#

    def TS0_write_handler(self, frame: AnalyzerFrame, SPDi3c_Address_byte, data_array, address_pointer):
        self.SPD_logger.debug("W to TS0")
        new_frame = AnalyzerFrame("Write Command Data Packet TS0", frame.start_time, frame.end_time, {
            "Data": "",
            "Length": 0
        })
        self.SPD_logger.debug("new_frame created")

        # -------------------- Decode SPD information ------------------#
        HID = ((SPDi3c_Address_byte & 0x0F) >> 1)
        new_frame.data["Dimm"]   = f"{HID:d}"
        new_frame.data["Address"] = f"0x{data_array[address_pointer + 1]:X}"
        new_frame.data["W/R"]    = "W"
        new_frame.data["Length"] = frame.data["Length"]
        new_frame.data["Data"]   = frame.data["Data"]

        # There can't be a R afterwards if the length is greater than 2

        return_frames = []
        # In the case that a short SPD write frame was saved
        if self.SPD_temp_frame is not None:
            return_frames.append(self.SPD_temp_frame)
            self.SPD_temp_frame = None

        if frame.data["Length"] > (2 + address_pointer):
            self.SPD_logger.debug(f"Length > {(2 + address_pointer ):d}")
            return_frames.append(new_frame)

        else:
            self.SPD_logger.debug(f"Length > {(2 + address_pointer ):d}")
            self.SPD_temp_frame = new_frame

        return return_frames

    def TS0_read_handler(self, frame: AnalyzerFrame):
        self.SPD_logger.debug("R to TS0")

        """This may be repetitive, but necessary to make sure no I3C transaction read is detected
        or we try to decode a read without a previous write.
        """
        if (self.SPD_temp_frame == None) | (frame.type == "I3C Transaction") :
            return frame

        if frame.data["Length"] == 1:
            self.SPD_temp_frame.end_time = frame.end_time
            return None

        new_frame = AnalyzerFrame("Read Command Data Packet TS0", self.SPD_temp_frame.start_time, frame.end_time, {
            "Data": "",
            "Length": 0
        })
        self.SPD_logger.debug("new_frame created")

        # -------------------- Decode SPD information ------------------#
        # The data of a NACK R to the TS0 is not added to Data or Length
        new_frame.data["Dimm"]   = self.SPD_temp_frame.data["Dimm"]
        new_frame.data["Address"] = self.SPD_temp_frame.data["Address"]
        new_frame.data["W/R"]    = "R"
        new_frame.data["Length"] = self.SPD_temp_frame.data["Length"] + frame.data["Length"]
        new_frame.data["Data"]   = self.SPD_temp_frame.data["Data"] + " " +  frame.data["Data"]

        self.SPD_temp_frame = None

        return new_frame

    def TS1_write_handler(self, frame: AnalyzerFrame, SPDi3c_Address_byte, data_array, address_pointer):
        self.SPD_logger.debug("W to TS1")

        new_frame = AnalyzerFrame("Write Command Data Packet TS1", frame.start_time, frame.end_time, {
            "Data": "",
            "Length": 0
        })
        self.SPD_logger.debug("new_frame created")

        # -------------------- Decode SPD information ------------------#
        HID = ((SPDi3c_Address_byte & 0x0F) >> 1)
        new_frame.data["Dimm"]   = f"{HID:d}"
        new_frame.data["Address"] = f"0x{data_array[address_pointer + 1 ]:X}"
        new_frame.data["W/R"]    = "W"
        new_frame.data["Length"] = frame.data["Length"]
        new_frame.data["Data"]   = frame.data["Data"]

        # There can't be a R afterwards if the length is greater than 2

        return_frames = []
        # In the case that a short SPD write frame was saved
        if self.SPD_temp_frame is not None:
            return_frames.append(self.SPD_temp_frame)
            self.SPD_temp_frame = None

        """We need to add the address_pointer (which is 0 for message and 1 for I3C transaction) since
        the BC byte (0x7E) adds one to the min length to determine that a transaction is purely an SPD write.
        """
        if frame.data["Length"] > (2 + address_pointer):
            self.SPD_logger.debug(f"Length > {(2 + address_pointer ):d}")
            return_frames.append(new_frame)

        else:
            self.SPD_logger.debug(f"Length > {(2 + address_pointer ):d}")
            self.SPD_temp_frame = new_frame

        return return_frames

    def TS1_read_handler(self, frame: AnalyzerFrame):
        self.SPD_logger.debug("R to TS1")

        """This may be repetitive, but necessary to make sure no I3C transaction read is detected
        or we try to decode a read without a previous write.
        """
        if (self.SPD_temp_frame == None) | (frame.type == "I3C Transaction") :
            return frame

        if frame.data["Length"] == 1:
            self.SPD_temp_frame.end_time = frame.end_time
            return None

        new_frame = AnalyzerFrame("Read Command Data Packet TS1", self.SPD_temp_frame.start_time, frame.end_time, {
            "Data": "",
            "Length": 0
        })
        self.SPD_logger.debug("new_frame created")

        # -------------------- Decode SPD information ------------------#
        # The data of a NACK R to the TS1 is not added to Data or Length
        new_frame.data["Dimm"]   = self.SPD_temp_frame.data["Dimm"]
        new_frame.data["Address"] = self.SPD_temp_frame.data["Address"]
        new_frame.data["W/R"]    = "R"
        new_frame.data["Length"] = self.SPD_temp_frame.data["Length"] + frame.data["Length"]
        new_frame.data["Data"]   = self.SPD_temp_frame.data["Data"] + " " +  frame.data["Data"]

        self.SPD_temp_frame = None

        return new_frame


    #----------------------------------------------------------------------------------#


    #------------------------------ RCD device ---------------------------------------#

    def RCD_write_handler(self, frame: AnalyzerFrame, SPDi3c_Address_byte, data_array, address_pointer):
        self.SPD_logger.debug("W to RCD")

        new_frame = AnalyzerFrame('Write Command Data Packet RCD', frame.start_time, frame.end_time, {
            "Data": "",
            "Length": 0
        })
        self.SPD_logger.debug("new_frame created")

        # -------------------- Decode SPD information ------------------#
        HID = ((SPDi3c_Address_byte & 0x0F) >> 1)
        new_frame.data["Dimm"]   = f"{HID:d}"
        new_frame.data["W/R"]    = "W"
        new_frame.data["Length"] = frame.data["Length"]
        new_frame.data["Data"]   = frame.data["Data"]

        # There can't be a R afterwards if the length is greater than 7

        return_frames = []
        # In the case that a short SPD write frame was saved
        if self.SPD_temp_frame is not None:
            return_frames.append(self.SPD_temp_frame)
            self.SPD_temp_frame = None

        """We need to add the address_pointer (which is 0 for message and 1 for I3C transaction) since
        the BC byte (0x7E) adds one to the min length to determine that a transaction is purely an SPD write.
        """
        if frame.data["Length"] > (7 + address_pointer):
            self.SPD_logger.debug(f"Length > {(7 + address_pointer ):d}")
            return_frames.append(new_frame)

        else:
            self.SPD_logger.debug(f"Length > {(7 + address_pointer ):d}")
            self.SPD_temp_frame = new_frame

        return return_frames

    def RCD_read_handler(self, frame: AnalyzerFrame):
        self.SPD_logger.debug("Read to RCD")

        """This may be repetitive, but necessary to make sure no I3C transaction read is detected
        or we try to decode a read without a previous write.
        """
        if (self.SPD_temp_frame == None) | (frame.type == "I3C Transaction") :
            return frame


        if frame.data["Length"] == 1:
            self.SPD_logger.debug("Length < 1")
            self.SPD_temp_frame.end_time = frame.end_time
            return None

        new_frame = AnalyzerFrame('Read Command Data Packet RCD', self.SPD_temp_frame.start_time, frame.end_time, {
            "Data": "",
            "Length": 0
        })
        self.SPD_logger.debug("new_frame created")

        # -------------------- Decode SPD information ------------------#
        # The data of a NACK R to the RCD is not added to Data or Length
        new_frame.data["Dimm"]   = self.SPD_temp_frame.data["Dimm"]
        new_frame.data["W/R"]    = "R"
        new_frame.data["Length"] = self.SPD_temp_frame.data["Length"] + frame.data["Length"]
        new_frame.data["Data"]   = self.SPD_temp_frame.data["Data"] + " " +  frame.data["Data"]

        self.SPD_temp_frame = None

        return new_frame

    #Returns the correct analyzer frame for each abort case possible
    def handle_abort_message(self, temp_frame: AnalyzerFrame,end_time) -> AnalyzerFrame:
        #In SPD the frame stays the same, there is no aborted version
        temp_frame.end_time = end_time
        return temp_frame
    #----------------------------------------------------------------------------------#

    #--------------------------------------------------------------------------------- #
    #--------------------------------------------------------------------------------- #

    # -------------------------------------------------------------------------------- #
    # -------------------------------------------------------------------------------- #
    # -------------------------------------------------------------------------------- #
