From 032a83e9e1bda3b4724870ad65310414a8020351 Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Mon, 23 Feb 2009 07:08:24 +0000 Subject: [PATCH] Moved all source to the trunk directory. --- .../AVRISP_Firmware_Design.txt | 176 ++ .../AVRISP_Programmer/AVRISP_Programmer.aps | 1 + .../AVRISP_Programmer/AVRISP_Programmer.c | 886 ++++++++++ .../AVRISP_Programmer/AVRISP_Programmer.h | 194 +++ .../AVRISP_Programmer/AVRISP_Programmer.txt | 89 + .../AVRISP_Programmer_Picture.jpg | Bin 0 -> 74610 bytes Projects/AVRISP_Programmer/Descriptors.c | 263 +++ Projects/AVRISP_Programmer/Descriptors.h | 98 ++ Projects/AVRISP_Programmer/Doxygen.conf | 1485 +++++++++++++++++ .../LUFA AVRISP_Programmer.inf | 55 + Projects/AVRISP_Programmer/RingBuff.c | 120 ++ Projects/AVRISP_Programmer/RingBuff.h | 116 ++ .../Sample_Programming_Session.txt | 104 ++ Projects/AVRISP_Programmer/makefile | 704 ++++++++ Projects/Magstripe/CircularBitBuffer.c | 113 ++ Projects/Magstripe/CircularBitBuffer.h | 95 ++ Projects/Magstripe/Descriptors.c | 247 +++ Projects/Magstripe/Descriptors.h | 98 ++ Projects/Magstripe/Doxygen.conf | 1485 +++++++++++++++++ Projects/Magstripe/Magstripe.aps | 1 + Projects/Magstripe/Magstripe.c | 436 +++++ Projects/Magstripe/Magstripe.h | 121 ++ Projects/Magstripe/Magstripe.txt | 85 + Projects/Magstripe/MagstripeHW.h | 100 ++ Projects/Magstripe/makefile | 712 ++++++++ Projects/makefile | 25 + 26 files changed, 7809 insertions(+) create mode 100644 Projects/AVRISP_Programmer/AVRISP_Firmware_Design.txt create mode 100644 Projects/AVRISP_Programmer/AVRISP_Programmer.aps create mode 100644 Projects/AVRISP_Programmer/AVRISP_Programmer.c create mode 100644 Projects/AVRISP_Programmer/AVRISP_Programmer.h create mode 100644 Projects/AVRISP_Programmer/AVRISP_Programmer.txt create mode 100644 Projects/AVRISP_Programmer/AVRISP_Programmer_Picture.jpg create mode 100644 Projects/AVRISP_Programmer/Descriptors.c create mode 100644 Projects/AVRISP_Programmer/Descriptors.h create mode 100644 Projects/AVRISP_Programmer/Doxygen.conf create mode 100644 Projects/AVRISP_Programmer/LUFA AVRISP_Programmer.inf create mode 100644 Projects/AVRISP_Programmer/RingBuff.c create mode 100644 Projects/AVRISP_Programmer/RingBuff.h create mode 100644 Projects/AVRISP_Programmer/Sample_Programming_Session.txt create mode 100644 Projects/AVRISP_Programmer/makefile create mode 100644 Projects/Magstripe/CircularBitBuffer.c create mode 100644 Projects/Magstripe/CircularBitBuffer.h create mode 100644 Projects/Magstripe/Descriptors.c create mode 100644 Projects/Magstripe/Descriptors.h create mode 100644 Projects/Magstripe/Doxygen.conf create mode 100644 Projects/Magstripe/Magstripe.aps create mode 100644 Projects/Magstripe/Magstripe.c create mode 100644 Projects/Magstripe/Magstripe.h create mode 100644 Projects/Magstripe/Magstripe.txt create mode 100644 Projects/Magstripe/MagstripeHW.h create mode 100644 Projects/Magstripe/makefile create mode 100644 Projects/makefile diff --git a/Projects/AVRISP_Programmer/AVRISP_Firmware_Design.txt b/Projects/AVRISP_Programmer/AVRISP_Firmware_Design.txt new file mode 100644 index 0000000000..643454d481 --- /dev/null +++ b/Projects/AVRISP_Programmer/AVRISP_Firmware_Design.txt @@ -0,0 +1,176 @@ +Instructions for converting the LUFA USBtoSerial Demo to an AVR ISP Programmer. +By Opendous Inc., Copyright under the Creative Commons Attribution License: +http://creativecommons.org/licenses/by/3.0/ + +1) Start with the LUFA/Demos/USBtoSerial firmware. + - rename USBtoSerial.c, USBtoSerial.h, and USBtoSerial.aps to + AVRISP_Programmer.* + - edit AVRISP_Programmer.aps and rename all instances of "USBtoSerial" to + "AVRISP_Programmer" + - copy AVRISP_Programmer.txt from an older version of AVRISP_Programmer + +2) Edit makefile by changing TARGET from "USBtoSerial" to "AVRISP_Programmer" + +3) Edit AVRISP_Programmer.h: + - change ifdef _USB_TO_SERIAL_H to _AVRISP_PROGRAMMER_H_ + - rename ReconfigureUSART(void) to ReconfigureSPI(void) + - add void processHostSPIRequest(void); & void delay_ms(uint8_t dly); + - replace the define for Serial.h with one for SPI.h: + #include + +4) Make alterations to Descriptors.c + - change manufacturer string to "www.AVRopendous.org", length=19 + - change product string to "LUFA-Based AVR ISP Programmer", length=29 + +5) Edit Ringbuff.h to enable the Peek Command: #define BUFF_USEPEEK + +6) Edit AVRISP_Programmer.c: + - change #include "USBtoSerial.h" to #include "AVRISP_Programmer.h" + - change BUTTLOADTAG(ProjName to "LUFA AVR910 ISP Programmer" + - in main(), rename ReconfigureUSART() to Reconfigure(); + - in EVENT_HANDLER(USB_UnhandledControlPacket), rename ReconfigureUSART + - delete the ISRs: ISR(USART1_RX_vect) & ISR(USART1_TX_vect) + - delete ReconfigureUSART(void) + - add void ReconfigureSPI(void), void processHostSPIRequest(void), + and void delay_ms(uint8_t dly) from a previous version + - add Timer1 and SPI initialization code to main(): + /* Hardware Initialization */ + //LEDs_Init(); + DDRB = 0; + PORTB = 0; + DDRC |= ((1 << PC2) | (1 << PC4) | (1 << PC5) | (1 << PC6) | (1 << PC7)); //AT90USBxx2 + // PC2 is also used for RESET, so set it HIGH initially - note 'P' command sets it to LOW (Active) + PORTC |= ((1 << PC2) | (1 << PC4) | (1 << PC5) | (1 << PC6) | (1 << PC7)); //AT90USBxx2 + DDRD = 0; + PORTD = (1 << PB7); // only PB7(HWB) should be High as this is the bootloader pin + // Prepare PortB for SPI - set PB0(^SS), PB1(SCK), PB2(MOSI) as output as well as all other pins except PB3(MISO) + DDRB = (1 << PB0) | (1 << PB1) | (1 << PB2) | (0 << PB3) | (1 << PB4) | (1 << PB5) | (1 << PB6) | (1 << PB7); + PORTB |= (1 << PB0); + + // initialize Timer1 for use in delay function + TCCR1A = 0; + //TCCR1B = (1 << CS10); // no prescaling, use CLK + TCCR1B = ((1 << CS12) | (1 << CS10)); // prescale by CLK/1024 + // 8MHz/1024 = 7813 ticks per second --> ~8 ticks per millisecond (ms) + timerval = TCNT1; // start timer1 + + - In TASK(CDC_Task) in the + if (USB_IsConnected) { + if (Endpoint_ReadWriteAllowed()) { + while (Endpoint_BytesInEndpoint()) { + ... + structure, after Buffer_StoreElement(&Rx_Buffer, Endpoint_Read_Byte()): + + /* Each time there is an element, check which comand should be + run and if enough data is available to run that command. + There are 1-byte, 2-byte, 3-byte, 4-byte commands, and 5-byte commands + Remember that the "which command" byte counts as 1 */ + if (Rx_Buffer.Elements == 0) { + // do nothing, wait for data + } else { + tempByte = Buffer_PeekElement(&Rx_Buffer); // peek at first element + + /* make sure the issued command and associated data are all ready */ + if (Rx_Buffer.Elements == 1) { // zero data byte command + if ((tempByte == 'P') | (tempByte == 'a') | (tempByte == 'm') | + (tempByte == 'R') | (tempByte == 'd') | (tempByte == 'e') | + (tempByte == 'L') | (tempByte == 's') | (tempByte == 't') | + (tempByte == 'S') | (tempByte == 'V') | (tempByte == 'v') | + (tempByte == 'p') | (tempByte == 'F')) { + processHostSPIRequest(); // command has enough data, process it + } + } else if (Rx_Buffer.Elements == 2) { // one data byte command + if ((tempByte == 'T') | (tempByte == 'c') | (tempByte == 'C') | + (tempByte == 'D') | (tempByte == 'l') | (tempByte == 'f') | + (tempByte == 'x') | (tempByte == 'y')) { + processHostSPIRequest(); // command has enough data, process it + } + } else if (Rx_Buffer.Elements == 3) { // two data byte command + if ((tempByte == 'A') | (tempByte == 'Z')) { + processHostSPIRequest(); // command has enough data, process it + } + } else if (Rx_Buffer.Elements == 4) { // three data byte command + if ((tempByte == ':')) { + processHostSPIRequest(); // command has enough data, process it + } + } else if (Rx_Buffer.Elements == 5) { // four data byte command + if ((tempByte == '.')) { + processHostSPIRequest(); // command has enough data, process it + } + } else { + // do nothing + } + } + + - need to add code to flush the buffer. Change: + /* Check if Rx buffer contains data */ + if (Rx_Buffer.Elements) + { + /* Initiate the transmission of the buffer contents if USART idle*/ + if (!(Transmitting)) + { + Transmitting = true; + Serial_TxByte(Buffer_GetElement(&Rx_Buffer)); + } + } + To: + /* Check if Rx buffer contains data */ + if (Rx_Buffer.Elements) + { + /* Initiate the transmission of the buffer contents if USART idle*/ + if (!(Transmitting)) + { + Transmitting = true; + /* The following flushes the receive buffer to prepare for new + data and commands. Need to flush the buffer as the command + byte which is peeked above needs to be dealt with, otherwise + the command bytes will overflow the buffer eventually */ + //Buffer_GetElement(&Rx_Buffer); // also works + Buffer_Initialize(&Rx_Buffer); + } + } + + - need to add the following defines and globals: + #define RESETPORT PORTB + #define RESETPIN PB0 + #define RESETPORT2 PORTC + #define RESETPIN2 PC2 + #define CR_HEX '\r' + + #define DELAY_VERYSHORT 0x01 + #define DELAY_SHORT 0x02 + #define DELAY_MEDIUM 0x03 + #define DELAY_LONG 0x05 + #define DELAY_MULTIPLE 0x04 + + /* AVR Device Codes - Can have a maximum of 14 but can be any you want. + Note that these are completely irrelevent. If AVRdude supports a + device, then that device is programmable. Use -F switch to ignore + device codes. */ + #define AVRDEVCODE01 0x55 /* ATtiny12 */ + #define AVRDEVCODE02 0x56 /* ATtiny15 */ + #define AVRDEVCODE03 0x5E /* ATtiny261 */ + #define AVRDEVCODE04 0x76 /* ATmega8 */ + #define AVRDEVCODE05 0x74 /* ATmega16 */ + #define AVRDEVCODE06 0x72 /* ATmega32 */ + #define AVRDEVCODE07 0x45 /* ATmega64 */ + #define AVRDEVCODE08 0x74 /* ATmega644 */ + #define AVRDEVCODE09 0x43 /* ATmega128 */ + #define AVRDEVCODE10 0x63 /* ATmega162 */ + #define AVRDEVCODE11 0x78 /* ATmega169 */ + #define AVRDEVCODE12 0x6C /* AT90S4434 */ + #define AVRDEVCODE13 0x38 /* AT90S8515A */ + #define AVRDEVCODE14 0x65 /* AT90S8555 */ + + /* some global variables used throughout */ + uint8_t tempIOreg = 0; + uint8_t tempIOreg2 = 0; + uint8_t tempIOreg3 = 0; + uint8_t tempIOreg4 = 0; + uint8_t dataWidth = 0; + uint8_t firstRun = 1; + uint8_t deviceCode = 0; + uint8_t tempByte = 0; + uint16_t currAddress = 0; + uint16_t timerval = 0; + diff --git a/Projects/AVRISP_Programmer/AVRISP_Programmer.aps b/Projects/AVRISP_Programmer/AVRISP_Programmer.aps new file mode 100644 index 0000000000..7480023174 --- /dev/null +++ b/Projects/AVRISP_Programmer/AVRISP_Programmer.aps @@ -0,0 +1 @@ +AVRISP_Programmer30-Sep-2008 14:18:3930-Sep-2008 14:18:52241030-Sep-2008 14:18:3944, 14, 0, 589AVR GCCC:\Users\Dean\Documents\Electronics\Projects\WORK\MyUSBWORK\Demos\AVRISP_Programmer\falseR00R01R02R03R04R05R06R07R08R09R10R11R12R13R14R15R16R17R18R19R20R21R22R23R24R25R26R27R28R29R30R31Auto000Descriptors.cRingBuff.cAVRISP_Programmer.cDescriptors.hRingBuff.hAVRISP_Programmer.hmakefiledefaultYESmakefileatmega128111AVRISP_Programmer.elfdefault\1-Wall -gdwarf-2 -std=gnu99 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enumsdefault1C:\WinAVR-20080512\bin\avr-gcc.exeC:\WinAVR-20080512\utils\bin\make.exe diff --git a/Projects/AVRISP_Programmer/AVRISP_Programmer.c b/Projects/AVRISP_Programmer/AVRISP_Programmer.c new file mode 100644 index 0000000000..4dc18cd625 --- /dev/null +++ b/Projects/AVRISP_Programmer/AVRISP_Programmer.c @@ -0,0 +1,886 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + AVR ISP Programmer code Copyright 2009 Opendous Inc. (www.opendous.org) + For more info and usage instructions for this firmware, visit: + http://code.google.com/p/avropendous/wiki/AVR_ISP_Programmer + + Note that this firmware is designed to work with AVRdude: + http://savannah.nongnu.org/projects/avrdude + But should work with other software that supports the AVR910 ISP + programmer or STK200 hardware. + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/* + Usage: + avrdude -vv -F -P COM7 -c avr910 -p t261 + Note -F flag which overrides signature check and enables programming + of any "In-System Programmable via SPI Port" AVR MCU. Part number, + t261, should be set to your target device. + avrdude -vv -F -P COM7 -c avr910 -p t261 -U flash:w:PROG.hex + PROG.hex is the hex file to program your t261 AVR with + avrdude -vv -F -P COM7 -b 115200 -c avr910 -p t261 -U flash:w:test.hex + The -b 115200 sets the SPI clock to 62.5kHz from the default 125kHz and may + work when the default programming speed fails. + AVROSP.exe -dATtiny261 -cCOM7 -rf + AVRosp is the Open Source AVR ISP Programming Software available from Atmel.com + + Note: on Linux systems, COM7 should be replaced with someting like /dev/ttyACM0 + You can determine this value by running dmesg after plugging in the device + Note: you must RESET the programmer after each use (AVRdude session). + + Note: If you experience errors with older devices, try changing the DELAY defines + + MISO, MOSI, and SCK are connected directly from the AVRopendous board + to the pin of the same functionality on the target. RESET pin on the target + can be connected either to SS (PB0), or PC2. Do not have any other pins + connected - especially HWB pin, to avoid unintentional behaviour. + + AVR910 functionality was overlayed on USBtoSerial functionality. + Keep this in mind when looking over the code. + Default target speed is 125kHz and corresponds to 19200 baud, which + is the default setting for AVRdude. + + Changing "Baud-Rate" will change the SPI speed. Defualt SPI clock speed + is 8Mhz / 4 = 2MHz. 8Mhz is the device clock speed. This is the setting at + 9600 baud. The following is a table of baud-rate vs. SPI Speed that will result + 9600 = 2Mhz + 14400 = 1MHz + 19200 = 125kHz (AVRdude Default) + 38400 = 250kHz + 57600 = 500kHz + 115200 = 62.5kHz + + Before running, you will need to install the INF file that + is located in the project directory. This will enable + Windows to use its inbuilt CDC drivers, negating the need + for special Windows drivers for the device. To install, + right-click the .INF file and choose the Install option. +*/ + +/* TODO: - fix the requirement that a RESET must be performed after each session, which + is only an issue under Windows. Everything works fine under Linux +*/ + +#include "AVRISP_Programmer.h" + +/* Project Tags, for reading out using the ButtLoad project */ +BUTTLOADTAG(ProjName, "LUFA AVR910 ISP Programmer"); +BUTTLOADTAG(BuildTime, __TIME__); +BUTTLOADTAG(BuildDate, __DATE__); +BUTTLOADTAG(LUFAVersion, "LUFA V" LUFA_VERSION_STRING); + + +#define RESETPORT PORTB +#define RESETPIN PB0 +#define RESETPORT2 PORTC +#define RESETPIN2 PC2 +#define CR_HEX '\r' + +#define DELAY_VERYSHORT 0x01 +#define DELAY_SHORT 0x02 +#define DELAY_MEDIUM 0x03 +#define DELAY_LONG 0x05 +#define DELAY_MULTIPLE 0x02 + + +/* AVR Device Codes - Can have a maximum of 14 but can be any you want. + Note that these are completely irrelevent. If AVRdude supports a device, + then that device is programmable. Use -F switch to ignore device codes. */ +#define AVRDEVCODE01 0x55 /* ATtiny12 */ +#define AVRDEVCODE02 0x56 /* ATtiny15 */ +#define AVRDEVCODE03 0x5E /* ATtiny261 */ +#define AVRDEVCODE04 0x76 /* ATmega8 */ +#define AVRDEVCODE05 0x74 /*ATmega16 */ +#define AVRDEVCODE06 0x72 /* ATmega32 */ +#define AVRDEVCODE07 0x45 /* ATmega64 */ +#define AVRDEVCODE08 0x74 /* ATmega644 */ +#define AVRDEVCODE09 0x43 /* ATmega128 */ +#define AVRDEVCODE10 0x63 /* ATmega162 */ +#define AVRDEVCODE11 0x78 /* ATmega169 */ +#define AVRDEVCODE12 0x6C /* AT90S4434 */ +#define AVRDEVCODE13 0x38 /* AT90S8515A */ +#define AVRDEVCODE14 0x65 /* AT90S8555 */ + + +/* Scheduler Task List */ +TASK_LIST +{ + { Task: USB_USBTask , TaskStatus: TASK_STOP }, + { Task: CDC_Task , TaskStatus: TASK_STOP }, +}; + +/* Globals: */ +/** Contains the current baud rate and other settings of the virtual serial port. + * + These values are set by the host via a class-specific request, and the physical USART should be reconfigured to match the + new settings each time they are changed by the host. + */ +CDC_Line_Coding_t LineCoding = { BaudRateBPS: 9600, + CharFormat: OneStopBit, + ParityType: Parity_None, + DataBits: 8 }; + +/** Ring (circular) buffer to hold the RX data - data from the host to the attached device on the serial port. */ +RingBuff_t Rx_Buffer; + +/** Ring (circular) buffer to hold the TX data - data from the attached device on the serial port to the host. */ +RingBuff_t Tx_Buffer; + +/** Flag to indicate if the USART is currently transmitting data from the Rx_Buffer circular buffer. */ +volatile bool Transmitting = false; + + +/* some global variables used throughout */ +uint8_t tempIOreg = 0; +uint8_t tempIOreg2 = 0; +uint8_t tempIOreg3 = 0; +uint8_t tempIOreg4 = 0; +uint8_t dataWidth = 0; +uint8_t firstRun = 1; +uint8_t deviceCode = 0; +uint8_t tempByte = 0; +uint16_t currAddress = 0; +uint16_t timerval = 0; + + + +/** Main program entry point. This routine configures the hardware required by the application, then + starts the scheduler to run the application tasks. + */ +int main(void) +{ + /* Disable watchdog if enabled by bootloader/fuses */ + MCUSR &= ~(1 << WDRF); + wdt_disable(); + + /* Disable Clock Division */ + SetSystemClockPrescaler(0); + + /* Hardware Initialization */ + LEDs_Init(); + ReconfigureSPI(); + // prepare PortB + DDRB = 0; + PORTB = 0; + DDRC |= ((1 << PC2) | (1 << PC4) | (1 << PC5) | (1 << PC6) | (1 << PC7)); //AT90USBxx2 + // PC2 is also used for RESET, so set it HIGH initially - note 'P' command sets it to LOW (Active) + PORTC |= ((1 << PC2) | (1 << PC4) | (1 << PC5) | (1 << PC6) | (1 << PC7)); //AT90USBxx2 + DDRD = 0; + PORTD = (1 << PB7); // only PB7(HWB) should be High as this is the bootloader pin + // Prepare PortB for SPI - set PB0(^SS), PB1(SCK), PB2(MOSI) as output as well as all other pins except PB3(MISO) + DDRB = (1 << PB0) | (1 << PB1) | (1 << PB2) | (0 << PB3) | (1 << PB4) | (1 << PB5) | (1 << PB6) | (1 << PB7); + PORTB |= (1 << PB0); + // make sure DataFlash devices to not interfere - deselect them by setting PE0 and PE1 HIGH: + PORTE = 0xFF; + DDRE = 0xFF; + + // initialize Timer1 for use in delay function + TCCR1A = 0; + //TCCR1B = (1 << CS10); // no prescaling, use CLK + TCCR1B = ((1 << CS12) | (1 << CS10)); // prescale by CLK/1024 + // 8MHz/1024 = 7813 ticks per second --> ~8 ticks per millisecond (ms) + timerval = TCNT1; // start timer1 + + + /* Ringbuffer Initialization */ + Buffer_Initialize(&Rx_Buffer); + Buffer_Initialize(&Tx_Buffer); + + /* Indicate USB not ready */ + UpdateStatus(Status_USBNotReady); + + /* Initialize Scheduler so that it can be used */ + Scheduler_Init(); + + /* Initialize USB Subsystem */ + USB_Init(); + + /* Scheduling - routine never returns, so put this last in the main function */ + Scheduler_Start(); +} + +/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and + starts the library USB task to begin the enumeration and USB management process. + */ +EVENT_HANDLER(USB_Connect) +{ + /* Start USB management task */ + Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); + + /* Indicate USB enumerating */ + UpdateStatus(Status_USBEnumerating); +} + +/** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via + the status LEDs and stops the USB management and CDC management tasks. + */ +EVENT_HANDLER(USB_Disconnect) +{ + /* Stop running CDC and USB management tasks */ + Scheduler_SetTaskMode(CDC_Task, TASK_STOP); + Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); + + /* Indicate USB not ready */ + UpdateStatus(Status_USBNotReady); +} + +/** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration + of the USB device after enumeration - the device endpoints are configured and the CDC management task started. + */ +EVENT_HANDLER(USB_ConfigurationChanged) +{ + /* Setup CDC Notification, Rx and Tx Endpoints */ + Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT, + ENDPOINT_DIR_IN, CDC_NOTIFICATION_EPSIZE, + ENDPOINT_BANK_SINGLE); + + Endpoint_ConfigureEndpoint(CDC_TX_EPNUM, EP_TYPE_BULK, + ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE, + ENDPOINT_BANK_SINGLE); + + Endpoint_ConfigureEndpoint(CDC_RX_EPNUM, EP_TYPE_BULK, + ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE, + ENDPOINT_BANK_SINGLE); + + /* Indicate USB connected and ready */ + UpdateStatus(Status_USBReady); + + /* Start CDC task */ + Scheduler_SetTaskMode(CDC_Task, TASK_RUN); +} + +/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific + control requests that are not handled internally by the USB library (including the CDC control commands, + which are all issued via the control endpoint), so that they can be handled appropriately for the application. + */ +EVENT_HANDLER(USB_UnhandledControlPacket) +{ + uint8_t* LineCodingData = (uint8_t*)&LineCoding; + + /* Process CDC specific control requests */ + switch (bRequest) + { + case REQ_GetLineEncoding: + if (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + /* Acknowedge the SETUP packet, ready for data transfer */ + Endpoint_ClearSetupReceived(); + + /* Write the line coding data to the control endpoint */ + Endpoint_Write_Control_Stream_LE(LineCodingData, sizeof(LineCoding)); + + /* Finalize the stream transfer to send the last packet or clear the host abort */ + Endpoint_ClearSetupOUT(); + } + + break; + case REQ_SetLineEncoding: + if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + /* Acknowedge the SETUP packet, ready for data transfer */ + Endpoint_ClearSetupReceived(); + + /* Read the line coding data in from the host into the global struct */ + Endpoint_Read_Control_Stream_LE(LineCodingData, sizeof(LineCoding)); + + /* Finalize the stream transfer to clear the last packet from the host */ + Endpoint_ClearSetupIN(); + + /* Reconfigure the USART with the new settings */ + ReconfigureSPI(); + } + + break; + case REQ_SetControlLineState: + if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { +#if 0 + /* NOTE: Here you can read in the line state mask from the host, to get the current state of the output handshake + lines. The mask is read in from the wValue parameter, and can be masked against the CONTROL_LINE_OUT_* masks + to determine the RTS and DTR line states using the following code: + */ + + uint16_t wIndex = Endpoint_Read_Word_LE(); + + // Do something with the given line states in wIndex +#endif + + /* Acknowedge the SETUP packet, ready for data transfer */ + Endpoint_ClearSetupReceived(); + + /* Send an empty packet to acknowedge the command */ + Endpoint_ClearSetupIN(); + } + + break; + } +} + +/** Task to manage CDC data transmission and reception to and from the host, from and to the physical USART. */ +TASK(CDC_Task) +{ + if (USB_IsConnected) + { +#if 0 + /* NOTE: Here you can use the notification endpoint to send back line state changes to the host, for the special RS-232 + handshake signal lines (and some error states), via the CONTROL_LINE_IN_* masks and the following code: + */ + + USB_Notification_Header_t Notification = (USB_Notification_Header_t) + { + NotificationType: (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), + Notification: NOTIF_SerialState, + wValue: 0, + wIndex: 0, + wLength: sizeof(uint16_t), + }; + + uint16_t LineStateMask; + + // Set LineStateMask here to a mask of CONTROL_LINE_IN_* masks to set the input handshake line states to send to the host + + Endpoint_SelectEndpoint(CDC_NOTIFICATION_EPNUM); + Endpoint_Write_Stream_LE(&Notification, sizeof(Notification)); + Endpoint_Write_Stream_LE(&LineStateMask, sizeof(LineStateMask)); + Endpoint_ClearCurrentBank(); +#endif + + /* Select the Serial Rx Endpoint */ + Endpoint_SelectEndpoint(CDC_RX_EPNUM); + + if (Endpoint_ReadWriteAllowed()) + { + /* Read the received data endpoint into the transmission buffer */ + while (Endpoint_BytesInEndpoint()) + { + /* Wait until the buffer has space for a new character */ + while (!((BUFF_STATICSIZE - Rx_Buffer.Elements))); + + /* Store each character from the endpoint */ + Buffer_StoreElement(&Rx_Buffer, Endpoint_Read_Byte()); + + + + + /* Each time there is an element, check which comand should be + run and if enough data is available to run that command. + There are 1-byte, 2-byte, 3-byte, 4-byte commands, and 5-byte commands + Remember that the "which command" byte counts as 1 */ + if (Rx_Buffer.Elements == 0) { + // do nothing, wait for data + } else { + tempByte = Buffer_PeekElement(&Rx_Buffer); // peek at first element + + /* make sure the issued command and associated data are all ready */ + if (Rx_Buffer.Elements == 1) { // zero data byte command + if ((tempByte == 'P') | (tempByte == 'a') | (tempByte == 'm') | + (tempByte == 'R') | (tempByte == 'd') | (tempByte == 'e') | + (tempByte == 'L') | (tempByte == 's') | (tempByte == 't') | + (tempByte == 'S') | (tempByte == 'V') | (tempByte == 'v') | + (tempByte == 'p') | (tempByte == 'F')) { + processHostSPIRequest(); // command has enough data, process it + } + } else if (Rx_Buffer.Elements == 2) { // one data byte command + if ((tempByte == 'T') | (tempByte == 'c') | (tempByte == 'C') | + (tempByte == 'D') | (tempByte == 'l') | (tempByte == 'f') | + (tempByte == 'x') | (tempByte == 'y')) { + processHostSPIRequest(); // command has enough data, process it + } + } else if (Rx_Buffer.Elements == 3) { // two data byte command + if ((tempByte == 'A') | (tempByte == 'Z')) { + processHostSPIRequest(); // command has enough data, process it + } + } else if (Rx_Buffer.Elements == 4) { // three data byte command + if ((tempByte == ':')) { + processHostSPIRequest(); // command has enough data, process it + } + } else if (Rx_Buffer.Elements == 5) { // four data byte command + if ((tempByte == '.')) { + processHostSPIRequest(); // command has enough data, process it + } + } else { + // do nothing + } + } + + + + } + + /* Clear the endpoint buffer */ + Endpoint_ClearCurrentBank(); + } + + /* Check if Rx buffer contains data */ + if (Rx_Buffer.Elements) + { + /* Initiate the transmission of the buffer contents if USART idle */ + if (!(Transmitting)) + { + Transmitting = true; + /* The following flushes the receive buffer to prepare for new data and commands */ + /* Need to flush the buffer as the command byte which is peeked above needs to be */ + /* dealt with, otherwise the command bytes will overflow the buffer eventually */ + //Buffer_GetElement(&Rx_Buffer); // works also + Buffer_Initialize(&Rx_Buffer); + } + } + + /* Select the Serial Tx Endpoint */ + Endpoint_SelectEndpoint(CDC_TX_EPNUM); + + /* Check if the Tx buffer contains anything to be sent to the host */ + if (Tx_Buffer.Elements) + { + /* Wait until Serial Tx Endpoint Ready for Read/Write */ + while (!(Endpoint_ReadWriteAllowed())); + + /* Check before sending the data if the endpoint is completely full */ + bool IsFull = (Endpoint_BytesInEndpoint() == CDC_TXRX_EPSIZE); + + /* Write the transmission buffer contents to the received data endpoint */ + while (Tx_Buffer.Elements && (Endpoint_BytesInEndpoint() < CDC_TXRX_EPSIZE)) + Endpoint_Write_Byte(Buffer_GetElement(&Tx_Buffer)); + + /* Send the data */ + Endpoint_ClearCurrentBank(); + + /* If a full endpoint was sent, we need to send an empty packet afterwards to terminate the transfer */ + if (IsFull) + { + /* Wait until Serial Tx Endpoint Ready for Read/Write */ + while (!(Endpoint_ReadWriteAllowed())); + + /* Send an empty packet to terminate the transfer */ + Endpoint_ClearCurrentBank(); + } + } + } +} + + + +/** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to + log to a serial port, or anything else that is suitable for status updates. + * + \param CurrentStatus Current status of the system, from the USBtoSerial_StatusCodes_t enum + */ +void UpdateStatus(uint8_t CurrentStatus) +{ + uint8_t LEDMask = LEDS_NO_LEDS; + + /* Set the LED mask to the appropriate LED mask based on the given status code */ + switch (CurrentStatus) + { + case Status_USBNotReady: + LEDMask = (LEDS_LED1); + break; + case Status_USBEnumerating: + LEDMask = (LEDS_LED1 | LEDS_LED2); + break; + case Status_USBReady: + LEDMask = (LEDS_LED2 | LEDS_LED4); + break; + } + + /* Set the board LEDs to the new LED mask */ + LEDs_SetAllLEDs(LEDMask); +} + + +/** Reconfigures SPI to match the current serial port settings issued by the host. */ +void ReconfigureSPI(void) +{ + uint8_t SPCRmask = (1 << SPE) | (1 << MSTR); // always enable SPI as Master + uint8_t SPSRmask = 0; + + /* Determine data width */ + if (LineCoding.ParityType == Parity_Odd) { + dataWidth = 16; + } else if (LineCoding.ParityType == Parity_Even) { + dataWidth = 32; + } else if (LineCoding.ParityType == Parity_None) { + dataWidth = 8; + } + + /* Determine stop bits - 1.5 stop bits is set as 1 stop bit due to hardware limitations */ + /* For SPI, determine whether format is LSB or MSB */ + if (LineCoding.CharFormat == TwoStopBits) { + SPCRmask |= (1 << DORD); + } else if (LineCoding.CharFormat == OneStopBit) { + SPCRmask |= (0 << DORD); + } + + /* Determine data size - 5, 6, 7, or 8 bits are supported */ + /* Changing line coding changes SPI Mode + CPOL=0, CPHA=0 Sample (Rising) Setup (Falling) SPI-Mode0 == 8 bits line coding + CPOL=0, CPHA=1 Setup (Rising) Sample (Falling) SPI-Mode1 == 7 bits line coding + CPOL=1, CPHA=0 Sample (Falling) Setup (Rising) SPI-Mode2 == 6 bits line coding + CPOL=1, CPHA=1 Setup (Falling) Sample (Rising) SPI-Mode3 == 5 bits line coding + */ + if (LineCoding.DataBits == 5) { + SPCRmask |= ((1 << CPOL) | (1 << CPHA)); + } else if (LineCoding.DataBits == 6) { + SPCRmask |= ((1 << CPOL) | (0 << CPHA)); + } else if (LineCoding.DataBits == 7) { + SPCRmask |= ((0 << CPOL) | (1 << CPHA)); + } else if (LineCoding.DataBits == 8) { + SPCRmask |= ((0 << CPOL) | (0 << CPHA)); + } + + + /* Set the USART baud rate register to the desired baud rate value */ + /* also alter the SPI speed via value of baud rate */ + if (LineCoding.BaudRateBPS == 9600) { // 2Mhz SPI (Fosc / 4) + SPCRmask |= ((0 << SPR1) | (0 << SPR0)); + SPSRmask |= (0 << SPI2X); + } else if (LineCoding.BaudRateBPS == 14400) { // 1Mhz SPI (Fosc / 8) + SPCRmask |= ((0 << SPR1) | (1 << SPR0)); + SPSRmask |= (1 << SPI2X); + } else if (LineCoding.BaudRateBPS == 57600) { // 500kHz SPI (Fosc / 16) + SPCRmask |= ((0 << SPR1) | (1 << SPR0)); + SPSRmask |= (0 << SPI2X); + } else if (LineCoding.BaudRateBPS == 38400) { // 250kHz SPI (Fosc / 32) + SPCRmask |= ((1 << SPR1) | (0 << SPR0)); + SPSRmask |= (1 << SPI2X); + } else if (LineCoding.BaudRateBPS == 19200) { // 125kHz SPI (Fosc / 64) + SPCRmask |= ((1 << SPR1) | (0 << SPR0)); + SPSRmask |= (0 << SPI2X); + } else if (LineCoding.BaudRateBPS == 115200) { // 62.5kHz SPI (Fosc / 128) + SPCRmask |= ((1 << SPR1) | (1 << SPR0)); + SPSRmask |= (0 << SPI2X); + } + + SPCR = SPCRmask; + SPSR = SPSRmask; + + // only read if first run + if (firstRun) { + tempIOreg = SPSR; //need to read to initiliaze + tempIOreg = SPDR; //need to read to initiliaze + firstRun = 0; + } + +} + + +/* process data according to AVR910 protocol */ +void processHostSPIRequest(void) { + + uint8_t readByte1 = 0; + uint8_t readByte2 = 0; + uint8_t readByte3 = 0; + uint8_t readByte4 = 0; + uint8_t firstByte = 0; + + /* Taken from a90isp_ver23.asm: + +-------------+------------+------+ + ;* Commands | Host writes | Host reads | | + ;* -------- +-----+-------+------+-----+ | + ;* | ID | data | data | | Note | + ;* +-----------------------------------+-----+-------+------+-----+------+ + ;* | Enter programming mode | 'P' | | | 13d | 1 | + ;* | Report autoincrement address | 'a' | | | 'Y' | | + ;* | Set address | 'A' | ah al | | 13d | 2 | + ;* | Write program memory, low byte | 'c' | dd | | 13d | 3 | + ;* | Write program memory, high byte | 'C' | dd | | 13d | 3 | + ;* | Issue Page Write | 'm' | | | 13d | | + ;* | Read program memory | 'R' | |dd(dd)| | 4 | + ;* | Write data memory | 'D' | dd | | 13d | | + ;* | Read data memory | 'd' | | dd | | | + ;* | Chip erase | 'e' | | | 13d | | + ;* | Write lock bits | 'l' | dd | | 13d | | + ;* | Write fuse bits | 'f' | dd | | 13d | 11 | + ;* | Read fuse and lock bits | 'F' | | dd | | 11 | + ;* | Leave programming mode | 'L' | | | 13d | 5 | + ;* | Select device type | 'T' | dd | | 13d | 6 | + ;* | Read signature bytes | 's' | | 3*dd | | | + ;* | Return supported device codes | 't' | | n*dd | 00d | 7 | + ;* | Return software identifier | 'S' | | s[7] | | 8 | + ;* | Return sofware version | 'V' | |dd dd | | 9 | + ;* | Return hardware version | 'v' | |dd dd | | 9 | + ;* | Return programmer type | 'p' | | dd | | 10 | + ;* | Set LED | 'x' | dd | | 13d | 12 | + ;* | Clear LED | 'y' | dd | | 13d | 12 | + ;* | Universial command | ':' | 3*dd | dd | 13d | | + ;* | New universal command | '.' | 4*dd | dd | 13d | | + ;* | Special test command | 'Z' | 2*dd | dd | | | + */ + + firstByte = Buffer_GetElement(&Rx_Buffer); + Buffer_Initialize(&Tx_Buffer); // make sure the buffer is clear before proceeding + + if (firstByte == 'P') { // enter Programming mode + // enable SPI -- already done + // enter programming mode on target: + //PORTB = 0; // set clock to zero + RESETPORT = (1 << RESETPIN); // set RESET pin on target to 1 + RESETPORT2 = (1 << RESETPIN2); + delay_ms(DELAY_SHORT); + //RESETPORT = (RESETPORT & ~(1 << RESETPIN)); // set RESET pin on target to 0 - Active + RESETPORT = 0x00; + RESETPORT2 = 0; + delay_ms(DELAY_SHORT); + SPI_SendByte(0xAC); + SPI_SendByte(0x53); + SPI_SendByte(0x00); + SPI_SendByte(0x00); + delay_ms(DELAY_VERYSHORT); + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 'T') { // Select device type + deviceCode = Buffer_GetElement(&Rx_Buffer); // set device type + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 'a') { // Report autoincrement address + Buffer_StoreElement(&Tx_Buffer, 'Y'); // return 'Y' - Auto-increment enabled + + } else if (firstByte == 'A') { //Load Address + // get two bytes over serial and set currAddress to them + readByte1 = Buffer_GetElement(&Rx_Buffer); // high byte + readByte2 = Buffer_GetElement(&Rx_Buffer); // low byte + currAddress = (readByte1 << 8) | (readByte2); + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 'c') { // Write program memory, low byte + // send 4 bytes over SPI; 0x40, then Address High Byte, then Low, then data + readByte1 = Buffer_GetElement(&Rx_Buffer); + SPI_SendByte(0x40); + SPI_SendByte((currAddress >> 8)); // high byte + SPI_SendByte((currAddress)); // low byte + SPI_SendByte(readByte1); // data + delay_ms(DELAY_MEDIUM); // certain MCUs require a delay of about 24585 cycles + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 'C') { // Write program memory, high byte + // send 4 bytes over SPI; 0x48, then Address High Byte, then Low, then data + readByte1 = Buffer_GetElement(&Rx_Buffer); + SPI_SendByte(0x48); + SPI_SendByte((currAddress >> 8)); // high byte + SPI_SendByte((currAddress)); // low byte + SPI_SendByte(readByte1); // data + currAddress++; // increment currAddress + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 'm') { // Write Program Memory Page + // send 4 bytes over SPI; 0x4c, then Address High Byte, then Low, then 0x00 + SPI_SendByte(0x4C); + SPI_SendByte((currAddress >> 8)); // high byte + SPI_SendByte((currAddress)); // low byte + SPI_SendByte(0x00); + delay_ms(DELAY_LONG); + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 'R') { // Read Program Memory + // send 4 bytes over SPI; 0x28, then Address High Byte, then Low, then send back read data from 4th byte over serial + SPI_SendByte(0x28); + SPI_SendByte((currAddress >> 8)); // high byte + SPI_SendByte((currAddress)); // low byte + readByte1 = SPI_TransferByte(0x00); // read in data + Buffer_StoreElement(&Tx_Buffer, readByte1); + // send 4 bytes over SPI; 0x20, then Address High Byte, then Low, then send back read data from 4th byte over serial + SPI_SendByte(0x20); + SPI_SendByte((currAddress >> 8)); // high byte + SPI_SendByte((currAddress)); // low byte + readByte2 = SPI_TransferByte(0x00); // read in data + Buffer_StoreElement(&Tx_Buffer, readByte2); + currAddress++; // increment currAddress + + } else if (firstByte == 'D') { // Write Data Memory + // send 4 bytes over SPI; 0xc0, then Address High Byte, then Low, then data + readByte1 = Buffer_GetElement(&Rx_Buffer); + SPI_SendByte(0xC0); + SPI_SendByte((currAddress >> 8)); // high byte + SPI_SendByte((currAddress)); // low byte + SPI_SendByte(readByte1); // data + delay_ms(DELAY_MEDIUM); + currAddress++; // increment currAddress + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 'd') { // Read Data Memory + // send 4 bytes over SPI; 0xa0, then Address High Byte, then Low, then send back read data from 4th byte over serial + SPI_SendByte(0xA0); + SPI_SendByte((currAddress >> 8)); // high byte + SPI_SendByte((currAddress)); // low byte + readByte1 = SPI_TransferByte(0x00); // read in data + Buffer_StoreElement(&Tx_Buffer, readByte1); + currAddress++; // increment currAddress + + } else if (firstByte == 'e') { // erase the target device + // send 4 bytes over SPI; 0xac, 0x80, 0x04, 0x00 + SPI_SendByte(0xAC); + SPI_SendByte(0x80); + SPI_SendByte(0x04); + SPI_SendByte(0x00); + delay_ms(DELAY_LONG); + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 'l') { // write lock bits + // send 4 bytes over SPI; 0xac, [andi s_data 0x06], 0xe0, 0x00 + readByte1 = Buffer_GetElement(&Rx_Buffer); // read in lock bits data + SPI_SendByte(0xAC); + SPI_SendByte(((0x06 & readByte1) | 0xE0)); // TODO - is this correct??? + SPI_SendByte(0x00); + SPI_SendByte(0x00); + delay_ms(DELAY_MEDIUM); + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 'f') { // write fuse bits + // ignore this command, but need to remove data from the receive buffer + readByte1 = Buffer_GetElement(&Rx_Buffer); + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 'L') { // leave programming mode + RESETPORT |= (1 << RESETPIN); // set RESET pin on target to 1 + RESETPORT2 |= (1 << RESETPIN2); // set RESET pin on target to 1 + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 's') { // Read signature bytes + // send 4 bytes over SPI; 0x30, 0x00, 0x02, read and send last byte over serial + SPI_SendByte(0x30); + SPI_SendByte(0x00); + SPI_SendByte(0x02); + readByte1 = SPI_TransferByte(0x00); // read in data + Buffer_StoreElement(&Tx_Buffer, readByte1); + SPI_SendByte(0x30); + SPI_SendByte(0x00); + SPI_SendByte(0x01); + readByte1 = SPI_TransferByte(0x00); // read in data + Buffer_StoreElement(&Tx_Buffer, readByte1); + SPI_SendByte(0x30); + SPI_SendByte(0x00); + SPI_SendByte(0x00); + readByte1 = SPI_TransferByte(0x00); // read in data + Buffer_StoreElement(&Tx_Buffer, readByte1); + + } else if (firstByte == 't') { // Return supported device codes + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE01); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE02); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE03); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE04); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE05); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE06); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE07); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE08); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE09); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE10); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE11); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE12); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE13); + Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE14); + Buffer_StoreElement(&Tx_Buffer, 0x00); + + } else if (firstByte == 'S') { // Return software identifier + // return string[7] with "AVR ISP" + Buffer_StoreElement(&Tx_Buffer, 'A'); + Buffer_StoreElement(&Tx_Buffer, 'V'); + Buffer_StoreElement(&Tx_Buffer, 'R'); + Buffer_StoreElement(&Tx_Buffer, 0x20); + Buffer_StoreElement(&Tx_Buffer, 'I'); + Buffer_StoreElement(&Tx_Buffer, 'S'); + Buffer_StoreElement(&Tx_Buffer, 'P'); + + } else if (firstByte == 'V') { // Return sofware version + //return two bytes, software Major then Minor + Buffer_StoreElement(&Tx_Buffer, '2'); + Buffer_StoreElement(&Tx_Buffer, '3'); + + } else if (firstByte == 'v') { // Return hardware version + //return two bytes, hardware Major then Minor + Buffer_StoreElement(&Tx_Buffer, ('1')); + Buffer_StoreElement(&Tx_Buffer, ('0')); + + } else if (firstByte == 'p') { // Return programmer type + // return 'S' for Serial Programmer + Buffer_StoreElement(&Tx_Buffer, 'S'); + + } else if (firstByte == 'x') { // set LED + // ignore this command, but need to remove data from the receive buffer + readByte1 = Buffer_GetElement(&Rx_Buffer); + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 'y') { // clear LED + // ignore this command, but need to remove data from the receive buffer + readByte1 = Buffer_GetElement(&Rx_Buffer); + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == ':') { // Universal Command + // get 3 bytes over serial + readByte1 = Buffer_GetElement(&Rx_Buffer); + readByte2 = Buffer_GetElement(&Rx_Buffer); + readByte3 = Buffer_GetElement(&Rx_Buffer); + SPI_SendByte(readByte1); + SPI_SendByte(readByte2); + SPI_SendByte(readByte3); + readByte1 = SPI_TransferByte(0x00); + Buffer_StoreElement(&Tx_Buffer, readByte1); + delay_ms(DELAY_MEDIUM); + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == '.') { // New Universal Command + // get 4 bytes over serial + readByte1 = Buffer_GetElement(&Rx_Buffer); + readByte2 = Buffer_GetElement(&Rx_Buffer); + readByte3 = Buffer_GetElement(&Rx_Buffer); + readByte4 = Buffer_GetElement(&Rx_Buffer); + SPI_SendByte(readByte1); + SPI_SendByte(readByte2); + SPI_SendByte(readByte3); + readByte1 = SPI_TransferByte(readByte4); + Buffer_StoreElement(&Tx_Buffer, readByte1); + delay_ms(DELAY_MEDIUM); + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + + } else if (firstByte == 'Z') { // Special test command + // do nothing, but need to remove data from the receive buffer + readByte1 = Buffer_GetElement(&Rx_Buffer); + readByte2 = Buffer_GetElement(&Rx_Buffer); + + } else { + // do nothing, but need to return with a carriage return + Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful + } +} + + +void delay_ms(uint8_t dly) { + uint16_t endtime = 0; + + endtime = TCNT1; + if (endtime > 63486) { + endtime = (dly * DELAY_MULTIPLE); + } else { + endtime += (dly * DELAY_MULTIPLE); + } + + timerval = TCNT1; + while (timerval < endtime) { + timerval = TCNT1; + } +} diff --git a/Projects/AVRISP_Programmer/AVRISP_Programmer.h b/Projects/AVRISP_Programmer/AVRISP_Programmer.h new file mode 100644 index 0000000000..e78ba29356 --- /dev/null +++ b/Projects/AVRISP_Programmer/AVRISP_Programmer.h @@ -0,0 +1,194 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for USBtoSerial.c. + */ + +#ifndef _AVRISP_PROGRAMMER_H_ +#define _AVRISP_PROGRAMMER_H_ + + /* Includes: */ + #include + #include + #include + + #include "Descriptors.h" + #include "RingBuff.h" + + #include // Library Version Information + #include // PROGMEM tags readable by the ButtLoad project + #include // USB Functionality + #include // SPI driver + #include // LEDs driver + #include // Simple scheduler for task management + + /* Macros: */ + /** CDC Class specific request to get the current virtual serial port configuration settings. */ + #define REQ_GetLineEncoding 0x21 + + /** CDC Class specific request to set the current virtual serial port configuration settings. */ + #define REQ_SetLineEncoding 0x20 + + /** CDC Class specific request to set the current virtual serial port handshake line states. */ + #define REQ_SetControlLineState 0x22 + + /** Notification type constant for a change in the virtual serial port handshake line states, for + * use with a USB_Notification_Header_t notification structure when sent to the host via the CDC + * notification endpoint. + */ + #define NOTIF_SerialState 0x20 + + /** Mask for the DTR handshake line for use with the REQ_SetControlLineState class specific request + * from the host, to indicate that the DTR line state should be high. + */ + #define CONTROL_LINE_OUT_DTR (1 << 0) + + /** Mask for the RTS handshake line for use with the REQ_SetControlLineState class specific request + * from the host, to indicate that theRTS line state should be high. + */ + #define CONTROL_LINE_OUT_RTS (1 << 1) + + /** Mask for the DCD handshake line for use with the a NOTIF_SerialState class specific notification + * from the device to the host, to indicate that the DCD line state is currently high. + */ + #define CONTROL_LINE_IN_DCD (1 << 0) + + /** Mask for the DSR handshake line for use with the a NOTIF_SerialState class specific notification + * from the device to the host, to indicate that the DSR line state is currently high. + */ + #define CONTROL_LINE_IN_DSR (1 << 1) + + /** Mask for the BREAK handshake line for use with the a NOTIF_SerialState class specific notification + * from the device to the host, to indicate that the BREAK line state is currently high. + */ + #define CONTROL_LINE_IN_BREAK (1 << 2) + + /** Mask for the RING handshake line for use with the a NOTIF_SerialState class specific notification + * from the device to the host, to indicate that the RING line state is currently high. + */ + #define CONTROL_LINE_IN_RING (1 << 3) + + /** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host, + * to indicate that a framing error has ocurred on the virtual serial port. + */ + #define CONTROL_LINE_IN_FRAMEERROR (1 << 4) + + /** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host, + * to indicate that a parity error has ocurred on the virtual serial port. + */ + #define CONTROL_LINE_IN_PARITYERROR (1 << 5) + + /** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host, + * to indicate that a data overrun error has ocurred on the virtual serial port. + */ + #define CONTROL_LINE_IN_OVERRUNERROR (1 << 6) + + /* Event Handlers: */ + /** Indicates that this module will catch the USB_Connect event when thrown by the library. */ + HANDLES_EVENT(USB_Connect); + + /** Indicates that this module will catch the USB_Disconnect event when thrown by the library. */ + HANDLES_EVENT(USB_Disconnect); + + /** Indicates that this module will catch the USB_ConfigurationChanged event when thrown by the library. */ + HANDLES_EVENT(USB_ConfigurationChanged); + + /** Indicates that this module will catch the USB_UnhandledControlPacket event when thrown by the library. */ + HANDLES_EVENT(USB_UnhandledControlPacket); + + /* Type Defines: */ + /** Type define for the virtual serial port line encoding settings, for storing the current USART configuration + * as set by the host via a class specific request. + */ + typedef struct + { + uint32_t BaudRateBPS; /**< Baud rate of the virtual serial port, in bits per second */ + uint8_t CharFormat; /**< Character format of the virtual serial port, a value from the + * CDCDevice_CDC_LineCodingFormats_t enum + */ + uint8_t ParityType; /**< Parity setting of the virtual serial port, a value from the + * CDCDevice_LineCodingParity_t enum + */ + uint8_t DataBits; /**< Bits of data per charater of the virtual serial port */ + } CDC_Line_Coding_t; + + /** Type define for a CDC notification, sent to the host via the CDC notification endpoint to indicate a + * change in the device state asynchronously. + */ + typedef struct + { + uint8_t NotificationType; /**< Notification type, a mask of REQDIR_*, REQTYPE_* and REQREC_* constants + * from the library StdRequestType.h header + */ + uint8_t Notification; /**< Notification value, a NOTIF_* constant */ + uint16_t wValue; /**< Notification wValue, notification-specific */ + uint16_t wIndex; /**< Notification wIndex, notification-specific */ + uint16_t wLength; /**< Notification wLength, notification-specific */ + } USB_Notification_Header_t; + + /* Enums: */ + /** Enum for the possible line encoding formats of a virtual serial port. */ + enum CDCDevice_CDC_LineCodingFormats_t + { + OneStopBit = 0, /**< Each frame contains one stop bit */ + OneAndAHalfStopBits = 1, /**< Each frame contains one and a half stop bits */ + TwoStopBits = 2, /**< Each frame contains two stop bits */ + }; + + /** Enum for the possible line encoding parity settings of a virtual serial port. */ + enum CDCDevice_LineCodingParity_t + { + Parity_None = 0, /**< No parity bit mode on each frame */ + Parity_Odd = 1, /**< Odd parity bit mode on each frame */ + Parity_Even = 2, /**< Even parity bit mode on each frame */ + Parity_Mark = 3, /**< Mark parity bit mode on each frame */ + Parity_Space = 4, /**< Space parity bit mode on each frame */ + }; + + /** Enum for the possible status codes for passing to the UpdateStatus() function. */ + enum USBtoSerial_StatusCodes_t + { + Status_USBNotReady = 0, /**< USB is not ready (disconnected from a USB host) */ + Status_USBEnumerating = 1, /**< USB interface is enumerating */ + Status_USBReady = 2, /**< USB interface is connected and ready */ + }; + + /* Tasks: */ + TASK(CDC_Task); + + /* Function Prototypes: */ + void ReconfigureSPI(void); + void UpdateStatus(uint8_t CurrentStatus); + void processHostSPIRequest(void); + void delay_ms(uint8_t dly); + +#endif diff --git a/Projects/AVRISP_Programmer/AVRISP_Programmer.txt b/Projects/AVRISP_Programmer/AVRISP_Programmer.txt new file mode 100644 index 0000000000..1872cfb5e7 --- /dev/null +++ b/Projects/AVRISP_Programmer/AVRISP_Programmer.txt @@ -0,0 +1,89 @@ +/** \file + * + * This file contains special DoxyGen information for the generation of the main page and other special + * documentation pages. It is not a project source file. + */ + +/** \mainpage AVRISP_Programmer + * + * Communications Device Class demonstration application. + * This gives a simple reference application for implementing + * a USB to Serial converter using the CDC class. Data communicated + * over the USB Virtual Serial Port according to Atmel's AVR910 + * protocol is used to program AVR MCUs that are + * "In-System Programmable via SPI Port". + * + * After running this firmware for the first time on a new computer, + * you will need to supply the .INF file located in this demo + * project's directory as the device's driver when running under + * Windows. This will enable Windows to use its inbuilt CDC drivers, + * negating the need for custom drivers for the device. Other + * Operating Systems should automatically use their own inbuilt + * CDC-ACM drivers. + * + * Usage: + * avrdude -vv -F -P COM7 -c avr910 -p t261 + * Note -F flag which overrides signature check and enables programming + * of any "In-System Programmable via SPI Port" AVR MCU. Part number, + * t261, should be set to your target device. + * avrdude -vv -F -P COM7 -c avr910 -p t261 -U flash:w:PROG.hex + * PROG.hex is the hex file to program your t261 AVR with + * avrdude -vv -F -P COM7 -b 115200 -c avr910 -p t261 -U flash:w:test.hex + * The -b 115200 sets the SPI clock to 62.5kHz from the default 125kHz and may + * work when the default programming speed fails. + * AVROSP.exe -dATtiny261 -cCOM7 -rf + * AVRosp is the Open Source AVR ISP Programming Software available from Atmel.com + * + * Note: on Linux systems, COM7 should be replaced with someting like /dev/ttyACM0 + * You can determine this value by running dmesg after plugging in the device + * Note: you must RESET the programmer after each use (AVRdude session). + * + * Note: If you experience errors with older devices, try changing DELAY_LONG + * to a larger value, such as 0xFF in AVRISP_Programmer.c + * + * MISO, MOSI, and SCK are connected directly from the AVRopendous board + * to the pin of the same functionality on the target. RESET pin on the target + * can be connected either to SS (PB0), or PC2. Do not have any other pins + * connected - especially HWB pin, to avoid unintentional behaviour. + * + * AVR910 functionality was overlayed on USBtoSerial functionality. + * Keep this in mind when looking over the code. + * Default target speed is 125kHz and corresponds to 19200 baud, which + * is the default setting for AVRdude. + * + * Changing "Baud-Rate" will change the SPI speed. Defualt SPI clock speed + * is 8Mhz / 4 = 2MHz. 8Mhz is the device clock speed. This is the setting at + * 9600 baud. The following is a table of baud-rate vs. SPI Speed that will result + * 9600 = 2Mhz + * 14400 = 1MHz + * 19200 = 125kHz (AVRdude Default) + * 38400 = 250kHz + * 57600 = 500kHz + * 115200 = 62.5kHz + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
USB Mode:Device
USB Class:Communications Device Class (CDC)
USB Subclass:Abstract Control Model (ACM)
Relevant Standards:USBIF CDC Class Standard
Usable Speeds:Full Speed Mode
+ */ diff --git a/Projects/AVRISP_Programmer/AVRISP_Programmer_Picture.jpg b/Projects/AVRISP_Programmer/AVRISP_Programmer_Picture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..87ec3d43ee0df3937060894b2773b04fb36aa91e GIT binary patch literal 74610 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 literal 0 HcmV?d00001 diff --git a/Projects/AVRISP_Programmer/Descriptors.c b/Projects/AVRISP_Programmer/Descriptors.c new file mode 100644 index 0000000000..5f3ffca08a --- /dev/null +++ b/Projects/AVRISP_Programmer/Descriptors.c @@ -0,0 +1,263 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * USB Device Descriptors, for library use when in USB device mode. Descriptors are special + * computer-readable structures which the host requests upon device enumeration, to determine + * the device's capabilities and functions. + */ + +#include "Descriptors.h" + +/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall + * device characteristics, including the supported USB version, control endpoint size and the + * number of device configurations. The descriptor is read out by the USB host when the enumeration + * process begins. + */ +USB_Descriptor_Device_t PROGMEM DeviceDescriptor = +{ + Header: {Size: sizeof(USB_Descriptor_Device_t), Type: DTYPE_Device}, + + USBSpecification: VERSION_BCD(01.10), + Class: 0x02, + SubClass: 0x00, + Protocol: 0x00, + + Endpoint0Size: 8, + + VendorID: 0x03EB, + ProductID: 0x204F, + ReleaseNumber: 0x0000, + + ManufacturerStrIndex: 0x01, + ProductStrIndex: 0x02, + SerialNumStrIndex: NO_DESCRIPTOR, + + NumberOfConfigurations: 1 +}; + +/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage + * of the device in one of its supported configurations, including information about any device interfaces + * and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting + * a configuration so that the host may correctly communicate with the USB device. + */ +USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = +{ + Config: + { + Header: {Size: sizeof(USB_Descriptor_Configuration_Header_t), Type: DTYPE_Configuration}, + + TotalConfigurationSize: sizeof(USB_Descriptor_Configuration_t), + TotalInterfaces: 2, + + ConfigurationNumber: 1, + ConfigurationStrIndex: NO_DESCRIPTOR, + + ConfigAttributes: (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELFPOWERED), + + MaxPowerConsumption: USB_CONFIG_POWER_MA(100) + }, + + CCI_Interface: + { + Header: {Size: sizeof(USB_Descriptor_Interface_t), Type: DTYPE_Interface}, + + InterfaceNumber: 0, + AlternateSetting: 0, + + TotalEndpoints: 1, + + Class: 0x02, + SubClass: 0x02, + Protocol: 0x01, + + InterfaceStrIndex: NO_DESCRIPTOR + }, + + CDC_Functional_IntHeader: + { + Header: {Size: sizeof(CDC_FUNCTIONAL_DESCRIPTOR(2)), Type: 0x24}, + SubType: 0x00, + + Data: {0x01, 0x10} + }, + + CDC_Functional_CallManagement: + { + Header: {Size: sizeof(CDC_FUNCTIONAL_DESCRIPTOR(2)), Type: 0x24}, + SubType: 0x01, + + Data: {0x03, 0x01} + }, + + CDC_Functional_AbstractControlManagement: + { + Header: {Size: sizeof(CDC_FUNCTIONAL_DESCRIPTOR(1)), Type: 0x24}, + SubType: 0x02, + + Data: {0x06} + }, + + CDC_Functional_Union: + { + Header: {Size: sizeof(CDC_FUNCTIONAL_DESCRIPTOR(2)), Type: 0x24}, + SubType: 0x06, + + Data: {0x00, 0x01} + }, + + ManagementEndpoint: + { + Header: {Size: sizeof(USB_Descriptor_Endpoint_t), Type: DTYPE_Endpoint}, + + EndpointAddress: (ENDPOINT_DESCRIPTOR_DIR_IN | CDC_NOTIFICATION_EPNUM), + Attributes: EP_TYPE_INTERRUPT, + EndpointSize: CDC_NOTIFICATION_EPSIZE, + PollingIntervalMS: 0xFF + }, + + DCI_Interface: + { + Header: {Size: sizeof(USB_Descriptor_Interface_t), Type: DTYPE_Interface}, + + InterfaceNumber: 1, + AlternateSetting: 0, + + TotalEndpoints: 2, + + Class: 0x0A, + SubClass: 0x00, + Protocol: 0x00, + + InterfaceStrIndex: NO_DESCRIPTOR + }, + + DataOutEndpoint: + { + Header: {Size: sizeof(USB_Descriptor_Endpoint_t), Type: DTYPE_Endpoint}, + + EndpointAddress: (ENDPOINT_DESCRIPTOR_DIR_OUT | CDC_RX_EPNUM), + Attributes: EP_TYPE_BULK, + EndpointSize: CDC_TXRX_EPSIZE, + PollingIntervalMS: 0x00 + }, + + DataInEndpoint: + { + Header: {Size: sizeof(USB_Descriptor_Endpoint_t), Type: DTYPE_Endpoint}, + + EndpointAddress: (ENDPOINT_DESCRIPTOR_DIR_IN | CDC_TX_EPNUM), + Attributes: EP_TYPE_BULK, + EndpointSize: CDC_TXRX_EPSIZE, + PollingIntervalMS: 0x00 + } +}; + +/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests + * the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate + * via the language ID table available at USB.org what languages the device supports for its string descriptors. + */ +USB_Descriptor_String_t PROGMEM LanguageString = +{ + Header: {Size: USB_STRING_LEN(1), Type: DTYPE_String}, + + UnicodeString: {LANGUAGE_ID_ENG} +}; + +/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable + * form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +USB_Descriptor_String_t PROGMEM ManufacturerString = +{ + Header: {Size: USB_STRING_LEN(19), Type: DTYPE_String}, + + UnicodeString: L"www.AVRopendous.org" +}; + +/** Product descriptor string. This is a Unicode string containing the product's details in human readable form, + * and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +USB_Descriptor_String_t PROGMEM ProductString = +{ + Header: {Size: USB_STRING_LEN(29), Type: DTYPE_String}, + + UnicodeString: L"LUFA-Based AVR ISP Programmer" +}; + +/** This function is called by the library when in device mode, and must be overridden (see StdDescriptors.h + * documentation) by the application code so that the address and size of a requested descriptor can be given + * to the USB library. When the device recieves a Get Descriptor request on the control endpoint, this function + * is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the + * USB host. + */ +uint16_t USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) +{ + const uint8_t DescriptorType = (wValue >> 8); + const uint8_t DescriptorNumber = (wValue & 0xFF); + + void* Address = NULL; + uint16_t Size = NO_DESCRIPTOR; + + switch (DescriptorType) + { + case DTYPE_Device: + Address = DESCRIPTOR_ADDRESS(DeviceDescriptor); + Size = sizeof(USB_Descriptor_Device_t); + break; + case DTYPE_Configuration: + Address = DESCRIPTOR_ADDRESS(ConfigurationDescriptor); + Size = sizeof(USB_Descriptor_Configuration_t); + break; + case DTYPE_String: + switch (DescriptorNumber) + { + case 0x00: + Address = DESCRIPTOR_ADDRESS(LanguageString); + Size = pgm_read_byte(&LanguageString.Header.Size); + break; + case 0x01: + Address = DESCRIPTOR_ADDRESS(ManufacturerString); + Size = pgm_read_byte(&ManufacturerString.Header.Size); + break; + case 0x02: + Address = DESCRIPTOR_ADDRESS(ProductString); + Size = pgm_read_byte(&ProductString.Header.Size); + break; + } + + break; + } + + *DescriptorAddress = Address; + return Size; +} diff --git a/Projects/AVRISP_Programmer/Descriptors.h b/Projects/AVRISP_Programmer/Descriptors.h new file mode 100644 index 0000000000..bec5e40d4a --- /dev/null +++ b/Projects/AVRISP_Programmer/Descriptors.h @@ -0,0 +1,98 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for Descriptors.c. + */ + +#ifndef _DESCRIPTORS_H_ +#define _DESCRIPTORS_H_ + + /* Includes: */ + #include + + #include + + /* Macros: */ + /** Macro to define a CDC class-specific functional descriptor. CDC functional descriptors have a + * uniform structure but variable sized data payloads, thus cannot be represented accurately by + * a single typedef struct. A macro is used instead so that functional descriptors can be created + * easily by specifying the size of the payload. This allows sizeof() to work correctly. + * + * \param DataSize Size in bytes of the CDC functional descriptor's data payload + */ + #define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \ + struct \ + { \ + USB_Descriptor_Header_t Header; \ + uint8_t SubType; \ + uint8_t Data[DataSize]; \ + } + + /** Endpoint number of the CDC device-to-host notification IN endpoint. */ + #define CDC_NOTIFICATION_EPNUM 2 + + /** Endpoint number of the CDC device-to-host data IN endpoint. */ + #define CDC_TX_EPNUM 3 + + /** Endpoint number of the CDC host-to-device data OUT endpoint. */ + #define CDC_RX_EPNUM 4 + + /** Size in bytes of the CDC device-to-host notification IN endpoint. */ + #define CDC_NOTIFICATION_EPSIZE 8 + + /** Size in bytes of the CDC data IN and OUT endpoints. */ + #define CDC_TXRX_EPSIZE 16 + + /* Type Defines: */ + /** Type define for the device configuration descriptor structure. This must be defined in the + * application code, as the configuration descriptor contains several sub-descriptors which + * vary between devices, and which describe the device's usage to the host. + */ + typedef struct + { + USB_Descriptor_Configuration_Header_t Config; + USB_Descriptor_Interface_t CCI_Interface; + CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_IntHeader; + CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_CallManagement; + CDC_FUNCTIONAL_DESCRIPTOR(1) CDC_Functional_AbstractControlManagement; + CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_Union; + USB_Descriptor_Endpoint_t ManagementEndpoint; + USB_Descriptor_Interface_t DCI_Interface; + USB_Descriptor_Endpoint_t DataOutEndpoint; + USB_Descriptor_Endpoint_t DataInEndpoint; + } USB_Descriptor_Configuration_t; + + /* Function Prototypes: */ + uint16_t USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) + ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); + +#endif diff --git a/Projects/AVRISP_Programmer/Doxygen.conf b/Projects/AVRISP_Programmer/Doxygen.conf new file mode 100644 index 0000000000..1eb8c5432e --- /dev/null +++ b/Projects/AVRISP_Programmer/Doxygen.conf @@ -0,0 +1,1485 @@ +# Doxyfile 1.5.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "LUFA Library - USB to Serial Device Demo" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.0.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./Documentation/ + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = YES + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ./ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.h \ + *.c \ + *.txt + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = */LowLevel/USBMode.h + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = __* + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = NO + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = YES + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Namespace. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Virtual Folders. + +QHP_VIRTUAL_FOLDER = doc + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file . + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 1 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = __DOXYGEN__ + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = BUTTLOADTAG + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = NO + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = NO + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = NO + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = NO + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = NO + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = NO + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = "C:/Program Files/Graphviz2.18/bin" + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 15 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 2 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = YES + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/Projects/AVRISP_Programmer/LUFA AVRISP_Programmer.inf b/Projects/AVRISP_Programmer/LUFA AVRISP_Programmer.inf new file mode 100644 index 0000000000..bd9c8bf142 --- /dev/null +++ b/Projects/AVRISP_Programmer/LUFA AVRISP_Programmer.inf @@ -0,0 +1,55 @@ +; Windows LUFA USB to Serial Setup File +; Copyright (c) 2000 Microsoft Corporation + +[Version] +Signature="$Windows NT$" +Class=Ports +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} +Provider=%COMPANY% +LayoutFile=layout.inf +DriverVer=06/06/2006,1.0.0.0 + +[Manufacturer] +%MFGNAME% = ManufName + +[DestinationDirs] +DefaultDestDir=12 + +[ManufName] +%Modem3% = Modem3, USB\VID_03EB&PID_204B + +;------------------------------------------------------------------------------ +; Windows 2000/XP Sections +;------------------------------------------------------------------------------ + +[Modem3.nt] +CopyFiles=USBModemCopyFileSection +AddReg=Modem3.nt.AddReg + +[USBModemCopyFileSection] +usbser.sys,,,0x20 + +[Modem3.nt.AddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[Modem3.nt.Services] +AddService=usbser, 0x00000002, DriverService + +[DriverService] +DisplayName=%SERVICE% +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%12%\usbser.sys + +;------------------------------------------------------------------------------ +; String Definitions +;------------------------------------------------------------------------------ + +[Strings] +COMPANY="LUFA Library" +MFGNAME="Dean Camera" +Modem3="USB Virtual Serial Port" +SERVICE="USB Virtual Serial Port CDC Driver" \ No newline at end of file diff --git a/Projects/AVRISP_Programmer/RingBuff.c b/Projects/AVRISP_Programmer/RingBuff.c new file mode 100644 index 0000000000..1f477f17ab --- /dev/null +++ b/Projects/AVRISP_Programmer/RingBuff.c @@ -0,0 +1,120 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +#include "RingBuff.h" + +void Buffer_Initialize(RingBuff_t* Buffer) +{ + BUFF_ATOMIC_BLOCK + { + Buffer->InPtr = (RingBuff_Data_t*)&Buffer->Buffer; + Buffer->OutPtr = (RingBuff_Data_t*)&Buffer->Buffer; + Buffer->Elements = 0; + } +} + +void Buffer_StoreElement(RingBuff_t* Buffer, RingBuff_Data_t Data) +{ + BUFF_ATOMIC_BLOCK + { + #if defined(BUFF_DROPOLD) + if (Buffer->Elements == BUFF_LENGTH) + { + Buffer->OutPtr++; + + if (Buffer->OutPtr == &Buffer->Buffer[BUFF_LENGTH]) + Buffer->OutPtr = (RingBuff_Data_t*)&Buffer->Buffer; + } + else + { + Buffer->Elements++; + } + #elif defined(BUFF_DROPNEW) + if (Buffer->Elements == BUFF_LENGTH) + return; + + Buffer->Elements++; + #elif defined(BUFF_NODROPCHECK) + Buffer->Elements++; + #endif + + *(Buffer->InPtr) = Data; + Buffer->InPtr++; + + if (Buffer->InPtr == &Buffer->Buffer[BUFF_LENGTH]) + Buffer->InPtr = (RingBuff_Data_t*)&Buffer->Buffer; + } +} + +RingBuff_Data_t Buffer_GetElement(RingBuff_t* Buffer) +{ + RingBuff_Data_t BuffData; + + BUFF_ATOMIC_BLOCK + { +#if defined(BUFF_EMPTYRETURNSZERO) + if (!(Buffer->Elements)) + return 0; +#elif !defined(BUFF_NOEMPTYCHECK) + #error No empty buffer check behaviour specified. +#endif + + BuffData = *(Buffer->OutPtr); + + Buffer->OutPtr++; + Buffer->Elements--; + + if (Buffer->OutPtr == &Buffer->Buffer[BUFF_LENGTH]) + Buffer->OutPtr = (RingBuff_Data_t*)&Buffer->Buffer; + } + + return BuffData; +} + +#if defined(BUFF_USEPEEK) +RingBuff_Data_t Buffer_PeekElement(const RingBuff_t* Buffer) +{ + RingBuff_Data_t BuffData; + + BUFF_ATOMIC_BLOCK + { +#if defined(BUFF_EMPTYRETURNSZERO) + if (!(Buffer->Elements)) + return 0; +#elif !defined(BUFF_NOEMPTYCHECK) + #error No empty buffer check behaviour specified. +#endif + + BuffData = *(Buffer->OutPtr); + } + + return BuffData; +} +#endif diff --git a/Projects/AVRISP_Programmer/RingBuff.h b/Projects/AVRISP_Programmer/RingBuff.h new file mode 100644 index 0000000000..68e4a6e75a --- /dev/null +++ b/Projects/AVRISP_Programmer/RingBuff.h @@ -0,0 +1,116 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/* Buffer Configuration: */ + /* Buffer length - select static size of created ringbuffers: */ + #define BUFF_STATICSIZE 128 // Set to the static ringbuffer size for all ringbuffers (place size after define) + + /* Volatile mode - uncomment to make buffers volatile, for use in ISRs, etc: */ + #define BUFF_VOLATILE // Uncomment to cause all ring buffers to become volatile (and atomic if multi-byte) in access + + /* Drop mode - select behaviour when Buffer_StoreElement called on a full buffer: */ + #define BUFF_DROPOLD // Uncomment to cause full ring buffers to drop the oldest character to make space when full + // #define BUFF_DROPNEW // Uncomment to cause full ring buffers to drop the new character when full + // #define BUFF_NODROPCHECK // Uncomment to ignore full ring buffer checks - checking left to user! + + /* Underflow behaviour - select behaviour when Buffer_GetElement is called with an empty ringbuffer: */ + //#define BUFF_EMPTYRETURNSZERO // Uncomment to return 0 when an empty ringbuffer is read + #define BUFF_NOEMPTYCHECK // Uncomment to disable checking of empty ringbuffers - checking left to user! + + /* Buffer storage type - set the datatype for the stored data */ + #define BUFF_DATATYPE uint8_t // Change to the data type that is going to be stored into the buffer + + /* Peek routine - uncomment to include the peek routine (fetches next byte without removing it from the buffer */ + #define BUFF_USEPEEK + +#ifndef _RINGBUFF_H_ +#define _RINGBUFF_H_ + + /* Includes: */ + #include + #include + #include + #include + + #include + + /* Defines and checks: */ + #if defined(BUFF_STATICSIZE) + #define BUFF_LENGTH BUFF_STATICSIZE + #else + #error No buffer length specified! + #endif + + #if !(defined(BUFF_DROPOLD) || defined(BUFF_DROPNEW) || defined(BUFF_NODROPCHECK)) + #error No buffer drop mode specified. + #endif + + #if !defined(BUFF_DATATYPE) + #error Ringbuffer storage data type not specified. + #endif + + #if defined(BUFF_VOLATILE) + #define BUFF_MODE volatile + #define BUFF_ATOMIC_BLOCK ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + #else + #define BUFF_MODE + #define BUFF_ATOMIC_BLOCK + #endif + + #if (BUFF_STATICSIZE > LONG_MAX) + #define RingBuff_Elements_t uint64_t + #elif (BUFF_STATICSIZE > INT_MAX) + #define RingBuff_Elements_t uint32_t + #elif (BUFF_STATICSIZE > CHAR_MAX) + #define RingBuff_Elements_t uint16_t + #else + #define RingBuff_Elements_t uint8_t + #endif + + /* Type Defines: */ + typedef BUFF_DATATYPE RingBuff_Data_t; + + typedef BUFF_MODE struct + { + RingBuff_Data_t Buffer[BUFF_LENGTH]; + RingBuff_Data_t* InPtr; + RingBuff_Data_t* OutPtr; + RingBuff_Elements_t Elements; + } RingBuff_t; + + /* Function Prototypes: */ + void Buffer_Initialize(RingBuff_t* Buff); + void Buffer_StoreElement(RingBuff_t* Buffer, RingBuff_Data_t Data); + RingBuff_Data_t Buffer_GetElement(RingBuff_t* Buffer); + #if defined(BUFF_USEPEEK) + RingBuff_Data_t Buffer_PeekElement(const RingBuff_t* Buffer); + #endif + +#endif diff --git a/Projects/AVRISP_Programmer/Sample_Programming_Session.txt b/Projects/AVRISP_Programmer/Sample_Programming_Session.txt new file mode 100644 index 0000000000..b5af76ebb4 --- /dev/null +++ b/Projects/AVRISP_Programmer/Sample_Programming_Session.txt @@ -0,0 +1,104 @@ +ubuntu@ubuntu:~/LUFA/Bootloaders/LUFA_DFU_Bootloader_AT90USB162$ sudo avrdude -vv -F -P /dev/ttyACM0 -c avr910 -p usb162 -U flash:w:BootloaderDFU.hex + +avrdude: Version 5.5, compiled on May 9 2008 at 13:04:46 + Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/ + + System wide configuration file is "/etc/avrdude.conf" + User configuration file is "/home/ubuntu/.avrduderc" + User configuration file does not exist or is not a regular file, skipping + + Using Port : /dev/ttyACM0 + Using Programmer : avr910 + AVR Part : AT90USB162 + Chip Erase delay : 9000 us + PAGEL : PD7 + BS2 : PA0 + RESET disposition : dedicated + RETRY pulse : SCK + serial program mode : yes + parallel program mode : yes + Timeout : 200 + StabDelay : 100 + CmdexeDelay : 25 + SyncLoops : 32 + ByteDelay : 0 + PollIndex : 3 + PollValue : 0x53 + Memory Detail : + + Block Poll Page Polled + Memory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack + ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- --------- + eeprom 65 10 8 0 no 512 4 0 9000 9000 0x00 0x00 + flash 65 6 128 0 yes 16384 128 128 4500 4500 0x00 0x00 + lfuse 0 0 0 0 no 1 0 0 9000 9000 0x00 0x00 + hfuse 0 0 0 0 no 1 0 0 9000 9000 0x00 0x00 + efuse 0 0 0 0 no 1 0 0 9000 9000 0x00 0x00 + lock 0 0 0 0 no 1 0 0 9000 9000 0x00 0x00 + calibration 0 0 0 0 no 1 0 0 0 0 0x00 0x00 + signature 0 0 0 0 no 3 0 0 0 0 0x00 0x00 + + Programmer Type : avr910 + Description : Atmel Low Cost Serial Programmer + +Found programmer: Id = "AVR ISP"; type = S + Software Version = 2.3; Hardware Version = 1.0 +Programmer supports auto addr increment. + +Programmer supports the following devices: + Device code: 0x55 = ATtiny12 + Device code: 0x56 = ATtiny15 + Device code: 0x5e = ATtiny2313 + Device code: 0x76 = ATMEGA8 + Device code: 0x74 = ATMEGA6450 + Device code: 0x72 = ATMEGA32 + Device code: 0x45 = ATMEGA64 + Device code: 0x74 = ATMEGA6450 + Device code: 0x43 = ATMEGA128 + Device code: 0x63 = ATMEGA162 + Device code: 0x78 = ATMEGA169 + Device code: 0x6c = AT90S4434 + Device code: 0x38 = AT90S8515 + Device code: 0x65 = (unknown) + +avrdude: warning: selected device is not supported by programmer: usb162 +avrdude: AVR device initialized and ready to accept instructions + +Reading | ################################################## | 100% 0.00s + +avrdude: Device signature = 0x1e9482 +avrdude: safemode: lfuse reads as 5E +avrdude: safemode: hfuse reads as D9 +avrdude: safemode: efuse reads as F4 +avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed + To disable this feature, specify the -D option. +avrdude: erasing chip +avrdude: reading input file "BootloaderDFU.hex" +avrdude: input file BootloaderDFU.hex auto detected as Intel Hex +avrdude: writing flash (16066 bytes): + +Writing | ################################################## | 100% 33.39s + + + +avrdude: 16066 bytes of flash written +avrdude: verifying flash memory against BootloaderDFU.hex: +avrdude: load data flash data from input file BootloaderDFU.hex: +avrdude: input file BootloaderDFU.hex auto detected as Intel Hex +avrdude: input file BootloaderDFU.hex contains 16066 bytes +avrdude: reading on-chip flash data: + +Reading | ################################################## | 100% 16.07s + + + +avrdude: verifying ... +avrdude: 16066 bytes of flash verified + +avrdude: safemode: lfuse reads as 5E +avrdude: safemode: hfuse reads as D9 +avrdude: safemode: efuse reads as F4 +avrdude: safemode: Fuses OK + +avrdude done. Thank you. + diff --git a/Projects/AVRISP_Programmer/makefile b/Projects/AVRISP_Programmer/makefile new file mode 100644 index 0000000000..d6617dc7ef --- /dev/null +++ b/Projects/AVRISP_Programmer/makefile @@ -0,0 +1,704 @@ +# Hey Emacs, this is a -*- makefile -*- +#---------------------------------------------------------------------------- +# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al. +# >> Modified for use with the LUFA project. << +# +# Released to the Public Domain +# +# Additional material for this makefile was written by: +# Peter Fleury +# Tim Henigan +# Colin O'Flynn +# Reiner Patommel +# Markus Pfaff +# Sander Pool +# Frederik Rouleau +# Carlos Lamas +# Dean Camera +# Opendous Inc. +# Denver Gingerich +# +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device, using avrdude. +# Please customize the avrdude settings below first! +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# make doxygen = Generate DoxyGen documentation for the project (must have +# DoxyGen installed) +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + + +# MCU name +MCU = at90usb1287 + + +# Target board (USBKEY, STK525, STK526, RZUSBSTICK, USER or blank for projects not requiring +# LUFA board drivers). If USER is selected, put custom board drivers in a directory called +# "Board" inside the application directory. +BOARD = USBKEY + + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# Typical values are: +# F_CPU = 1000000 +# F_CPU = 1843200 +# F_CPU = 2000000 +# F_CPU = 3686400 +# F_CPU = 4000000 +# F_CPU = 7372800 +# F_CPU = 8000000 +# F_CPU = 11059200 +# F_CPU = 14745600 +# F_CPU = 16000000 +# F_CPU = 18432000 +# F_CPU = 20000000 +F_CPU = 8000000 + + +# Output format. (can be srec, ihex, binary) +FORMAT = ihex + + +# Target file name (without extension). +TARGET = AVRISP_Programmer + + +# Object files directory +# To put object files in current directory, use a dot (.), do NOT make +# this an empty or blank macro! +OBJDIR = . + + +# List C source files here. (C dependencies are automatically generated.) +SRC = $(TARGET).c \ + Descriptors.c \ + RingBuff.c \ + ../../LUFA/Scheduler/Scheduler.c \ + ../../LUFA/Drivers/AT90USBXXX/Serial.c \ + ../../LUFA/Drivers/USB/LowLevel/LowLevel.c \ + ../../LUFA/Drivers/USB/LowLevel/Endpoint.c \ + ../../LUFA/Drivers/USB/LowLevel/DevChapter9.c \ + ../../LUFA/Drivers/USB/HighLevel/USBTask.c \ + ../../LUFA/Drivers/USB/HighLevel/USBInterrupt.c \ + ../../LUFA/Drivers/USB/HighLevel/Events.c \ + ../../LUFA/Drivers/USB/HighLevel/StdDescriptors.c \ + +# List C++ source files here. (C dependencies are automatically generated.) +CPPSRC = + + +# List Assembler source files here. +# Make them always end in a capital .S. Files ending in a lowercase .s +# will not be considered source files but generated files (assembler +# output from the compiler), and will be deleted upon "make clean"! +# Even though the DOS/Win* filesystem matches both .s and .S the same, +# it will preserve the spelling of the filenames, and gcc itself does +# care about how the name is spelled on its command-line. +ASRC = + + +# Optimization level, can be [0, 1, 2, 3, s]. +# 0 = turn off optimization. s = optimize for size. +# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) +OPT = s + + +# Debugging format. +# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs. +# AVR Studio 4.10 requires dwarf-2. +# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run. +DEBUG = dwarf-2 + + +# List any extra directories to look for include files here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRAINCDIRS = ../../ + + +# Compiler flag to set the C Standard level. +# c89 = "ANSI" C +# gnu89 = c89 plus GCC extensions +# c99 = ISO C99 standard (not yet fully implemented) +# gnu99 = c99 plus GCC extensions +CSTANDARD = -std=gnu99 + + +# Place -D or -U options here for C sources +CDEFS = -DF_CPU=$(F_CPU)UL -DBOARD=BOARD_$(BOARD) -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS +CDEFS += -DUSB_DEVICE_ONLY -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" + + +# Place -D or -U options here for ASM sources +ADEFS = -DF_CPU=$(F_CPU) + + +# Place -D or -U options here for C++ sources +CPPDEFS = -DF_CPU=$(F_CPU)UL +#CPPDEFS += -D__STDC_LIMIT_MACROS +#CPPDEFS += -D__STDC_CONSTANT_MACROS + + + +#---------------- Compiler Options C ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CFLAGS = -g$(DEBUG) +CFLAGS += $(CDEFS) +CFLAGS += -O$(OPT) +CFLAGS += -funsigned-char +CFLAGS += -funsigned-bitfields +CFLAGS += -ffunction-sections +CFLAGS += -fpack-struct +CFLAGS += -fshort-enums +CFLAGS += -finline-limit=20 +CFLAGS += -Wall +CFLAGS += -Wstrict-prototypes +CFLAGS += -Wundef +#CFLAGS += -fno-unit-at-a-time +#CFLAGS += -Wunreachable-code +#CFLAGS += -Wsign-compare +CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst) +CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +CFLAGS += $(CSTANDARD) + + +#---------------- Compiler Options C++ ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CPPFLAGS = -g$(DEBUG) +CPPFLAGS += $(CPPDEFS) +CPPFLAGS += -O$(OPT) +CPPFLAGS += -funsigned-char +CPPFLAGS += -funsigned-bitfields +CPPFLAGS += -fpack-struct +CPPFLAGS += -fshort-enums +CPPFLAGS += -fno-exceptions +CPPFLAGS += -Wall +CFLAGS += -Wundef +#CPPFLAGS += -mshort-calls +#CPPFLAGS += -fno-unit-at-a-time +#CPPFLAGS += -Wstrict-prototypes +#CPPFLAGS += -Wunreachable-code +#CPPFLAGS += -Wsign-compare +CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst) +CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +#CPPFLAGS += $(CSTANDARD) + + +#---------------- Assembler Options ---------------- +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns: create listing +# -gstabs: have the assembler create line number information; note that +# for use in COFF files, additional information about filenames +# and function names needs to be present in the assembler source +# files -- see avr-libc docs [FIXME: not yet described there] +# -listing-cont-lines: Sets the maximum number of continuation lines of hex +# dump that will be displayed for a given single line of source input. +ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100 + + +#---------------- Library Options ---------------- +# Minimalistic printf version +PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min + +# Floating point printf version (requires MATH_LIB = -lm below) +PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt + +# If this is left blank, then it will use the Standard printf version. +PRINTF_LIB = +#PRINTF_LIB = $(PRINTF_LIB_MIN) +#PRINTF_LIB = $(PRINTF_LIB_FLOAT) + + +# Minimalistic scanf version +SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min + +# Floating point + %[ scanf version (requires MATH_LIB = -lm below) +SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt + +# If this is left blank, then it will use the Standard scanf version. +SCANF_LIB = +#SCANF_LIB = $(SCANF_LIB_MIN) +#SCANF_LIB = $(SCANF_LIB_FLOAT) + + +MATH_LIB = -lm + + +# List any extra directories to look for libraries here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRALIBDIRS = + + + +#---------------- External Memory Options ---------------- + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# used for variables (.data/.bss) and heap (malloc()). +#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# only used for heap (malloc()). +#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff + +EXTMEMOPTS = + + + +#---------------- Linker Options ---------------- +# -Wl,...: tell GCC to pass this to linker. +# -Map: create map file +# --cref: add cross reference to map file +LDFLAGS = -Wl,-Map=$(TARGET).map,--cref +LDFLAGS += -Wl,--relax +LDFLAGS += -Wl,--gc-sections +LDFLAGS += $(EXTMEMOPTS) +LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS)) +LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) +#LDFLAGS += -T linker_script.x + + + +#---------------- Programming Options (avrdude) ---------------- + +# Programming hardware: alf avr910 avrisp bascom bsd +# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500 +# +# Type: avrdude -c ? +# to get a full listing. +# +AVRDUDE_PROGRAMMER = jtagmkII + +# com1 = serial port. Use lpt1 to connect to parallel port. +AVRDUDE_PORT = usb + +AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex +#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep + + +# Uncomment the following if you want avrdude's erase cycle counter. +# Note that this counter needs to be initialized first using -Yn, +# see avrdude manual. +#AVRDUDE_ERASE_COUNTER = -y + +# Uncomment the following if you do /not/ wish a verification to be +# performed after programming the device. +#AVRDUDE_NO_VERIFY = -V + +# Increase verbosity level. Please use this when submitting bug +# reports about avrdude. See +# to submit bug reports. +#AVRDUDE_VERBOSE = -v -v + +AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) +AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) +AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) +AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) + + + +#---------------- Debugging Options ---------------- + +# For simulavr only - target MCU frequency. +DEBUG_MFREQ = $(F_CPU) + +# Set the DEBUG_UI to either gdb or insight. +# DEBUG_UI = gdb +DEBUG_UI = insight + +# Set the debugging back-end to either avarice, simulavr. +DEBUG_BACKEND = avarice +#DEBUG_BACKEND = simulavr + +# GDB Init Filename. +GDBINIT_FILE = __avr_gdbinit + +# When using avarice settings for the JTAG +JTAG_DEV = /dev/com1 + +# Debugging port used to communicate between GDB / avarice / simulavr. +DEBUG_PORT = 4242 + +# Debugging host used to communicate between GDB / avarice / simulavr, normally +# just set to localhost unless doing some sort of crazy debugging when +# avarice is running on a different computer. +DEBUG_HOST = localhost + + + +#============================================================================ + + +# Define programs and commands. +SHELL = sh +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +AR = avr-ar rcs +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +REMOVEDIR = rm -rf +COPY = cp +WINSHELL = cmd + +# Define Messages +# English +MSG_ERRORS_NONE = Errors: none +MSG_BEGIN = -------- begin -------- +MSG_END = -------- end -------- +MSG_SIZE_BEFORE = Size before: +MSG_SIZE_AFTER = Size after: +MSG_COFF = Converting to AVR COFF: +MSG_EXTENDED_COFF = Converting to AVR Extended COFF: +MSG_FLASH = Creating load file for Flash: +MSG_EEPROM = Creating load file for EEPROM: +MSG_EXTENDED_LISTING = Creating Extended Listing: +MSG_SYMBOL_TABLE = Creating Symbol Table: +MSG_LINKING = Linking: +MSG_COMPILING = Compiling C: +MSG_COMPILING_CPP = Compiling C++: +MSG_ASSEMBLING = Assembling: +MSG_CLEANING = Cleaning project: +MSG_CREATING_LIBRARY = Creating library: + + + + +# Define all object files. +OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) + +# Define all listing files. +LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst) + + +# Compiler flags to generate dependency files. +GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d + + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS) +ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + + + + +# Default target. +all: begin gccversion sizebefore build checkhooks checklibmode sizeafter end + +# Change the build target to build a HEX file or a library. +build: elf hex eep lss sym +#build: lib + + +elf: $(TARGET).elf +hex: $(TARGET).hex +eep: $(TARGET).eep +lss: $(TARGET).lss +sym: $(TARGET).sym +LIBNAME=lib$(TARGET).a +lib: $(LIBNAME) + + + +# Eye candy. +# AVR Studio 3.x does not check make's exit code but relies on +# the following magic strings to be generated by the compile job. +begin: + @echo + @echo $(MSG_BEGIN) + +end: + @echo $(MSG_END) + @echo + + +# Display size of file. +HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex +ELFSIZE = $(SIZE) $(MCU_FLAG) $(FORMAT_FLAG) $(TARGET).elf +MCU_FLAG = $(shell $(SIZE) --help | grep -- --mcu > /dev/null && echo --mcu=$(MCU) ) +FORMAT_FLAG = $(shell $(SIZE) --help | grep -- --format=.*avr > /dev/null && echo --format=avr ) + +sizebefore: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \ + 2>/dev/null; echo; fi + +sizeafter: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \ + 2>/dev/null; echo; fi + +checkhooks: build + @echo + @echo ------- Unhooked LUFA Events ------- + @$(shell) (grep -s '^Event.*LUFA/.*\\.o' $(TARGET).map | \ + cut -d' ' -f1 | cut -d'_' -f2- | grep ".*") || \ + echo "(None)" + @echo ----- End Unhooked LUFA Events ----- + +checklibmode: + @echo + @echo ----------- Library Mode ----------- + @$(shell) ($(CC) $(ALL_CFLAGS) -E -dM - < /dev/null \ + | grep 'USB_\(DEVICE\|HOST\)_ONLY' | cut -d' ' -f2 | grep ".*") \ + || echo "No specific mode (both device and host mode allowable)." + @echo ------------------------------------ + +# Display compiler version information. +gccversion : + @$(CC) --version + + + +# Program the device. +program: $(TARGET).hex $(TARGET).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + +flip: $(TARGET).hex + batchisp -hardware usb -device $(MCU) -operation erase f + batchisp -hardware usb -device $(MCU) -operation loadbuffer $(TARGET).hex program + batchisp -hardware usb -device $(MCU) -operation start reset 0 + +dfu: $(TARGET).hex + dfu-programmer $(MCU) erase + dfu-programmer $(MCU) flash --debug 1 $(TARGET).hex + dfu-programmer $(MCU) reset + +flip-ee: $(TARGET).hex $(TARGET).eep + copy $(TARGET).eep $(TARGET)eep.hex + batchisp -hardware usb -device $(MCU) -operation memory EEPROM erase + batchisp -hardware usb -device $(MCU) -operation memory EEPROM loadbuffer $(TARGET)eep.hex program + batchisp -hardware usb -device $(MCU) -operation start reset 0 + +dfu-ee: $(TARGET).hex $(TARGET).eep + dfu-programmer $(MCU) erase + dfu-programmer $(MCU) eeprom --debug 1 $(TARGET).eep + dfu-programmer $(MCU) reset + +# Generate avr-gdb config/init file which does the following: +# define the reset signal, load the target file, connect to target, and set +# a breakpoint at main(). +gdb-config: + @$(REMOVE) $(GDBINIT_FILE) + @echo define reset >> $(GDBINIT_FILE) + @echo SIGNAL SIGHUP >> $(GDBINIT_FILE) + @echo end >> $(GDBINIT_FILE) + @echo file $(TARGET).elf >> $(GDBINIT_FILE) + @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE) +ifeq ($(DEBUG_BACKEND),simulavr) + @echo load >> $(GDBINIT_FILE) +endif + @echo break main >> $(GDBINIT_FILE) + +debug: gdb-config $(TARGET).elf +ifeq ($(DEBUG_BACKEND), avarice) + @echo Starting AVaRICE - Press enter when "waiting to connect" message displays. + @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \ + $(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT) + @$(WINSHELL) /c pause + +else + @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \ + $(DEBUG_MFREQ) --port $(DEBUG_PORT) +endif + @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE) + + + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT = $(OBJCOPY) --debugging +COFFCONVERT += --change-section-address .data-0x800000 +COFFCONVERT += --change-section-address .bss-0x800000 +COFFCONVERT += --change-section-address .noinit-0x800000 +COFFCONVERT += --change-section-address .eeprom-0x810000 + + + +coff: $(TARGET).elf + @echo + @echo $(MSG_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-avr $< $(TARGET).cof + + +extcoff: $(TARGET).elf + @echo + @echo $(MSG_EXTENDED_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof + + + +# Create final output files (.hex, .eep) from ELF output file. +%.hex: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +%.eep: %.elf + @echo + @echo $(MSG_EEPROM) $@ + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0 + +# Create extended listing file from ELF output file. +%.lss: %.elf + @echo + @echo $(MSG_EXTENDED_LISTING) $@ + $(OBJDUMP) -h -z -S $< > $@ + +# Create a symbol table from ELF output file. +%.sym: %.elf + @echo + @echo $(MSG_SYMBOL_TABLE) $@ + $(NM) -n $< > $@ + + + +# Create library from object files. +.SECONDARY : $(TARGET).a +.PRECIOUS : $(OBJ) +%.a: $(OBJ) + @echo + @echo $(MSG_CREATING_LIBRARY) $@ + $(AR) $@ $(OBJ) + + +# Link: create ELF output file from object files. +.SECONDARY : $(TARGET).elf +.PRECIOUS : $(OBJ) +%.elf: $(OBJ) + @echo + @echo $(MSG_LINKING) $@ + $(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS) + + +# Compile: create object files from C source files. +$(OBJDIR)/%.o : %.c + @echo + @echo $(MSG_COMPILING) $< + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create object files from C++ source files. +$(OBJDIR)/%.o : %.cpp + @echo + @echo $(MSG_COMPILING_CPP) $< + $(CC) -c $(ALL_CPPFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +%.s : %.c + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C++ source files. +%.s : %.cpp + $(CC) -S $(ALL_CPPFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +$(OBJDIR)/%.o : %.S + @echo + @echo $(MSG_ASSEMBLING) $< + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + +# Create preprocessed source for use in sending a bug report. +%.i : %.c + $(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@ + + +# Target: clean project. +clean: begin clean_list clean_binary end + +clean_binary: + $(REMOVE) $(TARGET).hex + +clean_list: + @echo $(MSG_CLEANING) + $(REMOVE) $(TARGET).eep + $(REMOVE) $(TARGET).cof + $(REMOVE) $(TARGET).elf + $(REMOVE) $(TARGET).map + $(REMOVE) $(TARGET).sym + $(REMOVE) $(TARGET).lss + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o) + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst) + $(REMOVE) $(SRC:.c=.s) + $(REMOVE) $(SRC:.c=.d) + $(REMOVE) $(SRC:.c=.i) + $(REMOVEDIR) .dep + + +doxygen: + @echo Generating Project Documentation... + @doxygen Doxygen.conf + @echo Documentation Generation Complete. + +clean_doxygen: + rm -rf Documentation + +# Create object files directory +$(shell mkdir $(OBJDIR) 2>/dev/null) + + +# Include the dependency files. +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + + +# Listing of phony targets. +.PHONY : all checkhooks checklibmode begin \ +finish end sizebefore sizeafter gccversion \ +build elf hex eep lss sym coff extcoff \ +clean clean_list clean_binary program debug \ +gdb-config doxygen dfu flip diff --git a/Projects/Magstripe/CircularBitBuffer.c b/Projects/Magstripe/CircularBitBuffer.c new file mode 100644 index 0000000000..5d23762ec8 --- /dev/null +++ b/Projects/Magstripe/CircularBitBuffer.c @@ -0,0 +1,113 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Denver Gingerich (denver [at] ossguy [dot] com) + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** Circular bit buffer library. This will allow for individual bits + * to be stored in packed form inside circular buffers, to reduce + * overall RAM usage. + */ + +#include "CircularBitBuffer.h" + +/** Function to initialize or reset a bit buffer, ready for data to be stored into it. */ +void BitBuffer_Init(BitBuffer_t* Buffer) +{ + /* Reset the number of stored bits in the buffer */ + Buffer->Elements = 0; + + /* Reset the data in and out pointer structures in the buffer to the first buffer bit */ + Buffer->In.CurrentByte = Buffer->Data; + Buffer->In.ByteMask = (1 << 0); + Buffer->Out.CurrentByte = Buffer->Data; + Buffer->Out.ByteMask = (1 << 0); +} + +/** Function to store the given bit into the given bit buffer. */ +void BitBuffer_StoreNextBit(BitBuffer_t* Buffer, bool Bit) +{ + /* If the bit to store is true, set the next bit in the buffer */ + if (Bit) + *Buffer->In.CurrentByte |= Buffer->In.ByteMask; + + /* Increment the number of stored bits in the buffer counter */ + Buffer->Elements++; + + /* Check if the current buffer byte is full of stored bits */ + if (Buffer->In.ByteMask == (1 << 7)) + { + /* Check if the end of the buffer has been reached, if so reset to start of buffer, otherwise advance to next bit */ + if (Buffer->In.CurrentByte != &Buffer->Data[sizeof(Buffer->Data) - 1]) + Buffer->In.CurrentByte++; + else + Buffer->In.CurrentByte = Buffer->Data; + + /* Reset the storage bit mask in the current buffer byte to the first bit */ + Buffer->In.ByteMask = (1 << 0); + } + else + { + /* Shift the current storage bit mask to the next bit in the current byte */ + Buffer->In.ByteMask <<= 1; + } +} + +/** Function to retrieve the next bit stored in the given bit buffer. */ +bool BitBuffer_GetNextBit(BitBuffer_t* Buffer) +{ + /* Retrieve the value of the next bit stored in the buffer */ + bool Bit = ((*Buffer->Out.CurrentByte & Buffer->Out.ByteMask) != 0); + + /* Clear the buffer bit */ + *Buffer->Out.CurrentByte &= ~Buffer->Out.ByteMask; + + /* Decrement the number of stored bits in the buffer counter */ + Buffer->Elements--; + + /* Check if the current buffer byte is empty of stored bits */ + if (Buffer->Out.ByteMask == (1 << 7)) + { + /* Check if the end of the buffer has been reached, if so reset to start of buffer, otherwise advance to next bit */ + if (Buffer->Out.CurrentByte != &Buffer->Data[sizeof(Buffer->Data) - 1]) + Buffer->Out.CurrentByte++; + else + Buffer->Out.CurrentByte = Buffer->Data; + + /* Reset the retrieval bit mask in the current buffer byte to the first bit */ + Buffer->Out.ByteMask = (1 << 0); + } + else + { + /* Shift the current retrieval bit mask to the next bit in the current byte */ + Buffer->Out.ByteMask <<= 1; + } + + /* Return the retrieved bit from the buffer */ + return Bit; +} diff --git a/Projects/Magstripe/CircularBitBuffer.h b/Projects/Magstripe/CircularBitBuffer.h new file mode 100644 index 0000000000..52410f649b --- /dev/null +++ b/Projects/Magstripe/CircularBitBuffer.h @@ -0,0 +1,95 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Denver Gingerich (denver [at] ossguy [dot] com) + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for CircularBitBuffer.c. + */ + +#ifndef _CIRCULARBITBUFFER_H_ +#define _CIRCULARBITBUFFER_H_ + + /* Includes: */ + #include + #include + + #include + + /* Macros: */ + #if (defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB647__) || \ + defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__)) || defined(__DOXYGEN__) + /** Maximum number of bits which can be stored into a bit buffer. The memory usage is one eigth of this value per buffer. */ + #define MAX_BITS 20480 + #else + #define MAX_BITS 1024 + #endif + + /* Type Defines: */ + /* Type define for a pointer to a bit in a bit buffer. */ + typedef struct + { + uint8_t* CurrentByte; /**< Pointer to the current byte in the buffer */ + uint8_t ByteMask; /**< Mask of the current bit in the buffer */ + } BitBufferPointer_t; + + /** Type define for a circular packet bit buffer. */ + typedef struct + { + uint8_t Data[MAX_BITS / 8]; /**< Buffer to hold the stored bits in packed form */ + uint16_t Elements; /**< Number of stored bits in the bit buffer */ + + BitBufferPointer_t In; /**< Bit pointer to the next storage location in the buffer */ + BitBufferPointer_t Out; /**< Bit pointer to the next retrieval location in the buffer */ + } BitBuffer_t; + + /* Function Prototypes: */ + /** Initializes or resets a given bit buffer, ready to store new bits. + * + * \param Buffer Bit buffer to initialize + */ + void BitBuffer_Init(BitBuffer_t* Buffer) ATTR_NON_NULL_PTR_ARG(1); + + /** Stores a bit into the next location inside a given bit buffer. + * + * \param Buffer Bit buffer to store a bit into + * \param Bit Bit to store into the buffer + */ + void BitBuffer_StoreNextBit(BitBuffer_t* Buffer, bool Bit) ATTR_NON_NULL_PTR_ARG(1); + + /** Retrieves a bit from the next location inside a given bit buffer. + * + * \param Buffer Bit buffer to store a bit into + * + * \return Next bit from the buffer + */ + bool BitBuffer_GetNextBit(BitBuffer_t* Buffer) ATTR_NON_NULL_PTR_ARG(1); + +#endif diff --git a/Projects/Magstripe/Descriptors.c b/Projects/Magstripe/Descriptors.c new file mode 100644 index 0000000000..6811f5266e --- /dev/null +++ b/Projects/Magstripe/Descriptors.c @@ -0,0 +1,247 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Denver Gingerich (denver [at] ossguy [dot] com) + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * USB Device Descriptors, for library use when in USB device mode. Descriptors are special + * computer-readable structures which the host requests upon device enumeration, to determine + * the device's capabilities and functions. + */ + +#include "Descriptors.h" + +/** HID report descriptor. This is a HID class specific descriptor, which defines the structure of the + * reports sent and received by the HID device to and from the USB host. It indicates what data is sent, + * where in the report each element is located and exactly how the data should be interpreted and used. + * + * See the HID class specification for more information on HID report descriptors. + */ +USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] = +{ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x06, /* Usage (Keyboard) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x05, 0x07, /* Usage Page (Key Codes) */ + 0x19, 0xe0, /* Usage Minimum (Keyboard LeftControl) */ + 0x29, 0xe7, /* Usage Maximum (Keyboard Right GUI) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x08, /* Report Count (8) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x08, /* Report Size (8) */ + 0x81, 0x03, /* Input (Const, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x08, /* Report Size (8) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x65, /* Logical Maximum (101) */ + 0x05, 0x07, /* Usage Page (Keyboard) */ + 0x19, 0x00, /* Usage Minimum (Reserved (no event indicated)) */ + 0x29, 0x65, /* Usage Maximum (Keyboard Application) */ + 0x81, 0x00, /* Input (Data, Array, Absolute) */ + 0xc0 /* End Collection */ +}; + +/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall + * device characteristics, including the supported USB version, control endpoint size and the + * number of device configurations. The descriptor is read out by the USB host when the enumeration + * process begins. + */ +USB_Descriptor_Device_t PROGMEM DeviceDescriptor = +{ + Header: {Size: sizeof(USB_Descriptor_Device_t), Type: DTYPE_Device}, + + USBSpecification: VERSION_BCD(01.10), + Class: 0x00, + SubClass: 0x00, + Protocol: 0x00, + + Endpoint0Size: 8, + + VendorID: 0x03EB, + ProductID: 0x2042, + ReleaseNumber: 0x0000, + + ManufacturerStrIndex: 0x01, + ProductStrIndex: 0x02, + SerialNumStrIndex: NO_DESCRIPTOR, + + NumberOfConfigurations: 1 +}; + +/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage + * of the device in one of its supported configurations, including information about any device interfaces + * and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting + * a configuration so that the host may correctly communicate with the USB device. + */ +USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = +{ + Config: + { + Header: {Size: sizeof(USB_Descriptor_Configuration_Header_t), Type: DTYPE_Configuration}, + + TotalConfigurationSize: sizeof(USB_Descriptor_Configuration_t), + TotalInterfaces: 1, + + ConfigurationNumber: 1, + ConfigurationStrIndex: NO_DESCRIPTOR, + + ConfigAttributes: (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELFPOWERED), + + MaxPowerConsumption: USB_CONFIG_POWER_MA(100) + }, + + Interface: + { + Header: {Size: sizeof(USB_Descriptor_Interface_t), Type: DTYPE_Interface}, + + InterfaceNumber: 0x00, + AlternateSetting: 0x00, + + TotalEndpoints: 1, + + Class: 0x03, + SubClass: 0x01, + Protocol: 0x01, + + InterfaceStrIndex: NO_DESCRIPTOR + }, + + KeyboardHID: + { + Header: {Size: sizeof(USB_Descriptor_HID_t), Type: DTYPE_HID}, + + HIDSpec: VERSION_BCD(01.11), + CountryCode: 0x00, + TotalHIDReports: 0x01, + HIDReportType: DTYPE_Report, + HIDReportLength: sizeof(KeyboardReport) + }, + + KeyboardEndpoint: + { + Header: {Size: sizeof(USB_Descriptor_Endpoint_t), Type: DTYPE_Endpoint}, + + EndpointAddress: (ENDPOINT_DESCRIPTOR_DIR_IN | KEYBOARD_EPNUM), + Attributes: EP_TYPE_INTERRUPT, + EndpointSize: KEYBOARD_EPSIZE, + PollingIntervalMS: 0x02 + }, +}; + +/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests + * the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate + * via the language ID table available at USB.org what languages the device supports for its string descriptors. */ +USB_Descriptor_String_t PROGMEM LanguageString = +{ + Header: {Size: USB_STRING_LEN(1), Type: DTYPE_String}, + + UnicodeString: {LANGUAGE_ID_ENG} +}; + +/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable + * form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +USB_Descriptor_String_t PROGMEM ManufacturerString = +{ + Header: {Size: USB_STRING_LEN(32), Type: DTYPE_String}, + + UnicodeString: L"Dean Camera and Denver Gingerich" +}; + +/** Product descriptor string. This is a Unicode string containing the product's details in human readable form, + * and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +USB_Descriptor_String_t PROGMEM ProductString = +{ + Header: {Size: USB_STRING_LEN(20), Type: DTYPE_String}, + + UnicodeString: L"Magnetic Card Reader" +}; + +/** This function is called by the library when in device mode, and must be overridden (see StdDescriptors.h + * documentation) by the application code so that the address and size of a requested descriptor can be given + * to the USB library. When the device recieves a Get Descriptor request on the control endpoint, this function + * is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the + * USB host. + */ +uint16_t USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) +{ + const uint8_t DescriptorType = (wValue >> 8); + const uint8_t DescriptorNumber = (wValue & 0xFF); + + void* Address = NULL; + uint16_t Size = NO_DESCRIPTOR; + + switch (DescriptorType) + { + case DTYPE_Device: + Address = DESCRIPTOR_ADDRESS(DeviceDescriptor); + Size = sizeof(USB_Descriptor_Device_t); + break; + case DTYPE_Configuration: + Address = DESCRIPTOR_ADDRESS(ConfigurationDescriptor); + Size = sizeof(USB_Descriptor_Configuration_t); + break; + case DTYPE_String: + switch (DescriptorNumber) + { + case 0x00: + Address = DESCRIPTOR_ADDRESS(LanguageString); + Size = pgm_read_byte(&LanguageString.Header.Size); + break; + case 0x01: + Address = DESCRIPTOR_ADDRESS(ManufacturerString); + Size = pgm_read_byte(&ManufacturerString.Header.Size); + break; + case 0x02: + Address = DESCRIPTOR_ADDRESS(ProductString); + Size = pgm_read_byte(&ProductString.Header.Size); + break; + } + + break; + case DTYPE_HID: + Address = DESCRIPTOR_ADDRESS(ConfigurationDescriptor.KeyboardHID); + Size = sizeof(USB_Descriptor_HID_t); + break; + case DTYPE_Report: + Address = DESCRIPTOR_ADDRESS(KeyboardReport); + Size = sizeof(KeyboardReport); + break; + } + + *DescriptorAddress = Address; + return Size; +} diff --git a/Projects/Magstripe/Descriptors.h b/Projects/Magstripe/Descriptors.h new file mode 100644 index 0000000000..2f58545231 --- /dev/null +++ b/Projects/Magstripe/Descriptors.h @@ -0,0 +1,98 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Denver Gingerich (denver [at] ossguy [dot] com) + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for Descriptors.c. + */ + +#ifndef _DESCRIPTORS_H_ +#define _DESCRIPTORS_H_ + + /* Includes: */ + #include + + #include + + /* Type Defines: */ + /** Type define for the HID class specific HID descriptor. A HID descriptor is used in HID class devices + * to give information about the HID device, including the HID specification used, and the report descriptors + * the device contains to describe how the HID device should be controlled. + */ + typedef struct + { + USB_Descriptor_Header_t Header; /**< Standard USB descriptor header */ + + uint16_t HIDSpec; /**< HID specification implemented by the device, in BCD form */ + uint8_t CountryCode; /**< Country code for the country the HID device is localised for */ + + uint8_t TotalHIDReports; /**< Total number of HID reports linked to this HID interface */ + + uint8_t HIDReportType; /**< Type of the first HID report descriptor */ + uint16_t HIDReportLength; /**< Length of the first HID report descriptor */ + } USB_Descriptor_HID_t; + + /** Type define for the data type used for the HID Report descriptor data elements. A HID report + * descriptor contains an array of this data type, indicating how the reports from and to the + * device are formatted and how the report data is to be used by the host. + */ + typedef uint8_t USB_Descriptor_HIDReport_Datatype_t; + + /** Type define for the device configuration descriptor structure. This must be defined in the + * application code, as the configuration descriptor contains several sub-descriptors which + * vary between devices, and which describe the device's usage to the host. + */ + typedef struct + { + USB_Descriptor_Configuration_Header_t Config; /**< Configuration descriptor header structure */ + USB_Descriptor_Interface_t Interface; /**< Keyboard interface descriptor */ + USB_Descriptor_HID_t KeyboardHID; /**< Keyboard HID descriptor */ + USB_Descriptor_Endpoint_t KeyboardEndpoint; /**< Keyboard key report endpoint descriptor */ + } USB_Descriptor_Configuration_t; + + /* Macros: */ + /** Endpoint number of the keyboard key press reporting endpoint. */ + #define KEYBOARD_EPNUM 1 + + /** Size of the keyboard report endpoints, in bytes. */ + #define KEYBOARD_EPSIZE 8 + + /** Descriptor type value for a HID descriptor. */ + #define DTYPE_HID 0x21 + + /** Descriptor type value for a HID report. */ + #define DTYPE_Report 0x22 + + /* Function Prototypes: */ + uint16_t USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) + ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); + +#endif diff --git a/Projects/Magstripe/Doxygen.conf b/Projects/Magstripe/Doxygen.conf new file mode 100644 index 0000000000..4d0abf9b53 --- /dev/null +++ b/Projects/Magstripe/Doxygen.conf @@ -0,0 +1,1485 @@ +# Doxyfile 1.5.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "Denver Gingerich's Stripe Snoop Project" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.0.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./Documentation/ + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = YES + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ./ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.h \ + *.c \ + *.txt + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = */LowLevel/USBMode.h + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = __* + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = NO + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = YES + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Namespace. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Virtual Folders. + +QHP_VIRTUAL_FOLDER = doc + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file . + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 1 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = __DOXYGEN__ + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = BUTTLOADTAG + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = NO + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = NO + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = NO + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = NO + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = NO + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = NO + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = "C:/Program Files/Graphviz2.18/bin" + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 15 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 2 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = YES + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/Projects/Magstripe/Magstripe.aps b/Projects/Magstripe/Magstripe.aps new file mode 100644 index 0000000000..86d011abb0 --- /dev/null +++ b/Projects/Magstripe/Magstripe.aps @@ -0,0 +1 @@ +Magstripe30-Sep-2008 14:19:1430-Sep-2008 14:19:28241030-Sep-2008 14:19:1444, 14, 0, 589AVR GCCC:\Users\Dean\Documents\Electronics\Projects\WORK\MyUSBWORK\Projects\Magstripe\falseR00R01R02R03R04R05R06R07R08R09R10R11R12R13R14R15R16R17R18R19R20R21R22R23R24R25R26R27R28R29R30R31Auto000Descriptors.cMagstripe.cDescriptors.hMagstripe.hMagstripeHW.hmakefiledefaultYESmakefileatmega128111Magstripe.elfdefault\1-Wall -gdwarf-2 -std=gnu99 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enumsdefault1C:\WinAVR-20080512\bin\avr-gcc.exeC:\WinAVR-20080512\utils\bin\make.exe diff --git a/Projects/Magstripe/Magstripe.c b/Projects/Magstripe/Magstripe.c new file mode 100644 index 0000000000..3696c12496 --- /dev/null +++ b/Projects/Magstripe/Magstripe.c @@ -0,0 +1,436 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Denver Gingerich (denver [at] ossguy [dot] com) + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Main source file for the MagStripe application. This file contains the code which drives + * the USB keyboard interface from the magnetic card stripe reader device. + */ + +#include "Magstripe.h" + +/* Project Tags, for reading out using the ButtLoad project */ +BUTTLOADTAG(ProjName, "Magstripe Reader"); +BUTTLOADTAG(BuildTime, __TIME__); +BUTTLOADTAG(BuildDate, __DATE__); +BUTTLOADTAG(LUFAVersion, "LUFA V" LUFA_VERSION_STRING); + +/* Scheduler Task List */ +TASK_LIST +{ + { Task: USB_USBTask , TaskStatus: TASK_STOP }, + { Task: USB_Keyboard_Report , TaskStatus: TASK_STOP }, + { Task: Magstripe_Read , TaskStatus: TASK_STOP }, +}; + +/* Global Variables */ +/** Indicates if the device is using Report Protocol mode, instead of Boot Protocol mode. Boot Protocol mode + * is a special reporting mode used by compatible PC BIOS to support USB keyboards before a full OS and USB + * driver has been loaded, by using predefined report structures indicated in the USB HID standard. + */ +bool UsingReportProtocol = true; + +/** Total idle period in milliseconds set by the host via a SetIdle request, used to silence the report endpoint + * until the report data changes or the idle period elapsed. Generally used to implement hardware key repeats, or + * by some BIOS to reduce the number of reports when in Boot Protocol mode. + */ +uint8_t IdleCount = 0; + +/** Milliseconds remaining counter for the HID class SetIdle and GetIdle requests, used to silence the report + * endpoint for an amount of time indicated by the host or until the report changes. + */ +uint16_t IdleMSRemaining = 0; + +/** Circular buffer to hold the read bits from track 1 of the inserted magnetic card. */ +BitBuffer_t Track1Data; + +/** Circular buffer to hold the read bits from track 2 of the inserted magnetic card. */ +BitBuffer_t Track2Data; + +/** Circular buffer to hold the read bits from track 3 of the inserted magnetic card. */ +BitBuffer_t Track3Data; + +/** Delay counter between sucessive key strokes. This is to prevent the OS from ignoring multiple keys in a short + * period of time due to key repeats. Two milliseconds works for most OSes. + */ +uint8_t KeyDelayRemaining; + + +/** Main program entry point. This routine configures the hardware required by the application, then + * starts the scheduler to run the application tasks. + */ +int main(void) +{ + /* Disable watchdog if enabled by bootloader/fuses */ + MCUSR &= ~(1 << WDRF); + wdt_disable(); + + /* Disable Clock Division */ + SetSystemClockPrescaler(0); + + /* Hardware Initialization */ + Magstripe_Init(); + + /* Buffer Initialization */ + BitBuffer_Init(&Track1Data); + BitBuffer_Init(&Track2Data); + BitBuffer_Init(&Track3Data); + + /* Millisecond timer initialization, with output compare interrupt enabled for the idle timing */ + OCR0A = 0xFA; + TCCR0A = (1 << WGM01); + TCCR0B = ((1 << CS01) | (1 << CS00)); + TIMSK0 = (1 << OCIE0A); + + /* Initialize Scheduler so that it can be used */ + Scheduler_Init(); + + /* Initialize USB Subsystem */ + USB_Init(); + + /* Scheduling - routine never returns, so put this last in the main function */ + Scheduler_Start(); +} + +/** Event handler for the USB_Connect event. This starts the USB task. */ +EVENT_HANDLER(USB_Connect) +{ + /* Start USB management task */ + Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); +} + +/** Event handler for the USB_Disconnect event. This stops the USB and keyboard report tasks. */ +EVENT_HANDLER(USB_Disconnect) +{ + /* Stop running keyboard reporting, card reading and USB management tasks */ + Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_STOP); + Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); + Scheduler_SetTaskMode(Magstripe_Read, TASK_STOP); +} + +/** Event handler for the USB_ConfigurationChanged event. This configures the device's endpoints ready + * to relay reports to the host, and starts the keyboard report task. + */ +EVENT_HANDLER(USB_ConfigurationChanged) +{ + /* Setup Keyboard Keycode Report Endpoint */ + Endpoint_ConfigureEndpoint(KEYBOARD_EPNUM, EP_TYPE_INTERRUPT, + ENDPOINT_DIR_IN, KEYBOARD_EPSIZE, + ENDPOINT_BANK_SINGLE); + + /* Default to report protocol on connect */ + UsingReportProtocol = true; + + /* Start Keyboard reporting and card reading tasks */ + Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_RUN); + Scheduler_SetTaskMode(Magstripe_Read, TASK_RUN); +} + +/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific + * control requests that are not handled internally by the USB library, so that they can be handled appropriately + * for the application. + */ +EVENT_HANDLER(USB_UnhandledControlPacket) +{ + /* Handle HID Class specific requests */ + switch (bRequest) + { + case REQ_GetReport: + if (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + USB_KeyboardReport_Data_t KeyboardReportData; + + /* Create the next keyboard report for transmission to the host */ + GetNextReport(&KeyboardReportData); + + /* Ignore report type and ID number value */ + Endpoint_Discard_Word(); + + /* Ignore unused Interface number value */ + Endpoint_Discard_Word(); + + /* Read in the number of bytes in the report to send to the host */ + uint16_t wLength = Endpoint_Read_Word_LE(); + + /* If trying to send more bytes than exist to the host, clamp the value at the report size */ + if (wLength > sizeof(KeyboardReportData)) + wLength = sizeof(KeyboardReportData); + + Endpoint_ClearSetupReceived(); + + /* Write the report data to the control endpoint */ + Endpoint_Write_Control_Stream_LE(&KeyboardReportData, wLength); + + /* Finalize the stream transfer to send the last packet or clear the host abort */ + Endpoint_ClearSetupOUT(); + } + + break; + case REQ_GetProtocol: + if (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSetupReceived(); + + /* Write the current protocol flag to the host */ + Endpoint_Write_Byte(UsingReportProtocol); + + /* Send the flag to the host */ + Endpoint_ClearSetupIN(); + } + + break; + case REQ_SetProtocol: + if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + /* Read in the wValue parameter containing the new protocol mode */ + uint16_t wValue = Endpoint_Read_Word_LE(); + + Endpoint_ClearSetupReceived(); + + /* Set or clear the flag depending on what the host indicates that the current Protocol should be */ + UsingReportProtocol = (wValue != 0x0000); + + /* Send an empty packet to acknowedge the command */ + Endpoint_ClearSetupIN(); + } + + break; + case REQ_SetIdle: + if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + /* Read in the wValue parameter containing the idle period */ + uint16_t wValue = Endpoint_Read_Word_LE(); + + Endpoint_ClearSetupReceived(); + + /* Get idle period in MSB */ + IdleCount = (wValue >> 8); + + /* Send an empty packet to acknowedge the command */ + Endpoint_ClearSetupIN(); + } + + break; + case REQ_GetIdle: + if (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSetupReceived(); + + /* Write the current idle duration to the host */ + Endpoint_Write_Byte(IdleCount); + + /* Send the flag to the host */ + Endpoint_ClearSetupIN(); + } + + break; + } +} + +/** ISR for the timer 0 compare vector. This ISR fires once each millisecond, and decrements the counter indicating + * the number of milliseconds left to idle (not send the host reports) if the device has been instructed to idle + * by the host via a SetIdle class specific request. + */ +ISR(TIMER0_COMPA_vect, ISR_BLOCK) +{ + /* One millisecond has elapsed, decrement the idle time remaining counter if it has not already elapsed */ + if (IdleMSRemaining) + IdleMSRemaining--; + + if (KeyDelayRemaining) + KeyDelayRemaining--; +} + +/** Constructs a keyboard report indicating the currently pressed keyboard keys to the host. + * + * \param ReportData Pointer to a USB_KeyboardReport_Data_t report structure where the resulting report should + * be stored + * + * \return Boolean true if the current report is different to the previous report, false otherwise + */ +bool GetNextReport(USB_KeyboardReport_Data_t* ReportData) +{ + static bool OddReport = false; + static bool MustRelease = false; + + BitBuffer_t* Buffer = NULL; + + /* Clear the report contents */ + memset(ReportData, 0, sizeof(USB_KeyboardReport_Data_t)); + + /* Get the next non-empty track data buffer */ + if (Track1Data.Elements) + Buffer = &Track1Data; + else if (Track2Data.Elements) + Buffer = &Track2Data; + else if (Track3Data.Elements) + Buffer = &Track3Data; + + if (Buffer != NULL) + { + /* Toggle the odd report number indicator */ + OddReport = !OddReport; + + /* Set the flag indicating that a null report must eventually be sent to release all pressed keys */ + MustRelease = true; + + /* Only send the next key on odd reports, so that they are interpersed with null reports to release keys */ + if (OddReport) + { + /* Set the report key code to the key code for the next data bit */ + ReportData->KeyCode[0] = BitBuffer_GetNextBit(Buffer) ? KEY_1 : KEY_0; + + /* If buffer is now empty, a new line must be sent instead of the terminating bit */ + if (!(Buffer->Elements)) + { + /* Set the keycode to the code for an enter key press */ + ReportData->KeyCode[0] = KEY_ENTER; + } + } + + return true; + } + else if (MustRelease) + { + /* Leave key code to null (0), to release all pressed keys */ + return true; + } + + return false; +} + +/** Task to read out data from inserted magnetic cards and place the seperate track data into their respective + * data buffers for later sending to the host as keyboard key presses. + */ +TASK(Magstripe_Read) +{ + /* Arrays to hold the buffer pointers, clock and data bit masks for the seperate card tracks */ + const struct + { + BitBuffer_t* Buffer; + uint8_t ClockMask; + uint8_t DataMask; + } TrackInfo[] = {{&Track1Data, MAG_T1_CLOCK, MAG_T1_DATA}, + {&Track2Data, MAG_T2_CLOCK, MAG_T2_DATA}, + {&Track3Data, MAG_T3_CLOCK, MAG_T3_DATA}}; + + /* Previous magnetic card control line' status, for later comparison */ + uint8_t Magstripe_Prev = 0; + + /* Buffered current card reader control line' status */ + uint8_t Magstripe_LCL = Magstripe_GetStatus(); + + /* Exit the task early if no card is present in the reader */ + if (!(Magstripe_LCL & MAG_CARDPRESENT)) + return; + + /* Read out card data while a card is present */ + while (Magstripe_LCL & MAG_CARDPRESENT) + { + /* Read out the next bit for each track of the card */ + for (uint8_t Track = 0; Track < 3; Track++) + { + /* Current data line status for the current card track */ + bool DataLevel = ((Magstripe_LCL & TrackInfo[Track].DataMask) != 0); + + /* Current clock line status for the current card track */ + bool ClockLevel = ((Magstripe_LCL & TrackInfo[Track].ClockMask) != 0); + + /* Current track clock transition check */ + bool ClockChanged = (((Magstripe_LCL ^ Magstripe_Prev) & TrackInfo[Track].ClockMask) != 0); + + /* Sample the next bit on the falling edge of the track's clock line, store key code into the track's buffer */ + if (ClockLevel && ClockChanged) + BitBuffer_StoreNextBit(TrackInfo[Track].Buffer, DataLevel); + } + + /* Retain the current card reader control line states for later edge detection */ + Magstripe_Prev = Magstripe_LCL; + + /* Retrieve the new card reader control line states */ + Magstripe_LCL = Magstripe_GetStatus(); + } + + /* Add terminators to the end of each track buffer */ + BitBuffer_StoreNextBit(&Track1Data, 0); + BitBuffer_StoreNextBit(&Track2Data, 0); + BitBuffer_StoreNextBit(&Track3Data, 0); +} + +/** Task for the magnetic card reading and keyboard report generation. This task waits until a card is inserted, + * then reads off the card data and sends it to the host as a series of keyboard keypresses via keyboard reports. + */ +TASK(USB_Keyboard_Report) +{ + USB_KeyboardReport_Data_t KeyboardReportData; + bool SendReport = false; + + /* Check if the USB system is connected to a host */ + if (USB_IsConnected) + { + /* Select the Keyboard Report Endpoint */ + Endpoint_SelectEndpoint(KEYBOARD_EPNUM); + + /* Check if Keyboard Endpoint Ready for Read/Write */ + if (Endpoint_ReadWriteAllowed()) + { + /* Only fetch the next key to send once the period between key presses has elapsed */ + if (!(KeyDelayRemaining)) + { + /* Create the next keyboard report for transmission to the host */ + SendReport = GetNextReport(&KeyboardReportData); + } + + /* Check if the idle period is set and has elapsed */ + if (IdleCount && !(IdleMSRemaining)) + { + /* Idle period elapsed, indicate that a report must be sent */ + SendReport = true; + + /* Reset the idle time remaining counter, must multiply by 4 to get the duration in milliseconds */ + IdleMSRemaining = (IdleCount << 2); + } + + /* Write the keyboard report if a report is to be sent to the host */ + if (SendReport) + { + /* Write Keyboard Report Data */ + Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(USB_KeyboardReport_Data_t)); + + /* Finalize the stream transfer to send the last packet */ + Endpoint_ClearCurrentBank(); + + /* Reset the key delay period counter */ + KeyDelayRemaining = 2; + } + } + } +} diff --git a/Projects/Magstripe/Magstripe.h b/Projects/Magstripe/Magstripe.h new file mode 100644 index 0000000000..cde2fcdc63 --- /dev/null +++ b/Projects/Magstripe/Magstripe.h @@ -0,0 +1,121 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Denver Gingerich (denver [at] ossguy [dot] com) + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for Magstripe.c. + */ + +#ifndef _MAGSTRIPE_H_ +#define _MAGSTRIPE_H_ + + /* Includes: */ + #include + #include + #include + #include + #include + + #include "Descriptors.h" + #include "MagstripeHW.h" + #include "CircularBitBuffer.h" + + #include // Library Version Information + #include // PROGMEM tags readable by the ButtLoad project + #include // USB Functionality + #include // Simple scheduler for task management + + + /* Task Definitions: */ + /** Task definition for the keyboard and magnetic card reading task. */ + TASK(USB_Keyboard_Report); + + TASK(Magstripe_Read); + + /* Macros: */ + /** HID Class Specific Request to get the current HID report from the device. */ + #define REQ_GetReport 0x01 + + /** HID Class Specific Request to get the current device idle count. */ + #define REQ_GetIdle 0x02 + + /** HID Class Specific Request to set the current HID report to the device. */ + #define REQ_SetReport 0x09 + + /** HID Class Specific Request to set the device's idle count. */ + #define REQ_SetIdle 0x0A + + /** HID Class Specific Request to get the current HID report protocol mode. */ + #define REQ_GetProtocol 0x03 + + /** HID Class Specific Request to set the current HID report protocol mode. */ + #define REQ_SetProtocol 0x0B + + /** HID keyboard keycode to indicate that the "1" key is currently pressed. */ + #define KEY_1 30 + + /** HID keyboard keycode to indicate that the "0" key is currently pressed. */ + #define KEY_0 39 + + /** HID keyboard keycode to indicate that the enter key is currently pressed. */ + #define KEY_ENTER 40 + + /* Type Defines: */ + /** Type define for the keyboard report structure. This structure matches the report layout + * given to the host in the HID Report descriptor, as well as matches the boot protocol report + * structure. This means that this one report structure can be used in both Report and Boot Protocol + * modes. */ + typedef struct + { + uint8_t Modifier; /**< Modifier byte, indicating pressed modifier keys such as CTRL or ALT */ + uint8_t Reserved; /**< Reserved for OEM use, always set to 0 */ + uint8_t KeyCode[6]; /**< Key code array for pressed keys - up to six can be given simultaneously */ + } USB_KeyboardReport_Data_t; + + /* Event Handlers: */ + /** Indicates that this module will catch the USB_Connect event when thrown by the library. */ + HANDLES_EVENT(USB_Connect); + + /** Indicates that this module will catch the USB_Disconnect event when thrown by the library. */ + HANDLES_EVENT(USB_Disconnect); + + /** Indicates that this module will catch the USB_ConfigurationChanged event when thrown by the library. */ + HANDLES_EVENT(USB_ConfigurationChanged); + + /** Indicates that this module will catch the USB_UnhandledControlPacket event when thrown by the library. */ + HANDLES_EVENT(USB_UnhandledControlPacket); + + /* Function Prototypes: */ + bool GetNextReport(USB_KeyboardReport_Data_t* ReportData); + void SendKey(USB_KeyboardReport_Data_t* KeyboardReportData, uint8_t Key); + void Send(USB_KeyboardReport_Data_t* KeyboardReportData, bool SendReport); + +#endif diff --git a/Projects/Magstripe/Magstripe.txt b/Projects/Magstripe/Magstripe.txt new file mode 100644 index 0000000000..d91fddde7f --- /dev/null +++ b/Projects/Magstripe/Magstripe.txt @@ -0,0 +1,85 @@ +/** \file + * + * This file contains special DoxyGen information for the generation of the main page and other special + * documentation pages. It is not a project source file. + */ + +/** \mainpage Denver Gingerich's USBSnoop Magnetic Card Reader Project + * + * Firmware for a USB AVR powered USB TTL magnetic stripe reader (using a card + * reader such as the Omron V3B-4K) by Denver Gingerich. This project is designed + * to be used with the open source Stripe Snoop project at http://stripesnoop.sourceforge.net/. + * + * See http://ossguy.com/ss_usb/ for the USB reader hardware project website, + * including construction and support details. + * + * To use, connect your magentic card reader device to the USB AVR as follows (pin and port mapping may be adjusted + * from the project makefile): + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Signal:AVR Port:
Track 1 DataPORTC, Pin 1
Track 1 ClockPORTC, Pin 2
Track 2 DataPORTC, Pin 3
Track 2 ClockPORTC, Pin 0
Track 3 DataPORTC, Pin 5
Track 3 ClockPORTC, Pin 6
Card DetectPORTC, Pin 4
+ * + * + * This project is based on the LUFA Keyboard demonstration application, + * written by Denver Gingerich. + * + * This application uses a keyboard HID driver to communicate the data collected + * a TTL magnetic stripe reader to the connected computer. The raw bitstream + * obtained from the magnetic stripe reader is "typed" through the keyboard + * driver as 0's and 1's. After every card swipe, the demo will send a return key. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
USB Mode:Device
USB Class:Human Interface Device (HID)
USB Subclass:Keyboard
Relevant Standards:USBIF HID Standard, USBIF HID Usage Tables
Usable Speeds:Low Speed Mode, Full Speed Mode
+ */ diff --git a/Projects/Magstripe/MagstripeHW.h b/Projects/Magstripe/MagstripeHW.h new file mode 100644 index 0000000000..c4681188a2 --- /dev/null +++ b/Projects/Magstripe/MagstripeHW.h @@ -0,0 +1,100 @@ +/* + Copyright 2009 Denver Gingerich (denver [at] ossguy [dot] com) + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/* + NOTE: The user of this include file MUST define the following macros + prior to including the file: + + MAG_T1_CLOCK_PIN Pin connected to Track 1 clock wire (ie. PORTC1) + MAG_T1_DATA_PIN Pin connected to Track 1 data wire (ie. PORTC2) + MAG_T2_CLOCK_PIN Pin connected to Track 2 clock wire (ie. PORTC3) + MAG_T2_DATA_PIN Pin connected to Track 2 data wire (ie. PORTC0) + MAG_T3_CLOCK_PIN Pin connected to Track 3 clock wire (ie. PORTC5) + MAG_T3_DATA_PIN Pin connected to Track 3 data wire (ie. PORTC6) + MAG_CLS_PIN Pin connected to card loaded wire (ie. PORTC4) + MAG_PIN PIN macro for the reader's port (ie. PINC) + MAG_DDR DDR macro for the reader's port (ie. DDRC) + MAG_PORT PORT macro for the reader's port (ie. PORTC) + + The example macros listed above assume that the Track 2 data wire is + connected to pin 0 on port C, the Track 2 clock wire is connected to + pin 3 on port C (similarly for Tracks 1 and 3), and the card loaded + wire is connected to pin 4 on port C. + + If the magstripe reader you are using only reads one or two tracks, + then set the clock and data pins for the tracks it doesn't read to a + pin that is unused. For example, on the AT90USBKey, any of the pins on + port C that do not have wires attached will be unused since they are + not connected to any onboard devices (such as the joystick or + temperature sensor). + + Connecting wires to pins on different ports (ie. a data wire to pin 0 + on port C and a clock wire to pin 0 on port D) is currently + unsupported. All pins specified above must be on the same port. +*/ + +/** \file + * + * Driver header for a TTL Magnetic Card reader device (such as the Omron V3B-4K). + */ + +#ifndef _MAGSTRIPEHW_H_ +#define _MAGSTRIPEHW_H_ + + /* Includes: */ + #include + + #include + + /* Private Interface - For use in library only: */ + /* Macros: */ + /** Mask of the track data, clock and card detection pins. */ + #define MAG_MASK (MAG_T1_DATA | MAG_T1_CLOCK | \ + MAG_T2_DATA | MAG_T2_CLOCK | \ + MAG_T3_DATA | MAG_T3_CLOCK | \ + MAG_CARDPRESENT) + + /* Public Interface - May be used in end-application: */ + /* Inline Functions: */ + /** Initializes the magnetic stripe card reader ports and pins so that the card reader + * device can be controlled and read by the card reader driver. This must be called before + * trying to read any of the card reader's status lines. + */ + static inline void Magstripe_Init(void) + { + MAG_DDR &= ~MAG_MASK; + MAG_PORT |= MAG_MASK; + }; + + /** Returns the status of all the magnetic card reader's outputs. + * + * \return A mask indicating which card lines are high or low + */ + static inline uint8_t Magstripe_GetStatus(void) ATTR_WARN_UNUSED_RESULT; + static inline uint8_t Magstripe_GetStatus(void) + { + /* Magstripe IOs are active low and must be inverted when read */ + return ((uint8_t)~MAG_PIN & MAG_MASK); + } + +#endif diff --git a/Projects/Magstripe/makefile b/Projects/Magstripe/makefile new file mode 100644 index 0000000000..2ea5536fb1 --- /dev/null +++ b/Projects/Magstripe/makefile @@ -0,0 +1,712 @@ +# Hey Emacs, this is a -*- makefile -*- +#---------------------------------------------------------------------------- +# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al. +# >> Modified for use with the LUFA project. << +# +# Released to the Public Domain +# +# Additional material for this makefile was written by: +# Peter Fleury +# Tim Henigan +# Colin O'Flynn +# Reiner Patommel +# Markus Pfaff +# Sander Pool +# Frederik Rouleau +# Carlos Lamas +# Dean Camera +# Opendous Inc. +# Denver Gingerich +# +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device, using avrdude. +# Please customize the avrdude settings below first! +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# make doxygen = Generate DoxyGen documentation for the project (must have +# DoxyGen installed) +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + + +# MCU name +MCU = at90usb1287 + + +# Target board (see library BoardTypes.h documentation, USER or blank for projects not requiring +# LUFA board drivers). If USER is selected, put custom board drivers in a directory called +# "Board" inside the application directory. +BOARD = USBKEY + + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# Typical values are: +# F_CPU = 1000000 +# F_CPU = 1843200 +# F_CPU = 2000000 +# F_CPU = 3686400 +# F_CPU = 4000000 +# F_CPU = 7372800 +# F_CPU = 8000000 +# F_CPU = 11059200 +# F_CPU = 14745600 +# F_CPU = 16000000 +# F_CPU = 18432000 +# F_CPU = 20000000 +F_CPU = 16000000 + + +# Output format. (can be srec, ihex, binary) +FORMAT = ihex + + +# Target file name (without extension). +TARGET = Magstripe + + +# Object files directory +# To put object files in current directory, use a dot (.), do NOT make +# this an empty or blank macro! +OBJDIR = . + + +# List C source files here. (C dependencies are automatically generated.) +SRC = $(TARGET).c \ + Descriptors.c \ + CircularBitBuffer.c \ + ../../LUFA/Scheduler/Scheduler.c \ + ../../LUFA/Drivers/USB/LowLevel/LowLevel.c \ + ../../LUFA/Drivers/USB/LowLevel/Endpoint.c \ + ../../LUFA/Drivers/USB/LowLevel/DevChapter9.c \ + ../../LUFA/Drivers/USB/HighLevel/USBTask.c \ + ../../LUFA/Drivers/USB/HighLevel/USBInterrupt.c \ + ../../LUFA/Drivers/USB/HighLevel/Events.c \ + ../../LUFA/Drivers/USB/HighLevel/StdDescriptors.c \ + +# List C++ source files here. (C dependencies are automatically generated.) +CPPSRC = + + +# List Assembler source files here. +# Make them always end in a capital .S. Files ending in a lowercase .s +# will not be considered source files but generated files (assembler +# output from the compiler), and will be deleted upon "make clean"! +# Even though the DOS/Win* filesystem matches both .s and .S the same, +# it will preserve the spelling of the filenames, and gcc itself does +# care about how the name is spelled on its command-line. +ASRC = + + +# Optimization level, can be [0, 1, 2, 3, s]. +# 0 = turn off optimization. s = optimize for size. +# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) +OPT = s + + +# Debugging format. +# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs. +# AVR Studio 4.10 requires dwarf-2. +# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run. +DEBUG = dwarf-2 + + +# List any extra directories to look for include files here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRAINCDIRS = ../../ + + +# Compiler flag to set the C Standard level. +# c89 = "ANSI" C +# gnu89 = c89 plus GCC extensions +# c99 = ISO C99 standard (not yet fully implemented) +# gnu99 = c99 plus GCC extensions +CSTANDARD = -std=gnu99 + + +# Place -D or -U options here for C sources +CDEFS = -DF_CPU=$(F_CPU)UL -DBOARD=BOARD_$(BOARD) -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS +CDEFS += -DUSB_DEVICE_ONLY -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" + +CDEFS += -DMAG_T1_CLOCK="(1 << 0)" +CDEFS += -DMAG_T1_DATA="(1 << 1)" +CDEFS += -DMAG_T2_CLOCK="(1 << 2)" +CDEFS += -DMAG_T2_DATA="(1 << 3)" +CDEFS += -DMAG_T3_CLOCK="(1 << 4)" +CDEFS += -DMAG_T3_DATA="(1 << 5)" +CDEFS += -DMAG_CARDPRESENT="(1 << 6)" +CDEFS += -DMAG_PIN=PINB +CDEFS += -DMAG_DDR=DDRB +CDEFS += -DMAG_PORT=PORTB + +# Place -D or -U options here for ASM sources +ADEFS = -DF_CPU=$(F_CPU) + + +# Place -D or -U options here for C++ sources +CPPDEFS = -DF_CPU=$(F_CPU)UL +#CPPDEFS += -D__STDC_LIMIT_MACROS +#CPPDEFS += -D__STDC_CONSTANT_MACROS + + + +#---------------- Compiler Options C ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CFLAGS = -g$(DEBUG) +CFLAGS += $(CDEFS) +CFLAGS += -O$(OPT) +CFLAGS += -funsigned-char +CFLAGS += -funsigned-bitfields +CFLAGS += -fpack-struct +CFLAGS += -fshort-enums +CFLAGS += -ffunction-sections +CFLAGS += -finline-limit=20 +CFLAGS += -Wall +CFLAGS += -Wstrict-prototypes +CFLAGS += -Wundef +#CFLAGS += -fno-unit-at-a-time +#CFLAGS += -Wunreachable-code +#CFLAGS += -Wsign-compare +CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst) +CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +CFLAGS += $(CSTANDARD) + + +#---------------- Compiler Options C++ ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CPPFLAGS = -g$(DEBUG) +CPPFLAGS += $(CPPDEFS) +CPPFLAGS += -O$(OPT) +CPPFLAGS += -funsigned-char +CPPFLAGS += -funsigned-bitfields +CPPFLAGS += -fpack-struct +CPPFLAGS += -fshort-enums +CPPFLAGS += -fno-exceptions +CPPFLAGS += -Wall +CFLAGS += -Wundef +#CPPFLAGS += -fno-unit-at-a-time +#CPPFLAGS += -Wstrict-prototypes +#CPPFLAGS += -Wunreachable-code +#CPPFLAGS += -Wsign-compare +CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst) +CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +#CPPFLAGS += $(CSTANDARD) + + +#---------------- Assembler Options ---------------- +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns: create listing +# -gstabs: have the assembler create line number information; note that +# for use in COFF files, additional information about filenames +# and function names needs to be present in the assembler source +# files -- see avr-libc docs [FIXME: not yet described there] +# -listing-cont-lines: Sets the maximum number of continuation lines of hex +# dump that will be displayed for a given single line of source input. +ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100 + + +#---------------- Library Options ---------------- +# Minimalistic printf version +PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min + +# Floating point printf version (requires MATH_LIB = -lm below) +PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt + +# If this is left blank, then it will use the Standard printf version. +PRINTF_LIB = +#PRINTF_LIB = $(PRINTF_LIB_MIN) +#PRINTF_LIB = $(PRINTF_LIB_FLOAT) + + +# Minimalistic scanf version +SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min + +# Floating point + %[ scanf version (requires MATH_LIB = -lm below) +SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt + +# If this is left blank, then it will use the Standard scanf version. +SCANF_LIB = +#SCANF_LIB = $(SCANF_LIB_MIN) +#SCANF_LIB = $(SCANF_LIB_FLOAT) + + +MATH_LIB = -lm + + +# List any extra directories to look for libraries here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRALIBDIRS = + + + +#---------------- External Memory Options ---------------- + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# used for variables (.data/.bss) and heap (malloc()). +#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# only used for heap (malloc()). +#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff + +EXTMEMOPTS = + + + +#---------------- Linker Options ---------------- +# -Wl,...: tell GCC to pass this to linker. +# -Map: create map file +# --cref: add cross reference to map file +LDFLAGS = -Wl,-Map=$(TARGET).map,--cref +LDFLAGS += -Wl,--relax +LDFLAGS += -Wl,--gc-sections +LDFLAGS += $(EXTMEMOPTS) +LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS)) +LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) +#LDFLAGS += -T linker_script.x + + + +#---------------- Programming Options (avrdude) ---------------- + +# Programming hardware: alf avr910 avrisp bascom bsd +# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500 +# +# Type: avrdude -c ? +# to get a full listing. +# +AVRDUDE_PROGRAMMER = jtagmkII + +# com1 = serial port. Use lpt1 to connect to parallel port. +AVRDUDE_PORT = usb + +AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex +#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep + + +# Uncomment the following if you want avrdude's erase cycle counter. +# Note that this counter needs to be initialized first using -Yn, +# see avrdude manual. +#AVRDUDE_ERASE_COUNTER = -y + +# Uncomment the following if you do /not/ wish a verification to be +# performed after programming the device. +#AVRDUDE_NO_VERIFY = -V + +# Increase verbosity level. Please use this when submitting bug +# reports about avrdude. See +# to submit bug reports. +#AVRDUDE_VERBOSE = -v -v + +AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) +AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) +AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) +AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) + + + +#---------------- Debugging Options ---------------- + +# For simulavr only - target MCU frequency. +DEBUG_MFREQ = $(F_CPU) + +# Set the DEBUG_UI to either gdb or insight. +# DEBUG_UI = gdb +DEBUG_UI = insight + +# Set the debugging back-end to either avarice, simulavr. +DEBUG_BACKEND = avarice +#DEBUG_BACKEND = simulavr + +# GDB Init Filename. +GDBINIT_FILE = __avr_gdbinit + +# When using avarice settings for the JTAG +JTAG_DEV = /dev/com1 + +# Debugging port used to communicate between GDB / avarice / simulavr. +DEBUG_PORT = 4242 + +# Debugging host used to communicate between GDB / avarice / simulavr, normally +# just set to localhost unless doing some sort of crazy debugging when +# avarice is running on a different computer. +DEBUG_HOST = localhost + + + +#============================================================================ + + +# Define programs and commands. +SHELL = sh +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +AR = avr-ar rcs +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +REMOVEDIR = rm -rf +COPY = cp +WINSHELL = cmd + +# Define Messages +# English +MSG_ERRORS_NONE = Errors: none +MSG_BEGIN = -------- begin -------- +MSG_END = -------- end -------- +MSG_SIZE_BEFORE = Size before: +MSG_SIZE_AFTER = Size after: +MSG_COFF = Converting to AVR COFF: +MSG_EXTENDED_COFF = Converting to AVR Extended COFF: +MSG_FLASH = Creating load file for Flash: +MSG_EEPROM = Creating load file for EEPROM: +MSG_EXTENDED_LISTING = Creating Extended Listing: +MSG_SYMBOL_TABLE = Creating Symbol Table: +MSG_LINKING = Linking: +MSG_COMPILING = Compiling C: +MSG_COMPILING_CPP = Compiling C++: +MSG_ASSEMBLING = Assembling: +MSG_CLEANING = Cleaning project: +MSG_CREATING_LIBRARY = Creating library: + + + + +# Define all object files. +OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) + +# Define all listing files. +LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst) + + +# Compiler flags to generate dependency files. +GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d + + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS) +ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + + + + +# Default target. +all: begin gccversion sizebefore build checkhooks checklibmode sizeafter end + +# Change the build target to build a HEX file or a library. +build: elf hex eep lss sym +#build: lib + + +elf: $(TARGET).elf +hex: $(TARGET).hex +eep: $(TARGET).eep +lss: $(TARGET).lss +sym: $(TARGET).sym +LIBNAME=lib$(TARGET).a +lib: $(LIBNAME) + + + +# Eye candy. +# AVR Studio 3.x does not check make's exit code but relies on +# the following magic strings to be generated by the compile job. +begin: + @echo + @echo $(MSG_BEGIN) + +end: + @echo $(MSG_END) + @echo + + +# Display size of file. +HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex +ELFSIZE = $(SIZE) $(MCU_FLAG) $(FORMAT_FLAG) $(TARGET).elf +MCU_FLAG = $(shell $(SIZE) --help | grep -- --mcu > /dev/null && echo --mcu=$(MCU) ) +FORMAT_FLAG = $(shell $(SIZE) --help | grep -- --format=.*avr > /dev/null && echo --format=avr ) + +sizebefore: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \ + 2>/dev/null; echo; fi + +sizeafter: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \ + 2>/dev/null; echo; fi + +checkhooks: build + @echo + @echo ------- Unhooked LUFA Events ------- + @$(shell) (grep -s '^Event.*LUFA/.*\\.o' $(TARGET).map | \ + cut -d' ' -f1 | cut -d'_' -f2- | grep ".*") || \ + echo "(None)" + @echo ----- End Unhooked LUFA Events ----- + +checklibmode: + @echo + @echo ----------- Library Mode ----------- + @$(shell) ($(CC) $(ALL_CFLAGS) -E -dM - < /dev/null \ + | grep 'USB_\(DEVICE\|HOST\)_ONLY' | cut -d' ' -f2 | grep ".*") \ + || echo "No specific mode (both device and host mode allowable)." + @echo ------------------------------------ + +# Display compiler version information. +gccversion : + @$(CC) --version + + + +# Program the device. +program: $(TARGET).hex $(TARGET).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + +flip: $(TARGET).hex + batchisp -hardware usb -device $(MCU) -operation erase f + batchisp -hardware usb -device $(MCU) -operation loadbuffer $(TARGET).hex program + batchisp -hardware usb -device $(MCU) -operation start reset 0 + +dfu: $(TARGET).hex + dfu-programmer $(MCU) erase + dfu-programmer $(MCU) flash --debug 1 $(TARGET).hex + dfu-programmer $(MCU) reset + +flip-ee: $(TARGET).hex $(TARGET).eep + copy $(TARGET).eep $(TARGET)eep.hex + batchisp -hardware usb -device $(MCU) -operation memory EEPROM erase + batchisp -hardware usb -device $(MCU) -operation memory EEPROM loadbuffer $(TARGET)eep.hex program + batchisp -hardware usb -device $(MCU) -operation start reset 0 + +dfu-ee: $(TARGET).hex $(TARGET).eep + dfu-programmer $(MCU) erase + dfu-programmer $(MCU) eeprom --debug 1 $(TARGET).eep + dfu-programmer $(MCU) reset + +# Generate avr-gdb config/init file which does the following: +# define the reset signal, load the target file, connect to target, and set +# a breakpoint at main(). +gdb-config: + @$(REMOVE) $(GDBINIT_FILE) + @echo define reset >> $(GDBINIT_FILE) + @echo SIGNAL SIGHUP >> $(GDBINIT_FILE) + @echo end >> $(GDBINIT_FILE) + @echo file $(TARGET).elf >> $(GDBINIT_FILE) + @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE) +ifeq ($(DEBUG_BACKEND),simulavr) + @echo load >> $(GDBINIT_FILE) +endif + @echo break main >> $(GDBINIT_FILE) + +debug: gdb-config $(TARGET).elf +ifeq ($(DEBUG_BACKEND), avarice) + @echo Starting AVaRICE - Press enter when "waiting to connect" message displays. + @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \ + $(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT) + @$(WINSHELL) /c pause + +else + @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \ + $(DEBUG_MFREQ) --port $(DEBUG_PORT) +endif + @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE) + + + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT = $(OBJCOPY) --debugging +COFFCONVERT += --change-section-address .data-0x800000 +COFFCONVERT += --change-section-address .bss-0x800000 +COFFCONVERT += --change-section-address .noinit-0x800000 +COFFCONVERT += --change-section-address .eeprom-0x810000 + + + +coff: $(TARGET).elf + @echo + @echo $(MSG_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-avr $< $(TARGET).cof + + +extcoff: $(TARGET).elf + @echo + @echo $(MSG_EXTENDED_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof + + + +# Create final output files (.hex, .eep) from ELF output file. +%.hex: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +%.eep: %.elf + @echo + @echo $(MSG_EEPROM) $@ + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0 + +# Create extended listing file from ELF output file. +%.lss: %.elf + @echo + @echo $(MSG_EXTENDED_LISTING) $@ + $(OBJDUMP) -h -z -S $< > $@ + +# Create a symbol table from ELF output file. +%.sym: %.elf + @echo + @echo $(MSG_SYMBOL_TABLE) $@ + $(NM) -n $< > $@ + + + +# Create library from object files. +.SECONDARY : $(TARGET).a +.PRECIOUS : $(OBJ) +%.a: $(OBJ) + @echo + @echo $(MSG_CREATING_LIBRARY) $@ + $(AR) $@ $(OBJ) + + +# Link: create ELF output file from object files. +.SECONDARY : $(TARGET).elf +.PRECIOUS : $(OBJ) +%.elf: $(OBJ) + @echo + @echo $(MSG_LINKING) $@ + $(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS) + + +# Compile: create object files from C source files. +$(OBJDIR)/%.o : %.c + @echo + @echo $(MSG_COMPILING) $< + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create object files from C++ source files. +$(OBJDIR)/%.o : %.cpp + @echo + @echo $(MSG_COMPILING_CPP) $< + $(CC) -c $(ALL_CPPFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +%.s : %.c + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C++ source files. +%.s : %.cpp + $(CC) -S $(ALL_CPPFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +$(OBJDIR)/%.o : %.S + @echo + @echo $(MSG_ASSEMBLING) $< + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + +# Create preprocessed source for use in sending a bug report. +%.i : %.c + $(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@ + + +# Target: clean project. +clean: begin clean_list clean_binary end + +clean_binary: + $(REMOVE) $(TARGET).hex + +clean_list: + @echo $(MSG_CLEANING) + $(REMOVE) $(TARGET).eep + $(REMOVE) $(TARGET).cof + $(REMOVE) $(TARGET).elf + $(REMOVE) $(TARGET).map + $(REMOVE) $(TARGET).sym + $(REMOVE) $(TARGET).lss + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o) + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst) + $(REMOVE) $(SRC:.c=.s) + $(REMOVE) $(SRC:.c=.d) + $(REMOVE) $(SRC:.c=.i) + $(REMOVEDIR) .dep + + +doxygen: + @echo Generating Project Documentation... + @doxygen Doxygen.conf + @echo Documentation Generation Complete. + +clean_doxygen: + rm -rf Documentation + +# Create object files directory +$(shell mkdir $(OBJDIR) 2>/dev/null) + + +# Include the dependency files. +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + + +# Listing of phony targets. +.PHONY : all checkhooks checklibmode begin \ +finish end sizebefore sizeafter gccversion \ +build elf hex eep lss sym coff extcoff \ +clean clean_list clean_binary program debug \ +gdb-config doxygen dfu flip diff --git a/Projects/makefile b/Projects/makefile new file mode 100644 index 0000000000..50851a3ef6 --- /dev/null +++ b/Projects/makefile @@ -0,0 +1,25 @@ +# +# LUFA Library +# Copyright (C) Dean Camera, 2009. +# +# dean [at] fourwalledcubicle [dot] com +# www.fourwalledcubicle.com +# + +# Makefile to build all the LUFA Projects. Call with "make all" to +# rebuild all projects. + +# Projects are pre-cleaned before each one is built, to ensure any +# custom LUFA library build options are reflected in the compiled +# code. + +all: + make -C Magstripe clean + make -C Magstripe all + + make -C AVRISP_Programmer clean + make -C AVRISP_Programmer all + +%: + make -C Magstripe $@ + make -C AVRISP_Programmer $@