forked from mfulz_github/qmk_firmware
		
	Commit of new class abstraction APIs for all device demos other than the MIDI demo - not documented yet.
Removed scheduler and memory allocation libraries. Added new EVENT_USB_StartOfFrame event in the library to indicate the start of each USB frame (when generated). Removed Tx interrupt from the USBtoSerial demo; now sends characters via polling to ensure more time for the Rx interrupt.
This commit is contained in:
		
							parent
							
								
									2440ca268a
								
							
						
					
					
						commit
						d1e5266036
					
				| @ -124,7 +124,6 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
|  | |||||||
| @ -124,7 +124,6 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 |  | ||||||
| 
 | 
 | ||||||
|   |   | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
|  | |||||||
| @ -124,7 +124,6 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
|  | |||||||
| @ -28,26 +28,32 @@ | |||||||
|   this software. |   this software. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| /** \file
 |  | ||||||
|  * |  | ||||||
|  *  Main source file for the Audio Input demo. This file contains the main tasks of the demo and |  | ||||||
|  *  is responsible for the initial application hardware configuration. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include "AudioInput.h" | #include "AudioInput.h" | ||||||
| 
 | 
 | ||||||
| /* Scheduler Task List */ | USB_ClassInfo_Audio_t Microphone_Audio_Interface = | ||||||
| TASK_LIST | 	{ | ||||||
| { | 		.InterfaceNumber      = 0, | ||||||
| 	{ .Task = USB_USBTask          , .TaskStatus = TASK_STOP }, |  | ||||||
| 	{ .Task = USB_Audio_Task       , .TaskStatus = TASK_STOP }, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
|  | 		.DataINEndpointNumber = AUDIO_STREAM_EPNUM, | ||||||
|  | 		.DataINEndpointSize   = AUDIO_STREAM_EPSIZE, | ||||||
|  | 	}; | ||||||
| 		 | 		 | ||||||
| /** 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) | int main(void) | ||||||
|  | { | ||||||
|  | 	SetupHardware(); | ||||||
|  | 
 | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | 	 | ||||||
|  | 	for (;;) | ||||||
|  | 	{ | ||||||
|  | 		if (Microphone_Audio_Interface.InterfaceEnabled) | ||||||
|  | 		  ProcessNextSample(); | ||||||
|  | 
 | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupHardware(void) | ||||||
| { | { | ||||||
| 	/* Disable watchdog if enabled by bootloader/fuses */ | 	/* Disable watchdog if enabled by bootloader/fuses */ | ||||||
| 	MCUSR &= ~(1 << WDRF); | 	MCUSR &= ~(1 << WDRF); | ||||||
| @ -58,145 +64,18 @@ int main(void) | |||||||
| 	 | 	 | ||||||
| 	/* Hardware Initialization */ | 	/* Hardware Initialization */ | ||||||
| 	LEDs_Init(); | 	LEDs_Init(); | ||||||
|  | 	USB_Init(); | ||||||
| 	ADC_Init(ADC_FREE_RUNNING | ADC_PRESCALE_32); | 	ADC_Init(ADC_FREE_RUNNING | ADC_PRESCALE_32); | ||||||
| 	ADC_SetupChannel(MIC_IN_ADC_CHANNEL); | 	ADC_SetupChannel(MIC_IN_ADC_CHANNEL); | ||||||
| 	 | 	 | ||||||
| 	/* Start the ADC conversion in free running mode */ | 	/* Start the ADC conversion in free running mode */ | ||||||
| 	ADC_StartReading(ADC_REFERENCE_AVCC | ADC_RIGHT_ADJUSTED | MIC_IN_ADC_CHANNEL); | 	ADC_StartReading(ADC_REFERENCE_AVCC | ADC_RIGHT_ADJUSTED | MIC_IN_ADC_CHANNEL); | ||||||
| 	 |  | ||||||
| 	/* 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
 | void ProcessNextSample(void) | ||||||
|  *  configures the sample update and PWM timers. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Connect(void) |  | ||||||
| { | { | ||||||
| 	/* Start USB management task */ | 	if ((TIFR0 & (1 << OCF0A)) && USB_Audio_IsReadyForNextSample(&Microphone_Audio_Interface)) | ||||||
| 	Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); |  | ||||||
| 
 |  | ||||||
| 	/* Indicate USB enumerating */ |  | ||||||
| 	UpdateStatus(Status_USBEnumerating); |  | ||||||
| 
 |  | ||||||
| 	/* Sample reload timer initialization */ |  | ||||||
| 	OCR0A   = (F_CPU / AUDIO_SAMPLE_FREQUENCY) - 1; |  | ||||||
| 	TCCR0A  = (1 << WGM01);  // CTC mode
 |  | ||||||
| 	TCCR0B  = (1 << CS00);   // Fcpu speed
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
 |  | ||||||
|  *  the status LEDs, disables the sample update and PWM output timers and stops the USB and Audio management tasks. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Disconnect(void) |  | ||||||
| { |  | ||||||
| 	/* Stop the sample reload timer */ |  | ||||||
| 	TCCR0B = 0; |  | ||||||
| 
 |  | ||||||
| 	/* Stop running audio and USB management tasks */ |  | ||||||
| 	Scheduler_SetTaskMode(USB_Audio_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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_ConfigurationChanged(void) |  | ||||||
| { |  | ||||||
| 	/* Setup audio stream endpoint */ |  | ||||||
| 	Endpoint_ConfigureEndpoint(AUDIO_STREAM_EPNUM, EP_TYPE_ISOCHRONOUS, |  | ||||||
| 		                       ENDPOINT_DIR_IN, AUDIO_STREAM_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_DOUBLE); |  | ||||||
| 
 |  | ||||||
| 	/* Indicate USB connected and ready */ |  | ||||||
| 	UpdateStatus(Status_USBReady); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** 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 Audio class-specific |  | ||||||
|  *  requests) so that they can be handled appropriately for the application. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_UnhandledControlPacket(void) |  | ||||||
| { |  | ||||||
| 	/* Process General and Audio specific control requests */ |  | ||||||
| 	switch (USB_ControlRequest.bRequest) |  | ||||||
| 	{ | 	{ | ||||||
| 		case REQ_SetInterface: |  | ||||||
| 			/* Set Interface is not handled by the library, as its function is application-specific */ |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Check if the host is enabling the audio interface (setting AlternateSetting to 1) */ |  | ||||||
| 				if (USB_ControlRequest.wValue) |  | ||||||
| 				{ |  | ||||||
| 					/* Start audio task */ |  | ||||||
| 					Scheduler_SetTaskMode(USB_Audio_Task, TASK_RUN); |  | ||||||
| 				} |  | ||||||
| 				else |  | ||||||
| 				{ |  | ||||||
| 					/* Stop audio task */ |  | ||||||
| 					Scheduler_SetTaskMode(USB_Audio_Task, TASK_STOP);				 |  | ||||||
| 				} |  | ||||||
| 				 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** 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 AudioInput_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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Task to manage the Audio interface, reading in ADC samples from the microphone, and them to the host. */ |  | ||||||
| TASK(USB_Audio_Task) |  | ||||||
| { |  | ||||||
| 	/* Select the audio stream endpoint */ |  | ||||||
| 	Endpoint_SelectEndpoint(AUDIO_STREAM_EPNUM); |  | ||||||
| 	 |  | ||||||
| 	/* Check if the current endpoint can be written to and that the next sample should be stored */ |  | ||||||
| 	if (Endpoint_IsINReady() && (TIFR0 & (1 << OCF0A))) |  | ||||||
| 	{ |  | ||||||
| 		/* Clear the sample reload timer */ |  | ||||||
| 		TIFR0 |= (1 << OCF0A); | 		TIFR0 |= (1 << OCF0A); | ||||||
| 
 | 
 | ||||||
| 		/* Audio sample is ADC value scaled to fit the entire range */ | 		/* Audio sample is ADC value scaled to fit the entire range */ | ||||||
| @ -207,14 +86,37 @@ TASK(USB_Audio_Task) | |||||||
| 		AudioSample -= (SAMPLE_MAX_RANGE / 2)); | 		AudioSample -= (SAMPLE_MAX_RANGE / 2)); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 		/* Write the sample to the buffer */ | 		USB_Audio_WriteSample16(AudioSample); | ||||||
| 		Endpoint_Write_Word_LE(AudioSample); |  | ||||||
| 
 |  | ||||||
| 		/* Check to see if the bank is now full */ |  | ||||||
| 		if (!(Endpoint_IsReadWriteAllowed())) |  | ||||||
| 		{ |  | ||||||
| 			/* Send the full packet to the host */ |  | ||||||
| 			Endpoint_ClearIN(); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void EVENT_USB_Connect(void) | ||||||
|  | { | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||||
|  | 
 | ||||||
|  | 	/* Sample reload timer initialization */ | ||||||
|  | 	OCR0A   = (F_CPU / AUDIO_SAMPLE_FREQUENCY) - 1; | ||||||
|  | 	TCCR0A  = (1 << WGM01);  // CTC mode
 | ||||||
|  | 	TCCR0B  = (1 << CS00);   // Fcpu speed
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EVENT_USB_Disconnect(void) | ||||||
|  | { | ||||||
|  | 	/* Stop the sample reload timer */ | ||||||
|  | 	TCCR0B = 0; | ||||||
|  | 
 | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EVENT_USB_ConfigurationChanged(void) | ||||||
|  | { | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
|  | 	 | ||||||
|  | 	if (!(USB_Audio_ConfigureEndpoints(&Microphone_Audio_Interface))) | ||||||
|  | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EVENT_USB_UnhandledControlPacket(void) | ||||||
|  | { | ||||||
|  | 	USB_Audio_ProcessControlPacket(&Microphone_Audio_Interface); | ||||||
|  | } | ||||||
|  | |||||||
| @ -43,11 +43,12 @@ | |||||||
| 
 | 
 | ||||||
| 		#include "Descriptors.h" | 		#include "Descriptors.h" | ||||||
| 				 | 				 | ||||||
| 		#include <LUFA/Version.h>                      // Library Version Information | 		#include <LUFA/Version.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>              // USB Functionality | 		#include <LUFA/Drivers/Board/LEDs.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>           // LEDs driver | 		#include <LUFA/Drivers/Board/Joystick.h> | ||||||
| 		#include <LUFA/Drivers/Peripheral/ADC.h>       // ADC driver | 		#include <LUFA/Drivers/Peripheral/ADC.h> | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>          // Simple scheduler for task management | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
|  | 		#include <LUFA/Drivers/USB/Class/Device/Audio.h> | ||||||
| 		 | 		 | ||||||
| 	/* Macros: */ | 	/* Macros: */ | ||||||
| 		/** ADC channel number for the microphone input. */ | 		/** ADC channel number for the microphone input. */ | ||||||
| @ -59,24 +60,19 @@ | |||||||
| 		/** Maximum ADC range for the microphone input. */ | 		/** Maximum ADC range for the microphone input. */ | ||||||
| 		#define ADC_MAX_RANGE                    0x3FF | 		#define ADC_MAX_RANGE                    0x3FF | ||||||
| 
 | 
 | ||||||
| 	/* Enums: */ | 	/* Macros: */ | ||||||
| 		/** Enum for the possible status codes for passing to the UpdateStatus() function. */ | 		#define LEDMASK_USB_NOTREADY      LEDS_LED1 | ||||||
| 		enum AudioInput_StatusCodes_t | 		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3) | ||||||
| 		{ | 		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4) | ||||||
| 			Status_USBNotReady    = 0, /**< USB is not ready (disconnected from a USB host) */ | 		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3) | ||||||
| 			Status_USBEnumerating = 1, /**< USB interface is enumerating */ |  | ||||||
| 			Status_USBReady       = 2, /**< USB interface is connected and ready */ |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 	/* Task Definitions: */ |  | ||||||
| 		TASK(USB_Audio_Task); |  | ||||||
| 		 | 		 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void SetupHardware(void); | ||||||
|  | 		void ProcessNextSample(void); | ||||||
|  | 		 | ||||||
| 		void EVENT_USB_Connect(void); | 		void EVENT_USB_Connect(void); | ||||||
| 		void EVENT_USB_Disconnect(void); | 		void EVENT_USB_Disconnect(void); | ||||||
| 		void EVENT_USB_ConfigurationChanged(void); | 		void EVENT_USB_ConfigurationChanged(void); | ||||||
| 		void EVENT_USB_UnhandledControlPacket(void); | 		void EVENT_USB_UnhandledControlPacket(void); | ||||||
| 
 | 
 | ||||||
| 		void UpdateStatus(uint8_t CurrentStatus); |  | ||||||
| 		 |  | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -125,7 +125,6 @@ LUFA_PATH = ../../.. | |||||||
| # List C source files here. (C dependencies are automatically generated.)
 | # List C source files here. (C dependencies are automatically generated.)
 | ||||||
| SRC = $(TARGET).c                                                 \
 | SRC = $(TARGET).c                                                 \
 | ||||||
| 	  Descriptors.c                                               \
 | 	  Descriptors.c                                               \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | ||||||
| @ -136,7 +135,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/Audio.c          \
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
|  | |||||||
| @ -28,26 +28,32 @@ | |||||||
|   this software. |   this software. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| /** \file
 |  | ||||||
|  * |  | ||||||
|  *  Main source file for the Audio Output demo. This file contains the main tasks of the demo and |  | ||||||
|  *  is responsible for the initial application hardware configuration. |  | ||||||
|  */ |  | ||||||
|   |  | ||||||
| #include "AudioOutput.h" | #include "AudioOutput.h" | ||||||
| 
 | 
 | ||||||
| /* Scheduler Task List */ | USB_ClassInfo_Audio_t Speaker_Audio_Interface = | ||||||
| TASK_LIST | 	{ | ||||||
| { | 		.InterfaceNumber       = 0, | ||||||
| 	{ .Task = USB_USBTask          , .TaskStatus = TASK_STOP }, |  | ||||||
| 	{ .Task = USB_Audio_Task       , .TaskStatus = TASK_STOP }, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
|  | 		.DataOUTEndpointNumber = AUDIO_STREAM_EPNUM, | ||||||
|  | 		.DataOUTEndpointSize   = AUDIO_STREAM_EPSIZE, | ||||||
|  | 	}; | ||||||
| 
 | 
 | ||||||
| /** 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) | int main(void) | ||||||
|  | { | ||||||
|  | 	SetupHardware(); | ||||||
|  | 
 | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | 	 | ||||||
|  | 	for (;;) | ||||||
|  | 	{ | ||||||
|  | 		if (Speaker_Audio_Interface.InterfaceEnabled) | ||||||
|  | 		  ProcessNextSample(); | ||||||
|  | 
 | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupHardware(void) | ||||||
| { | { | ||||||
| 	/* Disable watchdog if enabled by bootloader/fuses */ | 	/* Disable watchdog if enabled by bootloader/fuses */ | ||||||
| 	MCUSR &= ~(1 << WDRF); | 	MCUSR &= ~(1 << WDRF); | ||||||
| @ -58,186 +64,19 @@ int main(void) | |||||||
| 
 | 
 | ||||||
| 	/* Hardware Initialization */ | 	/* Hardware Initialization */ | ||||||
| 	LEDs_Init(); | 	LEDs_Init(); | ||||||
| 	 |  | ||||||
| 	/* Indicate USB not ready */ |  | ||||||
| 	UpdateStatus(Status_USBNotReady); |  | ||||||
| 	 |  | ||||||
| 	/* Initialize Scheduler so that it can be used */ |  | ||||||
| 	Scheduler_Init(); |  | ||||||
| 
 |  | ||||||
| 	/* Initialize USB Subsystem */ |  | ||||||
| 	USB_Init(); | 	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
 | void ProcessNextSample(void) | ||||||
|  *  configures the sample update and PWM timers. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Connect(void) |  | ||||||
| { | { | ||||||
| 	/* Start USB management task */ | 	if ((TIFR0 & (1 << OCF0A)) && USB_Audio_IsSampleReceived(&Speaker_Audio_Interface)) | ||||||
| 	Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); |  | ||||||
| 
 |  | ||||||
| 	/* Indicate USB enumerating */ |  | ||||||
| 	UpdateStatus(Status_USBEnumerating); |  | ||||||
| 	 |  | ||||||
| 	/* Sample reload timer initialization */ |  | ||||||
| 	OCR0A   = (F_CPU / AUDIO_SAMPLE_FREQUENCY) - 1; |  | ||||||
| 	TCCR0A  = (1 << WGM01);  // CTC mode
 |  | ||||||
| 	TCCR0B  = (1 << CS00);   // Fcpu speed
 |  | ||||||
| 			 |  | ||||||
| #if defined(AUDIO_OUT_MONO) |  | ||||||
| 	/* Set speaker as output */ |  | ||||||
| 	DDRC   |= (1 << 6); |  | ||||||
| #elif defined(AUDIO_OUT_STEREO) |  | ||||||
| 	/* Set speakers as outputs */ |  | ||||||
| 	DDRC   |= ((1 << 6) | (1 << 5)); |  | ||||||
| #elif defined(AUDIO_OUT_PORTC) |  | ||||||
| 	/* Set PORTC as outputs */ |  | ||||||
| 	DDRC   |= 0xFF; |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if (defined(AUDIO_OUT_MONO) || defined(AUDIO_OUT_STEREO)) |  | ||||||
| 	/* PWM speaker timer initialization */ |  | ||||||
| 	TCCRxA  = ((1 << WGMx0) | (1 << COMxA1) | (1 << COMxA0) |  | ||||||
| 							| (1 << COMxB1) | (1 << COMxB0)); // Set on match, clear on TOP
 |  | ||||||
| 	TCCRxB  = ((1 << WGMx2) | (1 << CSx0));  // Fast 8-Bit PWM, Fcpu speed
 |  | ||||||
| #endif	 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
 |  | ||||||
|  *  the status LEDs, disables the sample update and PWM output timers and stops the USB and Audio management tasks. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Disconnect(void) |  | ||||||
| { |  | ||||||
| 	/* Stop the timers */ |  | ||||||
| 	TCCR0B = 0; |  | ||||||
| #if (defined(AUDIO_OUT_MONO) || defined(AUDIO_OUT_STEREO)) |  | ||||||
| 	TCCRxB = 0; |  | ||||||
| #endif		 |  | ||||||
| 
 |  | ||||||
| #if defined(AUDIO_OUT_MONO) |  | ||||||
| 	/* Set speaker as input to reduce current draw */ |  | ||||||
| 	DDRC   &= ~(1 << 6); |  | ||||||
| #elif defined(AUDIO_OUT_STEREO) |  | ||||||
| 	/* Set speakers as inputs to reduce current draw */ |  | ||||||
| 	DDRC   &= ~((1 << 6) | (1 << 5)); |  | ||||||
| #elif defined(AUDIO_OUT_PORTC) |  | ||||||
| 	/* Set PORTC low */ |  | ||||||
| 	PORTC  = 0x00; |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| 	/* Stop running audio and USB management tasks */ |  | ||||||
| 	Scheduler_SetTaskMode(USB_Audio_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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_ConfigurationChanged(void) |  | ||||||
| { |  | ||||||
| 	/* Setup audio stream endpoint */ |  | ||||||
| 	Endpoint_ConfigureEndpoint(AUDIO_STREAM_EPNUM, EP_TYPE_ISOCHRONOUS, |  | ||||||
| 		                       ENDPOINT_DIR_OUT, AUDIO_STREAM_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_DOUBLE); |  | ||||||
| 
 |  | ||||||
| 	/* Indicate USB connected and ready */ |  | ||||||
| 	UpdateStatus(Status_USBReady); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** 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 Audio class-specific |  | ||||||
|  *  requests) so that they can be handled appropriately for the application. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_UnhandledControlPacket(void) |  | ||||||
| { |  | ||||||
| 	/* Process General and Audio specific control requests */ |  | ||||||
| 	switch (USB_ControlRequest.bRequest) |  | ||||||
| 	{ |  | ||||||
| 		case REQ_SetInterface: |  | ||||||
| 			/* Set Interface is not handled by the library, as its function is application-specific */ |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Check if the host is enabling the audio interface (setting AlternateSetting to 1) */ |  | ||||||
| 				if (USB_ControlRequest.wValue) |  | ||||||
| 				{ |  | ||||||
| 					/* Start audio task */ |  | ||||||
| 					Scheduler_SetTaskMode(USB_Audio_Task, TASK_RUN); |  | ||||||
| 				} |  | ||||||
| 				else |  | ||||||
| 				{ |  | ||||||
| 					/* Stop audio task */ |  | ||||||
| 					Scheduler_SetTaskMode(USB_Audio_Task, TASK_STOP);				 |  | ||||||
| 				} |  | ||||||
| 				 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** 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 AudioOutput_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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Task to manage the Audio interface, reading in audio samples from the host, and outputting them to the speakers/LEDs as
 |  | ||||||
|  *  desired. |  | ||||||
|  */ |  | ||||||
| TASK(USB_Audio_Task) |  | ||||||
| { |  | ||||||
| 	/* Select the audio stream endpoint */ |  | ||||||
| 	Endpoint_SelectEndpoint(AUDIO_STREAM_EPNUM); |  | ||||||
| 	 |  | ||||||
| 	/* Check if the current endpoint can be read from (contains a packet) and that the next sample should be read */ |  | ||||||
| 	if (Endpoint_IsOUTReceived() && (TIFR0 & (1 << OCF0A))) |  | ||||||
| 	{ | 	{ | ||||||
| 		/* Clear the sample reload timer */ | 		/* Clear the sample reload timer */ | ||||||
| 		TIFR0 |= (1 << OCF0A); | 		TIFR0 |= (1 << OCF0A); | ||||||
| 
 | 
 | ||||||
| 		/* Retrieve the signed 16-bit left and right audio samples */ | 		/* Retrieve the signed 16-bit left and right audio samples */ | ||||||
| 		int16_t LeftSample_16Bit  = (int16_t)Endpoint_Read_Word_LE(); | 		int16_t LeftSample_16Bit  = (int16_t)USB_Audio_ReadSample16(); | ||||||
| 		int16_t RightSample_16Bit = (int16_t)Endpoint_Read_Word_LE(); | 		int16_t RightSample_16Bit = (int16_t)USB_Audio_ReadSample16(); | ||||||
| 
 |  | ||||||
| 		/* Check to see if the bank is now empty */ |  | ||||||
| 		if (!(Endpoint_IsReadWriteAllowed())) |  | ||||||
| 		{ |  | ||||||
| 			/* Acknowledge the packet, clear the bank ready for the next packet */ |  | ||||||
| 			Endpoint_ClearOUT(); |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		/* Massage signed 16-bit left and right audio samples into signed 8-bit */ | 		/* Massage signed 16-bit left and right audio samples into signed 8-bit */ | ||||||
| 		int8_t  LeftSample_8Bit   = (LeftSample_16Bit  >> 8); | 		int8_t  LeftSample_8Bit   = (LeftSample_16Bit  >> 8); | ||||||
| @ -289,3 +128,69 @@ TASK(USB_Audio_Task) | |||||||
| #endif | #endif | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void EVENT_USB_Connect(void) | ||||||
|  | { | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||||
|  | 	 | ||||||
|  | 	/* Sample reload timer initialization */ | ||||||
|  | 	OCR0A   = (F_CPU / AUDIO_SAMPLE_FREQUENCY) - 1; | ||||||
|  | 	TCCR0A  = (1 << WGM01);  // CTC mode
 | ||||||
|  | 	TCCR0B  = (1 << CS00);   // Fcpu speed
 | ||||||
|  | 
 | ||||||
|  | #if defined(AUDIO_OUT_MONO) | ||||||
|  | 	/* Set speaker as output */ | ||||||
|  | 	DDRC   |= (1 << 6); | ||||||
|  | #elif defined(AUDIO_OUT_STEREO) | ||||||
|  | 	/* Set speakers as outputs */ | ||||||
|  | 	DDRC   |= ((1 << 6) | (1 << 5)); | ||||||
|  | #elif defined(AUDIO_OUT_PORTC) | ||||||
|  | 	/* Set PORTC as outputs */ | ||||||
|  | 	DDRC   |= 0xFF; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if (defined(AUDIO_OUT_MONO) || defined(AUDIO_OUT_STEREO)) | ||||||
|  | 	/* PWM speaker timer initialization */ | ||||||
|  | 	TCCRxA  = ((1 << WGMx0) | (1 << COMxA1) | (1 << COMxA0) | ||||||
|  | 							| (1 << COMxB1) | (1 << COMxB0)); // Set on match, clear on TOP
 | ||||||
|  | 	TCCRxB  = ((1 << WGMx2) | (1 << CSx0));  // Fast 8-Bit PWM, Fcpu speed
 | ||||||
|  | #endif	 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
 | ||||||
|  |  *  the status LEDs, disables the sample update and PWM output timers and stops the USB and Audio management tasks. | ||||||
|  |  */ | ||||||
|  | void EVENT_USB_Disconnect(void) | ||||||
|  | { | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | 
 | ||||||
|  | 	/* Stop the timers */ | ||||||
|  | 	TCCR0B = 0; | ||||||
|  | #if (defined(AUDIO_OUT_MONO) || defined(AUDIO_OUT_STEREO)) | ||||||
|  | 	TCCRxB = 0; | ||||||
|  | #endif		 | ||||||
|  | 
 | ||||||
|  | #if defined(AUDIO_OUT_MONO) | ||||||
|  | 	/* Set speaker as input to reduce current draw */ | ||||||
|  | 	DDRC   &= ~(1 << 6); | ||||||
|  | #elif defined(AUDIO_OUT_STEREO) | ||||||
|  | 	/* Set speakers as inputs to reduce current draw */ | ||||||
|  | 	DDRC   &= ~((1 << 6) | (1 << 5)); | ||||||
|  | #elif defined(AUDIO_OUT_PORTC) | ||||||
|  | 	/* Set PORTC low */ | ||||||
|  | 	PORTC  = 0x00; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EVENT_USB_ConfigurationChanged(void) | ||||||
|  | { | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
|  | 	 | ||||||
|  | 	if (!(USB_Audio_ConfigureEndpoints(&Speaker_Audio_Interface))) | ||||||
|  | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EVENT_USB_UnhandledControlPacket(void) | ||||||
|  | { | ||||||
|  | 	USB_Audio_ProcessControlPacket(&Speaker_Audio_Interface); | ||||||
|  | } | ||||||
|  | |||||||
| @ -43,10 +43,12 @@ | |||||||
| 
 | 
 | ||||||
| 		#include "Descriptors.h" | 		#include "Descriptors.h" | ||||||
| 		 | 		 | ||||||
| 		#include <LUFA/Version.h>                    // Library Version Information | 		#include <LUFA/Version.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>            // USB Functionality | 		#include <LUFA/Drivers/Board/LEDs.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>         // LEDs driver | 		#include <LUFA/Drivers/Board/Joystick.h> | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>        // Simple scheduler for task management | 		#include <LUFA/Drivers/Peripheral/ADC.h> | ||||||
|  | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
|  | 		#include <LUFA/Drivers/USB/Class/Device/Audio.h> | ||||||
| 	 | 	 | ||||||
| 	/* Macros: */ | 	/* Macros: */ | ||||||
| 		#if defined(USB_FULL_CONTROLLER) || defined(USB_MODIFIED_FULL_CONTROLLER) | 		#if defined(USB_FULL_CONTROLLER) || defined(USB_MODIFIED_FULL_CONTROLLER) | ||||||
| @ -96,24 +98,19 @@ | |||||||
| 			#define CSx0            CS10 | 			#define CSx0            CS10 | ||||||
| 		#endif | 		#endif | ||||||
| 		 | 		 | ||||||
| 	/* Enums: */ | 	/* Macros: */ | ||||||
| 		/** Enum for the possible status codes for passing to the UpdateStatus() function. */ | 		#define LEDMASK_USB_NOTREADY      LEDS_LED1 | ||||||
| 		enum AudioOutput_StatusCodes_t | 		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3) | ||||||
| 		{ | 		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4) | ||||||
| 			Status_USBNotReady    = 0, /**< USB is not ready (disconnected from a USB host) */ | 		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3) | ||||||
| 			Status_USBEnumerating = 1, /**< USB interface is enumerating */ |  | ||||||
| 			Status_USBReady       = 2, /**< USB interface is connected and ready */ |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 	/* Task Definitions: */ |  | ||||||
| 		TASK(USB_Audio_Task); |  | ||||||
| 		 | 		 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void SetupHardware(void); | ||||||
|  | 		void ProcessNextSample(void); | ||||||
|  | 		 | ||||||
| 		void EVENT_USB_Connect(void); | 		void EVENT_USB_Connect(void); | ||||||
| 		void EVENT_USB_Disconnect(void); | 		void EVENT_USB_Disconnect(void); | ||||||
| 		void EVENT_USB_ConfigurationChanged(void); | 		void EVENT_USB_ConfigurationChanged(void); | ||||||
| 		void EVENT_USB_UnhandledControlPacket(void); | 		void EVENT_USB_UnhandledControlPacket(void); | ||||||
| 
 | 
 | ||||||
| 		void UpdateStatus(uint8_t CurrentStatus); |  | ||||||
| 
 |  | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -125,7 +125,6 @@ LUFA_PATH = ../../.. | |||||||
| # List C source files here. (C dependencies are automatically generated.)
 | # List C source files here. (C dependencies are automatically generated.)
 | ||||||
| SRC = $(TARGET).c                                                 \
 | SRC = $(TARGET).c                                                 \
 | ||||||
| 	  Descriptors.c                                               \
 | 	  Descriptors.c                                               \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | ||||||
| @ -136,7 +135,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/Audio.c          \
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
| @ -186,7 +185,7 @@ CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | |||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY | ||||||
| CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | ||||||
| CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | ||||||
| CDEFS += -DAUDIO_OUT_STEREO | CDEFS += -DAUDIO_OUT_MONO | ||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for ASM sources
 | # Place -D or -U options here for ASM sources
 | ||||||
| ADEFS = -DF_CPU=$(F_CPU) | ADEFS = -DF_CPU=$(F_CPU) | ||||||
|  | |||||||
| @ -28,54 +28,42 @@ | |||||||
|   this software. |   this software. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| /** \file
 |  | ||||||
|  * |  | ||||||
|  *  Main source file for the CDC demo. This file contains the main tasks of the demo and |  | ||||||
|  *  is responsible for the initial application hardware configuration. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include "CDC.h" | #include "CDC.h" | ||||||
| 
 | 
 | ||||||
| /* Scheduler Task List */ | USB_ClassInfo_CDC_t VirtualSerial_CDC_Interface = | ||||||
| TASK_LIST | 	{ | ||||||
| { | 		.ControlInterfaceNumber     = 0, | ||||||
| 	{ .Task = USB_USBTask          , .TaskStatus = TASK_STOP }, |  | ||||||
| 	{ .Task = CDC_Task             , .TaskStatus = TASK_STOP }, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| /* Globals: */ | 		.DataINEndpointNumber       = CDC_TX_EPNUM, | ||||||
| /** Contains the current baud rate and other settings of the virtual serial port. While this demo does not use
 | 		.DataINEndpointSize         = CDC_TXRX_EPSIZE, | ||||||
|  *  the physical USART and thus does not use these settings, they must still be retained and returned to the host |  | ||||||
|  *  upon request or the host will assume the device is non-functional. |  | ||||||
|  * |  | ||||||
|  *  These values are set by the host via a class-specific request, however they are not required to be used accurately. |  | ||||||
|  *  It is possible to completely ignore these value or use other settings as the host is completely unaware of the physical |  | ||||||
|  *  serial link characteristics and instead sends and receives data in endpoint streams. |  | ||||||
|  */ |  | ||||||
| CDC_Line_Coding_t LineCoding = { .BaudRateBPS = 9600, |  | ||||||
|                                  .CharFormat  = OneStopBit, |  | ||||||
|                                  .ParityType  = Parity_None, |  | ||||||
|                                  .DataBits    = 8            }; |  | ||||||
| 
 | 
 | ||||||
| /** String to print through the virtual serial port when the joystick is pressed upwards. */ | 		.DataOUTEndpointNumber      = CDC_RX_EPNUM, | ||||||
| char JoystickUpString[]      = "Joystick Up\r\n"; | 		.DataOUTEndpointSize        = CDC_TXRX_EPSIZE, | ||||||
| 
 | 
 | ||||||
| /** String to print through the virtual serial port when the joystick is pressed downward. */ | 		.NotificationEndpointNumber = CDC_NOTIFICATION_EPNUM, | ||||||
| char JoystickDownString[]    = "Joystick Down\r\n"; | 		.NotificationEndpointSize   = CDC_NOTIFICATION_EPSIZE, | ||||||
|  | 	}; | ||||||
| 
 | 
 | ||||||
| /** String to print through the virtual serial port when the joystick is pressed left. */ |  | ||||||
| char JoystickLeftString[]    = "Joystick Left\r\n"; |  | ||||||
| 
 |  | ||||||
| /** String to print through the virtual serial port when the joystick is pressed right. */ |  | ||||||
| char JoystickRightString[]   = "Joystick Right\r\n"; |  | ||||||
| 
 |  | ||||||
| /** String to print through the virtual serial port when the joystick is pressed inwards. */ |  | ||||||
| char JoystickPressedString[] = "Joystick Pressed\r\n"; |  | ||||||
| 
 |  | ||||||
| /** 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) | int main(void) | ||||||
|  | { | ||||||
|  | 	SetupHardware(); | ||||||
|  | 	 | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | 
 | ||||||
|  | 	for (;;) | ||||||
|  | 	{ | ||||||
|  | 		CheckJoystickMovement(); | ||||||
|  | 		 | ||||||
|  | 		uint16_t BytesToDiscard = USB_CDC_BytesReceived(&VirtualSerial_CDC_Interface); | ||||||
|  | 		while (BytesToDiscard--) | ||||||
|  | 		  USB_CDC_ReceiveByte(&VirtualSerial_CDC_Interface); | ||||||
|  | 
 | ||||||
|  | 		USB_CDC_USBTask(&VirtualSerial_CDC_Interface); | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupHardware(void) | ||||||
| { | { | ||||||
| 	/* Disable watchdog if enabled by bootloader/fuses */ | 	/* Disable watchdog if enabled by bootloader/fuses */ | ||||||
| 	MCUSR &= ~(1 << WDRF); | 	MCUSR &= ~(1 << WDRF); | ||||||
| @ -87,235 +75,64 @@ int main(void) | |||||||
| 	/* Hardware Initialization */ | 	/* Hardware Initialization */ | ||||||
| 	Joystick_Init(); | 	Joystick_Init(); | ||||||
| 	LEDs_Init(); | 	LEDs_Init(); | ||||||
| 	 |  | ||||||
| 	/* Indicate USB not ready */ |  | ||||||
| 	UpdateStatus(Status_USBNotReady); |  | ||||||
| 	 |  | ||||||
| 	/* Initialize Scheduler so that it can be used */ |  | ||||||
| 	Scheduler_Init(); |  | ||||||
| 
 |  | ||||||
| 	/* Initialize USB Subsystem */ |  | ||||||
| 	USB_Init(); | 	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
 | void CheckJoystickMovement(void) | ||||||
|  *  starts the library USB task to begin the enumeration and USB management process. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Connect(void) |  | ||||||
| { | { | ||||||
| 	/* Start USB management task */ | 	uint8_t     JoyStatus_LCL = Joystick_GetStatus(); | ||||||
| 	Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); | 	char*       ReportString  = NULL; | ||||||
|  | 	static bool ActionSent = false; | ||||||
| 	 | 	 | ||||||
| 	/* Indicate USB enumerating */ | 	char* JoystickStrings[] = | ||||||
| 	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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Disconnect(void) |  | ||||||
| { |  | ||||||
| 	/* 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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_ConfigurationChanged(void) |  | ||||||
| { |  | ||||||
| 	/* 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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_UnhandledControlPacket(void) |  | ||||||
| { |  | ||||||
| 	uint8_t* LineCodingData = (uint8_t*)&LineCoding; |  | ||||||
| 
 |  | ||||||
| 	/* Process CDC specific control requests */ |  | ||||||
| 	switch (USB_ControlRequest.bRequest) |  | ||||||
| 	{ |  | ||||||
| 		case REQ_GetLineEncoding: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{	 |  | ||||||
| 				/* Acknowledge the SETUP packet, ready for data transfer */ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 
 |  | ||||||
| 				/* Write the line coding data to the control endpoint */ |  | ||||||
| 				Endpoint_Write_Control_Stream_LE(LineCodingData, sizeof(CDC_Line_Coding_t)); |  | ||||||
| 				 |  | ||||||
| 				/* Finalize the stream transfer to send the last packet or clear the host abort */ |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetLineEncoding: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				/* Acknowledge the SETUP packet, ready for data transfer */ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 
 |  | ||||||
| 				/* Read the line coding data in from the host into the global struct */ |  | ||||||
| 				Endpoint_Read_Control_Stream_LE(LineCodingData, sizeof(CDC_Line_Coding_t)); |  | ||||||
| 
 |  | ||||||
| 				/* Finalize the stream transfer to clear the last packet from the host */ |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 	 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetControlLineState: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				/* Acknowledge the SETUP packet, ready for data transfer */ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* 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 in USB_ControlRequest, and can be masked against the |  | ||||||
| 						 CONTROL_LINE_OUT_* masks to determine the RTS and DTR line states using the following code: |  | ||||||
| 				*/ |  | ||||||
| 				 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 	 |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** 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 CDC_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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Function to manage CDC data transmission and reception to and from the host. */ |  | ||||||
| TASK(CDC_Task) |  | ||||||
| { |  | ||||||
| 	char*       ReportString    = NULL; |  | ||||||
| 	uint8_t     JoyStatus_LCL   = Joystick_GetStatus(); |  | ||||||
| 	static bool ActionSent      = false; |  | ||||||
| 	 |  | ||||||
| #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), | 			"Joystick Up\r\n", | ||||||
| 			.Notification     = NOTIF_SerialState, | 			"Joystick Down\r\n", | ||||||
| 			.wValue           = 0, | 			"Joystick Left\r\n", | ||||||
| 			.wIndex           = 0, | 			"Joystick Right\r\n", | ||||||
| 			.wLength          = sizeof(uint16_t), | 			"Joystick Pressed\r\n", | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 	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_ClearIN(); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| 	/* Determine if a joystick action has occurred */ |  | ||||||
| 	if (JoyStatus_LCL & JOY_UP) | 	if (JoyStatus_LCL & JOY_UP) | ||||||
| 	  ReportString = JoystickUpString; | 	  ReportString = JoystickStrings[0]; | ||||||
| 	else if (JoyStatus_LCL & JOY_DOWN) | 	else if (JoyStatus_LCL & JOY_DOWN) | ||||||
| 	  ReportString = JoystickDownString; | 	  ReportString = JoystickStrings[1]; | ||||||
| 	else if (JoyStatus_LCL & JOY_LEFT) | 	else if (JoyStatus_LCL & JOY_LEFT) | ||||||
| 	  ReportString = JoystickLeftString; | 	  ReportString = JoystickStrings[2]; | ||||||
| 	else if (JoyStatus_LCL & JOY_RIGHT) | 	else if (JoyStatus_LCL & JOY_RIGHT) | ||||||
| 	  ReportString = JoystickRightString; | 	  ReportString = JoystickStrings[3]; | ||||||
| 	else if (JoyStatus_LCL & JOY_PRESS) | 	else if (JoyStatus_LCL & JOY_PRESS) | ||||||
| 	  ReportString = JoystickPressedString; | 	  ReportString = JoystickStrings[4]; | ||||||
|  | 	else | ||||||
|  | 	  ActionSent = false; | ||||||
| 	   | 	   | ||||||
| 	/* Flag management - Only allow one string to be sent per action */ | 	if ((ReportString != NULL) && (ActionSent == false)) | ||||||
| 	if (ReportString == NULL) |  | ||||||
| 	{ |  | ||||||
| 		ActionSent = false; |  | ||||||
| 	} |  | ||||||
| 	else if (ActionSent == false) |  | ||||||
| 	{ | 	{ | ||||||
| 		ActionSent = true; | 		ActionSent = true; | ||||||
| 		 | 		 | ||||||
| 		/* Select the Serial Tx Endpoint */ | 		USB_CDC_SendString(&VirtualSerial_CDC_Interface, ReportString, strlen(ReportString));		 | ||||||
| 		Endpoint_SelectEndpoint(CDC_TX_EPNUM); |  | ||||||
| 
 |  | ||||||
| 		/* Write the String to the Endpoint */ |  | ||||||
| 		Endpoint_Write_Stream_LE(ReportString, strlen(ReportString)); |  | ||||||
| 		 |  | ||||||
| 		/* Remember if the packet to send completely fills the endpoint */ |  | ||||||
| 		bool IsFull = (Endpoint_BytesInEndpoint() == CDC_TXRX_EPSIZE); |  | ||||||
| 
 |  | ||||||
| 		/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 		Endpoint_ClearIN(); |  | ||||||
| 
 |  | ||||||
| 		/* If the last packet filled the endpoint, send an empty packet to release the buffer on 
 |  | ||||||
| 		 * the receiver (otherwise all data will be cached until a non-full packet is received) */ |  | ||||||
| 		if (IsFull) |  | ||||||
| 		{ |  | ||||||
| 			/* Wait until the endpoint is ready for another packet */ |  | ||||||
| 			while (!(Endpoint_IsINReady())); |  | ||||||
| 			 |  | ||||||
| 			/* Send an empty packet to ensure that the host does not buffer data sent to it */ |  | ||||||
| 			Endpoint_ClearIN(); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | } | ||||||
| 	/* Select the Serial Rx Endpoint */ | 
 | ||||||
| 	Endpoint_SelectEndpoint(CDC_RX_EPNUM); | void EVENT_USB_Connect(void) | ||||||
| 	 | { | ||||||
| 	/* Throw away any received data from the host */ | 	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||||
| 	if (Endpoint_IsOUTReceived()) | } | ||||||
| 	  Endpoint_ClearOUT(); | 
 | ||||||
|  | void EVENT_USB_Disconnect(void) | ||||||
|  | { | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EVENT_USB_ConfigurationChanged(void) | ||||||
|  | { | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
|  | 
 | ||||||
|  | 	if (!(USB_CDC_ConfigureEndpoints(&VirtualSerial_CDC_Interface))) | ||||||
|  | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EVENT_USB_UnhandledControlPacket(void) | ||||||
|  | { | ||||||
|  | 	USB_CDC_ProcessControlPacket(&VirtualSerial_CDC_Interface); | ||||||
| } | } | ||||||
|  | |||||||
| @ -44,139 +44,26 @@ | |||||||
| 
 | 
 | ||||||
| 		#include "Descriptors.h" | 		#include "Descriptors.h" | ||||||
| 
 | 
 | ||||||
| 		#include <LUFA/Version.h>                        // Library Version Information | 		#include <LUFA/Version.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>                // USB Functionality | 		#include <LUFA/Drivers/Board/LEDs.h> | ||||||
| 		#include <LUFA/Drivers/Board/Joystick.h>         // Joystick driver | 		#include <LUFA/Drivers/Board/Joystick.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>             // LEDs driver | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>            // Simple scheduler for task management | 		#include <LUFA/Drivers/USB/Class/Device/CDC.h> | ||||||
| 
 | 
 | ||||||
| 	/* Macros: */ | 	/* Macros: */ | ||||||
| 		/** CDC Class specific request to get the current virtual serial port configuration settings. */ | 		#define LEDMASK_USB_NOTREADY      LEDS_LED1 | ||||||
| 		#define REQ_GetLineEncoding          0x21 | 		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3) | ||||||
| 
 | 		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4) | ||||||
| 		/** CDC Class specific request to set the current virtual serial port configuration settings. */ | 		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3) | ||||||
| 		#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 occurred 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 occurred 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 occurred on the virtual serial port. |  | ||||||
| 		 */ |  | ||||||
| 		#define CONTROL_LINE_IN_OVERRUNERROR (1 << 6) |  | ||||||
| 		 |  | ||||||
| 	/* 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 character 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 CDC_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: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void SetupHardware(void); | ||||||
|  | 		void CheckJoystickMovement(void); | ||||||
|  | 
 | ||||||
| 		void EVENT_USB_Connect(void); | 		void EVENT_USB_Connect(void); | ||||||
| 		void EVENT_USB_Disconnect(void); | 		void EVENT_USB_Disconnect(void); | ||||||
| 		void EVENT_USB_ConfigurationChanged(void); | 		void EVENT_USB_ConfigurationChanged(void); | ||||||
| 		void EVENT_USB_UnhandledControlPacket(void); | 		void EVENT_USB_UnhandledControlPacket(void); | ||||||
| 
 | 		void EVENT_USB_StartOfFrame(void); | ||||||
| 		void UpdateStatus(uint8_t CurrentStatus); |  | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -37,26 +37,12 @@ | |||||||
| #define _DESCRIPTORS_H_ | #define _DESCRIPTORS_H_ | ||||||
| 
 | 
 | ||||||
| 	/* Includes: */ | 	/* Includes: */ | ||||||
| 		#include <LUFA/Drivers/USB/USB.h> |  | ||||||
| 
 |  | ||||||
| 		#include <avr/pgmspace.h> | 		#include <avr/pgmspace.h> | ||||||
| 
 | 
 | ||||||
| 	/* Macros: */ | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 		/** Macro to define a CDC class-specific functional descriptor. CDC functional descriptors have a
 | 		#include <LUFA/Drivers/USB/Class/Device/CDC.h> | ||||||
| 		 *  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];  \ |  | ||||||
| 		     } |  | ||||||
| 
 | 
 | ||||||
|  | 	/* Macros: */			  | ||||||
| 		/** Endpoint number of the CDC device-to-host notification IN endpoint. */ | 		/** Endpoint number of the CDC device-to-host notification IN endpoint. */ | ||||||
| 		#define CDC_NOTIFICATION_EPNUM         2 | 		#define CDC_NOTIFICATION_EPNUM         2 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -125,7 +125,6 @@ LUFA_PATH = ../../.. | |||||||
| # List C source files here. (C dependencies are automatically generated.)
 | # List C source files here. (C dependencies are automatically generated.)
 | ||||||
| SRC = $(TARGET).c                                                 \
 | SRC = $(TARGET).c                                                 \
 | ||||||
| 	  Descriptors.c                                               \
 | 	  Descriptors.c                                               \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | ||||||
| @ -136,7 +135,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/CDC.c            \
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
| @ -183,7 +182,7 @@ CSTANDARD = -std=gnu99 | |||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for C sources
 | # Place -D or -U options here for C sources
 | ||||||
| CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | ||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY | ||||||
| CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | ||||||
| CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -37,26 +37,12 @@ | |||||||
| #define _DESCRIPTORS_H_ | #define _DESCRIPTORS_H_ | ||||||
| 
 | 
 | ||||||
| 	/* Includes: */ | 	/* Includes: */ | ||||||
| 		#include <LUFA/Drivers/USB/USB.h> |  | ||||||
| 
 |  | ||||||
| 		#include <avr/pgmspace.h> | 		#include <avr/pgmspace.h> | ||||||
| 
 | 
 | ||||||
| 	/* Macros: */ | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 		/** Macro to define a CDC class-specific functional descriptor. CDC functional descriptors have a
 | 		#include <LUFA/Drivers/USB/Class/Device/CDC.h> | ||||||
| 		 *  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];  \ |  | ||||||
| 		     } |  | ||||||
| 
 | 
 | ||||||
|  | 	/* Macros: */ | ||||||
| 		/** Endpoint number of the first CDC interface's device-to-host notification IN endpoint. */ | 		/** Endpoint number of the first CDC interface's device-to-host notification IN endpoint. */ | ||||||
| 		#define CDC1_NOTIFICATION_EPNUM        3 | 		#define CDC1_NOTIFICATION_EPNUM        3 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -28,68 +28,61 @@ | |||||||
|   this software. |   this software. | ||||||
| */ | */ | ||||||
|   |   | ||||||
| /** \file
 |  | ||||||
|  * |  | ||||||
|  *  Main source file for the DualCDC demo. This file contains the main tasks of the demo and |  | ||||||
|  *  is responsible for the initial application hardware configuration. |  | ||||||
|  */ |  | ||||||
|   |  | ||||||
| #include "DualCDC.h" | #include "DualCDC.h" | ||||||
| 
 | 
 | ||||||
| /* Scheduler Task List */ | USB_ClassInfo_CDC_t VirtualSerial1_CDC_Interface = | ||||||
| TASK_LIST | 	{ | ||||||
| { | 		.ControlInterfaceNumber     = 0, | ||||||
| 	{ .Task = USB_USBTask          , .TaskStatus = TASK_STOP }, |  | ||||||
| 	{ .Task = CDC1_Task            , .TaskStatus = TASK_STOP }, |  | ||||||
| 	{ .Task = CDC2_Task            , .TaskStatus = TASK_STOP }, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| /* Globals: */ | 		.DataINEndpointNumber       = CDC1_TX_EPNUM, | ||||||
| /** Contains the current baud rate and other settings of the first virtual serial port. While this demo does not use
 | 		.DataINEndpointSize         = CDC_TXRX_EPSIZE, | ||||||
|  *  the physical USART and thus does not use these settings, they must still be retained and returned to the host |  | ||||||
|  *  upon request or the host will assume the device is non-functional. |  | ||||||
|  * |  | ||||||
|  *  These values are set by the host via a class-specific request, however they are not required to be used accurately. |  | ||||||
|  *  It is possible to completely ignore these value or use other settings as the host is completely unaware of the physical |  | ||||||
|  *  serial link characteristics and instead sends and receives data in endpoint streams. |  | ||||||
|  */ |  | ||||||
| CDC_Line_Coding_t LineCoding1 = { .BaudRateBPS = 9600, |  | ||||||
|                                   .CharFormat  = OneStopBit, |  | ||||||
|                                   .ParityType  = Parity_None, |  | ||||||
|                                   .DataBits    = 8            }; |  | ||||||
| 
 | 
 | ||||||
| /** Contains the current baud rate and other settings of the second virtual serial port. While this demo does not use
 | 		.DataOUTEndpointNumber      = CDC1_RX_EPNUM, | ||||||
|  *  the physical USART and thus does not use these settings, they must still be retained and returned to the host | 		.DataOUTEndpointSize        = CDC_TXRX_EPSIZE, | ||||||
|  *  upon request or the host will assume the device is non-functional. |  | ||||||
|  * |  | ||||||
|  *  These values are set by the host via a class-specific request, however they are not required to be used accurately. |  | ||||||
|  *  It is possible to completely ignore these value or use other settings as the host is completely unaware of the physical |  | ||||||
|  *  serial link characteristics and instead sends and receives data in endpoint streams. |  | ||||||
|  */ |  | ||||||
| CDC_Line_Coding_t LineCoding2 = { .BaudRateBPS = 9600, |  | ||||||
|                                   .CharFormat  = OneStopBit, |  | ||||||
|                                   .ParityType  = Parity_None, |  | ||||||
|                                   .DataBits    = 8            }; |  | ||||||
| 
 | 
 | ||||||
| /** String to print through the first virtual serial port when the joystick is pressed upwards. */ | 		.NotificationEndpointNumber = CDC1_NOTIFICATION_EPNUM, | ||||||
| char JoystickUpString[]      = "Joystick Up\r\n"; | 		.NotificationEndpointSize   = CDC_NOTIFICATION_EPSIZE, | ||||||
|  | 	}; | ||||||
| 
 | 
 | ||||||
| /** String to print through the first virtual serial port when the joystick is pressed downward. */ | USB_ClassInfo_CDC_t VirtualSerial2_CDC_Interface = | ||||||
| char JoystickDownString[]    = "Joystick Down\r\n"; | 	{ | ||||||
|  | 		.ControlInterfaceNumber     = 0, | ||||||
| 
 | 
 | ||||||
| /** String to print through the first virtual serial port when the joystick is pressed left. */ | 		.DataINEndpointNumber       = CDC2_TX_EPNUM, | ||||||
| char JoystickLeftString[]    = "Joystick Left\r\n"; | 		.DataINEndpointSize         = CDC_TXRX_EPSIZE, | ||||||
| 
 | 
 | ||||||
| /** String to print through the first virtual serial port when the joystick is pressed right. */ | 		.DataOUTEndpointNumber      = CDC2_RX_EPNUM, | ||||||
| char JoystickRightString[]   = "Joystick Right\r\n"; | 		.DataOUTEndpointSize        = CDC_TXRX_EPSIZE, | ||||||
| 
 | 
 | ||||||
| /** String to print through the first virtual serial port when the joystick is pressed inwards. */ | 		.NotificationEndpointNumber = CDC2_NOTIFICATION_EPNUM, | ||||||
| char JoystickPressedString[] = "Joystick Pressed\r\n"; | 		.NotificationEndpointSize   = CDC_NOTIFICATION_EPSIZE, | ||||||
|  | 	}; | ||||||
| 
 | 
 | ||||||
| /** 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) | int main(void) | ||||||
|  | { | ||||||
|  | 	SetupHardware(); | ||||||
|  | 	 | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | 
 | ||||||
|  | 	for (;;) | ||||||
|  | 	{ | ||||||
|  | 		CheckJoystickMovement(); | ||||||
|  | 
 | ||||||
|  | 		uint16_t BytesToDiscard = USB_CDC_BytesReceived(&VirtualSerial1_CDC_Interface); | ||||||
|  | 		while (BytesToDiscard--) | ||||||
|  | 		  USB_CDC_ReceiveByte(&VirtualSerial1_CDC_Interface); | ||||||
|  | 
 | ||||||
|  | 		uint16_t BytesToEcho = USB_CDC_BytesReceived(&VirtualSerial2_CDC_Interface); | ||||||
|  | 		while (BytesToEcho--) | ||||||
|  | 		  USB_CDC_SendByte(&VirtualSerial2_CDC_Interface, USB_CDC_ReceiveByte(&VirtualSerial2_CDC_Interface)); | ||||||
|  | 		   | ||||||
|  | 		USB_CDC_USBTask(&VirtualSerial1_CDC_Interface); | ||||||
|  | 		USB_CDC_USBTask(&VirtualSerial2_CDC_Interface); | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupHardware(void) | ||||||
| { | { | ||||||
| 	/* Disable watchdog if enabled by bootloader/fuses */ | 	/* Disable watchdog if enabled by bootloader/fuses */ | ||||||
| 	MCUSR &= ~(1 << WDRF); | 	MCUSR &= ~(1 << WDRF); | ||||||
| @ -101,257 +94,68 @@ int main(void) | |||||||
| 	/* Hardware Initialization */ | 	/* Hardware Initialization */ | ||||||
| 	Joystick_Init(); | 	Joystick_Init(); | ||||||
| 	LEDs_Init(); | 	LEDs_Init(); | ||||||
| 	 |  | ||||||
| 	/* Indicate USB not ready */ |  | ||||||
| 	UpdateStatus(Status_USBNotReady); |  | ||||||
| 	 |  | ||||||
| 	/* Initialize Scheduler so that it can be used */ |  | ||||||
| 	Scheduler_Init(); |  | ||||||
| 
 |  | ||||||
| 	/* Initialize USB Subsystem */ |  | ||||||
| 	USB_Init(); | 	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
 | void CheckJoystickMovement(void) | ||||||
|  *  starts the library USB task to begin the enumeration and USB management process. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Connect(void) |  | ||||||
| { | { | ||||||
| 	/* Start USB management task */ | 	uint8_t     JoyStatus_LCL = Joystick_GetStatus(); | ||||||
| 	Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); | 	char*       ReportString  = NULL; | ||||||
|  | 	static bool ActionSent = false; | ||||||
| 
 | 
 | ||||||
| 	/* Indicate USB enumerating */ | 	char* JoystickStrings[] = | ||||||
| 	UpdateStatus(Status_USBEnumerating); | 		{ | ||||||
| } | 			"Joystick Up\r\n", | ||||||
|  | 			"Joystick Down\r\n", | ||||||
|  | 			"Joystick Left\r\n", | ||||||
|  | 			"Joystick Right\r\n", | ||||||
|  | 			"Joystick Pressed\r\n", | ||||||
|  | 		}; | ||||||
| 
 | 
 | ||||||
| /** 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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Disconnect(void) |  | ||||||
| { |  | ||||||
| 	/* Stop running CDC and USB management tasks */ |  | ||||||
| 	Scheduler_SetTaskMode(CDC1_Task, TASK_STOP); |  | ||||||
| 	Scheduler_SetTaskMode(CDC2_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 tasks are started. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_ConfigurationChanged(void) |  | ||||||
| { |  | ||||||
| 	/* Setup CDC Notification, Rx and Tx Endpoints for the first CDC */ |  | ||||||
| 	Endpoint_ConfigureEndpoint(CDC1_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT, |  | ||||||
| 		                       ENDPOINT_DIR_IN, CDC_NOTIFICATION_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 |  | ||||||
| 	Endpoint_ConfigureEndpoint(CDC1_TX_EPNUM, EP_TYPE_BULK, |  | ||||||
| 		                       ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 |  | ||||||
| 	Endpoint_ConfigureEndpoint(CDC1_RX_EPNUM, EP_TYPE_BULK, |  | ||||||
| 		                       ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 |  | ||||||
| 	/* Setup CDC Notification, Rx and Tx Endpoints for the second CDC */ |  | ||||||
| 	Endpoint_ConfigureEndpoint(CDC2_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT, |  | ||||||
| 		                       ENDPOINT_DIR_IN, CDC_NOTIFICATION_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 |  | ||||||
| 	Endpoint_ConfigureEndpoint(CDC2_TX_EPNUM, EP_TYPE_BULK, |  | ||||||
| 		                       ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 |  | ||||||
| 	Endpoint_ConfigureEndpoint(CDC2_RX_EPNUM, EP_TYPE_BULK, |  | ||||||
| 		                       ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 							    |  | ||||||
| 	/* Indicate USB connected and ready */ |  | ||||||
| 	UpdateStatus(Status_USBReady); |  | ||||||
| 	 |  | ||||||
| 	/* Start CDC tasks */ |  | ||||||
| 	Scheduler_SetTaskMode(CDC1_Task, TASK_RUN); |  | ||||||
| 	Scheduler_SetTaskMode(CDC2_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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_UnhandledControlPacket(void) |  | ||||||
| { |  | ||||||
| 	/* Determine which interface's Line Coding data is being set from the wIndex parameter */ |  | ||||||
| 	uint8_t* LineCodingData = (USB_ControlRequest.wIndex == 0) ? (uint8_t*)&LineCoding1 : (uint8_t*)&LineCoding2; |  | ||||||
| 
 |  | ||||||
| 	/* Process CDC specific control requests */ |  | ||||||
| 	switch (USB_ControlRequest.bRequest) |  | ||||||
| 	{ |  | ||||||
| 		case REQ_GetLineEncoding: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{	 |  | ||||||
| 				/* Acknowledge the SETUP packet, ready for data transfer */ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 
 |  | ||||||
| 				/* Write the line coding data to the control endpoint */ |  | ||||||
| 				Endpoint_Write_Control_Stream_LE(LineCodingData, sizeof(CDC_Line_Coding_t)); |  | ||||||
| 				 |  | ||||||
| 				/* Finalize the stream transfer to send the last packet or clear the host abort */ |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetLineEncoding: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				/* Acknowledge the SETUP packet, ready for data transfer */ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 
 |  | ||||||
| 				/* Read the line coding data in from the host into the global struct */ |  | ||||||
| 				Endpoint_Read_Control_Stream_LE(LineCodingData, sizeof(CDC_Line_Coding_t)); |  | ||||||
| 
 |  | ||||||
| 				/* Finalize the stream transfer to clear the last packet from the host */ |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 	 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetControlLineState: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				/* Acknowledge the SETUP packet, ready for data transfer */ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 	 |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** 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 DualCDC_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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Function to manage CDC data transmission and reception to and from the host for the first CDC interface, which sends joystick
 |  | ||||||
|  *  movements to the host as ASCII strings. |  | ||||||
|  */ |  | ||||||
| TASK(CDC1_Task) |  | ||||||
| { |  | ||||||
| 	char*       ReportString    = NULL; |  | ||||||
| 	uint8_t     JoyStatus_LCL   = Joystick_GetStatus(); |  | ||||||
| 	static bool ActionSent      = false; |  | ||||||
| 
 |  | ||||||
| 	/* Determine if a joystick action has occurred */ |  | ||||||
| 	if (JoyStatus_LCL & JOY_UP) | 	if (JoyStatus_LCL & JOY_UP) | ||||||
| 	  ReportString = JoystickUpString; | 	  ReportString = JoystickStrings[0]; | ||||||
| 	else if (JoyStatus_LCL & JOY_DOWN) | 	else if (JoyStatus_LCL & JOY_DOWN) | ||||||
| 	  ReportString = JoystickDownString; | 	  ReportString = JoystickStrings[1]; | ||||||
| 	else if (JoyStatus_LCL & JOY_LEFT) | 	else if (JoyStatus_LCL & JOY_LEFT) | ||||||
| 	  ReportString = JoystickLeftString; | 	  ReportString = JoystickStrings[2]; | ||||||
| 	else if (JoyStatus_LCL & JOY_RIGHT) | 	else if (JoyStatus_LCL & JOY_RIGHT) | ||||||
| 	  ReportString = JoystickRightString; | 	  ReportString = JoystickStrings[3]; | ||||||
| 	else if (JoyStatus_LCL & JOY_PRESS) | 	else if (JoyStatus_LCL & JOY_PRESS) | ||||||
| 	  ReportString = JoystickPressedString; | 	  ReportString = JoystickStrings[4]; | ||||||
|  | 	else | ||||||
|  | 	  ActionSent = false; | ||||||
| 	   | 	   | ||||||
| 	/* Flag management - Only allow one string to be sent per action */ | 	if ((ReportString != NULL) && (ActionSent == false)) | ||||||
| 	if (ReportString == NULL) |  | ||||||
| 	{ |  | ||||||
| 		ActionSent = false; |  | ||||||
| 	} |  | ||||||
| 	else if (ActionSent == false) |  | ||||||
| 	{ | 	{ | ||||||
| 		ActionSent = true; | 		ActionSent = true; | ||||||
| 		 | 		 | ||||||
| 		/* Select the Serial Tx Endpoint */ | 		USB_CDC_SendString(&VirtualSerial1_CDC_Interface, ReportString, strlen(ReportString));		 | ||||||
| 		Endpoint_SelectEndpoint(CDC1_TX_EPNUM); |  | ||||||
| 
 |  | ||||||
| 		/* Write the String to the Endpoint */ |  | ||||||
| 		Endpoint_Write_Stream_LE(ReportString, strlen(ReportString)); |  | ||||||
| 		 |  | ||||||
| 		/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 		Endpoint_ClearIN(); |  | ||||||
| 
 |  | ||||||
| 		/* Wait until the endpoint is ready for another packet */ |  | ||||||
| 		while (!(Endpoint_IsINReady())); |  | ||||||
| 		 |  | ||||||
| 		/* Send an empty packet to ensure that the host does not buffer data sent to it */ |  | ||||||
| 		Endpoint_ClearIN(); |  | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	/* Select the Serial Rx Endpoint */ |  | ||||||
| 	Endpoint_SelectEndpoint(CDC1_RX_EPNUM); |  | ||||||
| 	 |  | ||||||
| 	/* Throw away any received data from the host */ |  | ||||||
| 	if (Endpoint_IsOUTReceived()) |  | ||||||
| 	  Endpoint_ClearOUT(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Function to manage CDC data transmission and reception to and from the host for the second CDC interface, which echoes back
 | void EVENT_USB_Connect(void) | ||||||
|  *  all data sent to it from the host. |  | ||||||
|  */ |  | ||||||
| TASK(CDC2_Task) |  | ||||||
| { | { | ||||||
| 	/* Select the Serial Rx Endpoint */ | 	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||||
| 	Endpoint_SelectEndpoint(CDC2_RX_EPNUM); | } | ||||||
| 	 | 
 | ||||||
| 	/* Check to see if any data has been received */ | void EVENT_USB_Disconnect(void) | ||||||
| 	if (Endpoint_IsOUTReceived()) | { | ||||||
| 	{ | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
| 		/* Create a temp buffer big enough to hold the incoming endpoint packet */ | } | ||||||
| 		uint8_t  Buffer[Endpoint_BytesInEndpoint()]; | 
 | ||||||
| 		 | void EVENT_USB_ConfigurationChanged(void) | ||||||
| 		/* Remember how large the incoming packet is */ | { | ||||||
| 		uint16_t DataLength = Endpoint_BytesInEndpoint(); | 	LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
| 	 | 
 | ||||||
| 		/* Read in the incoming packet into the buffer */ | 	if (!(USB_CDC_ConfigureEndpoints(&VirtualSerial1_CDC_Interface))) | ||||||
| 		Endpoint_Read_Stream_LE(&Buffer, DataLength); | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
| 
 | 
 | ||||||
| 		/* Finalize the stream transfer to send the last packet */ | 	if (!(USB_CDC_ConfigureEndpoints(&VirtualSerial2_CDC_Interface))) | ||||||
| 		Endpoint_ClearOUT(); | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
| 
 | } | ||||||
| 		/* Select the Serial Tx Endpoint */ | 
 | ||||||
| 		Endpoint_SelectEndpoint(CDC2_TX_EPNUM); | void EVENT_USB_UnhandledControlPacket(void) | ||||||
| 		 | { | ||||||
| 		/* Write the received data to the endpoint */ | 	USB_CDC_ProcessControlPacket(&VirtualSerial1_CDC_Interface); | ||||||
| 		Endpoint_Write_Stream_LE(&Buffer, DataLength); | 	USB_CDC_ProcessControlPacket(&VirtualSerial2_CDC_Interface); | ||||||
| 
 |  | ||||||
| 		/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 		Endpoint_ClearIN(); |  | ||||||
| 
 |  | ||||||
| 		/* Wait until the endpoint is ready for the next packet */ |  | ||||||
| 		while (!(Endpoint_IsINReady())); |  | ||||||
| 
 |  | ||||||
| 		/* Send an empty packet to prevent host buffering */ |  | ||||||
| 		Endpoint_ClearIN(); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -44,75 +44,26 @@ | |||||||
| 
 | 
 | ||||||
| 		#include "Descriptors.h" | 		#include "Descriptors.h" | ||||||
| 
 | 
 | ||||||
| 		#include <LUFA/Version.h>                        // Library Version Information | 		#include <LUFA/Version.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>                // USB Functionality | 		#include <LUFA/Drivers/Board/LEDs.h> | ||||||
| 		#include <LUFA/Drivers/Board/Joystick.h>         // Joystick driver | 		#include <LUFA/Drivers/Board/Joystick.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>             // LEDs driver | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>            // Simple scheduler for task management | 		#include <LUFA/Drivers/USB/Class/Device/CDC.h> | ||||||
| 
 | 
 | ||||||
| 	/* Macros: */ | 	/* Macros: */ | ||||||
| 		/** CDC Class specific request to get the current virtual serial port configuration settings. */ | 		#define LEDMASK_USB_NOTREADY      LEDS_LED1 | ||||||
| 		#define REQ_GetLineEncoding          0x21 | 		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3) | ||||||
| 
 | 		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4) | ||||||
| 		/** CDC Class specific request to set the current virtual serial port configuration settings. */ | 		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3) | ||||||
| 		#define REQ_SetLineEncoding          0x20 |  | ||||||
| 
 |  | ||||||
| 		/** CDC Class specific request to set the current virtual serial port handshake line states. */ |  | ||||||
| 		#define REQ_SetControlLineState      0x22 |  | ||||||
| 
 |  | ||||||
| 	/* 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 character of the virtual serial port */ |  | ||||||
| 		} CDC_Line_Coding_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 DualCDC_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(CDC1_Task); |  | ||||||
| 		TASK(CDC2_Task); |  | ||||||
| 		 | 		 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void SetupHardware(void); | ||||||
|  | 		void CheckJoystickMovement(void); | ||||||
|  | 
 | ||||||
| 		void EVENT_USB_Connect(void); | 		void EVENT_USB_Connect(void); | ||||||
| 		void EVENT_USB_Disconnect(void); | 		void EVENT_USB_Disconnect(void); | ||||||
| 		void EVENT_USB_ConfigurationChanged(void); | 		void EVENT_USB_ConfigurationChanged(void); | ||||||
| 		void EVENT_USB_UnhandledControlPacket(void); | 		void EVENT_USB_UnhandledControlPacket(void); | ||||||
| 
 | 		void EVENT_USB_StartOfFrame(void); | ||||||
| 		void UpdateStatus(uint8_t CurrentStatus); |  | ||||||
| 		 | 		 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -125,7 +125,6 @@ LUFA_PATH = ../../.. | |||||||
| # List C source files here. (C dependencies are automatically generated.)
 | # List C source files here. (C dependencies are automatically generated.)
 | ||||||
| SRC = $(TARGET).c                                                 \
 | SRC = $(TARGET).c                                                 \
 | ||||||
| 	  Descriptors.c                                               \
 | 	  Descriptors.c                                               \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | ||||||
| @ -136,7 +135,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/CDC.c            \
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
| @ -183,7 +182,7 @@ CSTANDARD = -std=gnu99 | |||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for C sources
 | # Place -D or -U options here for C sources
 | ||||||
| CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | ||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY | ||||||
| CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | ||||||
| CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -37,30 +37,12 @@ | |||||||
| #define _DESCRIPTORS_H_ | #define _DESCRIPTORS_H_ | ||||||
| 
 | 
 | ||||||
| 	/* Includes: */ | 	/* Includes: */ | ||||||
| 		#include <LUFA/Drivers/USB/USB.h> |  | ||||||
| 
 |  | ||||||
| 		#include <avr/pgmspace.h> | 		#include <avr/pgmspace.h> | ||||||
| 
 | 
 | ||||||
| 	/* Type Defines: */ | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 		/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
 | 		#include <LUFA/Drivers/USB/Class/Device/HID.h> | ||||||
| 		 *  specification for details on the structure elements. |  | ||||||
| 		 */ |  | ||||||
| 		typedef struct |  | ||||||
| 		{ |  | ||||||
| 			USB_Descriptor_Header_t               Header; |  | ||||||
| 				 |  | ||||||
| 			uint16_t                              HIDSpec; |  | ||||||
| 			uint8_t                               CountryCode; |  | ||||||
| 		 |  | ||||||
| 			uint8_t                               TotalReportDescriptors; |  | ||||||
| 
 |  | ||||||
| 			uint8_t                               HIDReportType; |  | ||||||
| 			uint16_t                              HIDReportLength; |  | ||||||
| 		} USB_Descriptor_HID_t; |  | ||||||
| 
 |  | ||||||
| 		/** Type define for the data type used to store HID report descriptor elements. */ |  | ||||||
| 		typedef uint8_t USB_Descriptor_HIDReport_Datatype_t; |  | ||||||
| 
 | 
 | ||||||
|  | 	/** Type Defines: */ | ||||||
| 		/** Type define for the device configuration descriptor structure. This must be defined in the
 | 		/** 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 | 		 *  application code, as the configuration descriptor contains several sub-descriptors which | ||||||
| 		 *  vary between devices, and which describe the device's usage to the host. | 		 *  vary between devices, and which describe the device's usage to the host. | ||||||
| @ -87,12 +69,6 @@ | |||||||
| 		/** Size in bytes of the Generic HID reports (including report ID byte). */ | 		/** Size in bytes of the Generic HID reports (including report ID byte). */ | ||||||
| 		#define GENERIC_REPORT_SIZE       8 | 		#define GENERIC_REPORT_SIZE       8 | ||||||
| 		 | 		 | ||||||
| 		/** Descriptor header type value, to indicate a HID class HID descriptor. */ |  | ||||||
| 		#define DTYPE_HID                 0x21 |  | ||||||
| 		 |  | ||||||
| 		/** Descriptor header type value, to indicate a HID class HID report descriptor. */ |  | ||||||
| 		#define DTYPE_Report              0x22 |  | ||||||
| 
 |  | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
| 		uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) | 		uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) | ||||||
| 											ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); | 											ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); | ||||||
|  | |||||||
| @ -28,29 +28,37 @@ | |||||||
|   this software. |   this software. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| /** \file
 |  | ||||||
|  * |  | ||||||
|  *  Main source file for the GenericHID demo. This file contains the main tasks of the demo and |  | ||||||
|  *  is responsible for the initial application hardware configuration. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include "GenericHID.h" | #include "GenericHID.h" | ||||||
| 
 | 
 | ||||||
| /* Scheduler Task List */ | USB_ClassInfo_HID_t Generic_HID_Interface = | ||||||
| TASK_LIST | 	{ | ||||||
| { | 		.InterfaceNumber         = 0, | ||||||
| 	{ .Task = USB_USBTask          , .TaskStatus = TASK_STOP }, |  | ||||||
| 	{ .Task = USB_HID_Report       , .TaskStatus = TASK_STOP }, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| /** Static buffer to hold the last received report from the host, so that it can be echoed back in the next sent report */ | 		.ReportINEndpointNumber  = GENERIC_IN_EPNUM, | ||||||
| static uint8_t LastReceived[GENERIC_REPORT_SIZE]; | 		.ReportINEndpointSize    = GENERIC_EPSIZE, | ||||||
| 		 | 		 | ||||||
|  | 		.ReportOUTEndpointNumber = GENERIC_OUT_EPNUM, | ||||||
|  | 		.ReportOUTEndpointSize   = GENERIC_EPSIZE, | ||||||
|  | 		 | ||||||
|  | 		.ReportBufferSize        = GENERIC_REPORT_SIZE, | ||||||
|  | 
 | ||||||
|  | 		.UsingReportProtocol     = true, | ||||||
|  | 	}; | ||||||
| 
 | 
 | ||||||
| /** Main program entry point. This routine configures the hardware required by the application, then
 |  | ||||||
|  *  starts the scheduler to run the USB management task. |  | ||||||
|  */ |  | ||||||
| int main(void) | int main(void) | ||||||
|  | { | ||||||
|  | 	SetupHardware(); | ||||||
|  | 	 | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | 	 | ||||||
|  | 	for (;;) | ||||||
|  | 	{ | ||||||
|  | 		USB_HID_USBTask(&Generic_HID_Interface); | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupHardware(void) | ||||||
| { | { | ||||||
| 	/* Disable watchdog if enabled by bootloader/fuses */ | 	/* Disable watchdog if enabled by bootloader/fuses */ | ||||||
| 	MCUSR &= ~(1 << WDRF); | 	MCUSR &= ~(1 << WDRF); | ||||||
| @ -61,220 +69,45 @@ int main(void) | |||||||
| 
 | 
 | ||||||
| 	/* Hardware Initialization */ | 	/* Hardware Initialization */ | ||||||
| 	LEDs_Init(); | 	LEDs_Init(); | ||||||
| 
 |  | ||||||
| 	/* Indicate USB not ready */ |  | ||||||
| 	UpdateStatus(Status_USBNotReady); |  | ||||||
| 
 |  | ||||||
| 	/* Initialize Scheduler so that it can be used */ |  | ||||||
| 	Scheduler_Init(); |  | ||||||
| 
 |  | ||||||
| 	/* Initialize USB Subsystem */ |  | ||||||
| 	USB_Init(); | 	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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Connect(void) | void EVENT_USB_Connect(void) | ||||||
| { | { | ||||||
| 	/* Start USB management task */ | 	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||||
| 	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 task. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Disconnect(void) | void EVENT_USB_Disconnect(void) | ||||||
| { | { | ||||||
| 	/* Stop running HID reporting and USB management tasks */ | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
| 	Scheduler_SetTaskMode(USB_HID_Report, 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 sets the current configuration
 |  | ||||||
|  *  of the USB device after enumeration, and configures the generic HID device endpoints. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_ConfigurationChanged(void) | void EVENT_USB_ConfigurationChanged(void) | ||||||
| { | { | ||||||
| 	/* Setup Generic IN Report Endpoint */ | 	LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
| 	Endpoint_ConfigureEndpoint(GENERIC_IN_EPNUM, EP_TYPE_INTERRUPT, |  | ||||||
| 		                       ENDPOINT_DIR_IN, GENERIC_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 | 
 | ||||||
| 	/* Setup Generic OUT Report Endpoint */ | 	if (!(USB_HID_ConfigureEndpoints(&Generic_HID_Interface))) | ||||||
| 	Endpoint_ConfigureEndpoint(GENERIC_OUT_EPNUM, EP_TYPE_INTERRUPT, | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
| 		                       ENDPOINT_DIR_OUT, GENERIC_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 |  | ||||||
| 	/* Indicate USB connected and ready */ |  | ||||||
| 	UpdateStatus(Status_USBReady); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** 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 HID commands, which are |  | ||||||
|  *  all issued via the control endpoint), so that they can be handled appropriately for the application. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_UnhandledControlPacket(void) | void EVENT_USB_UnhandledControlPacket(void) | ||||||
| { | { | ||||||
| 	/* Handle HID Class specific requests */ | 	USB_HID_ProcessControlPacket(&Generic_HID_Interface); | ||||||
| 	switch (USB_ControlRequest.bRequest) |  | ||||||
| 	{ |  | ||||||
| 		case REQ_GetReport: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				uint8_t GenericData[GENERIC_REPORT_SIZE]; |  | ||||||
| 
 |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 	 |  | ||||||
| 				CreateGenericHIDReport(GenericData); |  | ||||||
| 
 |  | ||||||
| 				/* Write the report data to the control endpoint */ |  | ||||||
| 				Endpoint_Write_Control_Stream_LE(&GenericData, sizeof(GenericData)); |  | ||||||
| 
 |  | ||||||
| 				/* Finalize the stream transfer to send the last packet or clear the host abort */ |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 		 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetReport: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				uint8_t GenericData[GENERIC_REPORT_SIZE]; |  | ||||||
| 
 |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Wait until the generic report has been sent by the host */ |  | ||||||
| 				while (!(Endpoint_IsOUTReceived())); |  | ||||||
| 
 |  | ||||||
| 				Endpoint_Read_Control_Stream_LE(&GenericData, sizeof(GenericData)); |  | ||||||
| 
 |  | ||||||
| 				ProcessGenericHIDReport(GenericData); |  | ||||||
| 			 |  | ||||||
| 				/* Clear the endpoint data */ |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 
 |  | ||||||
| 				/* Wait until the host is ready to receive the request confirmation */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				 |  | ||||||
| 				/* Handshake the request by sending an empty IN packet */ |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
 | void EVENT_USB_StartOfFrame(void) | ||||||
|  *  log to a serial port, or anything else that is suitable for status updates. |  | ||||||
|  * |  | ||||||
|  *  \param CurrentStatus  Current status of the system, from the GenericHID_StatusCodes_t enum |  | ||||||
|  */ |  | ||||||
| void UpdateStatus(uint8_t CurrentStatus) |  | ||||||
| { | { | ||||||
| 	uint8_t LEDMask = LEDS_NO_LEDS; | 	USB_HID_RegisterStartOfFrame(&Generic_HID_Interface); | ||||||
| 	 |  | ||||||
| 	/* 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); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Function to process the lest received report from the host.
 | uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData) | ||||||
|  * |  | ||||||
|  *  \param DataArray  Pointer to a buffer where the last report data is stored |  | ||||||
|  */ |  | ||||||
| void ProcessGenericHIDReport(uint8_t* DataArray) |  | ||||||
| { | { | ||||||
| 	/*
 | 	// Create generic HID report here
 | ||||||
| 		This is where you need to process the reports being sent from the host to the device. |  | ||||||
| 		DataArray is an array holding the last report from the host. This function is called |  | ||||||
| 		each time the host has sent a report to the device. |  | ||||||
| 	*/ |  | ||||||
| 	 | 	 | ||||||
| 	for (uint8_t i = 0; i < GENERIC_REPORT_SIZE; i++) | 	return 0; | ||||||
| 	  LastReceived[i] = DataArray[i]; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Function to create the next report to send back to the host at the next reporting interval.
 | void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize) | ||||||
|  * |  | ||||||
|  *  \param DataArray  Pointer to a buffer where the next report data should be stored |  | ||||||
|  */ |  | ||||||
| void CreateGenericHIDReport(uint8_t* DataArray) |  | ||||||
| { | { | ||||||
| 	/*
 | 	// Process received generic HID report here
 | ||||||
| 		This is where you need to create reports to be sent to the host from the device. This |  | ||||||
| 		function is called each time the host is ready to accept a new report. DataArray is  |  | ||||||
| 		an array to hold the report to the host. |  | ||||||
| 	*/ |  | ||||||
| 
 |  | ||||||
| 	for (uint8_t i = 0; i < GENERIC_REPORT_SIZE; i++) |  | ||||||
| 	  DataArray[i] = LastReceived[i]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| TASK(USB_HID_Report) |  | ||||||
| { |  | ||||||
| 	/* Check if the USB system is connected to a host */ |  | ||||||
| 	if (USB_IsConnected) |  | ||||||
| 	{ |  | ||||||
| 		Endpoint_SelectEndpoint(GENERIC_OUT_EPNUM); |  | ||||||
| 		 |  | ||||||
| 		/* Check to see if a packet has been sent from the host */ |  | ||||||
| 		if (Endpoint_IsOUTReceived()) |  | ||||||
| 		{ |  | ||||||
| 			/* Check to see if the packet contains data */ |  | ||||||
| 			if (Endpoint_IsReadWriteAllowed()) |  | ||||||
| 			{ |  | ||||||
| 				/* Create a temporary buffer to hold the read in report from the host */ |  | ||||||
| 				uint8_t GenericData[GENERIC_REPORT_SIZE]; |  | ||||||
| 				 |  | ||||||
| 				/* Read Generic Report Data */ |  | ||||||
| 				Endpoint_Read_Stream_LE(&GenericData, sizeof(GenericData)); |  | ||||||
| 				 |  | ||||||
| 				/* Process Generic Report Data */ |  | ||||||
| 				ProcessGenericHIDReport(GenericData); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 			Endpoint_ClearOUT(); |  | ||||||
| 		}	 |  | ||||||
| 
 |  | ||||||
| 		Endpoint_SelectEndpoint(GENERIC_IN_EPNUM); |  | ||||||
| 		 |  | ||||||
| 		/* Check to see if the host is ready to accept another packet */ |  | ||||||
| 		if (Endpoint_IsINReady()) |  | ||||||
| 		{ |  | ||||||
| 			/* Create a temporary buffer to hold the report to send to the host */ |  | ||||||
| 			uint8_t GenericData[GENERIC_REPORT_SIZE]; |  | ||||||
| 			 |  | ||||||
| 			/* Create Generic Report Data */ |  | ||||||
| 			CreateGenericHIDReport(GenericData); |  | ||||||
| 
 |  | ||||||
| 			/* Write Generic Report Data */ |  | ||||||
| 			Endpoint_Write_Stream_LE(&GenericData, sizeof(GenericData)); |  | ||||||
| 
 |  | ||||||
| 			/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 			Endpoint_ClearIN(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -46,38 +46,28 @@ | |||||||
| 		 | 		 | ||||||
| 		#include "Descriptors.h" | 		#include "Descriptors.h" | ||||||
| 
 | 
 | ||||||
| 		#include <LUFA/Version.h>                    // Library Version Information | 		#include <LUFA/Version.h> | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>        // Simple scheduler for task management | 		#include <LUFA/Drivers/Board/LEDs.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>            // USB Functionality | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>         // LEDs driver | 		#include <LUFA/Drivers/USB/Class/Device/HID.h> | ||||||
| 
 | 
 | ||||||
| 	/* Macros: */ | 	/* Macros: */ | ||||||
| 		/** HID Class specific request to get the next HID report from the device. */ | 		#define LEDMASK_USB_NOTREADY      LEDS_LED1 | ||||||
| 		#define REQ_GetReport      0x01 | 		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3) | ||||||
| 
 | 		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4) | ||||||
| 		/** HID Class specific request to send the next HID report to the device. */ | 		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3) | ||||||
| 		#define REQ_SetReport      0x09 |  | ||||||
| 
 |  | ||||||
| 	/* Enums: */ |  | ||||||
| 		/** Enum for the possible status codes for passing to the UpdateStatus() function. */ |  | ||||||
| 		enum GenericHID_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 */ |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 	/* Task Definitions: */ |  | ||||||
| 		TASK(USB_HID_Report); |  | ||||||
| 
 | 
 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void SetupHardware(void); | ||||||
|  | 
 | ||||||
| 		void EVENT_USB_Connect(void); | 		void EVENT_USB_Connect(void); | ||||||
| 		void EVENT_USB_Disconnect(void); | 		void EVENT_USB_Disconnect(void); | ||||||
| 		void EVENT_USB_ConfigurationChanged(void); | 		void EVENT_USB_ConfigurationChanged(void); | ||||||
| 		void EVENT_USB_UnhandledControlPacket(void); | 		void EVENT_USB_UnhandledControlPacket(void); | ||||||
|  | 		void EVENT_USB_StartOfFrame(void); | ||||||
| 
 | 
 | ||||||
| 		void UpdateStatus(uint8_t CurrentStatus); | 		uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData); | ||||||
| 		void ProcessGenericHIDReport(uint8_t* DataArray); | 		void     CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, | ||||||
| 		void CreateGenericHIDReport(uint8_t* DataArray); | 		                                                   void* ReportData, uint16_t ReportSize); | ||||||
| 		 | 		 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -125,7 +125,6 @@ LUFA_PATH = ../../.. | |||||||
| # List C source files here. (C dependencies are automatically generated.)
 | # List C source files here. (C dependencies are automatically generated.)
 | ||||||
| SRC = $(TARGET).c                                                 \
 | SRC = $(TARGET).c                                                 \
 | ||||||
| 	  Descriptors.c                                               \
 | 	  Descriptors.c                                               \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | ||||||
| @ -136,7 +135,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/HID.c            \
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
| @ -183,7 +182,7 @@ CSTANDARD = -std=gnu99 | |||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for C sources
 | # Place -D or -U options here for C sources
 | ||||||
| CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | ||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY | ||||||
| CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | ||||||
| CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -37,30 +37,12 @@ | |||||||
| #define _DESCRIPTORS_H_ | #define _DESCRIPTORS_H_ | ||||||
| 
 | 
 | ||||||
| 	/* Includes: */ | 	/* Includes: */ | ||||||
| 		#include <LUFA/Drivers/USB/USB.h> |  | ||||||
| 
 |  | ||||||
| 		#include <avr/pgmspace.h> | 		#include <avr/pgmspace.h> | ||||||
| 
 | 
 | ||||||
|  | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
|  | 		#include <LUFA/Drivers/USB/Class/Device/HID.h> | ||||||
|  | 
 | ||||||
| 	/* Type Defines: */ | 	/* Type Defines: */ | ||||||
| 		/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
 |  | ||||||
| 		 *  specification for details on the structure elements. |  | ||||||
| 		 */ |  | ||||||
| 		typedef struct |  | ||||||
| 		{ |  | ||||||
| 			USB_Descriptor_Header_t               Header; |  | ||||||
| 				 |  | ||||||
| 			uint16_t                              HIDSpec; |  | ||||||
| 			uint8_t                               CountryCode; |  | ||||||
| 		 |  | ||||||
| 			uint8_t                               TotalReportDescriptors; |  | ||||||
| 
 |  | ||||||
| 			uint8_t                               HIDReportType; |  | ||||||
| 			uint16_t                              HIDReportLength; |  | ||||||
| 		} USB_Descriptor_HID_t; |  | ||||||
| 
 |  | ||||||
| 		/** Type define for the data type used to store HID report descriptor elements. */ |  | ||||||
| 		typedef uint8_t USB_Descriptor_HIDReport_Datatype_t; |  | ||||||
| 
 |  | ||||||
| 		/** Type define for the device configuration descriptor structure. This must be defined in the
 | 		/** 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 | 		 *  application code, as the configuration descriptor contains several sub-descriptors which | ||||||
| 		 *  vary between devices, and which describe the device's usage to the host. | 		 *  vary between devices, and which describe the device's usage to the host. | ||||||
| @ -80,12 +62,6 @@ | |||||||
| 		/** Size in bytes of the Joystick HID reporting IN endpoint. */ | 		/** Size in bytes of the Joystick HID reporting IN endpoint. */ | ||||||
| 		#define JOYSTICK_EPSIZE              8 | 		#define JOYSTICK_EPSIZE              8 | ||||||
| 
 | 
 | ||||||
| 		/** Descriptor header type value, to indicate a HID class HID descriptor. */ |  | ||||||
| 		#define DTYPE_HID                 0x21 |  | ||||||
| 		 |  | ||||||
| 		/** Descriptor header type value, to indicate a HID class HID report descriptor. */ |  | ||||||
| 		#define DTYPE_Report              0x22 |  | ||||||
| 
 |  | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
| 		uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) | 		uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) | ||||||
| 											ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); | 											ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); | ||||||
|  | |||||||
| @ -28,25 +28,34 @@ | |||||||
|   this software. |   this software. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| /** \file
 |  | ||||||
|  * |  | ||||||
|  *  Main source file for the Joystick demo. This file contains the main tasks of the demo and |  | ||||||
|  *  is responsible for the initial application hardware configuration. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include "Joystick.h" | #include "Joystick.h" | ||||||
| 
 | 
 | ||||||
| /* Scheduler Task List */ | USB_ClassInfo_HID_t Joystick_HID_Interface = | ||||||
| TASK_LIST | 	{ | ||||||
| { | 		.InterfaceNumber         = 0, | ||||||
| 	{ .Task = USB_USBTask          , .TaskStatus = TASK_STOP }, | 
 | ||||||
| 	{ .Task = USB_Joystick_Report  , .TaskStatus = TASK_STOP }, | 		.ReportINEndpointNumber  = JOYSTICK_EPNUM, | ||||||
| }; | 		.ReportINEndpointSize    = JOYSTICK_EPSIZE, | ||||||
|  | 		 | ||||||
|  | 		.ReportBufferSize        = sizeof(USB_JoystickReport_Data_t), | ||||||
|  | 
 | ||||||
|  | 		.UsingReportProtocol     = true, | ||||||
|  | 	}; | ||||||
| 
 | 
 | ||||||
| /** 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) | int main(void) | ||||||
|  | { | ||||||
|  | 	SetupHardware(); | ||||||
|  | 	 | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | 	 | ||||||
|  | 	for (;;) | ||||||
|  | 	{ | ||||||
|  | 		USB_HID_USBTask(&Joystick_HID_Interface); | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupHardware(void) | ||||||
| { | { | ||||||
| 	/* Disable watchdog if enabled by bootloader/fuses */ | 	/* Disable watchdog if enabled by bootloader/fuses */ | ||||||
| 	MCUSR &= ~(1 << WDRF); | 	MCUSR &= ~(1 << WDRF); | ||||||
| @ -59,188 +68,64 @@ int main(void) | |||||||
| 	Joystick_Init(); | 	Joystick_Init(); | ||||||
| 	LEDs_Init(); | 	LEDs_Init(); | ||||||
| 	Buttons_Init(); | 	Buttons_Init(); | ||||||
| 	 |  | ||||||
| 	/* Indicate USB not ready */ |  | ||||||
| 	UpdateStatus(Status_USBNotReady); |  | ||||||
| 	 |  | ||||||
| 	/* Initialize Scheduler so that it can be used */ |  | ||||||
| 	Scheduler_Init(); |  | ||||||
| 
 |  | ||||||
| 	/* Initialize USB Subsystem */ |  | ||||||
| 	USB_Init(); | 	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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Connect(void) | void EVENT_USB_Connect(void) | ||||||
| { | { | ||||||
| 	/* Start USB management task */ | 	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||||
| 	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 joystick reporting tasks. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Disconnect(void) | void EVENT_USB_Disconnect(void) | ||||||
| { | { | ||||||
| 	/* Stop running joystick reporting and USB management tasks */ | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
| 	Scheduler_SetTaskMode(USB_Joystick_Report, 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 joystick reporting task started. |  | ||||||
|  */  |  | ||||||
| void EVENT_USB_ConfigurationChanged(void) | void EVENT_USB_ConfigurationChanged(void) | ||||||
| { | { | ||||||
| 	/* Setup Joystick Report Endpoint */ | 	LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
| 	Endpoint_ConfigureEndpoint(JOYSTICK_EPNUM, EP_TYPE_INTERRUPT, |  | ||||||
| 		                       ENDPOINT_DIR_IN, JOYSTICK_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 | 
 | ||||||
| 	/* Indicate USB connected and ready */ | 	if (!(USB_HID_ConfigureEndpoints(&Joystick_HID_Interface))) | ||||||
| 	UpdateStatus(Status_USBReady); | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
| 
 |  | ||||||
| 	/* Start joystick reporting task */ |  | ||||||
| 	Scheduler_SetTaskMode(USB_Joystick_Report, 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 HID commands, which are |  | ||||||
|  *  all issued via the control endpoint), so that they can be handled appropriately for the application. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_UnhandledControlPacket(void) | void EVENT_USB_UnhandledControlPacket(void) | ||||||
| { | { | ||||||
| 	/* Handle HID Class specific requests */ | 	USB_HID_ProcessControlPacket(&Joystick_HID_Interface); | ||||||
| 	switch (USB_ControlRequest.bRequest) |  | ||||||
| 	{ |  | ||||||
| 		case REQ_GetReport: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				USB_JoystickReport_Data_t JoystickReportData; |  | ||||||
| 				 |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 
 |  | ||||||
| 				/* Create the next HID report to send to the host */				 |  | ||||||
| 				GetNextReport(&JoystickReportData); |  | ||||||
| 					 |  | ||||||
| 				/* Write the report data to the control endpoint */ |  | ||||||
| 				Endpoint_Write_Control_Stream_LE(&JoystickReportData, sizeof(JoystickReportData)); |  | ||||||
| 				 |  | ||||||
| 				/* Finalize the stream transfer to send the last packet or clear the host abort */ |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 		 |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Fills the given HID report data structure with the next HID report to send to the host.
 | void EVENT_USB_StartOfFrame(void) | ||||||
|  * |  | ||||||
|  *  \param ReportData  Pointer to a HID report data structure to be filled |  | ||||||
|  * |  | ||||||
|  *  \return Boolean true if the new report differs from the last report, false otherwise |  | ||||||
|  */ |  | ||||||
| bool GetNextReport(USB_JoystickReport_Data_t* ReportData) |  | ||||||
| { | { | ||||||
| 	static uint8_t PrevJoyStatus    = 0; | 	USB_HID_RegisterStartOfFrame(&Joystick_HID_Interface); | ||||||
| 	static uint8_t PrevButtonStatus = 0; | } | ||||||
| 	uint8_t        JoyStatus_LCL    = Joystick_GetStatus(); |  | ||||||
| 	uint8_t        ButtonStatus_LCL = Buttons_GetStatus(); |  | ||||||
| 	bool           InputChanged     = false; |  | ||||||
| 
 | 
 | ||||||
| 	/* Clear the report contents */ | uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData) | ||||||
| 	memset(ReportData, 0, sizeof(USB_JoystickReport_Data_t)); | { | ||||||
|  | 	USB_JoystickReport_Data_t* JoystickReport = (USB_JoystickReport_Data_t*)ReportData; | ||||||
|  | 	 | ||||||
|  | 	uint8_t JoyStatus_LCL    = Joystick_GetStatus(); | ||||||
|  | 	uint8_t ButtonStatus_LCL = Buttons_GetStatus(); | ||||||
| 
 | 
 | ||||||
| 	if (JoyStatus_LCL & JOY_UP) | 	if (JoyStatus_LCL & JOY_UP) | ||||||
| 	  ReportData->Y = -100; | 	  JoystickReport->Y = -100; | ||||||
| 	else if (JoyStatus_LCL & JOY_DOWN) | 	else if (JoyStatus_LCL & JOY_DOWN) | ||||||
| 	  ReportData->Y =  100; | 	  JoystickReport->Y =  100; | ||||||
| 
 | 
 | ||||||
| 	if (JoyStatus_LCL & JOY_RIGHT) | 	if (JoyStatus_LCL & JOY_RIGHT) | ||||||
| 	  ReportData->X =  100; | 	  JoystickReport->X =  100; | ||||||
| 	else if (JoyStatus_LCL & JOY_LEFT) | 	else if (JoyStatus_LCL & JOY_LEFT) | ||||||
| 	  ReportData->X = -100; | 	  JoystickReport->X = -100; | ||||||
| 
 | 
 | ||||||
| 	if (JoyStatus_LCL & JOY_PRESS) | 	if (JoyStatus_LCL & JOY_PRESS) | ||||||
| 	  ReportData->Button  = (1 << 1); | 	  JoystickReport->Button  = (1 << 1); | ||||||
| 	   | 	   | ||||||
| 	if (ButtonStatus_LCL & BUTTONS_BUTTON1) | 	if (ButtonStatus_LCL & BUTTONS_BUTTON1) | ||||||
| 	  ReportData->Button |= (1 << 0); | 	  JoystickReport->Button |= (1 << 0); | ||||||
| 	   | 	   | ||||||
| 	/* Check if the new report is different to the previous report */ | 	return sizeof(USB_JoystickReport_Data_t); | ||||||
| 	InputChanged = (uint8_t)(PrevJoyStatus ^ JoyStatus_LCL) | (uint8_t)(PrevButtonStatus ^ ButtonStatus_LCL); |  | ||||||
| 
 |  | ||||||
| 	/* Save the current joystick status for later comparison */ |  | ||||||
| 	PrevJoyStatus    = JoyStatus_LCL; |  | ||||||
| 	PrevButtonStatus = ButtonStatus_LCL; |  | ||||||
| 
 |  | ||||||
| 	/* Return whether the new report is different to the previous report or not */ |  | ||||||
| 	return InputChanged; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
 | void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize) | ||||||
|  *  log to a serial port, or anything else that is suitable for status updates. |  | ||||||
|  * |  | ||||||
|  *  \param CurrentStatus  Current status of the system, from the Joystick_StatusCodes_t enum |  | ||||||
|  */ |  | ||||||
| void UpdateStatus(uint8_t CurrentStatus) |  | ||||||
| { | { | ||||||
| 	uint8_t LEDMask = LEDS_NO_LEDS; | 	// Unused (but mandatory for the HID class driver) in this demo, since there are no Host->Device reports
 | ||||||
| 	 |  | ||||||
| 	/* 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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Function to manage HID report generation and transmission to the host. */ |  | ||||||
| TASK(USB_Joystick_Report) |  | ||||||
| { |  | ||||||
| 	/* Check if the USB System is connected to a Host */ |  | ||||||
| 	if (USB_IsConnected) |  | ||||||
| 	{ |  | ||||||
| 		/* Select the Joystick Report Endpoint */ |  | ||||||
| 		Endpoint_SelectEndpoint(JOYSTICK_EPNUM); |  | ||||||
| 
 |  | ||||||
| 		/* Check to see if the host is ready for another packet */ |  | ||||||
| 		if (Endpoint_IsINReady()) |  | ||||||
| 		{ |  | ||||||
| 			USB_JoystickReport_Data_t JoystickReportData; |  | ||||||
| 			 |  | ||||||
| 			/* Create the next HID report to send to the host */ |  | ||||||
| 			GetNextReport(&JoystickReportData); |  | ||||||
| 		 |  | ||||||
| 			/* Write Joystick Report Data */ |  | ||||||
| 			Endpoint_Write_Stream_LE(&JoystickReportData, sizeof(JoystickReportData)); |  | ||||||
| 
 |  | ||||||
| 			/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 			Endpoint_ClearIN(); |  | ||||||
| 			 |  | ||||||
| 			/* Clear the report data afterwards */ |  | ||||||
| 			memset(&JoystickReportData, 0, sizeof(JoystickReportData)); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -44,19 +44,12 @@ | |||||||
| 
 | 
 | ||||||
| 		#include "Descriptors.h" | 		#include "Descriptors.h" | ||||||
| 
 | 
 | ||||||
| 		#include <LUFA/Version.h>                    // Library Version Information | 		#include <LUFA/Version.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>            // USB Functionality | 		#include <LUFA/Drivers/Board/Joystick.h> | ||||||
| 		#include <LUFA/Drivers/Board/Joystick.h>     // Joystick driver | 		#include <LUFA/Drivers/Board/LEDs.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>         // LEDs driver | 		#include <LUFA/Drivers/Board/Buttons.h> | ||||||
| 		#include <LUFA/Drivers/Board/Buttons.h>      // Board Buttons driver | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>        // Simple scheduler for task management | 		#include <LUFA/Drivers/USB/Class/Device/HID.h> | ||||||
| 		 |  | ||||||
| 	/* Task Definitions: */ |  | ||||||
| 		TASK(USB_Joystick_Report); |  | ||||||
| 
 |  | ||||||
| 	/* Macros: */ |  | ||||||
| 		/** HID Class specific request to get the next HID report from the device. */ |  | ||||||
| 		#define REQ_GetReport   0x01 |  | ||||||
| 
 | 
 | ||||||
| 	/* Type Defines: */ | 	/* Type Defines: */ | ||||||
| 		/** Type define for the joystick HID report structure, for creating and sending HID reports to the host PC.
 | 		/** Type define for the joystick HID report structure, for creating and sending HID reports to the host PC.
 | ||||||
| @ -69,22 +62,23 @@ | |||||||
| 			uint8_t Button; /**< Bit mask of the currently pressed joystick buttons */ | 			uint8_t Button; /**< Bit mask of the currently pressed joystick buttons */ | ||||||
| 		} USB_JoystickReport_Data_t; | 		} USB_JoystickReport_Data_t; | ||||||
| 			 | 			 | ||||||
| 	/* Enums: */ | 	/* Macros: */ | ||||||
| 		/** Enum for the possible status codes for passing to the UpdateStatus() function. */ | 		#define LEDMASK_USB_NOTREADY      LEDS_LED1 | ||||||
| 		enum Joystick_StatusCodes_t | 		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3) | ||||||
| 		{ | 		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4) | ||||||
| 			Status_USBNotReady    = 0, /**< USB is not ready (disconnected from a USB host) */ | 		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3) | ||||||
| 			Status_USBEnumerating = 1, /**< USB interface is enumerating */ |  | ||||||
| 			Status_USBReady       = 2, /**< USB interface is connected and ready */ |  | ||||||
| 		}; |  | ||||||
| 
 | 
 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void SetupHardware(void); | ||||||
|  | 
 | ||||||
| 		void EVENT_USB_Connect(void); | 		void EVENT_USB_Connect(void); | ||||||
| 		void EVENT_USB_Disconnect(void); | 		void EVENT_USB_Disconnect(void); | ||||||
| 		void EVENT_USB_ConfigurationChanged(void); | 		void EVENT_USB_ConfigurationChanged(void); | ||||||
| 		void EVENT_USB_UnhandledControlPacket(void); | 		void EVENT_USB_UnhandledControlPacket(void); | ||||||
|  | 		void EVENT_USB_StartOfFrame(void); | ||||||
| 
 | 
 | ||||||
| 		bool GetNextReport(USB_JoystickReport_Data_t* ReportData); | 		uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData); | ||||||
| 		void UpdateStatus(uint8_t CurrentStatus); | 		void     CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, | ||||||
|  | 		                                                   void* ReportData, uint16_t ReportSize); | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -125,7 +125,6 @@ LUFA_PATH = ../../.. | |||||||
| # List C source files here. (C dependencies are automatically generated.)
 | # List C source files here. (C dependencies are automatically generated.)
 | ||||||
| SRC = $(TARGET).c                                                 \
 | SRC = $(TARGET).c                                                 \
 | ||||||
| 	  Descriptors.c                                               \
 | 	  Descriptors.c                                               \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | ||||||
| @ -136,7 +135,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/HID.c            \
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
| @ -183,7 +182,7 @@ CSTANDARD = -std=gnu99 | |||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for C sources
 | # Place -D or -U options here for C sources
 | ||||||
| CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | ||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY | ||||||
| CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | ||||||
| CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -38,30 +38,12 @@ | |||||||
| #define _DESCRIPTORS_H_ | #define _DESCRIPTORS_H_ | ||||||
| 
 | 
 | ||||||
| 	/* Includes: */ | 	/* Includes: */ | ||||||
| 		#include <LUFA/Drivers/USB/USB.h> |  | ||||||
| 
 |  | ||||||
| 		#include <avr/pgmspace.h> | 		#include <avr/pgmspace.h> | ||||||
| 
 | 
 | ||||||
|  | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
|  | 		#include <LUFA/Drivers/USB/Class/Device/HID.h> | ||||||
|  | 
 | ||||||
| 	/* Type Defines: */ | 	/* Type Defines: */ | ||||||
| 		/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
 |  | ||||||
| 		 *  specification for details on the structure elements. |  | ||||||
| 		 */	 |  | ||||||
| 		typedef struct |  | ||||||
| 		{ |  | ||||||
| 			USB_Descriptor_Header_t Header; |  | ||||||
| 				 |  | ||||||
| 			uint16_t                HIDSpec; |  | ||||||
| 			uint8_t                 CountryCode; |  | ||||||
| 		 |  | ||||||
| 			uint8_t                 TotalReportDescriptors; |  | ||||||
| 
 |  | ||||||
| 			uint8_t                 HIDReportType; |  | ||||||
| 			uint16_t                HIDReportLength; |  | ||||||
| 		} USB_Descriptor_HID_t; |  | ||||||
| 		 |  | ||||||
| 		/** Type define for the data type used to store HID report descriptor elements. */ |  | ||||||
| 		typedef uint8_t USB_Descriptor_HIDReport_Datatype_t; |  | ||||||
| 
 |  | ||||||
| 		/** Type define for the device configuration descriptor structure. This must be defined in the
 | 		/** 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 | 		 *  application code, as the configuration descriptor contains several sub-descriptors which | ||||||
| 		 *  vary between devices, and which describe the device's usage to the host. | 		 *  vary between devices, and which describe the device's usage to the host. | ||||||
| @ -85,12 +67,6 @@ | |||||||
| 		/** Size in bytes of the Keyboard HID reporting IN and OUT endpoints. */		 | 		/** Size in bytes of the Keyboard HID reporting IN and OUT endpoints. */		 | ||||||
| 		#define KEYBOARD_EPSIZE              8 | 		#define KEYBOARD_EPSIZE              8 | ||||||
| 
 | 
 | ||||||
| 		/** Descriptor header type value, to indicate a HID class HID descriptor. */ |  | ||||||
| 		#define DTYPE_HID                 0x21 |  | ||||||
| 		 |  | ||||||
| 		/** Descriptor header type value, to indicate a HID class HID report descriptor. */ |  | ||||||
| 		#define DTYPE_Report              0x22 |  | ||||||
| 
 |  | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
| 		uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) | 		uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) | ||||||
| 											ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); | 											ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); | ||||||
|  | |||||||
| @ -29,396 +29,119 @@ | |||||||
|   this software. |   this software. | ||||||
| */ | */ | ||||||
|   |   | ||||||
| /** \file
 |  | ||||||
|  * |  | ||||||
|  *  Main source file for the Keyboard demo. This file contains the main tasks of the demo and |  | ||||||
|  *  is responsible for the initial application hardware configuration. |  | ||||||
|  */ |  | ||||||
|   |  | ||||||
| #include "Keyboard.h" | #include "Keyboard.h" | ||||||
| 
 | 
 | ||||||
| /* Scheduler Task List */ | USB_ClassInfo_HID_t Keyboard_HID_Interface = | ||||||
| TASK_LIST |     { | ||||||
| { |         .InterfaceNumber         = 0, | ||||||
| 	{ .Task = USB_USBTask          , .TaskStatus = TASK_STOP },	 |  | ||||||
| 	{ .Task = USB_Keyboard_Report  , .TaskStatus = TASK_STOP }, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| /* Global Variables */ |         .ReportINEndpointNumber  = KEYBOARD_EPNUM, | ||||||
| /** Indicates what report mode the host has requested, true for normal HID reporting mode, false for special boot
 |         .ReportINEndpointSize    = KEYBOARD_EPSIZE, | ||||||
|  *  protocol reporting mode. |  | ||||||
|  */ |  | ||||||
| bool UsingReportProtocol = true; |  | ||||||
| 
 | 
 | ||||||
| /** Current Idle period. This is set by the host via a Set Idle HID class request to silence the device's reports
 |         .ReportOUTEndpointNumber = KEYBOARD_LEDS_EPNUM, | ||||||
|  *  for either the entire idle duration, or until the report status changes (e.g. the user presses a key). |         .ReportOUTEndpointSize   = KEYBOARD_EPSIZE, | ||||||
|  */ |  | ||||||
| uint16_t IdleCount = 500; |  | ||||||
|          |          | ||||||
| /** Current Idle period remaining. When the IdleCount value is set, this tracks the remaining number of idle
 | 		.ReportBufferSize        = sizeof(USB_KeyboardReport_Data_t), | ||||||
|  *  milliseconds. This is separate to the IdleCount timer and is incremented and compared as the host may request  |  | ||||||
|  *  the current idle period via a Get Idle HID class request, thus its value must be preserved. |  | ||||||
|  */ |  | ||||||
| uint16_t IdleMSRemaining = 0; |  | ||||||
| 
 | 
 | ||||||
|  |         .IdleCount               = 500, | ||||||
|  |     }; | ||||||
| 
 | 
 | ||||||
| /** Main program entry point. This routine configures the hardware required by the application, then
 |  | ||||||
|  *  starts the scheduler to run the USB management task. |  | ||||||
|  */ |  | ||||||
| int main(void) | int main(void) | ||||||
| { | { | ||||||
| 	/* Disable watchdog if enabled by bootloader/fuses */ |     SetupHardware(); | ||||||
| 	MCUSR &= ~(1 << WDRF); |  | ||||||
| 	wdt_disable(); |  | ||||||
| 
 | 
 | ||||||
| 	/* Disable clock division */ |     LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
| 	clock_prescale_set(clock_div_1); |  | ||||||
|      |      | ||||||
| 	/* Hardware Initialization */ |     for (;;) | ||||||
| 	Joystick_Init(); |     { | ||||||
| 	LEDs_Init(); |         USB_HID_USBTask(&Keyboard_HID_Interface); | ||||||
| 	 |         USB_USBTask(); | ||||||
| 	/* Millisecond timer initialization, with output compare interrupt enabled for the idle timing */ |     } | ||||||
| 	OCR0A  = 0x7D; | } | ||||||
| 	TCCR0A = (1 << WGM01); | 
 | ||||||
| 	TCCR0B = ((1 << CS01) | (1 << CS00)); | void SetupHardware() | ||||||
| 	TIMSK0 = (1 << OCIE0A); | { | ||||||
| 
 |     /* Disable watchdog if enabled by bootloader/fuses */ | ||||||
| 	/* Indicate USB not ready */ |     MCUSR &= ~(1 << WDRF); | ||||||
| 	UpdateStatus(Status_USBNotReady); |     wdt_disable(); | ||||||
| 
 | 
 | ||||||
| 	/* Initialize Scheduler so that it can be used */ |     /* Disable clock division */ | ||||||
| 	Scheduler_Init(); |     clock_prescale_set(clock_div_1); | ||||||
| 
 | 
 | ||||||
| 	/* Initialize USB Subsystem */ |     /* Hardware Initialization */ | ||||||
| 	USB_Init(); |     Joystick_Init(); | ||||||
| 	 |     LEDs_Init(); | ||||||
| 	/* Scheduling - routine never returns, so put this last in the main function */ |     Buttons_Init(); | ||||||
| 	Scheduler_Start(); |     USB_Init(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** 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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Connect(void) | void EVENT_USB_Connect(void) | ||||||
| { | { | ||||||
| 	/* Start USB management task */ |     LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||||
| 	Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); |  | ||||||
| 
 |  | ||||||
| 	/* Indicate USB enumerating */ |  | ||||||
| 	UpdateStatus(Status_USBEnumerating); |  | ||||||
| 
 |  | ||||||
| 	/* Default to report protocol on connect */ |  | ||||||
| 	UsingReportProtocol = true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
 |  | ||||||
|  *  the status LEDs. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Disconnect(void) | void EVENT_USB_Disconnect(void) | ||||||
| { | { | ||||||
| 	/* Stop running keyboard reporting and USB management tasks */ |     LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
| 	Scheduler_SetTaskMode(USB_Keyboard_Report, 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 sets the current configuration
 |  | ||||||
|  *  of the USB device after enumeration, and configures the keyboard device endpoints. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_ConfigurationChanged(void) | void EVENT_USB_ConfigurationChanged(void) | ||||||
| { | { | ||||||
| 	/* Setup Keyboard Keycode Report Endpoint */ |     LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
| 	Endpoint_ConfigureEndpoint(KEYBOARD_EPNUM, EP_TYPE_INTERRUPT, |  | ||||||
| 		                       ENDPOINT_DIR_IN, KEYBOARD_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 | 
 | ||||||
| 	/* Setup Keyboard LED Report Endpoint */ |     if (!(USB_HID_ConfigureEndpoints(&Keyboard_HID_Interface))) | ||||||
| 	Endpoint_ConfigureEndpoint(KEYBOARD_LEDS_EPNUM, EP_TYPE_INTERRUPT, |       LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
| 		                       ENDPOINT_DIR_OUT, KEYBOARD_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 |  | ||||||
| 	/* Indicate USB connected and ready */ |  | ||||||
| 	UpdateStatus(Status_USBReady); |  | ||||||
| 
 |  | ||||||
| 	/* Start running keyboard reporting task */ |  | ||||||
| 	Scheduler_SetTaskMode(USB_Keyboard_Report, 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 HID commands, which are |  | ||||||
|  *  all issued via the control endpoint), so that they can be handled appropriately for the application. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_UnhandledControlPacket(void) | void EVENT_USB_UnhandledControlPacket(void) | ||||||
| { | { | ||||||
| 	/* Handle HID Class specific requests */ |     USB_HID_ProcessControlPacket(&Keyboard_HID_Interface); | ||||||
| 	switch (USB_ControlRequest.bRequest) |  | ||||||
| 	{ |  | ||||||
| 		case REQ_GetReport: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				USB_KeyboardReport_Data_t KeyboardReportData; |  | ||||||
| 
 |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 	 |  | ||||||
| 				/* Create the next keyboard report for transmission to the host */ |  | ||||||
| 				CreateKeyboardReport(&KeyboardReportData); |  | ||||||
| 
 |  | ||||||
| 				/* Write the report data to the control endpoint */ |  | ||||||
| 				Endpoint_Write_Control_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData)); |  | ||||||
| 				 |  | ||||||
| 				/* Finalize the stream transfer to send the last packet or clear the host abort */ |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 		 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetReport: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Wait until the LED report has been sent by the host */ |  | ||||||
| 				while (!(Endpoint_IsOUTReceived())); |  | ||||||
| 
 |  | ||||||
| 				/* Read in the LED report from the host */ |  | ||||||
| 				uint8_t LEDStatus = Endpoint_Read_Byte(); |  | ||||||
| 
 |  | ||||||
| 				/* Process the incoming LED report */ |  | ||||||
| 				ProcessLEDReport(LEDStatus); |  | ||||||
| 			 |  | ||||||
| 				/* Clear the endpoint data */ |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 
 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_GetProtocol: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Write the current protocol flag to the host */ |  | ||||||
| 				Endpoint_Write_Byte(UsingReportProtocol); |  | ||||||
| 				 |  | ||||||
| 				/* Send the flag to the host */ |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 
 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsOUTReceived())); |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetProtocol: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 
 |  | ||||||
| 				/* Set or clear the flag depending on what the host indicates that the current Protocol should be */ |  | ||||||
| 				UsingReportProtocol = (USB_ControlRequest.wValue != 0); |  | ||||||
| 
 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetIdle: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Get idle period in MSB */ |  | ||||||
| 				IdleCount = (USB_ControlRequest.wValue >> 8); |  | ||||||
| 				 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_GetIdle: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{		 |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Write the current idle duration to the host */ |  | ||||||
| 				Endpoint_Write_Byte(IdleCount); |  | ||||||
| 				 |  | ||||||
| 				/* Send the flag to the host */ |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 
 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsOUTReceived())); |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** ISR for the timer 0 compare vector. This ISR fires once each millisecond, and increments the
 | void EVENT_USB_StartOfFrame(void) | ||||||
|  *  scheduler elapsed idle period counter when the host has set an idle period. |  | ||||||
|  */ |  | ||||||
| ISR(TIMER0_COMPA_vect, ISR_BLOCK) |  | ||||||
| { | { | ||||||
| 	/* One millisecond has elapsed, decrement the idle time remaining counter if it has not already elapsed */ |     USB_HID_RegisterStartOfFrame(&Keyboard_HID_Interface); | ||||||
| 	if (IdleMSRemaining) |  | ||||||
| 	  IdleMSRemaining--; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Fills the given HID report data structure with the next HID report to send to the host.
 | uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData) | ||||||
|  * |  | ||||||
|  *  \param ReportData  Pointer to a HID report data structure to be filled |  | ||||||
|  */ |  | ||||||
| void CreateKeyboardReport(USB_KeyboardReport_Data_t* ReportData) |  | ||||||
| { | { | ||||||
| 	uint8_t JoyStatus_LCL = Joystick_GetStatus(); |     USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData; | ||||||
|      |      | ||||||
| 	/* Clear the report contents */ |     uint8_t JoyStatus_LCL    = Joystick_GetStatus(); | ||||||
| 	memset(ReportData, 0, sizeof(USB_KeyboardReport_Data_t)); |     uint8_t ButtonStatus_LCL = Buttons_GetStatus(); | ||||||
| 
 | 
 | ||||||
| 	if (JoyStatus_LCL & JOY_UP) |     if (JoyStatus_LCL & JOY_UP) | ||||||
| 	  ReportData->KeyCode[0] = 0x04; // A
 |       KeyboardReport->KeyCode[0] = 0x04; // A
 | ||||||
| 	else if (JoyStatus_LCL & JOY_DOWN) |     else if (JoyStatus_LCL & JOY_DOWN) | ||||||
| 	  ReportData->KeyCode[0] = 0x05; // B
 |       KeyboardReport->KeyCode[0] = 0x05; // B
 | ||||||
| 
 | 
 | ||||||
| 	if (JoyStatus_LCL & JOY_LEFT) |     if (JoyStatus_LCL & JOY_LEFT) | ||||||
| 	  ReportData->KeyCode[0] = 0x06; // C
 |       KeyboardReport->KeyCode[0] = 0x06; // C
 | ||||||
| 	else if (JoyStatus_LCL & JOY_RIGHT) |     else if (JoyStatus_LCL & JOY_RIGHT) | ||||||
| 	  ReportData->KeyCode[0] = 0x07; // D
 |       KeyboardReport->KeyCode[0] = 0x07; // D
 | ||||||
| 
 | 
 | ||||||
| 	if (JoyStatus_LCL & JOY_PRESS) |     if (JoyStatus_LCL & JOY_PRESS) | ||||||
| 	  ReportData->KeyCode[0] = 0x08; // E
 |       KeyboardReport->KeyCode[0] = 0x08; // E
 | ||||||
|  |        | ||||||
|  |     if (ButtonStatus_LCL & BUTTONS_BUTTON1) | ||||||
|  |       KeyboardReport->KeyCode[0] = 0x09; // F
 | ||||||
|  |        | ||||||
|  |     return sizeof(USB_KeyboardReport_Data_t); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Processes a received LED report, and updates the board LEDs states to match.
 | void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize) | ||||||
|  * |  | ||||||
|  *  \param LEDReport  LED status report from the host |  | ||||||
|  */ |  | ||||||
| void ProcessLEDReport(uint8_t LEDReport) |  | ||||||
| { | { | ||||||
| 	uint8_t LEDMask = LEDS_LED2; |     uint8_t  LEDMask   = LEDS_NO_LEDS; | ||||||
|  |     uint8_t* LEDReport = (uint8_t*)ReportData; | ||||||
| 
 | 
 | ||||||
| 	if (LEDReport & 0x01) // NUM Lock
 |     if (*LEDReport & 0x01) // NUM Lock
 | ||||||
| 	  LEDMask |= LEDS_LED1; |       LEDMask |= LEDS_LED1; | ||||||
|      |      | ||||||
| 	if (LEDReport & 0x02) // CAPS Lock
 |     if (*LEDReport & 0x02) // CAPS Lock
 | ||||||
| 	  LEDMask |= LEDS_LED3; |       LEDMask |= LEDS_LED3; | ||||||
| 
 | 
 | ||||||
| 	if (LEDReport & 0x04) // SCROLL Lock
 |     if (*LEDReport & 0x04) // SCROLL Lock
 | ||||||
| 	  LEDMask |= LEDS_LED4; |       LEDMask |= LEDS_LED4; | ||||||
|        |        | ||||||
| 	/* Set the status LEDs to the current Keyboard LED status */ |     LEDs_SetAllLEDs(LEDMask); | ||||||
| 	LEDs_SetAllLEDs(LEDMask); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Sends the next HID report to the host, via the keyboard data endpoint. */ |  | ||||||
| void SendNextReport(void) |  | ||||||
| { |  | ||||||
| 	static USB_KeyboardReport_Data_t PrevKeyboardReportData; |  | ||||||
| 	USB_KeyboardReport_Data_t        KeyboardReportData; |  | ||||||
| 	bool                             SendReport = true; |  | ||||||
| 	 |  | ||||||
| 	/* Create the next keyboard report for transmission to the host */ |  | ||||||
| 	CreateKeyboardReport(&KeyboardReportData); |  | ||||||
| 	 |  | ||||||
| 	/* Check to see if the report data has changed - if so a report MUST be sent */ |  | ||||||
| 	SendReport = (memcmp(&PrevKeyboardReportData, &KeyboardReportData, sizeof(USB_KeyboardReport_Data_t)) != 0); |  | ||||||
| 	 |  | ||||||
| 	/* Save the current report data for later comparison to check for changes */ |  | ||||||
| 	PrevKeyboardReportData = KeyboardReportData; |  | ||||||
| 	 |  | ||||||
| 	/* Check if the idle period is set and has elapsed */ |  | ||||||
| 	if ((IdleCount != HID_IDLE_CHANGESONLY) && (!(IdleMSRemaining))) |  | ||||||
| 	{ |  | ||||||
| 		/* Reset the idle time remaining counter, must multiply by 4 to get the duration in milliseconds */ |  | ||||||
| 		IdleMSRemaining = (IdleCount << 2); |  | ||||||
| 		 |  | ||||||
| 		/* Idle period is set and has elapsed, must send a report to the host */ |  | ||||||
| 		SendReport = true; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	/* Select the Keyboard Report Endpoint */ |  | ||||||
| 	Endpoint_SelectEndpoint(KEYBOARD_EPNUM); |  | ||||||
| 
 |  | ||||||
| 	/* Check if Keyboard Endpoint Ready for Read/Write and if we should send a new report */ |  | ||||||
| 	if (Endpoint_IsReadWriteAllowed() && SendReport) |  | ||||||
| 	{ |  | ||||||
| 		/* Write Keyboard Report Data */ |  | ||||||
| 		Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData)); |  | ||||||
| 		 |  | ||||||
| 		/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 		Endpoint_ClearIN(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Reads the next LED status report from the host from the LED data endpoint, if one has been sent. */ |  | ||||||
| void ReceiveNextReport(void) |  | ||||||
| { |  | ||||||
| 	/* Select the Keyboard LED Report Endpoint */ |  | ||||||
| 	Endpoint_SelectEndpoint(KEYBOARD_LEDS_EPNUM); |  | ||||||
| 
 |  | ||||||
| 	/* Check if Keyboard LED Endpoint contains a packet */ |  | ||||||
| 	if (Endpoint_IsOUTReceived()) |  | ||||||
| 	{ |  | ||||||
| 		/* Check to see if the packet contains data */ |  | ||||||
| 		if (Endpoint_IsReadWriteAllowed()) |  | ||||||
| 		{ |  | ||||||
| 			/* Read in the LED report from the host */ |  | ||||||
| 			uint8_t LEDReport = Endpoint_Read_Byte(); |  | ||||||
| 
 |  | ||||||
| 			/* Process the read LED report from the host */ |  | ||||||
| 			ProcessLEDReport(LEDReport); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		/* Handshake the OUT Endpoint - clear endpoint and ready for next report */ |  | ||||||
| 		Endpoint_ClearOUT(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** 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 Keyboard_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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Function to manage HID report generation and transmission to the host, when in report mode. */ |  | ||||||
| TASK(USB_Keyboard_Report) |  | ||||||
| { |  | ||||||
| 	/* Check if the USB system is connected to a host */ |  | ||||||
| 	if (USB_IsConnected) |  | ||||||
| 	{ |  | ||||||
| 		/* Send the next keypress report to the host */ |  | ||||||
| 		SendNextReport(); |  | ||||||
| 		 |  | ||||||
| 		/* Process the LED report sent from the host */ |  | ||||||
| 		ReceiveNextReport(); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -47,36 +47,12 @@ | |||||||
| 
 | 
 | ||||||
| 		#include "Descriptors.h" | 		#include "Descriptors.h" | ||||||
| 
 | 
 | ||||||
| 		#include <LUFA/Version.h>                    // Library Version Information | 		#include <LUFA/Version.h> | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>        // Simple scheduler for task management | 		#include <LUFA/Drivers/Board/Joystick.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>            // USB Functionality | 		#include <LUFA/Drivers/Board/LEDs.h> | ||||||
| 		#include <LUFA/Drivers/Board/Joystick.h>     // Joystick driver | 		#include <LUFA/Drivers/Board/Buttons.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>         // LEDs driver | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 
 | 		#include <LUFA/Drivers/USB/Class/Device/HID.h> | ||||||
| 	/* Macros: */ |  | ||||||
| 		/** Idle period indicating that reports should be sent only when the inputs have changed */ |  | ||||||
| 		#define HID_IDLE_CHANGESONLY   0 |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to get the next HID report from the device. */ |  | ||||||
| 		#define REQ_GetReport          0x01 |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to get the idle timeout period of the device. */ |  | ||||||
| 		#define REQ_GetIdle            0x02 |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to send the next HID report to the device. */ |  | ||||||
| 		#define REQ_SetReport          0x09 |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to set the idle timeout period of the device. */ |  | ||||||
| 		#define REQ_SetIdle            0x0A |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to get the current HID protocol in use, either report or boot. */ |  | ||||||
| 		#define REQ_GetProtocol        0x03 |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to set the current HID protocol in use, either report or boot. */ |  | ||||||
| 		#define REQ_SetProtocol        0x0B |  | ||||||
| 		 |  | ||||||
| 	/* Task Definitions: */ |  | ||||||
| 		TASK(USB_Keyboard_Report); |  | ||||||
| 
 | 
 | ||||||
| 	/* Type Defines: */ | 	/* Type Defines: */ | ||||||
| 		/** Type define for the keyboard HID report structure, for creating and sending HID reports to the host PC.
 | 		/** Type define for the keyboard HID report structure, for creating and sending HID reports to the host PC.
 | ||||||
| @ -89,25 +65,23 @@ | |||||||
| 			uint8_t KeyCode[6]; /**< Array of up to six simultaneous key codes of pressed keys */ | 			uint8_t KeyCode[6]; /**< Array of up to six simultaneous key codes of pressed keys */ | ||||||
| 		} USB_KeyboardReport_Data_t; | 		} USB_KeyboardReport_Data_t; | ||||||
| 			 | 			 | ||||||
| 	/* Enums: */ | 	/* Macros: */ | ||||||
| 		/** Enum for the possible status codes for passing to the UpdateStatus() function. */ | 		#define LEDMASK_USB_NOTREADY      LEDS_LED1 | ||||||
| 		enum Keyboard_StatusCodes_t | 		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3) | ||||||
| 		{ | 		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4) | ||||||
| 			Status_USBNotReady    = 0, /**< USB is not ready (disconnected from a USB host) */ | 		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3) | ||||||
| 			Status_USBEnumerating = 1, /**< USB interface is enumerating */ |  | ||||||
| 			Status_USBReady       = 2, /**< USB interface is connected and ready */ |  | ||||||
| 		}; |  | ||||||
| 		 | 		 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void SetupHardware(void); | ||||||
|  | 
 | ||||||
| 		void EVENT_USB_Connect(void); | 		void EVENT_USB_Connect(void); | ||||||
| 		void EVENT_USB_Disconnect(void); | 		void EVENT_USB_Disconnect(void); | ||||||
| 		void EVENT_USB_ConfigurationChanged(void); | 		void EVENT_USB_ConfigurationChanged(void); | ||||||
| 		void EVENT_USB_UnhandledControlPacket(void); | 		void EVENT_USB_UnhandledControlPacket(void); | ||||||
|  | 		void EVENT_USB_StartOfFrame(void); | ||||||
| 
 | 
 | ||||||
| 		void CreateKeyboardReport(USB_KeyboardReport_Data_t* ReportData); | 		uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData); | ||||||
| 		void ProcessLEDReport(uint8_t LEDReport); | 		void     CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, | ||||||
| 		void SendNextReport(void); | 		                                                   void* ReportData, uint16_t ReportSize); | ||||||
| 		void ReceiveNextReport(void); |  | ||||||
| 		void UpdateStatus(uint8_t CurrentStatus); |  | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -125,7 +125,6 @@ LUFA_PATH = ../../.. | |||||||
| # List C source files here. (C dependencies are automatically generated.)
 | # List C source files here. (C dependencies are automatically generated.)
 | ||||||
| SRC = $(TARGET).c                                                 \
 | SRC = $(TARGET).c                                                 \
 | ||||||
| 	  Descriptors.c                                               \
 | 	  Descriptors.c                                               \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | ||||||
| @ -136,7 +135,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/HID.c            \
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
| @ -183,7 +182,7 @@ CSTANDARD = -std=gnu99 | |||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for C sources
 | # Place -D or -U options here for C sources
 | ||||||
| CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | ||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY | ||||||
| CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | ||||||
| CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -38,30 +38,12 @@ | |||||||
| #define _DESCRIPTORS_H_ | #define _DESCRIPTORS_H_ | ||||||
| 
 | 
 | ||||||
| 	/* Includes: */ | 	/* Includes: */ | ||||||
| 		#include <LUFA/Drivers/USB/USB.h> |  | ||||||
| 
 |  | ||||||
| 		#include <avr/pgmspace.h> | 		#include <avr/pgmspace.h> | ||||||
| 
 | 
 | ||||||
|  | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
|  | 		#include <LUFA/Drivers/USB/Class/Device/HID.h> | ||||||
|  | 
 | ||||||
| 	/* Type Defines: */ | 	/* Type Defines: */ | ||||||
| 		/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
 |  | ||||||
| 		 *  specification for details on the structure elements. |  | ||||||
| 		 */ |  | ||||||
| 		typedef struct |  | ||||||
| 		{ |  | ||||||
| 			USB_Descriptor_Header_t               Header; |  | ||||||
| 				 |  | ||||||
| 			uint16_t                              HIDSpec; |  | ||||||
| 			uint8_t                               CountryCode; |  | ||||||
| 		 |  | ||||||
| 			uint8_t                               TotalReportDescriptors; |  | ||||||
| 
 |  | ||||||
| 			uint8_t                               HIDReportType; |  | ||||||
| 			uint16_t                              HIDReportLength; |  | ||||||
| 		} USB_Descriptor_HID_t; |  | ||||||
| 
 |  | ||||||
| 		/** Type define for the data type used to store HID report descriptor elements. */ |  | ||||||
| 		typedef uint8_t USB_Descriptor_HIDReport_Datatype_t; |  | ||||||
| 
 |  | ||||||
| 		/** Type define for the device configuration descriptor structure. This must be defined in the
 | 		/** 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 | 		 *  application code, as the configuration descriptor contains several sub-descriptors which | ||||||
| 		 *  vary between devices, and which describe the device's usage to the host. | 		 *  vary between devices, and which describe the device's usage to the host. | ||||||
| @ -91,12 +73,6 @@ | |||||||
| 		/** Size in bytes of each of the HID reporting IN and OUT endpoints. */ | 		/** Size in bytes of each of the HID reporting IN and OUT endpoints. */ | ||||||
| 		#define HID_EPSIZE                8 | 		#define HID_EPSIZE                8 | ||||||
| 
 | 
 | ||||||
| 		/** Descriptor header type value, to indicate a HID class HID descriptor. */ |  | ||||||
| 		#define DTYPE_HID                 0x21 |  | ||||||
| 		 |  | ||||||
| 		/** Descriptor header type value, to indicate a HID class HID report descriptor. */ |  | ||||||
| 		#define DTYPE_Report              0x22 |  | ||||||
| 
 |  | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
| 		uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) | 		uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) | ||||||
| 											ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); | 											ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); | ||||||
|  | |||||||
| @ -29,33 +29,51 @@ | |||||||
|   this software. |   this software. | ||||||
| */ | */ | ||||||
|   |   | ||||||
| /** \file
 |  | ||||||
|  * |  | ||||||
|  *  Main source file for the KeyboardMouse demo. This file contains the main tasks of the demo and |  | ||||||
|  *  is responsible for the initial application hardware configuration. |  | ||||||
|  */ |  | ||||||
|   |  | ||||||
| #include "KeyboardMouse.h" | #include "KeyboardMouse.h" | ||||||
| 
 | 
 | ||||||
| /* Scheduler Task List */ | USB_ClassInfo_HID_t Keyboard_HID_Interface = | ||||||
| TASK_LIST | 	{ | ||||||
| { | 		.InterfaceNumber         = 0, | ||||||
| 	{ .Task = USB_USBTask               , .TaskStatus = TASK_STOP }, |  | ||||||
| 	{ .Task = USB_Mouse                 , .TaskStatus = TASK_RUN  }, |  | ||||||
| 	{ .Task = USB_Keyboard              , .TaskStatus = TASK_RUN  }, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| /* Global Variables */ | 		.ReportINEndpointNumber  = KEYBOARD_IN_EPNUM, | ||||||
| /** Global structure to hold the current keyboard interface HID report, for transmission to the host */ | 		.ReportINEndpointSize    = HID_EPSIZE, | ||||||
| USB_KeyboardReport_Data_t KeyboardReportData; |  | ||||||
| 
 | 
 | ||||||
| /** Global structure to hold the current mouse interface HID report, for transmission to the host */ | 		.ReportOUTEndpointNumber = KEYBOARD_OUT_EPNUM, | ||||||
| USB_MouseReport_Data_t    MouseReportData; | 		.ReportOUTEndpointSize   = HID_EPSIZE, | ||||||
|  | 		 | ||||||
|  | 		.ReportBufferSize        = sizeof(USB_KeyboardReport_Data_t), | ||||||
|  | 
 | ||||||
|  | 		.IdleCount               = 500, | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | USB_ClassInfo_HID_t Mouse_HID_Interface = | ||||||
|  | 	{ | ||||||
|  | 		.InterfaceNumber         = 0, | ||||||
|  | 
 | ||||||
|  | 		.ReportINEndpointNumber  = MOUSE_IN_EPNUM, | ||||||
|  | 		.ReportINEndpointSize    = HID_EPSIZE, | ||||||
|  | 
 | ||||||
|  | 		.ReportBufferSize        = sizeof(USB_MouseReport_Data_t), | ||||||
|  | 
 | ||||||
|  | 		.ReportOUTEndpointNumber = 0, | ||||||
|  | 		.ReportOUTEndpointSize   = 0, | ||||||
|  | 	}; | ||||||
| 	 | 	 | ||||||
| /** Main program entry point. This routine configures the hardware required by the application, then
 |  | ||||||
|  *  starts the scheduler to run the USB management task. |  | ||||||
|  */ |  | ||||||
| int main(void) | int main(void) | ||||||
|  | { | ||||||
|  | 	SetupHardware(); | ||||||
|  | 
 | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | 
 | ||||||
|  | 	for (;;) | ||||||
|  | 	{ | ||||||
|  | 		USB_HID_USBTask(&Keyboard_HID_Interface); | ||||||
|  | 		USB_HID_USBTask(&Mouse_HID_Interface); | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupHardware() | ||||||
| { | { | ||||||
| 	/* Disable watchdog if enabled by bootloader/fuses */ | 	/* Disable watchdog if enabled by bootloader/fuses */ | ||||||
| 	MCUSR &= ~(1 << WDRF); | 	MCUSR &= ~(1 << WDRF); | ||||||
| @ -67,284 +85,111 @@ int main(void) | |||||||
| 	/* Hardware Initialization */ | 	/* Hardware Initialization */ | ||||||
| 	Joystick_Init(); | 	Joystick_Init(); | ||||||
| 	LEDs_Init(); | 	LEDs_Init(); | ||||||
| 	 |  | ||||||
| 	/* Indicate USB not ready */ |  | ||||||
| 	UpdateStatus(Status_USBNotReady); |  | ||||||
| 	 |  | ||||||
| 	/* Initialize Scheduler so that it can be used */ |  | ||||||
| 	Scheduler_Init(); |  | ||||||
| 
 |  | ||||||
| 	/* Initialize USB Subsystem */ |  | ||||||
| 	USB_Init();	 | 	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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Connect(void) | void EVENT_USB_Connect(void) | ||||||
| { | { | ||||||
| 	/* Start USB management task */ | 	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||||
| 	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 task. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Disconnect(void) | void EVENT_USB_Disconnect(void) | ||||||
| { | { | ||||||
| 	/* Stop running HID reporting and USB management tasks */ | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
| 	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 sets the current configuration
 |  | ||||||
|  *  of the USB device after enumeration, and configures the keyboard and mouse device endpoints. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_ConfigurationChanged(void) | void EVENT_USB_ConfigurationChanged(void) | ||||||
| { | { | ||||||
| 	/* Setup Keyboard Report Endpoint */ | 	LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
| 	Endpoint_ConfigureEndpoint(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, |  | ||||||
| 		                       ENDPOINT_DIR_IN, HID_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 | 
 | ||||||
| 	/* Setup Keyboard LED Report Endpoint */ | 	if (!(USB_HID_ConfigureEndpoints(&Keyboard_HID_Interface))) | ||||||
| 	Endpoint_ConfigureEndpoint(KEYBOARD_OUT_EPNUM, EP_TYPE_INTERRUPT, | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
| 		                       ENDPOINT_DIR_OUT, HID_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 	 | 	 | ||||||
| 	/* Setup Mouse Report Endpoint */ | 	if (!(USB_HID_ConfigureEndpoints(&Mouse_HID_Interface))) | ||||||
| 	Endpoint_ConfigureEndpoint(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
| 		                       ENDPOINT_DIR_IN, HID_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 |  | ||||||
| 	/* Indicate USB connected and ready */ |  | ||||||
| 	UpdateStatus(Status_USBReady); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** 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 HID commands, which are |  | ||||||
|  *  all issued via the control endpoint), so that they can be handled appropriately for the application. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_UnhandledControlPacket(void) | void EVENT_USB_UnhandledControlPacket(void) | ||||||
| { | { | ||||||
| 	uint8_t* ReportData; | 	USB_HID_ProcessControlPacket(&Keyboard_HID_Interface); | ||||||
| 	uint8_t  ReportSize; | 	USB_HID_ProcessControlPacket(&Mouse_HID_Interface); | ||||||
| 
 |  | ||||||
| 	/* Handle HID Class specific requests */ |  | ||||||
| 	switch (USB_ControlRequest.bRequest) |  | ||||||
| 	{ |  | ||||||
| 		case REQ_GetReport: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 	 |  | ||||||
| 				/* Determine if it is the mouse or the keyboard data that is being requested */ |  | ||||||
| 				if (!(USB_ControlRequest.wIndex)) |  | ||||||
| 				{ |  | ||||||
| 					ReportData = (uint8_t*)&KeyboardReportData; |  | ||||||
| 					ReportSize = sizeof(KeyboardReportData); |  | ||||||
| 				} |  | ||||||
| 				else |  | ||||||
| 				{ |  | ||||||
| 					ReportData = (uint8_t*)&MouseReportData; |  | ||||||
| 					ReportSize = sizeof(MouseReportData); |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				/* Write the report data to the control endpoint */ |  | ||||||
| 				Endpoint_Write_Control_Stream_LE(ReportData, ReportSize); |  | ||||||
| 
 |  | ||||||
| 				/* Clear the report data afterwards */ |  | ||||||
| 				memset(ReportData, 0, ReportSize); |  | ||||||
| 				 |  | ||||||
| 				/* Finalize the stream transfer to send the last packet or clear the host abort */ |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 		 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetReport: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Wait until the LED report has been sent by the host */ |  | ||||||
| 				while (!(Endpoint_IsOUTReceived())); |  | ||||||
| 
 |  | ||||||
| 				/* Read in the LED report from the host */ |  | ||||||
| 				uint8_t LEDStatus = Endpoint_Read_Byte(); |  | ||||||
| 				uint8_t LEDMask   = LEDS_LED2; |  | ||||||
| 				 |  | ||||||
| 				if (LEDStatus & 0x01) // NUM Lock
 |  | ||||||
| 				  LEDMask |= LEDS_LED1; |  | ||||||
| 				 |  | ||||||
| 				if (LEDStatus & 0x02) // CAPS Lock
 |  | ||||||
| 				  LEDMask |= LEDS_LED3; |  | ||||||
| 
 |  | ||||||
| 				if (LEDStatus & 0x04) // SCROLL Lock
 |  | ||||||
| 				  LEDMask |= LEDS_LED4; |  | ||||||
| 
 |  | ||||||
| 				/* Set the status LEDs to the current HID LED status */ |  | ||||||
| 				LEDs_SetAllLEDs(LEDMask); |  | ||||||
| 
 |  | ||||||
| 				/* Clear the endpoint data */ |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 
 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
 | void EVENT_USB_StartOfFrame(void) | ||||||
|  *  log to a serial port, or anything else that is suitable for status updates. |  | ||||||
|  * |  | ||||||
|  *  \param CurrentStatus  Current status of the system, from the KeyboardMouse_StatusCodes_t enum |  | ||||||
|  */ |  | ||||||
| void UpdateStatus(uint8_t CurrentStatus) |  | ||||||
| { | { | ||||||
| 	uint8_t LEDMask = LEDS_NO_LEDS; | 	USB_HID_RegisterStartOfFrame(&Keyboard_HID_Interface); | ||||||
| 	 | 	USB_HID_RegisterStartOfFrame(&Mouse_HID_Interface); | ||||||
| 	/* 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); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Keyboard task. This generates the next keyboard HID report for the host, and transmits it via the
 | uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData) | ||||||
|  *  keyboard IN endpoint when the host is ready for more data. Additionally, it processes host LED status |  | ||||||
|  *  reports sent to the device via the keyboard OUT reporting endpoint. |  | ||||||
|  */ |  | ||||||
| TASK(USB_Keyboard) |  | ||||||
| { | { | ||||||
| 	uint8_t JoyStatus_LCL = Joystick_GetStatus(); | 	uint8_t JoyStatus_LCL    = Joystick_GetStatus(); | ||||||
|  | 	uint8_t ButtonStatus_LCL = Buttons_GetStatus(); | ||||||
| 
 | 
 | ||||||
| 	/* Check if board button is not pressed, if so mouse mode enabled */ | 	if (HIDInterfaceInfo == &Keyboard_HID_Interface) | ||||||
| 	if (!(Buttons_GetStatus() & BUTTONS_BUTTON1)) |  | ||||||
| 	{ | 	{ | ||||||
|  | 		USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData; | ||||||
|  | 		 | ||||||
|  | 		/* If first board button not being held down, no keyboard report */ | ||||||
|  | 		if (!(ButtonStatus_LCL & BUTTONS_BUTTON1)) | ||||||
|  | 		  return 0; | ||||||
|  | 		 | ||||||
| 		if (JoyStatus_LCL & JOY_UP) | 		if (JoyStatus_LCL & JOY_UP) | ||||||
| 		  KeyboardReportData.KeyCode[0] = 0x04; // A
 | 		  KeyboardReport->KeyCode[0] = 0x04; // A
 | ||||||
| 		else if (JoyStatus_LCL & JOY_DOWN) | 		else if (JoyStatus_LCL & JOY_DOWN) | ||||||
| 		  KeyboardReportData.KeyCode[0] = 0x05; // B
 | 		  KeyboardReport->KeyCode[0] = 0x05; // B
 | ||||||
| 
 | 
 | ||||||
| 		if (JoyStatus_LCL & JOY_LEFT) | 		if (JoyStatus_LCL & JOY_LEFT) | ||||||
| 		  KeyboardReportData.KeyCode[0] = 0x06; // C
 | 		  KeyboardReport->KeyCode[0] = 0x06; // C
 | ||||||
| 		else if (JoyStatus_LCL & JOY_RIGHT) | 		else if (JoyStatus_LCL & JOY_RIGHT) | ||||||
| 		  KeyboardReportData.KeyCode[0] = 0x07; // D
 | 		  KeyboardReport->KeyCode[0] = 0x07; // D
 | ||||||
| 
 | 
 | ||||||
| 		if (JoyStatus_LCL & JOY_PRESS) | 		if (JoyStatus_LCL & JOY_PRESS) | ||||||
| 		  KeyboardReportData.KeyCode[0] = 0x08; // E
 | 		  KeyboardReport->KeyCode[0] = 0x08; // E
 | ||||||
|  | 		   | ||||||
|  | 		return sizeof(USB_KeyboardReport_Data_t); | ||||||
| 	} | 	} | ||||||
| 	 | 	else | ||||||
| 	/* Check if the USB system is connected to a host and report protocol mode is enabled */ |  | ||||||
| 	if (USB_IsConnected) |  | ||||||
| 	{ | 	{ | ||||||
| 		/* Select the Keyboard Report Endpoint */ | 		USB_MouseReport_Data_t* MouseReport = (USB_MouseReport_Data_t*)ReportData; | ||||||
| 		Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM); |  | ||||||
| 
 | 
 | ||||||
| 		/* Check if Keyboard Endpoint Ready for Read/Write */ | 		/* If first board button being held down, no mouse report */ | ||||||
| 		if (Endpoint_IsReadWriteAllowed()) | 		if (ButtonStatus_LCL & BUTTONS_BUTTON1) | ||||||
| 		{ | 		  return 0; | ||||||
| 			/* Write Keyboard Report Data */ |  | ||||||
| 			Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData)); |  | ||||||
| 		   | 		   | ||||||
| 			/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 			Endpoint_ClearIN(); |  | ||||||
| 
 |  | ||||||
| 			/* Clear the report data afterwards */ |  | ||||||
| 			memset(&KeyboardReportData, 0, sizeof(KeyboardReportData)); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		/* Select the Keyboard LED Report Endpoint */ |  | ||||||
| 		Endpoint_SelectEndpoint(KEYBOARD_OUT_EPNUM); |  | ||||||
| 
 |  | ||||||
| 		/* Check if Keyboard LED Endpoint Ready for Read/Write */ |  | ||||||
| 		if (Endpoint_IsReadWriteAllowed()) |  | ||||||
| 		{		 |  | ||||||
| 			/* Read in the LED report from the host */ |  | ||||||
| 			uint8_t LEDStatus = Endpoint_Read_Byte(); |  | ||||||
| 			uint8_t LEDMask   = LEDS_LED2; |  | ||||||
| 			 |  | ||||||
| 			if (LEDStatus & 0x01) // NUM Lock
 |  | ||||||
| 			  LEDMask |= LEDS_LED1; |  | ||||||
| 			 |  | ||||||
| 			if (LEDStatus & 0x02) // CAPS Lock
 |  | ||||||
| 			  LEDMask |= LEDS_LED3; |  | ||||||
| 
 |  | ||||||
| 			if (LEDStatus & 0x04) // SCROLL Lock
 |  | ||||||
| 			  LEDMask |= LEDS_LED4; |  | ||||||
| 
 |  | ||||||
| 			/* Set the status LEDs to the current Keyboard LED status */ |  | ||||||
| 			LEDs_SetAllLEDs(LEDMask); |  | ||||||
| 
 |  | ||||||
| 			/* Handshake the OUT Endpoint - clear endpoint and ready for next report */ |  | ||||||
| 			Endpoint_ClearOUT(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Mouse task. This generates the next mouse HID report for the host, and transmits it via the
 |  | ||||||
|  *  mouse IN endpoint when the host is ready for more data. |  | ||||||
|  */ |  | ||||||
| TASK(USB_Mouse) |  | ||||||
| { |  | ||||||
| 	uint8_t JoyStatus_LCL = Joystick_GetStatus(); |  | ||||||
| 
 |  | ||||||
| 	/* Check if board button is pressed, if so mouse mode enabled */ |  | ||||||
| 	if (Buttons_GetStatus() & BUTTONS_BUTTON1) |  | ||||||
| 	{ |  | ||||||
| 		if (JoyStatus_LCL & JOY_UP) | 		if (JoyStatus_LCL & JOY_UP) | ||||||
| 		  MouseReportData.Y =  1; | 		  MouseReport->Y = -1; | ||||||
| 		else if (JoyStatus_LCL & JOY_DOWN) | 		else if (JoyStatus_LCL & JOY_DOWN) | ||||||
| 		  MouseReportData.Y = -1; | 		  MouseReport->Y =  1; | ||||||
| 
 | 
 | ||||||
| 		if (JoyStatus_LCL & JOY_RIGHT) | 		if (JoyStatus_LCL & JOY_RIGHT) | ||||||
| 		  MouseReportData.X =  1; | 		  MouseReport->X =  1; | ||||||
| 		else if (JoyStatus_LCL & JOY_LEFT) | 		else if (JoyStatus_LCL & JOY_LEFT) | ||||||
| 		  MouseReportData.X = -1; | 		  MouseReport->X = -1; | ||||||
| 
 | 
 | ||||||
| 		if (JoyStatus_LCL & JOY_PRESS) | 		if (JoyStatus_LCL & JOY_PRESS) | ||||||
| 		  MouseReportData.Button  = (1 << 0); | 		  MouseReport->Button  = (1 << 0); | ||||||
| 	} |  | ||||||
| 		 | 		 | ||||||
| 	/* Check if the USB system is connected to a host and report protocol mode is enabled */ | 		return sizeof(USB_MouseReport_Data_t);		 | ||||||
| 	if (USB_IsConnected) | 	} | ||||||
| 	{ | } | ||||||
| 		/* Select the Mouse Report Endpoint */ | 
 | ||||||
| 		Endpoint_SelectEndpoint(MOUSE_IN_EPNUM); | void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize) | ||||||
| 
 | { | ||||||
| 		/* Check if Mouse Endpoint Ready for Read/Write */ | 	if (HIDInterfaceInfo == &Keyboard_HID_Interface) | ||||||
| 		if (Endpoint_IsReadWriteAllowed()) | 	{ | ||||||
| 		{ | 		uint8_t  LEDMask   = LEDS_NO_LEDS; | ||||||
| 			/* Write Mouse Report Data */ | 		uint8_t* LEDReport = (uint8_t*)ReportData; | ||||||
| 			Endpoint_Write_Stream_LE(&MouseReportData, sizeof(MouseReportData)); | 
 | ||||||
| 
 | 		if (*LEDReport & 0x01) // NUM Lock
 | ||||||
| 			/* Finalize the stream transfer to send the last packet */ | 		  LEDMask |= LEDS_LED1; | ||||||
| 			Endpoint_ClearIN(); | 		 | ||||||
| 
 | 		if (*LEDReport & 0x02) // CAPS Lock
 | ||||||
| 			/* Clear the report data afterwards */ | 		  LEDMask |= LEDS_LED3; | ||||||
| 			memset(&MouseReportData, 0, sizeof(MouseReportData)); | 
 | ||||||
| 		} | 		if (*LEDReport & 0x04) // SCROLL Lock
 | ||||||
|  | 		  LEDMask |= LEDS_LED4; | ||||||
|  | 		   | ||||||
|  | 		LEDs_SetAllLEDs(LEDMask); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -41,38 +41,18 @@ | |||||||
| 
 | 
 | ||||||
| 		#include "Descriptors.h" | 		#include "Descriptors.h" | ||||||
| 
 | 
 | ||||||
| 		#include <LUFA/Version.h>                    // Library Version Information | 		#include <LUFA/Version.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>            // USB Functionality | 		#include <LUFA/Drivers/Board/Joystick.h> | ||||||
| 		#include <LUFA/Drivers/Board/Joystick.h>     // Joystick driver | 		#include <LUFA/Drivers/Board/LEDs.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>         // LEDs driver | 		#include <LUFA/Drivers/Board/Buttons.h> | ||||||
| 		#include <LUFA/Drivers/Board/Buttons.h>      // Board Buttons driver | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>        // Simple scheduler for task management | 		#include <LUFA/Drivers/USB/Class/Device/HID.h> | ||||||
| 		 |  | ||||||
| 	/* Task Definitions: */ |  | ||||||
| 		TASK(USB_Keyboard); |  | ||||||
| 		TASK(USB_Mouse); |  | ||||||
| 
 |  | ||||||
| 	/* Enums: */ |  | ||||||
| 		/** Enum for the possible status codes for passing to the UpdateStatus() function. */ |  | ||||||
| 		enum KeyboardMouse_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 */ |  | ||||||
| 		}; |  | ||||||
| 
 | 
 | ||||||
| 	/* Macros: */ | 	/* Macros: */ | ||||||
| 		/** HID Class specific request to get the next HID report from the device. */ | 		#define LEDMASK_USB_NOTREADY      LEDS_LED1 | ||||||
| 		#define REQ_GetReport      0x01 | 		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3) | ||||||
| 
 | 		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4) | ||||||
| 		/** HID Class specific request to send the next HID report to the device. */ | 		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3) | ||||||
| 		#define REQ_SetReport      0x09 |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to get the current HID protocol in use, either report or boot. */ |  | ||||||
| 		#define REQ_GetProtocol    0x03 |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to set the current HID protocol in use, either report or boot. */ |  | ||||||
| 		#define REQ_SetProtocol    0x0B |  | ||||||
| 		 | 		 | ||||||
| 	/* Type Defines: */ | 	/* Type Defines: */ | ||||||
| 		/** Type define for the keyboard HID report structure, for creating and sending HID reports to the host PC.
 | 		/** Type define for the keyboard HID report structure, for creating and sending HID reports to the host PC.
 | ||||||
| @ -96,11 +76,16 @@ | |||||||
| 		} USB_MouseReport_Data_t; | 		} USB_MouseReport_Data_t; | ||||||
| 			 | 			 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void SetupHardware(void); | ||||||
|  | 
 | ||||||
| 		void EVENT_USB_Connect(void); | 		void EVENT_USB_Connect(void); | ||||||
| 		void EVENT_USB_Disconnect(void); | 		void EVENT_USB_Disconnect(void); | ||||||
| 		void EVENT_USB_ConfigurationChanged(void); | 		void EVENT_USB_ConfigurationChanged(void); | ||||||
| 		void EVENT_USB_UnhandledControlPacket(void); | 		void EVENT_USB_UnhandledControlPacket(void); | ||||||
|  | 		void EVENT_USB_StartOfFrame(void); | ||||||
| 
 | 
 | ||||||
| 		void UpdateStatus(uint8_t CurrentStatus); | 		uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData); | ||||||
|  | 		void     CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, | ||||||
|  | 		                                                   void* ReportData, uint16_t ReportSize); | ||||||
| 		 | 		 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -125,7 +125,6 @@ LUFA_PATH = ../../.. | |||||||
| # List C source files here. (C dependencies are automatically generated.)
 | # List C source files here. (C dependencies are automatically generated.)
 | ||||||
| SRC = $(TARGET).c                                                 \
 | SRC = $(TARGET).c                                                 \
 | ||||||
| 	  Descriptors.c                                               \
 | 	  Descriptors.c                                               \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | ||||||
| @ -136,7 +135,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/HID.c            \
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
| @ -183,7 +182,7 @@ CSTANDARD = -std=gnu99 | |||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for C sources
 | # Place -D or -U options here for C sources
 | ||||||
| CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | ||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY | ||||||
| CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | ||||||
| CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -183,7 +183,7 @@ CSTANDARD = -std=gnu99 | |||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for C sources
 | # Place -D or -U options here for C sources
 | ||||||
| CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | ||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY | ||||||
| CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | ||||||
| CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ | |||||||
|  *  \param BlockAddress  Data block starting address for the write sequence |  *  \param BlockAddress  Data block starting address for the write sequence | ||||||
|  *  \param TotalBlocks   Number of blocks of data to write |  *  \param TotalBlocks   Number of blocks of data to write | ||||||
|  */ |  */ | ||||||
| void DataflashManager_WriteBlocks(const uint32_t BlockAddress, uint16_t TotalBlocks) | void DataflashManager_WriteBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks) | ||||||
| { | { | ||||||
| 	uint16_t CurrDFPage          = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE); | 	uint16_t CurrDFPage          = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE); | ||||||
| 	uint16_t CurrDFPageByte      = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE); | 	uint16_t CurrDFPageByte      = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE); | ||||||
| @ -142,7 +142,7 @@ void DataflashManager_WriteBlocks(const uint32_t BlockAddress, uint16_t TotalBlo | |||||||
| 			BytesInBlockDiv16++; | 			BytesInBlockDiv16++; | ||||||
| 
 | 
 | ||||||
| 			/* Check if the current command is being aborted by the host */ | 			/* Check if the current command is being aborted by the host */ | ||||||
| 			if (IsMassStoreReset) | 			if (MSInterfaceInfo->IsMassStoreReset) | ||||||
| 			  return;			 | 			  return;			 | ||||||
| 		} | 		} | ||||||
| 			 | 			 | ||||||
| @ -171,7 +171,7 @@ void DataflashManager_WriteBlocks(const uint32_t BlockAddress, uint16_t TotalBlo | |||||||
|  *  \param BlockAddress  Data block starting address for the read sequence |  *  \param BlockAddress  Data block starting address for the read sequence | ||||||
|  *  \param TotalBlocks   Number of blocks of data to read |  *  \param TotalBlocks   Number of blocks of data to read | ||||||
|  */ |  */ | ||||||
| void DataflashManager_ReadBlocks(const uint32_t BlockAddress, uint16_t TotalBlocks) | void DataflashManager_ReadBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks) | ||||||
| { | { | ||||||
| 	uint16_t CurrDFPage          = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE); | 	uint16_t CurrDFPage          = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE); | ||||||
| 	uint16_t CurrDFPageByte      = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE); | 	uint16_t CurrDFPageByte      = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE); | ||||||
| @ -250,7 +250,7 @@ void DataflashManager_ReadBlocks(const uint32_t BlockAddress, uint16_t TotalBloc | |||||||
| 			BytesInBlockDiv16++; | 			BytesInBlockDiv16++; | ||||||
| 
 | 
 | ||||||
| 			/* Check if the current command is being aborted by the host */ | 			/* Check if the current command is being aborted by the host */ | ||||||
| 			if (IsMassStoreReset) | 			if (MSInterfaceInfo->IsMassStoreReset) | ||||||
| 			  return; | 			  return; | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| @ -342,10 +342,6 @@ void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t Tota | |||||||
| 
 | 
 | ||||||
| 			/* Increment the block 16 byte block counter */ | 			/* Increment the block 16 byte block counter */ | ||||||
| 			BytesInBlockDiv16++;		 | 			BytesInBlockDiv16++;		 | ||||||
| 
 |  | ||||||
| 			/* Check if the current command is being aborted by the host */ |  | ||||||
| 			if (IsMassStoreReset) |  | ||||||
| 			  return;			 |  | ||||||
| 		} | 		} | ||||||
| 			 | 			 | ||||||
| 		/* Decrement the blocks remaining counter and reset the sub block counter */ | 		/* Decrement the blocks remaining counter and reset the sub block counter */ | ||||||
| @ -421,10 +417,6 @@ void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t Total | |||||||
| 			 | 			 | ||||||
| 			/* Increment the block 16 byte block counter */ | 			/* Increment the block 16 byte block counter */ | ||||||
| 			BytesInBlockDiv16++; | 			BytesInBlockDiv16++; | ||||||
| 
 |  | ||||||
| 			/* Check if the current command is being aborted by the host */ |  | ||||||
| 			if (IsMassStoreReset) |  | ||||||
| 			  return; |  | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		/* Decrement the blocks remaining counter */ | 		/* Decrement the blocks remaining counter */ | ||||||
|  | |||||||
| @ -64,8 +64,8 @@ | |||||||
| 		#define VIRTUAL_MEMORY_BLOCKS               (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE) | 		#define VIRTUAL_MEMORY_BLOCKS               (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE) | ||||||
| 		 | 		 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
| 		void DataflashManager_WriteBlocks(const uint32_t BlockAddress, uint16_t TotalBlocks); | 		void DataflashManager_WriteBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks); | ||||||
| 		void DataflashManager_ReadBlocks(const uint32_t BlockAddress, uint16_t TotalBlocks); | 		void DataflashManager_ReadBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks); | ||||||
| 		void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, | 		void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, | ||||||
| 		                                      uint8_t* BufferPtr) ATTR_NON_NULL_PTR_ARG(3); | 		                                      uint8_t* BufferPtr) ATTR_NON_NULL_PTR_ARG(3); | ||||||
| 		void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, | 		void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, | ||||||
|  | |||||||
| @ -84,37 +84,37 @@ SCSI_Request_Sense_Response_t SenseData = | |||||||
|  *  to the appropriate SCSI command handling routine if the issued command is supported by the device, else it returns |  *  to the appropriate SCSI command handling routine if the issued command is supported by the device, else it returns | ||||||
|  *  a command failure due to a ILLEGAL REQUEST. |  *  a command failure due to a ILLEGAL REQUEST. | ||||||
|  */ |  */ | ||||||
| void SCSI_DecodeSCSICommand(void) | bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_t* MSInterfaceInfo) | ||||||
| { | { | ||||||
| 	bool CommandSuccess = false; | 	bool CommandSuccess = false; | ||||||
| 
 | 
 | ||||||
| 	/* Run the appropriate SCSI command hander function based on the passed command */ | 	/* Run the appropriate SCSI command hander function based on the passed command */ | ||||||
| 	switch (CommandBlock.SCSICommandData[0]) | 	switch (MSInterfaceInfo->CommandBlock.SCSICommandData[0]) | ||||||
| 	{ | 	{ | ||||||
| 		case SCSI_CMD_INQUIRY: | 		case SCSI_CMD_INQUIRY: | ||||||
| 			CommandSuccess = SCSI_Command_Inquiry();			 | 			CommandSuccess = SCSI_Command_Inquiry(MSInterfaceInfo);			 | ||||||
| 			break; | 			break; | ||||||
| 		case SCSI_CMD_REQUEST_SENSE: | 		case SCSI_CMD_REQUEST_SENSE: | ||||||
| 			CommandSuccess = SCSI_Command_Request_Sense(); | 			CommandSuccess = SCSI_Command_Request_Sense(MSInterfaceInfo); | ||||||
| 			break; | 			break; | ||||||
| 		case SCSI_CMD_READ_CAPACITY_10: | 		case SCSI_CMD_READ_CAPACITY_10: | ||||||
| 			CommandSuccess = SCSI_Command_Read_Capacity_10();			 | 			CommandSuccess = SCSI_Command_Read_Capacity_10(MSInterfaceInfo);			 | ||||||
| 			break; | 			break; | ||||||
| 		case SCSI_CMD_SEND_DIAGNOSTIC: | 		case SCSI_CMD_SEND_DIAGNOSTIC: | ||||||
| 			CommandSuccess = SCSI_Command_Send_Diagnostic(); | 			CommandSuccess = SCSI_Command_Send_Diagnostic(MSInterfaceInfo); | ||||||
| 			break; | 			break; | ||||||
| 		case SCSI_CMD_WRITE_10: | 		case SCSI_CMD_WRITE_10: | ||||||
| 			CommandSuccess = SCSI_Command_ReadWrite_10(DATA_WRITE); | 			CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_WRITE); | ||||||
| 			break; | 			break; | ||||||
| 		case SCSI_CMD_READ_10: | 		case SCSI_CMD_READ_10: | ||||||
| 			CommandSuccess = SCSI_Command_ReadWrite_10(DATA_READ); | 			CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ); | ||||||
| 			break; | 			break; | ||||||
| 		case SCSI_CMD_TEST_UNIT_READY: | 		case SCSI_CMD_TEST_UNIT_READY: | ||||||
| 		case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: | 		case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: | ||||||
| 		case SCSI_CMD_VERIFY_10: | 		case SCSI_CMD_VERIFY_10: | ||||||
| 			/* These commands should just succeed, no handling required */ | 			/* These commands should just succeed, no handling required */ | ||||||
| 			CommandSuccess = true; | 			CommandSuccess = true; | ||||||
| 			CommandBlock.DataTransferLength = 0; | 			MSInterfaceInfo->CommandBlock.DataTransferLength = 0; | ||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			/* Update the SENSE key to reflect the invalid command */ | 			/* Update the SENSE key to reflect the invalid command */ | ||||||
| @ -127,18 +127,14 @@ void SCSI_DecodeSCSICommand(void) | |||||||
| 	/* Check if command was successfully processed */ | 	/* Check if command was successfully processed */ | ||||||
| 	if (CommandSuccess) | 	if (CommandSuccess) | ||||||
| 	{ | 	{ | ||||||
| 		/* Command succeeded - set the CSW status and update the SENSE key */ |  | ||||||
| 		CommandStatus.Status = Command_Pass; |  | ||||||
| 		 |  | ||||||
| 		SCSI_SET_SENSE(SCSI_SENSE_KEY_GOOD, | 		SCSI_SET_SENSE(SCSI_SENSE_KEY_GOOD, | ||||||
| 		               SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, | 		               SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, | ||||||
| 		               SCSI_ASENSEQ_NO_QUALIFIER); | 		               SCSI_ASENSEQ_NO_QUALIFIER); | ||||||
|  | 		 | ||||||
|  | 		return true; | ||||||
| 	} | 	} | ||||||
| 	else | 
 | ||||||
| 	{ | 	return false; | ||||||
| 		/* Command failed - set the CSW status - failed command function updates the SENSE key */ |  | ||||||
| 		CommandStatus.Status = Command_Fail; |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Command processing for an issued SCSI INQUIRY command. This command returns information about the device's features
 | /** Command processing for an issued SCSI INQUIRY command. This command returns information about the device's features
 | ||||||
| @ -146,16 +142,16 @@ void SCSI_DecodeSCSICommand(void) | |||||||
|  * |  * | ||||||
|  *  \return Boolean true if the command completed successfully, false otherwise. |  *  \return Boolean true if the command completed successfully, false otherwise. | ||||||
|  */ |  */ | ||||||
| static bool SCSI_Command_Inquiry(void) | static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_t* MSInterfaceInfo) | ||||||
| { | { | ||||||
| 	uint16_t AllocationLength  = (((uint16_t)CommandBlock.SCSICommandData[3] << 8) | | 	uint16_t AllocationLength  = (((uint16_t)MSInterfaceInfo->CommandBlock.SCSICommandData[3] << 8) | | ||||||
| 	                                         CommandBlock.SCSICommandData[4]); | 	                                         MSInterfaceInfo->CommandBlock.SCSICommandData[4]); | ||||||
| 	uint16_t BytesTransferred  = (AllocationLength < sizeof(InquiryData))? AllocationLength : | 	uint16_t BytesTransferred  = (AllocationLength < sizeof(InquiryData))? AllocationLength : | ||||||
| 	                                                                       sizeof(InquiryData); | 	                                                                       sizeof(InquiryData); | ||||||
| 
 | 
 | ||||||
| 	/* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */ | 	/* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */ | ||||||
| 	if ((CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) || | 	if ((MSInterfaceInfo->CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) || | ||||||
| 	     CommandBlock.SCSICommandData[2]) | 	     MSInterfaceInfo->CommandBlock.SCSICommandData[2]) | ||||||
| 	{ | 	{ | ||||||
| 		/* Optional but unsupported bits set - update the SENSE key and fail the request */ | 		/* Optional but unsupported bits set - update the SENSE key and fail the request */ | ||||||
| 		SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, | 		SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, | ||||||
| @ -165,19 +161,18 @@ static bool SCSI_Command_Inquiry(void) | |||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	/* Write the INQUIRY data to the endpoint */ | 	Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, NO_STREAM_CALLBACK); | ||||||
| 	Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, StreamCallback_AbortOnMassStoreReset); |  | ||||||
| 
 | 
 | ||||||
| 	uint8_t PadBytes[AllocationLength - BytesTransferred]; | 	uint8_t PadBytes[AllocationLength - BytesTransferred]; | ||||||
| 	 | 	 | ||||||
| 	/* Pad out remaining bytes with 0x00 */ | 	/* Pad out remaining bytes with 0x00 */ | ||||||
| 	Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), StreamCallback_AbortOnMassStoreReset); | 	Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK); | ||||||
| 
 | 
 | ||||||
| 	/* Finalize the stream transfer to send the last packet */ | 	/* Finalize the stream transfer to send the last packet */ | ||||||
| 	Endpoint_ClearIN(); | 	Endpoint_ClearIN(); | ||||||
| 
 | 
 | ||||||
| 	/* Succeed the command and update the bytes transferred counter */ | 	/* Succeed the command and update the bytes transferred counter */ | ||||||
| 	CommandBlock.DataTransferLength -= BytesTransferred; | 	MSInterfaceInfo->CommandBlock.DataTransferLength -= BytesTransferred; | ||||||
| 	 | 	 | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| @ -187,24 +182,19 @@ static bool SCSI_Command_Inquiry(void) | |||||||
|  * |  * | ||||||
|  *  \return Boolean true if the command completed successfully, false otherwise. |  *  \return Boolean true if the command completed successfully, false otherwise. | ||||||
|  */ |  */ | ||||||
| static bool SCSI_Command_Request_Sense(void) | static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_t* MSInterfaceInfo) | ||||||
| { | { | ||||||
| 	uint8_t  AllocationLength = CommandBlock.SCSICommandData[4]; | 	uint8_t  AllocationLength = MSInterfaceInfo->CommandBlock.SCSICommandData[4]; | ||||||
| 	uint8_t  BytesTransferred = (AllocationLength < sizeof(SenseData))? AllocationLength : sizeof(SenseData); | 	uint8_t  BytesTransferred = (AllocationLength < sizeof(SenseData))? AllocationLength : sizeof(SenseData); | ||||||
| 	 | 	 | ||||||
| 	/* Send the SENSE data - this indicates to the host the status of the last command */ |  | ||||||
| 	Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, StreamCallback_AbortOnMassStoreReset); |  | ||||||
| 	 |  | ||||||
| 	uint8_t PadBytes[AllocationLength - BytesTransferred]; | 	uint8_t PadBytes[AllocationLength - BytesTransferred]; | ||||||
| 
 | 
 | ||||||
| 	/* Pad out remaining bytes with 0x00 */ | 	Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, NO_STREAM_CALLBACK); | ||||||
| 	Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), StreamCallback_AbortOnMassStoreReset); | 	Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK); | ||||||
| 
 |  | ||||||
| 	/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 	Endpoint_ClearIN(); | 	Endpoint_ClearIN(); | ||||||
| 
 | 
 | ||||||
| 	/* Succeed the command and update the bytes transferred counter */ | 	/* Succeed the command and update the bytes transferred counter */ | ||||||
| 	CommandBlock.DataTransferLength -= BytesTransferred; | 	MSInterfaceInfo->CommandBlock.DataTransferLength -= BytesTransferred; | ||||||
| 
 | 
 | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| @ -214,23 +204,17 @@ static bool SCSI_Command_Request_Sense(void) | |||||||
|  * |  * | ||||||
|  *  \return Boolean true if the command completed successfully, false otherwise. |  *  \return Boolean true if the command completed successfully, false otherwise. | ||||||
|  */ |  */ | ||||||
| static bool SCSI_Command_Read_Capacity_10(void) | static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_t* MSInterfaceInfo) | ||||||
| { | { | ||||||
| 	/* Send the total number of logical blocks in the current LUN */ | 	uint32_t TotalLUNs      = (LUN_MEDIA_BLOCKS - 1); | ||||||
| 	Endpoint_Write_DWord_BE(LUN_MEDIA_BLOCKS - 1); | 	uint32_t MediaBlockSize = VIRTUAL_MEMORY_BLOCK_SIZE; | ||||||
| 
 | 
 | ||||||
| 	/* Send the logical block size of the device (must be 512 bytes) */ | 	Endpoint_Write_Stream_BE(&TotalLUNs, sizeof(TotalLUNs), NO_STREAM_CALLBACK); | ||||||
| 	Endpoint_Write_DWord_BE(VIRTUAL_MEMORY_BLOCK_SIZE); | 	Endpoint_Write_Stream_BE(&MediaBlockSize, sizeof(MediaBlockSize), NO_STREAM_CALLBACK); | ||||||
| 
 |  | ||||||
| 	/* Check if the current command is being aborted by the host */ |  | ||||||
| 	if (IsMassStoreReset) |  | ||||||
| 	  return false; |  | ||||||
| 
 |  | ||||||
| 	/* Send the endpoint data packet to the host */ |  | ||||||
| 	Endpoint_ClearIN(); | 	Endpoint_ClearIN(); | ||||||
| 	 | 	 | ||||||
| 	/* Succeed the command and update the bytes transferred counter */ | 	/* Succeed the command and update the bytes transferred counter */ | ||||||
| 	CommandBlock.DataTransferLength -= 8; | 	MSInterfaceInfo->CommandBlock.DataTransferLength -= 8; | ||||||
| 	 | 	 | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| @ -241,12 +225,12 @@ static bool SCSI_Command_Read_Capacity_10(void) | |||||||
|  * |  * | ||||||
|  *  \return Boolean true if the command completed successfully, false otherwise. |  *  \return Boolean true if the command completed successfully, false otherwise. | ||||||
|  */ |  */ | ||||||
| static bool SCSI_Command_Send_Diagnostic(void) | static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_t* MSInterfaceInfo) | ||||||
| { | { | ||||||
| 	uint8_t ReturnByte; | 	uint8_t ReturnByte; | ||||||
| 
 | 
 | ||||||
| 	/* Check to see if the SELF TEST bit is not set */ | 	/* Check to see if the SELF TEST bit is not set */ | ||||||
| 	if (!(CommandBlock.SCSICommandData[1] & (1 << 2))) | 	if (!(MSInterfaceInfo->CommandBlock.SCSICommandData[1] & (1 << 2))) | ||||||
| 	{ | 	{ | ||||||
| 		/* Only self-test supported - update SENSE key and fail the command */ | 		/* Only self-test supported - update SENSE key and fail the command */ | ||||||
| 		SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, | 		SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, | ||||||
| @ -293,7 +277,7 @@ static bool SCSI_Command_Send_Diagnostic(void) | |||||||
| 	#endif | 	#endif | ||||||
| 	 | 	 | ||||||
| 	/* Succeed the command and update the bytes transferred counter */ | 	/* Succeed the command and update the bytes transferred counter */ | ||||||
| 	CommandBlock.DataTransferLength = 0; | 	MSInterfaceInfo->CommandBlock.DataTransferLength = 0; | ||||||
| 	 | 	 | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| @ -306,20 +290,20 @@ static bool SCSI_Command_Send_Diagnostic(void) | |||||||
|  * |  * | ||||||
|  *  \return Boolean true if the command completed successfully, false otherwise. |  *  \return Boolean true if the command completed successfully, false otherwise. | ||||||
|  */ |  */ | ||||||
| static bool SCSI_Command_ReadWrite_10(const bool IsDataRead) | static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_t* MSInterfaceInfo, const bool IsDataRead) | ||||||
| { | { | ||||||
| 	uint32_t BlockAddress; | 	uint32_t BlockAddress; | ||||||
| 	uint16_t TotalBlocks; | 	uint16_t TotalBlocks; | ||||||
| 	 | 	 | ||||||
| 	/* Load in the 32-bit block address (SCSI uses big-endian, so have to do it byte-by-byte) */ | 	/* Load in the 32-bit block address (SCSI uses big-endian, so have to do it byte-by-byte) */ | ||||||
| 	((uint8_t*)&BlockAddress)[3] = CommandBlock.SCSICommandData[2]; | 	((uint8_t*)&BlockAddress)[3] = MSInterfaceInfo->CommandBlock.SCSICommandData[2]; | ||||||
| 	((uint8_t*)&BlockAddress)[2] = CommandBlock.SCSICommandData[3]; | 	((uint8_t*)&BlockAddress)[2] = MSInterfaceInfo->CommandBlock.SCSICommandData[3]; | ||||||
| 	((uint8_t*)&BlockAddress)[1] = CommandBlock.SCSICommandData[4]; | 	((uint8_t*)&BlockAddress)[1] = MSInterfaceInfo->CommandBlock.SCSICommandData[4]; | ||||||
| 	((uint8_t*)&BlockAddress)[0] = CommandBlock.SCSICommandData[5]; | 	((uint8_t*)&BlockAddress)[0] = MSInterfaceInfo->CommandBlock.SCSICommandData[5]; | ||||||
| 
 | 
 | ||||||
| 	/* Load in the 16-bit total blocks (SCSI uses big-endian, so have to do it byte-by-byte) */ | 	/* Load in the 16-bit total blocks (SCSI uses big-endian, so have to do it byte-by-byte) */ | ||||||
| 	((uint8_t*)&TotalBlocks)[1]  = CommandBlock.SCSICommandData[7]; | 	((uint8_t*)&TotalBlocks)[1]  = MSInterfaceInfo->CommandBlock.SCSICommandData[7]; | ||||||
| 	((uint8_t*)&TotalBlocks)[0]  = CommandBlock.SCSICommandData[8]; | 	((uint8_t*)&TotalBlocks)[0]  = MSInterfaceInfo->CommandBlock.SCSICommandData[8]; | ||||||
| 	 | 	 | ||||||
| 	/* Check if the block address is outside the maximum allowable value for the LUN */ | 	/* Check if the block address is outside the maximum allowable value for the LUN */ | ||||||
| 	if (BlockAddress >= LUN_MEDIA_BLOCKS) | 	if (BlockAddress >= LUN_MEDIA_BLOCKS) | ||||||
| @ -334,17 +318,17 @@ static bool SCSI_Command_ReadWrite_10(const bool IsDataRead) | |||||||
| 
 | 
 | ||||||
| 	#if (TOTAL_LUNS > 1) | 	#if (TOTAL_LUNS > 1) | ||||||
| 	/* Adjust the given block address to the real media address based on the selected LUN */ | 	/* Adjust the given block address to the real media address based on the selected LUN */ | ||||||
| 	BlockAddress += ((uint32_t)CommandBlock.LUN * LUN_MEDIA_BLOCKS); | 	BlockAddress += ((uint32_t)MSInterfaceInfo->CommandBlock.LUN * LUN_MEDIA_BLOCKS); | ||||||
| 	#endif | 	#endif | ||||||
| 	 | 	 | ||||||
| 	/* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */ | 	/* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */ | ||||||
| 	if (IsDataRead == DATA_READ) | 	if (IsDataRead == DATA_READ) | ||||||
| 	  DataflashManager_ReadBlocks(BlockAddress, TotalBlocks); | 	  DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks); | ||||||
| 	else | 	else | ||||||
| 	  DataflashManager_WriteBlocks(BlockAddress, TotalBlocks); | 	  DataflashManager_WriteBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks); | ||||||
| 
 | 
 | ||||||
| 	/* Update the bytes transferred counter and succeed the command */ | 	/* Update the bytes transferred counter and succeed the command */ | ||||||
| 	CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE); | 	MSInterfaceInfo->CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE); | ||||||
| 	 | 	 | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  | |||||||
| @ -40,9 +40,8 @@ | |||||||
| 		#include <avr/io.h> | 		#include <avr/io.h> | ||||||
| 		#include <avr/pgmspace.h> | 		#include <avr/pgmspace.h> | ||||||
| 
 | 
 | ||||||
| 		#include <LUFA/Common/Common.h>              // Function Attribute, Atomic, Debug and ISR Macros | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>            // USB Functionality | 		#include <LUFA/Drivers/USB/Class/Device/MassStorage.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>         // LEDs driver |  | ||||||
| 
 | 
 | ||||||
| 		#include "MassStorage.h" | 		#include "MassStorage.h" | ||||||
| 		#include "Descriptors.h" | 		#include "Descriptors.h" | ||||||
| @ -63,16 +62,16 @@ | |||||||
| 		                                                   SenseData.AdditionalSenseQualifier = aqual; }MACROE | 		                                                   SenseData.AdditionalSenseQualifier = aqual; }MACROE | ||||||
| 
 | 
 | ||||||
| 		/** Macro for the SCSI_Command_ReadWrite_10() function, to indicate that data is to be read from the storage medium. */ | 		/** Macro for the SCSI_Command_ReadWrite_10() function, to indicate that data is to be read from the storage medium. */ | ||||||
| 		#define DATA_READ      true | 		#define DATA_READ           true | ||||||
| 
 | 
 | ||||||
| 		/** Macro for the SCSI_Command_ReadWrite_10() function, to indicate that data is to be written to the storage medium. */ | 		/** Macro for the SCSI_Command_ReadWrite_10() function, to indicate that data is to be written to the storage medium. */ | ||||||
| 		#define DATA_WRITE     false | 		#define DATA_WRITE          false | ||||||
| 
 | 
 | ||||||
| 		/** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a Block Media device. */ | 		/** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a Block Media device. */ | ||||||
| 		#define DEVICE_TYPE_BLOCK 0x00 | 		#define DEVICE_TYPE_BLOCK   0x00 | ||||||
| 		 | 		 | ||||||
| 		/** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a CD-ROM device. */ | 		/** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a CD-ROM device. */ | ||||||
| 		#define DEVICE_TYPE_CDROM 0x05 | 		#define DEVICE_TYPE_CDROM   0x05 | ||||||
| 
 | 
 | ||||||
| 	/* Type Defines: */ | 	/* Type Defines: */ | ||||||
| 		/** Type define for a SCSI response structure to a SCSI INQUIRY command. For details of the
 | 		/** Type define for a SCSI response structure to a SCSI INQUIRY command. For details of the
 | ||||||
| @ -136,14 +135,14 @@ | |||||||
| 		} SCSI_Request_Sense_Response_t; | 		} SCSI_Request_Sense_Response_t; | ||||||
| 		 | 		 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
| 		void SCSI_DecodeSCSICommand(void); | 		bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_t* MSInterfaceInfo); | ||||||
| 		 | 		 | ||||||
| 		#if defined(INCLUDE_FROM_SCSI_C) | 		#if defined(INCLUDE_FROM_SCSI_C) | ||||||
| 			static bool SCSI_Command_Inquiry(void); | 			static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_t* MSInterfaceInfo); | ||||||
| 			static bool SCSI_Command_Request_Sense(void); | 			static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_t* MSInterfaceInfo); | ||||||
| 			static bool SCSI_Command_Read_Capacity_10(void); | 			static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_t* MSInterfaceInfo); | ||||||
| 			static bool SCSI_Command_Send_Diagnostic(void); | 			static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_t* MSInterfaceInfo); | ||||||
| 			static bool SCSI_Command_ReadWrite_10(const bool IsDataRead); | 			static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_t* MSInterfaceInfo, const bool IsDataRead); | ||||||
| 		#endif | 		#endif | ||||||
| 		 | 		 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -28,35 +28,35 @@ | |||||||
|   this software. |   this software. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| /** \file
 |  | ||||||
|  * |  | ||||||
|  *  Main source file for the Mass Storage demo. This file contains the main tasks of the demo and |  | ||||||
|  *  is responsible for the initial application hardware configuration. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #define  INCLUDE_FROM_MASSSTORAGE_C |  | ||||||
| #include "MassStorage.h" | #include "MassStorage.h" | ||||||
| 
 | 
 | ||||||
| /* Scheduler Task List */ | USB_ClassInfo_MS_t Disk_MS_Interface = | ||||||
| TASK_LIST | 	{ | ||||||
| { | 		.InterfaceNumber        = 0, | ||||||
| 	{ .Task = USB_MassStorage      , .TaskStatus = TASK_STOP }, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| /* Global Variables */ | 		.DataINEndpointNumber   = MASS_STORAGE_IN_EPNUM, | ||||||
| /** Structure to hold the latest Command Block Wrapper issued by the host, containing a SCSI command to execute. */ | 		.DataINEndpointSize     = MASS_STORAGE_IO_EPSIZE, | ||||||
| CommandBlockWrapper_t  CommandBlock; |  | ||||||
| 
 | 
 | ||||||
| /** Structure to hold the latest Command Status Wrapper to return to the host, containing the status of the last issued command. */ | 		.DataOUTEndpointNumber  = MASS_STORAGE_OUT_EPNUM, | ||||||
| CommandStatusWrapper_t CommandStatus = { .Signature = CSW_SIGNATURE }; | 		.DataOUTEndpointSize    = MASS_STORAGE_IO_EPSIZE, | ||||||
| 
 | 
 | ||||||
| /** Flag to asynchronously abort any in-progress data transfers upon the reception of a mass storage reset command. */ | 		.TotalLUNs              = TOTAL_LUNS, | ||||||
| volatile bool          IsMassStoreReset = false; | 	}; | ||||||
| 
 | 
 | ||||||
| /** 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) | int main(void) | ||||||
|  | { | ||||||
|  | 	SetupHardware(); | ||||||
|  | 
 | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | 
 | ||||||
|  | 	for (;;) | ||||||
|  | 	{ | ||||||
|  | 		USB_MS_USBTask(&Disk_MS_Interface); | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupHardware(void) | ||||||
| { | { | ||||||
| 	/* Disable watchdog if enabled by bootloader/fuses */ | 	/* Disable watchdog if enabled by bootloader/fuses */ | ||||||
| 	MCUSR &= ~(1 << WDRF); | 	MCUSR &= ~(1 << WDRF); | ||||||
| @ -68,303 +68,42 @@ int main(void) | |||||||
| 	/* Hardware Initialization */ | 	/* Hardware Initialization */ | ||||||
| 	LEDs_Init(); | 	LEDs_Init(); | ||||||
| 	Dataflash_Init(SPI_SPEED_FCPU_DIV_2); | 	Dataflash_Init(SPI_SPEED_FCPU_DIV_2); | ||||||
|  | 	USB_Init(); | ||||||
| 
 | 
 | ||||||
| 	/* Clear Dataflash sector protections, if enabled */ | 	/* Clear Dataflash sector protections, if enabled */ | ||||||
| 	DataflashManager_ResetDataflashProtections(); | 	DataflashManager_ResetDataflashProtections(); | ||||||
| 	 |  | ||||||
| 	/* 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. */ |  | ||||||
| void EVENT_USB_Connect(void) | void EVENT_USB_Connect(void) | ||||||
| { | { | ||||||
| 	/* Indicate USB enumerating */ | 	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||||
| 	UpdateStatus(Status_USBEnumerating); |  | ||||||
| 	 |  | ||||||
| 	/* Reset the MSReset flag upon connection */ |  | ||||||
| 	IsMassStoreReset = false; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** 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 Mass Storage management task. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Disconnect(void) | void EVENT_USB_Disconnect(void) | ||||||
| { | { | ||||||
| 	/* Stop running mass storage task */ | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
| 	Scheduler_SetTaskMode(USB_MassStorage, 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 Mass Storage management task started. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_ConfigurationChanged(void) | void EVENT_USB_ConfigurationChanged(void) | ||||||
| { | { | ||||||
| 	/* Setup Mass Storage In and Out Endpoints */ | 	LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
| 	Endpoint_ConfigureEndpoint(MASS_STORAGE_IN_EPNUM, EP_TYPE_BULK, |  | ||||||
| 		                       ENDPOINT_DIR_IN, MASS_STORAGE_IO_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_DOUBLE); |  | ||||||
| 
 | 
 | ||||||
| 	Endpoint_ConfigureEndpoint(MASS_STORAGE_OUT_EPNUM, EP_TYPE_BULK, | 	if (!(USB_MS_ConfigureEndpoints(&Disk_MS_Interface))) | ||||||
| 		                       ENDPOINT_DIR_OUT, MASS_STORAGE_IO_EPSIZE, | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
| 	                           ENDPOINT_BANK_DOUBLE); |  | ||||||
| 
 |  | ||||||
| 	/* Indicate USB connected and ready */ |  | ||||||
| 	UpdateStatus(Status_USBReady); |  | ||||||
| 	 |  | ||||||
| 	/* Start mass storage task */ |  | ||||||
| 	Scheduler_SetTaskMode(USB_MassStorage, 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 Mass Storage class-specific |  | ||||||
|  *  requests) so that they can be handled appropriately for the application. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_UnhandledControlPacket(void) | void EVENT_USB_UnhandledControlPacket(void) | ||||||
| { | { | ||||||
| 	/* Process UFI specific control requests */ | 	USB_MS_ProcessControlPacket(&Disk_MS_Interface); | ||||||
| 	switch (USB_ControlRequest.bRequest) |  | ||||||
| 	{ |  | ||||||
| 		case REQ_MassStorageReset: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 
 |  | ||||||
| 				/* Indicate that the current transfer should be aborted */ |  | ||||||
| 				IsMassStoreReset = true;			 |  | ||||||
| 
 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_GetMaxLUN: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 
 |  | ||||||
| 				/* Indicate to the host the number of supported LUNs (virtual disks) on the device */ |  | ||||||
| 				Endpoint_Write_Byte(TOTAL_LUNS - 1); |  | ||||||
| 				 |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 				 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsOUTReceived())); |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
 | bool CALLBACK_USB_MS_SCSICommandReceived(USB_ClassInfo_MS_t* MSInterfaceInfo) | ||||||
|  *  log to a serial port, or anything else that is suitable for status updates. |  | ||||||
|  * |  | ||||||
|  *  \param CurrentStatus  Current status of the system, from the MassStorage_StatusCodes_t enum |  | ||||||
|  */ |  | ||||||
| void UpdateStatus(uint8_t CurrentStatus) |  | ||||||
| { | { | ||||||
| 	uint8_t LEDMask = LEDS_NO_LEDS; | 	bool CommandSuccess; | ||||||
| 	 | 	 | ||||||
| 	/* Set the LED mask to the appropriate LED mask based on the given status code */ | 	LEDs_SetAllLEDs(LEDMASK_USB_BUSY); | ||||||
| 	switch (CurrentStatus) | 	CommandSuccess = SCSI_DecodeSCSICommand(MSInterfaceInfo); | ||||||
| 	{ | 	LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
| 		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; |  | ||||||
| 		case Status_CommandBlockError: |  | ||||||
| 			LEDMask = (LEDS_LED1); |  | ||||||
| 			break; |  | ||||||
| 		case Status_ProcessingCommandBlock: |  | ||||||
| 			LEDMask = (LEDS_LED1 | LEDS_LED2); |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| 	 | 	 | ||||||
| 	/* Set the board LEDs to the new LED mask */ | 	return CommandSuccess; | ||||||
| 	LEDs_SetAllLEDs(LEDMask); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Task to manage the Mass Storage interface, reading in Command Block Wrappers from the host, processing the SCSI commands they
 |  | ||||||
|  *  contain, and returning Command Status Wrappers back to the host to indicate the success or failure of the last issued command. |  | ||||||
|  */ |  | ||||||
| TASK(USB_MassStorage) |  | ||||||
| { |  | ||||||
| 	/* Check if the USB System is connected to a Host */ |  | ||||||
| 	if (USB_IsConnected) |  | ||||||
| 	{ |  | ||||||
| 		/* Select the Data Out Endpoint */ |  | ||||||
| 		Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM); |  | ||||||
| 		 |  | ||||||
| 		/* Check to see if a command from the host has been issued */ |  | ||||||
| 		if (Endpoint_IsReadWriteAllowed()) |  | ||||||
| 		{	 |  | ||||||
| 			/* Indicate busy */ |  | ||||||
| 			UpdateStatus(Status_ProcessingCommandBlock); |  | ||||||
| 
 |  | ||||||
| 			/* Process sent command block from the host */ |  | ||||||
| 			if (ReadInCommandBlock()) |  | ||||||
| 			{ |  | ||||||
| 				/* Check direction of command, select Data IN endpoint if data is from the device */ |  | ||||||
| 				if (CommandBlock.Flags & COMMAND_DIRECTION_DATA_IN) |  | ||||||
| 				  Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM); |  | ||||||
| 
 |  | ||||||
| 				/* Decode the received SCSI command */ |  | ||||||
| 				SCSI_DecodeSCSICommand(); |  | ||||||
| 
 |  | ||||||
| 				/* Load in the CBW tag into the CSW to link them together */ |  | ||||||
| 				CommandStatus.Tag = CommandBlock.Tag; |  | ||||||
| 
 |  | ||||||
| 				/* Load in the data residue counter into the CSW */ |  | ||||||
| 				CommandStatus.DataTransferResidue = CommandBlock.DataTransferLength; |  | ||||||
| 
 |  | ||||||
| 				/* Stall the selected data pipe if command failed (if data is still to be transferred) */ |  | ||||||
| 				if ((CommandStatus.Status == Command_Fail) && (CommandStatus.DataTransferResidue)) |  | ||||||
| 				  Endpoint_StallTransaction(); |  | ||||||
| 
 |  | ||||||
| 				/* Return command status block to the host */ |  | ||||||
| 				ReturnCommandStatus(); |  | ||||||
| 				 |  | ||||||
| 				/* Check if a Mass Storage Reset occurred */ |  | ||||||
| 				if (IsMassStoreReset) |  | ||||||
| 				{ |  | ||||||
| 					/* Reset the data endpoint banks */ |  | ||||||
| 					Endpoint_ResetFIFO(MASS_STORAGE_OUT_EPNUM); |  | ||||||
| 					Endpoint_ResetFIFO(MASS_STORAGE_IN_EPNUM); |  | ||||||
| 					 |  | ||||||
| 					Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM); |  | ||||||
| 					Endpoint_ClearStall(); |  | ||||||
| 					Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM); |  | ||||||
| 					Endpoint_ClearStall(); |  | ||||||
| 
 |  | ||||||
| 					/* Clear the abort transfer flag */ |  | ||||||
| 					IsMassStoreReset = false; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				/* Indicate ready */ |  | ||||||
| 				UpdateStatus(Status_USBReady); |  | ||||||
| 			} |  | ||||||
| 			else |  | ||||||
| 			{ |  | ||||||
| 				/* Indicate error reading in the command block from the host */ |  | ||||||
| 				UpdateStatus(Status_CommandBlockError); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Function to read in a command block from the host, via the bulk data OUT endpoint. This function reads in the next command block
 |  | ||||||
|  *  if one has been issued, and performs validation to ensure that the block command is valid. |  | ||||||
|  * |  | ||||||
|  *  \return Boolean true if a valid command block has been read in from the endpoint, false otherwise |  | ||||||
|  */ |  | ||||||
| static bool ReadInCommandBlock(void) |  | ||||||
| { |  | ||||||
| 	/* Select the Data Out endpoint */ |  | ||||||
| 	Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM); |  | ||||||
| 
 |  | ||||||
| 	/* Read in command block header */ |  | ||||||
| 	Endpoint_Read_Stream_LE(&CommandBlock, (sizeof(CommandBlock) - sizeof(CommandBlock.SCSICommandData)), |  | ||||||
| 	                        StreamCallback_AbortOnMassStoreReset); |  | ||||||
| 
 |  | ||||||
| 	/* Check if the current command is being aborted by the host */ |  | ||||||
| 	if (IsMassStoreReset) |  | ||||||
| 	  return false; |  | ||||||
| 
 |  | ||||||
| 	/* Verify the command block - abort if invalid */ |  | ||||||
| 	if ((CommandBlock.Signature != CBW_SIGNATURE) || |  | ||||||
| 	    (CommandBlock.LUN >= TOTAL_LUNS) || |  | ||||||
| 		(CommandBlock.SCSICommandLength > MAX_SCSI_COMMAND_LENGTH)) |  | ||||||
| 	{ |  | ||||||
| 		/* Stall both data pipes until reset by host */ |  | ||||||
| 		Endpoint_StallTransaction(); |  | ||||||
| 		Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM); |  | ||||||
| 		Endpoint_StallTransaction(); |  | ||||||
| 		 |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* Read in command block command data */ |  | ||||||
| 	Endpoint_Read_Stream_LE(&CommandBlock.SCSICommandData, |  | ||||||
| 	                        CommandBlock.SCSICommandLength, |  | ||||||
| 	                        StreamCallback_AbortOnMassStoreReset); |  | ||||||
| 	   |  | ||||||
| 	/* Check if the current command is being aborted by the host */ |  | ||||||
| 	if (IsMassStoreReset) |  | ||||||
| 	  return false; |  | ||||||
| 
 |  | ||||||
| 	/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 	Endpoint_ClearOUT(); |  | ||||||
| 	 |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Returns the filled Command Status Wrapper back to the host via the bulk data IN endpoint, waiting for the host to clear any
 |  | ||||||
|  *  stalled data endpoints as needed. |  | ||||||
|  */ |  | ||||||
| static void ReturnCommandStatus(void) |  | ||||||
| { |  | ||||||
| 	/* Select the Data Out endpoint */ |  | ||||||
| 	Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM); |  | ||||||
| 
 |  | ||||||
| 	/* While data pipe is stalled, wait until the host issues a control request to clear the stall */ |  | ||||||
| 	while (Endpoint_IsStalled()) |  | ||||||
| 	{ |  | ||||||
| 		/* Check if the current command is being aborted by the host */ |  | ||||||
| 		if (IsMassStoreReset) |  | ||||||
| 		  return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* Select the Data In endpoint */ |  | ||||||
| 	Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM); |  | ||||||
| 
 |  | ||||||
| 	/* While data pipe is stalled, wait until the host issues a control request to clear the stall */ |  | ||||||
| 	while (Endpoint_IsStalled()) |  | ||||||
| 	{ |  | ||||||
| 		/* Check if the current command is being aborted by the host */ |  | ||||||
| 		if (IsMassStoreReset) |  | ||||||
| 		  return; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	/* Write the CSW to the endpoint */ |  | ||||||
| 	Endpoint_Write_Stream_LE(&CommandStatus, sizeof(CommandStatus), |  | ||||||
| 	                          StreamCallback_AbortOnMassStoreReset); |  | ||||||
| 	 |  | ||||||
| 	/* Check if the current command is being aborted by the host */ |  | ||||||
| 	if (IsMassStoreReset) |  | ||||||
| 	  return; |  | ||||||
| 
 |  | ||||||
| 	/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 	Endpoint_ClearIN(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Stream callback function for the Endpoint stream read and write functions. This callback will abort the current stream transfer
 |  | ||||||
|  *  if a Mass Storage Reset request has been issued to the control endpoint. |  | ||||||
|  */ |  | ||||||
| uint8_t StreamCallback_AbortOnMassStoreReset(void) |  | ||||||
| {	 |  | ||||||
| 	/* Abort if a Mass Storage reset command was received */ |  | ||||||
| 	if (IsMassStoreReset) |  | ||||||
| 	  return STREAMCALLBACK_Abort; |  | ||||||
| 	 |  | ||||||
| 	/* Continue with the current stream operation */ |  | ||||||
| 	return STREAMCALLBACK_Continue; |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -46,104 +46,33 @@ | |||||||
| 		#include "Lib/SCSI.h" | 		#include "Lib/SCSI.h" | ||||||
| 		#include "Lib/DataflashManager.h" | 		#include "Lib/DataflashManager.h" | ||||||
| 
 | 
 | ||||||
| 		#include <LUFA/Version.h>                    // Library Version Information | 		#include <LUFA/Version.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>            // USB Functionality | 		#include <LUFA/Drivers/Board/Joystick.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>         // LEDs driver | 		#include <LUFA/Drivers/Board/LEDs.h> | ||||||
| 		#include <LUFA/Drivers/Board/Dataflash.h>    // Dataflash chip driver | 		#include <LUFA/Drivers/Board/Buttons.h> | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>        // Simple scheduler for task management | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
|  | 		#include <LUFA/Drivers/USB/Class/Device/MassStorage.h> | ||||||
| 
 | 
 | ||||||
| 	/* Macros: */ | 	/* Macros: */ | ||||||
| 		/** Mass Storage Class specific request to reset the Mass Storage interface, ready for the next command. */ | 		#define LEDMASK_USB_NOTREADY      LEDS_LED1 | ||||||
| 		#define REQ_MassStorageReset       0xFF | 		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3) | ||||||
|  | 		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4) | ||||||
|  | 		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3) | ||||||
|  | 		#define LEDMASK_USB_BUSY          LEDS_LED2 | ||||||
| 		 | 		 | ||||||
| 		/** Mass Storage Class specific request to retrieve the total number of Logical Units (drives) in the SCSI device. */ | 		#define TOTAL_LUNS                2 | ||||||
| 		#define REQ_GetMaxLUN              0xFE |  | ||||||
| 
 |  | ||||||
| 		/** Maximum length of a SCSI command which can be issued by the device or host in a Mass Storage bulk wrapper. */ |  | ||||||
| 		#define MAX_SCSI_COMMAND_LENGTH    16 |  | ||||||
| 		 |  | ||||||
| 		/** Total number of Logical Units (drives) in the device. The total device capacity is shared equally between
 |  | ||||||
| 		 *  each drive - this can be set to any positive non-zero amount. |  | ||||||
| 		 */ |  | ||||||
| 		#define TOTAL_LUNS                 2 |  | ||||||
| 		 | 		 | ||||||
| 		/** Blocks in each LUN, calculated from the total capacity divided by the total number of Logical Units in the device. */ | 		/** Blocks in each LUN, calculated from the total capacity divided by the total number of Logical Units in the device. */ | ||||||
| 		#define LUN_MEDIA_BLOCKS           (VIRTUAL_MEMORY_BLOCKS / TOTAL_LUNS)     | 		#define LUN_MEDIA_BLOCKS         (VIRTUAL_MEMORY_BLOCKS / TOTAL_LUNS) | ||||||
| 		 |  | ||||||
| 		/** Magic signature for a Command Block Wrapper used in the Mass Storage Bulk-Only transport protocol. */ |  | ||||||
| 		#define CBW_SIGNATURE              0x43425355UL |  | ||||||
| 
 |  | ||||||
| 		/** Magic signature for a Command Status Wrapper used in the Mass Storage Bulk-Only transport protocol. */ |  | ||||||
| 		#define CSW_SIGNATURE              0x53425355UL |  | ||||||
| 		 |  | ||||||
| 		/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from host-to-device. */ |  | ||||||
| 		#define COMMAND_DIRECTION_DATA_OUT (0 << 7) |  | ||||||
| 
 |  | ||||||
| 		/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from device-to-host. */ |  | ||||||
| 		#define COMMAND_DIRECTION_DATA_IN  (1 << 7) |  | ||||||
| 
 |  | ||||||
| 	/* Type defines: */ |  | ||||||
| 		/** Type define for a Command Block Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */ |  | ||||||
| 		typedef struct |  | ||||||
| 		{ |  | ||||||
| 			uint32_t Signature; /**< Command block signature, must be CBW_SIGNATURE to indicate a valid Command Block */ |  | ||||||
| 			uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */ |  | ||||||
| 			uint32_t DataTransferLength; /** Length of the optional data portion of the issued command, in bytes */ |  | ||||||
| 			uint8_t  Flags; /**< Command block flags, indicating command data direction */ |  | ||||||
| 			uint8_t  LUN; /**< Logical Unit number this command is issued to */ |  | ||||||
| 			uint8_t  SCSICommandLength; /**< Length of the issued SCSI command within the SCSI command data array */ |  | ||||||
| 			uint8_t  SCSICommandData[MAX_SCSI_COMMAND_LENGTH]; /**< Issued SCSI command in the Command Block */ |  | ||||||
| 		} CommandBlockWrapper_t; |  | ||||||
| 		 |  | ||||||
| 		/** Type define for a Command Status Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */ |  | ||||||
| 		typedef struct |  | ||||||
| 		{ |  | ||||||
| 			uint32_t Signature; /**< Status block signature, must be CSW_SIGNATURE to indicate a valid Command Status */ |  | ||||||
| 			uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */ |  | ||||||
| 			uint32_t DataTransferResidue; /**< Number of bytes of data not processed in the SCSI command */ |  | ||||||
| 			uint8_t  Status; /**< Status code of the issued command - a value from the MassStorage_CommandStatusCodes_t enum */ |  | ||||||
| 		} CommandStatusWrapper_t; |  | ||||||
| 		 |  | ||||||
| 	/* Enums: */ |  | ||||||
| 		/** Enum for the possible command status wrapper return status codes. */ |  | ||||||
| 		enum MassStorage_CommandStatusCodes_t |  | ||||||
| 		{ |  | ||||||
| 			Command_Pass = 0, /**< Command completed with no error */ |  | ||||||
| 			Command_Fail = 1, /**< Command failed to complete - host may check the exact error via a SCSI REQUEST SENSE command */ |  | ||||||
| 			Phase_Error  = 2  /**< Command failed due to being invalid in the current phase */ |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 		/** Enum for the possible status codes for passing to the UpdateStatus() function. */ |  | ||||||
| 		enum MassStorage_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 */ |  | ||||||
| 			Status_CommandBlockError      = 3, /**< Processing a SCSI command block from the host */ |  | ||||||
| 			Status_ProcessingCommandBlock = 4, /**< Error during the processing of a SCSI command block from the host */ |  | ||||||
| 		}; |  | ||||||
| 		 |  | ||||||
| 	/* Global Variables: */ |  | ||||||
| 		extern CommandBlockWrapper_t  CommandBlock; |  | ||||||
| 		extern CommandStatusWrapper_t CommandStatus; |  | ||||||
| 		extern volatile bool          IsMassStoreReset; |  | ||||||
| 
 |  | ||||||
| 	/* Task Definitions: */ |  | ||||||
| 		TASK(USB_MassStorage); |  | ||||||
| 		 | 		 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void SetupHardware(void); | ||||||
|  | 
 | ||||||
| 		void EVENT_USB_Connect(void); | 		void EVENT_USB_Connect(void); | ||||||
| 		void EVENT_USB_Disconnect(void); | 		void EVENT_USB_Disconnect(void); | ||||||
| 		void EVENT_USB_ConfigurationChanged(void); | 		void EVENT_USB_ConfigurationChanged(void); | ||||||
| 		void EVENT_USB_UnhandledControlPacket(void); | 		void EVENT_USB_UnhandledControlPacket(void); | ||||||
| 
 | 
 | ||||||
| 		void UpdateStatus(uint8_t CurrentStatus); | 		bool CALLBACK_USB_MS_SCSICommandReceived(USB_ClassInfo_MS_t* MSInterfaceInfo); | ||||||
| 
 |  | ||||||
| 		#if defined(INCLUDE_FROM_MASSSTORAGE_C) |  | ||||||
| 			static bool ReadInCommandBlock(void); |  | ||||||
| 			static void ReturnCommandStatus(void); |  | ||||||
| 		#endif |  | ||||||
| 
 |  | ||||||
| 		uint8_t StreamCallback_AbortOnMassStoreReset(void); |  | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -127,7 +127,6 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  Descriptors.c                                               \
 | 	  Descriptors.c                                               \
 | ||||||
| 	  Lib/SCSI.c                                                  \
 | 	  Lib/SCSI.c                                                  \
 | ||||||
| 	  Lib/DataflashManager.c                                      \
 | 	  Lib/DataflashManager.c                                      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | ||||||
| @ -138,7 +137,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/MassStorage.c    \
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
| @ -188,7 +187,6 @@ CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | |||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY | ||||||
| CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | ||||||
| CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | ||||||
| CDEFS += -DINTERRUPT_CONTROL_ENDPOINT |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for ASM sources
 | # Place -D or -U options here for ASM sources
 | ||||||
|  | |||||||
| @ -37,30 +37,12 @@ | |||||||
| #define _DESCRIPTORS_H_ | #define _DESCRIPTORS_H_ | ||||||
| 
 | 
 | ||||||
| 	/* Includes: */ | 	/* Includes: */ | ||||||
| 		#include <LUFA/Drivers/USB/USB.h> |  | ||||||
| 
 |  | ||||||
| 		#include <avr/pgmspace.h> | 		#include <avr/pgmspace.h> | ||||||
| 
 | 
 | ||||||
|  | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
|  | 		#include <LUFA/Drivers/USB/Class/Device/HID.h> | ||||||
|  | 
 | ||||||
| 	/* Type Defines: */ | 	/* Type Defines: */ | ||||||
| 		/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
 |  | ||||||
| 		 *  specification for details on the structure elements. |  | ||||||
| 		 */ |  | ||||||
| 		typedef struct |  | ||||||
| 		{ |  | ||||||
| 			USB_Descriptor_Header_t Header; |  | ||||||
| 				 |  | ||||||
| 			uint16_t                HIDSpec; |  | ||||||
| 			uint8_t                 CountryCode; |  | ||||||
| 		 |  | ||||||
| 			uint8_t                 TotalReportDescriptors; |  | ||||||
| 
 |  | ||||||
| 			uint8_t                 HIDReportType; |  | ||||||
| 			uint16_t                HIDReportLength; |  | ||||||
| 		} USB_Descriptor_HID_t; |  | ||||||
| 
 |  | ||||||
| 		/** Type define for the data type used to store HID report descriptor elements. */ |  | ||||||
| 		typedef uint8_t USB_Descriptor_HIDReport_Datatype_t; |  | ||||||
| 
 |  | ||||||
| 		/** Type define for the device configuration descriptor structure. This must be defined in the
 | 		/** 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 | 		 *  application code, as the configuration descriptor contains several sub-descriptors which | ||||||
| 		 *  vary between devices, and which describe the device's usage to the host. | 		 *  vary between devices, and which describe the device's usage to the host. | ||||||
| @ -80,12 +62,6 @@ | |||||||
| 		/** Size in bytes of the Mouse HID reporting IN endpoint. */ | 		/** Size in bytes of the Mouse HID reporting IN endpoint. */ | ||||||
| 		#define MOUSE_EPSIZE              8 | 		#define MOUSE_EPSIZE              8 | ||||||
| 
 | 
 | ||||||
| 		/** Descriptor header type value, to indicate a HID class HID descriptor. */ |  | ||||||
| 		#define DTYPE_HID                 0x21 |  | ||||||
| 		 |  | ||||||
| 		/** Descriptor header type value, to indicate a HID class HID report descriptor. */ |  | ||||||
| 		#define DTYPE_Report              0x22 |  | ||||||
| 
 |  | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
| 		uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) | 		uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress) | ||||||
| 											ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); | 											ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); | ||||||
|  | |||||||
| @ -28,43 +28,32 @@ | |||||||
|   this software. |   this software. | ||||||
| */ | */ | ||||||
|   |   | ||||||
| /** \file
 |  | ||||||
|  * |  | ||||||
|  *  Main source file for the Mouse demo. This file contains the main tasks of the demo and |  | ||||||
|  *  is responsible for the initial application hardware configuration. |  | ||||||
|  */ |  | ||||||
|   |  | ||||||
| #include "Mouse.h" | #include "Mouse.h" | ||||||
| 
 | 
 | ||||||
| /* Scheduler Task List */ | USB_ClassInfo_HID_t Mouse_HID_Interface = | ||||||
| TASK_LIST | 	{ | ||||||
| { | 		.InterfaceNumber         = 0, | ||||||
| 	{ .Task = USB_USBTask          , .TaskStatus = TASK_STOP }, |  | ||||||
| 	{ .Task = USB_Mouse_Report     , .TaskStatus = TASK_STOP }, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| /* Global Variables */ | 		.ReportINEndpointNumber  = MOUSE_EPNUM, | ||||||
| /** Indicates what report mode the host has requested, true for normal HID reporting mode, false for special boot
 | 		.ReportINEndpointSize    = MOUSE_EPSIZE, | ||||||
|  *  protocol reporting mode. |  | ||||||
|  */ |  | ||||||
| bool UsingReportProtocol = true; |  | ||||||
| 
 | 
 | ||||||
| /** Current Idle period. This is set by the host via a Set Idle HID class request to silence the device's reports
 | 		.ReportBufferSize        = sizeof(USB_MouseReport_Data_t), | ||||||
|  *  for either the entire idle duration, or until the report status changes (e.g. the user moves the mouse). | 	}; | ||||||
|  */ |  | ||||||
| uint16_t IdleCount = HID_IDLE_CHANGESONLY; |  | ||||||
| 
 | 
 | ||||||
| /** Current Idle period remaining. When the IdleCount value is set, this tracks the remaining number of idle
 |  | ||||||
|  *  milliseconds. This is separate to the IdleCount timer and is incremented and compared as the host may request  |  | ||||||
|  *  the current idle period via a Get Idle HID class request, thus its value must be preserved. |  | ||||||
|  */ |  | ||||||
| uint16_t IdleMSRemaining = 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) | int main(void) | ||||||
|  | {	 | ||||||
|  | 	SetupHardware(); | ||||||
|  | 	 | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | 
 | ||||||
|  | 	for (;;) | ||||||
|  | 	{ | ||||||
|  | 		USB_HID_USBTask(&Mouse_HID_Interface); | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupHardware(void) | ||||||
| { | { | ||||||
| 	/* Disable watchdog if enabled by bootloader/fuses */ | 	/* Disable watchdog if enabled by bootloader/fuses */ | ||||||
| 	MCUSR &= ~(1 << WDRF); | 	MCUSR &= ~(1 << WDRF); | ||||||
| @ -77,284 +66,64 @@ int main(void) | |||||||
| 	Joystick_Init(); | 	Joystick_Init(); | ||||||
| 	LEDs_Init(); | 	LEDs_Init(); | ||||||
| 	Buttons_Init(); | 	Buttons_Init(); | ||||||
| 	 |  | ||||||
| 	/* Millisecond timer initialization, with output compare interrupt enabled for the idle timing */ |  | ||||||
| 	OCR0A  = 0x7D; |  | ||||||
| 	TCCR0A = (1 << WGM01); |  | ||||||
| 	TCCR0B = ((1 << CS01) | (1 << CS00)); |  | ||||||
| 	TIMSK0 = (1 << OCIE0A); |  | ||||||
| 
 |  | ||||||
| 	/* Indicate USB not ready */ |  | ||||||
| 	UpdateStatus(Status_USBNotReady); |  | ||||||
| 	 |  | ||||||
| 	/* Initialize Scheduler so that it can be used */ |  | ||||||
| 	Scheduler_Init(); |  | ||||||
| 
 |  | ||||||
| 	/* Initialize USB Subsystem */ |  | ||||||
| 	USB_Init(); | 	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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Connect(void) | void EVENT_USB_Connect(void) | ||||||
| { | { | ||||||
| 	/* Start USB management task */ | 	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||||
| 	Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); |  | ||||||
| 	 |  | ||||||
| 	/* Indicate USB enumerating */ |  | ||||||
| 	UpdateStatus(Status_USBEnumerating); |  | ||||||
| 
 |  | ||||||
| 	/* Default to report protocol on connect */ |  | ||||||
| 	UsingReportProtocol = true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** 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 Mouse reporting tasks. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Disconnect(void) | void EVENT_USB_Disconnect(void) | ||||||
| { | { | ||||||
| 	/* Stop running mouse reporting and USB management tasks */ | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
| 	Scheduler_SetTaskMode(USB_Mouse_Report, 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 sets the current configuration
 |  | ||||||
|  *  of the USB device after enumeration - the device endpoints are configured and the mouse reporting task started. |  | ||||||
|  */  |  | ||||||
| void EVENT_USB_ConfigurationChanged(void) | void EVENT_USB_ConfigurationChanged(void) | ||||||
| { | { | ||||||
| 	/* Setup Mouse Report Endpoint */ | 	LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
| 	Endpoint_ConfigureEndpoint(MOUSE_EPNUM, EP_TYPE_INTERRUPT, |  | ||||||
| 		                       ENDPOINT_DIR_IN, MOUSE_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 | 
 | ||||||
| 	/* Indicate USB connected and ready */ | 	if (!(USB_HID_ConfigureEndpoints(&Mouse_HID_Interface))) | ||||||
| 	UpdateStatus(Status_USBReady); | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
| 
 |  | ||||||
| 	/* Start running mouse reporting task */ |  | ||||||
| 	Scheduler_SetTaskMode(USB_Mouse_Report, 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 HID commands, which are |  | ||||||
|  *  all issued via the control endpoint), so that they can be handled appropriately for the application. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_UnhandledControlPacket(void) | void EVENT_USB_UnhandledControlPacket(void) | ||||||
| { | { | ||||||
| 	/* Handle HID Class specific requests */ | 	USB_HID_ProcessControlPacket(&Mouse_HID_Interface); | ||||||
| 	switch (USB_ControlRequest.bRequest) |  | ||||||
| 	{ |  | ||||||
| 		case REQ_GetReport: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				USB_MouseReport_Data_t MouseReportData; |  | ||||||
| 
 |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 
 |  | ||||||
| 				/* Create the next mouse report for transmission to the host */ |  | ||||||
| 				CreateMouseReport(&MouseReportData); |  | ||||||
| 	 |  | ||||||
| 				/* Write the report data to the control endpoint */ |  | ||||||
| 				Endpoint_Write_Control_Stream_LE(&MouseReportData, sizeof(MouseReportData)); |  | ||||||
| 				 |  | ||||||
| 				/* Clear the report data afterwards */ |  | ||||||
| 				memset(&MouseReportData, 0, sizeof(MouseReportData)); |  | ||||||
| 
 |  | ||||||
| 				/* Finalize the stream transfer to send the last packet or clear the host abort */ |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 		 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_GetProtocol: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Write the current protocol flag to the host */ |  | ||||||
| 				Endpoint_Write_Byte(UsingReportProtocol); |  | ||||||
| 				 |  | ||||||
| 				/* Send the flag to the host */ |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 
 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsOUTReceived())); |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetProtocol: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Set or clear the flag depending on what the host indicates that the current Protocol should be */ |  | ||||||
| 				UsingReportProtocol = (USB_ControlRequest.wValue != 0); |  | ||||||
| 				 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetIdle: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Get idle period in MSB */ |  | ||||||
| 				IdleCount = (USB_ControlRequest.wValue >> 8); |  | ||||||
| 				 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_GetIdle: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{		 |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Write the current idle duration to the host */ |  | ||||||
| 				Endpoint_Write_Byte(IdleCount); |  | ||||||
| 				 |  | ||||||
| 				/* Send the flag to the host */ |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 
 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsOUTReceived())); |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** ISR for the timer 0 compare vector. This ISR fires once each millisecond, and increments the
 | void EVENT_USB_StartOfFrame(void) | ||||||
|  *  scheduler elapsed idle period counter when the host has set an idle period. |  | ||||||
|  */ |  | ||||||
| ISR(TIMER0_COMPA_vect, ISR_BLOCK) |  | ||||||
| { | { | ||||||
| 	/* One millisecond has elapsed, decrement the idle time remaining counter if it has not already elapsed */ | 	USB_HID_RegisterStartOfFrame(&Mouse_HID_Interface); | ||||||
| 	if (IdleMSRemaining) |  | ||||||
| 	  IdleMSRemaining--; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Fills the given HID report data structure with the next HID report to send to the host.
 | uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData) | ||||||
|  * |  | ||||||
|  *  \param ReportData  Pointer to a HID report data structure to be filled |  | ||||||
|  */ |  | ||||||
| void CreateMouseReport(USB_MouseReport_Data_t* ReportData) |  | ||||||
| { | { | ||||||
|  | 	USB_MouseReport_Data_t* MouseReport = (USB_MouseReport_Data_t*)ReportData; | ||||||
|  | 		 | ||||||
| 	uint8_t JoyStatus_LCL    = Joystick_GetStatus(); | 	uint8_t JoyStatus_LCL    = Joystick_GetStatus(); | ||||||
| 	uint8_t ButtonStatus_LCL = Buttons_GetStatus(); | 	uint8_t ButtonStatus_LCL = Buttons_GetStatus(); | ||||||
| 
 | 
 | ||||||
| 	/* Clear the report contents */ |  | ||||||
| 	memset(ReportData, 0, sizeof(USB_MouseReport_Data_t)); |  | ||||||
| 
 |  | ||||||
| 	if (JoyStatus_LCL & JOY_UP) | 	if (JoyStatus_LCL & JOY_UP) | ||||||
| 	  ReportData->Y = -1; | 	  MouseReport->Y = -1; | ||||||
| 	else if (JoyStatus_LCL & JOY_DOWN) | 	else if (JoyStatus_LCL & JOY_DOWN) | ||||||
| 	  ReportData->Y =  1; | 	  MouseReport->Y =  1; | ||||||
| 
 | 
 | ||||||
| 	if (JoyStatus_LCL & JOY_RIGHT) | 	if (JoyStatus_LCL & JOY_RIGHT) | ||||||
| 	  ReportData->X =  1; | 	  MouseReport->X =  1; | ||||||
| 	else if (JoyStatus_LCL & JOY_LEFT) | 	else if (JoyStatus_LCL & JOY_LEFT) | ||||||
| 	  ReportData->X = -1; | 	  MouseReport->X = -1; | ||||||
| 
 | 
 | ||||||
| 	if (JoyStatus_LCL & JOY_PRESS) | 	if (JoyStatus_LCL & JOY_PRESS) | ||||||
| 	  ReportData->Button  = (1 << 0); | 	  MouseReport->Button  = (1 << 0); | ||||||
| 	   | 	   | ||||||
| 	if (ButtonStatus_LCL & BUTTONS_BUTTON1) | 	if (ButtonStatus_LCL & BUTTONS_BUTTON1) | ||||||
| 	  ReportData->Button |= (1 << 1); | 	  MouseReport->Button |= (1 << 1); | ||||||
|  | 	 | ||||||
|  | 	return sizeof(USB_MouseReport_Data_t); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Sends the next HID report to the host, via the keyboard data endpoint. */ | void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize) | ||||||
| void SendNextReport(void) |  | ||||||
| { | { | ||||||
| 	static USB_MouseReport_Data_t PrevMouseReportData; | 	// Unused (but mandatory for the HID class driver) in this demo, since there are no Host->Device reports
 | ||||||
| 	USB_MouseReport_Data_t        MouseReportData; |  | ||||||
| 	bool                          SendReport; |  | ||||||
| 	 |  | ||||||
| 	/* Create the next mouse report for transmission to the host */ |  | ||||||
| 	CreateMouseReport(&MouseReportData); |  | ||||||
| 	 |  | ||||||
| 	/* Check to see if the report data has changed - if so a report MUST be sent */ |  | ||||||
| 	SendReport = (memcmp(&PrevMouseReportData, &MouseReportData, sizeof(USB_MouseReport_Data_t)) != 0); |  | ||||||
| 	 |  | ||||||
| 	/* Override the check if the Y or X values are non-zero - we want continuous movement while the joystick
 |  | ||||||
| 	 * is being held down (via continuous reports), otherwise the cursor will only move once per joystick toggle */ |  | ||||||
| 	if ((MouseReportData.Y != 0) || (MouseReportData.X != 0)) |  | ||||||
| 	  SendReport = true; |  | ||||||
| 	 |  | ||||||
| 	/* Save the current report data for later comparison to check for changes */ |  | ||||||
| 	PrevMouseReportData = MouseReportData; |  | ||||||
| 	 |  | ||||||
| 	/* Check if the idle period is set and has elapsed */ |  | ||||||
| 	if ((IdleCount != HID_IDLE_CHANGESONLY) && (!(IdleMSRemaining))) |  | ||||||
| 	{ |  | ||||||
| 		/* Reset the idle time remaining counter, must multiply by 4 to get the duration in milliseconds */ |  | ||||||
| 		IdleMSRemaining = (IdleCount << 2); |  | ||||||
| 		 |  | ||||||
| 		/* Idle period is set and has elapsed, must send a report to the host */ |  | ||||||
| 		SendReport = true; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	/* Select the Mouse Report Endpoint */ |  | ||||||
| 	Endpoint_SelectEndpoint(MOUSE_EPNUM); |  | ||||||
| 
 |  | ||||||
| 	/* Check if Mouse Endpoint Ready for Read/Write and if we should send a new report */ |  | ||||||
| 	if (Endpoint_IsReadWriteAllowed() && SendReport) |  | ||||||
| 	{ |  | ||||||
| 		/* Write Mouse Report Data */ |  | ||||||
| 		Endpoint_Write_Stream_LE(&MouseReportData, sizeof(MouseReportData)); |  | ||||||
| 		 |  | ||||||
| 		/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 		Endpoint_ClearIN(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** 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 Mouse_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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Task to manage HID report generation and transmission to the host, when in report mode. */ |  | ||||||
| TASK(USB_Mouse_Report) |  | ||||||
| { |  | ||||||
| 	/* Check if the USB system is connected to a host */ |  | ||||||
| 	if (USB_IsConnected) |  | ||||||
| 	{ |  | ||||||
| 		/* Send the next mouse report to the host */ |  | ||||||
| 		SendNextReport(); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -46,37 +46,12 @@ | |||||||
| 		 | 		 | ||||||
| 		#include "Descriptors.h" | 		#include "Descriptors.h" | ||||||
| 
 | 
 | ||||||
| 		#include <LUFA/Version.h>                    // Library Version Information | 		#include <LUFA/Version.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>            // USB Functionality | 		#include <LUFA/Drivers/Board/Joystick.h> | ||||||
| 		#include <LUFA/Drivers/Board/Joystick.h>     // Joystick driver | 		#include <LUFA/Drivers/Board/LEDs.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>         // LEDs driver | 		#include <LUFA/Drivers/Board/Buttons.h> | ||||||
| 		#include <LUFA/Drivers/Board/Buttons.h>      // Board Buttons driver | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>        // Simple scheduler for task management | 		#include <LUFA/Drivers/USB/Class/Device/HID.h> | ||||||
| 		 |  | ||||||
| 	/* Task Definitions: */ |  | ||||||
| 		TASK(USB_Mouse_Report); |  | ||||||
| 
 |  | ||||||
| 	/* Macros: */ |  | ||||||
| 		/** Idle period indicating that reports should be sent only when the inputs have changed */ |  | ||||||
| 		#define HID_IDLE_CHANGESONLY 0 |  | ||||||
| 	 |  | ||||||
| 		/** HID Class specific request to get the next HID report from the device. */ |  | ||||||
| 		#define REQ_GetReport        0x01 |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to get the idle timeout period of the device. */ |  | ||||||
| 		#define REQ_GetIdle          0x02 |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to send the next HID report to the device. */ |  | ||||||
| 		#define REQ_SetReport        0x09 |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to set the idle timeout period of the device. */ |  | ||||||
| 		#define REQ_SetIdle          0x0A |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to get the current HID protocol in use, either report or boot. */ |  | ||||||
| 		#define REQ_GetProtocol      0x03 |  | ||||||
| 
 |  | ||||||
| 		/** HID Class specific request to set the current HID protocol in use, either report or boot. */ |  | ||||||
| 		#define REQ_SetProtocol      0x0B |  | ||||||
| 
 | 
 | ||||||
| 	/* Type Defines: */ | 	/* Type Defines: */ | ||||||
| 		/** Type define for the mouse HID report structure, for creating and sending HID reports to the host PC.
 | 		/** Type define for the mouse HID report structure, for creating and sending HID reports to the host PC.
 | ||||||
| @ -89,22 +64,23 @@ | |||||||
| 			int8_t  Y; /**< Current mouse delta Y movement, as a signed 8-bit integer */ | 			int8_t  Y; /**< Current mouse delta Y movement, as a signed 8-bit integer */ | ||||||
| 		} USB_MouseReport_Data_t; | 		} USB_MouseReport_Data_t; | ||||||
| 		 | 		 | ||||||
| 	/* Enums: */ | 	/* Macros: */ | ||||||
| 		/** Enum for the possible status codes for passing to the UpdateStatus() function. */ | 		#define LEDMASK_USB_NOTREADY      LEDS_LED1 | ||||||
| 		enum Mouse_StatusCodes_t | 		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3) | ||||||
| 		{ | 		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4) | ||||||
| 			Status_USBNotReady    = 0, /**< USB is not ready (disconnected from a USB host) */ | 		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3) | ||||||
| 			Status_USBEnumerating = 1, /**< USB interface is enumerating */ |  | ||||||
| 			Status_USBReady       = 2, /**< USB interface is connected and ready */ |  | ||||||
| 		}; |  | ||||||
| 			 | 			 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void SetupHardware(void); | ||||||
|  | 
 | ||||||
| 		void EVENT_USB_Connect(void); | 		void EVENT_USB_Connect(void); | ||||||
| 		void EVENT_USB_Disconnect(void); | 		void EVENT_USB_Disconnect(void); | ||||||
| 		void EVENT_USB_ConfigurationChanged(void); | 		void EVENT_USB_ConfigurationChanged(void); | ||||||
| 		void EVENT_USB_UnhandledControlPacket(void); | 		void EVENT_USB_UnhandledControlPacket(void); | ||||||
|  | 		void EVENT_USB_StartOfFrame(void); | ||||||
| 
 | 
 | ||||||
| 		void CreateMouseReport(USB_MouseReport_Data_t* ReportData); | 		uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData); | ||||||
| 		void UpdateStatus(uint8_t CurrentStatus); | 		void     CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, | ||||||
|  | 		                                                   void* ReportData, uint16_t ReportSize); | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -125,7 +125,6 @@ LUFA_PATH = ../../.. | |||||||
| # List C source files here. (C dependencies are automatically generated.)
 | # List C source files here. (C dependencies are automatically generated.)
 | ||||||
| SRC = $(TARGET).c                                                 \
 | SRC = $(TARGET).c                                                 \
 | ||||||
| 	  Descriptors.c                                               \
 | 	  Descriptors.c                                               \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | ||||||
| @ -136,7 +135,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/HID.c            \
 | ||||||
|   |   | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
| CPPSRC =  | CPPSRC =  | ||||||
| @ -182,7 +181,7 @@ CSTANDARD = -std=gnu99 | |||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for C sources
 | # Place -D or -U options here for C sources
 | ||||||
| CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | ||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY | ||||||
| CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | ||||||
| CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -40,8 +40,6 @@ | |||||||
| 		#include <avr/io.h> | 		#include <avr/io.h> | ||||||
| 		#include <string.h> | 		#include <string.h> | ||||||
| 		 | 		 | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h> |  | ||||||
| 		 |  | ||||||
| 		#include "EthernetProtocols.h" | 		#include "EthernetProtocols.h" | ||||||
| 		#include "Ethernet.h" | 		#include "Ethernet.h" | ||||||
| 		#include "ProtocolDecoders.h" | 		#include "ProtocolDecoders.h" | ||||||
|  | |||||||
| @ -38,12 +38,6 @@ | |||||||
| #include "Ethernet.h" | #include "Ethernet.h" | ||||||
| 
 | 
 | ||||||
| /* Global Variables: */ | /* Global Variables: */ | ||||||
| /** Ethernet Frame buffer structure, to hold the incoming Ethernet frame from the host. */ |  | ||||||
| Ethernet_Frame_Info_t FrameIN; |  | ||||||
| 
 |  | ||||||
| /** Ethernet Frame buffer structure, to hold the outgoing Ethernet frame to the host. */ |  | ||||||
| Ethernet_Frame_Info_t FrameOUT; |  | ||||||
| 
 |  | ||||||
| /** Constant for convenience when checking against or setting a MAC address to the virtual server MAC address. */ | /** Constant for convenience when checking against or setting a MAC address to the virtual server MAC address. */ | ||||||
| const MAC_Address_t ServerMACAddress    = {SERVER_MAC_ADDRESS}; | const MAC_Address_t ServerMACAddress    = {SERVER_MAC_ADDRESS}; | ||||||
| 
 | 
 | ||||||
| @ -63,31 +57,31 @@ const IP_Address_t  ClientIPAddress     = {CLIENT_IP_ADDRESS}; | |||||||
| /** Processes an incoming Ethernet frame, and writes the appropriate response to the output Ethernet
 | /** Processes an incoming Ethernet frame, and writes the appropriate response to the output Ethernet
 | ||||||
|  *  frame buffer if the sub protocol handlers create a valid response. |  *  frame buffer if the sub protocol handlers create a valid response. | ||||||
|  */ |  */ | ||||||
| void Ethernet_ProcessPacket(void) | void Ethernet_ProcessPacket(Ethernet_Frame_Info_t* FrameIN, Ethernet_Frame_Info_t* FrameOUT) | ||||||
| { | { | ||||||
| 	DecodeEthernetFrameHeader(FrameIN.FrameData); | 	DecodeEthernetFrameHeader(FrameIN->FrameData); | ||||||
| 
 | 
 | ||||||
| 	/* Cast the incoming Ethernet frame to the Ethernet header type */ | 	/* Cast the incoming Ethernet frame to the Ethernet header type */ | ||||||
| 	Ethernet_Frame_Header_t* FrameINHeader  = (Ethernet_Frame_Header_t*)&FrameIN.FrameData; | 	Ethernet_Frame_Header_t* FrameINHeader  = (Ethernet_Frame_Header_t*)&FrameIN->FrameData; | ||||||
| 	Ethernet_Frame_Header_t* FrameOUTHeader = (Ethernet_Frame_Header_t*)&FrameOUT.FrameData; | 	Ethernet_Frame_Header_t* FrameOUTHeader = (Ethernet_Frame_Header_t*)&FrameOUT->FrameData; | ||||||
| 	 | 	 | ||||||
| 	int16_t                  RetSize        = NO_RESPONSE; | 	int16_t                  RetSize        = NO_RESPONSE; | ||||||
| 	 | 	 | ||||||
| 	/* Ensure frame is addressed to either all (broadcast) or the virtual webserver, and is a type II frame */ | 	/* Ensure frame is addressed to either all (broadcast) or the virtual webserver, and is a type II frame */ | ||||||
| 	if ((MAC_COMPARE(&FrameINHeader->Destination, &ServerMACAddress) || | 	if ((MAC_COMPARE(&FrameINHeader->Destination, &ServerMACAddress) || | ||||||
| 	     MAC_COMPARE(&FrameINHeader->Destination, &BroadcastMACAddress)) && | 	     MAC_COMPARE(&FrameINHeader->Destination, &BroadcastMACAddress))) | ||||||
| 		(SwapEndian_16(FrameIN.FrameLength) > ETHERNET_VER2_MINSIZE)) |  | ||||||
| 	{ | 	{ | ||||||
| 		/* Process the packet depending on its protocol */ | 		/* Process the packet depending on its protocol */ | ||||||
| 		switch (SwapEndian_16(FrameINHeader->EtherType)) | 		switch (SwapEndian_16(FrameINHeader->EtherType)) | ||||||
| 		{ | 		{ | ||||||
| 			case ETHERTYPE_ARP: | 			case ETHERTYPE_ARP: | ||||||
| 				RetSize = ARP_ProcessARPPacket(&FrameIN.FrameData[sizeof(Ethernet_Frame_Header_t)], | 				RetSize = ARP_ProcessARPPacket(&FrameIN->FrameData[sizeof(Ethernet_Frame_Header_t)], | ||||||
| 				                               &FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t)]); | 				                               &FrameOUT->FrameData[sizeof(Ethernet_Frame_Header_t)]); | ||||||
| 				break;		 | 				break;		 | ||||||
| 			case ETHERTYPE_IPV4: | 			case ETHERTYPE_IPV4: | ||||||
| 				RetSize = IP_ProcessIPPacket(&FrameIN.FrameData[sizeof(Ethernet_Frame_Header_t)], | 				RetSize = IP_ProcessIPPacket(FrameIN, | ||||||
| 				                             &FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t)]); | 				                             &FrameIN->FrameData[sizeof(Ethernet_Frame_Header_t)], | ||||||
|  | 				                             &FrameOUT->FrameData[sizeof(Ethernet_Frame_Header_t)]); | ||||||
| 				break; | 				break; | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| @ -100,8 +94,8 @@ void Ethernet_ProcessPacket(void) | |||||||
| 			FrameOUTHeader->EtherType       = FrameINHeader->EtherType; | 			FrameOUTHeader->EtherType       = FrameINHeader->EtherType; | ||||||
| 			 | 			 | ||||||
| 			/* Set the response length in the buffer and indicate that a response is ready to be sent */ | 			/* Set the response length in the buffer and indicate that a response is ready to be sent */ | ||||||
| 			FrameOUT.FrameLength            = (sizeof(Ethernet_Frame_Header_t) + RetSize); | 			FrameOUT->FrameLength           = (sizeof(Ethernet_Frame_Header_t) + RetSize); | ||||||
| 			FrameOUT.FrameInBuffer          = true; | 			FrameOUT->FrameInBuffer         = true; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -109,7 +103,7 @@ void Ethernet_ProcessPacket(void) | |||||||
| 	if (RetSize != NO_PROCESS) | 	if (RetSize != NO_PROCESS) | ||||||
| 	{ | 	{ | ||||||
| 		/* Clear the frame buffer */ | 		/* Clear the frame buffer */ | ||||||
| 		FrameIN.FrameInBuffer = false; | 		FrameIN->FrameInBuffer = false; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -40,6 +40,8 @@ | |||||||
| 		#include <avr/io.h> | 		#include <avr/io.h> | ||||||
| 		#include <string.h> | 		#include <string.h> | ||||||
| 		 | 		 | ||||||
|  | 		#include <LUFA/Drivers/USB/Class/Device/RNDIS.h> | ||||||
|  | 
 | ||||||
| 		#include "EthernetProtocols.h" | 		#include "EthernetProtocols.h" | ||||||
| 		#include "ProtocolDecoders.h" | 		#include "ProtocolDecoders.h" | ||||||
| 		#include "ICMP.h" | 		#include "ICMP.h" | ||||||
| @ -50,6 +52,9 @@ | |||||||
| 		#include "IP.h" | 		#include "IP.h" | ||||||
| 		 | 		 | ||||||
| 	/* Macros: */ | 	/* Macros: */ | ||||||
|  | 		/** Physical MAC address of the USB RNDIS network adapter */ | ||||||
|  | 		#define ADAPTER_MAC_ADDRESS              {0x00, 0x02, 0x00, 0x02, 0x00, 0x02}		 | ||||||
|  | 
 | ||||||
| 		/** Physical MAC address of the virtual server on the network */ | 		/** Physical MAC address of the virtual server on the network */ | ||||||
| 		#define SERVER_MAC_ADDRESS               {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}		 | 		#define SERVER_MAC_ADDRESS               {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}		 | ||||||
| 
 | 
 | ||||||
| @ -65,12 +70,6 @@ | |||||||
| 		 */ | 		 */ | ||||||
| 		#define MAC_COMPARE(MAC1, MAC2)          (memcmp(MAC1, MAC2, sizeof(MAC_Address_t)) == 0) | 		#define MAC_COMPARE(MAC1, MAC2)          (memcmp(MAC1, MAC2, sizeof(MAC_Address_t)) == 0) | ||||||
| 		 | 		 | ||||||
| 		/** Maximum size of an incoming or outgoing Ethernet frame in bytes */ |  | ||||||
| 		#define ETHERNET_FRAME_SIZE_MAX          1500 |  | ||||||
| 		 |  | ||||||
| 		/** Minimum size of an Ethernet packet in bytes, to conform to the Ethernet V2 packet standard */ |  | ||||||
| 		#define ETHERNET_VER2_MINSIZE            0x0600 |  | ||||||
| 		 |  | ||||||
| 		/** Return value for all sub protocol handling routines, indicating that no response packet has been generated */ | 		/** Return value for all sub protocol handling routines, indicating that no response packet has been generated */ | ||||||
| 		#define NO_RESPONSE                      0		 | 		#define NO_RESPONSE                      0		 | ||||||
| 
 | 
 | ||||||
| @ -78,14 +77,6 @@ | |||||||
| 		#define NO_PROCESS                       -1 | 		#define NO_PROCESS                       -1 | ||||||
| 
 | 
 | ||||||
| 	/* Type Defines: */ | 	/* Type Defines: */ | ||||||
| 		/** Type define for an Ethernet frame buffer. */ |  | ||||||
| 		typedef struct |  | ||||||
| 		{ |  | ||||||
| 			uint8_t       FrameData[ETHERNET_FRAME_SIZE_MAX]; /**< Ethernet frame contents */ |  | ||||||
| 			uint16_t      FrameLength; /**< Length in bytes of the Ethernet frame stored in the buffer */ |  | ||||||
| 			bool          FrameInBuffer; /**< Indicates if a frame is currently stored in the buffer */ |  | ||||||
| 		} Ethernet_Frame_Info_t; |  | ||||||
| 
 |  | ||||||
| 		/** Type define for an Ethernet frame header */ | 		/** Type define for an Ethernet frame header */ | ||||||
| 		typedef struct | 		typedef struct | ||||||
| 		{ | 		{ | ||||||
| @ -100,9 +91,6 @@ | |||||||
| 		} Ethernet_Frame_Header_t; | 		} Ethernet_Frame_Header_t; | ||||||
| 		 | 		 | ||||||
| 	/* External Variables: */ | 	/* External Variables: */ | ||||||
| 		extern Ethernet_Frame_Info_t FrameIN; |  | ||||||
| 		extern Ethernet_Frame_Info_t FrameOUT; |  | ||||||
| 
 |  | ||||||
| 		extern const MAC_Address_t ServerMACAddress; | 		extern const MAC_Address_t ServerMACAddress; | ||||||
| 		extern const IP_Address_t  ServerIPAddress; | 		extern const IP_Address_t  ServerIPAddress; | ||||||
| 		extern const MAC_Address_t BroadcastMACAddress; | 		extern const MAC_Address_t BroadcastMACAddress; | ||||||
| @ -110,7 +98,7 @@ | |||||||
| 		extern const IP_Address_t  ClientIPAddress; | 		extern const IP_Address_t  ClientIPAddress; | ||||||
| 		 | 		 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
| 		void     Ethernet_ProcessPacket(void); | 		void     Ethernet_ProcessPacket(Ethernet_Frame_Info_t* FrameIN, Ethernet_Frame_Info_t* FrameOUT); | ||||||
| 		uint16_t Ethernet_Checksum16(void* Data, uint16_t Bytes); | 		uint16_t Ethernet_Checksum16(void* Data, uint16_t Bytes); | ||||||
| 		 | 		 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -72,12 +72,6 @@ | |||||||
| 		#define PROTOCOL_SCTP                    132 | 		#define PROTOCOL_SCTP                    132 | ||||||
| 
 | 
 | ||||||
| 	/* Type Defines: */		 | 	/* Type Defines: */		 | ||||||
| 		/** Type define for a physical MAC address of a device on a network */ |  | ||||||
| 		typedef struct |  | ||||||
| 		{ |  | ||||||
| 			uint8_t       Octets[6]; /**< Individual bytes of a MAC address */ |  | ||||||
| 		} MAC_Address_t; |  | ||||||
| 		 |  | ||||||
| 		/** Type define for a protocol IP address of a device on a network */ | 		/** Type define for a protocol IP address of a device on a network */ | ||||||
| 		typedef struct | 		typedef struct | ||||||
| 		{ | 		{ | ||||||
|  | |||||||
| @ -45,7 +45,7 @@ | |||||||
|  * |  * | ||||||
|  *  \return The number of bytes written to the out Ethernet frame if any, NO_RESPONSE otherwise |  *  \return The number of bytes written to the out Ethernet frame if any, NO_RESPONSE otherwise | ||||||
|  */ |  */ | ||||||
| int16_t ICMP_ProcessICMPPacket(void* InDataStart, void* OutDataStart) | int16_t ICMP_ProcessICMPPacket(Ethernet_Frame_Info_t* FrameIN, void* InDataStart, void* OutDataStart) | ||||||
| { | { | ||||||
| 	ICMP_Header_t* ICMPHeaderIN  = (ICMP_Header_t*)InDataStart; | 	ICMP_Header_t* ICMPHeaderIN  = (ICMP_Header_t*)InDataStart; | ||||||
| 	ICMP_Header_t* ICMPHeaderOUT = (ICMP_Header_t*)OutDataStart; | 	ICMP_Header_t* ICMPHeaderOUT = (ICMP_Header_t*)OutDataStart; | ||||||
| @ -62,7 +62,7 @@ int16_t ICMP_ProcessICMPPacket(void* InDataStart, void* OutDataStart) | |||||||
| 		ICMPHeaderOUT->Id       = ICMPHeaderIN->Id; | 		ICMPHeaderOUT->Id       = ICMPHeaderIN->Id; | ||||||
| 		ICMPHeaderOUT->Sequence = ICMPHeaderIN->Sequence; | 		ICMPHeaderOUT->Sequence = ICMPHeaderIN->Sequence; | ||||||
| 		 | 		 | ||||||
| 		uint16_t DataSize = FrameIN.FrameLength - ((((uint16_t)InDataStart + sizeof(ICMP_Header_t)) - (uint16_t)FrameIN.FrameData)); | 		uint16_t DataSize = FrameIN->FrameLength - ((((uint16_t)InDataStart + sizeof(ICMP_Header_t)) - (uint16_t)FrameIN->FrameData)); | ||||||
| 		 | 		 | ||||||
| 		/* Copy the remaining payload to the response - echo requests should echo back any sent data */ | 		/* Copy the remaining payload to the response - echo requests should echo back any sent data */ | ||||||
| 		memcpy(&((uint8_t*)OutDataStart)[sizeof(ICMP_Header_t)], | 		memcpy(&((uint8_t*)OutDataStart)[sizeof(ICMP_Header_t)], | ||||||
|  | |||||||
| @ -75,6 +75,6 @@ | |||||||
| 		} ICMP_Header_t; | 		} ICMP_Header_t; | ||||||
| 		 | 		 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
| 		int16_t ICMP_ProcessICMPPacket(void* InDataStart, void* OutDataStart); | 		int16_t ICMP_ProcessICMPPacket(Ethernet_Frame_Info_t* FrameIN, void* InDataStart, void* OutDataStart); | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ | |||||||
|  *           response was generated, NO_PROCESS if the packet processing was deferred until the |  *           response was generated, NO_PROCESS if the packet processing was deferred until the | ||||||
|  *           next Ethernet packet handler iteration |  *           next Ethernet packet handler iteration | ||||||
|  */ |  */ | ||||||
| int16_t IP_ProcessIPPacket(void* InDataStart, void* OutDataStart) | int16_t IP_ProcessIPPacket(Ethernet_Frame_Info_t* FrameIN, void* InDataStart, void* OutDataStart) | ||||||
| { | { | ||||||
| 	DecodeIPHeader(InDataStart); | 	DecodeIPHeader(InDataStart); | ||||||
| 
 | 
 | ||||||
| @ -69,7 +69,8 @@ int16_t IP_ProcessIPPacket(void* InDataStart, void* OutDataStart) | |||||||
| 	switch (IPHeaderIN->Protocol) | 	switch (IPHeaderIN->Protocol) | ||||||
| 	{ | 	{ | ||||||
| 		case PROTOCOL_ICMP: | 		case PROTOCOL_ICMP: | ||||||
| 			RetSize = ICMP_ProcessICMPPacket(&((uint8_t*)InDataStart)[HeaderLengthBytes], | 			RetSize = ICMP_ProcessICMPPacket(FrameIN, | ||||||
|  | 			                                 &((uint8_t*)InDataStart)[HeaderLengthBytes], | ||||||
| 			                                 &((uint8_t*)OutDataStart)[sizeof(IP_Header_t)]); | 			                                 &((uint8_t*)OutDataStart)[sizeof(IP_Header_t)]); | ||||||
| 			break; | 			break; | ||||||
| 		case PROTOCOL_TCP: | 		case PROTOCOL_TCP: | ||||||
|  | |||||||
| @ -88,6 +88,6 @@ | |||||||
| 		} IP_Header_t; | 		} IP_Header_t; | ||||||
| 		 | 		 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
| 		int16_t IP_ProcessIPPacket(void* InDataStart, void* OutDataStart); | 		int16_t IP_ProcessIPPacket(Ethernet_Frame_Info_t* FrameIN, void* InDataStart, void* OutDataStart); | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -1,394 +0,0 @@ | |||||||
| /*
 |  | ||||||
|              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
 |  | ||||||
|  * |  | ||||||
|  *  RNDIS command handler functions. This handles RNDIS commands according to |  | ||||||
|  *  the Microsoft RNDIS specification, creating a USB Ethernet network adapter. |  | ||||||
|  */ |  | ||||||
|   |  | ||||||
| #define  INCLUDE_FROM_RNDIS_C |  | ||||||
| #include "RNDIS.h" |  | ||||||
| 
 |  | ||||||
| /* Global Variables: */ |  | ||||||
| /** Physical MAC address of the network adapter, which becomes the MAC address of the host for packets sent to the adapter. */ |  | ||||||
| static MAC_Address_t  PROGMEM AdapterMACAddress          = {ADAPTER_MAC_ADDRESS}; |  | ||||||
| 
 |  | ||||||
| /** Vendor description of the adapter. This is overridden by the INF file required to install the appropriate RNDIS drivers for
 |  | ||||||
|  *  the device, but may still be used by the OS in some circumstances. |  | ||||||
|  */ |  | ||||||
| static char           PROGMEM AdapterVendorDescription[] = "LUFA RNDIS Adapter"; |  | ||||||
| 
 |  | ||||||
| /** List of RNDIS OID commands supported by this adapter. */ |  | ||||||
| static const uint32_t PROGMEM AdapterSupportedOIDList[]  = |  | ||||||
| 							{ |  | ||||||
| 								OID_GEN_SUPPORTED_LIST, |  | ||||||
| 								OID_GEN_PHYSICAL_MEDIUM, |  | ||||||
| 								OID_GEN_HARDWARE_STATUS, |  | ||||||
| 								OID_GEN_MEDIA_SUPPORTED, |  | ||||||
| 								OID_GEN_MEDIA_IN_USE, |  | ||||||
| 								OID_GEN_MAXIMUM_FRAME_SIZE, |  | ||||||
| 								OID_GEN_MAXIMUM_TOTAL_SIZE, |  | ||||||
| 								OID_GEN_LINK_SPEED, |  | ||||||
| 								OID_GEN_TRANSMIT_BLOCK_SIZE, |  | ||||||
| 								OID_GEN_RECEIVE_BLOCK_SIZE, |  | ||||||
| 								OID_GEN_VENDOR_ID, |  | ||||||
| 								OID_GEN_VENDOR_DESCRIPTION, |  | ||||||
| 								OID_GEN_CURRENT_PACKET_FILTER, |  | ||||||
| 								OID_GEN_MAXIMUM_TOTAL_SIZE, |  | ||||||
| 								OID_GEN_MEDIA_CONNECT_STATUS, |  | ||||||
| 								OID_GEN_XMIT_OK, |  | ||||||
| 								OID_GEN_RCV_OK, |  | ||||||
| 								OID_GEN_XMIT_ERROR, |  | ||||||
| 								OID_GEN_RCV_ERROR, |  | ||||||
| 								OID_GEN_RCV_NO_BUFFER, |  | ||||||
| 								OID_802_3_PERMANENT_ADDRESS, |  | ||||||
| 								OID_802_3_CURRENT_ADDRESS, |  | ||||||
| 								OID_802_3_MULTICAST_LIST, |  | ||||||
| 								OID_802_3_MAXIMUM_LIST_SIZE, |  | ||||||
| 								OID_802_3_RCV_ERROR_ALIGNMENT, |  | ||||||
| 								OID_802_3_XMIT_ONE_COLLISION, |  | ||||||
| 								OID_802_3_XMIT_MORE_COLLISIONS, |  | ||||||
| 							}; |  | ||||||
| 
 |  | ||||||
| /** Buffer for RNDIS messages (as distinct from Ethernet frames sent through the adapter. This must be big enough to hold the entire
 |  | ||||||
|  *  Supported OID list, plus the response header. The buffer is half-duplex, and is written to as it is read to save on SRAM - for this |  | ||||||
|  *  reason, care must be taken when constructing RNDIS responses that unread data is not overwritten when writing in responses. |  | ||||||
|  */ |  | ||||||
| uint8_t                 RNDISMessageBuffer[sizeof(AdapterSupportedOIDList) + sizeof(RNDIS_QUERY_CMPLT_t)]; |  | ||||||
| 
 |  | ||||||
| /** Pointer to the RNDIS message header at the top of the RNDIS message buffer, for convenience. */ |  | ||||||
| RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISMessageBuffer; |  | ||||||
| 
 |  | ||||||
| /** Indicates if a RNDIS message response is ready to be sent back to the host. */ |  | ||||||
| bool                    ResponseReady               = false; |  | ||||||
| 
 |  | ||||||
| /** Current RNDIS adapter state, a value from the RNDIS_States_t enum. */ |  | ||||||
| uint8_t                 CurrRNDISState              = RNDIS_Uninitialized; |  | ||||||
| 
 |  | ||||||
| /** Current Ethernet packet filter mask. This is non-zero when the adapter is initialized, or zero when disabled. */ |  | ||||||
| uint32_t                CurrPacketFilter            = 0;							 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /** Processes the RNDIS message received by the host and stored in the RNDISMessageBuffer global buffer. If a response is
 |  | ||||||
|  *  created, the ResponseReady global is updated so that the response is written back to the host upon request. |  | ||||||
|  */ |  | ||||||
| void ProcessRNDISControlMessage(void) |  | ||||||
| { |  | ||||||
| 	/* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of
 |  | ||||||
| 	         this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */ |  | ||||||
| 
 |  | ||||||
| 	switch (MessageHeader->MessageType) |  | ||||||
| 	{ |  | ||||||
| 		case REMOTE_NDIS_INITIALIZE_MSG: |  | ||||||
| 			/* Initialize the adapter - return information about the supported RNDIS version and buffer sizes */ |  | ||||||
| 
 |  | ||||||
| 			ResponseReady = true; |  | ||||||
| 			 |  | ||||||
| 			RNDIS_INITIALIZE_MSG_t*   INITIALIZE_Message  = (RNDIS_INITIALIZE_MSG_t*)&RNDISMessageBuffer; |  | ||||||
| 			RNDIS_INITIALIZE_CMPLT_t* INITIALIZE_Response = (RNDIS_INITIALIZE_CMPLT_t*)&RNDISMessageBuffer; |  | ||||||
| 			 |  | ||||||
| 			INITIALIZE_Response->MessageType           = REMOTE_NDIS_INITIALIZE_CMPLT; |  | ||||||
| 			INITIALIZE_Response->MessageLength         = sizeof(RNDIS_INITIALIZE_CMPLT_t); |  | ||||||
| 			INITIALIZE_Response->RequestId             = INITIALIZE_Message->RequestId; |  | ||||||
| 			INITIALIZE_Response->Status                = REMOTE_NDIS_STATUS_SUCCESS; |  | ||||||
| 			 |  | ||||||
| 			INITIALIZE_Response->MajorVersion          = REMOTE_NDIS_VERSION_MAJOR; |  | ||||||
| 			INITIALIZE_Response->MinorVersion          = REMOTE_NDIS_VERSION_MINOR;			 |  | ||||||
| 			INITIALIZE_Response->DeviceFlags           = REMOTE_NDIS_DF_CONNECTIONLESS; |  | ||||||
| 			INITIALIZE_Response->Medium                = REMOTE_NDIS_MEDIUM_802_3; |  | ||||||
| 			INITIALIZE_Response->MaxPacketsPerTransfer = 1; |  | ||||||
| 			INITIALIZE_Response->MaxTransferSize       = (sizeof(RNDIS_PACKET_MSG_t) + ETHERNET_FRAME_SIZE_MAX); |  | ||||||
| 			INITIALIZE_Response->PacketAlignmentFactor = 0; |  | ||||||
| 			INITIALIZE_Response->AFListOffset          = 0; |  | ||||||
| 			INITIALIZE_Response->AFListSize            = 0; |  | ||||||
| 			 |  | ||||||
| 			CurrRNDISState = RNDIS_Initialized; |  | ||||||
| 		 |  | ||||||
| 			break; |  | ||||||
| 		case REMOTE_NDIS_HALT_MSG: |  | ||||||
| 			/* Halt the adapter, reset the adapter state - note that no response should be returned when completed */ |  | ||||||
| 
 |  | ||||||
| 			ResponseReady = false; |  | ||||||
| 			MessageHeader->MessageLength = 0; |  | ||||||
| 
 |  | ||||||
| 			CurrRNDISState = RNDIS_Uninitialized; |  | ||||||
| 
 |  | ||||||
| 			break; |  | ||||||
| 		case REMOTE_NDIS_QUERY_MSG: |  | ||||||
| 			/* Request for information about a parameter about the adapter, specified as an OID token */ |  | ||||||
| 
 |  | ||||||
| 			ResponseReady = true; |  | ||||||
| 						 |  | ||||||
| 			RNDIS_QUERY_MSG_t*   QUERY_Message  = (RNDIS_QUERY_MSG_t*)&RNDISMessageBuffer; |  | ||||||
| 			RNDIS_QUERY_CMPLT_t* QUERY_Response = (RNDIS_QUERY_CMPLT_t*)&RNDISMessageBuffer; |  | ||||||
| 			uint32_t             Query_Oid      = QUERY_Message->Oid; |  | ||||||
| 						 |  | ||||||
| 			void*     QueryData                 = &RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) + |  | ||||||
| 			                                                          QUERY_Message->InformationBufferOffset]; |  | ||||||
| 			void*     ResponseData              = &RNDISMessageBuffer[sizeof(RNDIS_QUERY_CMPLT_t)];		 |  | ||||||
| 			uint16_t  ResponseSize; |  | ||||||
| 
 |  | ||||||
| 			QUERY_Response->MessageType         = REMOTE_NDIS_QUERY_CMPLT; |  | ||||||
| 			QUERY_Response->MessageLength       = sizeof(RNDIS_QUERY_CMPLT_t); |  | ||||||
| 						 |  | ||||||
| 			if (ProcessNDISQuery(Query_Oid, QueryData, QUERY_Message->InformationBufferLength, |  | ||||||
| 			                     ResponseData, &ResponseSize)) |  | ||||||
| 			{ |  | ||||||
| 				QUERY_Response->Status                  = REMOTE_NDIS_STATUS_SUCCESS; |  | ||||||
| 				QUERY_Response->MessageLength          += ResponseSize; |  | ||||||
| 							 |  | ||||||
| 				QUERY_Response->InformationBufferLength = ResponseSize; |  | ||||||
| 				QUERY_Response->InformationBufferOffset = (sizeof(RNDIS_QUERY_CMPLT_t) - sizeof(RNDIS_Message_Header_t)); |  | ||||||
| 			} |  | ||||||
| 			else |  | ||||||
| 			{				 |  | ||||||
| 				QUERY_Response->Status                  = REMOTE_NDIS_STATUS_NOT_SUPPORTED; |  | ||||||
| 
 |  | ||||||
| 				QUERY_Response->InformationBufferLength = 0; |  | ||||||
| 				QUERY_Response->InformationBufferOffset = 0; |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 		case REMOTE_NDIS_SET_MSG: |  | ||||||
| 			/* Request to set a parameter of the adapter, specified as an OID token */ |  | ||||||
| 		 |  | ||||||
| 			ResponseReady = true; |  | ||||||
| 			 |  | ||||||
| 			RNDIS_SET_MSG_t*   SET_Message  = (RNDIS_SET_MSG_t*)&RNDISMessageBuffer; |  | ||||||
| 			RNDIS_SET_CMPLT_t* SET_Response = (RNDIS_SET_CMPLT_t*)&RNDISMessageBuffer; |  | ||||||
| 			uint32_t           SET_Oid      = SET_Message->Oid; |  | ||||||
| 
 |  | ||||||
| 			SET_Response->MessageType       = REMOTE_NDIS_SET_CMPLT; |  | ||||||
| 			SET_Response->MessageLength     = sizeof(RNDIS_SET_CMPLT_t); |  | ||||||
| 			SET_Response->RequestId         = SET_Message->RequestId; |  | ||||||
| 
 |  | ||||||
| 			void* SetData                   = &RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) + |  | ||||||
| 			                                                      SET_Message->InformationBufferOffset]; |  | ||||||
| 						 |  | ||||||
| 			if (ProcessNDISSet(SET_Oid, SetData, SET_Message->InformationBufferLength)) |  | ||||||
| 			  SET_Response->Status        = REMOTE_NDIS_STATUS_SUCCESS; |  | ||||||
| 			else |  | ||||||
| 			  SET_Response->Status        = REMOTE_NDIS_STATUS_NOT_SUPPORTED; |  | ||||||
| 
 |  | ||||||
| 			break; |  | ||||||
| 		case REMOTE_NDIS_RESET_MSG: |  | ||||||
| 			/* Soft reset the adapter */ |  | ||||||
| 		 |  | ||||||
| 			ResponseReady = true; |  | ||||||
| 			 |  | ||||||
| 			RNDIS_RESET_CMPLT_t* RESET_Response = (RNDIS_RESET_CMPLT_t*)&RNDISMessageBuffer; |  | ||||||
| 
 |  | ||||||
| 			RESET_Response->MessageType         = REMOTE_NDIS_RESET_CMPLT; |  | ||||||
| 			RESET_Response->MessageLength       = sizeof(RNDIS_RESET_CMPLT_t); |  | ||||||
| 			RESET_Response->Status              = REMOTE_NDIS_STATUS_SUCCESS; |  | ||||||
| 			RESET_Response->AddressingReset     = 0; |  | ||||||
| 
 |  | ||||||
| 			break; |  | ||||||
| 		case REMOTE_NDIS_KEEPALIVE_MSG: |  | ||||||
| 			/* Keep alive message sent to the adapter every 5 seconds when idle to ensure it is still responding */ |  | ||||||
| 		 |  | ||||||
| 			ResponseReady = true; |  | ||||||
| 			 |  | ||||||
| 			RNDIS_KEEPALIVE_MSG_t*   KEEPALIVE_Message  = (RNDIS_KEEPALIVE_MSG_t*)&RNDISMessageBuffer; |  | ||||||
| 			RNDIS_KEEPALIVE_CMPLT_t* KEEPALIVE_Response = (RNDIS_KEEPALIVE_CMPLT_t*)&RNDISMessageBuffer; |  | ||||||
| 
 |  | ||||||
| 			KEEPALIVE_Response->MessageType     = REMOTE_NDIS_KEEPALIVE_CMPLT; |  | ||||||
| 			KEEPALIVE_Response->MessageLength   = sizeof(RNDIS_KEEPALIVE_CMPLT_t); |  | ||||||
| 			KEEPALIVE_Response->RequestId       = KEEPALIVE_Message->RequestId; |  | ||||||
| 			KEEPALIVE_Response->Status          = REMOTE_NDIS_STATUS_SUCCESS; |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Processes RNDIS query commands, retrieving information from the adapter and reporting it back to the host. The requested
 |  | ||||||
|  *  parameter is given as an OID value. |  | ||||||
|  * |  | ||||||
|  *  \param OId           OId value of the parameter being queried |  | ||||||
|  *  \param QueryData     Pointer to any extra query data being sent by the host to the device inside the RNDIS message buffer |  | ||||||
|  *  \param QuerySize     Size in bytes of the extra query data being sent by the host |  | ||||||
|  *  \param ResponseData  Pointer to the start of the query response inside the RNDIS message buffer |  | ||||||
|  *  \param ResponseSize  Pointer to the size in bytes of the response data being sent to the host |  | ||||||
|  * |  | ||||||
|  *  \return Boolean true if the query was handled, false otherwise |  | ||||||
|  */ |  | ||||||
| static bool ProcessNDISQuery(uint32_t OId, void* QueryData, uint16_t QuerySize, |  | ||||||
|                              void* ResponseData, uint16_t* ResponseSize) |  | ||||||
| { |  | ||||||
| 	/* Handler for REMOTE_NDIS_QUERY_MSG messages */ |  | ||||||
| 
 |  | ||||||
| 	switch (OId) |  | ||||||
| 	{ |  | ||||||
| 		case OID_GEN_SUPPORTED_LIST: |  | ||||||
| 			*ResponseSize = sizeof(AdapterSupportedOIDList); |  | ||||||
| 			 |  | ||||||
| 			/* Copy the list of supported NDIS OID tokens to the response buffer */ |  | ||||||
| 			memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList)); |  | ||||||
| 			 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_GEN_PHYSICAL_MEDIUM: |  | ||||||
| 			*ResponseSize = sizeof(uint32_t); |  | ||||||
| 			 |  | ||||||
| 			/* Indicate that the device is a true ethernet link */ |  | ||||||
| 			*((uint32_t*)ResponseData) = 0; |  | ||||||
| 			 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_GEN_HARDWARE_STATUS: |  | ||||||
| 			*ResponseSize = sizeof(uint32_t); |  | ||||||
| 			 |  | ||||||
| 			/* Always indicate hardware ready */ |  | ||||||
| 			*((uint32_t*)ResponseData) = NdisHardwareStatusReady; |  | ||||||
| 			 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_GEN_MEDIA_SUPPORTED: |  | ||||||
| 		case OID_GEN_MEDIA_IN_USE: |  | ||||||
| 			*ResponseSize = sizeof(uint32_t); |  | ||||||
| 			 |  | ||||||
| 			/* Indicate 802.3 (Ethernet) supported by the adapter */ |  | ||||||
| 			*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIUM_802_3; |  | ||||||
| 			 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_GEN_VENDOR_ID: |  | ||||||
| 			*ResponseSize = sizeof(uint32_t); |  | ||||||
| 			 |  | ||||||
| 			/* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */ |  | ||||||
| 			*((uint32_t*)ResponseData) = 0x00FFFFFF; |  | ||||||
| 			 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_GEN_MAXIMUM_FRAME_SIZE: |  | ||||||
| 		case OID_GEN_TRANSMIT_BLOCK_SIZE: |  | ||||||
| 		case OID_GEN_RECEIVE_BLOCK_SIZE: |  | ||||||
| 			*ResponseSize = sizeof(uint32_t); |  | ||||||
| 			 |  | ||||||
| 			/* Indicate that the maximum frame size is the size of the ethernet frame buffer */ |  | ||||||
| 			*((uint32_t*)ResponseData) = ETHERNET_FRAME_SIZE_MAX; |  | ||||||
| 			 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_GEN_VENDOR_DESCRIPTION: |  | ||||||
| 			*ResponseSize = sizeof(AdapterVendorDescription); |  | ||||||
| 			 |  | ||||||
| 			/* Copy vendor description string to the response buffer */ |  | ||||||
| 			memcpy_P(ResponseData, AdapterVendorDescription, sizeof(AdapterVendorDescription)); |  | ||||||
| 			 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_GEN_MEDIA_CONNECT_STATUS: |  | ||||||
| 			*ResponseSize = sizeof(uint32_t); |  | ||||||
| 			 |  | ||||||
| 			/* Always indicate that the adapter is connected to a network */ |  | ||||||
| 			*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIA_STATE_CONNECTED; |  | ||||||
| 			 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_GEN_LINK_SPEED: |  | ||||||
| 			*ResponseSize = sizeof(uint32_t); |  | ||||||
| 			 |  | ||||||
| 			/* Indicate 10Mb/s link speed */ |  | ||||||
| 			*((uint32_t*)ResponseData) = 100000; |  | ||||||
| 
 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_802_3_PERMANENT_ADDRESS: |  | ||||||
| 		case OID_802_3_CURRENT_ADDRESS: |  | ||||||
| 			*ResponseSize = sizeof(MAC_Address_t); |  | ||||||
| 			 |  | ||||||
| 			/* Copy over the fixed adapter MAC to the response buffer */ |  | ||||||
| 			memcpy_P(ResponseData, &AdapterMACAddress, sizeof(MAC_Address_t)); |  | ||||||
| 
 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_802_3_MAXIMUM_LIST_SIZE: |  | ||||||
| 			*ResponseSize = sizeof(uint32_t); |  | ||||||
| 			 |  | ||||||
| 			/* Indicate only one multicast address supported */ |  | ||||||
| 			*((uint32_t*)ResponseData) = 1; |  | ||||||
| 		 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_GEN_CURRENT_PACKET_FILTER: |  | ||||||
| 			*ResponseSize = sizeof(uint32_t); |  | ||||||
| 			 |  | ||||||
| 			/* Indicate the current packet filter mask */ |  | ||||||
| 			*((uint32_t*)ResponseData) = CurrPacketFilter; |  | ||||||
| 		 |  | ||||||
| 			return true;			 |  | ||||||
| 		case OID_GEN_XMIT_OK: |  | ||||||
| 		case OID_GEN_RCV_OK: |  | ||||||
| 		case OID_GEN_XMIT_ERROR: |  | ||||||
| 		case OID_GEN_RCV_ERROR: |  | ||||||
| 		case OID_GEN_RCV_NO_BUFFER: |  | ||||||
| 		case OID_802_3_RCV_ERROR_ALIGNMENT: |  | ||||||
| 		case OID_802_3_XMIT_ONE_COLLISION: |  | ||||||
| 		case OID_802_3_XMIT_MORE_COLLISIONS: |  | ||||||
| 			*ResponseSize = sizeof(uint32_t); |  | ||||||
| 			 |  | ||||||
| 			/* Unused statistic OIDs - always return 0 for each */ |  | ||||||
| 			*((uint32_t*)ResponseData) = 0; |  | ||||||
| 		 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_GEN_MAXIMUM_TOTAL_SIZE: |  | ||||||
| 			*ResponseSize = sizeof(uint32_t); |  | ||||||
| 			 |  | ||||||
| 			/* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */ |  | ||||||
| 			*((uint32_t*)ResponseData) = (sizeof(RNDISMessageBuffer) + ETHERNET_FRAME_SIZE_MAX); |  | ||||||
| 		 |  | ||||||
| 			return true; |  | ||||||
| 		default: |  | ||||||
| 			return false; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Processes RNDIS set commands, setting adapter parameters to values given by the host. The requested parameter is given 
 |  | ||||||
|  *  as an OID value. |  | ||||||
|  * |  | ||||||
|  *  \param OId      OId value of the parameter being set |  | ||||||
|  *  \param SetData  Pointer to the parameter value in the RNDIS message buffer |  | ||||||
|  *  \param SetSize  Size in bytes of the parameter value being sent by the host |  | ||||||
|  * |  | ||||||
|  *  \return Boolean true if the set was handled, false otherwise |  | ||||||
|  */ |  | ||||||
| static bool ProcessNDISSet(uint32_t OId, void* SetData, uint16_t SetSize) |  | ||||||
| { |  | ||||||
| 	/* Handler for REMOTE_NDIS_SET_MSG messages */ |  | ||||||
| 
 |  | ||||||
| 	switch (OId) |  | ||||||
| 	{ |  | ||||||
| 		case OID_GEN_CURRENT_PACKET_FILTER: |  | ||||||
| 			/* Save the packet filter mask in case the host queries it again later */ |  | ||||||
| 			CurrPacketFilter = *((uint32_t*)SetData); |  | ||||||
| 		 |  | ||||||
| 			/* Set the RNDIS state to initialized if the packet filter is non-zero */ |  | ||||||
| 			CurrRNDISState = ((CurrPacketFilter) ? RNDIS_Data_Initialized : RNDIS_Data_Initialized); |  | ||||||
| 			 |  | ||||||
| 			return true; |  | ||||||
| 		case OID_802_3_MULTICAST_LIST: |  | ||||||
| 			/* Do nothing - throw away the value from the host as it is unused */ |  | ||||||
| 		 |  | ||||||
| 			return true; |  | ||||||
| 		default: |  | ||||||
| 			return false; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @ -56,7 +56,7 @@ TCP_ConnectionState_t  ConnectionStateTable[MAX_TCP_CONNECTIONS]; | |||||||
|  *  level. If an application produces a response, this task constructs the appropriate Ethernet frame and places it into the Ethernet OUT |  *  level. If an application produces a response, this task constructs the appropriate Ethernet frame and places it into the Ethernet OUT | ||||||
|  *  buffer for later transmission. |  *  buffer for later transmission. | ||||||
|  */ |  */ | ||||||
| TASK(TCP_Task) | void TCP_TCPTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo) | ||||||
| { | { | ||||||
| 	/* Task to hand off TCP packets to and from the listening applications. */ | 	/* Task to hand off TCP packets to and from the listening applications. */ | ||||||
| 
 | 
 | ||||||
| @ -76,7 +76,7 @@ TASK(TCP_Task) | |||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	/* Bail out early if there is already a frame waiting to be sent in the Ethernet OUT buffer */ | 	/* Bail out early if there is already a frame waiting to be sent in the Ethernet OUT buffer */ | ||||||
| 	if (FrameOUT.FrameInBuffer) | 	if (RNDISInterfaceInfo->FrameOUT.FrameInBuffer) | ||||||
| 	  return; | 	  return; | ||||||
| 	 | 	 | ||||||
| 	/* Send response packets from each application as the TCP packet buffers are filled by the applications */ | 	/* Send response packets from each application as the TCP packet buffers are filled by the applications */ | ||||||
| @ -86,13 +86,13 @@ TASK(TCP_Task) | |||||||
| 		if ((ConnectionStateTable[CSTableEntry].Info.Buffer.Direction == TCP_PACKETDIR_OUT) && | 		if ((ConnectionStateTable[CSTableEntry].Info.Buffer.Direction == TCP_PACKETDIR_OUT) && | ||||||
| 		    (ConnectionStateTable[CSTableEntry].Info.Buffer.Ready)) | 		    (ConnectionStateTable[CSTableEntry].Info.Buffer.Ready)) | ||||||
| 		{ | 		{ | ||||||
| 			Ethernet_Frame_Header_t* FrameOUTHeader = (Ethernet_Frame_Header_t*)&FrameOUT.FrameData; | 			Ethernet_Frame_Header_t* FrameOUTHeader = (Ethernet_Frame_Header_t*)&RNDISInterfaceInfo->FrameOUT.FrameData; | ||||||
| 			IP_Header_t*             IPHeaderOUT    = (IP_Header_t*)&FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t)]; | 			IP_Header_t*    IPHeaderOUT  = (IP_Header_t*)&RNDISInterfaceInfo->FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t)]; | ||||||
| 			TCP_Header_t*            TCPHeaderOUT   = (TCP_Header_t*)&FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t) + | 			TCP_Header_t*   TCPHeaderOUT = (TCP_Header_t*)&RNDISInterfaceInfo->FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t) + | ||||||
| 			                                                                             sizeof(IP_Header_t)];						 | 			                                                                                      sizeof(IP_Header_t)];						 | ||||||
| 			void*                    TCPDataOUT     = &FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t) + | 			void*           TCPDataOUT     = &RNDISInterfaceInfo->FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t) + | ||||||
| 			                                                              sizeof(IP_Header_t) + | 			                                                                         sizeof(IP_Header_t) + | ||||||
| 			                                                              sizeof(TCP_Header_t)]; | 			                                                                         sizeof(TCP_Header_t)]; | ||||||
| 
 | 
 | ||||||
| 			uint16_t PacketSize = ConnectionStateTable[CSTableEntry].Info.Buffer.Length; | 			uint16_t PacketSize = ConnectionStateTable[CSTableEntry].Info.Buffer.Length; | ||||||
| 
 | 
 | ||||||
| @ -145,8 +145,8 @@ TASK(TCP_Task) | |||||||
| 			PacketSize += sizeof(Ethernet_Frame_Header_t); | 			PacketSize += sizeof(Ethernet_Frame_Header_t); | ||||||
| 
 | 
 | ||||||
| 			/* Set the response length in the buffer and indicate that a response is ready to be sent */ | 			/* Set the response length in the buffer and indicate that a response is ready to be sent */ | ||||||
| 			FrameOUT.FrameLength            = PacketSize; | 			RNDISInterfaceInfo->FrameOUT.FrameLength   = PacketSize; | ||||||
| 			FrameOUT.FrameInBuffer          = true; | 			RNDISInterfaceInfo->FrameOUT.FrameInBuffer = true; | ||||||
| 			 | 			 | ||||||
| 			ConnectionStateTable[CSTableEntry].Info.Buffer.Ready = false; | 			ConnectionStateTable[CSTableEntry].Info.Buffer.Ready = false; | ||||||
| 			 | 			 | ||||||
|  | |||||||
| @ -40,8 +40,6 @@ | |||||||
| 		#include <avr/io.h> | 		#include <avr/io.h> | ||||||
| 		#include <stdbool.h> | 		#include <stdbool.h> | ||||||
| 		 | 		 | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h> |  | ||||||
| 		 |  | ||||||
| 		#include "EthernetProtocols.h" | 		#include "EthernetProtocols.h" | ||||||
| 		#include "Ethernet.h" | 		#include "Ethernet.h" | ||||||
| 		#include "ProtocolDecoders.h" | 		#include "ProtocolDecoders.h" | ||||||
| @ -230,13 +228,11 @@ | |||||||
| 			uint16_t               UrgentPointer; /**< Urgent data pointer */ | 			uint16_t               UrgentPointer; /**< Urgent data pointer */ | ||||||
| 		} TCP_Header_t; | 		} TCP_Header_t; | ||||||
| 		 | 		 | ||||||
| 	/* Tasks: */ |  | ||||||
| 		TASK(TCP_Task); |  | ||||||
| 		 |  | ||||||
| 	/* External Variables: */ | 	/* External Variables: */ | ||||||
| 		TCP_PortState_t PortStateTable[MAX_OPEN_TCP_PORTS]; | 		TCP_PortState_t PortStateTable[MAX_OPEN_TCP_PORTS]; | ||||||
| 
 | 
 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void                  TCP_TCPTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); | ||||||
| 		void                  TCP_Init(void); | 		void                  TCP_Init(void); | ||||||
| 		bool                  TCP_SetPortState(uint16_t Port, uint8_t State, void (*Handler)(TCP_ConnectionState_t*, TCP_ConnectionBuffer_t*)); | 		bool                  TCP_SetPortState(uint16_t Port, uint8_t State, void (*Handler)(TCP_ConnectionState_t*, TCP_ConnectionBuffer_t*)); | ||||||
| 		uint8_t               TCP_GetPortState(uint16_t Port); | 		uint8_t               TCP_GetPortState(uint16_t Port); | ||||||
|  | |||||||
| @ -28,27 +28,50 @@ | |||||||
|   this software. |   this software. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| /** \file
 |  | ||||||
|  * |  | ||||||
|  *  Main source file for the RNDISEthernet demo. This file contains the main tasks of the demo and |  | ||||||
|  *  is responsible for the initial application hardware configuration. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include "RNDISEthernet.h" | #include "RNDISEthernet.h" | ||||||
| 
 | 
 | ||||||
| /* Scheduler Task List */ | USB_ClassInfo_RNDIS_t Ethernet_RNDIS_Interface = | ||||||
| TASK_LIST | 	{ | ||||||
| { | 		.ControlInterfaceNumber     = 0, | ||||||
| 	{ .Task = USB_USBTask          , .TaskStatus = TASK_STOP }, | 
 | ||||||
| 	{ .Task = Ethernet_Task        , .TaskStatus = TASK_STOP }, | 		.DataINEndpointNumber       = CDC_TX_EPNUM, | ||||||
| 	{ .Task = TCP_Task             , .TaskStatus = TASK_STOP }, | 		.DataINEndpointSize         = CDC_TXRX_EPSIZE, | ||||||
| 	{ .Task = RNDIS_Task           , .TaskStatus = TASK_STOP }, | 
 | ||||||
| }; | 		.DataOUTEndpointNumber      = CDC_RX_EPNUM, | ||||||
|  | 		.DataOUTEndpointSize        = CDC_TXRX_EPSIZE, | ||||||
|  | 
 | ||||||
|  | 		.NotificationEndpointNumber = CDC_NOTIFICATION_EPNUM, | ||||||
|  | 		.NotificationEndpointSize   = CDC_NOTIFICATION_EPSIZE, | ||||||
|  | 		 | ||||||
|  | 		.AdapterVendorDescription   = "LUFA RNDIS Demo Adapter", | ||||||
|  | 		.AdapterMACAddress          = {ADAPTER_MAC_ADDRESS}, | ||||||
|  | 	}; | ||||||
| 	 | 	 | ||||||
| /** Main program entry point. This routine configures the hardware required by the application, then
 |  | ||||||
|  *  starts the scheduler to run the USB management task. |  | ||||||
|  */ |  | ||||||
| int main(void) | int main(void) | ||||||
|  | { | ||||||
|  | 	SetupHardware(); | ||||||
|  | 
 | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | 	 | ||||||
|  | 	printf_P(PSTR("\r\n\r\n****** RNDIS Demo running. ******\r\n")); | ||||||
|  | 
 | ||||||
|  | 	for (;;) | ||||||
|  | 	{ | ||||||
|  | 		if (Ethernet_RNDIS_Interface.FrameIN.FrameInBuffer) | ||||||
|  | 		{ | ||||||
|  | 			LEDs_SetAllLEDs(LEDMASK_USB_BUSY); | ||||||
|  | 			Ethernet_ProcessPacket(&Ethernet_RNDIS_Interface.FrameIN, &Ethernet_RNDIS_Interface.FrameOUT); | ||||||
|  | 			LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		TCP_TCPTask(&Ethernet_RNDIS_Interface); | ||||||
|  | 
 | ||||||
|  | 		USB_RNDIS_USBTask(&Ethernet_RNDIS_Interface); | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupHardware(void) | ||||||
| { | { | ||||||
| 	/* Disable watchdog if enabled by bootloader/fuses */ | 	/* Disable watchdog if enabled by bootloader/fuses */ | ||||||
| 	MCUSR &= ~(1 << WDRF); | 	MCUSR &= ~(1 << WDRF); | ||||||
| @ -60,279 +83,32 @@ int main(void) | |||||||
| 	/* Hardware Initialization */ | 	/* Hardware Initialization */ | ||||||
| 	LEDs_Init(); | 	LEDs_Init(); | ||||||
| 	SerialStream_Init(9600, false); | 	SerialStream_Init(9600, false); | ||||||
| 	 |  | ||||||
| 	/* Webserver Initialization */ |  | ||||||
| 	TCP_Init(); |  | ||||||
| 	Webserver_Init(); |  | ||||||
| 
 |  | ||||||
| 	printf_P(PSTR("\r\n\r\n****** RNDIS Demo running. ******\r\n")); |  | ||||||
| 
 |  | ||||||
| 	/* Indicate USB not ready */ |  | ||||||
| 	UpdateStatus(Status_USBNotReady); |  | ||||||
| 	 |  | ||||||
| 	/* Initialize Scheduler so that it can be used */ |  | ||||||
| 	Scheduler_Init(); |  | ||||||
| 
 |  | ||||||
| 	/* Initialize USB Subsystem */ |  | ||||||
| 	USB_Init(); | 	USB_Init(); | ||||||
| 
 | 
 | ||||||
| 	/* Scheduling - routine never returns, so put this last in the main function */ | 	/* Initialize TCP and Webserver modules */ | ||||||
| 	Scheduler_Start(); | 	TCP_Init(); | ||||||
|  | 	Webserver_Init(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** 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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Connect(void) | void EVENT_USB_Connect(void) | ||||||
| { | { | ||||||
| 	/* Start USB management task */ | 	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||||
| 	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 all the relevant tasks. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Disconnect(void) | void EVENT_USB_Disconnect(void) | ||||||
| { | { | ||||||
| 	/* Stop running TCP/IP and USB management tasks */ | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
| 	Scheduler_SetTaskMode(RNDIS_Task, TASK_STOP); |  | ||||||
| 	Scheduler_SetTaskMode(Ethernet_Task, TASK_STOP); |  | ||||||
| 	Scheduler_SetTaskMode(TCP_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 sets the current configuration
 |  | ||||||
|  *  of the USB device after enumeration, and configures the RNDIS device endpoints and starts the relevant tasks. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_ConfigurationChanged(void) | void EVENT_USB_ConfigurationChanged(void) | ||||||
| { | { | ||||||
| 	/* Setup CDC Notification, Rx and Tx Endpoints */ | 	LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
| 	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, | 	if (!(USB_RNDIS_ConfigureEndpoints(&Ethernet_RNDIS_Interface))) | ||||||
| 		                       ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE, | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 |  | ||||||
| 	Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT, |  | ||||||
| 		                       ENDPOINT_DIR_IN, CDC_NOTIFICATION_EPSIZE, |  | ||||||
| 	                           ENDPOINT_BANK_SINGLE); |  | ||||||
| 
 |  | ||||||
| 	/* Indicate USB connected and ready */ |  | ||||||
| 	UpdateStatus(Status_USBReady); |  | ||||||
| 
 |  | ||||||
| 	/* Start TCP/IP tasks */ |  | ||||||
| 	Scheduler_SetTaskMode(RNDIS_Task, TASK_RUN); |  | ||||||
| 	Scheduler_SetTaskMode(Ethernet_Task, TASK_RUN); |  | ||||||
| 	Scheduler_SetTaskMode(TCP_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 RNDIS control commands, |  | ||||||
|  *  which set up the USB RNDIS network adapter), so that they can be handled appropriately for the application. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_UnhandledControlPacket(void) | void EVENT_USB_UnhandledControlPacket(void) | ||||||
| { | { | ||||||
| 	/* Process RNDIS class commands */ | 	USB_RNDIS_ProcessControlPacket(&Ethernet_RNDIS_Interface); | ||||||
| 	switch (USB_ControlRequest.bRequest) |  | ||||||
| 	{ |  | ||||||
| 		case REQ_SendEncapsulatedCommand: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				/* Clear the SETUP packet, ready for data transfer */ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Read in the RNDIS message into the message buffer */ |  | ||||||
| 				Endpoint_Read_Control_Stream_LE(RNDISMessageBuffer, USB_ControlRequest.wLength); |  | ||||||
| 
 |  | ||||||
| 				/* Finalize the stream transfer to clear the last packet from the host */ |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 
 |  | ||||||
| 				/* Process the RNDIS message */ |  | ||||||
| 				ProcessRNDISControlMessage(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_GetEncapsulatedResponse: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				/* Clear the SETUP packet, ready for data transfer */ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* Check if a response to the last message is ready */ |  | ||||||
| 				if (!(MessageHeader->MessageLength)) |  | ||||||
| 				{ |  | ||||||
| 					/* Set the response to a single 0x00 byte to indicate that no response is ready */ |  | ||||||
| 					RNDISMessageBuffer[0] = 0; |  | ||||||
| 					MessageHeader->MessageLength = 1; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				/* Write the message response data to the endpoint */ |  | ||||||
| 				Endpoint_Write_Control_Stream_LE(RNDISMessageBuffer, MessageHeader->MessageLength); |  | ||||||
| 				 |  | ||||||
| 				/* Finalize the stream transfer to send the last packet or clear the host abort */ |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 
 |  | ||||||
| 				/* Reset the message header once again after transmission */ |  | ||||||
| 				MessageHeader->MessageLength = 0; |  | ||||||
| 			} |  | ||||||
| 	 |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** 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 RNDISEthernet_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; |  | ||||||
| 		case Status_ProcessingEthernetFrame: |  | ||||||
| 			LEDMask = (LEDS_LED2 | LEDS_LED3); |  | ||||||
| 			break;		 |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	/* Set the board LEDs to the new LED mask */ |  | ||||||
| 	LEDs_SetAllLEDs(LEDMask); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Task to manage the sending and receiving of encapsulated RNDIS data and notifications. This removes the RNDIS
 |  | ||||||
|  *  wrapper from received Ethernet frames and places them in the FrameIN global buffer, or adds the RNDIS wrapper |  | ||||||
|  *  to a frame in the FrameOUT global before sending the buffer contents to the host. |  | ||||||
|  */ |  | ||||||
| TASK(RNDIS_Task) |  | ||||||
| { |  | ||||||
| 	/* Select the notification endpoint */ |  | ||||||
| 	Endpoint_SelectEndpoint(CDC_NOTIFICATION_EPNUM); |  | ||||||
| 
 |  | ||||||
| 	/* Check if a message response is ready for the host */ |  | ||||||
| 	if (Endpoint_IsINReady() && ResponseReady) |  | ||||||
| 	{ |  | ||||||
| 		USB_Notification_t Notification = (USB_Notification_t) |  | ||||||
| 			{ |  | ||||||
| 				.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), |  | ||||||
| 				.bNotification = NOTIF_RESPONSE_AVAILABLE, |  | ||||||
| 				.wValue        = 0, |  | ||||||
| 				.wIndex        = 0, |  | ||||||
| 				.wLength       = 0, |  | ||||||
| 			}; |  | ||||||
| 		 |  | ||||||
| 		/* Indicate that a message response is ready for the host */ |  | ||||||
| 		Endpoint_Write_Stream_LE(&Notification, sizeof(Notification)); |  | ||||||
| 
 |  | ||||||
| 		/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 		Endpoint_ClearIN(); |  | ||||||
| 
 |  | ||||||
| 		/* Indicate a response is no longer ready */ |  | ||||||
| 		ResponseReady = false; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	/* Don't process the data endpoints until the system is in the data initialized state, and the buffer is free */ |  | ||||||
| 	if ((CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength)) |  | ||||||
| 	{ |  | ||||||
| 		/* Create a new packet header for reading/writing */ |  | ||||||
| 		RNDIS_PACKET_MSG_t RNDISPacketHeader; |  | ||||||
| 
 |  | ||||||
| 		/* Select the data OUT endpoint */ |  | ||||||
| 		Endpoint_SelectEndpoint(CDC_RX_EPNUM); |  | ||||||
| 		 |  | ||||||
| 		/* Check if the data OUT endpoint contains data, and that the IN buffer is empty */ |  | ||||||
| 		if (Endpoint_IsOUTReceived() && !(FrameIN.FrameInBuffer)) |  | ||||||
| 		{ |  | ||||||
| 			/* Read in the packet message header */ |  | ||||||
| 			Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t)); |  | ||||||
| 
 |  | ||||||
| 			/* Stall the request if the data is too large */ |  | ||||||
| 			if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX) |  | ||||||
| 			{ |  | ||||||
| 				Endpoint_StallTransaction(); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			/* Read in the Ethernet frame into the buffer */ |  | ||||||
| 			Endpoint_Read_Stream_LE(FrameIN.FrameData, RNDISPacketHeader.DataLength); |  | ||||||
| 
 |  | ||||||
| 			/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 			Endpoint_ClearOUT(); |  | ||||||
| 			 |  | ||||||
| 			/* Store the size of the Ethernet frame */ |  | ||||||
| 			FrameIN.FrameLength = RNDISPacketHeader.DataLength; |  | ||||||
| 
 |  | ||||||
| 			/* Indicate Ethernet IN buffer full */ |  | ||||||
| 			FrameIN.FrameInBuffer = true; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		/* Select the data IN endpoint */ |  | ||||||
| 		Endpoint_SelectEndpoint(CDC_TX_EPNUM); |  | ||||||
| 		 |  | ||||||
| 		/* Check if the data IN endpoint is ready for more data, and that the IN buffer is full */ |  | ||||||
| 		if (Endpoint_IsINReady() && FrameOUT.FrameInBuffer) |  | ||||||
| 		{ |  | ||||||
| 			/* Clear the packet header with all 0s so that the relevant fields can be filled */ |  | ||||||
| 			memset(&RNDISPacketHeader, 0, sizeof(RNDIS_PACKET_MSG_t)); |  | ||||||
| 
 |  | ||||||
| 			/* Construct the required packet header fields in the buffer */ |  | ||||||
| 			RNDISPacketHeader.MessageType   = REMOTE_NDIS_PACKET_MSG; |  | ||||||
| 			RNDISPacketHeader.MessageLength = (sizeof(RNDIS_PACKET_MSG_t) + FrameOUT.FrameLength); |  | ||||||
| 			RNDISPacketHeader.DataOffset    = (sizeof(RNDIS_PACKET_MSG_t) - sizeof(RNDIS_Message_Header_t)); |  | ||||||
| 			RNDISPacketHeader.DataLength    = FrameOUT.FrameLength; |  | ||||||
| 
 |  | ||||||
| 			/* Send the packet header to the host */ |  | ||||||
| 			Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t)); |  | ||||||
| 
 |  | ||||||
| 			/* Send the Ethernet frame data to the host */ |  | ||||||
| 			Endpoint_Write_Stream_LE(FrameOUT.FrameData, RNDISPacketHeader.DataLength); |  | ||||||
| 			 |  | ||||||
| 			/* Finalize the stream transfer to send the last packet */ |  | ||||||
| 			Endpoint_ClearIN(); |  | ||||||
| 			 |  | ||||||
| 			/* Indicate Ethernet OUT buffer no longer full */ |  | ||||||
| 			FrameOUT.FrameInBuffer = false; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Ethernet frame processing task. This task checks to see if a frame has been received, and if so hands off the processing
 |  | ||||||
|  *  of the frame to the Ethernet processing routines. |  | ||||||
|  */ |  | ||||||
| TASK(Ethernet_Task) |  | ||||||
| { |  | ||||||
| 	/* Task for Ethernet processing. Incoming ethernet frames are loaded into the FrameIN structure, and
 |  | ||||||
| 	   outgoing frames should be loaded into the FrameOUT structure. Both structures can only hold a single |  | ||||||
| 	   Ethernet frame at a time, so the FrameInBuffer bool is used to indicate when the buffers contain data. */ |  | ||||||
| 
 |  | ||||||
| 	/* Check if a frame has been written to the IN frame buffer */ |  | ||||||
| 	if (FrameIN.FrameInBuffer) |  | ||||||
| 	{ |  | ||||||
| 		/* Indicate packet processing started */ |  | ||||||
| 		UpdateStatus(Status_ProcessingEthernetFrame); |  | ||||||
| 
 |  | ||||||
| 		/* Process the ethernet frame - replace this with your own Ethernet handler code as desired */ |  | ||||||
| 		Ethernet_ProcessPacket(); |  | ||||||
| 
 |  | ||||||
| 		/* Indicate packet processing complete */ |  | ||||||
| 		UpdateStatus(Status_USBReady); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -46,55 +46,33 @@ | |||||||
| 
 | 
 | ||||||
| 		#include "Descriptors.h" | 		#include "Descriptors.h" | ||||||
| 
 | 
 | ||||||
| 		#include "Lib/RNDIS.h" |  | ||||||
| 		#include "Lib/Ethernet.h" | 		#include "Lib/Ethernet.h" | ||||||
| 		#include "Lib/TCP.h" | 		#include "Lib/TCP.h" | ||||||
| 		#include "Lib/ARP.h" | 		#include "Lib/ARP.h" | ||||||
| 		#include "Lib/Webserver.h" | 		#include "Lib/Webserver.h" | ||||||
| 
 | 
 | ||||||
| 		#include <LUFA/Version.h>                         // Library Version Information | 		#include <LUFA/Version.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>                 // USB Functionality | 		#include <LUFA/Drivers/Board/LEDs.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>              // LEDs driver | 		#include <LUFA/Drivers/Board/Joystick.h> | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>             // Simple scheduler for task management | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 		#include <LUFA/Drivers/Peripheral/SerialStream.h> // Serial stream driver | 		#include <LUFA/Drivers/USB/Class/Device/RNDIS.h> | ||||||
| 
 | 
 | ||||||
| 	/* Macros: */ | 	/* Macros: */ | ||||||
| 		/** Notification value to indicate that a frame is ready to be read by the host. */ | 		#define LEDMASK_USB_NOTREADY      LEDS_LED1 | ||||||
| 		#define NOTIF_RESPONSE_AVAILABLE                 0x01 | 		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3) | ||||||
| 
 | 		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4) | ||||||
| 	/* Type Defines: */ | 		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3) | ||||||
| 		/** Type define for a RNDIS notification message, for transmission to the RNDIS host via the notification
 | 		#define LEDMASK_USB_BUSY          LEDS_LED2 | ||||||
| 		 *  Endpoint. |  | ||||||
| 		 */ |  | ||||||
| 		typedef struct |  | ||||||
| 		{ |  | ||||||
| 			uint8_t  bmRequestType; /**< Notification type, a mask of values from SrdRequestType.h */ |  | ||||||
| 			uint8_t  bNotification; /**< Notification index, indicating what the RNDIS notification relates to */ |  | ||||||
| 			uint16_t wValue; /**< Two byte notification value parameter */ |  | ||||||
| 			uint16_t wIndex; /**< Two byte notification index parameter */ |  | ||||||
| 			uint16_t wLength; /**< Size of data payload following the notification header */ |  | ||||||
| 		} USB_Notification_t; |  | ||||||
| 
 |  | ||||||
| 	/* Enums: */ |  | ||||||
| 		/** Enum for the possible status codes for passing to the UpdateStatus() function. */ |  | ||||||
| 		enum RNDISEthernet_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 */ |  | ||||||
| 			Status_ProcessingEthernetFrame = 3, /**< Currently processing an ethernet frame from the host */ |  | ||||||
| 		}; |  | ||||||
| 		 |  | ||||||
| 	/* Tasks: */ |  | ||||||
| 		TASK(RNDIS_Task); |  | ||||||
| 		TASK(Ethernet_Task); |  | ||||||
| 		 | 		 | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void SetupHardware(void); | ||||||
|  | 
 | ||||||
| 		void EVENT_USB_Connect(void); | 		void EVENT_USB_Connect(void); | ||||||
| 		void EVENT_USB_Disconnect(void); | 		void EVENT_USB_Disconnect(void); | ||||||
| 		void EVENT_USB_ConfigurationChanged(void); | 		void EVENT_USB_ConfigurationChanged(void); | ||||||
| 		void EVENT_USB_UnhandledControlPacket(void); | 		void EVENT_USB_UnhandledControlPacket(void); | ||||||
|  | 		void EVENT_USB_StartOfFrame(void); | ||||||
| 		 | 		 | ||||||
| 		void UpdateStatus(uint8_t CurrentStatus); | 		void CALLBACK_USB_RNDIS_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); | ||||||
| 	 | 	 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -125,7 +125,6 @@ LUFA_PATH = ../../.. | |||||||
| # List C source files here. (C dependencies are automatically generated.)
 | # List C source files here. (C dependencies are automatically generated.)
 | ||||||
| SRC = $(TARGET).c                                                 \
 | SRC = $(TARGET).c                                                 \
 | ||||||
|       Descriptors.c                                               \
 |       Descriptors.c                                               \
 | ||||||
|       Lib/RNDIS.c                                                 \
 |  | ||||||
| 	  Lib/Ethernet.c                                              \
 | 	  Lib/Ethernet.c                                              \
 | ||||||
| 	  Lib/ProtocolDecoders.c                                      \
 | 	  Lib/ProtocolDecoders.c                                      \
 | ||||||
| 	  Lib/ICMP.c                                                  \
 | 	  Lib/ICMP.c                                                  \
 | ||||||
| @ -135,7 +134,6 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  Lib/ARP.c                                                   \
 | 	  Lib/ARP.c                                                   \
 | ||||||
| 	  Lib/IP.c                                                    \
 | 	  Lib/IP.c                                                    \
 | ||||||
| 	  Lib/Webserver.c                                             \
 | 	  Lib/Webserver.c                                             \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/Peripheral/SerialStream.c         \
 | 	  $(LUFA_PATH)/LUFA/Drivers/Peripheral/SerialStream.c         \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/Peripheral/Serial.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/Peripheral/Serial.c               \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | ||||||
| @ -148,7 +146,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/RNDIS.c          \
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
| @ -195,7 +193,7 @@ CSTANDARD = -std=gnu99 | |||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for C sources
 | # Place -D or -U options here for C sources
 | ||||||
| CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | ||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY | ||||||
| CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | ||||||
| CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | ||||||
| CDEFS += -DNO_DECODE_ETHERNET -DNO_DECODE_ARP -DNO_DECODE_ICMP -DNO_DECODE_IP -DNO_DECODE_TCP -DNO_DECODE_UDP -DNO_DECODE_DHCP | CDEFS += -DNO_DECODE_ETHERNET -DNO_DECODE_ARP -DNO_DECODE_ICMP -DNO_DECODE_IP -DNO_DECODE_TCP -DNO_DECODE_UDP -DNO_DECODE_DHCP | ||||||
|  | |||||||
| @ -37,26 +37,12 @@ | |||||||
| #define _DESCRIPTORS_H_ | #define _DESCRIPTORS_H_ | ||||||
| 
 | 
 | ||||||
| 	/* Includes: */ | 	/* Includes: */ | ||||||
| 		#include <LUFA/Drivers/USB/USB.h> |  | ||||||
| 
 |  | ||||||
| 		#include <avr/pgmspace.h> | 		#include <avr/pgmspace.h> | ||||||
| 
 | 
 | ||||||
| 	/* Macros: */ | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
| 		/** Macro to define a CDC class-specific functional descriptor. CDC functional descriptors have a
 | 		#include <LUFA/Drivers/USB/Class/Device/CDC.h> | ||||||
| 		 *  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];  \ |  | ||||||
| 		     } |  | ||||||
| 
 | 
 | ||||||
|  | 	/* Macros: */ | ||||||
| 		/** Endpoint number of the CDC device-to-host notification IN endpoint. */ | 		/** Endpoint number of the CDC device-to-host notification IN endpoint. */ | ||||||
| 		#define CDC_NOTIFICATION_EPNUM         2 | 		#define CDC_NOTIFICATION_EPNUM         2 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -30,37 +30,54 @@ | |||||||
| 
 | 
 | ||||||
| #include "USBtoSerial.h" | #include "USBtoSerial.h" | ||||||
| 
 | 
 | ||||||
| /* 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; | 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; | RingBuff_t Tx_Buffer; | ||||||
| 
 | 
 | ||||||
| /** Flag to indicate if the USART is currently transmitting data from the Rx_Buffer circular buffer. */ | USB_ClassInfo_CDC_t VirtualSerial_CDC_Interface = | ||||||
| volatile bool Transmitting = false; | 	{ | ||||||
|  | 		.ControlInterfaceNumber     = 0, | ||||||
|  | 
 | ||||||
|  | 		.DataINEndpointNumber       = CDC_TX_EPNUM, | ||||||
|  | 		.DataINEndpointSize         = CDC_TXRX_EPSIZE, | ||||||
|  | 
 | ||||||
|  | 		.DataOUTEndpointNumber      = CDC_RX_EPNUM, | ||||||
|  | 		.DataOUTEndpointSize        = CDC_TXRX_EPSIZE, | ||||||
|  | 
 | ||||||
|  | 		.NotificationEndpointNumber = CDC_NOTIFICATION_EPNUM, | ||||||
|  | 		.NotificationEndpointSize   = CDC_NOTIFICATION_EPSIZE, | ||||||
|  | 	}; | ||||||
| 
 | 
 | ||||||
| /** 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) | int main(void) | ||||||
|  | { | ||||||
|  | 	SetupHardware(); | ||||||
|  | 	 | ||||||
|  | 	Buffer_Initialize(&Rx_Buffer); | ||||||
|  | 	Buffer_Initialize(&Tx_Buffer); | ||||||
|  | 
 | ||||||
|  | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
|  | 
 | ||||||
|  | 	for (;;) | ||||||
|  | 	{ | ||||||
|  | 		for (uint8_t DataBytesRem = USB_CDC_BytesReceived(&VirtualSerial_CDC_Interface); DataBytesRem != 0; DataBytesRem--) | ||||||
|  | 		{ | ||||||
|  | 			if (!(BUFF_STATICSIZE - Rx_Buffer.Elements)) | ||||||
|  | 			  break; | ||||||
|  | 			   | ||||||
|  | 			Buffer_StoreElement(&Rx_Buffer, USB_CDC_ReceiveByte(&VirtualSerial_CDC_Interface)); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if (Tx_Buffer.Elements) | ||||||
|  | 		  USB_CDC_SendByte(&VirtualSerial_CDC_Interface, Buffer_GetElement(&Rx_Buffer)); | ||||||
|  | 		   | ||||||
|  | 		if (Rx_Buffer.Elements) | ||||||
|  | 		  Serial_TxByte(Buffer_GetElement(&Rx_Buffer)); | ||||||
|  | 		 | ||||||
|  | 		USB_CDC_USBTask(&VirtualSerial_CDC_Interface); | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SetupHardware(void) | ||||||
| { | { | ||||||
| 	/* Disable watchdog if enabled by bootloader/fuses */ | 	/* Disable watchdog if enabled by bootloader/fuses */ | ||||||
| 	MCUSR &= ~(1 << WDRF); | 	MCUSR &= ~(1 << WDRF); | ||||||
| @ -70,304 +87,61 @@ int main(void) | |||||||
| 	clock_prescale_set(clock_div_1); | 	clock_prescale_set(clock_div_1); | ||||||
| 
 | 
 | ||||||
| 	/* Hardware Initialization */ | 	/* Hardware Initialization */ | ||||||
|  | 	Joystick_Init(); | ||||||
| 	LEDs_Init(); | 	LEDs_Init(); | ||||||
| 	ReconfigureUSART(); |  | ||||||
| 	 |  | ||||||
| 	/* Ring buffer 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(); | 	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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Connect(void) | void EVENT_USB_Connect(void) | ||||||
| { | { | ||||||
| 	/* Start USB management task */ | 	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||||
| 	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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_Disconnect(void) | void EVENT_USB_Disconnect(void) | ||||||
| { | { | ||||||
| 	/* Stop running CDC and USB management tasks */ | 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||||
| 	Scheduler_SetTaskMode(CDC_Task, TASK_STOP); |  | ||||||
| 	Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); |  | ||||||
| 	 |  | ||||||
| 	/* Reset Tx and Rx buffers, device disconnected */ |  | ||||||
| 	Buffer_Initialize(&Rx_Buffer); |  | ||||||
| 	Buffer_Initialize(&Tx_Buffer); |  | ||||||
| 
 |  | ||||||
| 	/* 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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_ConfigurationChanged(void) | void EVENT_USB_ConfigurationChanged(void) | ||||||
| { | { | ||||||
| 	/* Setup CDC Notification, Rx and Tx Endpoints */ | 	LEDs_SetAllLEDs(LEDMASK_USB_READY); | ||||||
| 	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, | 	if (!(USB_CDC_ConfigureEndpoints(&VirtualSerial_CDC_Interface))) | ||||||
| 		                       ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE, | 	  LEDs_SetAllLEDs(LEDMASK_USB_ERROR); | ||||||
| 	                           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. |  | ||||||
|  */ |  | ||||||
| void EVENT_USB_UnhandledControlPacket(void) | void EVENT_USB_UnhandledControlPacket(void) | ||||||
| { | { | ||||||
| 	uint8_t* LineCodingData = (uint8_t*)&LineCoding; | 	USB_CDC_ProcessControlPacket(&VirtualSerial_CDC_Interface); | ||||||
| 
 |  | ||||||
| 	/* Process CDC specific control requests */ |  | ||||||
| 	switch (USB_ControlRequest.bRequest) |  | ||||||
| 	{ |  | ||||||
| 		case REQ_GetLineEncoding: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{	 |  | ||||||
| 				/* Acknowledge the SETUP packet, ready for data transfer */ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 
 |  | ||||||
| 				/* 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_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetLineEncoding: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{ |  | ||||||
| 				/* Acknowledge the SETUP packet, ready for data transfer */ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 
 |  | ||||||
| 				/* 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_ClearIN(); |  | ||||||
| 				 |  | ||||||
| 				/* Reconfigure the USART with the new settings */ |  | ||||||
| 				ReconfigureUSART(); |  | ||||||
| 			} |  | ||||||
| 	 |  | ||||||
| 			break; |  | ||||||
| 		case REQ_SetControlLineState: |  | ||||||
| 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) |  | ||||||
| 			{				 |  | ||||||
| 				/* Acknowledge the SETUP packet, ready for data transfer */ |  | ||||||
| 				Endpoint_ClearSETUP(); |  | ||||||
| 				 |  | ||||||
| 				/* 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 in USB_ControlRequest, and can be masked against the |  | ||||||
| 						 CONTROL_LINE_OUT_* masks to determine the RTS and DTR line states using the following code: |  | ||||||
| 				*/ |  | ||||||
| 
 |  | ||||||
| 				/* Acknowledge status stage */ |  | ||||||
| 				while (!(Endpoint_IsINReady())); |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 	 |  | ||||||
| 			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_ClearIN(); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| 		/* Select the Serial Rx Endpoint */ |  | ||||||
| 		Endpoint_SelectEndpoint(CDC_RX_EPNUM); |  | ||||||
| 		 |  | ||||||
| 		/* Check to see if a packet has been received from the host */ |  | ||||||
| 		if (Endpoint_IsOUTReceived()) |  | ||||||
| 		{ |  | ||||||
| 			/* Read the bytes in from the endpoint into the buffer while space is available */ |  | ||||||
| 			while (Endpoint_BytesInEndpoint() && (BUFF_STATICSIZE - Rx_Buffer.Elements)) |  | ||||||
| 			{ |  | ||||||
| 				/* Store each character from the endpoint */ |  | ||||||
| 				Buffer_StoreElement(&Rx_Buffer, Endpoint_Read_Byte()); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			/* Check to see if all bytes in the current packet have been read */ |  | ||||||
| 			if (!(Endpoint_BytesInEndpoint())) |  | ||||||
| 			{ |  | ||||||
| 				/* Clear the endpoint buffer */ |  | ||||||
| 				Endpoint_ClearOUT(); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		/* Check if Rx buffer contains data - if so, send it */ |  | ||||||
| 		if (Rx_Buffer.Elements) |  | ||||||
| 		  Serial_TxByte(Buffer_GetElement(&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_IsReadWriteAllowed())); |  | ||||||
| 			 |  | ||||||
| 			/* Write the bytes from the buffer to the endpoint while space is available */ |  | ||||||
| 			while (Tx_Buffer.Elements && (Endpoint_BytesInEndpoint() < CDC_TXRX_EPSIZE)) |  | ||||||
| 			{ |  | ||||||
| 				/* Write each byte retreived from the buffer to the endpoint */ |  | ||||||
| 				Endpoint_Write_Byte(Buffer_GetElement(&Tx_Buffer)); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			/* Remember if the packet to send completely fills the endpoint */ |  | ||||||
| 			bool IsFull = (Endpoint_BytesInEndpoint() == CDC_TXRX_EPSIZE); |  | ||||||
| 			 |  | ||||||
| 			/* Send the data */ |  | ||||||
| 			Endpoint_ClearIN(); |  | ||||||
| 
 |  | ||||||
| 			/* If no more data to send and the last packet filled the endpoint, send an empty packet to release
 |  | ||||||
| 			 * the buffer on the receiver (otherwise all data will be cached until a non-full packet is received) */ |  | ||||||
| 			if (IsFull && !(Tx_Buffer.Elements)) |  | ||||||
| 			{ |  | ||||||
| 				/* Wait until Serial Tx Endpoint Ready for Read/Write */ |  | ||||||
| 				while (!(Endpoint_IsReadWriteAllowed())); |  | ||||||
| 
 |  | ||||||
| 				/* Send an empty packet to terminate the transfer */ |  | ||||||
| 				Endpoint_ClearIN(); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** ISR to handle the USART receive complete interrupt, fired each time the USART has received a character. This stores the received
 |  | ||||||
|  *  character into the Tx_Buffer circular buffer for later transmission to the host. |  | ||||||
|  */ |  | ||||||
| ISR(USART1_RX_vect, ISR_BLOCK) | ISR(USART1_RX_vect, ISR_BLOCK) | ||||||
| { | { | ||||||
| 	/* Only store received characters if the USB interface is connected */ |  | ||||||
| 	if (USB_IsConnected) | 	if (USB_IsConnected) | ||||||
| 	{ | 	  Buffer_StoreElement(&Tx_Buffer, UDR1); | ||||||
| 		/* Character received, store it into the buffer */ |  | ||||||
| 		Buffer_StoreElement(&Tx_Buffer, UDR1); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
 | void EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo) | ||||||
|  *  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 the USART to match the current serial port settings issued by the host as closely as possible. */ |  | ||||||
| void ReconfigureUSART(void) |  | ||||||
| { | { | ||||||
| 	uint8_t ConfigMask = 0; | 	uint8_t ConfigMask = 0; | ||||||
| 
 | 
 | ||||||
| 	/* Determine parity - non odd/even parity mode defaults to no parity */ | 	if (CDCInterfaceInfo->LineEncoding.ParityType == Parity_Odd) | ||||||
| 	if (LineCoding.ParityType == Parity_Odd) |  | ||||||
| 	  ConfigMask = ((1 << UPM11) | (1 << UPM10)); | 	  ConfigMask = ((1 << UPM11) | (1 << UPM10)); | ||||||
| 	else if (LineCoding.ParityType == Parity_Even) | 	else if (CDCInterfaceInfo->LineEncoding.ParityType == Parity_Even) | ||||||
| 	  ConfigMask = (1 << UPM11); | 	  ConfigMask = (1 << UPM11); | ||||||
| 
 | 
 | ||||||
| 	/* Determine stop bits - 1.5 stop bits is set as 1 stop bit due to hardware limitations */ | 	if (CDCInterfaceInfo->LineEncoding.CharFormat == TwoStopBits) | ||||||
| 	if (LineCoding.CharFormat == TwoStopBits) |  | ||||||
| 	  ConfigMask |= (1 << USBS1); | 	  ConfigMask |= (1 << USBS1); | ||||||
| 
 | 
 | ||||||
| 	/* Determine data size - 5, 6, 7, or 8 bits are supported */ | 	if (CDCInterfaceInfo->LineEncoding.DataBits == 6) | ||||||
| 	if (LineCoding.DataBits == 6) |  | ||||||
| 	  ConfigMask |= (1 << UCSZ10); | 	  ConfigMask |= (1 << UCSZ10); | ||||||
| 	else if (LineCoding.DataBits == 7) | 	else if (CDCInterfaceInfo->LineEncoding.DataBits == 7) | ||||||
| 	  ConfigMask |= (1 << UCSZ11); | 	  ConfigMask |= (1 << UCSZ11); | ||||||
| 	else if (LineCoding.DataBits == 8) | 	else if (CDCInterfaceInfo->LineEncoding.DataBits == 8) | ||||||
| 	  ConfigMask |= ((1 << UCSZ11) | (1 << UCSZ10)); | 	  ConfigMask |= ((1 << UCSZ11) | (1 << UCSZ10)); | ||||||
| 	 | 	 | ||||||
| 	/* Enable double speed, gives better error percentages at 8MHz */ |  | ||||||
| 	UCSR1A = (1 << U2X1);	 | 	UCSR1A = (1 << U2X1);	 | ||||||
| 	 |  | ||||||
| 	/* Enable transmit and receive modules and interrupts */ |  | ||||||
| 	UCSR1B = ((1 << RXCIE1) | (1 << TXEN1) | (1 << RXEN1)); | 	UCSR1B = ((1 << RXCIE1) | (1 << TXEN1) | (1 << RXEN1)); | ||||||
| 
 |  | ||||||
| 	/* Set the USART mode to the mask generated by the Line Coding options */ |  | ||||||
| 	UCSR1C = ConfigMask;	 | 	UCSR1C = ConfigMask;	 | ||||||
| 	 | 	UBRR1  = SERIAL_2X_UBBRVAL((uint16_t)CDCInterfaceInfo->LineEncoding.BaudRateBPS); | ||||||
| 	/* Set the USART baud rate register to the desired baud rate value */ |  | ||||||
| 	UBRR1  = SERIAL_2X_UBBRVAL((uint16_t)LineCoding.BaudRateBPS); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -46,140 +46,28 @@ | |||||||
| 
 | 
 | ||||||
| 		#include "Lib/RingBuff.h" | 		#include "Lib/RingBuff.h" | ||||||
| 
 | 
 | ||||||
| 		#include <LUFA/Version.h>                         // Library Version Information | 		#include <LUFA/Version.h> | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>                 // USB Functionality | 		#include <LUFA/Drivers/Board/LEDs.h> | ||||||
| 		#include <LUFA/Drivers/Peripheral/Serial.h>       // USART driver | 		#include <LUFA/Drivers/Board/Joystick.h> | ||||||
| 		#include <LUFA/Drivers/Board/LEDs.h>              // LEDs driver | 		#include <LUFA/Drivers/Peripheral/Serial.h> | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>             // Simple scheduler for task management | 		#include <LUFA/Drivers/USB/USB.h> | ||||||
|  | 		#include <LUFA/Drivers/USB/Class/Device/CDC.h> | ||||||
| 
 | 
 | ||||||
| 	/* Macros: */ | 	/* Macros: */ | ||||||
| 		/** CDC Class specific request to get the current virtual serial port configuration settings. */ | 		#define LEDMASK_USB_NOTREADY      LEDS_LED1 | ||||||
| 		#define REQ_GetLineEncoding          0x21 | 		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3) | ||||||
| 
 | 		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4) | ||||||
| 		/** CDC Class specific request to set the current virtual serial port configuration settings. */ | 		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3) | ||||||
| 		#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 occurred 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 occurred 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 occurred on the virtual serial port. |  | ||||||
| 		 */ |  | ||||||
| 		#define CONTROL_LINE_IN_OVERRUNERROR (1 << 6) |  | ||||||
| 		 |  | ||||||
| 	/* 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 character 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: */ | 	/* Function Prototypes: */ | ||||||
|  | 		void SetupHardware(void); | ||||||
|  | 
 | ||||||
| 		void EVENT_USB_Connect(void); | 		void EVENT_USB_Connect(void); | ||||||
| 		void EVENT_USB_Disconnect(void); | 		void EVENT_USB_Disconnect(void); | ||||||
| 		void EVENT_USB_ConfigurationChanged(void); | 		void EVENT_USB_ConfigurationChanged(void); | ||||||
| 		void EVENT_USB_UnhandledControlPacket(void); | 		void EVENT_USB_UnhandledControlPacket(void); | ||||||
|  | 		void EVENT_USB_StartOfFrame(void); | ||||||
| 		 | 		 | ||||||
| 		void ReconfigureUSART(void); | 		void EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo); | ||||||
| 		void UpdateStatus(uint8_t CurrentStatus); |  | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -126,7 +126,6 @@ LUFA_PATH = ../../.. | |||||||
| SRC = $(TARGET).c                                                 \
 | SRC = $(TARGET).c                                                 \
 | ||||||
| 	  Descriptors.c                                               \
 | 	  Descriptors.c                                               \
 | ||||||
| 	  Lib/RingBuff.c                                              \
 | 	  Lib/RingBuff.c                                              \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c        \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c               \
 | ||||||
| @ -137,7 +136,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/CDC.c            \
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
| @ -184,7 +183,7 @@ CSTANDARD = -std=gnu99 | |||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for C sources
 | # Place -D or -U options here for C sources
 | ||||||
| CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | ||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DNO_STREAM_CALLBACKS -DUSB_DEVICE_ONLY | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY | ||||||
| CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION | ||||||
| CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -138,7 +138,7 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/Host/HIDParser.c        \
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
|  | |||||||
| @ -119,10 +119,10 @@ static uint8_t MassStore_WaitForDataReceived(void) | |||||||
| 	while (!(Pipe_IsINReceived())) | 	while (!(Pipe_IsINReceived())) | ||||||
| 	{ | 	{ | ||||||
| 		/* Check to see if a new frame has been issued (1ms elapsed) */ | 		/* Check to see if a new frame has been issued (1ms elapsed) */ | ||||||
| 		if (USB_INT_HasOccurred(USB_INT_HSOFI)) | 		if (FrameElapsed) | ||||||
| 		{ | 		{ | ||||||
| 			/* Clear the flag and decrement the timeout period counter */ | 			/* Clear the flag and decrement the timeout period counter */ | ||||||
| 			USB_INT_Clear(USB_INT_HSOFI); | 			FrameElapsed = false; | ||||||
| 			TimeoutMSRem--; | 			TimeoutMSRem--; | ||||||
| 
 | 
 | ||||||
| 			/* Check to see if the timeout period for the command has elapsed */ | 			/* Check to see if the timeout period for the command has elapsed */ | ||||||
|  | |||||||
| @ -109,10 +109,10 @@ uint8_t SImage_RecieveBlockHeader(void) | |||||||
| 	while (!(Pipe_IsReadWriteAllowed())) | 	while (!(Pipe_IsReadWriteAllowed())) | ||||||
| 	{ | 	{ | ||||||
| 		/* Check to see if a new frame has been issued (1ms elapsed) */ | 		/* Check to see if a new frame has been issued (1ms elapsed) */ | ||||||
| 		if (USB_INT_HasOccurred(USB_INT_HSOFI)) | 		if (FrameElapsed) | ||||||
| 		{ | 		{ | ||||||
| 			/* Clear the flag and decrement the timeout period counter */ | 			/* Clear the flag and decrement the timeout period counter */ | ||||||
| 			USB_INT_Clear(USB_INT_HSOFI); | 			FrameElapsed = false; | ||||||
| 			TimeoutMSRem--; | 			TimeoutMSRem--; | ||||||
| 
 | 
 | ||||||
| 			/* Check to see if the timeout period for the command has elapsed */ | 			/* Check to see if the timeout period for the command has elapsed */ | ||||||
|  | |||||||
| @ -45,7 +45,6 @@ | |||||||
| 		#include <LUFA/Version.h>                               // Library Version Information | 		#include <LUFA/Version.h>                               // Library Version Information | ||||||
| 		#include <LUFA/Drivers/USB/USB.h>                       // USB Functionality | 		#include <LUFA/Drivers/USB/USB.h>                       // USB Functionality | ||||||
| 		#include <LUFA/Scheduler/Scheduler.h>                   // Simple scheduler for task management | 		#include <LUFA/Scheduler/Scheduler.h>                   // Simple scheduler for task management | ||||||
| 		#include <LUFA/MemoryAllocator/DynAlloc.h>              // Auto-defragmenting Dynamic Memory allocation |  | ||||||
| 		#include <LUFA/Drivers/Misc/TerminalCodes.h>            // ANSI Terminal Escape Codes | 		#include <LUFA/Drivers/Misc/TerminalCodes.h>            // ANSI Terminal Escape Codes | ||||||
| 		#include <LUFA/Drivers/Peripheral/ADC.h>                // ADC driver | 		#include <LUFA/Drivers/Peripheral/ADC.h>                // ADC driver | ||||||
| 		#include <LUFA/Drivers/Peripheral/SerialStream.h>       // USART Stream driver | 		#include <LUFA/Drivers/Peripheral/SerialStream.h>       // USART Stream driver | ||||||
|  | |||||||
| @ -127,7 +127,6 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  TestEvents.c                                                \
 | 	  TestEvents.c                                                \
 | ||||||
| 	  Descriptors.c                                               \
 | 	  Descriptors.c                                               \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 | 	  $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c                     \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/MemoryAllocator/DynAlloc.c                \
 |  | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/Board/Temperature.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/Board/Temperature.c               \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/Peripheral/SerialStream.c         \
 | 	  $(LUFA_PATH)/LUFA/Drivers/Peripheral/SerialStream.c         \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/Peripheral/Serial.c               \
 | 	  $(LUFA_PATH)/LUFA/Drivers/Peripheral/Serial.c               \
 | ||||||
| @ -141,7 +140,6 @@ SRC = $(TARGET).c                                                 \ | |||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c      \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c           \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | 	  $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c  \
 | ||||||
| 	  $(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c             \
 |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # List C++ source files here. (C dependencies are automatically generated.)
 | # List C++ source files here. (C dependencies are automatically generated.)
 | ||||||
| @ -189,7 +187,6 @@ CSTANDARD = -std=gnu99 | |||||||
| # Place -D or -U options here for C sources
 | # Place -D or -U options here for C sources
 | ||||||
| CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | CDEFS  = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) | ||||||
| CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES | CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES | ||||||
| CDEFS += -DNUM_BLOCKS=100 -DBLOCK_SIZE=8 -DNUM_HANDLES=20 |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # Place -D or -U options here for ASM sources
 | # Place -D or -U options here for ASM sources
 | ||||||
|  | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -4,6 +4,14 @@ | |||||||
|  *  documentation pages. It is not a project source file. |  *  documentation pages. It is not a project source file. | ||||||
|  */ |  */ | ||||||
|     |     | ||||||
|  | ========== TODO: =========== | ||||||
|  | 	- Document new class drivers | ||||||
|  | 	- Re-document all demos now that they have changed | ||||||
|  | 	- Add standardized descriptor names to class driver structures, controlled by USE_NONSTANDARD_DESCRIPTOR_NAMES | ||||||
|  | 	- Add C++ compatibility to class drivers | ||||||
|  | 	- Disable JTAG in demos | ||||||
|  | ============================ | ||||||
|  | 
 | ||||||
|  /** \page Page_ChangeLog Project Changelog |  /** \page Page_ChangeLog Project Changelog | ||||||
|   * |   * | ||||||
|   *  \section Sec_ChangeLogXXXXXX Version XXXXXX |   *  \section Sec_ChangeLogXXXXXX Version XXXXXX | ||||||
| @ -30,6 +38,8 @@ | |||||||
|   *    LUFA/Drivers/USB/Class/ directory to LUFA/Drivers/USB/HighLevel/ in preperation for the new USB class APIs |   *    LUFA/Drivers/USB/Class/ directory to LUFA/Drivers/USB/HighLevel/ in preperation for the new USB class APIs | ||||||
|   *  - Moved out each demos' functionality library files (e.g. Ring Buffer library) to /Lib directories for a better directory structure |   *  - Moved out each demos' functionality library files (e.g. Ring Buffer library) to /Lib directories for a better directory structure | ||||||
|   *  - Removed Tx interrupt from the USBtoSerial demo; now sends characters via polling to ensure more time for the Rx interrupt |   *  - Removed Tx interrupt from the USBtoSerial demo; now sends characters via polling to ensure more time for the Rx interrupt | ||||||
|  |   *  - Added new EVENT_USB_StartOfFrame event in the library to indicate the start of each USB frame (when generated) | ||||||
|  |   *  - Removed psuedo-scheduler, dynamic memory block allocator from the library (no longer needed and not used respectively) | ||||||
|   * |   * | ||||||
|   * |   * | ||||||
|   *  \section Sec_ChangeLog090510 Version 090510 |   *  \section Sec_ChangeLog090510 Version 090510 | ||||||
|  | |||||||
| @ -10,19 +10,6 @@ | |||||||
|  *  This folder contains header files which are common to all parts of the LUFA library. They may be used freely in |  *  This folder contains header files which are common to all parts of the LUFA library. They may be used freely in | ||||||
|  *  user applications. |  *  user applications. | ||||||
|  * |  * | ||||||
|  *  \dir MemoryAllocator |  | ||||||
|  *  \brief Auto-defragmenting dynamic memory allocation library. |  | ||||||
|  *   |  | ||||||
|  *  This folder contains a simple handle-based dynamic memory allocation library, capable of handing out memory in |  | ||||||
|  *  block chunks. As new memory is allocated, the library will defragment the already allocated memory to ensure |  | ||||||
|  *  optimal memory usage. It is not used within the LUFA library, and is provided as a convenience for user applications. |  | ||||||
|  * |  | ||||||
|  *  \dir Scheduler |  | ||||||
|  *  \brief Simple round-robbin scheduler. |  | ||||||
|  *   |  | ||||||
|  *  This folder contains the simple LUFA round-robbin scheduler, provided as a convenience for user applications. It |  | ||||||
|  *  is very simple in design, and is intended to make code easier to read, rather than providing a complete RTOS kernel. |  | ||||||
|  * |  | ||||||
|  *  \dir Drivers |  *  \dir Drivers | ||||||
|  *  \brief Library hardware and software drivers. |  *  \brief Library hardware and software drivers. | ||||||
|  *   |  *   | ||||||
|  | |||||||
							
								
								
									
										154
									
								
								LUFA/Drivers/USB/Class/Device/Audio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								LUFA/Drivers/USB/Class/Device/Audio.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,154 @@ | |||||||
|  | /*
 | ||||||
|  |              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 "Audio.h" | ||||||
|  | 
 | ||||||
|  | void USB_Audio_ProcessControlPacket(USB_ClassInfo_Audio_t* AudioInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (!(Endpoint_IsSETUPReceived())) | ||||||
|  | 	  return; | ||||||
|  | 	   | ||||||
|  | //	if (USB_ControlRequest.wIndex != AudioInterfaceInfo->InterfaceNumber)
 | ||||||
|  | //	  return;
 | ||||||
|  | 
 | ||||||
|  | 	switch (USB_ControlRequest.bRequest) | ||||||
|  | 	{ | ||||||
|  | 		case REQ_SetInterface: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE)) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 				 | ||||||
|  | 				AudioInterfaceInfo->InterfaceEnabled = (USB_ControlRequest.wValue != 0); | ||||||
|  | 				   | ||||||
|  | 				while (!(Endpoint_IsINReady())); | ||||||
|  | 				Endpoint_ClearIN(); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool USB_Audio_ConfigureEndpoints(USB_ClassInfo_Audio_t* AudioInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (AudioInterfaceInfo->DataINEndpointNumber) | ||||||
|  | 	{ | ||||||
|  | 		if (!(Endpoint_ConfigureEndpoint(AudioInterfaceInfo->DataINEndpointNumber, EP_TYPE_ISOCHRONOUS, | ||||||
|  | 										 ENDPOINT_DIR_IN, AudioInterfaceInfo->DataINEndpointSize, | ||||||
|  | 										 ENDPOINT_BANK_DOUBLE))) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (AudioInterfaceInfo->DataOUTEndpointNumber) | ||||||
|  | 	{ | ||||||
|  | 		if (!(Endpoint_ConfigureEndpoint(AudioInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_ISOCHRONOUS, | ||||||
|  | 										 ENDPOINT_DIR_OUT, AudioInterfaceInfo->DataOUTEndpointSize, | ||||||
|  | 										 ENDPOINT_BANK_DOUBLE))) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int8_t USB_Audio_ReadSample8(void) | ||||||
|  | { | ||||||
|  | 	int8_t Sample; | ||||||
|  | 
 | ||||||
|  | 	Sample = Endpoint_Read_Byte(); | ||||||
|  | 
 | ||||||
|  | 	if (!(Endpoint_IsReadWriteAllowed())) | ||||||
|  | 	  Endpoint_ClearOUT(); | ||||||
|  | 	 | ||||||
|  | 	return Sample; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int16_t USB_Audio_ReadSample16(void) | ||||||
|  | { | ||||||
|  | 	int16_t Sample; | ||||||
|  | 
 | ||||||
|  | 	Sample = (int16_t)Endpoint_Read_Word_LE(); | ||||||
|  | 		   | ||||||
|  | 	if (!(Endpoint_IsReadWriteAllowed())) | ||||||
|  | 	  Endpoint_ClearOUT(); | ||||||
|  | 
 | ||||||
|  | 	return Sample; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t USB_Audio_ReadSample24(void) | ||||||
|  | { | ||||||
|  | 	int32_t Sample; | ||||||
|  | 
 | ||||||
|  | 	Sample = (((uint32_t)Endpoint_Read_Byte() << 16) | Endpoint_Read_Word_LE()); | ||||||
|  | 		   | ||||||
|  | 	if (!(Endpoint_IsReadWriteAllowed())) | ||||||
|  | 	  Endpoint_ClearOUT(); | ||||||
|  | 
 | ||||||
|  | 	return Sample; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void USB_Audio_WriteSample8(int8_t Sample) | ||||||
|  | { | ||||||
|  | 	Endpoint_Write_Byte(Sample); | ||||||
|  | 
 | ||||||
|  | 	if (!(Endpoint_IsReadWriteAllowed())) | ||||||
|  | 	  Endpoint_ClearIN(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void USB_Audio_WriteSample16(int16_t Sample) | ||||||
|  | { | ||||||
|  | 	Endpoint_Write_Word_LE(Sample); | ||||||
|  | 
 | ||||||
|  | 	if (!(Endpoint_IsReadWriteAllowed())) | ||||||
|  | 	  Endpoint_ClearIN(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void USB_Audio_WriteSample24(int32_t Sample) | ||||||
|  | { | ||||||
|  | 	Endpoint_Write_Byte(Sample >> 16); | ||||||
|  | 	Endpoint_Write_Word_LE(Sample); | ||||||
|  | 
 | ||||||
|  | 	if (!(Endpoint_IsReadWriteAllowed())) | ||||||
|  | 	  Endpoint_ClearIN(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool USB_Audio_IsSampleReceived(USB_ClassInfo_Audio_t* AudioInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	Endpoint_SelectEndpoint(AudioInterfaceInfo->DataOUTEndpointNumber); | ||||||
|  | 	return Endpoint_IsOUTReceived(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool USB_Audio_IsReadyForNextSample(USB_ClassInfo_Audio_t* AudioInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	Endpoint_SelectEndpoint(AudioInterfaceInfo->DataINEndpointNumber); | ||||||
|  | 	return Endpoint_IsINReady(); | ||||||
|  | } | ||||||
							
								
								
									
										70
									
								
								LUFA/Drivers/USB/Class/Device/Audio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								LUFA/Drivers/USB/Class/Device/Audio.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | |||||||
|  | /*
 | ||||||
|  |              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. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #ifndef _AUDIO_CLASS_H_ | ||||||
|  | #define _AUDIO_CLASS_H_ | ||||||
|  | 
 | ||||||
|  | 	/* Includes: */ | ||||||
|  | 		#include "../../USB.h" | ||||||
|  | 
 | ||||||
|  | 		#include <string.h> | ||||||
|  | 
 | ||||||
|  | 	/* Macros: */ | ||||||
|  | 
 | ||||||
|  | 	/* Enums: */ | ||||||
|  | 
 | ||||||
|  | 	/* Type Defines: */ | ||||||
|  | 		typedef struct | ||||||
|  | 		{ | ||||||
|  | 			uint8_t  InterfaceNumber; | ||||||
|  | 
 | ||||||
|  | 			uint8_t  DataINEndpointNumber; | ||||||
|  | 			uint16_t DataINEndpointSize; | ||||||
|  | 
 | ||||||
|  | 			uint8_t  DataOUTEndpointNumber; | ||||||
|  | 			uint16_t DataOUTEndpointSize; | ||||||
|  | 
 | ||||||
|  | 			bool     InterfaceEnabled; | ||||||
|  | 		} USB_ClassInfo_Audio_t; | ||||||
|  | 		 | ||||||
|  | 	/* Function Prototypes: */ | ||||||
|  | 		bool     USB_Audio_ConfigureEndpoints(USB_ClassInfo_Audio_t* AudioInterfaceInfo); | ||||||
|  | 		void     USB_Audio_ProcessControlPacket(USB_ClassInfo_Audio_t* AudioInterfaceInfo); | ||||||
|  | 		void     USB_Audio_USBTask(USB_ClassInfo_Audio_t* AudioInterfaceInfo); | ||||||
|  | 		 | ||||||
|  | 		int8_t   USB_Audio_ReadSample8(void); | ||||||
|  | 		int16_t  USB_Audio_ReadSample16(void); | ||||||
|  | 		int32_t  USB_Audio_ReadSample24(void); | ||||||
|  | 		void     USB_Audio_WriteSample8(int8_t Sample); | ||||||
|  | 		void     USB_Audio_WriteSample16(int16_t Sample); | ||||||
|  | 		void     USB_Audio_WriteSample24(int32_t Sample); | ||||||
|  | 		bool     USB_Audio_IsSampleReceived(USB_ClassInfo_Audio_t* AudioInterfaceInfo); | ||||||
|  | 		bool     USB_Audio_IsReadyForNextSample(USB_ClassInfo_Audio_t* AudioInterfaceInfo); | ||||||
|  | #endif | ||||||
							
								
								
									
										185
									
								
								LUFA/Drivers/USB/Class/Device/CDC.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								LUFA/Drivers/USB/Class/Device/CDC.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,185 @@ | |||||||
|  | /*
 | ||||||
|  |              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. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #define  INCLUDE_FROM_CDC_CLASS_C | ||||||
|  | #include "CDC.h" | ||||||
|  | 
 | ||||||
|  | void USB_CDC_Event_Stub(void) | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void USB_CDC_ProcessControlPacket(USB_ClassInfo_CDC_t* CDCInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (!(Endpoint_IsSETUPReceived())) | ||||||
|  | 	  return; | ||||||
|  | 	   | ||||||
|  | 	if (USB_ControlRequest.wIndex != CDCInterfaceInfo->ControlInterfaceNumber) | ||||||
|  | 	  return; | ||||||
|  | 
 | ||||||
|  | 	switch (USB_ControlRequest.bRequest) | ||||||
|  | 	{ | ||||||
|  | 		case REQ_GetLineEncoding: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 				Endpoint_Write_Control_Stream_LE(&CDCInterfaceInfo->LineEncoding, sizeof(CDCInterfaceInfo->LineEncoding)); | ||||||
|  | 				Endpoint_ClearOUT(); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			break; | ||||||
|  | 		case REQ_SetLineEncoding: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 				Endpoint_Read_Control_Stream_LE(&CDCInterfaceInfo->LineEncoding, sizeof(CDCInterfaceInfo->LineEncoding)); | ||||||
|  | 				Endpoint_ClearIN(); | ||||||
|  | 
 | ||||||
|  | 				EVENT_USB_CDC_LineEncodingChanged(CDCInterfaceInfo); | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
|  | 			break; | ||||||
|  | 		case REQ_SetControlLineState: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{				 | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 				 | ||||||
|  | 				CDCInterfaceInfo->ControlLineState = USB_ControlRequest.wValue; | ||||||
|  | 				 | ||||||
|  | 				EVENT_USB_CDC_ControLineStateChanged(); | ||||||
|  | 
 | ||||||
|  | 				while (!(Endpoint_IsINReady())); | ||||||
|  | 				Endpoint_ClearIN(); | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool USB_CDC_ConfigureEndpoints(USB_ClassInfo_CDC_t* CDCInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK, | ||||||
|  | 							         ENDPOINT_DIR_IN, CDCInterfaceInfo->DataINEndpointSize, | ||||||
|  | 							         ENDPOINT_BANK_SINGLE))) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK, | ||||||
|  | 	                                 ENDPOINT_DIR_OUT, CDCInterfaceInfo->DataOUTEndpointSize, | ||||||
|  | 	                                 ENDPOINT_BANK_SINGLE))) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->NotificationEndpointNumber, EP_TYPE_INTERRUPT, | ||||||
|  | 	                                 ENDPOINT_DIR_IN, CDCInterfaceInfo->NotificationEndpointSize, | ||||||
|  | 	                                 ENDPOINT_BANK_SINGLE))) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void USB_CDC_USBTask(USB_ClassInfo_CDC_t* CDCInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (!(USB_IsConnected)) | ||||||
|  | 	  return; | ||||||
|  | 
 | ||||||
|  | 	Endpoint_SelectEndpoint(CDCInterfaceInfo->DataINEndpointNumber); | ||||||
|  | 
 | ||||||
|  | 	if (!(Endpoint_BytesInEndpoint())) | ||||||
|  | 	  return; | ||||||
|  | 	   | ||||||
|  | 	if (!(Endpoint_IsReadWriteAllowed())) | ||||||
|  | 	{ | ||||||
|  | 		Endpoint_ClearIN(); | ||||||
|  | 		while (!(Endpoint_IsReadWriteAllowed())); | ||||||
|  | 	}	 | ||||||
|  | 	 | ||||||
|  | 	Endpoint_ClearIN(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void USB_CDC_SendString(USB_ClassInfo_CDC_t* CDCInterfaceInfo, char* Data, uint16_t Length) | ||||||
|  | { | ||||||
|  | 	Endpoint_SelectEndpoint(CDCInterfaceInfo->DataINEndpointNumber); | ||||||
|  | 	Endpoint_Write_Stream_LE(Data, Length, NO_STREAM_CALLBACK); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void USB_CDC_SendByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint8_t Data) | ||||||
|  | { | ||||||
|  | 	Endpoint_SelectEndpoint(CDCInterfaceInfo->DataINEndpointNumber); | ||||||
|  | 
 | ||||||
|  | 	if (!(Endpoint_IsReadWriteAllowed())) | ||||||
|  | 	{ | ||||||
|  | 		Endpoint_ClearIN(); | ||||||
|  | 		while (!(Endpoint_IsReadWriteAllowed())); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	Endpoint_Write_Byte(Data);	 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint16_t USB_CDC_BytesReceived(USB_ClassInfo_CDC_t* CDCInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	Endpoint_SelectEndpoint(CDCInterfaceInfo->DataOUTEndpointNumber); | ||||||
|  | 
 | ||||||
|  | 	return Endpoint_BytesInEndpoint(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t USB_CDC_ReceiveByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	Endpoint_SelectEndpoint(CDCInterfaceInfo->DataOUTEndpointNumber); | ||||||
|  | 	 | ||||||
|  | 	uint8_t DataByte = Endpoint_Read_Byte(); | ||||||
|  | 	 | ||||||
|  | 	if (!(Endpoint_BytesInEndpoint())) | ||||||
|  | 	  Endpoint_ClearOUT(); | ||||||
|  | 	   | ||||||
|  | 	return DataByte; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void USB_CDC_SendSerialLineStateChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint16_t LineStateMask) | ||||||
|  | { | ||||||
|  | 	Endpoint_SelectEndpoint(CDCInterfaceInfo->NotificationEndpointNumber); | ||||||
|  | 	 | ||||||
|  | 	USB_Request_Header_t Notification = (USB_Request_Header_t) | ||||||
|  | 		{ | ||||||
|  | 			.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), | ||||||
|  | 			.bRequest      = NOTIF_SerialState, | ||||||
|  | 			.wValue        = 0, | ||||||
|  | 			.wIndex        = 0, | ||||||
|  | 			.wLength       = sizeof(uint16_t), | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
|  | 	Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK); | ||||||
|  | 	Endpoint_Write_Stream_LE(&LineStateMask, sizeof(LineStateMask), NO_STREAM_CALLBACK); | ||||||
|  | 	Endpoint_ClearIN(); | ||||||
|  | } | ||||||
							
								
								
									
										188
									
								
								LUFA/Drivers/USB/Class/Device/CDC.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								LUFA/Drivers/USB/Class/Device/CDC.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,188 @@ | |||||||
|  | /*
 | ||||||
|  |              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. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #ifndef _CDC_CLASS_H_ | ||||||
|  | #define _CDC_CLASS_H_ | ||||||
|  | 
 | ||||||
|  | 	/* Includes: */ | ||||||
|  | 		#include "../../USB.h" | ||||||
|  | 
 | ||||||
|  | 		#include <string.h> | ||||||
|  | 
 | ||||||
|  | 	/* 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 occurred 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 occurred 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 occurred on the virtual serial port. | ||||||
|  | 		 */ | ||||||
|  | 		#define CONTROL_LINE_IN_OVERRUNERROR (1 << 6) | ||||||
|  | 		 | ||||||
|  | 		/** 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];  \ | ||||||
|  | 		     } | ||||||
|  | 
 | ||||||
|  | 	/* 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 */ | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
|  | 	/* 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 | ||||||
|  | 		{ | ||||||
|  | 			uint8_t  ControlInterfaceNumber; /**< Interface number of the CDC control interface within the device */ | ||||||
|  | 
 | ||||||
|  | 			uint8_t  DataINEndpointNumber; /**< Endpoint number of the CDC interface's IN data endpoint */ | ||||||
|  | 			uint16_t DataINEndpointSize; /**< Size in bytes of the CDC interface's IN data endpoint */ | ||||||
|  | 
 | ||||||
|  | 			uint8_t  DataOUTEndpointNumber; /**< Endpoint number of the CDC interface's OUT data endpoint */ | ||||||
|  | 			uint16_t DataOUTEndpointSize;  /**< Size in bytes of the CDC interface's OUT data endpoint */ | ||||||
|  | 
 | ||||||
|  | 			uint8_t  NotificationEndpointNumber; /**< Endpoint number of the CDC interface's IN notification endpoint, if used */ | ||||||
|  | 			uint16_t NotificationEndpointSize;  /**< Size in bytes of the CDC interface's IN notification endpoint, if used */ | ||||||
|  | 
 | ||||||
|  | 			uint8_t  ControlLineState; | ||||||
|  | 
 | ||||||
|  | 			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 character of the virtual serial port */ | ||||||
|  | 			} LineEncoding; | ||||||
|  | 		} USB_ClassInfo_CDC_t; | ||||||
|  | 		 | ||||||
|  | 	/* Function Prototypes: */ | ||||||
|  | 		#if defined(INCLUDE_FROM_CDC_CLASS_C) | ||||||
|  | 			void USB_CDC_Event_Stub(void); | ||||||
|  | 			void EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo) | ||||||
|  | 												   ATTR_WEAK ATTR_ALIAS(USB_CDC_Event_Stub); | ||||||
|  | 			void EVENT_USB_CDC_ControLineStateChanged(void) ATTR_WEAK ATTR_ALIAS(USB_CDC_Event_Stub);;  | ||||||
|  | 		#endif | ||||||
|  | 	 | ||||||
|  | 		void     USB_CDC_USBTask(USB_ClassInfo_CDC_t* CDCInterfaceInfo); | ||||||
|  | 		bool     USB_CDC_ConfigureEndpoints(USB_ClassInfo_CDC_t* CDCInterfaceInfo); | ||||||
|  | 		void     USB_CDC_ProcessControlPacket(USB_ClassInfo_CDC_t* CDCInterfaceInfo); | ||||||
|  | 		void     USB_CDC_USBTask(USB_ClassInfo_CDC_t* CDCInterfaceInfo); | ||||||
|  | 
 | ||||||
|  | 		void     EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo); | ||||||
|  | 		void     EVENT_USB_CDC_ControLineStateChanged(void); | ||||||
|  | 
 | ||||||
|  | 		void     USB_CDC_SendString(USB_ClassInfo_CDC_t* CDCInterfaceInfo, char* Data, uint16_t Length); | ||||||
|  | 		void     USB_CDC_SendByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint8_t Data); | ||||||
|  | 		uint16_t USB_CDC_BytesReceived(USB_ClassInfo_CDC_t* CDCInterfaceInfo); | ||||||
|  | 		uint8_t  USB_CDC_ReceiveByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo); | ||||||
|  | 		void USB_CDC_SendSerialLineStateChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint16_t LineStateMask); | ||||||
|  | 		 | ||||||
|  | #endif | ||||||
							
								
								
									
										211
									
								
								LUFA/Drivers/USB/Class/Device/HID.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								LUFA/Drivers/USB/Class/Device/HID.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,211 @@ | |||||||
|  | /*
 | ||||||
|  |              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 "HID.h" | ||||||
|  | 
 | ||||||
|  | void USB_HID_ProcessControlPacket(USB_ClassInfo_HID_t* HIDInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (!(Endpoint_IsSETUPReceived())) | ||||||
|  | 	  return; | ||||||
|  | 	   | ||||||
|  | 	if (USB_ControlRequest.wIndex != HIDInterfaceInfo->InterfaceNumber) | ||||||
|  | 	  return; | ||||||
|  | 
 | ||||||
|  | 	switch (USB_ControlRequest.bRequest) | ||||||
|  | 	{ | ||||||
|  | 		case REQ_GetReport: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ClearSETUP();	 | ||||||
|  | 
 | ||||||
|  | 				uint8_t  ReportINData[HIDInterfaceInfo->ReportBufferSize]; | ||||||
|  | 				uint16_t ReportINSize; | ||||||
|  | 
 | ||||||
|  | 				memset(ReportINData, 0, sizeof(ReportINData)); | ||||||
|  | 
 | ||||||
|  | 				ReportINSize = CALLBACK_USB_HID_CreateNextHIDReport(HIDInterfaceInfo, ReportINData); | ||||||
|  | 
 | ||||||
|  | 				Endpoint_Write_Control_Stream_LE(ReportINData, ReportINSize); | ||||||
|  | 				Endpoint_ClearOUT(); | ||||||
|  | 			} | ||||||
|  | 		 | ||||||
|  | 			break; | ||||||
|  | 		case REQ_SetReport: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 				 | ||||||
|  | 				uint16_t ReportOUTSize = USB_ControlRequest.wLength; | ||||||
|  | 				uint8_t  ReportOUTData[ReportOUTSize]; | ||||||
|  | 
 | ||||||
|  | 				Endpoint_Read_Control_Stream_LE(ReportOUTData, ReportOUTSize); | ||||||
|  | 				Endpoint_ClearIN(); | ||||||
|  | 				 | ||||||
|  | 				CALLBACK_USB_HID_ProcessReceivedHIDReport(HIDInterfaceInfo, ReportOUTData, ReportOUTSize); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			break; | ||||||
|  | 		case REQ_GetProtocol: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 
 | ||||||
|  | 				Endpoint_Write_Byte(HIDInterfaceInfo->UsingReportProtocol); | ||||||
|  | 				Endpoint_ClearIN(); | ||||||
|  | 
 | ||||||
|  | 				while (!(Endpoint_IsOUTReceived())); | ||||||
|  | 				Endpoint_ClearOUT(); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			break; | ||||||
|  | 		case REQ_SetProtocol: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 
 | ||||||
|  | 				HIDInterfaceInfo->UsingReportProtocol = (USB_ControlRequest.wValue != 0x0000); | ||||||
|  | 				 | ||||||
|  | 				while (!(Endpoint_IsINReady())); | ||||||
|  | 				Endpoint_ClearIN(); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			break; | ||||||
|  | 		case REQ_SetIdle: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 				 | ||||||
|  | 				HIDInterfaceInfo->IdleCount = ((USB_ControlRequest.wValue >> 8) << 2); | ||||||
|  | 				 | ||||||
|  | 				while (!(Endpoint_IsINReady())); | ||||||
|  | 				Endpoint_ClearIN(); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			break; | ||||||
|  | 		case REQ_GetIdle: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{		 | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 				 | ||||||
|  | 				Endpoint_Write_Byte(HIDInterfaceInfo->IdleCount >> 2); | ||||||
|  | 				Endpoint_ClearIN(); | ||||||
|  | 
 | ||||||
|  | 				while (!(Endpoint_IsOUTReceived())); | ||||||
|  | 				Endpoint_ClearOUT(); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool USB_HID_ConfigureEndpoints(USB_ClassInfo_HID_t* HIDInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	HIDInterfaceInfo->UsingReportProtocol = true; | ||||||
|  | 
 | ||||||
|  | 	if (!(Endpoint_ConfigureEndpoint(HIDInterfaceInfo->ReportINEndpointNumber, EP_TYPE_INTERRUPT, | ||||||
|  | 									 ENDPOINT_DIR_IN, HIDInterfaceInfo->ReportINEndpointSize, ENDPOINT_BANK_SINGLE))) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if (HIDInterfaceInfo->ReportOUTEndpointNumber) | ||||||
|  | 	{ | ||||||
|  | 		if (!(Endpoint_ConfigureEndpoint(HIDInterfaceInfo->ReportOUTEndpointNumber, EP_TYPE_INTERRUPT, | ||||||
|  | 										 ENDPOINT_DIR_OUT, HIDInterfaceInfo->ReportOUTEndpointSize, ENDPOINT_BANK_SINGLE))) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void USB_HID_RegisterStartOfFrame(USB_ClassInfo_HID_t* HIDInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (HIDInterfaceInfo->IdleMSRemaining) | ||||||
|  | 	  HIDInterfaceInfo->IdleMSRemaining--; | ||||||
|  | } | ||||||
|  | 		 | ||||||
|  | void USB_HID_USBTask(USB_ClassInfo_HID_t* HIDInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (!(USB_IsConnected)) | ||||||
|  | 	  return; | ||||||
|  | 
 | ||||||
|  | 	Endpoint_SelectEndpoint(HIDInterfaceInfo->ReportINEndpointNumber); | ||||||
|  | 	 | ||||||
|  | 	if (Endpoint_IsReadWriteAllowed() && | ||||||
|  | 	    !(HIDInterfaceInfo->IdleCount && HIDInterfaceInfo->IdleMSRemaining)) | ||||||
|  | 	{ | ||||||
|  | 		if (HIDInterfaceInfo->IdleCount && !(HIDInterfaceInfo->IdleMSRemaining)) | ||||||
|  | 		  HIDInterfaceInfo->IdleMSRemaining = HIDInterfaceInfo->IdleCount; | ||||||
|  | 
 | ||||||
|  | 		uint8_t  ReportINData[HIDInterfaceInfo->ReportBufferSize]; | ||||||
|  | 		uint16_t ReportINSize; | ||||||
|  | 
 | ||||||
|  | 		memset(ReportINData, 0, sizeof(ReportINData)); | ||||||
|  | 
 | ||||||
|  | 		ReportINSize = CALLBACK_USB_HID_CreateNextHIDReport(HIDInterfaceInfo, ReportINData); | ||||||
|  | 
 | ||||||
|  | 		if (ReportINSize) | ||||||
|  | 		{ | ||||||
|  | 			Endpoint_Write_Stream_LE(ReportINData, ReportINSize | ||||||
|  | 			#if !defined(NO_STREAM_CALLBACKS) | ||||||
|  | 			                         , NO_STREAM_CALLBACK | ||||||
|  | 			#endif | ||||||
|  | 			                         ); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		Endpoint_ClearIN(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if (HIDInterfaceInfo->ReportOUTEndpointNumber) | ||||||
|  | 	{ | ||||||
|  | 		Endpoint_SelectEndpoint(HIDInterfaceInfo->ReportOUTEndpointNumber); | ||||||
|  | 		 | ||||||
|  | 		if (Endpoint_IsOUTReceived()) | ||||||
|  | 		{ | ||||||
|  | 			uint16_t ReportOUTSize = Endpoint_BytesInEndpoint(); | ||||||
|  | 			uint8_t  ReportOUTData[ReportOUTSize]; | ||||||
|  | 			 | ||||||
|  | 			if (ReportOUTSize) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_Read_Stream_LE(ReportOUTData, ReportOUTSize | ||||||
|  | 				#if !defined(NO_STREAM_CALLBACKS) | ||||||
|  | 			                            , NO_STREAM_CALLBACK | ||||||
|  | 				#endif | ||||||
|  | 			                            ); | ||||||
|  | 			} | ||||||
|  | 			   | ||||||
|  | 			CALLBACK_USB_HID_ProcessReceivedHIDReport(HIDInterfaceInfo, ReportOUTData, ReportOUTSize); | ||||||
|  | 			 | ||||||
|  | 			Endpoint_ClearOUT(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										115
									
								
								LUFA/Drivers/USB/Class/Device/HID.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								LUFA/Drivers/USB/Class/Device/HID.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,115 @@ | |||||||
|  | /*
 | ||||||
|  |              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. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #ifndef _HID_CLASS_H_ | ||||||
|  | #define _HID_CLASS_H_ | ||||||
|  | 
 | ||||||
|  | 	/* Includes: */ | ||||||
|  | 		#include "../../USB.h" | ||||||
|  | 
 | ||||||
|  | 		#include <string.h> | ||||||
|  | 
 | ||||||
|  | 	/* 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 | ||||||
|  | 
 | ||||||
|  | 		/** Descriptor header type value, to indicate a HID class HID descriptor. */ | ||||||
|  | 		#define DTYPE_HID          0x21 | ||||||
|  | 		 | ||||||
|  | 		/** Descriptor header type value, to indicate a HID class HID report descriptor. */ | ||||||
|  | 		#define DTYPE_Report       0x22 | ||||||
|  | 
 | ||||||
|  | 	/* Type Defines: */ | ||||||
|  | 		/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
 | ||||||
|  | 		 *  specification for details on the structure elements. | ||||||
|  | 		 */ | ||||||
|  | 		typedef struct | ||||||
|  | 		{ | ||||||
|  | 			USB_Descriptor_Header_t               Header; | ||||||
|  | 				 | ||||||
|  | 			uint16_t                              HIDSpec; | ||||||
|  | 			uint8_t                               CountryCode; | ||||||
|  | 		 | ||||||
|  | 			uint8_t                               TotalReportDescriptors; | ||||||
|  | 
 | ||||||
|  | 			uint8_t                               HIDReportType; | ||||||
|  | 			uint16_t                              HIDReportLength; | ||||||
|  | 		} USB_Descriptor_HID_t; | ||||||
|  | 
 | ||||||
|  | 		/** Type define for the data type used to store HID report descriptor elements. */ | ||||||
|  | 		typedef uint8_t USB_Descriptor_HIDReport_Datatype_t; | ||||||
|  | 
 | ||||||
|  | 		/** Class state structure. An instance of this structure should be made for each HID interface
 | ||||||
|  | 		 *  within the user application, and passed to each of the HID class driver functions as the | ||||||
|  | 		 *  HIDInterfaceInfo parameter. The contents of this structure should be set to their correct | ||||||
|  | 		 *  values when used, or ommitted to force the library to use default values. | ||||||
|  | 		 */ | ||||||
|  | 		typedef struct | ||||||
|  | 		{ | ||||||
|  | 			uint8_t  InterfaceNumber; /**< Interface number of the HID interface within the device */ | ||||||
|  | 
 | ||||||
|  | 			uint8_t  ReportINEndpointNumber; /**< Endpoint number of the HID interface's IN report endpoint */ | ||||||
|  | 			uint16_t ReportINEndpointSize; /**< Size in bytes of the HID interface's IN report endpoint */ | ||||||
|  | 
 | ||||||
|  | 			uint8_t  ReportOUTEndpointNumber; /**< Endpoint number of the HID interface's OUT report endpoint, if used */ | ||||||
|  | 			uint16_t ReportOUTEndpointSize;  /**< Size in bytes of the HID interface's OUT report endpoint, if used */ | ||||||
|  | 			 | ||||||
|  | 			uint8_t  ReportBufferSize; | ||||||
|  | 
 | ||||||
|  | 			bool     UsingReportProtocol; /**< Indicates if the HID interface is set to Boot or Report protocol mode */ | ||||||
|  | 			uint16_t IdleCount; /**< Report idle period, in ms, set by the host */ | ||||||
|  | 			uint16_t IdleMSRemaining; /**< Total number of ms remaining before the idle period elapses */ | ||||||
|  | 		} USB_ClassInfo_HID_t; | ||||||
|  | 
 | ||||||
|  | 	/* Function Prototypes: */ | ||||||
|  | 		bool USB_HID_ConfigureEndpoints(USB_ClassInfo_HID_t* HIDInterfaceInfo); | ||||||
|  | 		void USB_HID_ProcessControlPacket(USB_ClassInfo_HID_t* HIDInterfaceInfo); | ||||||
|  | 		void USB_HID_RegisterStartOfFrame(USB_ClassInfo_HID_t* HIDInterfaceInfo); | ||||||
|  | 		void USB_HID_USBTask(USB_ClassInfo_HID_t* HIDInterfaceInfo); | ||||||
|  | 		 | ||||||
|  | 		uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData); | ||||||
|  | 		void     CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize); | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
							
								
								
									
										208
									
								
								LUFA/Drivers/USB/Class/Device/MassStorage.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								LUFA/Drivers/USB/Class/Device/MassStorage.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,208 @@ | |||||||
|  | /*
 | ||||||
|  |              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. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #define  INCLUDE_FROM_MS_CLASS_C | ||||||
|  | #include "MassStorage.h" | ||||||
|  | 
 | ||||||
|  | static USB_ClassInfo_MS_t* CallbackMSInterfaceInfo; | ||||||
|  | 
 | ||||||
|  | void USB_MS_ProcessControlPacket(USB_ClassInfo_MS_t* MSInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (!(Endpoint_IsSETUPReceived())) | ||||||
|  | 	  return; | ||||||
|  | 	   | ||||||
|  | 	if (USB_ControlRequest.wIndex != MSInterfaceInfo->InterfaceNumber) | ||||||
|  | 	  return; | ||||||
|  | 
 | ||||||
|  | 	switch (USB_ControlRequest.bRequest) | ||||||
|  | 	{ | ||||||
|  | 		case REQ_MassStorageReset: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 
 | ||||||
|  | 				MSInterfaceInfo->IsMassStoreReset = true;			 | ||||||
|  | 
 | ||||||
|  | 				while (!(Endpoint_IsINReady())); | ||||||
|  | 				Endpoint_ClearIN(); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			break; | ||||||
|  | 		case REQ_GetMaxLUN: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 
 | ||||||
|  | 				Endpoint_Write_Byte(MSInterfaceInfo->TotalLUNs - 1); | ||||||
|  | 				 | ||||||
|  | 				Endpoint_ClearIN(); | ||||||
|  | 				 | ||||||
|  | 				while (!(Endpoint_IsOUTReceived())); | ||||||
|  | 				Endpoint_ClearOUT(); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool USB_MS_ConfigureEndpoints(USB_ClassInfo_MS_t* MSInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (!(Endpoint_ConfigureEndpoint(MSInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK, | ||||||
|  | 							         ENDPOINT_DIR_IN, MSInterfaceInfo->DataINEndpointSize, | ||||||
|  | 							         ENDPOINT_BANK_SINGLE))) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!(Endpoint_ConfigureEndpoint(MSInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK, | ||||||
|  | 	                                 ENDPOINT_DIR_OUT, MSInterfaceInfo->DataOUTEndpointSize, | ||||||
|  | 	                                 ENDPOINT_BANK_SINGLE))) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void USB_MS_USBTask(USB_ClassInfo_MS_t* MSInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (!(USB_IsConnected)) | ||||||
|  | 	  return; | ||||||
|  | 
 | ||||||
|  | 	Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber); | ||||||
|  | 		 | ||||||
|  | 	if (Endpoint_IsReadWriteAllowed()) | ||||||
|  | 	{ | ||||||
|  | 		if (USB_MS_ReadInCommandBlock(MSInterfaceInfo)) | ||||||
|  | 		{ | ||||||
|  | 			if (MSInterfaceInfo->CommandBlock.Flags & COMMAND_DIRECTION_DATA_IN) | ||||||
|  | 			  Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber); | ||||||
|  | 			   | ||||||
|  | 			MSInterfaceInfo->CommandStatus.Status              = CALLBACK_USB_MS_SCSICommandReceived(MSInterfaceInfo) ? | ||||||
|  | 			                                                      Command_Pass : Command_Fail; | ||||||
|  | 			MSInterfaceInfo->CommandStatus.Signature           = CSW_SIGNATURE; | ||||||
|  | 			MSInterfaceInfo->CommandStatus.Tag                 = MSInterfaceInfo->CommandBlock.Tag; | ||||||
|  | 			MSInterfaceInfo->CommandStatus.DataTransferResidue = MSInterfaceInfo->CommandBlock.DataTransferLength; | ||||||
|  | 
 | ||||||
|  | 			if ((MSInterfaceInfo->CommandStatus.Status == Command_Fail) && (MSInterfaceInfo->CommandStatus.DataTransferResidue)) | ||||||
|  | 			  Endpoint_StallTransaction(); | ||||||
|  | 			 | ||||||
|  | 			USB_MS_ReturnCommandStatus(MSInterfaceInfo); | ||||||
|  | 			 | ||||||
|  | 			if (MSInterfaceInfo->IsMassStoreReset) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ResetFIFO(MSInterfaceInfo->DataOUTEndpointNumber); | ||||||
|  | 				Endpoint_ResetFIFO(MSInterfaceInfo->DataINEndpointNumber); | ||||||
|  | 				 | ||||||
|  | 				Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber); | ||||||
|  | 				Endpoint_ClearStall(); | ||||||
|  | 				Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber); | ||||||
|  | 				Endpoint_ClearStall(); | ||||||
|  | 
 | ||||||
|  | 				MSInterfaceInfo->IsMassStoreReset = false; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool USB_MS_ReadInCommandBlock(USB_ClassInfo_MS_t* MSInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber); | ||||||
|  | 
 | ||||||
|  | 	CallbackMSInterfaceInfo = MSInterfaceInfo; | ||||||
|  | 	Endpoint_Read_Stream_LE(&MSInterfaceInfo->CommandBlock, | ||||||
|  | 	                        (sizeof(CommandBlockWrapper_t) - MAX_SCSI_COMMAND_LENGTH), | ||||||
|  | 	                        StreamCallback_AbortOnMassStoreReset); | ||||||
|  | 
 | ||||||
|  | 	if ((MSInterfaceInfo->CommandBlock.Signature         != CBW_SIGNATURE)              || | ||||||
|  | 	    (MSInterfaceInfo->CommandBlock.LUN               >= MSInterfaceInfo->TotalLUNs) || | ||||||
|  | 		(MSInterfaceInfo->CommandBlock.SCSICommandLength >  MAX_SCSI_COMMAND_LENGTH)) | ||||||
|  | 	{ | ||||||
|  | 		Endpoint_StallTransaction(); | ||||||
|  | 		Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber); | ||||||
|  | 		Endpoint_StallTransaction(); | ||||||
|  | 		 | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	CallbackMSInterfaceInfo = MSInterfaceInfo; | ||||||
|  | 	Endpoint_Read_Stream_LE(&MSInterfaceInfo->CommandBlock.SCSICommandData, | ||||||
|  | 	                        MSInterfaceInfo->CommandBlock.SCSICommandLength, | ||||||
|  | 	                        StreamCallback_AbortOnMassStoreReset); | ||||||
|  | 							 | ||||||
|  | 	Endpoint_ClearOUT(); | ||||||
|  | 	   | ||||||
|  | 	if (MSInterfaceInfo->IsMassStoreReset) | ||||||
|  | 	  return false; | ||||||
|  | 
 | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void USB_MS_ReturnCommandStatus(USB_ClassInfo_MS_t* MSInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber); | ||||||
|  | 
 | ||||||
|  | 	while (Endpoint_IsStalled()) | ||||||
|  | 	{ | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 
 | ||||||
|  | 		if (MSInterfaceInfo->IsMassStoreReset) | ||||||
|  | 		  return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber); | ||||||
|  | 
 | ||||||
|  | 	while (Endpoint_IsStalled()) | ||||||
|  | 	{ | ||||||
|  | 		USB_USBTask(); | ||||||
|  | 
 | ||||||
|  | 		if (MSInterfaceInfo->IsMassStoreReset) | ||||||
|  | 		  return; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	CallbackMSInterfaceInfo = MSInterfaceInfo; | ||||||
|  | 	Endpoint_Write_Stream_LE(&MSInterfaceInfo->CommandStatus, sizeof(CommandStatusWrapper_t), | ||||||
|  | 	                         StreamCallback_AbortOnMassStoreReset); | ||||||
|  | 	 | ||||||
|  | 	Endpoint_ClearIN(); | ||||||
|  | 
 | ||||||
|  | 	if (MSInterfaceInfo->IsMassStoreReset) | ||||||
|  | 	  return; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static uint8_t StreamCallback_AbortOnMassStoreReset(void) | ||||||
|  | { | ||||||
|  | 	USB_MS_USBTask(CallbackMSInterfaceInfo); | ||||||
|  | 
 | ||||||
|  | 	if (CallbackMSInterfaceInfo->IsMassStoreReset) | ||||||
|  | 	  return STREAMCALLBACK_Abort; | ||||||
|  | 	else | ||||||
|  | 	  return STREAMCALLBACK_Continue; | ||||||
|  | } | ||||||
							
								
								
									
										127
									
								
								LUFA/Drivers/USB/Class/Device/MassStorage.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								LUFA/Drivers/USB/Class/Device/MassStorage.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,127 @@ | |||||||
|  | /*
 | ||||||
|  |              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. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #ifndef _MS_CLASS_H_ | ||||||
|  | #define _MS_CLASS_H_ | ||||||
|  | 
 | ||||||
|  | 	/* Includes: */ | ||||||
|  | 		#include "../../USB.h" | ||||||
|  | 
 | ||||||
|  | 		#include <string.h> | ||||||
|  | 
 | ||||||
|  | 	/* Macros: */ | ||||||
|  | 		/** Mass Storage Class specific request to reset the Mass Storage interface, ready for the next command. */ | ||||||
|  | 		#define REQ_MassStorageReset       0xFF | ||||||
|  | 
 | ||||||
|  | 		/** Mass Storage Class specific request to retrieve the total number of Logical Units (drives) in the SCSI device. */ | ||||||
|  | 		#define REQ_GetMaxLUN              0xFE | ||||||
|  | 
 | ||||||
|  | 		/** Maximum length of a SCSI command which can be issued by the device or host in a Mass Storage bulk wrapper. */ | ||||||
|  | 		#define MAX_SCSI_COMMAND_LENGTH    16 | ||||||
|  | 		 | ||||||
|  | 		/** Magic signature for a Command Block Wrapper used in the Mass Storage Bulk-Only transport protocol. */ | ||||||
|  | 		#define CBW_SIGNATURE              0x43425355UL | ||||||
|  | 
 | ||||||
|  | 		/** Magic signature for a Command Status Wrapper used in the Mass Storage Bulk-Only transport protocol. */ | ||||||
|  | 		#define CSW_SIGNATURE              0x53425355UL | ||||||
|  | 		 | ||||||
|  | 		/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from host-to-device. */ | ||||||
|  | 		#define COMMAND_DIRECTION_DATA_OUT (0 << 7) | ||||||
|  | 
 | ||||||
|  | 		/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from device-to-host. */ | ||||||
|  | 		#define COMMAND_DIRECTION_DATA_IN  (1 << 7) | ||||||
|  | 
 | ||||||
|  | 	/* Type defines: */ | ||||||
|  | 		/** Type define for a Command Block Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */ | ||||||
|  | 		typedef struct | ||||||
|  | 		{ | ||||||
|  | 			uint32_t Signature; /**< Command block signature, must be CBW_SIGNATURE to indicate a valid Command Block */ | ||||||
|  | 			uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */ | ||||||
|  | 			uint32_t DataTransferLength; /** Length of the optional data portion of the issued command, in bytes */ | ||||||
|  | 			uint8_t  Flags; /**< Command block flags, indicating command data direction */ | ||||||
|  | 			uint8_t  LUN; /**< Logical Unit number this command is issued to */ | ||||||
|  | 			uint8_t  SCSICommandLength; /**< Length of the issued SCSI command within the SCSI command data array */ | ||||||
|  | 			uint8_t  SCSICommandData[MAX_SCSI_COMMAND_LENGTH]; /**< Issued SCSI command in the Command Block */ | ||||||
|  | 		} CommandBlockWrapper_t; | ||||||
|  | 		 | ||||||
|  | 		/** Type define for a Command Status Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */ | ||||||
|  | 		typedef struct | ||||||
|  | 		{ | ||||||
|  | 			uint32_t Signature; /**< Status block signature, must be CSW_SIGNATURE to indicate a valid Command Status */ | ||||||
|  | 			uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */ | ||||||
|  | 			uint32_t DataTransferResidue; /**< Number of bytes of data not processed in the SCSI command */ | ||||||
|  | 			uint8_t  Status; /**< Status code of the issued command - a value from the MassStorage_CommandStatusCodes_t enum */ | ||||||
|  | 		} CommandStatusWrapper_t; | ||||||
|  | 		 | ||||||
|  | 	/* Enums: */ | ||||||
|  | 		/** Enum for the possible command status wrapper return status codes. */ | ||||||
|  | 		enum MassStorage_CommandStatusCodes_t | ||||||
|  | 		{ | ||||||
|  | 			Command_Pass = 0, /**< Command completed with no error */ | ||||||
|  | 			Command_Fail = 1, /**< Command failed to complete - host may check the exact error via a SCSI REQUEST SENSE command */ | ||||||
|  | 			Phase_Error  = 2  /**< Command failed due to being invalid in the current phase */ | ||||||
|  | 		}; | ||||||
|  | 		 | ||||||
|  | 	/* 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 | ||||||
|  | 		{ | ||||||
|  | 			uint8_t  InterfaceNumber; /**< Interface number of the Mass Storage interface within the device */ | ||||||
|  | 
 | ||||||
|  | 			uint8_t  DataINEndpointNumber; /**< Endpoint number of the Mass Storage interface's IN data endpoint */ | ||||||
|  | 			uint16_t DataINEndpointSize; /**< Size in bytes of the Mass Storage interface's IN data endpoint */ | ||||||
|  | 
 | ||||||
|  | 			uint8_t  DataOUTEndpointNumber; /**< Endpoint number of the Mass Storage interface's OUT data endpoint */ | ||||||
|  | 			uint16_t DataOUTEndpointSize;  /**< Size in bytes of the Mass Storage interface's OUT data endpoint */ | ||||||
|  | 
 | ||||||
|  | 			uint8_t  TotalLUNs; | ||||||
|  | 
 | ||||||
|  | 			CommandBlockWrapper_t  CommandBlock; | ||||||
|  | 			CommandStatusWrapper_t CommandStatus; | ||||||
|  | 
 | ||||||
|  | 			bool IsMassStoreReset; | ||||||
|  | 		} USB_ClassInfo_MS_t; | ||||||
|  | 		 | ||||||
|  | 	/* Function Prototypes: */ | ||||||
|  | 		#if defined(INCLUDE_FROM_MS_CLASS_C) | ||||||
|  | 			static void    USB_MS_ReturnCommandStatus(USB_ClassInfo_MS_t* MSInterfaceInfo); | ||||||
|  | 			static bool    USB_MS_ReadInCommandBlock(USB_ClassInfo_MS_t* MSInterfaceInfo); | ||||||
|  | 			static uint8_t StreamCallback_AbortOnMassStoreReset(void); | ||||||
|  | 		#endif | ||||||
|  | 	 | ||||||
|  | 		void USB_MS_USBTask(USB_ClassInfo_MS_t* MSInterfaceInfo); | ||||||
|  | 		bool USB_MS_ConfigureEndpoints(USB_ClassInfo_MS_t* MSInterfaceInfo); | ||||||
|  | 		void USB_MS_ProcessControlPacket(USB_ClassInfo_MS_t* MSInterfaceInfo); | ||||||
|  | 		 | ||||||
|  | 		bool CALLBACK_USB_MS_SCSICommandReceived(USB_ClassInfo_MS_t* MSInterfaceInfo); | ||||||
|  | 		 | ||||||
|  | #endif | ||||||
							
								
								
									
										456
									
								
								LUFA/Drivers/USB/Class/Device/RNDIS.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										456
									
								
								LUFA/Drivers/USB/Class/Device/RNDIS.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,456 @@ | |||||||
|  | /*
 | ||||||
|  |              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. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #define  INCLUDE_FROM_RNDIS_CLASS_C | ||||||
|  | #include "RNDIS.h" | ||||||
|  | 
 | ||||||
|  | static const uint32_t PROGMEM AdapterSupportedOIDList[]  = | ||||||
|  | 	{ | ||||||
|  | 		OID_GEN_SUPPORTED_LIST, | ||||||
|  | 		OID_GEN_PHYSICAL_MEDIUM, | ||||||
|  | 		OID_GEN_HARDWARE_STATUS, | ||||||
|  | 		OID_GEN_MEDIA_SUPPORTED, | ||||||
|  | 		OID_GEN_MEDIA_IN_USE, | ||||||
|  | 		OID_GEN_MAXIMUM_FRAME_SIZE, | ||||||
|  | 		OID_GEN_MAXIMUM_TOTAL_SIZE, | ||||||
|  | 		OID_GEN_LINK_SPEED, | ||||||
|  | 		OID_GEN_TRANSMIT_BLOCK_SIZE, | ||||||
|  | 		OID_GEN_RECEIVE_BLOCK_SIZE, | ||||||
|  | 		OID_GEN_VENDOR_ID, | ||||||
|  | 		OID_GEN_VENDOR_DESCRIPTION, | ||||||
|  | 		OID_GEN_CURRENT_PACKET_FILTER, | ||||||
|  | 		OID_GEN_MAXIMUM_TOTAL_SIZE, | ||||||
|  | 		OID_GEN_MEDIA_CONNECT_STATUS, | ||||||
|  | 		OID_GEN_XMIT_OK, | ||||||
|  | 		OID_GEN_RCV_OK, | ||||||
|  | 		OID_GEN_XMIT_ERROR, | ||||||
|  | 		OID_GEN_RCV_ERROR, | ||||||
|  | 		OID_GEN_RCV_NO_BUFFER, | ||||||
|  | 		OID_802_3_PERMANENT_ADDRESS, | ||||||
|  | 		OID_802_3_CURRENT_ADDRESS, | ||||||
|  | 		OID_802_3_MULTICAST_LIST, | ||||||
|  | 		OID_802_3_MAXIMUM_LIST_SIZE, | ||||||
|  | 		OID_802_3_RCV_ERROR_ALIGNMENT, | ||||||
|  | 		OID_802_3_XMIT_ONE_COLLISION, | ||||||
|  | 		OID_802_3_XMIT_MORE_COLLISIONS, | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | void USB_RNDIS_ProcessControlPacket(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (!(Endpoint_IsSETUPReceived())) | ||||||
|  | 	  return; | ||||||
|  | 	   | ||||||
|  | 	if (USB_ControlRequest.wIndex != RNDISInterfaceInfo->ControlInterfaceNumber) | ||||||
|  | 	  return; | ||||||
|  | 
 | ||||||
|  | 	switch (USB_ControlRequest.bRequest) | ||||||
|  | 	{ | ||||||
|  | 		case REQ_SendEncapsulatedCommand: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 
 | ||||||
|  | 				Endpoint_Read_Control_Stream_LE(RNDISInterfaceInfo->RNDISMessageBuffer, USB_ControlRequest.wLength); | ||||||
|  | 				Endpoint_ClearIN(); | ||||||
|  | 
 | ||||||
|  | 				USB_RNDIS_ProcessRNDISControlMessage(RNDISInterfaceInfo); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			break; | ||||||
|  | 		case REQ_GetEncapsulatedResponse: | ||||||
|  | 			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_ClearSETUP(); | ||||||
|  | 
 | ||||||
|  | 				RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; | ||||||
|  | 
 | ||||||
|  | 				if (!(MessageHeader->MessageLength)) | ||||||
|  | 				{ | ||||||
|  | 					RNDISInterfaceInfo->RNDISMessageBuffer[0] = 0; | ||||||
|  | 					MessageHeader->MessageLength = 1; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				Endpoint_Write_Control_Stream_LE(RNDISInterfaceInfo->RNDISMessageBuffer, MessageHeader->MessageLength);				 | ||||||
|  | 				Endpoint_ClearOUT(); | ||||||
|  | 
 | ||||||
|  | 				MessageHeader->MessageLength = 0; | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool USB_RNDIS_ConfigureEndpoints(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK, | ||||||
|  | 							         ENDPOINT_DIR_IN, RNDISInterfaceInfo->DataINEndpointSize, | ||||||
|  | 							         ENDPOINT_BANK_SINGLE))) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK, | ||||||
|  | 	                                 ENDPOINT_DIR_OUT, RNDISInterfaceInfo->DataOUTEndpointSize, | ||||||
|  | 	                                 ENDPOINT_BANK_SINGLE))) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->NotificationEndpointNumber, EP_TYPE_INTERRUPT, | ||||||
|  | 	                                 ENDPOINT_DIR_IN, RNDISInterfaceInfo->NotificationEndpointSize, | ||||||
|  | 	                                 ENDPOINT_BANK_SINGLE))) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void USB_RNDIS_USBTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	if (!(USB_IsConnected)) | ||||||
|  | 	  return; | ||||||
|  | 
 | ||||||
|  | 	RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; | ||||||
|  | 
 | ||||||
|  | 	Endpoint_SelectEndpoint(RNDISInterfaceInfo->NotificationEndpointNumber); | ||||||
|  | 
 | ||||||
|  | 	if (Endpoint_IsINReady() && RNDISInterfaceInfo->ResponseReady) | ||||||
|  | 	{ | ||||||
|  | 		USB_Request_Header_t Notification = (USB_Request_Header_t) | ||||||
|  | 			{ | ||||||
|  | 				.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), | ||||||
|  | 				.bRequest      = NOTIF_ResponseAvailable, | ||||||
|  | 				.wValue        = 0, | ||||||
|  | 				.wIndex        = 0, | ||||||
|  | 				.wLength       = 0, | ||||||
|  | 			}; | ||||||
|  | 		 | ||||||
|  | 		Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK); | ||||||
|  | 
 | ||||||
|  | 		Endpoint_ClearIN(); | ||||||
|  | 
 | ||||||
|  | 		RNDISInterfaceInfo->ResponseReady = false; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if ((RNDISInterfaceInfo->CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength)) | ||||||
|  | 	{ | ||||||
|  | 		RNDIS_PACKET_MSG_t RNDISPacketHeader; | ||||||
|  | 
 | ||||||
|  | 		Endpoint_SelectEndpoint(RNDISInterfaceInfo->DataOUTEndpointNumber); | ||||||
|  | 
 | ||||||
|  | 		if (Endpoint_IsOUTReceived() && !(RNDISInterfaceInfo->FrameIN.FrameInBuffer)) | ||||||
|  | 		{ | ||||||
|  | 			Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t), NO_STREAM_CALLBACK); | ||||||
|  | 
 | ||||||
|  | 			if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX) | ||||||
|  | 			{ | ||||||
|  | 				Endpoint_StallTransaction(); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			Endpoint_Read_Stream_LE(RNDISInterfaceInfo->FrameIN.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK); | ||||||
|  | 
 | ||||||
|  | 			Endpoint_ClearOUT(); | ||||||
|  | 			 | ||||||
|  | 			RNDISInterfaceInfo->FrameIN.FrameLength = RNDISPacketHeader.DataLength; | ||||||
|  | 
 | ||||||
|  | 			RNDISInterfaceInfo->FrameIN.FrameInBuffer = true; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		Endpoint_SelectEndpoint(RNDISInterfaceInfo->DataINEndpointNumber); | ||||||
|  | 		 | ||||||
|  | 		if (Endpoint_IsINReady() && RNDISInterfaceInfo->FrameOUT.FrameInBuffer) | ||||||
|  | 		{ | ||||||
|  | 			memset(&RNDISPacketHeader, 0, sizeof(RNDIS_PACKET_MSG_t)); | ||||||
|  | 
 | ||||||
|  | 			RNDISPacketHeader.MessageType   = REMOTE_NDIS_PACKET_MSG; | ||||||
|  | 			RNDISPacketHeader.MessageLength = (sizeof(RNDIS_PACKET_MSG_t) + RNDISInterfaceInfo->FrameOUT.FrameLength); | ||||||
|  | 			RNDISPacketHeader.DataOffset    = (sizeof(RNDIS_PACKET_MSG_t) - sizeof(RNDIS_Message_Header_t)); | ||||||
|  | 			RNDISPacketHeader.DataLength    = RNDISInterfaceInfo->FrameOUT.FrameLength; | ||||||
|  | 
 | ||||||
|  | 			Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t), NO_STREAM_CALLBACK); | ||||||
|  | 			Endpoint_Write_Stream_LE(RNDISInterfaceInfo->FrameOUT.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK); | ||||||
|  | 			Endpoint_ClearIN(); | ||||||
|  | 			 | ||||||
|  | 			RNDISInterfaceInfo->FrameOUT.FrameInBuffer = false; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }							 | ||||||
|  | 
 | ||||||
|  | void USB_RNDIS_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo) | ||||||
|  | { | ||||||
|  | 	/* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of
 | ||||||
|  | 	         this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */ | ||||||
|  | 
 | ||||||
|  | 	RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; | ||||||
|  | 
 | ||||||
|  | 	switch (MessageHeader->MessageType) | ||||||
|  | 	{ | ||||||
|  | 		case REMOTE_NDIS_INITIALIZE_MSG: | ||||||
|  | 			RNDISInterfaceInfo->ResponseReady = true; | ||||||
|  | 			 | ||||||
|  | 			RNDIS_INITIALIZE_MSG_t*   INITIALIZE_Message  = (RNDIS_INITIALIZE_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; | ||||||
|  | 			RNDIS_INITIALIZE_CMPLT_t* INITIALIZE_Response = (RNDIS_INITIALIZE_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; | ||||||
|  | 			 | ||||||
|  | 			INITIALIZE_Response->MessageType           = REMOTE_NDIS_INITIALIZE_CMPLT; | ||||||
|  | 			INITIALIZE_Response->MessageLength         = sizeof(RNDIS_INITIALIZE_CMPLT_t); | ||||||
|  | 			INITIALIZE_Response->RequestId             = INITIALIZE_Message->RequestId; | ||||||
|  | 			INITIALIZE_Response->Status                = REMOTE_NDIS_STATUS_SUCCESS; | ||||||
|  | 			 | ||||||
|  | 			INITIALIZE_Response->MajorVersion          = REMOTE_NDIS_VERSION_MAJOR; | ||||||
|  | 			INITIALIZE_Response->MinorVersion          = REMOTE_NDIS_VERSION_MINOR;			 | ||||||
|  | 			INITIALIZE_Response->DeviceFlags           = REMOTE_NDIS_DF_CONNECTIONLESS; | ||||||
|  | 			INITIALIZE_Response->Medium                = REMOTE_NDIS_MEDIUM_802_3; | ||||||
|  | 			INITIALIZE_Response->MaxPacketsPerTransfer = 1; | ||||||
|  | 			INITIALIZE_Response->MaxTransferSize       = (sizeof(RNDIS_PACKET_MSG_t) + ETHERNET_FRAME_SIZE_MAX); | ||||||
|  | 			INITIALIZE_Response->PacketAlignmentFactor = 0; | ||||||
|  | 			INITIALIZE_Response->AFListOffset          = 0; | ||||||
|  | 			INITIALIZE_Response->AFListSize            = 0; | ||||||
|  | 			 | ||||||
|  | 			RNDISInterfaceInfo->CurrRNDISState = RNDIS_Initialized; | ||||||
|  | 		 | ||||||
|  | 			break; | ||||||
|  | 		case REMOTE_NDIS_HALT_MSG: | ||||||
|  | 			RNDISInterfaceInfo->ResponseReady = false; | ||||||
|  | 			MessageHeader->MessageLength = 0; | ||||||
|  | 
 | ||||||
|  | 			RNDISInterfaceInfo->CurrRNDISState = RNDIS_Uninitialized; | ||||||
|  | 
 | ||||||
|  | 			break; | ||||||
|  | 		case REMOTE_NDIS_QUERY_MSG: | ||||||
|  | 			RNDISInterfaceInfo->ResponseReady = true; | ||||||
|  | 						 | ||||||
|  | 			RNDIS_QUERY_MSG_t*   QUERY_Message  = (RNDIS_QUERY_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; | ||||||
|  | 			RNDIS_QUERY_CMPLT_t* QUERY_Response = (RNDIS_QUERY_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; | ||||||
|  | 			uint32_t             Query_Oid      = QUERY_Message->Oid; | ||||||
|  | 						 | ||||||
|  | 			void*     QueryData                 = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) + | ||||||
|  | 			                                                                              QUERY_Message->InformationBufferOffset]; | ||||||
|  | 			void*     ResponseData              = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_QUERY_CMPLT_t)];		 | ||||||
|  | 			uint16_t  ResponseSize; | ||||||
|  | 
 | ||||||
|  | 			QUERY_Response->MessageType         = REMOTE_NDIS_QUERY_CMPLT; | ||||||
|  | 			QUERY_Response->MessageLength       = sizeof(RNDIS_QUERY_CMPLT_t); | ||||||
|  | 						 | ||||||
|  | 			if (USB_RNDIS_ProcessNDISQuery(RNDISInterfaceInfo, Query_Oid, QueryData, QUERY_Message->InformationBufferLength, | ||||||
|  | 			                               ResponseData, &ResponseSize)) | ||||||
|  | 			{ | ||||||
|  | 				QUERY_Response->Status                  = REMOTE_NDIS_STATUS_SUCCESS; | ||||||
|  | 				QUERY_Response->MessageLength          += ResponseSize; | ||||||
|  | 							 | ||||||
|  | 				QUERY_Response->InformationBufferLength = ResponseSize; | ||||||
|  | 				QUERY_Response->InformationBufferOffset = (sizeof(RNDIS_QUERY_CMPLT_t) - sizeof(RNDIS_Message_Header_t)); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{				 | ||||||
|  | 				QUERY_Response->Status                  = REMOTE_NDIS_STATUS_NOT_SUPPORTED; | ||||||
|  | 
 | ||||||
|  | 				QUERY_Response->InformationBufferLength = 0; | ||||||
|  | 				QUERY_Response->InformationBufferOffset = 0; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			break; | ||||||
|  | 		case REMOTE_NDIS_SET_MSG: | ||||||
|  | 			RNDISInterfaceInfo->ResponseReady = true; | ||||||
|  | 			 | ||||||
|  | 			RNDIS_SET_MSG_t*   SET_Message  = (RNDIS_SET_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; | ||||||
|  | 			RNDIS_SET_CMPLT_t* SET_Response = (RNDIS_SET_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; | ||||||
|  | 			uint32_t           SET_Oid      = SET_Message->Oid; | ||||||
|  | 
 | ||||||
|  | 			SET_Response->MessageType       = REMOTE_NDIS_SET_CMPLT; | ||||||
|  | 			SET_Response->MessageLength     = sizeof(RNDIS_SET_CMPLT_t); | ||||||
|  | 			SET_Response->RequestId         = SET_Message->RequestId; | ||||||
|  | 
 | ||||||
|  | 			void* SetData                   = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) + | ||||||
|  | 			                                                                          SET_Message->InformationBufferOffset]; | ||||||
|  | 						 | ||||||
|  | 			if (USB_RNDIS_ProcessNDISSet(RNDISInterfaceInfo, SET_Oid, SetData, SET_Message->InformationBufferLength)) | ||||||
|  | 			  SET_Response->Status        = REMOTE_NDIS_STATUS_SUCCESS; | ||||||
|  | 			else | ||||||
|  | 			  SET_Response->Status        = REMOTE_NDIS_STATUS_NOT_SUPPORTED; | ||||||
|  | 
 | ||||||
|  | 			break; | ||||||
|  | 		case REMOTE_NDIS_RESET_MSG: | ||||||
|  | 			RNDISInterfaceInfo->ResponseReady = true; | ||||||
|  | 			 | ||||||
|  | 			RNDIS_RESET_CMPLT_t* RESET_Response = (RNDIS_RESET_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; | ||||||
|  | 
 | ||||||
|  | 			RESET_Response->MessageType         = REMOTE_NDIS_RESET_CMPLT; | ||||||
|  | 			RESET_Response->MessageLength       = sizeof(RNDIS_RESET_CMPLT_t); | ||||||
|  | 			RESET_Response->Status              = REMOTE_NDIS_STATUS_SUCCESS; | ||||||
|  | 			RESET_Response->AddressingReset     = 0; | ||||||
|  | 
 | ||||||
|  | 			break; | ||||||
|  | 		case REMOTE_NDIS_KEEPALIVE_MSG: | ||||||
|  | 			RNDISInterfaceInfo->ResponseReady = true; | ||||||
|  | 			 | ||||||
|  | 			RNDIS_KEEPALIVE_MSG_t*   KEEPALIVE_Message  = (RNDIS_KEEPALIVE_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; | ||||||
|  | 			RNDIS_KEEPALIVE_CMPLT_t* KEEPALIVE_Response = (RNDIS_KEEPALIVE_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; | ||||||
|  | 
 | ||||||
|  | 			KEEPALIVE_Response->MessageType     = REMOTE_NDIS_KEEPALIVE_CMPLT; | ||||||
|  | 			KEEPALIVE_Response->MessageLength   = sizeof(RNDIS_KEEPALIVE_CMPLT_t); | ||||||
|  | 			KEEPALIVE_Response->RequestId       = KEEPALIVE_Message->RequestId; | ||||||
|  | 			KEEPALIVE_Response->Status          = REMOTE_NDIS_STATUS_SUCCESS; | ||||||
|  | 			 | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool USB_RNDIS_ProcessNDISQuery(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, | ||||||
|  |                                        uint32_t OId, void* QueryData, uint16_t QuerySize, | ||||||
|  |                                        void* ResponseData, uint16_t* ResponseSize) | ||||||
|  | { | ||||||
|  | 	switch (OId) | ||||||
|  | 	{ | ||||||
|  | 		case OID_GEN_SUPPORTED_LIST: | ||||||
|  | 			*ResponseSize = sizeof(AdapterSupportedOIDList); | ||||||
|  | 			 | ||||||
|  | 			memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList)); | ||||||
|  | 			 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_GEN_PHYSICAL_MEDIUM: | ||||||
|  | 			*ResponseSize = sizeof(uint32_t); | ||||||
|  | 			 | ||||||
|  | 			/* Indicate that the device is a true ethernet link */ | ||||||
|  | 			*((uint32_t*)ResponseData) = 0; | ||||||
|  | 			 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_GEN_HARDWARE_STATUS: | ||||||
|  | 			*ResponseSize = sizeof(uint32_t); | ||||||
|  | 			 | ||||||
|  | 			*((uint32_t*)ResponseData) = NdisHardwareStatusReady; | ||||||
|  | 			 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_GEN_MEDIA_SUPPORTED: | ||||||
|  | 		case OID_GEN_MEDIA_IN_USE: | ||||||
|  | 			*ResponseSize = sizeof(uint32_t); | ||||||
|  | 			 | ||||||
|  | 			*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIUM_802_3; | ||||||
|  | 			 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_GEN_VENDOR_ID: | ||||||
|  | 			*ResponseSize = sizeof(uint32_t); | ||||||
|  | 			 | ||||||
|  | 			/* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */ | ||||||
|  | 			*((uint32_t*)ResponseData) = 0x00FFFFFF; | ||||||
|  | 			 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_GEN_MAXIMUM_FRAME_SIZE: | ||||||
|  | 		case OID_GEN_TRANSMIT_BLOCK_SIZE: | ||||||
|  | 		case OID_GEN_RECEIVE_BLOCK_SIZE: | ||||||
|  | 			*ResponseSize = sizeof(uint32_t); | ||||||
|  | 			 | ||||||
|  | 			*((uint32_t*)ResponseData) = ETHERNET_FRAME_SIZE_MAX; | ||||||
|  | 			 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_GEN_VENDOR_DESCRIPTION: | ||||||
|  | 			*ResponseSize = (strlen(RNDISInterfaceInfo->AdapterVendorDescription) + 1); | ||||||
|  | 			 | ||||||
|  | 			memcpy(ResponseData, RNDISInterfaceInfo->AdapterVendorDescription, *ResponseSize); | ||||||
|  | 			 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_GEN_MEDIA_CONNECT_STATUS: | ||||||
|  | 			*ResponseSize = sizeof(uint32_t); | ||||||
|  | 			 | ||||||
|  | 			*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIA_STATE_CONNECTED; | ||||||
|  | 			 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_GEN_LINK_SPEED: | ||||||
|  | 			*ResponseSize = sizeof(uint32_t); | ||||||
|  | 			 | ||||||
|  | 			/* Indicate 10Mb/s link speed */ | ||||||
|  | 			*((uint32_t*)ResponseData) = 100000; | ||||||
|  | 
 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_802_3_PERMANENT_ADDRESS: | ||||||
|  | 		case OID_802_3_CURRENT_ADDRESS: | ||||||
|  | 			*ResponseSize = sizeof(MAC_Address_t); | ||||||
|  | 			 | ||||||
|  | 			memcpy(ResponseData, &RNDISInterfaceInfo->AdapterMACAddress, sizeof(MAC_Address_t)); | ||||||
|  | 
 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_802_3_MAXIMUM_LIST_SIZE: | ||||||
|  | 			*ResponseSize = sizeof(uint32_t); | ||||||
|  | 			 | ||||||
|  | 			/* Indicate only one multicast address supported */ | ||||||
|  | 			*((uint32_t*)ResponseData) = 1; | ||||||
|  | 		 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_GEN_CURRENT_PACKET_FILTER: | ||||||
|  | 			*ResponseSize = sizeof(uint32_t); | ||||||
|  | 			 | ||||||
|  | 			*((uint32_t*)ResponseData) = RNDISInterfaceInfo->CurrPacketFilter; | ||||||
|  | 		 | ||||||
|  | 			return true;			 | ||||||
|  | 		case OID_GEN_XMIT_OK: | ||||||
|  | 		case OID_GEN_RCV_OK: | ||||||
|  | 		case OID_GEN_XMIT_ERROR: | ||||||
|  | 		case OID_GEN_RCV_ERROR: | ||||||
|  | 		case OID_GEN_RCV_NO_BUFFER: | ||||||
|  | 		case OID_802_3_RCV_ERROR_ALIGNMENT: | ||||||
|  | 		case OID_802_3_XMIT_ONE_COLLISION: | ||||||
|  | 		case OID_802_3_XMIT_MORE_COLLISIONS: | ||||||
|  | 			*ResponseSize = sizeof(uint32_t); | ||||||
|  | 			 | ||||||
|  | 			/* Unused statistic OIDs - always return 0 for each */ | ||||||
|  | 			*((uint32_t*)ResponseData) = 0; | ||||||
|  | 		 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_GEN_MAXIMUM_TOTAL_SIZE: | ||||||
|  | 			*ResponseSize = sizeof(uint32_t); | ||||||
|  | 			 | ||||||
|  | 			/* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */ | ||||||
|  | 			*((uint32_t*)ResponseData) = (RNDIS_MESSAGE_BUFFER_SIZE + ETHERNET_FRAME_SIZE_MAX); | ||||||
|  | 		 | ||||||
|  | 			return true; | ||||||
|  | 		default: | ||||||
|  | 			return false; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool USB_RNDIS_ProcessNDISSet(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, uint32_t OId, void* SetData, uint16_t SetSize) | ||||||
|  | { | ||||||
|  | 	switch (OId) | ||||||
|  | 	{ | ||||||
|  | 		case OID_GEN_CURRENT_PACKET_FILTER: | ||||||
|  | 			RNDISInterfaceInfo->CurrPacketFilter = *((uint32_t*)SetData); | ||||||
|  | 			RNDISInterfaceInfo->CurrRNDISState = ((RNDISInterfaceInfo->CurrPacketFilter) ? | ||||||
|  | 			                                      RNDIS_Data_Initialized : RNDIS_Data_Initialized); | ||||||
|  | 			 | ||||||
|  | 			return true; | ||||||
|  | 		case OID_802_3_MULTICAST_LIST: | ||||||
|  | 			/* Do nothing - throw away the value from the host as it is unused */ | ||||||
|  | 		 | ||||||
|  | 			return true; | ||||||
|  | 		default: | ||||||
|  | 			return false; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -28,26 +28,16 @@ | |||||||
|   this software. |   this software. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| /** \file
 | #ifndef _RNDIS_CLASS_H_ | ||||||
|  * | #define _RNDIS_CLASS_H_ | ||||||
|  *  Header file for RNDIS.c. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #ifndef _RNDIS_H_ |  | ||||||
| #define _RNDIS_H_ |  | ||||||
| 
 | 
 | ||||||
| 	/* Includes: */ | 	/* Includes: */ | ||||||
| 		#include <avr/io.h> | 		#include <string.h> | ||||||
| 		#include <stdbool.h> |  | ||||||
| 	 | 	 | ||||||
| 		#include "RNDISEthernet.h" | 		#include "../../USB.h" | ||||||
| 		#include "RNDISConstants.h" | 		#include "RNDISConstants.h" | ||||||
| 		#include "Ethernet.h" |  | ||||||
| 		 | 		 | ||||||
| 	/* Macros: */ | 	/* Macros: */ | ||||||
| 		/** Physical MAC Address of the USB network adapter */ |  | ||||||
| 		#define ADAPTER_MAC_ADDRESS                   {0x02, 0x00, 0x02, 0x00, 0x02, 0x00} |  | ||||||
| 	 |  | ||||||
| 		/** Implemented RNDIS Version Major */ | 		/** Implemented RNDIS Version Major */ | ||||||
| 		#define REMOTE_NDIS_VERSION_MAJOR             0x01 | 		#define REMOTE_NDIS_VERSION_MAJOR             0x01 | ||||||
| 
 | 
 | ||||||
| @ -60,6 +50,12 @@ | |||||||
| 		/** RNDIS request to issue a device-to-host NDIS response */ | 		/** RNDIS request to issue a device-to-host NDIS response */ | ||||||
| 		#define REQ_GetEncapsulatedResponse           0x01 | 		#define REQ_GetEncapsulatedResponse           0x01 | ||||||
| 		 | 		 | ||||||
|  | 		#define RNDIS_MESSAGE_BUFFER_SIZE             128 | ||||||
|  | 
 | ||||||
|  | 		#define ETHERNET_FRAME_SIZE_MAX               1500 | ||||||
|  | 		 | ||||||
|  | 		#define NOTIF_ResponseAvailable               1 | ||||||
|  | 		 | ||||||
| 	/* Enums: */ | 	/* Enums: */ | ||||||
| 		/** Enum for the possible NDIS adapter states. */ | 		/** Enum for the possible NDIS adapter states. */ | ||||||
| 		enum RNDIS_States_t | 		enum RNDIS_States_t | ||||||
| @ -80,6 +76,12 @@ | |||||||
| 		}; | 		}; | ||||||
| 		 | 		 | ||||||
| 	/* Type Defines: */ | 	/* Type Defines: */ | ||||||
|  | 		/** Type define for a physical MAC address of a device on a network */ | ||||||
|  | 		typedef struct | ||||||
|  | 		{ | ||||||
|  | 			uint8_t       Octets[6]; /**< Individual bytes of a MAC address */ | ||||||
|  | 		} MAC_Address_t; | ||||||
|  | 
 | ||||||
| 		/** Type define for a RNDIS message header, sent before RNDIS messages */ | 		/** Type define for a RNDIS message header, sent before RNDIS messages */ | ||||||
| 		typedef struct | 		typedef struct | ||||||
| 		{ | 		{ | ||||||
| @ -87,6 +89,14 @@ | |||||||
| 			uint32_t MessageLength; /**< Total length of the RNDIS message, in bytes */ | 			uint32_t MessageLength; /**< Total length of the RNDIS message, in bytes */ | ||||||
| 		} RNDIS_Message_Header_t; | 		} RNDIS_Message_Header_t; | ||||||
| 
 | 
 | ||||||
|  | 		/** Type define for an Ethernet frame buffer. */ | ||||||
|  | 		typedef struct | ||||||
|  | 		{ | ||||||
|  | 			uint8_t       FrameData[ETHERNET_FRAME_SIZE_MAX]; /**< Ethernet frame contents */ | ||||||
|  | 			uint16_t      FrameLength; /**< Length in bytes of the Ethernet frame stored in the buffer */ | ||||||
|  | 			bool          FrameInBuffer; /**< Indicates if a frame is currently stored in the buffer */ | ||||||
|  | 		} Ethernet_Frame_Info_t; | ||||||
|  | 
 | ||||||
| 		/** Type define for a RNDIS packet message, used to encapsulate Ethernet packets sent to and from the adapter */ | 		/** Type define for a RNDIS packet message, used to encapsulate Ethernet packets sent to and from the adapter */ | ||||||
| 		typedef struct | 		typedef struct | ||||||
| 		{ | 		{ | ||||||
| @ -103,6 +113,30 @@ | |||||||
| 			uint32_t Reserved; | 			uint32_t Reserved; | ||||||
| 		} RNDIS_PACKET_MSG_t; | 		} RNDIS_PACKET_MSG_t; | ||||||
| 
 | 
 | ||||||
|  | 		typedef struct | ||||||
|  | 		{ | ||||||
|  | 			uint8_t  ControlInterfaceNumber; /**< Interface number of the CDC control interface within the device */ | ||||||
|  | 
 | ||||||
|  | 			uint8_t  DataINEndpointNumber; /**< Endpoint number of the CDC interface's IN data endpoint */ | ||||||
|  | 			uint16_t DataINEndpointSize; /**< Size in bytes of the CDC interface's IN data endpoint */ | ||||||
|  | 
 | ||||||
|  | 			uint8_t  DataOUTEndpointNumber; /**< Endpoint number of the CDC interface's OUT data endpoint */ | ||||||
|  | 			uint16_t DataOUTEndpointSize;  /**< Size in bytes of the CDC interface's OUT data endpoint */ | ||||||
|  | 
 | ||||||
|  | 			uint8_t  NotificationEndpointNumber; /**< Endpoint number of the CDC interface's IN notification endpoint, if used */ | ||||||
|  | 			uint16_t NotificationEndpointSize;  /**< Size in bytes of the CDC interface's IN notification endpoint, if used */ | ||||||
|  | 			 | ||||||
|  | 			char*         AdapterVendorDescription; | ||||||
|  | 			MAC_Address_t AdapterMACAddress; | ||||||
|  | 
 | ||||||
|  | 			uint8_t  RNDISMessageBuffer[RNDIS_MESSAGE_BUFFER_SIZE]; | ||||||
|  | 			bool     ResponseReady; | ||||||
|  | 			uint8_t  CurrRNDISState; | ||||||
|  | 			uint32_t CurrPacketFilter; | ||||||
|  | 			Ethernet_Frame_Info_t FrameIN; | ||||||
|  | 			Ethernet_Frame_Info_t FrameOUT; | ||||||
|  | 		} USB_ClassInfo_RNDIS_t; | ||||||
|  | 		 | ||||||
| 		/** Type define for a RNDIS Initialize command message */ | 		/** Type define for a RNDIS Initialize command message */ | ||||||
| 		typedef struct | 		typedef struct | ||||||
| 		{ | 		{ | ||||||
| @ -208,19 +242,19 @@ | |||||||
| 			uint32_t InformationBufferOffset; | 			uint32_t InformationBufferOffset; | ||||||
| 		} RNDIS_QUERY_CMPLT_t; | 		} RNDIS_QUERY_CMPLT_t; | ||||||
| 		 | 		 | ||||||
| 	/* External Variables: */ |  | ||||||
| 		extern uint8_t                 RNDISMessageBuffer[]; |  | ||||||
| 		extern RNDIS_Message_Header_t* MessageHeader; |  | ||||||
| 		extern bool                    ResponseReady; |  | ||||||
| 		extern uint8_t                 CurrRNDISState; |  | ||||||
| 
 |  | ||||||
| 	/* Function Prototypes: */ | 	/* Function Prototypes: */ | ||||||
| 		void ProcessRNDISControlMessage(void); | 		#if defined(INCLUDE_FROM_RNDIS_CLASS_C) | ||||||
| 
 | 			static void USB_RNDIS_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); | ||||||
| 		#if defined(INCLUDE_FROM_RNDIS_C) | 			static bool USB_RNDIS_ProcessNDISQuery(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo,  | ||||||
| 			static bool ProcessNDISQuery(uint32_t OId, void* QueryData, uint16_t QuerySize, | 			                                       uint32_t OId, void* QueryData, uint16_t QuerySize, | ||||||
| 										 void* ResponseData, uint16_t* ResponseSize); | 										           void* ResponseData, uint16_t* ResponseSize); | ||||||
| 			static bool ProcessNDISSet(uint32_t OId, void* SetData, uint16_t SetSize);	 | 			static bool USB_RNDIS_ProcessNDISSet(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, uint32_t OId, | ||||||
|  | 			                                     void* SetData, uint16_t SetSize);	 | ||||||
| 		#endif | 		#endif | ||||||
| 
 | 
 | ||||||
|  | 		void     USB_RNDIS_USBTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); | ||||||
|  | 		bool     USB_RNDIS_ConfigureEndpoints(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); | ||||||
|  | 		void     USB_RNDIS_ProcessControlPacket(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); | ||||||
|  | 		void     USB_RNDIS_USBTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); | ||||||
|  | 		 | ||||||
| #endif | #endif | ||||||
| @ -63,7 +63,7 @@ | |||||||
| 
 | 
 | ||||||
| 		#include "HIDReportData.h" | 		#include "HIDReportData.h" | ||||||
| 
 | 
 | ||||||
| 		#include "../../../Common/Common.h" | 		#include "../../../../Common/Common.h" | ||||||
| 
 | 
 | ||||||
| 	/* Enable C linkage for C++ Compilers: */ | 	/* Enable C linkage for C++ Compilers: */ | ||||||
| 		#if defined(__cplusplus) | 		#if defined(__cplusplus) | ||||||
| @ -267,6 +267,11 @@ | |||||||
| 			 *        \ref Group_USBManagement documentation). | 			 *        \ref Group_USBManagement documentation). | ||||||
| 			 */ | 			 */ | ||||||
| 			void EVENT_USB_Reset(void); | 			void EVENT_USB_Reset(void); | ||||||
|  | 			 | ||||||
|  | 			/** Event for the USB start of frame interrupt, firing once each millisecond in either device or host
 | ||||||
|  | 			 *  mode, while USB frames are being generated or recieved. | ||||||
|  | 			 */ | ||||||
|  | 			void EVENT_USB_StartOfFrame(void); | ||||||
| 		#endif | 		#endif | ||||||
| 		 | 		 | ||||||
| 	/* Private Interface - For use in library only: */ | 	/* Private Interface - For use in library only: */ | ||||||
| @ -303,6 +308,7 @@ | |||||||
| 				void EVENT_USB_Suspend(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); | 				void EVENT_USB_Suspend(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); | ||||||
| 				void EVENT_USB_WakeUp(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); | 				void EVENT_USB_WakeUp(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); | ||||||
| 				void EVENT_USB_Reset(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); | 				void EVENT_USB_Reset(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); | ||||||
|  | 				void EVENT_USB_StartOfFrame(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); | ||||||
| 			#endif | 			#endif | ||||||
| 	#endif | 	#endif | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -180,6 +180,15 @@ ISR(USB_GEN_vect, ISR_BLOCK) | |||||||
| 
 | 
 | ||||||
| 		EVENT_USB_Reset(); | 		EVENT_USB_Reset(); | ||||||
| 	} | 	} | ||||||
|  | 	 | ||||||
|  | 	if (USB_INT_HasOccurred(USB_INT_SOFI) && USB_INT_IsEnabled(USB_INT_SOFI)) | ||||||
|  | 	{ | ||||||
|  | 		USB_INT_Clear(USB_INT_SOFI); | ||||||
|  | 
 | ||||||
|  | 		FrameElapsed = true; | ||||||
|  | 		 | ||||||
|  | 		EVENT_USB_StartOfFrame(); | ||||||
|  | 	} | ||||||
| 	#endif | 	#endif | ||||||
| 	 | 	 | ||||||
| 	#if defined(USB_CAN_BE_HOST) | 	#if defined(USB_CAN_BE_HOST) | ||||||
| @ -232,6 +241,15 @@ ISR(USB_GEN_vect, ISR_BLOCK) | |||||||
| 
 | 
 | ||||||
| 		USB_ResetInterface(); | 		USB_ResetInterface(); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	if (USB_INT_HasOccurred(USB_INT_HSOFI) && USB_INT_IsEnabled(USB_INT_HSOFI)) | ||||||
|  | 	{ | ||||||
|  | 		USB_INT_Clear(USB_INT_HSOFI); | ||||||
|  | 
 | ||||||
|  | 		FrameElapsed = true; | ||||||
|  | 		 | ||||||
|  | 		EVENT_USB_StartOfFrame(); | ||||||
|  | 	} | ||||||
| 	#endif | 	#endif | ||||||
| 
 | 
 | ||||||
| 	#if defined(USB_CAN_BE_BOTH) | 	#if defined(USB_CAN_BE_BOTH) | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ USB_Request_Header_t USB_ControlRequest; | |||||||
| volatile uint8_t   USB_HostState; | volatile uint8_t   USB_HostState; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| TASK(USB_USBTask) | void USB_USBTask(void) | ||||||
| { | { | ||||||
| 	#if defined(USB_HOST_ONLY) | 	#if defined(USB_HOST_ONLY) | ||||||
| 		USB_HostTask(); | 		USB_HostTask(); | ||||||
|  | |||||||
| @ -38,7 +38,6 @@ | |||||||
| 		#include <stdbool.h> | 		#include <stdbool.h> | ||||||
| 		#include <stddef.h> | 		#include <stddef.h> | ||||||
| 		 | 		 | ||||||
| 		#include "../../../Scheduler/Scheduler.h" |  | ||||||
| 		#include "../LowLevel/LowLevel.h" | 		#include "../LowLevel/LowLevel.h" | ||||||
| 		#include "StdRequestType.h" | 		#include "StdRequestType.h" | ||||||
| 		#include "USBMode.h" | 		#include "USBMode.h" | ||||||
| @ -122,11 +121,11 @@ | |||||||
| 			extern volatile uint8_t USB_HostState; | 			extern volatile uint8_t USB_HostState; | ||||||
| 			#endif | 			#endif | ||||||
| 
 | 
 | ||||||
| 		/* Tasks: */ | 		/* Function Prototypes: */ | ||||||
| 			/** This is the main USB management task. The USB driver requires that this task be executed
 | 			/** This is the main USB management task. The USB driver requires that this task be executed
 | ||||||
| 			 *  continuously when the USB system is active (device attached in host mode, or attached to a host | 			 *  continuously when the USB system is active (device attached in host mode, or attached to a host | ||||||
| 			 *  in device mode) in order to manage USB communications. This task may be executed inside an RTOS, | 			 *  in device mode) in order to manage USB communications. This task may be executed inside an RTOS, | ||||||
| 			 *  scheduler (e.g. the simple LUFA Scheduler), fast timer ISR or the main user application loop. | 			 *  fast timer ISR or the main user application loop. | ||||||
| 			 * | 			 * | ||||||
| 			 *  The USB task must be serviced within 30ms while in device mode, or within 1ms while in host mode. | 			 *  The USB task must be serviced within 30ms while in device mode, or within 1ms while in host mode. | ||||||
| 			 *  The task may be serviced at all times, or (for minimum CPU consumption): | 			 *  The task may be serviced at all times, or (for minimum CPU consumption): | ||||||
| @ -145,7 +144,7 @@ | |||||||
| 			 * | 			 * | ||||||
| 			 *  \ingroup Group_USBManagement | 			 *  \ingroup Group_USBManagement | ||||||
| 			 */ | 			 */ | ||||||
| 			TASK(USB_USBTask); | 			void USB_USBTask(void); | ||||||
| 
 | 
 | ||||||
| 	/* Private Interface - For use in library only: */ | 	/* Private Interface - For use in library only: */ | ||||||
| 	#if !defined(__DOXYGEN__) | 	#if !defined(__DOXYGEN__) | ||||||
|  | |||||||
| @ -80,8 +80,6 @@ uint8_t Endpoint_WaitUntilReady(void) | |||||||
| 	uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS; | 	uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS; | ||||||
| 	#endif | 	#endif | ||||||
| 
 | 
 | ||||||
| 	USB_INT_Clear(USB_INT_SOFI); |  | ||||||
| 
 |  | ||||||
| 	for (;;) | 	for (;;) | ||||||
| 	{ | 	{ | ||||||
| 		if (Endpoint_GetEndpointDirection() == ENDPOINT_DIR_IN) | 		if (Endpoint_GetEndpointDirection() == ENDPOINT_DIR_IN) | ||||||
| @ -100,9 +98,9 @@ uint8_t Endpoint_WaitUntilReady(void) | |||||||
| 		else if (Endpoint_IsStalled()) | 		else if (Endpoint_IsStalled()) | ||||||
| 		  return ENDPOINT_READYWAIT_EndpointStalled; | 		  return ENDPOINT_READYWAIT_EndpointStalled; | ||||||
| 			   | 			   | ||||||
| 		if (USB_INT_HasOccurred(USB_INT_SOFI)) | 		if (FrameElapsed) | ||||||
| 		{ | 		{ | ||||||
| 			USB_INT_Clear(USB_INT_SOFI); | 			FrameElapsed = false; | ||||||
| 
 | 
 | ||||||
| 			if (!(TimeoutMSRem--)) | 			if (!(TimeoutMSRem--)) | ||||||
| 			  return ENDPOINT_READYWAIT_Timeout; | 			  return ENDPOINT_READYWAIT_Timeout; | ||||||
|  | |||||||
| @ -210,14 +210,13 @@ uint8_t USB_Host_WaitMS(uint8_t MS) | |||||||
| 	bool    BusSuspended = USB_Host_IsBusSuspended(); | 	bool    BusSuspended = USB_Host_IsBusSuspended(); | ||||||
| 	uint8_t ErrorCode    = HOST_WAITERROR_Successful; | 	uint8_t ErrorCode    = HOST_WAITERROR_Successful; | ||||||
| 	 | 	 | ||||||
| 	USB_INT_Clear(USB_INT_HSOFI); |  | ||||||
| 	USB_Host_ResumeBus(); | 	USB_Host_ResumeBus(); | ||||||
| 
 | 
 | ||||||
| 	while (MS) | 	while (MS) | ||||||
| 	{ | 	{ | ||||||
| 		if (USB_INT_HasOccurred(USB_INT_HSOFI)) | 		if (FrameElapsed) | ||||||
| 		{ | 		{ | ||||||
| 			USB_INT_Clear(USB_INT_HSOFI); | 			FrameElapsed = false; | ||||||
| 			MS--; | 			MS--; | ||||||
| 		} | 		} | ||||||
| 					 | 					 | ||||||
| @ -260,9 +259,10 @@ static void USB_Host_ResetDevice(void) | |||||||
| 	USB_Host_ResetBus(); | 	USB_Host_ResetBus(); | ||||||
| 	while (!(USB_Host_IsBusResetComplete())); | 	while (!(USB_Host_IsBusResetComplete())); | ||||||
| 
 | 
 | ||||||
| 	USB_INT_Clear(USB_INT_HSOFI); |  | ||||||
| 	USB_Host_ResumeBus();	 | 	USB_Host_ResumeBus();	 | ||||||
| 	 | 	 | ||||||
|  | 	FrameElapsed = false; | ||||||
|  | 
 | ||||||
| 	for (uint8_t MSRem = 10; MSRem != 0; MSRem--) | 	for (uint8_t MSRem = 10; MSRem != 0; MSRem--) | ||||||
| 	{ | 	{ | ||||||
| 		/* Workaround for powerless-pull-up devices. After a USB bus reset,
 | 		/* Workaround for powerless-pull-up devices. After a USB bus reset,
 | ||||||
| @ -270,8 +270,10 @@ static void USB_Host_ResetDevice(void) | |||||||
| 		   looked for - if it is found within 10ms, the device is still | 		   looked for - if it is found within 10ms, the device is still | ||||||
| 		   present.                                                        */ | 		   present.                                                        */ | ||||||
| 
 | 
 | ||||||
| 		if (USB_INT_HasOccurred(USB_INT_HSOFI)) | 		if (FrameElapsed) | ||||||
| 		{ | 		{ | ||||||
|  | 			FrameElapsed = false; | ||||||
|  | 			 | ||||||
| 			USB_INT_Clear(USB_INT_DDISCI); | 			USB_INT_Clear(USB_INT_DDISCI); | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -38,6 +38,8 @@ volatile uint8_t USB_CurrentMode = USB_MODE_NONE; | |||||||
| volatile uint8_t USB_Options; | volatile uint8_t USB_Options; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | volatile bool FrameElapsed; | ||||||
|  | 
 | ||||||
| void USB_Init( | void USB_Init( | ||||||
|                #if defined(USB_CAN_BE_BOTH) |                #if defined(USB_CAN_BE_BOTH) | ||||||
|                const uint8_t Mode |                const uint8_t Mode | ||||||
| @ -150,6 +152,8 @@ void USB_ResetInterface(void) | |||||||
| 	USB_INT_DisableAllInterrupts(); | 	USB_INT_DisableAllInterrupts(); | ||||||
| 	USB_INT_ClearAllInterrupts(); | 	USB_INT_ClearAllInterrupts(); | ||||||
| 
 | 
 | ||||||
|  | 	FrameElapsed = false; | ||||||
|  | 
 | ||||||
| 	USB_IsConnected = false; | 	USB_IsConnected = false; | ||||||
| 
 | 
 | ||||||
| 	#if defined(USB_CAN_BE_HOST) | 	#if defined(USB_CAN_BE_HOST) | ||||||
| @ -224,6 +228,7 @@ void USB_ResetInterface(void) | |||||||
| 	#if defined(USB_DEVICE_ONLY)	 | 	#if defined(USB_DEVICE_ONLY)	 | ||||||
| 	USB_INT_Enable(USB_INT_SUSPEND); | 	USB_INT_Enable(USB_INT_SUSPEND); | ||||||
| 	USB_INT_Enable(USB_INT_EORSTI); | 	USB_INT_Enable(USB_INT_EORSTI); | ||||||
|  | 	USB_INT_Enable(USB_INT_SOFI); | ||||||
| 
 | 
 | ||||||
| 	#if defined(CONTROL_ONLY_DEVICE) | 	#if defined(CONTROL_ONLY_DEVICE) | ||||||
| 	UENUM = ENDPOINT_CONTROLEP; | 	UENUM = ENDPOINT_CONTROLEP; | ||||||
| @ -240,11 +245,13 @@ void USB_ResetInterface(void) | |||||||
| 	 | 	 | ||||||
| 	USB_INT_Enable(USB_INT_SRPI); | 	USB_INT_Enable(USB_INT_SRPI); | ||||||
| 	USB_INT_Enable(USB_INT_BCERRI); | 	USB_INT_Enable(USB_INT_BCERRI); | ||||||
|  | 	USB_INT_Enable(USB_INT_HSOFI); | ||||||
| 	#else | 	#else | ||||||
| 	if (USB_CurrentMode == USB_MODE_DEVICE) | 	if (USB_CurrentMode == USB_MODE_DEVICE) | ||||||
| 	{ | 	{ | ||||||
| 		USB_INT_Enable(USB_INT_SUSPEND); | 		USB_INT_Enable(USB_INT_SUSPEND); | ||||||
| 		USB_INT_Enable(USB_INT_EORSTI); | 		USB_INT_Enable(USB_INT_EORSTI); | ||||||
|  | 		USB_INT_Enable(USB_INT_SOFI); | ||||||
| 
 | 
 | ||||||
| 		#if defined(CONTROL_ONLY_DEVICE) | 		#if defined(CONTROL_ONLY_DEVICE) | ||||||
| 		UENUM = ENDPOINT_CONTROLEP; | 		UENUM = ENDPOINT_CONTROLEP; | ||||||
| @ -262,6 +269,7 @@ void USB_ResetInterface(void) | |||||||
| 		 | 		 | ||||||
| 		USB_INT_Enable(USB_INT_SRPI); | 		USB_INT_Enable(USB_INT_SRPI); | ||||||
| 		USB_INT_Enable(USB_INT_BCERRI); | 		USB_INT_Enable(USB_INT_BCERRI); | ||||||
|  | 		USB_INT_Enable(USB_INT_HSOFI); | ||||||
| 	} | 	} | ||||||
| 	#endif | 	#endif | ||||||
| } | } | ||||||
|  | |||||||
| @ -351,6 +351,9 @@ | |||||||
| 			} | 			} | ||||||
| 			#endif | 			#endif | ||||||
| 		 | 		 | ||||||
|  | 		/* External Variables: */ | ||||||
|  | 			extern volatile bool FrameElapsed; | ||||||
|  | 			 | ||||||
| 	#endif | 	#endif | ||||||
| 	 | 	 | ||||||
| 	/* Disable C linkage for C++ Compilers: */ | 	/* Disable C linkage for C++ Compilers: */ | ||||||
|  | |||||||
| @ -76,8 +76,6 @@ uint8_t Pipe_WaitUntilReady(void) | |||||||
| 	uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS; | 	uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS; | ||||||
| 	#endif | 	#endif | ||||||
| 
 | 
 | ||||||
| 	USB_INT_Clear(USB_INT_HSOFI); |  | ||||||
| 
 |  | ||||||
| 	for (;;) | 	for (;;) | ||||||
| 	{ | 	{ | ||||||
| 		if (Pipe_GetPipeToken() == PIPE_TOKEN_IN) | 		if (Pipe_GetPipeToken() == PIPE_TOKEN_IN) | ||||||
| @ -96,9 +94,9 @@ uint8_t Pipe_WaitUntilReady(void) | |||||||
| 		else if (!(USB_IsConnected)) | 		else if (!(USB_IsConnected)) | ||||||
| 		  return PIPE_READYWAIT_DeviceDisconnected; | 		  return PIPE_READYWAIT_DeviceDisconnected; | ||||||
| 			   | 			   | ||||||
| 		if (USB_INT_HasOccurred(USB_INT_HSOFI)) | 		if (FrameElapsed) | ||||||
| 		{ | 		{ | ||||||
| 			USB_INT_Clear(USB_INT_HSOFI); | 			FrameElapsed = false; | ||||||
| 
 | 
 | ||||||
| 			if (!(TimeoutMSRem--)) | 			if (!(TimeoutMSRem--)) | ||||||
| 			  return PIPE_READYWAIT_Timeout; | 			  return PIPE_READYWAIT_Timeout; | ||||||
|  | |||||||
| @ -49,7 +49,6 @@ | |||||||
|  *    - LUFA/Drivers/USB/HighLevel/USBInterrupt.c |  *    - LUFA/Drivers/USB/HighLevel/USBInterrupt.c | ||||||
|  *    - LUFA/Drivers/USB/HighLevel/USBTask.c |  *    - LUFA/Drivers/USB/HighLevel/USBTask.c | ||||||
|  *    - LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c |  *    - LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c | ||||||
|  *    - LUFA/Drivers/USB/Class/HIDParser.c |  | ||||||
|  * |  * | ||||||
|  *  \section Module Description |  *  \section Module Description | ||||||
|  *  Functions, macros, variables, enums and types related to the management of USB communications. |  *  Functions, macros, variables, enums and types related to the management of USB communications. | ||||||
| @ -97,7 +96,6 @@ | |||||||
| 		#endif | 		#endif | ||||||
| 		 | 		 | ||||||
| 		#include "HighLevel/ConfigDescriptor.h" | 		#include "HighLevel/ConfigDescriptor.h" | ||||||
| 		#include "Class/HIDParser.h" |  | ||||||
| 		 | 		 | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,226 +0,0 @@ | |||||||
| /*
 |  | ||||||
|              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. |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| #define  INCLUDE_FROM_DYNALLOC_C |  | ||||||
| #include "DynAlloc.h" |  | ||||||
| 
 |  | ||||||
| struct |  | ||||||
| { |  | ||||||
| 	char    Mem_Heap[NUM_BLOCKS * BLOCK_SIZE]; |  | ||||||
| 	void*   Mem_Handles[NUM_HANDLES]; |  | ||||||
| 	uint8_t Mem_Block_Flags[(NUM_BLOCKS / 4) + ((NUM_BLOCKS % 4) ? 1 : 0)]; |  | ||||||
| 	uint8_t FlagMaskLookupMask[4]; |  | ||||||
| 	uint8_t FlagMaskLookupNum[4]; |  | ||||||
| } Mem_MemData = {.FlagMaskLookupMask = {(3 << 0), (3 << 2), (3 << 4), (3 << 6)}, |  | ||||||
|                  .FlagMaskLookupNum  = {      0,        2,        4,        6}}; |  | ||||||
| 
 |  | ||||||
| static uint8_t Mem_GetBlockFlags(const Block_Number_t BlockNum) |  | ||||||
| { |  | ||||||
| 	const Block_Number_t BlockIndex    = (BlockNum >> 2); |  | ||||||
| 	const uint8_t        FlagMask      = Mem_MemData.FlagMaskLookupMask[BlockNum & 0x03]; |  | ||||||
| 	const uint8_t        FlagMaskShift = Mem_MemData.FlagMaskLookupNum[BlockNum & 0x03]; |  | ||||||
| 
 |  | ||||||
| 	return ((Mem_MemData.Mem_Block_Flags[BlockIndex] & FlagMask) >> FlagMaskShift); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void Mem_SetBlockFlags(const Block_Number_t BlockNum, const uint8_t Flags) |  | ||||||
| { |  | ||||||
| 	const Block_Number_t BlockIndex    = (BlockNum >> 2); |  | ||||||
| 	const uint8_t        FlagMask      = Mem_MemData.FlagMaskLookupMask[BlockNum & 0x03]; |  | ||||||
| 	const uint8_t        FlagMaskShift = Mem_MemData.FlagMaskLookupNum[BlockNum & 0x03]; |  | ||||||
| 
 |  | ||||||
| 	Mem_MemData.Mem_Block_Flags[BlockIndex] &= ~FlagMask; |  | ||||||
| 	Mem_MemData.Mem_Block_Flags[BlockIndex] |= (Flags << FlagMaskShift); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline void Mem_Defrag(void) |  | ||||||
| { |  | ||||||
| 	Block_Number_t FreeStartBlock = 0; |  | ||||||
| 	char*          FreeStartPtr   = NULL; |  | ||||||
| 	char*          UsedStartPtr   = NULL; |  | ||||||
| 	Block_Number_t CurrBlock; |  | ||||||
| 	 |  | ||||||
| 	for (CurrBlock = 0; CurrBlock < NUM_BLOCKS; CurrBlock++) |  | ||||||
| 	{ |  | ||||||
| 		if (!(Mem_GetBlockFlags(CurrBlock) & BLOCK_USED_MASK)) |  | ||||||
| 		{ |  | ||||||
| 			FreeStartPtr   = &Mem_MemData.Mem_Heap[CurrBlock * BLOCK_SIZE]; |  | ||||||
| 			FreeStartBlock = CurrBlock; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	if (FreeStartPtr == NULL) |  | ||||||
| 	  return; |  | ||||||
| 
 |  | ||||||
| 	while (++CurrBlock < NUM_BLOCKS) |  | ||||||
| 	{ |  | ||||||
| 		uint8_t CurrBlockFlags = Mem_GetBlockFlags(CurrBlock); |  | ||||||
| 	 |  | ||||||
| 		if (CurrBlockFlags & BLOCK_USED_MASK) |  | ||||||
| 		{ |  | ||||||
| 			UsedStartPtr = &Mem_MemData.Mem_Heap[CurrBlock * BLOCK_SIZE]; |  | ||||||
| 		 |  | ||||||
| 			for (Handle_Number_t HandleNum = 0; HandleNum < NUM_HANDLES; HandleNum++) |  | ||||||
| 			{ |  | ||||||
| 				if (Mem_MemData.Mem_Handles[HandleNum] == UsedStartPtr) |  | ||||||
| 				{ |  | ||||||
| 					Mem_MemData.Mem_Handles[HandleNum] = FreeStartPtr; |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			memcpy(FreeStartPtr, UsedStartPtr, BLOCK_SIZE); |  | ||||||
| 			FreeStartPtr += BLOCK_SIZE; |  | ||||||
| 			   |  | ||||||
| 			Mem_SetBlockFlags(FreeStartBlock++, CurrBlockFlags); |  | ||||||
| 			Mem_SetBlockFlags(CurrBlock, 0); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline bool Mem_FindFreeBlocks(Block_Number_t* const RetStartPtr, const Block_Number_t Blocks) |  | ||||||
| { |  | ||||||
| 	Block_Number_t FreeInCurrSec = 0; |  | ||||||
| 
 |  | ||||||
| 	for (Block_Number_t CurrBlock = 0; CurrBlock < NUM_BLOCKS; CurrBlock++) |  | ||||||
| 	{ |  | ||||||
| 		if (Mem_GetBlockFlags(CurrBlock) & BLOCK_USED_MASK) |  | ||||||
| 		  FreeInCurrSec = 0; |  | ||||||
| 		else |  | ||||||
| 		  FreeInCurrSec++; |  | ||||||
| 
 |  | ||||||
| 		if (FreeInCurrSec >= Blocks) |  | ||||||
| 		{ |  | ||||||
| 			*RetStartPtr = CurrBlock; |  | ||||||
| 			return true; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Mem_Handle_t Mem_Alloc(const Alloc_Size_t Bytes) |  | ||||||
| { |  | ||||||
| 	Block_Number_t ReqBlocks = (Bytes / BLOCK_SIZE); |  | ||||||
| 	Block_Number_t StartBlock; |  | ||||||
| 	 |  | ||||||
| 	if (Bytes % BLOCK_SIZE) |  | ||||||
| 	  ReqBlocks++; |  | ||||||
| 	 |  | ||||||
| 	if (!(Mem_FindFreeBlocks(&StartBlock, ReqBlocks))) |  | ||||||
| 	{ |  | ||||||
| 		Mem_Defrag(); |  | ||||||
| 		 |  | ||||||
| 		if (!(Mem_FindFreeBlocks(&StartBlock, ReqBlocks))) |  | ||||||
| 		  return NULL;	 |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	for (Block_Number_t UsedBlock = 0; UsedBlock < (ReqBlocks - 1); UsedBlock++) |  | ||||||
| 	  Mem_SetBlockFlags((StartBlock + UsedBlock), (BLOCK_USED_MASK | BLOCK_LINKED_MASK)); |  | ||||||
| 
 |  | ||||||
| 	Mem_SetBlockFlags((StartBlock + (ReqBlocks - 1)), BLOCK_USED_MASK); |  | ||||||
| 	 |  | ||||||
| 	for (Handle_Number_t AllocEntry = 0; AllocEntry < NUM_HANDLES; AllocEntry++) |  | ||||||
| 	{ |  | ||||||
| 		Mem_Handle_t CurrHdl = (Mem_Handle_t)&Mem_MemData.Mem_Handles[AllocEntry]; |  | ||||||
| 	 |  | ||||||
| 		if (DEREF(CurrHdl, void*) == NULL) |  | ||||||
| 		{ |  | ||||||
| 			DEREF(CurrHdl, void*) = &Mem_MemData.Mem_Heap[StartBlock * BLOCK_SIZE]; |  | ||||||
| 			return CurrHdl; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Mem_Handle_t Mem_Realloc(Mem_Handle_t CurrAllocHdl, const Alloc_Size_t Bytes) |  | ||||||
| { |  | ||||||
| 	Mem_Free(CurrAllocHdl); |  | ||||||
| 	return Mem_Alloc(Bytes); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Mem_Handle_t Mem_Calloc(const Alloc_Size_t Bytes) |  | ||||||
| { |  | ||||||
| 	Mem_Handle_t AllocHdl = Mem_Alloc(Bytes); |  | ||||||
| 	 |  | ||||||
| 	if (AllocHdl != NULL) |  | ||||||
| 	  memset(DEREF(AllocHdl, void*), 0x00, Bytes); |  | ||||||
| 
 |  | ||||||
| 	return AllocHdl; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Mem_Free(Mem_Handle_t CurrAllocHdl) |  | ||||||
| { |  | ||||||
| 	char*          MemBlockPtr = DEREF(CurrAllocHdl, char*); |  | ||||||
| 	Block_Number_t CurrBlock   = ((uint16_t)(MemBlockPtr - Mem_MemData.Mem_Heap) / BLOCK_SIZE); |  | ||||||
| 	uint8_t        CurrBlockFlags; |  | ||||||
| 
 |  | ||||||
| 	if ((CurrAllocHdl == NULL) || (MemBlockPtr == NULL)) |  | ||||||
| 	  return; |  | ||||||
| 
 |  | ||||||
| 	do |  | ||||||
| 	{ |  | ||||||
| 		CurrBlockFlags = Mem_GetBlockFlags(CurrBlock); |  | ||||||
| 		Mem_SetBlockFlags(CurrBlock, 0); |  | ||||||
| 
 |  | ||||||
| 		CurrBlock++; |  | ||||||
| 	} |  | ||||||
| 	while (CurrBlockFlags & BLOCK_LINKED_MASK); |  | ||||||
| 	 |  | ||||||
| 	DEREF(CurrAllocHdl, void*) = NULL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Block_Number_t Mem_TotalFreeBlocks(void) |  | ||||||
| { |  | ||||||
| 	Block_Number_t FreeBlocks = 0; |  | ||||||
| 	 |  | ||||||
| 	for (Block_Number_t CurrBlock = 0; CurrBlock < NUM_BLOCKS; CurrBlock++) |  | ||||||
| 	{ |  | ||||||
| 		if (!(Mem_GetBlockFlags(CurrBlock) & BLOCK_USED_MASK)) |  | ||||||
| 		  FreeBlocks++; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	return FreeBlocks; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Handle_Number_t Mem_TotalFreeHandles(void) |  | ||||||
| { |  | ||||||
| 	Handle_Number_t FreeHandles = 0; |  | ||||||
| 	 |  | ||||||
| 	for (Handle_Number_t CurrHandle = 0; CurrHandle < NUM_HANDLES; CurrHandle++) |  | ||||||
| 	{ |  | ||||||
| 		if (Mem_MemData.Mem_Handles[CurrHandle] == NULL) |  | ||||||
| 		  FreeHandles++; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	return FreeHandles; |  | ||||||
| } |  | ||||||
| @ -1,198 +0,0 @@ | |||||||
| /*
 |  | ||||||
|              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
 |  | ||||||
|  * |  | ||||||
|  *  Dynamic, auto-defragmenting block memory allocator library. This library provides a convenient replacement for |  | ||||||
|  *  the standard avr-libc dynamic memory allocation routines. Memory is handed out in block chunks, to reduce the |  | ||||||
|  *  management memory overhead. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| /** @defgroup Group_MemoryAllocator Dynamic Block Memory Allocator - LUFA/MemoryAllocator/DynAlloc.h
 |  | ||||||
|  * |  | ||||||
|  *  \section Sec_Dependencies Module Source Dependencies |  | ||||||
|  *  The following files must be built with any user project that uses this module: |  | ||||||
|  *    - LUFA/MemoryAllocator/DynAlloc.c |  | ||||||
|  * |  | ||||||
|  *  \section Module Description |  | ||||||
|  *  Dynamic, auto-defragmenting block memory allocator library. This library provides a convenient replacement for |  | ||||||
|  *  the standard avr-libc dynamic memory allocation routines. Memory is handed out in block chunks, to reduce the |  | ||||||
|  *  management memory overhead. |  | ||||||
|  * |  | ||||||
|  *  Unlike the normal memory allocation routines, this library gives out handles to memory which must be dereferenced |  | ||||||
|  *  at the exact time of use, rather than handing back direct memory pointers. By using library managed handles |  | ||||||
|  *  instead of pointers, allocated memory blocks can be shifted around as needed transparently to defragment the |  | ||||||
|  *  memory as more blocks are requested. |  | ||||||
|  * |  | ||||||
|  *  The memory heap is static, thus the total memory usage of the compiled application (as reported by the avr-size |  | ||||||
|  *  tool of the AVR-GCC toolchain) includes the dynamic memory heap. |  | ||||||
|  * |  | ||||||
|  *  The constants NUM_BLOCKS, BLOCK_SIZE and NUM_HANDLES must be defined in the project makefile (and passed to the |  | ||||||
|  *  preprocessor via the -D GCC switch) for this library to compile. |  | ||||||
|  * |  | ||||||
|  *  NUM_BLOCKS indicates the number of memory blocks in the memory psudoheap which can be chained together and handed |  | ||||||
|  *  to the application via a memory handle. NUM_HANDLES is the maximum number of memory handles (pointing to one or |  | ||||||
|  *  more chained memory blocks) which can be handed out simultaneously before requiring a handle (and its associated |  | ||||||
|  *  memory) to be freed. BLOCK_SIZE gives the number of bytes in each memory block.  |  | ||||||
|  * |  | ||||||
|  *  @{ |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #ifndef __DYN_ALLOC__ |  | ||||||
| #define __DYN_ALLOC__ |  | ||||||
| 
 |  | ||||||
| 	/* Includes : */ |  | ||||||
| 		#include <avr/io.h> |  | ||||||
| 		#include <stdbool.h> |  | ||||||
| 		#include <string.h> |  | ||||||
| 	 |  | ||||||
| 	/* Preprocessor Checks: */ |  | ||||||
| 		#if (!defined(NUM_BLOCKS) || !defined(BLOCK_SIZE) || !defined(NUM_HANDLES)) |  | ||||||
| 			#error NUM_BLOCKS, BLOCK_SIZE and NUM_HANDLES must be defined before use via makefile. |  | ||||||
| 		#endif |  | ||||||
| 
 |  | ||||||
| 	/* Public Interface - May be used in end-application: */ |  | ||||||
| 		/* Macros: */ |  | ||||||
| 			/** Macro to dereference a given memory handle into the given type. The given type should be a pointer
 |  | ||||||
| 			 *  if the memory is to contain an array of items, or should be a standard type (such as a primitive or |  | ||||||
| 			 *  structure) if the memory is to hold a single item of a single type. */ |  | ||||||
| 			#define DEREF(handle, type)       (*(type*)handle) |  | ||||||
| 			 |  | ||||||
| 			/** Constant, giving the total heap size in bytes. */ |  | ||||||
| 			#define ALLOCABLE_BYTES           (1UL * NUM_BLOCKS * BLOCK_SIZE) |  | ||||||
| 		 |  | ||||||
| 		/* Type Defines: */ |  | ||||||
| 			/** Memory handle type, used to store handles given by the library functions. */ |  | ||||||
| 			typedef const void** Mem_Handle_t; |  | ||||||
| 			 |  | ||||||
| 			#if (ALLOCABLE_BYTES > 0xFFFF) || defined(__DOXYGEN__) |  | ||||||
| 				/** Type define for the size (in bytes) for an allocation for passing to the library functions.
 |  | ||||||
| 				 *  The exact type width varies depending on the value of ALLOCABLE_BYTES to ensure that a single |  | ||||||
| 				 *  allocation can request the entire heap if needed. |  | ||||||
| 				 */ |  | ||||||
| 				typedef uint32_t Alloc_Size_t; |  | ||||||
| 			#elif (ALLOCABLE_BYTES > 0xFF) |  | ||||||
| 				typedef uint16_t Alloc_Size_t; |  | ||||||
| 			#else			 |  | ||||||
| 				typedef uint8_t  Alloc_Size_t; |  | ||||||
| 			#endif |  | ||||||
| 
 |  | ||||||
| 			#if (NUM_BLOCKS > 0xFFFF) || defined(__DOXYGEN__) |  | ||||||
| 				/** Type define for a block number in the heap. The exact type width varies depending on the
 |  | ||||||
| 				 *   value of NUM_BLOCKS to ensure that the type can store an index to any block in the block pool. |  | ||||||
| 				 */ |  | ||||||
| 				typedef uint32_t Block_Number_t; |  | ||||||
| 			#elif (NUM_BLOCKS > 0xFF) |  | ||||||
| 				typedef uint16_t Block_Number_t; |  | ||||||
| 			#else |  | ||||||
| 				typedef uint8_t  Block_Number_t; |  | ||||||
| 			#endif |  | ||||||
| 
 |  | ||||||
| 			#if (NUM_HANDLES > 0xFFFF) || defined(__DOXYGEN__) |  | ||||||
| 				/** Type define for a handle number. The exact type width varies depending on the value of NUM_HANDLES
 |  | ||||||
| 				 *  to ensure that the type can store the index of any handle in the handle pool. |  | ||||||
| 				 */ |  | ||||||
| 				typedef uint32_t Handle_Number_t; |  | ||||||
| 			#elif (NUM_HANDLES > 0xFF) |  | ||||||
| 				typedef uint16_t Handle_Number_t; |  | ||||||
| 			#else			 |  | ||||||
| 				typedef uint8_t  Handle_Number_t; |  | ||||||
| 			#endif |  | ||||||
| 			 |  | ||||||
| 		/* Function Prototypes: */ |  | ||||||
| 			/** Allocates a given number of blocks from the heap (calculated from the requested number of bytes) and
 |  | ||||||
| 			 *  returns a handle to the newly allocated memory. |  | ||||||
| 			 * |  | ||||||
| 			 *  \param Bytes  The number of bytes requested to be allocated from the heap |  | ||||||
| 			 * |  | ||||||
| 			 *  \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds |  | ||||||
| 			 */ |  | ||||||
| 			Mem_Handle_t    Mem_Alloc(const Alloc_Size_t Bytes); |  | ||||||
| 			 |  | ||||||
| 			/** Allocates a given number of blocks from the heap (calculated from the requested number of bytes) and
 |  | ||||||
| 			 *  returns a handle to the newly allocated memory. Calloced memory is automatically cleared to all 0x00 |  | ||||||
| 			 *  values at the time of allocation. |  | ||||||
| 			 * |  | ||||||
| 			 *  \param Bytes  The number of pre-cleared bytes requested to be allocated from the heap |  | ||||||
| 			 * |  | ||||||
| 			 *  \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds |  | ||||||
| 			 */ |  | ||||||
| 			Mem_Handle_t    Mem_Calloc(const Alloc_Size_t Bytes); |  | ||||||
| 
 |  | ||||||
| 			/** Deallocates a given memory handle, and attempts to allocates the given number of blocks from the heap
 |  | ||||||
| 			 *  (calculated from the requested number of bytes) immediately following the deallocation. The new memory |  | ||||||
| 			 *  may be located in the same area as the previous memory, but this is not guaranteed. |  | ||||||
| 			 * |  | ||||||
| 			 *  \param CurrAllocHdl  Handle to an already allocated section of memory in the heap to deallocate |  | ||||||
| 			 *  \param Bytes         The number of bytes requested to be allocated from the heap following the |  | ||||||
| 			 *                       deallocation |  | ||||||
| 			 * |  | ||||||
| 			 *  \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds |  | ||||||
| 			 * |  | ||||||
| 			 *  \warning Even if the allocation fails, the deallocation will still occur. Care should be taken to ensure |  | ||||||
| 			 *           that the previously allocated memory is not used following an unsuccessful realloc(). |  | ||||||
| 			 */ |  | ||||||
| 			Mem_Handle_t    Mem_Realloc(Mem_Handle_t CurrAllocHdl, const Alloc_Size_t Bytes); |  | ||||||
| 			 |  | ||||||
| 			/** Deallocates a given previously allocated section of memory from the heap.
 |  | ||||||
| 			 * |  | ||||||
| 			 *  \param CurrAllocHdl  Handle to a previously allocated section of memory in the heap |  | ||||||
| 			 */ |  | ||||||
| 			void            Mem_Free(Mem_Handle_t CurrAllocHdl); |  | ||||||
| 			 |  | ||||||
| 			/** Returns the total number of unallocated blocks in the heap.
 |  | ||||||
| 			 * |  | ||||||
| 			 *  \return Number of free blocks in the heap, as a Block_Number_t integer |  | ||||||
| 			 */ |  | ||||||
| 			Block_Number_t  Mem_TotalFreeBlocks(void); |  | ||||||
| 
 |  | ||||||
| 			/** Returns the total number of unallocated handles in the handle pool.
 |  | ||||||
| 			 * |  | ||||||
| 			 *  \return Number of free handles in the handle pool, as a Handle_Number_t integer |  | ||||||
| 			 */ |  | ||||||
| 			Handle_Number_t Mem_TotalFreeHandles(void); |  | ||||||
| 		 |  | ||||||
| 	/* Private Interface - For use in library only: */ |  | ||||||
| 	#if !defined(__DOXYGEN__) |  | ||||||
| 		/* Macros: */ |  | ||||||
| 			#define BLOCK_USED_MASK           (1 << 0) |  | ||||||
| 			#define BLOCK_LINKED_MASK         (1 << 1) |  | ||||||
| 			 |  | ||||||
| 		/* Function Prototypes: */ |  | ||||||
| 			#if defined(INCLUDE_FROM_DYNALLOC_C) |  | ||||||
| 				static uint8_t Mem_GetBlockFlags(const Block_Number_t BlockNum); |  | ||||||
| 				static void    Mem_SetBlockFlags(const Block_Number_t BlockNum, const uint8_t Flags); |  | ||||||
| 				static void    Mem_Defrag(void); |  | ||||||
| 			#endif |  | ||||||
| 	#endif |  | ||||||
| 	 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /** @} */ |  | ||||||
| @ -1,95 +0,0 @@ | |||||||
| /*
 |  | ||||||
|              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 "Scheduler.h" |  | ||||||
| 
 |  | ||||||
| volatile SchedulerDelayCounter_t Scheduler_TickCounter; |  | ||||||
| volatile uint8_t                 Scheduler_TotalTasks; |  | ||||||
| 
 |  | ||||||
| bool Scheduler_HasDelayElapsed(const uint16_t Delay, SchedulerDelayCounter_t* const DelayCounter) |  | ||||||
| { |  | ||||||
| 	SchedulerDelayCounter_t CurrentTickValue_LCL; |  | ||||||
| 	SchedulerDelayCounter_t DelayCounter_LCL; |  | ||||||
| 	 |  | ||||||
| 	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) |  | ||||||
| 	{ |  | ||||||
| 		CurrentTickValue_LCL = Scheduler_TickCounter; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	DelayCounter_LCL = *DelayCounter; |  | ||||||
| 	 |  | ||||||
| 	if (CurrentTickValue_LCL >= DelayCounter_LCL) |  | ||||||
| 	{ |  | ||||||
| 		if ((CurrentTickValue_LCL - DelayCounter_LCL) >= Delay) |  | ||||||
| 		{ |  | ||||||
| 			*DelayCounter = CurrentTickValue_LCL; |  | ||||||
| 			return true; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		if (((MAX_DELAYCTR_COUNT - DelayCounter_LCL) + CurrentTickValue_LCL) >= Delay) |  | ||||||
| 		{ |  | ||||||
| 			*DelayCounter = CurrentTickValue_LCL; |  | ||||||
| 			return true; |  | ||||||
| 		}	 |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Scheduler_SetTaskMode(const TaskPtr_t Task, const bool TaskStatus) |  | ||||||
| { |  | ||||||
| 	TaskEntry_t* CurrTask = &Scheduler_TaskList[0]; |  | ||||||
| 					 |  | ||||||
| 	while (CurrTask != &Scheduler_TaskList[Scheduler_TotalTasks]) |  | ||||||
| 	{ |  | ||||||
| 		if (CurrTask->Task == Task) |  | ||||||
| 		{ |  | ||||||
| 			CurrTask->TaskStatus = TaskStatus; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		CurrTask++; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Scheduler_SetGroupTaskMode(const uint8_t GroupID, const bool TaskStatus) |  | ||||||
| { |  | ||||||
| 	TaskEntry_t* CurrTask = &Scheduler_TaskList[0]; |  | ||||||
| 					 |  | ||||||
| 	while (CurrTask != &Scheduler_TaskList[Scheduler_TotalTasks]) |  | ||||||
| 	{ |  | ||||||
| 		if (CurrTask->GroupID == GroupID) |  | ||||||
| 		  CurrTask->TaskStatus = TaskStatus; |  | ||||||
| 		 |  | ||||||
| 		CurrTask++; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @ -1,285 +0,0 @@ | |||||||
| /*
 |  | ||||||
|              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
 |  | ||||||
|  * |  | ||||||
|  *  Simple round-robbin cooperative scheduler for use in basic projects where non real-time tasks need |  | ||||||
|  *  to be executed. Each task is executed in sequence, and can be enabled or disabled individually or as a group. |  | ||||||
|  */ |  | ||||||
|   |  | ||||||
| /** @defgroup Group_Scheduler Simple Task Scheduler - LUFA/Scheduler/Scheduler.h
 |  | ||||||
|  * |  | ||||||
|  *  \section Sec_Dependencies Module Source Dependencies |  | ||||||
|  *  The following files must be built with any user project that uses this module: |  | ||||||
|  *    - LUFA/Scheduler/Scheduler.c |  | ||||||
|  * |  | ||||||
|  *  \section Module Description |  | ||||||
|  *  Simple round-robbin cooperative scheduler for use in basic projects where non real-time tasks need |  | ||||||
|  *  to be executed. Each task is executed in sequence, and can be enabled or disabled individually or as a group. |  | ||||||
|  * |  | ||||||
|  *  For a task to yield it must return, thus each task should have persistent data marked with the static attribute. |  | ||||||
|  * |  | ||||||
|  *  Usage Example: |  | ||||||
|  *  \code |  | ||||||
|  *      #include <LUFA/Scheduler/Scheduler.h> |  | ||||||
|  *       |  | ||||||
|  *      TASK(MyTask1); |  | ||||||
|  *      TASK(MyTask2); |  | ||||||
|  *       |  | ||||||
|  *      TASK_LIST |  | ||||||
|  *      { |  | ||||||
|  *      	{ .Task = MyTask1, .TaskStatus = TASK_RUN, .GroupID = 1  }, |  | ||||||
|  *      	{ .Task = MyTask2, .TaskStatus = TASK_RUN, .GroupID = 1  }, |  | ||||||
|  *      } |  | ||||||
|  * |  | ||||||
|  *      int main(void) |  | ||||||
|  *      { |  | ||||||
|  *      	Scheduler_Start(); |  | ||||||
|  *      } |  | ||||||
|  * |  | ||||||
|  *      TASK(MyTask1) |  | ||||||
|  *      { |  | ||||||
|  *      	// Implementation Here
 |  | ||||||
|  *      } |  | ||||||
|  * |  | ||||||
|  *      TASK(MyTask2) |  | ||||||
|  *      { |  | ||||||
|  *      	// Implementation Here
 |  | ||||||
|  *      } |  | ||||||
|  *  \endcode |  | ||||||
|  * |  | ||||||
|  *  @{ |  | ||||||
|  */ |  | ||||||
|   |  | ||||||
| #ifndef __SCHEDULER_H__ |  | ||||||
| #define __SCHEDULER_H__ |  | ||||||
| 
 |  | ||||||
| 	/* Includes: */ |  | ||||||
| 		#include <avr/io.h> |  | ||||||
| 		#include <stdbool.h> |  | ||||||
| 		 |  | ||||||
| 		#include <util/atomic.h> |  | ||||||
| 
 |  | ||||||
| 		#include "../Common/Common.h" |  | ||||||
| 
 |  | ||||||
| 	/* Enable C linkage for C++ Compilers: */ |  | ||||||
| 		#if defined(__cplusplus) |  | ||||||
| 			extern "C" { |  | ||||||
| 		#endif |  | ||||||
| 
 |  | ||||||
| 	/* Public Interface - May be used in end-application: */ |  | ||||||
| 		/* Macros: */ |  | ||||||
| 			/** Creates a new scheduler task body or prototype. Should be used in the form:
 |  | ||||||
| 			 *  \code |  | ||||||
| 			 *      TASK(TaskName); // Prototype
 |  | ||||||
| 			 * |  | ||||||
| 			 *      TASK(TaskName) |  | ||||||
| 			 *      { |  | ||||||
| 			 *           // Task body
 |  | ||||||
| 			 *      } |  | ||||||
| 			 *  \endcode |  | ||||||
| 			 */ |  | ||||||
| 			#define TASK(name)                        void name (void) |  | ||||||
| 			 |  | ||||||
| 			/** Defines a task list array, containing one or more task entries of the type TaskEntry_t. Each task list
 |  | ||||||
| 			 *  should be encased in curly braces and ended with a comma. |  | ||||||
| 			 * |  | ||||||
| 			 *  Usage Example: |  | ||||||
| 			 *  \code |  | ||||||
| 			 *      TASK_LIST |  | ||||||
| 			 *      { |  | ||||||
| 			 *           { .Task = MyTask1, .TaskStatus = TASK_RUN, .GroupID = 1 }, |  | ||||||
| 			 *           // More task entries here
 |  | ||||||
| 			 *      } |  | ||||||
| 			 *  \endcode |  | ||||||
| 			 */ |  | ||||||
| 			#define TASK_LIST                         TaskEntry_t Scheduler_TaskList[] =  |  | ||||||
| 			 |  | ||||||
| 			/** Constant, giving the maximum delay in scheduler ticks which can be stored in a variable of type
 |  | ||||||
| 			 *  SchedulerDelayCounter_t. |  | ||||||
| 			 */ |  | ||||||
| 			#define TASK_MAX_DELAY                    (MAX_DELAYCTR_COUNT - 1) |  | ||||||
| 
 |  | ||||||
| 			/** Task status mode constant, for passing to Scheduler_SetTaskMode() or Scheduler_SetGroupTaskMode(). */ |  | ||||||
| 			#define TASK_RUN                          true |  | ||||||
| 
 |  | ||||||
| 			/** Task status mode constant, for passing to Scheduler_SetTaskMode() or Scheduler_SetGroupTaskMode(). */ |  | ||||||
| 			#define TASK_STOP                         false |  | ||||||
| 			 |  | ||||||
| 		/* Pseudo-Function Macros: */ |  | ||||||
| 			#if defined(__DOXYGEN__) |  | ||||||
| 				/** Starts the scheduler in its infinite loop, executing running tasks. This should be placed at the end
 |  | ||||||
| 				 *  of the user application's main() function, as it can never return to the calling function. |  | ||||||
| 				 */ |  | ||||||
| 				void Scheduler_Start(void); |  | ||||||
| 				 |  | ||||||
| 				/** Initializes the scheduler so that the scheduler functions can be called before the scheduler itself
 |  | ||||||
| 				 *  is started. This must be executed before any scheduler function calls other than Scheduler_Start(), |  | ||||||
| 				 *  and can be omitted if no such functions could be called before the scheduler is started. |  | ||||||
| 				 */ |  | ||||||
| 				void Scheduler_Init(void); |  | ||||||
| 			#else |  | ||||||
| 				#define Scheduler_Start()                 Scheduler_GoSchedule(TOTAL_TASKS); |  | ||||||
| 				 |  | ||||||
| 				#define Scheduler_Init()                  Scheduler_InitScheduler(TOTAL_TASKS); |  | ||||||
| 			#endif |  | ||||||
| 
 |  | ||||||
| 		/* Type Defines: */ |  | ||||||
| 			/** Type define for a pointer to a scheduler task. */ |  | ||||||
| 			typedef void (*TaskPtr_t)(void); |  | ||||||
| 			 |  | ||||||
| 			/** Type define for a variable which can hold a tick delay value for the scheduler up to the maximum delay
 |  | ||||||
| 			 *  possible. |  | ||||||
| 			 */ |  | ||||||
| 			typedef uint16_t SchedulerDelayCounter_t; |  | ||||||
| 			 |  | ||||||
| 			/** Structure for holding a single task's information in the scheduler task list. */ |  | ||||||
| 			typedef struct |  | ||||||
| 			{ |  | ||||||
| 				TaskPtr_t Task;       /**< Pointer to the task to execute. */ |  | ||||||
| 				bool      TaskStatus; /**< Status of the task (either TASK_RUN or TASK_STOP). */ |  | ||||||
| 				uint8_t   GroupID;    /**< Group ID of the task so that its status can be changed as a group. */ |  | ||||||
| 			} TaskEntry_t;			 |  | ||||||
| 
 |  | ||||||
| 		/* Global Variables: */ |  | ||||||
| 			/** Task entry list, containing the scheduler tasks, task statuses and group IDs. Each entry is of type
 |  | ||||||
| 			 *  TaskEntry_t and can be manipulated as desired, although it is preferential that the proper Scheduler |  | ||||||
| 			 *  functions should be used instead of direct manipulation. |  | ||||||
| 			 */ |  | ||||||
| 			extern          TaskEntry_t               Scheduler_TaskList[]; |  | ||||||
| 			 |  | ||||||
| 			/** Contains the total number of tasks in the task list, irrespective of if the task's status is set to
 |  | ||||||
| 			 *  TASK_RUN or TASK_STOP. |  | ||||||
| 			 * |  | ||||||
| 			 *  \note This value should be treated as read-only, and never altered in user-code. |  | ||||||
| 			 */ |  | ||||||
| 			extern volatile uint8_t                   Scheduler_TotalTasks; |  | ||||||
| 
 |  | ||||||
| 			/**  Contains the current scheduler tick count, for use with the delay functions. If the delay functions
 |  | ||||||
| 			 *   are used in the user code, this should be incremented each tick period so that the delays can be |  | ||||||
| 			 *   calculated. |  | ||||||
| 			 */ |  | ||||||
| 			extern volatile SchedulerDelayCounter_t   Scheduler_TickCounter; |  | ||||||
| 
 |  | ||||||
| 		/* Inline Functions: */ |  | ||||||
| 			/** Resets the delay counter value to the current tick count. This should be called to reset the period
 |  | ||||||
| 			 *  for a delay in a task which is dependant on the current tick value. |  | ||||||
| 			 * |  | ||||||
| 			 *  \param DelayCounter  Counter which is storing the starting tick count for a given delay. |  | ||||||
| 			 */ |  | ||||||
| 			static inline void Scheduler_ResetDelay(SchedulerDelayCounter_t* const DelayCounter) |  | ||||||
| 			                                        ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; |  | ||||||
| 			static inline void Scheduler_ResetDelay(SchedulerDelayCounter_t* const DelayCounter) |  | ||||||
| 			{ |  | ||||||
| 				ATOMIC_BLOCK(ATOMIC_RESTORESTATE) |  | ||||||
| 				{ |  | ||||||
| 					*DelayCounter = Scheduler_TickCounter; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		 |  | ||||||
| 		/* Function Prototypes: */ |  | ||||||
| 			/** Determines if the given tick delay has elapsed, based on the given .
 |  | ||||||
| 			 * |  | ||||||
| 			 *  \param Delay         The delay to test for, measured in ticks |  | ||||||
| 			 *  \param DelayCounter  The counter which is storing the starting tick value for the delay |  | ||||||
| 			 * |  | ||||||
| 			 *  \return Boolean true if the delay has elapsed, false otherwise |  | ||||||
| 			 * |  | ||||||
| 			 *  Usage Example: |  | ||||||
| 			 *  \code |  | ||||||
| 			 *      static SchedulerDelayCounter_t DelayCounter = 10000; // Force immediate run on start-up
 |  | ||||||
| 			 *				  |  | ||||||
| 			 *      // Task runs every 10000 ticks, 10 seconds for this demo
 |  | ||||||
| 			 *      if (Scheduler_HasDelayElapsed(10000, &DelayCounter)) |  | ||||||
| 			 *      { |  | ||||||
| 			 *           // Code to execute after delay interval elapsed here
 |  | ||||||
| 			 *      } |  | ||||||
| 			 *  \endcode |  | ||||||
| 			 */ |  | ||||||
| 			bool Scheduler_HasDelayElapsed(const uint16_t Delay, |  | ||||||
| 			                               SchedulerDelayCounter_t* const DelayCounter) |  | ||||||
| 										   ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(2); |  | ||||||
| 			 |  | ||||||
| 			/** Sets the task mode for a given task.
 |  | ||||||
| 			 * |  | ||||||
| 			 *  \param Task        Name of the task whose status is to be changed |  | ||||||
| 			 *  \param TaskStatus  New task status for the task (TASK_RUN or TASK_STOP) |  | ||||||
| 			 */ |  | ||||||
| 			void Scheduler_SetTaskMode(const TaskPtr_t Task, const bool TaskStatus); |  | ||||||
| 			 |  | ||||||
| 			/** Sets the task mode for a given task group ID, allowing for an entire group of tasks to have their
 |  | ||||||
| 			 *  statuses changed at once. |  | ||||||
| 			 * |  | ||||||
| 			 *  \param GroupID     Value of the task group ID whose status is to be changed |  | ||||||
| 			 *  \param TaskStatus  New task status for tasks in the specified group (TASK_RUN or TASK_STOP) |  | ||||||
| 			 */ |  | ||||||
| 			void Scheduler_SetGroupTaskMode(const uint8_t GroupID, const bool TaskStatus); |  | ||||||
| 
 |  | ||||||
| 	/* Private Interface - For use in library only: */		 |  | ||||||
| 	#if !defined(__DOXYGEN__) |  | ||||||
| 		/* Macros: */ |  | ||||||
| 			#define TOTAL_TASKS                       (sizeof(Scheduler_TaskList) / sizeof(TaskEntry_t)) |  | ||||||
| 			#define MAX_DELAYCTR_COUNT                0xFFFF |  | ||||||
| 
 |  | ||||||
| 		/* Inline Functions: */ |  | ||||||
| 			static inline void Scheduler_InitScheduler(const uint8_t TotalTasks) ATTR_ALWAYS_INLINE; |  | ||||||
| 			static inline void Scheduler_InitScheduler(const uint8_t TotalTasks) |  | ||||||
| 			{ |  | ||||||
| 				Scheduler_TotalTasks = TotalTasks; |  | ||||||
| 			} |  | ||||||
| 		 |  | ||||||
| 			static inline void Scheduler_GoSchedule(const uint8_t TotalTasks) ATTR_NO_RETURN ATTR_ALWAYS_INLINE; |  | ||||||
| 			static inline void Scheduler_GoSchedule(const uint8_t TotalTasks) |  | ||||||
| 			{ |  | ||||||
| 				Scheduler_InitScheduler(TotalTasks); |  | ||||||
| 
 |  | ||||||
| 				for (;;) |  | ||||||
| 				{ |  | ||||||
| 					TaskEntry_t* CurrTask = &Scheduler_TaskList[0]; |  | ||||||
| 					 |  | ||||||
| 					while (CurrTask != &Scheduler_TaskList[TotalTasks]) |  | ||||||
| 					{ |  | ||||||
| 						if (CurrTask->TaskStatus == TASK_RUN) |  | ||||||
| 						  CurrTask->Task(); |  | ||||||
| 
 |  | ||||||
| 						CurrTask++; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 	#endif |  | ||||||
| 		 |  | ||||||
| 	/* Disable C linkage for C++ Compilers: */ |  | ||||||
| 		#if defined(__cplusplus) |  | ||||||
| 			} |  | ||||||
| 		#endif |  | ||||||
| 		 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /** @} */ |  | ||||||
| @ -1,31 +0,0 @@ | |||||||
| /** \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. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| /** \page Page_SchedulerOverview LUFA Scheduler Overview |  | ||||||
|  * |  | ||||||
|  *  The LUFA library comes with a small, basic round-robbin scheduler which allows for small "tasks" to be executed |  | ||||||
|  *  continuously in sequence, and enabled/disabled at runtime. Unlike a conventional, complex RTOS scheduler, the |  | ||||||
|  *  LUFA scheduler is very simple in design and operation and is essentially a loop conditionally executing a series |  | ||||||
|  *  of functions. |  | ||||||
|  * |  | ||||||
|  *  Each LUFA scheduler task should be written similar to an ISR; it should execute quickly (so that no one task |  | ||||||
|  *  hogs the processor, preventing another from running before some sort of timeout is exceeded). Unlike normal RTOS |  | ||||||
|  *  tasks, each LUFA scheduler task is a regular function, and thus must be designed to be called, and designed to |  | ||||||
|  *  return to the calling scheduler function repeatedly. Data which must be preserved between task calls should be |  | ||||||
|  *  declared as global or (preferably) as a static local variable inside the task. |  | ||||||
|  * |  | ||||||
|  *  The scheduler consists of a task list, listing all the tasks which can be executed by the scheduler. Once started, |  | ||||||
|  *  each task is then called one after another, unless the task is stopped by another running task or interrupt. |  | ||||||
|  * |  | ||||||
|  * |  | ||||||
|  *  If desired, the LUFA scheduler <b>does not need to be used</b> in a LUFA powered application. A more conventional |  | ||||||
|  *  approach to application design can be used, or a proper scheduling RTOS inserted in the place of the LUFA scheduler. |  | ||||||
|  *  In the case of the former the USB task must be run manually repeatedly to maintain USB communications, and in the |  | ||||||
|  *  case of the latter a proper RTOS task must be set up to do the same. |  | ||||||
|  * |  | ||||||
|  * |  | ||||||
|  *  For more information on the LUFA scheduler, see the Scheduler.h file documentation. |  | ||||||
|  */ |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dean Camera
						Dean Camera