Last active
January 1, 2016 14:29
-
-
Save makestuff/8158151 to your computer and use it in GitHub Desktop.
Python binding matching the libfpgalink/20131101 DLL release
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python | |
| # | |
| # Copyright (C) 2009-2012 Chris McClelland | |
| # | |
| # This program is free software: you can redistribute it and/or modify | |
| # it under the terms of the GNU Lesser General Public License as published by | |
| # the Free Software Foundation, either version 3 of the License, or | |
| # (at your option) any later version. | |
| # | |
| # This program is distributed in the hope that it will be useful, | |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| # GNU Lesser General Public License for more details. | |
| # | |
| # You should have received a copy of the GNU Lesser General Public License | |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| # | |
| import array | |
| import time | |
| import sys | |
| import argparse | |
| from ctypes import * | |
| # Define types | |
| class FLContext(Structure): | |
| pass | |
| class FLException(Exception): | |
| pass | |
| FLHandle = POINTER(FLContext) | |
| FLStatus = c_uint | |
| FL_SUCCESS = 0 | |
| uint32 = c_uint | |
| uint16 = c_ushort | |
| uint8 = c_ubyte | |
| ErrorString = c_char_p | |
| # Get DLL | |
| if ( sys.platform.startswith("linux") ): | |
| cdll.LoadLibrary("libfpgalink.so") | |
| fpgalink = CDLL("libfpgalink.so") | |
| elif ( sys.platform == "darwin" ): | |
| cdll.LoadLibrary("libfpgalink.dylib") | |
| fpgalink = CDLL("libfpgalink.dylib") | |
| elif ( sys.platform == "win32" ): | |
| windll.LoadLibrary("libfpgalink.dll") | |
| fpgalink = WinDLL("libfpgalink.dll") | |
| else: | |
| raise FLException("Unrecognised platform: " + sys.platform) | |
| # Miscellaneous Functions | |
| fpgalink.flInitialise.argtypes = [c_int, POINTER(ErrorString)] | |
| fpgalink.flInitialise.restype = FLStatus | |
| fpgalink.flFreeError.argtypes = [c_char_p] | |
| fpgalink.flFreeError.restype = None | |
| fpgalink.flSleep.argtypes = [uint32] | |
| fpgalink.flSleep.restype = None | |
| fpgalink.flLoadFile.argtypes = [c_char_p, POINTER(uint32)] | |
| fpgalink.flLoadFile.restype = POINTER(uint8) | |
| fpgalink.flFreeFile.argtypes = [POINTER(uint8)] | |
| fpgalink.flFreeFile.restype = None | |
| fpgalink.flSingleBitPortAccess.argtypes = [FLHandle, uint8, uint8, uint8, uint8, POINTER(uint8), POINTER(ErrorString)] | |
| fpgalink.flSingleBitPortAccess.restype = FLStatus | |
| fpgalink.flMultiBitPortAccess.argtypes = [FLHandle, c_char_p, POINTER(uint32), POINTER(ErrorString)] | |
| fpgalink.flMultiBitPortAccess.restype = FLStatus | |
| # Connection Lifecycle | |
| fpgalink.flOpen.argtypes = [c_char_p, POINTER(FLHandle), POINTER(ErrorString)] | |
| fpgalink.flOpen.restype = FLStatus | |
| fpgalink.flClose.argtypes = [FLHandle] | |
| fpgalink.flClose.restype = None | |
| # Device Capabilities and Status | |
| fpgalink.flIsDeviceAvailable.argtypes = [c_char_p, POINTER(uint8), POINTER(ErrorString)] | |
| fpgalink.flIsDeviceAvailable.restype = FLStatus | |
| fpgalink.flIsNeroCapable.argtypes = [FLHandle] | |
| fpgalink.flIsNeroCapable.restype = uint8 | |
| fpgalink.flIsCommCapable.argtypes = [FLHandle, uint8] | |
| fpgalink.flIsCommCapable.restype = uint8 | |
| # CommFPGA Operations | |
| fpgalink.flSelectConduit.argtypes = [FLHandle, uint8, POINTER(ErrorString)] | |
| fpgalink.flSelectConduit.restype = FLStatus | |
| fpgalink.flIsFPGARunning.argtypes = [FLHandle, POINTER(uint8), POINTER(ErrorString)] | |
| fpgalink.flIsFPGARunning.restype = FLStatus | |
| fpgalink.flWriteChannel.argtypes = [FLHandle, uint8, uint32, POINTER(uint8), POINTER(ErrorString)] | |
| fpgalink.flWriteChannel.restype = FLStatus | |
| fpgalink.flReadChannel.argtypes = [FLHandle, uint8, uint32, POINTER(uint8), POINTER(ErrorString)] | |
| fpgalink.flReadChannel.restype = FLStatus | |
| # NeroProg Operations | |
| fpgalink.flProgram.argtypes = [FLHandle, c_char_p, c_char_p, POINTER(ErrorString)] | |
| fpgalink.flProgram.restype = FLStatus | |
| fpgalink.jtagScanChain.argtypes = [FLHandle, c_char_p, POINTER(uint32), POINTER(uint32), uint32, POINTER(ErrorString)] | |
| fpgalink.jtagScanChain.restype = FLStatus | |
| fpgalink.jtagOpen.argtypes = [FLHandle, c_char_p, POINTER(ErrorString)] | |
| fpgalink.jtagOpen.restype = FLStatus | |
| fpgalink.jtagClose.argtypes = [FLHandle, POINTER(ErrorString)] | |
| fpgalink.jtagClose.restype = FLStatus | |
| fpgalink.jtagClockFSM.argtypes = [FLHandle, uint32, uint8, POINTER(ErrorString)] | |
| fpgalink.jtagClockFSM.restype = FLStatus | |
| fpgalink.jtagClocks.argtypes = [FLHandle, uint32, POINTER(ErrorString)] | |
| fpgalink.jtagClocks.restype = FLStatus | |
| # FX2LP Firmware Operations | |
| fpgalink.flLoadStandardFirmware.argtypes = [c_char_p, c_char_p, POINTER(ErrorString)] | |
| fpgalink.flLoadStandardFirmware.restype = FLStatus | |
| fpgalink.flFlashStandardFirmware.argtypes = [FLHandle, c_char_p, POINTER(ErrorString)] | |
| fpgalink.flFlashStandardFirmware.restype = FLStatus | |
| fpgalink.flSaveFirmware.argtypes = [FLHandle, uint32, c_char_p, POINTER(ErrorString)] | |
| fpgalink.flSaveFirmware.restype = FLStatus | |
| fpgalink.flLoadCustomFirmware.argtypes = [c_char_p, c_char_p, POINTER(ErrorString)] | |
| fpgalink.flLoadCustomFirmware.restype = FLStatus | |
| fpgalink.flFlashCustomFirmware.argtypes = [FLHandle, c_char_p, uint32, POINTER(ErrorString)] | |
| fpgalink.flFlashCustomFirmware.restype = FLStatus | |
| # Open a connection to the FPGALink device | |
| def flOpen(vp): | |
| handle = FLHandle() | |
| error = ErrorString() | |
| status = fpgalink.flOpen(vp.encode('ascii'), byref(handle), byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| return handle | |
| # Close the FPGALink connection | |
| def flClose(handle): | |
| fpgalink.flClose(handle) | |
| # Await renumeration - return true if found before timeout | |
| def flAwaitDevice(vp, timeout): | |
| error = ErrorString() | |
| isAvailable = uint8() | |
| fpgalink.flSleep(1000); | |
| while ( True ): | |
| fpgalink.flSleep(100); | |
| status = fpgalink.flIsDeviceAvailable(vp.encode('ascii'), byref(isAvailable), byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| timeout = timeout - 1 | |
| if ( isAvailable ): | |
| return True | |
| if ( timeout == 0 ): | |
| return False | |
| # Query NeroJTAG capability | |
| def flIsNeroCapable(handle): | |
| if ( fpgalink.flIsNeroCapable(handle) ): | |
| return True | |
| else: | |
| return False | |
| # Query CommFPGA capability | |
| def flIsCommCapable(handle, conduit): | |
| if ( fpgalink.flIsCommCapable(handle, conduit) ): | |
| return True | |
| else: | |
| return False | |
| # Access the I/O ports on the micro | |
| def flSingleBitPortAccess(handle, portNumber, bitNumber, drive, high): | |
| error = ErrorString() | |
| bitRead = uint8() | |
| status = fpgalink.flSingleBitPortAccess(handle, portNumber, bitNumber, drive, high, byref(bitRead), byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| return bitRead.value | |
| # Access the I/O ports on the micro | |
| def flMultiBitPortAccess(handle, portConfig): | |
| error = ErrorString() | |
| readState = uint32() | |
| status = fpgalink.flMultiBitPortAccess(handle, portConfig.encode('ascii'), byref(readState), byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| return readState.value | |
| # Set the FIFO mode | |
| def flSelectConduit(handle, fifoMode): | |
| error = ErrorString() | |
| status = fpgalink.flSelectConduit(handle, fifoMode, byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| # Return true if the FPGA is actually running | |
| def flIsFPGARunning(handle): | |
| error = ErrorString() | |
| isRunning = uint8() | |
| status = fpgalink.flIsFPGARunning(handle, byref(isRunning), byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| if ( isRunning ): | |
| return True | |
| else: | |
| return False | |
| # Write one or more bytes to the specified channel | |
| def flWriteChannel(handle, chan, values): | |
| error = ErrorString() | |
| if ( isinstance(values, bytearray) ): | |
| # Write the contents of the byte array: | |
| numValues = len(values) | |
| BufType = uint8*numValues | |
| buf = BufType.from_buffer(values) | |
| status = fpgalink.flWriteChannel(handle, chan, numValues, buf, byref(error)) | |
| elif ( isinstance(values, int) ): | |
| # Write a single integer | |
| if ( values > 0xFF ): | |
| raise FLException("Supplied value won't fit in a byte!") | |
| status = fpgalink.flWriteChannel(handle, chan, 1, (uint8*1)(values), byref(error)) | |
| else: | |
| # Write the contents of a file | |
| fileLen = uint32() | |
| fileData = fpgalink.flLoadFile(values.encode('ascii'), byref(fileLen)) | |
| if ( fileData == None ): | |
| raise FLException("Cannot load file!") | |
| status = fpgalink.flWriteChannel(handle, chan, fileLen, fileData, byref(error)) | |
| fpgalink.flFreeFile(fileData) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| # Read one or more values from the specified channel | |
| def flReadChannel(handle, chan, count = 1): | |
| error = ErrorString() | |
| if ( count == 1 ): | |
| # Read a single byte | |
| buf = uint8() | |
| status = fpgalink.flReadChannel(handle, chan, 1, byref(buf), byref(error)) | |
| returnValue = buf.value | |
| else: | |
| # Read multiple bytes | |
| byteArray = bytearray(count) | |
| BufType = uint8*count | |
| buf = BufType.from_buffer(byteArray) | |
| status = fpgalink.flReadChannel(handle, chan, count, buf, byref(error)) | |
| returnValue = byteArray | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| return returnValue | |
| # Load standard firmware into the FX2LP chip | |
| def flLoadStandardFirmware(curVidPid, newVidPid): | |
| error = ErrorString() | |
| status = fpgalink.flLoadStandardFirmware(curVidPid.encode('ascii'), newVidPid.encode('ascii'), byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| # Load standard firmware into the FX2LP chip | |
| def flLoadCustomFirmware(curVidPid, fwFile): | |
| error = ErrorString() | |
| status = fpgalink.flLoadCustomFirmware(curVidPid.encode('ascii'), fwFile.encode('ascii'), byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| # Append channel write to init buffer | |
| def flAppendWriteChannelCommand(handle, chan, values): | |
| error = ErrorString() | |
| if ( isinstance(values, (list, tuple, array.array)) ): | |
| numValues = len(values) | |
| status = fpgalink.flAppendWriteChannelCommand(handle, chan, numValues, (uint8*numValues)(*values), byref(error)) | |
| elif ( isinstance(values, int) ): | |
| status = fpgalink.flAppendWriteChannelCommand(handle, chan, 1, (uint8*1)(values), byref(error)) | |
| else: | |
| fileLen = uint32() | |
| fileData = fpgalink.flLoadFile(values, byref(fileLen)) | |
| if ( fileData == None ): | |
| raise FLException("Cannot load file!") | |
| status = fpgalink.flAppendWriteChannelCommand(handle, chan, fileLen, fileData, byref(error)) | |
| fpgalink.flFreeFile(fileData) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| # Flash standard firmware into the FX2LP's EEPROM | |
| def flFlashStandardFirmware(handle, newVidPid): | |
| error = ErrorString() | |
| status = fpgalink.flFlashStandardFirmware(handle, newVidPid.encode('ascii'), byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| # Initialise the library | |
| def flInitialise(debugLevel): | |
| error = ErrorString() | |
| status = fpgalink.flInitialise(debugLevel, byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| # Program a device using the given config string and file | |
| def flProgram(handle, progConfig, progFile = None): | |
| error = ErrorString() | |
| if ( progFile != None ): | |
| progFile = progFile.encode('ascii') | |
| status = fpgalink.flProgram(handle, progConfig.encode('ascii'), progFile, byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| # Scan the JTAG chain | |
| def jtagScanChain(handle, portConfig): | |
| error = ErrorString() | |
| ChainType = (uint32 * 16) # Guess there are fewer than 16 devices | |
| chain = ChainType() | |
| length = uint32(0) | |
| status = fpgalink.jtagScanChain(handle, portConfig, byref(length), chain, 16, byref(error)) | |
| if ( length.value > 16 ): | |
| # We know exactly how many devices there are, so try again | |
| ChainType = (uint32 * length.value) | |
| chain = ChainType() | |
| status = fpgalink.jtagScanChain(handle, portConfig, None, chain, length.value, byref(error)) | |
| result = [] | |
| for id in chain[:length.value]: | |
| result.append(id) | |
| return result | |
| # Open a JTAG port | |
| def jtagOpen(handle, portConfig): | |
| error = ErrorString() | |
| status = fpgalink.jtagOpen(handle, portConfig.encode('ascii'), byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| # Close a JTAG port | |
| def jtagClose(handle): | |
| error = ErrorString() | |
| status = fpgalink.jtagClose(handle, byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| # Transition the TAP state machine | |
| def jtagClockFSM(handle, bitPattern, transitionCount): | |
| error = ErrorString() | |
| status = fpgalink.jtagClockFSM(handle, bitPattern, transitionCount, byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| # Transition the TAP state machine | |
| def jtagClocks(handle, numClocks): | |
| error = ErrorString() | |
| status = fpgalink.jtagClocks(handle, numClocks, byref(error)) | |
| if ( status != FL_SUCCESS ): | |
| s = str(error.value) | |
| fpgalink.flFreeError(error) | |
| raise FLException(s) | |
| flInitialise(0) | |
| # Main function if we're not loaded as a module | |
| if __name__ == "__main__": | |
| print "FPGALink Python Example Copyright (C) 2011-2013 Chris McClelland\n" | |
| parser = argparse.ArgumentParser(description='Load FX2LP firmware, load the FPGA, interact with the FPGA.') | |
| parser.add_argument('-i', action="store", nargs=1, metavar="<VID:PID>", help="vendor ID and product ID (e.g 04B4:8613)") | |
| parser.add_argument('-v', action="store", nargs=1, required=True, metavar="<VID:PID>", help="VID, PID and opt. dev ID (e.g 1D50:602B:0002)") | |
| parser.add_argument('-d', action="store", nargs=1, metavar="<port+>", help="read/write digital ports (e.g B13+,C1-,B2?)") | |
| parser.add_argument('-q', action="store", nargs=1, metavar="<jtagPorts>", help="query the JTAG chain") | |
| parser.add_argument('-p', action="store", nargs=1, metavar="<config>", help="program a device") | |
| parser.add_argument('-f', action="store", nargs=1, metavar="<dataFile>", help="binary data to write to channel 0") | |
| argList = parser.parse_args() | |
| handle = FLHandle() | |
| try: | |
| vp = argList.v[0] | |
| print "Attempting to open connection to FPGALink device %s..." % vp | |
| try: | |
| handle = flOpen(vp) | |
| except FLException, ex: | |
| if ( argList.i ): | |
| ivp = argList.i[0] | |
| print "Loading firmware into %s..." % ivp | |
| flLoadStandardFirmware(ivp, vp); | |
| print "Awaiting renumeration..." | |
| if ( not flAwaitDevice(vp, 600) ): | |
| raise FLException("FPGALink device did not renumerate properly as %s" % vp) | |
| print "Attempting to open connection to FPGALink device %s again..." % vp | |
| handle = flOpen(vp) | |
| else: | |
| raise FLException("Could not open FPGALink device at %s and no initial VID:PID was supplied" % vp) | |
| if ( argList.d ): | |
| print "Configuring ports..." | |
| rb = "{:0{}b}".format(flMultiBitPortAccess(handle, argList.d[0]), 32) | |
| print "Readback: 28 24 20 16 12 8 4 0\n %s %s %s %s %s %s %s %s" % (rb[0:4], rb[4:8], rb[8:12], rb[12:16], rb[16:20], rb[20:24], rb[24:28], rb[28:32]) | |
| fpgalink.flSleep(100) | |
| isNeroCapable = flIsNeroCapable(handle) | |
| isCommCapable = flIsCommCapable(handle, 1) | |
| if ( argList.q ): | |
| if ( isNeroCapable ): | |
| chain = jtagScanChain(handle, argList.q[0]) | |
| if ( len(chain) > 0 ): | |
| print "The FPGALink device at %s scanned its JTAG chain, yielding:" % vp | |
| for i in chain: | |
| print " 0x%08X" % i | |
| else: | |
| print "The FPGALink device at %s scanned its JTAG chain but did not find any attached devices" % vp | |
| else: | |
| raise FLException("JTAG chain scan requested but FPGALink device at %s does not support NeroJTAG" % vp) | |
| if ( argList.p ): | |
| progConfig = argList.p[0] | |
| print "Programming device with config %s..." % progConfig | |
| if ( isNeroCapable ): | |
| flProgram(handle, progConfig) | |
| else: | |
| raise FLException("Device program requested but device at %s does not support NeroProg" % vp) | |
| if ( argList.f and not(isCommCapable) ): | |
| raise FLException("Data file load requested but device at %s does not support CommFPGA" % vp) | |
| if ( isCommCapable ): | |
| print "Zeroing R1 & R2..." | |
| flSelectConduit(handle, 1) | |
| flWriteChannel(handle, 0x01, 0x00) | |
| flWriteChannel(handle, 0x02, 0x00) | |
| if ( argList.f ): | |
| dataFile = argList.f[0] | |
| print "Writing %s to FPGALink device %s..." % (dataFile, vp) | |
| flWriteChannel(handle, 0x00, dataFile) | |
| print "Reading channel 0..." | |
| print "Got 0x%02X" % flReadChannel(handle, 0x00) | |
| print "Reading channel 1..." | |
| print "Got 0x%02X" % flReadChannel(handle, 0x01) | |
| print "Reading channel 2..." | |
| print "Got 0x%02X" % flReadChannel(handle, 0x02) | |
| except FLException, ex: | |
| print ex | |
| finally: | |
| flClose(handle) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment