mirror of
				https://github.com/Klipper3d/klipper.git
				synced 2025-10-30 09:55:51 +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