initial commit with unmodified qt5-based bootloader flash utility source from the MLA
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build-*
|
||||||
13
qt5_src/.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Makefile
|
||||||
|
Makefile.*
|
||||||
|
.qmake.stash
|
||||||
|
|
||||||
|
*.pro.user
|
||||||
|
|
||||||
|
*_plugin_import.cpp
|
||||||
|
object_script.*
|
||||||
|
|
||||||
|
debug
|
||||||
|
release
|
||||||
|
|
||||||
|
ui_*.h
|
||||||
71
qt5_src/Bootloader/Bootloader.pro
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
TARGET = "HIDBootloader"
|
||||||
|
TEMPLATE = app
|
||||||
|
QT += sql
|
||||||
|
QT += widgets
|
||||||
|
QMAKE_CXXFLAGS_RELEASE = -Os
|
||||||
|
INCLUDEPATH += ../
|
||||||
|
SOURCES += \
|
||||||
|
Settings.cpp \
|
||||||
|
MainWindow.cpp \
|
||||||
|
main.cpp \
|
||||||
|
DeviceData.cpp \
|
||||||
|
Device.cpp \
|
||||||
|
Comm.cpp \
|
||||||
|
ImportExportHex.cpp
|
||||||
|
HEADERS += \
|
||||||
|
Settings.h \
|
||||||
|
MainWindow.h \
|
||||||
|
DeviceData.h \
|
||||||
|
Device.h \
|
||||||
|
Comm.h \
|
||||||
|
ImportExportHex.h
|
||||||
|
|
||||||
|
|
||||||
|
FORMS += MainWindow.ui \
|
||||||
|
Settings.ui
|
||||||
|
RESOURCES += resources.qrc
|
||||||
|
OTHER_FILES += windows.rc
|
||||||
|
|
||||||
|
#-------------------------------------------------
|
||||||
|
# Add the correct HIDAPI library according to what
|
||||||
|
# OS is being used
|
||||||
|
#-------------------------------------------------
|
||||||
|
win32: LIBS += -L../HIDAPI/windows
|
||||||
|
macx: LIBS += -L../HIDAPI/mac
|
||||||
|
unix: !macx: LIBS += -L../HIDAPI/linux
|
||||||
|
LIBS += -lHIDAPI
|
||||||
|
|
||||||
|
#-------------------------------------------------
|
||||||
|
# Make sure to add the required libraries or
|
||||||
|
# frameoworks for the hidapi to work depending on
|
||||||
|
# what OS is being used
|
||||||
|
#-------------------------------------------------
|
||||||
|
macx: LIBS += -framework CoreFoundation -framework IOkit
|
||||||
|
win32: LIBS += -lSetupAPI
|
||||||
|
unix: !macx: LIBS += -lusb-1.0
|
||||||
|
|
||||||
|
#-------------------------------------------------
|
||||||
|
# Make sure output directory for object file and
|
||||||
|
# executable is in the correct subdirectory
|
||||||
|
#-------------------------------------------------
|
||||||
|
macx {
|
||||||
|
DESTDIR = mac
|
||||||
|
OBJECTS_DIR = mac
|
||||||
|
MOC_DIR = mac
|
||||||
|
UI_DIR = mac
|
||||||
|
RCC_DIR = mac
|
||||||
|
}
|
||||||
|
unix: !macx {
|
||||||
|
DESTDIR = linux
|
||||||
|
OBJECTS_DIR = linux
|
||||||
|
MOC_DIR = linux
|
||||||
|
UI_DIR = linux
|
||||||
|
RCC_DIR = linux
|
||||||
|
}
|
||||||
|
win32 {
|
||||||
|
DESTDIR = windows
|
||||||
|
OBJECTS_DIR = windows
|
||||||
|
MOC_DIR = windows
|
||||||
|
UI_DIR = windows
|
||||||
|
RCC_DIR = windows
|
||||||
|
}
|
||||||
1021
qt5_src/Bootloader/Comm.cpp
Normal file
197
qt5_src/Bootloader/Comm.h
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* Copyright (c) 2009-2010, Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* Microchip licenses this software to you solely for use with Microchip
|
||||||
|
* products. The software is owned by Microchip and its licensors, and
|
||||||
|
* is protected under applicable copyright laws. All rights reserved.
|
||||||
|
*
|
||||||
|
* SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY
|
||||||
|
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR
|
||||||
|
* EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY
|
||||||
|
* OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED
|
||||||
|
* TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION,
|
||||||
|
* OR OTHER SIMILAR COSTS.
|
||||||
|
*
|
||||||
|
* To the fullest extent allowed by law, Microchip and its licensors
|
||||||
|
* liability shall not exceed the amount of fees, if any, that you
|
||||||
|
* have paid directly to Microchip to use this software.
|
||||||
|
*
|
||||||
|
* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE
|
||||||
|
* OF THESE TERMS.
|
||||||
|
*
|
||||||
|
* Author Date Comment
|
||||||
|
*************************************************************************
|
||||||
|
* T. Lawrence 2011/01/24 Initial code ported from AN1310.
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
#ifndef COMM_H
|
||||||
|
#define COMM_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "../HIDAPI/hidapi.h"
|
||||||
|
#include "Device.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define USB_PACKET_SIZE 64
|
||||||
|
#define USB_PACKET_SIZE_WITH_REPORT_ID (USB_PACKET_SIZE + 1)
|
||||||
|
|
||||||
|
|
||||||
|
// Packet commands
|
||||||
|
#define QUERY_DEVICE 0x02
|
||||||
|
#define UNLOCK_CONFIG 0x03
|
||||||
|
#define ERASE_DEVICE 0x04
|
||||||
|
#define PROGRAM_DEVICE 0x05
|
||||||
|
#define PROGRAM_COMPLETE 0x06
|
||||||
|
#define GET_DATA 0x07
|
||||||
|
#define RESET_DEVICE 0x08
|
||||||
|
#define SIGN_FLASH 0x09 //The host PC application should send this command after the verify operation has completed successfully. If checksums are used instead of a true verify (due to ALLOW_GET_DATA_COMMAND being commented), then the host PC application should send SIGN_FLASH command after is has verified the checksums are as exected. The firmware will then program the SIGNATURE_WORD into flash at the SIGNATURE_ADDRESS.
|
||||||
|
#define QUERY_EXTENDED_INFO 0x0C //Used by host PC app to get additional info about the device, beyond the basic NVM layout provided by the query device command
|
||||||
|
|
||||||
|
// Maximum number of memory regions that can be bootloaded
|
||||||
|
#define MAX_DATA_REGIONS 0x06
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_ERASE_BLOCK_SIZE 8196 //Increase this in the future if any microcontrollers with bigger than 8196 byte erase block is implemented
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Provides low level HID bootloader communication.
|
||||||
|
*/
|
||||||
|
class Comm : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void SetProgressBar(int newValue);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
hid_device *boot_device;
|
||||||
|
bool connected;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit Comm();
|
||||||
|
~Comm();
|
||||||
|
|
||||||
|
static const int SyncWaitTime;
|
||||||
|
|
||||||
|
enum ErrorCode
|
||||||
|
{
|
||||||
|
Success = 0, NotConnected, Fail, IncorrectCommand, Timeout, Other = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
QString ErrorString(ErrorCode errorCode) const;
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct MemoryRegion
|
||||||
|
{
|
||||||
|
unsigned char type;
|
||||||
|
uint32_t address;
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BootInfo
|
||||||
|
{
|
||||||
|
unsigned char command;
|
||||||
|
unsigned char bytesPerPacket;
|
||||||
|
unsigned char deviceFamily;
|
||||||
|
MemoryRegion memoryRegions[MAX_DATA_REGIONS];
|
||||||
|
unsigned char versionFlag;
|
||||||
|
unsigned char pad[7];
|
||||||
|
};
|
||||||
|
|
||||||
|
//Structure for the response to the QUERY_EXTENDED_INFO command
|
||||||
|
union ExtendedQueryInfo
|
||||||
|
{
|
||||||
|
unsigned char command;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned char command;
|
||||||
|
uint16_t bootloaderVersion;
|
||||||
|
uint16_t applicationVersion;
|
||||||
|
uint32_t signatureAddress;
|
||||||
|
uint16_t signatureValue;
|
||||||
|
uint32_t erasePageSize;
|
||||||
|
unsigned char config1LMask;
|
||||||
|
unsigned char config1HMask;
|
||||||
|
unsigned char config2LMask;
|
||||||
|
unsigned char config2HMask;
|
||||||
|
unsigned char config3LMask;
|
||||||
|
unsigned char config3HMask;
|
||||||
|
unsigned char config4LMask;
|
||||||
|
unsigned char config4HMask;
|
||||||
|
unsigned char config5LMask;
|
||||||
|
unsigned char config5HMask;
|
||||||
|
unsigned char config6LMask;
|
||||||
|
unsigned char config6HMask;
|
||||||
|
unsigned char config7LMask;
|
||||||
|
unsigned char config7HMask;
|
||||||
|
unsigned char pad[USB_PACKET_SIZE_WITH_REPORT_ID - 29];
|
||||||
|
}PIC18;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned char command;
|
||||||
|
uint16_t bootloaderVersion;
|
||||||
|
uint16_t applicationVersion;
|
||||||
|
uint32_t signatureAddress;
|
||||||
|
uint16_t signatureValue;
|
||||||
|
uint32_t erasePageSize;
|
||||||
|
#warning Replace with real stuff when implemented.
|
||||||
|
//uint16_t configxxMask...
|
||||||
|
//unsigned char pad[USB_PACKET_SIZE_WITH_REPORT_ID - XX];
|
||||||
|
}PIC24;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct WritePacket
|
||||||
|
{
|
||||||
|
unsigned char report;
|
||||||
|
unsigned char command;
|
||||||
|
union {
|
||||||
|
uint32_t address;
|
||||||
|
unsigned char LockedValue;
|
||||||
|
};
|
||||||
|
unsigned char bytesPerPacket;
|
||||||
|
unsigned char data[58];
|
||||||
|
};
|
||||||
|
struct ReadPacket
|
||||||
|
{
|
||||||
|
unsigned char command;
|
||||||
|
uint32_t address;
|
||||||
|
unsigned char bytesPerPacket;
|
||||||
|
unsigned char data[59];
|
||||||
|
};
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
void PollUSB(uint16_t deviceVIDtoPoll, uint16_t devicePIDtoPoll);
|
||||||
|
ErrorCode open(uint16_t deviceVIDtoOpen, uint16_t devicePIDtoOpen);
|
||||||
|
void close(void);
|
||||||
|
bool isConnected(void);
|
||||||
|
void Reset(void);
|
||||||
|
|
||||||
|
ErrorCode GetData(uint32_t address, unsigned char bytesPerPacket, unsigned char bytesPerAddress,
|
||||||
|
unsigned char bytesPerWord, uint32_t endAddress, unsigned char *data);
|
||||||
|
ErrorCode Program(uint32_t address, unsigned char bytesPerPacket, unsigned char bytesPerAddress,
|
||||||
|
unsigned char bytesPerWord, unsigned char deviceFamily, uint32_t endAddress, unsigned char *data);
|
||||||
|
ErrorCode Erase(void);
|
||||||
|
ErrorCode LockUnlockConfig(bool lock);
|
||||||
|
ErrorCode ReadBootloaderInfo(BootInfo* bootInfo);
|
||||||
|
ErrorCode ReadExtendedQueryInfo(ExtendedQueryInfo* extendedBootInfo);
|
||||||
|
ErrorCode SignFlash(void);
|
||||||
|
ErrorCode SendPacket(unsigned char *data, int size);
|
||||||
|
ErrorCode ReceivePacket(unsigned char *data, int size);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COMM_H
|
||||||
204
qt5_src/Bootloader/Device.cpp
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* Copyright (c) 2009-2011, Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* Microchip licenses this software to you solely for use with Microchip
|
||||||
|
* products. The software is owned by Microchip and its licensors, and
|
||||||
|
* is protected under applicable copyright laws. All rights reserved.
|
||||||
|
*
|
||||||
|
* SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY
|
||||||
|
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR
|
||||||
|
* EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY
|
||||||
|
* OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED
|
||||||
|
* TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION,
|
||||||
|
* OR OTHER SIMILAR COSTS.
|
||||||
|
*
|
||||||
|
* To the fullest extent allowed by law, Microchip and its licensors
|
||||||
|
* liability shall not exceed the amount of fees, if any, that you
|
||||||
|
* have paid directly to Microchip to use this software.
|
||||||
|
*
|
||||||
|
* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE
|
||||||
|
* OF THESE TERMS.
|
||||||
|
*
|
||||||
|
* Author Date Comment
|
||||||
|
*************************************************************************
|
||||||
|
* E. Schlunder 2010/02/01 Loading config bit fields/settings added.
|
||||||
|
* E. Schlunder 2009/04/14 Initial code ported from VB app.
|
||||||
|
* F. Schlunder 2011/06/13 Minor changes for USB HID Bootloader use.
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
#include "Device.h"
|
||||||
|
|
||||||
|
Device::Device(DeviceData *data)
|
||||||
|
{
|
||||||
|
deviceData = data;
|
||||||
|
|
||||||
|
setUnknown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::setUnknown(void)
|
||||||
|
{
|
||||||
|
family = Unknown;
|
||||||
|
|
||||||
|
bytesPerAddressFLASH = 1;
|
||||||
|
bytesPerAddressEEPROM = 1;
|
||||||
|
bytesPerAddressConfig = 1;
|
||||||
|
|
||||||
|
bytesPerWordEEPROM = 1;
|
||||||
|
bytesPerWordConfig = 2;
|
||||||
|
bytesPerWordFLASH = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device::hasEeprom(void)
|
||||||
|
{
|
||||||
|
DeviceData::MemoryRange range;
|
||||||
|
foreach(range, deviceData->ranges)
|
||||||
|
{
|
||||||
|
if(range.type == EEPROM_MEMORY)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device::hasConfig(void)
|
||||||
|
{
|
||||||
|
DeviceData::MemoryRange range;
|
||||||
|
foreach(range, deviceData->ranges)
|
||||||
|
{
|
||||||
|
if(range.type == CONFIG_MEMORY)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//This method is useful for hex file parsing. This function checks if the address indicated in the hex
|
||||||
|
//file line is contained in one of the programmable regions (ex: flash, eeprom, config words, etc.), as
|
||||||
|
//specified by the USB device, (from the query response that we received earlier). If the address
|
||||||
|
//from the hex file is contained in the programmable device address range, this function returns
|
||||||
|
//bool includedInProgrammableRange = true, with the type set to the programmable region type
|
||||||
|
//(which can be determined based on the address and the query response). This function also returns
|
||||||
|
//the new effective device address (not from the .hex file, which is a raw linear byte address, but the
|
||||||
|
//effective address the device should load into its self programming address registers, in order to
|
||||||
|
//program the contents [PIC24 uses a 16-bit word addressed flash array, so the hex file addresses
|
||||||
|
//don't match the microcontroller addresses]).
|
||||||
|
//This function also returns bool addressWasEndofRange = true, if the input hexAddress corresponded
|
||||||
|
//to the very last byte of the last address of the programmable memory region that the hexAddress
|
||||||
|
//corresponded to. Otherwise this value returns false. This provides an easy check later to
|
||||||
|
//know when an end of a region has been completed during hex file parsing.
|
||||||
|
unsigned int Device::GetDeviceAddressFromHexAddress(unsigned int hexAddress, DeviceData* pData, unsigned char& type, bool& includedInProgrammableRange, bool& addressWasEndofRange, unsigned int& bytesPerAddressAndType, unsigned int& endDeviceAddressofRegion, unsigned char*& pPCRAMBuffer)
|
||||||
|
{
|
||||||
|
DeviceData::MemoryRange range;
|
||||||
|
unsigned int flashAddress = hexAddress / bytesPerAddressFLASH;
|
||||||
|
unsigned int eepromAddress = hexAddress / bytesPerAddressEEPROM;
|
||||||
|
unsigned int configAddress = hexAddress / bytesPerAddressConfig;
|
||||||
|
unsigned char* pRAMDataBuffer;
|
||||||
|
unsigned int byteOffset;
|
||||||
|
|
||||||
|
|
||||||
|
//Loop for each of the previously identified programmable regions, based on the results of the
|
||||||
|
//previous Query device response packet.
|
||||||
|
foreach(range, pData->ranges)
|
||||||
|
{
|
||||||
|
//Find what address range the hex address seems to contained within (if any, could be none, in
|
||||||
|
//the case the .hex file contains info that is not part of the bootloader re-programmable region of flash).
|
||||||
|
if((range.type == PROGRAM_MEMORY) && (flashAddress >= range.start) && (flashAddress < range.end))
|
||||||
|
{
|
||||||
|
includedInProgrammableRange = true;
|
||||||
|
if(range.start != 0)
|
||||||
|
{
|
||||||
|
byteOffset = ((flashAddress - range.start) * bytesPerAddressFLASH) + (hexAddress % bytesPerAddressFLASH);
|
||||||
|
pRAMDataBuffer = range.pDataBuffer + byteOffset;
|
||||||
|
pPCRAMBuffer = pRAMDataBuffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pPCRAMBuffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = PROGRAM_MEMORY;
|
||||||
|
bytesPerAddressAndType = bytesPerAddressFLASH;
|
||||||
|
endDeviceAddressofRegion = range.end;
|
||||||
|
//Check if this was the very last byte of the very last address of the region.
|
||||||
|
//We can determine this, using the below check.
|
||||||
|
if((flashAddress == (range.end - 1)) && ((hexAddress % bytesPerAddressFLASH) == (bytesPerAddressFLASH - 1)))
|
||||||
|
{
|
||||||
|
addressWasEndofRange = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addressWasEndofRange = false;
|
||||||
|
}
|
||||||
|
return flashAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((range.type == EEPROM_MEMORY) && (eepromAddress >= range.start) && (eepromAddress < range.end))
|
||||||
|
{
|
||||||
|
includedInProgrammableRange = true;
|
||||||
|
if(range.start != 0)
|
||||||
|
{
|
||||||
|
byteOffset = ((eepromAddress - range.start) * bytesPerAddressEEPROM) + (hexAddress % bytesPerAddressEEPROM);
|
||||||
|
pRAMDataBuffer = range.pDataBuffer + byteOffset;
|
||||||
|
pPCRAMBuffer = pRAMDataBuffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pPCRAMBuffer = 0;
|
||||||
|
}
|
||||||
|
type = EEPROM_MEMORY;
|
||||||
|
bytesPerAddressAndType = bytesPerAddressEEPROM;
|
||||||
|
endDeviceAddressofRegion = range.end;
|
||||||
|
//Check if this was the very last byte of the very last address of the region.
|
||||||
|
//We can determine this, using the below check.
|
||||||
|
if((eepromAddress == (range.end - 1)) && ((eepromAddress % bytesPerAddressEEPROM) == (bytesPerAddressEEPROM - 1)))
|
||||||
|
{
|
||||||
|
addressWasEndofRange = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addressWasEndofRange = false;
|
||||||
|
}
|
||||||
|
return eepromAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((range.type == CONFIG_MEMORY) && (configAddress >= range.start) && (configAddress < range.end))
|
||||||
|
{
|
||||||
|
includedInProgrammableRange = true;
|
||||||
|
if(range.start != 0)
|
||||||
|
{
|
||||||
|
byteOffset = ((configAddress - range.start) * bytesPerAddressConfig) + (hexAddress % bytesPerAddressConfig);
|
||||||
|
pRAMDataBuffer = range.pDataBuffer + byteOffset;
|
||||||
|
pPCRAMBuffer = pRAMDataBuffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pPCRAMBuffer = 0;
|
||||||
|
}
|
||||||
|
type = CONFIG_MEMORY;
|
||||||
|
bytesPerAddressAndType = bytesPerAddressConfig;
|
||||||
|
endDeviceAddressofRegion = range.end;
|
||||||
|
//Check if this was the very last byte of the very last address of the region.
|
||||||
|
//We can determine this, using the below check.
|
||||||
|
if((configAddress == (range.end - 1)) && ((configAddress % bytesPerAddressConfig) == (bytesPerAddressConfig - 1)))
|
||||||
|
{
|
||||||
|
addressWasEndofRange = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addressWasEndofRange = false;
|
||||||
|
}
|
||||||
|
return configAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//If we get to here, that means the hex file address that was passed in was not included in any of the
|
||||||
|
//device's reported programmable memory regions.
|
||||||
|
includedInProgrammableRange = false;
|
||||||
|
addressWasEndofRange = false;
|
||||||
|
pPCRAMBuffer = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
80
qt5_src/Bootloader/Device.h
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* Copyright (c) 2009-2010, Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* Microchip licenses this software to you solely for use with Microchip
|
||||||
|
* products. The software is owned by Microchip and its licensors, and
|
||||||
|
* is protected under applicable copyright laws. All rights reserved.
|
||||||
|
*
|
||||||
|
* SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY
|
||||||
|
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR
|
||||||
|
* EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY
|
||||||
|
* OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED
|
||||||
|
* TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION,
|
||||||
|
* OR OTHER SIMILAR COSTS.
|
||||||
|
*
|
||||||
|
* To the fullest extent allowed by law, Microchip and its licensors
|
||||||
|
* liability shall not exceed the amount of fees, if any, that you
|
||||||
|
* have paid directly to Microchip to use this software.
|
||||||
|
*
|
||||||
|
* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE
|
||||||
|
* OF THESE TERMS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEVICE_H
|
||||||
|
#define DEVICE_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QLinkedList>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
#include "DeviceData.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Provides microcontroller device specific parameters, address calculations, and
|
||||||
|
* assembly code tools.
|
||||||
|
*/
|
||||||
|
class Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Families
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
PIC18 = 0x01,
|
||||||
|
PIC24 = 0x02,
|
||||||
|
PIC32 = 0x03,
|
||||||
|
PIC16 = 0x04
|
||||||
|
};
|
||||||
|
|
||||||
|
Device(DeviceData* data);
|
||||||
|
|
||||||
|
void setUnknown(void);
|
||||||
|
|
||||||
|
Families family;
|
||||||
|
|
||||||
|
unsigned int bytesPerPacket;
|
||||||
|
unsigned int bytesPerWordFLASH;
|
||||||
|
unsigned int bytesPerWordEEPROM;
|
||||||
|
unsigned int bytesPerWordConfig;
|
||||||
|
|
||||||
|
unsigned int bytesPerAddressFLASH;
|
||||||
|
unsigned int bytesPerAddressEEPROM;
|
||||||
|
unsigned int bytesPerAddressConfig;
|
||||||
|
|
||||||
|
bool hasEeprom(void);
|
||||||
|
bool hasConfig(void);
|
||||||
|
|
||||||
|
bool hasConfigAsFlash(void);
|
||||||
|
bool hasConfigAsFuses(void);
|
||||||
|
|
||||||
|
unsigned int GetDeviceAddressFromHexAddress(unsigned int hexAddress, DeviceData* pData, unsigned char& type, bool& includedInProgrammableRange, bool& addressWasEndofRange, unsigned int& bytesPerAddressAndType, unsigned int& endDeviceAddressofRegion, unsigned char*& pPCRAMBuffer);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DeviceData *deviceData;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEVICE_H
|
||||||
40
qt5_src/Bootloader/DeviceData.cpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* Copyright (c) 2009-2011, Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* Microchip licenses this software to you solely for use with Microchip
|
||||||
|
* products. The software is owned by Microchip and its licensors, and
|
||||||
|
* is protected under applicable copyright laws. All rights reserved.
|
||||||
|
*
|
||||||
|
* SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY
|
||||||
|
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR
|
||||||
|
* EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY
|
||||||
|
* OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED
|
||||||
|
* TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION,
|
||||||
|
* OR OTHER SIMILAR COSTS.
|
||||||
|
*
|
||||||
|
* To the fullest extent allowed by law, Microchip and its licensors
|
||||||
|
* liability shall not exceed the amount of fees, if any, that you
|
||||||
|
* have paid directly to Microchip to use this software.
|
||||||
|
*
|
||||||
|
* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE
|
||||||
|
* OF THESE TERMS.
|
||||||
|
*
|
||||||
|
* Author Date Comment
|
||||||
|
*************************************************************************
|
||||||
|
* E. Schlunder 2009/05/07 Added code for CRC calculation.
|
||||||
|
* E. Schlunder 2009/04/29 Code ported from PicKit2 pk2cmd source code.
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#include "DeviceData.h"
|
||||||
|
|
||||||
|
DeviceData::DeviceData()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceData::~DeviceData()
|
||||||
|
{
|
||||||
|
}
|
||||||
62
qt5_src/Bootloader/DeviceData.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* Copyright (c) 2009-2011, Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* Microchip licenses this software to you solely for use with Microchip
|
||||||
|
* products. The software is owned by Microchip and its licensors, and
|
||||||
|
* is protected under applicable copyright laws. All rights reserved.
|
||||||
|
*
|
||||||
|
* SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY
|
||||||
|
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR
|
||||||
|
* EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY
|
||||||
|
* OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED
|
||||||
|
* TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION,
|
||||||
|
* OR OTHER SIMILAR COSTS.
|
||||||
|
*
|
||||||
|
* To the fullest extent allowed by law, Microchip and its licensors
|
||||||
|
* liability shall not exceed the amount of fees, if any, that you
|
||||||
|
* have paid directly to Microchip to use this software.
|
||||||
|
*
|
||||||
|
* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE
|
||||||
|
* OF THESE TERMS.
|
||||||
|
*/
|
||||||
|
#ifndef DEVICEDATA_H
|
||||||
|
#define DEVICEDATA_H
|
||||||
|
|
||||||
|
// Types of memory regions
|
||||||
|
#define PROGRAM_MEMORY 0x01
|
||||||
|
#define EEPROM_MEMORY 0x02
|
||||||
|
#define CONFIG_MEMORY 0x03
|
||||||
|
#define USERID_MEMORY 0x04
|
||||||
|
#define END_OF_TYPES_LIST 0xFF
|
||||||
|
#define BOOTLOADER_V1_01_OR_NEWER_FLAG 0xA5 //Tacked on in region Type6 byte, to indicate when using newer version of bootloader with extended query info available
|
||||||
|
|
||||||
|
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Provides in-memory, PC representation of microcontroller device memory contents.
|
||||||
|
*/
|
||||||
|
class DeviceData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeviceData();
|
||||||
|
~DeviceData();
|
||||||
|
|
||||||
|
struct MemoryRange
|
||||||
|
{
|
||||||
|
unsigned char type;
|
||||||
|
unsigned int start;
|
||||||
|
unsigned int end;
|
||||||
|
unsigned int dataBufferLength;
|
||||||
|
unsigned char* pDataBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
QList<DeviceData::MemoryRange> ranges;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEVICEDATA_H
|
||||||
287
qt5_src/Bootloader/ImportExportHex.cpp
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* Copyright (c) 2005-2010, Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* Microchip licenses this software to you solely for use with Microchip
|
||||||
|
* products. The software is owned by Microchip and its licensors, and
|
||||||
|
* is protected under applicable copyright laws. All rights reserved.
|
||||||
|
*
|
||||||
|
* SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY
|
||||||
|
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR
|
||||||
|
* EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY
|
||||||
|
* OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED
|
||||||
|
* TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION,
|
||||||
|
* OR OTHER SIMILAR COSTS.
|
||||||
|
*
|
||||||
|
* To the fullest extent allowed by law, Microchip and its licensors
|
||||||
|
* liability shall not exceed the amount of fees, if any, that you
|
||||||
|
* have paid directly to Microchip to use this software.
|
||||||
|
*
|
||||||
|
* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE
|
||||||
|
* OF THESE TERMS.
|
||||||
|
*
|
||||||
|
* Author Date Ver Comment
|
||||||
|
*************************************************************************
|
||||||
|
* E. Schlunder 2009/04/29 0.01 Code ported from PicKit2 pk2cmd source code.
|
||||||
|
* F. Schlunder 2011/06/13 2.90 Some changes for USB HID Bootloader use.
|
||||||
|
* F. Schlunder 2011/07/06 2.90a Updated ImportHexFile() function so it can
|
||||||
|
* support importing of hex files with
|
||||||
|
* "non-monotonic" line address ordering.
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include "ImportExportHex.h"
|
||||||
|
#include "Device.h"
|
||||||
|
|
||||||
|
|
||||||
|
HexImporter::HexImporter(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HexImporter::~HexImporter(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
PIC16Fxx parts use only one address for each FLASH program word. Address 0 has 14 bits of data, Address 1 has
|
||||||
|
14 bits of data, etc. However, the PIC16Fxx HEX file addresses each byte of data with a unique address number.
|
||||||
|
As a result, you basically have to take the HEX file address and divide by 2 to figure out the actual
|
||||||
|
PIC16Fxx FLASH memory address that the byte belongs to.
|
||||||
|
|
||||||
|
Example: PIC16F886 has 8K program words, word addressed as 0 to 0x2000.
|
||||||
|
A full HEX file for this part would have 16Kbytes of FLASH data. The HEX file bytes would
|
||||||
|
be addressed from 0 to 0x4000.
|
||||||
|
|
||||||
|
This presents a predicament for EEPROM data. Instead of starting from HEX file address 0x2100 as
|
||||||
|
the EDC device database might indicate, the HEX file has to start EEPROM data at 0x2000 + 0x2100 = 0x4100,
|
||||||
|
to avoid overlapping with the HEX file's FLASH addresses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//This function reads in Intel 32-bit .hex file formatted firmware image files and stores the
|
||||||
|
//parsed data into buffers in the PC system RAM, so that it is in a format more suitable for directly
|
||||||
|
//programming into the target microcontroller.
|
||||||
|
HexImporter::ErrorCode HexImporter::ImportHexFile(QString fileName, DeviceData* pData, Device* device)
|
||||||
|
{
|
||||||
|
QFile hexfile(fileName);
|
||||||
|
|
||||||
|
hasEndOfFileRecord = false;
|
||||||
|
fileExceedsFlash = false;
|
||||||
|
|
||||||
|
//Open the user specified .hex file.
|
||||||
|
if (!hexfile.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
|
{
|
||||||
|
return CouldNotOpenFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
bool includedInProgrammableRange;
|
||||||
|
bool addressWasEndofRange;
|
||||||
|
unsigned int segmentAddress = 0;
|
||||||
|
unsigned int byteCount;
|
||||||
|
unsigned int lineAddress;
|
||||||
|
unsigned int deviceAddress;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int endDeviceAddressofRegion;
|
||||||
|
unsigned int bytesPerAddressAndType;
|
||||||
|
|
||||||
|
unsigned char* pPCRAMBuffer = 0;
|
||||||
|
bool importedAtLeastOneByte = false;
|
||||||
|
|
||||||
|
unsigned char type;
|
||||||
|
|
||||||
|
HEX32_RECORD recordType;
|
||||||
|
|
||||||
|
QString hexByte;
|
||||||
|
unsigned int wordByte;
|
||||||
|
hasConfigBits = false;
|
||||||
|
|
||||||
|
|
||||||
|
//Parse the entire hex file, line by line.
|
||||||
|
while (!hexfile.atEnd())
|
||||||
|
{
|
||||||
|
//Fetch a line of ASCII text from the .hex file.
|
||||||
|
QByteArray line = hexfile.readLine();
|
||||||
|
|
||||||
|
//Do some error checking on the .hex file contents, to make sure the file is
|
||||||
|
//formatted like a legitimate Intel 32-bit formatted .hex file.
|
||||||
|
if ((line[0] != ':') || (line.size() < 11))
|
||||||
|
{
|
||||||
|
//Something is wrong if hex line entry, is not minimum length or does not have leading colon (ex: ":BBAAAATTCC")
|
||||||
|
//If an error is detected in the hex file formatting, the safest approach is to
|
||||||
|
//abort the operation and force the user to supply a properly formatted hex file.
|
||||||
|
if(hexfile.isOpen())
|
||||||
|
hexfile.close();
|
||||||
|
return ErrorInHexFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Extract the info prefix fields from the hex file line data.
|
||||||
|
//Example Intel 32-bit hex file line format is as follows (Note: spaces added to separate fields, actual line does not have spaces in it):
|
||||||
|
//: 10 0100 00 214601360121470136007EFE09D21901 40
|
||||||
|
//Leading ":" is always present on each line from the .hex file.
|
||||||
|
//Next two chars (10) are the byte count of the data payload on this hex file line. (ex: 10 = 0x10 = 16 bytes)
|
||||||
|
//Next four chars (0100) are the 16 bit address (needs to be combined with the extended linear address to generate a 32-bit address).
|
||||||
|
//Next two chars (00) are the "record type". "00" means it is a "data" record, which means it contains programmable payload data bytes.
|
||||||
|
//Next 2n characters are the data payload bytes (where n is the number of bytes specified in the first two numbers (10 in this example))
|
||||||
|
//Last two characters on the line are the two complement of the byte checksum computed on the other bytes in the line.
|
||||||
|
//For more details on Intel 32-bit hex file formatting see: http://en.wikipedia.org/wiki/Intel_HEX
|
||||||
|
byteCount = line.mid(1, 2).toInt(&ok, 16); //Convert the two ASCII chars corresponding to the byte count into a binary encoded byte
|
||||||
|
lineAddress = segmentAddress + line.mid(3, 4).toInt(&ok, 16); //Convert the four ASCII chars that correspond to the line address into a 16-bit binary encoded word
|
||||||
|
recordType = (HEX32_RECORD)line.mid(7, 2).toInt(&ok, 16); //Convert the two ASCII chars corresponding to the record type into a binary encoded byte
|
||||||
|
|
||||||
|
//Error check: Verify checksum byte at the end of the .hex file line is valid. Note,
|
||||||
|
//this is not the same checksum as MPLAB(R) IDE uses/computes for the entire hex file.
|
||||||
|
//This is only the mini-checksum at the end of each line in the .hex file.
|
||||||
|
unsigned int hexLineChecksum = 0;
|
||||||
|
for(i = 0; i < (byteCount+4); i++) //+4 correction is for byte count, 16-bit address, and record type bytes
|
||||||
|
{
|
||||||
|
hexByte = line.mid(1 + (2 * i), 2); //Fetch two adjacent ASCII bytes from the .hex file
|
||||||
|
wordByte = hexByte.toInt(&ok, 16); //Re-format the above two ASCII bytes into a single binary encoded byte (0x00-0xFF)
|
||||||
|
//Add the newly fetched byte to the running checksum
|
||||||
|
hexLineChecksum += (unsigned char)wordByte;
|
||||||
|
}
|
||||||
|
//Now get the two's complement of the hexLineChecksum.
|
||||||
|
hexLineChecksum = 0 - hexLineChecksum;
|
||||||
|
hexLineChecksum &= 0xFF; //Truncate to a single byte. We now have our computed checksum. This should match the .hex file.
|
||||||
|
//Fetch checksum byte from the .hex file
|
||||||
|
hexByte = line.mid(1 + (2 * i), 2); //Fetch the two ASCII bytes that correspond to the checksum byte
|
||||||
|
wordByte = hexByte.toInt(&ok, 16); //Re-format the above two ASCII bytes into a single binary encoded byte (0x00-0xFF)
|
||||||
|
wordByte &= 0xFF;
|
||||||
|
//Now check if the checksum we computed matches the one at the end of the line in the hex file.
|
||||||
|
if(hexLineChecksum != wordByte)
|
||||||
|
{
|
||||||
|
//Checksum in the hex file doesn't match the line contents. This implies a corrupted hex file.
|
||||||
|
//If an error is detected in the hex file formatting, the safest approach is to
|
||||||
|
//abort the operation and force the user to supply a properly formatted hex file.
|
||||||
|
if(hexfile.isOpen())
|
||||||
|
hexfile.close();
|
||||||
|
return ErrorInHexFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Check the record type of the hex line, to determine how to continue parsing the data.
|
||||||
|
if (recordType == END_OF_FILE) // end of file record
|
||||||
|
{
|
||||||
|
hasEndOfFileRecord = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if ((recordType == EXTENDED_SEGMENT_ADDR) || (recordType == EXTENDED_LINEAR_ADDR)) // Segment address
|
||||||
|
{
|
||||||
|
//Error check: Make sure the line contains the correct number of bytes for the specified record type
|
||||||
|
if((unsigned int)line.size() >= (11 + (2 * byteCount)))
|
||||||
|
{
|
||||||
|
//Fetch the payload, which is the upper 4 or 16-bits of the 20-bit or 32-bit hex file address
|
||||||
|
segmentAddress = line.mid(9, 4).toInt(&ok, 16);
|
||||||
|
|
||||||
|
//Load the upper bits of the address
|
||||||
|
if (recordType == EXTENDED_SEGMENT_ADDR)
|
||||||
|
{
|
||||||
|
segmentAddress <<= 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
segmentAddress <<= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update the line address, now that we know the upper bits are something new.
|
||||||
|
lineAddress = segmentAddress + line.mid(3, 4).toInt(&ok, 16);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Length appears to be wrong in hex line entry.
|
||||||
|
//If an error is detected in the hex file formatting, the safest approach is to
|
||||||
|
//abort the operation and force the user to supply a properly formatted hex file.
|
||||||
|
if(hexfile.isOpen())
|
||||||
|
hexfile.close();
|
||||||
|
return ErrorInHexFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end if ((recordType == EXTENDED_SEGMENT_ADDR) || (recordType == EXTENDED_LINEAR_ADDR)) // Segment address
|
||||||
|
else if (recordType == DATA) // Data Record
|
||||||
|
{
|
||||||
|
//Error check to make sure line is long enough to be consistent with the specified record type
|
||||||
|
if ((unsigned int)line.size() < (11 + (2 * byteCount)))
|
||||||
|
{
|
||||||
|
//If an error is detected in the hex file formatting, the safest approach is to
|
||||||
|
//abort the operation and force the user to supply a proper hex file.
|
||||||
|
if(hexfile.isOpen())
|
||||||
|
hexfile.close();
|
||||||
|
return ErrorInHexFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//For each data payload byte we find in the hex file line, check if it is contained within
|
||||||
|
//a progammable region inside the microcontroller. If so save it. If not, discard it.
|
||||||
|
for(i = 0; i < byteCount; i++)
|
||||||
|
{
|
||||||
|
//Use the hex file linear byte address, to compute other imformation about the
|
||||||
|
//byte/location. The GetDeviceAddressFromHexAddress() function gives us a pointer to
|
||||||
|
//the PC RAM buffer byte that will get programmed into the microcontroller, which corresponds
|
||||||
|
//to the specified .hex file extended address.
|
||||||
|
//The function also returns a boolean letting us know if the address is part of a programmable memory region on the device.
|
||||||
|
deviceAddress = device->GetDeviceAddressFromHexAddress(lineAddress + i, pData, type, includedInProgrammableRange, addressWasEndofRange, bytesPerAddressAndType, endDeviceAddressofRegion, pPCRAMBuffer);
|
||||||
|
//Check if the just parsed hex byte was included in one of the microcontroller reported programmable memory regions.
|
||||||
|
//If so, save the byte into the proper location in the PC RAM buffer, so it can be programmed later.
|
||||||
|
if((includedInProgrammableRange == true) && (pPCRAMBuffer != 0)) //Make sure pPCRAMBuffer pointer is valid before using it.
|
||||||
|
{
|
||||||
|
//Print debug output text to debug window
|
||||||
|
if(i == 0)
|
||||||
|
{
|
||||||
|
qDebug(QString("Importing .hex file line with device address: 0x" + QString::number(deviceAddress, 16)).toLatin1());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Fetch ASCII encoded payload byte from .hex file and save the byte to our temporary RAM buffer.
|
||||||
|
hexByte = line.mid(9 + (2 * i), 2); //Fetch two ASCII data payload bytes from the .hex file
|
||||||
|
wordByte = hexByte.toInt(&ok, 16); //Re-format the above two ASCII bytes into a single binary encoded byte (0x00-0xFF)
|
||||||
|
|
||||||
|
*pPCRAMBuffer = (unsigned char)wordByte; //Save the .hex file data byte into the PC RAM buffer that holds the data to be programmed
|
||||||
|
importedAtLeastOneByte = true; //Set flag so we know we imported something successfully.
|
||||||
|
|
||||||
|
//Check if we just parsed a config bit byte. If so, set flag so the user is no longer locked out
|
||||||
|
//of programming the config bits section.
|
||||||
|
if(type == CONFIG_MEMORY)
|
||||||
|
{
|
||||||
|
hasConfigBits = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if((includedInProgrammableRange == true) && (pPCRAMBuffer == 0))
|
||||||
|
{
|
||||||
|
//Previous memory allocation must have failed, or otherwise pPCRAMBuffer would not be = 0.
|
||||||
|
//Since the memory allocation failed, we should bug out and let the user know.
|
||||||
|
if(hexfile.isOpen())
|
||||||
|
hexfile.close();
|
||||||
|
return InsufficientMemory;
|
||||||
|
}
|
||||||
|
}//for(i = 0; i < byteCount; i++)
|
||||||
|
} // end else if (recordType == DATA)
|
||||||
|
}//while (!hexfile.atEnd())
|
||||||
|
|
||||||
|
//If we get to here, that means we reached the end of the hex file, or we found a END_OF_FILE record in the .hex file.
|
||||||
|
if(hexfile.isOpen())
|
||||||
|
{
|
||||||
|
hexfile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if we imported any data from the .hex file.
|
||||||
|
if(importedAtLeastOneByte == true)
|
||||||
|
{
|
||||||
|
qDebug(QString("Hex File imported successfully.").toLatin1());
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//If we get to here, we didn't import anything. The hex file must have been empty or otherwise didn't
|
||||||
|
//contain any data that overlaps a device programmable region. We should let the user know they should
|
||||||
|
//supply a better hex file designed for their device.
|
||||||
|
return NoneInRange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
78
qt5_src/Bootloader/ImportExportHex.h
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* Copyright (c) 2005-2009, Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* Microchip licenses this software to you solely for use with Microchip
|
||||||
|
* products. The software is owned by Microchip and its licensors, and
|
||||||
|
* is protected under applicable copyright laws. All rights reserved.
|
||||||
|
*
|
||||||
|
* SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY
|
||||||
|
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR
|
||||||
|
* EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY
|
||||||
|
* OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED
|
||||||
|
* TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION,
|
||||||
|
* OR OTHER SIMILAR COSTS.
|
||||||
|
*
|
||||||
|
* To the fullest extent allowed by law, Microchip and its licensors
|
||||||
|
* liability shall not exceed the amount of fees, if any, that you
|
||||||
|
* have paid directly to Microchip to use this software.
|
||||||
|
*
|
||||||
|
* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE
|
||||||
|
* OF THESE TERMS.
|
||||||
|
*/
|
||||||
|
#ifndef IMPORTEXPORTHEX_H
|
||||||
|
#define IMPORTEXPORTHEX_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include "DeviceData.h"
|
||||||
|
#include "Device.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Reads HEX files into an in-memory DeviceData object.
|
||||||
|
*/
|
||||||
|
class HexImporter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum ErrorCode { Success = 0, CouldNotOpenFile, NoneInRange, ErrorInHexFile, InsufficientMemory };
|
||||||
|
//Definitions for the record type bytes in Intel 32-bit .HEX file formatted firmware images
|
||||||
|
enum HEX32_RECORD
|
||||||
|
{
|
||||||
|
DATA = 0x00,
|
||||||
|
END_OF_FILE = 0x01,
|
||||||
|
EXTENDED_SEGMENT_ADDR = 0x02,
|
||||||
|
EXTENDED_LINEAR_ADDR = 0x04,
|
||||||
|
};
|
||||||
|
|
||||||
|
//Definitions for the program memory "word write" size for different microcontroller families
|
||||||
|
enum PROG_WORD_WRITE_SIZE
|
||||||
|
{
|
||||||
|
PIC18_PROG_WORD_WRITE_SIZE = 0x02, //Word writes perform two byte writes on these devices.
|
||||||
|
PIC24_PROG_WORD_WRITE_SIZE = 0x04, //3 useful bytes per "word write", but the empty phantom byte makes 4 bytes total
|
||||||
|
PIC32_PROG_WORD_WRITE_SIZE = 0x04,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
HexImporter(void);
|
||||||
|
~HexImporter(void);
|
||||||
|
|
||||||
|
ErrorCode ImportHexFile(QString fileName, DeviceData* data, Device* device);
|
||||||
|
|
||||||
|
bool hasEndOfFileRecord; // hex file does have an end of file record
|
||||||
|
bool hasConfigBits; // hex file has config bit settings
|
||||||
|
bool fileExceedsFlash; // hex file records exceed device memory constraints
|
||||||
|
|
||||||
|
QList<DeviceData::MemoryRange> rawimport;
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//int ParseHex(char* characters, int length);
|
||||||
|
//unsigned char computeChecksum(char* fileLine);
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IMPORTEXPORTHEX_H
|
||||||
1538
qt5_src/Bootloader/MainWindow.cpp
Normal file
130
qt5_src/Bootloader/MainWindow.h
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* Copyright (c) 2009-2010, Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* Microchip licenses this software to you solely for use with Microchip
|
||||||
|
* products. The software is owned by Microchip and its licensors, and
|
||||||
|
* is protected under applicable copyright laws. All rights reserved.
|
||||||
|
*
|
||||||
|
* SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY
|
||||||
|
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR
|
||||||
|
* EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY
|
||||||
|
* OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED
|
||||||
|
* TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION,
|
||||||
|
* OR OTHER SIMILAR COSTS.
|
||||||
|
*
|
||||||
|
* To the fullest extent allowed by law, Microchip and its licensors
|
||||||
|
* liability shall not exceed the amount of fees, if any, that you
|
||||||
|
* have paid directly to Microchip to use this software.
|
||||||
|
*
|
||||||
|
* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE
|
||||||
|
* OF THESE TERMS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QtWidgets/QMainWindow>
|
||||||
|
#include <QtWidgets/QLabel>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QFileSystemWatcher>
|
||||||
|
#include <QtCore/QProcess>
|
||||||
|
#include <QtWidgets/QMenu>
|
||||||
|
#include <QFuture>
|
||||||
|
|
||||||
|
#include "Comm.h"
|
||||||
|
#include "DeviceData.h"
|
||||||
|
#include "Device.h"
|
||||||
|
#include "ImportExportHex.h"
|
||||||
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
|
class MainWindowClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_RECENT_FILES 3
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* The main Serial Bootloader GUI window.
|
||||||
|
*/
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MainWindow(QWidget *parent = 0);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
void GetQuery(void);
|
||||||
|
void LoadFile(QString fileName);
|
||||||
|
|
||||||
|
void EraseDevice(void);
|
||||||
|
void BlankCheckDevice(void);
|
||||||
|
void WriteDevice(void);
|
||||||
|
void VerifyDevice(void);
|
||||||
|
|
||||||
|
void setBootloadBusy(bool busy);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void IoWithDeviceCompleted(QString msg, Comm::ErrorCode, double time);
|
||||||
|
void IoWithDeviceStarted(QString msg);
|
||||||
|
void AppendString(QString msg);
|
||||||
|
void SetProgressBar(int newValue);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void Connection(void);
|
||||||
|
void openRecentFile(void);
|
||||||
|
void IoWithDeviceComplete(QString msg, Comm::ErrorCode, double time);
|
||||||
|
void IoWithDeviceStart(QString msg);
|
||||||
|
void AppendStringToTextbox(QString msg);
|
||||||
|
void UpdateProgressBar(int newValue);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Comm* comm;
|
||||||
|
DeviceData* deviceData;
|
||||||
|
DeviceData* hexData;
|
||||||
|
Device* device;
|
||||||
|
|
||||||
|
QFuture<void> future;
|
||||||
|
|
||||||
|
QString fileName, watchFileName;
|
||||||
|
QFileSystemWatcher* fileWatcher;
|
||||||
|
QTimer *timer;
|
||||||
|
|
||||||
|
bool writeFlash;
|
||||||
|
bool writeEeprom;
|
||||||
|
bool writeConfig;
|
||||||
|
bool eraseDuringWrite;
|
||||||
|
bool hexOpen;
|
||||||
|
|
||||||
|
void setBootloadEnabled(bool enable);
|
||||||
|
|
||||||
|
void UpdateRecentFileList(void);
|
||||||
|
|
||||||
|
Comm::ErrorCode RemapInterruptVectors(Device* device, DeviceData* deviceData);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::MainWindowClass *ui;
|
||||||
|
QLabel deviceLabel;
|
||||||
|
|
||||||
|
int failed;
|
||||||
|
QAction *recentFiles[MAX_RECENT_FILES];
|
||||||
|
|
||||||
|
bool wasBootloaderMode;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_actionBlank_Check_triggered();
|
||||||
|
void on_actionReset_Device_triggered();
|
||||||
|
void on_action_Settings_triggered();
|
||||||
|
void on_action_Verify_Device_triggered();
|
||||||
|
void on_action_About_triggered();
|
||||||
|
void on_actionWrite_Device_triggered();
|
||||||
|
void on_actionOpen_triggered();
|
||||||
|
void on_actionErase_Device_triggered();
|
||||||
|
void on_actionExit_triggered();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
||||||
243
qt5_src/Bootloader/MainWindow.ui
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindowClass</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindowClass">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>439</width>
|
||||||
|
<height>403</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string notr="true">USB HID Bootloader</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset resource="resources.qrc">
|
||||||
|
<normaloff>:/MainWindow/img/Microchip_logo.Ico</normaloff>:/MainWindow/img/Microchip_logo.Ico</iconset>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralWidget">
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QProgressBar" name="progressBar">
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="textVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QPlainTextEdit" name="plainTextEdit">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>350</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menuBar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>439</width>
|
||||||
|
<height>19</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuFile">
|
||||||
|
<property name="title">
|
||||||
|
<string>&File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionOpen"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionExit"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuProgrammer">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Program</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionWrite_Device"/>
|
||||||
|
<addaction name="action_Verify_Device"/>
|
||||||
|
<addaction name="actionErase_Device"/>
|
||||||
|
<addaction name="actionBlank_Check"/>
|
||||||
|
<addaction name="actionReset_Device"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="action_Settings"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Help">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Help</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="action_About"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuFile"/>
|
||||||
|
<addaction name="menuProgrammer"/>
|
||||||
|
<addaction name="menu_Help"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusBar"/>
|
||||||
|
<widget class="QToolBar" name="mainToolBar">
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Display Toolbar</string>
|
||||||
|
</property>
|
||||||
|
<property name="movable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="floatable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="toolBarArea">
|
||||||
|
<enum>TopToolBarArea</enum>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="toolBarBreak">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<addaction name="actionOpen"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionWrite_Device"/>
|
||||||
|
<addaction name="action_Verify_Device"/>
|
||||||
|
<addaction name="actionErase_Device"/>
|
||||||
|
<addaction name="actionBlank_Check"/>
|
||||||
|
<addaction name="actionReset_Device"/>
|
||||||
|
</widget>
|
||||||
|
<action name="actionOpen">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources.qrc">
|
||||||
|
<normaloff>:/MainWindow/img/open.png</normaloff>:/MainWindow/img/open.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Import Firmware Image</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Import Firmware Image</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+O</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExit">
|
||||||
|
<property name="text">
|
||||||
|
<string>E&xit</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Q</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionWrite_Device">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources.qrc">
|
||||||
|
<normaloff>:/MainWindow/img/writetqfp.png</normaloff>:/MainWindow/img/writetqfp.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Erase/Program/Verify Device</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionErase_Device">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources.qrc">
|
||||||
|
<normaloff>:/MainWindow/img/erasetqfp.png</normaloff>:/MainWindow/img/erasetqfp.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Erase Device</string>
|
||||||
|
</property>
|
||||||
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_About">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources.qrc">
|
||||||
|
<normaloff>:/MainWindow/img/help.png</normaloff>:/MainWindow/img/help.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&About</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_Verify_Device">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources.qrc">
|
||||||
|
<normaloff>:/MainWindow/img/verify.png</normaloff>:/MainWindow/img/verify.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Verify Device</string>
|
||||||
|
</property>
|
||||||
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_Settings">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Settings...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionReset_Device">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources.qrc">
|
||||||
|
<normaloff>:/MainWindow/img/Reset.png</normaloff>:/MainWindow/img/Reset.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Reset Device</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionBlank_Check">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources.qrc">
|
||||||
|
<normaloff>:/MainWindow/img/BlankCheck.png</normaloff>:/MainWindow/img/BlankCheck.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Blank Check</string>
|
||||||
|
</property>
|
||||||
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
<resources>
|
||||||
|
<include location="resources.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
120
qt5_src/Bootloader/Settings.cpp
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* Copyright (c) 2009, Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* Microchip licenses this software to you solely for use with Microchip
|
||||||
|
* products. The software is owned by Microchip and its licensors, and
|
||||||
|
* is protected under applicable copyright laws. All rights reserved.
|
||||||
|
*
|
||||||
|
* SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY
|
||||||
|
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR
|
||||||
|
* EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY
|
||||||
|
* OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED
|
||||||
|
* TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION,
|
||||||
|
* OR OTHER SIMILAR COSTS.
|
||||||
|
*
|
||||||
|
* To the fullest extent allowed by law, Microchip and its licensors
|
||||||
|
* liability shall not exceed the amount of fees, if any, that you
|
||||||
|
* have paid directly to Microchip to use this software.
|
||||||
|
*
|
||||||
|
* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE
|
||||||
|
* OF THESE TERMS.
|
||||||
|
*
|
||||||
|
* Author Date Comment
|
||||||
|
*************************************************************************
|
||||||
|
* E. Schlunder 2009/04/29 Initial code.
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
#include "Settings.h"
|
||||||
|
#include "ui_Settings.h"
|
||||||
|
|
||||||
|
#include <QtWidgets/QMessageBox>
|
||||||
|
|
||||||
|
Settings::Settings(QWidget *parent) : QDialog(parent), m_ui(new Ui::Settings)
|
||||||
|
{
|
||||||
|
m_ui->setupUi(this);
|
||||||
|
|
||||||
|
alreadyWarnedConfigBitWrite = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings::~Settings()
|
||||||
|
{
|
||||||
|
delete m_ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::enableEepromBox(bool Eeprom)
|
||||||
|
{
|
||||||
|
m_ui->EepromCheckBox->setEnabled(Eeprom);
|
||||||
|
hasEeprom = Eeprom;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::setWriteFlash(bool value)
|
||||||
|
{
|
||||||
|
writeFlash = value;
|
||||||
|
m_ui->FlashProgramMemorycheckBox->setChecked(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::setWriteEeprom(bool value)
|
||||||
|
{
|
||||||
|
writeEeprom = value && hasEeprom;
|
||||||
|
m_ui->EepromCheckBox->setChecked(value && hasEeprom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::setWriteConfig(bool value)
|
||||||
|
{
|
||||||
|
writeConfig = value && hasConfig;
|
||||||
|
bool warnedFlag = alreadyWarnedConfigBitWrite;
|
||||||
|
alreadyWarnedConfigBitWrite = true;
|
||||||
|
m_ui->ConfigBitsCheckBox->setChecked(value && hasConfig);
|
||||||
|
alreadyWarnedConfigBitWrite = warnedFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::changeEvent(QEvent *e)
|
||||||
|
{
|
||||||
|
switch (e->type())
|
||||||
|
{
|
||||||
|
case QEvent::LanguageChange:
|
||||||
|
m_ui->retranslateUi(this);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::on_buttonBox_accepted()
|
||||||
|
{
|
||||||
|
writeFlash = m_ui->FlashProgramMemorycheckBox->isChecked();
|
||||||
|
writeConfig = m_ui->ConfigBitsCheckBox->isChecked();
|
||||||
|
writeEeprom = m_ui->EepromCheckBox->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::on_ConfigBitsCheckBox_toggled(bool checked)
|
||||||
|
{
|
||||||
|
if((alreadyWarnedConfigBitWrite == false) && checked)
|
||||||
|
{
|
||||||
|
QMessageBox msgBox(this);
|
||||||
|
msgBox.setWindowTitle("Warning!");
|
||||||
|
|
||||||
|
msgBox.setText("Writing Config Bits is not a safe bootloader operation.\n" \
|
||||||
|
"\n" \
|
||||||
|
"The device and bootloader may stop functioning if the new config bit settings are\nnot compatible with USB operation.\n" \
|
||||||
|
"When the bootloader becomes inoperable, restoring the device will not be possible\n" \
|
||||||
|
"without dedicated external chip programming tools.\n" \
|
||||||
|
"\n" \
|
||||||
|
"Are you sure you wish to enable the \"Write Config Bits\" option?");
|
||||||
|
|
||||||
|
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
||||||
|
msgBox.setDefaultButton(QMessageBox::Cancel);
|
||||||
|
int result = msgBox.exec();
|
||||||
|
if(result != QMessageBox::Ok)
|
||||||
|
{
|
||||||
|
m_ui->ConfigBitsCheckBox->setChecked(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
alreadyWarnedConfigBitWrite = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
77
qt5_src/Bootloader/Settings.h
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* Copyright (c) 2009, Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* Microchip licenses this software to you solely for use with Microchip
|
||||||
|
* products. The software is owned by Microchip and its licensors, and
|
||||||
|
* is protected under applicable copyright laws. All rights reserved.
|
||||||
|
*
|
||||||
|
* SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY
|
||||||
|
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR
|
||||||
|
* EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY
|
||||||
|
* OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED
|
||||||
|
* TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION,
|
||||||
|
* OR OTHER SIMILAR COSTS.
|
||||||
|
*
|
||||||
|
* To the fullest extent allowed by law, Microchip and its licensors
|
||||||
|
* liability shall not exceed the amount of fees, if any, that you
|
||||||
|
* have paid directly to Microchip to use this software.
|
||||||
|
*
|
||||||
|
* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE
|
||||||
|
* OF THESE TERMS.
|
||||||
|
*
|
||||||
|
* Author Date Comment
|
||||||
|
*************************************************************************
|
||||||
|
* E. Schlunder 2009/04/29 Initial code.
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
#ifndef SETTINGS_H
|
||||||
|
#define SETTINGS_H
|
||||||
|
|
||||||
|
#include <QtWidgets/QDialog>
|
||||||
|
//#include <hidapi.h>
|
||||||
|
#include <QtWidgets/QComboBox>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class Settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* The Settings GUI dialog box for configuring flash, EEPROM, and config bit write regions.
|
||||||
|
*/
|
||||||
|
class Settings : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY(Settings)
|
||||||
|
public:
|
||||||
|
explicit Settings(QWidget *parent = 0);
|
||||||
|
virtual ~Settings();
|
||||||
|
|
||||||
|
void enableEepromBox(bool Eeprom);
|
||||||
|
void setWriteFlash(bool value);
|
||||||
|
void setWriteEeprom(bool value);
|
||||||
|
void setWriteConfig(bool value);
|
||||||
|
|
||||||
|
bool writeFlash;
|
||||||
|
bool writeEeprom;
|
||||||
|
bool writeConfig;
|
||||||
|
|
||||||
|
bool hasEeprom;
|
||||||
|
bool hasConfig;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void changeEvent(QEvent *e);
|
||||||
|
void populateBaudRates(QComboBox* comboBox);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::Settings *m_ui;
|
||||||
|
bool alreadyWarnedConfigBitWrite;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_ConfigBitsCheckBox_toggled(bool checked);
|
||||||
|
void on_buttonBox_accepted();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SETTINGS_H
|
||||||
124
qt5_src/Bootloader/Settings.ui
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Settings</class>
|
||||||
|
<widget class="QDialog" name="Settings">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>402</width>
|
||||||
|
<height>190</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Settings</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>:/MainWindow/img/microchip.png</normaloff>:/MainWindow/img/microchip.png</iconset>
|
||||||
|
</property>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>30</x>
|
||||||
|
<y>150</y>
|
||||||
|
<width>341</width>
|
||||||
|
<height>32</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QGroupBox" name="WriteOptionsGroupBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>20</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>361</width>
|
||||||
|
<height>131</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Write Options</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QCheckBox" name="FlashProgramMemorycheckBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>17</x>
|
||||||
|
<y>30</y>
|
||||||
|
<width>201</width>
|
||||||
|
<height>19</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>FLASH Program Memory</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QCheckBox" name="ConfigBitsCheckBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>17</x>
|
||||||
|
<y>60</y>
|
||||||
|
<width>201</width>
|
||||||
|
<height>19</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Config Bits</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QCheckBox" name="EepromCheckBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>16</x>
|
||||||
|
<y>90</y>
|
||||||
|
<width>201</width>
|
||||||
|
<height>19</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>EEPROM</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>Settings</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>Settings</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
BIN
qt5_src/Bootloader/img/BlankCheck.png
Normal file
|
After Width: | Height: | Size: 252 B |
BIN
qt5_src/Bootloader/img/Microchip_logo.Ico
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
qt5_src/Bootloader/img/Reset.png
Normal file
|
After Width: | Height: | Size: 227 B |
BIN
qt5_src/Bootloader/img/abort.png
Normal file
|
After Width: | Height: | Size: 421 B |
BIN
qt5_src/Bootloader/img/clear.png
Normal file
|
After Width: | Height: | Size: 235 B |
BIN
qt5_src/Bootloader/img/erasetqfp.png
Normal file
|
After Width: | Height: | Size: 250 B |
BIN
qt5_src/Bootloader/img/help.png
Normal file
|
After Width: | Height: | Size: 622 B |
BIN
qt5_src/Bootloader/img/open.png
Normal file
|
After Width: | Height: | Size: 259 B |
BIN
qt5_src/Bootloader/img/readtqfp.png
Normal file
|
After Width: | Height: | Size: 244 B |
BIN
qt5_src/Bootloader/img/stop.png
Normal file
|
After Width: | Height: | Size: 303 B |
BIN
qt5_src/Bootloader/img/verify.png
Normal file
|
After Width: | Height: | Size: 249 B |
BIN
qt5_src/Bootloader/img/writetqfp.png
Normal file
|
After Width: | Height: | Size: 245 B |
44
qt5_src/Bootloader/main.cpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* Copyright (c) 2009-2010, Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* Microchip licenses this software to you solely for use with Microchip
|
||||||
|
* products. The software is owned by Microchip and its licensors, and
|
||||||
|
* is protected under applicable copyright laws. All rights reserved.
|
||||||
|
*
|
||||||
|
* SOFTWARE IS PROVIDED "AS IS." MICROCHIP EXPRESSLY DISCLAIMS ANY
|
||||||
|
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
|
||||||
|
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR
|
||||||
|
* EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY
|
||||||
|
* OR SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED
|
||||||
|
* TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION,
|
||||||
|
* OR OTHER SIMILAR COSTS.
|
||||||
|
*
|
||||||
|
* To the fullest extent allowed by law, Microchip and its licensors
|
||||||
|
* liability shall not exceed the amount of fees, if any, that you
|
||||||
|
* have paid directly to Microchip to use this software.
|
||||||
|
*
|
||||||
|
* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE
|
||||||
|
* OF THESE TERMS.
|
||||||
|
*
|
||||||
|
* Author Date Comment
|
||||||
|
*************************************************************************
|
||||||
|
* E. Schlunder 2009/04/14 Initial code ported from VB app.
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
#include <QtWidgets/QApplication>
|
||||||
|
#include "MainWindow.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
QCoreApplication::setOrganizationName("Microchip");
|
||||||
|
QCoreApplication::setOrganizationDomain("microchip.com");
|
||||||
|
QCoreApplication::setApplicationName("USB HID Bootloader");
|
||||||
|
|
||||||
|
MainWindow w;
|
||||||
|
w.show();
|
||||||
|
return a.exec();
|
||||||
|
}
|
||||||
14
qt5_src/Bootloader/resources.qrc
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/MainWindow">
|
||||||
|
<file>img/abort.png</file>
|
||||||
|
<file>img/open.png</file>
|
||||||
|
<file>img/writetqfp.png</file>
|
||||||
|
<file>img/erasetqfp.png</file>
|
||||||
|
<file>img/verify.png</file>
|
||||||
|
<file>img/stop.png</file>
|
||||||
|
<file>img/BlankCheck.png</file>
|
||||||
|
<file>img/Reset.png</file>
|
||||||
|
<file>img/help.png</file>
|
||||||
|
<file>img/Microchip_logo.Ico</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
1
qt5_src/Bootloader/windows.rc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
IDI_ICON1 ICON DISCARDABLE "img/icon.ico"
|
||||||
41
qt5_src/HIDAPI/HIDAPI.pro
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# -------------------------------------------------
|
||||||
|
# Project created by QtCreator 2010-10-29T15:54:07
|
||||||
|
# -------------------------------------------------
|
||||||
|
QT -= gui
|
||||||
|
TARGET = HIDAPI
|
||||||
|
TEMPLATE = lib
|
||||||
|
CONFIG += staticlib
|
||||||
|
HEADERS += hidapi.h
|
||||||
|
|
||||||
|
# -------------------------------------------------
|
||||||
|
# Add appropriate source file depending on OS
|
||||||
|
# -------------------------------------------------
|
||||||
|
macx: SOURCES += mac/hid.c
|
||||||
|
unix: !macx: SOURCES += linux/hid-libusb.c
|
||||||
|
win32: SOURCES += windows/hid.cpp
|
||||||
|
|
||||||
|
# -------------------------------------------------
|
||||||
|
# Make sure output directory for object file and
|
||||||
|
# library is in the correct subdirectory
|
||||||
|
# -------------------------------------------------
|
||||||
|
macx {
|
||||||
|
DESTDIR = mac
|
||||||
|
OBJECTS_DIR = mac
|
||||||
|
MOC_DIR = mac
|
||||||
|
UI_DIR = mac
|
||||||
|
RCC_DIR = mac
|
||||||
|
}
|
||||||
|
unix: !macx {
|
||||||
|
DESTDIR = linux
|
||||||
|
OBJECTS_DIR = linux
|
||||||
|
MOC_DIR = linux
|
||||||
|
UI_DIR = linux
|
||||||
|
RCC_DIR = linux
|
||||||
|
}
|
||||||
|
win32 {
|
||||||
|
DESTDIR = windows
|
||||||
|
OBJECTS_DIR = windows
|
||||||
|
MOC_DIR = windows
|
||||||
|
UI_DIR = windows
|
||||||
|
RCC_DIR = windows
|
||||||
|
}
|
||||||
339
qt5_src/HIDAPI/hidapi.h
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
/*******************************************************
|
||||||
|
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
|
||||||
1122
qt5_src/HIDAPI/linux/hid-libusb.c
Normal file
532
qt5_src/HIDAPI/linux/hid.c
Normal file
@@ -0,0 +1,532 @@
|
|||||||
|
/*******************************************************
|
||||||
|
HIDAPI - Multi-Platform library for
|
||||||
|
communication with HID devices.
|
||||||
|
|
||||||
|
Alan Ott
|
||||||
|
Signal 11 Software
|
||||||
|
|
||||||
|
8/22/2009
|
||||||
|
Linux Version - 6/2/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 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 .
|
||||||
|
********************************************************/
|
||||||
|
|
||||||
|
/* C */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/* Unix */
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
/* Linux */
|
||||||
|
#include <linux/hidraw.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <libudev.h>
|
||||||
|
|
||||||
|
#include "hidapi.h"
|
||||||
|
|
||||||
|
struct hid_device_ {
|
||||||
|
int device_handle;
|
||||||
|
int blocking;
|
||||||
|
int uses_numbered_reports;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static __u32 kernel_version = 0;
|
||||||
|
|
||||||
|
hid_device *new_hid_device()
|
||||||
|
{
|
||||||
|
hid_device *dev = calloc(1, sizeof(hid_device));
|
||||||
|
dev->device_handle = -1;
|
||||||
|
dev->blocking = 1;
|
||||||
|
dev->uses_numbered_reports = 0;
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_error(hid_device *device, const char *op)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get an attribute value from a udev_device and return it as a whar_t
|
||||||
|
string. The returned string must be freed with free() when done.*/
|
||||||
|
static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
wchar_t *ret = NULL;
|
||||||
|
str = udev_device_get_sysattr_value(dev, udev_name);
|
||||||
|
if (str) {
|
||||||
|
/* Convert the string from UTF-8 to wchar_t */
|
||||||
|
size_t wlen = mbstowcs(NULL, str, 0);
|
||||||
|
ret = calloc(wlen+1, sizeof(wchar_t));
|
||||||
|
mbstowcs(ret, str, wlen+1);
|
||||||
|
ret[wlen] = 0x0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* uses_numbered_reports() returns 1 if report_descriptor describes a device
|
||||||
|
which contains numbered reports. */
|
||||||
|
static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) {
|
||||||
|
int i = 0;
|
||||||
|
int size_code;
|
||||||
|
int data_len, key_size;
|
||||||
|
|
||||||
|
while (i < size) {
|
||||||
|
int key = report_descriptor[i];
|
||||||
|
|
||||||
|
/* Check for the Report ID key */
|
||||||
|
if (key == 0x85/*Report ID*/) {
|
||||||
|
/* This device has a Report ID, which means it uses
|
||||||
|
numbered reports. */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("key: %02hhx\n", key);
|
||||||
|
|
||||||
|
if ((key & 0xf0) == 0xf0) {
|
||||||
|
/* This is a Long Item. The next byte contains the
|
||||||
|
length of the data section (value) for this key.
|
||||||
|
See the HID specification, version 1.11, section
|
||||||
|
6.2.2.3, titled "Long Items." */
|
||||||
|
if (i+1 < size)
|
||||||
|
data_len = report_descriptor[i+1];
|
||||||
|
else
|
||||||
|
data_len = 0; /* malformed report */
|
||||||
|
key_size = 3;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* This is a Short Item. The bottom two bits of the
|
||||||
|
key contain the size code for the data section
|
||||||
|
(value) for this key. Refer to the HID
|
||||||
|
specification, version 1.11, section 6.2.2.2,
|
||||||
|
titled "Short Items." */
|
||||||
|
size_code = key & 0x3;
|
||||||
|
switch (size_code) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
data_len = size_code;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
data_len = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Can't ever happen since size_code is & 0x3 */
|
||||||
|
data_len = 0;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
key_size = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip over this key and it's associated data */
|
||||||
|
i += data_len + key_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Didn't find a Report ID key. Device doesn't use numbered reports. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_device_string(hid_device *dev, const char *key, wchar_t *string, size_t maxlen)
|
||||||
|
{
|
||||||
|
struct udev *udev;
|
||||||
|
struct udev_device *udev_dev, *parent;
|
||||||
|
struct stat s;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
setlocale(LC_ALL,"");
|
||||||
|
|
||||||
|
/* Create the udev object */
|
||||||
|
udev = udev_new();
|
||||||
|
if (!udev) {
|
||||||
|
printf("Can't create udev\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the dev_t (major/minor numbers) from the file handle. */
|
||||||
|
fstat(dev->device_handle, &s);
|
||||||
|
/* Open a udev device from the dev_t. 'c' means character device. */
|
||||||
|
udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev);
|
||||||
|
if (udev_dev) {
|
||||||
|
const char *str;
|
||||||
|
/* Find the parent USB Device */
|
||||||
|
parent = udev_device_get_parent_with_subsystem_devtype(
|
||||||
|
udev_dev,
|
||||||
|
"usb",
|
||||||
|
"usb_device");
|
||||||
|
if (parent) {
|
||||||
|
str = udev_device_get_sysattr_value(parent, key);
|
||||||
|
if (str) {
|
||||||
|
/* Convert the string from UTF-8 to wchar_t */
|
||||||
|
ret = mbstowcs(string, str, maxlen);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
udev_device_unref(parent);
|
||||||
|
// udev_dev doesn't need unref'd. Not sure why, but
|
||||||
|
// it'll throw "double free" errors.
|
||||||
|
udev_unref(udev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
|
||||||
|
{
|
||||||
|
struct udev *udev;
|
||||||
|
struct udev_enumerate *enumerate;
|
||||||
|
struct udev_list_entry *devices, *dev_list_entry;
|
||||||
|
struct udev_device *dev;
|
||||||
|
|
||||||
|
struct hid_device_info *root = NULL; // return object
|
||||||
|
struct hid_device_info *cur_dev = NULL;
|
||||||
|
|
||||||
|
setlocale(LC_ALL,"");
|
||||||
|
|
||||||
|
/* Create the udev object */
|
||||||
|
udev = udev_new();
|
||||||
|
if (!udev) {
|
||||||
|
printf("Can't create udev\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a list of the devices in the 'hidraw' subsystem. */
|
||||||
|
enumerate = udev_enumerate_new(udev);
|
||||||
|
udev_enumerate_add_match_subsystem(enumerate, "hidraw");
|
||||||
|
udev_enumerate_scan_devices(enumerate);
|
||||||
|
devices = udev_enumerate_get_list_entry(enumerate);
|
||||||
|
/* For each item, see if it matches the vid/pid, and if so
|
||||||
|
create a udev_device record for it */
|
||||||
|
udev_list_entry_foreach(dev_list_entry, devices) {
|
||||||
|
const char *sysfs_path;
|
||||||
|
const char *dev_path;
|
||||||
|
const char *str;
|
||||||
|
unsigned short dev_vid;
|
||||||
|
unsigned short dev_pid;
|
||||||
|
|
||||||
|
/* Get the filename of the /sys entry for the device
|
||||||
|
and create a udev_device object (dev) representing it */
|
||||||
|
sysfs_path = udev_list_entry_get_name(dev_list_entry);
|
||||||
|
dev = udev_device_new_from_syspath(udev, sysfs_path);
|
||||||
|
dev_path = udev_device_get_devnode(dev);
|
||||||
|
|
||||||
|
/* The device pointed to by dev contains information about
|
||||||
|
the hidraw device. In order to get information about the
|
||||||
|
USB device, get the parent device with the
|
||||||
|
subsystem/devtype pair of "usb"/"usb_device". This will
|
||||||
|
be several levels up the tree, but the function will find
|
||||||
|
it.*/
|
||||||
|
dev = udev_device_get_parent_with_subsystem_devtype(
|
||||||
|
dev,
|
||||||
|
"usb",
|
||||||
|
"usb_device");
|
||||||
|
if (!dev) {
|
||||||
|
/* Unable to find parent usb device. */
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the VID/PID of the device */
|
||||||
|
str = udev_device_get_sysattr_value(dev,"idVendor");
|
||||||
|
dev_vid = (str)? strtol(str, NULL, 16): 0x0;
|
||||||
|
str = udev_device_get_sysattr_value(dev, "idProduct");
|
||||||
|
dev_pid = (str)? strtol(str, NULL, 16): 0x0;
|
||||||
|
|
||||||
|
/* Check the VID/PID against the arguments */
|
||||||
|
if ((vendor_id == 0x0 && product_id == 0x0) ||
|
||||||
|
(vendor_id == dev_vid && product_id == dev_pid)) {
|
||||||
|
struct hid_device_info *tmp;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
/* VID/PID match. Create the record. */
|
||||||
|
tmp = malloc(sizeof(struct hid_device_info));
|
||||||
|
if (cur_dev) {
|
||||||
|
cur_dev->next = tmp;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
root = tmp;
|
||||||
|
}
|
||||||
|
cur_dev = tmp;
|
||||||
|
|
||||||
|
/* Fill out the record */
|
||||||
|
cur_dev->next = NULL;
|
||||||
|
str = dev_path;
|
||||||
|
if (str) {
|
||||||
|
len = strlen(str);
|
||||||
|
cur_dev->path = calloc(len+1, sizeof(char));
|
||||||
|
strncpy(cur_dev->path, str, len+1);
|
||||||
|
cur_dev->path[len] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cur_dev->path = NULL;
|
||||||
|
|
||||||
|
/* Serial Number */
|
||||||
|
cur_dev->serial_number
|
||||||
|
= copy_udev_string(dev, "serial");
|
||||||
|
|
||||||
|
/* Manufacturer and Product strings */
|
||||||
|
cur_dev->manufacturer_string
|
||||||
|
= copy_udev_string(dev, "manufacturer");
|
||||||
|
cur_dev->product_string
|
||||||
|
= copy_udev_string(dev, "product");
|
||||||
|
|
||||||
|
/* VID/PID */
|
||||||
|
cur_dev->vendor_id = dev_vid;
|
||||||
|
cur_dev->product_id = dev_pid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
next:
|
||||||
|
udev_device_unref(dev);
|
||||||
|
}
|
||||||
|
/* Free the enumerator and udev objects. */
|
||||||
|
udev_enumerate_unref(enumerate);
|
||||||
|
udev_unref(udev);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
|
||||||
|
{
|
||||||
|
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_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
|
||||||
|
{
|
||||||
|
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_device * HID_API_EXPORT hid_open_path(const char *path)
|
||||||
|
{
|
||||||
|
hid_device *dev = NULL;
|
||||||
|
|
||||||
|
dev = new_hid_device();
|
||||||
|
|
||||||
|
if (kernel_version == 0) {
|
||||||
|
struct utsname name;
|
||||||
|
int major, minor, release;
|
||||||
|
int ret;
|
||||||
|
uname(&name);
|
||||||
|
ret = sscanf(name.release, "%d.%d.%d", &major, &minor, &release);
|
||||||
|
if (ret == 3) {
|
||||||
|
kernel_version = major << 16 | minor << 8 | release;
|
||||||
|
//printf("Kernel Version: %d\n", kernel_version);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Couldn't sscanf() version string %s\n", name.release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OPEN HERE //
|
||||||
|
dev->device_handle = open(path, O_RDWR);
|
||||||
|
|
||||||
|
// If we have a good handle, return it.
|
||||||
|
if (dev->device_handle > 0) {
|
||||||
|
|
||||||
|
/* Get the report descriptor */
|
||||||
|
int res, desc_size = 0;
|
||||||
|
struct hidraw_report_descriptor rpt_desc;
|
||||||
|
|
||||||
|
memset(&rpt_desc, 0x0, sizeof(rpt_desc));
|
||||||
|
|
||||||
|
/* Get Report Descriptor Size */
|
||||||
|
res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size);
|
||||||
|
if (res < 0)
|
||||||
|
perror("HIDIOCGRDESCSIZE");
|
||||||
|
|
||||||
|
|
||||||
|
/* Get Report Descriptor */
|
||||||
|
rpt_desc.size = desc_size;
|
||||||
|
res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc);
|
||||||
|
if (res < 0) {
|
||||||
|
perror("HIDIOCGRDESC");
|
||||||
|
} else {
|
||||||
|
/* Determine if this device uses numbered reports. */
|
||||||
|
dev->uses_numbered_reports =
|
||||||
|
uses_numbered_reports(rpt_desc.value,
|
||||||
|
rpt_desc.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Unable to open any devices.
|
||||||
|
free(dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
|
||||||
|
{
|
||||||
|
int bytes_written;
|
||||||
|
|
||||||
|
bytes_written = write(dev->device_handle, data, length);
|
||||||
|
|
||||||
|
return bytes_written;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
|
||||||
|
{
|
||||||
|
int bytes_read;
|
||||||
|
|
||||||
|
bytes_read = read(dev->device_handle, data, length);
|
||||||
|
if (bytes_read < 0 && errno == EAGAIN)
|
||||||
|
bytes_read = 0;
|
||||||
|
|
||||||
|
if (bytes_read >= 0 &&
|
||||||
|
kernel_version < KERNEL_VERSION(2,6,34) &&
|
||||||
|
dev->uses_numbered_reports) {
|
||||||
|
/* Work around a kernel bug. Chop off the first byte. */
|
||||||
|
memmove(data, data+1, bytes_read);
|
||||||
|
bytes_read--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
|
||||||
|
{
|
||||||
|
int flags, res;
|
||||||
|
|
||||||
|
flags = fcntl(dev->device_handle, F_GETFL, 0);
|
||||||
|
if (flags >= 0) {
|
||||||
|
if (nonblock)
|
||||||
|
res = fcntl(dev->device_handle, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
else
|
||||||
|
res = fcntl(dev->device_handle, F_SETFL, flags & ~O_NONBLOCK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dev->blocking = !nonblock;
|
||||||
|
return 0; /* Success */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data);
|
||||||
|
if (res < 0)
|
||||||
|
perror("ioctl (SFEATURE)");
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);
|
||||||
|
if (res < 0)
|
||||||
|
perror("ioctl (GFEATURE)");
|
||||||
|
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HID_API_EXPORT hid_close(hid_device *dev)
|
||||||
|
{
|
||||||
|
if (!dev)
|
||||||
|
return;
|
||||||
|
close(dev->device_handle);
|
||||||
|
free(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
|
||||||
|
{
|
||||||
|
return get_device_string(dev, "manufacturer", string, maxlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
|
||||||
|
{
|
||||||
|
return get_device_string(dev, "product", string, maxlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
|
||||||
|
{
|
||||||
|
return get_device_string(dev, "serial", string, maxlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
1094
qt5_src/HIDAPI/mac/hid.c
Normal file
792
qt5_src/HIDAPI/windows/hid.cpp
Normal file
@@ -0,0 +1,792 @@
|
|||||||
|
/*******************************************************
|
||||||
|
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 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>
|
||||||
|
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
#include <ntdef.h>
|
||||||
|
#include <winbase.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
#include <ntdef.h>
|
||||||
|
#define _wcsdup wcsdup
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#define HIDAPI_USE_DDK
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#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)
|
||||||
|
|
||||||
|
}
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "../hidapi.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// Thanks Microsoft, but I know how to use strncpy().
|
||||||
|
#pragma warning(disable:4996)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
#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 char* HIDP_PREPARSED_DATA;
|
||||||
|
#define HIDP_STATUS_SUCCESS 0x0
|
||||||
|
|
||||||
|
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, HIDP_PREPARSED_DATA **preparsed_data);
|
||||||
|
typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(HIDP_PREPARSED_DATA *preparsed_data);
|
||||||
|
typedef BOOLEAN (__stdcall *HidP_GetCaps_)(HIDP_PREPARSED_DATA *preparsed_data, HIDP_CAPS *caps);
|
||||||
|
|
||||||
|
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 BOOLEAN initialized = FALSE;
|
||||||
|
#endif // HIDAPI_USE_DDK
|
||||||
|
|
||||||
|
struct hid_device_ {
|
||||||
|
HANDLE device_handle;
|
||||||
|
BOOL blocking;
|
||||||
|
size_t input_report_length;
|
||||||
|
void *last_error_str;
|
||||||
|
DWORD last_error_num;
|
||||||
|
BOOL ioPending;
|
||||||
|
};
|
||||||
|
|
||||||
|
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->input_report_length = 0;
|
||||||
|
dev->last_error_str = NULL;
|
||||||
|
dev->last_error_num = 0;
|
||||||
|
dev->ioPending = false;
|
||||||
|
|
||||||
|
return 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),
|
||||||
|
(LPWSTR)&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 void lookup_functions()
|
||||||
|
{
|
||||||
|
HMODULE lib = LoadLibraryA("hid.dll");
|
||||||
|
if (lib) {
|
||||||
|
#define RESOLVE(x) x = (x##_)GetProcAddress(lib, #x);
|
||||||
|
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);
|
||||||
|
//FreeLibrary(lib);
|
||||||
|
#undef RESOLVE
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
#ifndef HIDAPI_USE_DDK
|
||||||
|
if (!initialized)
|
||||||
|
lookup_functions();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Initialize the Windows objects.
|
||||||
|
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.
|
||||||
|
int device_index = 0;
|
||||||
|
for (;;) {
|
||||||
|
HANDLE write_handle = INVALID_HANDLE_VALUE;
|
||||||
|
DWORD required_size = 0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
|
||||||
|
|
||||||
|
// Open a handle to the device
|
||||||
|
write_handle = CreateFileA(device_interface_detail_data->DevicePath,
|
||||||
|
GENERIC_WRITE |GENERIC_READ,
|
||||||
|
FILE_SHARE_READ|FILE_SHARE_WRITE, /*share mode*/
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
HIDD_ATTRIBUTES attrib;
|
||||||
|
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 && product_id == 0x0) ||
|
||||||
|
(attrib.VendorID == vendor_id && attrib.ProductID == product_id)) {
|
||||||
|
|
||||||
|
#define WSTR_LEN 512
|
||||||
|
const char *str;
|
||||||
|
struct hid_device_info *tmp;
|
||||||
|
wchar_t wstr[WSTR_LEN]; // TODO: Determine Size
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
/* VID/PID match. Create the record. */
|
||||||
|
tmp = (hid_device_info*) calloc(1, sizeof(struct hid_device_info));
|
||||||
|
if (cur_dev) {
|
||||||
|
cur_dev->next = tmp;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
root = tmp;
|
||||||
|
}
|
||||||
|
cur_dev = tmp;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
HIDP_PREPARSED_DATA *pp_data = NULL;
|
||||||
|
BOOLEAN res;
|
||||||
|
NTSTATUS nt_res;
|
||||||
|
|
||||||
|
#ifndef HIDAPI_USE_DDK
|
||||||
|
if (!initialized)
|
||||||
|
lookup_functions();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dev = new_hid_device();
|
||||||
|
|
||||||
|
// Open a handle to the device
|
||||||
|
dev->device_handle = CreateFileA(path,
|
||||||
|
GENERIC_WRITE |GENERIC_READ,
|
||||||
|
FILE_SHARE_READ|FILE_SHARE_WRITE, /*share mode*/
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
// Check validity of write_handle.
|
||||||
|
if (dev->device_handle == INVALID_HANDLE_VALUE) {
|
||||||
|
// Unable to open the device.
|
||||||
|
register_error(dev, "CreateFile");
|
||||||
|
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->input_report_length = caps.InputReportByteLength;
|
||||||
|
HidD_FreePreparsedData(pp_data);
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
|
||||||
|
err_pp_data:
|
||||||
|
HidD_FreePreparsedData(pp_data);
|
||||||
|
err:
|
||||||
|
CloseHandle(dev->device_handle);
|
||||||
|
free(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;
|
||||||
|
|
||||||
|
static OVERLAPPED ol;
|
||||||
|
|
||||||
|
Check_For_Result:
|
||||||
|
if(!dev->blocking && dev->ioPending)
|
||||||
|
{
|
||||||
|
res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, FALSE/*don't wait*/);
|
||||||
|
if(!res)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dev->ioPending = false;
|
||||||
|
return bytes_written;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ol, 0, sizeof(ol));
|
||||||
|
|
||||||
|
res = WriteFile(dev->device_handle, data, length, &bytes_written, &ol);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
if (GetLastError() != ERROR_IO_PENDING) {
|
||||||
|
// WriteFile() failed. Return error.
|
||||||
|
register_error(dev, "WriteFile");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!dev->blocking)
|
||||||
|
{
|
||||||
|
dev->ioPending = true;
|
||||||
|
goto Check_For_Result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 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");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_written;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
|
||||||
|
{
|
||||||
|
DWORD bytes_read;
|
||||||
|
BOOL res;
|
||||||
|
|
||||||
|
static OVERLAPPED ol;
|
||||||
|
|
||||||
|
Check_For_Result:
|
||||||
|
if(!dev->blocking && dev->ioPending)
|
||||||
|
{
|
||||||
|
res = GetOverlappedResult(dev->device_handle, &ol, &bytes_read, FALSE/*don't wait*/);
|
||||||
|
if(!res)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dev->ioPending = false;
|
||||||
|
if (bytes_read > 0 && data[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--;
|
||||||
|
memmove(data, data+1, bytes_read);
|
||||||
|
}
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ol, 0, sizeof(ol));
|
||||||
|
|
||||||
|
// Limit the data to be returned. This ensures we get
|
||||||
|
// only one report returned per call to hid_read().
|
||||||
|
length = (length < dev->input_report_length)? length: dev->input_report_length;
|
||||||
|
|
||||||
|
res = ReadFile(dev->device_handle, data, length, &bytes_read, &ol);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
if (GetLastError() != ERROR_IO_PENDING) {
|
||||||
|
// ReadFile() failed. Return error.
|
||||||
|
register_error(dev, "ReadFile");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!dev->blocking)
|
||||||
|
{
|
||||||
|
dev->ioPending = true;
|
||||||
|
goto Check_For_Result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Wait here until the write is done. This makes
|
||||||
|
// hid_write() synchronous.
|
||||||
|
res = GetOverlappedResult(dev->device_handle, &ol, &bytes_read, TRUE/*wait*/);
|
||||||
|
if (!res) {
|
||||||
|
// The Read operation failed.
|
||||||
|
register_error(dev, "ReadFile");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HID_API_EXPORT HID_API_CALL hid_cancelIo(hid_device *dev)
|
||||||
|
{
|
||||||
|
CancelIo(dev->device_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return bytes_returned;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
|
||||||
|
{
|
||||||
|
if (!dev)
|
||||||
|
return;
|
||||||
|
CloseHandle(dev->device_handle);
|
||||||
|
LocalFree(dev->last_error_str);
|
||||||
|
free(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, 2 * maxlen);
|
||||||
|
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, 2 * maxlen);
|
||||||
|
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, 2 * maxlen);
|
||||||
|
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, 2 * maxlen);
|
||||||
|
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
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
6
qt5_src/HIDBootloader.pro
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
TEMPLATE = subdirs
|
||||||
|
CONFIG += ordered
|
||||||
|
|
||||||
|
SUBDIRS = \
|
||||||
|
HIDAPI \
|
||||||
|
Bootloader
|
||||||
6
qt5_src/README.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
The application in this folder was build with QT, an open source cross-platform enviornment.
|
||||||
|
The license information for QT and its components can be found at http://qt-project.org/
|
||||||
|
|
||||||
|
|
||||||
|
This project was built and tested with the Qt 5.0.2 for Windows 32-bit (using the MinGW 4.7 compiler).
|
||||||
|
The project has not been tested with other versions of Qt or with the MSVC compiler.
|
||||||
3
qt5_src/version.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
#define APPLICATION "USB Bootloader"
|
||||||
|
#define VERSION "2.15"
|
||||||