mirror of
				https://github.com/Klipper3d/klipper.git
				synced 2025-10-31 02:15:52 +01:00 
			
		
		
		
	lib: Add hidflash source
Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
		
							
								
								
									
										15
									
								
								lib/hidflash/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								lib/hidflash/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| * STM32 HID Bootloader - USB HID bootloader for STM32F10X | ||||
| * Copyright (c) 2018 Bruno Freitas - bruno@brunofreitas.com | ||||
| * | ||||
| * This program is free software: you can redistribute it and/or modify | ||||
| * it under the terms of the GNU General Public License as published by | ||||
| * the Free Software Foundation, either version 3 of the License, or | ||||
| * (at your option) any later version. | ||||
| * | ||||
| * This program is distributed in the hope that it will be useful, | ||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| * GNU General Public License for more details. | ||||
| * | ||||
| * You should have received a copy of the GNU General Public License | ||||
| * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
							
								
								
									
										48
									
								
								lib/hidflash/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								lib/hidflash/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| CC=gcc | ||||
| CFLAGS=-c -Wall | ||||
| LDFLAGS= | ||||
| SOURCES=main.c | ||||
| INCLUDE_DIRS=-I . | ||||
| CHECK=1 | ||||
|  | ||||
| ifeq ($(OS),Windows_NT) | ||||
| 	SOURCES+=hid-win.c | ||||
| 	SOURCES+=rs232.c | ||||
| 	LIBS=-lsetupapi -lhid | ||||
| else | ||||
| 	UNAME_S := $(shell uname -s) | ||||
| 	ifeq ($(UNAME_S),Darwin) | ||||
| 		SOURCES+=hid-mac.c | ||||
| 		SOURCES+=rs232.c | ||||
| 		LIBS=-framework IOKit -framework CoreFoundation | ||||
| 	else | ||||
| 		CHECK:=$(shell pkg-config --exists libusb-1.0 && echo 1) | ||||
| 		SOURCES+=hid-libusb.c | ||||
| 		SOURCES+=rs232.c | ||||
| 		LIBS=`pkg-config libusb-1.0 --libs` -lrt -lpthread | ||||
| 		INCLUDE_DIRS+=`pkg-config libusb-1.0 --cflags` | ||||
| 		CFLAGS+=-std=gnu99 | ||||
| 		LDFLAGS+=-no-pie | ||||
| 	endif | ||||
| endif | ||||
|  | ||||
| OBJECTS=$(SOURCES:.c=.o) | ||||
|  | ||||
| EXECUTABLE = hid-flash | ||||
|  | ||||
| ifeq ($(CHECK), 1) | ||||
| all: $(SOURCES) $(EXECUTABLE) | ||||
|  | ||||
| $(EXECUTABLE): $(OBJECTS) | ||||
| 	$(CC) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $@ | ||||
|  | ||||
| .c.o: | ||||
| 	$(CC) $(CFLAGS) $(INCLUDE_DIRS) $< -o $@ | ||||
| else | ||||
| all: | ||||
| 	@echo "    hid-flash requires libusb-1.0, please install with:" | ||||
| 	@echo "    sudo apt-get install libusb-1.0" | ||||
| endif | ||||
|  | ||||
| clean: | ||||
| 	rm -f $(OBJECTS) $(EXECUTABLE) $(EXECUTABLE).exe | ||||
							
								
								
									
										34
									
								
								lib/hidflash/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								lib/hidflash/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| The source for the hid-flash program in this folder is a deriviative of the | ||||
| "cli" modified by Vassilis Serasidis to work with the STM32 Arduino core, | ||||
| available here: | ||||
| https://github.com/Serasidis/STM32_HID_Bootloader/tree/master/cli | ||||
|  | ||||
| The original source for hid-flash was written by Bruno Freitas, available | ||||
| here: | ||||
| https://github.com/bootsector/stm32-hid-bootloader/tree/master/cli | ||||
|  | ||||
| This derivative contains the following changes: | ||||
| 1) The "port" argument is now optional.  If not supplied hid-flash will not | ||||
|    attempt to open a serial port and enter the bootloader, it will assume | ||||
|    that the device has already entered the bootloader and look for a USB | ||||
|    device with the appropriate Vendor and Product IDs. This change allows | ||||
|    Klipper's "flash_usb.py" script to enter the bootloader and wait for the | ||||
|    mcu to reconnect. | ||||
| 2) When the serial port is specified, hid-flash will use Klipper's procedure | ||||
|    for entering the bootloader (Open the port at 1200 baud and toggle DTR). | ||||
| 3) The hid-flash program now accepts a command from the bootloader that allows | ||||
|    a STM32F103 device to identify itself as a "high-density" device during | ||||
|    the flashing process.  This fixes a bug where the final page would not | ||||
|    be written if the last portion of the binary was less than or equal to | ||||
|    1024 bytes. A forked version of the bootloader is required to send the | ||||
|    "high-density" command, however the tool will still work correctly with | ||||
|    the original bootloader (sans the bug that affects high density devices). | ||||
| 4) A typo was fixed where an "if" statement was using an assignment operator | ||||
|    to test for equality. | ||||
| 5) The Makefile was changed to check for the libusb-1.0 dependency. If it | ||||
|    does not exist the user will be warned and the build aborted, however | ||||
|    no error will be generated.  This allows Klipper's "make FLASH" | ||||
|    functionality to work when flashing via DFU without installing the | ||||
|    libusb-1.0 dependency for hid-flash. | ||||
|  | ||||
| - Eric Callahan <arksine.code@gmail.com> | ||||
							
								
								
									
										1514
									
								
								lib/hidflash/hid-libusb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1514
									
								
								lib/hidflash/hid-libusb.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1110
									
								
								lib/hidflash/hid-mac.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1110
									
								
								lib/hidflash/hid-mac.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										944
									
								
								lib/hidflash/hid-win.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										944
									
								
								lib/hidflash/hid-win.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,944 @@ | ||||
| /******************************************************* | ||||
|  HIDAPI - Multi-Platform library for | ||||
|  communication with HID devices. | ||||
|  | ||||
|  Alan Ott | ||||
|  Signal 11 Software | ||||
|  | ||||
|  8/22/2009 | ||||
|  | ||||
|  Copyright 2009, All Rights Reserved. | ||||
|   | ||||
|  At the discretion of the user of this library, | ||||
|  this software may be licensed under the terms of the | ||||
|  GNU General Public License v3, a BSD-Style license, or the | ||||
|  original HIDAPI license as outlined in the LICENSE.txt, | ||||
|  LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt | ||||
|  files located at the root of the source distribution. | ||||
|  These files may also be found in the public source | ||||
|  code repository located at: | ||||
|         http://github.com/signal11/hidapi . | ||||
| ********************************************************/ | ||||
|  | ||||
| #include <windows.h> | ||||
|  | ||||
| #ifndef _NTDEF_ | ||||
| typedef LONG NTSTATUS; | ||||
| #endif | ||||
|  | ||||
| #ifdef __MINGW32__ | ||||
| #include <ntdef.h> | ||||
| #include <winbase.h> | ||||
| #endif | ||||
|  | ||||
| #ifdef __CYGWIN__ | ||||
| #include <ntdef.h> | ||||
| #define _wcsdup wcsdup | ||||
| #endif | ||||
|  | ||||
| /* The maximum number of characters that can be passed into the | ||||
|    HidD_Get*String() functions without it failing.*/ | ||||
| #define MAX_STRING_WCHARS 0xFFF | ||||
|  | ||||
| /*#define HIDAPI_USE_DDK*/ | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|   #include <setupapi.h> | ||||
|   #include <winioctl.h> | ||||
|   #ifdef HIDAPI_USE_DDK | ||||
|     #include <hidsdi.h> | ||||
|   #endif | ||||
|  | ||||
|   /* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */ | ||||
|   #define HID_OUT_CTL_CODE(id)  \ | ||||
|     CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) | ||||
|   #define IOCTL_HID_GET_FEATURE                   HID_OUT_CTL_CODE(100) | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } /* extern "C" */ | ||||
| #endif | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
|  | ||||
| #include "hidapi.h" | ||||
|  | ||||
| #undef MIN | ||||
| #define MIN(x,y) ((x) < (y)? (x): (y)) | ||||
|  | ||||
| #ifdef _MSC_VER | ||||
|   /* Thanks Microsoft, but I know how to use strncpy(). */ | ||||
|   #pragma warning(disable:4996) | ||||
| #endif | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #ifndef HIDAPI_USE_DDK | ||||
|   /* Since we're not building with the DDK, and the HID header | ||||
|      files aren't part of the SDK, we have to define all this | ||||
|      stuff here. In lookup_functions(), the function pointers | ||||
|      defined below are set. */ | ||||
|   typedef struct _HIDD_ATTRIBUTES{ | ||||
|     ULONG Size; | ||||
|     USHORT VendorID; | ||||
|     USHORT ProductID; | ||||
|     USHORT VersionNumber; | ||||
|   } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; | ||||
|  | ||||
|   typedef USHORT USAGE; | ||||
|   typedef struct _HIDP_CAPS { | ||||
|     USAGE Usage; | ||||
|     USAGE UsagePage; | ||||
|     USHORT InputReportByteLength; | ||||
|     USHORT OutputReportByteLength; | ||||
|     USHORT FeatureReportByteLength; | ||||
|     USHORT Reserved[17]; | ||||
|     USHORT fields_not_used_by_hidapi[10]; | ||||
|   } HIDP_CAPS, *PHIDP_CAPS; | ||||
|   typedef void* PHIDP_PREPARSED_DATA; | ||||
|   #define HIDP_STATUS_SUCCESS 0x110000 | ||||
|  | ||||
|   typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib); | ||||
|   typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len); | ||||
|   typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); | ||||
|   typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); | ||||
|   typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length); | ||||
|   typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length); | ||||
|   typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len); | ||||
|   typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data); | ||||
|   typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data); | ||||
|   typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps); | ||||
|   typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers); | ||||
|  | ||||
|   static HidD_GetAttributes_ HidD_GetAttributes; | ||||
|   static HidD_GetSerialNumberString_ HidD_GetSerialNumberString; | ||||
|   static HidD_GetManufacturerString_ HidD_GetManufacturerString; | ||||
|   static HidD_GetProductString_ HidD_GetProductString; | ||||
|   static HidD_SetFeature_ HidD_SetFeature; | ||||
|   static HidD_GetFeature_ HidD_GetFeature; | ||||
|   static HidD_GetIndexedString_ HidD_GetIndexedString; | ||||
|   static HidD_GetPreparsedData_ HidD_GetPreparsedData; | ||||
|   static HidD_FreePreparsedData_ HidD_FreePreparsedData; | ||||
|   static HidP_GetCaps_ HidP_GetCaps; | ||||
|   static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers; | ||||
|  | ||||
|   static HMODULE lib_handle = NULL; | ||||
|   static BOOLEAN initialized = FALSE; | ||||
| #endif /* HIDAPI_USE_DDK */ | ||||
|  | ||||
| struct hid_device_ { | ||||
|     HANDLE device_handle; | ||||
|     BOOL blocking; | ||||
|     USHORT output_report_length; | ||||
|     size_t input_report_length; | ||||
|     void *last_error_str; | ||||
|     DWORD last_error_num; | ||||
|     BOOL read_pending; | ||||
|     char *read_buf; | ||||
|     OVERLAPPED ol; | ||||
| }; | ||||
|  | ||||
| static hid_device *new_hid_device() | ||||
| { | ||||
|   hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device)); | ||||
|   dev->device_handle = INVALID_HANDLE_VALUE; | ||||
|   dev->blocking = TRUE; | ||||
|   dev->output_report_length = 0; | ||||
|   dev->input_report_length = 0; | ||||
|   dev->last_error_str = NULL; | ||||
|   dev->last_error_num = 0; | ||||
|   dev->read_pending = FALSE; | ||||
|   dev->read_buf = NULL; | ||||
|   memset(&dev->ol, 0, sizeof(dev->ol)); | ||||
|   dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL); | ||||
|  | ||||
|   return dev; | ||||
| } | ||||
|  | ||||
| static void free_hid_device(hid_device *dev) | ||||
| { | ||||
|   CloseHandle(dev->ol.hEvent); | ||||
|   CloseHandle(dev->device_handle); | ||||
|   LocalFree(dev->last_error_str); | ||||
|   free(dev->read_buf); | ||||
|   free(dev); | ||||
| } | ||||
|  | ||||
| static void register_error(hid_device *device, const char *op) | ||||
| { | ||||
|   WCHAR *ptr, *msg; | ||||
|  | ||||
|   FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||||
|     FORMAT_MESSAGE_FROM_SYSTEM | | ||||
|     FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
|     NULL, | ||||
|     GetLastError(), | ||||
|     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
|     (LPVOID)&msg, 0/*sz*/, | ||||
|     NULL); | ||||
|    | ||||
|   /* Get rid of the CR and LF that FormatMessage() sticks at the | ||||
|      end of the message. Thanks Microsoft! */ | ||||
|   ptr = msg; | ||||
|   while (*ptr) { | ||||
|     if (*ptr == '\r') { | ||||
|       *ptr = 0x0000; | ||||
|       break; | ||||
|     } | ||||
|     ptr++; | ||||
|   } | ||||
|  | ||||
|   /* Store the message off in the Device entry so that | ||||
|      the hid_error() function can pick it up. */ | ||||
|   LocalFree(device->last_error_str); | ||||
|   device->last_error_str = msg; | ||||
| } | ||||
|  | ||||
| #ifndef HIDAPI_USE_DDK | ||||
| static int lookup_functions() | ||||
| { | ||||
|   lib_handle = LoadLibraryA("hid.dll"); | ||||
|   if (lib_handle) { | ||||
| #define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1; | ||||
|     RESOLVE(HidD_GetAttributes); | ||||
|     RESOLVE(HidD_GetSerialNumberString); | ||||
|     RESOLVE(HidD_GetManufacturerString); | ||||
|     RESOLVE(HidD_GetProductString); | ||||
|     RESOLVE(HidD_SetFeature); | ||||
|     RESOLVE(HidD_GetFeature); | ||||
|     RESOLVE(HidD_GetIndexedString); | ||||
|     RESOLVE(HidD_GetPreparsedData); | ||||
|     RESOLVE(HidD_FreePreparsedData); | ||||
|     RESOLVE(HidP_GetCaps); | ||||
|     RESOLVE(HidD_SetNumInputBuffers); | ||||
| #undef RESOLVE | ||||
|   } | ||||
|   else | ||||
|     return -1; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static HANDLE open_device(const char *path, BOOL enumerate) | ||||
| { | ||||
|   HANDLE handle; | ||||
|   DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ); | ||||
|   DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE; | ||||
|  | ||||
|   handle = CreateFileA(path, | ||||
|     desired_access, | ||||
|     share_mode, | ||||
|     NULL, | ||||
|     OPEN_EXISTING, | ||||
|     FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/ | ||||
|     0); | ||||
|  | ||||
|   return handle; | ||||
| } | ||||
|  | ||||
| int HID_API_EXPORT hid_init(void) | ||||
| { | ||||
| #ifndef HIDAPI_USE_DDK | ||||
|   if (!initialized) { | ||||
|     if (lookup_functions() < 0) { | ||||
|       hid_exit(); | ||||
|       return -1; | ||||
|     } | ||||
|     initialized = TRUE; | ||||
|   } | ||||
| #endif | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int HID_API_EXPORT hid_exit(void) | ||||
| { | ||||
| #ifndef HIDAPI_USE_DDK | ||||
|   if (lib_handle) | ||||
|     FreeLibrary(lib_handle); | ||||
|   lib_handle = NULL; | ||||
|   initialized = FALSE; | ||||
| #endif | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id) | ||||
| { | ||||
|   BOOL res; | ||||
|   struct hid_device_info *root = NULL; /* return object */ | ||||
|   struct hid_device_info *cur_dev = NULL; | ||||
|  | ||||
|   /* Windows objects for interacting with the driver. */ | ||||
|   GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} }; | ||||
|   SP_DEVINFO_DATA devinfo_data; | ||||
|   SP_DEVICE_INTERFACE_DATA device_interface_data; | ||||
|   SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL; | ||||
|   HDEVINFO device_info_set = INVALID_HANDLE_VALUE; | ||||
|   int device_index = 0; | ||||
|   int i; | ||||
|  | ||||
|   if (hid_init() < 0) | ||||
|     return NULL; | ||||
|  | ||||
|   /* Initialize the Windows objects. */ | ||||
|   memset(&devinfo_data, 0x0, sizeof(devinfo_data)); | ||||
|   devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA); | ||||
|   device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); | ||||
|  | ||||
|   /* Get information for all the devices belonging to the HID class. */ | ||||
|   device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); | ||||
|    | ||||
|   /* Iterate over each device in the HID class, looking for the right one. */ | ||||
|    | ||||
|   for (;;) { | ||||
|     HANDLE write_handle = INVALID_HANDLE_VALUE; | ||||
|     DWORD required_size = 0; | ||||
|     HIDD_ATTRIBUTES attrib; | ||||
|  | ||||
|     res = SetupDiEnumDeviceInterfaces(device_info_set, | ||||
|       NULL, | ||||
|       &InterfaceClassGuid, | ||||
|       device_index, | ||||
|       &device_interface_data); | ||||
|      | ||||
|     if (!res) { | ||||
|       /* A return of FALSE from this function means that | ||||
|          there are no more devices. */ | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     /* Call with 0-sized detail size, and let the function | ||||
|        tell us how long the detail struct needs to be. The | ||||
|        size is put in &required_size. */ | ||||
|     res = SetupDiGetDeviceInterfaceDetailA(device_info_set, | ||||
|       &device_interface_data, | ||||
|       NULL, | ||||
|       0, | ||||
|       &required_size, | ||||
|       NULL); | ||||
|  | ||||
|     /* Allocate a long enough structure for device_interface_detail_data. */ | ||||
|     device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size); | ||||
|     device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); | ||||
|  | ||||
|     /* Get the detailed data for this device. The detail data gives us | ||||
|        the device path for this device, which is then passed into | ||||
|        CreateFile() to get a handle to the device. */ | ||||
|     res = SetupDiGetDeviceInterfaceDetailA(device_info_set, | ||||
|       &device_interface_data, | ||||
|       device_interface_detail_data, | ||||
|       required_size, | ||||
|       NULL, | ||||
|       NULL); | ||||
|  | ||||
|     if (!res) { | ||||
|       /* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail"); | ||||
|          Continue to the next device. */ | ||||
|       goto cont; | ||||
|     } | ||||
|  | ||||
|     /* Make sure this device is of Setup Class "HIDClass" and has a | ||||
|        driver bound to it. */ | ||||
|     for (i = 0; ; i++) { | ||||
|       char driver_name[256]; | ||||
|  | ||||
|       /* Populate devinfo_data. This function will return failure | ||||
|          when there are no more interfaces left. */ | ||||
|       res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data); | ||||
|       if (!res) | ||||
|         goto cont; | ||||
|  | ||||
|       res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data, | ||||
|                      SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL); | ||||
|       if (!res) | ||||
|         goto cont; | ||||
|  | ||||
|       if (strcmp(driver_name, "HIDClass") == 0) { | ||||
|         /* See if there's a driver bound. */ | ||||
|         res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data, | ||||
|                    SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL); | ||||
|         if (res) | ||||
|           break; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath); | ||||
|  | ||||
|     /* Open a handle to the device */ | ||||
|     write_handle = open_device(device_interface_detail_data->DevicePath, TRUE); | ||||
|  | ||||
|     /* Check validity of write_handle. */ | ||||
|     if (write_handle == INVALID_HANDLE_VALUE) { | ||||
|       /* Unable to open the device. */ | ||||
|       //register_error(dev, "CreateFile"); | ||||
|       goto cont_close; | ||||
|     }     | ||||
|  | ||||
|  | ||||
|     /* Get the Vendor ID and Product ID for this device. */ | ||||
|     attrib.Size = sizeof(HIDD_ATTRIBUTES); | ||||
|     HidD_GetAttributes(write_handle, &attrib); | ||||
|     //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID); | ||||
|  | ||||
|     /* Check the VID/PID to see if we should add this | ||||
|        device to the enumeration list. */ | ||||
|     if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) && | ||||
|         (product_id == 0x0 || attrib.ProductID == product_id)) { | ||||
|  | ||||
|       #define WSTR_LEN 512 | ||||
|       const char *str; | ||||
|       struct hid_device_info *tmp; | ||||
|       PHIDP_PREPARSED_DATA pp_data = NULL; | ||||
|       HIDP_CAPS caps; | ||||
|       BOOLEAN res; | ||||
|       NTSTATUS nt_res; | ||||
|       wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */ | ||||
|       size_t len; | ||||
|  | ||||
|       /* VID/PID match. Create the record. */ | ||||
|       tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info)); | ||||
|       if (cur_dev) { | ||||
|         cur_dev->next = tmp; | ||||
|       } | ||||
|       else { | ||||
|         root = tmp; | ||||
|       } | ||||
|       cur_dev = tmp; | ||||
|  | ||||
|       /* Get the Usage Page and Usage for this device. */ | ||||
|       res = HidD_GetPreparsedData(write_handle, &pp_data); | ||||
|       if (res) { | ||||
|         nt_res = HidP_GetCaps(pp_data, &caps); | ||||
|         if (nt_res == HIDP_STATUS_SUCCESS) { | ||||
|           cur_dev->usage_page = caps.UsagePage; | ||||
|           cur_dev->usage = caps.Usage; | ||||
|         } | ||||
|  | ||||
|         HidD_FreePreparsedData(pp_data); | ||||
|       } | ||||
|        | ||||
|       /* Fill out the record */ | ||||
|       cur_dev->next = NULL; | ||||
|       str = device_interface_detail_data->DevicePath; | ||||
|       if (str) { | ||||
|         len = strlen(str); | ||||
|         cur_dev->path = (char*) calloc(len+1, sizeof(char)); | ||||
|         strncpy(cur_dev->path, str, len+1); | ||||
|         cur_dev->path[len] = '\0'; | ||||
|       } | ||||
|       else | ||||
|         cur_dev->path = NULL; | ||||
|  | ||||
|       /* Serial Number */ | ||||
|       res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr)); | ||||
|       wstr[WSTR_LEN-1] = 0x0000; | ||||
|       if (res) { | ||||
|         cur_dev->serial_number = _wcsdup(wstr); | ||||
|       } | ||||
|  | ||||
|       /* Manufacturer String */ | ||||
|       res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr)); | ||||
|       wstr[WSTR_LEN-1] = 0x0000; | ||||
|       if (res) { | ||||
|         cur_dev->manufacturer_string = _wcsdup(wstr); | ||||
|       } | ||||
|  | ||||
|       /* Product String */ | ||||
|       res = HidD_GetProductString(write_handle, wstr, sizeof(wstr)); | ||||
|       wstr[WSTR_LEN-1] = 0x0000; | ||||
|       if (res) { | ||||
|         cur_dev->product_string = _wcsdup(wstr); | ||||
|       } | ||||
|  | ||||
|       /* VID/PID */ | ||||
|       cur_dev->vendor_id = attrib.VendorID; | ||||
|       cur_dev->product_id = attrib.ProductID; | ||||
|  | ||||
|       /* Release Number */ | ||||
|       cur_dev->release_number = attrib.VersionNumber; | ||||
|  | ||||
|       /* Interface Number. It can sometimes be parsed out of the path | ||||
|          on Windows if a device has multiple interfaces. See | ||||
|          http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or | ||||
|          search for "Hardware IDs for HID Devices" at MSDN. If it's not | ||||
|          in the path, it's set to -1. */ | ||||
|       cur_dev->interface_number = -1; | ||||
|       if (cur_dev->path) { | ||||
|         char *interface_component = strstr(cur_dev->path, "&mi_"); | ||||
|         if (interface_component) { | ||||
|           char *hex_str = interface_component + 4; | ||||
|           char *endptr = NULL; | ||||
|           cur_dev->interface_number = strtol(hex_str, &endptr, 16); | ||||
|           if (endptr == hex_str) { | ||||
|             /* The parsing failed. Set interface_number to -1. */ | ||||
|             cur_dev->interface_number = -1; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
| cont_close: | ||||
|     CloseHandle(write_handle); | ||||
| cont: | ||||
|     /* We no longer need the detail data. It can be freed */ | ||||
|     free(device_interface_detail_data); | ||||
|  | ||||
|     device_index++; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   /* Close the device information handle. */ | ||||
|   SetupDiDestroyDeviceInfoList(device_info_set); | ||||
|  | ||||
|   return root; | ||||
|  | ||||
| } | ||||
|  | ||||
| void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs) | ||||
| { | ||||
|   /* TODO: Merge this with the Linux version. This function is platform-independent. */ | ||||
|   struct hid_device_info *d = devs; | ||||
|   while (d) { | ||||
|     struct hid_device_info *next = d->next; | ||||
|     free(d->path); | ||||
|     free(d->serial_number); | ||||
|     free(d->manufacturer_string); | ||||
|     free(d->product_string); | ||||
|     free(d); | ||||
|     d = next; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) | ||||
| { | ||||
|   /* TODO: Merge this functions with the Linux version. This function should be platform independent. */ | ||||
|   struct hid_device_info *devs, *cur_dev; | ||||
|   const char *path_to_open = NULL; | ||||
|   hid_device *handle = NULL; | ||||
|    | ||||
|   devs = hid_enumerate(vendor_id, product_id); | ||||
|   cur_dev = devs; | ||||
|   while (cur_dev) { | ||||
|     if (cur_dev->vendor_id == vendor_id && | ||||
|         cur_dev->product_id == product_id) { | ||||
|       if (serial_number) { | ||||
|         if (wcscmp(serial_number, cur_dev->serial_number) == 0) { | ||||
|           path_to_open = cur_dev->path; | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|       else { | ||||
|         path_to_open = cur_dev->path; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     cur_dev = cur_dev->next; | ||||
|   } | ||||
|  | ||||
|   if (path_to_open) { | ||||
|     /* Open the device */ | ||||
|     handle = hid_open_path(path_to_open); | ||||
|   } | ||||
|  | ||||
|   hid_free_enumeration(devs); | ||||
|    | ||||
|   return handle; | ||||
| } | ||||
|  | ||||
| HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) | ||||
| { | ||||
|   hid_device *dev; | ||||
|   HIDP_CAPS caps; | ||||
|   PHIDP_PREPARSED_DATA pp_data = NULL; | ||||
|   BOOLEAN res; | ||||
|   NTSTATUS nt_res; | ||||
|  | ||||
|   if (hid_init() < 0) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   dev = new_hid_device(); | ||||
|  | ||||
|   /* Open a handle to the device */ | ||||
|   dev->device_handle = open_device(path, FALSE); | ||||
|  | ||||
|   /* Check validity of write_handle. */ | ||||
|   if (dev->device_handle == INVALID_HANDLE_VALUE) { | ||||
|     /* Unable to open the device. */ | ||||
|     register_error(dev, "CreateFile"); | ||||
|     goto err; | ||||
|   } | ||||
|  | ||||
|   /* Set the Input Report buffer size to 64 reports. */ | ||||
|   res = HidD_SetNumInputBuffers(dev->device_handle, 64); | ||||
|   if (!res) { | ||||
|     register_error(dev, "HidD_SetNumInputBuffers"); | ||||
|     goto err; | ||||
|   } | ||||
|  | ||||
|   /* Get the Input Report length for the device. */ | ||||
|   res = HidD_GetPreparsedData(dev->device_handle, &pp_data); | ||||
|   if (!res) { | ||||
|     register_error(dev, "HidD_GetPreparsedData"); | ||||
|     goto err; | ||||
|   } | ||||
|   nt_res = HidP_GetCaps(pp_data, &caps); | ||||
|   if (nt_res != HIDP_STATUS_SUCCESS) { | ||||
|     register_error(dev, "HidP_GetCaps");   | ||||
|     goto err_pp_data; | ||||
|   } | ||||
|   dev->output_report_length = caps.OutputReportByteLength; | ||||
|   dev->input_report_length = caps.InputReportByteLength; | ||||
|   HidD_FreePreparsedData(pp_data); | ||||
|  | ||||
|   dev->read_buf = (char*) malloc(dev->input_report_length); | ||||
|  | ||||
|   return dev; | ||||
|  | ||||
| err_pp_data: | ||||
|     HidD_FreePreparsedData(pp_data); | ||||
| err:   | ||||
|     free_hid_device(dev); | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length) | ||||
| { | ||||
|   DWORD bytes_written; | ||||
|   BOOL res; | ||||
|  | ||||
|   OVERLAPPED ol; | ||||
|   unsigned char *buf; | ||||
|   memset(&ol, 0, sizeof(ol)); | ||||
|  | ||||
|   /* Make sure the right number of bytes are passed to WriteFile. Windows | ||||
|      expects the number of bytes which are in the _longest_ report (plus | ||||
|      one for the report number) bytes even if the data is a report | ||||
|      which is shorter than that. Windows gives us this value in | ||||
|      caps.OutputReportByteLength. If a user passes in fewer bytes than this, | ||||
|      create a temporary buffer which is the proper size. */ | ||||
|   if (length >= dev->output_report_length) { | ||||
|     /* The user passed the right number of bytes. Use the buffer as-is. */ | ||||
|     buf = (unsigned char *) data; | ||||
|   } else { | ||||
|     /* Create a temporary buffer and copy the user's data | ||||
|        into it, padding the rest with zeros. */ | ||||
|     buf = (unsigned char *) malloc(dev->output_report_length); | ||||
|     memcpy(buf, data, length); | ||||
|     memset(buf + length, 0, dev->output_report_length - length); | ||||
|     length = dev->output_report_length; | ||||
|   } | ||||
|  | ||||
|   res = WriteFile(dev->device_handle, buf, length, NULL, &ol); | ||||
|    | ||||
|   if (!res) { | ||||
|     if (GetLastError() != ERROR_IO_PENDING) { | ||||
|       /* WriteFile() failed. Return error. */ | ||||
|       register_error(dev, "WriteFile"); | ||||
|       bytes_written = -1; | ||||
|       goto end_of_function; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* Wait here until the write is done. This makes | ||||
|      hid_write() synchronous. */ | ||||
|   res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/); | ||||
|   if (!res) { | ||||
|     /* The Write operation failed. */ | ||||
|     register_error(dev, "WriteFile"); | ||||
|     bytes_written = -1; | ||||
|     goto end_of_function; | ||||
|   } | ||||
|  | ||||
| end_of_function: | ||||
|   if (buf != data) | ||||
|     free(buf); | ||||
|  | ||||
|   return bytes_written; | ||||
| } | ||||
|  | ||||
|  | ||||
| int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) | ||||
| { | ||||
|   DWORD bytes_read = 0; | ||||
|   size_t copy_len = 0; | ||||
|   BOOL res; | ||||
|  | ||||
|   /* Copy the handle for convenience. */ | ||||
|   HANDLE ev = dev->ol.hEvent; | ||||
|  | ||||
|   if (!dev->read_pending) { | ||||
|     /* Start an Overlapped I/O read. */ | ||||
|     dev->read_pending = TRUE; | ||||
|     memset(dev->read_buf, 0, dev->input_report_length); | ||||
|     ResetEvent(ev); | ||||
|     res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol); | ||||
|      | ||||
|     if (!res) { | ||||
|       if (GetLastError() != ERROR_IO_PENDING) { | ||||
|         /* ReadFile() has failed. | ||||
|            Clean up and return error. */ | ||||
|         CancelIo(dev->device_handle); | ||||
|         dev->read_pending = FALSE; | ||||
|         goto end_of_function; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (milliseconds >= 0) { | ||||
|     /* See if there is any data yet. */ | ||||
|     res = WaitForSingleObject(ev, milliseconds); | ||||
|     if (res != WAIT_OBJECT_0) { | ||||
|       /* There was no data this time. Return zero bytes available, | ||||
|          but leave the Overlapped I/O running. */ | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* Either WaitForSingleObject() told us that ReadFile has completed, or | ||||
|      we are in non-blocking mode. Get the number of bytes read. The actual | ||||
|      data has been copied to the data[] array which was passed to ReadFile(). */ | ||||
|   res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/); | ||||
|    | ||||
|   /* Set pending back to false, even if GetOverlappedResult() returned error. */ | ||||
|   dev->read_pending = FALSE; | ||||
|  | ||||
|   if (res && bytes_read > 0) { | ||||
|     if (dev->read_buf[0] == 0x0) { | ||||
|       /* If report numbers aren't being used, but Windows sticks a report | ||||
|          number (0x0) on the beginning of the report anyway. To make this | ||||
|          work like the other platforms, and to make it work more like the | ||||
|          HID spec, we'll skip over this byte. */ | ||||
|       bytes_read--; | ||||
|       copy_len = length > bytes_read ? bytes_read : length; | ||||
|       memcpy(data, dev->read_buf+1, copy_len); | ||||
|     } | ||||
|     else { | ||||
|       /* Copy the whole buffer, report number and all. */ | ||||
|       copy_len = length > bytes_read ? bytes_read : length; | ||||
|       memcpy(data, dev->read_buf, copy_len); | ||||
|     } | ||||
|   } | ||||
|    | ||||
| end_of_function: | ||||
|   if (!res) { | ||||
|     register_error(dev, "GetOverlappedResult"); | ||||
|     return -1; | ||||
|   } | ||||
|    | ||||
|   return copy_len; | ||||
| } | ||||
|  | ||||
| int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length) | ||||
| { | ||||
|   return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); | ||||
| } | ||||
|  | ||||
| int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock) | ||||
| { | ||||
|   dev->blocking = !nonblock; | ||||
|   return 0; /* Success */ | ||||
| } | ||||
|  | ||||
| int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) | ||||
| { | ||||
|   BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, length); | ||||
|   if (!res) { | ||||
|     register_error(dev, "HidD_SetFeature"); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   return length; | ||||
| } | ||||
|  | ||||
|  | ||||
| int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) | ||||
| { | ||||
|   BOOL res; | ||||
| #if 0 | ||||
|   res = HidD_GetFeature(dev->device_handle, data, length); | ||||
|   if (!res) { | ||||
|     register_error(dev, "HidD_GetFeature"); | ||||
|     return -1; | ||||
|   } | ||||
|   return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */ | ||||
| #else | ||||
|   DWORD bytes_returned; | ||||
|  | ||||
|   OVERLAPPED ol; | ||||
|   memset(&ol, 0, sizeof(ol)); | ||||
|  | ||||
|   res = DeviceIoControl(dev->device_handle, | ||||
|     IOCTL_HID_GET_FEATURE, | ||||
|     data, length, | ||||
|     data, length, | ||||
|     &bytes_returned, &ol); | ||||
|  | ||||
|   if (!res) { | ||||
|     if (GetLastError() != ERROR_IO_PENDING) { | ||||
|       /* DeviceIoControl() failed. Return error. */ | ||||
|       register_error(dev, "Send Feature Report DeviceIoControl"); | ||||
|       return -1; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* Wait here until the write is done. This makes | ||||
|      hid_get_feature_report() synchronous. */ | ||||
|   res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/); | ||||
|   if (!res) { | ||||
|     /* The operation failed. */ | ||||
|     register_error(dev, "Send Feature Report GetOverLappedResult"); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   /* bytes_returned does not include the first byte which contains the | ||||
|      report ID. The data buffer actually contains one more byte than | ||||
|      bytes_returned. */ | ||||
|   bytes_returned++; | ||||
|  | ||||
|   return bytes_returned; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev) | ||||
| { | ||||
|   if (!dev) | ||||
|     return; | ||||
|   CancelIo(dev->device_handle); | ||||
|   free_hid_device(dev); | ||||
| } | ||||
|  | ||||
| int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) | ||||
| { | ||||
|   BOOL res; | ||||
|  | ||||
|   res = HidD_GetManufacturerString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)); | ||||
|   if (!res) { | ||||
|     register_error(dev, "HidD_GetManufacturerString"); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) | ||||
| { | ||||
|   BOOL res; | ||||
|  | ||||
|   res = HidD_GetProductString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)); | ||||
|   if (!res) { | ||||
|     register_error(dev, "HidD_GetProductString"); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) | ||||
| { | ||||
|   BOOL res; | ||||
|  | ||||
|   res = HidD_GetSerialNumberString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)); | ||||
|   if (!res) { | ||||
|     register_error(dev, "HidD_GetSerialNumberString"); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) | ||||
| { | ||||
|   BOOL res; | ||||
|  | ||||
|   res = HidD_GetIndexedString(dev->device_handle, string_index, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)); | ||||
|   if (!res) { | ||||
|     register_error(dev, "HidD_GetIndexedString"); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev) | ||||
| { | ||||
|   return (wchar_t*)dev->last_error_str; | ||||
| } | ||||
|  | ||||
|  | ||||
| /*#define PICPGM*/ | ||||
| /*#define S11*/ | ||||
| #define P32 | ||||
| #ifdef S11  | ||||
|   unsigned short VendorID = 0xa0a0; | ||||
|   unsigned short ProductID = 0x0001; | ||||
| #endif | ||||
|  | ||||
| #ifdef P32 | ||||
|   unsigned short VendorID = 0x04d8; | ||||
|   unsigned short ProductID = 0x3f; | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef PICPGM | ||||
|   unsigned short VendorID = 0x04d8; | ||||
|   unsigned short ProductID = 0x0033; | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #if 0 | ||||
| int __cdecl main(int argc, char* argv[]) | ||||
| { | ||||
|   int res; | ||||
|   unsigned char buf[65]; | ||||
|  | ||||
|   UNREFERENCED_PARAMETER(argc); | ||||
|   UNREFERENCED_PARAMETER(argv); | ||||
|  | ||||
|   /* Set up the command buffer. */ | ||||
|   memset(buf,0x00,sizeof(buf)); | ||||
|   buf[0] = 0; | ||||
|   buf[1] = 0x81; | ||||
|    | ||||
|  | ||||
|   /* Open the device. */ | ||||
|   int handle = open(VendorID, ProductID, L"12345"); | ||||
|   if (handle < 0) | ||||
|     printf("> unable to open device\n"); | ||||
|  | ||||
|  | ||||
|   /* Toggle LED (cmd 0x80) */ | ||||
|   buf[1] = 0x80; | ||||
|   res = write(handle, buf, 65); | ||||
|   if (res < 0) | ||||
|     printf("> Unable to write()\n"); | ||||
|  | ||||
|   /* Request state (cmd 0x81) */ | ||||
|   buf[1] = 0x81; | ||||
|   write(handle, buf, 65); | ||||
|   if (res < 0) | ||||
|     printf("> Unable to write() (2)\n"); | ||||
|  | ||||
|   /* Read requested state */ | ||||
|   read(handle, buf, 65); | ||||
|   if (res < 0) | ||||
|     printf("> Unable to read()\n"); | ||||
|  | ||||
|   /* Print out the returned buffer. */ | ||||
|   for (int i = 0; i < 4; i++) | ||||
|     printf("> buf[%d]: %d\n", i, buf[i]); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } /* extern "C" */ | ||||
| #endif | ||||
							
								
								
									
										391
									
								
								lib/hidflash/hidapi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										391
									
								
								lib/hidflash/hidapi.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,391 @@ | ||||
| /******************************************************* | ||||
|  HIDAPI - Multi-Platform library for | ||||
|  communication with HID devices. | ||||
|  | ||||
|  Alan Ott | ||||
|  Signal 11 Software | ||||
|  | ||||
|  8/22/2009 | ||||
|  | ||||
|  Copyright 2009, All Rights Reserved. | ||||
|  | ||||
|  At the discretion of the user of this library, | ||||
|  this software may be licensed under the terms of the | ||||
|  GNU General Public License v3, a BSD-Style license, or the | ||||
|  original HIDAPI license as outlined in the LICENSE.txt, | ||||
|  LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt | ||||
|  files located at the root of the source distribution. | ||||
|  These files may also be found in the public source | ||||
|  code repository located at: | ||||
|         http://github.com/signal11/hidapi . | ||||
| ********************************************************/ | ||||
|  | ||||
| /** @file | ||||
|  * @defgroup API hidapi API | ||||
|  */ | ||||
|  | ||||
| #ifndef HIDAPI_H__ | ||||
| #define HIDAPI_H__ | ||||
|  | ||||
| #include <wchar.h> | ||||
|  | ||||
| #ifdef _WIN32 | ||||
|       #define HID_API_EXPORT __declspec(dllexport) | ||||
|       #define HID_API_CALL | ||||
| #else | ||||
|       #define HID_API_EXPORT /**< API export macro */ | ||||
|       #define HID_API_CALL /**< API call macro */ | ||||
| #endif | ||||
|  | ||||
| #define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|     struct hid_device_; | ||||
|     typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ | ||||
|  | ||||
|     /** hidapi info structure */ | ||||
|     struct hid_device_info { | ||||
|       /** Platform-specific device path */ | ||||
|       char *path; | ||||
|       /** Device Vendor ID */ | ||||
|       unsigned short vendor_id; | ||||
|       /** Device Product ID */ | ||||
|       unsigned short product_id; | ||||
|       /** Serial Number */ | ||||
|       wchar_t *serial_number; | ||||
|       /** Device Release Number in binary-coded decimal, | ||||
|           also known as Device Version Number */ | ||||
|       unsigned short release_number; | ||||
|       /** Manufacturer String */ | ||||
|       wchar_t *manufacturer_string; | ||||
|       /** Product string */ | ||||
|       wchar_t *product_string; | ||||
|       /** Usage Page for this Device/Interface | ||||
|           (Windows/Mac only). */ | ||||
|       unsigned short usage_page; | ||||
|       /** Usage for this Device/Interface | ||||
|           (Windows/Mac only).*/ | ||||
|       unsigned short usage; | ||||
|       /** The USB interface which this logical device | ||||
|           represents. Valid on both Linux implementations | ||||
|           in all cases, and valid on the Windows implementation | ||||
|           only if the device contains more than one interface. */ | ||||
|       int interface_number; | ||||
|  | ||||
|       /** Pointer to the next device */ | ||||
|       struct hid_device_info *next; | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     /** @brief Initialize the HIDAPI library. | ||||
|  | ||||
|       This function initializes the HIDAPI library. Calling it is not | ||||
|       strictly necessary, as it will be called automatically by | ||||
|       hid_enumerate() and any of the hid_open_*() functions if it is | ||||
|       needed.  This function should be called at the beginning of | ||||
|       execution however, if there is a chance of HIDAPI handles | ||||
|       being opened by different threads simultaneously. | ||||
|        | ||||
|       @ingroup API | ||||
|  | ||||
|       @returns | ||||
|         This function returns 0 on success and -1 on error. | ||||
|     */ | ||||
|     int HID_API_EXPORT HID_API_CALL hid_init(void); | ||||
|  | ||||
|     /** @brief Finalize the HIDAPI library. | ||||
|  | ||||
|       This function frees all of the static data associated with | ||||
|       HIDAPI. It should be called at the end of execution to avoid | ||||
|       memory leaks. | ||||
|  | ||||
|       @ingroup API | ||||
|  | ||||
|         @returns | ||||
|         This function returns 0 on success and -1 on error. | ||||
|     */ | ||||
|     int HID_API_EXPORT HID_API_CALL hid_exit(void); | ||||
|  | ||||
|     /** @brief Enumerate the HID Devices. | ||||
|  | ||||
|       This function returns a linked list of all the HID devices | ||||
|       attached to the system which match vendor_id and product_id. | ||||
|       If @p vendor_id is set to 0 then any vendor matches. | ||||
|       If @p product_id is set to 0 then any product matches. | ||||
|       If @p vendor_id and @p product_id are both set to 0, then | ||||
|       all HID devices will be returned. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param vendor_id The Vendor ID (VID) of the types of device | ||||
|         to open. | ||||
|       @param product_id The Product ID (PID) of the types of | ||||
|         device to open. | ||||
|  | ||||
|         @returns | ||||
|           This function returns a pointer to a linked list of type | ||||
|           struct #hid_device, containing information about the HID devices | ||||
|           attached to the system, or NULL in the case of failure. Free | ||||
|           this linked list by calling hid_free_enumeration(). | ||||
|     */ | ||||
|     struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); | ||||
|  | ||||
|     /** @brief Free an enumeration Linked List | ||||
|  | ||||
|         This function frees a linked list created by hid_enumerate(). | ||||
|  | ||||
|       @ingroup API | ||||
|         @param devs Pointer to a list of struct_device returned from | ||||
|                 hid_enumerate(). | ||||
|     */ | ||||
|     void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); | ||||
|  | ||||
|     /** @brief Open a HID device using a Vendor ID (VID), Product ID | ||||
|       (PID) and optionally a serial number. | ||||
|  | ||||
|       If @p serial_number is NULL, the first device with the | ||||
|       specified VID and PID is opened. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param vendor_id The Vendor ID (VID) of the device to open. | ||||
|       @param product_id The Product ID (PID) of the device to open. | ||||
|       @param serial_number The Serial Number of the device to open | ||||
|                        (Optionally NULL). | ||||
|  | ||||
|       @returns | ||||
|         This function returns a pointer to a #hid_device object on | ||||
|         success or NULL on failure. | ||||
|     */ | ||||
|     HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number); | ||||
|  | ||||
|     /** @brief Open a HID device by its path name. | ||||
|  | ||||
|       The path name be determined by calling hid_enumerate(), or a | ||||
|       platform-specific path name can be used (eg: /dev/hidraw0 on | ||||
|       Linux). | ||||
|  | ||||
|       @ingroup API | ||||
|         @param path The path name of the device to open | ||||
|  | ||||
|       @returns | ||||
|         This function returns a pointer to a #hid_device object on | ||||
|         success or NULL on failure. | ||||
|     */ | ||||
|     HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); | ||||
|  | ||||
|     /** @brief Write an Output report to a HID device. | ||||
|  | ||||
|       The first byte of @p data[] must contain the Report ID. For | ||||
|       devices which only support a single report, this must be set | ||||
|       to 0x0. The remaining bytes contain the report data. Since | ||||
|       the Report ID is mandatory, calls to hid_write() will always | ||||
|       contain one more byte than the report contains. For example, | ||||
|       if a hid report is 16 bytes long, 17 bytes must be passed to | ||||
|       hid_write(), the Report ID (or 0x0, for devices with a | ||||
|       single report), followed by the report data (16 bytes). In | ||||
|       this example, the length passed in would be 17. | ||||
|  | ||||
|       hid_write() will send the data on the first OUT endpoint, if | ||||
|       one exists. If it does not, it will send the data through | ||||
|       the Control Endpoint (Endpoint 0). | ||||
|  | ||||
|       @ingroup API | ||||
|       @param device A device handle returned from hid_open(). | ||||
|       @param data The data to send, including the report number as | ||||
|         the first byte. | ||||
|       @param length The length in bytes of the data to send. | ||||
|  | ||||
|       @returns | ||||
|         This function returns the actual number of bytes written and | ||||
|         -1 on error. | ||||
|     */ | ||||
|     int  HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length); | ||||
|  | ||||
|     /** @brief Read an Input report from a HID device with timeout. | ||||
|  | ||||
|       Input reports are returned | ||||
|       to the host through the INTERRUPT IN endpoint. The first byte will | ||||
|       contain the Report number if the device uses numbered reports. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param device A device handle returned from hid_open(). | ||||
|       @param data A buffer to put the read data into. | ||||
|       @param length The number of bytes to read. For devices with | ||||
|         multiple reports, make sure to read an extra byte for | ||||
|         the report number. | ||||
|       @param milliseconds timeout in milliseconds or -1 for blocking wait. | ||||
|  | ||||
|       @returns | ||||
|         This function returns the actual number of bytes read and | ||||
|         -1 on error. If no packet was available to be read within | ||||
|         the timeout period, this function returns 0. | ||||
|     */ | ||||
|     int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); | ||||
|  | ||||
|     /** @brief Read an Input report from a HID device. | ||||
|  | ||||
|       Input reports are returned | ||||
|         to the host through the INTERRUPT IN endpoint. The first byte will | ||||
|       contain the Report number if the device uses numbered reports. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param device A device handle returned from hid_open(). | ||||
|       @param data A buffer to put the read data into. | ||||
|       @param length The number of bytes to read. For devices with | ||||
|         multiple reports, make sure to read an extra byte for | ||||
|         the report number. | ||||
|  | ||||
|       @returns | ||||
|         This function returns the actual number of bytes read and | ||||
|         -1 on error. If no packet was available to be read and | ||||
|         the handle is in non-blocking mode, this function returns 0. | ||||
|     */ | ||||
|     int  HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length); | ||||
|  | ||||
|     /** @brief Set the device handle to be non-blocking. | ||||
|  | ||||
|       In non-blocking mode calls to hid_read() will return | ||||
|       immediately with a value of 0 if there is no data to be | ||||
|       read. In blocking mode, hid_read() will wait (block) until | ||||
|       there is data to read before returning. | ||||
|  | ||||
|       Nonblocking can be turned on and off at any time. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param device A device handle returned from hid_open(). | ||||
|       @param nonblock enable or not the nonblocking reads | ||||
|        - 1 to enable nonblocking | ||||
|        - 0 to disable nonblocking. | ||||
|  | ||||
|       @returns | ||||
|         This function returns 0 on success and -1 on error. | ||||
|     */ | ||||
|     int  HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); | ||||
|  | ||||
|     /** @brief Send a Feature report to the device. | ||||
|  | ||||
|       Feature reports are sent over the Control endpoint as a | ||||
|       Set_Report transfer.  The first byte of @p data[] must | ||||
|       contain the Report ID. For devices which only support a | ||||
|       single report, this must be set to 0x0. The remaining bytes | ||||
|       contain the report data. Since the Report ID is mandatory, | ||||
|       calls to hid_send_feature_report() will always contain one | ||||
|       more byte than the report contains. For example, if a hid | ||||
|       report is 16 bytes long, 17 bytes must be passed to | ||||
|       hid_send_feature_report(): the Report ID (or 0x0, for | ||||
|       devices which do not use numbered reports), followed by the | ||||
|       report data (16 bytes). In this example, the length passed | ||||
|       in would be 17. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param device A device handle returned from hid_open(). | ||||
|       @param data The data to send, including the report number as | ||||
|         the first byte. | ||||
|       @param length The length in bytes of the data to send, including | ||||
|         the report number. | ||||
|  | ||||
|       @returns | ||||
|         This function returns the actual number of bytes written and | ||||
|         -1 on error. | ||||
|     */ | ||||
|     int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); | ||||
|  | ||||
|     /** @brief Get a feature report from a HID device. | ||||
|  | ||||
|       Set the first byte of @p data[] to the Report ID of the | ||||
|       report to be read.  Make sure to allow space for this | ||||
|       extra byte in @p data[]. Upon return, the first byte will | ||||
|       still contain the Report ID, and the report data will | ||||
|       start in data[1]. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param device A device handle returned from hid_open(). | ||||
|       @param data A buffer to put the read data into, including | ||||
|         the Report ID. Set the first byte of @p data[] to the | ||||
|         Report ID of the report to be read, or set it to zero | ||||
|         if your device does not use numbered reports. | ||||
|       @param length The number of bytes to read, including an | ||||
|         extra byte for the report ID. The buffer can be longer | ||||
|         than the actual report. | ||||
|  | ||||
|       @returns | ||||
|         This function returns the number of bytes read plus | ||||
|         one for the report ID (which is still in the first | ||||
|         byte), or -1 on error. | ||||
|     */ | ||||
|     int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); | ||||
|  | ||||
|     /** @brief Close a HID device. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param device A device handle returned from hid_open(). | ||||
|     */ | ||||
|     void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); | ||||
|  | ||||
|     /** @brief Get The Manufacturer String from a HID device. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param device A device handle returned from hid_open(). | ||||
|       @param string A wide string buffer to put the data into. | ||||
|       @param maxlen The length of the buffer in multiples of wchar_t. | ||||
|  | ||||
|       @returns | ||||
|         This function returns 0 on success and -1 on error. | ||||
|     */ | ||||
|     int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); | ||||
|  | ||||
|     /** @brief Get The Product String from a HID device. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param device A device handle returned from hid_open(). | ||||
|       @param string A wide string buffer to put the data into. | ||||
|       @param maxlen The length of the buffer in multiples of wchar_t. | ||||
|  | ||||
|       @returns | ||||
|         This function returns 0 on success and -1 on error. | ||||
|     */ | ||||
|     int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); | ||||
|  | ||||
|     /** @brief Get The Serial Number String from a HID device. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param device A device handle returned from hid_open(). | ||||
|       @param string A wide string buffer to put the data into. | ||||
|       @param maxlen The length of the buffer in multiples of wchar_t. | ||||
|  | ||||
|       @returns | ||||
|         This function returns 0 on success and -1 on error. | ||||
|     */ | ||||
|     int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); | ||||
|  | ||||
|     /** @brief Get a string from a HID device, based on its string index. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param device A device handle returned from hid_open(). | ||||
|       @param string_index The index of the string to get. | ||||
|       @param string A wide string buffer to put the data into. | ||||
|       @param maxlen The length of the buffer in multiples of wchar_t. | ||||
|  | ||||
|       @returns | ||||
|         This function returns 0 on success and -1 on error. | ||||
|     */ | ||||
|     int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); | ||||
|  | ||||
|     /** @brief Get a string describing the last error which occurred. | ||||
|  | ||||
|       @ingroup API | ||||
|       @param device A device handle returned from hid_open(). | ||||
|  | ||||
|       @returns | ||||
|         This function returns a string containing the last error | ||||
|         which occurred or NULL if none has occurred. | ||||
|     */ | ||||
|     HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										280
									
								
								lib/hidflash/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								lib/hidflash/main.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,280 @@ | ||||
| /* | ||||
| * STM32 HID Bootloader - USB HID bootloader for STM32F10X | ||||
| * Copyright (c) 2018 Bruno Freitas - bruno@brunofreitas.com | ||||
| * | ||||
| * This program is free software: you can redistribute it and/or modify | ||||
| * it under the terms of the GNU General Public License as published by | ||||
| * the Free Software Foundation, either version 3 of the License, or | ||||
| * (at your option) any later version. | ||||
| * | ||||
| * This program is distributed in the hope that it will be useful, | ||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| * GNU General Public License for more details. | ||||
| * | ||||
| * You should have received a copy of the GNU General Public License | ||||
| * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
| * | ||||
| * Modified 20 April 2018 | ||||
| *	by Vassilis Serasidis <avrsite@yahoo.gr> | ||||
| *	This HID bootloader work with bluepill + STM32duino + Arduino IDE <http://www.stm32duino.com/> | ||||
| * | ||||
| * Modified 4/24/2020 | ||||
| * by Eric Callahan <arksine.code@gmail.com> | ||||
| * This version of hid-flash has been modified to work with Klipper. | ||||
| * The serial port argument is now optional.  If entered and found this program | ||||
| * will attempt to force Klipper jump to the bootloader by connecting at | ||||
| * 1200 baud and enabling DTR. | ||||
| */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <stdint.h> | ||||
| #include "rs232.h" | ||||
| #include "hidapi.h" | ||||
|  | ||||
| #define SECTOR_SIZE  1024 | ||||
| #define HID_TX_SIZE    65 | ||||
| #define HID_RX_SIZE     9 | ||||
|  | ||||
| #define VID           0x1209 | ||||
| #define PID           0xBEBA | ||||
| #define FIRMWARE_VER  0x0300 | ||||
|  | ||||
| #define MAX_PAGE_SIZE 2048 | ||||
|  | ||||
| int serial_init(char *argument, uint8_t __timer); | ||||
|  | ||||
|  | ||||
| static int usb_write(hid_device *device, uint8_t *buffer, int len) { | ||||
|   int retries = 20; | ||||
|   int retval; | ||||
|  | ||||
|   while(((retval = hid_write(device, buffer, len)) < len) && --retries) { | ||||
|     if(retval < 0) { | ||||
|       usleep(100 * 1000); // No data has been sent here. Delay and retry. | ||||
|     } else { | ||||
|       return 0; // Partial data has been sent. Firmware will be corrupted. Abort process. | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if(retries <= 0) { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| int main(int argc, char *argv[]) { | ||||
|   uint8_t page_data[SECTOR_SIZE]; | ||||
|   uint8_t hid_tx_buf[HID_TX_SIZE]; | ||||
|   uint8_t hid_rx_buf[HID_RX_SIZE]; | ||||
|   uint8_t CMD_RESET_PAGES[8] = {'B','T','L','D','C','M','D', 0x00}; | ||||
|   uint8_t CMD_REBOOT_MCU[8] = {'B','T','L','D','C','M','D', 0x01}; | ||||
|   hid_device *handle = NULL; | ||||
|   size_t read_bytes; | ||||
|   FILE *firmware_file = NULL; | ||||
|   int error = 0; | ||||
|   uint32_t n_bytes = 0; | ||||
|   int i; | ||||
|   setbuf(stdout, NULL); | ||||
|   uint8_t _timer = 0; | ||||
|  | ||||
|   printf("\n+-----------------------------------------------------------------------+\n"); | ||||
|   printf  ("|         HID-Flash v2.2.1 - STM32 HID Bootloader Flash Tool            |\n"); | ||||
|   printf  ("|     (c)      2018 - Bruno Freitas       http://www.brunofreitas.com   |\n"); | ||||
|   printf  ("|     (c) 2018-2019 - Vassilis Serasidis  https://www.serasidis.gr      |\n"); | ||||
|   printf  ("|   Customized for STM32duino ecosystem   https://www.stm32duino.com    |\n"); | ||||
|   printf  ("+-----------------------------------------------------------------------+\n\n"); | ||||
|  | ||||
|   // TODO:  This really needs an option parser | ||||
|   if(argc < 2) { | ||||
|     printf("Usage: hid-flash <bin_firmware_file> <comport (optional)> <delay (optional)>\n"); | ||||
|     return 1; | ||||
|   }else if(argc == 4){ | ||||
|     _timer = atol(argv[3]); | ||||
|   } | ||||
|  | ||||
|   firmware_file = fopen(argv[1], "rb"); | ||||
|   if(!firmware_file) { | ||||
|     printf("> Error opening firmware file: %s\n", argv[1]); | ||||
|     return error; | ||||
|   } | ||||
|  | ||||
|   if (argc > 2) { | ||||
|     if(serial_init(argv[2], _timer) == 0){ //Setting up Serial port | ||||
|       RS232_CloseComport(); | ||||
|     }else{ | ||||
|       printf("> Unable to open the [%s]\n",argv[2]); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   hid_init(); | ||||
|  | ||||
|   printf("> Searching for [%04X:%04X] device...\n",VID,PID); | ||||
|  | ||||
|   struct hid_device_info *devs, *cur_dev; | ||||
|   uint8_t valid_hid_devices = 0; | ||||
|  | ||||
|   for(i=0;i<10;i++){ //Try up to 10 times to open the HID device. | ||||
|     devs = hid_enumerate(VID, PID); | ||||
|     cur_dev = devs; | ||||
|     while (cur_dev) { //Search for valid HID Bootloader USB devices | ||||
|       if((cur_dev->vendor_id == VID)&&(cur_dev->product_id == PID)){ | ||||
|         valid_hid_devices++; | ||||
|         if(cur_dev->release_number < FIRMWARE_VER){ //The STM32 board has firmware lower than 3.00 | ||||
|           printf("\nError - Please update the firmware to the latest version (v3.00+)"); | ||||
|           goto exit; | ||||
|         } | ||||
|       } | ||||
|       cur_dev = cur_dev->next; | ||||
|     } | ||||
|     hid_free_enumeration(devs); | ||||
|     printf("#"); | ||||
|     sleep(1); | ||||
|     if(valid_hid_devices > 0) break; | ||||
|   } | ||||
|   if (valid_hid_devices == 0){ | ||||
|     printf("\nError - [%04X:%04X] device is not found :(",VID,PID); | ||||
|     error = 1; | ||||
|     goto exit; | ||||
|   } | ||||
|  | ||||
|   handle = hid_open(VID, PID, NULL); | ||||
|  | ||||
|   if (i == 10 && handle != NULL) { | ||||
|     printf("\n> Unable to open the [%04X:%04X] device.\n",VID,PID); | ||||
|     error = 1; | ||||
|     goto exit; | ||||
|   } | ||||
|  | ||||
|   printf("\n> [%04X:%04X] device is found !\n",VID,PID); | ||||
|  | ||||
|   // Send RESET PAGES command to put HID bootloader in initial stage... | ||||
|   memset(hid_tx_buf, 0, sizeof(hid_tx_buf)); //Fill the hid_tx_buf with zeros. | ||||
|   memcpy(&hid_tx_buf[1], CMD_RESET_PAGES, sizeof(CMD_RESET_PAGES)); | ||||
|  | ||||
|   printf("> Sending <reset pages> command...\n"); | ||||
|  | ||||
|   // Flash is unavailable when writing to it, so USB interrupt may fail here | ||||
|   if(!usb_write(handle, hid_tx_buf, HID_TX_SIZE)) { | ||||
|     printf("> Error while sending <reset pages> command.\n"); | ||||
|     error = 1; | ||||
|     goto exit; | ||||
|   } | ||||
|   memset(hid_tx_buf, 0, sizeof(hid_tx_buf)); | ||||
|  | ||||
|   // Send Firmware File data | ||||
|   printf("> Flashing firmware...\n"); | ||||
|  | ||||
|   memset(page_data, 0, sizeof(page_data)); | ||||
|   read_bytes = fread(page_data, 1, sizeof(page_data), firmware_file); | ||||
|  | ||||
|   while(1) { | ||||
|  | ||||
|     for(int i = 0; i < SECTOR_SIZE; i += HID_TX_SIZE - 1) { | ||||
|       memcpy(&hid_tx_buf[1], page_data + i, HID_TX_SIZE - 1); | ||||
|  | ||||
|       if((i % 1024) == 0){ | ||||
|         printf("."); | ||||
|       } | ||||
|  | ||||
|       // Flash is unavailable when writing to it, so USB interrupt may fail here | ||||
|       if(!usb_write(handle, hid_tx_buf, HID_TX_SIZE)) { | ||||
|         printf("> Error while flashing firmware data.\n"); | ||||
|         error = 1; | ||||
|         goto exit; | ||||
|       } | ||||
|       n_bytes += (HID_TX_SIZE - 1); | ||||
|       usleep(500); | ||||
|     } | ||||
|  | ||||
|     printf(" %d Bytes\n", n_bytes); | ||||
|  | ||||
|     do{ | ||||
|       hid_read(handle, hid_rx_buf, 9); | ||||
|       usleep(500); | ||||
|     // Exit the loop if we recieve 0x02 or 0x03 | ||||
|     }while((hid_rx_buf[7] & 0xFE) != 0x02); | ||||
|  | ||||
|     memset(page_data, 0, sizeof(page_data)); | ||||
|     read_bytes = fread(page_data, 1, sizeof(page_data), firmware_file); | ||||
|  | ||||
|     // For stm32f1 high density devices (2K page size) will receive a | ||||
|     // 0x03 command acknowledgement above.  In that case, we must | ||||
|     // make sure that we send a full 2K so the last page is written. | ||||
|     // Note that this issue does not affect STM32F4 devices with larger | ||||
|     // page sizes. | ||||
|     if (read_bytes == 0) { | ||||
|       if (hid_rx_buf[7] != 0x03 || (n_bytes % MAX_PAGE_SIZE) == 0) | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   printf("\n> Done!\n"); | ||||
|  | ||||
|   // Send CMD_REBOOT_MCU command to reboot the microcontroller... | ||||
|   memset(hid_tx_buf, 0, sizeof(hid_tx_buf)); | ||||
|   memcpy(&hid_tx_buf[1], CMD_REBOOT_MCU, sizeof(CMD_REBOOT_MCU)); | ||||
|  | ||||
|   printf("> Sending <reboot mcu> command...\n"); | ||||
|  | ||||
|   // Flash is unavailable when writing to it, so USB interrupt may fail here | ||||
|   if(!usb_write(handle, hid_tx_buf, HID_TX_SIZE)) { | ||||
|     printf("> Error while sending <reboot mcu> command.\n"); | ||||
|   } | ||||
|  | ||||
| exit: | ||||
|   if(handle) { | ||||
|     hid_close(handle); | ||||
|   } | ||||
|  | ||||
|   hid_exit(); | ||||
|  | ||||
|   if(firmware_file) { | ||||
|     fclose(firmware_file); | ||||
|   } | ||||
|  | ||||
|   if (argc > 2) { | ||||
|     printf("> Searching for [%s] ...\n",argv[2]); | ||||
|  | ||||
|     for(int i=0;i<5;i++){ | ||||
|       if(RS232_OpenComport(argv[2]) == 0){ | ||||
|         printf("> [%s] is found !\n",argv[2] ); | ||||
|         break; | ||||
|       } | ||||
|       sleep(1); | ||||
|     } | ||||
|  | ||||
|     if(i==5){ | ||||
|       printf("> Comport is not found\n"); | ||||
|     } | ||||
|   } | ||||
|   printf("> Finish\n"); | ||||
|  | ||||
|   return error; | ||||
| } | ||||
|  | ||||
| int serial_init(char *argument, uint8_t __timer) { | ||||
|  | ||||
|   printf("> Trying to open the [%s]...\n",argument); | ||||
|   if(RS232_OpenComport(argument)){ | ||||
|     return(1); | ||||
|   } | ||||
|   printf("> Toggling DTR...\n"); | ||||
|  | ||||
|   RS232_disableRTS(); | ||||
|   RS232_disableDTR(); | ||||
|   usleep(200000L); | ||||
|   RS232_enableDTR(); | ||||
|   usleep(200000L); | ||||
|   RS232_CloseComport(); | ||||
|  | ||||
|   //printf("A %i\n",__timer); | ||||
|   if (__timer > 0) { | ||||
|     usleep(__timer); | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										314
									
								
								lib/hidflash/rs232.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								lib/hidflash/rs232.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,314 @@ | ||||
| /* | ||||
| *************************************************************************** | ||||
| * | ||||
| * Author: Teunis van Beelen | ||||
| * | ||||
| * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Teunis van Beelen | ||||
| * | ||||
| * Email: teuniz@gmail.com | ||||
| * | ||||
| *************************************************************************** | ||||
| * | ||||
| * This program is free software: you can redistribute it and/or modify | ||||
| * it under the terms of the GNU General Public License as published by | ||||
| * the Free Software Foundation, either version 3 of the License, or | ||||
| * (at your option) any later version. | ||||
| * | ||||
| * This program is distributed in the hope that it will be useful, | ||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| * GNU General Public License for more details. | ||||
| * | ||||
| * You should have received a copy of the GNU General Public License | ||||
| * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
| * | ||||
| *************************************************************************** | ||||
| */ | ||||
|  | ||||
|  | ||||
| /* Last revision: November 22, 2017 */ | ||||
|  | ||||
| /* For more info and how to use this library, visit: http://www.teuniz.net/RS-232/ */ | ||||
|  | ||||
|  | ||||
| #include "rs232.h" | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)  /* Linux & FreeBSD */ | ||||
|  | ||||
|     int tty_fd; | ||||
|     struct termios old_termios; | ||||
|     struct termios new_termios; | ||||
|      | ||||
|  | ||||
|  int RS232_OpenComport(char *comport) { | ||||
|  | ||||
|     char str[64]= "/dev/"; | ||||
|     strcat(str, comport); | ||||
|      | ||||
|     tty_fd = open(str, O_RDWR | O_NOCTTY); | ||||
|     if (tty_fd < 0) { | ||||
|         fprintf(stderr, "error, counldn't open [%s]\n", str); | ||||
|         return 1; | ||||
|     } | ||||
|     if (tcgetattr(tty_fd, &old_termios) != 0) { | ||||
|         fprintf(stderr, "tcgetattr(fd, &old_termios) failed: %s\n", strerror(errno)); | ||||
|         return 1; | ||||
|     } | ||||
|     memset(&new_termios, 0, sizeof(new_termios)); | ||||
|     new_termios.c_iflag = IGNPAR; | ||||
|     new_termios.c_oflag = 0; | ||||
|     new_termios.c_cflag = CS8 | CREAD | CLOCAL | HUPCL; | ||||
|     new_termios.c_lflag = 0; | ||||
|     new_termios.c_cc[VINTR]    = 0; | ||||
|     new_termios.c_cc[VQUIT]    = 0; | ||||
|     new_termios.c_cc[VERASE]   = 0; | ||||
|     new_termios.c_cc[VKILL]    = 0; | ||||
|     new_termios.c_cc[VEOF]     = 4; | ||||
|     new_termios.c_cc[VTIME]    = 0; | ||||
|     new_termios.c_cc[VMIN]     = 1; | ||||
|     //new_termios.c_cc[VSWTC]    = 0; | ||||
|     new_termios.c_cc[VSTART]   = 0; | ||||
|     new_termios.c_cc[VSTOP]    = 0; | ||||
|     new_termios.c_cc[VSUSP]    = 0; | ||||
|     new_termios.c_cc[VEOL]     = 0; | ||||
|     new_termios.c_cc[VREPRINT] = 0; | ||||
|     new_termios.c_cc[VDISCARD] = 0; | ||||
|     new_termios.c_cc[VWERASE]  = 0; | ||||
|     new_termios.c_cc[VLNEXT]   = 0; | ||||
|     new_termios.c_cc[VEOL2]    = 0; | ||||
|  | ||||
|  | ||||
|     if (cfsetispeed(&new_termios, B1200) != 0) { | ||||
|         fprintf(stderr, "cfsetispeed(&new_termios, B1200) failed: %s\n", strerror(errno)); | ||||
|         return 1; | ||||
|     } | ||||
|     if (cfsetospeed(&new_termios, B1200) != 0) { | ||||
|         fprintf(stderr, "cfsetospeed(&new_termios, B1200) failed: %s\n", strerror(errno)); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     if (tcsetattr(tty_fd, TCSANOW, &new_termios) != 0) { | ||||
|         fprintf(stderr, "tcsetattr(fd, TCSANOW, &new_termios) failed: %s\n", strerror(errno)); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| //====================================================================================== | ||||
|  } | ||||
|  | ||||
|  | ||||
|  int RS232_SendByte(unsigned char byte) { | ||||
|    int n = write(tty_fd, &byte, 1); | ||||
|    if(n < 0) { | ||||
|      if(errno == EAGAIN) { | ||||
|        return 0; | ||||
|      } else { | ||||
|        return 1; | ||||
|      } | ||||
|    } | ||||
|  | ||||
|  | ||||
|    return(0); | ||||
|   } | ||||
|  | ||||
| /* | ||||
|   int RS232_ReadByte() { | ||||
|     unsigned char c; | ||||
|     if (read(tty_fd,&c,1)>0) { | ||||
|         return c; | ||||
|     } | ||||
|      | ||||
|     return -1; | ||||
|   } | ||||
| */ | ||||
|  | ||||
|  void RS232_CloseComport() { | ||||
|  | ||||
|    tcsetattr(tty_fd, TCSANOW, &old_termios); | ||||
|    close(tty_fd); | ||||
|  | ||||
|  } | ||||
|  | ||||
|  | ||||
|  void RS232_enableDTR() { | ||||
|    int status; | ||||
|  | ||||
|    if(ioctl(tty_fd, TIOCMGET, &status) == -1) { | ||||
|      perror("unable to get portstatus"); | ||||
|    } | ||||
|  | ||||
|    status |= TIOCM_DTR;    /* turn on DTR */ | ||||
|  | ||||
|    if(ioctl(tty_fd, TIOCMSET, &status) == -1) { | ||||
|      perror("unable to set portstatus"); | ||||
|    } | ||||
|  } | ||||
|  | ||||
|  | ||||
|  void RS232_disableDTR() | ||||
|  { | ||||
|    int status; | ||||
|  | ||||
|    if(ioctl(tty_fd, TIOCMGET, &status) == -1) { | ||||
|      perror("unable to get portstatus"); | ||||
|    } | ||||
|  | ||||
|    status &= ~TIOCM_DTR;    /* turn off DTR */ | ||||
|  | ||||
|    if(ioctl(tty_fd, TIOCMSET, &status) == -1) { | ||||
|      perror("unable to set portstatus"); | ||||
|    } | ||||
|  } | ||||
|  | ||||
|  | ||||
|  void RS232_enableRTS() | ||||
|  { | ||||
|    int status; | ||||
|  | ||||
|    if(ioctl(tty_fd, TIOCMGET, &status) == -1) { | ||||
|      perror("unable to get portstatus"); | ||||
|    } | ||||
|  | ||||
|    status |= TIOCM_RTS;    /* turn on RTS */ | ||||
|  | ||||
|    if(ioctl(tty_fd, TIOCMSET, &status) == -1) { | ||||
|      perror("unable to set portstatus"); | ||||
|    } | ||||
|  } | ||||
|  | ||||
|  | ||||
|  void RS232_disableRTS() { | ||||
|    int status; | ||||
|  | ||||
|    if(ioctl(tty_fd, TIOCMGET, &status) == -1) { | ||||
|      perror("unable to get portstatus"); | ||||
|    } | ||||
|  | ||||
|    status &= ~TIOCM_RTS;    /* turn off RTS */ | ||||
|  | ||||
|    if(ioctl(tty_fd, TIOCMSET, &status) == -1) { | ||||
|      perror("unable to set portstatus"); | ||||
|    } | ||||
|  } | ||||
|  | ||||
|  void RS232_send_magic(){ | ||||
|    write(tty_fd,"1EAF",4); | ||||
|  } | ||||
|  | ||||
|  | ||||
| #else  /* windows */ | ||||
|  | ||||
| HANDLE Cport; | ||||
|  | ||||
| char mode_str_2[] = "baud=9600 data=8 parity=n stop=1 dtr=off rts=off"; | ||||
|  | ||||
| int RS232_OpenComport(char *comport) | ||||
| { | ||||
| 	 | ||||
| 	//printf("%s\n %s\n %s\n %p\n", mode_str_2, comports[comport_number], comport, Cport); | ||||
|      | ||||
| 	char str[32] = "\\\\.\\"; | ||||
| 	strcat(str, comport); | ||||
| 	//printf("%s\n", str); | ||||
| 	 | ||||
|   Cport = CreateFileA(str, | ||||
|                       GENERIC_READ|GENERIC_WRITE, | ||||
|                       0,                          /* no share  */ | ||||
|                       NULL,                       /* no security */ | ||||
|                       OPEN_EXISTING, | ||||
|                       0,                          /* no threads */ | ||||
|                       NULL);                      /* no templates */ | ||||
|  | ||||
|   if(Cport==INVALID_HANDLE_VALUE) | ||||
|   { | ||||
|     //printf("> unable to open comport\n"); | ||||
|     return(1); | ||||
|   } | ||||
|  | ||||
|   DCB port_settings; | ||||
|   memset(&port_settings, 0, sizeof(port_settings));  /* clear the new struct  */ | ||||
|   port_settings.DCBlength = sizeof(port_settings); | ||||
|  | ||||
|   if(!BuildCommDCBA(mode_str_2, &port_settings)) | ||||
|   { | ||||
|     printf("> unable to set comport dcb settings\n"); | ||||
|     CloseHandle(Cport); | ||||
|     return(1); | ||||
|   } | ||||
|  | ||||
|   if(!SetCommState(Cport, &port_settings)) | ||||
|   { | ||||
|     printf("> unable to set comport cfg settings\n"); | ||||
|     CloseHandle(Cport); | ||||
|     return(1); | ||||
|   } | ||||
|  | ||||
|   COMMTIMEOUTS Cptimeouts; | ||||
|  | ||||
|   Cptimeouts.ReadIntervalTimeout         = MAXDWORD; | ||||
|   Cptimeouts.ReadTotalTimeoutMultiplier  = 0; | ||||
|   Cptimeouts.ReadTotalTimeoutConstant    = 0; | ||||
|   Cptimeouts.WriteTotalTimeoutMultiplier = 0; | ||||
|   Cptimeouts.WriteTotalTimeoutConstant   = 0; | ||||
|  | ||||
|   if(!SetCommTimeouts(Cport, &Cptimeouts)) | ||||
|   { | ||||
|     printf("> unable to set comport time-out settings\n"); | ||||
|     CloseHandle(Cport); | ||||
|     return(1); | ||||
|   } | ||||
|  | ||||
|   return(0); | ||||
| } | ||||
|  | ||||
|  | ||||
| int RS232_SendByte(unsigned char byte) | ||||
| { | ||||
|   int n; | ||||
|  | ||||
|   WriteFile(Cport, &byte, 1, (LPDWORD)((void *)&n), NULL); | ||||
|  | ||||
|   if(n<0)  return(1); | ||||
|  | ||||
|   return(0); | ||||
| } | ||||
|  | ||||
| void RS232_CloseComport() | ||||
| { | ||||
|   CloseHandle(Cport); | ||||
| } | ||||
|  | ||||
| void RS232_enableDTR() | ||||
| { | ||||
|   EscapeCommFunction(Cport, SETDTR); | ||||
| } | ||||
|  | ||||
|  | ||||
| void RS232_disableDTR() | ||||
| { | ||||
|   EscapeCommFunction(Cport, CLRDTR); | ||||
| } | ||||
|  | ||||
|  | ||||
| void RS232_enableRTS() | ||||
| { | ||||
|   EscapeCommFunction(Cport, SETRTS); | ||||
| } | ||||
|  | ||||
|  | ||||
| void RS232_disableRTS() | ||||
| { | ||||
|   EscapeCommFunction(Cport, CLRRTS); | ||||
| } | ||||
|  | ||||
| void RS232_send_magic() | ||||
| { | ||||
|   int n; | ||||
|  | ||||
|   WriteFile(Cport, "1EAF", 4, (LPDWORD)((void *)&n), NULL); | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										83
									
								
								lib/hidflash/rs232.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								lib/hidflash/rs232.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| /* | ||||
| *************************************************************************** | ||||
| * | ||||
| * Author: Teunis van Beelen | ||||
| * | ||||
| * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Teunis van Beelen | ||||
| * | ||||
| * Email: teuniz@gmail.com | ||||
| * | ||||
| *************************************************************************** | ||||
| * | ||||
| * This program is free software: you can redistribute it and/or modify | ||||
| * it under the terms of the GNU General Public License as published by | ||||
| * the Free Software Foundation, either version 3 of the License, or | ||||
| * (at your option) any later version. | ||||
| * | ||||
| * This program is distributed in the hope that it will be useful, | ||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| * GNU General Public License for more details. | ||||
| * | ||||
| * You should have received a copy of the GNU General Public License | ||||
| * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
| * | ||||
| *************************************************************************** | ||||
| */ | ||||
|  | ||||
| /** | ||||
|  * This rs232 source code file is a customized version for HID Bootloader project | ||||
|  * (c) 10 May 2018 by Vassilis Serasidis http://www.serasidis.gr <avrsite@yahoo.gr> | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| /* For more info and how to use this library, visit: http://www.teuniz.net/RS-232/ */ | ||||
|  | ||||
|  | ||||
| #ifndef rs232_INCLUDED | ||||
| #define rs232_INCLUDED | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
|  | ||||
|  | ||||
|  | ||||
| #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) | ||||
|  | ||||
| #include <termios.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <limits.h> | ||||
| #include <sys/file.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #else | ||||
|  | ||||
| #include <windows.h> | ||||
|  | ||||
| #endif | ||||
|  | ||||
| int  RS232_OpenComport(char *); | ||||
| int  RS232_SendByte(unsigned char); | ||||
| //int  RS232_ReadByte(); | ||||
| void RS232_CloseComport(); | ||||
| void RS232_enableDTR(); | ||||
| void RS232_disableDTR(); | ||||
| void RS232_enableRTS(); | ||||
| void RS232_disableRTS(); | ||||
| void RS232_send_magic(); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } /* extern "C" */ | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user