sq50-re/libsqfake.c

554 lines
21 KiB
C
Raw Normal View History

2021-06-22 07:00:04 +00:00
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
2021-06-22 16:02:28 +00:00
#include <string.h>
2021-06-22 07:00:04 +00:00
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,
2021-06-22 10:00:32 +00:00
CAP_READING,
CAP_ENDED,
GEN_DOWNLOAD
2021-06-22 07:00:04 +00:00
} sq_state = APP_INIT;
2021-06-22 10:00:32 +00:00
size_t gen_downloaded = 0;
size_t gen_total = 0;
2021-06-22 07:57:02 +00:00
bool settings_init = false;
unsigned char sq_settings[24] = {0};
2021-06-22 07:00:04 +00:00
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);
2021-06-22 10:00:32 +00:00
sq_state = APP_INIT;
2021-06-22 07:00:04 +00:00
return FT_OK;
}
FT_STATUS FT_OpenEx(PVOID pArg1, DWORD flags, FT_HANDLE* pHandle) {
TRACE("FT_OpenEx");
*pHandle = malloc(20);
2021-06-22 10:00:32 +00:00
sq_state = APP_INIT;
2021-06-22 07:00:04 +00:00
return FT_OK;
}
FT_STATUS FT_Read(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesReturned) {
2021-06-22 07:57:02 +00:00
/* TRACE("FT_Read"); */
2021-06-22 07:00:04 +00:00
2021-06-22 10:00:32 +00:00
/* printf("FT_Read of %lu\n", dwBytesToRead); */
2021-06-22 07:00:04 +00:00
size_t max_bytes = dwBytesToRead;
if (read_state.len - read_state.pos > max_bytes) {
max_bytes = read_state.len - read_state.pos;
}
2021-06-22 10:00:32 +00:00
if (max_bytes == 0) {
printf("ERROR: read is not ready\n");
}
2021-06-22 07:57:02 +00:00
/* printf("req size: %lu | state pos %lu state len %lu\n", max_bytes, */
/* read_state.pos, read_state.len); */
2021-06-22 07:00:04 +00:00
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");
}
2021-06-22 07:57:02 +00:00
void dump_with_color(unsigned char* buffer, unsigned char* compare, size_t len) {
for (size_t i = 0; i < len; i++) {
if (buffer[i] == compare[i]) {
printf("%02x ", buffer[i]);
} else {
printf("\x1b[1m\x1b[31m%02x\x1b[m\x0f ", buffer[i]);
}
}
printf("\n");
}
2021-06-22 07:00:04 +00:00
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) {
2021-06-22 07:57:02 +00:00
/* TRACE("FT_Write"); */
2021-06-22 07:00:04 +00:00
unsigned char* buffer = (unsigned char*) lpBuffer;
2021-06-22 10:00:32 +00:00
if (sq_state == GEN_DOWNLOAD) {
printf("downloading chunk len %lu\n", len);
gen_downloaded += len;
if (gen_downloaded > gen_total) {
ABORT("too much data downloaded!");
} else if (gen_downloaded == gen_total) {
printf("done downloading\n");
sq_state = CAP_READY;
}
*written = len;
return FT_OK;
}
2021-06-22 07:00:04 +00:00
switch (buffer[0]) {
case 0x94:
2021-06-22 07:57:02 +00:00
/* TRACE("bootloader reset"); */
2021-06-22 07:00:04 +00:00
sq_state = BOOT_INIT;
break;
case 0x93:
2021-06-22 07:57:02 +00:00
/* TRACE("app reset"); */
2021-06-22 07:00:04 +00:00
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 {
2021-06-22 07:57:02 +00:00
if (len != 25) {
dump(buffer, len);
ABORT("bad settings len");
}
printf(" addr: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17\n");
printf("settings data: ");
if (!settings_init) {
dump(&buffer[1], 24);
memcpy(sq_settings, &buffer[1], 24);
printf("saved init settings\n");
settings_init = true;
} else {
dump_with_color(&buffer[1], sq_settings, 24);
}
2021-06-22 07:00:04 +00:00
}
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) {
2021-06-22 07:57:02 +00:00
/* printf("boot echo\n"); */
2021-06-22 07:00:04 +00:00
init_read_state("\x01\x01\x01\x01", 4);
2021-06-22 07:57:02 +00:00
/* dump(read_state.data, read_state.len); */
2021-06-22 07:00:04 +00:00
} else {
2021-06-22 07:57:02 +00:00
/* printf("app echo\n"); */
2021-06-22 07:00:04 +00:00
init_read_state("\x22\x22\x22\x22", 4);
2021-06-22 07:57:02 +00:00
/* dump(read_state.data, read_state.len); */
2021-06-22 07:00:04 +00:00
}
break;
case 0xf4:
2021-06-22 07:57:02 +00:00
/* TRACE("got trigger settings"); */
/* dump(buffer, len); */
2021-06-22 07:00:04 +00:00
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];
2021-06-22 07:57:02 +00:00
printf("TRIG SLOT: ");
2021-06-22 07:00:04 +00:00
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:
2021-06-22 07:57:02 +00:00
/* printf("state -> ready\n"); */
if (sq_state == CAP_READING) {
2021-06-22 10:00:32 +00:00
sq_state = CAP_ENDED;
} else if (sq_state != CAP_READY) {
printf("========= start capture =========\n");
sq_state = CAP_READY;
2021-06-22 07:57:02 +00:00
}
2021-06-22 07:00:04 +00:00
break;
case 0x01:
2021-06-22 10:00:32 +00:00
printf("=========== sending trigger =========== ...");
2021-06-22 07:00:04 +00:00
init_read_state("\x11\x00\x00\xdd", 4);
break;
2021-06-22 10:00:32 +00:00
case 0x02:
printf("generator generating forever\n");
break;
2021-06-22 07:00:04 +00:00
case 0x06:
2021-06-22 10:00:32 +00:00
printf("=========== starting read ===========\n");
2021-06-22 07:57:02 +00:00
sq_state = CAP_READING;
2021-06-22 07:00:04 +00:00
read_state.len = 16384;
read_state.pos = 0;
for (size_t i = 0; i < 16384; i++) {
read_state.data[i] = (i & 0x1) ? 0xf0 : 0xa5;
}
2021-06-22 07:57:02 +00:00
/* printf("sending to app"); */
2021-06-22 07:00:04 +00:00
break;
2021-06-22 10:00:32 +00:00
case 0x05:
printf("======== entering generator mode ======\n");
if (buffer[2] != 0xf3) {
dump(buffer, len);
ABORT("wrong byte 3 in generator sequence");
}
sq_state = GEN_DOWNLOAD;
gen_downloaded = 0;
gen_total = 500000; // TODO
break;
2021-06-22 07:00:04 +00:00
default:
dump(buffer, len);
2021-06-22 10:00:32 +00:00
printf("unknown capture cmd code (len %lu)\n", len);
2021-06-22 07:00:04 +00:00
ABORT("FT_Write");
}
break;
default:
dump(buffer, len);
2021-06-22 10:00:32 +00:00
printf("UNKNOWN write sequence! (len %lu)\n", len);
2021-06-22 07:00:04 +00:00
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");
}