diff --git a/alchitry-loader/LICENSE.txt b/alchitry-loader/LICENSE.txt new file mode 100644 index 0000000..1903fc5 --- /dev/null +++ b/alchitry-loader/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 alchitry + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/alchitry-loader/au_loader.bin b/alchitry-loader/au_loader.bin new file mode 100644 index 0000000..2689979 Binary files /dev/null and b/alchitry-loader/au_loader.bin differ diff --git a/alchitry-loader/lib/linux/libftd2xx.a b/alchitry-loader/lib/linux/libftd2xx.a new file mode 100644 index 0000000..2de7c50 Binary files /dev/null and b/alchitry-loader/lib/linux/libftd2xx.a differ diff --git a/alchitry-loader/lib/macos/libftd2xx.a b/alchitry-loader/lib/macos/libftd2xx.a new file mode 100644 index 0000000..56faf81 Binary files /dev/null and b/alchitry-loader/lib/macos/libftd2xx.a differ diff --git a/alchitry-loader/lib/windows/ftbusui.dll b/alchitry-loader/lib/windows/ftbusui.dll new file mode 100644 index 0000000..c55695a Binary files /dev/null and b/alchitry-loader/lib/windows/ftbusui.dll differ diff --git a/alchitry-loader/lib/windows/ftcserco.dll b/alchitry-loader/lib/windows/ftcserco.dll new file mode 100644 index 0000000..ca6d397 Binary files /dev/null and b/alchitry-loader/lib/windows/ftcserco.dll differ diff --git a/alchitry-loader/lib/windows/ftd2xx.dll b/alchitry-loader/lib/windows/ftd2xx.dll new file mode 100644 index 0000000..ecafeb7 Binary files /dev/null and b/alchitry-loader/lib/windows/ftd2xx.dll differ diff --git a/alchitry-loader/lib/windows/ftd2xx.lib b/alchitry-loader/lib/windows/ftd2xx.lib new file mode 100644 index 0000000..b2e0a53 Binary files /dev/null and b/alchitry-loader/lib/windows/ftd2xx.lib differ diff --git a/alchitry-loader/lib/windows/ftdibus.sys b/alchitry-loader/lib/windows/ftdibus.sys new file mode 100644 index 0000000..e779f07 Binary files /dev/null and b/alchitry-loader/lib/windows/ftdibus.sys differ diff --git a/alchitry-loader/lib/windows/ftlang.dll b/alchitry-loader/lib/windows/ftlang.dll new file mode 100644 index 0000000..b57a0bb Binary files /dev/null and b/alchitry-loader/lib/windows/ftlang.dll differ diff --git a/alchitry-loader/lib/windows/ftser2k.sys b/alchitry-loader/lib/windows/ftser2k.sys new file mode 100644 index 0000000..12795e8 Binary files /dev/null and b/alchitry-loader/lib/windows/ftser2k.sys differ diff --git a/alchitry-loader/lib/windows/ftserui2.dll b/alchitry-loader/lib/windows/ftserui2.dll new file mode 100644 index 0000000..471234c Binary files /dev/null and b/alchitry-loader/lib/windows/ftserui2.dll differ diff --git a/alchitry-loader/makefile b/alchitry-loader/makefile new file mode 100644 index 0000000..0cbea0b --- /dev/null +++ b/alchitry-loader/makefile @@ -0,0 +1,24 @@ +sources = $(wildcard src/*.cpp) +objects = $(sources:.cpp=.o) +static_libs = lib/macos/libftd2xx.a +libs = -lpthread + +CXXFLAGS = -std=c++11 + +UNAME := $(shell uname) +# Assume target is Mac OS if build host is Mac OS; any other host targets Linux +ifeq ($(UNAME), Darwin) + libs += -lobjc -framework IOKit -framework CoreFoundation +else + libs += -lrt +endif + +all: loader + +loader: $(objects) + $(CXX) $(LDFLAGS) -o $@ $^ $(static_libs) $(libs) + +.PHONY: clean + +clean: + rm -rf loader $(objects) diff --git a/alchitry-loader/src/Alchitry_Loader.cpp b/alchitry-loader/src/Alchitry_Loader.cpp new file mode 100644 index 0000000..1eeeedb --- /dev/null +++ b/alchitry-loader/src/Alchitry_Loader.cpp @@ -0,0 +1,611 @@ +#include +#include +#include "ftd2xx.h" +#include "jtag.h" +#include "jtag_fsm.h" +#include "loader.h" +#include "spi.h" +#include +#include +#include +#include +#include +#include +#include +#include "loader.h" +#include +#ifdef _WIN32 +#include "mingw.thread.h" +#else +#include +#endif +#include +#include "config_type.h" + +#define BOARD_ERROR -2 +#define BOARD_UNKNOWN -1 +#define BOARD_AU 0 +#define BOARD_CU 1 + +using namespace std; +using get_time = chrono::steady_clock; + +char ManufacturerBuf[32]; +char ManufacturerIdBuf[16]; +char DescriptionBuf[64]; +char SerialNumberBuf[16]; + +string getErrorName(int error) { + switch (error) { + case FT_OK: + return "FT_OK"; + case FT_INVALID_HANDLE: + return "FT_INVALID_HANDLE"; + case FT_DEVICE_NOT_FOUND: + return "FT_DEVICE_NOT_FOUND"; + case FT_DEVICE_NOT_OPENED: + return "FT_DEVICE_NOT_OPENED"; + case FT_IO_ERROR: + return "FT_IO_ERROR"; + case FT_INSUFFICIENT_RESOURCES: + return "FT_INSUFFICIENT_RESOURCES"; + case FT_INVALID_PARAMETER: + return "FT_INVALID_PARAMETER"; + case FT_INVALID_BAUD_RATE: + return "FT_INVALID_BAUD_RATE"; + + case FT_DEVICE_NOT_OPENED_FOR_ERASE: + return "FT_DEVICE_NOT_OPENED_FOR_ERASE"; + case FT_DEVICE_NOT_OPENED_FOR_WRITE: + return "FT_DEVICE_NOT_OPENED_FOR_WRITE"; + case FT_FAILED_TO_WRITE_DEVICE: + return "FT_FAILED_TO_WRITE_DEVICE"; + case FT_EEPROM_READ_FAILED: + return "FT_EEPROM_READ_FAILED"; + case FT_EEPROM_WRITE_FAILED: + return "FT_EEPROM_WRITE_FAILED"; + case FT_EEPROM_ERASE_FAILED: + return "FT_EEPROM_ERASE_FAILED"; + case FT_EEPROM_NOT_PRESENT: + return "FT_EEPROM_NOT_PRESENT"; + case FT_EEPROM_NOT_PROGRAMMED: + return "FT_EEPROM_NOT_PROGRAMMED"; + case FT_INVALID_ARGS: + return "FT_INVALID_ARGS"; + case FT_NOT_SUPPORTED: + return "FT_NOT_SUPPORTED"; + case FT_OTHER_ERROR: + return "FT_OTHER_ERROR"; + case FT_DEVICE_LIST_NOT_READY: + return "FT_DEVICE_LIST_NOT_READY"; + } + return "Unknown"; +} + +void write_to_file(string file, PFT_PROGRAM_DATA ftData) { + ofstream output_file(file, ios::binary); + CONFIG_DATA config; + ft_to_config(&config, ftData); + output_file.write((char*) &config, sizeof(CONFIG_DATA)); + output_file.write(ManufacturerBuf, sizeof(ManufacturerBuf)); + output_file.write(ManufacturerIdBuf, sizeof(ManufacturerIdBuf)); + output_file.write(DescriptionBuf, sizeof(DescriptionBuf)); + output_file.write(SerialNumberBuf, sizeof(SerialNumberBuf)); + output_file.close(); +} + +bool read_from_file(string file, PFT_PROGRAM_DATA ftData) { + cout << "Reading " << file << endl; + try { + ifstream input_file(file, ios::in | ios::binary); + if (!input_file.is_open()) { + cerr << "Failed to open file " << file << endl; + return false; + } + CONFIG_DATA config; + + input_file.read((char*) &config, sizeof(CONFIG_DATA)); + config_to_ft(ftData, &config); + input_file.read(ManufacturerBuf, sizeof(ManufacturerBuf)); + input_file.read(ManufacturerIdBuf, sizeof(ManufacturerIdBuf)); + input_file.read(DescriptionBuf, sizeof(DescriptionBuf)); + input_file.read(SerialNumberBuf, sizeof(SerialNumberBuf)); + input_file.close(); + ftData->Manufacturer = ManufacturerBuf; + ftData->ManufacturerId = ManufacturerIdBuf; + ftData->Description = DescriptionBuf; + ftData->SerialNumber = SerialNumberBuf; + } catch (...) { + cerr << "Failed to read file " << file << endl; + return false; + } + return true; +} + +FT_STATUS read_from_device(FT_HANDLE ftHandle, PFT_PROGRAM_DATA ftData) { + ftData->Signature1 = 0x00000000; + ftData->Signature2 = 0xffffffff; + ftData->Version = 0x00000005; + ftData->Manufacturer = ManufacturerBuf; + ftData->ManufacturerId = ManufacturerIdBuf; + ftData->Description = DescriptionBuf; + ftData->SerialNumber = SerialNumberBuf; + + return FT_EE_Read(ftHandle, ftData); +} + +void print_info() { + cout << "Manufacture: " << ManufacturerBuf << endl; + cout << "ManufacturerId: " << ManufacturerIdBuf << endl; + cout << "Description: " << DescriptionBuf << endl; + cout << "SerialNumber: " << SerialNumberBuf << endl; +} + +void erase(FT_HANDLE ftHandle) { + cout << "Erasing... "; + FT_STATUS ftStatus = FT_EraseEE(ftHandle); + if (ftStatus != FT_OK) // Did the command execute OK? + { + cerr << "Error in erasing device!" << endl; + FT_Close(ftHandle); + return; + } + cout << "Done." << endl; +} + +bool programDevice(unsigned int devNumber, string file) { + FT_HANDLE ftHandle; + + cout << "Opening device... "; + FT_STATUS ftStatus = FT_Open(devNumber, &ftHandle); + if (ftStatus != FT_OK) // Did the command execute OK? + { + printf("Error in opening device!\n"); + return false; // Exit with error + } + cout << "Done." << endl; + FT_PROGRAM_DATA ftData; + + cout << "Checking EEPROM... "; + ftStatus = read_from_device(ftHandle, &ftData); + + if (ftStatus != FT_EEPROM_NOT_PROGRAMMED) { // device isn't blank + if (ftStatus == FT_OK) { + cout << "Not blank." << endl; + erase(ftHandle); + } else if (ftStatus == FT_EEPROM_NOT_PRESENT) { + cout << "Not present!" << endl; + FT_Close(ftHandle); + return false; + } else { + cout << getErrorName(ftStatus) << endl; + FT_Close(ftHandle); + return false; + } + } else { + cout << "Blank." << endl; + } + + if (!read_from_file(file, &ftData)) { + FT_Close(ftHandle); + return false; + } + + print_info(); + + cout << "Programming... "; + ftStatus = FT_EE_Program(ftHandle, &ftData); + if (ftStatus != FT_OK) // Did the command execute OK? + { + cout << "ERROR: " << getErrorName(ftStatus) << endl; + FT_Close(ftHandle); + return false; + } + cout << "Done." << endl; + + FT_Close(ftHandle); + return true; +} + +string descriptionToName(string des) { + if (des == "Alchitry Cu A") { + return "Alchitry Cu"; + } else if (des == "Alchitry Au A") { + return "Alchitry Au"; + } else { + return "Unknown"; + } +} + +int desciptionToType(string des) { + if (des == "Alchitry Cu A") { + return BOARD_CU; + } else if (des == "Alchitry Au A") { + return BOARD_AU; + } else { + return BOARD_UNKNOWN; + } +} + +void printDeviceList() { + FT_STATUS ftStatus; + FT_DEVICE_LIST_INFO_NODE *devInfo; + DWORD numDevs = 0; + // create the device information list + ftStatus = FT_CreateDeviceInfoList(&numDevs); + if (ftStatus != FT_OK) { + cerr << "Could not read device list!" << endl; + return; + } + + if (numDevs > 0) { + cout << "Devices: " << endl; + // allocate storage for list based on numDevs + devInfo = (FT_DEVICE_LIST_INFO_NODE*) malloc( + sizeof(FT_DEVICE_LIST_INFO_NODE) * numDevs); + // get the device information list + ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs); + if (ftStatus == FT_OK) { + for (unsigned int i = 0; i < numDevs; i++) { + cout << " " << i << ": " + << descriptionToName(devInfo[i].Description) << endl; + } + } else { + cerr << "Error getting device list!" << endl; + } + free(devInfo); + } else { + cout << "No devices found!" << endl; + } +} + +int getDeviceType(unsigned int devNumber) { + FT_STATUS ftStatus; + FT_DEVICE_LIST_INFO_NODE *devInfo; + DWORD numDevs = 0; + int board = BOARD_ERROR; + // create the device information list + ftStatus = FT_CreateDeviceInfoList(&numDevs); + if (ftStatus != FT_OK) { + cerr << "Could not read device list!" << endl; + return BOARD_ERROR; + } + + if (numDevs <= devNumber) { + cerr << "Invalid device number!" << endl; + return BOARD_ERROR; + } + + // allocate storage for list based on numDevs + devInfo = (FT_DEVICE_LIST_INFO_NODE*) malloc( + sizeof(FT_DEVICE_LIST_INFO_NODE) * numDevs); + // get the device information list + ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs); + if (ftStatus == FT_OK) { + string boardDescription = devInfo[devNumber].Description; + if (boardDescription == "Alchitry Cu A") { + board = BOARD_CU; + } else if (boardDescription == "Alchitry Au A") { + board = BOARD_AU; + } else { + board = BOARD_UNKNOWN; + } + } else { + cerr << "Error getting device list!" << endl; + } + free(devInfo); + + return board; +} + +int getFirstDeviceOfType(int board) { + FT_STATUS ftStatus; + FT_DEVICE_LIST_INFO_NODE *devInfo; + DWORD numDevs = 0; + + // create the device information list + ftStatus = FT_CreateDeviceInfoList(&numDevs); + if (ftStatus != FT_OK) { + cerr << "Could not read device list!" << endl; + return -1; + } + + if (numDevs < 1) { + cerr << "No devices found!" << endl; + return -1; + } + + // allocate storage for list based on numDevs + devInfo = (FT_DEVICE_LIST_INFO_NODE*) malloc( + sizeof(FT_DEVICE_LIST_INFO_NODE) * numDevs); + // get the device information list + ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs); + + if (ftStatus == FT_OK) { + for (int devNumber = 0; devNumber < numDevs; devNumber++) { + string boardDescription = devInfo[devNumber].Description; + int type = desciptionToType(boardDescription); + if (type == board) { + free(devInfo); + return devNumber; + } + } + } else { + cerr << "Error getting device list!" << endl; + } + free(devInfo); + return -1; +} + +bool readAndSaveFTDI(string file) { + FT_HANDLE ftHandle; + + cout << "Opening device... "; + FT_STATUS ftStatus = FT_Open(0, &ftHandle); + if (ftStatus != FT_OK) // Did the command execute OK? + { + printf("Error in opening device!\n"); + return false; // Exit with error + } + cout << "Done." << endl; + FT_PROGRAM_DATA ftData; + + cout << "Checking EEPROM... "; + ftStatus = read_from_device(ftHandle, &ftData); + + if (ftStatus != FT_OK) { + if (ftStatus == FT_EEPROM_NOT_PROGRAMMED) { + cout << "Blank." << endl; + return false; + } else if (ftStatus == FT_EEPROM_NOT_PRESENT) { + cout << "Not present!" << endl; + FT_Close(ftHandle); + return false; + } else { + cout << "Unknown error " << ftStatus << endl; + FT_Close(ftHandle); + return false; + } + } else { // eeprom not blank + cout << "Done." << endl; + } + + cout << "Writing to file... "; + + write_to_file(file, &ftData); + + cout << "Done." << endl; + + FT_Close(ftHandle); + return true; +} + +void printUsage() { + cout << "Usage: \"loader arguments\"" << endl; + cout << endl; + cout << "Arguments:" << endl; + cout << " -e : erase FPGA flash" << endl; + cout << " -l : list detected boards" << endl; + cout << " -h : print this help message" << endl; + cout << " -f config.bin : write FPGA flash" << endl; + cout << " -r config.bin : write FPGA RAM" << endl; + cout << " -u config.data : write FTDI eeprom" << endl; + cout << " -b n : select board \"n\" (defaults to 0)" << endl; + cout << " -p loader.bin : Au bridge bin" << endl; + cout << " -t TYPE : TYPE can be au or cu (defaults to au)" << endl; +} + +int main(int argc, char *argv[]) { + if (argc < 2) { + printUsage(); + return 1; + } + + bool fpgaFlash = false; + bool fpgaRam = false; + bool eeprom = false; + string eepromConfig; + string fpgaBinFlash; + string fpgaBinRam; + bool erase = false; + bool list = false; + bool print = false; + int deviceNumber = -1; + bool bridgeProvided = false; + string auBridgeBin; + bool isAu = true; + + for (int i = 1; i < argc;) { + string arg = argv[i]; + if (arg == "-e") { + i++; + erase = true; + } else if (arg == "-l") { + i++; + list = true; + } else if (arg == "-h") { + i++; + print = true; + } else if (arg == "-f") { + if (argc <= i + 1) { + cerr << "Missing bin file!" << endl; + printUsage(); + return 1; + } + fpgaFlash = true; + fpgaBinFlash = argv[i + 1]; + i += 2; + } else if (arg == "-r") { + if (argc <= i + 1) { + cerr << "Missing bin file!" << endl; + printUsage(); + return 1; + } + fpgaRam = true; + fpgaBinRam = argv[i + 1]; + i += 2; + } else if (arg == "-u") { + if (argc <= i + 1) { + cerr << "Missing data file!" << endl; + printUsage(); + return 1; + } + eeprom = true; + eepromConfig = argv[i + 1]; + i += 2; + } else if (arg == "-b") { + if (argc <= i + 1) { + cerr << "Missing board number!" << endl; + printUsage(); + return 1; + } + try { + deviceNumber = stoi(argv[i + 1]); + } catch (const std::invalid_argument& ia) { + cerr << argv[i + 1] << " is not a number!" << endl; + printUsage(); + return 1; + } + if (deviceNumber < 0) { + cerr << "Device numbers can't be negative!" << endl; + printUsage(); + return 1; + } + i += 2; + } else if (arg == "-p") { + if (argc <= i + 1) { + cerr << "Missing bin file!" << endl; + printUsage(); + return 1; + } + bridgeProvided = true; + auBridgeBin = argv[i + 1]; + i += 2; + } else if (arg == "-t") { + if (argc <= i + 1) { + cerr << "Missing board type!" << endl; + printUsage(); + return 1; + } + if (strcmp(argv[i + 1], "au") == 0) { + isAu = true; + } else if (strcmp(argv[i + 1], "cu") == 0) { + isAu = false; + } else { + cerr << "Invalid board type: " << argv[i + 1] << endl; + printUsage(); + return 1; + } + i += 2; + + } else { + cerr << "Unknown argument " << arg << endl; + printUsage(); + return 1; + } + } + + if (print) + printUsage(); + + if (list) + printDeviceList(); + + if (deviceNumber < 0) + deviceNumber = getFirstDeviceOfType(isAu ? BOARD_AU : BOARD_CU); + + if (deviceNumber < 0) { + cerr << "Couldn't find device!" << endl; + return 2; + } + + cout << "Found " << (isAu ? "Au" : "Cu") << " as device " << deviceNumber + << "." << endl; + + if (eeprom) + programDevice(deviceNumber, eepromConfig); + + if (erase || fpgaFlash || fpgaRam) { + int boardType = getDeviceType(deviceNumber); + if ((isAu && boardType != BOARD_AU) + || (!isAu && boardType != BOARD_CU)) { + cerr << "Invalid board type detected!" << endl; + return 2; + } + + if (boardType == BOARD_AU) { + if (bridgeProvided == false && (erase || fpgaFlash)) { + cerr << "No Au bridge bin provided!" << endl; + return 2; + } + Jtag jtag; + if (jtag.connect(deviceNumber) != FT_OK) { + cerr << "Failed to connect to JTAG!" << endl; + return 2; + } + if (jtag.initialize() == false) { + cerr << "Failed to initialize JTAG!" << endl; + return 2; + } + Loader loader(&jtag); + + if (erase) { + if (!loader.eraseFlash(auBridgeBin)) { + cerr << "Failed to erase flash!" << endl; + } else { + cout << "Done." << endl; + } + } + + if (fpgaFlash) { + if (!loader.writeBin(fpgaBinFlash, true, auBridgeBin)) { + cerr << "Failed to write FPGA flash!" << endl; + } + } + + if (fpgaRam) { + if (!loader.writeBin(fpgaBinRam, false, "")) { + cerr << "Failed to write FPGA RAM!" << endl; + } + } + + jtag.disconnect(); + } else if (boardType == BOARD_CU) { + Spi spi; + if (spi.connect(deviceNumber) != FT_OK) { + cerr << "Failed to connect to SPI!" << endl; + return 2; + } + if (spi.initialize() == false) { + cerr << "Failed to initialize SPI!" << endl; + return 2; + } + + if (erase) { + if (!spi.eraseFlash()) { + cerr << "Failed to erase flash!" << endl; + } else { + cout << "Done." << endl; + } + } + + if (fpgaFlash) { + if (!spi.writeBin(fpgaBinFlash)) { + cerr << "Failed to write FPGA flash!" << endl; + } + } + + if (fpgaRam) { + cerr << "Alchitry Cu doesn't support RAM only programming!" + << endl; + return 1; + } + } else { + cerr << "Unknown board type!" << endl; + return 2; + } + } + + return 0; +} + diff --git a/alchitry-loader/src/WinTypes.h b/alchitry-loader/src/WinTypes.h new file mode 100644 index 0000000..88e500e --- /dev/null +++ b/alchitry-loader/src/WinTypes.h @@ -0,0 +1,154 @@ +#ifndef __WINDOWS_TYPES__ +#define __WINDOWS_TYPES__ + +#define WINAPI + +typedef unsigned int DWORD; +typedef unsigned int ULONG; +typedef unsigned short USHORT; +typedef unsigned short SHORT; +typedef unsigned char UCHAR; +typedef unsigned short WORD; +typedef unsigned short WCHAR; +typedef unsigned char BYTE; +typedef BYTE *LPBYTE; +typedef unsigned int BOOL; +typedef unsigned char BOOLEAN; +typedef unsigned char CHAR; +typedef BOOL *LPBOOL; +typedef UCHAR *PUCHAR; +typedef const char *LPCSTR; +typedef char *PCHAR; +typedef void *PVOID; +typedef void *HANDLE; +typedef unsigned int LONG; +typedef int INT; +typedef unsigned int UINT; +typedef char *LPSTR; +typedef char *LPTSTR; +typedef const char *LPCTSTR; +typedef DWORD *LPDWORD; +typedef WORD *LPWORD; +typedef ULONG *PULONG; +typedef LONG *LPLONG; +typedef PVOID LPVOID; +typedef void VOID; +typedef USHORT *PUSHORT; +typedef unsigned long long int ULONGLONG; + +typedef struct _OVERLAPPED { + DWORD Internal; + DWORD InternalHigh; + union { + struct{ + DWORD Offset; + DWORD OffsetHigh; + }; + PVOID Pointer; + }; + HANDLE hEvent; +} OVERLAPPED, *LPOVERLAPPED; + +typedef struct _SECURITY_ATTRIBUTES { + DWORD nLength; + LPVOID lpSecurityDescriptor; + BOOL bInheritHandle; +} SECURITY_ATTRIBUTES , *LPSECURITY_ATTRIBUTES; + +#include +// Substitute for HANDLE returned by Windows CreateEvent API. +// FT_SetEventNotification expects parameter 3 to be the address +// of one of these structures. +typedef struct _EVENT_HANDLE +{ + pthread_cond_t eCondVar; + pthread_mutex_t eMutex; + int iVar; +} EVENT_HANDLE; + +typedef struct timeval SYSTEMTIME; +typedef struct timeval FILETIME; + +// WaitForSingleObject return values. +#define WAIT_ABANDONED 0x00000080L +#define WAIT_OBJECT_0 0x00000000L +#define WAIT_TIMEOUT 0x00000102L +#define WAIT_FAILED 0xFFFFFFFF +// Special value for WaitForSingleObject dwMilliseconds parameter +#define INFINITE 0xFFFFFFFF // Infinite timeout + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef CONST +#define CONST const +#endif +// +// Modem Status Flags +// +#define MS_CTS_ON ((DWORD)0x0010) +#define MS_DSR_ON ((DWORD)0x0020) +#define MS_RING_ON ((DWORD)0x0040) +#define MS_RLSD_ON ((DWORD)0x0080) + +// +// Error Flags +// +#define CE_RXOVER 0x0001 // Receive Queue overflow +#define CE_OVERRUN 0x0002 // Receive Overrun Error +#define CE_RXPARITY 0x0004 // Receive Parity Error +#define CE_FRAME 0x0008 // Receive Framing error +#define CE_BREAK 0x0010 // Break Detected +#define CE_TXFULL 0x0100 // TX Queue is full +#define CE_PTO 0x0200 // LPTx Timeout +#define CE_IOE 0x0400 // LPTx I/O Error +#define CE_DNS 0x0800 // LPTx Device not selected +#define CE_OOP 0x1000 // LPTx Out-Of-Paper +#define CE_MODE 0x8000 // Requested mode unsupported + +// +// Events +// +#define EV_RXCHAR 0x0001 // Any Character received +#define EV_RXFLAG 0x0002 // Received certain character +#define EV_TXEMPTY 0x0004 // Transmit Queue Empty +#define EV_CTS 0x0008 // CTS changed state +#define EV_DSR 0x0010 // DSR changed state +#define EV_RLSD 0x0020 // RLSD changed state +#define EV_BREAK 0x0040 // BREAK received +#define EV_ERR 0x0080 // Line status error occurred +#define EV_RING 0x0100 // Ring signal detected +#define EV_PERR 0x0200 // Printer error occured +#define EV_RX80FULL 0x0400 // Receive buffer is 80 percent full +#define EV_EVENT1 0x0800 // Provider specific event 1 +#define EV_EVENT2 0x1000 // Provider specific event 2 + +// +// Escape Functions +// +#define SETXOFF 1 // Simulate XOFF received +#define SETXON 2 // Simulate XON received +#define SETRTS 3 // Set RTS high +#define CLRRTS 4 // Set RTS low +#define SETDTR 5 // Set DTR high +#define CLRDTR 6 // Set DTR low +#define RESETDEV 7 // Reset device if possible +#define SETBREAK 8 // Set the device break line. +#define CLRBREAK 9 // Clear the device break line. + +// +// PURGE function flags. +// +#define PURGE_TXABORT 0x0001 // Kill the pending/current writes to the comm port. +#define PURGE_RXABORT 0x0002 // Kill the pending/current reads to the comm port. +#define PURGE_TXCLEAR 0x0004 // Kill the transmit queue if there. +#define PURGE_RXCLEAR 0x0008 // Kill the typeahead buffer if there. + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE 0xFFFFFFFF +#endif + +#endif /* __WINDOWS_TYPES__ */ diff --git a/alchitry-loader/src/config_type.cpp b/alchitry-loader/src/config_type.cpp new file mode 100644 index 0000000..331f98a --- /dev/null +++ b/alchitry-loader/src/config_type.cpp @@ -0,0 +1,272 @@ +/* + * config_type.cpp + * + * Created on: Feb 11, 2019 + * Author: justin + */ + +#include "config_type.h" +#ifdef _WIN32 +#include +#else +#include "WinTypes.h" +#endif +#include "ftd2xx.h" + +void ft_to_config(CONFIG_DATA* dest, PFT_PROGRAM_DATA src) { + dest->Signature1 = src->Signature1; + dest->Signature2 = src->Signature2; + dest->Version = src->Version; + dest->VendorId = src->VendorId; + dest->ProductId = src->ProductId; + dest->MaxPower = src->MaxPower; + dest->PnP = src->PnP; + dest->SelfPowered = src->SelfPowered; + dest->RemoteWakeup = src->RemoteWakeup; + dest->Rev4 = src->Rev4; + dest->IsoIn = src->IsoIn; + dest->IsoOut = src->IsoOut; + dest->PullDownEnable = src->PullDownEnable; + dest->SerNumEnable = src->SerNumEnable; + dest->USBVersionEnable = src->USBVersionEnable; + dest->USBVersion = src->USBVersion; + dest->Rev5 = src->Rev5; + dest->IsoInA = src->IsoInA; + dest->IsoInB = src->IsoInB; + dest->IsoOutA = src->IsoOutA; + dest->IsoOutB = src->IsoOutB; + dest->PullDownEnable5 = src->PullDownEnable5; + dest->SerNumEnable5 = src->SerNumEnable5; + dest->USBVersionEnable5 = src->USBVersionEnable5; + dest->USBVersion5 = src->USBVersion5; + dest->AIsHighCurrent = src->AIsHighCurrent; + dest->BIsHighCurrent = src->BIsHighCurrent; + dest->IFAIsFifo = src->IFAIsFifo; + dest->IFAIsFifoTar = src->IFAIsFifoTar; + dest->IFAIsFastSer = src->IFAIsFastSer; + dest->AIsVCP = src->AIsVCP; + dest->IFBIsFifo = src->IFBIsFifo; + dest->IFBIsFifoTar = src->IFBIsFifoTar; + dest->IFBIsFastSer = src->IFBIsFastSer; + dest->BIsVCP = src->BIsVCP; + dest->UseExtOsc = src->UseExtOsc; + dest->HighDriveIOs = src->HighDriveIOs; + dest->EndpointSize = src->EndpointSize; + dest->PullDownEnableR = src->PullDownEnableR; + dest->SerNumEnableR = src->SerNumEnableR; + dest->InvertTXD = src->InvertTXD; + dest->InvertRXD = src->InvertRXD; + dest->InvertRTS = src->InvertRTS; + dest->InvertCTS = src->InvertCTS; + dest->InvertDTR = src->InvertDTR; + dest->InvertDSR = src->InvertDSR; + dest->InvertDCD = src->InvertDCD; + dest->InvertRI = src->InvertRI; + dest->Cbus0 = src->Cbus0; + dest->Cbus1 = src->Cbus1; + dest->Cbus2 = src->Cbus2; + dest->Cbus3 = src->Cbus3; + dest->Cbus4 = src->Cbus4; + dest->RIsD2XX = src->RIsD2XX; + dest->PullDownEnable7 = src->PullDownEnable7; + dest->SerNumEnable7 = src->SerNumEnable7; + dest->ALSlowSlew = src->ALSlowSlew; + dest->ALSchmittInput = src->ALSchmittInput; + dest->ALDriveCurrent = src->ALDriveCurrent; + dest->AHSlowSlew = src->AHSlowSlew; + dest->AHSchmittInput = src->AHSchmittInput; + dest->AHDriveCurrent = src->AHDriveCurrent; + dest->BLSlowSlew = src->BLSlowSlew; + dest->BLSchmittInput = src->BLSchmittInput; + dest->BLDriveCurrent = src->BLDriveCurrent; + dest->BHSlowSlew = src->BHSlowSlew; + dest->BHSchmittInput = src->BHSchmittInput; + dest->BHDriveCurrent = src->BHDriveCurrent; + dest->IFAIsFifo7 = src->IFAIsFifo7; + dest->IFAIsFifoTar7 = src->IFAIsFifoTar7; + dest->IFAIsFastSer7 = src->IFAIsFastSer7; + dest->AIsVCP7 = src->AIsVCP7; + dest->IFBIsFifo7 = src->IFBIsFifo7; + dest->IFBIsFifoTar7 = src->IFBIsFifoTar7; + dest->IFBIsFastSer7 = src->IFBIsFastSer7; + dest->BIsVCP7 = src->BIsVCP7; + dest->PowerSaveEnable = src->PowerSaveEnable; + dest->PullDownEnable8 = src->PullDownEnable8; + dest->SerNumEnable8 = src->SerNumEnable8; + dest->ASlowSlew = src->ASlowSlew; + dest->ASchmittInput = src->ASchmittInput; + dest->ADriveCurrent = src->ADriveCurrent; + dest->BSlowSlew = src->BSlowSlew; + dest->BSchmittInput = src->BSchmittInput; + dest->BDriveCurrent = src->BDriveCurrent; + dest->CSlowSlew = src->CSlowSlew; + dest->CSchmittInput = src->CSchmittInput; + dest->CDriveCurrent = src->CDriveCurrent; + dest->DSlowSlew = src->DSlowSlew; + dest->DSchmittInput = src->DSchmittInput; + dest->DDriveCurrent = src->DDriveCurrent; + dest->ARIIsTXDEN = src->ARIIsTXDEN; + dest->BRIIsTXDEN = src->BRIIsTXDEN; + dest->CRIIsTXDEN = src->CRIIsTXDEN; + dest->DRIIsTXDEN = src->DRIIsTXDEN; + dest->AIsVCP8 = src->AIsVCP8; + dest->BIsVCP8 = src->BIsVCP8; + dest->CIsVCP8 = src->CIsVCP8; + dest->DIsVCP8 = src->DIsVCP8; + dest->PullDownEnableH = src->PullDownEnableH; + dest->SerNumEnableH = src->SerNumEnableH; + dest->ACSlowSlewH = src->ACSlowSlewH; + dest->ACSchmittInputH = src->ACSchmittInputH; + dest->ACDriveCurrentH = src->ACDriveCurrentH; + dest->ADSlowSlewH = src->ADSlowSlewH; + dest->ADSchmittInputH = src->ADSchmittInputH; + dest->ADDriveCurrentH = src->ADDriveCurrentH; + dest->Cbus0H = src->Cbus0H; + dest->Cbus1H = src->Cbus1H; + dest->Cbus2H = src->Cbus2H; + dest->Cbus3H = src->Cbus3H; + dest->Cbus4H = src->Cbus4H; + dest->Cbus5H = src->Cbus5H; + dest->Cbus6H = src->Cbus6H; + dest->Cbus7H = src->Cbus7H; + dest->Cbus8H = src->Cbus8H; + dest->Cbus9H = src->Cbus9H; + dest->IsFifoH = src->IsFifoH; + dest->IsFifoTarH = src->IsFifoTarH; + dest->IsFastSerH = src->IsFastSerH; + dest->IsFT1248H = src->IsFT1248H; + dest->FT1248CpolH = src->FT1248CpolH; + dest->FT1248LsbH = src->FT1248LsbH; + dest->FT1248FlowControlH = src->FT1248FlowControlH; + dest->IsVCPH = src->IsVCPH; + dest->PowerSaveEnableH = src->PowerSaveEnableH; +} + +void config_to_ft(PFT_PROGRAM_DATA dest, CONFIG_DATA* src) { + dest->Signature1 = src->Signature1; + dest->Signature2 = src->Signature2; + dest->Version = src->Version; + dest->VendorId = src->VendorId; + dest->ProductId = src->ProductId; + dest->MaxPower = src->MaxPower; + dest->PnP = src->PnP; + dest->SelfPowered = src->SelfPowered; + dest->RemoteWakeup = src->RemoteWakeup; + dest->Rev4 = src->Rev4; + dest->IsoIn = src->IsoIn; + dest->IsoOut = src->IsoOut; + dest->PullDownEnable = src->PullDownEnable; + dest->SerNumEnable = src->SerNumEnable; + dest->USBVersionEnable = src->USBVersionEnable; + dest->USBVersion = src->USBVersion; + dest->Rev5 = src->Rev5; + dest->IsoInA = src->IsoInA; + dest->IsoInB = src->IsoInB; + dest->IsoOutA = src->IsoOutA; + dest->IsoOutB = src->IsoOutB; + dest->PullDownEnable5 = src->PullDownEnable5; + dest->SerNumEnable5 = src->SerNumEnable5; + dest->USBVersionEnable5 = src->USBVersionEnable5; + dest->USBVersion5 = src->USBVersion5; + dest->AIsHighCurrent = src->AIsHighCurrent; + dest->BIsHighCurrent = src->BIsHighCurrent; + dest->IFAIsFifo = src->IFAIsFifo; + dest->IFAIsFifoTar = src->IFAIsFifoTar; + dest->IFAIsFastSer = src->IFAIsFastSer; + dest->AIsVCP = src->AIsVCP; + dest->IFBIsFifo = src->IFBIsFifo; + dest->IFBIsFifoTar = src->IFBIsFifoTar; + dest->IFBIsFastSer = src->IFBIsFastSer; + dest->BIsVCP = src->BIsVCP; + dest->UseExtOsc = src->UseExtOsc; + dest->HighDriveIOs = src->HighDriveIOs; + dest->EndpointSize = src->EndpointSize; + dest->PullDownEnableR = src->PullDownEnableR; + dest->SerNumEnableR = src->SerNumEnableR; + dest->InvertTXD = src->InvertTXD; + dest->InvertRXD = src->InvertRXD; + dest->InvertRTS = src->InvertRTS; + dest->InvertCTS = src->InvertCTS; + dest->InvertDTR = src->InvertDTR; + dest->InvertDSR = src->InvertDSR; + dest->InvertDCD = src->InvertDCD; + dest->InvertRI = src->InvertRI; + dest->Cbus0 = src->Cbus0; + dest->Cbus1 = src->Cbus1; + dest->Cbus2 = src->Cbus2; + dest->Cbus3 = src->Cbus3; + dest->Cbus4 = src->Cbus4; + dest->RIsD2XX = src->RIsD2XX; + dest->PullDownEnable7 = src->PullDownEnable7; + dest->SerNumEnable7 = src->SerNumEnable7; + dest->ALSlowSlew = src->ALSlowSlew; + dest->ALSchmittInput = src->ALSchmittInput; + dest->ALDriveCurrent = src->ALDriveCurrent; + dest->AHSlowSlew = src->AHSlowSlew; + dest->AHSchmittInput = src->AHSchmittInput; + dest->AHDriveCurrent = src->AHDriveCurrent; + dest->BLSlowSlew = src->BLSlowSlew; + dest->BLSchmittInput = src->BLSchmittInput; + dest->BLDriveCurrent = src->BLDriveCurrent; + dest->BHSlowSlew = src->BHSlowSlew; + dest->BHSchmittInput = src->BHSchmittInput; + dest->BHDriveCurrent = src->BHDriveCurrent; + dest->IFAIsFifo7 = src->IFAIsFifo7; + dest->IFAIsFifoTar7 = src->IFAIsFifoTar7; + dest->IFAIsFastSer7 = src->IFAIsFastSer7; + dest->AIsVCP7 = src->AIsVCP7; + dest->IFBIsFifo7 = src->IFBIsFifo7; + dest->IFBIsFifoTar7 = src->IFBIsFifoTar7; + dest->IFBIsFastSer7 = src->IFBIsFastSer7; + dest->BIsVCP7 = src->BIsVCP7; + dest->PowerSaveEnable = src->PowerSaveEnable; + dest->PullDownEnable8 = src->PullDownEnable8; + dest->SerNumEnable8 = src->SerNumEnable8; + dest->ASlowSlew = src->ASlowSlew; + dest->ASchmittInput = src->ASchmittInput; + dest->ADriveCurrent = src->ADriveCurrent; + dest->BSlowSlew = src->BSlowSlew; + dest->BSchmittInput = src->BSchmittInput; + dest->BDriveCurrent = src->BDriveCurrent; + dest->CSlowSlew = src->CSlowSlew; + dest->CSchmittInput = src->CSchmittInput; + dest->CDriveCurrent = src->CDriveCurrent; + dest->DSlowSlew = src->DSlowSlew; + dest->DSchmittInput = src->DSchmittInput; + dest->DDriveCurrent = src->DDriveCurrent; + dest->ARIIsTXDEN = src->ARIIsTXDEN; + dest->BRIIsTXDEN = src->BRIIsTXDEN; + dest->CRIIsTXDEN = src->CRIIsTXDEN; + dest->DRIIsTXDEN = src->DRIIsTXDEN; + dest->AIsVCP8 = src->AIsVCP8; + dest->BIsVCP8 = src->BIsVCP8; + dest->CIsVCP8 = src->CIsVCP8; + dest->DIsVCP8 = src->DIsVCP8; + dest->PullDownEnableH = src->PullDownEnableH; + dest->SerNumEnableH = src->SerNumEnableH; + dest->ACSlowSlewH = src->ACSlowSlewH; + dest->ACSchmittInputH = src->ACSchmittInputH; + dest->ACDriveCurrentH = src->ACDriveCurrentH; + dest->ADSlowSlewH = src->ADSlowSlewH; + dest->ADSchmittInputH = src->ADSchmittInputH; + dest->ADDriveCurrentH = src->ADDriveCurrentH; + dest->Cbus0H = src->Cbus0H; + dest->Cbus1H = src->Cbus1H; + dest->Cbus2H = src->Cbus2H; + dest->Cbus3H = src->Cbus3H; + dest->Cbus4H = src->Cbus4H; + dest->Cbus5H = src->Cbus5H; + dest->Cbus6H = src->Cbus6H; + dest->Cbus7H = src->Cbus7H; + dest->Cbus8H = src->Cbus8H; + dest->Cbus9H = src->Cbus9H; + dest->IsFifoH = src->IsFifoH; + dest->IsFifoTarH = src->IsFifoTarH; + dest->IsFastSerH = src->IsFastSerH; + dest->IsFT1248H = src->IsFT1248H; + dest->FT1248CpolH = src->FT1248CpolH; + dest->FT1248LsbH = src->FT1248LsbH; + dest->FT1248FlowControlH = src->FT1248FlowControlH; + dest->IsVCPH = src->IsVCPH; + dest->PowerSaveEnableH = src->PowerSaveEnableH; +} diff --git a/alchitry-loader/src/config_type.h b/alchitry-loader/src/config_type.h new file mode 100644 index 0000000..5ca4673 --- /dev/null +++ b/alchitry-loader/src/config_type.h @@ -0,0 +1,177 @@ +/* + * config_def.h + * + * Created on: Feb 11, 2019 + * Author: justin + */ + +#ifndef CONFIG_TYPE_H_ +#define CONFIG_TYPE_H_ + +#ifdef _WIN32 +#include +#else +#include "WinTypes.h" +#endif +#include "ftd2xx.h" + +typedef struct config_data { + + DWORD Signature1; // Header - must be 0x00000000 + DWORD Signature2; // Header - must be 0xffffffff + DWORD Version; // Header - FT_PROGRAM_DATA version + // 0 = original + // 1 = FT2232 extensions + // 2 = FT232R extensions + // 3 = FT2232H extensions + // 4 = FT4232H extensions + // 5 = FT232H extensions + + WORD VendorId; // 0x0403 + WORD ProductId; // 0x6001 + WORD MaxPower; // 0 < MaxPower <= 500 + WORD PnP; // 0 = disabled, 1 = enabled + WORD SelfPowered; // 0 = bus powered, 1 = self powered + WORD RemoteWakeup; // 0 = not capable, 1 = capable + // + // Rev4 (FT232B) extensions + // + UCHAR Rev4; // non-zero if Rev4 chip, zero otherwise + UCHAR IsoIn; // non-zero if in endpoint is isochronous + UCHAR IsoOut; // non-zero if out endpoint is isochronous + UCHAR PullDownEnable; // non-zero if pull down enabled + UCHAR SerNumEnable; // non-zero if serial number to be used + UCHAR USBVersionEnable; // non-zero if chip uses USBVersion + WORD USBVersion; // BCD (0x0200 => USB2) + // + // Rev 5 (FT2232) extensions + // + UCHAR Rev5; // non-zero if Rev5 chip, zero otherwise + UCHAR IsoInA; // non-zero if in endpoint is isochronous + UCHAR IsoInB; // non-zero if in endpoint is isochronous + UCHAR IsoOutA; // non-zero if out endpoint is isochronous + UCHAR IsoOutB; // non-zero if out endpoint is isochronous + UCHAR PullDownEnable5; // non-zero if pull down enabled + UCHAR SerNumEnable5; // non-zero if serial number to be used + UCHAR USBVersionEnable5; // non-zero if chip uses USBVersion + WORD USBVersion5; // BCD (0x0200 => USB2) + UCHAR AIsHighCurrent; // non-zero if interface is high current + UCHAR BIsHighCurrent; // non-zero if interface is high current + UCHAR IFAIsFifo; // non-zero if interface is 245 FIFO + UCHAR IFAIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR IFAIsFastSer; // non-zero if interface is Fast serial + UCHAR AIsVCP; // non-zero if interface is to use VCP drivers + UCHAR IFBIsFifo; // non-zero if interface is 245 FIFO + UCHAR IFBIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR IFBIsFastSer; // non-zero if interface is Fast serial + UCHAR BIsVCP; // non-zero if interface is to use VCP drivers + // + // Rev 6 (FT232R) extensions + // + UCHAR UseExtOsc; // Use External Oscillator + UCHAR HighDriveIOs; // High Drive I/Os + UCHAR EndpointSize; // Endpoint size + UCHAR PullDownEnableR; // non-zero if pull down enabled + UCHAR SerNumEnableR; // non-zero if serial number to be used + UCHAR InvertTXD; // non-zero if invert TXD + UCHAR InvertRXD; // non-zero if invert RXD + UCHAR InvertRTS; // non-zero if invert RTS + UCHAR InvertCTS; // non-zero if invert CTS + UCHAR InvertDTR; // non-zero if invert DTR + UCHAR InvertDSR; // non-zero if invert DSR + UCHAR InvertDCD; // non-zero if invert DCD + UCHAR InvertRI; // non-zero if invert RI + UCHAR Cbus0; // Cbus Mux control + UCHAR Cbus1; // Cbus Mux control + UCHAR Cbus2; // Cbus Mux control + UCHAR Cbus3; // Cbus Mux control + UCHAR Cbus4; // Cbus Mux control + UCHAR RIsD2XX; // non-zero if using D2XX driver + // + // Rev 7 (FT2232H) Extensions + // + UCHAR PullDownEnable7; // non-zero if pull down enabled + UCHAR SerNumEnable7; // non-zero if serial number to be used + UCHAR ALSlowSlew; // non-zero if AL pins have slow slew + UCHAR ALSchmittInput; // non-zero if AL pins are Schmitt input + UCHAR ALDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR AHSlowSlew; // non-zero if AH pins have slow slew + UCHAR AHSchmittInput; // non-zero if AH pins are Schmitt input + UCHAR AHDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR BLSlowSlew; // non-zero if BL pins have slow slew + UCHAR BLSchmittInput; // non-zero if BL pins are Schmitt input + UCHAR BLDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR BHSlowSlew; // non-zero if BH pins have slow slew + UCHAR BHSchmittInput; // non-zero if BH pins are Schmitt input + UCHAR BHDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR IFAIsFifo7; // non-zero if interface is 245 FIFO + UCHAR IFAIsFifoTar7; // non-zero if interface is 245 FIFO CPU target + UCHAR IFAIsFastSer7; // non-zero if interface is Fast serial + UCHAR AIsVCP7; // non-zero if interface is to use VCP drivers + UCHAR IFBIsFifo7; // non-zero if interface is 245 FIFO + UCHAR IFBIsFifoTar7; // non-zero if interface is 245 FIFO CPU target + UCHAR IFBIsFastSer7; // non-zero if interface is Fast serial + UCHAR BIsVCP7; // non-zero if interface is to use VCP drivers + UCHAR PowerSaveEnable; // non-zero if using BCBUS7 to save power for self-powered designs + // + // Rev 8 (FT4232H) Extensions + // + UCHAR PullDownEnable8; // non-zero if pull down enabled + UCHAR SerNumEnable8; // non-zero if serial number to be used + UCHAR ASlowSlew; // non-zero if A pins have slow slew + UCHAR ASchmittInput; // non-zero if A pins are Schmitt input + UCHAR ADriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR BSlowSlew; // non-zero if B pins have slow slew + UCHAR BSchmittInput; // non-zero if B pins are Schmitt input + UCHAR BDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR CSlowSlew; // non-zero if C pins have slow slew + UCHAR CSchmittInput; // non-zero if C pins are Schmitt input + UCHAR CDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR DSlowSlew; // non-zero if D pins have slow slew + UCHAR DSchmittInput; // non-zero if D pins are Schmitt input + UCHAR DDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR ARIIsTXDEN; // non-zero if port A uses RI as RS485 TXDEN + UCHAR BRIIsTXDEN; // non-zero if port B uses RI as RS485 TXDEN + UCHAR CRIIsTXDEN; // non-zero if port C uses RI as RS485 TXDEN + UCHAR DRIIsTXDEN; // non-zero if port D uses RI as RS485 TXDEN + UCHAR AIsVCP8; // non-zero if interface is to use VCP drivers + UCHAR BIsVCP8; // non-zero if interface is to use VCP drivers + UCHAR CIsVCP8; // non-zero if interface is to use VCP drivers + UCHAR DIsVCP8; // non-zero if interface is to use VCP drivers + // + // Rev 9 (FT232H) Extensions + // + UCHAR PullDownEnableH; // non-zero if pull down enabled + UCHAR SerNumEnableH; // non-zero if serial number to be used + UCHAR ACSlowSlewH; // non-zero if AC pins have slow slew + UCHAR ACSchmittInputH; // non-zero if AC pins are Schmitt input + UCHAR ACDriveCurrentH; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR ADSlowSlewH; // non-zero if AD pins have slow slew + UCHAR ADSchmittInputH; // non-zero if AD pins are Schmitt input + UCHAR ADDriveCurrentH; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR Cbus0H; // Cbus Mux control + UCHAR Cbus1H; // Cbus Mux control + UCHAR Cbus2H; // Cbus Mux control + UCHAR Cbus3H; // Cbus Mux control + UCHAR Cbus4H; // Cbus Mux control + UCHAR Cbus5H; // Cbus Mux control + UCHAR Cbus6H; // Cbus Mux control + UCHAR Cbus7H; // Cbus Mux control + UCHAR Cbus8H; // Cbus Mux control + UCHAR Cbus9H; // Cbus Mux control + UCHAR IsFifoH; // non-zero if interface is 245 FIFO + UCHAR IsFifoTarH; // non-zero if interface is 245 FIFO CPU target + UCHAR IsFastSerH; // non-zero if interface is Fast serial + UCHAR IsFT1248H; // non-zero if interface is FT1248 + UCHAR FT1248CpolH; // FT1248 clock polarity - clock idle high (1) or clock idle low (0) + UCHAR FT1248LsbH; // FT1248 data is LSB (1) or MSB (0) + UCHAR FT1248FlowControlH; // FT1248 flow control enable + UCHAR IsVCPH; // non-zero if interface is to use VCP drivers + UCHAR PowerSaveEnableH; // non-zero if using ACBUS7 to save power for self-powered designs + + } CONFIG_DATA; + + void ft_to_config(CONFIG_DATA*, PFT_PROGRAM_DATA); + void config_to_ft(PFT_PROGRAM_DATA, CONFIG_DATA*); + +#endif /* CONFIG_TYPE_H_ */ diff --git a/alchitry-loader/src/ftd2xx.h b/alchitry-loader/src/ftd2xx.h new file mode 100644 index 0000000..e5bbb46 --- /dev/null +++ b/alchitry-loader/src/ftd2xx.h @@ -0,0 +1,1443 @@ +/*++ + +Copyright © 2001-2011 Future Technology Devices International Limited + +THIS SOFTWARE IS PROVIDED BY FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +FTDI DRIVERS MAY BE USED ONLY IN CONJUNCTION WITH PRODUCTS BASED ON FTDI PARTS. + +FTDI DRIVERS MAY BE DISTRIBUTED IN ANY FORM AS LONG AS LICENSE INFORMATION IS NOT MODIFIED. + +IF A CUSTOM VENDOR ID AND/OR PRODUCT ID OR DESCRIPTION STRING ARE USED, IT IS THE +RESPONSIBILITY OF THE PRODUCT MANUFACTURER TO MAINTAIN ANY CHANGES AND SUBSEQUENT WHQL +RE-CERTIFICATION AS A RESULT OF MAKING THESE CHANGES. + + +Module Name: + +ftd2xx.h + +Abstract: + +Native USB device driver for FTDI FT232x, FT245x, FT2232x and FT4232x devices +FTD2XX library definitions + +Environment: + +kernel & user mode + + +--*/ + + +#ifndef FTD2XX_H +#define FTD2XX_H + +#ifdef _WIN32 +// Compiling on Windows +#include + +// The following ifdef block is the standard way of creating macros +// which make exporting from a DLL simpler. All files within this DLL +// are compiled with the FTD2XX_EXPORTS symbol defined on the command line. +// This symbol should not be defined on any project that uses this DLL. +// This way any other project whose source files include this file see +// FTD2XX_API functions as being imported from a DLL, whereas this DLL +// sees symbols defined with this macro as being exported. + +#ifdef FTD2XX_EXPORTS +#define FTD2XX_API __declspec(dllexport) +#elif defined(FTD2XX_STATIC) +// Avoid decorations when linking statically to D2XX. +#define FTD2XX_API +// Static D2XX depends on these Windows libs: +#pragma comment(lib, "setupapi.lib") +#pragma comment(lib, "advapi32.lib") +#pragma comment(lib, "user32.lib") +#else +#define FTD2XX_API __declspec(dllimport) +#endif + +#else // _WIN32 +// Compiling on non-Windows platform. +#include "WinTypes.h" +// No decorations needed. +#define FTD2XX_API + +#endif // _WIN32 + +typedef PVOID FT_HANDLE; +typedef ULONG FT_STATUS; + +// +// Device status +// +enum { + FT_OK, + FT_INVALID_HANDLE, + FT_DEVICE_NOT_FOUND, + FT_DEVICE_NOT_OPENED, + FT_IO_ERROR, + FT_INSUFFICIENT_RESOURCES, + FT_INVALID_PARAMETER, + FT_INVALID_BAUD_RATE, + + FT_DEVICE_NOT_OPENED_FOR_ERASE, + FT_DEVICE_NOT_OPENED_FOR_WRITE, + FT_FAILED_TO_WRITE_DEVICE, + FT_EEPROM_READ_FAILED, + FT_EEPROM_WRITE_FAILED, + FT_EEPROM_ERASE_FAILED, + FT_EEPROM_NOT_PRESENT, + FT_EEPROM_NOT_PROGRAMMED, + FT_INVALID_ARGS, + FT_NOT_SUPPORTED, + FT_OTHER_ERROR, + FT_DEVICE_LIST_NOT_READY, +}; + + +#define FT_SUCCESS(status) ((status) == FT_OK) + +// +// FT_OpenEx Flags +// + +#define FT_OPEN_BY_SERIAL_NUMBER 1 +#define FT_OPEN_BY_DESCRIPTION 2 +#define FT_OPEN_BY_LOCATION 4 + +#define FT_OPEN_MASK (FT_OPEN_BY_SERIAL_NUMBER | \ + FT_OPEN_BY_DESCRIPTION | \ + FT_OPEN_BY_LOCATION) + +// +// FT_ListDevices Flags (used in conjunction with FT_OpenEx Flags +// + +#define FT_LIST_NUMBER_ONLY 0x80000000 +#define FT_LIST_BY_INDEX 0x40000000 +#define FT_LIST_ALL 0x20000000 + +#define FT_LIST_MASK (FT_LIST_NUMBER_ONLY|FT_LIST_BY_INDEX|FT_LIST_ALL) + +// +// Baud Rates +// + +#define FT_BAUD_300 300 +#define FT_BAUD_600 600 +#define FT_BAUD_1200 1200 +#define FT_BAUD_2400 2400 +#define FT_BAUD_4800 4800 +#define FT_BAUD_9600 9600 +#define FT_BAUD_14400 14400 +#define FT_BAUD_19200 19200 +#define FT_BAUD_38400 38400 +#define FT_BAUD_57600 57600 +#define FT_BAUD_115200 115200 +#define FT_BAUD_230400 230400 +#define FT_BAUD_460800 460800 +#define FT_BAUD_921600 921600 + +// +// Word Lengths +// + +#define FT_BITS_8 (UCHAR) 8 +#define FT_BITS_7 (UCHAR) 7 + +// +// Stop Bits +// + +#define FT_STOP_BITS_1 (UCHAR) 0 +#define FT_STOP_BITS_2 (UCHAR) 2 + +// +// Parity +// + +#define FT_PARITY_NONE (UCHAR) 0 +#define FT_PARITY_ODD (UCHAR) 1 +#define FT_PARITY_EVEN (UCHAR) 2 +#define FT_PARITY_MARK (UCHAR) 3 +#define FT_PARITY_SPACE (UCHAR) 4 + +// +// Flow Control +// + +#define FT_FLOW_NONE 0x0000 +#define FT_FLOW_RTS_CTS 0x0100 +#define FT_FLOW_DTR_DSR 0x0200 +#define FT_FLOW_XON_XOFF 0x0400 + +// +// Purge rx and tx buffers +// +#define FT_PURGE_RX 1 +#define FT_PURGE_TX 2 + +// +// Events +// + +typedef void (*PFT_EVENT_HANDLER)(DWORD,DWORD); + +#define FT_EVENT_RXCHAR 1 +#define FT_EVENT_MODEM_STATUS 2 +#define FT_EVENT_LINE_STATUS 4 + +// +// Timeouts +// + +#define FT_DEFAULT_RX_TIMEOUT 300 +#define FT_DEFAULT_TX_TIMEOUT 300 + +// +// Device types +// + +typedef ULONG FT_DEVICE; + +enum { + FT_DEVICE_BM, + FT_DEVICE_AM, + FT_DEVICE_100AX, + FT_DEVICE_UNKNOWN, + FT_DEVICE_2232C, + FT_DEVICE_232R, + FT_DEVICE_2232H, + FT_DEVICE_4232H, + FT_DEVICE_232H, + FT_DEVICE_X_SERIES, + FT_DEVICE_4222H_0, + FT_DEVICE_4222H_1_2, + FT_DEVICE_4222H_3, + FT_DEVICE_4222_PROG, +}; + +// +// Bit Modes +// + +#define FT_BITMODE_RESET 0x00 +#define FT_BITMODE_ASYNC_BITBANG 0x01 +#define FT_BITMODE_MPSSE 0x02 +#define FT_BITMODE_SYNC_BITBANG 0x04 +#define FT_BITMODE_MCU_HOST 0x08 +#define FT_BITMODE_FAST_SERIAL 0x10 +#define FT_BITMODE_CBUS_BITBANG 0x20 +#define FT_BITMODE_SYNC_FIFO 0x40 + +// +// FT232R CBUS Options EEPROM values +// + +#define FT_232R_CBUS_TXDEN 0x00 // Tx Data Enable +#define FT_232R_CBUS_PWRON 0x01 // Power On +#define FT_232R_CBUS_RXLED 0x02 // Rx LED +#define FT_232R_CBUS_TXLED 0x03 // Tx LED +#define FT_232R_CBUS_TXRXLED 0x04 // Tx and Rx LED +#define FT_232R_CBUS_SLEEP 0x05 // Sleep +#define FT_232R_CBUS_CLK48 0x06 // 48MHz clock +#define FT_232R_CBUS_CLK24 0x07 // 24MHz clock +#define FT_232R_CBUS_CLK12 0x08 // 12MHz clock +#define FT_232R_CBUS_CLK6 0x09 // 6MHz clock +#define FT_232R_CBUS_IOMODE 0x0A // IO Mode for CBUS bit-bang +#define FT_232R_CBUS_BITBANG_WR 0x0B // Bit-bang write strobe +#define FT_232R_CBUS_BITBANG_RD 0x0C // Bit-bang read strobe + +// +// FT232H CBUS Options EEPROM values +// + +#define FT_232H_CBUS_TRISTATE 0x00 // Tristate +#define FT_232H_CBUS_TXLED 0x01 // Tx LED +#define FT_232H_CBUS_RXLED 0x02 // Rx LED +#define FT_232H_CBUS_TXRXLED 0x03 // Tx and Rx LED +#define FT_232H_CBUS_PWREN 0x04 // Power Enable +#define FT_232H_CBUS_SLEEP 0x05 // Sleep +#define FT_232H_CBUS_DRIVE_0 0x06 // Drive pin to logic 0 +#define FT_232H_CBUS_DRIVE_1 0x07 // Drive pin to logic 1 +#define FT_232H_CBUS_IOMODE 0x08 // IO Mode for CBUS bit-bang +#define FT_232H_CBUS_TXDEN 0x09 // Tx Data Enable +#define FT_232H_CBUS_CLK30 0x0A // 30MHz clock +#define FT_232H_CBUS_CLK15 0x0B // 15MHz clock +#define FT_232H_CBUS_CLK7_5 0x0C // 7.5MHz clock + +// +// FT X Series CBUS Options EEPROM values +// + +#define FT_X_SERIES_CBUS_TRISTATE 0x00 // Tristate +#define FT_X_SERIES_CBUS_TXLED 0x01 // Tx LED +#define FT_X_SERIES_CBUS_RXLED 0x02 // Rx LED +#define FT_X_SERIES_CBUS_TXRXLED 0x03 // Tx and Rx LED +#define FT_X_SERIES_CBUS_PWREN 0x04 // Power Enable +#define FT_X_SERIES_CBUS_SLEEP 0x05 // Sleep +#define FT_X_SERIES_CBUS_DRIVE_0 0x06 // Drive pin to logic 0 +#define FT_X_SERIES_CBUS_DRIVE_1 0x07 // Drive pin to logic 1 +#define FT_X_SERIES_CBUS_IOMODE 0x08 // IO Mode for CBUS bit-bang +#define FT_X_SERIES_CBUS_TXDEN 0x09 // Tx Data Enable +#define FT_X_SERIES_CBUS_CLK24 0x0A // 24MHz clock +#define FT_X_SERIES_CBUS_CLK12 0x0B // 12MHz clock +#define FT_X_SERIES_CBUS_CLK6 0x0C // 6MHz clock +#define FT_X_SERIES_CBUS_BCD_CHARGER 0x0D // Battery charger detected +#define FT_X_SERIES_CBUS_BCD_CHARGER_N 0x0E // Battery charger detected inverted +#define FT_X_SERIES_CBUS_I2C_TXE 0x0F // I2C Tx empty +#define FT_X_SERIES_CBUS_I2C_RXF 0x10 // I2C Rx full +#define FT_X_SERIES_CBUS_VBUS_SENSE 0x11 // Detect VBUS +#define FT_X_SERIES_CBUS_BITBANG_WR 0x12 // Bit-bang write strobe +#define FT_X_SERIES_CBUS_BITBANG_RD 0x13 // Bit-bang read strobe +#define FT_X_SERIES_CBUS_TIMESTAMP 0x14 // Toggle output when a USB SOF token is received +#define FT_X_SERIES_CBUS_KEEP_AWAKE 0x15 // + + +// Driver types +#define FT_DRIVER_TYPE_D2XX 0 +#define FT_DRIVER_TYPE_VCP 1 + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef FTD2XX_STATIC + FTD2XX_API + FT_STATUS WINAPI FT_Initialise( + void + ); + + FTD2XX_API + void WINAPI FT_Finalise( + void + ); +#endif // FTD2XX_STATIC + + FTD2XX_API + FT_STATUS WINAPI FT_Open( + int deviceNumber, + FT_HANDLE *pHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_OpenEx( + PVOID pArg1, + DWORD Flags, + FT_HANDLE *pHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_ListDevices( + PVOID pArg1, + PVOID pArg2, + DWORD Flags + ); + + FTD2XX_API + FT_STATUS WINAPI FT_Close( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_Read( + FT_HANDLE ftHandle, + LPVOID lpBuffer, + DWORD dwBytesToRead, + LPDWORD lpBytesReturned + ); + + FTD2XX_API + FT_STATUS WINAPI FT_Write( + FT_HANDLE ftHandle, + LPVOID lpBuffer, + DWORD dwBytesToWrite, + LPDWORD lpBytesWritten + ); + + FTD2XX_API + FT_STATUS WINAPI FT_IoCtl( + FT_HANDLE ftHandle, + DWORD dwIoControlCode, + LPVOID lpInBuf, + DWORD nInBufSize, + LPVOID lpOutBuf, + DWORD nOutBufSize, + LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetBaudRate( + FT_HANDLE ftHandle, + ULONG BaudRate + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetDivisor( + FT_HANDLE ftHandle, + USHORT Divisor + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetDataCharacteristics( + FT_HANDLE ftHandle, + UCHAR WordLength, + UCHAR StopBits, + UCHAR Parity + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetFlowControl( + FT_HANDLE ftHandle, + USHORT FlowControl, + UCHAR XonChar, + UCHAR XoffChar + ); + + FTD2XX_API + FT_STATUS WINAPI FT_ResetDevice( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetDtr( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_ClrDtr( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetRts( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_ClrRts( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_GetModemStatus( + FT_HANDLE ftHandle, + ULONG *pModemStatus + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetChars( + FT_HANDLE ftHandle, + UCHAR EventChar, + UCHAR EventCharEnabled, + UCHAR ErrorChar, + UCHAR ErrorCharEnabled + ); + + FTD2XX_API + FT_STATUS WINAPI FT_Purge( + FT_HANDLE ftHandle, + ULONG Mask + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetTimeouts( + FT_HANDLE ftHandle, + ULONG ReadTimeout, + ULONG WriteTimeout + ); + + FTD2XX_API + FT_STATUS WINAPI FT_GetQueueStatus( + FT_HANDLE ftHandle, + DWORD *dwRxBytes + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetEventNotification( + FT_HANDLE ftHandle, + DWORD Mask, + PVOID Param + ); + + FTD2XX_API + FT_STATUS WINAPI FT_GetStatus( + FT_HANDLE ftHandle, + DWORD *dwRxBytes, + DWORD *dwTxBytes, + DWORD *dwEventDWord + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetBreakOn( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetBreakOff( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetWaitMask( + FT_HANDLE ftHandle, + DWORD Mask + ); + + FTD2XX_API + FT_STATUS WINAPI FT_WaitOnMask( + FT_HANDLE ftHandle, + DWORD *Mask + ); + + FTD2XX_API + FT_STATUS WINAPI FT_GetEventStatus( + FT_HANDLE ftHandle, + DWORD *dwEventDWord + ); + + FTD2XX_API + FT_STATUS WINAPI FT_ReadEE( + FT_HANDLE ftHandle, + DWORD dwWordOffset, + LPWORD lpwValue + ); + + FTD2XX_API + FT_STATUS WINAPI FT_WriteEE( + FT_HANDLE ftHandle, + DWORD dwWordOffset, + WORD wValue + ); + + FTD2XX_API + FT_STATUS WINAPI FT_EraseEE( + FT_HANDLE ftHandle + ); + + // + // structure to hold program data for FT_EE_Program, FT_EE_ProgramEx, FT_EE_Read + // and FT_EE_ReadEx functions + // + typedef struct ft_program_data { + + DWORD Signature1; // Header - must be 0x00000000 + DWORD Signature2; // Header - must be 0xffffffff + DWORD Version; // Header - FT_PROGRAM_DATA version + // 0 = original + // 1 = FT2232 extensions + // 2 = FT232R extensions + // 3 = FT2232H extensions + // 4 = FT4232H extensions + // 5 = FT232H extensions + + WORD VendorId; // 0x0403 + WORD ProductId; // 0x6001 + char *Manufacturer; // "FTDI" + char *ManufacturerId; // "FT" + char *Description; // "USB HS Serial Converter" + char *SerialNumber; // "FT000001" if fixed, or NULL + WORD MaxPower; // 0 < MaxPower <= 500 + WORD PnP; // 0 = disabled, 1 = enabled + WORD SelfPowered; // 0 = bus powered, 1 = self powered + WORD RemoteWakeup; // 0 = not capable, 1 = capable + // + // Rev4 (FT232B) extensions + // + UCHAR Rev4; // non-zero if Rev4 chip, zero otherwise + UCHAR IsoIn; // non-zero if in endpoint is isochronous + UCHAR IsoOut; // non-zero if out endpoint is isochronous + UCHAR PullDownEnable; // non-zero if pull down enabled + UCHAR SerNumEnable; // non-zero if serial number to be used + UCHAR USBVersionEnable; // non-zero if chip uses USBVersion + WORD USBVersion; // BCD (0x0200 => USB2) + // + // Rev 5 (FT2232) extensions + // + UCHAR Rev5; // non-zero if Rev5 chip, zero otherwise + UCHAR IsoInA; // non-zero if in endpoint is isochronous + UCHAR IsoInB; // non-zero if in endpoint is isochronous + UCHAR IsoOutA; // non-zero if out endpoint is isochronous + UCHAR IsoOutB; // non-zero if out endpoint is isochronous + UCHAR PullDownEnable5; // non-zero if pull down enabled + UCHAR SerNumEnable5; // non-zero if serial number to be used + UCHAR USBVersionEnable5; // non-zero if chip uses USBVersion + WORD USBVersion5; // BCD (0x0200 => USB2) + UCHAR AIsHighCurrent; // non-zero if interface is high current + UCHAR BIsHighCurrent; // non-zero if interface is high current + UCHAR IFAIsFifo; // non-zero if interface is 245 FIFO + UCHAR IFAIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR IFAIsFastSer; // non-zero if interface is Fast serial + UCHAR AIsVCP; // non-zero if interface is to use VCP drivers + UCHAR IFBIsFifo; // non-zero if interface is 245 FIFO + UCHAR IFBIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR IFBIsFastSer; // non-zero if interface is Fast serial + UCHAR BIsVCP; // non-zero if interface is to use VCP drivers + // + // Rev 6 (FT232R) extensions + // + UCHAR UseExtOsc; // Use External Oscillator + UCHAR HighDriveIOs; // High Drive I/Os + UCHAR EndpointSize; // Endpoint size + UCHAR PullDownEnableR; // non-zero if pull down enabled + UCHAR SerNumEnableR; // non-zero if serial number to be used + UCHAR InvertTXD; // non-zero if invert TXD + UCHAR InvertRXD; // non-zero if invert RXD + UCHAR InvertRTS; // non-zero if invert RTS + UCHAR InvertCTS; // non-zero if invert CTS + UCHAR InvertDTR; // non-zero if invert DTR + UCHAR InvertDSR; // non-zero if invert DSR + UCHAR InvertDCD; // non-zero if invert DCD + UCHAR InvertRI; // non-zero if invert RI + UCHAR Cbus0; // Cbus Mux control + UCHAR Cbus1; // Cbus Mux control + UCHAR Cbus2; // Cbus Mux control + UCHAR Cbus3; // Cbus Mux control + UCHAR Cbus4; // Cbus Mux control + UCHAR RIsD2XX; // non-zero if using D2XX driver + // + // Rev 7 (FT2232H) Extensions + // + UCHAR PullDownEnable7; // non-zero if pull down enabled + UCHAR SerNumEnable7; // non-zero if serial number to be used + UCHAR ALSlowSlew; // non-zero if AL pins have slow slew + UCHAR ALSchmittInput; // non-zero if AL pins are Schmitt input + UCHAR ALDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR AHSlowSlew; // non-zero if AH pins have slow slew + UCHAR AHSchmittInput; // non-zero if AH pins are Schmitt input + UCHAR AHDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR BLSlowSlew; // non-zero if BL pins have slow slew + UCHAR BLSchmittInput; // non-zero if BL pins are Schmitt input + UCHAR BLDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR BHSlowSlew; // non-zero if BH pins have slow slew + UCHAR BHSchmittInput; // non-zero if BH pins are Schmitt input + UCHAR BHDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR IFAIsFifo7; // non-zero if interface is 245 FIFO + UCHAR IFAIsFifoTar7; // non-zero if interface is 245 FIFO CPU target + UCHAR IFAIsFastSer7; // non-zero if interface is Fast serial + UCHAR AIsVCP7; // non-zero if interface is to use VCP drivers + UCHAR IFBIsFifo7; // non-zero if interface is 245 FIFO + UCHAR IFBIsFifoTar7; // non-zero if interface is 245 FIFO CPU target + UCHAR IFBIsFastSer7; // non-zero if interface is Fast serial + UCHAR BIsVCP7; // non-zero if interface is to use VCP drivers + UCHAR PowerSaveEnable; // non-zero if using BCBUS7 to save power for self-powered designs + // + // Rev 8 (FT4232H) Extensions + // + UCHAR PullDownEnable8; // non-zero if pull down enabled + UCHAR SerNumEnable8; // non-zero if serial number to be used + UCHAR ASlowSlew; // non-zero if A pins have slow slew + UCHAR ASchmittInput; // non-zero if A pins are Schmitt input + UCHAR ADriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR BSlowSlew; // non-zero if B pins have slow slew + UCHAR BSchmittInput; // non-zero if B pins are Schmitt input + UCHAR BDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR CSlowSlew; // non-zero if C pins have slow slew + UCHAR CSchmittInput; // non-zero if C pins are Schmitt input + UCHAR CDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR DSlowSlew; // non-zero if D pins have slow slew + UCHAR DSchmittInput; // non-zero if D pins are Schmitt input + UCHAR DDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR ARIIsTXDEN; // non-zero if port A uses RI as RS485 TXDEN + UCHAR BRIIsTXDEN; // non-zero if port B uses RI as RS485 TXDEN + UCHAR CRIIsTXDEN; // non-zero if port C uses RI as RS485 TXDEN + UCHAR DRIIsTXDEN; // non-zero if port D uses RI as RS485 TXDEN + UCHAR AIsVCP8; // non-zero if interface is to use VCP drivers + UCHAR BIsVCP8; // non-zero if interface is to use VCP drivers + UCHAR CIsVCP8; // non-zero if interface is to use VCP drivers + UCHAR DIsVCP8; // non-zero if interface is to use VCP drivers + // + // Rev 9 (FT232H) Extensions + // + UCHAR PullDownEnableH; // non-zero if pull down enabled + UCHAR SerNumEnableH; // non-zero if serial number to be used + UCHAR ACSlowSlewH; // non-zero if AC pins have slow slew + UCHAR ACSchmittInputH; // non-zero if AC pins are Schmitt input + UCHAR ACDriveCurrentH; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR ADSlowSlewH; // non-zero if AD pins have slow slew + UCHAR ADSchmittInputH; // non-zero if AD pins are Schmitt input + UCHAR ADDriveCurrentH; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR Cbus0H; // Cbus Mux control + UCHAR Cbus1H; // Cbus Mux control + UCHAR Cbus2H; // Cbus Mux control + UCHAR Cbus3H; // Cbus Mux control + UCHAR Cbus4H; // Cbus Mux control + UCHAR Cbus5H; // Cbus Mux control + UCHAR Cbus6H; // Cbus Mux control + UCHAR Cbus7H; // Cbus Mux control + UCHAR Cbus8H; // Cbus Mux control + UCHAR Cbus9H; // Cbus Mux control + UCHAR IsFifoH; // non-zero if interface is 245 FIFO + UCHAR IsFifoTarH; // non-zero if interface is 245 FIFO CPU target + UCHAR IsFastSerH; // non-zero if interface is Fast serial + UCHAR IsFT1248H; // non-zero if interface is FT1248 + UCHAR FT1248CpolH; // FT1248 clock polarity - clock idle high (1) or clock idle low (0) + UCHAR FT1248LsbH; // FT1248 data is LSB (1) or MSB (0) + UCHAR FT1248FlowControlH; // FT1248 flow control enable + UCHAR IsVCPH; // non-zero if interface is to use VCP drivers + UCHAR PowerSaveEnableH; // non-zero if using ACBUS7 to save power for self-powered designs + + } FT_PROGRAM_DATA, *PFT_PROGRAM_DATA; + + FTD2XX_API + FT_STATUS WINAPI FT_EE_Program( + FT_HANDLE ftHandle, + PFT_PROGRAM_DATA pData + ); + + FTD2XX_API + FT_STATUS WINAPI FT_EE_ProgramEx( + FT_HANDLE ftHandle, + PFT_PROGRAM_DATA pData, + char *Manufacturer, + char *ManufacturerId, + char *Description, + char *SerialNumber + ); + + FTD2XX_API + FT_STATUS WINAPI FT_EE_Read( + FT_HANDLE ftHandle, + PFT_PROGRAM_DATA pData + ); + + FTD2XX_API + FT_STATUS WINAPI FT_EE_ReadEx( + FT_HANDLE ftHandle, + PFT_PROGRAM_DATA pData, + char *Manufacturer, + char *ManufacturerId, + char *Description, + char *SerialNumber + ); + + FTD2XX_API + FT_STATUS WINAPI FT_EE_UASize( + FT_HANDLE ftHandle, + LPDWORD lpdwSize + ); + + FTD2XX_API + FT_STATUS WINAPI FT_EE_UAWrite( + FT_HANDLE ftHandle, + PUCHAR pucData, + DWORD dwDataLen + ); + + FTD2XX_API + FT_STATUS WINAPI FT_EE_UARead( + FT_HANDLE ftHandle, + PUCHAR pucData, + DWORD dwDataLen, + LPDWORD lpdwBytesRead + ); + + + typedef struct ft_eeprom_header { + FT_DEVICE deviceType; // FTxxxx device type to be programmed + // Device descriptor options + WORD VendorId; // 0x0403 + WORD ProductId; // 0x6001 + UCHAR SerNumEnable; // non-zero if serial number to be used + // Config descriptor options + WORD MaxPower; // 0 < MaxPower <= 500 + UCHAR SelfPowered; // 0 = bus powered, 1 = self powered + UCHAR RemoteWakeup; // 0 = not capable, 1 = capable + // Hardware options + UCHAR PullDownEnable; // non-zero if pull down in suspend enabled + } FT_EEPROM_HEADER, *PFT_EEPROM_HEADER; + + + // FT232B EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program + typedef struct ft_eeprom_232b { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + } FT_EEPROM_232B, *PFT_EEPROM_232B; + + + // FT2232 EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program + typedef struct ft_eeprom_2232 { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + // Drive options + UCHAR AIsHighCurrent; // non-zero if interface is high current + UCHAR BIsHighCurrent; // non-zero if interface is high current + // Hardware options + UCHAR AIsFifo; // non-zero if interface is 245 FIFO + UCHAR AIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR AIsFastSer; // non-zero if interface is Fast serial + UCHAR BIsFifo; // non-zero if interface is 245 FIFO + UCHAR BIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR BIsFastSer; // non-zero if interface is Fast serial + // Driver option + UCHAR ADriverType; // + UCHAR BDriverType; // + } FT_EEPROM_2232, *PFT_EEPROM_2232; + + + // FT232R EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program + typedef struct ft_eeprom_232r { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + // Drive options + UCHAR IsHighCurrent; // non-zero if interface is high current + // Hardware options + UCHAR UseExtOsc; // Use External Oscillator + UCHAR InvertTXD; // non-zero if invert TXD + UCHAR InvertRXD; // non-zero if invert RXD + UCHAR InvertRTS; // non-zero if invert RTS + UCHAR InvertCTS; // non-zero if invert CTS + UCHAR InvertDTR; // non-zero if invert DTR + UCHAR InvertDSR; // non-zero if invert DSR + UCHAR InvertDCD; // non-zero if invert DCD + UCHAR InvertRI; // non-zero if invert RI + UCHAR Cbus0; // Cbus Mux control + UCHAR Cbus1; // Cbus Mux control + UCHAR Cbus2; // Cbus Mux control + UCHAR Cbus3; // Cbus Mux control + UCHAR Cbus4; // Cbus Mux control + // Driver option + UCHAR DriverType; // + } FT_EEPROM_232R, *PFT_EEPROM_232R; + + + // FT2232H EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program + typedef struct ft_eeprom_2232h { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + // Drive options + UCHAR ALSlowSlew; // non-zero if AL pins have slow slew + UCHAR ALSchmittInput; // non-zero if AL pins are Schmitt input + UCHAR ALDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR AHSlowSlew; // non-zero if AH pins have slow slew + UCHAR AHSchmittInput; // non-zero if AH pins are Schmitt input + UCHAR AHDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR BLSlowSlew; // non-zero if BL pins have slow slew + UCHAR BLSchmittInput; // non-zero if BL pins are Schmitt input + UCHAR BLDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR BHSlowSlew; // non-zero if BH pins have slow slew + UCHAR BHSchmittInput; // non-zero if BH pins are Schmitt input + UCHAR BHDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + // Hardware options + UCHAR AIsFifo; // non-zero if interface is 245 FIFO + UCHAR AIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR AIsFastSer; // non-zero if interface is Fast serial + UCHAR BIsFifo; // non-zero if interface is 245 FIFO + UCHAR BIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR BIsFastSer; // non-zero if interface is Fast serial + UCHAR PowerSaveEnable; // non-zero if using BCBUS7 to save power for self-powered designs + // Driver option + UCHAR ADriverType; // + UCHAR BDriverType; // + } FT_EEPROM_2232H, *PFT_EEPROM_2232H; + + + // FT4232H EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program + typedef struct ft_eeprom_4232h { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + // Drive options + UCHAR ASlowSlew; // non-zero if A pins have slow slew + UCHAR ASchmittInput; // non-zero if A pins are Schmitt input + UCHAR ADriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR BSlowSlew; // non-zero if B pins have slow slew + UCHAR BSchmittInput; // non-zero if B pins are Schmitt input + UCHAR BDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR CSlowSlew; // non-zero if C pins have slow slew + UCHAR CSchmittInput; // non-zero if C pins are Schmitt input + UCHAR CDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR DSlowSlew; // non-zero if D pins have slow slew + UCHAR DSchmittInput; // non-zero if D pins are Schmitt input + UCHAR DDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + // Hardware options + UCHAR ARIIsTXDEN; // non-zero if port A uses RI as RS485 TXDEN + UCHAR BRIIsTXDEN; // non-zero if port B uses RI as RS485 TXDEN + UCHAR CRIIsTXDEN; // non-zero if port C uses RI as RS485 TXDEN + UCHAR DRIIsTXDEN; // non-zero if port D uses RI as RS485 TXDEN + // Driver option + UCHAR ADriverType; // + UCHAR BDriverType; // + UCHAR CDriverType; // + UCHAR DDriverType; // + } FT_EEPROM_4232H, *PFT_EEPROM_4232H; + + + // FT232H EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program + typedef struct ft_eeprom_232h { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + // Drive options + UCHAR ACSlowSlew; // non-zero if AC bus pins have slow slew + UCHAR ACSchmittInput; // non-zero if AC bus pins are Schmitt input + UCHAR ACDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR ADSlowSlew; // non-zero if AD bus pins have slow slew + UCHAR ADSchmittInput; // non-zero if AD bus pins are Schmitt input + UCHAR ADDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + // CBUS options + UCHAR Cbus0; // Cbus Mux control + UCHAR Cbus1; // Cbus Mux control + UCHAR Cbus2; // Cbus Mux control + UCHAR Cbus3; // Cbus Mux control + UCHAR Cbus4; // Cbus Mux control + UCHAR Cbus5; // Cbus Mux control + UCHAR Cbus6; // Cbus Mux control + UCHAR Cbus7; // Cbus Mux control + UCHAR Cbus8; // Cbus Mux control + UCHAR Cbus9; // Cbus Mux control + // FT1248 options + UCHAR FT1248Cpol; // FT1248 clock polarity - clock idle high (1) or clock idle low (0) + UCHAR FT1248Lsb; // FT1248 data is LSB (1) or MSB (0) + UCHAR FT1248FlowControl; // FT1248 flow control enable + // Hardware options + UCHAR IsFifo; // non-zero if interface is 245 FIFO + UCHAR IsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR IsFastSer; // non-zero if interface is Fast serial + UCHAR IsFT1248 ; // non-zero if interface is FT1248 + UCHAR PowerSaveEnable; // + // Driver option + UCHAR DriverType; // + } FT_EEPROM_232H, *PFT_EEPROM_232H; + + + // FT X Series EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program + typedef struct ft_eeprom_x_series { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + // Drive options + UCHAR ACSlowSlew; // non-zero if AC bus pins have slow slew + UCHAR ACSchmittInput; // non-zero if AC bus pins are Schmitt input + UCHAR ACDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR ADSlowSlew; // non-zero if AD bus pins have slow slew + UCHAR ADSchmittInput; // non-zero if AD bus pins are Schmitt input + UCHAR ADDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + // CBUS options + UCHAR Cbus0; // Cbus Mux control + UCHAR Cbus1; // Cbus Mux control + UCHAR Cbus2; // Cbus Mux control + UCHAR Cbus3; // Cbus Mux control + UCHAR Cbus4; // Cbus Mux control + UCHAR Cbus5; // Cbus Mux control + UCHAR Cbus6; // Cbus Mux control + // UART signal options + UCHAR InvertTXD; // non-zero if invert TXD + UCHAR InvertRXD; // non-zero if invert RXD + UCHAR InvertRTS; // non-zero if invert RTS + UCHAR InvertCTS; // non-zero if invert CTS + UCHAR InvertDTR; // non-zero if invert DTR + UCHAR InvertDSR; // non-zero if invert DSR + UCHAR InvertDCD; // non-zero if invert DCD + UCHAR InvertRI; // non-zero if invert RI + // Battery Charge Detect options + UCHAR BCDEnable; // Enable Battery Charger Detection + UCHAR BCDForceCbusPWREN; // asserts the power enable signal on CBUS when charging port detected + UCHAR BCDDisableSleep; // forces the device never to go into sleep mode + // I2C options + WORD I2CSlaveAddress; // I2C slave device address + DWORD I2CDeviceId; // I2C device ID + UCHAR I2CDisableSchmitt; // Disable I2C Schmitt trigger + // FT1248 options + UCHAR FT1248Cpol; // FT1248 clock polarity - clock idle high (1) or clock idle low (0) + UCHAR FT1248Lsb; // FT1248 data is LSB (1) or MSB (0) + UCHAR FT1248FlowControl; // FT1248 flow control enable + // Hardware options + UCHAR RS485EchoSuppress; // + UCHAR PowerSaveEnable; // + // Driver option + UCHAR DriverType; // + } FT_EEPROM_X_SERIES, *PFT_EEPROM_X_SERIES; + + + FTD2XX_API + FT_STATUS WINAPI FT_EEPROM_Read( + FT_HANDLE ftHandle, + void *eepromData, + DWORD eepromDataSize, + char *Manufacturer, + char *ManufacturerId, + char *Description, + char *SerialNumber + ); + + + FTD2XX_API + FT_STATUS WINAPI FT_EEPROM_Program( + FT_HANDLE ftHandle, + void *eepromData, + DWORD eepromDataSize, + char *Manufacturer, + char *ManufacturerId, + char *Description, + char *SerialNumber + ); + + + FTD2XX_API + FT_STATUS WINAPI FT_SetLatencyTimer( + FT_HANDLE ftHandle, + UCHAR ucLatency + ); + + FTD2XX_API + FT_STATUS WINAPI FT_GetLatencyTimer( + FT_HANDLE ftHandle, + PUCHAR pucLatency + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetBitMode( + FT_HANDLE ftHandle, + UCHAR ucMask, + UCHAR ucEnable + ); + + FTD2XX_API + FT_STATUS WINAPI FT_GetBitMode( + FT_HANDLE ftHandle, + PUCHAR pucMode + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetUSBParameters( + FT_HANDLE ftHandle, + ULONG ulInTransferSize, + ULONG ulOutTransferSize + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetDeadmanTimeout( + FT_HANDLE ftHandle, + ULONG ulDeadmanTimeout + ); + +#ifndef _WIN32 + // Extra functions for non-Windows platforms to compensate + // for lack of .INF file to specify Vendor and Product IDs. + + FTD2XX_API + FT_STATUS FT_SetVIDPID( + DWORD dwVID, + DWORD dwPID + ); + + FTD2XX_API + FT_STATUS FT_GetVIDPID( + DWORD * pdwVID, + DWORD * pdwPID + ); + + FTD2XX_API + FT_STATUS WINAPI FT_GetDeviceLocId( + FT_HANDLE ftHandle, + LPDWORD lpdwLocId + ); +#endif // _WIN32 + + FTD2XX_API + FT_STATUS WINAPI FT_GetDeviceInfo( + FT_HANDLE ftHandle, + FT_DEVICE *lpftDevice, + LPDWORD lpdwID, + PCHAR SerialNumber, + PCHAR Description, + LPVOID Dummy + ); + + FTD2XX_API + FT_STATUS WINAPI FT_StopInTask( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_RestartInTask( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_SetResetPipeRetryCount( + FT_HANDLE ftHandle, + DWORD dwCount + ); + + FTD2XX_API + FT_STATUS WINAPI FT_ResetPort( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_CyclePort( + FT_HANDLE ftHandle + ); + + + // + // Win32-type functions + // + + FTD2XX_API + FT_HANDLE WINAPI FT_W32_CreateFile( + LPCTSTR lpszName, + DWORD dwAccess, + DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreate, + DWORD dwAttrsAndFlags, + HANDLE hTemplate + ); + + FTD2XX_API + BOOL WINAPI FT_W32_CloseHandle( + FT_HANDLE ftHandle + ); + + FTD2XX_API + BOOL WINAPI FT_W32_ReadFile( + FT_HANDLE ftHandle, + LPVOID lpBuffer, + DWORD nBufferSize, + LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped + ); + + FTD2XX_API + BOOL WINAPI FT_W32_WriteFile( + FT_HANDLE ftHandle, + LPVOID lpBuffer, + DWORD nBufferSize, + LPDWORD lpBytesWritten, + LPOVERLAPPED lpOverlapped + ); + + FTD2XX_API + DWORD WINAPI FT_W32_GetLastError( + FT_HANDLE ftHandle + ); + + FTD2XX_API + BOOL WINAPI FT_W32_GetOverlappedResult( + FT_HANDLE ftHandle, + LPOVERLAPPED lpOverlapped, + LPDWORD lpdwBytesTransferred, + BOOL bWait + ); + + FTD2XX_API + BOOL WINAPI FT_W32_CancelIo( + FT_HANDLE ftHandle + ); + + + // + // Win32 COMM API type functions + // + typedef struct _FTCOMSTAT { + DWORD fCtsHold : 1; + DWORD fDsrHold : 1; + DWORD fRlsdHold : 1; + DWORD fXoffHold : 1; + DWORD fXoffSent : 1; + DWORD fEof : 1; + DWORD fTxim : 1; + DWORD fReserved : 25; + DWORD cbInQue; + DWORD cbOutQue; + } FTCOMSTAT, *LPFTCOMSTAT; + + typedef struct _FTDCB { + DWORD DCBlength; /* sizeof(FTDCB) */ + DWORD BaudRate; /* Baudrate at which running */ + DWORD fBinary: 1; /* Binary Mode (skip EOF check) */ + DWORD fParity: 1; /* Enable parity checking */ + DWORD fOutxCtsFlow:1; /* CTS handshaking on output */ + DWORD fOutxDsrFlow:1; /* DSR handshaking on output */ + DWORD fDtrControl:2; /* DTR Flow control */ + DWORD fDsrSensitivity:1; /* DSR Sensitivity */ + DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */ + DWORD fOutX: 1; /* Enable output X-ON/X-OFF */ + DWORD fInX: 1; /* Enable input X-ON/X-OFF */ + DWORD fErrorChar: 1; /* Enable Err Replacement */ + DWORD fNull: 1; /* Enable Null stripping */ + DWORD fRtsControl:2; /* Rts Flow control */ + DWORD fAbortOnError:1; /* Abort all reads and writes on Error */ + DWORD fDummy2:17; /* Reserved */ + WORD wReserved; /* Not currently used */ + WORD XonLim; /* Transmit X-ON threshold */ + WORD XoffLim; /* Transmit X-OFF threshold */ + BYTE ByteSize; /* Number of bits/byte, 4-8 */ + BYTE Parity; /* 0-4=None,Odd,Even,Mark,Space */ + BYTE StopBits; /* FT_STOP_BITS_1 or FT_STOP_BITS_2 */ + char XonChar; /* Tx and Rx X-ON character */ + char XoffChar; /* Tx and Rx X-OFF character */ + char ErrorChar; /* Error replacement char */ + char EofChar; /* End of Input character */ + char EvtChar; /* Received Event character */ + WORD wReserved1; /* Fill for now. */ + } FTDCB, *LPFTDCB; + + typedef struct _FTTIMEOUTS { + DWORD ReadIntervalTimeout; /* Maximum time between read chars. */ + DWORD ReadTotalTimeoutMultiplier; /* Multiplier of characters. */ + DWORD ReadTotalTimeoutConstant; /* Constant in milliseconds. */ + DWORD WriteTotalTimeoutMultiplier; /* Multiplier of characters. */ + DWORD WriteTotalTimeoutConstant; /* Constant in milliseconds. */ + } FTTIMEOUTS,*LPFTTIMEOUTS; + + + FTD2XX_API + BOOL WINAPI FT_W32_ClearCommBreak( + FT_HANDLE ftHandle + ); + + FTD2XX_API + BOOL WINAPI FT_W32_ClearCommError( + FT_HANDLE ftHandle, + LPDWORD lpdwErrors, + LPFTCOMSTAT lpftComstat + ); + + FTD2XX_API + BOOL WINAPI FT_W32_EscapeCommFunction( + FT_HANDLE ftHandle, + DWORD dwFunc + ); + + FTD2XX_API + BOOL WINAPI FT_W32_GetCommModemStatus( + FT_HANDLE ftHandle, + LPDWORD lpdwModemStatus + ); + + FTD2XX_API + BOOL WINAPI FT_W32_GetCommState( + FT_HANDLE ftHandle, + LPFTDCB lpftDcb + ); + + FTD2XX_API + BOOL WINAPI FT_W32_GetCommTimeouts( + FT_HANDLE ftHandle, + FTTIMEOUTS *pTimeouts + ); + + FTD2XX_API + BOOL WINAPI FT_W32_PurgeComm( + FT_HANDLE ftHandle, + DWORD dwMask + ); + + FTD2XX_API + BOOL WINAPI FT_W32_SetCommBreak( + FT_HANDLE ftHandle + ); + + FTD2XX_API + BOOL WINAPI FT_W32_SetCommMask( + FT_HANDLE ftHandle, + ULONG ulEventMask + ); + + FTD2XX_API + BOOL WINAPI FT_W32_GetCommMask( + FT_HANDLE ftHandle, + LPDWORD lpdwEventMask + ); + + FTD2XX_API + BOOL WINAPI FT_W32_SetCommState( + FT_HANDLE ftHandle, + LPFTDCB lpftDcb + ); + + FTD2XX_API + BOOL WINAPI FT_W32_SetCommTimeouts( + FT_HANDLE ftHandle, + FTTIMEOUTS *pTimeouts + ); + + FTD2XX_API + BOOL WINAPI FT_W32_SetupComm( + FT_HANDLE ftHandle, + DWORD dwReadBufferSize, + DWORD dwWriteBufferSize + ); + + FTD2XX_API + BOOL WINAPI FT_W32_WaitCommEvent( + FT_HANDLE ftHandle, + PULONG pulEvent, + LPOVERLAPPED lpOverlapped + ); + + + // + // Device information + // + + typedef struct _ft_device_list_info_node { + ULONG Flags; + ULONG Type; + ULONG ID; + DWORD LocId; + char SerialNumber[16]; + char Description[64]; + FT_HANDLE ftHandle; + } FT_DEVICE_LIST_INFO_NODE; + + // Device information flags + enum { + FT_FLAGS_OPENED = 1, + FT_FLAGS_HISPEED = 2 + }; + + + FTD2XX_API + FT_STATUS WINAPI FT_CreateDeviceInfoList( + LPDWORD lpdwNumDevs + ); + + FTD2XX_API + FT_STATUS WINAPI FT_GetDeviceInfoList( + FT_DEVICE_LIST_INFO_NODE *pDest, + LPDWORD lpdwNumDevs + ); + + FTD2XX_API + FT_STATUS WINAPI FT_GetDeviceInfoDetail( + DWORD dwIndex, + LPDWORD lpdwFlags, + LPDWORD lpdwType, + LPDWORD lpdwID, + LPDWORD lpdwLocId, + LPVOID lpSerialNumber, + LPVOID lpDescription, + FT_HANDLE *pftHandle + ); + + + // + // Version information + // + + FTD2XX_API + FT_STATUS WINAPI FT_GetDriverVersion( + FT_HANDLE ftHandle, + LPDWORD lpdwVersion + ); + + FTD2XX_API + FT_STATUS WINAPI FT_GetLibraryVersion( + LPDWORD lpdwVersion + ); + + + FTD2XX_API + FT_STATUS WINAPI FT_Rescan( + void + ); + + FTD2XX_API + FT_STATUS WINAPI FT_Reload( + WORD wVid, + WORD wPid + ); + + FTD2XX_API + FT_STATUS WINAPI FT_GetComPortNumber( + FT_HANDLE ftHandle, + LPLONG lpdwComPortNumber + ); + + + // + // FT232H additional EEPROM functions + // + + FTD2XX_API + FT_STATUS WINAPI FT_EE_ReadConfig( + FT_HANDLE ftHandle, + UCHAR ucAddress, + PUCHAR pucValue + ); + + FTD2XX_API + FT_STATUS WINAPI FT_EE_WriteConfig( + FT_HANDLE ftHandle, + UCHAR ucAddress, + UCHAR ucValue + ); + + FTD2XX_API + FT_STATUS WINAPI FT_EE_ReadECC( + FT_HANDLE ftHandle, + UCHAR ucOption, + LPWORD lpwValue + ); + + FTD2XX_API + FT_STATUS WINAPI FT_GetQueueStatusEx( + FT_HANDLE ftHandle, + DWORD *dwRxBytes + ); + + FTD2XX_API + FT_STATUS WINAPI FT_ComPortIdle( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_ComPortCancelIdle( + FT_HANDLE ftHandle + ); + + FTD2XX_API + FT_STATUS WINAPI FT_VendorCmdGet( + FT_HANDLE ftHandle, + UCHAR Request, + UCHAR *Buf, + USHORT Len + ); + + FTD2XX_API + FT_STATUS WINAPI FT_VendorCmdSet( + FT_HANDLE ftHandle, + UCHAR Request, + UCHAR *Buf, + USHORT Len + ); + + FTD2XX_API + FT_STATUS WINAPI FT_VendorCmdGetEx( + FT_HANDLE ftHandle, + USHORT wValue, + UCHAR *Buf, + USHORT Len + ); + + FTD2XX_API + FT_STATUS WINAPI FT_VendorCmdSetEx( + FT_HANDLE ftHandle, + USHORT wValue, + UCHAR *Buf, + USHORT Len + ); + +#ifdef __cplusplus +} +#endif + + +#endif /* FTD2XX_H */ + diff --git a/alchitry-loader/src/jtag.cpp b/alchitry-loader/src/jtag.cpp new file mode 100644 index 0000000..74751af --- /dev/null +++ b/alchitry-loader/src/jtag.cpp @@ -0,0 +1,781 @@ +/* + * jtag.cpp + * + * Created on: May 24, 2017 + * Author: justin + */ + +#include "jtag.h" +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include "mingw.thread.h" +#else +#include +#endif + +#include + +using namespace std; + +Jtag::Jtag() { + ftHandle = 0; + active = false; +} + +FT_STATUS Jtag::connect(unsigned int devNumber) { + return FT_Open(devNumber, &ftHandle); +} + +FT_STATUS Jtag::disconnect() { + active = false; + return FT_Close(ftHandle); +} + +bool Jtag::initialize() { + BYTE byInputBuffer[1024]; // Buffer to hold data read from the FT2232H + DWORD dwNumBytesToRead = 0; // Number of bytes available to read in the driver's input buffer + DWORD dwNumBytesRead = 0; // Count of actual bytes read - used with FT_Read + FT_STATUS ftStatus; + ftStatus = FT_ResetDevice(ftHandle); + //Reset USB device + //Purge USB receive buffer first by reading out all old data from FT2232H receive buffer + ftStatus |= FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); // Get the number of bytes in the FT2232H receive buffer + if ((ftStatus == FT_OK) && (dwNumBytesToRead > 0)) + FT_Read(ftHandle, &byInputBuffer, dwNumBytesToRead, &dwNumBytesRead);//Read out the data from FT2232H receive buffer + ftStatus |= FT_SetUSBParameters(ftHandle, 65536, 65535);//Set USB request transfer sizes to 64K + ftStatus |= FT_SetChars(ftHandle, false, 0, false, 0); //Disable event and error characters + ftStatus |= FT_SetTimeouts(ftHandle, 0, 5000); //Sets the read and write timeouts in milliseconds + ftStatus |= FT_SetLatencyTimer(ftHandle, 16); //Set the latency timer (default is 16mS) + ftStatus |= FT_SetBitMode(ftHandle, 0x0, 0x00); //Reset controller + ftStatus |= FT_SetBitMode(ftHandle, 0x0, 0x02); //Enable MPSSE mode + + if (ftStatus != FT_OK) { + cerr << "Failed to set initial configuration!" << endl; + return false; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Wait for all the USB stuff to complete and work + + if (!sync_mpsse()) { + cerr << "Failed to sync with MPSSE!" << endl; + return false; + } + + if (!config_jtag()) { + cerr << "Failed to set JTAG configuration!" << endl; + return false; + } + + active = true; + + return true; +} + +bool Jtag::sync_mpsse() { + BYTE byOutputBuffer[8]; // Buffer to hold MPSSE commands and data to be sent to the FT2232H + BYTE byInputBuffer[8]; // Buffer to hold data read from the FT2232H + DWORD dwCount = 0; // General loop index + DWORD dwNumBytesToSend = 0; // Index to the output buffer + DWORD dwNumBytesSent = 0; // Count of actual bytes sent - used with FT_Write + DWORD dwNumBytesToRead = 0; // Number of bytes available to read in the driver's input buffer + DWORD dwNumBytesRead = 0; // Count of actual bytes read - used with FT_Read + FT_STATUS ftStatus; + + byOutputBuffer[dwNumBytesToSend++] = 0xAA; //'\xAA'; + //Add bogus command ‘xAA’ to the queue + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + if (ftStatus != FT_OK) + cerr << "Failed to send bad command" << endl; + // Send off the BAD commands + dwNumBytesToSend = 0; // Reset output buffer pointer + do { + ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); + if (ftStatus != FT_OK) + cerr << "Failed to get queue status " << ftStatus << endl; + // Get the number of bytes in the device input buffer + } while ((dwNumBytesToRead == 0) && (ftStatus == FT_OK)); + if (dwNumBytesRead > 8) { + cerr << "Input buffer too small in sync_mpsse()!" << endl; + return false; + } + //or Timeout + bool bCommandEchod = false; + ftStatus = FT_Read(ftHandle, &byInputBuffer, dwNumBytesToRead, + &dwNumBytesRead); + + if (ftStatus != FT_OK) + cerr << "Failed to read data" << endl; + + //Read out the data from input buffer + for (dwCount = 0; dwCount < dwNumBytesRead - 1; dwCount++) + //Check if Bad command and echo command received + { + if ((byInputBuffer[dwCount] == 0xFA) + && (byInputBuffer[dwCount + 1] == 0xAA)) { + bCommandEchod = true; + break; + } + } + + return bCommandEchod; +} + +bool Jtag::config_jtag() { + FT_STATUS ftStatus; + BYTE byOutputBuffer[64]; // Buffer to hold MPSSE commands and data to be sent to the FT2232H + DWORD dwNumBytesToSend = 0; // Index to the output buffer + DWORD dwNumBytesSent = 0; // Count of actual bytes sent - used with FT_Write + DWORD dwClockDivisor = 0x05DB; // Value of clock divisor, SCL Frequency = 60/((1+0x05DB)*2) (MHz) = 20khz + // ----------------------------------------------------------- + // Configure the MPSSE settings for JTAG + // Multiple commands can be sent to the MPSSE with one FT_Write + // ----------------------------------------------------------- + dwNumBytesToSend = 0; // Start with a fresh index + // Set up the Hi-Speed specific commands for the FTx232H + byOutputBuffer[dwNumBytesToSend++] = 0x8A; + // Use 60MHz master clock (disable divide by 5) + byOutputBuffer[dwNumBytesToSend++] = 0x97; + // Turn off adaptive clocking (may be needed for ARM) + byOutputBuffer[dwNumBytesToSend++] = 0x8D; + // Disable three-phase clocking + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + // Send off the HS-specific commands + + if (ftStatus != FT_OK) + return false; + + dwNumBytesToSend = 0; // Reset output buffer pointer + // Set initial states of the MPSSE interface - low byte, both pin directions and output values + // Pin name Signal Direction Config Initial State Config + // ADBUS0 TCK output 1 low 0 + // ADBUS1 TDI output 1 low 0 + // ADBUS2 TDO input 0 0 + // ADBUS3 TMS output 1 high 1 + // ADBUS4 GPIOL0 input 0 0 + // ADBUS5 GPIOL1 input 0 0 + // ADBUS6 GPIOL2 input 0 0 + // ADBUS7 GPIOL3 input 0 0 + byOutputBuffer[dwNumBytesToSend++] = 0x80; + // Set data bits low-byte of MPSSE port + byOutputBuffer[dwNumBytesToSend++] = 0x08; + // Initial state config above + byOutputBuffer[dwNumBytesToSend++] = 0x0B; + // Direction config above + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + // Send off the low GPIO config commands + + if (ftStatus != FT_OK) + return false; + + dwNumBytesToSend = 0; // Reset output buffer pointer + // Set initial states of the MPSSE interface - high byte, both pin directions and output values + // Pin name Signal Direction Config Initial State Config + // ACBUS0 GPIOH0 input 0 0 + // ACBUS1 GPIOH1 input 0 0 + // ACBUS2 GPIOH2 input 0 0 + // ACBUS3 GPIOH3 input 0 0 + // ACBUS4 GPIOH4 input 0 0 + // ACBUS5 GPIOH5 input 0 0 + // ACBUS6 GPIOH6 input 0 0 + // ACBUS7 GPIOH7 input 0 0 + byOutputBuffer[dwNumBytesToSend++] = 0x82; + // Set data bits low-byte of MPSSE port + byOutputBuffer[dwNumBytesToSend++] = 0x00; + // Initial state config above + byOutputBuffer[dwNumBytesToSend++] = 0x00; + // Direction config above + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + // Send off the high GPIO config commands + + if (ftStatus != FT_OK) + return false; + + dwNumBytesToSend = 0; // Reset output buffer pointer + // Set TCK frequency + // TCK = 60MHz /((1 + [(1 +0xValueH*256) OR 0xValueL])*2) + byOutputBuffer[dwNumBytesToSend++] = 0x86; + //Command to set clock divisor + byOutputBuffer[dwNumBytesToSend++] = dwClockDivisor & 0xFF; + //Set 0xValueL of clock divisor + byOutputBuffer[dwNumBytesToSend++] = (dwClockDivisor >> 8) & 0xFF; + //Set 0xValueH of clock divisor + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + // Send off the clock divisor commands + + if (ftStatus != FT_OK) + return false; + + dwNumBytesToSend = 0; // Reset output buffer pointer + // Disable internal loop-back + byOutputBuffer[dwNumBytesToSend++] = 0x85; + // Disable loopback + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + // Send off the loopback command + + if (ftStatus != FT_OK) + return false; + + return true; +} + +bool Jtag::setFreq(double freq) { + if (!active) { + cerr + << "Jtag must be connected and initialized before calling setFreq()!" + << endl; + return false; + } + FT_STATUS ftStatus; + BYTE byOutputBuffer[8]; // Buffer to hold MPSSE commands and data to be sent to the FT2232H + DWORD dwNumBytesToSend = 0; // Index to the output buffer + DWORD dwNumBytesSent = 0; // Count of actual bytes sent - used with FT_Write + DWORD dwClockDivisor; // Value of clock divisor, SCL Frequency = 60/((1+clkDiv)*2) (MHz) + + dwClockDivisor = 30.0 / (freq / 1000000.0) - 1.0; + + // Set TCK frequency + // TCK = 60MHz /((1 + [(1 +0xValueH*256) OR 0xValueL])*2) + byOutputBuffer[dwNumBytesToSend++] = 0x86; + //Command to set clock divisor + byOutputBuffer[dwNumBytesToSend++] = dwClockDivisor & 0xFF; + //Set 0xValueL of clock divisor + byOutputBuffer[dwNumBytesToSend++] = (dwClockDivisor >> 8) & 0xFF; + //Set 0xValueH of clock divisor + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + // Send off the clock divisor commands + + if (ftStatus != FT_OK) + return false; + return true; +} + +bool Jtag::navigateToState(Jtag_fsm::State init, Jtag_fsm::State dest) { + FT_STATUS ftStatus; + BYTE byOutputBuffer[3]; // Buffer to hold MPSSE commands and data to be sent to the FT2232H + DWORD dwNumBytesSent = 0; // Count of actual bytes sent - used with FT_Write + + Jtag_fsm::Transistions transistions = Jtag_fsm::getTransitions(init, dest); + + if (transistions.moves > 0) { + if (transistions.moves < 8) { + byOutputBuffer[0] = 0x4B; + byOutputBuffer[1] = transistions.moves - 1; + byOutputBuffer[2] = 0x7f & transistions.tms; + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3, &dwNumBytesSent); + if (ftStatus != FT_OK) + return false; + } else { + cout << "Transition of 8 moves!" << endl; + byOutputBuffer[0] = 0x4B; + byOutputBuffer[1] = 6; + byOutputBuffer[2] = 0x7f & transistions.tms; + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3, &dwNumBytesSent); + if (ftStatus != FT_OK) + return false; + byOutputBuffer[0] = 0x4B; + byOutputBuffer[1] = transistions.moves - 8; + byOutputBuffer[2] = 0x7f & (transistions.tms >> 7); + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3, &dwNumBytesSent); + if (ftStatus != FT_OK) + return false; + } + } + return true; +} + +bool Jtag::shiftData(unsigned int bitCount, string tdi, string tdo, + string mask) { + FT_STATUS ftStatus; + unsigned int reqBytes = bitCount / 8 + (bitCount % 8 > 0); + BYTE *byOutputBuffer = new BYTE[reqBytes + 3]; + BYTE *tdoBuffer = new BYTE[reqBytes + 3]; + BYTE *byInputBuffer = new BYTE[reqBytes + 6]; + DWORD dwNumBytesSent = 0; + DWORD dwNumBytesToRead = 0; + DWORD dwNumBytesRead = 0; + DWORD tdoBytes = 0; + + unsigned int reqHex = bitCount / 4 + (bitCount % 4 > 0); + + if (tdi.length() < reqHex) + return false; + bool read = tdo != ""; + if (read) { + if (tdo.length() < reqHex) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + return false; + } + if (mask != "" && mask.length() < reqHex) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + return false; + } + } + + if (!flush()) + return false; + + if (bitCount < 9) { + int data = stoi(tdi, 0, 16); + byOutputBuffer[0] = read ? 0x3B : 0x1B; + byOutputBuffer[1] = bitCount - 2; + byOutputBuffer[2] = data & 0xff; + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3, &dwNumBytesSent); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + return false; + } + + BYTE lastBit = (data >> ((bitCount - 1) % 8)) & 0x01; + + byOutputBuffer[0] = read ? 0x6E : 0x4E; + byOutputBuffer[1] = 0x00; + byOutputBuffer[2] = 0x03 | (lastBit << 7); + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3, &dwNumBytesSent); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + return false; + } + + if (read) { + do { + ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); + // Get the number of bytes in the device input buffer + } while ((dwNumBytesToRead == 0) && (ftStatus == FT_OK)); + //or Timeout + ftStatus = FT_Read(ftHandle, byInputBuffer, dwNumBytesToRead, + &dwNumBytesRead); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + return false; + } + + tdoBuffer[0] = byInputBuffer[0] >> (8 - (bitCount - 1)); + tdoBuffer[0] |= byInputBuffer[1] >> (7 - (bitCount - 1)); + tdoBytes = 1; + } + } else { + BYTE *tdiBytes = new BYTE[reqBytes + 1]; + hexToByte(tdi, tdiBytes); + + unsigned int fullBytes = (bitCount - 1) / 8; + unsigned int remBytes = fullBytes; + unsigned int offset = 0; + + if (fullBytes > 65536 && read) { + cout << "Large transfers with reads may not work!" << endl; + } + + while (remBytes > 0) { + unsigned int bct = remBytes > 65536 ? 65536 : remBytes; + byOutputBuffer[0] = read ? 0x39 : 0x19; + byOutputBuffer[1] = (bct - 1) & 0xff; + byOutputBuffer[2] = ((bct - 1) >> 8) & 0xff; + + for (unsigned int i = 0; i < bct; i++) { + byOutputBuffer[3 + i] = tdiBytes[i + offset]; + } + + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3 + bct, + &dwNumBytesSent); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + delete tdiBytes; + return false; + } + + remBytes -= bct; + offset += bct; + } + + unsigned int partialBits = bitCount - 1 - (fullBytes * 8); + + if (fullBytes * 8 + 1 != bitCount) { + byOutputBuffer[0] = read ? 0x3B : 0x1B; + byOutputBuffer[1] = partialBits - 1; + byOutputBuffer[2] = tdiBytes[reqBytes - 1] & 0xff; + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3, &dwNumBytesSent); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + delete tdiBytes; + return false; + } + } + + BYTE lastBit = (tdiBytes[reqBytes - 1] >> ((bitCount - 1) % 8)) & 0x01; + + byOutputBuffer[0] = read ? 0x6E : 0x4E; + byOutputBuffer[1] = 0x00; + byOutputBuffer[2] = 0x03 | (lastBit << 7); + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3, &dwNumBytesSent); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + delete tdiBytes; + return false; + } + + if (read) { + DWORD bytesToRead = fullBytes + + ((fullBytes * 8 + 1 != bitCount) ? 2 : 1); + do { + ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); + // Get the number of bytes in the device input buffer + } while ((dwNumBytesToRead != bytesToRead) && (ftStatus == FT_OK)); + //or Timeout + ftStatus = FT_Read(ftHandle, byInputBuffer, dwNumBytesToRead, + &dwNumBytesRead); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + delete tdiBytes; + return false; + } + + for (unsigned int i = 0; i < fullBytes; i++) + tdoBuffer[tdoBytes++] = byInputBuffer[i]; + + if (fullBytes * 8 + 1 != bitCount) { + tdoBuffer[tdoBytes] = byInputBuffer[tdoBytes] + >> (8 - partialBits); + tdoBuffer[tdoBytes++] |= byInputBuffer[dwNumBytesRead - 1] + >> (7 - partialBits); + } else { + tdoBuffer[tdoBytes++] = byInputBuffer[dwNumBytesRead - 1] >> 7; + } + } + + delete tdiBytes; + } + + if (read) { + //Read out the data from input buffer + std::stringstream ss; + for (int i = tdoBytes - 1; i >= 0; i--) + ss << setfill('0') << setw(2) << hex << (int) tdoBuffer[i]; + string hexTdo = ss.str(); + if (hexTdo.length() - 1 == mask.length()) + hexTdo = hexTdo.substr(1, hexTdo.length() - 1); + if (!compareHexString(hexTdo, tdo, mask)) { + cerr << "TDO didn't match expected string. Got " << hexTdo + << " expected " << tdo << " with mask " << mask << endl; + + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + return false; + + } + } + + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + return true; +} + +string Jtag::shiftData(unsigned int bitCount, string tdi) { + FT_STATUS ftStatus; + unsigned int reqBytes = bitCount / 8 + (bitCount % 8 > 0); + BYTE *byOutputBuffer = new BYTE[reqBytes + 3]; + BYTE *tdoBuffer = new BYTE[reqBytes + 3]; + BYTE *byInputBuffer = new BYTE[reqBytes + 6]; + DWORD dwNumBytesSent = 0; + DWORD dwNumBytesToRead = 0; + DWORD dwNumBytesRead = 0; + DWORD tdoBytes = 0; + + unsigned int reqHex = bitCount / 4 + (bitCount % 4 > 0); + + if (tdi.length() < reqHex) + return ""; + + if (!flush()) + return ""; + + if (bitCount < 9) { + int data = stoi(tdi, 0, 16); + byOutputBuffer[0] = 0x3B; + byOutputBuffer[1] = bitCount - 2; + byOutputBuffer[2] = data & 0xff; + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3, &dwNumBytesSent); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + return ""; + } + + BYTE lastBit = (data >> ((bitCount - 1) % 8)) & 0x01; + + byOutputBuffer[0] = 0x6E; + byOutputBuffer[1] = 0x00; + byOutputBuffer[2] = 0x03 | (lastBit << 7); + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3, &dwNumBytesSent); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + return ""; + } + + do { + ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); + // Get the number of bytes in the device input buffer + } while ((dwNumBytesToRead == 0) && (ftStatus == FT_OK)); + //or Timeout + ftStatus = FT_Read(ftHandle, byInputBuffer, dwNumBytesToRead, + &dwNumBytesRead); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + return ""; + } + + tdoBuffer[0] = byInputBuffer[0] >> (8 - (bitCount - 1)); + tdoBuffer[0] |= byInputBuffer[1] >> (7 - (bitCount - 1)); + tdoBytes = 1; + + } else { + BYTE *tdiBytes = new BYTE[reqBytes + 1]; + hexToByte(tdi, tdiBytes); + + unsigned int fullBytes = (bitCount - 1) / 8; + unsigned int remBytes = fullBytes; + unsigned int offset = 0; + + if (fullBytes > 65536) { + cout << "Large transfers with reads may not work!" << endl; + } + + while (remBytes > 0) { + unsigned int bct = remBytes > 65536 ? 65536 : remBytes; + byOutputBuffer[0] = 0x39; + byOutputBuffer[1] = (bct - 1) & 0xff; + byOutputBuffer[2] = ((bct - 1) >> 8) & 0xff; + + for (unsigned int i = 0; i < bct; i++) { + byOutputBuffer[3 + i] = tdiBytes[i + offset]; + } + + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3 + bct, + &dwNumBytesSent); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + delete tdiBytes; + return ""; + } + + remBytes -= bct; + offset += bct; + } + + unsigned int partialBits = bitCount - 1 - (fullBytes * 8); + + if (fullBytes * 8 + 1 != bitCount) { + byOutputBuffer[0] = 0x3B; + byOutputBuffer[1] = partialBits - 1; + byOutputBuffer[2] = tdiBytes[reqBytes - 1] & 0xff; + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3, &dwNumBytesSent); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + delete tdiBytes; + return ""; + } + } + + BYTE lastBit = (tdiBytes[reqBytes - 1] >> ((bitCount - 1) % 8)) & 0x01; + + byOutputBuffer[0] = 0x6E; + byOutputBuffer[1] = 0x00; + byOutputBuffer[2] = 0x03 | (lastBit << 7); + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3, &dwNumBytesSent); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + delete tdiBytes; + return ""; + } + + DWORD bytesToRead = fullBytes + + ((fullBytes * 8 + 1 != bitCount) ? 2 : 1); + do { + ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); + // Get the number of bytes in the device input buffer + } while ((dwNumBytesToRead != bytesToRead) && (ftStatus == FT_OK)); + //or Timeout + ftStatus = FT_Read(ftHandle, byInputBuffer, dwNumBytesToRead, + &dwNumBytesRead); + if (ftStatus != FT_OK) { + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + delete tdiBytes; + return ""; + } + + for (unsigned int i = 0; i < fullBytes; i++) + tdoBuffer[tdoBytes++] = byInputBuffer[i]; + + if (fullBytes * 8 + 1 != bitCount) { + tdoBuffer[tdoBytes] = byInputBuffer[tdoBytes] >> (8 - partialBits); + tdoBuffer[tdoBytes++] |= byInputBuffer[dwNumBytesRead - 1] + >> (7 - partialBits); + } else { + tdoBuffer[tdoBytes++] = byInputBuffer[dwNumBytesRead - 1] >> 7; + } + + delete tdiBytes; + } + + //Read out the data from input buffer + std::stringstream ss; + for (int i = tdoBytes - 1; i >= 0; i--) + ss << setfill('0') << setw(2) << hex << (int) tdoBuffer[i]; + string hexTdo = ss.str(); + if (hexTdo.length() - 1 == tdi.length()) + hexTdo = hexTdo.substr(1, hexTdo.length() - 1); + + delete byOutputBuffer; + delete tdoBuffer; + delete byInputBuffer; + return hexTdo; +} + +bool Jtag::sendClocks(unsigned long cycles) { + BYTE byOutputBuffer[3]; + DWORD dwNumBytesSent; + FT_STATUS ftStatus; + + if (cycles / 8 > 65536) { + if (!sendClocks(cycles - 65536 * 8)) + return false; + cycles = 65536 * 8; + } + + cycles /= 8; + + byOutputBuffer[0] = 0x8F; + byOutputBuffer[1] = (cycles - 1) & 0xff; + byOutputBuffer[2] = ((cycles - 1) >> 8) & 0xff; + ftStatus = FT_Write(ftHandle, byOutputBuffer, 3, &dwNumBytesSent); + if (ftStatus != FT_OK) + return false; + + return true; +} + +bool Jtag::compareHexString(string a, string b, string mask) { + unsigned int length = a.length(); + + if (length != b.length()) { + cout << "length mismatch!" << endl; + return false; + } + + if (mask == "") + return a == b; + + if (length != mask.length()) { + cout << "length and mask mismatch! " << length << " and " + << mask.length() << " of strings " << a << " and " << mask + << endl; + return false; + } + + for (unsigned int i = 0; i < length / 2; i++) { + BYTE m = stoi(mask.substr(length - 2 - i * 2, 2), 0, 16); + BYTE pa = stoi(a.substr(length - 2 - i * 2, 2), 0, 16); + BYTE pb = stoi(b.substr(length - 2 - i * 2, 2), 0, 16); + if ((pa & m) != (pb & m)) { + cout << "Mismatch at " << i << endl; + return false; + } + + } + if ((length & 1) != 0) { + BYTE m = stoi(mask.substr(0, 1), 0, 16); + BYTE pa = stoi(a.substr(0, 1), 0, 16); + BYTE pb = stoi(b.substr(0, 1), 0, 16); + if ((pa & m) != (pb & m)) { + cout << "Mismatch at last bit" << endl; + return false; + } + } + + return true; +} + +void Jtag::hexToByte(string hex, BYTE* out) { + int length = hex.length(); + for (int i = 0; i < length / 2; i++) { + try { + out[i] = stoi(hex.substr(length - 2 - i * 2, 2), 0, 16); + } catch (exception& e) { + cerr << "Failed at " << i << " with length " << length << endl; + cerr.flush(); + exit(2); + } + } + if ((length & 1) != 0) + try { + out[length / 2] = stoi(hex.substr(0, 1), 0, 16); + } catch (exception& e) { + cerr << "Failed to convert string " << hex.substr(0, 1) + << " to an int!" << endl; + cerr.flush(); + exit(2); + } +} + +bool Jtag::flush() { + FT_STATUS ftStatus; + BYTE byInputBuffer[1024]; + DWORD dwNumBytesToRead = 0; + DWORD dwNumBytesRead = 0; + + ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); + if (ftStatus != FT_OK) + return false; + if (dwNumBytesToRead == 0) + return true; + +//or Timeout + ftStatus = FT_Read(ftHandle, &byInputBuffer, dwNumBytesToRead, + &dwNumBytesRead); + if (ftStatus != FT_OK) + return false; + return true; +} diff --git a/alchitry-loader/src/jtag.h b/alchitry-loader/src/jtag.h new file mode 100644 index 0000000..823214e --- /dev/null +++ b/alchitry-loader/src/jtag.h @@ -0,0 +1,40 @@ +/* + * jtag.h + * + * Created on: May 24, 2017 + * Author: justin + */ + +#ifndef JTAG_H_ +#define JTAG_H_ + +#include "ftd2xx.h" +#include "jtag_fsm.h" +#include + +class Jtag { + FT_HANDLE ftHandle; + unsigned int uiDevIndex = 0xF; // The device in the list that is used + bool active; + +public: + Jtag(); + FT_STATUS connect(unsigned int); + FT_STATUS disconnect(); + bool initialize(); + bool setFreq(double); + bool navigateToState(Jtag_fsm::State, Jtag_fsm::State); + bool shiftData(unsigned int, string, string, string); + string shiftData(unsigned int, string); + bool sendClocks(unsigned long); + +private: + bool sync_mpsse(); + bool config_jtag(); + static void hexToByte(string, BYTE*); + bool flush(); + bool compareHexString(string, string, string); + +}; + +#endif /* JTAG_H_ */ diff --git a/alchitry-loader/src/jtag_fsm.cpp b/alchitry-loader/src/jtag_fsm.cpp new file mode 100644 index 0000000..1289d9c --- /dev/null +++ b/alchitry-loader/src/jtag_fsm.cpp @@ -0,0 +1,119 @@ +/* + * jtag_fsm.cpp + * + * Created on: May 24, 2017 + * Author: justin + */ + +#include "jtag_fsm.h" +#include +#include + +using namespace std; + +Jtag_fsm::State Jtag_fsm::getTransition(State state, bool tms) { + switch (state) { + case TEST_LOGIC_RESET: + return tms ? TEST_LOGIC_RESET : RUN_TEST_IDLE; + case RUN_TEST_IDLE: + return tms ? SELECT_DR_SCAN : RUN_TEST_IDLE; + case SELECT_DR_SCAN: + return tms ? SELECT_IR_SCAN : CAPTURE_DR; + case CAPTURE_DR: + return tms ? EXIT1_DR : SHIFT_DR; + case SHIFT_DR: + return tms ? EXIT1_DR : SHIFT_DR; + case EXIT1_DR: + return tms ? UPDATE_DR : PAUSE_DR; + case PAUSE_DR: + return tms ? EXIT2_DR : PAUSE_DR; + case EXIT2_DR: + return tms ? UPDATE_DR : SHIFT_DR; + case UPDATE_DR: + return tms ? SELECT_DR_SCAN : RUN_TEST_IDLE; + case SELECT_IR_SCAN: + return tms ? TEST_LOGIC_RESET : CAPTURE_IR; + case CAPTURE_IR: + return tms ? EXIT1_IR : SHIFT_IR; + case SHIFT_IR: + return tms ? EXIT1_IR : SHIFT_IR; + case EXIT1_IR: + return tms ? UPDATE_IR : PAUSE_IR; + case PAUSE_IR: + return tms ? EXIT2_IR : PAUSE_IR; + case EXIT2_IR: + return tms ? UPDATE_IR : SHIFT_IR; + case UPDATE_IR: + return tms ? SELECT_DR_SCAN : RUN_TEST_IDLE; + } + + return TEST_LOGIC_RESET; +} + +Jtag_fsm::Transistions Jtag_fsm::getTransitions(State init, State final) { + queue queue; + Transistions t; + t.currentState = init; + t.moves = 0; + t.tms = 0; + queue.push(t); + while (!queue.empty()) { + t = queue.front(); + queue.pop(); + if (t.currentState == final) { + break; + } + + State s0 = getTransition(t.currentState, false); + State s1 = getTransition(t.currentState, true); + + t.moves++; + t.tms &= ~(1 << (t.moves-1)); // clear bit + t.currentState = s0; + queue.push(t); + + t.tms |= (1 << (t.moves-1)); + t.currentState = s1; + queue.push(t); + } + + return t; +} + +Jtag_fsm::State Jtag_fsm::getStateFromName(string s) { + if (s == "RESET") + return TEST_LOGIC_RESET; + if (s == "IDLE") + return RUN_TEST_IDLE; + if (s == "DRSELECT") + return SELECT_DR_SCAN; + if (s == "DRCAPTURE") + return CAPTURE_DR; + if (s == "DRSHIFT") + return SHIFT_DR; + if (s == "DREXIT1") + return EXIT1_DR; + if (s == "DRPAUSE") + return PAUSE_DR; + if (s == "DREXIT2") + return EXIT2_DR; + if (s == "DRUPDATE") + return UPDATE_DR; + if (s == "IRSELECT") + return SELECT_IR_SCAN; + if (s == "IRCAPTURE") + return CAPTURE_IR; + if (s == "IRSHIFT") + return SHIFT_IR; + if (s == "IREXIT1") + return EXIT1_IR; + if (s == "IRPAUSE") + return PAUSE_IR; + if (s == "IREXIT2") + return EXIT2_IR; + if (s == "IRUPDATE") + return UPDATE_IR; + + cerr << "ERROR! Invalid state name " << s << endl; + return TEST_LOGIC_RESET; +} diff --git a/alchitry-loader/src/jtag_fsm.h b/alchitry-loader/src/jtag_fsm.h new file mode 100644 index 0000000..094154a --- /dev/null +++ b/alchitry-loader/src/jtag_fsm.h @@ -0,0 +1,52 @@ +/* + * jtag_fsm.h + * + * Created on: May 24, 2017 + * Author: justin + */ + +#ifndef JTAG_FSM_H_ +#define JTAG_FSM_H_ + +#include +#include + +using namespace std; + +class Jtag_fsm { +public: + enum State { + TEST_LOGIC_RESET, + RUN_TEST_IDLE, + SELECT_DR_SCAN, + CAPTURE_DR, + SHIFT_DR, + EXIT1_DR, + PAUSE_DR, + EXIT2_DR, + UPDATE_DR, + SELECT_IR_SCAN, + CAPTURE_IR, + SHIFT_IR, + EXIT1_IR, + PAUSE_IR, + EXIT2_IR, + UPDATE_IR + }; + class Transistions { + public: + State currentState; + uint8_t tms; + uint8_t moves; + }; + + static Transistions getTransitions(State, State); + static State getStateFromName(string); + + +private: + static State getTransition(State, bool); + +}; + +#endif /* JTAG_FSM_H_ */ diff --git a/alchitry-loader/src/loader.cpp b/alchitry-loader/src/loader.cpp new file mode 100644 index 0000000..b6ac849 --- /dev/null +++ b/alchitry-loader/src/loader.cpp @@ -0,0 +1,388 @@ +/* + * Loader.cpp + * + * Created on: Nov 6, 2017 + * Author: justin + */ + +#include "loader.h" +#include "jtag.h" +#include +#include +#include +#include +#include +#include +#include "config_type.h" +#ifdef _WIN32 +#include "mingw.thread.h" +#else +#include +#endif + + +using namespace std; + +Loader::Loader(Jtag *dev) { + device = dev; + currentState = Jtag_fsm::TEST_LOGIC_RESET; +} +bool Loader::setState(Jtag_fsm::State state) { + if (!device->navigateToState(currentState, state)) + return false; + currentState = state; + return true; + +} + +bool Loader::resetState() { + currentState = Jtag_fsm::TEST_LOGIC_RESET; + return device->navigateToState(Jtag_fsm::CAPTURE_DR, + Jtag_fsm::TEST_LOGIC_RESET); +} + +bool Loader::setIR(Instruction inst) { + stringstream inst_str; + inst_str << std::setfill('0') << std::setw(2) << hex + << static_cast(inst); + + if (!device->navigateToState(currentState, Jtag_fsm::SHIFT_IR)) { + cerr << "Failed to change to SHIFT_IR state!" << endl; + return false; + } + if (!device->shiftData(6, inst_str.str(), "", "")) { + cerr << "Failed to shift instruction data!" << endl; + return false; + } + if (!device->navigateToState(Jtag_fsm::EXIT1_IR, Jtag_fsm::RUN_TEST_IDLE)) { + cerr << "Failed to change to RUN_TEST_IDLE state!" << endl; + return false; + } + currentState = Jtag_fsm::RUN_TEST_IDLE; + return true; +} + +// basically the same as shiftDR but ignores the first four bits +bool Loader::shiftUDR(int bits, string write, string read, string mask) { + string uread = read; + string umask = mask; + string uwrite = write; + + if (!read.empty()) { + uread = read + "0"; + umask = mask + "0"; + uwrite = "0" + write; + bits += 4; + } + + return shiftDR(bits, uwrite, uread, umask); +} + +bool Loader::shiftDR(int bits, string write, string read, string mask) { + if (!device->navigateToState(currentState, Jtag_fsm::SHIFT_DR)) { + cerr << "Failed to change to SHIFT_DR state!" << endl; + return false; + } + if (!device->shiftData(bits, write, read, mask)) { + cerr << "Failed to shift data!" << endl; + return false; + } + if (!device->navigateToState(Jtag_fsm::EXIT1_DR, Jtag_fsm::RUN_TEST_IDLE)) { + cerr << "Failed to change to RUN_TEST_IDLE state!" << endl; + return false; + } + currentState = Jtag_fsm::RUN_TEST_IDLE; + return true; +} + +bool Loader::shiftIR(int bits, string write, string read, string mask) { + if (!device->navigateToState(currentState, Jtag_fsm::SHIFT_IR)) { + cerr << "Failed to change to SHIFT_IR state!" << endl; + return false; + } + if (!device->shiftData(bits, write, read, mask)) { + cerr << "Failed to shift data!" << endl; + return false; + } + if (!device->navigateToState(Jtag_fsm::EXIT1_IR, Jtag_fsm::RUN_TEST_IDLE)) { + cerr << "Failed to change to RUN_TEST_IDLE state!" << endl; + return false; + } + currentState = Jtag_fsm::RUN_TEST_IDLE; + return true; +} + +string Loader::shiftDR(int bits, string write) { + if (!device->navigateToState(currentState, Jtag_fsm::SHIFT_DR)) { + cerr << "Failed to change to SHIFT_DR state!" << endl; + return NULL; + } + + string data = device->shiftData(bits, write); + if (data.empty()) { + cerr << "Failed to shift data!" << endl; + return NULL; + } + if (!device->navigateToState(Jtag_fsm::EXIT1_DR, Jtag_fsm::RUN_TEST_IDLE)) { + cerr << "Failed to change to RUN_TEST_IDLE state!" << endl; + return NULL; + } + currentState = Jtag_fsm::RUN_TEST_IDLE; + return data; +} + +bool Loader::loadBin(string file) { + string binStr = fileToBinStr(file); + + string reversedBinStr = reverseBytes(binStr); + + if (!device->setFreq(10000000)) { + cerr << "Failed to set JTAG frequency!" << endl; + return false; + } + if (!resetState()) + return false; + if (!setState(Jtag_fsm::RUN_TEST_IDLE)) + return false; + + if (!setIR(JPROGRAM)) + return false; + if (!setIR(ISC_NOOP)) + return false; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // config/jprog/poll + if (!device->sendClocks(10000)) + return false; + if (!shiftIR(6, "14", "11", "31")) + return false; + + // config/slr + if (!setIR(CFG_IN)) + return false; + if (!shiftDR(binStr.length() * 4, reversedBinStr, "", "")) + return false; + + // config/start + if (!setState(Jtag_fsm::RUN_TEST_IDLE)) + return false; + if (!device->sendClocks(100000)) + return false; + if (!setIR(JSTART)) + return false; + if (!setState(Jtag_fsm::RUN_TEST_IDLE)) + return false; + if (!device->sendClocks(100)) + return false; + if (!shiftIR(6, "09", "31", "11")) + return false; + + // config/status + if (!setState(Jtag_fsm::TEST_LOGIC_RESET)) + return false; + if (!device->sendClocks(5)) + return false; + if (!setIR(CFG_IN)) + return false; + if (!shiftDR(160, "0000000400000004800700140000000466aa9955", "", "")) + return false; + if (!setIR(CFG_OUT)) + return false; + if (!shiftDR(32, "00000000", "3f5e0d40", "08000000")) + return false; + if (!setState(Jtag_fsm::TEST_LOGIC_RESET)) + return false; + if (!device->sendClocks(5)) + return false; + + return true; +} + +string Loader::fileToBinStr(string file) { + ifstream binFile(file); + stringstream hexString; + + char *buffer; + binFile.seekg(0, ios::end); + unsigned int byteCount = binFile.tellg(); + binFile.seekg(0, ios::beg); + buffer = new char[byteCount]; + binFile.read(buffer, byteCount); + binFile.close(); + + for (int i = byteCount - 1; i >= 0; i--) { + hexString << setfill('0') << setw(2) << std::hex + << (int) ((unsigned char) buffer[i]); + } + + delete buffer; + + return hexString.str(); +} + +bool Loader::eraseFlash(string loaderFile) { + cout << "Initializing FPGA..." << endl; + if (!loadBin(loaderFile)) { + cerr << "Failed to initialize FPGA!" << endl; + return false; + } + + if (!device->setFreq(1500000)) { + cerr << "Failed to set JTAG frequency!" << endl; + return false; + } + + cout << "Erasing..." << endl; + + // Erase the flash + if (!setIR(USER1)) + return false; + + if (!shiftDR(1, "0", "", "")) + return false; + + std::this_thread::sleep_for(std::chrono::seconds(1)); // wait for erase + + if (!setIR(JPROGRAM)) + return false; + + // reset just for good measure + if (!resetState()) + return false; + + return true; +} + +bool Loader::writeBin(string binFile, bool flash, string loaderFile) { + if (flash) { + string binStr = fileToBinStr(binFile); + + cout << "Initializing FPGA..." << endl; + if (!loadBin(loaderFile)) { + cerr << "Failed to initialize FPGA!" << endl; + return false; + } + + if (!device->setFreq(1500000)) { + cerr << "Failed to set JTAG frequency!" << endl; + return false; + } + + cout << "Erasing..." << endl; + + // Erase the flash + if (!setIR(USER1)) + return false; + + if (!shiftDR(1, "0", "", "")) + return false; + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + cout << "Writing..." << endl; + + // Write the flash + if (!setIR(USER2)) + return false; + + if (!shiftDR(binStr.length() * 4, binStr, "", "")) + return false; + + // If you enter the reset state after a write + // the loader firmware resets the flash into + // regular SPI mode and gets stuck in a dead FSM + // state. You need to do this before issuing a + // JPROGRAM command or the FPGA can't read the + // flash. + if (!resetState()) + return false; + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 100ms delay is required before issuing JPROGRAM + + cout << "Resetting FPGA..." << endl; + // JPROGRAM resets the FPGA configuration and will + // cause it to read the flash memory + if (!setIR(JPROGRAM)) + return false; + } else { + cout << "Programming FPGA..." << endl; + if (!loadBin(binFile)) { + cerr << "Failed to initialize FPGA!" << endl; + return false; + } + } + + // reset just for good measure + if (!resetState()) + return false; + + cout << "Done." << endl; + return true; +} + +bool Loader::checkIDCODE() { + if (!setIR(IDCODE)) + return false; + + if (!shiftDR(32, "00000000", "0362D093", "0FFFFFFF")) // FPGA IDCODE + return false; + + return true; +} + +BYTE reverse(BYTE b) { + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + return b; +} + +bool Loader::setWREN() { + if (!setIR(USER1)) + return false; + if (!shiftDR(8, reverseBytes("06"), "", "")) + return false; + return true; +} + +int Loader::getStatus() { + if (!setIR(USER1)) + return -1; + string data = shiftDR(17, reverseBytes("00005")); + cout << data << endl; + if (data.empty()) + return -1; + int status = stoi(data, 0, 16); + status >>= 9; + return reverse(status); +} + +void hexToByte(string hex, BYTE* out) { + int length = hex.length(); + for (int i = 0; i < length / 2; i++) { + out[i] = stoi(hex.substr(length - 2 - i * 2, 2), 0, 16); + } + if ((length & 1) != 0) + out[length / 2] = stoi(hex.substr(0, 1), 0, 16); +} + +string Loader::reverseBytes(string start) { + unsigned long l = start.length(); + if (l & 1) + l++; + l /= 2; + BYTE* bytes = new BYTE[l]; + hexToByte(start, bytes); + for (unsigned long i = 0; i < l; i++) { + bytes[i] = reverse(bytes[i]); + } + std::stringstream ss; + for (long i = l - 1; i >= 0; i--) + ss << setfill('0') << setw(2) << hex << (unsigned int) bytes[i]; + string out = ss.str(); + if (out.length() - 1 == start.length()) + out = out.substr(1, out.length() - 1); + delete bytes; + return out; +} + diff --git a/alchitry-loader/src/loader.h b/alchitry-loader/src/loader.h new file mode 100644 index 0000000..5932b3e --- /dev/null +++ b/alchitry-loader/src/loader.h @@ -0,0 +1,77 @@ +/* + * Loader.h + * + * Created on: Nov 6, 2017 + * Author: justin + */ + +#ifndef LOADER_H_ +#define LOADER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include "jtag.h" +#include "jtag_fsm.h" + +class Loader { + Jtag* device; + Jtag_fsm::State currentState; + + public: + enum Instruction { + EXTEST = 0x26, + EXTEST_PULSE = 0x3C, + EXTEST_TRAIN = 0x3D, + SAMPLE = 0x01, + USER1 = 0x02, + USER2 = 0x03, + USER3 = 0x22, + USER4 = 0x23, + CFG_OUT = 0x04, + CFG_IN = 0x05, + USERCODE = 0x08, + IDCODE = 0x09, + HIGHZ_IO = 0x0A, + JPROGRAM = 0x0B, + JSTART = 0x0C, + JSHUTDOWN = 0x0D, + XADC_DRP = 0x37, + ISC_ENABLE = 0x10, + ISC_PROGRAM = 0x11, + XSC_PROGRAM_KEY = 0x12, + XSC_DNA = 0x17, + FUSE_DNA = 0x32, + ISC_NOOP = 0x14, + ISC_DISABLE = 0x16, + BYPASS = 0x2F, + }; + +public: + Loader(Jtag*); + bool resetState(); + bool checkIDCODE(); + bool eraseFlash(string); + bool writeBin(string, bool, string); + +private: + bool setWREN(); + bool setIR(Instruction); + bool shiftUDR(int, string, string, string); + bool shiftDR(int, string, string, string); + string shiftDR(int, string); + bool shiftIR(int, string, string, string); + int getStatus(); + string reverseBytes(string); + string fileToBinStr(string); + bool loadBin(string); + bool setState(Jtag_fsm::State); +}; + + + +#endif /* LOADER_H_ */ diff --git a/alchitry-loader/src/mingw.thread.h b/alchitry-loader/src/mingw.thread.h new file mode 100644 index 0000000..34ec6c2 --- /dev/null +++ b/alchitry-loader/src/mingw.thread.h @@ -0,0 +1,414 @@ +/** +* @file mingw.thread.h +* @brief std::thread implementation for MinGW +* (c) 2013-2016 by Mega Limited, Auckland, New Zealand +* @author Alexander Vassilev +* +* @copyright Simplified (2-clause) BSD License. +* You should have received a copy of the license along with this +* program. +* +* This code 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. +* @note +* This file may become part of the mingw-w64 runtime package. If/when this happens, +* the appropriate license will be added, i.e. this code will become dual-licensed, +* and the current BSD 2-clause license will stay. +*/ + +#ifndef WIN32STDTHREAD_H +#define WIN32STDTHREAD_H + +#if !defined(__cplusplus) || (__cplusplus < 201103L) +#error A C++11 compiler is required! +#endif + +// Use the standard classes for std::, if available. +#include + +#include // For std::size_t +#include // Detect error type. +#include // For std::terminate +#include // For std::system_error +#include // For std::hash +#include // For std::tuple +#include // For sleep timing. +#include // For std::unique_ptr +#include // Stream output for thread ids. +#include // For std::swap, std::forward + +// For the invoke implementation only: +#include // For std::result_of, etc. +//#include // For std::forward +//#include // For std::reference_wrapper + +#include +#include // For _beginthreadex + +#ifndef NDEBUG +#include +#endif + +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0501) +#error To use the MinGW-std-threads library, you will need to define the macro _WIN32_WINNT to be 0x0501 (Windows XP) or higher. +#endif + +// Instead of INVALID_HANDLE_VALUE, _beginthreadex returns 0. +namespace mingw_stdthread +{ +namespace detail +{ +// For compatibility, implement std::invoke for C++11 and C++14 +#if __cplusplus < 201703L + template + struct Invoker + { + template + inline static typename std::result_of::type invoke (F&& f, Args&&... args) + { + return std::forward(f)(std::forward(args)...); + } + }; + template + struct InvokerHelper; + + template<> + struct InvokerHelper + { + template + inline static auto get (T1&& t1) -> decltype(*std::forward(t1)) + { + return *std::forward(t1); + } + + template + inline static auto get (const std::reference_wrapper& t1) -> decltype(t1.get()) + { + return t1.get(); + } + }; + + template<> + struct InvokerHelper + { + template + inline static auto get (T1&& t1) -> decltype(std::forward(t1)) + { + return std::forward(t1); + } + }; + + template<> + struct Invoker + { + template + inline static auto invoke (F T::* f, T1&& t1, Args&&... args) ->\ + decltype((InvokerHelper::type>::value>::get(std::forward(t1)).*f)(std::forward(args)...)) + { + return (InvokerHelper::type>::value>::get(std::forward(t1)).*f)(std::forward(args)...); + } + }; + + template<> + struct Invoker + { + template + inline static auto invoke (F T::* f, T1&& t1, Args&&... args) ->\ + decltype(InvokerHelper::type>::value>::get(t1).*f) + { + return InvokerHelper::type>::value>::get(t1).*f; + } + }; + + template + struct InvokeResult + { + typedef Invoker::type>::value, + std::is_member_object_pointer::type>::value && + (sizeof...(Args) == 1)> invoker; + inline static auto invoke (F&& f, Args&&... args) -> decltype(invoker::invoke(std::forward(f), std::forward(args)...)) + { + return invoker::invoke(std::forward(f), std::forward(args)...); + }; + }; + + template + auto invoke (F&& f, Args&&... args) -> decltype(InvokeResult::invoke(std::forward(f), std::forward(args)...)) + { + return InvokeResult::invoke(std::forward(f), std::forward(args)...); + } +#else + using std::invoke; +#endif + + template + struct IntSeq {}; + + template + struct GenIntSeq : GenIntSeq { }; + + template + struct GenIntSeq<0, S...> { typedef IntSeq type; }; + + // We can't define the Call struct in the function - the standard forbids template methods in that case + template + class ThreadFuncCall + { + typedef std::tuple Tuple; + Func mFunc; + Tuple mArgs; + + template + void callFunc(detail::IntSeq) + { + detail::invoke(std::forward(mFunc), std::get(std::forward(mArgs)) ...); + } + public: + ThreadFuncCall(Func&& aFunc, Args&&... aArgs) + :mFunc(std::forward(aFunc)), mArgs(std::forward(aArgs)...){} + + void callFunc() + { + callFunc(typename detail::GenIntSeq::type()); + } + }; + +} // Namespace "detail" + +class thread +{ +public: + class id + { + DWORD mId; + void clear() {mId = 0;} + friend class thread; + friend class std::hash; + public: + explicit id(DWORD aId=0) noexcept : mId(aId){} + friend bool operator==(id x, id y) noexcept {return x.mId == y.mId; } + friend bool operator!=(id x, id y) noexcept {return x.mId != y.mId; } + friend bool operator< (id x, id y) noexcept {return x.mId < y.mId; } + friend bool operator<=(id x, id y) noexcept {return x.mId <= y.mId; } + friend bool operator> (id x, id y) noexcept {return x.mId > y.mId; } + friend bool operator>=(id x, id y) noexcept {return x.mId >= y.mId; } + + template + friend std::basic_ostream<_CharT, _Traits>& + operator<<(std::basic_ostream<_CharT, _Traits>& __out, id __id) + { + if (__id.mId == 0) + { + return __out << "(invalid std::thread::id)"; + } + else + { + return __out << __id.mId; + } + } + }; +private: + static constexpr HANDLE kInvalidHandle = nullptr; + HANDLE mHandle; + id mThreadId; + + template + static unsigned __stdcall threadfunc(void* arg) + { + std::unique_ptr call(static_cast(arg)); + call->callFunc(); + return 0; + } + + static unsigned int _hardware_concurrency_helper() noexcept + { + SYSTEM_INFO sysinfo; +// This is one of the few functions used by the library which has a nearly- +// equivalent function defined in earlier versions of Windows. Include the +// workaround, just as a reminder that it does exist. +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) + ::GetNativeSystemInfo(&sysinfo); +#else + ::GetSystemInfo(&sysinfo); +#endif + return sysinfo.dwNumberOfProcessors; + } +public: + typedef HANDLE native_handle_type; + id get_id() const noexcept {return mThreadId;} + native_handle_type native_handle() const {return mHandle;} + thread(): mHandle(kInvalidHandle), mThreadId(){} + + thread(thread&& other) + :mHandle(other.mHandle), mThreadId(other.mThreadId) + { + other.mHandle = kInvalidHandle; + other.mThreadId.clear(); + } + + thread(const thread &other)=delete; + + template + explicit thread(Func&& func, Args&&... args) : mHandle(), mThreadId() + { + typedef detail::ThreadFuncCall Call; + auto call = new Call( + std::forward(func), std::forward(args)...); + auto int_handle = _beginthreadex(NULL, 0, threadfunc, + static_cast(call), 0, + reinterpret_cast(&(mThreadId.mId))); + if (int_handle == 0) + { + mHandle = kInvalidHandle; + int errnum = errno; + delete call; +// Note: Should only throw EINVAL, EAGAIN, EACCES + throw std::system_error(errnum, std::generic_category()); + } else + mHandle = reinterpret_cast(int_handle); + } + + bool joinable() const {return mHandle != kInvalidHandle;} + +// Note: Due to lack of synchronization, this function has a race condition +// if called concurrently, which leads to undefined behavior. The same applies +// to all other member functions of this class, but this one is mentioned +// explicitly. + void join() + { + using namespace std; + if (get_id() == id(GetCurrentThreadId())) + throw system_error(make_error_code(errc::resource_deadlock_would_occur)); + if (mHandle == kInvalidHandle) + throw system_error(make_error_code(errc::no_such_process)); + if (!joinable()) + throw system_error(make_error_code(errc::invalid_argument)); + WaitForSingleObject(mHandle, INFINITE); + CloseHandle(mHandle); + mHandle = kInvalidHandle; + mThreadId.clear(); + } + + ~thread() + { + if (joinable()) + { +#ifndef NDEBUG + std::printf("Error: Must join() or detach() a thread before \ +destroying it.\n"); +#endif + std::terminate(); + } + } + thread& operator=(const thread&) = delete; + thread& operator=(thread&& other) noexcept + { + if (joinable()) + { +#ifndef NDEBUG + std::printf("Error: Must join() or detach() a thread before \ +moving another thread to it.\n"); +#endif + std::terminate(); + } + swap(std::forward(other)); + return *this; + } + void swap(thread&& other) noexcept + { + HANDLE tmph = mHandle; + mHandle = other.mHandle; + other.mHandle = tmph; + DWORD tmpd = mThreadId.mId; + mThreadId.mId = other.mThreadId.mId; + other.mThreadId.mId = tmpd; + } + + static unsigned int hardware_concurrency() noexcept + { + static unsigned int cached = _hardware_concurrency_helper(); + return cached; + } + + void detach() + { + if (!joinable()) + { + using namespace std; + throw system_error(make_error_code(errc::invalid_argument)); + } + if (mHandle != kInvalidHandle) + { + CloseHandle(mHandle); + mHandle = kInvalidHandle; + } + mThreadId.clear(); + } +}; + +namespace this_thread +{ + inline thread::id get_id() noexcept {return thread::id(GetCurrentThreadId());} + inline void yield() noexcept {Sleep(0);} + template< class Rep, class Period > + void sleep_for( const std::chrono::duration& sleep_duration) + { + using namespace std::chrono; + using rep = milliseconds::rep; + rep ms = duration_cast(sleep_duration).count(); + while (ms > 0) + { + constexpr rep kMaxRep = static_cast(INFINITE - 1); + auto sleepTime = (ms < kMaxRep) ? ms : kMaxRep; + Sleep(static_cast(sleepTime)); + ms -= sleepTime; + } + } + template + void sleep_until(const std::chrono::time_point& sleep_time) + { + sleep_for(sleep_time-Clock::now()); + } +} +} // Namespace mingw_stdthread + +namespace std +{ +// Because of quirks of the compiler, the common "using namespace std;" +// directive would flatten the namespaces and introduce ambiguity where there +// was none. Direct specification (std::), however, would be unaffected. +// Take the safe option, and include only in the presence of MinGW's win32 +// implementation. +#if defined(__MINGW32__ ) && !defined(_GLIBCXX_HAS_GTHREADS) +using mingw_stdthread::thread; +// Remove ambiguity immediately, to avoid problems arising from the above. +//using std::thread; +namespace this_thread +{ +using namespace mingw_stdthread::this_thread; +} +#elif !defined(MINGW_STDTHREAD_REDUNDANCY_WARNING) // Skip repetition +#define MINGW_STDTHREAD_REDUNDANCY_WARNING +#pragma message "This version of MinGW seems to include a win32 port of\ + pthreads, and probably already has C++11 std threading classes implemented,\ + based on pthreads. These classes, found in namespace std, are not overridden\ + by the mingw-std-thread library. If you would still like to use this\ + implementation (as it is more lightweight), use the classes provided in\ + namespace mingw_stdthread." +#endif + +// Specialize hash for this implementation's thread::id, even if the +// std::thread::id already has a hash. +template<> +struct hash +{ + typedef mingw_stdthread::thread::id argument_type; + typedef size_t result_type; + size_t operator() (const argument_type & i) const noexcept + { + return i.mId; + } +}; +} +#endif // WIN32STDTHREAD_H diff --git a/alchitry-loader/src/spi.cpp b/alchitry-loader/src/spi.cpp new file mode 100644 index 0000000..58cd6cd --- /dev/null +++ b/alchitry-loader/src/spi.cpp @@ -0,0 +1,940 @@ +/* + * iceprog -- simple programming tool for FTDI-based Lattice iCE programmers + * + * Copyright (C) 2015 Clifford Wolf + * Copyright (C) 2018 Piotr Esden-Tempski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Relevant Documents: + * ------------------- + * http://www.latticesemi.com/~/media/Documents/UserManuals/EI/icestickusermanual.pdf + * http://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/n25q/n25q_32mb_3v_65nm.pdf + * http://www.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf + */ + +#include "spi.h" +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include "mingw.thread.h" +#else +#include +#endif + +#include + +using namespace std; + +/* MPSSE engine command definitions */ +enum mpsse_cmd { + /* Mode commands */ + MC_SETB_LOW = 0x80, /* Set Data bits LowByte */ + MC_READB_LOW = 0x81, /* Read Data bits LowByte */ + MC_SETB_HIGH = 0x82, /* Set Data bits HighByte */ + MC_READB_HIGH = 0x83, /* Read data bits HighByte */ + MC_LOOPBACK_EN = 0x84, /* Enable loopback */ + MC_LOOPBACK_DIS = 0x85, /* Disable loopback */ + MC_SET_CLK_DIV = 0x86, /* Set clock divisor */ + MC_FLUSH = 0x87, /* Flush buffer fifos to the PC. */ + MC_WAIT_H = 0x88, /* Wait on GPIOL1 to go high. */ + MC_WAIT_L = 0x89, /* Wait on GPIOL1 to go low. */ + MC_TCK_X5 = 0x8A, /* Disable /5 div, enables 60MHz master clock */ + MC_TCK_D5 = 0x8B, /* Enable /5 div, backward compat to FT2232D */ + MC_EN_3PH_CLK = 0x8C, /* Enable 3 phase clk, DDR I2C */ + MC_DIS_3PH_CLK = 0x8D, /* Disable 3 phase clk */ + MC_CLK_N = 0x8E, /* Clock every bit, used for JTAG */ + MC_CLK_N8 = 0x8F, /* Clock every byte, used for JTAG */ + MC_CLK_TO_H = 0x94, /* Clock until GPIOL1 goes high */ + MC_CLK_TO_L = 0x95, /* Clock until GPIOL1 goes low */ + MC_EN_ADPT_CLK = 0x96, /* Enable adaptive clocking */ + MC_DIS_ADPT_CLK = 0x97, /* Disable adaptive clocking */ + MC_CLK8_TO_H = 0x9C, /* Clock until GPIOL1 goes high, count bytes */ + MC_CLK8_TO_L = 0x9D, /* Clock until GPIOL1 goes low, count bytes */ + MC_TRI = 0x9E, /* Set IO to only drive on 0 and tristate on 1 */ + /* CPU mode commands */ + MC_CPU_RS = 0x90, /* CPUMode read short address */ + MC_CPU_RE = 0x91, /* CPUMode read extended address */ + MC_CPU_WS = 0x92, /* CPUMode write short address */ + MC_CPU_WE = 0x93, /* CPUMode write extended address */ +}; + +// --------------------------------------------------------- +// FLASH definitions +// --------------------------------------------------------- + +/* Transfer Command bits */ + +/* All byte based commands consist of: + * - Command byte + * - Length lsb + * - Length msb + * + * If data out is enabled the data follows after the above command bytes, + * otherwise no additional data is needed. + * - Data * n + * + * All bit based commands consist of: + * - Command byte + * - Length + * + * If data out is enabled a byte containing bitst to transfer follows. + * Otherwise no additional data is needed. Only up to 8 bits can be transferred + * per transaction when in bit mode. + */ + +/* b 0000 0000 + * |||| |||`- Data out negative enable. Update DO on negative clock edge. + * |||| ||`-- Bit count enable. When reset count represents bytes. + * |||| |`--- Data in negative enable. Latch DI on negative clock edge. + * |||| `---- LSB enable. When set clock data out LSB first. + * |||| + * |||`------ Data out enable + * ||`------- Data in enable + * |`-------- TMS mode enable + * `--------- Special command mode enable. See mpsse_cmd enum. + */ + +#define MC_DATA_TMS (0x40) /* When set use TMS mode */ +#define MC_DATA_IN (0x20) /* When set read data (Data IN) */ +#define MC_DATA_OUT (0x10) /* When set write data (Data OUT) */ +#define MC_DATA_LSB (0x08) /* When set input/output data LSB first. */ +#define MC_DATA_ICN (0x04) /* When set receive data on negative clock edge */ +#define MC_DATA_BITS (0x02) /* When set count bits not bytes */ +#define MC_DATA_OCN (0x01) /* When set update data on negative clock edge */ + +/* Flash command definitions */ +/* This command list is based on the Winbond W25Q128JV Datasheet */ +enum flash_cmd { + FC_WE = 0x06, /* Write Enable */ + FC_SRWE = 0x50, /* Volatile SR Write Enable */ + FC_WD = 0x04, /* Write Disable */ + FC_RPD = 0xAB, /* Release Power-Down, returns Device ID */ + FC_MFGID = 0x90, /* Read Manufacturer/Device ID */ + FC_JEDECID = 0x9F, /* Read JEDEC ID */ + FC_UID = 0x4B, /* Read Unique ID */ + FC_RD = 0x03, /* Read Data */ + FC_FR = 0x0B, /* Fast Read */ + FC_PP = 0x02, /* Page Program */ + FC_SE = 0x20, /* Sector Erase 4kb */ + FC_BE32 = 0x52, /* Block Erase 32kb */ + FC_BE64 = 0xD8, /* Block Erase 64kb */ + FC_CE = 0xC7, /* Chip Erase */ + FC_RSR1 = 0x05, /* Read Status Register 1 */ + FC_WSR1 = 0x01, /* Write Status Register 1 */ + FC_RSR2 = 0x35, /* Read Status Register 2 */ + FC_WSR2 = 0x31, /* Write Status Register 2 */ + FC_RSR3 = 0x15, /* Read Status Register 3 */ + FC_WSR3 = 0x11, /* Write Status Register 3 */ + FC_RSFDP = 0x5A, /* Read SFDP Register */ + FC_ESR = 0x44, /* Erase Security Register */ + FC_PSR = 0x42, /* Program Security Register */ + FC_RSR = 0x48, /* Read Security Register */ + FC_GBL = 0x7E, /* Global Block Lock */ + FC_GBU = 0x98, /* Global Block Unlock */ + FC_RBL = 0x3D, /* Read Block Lock */ + FC_RPR = 0x3C, /* Read Sector Protection Registers (adesto) */ + FC_IBL = 0x36, /* Individual Block Lock */ + FC_IBU = 0x39, /* Individual Block Unlock */ + FC_EPS = 0x75, /* Erase / Program Suspend */ + FC_EPR = 0x7A, /* Erase / Program Resume */ + FC_PD = 0xB9, /* Power-down */ + FC_QPI = 0x38, /* Enter QPI mode */ + FC_ERESET = 0x66, /* Enable Reset */ + FC_RESET = 0x99, /* Reset Device */ +}; + +Spi::Spi() { + ftHandle = 0; + active = false; + verbose = false; +} + +FT_STATUS Spi::connect(unsigned int devNumber) { + return FT_Open(devNumber, &ftHandle); +} + +FT_STATUS Spi::disconnect() { + active = false; + return FT_Close(ftHandle); +} + +bool Spi::initialize() { + BYTE byInputBuffer[1024]; // Buffer to hold data read from the FT2232H + DWORD dwNumBytesToRead = 0; // Number of bytes available to read in the driver's input buffer + DWORD dwNumBytesRead = 0; // Count of actual bytes read - used with FT_Read + FT_STATUS ftStatus; + ftStatus = FT_ResetDevice(ftHandle); + //Reset USB device + //Purge USB receive buffer first by reading out all old data from FT2232H receive buffer + ftStatus |= FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); // Get the number of bytes in the FT2232H receive buffer + if ((ftStatus == FT_OK) && (dwNumBytesToRead > 0)) + FT_Read(ftHandle, &byInputBuffer, dwNumBytesToRead, &dwNumBytesRead);//Read out the data from FT2232H receive buffer + ftStatus |= FT_SetUSBParameters(ftHandle, 65536, 65535);//Set USB request transfer sizes to 64K + ftStatus |= FT_SetChars(ftHandle, false, 0, false, 0); //Disable event and error characters + ftStatus |= FT_SetTimeouts(ftHandle, 0, 5000); //Sets the read and write timeouts in milliseconds + ftStatus |= FT_SetLatencyTimer(ftHandle, 1); //Set the latency timer 1ms + ftStatus |= FT_SetBitMode(ftHandle, 0x0, 0x00); //Reset controller + ftStatus |= FT_SetBitMode(ftHandle, 0x0, 0x02); //Enable MPSSE mode + + if (ftStatus != FT_OK) { + cerr << "Failed to set initial configuration!" << endl; + return false; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Wait for all the USB stuff to complete and work + + if (!sync_mpsse()){ + cerr << "Failed to sync with MPSSE!" << endl; + return false; + } + + if (!config_spi()){ + cerr << "Failed to set SPI configuration!" << endl; + return false; + } + + active = true; + + return true; +} + +bool Spi::sync_mpsse() { + BYTE byOutputBuffer[8]; // Buffer to hold MPSSE commands and data to be sent to the FT2232H + BYTE byInputBuffer[8]; // Buffer to hold data read from the FT2232H + DWORD dwCount = 0; // General loop index + DWORD dwNumBytesToSend = 0; // Index to the output buffer + DWORD dwNumBytesSent = 0; // Count of actual bytes sent - used with FT_Write + DWORD dwNumBytesToRead = 0; // Number of bytes available to read in the driver's input buffer + DWORD dwNumBytesRead = 0; // Count of actual bytes read - used with FT_Read + FT_STATUS ftStatus; + + byOutputBuffer[dwNumBytesToSend++] = 0xAA; //'\xAA'; + //Add bogus command ‘xAA’ to the queue + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + // Send off the BAD commands + dwNumBytesToSend = 0; // Reset output buffer pointer + do { + ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead); + // Get the number of bytes in the device input buffer + } while ((dwNumBytesToRead == 0) && (ftStatus == FT_OK)); + if (dwNumBytesRead > 8) { + cerr << "Input buffer too small in sync_mpsse()!" << endl; + return false; + } + //or Timeout + bool bCommandEchod = false; + ftStatus = FT_Read(ftHandle, &byInputBuffer, dwNumBytesToRead, + &dwNumBytesRead); + //Read out the data from input buffer + for (dwCount = 0; dwCount < dwNumBytesRead - 1; dwCount++) + //Check if Bad command and echo command received + { + if ((byInputBuffer[dwCount] == 0xFA) + && (byInputBuffer[dwCount + 1] == 0xAA)) { + bCommandEchod = true; + break; + } + } + + return bCommandEchod; +} + +bool Spi::config_spi() { + FT_STATUS ftStatus; + BYTE byOutputBuffer[64]; // Buffer to hold MPSSE commands and data to be sent to the FT2232H + DWORD dwNumBytesToSend = 0; // Index to the output buffer + DWORD dwNumBytesSent = 0; // Count of actual bytes sent - used with FT_Write + DWORD dwClockDivisor = 0x0; // Value of clock divisor, SCL Frequency = 60/((1+0x0)*2) (MHz) = 30MHz + // ----------------------------------------------------------- + // Configure the MPSSE settings for SPI + // Multiple commands can be sent to the MPSSE with one FT_Write + // ----------------------------------------------------------- + dwNumBytesToSend = 0; // Start with a fresh index + // Set up the Hi-Speed specific commands for the FTx232H + byOutputBuffer[dwNumBytesToSend++] = 0x8A; + // Use 60MHz master clock (disable divide by 5) + byOutputBuffer[dwNumBytesToSend++] = 0x97; + // Turn off adaptive clocking (may be needed for ARM) + byOutputBuffer[dwNumBytesToSend++] = 0x8D; + // Disable three-phase clocking + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + // Send off the HS-specific commands + + if (ftStatus != FT_OK) + return false; + + dwNumBytesToSend = 0; // Reset output buffer pointer + // Set initial states of the MPSSE interface - low byte, both pin directions and output values + // Pin name Signal Direction Config Initial State Config + // ADBUS0 SCK output 1 low 0 + // ADBUS1 MOSI output 1 low 0 + // ADBUS2 MISO input 0 low 0 + // ADBUS3 NC output 1 low 0 + // ADBUS4 SS output 1 low 0 + // ADBUS5 NC output 1 low 0 + // ADBUS6 CDONE input 0 low 0 + // ADBUS7 CRESET output 1 low 0 + byOutputBuffer[dwNumBytesToSend++] = 0x80; + // Set data bits low-byte of MPSSE port + byOutputBuffer[dwNumBytesToSend++] = 0x00; + // Initial state config above + byOutputBuffer[dwNumBytesToSend++] = 0xBB; + // Direction config above + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + // Send off the low GPIO config commands + + if (ftStatus != FT_OK) + return false; + + dwNumBytesToSend = 0; // Reset output buffer pointer + // Set initial states of the MPSSE interface - high byte, both pin directions and output values + // Pin name Signal Direction Config Initial State Config + // ACBUS0 GPIOH0 input 0 0 + // ACBUS1 GPIOH1 input 0 0 + // ACBUS2 GPIOH2 input 0 0 + // ACBUS3 GPIOH3 input 0 0 + // ACBUS4 GPIOH4 input 0 0 + // ACBUS5 GPIOH5 input 0 0 + // ACBUS6 GPIOH6 input 0 0 + // ACBUS7 GPIOH7 input 0 0 + byOutputBuffer[dwNumBytesToSend++] = 0x82; + // Set data bits low-byte of MPSSE port + byOutputBuffer[dwNumBytesToSend++] = 0x00; + // Initial state config above + byOutputBuffer[dwNumBytesToSend++] = 0x00; + // Direction config above + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + // Send off the high GPIO config commands + + if (ftStatus != FT_OK) + return false; + + dwNumBytesToSend = 0; // Reset output buffer pointer + // Set TCK frequency + // TCK = 60MHz /((1 + [(1 +0xValueH*256) OR 0xValueL])*2) + byOutputBuffer[dwNumBytesToSend++] = 0x86; + //Command to set clock divisor + byOutputBuffer[dwNumBytesToSend++] = dwClockDivisor & 0xFF; + //Set 0xValueL of clock divisor + byOutputBuffer[dwNumBytesToSend++] = (dwClockDivisor >> 8) & 0xFF; + //Set 0xValueH of clock divisor + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + // Send off the clock divisor commands + + if (ftStatus != FT_OK) + return false; + + dwNumBytesToSend = 0; // Reset output buffer pointer + // Disable internal loop-back + byOutputBuffer[dwNumBytesToSend++] = 0x85; + // Disable loopback + ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, + &dwNumBytesSent); + // Send off the loopback command + + if (ftStatus != FT_OK) + return false; + + return true; +} + +void Spi::check_rx() { + FT_STATUS ftStatus; + BYTE byInputBuffer[1]; + DWORD dwNumBytesRead = 0; + + while (1) { + ftStatus = FT_Read(ftHandle, &byInputBuffer, 1, &dwNumBytesRead); + if (ftStatus != FT_OK) + break; + cerr << "Unexpected rx byte: " << byInputBuffer[0] << endl; + } +} + +void Spi::error(int status) { + check_rx(); + cerr << "ABORT." << endl; + if (active) + disconnect(); + exit(status); +} + +BYTE Spi::recv_byte() { + FT_STATUS ftStatus; + BYTE byInputBuffer[1]; + DWORD dwNumBytesRead = 0; + while (1) { + ftStatus = FT_Read(ftHandle, &byInputBuffer, 1, &dwNumBytesRead); + if (ftStatus != FT_OK) { + cerr << "Read error." << endl; + error(2); + } + if (dwNumBytesRead == 1) + break; + std::this_thread::sleep_for(std::chrono::microseconds(100)); + } + return byInputBuffer[0]; +} + +void Spi::send_byte(uint8_t data) { + FT_STATUS ftStatus; + BYTE byOutputBuffer[1]; + DWORD dwNumBytesSent = 0; + + byOutputBuffer[0] = data; + + ftStatus = FT_Write(ftHandle, byOutputBuffer, 1, &dwNumBytesSent); + if (ftStatus != FT_OK) { + cerr << "Write error!" << endl; + error(2); + } + if (dwNumBytesSent != 1) { + cerr << "Write error (single byte, received " << dwNumBytesSent + << ", expected 1)." << endl; + error(2); + } +} + +void Spi::send_spi(uint8_t *data, int n) { + if (n < 1) + return; + + /* Output only, update data on negative clock edge. */ + send_byte(MC_DATA_OUT | MC_DATA_OCN); + send_byte(n - 1); + send_byte((n - 1) >> 8); + + FT_STATUS ftStatus; + DWORD dwNumBytesSent = 0; + + ftStatus = FT_Write(ftHandle, data, n, &dwNumBytesSent); + if (ftStatus != FT_OK) { + cerr << "Write error!" << endl; + error(2); + } + + if (dwNumBytesSent != (unsigned int) n) { + fprintf(stderr, "Write error (chunk, rc=%u, expected %d).\n", + dwNumBytesSent, n); + error(2); + } +} + +void Spi::xfer_spi(uint8_t *data, int n) { + if (n < 1) + return; + + /* Input and output, update data on negative edge read on positive. */ + send_byte(MC_DATA_IN | MC_DATA_OUT | MC_DATA_OCN); + send_byte(n - 1); + send_byte((n - 1) >> 8); + + FT_STATUS ftStatus; + DWORD dwNumBytesSent = 0; + + ftStatus = FT_Write(ftHandle, data, n, &dwNumBytesSent); + if (ftStatus != FT_OK) { + cerr << "Write error!" << endl; + error(2); + } + + if (dwNumBytesSent != (unsigned int) n) { + fprintf(stderr, "Write error (chunk, rc=%u, expected %d).\n", + dwNumBytesSent, n); + error(2); + } + + for (int i = 0; i < n; i++) + data[i] = recv_byte(); +} + +uint8_t Spi::xfer_spi_bits(uint8_t data, int n) { + if (n < 1) + return 0; + + /* Input and output, update data on negative edge read on positive, bits. */ + send_byte(MC_DATA_IN | MC_DATA_OUT | MC_DATA_OCN | MC_DATA_BITS); + send_byte(n - 1); + send_byte(data); + + return recv_byte(); +} + +void Spi::set_gpio(int slavesel_b, int creset_b) { + uint8_t gpio = 0; + + if (slavesel_b) { + // ADBUS4 (GPIOL0) + gpio |= 0x10; + } + + if (creset_b) { + // ADBUS7 (GPIOL3) + gpio |= 0x80; + } + + send_byte(MC_SETB_LOW); + send_byte(gpio); /* Value */ + send_byte(0x93); /* Direction */ +} + +int Spi::get_cdone() { + uint8_t data; + send_byte(MC_READB_LOW); + data = recv_byte(); + // ADBUS6 (GPIOL2) + return (data & 0x40) != 0; +} + +// --------------------------------------------------------- +// FLASH function implementations +// --------------------------------------------------------- + +// the FPGA reset is released so also FLASH chip select should be deasserted +void Spi::flash_release_reset() { + set_gpio(1, 1); +} + +// FLASH chip select assert +// should only happen while FPGA reset is asserted +void Spi::flash_chip_select() { + set_gpio(0, 0); +} + +// FLASH chip select deassert +void Spi::flash_chip_deselect() { + set_gpio(1, 0); +} + +// SRAM reset is the same as flash_chip_select() +// For ease of code reading we use this function instead +void Spi::sram_reset() { + // Asserting chip select and reset lines + set_gpio(0, 0); +} + +// SRAM chip select assert +// When accessing FPGA SRAM the reset should be released +void Spi::sram_chip_select() { + set_gpio(0, 1); +} + +void Spi::flash_read_id() { + /* JEDEC ID structure: + * Byte No. | Data Type + * ---------+---------- + * 0 | FC_JEDECID Request Command + * 1 | MFG ID + * 2 | Dev ID 1 + * 3 | Dev ID 2 + * 4 | Ext Dev Str Len + */ + + uint8_t data[260] = { FC_JEDECID }; + int len = 5; // command + 4 response bytes + + if (verbose) + fprintf(stdout, "read flash ID..\n"); + + flash_chip_select(); + + // Write command and read first 4 bytes + xfer_spi(data, len); + + if (data[4] == 0xFF) + fprintf(stderr, "Extended Device String Length is 0xFF, " + "this is likely a read error. Ignorig...\n"); + else { + // Read extended JEDEC ID bytes + if (data[4] != 0) { + len += data[4]; + xfer_spi(data + 5, len - 5); + } + } + + flash_chip_deselect(); + + fprintf(stdout, "flash ID:"); + for (int i = 1; i < len; i++) + fprintf(stdout, " 0x%02X", data[i]); + fprintf(stdout, "\n"); +} + +void Spi::flash_reset() { + flash_chip_select(); + xfer_spi_bits(0xFF, 8); + flash_chip_deselect(); + + flash_chip_select(); + xfer_spi_bits(0xFF, 2); + flash_chip_deselect(); +} + +void Spi::flash_power_up() { + uint8_t data_rpd[1] = { FC_RPD }; + flash_chip_select(); + xfer_spi(data_rpd, 1); + flash_chip_deselect(); +} + +void Spi::flash_power_down() { + uint8_t data[1] = { FC_PD }; + flash_chip_select(); + xfer_spi(data, 1); + flash_chip_deselect(); +} + +uint8_t Spi::flash_read_status() { + uint8_t data[2] = { FC_RSR1 }; + + flash_chip_select(); + xfer_spi(data, 2); + flash_chip_deselect(); + + if (verbose) { + fprintf(stdout, "SR1: 0x%02X\n", data[1]); + fprintf(stdout, " - SPRL: %s\n", + ((data[1] & (1 << 7)) == 0) ? "unlocked" : "locked"); + fprintf(stdout, " - SPM: %s\n", + ((data[1] & (1 << 6)) == 0) ? + "Byte/Page Prog Mode" : "Sequential Prog Mode"); + fprintf(stdout, " - EPE: %s\n", + ((data[1] & (1 << 5)) == 0) ? + "Erase/Prog success" : "Erase/Prog error"); + fprintf(stdout, "- SPM: %s\n", + ((data[1] & (1 << 4)) == 0) ? + "~WP asserted" : "~WP deasserted"); + fprintf(stdout, " - SWP: "); + switch ((data[1] >> 2) & 0x3) { + case 0: + fprintf(stdout, "All sectors unprotected\n"); + break; + case 1: + fprintf(stdout, "Some sectors protected\n"); + break; + case 2: + fprintf(stdout, "Reserved (xxxx 10xx)\n"); + break; + case 3: + fprintf(stdout, "All sectors protected\n"); + break; + } + fprintf(stdout, " - WEL: %s\n", + ((data[1] & (1 << 1)) == 0) ? + "Not write enabled" : "Write enabled"); + fprintf(stdout, " - ~RDY: %s\n", + ((data[1] & (1 << 0)) == 0) ? "Ready" : "Busy"); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + return data[1]; +} + +void Spi::flash_write_enable() { + if (verbose) { + fprintf(stdout, "status before enable:\n"); + flash_read_status(); + } + + if (verbose) + fprintf(stdout, "write enable..\n"); + + uint8_t data[1] = { FC_WE }; + flash_chip_select(); + xfer_spi(data, 1); + flash_chip_deselect(); + + if (verbose) { + fprintf(stdout, "status after enable:\n"); + flash_read_status(); + } +} + +void Spi::flash_bulk_erase() { + if (verbose) + fprintf(stdout, "bulk erase..\n"); + + uint8_t data[1] = { FC_CE }; + flash_chip_select(); + xfer_spi(data, 1); + flash_chip_deselect(); +} + +void Spi::flash_64kB_sector_erase(int addr) { + if (verbose) + fprintf(stdout, "erase 64kB sector at 0x%06X..\n", addr); + + uint8_t command[4] = { FC_BE64, (uint8_t) (addr >> 16), + (uint8_t) (addr >> 8), (uint8_t) addr }; + + flash_chip_select(); + send_spi(command, 4); + flash_chip_deselect(); +} + +void Spi::flash_prog(int addr, uint8_t *data, int n) { + if (verbose) + fprintf(stdout, "prog 0x%06X +0x%03X..\n", addr, n); + + uint8_t command[4] = { FC_PP, (uint8_t) (addr >> 16), (uint8_t) (addr >> 8), + (uint8_t) addr }; + + flash_chip_select(); + send_spi(command, 4); + send_spi(data, n); + flash_chip_deselect(); + + if (verbose) + for (int i = 0; i < n; i++) + fprintf(stderr, "%02x%c", data[i], + i == n - 1 || i % 32 == 31 ? '\n' : ' '); +} + +void Spi::flash_read(int addr, uint8_t *data, int n) { + if (verbose) + fprintf(stdout, "read 0x%06X +0x%03X..\n", addr, n); + + uint8_t command[4] = { FC_RD, (uint8_t) (addr >> 16), (uint8_t) (addr >> 8), + (uint8_t) addr }; + + flash_chip_select(); + send_spi(command, 4); + memset(data, 0, n); + xfer_spi(data, n); + flash_chip_deselect(); + + if (verbose) + for (int i = 0; i < n; i++) + fprintf(stderr, "%02x%c", data[i], + i == n - 1 || i % 32 == 31 ? '\n' : ' '); +} + +void Spi::flash_wait() { + if (verbose) + fprintf(stderr, "waiting.."); + + int count = 0; + while (1) { + uint8_t data[2] = { FC_RSR1 }; + + flash_chip_select(); + xfer_spi(data, 2); + flash_chip_deselect(); + + if ((data[1] & 0x01) == 0) { + if (count < 2) { + count++; + if (verbose) { + fprintf(stderr, "r"); + fflush(stderr); + } + } else { + if (verbose) { + fprintf(stderr, "R"); + fflush(stderr); + } + break; + } + } else { + if (verbose) { + fprintf(stderr, "."); + fflush(stderr); + } + count = 0; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + if (verbose) + fprintf(stderr, "\n"); + +} + +void Spi::flash_disable_protection() { + fprintf(stderr, "disable flash protection...\n"); + + // Write Status Register 1 <- 0x00 + uint8_t data[2] = { FC_WSR1, 0x00 }; + flash_chip_select(); + xfer_spi(data, 2); + flash_chip_deselect(); + + flash_wait(); + + // Read Status Register 1 + data[0] = FC_RSR1; + + flash_chip_select(); + xfer_spi(data, 2); + flash_chip_deselect(); + + if (data[1] != 0x00) + fprintf(stderr, + "failed to disable protection, SR now equal to 0x%02x (expected 0x00)\n", + data[1]); + +} + +bool Spi::eraseFlash() { + fprintf(stdout, "reset..\n"); + + flash_chip_deselect(); + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + fprintf(stdout, "cdone: %s\n", get_cdone() ? "high" : "low"); + + flash_reset(); + flash_power_up(); + + flash_read_id(); + + flash_write_enable(); + flash_bulk_erase(); + flash_wait(); + + // --------------------------------------------------------- + // Reset + // --------------------------------------------------------- + + flash_power_down(); + + set_gpio(1, 1); + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + fprintf(stdout, "cdone: %s\n", get_cdone() ? "high" : "low"); + + return true; +} +bool Spi::writeBin(string filename) { + int rw_offset = 0; + + FILE *f = NULL; + long file_size = -1; + + f = fopen(filename.c_str(), "rb"); + + if (f == NULL) { + fprintf(stderr, "Can't open '%s' for reading: ", filename.c_str()); + return false; + } + + if (fseek(f, 0L, SEEK_END) != -1) { + file_size = ftell(f); + if (file_size == -1) { + fprintf(stderr, "%s: ftell: ", filename.c_str()); + return false; + } + if (fseek(f, 0L, SEEK_SET) == -1) { + fprintf(stderr, "%s: fseek: ", filename.c_str()); + return false; + } + } else { + FILE *pipe = f; + + f = tmpfile(); + if (f == NULL) { + fprintf(stderr, "can't open temporary file\n"); + return false; + } + file_size = 0; + + while (true) { + static unsigned char buffer[4096]; + size_t rc = fread(buffer, 1, 4096, pipe); + if (rc <= 0) + break; + size_t wc = fwrite(buffer, 1, rc, f); + if (wc != rc) { + fprintf(stderr, "can't write to temporary file\n"); + return false; + } + file_size += rc; + } + fclose(pipe); + + /* now seek to the beginning so we can + start reading again */ + fseek(f, 0, SEEK_SET); + } + + cout << "Resetting..." << endl; + + flash_chip_deselect(); + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + cout << "cdone: " << (get_cdone() ? "high" : "low") << endl; + + flash_reset(); + flash_power_up(); + + flash_read_id(); + + int begin_addr = rw_offset & ~0xffff; + int end_addr = (rw_offset + file_size + 0xffff) & ~0xffff; + + for (int addr = begin_addr; addr < end_addr; addr += 0x10000) { + flash_write_enable(); + flash_64kB_sector_erase(addr); + if (verbose) { + fprintf(stderr, "Status after block erase:\n"); + flash_read_status(); + } + flash_wait(); + } + + cout << "Programming... "; + + for (int rc, addr = 0; true; addr += rc) { + uint8_t buffer[256]; + int page_size = 256 - (rw_offset + addr) % 256; + rc = fread(buffer, 1, page_size, f); + if (rc <= 0) + break; + flash_write_enable(); + flash_prog(rw_offset + addr, buffer, rc); + flash_wait(); + } + + cout << "Done." << endl; + + /* seek to the beginning for second pass */ + fseek(f, 0, SEEK_SET); + + // --------------------------------------------------------- + // Reset + // --------------------------------------------------------- + + flash_power_down(); + + set_gpio(1, 1); + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + cout << "cdone: " << (get_cdone() ? "high" : "low") << endl; + cout << "Done." << endl; + + if (f != NULL && f != stdin && f != stdout) + fclose(f); + return true; +} diff --git a/alchitry-loader/src/spi.h b/alchitry-loader/src/spi.h new file mode 100644 index 0000000..d2a38a2 --- /dev/null +++ b/alchitry-loader/src/spi.h @@ -0,0 +1,66 @@ +/* + * spi.h + * + * Created on: Feb 5, 2019 + * Author: justin + */ + +#ifndef SPI_H_ +#define SPI_H_ + +#include "ftd2xx.h" +#include +#include + +using namespace std; + +class Spi { + FT_HANDLE ftHandle; + unsigned int uiDevIndex = 0xF; // The device in the list that is used + bool active; + bool verbose; + +public: + Spi(); + FT_STATUS connect(unsigned int); + FT_STATUS disconnect(); + bool initialize(); + bool eraseFlash(); + bool writeBin(string); + +private: + bool sync_mpsse(); + bool config_spi(); + static void hexToByte(string, BYTE*); + bool flush(); + bool compareHexString(string, string, string); + void check_rx(); + void error(int); + BYTE recv_byte(); + void send_byte(BYTE data); + void send_spi(uint8_t *data, int n); + void xfer_spi(uint8_t *data, int n); + uint8_t xfer_spi_bits(uint8_t data, int n); + void set_gpio(int slavesel_b, int creset_b); + int get_cdone(); + void flash_release_reset(); + void flash_chip_select(); + void flash_chip_deselect(); + void sram_reset(); + void sram_chip_select(); + void flash_read_id(); + void flash_reset(); + void flash_power_up(); + void flash_power_down(); + uint8_t flash_read_status(); + void flash_write_enable(); + void flash_bulk_erase(); + void flash_64kB_sector_erase(int addr); + void flash_prog(int addr, uint8_t *data, int n); + void flash_read(int addr, uint8_t *data, int n); + void flash_wait(); + void flash_disable_protection(); + +}; + +#endif /* SPI_H_ */