class Controller(object): def __init__(self, dev=None, vendor_id=0x0403, product_id=0x8531, status=None): super(Controller, self).__init__() self.vendor = vendor_id self.product = product_id self.s = status def upload(self, filepath): """ Write a binary file to the the SPI Prom Args: filepath (String): Path to FPGA Binary (bin) image Returns (boolean): True: Successfully programmed False: Failed to program Raises: IOError: Failed to open binary file """ binf = "" f = open(filepath, "r") binf = f.read() f.close() #Allow the users to handle File Errors #Open the SPI Flash Device manager = serial_flash_manager.SerialFlashManager( self.vendor, self.product, 2) flash = manager.get_flash_device() #Print out the device was found if self.s: self.s.Info("Found: %s" % str(flash)) #Erase the flash if self.s: self.s.Info( "Erasing the SPI Flash device, this can take a minute or two..." ) flash.bulk_erase() #Write the binary file if self.s: self.s.Info("Flash erased, writing binary image to PROM") flash.write(0x00, binf) #Verify the data was read binf_rb = flash.read(0x00, len(binf)) binf_str = binf_rb.tostring() del flash del manager if binf_str != binf: raise NysaError( "Image Verification Failed!, data written is not the same as data read" ) def program(self): """ Send a program signal to the board, the FPGA will attempt to read the binary image file from the SPI prom. If successful the 'done' LED will illuminate Args: Nothing Returns: Nothing Raises: Nothing """ bbc = BitBangController(self.vendor, self.product, 2) if self.s: self.s.Important("Set signals to input") bbc.set_pins_to_input() bbc.set_pins_to_output() bbc.program_high() time.sleep(.5) bbc.program_low() time.sleep(.2) bbc.program_high() bbc.pins_on() bbc.set_pins_to_input() def read_bin_file(self, filepath): """ Read the binary image from the SPI Flash Args: filepath (String): Path to the filepath where the SPI image will be written to Returns: Nothing Raises: IOError: Problem openning file to write to """ manager = serial_flash_manager.SerialFlashManager( self.vendor, self.product, 2) flash = manager.get_flash_device() #Don't know how long the binary file is so we need to read the entire #Image binf_rb = flash.read(0x00, len(flash)) f = open(filepath, "w") binf_rb.tofile(f) f.close() def reset(self): """ Send a reset signal to the board, this is the same as pressing the 'reset' button Args: Nothing Returns: Nothing Raises: Nothing """ bbc = BitBangController(self.vendor, self.product, 2) bbc.set_soft_reset_to_output() bbc.soft_reset_high() time.sleep(.2) bbc.soft_reset_low() time.sleep(.2) bbc.soft_reset_high() bbc.pins_on() bbc.set_pins_to_input() def set_sync_fifo_mode(self): """ Change the mode of the FIFO to a synchronous FIFO Args: Nothing Returns: Nothing Raises: Nothing """ fifo = FifoController(self.vendor, self.product) fifo.set_sync_fifo() def set_debug_mode(self): """ Change the mode of the FIFO to a asynchronous FIFO Args: Nothing Returns: Nothing Raises: Nothing """ fifo = FifoController(self.vendor, self.product) fifo.set_async_fifo() def open_dev(self): """_open_dev Open an FTDI Communication Channel Args: Nothing Returns: Nothing Raises: Exception """ self.dev = Ftdi() frequency = 30.0E6 latency = 4 #Ftdi.add_type(self.vendor, self.product, 0x700, "ft2232h") self.dev.open(self.vendor, self.product, 0) #Drain the input buffer self.dev.purge_buffers() #Reset #Enable MPSSE Mode self.dev.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF) #Configure Clock frequency = self.dev._set_frequency(frequency) #Set Latency Timer self.dev.set_latency_timer(latency) #Set Chunk Size self.dev.write_data_set_chunksize(0x10000) self.dev.read_data_set_chunksize(0x10000) #Set the hardware flow control self.dev.set_flowctrl('hw') self.dev.purge_buffers() def ioctl(self, name, arg=None): raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name) def list_ioctl(self): raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name)
class _Artemis(Nysa): """ Artemis Concrete Class that implemented Artemis specific communication functions """ def __init__(self, idVendor=0x0403, idProduct=0x8531, sernum=None, status=False): Nysa.__init__(self, status) self.vendor = idVendor self.product = idProduct self.sernum = sernum self.dev = None #Run a full garbage collection so any previous references to Artemis will be removed gc.collect() self.lock = threading.Lock() self.dev = Ftdi() self._open_dev() self.name = "Artemis" self.interrupts = 0x00 self.events = [] for i in range(INTERRUPT_COUNT): e = threading.Event() e.set() self.events.append(e) self.hwq = Queue.Queue(10) self.hrq = Queue.Queue(10) self.d = ArtemisData() self.worker = WorkerThread(self.dev, self.hwq, self.hrq, self.d, self.lock, self.interrupt_update_callback) #Is there a way to indicate closing self.worker.setDaemon(True) self.worker.start() try: #XXX: Hack to fix a strange bug where FTDI #XXX: won't recognize Artemis until a read and reset occurs #self.ping() pass except NysaCommError: pass self.reset() ''' #status = True self.reader_thread = ReaderThread(self.dev, self.interrupt_update_callback, self.lock, status = status) self.reader_thread.setName("Reader Thread") #XXX: Need to find a better way to shut this down self.reader_thread.setDaemon(True) self.reader_thread.start() ''' def __del__(self): #if self.s: self.s.Debug( "Close reader thread") #self.lock.aquire() #if (self.reader_thread is not None) and self.reader_thread.isAlive(): # self.reader_thread.stop() # self.s.Debug( "Waiting to join") # self.reader_thread.join() #self.lock.release() #self.s = True #if self.s: self.s.Debug( "Reader thread joined") #self.dev.close() pass def _open_dev(self): """_open_dev Open an FTDI Communication Channel Args: Nothing Returns: Nothing Raises: Exception """ #This frequency should go up to 60MHz frequency = 30.0E6 #Latency can go down to 2 but there is a small chance there will be a #crash latency = 2 #Ftdi.add_type(self.vendor, self.product, 0x700, "ft2232h") self.dev.open(self.vendor, self.product, 0, serial=self.sernum) #Drain the input buffer self.dev.purge_buffers() #Reset #Configure Clock #frequency = self.dev._set_frequency(frequency) #Set Latency Timer self.dev.set_latency_timer(latency) #Set Chunk Size (Maximum Chunk size) self.dev.write_data_set_chunksize(0x10000) self.dev.read_data_set_chunksize(0x10000) #Set the hardware flow control self.dev.set_flowctrl('hw') self.dev.purge_buffers() #Enable MPSSE Mode self.dev.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF) def ipc_comm_response(self, name): try: resp = self.hrq.get(block=True, timeout=ARTEMIS_QUEUE_TIMEOUT) if resp == ARTEMIS_RESP_OK: #print "%s got an OK response!" % current_thread().name return self.d.data else: raise NysaCommError("Artemis response error %s: %d" % (name, resp)) except Queue.Empty: raise NysaCommError("Artemis error %s: timeout: %d" % (name, ARTEMIS_QUEUE_TIMEOUT)) def read(self, address, length=1, disable_auto_inc=False): """read read data from Artemis Command Format ID 02 NN NN NN OO AA AA AA ID: ID Byte (0xCD) 02: Read Command (12 for memory read) NN: Size of Read (3 Bytes) OO: Offset (for peripheral, part of address for mem) AA: Address (3 bytes for peripheral, (4 bytes including offset for mem) Args: address (long): Address of the register/memory to read length (int): Number of 32-bit words to read disable_auto_inc (bool): if true, auto increment feature will be disabled Returns: (Byte Array): A byte array containing the raw data returned from Artemis Raises: NysaCommError """ with self.lock: self.d.data = Array('B', [0xCD, 0x02]) if address >= ARTEMIS_MEMORY_OFFSET: address -= ARTEMIS_MEMORY_OFFSET self.d.data[1] = self.d.data[1] | 0x10 if disable_auto_inc: self.d.data[1] = self.d.data[1] | 0x20 fmt_string = "%06X" % length self.d.data.fromstring(fmt_string.decode('hex')) #Add the address addr_string = "%08X" % (address & 0xFFFFFFFF) self.d.data.fromstring(addr_string.decode('hex')) self.d.length = length self.hwq.put(ARTEMIS_READ) return self.ipc_comm_response("read") def write(self, address, data, disable_auto_inc=False): """write Write data to a Nysa image Command Format ID 01 NN NN NN OO AA AA AA DD DD DD DD ID: ID Byte (0xCD) 01: Write Command (11 for Memory Write) NN: Size of Write (3 Bytes) OO: Offset (for peripheral, part of address for mem) AA: Address (3 bytes for peripheral, #(4 bytes including offset for mem) DD: Data (4 bytes) Args: address (long): Address of the register/memory to write to memory_device (boolean): True: Memory device False: Peripheral device data (array of bytes): Array of raw bytes to send to the devcie disable_auto_inc (boolean): Default False Set to true if only writing to one memory address (FIFO Mode) Returns: Nothing Raises: NysaCommError """ with self.lock: length = len(data) / 4 #Create an Array with the identification byte and code for writing self.d.data = Array('B', [0xCD, 0x01]) if address >= ARTEMIS_MEMORY_OFFSET: address -= ARTEMIS_MEMORY_OFFSET self.d.data[1] = self.d.data[1] | 0x10 if disable_auto_inc: self.d.data[1] = self.d.data[1] | 0x20 #Append the length into the first 24 bits fmt_string = "%06X" % length self.d.data.fromstring(fmt_string.decode('hex')) addr_string = "%08X" % (address & 0xFFFFFFFF) self.d.data.fromstring(addr_string.decode('hex')) self.d.data.extend(data) self.hwq.put(ARTEMIS_WRITE) self.ipc_comm_response("write") def ping(self): """ping Command Format ID 00 00 00 00 00 00 00 00 ID: ID Byte (0xCD) 00: Ping Command 00 00 00 00 00 00 00: Zeros Args: Nothing Returns: Nothing Raises: NysaCommError """ with self.lock: self.hwq.put(ARTEMIS_PING) self.ipc_comm_response("ping") def reset(self): """ reset Software reset the Nysa FPGA Master, this may not actually reset the entire FPGA image ID 03 00 00 00 ID: ID Byte (0xCD) 00: Reset Command 00 00 00: Zeros Args: Nothing Return: Nothing Raises: NysaCommError: Failue in communication """ with self.lock: self.d.data = (self.vendor, self.product) self.hwq.put(ARTEMIS_RESET) self.ipc_comm_response("reset") def is_programmed(self): """ Check if the FPGA is programmed Args: Nothing Return (Boolean): True: FPGA is programmed False: FPGA is not programmed Raises: NysaCommError: Failue in communication """ with self.lock: self.d.data = (self.vendor, self.product) self.hwq.put(ARTEMIS_IS_PROGRAMMED) self.dev.purge_buffers() return self.ipc_comm_response("is programmed") def dump_core(self): """ dump_core Returns the state of the wishbone master priorto a reset, this is usefu for statusging a crash Command Format ID 0F 00 00 00 00 00 00 00 ID: ID Byte (0xCD) 0F: Dump Core Command 00 00 00 00 00 00 00 00 00 00 00: Zeros Args: Nothing Returns: (Array of 32-bit Values) to be parsed by the core_analyzer utility Raises: NysaCommError: A failure in communication is detected """ with self.lock: self.hwq.put(ARTEMIS_DUMP_CORE) return self.ipc_comm_response("dump core") def register_interrupt_callback(self, index, callback): """ register_interrupt Setup the thread to call the callback when an interrupt is detected Args: index (Integer): bit position of the device if the device is 1, then set index = 1 callback: a function to call when an interrupt is detected Returns: Nothing Raises: Nothing """ self.worker.register_interrupt_cb(index, callback) def unregister_interrupt_callback(self, index, callback=None): """ unregister_interrupt_callback Removes an interrupt callback from the reader thread list Args: index (Integer): bit position of the associated device EX: if the device that will receive callbacks is 1, index = 1 callback: a function to remove from the callback list Returns: Nothing Raises: Nothing (This function fails quietly if ther callback is not found) """ self.worker.unregister_interrupt_cb(index, callback) def wait_for_interrupts(self, wait_time=1, dev_id=None): """ wait_for_interrupts listen for interrupts for the user specified amount of time The Nysa image will send a small packet of info to the host when a slave needs to send information to the host Response Format DC 01 00 00 00 II II II II DC: Inverted CD is the start of a response 01: Interrupt ID 00 00 00 00 00 00 00 00: Zeros, reserved for future use II II II II: 32-bit interrupts Args: wait_time (Integer): the amount of time in seconds to wait for an interrupt dev_id (Integer): Optional device id, if set the function will look if an interrupt has already been declared for that function, if so then return immediately otherwise setup a callback for this Returns (boolean): True: Interrupts were detected Falses: Interrupts were not detected Raises: NysaCommError: A failure in communication is detected """ if dev_id is None: dev_id = 0 e = self.events[dev_id] #print "Checking events!" with self.lock: #Check if we have interrupts if (self.interrupts & (1 << dev_id)) > 0: #There are already existing interrupts, we're done return True #if we don't have interrupts clear the associated event #Clear the event, the interrupt handler will unblock this e.clear() #Now wait for interrupts if e.wait(wait_time): #Received an interrupt return True #Timed out while waiting for interrupts e.set() return False def interrupt_update_callback(self, interrupts): #print "Entered interrupt update callback" self.interrupts = interrupts for i in range(INTERRUPT_COUNT): if i == 0: if not self.events[i].is_set(): #self.s.Debug( "interrupt!") self.events[i].set() elif (self.interrupts & (1 << i)) > 0: if not self.events[i].is_set(): self.events[i].set() def get_board_name(self): return "Artemis" def upload(self, filepath): artemis_utils.upload(self.vendor, self.product, self.sernum, filepath, self.s) def program(self): artemis_utils.program(self.vendor, self.product, self.sernum, self.s) def ioctl(self, name, arg=None): raise AssertionError( "%s not implemented" % sys._getframe().f_code.co_name, self.s) def list_ioctl(self): raise AssertionError( "%s not implemented" % sys._getframe().f_code.co_name, self.s) def get_sdb_base_address(self): return 0x00000000
class Controller(object): def __init__(self, dev = None, vendor_id = 0x0403, product_id = 0x8530, status = None): super (Controller, self).__init__() self.vendor = vendor_id self.product = product_id self.s = status def upload(self, filepath): """ Write a binary file to the the SPI Prom Args: filepath (String): Path to FPGA Binary (bin) image Returns (boolean): True: Successfully programmed False: Failed to program Raises: IOError: Failed to open binary file """ binf = "" f = open(filepath, "r") binf = f.read() f.close() #Allow the users to handle File Errors #Open the SPI Flash Device manager = serial_flash_manager.SerialFlashManager(self.vendor, self.product, 2) flash = manager.get_flash_device() #Print out the device was found if self.s: self.s.Info("Found: %s" % str(flash)) #Erase the flash if self.s: self.s.Info("Erasing the SPI Flash device, this can take a minute or two...") flash.bulk_erase() #Write the binary file if self.s: self.s.Info("Flash erased, writing binary image to PROM") flash.write(0x00, binf) #Verify the data was read binf_rb = flash.read(0x00, len(binf)) binf_str = binf_rb.tostring() del flash del manager if binf_str != binf: raise NysaError("Image Verification Failed!, data written is not the same as data read") def program(self): """ Send a program signal to the board, the FPGA will attempt to read the binary image file from the SPI prom. If successful the 'done' LED will illuminate Args: Nothing Returns: Nothing Raises: Nothing """ bbc = BitBangController(self.vendor, self.product, 2) if self.s: self.s.Important("Set signals to input") bbc.set_pins_to_input() bbc.set_pins_to_output() bbc.program_high() time.sleep(.5) bbc.program_low() time.sleep(.2) bbc.program_high() bbc.pins_on() bbc.set_pins_to_input() def read_bin_file(self, filepath): """ Read the binary image from the SPI Flash Args: filepath (String): Path to the filepath where the SPI image will be written to Returns: Nothing Raises: IOError: Problem openning file to write to """ manager = serial_flash_manager.SerialFlashManager(self.vendor, self.product, 2) flash = manager.get_flash_device() #Don't know how long the binary file is so we need to read the entire #Image binf_rb = flash.read(0x00, len(flash)) f = open(filepath, "w") binf_rb.tofile(f) f.close() def reset(self): """ Send a reset signal to the board, this is the same as pressing the 'reset' button Args: Nothing Returns: Nothing Raises: Nothing """ bbc = BitBangController(self.vendor, self.product, 2) bbc.set_soft_reset_to_output() bbc.soft_reset_high() time.sleep(.2) bbc.soft_reset_low() time.sleep(.2) bbc.soft_reset_high() bbc.pins_on() bbc.set_pins_to_input() def set_sync_fifo_mode(self): """ Change the mode of the FIFO to a synchronous FIFO Args: Nothing Returns: Nothing Raises: Nothing """ fifo = FifoController(self.vendor, self.product) fifo.set_sync_fifo() def set_debug_mode(self): """ Change the mode of the FIFO to a asynchronous FIFO Args: Nothing Returns: Nothing Raises: Nothing """ fifo = FifoController(self.vendor, self.product) fifo.set_async_fifo() def open_dev(self): """_open_dev Open an FTDI Communication Channel Args: Nothing Returns: Nothing Raises: Exception """ self.dev = Ftdi() frequency = 30.0E6 latency = 4 #Ftdi.add_type(self.vendor, self.product, 0x700, "ft2232h") self.dev.open(self.vendor, self.product, 0) #Drain the input buffer self.dev.purge_buffers() #Reset #Enable MPSSE Mode self.dev.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF) #Configure Clock frequency = self.dev._set_frequency(frequency) #Set Latency Timer self.dev.set_latency_timer(latency) #Set Chunk Size self.dev.write_data_set_chunksize(0x10000) self.dev.read_data_set_chunksize(0x10000) #Set the hardware flow control self.dev.set_flowctrl('hw') self.dev.purge_buffers() def ioctl(self, name, arg = None): raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name) def list_ioctl(self): raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name)
class _Dionysus (Nysa): """ Dionysus Concrete Class that implemented Dionysus specific communication functions """ def __init__(self, idVendor = 0x0403, idProduct = 0x8530, sernum = None, status = False): Nysa.__init__(self, status) self.vendor = idVendor self.product = idProduct self.sernum = sernum self.dev = None #Run a full garbage collection so any previous references to Dionysus will be removed gc.collect() self.lock = threading.Lock() self.dev = Ftdi() self._open_dev() self.name = "Dionysus" self.interrupts = 0x00 self.events = [] for i in range (INTERRUPT_COUNT): e = threading.Event() e.set() self.events.append(e) self.hwq = Queue.Queue(10) self.hrq = Queue.Queue(10) self.d = DionysusData() self.worker = WorkerThread(self.dev, self.hwq, self.hrq, self.d, self.lock, self.interrupt_update_callback) #Is there a way to indicate closing self.worker.setDaemon(True) self.worker.start() try: #XXX: Hack to fix a strange bug where FTDI #XXX: won't recognize Dionysus until a read and reset occurs self.ping() except NysaCommError: pass self.reset() ''' #status = True self.reader_thread = ReaderThread(self.dev, self.interrupt_update_callback, self.lock, status = status) self.reader_thread.setName("Reader Thread") #XXX: Need to find a better way to shut this down self.reader_thread.setDaemon(True) self.reader_thread.start() ''' def __del__(self): #if self.s: self.s.Debug( "Close reader thread") #self.lock.aquire() #if (self.reader_thread is not None) and self.reader_thread.isAlive(): # self.reader_thread.stop() # self.s.Debug( "Waiting to join") # self.reader_thread.join() #self.lock.release() #self.s = True #if self.s: self.s.Debug( "Reader thread joined") #self.dev.close() pass def _open_dev(self): """_open_dev Open an FTDI Communication Channel Args: Nothing Returns: Nothing Raises: Exception """ #This frequency should go up to 60MHz frequency = 30.0E6 #Latency can go down to 2 but there is a small chance there will be a #crash latency = 2 #Ftdi.add_type(self.vendor, self.product, 0x700, "ft2232h") self.dev.open(self.vendor, self.product, 0, serial = self.sernum) #Drain the input buffer self.dev.purge_buffers() #Reset #Configure Clock #frequency = self.dev._set_frequency(frequency) #Set Latency Timer self.dev.set_latency_timer(latency) #Set Chunk Size (Maximum Chunk size) self.dev.write_data_set_chunksize(0x10000) self.dev.read_data_set_chunksize(0x10000) #Set the hardware flow control self.dev.set_flowctrl('hw') self.dev.purge_buffers() #Enable MPSSE Mode self.dev.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF) def ipc_comm_response(self, name): try: resp = self.hrq.get(block = True, timeout = DIONYSUS_QUEUE_TIMEOUT) if resp == DIONYSUS_RESP_OK: #print "%s got an OK response!" % current_thread().name return self.d.data else: raise NysaCommError("Dionysus response error %s: %d" % (name, resp)) except Queue.Empty: raise NysaCommError("Dionysus error %s: timeout: %d" % (name, DIONYSUS_QUEUE_TIMEOUT)) def read(self, address, length = 1, disable_auto_inc = False): """read read data from Dionysus Command Format ID 02 NN NN NN OO AA AA AA ID: ID Byte (0xCD) 02: Read Command (12 for memory read) NN: Size of Read (3 Bytes) OO: Offset (for peripheral, part of address for mem) AA: Address (3 bytes for peripheral, (4 bytes including offset for mem) Args: address (long): Address of the register/memory to read length (int): Number of 32-bit words to read disable_auto_inc (bool): if true, auto increment feature will be disabled Returns: (Byte Array): A byte array containing the raw data returned from Dionysus Raises: NysaCommError """ with self.lock: self.d.data = Array('B', [0xCD, 0x02]) if address >= DIONYSUS_MEMORY_OFFSET: address -= DIONYSUS_MEMORY_OFFSET self.d.data[1] = self.d.data[1] | 0x10 if disable_auto_inc: self.d.data[1] = self.d.data[1] | 0x20 fmt_string = "%06X" % length self.d.data.fromstring(fmt_string.decode('hex')) #Add the address addr_string = "%08X" % (address & 0xFFFFFFFF) self.d.data.fromstring(addr_string.decode('hex')) self.d.length = length self.hwq.put(DIONYSUS_READ) return self.ipc_comm_response("read") def write(self, address, data, disable_auto_inc = False): """write Write data to a Nysa image Command Format ID 01 NN NN NN OO AA AA AA DD DD DD DD ID: ID Byte (0xCD) 01: Write Command (11 for Memory Write) NN: Size of Write (3 Bytes) OO: Offset (for peripheral, part of address for mem) AA: Address (3 bytes for peripheral, #(4 bytes including offset for mem) DD: Data (4 bytes) Args: address (long): Address of the register/memory to write to memory_device (boolean): True: Memory device False: Peripheral device data (array of bytes): Array of raw bytes to send to the devcie disable_auto_inc (boolean): Default False Set to true if only writing to one memory address (FIFO Mode) Returns: Nothing Raises: NysaCommError """ with self.lock: length = len(data) / 4 #Create an Array with the identification byte and code for writing self.d.data = Array ('B', [0xCD, 0x01]) if address >= DIONYSUS_MEMORY_OFFSET: address -= DIONYSUS_MEMORY_OFFSET self.d.data[1] = self.d.data[1] | 0x10 if disable_auto_inc: self.d.data[1] = self.d.data[1] | 0x20 #Append the length into the first 24 bits fmt_string = "%06X" % length self.d.data.fromstring(fmt_string.decode('hex')) addr_string = "%08X" % (address & 0xFFFFFFFF) self.d.data.fromstring(addr_string.decode('hex')) self.d.data.extend(data) self.hwq.put(DIONYSUS_WRITE) self.ipc_comm_response("write") def ping (self): """ping Command Format ID 00 00 00 00 00 00 00 00 ID: ID Byte (0xCD) 00: Ping Command 00 00 00 00 00 00 00: Zeros Args: Nothing Returns: Nothing Raises: NysaCommError """ with self.lock: self.hwq.put(DIONYSUS_PING) self.ipc_comm_response("ping") def reset (self): """ reset Software reset the Nysa FPGA Master, this may not actually reset the entire FPGA image ID 03 00 00 00 ID: ID Byte (0xCD) 00: Reset Command 00 00 00: Zeros Args: Nothing Return: Nothing Raises: NysaCommError: Failue in communication """ with self.lock: self.d.data = (self.vendor, self.product) self.hwq.put(DIONYSUS_RESET) self.ipc_comm_response("reset") def is_programmed(self): """ Check if the FPGA is programmed Args: Nothing Return (Boolean): True: FPGA is programmed False: FPGA is not programmed Raises: NysaCommError: Failue in communication """ with self.lock: self.d.data = (self.vendor, self.product) self.hwq.put(DIONYSUS_IS_PROGRAMMED) return self.ipc_comm_response("is programmed") def dump_core(self): """ dump_core Returns the state of the wishbone master priorto a reset, this is usefu for statusging a crash Command Format ID 0F 00 00 00 00 00 00 00 ID: ID Byte (0xCD) 0F: Dump Core Command 00 00 00 00 00 00 00 00 00 00 00: Zeros Args: Nothing Returns: (Array of 32-bit Values) to be parsed by the core_analyzer utility Raises: NysaCommError: A failure in communication is detected """ with self.lock: self.hwq.put(DIONYSUS_DUMP_CORE) return self.ipc_comm_response("dump core") def register_interrupt_callback(self, index, callback): """ register_interrupt Setup the thread to call the callback when an interrupt is detected Args: index (Integer): bit position of the device if the device is 1, then set index = 1 callback: a function to call when an interrupt is detected Returns: Nothing Raises: Nothing """ self.worker.register_interrupt_cb(index, callback) def unregister_interrupt_callback(self, index, callback = None): """ unregister_interrupt_callback Removes an interrupt callback from the reader thread list Args: index (Integer): bit position of the associated device EX: if the device that will receive callbacks is 1, index = 1 callback: a function to remove from the callback list Returns: Nothing Raises: Nothing (This function fails quietly if ther callback is not found) """ self.worker.unregister_interrupt_cb(index, callback) def wait_for_interrupts(self, wait_time = 1, dev_id = None): """ wait_for_interrupts listen for interrupts for the user specified amount of time The Nysa image will send a small packet of info to the host when a slave needs to send information to the host Response Format DC 01 00 00 00 II II II II DC: Inverted CD is the start of a response 01: Interrupt ID 00 00 00 00 00 00 00 00: Zeros, reserved for future use II II II II: 32-bit interrupts Args: wait_time (Integer): the amount of time in seconds to wait for an interrupt dev_id (Integer): Optional device id, if set the function will look if an interrupt has already been declared for that function, if so then return immediately otherwise setup a callback for this Returns (boolean): True: Interrupts were detected Falses: Interrupts were not detected Raises: NysaCommError: A failure in communication is detected """ if dev_id is None: dev_id = 0 e = self.events[dev_id] #print "Checking events!" with self.lock: #Check if we have interrupts if (self.interrupts & (1 << dev_id)) > 0: #There are already existing interrupts, we're done return True #if we don't have interrupts clear the associated event #Clear the event, the interrupt handler will unblock this e.clear() #Now wait for interrupts if e.wait(wait_time): #Received an interrupt return True #Timed out while waiting for interrupts e.set() return False def interrupt_update_callback(self, interrupts): #print "Entered interrupt update callback" self.interrupts = interrupts for i in range (INTERRUPT_COUNT): if i == 0: if not self.events[i].is_set(): #self.s.Debug( "interrupt!") self.events[i].set() elif (self.interrupts & (1 << i)) > 0: if not self.events[i].is_set(): self.events[i].set() def get_board_name(self): return "Dionysus" def upload(self, filepath): dionysus_utils.upload(self.vendor, self.product, self.sernum, filepath, self.s) def program (self): dionysus_utils.program(self.vendor, self.product, self.sernum, self.s) def ioctl(self, name, arg = None): raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name, self.s) def list_ioctl(self): raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name, self.s) def get_sdb_base_address(self): return 0x00000000