initial commit with unmodified qt5-based bootloader flash utility source from the MLA
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"
|
||||