#include #include #include #include #include typedef unsigned int FT_STATUS; typedef void* FT_HANDLE; typedef unsigned char* PUCHAR; typedef unsigned int DWORD; typedef unsigned short WORD; typedef unsigned char UCHAR; typedef void* PVOID; typedef void* LPVOID; typedef unsigned int* LPDWORD; typedef unsigned short* LPWORD; typedef unsigned int ULONG; 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; 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 ABORT(msg) \ printf("ERR: unsupported function called!: %s\n", msg); \ return FT_IO_ERROR; #define TRACE(func) \ printf("TRACE: %s\n", func) typedef struct { size_t pos; size_t len; unsigned char data[16384]; } sq_read_state; sq_read_state read_state = {0, 0, {0}}; void init_read_state(unsigned char* data, size_t len) { memcpy(read_state.data, data, len); read_state.pos = 0; read_state.len = len; } enum { BOOT_INIT, APP_INIT, CAP_READY, CAP_TRIGGERED, CAP_READING } sq_state = APP_INIT; FT_STATUS FT_Close(FT_HANDLE ftHandle) { /* TRACE("FT_Close"); */ free(ftHandle); return FT_OK; } FT_STATUS FT_GetBitMode(FT_HANDLE ftHandle, PUCHAR pucMode) { ABORT("FT_GetBitMode"); } FT_STATUS FT_GetQueueStatus(FT_HANDLE ftHandle, DWORD* dwRxBytes) { *dwRxBytes = read_state.len - read_state.pos; return FT_OK; } #define FT_OPEN_BY_SERIAL_NUMBER 1 #define FT_OPEN_BY_DESCRIPTION 2 #define FT_OPEN_BY_LOCATION 4 #define FT_LIST_NUMBER_ONLY 0x80000000 #define FT_LIST_BY_INDEX 0x40000000 #define FT_LIST_ALL 0x20000000 FT_STATUS FT_ListDevices(PVOID pArg1, PVOID pArg2, DWORD flags) { /* TRACE("FT_ListDevices"); */ if (flags & FT_LIST_NUMBER_ONLY) { *((unsigned int*) pArg1) = 1; return FT_OK; } else if (flags & FT_LIST_ALL) { char** pa1 = (char**) pArg1; if (flags & FT_OPEN_BY_SERIAL_NUMBER) { pa1[0] = strdup("1003050005482"); pa1[1] = NULL; *((unsigned int*) pArg2) = 1; return FT_OK; } else if (flags & FT_OPEN_BY_DESCRIPTION) { pa1[0] = strdup("ScanaQuad SQ50"); pa1[1] = NULL; *((unsigned int*) pArg2) = 1; return FT_OK; } } printf("unknown list device mode: %x\n", flags); ABORT("FT_ListDevice list mode"); } FT_STATUS FT_Open(int devno, FT_HANDLE* pHandle) { /* TRACE("FT_Open"); */ *pHandle = malloc(20); return FT_OK; } FT_STATUS FT_OpenEx(PVOID pArg1, DWORD flags, FT_HANDLE* pHandle) { TRACE("FT_OpenEx"); *pHandle = malloc(20); return FT_OK; } FT_STATUS FT_Read(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesReturned) { TRACE("FT_Read"); size_t max_bytes = dwBytesToRead; if (read_state.len - read_state.pos > max_bytes) { max_bytes = read_state.len - read_state.pos; } printf("req size: %lu | state pos %lu state len %lu\n", max_bytes, read_state.pos, read_state.len); memcpy(lpBuffer, &read_state.data[read_state.pos], max_bytes); read_state.pos += max_bytes; *lpBytesReturned = max_bytes; return FT_OK; } FT_STATUS FT_SetBitMode(FT_HANDLE ftHandle, UCHAR ucMask, UCHAR ucEnable) { ABORT("FT_SetBitMode"); } FT_STATUS FT_SetLatencyTimer(FT_HANDLE ftHandle, UCHAR ucLatency) { ABORT("FT_SetLatencyTimer"); } FT_STATUS FT_SetTimeouts(FT_HANDLE ftHandle, ULONG rto, ULONG wto) { /* TRACE("FT_SetTimeouts"); */ /* printf("rto=%u, wto=%u\n", rto, wto); */ return FT_OK; } FT_STATUS FT_SetUSBParameters(FT_HANDLE ftHandle, ULONG inxfersz, ULONG outxfersz) { /* TRACE("FT_SetUSBParameters"); */ return FT_OK; } FT_STATUS FT_SetVIDPID(DWORD dwVid, DWORD dwPid) { /* TRACE("FT_SetVIDPID"); */ return FT_OK; } void dump(unsigned char* buffer, size_t len) { for (size_t i = 0; i < len; i++) { printf("%02x ", buffer[i]); if (i % 32 == 31) { printf("\n"); } } printf("\n"); } void print_bin(unsigned char b) { for (int i = 7; i >= 0; i--) { if ((b>>i)&0x1) { printf("1"); } else { printf("0"); } } } FT_STATUS FT_Write(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD len, LPDWORD written) { TRACE("FT_Write"); unsigned char* buffer = (unsigned char*) lpBuffer; switch (buffer[0]) { case 0x94: TRACE("bootloader reset"); sq_state = BOOT_INIT; break; case 0x93: TRACE("app reset"); sq_state = APP_INIT; break; case 0xf1: if (sq_state == BOOT_INIT) { printf("boot code: %02x %02x %02x\n", buffer[1], buffer[2], buffer[3]); if (buffer[1] != 0x62 || buffer[2] != 0xa7 || buffer[3] != 0x7e) { ABORT("wrong code!"); } } else { printf("settings buffer:\n"); dump(buffer, len); } break; case 0xfd: if (buffer[1] != 0x00 || buffer[2] != 0x01 || buffer[3] != 0x02 || buffer[4] != 0xfe) { ABORT("wrong 0xfd command"); } if (sq_state == BOOT_INIT) { printf("boot echo\n"); init_read_state("\x01\x01\x01\x01", 4); dump(read_state.data, read_state.len); } else { printf("app echo\n"); init_read_state("\x22\x22\x22\x22", 4); dump(read_state.data, read_state.len); } break; case 0xf4: TRACE("got trigger settings"); dump(buffer, len); for (size_t i = 1; i < len; i += 4) { unsigned char cfg0 = buffer[i+0]; unsigned char cfg1 = buffer[i+1]; unsigned char cfg2 = buffer[i+2]; unsigned char cfg3 = buffer[i+3]; printf("SLOT: "); print_bin(cfg0); printf(" "); print_bin(cfg1); printf(" "); print_bin(cfg2); printf(" "); print_bin(cfg3); printf("\n"); } break; case 0xf0: switch (buffer[1]) { case 0x00: printf("state -> ready\n"); sq_state = CAP_READY; break; case 0x01: printf("wait for trigger command\n"); init_read_state("\x11\x00\x00\xdd", 4); break; case 0x06: printf("start read"); read_state.len = 16384; read_state.pos = 0; for (size_t i = 0; i < 16384; i++) { read_state.data[i] = (i & 0x1) ? 0xf0 : 0xa5; } printf("sending to app"); break; default: printf("unknown capture cmd code\n"); dump(buffer, len); ABORT("FT_Write"); } break; default: printf("UNKNOWN write sequence!\n"); dump(buffer, len); ABORT("FT_Write"); } *written = len; return FT_OK; } unsigned char eeprom[] = {0x62, 0xa7, 0x7e, 0x03, 0x9f, 0xf5, 0xf6, 0x74, 0xf4, 0x01}; FT_STATUS FT_ReadEE(FT_HANDLE ftHandle, DWORD off, LPWORD val) { TRACE("FT_ReadEE"); if (off == 0x12) { printf("0x12 -> 0xa762\n"); *val = 0xa762; return FT_OK; } else if (off == 0x13) { printf("0x13 -> 0x037e\n"); *val = 0x037e; return FT_OK; } else if (off == 0x20) { printf("0x20 -> 0x8888\n"); *val = 0x8888; return FT_OK; } else { printf("unknown ReadEE req: %x\n", off); ABORT("FT_ReadEE"); } } FT_STATUS FT_WriteEE(FT_HANDLE ftHandle, DWORD off, WORD val) { ABORT("FT_WriteEE"); } FT_STATUS FT_EE_Program(FT_HANDLE ftHandle, PFT_PROGRAM_DATA pData) { ABORT("FT_EE_Program"); } FT_STATUS FT_EE_Read(FT_HANDLE ftHandle, PFT_PROGRAM_DATA pData) { ABORT("FT_EE_Read"); } FT_STATUS FT_EE_UARead(FT_HANDLE ftHandle, PUCHAR pucData, DWORD len, LPDWORD read) { ABORT("FT_EE_UARead"); } FT_STATUS FT_EE_UAWrite(FT_HANDLE ftHandle, PUCHAR pucData, DWORD len) { ABORT("FT_EE_UAWrite"); }