
import struct


# @todo: use these
PACKET_LENGTH = 12
DATA_OFFSET = 8


class CommandPacket(object):
    def __init__(self, rnw=True, address=0, vals=None):
        """ """
        assert isinstance(vals, (type(None), list))
        self.rawbytes = bytearray([0 for _ in range(PACKET_LENGTH)])
        self.rawbytes[0] = 0xDE
        self.rawbytes[1] = 1 if rnw else 2
        self.rawbytes[2:6] = struct.pack(">L", address)
        self.rawbytes[6] = 4   # only support single read/write
        self.rawbytes[7] = 0xCA

        # @todo: support variable packets, block read/writes
        if vals is not None:
            self.rawbytes[8:12] = struct.pack(">L", vals[0])
        else:
            self.rawbytes[8:12] = struct.pack(">L", 0xFEEDFACE)

        # @todo: added checksum / CRC

    def dump(self):
        pass

    def check_response(self, pkt, rvals=None, evals=None):
        assert pkt[0] == 0xDE
        assert pkt[1] == self.rawbytes[1]
        assert pkt[2:6] == self.rawbytes[2:6]
        assert pkt[7] == 0xCA
        if rvals is not None and evals is not None:
            for ii, ev in enumerate(evals):
                rval, = struct.unpack(">L", pkt[8+(ii*4):12+(ii*4)])
                assert rval == ev, "{:08X} != {:08X}".format(rval, ev)
                rvals.append(rval)

    def put(self, fifobus):
        yield fifobus.clock.posedge
        for byte in self.rawbytes:
            fifobus.wr.next = True
            fifobus.wdata.next = byte
            yield fifobus.clock.posedge
        fifobus.wr.next = False

    def get(self, fifobus, rvals=None, evals=None, timeout=4000):
        response_bytes = bytearray([0 for _ in range(PACKET_LENGTH)])
        rpkt = response_bytes
        bytestoget, ii = PACKET_LENGTH, 0

        while fifobus.empty and timeout > 0:
            timeout -= 1
            yield fifobus.clock.posedge

        if timeout == 0:
            raise TimeoutError

        while bytestoget > 0:
            if not fifobus.empty and bytestoget > 1:
                fifobus.rd.next = True
            else:
                fifobus.rd.next = False

            if fifobus.rvld:
                bb = int(fifobus.rdata)
                rpkt[ii] = bb
                bytestoget -= 1
                ii += 1
            yield fifobus.clock.posedge
        fifobus.rd.next = False
        self.check_response(response_bytes, rvals, evals)




import struct


# @todo: use these
PACKET_LENGTH = 12
DATA_OFFSET = 8


class CommandPacket(object):
    def __init__(self, rnw=True, address=0, vals=None):
        """ """
        assert isinstance(vals, (type(None), list))
        self.rawbytes = bytearray([0 for _ in range(PACKET_LENGTH)])
        self.rawbytes[0] = 0xDE
        self.rawbytes[1] = 1 if rnw else 2
        self.rawbytes[2:6] = struct.pack(">L", address)
        self.rawbytes[6] = 4   # only support single read/write
        self.rawbytes[7] = 0xCA

        # @todo: support variable packets, block read/writes
        if vals is not None:
            self.rawbytes[8:12] = struct.pack(">L", vals[0])
        else:
            self.rawbytes[8:12] = struct.pack(">L", 0xFEEDFACE)

        # @todo: added checksum / CRC

    def dump(self):
        pass

    def check_response(self, pkt, rvals=None, evals=None):
        assert pkt[0] == 0xDE
        assert pkt[1] == self.rawbytes[1]
        assert pkt[2:6] == self.rawbytes[2:6]
        assert pkt[7] == 0xCA
        if rvals is not None and evals is not None:
            for ii, ev in enumerate(evals):
                rval, = struct.unpack(">L", pkt[8+(ii*4):12+(ii*4)])
                assert rval == ev, "{:08X} != {:08X}".format(rval, ev)
                rvals.append(rval)

    def put(self, fifobus):
        yield fifobus.clock.posedge
        for byte in self.rawbytes:
            fifobus.wr.next = True
            fifobus.wdata.next = byte
            yield fifobus.clock.posedge
        fifobus.wr.next = False

    def get(self, fifobus, rvals=None, evals=None, timeout=4000):
        response_bytes = bytearray([0 for _ in range(PACKET_LENGTH)])
        rpkt = response_bytes
        bytestoget, ii = PACKET_LENGTH, 0

        while fifobus.empty and timeout > 0:
            timeout -= 1
            yield fifobus.clock.posedge

        if timeout == 0:
            raise TimeoutError

        while bytestoget > 0:
            if not fifobus.empty and bytestoget > 1:
                fifobus.rd.next = True
            else:
                fifobus.rd.next = False

            if fifobus.rvld:
                bb = int(fifobus.rdata)
                rpkt[ii] = bb
                bytestoget -= 1
                ii += 1
            yield fifobus.clock.posedge
        fifobus.rd.next = False
        self.check_response(response_bytes, rvals, evals)



# @todo: use these # only support single read/write # @todo: support variable packets, block read/writes # @todo: added checksum / CRC