From 00d0883507efdc17688abafa75e81bf62f83d777 Mon Sep 17 00:00:00 2001
From: Dean Camera <dean@fourwalledcubicle.com>
Date: Sat, 20 Jun 2009 11:43:26 +0000
Subject: [PATCH] Added USE_INTERNAL_SERIAL compile time option to
 automatically read out the internal unique serial number as the device's
 serial number descriptor on supported AVR models.

---
 .../Device/LowLevel/USBtoSerial/USBtoSerial.c |  2 +-
 .../GenericHIDHost/ConfigDescriptor.c         |  2 +-
 LUFA/Drivers/USB/Class/Device/CDC.c           |  6 ++--
 LUFA/Drivers/USB/Class/Device/CDC.h           | 24 +++++++++-----
 LUFA/Drivers/USB/Class/Host/CDC.c             | 28 +++++++++-------
 LUFA/Drivers/USB/Class/Host/CDC.h             | 24 ++++++++++++--
 LUFA/Drivers/USB/HighLevel/StdDescriptors.h   |  8 ++++-
 LUFA/Drivers/USB/LowLevel/DevChapter9.c       | 32 ++++++++++++++++++-
 LUFA/Drivers/USB/LowLevel/DevChapter9.h       | 12 +++++++
 LUFA/ManPages/ChangeLog.txt                   |  3 +-
 LUFA/ManPages/CompileTimeTokens.txt           |  8 +++++
 LUFA/ManPages/LUFAPoweredProjects.txt         | 31 ++++++++++++++----
 12 files changed, 142 insertions(+), 38 deletions(-)

diff --git a/Demos/Device/LowLevel/USBtoSerial/USBtoSerial.c b/Demos/Device/LowLevel/USBtoSerial/USBtoSerial.c
index 3ed406db4..444aa5e1c 100644
--- a/Demos/Device/LowLevel/USBtoSerial/USBtoSerial.c
+++ b/Demos/Device/LowLevel/USBtoSerial/USBtoSerial.c
@@ -265,7 +265,7 @@ void CDC_Task(void)
 			while (!(Endpoint_IsReadWriteAllowed()));
 			
 			/* Write the bytes from the buffer to the endpoint while space is available */
-			while (Tx_Buffer.Elements && (Endpoint_BytesInEndpoint() < CDC_TXRX_EPSIZE))
+			while (Tx_Buffer.Elements && Endpoint_IsReadWriteAllowed())
 			{
 				/* Write each byte retreived from the buffer to the endpoint */
 				Endpoint_Write_Byte(Buffer_GetElement(&Tx_Buffer));
diff --git a/Demos/Host/LowLevel/GenericHIDHost/ConfigDescriptor.c b/Demos/Host/LowLevel/GenericHIDHost/ConfigDescriptor.c
index 2a6e15256..26181c146 100644
--- a/Demos/Host/LowLevel/GenericHIDHost/ConfigDescriptor.c
+++ b/Demos/Host/LowLevel/GenericHIDHost/ConfigDescriptor.c
@@ -134,7 +134,7 @@ uint8_t DComp_NextHIDInterface(void* CurrentDescriptor)
 	/* Determine if the current descriptor is an interface descriptor */
 	if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
 	{
-		/* Check the HID descriptor class and protocol, break out if correct class/protocol interface found */
+		/* Check the HID descriptor class, break out if correct class/protocol interface found */
 		if (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Class == HID_CLASS)
 		{
 			/* Indicate that the descriptor being searched for has been found */
diff --git a/LUFA/Drivers/USB/Class/Device/CDC.c b/LUFA/Drivers/USB/Class/Device/CDC.c
index cc8161e0b..fc6ea93fb 100644
--- a/LUFA/Drivers/USB/Class/Device/CDC.c
+++ b/LUFA/Drivers/USB/Class/Device/CDC.c
@@ -74,7 +74,7 @@ void CDC_Device_ProcessControlPacket(USB_ClassInfo_CDC_Device_t* CDCInterfaceInf
 			{				
 				Endpoint_ClearSETUP();
 				
-				CDCInterfaceInfo->State.ControlLineState = USB_ControlRequest.wValue;
+				CDCInterfaceInfo->State.ControlLineStates.HostToDevice = USB_ControlRequest.wValue;
 				
 				EVENT_CDC_Device_ControLineStateChanged(CDCInterfaceInfo);
 
@@ -178,7 +178,7 @@ uint8_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo)
 	return DataByte;
 }
 
-void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo, uint16_t LineStateMask)
+void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo)
 {
 	if (!(USB_IsConnected))
 	  return;
@@ -195,7 +195,7 @@ void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* CDCInterf
 		};
 
 	Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK);
-	Endpoint_Write_Stream_LE(&LineStateMask, sizeof(LineStateMask), NO_STREAM_CALLBACK);
+	Endpoint_Write_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost, sizeof(uint8_t), NO_STREAM_CALLBACK);
 	Endpoint_ClearIN();
 }
 
diff --git a/LUFA/Drivers/USB/Class/Device/CDC.h b/LUFA/Drivers/USB/Class/Device/CDC.h
index 13fa8d3b7..bcf8ff7b9 100644
--- a/LUFA/Drivers/USB/Class/Device/CDC.h
+++ b/LUFA/Drivers/USB/Class/Device/CDC.h
@@ -71,7 +71,15 @@
 			/** Current State information structure for \ref USB_ClassInfo_CDC_Device_t CDC device interface structures. */
 			typedef struct
 			{
-				uint8_t  ControlLineState; /**< Current control line states, as set by the host */
+				struct
+				{
+					uint8_t HostToDevice; /**< Control line states from the host to device, as a set of CDC_CONTROL_LINE_OUT_*
+					                       *   masks.
+					                       */
+					uint8_t DeviceToHost; /**< Control line states from the device to host, as a set of CDC_CONTROL_LINE_IN_*
+					                       *   masks.
+					                       */
+				} ControlLineStates;
 
 				struct
 				{
@@ -143,8 +151,8 @@
 			/** CDC class driver event for a control line state change on a CDC interface. This event fires each time the host requests a
 			 *  control line state change (containing the virtual serial control line states, such as DTR) and may be hooked in the
 			 *  user program by declaring a handler function with the same name and parameters listed here. The new control line states
-			 *  are available in the ControlLineState value inside the CDC interface structure passed as a parameter, set as a mask of
-			 *  CDC_CONTROL_LINE_OUT_* masks.
+			 *  are available in the ControlLineStates.HostToDevice value inside the CDC interface structure passed as a parameter, set as
+			 *  a mask of CDC_CONTROL_LINE_OUT_* masks.
 			 *
 			 *  \param CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state.
 			 */		
@@ -185,14 +193,14 @@
 			 */
 			uint8_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo);
 			
-			/** Sends a Serial Control Line State Change notification to the host. This should be called when the virtual serial control
-			 *  lines (DCD, DSR, etc.) have changed states, or to give BREAK notfications to the host. Line states persist until they are
-			 *  cleared via a second notification.
+			/** Sends a Serial Control Line State Change notification to the host. This should be called when the virtual serial
+			 *  control lines (DCD, DSR, etc.) have changed states, or to give BREAK notfications to the host. Line states persist
+			 *  until they are cleared via a second notification. This should be called each time the CDC class driver's 
+			 *  ControlLineStates.DeviceToHost value is updated to push the new states to the USB host.
 			 *
 			 *  \param CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state.
-			 *  \param LineStateMask  Mask of CDC_CONTROL_LINE_IN_* masks giving the current control line states
 			 */
-			void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo, uint16_t LineStateMask);
+			void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo);
 
 	/* Private Interface - For use in library only: */
 	#if !defined(__DOXYGEN__)
diff --git a/LUFA/Drivers/USB/Class/Host/CDC.c b/LUFA/Drivers/USB/Class/Host/CDC.c
index aef5b3539..2d5ec0fb2 100644
--- a/LUFA/Drivers/USB/Class/Host/CDC.c
+++ b/LUFA/Drivers/USB/Class/Host/CDC.c
@@ -71,7 +71,6 @@ static uint8_t CDC_Host_ProcessConfigDescriptor(USB_ClassInfo_CDC_Host_t* CDCInt
 				if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, 
 				                              DComp_CDC_Host_NextCDCDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)
 				{
-					/* Descriptor not found, error out */
 					return CDC_ENUMERROR_NoCDCInterfaceFound;
 				}
 			}
@@ -149,10 +148,12 @@ static uint8_t DComp_CDC_Host_NextCDCControlInterface(void* CurrentDescriptor)
 {
 	if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
 	{
-		/* Check the CDC descriptor class, subclass and protocol, break out if correct control interface found */
-		if ((DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Class    == CDC_CONTROL_CLASS)    &&
-		    (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).SubClass == CDC_CONTROL_SUBCLASS) &&
-		    (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Protocol == CDC_CONTROL_PROTOCOL))
+		USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
+		                                                                USB_Descriptor_Interface_t);
+	
+		if ((CurrentInterface->Class    == CDC_CONTROL_CLASS)    &&
+		    (CurrentInterface->SubClass == CDC_CONTROL_SUBCLASS) &&
+			(CurrentInterface->Protocol == CDC_CONTROL_PROTOCOL))
 		{
 			return DESCRIPTOR_SEARCH_Found;
 		}
@@ -165,10 +166,12 @@ static uint8_t DComp_CDC_Host_NextCDCDataInterface(void* CurrentDescriptor)
 {
 	if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
 	{
-		/* Check the CDC descriptor class, subclass and protocol, break out if correct data interface found */
-		if ((DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Class    == CDC_DATA_CLASS)    &&
-		    (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).SubClass == CDC_DATA_SUBCLASS) &&
-		    (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Protocol == CDC_DATA_PROTOCOL))
+		USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
+		                                                                USB_Descriptor_Interface_t);
+	
+		if ((CurrentInterface->Class    == CDC_DATA_CLASS)    &&
+		    (CurrentInterface->SubClass == CDC_DATA_SUBCLASS) &&
+			(CurrentInterface->Protocol == CDC_DATA_PROTOCOL))
 		{
 			return DESCRIPTOR_SEARCH_Found;
 		}
@@ -181,8 +184,10 @@ static uint8_t DComp_CDC_Host_NextInterfaceCDCDataEndpoint(void* CurrentDescript
 {
 	if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
 	{
-		uint8_t EndpointType = (DESCRIPTOR_CAST(CurrentDescriptor,
-		                                        USB_Descriptor_Endpoint_t).Attributes & EP_TYPE_MASK);
+		USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
+		                                                              USB_Descriptor_Endpoint_t)
+	
+		uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK);
 	
 		if ((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT))
 		  return DESCRIPTOR_SEARCH_Found;
@@ -215,7 +220,6 @@ void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo)
 			USB_HostState = HOST_STATE_Configured;
 			break;
 		case HOST_STATE_Configured:
-				
 			USB_HostState = HOST_STATE_Ready;
 			break;
 	}
diff --git a/LUFA/Drivers/USB/Class/Host/CDC.h b/LUFA/Drivers/USB/Class/Host/CDC.h
index 859c41d57..4054cf117 100644
--- a/LUFA/Drivers/USB/Class/Host/CDC.h
+++ b/LUFA/Drivers/USB/Class/Host/CDC.h
@@ -68,8 +68,16 @@
 				uint16_t DataOUTPipeSize;  /**< Size in bytes of the CDC interface's OUT data pipe */
 				uint16_t NotificationPipeSize;  /**< Size in bytes of the CDC interface's IN notification endpoint, if used */
 
-				uint8_t  ControlLineState; /**< Current control line states */
-
+				struct
+				{
+					uint8_t HostToDevice; /**< Control line states from the host to device, as a set of CDC_CONTROL_LINE_OUT_*
+					                       *   masks.
+					                       */
+					uint8_t DeviceToHost; /**< Control line states from the device to host, as a set of CDC_CONTROL_LINE_IN_*
+					                       *   masks.
+					                       */
+				} ControlLineStates;
+				
 				struct
 				{
 					uint32_t BaudRateBPS; /**< Baud rate of the virtual serial port, in bits per second */
@@ -80,7 +88,7 @@
 										  *   CDCDevice_LineCodingParity_t enum
 										  */
 					uint8_t  DataBits; /**< Bits of data per character of the virtual serial port */
-				} LineEncoding;			
+				} LineEncoding;
 			} USB_ClassInfo_CDC_Host_State_t;
 
 			/** Class state structure. An instance of this structure should be made within the user application,
@@ -138,6 +146,16 @@
 				static uint8_t DComp_CDC_Host_NextCDCDataInterface(void* CurrentDescriptor);
 				static uint8_t DComp_CDC_Host_NextInterfaceCDCDataEndpoint(void* CurrentDescriptor);
 			#endif
+
+			void EVENT_CDC_Host_ControLineStateChanged(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo);
+			
+			uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo);
+			uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo);
+			
+			void CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, char* Data, uint16_t Length);
+			void CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, uint8_t Data);
+			uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo);
+			uint8_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo);
 	
 	#endif
 				
diff --git a/LUFA/Drivers/USB/HighLevel/StdDescriptors.h b/LUFA/Drivers/USB/HighLevel/StdDescriptors.h
index 7a0ca52b3..2ce75b2d9 100644
--- a/LUFA/Drivers/USB/HighLevel/StdDescriptors.h
+++ b/LUFA/Drivers/USB/HighLevel/StdDescriptors.h
@@ -244,7 +244,13 @@
 				                                          */
 				uint8_t                 SerialNumStrIndex; /**< String index for the product's globally unique hexadecimal
 				                                            *   serial number, in uppercase Unicode ASCII.
-				                                            *
+															*
+															*  \note On some AVR models, there is an embedded serial number
+															*        in the chip which can be used for the device serial number.
+				                                            *        To use this serial number, define USE_INTERNAL_SERIAL to a
+															*        unique string index number in the project makefile and set
+															*        this value to USE_INTERNAL_SERIAL.
+															*
 				                                            *  \see ManufacturerStrIndex structure entry.
 				                                            */
 
diff --git a/LUFA/Drivers/USB/LowLevel/DevChapter9.c b/LUFA/Drivers/USB/LowLevel/DevChapter9.c
index 829bd13e8..9acf30099 100644
--- a/LUFA/Drivers/USB/LowLevel/DevChapter9.c
+++ b/LUFA/Drivers/USB/LowLevel/DevChapter9.c
@@ -179,6 +179,36 @@ static void USB_Device_GetDescriptor(void)
 	void*    DescriptorPointer;
 	uint16_t DescriptorSize;
 	
+	#if defined(USE_INTERNAL_SERIAL)
+	if (USB_ControlRequest.wValue == ((DTYPE_String << 8) | USE_INTERNAL_SERIAL))
+	{
+		uint8_t SignatureDescriptor[2 + (sizeof(int16_t) * 20)];
+
+		SignatureDescriptor[0] = sizeof(SignatureDescriptor);
+		SignatureDescriptor[1] = DTYPE_String;
+		
+		uint16_t* SigUnicodeChars = (uint16_t*)&SignatureDescriptor[2];
+
+		for (uint8_t SerialByteNum = 0; SerialByteNum < 10; SerialByteNum++)
+		{
+			char ConvSigString[3];
+
+			itoa(boot_signature_byte_get(0x0E + SerialByteNum), ConvSigString, 16);
+			
+			SigUnicodeChars[0] = toupper(ConvSigString[0]);
+			SigUnicodeChars[1] = toupper(ConvSigString[1]);
+			
+			SigUnicodeChars += 2;
+		}
+		
+		Endpoint_ClearSETUP();
+		Endpoint_Write_Control_Stream_LE(SignatureDescriptor, sizeof(SignatureDescriptor));
+		Endpoint_ClearOUT();
+
+		return;
+	}
+	#endif
+	
 	if ((DescriptorSize = CALLBACK_USB_GetDescriptor(USB_ControlRequest.wValue, USB_ControlRequest.wIndex,
 	                                                 &DescriptorPointer)) == NO_DESCRIPTOR)
 	{
@@ -186,7 +216,7 @@ static void USB_Device_GetDescriptor(void)
 	}
 	
 	Endpoint_ClearSETUP();
-	
+
 	#if defined(USE_RAM_DESCRIPTORS)
 	Endpoint_Write_Control_Stream_LE(DescriptorPointer, DescriptorSize);
 	#else
diff --git a/LUFA/Drivers/USB/LowLevel/DevChapter9.h b/LUFA/Drivers/USB/LowLevel/DevChapter9.h
index 68cb2c448..65fa0418c 100644
--- a/LUFA/Drivers/USB/LowLevel/DevChapter9.h
+++ b/LUFA/Drivers/USB/LowLevel/DevChapter9.h
@@ -35,6 +35,9 @@
 		#include <avr/io.h>
 		#include <avr/pgmspace.h>
 		#include <avr/eeprom.h>
+		#include <avr/boot.h>
+		#include <stdlib.h>
+		#include <ctype.h>
 		
 		#include "../HighLevel/StdDescriptors.h"
 		#include "../HighLevel/Events.h"
@@ -42,6 +45,15 @@
 		#include "../HighLevel/USBTask.h"
 		#include "LowLevel.h"
 
+	/* Preprocessor Checks: */
+		#if defined(USE_INTERNAL_SERIAL) && !(defined(USB_SERIES_6_AVR) || defined(USB_SERIES_7_AVR))
+			#error USE_INTERNAL_SERIAL invalid, the selected AVR model does not contain unique serial bytes.
+		#endif
+		
+		#if defined(USE_INTERNAL_SERIAL) && (USE_INTERNAL_SERIAL <= 1)
+			#error USE_INTERNAL_SERIAL must be defined to the string descriptor index chosen for the serial number descriptor.
+		#endif
+
 	/* Enable C linkage for C++ Compilers: */
 		#if defined(__cplusplus)
 			extern "C" {
diff --git a/LUFA/ManPages/ChangeLog.txt b/LUFA/ManPages/ChangeLog.txt
index 464418140..f7ae4c664 100644
--- a/LUFA/ManPages/ChangeLog.txt
+++ b/LUFA/ManPages/ChangeLog.txt
@@ -8,7 +8,7 @@
   *
   *  \section Sec_ChangeLogXXXXXX Version XXXXXX
   *
-  *  - Removed psuedo-scheduler, dynamic memory block allocator from the library (no longer needed and not used respectively)
+  *  - Deprecated psuedo-scheduler and removed dynamic memory allocator from the library (first no longer needed and second unused)
   *  - Added new class drivers and matching demos to the library for rapid application development
   *  - Added incomplete device and host mode demos for later enhancement
   *  - Changed bootloaders to use FLASHEND rather than the existence of RAMPZ to determine if far FLASH pointers are needed
@@ -28,6 +28,7 @@
   *    cleared to prevent endpoint type corruption
   *  - Fix documentation mentioning Pipe_GetCurrentToken() function when real name is Pipe_GetPipeToken()
   *  - Extend USB_GetDeviceConfigDescriptor() routine to require the configuration number within the device to fetch
+  *  - Added new USE_INTERNAL_SERIAL compile time option
   *
   *  \section Sec_ChangeLog090605 Version 090605
   *
diff --git a/LUFA/ManPages/CompileTimeTokens.txt b/LUFA/ManPages/CompileTimeTokens.txt
index d8a7cf74a..e1f248d8f 100644
--- a/LUFA/ManPages/CompileTimeTokens.txt
+++ b/LUFA/ManPages/CompileTimeTokens.txt
@@ -80,6 +80,14 @@
  *  compatibility. If this token is defined, the structure element names are switched to the LUFA-specific but more descriptive
  *  names documented in the StdDescriptors.h source file.
  *
+ *  <b>USE_INTERNAL_SERIAL</b> - ( \ref Group_Descriptors ) \n
+ *  Some AVR models contain a unique 20-digit serial number which can be used as the device serial number, while in device mode. This
+ *  allows the host to uniquely identify the device regardless of if it is moved between USB ports on the same computer, allowing
+ *  allocated resources (such as drivers, COM Port number allocations) to be preserved. To make the library use this value for the
+ *  device's serial number, define this token in the project makefile, set it to a unique string descriptor index (i.e. one not used
+ *  elsewhere in the device for a string descriptor) and set the Device Descriptor's serial number descriptor index entry to the
+ *  USE_INTERNAL_SERIAL value.
+ *
  *  <b>FIXED_CONTROL_ENDPOINT_SIZE</b> - ( \ref Group_EndpointManagement ) \n
  *  By default, the library determines the size of the control endpoint (when in device mode) by reading the device descriptor.
  *  Normally this reduces the amount of configuration required for the library, allows the value to change dynamically (if
diff --git a/LUFA/ManPages/LUFAPoweredProjects.txt b/LUFA/ManPages/LUFAPoweredProjects.txt
index b93604e2f..1f9a317e6 100644
--- a/LUFA/ManPages/LUFAPoweredProjects.txt
+++ b/LUFA/ManPages/LUFAPoweredProjects.txt
@@ -13,20 +13,37 @@
  *  If you have a project that you would like to add to this list, please contact me via the details on the main page of this
  *  documentation.
  *
+ *  \section Sec_BoardsUsingLUFA AVR-USB Development Boards Using LUFA
+ *
+ *  The following is a list of known AVR USB development boards, which recommend using LUFA for the USB stack. Some of these
+ *  are open design, and all are available for purchase as completed development boards suitable for project development.
+ *
+ *  - AVROpendous, an open design/source set of AVR USB development boards: http://avropendous.org/
+ *  - Teensy and Teensy++, two other AVR USB development boards: http://www.pjrc.com/teensy/index.html
+ *  - USBFoo, an AT90USB162 based development board: http://shop.kernelconcepts.de/product_info.php?products_id=102
+ *  - USB10 AKA "The Ferret", a AT90USB162 development board: http://www.soc-machines.com
+ * 
+ *  \section Sec_LUFAProjects Projects Using LUFA (Hobbyist)
+ *
+ *  The following are hobbyist projects using LUFA. Most are open source, and show off interesting ways that the LUFA library
+ *  can be incorporated into many different applications.
  *
- *  - Benito #7, an AVR Programmer: http://www.dorkbotpdx.org/blog/feurig/benito_7_the_next_big_thing
  *  - Stripe Snoop, a Magnetic Card reader: http://www.ossguy.com/ss_usb/
- *  - USB10 AKA "The Ferret", a USB162 development board: http://www.soc-machines.com
+ *  - Benito #7, an AVR Programmer: http://www.dorkbotpdx.org/blog/feurig/benito_7_the_next_big_thing
  *  - Bicycle POV: http://www.code.google.com/p/bicycleledpov/
- *  - Digital Survey Instruments Magnetometer and Pointer: http://www.digitalsurveyinstruments.com/
- *  - ARPS Locator: http://la3t.hamradio.no/lab//?id=tracker_en
- *  - Lightweight CC110x USB dongle for 868MHz Protocols: http://busware.de/tiki-index.php?page=CUL
- *  - AVROpendous, an open design/source AT90USB162 development board: http://avropendous.org/
  *  - USB Interface for Playstation Portable Devices: http://forums.ps2dev.org/viewtopic.php?t=11001
  *  - USB to Serial Bridge, via SPI and I2C: http://www.tty1.net/userial/
- *  - Teensy, another tiny AT90USB162 development board: http://www.pjrc.com/teensy/index.html
  *  - SEGA Megadrive/Genesis Development Cartridge: http://www.spritesmind.net/_GenDev/forum/viewtopic.php?t=464
  *  - CAMTRIG, a remote Camera Trigger device: http://code.astraw.com/projects/motmot/camtrig
  *  - Opendous-JTAG, an open source JTAG device: http://code.google.com/p/opendous-jtag/
  *  - Openkubus, an open source hardware-based authentication dongle: http://code.google.com/p/openkubus/
+ * 
+ *  \section Sec_LUFACommercialProjects Projects Using LUFA (Commercial)
+ *
+ *  The following is a list of known commercial products using LUFA. Some of these are open source, although many are "black-box"
+ *  solutions with no source code given.
+ *
+ *  - ARPS Locator: http://la3t.hamradio.no/lab//?id=tracker_en
+ *  - Digital Survey Instruments Magnetometer and Pointer: http://www.digitalsurveyinstruments.com/
+ *  - Lightweight CC110x USB dongle for 868MHz Protocols: http://busware.de/tiki-index.php?page=CUL
  */
\ No newline at end of file
-- 
GitLab