<commit_before>#-*- coding: utf-8 -*-
"""
    digilentdriver
    ~~~~~~~~~~~~~~

    Digilent driver for Linux USB JTAG controller

    :copyright: (c) 2014 by <NAME>
    :license: Pending, see LICENSE for more details.
"""

import struct
from time import time

from proteusisc.jtagUtils import blen2Blen, buff2Blen,\
    build_byte_align_buff
from proteusisc.cabledriver import CableDriver
from proteusisc.primitive import Level1Primitive, Executable
from proteusisc.bittypes import ConstantBitarray, NoCareBitarray,\
    CompositeBitarray, bitarray, PreferFalseBitarray
from proteusisc.contracts import NOCARE, ZERO, ONE, CONSTANT, ARBITRARY
from proteusisc.errors import JTAGEnableFailedError,\
    JTAGAlreadyEnabledError, JTAGControlError, JTAGNotEnabledError

#Controller documentation available at
#http://diamondman.github.io/Adapt/cable_digilent_adept.html
#This document is not complete and will evolve as Digilent adds
#new features to the protocol. Please report any issues.
#
#CONTROL MESSAGES:
_CMSG_PROD_NAME = 0xE1
_CMSG_USER_NAME = 0xE2
_CMSG_SERIAL_NO = 0xE4
_CMSG_FW_VER    = 0xE6
_CMSG_DEV_CAPS  = 0xE7
_CMSG_OEM_SEED  = 0xE8
_CMSG_PROD_ID   = 0xE9
_CMSG_OEM_CHECK = 0xEC

#SZ:CT:RQ:00:{Parameters to the request if any}
#   SZ: Length of bulk packet minus 1.
#   CT: Category or request. Category 0x02 appears to be JTAG.
#   RQ: Request Code
#
#BULK MSG PARAMS (Min 1 byte each):
# XX:XX:XX:XX: Transaction count in bits (4 bytes). Little Engian.
# RV: Should return TDO data (Boolean). Little Endian.
# MS: TMS VALUE (Boolean)
# DI: TDI VALUE (Boolean)
# DO: TDO VALUE (Boolean)
# CK: TCK VALUE (Boolean)
# SP: SPEED in Bits/Second
_BMSG_ENABLE_JTAG         = b'\x03\x02\x00\x00'       # NO PARAMS
_BMSG_DISABLE_JTAG        = b'\x03\x02\x01\x00'       # NO PARAMS
_BMSG_PORT_INFO           = b'\x04\x02\x02\x00'       # ??
_BMSG_SET_SPEED           = b'\x07\x02\x03\x00%b'     # SP:SP:SP:SP
_BMSG_GET_SPEED           = b'\x03\x02\x04\x00'       # NO PARAMS
_BMSG_SET_TMS_TDI_TDO     = b'\x06\x02\x05\x00%c%c%c' # MS:DI:DO
_BMSG_GET_TMS_TDI_TDO_TCK = b'\x03\x02\x06\x00'       # NO PARAMS
_BMSG_CLOCK_TICK          = b'\x09\x02\x07\x00%c%c%b' # MS:DI:XX:XX:XX:XX
_BMSG_WRITE_TDI           = b'\x09\x02\x08\x00%c%c%b' # RV:MS:XX:XX:XX:XX
_BMSG_READ_TDO            = b'\x09\x02\x09\x00%c%c%b' # MS:DI:XX:XX:XX:XX
_BMSG_WRITE_TMS_TDI       = b'\x08\x02\x0A\x00%c%b'   # RV:XX:XX:XX:XX
_BMSG_WRITE_TMS           = b'\x09\x02\x0B\x00%c%c%b' # RV:DI:XX:XX:XX:XX

def index_or_default(s):
    try:
        s = s[:s.index(b'\x00')]
    except ValueError:
        pass
    try:
        s = s[:s.index(b'\xFF')]
    except ValueError:
        pass
    return s


##############
# PRIMITIVES #
##############
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'}


class DigilentAdeptController(CableDriver):
    _primitives = [DigilentWriteTDIPrimitive, DigilentWriteTMSPrimitive,
                   DigilentWriteTMSTDIPrimitive, DigilentReadTDOPrimitive,
                   DigilentClockTickPrimitive]
    def __init__(self, dev):
        super(DigilentAdeptController, self).__init__(dev)
        h = self._dev.open()

        self.serialNumber = h.controlRead(
            0xC0, _CMSG_SERIAL_NO, 0, 0, 12).decode()
        self.name = index_or_default(
            h.controlRead(0xC0, _CMSG_USER_NAME, 0, 0, 16)).decode()
        #This is probably subtly wrong...
        pidraw = h.controlRead(0xC0, _CMSG_PROD_ID, 0, 0, 4)
        self.productId = (pidraw[3]<<24)|(pidraw[2]<<16)|\
            (pidraw[1]<<8)|pidraw[0] #%08x

        self.productName = index_or_default(
            h.controlRead(0xC0, _CMSG_PROD_NAME, 0, 0, 28)).decode()
        firmwareraw = h.controlRead(0xC0, _CMSG_FW_VER, 0, 0, 2)
        self.firmwareVersion = (firmwareraw[1]<<8)|firmwareraw[0]
        h.close()

        if (self.productId & 0xFF) <= 0x0F:
            self._cmdout_interface = 1
            self._cmdin_interface = 1
            self._datout_interface = 2
            self._datin_interface = 6
        else:
            self._cmdout_interface = 1
            self._cmdin_interface = 2
            self._datout_interface = 3
            self._datin_interface = 4


    def __repr__(self):
        return "%s(%s; Name: %s; SN: %s; FWver: %04x)"%\
            (self.__class__.__name__,
             self.productName,
             self.name,
             self.serialNumber,
             self.firmwareVersion) # pragma: no cover

    def _get_adv_trans_stats(self, cmd, return_tdo=False):
        """Utility function to fetch the transfer statistics for the last
        advanced transfer. Checking the stats appears to sync the
        controller. For details on the advanced transfer please refer
        to the documentation at
        http://diamondman.github.io/Adapt/cable_digilent_adept.html#bulk-requests

        """
        t = time()
        code, res = self.bulkCommand(b'\x03\x02%c\x00'%(0x80|cmd),\
                                     10 if return_tdo else 6)
        print("GET STATS TIME", time()-t)
        if len(res) == 4:
            count = struct.unpack('<I', res)[0]
            #if return_tdo:
            #    print("READ", count)
            #else:
            #    print("WRITTEN", count)
            return count
        elif len(res) == 8:
            assert len(res)==8,"WTF it is %s"%len(res)
            written, read =  struct.unpack('<II', res)
            #print("WRITTEN", written)
            #print("READ", read)
            return written, read
        return res

    def _update_scanchain(self, val):
        pass
        #if self._scanchain:
        #    if isinstance(val, bool):
        #        val = ConstantBitarray(, count)
        #    self._scanchain._tap_transition_driver_trigger(val)

    def bulkReadCmd(self, bytecount):
        return self._handle.bulkRead(self._cmdin_interface, bytecount)

    def bulkWriteCmd(self, data):
        return self._handle.bulkWrite(self._cmdout_interface, data)

    def bulkReadData(self, bytecount):
        return self._handle.bulkRead(self._datin_interface, bytecount)

    def bulkWriteData(self, data):
        return self._handle.bulkWrite(self._datout_interface, data)<commit_msg>Fixed oerflow of usb data in digilent driver on some boards.<commit_after>#-*- coding: utf-8 -*-
"""
    digilentdriver
    ~~~~~~~~~~~~~~

    Digilent driver for Linux USB JTAG controller

    :copyright: (c) 2014 by <NAME>
    :license: Pending, see LICENSE for more details.
"""

import struct
from time import time

from proteusisc.jtagUtils import blen2Blen, buff2Blen,\
    build_byte_align_buff
from proteusisc.cabledriver import CableDriver
from proteusisc.primitive import Level1Primitive, Executable
from proteusisc.bittypes import ConstantBitarray, NoCareBitarray,\
    CompositeBitarray, bitarray, PreferFalseBitarray
from proteusisc.contracts import NOCARE, ZERO, ONE, CONSTANT, ARBITRARY
from proteusisc.errors import JTAGEnableFailedError,\
    JTAGAlreadyEnabledError, JTAGControlError, JTAGNotEnabledError

#Controller documentation available at
#http://diamondman.github.io/Adapt/cable_digilent_adept.html
#This document is not complete and will evolve as Digilent adds
#new features to the protocol. Please report any issues.
#
#CONTROL MESSAGES:
_CMSG_PROD_NAME = 0xE1
_CMSG_USER_NAME = 0xE2
_CMSG_SERIAL_NO = 0xE4
_CMSG_FW_VER    = 0xE6
_CMSG_DEV_CAPS  = 0xE7
_CMSG_OEM_SEED  = 0xE8
_CMSG_PROD_ID   = 0xE9
_CMSG_OEM_CHECK = 0xEC

#SZ:CT:RQ:00:{Parameters to the request if any}
#   SZ: Length of bulk packet minus 1.
#   CT: Category or request. Category 0x02 appears to be JTAG.
#   RQ: Request Code
#
#BULK MSG PARAMS (Min 1 byte each):
# XX:XX:XX:XX: Transaction count in bits (4 bytes). Little Engian.
# RV: Should return TDO data (Boolean). Little Endian.
# MS: TMS VALUE (Boolean)
# DI: TDI VALUE (Boolean)
# DO: TDO VALUE (Boolean)
# CK: TCK VALUE (Boolean)
# SP: SPEED in Bits/Second
_BMSG_ENABLE_JTAG         = b'\x03\x02\x00\x00'       # NO PARAMS
_BMSG_DISABLE_JTAG        = b'\x03\x02\x01\x00'       # NO PARAMS
_BMSG_PORT_INFO           = b'\x04\x02\x02\x00'       # ??
_BMSG_SET_SPEED           = b'\x07\x02\x03\x00%b'     # SP:SP:SP:SP
_BMSG_GET_SPEED           = b'\x03\x02\x04\x00'       # NO PARAMS
_BMSG_SET_TMS_TDI_TDO     = b'\x06\x02\x05\x00%c%c%c' # MS:DI:DO
_BMSG_GET_TMS_TDI_TDO_TCK = b'\x03\x02\x06\x00'       # NO PARAMS
_BMSG_CLOCK_TICK          = b'\x09\x02\x07\x00%c%c%b' # MS:DI:XX:XX:XX:XX
_BMSG_WRITE_TDI           = b'\x09\x02\x08\x00%c%c%b' # RV:MS:XX:XX:XX:XX
_BMSG_READ_TDO            = b'\x09\x02\x09\x00%c%c%b' # MS:DI:XX:XX:XX:XX
_BMSG_WRITE_TMS_TDI       = b'\x08\x02\x0A\x00%c%b'   # RV:XX:XX:XX:XX
_BMSG_WRITE_TMS           = b'\x09\x02\x0B\x00%c%c%b' # RV:DI:XX:XX:XX:XX

def index_or_default(s):
    try:
        s = s[:s.index(b'\x00')]
    except ValueError:
        pass
    try:
        s = s[:s.index(b'\xFF')]
    except ValueError:
        pass
    return s


##############
# PRIMITIVES #
##############
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'}


class DigilentAdeptController(CableDriver):
    _primitives = [DigilentWriteTDIPrimitive, DigilentWriteTMSPrimitive,
                   DigilentWriteTMSTDIPrimitive, DigilentReadTDOPrimitive,
                   DigilentClockTickPrimitive]
    def __init__(self, dev):
        super(DigilentAdeptController, self).__init__(dev)
        h = self._dev.open()

        self.serialNumber = h.controlRead(
            0xC0, _CMSG_SERIAL_NO, 0, 0, 12).decode()
        self.name = index_or_default(
            h.controlRead(0xC0, _CMSG_USER_NAME, 0, 0, 16)).decode()
        #This is probably subtly wrong...
        pidraw = h.controlRead(0xC0, _CMSG_PROD_ID, 0, 0, 4)
        self.productId = (pidraw[3]<<24)|(pidraw[2]<<16)|\
            (pidraw[1]<<8)|pidraw[0] #%08x

        self.productName = index_or_default(
            h.controlRead(0xC0, _CMSG_PROD_NAME, 0, 0, 28)).decode()
        firmwareraw = h.controlRead(0xC0, _CMSG_FW_VER, 0, 0, 2)
        self.firmwareVersion = (firmwareraw[1]<<8)|firmwareraw[0]
        h.close()

        if (self.productId & 0xFF) <= 0x0F:
            self._cmdout_interface = 1
            self._cmdin_interface = 1
            self._datout_interface = 2
            self._datin_interface = 6
        else:
            self._cmdout_interface = 1
            self._cmdin_interface = 2
            self._datout_interface = 3
            self._datin_interface = 4


    def __repr__(self):
        return "%s(%s; Name: %s; SN: %s; FWver: %04x)"%\
            (self.__class__.__name__,
             self.productName,
             self.name,
             self.serialNumber,
             self.firmwareVersion) # pragma: no cover

    def _get_adv_trans_stats(self, cmd, return_tdo=False):
        """Utility function to fetch the transfer statistics for the last
        advanced transfer. Checking the stats appears to sync the
        controller. For details on the advanced transfer please refer
        to the documentation at
        http://diamondman.github.io/Adapt/cable_digilent_adept.html#bulk-requests

        """
        t = time()
        code, res = self.bulkCommand(b'\x03\x02%c\x00'%(0x80|cmd), 10)
        print("GET STATS TIME", time()-t)
        if len(res) == 4:
            count = struct.unpack('<I', res)[0]
            #if return_tdo:
            #    print("READ", count)
            #else:
            #    print("WRITTEN", count)
            return count
        elif len(res) == 8:
            written, read =  struct.unpack('<II', res)
            #print("WRITTEN", written)
            #print("READ", read)
            return written, read
        return res

    def _update_scanchain(self, val):
        pass
        #if self._scanchain:
        #    if isinstance(val, bool):
        #        val = ConstantBitarray(, count)
        #    self._scanchain._tap_transition_driver_trigger(val)

    def bulkReadCmd(self, bytecount):
        return self._handle.bulkRead(self._cmdin_interface, bytecount)

    def bulkWriteCmd(self, data):
        return self._handle.bulkWrite(self._cmdout_interface, data)

    def bulkReadData(self, bytecount):
        return self._handle.bulkRead(self._datin_interface, bytecount)

    def bulkWriteData(self, data):
        return self._handle.bulkWrite(self._datout_interface, data)
{'fraction_non_alphanumeric': 0.11572777596873983, 'fraction_numerical': 0.029957668511885378, 'mean_word_length': 2.884644573741462, 'pattern_counts': {'":': 2, '<': 27, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2215798', 'n_tokens_mistral': 5961, 'n_tokens_neox': 5570, 'n_words': 1156}