commit 1c236365d6f95c778329f1f65db1b040f5340f5b Author: Boris Honman Date: Sat Aug 10 15:36:38 2019 -0400 added hacked bootloader demo project that came with the MLA diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bea0c4c --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +**/*.X/*.d +**/*.X/*.pre +**/*.X/*.p1 +**/*.X/*.lst +**/*.X/*.sym +**/*.X/*.obj +**/*.X/*.o +**/*.X/*.sdb +**/*.X/*.obj.dmp +**/*.X/html/ +**/*.X/nbproject/private/ +**/*.X/nbproject/Package-*.bash +**/*.X/build/ +**/*.X/nbbuild/ +**/*.X/dist/ +**/*.X/nbdist/ +**/*.X/nbactions.xml +**/*.X/nb-configuration.xml +**/*.X/funclist +**/*.X/nbproject/Makefile-* +**/*.X/disassembly/ +**/*.X/*.map \ No newline at end of file diff --git a/bootloader_hacked_from_mla/clubdance_v2_bootloader.X/Makefile b/bootloader_hacked_from_mla/clubdance_v2_bootloader.X/Makefile new file mode 100644 index 0000000..05a3fb1 --- /dev/null +++ b/bootloader_hacked_from_mla/clubdance_v2_bootloader.X/Makefile @@ -0,0 +1,108 @@ +# +# There exist several targets which are by default empty and which can be +# used for execution of your targets. These targets are usually executed +# before and after some main targets. They are: +# +# .build-pre: called before 'build' target +# .build-post: called after 'build' target +# .clean-pre: called before 'clean' target +# .clean-post: called after 'clean' target +# .clobber-pre: called before 'clobber' target +# .clobber-post: called after 'clobber' target +# .all-pre: called before 'all' target +# .all-post: called after 'all' target +# .help-pre: called before 'help' target +# .help-post: called after 'help' target +# +# Targets beginning with '.' are not intended to be called on their own. +# +# Main targets can be executed directly, and they are: +# +# build build a specific configuration +# clean remove built files from a configuration +# clobber remove all built files +# all build all configurations +# help print help mesage +# +# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and +# .help-impl are implemented in nbproject/makefile-impl.mk. +# +# Available make variables: +# +# CND_BASEDIR base directory for relative paths +# CND_DISTDIR default top distribution directory (build artifacts) +# CND_BUILDDIR default top build directory (object files, ...) +# CONF name of current configuration +# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration) +# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration) +# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration) +# CND_PACKAGE_DIR_${CONF} directory of package (current configuration) +# CND_PACKAGE_NAME_${CONF} name of package (current configuration) +# CND_PACKAGE_PATH_${CONF} path to package (current configuration) +# +# NOCDDL + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin +RANLIB=ranlib + + +# build +build: .build-post + +.build-pre: +# Add your pre 'build' code here... + +.build-post: .build-impl +# Add your post 'build' code here... + + +# clean +clean: .clean-post + +.clean-pre: +# Add your pre 'clean' code here... + +.clean-post: .clean-impl +# Add your post 'clean' code here... + + +# clobber +clobber: .clobber-post + +.clobber-pre: +# Add your pre 'clobber' code here... + +.clobber-post: .clobber-impl +# Add your post 'clobber' code here... + + +# all +all: .all-post + +.all-pre: +# Add your pre 'all' code here... + +.all-post: .all-impl +# Add your post 'all' code here... + + +# help +help: .help-post + +.help-pre: +# Add your pre 'help' code here... + +.help-post: .help-impl +# Add your post 'help' code here... + + + +# include project implementation makefile +include nbproject/Makefile-impl.mk + +# include project make variables +include nbproject/Makefile-variables.mk diff --git a/bootloader_hacked_from_mla/clubdance_v2_bootloader.X/nbproject/configurations.xml b/bootloader_hacked_from_mla/clubdance_v2_bootloader.X/nbproject/configurations.xml new file mode 100644 index 0000000..0e65511 --- /dev/null +++ b/bootloader_hacked_from_mla/clubdance_v2_bootloader.X/nbproject/configurations.xml @@ -0,0 +1,264 @@ + + + + + ../src/BootPIC18NonJ.h + ../src/HardwareProfile.h + ../src/typedefs.h + ../src/usb.h + ../src/usb_config.h + ../src/usb_device.h + ../src/usb_device_hid.h + + + + + + + + + ../src/BootPIC18NonJ.c + ../src/VectorRemap.asm + ../src/main.c + ../src/usb_descriptors.c + ../src/usb_device.c + ../src/usb_device_hid.c + ../../src/system.c + + + Makefile + + + + ../ + ../../src + + Makefile + + + + localhost + PIC18F2550 + + + PICkit3PlatformTool + XC8 + 2.05 + 3 + + + + + + + + + + + + + false + true + + + + + + + false + + false + + false + false + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bootloader_hacked_from_mla/clubdance_v2_bootloader.X/nbproject/project.xml b/bootloader_hacked_from_mla/clubdance_v2_bootloader.X/nbproject/project.xml new file mode 100644 index 0000000..3f4f859 --- /dev/null +++ b/bootloader_hacked_from_mla/clubdance_v2_bootloader.X/nbproject/project.xml @@ -0,0 +1,30 @@ + + + com.microchip.mplab.nbide.embedded.makeproject + + + bootloader_hacked_from_mla + 10ecf416-ca94-402f-a3ea-0a0beb0c5a13 + 0 + c + + h + ISO-8859-1 + + + + ../ + ../../src + + + + PIC18F2550_XC8 + 2 + + + + false + + + + diff --git a/bootloader_hacked_from_mla/src/BootPIC18NonJ.c b/bootloader_hacked_from_mla/src/BootPIC18NonJ.c new file mode 100644 index 0000000..53350ad --- /dev/null +++ b/bootloader_hacked_from_mla/src/BootPIC18NonJ.c @@ -0,0 +1,926 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +/** I N C L U D E S **********************************************************/ +#include "usb.h" +#include "BootPIC18NonJ.h" + + + +/** C O N S T A N T S **********************************************************/ +//The bootloader version, which the bootloader PC application can do extended query to get. +//Value provided is expected to be in the format of BOOTLOADER_VERSION_MAJOR.BOOTLOADER_VERSION_MINOR +//Ex: 1.01 would be BOOTLOADER_VERSION_MAJOR == 1, and BOOTLOADER_VERSION_MINOR == 1 +#define BOOTLOADER_VERSION_MAJOR 1 //Legal value 0-255 +#define BOOTLOADER_VERSION_MINOR 2 //Legal value 0-99. (1 = X.01) + + +//Section defining the address range to erase for the erase device command, along with the valid programming range to be reported by the QUERY_DEVICE command. +#define PROGRAM_MEM_START_ADDRESS REMAPPED_APPLICATION_RESET_VECTOR //Beginning of application program memory (not occupied by bootloader). **THIS VALUE MUST BE ALIGNED WITH 64 BYTE BLOCK BOUNDRY** Also, in order to work correctly, make sure the StartPageToErase is set to erase this section. + +#if defined(__18F4550)||defined(__18F2550)||defined(__18F45K50)||defined(__18LF45K50)||defined(__18F25K50)||defined(__18LF25K50) + #define MAX_PAGE_TO_ERASE 511 //Last 64 byte page of flash on the PIC18F4550 + #define PROGRAM_MEM_STOP_ADDRESS 0x008000 //**MUST BE WORD ALIGNED (EVEN) ADDRESS. This address does not get updated, but the one just below it does: IE: If PROGRAM_MEM_STOP_ADDRESS = 0x200, 0x1FF is the last programmed address (0x200 not programmed)** + #define CONFIG_WORDS_START_ADDRESS 0x300000 //0x300000 is start of CONFIG space for these devices + #define CONFIG_WORDS_SECTION_LENGTH 14 //14 bytes worth of Configuration words on these devices + #define USER_ID_ADDRESS 0x200000 //User ID is 8 bytes starting at 0x200000 + #define USER_ID_SIZE 8 + #define DEVICE_WITH_EEPROM //Comment this out, if you never want the bootloader to reprogram the EEPROM space + #define EEPROM_SIZE 0x100 //256 bytes of EEPROM on this device + #define EEPROM_EFFECTIVE_ADDRESS 0xF00000 //Location in the .hex file where the EEPROM contents are stored + #define WRITE_BLOCK_SIZE 0x20 //32 byte programming block size on the PIC18F4550/PIC18F4553 family devices + #define ERASE_PAGE_SIZE 64 + +#elif defined(__18F4553)||defined(__18F2553) + #define MAX_PAGE_TO_ERASE 511 //Last 64 byte page of flash on the PIC18F4550 + #define PROGRAM_MEM_STOP_ADDRESS 0x008000 //**MUST BE WORD ALIGNED (EVEN) ADDRESS. This address does not get updated, but the one just below it does: IE: If PROGRAM_MEM_STOP_ADDRESS = 0x200, 0x1FF is the last programmed address (0x200 not programmed)** + #define CONFIG_WORDS_START_ADDRESS 0x300000 //0x300000 is start of CONFIG space for these devices + #define CONFIG_WORDS_SECTION_LENGTH 14 //14 bytes worth of Configuration words on these devices + #define USER_ID_ADDRESS 0x200000 //User ID is 8 bytes starting at 0x200000 + #define USER_ID_SIZE 8 + #define DEVICE_WITH_EEPROM //Comment this out, if you never want the bootloader to reprogram the EEPROM space + #define EEPROM_SIZE 0x100 //256 bytes of EEPROM on this device + #define EEPROM_EFFECTIVE_ADDRESS 0xF00000 //Location in the .hex file where the EEPROM contents are stored + #define WRITE_BLOCK_SIZE 0x20 //32 byte programming block size on the PIC18F4550/PIC18F4553 family devices + #define ERASE_PAGE_SIZE 64 + +#elif defined(__18F4455)||defined(__18F2455) + #define MAX_PAGE_TO_ERASE 383 //Last 64 byte page of flash on the PIC18F4455 + #define PROGRAM_MEM_STOP_ADDRESS 0x006000 //**MUST BE WORD ALIGNED (EVEN) ADDRESS. This address does not get updated, but the one just below it does: IE: If PROGRAM_MEM_STOP_ADDRESS = 0x200, 0x1FF is the last programmed address (0x200 not programmed)** + #define CONFIG_WORDS_START_ADDRESS 0x300000 /0x300000 is start of CONFIG space for these devices + #define CONFIG_WORDS_SECTION_LENGTH 14 //14 bytes worth of Configuration words on these devices + #define USER_ID_ADDRESS 0x200000 //User ID is 8 bytes starting at 0x200000 + #define USER_ID_SIZE 8 + #define DEVICE_WITH_EEPROM //Comment this out, if you never want the bootloader to reprogram the EEPROM space + #define EEPROM_SIZE 0x100 //256 bytes of EEPROM on this device + #define EEPROM_EFFECTIVE_ADDRESS 0xF00000 //Location in the .hex file where the EEPROM contents are stored + #define WRITE_BLOCK_SIZE 0x20 //32 byte programming block size on the PIC18F4550/PIC18F4553 family devices + #define ERASE_PAGE_SIZE 64 + +#elif defined(__18F4458)||defined(__18F2458) + #define MAX_PAGE_TO_ERASE 383 //Last 64 byte page of flash on the PIC18F4455 + #define PROGRAM_MEM_STOP_ADDRESS 0x006000 //**MUST BE WORD ALIGNED (EVEN) ADDRESS. This address does not get updated, but the one just below it does: IE: If PROGRAM_MEM_STOP_ADDRESS = 0x200, 0x1FF is the last programmed address (0x200 not programmed)** + #define CONFIG_WORDS_START_ADDRESS 0x300000 /0x300000 is start of CONFIG space for these devices + #define CONFIG_WORDS_SECTION_LENGTH 14 //14 bytes worth of Configuration words on these devices + #define USER_ID_ADDRESS 0x200000 //User ID is 8 bytes starting at 0x200000 + #define UserIDSize 8 + #define DEVICE_WITH_EEPROM //Comment this out, if you never want the bootloader to reprogram the EEPROM space + #define EEPROM_SIZE 0x100 //256 bytes of EEPROM on this device + #define EEPROM_EFFECTIVE_ADDRESS 0xF00000 //Location in the .hex file where the EEPROM contents are stored + #define WRITE_BLOCK_SIZE 0x20 //32 byte programming block size on the PIC18F4550/PIC18F4553 family devices + #define ERASE_PAGE_SIZE 64 + +#elif defined(__18F4450)||defined(__18F2450) + #define MAX_PAGE_TO_ERASE 255 //Last 64 byte page of flash on the PIC18F4450 + #define PROGRAM_MEM_STOP_ADDRESS 0x004000 //**MUST BE WORD ALIGNED (EVEN) ADDRESS. This address does not get updated, but the one just below it does: IE: If PROGRAM_MEM_STOP_ADDRESS = 0x200, 0x1FF is the last programmed address (0x200 not programmed)** + #define CONFIG_WORDS_START_ADDRESS 0x300000 /0x300000 is start of CONFIG space for these devices + #define CONFIG_WORDS_SECTION_LENGTH 14 //14 bytes worth of Configuration words on these devices + #define USER_ID_ADDRESS 0x200000 //User ID is 8 bytes starting at 0x200000 + #define USER_ID_SIZE 8 + #define WRITE_BLOCK_SIZE 0x10 //16 byte programming block size on the PIC18F4450/2450 family devices + #define ERASE_PAGE_SIZE 64 + +#elif defined(__18F24K50)||defined(__18LF24K50) + #define MAX_PAGE_TO_ERASE 255 //Last 64 byte page of flash on the PIC18F4450 + #define PROGRAM_MEM_STOP_ADDRESS 0x004000 //**MUST BE WORD ALIGNED (EVEN) ADDRESS. This address does not get updated, but the one just below it does: IE: If PROGRAM_MEM_STOP_ADDRESS = 0x200, 0x1FF is the last programmed address (0x200 not programmed)** + #define CONFIG_WORDS_START_ADDRESS 0x300000 /0x300000 is start of CONFIG space for these devices + #define CONFIG_WORDS_SECTION_LENGTH 14 //14 bytes worth of Configuration words on these devices + #define USER_ID_ADDRESS 0x200000 //User ID is 8 bytes starting at 0x200000 + #define USER_ID_SIZE 8 + #define DEVICE_WITH_EEPROM //Comment this out, if you never want the bootloader to reprogram the EEPROM space + #define EEPROM_SIZE 0x100 //256 bytes of EEPROM on this device + #define EEPROM_EFFECTIVE_ADDRESS 0xF00000 //Location in the .hex file where the EEPROM contents are stored + #define WRITE_BLOCK_SIZE 0x10 //16 byte programming block size on the PIC18F4450/2450 family devices + #define ERASE_PAGE_SIZE 64 + +#elif defined(__18F14K50) || defined(__18LF14K50) + #define MAX_PAGE_TO_ERASE 255 //Last 64 byte page of flash on the PIC18F4455 + #define PROGRAM_MEM_STOP_ADDRESS 0x004000 //**MUST BE WORD ALIGNED (EVEN) ADDRESS. This address does not get updated, but the one just below it does: IE: If PROGRAM_MEM_STOP_ADDRESS = 0x200, 0x1FF is the last programmed address (0x200 not programmed)** + #define CONFIG_WORDS_START_ADDRESS 0x300000 //0x300000 is start of CONFIG space for these devices + #define CONFIG_WORDS_SECTION_LENGTH 14 //14 bytes worth of Configuration words on these devices + #define USER_ID_ADDRESS 0x200000 //User ID is 8 bytes starting at 0x200000 + #define USER_ID_SIZE 8 + #define DEVICE_WITH_EEPROM //Comment this out, if you never want the bootloader to reprogram the EEPROM space + #define EEPROM_SIZE 0x100 //256 bytes of EEPROM on this device + #define EEPROM_EFFECTIVE_ADDRESS 0xF00000 //Location in the .hex file where the EEPROM contents are stored + #define WRITE_BLOCK_SIZE 0x10 //16 byte programming block size on the PIC18F14K50 family devices + #define ERASE_PAGE_SIZE 64 + +#elif defined(__18F13K50) || defined(__18LF13K50) + #define MAX_PAGE_TO_ERASE 127 //Last 64 byte page of flash on the PIC18F4455 + #define PROGRAM_MEM_STOP_ADDRESS 0x002000 //**MUST BE WORD ALIGNED (EVEN) ADDRESS. This address does not get updated, but the one just below it does: IE: If PROGRAM_MEM_STOP_ADDRESS = 0x200, 0x1FF is the last programmed address (0x200 not programmed)** + #define CONFIG_WORDS_START_ADDRESS 0x300000 //0x300000 is start of CONFIG space for these devices + #define CONFIG_WORDS_SECTION_LENGTH 14 //14 bytes worth of Configuration words on these devices + #define USER_ID_ADDRESS 0x200000 //User ID is 8 bytes starting at 0x200000 + #define USER_ID_SIZE 8 + #define DEVICE_WITH_EEPROM //Comment this out, if you never want the bootloader to reprogram the EEPROM space + #define EEPROM_SIZE 0x100 //256 bytes of EEPROM on this device + #define EEPROM_EFFECTIVE_ADDRESS 0xF00000 //Location in the .hex file where the EEPROM contents are stored + #define WRITE_BLOCK_SIZE 0x08 //8 byte programming block size on the PIC18F14K50 family devices + #define ERASE_PAGE_SIZE 64 + +#endif + + +//Derived microcontroller address/page constants +#define START_PAGE_TO_ERASE (PROGRAM_MEM_START_ADDRESS/ERASE_PAGE_SIZE) //The first flash page number to erase, which is the start of the application program space +#define ERASE_PAGE_ADDRESS_MASK (uint24_t)(0x1000000 - ERASE_PAGE_SIZE) //AND mask to move an address pointer to the start of an erase page + + + +//Bootloader Command From Host - Switch() State Variable Choices +#define QUERY_DEVICE 0x02 //Command that the host uses to learn about the device (what regions can be programmed, and what type of memory is the region) +#define UNLOCK_CONFIG 0x03 //Note, this command is used for both locking and unlocking the config bits (see the "//Unlock Configs Command Definitions" below) +#define ERASE_DEVICE 0x04 //Host sends this command to start an erase operation. Firmware controls which pages should be erased. +#define PROGRAM_DEVICE 0x05 //If host is going to send a full RequestDataBlockSize to be programmed, it uses this command. +#define PROGRAM_COMPLETE 0x06 //If host send less than a RequestDataBlockSize to be programmed, or if it wished to program whatever was left in the buffer, it uses this command. +#define GET_DATA 0x07 //The host sends this command in order to read out memory from the device. Used during verify (and read/export hex operations) +#define RESET_DEVICE 0x08 //Resets the microcontroller, so it can update the config bits (if they were programmed, and so as to leave the bootloader (and potentially go back into the main application) +#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 + +//Unlock Configs Command Definitions +#define UNLOCKCONFIG 0x00 //Sub-command for the ERASE_DEVICE command +#define LOCKCONFIG 0x01 //Sub-command for the ERASE_DEVICE command + +//Query Device Response "Types" +#define MEMORY_REGION_PROGRAM_MEM 0x01 //When the host sends a QUERY_DEVICE command, need to respond by populating a list of valid memory regions that exist in the device (and should be programmed) +#define MEMORY_REGION_EEDATA 0x02 +#define MEMORY_REGION_CONFIG 0x03 +#define MEMORY_REGION_USERID 0x04 +#define MEMORY_REGION_END 0xFF //Sort of serves as a "null terminator" like number, which denotes the end of the memory region list has been reached. +#define BOOTLOADER_V1_01_OR_NEWER_FLAG 0xA5 //Tacked on in the VersionFlag byte, to indicate when using newer version of bootloader with extended query info available + + +//BootState Variable States +#define IDLE 0x00 +#define NOT_IDLE 0x01 + +//OtherConstants +#define INVALID_ADDRESS 0xFFFFFFFF +#define CORRECT_UNLOCK_KEY 0xB5 + +//Application and Microcontroller constants +#define BYTES_PER_ADDRESS_PIC18 0x01 //One byte per address. PIC24 uses 2 bytes for each address in the hex file. +#define USB_PACKET_SIZE 0x40 +#define WORDSIZE 0x02 //PIC18 uses 2 byte words, PIC24 uses 3 byte words. +#define REQUEST_DATA_BLOCK_SIZE 0x3A //Number of data bytes in a standard request to the PC. Must be an even number from 2-58 (0x02-0x3A). Larger numbers make better use of USB bandwidth and + //yeild shorter program/verify times, but require more micrcontroller RAM for buffer space. + + + +/** USB Packet Request/Response Formatting Structure **********************************************************/ +typedef union +{ + unsigned char Contents[USB_PACKET_SIZE]; + + //General command (with data in it) packet structure used by PROGRAM_DEVICE and GET_DATA commands + struct{ + unsigned char Command; + unsigned long Address; + unsigned char Size; + //unsigned char PadBytes[58-REQUEST_DATA_BLOCK_SIZE]; //Uncomment this if using a smaller than 0x3A RequestDataBlockSize. Compiler doesn't like 0 byte array when using 58 byte data block size. + unsigned char Data[REQUEST_DATA_BLOCK_SIZE]; + }; + + //This struct used for responding to QUERY_DEVICE command (on a device with four programmable sections) + struct{ + unsigned char Command; + unsigned char PacketDataFieldSize; + unsigned char BytesPerAddress; + unsigned char Type1; + unsigned long Address1; + unsigned long Length1; + unsigned char Type2; + unsigned long Address2; + unsigned long Length2; + unsigned char Type3; + unsigned long Address3; + unsigned long Length3; + unsigned char Type4; + unsigned long Address4; + unsigned long Length4; + unsigned char Type5; + unsigned long Address5; + unsigned long Length5; + unsigned char Type6; + unsigned long Address6; + unsigned long Length6; + unsigned char VersionFlag; //Used by host software to identify if device is new enough to support QUERY_EXTENDED_INFO command + unsigned char ExtraPadBytes[7]; + }; + + struct{ //For UNLOCK_CONFIG command + unsigned char Command; + unsigned char LockValue; + }; + + //Structure for the QUERY_EXTENDED_INFO command (and response) + struct{ + unsigned char Command; + unsigned int BootloaderVersion; + unsigned int ApplicationVersion; + unsigned long SignatureAddress; + unsigned int SignatureValue; + unsigned long 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; + }; +} PacketToFromPC; + + +/** V A R I A B L E S ********************************************************/ +#ifndef __XC8__ +#pragma udata +#endif +PacketToFromPC PacketFromPC; +#ifndef __XC8__ +#pragma udata SomeSectionName3 +#endif +PacketToFromPC PacketToPC; +#ifndef __XC8__ +#pragma udata WriteBufferSection +#endif +unsigned char ProgrammingBuffer[ERASE_PAGE_SIZE]; +#ifndef __XC8__ +#pragma udata OtherVariablesSection +#endif +unsigned char BootState; +unsigned int ErasePageTracker; +unsigned char BufferedDataIndex; +uint24_t ProgrammedPointer; +unsigned char ConfigsLockValue; + + +/** P R I V A T E P R O T O T Y P E S ***************************************/ +void WriteFlashBlock(void); +void WriteConfigBits(void); +void WriteEEPROM(void); +void UnlockAndActivate(unsigned char UnlockKey); +void ResetDeviceCleanly(void); +void TableReadPostIncrement(void); +void SignFlash(void); +void LowVoltageCheck(void); + + +/** D E C L A R A T I O N S **************************************************/ +#ifndef __XC8__ +#pragma code +#endif +void UserInit(void) +{ + //Initialize bootloader state variables + BootState = IDLE; + ProgrammedPointer = INVALID_ADDRESS; + BufferedDataIndex = 0; + ConfigsLockValue = TRUE; +}//end UserInit + +/****************************************************************************** + * Function: void ProcessIO(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This function receives/sends USB packets to/from the USB + * host. It also processes any received OUT packets and + * is reponsible for generating USB IN packet data. + * + * Note: None + *****************************************************************************/ +void ProcessIO(void) +{ + static unsigned char i; + static ROM uint8_t* pROM; + + //Checks for and processes application related USB packets (assuming the + //USB bus is in the CONFIGURED_STATE, which is the only state where + //the host is allowed to send application related USB packets to the device. + if((USBGetDeviceState() != CONFIGURED_STATE) || (USBIsDeviceSuspended() == 1)) + { + //No point to trying to run the application code until the device has + //been configured (finished with enumeration) and is not currently suspended. + return; + } + + //Check the current bootloader state (if we are currently waiting from a new + //command to process from the host, or if we are still processing a previous + //command. + if(BootState == IDLE) + { + //We are currently in the IDLE state waiting for a command from the + //PC software on the USB host. + if(!mHIDRxIsBusy()) //Did we receive a command? + { + //We received a new command from the host. Copy the OUT packet from + //the host into a local buffer for processing. + HIDRxReport((char *)&PacketFromPC, USB_PACKET_SIZE); //Also re-arms the OUT endpoint to be able to receive the next packet + BootState = NOT_IDLE; //Set flag letting state machine know it has a command that needs processing. + + //Pre-initialize a response packet buffer (only used for some commands) + for(i = 0; i < USB_PACKET_SIZE; i++) //Prepare the next packet we will send to the host, by initializing the entire packet to 0x00. + PacketToPC.Contents[i] = 0; //This saves code space, since we don't have to do it independently in the QUERY_DEVICE and GET_DATA cases. + } + }//if(BootState == IDLE) + else //(BootState must be NOT_IDLE) + { + //Check the latest command we received from the PC app, to determine what + //we should be doing. + switch(PacketFromPC.Command) + { + case QUERY_DEVICE: + //Make sure the USB IN endpoint buffer is available, then load + //up a query response packet to send to the host. + if(!mHIDTxIsBusy()) + { + //Prepare a response packet, which lets the PC software know about the memory ranges of this device. + PacketToPC.Command = QUERY_DEVICE; + PacketToPC.PacketDataFieldSize = REQUEST_DATA_BLOCK_SIZE; + PacketToPC.BytesPerAddress = BYTES_PER_ADDRESS_PIC18; + PacketToPC.Type1 = MEMORY_REGION_PROGRAM_MEM; + PacketToPC.Address1 = (unsigned long)PROGRAM_MEM_START_ADDRESS; + PacketToPC.Length1 = (unsigned long)(PROGRAM_MEM_STOP_ADDRESS - PROGRAM_MEM_START_ADDRESS); //Size of program memory area + PacketToPC.Type2 = MEMORY_REGION_CONFIG; + PacketToPC.Address2 = (unsigned long)CONFIG_WORDS_START_ADDRESS; + PacketToPC.Length2 = (unsigned long)CONFIG_WORDS_SECTION_LENGTH; + PacketToPC.Type3 = MEMORY_REGION_USERID; //Not really program memory (User ID), but may be treated as it it was as far as the host is concerned + PacketToPC.Address3 = (unsigned long)USER_ID_ADDRESS; + PacketToPC.Length3 = (unsigned long)(USER_ID_SIZE); + PacketToPC.Type4 = MEMORY_REGION_END; + #if defined(DEVICE_WITH_EEPROM) + PacketToPC.Type4 = MEMORY_REGION_EEDATA; + PacketToPC.Address4 = (unsigned long)EEPROM_EFFECTIVE_ADDRESS; + PacketToPC.Length4 = (unsigned long)EEPROM_SIZE; + PacketToPC.Type5 = MEMORY_REGION_END; + #endif + PacketToPC.VersionFlag = BOOTLOADER_V1_01_OR_NEWER_FLAG; + //Init pad bytes to 0x00... Already done after we received the QUERY_DEVICE command (just after calling HIDRxReport()). + + //Now send the packet to the USB host software, assuming the USB endpoint is available/ready to accept new data. + HIDTxReport((char *)&PacketToPC, USB_PACKET_SIZE); + BootState = IDLE; + } + break; + case UNLOCK_CONFIG: + ConfigsLockValue = TRUE; + if(PacketFromPC.LockValue == UNLOCKCONFIG) + { + ConfigsLockValue = FALSE; + } + BootState = IDLE; + break; + case ERASE_DEVICE: + //First erase main program flash memory + for(ErasePageTracker = START_PAGE_TO_ERASE; ErasePageTracker < (unsigned int)(MAX_PAGE_TO_ERASE + 1); ErasePageTracker++) + { + ClearWatchdog(); + #ifdef __XC8__ + TBLPTRU = 0x00; + TBLPTRH = (uint8_t)((uint24_t)ErasePageTracker >> 2); + TBLPTRL = (uint8_t)((uint24_t)ErasePageTracker << 6); + #else + TBLPTR = ErasePageTracker << 6; + #endif + EECON1 = 0b10010100; //Prepare for erasing flash memory + UnlockAndActivate(CORRECT_UNLOCK_KEY); + USBDeviceTasks(); //Call USBDeviceTasks() periodically to prevent falling off the bus if any SETUP packets should happen to arrive. + } + + #if defined(DEVICE_WITH_EEPROM) + //Now erase EEPROM (if any is present on the device) + i = EEPROM_EFFECTIVE_ADDRESS & (EEPROM_SIZE-1); + do{ + EEADR = i; + EEDATA = 0xFF; + EECON1 = 0b00000100; //EEPROM Write mode + USBDeviceTasks(); //Call USBDeviceTasks() periodically to prevent falling off the bus if any SETUP packets should happen to arrive. + UnlockAndActivate(CORRECT_UNLOCK_KEY); + }while(i++<((EEPROM_SIZE-1)+(EEPROM_EFFECTIVE_ADDRESS & (EEPROM_SIZE-1)))); + #endif + + //Now erase the User ID space (0x200000 to 0x200007) + //TBLPTR = USER_ID_ADDRESS; + TBLPTRU = 0x20; + TBLPTRH = 0x00; + TBLPTRL = (uint8_t)USER_ID_ADDRESS; + EECON1 = 0b10010100; //Prepare for erasing flash memory + UnlockAndActivate(CORRECT_UNLOCK_KEY); + + BootState = IDLE; + break; + case PROGRAM_DEVICE: + //Check if host is trying to program the config bits + if(PacketFromPC.Contents[3] == 0x30) // //PacketFromPC.Contents[3] is bits 23:16 of the address. + { //0x30 implies config bits + if(ConfigsLockValue == FALSE) + { + WriteConfigBits(); //Doesn't get reprogrammed if the UNLOCK_CONFIG (LockValue = UNLOCKCONFIG) command hasn't previously been sent + } + BootState = IDLE; + break; + } + + #if defined(DEVICE_WITH_EEPROM) + //Check if host is trying to program the EEPROM + if(PacketFromPC.Contents[3] == 0xF0) //PacketFromPC.Contents[3] is bits 23:16 of the address. + { //0xF0 implies EEPROM + WriteEEPROM(); + BootState = IDLE; + break; + } + #endif + + if(ProgrammedPointer == (uint24_t)INVALID_ADDRESS) + ProgrammedPointer = PacketFromPC.Address; + + if(ProgrammedPointer == (uint24_t)PacketFromPC.Address) + { + for(i = 0; i < PacketFromPC.Size; i++) + { + ProgrammingBuffer[BufferedDataIndex] = PacketFromPC.Data[i+(REQUEST_DATA_BLOCK_SIZE-PacketFromPC.Size)]; //Data field is right justified. Need to put it in the buffer left justified. + BufferedDataIndex++; + ProgrammedPointer++; + if(BufferedDataIndex == WRITE_BLOCK_SIZE) + { + WriteFlashBlock(); + } + } + } + //else host sent us a non-contiguous packet address... to make + //this firmware simpler, host should not do this without sending + //a PROGRAM_COMPLETE command in between program sections. + BootState = IDLE; + break; + case PROGRAM_COMPLETE: + WriteFlashBlock(); + ProgrammedPointer = INVALID_ADDRESS; //Reinitialize pointer to an invalid range, so we know the next PROGRAM_DEVICE will be the start address of a contiguous section. + BootState = IDLE; + break; + case GET_DATA: + //Init pad bytes to 0x00... Already done after we received the QUERY_DEVICE command (just after calling HIDRxReport()). + PacketToPC.Command = GET_DATA; + PacketToPC.Address = PacketFromPC.Address; + PacketToPC.Size = PacketFromPC.Size; + + pROM = (ROM uint8_t*)PacketFromPC.Address; + for(i = 0; i < PacketFromPC.Size; i++) + { + if(PacketFromPC.Contents[3] == 0xF0) //PacketFromPC.Contents[3] is bits 23:16 of the address. + { //0xF0 implies EEPROM, which doesn't use the table pointer to read from + #if defined(DEVICE_WITH_EEPROM) + EEADR = (((unsigned char)PacketFromPC.Address) + i); //The bits 7:0 are 1:1 mapped to the EEPROM address space values + EECON1 = 0b00000000; //EEPROM read mode + EECON1bits.RD = 1; + PacketToPC.Data[i+((USB_PACKET_SIZE - 6) - PacketFromPC.Size)] = EEDATA; + #endif + } + else //else must have been a normal program memory region, or one that can be read from with the table pointer + { + PacketToPC.Data[i+((USB_PACKET_SIZE - 6) - PacketFromPC.Size)] = *pROM++; + } + } + + //Assuming the USB IN (to host) buffer is available/ready, copy the + //data over so it can get sent to the USB host software. + if(!mHIDTxIsBusy()) + { + HIDTxReport((char *)&PacketToPC, USB_PACKET_SIZE); + BootState = IDLE; + } + break; + case SIGN_FLASH: + SignFlash(); + BootState = IDLE; + break; + case QUERY_EXTENDED_INFO: + //Prepare a response packet with the QUERY_EXTENDED_INFO response info in it. + //This command is only supported in bootloader firmware verison 1.01 or later. + //Make sure the regular QUERY_DEVIER reponse packet value "PacketToPC.Type6" is = BOOTLOADER_V1_01_OR_NEWER_FLAG; + //to let the host PC software know that the QUERY_EXTENDED_INFO command is implemented + //in this firmware and is available for requesting by the host software. + PacketToPC.Command = QUERY_EXTENDED_INFO; //Echo the command byte + PacketToPC.BootloaderVersion = ((unsigned int)BOOTLOADER_VERSION_MAJOR << 8)| BOOTLOADER_VERSION_MINOR; + PacketToPC.ApplicationVersion = *(ROM unsigned int*)APP_VERSION_ADDRESS; + PacketToPC.SignatureAddress = APP_SIGNATURE_ADDRESS; + PacketToPC.SignatureValue = APP_SIGNATURE_VALUE; + PacketToPC.ErasePageSize = ERASE_PAGE_SIZE; + PacketToPC.Config1LMask = 0xFF; + PacketToPC.Config1HMask = 0xFF; + PacketToPC.Config2LMask = 0xFF; + PacketToPC.Config2HMask = 0xFF; + PacketToPC.Config3LMask = 0x00; + PacketToPC.Config3HMask = 0xFF; + PacketToPC.Config4LMask = 0xFF; + PacketToPC.Config4HMask = 0x00; + PacketToPC.Config5LMask = 0xFF; + PacketToPC.Config5HMask = 0xFF; + PacketToPC.Config6LMask = 0xFF; + PacketToPC.Config6HMask = 0xFF; + PacketToPC.Config7LMask = 0xFF; + PacketToPC.Config7HMask = 0xFF; + + //Now actually command USB to send the packet to the host + if(!mHIDTxIsBusy()) + { + HIDTxReport((char *)&PacketToPC, USB_PACKET_SIZE); + BootState = IDLE; //Packet will be sent, go back to idle state ready for next command from host + } + break; + case RESET_DEVICE: + ResetDeviceCleanly(); + //break; //no need, commented to save space + default: + //Should never hit the default + BootState = IDLE; + }//End switch + }//End of else of if(BootState == IDLE) + +}//End ProcessIO() + + + +//Should be called once, only after the regular erase/program/verify sequence +//has completed successfully. This function will program the magic +//APP_SIGNATURE_VALUE into the magic APP_SIGNATURE_ADDRESS in the application +//flash memory space. This is used on the next bootup to know that the the +//flash memory image of the application is intact, and can be executed. +//This is useful for recovery purposes, in the event that an unexpected +//failure occurs during the erase/program sequence (ex: power loss or user +//unplugging the USB cable). +void SignFlash(void) +{ + static unsigned char i; + static ROM uint8_t* pROM; + + //First read in the erase page contents of the page with the signature WORD + //in it, and temporarily store it in a RAM buffer. + pROM = (ROM uint8_t*)(APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK); + for(i = 0; i < ERASE_PAGE_SIZE; i++) + { + ProgrammingBuffer[i] = *pROM++; + } + + //Now change the signature WORD value at the correct address in the RAM buffer + ProgrammingBuffer[(APP_SIGNATURE_ADDRESS & ~ERASE_PAGE_ADDRESS_MASK)] = (unsigned char)APP_SIGNATURE_VALUE; + ProgrammingBuffer[(APP_SIGNATURE_ADDRESS & ~ERASE_PAGE_ADDRESS_MASK) + 1] = (unsigned char)(APP_SIGNATURE_VALUE >> 8); + + //Now erase the flash memory block with the signature WORD in it + //TBLPTR = APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK; + TBLPTRU = (uint8_t)((APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK) >> 16); + TBLPTRH = (uint8_t)((APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK) >> 8); + TBLPTRL = (uint8_t)(APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK); + + EECON1 = 0x94; //Prepare for flash erase operation + UnlockAndActivate(CORRECT_UNLOCK_KEY); + + //Now re-program the values from the RAM buffer into the flash memory. Use + //reverse order, so we program the larger addresses first. This way, the + //write page with the flash signature word is the last page that gets + //programmed (assuming the flash signature resides on the lowest address + //write page, which is recommended, so that it becomes the first page + //erased, and the last page programmed). + pROM = (ROM uint8_t*)((APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK) + ERASE_PAGE_SIZE - 1); //Point to last byte on the erase page + //TBLPTR = (APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK) + ERASE_PAGE_SIZE - 1; //Point to last byte on the erase page + i = ERASE_PAGE_SIZE - 1; + while(1) + { + #ifdef __XC8__ + TBLPTRU = (uint32_t)pROM >> 16; + TBLPTRH = (uint16_t)pROM >> 8; + TBLPTRL = (uint8_t)pROM; + #else + TBLPTR = (uint24_t)pROM; + #endif + TABLAT = ProgrammingBuffer[i]; + + #ifdef __XC8__ + #asm + tblwt + #endasm + #else //must be C18 instead + _asm tblwt _endasm + #endif + + //Check if we are at a program write block size boundary + if((i % WRITE_BLOCK_SIZE) == 0) + { + //The write latches are full, time to program the block. + ClearWatchdog(); + EECON1 = 0xA4; //Write to flash on next WR = 1 operation + UnlockAndActivate(CORRECT_UNLOCK_KEY); + } + //Move ROM pointer back to next location + pROM--; + #ifdef __XC8__ + #asm + tblrdpostdec + #endasm + #else //must be C18 instead + _asm tblrdpostdec _endasm + #endif + + //Check if we are done writing all blocks + if(i == 0) + { + break; //Exit while loop + } + i--; + } +} + + +//Before resetting the microcontroller, we should shut down the USB module +//gracefully, to make sure the host correctly recognizes that we detached +//from the bus. Some USB hosts malfunction/fail to re-enumerate the device +//correctly if the USB device does not stay detached for a minimum amount of +//time before re-attaching to the USB bus. For reliable operation, the USB +//device should stay detached for as long as a human would require to unplug and +//reattach a USB device (ex: 100ms+), to ensure the USB host software has a +//chance to process the detach event and configure itself for a state ready for +//a new attachment event. +void ResetDeviceCleanly(void) +{ + USBDisableWithLongDelay(); + Reset(); + Nop(); + Nop(); +} + + + + + +//Routine used to write data to the flash memory from the ProgrammingBuffer[]. +void WriteFlashBlock(void) //Use to write blocks of data to flash. +{ + static unsigned char i; + static unsigned char BytesTakenFromBuffer; + static unsigned char CorrectionFactor; + + #ifdef __XC8__ + static ROM uint8_t* pROM; + + pROM = (ROM uint8_t*)(ProgrammedPointer - BufferedDataIndex); + TBLPTRU = 0x00; + TBLPTRH = (uint8_t)((uint16_t)pROM >> 8); + TBLPTRL = (uint8_t)pROM; + #else + TBLPTR = (ProgrammedPointer - BufferedDataIndex); + #endif + + BytesTakenFromBuffer = 0; + + //Check the lower 5 bits of the TBLPTR to verify it is pointing to a 32 byte aligned block (5 LSb = 00000). + //If it isn't, need to somehow make it so before doing the actual loading of the programming latches. + //In order to maximize programming speed, the PC application meant to be used with this firmware will not send + //large blocks of 0xFF bytes. If the PC application + //detects a large block of unprogrammed space in the hex file (effectively = 0xFF), it will skip over that + //section and will not send it to the firmware. This works, because the firmware will have already done an + //erase on that section of memory when it received the ERASE_DEVICE command from the PC. Therefore, the section + //can be left unprogrammed (after an erase the flash ends up = 0xFF). + //This can result in a problem however, in that the next genuine non-0xFF section in the hex file may not start + //on a 32 byte aligned block boundary. This needs to be handled with care since the microcontroller can only + //program 32 byte blocks that are aligned with 32 byte boundaries. + //So, use the below code to avoid this potential issue. + + #if(WRITE_BLOCK_SIZE == 0x20) + CorrectionFactor = (TBLPTRL & 0b00011111); //Correctionfactor = number of bytes tblptr must go back to find the immediate preceeding 32 byte boundary + TBLPTRL &= 0b11100000; //Move the table pointer back to the immediately preceeding 32 byte boundary + #elif(WRITE_BLOCK_SIZE == 0x10) + CorrectionFactor = (TBLPTRL & 0b00001111); //Correctionfactor = number of bytes tblptr must go back to find the immediate preceeding 16 byte boundary + TBLPTRL &= 0b11110000; //Move the table pointer back to the immediately preceeding 16 byte boundary + #elif(WRITE_BLOCK_SIZE == 0x8) + CorrectionFactor = (TBLPTRL & 0b00000111); //Correctionfactor = number of bytes tblptr must go back to find the immediate preceeding 16 byte boundary + TBLPTRL &= 0b11111000; //Move the table pointer back to the immediately preceeding 16 byte boundary + #else + #warning "Double click this error message and fix this section for your microcontroller type." + #endif + + for(i = 0; i < WRITE_BLOCK_SIZE; i++) //Load the programming latches + { + if(CorrectionFactor == 0) + { + if(BufferedDataIndex != 0) //If the buffer isn't empty + { + TABLAT = ProgrammingBuffer[BytesTakenFromBuffer]; + #ifdef __XC8__ + #asm + tblwtpostinc + #endasm + #else //must be C18 instead + _asm tblwtpostinc _endasm + #endif + + BytesTakenFromBuffer++; + BufferedDataIndex--; //Used up a byte from the buffer. + } + else //No more data in buffer, need to write 0xFF to fill the rest of the programming latch locations + { + TABLAT = 0xFF; + #ifdef __XC8__ + #asm + tblwtpostinc + #endasm + #else //must be C18 instead + _asm tblwtpostinc _endasm + #endif + + + } + } + else + { + TABLAT = 0xFF; + #ifdef __XC8__ + #asm + tblwtpostinc + #endasm + #else //must be C18 instead + _asm tblwtpostinc _endasm + #endif + CorrectionFactor--; + } + } + + // TBLPTR--; //Need to make table pointer point to the region which will be programmed before initiating the programming operation + #ifdef __XC8__ + #asm + tblrdpostdec + #endasm + #else //must be C18 instead + _asm tblrdpostdec _endasm //Do this instead of TBLPTR--; since it takes less code space. + #endif + + EECON1 = 0b10100100; //flash programming mode + UnlockAndActivate(CORRECT_UNLOCK_KEY); + + //Now need to fix the ProgrammingBuffer[]. We may not have taken a full 32 bytes out of the buffer. In this case, + //the data is no longer justified correctly. + for(i = 0; i < BufferedDataIndex; i++) //Need to rejustify the remaining data to the "left" of the buffer (if there is any left) + { + ProgrammingBuffer[i] = ProgrammingBuffer[BytesTakenFromBuffer+i]; + } +} + + +void WriteConfigBits(void) //Also used to write the Device ID +{ + static unsigned char i; + + #ifdef __XC8__ + TBLPTRU = 0x30; + TBLPTRH = (uint8_t)((uint16_t)PacketFromPC.Address >> 8); + TBLPTRH = (uint8_t)(PacketFromPC.Address); + #else + TBLPTR = (uint24_t)PacketFromPC.Address; + #endif + + for(i = 0; i < PacketFromPC.Size; i++) + { + TABLAT = PacketFromPC.Data[i+(REQUEST_DATA_BLOCK_SIZE-PacketFromPC.Size)]; + #ifdef __XC8__ + #asm + tblwt + #endasm + #else //must be C18 instead + _asm tblwt _endasm + #endif + + EECON1 = 0b11000100; //Config bits programming mode + UnlockAndActivate(CORRECT_UNLOCK_KEY); + + #ifdef __XC8__ + #asm + tblrdpostinc + #endasm + #else //must be C18 instead + _asm tblrdpostinc _endasm + #endif + } +} + +#if defined(DEVICE_WITH_EEPROM) +void WriteEEPROM(void) +{ + static unsigned char i; + + for(i = 0; i < PacketFromPC.Size; i++) + { + EEADR = (((unsigned char)PacketFromPC.Address) + i); + EEDATA = PacketFromPC.Data[i+(REQUEST_DATA_BLOCK_SIZE-PacketFromPC.Size)]; + + EECON1 = 0b00000100; //EEPROM Write mode + UnlockAndActivate(CORRECT_UNLOCK_KEY); + } + +} +#endif + +//It is preferrable to only place this sequence in only one place in the flash memory. +//This reduces the probabilty of the code getting executed inadvertently by +//errant code. It is also recommended to enable BOR (in hardware) and/or add +//software checks to avoid microcontroller "overclocking". Always make sure +//to obey the voltage versus frequency graph in the datasheet, even during +//momentary events (such as the power up and power down ramp of the microcontroller). +void UnlockAndActivate(unsigned char UnlockKey) +{ + INTCONbits.GIE = 0; //Make certain interrupts disabled for unlock process. + + //Check to make sure the caller really was trying to call this function. + //If they were, they should always pass us the CORRECT_UNLOCK_KEY. + if(UnlockKey != CORRECT_UNLOCK_KEY) + { + //Warning! Errant code execution detected. Somehow this + //UnlockAndActivate() function got called by someone that wasn't trying + //to actually perform an NVM erase or write. This could happen due to + //microcontroller overclocking (or undervolting for an otherwise allowed + //CPU frequency), or due to buggy code (ex: incorrect use of function + //pointers, etc.). In either case, we should execute some fail safe + //code here to prevent corruption of the NVM contents. + OSCCON = 0x03; //Switch to INTOSC at low frequency + while(1) + { + Sleep(); + } + Reset(); + } + + #ifdef __XC8__ + EECON2 = 0x55; + EECON2 = 0xAA; + EECON1bits.WR = 1; + #else + _asm + //Now unlock sequence to set WR (make sure interrupts are disabled before executing this) + MOVLW 0x55 + MOVWF EECON2, 0 + MOVLW 0xAA + MOVWF EECON2, 0 + BSF EECON1, 1, 0 //Performs write by setting WR bit + _endasm + #endif + + while(EECON1bits.WR); //Wait until complete (relevant when programming EEPROM, not important when programming flash since processor stalls during flash program) + EECON1bits.WREN = 0; //Good practice now to clear the WREN bit, as further protection against any accidental activation of self write/erase operations. +} + + +//Note: The ClrWdt() and "_asm tblrdpostinc _endasm" are inline assembly language +//instructions. The ClearWatchdog() and TableReadPostIncrement() functions are +//theoretically extraneous, since the operations being accomplished could be +//done without calling them as separate functions. However, when using inline +//assembly language, the C18 compiler normally doesn't know what the code will +//actually do (ex: will it modify STATUS reg, WREG, BSR contents??). As a +//result, it is potentially dangerous for the C compiler to make assumptions, +//that might turn out not to be correct. Therefore, the C18 compiler disables +//the compiler optimizations for a function, when one or more inline asm +//instructions are located within the C function. Therefore, to promote best +//code size optimizations from the C18 compiler, it is best to locate inline +//assembly sequences in their own separate C functions, that do not contain much +//other code (which could otherwise be optimized by the C compiler). This often +//results in the smallest code size, and is the reason it is being done here. +void TableReadPostIncrement(void) +{ + #ifdef __XC8__ + #asm + tblrdpostinc + #endasm + #else //must be C18 instead + _asm tblrdpostinc _endasm + #endif +} + +/** EOF BootPIC18NonJ.c *********************************************************/ diff --git a/bootloader_hacked_from_mla/src/BootPIC18NonJ.h b/bootloader_hacked_from_mla/src/BootPIC18NonJ.h new file mode 100644 index 0000000..9c8e93b --- /dev/null +++ b/bootloader_hacked_from_mla/src/BootPIC18NonJ.h @@ -0,0 +1,41 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +#ifndef BOOTPIC18NONJ_H +#define BOOTPIC18NONJ_H + +/** P U B L I C P R O T O T Y P E S *****************************************/ +void UserInit(void); +void ProcessIO(void); +void ClearWatchdog(void); +void DisableUSBandExecuteLongDelay(void); + + +//Vector remapping/absolute address constants +#define REMAPPED_APPLICATION_RESET_VECTOR 0x1400 +//#define REMAPPED_APPLICATION_HIGH_ISR_VECTOR 0x1408 //See VectorRemap.asm +//#define REMAPPED_APPLICATION_LOW_ISR_VECTOR 0x1418 //See VectorRemap.asm +#define BOOTLOADER_ABSOLUTE_ENTRY_ADDRESS 0x001C //Execute a "goto 0x001C" inline assembly instruction, if you want to enter the bootloader mode from the application via software + +#define APP_SIGNATURE_ADDRESS 0x1406 //0x1006 and 0x1007 contains the "signature" WORD, indicating successful erase/program/verify operation +#define APP_SIGNATURE_VALUE 0x600D //leet "GOOD", implying that the erase/program was a success and the bootloader intentionally programmed the APP_SIGNATURE_ADDRESS with this value +#define APP_VERSION_ADDRESS 0x1416 //0x1016 and 0x1017 should contain the application image firmware version number + + + +#endif //BOOTPIC18NONJ_H diff --git a/bootloader_hacked_from_mla/src/HardwareProfile.h b/bootloader_hacked_from_mla/src/HardwareProfile.h new file mode 100644 index 0000000..446247d --- /dev/null +++ b/bootloader_hacked_from_mla/src/HardwareProfile.h @@ -0,0 +1,30 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +#ifndef __HARDWARE_PROFILE_H_ +#define __HARDWARE_PROFILE_H_ + + +/** I N C L U D E S *************************************************/ +#include "usb_config.h" + + + + +#endif //__HARDWARE_PROFILE_H_ diff --git a/bootloader_hacked_from_mla/src/VectorRemap.asm b/bootloader_hacked_from_mla/src/VectorRemap.asm new file mode 100644 index 0000000..7cee7c3 --- /dev/null +++ b/bootloader_hacked_from_mla/src/VectorRemap.asm @@ -0,0 +1,39 @@ +;/******************************************************************************* +;Copyright 2016 Microchip Technology Inc. (www.microchip.com) +; +;Licensed under the Apache License, Version 2.0 (the "License"); +;you may not use this file except in compliance with the License. +;You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +;Unless required by applicable law or agreed to in writing, software +;distributed under the License is distributed on an "AS IS" BASIS, +;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +;See the License for the specific language governing permissions and +;limitations under the License. +; +;To request to license the code under the MLA license (www.microchip.com/mla_license), +;please contact mla_licensing@microchip.com +;*******************************************************************************/ + + ;//High priority interrupt vector remapping +#ifdef __XC8__ + PSECT HiVector,class=CODE,delta=1,abs +#endif + org 0x08 + goto 0x1408 ;Resides at 0x0008 (hardware high priority interrupt vector), and causes PC to jump to 0x1408 upon a high priority interrupt event + + + ;//Low priority interrupt vector remapping, as well as bootloader mode absolute + ;//entry point (located at 0x001C). +#ifdef __XC8__ + PSECT LoVector,class=CODE,delta=1,abs +#endif + org 0x18 + goto 0x1418 ;Resides at 0x0018 (hardware low priority interrupt vector), and causes PC to jump to 0x1418 upon a low priority interrupt event + goto 0x30 ;Resides at 0x001C //Serves as absolute entry point from application program into the bootloader mode + + + + end \ No newline at end of file diff --git a/bootloader_hacked_from_mla/src/main.c b/bootloader_hacked_from_mla/src/main.c new file mode 100644 index 0000000..164c175 --- /dev/null +++ b/bootloader_hacked_from_mla/src/main.c @@ -0,0 +1,626 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +/********************************************************************* +IMPORTANT NOTES: This code can be readily adapted for use with the +both the F and LF versions of the following devices: + +PIC18F4553/4458/2553/2458 +PIC18F4550/4455/2550/2455 +PIC18F4450/2450 +PIC18F14K50/13K50 +PIC18F45K50/25K50/24K50 + +However, the default device that is currently selected in the project +may not be the device you are interested. To change the device: + +Replace the linker script with an appropriate version, and +click "Configure --> Select Device" and select the proper +microcontroller. Also double check to verify that the HardwareProfile.h and +usb_config.h are properly configured to match your desired application +platform. + +Verify that the configuration bits are set correctly for the intended +target application, and fix any build errors that result from either +the #error directives, or due to I/O pin count mismatch issues (such +as when using a 28-pin device, but without making sufficient changes +to the HardwareProfile.h file) + + +------------------------------------------------------------------- +NOTE FOR BUILDING WITH C18 COMPILER: +------------------------------------------------------------------- +This project needs to be built with the full compiler optimizations +enabled, and using the Default storage class "Static" or the total +code size will be too large to fit within the program memory +range 0x000-0xFFF. The default linker script included +in the project has this range reserved for the use by the bootloader, +but marks the rest of program memory as "PROTECTED". If you try to +build this project with the compiler optimizations turned off, or +you try to modify some of this code, but add too much code to fit +within the 0x000-0xFFF region, a linker error like that below may occur: + +Error - section '.code' can not fit the section. Section '.code' length=0x00000020 +To fix this error, either optimize the program to fit within 0x000-0xFFF +(such as by turning on all compiler optimizations, and making sure the +"default storage class" is set to "Static"), or modify the linker +and vector remapping (as well as the application projects) to allow this +bootloader to use more program memory. + +------------------------------------------------------------------- +NOTE FOR BUILDING THIS BOOTLOADER FIRMWARE WITH THE XC8 COMPILER: +------------------------------------------------------------------- +To build this code with the XC8 compiler, make sure to use the linker +option: +ROM ranges: default,-1000-XXXXXX //Where "XXXXXX" is the last implemented flash memory +address, excluding the config bit region (ex: "default,-1000-7FFF" for the 32kB PIC18F45K50) +This setting is found in the XC8 compiler linker settings, Option category: Memory Model. + +If any errors are encountered relating to "cannot find space", this +presumably means that either the compiler was configured to build the +code in Free or Standard mode, or that modifications have been made to +the code that have increased the code size to exceed the 0x000-0xFFF program +memory region. If this error is encountered, make sure to build the project +with all PRO mode optimizations enabled, and/or optimize any user added code +that is causing the project size to exceed the 0x000-0xFFF region. + +---------------------------------------------------------------------- +NOTE FOR BUILDING APPLICATION FIRMWARE PROJECTS WITH THE XC8 COMPILER: +---------------------------------------------------------------------- +When building the application project that is meant to be programmed by this +bootloader, you must use different XC8 linker settings as this project. +For application projects, two linker settings are required: + +ROM ranges: default,-0-FFF,-1006-1007,-1016-1017 +Codeoffset: 0x1000 + +When the above settings are implemented, the application firmware will no longer work +without the bootloader present. Therefore, it is recommended to add the bootloader +firmware output (from this bootloader project) .hex file as a "Loadable" into +the application firmware project. This will allow the "HEXMATE" tool to run +after building the application firmware project, which will merge the application +output .hex file contents with the bootloader output .hex file contents (which was +added as a loadable file). + +However, in some cases you may encounter build errors during the hex merge operation. +This will occur if there are any overlapping regions in the bootloader firmware +.hex file, with the application firmware .hex file, when the contents of these +overlapping regions are not 100% exact matches to each other. Normally, only the +configuration bit settings will be overlapping between the two projects. + +Therefore, to prevent build errors, the configuration bit settings between the +bootloader firmware project and the application firmware project must be set to +100% exactly identical values (or they must only be set in one of the projects, +to eliminate the overlapping region altogether). + + +----------------------Bootloader Entry------------------------------------------ +Entry into this bootloader firmware can be done by either of two possible +ways: + +1. I/O pin check at power up/after any reset. and/or: +2. Software entry via absolute jump to address 0x001C. + +The I/O pin check method is the most rugged, since it does not require the +application firmware image to be intact (at all) to get into the bootloader +mode. However, software entry is also possible and may be more convenient +in applications that do not have user exposed pushbuttons available. + +When the "application" image is executing, it may optionally jump into +bootloader mode, by executing a _asm goto 0x001C _endasm instruction. +Before doing so however, the firwmare should configure the current +clock settings to be compatible with USB module operation, in they +are not already. Once the goto 0x001C has been executed the USB device +will detach from the USB bus (if it was previously attached), and will +re-enumerate as a HID class device with a new VID/PID (adjustable via +usb_dsc.c settings), which can communicate with the associated +USB host software that loads and programs the new .hex file. + + +-------------------------------------------------------------------------------- +Anytime that an application implements flash self erase/write capability, +special care should be taken to make sure that the microcontroller is operated +within all datasheet ratings, especially those associated with voltage versus +frequency. + +Operating the device at too high of a frequency (for a given voltage, ex: by +operating at 48MHz at 2.1V, while the device datasheet indicates some higher +value such as 2.35V+ is required) can cause unexpected code operation. This +could potentially allow inadvertent execution of bootloader or other self +erase/write routines, causing corruption of the flash memory of the application. + +To avoid this, all applications that implement self erase/write capability +should make sure to prevent execution during overclocked/undervolted conditions. + +For this reason, enabling and using the microcontroller hardware Brown-out-Reset +feature is particularly recommended for applications using a bootloader. If +BOR is not used, or the trip threshold is too low for the intended application +frequency, it is suggested to add extra code in the application to detect low +voltage conditions, and to intentionally clock switch to a lower frequency +(or put the device to sleep) during the low voltage condition. Hardware +modules such as the ADC, comparators, or the HLVD (high/low voltage detect) +can often be used for this purpose. + + +-------------------------------------------------------------------------------- +This bootloader supports reprogramming of the microcontroller configuration bits, +however, it is strongly recommended never to do so, unless absolutely necessary. +Reprogramming the config bits is potentially risky, since it requires that the +new configuration bits be 100% compatible with USB operation (ex: oscillator +settings, etc.). If a .hex file with incorrect config bits is programmed +into this device, it can render the bootloader inoperable. Additionally, +unexpected power failure or device detachment during the reprogramming of the +config bits could result in unknown values getting stored in the config bits, +which could "brick" the application. + +Normally, the application firmware project and this bootloader project should +be configured to use/set the exact same configuration bit values. Only one set +of configuration bits actually exists in the microcontroller, and these values +must be shared between the bootloader and application firmware. +*******************************************************************************/ + + + +/** I N C L U D E S **********************************************************/ +#include "usb.h" +#include "HardwareProfile.h" +#include "BootPIC18NonJ.h" + +/** V A R I A B L E S ********************************************************/ +//NOTE: You must not use initalized variables in this bootloader project. This +//firmware project does not rely on the standard C initializer, which is +//responsible for setting up initialized variables in RAM. Therefore, all +//variables will be non-initialized/random at start up. +#ifndef __XC8__ +#pragma udata +#endif +unsigned int uint_delay_counter; + + +//------------------------------------------------------------------------------ +//Private prototypes +//------------------------------------------------------------------------------ +void main(void); +void BootMain(void); +void LowVoltageCheck(void); +void InitializeSystem(void); + + + +//Special "flash signature" located in the application program memory space (not +//part of the bootloader firmware program space). This flash signature is used +//to improve application recoverability/robustness, in the event the user unplugs +//the USB cable or AC power is lost during an erase/program/verify sequence. +#ifdef __XC8__ + const unsigned int __at(APP_SIGNATURE_ADDRESS) FlashSignatureWord = APP_SIGNATURE_VALUE; +#else + #pragma romdata FLASH_SIG_SECTION = APP_SIGNATURE_ADDRESS + ROM unsigned int FlashSignatureWord = APP_SIGNATURE_VALUE; + #pragma code +#endif + + +//Special handling for modified linker script. +#ifndef __XC8__ +//Note: This project uses a modified linker script, which does not include the +//c018i.o standard C initializer for C18 projects. Therefore, we must manually +//place a goto main() at the hardware reset vector. +#pragma code _entry_scn=0x000000 //Reset vector is at 0x00. Device begins executing code from 0x00 after a reset or POR event +void _entry (void) +{ + _asm goto main _endasm +} +#pragma code +#endif + + + +/****************************************************************************** + * Function: void main(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This is the first code that executes during boot up of + * the microcontroller. This code checks to see if execution + * should stay in the "bootloader" mode, or if it should jump + * into the "application" (non-bootloder) execution mode. + * No other unrelated code should be added to this function. + * + * Note: THIS FUNCTION EXECUTES PRIOR TO INITIALIZATION OF THE C + * STACK. NO C INITIALIZATION OF STATIC VARIABLES OR RESOURCES + * WILL OCCUR, PRIOR TO EXECUTING THIS FUNCTION. THEREFORE, + * THE CODE IN THIS FUNCTION MUST NOT CALL OTHER FUNCTIONS OR + * PERFORM ANY OPERATIONS THAT WILL REQUIRE C INITIALIZED + * BEHAVIOR. + *****************************************************************************/ +void main(void) +{ + //Assuming the I/O pin check entry method is enabled, check the I/O pin value + //to see if we should stay in bootloader mode, or jump to normal applicaiton + //execution mode. + /*#ifdef ENABLE_IO_PIN_CHECK_BOOTLOADER_ENTRY + //Check Bootload Mode Entry Condition from the I/O pin (ex: place a + //pushbutton and pull up resistor on the pin) + if(0) + { + //Before going to application image however, make sure the image + //is properly signed and is intact. + goto DoFlashSignatureCheck; + } + else + { + //User is pressing the pushbutton. We should stay in bootloader mode + BootMain(); + } + #endif //#ifdef ENABLE_IO_PIN_CHECK_BOOTLOADER_ENTRY + */ +DoFlashSignatureCheck: + //Check if the application region flash signature is valid + if(*(ROM unsigned int*)APP_SIGNATURE_ADDRESS == APP_SIGNATURE_VALUE) + { + //The flash signature was valid, implying the previous + //erase/program/verify operation was a success. + + //Also make sure the first WORD of program memory in the app space + //is not blank, meaning there is an application image programmed into the device. + if(*(ROM unsigned int*)REMAPPED_APPLICATION_RESET_VECTOR != 0xFFFF) + { + //Go ahead and jump out of bootloader mode into the application run mode + #ifdef __XC8__ + #asm + goto REMAPPED_APPLICATION_RESET_VECTOR + #endasm + #else //Must be C18 instead + _asm goto REMAPPED_APPLICATION_RESET_VECTOR _endasm + #endif + } + } + //else the application image is missing or corrupt. In this case, we + //need to stay in the bootloader mode, so the user has the ability to + //try (again) to re-program a valid application image into the device. + + //We should stay in bootloader mode + BootMain(); + +}//end UninitializedMain + + + +/****************************************************************************** + * Function: void BootMain(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This is the main function for this bootloader mode firmware. + * if execution gets to this function, it is assumed that we + * want to stay in bootloader mode for now. + * + * Note: If adding code to this function, make sure to add it only + * after the C initializer like code at the top of this function. + * Additionally, code written in this project should not assume + * any variables or registers have been initialized by the C + * compiler (since they may not have been, if the user jumped + * from the application run mode into bootloader mode directly). + *****************************************************************************/ +#ifdef __XC8__ +void __at(0x30) BootMain(void) +#else +#pragma code BOOT_MAIN_SECTION=0x30 +void BootMain(void) +#endif +{ + //NOTE: The c018.o file is not included in the linker script for this project. + //The C initialization code in the c018.c (comes with C18 compiler in the src directory) + //file is instead modified and included here manually. This is done so as to provide + //a more convenient entry method into the bootloader firmware. Ordinarily the _entry_scn + //program code section starts at 0x00 and is created by the code of c018.o. However, + //the linker will not work if there is more than one section of code trying to occupy 0x00. + //Therefore, must not use the c018.o code, must instead manually include the useful code + //here instead. + + //Make sure interrupts are disabled for this code (could still be on, + //if the application firmware jumped into the bootloader via software methods) + INTCON = 0x00; + + //Initialize the C stack pointer, and other compiler managed items as + //normally done in the c018.c file (applicable when using C18 compiler) + #ifndef __XC8__ + _asm + lfsr 1, _stack + lfsr 2, _stack + clrf TBLPTRU, 0 + _endasm + #endif + + //Clear the stack pointer, in case the user application jumped into + //bootloader mode with excessive junk on the call stack + STKPTR = 0x00; + + // End of the important parts of the C initializer. This bootloader firmware does not use + // any C initialized user variables (idata memory sections). Therefore, the above is all + // the initialization that is required. + + + + //Call other initialization code and (re)enable the USB module + InitializeSystem(); //Some USB, I/O pins, and other initialization + + //Execute main loop + while(1) + { + ClrWdt(); + + //Need to call USBDeviceTasks() periodically. This function takes care of + //processing non-USB application related USB packets (ex: "Chapter 9" + //packets associated with USB enumeration) + USBDeviceTasks(); + + ProcessIO(); //This is where all the actual bootloader related data transfer/self programming takes + //place see ProcessIO() function in the BootPIC[xxxx].c file. + }//end while +} + + +#ifndef __XC8__ +#pragma code +#endif +/****************************************************************************** + * Function: static void InitializeSystem(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: InitializeSystem is a centralize initialization routine. + * All required USB initialization routines are called from + * here. + * + * User application initialization routine should also be + * called from here. + * + * Note: None + *****************************************************************************/ +void InitializeSystem(void) +{ + UserInit(); //Initialize bootloader application variables (see Bootxxxx.c file) + + //Initialize USB module only after oscillator and other settings are compatible with USB operation + USBDeviceInit(); //Initializes USB module SFRs and firmware + //variables to known states. +}//end InitializeSystem + +// ****************************************************************************************************** +// ************** USB Callback Functions **************************************************************** +// ****************************************************************************************************** +// The USB firmware stack will call the callback functions USBCBxxx() in response to certain USB related +// events. For example, if the host PC is powering down, it will stop sending out Start of Frame (SOF) +// packets to your device. In response to this, all USB devices are supposed to decrease their power +// consumption from the USB Vbus to <2.5mA* each. The USB module detects this condition (which according +// to the USB specifications is 3+ms of no bus activity/SOF packets) and then calls the USBCBSuspend() +// function. You should modify these callback functions to take appropriate actions for each of these +// conditions. For example, in the USBCBSuspend(), you may wish to add code that will decrease power +// consumption from Vbus to <2.5mA (such as by clock switching, turning off LEDs, putting the +// microcontroller to sleep, etc.). Then, in the USBCBWakeFromSuspend() function, you may then wish to +// add code that undoes the power saving things done in the USBCBSuspend() function. +// +// Note *: The "usb_20.pdf" specs indicate 500uA or 2.5mA, depending upon device classification. However, +// the USB-IF has officially issued an ECN (engineering change notice) changing this to 2.5mA for all +// devices. Make sure to re-download the latest specifications to get all of the newest ECNs. + +/****************************************************************************** + * Function: void USBCBWakeFromSuspend(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: The host may put USB peripheral devices in low power + * suspend mode (by "sending" 3+ms of idle). Once in suspend + * mode, the host may wake the device back up by sending non- + * idle state signalling. + * + * This call back is invoked when a wakeup from USB suspend + * is detected. + * + * Note: Before returning from this function, make sure that the + * oscillator settings are fully compatible with USB module + * operation. + * If using the two-speed startup feature, wakeup and execution + * will occur before the main oscillator + PLL has had a chance + * to start. Device will run from INTOSC (no PLL). However, the + * USB module cannot be clocked and receive correct USB data when + * it is not clocked with the correct frequency clock source. + * Therefore, when using two-speed startup, should execute software + * delay to prevent any other code from executing until the main + * oscillator is ready. + * The host will allow at least 10ms for USB "resume recovery", during + * which it will not try to communicate with the device. + *****************************************************************************/ +void USBCBWakeFromSuspend(void) +{ + //This code delays ~5ms @ 8MHz to execute (using C18 3.21 with full + //optimizations enabled), but takes much less time at 48MHz. This delay + //is to make sure the PLL is enabled and locked, in case two speed startup + //was enabled + DelayRoutine(0x300); //Device will switch clocks (if using two-speed startup) while executing this delay function + + //Primary oscillator and PLL should be running by now. + + //Do not return from this function until the oscillator is correctly configured and + //running in a USB compatible mode/frequency. + + + //Additional code for re-enabling I/O pins and increasing power draw from VBUS + //may be placed here (up to the maximum of 100mA [when unconfigured] or the + //amount specified in the configuration descriptor (when configured). +} + + + +/****************************************************************************** + * Function: void USBCBSuspend(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: Call back that is invoked when a USB suspend is detected + * + * Note: None + *****************************************************************************/ +void USBCBSuspend(void) +{ + Sleep(); // Go to sleep, wake up when a USB activity event occurs + //If using the WDT, should go back to sleep if awoke by WDT instead of USBIF + while((USBIF_FLAG == 0) && (RCONbits.TO == 0)) //If using the WDT, should go back to sleep if awoke by WDT instead of USBIF + { + Sleep(); //Entry into sleep clears WDT count, much like executing ClrWdt() instruction + } + + //After the USB suspend event ends, you should re-configure your I/O pins + //for normal operation mode (which is allowed to consume more current). + //However, it is recommended to put this code in the USBCBWakeFromSuspend() + //function instead of here (so that this function will work with either + //sleeping or clock switching to a lower frequency). +} + + +/******************************************************************* + * Function: void USBCBInitEP(uint8_t ConfigurationIndex) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This function is called when the device becomes + * initialized, which occurs after the host sends a + * SET_CONFIGURATION request. This + * callback function should initialize the endpoints + * for the device's usage according to the current + * configuration. + * + * Note: If the host ever "unconfigures" the device, it will + * set the configuration to '0'. In this case, this + * callback gets called with ConfigurationIndex == 0, where + * the firmware should disable all non-EP0 endpoints (until + * the next non-zero SET_CONFIGURATION request is received, + * which will cause this callback to execute again). + *******************************************************************/ +void USBCBInitEP(uint8_t ConfigurationIndex) +{ + //Check what configuration "index" the host has requested us to select. + //Configuration index 0 is special and represents that the device should be + //un-configured. However, when the host sets the configuration (with index + //matching the valid/implemented configuration from the configuration descriptor), + //the firmware should enable the application endpoints associated with that + //configuration, and (re)initialize all application state variables associated + //with the USB application endpoints operation. + if(ConfigurationIndex == 1) //This application only implements one configuration, with index == 1. + { + //The host sent us a non-zero set configuration index. In this + //case we should prepare the application endpoints to be ready + //to use, and to (re-)initialize any application variables associated + //with the endpoints. + HIDInitEP(); + + //(Re-)Initialize the application variables associated with the USB interface + UserInit(); // See BootPIC[xxxx].c. Initializes the bootloader firmware state machine variables. + } + //else the host set the configuration back to 0 (indicating unconfigured), or + //to some higher (non-implemented value). In either case, we don't need to + //do anything specifically, unless the application requires some kind of + //"safe shutdown" code to execute after the host has deconfigured the device. + +} + + + +/******************************************************************* + * Function: void USBCBCheckOtherReq(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This function is called when the USB stack receives a + * new control transfer SETUP packet from the host. The + * USB stack handles normal USB "Chapter 9" requests internally, + * but some control transfer requests are class specific. In + * order to handle these class specific requests, you must call + * the class handler's firmware control transfer handler function. + * If implementing a composite device with multiple classes + * implemented, call each of the handlers in the below callback. + * + * Note: None + *******************************************************************/ +void USBCBCheckOtherReq(void) +{ + USBCheckHIDRequest(); +} + + +//Compiler mode and version check. This code needs to fit within the [0x000-0xFFF] program +//memory region that is reserved for use by the bootloader. However, if this +//code is built in XC8 Standard or Free mode (instead of PRO), +//the code may be too large to fit within the region, and a variety of linker +//error messages (ex: "can't find space") will result. Unfortunately these +//linker error messages can be cryptic to a user, so instead we add a deliberate +//#error to make a more human friendly error appear, in the event the wrong +//compiler mode is attempted to use to build this code. If you get this error +//message, please upgrade to the PRO compiler, and then use the mode +//(ex: build configuration --> XC8 compiler --> Option Categories: Optimizations --> Operation Mode: PRO) +//#ifdef __XC8__ +// #if _HTC_EDITION_ < 2 //Check if PRO, Standard, or Free mode +// #error "This bootloader project must be built in PRO mode to fit within the reserved region. Double click this message for more details." +// #endif +//#endif + +/** EOF main.c ***************************************************************/ diff --git a/bootloader_hacked_from_mla/src/typedefs.h b/bootloader_hacked_from_mla/src/typedefs.h new file mode 100644 index 0000000..011a7bd --- /dev/null +++ b/bootloader_hacked_from_mla/src/typedefs.h @@ -0,0 +1,425 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +#ifndef __CUSTOMIZED_TYPE_DEFS_H_ +#define __CUSTOMIZED_TYPE_DEFS_H_ + +#include +#define ROM const +#define rom +#include +#include +#ifndef Nop() +#define Nop() {asm("NOP");} +#endif +#ifndef ClrWdt() +#define ClrWdt() {asm("CLRWDT");} +#endif +#ifndef Reset() +#define Reset() {asm("RESET");} +#endif +#ifndef Sleep() +#define Sleep() {asm("SLEEP");} +#endif + +#define __EXTENSION + +#if !defined(__PACKED) + #define __PACKED +#endif + +/* get compiler defined type definitions (NULL, size_t, etc) */ +#include +#include +#include +#include + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define PUBLIC /* Function attributes */ +#define PROTECTED +#define PRIVATE static + +/* INT is processor specific in length may vary in size */ +typedef signed int INT; +typedef signed char INT8; +typedef signed short int INT16; +typedef signed long int INT32; + +/* UINT is processor specific in length may vary in size */ +typedef unsigned int UINT; +typedef unsigned char UINT8; +typedef unsigned short int UINT16; +typedef unsigned long int UINT32; /* other name for 32-bit integer */ + + +typedef union +{ + UINT8 Val; + struct + { + __EXTENSION UINT8 b0:1; + __EXTENSION UINT8 b1:1; + __EXTENSION UINT8 b2:1; + __EXTENSION UINT8 b3:1; + __EXTENSION UINT8 b4:1; + __EXTENSION UINT8 b5:1; + __EXTENSION UINT8 b6:1; + __EXTENSION UINT8 b7:1; + } bits; +} UINT8_VAL, UINT8_BITS; + +typedef union +{ + UINT16 Val; + UINT8 v[2] __PACKED; + struct __PACKED + { + UINT8 LB; + UINT8 HB; + } byte; + struct __PACKED + { + __EXTENSION UINT8 b0:1; + __EXTENSION UINT8 b1:1; + __EXTENSION UINT8 b2:1; + __EXTENSION UINT8 b3:1; + __EXTENSION UINT8 b4:1; + __EXTENSION UINT8 b5:1; + __EXTENSION UINT8 b6:1; + __EXTENSION UINT8 b7:1; + __EXTENSION UINT8 b8:1; + __EXTENSION UINT8 b9:1; + __EXTENSION UINT8 b10:1; + __EXTENSION UINT8 b11:1; + __EXTENSION UINT8 b12:1; + __EXTENSION UINT8 b13:1; + __EXTENSION UINT8 b14:1; + __EXTENSION UINT8 b15:1; + } bits; +} UINT16_VAL, UINT16_BITS; + +typedef union +{ + UINT32 Val; + UINT16 w[2] __PACKED; + UINT8 v[4] __PACKED; + struct __PACKED + { + UINT16 LW; + UINT16 HW; + } word; + struct __PACKED + { + UINT8 LB; + UINT8 HB; + UINT8 UB; + UINT8 MB; + } byte; + struct __PACKED + { + UINT16_VAL low; + UINT16_VAL high; + }wordUnion; + struct __PACKED + { + __EXTENSION UINT8 b0:1; + __EXTENSION UINT8 b1:1; + __EXTENSION UINT8 b2:1; + __EXTENSION UINT8 b3:1; + __EXTENSION UINT8 b4:1; + __EXTENSION UINT8 b5:1; + __EXTENSION UINT8 b6:1; + __EXTENSION UINT8 b7:1; + __EXTENSION UINT8 b8:1; + __EXTENSION UINT8 b9:1; + __EXTENSION UINT8 b10:1; + __EXTENSION UINT8 b11:1; + __EXTENSION UINT8 b12:1; + __EXTENSION UINT8 b13:1; + __EXTENSION UINT8 b14:1; + __EXTENSION UINT8 b15:1; + __EXTENSION UINT8 b16:1; + __EXTENSION UINT8 b17:1; + __EXTENSION UINT8 b18:1; + __EXTENSION UINT8 b19:1; + __EXTENSION UINT8 b20:1; + __EXTENSION UINT8 b21:1; + __EXTENSION UINT8 b22:1; + __EXTENSION UINT8 b23:1; + __EXTENSION UINT8 b24:1; + __EXTENSION UINT8 b25:1; + __EXTENSION UINT8 b26:1; + __EXTENSION UINT8 b27:1; + __EXTENSION UINT8 b28:1; + __EXTENSION UINT8 b29:1; + __EXTENSION UINT8 b30:1; + __EXTENSION UINT8 b31:1; + } bits; +} UINT32_VAL; + +/***********************************************************************************/ + +/* Alternate definitions */ +typedef void VOID; + +typedef char CHAR8; +typedef unsigned char UCHAR8; + +typedef unsigned char BYTE; /* 8-bit unsigned */ +typedef unsigned short int WORD; /* 16-bit unsigned */ +typedef unsigned long DWORD; /* 32-bit unsigned */ +//typedef unsigned long long QWORD; /* 64-bit unsigned */ +typedef signed char CHAR; /* 8-bit signed */ +typedef signed short int SHORT; /* 16-bit signed */ +typedef signed long LONG; /* 32-bit signed */ +//typedef signed long long LONGLONG; /* 64-bit signed */ +typedef union +{ + BYTE Val; + struct __PACKED + { + __EXTENSION BYTE b0:1; + __EXTENSION BYTE b1:1; + __EXTENSION BYTE b2:1; + __EXTENSION BYTE b3:1; + __EXTENSION BYTE b4:1; + __EXTENSION BYTE b5:1; + __EXTENSION BYTE b6:1; + __EXTENSION BYTE b7:1; + } bits; +} BYTE_VAL, BYTE_BITS; + +typedef union +{ + WORD Val; + BYTE v[2] __PACKED; + struct __PACKED + { + BYTE LB; + BYTE HB; + } byte; + struct __PACKED + { + __EXTENSION BYTE b0:1; + __EXTENSION BYTE b1:1; + __EXTENSION BYTE b2:1; + __EXTENSION BYTE b3:1; + __EXTENSION BYTE b4:1; + __EXTENSION BYTE b5:1; + __EXTENSION BYTE b6:1; + __EXTENSION BYTE b7:1; + __EXTENSION BYTE b8:1; + __EXTENSION BYTE b9:1; + __EXTENSION BYTE b10:1; + __EXTENSION BYTE b11:1; + __EXTENSION BYTE b12:1; + __EXTENSION BYTE b13:1; + __EXTENSION BYTE b14:1; + __EXTENSION BYTE b15:1; + } bits; +} WORD_VAL, WORD_BITS; + +typedef union +{ + DWORD Val; + WORD w[2] __PACKED; + BYTE v[4] __PACKED; + struct __PACKED + { + WORD LW; + WORD HW; + } word; + struct __PACKED + { + BYTE LB; + BYTE HB; + BYTE UB; + BYTE MB; + } byte; + struct __PACKED + { + WORD_VAL low; + WORD_VAL high; + }wordUnion; + struct __PACKED + { + __EXTENSION BYTE b0:1; + __EXTENSION BYTE b1:1; + __EXTENSION BYTE b2:1; + __EXTENSION BYTE b3:1; + __EXTENSION BYTE b4:1; + __EXTENSION BYTE b5:1; + __EXTENSION BYTE b6:1; + __EXTENSION BYTE b7:1; + __EXTENSION BYTE b8:1; + __EXTENSION BYTE b9:1; + __EXTENSION BYTE b10:1; + __EXTENSION BYTE b11:1; + __EXTENSION BYTE b12:1; + __EXTENSION BYTE b13:1; + __EXTENSION BYTE b14:1; + __EXTENSION BYTE b15:1; + __EXTENSION BYTE b16:1; + __EXTENSION BYTE b17:1; + __EXTENSION BYTE b18:1; + __EXTENSION BYTE b19:1; + __EXTENSION BYTE b20:1; + __EXTENSION BYTE b21:1; + __EXTENSION BYTE b22:1; + __EXTENSION BYTE b23:1; + __EXTENSION BYTE b24:1; + __EXTENSION BYTE b25:1; + __EXTENSION BYTE b26:1; + __EXTENSION BYTE b27:1; + __EXTENSION BYTE b28:1; + __EXTENSION BYTE b29:1; + __EXTENSION BYTE b30:1; + __EXTENSION BYTE b31:1; + } bits; +} DWORD_VAL; + +/* MPLAB C Compiler for PIC18 does not support 64-bit integers */ +/*typedef union +{ + QWORD Val; + DWORD d[2] __PACKED; + WORD w[4] __PACKED; + BYTE v[8] __PACKED; + struct __PACKED + { + DWORD LD; + DWORD HD; + } dword; + struct __PACKED + { + WORD LW; + WORD HW; + WORD UW; + WORD MW; + } word; + struct __PACKED + { + __EXTENSION BYTE b0:1; + __EXTENSION BYTE b1:1; + __EXTENSION BYTE b2:1; + __EXTENSION BYTE b3:1; + __EXTENSION BYTE b4:1; + __EXTENSION BYTE b5:1; + __EXTENSION BYTE b6:1; + __EXTENSION BYTE b7:1; + __EXTENSION BYTE b8:1; + __EXTENSION BYTE b9:1; + __EXTENSION BYTE b10:1; + __EXTENSION BYTE b11:1; + __EXTENSION BYTE b12:1; + __EXTENSION BYTE b13:1; + __EXTENSION BYTE b14:1; + __EXTENSION BYTE b15:1; + __EXTENSION BYTE b16:1; + __EXTENSION BYTE b17:1; + __EXTENSION BYTE b18:1; + __EXTENSION BYTE b19:1; + __EXTENSION BYTE b20:1; + __EXTENSION BYTE b21:1; + __EXTENSION BYTE b22:1; + __EXTENSION BYTE b23:1; + __EXTENSION BYTE b24:1; + __EXTENSION BYTE b25:1; + __EXTENSION BYTE b26:1; + __EXTENSION BYTE b27:1; + __EXTENSION BYTE b28:1; + __EXTENSION BYTE b29:1; + __EXTENSION BYTE b30:1; + __EXTENSION BYTE b31:1; + __EXTENSION BYTE b32:1; + __EXTENSION BYTE b33:1; + __EXTENSION BYTE b34:1; + __EXTENSION BYTE b35:1; + __EXTENSION BYTE b36:1; + __EXTENSION BYTE b37:1; + __EXTENSION BYTE b38:1; + __EXTENSION BYTE b39:1; + __EXTENSION BYTE b40:1; + __EXTENSION BYTE b41:1; + __EXTENSION BYTE b42:1; + __EXTENSION BYTE b43:1; + __EXTENSION BYTE b44:1; + __EXTENSION BYTE b45:1; + __EXTENSION BYTE b46:1; + __EXTENSION BYTE b47:1; + __EXTENSION BYTE b48:1; + __EXTENSION BYTE b49:1; + __EXTENSION BYTE b50:1; + __EXTENSION BYTE b51:1; + __EXTENSION BYTE b52:1; + __EXTENSION BYTE b53:1; + __EXTENSION BYTE b54:1; + __EXTENSION BYTE b55:1; + __EXTENSION BYTE b56:1; + __EXTENSION BYTE b57:1; + __EXTENSION BYTE b58:1; + __EXTENSION BYTE b59:1; + __EXTENSION BYTE b60:1; + __EXTENSION BYTE b61:1; + __EXTENSION BYTE b62:1; + __EXTENSION BYTE b63:1; + } bits; +} QWORD_VAL; +*/ +#undef __EXTENSION + +#ifndef uint24_t + #define uint24_t uint32_t +#endif + +typedef void(*pFunc)(void); + +typedef union _POINTER +{ + struct + { + BYTE bLow; + BYTE bHigh; + //BYTE bUpper; + }; + uint16_t _word; // bLow & bHigh + + //pFunc _pFunc; // Usage: ptr.pFunc(); Init: ptr.pFunc = &; + + BYTE* bRam; // Ram byte pointer: 2 bytes pointer pointing + // to 1 byte of data + uint16_t* wRam; // Ram word poitner: 2 bytes poitner pointing + // to 2 bytes of data + + ROM BYTE* bRom; // Size depends on compiler setting + ROM WORD* wRom; + //ROM near BYTE* nbRom; // Near = 2 bytes pointer + //ROM near uint16_t* nwRom; + //ROM far BYTE* fbRom; // Far = 3 bytes pointer + //ROM far uint16_t* fwRom; +} POINTER; + + +#endif /* __CUSTOMIZED_TYPE_DEFS_H_ */ diff --git a/bootloader_hacked_from_mla/src/usb.h b/bootloader_hacked_from_mla/src/usb.h new file mode 100644 index 0000000..b91d1fe --- /dev/null +++ b/bootloader_hacked_from_mla/src/usb.h @@ -0,0 +1,56 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +#ifndef USB_H +#define USB_H + +/* + * usb.h provides a centralize way to include all files + * required by Microchip USB Firmware. + * + * The order of inclusion is important. + * Dependency conflicts are resolved by the correct ordering. + */ + +#include "typedefs.h" +#include "usb_config.h" +#include "usb_device.h" +#include "HardwareProfile.h" + +#if defined(USB_USE_HID) // See usb_config.h +#include "usb_device_hid.h" +#endif + + +//These callback functions belong in your main.c (or equivalent) file. The USB +//stack will call these callback functions in response to specific USB bus events, +//such as entry into USB suspend mode, exit from USB suspend mode, and upon +//receiving the "set configuration" control tranfer request, which marks the end +//of the USB enumeration sequence and the start of normal application run mode (and +//where application related variables and endpoints may need to get (re)-initialized. +void USBCBSuspend(void); +void USBCBWakeFromSuspend(void); +void USBCBInitEP(uint8_t ConfigurationIndex); +void USBCBCheckOtherReq(void); + + +//API renaming wrapper functions +#define HIDTxHandleBusy(a) {mHIDTxIsBusy()} +#define HIDRxHandleBusy(a) {mHIDRxIsBusy()} + +#endif //USB_H diff --git a/bootloader_hacked_from_mla/src/usb_config.h b/bootloader_hacked_from_mla/src/usb_config.h new file mode 100644 index 0000000..02965f7 --- /dev/null +++ b/bootloader_hacked_from_mla/src/usb_config.h @@ -0,0 +1,74 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +#ifndef USBCFG_H +#define USBCFG_H + +//---------------------------------------------------------------------------------------------------------- +//User configurable options +//---------------------------------------------------------------------------------------------------------- + +//When defined/enabled, this option allows the boot up code to check an I/O pin +//(as defined by the sw2() macro in HardwareProfile.h), and if logic low, execution +//stays within the bootloader, allowing the user to update the firmware. If this +//option is not enabled, then the only method of entering the bootloader will +//be from the application firmware project, by executing a goto 0x001C operation. +//Enabling the I/O pin to enter the bootloader is recommended, since it is more +//robust/recoverable (compared to software only entry into the bootloader), in +//the event of a failed erase/program/verify operation, or an otherwise corrupted +//application firmware image is loaded. +#define ENABLE_IO_PIN_CHECK_BOOTLOADER_ENTRY //Uncomment if you wish to enable I/O pin entry method into bootloader mode + //Make sure proper sw2() macro definition is provided in HardwareProfile.h + +//---------------------------------------------------------------------------------------------------------- +//Other semi-configurable settings that tell the USB stack how to operate (but usually don't need changing) +//---------------------------------------------------------------------------------------------------------- +#define MAX_EP_NUMBER 1 // EP0 and EP1 are the only EPs used in this application +#define MAX_NUM_INT 1 // For tracking Alternate Setting - make sure this matches the number of interfaces implemented in the device +#define EP0_BUFF_SIZE 8 // Valid Options: 8, 16, 32, or 64 bytes. + // There is little advantage in using + // more than 8 bytes on EP0 IN/OUT in most cases. +#define USB_MAX_NUM_CONFIG_DSC 1 // Number of configurations that this firmware implements +//#define ENABLE_CONTROL_TRANSFERS_WITH_OUT_DATA_STAGE //Commented out to save code size, since this bootloader firmware doesn't use OUT control transfers with data stage + + +#define CONFIG_DESC_TOTAL_LEN 41 //Make sure this matches the size of your configuration descriptor + all subordinate + //descriptors returned by the get descriptor(configuration) request + +/* Parameter definitions are defined in usb_device.h */ +#define MODE_PP _PPBM1 //This code is only written to support _PPBM1 mode only (ping pong on EP0 OUT buffer only). Do not change. +#define UCFG_VAL _PUEN|_TRINT|_FS|MODE_PP + +//Device class and endpoint definitions +#define USB_USE_HID + +/* HID */ +#define HID_INTF_ID 0x00 +#define HID_UEP UEP1 +#define HID_BD_OUT ep1Bo +#define HID_INT_OUT_EP_SIZE 64 +#define HID_BD_IN ep1Bi +#define HID_INT_IN_EP_SIZE 64 +#define HID_NUM_OF_DSC 1 //Just the Report descriptor (no physical descriptor present) +#define HID_RPT01_SIZE 29 //Make sure this matches the size of your HID report descriptor + + + + +#endif //USBCFG_H diff --git a/bootloader_hacked_from_mla/src/usb_descriptors.c b/bootloader_hacked_from_mla/src/usb_descriptors.c new file mode 100644 index 0000000..e4018e4 --- /dev/null +++ b/bootloader_hacked_from_mla/src/usb_descriptors.c @@ -0,0 +1,282 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +/********************************************************************* + * -usb_descriptors.c- + * This file contains the USB descriptor information. It is used + * in conjunction with the usb_descriptors.h file. When a descriptor is added + * or removed from the main configuration descriptor, i.e. CFG01, + * the user must also change the descriptor structure defined in + * the usb_descriptors.h file. The structure is used to calculate the + * descriptor size, i.e. sizeof(CFG01). + * + * A typical configuration descriptor consists of: + * At least one configuration descriptor (USB_CFG_DSC) + * One or more interface descriptors (USB_INTF_DSC) + * One or more endpoint descriptors (USB_EP_DSC) + * + * Naming Convention: + * To resolve ambiguity, the naming convention are as followed: + * - USB_CFG_DSC type should be named cdxx, where xx is the + * configuration number. This number should match the actual + * index value of this configuration. + * - USB_INTF_DSC type should be named ia, where yy is the + * interface number and zz is the alternate interface number. + * - USB_EP_DSC type should be named ep<##>_ia, where + * ## is the endpoint number and d is the direction of transfer. + * The interface name should also be listed as a suffix to identify + * which interface does the endpoint belong to. + * + * Example: + * If a device has one configuration, two interfaces; interface 0 + * has two endpoints (in and out), and interface 1 has one endpoint(in). + * Then the CFG01 structure in the usb_descriptors.h should be: + * + * #define CFG01 ROM struct \ + * { USB_CFG_DSC cd01; \ + * USB_INTF_DSC i00a00; \ + * USB_EP_DSC ep01o_i00a00; \ + * USB_EP_DSC ep01i_i00a00; \ + * USB_INTF_DSC i01a00; \ + * USB_EP_DSC ep02i_i01a00; \ + * } cfg01 + * + * Note the hierarchy of the descriptors above, it follows the USB + * specification requirement. All endpoints belonging to an interface + * should be listed immediately after that interface. + * + * ------------------------------------------------------------------- + * Filling in the descriptor values in the usb_descriptors.c file: + * ------------------------------------------------------------------- + * Most items should be self-explanatory, however, a few will be + * explained for clarification. + * + * [Configuration Descriptor(USB_CFG_DSC)] + * The configuration attribute must always have the _DEFAULT + * definition at the minimum. Additional options can be ORed + * to the _DEFAULT attribute. Available options are _SELF and _RWU. + * These definitions are defined in the usb_device.h file. The + * _SELF tells the USB host that this device is self-powered. The + * _RWU tells the USB host that this device supports Remote Wakeup. + * + * [Endpoint Descriptor(USB_EP_DSC)] + * Assume the following example: + * sizeof(USB_EP_DSC),DSC_EP,_EP01_OUT,_BULK,64,0x00 + * + * The first two parameters are self-explanatory. They specify the + * length of this endpoint descriptor (7) and the descriptor type. + * The next parameter identifies the endpoint, the definitions are + * defined in usb_device.h and has the following naming + * convention: + * _EP<##>_ + * where ## is the endpoint number and dir is the direction of + * transfer. The dir has the value of either 'OUT' or 'IN'. + * The next parameter identifies the type of the endpoint. Available + * options are _BULK, _INT, _ISO, and _CTRL. The _CTRL is not + * typically used because the default control transfer endpoint is + * not defined in the USB descriptors. When _ISO option is used, + * addition options can be ORed to _ISO. Example: + * _ISO|_AD|_FE + * This describes the endpoint as an isochronous pipe with adaptive + * and feedback attributes. See usb_device.h and the USB + * specification for details. The next parameter defines the size of + * the endpoint. The last parameter in the polling interval. + * + * ------------------------------------------------------------------- + * Adding a USB String + * ------------------------------------------------------------------- + * A string descriptor array should have the following format: + * + * ROM struct{uint8_t bLength;uint8_t bDscType;uint16_t string[size];}sdxxx={ + * sizeof(sdxxx),DSC_STR,}; + * + * The above structure provides a means for the C compiler to + * calculate the length of string descriptor sdxxx, where xxx is the + * index number. The first two bytes of the descriptor are descriptor + * length and type. The rest are string texts which must be + * in the unicode format. The unicode format is achieved by declaring + * each character as a word type. The whole text string is declared + * as a word array with the number of characters equals to . + * has to be manually counted and entered into the array + * declaration. Let's study this through an example: + * if the string is "USB" , then the string descriptor should be: + * (Using index 02) + * ROM struct{byte bLength;uint8_t bDscType;uint16_t string[3];}sd002={ + * sizeof(sd002),DSC_STR,'U','S','B'}; + * + * A USB project may have multiple strings and the firmware supports + * the management of multiple strings through a look-up table. + * The look-up table is defined as: + * ROM const unsigned char *ROM USB_SD_Ptr[]={&sd000,&sd001,&sd002}; + * + * The above declaration has 3 strings, sd000, sd001, and sd002. + * Strings can be removed or added. sd000 is a specialized string + * descriptor. It defines the language code, usually this is + * US English (0x0409). The index of the string must match the index + * position of the USB_SD_Ptr array, &sd000 must be in position + * USB_SD_Ptr[0], &sd001 must be in position USB_SD_Ptr[1] and so on. + * The look-up table USB_SD_Ptr is used by the get string handler + * function in usb9.c. + * + * ------------------------------------------------------------------- + * + * The look-up table scheme also applies to the configuration + * descriptor. A USB device may have multiple configuration + * descriptors, i.e. CFG01, CFG02, etc. To add a configuration + * descriptor, user must implement a structure similar to CFG01. + * The next step is to add the configuration descriptor name, i.e. + * cfg01, cfg02,.., to the look-up table USB_CD_Ptr. USB_CD_Ptr[0] + * is a dummy place holder since configuration 0 is the un-configured + * state according to the definition in the USB specification. + * + ********************************************************************/ + + + +/** I N C L U D E S *************************************************/ +#include "usb.h" + + +/** C O N S T A N T S ************************************************/ +#ifndef __XC8__ +#pragma romdata +#endif + +/* Device Descriptor */ +ROM USB_DEV_DSC device_dsc= +{ + sizeof(USB_DEV_DSC), // Size of this descriptor in bytes + DSC_DEV, // DEVICE descriptor type + 0x0200, // USB Spec Release Number in BCD format + 0x00, // Class Code + 0x00, // Subclass code + 0x00, // Protocol code + EP0_BUFF_SIZE, // Max packet size for EP0, see usb_config.h + 0x04D8, // Vendor ID: Microchip + 0x003C, // Product ID: HID Bootloader + 0x0101, // Device release number in BCD format + 0x01, // Manufacturer string index + 0x02, // Product string index + 0x00, // Device serial number string index + 0x01 // Number of possible configurations +}; + +/* Configuration 1 Descriptors */ +ROM uint8_t CFG01[CONFIG_DESC_TOTAL_LEN]={ + /* Configuration Descriptor */ + sizeof(USB_CFG_DSC), // Size of this descriptor in bytes + DSC_CFG, // CONFIGURATION descriptor type + (uint8_t)CONFIG_DESC_TOTAL_LEN, // Total length of data for this cfg - LSB + (uint8_t)(CONFIG_DESC_TOTAL_LEN>>8), // Total length of data for this cfg - MSB + 1, // Number of interfaces in this cfg + 1, // Index value of this configuration + 0, // Configuration string index + _DEFAULT, // Attributes, see usb_device.h + 50, // Max power consumption (2X mA) + + /* Interface Descriptor */ + sizeof(USB_INTF_DSC), // Size of this descriptor in bytes + DSC_INTF, // INTERFACE descriptor type + 0, // Interface Number + 0, // Alternate Setting Number + 2, // Number of endpoints in this intf + HID_INTF, // Class code + 0, // Subclass code, no subclass + 0, // Protocol code, no protocol + 0, // Interface string index + + /* HID Class-Specific Descriptor */ + sizeof(USB_HID_DSC), // Size of this descriptor in bytes + DSC_HID, // HID descriptor type + 0x11, // HID Spec Release Number in BCD format (0x0111 = v1.11) - LSB + 0x01, // HID Spec Release Number in BCD format (0x0111 = v1.11) - MSB + 0x00, // Country Code (0x00 for Not supported) + HID_NUM_OF_DSC, // Number of class descriptors, see usb_config.h + DSC_RPT, // Report descriptor type + (uint8_t)HID_RPT01_SIZE, // Size of the report descriptor - LSB + (uint8_t)((uint16_t)HID_RPT01_SIZE >> 8), // Size of the report descriptor - MSB + + /* Endpoint Descriptor */ + sizeof(USB_EP_DSC), //Endpoint descriptor size + DSC_EP, //Type of descriptor (endpoint) + _EP01_IN, //Endpoint number + direction + _INT, //Endpoint transfer type implemented + HID_INT_IN_EP_SIZE, //LSB - endpoint size + 0x00, //MSB - endpoint size + 0x01, //bInterval + + /* Endpoint Descriptor */ + sizeof(USB_EP_DSC), //Endpoint descriptor size + DSC_EP, //Type of descriptor (endpoint) + _EP01_OUT, //Endpoint number + direction + _INT, //Endpoint transfer type implemented + HID_INT_OUT_EP_SIZE, //LSB - endpoint size + 0x00, //MSB - endpoint size + 0x01 //bInterval +}; + +ROM struct{uint8_t bLength;uint8_t bDscType;uint16_t string[1];}sd000={ +sizeof(sd000),DSC_STR,0x0409}; + +ROM struct{uint8_t bLength;uint8_t bDscType;uint16_t string[25];}sd001={ +sizeof(sd001),DSC_STR, +'M','i','c','r','o','c','h','i','p',' ', +'T','e','c','h','n','o','l','o','g','y',' ','I','n','c','.'}; + +ROM struct{uint8_t bLength;uint8_t bDscType;uint16_t string[18];}sd002={ +sizeof(sd002),DSC_STR, +'H','I','D',' ','U','S','B',' ','B','o','o', +'t','l','o','a','d','e','r'}; + +ROM uint8_t hid_rpt01[HID_RPT01_SIZE]= +// First byte in each row is the "item". First byte's two least significant +// bits are the number of data bytes that follow, but encoded (0=0, 1=1, 2=2, 3=4 bytes). +// bSize should match number of bytes that follow, or REPORT descriptor parser won't work. The bytes +// that follow in each item line are data bytes +{ + 0x06, 0x00, 0xFF, // Usage Page = 0xFF00 (Vendor Defined Page 1) + 0x09, 0x01, // Usage (Vendor Usage 1) + 0xA1, 0x01, // Collection (Application) + 0x19, 0x01, // Usage Minimum + 0x29, 0x40, // Usage Maximum //64 input usages total (0x01 to 0x40) + 0x15, 0x00, // Logical Minimum (data bytes in the report may have minimum value = 0x00) + 0x26, 0xFF, 0x00, // Logical Maximum (data bytes in the report may have maximum value = 0x00FF = unsigned 255) + 0x75, 0x08, // Report Size: 8-bit field size + 0x95, 0x40, // Report Count: Make sixty-four 8-bit fields (the next time the parser hits an "Input", "Output", or "Feature" item) + 0x81, 0x00, // Input (Data, Array, Abs): Instantiates input packet fields based on the above report size, count, logical min/max, and usage. + 0x19, 0x01, // Usage Minimum + 0x29, 0x40, // Usage Maximum //64 output usages total (0x01 to 0x40) + 0x91, 0x00, // Output (Data, Array, Abs): Instantiates output packet fields. Uses same report size and count as "Input" fields, since nothing new/different was specified to the parser since the "Input" item. + 0xC0 // End Collection +}; + + +ROM unsigned char* ROM USB_SD_Ptr[]= +{ + (ROM const unsigned char *ROM)&sd000, + (ROM const unsigned char *ROM)&sd001, + (ROM const unsigned char *ROM)&sd002 +}; + + +#ifndef __XC8__ +#pragma code +#endif + +/** EOF usb_descriptors.c ****************************************************/ diff --git a/bootloader_hacked_from_mla/src/usb_device.c b/bootloader_hacked_from_mla/src/usb_device.c new file mode 100644 index 0000000..6bc8ebd --- /dev/null +++ b/bootloader_hacked_from_mla/src/usb_device.c @@ -0,0 +1,1626 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +/** I N C L U D E S **********************************************************/ +#include "usb.h" +#include "HardwareProfile.h" // Required for USBCheckBusStatus() + + +//Private prototypes (see usb_device.h for public API functions exposed by the USB stack) +void USBCheckStdRequest(void); +void USBSuspend(void); +void USBProtocolResetHandler(void); +void USBWakeFromSuspend(void); +void USBStdGetDscHandler(void); +void USBStdSetCfgHandler(void); +void USBStdGetStatusHandler(void); +void USBStdFeatureReqHandler(void); +void USBCtrlTrfSetupHandler(void); +void USBCtrlTrfInHandler(void); +void USBCtrlTrfTxService(void); +void USBCtrlEPServiceComplete(void); +void LoadBDTandSetUOWN(uint8_t BDTIndexToLoad); +#if !defined(ENABLE_CONTROL_TRANSFERS_WITH_OUT_DATA_STAGE) +#define USBCtrlTrfOutHandler(a) +#endif + + + +/** V A R I A B L E S ********************************************************/ +#ifndef __XC8__ +#pragma udata +#endif +uint8_t bTRNIFCount; +uint8_t ctrl_trf_state; // Control Transfer State +uint8_t ctrl_trf_session_owner; // Current transfer session owner +POINTER pSrc; // Data source pointer +POINTER pDst; // Data destination pointer +WORD_VAL wCount; // Data counter +uint8_t short_pkt_status; // Flag used by Control Transfer Read +CTRL_TRF_SETUP SetupPkt; +bool EP0OutOddNeedsArmingNext; +BDT TempBDT; +uint8_t usb_device_state; // Device States: DETACHED, ATTACHED, ... +USB_DEVICE_STATUS usb_stat; // Global USB flags (remote wakeup armed status, etc.) +uint8_t usb_active_cfg; // Value of current configuration +uint8_t usb_alt_intf[MAX_NUM_INT]; // Array to keep track of the current alternate + // setting for each interface ID + +#ifdef __XC8__ + #pragma warning disable 1090 //Disable unused variable warning. USTATSave may not be used, depending upon user settings, but that is okay/harmless/expected. +#endif +uint8_t USTATSave; +uint16_t Counter; +bool DeviceIsSoftDetached; + +/** USB FIXED LOCATION VARIABLES ***********************************/ +#if defined(__18F14K50) || defined(__18F13K50) || defined(__18LF14K50) || defined(__18LF13K50) + #define BDT_ADDR 0x200 //BDT in bank 2 on these devices +#elif defined(__18F47J53) || defined(__18F46J53) || defined(__18F27J53) || defined(__18F26J53) || defined(__18LF47J53) || defined(__18LF46J53) || defined(__18LF27J53) || defined(__18LF26J53) + #define BDT_ADDR 0xD00 //BDT in Bank 13 on these devices +#elif defined(__18F97J94) || defined(__18F87J94) || defined(__18F67J94) || defined(__18F96J99) || defined(__18F86J99) || defined(__18F66J99) || defined(__18F96J94) || defined(__18F86J94) || defined(__18F66J94) || defined(__18F95J94) || defined(__18F85J94) || defined(__18F65J94) + #define BDT_ADDR 0x100 // The USB BDT is located in Bank 1 on the PIC18F97J94 Family of devices +#elif defined(__16F1459) || defined(__16LF1459) || defined(__16F1455) || defined(__16LF1455) || defined(__16F1454) || defined(__16LF1454) + #define BDT_ADDR 0x20 + #define USB_RAM_BUFF_ADDR 0x40 //EP0 OUT and IN buffers + #define USB_HID_BUFF_OUT_ADDR @0xA0 + #define USB_HID_BUFF_IN_ADDR @0x120 +#else + //Most other PIC18 USB families use bank 4 for the BDT (ex: PIC18F46J50 family, PIC18F87J50 family, PIC18F4550/3 family, etc.) + #define BDT_ADDR 0x400 +#endif + +#ifndef __XC8__ + #pragma udata USB_BDT = BDT_ADDR +#else + #ifndef USB_RAM_BUFF_ADDR + #define USB_RAM_BUFF_ADDR (BDT_ADDR + 12 + (MAX_EP_NUMBER * 8)) + #endif +#endif + +/****************************************************************************** + * Section A: Buffer Descriptor Table - must be allocated by the linker to the + * correct address that the hardware USB module DMA engine will be looking at. + * - 0xX00 - 0xXFF( 256 bytes max) + * - MAX_EP_NUMBER is defined in usb_config.h + * - BDT data type is defined in usb_device.h + *****************************************************************************/ +#ifdef __XC8__ + #define BDT_ADDR_TAG @BDT_ADDR + #define BDT_ADDR_TAG_EP0O_EVEN @BDT_ADDR + #define BDT_ADDR_TAG_EP0O_ODD BDT_ADDR_TAG_EP0O_EVEN+4 + #define BDT_ADDR_TAG_EP0I BDT_ADDR_TAG+8 + #define BDT_ADDR_TAG_EP1O BDT_ADDR_TAG+12 + #define BDT_ADDR_TAG_EP1I BDT_ADDR_TAG+16 + #define USB_EP0_BUFF_ADDR @USB_RAM_BUFF_ADDR + #define USB_EP0_BUFF_ADDR2 USB_EP0_BUFF_ADDR+EP0_BUFF_SIZE + #define USB_CTRL_TRF_DATA_ADDR USB_EP0_BUFF_ADDR2+EP0_BUFF_SIZE + #if defined(USB_USE_HID) + #ifndef USB_HID_BUFF_OUT_ADDR + #define USB_HID_BUFF_OUT_ADDR USB_CTRL_TRF_DATA_ADDR+EP0_BUFF_SIZE + #define USB_HID_BUFF_IN_ADDR USB_HID_BUFF_OUT_ADDR+HID_INT_OUT_EP_SIZE + #endif + #endif +#else + //Else must be using the C18 compiler. The C18 compiler puts things in + //consecutive order with a udata section, so no explicit addresses for + //each BDT/buffer is needed, provided the variables go into the correct + //udata section (with the right start address of the BDT). + #define BDT_ADDR_TAG + #define BDT_ADDR_TAG_EP0O_EVEN + #define BDT_ADDR_TAG_EP0O_ODD + #define BDT_ADDR_TAG_EP0I + #define BDT_ADDR_TAG_EP1O + #define BDT_ADDR_TAG_EP1I + #define USB_EP0_BUFF_ADDR + #define USB_EP0_BUFF_ADDR2 + #define USB_CTRL_TRF_DATA_ADDR + #define USB_HID_BUFF_OUT_ADDR + #define USB_HID_BUFF_IN_ADDR +#endif + +#if(0 <= MAX_EP_NUMBER) +volatile BDT ep0BoEven BDT_ADDR_TAG_EP0O_EVEN; //Endpoint #0 BD Out EVEN +volatile BDT ep0BoOdd BDT_ADDR_TAG_EP0O_ODD; //Endpoint #0 BD Out ODD +volatile BDT ep0Bi BDT_ADDR_TAG_EP0I; //Endpoint #0 BD In +#endif + +#if(1 <= MAX_EP_NUMBER) +volatile BDT ep1Bo BDT_ADDR_TAG_EP1O; //Endpoint #1 BD Out +volatile BDT ep1Bi BDT_ADDR_TAG_EP1I; //Endpoint #1 BD In +#endif + +#if(2 <= MAX_EP_NUMBER) +volatile BDT ep2Bo; //Endpoint #2 BD Out +volatile BDT ep2Bi; //Endpoint #2 BD In +#endif + +#if(3 <= MAX_EP_NUMBER) +volatile BDT ep3Bo; //Endpoint #3 BD Out +volatile BDT ep3Bi; //Endpoint #3 BD In +#endif + +#if(4 <= MAX_EP_NUMBER) +volatile BDT ep4Bo; //Endpoint #4 BD Out +volatile BDT ep4Bi; //Endpoint #4 BD In +#endif + +#if(5 <= MAX_EP_NUMBER) +volatile far BDT ep5Bo; //Endpoint #5 BD Out +volatile far BDT ep5Bi; //Endpoint #5 BD In +#endif + +#if(6 <= MAX_EP_NUMBER) +volatile far BDT ep6Bo; //Endpoint #6 BD Out +volatile far BDT ep6Bi; //Endpoint #6 BD In +#endif + +#if(7 <= MAX_EP_NUMBER) +volatile far BDT ep7Bo; //Endpoint #7 BD Out +volatile far BDT ep7Bi; //Endpoint #7 BD In +#endif + +#if(8 <= MAX_EP_NUMBER) +volatile far BDT ep8Bo; //Endpoint #8 BD Out +volatile far BDT ep8Bi; //Endpoint #8 BD In +#endif + +#if(9 <= MAX_EP_NUMBER) +volatile far BDT ep9Bo; //Endpoint #9 BD Out +volatile far BDT ep9Bi; //Endpoint #9 BD In +#endif + +#if(10 <= MAX_EP_NUMBER) +volatile far BDT ep10Bo; //Endpoint #10 BD Out +volatile far BDT ep10Bi; //Endpoint #10 BD In +#endif + +#if(11 <= MAX_EP_NUMBER) +volatile far BDT ep11Bo; //Endpoint #11 BD Out +volatile far BDT ep11Bi; //Endpoint #11 BD In +#endif + +#if(12 <= MAX_EP_NUMBER) +volatile far BDT ep12Bo; //Endpoint #12 BD Out +volatile far BDT ep12Bi; //Endpoint #12 BD In +#endif + +#if(13 <= MAX_EP_NUMBER) +volatile far BDT ep13Bo; //Endpoint #13 BD Out +volatile far BDT ep13Bi; //Endpoint #13 BD In +#endif + +#if(14 <= MAX_EP_NUMBER) +volatile far BDT ep14Bo; //Endpoint #14 BD Out +volatile far BDT ep14Bi; //Endpoint #14 BD In +#endif + +#if(15 <= MAX_EP_NUMBER) +volatile far BDT ep15Bo; //Endpoint #15 BD Out +volatile far BDT ep15Bi; //Endpoint #15 BD In +#endif + +/****************************************************************************** + * Section B: EP0 endpoint data buffer space - must be located in USB module + * accessible RAM region + *****************************************************************************/ +volatile uint8_t EP0OutEvenBuf[EP0_BUFF_SIZE] USB_EP0_BUFF_ADDR; +volatile uint8_t EP0OutOddBuf[EP0_BUFF_SIZE] USB_EP0_BUFF_ADDR2; +volatile CTRL_TRF_DATA CtrlTrfData USB_CTRL_TRF_DATA_ADDR; + +/****************************************************************************** + * Section C: HID application interrupt endpoint buffers - must be located in + * USB module accessible RAM region + *****************************************************************************/ +#if defined(USB_USE_HID) +volatile unsigned char hid_report_out[HID_INT_OUT_EP_SIZE] USB_HID_BUFF_OUT_ADDR; +volatile unsigned char hid_report_in[HID_INT_IN_EP_SIZE] USB_HID_BUFF_IN_ADDR; +#endif + +#ifndef __XC8__ +#pragma udata +#endif + + + +//If the user is not using an I/O pin for USB +5V VBUS presence detection (ex: because +//they are using a bus powered only application), default to assuming that VBUS +//is effectively always present (which is true for bus powered only applications). +#if !defined(USE_USB_BUS_SENSE_IO) + #define usb_bus_sense 1 +#endif + +//If the user is not using an I/O pin for self powered detection (ex: because +//the application is bus powered only or is dual self/bus powered but uses less +//than 100mA max from VBUS), default to assuming that the device is currently bus +//powered. +#if !defined(USE_SELF_POWER_SENSE_IO) + #define self_power 0 +#endif + +//Most applications only implement one configuration descriptor. If the application +//does use more than one, make sure the USB_MAX_NUM_CONFIG_DSC is set to the value +//actually implemented. Needed for error checking of host requests, to make sure +//they are in bounds/have a legal index. +#if !defined(USB_MAX_NUM_CONFIG_DSC) + #define USB_MAX_NUM_CONFIG_DSC 1 +#endif + + + +/** D E C L A R A T I O N S **************************************************/ +#ifndef __XC8__ +#pragma code +#endif + + +/****************************************************************************** + * Function: void USBDeviceInit(void) + * + * PreCondition: User application code is responsible for making sure the + * currently selected oscillator settings are compatible with + * USB operation, prior to calling this function. The user + * application code must also initialize the VBUS sensing I/O + * pin before calling this code, if it uses VBUS sensing + * (only needed in self powered applications). + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine initializes the USB stack state machine + * and turns on the USB module. It should be called only + * once during bootup of the application code. + * + * Note: None + *****************************************************************************/ +void USBDeviceInit(void) +{ + //Check if the USB module is already enabled. If so, disable it and wait + //~100ms+ (>1 second recommended if CDC application firmware on XP), to + //ensure that the host has a chance to see and process the USB device detach + //event. + if(UCONbits.USBEN == 1) + { + //USB module was already on. This is likely because the user applicaiton + //firmware jumped into this bootloader firmware using the absolute + //software entry method, without first turning off the USB module + USBDisableWithLongDelay(); + } + DeviceIsSoftDetached = FALSE; + + //Make initial call to USBCheckBusStatus() which will either do nothing (if + //VBUS is not present), or, will totally re-init everything and perform + //a soft attach event (if VBUS is present, or the user doesn't use + //VBUS sense I/O in their application). Either way, everything gets + //totally re-initialized either now, or in the future, once VBUS 0->1 transition + //is detected. + USBCheckBusStatus(); +} + + +//Turns on the USB module and attaches to the host. Normally, this function should +//only be called after you are already sure that VBUS is present/the USB cable +//is attached to a powered host. +void USBSoftAttach(void) +{ + //Check if we are transitioning from deliberate soft detached to attached + //state. If so, need to delay a relatively long time (ex: 100ms+) to ensure + //enough detached dwell time is met, to ensure the host correctly detects + //the detach/reattach event (very short detachment less than possible via + //a human unplug/reattachment event can sometimes be misprocessed by the host). + if(DeviceIsSoftDetached == TRUE) + { + USBDisableWithLongDelay(); + } + //(Re-)initialize registers and turn on the USB module + UCON = 0; + UCFG = UCFG_VAL; + UIE = 0; + UCONbits.USBEN = 1; + //(Re-)initialize various USB stack variables and other things + USBProtocolResetHandler(); + usb_device_state = ATTACHED_STATE; + DeviceIsSoftDetached = FALSE; +} + +//Disables the USB module and performs a soft detach from the USB host, regardless +//of the detected VBUS status. However, if you call this function, and you are +//not using VBUS I/O sensing in your application you must stop calling USBCheckBusStatus(), +//since it will promptly try to re-enable the USB module. +void USBSoftDetach(void) +{ + //Disable USB module (this doesn't need to be done in the loop, but we + //add it to the loop to deliberately make the loop execute slower) + UCONbits.SUSPND = 0; + UCON = 0x00; //Disable module + usb_device_state = DETACHED_STATE; + DeviceIsSoftDetached = TRUE; +} + +/****************************************************************************** + * Function: void USBCheckBusStatus(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine enables/disables the USB module by monitoring + * the USB power signal. + * + * Note: None + *****************************************************************************/ +void USBCheckBusStatus(void) +{ + //Check if the user's firmware deliberately soft detached from the host. + //If so, don't automatically try to reconnect, until the user subsequently + //calls the USBSoftAttach() API. + if(DeviceIsSoftDetached == TRUE) + { + return; + } + + /************************************************************************** + * Bus Attachment & Detachment Detection + * usb_bus_sense is an i/o pin defined in HardwareProfile.h + *************************************************************************/ + #define USB_BUS_ATTACHED 1 + #define USB_BUS_DETACHED 0 + + #ifdef USE_USB_BUS_SENSE_IO + if(usb_bus_sense == USB_BUS_ATTACHED) // Is USB bus attached? + { + if(UCONbits.USBEN == 0) // Is the module off? + { + USBSoftAttach(); // Is off, enable it + } + } + else + { + if(UCONbits.USBEN == 1) // Is the module on? + { + USBSoftDetach(); + DeviceIsSoftDetached = FALSE; + } + }//end if(usb_bus_sense...) + #else + if(UCONbits.USBEN == 0) // Is the module off? + USBSoftAttach(); // Is off, enable it + #endif +}//end USBCheckBusStatus + + + + + + + +/****************************************************************************** + * Function: void USBDeviceTasks(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine is the heart of this firmware. It manages + * all USB interrupts/events that need processing. + * + * Note: Device state transitions through the following stages: + * DETACHED -> ATTACHED -> POWERED -> DEFAULT -> + * ADDRESS_PENDING -> ADDRESSED -> CONFIGURED. Once in the + * CONFIGURED state the application is ready to run. Only + * in the CONFIGURED state should the host try to send/receive + * packets on the application endpoints (ex: endpoints > 0). + *****************************************************************************/ +void USBDeviceTasks(void) +{ + static volatile BDT* pBDTEntry; + static uint8_t i; + + //Check for possible changes in VBUS (USB connection) status. + USBCheckBusStatus(); + + /* + * Pointless to continue servicing if USB cable is not even attached. + */ + if(usb_device_state == DETACHED_STATE) return; + + /* + * Task A: Service USB Activity Interrupt + */ + + if(UIRbits.ACTVIF) USBWakeFromSuspend(); + + /* + * Pointless to continue servicing if the device is in suspend mode. + */ + if(UCONbits.SUSPND == 1) return; + + /* + * Task B: Service USB Bus Reset Interrupt. + * When bus reset is received during suspend, ACTVIF will be set first, + * once the UCONbits.SUSPND is clear, then the URSTIF bit will be asserted. + * This is why URSTIF is checked after ACTVIF. + */ + if(UIRbits.URSTIF) USBProtocolResetHandler(); + + /* + * Task C: Service other USB interrupts + */ + if(UIRbits.IDLEIF) USBSuspend(); + + //Don't need to actually do anything for SOF packets (except in isochronous devices) + //if(UIRbits.SOFIF && UIEbits.SOFIE) USB_SOF_Handler(); + + //Don't need to actually do anything for STALL packets being sent. For stalls + //on EP0, the host is required to send a new SETUP packet, which the hardware + //accepts (even if the BSTALL bit is set), as STALL is not a valid response to a + //SETUP packet. + //if(UIRbits.STALLIF) USBStallHandler(); + + + /* + * Pointless to continue servicing if the host has not sent a bus reset. + * Once bus reset is received, the device transitions into the DEFAULT + * state and is ready for communication. + */ + if(usb_device_state < DEFAULT_STATE) return; + + /* + * Task D: Servicing USB Transaction Complete Interrupt + */ + for(bTRNIFCount = 0; bTRNIFCount < 4; bTRNIFCount++) + { + if(UIRbits.TRNIF) + { + //Check what endpoint and direction the last packet was sent or received on. + USTATSave = USTAT; //AND out any bits other than EP dir + num + ping pong dest + if((USTAT & 0x7C) == EP00_OUT) + { + //Check if it was even or odd EP0 OUT buffer + if(USTATbits.PPBI == 0) + { + //The OUT or SETUP packet arrived on EP0 OUT EVEN endpoint + pBDTEntry = &ep0BoEven; + } + else + { + //The OUT or SETUP packet arrived on EP0 OUT ODD endpoint + pBDTEntry = &ep0BoOdd; + } + + //Allow USTAT FIFO to advance, done with the value + UIRbits.TRNIF = 0; + + //Check if the current EP0 OUT buffer has a SETUP packet (or a regular OUT instead) + if(pBDTEntry->Stat.PID == SETUP_TOKEN) + { + //Copy the 8 bytes of packet data that arrived for the SETUP transaction + //from the USB endpoint buffer, into the global SetupPkt buffer. + for(i = 0; i < sizeof(CTRL_TRF_SETUP); i++) + { + SetupPkt._byte[i] = *pBDTEntry->ADR++; + } + + //Handle the control transfer (parse the 8-byte SETUP command and + //figure out what to do with the host's request) + USBCtrlTrfSetupHandler(); + } + else + { + //Handle the conventional OUT DATA packet the just arrived from the host + USBCtrlTrfOutHandler(USTATSave); + } + } + else if(USTAT == EP00_IN) // EP0 IN + { + //A packet just got sent to the host over the EP0 IN endpoint + UIRbits.TRNIF = 0; + USBCtrlTrfInHandler(); //Figure out what to do now (ex: such as preparing the next IN data packet in the sequence) + } + else + { + //The last packet sent or received was on EP1 or higher. In this + //case the USB stack doesn't need to handle anything, since the + //user's application code is responsible for checking status/arming + //the applicaiton endpoints + UIRbits.TRNIF = 0; //Just clear TRNIF to advance the USTAT FIFO. + } + }//if(UIRbits.TRNIF) + else + { + break; + } + }// end for(bTRNIFCount = 0; bTRNIFCount < 4; bTRNIFCount++) + +}//end USBDeviceTasks() + +/****************************************************************************** + * Function: void USBSuspend(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: When the USB host sends USB suspend signalling, this function + * gets called. In order to be USB compliant, the device + * firmware should configure the application so that it takes + * no more than 2.5mA from the +5VBus supply from the + * USB port during USB suspend events. Bus powered devices can + * meet this by suspending the USB module, and either clock switching + * to a low frequency or sleeping. This is not necessary if the + * application is self powered, or if it doesn't need to meet + * all USB compliance requirements. + * + * Note: None + *****************************************************************************/ +void USBSuspend(void) +{ + static unsigned char UIESave; + #if defined(_PIC14E) + static unsigned char INTCONSave; + #endif + + /* + * NOTE: Do not clear UIRbits.ACTVIF here! + * Reason: + * ACTVIF is only generated once an IDLEIF has been generated. + * This is a 1:1 ratio interrupt generation. + * For every IDLEIF, there will be only one ACTVIF regardless of + * the number of subsequent bus transitions. + * + * If the ACTIF is cleared here, a problem could occur when: + * [ IDLE ][bus activity -> + * <--- 3 ms -----> ^ + * ^ ACTVIF=1 + * IDLEIF=1 + * # # # # (#=Program polling flags) + * ^ + * This polling loop will see both + * IDLEIF=1 and ACTVIF=1. + * However, the program services IDLEIF first + * because ACTIVIE=0. + * If this routine clears the only ACTIVIF, + * then it can never get out of the suspend + * mode. + */ + + //After the suspend condition is detected, we should do what is necessary + //to reduce USB VBUS power consumption from the host down to <2.5mA. + //For self powered devices, no action is really strictly necessary. + //For bus powered devices, either the microcontroller must clock switch or + //enter sleep mode to conserve enough power to meet the 2.5mA limit. + + UIESave = UIE; //Save UIE values, only want to wake on certain events + UIE = 0b00000100; //Enabling the ACTVIF interrupt source only + //Since ACTVIF triggers on any bus activity, it will also trigger on USB reset events. + //But that is okay, we want that. + + UIRbits.IDLEIF = 0; //Clear interrupt flag, we are servicing the idle event + UCONbits.SUSPND = 1; // Put USB module in power conserve + // mode, SIE clock inactive + + //Disable all microcontroller wake up sources, except for the one(s) which will + //be used to wake up the microcontroller. At the very least, the USB activity + //detect interrupt should be enabled as a wake up source. + + USBIF_FLAG = 0; //Won't get clear if an enabled and pending wake up source was already triggered + //However, since only the ACTVIF interrupt source is currently enabled, + //only bus activity events will prevent entry into sleep. + + USBIE_BIT = 1; //Set USB wakeup source + + #if defined(_PIC14E) + INTCONbits.PEIE = 1; //Enable interrupts to wake device on PIC16 (but GIE = 0, so no vectoring) + #endif + + //Now call the user's callback function, so that they can configure I/O pins + //for low power states, and then either sleep the microcontroller or clock + //switch to a lower power state. + USBCBSuspend(); + + #if defined(_PIC14E) + INTCONbits.PEIE = 0; //Clear interrupts + #endif + + + USBIE_BIT = 0; + UIE |= UIESave; //Restore UIE to state it was in prior to entering USB suspend (with the ACTVIF enabled as well, used later in stack) + //USB suspend events do not by themselves cause any loss of + //state information inside either the USB device firmware, or + //in the USB host software. +}//end USBSuspend + +/****************************************************************************** + * Function: void USBWakeFromSuspend(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: + * + * Note: None + *****************************************************************************/ +void USBWakeFromSuspend(void) +{ + //Call the user's callback function letting them know of wake up from suspend + //state. The user is responsible for clock switching back to fully USB compatible + //clock settings, prior to returning from the USBCBWakeFromSuspend() function. + USBCBWakeFromSuspend(); + + //Now bring the USB module out of suspend state and clear the interrupt flag. + UCONbits.SUSPND = 0; //Bring USB module hardware out of suspend mode/begin clocking it normally + UIEbits.ACTVIE = 0; //Disable ACTVIF as a USB wake up source (until another USB suspend condition is detected) + while(UIRbits.ACTVIF){UIRbits.ACTVIF = 0;} //May not be immediately clearable if USB module not yet clocked, therefore, using loop to allow osc startup time if necessary + +}//end USBWakeFromSuspend + + + + + + + + +/****************************************************************************** + * Function: void USBProtocolResetHandler(void) + * + * PreCondition: A USB bus reset is received from the host (or we have just + * turned on the USB module). + * + * Input: None + * + * Output: None + * + * Side Effects: Totally re-initializes USB stack variables and several + * USB module hardware settings as well. + * + * Overview: Once a USB bus reset is received from the host, this + * routine should be called. It resets the device address to + * zero, disables all non-EP0 endpoints, initializes EP0 to + * be ready for default communication, clears all USB + * interrupt flags, unmasks applicable USB interrupts, and + * reinitializes internal state-machine variables. + * + * Note: None + *****************************************************************************/ +void USBProtocolResetHandler(void) +{ + usb_device_state = DEFAULT_STATE; + UEIE = 0; // Not using USB error interrupts (no special handling required anyway) + UIR = 0; // Clears all USB interrupts + UIE = 0b01111011; // Enable all interrupts except ACTVIE + UADDR = 0x00; // Reset to default address + mDisableEP1to7(); // Reset all non-EP0 UEPn registers + UEP0 = EP_CTRL|HSHK_EN; // Init EP0 as a Ctrl EP, see usb_device.h + UCONbits.PPBRST = 1; // Reset ping pong buffer pointers + while(UIRbits.TRNIF == 1) // Flush any pending transactions + { + UIRbits.TRNIF = 0; + ClearWatchdog(); //5 Tcy minimum (2 for call, 2 for return, 1 for clearing) to allow TRNIF to (potentially) reassert + } + UCONbits.PPBRST = 0; + UCONbits.PKTDIS = 0; // Make sure packet processing is enabled + + //Prepare EP0 OUT Even to receive the first SETUP packet + TempBDT.Stat._byte = _DAT0|_BSTALL; + LoadBDTandSetUOWN(EP0_OUT_EVEN_BDT_INDEX); //Configures address/size fields and sets UOWN + EP0OutOddNeedsArmingNext = TRUE; + usb_stat._byte = 0x00; // Clear USB flags (like remote wakeup armed status) + usb_active_cfg = 0; // Clear active configuration + USBCBInitEP(0); // Call application callback function to give it notification + // it is getting un-configured (ex: equiv of set configuration to 0). +}//end USBProtocolResetHandler + + + +/****************************************************************************** + * Function: void USBCtrlTrfSetupHandler(void) + * + * PreCondition: SetupPkt buffer is loaded with valid USB Setup Data + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine is a task dispatcher and has 3 stages. + * 1. It initializes the control transfer state machine. + * 2. It calls on each of the module that may know how to + * service the Setup Request from the host. + * Module Example: USB9, HID, CDC, MSD, ... + * As new classes are added, the USBCBCheckOtherReq() function + * in main.c should be modified to call all of the new class handlers. + * 3. Once each of the modules has had a chance to check if + * it is responsible for servicing the request, stage 3 + * then checks direction of the transfer to determine how + * to prepare EP0 for the control transfer. + * Refer to USBCtrlEPServiceComplete() for more details. + * + * Note: Microchip USB Firmware has three different states for + * the control transfer state machine: + * 1. WAIT_SETUP + * 2. CTRL_TRF_TX + * 3. CTRL_TRF_RX + * + * A Control Transfer is composed of many USB transactions. + * When transferring data over multiple transactions, + * it is important to keep track of data source, data + * destination, and data count. These three parameters are + * stored in pSrc,pDst, and wCount. A flag is used to + * note if the data source is from ROM or RAM. + * + *****************************************************************************/ +void USBCtrlTrfSetupHandler(void) +{ + //If we get to here, that means we just received a new SETUP packet from the + //host. In this case, we should re-initalize any control transfer status + //tracking variables, since only one control transfer can be pending at a + //time (and if the last one didn't fully complete for whatever reason, + //abandon it). + ep0Bi.Stat._byte = _UCPU; + short_pkt_status = SHORT_PKT_NOT_SENT; + + //Make sure none of the EP0 OUT endpoints are still armed (one could still + //be UOWN == 1, if EP0 OUT was previously double armed). + //Clear UOWN on all EP0 OUT BDTs until we are done parsing/processing this SETUP. + if(ep0BoEven.Stat.UOWN == 1) + { + ep0BoEven.Stat._byte = _UCPU; + EP0OutOddNeedsArmingNext = FALSE; + } + if(ep0BoOdd.Stat.UOWN == 1) + { + ep0BoOdd.Stat._byte = _UCPU; + EP0OutOddNeedsArmingNext = TRUE; + } + ctrl_trf_state = WAIT_SETUP; + ctrl_trf_session_owner = MUID_NULL; // Set owner to NULL so stack knows to STALL if no control transfer handlers know how to handle the request + wCount.Val = 0; + UCONbits.PKTDIS = 0; //Clear PKTDIS bit now, since all EP0 IN/OUT endpoints are currently configured to NAK + + //Now that we are done re-initializing state tracking variables, it is + //time to parse the recently received SETUP packet to determine how to respond + //to the host's request (which could be USB 2.0 "Chapter 9" or a USB device + //class specific request). + USBCheckStdRequest(); // Takes care of handling USB "Chapter 9" standard requests + USBCBCheckOtherReq(); // User callback function, which should call any class specific control transfer handler functions + + //Now do final endpoint servicing to complete our response for the request + USBCtrlEPServiceComplete(); + +}//end USBCtrlTrfSetupHandler + + +/****************************************************************************** + * Function: void USBCtrlTrfOutHandler(uint8_t) + * + * PreCondition: None + * + * Input: The USTAT register value for the most recently received + * OUT data packet that we are processing. + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine handles an OUT transaction according to + * which control transfer state is currently active. + * + * Note: Note that if the the control transfer was from + * host to device, the session owner should be notified + * at the end of the transfer to service/consume the + * received data. To do this, the user must implement + * a function called USBCBControlTransferOutDataReady() + * in their application code, which consumes the OUT (from host) + * data that was just received. The USB stack will call this + * user callback function once all the expected bytes are received + * from the host. + * + * This is an optional function, and may be disabled to save code space by + * commenting out the "#define ENABLE_CONTROL_TRANSFERS_WITH_OUT_DATA_STAGE" + * option in usb_config.h, for applications that never use + * host to device control transfers with OUT data stage. + * + *****************************************************************************/ +#if defined (ENABLE_CONTROL_TRANSFERS_WITH_OUT_DATA_STAGE) +void USBCtrlTrfOutHandler(uint8_t USTATValue) +{ + uint8_t bytes_received; + + //Check if a host to device control transfer is in progress (ex: SETUP, OUT, OUT, ..., IN[status]) + if(ctrl_trf_state == CTRL_TRF_RX) + { + //We just received an OUT data packet from the host. Need to copy it + //to the control transfer session owner's receive buffer. + //First: Figure out how many bytes arrived in the packet, and where they went + + //Check if the OUT packet arrived on the odd EP0 OUT endpoint + if(USTATValue & 0x02) + { + //The OUT packet arrived on EP0 OUT Odd + bytes_received = ep0BoOdd.Cnt; + pSrc.bRam = ep0BoOdd.ADR; + } + else + { + //The OUT packet arrived on EP0 OUT Even + bytes_received = ep0BoEven.Cnt; + pSrc.bRam = ep0BoEven.ADR; + } + + //Keep track of how many total bytes have been received in this OUT + //control transfer (host to device), so we know when the host + //is finished sending us all the data. + wCount.Val = wCount.Val + bytes_received; + + //Copy the bytes received from the OUT endpoint buffer, into the user + //specified buffer (the pDst pointer was setup at the start of the control transfer). + while(bytes_received) + { + *pDst.bRam++ = *pSrc.bRam++; + bytes_received--; + }//end while(byte_to_read.word_val) + + + //Check if there are anymore OUT packets in the request or not + if(wCount.Val < SetupPkt.wLength) + { + //If we get to here, then the host is still going to send us more data. + //Re-arm the OUT endpoint to receive the next OUT data packet + if(EP0OutOddNeedsArmingNext == TRUE) + { + if(ep0BoEven.Stat.DTS == 1) + { + TempBDT.Stat._byte = _DAT0 | _DTSEN; + } + else + { + TempBDT.Stat._byte = _DAT1 | _DTSEN; + } + LoadBDTandSetUOWN(EP0_OUT_ODD_BDT_INDEX); + EP0OutOddNeedsArmingNext = FALSE; + } + else + { + if(ep0BoOdd.Stat.DTS == 1) + { + TempBDT.Stat._byte = _DAT0 | _DTSEN; + } + else + { + TempBDT.Stat._byte = _DAT1 | _DTSEN; + } + LoadBDTandSetUOWN(EP0_OUT_EVEN_BDT_INDEX); + EP0OutOddNeedsArmingNext = TRUE; + } + }//if(wCount.Val < SetupPkt.wLength) + else + { + //No more OUT data packets expected, re-arm EP0 OUT to receive the + //next SETUP packet, and then allow the IN status stage to complete + TempBDT.Stat._byte = _BSTALL; + if(EP0OutOddNeedsArmingNext == TRUE) + { + LoadBDTandSetUOWN(EP0_OUT_ODD_BDT_INDEX); + EP0OutOddNeedsArmingNext = FALSE; + } + else + { + LoadBDTandSetUOWN(EP0_OUT_EVEN_BDT_INDEX); + EP0OutOddNeedsArmingNext = TRUE; + } + + //Allow the IN status stage to complete now. + ep0Bi.Cnt = 0; + ep0Bi.Stat._byte = _DAT1|_DTSEN; + ep0Bi.Stat._byte |= _USIE; + + + //Call the application's callback function now to consume/use + //the data that has arrived as a control transfer over EP0 OUT... + USBCBControlTransferOutDataReady(); //<--Implement a real application call back function of this name, to consume the received OUT data... + } + }//if(ctrl_trf_state == CTRL_TRF_RX) + else //In this case the last OUT transaction must have been a status stage of a CTRL_TRF_TX + { + //Don't need to do anything here. EP0 OUT was already double armed (when + //we first processed the intial SETUP packet), so it is already ready + //for a new SETUP packet. + } +}//end USBCtrlTrfOutHandler() +#endif + + +/****************************************************************************** + * Function: void USBCtrlTrfInHandler(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine handles an IN transaction according to + * which control transfer state is currently active. + * + * Note: A Set Address Request must not change the actual address + * of the device until the completion of the control + * transfer (ex: after status stage packet is ACKed). The + * end (status stage) of the control transfer for Set Address + * Request is an IN transaction. Therefore it is necessary + * to service this unique situation when the condition is + * right. + *****************************************************************************/ +void USBCtrlTrfInHandler(void) +{ + //Check if we are in the address pending state. If so, we just completed + //the status stage of the SET ADDRESS command, and we now must switch + //ourself to the new USB device address. + if(usb_device_state == ADR_PENDING_STATE) + { + UADDR = SetupPkt.bDevADR; + if(UADDR > 0) + usb_device_state = ADDRESS_STATE; + else + usb_device_state = DEFAULT_STATE; + }//end if + + //Now check what control transfer state we are in, so we know if the most + //recent IN packet was a data stage packet, or a status stage packet. + if(ctrl_trf_state == CTRL_TRF_TX) + { + //If we get to here, we must have just sent an IN data packet, as part + //of a data stage (ex: SETUP, IN, IN [one of these data IN's just occurred], OUT[status, probably hasn't occurred yet]) + USBCtrlTrfTxService(); + + //Check if we have finisihed sending a short packet or not. + if(short_pkt_status == SHORT_PKT_SENT) + { + //If a short packet has been sent, don't want to send any more, + //stall next time if host is tries to read more data than it originally requested. + ep0Bi.Stat._byte = _BSTALL; + ep0Bi.Stat._byte |= _USIE; + } + else + { + //We still have one or more IN data packets to send. Arm the IN endpoint now. + if(ep0Bi.Stat.DTS == 0) + ep0Bi.Stat._byte = _DAT1|_DTSEN; + else + ep0Bi.Stat._byte = _DAT0|_DTSEN; + + ep0Bi.Stat._byte |= _USIE; + }//end if(...)else + } + else // CTRL_TRF_RX + { + //The status stage of a host to device control transfer just completed (SETUP, OUT, OUT,...IN[status, just completed]) + //Don't need to do anything here, already armed EP0 OUT to be ready for the + //next SETUP packet after the last OUT packet arrived. + } + +}//end USBCtrlTrfInHandler + + +/****************************************************************************** + * Function: void USBCtrlTrfTxService(void) + * + * PreCondition: pSrc, wCount, and usb_stat.ctrl_trf_mem are setup properly. + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine should be called from only two places. + * One from USBCtrlEPServiceComplete() and one from + * USBCtrlTrfInHandler(). It takes care of managing a + * device to host (IN to host) control transfer over multiple + * USB transactions. + * + * Note: None + *****************************************************************************/ +void USBCtrlTrfTxService(void) +{ + static uint8_t bytes_to_send; + + //First, have to figure out how many bytes of data to send in the transaction + //Check if the number of byte remaining to be sent it less than one full width + //packet worth of data payload. + bytes_to_send = EP0_BUFF_SIZE; + if(wCount.Val < EP0_BUFF_SIZE) + { + //The data remaining is less than a full width packet. We will send a + //short packet on the next transaction. + bytes_to_send = wCount.Val; + if(short_pkt_status == SHORT_PKT_NOT_SENT) + { + short_pkt_status = SHORT_PKT_PENDING; + } + else if(short_pkt_status == SHORT_PKT_PENDING) + { + short_pkt_status = SHORT_PKT_SENT; + } + } + + //Setup BDT so USB module knows how big of a USB packet to send IN to the host on the next EP0 IN transaction + ep0Bi.Cnt = bytes_to_send; + + //Keep track of how many bytes still need to be sent in this control transfer + wCount.Val -= bytes_to_send; + + //Now copy the data from the original source location (which was previously + //setup by the Chapter 9 or class specific control transfer handler code), to + //the USB endpoint buffer. + pDst.bRam = (uint8_t*)&CtrlTrfData; // Set destination pointer + if(usb_stat.ctrl_trf_mem == _ROM) // Determine type of memory source + { + while(bytes_to_send) + { + *pDst.bRam = *pSrc.bRom; + pDst.bRam++; + pSrc.bRom++; + bytes_to_send--; + }//end while(byte_to_send.Val) + } + else // RAM + { + while(bytes_to_send) + { + *pDst.bRam = *pSrc.bRam; + pDst.bRam++; + pSrc.bRam++; + bytes_to_send--; + }//end while(byte_to_send.Val) + }//end if(usb_stat.ctrl_trf_mem == _ROM) + +}//end USBCtrlTrfTxService + + + +/****************************************************************************** + * Function: void USBCtrlEPServiceComplete(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine wrap up the ramaining tasks in servicing + * a Setup Request. Its main task is to set the endpoint + * controls appropriately for a given situation. See code + * below. + * There are three main scenarios: + * a) There was no handler for the Request, in this case + * a STALL should be sent out. + * b) The host has requested a read control transfer, + * endpoints are required to be setup in a specific way. + * c) The host has requested a write control transfer, or + * a control data stage is not required, endpoints are + * required to be setup in a specific way. + * + * Note: None + *****************************************************************************/ +void USBCtrlEPServiceComplete(void) +{ + //Check if any USB chapter 9 or device class specific control transfer handlers + //knew how to handle the request or not. + if(ctrl_trf_session_owner == MUID_NULL) + { + //If we get to here, that means no request handlers knew how to handle + //the host's control transfer request. In this case, we are supposed + //to send STALL response to the host, to let it know of the situation. + ep0Bi.Stat._byte = _BSTALL; + ep0Bi.Stat._byte |= _USIE; + TempBDT.Stat._byte = _BSTALL; + if(EP0OutOddNeedsArmingNext == TRUE) + { + LoadBDTandSetUOWN(EP0_OUT_ODD_BDT_INDEX); + EP0OutOddNeedsArmingNext = FALSE; + } + else + { + LoadBDTandSetUOWN(EP0_OUT_EVEN_BDT_INDEX); + EP0OutOddNeedsArmingNext = TRUE; + } + } + else // A module has claimed ownership of the control transfer session. + { + if(SetupPkt.DataDir == DEV_TO_HOST) + { + /* + * If we get to here, this means a control read is occurring: + * ... | + * + * To handle this case, we need to arm both EP0 IN and OUT (twice) + * so as to handle the case where the host performs early termination + * (ex: when it sends the OUT status stage before is receives all + * of the requested data). + * + * NOTE: + * If something went wrong during the control transfer, + * the last status stage may not be sent by the host. + * When this happens, two different things could happen + * depending on the host. + * a) The host could send out a RESET. + * b) The host could send out a new SETUP transaction + * without sending a RESET first. + * To properly handle case (b), the OUT EP must be setup + * to receive either a zero length OUT transaction, or a + * new SETUP transaction. + */ + + //Set state machine to keep track of what we are doing accross multiple USB packets. + ctrl_trf_state = CTRL_TRF_TX; + + //Boundary check how many bytes the transfer handler is expecting + //to send IN to the host, versus the number that the host is actually + //requesting. We should always send the lesser of the two. + if(SetupPkt.wLength < wCount.Val) + wCount.Val = SetupPkt.wLength; + + //Allow the IN transaction hanlder function to execute, so as to copy + //the requested IN data into the proper USB IN endpoint buffer. + USBCtrlTrfTxService(); + + //Double arm EP0 OUT (even and odd both active at the same time): Once + //for the 0-byte status stage OUT packet, and once for the next 8-byte SETUP packet + TempBDT.Stat._byte = _DAT1 | _DTSEN; //DTS = 1 for the status stage, DTS ignored/irrelevant for SETUP packets + LoadBDTandSetUOWN(EP0_OUT_ODD_BDT_INDEX); + LoadBDTandSetUOWN(EP0_OUT_EVEN_BDT_INDEX); + + //Arm EP0 IN to send the first packet worth of data that the host has + //requested for this particular control transfer. The USBCtrlTrfTxService() + //function will have already copied the data into the CtrlTrfData[] buffer. + ep0Bi.ADR = (uint8_t*)&CtrlTrfData; + ep0Bi.Stat._byte = _DAT1|_DTSEN; + ep0Bi.Stat._byte |= _USIE; + }//if(SetupPkt.DataDir == DEV_TO_HOST) + else //else we must be (SetupPkt.DataDir == HOST_TO_DEV) + { + /* + * Control Write (with data stage): + * ... | + * + * Certain host to device requests may not have any data stage, such + * as the "set address" request: + * | + */ + + //Keep track of what we are doing, accross multiple USB packets. + ctrl_trf_state = CTRL_TRF_RX; + + //Prepare OUT EP to receive either the first DATA1 OUT data packet in the host + //to device control transfer, or the SETUP packet (if no data stage). + //We only arm one of the EP0 OUT buffers for this. + TempBDT.Stat._byte = _BSTALL; //Assume initially we will get a SETUP + //Check the length of the transfer, if is not 0, then the next packet will be a normal OUT instead + if(SetupPkt.wLength == 0) + { + TempBDT.Stat._byte = _DAT1|_DTSEN; //Prepare for normal OUT packet instead + } + //Check which EP0 out needs arming, and arm it. + if(EP0OutOddNeedsArmingNext == TRUE) + { + LoadBDTandSetUOWN(EP0_OUT_ODD_BDT_INDEX); + EP0OutOddNeedsArmingNext = FALSE; + } + else + { + LoadBDTandSetUOWN(EP0_OUT_EVEN_BDT_INDEX); + EP0OutOddNeedsArmingNext = TRUE; + } + + //Check if there is any actual OUT data in this transfer. If there + //is no data stage, then we can proceed to arm the status stage now. + if(SetupPkt.wLength == 0) + { + //Arm the status stage 0-byte IN packet + ep0Bi.Cnt = 0; + ep0Bi.Stat._byte = _DAT1|_DTSEN; + ep0Bi.Stat._byte |= _USIE; + } + //else + //{ + // //If there is OUT data pending to be received, we wait until we have + // //received the host's data before arming the status stage + //} + }//end if(SetupPkt.DataDir == DEV_TO_HOST) + }//end if(ctrl_trf_session_owner == MUID_NULL) + +}//end USBCtrlEPServiceComplete + + + +/****************************************************************************** + * Function: void USBCheckStdRequest(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine checks the setup data packet to see if it + * knows how to handle it + * + * Note: None + *****************************************************************************/ +void USBCheckStdRequest(void) +{ + if(SetupPkt.RequestType != STANDARD) return; + + switch(SetupPkt.bRequest) + { + case SET_ADR: + ctrl_trf_session_owner = MUID_USB9; + usb_device_state = ADR_PENDING_STATE; // Update state only + /* See USBCtrlTrfInHandler() in usbctrltrf.c for the next step */ + break; + case GET_DSC: + USBStdGetDscHandler(); + break; + case SET_CFG: + USBStdSetCfgHandler(); + break; + case GET_CFG: + ctrl_trf_session_owner = MUID_USB9; + pSrc.bRam = (uint8_t*)&usb_active_cfg; // Set Source + usb_stat.ctrl_trf_mem = _RAM; // Set memory type + //LSB(wCount) = 1; // Set data count + wCount.v[0] = 1; + break; + case GET_STATUS: + USBStdGetStatusHandler(); + break; + case CLR_FEATURE: + case SET_FEATURE: + USBStdFeatureReqHandler(); + break; + case GET_INTF: + ctrl_trf_session_owner = MUID_USB9; + pSrc.bRam = (uint8_t*)&usb_alt_intf+SetupPkt.bIntfID; // Set source + usb_stat.ctrl_trf_mem = _RAM; // Set memory type + wCount.v[0] = 1; // Set data count + break; + case SET_INTF: + ctrl_trf_session_owner = MUID_USB9; + usb_alt_intf[SetupPkt.bIntfID] = SetupPkt.bAltID; + break; + case SET_DSC: + case SYNCH_FRAME: + default: + break; + }//end switch + +}//end USBCheckStdRequest + +/****************************************************************************** + * Function: void USBStdGetDscHandler(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine handles the standard GET_DESCRIPTOR request. + * It utilizes tables dynamically looks up descriptor size. + * This routine should never have to be modified if the tables + * in usb_descriptors.c are declared correctly. + * + * Note: None + *****************************************************************************/ +void USBStdGetDscHandler(void) +{ + if(SetupPkt.bmRequestType == 0x80) + { + switch(SetupPkt.bDscType) + { + case DSC_DEV: + ctrl_trf_session_owner = MUID_USB9; + pSrc.bRom = (ROM uint8_t*)&device_dsc; + wCount.v[0] = sizeof(device_dsc); // Set data count + break; + case DSC_CFG: + //Error check to make sure the host is requesting a legal/implemented configuration descriptor + if(SetupPkt.bDscIndex < USB_MAX_NUM_CONFIG_DSC) + { + ctrl_trf_session_owner = MUID_USB9; + pSrc.bRom = (ROM BYTE*)&CFG01; + wCount.Val = sizeof(CFG01); // Set data count + } + break; + case DSC_STR: + ctrl_trf_session_owner = MUID_USB9; + pSrc.bRom = *(USB_SD_Ptr+SetupPkt.bDscIndex); + wCount.Val = *pSrc.bRom; // Set data count + break; + }//end switch + + usb_stat.ctrl_trf_mem = _ROM; // Set memory type + }//end if +}//end USBStdGetDscHandler + +/****************************************************************************** + * Function: void USBStdSetCfgHandler(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine first disables all endpoints by clearing + * UEP registers. It then configures (initializes) endpoints + * specified in the modifiable section. + * + * Note: None + *****************************************************************************/ +void USBStdSetCfgHandler(void) +{ + static unsigned char i; + + ctrl_trf_session_owner = MUID_USB9; + //Initially disable all endpoints (except EP0, which we are still using) + mDisableEP1to7(); // See usb_device.h + //Reset alternate interface selection settings to default value + for(i = 0; i < MAX_NUM_INT; i++) + { + usb_alt_intf[i] = 0; + } + + //Save the current configuration number that we have been set to + usb_active_cfg = SetupPkt.bCfgValue; + + //Call the user's set configuration handler function. Note: We pass + //the user's set configuration handler the configuration number, since + //the USB host could either configure us (set to !0), or de-configure + //us (set to == 0). The application firmware should disable endpoints + //when getting de-configured. + USBCBInitEP(usb_active_cfg); + + if(SetupPkt.bCfgValue == 0) + { + usb_device_state = ADDRESS_STATE; + } + else + { + usb_device_state = CONFIGURED_STATE; + }//end if(SetupPkt.bcfgValue == 0) +}//end USBStdSetCfgHandler + + +/****************************************************************************** + * Function: void USBStdGetStatusHandler(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine handles the standard GET_STATUS request + * + * Note: None + *****************************************************************************/ +void USBStdGetStatusHandler(void) +{ + CtrlTrfData._byte0 = 0; // Initialize content + CtrlTrfData._byte1 = 0; + + switch(SetupPkt.Recipient) + { + case RCPT_DEV: + ctrl_trf_session_owner = MUID_USB9; + /* + * _byte0: bit0: Self-Powered Status [0] Bus-Powered [1] Self-Powered + * bit1: RemoteWakeup [0] Disabled [1] Enabled + */ + + if(self_power == 1) // self_power defined in HardwareProfile.h + CtrlTrfData._byte0 |= 0b00000001; // Set bit0 + if(usb_stat.RemoteWakeup == 1) // usb_stat defined in usbmmap.c + CtrlTrfData._byte0|=0b00000010; // Set bit1 + break; + case RCPT_INTF: + ctrl_trf_session_owner = MUID_USB9; // No data to update + break; + case RCPT_EP: + ctrl_trf_session_owner = MUID_USB9; + /* + * _byte0: bit0: Halt Status [0] Not Halted [1] Halted + */ + pDst.bRam = (uint8_t*)&ep0BoEven+(SetupPkt.EPNum*8)+(SetupPkt.EPDir*4)+4; //+4 is to skip past the EP0 OUT ODD BDT entry + if(*pDst.bRam & _BSTALL) // Use _BSTALL as a bit mask + CtrlTrfData._byte0=0x01;// Set bit0 + break; + }//end switch + + if(ctrl_trf_session_owner == MUID_USB9) + { + pSrc.bRam = (uint8_t*)&CtrlTrfData; // Set Source + usb_stat.ctrl_trf_mem = _RAM; // Set memory type + wCount.v[0] = 2; // Set data count + }//end if(...) +}//end USBStdGetStatusHandler + + +/****************************************************************************** + * Function: void USBStdFeatureReqHandler(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine handles the standard SET & CLEAR FEATURES + * requests + * + * Note: None + *****************************************************************************/ +void USBStdFeatureReqHandler(void) +{ + //Check if the host GET STATUS request was for the device's remote wakeup armed status + if((SetupPkt.bFeature == DEVICE_REMOTE_WAKEUP)&&(SetupPkt.Recipient == RCPT_DEV)) + { + ctrl_trf_session_owner = MUID_USB9; + if(SetupPkt.bRequest == SET_FEATURE) + usb_stat.RemoteWakeup = 1; + else + usb_stat.RemoteWakeup = 0; + }//end if + + //Check if the host GET STATUS request was for the endpoint halt status of an endpoint + if((SetupPkt.bFeature == ENDPOINT_HALT)&&(SetupPkt.Recipient == RCPT_EP)&&(SetupPkt.EPNum != 0)) + { + ctrl_trf_session_owner = MUID_USB9; + /* Must do address calculation here */ + pDst.bRam = (uint8_t*)&ep0BoEven+(SetupPkt.EPNum*8)+(SetupPkt.EPDir*4)+4; + + if(SetupPkt.bRequest == SET_FEATURE) + { + *pDst.bRam = _BSTALL; + *pDst.bRam |= _USIE; + } + else + { + if(SetupPkt.EPDir == 1) // IN + *pDst.bRam = _UCPU|_DAT1; + else + { + *pDst.bRam = _DAT0|_DTSEN; + *pDst.bRam |= _USIE; + } + }//end if + }//end if +}//end USBStdFeatureReqHandler + + + +//This is a helper function for copying prepared BDT entry data from the global +//TempBDT buffer, into the real BDT EP0 OUT (even or odd) entry of the user's +//specified index. Once copied, this function also sets the UOWN bit in the +//real BDT entry. This helper function helps to reduce code space, by minimizing +//use of pointers in the rest of the code. This function is only intended to +//be used to arm EP0 OUT (even or odd). +void LoadBDTandSetUOWN(uint8_t BDTIndexToLoad) +{ + static volatile BDT* pBDTEntry; + + //Setup the byte count and destination address values. Since this function + //is only intended to be used for EP0 OUT even/odd, the size should always + //be the endpoint size (the host determines that actual size of packet sent), + //and the address should always be the respective even/odd USB packet buffer. + TempBDT.Cnt = EP0_BUFF_SIZE; + TempBDT.ADR = (uint8_t*)&EP0OutOddBuf[0]; + if(BDTIndexToLoad == EP0_OUT_EVEN_BDT_INDEX) + { + TempBDT.ADR = (uint8_t*)&EP0OutEvenBuf[0]; + pBDTEntry = (volatile BDT*)BDT_ADDR; + } + else + { + pBDTEntry = (volatile BDT*)(BDT_ADDR + 4); + } + + //Copy the global TempBDT contents into the user specified actual BDT location + *pBDTEntry = TempBDT; + + //Now set the UOWN bit to arm the endpoint + pBDTEntry->Stat.UOWN = 1; +} + + + +//Disable the USB module and then wait a long time (long enough for the host +//to correctly detect the USB detach event, process the plug and play event, +//and get itself back into a state ready for a new USB attach event. +void USBDisableWithLongDelay(void) +{ + UCONbits.SUSPND = 0; //Make sure not in suspend mode + UCON = 0x00; //Disable USB module + DelayRoutine(0xFFFF); //Wait long time for host to recognize detach event + usb_device_state = DETACHED_STATE; +} + + +//Helper function to execute some blocking delay. +void DelayRoutine(unsigned int DelayAmount) +{ + while(DelayAmount) + { + ClearWatchdog(); + DelayAmount--; + } +} + + + +//Helper function to reduce code size when built with C18. The ClrWdt() is an +//inline assembly macro, and on the C18 compiler, if you execute an inline asm +//instruction in a C function, it prevents the compiler from implementing +//optimizations to that particular function (since the compiler doesn't know what +//the user did in the inline asm). Therefore, inline asm is more efficient if +//implemented outside of large C functions, when using C18. +void ClearWatchdog(void) +{ + ClrWdt(); +} + + +/** EOF usb_device.c *************************************************************/ diff --git a/bootloader_hacked_from_mla/src/usb_device.h b/bootloader_hacked_from_mla/src/usb_device.h new file mode 100644 index 0000000..d2749c1 --- /dev/null +++ b/bootloader_hacked_from_mla/src/usb_device.h @@ -0,0 +1,699 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +#ifndef _USB_DEVICE_H +#define _USB_DEVICE_H + +/** I N C L U D E S **********************************************************/ +#include "usb.h" + + + +//Hardware abstraction. The USBIF and USBIE bits reside in different registers +//on different USB microcontrollers. +#if defined(__18F45K50) || defined(__18F25K50) || defined(__18F24K50) || defined(__18LF45K50) || defined(__18LF25K50) || defined(__18LF24K50) + #define USBIF_FLAG PIR3bits.USBIF + #define USBIE_BIT PIE3bits.USBIE +#else + #define USBIF_FLAG PIR2bits.USBIF + #define USBIE_BIT PIE2bits.USBIE +#endif + + +/** D E F I N I T I O N S ****************************************************/ +/****************************************************************************** + * Standard Request Codes + * USB 2.0 Spec Ref Table 9-4 + *****************************************************************************/ +#define GET_STATUS 0 +#define CLR_FEATURE 1 +#define SET_FEATURE 3 +#define SET_ADR 5 +#define GET_DSC 6 +#define SET_DSC 7 +#define GET_CFG 8 +#define SET_CFG 9 +#define GET_INTF 10 +#define SET_INTF 11 +#define SYNCH_FRAME 12 + +/* Standard Feature Selectors */ +#define DEVICE_REMOTE_WAKEUP 0x01 +#define ENDPOINT_HALT 0x00 + + +/* UCFG Initialization Parameters */ +#define _PPBM0 0x00 // Pingpong Buffer Mode 0 - ping pong bufferring disabled +#define _PPBM1 0x01 // Pingpong Buffer Mode 1 - ping pong on EP0 OUT only +#define _PPBM2 0x02 // Pingpong Buffer Mode 2 - ping pong on all endpoints +#define _LS 0x00 // Use Low-Speed USB Mode +#define _FS 0x04 // Use Full-Speed USB Mode +#define _TRINT 0x00 // Use internal transceiver +#define _TREXT 0x08 // Use external transceiver +#define _PUEN 0x10 // Use internal pull-up resistor +#define _OEMON 0x40 // Use SIE output indicator +#define _UTEYE 0x80 // Use Eye-Pattern test + +/* UEPn Initialization Parameters */ +#define EP_CTRL 0x06 // Cfg Control pipe for this ep +#define EP_OUT 0x0C // Cfg OUT only pipe for this ep +#define EP_IN 0x0A // Cfg IN only pipe for this ep +#define EP_OUT_IN 0x0E // Cfg both OUT & IN pipes for this ep +#define HSHK_EN 0x10 // Enable handshake packet + // Handshake should be disable for isoch + +/****************************************************************************** + * USB - PICmicro Endpoint Definitions + * PICmicro EP Address Format: X:EP3:EP2:EP1:EP0:DIR:PPBI:X + * This is used when checking the value read from USTAT + * + * NOTE: These definitions are not used in the descriptors. + * EP addresses used in the descriptors have different format and + * are defined in: usb_device.h + *****************************************************************************/ +#define OUT 0 +#define IN 1 + +#define PIC_EP_NUM_MASK 0b01111000 +#define PIC_EP_DIR_MASK 0b00000100 + +#define EP00_OUT ((0x00<<3)|(OUT<<2)) +#define EP00_IN ((0x00<<3)|(IN<<2)) +#define EP01_OUT ((0x01<<3)|(OUT<<2)) +#define EP01_IN ((0x01<<3)|(IN<<2)) +#define EP02_OUT ((0x02<<3)|(OUT<<2)) +#define EP02_IN ((0x02<<3)|(IN<<2)) +#define EP03_OUT ((0x03<<3)|(OUT<<2)) +#define EP03_IN ((0x03<<3)|(IN<<2)) +#define EP04_OUT ((0x04<<3)|(OUT<<2)) +#define EP04_IN ((0x04<<3)|(IN<<2)) +#define EP05_OUT ((0x05<<3)|(OUT<<2)) +#define EP05_IN ((0x05<<3)|(IN<<2)) +#define EP06_OUT ((0x06<<3)|(OUT<<2)) +#define EP06_IN ((0x06<<3)|(IN<<2)) +#define EP07_OUT ((0x07<<3)|(OUT<<2)) +#define EP07_IN ((0x07<<3)|(IN<<2)) +#define EP08_OUT ((0x08<<3)|(OUT<<2)) +#define EP08_IN ((0x08<<3)|(IN<<2)) +#define EP09_OUT ((0x09<<3)|(OUT<<2)) +#define EP09_IN ((0x09<<3)|(IN<<2)) +#define EP10_OUT ((0x0A<<3)|(OUT<<2)) +#define EP10_IN ((0x0A<<3)|(IN<<2)) +#define EP11_OUT ((0x0B<<3)|(OUT<<2)) +#define EP11_IN ((0x0B<<3)|(IN<<2)) +#define EP12_OUT ((0x0C<<3)|(OUT<<2)) +#define EP12_IN ((0x0C<<3)|(IN<<2)) +#define EP13_OUT ((0x0D<<3)|(OUT<<2)) +#define EP13_IN ((0x0D<<3)|(IN<<2)) +#define EP14_OUT ((0x0E<<3)|(OUT<<2)) +#define EP14_IN ((0x0E<<3)|(IN<<2)) +#define EP15_OUT ((0x0F<<3)|(OUT<<2)) +#define EP15_IN ((0x0F<<3)|(IN<<2)) + +#define EP0_OUT_EVEN_BDT_INDEX 0 +#define EP0_OUT_ODD_BDT_INDEX 1 + + +/* Buffer Descriptor Status Register Initialization Parameters */ +#define _BSTALL 0x04 //Buffer Stall enable +#define _DTSEN 0x08 //Data Toggle Synch enable +#define _INCDIS 0x10 //Address increment disable +#define _KEN 0x20 //SIE keeps buff descriptors enable +#define _DAT0 0x00 //DATA0 packet expected next +#define _DAT1 0x40 //DATA1 packet expected next +#define _DTSMASK 0x40 //DTS Mask +#define _USIE 0x80 //SIE owns buffer +#define _UCPU 0x00 //CPU owns buffer + +/* USB Device States - To be used with [byte usb_device_state] */ +#define DETACHED_STATE 0 +#define ATTACHED_STATE 1 +#define POWERED_STATE 2 +#define DEFAULT_STATE 3 +#define ADR_PENDING_STATE 4 +#define ADDRESS_STATE 5 +#define CONFIGURED_STATE 6 + +/* Memory Types for Control Transfer - used in USB_DEVICE_STATUS */ +#define _RAM 0 +#define _ROM 1 + +/* Descriptor Types */ +#define DSC_DEV 0x01 +#define DSC_CFG 0x02 +#define DSC_STR 0x03 +#define DSC_INTF 0x04 +#define DSC_EP 0x05 + +/****************************************************************************** + * USB Endpoint Definitions + * USB Standard EP Address Format: DIR:X:X:X:EP3:EP2:EP1:EP0 + * This is used in the descriptors. See usb_descriptors.c + * + * NOTE: Do not use these values for checking against USTAT. + * To check against USTAT, use values defined in "usb_device.h" + *****************************************************************************/ +#define _EP01_OUT 0x01 +#define _EP01_IN 0x81 +#define _EP02_OUT 0x02 +#define _EP02_IN 0x82 +#define _EP03_OUT 0x03 +#define _EP03_IN 0x83 +#define _EP04_OUT 0x04 +#define _EP04_IN 0x84 +#define _EP05_OUT 0x05 +#define _EP05_IN 0x85 +#define _EP06_OUT 0x06 +#define _EP06_IN 0x86 +#define _EP07_OUT 0x07 +#define _EP07_IN 0x87 +#define _EP08_OUT 0x08 +#define _EP08_IN 0x88 +#define _EP09_OUT 0x09 +#define _EP09_IN 0x89 +#define _EP10_OUT 0x0A +#define _EP10_IN 0x8A +#define _EP11_OUT 0x0B +#define _EP11_IN 0x8B +#define _EP12_OUT 0x0C +#define _EP12_IN 0x8C +#define _EP13_OUT 0x0D +#define _EP13_IN 0x8D +#define _EP14_OUT 0x0E +#define _EP14_IN 0x8E +#define _EP15_OUT 0x0F +#define _EP15_IN 0x8F + +/* Configuration Attributes */ +#define _DEFAULT 0x01<<7 //Default Value (Bit 7 is set) +#define _SELF 0x01<<6 //Self-powered (Supports if set) +#define _RWU 0x01<<5 //Remote Wakeup (Supports if set) + +/* Endpoint Transfer Type */ +#define _CTRL 0x00 //Control Transfer +#define _ISO 0x01 //Isochronous Transfer +#define _BULK 0x02 //Bulk Transfer +#define _INT 0x03 //Interrupt Transfer + +/* Isochronous Endpoint Synchronization Type */ +#define _NS 0x00<<2 //No Synchronization +#define _AS 0x01<<2 //Asynchronous +#define _AD 0x02<<2 //Adaptive +#define _SY 0x03<<2 //Synchronous + +/* Isochronous Endpoint Usage Type */ +#define _DE 0x00<<4 //Data endpoint +#define _FE 0x01<<4 //Feedback endpoint +#define _IE 0x02<<4 //Implicit feedback Data endpoint + + + + +/** T Y P E S ****************************************************************/ +typedef union _USB_DEVICE_STATUS +{ + uint8_t _byte; + struct + { + unsigned RemoteWakeup:1;// [0]Disabled [1]Enabled: See usb_device.c,usb9.c + unsigned ctrl_trf_mem:1;// [0]RAM [1]ROM + }; +} USB_DEVICE_STATUS; + +typedef union _BD_STAT +{ + uint8_t _byte; + struct{ + unsigned BC8:1; + unsigned BC9:1; + unsigned BSTALL:1; //Buffer Stall Enable + unsigned DTSEN:1; //Data Toggle Synch Enable + unsigned INCDIS:1; //Address Increment Disable + unsigned KEN:1; //BD Keep Enable + unsigned DTS:1; //Data Toggle Synch Value + unsigned UOWN:1; //USB Ownership + }; + struct{ + unsigned :2; + unsigned PID0:1; + unsigned PID1:1; + unsigned PID2:1; + unsigned PID3:1; + unsigned :2; + }; + struct{ + unsigned :2; + unsigned PID:4; //Packet Identifier + unsigned :2; + }; +} BD_STAT; //Buffer Descriptor Status Register + +typedef union _BDT +{ + struct + { + BD_STAT Stat; + uint8_t Cnt; + uint8_t ADRL; //Buffer Address Low + uint8_t ADRH; //Buffer Address High + }; + struct + { + unsigned :8; + unsigned :8; + uint8_t* ADR; //Buffer Address + }; +} BDT; //Buffer Descriptor Table + + +/****************************************************************************** + * CTRL_TRF_SETUP: + * + * Every setup packet has 8 bytes. + * However, the buffer size has to equal the EP0_BUFF_SIZE value specified + * in usb_config.h + * The value of EP0_BUFF_SIZE can be 8, 16, 32, or 64. + * + * First 8 bytes are defined to be directly addressable to improve speed + * and reduce code size. + * Bytes beyond the 8th byte have to be accessed using indirect addressing. + *****************************************************************************/ +typedef union _CTRL_TRF_SETUP +{ + /** Array for indirect addressing ****************************************/ + struct + { + uint8_t _byte[EP0_BUFF_SIZE]; + }; + + /** Standard Device Requests *********************************************/ + struct + { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + }; + struct + { + unsigned :8; + unsigned :8; + WORD_VAL W_Value; + WORD_VAL W_Index; + WORD_VAL W_Length; + }; + struct + { + unsigned Recipient:5; //Device,Interface,Endpoint,Other + unsigned RequestType:2; //Standard,Class,Vendor,Reserved + unsigned DataDir:1; //Host-to-device,Device-to-host + unsigned :8; + uint8_t bFeature; //DEVICE_REMOTE_WAKEUP,ENDPOINT_HALT + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + }; + struct + { + unsigned :8; + unsigned :8; + uint8_t bDscIndex; //For Configuration and String DSC Only + uint8_t bDscType; //Device,Configuration,String + uint16_t wLangID; //Language ID + unsigned :8; + unsigned :8; + }; + struct + { + unsigned :8; + unsigned :8; + uint8_t bDevADR; //Device Address 0-127 + uint8_t bDevADRH; //Must equal zero + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + }; + struct + { + unsigned :8; + unsigned :8; + uint8_t bCfgValue; //Configuration Value 0-255 + uint8_t bCfgRSD; //Must equal zero (Reserved) + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + }; + struct + { + unsigned :8; + unsigned :8; + uint8_t bAltID; //Alternate Setting Value 0-255 + uint8_t bAltID_H; //Must equal zero + uint8_t bIntfID; //Interface Number Value 0-255 + uint8_t bIntfID_H; //Must equal zero + unsigned :8; + unsigned :8; + }; + struct + { + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + uint8_t bEPID; //Endpoint ID (Number & Direction) + uint8_t bEPID_H; //Must equal zero + unsigned :8; + unsigned :8; + }; + struct + { + unsigned :8; + unsigned :8; + unsigned :8; + unsigned :8; + unsigned EPNum:4; //Endpoint Number 0-15 + unsigned :3; + unsigned EPDir:1; //Endpoint Direction: 0-OUT, 1-IN + unsigned :8; + unsigned :8; + unsigned :8; + }; + /** End: Standard Device Requests ****************************************/ + +} CTRL_TRF_SETUP; + +/****************************************************************************** + * CTRL_TRF_DATA: + * + * Buffer size has to equal the EP0_BUFF_SIZE value specified + * in usb_config.h + * The value of EP0_BUFF_SIZE can be 8, 16, 32, or 64. + * + * First 8 bytes are defined to be directly addressable to improve speed + * and reduce code size. + * Bytes beyond the 8th byte have to be accessed using indirect addressing. + *****************************************************************************/ +typedef union _CTRL_TRF_DATA +{ + /** Array for indirect addressing ****************************************/ + struct + { + uint8_t _byte[EP0_BUFF_SIZE]; + }; + + /** First 8-byte direct addressing ***************************************/ + struct + { + uint8_t _byte0; + uint8_t _byte1; + uint8_t _byte2; + uint8_t _byte3; + uint8_t _byte4; + uint8_t _byte5; + uint8_t _byte6; + uint8_t _byte7; + }; + struct + { + uint16_t _word0; + uint16_t _word1; + uint16_t _word2; + uint16_t _word3; + }; + +} CTRL_TRF_DATA; + + + + +/****************************************************************************** + * USB Device Descriptor Structure + *****************************************************************************/ +typedef struct _USB_DEV_DSC +{ + uint8_t bLength; uint8_t bDscType; uint16_t bcdUSB; + uint8_t bDevCls; uint8_t bDevSubCls; uint8_t bDevProtocol; + uint8_t bMaxPktSize0; uint16_t idVendor; uint16_t idProduct; + uint16_t bcdDevice; uint8_t iMFR; uint8_t iProduct; + uint8_t iSerialNum; uint8_t bNumCfg; +} USB_DEV_DSC; + +/****************************************************************************** + * USB Configuration Descriptor Structure + *****************************************************************************/ +typedef struct _USB_CFG_DSC +{ + uint8_t bLength; uint8_t bDscType; uint16_t wTotalLength; + uint8_t bNumIntf; uint8_t bCfgValue; uint8_t iCfg; + uint8_t bmAttributes; uint8_t bMaxPower; +} USB_CFG_DSC; + +/****************************************************************************** + * USB Interface Descriptor Structure + *****************************************************************************/ +typedef struct _USB_INTF_DSC +{ + uint8_t bLength; uint8_t bDscType; uint8_t bIntfNum; + uint8_t bAltSetting; uint8_t bNumEPs; uint8_t bIntfCls; + uint8_t bIntfSubCls; uint8_t bIntfProtocol; uint8_t iIntf; +} USB_INTF_DSC; + +/****************************************************************************** + * USB Endpoint Descriptor Structure + *****************************************************************************/ +typedef struct _USB_EP_DSC +{ + uint8_t bLength; uint8_t bDscType; uint8_t bEPAdr; + uint8_t bmAttributes; uint16_t wMaxPktSize; uint8_t bInterval; +} USB_EP_DSC; + + + + +/****************************************************************************** + * Macro: void mInitializeUSBDriver(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: Configures the USB module, definition of UCFG_VAL can be + * found in usb_config.h + * + * This register determines: USB Speed, On-chip pull-up + * resistor selection, On-chip tranceiver selection, bus + * eye pattern generation mode, Ping-pong buffering mode + * selection. + * + * Note: None + *****************************************************************************/ +#define mInitializeUSBDriver() {UCFG = UCFG_VAL; \ + usb_device_state = DETACHED_STATE; \ + USBProtocolResetHandler();} + +/****************************************************************************** + * Macro: void mDisableEP1to15(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This macro disables all endpoints except EP0. + * This macro should be called when the host sends a RESET + * signal or a SET_CONFIGURATION request. + * + * Note: None + *****************************************************************************/ +//#if defined(__18F14K50) || defined(__18F13K50) || defined(__18LF14K50) || defined(__18LF13K50) +// #define mDisableEP1to15() ClearArray((uint8_t*)&UEP1,7); +//#else +// #define mDisableEP1to15() ClearArray((uint8_t*)&UEP1,15); +//#endif + +//Using below instead to save code space. Dedicated bootloader project, +//will never use UEP3+, therefore no need to really mess with those registers +#define mDisableEP1to7() UEP1=0x00;UEP2=0x00;UEP3=0x00;\ + UEP4=0x00;UEP5=0x00;UEP6=0x00;UEP7=0x00; +// UEP8=0x00;UEP9=0x00;UEP10=0x00;UEP11=0x00;\ +// UEP12=0x00;UEP13=0x00;UEP14=0x00;UEP15=0x00; + +/****************************************************************************** + * Macro: void mUSBBufferReady(buffer_dsc) + * + * PreCondition: IN Endpoint: Buffer is loaded and ready to be sent. + * OUT Endpoint: Buffer is free to be written to by SIE. + * + * Input: byte buffer_dsc: Root name of the buffer descriptor group. + * i.e. ep0Bo, ep1Bi, ... Declared in usbmmap.c + * Names can be remapped for readability, see examples in + * usb_config.h (#define HID_BD_OUT ep1Bo) + * + * Output: None + * + * Side Effects: None + * + * Overview: This macro should be called each time after: + * 1. A non-EP0 IN endpoint buffer is populated with data. + * 2. A non-EP0 OUT endpoint buffer is read. + * This macro turns the buffer ownership to SIE for servicing. + * It also toggles the DTS bit for synchronization. + * + * Note: None + *****************************************************************************/ +#define mUSBBufferReady(buffer_dsc) \ +{ \ + buffer_dsc.Stat._byte &= _DTSMASK; /* Save only DTS bit */ \ + buffer_dsc.Stat.DTS = !buffer_dsc.Stat.DTS; /* Toggle DTS bit */ \ + buffer_dsc.Stat._byte |= _DTSEN; /* Configure other settings */ \ + buffer_dsc.Stat._byte |= _USIE; /* Turn ownership to SIE */ \ +} + + + + +/** D E F I N I T I O N S ****************************************************/ +/* + * MUID = Microchip USB Class ID + * Used to identify which of the USB classes owns the current + * session of control transfer over EP0 + */ +#define MUID_NULL 0 +#define MUID_USB9 1 +#define MUID_HID 2 +#define MUID_CDC 3 + + +/* Control Transfer States */ +#define WAIT_SETUP 0 +#define CTRL_TRF_TX 1 +#define CTRL_TRF_RX 2 + +/* Short Packet States - Used by Control Transfer Read - CTRL_TRF_TX */ +#define SHORT_PKT_NOT_SENT 0 +#define SHORT_PKT_PENDING 1 +#define SHORT_PKT_SENT 2 + +/* USB PID: Token Types - See chapter 8 in the USB specification */ +#define SETUP_TOKEN 0b00001101 +#define OUT_TOKEN 0b00000001 +#define IN_TOKEN 0b00001001 + +/* bmRequestType Definitions */ +#define HOST_TO_DEV 0 +#define DEV_TO_HOST 1 + +#define STANDARD 0x00 +#define CLASS 0x01 +#define VENDOR 0x02 + +#define RCPT_DEV 0 +#define RCPT_INTF 1 +#define RCPT_EP 2 +#define RCPT_OTH 3 + + + +/** E X T E R N S ************************************************************/ +extern uint8_t ctrl_trf_session_owner; +extern POINTER pSrc; +extern POINTER pDst; +extern WORD_VAL wCount; +extern uint8_t usb_device_state; +extern USB_DEVICE_STATUS usb_stat; +extern uint8_t usb_active_cfg; +extern uint8_t usb_alt_intf[MAX_NUM_INT]; + +extern volatile BDT ep0Bo; //Endpoint #0 BD Out +extern volatile BDT ep0Bi; //Endpoint #0 BD In +extern volatile BDT ep1Bo; //Endpoint #1 BD Out +extern volatile BDT ep1Bi; //Endpoint #1 BD In +extern volatile BDT ep2Bo; //Endpoint #2 BD Out +extern volatile BDT ep2Bi; //Endpoint #2 BD In +extern volatile BDT ep3Bo; //Endpoint #3 BD Out +extern volatile BDT ep3Bi; //Endpoint #3 BD In +extern volatile BDT ep4Bo; //Endpoint #4 BD Out +extern volatile BDT ep4Bi; //Endpoint #4 BD In +extern volatile BDT ep5Bo; //Endpoint #5 BD Out +extern volatile BDT ep5Bi; //Endpoint #5 BD In +extern volatile BDT ep6Bo; //Endpoint #6 BD Out +extern volatile BDT ep6Bi; //Endpoint #6 BD In +extern volatile BDT ep7Bo; //Endpoint #7 BD Out +extern volatile BDT ep7Bi; //Endpoint #7 BD In +extern volatile BDT ep8Bo; //Endpoint #8 BD Out +extern volatile BDT ep8Bi; //Endpoint #8 BD In +extern volatile BDT ep9Bo; //Endpoint #9 BD Out +extern volatile BDT ep9Bi; //Endpoint #9 BD In +extern volatile BDT ep10Bo; //Endpoint #10 BD Out +extern volatile BDT ep10Bi; //Endpoint #10 BD In +extern volatile BDT ep11Bo; //Endpoint #11 BD Out +extern volatile BDT ep11Bi; //Endpoint #11 BD In +extern volatile BDT ep12Bo; //Endpoint #12 BD Out +extern volatile BDT ep12Bi; //Endpoint #12 BD In +extern volatile BDT ep13Bo; //Endpoint #13 BD Out +extern volatile BDT ep13Bi; //Endpoint #13 BD In +extern volatile BDT ep14Bo; //Endpoint #14 BD Out +extern volatile BDT ep14Bi; //Endpoint #14 BD In +extern volatile BDT ep15Bo; //Endpoint #15 BD Out +extern volatile BDT ep15Bi; //Endpoint #15 BD In + +extern CTRL_TRF_SETUP SetupPkt; +volatile extern CTRL_TRF_DATA CtrlTrfData; + + +#if defined(USB_USE_HID) +extern volatile unsigned char hid_report_out[HID_INT_OUT_EP_SIZE]; +extern volatile unsigned char hid_report_in[HID_INT_IN_EP_SIZE]; +#endif + + +extern ROM USB_DEV_DSC device_dsc; +extern ROM uint8_t CFG01[CONFIG_DESC_TOTAL_LEN]; +extern ROM const unsigned char *ROM USB_CD_Ptr[]; +extern ROM unsigned char* ROM USB_SD_Ptr[]; + + + + +/** P U B L I C P R O T O T Y P E S *****************************************/ +void USBDeviceInit(void); +void USBCheckBusStatus(void); +void USBSoftAttach(void); +void USBSoftDetach(void); +void USBDeviceTasks(void); +void USBDisableWithLongDelay(void); +void DelayRoutine(unsigned int DelayAmount); +void ClearWatchdog(void); +#define USBGetDeviceState() usb_device_state +#define USBIsDeviceSuspended() UCONbits.SUSPND + + +#endif //_USB_DEVICE_H diff --git a/bootloader_hacked_from_mla/src/usb_device_hid.c b/bootloader_hacked_from_mla/src/usb_device_hid.c new file mode 100644 index 0000000..39524c4 --- /dev/null +++ b/bootloader_hacked_from_mla/src/usb_device_hid.c @@ -0,0 +1,302 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ + +/** I N C L U D E S **********************************************************/ +#include "usb.h" + +#ifdef USB_USE_HID + +/** V A R I A B L E S ********************************************************/ +#ifndef __XC8__ +#pragma udata +#endif +uint8_t idle_rate; +uint8_t active_protocol; // [0] Boot Protocol [1] Report Protocol +uint8_t hid_rpt_rx_len; + +/** P R I V A T E P R O T O T Y P E S ***************************************/ +void HIDGetReportHandler(void); +void HIDSetReportHandler(void); + +/** D E C L A R A T I O N S **************************************************/ +#ifndef __XC8__ +#pragma code +#endif + +/** C L A S S S P E C I F I C R E Q ****************************************/ +/****************************************************************************** + * Function: void USBCheckHIDRequest(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This routine checks the setup data packet to see if it + * knows how to handle it + * + * Note: None + *****************************************************************************/ +void USBCheckHIDRequest(void) +{ + if(SetupPkt.Recipient != RCPT_INTF) return; + if(SetupPkt.bIntfID != HID_INTF_ID) return; + + /* + * There are two standard requests that hid.c may support. + * 1. GET_DSC(DSC_HID,DSC_RPT,DSC_PHY); + * 2. SET_DSC(DSC_HID,DSC_RPT,DSC_PHY); + */ + if(SetupPkt.bRequest == GET_DSC) + { + switch(SetupPkt.bDscType) + { + case DSC_HID: + ctrl_trf_session_owner = MUID_HID; + pSrc.bRom = &CFG01[18]; //18 is a magic number (offset from start of configuration descriptor, to the start of the HID descriptor) + wCount.Val = sizeof(USB_HID_DSC); + break; + case DSC_RPT: + ctrl_trf_session_owner = MUID_HID; + mUSBGetHIDRptDscAdr(pSrc.bRom); // See usb_config.h + mUSBGetHIDRptDscSize(wCount.Val); // See usb_config.h + break; + case DSC_PHY: + // ctrl_trf_session_owner = MUID_HID; + break; + }//end switch(SetupPkt.bDscType) + usb_stat.ctrl_trf_mem = _ROM; + }//end if(SetupPkt.bRequest == GET_DSC) + + if(SetupPkt.RequestType != CLASS) return; + switch(SetupPkt.bRequest) + { + case GET_REPORT: + HIDGetReportHandler(); + break; + case SET_REPORT: + HIDSetReportHandler(); + break; + case GET_IDLE: + ctrl_trf_session_owner = MUID_HID; + pSrc.bRam = (uint8_t*)&idle_rate; // Set source + usb_stat.ctrl_trf_mem = _RAM; // Set memory type + wCount.v[0] = 1; // Set data count + break; + case SET_IDLE: + ctrl_trf_session_owner = MUID_HID; + //idle_rate = MSB(SetupPkt.W_Value); + idle_rate = SetupPkt.W_Value.v[1]; + break; + case GET_PROTOCOL: + ctrl_trf_session_owner = MUID_HID; + pSrc.bRam = (uint8_t*)&active_protocol;// Set source + usb_stat.ctrl_trf_mem = _RAM; // Set memory type + wCount.v[0] = 1; // Set data count + break; + case SET_PROTOCOL: + ctrl_trf_session_owner = MUID_HID; + //active_protocol = LSB(SetupPkt.W_Value); + active_protocol = SetupPkt.W_Value.v[0]; + break; + }//end switch(SetupPkt.bRequest) + +}//end USBCheckHIDRequest + +void HIDGetReportHandler(void) +{ + // ctrl_trf_session_owner = MUID_HID; +}//end HIDGetReportHandler + +void HIDSetReportHandler(void) +{ + // ctrl_trf_session_owner = MUID_HID; + // pDst.bRam = (byte*)&hid_report_out; +}//end HIDSetReportHandler + +/** U S E R A P I ***********************************************************/ + +/****************************************************************************** + * Function: void HIDInitEP(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: HIDInitEP initializes HID endpoints, buffer descriptors, + * internal state-machine, and variables. + * It should be called after the USB host has sent out a + * SET_CONFIGURATION request. + * See USBStdSetCfgHandler() in usb9.c for examples. + * + * Note: None + *****************************************************************************/ +void HIDInitEP(void) +{ + hid_rpt_rx_len =0; + + HID_UEP = EP_OUT_IN|HSHK_EN; // Enable 2 data pipes + + //Arm the OUT interrupt endpoint so the host can send the first packet of data. + HID_BD_OUT.Cnt = sizeof(hid_report_out); // Set buffer size + HID_BD_OUT.ADR = (uint8_t*)&hid_report_out; // Set buffer address + HID_BD_OUT.Stat._byte = _DAT0|_DTSEN; // Set status + HID_BD_OUT.Stat._byte |= _USIE; + + /* + * Do not have to init Cnt of IN pipes here. + * Reason: Number of bytes to send to the host + * varies from one transaction to + * another. Cnt should equal the exact + * number of bytes to transmit for + * a given IN transaction. + * This number of bytes will only + * be known right before the data is + * sent. + */ + HID_BD_IN.ADR = (uint8_t*)&hid_report_in; // Set buffer address + HID_BD_IN.Stat._byte = _UCPU|_DAT1; // Set status + +}//end HIDInitEP + +/****************************************************************************** + * Function: void HIDTxReport(char *buffer, byte len) + * + * PreCondition: mHIDTxIsBusy() must return false. + * + * Value of 'len' must be equal to or smaller than + * HID_INT_IN_EP_SIZE + * For an interrupt endpoint, the largest buffer size is + * 64 bytes. + * + * Input: buffer : Pointer to the starting location of data bytes + * len : Number of bytes to be transferred + * + * Output: None + * + * Side Effects: None + * + * Overview: Use this macro to transfer data located in data memory. + * + * Remember: mHIDTxIsBusy() must return false before user + * can call this function. + * Unexpected behavior will occur if this function is called + * when mHIDTxIsBusy() == 0 + * + * Typical Usage: + * if(!mHIDTxIsBusy()) + * HIDTxReport(buffer, 3); + * + * Note: None + *****************************************************************************/ +void HIDTxReport(char *buffer, uint8_t len) +{ + uint8_t i; + + /* + * Value of len should be equal to or smaller than HID_INT_IN_EP_SIZE. + * This check forces the value of len to meet the precondition. + */ + if(len > HID_INT_IN_EP_SIZE) + len = HID_INT_IN_EP_SIZE; + + /* + * Copy data from user's buffer to a USB module accessible RAM packet buffer + */ + for (i = 0; i < len; i++) + hid_report_in[i] = buffer[i]; + + HID_BD_IN.Cnt = len; + mUSBBufferReady(HID_BD_IN); + +}//end HIDTxReport + +/****************************************************************************** + * Function: byte HIDRxReport(char *buffer, byte len) + * + * PreCondition: Value of input argument 'len' should be smaller than the + * maximum endpoint size responsible for receiving report + * data from USB host for HID class. + * Input argument 'buffer' should point to a buffer area that + * is bigger or equal to the size specified by 'len'. + * + * Input: buffer : Pointer to where received bytes are to be stored + * len : The number of bytes expected. + * + * Output: The number of bytes copied to buffer. + * + * Side Effects: Publicly accessible variable hid_rpt_rx_len is updated + * with the number of bytes copied to buffer. + * Once HIDRxReport is called, subsequent retrieval of + * hid_rpt_rx_len can be done by calling macro + * mHIDGetRptRxLength(). + * + * Overview: HIDRxReport copies a string of bytes received through + * USB HID OUT endpoint to a user's specified location. + * It is a non-blocking function. It does not wait + * for data if there is no data available. Instead it returns + * '0' to notify the caller that there is no data available. + * + * Note: If the actual number of bytes received is larger than the + * number of bytes expected (len), only the expected number + * of bytes specified will be copied to buffer. + * If the actual number of bytes received is smaller than the + * number of bytes expected (len), only the actual number + * of bytes received will be copied to buffer. + *****************************************************************************/ +uint8_t HIDRxReport(char *buffer, uint8_t len) +{ + hid_rpt_rx_len = 0; + + if(!mHIDRxIsBusy()) + { + /* + * Adjust the expected number of bytes to equal + * the actual number of bytes received. + */ + if(len > HID_BD_OUT.Cnt) + len = HID_BD_OUT.Cnt; + + /* + * Copy data from dual-ram buffer to user's buffer + */ + for(hid_rpt_rx_len = 0; hid_rpt_rx_len < len; hid_rpt_rx_len++) + buffer[hid_rpt_rx_len] = hid_report_out[hid_rpt_rx_len]; + + /* + * Prepare dual-ram buffer for next OUT transaction + */ + HID_BD_OUT.Cnt = sizeof(hid_report_out); + mUSBBufferReady(HID_BD_OUT); + }//end if + + return hid_rpt_rx_len; + +}//end HIDRxReport + +#endif //def USB_USE_HID + +/** EOF hid.c ***************************************************************/ diff --git a/bootloader_hacked_from_mla/src/usb_device_hid.h b/bootloader_hacked_from_mla/src/usb_device_hid.h new file mode 100644 index 0000000..12729d7 --- /dev/null +++ b/bootloader_hacked_from_mla/src/usb_device_hid.h @@ -0,0 +1,163 @@ +/******************************************************************************* +Copyright 2016 Microchip Technology Inc. (www.microchip.com) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +To request to license the code under the MLA license (www.microchip.com/mla_license), +please contact mla_licensing@microchip.com +*******************************************************************************/ +#ifndef HID_H +#define HID_H + +/** I N C L U D E S **********************************************************/ +#include "typedefs.h" + +/** D E F I N I T I O N S ****************************************************/ + +/* Class-Specific Requests */ +#define GET_REPORT 0x01 +#define GET_IDLE 0x02 +#define GET_PROTOCOL 0x03 +#define SET_REPORT 0x09 +#define SET_IDLE 0x0A +#define SET_PROTOCOL 0x0B + +/* Class Descriptor Types */ +#define DSC_HID 0x21 +#define DSC_RPT 0x22 +#define DSC_PHY 0x23 + +/* Protocol Selection */ +#define BOOT_PROTOCOL 0x00 +#define RPT_PROTOCOL 0x01 + + +/* HID Interface Class Code */ +#define HID_INTF 0x03 + +/* HID Interface Class SubClass Codes */ +#define BOOT_INTF_SUBCLASS 0x01 + +/* HID Interface Class Protocol Codes */ +#define HID_PROTOCOL_NONE 0x00 +#define HID_PROTOCOL_KEYBOAD 0x01 +#define HID_PROTOCOL_MOUSE 0x02 + +/****************************************************************************** + * Macro: (bit) mHIDRxIsBusy(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This macro is used to check if HID OUT endpoint is + * busy (owned by SIE) or not. + * Typical Usage: if(mHIDRxIsBusy()) + * + * Note: None + *****************************************************************************/ +#define mHIDRxIsBusy() HID_BD_OUT.Stat.UOWN + +/****************************************************************************** + * Macro: (bit) mHIDTxIsBusy(void) + * + * PreCondition: None + * + * Input: None + * + * Output: None + * + * Side Effects: None + * + * Overview: This macro is used to check if HID IN endpoint is + * busy (owned by SIE) or not. + * Typical Usage: if(mHIDTxIsBusy()) + * + * Note: None + *****************************************************************************/ +#define mHIDTxIsBusy() HID_BD_IN.Stat.UOWN + +/****************************************************************************** + * Macro: uint8_t mHIDGetRptRxLength(void) + * + * PreCondition: None + * + * Input: None + * + * Output: mHIDGetRptRxLength returns hid_rpt_rx_len + * + * Side Effects: None + * + * Overview: mHIDGetRptRxLength is used to retrieve the number of bytes + * copied to user's buffer by the most recent call to + * HIDRxReport function. + * + * Note: None + *****************************************************************************/ +#define mHIDGetRptRxLength() hid_rpt_rx_len + + +/* HID macros */ +#define mUSBGetHIDDscAdr(ptr) \ +{ \ + if(usb_active_cfg == 1) \ + ptr = (ROM uint8_t*)&cfg01.hid_i00a00; \ +} + +#define mUSBGetHIDRptDscAdr(ptr) \ +{ \ + if(usb_active_cfg == 1) \ + ptr = (ROM uint8_t*)&hid_rpt01; \ +} + +#define mUSBGetHIDRptDscSize(count) \ +{ \ + if(usb_active_cfg == 1) \ + count = sizeof(hid_rpt01); \ +} + + + +/** S T R U C T U R E S ******************************************************/ +typedef struct _USB_HID_DSC_HEADER +{ + uint8_t bDscType; + uint16_t wDscLength; +} USB_HID_DSC_HEADER; + +typedef struct _USB_HID_DSC +{ + uint8_t bLength; uint8_t bDscType; uint16_t bcdHID; + uint8_t bCountryCode; uint8_t bNumDsc; + USB_HID_DSC_HEADER hid_dsc_header[HID_NUM_OF_DSC]; + /* + * HID_NUM_OF_DSC is defined in autofiles\usb_config.h + */ +} USB_HID_DSC; + +/** E X T E R N S ************************************************************/ +extern uint8_t hid_rpt_rx_len; +extern ROM uint8_t hid_rpt01[HID_RPT01_SIZE]; + + +/** P U B L I C P R O T O T Y P E S *****************************************/ +void HIDInitEP(void); +void USBCheckHIDRequest(void); +void HIDTxReport(char *buffer, uint8_t len); +uint8_t HIDRxReport(char *buffer, uint8_t len); + +#endif //HID_H