def getDriverInstanceForDevice(device):
    vid_dict = _controllerfilter.get(device.getVendorID())
    if vid_dict:
        driver_class = vid_dict.get(device.getProductID(),
                                    vid_dict.get(None))
        if driver_class:
            try:
                return driver_class(device)
            # pylint: disable=no-member
            except usb1.USBErrorAccess as e:
                return InaccessibleController(driver_class, device) class FakeDevHandle(object):
    """Artificial USB Digilent ISC controller that implements the usb1.USBDeviceHandle interface.

    With real USB ISC Controllers, a USBDevice can be used to get a
    Handle to th communicate with the physical device. But simulating
    the full USB subsysem, or hooking into it, is too much of a pain,
    so simulating a USB device is more easily done by just handling
    the application level USB library functions directly.

    FakeDevHandle is treated as a handle, but it is really the
    simulated USB device.

    Understanding the USB related functions of this class requires
    understanding libusb1.0 and USB in general, most ththe types of
    requests, what endpoints are, and what fields are required for
    each message type. The following links should be enough to get
    started:
        http://www.beyondlogic.org/usbnutshell/usb6.shtml
        https://github.com/vpelletier/python-libusb1/blob/master/usb1.py
        http://libusb.sourceforge.net/api-1.0/group__syncio.html#gadb11f7a761bd12fc77a07f4568d56f38

    """
    USB_VEND_ID = 0x1443
    USB_PROD_ID = 0x0007

    # Special Controller specific constants.
    PROD_NAME = b'CoolRunner 2 Starter 2'
    USER_NAME = b'Cr2s2'
    SERIAL_NO = b"10146D508907"
    FW_VER = b'\x1A\x01\x31\x30'#0x1A013130
    PROD_ID = b'\x00\x90\x01\x26'#'0x00900126
    DEV_CAP = b'\x00\x00\x00\x15'#0x00000015

    #Digilent controllers use a 4 byte bulk packet header to specify
    #what command will be run. This structure is a mappint of
    # (category, request) : (command_name, init_packet_length)
    BLK_HANDLERS = {
        (0x02, 0x00): ("ENABLE_JTAG", 0x03),
        (0x02, 0x01): ("DISABLE_JTAG", 0x03),
        (0x02, 0x02): ("PORT_INFO", 0x04),
        (0x02, 0x03): ("SET_SPEED", 0x07), #Returns error 4
        (0x02, 0x04): ("GET_SPEED", 0x03), #Returns error 4
        (0x02, 0x05): ("SET_TMS_TDI_TDO", 0x06),
        (0x02, 0x06): ("GET_TMS_TDI_TDO_TCK", 0x03),
        (0x02, 0x07): ("CLOCK_TICK", 0x09),
        (0x02, 0x08): ("WRITE_TDI", 0x09),
        (0x02, 0x09): ("READ_TDO", 0x09),
        (0x02, 0x0A): ("WRITE_TMS_TDI", 0x08),
        (0x02, 0x0B): ("WRITE_TMS", 0x09)
    }

    def __init__(self, *devices):
        self.devices = devices
        self._jtag_on = False
        self._oem_seed = b'\x00\x00'
        self._blk_read_buffer = []
        self._lastcmd = None
        self._adv_req_enabled = False
        self._adv_req_read_tdo = False
        self._adv_req_bitcount = 0
        self._speed = 4000000

    @property
    def jtagon(self):
        """Check if the controller's JTAG enable bit is set"""
        return self._jtag_on

    def close(self):
        """Close the handle.

        This is required for real hardware, but for a simulation that
        is really just a controller, nothing has to happen. The
        function is required to comply with the usb1.USBDeviceHandle
        interface."""
        pass

    def controlWrite(self, request_type, request, value, index, data,
                     timeout=0):

        """Simulates libusb's synchronous control write in a sandbox.

        Only features explicitly used by the simulated controller's
        drier are implemented, so important USB management messages
        are not implemented.

        For details about this interface and arguments, refer to the
        links provided in the class description.

        For details on the commands supported by this simulated
        controller, please consult the controller doncumentation:
            http://diamondman.github.io/Adapt/cable_digilent_adept.html#control-messages

        Returns:
            An integer length of the number of bytes sent.

        """
        if request_type & 0x80 is not 0x00:
            raise Exception("Incorrect data direction in reqtype")

        if request is _CMSG_OEM_SEED:
            self._oem_seed = data

        return len(data)

    def controlRead(self, request_type, request, value, index, length,
                    timeout=0):
        """Simulates libusb's synchronous control read in a sandbox.

        Only features explicitly used by the simulated controller's
        drier are implemented, so important USB management messages
        are not implemented.

        For details about this interface and arguments, refer to the
        links provided in the class description.

        For details on the commands supported by this simulated
        controller, please consult the controller doncumentation:
            http://diamondman.github.io/Adapt/cable_digilent_adept.html#control-messages

        Returns:
            A bytes buffer containing the data read from the controller.
            #TODO Add details about format to docstring or documentation.
        """
        if request_type & 0x80 is not 0x80:
            raise Exception("Incorrect data direction in reqtype")

        if request is _CMSG_PROD_NAME:
            res =  self.PROD_NAME
        elif request is _CMSG_USER_NAME:
            res =  self.USER_NAME
        elif request is _CMSG_SERIAL_NO:
            res =  self.SERIAL_NO
        elif request is _CMSG_FW_VER:
            res =  self.FW_VER[:length]
        elif request is _CMSG_DEV_CAPS:
            res =  self.DEV_CAP
        elif request is _CMSG_PROD_ID:
            res =  self.PROD_ID
        elif request is _CMSG_OEM_CHECK:
            oembyte = self._oem_seed[0]^self._oem_seed[1]
            res =  bytes((oembyte^ord(b) for b in reversed('Digi')))
        else:
            raise USBErrorPipe(-9)

        if len(res)>length:
            raise USBErrorOverflow(-8)
        return res

    def bulkWrite(self, endpoint, data, timeout=0):
        """Simulates libusb's synchronous bulk write in a sandbox.

        Almost all RPC calls to the Digilent JTAG controller are
        started with a bulk write. The message contains a length, a
        cateory, a command, and optional parameters. The format of the
        initialization request is described at:
            http://diamondman.github.io/Adapt/cable_digilent_adept.html#bulk-requests

        This function has to update the state of the 'controller' so
        further messages can finish the RPC request. Each command can
        have a unique sequence of messages, so each command is handled
        with its own function .

        For example, if a message came in starting with
            0x09 02 0B 00

        The category is 2, and the command is 0x0B. In the table
        'BLK_HANDLERS', (2, 0xB) maps to ("WRITE_TMS", 9) which is the
        name and required length. The required length field matches,
        so the function _handle_blk_WRITE_TMS will be called.

        The WRITE_TMS handler will decode all the RPC specific
        parameters, and prepare the simulated device for the next
        write stage. A status message (2 bytes) will also be added to
        the return buffer to be retrieved on the next read.

        The next bulk write will be treated as the data stage of the
        Digilent 'advanced transfer protocol' specified in the above
        controller documentation link. This requrest will be handled
        by the stage2 handler for WRITE_TMS:
            _handle_blk_WRITE_TMS_stage2

        If data was requested to be returned, it will be put on the
        return buffer to be read later.

        Finally, statistics on the last operation may be requested by
        setting the 7th bit of Request to 1. These statistics will be
        put on the return buffer and can be read out later.

        """

        if not self._adv_req_enabled:
            if len(data) < 4:
                raise Exception("Too short message. Min 4 bytes")

            length, cat, req, params = data[0], data[1], data[2], data[4:]
            if req & 0x80 is 0x80:
                self._report_advanced_metrics()
            else:
                if length+1 is not len(data):
                    raise Exception("Length does not match header; "
                                    "length: %s; Payload len: %s"%
                                    (length, len(data)-1))

                self._lastcmd = (cat, req)
                name, length_req = self.BLK_HANDLERS.get((cat, req),
                                                         (None, None))
                #if name is None:
                #    #TODO MAKE RESPOND WITH STALL
                if length is not length_req:
                    raise Exception("Wrong Length for instruction. "
                                    "Would Hang")

                handler_name = "_handle_blk_"+name
                handler = getattr(self, handler_name, None)
                if not handler:
                    raise Exception("No handler %s. Would Stall."%
                                    handler_name) # pragma: no cover

                #print("BEFOREEXEC %s******"%name, self._blk_read_buffer)
                handler(params)
                #print("AFTER EXEC******", self._blk_read_buffer)
        else:
            #For Advanced messages, there is no header, just raw data.
            self._adv_req_enabled = False
            name, _ = self.BLK_HANDLERS[self._lastcmd]
            handler_name = "_handle_blk_"+name+"_stage2"
            handler = getattr(self, handler_name)
            res = handler(data, self._adv_req_bitcount,
                          self._adv_req_read_tdo,
                          **self._adv_req_extra_params)

    def bulkRead(self, endpoint, length, timeout=0):
        if self._blk_read_buffer:
            #print("BEFORE READ******", self._blk_read_buffer)
            res = self._blk_read_buffer[0]
            del self._blk_read_buffer[0]
            #print("AFTER READ******", self._blk_read_buffer)
            return res
        raise Exception("Would Hang waiting for something to return")

    def _report_advanced_metrics(self):
        """Report the metrics of the last RPC.

        Digilent RPCs can be followed up with a call to check the
        statistics of the last command. This includes the number of
        bits writte, if a read happened, and the number of bits read
        (only if a read did occur).

        When called, this puts the metrics packet in the response
        buffer for retrieval on a future read..

        """
        sz = 1 + 4 + (4*bool(self._adv_req_read_tdo))
        flags = 0x80 + (0x40 if self._adv_req_read_tdo else 0)
        writecount = self._adv_req_bitcount.to_bytes(4, 'little')
        readcount = self._adv_req_bitcount.to_bytes(4, 'little')\
                    if self._adv_req_read_tdo else b''
        self._blk_read_buffer.append(
            b'%c%c'%(sz, flags) + writecount\
            + readcount)

    def _write_to_dev_chain(self, tms, tdi):
        """Simulate electrically asserting a bit to the JTAG output pins.

        Args:
            tms: A boolean to be asserted to every simulated device's
             (in the chain) tms bit.
            tdi: A boolean to be shifted into the first simulated
             device's tdi pin.

        Returns:
            The boolean read from the tdo pin of the last device in
            the scan chain

        """
        #oldstate = self.devices[0].tap.state
        for dev in self.devices:
            tdi = dev.shift(tms, tdi)
        #print("State %s => %s; Reading %s"%
        #    (oldstate,self.devices[0].tap.state,tdi))
        return tdi

    def _initialize_advanced_return(self, bitcount, read_tdo,
                                    **params):
        """Helper method to assign some important values to keep track of Digilent controller state."""
        self._adv_req_enabled = True
        self._adv_req_bitcount = bitcount
        self._adv_req_read_tdo = read_tdo
        self._adv_req_extra_params = params

    def _handle_blk_ENABLE_JTAG(self, params):
        if self._jtag_on:
            self._blk_read_buffer.append(b'\x01\x03')
        else:
            self._jtag_on = True
            self._blk_read_buffer.append(b'\x01\x00')

    def _handle_blk_DISABLE_JTAG(self, params):
        self._jtag_on = False
        self._blk_read_buffer.append(b'\x01\x00')

    def _handle_blk_WRITE_TMS_TDI(self, params):
        doreturn = bool(params[0])
        bitcount = sum([b<<(i*8) for i,b in enumerate(params[1:5])])
        self._initialize_advanced_return(bitcount, doreturn)
        self._blk_read_buffer.append(b'\x01\x00')
    def _handle_blk_WRITE_TMS_TDI_stage2(self, data, bitcount, read_tdo):
        if isinstance(data, bytearray):
            data = bytes(data) # pragma: no cover
        bits = bitarray()
        bits.frombytes(data[::-1])
        bits = bits[(8*len(data)) - (bitcount*2):]
        tms = bits[::2][::-1]
        tdi = bits[1::2][::-1]
        tdo = []
        for i in range(bitcount):
            tdo.append(self._write_to_dev_chain(tms[i], tdi[i]))
        if read_tdo:
            tdo_bits = bitarray(([False]*(8-(len(tdo)%8)))+tdo[::-1])
            tdo_bytes = tdo_bits.tobytes()
            self._blk_read_buffer.append(tdo_bytes[::-1])

    def _handle_blk_WRITE_TMS(self, params):
        doreturn = bool(params[0])
        tdi = params[1]
        bitcount = sum([b<<(i*8) for i,b in enumerate(params[2:6])])
        self._initialize_advanced_return(bitcount, doreturn, tdi=tdi)
        self._blk_read_buffer.append(b'\x01\x00')
    def _handle_blk_WRITE_TMS_stage2(self, data, bitcount,
                                     read_tdo, *, tdi):
        if isinstance(data, bytearray):
            data = bytes(data) # pragma: no cover
        bits = bitarray()
        bits.frombytes(data[::-1])
        tms = bits[(8*len(data)) - (bitcount):]
        tdo = []
        for tmsbit in reversed(tms):
            tdo.append(self._write_to_dev_chain(tmsbit, tdi))
        if read_tdo:
            tdo_bits = bitarray(([False]*(8-(len(tdo)%8)))+tdo[::-1])
            tdo_bytes = tdo_bits.tobytes()
            self._blk_read_buffer.append(tdo_bytes[::-1])

    def _handle_blk_READ_TDO(self, params):
        tms = params[0]
        tdi = params[1]
        bitcount = sum([b<<(i*8) for i,b in enumerate(params[2:6])])
        tdo = []
        for i in range(bitcount):
            tdo.append(self._write_to_dev_chain(tms, tdi))

        self._adv_req_bitcount = bitcount
        self._adv_req_read_tdo = True
        self._blk_read_buffer.append(b'\x01\x00')
        tdo_bits = bitarray(([False]*(8-(len(tdo)%8)))+tdo[::-1])
        tdo_bytes = tdo_bits.tobytes()
        self._blk_read_buffer.append(tdo_bytes[::-1])

    def _handle_blk_WRITE_TDI(self, params):
        doreturn = bool(params[0])
        tms = params[1]
        bitcount = sum([b<<(i*8) for i,b in enumerate(params[2:6])])
        self._initialize_advanced_return(bitcount, doreturn, tms=tms)
        self._blk_read_buffer.append(b'\x01\x00')
    def _handle_blk_WRITE_TDI_stage2(self, data, bitcount,
                                     read_tdo, *, tms):
        if isinstance(data, bytearray):
            data = bytes(data) # pragma: no cover
        bits = bitarray()
        bits.frombytes(data[::-1])
        tdi = bits[(8*len(data)) - (bitcount):]
        tdo = []
        for tdibit in reversed(tdi):
            tdo.append(self._write_to_dev_chain(tms, tdibit))
        if read_tdo:
            tdo_bits = bitarray(([False]*(8-(len(tdo)%8)))+tdo[::-1])
            tdo_bytes = tdo_bits.tobytes()
            self._blk_read_buffer.append(tdo_bytes[::-1])

    def _handle_blk_CLOCK_TICK(self, params):
        tms = params[0]
        tdi = params[1]
        bitcount = sum([b<<(i*8) for i,b in enumerate(params[2:6])])
        for i in range(bitcount):
            self._write_to_dev_chain(tms, tdi)

        self._adv_req_read_tdo = False
        self._adv_req_bitcount = bitcount
        self._blk_read_buffer.append(b'\x01\x00')

    def _handle_blk_GET_SPEED(self, params):
        if not self._jtag_on:
            self._blk_read_buffer.append(b'\x01\x04')
        else:
            self._blk_read_buffer.append(b'\x05\x00'+\
                                         struct.pack("<I", self._speed))

    def _handle_blk_SET_SPEED(self, params):
        if not self._jtag_on:
            self._blk_read_buffer.append(b'\x01\x04')
        else:
            req_speed = struct.unpack("<I", params)[0]
            self._speed = 62500*(2**min(6,max(0,math.floor(
                math.log2(req_speed/62500)
            ))))
            self._blk_read_buffer.append(b'\x05\x00'+\
                                         struct.pack("<I", self._speed)) class FakeUSBDev(object):
    """The most basic features required for simulating a usb1.USBDevice.

    Normally, a usb1.USBDevice is retrieved with:
        >>> import usb1
        >>> context = usb1.USBContext()
        >>> dev = context.getDeviceList()[0]

    The USBDevice only is used to check ids to match a driver, and
    open a handle (type usb1.USBDeviceHandle) that can be used to talk
    to the physical device.  The handle is retrieved from the
    USBDevice with the open method:
        >>> handle = dev.open()
        >>> handle.controlWrite(........) #DO USB THINGS

    A real USBDevice must track many states and pointers to usb
    resources, including managing open handles. A fake USBDevice only
    has to provide a handle when open is called, and report the
    appropriate vendorID and productID.

    Attributes:
        ctrl_handle: An implementation of the usb1.USBDeviceHandle
        interface that will be returned when the FakeUSBDev's open()
        method is called.

    """
    def __init__(self, mockPhysicalController):
        self.ctrl_handle = mockPhysicalController
    def open(self):
        return self.ctrl_handle
    def getVendorID(self):
        return type(self.ctrl_handle).USB_VEND_ID
    def getProductID(self):
        return type(self.ctrl_handle).USB_PROD_ID class MockPhysicalJTAGDevice(object):
    def __init__(self, *, name=None, status=bitarray('11111011'),
                 idcode=bitarray('00000110110101001000000010010011'),
                 irlen=None, instructions=None, ins_reg_map=None,
                 registers=None):
        if any((instructions, ins_reg_map, registers, irlen)) and not\
           all((instructions, ins_reg_map, registers, irlen)):
            raise ValueError("Either initialize all reg/ins fields or "
                             "do not provide any.") #pragma: no cover
        self.name = name
        self._custom_status = status
        self._idcode = idcode
        self.tap = JTAGStateMachine()

        if all((instructions, ins_reg_map, registers, irlen)):
            self._instruction_register_map = ins_reg_map
            self._instructions = instructions
            self._registers = registers
            self._irlen = irlen
        else:
            numericid = int(self._idcode.to01(), 2)
            desc = jtagDeviceDescription.\
                   get_descriptor_for_idcode(numericid)
            self._instruction_register_map\
                = desc._instruction_register_map
            self._instructions = {k:v.to01() for k,v in
                                  desc._instructions.items()}
            self._registers = desc._registers
            self._irlen = desc._ir_length

        for ins in ("IDCODE", "BYPASS"):
            if ins not in self._instructions:
                raise ValueError("device instruction set must "
                                 "include %s"%ins)#pragma: no cover

        self.inscode_to_ins = {v:k for k,v in self._instructions.items()}

        self.event_history = []
        self.IR = ShiftRegister(self._irlen)
        self.DRs = {reg:ShiftRegister(l) for reg, l
                    in self._registers.items()}
        self.DRs[None] = BlackHoleShiftRegister()
        self.DRname = "DEVICE_ID"
        self.DR = self.DRs[self.DRname]
        self.current_instruction = "IDCODE"

    @property
    def tapstate(self):
        return self.tap.state

    @property
    def idcode(self):
        return self._idcode.copy()

    @property
    def irlen(self):
        return self._irlen

    def clearhistory(self):
        self.event_history = []

    def shift(self, tms, tdi):
        res = False
        #oldstate = self.tap.state
        if self.DR and self.tap.state=="SHIFTDR":
            res = self.DR.shift(tdi)
        if self.tap.state=="SHIFTIR":
            res = self.IR.shift(tdi)

        self.tap.transition_bit(tms)
        func = getattr(self, "_"+self.tap.state, None)
        if func:
            func()
        #print("%s State %s => %s; Reading %s"%
        #(self.name,oldstate,self.tap.state,res))
        return res

    def calc_status_register_val(self):
        #Meant to be overridden
        return self._custom_status

    def _TLR(self):
        self.DR = ShiftRegister(32, self._idcode)
        self.event_history.append("RESET")
    def _RTI(self):
        self.event_history.append("RTI")
    def _CAPTUREDR(self):
        self.event_history.append("CAPTUREDR")

        regname = self._instruction_register_map.get(
            self.current_instruction)
        self.DRname = regname
        self.DR = self.DRs[self.DRname]

        if self.current_instruction == "IDCODE":
            self.DR.loadData(self._idcode)
        if isinstance(self.DR, BlackHoleShiftRegister):
            self.DR.clear()

    def _UPDATEDR(self):
        drval = self.DR.dumpData().to01()
        #print(self.name, "** Updated DR: %s"%(drval))
        self.event_history.append("UPDATEDR")
        self.event_history.append(drval)
    def _CAPTUREIR(self):
        self.event_history.append("CAPTUREIR")
        self.IR.loadData(self.calc_status_register_val())
    def _UPDATEIR(self):
        irval = self.IR.dumpData().to01()
        self.current_instruction = self.inscode_to_ins[irval]
        #print("** %s Updated IR: %s(%s); DR set to %s"%
        #      (self.name, irval, insname, regname))
        self.event_history.append("UPDATEIR")
        self.event_history.append(irval) class ConstantBitarray(collections.Sequence):
    """A bitarray type where all bits are the same value.

    The bitarray class is already more efficient at storing a sequence
    of boolean values than an array, but all bits having the same
    value is a common enough case to optimize for.

    The most immediate obvious is a lower memory footprint, as only
    one boolean value is stored. But there are more important benefits.

    Splitting or reversing a constant bitarray, or combining two
    constant bitarrays (that have the same value) is trivial.

    Checking if any or all bits are set is trivial (A normal bitarray
    has to scan every bit every time such a check is done).

    A constant bitarray shows intent. By simply checking the type of
    the bitarray, we can know if sending the data in the bitarray down
    a wire requires arbitrary control of the signal value for every
    bit, of if we can get away with a simplier constant value.

    Args:
        val: A boolean that will be the value for each bit in the array.
        length: An integer specifying how many bits are in the array.
    """
    def __init__(self, val, length):
        self._val = bool(val)
        self._length = length

    def __len__(self):
        return self._length
    def __getitem__(self, index):
        if isinstance(index, slice):
            indices = index.indices(len(self))
            return ConstantBitarray(self._val, len(range(*indices)))

        if isinstance(index, int):
            index = len(self)-abs(index) if index < 0 else index
            if (index < self._length and index >= 0):
                return self._val
            raise IndexError("%s index out of range"%type(self))
        raise TypeError("%s indices must be integers or slices, not %s"%
                        (type(self), type(index)))
    def __repr__(self):
        return "<Const: %s (%s)>"%\
            (self._val, self._length)# pragma: no cover

    def __add__(self, other):
        """Handles combining different bitarray types.

        There are special rules for combining each type of bitarray:
        bitarray, ConstantBitarray, and NoCareBitArray. For example,
        two NoCareBitarrays combine into a bigger NoCareBit array,
        while combining two ConstantBitArrays depends on if the two
        array's constant value are the same.
        """
        if len(self) == 0:
            return other
        if len(other) == 0:
            return self
        if isinstance(other, ConstantBitarray):
            if self._val == other._val:
                return ConstantBitarray(self._val,
                                        self._length+other._length)
            return CompositeBitarray(self, other)
        if isinstance(other, bitarray):
            return CompositeBitarray(self, other)
        return NotImplemented

    def __radd__(self, other):
        if isinstance(other, bitarray):
            return CompositeBitarray(other, self)
        return NotImplemented

    def __iter__(self):
        for _ in range(self._length):
            yield self._val

    def __reversed__(self):
        for _ in range(self._length):
            yield self._val

    def __eq__(self, other):
        if isinstance(other, ConstantBitarray):
            return len(self) == len(other) and self._val == other._val
        if isinstance(other, bitarray):
            if len(self) != len(other):
                return False
            if self._val:
                return other.all()
            else:
                return not other.any()
        return NotImplemented

    def count(self, val=True):
        """Get the number of bits in the array with the specified value.

        Args:
            val: A boolean value to check against the array's value.

        Returns:
            An integer of the number of bits in the array equal to val.
        """
        if val == self._val:
            return self._length
        return 0

    def any(self):
        return self._val

    def all(self):
        return self._val

    #@profile
    def tobytes(self):
        if not len(self):
            return b''
        if self._val:
            if len(self)%8:
                return bytes([0xFF]*(math.ceil(len(self)/8)-1)+\
                             [(0xFF<<(8-len(self)%8))&0xFF])
            return bytes([0xFF]*(math.ceil(len(self)/8)))

        return bytes([0x00]*(math.ceil(len(self)/8)))

    def reverse(self):
        pass

    def split(self, bitindex):
        return self[:bitindex], self[bitindex:]

    def _easy_mergable(self, other):
        return isinstance(other, NoCareBitarray) or\
            (isinstance(other, PreferFalseBitarray) and\
             self._val is False) or\
            (isinstance(other, ConstantBitarray) and\
                 other._val == self._val)

    def byteiter(self):
        if self._val:
            for _ in range(math.ceil(len(self)/8)):
                yield 0xFF
        else:
            for _ in range(math.ceil(len(self)/8)):
                yield 0 class bitarray(_bitarray):
    def _easy_mergable(self, other):
        return False #Consider merging single bit bitarrays.

    def byteiter(self):
        data = self.tobytes()
        for byte in data:
            yield byte class DigilentWriteTMSPrimitive(Level1Primitive, Executable):
    _function_name = 'write_tms'
    _driver_function_name = 'write_tms_bits'
    _max_send_bits = 0x5FFFFF
    _max_recv_bits = 504
    _TMS, _TDI, _TDO = ARBITRARY, CONSTANT, CONSTANT
    _args = ['tms']
    _kwargs = {'return_tdo':'tdo', "TDI": 'tdi'} class DigilentWriteTDIPrimitive(Level1Primitive, Executable):
    _function_name = 'write_tdi'
    _driver_function_name = 'write_tdi_bits'
    _max_send_bits = 0x5FFFFF
    _max_recv_bits = 504
    _TMS, _TDI, _TDO = CONSTANT, ARBITRARY, CONSTANT
    _args = ['tdi']
    _kwargs = {'return_tdo':'tdo', 'TMS': 'tms'} class DigilentWriteTMSTDIPrimitive(Level1Primitive, Executable):
    _function_name = 'write_tms_tdi'
    _driver_function_name = 'write_tms_tdi_bits'
    _max_send_bits = 0x5FFFFF
    _max_recv_bits = 504
    _TMS, _TDI, _TDO = ARBITRARY, ARBITRARY, CONSTANT
    _args = ['tms', 'tdi']
    _kwargs = {'return_tdo':'tdo'} class DigilentReadTDOPrimitive(Level1Primitive, Executable):
    _function_name = 'read_tdo'
    _driver_function_name = 'read_tdo_bits'
    _max_send_bits = 504 #63 bytes
    _max_recv_bits = 504 #63 bytes
    _TMS, _TDI, _TDO = CONSTANT, CONSTANT, ONE
    _args = ['count']
    _kwargs = {'TMS':'tms', 'TDI': 'tdi'} class DigilentClockTickPrimitive(Level1Primitive, Executable):
    _function_name = 'tick_clock'
    _driver_function_name = 'tick_clock'
    _max_send_bits = 0x5FFFFF
    _max_recv_bits = 0
    _TMS, _TDI, _TDO = CONSTANT, CONSTANT, ZERO
    _args = ['count']
    _kwargs = {'TMS': 'tms', 'TDI': 'tdi'} ARBITRARY =    Requirement(True,  False, False, False) CONSTANT    =  Requirement(False, True,  False, False) NOCARE =       Requirement(False, False, False, False) ZERO =         Requirement(False, False, True,  False) ONE =          Requirement(False, False, True,  True) class TDOPromise(object):
    """Placeholder/Container for a value that isn't available immediately.

    When a primitive is created and asked to return a value, a promise
    is returned instead of the requested value. This delayed
    satisfaction of return values allows for more aggressive
    optimizations of the primitive stream.

    Promises track a return value from a primitive. As the primitive
    is modified, split, and joined with other primitives during the
    compilation process, the ultimate source of the data to fulfill
    the promise changes. The promise tracks the data about the
    transformation of its original primitives and can piece the
    appropriate bits together to form its value.

    Some primitives support arbitrary tdo bits. When a primitive that
    returns TDO and anoter one that does not are merged into a
    primitive that supports arbitrary TDO bits, the resulting
    primitive can specify exactly which bits it wants to be read back
    from the chip (This is tracked with the ComponentBitarray
    class). When this happend, normal offsets do not work anymore
    since they are based on the assumption that all bits are
    returned. A new offset must be tracked in case the final primitive
    supports arbitrary TDO.

    It does not seem that this new offset can replace the original
    offset, nor can No Care bits for tdo be rendered as False if the
    current primitive supports Arbitrary bits since it may be merged
    into another prim and end up unable to execute. Until a more
    elegant solution comes up, both offsets must be stored.

    A promise's value can be returned by calling the promise:
        res = mypromise()

    If a promise does not yet have a value, it will automatically
    trigger a flush operation on the associated JTAGScanChain, which
    will compile and execute all pending primitives and distribute the
    resulting data to the promises.

    Reading the value of any promise from the currently unexecuted set
    of primitives will automatically run all pending primitives, and
    fulfill all their promises.

    Manually flushing the scan chain will automatically fulfill all
    pending promises.


    Args:
        chain: A JTAGScanChain associated with this promise's primitie.
        bitstart: An integer offset used for selecting which bits of the original primitive the promise is selecting.
        bitlength: An integer count of how many bits of the original primitive should be selected by this promise.
        bitstartselective: The index to use if only the needed tdo bits are returned instead of all bits for a primitive.

    """
    count = 0
    def __init__(self, chain, bitstart, bitlength, *,
                 _parent=None, bitstartselective=None):
        self.sn = TDOPromise.count
        TDOPromise.count += 1
        self._chain = chain
        self._value = None
        self._parent = _parent
        self._components = []
        self._bitstart = bitstart
        self._bitlength = bitlength
        self._bitstartselective = bitstartselective if \
                                  bitstartselective is not None else\
                                  bitstart

    def __call__(self):
        if self._value:
            return self._value
        self._chain.flush()
        return self._value

    def __repr__(self):
        return "<P %s; bit %s; len %s; parent: %s; bitideal:%s>" %\
            (self.sn, self._bitstart, self._bitlength,
             self._parent.sn if self._parent else "NONE",
             self._bitstartselective)\
             #pragma: no cover

    def __len__(self):
        return self._bitlength

    @property
    def bitstart(self):
        return self._bitstart

    @property
    def bitlength(self):
        return self._bitlength

    @property
    def bitend(self):
        return self._bitend

    @property
    def _bitend(self):
        return self._bitstart + self._bitlength

    def _addsub(self, subpromise, offset):
        self._components.append((subpromise, offset))

    def split(self, bitindex):
        """Split a promise into two promises at the provided index.

        A common operation in JTAG is reading/writing to a
        register. During the operation, the TMS pin must be low, but
        during the writing of the last bit, the TMS pin must be
        high. Requiring all reads or writes to have full arbitrary
        control over the TMS pin is unrealistic.

        Splitting a promise into two sub promises is a way to mitigate
        this issue. The final read bit is its own subpromise that can
        be associated with a different primitive than the 'rest' of
        the subpromise.

        Returns:
            Two TDOPromise instances: the 'Rest' and the 'Tail'.
            The 'Rest' is the first chunk of the original promise.
            The 'Tail' is a single bit sub promise for the final bit
              in the operation

            If the 'Rest' would have a length of 0, None is returned

        """
        if bitindex < 0:
            raise ValueError("bitindex must be larger or equal to 0.")
        if bitindex > len(self):
            raise ValueError(
                "bitindex larger than the array's size. "
                "Len: %s; bitindex: %s"%(len(self), bitindex))

        if bitindex == 0:
            return None, self
        if bitindex == len(self):
            return self, None

        left = TDOPromise(self._chain, self._bitstart, bitindex,
                          _parent=self)
        #Starts at 0 because offset is for incoming data from
        #associated primitive, not location in parent.
        right = TDOPromise(self._chain, 0, len(self)-bitindex,
                          _parent=self)
        self._components = []
        self._addsub(left, 0)
        self._addsub(right, bitindex)
        return left, right

    def _fulfill(self, bits, ignore_nonpromised_bits=False):
        """Supply the promise with the bits from its associated primitive's execution.

        The fulfillment process must walk the promise chain backwards
        until it reaches the original promise and can supply the final
        value.

        The data that comes in can either be all a bit read for every
        bit written by the associated primitive, or (if the primitive
        supports it), only the bits that are used by promises. The
        ignore_nonpromised_bits flag specifies which format the
        incoming data is in.

        Args:
            bits: A bitarray (or compatible) containing the data read from the jtag controller's TDO pin.
            ignore_nonpromised_bits: A boolean specifying if only promised bits are being returned (and thus the 2nd index of the promise must be used for slicing the incoming data).

        """
        if self._allsubsfulfilled():
            if not self._components:
                if ignore_nonpromised_bits:
                    self._value = bits[self._bitstartselective:
                                       self._bitstartselective +
                                       self._bitlength]
                else:
                    self._value = bits[self._bitstart:self._bitend]
            else:
                self._value = self._components[0][0]._value
                for sub, offset in self._components[1:]:
                    self._value += sub._value
            if self._parent is not None:
                self._parent._fulfill(None)

    def _allsubsfulfilled(self):
        """Check if every subpromise has been fulfilles

        Returns:
            A boolean describing if all subpromises have been fulfilled
        """
        return not any((sub._value is None
                        for sub, offset in self._components))

    def makesubatoffset(self, bitoffset, *, _offsetideal=None):
        """Create a copy of this promise with an offset, and use it as this promise's child.

        If this promise's primitive is being merged with another
        primitive, a new subpromise may be required to keep track of
        the new offset of data coming from the new primitive.


        Args:
            bitoffset: An integer offset of the data in the new primitive.
        _offsetideal: integer offset of the data if terms of bits actually used for promises. Used to calculate the start index to read if the associated primitive has arbitrary TDO control.

        Returns:
            A TDOPromise registered with this promise, and with the
            correct offset.

        """
        if _offsetideal is None:
            _offsetideal = bitoffset
        if bitoffset is 0:
            return self
        newpromise = TDOPromise(
            self._chain,
            self._bitstart + bitoffset,
            self._bitlength,
            _parent=self,
            bitstartselective=self._bitstartselective+_offsetideal
        )
        self._addsub(newpromise, 0)
        return newpromise
import pytest
from proteusisc.controllerManager import getDriverInstanceForDevice
from proteusisc.test_utils import FakeUSBDev, FakeDevHandle,\
    MockPhysicalJTAGDevice
from proteusisc.bittypes import ConstantBitarray, bitarray
from proteusisc.drivers.digilentdriver import DigilentWriteTMSPrimitive,\
    DigilentWriteTDIPrimitive, DigilentWriteTMSTDIPrimitive,\
    DigilentReadTDOPrimitive, DigilentClockTickPrimitive
from proteusisc.contracts import ARBITRARY, CONSTANT, NOCARE, ZERO, ONE
from proteusisc.promise import TDOPromise
    bits = c.tick_clock(32, TMS=False, TDI=False)
    assert d0.tapstate == "SHIFTDR"

    #Read out the TDI value shifted in
    bits = c.read_tdo_bits(32, TMS=False)
    assert d0.tapstate == "SHIFTDR"
    assert bits == ConstantBitarray(False, 32)

    #WRITE A DIFFERENT VALUE
    c.tick_clock(32, TMS=False, TDI=True)

    #Read out the TDI value shifted in
    bits = c.read_tdo_bits(32, TMS=False)
    assert d0.tapstate == "SHIFTDR"
    assert bits == ConstantBitarray(True, 32)



def test_write_tms_bits_primitive():
    d0 = MockPhysicalJTAGDevice(name="D0", status=bitarray('11111100'),
                    idcode=bitarray('00000110110101001000000010010011'))
    ctrl = FakeDevHandle(d0)
    c = getDriverInstanceForDevice(FakeUSBDev(ctrl))
    c.jtag_enable()

    #RESET TAP AND TRANS TO SHIFTDR
    prim = DigilentWriteTMSPrimitive(tms=bitarray('001011111'),
                                     reqef=(ARBITRARY, NOCARE, NOCARE),
                                     _chain=None)
    c._execute_primitives([prim])
    assert d0.tapstate == "SHIFTDR"

    #READ 32 BITS OF DATA
    promise = TDOPromise(None, 0, 32)
    prim = DigilentWriteTMSPrimitive(tms=ConstantBitarray(False,32),
                                     tdo=ConstantBitarray(True,32),
                                     _chain=None, _promise=promise,
                                     reqef=(ARBITRARY, NOCARE, ONE))
    c._execute_primitives([prim])
    assert d0.tapstate == "SHIFTDR"
    assert promise() == d0._idcode

def test_write_tdi_bits_primitive():
    d0 = MockPhysicalJTAGDevice(name="D0", status=bitarray('11111100'),
                    idcode=bitarray('00000110110101001000000010010011'))
    ctrl = FakeDevHandle(d0)
    c = getDriverInstanceForDevice(FakeUSBDev(ctrl))
    c.jtag_enable()

    #RESET TAP AND TRANS TO SHIFTDR
    for bit in reversed(bitarray('001011111')):
        prim = DigilentWriteTDIPrimitive(
            tdi=ConstantBitarray(False, 1),
            tms=ConstantBitarray(bit, 1),
            reqef=(ONE if bit else ZERO, ZERO, NOCARE ),
            _chain=None
        )
        c._execute_primitives([prim])
    assert d0.tapstate == "SHIFTDR"

    #READ 32 BITS OF DATA
    promise = TDOPromise(None, 0, 32)
    prim = DigilentWriteTDIPrimitive(
        tms=ConstantBitarray(False,32),
        tdi=ConstantBitarray(False,32),
        tdo=ConstantBitarray(True,32),
        _chain=None, _promise=promise,
        reqef=(ZERO, ZERO, ONE)
    )
    c._execute_primitives([prim])
    assert d0.tapstate == "SHIFTDR"
    assert promise() == d0._idcode

def test_write_tms_tdi_bits_primitive():
    d0 = MockPhysicalJTAGDevice(name="D0", status=bitarray('11111100'),
                    idcode=bitarray('00000110110101001000000010010011'))
    ctrl = FakeDevHandle(d0)
    c = getDriverInstanceForDevice(FakeUSBDev(ctrl))
    c.jtag_enable()

    #RESET TAP AND TRANS TO SHIFTDR
    prim = DigilentWriteTMSTDIPrimitive(
        tms=bitarray('001011111'),
        tdi=ConstantBitarray(False, 9),
        reqef=(ARBITRARY, ZERO, NOCARE), _chain=None
    )
    c._execute_primitives([prim])
    assert d0.tapstate == "SHIFTDR"

    #READ 32 BITS OF DATA
    promise = TDOPromise(None, 0, 32)
    prim = DigilentWriteTMSTDIPrimitive(
        tdi=ConstantBitarray(False,32),
        tms=ConstantBitarray(False,32),
        tdo=ConstantBitarray(True,32),
        _chain=None, _promise=promise,
        reqef=(ZERO, ZERO, ONE))
    c._execute_primitives([prim])
    assert d0.tapstate == "SHIFTDR"
    assert promise() == d0._idcode

def test_read_tdo_primitie():
    d0 = MockPhysicalJTAGDevice(name="D0", status=bitarray('11111100'),
                    idcode=bitarray('00000110110101001000000010010011'))
    ctrl = FakeDevHandle(d0)
    c = getDriverInstanceForDevice(FakeUSBDev(ctrl))
    c.jtag_enable()

    #RESET TAP AND TRANS TO SHIFTDR
    for bit in reversed(bitarray('001011111')):
        prim = DigilentReadTDOPrimitive(
            tdi=False, tms=bit,
            reqef=(ONE if bit else ZERO, ZERO, NOCARE),
            _chain=None
        )
        c._execute_primitives([prim])
    assert d0.tapstate == "SHIFTDR"

    #READ 32 BITS OF DATA
    promise = TDOPromise(None, 0, 32)

    prim = DigilentReadTDOPrimitive(