├── .gitignore ├── CH347 ├── CH347DLL.H ├── CH347DLL_EN.H ├── amd64 │ └── CH347DLLA64.lib ├── arm64 │ └── CH347DLLA64.lib └── i386 │ └── CH347DLL.lib ├── CMakeLists.txt ├── README.md ├── io_ch347.c ├── io_ch347.h └── xvcd_win.c /.gitignore: -------------------------------------------------------------------------------- 1 | build/ -------------------------------------------------------------------------------- /CH347/CH347DLL.H: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOT-CAT/xvcd-ch347/e20dd824d1ece541d89a9beb49f340ff24278443/CH347/CH347DLL.H -------------------------------------------------------------------------------- /CH347/CH347DLL_EN.H: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | ** Copyright (C) WCH 2001 - 2025 ** 3 | ** Web: http://wch.cn ** 4 | ******************************************************************************/ 5 | // USB bus interface chip CH341/7 parallel port application layer interface library. CH347/CH339W extends UART/SPI/I2C/JTAG/SWD based on the 480Mbps high-speed USB bus. 6 | // CH347-DLL V1.4 7 | // Support OS: Windows 98/ME, Windows 2000/XP, WIN7/8/10/11, and later. 8 | // Support USB chips: CH341, CH341A, CH347, CH339W 9 | // USB => Parallel, I2C, SPI, JTAG, SWD, PARALLEL, UART ... 10 | // Notes: 11 | // Copyright (C) 2025 Nanjing Qinheng Microelectronics Co., Ltd. 12 | 13 | #ifndef _CH347_DLL_H 14 | #define _CH347_DLL_H 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #ifdef _WIN64 21 | #define mOFFSET(s, m) ((ULONG_PTR) & (((s *)0)->m)) // Defines a macro that gets the relative offset address of a structure member 22 | #else 23 | #define mOFFSET(s, m) ((ULONG) & (((s *)0)->m)) // Defines a macro that gets the relative offset address of a structure member 24 | #endif 25 | 26 | #ifndef max 27 | #define max(a, b) (((a) > (b)) ? (a) : (b)) // Determine the maximum value 28 | #endif 29 | 30 | #ifndef min 31 | #define min(a, b) (((a) < (b)) ? (a) : (b)) // Determine the minimum value 32 | #endif 33 | 34 | #ifdef ExAllocatePool 35 | #undef ExAllocatePool // Delete memory allocation with TAG 36 | #endif 37 | 38 | #ifndef NTSTATUS 39 | typedef LONG NTSTATUS; // Return status 40 | #endif 41 | 42 | // Sharing CH341WDM driver with CH341DLL 43 | #ifndef _CH341_DLL_H 44 | typedef struct _USB_SETUP_PKT { // USB control transfer structure 45 | UCHAR mUspReqType; // 00H request type 46 | UCHAR mUspRequest; // 01H request code 47 | union { 48 | struct { 49 | UCHAR mUspValueLow; // 02H Value parameter low byte 50 | UCHAR mUspValueHigh; // 03H Value parameter high byte 51 | }; 52 | USHORT mUspValue; // 02H-03H value parameters 53 | }; 54 | union { 55 | struct { 56 | UCHAR mUspIndexLow; // 04H index parameter low byte 57 | UCHAR mUspIndexHigh; // 05H index parameter high byte 58 | }; 59 | USHORT mUspIndex; // 04H-05H index parameter 60 | }; 61 | USHORT mLength; // 06H-07H data length 62 | } mUSB_SETUP_PKT, *mPUSB_SETUP_PKT; 63 | 64 | typedef struct _WIN32_COMMAND { // Define the WIN32 command interface structure 65 | union { 66 | ULONG mFunction; // Specify function code or pipe number when inputting 67 | NTSTATUS mStatus; // return operation status when output 68 | }; 69 | ULONG mLength; // access length, return the length of subsequent data 70 | union { 71 | mUSB_SETUP_PKT mSetupPkt; // Data request in the setup phase of USB control transfer 72 | UCHAR mBuffer[512]; // data buffer, the length is 0 to 255B 73 | }; 74 | } mWIN32_COMMAND, *mPWIN32_COMMAND; 75 | // WIN32 Application layer interface command 76 | #define IOCTL_CH341_COMMAND (FILE_DEVICE_UNKNOWN << 16 | FILE_ANY_ACCESS << 14 | 0x0f34 << 2 | METHOD_BUFFERED) // private interface 77 | 78 | #define mWIN32_COMMAND_HEAD mOFFSET(mWIN32_COMMAND, mBuffer) // Header length of WIN32 command interface 79 | 80 | #define mCH341_MAX_NUMBER 32 // Maximum number of CH341/7 connected at the same time 81 | 82 | #define mMAX_BUFFER_LENGTH 0x1000 // The maximum length of the data buffer is 4MB 83 | 84 | #define mMAX_COMMAND_LENGTH (mWIN32_COMMAND_HEAD + mMAX_BUFFER_LENGTH) // maximum data length and the command structure header length 85 | 86 | #define mDEFAULT_BUFFER_LEN 0x0400 // The data buffer default length is 1024 87 | 88 | #define mDEFAULT_COMMAND_LEN (mWIN32_COMMAND_HEAD + mDEFAULT_BUFFER_LEN) // default data length and the command structure header length 89 | 90 | // CH341 endpoint address 91 | #define mCH347_ENDP_DATA_UP 0x86 // The data upload endpoint of CH347 92 | #define mCH347_ENDP_DATA_DOWN 0x06 // The data download endpoint of CH347 93 | 94 | // Pipeline operation command provided by equipment layer interface 95 | #define mPipeDeviceCtrl 0x00000004 // CH347 integrated control pipeline 96 | #define mPipeDataUp 0x00000006 // CH347 data block upload pipeline 97 | #define mPipeDataDown 0x00000007 // CH347 data block download pipeline 98 | 99 | // Function code of application layer interface 100 | #define mFuncNoOperation 0x00000000 // no operation 101 | #define mFuncGetVersion 0x00000001 // Get the driver version number 102 | #define mFuncGetConfig 0x00000002 // Get the USB device configuration descriptor 103 | #define mFuncSetTimeout 0x00000009 // Set USB communication timeout 104 | #define mFuncSetExclusive 0x0000000b // Set exclusive use 105 | #define mFuncResetDevice 0x0000000c // Reset the USB device 106 | #define mFuncResetPipe 0x0000000d // Reset the USB pipe 107 | #define mFuncAbortPipe 0x0000000e // Cancel the data request of the USB pipe 108 | #define mFuncBufferMode 0x00000020 // Set the buffer upload mode and query the data length in the buffer 109 | #define mFuncBufferModeDn 0x00000021 // Set the buffer download mode and query the data length in the buffer 110 | #define mFuncGetVersionEx 0x00000022 // Get the driver version number and chip model 111 | // USB device standard request code 112 | #define mUSB_CLR_FEATURE 0x01 113 | #define mUSB_SET_FEATURE 0x03 114 | #define mUSB_GET_STATUS 0x00 115 | #define mUSB_SET_ADDRESS 0x05 116 | #define mUSB_GET_DESCR 0x06 117 | #define mUSB_SET_DESCR 0x07 118 | #define mUSB_GET_CONFIG 0x08 119 | #define mUSB_SET_CONFIG 0x09 120 | #define mUSB_GET_INTERF 0x0a 121 | #define mUSB_SET_INTERF 0x0b 122 | #define mUSB_SYNC_FRAME 0x0c 123 | 124 | // CH341 manufacturer specific request type for control transmission 125 | #define mCH341_VENDOR_READ 0xC0 // CH341 vendor-specific read operation through control transfer 126 | #define mCH341_VENDOR_WRITE 0x40 // CH341 vendor-specific write operation through control transfer 127 | 128 | #define mCH341A_CMD_I2C_STREAM 0xAA // The command package of the I2C interface, starting from the secondary byte, is the I2C command stream 129 | #define mCH341A_CMD_UIO_STREAM 0xAB // The command package of the UIO interface, starting from the secondary byte, is the command stream 130 | #define mCH341A_CMD_PIO_STREAM 0xAE // The command package of PIO interface, starting from the secondary byte, is the data stream 131 | // CH341A manufacturer specific request code for control transmission 132 | #define mCH341A_BUF_CLEAR 0xB2 // Clear incomplete data 133 | #define mCH341A_I2C_CMD_X 0x54 // Issue the command of I2C interface and execute it immediately 134 | #define mCH341A_DELAY_MS 0x5E // Delay the specified time in microseconds 135 | #define mCH341A_GET_VER 0x5F // Get chip version 136 | 137 | #define mCH341A_CMD_I2C_STM_STA 0x74 // Command flow of I2C interface: generate start bit 138 | #define mCH341A_CMD_I2C_STM_STO 0x75 // Command flow of I2C interface: generate stop bit 139 | #define mCH341A_CMD_I2C_STM_OUT 0x80 // Command flow of I2C interface: output data, bit 5- bit 0 is the length, subsequent bytes are data, and length 0 only sends one byte and returns an answer 140 | #define mCH341A_CMD_I2C_STM_IN 0xC0 // I2C interface command flow: input data, bit 5-bit 0 is the length, and 0 length only receives one byte and sends no response 141 | #define mCH341A_CMD_I2C_STM_MAX (min(0x3F, mCH341_PACKET_LENGTH)) // The maximum length of input and output data of a single command in the command stream of I2C interface 142 | #define mCH341A_CMD_I2C_STM_SET 0x60 // Command flow of I2C interface: set parameters, bit 2=i/o number of SPI (0= single input single output, 1= double input double output), bit 1 0=i2c speed (00= low speed, 01= standard, 10= fast, 11= high speed) 143 | #define mCH341A_CMD_I2C_STM_US 0x40 // Command flow of I2C interface: delay in microseconds, bit 3- bit 0 as delay value 144 | #define mCH341A_CMD_I2C_STM_MS 0x50 // Command flow of I2C interface: delay in microseconds, bit 3-bit 0 as delay value 145 | #define mCH341A_CMD_I2C_STM_DLY 0x0F // Maximum value of single command delay of command flow of I2C interface 146 | #define mCH341A_CMD_I2C_STM_END 0x00 // Command flow of I2C interface: Command package ends in advance 147 | 148 | #define mCH341A_CMD_UIO_STM_IN 0x00 // Command flow of UIO interface: input data D7-D0 149 | #define mCH341A_CMD_UIO_STM_DIR 0x40 // Command flow of UIO interface: set i/o direction D5-D0, bit 5- bit 0 as direction data 150 | #define mCH341A_CMD_UIO_STM_OUT 0x80 // Command flow of UIO interface: output data D5-D0, bit 5-bit 0 is data 151 | #define mCH341A_CMD_UIO_STM_US 0xC0 // Command flow of UIO interface: delay in microseconds, bit 5- bit 0 as delay value 152 | #define mCH341A_CMD_UIO_STM_END 0x20 // Command flow of UIO interface: Command package ends in advance 153 | 154 | #define MAX_DEVICE_PATH_SIZE 128 // Maximum number of characters for device name 155 | #define MAX_DEVICE_ID_SIZE 64 // Maximum number of characters for device ID 156 | #endif _CH341_DLL_H 157 | 158 | // Drive Interface 159 | #define CH347_USB_VENDOR 0 160 | #define CH347_USB_HID 2 161 | #define CH347_USB_VCP 3 162 | 163 | // CH347_USB_VENDOR support CH341/CH347T/CH347F/CH339W 164 | #define CHIP_TYPE_CH341 0 165 | #define CHIP_TYPE_CH347 1 166 | #define CHIP_TYPE_CH347F 2 167 | #define CHIP_TYPE_CH339W 3 168 | #define CHIP_TYPE_CH347T CHIP_TYPE_CH347 169 | 170 | // Chip Function Interface Number 171 | #define CH347_FUNC_UART 0 172 | #define CH347_FUNC_SPI_IIC 1 173 | #define CH347_FUNC_JTAG_IIC 2 174 | #define CH347_FUNC_JTAG_IIC_SPI 3 // CH347F SPI&I2C&JTAG interfaces can be used simultaneously 175 | 176 | #define DEFAULT_READ_TIMEOUT 500 // Default read timeout (mS) 177 | #define DEFAULT_WRITE_TIMEOUT 500 // Default write timeout (mS) 178 | 179 | #define mCH347_PACKET_LENGTH 512 // Length of packets supported by CH347 180 | #pragma pack(1) 181 | // SPI Controller Configuration 182 | typedef struct _SPI_CONFIG { 183 | UCHAR iMode; // 0-3:SPI Mode0/1/2/3 184 | UCHAR iClock; // 0=60MHz, 1=30MHz, 2=15MHz, 3=7.5MHz, 4=3.75MHz, 5=1.875MHz, 6=937.5KHz, 7=468.75KHz 185 | UCHAR iByteOrder; // 0=LSB first(LSB), 1=MSB first(MSB) 186 | USHORT iSpiWriteReadInterval; // The SPI interface routinely reads and writes data command, the unit is uS 187 | UCHAR iSpiOutDefaultData; // SPI MOSI default data when it reads data 188 | ULONG iChipSelect; // Piece of selected control, if bit 7 is 0, CS selection control is ignored, if bit 7 is 1, the parameter is valid: 189 | // Bit 1 Bit 0 is 00/01 and CS1/CS2 pins are selected as low level active chip options respectively 190 | UCHAR CS1Polarity; // Bit 0: CS1 polarity control: 0: effective low level; 1: effective lhigh level; 191 | UCHAR CS2Polarity; // Bit 0: CS2 polarity control: 0: effective low level; 1: effective lhigh level; 192 | USHORT iIsAutoDeativeCS; // Whether to undo CS selection automatically after the operation is complete 193 | USHORT iActiveDelay; // Set the latency for read/write operations after CS selection,the unit is uS 194 | ULONG iDelayDeactive; // Delay time for read and write operations after CS selection is unselected,the unit is uS 195 | } mSpiCfgS, *mPSpiCfgS; 196 | 197 | // Device Information 198 | typedef struct _DEV_INFOR { 199 | UCHAR iIndex; // Current open index 200 | UCHAR DevicePath[MAX_PATH]; // Device link name, used for CreateFile 201 | UCHAR UsbClass; // 0:CH347_USB_CH341, 2:CH347_USB_HID,3:CH347_USB_VCP 202 | UCHAR FuncType; // 0:CH347_FUNC_UART, 1:CH347_FUNC_SPI_I2C, 2:CH347_FUNC_JTAG_I2C 203 | CHAR DeviceID[64]; // USB\VID_xxxx&PID_xxxx 204 | UCHAR ChipMode; // Chip Mode, 0:Mode0(UART0/1); 1:Mode1(Uart1+SPI+I2C); 2:Mode2(HID Uart1+SPI+I2C) 3:Mode3(Uart1+Jtag+I2C) 4:CH347F(Uart*2+Jtag/SPI/I2C) 205 | HANDLE DevHandle; // Device handle 206 | USHORT BulkOutEndpMaxSize; // Upload endpoint size 207 | USHORT BulkInEndpMaxSize; // downstream endpoint size 208 | UCHAR UsbSpeedType; // USB Speed type, 0:FS,1:HS,2:SS 209 | UCHAR CH347IfNum; // USB interface number: CH347T: IF0:UART; IF1:SPI/IIC/JTAG/GPIO 210 | // CH347F: IF0:UART0; IF1:UART1; IF2:SPI/IIC/JTAG/GPIO 211 | UCHAR DataUpEndp; // The endpoint address 212 | UCHAR DataDnEndp; // The endpoint address 213 | CHAR ProductString[64]; // Product string in USB descriptor 214 | CHAR ManufacturerString[64]; // Manufacturer string in USB descriptor 215 | ULONG WriteTimeout; // USB write timeout 216 | ULONG ReadTimeout; // USB read timeout 217 | CHAR FuncDescStr[64]; // Interface functions 218 | UCHAR FirewareVer; // Firmware version 219 | 220 | } mDeviceInforS, *mPDeviceInforS; 221 | #pragma pack() 222 | 223 | // CH347 Mode Common Function,support open,close,USB read,USB written and HID of all modes. 224 | // Open USB device 225 | HANDLE WINAPI CH347OpenDevice(ULONG DevI); // Specifies the device number 226 | 227 | // Close USB device 228 | BOOL WINAPI CH347CloseDevice(ULONG iIndex); // Specifies the device number 229 | 230 | // Get the USB serial number of the device 231 | BOOL WINAPI CH347GetSerialNumber(ULONG iIndex, // Specifies the device number 232 | PUCHAR iSerialNumberStr); // Point to the obtained device serial number 233 | 234 | // Get Device Information 235 | BOOL WINAPI CH347GetDeviceInfor(ULONG iIndex, mDeviceInforS *DevInformation); 236 | 237 | // Get CH347 type:0:CHIP_TYPE_CH341,1:CHIP_TYPE_CH347/CHIP_TYPE_CH347T,2:CHIP_TYPE_CH347F,3:CHIP_TYPE_CH339W 238 | UCHAR WINAPI CH347GetChipType(ULONG iIndex); 239 | 240 | // Obtain driver version, library version, device version and chip type(CH341(FS)/CH347HS) 241 | BOOL WINAPI CH347GetVersion(ULONG iIndex, 242 | PUCHAR iDriverVer, 243 | PUCHAR iDLLVer, 244 | PUCHAR ibcdDevice, 245 | PUCHAR iChipType); // CHIP_TYPE_CH341/7 246 | 247 | typedef VOID(CALLBACK *mPCH347_NOTIFY_ROUTINE)( // Device event notification callback routine 248 | ULONG iEventStatus); // Device event and current status (refer to the description below): 0=Device unplug event, 3=Device insertion event 249 | 250 | #define CH347_DEVICE_ARRIVAL 3 // Device insertion event,has been inserted 251 | #define CH347_DEVICE_REMOVE_PEND 1 // Device wil be unplugged 252 | #define CH347_DEVICE_REMOVE 0 // Device unplug event,has been pulled out 253 | 254 | BOOL WINAPI CH347SetDeviceNotify( // Configure device event notifier 255 | ULONG iIndex, // Specifies the device number,bit 0 corresponds to the first device 256 | PCHAR iDeviceID, // Optional parameter,pointing to a string terminated by \0,specifying the ID of the monitored device 257 | mPCH347_NOTIFY_ROUTINE iNotifyRoutine); // Specifies the port device event callback program. If it is NULL, the event notification will be canceled. Otherwise, the program will be called when an event is detected. 258 | 259 | // Read USB data block 260 | BOOL WINAPI CH347ReadData(ULONG iIndex, // Specifies the device number 261 | PVOID oBuffer, // Points to a buffer large enough to save the read data 262 | PULONG ioLength); // Points to the length unit, the length to be read when input is the length to be read, and the actual read length after return 263 | 264 | // Write USB data block 265 | BOOL WINAPI CH347WriteData(ULONG iIndex, // Specifies the device number 266 | PVOID iBuffer, // Points to a buffer large enough to save the written data 267 | PULONG ioLength); // Points to the length unit,the input length is the intended length, and the return length is the actual length 268 | 269 | // Set the timeout of USB data read and write 270 | BOOL WINAPI CH347SetTimeout(ULONG iIndex, // Specifies the device number 271 | ULONG iWriteTimeout, // Specifies the timeout for USB to write data blocks, in milliseconds mS,0xFFFFFFFF specifies no timeout (default) 272 | ULONG iReadTimeout); // Specifies the timeout for USB to read data blocks, in milliseconds mS,0xFFFFFFFF specifies no timeout (default) 273 | 274 | /***************SPI********************/ 275 | // SPI Controller Initialization 276 | BOOL WINAPI CH347SPI_Init(ULONG iIndex, mSpiCfgS *SpiCfg); 277 | 278 | // Set the SPI clock frequency, and after calling this interface, you need to call CH347SPI_Init again for reinitialisation. 279 | BOOL WINAPI CH347SPI_SetFrequency(ULONG iIndex, // Specify device number 280 | ULONG iSpiSpeedHz);// Set the SPI clock, with the unit in Hz. 281 | 282 | // CH347F set the SPI databit 283 | BOOL WINAPI CH347SPI_SetDataBits(ULONG iIndex, // Specify device number 284 | UCHAR iDataBits); // 0=8bit,1=16bit 285 | 286 | // Get SPI controller configuration information 287 | BOOL WINAPI CH347SPI_GetCfg(ULONG iIndex, mSpiCfgS *SpiCfg); 288 | 289 | // Before setting the chip selection status, call CH347SPI_Init to set CS 290 | BOOL WINAPI CH347SPI_ChangeCS(ULONG iIndex, // Specify device number 291 | UCHAR iStatus); // 0=Cancel the piece to choose,1=Set piece selected 292 | 293 | // Set SPI slice selection 294 | BOOL WINAPI CH347SPI_SetChipSelect(ULONG iIndex, // Specify device number 295 | USHORT iEnableSelect, // The lower octet is CS1 and the higher octet is CS2. A byte value of 1= sets CS, 0= ignores this CS setting 296 | USHORT iChipSelect, // The lower octet is CS1 and the higher octet is CS2. A byte value of 1= sets CS, 0= ignores this CS setting 297 | ULONG iIsAutoDeativeCS, // The lower 16 bits are CS1 and the higher 16 bits are CS2. Whether to undo slice selection automatically after the operation is complete 298 | ULONG iActiveDelay, // The lower 16 bits are CS1 and the higher 16 bits are CS2. Set the latency of read/write operations after chip selection, the unit is us 299 | ULONG iDelayDeactive); // The lower 16 bits are CS1 and the higher 16 bits are CS2. Delay time for read and write operations after slice selection the unit is us 300 | 301 | // SPI4 write data 302 | BOOL WINAPI CH347SPI_Write(ULONG iIndex, // Specify device number 303 | ULONG iChipSelect, // CS selection control, when bit 7 is 0, slice selection control is ignored, and when bit 7 is 1, slice selection operation is performed 304 | ULONG iLength, // Number of bytes of data to be transferred 305 | ULONG iWriteStep, // The length of a single block to be read 306 | PVOID ioBuffer); // Point to a buffer to place the data to be written out from MOSI 307 | 308 | // SPI4 read data, no need to write data first, much more efficient than CH347SPI_WriteRead 309 | BOOL WINAPI CH347SPI_Read(ULONG iIndex, // Specify device number 310 | ULONG iChipSelect, // Slice selection control, when bit 7 is 0, slice selection control is ignored, and when bit 7 is 1, slice selection operation is performed 311 | ULONG oLength, // Number of bytes to send 312 | PULONG iLength, // Number of bytes of data to be read in 313 | PVOID ioBuffer); // Points to a buffer that place the data to be written out from DOUT, return the data read in from DIN 314 | 315 | // Handle SPI data stream 4-wire interface 316 | BOOL WINAPI CH347SPI_WriteRead(ULONG iIndex, // Specify the device number 317 | ULONG iChipSelect, // Selection control, if the film selection control bit 7 is 0, ignore the film selection control bit 7 is 1 and operate the film selection 318 | ULONG iLength, // Number of bytes of data to be transferred 319 | PVOID ioBuffer); // Points to a buffer that place the data to be written out from DOUT, return the data read in from DIN 320 | 321 | // place the data to be written from MOSI, return the data read in from MISO 322 | BOOL WINAPI CH347StreamSPI4(ULONG iIndex, // Specify the device number 323 | ULONG iChipSelect, // Film selection control, if bit 7 is 0, slice selection control is ignored.If bit 7 is 1, the parameter is valid:Bit 1 bit 0 is 00/01/10. Select D0/D1/D2 pins as low level active chip options respectively 324 | ULONG iLength, // Number of bytes of data to be transferred 325 | PVOID ioBuffer); // Points to a buffer, places data to be written out from DOUT, and returns data to be read in from DIN 326 | 327 | /***************JTAG********************/ 328 | // JTAG interface initialization, set mode and speed 329 | BOOL WINAPI CH347Jtag_INIT(ULONG iIndex, 330 | UCHAR iClockRate); // Communication speed; The value ranges from 0 to 5. A larger value indicates a faster communication speed 331 | 332 | // Gets Jtag speed configuration 333 | BOOL WINAPI CH347Jtag_GetCfg(ULONG iIndex, // Specify the device number 334 | UCHAR *ClockRate); // Communication speed; The value ranges from 0 to 5. A larger value indicates a faster communication speed 335 | 336 | // Function that performs state switching by changing the value of TMS 337 | BOOL WINAPI CH347Jtag_TmsChange(ULONG iIndex, // Specify the device number 338 | PUCHAR tmsValue, // The TMS values that need to be switched form one byte of data in the switching order 339 | ULONG Step, // The number of bit values that need to be read from the tmsValue value 340 | ULONG Skip); // Count from the skip bit of tmsValue to step 341 | 342 | // Read/write data in the shift-dr/ir state and Exit DR/IR after the command is executed 343 | // State machine :Shift-DR/ ir.rw.->Exit DR/IR 344 | BOOL WINAPI CH347Jtag_IoScan(ULONG iIndex, 345 | PUCHAR DataBits, // Bits of data that need to be transferred 346 | ULONG DataBitsNb, // The number of bits of data to be transmitted 347 | BOOL IsRead); // Whether to read data 348 | 349 | // Switch to the shift-dr/ir state for reading/writing. After the command is executed, if the last packet is displayed, switch to Exit DR/IR. If not, stop at Shift-DR/IR 350 | // State machine :Shift-DR/IR.RW.. ->[Exit DR/IR] 351 | BOOL WINAPI CH347Jtag_IoScanT(ULONG iIndex, // Specify the device number 352 | PUCHAR DataBits, // Bits of data that need to be transferred 353 | ULONG DataBitsNb, // The number of bits of data to be transmitted 354 | BOOL IsRead, // Whether to read data 355 | BOOL IsLastPkt); // Whether to the last packet 356 | 357 | // Reset the Tap status function. The TMS is high for more than six clocks, Tap state on Test-Logic Reset 358 | ULONG WINAPI CH347Jtag_Reset(ULONG iIndex); 359 | 360 | // Perform TRST operations to reset hardware 361 | BOOL WINAPI CH347Jtag_ResetTrst(ULONG iIndex, // Specify the device number 362 | BOOL iLevel); // 0=Set lower,1=Set High 363 | 364 | // Bit band mode JTAG IR/DR data read and write. Suitable for reading and writing small amounts of data. Such as command operation, state machine switching and other control transmission. For batch data transmission, you are advised to use CH347Jtag_WriteRead_Fast 365 | // Command packages are read and written in batches in 4096 bytes 366 | // The state machine: Run-Test->Shift-IR/DR..->Exit IR/DR -> Run-Test 367 | BOOL WINAPI CH347Jtag_WriteRead(ULONG iIndex, // Specify the device number 368 | BOOL IsDR, // =TRUE: DR data read/write, =FALSE:IR data read/write 369 | ULONG iWriteBitLength, // Write length, the length to be written 370 | PVOID iWriteBitBuffer, // Points to a buffer to place data ready to be written out 371 | PULONG oReadBitLength, // Points to the length unit and returns the length actually read 372 | PVOID oReadBitBuffer); // Points to a buffer large enough to hold the read data 373 | 374 | // JTAG IR/DR data batch read and write The IR/DR data is used for multi-byte continuous read and write. For example, download firmware. The hardware has four buffers. If the buffer is written before the buffer is read, the length cannot exceed 4096 bytes. Buffer size can be adjusted 375 | // The state machine: Run-Test->Shift-IR/DR..->Exit IR/DR -> Run-Test 376 | BOOL WINAPI CH347Jtag_WriteRead_Fast(ULONG iIndex, // Specify the device number 377 | BOOL IsDR, // =TRUE: in SHIFT-DR read/write, =FALSE:IR data read/write 378 | ULONG iWriteBitLength, // Write length. The length to be written 379 | PVOID iWriteBitBuffer, // Points to a buffer to place data ready to be written out 380 | PULONG oReadBitLength, // Point to the length unit and return the actual read length 381 | PVOID oReadBitBuffer); // Points to a buffer large enough to hold the read data 382 | 383 | // Bitband mode JTAG IR/DR Data read and write. It is suitable for reading and writing small amounts of data. Such as instruction operation, state machine switching and other control class transmission. For batch data transfer, CH347Jtag_WriteRead_Fast is recommended 384 | // State switch:Run-Test-> Shift-IR/DR..->Exit IR/DR -> Run-Test 385 | BOOL WINAPI CH347Jtag_WriteReadEx(ULONG iIndex, // Specify the device number 386 | BOOL IsInDrOrIr, // =TRUE: In SHIFT-DR read/write ==FALSE: Run-Test->Shift-IR/DR.(data read/write).->Exit IR/DR -> Run-Test 387 | BOOL IsDR, // =TRUE: in SHIFT-DR read/write, =FALSE:IR data read/write 388 | ULONG iWriteBitLength, // Write length. The length to be written 389 | PVOID iWriteBitBuffer, // Points to a buffer to place data ready to be written out 390 | PULONG oReadBitLength, // Point to the length unit and return the actual read length 391 | PVOID oReadBitBuffer); // 392 | 393 | // JTAG IR/DR Read and write data in batches. It is used to read and write multi-byte data continuously. For example, download JTAG firmware. Because the hardware has 4K buffer, such as write before read, the length does not exceed 4096 bytes. The buffer size can be adjusted 394 | // State switch:Run-Test->Shift-IR/DR..->Exit IR/DR -> Run-Test 395 | BOOL WINAPI CH347Jtag_WriteRead_FastEx(ULONG iIndex, // Specify the device number 396 | BOOL IsInDrOrIr, // =TRUE: In SHIFT-DR read/write ==FALSE: Run-Test->Shift-IR/DR.(data read/write).->Exit IR/DR -> Run-Test 397 | BOOL IsDR, // =TRUE: in SHIFT-DR read/write, =FALSE:IR data read/write 398 | ULONG iWriteBitLength, // Write length. The length to be written 399 | PVOID iWriteBitBuffer, // Points to a buffer to place data ready to be written out 400 | PULONG oReadBitLength, // Point to the length unit and return the actual read length 401 | PVOID oReadBitBuffer); // Points to a buffer large enough to hold the read data 402 | 403 | // Single-step switching of the JTAG state machine must be executed in order. 404 | BOOL WINAPI CH347Jtag_SwitchTapState(UCHAR TapState); // state to switch 405 | // 0:Test-Logic Reset,1:Run-Test/Idle,2:Run-Test/Idle -> Shift-DR,3:Shift-DR -> Run-Test/Idle 406 | // 4:Run-Test/Idle -> Shift-IR, 5:Shift-IR -> Run-Test/Idle, 6:Exit1-DR/IR -> Update-DR/IR -> Run-Test/Idle 407 | 408 | // Single-step switching of the JTAG state machine allows for the specification of the operating device iIndex. 409 | BOOL WINAPI CH347Jtag_SwitchTapStateEx(ULONG iIndex, // Specify the device number 410 | UCHAR TapState); // state to switch 411 | 412 | // JTAG DR Write, in bytes, for multi-byte sequential reads and writes. For example, download firmware. 413 | // The state machine: Run-Test->Shift-DR..->Exit DR -> Run-Test 414 | BOOL WINAPI CH347Jtag_ByteWriteDR(ULONG iIndex, // Specify the device number 415 | ULONG iWriteLength, // Write length, length of bytes to be written 416 | PVOID iWriteBuffer); // Points to a buffer to place data ready to be written out 417 | 418 | // JTAG DR Read, read multiple bytes consecutively in bytes. 419 | // The state machine: Run-Test->Shift-DR..->Exit DR -> Run-Test 420 | BOOL WINAPI CH347Jtag_ByteReadDR(ULONG iIndex, // Specify the device number 421 | PULONG oReadLength, // Points to the length unit and returns the length of the bytes actually read 422 | PVOID oReadBuffer); // Points to a buffer large enough to hold the read data 423 | 424 | // JTAG IR write, written in bytes, multiple bytes are written consecutively. 425 | // The state machine: Run-Test->Shift-IR..->Exit IR -> Run-Test 426 | BOOL WINAPI CH347Jtag_ByteWriteIR(ULONG iIndex, // Specify the CH347 device number 427 | ULONG iWriteLength, // Write length, the length of bytes to be written 428 | PVOID iWriteBuffer); // Points to a buffer to place data ready to be written out 429 | 430 | // JTAG IR read, readen in bytes, multiple bytes are readen consecutively. 431 | // The state machine: Run-Test->Shift-IR..->Exit IR -> Run-Test 432 | BOOL WINAPI CH347Jtag_ByteReadIR(ULONG iIndex, // Specify the device number 433 | PULONG oReadLength, // Points to the length unit and returns the length of the bytes actually read 434 | PVOID oReadBuffer); // Points to a buffer large enough to hold the read data 435 | 436 | // Bit band mode JTAG DR data write. Suitable for reading and writing small amounts of data. Such as command operation, state machine switching and other control transmission. For batch data transmission, CH347Jtag_ByteWriteDR is recommended 437 | // The state machine: Run-Test->Shift-DR..->Exit DR -> Run-Test 438 | BOOL WINAPI CH347Jtag_BitWriteDR(ULONG iIndex, // Specify the device number 439 | ULONG iWriteBitLength, // Points to the length unit and returns the length of the bytes actually read 440 | PVOID iWriteBitBuffer); // Points to a buffer large enough to hold the read data 441 | 442 | // Bit band mode JTAG IR data write. Suitable for reading and writing small amounts of data. Such as command operation, state machine switching and other control transmission. For batch data transmission, CH347Jtag_ByteWriteIR is recommended 443 | // The state machine: Run-Test->Shift-IR..->Exit IR -> Run-Test 444 | BOOL WINAPI CH347Jtag_BitWriteIR(ULONG iIndex, // Specify the device number 445 | ULONG iWriteBitLength, // Points to the length unit and returns the length of the bytes actually read 446 | PVOID iWriteBitBuffer); // Points to a buffer large enough to hold the read data 447 | 448 | // Bit band mode JTAG IR data read. Suitable for reading and writing small amounts of data. Such as command operation, state machine switching, etc. For batch data transmission, CH347Jtag_ByteReadIR is recommended. 449 | // The state machine: Run-Test->Shift-IR..->Exit IR -> Run-Test 450 | BOOL WINAPI CH347Jtag_BitReadIR(ULONG iIndex, // Specify the device number 451 | PULONG oReadBitLength, // Points to the length unit and returns the length of the bytes actually read 452 | PVOID oReadBitBuffer); // Points to a buffer large enough to hold the read data 453 | 454 | // Bit band mode JTAG DR data read. Suitable for reading and writing small amounts of data. For batch and high-speed data transmission, CH347Jtag_ByteReadDR is recommended 455 | // The state machine: Run-Test->Shift-DR..->Exit DR -> Run-Test 456 | BOOL WINAPI CH347Jtag_BitReadDR(ULONG iIndex, // Specify the device number 457 | PULONG oReadBitLength, // Points to the length unit and returns the length of the bytes actually read 458 | PVOID oReadBitBuffer); // Points to a buffer large enough to hold the read data 459 | 460 | /***************GPIO********************/ 461 | // Get the GPIO direction and pin level of CH347 462 | BOOL WINAPI CH347GPIO_Get(ULONG iIndex, 463 | UCHAR *iDir, // Pin direction: GPIo0-7 corresponding bit 0-7,0: input; 1: output 464 | UCHAR *iData); // GPIO0 level: GPIO0-7 corresponding bit 0-7,0: low level; 1: high level 465 | 466 | // Set the GPIO direction and pin level of CH347 467 | BOOL WINAPI CH347GPIO_Set(ULONG iIndex, 468 | UCHAR iEnable, // Data validity flag: The corresponding bits 0-7 correspond to GPIO0-7. 469 | UCHAR iSetDirOut, // Sets the I/O direction, with pin 0 corresponding to input and pin 1 corresponding to output. Gpio0-7 corresponds to bits 0-7. 470 | UCHAR iSetDataOut); // Outputs data. If the I/O direction is output, then a pin outputs low level at a clear 0 and high level at a position 1 471 | 472 | typedef VOID(CALLBACK *mPCH347_INT_ROUTINE)( // Interrupt service routine 473 | PUCHAR iStatus); // For interrupt status data, refer to the bit description below 474 | // 8 byte GPIO0-7 pin status, the bits per byte are defined as follows. 475 | // Bit7:Current GPIO0 direction, 0:Input; 1:Output 476 | // Bit6:Current GPIO0 level, 0:Low level;1:High level 477 | // Bit5:Whether the current GPIO0 is set to interrupt; 0:Query mode; 1:Interrupt mode 478 | // Bit4-3:Set the GPIO0 interrupt mode, 00:Falling edge trigger; 01:Rising edge trigger; 10:Double edge trigger;11: reserved; 479 | // Bit2-0:reserved; 480 | 481 | // Set GPIO interrupt service routine 482 | BOOL WINAPI CH347SetIntRoutine(ULONG iIndex, // Specify the device number 483 | UCHAR Int0PinN, // INT0 GPIO pin number greater than 7: Disable this interrupt source. 0-7 corresponds to gpio0-7 484 | UCHAR Int0TripMode, // INT0 type: 00:Falling edge trigger; 01:Rising edge trigger; 02:Double edge trigger; 03:reserve; 485 | UCHAR Int1PinN, // INT1 GPIO pin number. If it is greater than 7, this interrupt source is not enabled. 0-7 corresponds to gpio0-7 486 | UCHAR Int1TripMode, // INT1 type: 00:Falling edge trigger; 01:Rising edge trigger; 02:Double edge trigger; 03:reserve; 487 | mPCH347_INT_ROUTINE iIntRoutine); // Specifies the interrupt service program. If NULL is specified, the interrupt service is canceled. Otherwise, the program is invoked when the interrupt is performed 488 | 489 | // Read interrupt data 490 | BOOL WINAPI CH347ReadInter(ULONG iIndex, // Specify the device number 491 | PUCHAR iStatus); // Refers to the 8-byte unit used to hold read GPIO pin state data, refer to the bit instructions below 492 | 493 | // Abandon interrupt data read operation 494 | BOOL WINAPI CH347AbortInter(ULONG iIndex); // Specify the device number 495 | 496 | // Enter the IAP firmware upgrade mode 497 | BOOL WINAPI CH347StartIapFwUpate(ULONG iIndex, 498 | ULONG FwSize); // The length of the firmware 499 | 500 | /**************HID/VCP Serial Port*********************/ 501 | // Open serial port 502 | HANDLE WINAPI CH347Uart_Open(ULONG iIndex); 503 | 504 | // Close serial port 505 | BOOL WINAPI CH347Uart_Close(ULONG iIndex); 506 | 507 | // Set the device event notification program 508 | BOOL WINAPI CH347Uart_SetDeviceNotify( 509 | ULONG iIndex, // Specify the device number, 0 corresponds to the first device 510 | PCHAR iDeviceID, // Optional parameter,points to a string specifying the ID of the device to be monitored, terminated with \0 511 | mPCH347_NOTIFY_ROUTINE iNotifyRoutine); // Specifies the device event callback. NULL cancels event notification, otherwise it will be called when an event is detected 512 | 513 | // Obtain UART hardware configuration 514 | BOOL WINAPI CH347Uart_GetCfg(ULONG iIndex, // Specify the device number 515 | PULONG BaudRate, // Baud rate 516 | PUCHAR ByteSize, // Data bits (5,6,7,8,16) 517 | PUCHAR Parity, // Parity bits(0:None; 1:Odd; 2:Even; 3:Mark; 4:Space) 518 | PUCHAR StopBits, // Stop bits (0:1 stop bits; 1:1.5 stop bit; 2:2 stop bit); 519 | PUCHAR ByteTimeout); // Byte timeout 520 | 521 | // Set UART configuration 522 | BOOL WINAPI CH347Uart_Init(ULONG iIndex, // Specify the device number 523 | DWORD BaudRate, // Baud rate 524 | UCHAR ByteSize, // Data bits (5,6,7,8,16) 525 | UCHAR Parity, // Check bit (0:None; 1:Odd; 2:Even; 3:Mark; 4:Space) 526 | UCHAR StopBits, // Stop bits 0:1 Stop bit; 1:1.5 stop bit; 2:2 stop bit); 527 | UCHAR ByteTimeout); // Byte Timeout duration, in unit of 100uS 528 | 529 | // Set the timeout of USB data read and write 530 | BOOL WINAPI CH347Uart_SetTimeout(ULONG iIndex, // Specify the device number 531 | ULONG iWriteTimeout, // Specifies the timeout for USB to write data blocks, in milliseconds mS,0xFFFFFFFF specifies no timeout (default) 532 | ULONG iReadTimeout); // Specifies the timeout for USB to read data blocks, in milliseconds mS,0xFFFFFFFF specifies no timeout (default) 533 | 534 | // Read data block 535 | BOOL WINAPI CH347Uart_Read(ULONG iIndex, // Specify the device number 536 | PVOID oBuffer, // Points to a buffer large enough to hold the read data 537 | PULONG ioLength); // Refers to the length unit. The input is the length to be read and the return is the actual length to be read 538 | 539 | // Write out blocks of data 540 | BOOL WINAPI CH347Uart_Write(ULONG iIndex, // Specify the device number 541 | PVOID iBuffer, // Points to a buffer to place data ready to be written out 542 | PULONG ioLength); // Point to the length unit. The input is the intended length and the return is the actual length 543 | 544 | // Query how many bytes are unfetched in the read buffer 545 | BOOL WINAPI CH347Uart_QueryBufUpload(ULONG iIndex, // Specify the device number 546 | LONGLONG *RemainBytes); 547 | 548 | // Obtaining Device Information 549 | BOOL WINAPI CH347Uart_GetDeviceInfor(ULONG iIndex, mDeviceInforS *DevInformation); 550 | 551 | /********I2C***********/ 552 | // Set the serial port flow mode 553 | BOOL WINAPI CH347I2C_Set(ULONG iIndex, // Specify the device number 554 | ULONG iMode); // See downlink for the specified mode 555 | // bit 1-bit 0: I2C interface speed /SCL frequency, 00= low speed /20KHz,01= standard /100KHz(default),10= fast /400KHz,11= high speed /750KHz 556 | // Other reservations, must be 0 557 | 558 | // Set I2C Clock Stretch 559 | BOOL WINAPI CH347I2C_SetStretch(ULONG iIndex, // Specify the device number 560 | BOOL iEnable); // I2C Clock Stretch enable, 1:enable,0:disable 561 | 562 | // Set the hardware asynchronous delay to a specified number of milliseconds before the next stream operation 563 | BOOL WINAPI CH347I2C_SetDelaymS(ULONG iIndex, // Specify the device number 564 | ULONG iDelay); // Specifies the delay duration (mS) 565 | 566 | // Set the I2C pins drive mode. 567 | BOOL WINAPI CH347I2C_SetDriverMode(ULONG iIndex, // Specify the device number 568 | UCHAR iMode); // 0=open-drain mode; 1=push-pull mode 569 | 570 | // Process I2C data stream, 2-wire interface, clock line for SCL pin, data line for SDA pin 571 | BOOL WINAPI CH347StreamI2C(ULONG iIndex, // Specify the device number 572 | ULONG iWriteLength, // The number of bytes of data to write 573 | PVOID iWriteBuffer, // Points to a buffer to place data ready to be written out, the first byte is usually the I2C device address and read/write direction bit 574 | ULONG iReadLength, // Number of bytes of data to be read 575 | PVOID oReadBuffer); // Points to a buffer to place data ready to be read in 576 | 577 | // Process I2C data stream, 2-wire interface, SCL pin for clock line, SDA pin for data line (quasi-bidirectional I/O), speed of about 56K bytes, and return the number of ACK obtained by the host side 578 | BOOL WINAPI CH347StreamI2C_RetACK(ULONG iIndex, // Specify the device number 579 | ULONG iWriteLength, // The number of bytes of data to write 580 | PVOID iWriteBuffer, // Points to a buffer to place data ready to be written out, the first byte is usually the I2C device address and read/write direction bit 581 | ULONG iReadLength, // Number of bytes of data to be read 582 | PVOID oReadBuffer, // Points to a buffer to place data ready to be read in 583 | PULONG rAckCount); // Refers to the ACK value returned by read/write 584 | 585 | #ifndef _CH341_DLL_H 586 | typedef enum _EEPROM_TYPE { // EEPROM type 587 | ID_24C01, 588 | ID_24C02, 589 | ID_24C04, 590 | ID_24C08, 591 | ID_24C16, 592 | ID_24C32, 593 | ID_24C64, 594 | ID_24C128, 595 | ID_24C256, 596 | ID_24C512, 597 | ID_24C1024, 598 | ID_24C2048, 599 | ID_24C4096 600 | } EEPROM_TYPE; 601 | #endif 602 | 603 | // Reads data blocks from EEPROM at a speed of about 56 KB 604 | BOOL WINAPI CH347ReadEEPROM(ULONG iIndex, // Specify the device number 605 | EEPROM_TYPE iEepromID, // Specifies the EEPROM model 606 | ULONG iAddr, // Specifies the address of data unit 607 | ULONG iLength, // Number of bytes of data to be read 608 | PUCHAR oBuffer); // Points to a buffer to place data ready to be read in 609 | 610 | // Writes a data block to the EEPROM 611 | BOOL WINAPI CH347WriteEEPROM(ULONG iIndex, // Specify the device number 612 | EEPROM_TYPE iEepromID, // Specifies the EEPROM model 613 | ULONG iAddr, // Specifies the address of data unit 614 | ULONG iLength, // Number of bytes of data to be written out 615 | PUCHAR iBuffer); // Points to a buffer to place data ready to be written out 616 | 617 | // Set the low cycle delay time for the 8th clock, applicable only to CH347T. 618 | BOOL WINAPI CH347I2C_SetAckClk_DelayuS(ULONG iIndex, // Specify the device number 619 | ULONG iDelay); // Specified delay in microseconds. 620 | 621 | // This function is used to query the current enable status of each interface function of the CH339W chip with the specified index. 622 | // Return value bit definition: 623 | // Bit 7 (0x80): USB to JTAG enable status (1 = enabled, 0 = disabled) 624 | // Bit 6 (0x40): USB to SPI enable status (1 = enabled, 0 = disabled) 625 | // Bit 5 (0x20): USB to UART enable (without flow control) (1 = enabled, 0 = disabled) 626 | // Bit 4 (0x10): USB to UART flow control enable (1 = enabled, 0 = disabled) 627 | // Bit 3 (0x08): USB to I2C enable status (1 = enabled, 0 = disabled) 628 | // Bits 2 - 0: Reserved bits 629 | UCHAR WINAPI CH339GetChipFuncState( ULONG iIndex ); // Specify the device number 630 | 631 | #ifdef __cplusplus 632 | } 633 | #endif 634 | 635 | #endif // _CH347_DLL_H 636 | -------------------------------------------------------------------------------- /CH347/amd64/CH347DLLA64.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOT-CAT/xvcd-ch347/e20dd824d1ece541d89a9beb49f340ff24278443/CH347/amd64/CH347DLLA64.lib -------------------------------------------------------------------------------- /CH347/arm64/CH347DLLA64.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOT-CAT/xvcd-ch347/e20dd824d1ece541d89a9beb49f340ff24278443/CH347/arm64/CH347DLLA64.lib -------------------------------------------------------------------------------- /CH347/i386/CH347DLL.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIOT-CAT/xvcd-ch347/e20dd824d1ece541d89a9beb49f340ff24278443/CH347/i386/CH347DLL.lib -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(xvcd_ch347) 3 | 4 | set(CMAKE_C_STANDARD 99) 5 | 6 | set(SOURCES 7 | io_ch347.c 8 | xvcd_win.c 9 | ) 10 | 11 | set(CH347_DIR ${CMAKE_SOURCE_DIR}/CH347) 12 | 13 | include_directories(${CH347_DIR}) 14 | 15 | if(CMAKE_GENERATOR_PLATFORM STREQUAL "arm64") 16 | set(TARGET_ARCH "arm64") 17 | set(CH347_LIB_PATH ${CH347_DIR}/arm64/CH347DLLA64.lib) 18 | elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "x64") 19 | set(TARGET_ARCH "amd64") 20 | set(CH347_LIB_PATH ${CH347_DIR}/amd64/CH347DLLA64.lib) 21 | elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "win32") 22 | set(TARGET_ARCH "386") 23 | set(CH347_LIB_PATH ${CH347_DIR}/i386/CH347DLL.lib) 24 | else() 25 | message(FATAL_ERROR "Unsupported platform: ${CMAKE_GENERATOR_PLATFORM}") 26 | endif() 27 | 28 | set(TARGET_NAME "xvcd_ch347_${TARGET_ARCH}") 29 | 30 | add_executable(${TARGET_NAME} ${SOURCES}) 31 | 32 | target_link_libraries(${TARGET_NAME} ws2_32 ${CH347_LIB_PATH}) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xvcd-ch347 2 | CH347 Xilinx Virtual Cable 3 | xvcd_ch347 of XVC (Xilinx Virtual Cable) protocol based on xvcd (https://github.com/tmbinc/xvcd) 4 | 1. compile 5 | gcc io_ch347.c xvcd_win.c CH347/amd64/CH347DLLA64.lib -lws2_32 -o xvcd_ch347.exe 6 | Regarding CH347DLLA64.DLL, you can obtain it from here : https://www.wch.cn/downloads/CH341PAR_ZIP.html 7 | 2. About clock 8 | Support : KHZ(468.75), KHZ(937.5), MHZ(1.875), MHZ(3.75), MHZ(7.5), MHZ(15), MHZ(30), MHZ(60) 9 | If you need to set a 10MHz clock, choose 15MHz or 7.5MHz, and modify the DEFAULT_JTAG-SPEED variable in xvcd_win. c to correspond to the clock, such as 150000000 10 | 3. If you have a better way to accelerate the speed of this xvcd, please communicate with me for research, or if there are other integrated methods such as Vivado, we can also communicate together. If there are results, we can open them up again to serve more developers, oidcatiot@outlook.com 11 | -------------------------------------------------------------------------------- /io_ch347.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | //#include 5 | #include 6 | #include 7 | #include 8 | #include "io_ch347.h" 9 | #include "CH347/CH347DLL.H" 10 | #define SINGLEDATA 1 11 | #define PACKDATA 0 12 | 13 | #define MAX_BUFFER 512 14 | typedef uint8_t bool; 15 | #define true 1 16 | #define false 0 17 | int usb_xfer(unsigned wlen, unsigned rlen, unsigned* ract, bool defer); 18 | int flush() { return usb_xfer(0, 0, 0, false); } 19 | /*********/ 20 | 21 | #define JTAGIO_STA_OUT_TDI (0x10) 22 | #define JTAGIO_STA_OUT_TMS (0x02) 23 | #define JTAGIO_STA_OUT_TCK (0x01) 24 | #define JTAGIO_STA_OUT_TRST (0x20) 25 | #define TDI_H JTAGIO_STA_OUT_TDI 26 | #define TDI_L 0 27 | #define TMS_H JTAGIO_STA_OUT_TMS 28 | #define TMS_L 0 29 | #define TCK_H JTAGIO_STA_OUT_TCK 30 | #define TCK_L 0 31 | #define TRST_H JTAGIO_STA_OUT_TRST 32 | #define TRST_L 0 33 | 34 | #define CH347_CMD_HEADER 3 // 协议包头长度 35 | // Protocol transmission format: CMD (1 byte)+Length (2 bytes)+Data 36 | #define CH347_CMD_INFO_RD 0xCA // Parameter acquisition, used to obtain firmware version, JTAG interface related parameters, etc 37 | #define CH347_CMD_JTAG_INIT 0xD0 // JTAG Interface Initialization Command 38 | #define CH347_CMD_JTAG_BIT_OP 0xD1 // JTAG interface pin bit control command 39 | #define CH347_CMD_JTAG_BIT_OP_RD 0xD2 // JTAG interface pin bit control and read commands 40 | #define CH347_CMD_JTAG_DATA_SHIFT 0xD3 // JTAG interface data shift command 41 | #define CH347_CMD_JTAG_DATA_SHIFT_RD 0xD4 // JTAG interface data shift and read command 42 | 43 | #define HW_TDO_BUF_SIZE 4096 44 | #define UCMDPKT_DATA_MAX_BYTES_USBHS 507 // The data length contained in each command packet during USB high-speed operation 45 | #define UCMDPKT_DATA_MAX_BITS_USBHS 248 // 248 46 | 47 | #define KHZ(n) ((n) * (unsigned long)(1000)) 48 | #define MHZ(n) ((n) * (unsigned long)(1000000)) 49 | #define GHZ(n) ((n) * (unsigned long)(1000000000)) 50 | 51 | unsigned int iIndex = 0; 52 | 53 | uint8_t ibuf[MAX_BUFFER]; 54 | uint8_t _obuf[MAX_BUFFER]; 55 | uint8_t* obuf = _obuf; 56 | int get_buffer_size() { return get_obuf_length(); } 57 | int get_obuf_length() { return MAX_BUFFER - (obuf - _obuf); } 58 | bool isFull() { return get_obuf_length() == 0; } 59 | int io_init(unsigned int index) 60 | { 61 | int RetVal; 62 | mDeviceInforS DevInfor = {0}; 63 | 64 | // Open the CH347 65 | if (CH347OpenDevice(index) != INVALID_HANDLE_VALUE) { 66 | printf("Open CH347 Succes.\n"); 67 | } else { 68 | printf("Open CH347 fail.\n"); 69 | return -1; 70 | } 71 | 72 | // Set the time for USB timeout return 73 | CH347SetTimeout(index, 1000, 1000); 74 | 75 | iIndex = index; 76 | 77 | // Init the CH347 default clock rate : 3.75MHz 78 | RetVal = CH347Jtag_INIT(iIndex, 3); 79 | if (!RetVal) 80 | return -1; 81 | printf("CH347:[%d] init done.\n", index); 82 | 83 | return 0; 84 | } 85 | 86 | int io_set_period(unsigned int index, unsigned int period) 87 | { 88 | int i = 0; 89 | int clockIndex = 0; 90 | int RetVal; 91 | long clock_rate = 1000000000 / period; 92 | int speed_clock[] = { KHZ(468.75), KHZ(937.5), MHZ(1.875), MHZ(3.75), MHZ(7.5), MHZ(15), MHZ(30), MHZ(60) }; 93 | // int speed_clock[] = {MHZ(1.875), MHZ(3.75), MHZ(7.5), MHZ(15), MHZ(30), MHZ(60)}; 94 | 95 | for (i = 0; i < sizeof(speed_clock) / sizeof(int); i++) { 96 | if (clock_rate < speed_clock[i]) { 97 | clockIndex = i; 98 | break; 99 | } 100 | } 101 | if (clockIndex > 7 || clock_rate > MHZ(60)) { 102 | clockIndex = 7; 103 | } 104 | RetVal = CH347Jtag_INIT(iIndex, clockIndex); 105 | if (!RetVal) { 106 | printf("CH347 Set Clock failed\n"); 107 | return -1; 108 | } 109 | printf("CH347 Set Clock : %d.\n", speed_clock[clockIndex]); 110 | period = MHZ(1000) / speed_clock[i]; 111 | if (period > 10) 112 | period = period - (period % 10); 113 | return period; 114 | } 115 | 116 | int writeTDI(const uint8_t* tx, uint8_t* rx, uint32_t len, bool end) 117 | { 118 | if (len == 0) { 119 | return 0; 120 | } 121 | unsigned bytes = (len - (end ? 1 : 0)) / 8; 122 | unsigned bits = len - bytes * 8; 123 | uint8_t* rptr = rx; 124 | const uint8_t* tptr = tx; 125 | const uint8_t* txend = tx + bytes; 126 | uint8_t cmd = (rx != NULL) ? CH347_CMD_JTAG_DATA_SHIFT_RD : CH347_CMD_JTAG_DATA_SHIFT; 127 | while (tptr < txend) { 128 | if (get_obuf_length() < 4) { 129 | flush(); 130 | if (!isFull() || obuf != _obuf) { 131 | printf("flush fail\n"); 132 | } 133 | } 134 | if (obuf != _obuf) printf("have data\n"); 135 | int avail = get_obuf_length() - 3; 136 | int chunk = (txend - tptr < avail) ? txend - tptr : avail; 137 | if (tx) { 138 | memcpy(&obuf[3], tptr, chunk); 139 | } 140 | else { 141 | memset(&obuf[3], 0, chunk); 142 | } 143 | tptr += chunk; 144 | // write header 145 | obuf[0] = cmd; 146 | obuf[1] = (chunk >> 0) & 0xff; 147 | obuf[2] = (chunk >> 8) & 0xff; 148 | unsigned actual_length = 0; 149 | int ret = usb_xfer(chunk + 3, (rx) ? chunk + 3 : 0, &actual_length, rx == 0 && get_obuf_length()); 150 | if (!rx) 151 | continue; 152 | if (ibuf[0] != CH347_CMD_JTAG_DATA_SHIFT_RD) { 153 | printf("ibuf[0] != CH347_CMD_JTAG_DATA_SHIFT_RD\n"); 154 | } 155 | unsigned size = ibuf[1] + ibuf[2] * 0x100; 156 | if (ibuf[0] != CH347_CMD_JTAG_DATA_SHIFT_RD || actual_length - 3 != size) { 157 | printf("writeTDI: invalid read data\n"); 158 | } 159 | memcpy(rptr, &ibuf[3], size); 160 | rptr += size; 161 | } 162 | unsigned actual_length; 163 | if (bits == 0) 164 | return EXIT_SUCCESS; 165 | cmd = (rx) ? CH347_CMD_JTAG_BIT_OP_RD : CH347_CMD_JTAG_BIT_OP; 166 | if (get_obuf_length() < (int)(4 + bits * 2)) { 167 | flush(); 168 | } 169 | uint8_t* ptr = &obuf[3]; 170 | uint8_t x = 0; 171 | const uint8_t* bptr = tx + bytes; 172 | for (unsigned i = 0; i < bits; ++i) { 173 | uint8_t txb = (tx) ? bptr[i >> 3] : 0; 174 | uint8_t _tdi = (txb & (1 << (i & 7))) ? TDI_H : 0; 175 | x = _tdi; 176 | if (i == bits - 1) { 177 | x |= TMS_H; 178 | } 179 | *ptr++ = x; 180 | *ptr++ = x | TCK_H; 181 | } 182 | *ptr++ = x & ~TCK_H; 183 | unsigned wlen = ptr - obuf; 184 | obuf[0] = cmd; 185 | obuf[1] = wlen - 3; 186 | obuf[2] = (wlen - 3) >> 8; 187 | int ret = usb_xfer(wlen, (rx) ? (bits + 3) : 0, &actual_length, rx == NULL); 188 | 189 | if (ret < 0) { 190 | printf("writeTDI: usb bulk read failed\n"); 191 | } 192 | if (!rx) 193 | return EXIT_SUCCESS; 194 | 195 | unsigned size = ibuf[1] + ibuf[2] * 0x100; 196 | if (ibuf[0] != CH347_CMD_JTAG_BIT_OP_RD || actual_length - 3 != size) { 197 | printf("writeTDI: invalid read data\n"); 198 | } 199 | for (unsigned i = 0; i < size; ++i) { 200 | if (ibuf[3 + i] == 0x01) { 201 | *rptr |= (0x01 << i); 202 | } 203 | else { 204 | *rptr &= ~(0x01 << i); 205 | } 206 | } 207 | return EXIT_SUCCESS; 208 | } 209 | 210 | bool is_all_zero(void* ptr, size_t size) { 211 | unsigned char* byte_ptr = (unsigned char*)ptr; 212 | 213 | for (size_t i = 0; i < size; i++) { 214 | if (byte_ptr[i] != 0) { 215 | return false; 216 | } 217 | } 218 | return true; 219 | } 220 | 221 | int io_scan(const unsigned char *TMS, const unsigned char *TDI, unsigned char *TDO, int bits, int state) 222 | { 223 | unsigned char v; 224 | unsigned char CmdBuffer[2 * 16384 + 512]; 225 | unsigned char buffer[2 * 16384 + 512]; 226 | unsigned char rbuffer[2 * 16384 + 512]; 227 | unsigned long i, length, DI, DII, RetVal; 228 | unsigned long BI, Txlen; 229 | 230 | int count = 0; 231 | int nb8 = 0; 232 | 233 | if (bits > sizeof(CmdBuffer) / 2) { 234 | fprintf(stderr, "FATAL: out of buffer space for %d bits\n", bits); 235 | return -1; 236 | } 237 | 238 | DI = DII = BI = 0; 239 | // TODO:状态为shift_dr或shift_ir,但tms仍有可能不全为0 240 | if ((state == shift_dr || state == shift_ir) && is_all_zero(TMS, (bits+7)/8)) { 241 | // set tck to low 242 | v = TCK_L | TMS_L | TDI_L; 243 | unsigned char settck[] = { 0xD2,0x01,0x00,0x00 }; 244 | int len = 4; 245 | if (!CH347WriteData(iIndex, settck, &len) || len != 4) { 246 | printf("%d : CH347WriteData failed.\n", __LINE__); 247 | return -1; 248 | } 249 | len = 10; 250 | if (!CH347ReadData(iIndex, settck, &len)) { 251 | printf("%d : CH347ReadData failed.\n", __LINE__); 252 | return -1; 253 | } 254 | return writeTDI(TDI, TDO, bits, false); 255 | } 256 | while (DI < bits) { 257 | if ((bits - DI) > UCMDPKT_DATA_MAX_BITS_USBHS) 258 | length = UCMDPKT_DATA_MAX_BITS_USBHS; 259 | else 260 | length = bits - DI; 261 | 262 | CmdBuffer[BI++] = CH347_CMD_JTAG_BIT_OP_RD; 263 | CmdBuffer[BI++] = (unsigned char)(((length * 2) >> 0) & 0xFF); 264 | CmdBuffer[BI++] = (unsigned char)(((length * 2) >> 8) & 0xFF); 265 | 266 | for (i = 0; i < length; ++i) { 267 | v = TCK_L | TMS_L | TDI_L; 268 | if (TMS[nb8 + (i / 8)] & (1 << (i & 7))) { 269 | v |= TMS_H; 270 | } 271 | if (TDI[nb8 + (i / 8)] & (1 << (i & 7))) { 272 | v |= TDI_H; 273 | } 274 | CmdBuffer[BI++] = v; 275 | CmdBuffer[BI++] = v | TCK_H; 276 | } 277 | 278 | // 添加用于处理大包数据时组包操作参数 279 | RetVal = CH347WriteData(iIndex, CmdBuffer, &BI); 280 | if (!RetVal) { 281 | printf("CH347 Write data failed.\n"); 282 | return -1; 283 | } 284 | 285 | Txlen = length + 3; 286 | RetVal = CH347ReadData(iIndex, rbuffer, & 287 | Txlen); 288 | if (!RetVal) { 289 | printf("CH347 read data failed.\n"); 290 | return -1; 291 | } 292 | memcpy(&buffer[DI], &rbuffer[CH347_CMD_HEADER], Txlen); 293 | 294 | if (Txlen != (length + 3)) { 295 | RetVal = CH347ReadData(iIndex, rbuffer, &BI); 296 | if (!RetVal) { 297 | printf("CH347 read data failed.\n"); 298 | return -1; 299 | } 300 | memcpy(&buffer[DI + Txlen], rbuffer, BI); 301 | } 302 | BI = 0; 303 | memset(CmdBuffer, 0, sizeof(CmdBuffer)); 304 | 305 | DI += length; 306 | nb8 += (length / 8); 307 | } 308 | memset(TDO, 0, (bits + 7) / 8); 309 | 310 | for (i = 0; i < bits; ++i) { 311 | if (buffer[i] & 0x01) { 312 | TDO[i / 8] |= 1 << (i & 7); 313 | } 314 | } 315 | 316 | return 0; 317 | } 318 | 319 | void io_close(void) 320 | { 321 | CH347CloseDevice(iIndex); 322 | } 323 | 324 | int usb_xfer(unsigned wlen, unsigned rlen, unsigned* ract, bool defer) { 325 | unsigned long actual_length = 0; 326 | 327 | if (defer && !rlen && obuf - _obuf > (wlen + 12)) { 328 | obuf += wlen; 329 | return 0; 330 | } 331 | 332 | if (obuf - _obuf > MAX_BUFFER) { 333 | printf("buffer overflow\n"); 334 | } 335 | 336 | wlen += obuf - _obuf; 337 | if (wlen > MAX_BUFFER) { 338 | printf("buffer overflow\n"); 339 | } 340 | obuf = _obuf; 341 | 342 | if (wlen == 0) { 343 | return 0; 344 | } 345 | 346 | int r = 0; 347 | if (wlen) { 348 | actual_length = wlen; 349 | if (!CH347WriteData(iIndex, obuf, &actual_length) || actual_length != wlen) { 350 | printf("write fail.\n"); 351 | return -1; 352 | } 353 | } 354 | obuf = _obuf; 355 | int rlen_total = 0; 356 | uint8_t* pibuf = ibuf; 357 | if (rlen) { 358 | while (rlen) { 359 | actual_length = rlen; 360 | if (!CH347ReadData(iIndex, pibuf, &actual_length)) { 361 | printf("read fail.\n"); 362 | return -1; 363 | } 364 | rlen -= actual_length; 365 | pibuf += actual_length; 366 | rlen_total += actual_length; 367 | } 368 | *ract = rlen_total; 369 | } 370 | return 0; 371 | } 372 | -------------------------------------------------------------------------------- /io_ch347.h: -------------------------------------------------------------------------------- 1 | #ifndef _IO_CH347_H 2 | #define _IO_CH347_H 3 | 4 | /*JTAG state machine.*/ 5 | enum { 6 | test_logic_reset, 7 | run_test_idle, 8 | 9 | select_dr_scan, 10 | capture_dr, 11 | shift_dr, 12 | exit1_dr, 13 | pause_dr, 14 | exit2_dr, 15 | update_dr, 16 | 17 | select_ir_scan, 18 | capture_ir, 19 | shift_ir, 20 | exit1_ir, 21 | pause_ir, 22 | exit2_ir, 23 | update_ir, 24 | 25 | num_states 26 | }; 27 | 28 | int io_init(unsigned int index); 29 | int io_set_period(unsigned int index, unsigned int period); 30 | int io_scan(const unsigned char* tms, const unsigned char* tdi, unsigned char* tdo, int len, int state); 31 | void io_close(void); 32 | 33 | #endif -------------------------------------------------------------------------------- /xvcd_win.c: -------------------------------------------------------------------------------- 1 | // xilinx virtual cable demon for jlink jtag 2 | // use connection string in Impact and another 3 | // xilinx_xvc host=localhost:2542 disableversioncheck=true 4 | #define _CRT_SECURE_NO_WARNINGS 5 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 6 | #include 7 | #include 8 | #include 9 | //#include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "io_ch347.h" 16 | #pragma comment(lib, "Ws2_32.lib") 17 | #define VECTOR_IN_SZ 2048 18 | // #define VECTOR_IN_SZ 4096 19 | 20 | #define STRINGIFY(x) #x 21 | #define TOSTRING(x) STRINGIFY(x) 22 | 23 | 24 | int DEFAULT_JTAG_SPEED = 30000000; // 30 Mhz 25 | 26 | static int jtag_state; 27 | static int verbose = 0; 28 | 29 | /*Listen on port 2542.*/ 30 | int iPort = 2542; 31 | static int vlevel = 1; 32 | unsigned long iIndex_CH347 = 0; 33 | unsigned char szAddress[32] = ""; 34 | 35 | 36 | static int jtag_step(int state, int tms) 37 | { 38 | static const int next_state[num_states][2] = 39 | { 40 | [test_logic_reset] = {run_test_idle, test_logic_reset}, 41 | [run_test_idle] = {run_test_idle, select_dr_scan}, 42 | 43 | [select_dr_scan] = {capture_dr, select_ir_scan}, 44 | [capture_dr] = {shift_dr, exit1_dr}, 45 | [shift_dr] = {shift_dr, exit1_dr}, 46 | [exit1_dr] = {pause_dr, update_dr}, 47 | [pause_dr] = {pause_dr, exit2_dr}, 48 | [exit2_dr] = {shift_dr, update_dr}, 49 | [update_dr] = {run_test_idle, select_dr_scan}, 50 | 51 | [select_ir_scan] = {capture_ir, test_logic_reset}, 52 | [capture_ir] = {shift_ir, exit1_ir}, 53 | [shift_ir] = {shift_ir, exit1_ir}, 54 | [exit1_ir] = {pause_ir, update_ir}, 55 | [pause_ir] = {pause_ir, exit2_ir}, 56 | [exit2_ir] = {shift_ir, update_ir}, 57 | [update_ir] = {run_test_idle, select_dr_scan}}; 58 | 59 | return next_state[state][tms]; 60 | } 61 | 62 | void printTDO(const unsigned char *buf, int bitLen) 63 | { 64 | printf(" TDO: "); 65 | for (int i = 0; i < bitLen; i += 8) { 66 | printf("%.2X", buf[(bitLen - i - 1) / 8]); 67 | } 68 | printf("\n"); 69 | } 70 | 71 | static int sread(SOCKET fd, void *target, int len) 72 | { 73 | char *t = target; 74 | while (len) { 75 | int r = recv(fd, t, len, 0); 76 | if (r == SOCKET_ERROR || r == 0) { 77 | int err = WSAGetLastError(); 78 | printf("Recv failed with error: %d\n", err); 79 | if (r == 0) { 80 | puts("Seems like connection was gracefully closed. Exiting"); 81 | } 82 | return r; 83 | } 84 | t += r; 85 | len -= r; 86 | } 87 | return 1; 88 | } 89 | 90 | static int swrite(SOCKET fd, void *target, int len) 91 | { 92 | char *t = target; 93 | while (len) { 94 | int r = send(fd, t, len, 0); 95 | if (r == SOCKET_ERROR || r == 0) { 96 | int err = WSAGetLastError(); 97 | printf("Send failed with error: %d\n", err); 98 | if (r == 0) { 99 | puts("Seems like connection was gracefully closed. Exiting"); 100 | } 101 | return r; 102 | } 103 | t += r; 104 | len -= r; 105 | } 106 | return 1; 107 | } 108 | 109 | int getInt32(unsigned char *data) 110 | { 111 | // Return an int from the received byte string, data. data is 112 | // expected to be 4 bytes long. 113 | int num; 114 | 115 | // The int32 in data is sent little endian 116 | num = data[3]; 117 | num = (num << 8) | data[2]; 118 | num = (num << 8) | data[1]; 119 | num = (num << 8) | data[0]; 120 | 121 | return num; 122 | } 123 | 124 | void putInt32(unsigned char *data, int num) 125 | { 126 | // Convert the int32_t number, num, into a 4-byte, little endian 127 | // string pointed to by data 128 | data[0] = num & 0x00ff; num >>= 8; 129 | data[1] = num & 0x00ff; num >>= 8; 130 | data[2] = num & 0x00ff; num >>= 8; 131 | data[3] = num & 0x00ff; num >>= 8; 132 | 133 | } 134 | 135 | // 136 | // handle_data(fd) handles JTAG shift instructions. 137 | // To allow multiple programs to access the JTAG chain 138 | // at the same time, we only allow switching between 139 | // different clients only when we're in run_test_idle 140 | // after going test_logic_reset. This ensures that one 141 | // client can't disrupt the other client's IR or state. 142 | // 143 | int handle_data(SOCKET fd, unsigned long frequency) 144 | { 145 | int i; 146 | int seen_tlr = 0; 147 | int retVal = 0; 148 | const char xvcInfo[] = "xvcServer_v1.0:" TOSTRING(VECTOR_IN_SZ) "\n"; 149 | do { 150 | char cmd[16]; 151 | unsigned char buffer[2048], result[2048]; 152 | // unsigned char buffer[4096], result[4096]; 153 | 154 | if (sread(fd, cmd, 2) != 1) 155 | return 1; 156 | if (memcmp(cmd, "ge", 2) == 0) { // 获取信息 157 | if (sread(fd, cmd, 6) != 1) 158 | return 1; 159 | memcpy(result, xvcInfo, strlen(xvcInfo)); 160 | 161 | if (swrite(fd, result, strlen(xvcInfo)) != 1) { 162 | printf("[%d]write %d bytes != %d\n", __LINE__, retVal, strlen(xvcInfo)); 163 | return 1; 164 | } 165 | if (vlevel > 0) { 166 | printf("%u : Received command: 'getinfo'\n", (int)time(NULL)); 167 | printf("\t Replied with %s\n", xvcInfo); 168 | } 169 | break; 170 | } else if (memcmp(cmd, "se", 2) == 0) { // 速度设置 171 | if (sread(fd, cmd, 9) != 1) 172 | return 1; 173 | 174 | // Convert the 4-byte little endian integer after "settck:" to be an integer 175 | int period, actPeriod; 176 | 177 | // if frequency argument is non-0, use it instead of the 178 | // period from the settck: command 179 | if (frequency == 0) { 180 | period = getInt32((unsigned char *)cmd + 5); 181 | } else { 182 | period = 1000000000 / frequency; 183 | } 184 | 185 | printf("Get the period:%d.\n", period); 186 | 187 | actPeriod = io_set_period(iIndex_CH347, (unsigned int)period); 188 | 189 | if (actPeriod < 0) { 190 | fprintf(stderr, "Error while setting the JTAG TCK period\n"); 191 | actPeriod = period; /* on error, simply echo back the period value so client while not try to change it*/ 192 | } 193 | 194 | putInt32(result, actPeriod); 195 | 196 | if (swrite(fd, result, 4) != 1) { 197 | return 1; 198 | } 199 | if (vlevel > 0) { 200 | printf("%u : Received command: 'settck'\n", (int)time(NULL)); 201 | printf("\t Replied with '%d'\n\n", actPeriod); 202 | } 203 | break; 204 | } else if (memcmp(cmd, "sh", 2) == 0) { 205 | if (sread(fd, cmd, 4) != 1) { 206 | return 1; 207 | } 208 | if (vlevel > 1) { 209 | printf("%u : Received command: 'shift'\n", (int)time(NULL)); 210 | } 211 | } else { 212 | fprintf(stderr, "invalid cmd '%s'\n", cmd); 213 | return 1; 214 | } 215 | 216 | // 读取shift数据长度 217 | if (sread(fd, cmd + 6, 4) != 1) { 218 | fprintf(stderr, "reading length failed\n"); 219 | return 1; 220 | } 221 | 222 | int len; 223 | len = getInt32((unsigned char *)cmd + 6); 224 | 225 | int nr_bytes = (len + 7) / 8; 226 | if (nr_bytes * 2 > sizeof(buffer)) { 227 | fprintf(stderr, "buffer size exceeded\n"); 228 | return 1; 229 | } 230 | 231 | if (sread(fd, buffer, nr_bytes * 2) != 1) { 232 | fprintf(stderr, "reading data failed\n"); 233 | return 1; 234 | } 235 | memset(result, 0, sizeof(result)); 236 | 237 | if (vlevel > 2) { 238 | printf("\tNumber of Bits : %d\n", len); 239 | printf("\tNumber of Bytes : %d \n", nr_bytes); 240 | for (i=0; i < nr_bytes; i++) 241 | printf("%02x ", buffer[i]); 242 | printf("\n"); 243 | } 244 | 245 | // Only allow exiting if the state is rti and the IR 246 | // has the default value (IDCODE) by going through test_logic_reset. 247 | // As soon as going through capture_dr or capture_ir no exit is 248 | // allowed as this will change DR/IR. 249 | seen_tlr = (seen_tlr || jtag_state == test_logic_reset) && (jtag_state != capture_dr) && (jtag_state != capture_ir); 250 | 251 | // Due to a weird bug(??) xilinx impacts goes through another "capture_ir"/"capture_dr" cycle after 252 | // reading IR/DR which unfortunately sets IR to the read-out IR value. 253 | // Just ignore these transactions. 254 | if ((jtag_state == exit1_ir && len == 5 && buffer[0] == 0x17) || 255 | (jtag_state == exit1_dr && len == 4 && buffer[0] == 0x0b)) { 256 | if (verbose) 257 | printf("ignoring bogus jtag state movement in jtag_state %d\n", jtag_state); 258 | } else { 259 | for (i = 0; i < len; ++i) { 260 | // Do the actual cycle. 261 | int tms = !!(buffer[i / 8] & (1 << (i & 7))); 262 | 263 | // Track the state. 264 | jtag_state = jtag_step(jtag_state, tms); 265 | } 266 | 267 | if (io_scan(buffer, buffer + nr_bytes, result, len, jtag_state) < 0) { 268 | fprintf(stderr, "io_scan failed\n"); 269 | exit(1); 270 | } 271 | 272 | if (verbose) { 273 | for (i = 0; i < nr_bytes; ++i) 274 | printf("%02x ", result[i]); 275 | } 276 | } 277 | 278 | if (send(fd, (const char *)result, nr_bytes, 0) != nr_bytes) { 279 | printf("Send failed with error: %d\n", WSAGetLastError()); 280 | return 1; 281 | } 282 | 283 | if (verbose) { 284 | printf("jtag state %d\n", jtag_state); 285 | } 286 | } while (!(seen_tlr && jtag_state == run_test_idle)); 287 | if (verbose) { 288 | puts("exit handle_data"); 289 | } 290 | return 0; 291 | } 292 | 293 | void usage(void) 294 | { 295 | const char use[] = 296 | " Usage:\n"\ 297 | " -h, --help display this message\n"\ 298 | " -a, --address specify host address, default is 127.0.0.1\n"\ 299 | " -p, --port specify socket port, default is 2542\n"\ 300 | " -i, --index specify CH347 index, default is 0\n"\ 301 | " -s, --speed specify CH347 JTAG speed, default is 30MHz\n"\ 302 | "\n\n" 303 | ; 304 | printf(use); 305 | exit(0); 306 | } 307 | 308 | int main(int argc, char **argv) 309 | { 310 | int ret = 0; 311 | int i; 312 | SOCKET s; 313 | int c; 314 | struct sockaddr_in address; 315 | unsigned short port = iPort; 316 | unsigned short jtagSpeed = DEFAULT_JTAG_SPEED; 317 | unsigned int coreId = 0; 318 | for (int i = 1; i < argc; ++i) { 319 | if (!strcmp(argv[i],"-h") || !strcmp(argv[i], "--help")) { 320 | usage(); 321 | } 322 | else \ 323 | if (!strcmp(argv[i], "-a") || !strcmp(argv[i], "--address") && i + 1 < argc) { 324 | strcpy(szAddress, argv[i + 1]); 325 | ++i; 326 | } 327 | else \ 328 | // port 329 | if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--port") && i + 1 < argc) { 330 | iPort = atoi(argv[i + 1]); 331 | ++i; 332 | } 333 | else \ 334 | if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--index") && i + 1 < argc) { 335 | iIndex_CH347 = atoi(argv[i + 1]); 336 | ++i; 337 | } 338 | else \ 339 | if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--speed") && i + 1 < argc) { 340 | DEFAULT_JTAG_SPEED = atoi(argv[i + 1]); 341 | ++i; 342 | } 343 | else { 344 | usage(); 345 | } 346 | } 347 | if (io_init(iIndex_CH347)) { 348 | fprintf(stderr, "io_init failed\n"); 349 | return 1; 350 | } 351 | 352 | WSADATA wsaData; 353 | 354 | int iResult; 355 | 356 | // Initialize Winsock 357 | iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 358 | if (iResult != 0) { 359 | printf("WSAStartup failed: %d\n", iResult); 360 | return 1; 361 | } 362 | 363 | s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); 364 | 365 | if (s == INVALID_SOCKET) { 366 | printf("Error at socket(): %d\n", WSAGetLastError()); 367 | WSACleanup(); 368 | return 1; 369 | } 370 | 371 | i = 1; 372 | setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof i); 373 | 374 | address.sin_addr.s_addr = strcmp(szAddress, "") ? inet_addr(szAddress) : INADDR_ANY; 375 | address.sin_port = htons(port); 376 | address.sin_family = AF_INET; 377 | 378 | iResult = bind(s, (struct sockaddr *)&address, sizeof(address)); 379 | 380 | if (iResult == SOCKET_ERROR) { 381 | printf("Bind failed with error: %d\n", WSAGetLastError()); 382 | closesocket(s); 383 | WSACleanup(); 384 | return 1; 385 | } 386 | 387 | if (listen(s, SOMAXCONN) == SOCKET_ERROR) { 388 | printf("Listen failed with error: %d\n", WSAGetLastError()); 389 | closesocket(s); 390 | WSACleanup(); 391 | return 1; 392 | } 393 | 394 | fd_set conn; 395 | int maxfd = 0; 396 | 397 | FD_ZERO(&conn); 398 | FD_SET(s, &conn); 399 | 400 | maxfd = s; 401 | 402 | if (verbose) { 403 | puts("Started"); 404 | } 405 | while (1) { 406 | fd_set read = conn, except = conn; 407 | SOCKET fd; 408 | 409 | // Look for work to do. 410 | if (select(maxfd + 1, &read, 0, &except, 0) == SOCKET_ERROR) { 411 | printf("Select failed with error: %d\n", WSAGetLastError()); 412 | break; 413 | } 414 | 415 | for (fd = 0; fd <= maxfd; ++fd) { 416 | if (FD_ISSET(fd, &read)) { 417 | // Readable listen socket? Accept connection. 418 | if (fd == s) { 419 | SOCKET newfd; 420 | int nsize = sizeof(address); 421 | 422 | newfd = accept(s, (struct sockaddr *)&address, &nsize); 423 | if (verbose) { 424 | printf("connection accepted - fd %d\n", newfd); 425 | } 426 | if (newfd == INVALID_SOCKET) { 427 | printf("accept failed with error: %d\n", WSAGetLastError()); 428 | } else { 429 | puts("setting TCP_NODELAY to 1"); 430 | int flag = 1; 431 | int optResult = setsockopt(newfd, 432 | IPPROTO_TCP, 433 | TCP_NODELAY, 434 | (char *)&flag, 435 | sizeof(flag)); 436 | if (optResult < 0) { 437 | perror("TCP_NODELAY error"); 438 | } 439 | if (newfd > maxfd) { 440 | maxfd = newfd; 441 | } 442 | FD_SET(newfd, &conn); 443 | } 444 | } 445 | // Otherwise, do work. 446 | else { 447 | int r; 448 | if (verbose) { 449 | puts("start handle_data"); 450 | } 451 | r = handle_data(fd, DEFAULT_JTAG_SPEED); 452 | if (verbose) { 453 | puts("stop handle_data"); 454 | } 455 | if (r) { 456 | // Close connection when required. 457 | if (verbose) 458 | printf("connection closed - fd %d\n", fd); 459 | closesocket(fd); 460 | FD_CLR(fd, &conn); 461 | } 462 | } 463 | } 464 | // Abort connection? 465 | else if (FD_ISSET(fd, &except)) { 466 | if (verbose) { 467 | printf("connection aborted - fd %d\n", fd); 468 | } 469 | closesocket(fd); 470 | FD_CLR(fd, &conn); 471 | if (fd == s) 472 | break; 473 | } 474 | } 475 | } 476 | closesocket(s); 477 | WSACleanup(); 478 | // Un-map IOs. 479 | io_close(); 480 | 481 | return 0; 482 | } 483 | --------------------------------------------------------------------------------