diff --git a/Bootloaders/CDC/makefile b/Bootloaders/CDC/makefile index bc8e2ca1ae..e3d8e5c513 100644 --- a/Bootloaders/CDC/makefile +++ b/Bootloaders/CDC/makefile @@ -124,7 +124,6 @@ SRC = $(TARGET).c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.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.) diff --git a/Bootloaders/DFU/makefile b/Bootloaders/DFU/makefile index 4e51e299c6..b3eb1b0a1d 100644 --- a/Bootloaders/DFU/makefile +++ b/Bootloaders/DFU/makefile @@ -124,7 +124,6 @@ SRC = $(TARGET).c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.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.) diff --git a/Bootloaders/TeensyHID/makefile b/Bootloaders/TeensyHID/makefile index de929edfb8..68b0160221 100644 --- a/Bootloaders/TeensyHID/makefile +++ b/Bootloaders/TeensyHID/makefile @@ -124,7 +124,6 @@ SRC = $(TARGET).c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.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.) diff --git a/Demos/Device/AudioInput/AudioInput.c b/Demos/Device/AudioInput/AudioInput.c index ecd8cdda8b..bcfb04be1b 100644 --- a/Demos/Device/AudioInput/AudioInput.c +++ b/Demos/Device/AudioInput/AudioInput.c @@ -28,26 +28,32 @@ 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" -/* Scheduler Task List */ -TASK_LIST +USB_ClassInfo_Audio_t Microphone_Audio_Interface = + { + .InterfaceNumber = 0, + + .DataINEndpointNumber = AUDIO_STREAM_EPNUM, + .DataINEndpointSize = AUDIO_STREAM_EPSIZE, + }; + +int main(void) { - { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, - { .Task = USB_Audio_Task , .TaskStatus = TASK_STOP }, -}; + SetupHardware(); + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); + + for (;;) + { + if (Microphone_Audio_Interface.InterfaceEnabled) + ProcessNextSample(); -/** 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) + USB_USBTask(); + } +} + +void SetupHardware(void) { /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); @@ -58,35 +64,35 @@ int main(void) /* Hardware Initialization */ LEDs_Init(); + USB_Init(); ADC_Init(ADC_FREE_RUNNING | ADC_PRESCALE_32); ADC_SetupChannel(MIC_IN_ADC_CHANNEL); /* Start the ADC conversion in free running mode */ 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(); +void ProcessNextSample(void) +{ + if ((TIFR0 & (1 << OCF0A)) && USB_Audio_IsReadyForNextSample(&Microphone_Audio_Interface)) + { + TIFR0 |= (1 << OCF0A); + + /* Audio sample is ADC value scaled to fit the entire range */ + int16_t AudioSample = ((SAMPLE_MAX_RANGE / ADC_MAX_RANGE) * ADC_GetResult()); + +#if defined(MICROPHONE_BIASED_TO_HALF_RAIL) + /* Microphone is biased to half rail voltage, subtract the bias from the sample value */ + AudioSample -= (SAMPLE_MAX_RANGE / 2)); +#endif - /* Scheduling - routine never returns, so put this last in the main function */ - Scheduler_Start(); + USB_Audio_WriteSample16(AudioSample); + } } -/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs, and - * configures the sample update and PWM timers. - */ void EVENT_USB_Connect(void) { - /* Start USB management task */ - Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); - - /* Indicate USB enumerating */ - UpdateStatus(Status_USBEnumerating); + LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); /* Sample reload timer initialization */ OCR0A = (F_CPU / AUDIO_SAMPLE_FREQUENCY) - 1; @@ -94,127 +100,23 @@ void EVENT_USB_Connect(void) 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); + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); } -/** 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; + LEDs_SetAllLEDs(LEDMASK_USB_READY); - /* 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); + if (!(USB_Audio_ConfigureEndpoints(&Microphone_Audio_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); } -/** Task to manage the Audio interface, reading in ADC samples from the microphone, and them to the host. */ -TASK(USB_Audio_Task) +void EVENT_USB_UnhandledControlPacket(void) { - /* 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); - - /* Audio sample is ADC value scaled to fit the entire range */ - int16_t AudioSample = ((SAMPLE_MAX_RANGE / ADC_MAX_RANGE) * ADC_GetResult()); - -#if defined(MICROPHONE_BIASED_TO_HALF_RAIL) - /* Microphone is biased to half rail voltage, subtract the bias from the sample value */ - AudioSample -= (SAMPLE_MAX_RANGE / 2)); -#endif - - /* Write the sample to the buffer */ - 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(); - } - } + USB_Audio_ProcessControlPacket(&Microphone_Audio_Interface); } diff --git a/Demos/Device/AudioInput/AudioInput.h b/Demos/Device/AudioInput/AudioInput.h index a394492f08..e9f56b30a6 100644 --- a/Demos/Device/AudioInput/AudioInput.h +++ b/Demos/Device/AudioInput/AudioInput.h @@ -43,12 +43,13 @@ #include "Descriptors.h" - #include // Library Version Information - #include // USB Functionality - #include // LEDs driver - #include // ADC driver - #include // Simple scheduler for task management - + #include + #include + #include + #include + #include + #include + /* Macros: */ /** ADC channel number for the microphone input. */ #define MIC_IN_ADC_CHANNEL 2 @@ -59,24 +60,19 @@ /** Maximum ADC range for the microphone input. */ #define ADC_MAX_RANGE 0x3FF - /* Enums: */ - /** Enum for the possible status codes for passing to the UpdateStatus() function. */ - enum AudioInput_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_Audio_Task); - + /* Macros: */ + #define LEDMASK_USB_NOTREADY LEDS_LED1 + #define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3) + #define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4) + #define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3) + /* Function Prototypes: */ + void SetupHardware(void); + void ProcessNextSample(void); + void EVENT_USB_Connect(void); void EVENT_USB_Disconnect(void); void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_UnhandledControlPacket(void); - void UpdateStatus(uint8_t CurrentStatus); - #endif diff --git a/Demos/Device/AudioInput/makefile b/Demos/Device/AudioInput/makefile index c70e98e04d..9d3adff69c 100644 --- a/Demos/Device/AudioInput/makefile +++ b/Demos/Device/AudioInput/makefile @@ -125,7 +125,6 @@ LUFA_PATH = ../../.. # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c \ Descriptors.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.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/USBTask.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.) diff --git a/Demos/Device/AudioOutput/AudioOutput.c b/Demos/Device/AudioOutput/AudioOutput.c index 40e376b52f..0f193567a3 100644 --- a/Demos/Device/AudioOutput/AudioOutput.c +++ b/Demos/Device/AudioOutput/AudioOutput.c @@ -28,26 +28,32 @@ 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" -/* Scheduler Task List */ -TASK_LIST -{ - { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, - { .Task = USB_Audio_Task , .TaskStatus = TASK_STOP }, -}; +USB_ClassInfo_Audio_t Speaker_Audio_Interface = + { + .InterfaceNumber = 0, + .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) +{ + 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 */ MCUSR &= ~(1 << WDRF); @@ -58,186 +64,19 @@ int main(void) /* Hardware Initialization */ LEDs_Init(); - - /* 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 - * configures the sample update and PWM timers. - */ -void EVENT_USB_Connect(void) -{ - /* Start USB management task */ - 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) +void ProcessNextSample(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))) + if ((TIFR0 & (1 << OCF0A)) && USB_Audio_IsSampleReceived(&Speaker_Audio_Interface)) { /* Clear the sample reload timer */ TIFR0 |= (1 << OCF0A); /* Retrieve the signed 16-bit left and right audio samples */ - int16_t LeftSample_16Bit = (int16_t)Endpoint_Read_Word_LE(); - int16_t RightSample_16Bit = (int16_t)Endpoint_Read_Word_LE(); - - /* 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(); - } + int16_t LeftSample_16Bit = (int16_t)USB_Audio_ReadSample16(); + int16_t RightSample_16Bit = (int16_t)USB_Audio_ReadSample16(); /* Massage signed 16-bit left and right audio samples into signed 8-bit */ int8_t LeftSample_8Bit = (LeftSample_16Bit >> 8); @@ -289,3 +128,69 @@ TASK(USB_Audio_Task) #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); +} diff --git a/Demos/Device/AudioOutput/AudioOutput.h b/Demos/Device/AudioOutput/AudioOutput.h index d8725a07b3..7d112db88a 100644 --- a/Demos/Device/AudioOutput/AudioOutput.h +++ b/Demos/Device/AudioOutput/AudioOutput.h @@ -43,10 +43,12 @@ #include "Descriptors.h" - #include // Library Version Information - #include // USB Functionality - #include // LEDs driver - #include // Simple scheduler for task management + #include + #include + #include + #include + #include + #include /* Macros: */ #if defined(USB_FULL_CONTROLLER) || defined(USB_MODIFIED_FULL_CONTROLLER) @@ -96,24 +98,19 @@ #define CSx0 CS10 #endif - /* Enums: */ - /** Enum for the possible status codes for passing to the UpdateStatus() function. */ - enum AudioOutput_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_Audio_Task); - + /* Macros: */ + #define LEDMASK_USB_NOTREADY LEDS_LED1 + #define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3) + #define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4) + #define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3) + /* Function Prototypes: */ + void SetupHardware(void); + void ProcessNextSample(void); + void EVENT_USB_Connect(void); void EVENT_USB_Disconnect(void); void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_UnhandledControlPacket(void); - - void UpdateStatus(uint8_t CurrentStatus); #endif diff --git a/Demos/Device/AudioOutput/makefile b/Demos/Device/AudioOutput/makefile index 28f038f493..8ad1def4d0 100644 --- a/Demos/Device/AudioOutput/makefile +++ b/Demos/Device/AudioOutput/makefile @@ -125,7 +125,6 @@ LUFA_PATH = ../../.. # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c \ Descriptors.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.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/USBTask.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.) @@ -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 += -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 += -DAUDIO_OUT_STEREO +CDEFS += -DAUDIO_OUT_MONO # Place -D or -U options here for ASM sources ADEFS = -DF_CPU=$(F_CPU) diff --git a/Demos/Device/CDC/CDC.c b/Demos/Device/CDC/CDC.c index d7ebb9e6b2..e6bc1a455f 100644 --- a/Demos/Device/CDC/CDC.c +++ b/Demos/Device/CDC/CDC.c @@ -28,54 +28,42 @@ 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" -/* Scheduler Task List */ -TASK_LIST -{ - { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, - { .Task = CDC_Task , .TaskStatus = TASK_STOP }, -}; +USB_ClassInfo_CDC_t VirtualSerial_CDC_Interface = + { + .ControlInterfaceNumber = 0, -/* Globals: */ -/** Contains the current baud rate and other settings of the virtual serial port. While this demo does not use - * 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 }; + .DataINEndpointNumber = CDC_TX_EPNUM, + .DataINEndpointSize = CDC_TXRX_EPSIZE, -/** String to print through the virtual serial port when the joystick is pressed upwards. */ -char JoystickUpString[] = "Joystick Up\r\n"; + .DataOUTEndpointNumber = CDC_RX_EPNUM, + .DataOUTEndpointSize = CDC_TXRX_EPSIZE, -/** String to print through the virtual serial port when the joystick is pressed downward. */ -char JoystickDownString[] = "Joystick Down\r\n"; + .NotificationEndpointNumber = CDC_NOTIFICATION_EPNUM, + .NotificationEndpointSize = CDC_NOTIFICATION_EPSIZE, + }; -/** String to print through the virtual serial port when the joystick is pressed left. */ -char JoystickLeftString[] = "Joystick Left\r\n"; +int main(void) +{ + SetupHardware(); + + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); -/** String to print through the virtual serial port when the joystick is pressed right. */ -char JoystickRightString[] = "Joystick Right\r\n"; + for (;;) + { + CheckJoystickMovement(); + + uint16_t BytesToDiscard = USB_CDC_BytesReceived(&VirtualSerial_CDC_Interface); + while (BytesToDiscard--) + USB_CDC_ReceiveByte(&VirtualSerial_CDC_Interface); -/** String to print through the virtual serial port when the joystick is pressed inwards. */ -char JoystickPressedString[] = "Joystick Pressed\r\n"; + USB_CDC_USBTask(&VirtualSerial_CDC_Interface); + USB_USBTask(); + } +} -/** 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) +void SetupHardware(void) { /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); @@ -87,235 +75,64 @@ int main(void) /* Hardware Initialization */ Joystick_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(); - - /* 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) -{ - /* Start USB management task */ - Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); - - /* Indicate USB enumerating */ - UpdateStatus(Status_USBEnumerating); -} - -/** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via - * the status LEDs and stops the USB management and CDC management tasks. - */ -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) +void CheckJoystickMovement(void) { - 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; - } + uint8_t JoyStatus_LCL = Joystick_GetStatus(); + char* ReportString = NULL; + static bool ActionSent = false; - /* 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) + char* JoystickStrings[] = { - .NotificationType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), - .Notification = NOTIF_SerialState, - .wValue = 0, - .wIndex = 0, - .wLength = sizeof(uint16_t), + "Joystick Up\r\n", + "Joystick Down\r\n", + "Joystick Left\r\n", + "Joystick Right\r\n", + "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) - ReportString = JoystickUpString; + ReportString = JoystickStrings[0]; else if (JoyStatus_LCL & JOY_DOWN) - ReportString = JoystickDownString; + ReportString = JoystickStrings[1]; else if (JoyStatus_LCL & JOY_LEFT) - ReportString = JoystickLeftString; + ReportString = JoystickStrings[2]; else if (JoyStatus_LCL & JOY_RIGHT) - ReportString = JoystickRightString; + ReportString = JoystickStrings[3]; else if (JoyStatus_LCL & JOY_PRESS) - ReportString = JoystickPressedString; - - /* Flag management - Only allow one string to be sent per action */ - if (ReportString == NULL) - { - ActionSent = false; - } - else if (ActionSent == false) + ReportString = JoystickStrings[4]; + else + ActionSent = false; + + if ((ReportString != NULL) && (ActionSent == false)) { ActionSent = true; + + USB_CDC_SendString(&VirtualSerial_CDC_Interface, ReportString, strlen(ReportString)); + } +} - /* Select the Serial Tx Endpoint */ - Endpoint_SelectEndpoint(CDC_TX_EPNUM); +void EVENT_USB_Connect(void) +{ + LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); +} - /* 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); +void EVENT_USB_Disconnect(void) +{ + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); +} - /* Finalize the stream transfer to send the last packet */ - Endpoint_ClearIN(); +void EVENT_USB_ConfigurationChanged(void) +{ + LEDs_SetAllLEDs(LEDMASK_USB_READY); - /* 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(); - } - } + if (!(USB_CDC_ConfigureEndpoints(&VirtualSerial_CDC_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); +} - /* Select the Serial Rx Endpoint */ - Endpoint_SelectEndpoint(CDC_RX_EPNUM); - - /* Throw away any received data from the host */ - if (Endpoint_IsOUTReceived()) - Endpoint_ClearOUT(); +void EVENT_USB_UnhandledControlPacket(void) +{ + USB_CDC_ProcessControlPacket(&VirtualSerial_CDC_Interface); } diff --git a/Demos/Device/CDC/CDC.h b/Demos/Device/CDC/CDC.h index 4c4ca74d56..b487813b08 100644 --- a/Demos/Device/CDC/CDC.h +++ b/Demos/Device/CDC/CDC.h @@ -44,139 +44,26 @@ #include "Descriptors.h" - #include // Library Version Information - #include // USB Functionality - #include // Joystick driver - #include // LEDs driver - #include // Simple scheduler for task management + #include + #include + #include + #include + #include /* 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) - - /* 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 */ - }; + #define LEDMASK_USB_NOTREADY LEDS_LED1 + #define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3) + #define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4) + #define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3) - /** 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: */ + void SetupHardware(void); + void CheckJoystickMovement(void); + void EVENT_USB_Connect(void); void EVENT_USB_Disconnect(void); void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_UnhandledControlPacket(void); - - void UpdateStatus(uint8_t CurrentStatus); + void EVENT_USB_StartOfFrame(void); #endif diff --git a/Demos/Device/CDC/Descriptors.h b/Demos/Device/CDC/Descriptors.h index 41b44300ac..1a9dbb5bff 100644 --- a/Demos/Device/CDC/Descriptors.h +++ b/Demos/Device/CDC/Descriptors.h @@ -37,26 +37,12 @@ #define _DESCRIPTORS_H_ /* Includes: */ - #include - #include - /* Macros: */ - /** Macro to define a CDC class-specific functional descriptor. CDC functional descriptors have a - * uniform structure but variable sized data payloads, thus cannot be represented accurately by - * a single typedef struct. A macro is used instead so that functional descriptors can be created - * easily by specifying the size of the payload. This allows sizeof() to work correctly. - * - * \param DataSize Size in bytes of the CDC functional descriptor's data payload - */ - #define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \ - struct \ - { \ - USB_Descriptor_Header_t Header; \ - uint8_t SubType; \ - uint8_t Data[DataSize]; \ - } - + #include + #include + + /* Macros: */ /** Endpoint number of the CDC device-to-host notification IN endpoint. */ #define CDC_NOTIFICATION_EPNUM 2 diff --git a/Demos/Device/CDC/makefile b/Demos/Device/CDC/makefile index bc22be5c0a..bd4ff36b96 100644 --- a/Demos/Device/CDC/makefile +++ b/Demos/Device/CDC/makefile @@ -125,7 +125,6 @@ LUFA_PATH = ../../.. # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c \ Descriptors.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.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/USBTask.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.) @@ -183,7 +182,7 @@ CSTANDARD = -std=gnu99 # Place -D or -U options here for C sources 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 += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" diff --git a/Demos/Device/DualCDC/Descriptors.h b/Demos/Device/DualCDC/Descriptors.h index 2c2311b9ca..97165e5ded 100644 --- a/Demos/Device/DualCDC/Descriptors.h +++ b/Demos/Device/DualCDC/Descriptors.h @@ -37,26 +37,12 @@ #define _DESCRIPTORS_H_ /* Includes: */ - #include - #include - /* Macros: */ - /** Macro to define a CDC class-specific functional descriptor. CDC functional descriptors have a - * uniform structure but variable sized data payloads, thus cannot be represented accurately by - * a single typedef struct. A macro is used instead so that functional descriptors can be created - * easily by specifying the size of the payload. This allows sizeof() to work correctly. - * - * \param DataSize Size in bytes of the CDC functional descriptor's data payload - */ - #define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \ - struct \ - { \ - USB_Descriptor_Header_t Header; \ - uint8_t SubType; \ - uint8_t Data[DataSize]; \ - } + #include + #include + /* Macros: */ /** Endpoint number of the first CDC interface's device-to-host notification IN endpoint. */ #define CDC1_NOTIFICATION_EPNUM 3 diff --git a/Demos/Device/DualCDC/DualCDC.c b/Demos/Device/DualCDC/DualCDC.c index 34d772ff07..26947f433f 100644 --- a/Demos/Device/DualCDC/DualCDC.c +++ b/Demos/Device/DualCDC/DualCDC.c @@ -27,69 +27,62 @@ arising out of or in connection with the use or performance of 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" -/* Scheduler Task List */ -TASK_LIST -{ - { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, - { .Task = CDC1_Task , .TaskStatus = TASK_STOP }, - { .Task = CDC2_Task , .TaskStatus = TASK_STOP }, -}; +USB_ClassInfo_CDC_t VirtualSerial1_CDC_Interface = + { + .ControlInterfaceNumber = 0, -/* Globals: */ -/** Contains the current baud rate and other settings of the first virtual serial port. While this demo does not use - * 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 }; + .DataINEndpointNumber = CDC1_TX_EPNUM, + .DataINEndpointSize = CDC_TXRX_EPSIZE, -/** Contains the current baud rate and other settings of the second virtual serial port. While this demo does not use - * 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 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. */ -char JoystickUpString[] = "Joystick Up\r\n"; + .DataOUTEndpointNumber = CDC1_RX_EPNUM, + .DataOUTEndpointSize = CDC_TXRX_EPSIZE, -/** String to print through the first virtual serial port when the joystick is pressed downward. */ -char JoystickDownString[] = "Joystick Down\r\n"; + .NotificationEndpointNumber = CDC1_NOTIFICATION_EPNUM, + .NotificationEndpointSize = CDC_NOTIFICATION_EPSIZE, + }; + +USB_ClassInfo_CDC_t VirtualSerial2_CDC_Interface = + { + .ControlInterfaceNumber = 0, -/** String to print through the first virtual serial port when the joystick is pressed left. */ -char JoystickLeftString[] = "Joystick Left\r\n"; + .DataINEndpointNumber = CDC2_TX_EPNUM, + .DataINEndpointSize = CDC_TXRX_EPSIZE, -/** String to print through the first virtual serial port when the joystick is pressed right. */ -char JoystickRightString[] = "Joystick Right\r\n"; + .DataOUTEndpointNumber = CDC2_RX_EPNUM, + .DataOUTEndpointSize = CDC_TXRX_EPSIZE, -/** String to print through the first virtual serial port when the joystick is pressed inwards. */ -char JoystickPressedString[] = "Joystick Pressed\r\n"; + .NotificationEndpointNumber = CDC2_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) +{ + 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 */ MCUSR &= ~(1 << WDRF); @@ -101,257 +94,68 @@ int main(void) /* Hardware Initialization */ Joystick_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(); - - /* 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) -{ - /* Start USB management task */ - Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); - - /* Indicate USB enumerating */ - UpdateStatus(Status_USBEnumerating); -} - -/** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via - * the status LEDs and stops the USB management and CDC management tasks. - */ -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) +void CheckJoystickMovement(void) { - char* ReportString = NULL; - uint8_t JoyStatus_LCL = Joystick_GetStatus(); - static bool ActionSent = false; + uint8_t JoyStatus_LCL = Joystick_GetStatus(); + char* ReportString = NULL; + static bool ActionSent = false; + + char* JoystickStrings[] = + { + "Joystick Up\r\n", + "Joystick Down\r\n", + "Joystick Left\r\n", + "Joystick Right\r\n", + "Joystick Pressed\r\n", + }; - /* Determine if a joystick action has occurred */ if (JoyStatus_LCL & JOY_UP) - ReportString = JoystickUpString; + ReportString = JoystickStrings[0]; else if (JoyStatus_LCL & JOY_DOWN) - ReportString = JoystickDownString; + ReportString = JoystickStrings[1]; else if (JoyStatus_LCL & JOY_LEFT) - ReportString = JoystickLeftString; + ReportString = JoystickStrings[2]; else if (JoyStatus_LCL & JOY_RIGHT) - ReportString = JoystickRightString; + ReportString = JoystickStrings[3]; else if (JoyStatus_LCL & JOY_PRESS) - ReportString = JoystickPressedString; - - /* Flag management - Only allow one string to be sent per action */ - if (ReportString == NULL) - { - ActionSent = false; - } - else if (ActionSent == false) + ReportString = JoystickStrings[4]; + else + ActionSent = false; + + if ((ReportString != NULL) && (ActionSent == false)) { ActionSent = true; - /* Select the Serial Tx Endpoint */ - 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(); + USB_CDC_SendString(&VirtualSerial1_CDC_Interface, ReportString, strlen(ReportString)); } - - /* 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 - * all data sent to it from the host. - */ -TASK(CDC2_Task) +void EVENT_USB_Connect(void) { - /* Select the Serial Rx Endpoint */ - Endpoint_SelectEndpoint(CDC2_RX_EPNUM); - - /* Check to see if any data has been received */ - if (Endpoint_IsOUTReceived()) - { - /* Create a temp buffer big enough to hold the incoming endpoint packet */ - uint8_t Buffer[Endpoint_BytesInEndpoint()]; - - /* Remember how large the incoming packet is */ - uint16_t DataLength = Endpoint_BytesInEndpoint(); - - /* Read in the incoming packet into the buffer */ - Endpoint_Read_Stream_LE(&Buffer, DataLength); + LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); +} - /* Finalize the stream transfer to send the last packet */ - Endpoint_ClearOUT(); +void EVENT_USB_Disconnect(void) +{ + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); +} - /* Select the Serial Tx Endpoint */ - Endpoint_SelectEndpoint(CDC2_TX_EPNUM); - - /* Write the received data to the endpoint */ - Endpoint_Write_Stream_LE(&Buffer, DataLength); +void EVENT_USB_ConfigurationChanged(void) +{ + LEDs_SetAllLEDs(LEDMASK_USB_READY); - /* Finalize the stream transfer to send the last packet */ - Endpoint_ClearIN(); + if (!(USB_CDC_ConfigureEndpoints(&VirtualSerial1_CDC_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); - /* Wait until the endpoint is ready for the next packet */ - while (!(Endpoint_IsINReady())); + if (!(USB_CDC_ConfigureEndpoints(&VirtualSerial2_CDC_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); +} - /* Send an empty packet to prevent host buffering */ - Endpoint_ClearIN(); - } +void EVENT_USB_UnhandledControlPacket(void) +{ + USB_CDC_ProcessControlPacket(&VirtualSerial1_CDC_Interface); + USB_CDC_ProcessControlPacket(&VirtualSerial2_CDC_Interface); } diff --git a/Demos/Device/DualCDC/DualCDC.h b/Demos/Device/DualCDC/DualCDC.h index 117af601e2..3c1e296123 100644 --- a/Demos/Device/DualCDC/DualCDC.h +++ b/Demos/Device/DualCDC/DualCDC.h @@ -44,75 +44,26 @@ #include "Descriptors.h" - #include // Library Version Information - #include // USB Functionality - #include // Joystick driver - #include // LEDs driver - #include // Simple scheduler for task management + #include + #include + #include + #include + #include /* 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 - - /* 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; + #define LEDMASK_USB_NOTREADY LEDS_LED1 + #define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3) + #define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4) + #define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3) - /* 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: */ + void SetupHardware(void); + void CheckJoystickMovement(void); + void EVENT_USB_Connect(void); void EVENT_USB_Disconnect(void); void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_UnhandledControlPacket(void); - - void UpdateStatus(uint8_t CurrentStatus); + void EVENT_USB_StartOfFrame(void); #endif diff --git a/Demos/Device/DualCDC/makefile b/Demos/Device/DualCDC/makefile index 06d0e184bf..5fbda61dd1 100644 --- a/Demos/Device/DualCDC/makefile +++ b/Demos/Device/DualCDC/makefile @@ -125,7 +125,6 @@ LUFA_PATH = ../../.. # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c \ Descriptors.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.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/USBTask.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.) @@ -183,7 +182,7 @@ CSTANDARD = -std=gnu99 # Place -D or -U options here for C sources 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 += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" diff --git a/Demos/Device/GenericHID/Descriptors.h b/Demos/Device/GenericHID/Descriptors.h index 0236870329..bc4c68ae6b 100644 --- a/Demos/Device/GenericHID/Descriptors.h +++ b/Demos/Device/GenericHID/Descriptors.h @@ -37,30 +37,12 @@ #define _DESCRIPTORS_H_ /* Includes: */ - #include - #include - /* 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; + #include + #include + /** Type Defines: */ /** Type define for the device configuration descriptor structure. This must be defined in the * application code, as the configuration descriptor contains several sub-descriptors which * vary between devices, and which describe the device's usage to the host. @@ -73,7 +55,7 @@ USB_Descriptor_Endpoint_t GenericINEndpoint; USB_Descriptor_Endpoint_t GenericOUTEndpoint; } USB_Descriptor_Configuration_t; - + /* Macros: */ /** Endpoint number of the Generic HID reporting IN endpoint. */ #define GENERIC_IN_EPNUM 1 @@ -86,13 +68,7 @@ /** Size in bytes of the Generic HID reports (including report ID byte). */ #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: */ 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); diff --git a/Demos/Device/GenericHID/GenericHID.c b/Demos/Device/GenericHID/GenericHID.c index 058d269fef..4dfb8e4557 100644 --- a/Demos/Device/GenericHID/GenericHID.c +++ b/Demos/Device/GenericHID/GenericHID.c @@ -28,29 +28,37 @@ 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" -/* Scheduler Task List */ -TASK_LIST -{ - { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, - { .Task = USB_HID_Report , .TaskStatus = TASK_STOP }, -}; +USB_ClassInfo_HID_t Generic_HID_Interface = + { + .InterfaceNumber = 0, -/** Static buffer to hold the last received report from the host, so that it can be echoed back in the next sent report */ -static uint8_t LastReceived[GENERIC_REPORT_SIZE]; + .ReportINEndpointNumber = GENERIC_IN_EPNUM, + .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) +{ + 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 */ MCUSR &= ~(1 << WDRF); @@ -61,220 +69,45 @@ int main(void) /* Hardware Initialization */ LEDs_Init(); - - /* Indicate USB not ready */ - UpdateStatus(Status_USBNotReady); - - /* Initialize Scheduler so that it can be used */ - Scheduler_Init(); - - /* Initialize USB Subsystem */ USB_Init(); - - /* Scheduling - routine never returns, so put this last in the main function */ - Scheduler_Start(); } -/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and - * starts the library USB task to begin the enumeration and USB management process. - */ void EVENT_USB_Connect(void) { - /* Start USB management task */ - Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); - - /* Indicate USB enumerating */ - UpdateStatus(Status_USBEnumerating); + LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); } -/** 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) { - /* Stop running HID reporting and USB management tasks */ - Scheduler_SetTaskMode(USB_HID_Report, TASK_STOP); - Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); - - /* Indicate USB not ready */ - UpdateStatus(Status_USBNotReady); + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); } -/** 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) { - /* Setup Generic IN Report Endpoint */ - Endpoint_ConfigureEndpoint(GENERIC_IN_EPNUM, EP_TYPE_INTERRUPT, - ENDPOINT_DIR_IN, GENERIC_EPSIZE, - ENDPOINT_BANK_SINGLE); + LEDs_SetAllLEDs(LEDMASK_USB_READY); - /* Setup Generic OUT Report Endpoint */ - Endpoint_ConfigureEndpoint(GENERIC_OUT_EPNUM, EP_TYPE_INTERRUPT, - ENDPOINT_DIR_OUT, GENERIC_EPSIZE, - ENDPOINT_BANK_SINGLE); - - /* Indicate USB connected and ready */ - UpdateStatus(Status_USBReady); + if (!(USB_HID_ConfigureEndpoints(&Generic_HID_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); } -/** 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) { - /* Handle HID Class specific requests */ - 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; - } + USB_HID_ProcessControlPacket(&Generic_HID_Interface); } -/** 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 GenericHID_StatusCodes_t enum - */ -void UpdateStatus(uint8_t CurrentStatus) +void EVENT_USB_StartOfFrame(void) { - 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); + USB_HID_RegisterStartOfFrame(&Generic_HID_Interface); } -/** Function to process the lest received report from the host. - * - * \param DataArray Pointer to a buffer where the last report data is stored - */ -void ProcessGenericHIDReport(uint8_t* DataArray) +uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData) { - /* - 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. - */ + // Create generic HID report here - for (uint8_t i = 0; i < GENERIC_REPORT_SIZE; i++) - LastReceived[i] = DataArray[i]; + return 0; } -/** Function to create the next report to send back to the host at the next reporting interval. - * - * \param DataArray Pointer to a buffer where the next report data should be stored - */ -void CreateGenericHIDReport(uint8_t* DataArray) +void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize) { - /* - 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(); - } - } + // Process received generic HID report here } diff --git a/Demos/Device/GenericHID/GenericHID.h b/Demos/Device/GenericHID/GenericHID.h index 30354b7560..27426431c9 100644 --- a/Demos/Device/GenericHID/GenericHID.h +++ b/Demos/Device/GenericHID/GenericHID.h @@ -46,38 +46,28 @@ #include "Descriptors.h" - #include // Library Version Information - #include // Simple scheduler for task management - #include // USB Functionality - #include // LEDs driver - - /* Macros: */ - /** HID Class specific request to get the next HID report from the device. */ - #define REQ_GetReport 0x01 - - /** HID Class specific request to send the next HID report to the device. */ - #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 */ - }; + #include + #include + #include + #include - /* Task Definitions: */ - TASK(USB_HID_Report); + /* Macros: */ + #define LEDMASK_USB_NOTREADY LEDS_LED1 + #define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3) + #define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4) + #define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3) /* Function Prototypes: */ + void SetupHardware(void); + void EVENT_USB_Connect(void); void EVENT_USB_Disconnect(void); void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_UnhandledControlPacket(void); + void EVENT_USB_StartOfFrame(void); - void UpdateStatus(uint8_t CurrentStatus); - void ProcessGenericHIDReport(uint8_t* DataArray); - void CreateGenericHIDReport(uint8_t* DataArray); + 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 diff --git a/Demos/Device/GenericHID/makefile b/Demos/Device/GenericHID/makefile index 9c6c891cd9..5cc4b4a43b 100644 --- a/Demos/Device/GenericHID/makefile +++ b/Demos/Device/GenericHID/makefile @@ -125,7 +125,6 @@ LUFA_PATH = ../../.. # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c \ Descriptors.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.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/USBTask.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.) @@ -183,7 +182,7 @@ CSTANDARD = -std=gnu99 # Place -D or -U options here for C sources 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 += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" diff --git a/Demos/Device/Joystick/Descriptors.h b/Demos/Device/Joystick/Descriptors.h index 6121295fa5..1241ad14e1 100644 --- a/Demos/Device/Joystick/Descriptors.h +++ b/Demos/Device/Joystick/Descriptors.h @@ -37,30 +37,12 @@ #define _DESCRIPTORS_H_ /* Includes: */ - #include - #include - /* 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; + #include + #include + /* Type Defines: */ /** Type define for the device configuration descriptor structure. This must be defined in the * application code, as the configuration descriptor contains several sub-descriptors which * vary between devices, and which describe the device's usage to the host. @@ -80,12 +62,6 @@ /** Size in bytes of the Joystick HID reporting IN endpoint. */ #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: */ 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); diff --git a/Demos/Device/Joystick/Joystick.c b/Demos/Device/Joystick/Joystick.c index 8c50a2c163..e073a87fdd 100644 --- a/Demos/Device/Joystick/Joystick.c +++ b/Demos/Device/Joystick/Joystick.c @@ -28,25 +28,34 @@ 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" -/* Scheduler Task List */ -TASK_LIST -{ - { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, - { .Task = USB_Joystick_Report , .TaskStatus = TASK_STOP }, -}; +USB_ClassInfo_HID_t Joystick_HID_Interface = + { + .InterfaceNumber = 0, + + .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) +{ + 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 */ MCUSR &= ~(1 << WDRF); @@ -59,188 +68,64 @@ int main(void) Joystick_Init(); LEDs_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(); - - /* 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) { - /* Start USB management task */ - Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); - - /* Indicate USB enumerating */ - UpdateStatus(Status_USBEnumerating); + LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); } -/** 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) { - /* Stop running joystick reporting and USB management tasks */ - Scheduler_SetTaskMode(USB_Joystick_Report, TASK_STOP); - Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); - - /* Indicate USB not ready */ - UpdateStatus(Status_USBNotReady); + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); } -/** 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) { - /* Setup Joystick Report Endpoint */ - Endpoint_ConfigureEndpoint(JOYSTICK_EPNUM, EP_TYPE_INTERRUPT, - ENDPOINT_DIR_IN, JOYSTICK_EPSIZE, - ENDPOINT_BANK_SINGLE); + LEDs_SetAllLEDs(LEDMASK_USB_READY); - /* Indicate USB connected and ready */ - UpdateStatus(Status_USBReady); - - /* Start joystick reporting task */ - Scheduler_SetTaskMode(USB_Joystick_Report, TASK_RUN); + if (!(USB_HID_ConfigureEndpoints(&Joystick_HID_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); } -/** 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) { - /* Handle HID Class specific requests */ - 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; - } + USB_HID_ProcessControlPacket(&Joystick_HID_Interface); } -/** Fills the given HID report data structure with the next HID report to send to the host. - * - * \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) +void EVENT_USB_StartOfFrame(void) { - static uint8_t PrevJoyStatus = 0; - static uint8_t PrevButtonStatus = 0; - uint8_t JoyStatus_LCL = Joystick_GetStatus(); - uint8_t ButtonStatus_LCL = Buttons_GetStatus(); - bool InputChanged = false; + USB_HID_RegisterStartOfFrame(&Joystick_HID_Interface); +} - /* Clear the report contents */ - memset(ReportData, 0, sizeof(USB_JoystickReport_Data_t)); +uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData) +{ + 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) - ReportData->Y = -100; + JoystickReport->Y = -100; else if (JoyStatus_LCL & JOY_DOWN) - ReportData->Y = 100; + JoystickReport->Y = 100; if (JoyStatus_LCL & JOY_RIGHT) - ReportData->X = 100; + JoystickReport->X = 100; else if (JoyStatus_LCL & JOY_LEFT) - ReportData->X = -100; + JoystickReport->X = -100; if (JoyStatus_LCL & JOY_PRESS) - ReportData->Button = (1 << 1); + JoystickReport->Button = (1 << 1); if (ButtonStatus_LCL & BUTTONS_BUTTON1) - ReportData->Button |= (1 << 0); + JoystickReport->Button |= (1 << 0); - /* Check if the new report is different to the previous report */ - 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; + return sizeof(USB_JoystickReport_Data_t); } -/** 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 Joystick_StatusCodes_t enum - */ -void UpdateStatus(uint8_t CurrentStatus) +void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize) { - 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. */ -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)); - } - } + // Unused (but mandatory for the HID class driver) in this demo, since there are no Host->Device reports } diff --git a/Demos/Device/Joystick/Joystick.h b/Demos/Device/Joystick/Joystick.h index 9763cada39..461d0d0ccc 100644 --- a/Demos/Device/Joystick/Joystick.h +++ b/Demos/Device/Joystick/Joystick.h @@ -44,19 +44,12 @@ #include "Descriptors.h" - #include // Library Version Information - #include // USB Functionality - #include // Joystick driver - #include // LEDs driver - #include // Board Buttons driver - #include // Simple scheduler for task management - - /* Task Definitions: */ - TASK(USB_Joystick_Report); - - /* Macros: */ - /** HID Class specific request to get the next HID report from the device. */ - #define REQ_GetReport 0x01 + #include + #include + #include + #include + #include + #include /* Type Defines: */ /** 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 */ } USB_JoystickReport_Data_t; - /* Enums: */ - /** Enum for the possible status codes for passing to the UpdateStatus() function. */ - enum Joystick_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: */ + #define LEDMASK_USB_NOTREADY LEDS_LED1 + #define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3) + #define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4) + #define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3) /* Function Prototypes: */ + void SetupHardware(void); + void EVENT_USB_Connect(void); void EVENT_USB_Disconnect(void); void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_UnhandledControlPacket(void); + void EVENT_USB_StartOfFrame(void); - bool GetNextReport(USB_JoystickReport_Data_t* ReportData); - 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 diff --git a/Demos/Device/Joystick/makefile b/Demos/Device/Joystick/makefile index aaf69e80bd..826766c306 100644 --- a/Demos/Device/Joystick/makefile +++ b/Demos/Device/Joystick/makefile @@ -125,7 +125,6 @@ LUFA_PATH = ../../.. # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c \ Descriptors.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.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/USBTask.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.) @@ -183,7 +182,7 @@ CSTANDARD = -std=gnu99 # Place -D or -U options here for C sources 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 += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" diff --git a/Demos/Device/Keyboard/Descriptors.h b/Demos/Device/Keyboard/Descriptors.h index 92eb7b884a..0a95ca06e8 100644 --- a/Demos/Device/Keyboard/Descriptors.h +++ b/Demos/Device/Keyboard/Descriptors.h @@ -38,30 +38,12 @@ #define _DESCRIPTORS_H_ /* Includes: */ - #include - #include - /* 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; + #include + #include + /* Type Defines: */ /** Type define for the device configuration descriptor structure. This must be defined in the * application code, as the configuration descriptor contains several sub-descriptors which * vary between devices, and which describe the device's usage to the host. @@ -85,12 +67,6 @@ /** Size in bytes of the Keyboard HID reporting IN and OUT endpoints. */ #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: */ 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); diff --git a/Demos/Device/Keyboard/Keyboard.c b/Demos/Device/Keyboard/Keyboard.c index 6abd193f4b..d8893bfaae 100644 --- a/Demos/Device/Keyboard/Keyboard.c +++ b/Demos/Device/Keyboard/Keyboard.c @@ -28,397 +28,120 @@ arising out of or in connection with the use or performance of 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" -/* Scheduler Task List */ -TASK_LIST -{ - { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, - { .Task = USB_Keyboard_Report , .TaskStatus = TASK_STOP }, -}; - -/* Global Variables */ -/** Indicates what report mode the host has requested, true for normal HID reporting mode, false for special boot - * protocol reporting mode. - */ -bool UsingReportProtocol = true; +USB_ClassInfo_HID_t Keyboard_HID_Interface = + { + .InterfaceNumber = 0, -/** Current Idle period. This is set by the host via a Set Idle HID class request to silence the device's reports - * for either the entire idle duration, or until the report status changes (e.g. the user presses a key). - */ -uint16_t IdleCount = 500; + .ReportINEndpointNumber = KEYBOARD_EPNUM, + .ReportINEndpointSize = KEYBOARD_EPSIZE, -/** 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; + .ReportOUTEndpointNumber = KEYBOARD_LEDS_EPNUM, + .ReportOUTEndpointSize = KEYBOARD_EPSIZE, + + .ReportBufferSize = sizeof(USB_KeyboardReport_Data_t), + .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) { - /* Disable watchdog if enabled by bootloader/fuses */ - MCUSR &= ~(1 << WDRF); - wdt_disable(); - - /* Disable clock division */ - clock_prescale_set(clock_div_1); - - /* Hardware Initialization */ - Joystick_Init(); - LEDs_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(); + SetupHardware(); + + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); + + for (;;) + { + USB_HID_USBTask(&Keyboard_HID_Interface); + USB_USBTask(); + } +} - /* Initialize USB Subsystem */ - USB_Init(); - - /* Scheduling - routine never returns, so put this last in the main function */ - Scheduler_Start(); +void SetupHardware() +{ + /* Disable watchdog if enabled by bootloader/fuses */ + MCUSR &= ~(1 << WDRF); + wdt_disable(); + + /* Disable clock division */ + clock_prescale_set(clock_div_1); + + /* Hardware Initialization */ + Joystick_Init(); + LEDs_Init(); + Buttons_Init(); + 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) { - /* Start USB management task */ - Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); - - /* Indicate USB enumerating */ - UpdateStatus(Status_USBEnumerating); - - /* Default to report protocol on connect */ - UsingReportProtocol = true; + LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); } -/** 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) { - /* Stop running keyboard reporting and USB management tasks */ - Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_STOP); - Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); - - /* Indicate USB not ready */ - UpdateStatus(Status_USBNotReady); + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); } -/** 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) { - /* Setup Keyboard Keycode Report Endpoint */ - Endpoint_ConfigureEndpoint(KEYBOARD_EPNUM, EP_TYPE_INTERRUPT, - ENDPOINT_DIR_IN, KEYBOARD_EPSIZE, - ENDPOINT_BANK_SINGLE); - - /* Setup Keyboard LED Report Endpoint */ - Endpoint_ConfigureEndpoint(KEYBOARD_LEDS_EPNUM, EP_TYPE_INTERRUPT, - ENDPOINT_DIR_OUT, KEYBOARD_EPSIZE, - ENDPOINT_BANK_SINGLE); + LEDs_SetAllLEDs(LEDMASK_USB_READY); - /* Indicate USB connected and ready */ - UpdateStatus(Status_USBReady); - - /* Start running keyboard reporting task */ - Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_RUN); + if (!(USB_HID_ConfigureEndpoints(&Keyboard_HID_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); } -/** 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) { - /* Handle HID Class specific requests */ - 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; - } + USB_HID_ProcessControlPacket(&Keyboard_HID_Interface); } -/** ISR for the timer 0 compare vector. This ISR fires once each millisecond, and increments the - * scheduler elapsed idle period counter when the host has set an idle period. - */ -ISR(TIMER0_COMPA_vect, ISR_BLOCK) +void EVENT_USB_StartOfFrame(void) { - /* One millisecond has elapsed, decrement the idle time remaining counter if it has not already elapsed */ - if (IdleMSRemaining) - IdleMSRemaining--; -} - -/** Fills the given HID report data structure with the next HID report to send to the host. - * - * \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(); - - /* Clear the report contents */ - memset(ReportData, 0, sizeof(USB_KeyboardReport_Data_t)); - - if (JoyStatus_LCL & JOY_UP) - ReportData->KeyCode[0] = 0x04; // A - else if (JoyStatus_LCL & JOY_DOWN) - ReportData->KeyCode[0] = 0x05; // B - - if (JoyStatus_LCL & JOY_LEFT) - ReportData->KeyCode[0] = 0x06; // C - else if (JoyStatus_LCL & JOY_RIGHT) - ReportData->KeyCode[0] = 0x07; // D - - if (JoyStatus_LCL & JOY_PRESS) - ReportData->KeyCode[0] = 0x08; // E -} - -/** Processes a received LED report, and updates the board LEDs states to match. - * - * \param LEDReport LED status report from the host - */ -void ProcessLEDReport(uint8_t LEDReport) -{ - uint8_t LEDMask = LEDS_LED2; - - if (LEDReport & 0x01) // NUM Lock - LEDMask |= LEDS_LED1; - - if (LEDReport & 0x02) // CAPS Lock - LEDMask |= LEDS_LED3; - - if (LEDReport & 0x04) // SCROLL Lock - LEDMask |= LEDS_LED4; - - /* Set the status LEDs to the current Keyboard LED status */ - 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(); - } + USB_HID_RegisterStartOfFrame(&Keyboard_HID_Interface); } -/** 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) +uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData) { - 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); + USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData; + + uint8_t JoyStatus_LCL = Joystick_GetStatus(); + uint8_t ButtonStatus_LCL = Buttons_GetStatus(); + + if (JoyStatus_LCL & JOY_UP) + KeyboardReport->KeyCode[0] = 0x04; // A + else if (JoyStatus_LCL & JOY_DOWN) + KeyboardReport->KeyCode[0] = 0x05; // B + + if (JoyStatus_LCL & JOY_LEFT) + KeyboardReport->KeyCode[0] = 0x06; // C + else if (JoyStatus_LCL & JOY_RIGHT) + KeyboardReport->KeyCode[0] = 0x07; // D + + if (JoyStatus_LCL & JOY_PRESS) + KeyboardReport->KeyCode[0] = 0x08; // E + + if (ButtonStatus_LCL & BUTTONS_BUTTON1) + KeyboardReport->KeyCode[0] = 0x09; // F + + return sizeof(USB_KeyboardReport_Data_t); } -/** Function to manage HID report generation and transmission to the host, when in report mode. */ -TASK(USB_Keyboard_Report) +void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize) { - /* 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(); - } + uint8_t LEDMask = LEDS_NO_LEDS; + uint8_t* LEDReport = (uint8_t*)ReportData; + + if (*LEDReport & 0x01) // NUM Lock + LEDMask |= LEDS_LED1; + + if (*LEDReport & 0x02) // CAPS Lock + LEDMask |= LEDS_LED3; + + if (*LEDReport & 0x04) // SCROLL Lock + LEDMask |= LEDS_LED4; + + LEDs_SetAllLEDs(LEDMask); } diff --git a/Demos/Device/Keyboard/Keyboard.h b/Demos/Device/Keyboard/Keyboard.h index c4ed6e07cc..eeb7be9b74 100644 --- a/Demos/Device/Keyboard/Keyboard.h +++ b/Demos/Device/Keyboard/Keyboard.h @@ -47,36 +47,12 @@ #include "Descriptors.h" - #include // Library Version Information - #include // Simple scheduler for task management - #include // USB Functionality - #include // Joystick driver - #include // LEDs driver - - /* 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); + #include + #include + #include + #include + #include + #include /* Type Defines: */ /** 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 */ } USB_KeyboardReport_Data_t; - /* Enums: */ - /** Enum for the possible status codes for passing to the UpdateStatus() function. */ - enum Keyboard_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: */ + #define LEDMASK_USB_NOTREADY LEDS_LED1 + #define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3) + #define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4) + #define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3) /* Function Prototypes: */ + void SetupHardware(void); + void EVENT_USB_Connect(void); void EVENT_USB_Disconnect(void); void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_UnhandledControlPacket(void); + void EVENT_USB_StartOfFrame(void); - void CreateKeyboardReport(USB_KeyboardReport_Data_t* ReportData); - void ProcessLEDReport(uint8_t LEDReport); - void SendNextReport(void); - void ReceiveNextReport(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 diff --git a/Demos/Device/Keyboard/makefile b/Demos/Device/Keyboard/makefile index 88e4de0e61..98cda2f895 100644 --- a/Demos/Device/Keyboard/makefile +++ b/Demos/Device/Keyboard/makefile @@ -125,7 +125,6 @@ LUFA_PATH = ../../.. # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c \ Descriptors.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.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/USBTask.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.) @@ -183,7 +182,7 @@ CSTANDARD = -std=gnu99 # Place -D or -U options here for C sources 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 += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" diff --git a/Demos/Device/KeyboardMouse/Descriptors.h b/Demos/Device/KeyboardMouse/Descriptors.h index 43c345a211..152e5111af 100644 --- a/Demos/Device/KeyboardMouse/Descriptors.h +++ b/Demos/Device/KeyboardMouse/Descriptors.h @@ -38,30 +38,12 @@ #define _DESCRIPTORS_H_ /* Includes: */ - #include - #include - /* 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; + #include + #include + /* Type Defines: */ /** Type define for the device configuration descriptor structure. This must be defined in the * application code, as the configuration descriptor contains several sub-descriptors which * vary between devices, and which describe the device's usage to the host. @@ -91,12 +73,6 @@ /** Size in bytes of each of the HID reporting IN and OUT endpoints. */ #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: */ 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); diff --git a/Demos/Device/KeyboardMouse/KeyboardMouse.c b/Demos/Device/KeyboardMouse/KeyboardMouse.c index 25d633e435..8f6a573a67 100644 --- a/Demos/Device/KeyboardMouse/KeyboardMouse.c +++ b/Demos/Device/KeyboardMouse/KeyboardMouse.c @@ -28,34 +28,52 @@ arising out of or in connection with the use or performance of 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" -/* Scheduler Task List */ -TASK_LIST -{ - { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, - { .Task = USB_Mouse , .TaskStatus = TASK_RUN }, - { .Task = USB_Keyboard , .TaskStatus = TASK_RUN }, -}; +USB_ClassInfo_HID_t Keyboard_HID_Interface = + { + .InterfaceNumber = 0, + + .ReportINEndpointNumber = KEYBOARD_IN_EPNUM, + .ReportINEndpointSize = HID_EPSIZE, + + .ReportOUTEndpointNumber = KEYBOARD_OUT_EPNUM, + .ReportOUTEndpointSize = HID_EPSIZE, + + .ReportBufferSize = sizeof(USB_KeyboardReport_Data_t), + + .IdleCount = 500, + }; + +USB_ClassInfo_HID_t Mouse_HID_Interface = + { + .InterfaceNumber = 0, -/* Global Variables */ -/** Global structure to hold the current keyboard interface HID report, for transmission to the host */ -USB_KeyboardReport_Data_t KeyboardReportData; + .ReportINEndpointNumber = MOUSE_IN_EPNUM, + .ReportINEndpointSize = HID_EPSIZE, -/** Global structure to hold the current mouse interface HID report, for transmission to the host */ -USB_MouseReport_Data_t MouseReportData; + .ReportBufferSize = sizeof(USB_MouseReport_Data_t), -/** Main program entry point. This routine configures the hardware required by the application, then - * starts the scheduler to run the USB management task. - */ + .ReportOUTEndpointNumber = 0, + .ReportOUTEndpointSize = 0, + }; + 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 */ MCUSR &= ~(1 << WDRF); @@ -67,284 +85,111 @@ int main(void) /* Hardware Initialization */ Joystick_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(); - - /* Scheduling - routine never returns, so put this last in the main function */ - 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) { - /* Start USB management task */ - Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); - - /* Indicate USB enumerating */ - UpdateStatus(Status_USBEnumerating); + LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); } -/** 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) { - /* Stop running HID reporting and USB management tasks */ - Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); - - /* Indicate USB not ready */ - UpdateStatus(Status_USBNotReady); + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); } -/** 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) { - /* Setup Keyboard Report Endpoint */ - Endpoint_ConfigureEndpoint(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, - ENDPOINT_DIR_IN, HID_EPSIZE, - ENDPOINT_BANK_SINGLE); - - /* Setup Keyboard LED Report Endpoint */ - Endpoint_ConfigureEndpoint(KEYBOARD_OUT_EPNUM, EP_TYPE_INTERRUPT, - ENDPOINT_DIR_OUT, HID_EPSIZE, - ENDPOINT_BANK_SINGLE); + LEDs_SetAllLEDs(LEDMASK_USB_READY); - /* Setup Mouse Report Endpoint */ - Endpoint_ConfigureEndpoint(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, - ENDPOINT_DIR_IN, HID_EPSIZE, - ENDPOINT_BANK_SINGLE); - - /* Indicate USB connected and ready */ - UpdateStatus(Status_USBReady); + if (!(USB_HID_ConfigureEndpoints(&Keyboard_HID_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); + + if (!(USB_HID_ConfigureEndpoints(&Mouse_HID_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); } -/** 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) { - uint8_t* ReportData; - uint8_t ReportSize; - - /* 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; - } + USB_HID_ProcessControlPacket(&Keyboard_HID_Interface); + USB_HID_ProcessControlPacket(&Mouse_HID_Interface); } -/** 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 KeyboardMouse_StatusCodes_t enum - */ -void UpdateStatus(uint8_t CurrentStatus) +void EVENT_USB_StartOfFrame(void) { - 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); + USB_HID_RegisterStartOfFrame(&Keyboard_HID_Interface); + USB_HID_RegisterStartOfFrame(&Mouse_HID_Interface); } -/** Keyboard task. This generates the next keyboard HID report for the host, and transmits it via the - * 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) +uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData) { - 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 (!(Buttons_GetStatus() & BUTTONS_BUTTON1)) + if (HIDInterfaceInfo == &Keyboard_HID_Interface) { + 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) - KeyboardReportData.KeyCode[0] = 0x04; // A + KeyboardReport->KeyCode[0] = 0x04; // A else if (JoyStatus_LCL & JOY_DOWN) - KeyboardReportData.KeyCode[0] = 0x05; // B + KeyboardReport->KeyCode[0] = 0x05; // B if (JoyStatus_LCL & JOY_LEFT) - KeyboardReportData.KeyCode[0] = 0x06; // C + KeyboardReport->KeyCode[0] = 0x06; // C else if (JoyStatus_LCL & JOY_RIGHT) - KeyboardReportData.KeyCode[0] = 0x07; // D + KeyboardReport->KeyCode[0] = 0x07; // D if (JoyStatus_LCL & JOY_PRESS) - KeyboardReportData.KeyCode[0] = 0x08; // E + KeyboardReport->KeyCode[0] = 0x08; // E + + return sizeof(USB_KeyboardReport_Data_t); } - - /* Check if the USB system is connected to a host and report protocol mode is enabled */ - if (USB_IsConnected) + else { - /* Select the Keyboard Report Endpoint */ - Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM); - - /* Check if Keyboard Endpoint Ready for Read/Write */ - if (Endpoint_IsReadWriteAllowed()) - { - /* 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)); - } + USB_MouseReport_Data_t* MouseReport = (USB_MouseReport_Data_t*)ReportData; - /* 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 first board button being held down, no mouse report */ + if (ButtonStatus_LCL & BUTTONS_BUTTON1) + return 0; + if (JoyStatus_LCL & JOY_UP) - MouseReportData.Y = 1; + MouseReport->Y = -1; else if (JoyStatus_LCL & JOY_DOWN) - MouseReportData.Y = -1; + MouseReport->Y = 1; if (JoyStatus_LCL & JOY_RIGHT) - MouseReportData.X = 1; + MouseReport->X = 1; else if (JoyStatus_LCL & JOY_LEFT) - MouseReportData.X = -1; + MouseReport->X = -1; if (JoyStatus_LCL & JOY_PRESS) - MouseReportData.Button = (1 << 0); + MouseReport->Button = (1 << 0); + + return sizeof(USB_MouseReport_Data_t); } +} - /* Check if the USB system is connected to a host and report protocol mode is enabled */ - if (USB_IsConnected) +void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize) +{ + if (HIDInterfaceInfo == &Keyboard_HID_Interface) { - /* Select the Mouse Report Endpoint */ - Endpoint_SelectEndpoint(MOUSE_IN_EPNUM); - - /* Check if Mouse Endpoint Ready for Read/Write */ - if (Endpoint_IsReadWriteAllowed()) - { - /* Write Mouse Report Data */ - Endpoint_Write_Stream_LE(&MouseReportData, sizeof(MouseReportData)); + uint8_t LEDMask = LEDS_NO_LEDS; + uint8_t* LEDReport = (uint8_t*)ReportData; - /* Finalize the stream transfer to send the last packet */ - Endpoint_ClearIN(); + if (*LEDReport & 0x01) // NUM Lock + LEDMask |= LEDS_LED1; + + if (*LEDReport & 0x02) // CAPS Lock + LEDMask |= LEDS_LED3; - /* Clear the report data afterwards */ - memset(&MouseReportData, 0, sizeof(MouseReportData)); - } + if (*LEDReport & 0x04) // SCROLL Lock + LEDMask |= LEDS_LED4; + + LEDs_SetAllLEDs(LEDMask); } -} +} \ No newline at end of file diff --git a/Demos/Device/KeyboardMouse/KeyboardMouse.h b/Demos/Device/KeyboardMouse/KeyboardMouse.h index e3f9434029..a5c3c5db2b 100644 --- a/Demos/Device/KeyboardMouse/KeyboardMouse.h +++ b/Demos/Device/KeyboardMouse/KeyboardMouse.h @@ -41,38 +41,18 @@ #include "Descriptors.h" - #include // Library Version Information - #include // USB Functionality - #include // Joystick driver - #include // LEDs driver - #include // Board Buttons driver - #include // Simple scheduler for task management - - /* Task Definitions: */ - TASK(USB_Keyboard); - TASK(USB_Mouse); + #include + #include + #include + #include + #include + #include - /* 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: */ - /** HID Class specific request to get the next HID report from the device. */ - #define REQ_GetReport 0x01 - - /** HID Class specific request to send the next HID report to the device. */ - #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 + #define LEDMASK_USB_NOTREADY LEDS_LED1 + #define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3) + #define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4) + #define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3) /* Type Defines: */ /** 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; /* Function Prototypes: */ + void SetupHardware(void); + void EVENT_USB_Connect(void); void EVENT_USB_Disconnect(void); void EVENT_USB_ConfigurationChanged(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 diff --git a/Demos/Device/KeyboardMouse/makefile b/Demos/Device/KeyboardMouse/makefile index c6b34d96e9..ddad7d24bd 100644 --- a/Demos/Device/KeyboardMouse/makefile +++ b/Demos/Device/KeyboardMouse/makefile @@ -125,7 +125,6 @@ LUFA_PATH = ../../.. # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c \ Descriptors.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.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/USBTask.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.) @@ -183,7 +182,7 @@ CSTANDARD = -std=gnu99 # Place -D or -U options here for C sources 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 += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" diff --git a/Demos/Device/MIDI/makefile b/Demos/Device/MIDI/makefile index 18fc3b1547..485cdc710d 100644 --- a/Demos/Device/MIDI/makefile +++ b/Demos/Device/MIDI/makefile @@ -183,7 +183,7 @@ CSTANDARD = -std=gnu99 # Place -D or -U options here for C sources 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 += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" diff --git a/Demos/Device/MassStorage/Lib/DataflashManager.c b/Demos/Device/MassStorage/Lib/DataflashManager.c index 4b624190f9..87edef12b4 100644 --- a/Demos/Device/MassStorage/Lib/DataflashManager.c +++ b/Demos/Device/MassStorage/Lib/DataflashManager.c @@ -46,7 +46,7 @@ * \param BlockAddress Data block starting address for the write sequence * \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 CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE); @@ -142,7 +142,7 @@ void DataflashManager_WriteBlocks(const uint32_t BlockAddress, uint16_t TotalBlo BytesInBlockDiv16++; /* Check if the current command is being aborted by the host */ - if (IsMassStoreReset) + if (MSInterfaceInfo->IsMassStoreReset) 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 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 CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE); @@ -250,7 +250,7 @@ void DataflashManager_ReadBlocks(const uint32_t BlockAddress, uint16_t TotalBloc BytesInBlockDiv16++; /* Check if the current command is being aborted by the host */ - if (IsMassStoreReset) + if (MSInterfaceInfo->IsMassStoreReset) return; } @@ -341,11 +341,7 @@ void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t Tota CurrDFPageByteDiv16++; /* Increment the block 16 byte block counter */ - BytesInBlockDiv16++; - - /* Check if the current command is being aborted by the host */ - if (IsMassStoreReset) - return; + BytesInBlockDiv16++; } /* 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 */ BytesInBlockDiv16++; - - /* Check if the current command is being aborted by the host */ - if (IsMassStoreReset) - return; } /* Decrement the blocks remaining counter */ diff --git a/Demos/Device/MassStorage/Lib/DataflashManager.h b/Demos/Device/MassStorage/Lib/DataflashManager.h index 1332fd3a30..b828051aa6 100644 --- a/Demos/Device/MassStorage/Lib/DataflashManager.h +++ b/Demos/Device/MassStorage/Lib/DataflashManager.h @@ -64,8 +64,8 @@ #define VIRTUAL_MEMORY_BLOCKS (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE) /* Function Prototypes: */ - void DataflashManager_WriteBlocks(const uint32_t BlockAddress, uint16_t TotalBlocks); - void DataflashManager_ReadBlocks(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(USB_ClassInfo_MS_t* MSInterfaceInfo, 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); void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, diff --git a/Demos/Device/MassStorage/Lib/SCSI.c b/Demos/Device/MassStorage/Lib/SCSI.c index 5993a546dd..8f3167a47b 100644 --- a/Demos/Device/MassStorage/Lib/SCSI.c +++ b/Demos/Device/MassStorage/Lib/SCSI.c @@ -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 * a command failure due to a ILLEGAL REQUEST. */ -void SCSI_DecodeSCSICommand(void) +bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_t* MSInterfaceInfo) { bool CommandSuccess = false; /* 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: - CommandSuccess = SCSI_Command_Inquiry(); + CommandSuccess = SCSI_Command_Inquiry(MSInterfaceInfo); break; case SCSI_CMD_REQUEST_SENSE: - CommandSuccess = SCSI_Command_Request_Sense(); + CommandSuccess = SCSI_Command_Request_Sense(MSInterfaceInfo); break; case SCSI_CMD_READ_CAPACITY_10: - CommandSuccess = SCSI_Command_Read_Capacity_10(); + CommandSuccess = SCSI_Command_Read_Capacity_10(MSInterfaceInfo); break; case SCSI_CMD_SEND_DIAGNOSTIC: - CommandSuccess = SCSI_Command_Send_Diagnostic(); + CommandSuccess = SCSI_Command_Send_Diagnostic(MSInterfaceInfo); break; case SCSI_CMD_WRITE_10: - CommandSuccess = SCSI_Command_ReadWrite_10(DATA_WRITE); + CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_WRITE); break; case SCSI_CMD_READ_10: - CommandSuccess = SCSI_Command_ReadWrite_10(DATA_READ); + CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ); break; case SCSI_CMD_TEST_UNIT_READY: case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: case SCSI_CMD_VERIFY_10: /* These commands should just succeed, no handling required */ CommandSuccess = true; - CommandBlock.DataTransferLength = 0; + MSInterfaceInfo->CommandBlock.DataTransferLength = 0; break; default: /* Update the SENSE key to reflect the invalid command */ @@ -123,22 +123,18 @@ void SCSI_DecodeSCSICommand(void) SCSI_ASENSEQ_NO_QUALIFIER); break; } - + /* Check if command was successfully processed */ 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_ASENSE_NO_ADDITIONAL_INFORMATION, - SCSI_ASENSEQ_NO_QUALIFIER); - } - else - { - /* Command failed - set the CSW status - failed command function updates the SENSE key */ - CommandStatus.Status = Command_Fail; + SCSI_ASENSEQ_NO_QUALIFIER); + + return true; } + + return false; } /** 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. */ -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) | - CommandBlock.SCSICommandData[4]); + uint16_t AllocationLength = (((uint16_t)MSInterfaceInfo->CommandBlock.SCSICommandData[3] << 8) | + MSInterfaceInfo->CommandBlock.SCSICommandData[4]); uint16_t BytesTransferred = (AllocationLength < sizeof(InquiryData))? AllocationLength : sizeof(InquiryData); /* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */ - if ((CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) || - CommandBlock.SCSICommandData[2]) + if ((MSInterfaceInfo->CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) || + MSInterfaceInfo->CommandBlock.SCSICommandData[2]) { /* Optional but unsupported bits set - update the SENSE key and fail the request */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, @@ -164,20 +160,19 @@ static bool SCSI_Command_Inquiry(void) return false; } - - /* Write the INQUIRY data to the endpoint */ - Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, StreamCallback_AbortOnMassStoreReset); + + Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, NO_STREAM_CALLBACK); uint8_t PadBytes[AllocationLength - BytesTransferred]; /* 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 */ Endpoint_ClearIN(); /* Succeed the command and update the bytes transferred counter */ - CommandBlock.DataTransferLength -= BytesTransferred; + MSInterfaceInfo->CommandBlock.DataTransferLength -= BytesTransferred; return true; } @@ -187,24 +182,19 @@ static bool SCSI_Command_Inquiry(void) * * \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); - /* 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]; - - /* Pad out remaining bytes with 0x00 */ - Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), StreamCallback_AbortOnMassStoreReset); - /* Finalize the stream transfer to send the last packet */ + Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, NO_STREAM_CALLBACK); + Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK); Endpoint_ClearIN(); /* Succeed the command and update the bytes transferred counter */ - CommandBlock.DataTransferLength -= BytesTransferred; + MSInterfaceInfo->CommandBlock.DataTransferLength -= BytesTransferred; return true; } @@ -214,23 +204,17 @@ static bool SCSI_Command_Request_Sense(void) * * \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 */ - Endpoint_Write_DWord_BE(LUN_MEDIA_BLOCKS - 1); + uint32_t TotalLUNs = (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_DWord_BE(VIRTUAL_MEMORY_BLOCK_SIZE); - - /* Check if the current command is being aborted by the host */ - if (IsMassStoreReset) - return false; - - /* Send the endpoint data packet to the host */ + Endpoint_Write_Stream_BE(&TotalLUNs, sizeof(TotalLUNs), NO_STREAM_CALLBACK); + Endpoint_Write_Stream_BE(&MediaBlockSize, sizeof(MediaBlockSize), NO_STREAM_CALLBACK); Endpoint_ClearIN(); - + /* Succeed the command and update the bytes transferred counter */ - CommandBlock.DataTransferLength -= 8; + MSInterfaceInfo->CommandBlock.DataTransferLength -= 8; return true; } @@ -241,12 +225,12 @@ static bool SCSI_Command_Read_Capacity_10(void) * * \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; /* 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 */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, @@ -293,7 +277,7 @@ static bool SCSI_Command_Send_Diagnostic(void) #endif /* Succeed the command and update the bytes transferred counter */ - CommandBlock.DataTransferLength = 0; + MSInterfaceInfo->CommandBlock.DataTransferLength = 0; return true; } @@ -306,20 +290,20 @@ static bool SCSI_Command_Send_Diagnostic(void) * * \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; uint16_t TotalBlocks; /* 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)[2] = CommandBlock.SCSICommandData[3]; - ((uint8_t*)&BlockAddress)[1] = CommandBlock.SCSICommandData[4]; - ((uint8_t*)&BlockAddress)[0] = CommandBlock.SCSICommandData[5]; + ((uint8_t*)&BlockAddress)[3] = MSInterfaceInfo->CommandBlock.SCSICommandData[2]; + ((uint8_t*)&BlockAddress)[2] = MSInterfaceInfo->CommandBlock.SCSICommandData[3]; + ((uint8_t*)&BlockAddress)[1] = MSInterfaceInfo->CommandBlock.SCSICommandData[4]; + ((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) */ - ((uint8_t*)&TotalBlocks)[1] = CommandBlock.SCSICommandData[7]; - ((uint8_t*)&TotalBlocks)[0] = CommandBlock.SCSICommandData[8]; + ((uint8_t*)&TotalBlocks)[1] = MSInterfaceInfo->CommandBlock.SCSICommandData[7]; + ((uint8_t*)&TotalBlocks)[0] = MSInterfaceInfo->CommandBlock.SCSICommandData[8]; /* Check if the block address is outside the maximum allowable value for the LUN */ if (BlockAddress >= LUN_MEDIA_BLOCKS) @@ -334,17 +318,17 @@ static bool SCSI_Command_ReadWrite_10(const bool IsDataRead) #if (TOTAL_LUNS > 1) /* 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 /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */ if (IsDataRead == DATA_READ) - DataflashManager_ReadBlocks(BlockAddress, TotalBlocks); + DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks); else - DataflashManager_WriteBlocks(BlockAddress, TotalBlocks); + DataflashManager_WriteBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks); /* 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; } diff --git a/Demos/Device/MassStorage/Lib/SCSI.h b/Demos/Device/MassStorage/Lib/SCSI.h index d7693cafbb..3fd751deef 100644 --- a/Demos/Device/MassStorage/Lib/SCSI.h +++ b/Demos/Device/MassStorage/Lib/SCSI.h @@ -40,9 +40,8 @@ #include #include - #include // Function Attribute, Atomic, Debug and ISR Macros - #include // USB Functionality - #include // LEDs driver + #include + #include #include "MassStorage.h" #include "Descriptors.h" @@ -63,16 +62,16 @@ SenseData.AdditionalSenseQualifier = aqual; }MACROE /** 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. */ - #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. */ - #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. */ - #define DEVICE_TYPE_CDROM 0x05 + #define DEVICE_TYPE_CDROM 0x05 /* Type Defines: */ /** 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; /* Function Prototypes: */ - void SCSI_DecodeSCSICommand(void); + bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_t* MSInterfaceInfo); #if defined(INCLUDE_FROM_SCSI_C) - static bool SCSI_Command_Inquiry(void); - static bool SCSI_Command_Request_Sense(void); - static bool SCSI_Command_Read_Capacity_10(void); - static bool SCSI_Command_Send_Diagnostic(void); - static bool SCSI_Command_ReadWrite_10(const bool IsDataRead); + static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_t* MSInterfaceInfo); + static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_t* MSInterfaceInfo); + static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_t* MSInterfaceInfo); + static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_t* MSInterfaceInfo); + static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_t* MSInterfaceInfo, const bool IsDataRead); #endif #endif diff --git a/Demos/Device/MassStorage/MassStorage.c b/Demos/Device/MassStorage/MassStorage.c index 72a2302199..8e2b9f4500 100644 --- a/Demos/Device/MassStorage/MassStorage.c +++ b/Demos/Device/MassStorage/MassStorage.c @@ -28,35 +28,35 @@ 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" -/* Scheduler Task List */ -TASK_LIST -{ - { .Task = USB_MassStorage , .TaskStatus = TASK_STOP }, -}; +USB_ClassInfo_MS_t Disk_MS_Interface = + { + .InterfaceNumber = 0, -/* Global Variables */ -/** Structure to hold the latest Command Block Wrapper issued by the host, containing a SCSI command to execute. */ -CommandBlockWrapper_t CommandBlock; + .DataINEndpointNumber = MASS_STORAGE_IN_EPNUM, + .DataINEndpointSize = MASS_STORAGE_IO_EPSIZE, -/** Structure to hold the latest Command Status Wrapper to return to the host, containing the status of the last issued command. */ -CommandStatusWrapper_t CommandStatus = { .Signature = CSW_SIGNATURE }; + .DataOUTEndpointNumber = MASS_STORAGE_OUT_EPNUM, + .DataOUTEndpointSize = MASS_STORAGE_IO_EPSIZE, -/** Flag to asynchronously abort any in-progress data transfers upon the reception of a mass storage reset command. */ -volatile bool IsMassStoreReset = false; + .TotalLUNs = TOTAL_LUNS, + }; -/** 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) +{ + 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 */ MCUSR &= ~(1 << WDRF); @@ -68,303 +68,42 @@ int main(void) /* Hardware Initialization */ LEDs_Init(); Dataflash_Init(SPI_SPEED_FCPU_DIV_2); + USB_Init(); /* Clear Dataflash sector protections, if enabled */ 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) { - /* Indicate USB enumerating */ - UpdateStatus(Status_USBEnumerating); - - /* Reset the MSReset flag upon connection */ - IsMassStoreReset = false; + LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); } -/** 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) { - /* Stop running mass storage task */ - Scheduler_SetTaskMode(USB_MassStorage, TASK_STOP); - - /* Indicate USB not ready */ - UpdateStatus(Status_USBNotReady); + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); } -/** 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) { - /* Setup Mass Storage In and Out Endpoints */ - 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, - ENDPOINT_DIR_OUT, MASS_STORAGE_IO_EPSIZE, - ENDPOINT_BANK_DOUBLE); + LEDs_SetAllLEDs(LEDMASK_USB_READY); - /* Indicate USB connected and ready */ - UpdateStatus(Status_USBReady); - - /* Start mass storage task */ - Scheduler_SetTaskMode(USB_MassStorage, TASK_RUN); + if (!(USB_MS_ConfigureEndpoints(&Disk_MS_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); } -/** 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) { - /* Process UFI specific control requests */ - 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 - * 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; - - /* 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_CommandBlockError: - LEDMask = (LEDS_LED1); - break; - case Status_ProcessingCommandBlock: - LEDMask = (LEDS_LED1 | LEDS_LED2); - break; - } - - /* Set the board LEDs to the new LED mask */ - 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; + USB_MS_ProcessControlPacket(&Disk_MS_Interface); } -/** 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) +bool CALLBACK_USB_MS_SCSICommandReceived(USB_ClassInfo_MS_t* MSInterfaceInfo) { - /* 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; - } + bool CommandSuccess; - /* 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; + LEDs_SetAllLEDs(LEDMASK_USB_BUSY); + CommandSuccess = SCSI_DecodeSCSICommand(MSInterfaceInfo); + LEDs_SetAllLEDs(LEDMASK_USB_READY); - /* Continue with the current stream operation */ - return STREAMCALLBACK_Continue; + return CommandSuccess; } diff --git a/Demos/Device/MassStorage/MassStorage.h b/Demos/Device/MassStorage/MassStorage.h index cbd3cd9312..a50edac990 100644 --- a/Demos/Device/MassStorage/MassStorage.h +++ b/Demos/Device/MassStorage/MassStorage.h @@ -46,104 +46,33 @@ #include "Lib/SCSI.h" #include "Lib/DataflashManager.h" - #include // Library Version Information - #include // USB Functionality - #include // LEDs driver - #include // Dataflash chip driver - #include // Simple scheduler for task management + #include + #include + #include + #include + #include + #include /* 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 + #define LEDMASK_USB_NOTREADY LEDS_LED1 + #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 - /** 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 + #define TOTAL_LUNS 2 /** 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) - - /** 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); + #define LUN_MEDIA_BLOCKS (VIRTUAL_MEMORY_BLOCKS / TOTAL_LUNS) /* Function Prototypes: */ + void SetupHardware(void); + void EVENT_USB_Connect(void); void EVENT_USB_Disconnect(void); void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_UnhandledControlPacket(void); - void UpdateStatus(uint8_t CurrentStatus); - - #if defined(INCLUDE_FROM_MASSSTORAGE_C) - static bool ReadInCommandBlock(void); - static void ReturnCommandStatus(void); - #endif - - uint8_t StreamCallback_AbortOnMassStoreReset(void); + bool CALLBACK_USB_MS_SCSICommandReceived(USB_ClassInfo_MS_t* MSInterfaceInfo); #endif diff --git a/Demos/Device/MassStorage/makefile b/Demos/Device/MassStorage/makefile index 93f895727c..c4adfc9bea 100644 --- a/Demos/Device/MassStorage/makefile +++ b/Demos/Device/MassStorage/makefile @@ -127,7 +127,6 @@ SRC = $(TARGET).c \ Descriptors.c \ Lib/SCSI.c \ Lib/DataflashManager.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.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/USBTask.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.) @@ -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 += -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 += -DINTERRUPT_CONTROL_ENDPOINT # Place -D or -U options here for ASM sources diff --git a/Demos/Device/Mouse/Descriptors.h b/Demos/Device/Mouse/Descriptors.h index 883ef31e82..ef3215ca62 100644 --- a/Demos/Device/Mouse/Descriptors.h +++ b/Demos/Device/Mouse/Descriptors.h @@ -37,30 +37,12 @@ #define _DESCRIPTORS_H_ /* Includes: */ - #include - #include - /* 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; + #include + #include + /* Type Defines: */ /** Type define for the device configuration descriptor structure. This must be defined in the * application code, as the configuration descriptor contains several sub-descriptors which * vary between devices, and which describe the device's usage to the host. @@ -80,12 +62,6 @@ /** Size in bytes of the Mouse HID reporting IN endpoint. */ #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: */ 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); diff --git a/Demos/Device/Mouse/Mouse.c b/Demos/Device/Mouse/Mouse.c index 32b12fc618..57c1aa1142 100644 --- a/Demos/Device/Mouse/Mouse.c +++ b/Demos/Device/Mouse/Mouse.c @@ -27,44 +27,33 @@ arising out of or in connection with the use or performance of 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" -/* Scheduler Task List */ -TASK_LIST -{ - { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, - { .Task = USB_Mouse_Report , .TaskStatus = TASK_STOP }, -}; +USB_ClassInfo_HID_t Mouse_HID_Interface = + { + .InterfaceNumber = 0, -/* Global Variables */ -/** Indicates what report mode the host has requested, true for normal HID reporting mode, false for special boot - * protocol reporting mode. - */ -bool UsingReportProtocol = true; + .ReportINEndpointNumber = MOUSE_EPNUM, + .ReportINEndpointSize = MOUSE_EPSIZE, -/** Current Idle period. This is set by the host via a Set Idle HID class request to silence the device's reports - * 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; + .ReportBufferSize = sizeof(USB_MouseReport_Data_t), + }; -/** 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; +int main(void) +{ + SetupHardware(); + + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); + for (;;) + { + USB_HID_USBTask(&Mouse_HID_Interface); + USB_USBTask(); + } +} -/** 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) +void SetupHardware(void) { /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); @@ -77,284 +66,64 @@ int main(void) Joystick_Init(); LEDs_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(); - - /* 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) { - /* Start USB management task */ - Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); - - /* Indicate USB enumerating */ - UpdateStatus(Status_USBEnumerating); - - /* Default to report protocol on connect */ - UsingReportProtocol = true; + LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); } -/** 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) { - /* Stop running mouse reporting and USB management tasks */ - Scheduler_SetTaskMode(USB_Mouse_Report, TASK_STOP); - Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); - - /* Indicate USB not ready */ - UpdateStatus(Status_USBNotReady); + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); } -/** 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) { - /* Setup Mouse Report Endpoint */ - Endpoint_ConfigureEndpoint(MOUSE_EPNUM, EP_TYPE_INTERRUPT, - ENDPOINT_DIR_IN, MOUSE_EPSIZE, - ENDPOINT_BANK_SINGLE); - - /* Indicate USB connected and ready */ - UpdateStatus(Status_USBReady); + LEDs_SetAllLEDs(LEDMASK_USB_READY); - /* Start running mouse reporting task */ - Scheduler_SetTaskMode(USB_Mouse_Report, TASK_RUN); + if (!(USB_HID_ConfigureEndpoints(&Mouse_HID_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); } -/** 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) { - /* Handle HID Class specific requests */ - 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; - } + USB_HID_ProcessControlPacket(&Mouse_HID_Interface); } -/** ISR for the timer 0 compare vector. This ISR fires once each millisecond, and increments the - * scheduler elapsed idle period counter when the host has set an idle period. - */ -ISR(TIMER0_COMPA_vect, ISR_BLOCK) +void EVENT_USB_StartOfFrame(void) { - /* One millisecond has elapsed, decrement the idle time remaining counter if it has not already elapsed */ - if (IdleMSRemaining) - IdleMSRemaining--; + USB_HID_RegisterStartOfFrame(&Mouse_HID_Interface); } -/** Fills the given HID report data structure with the next HID report to send to the host. - * - * \param ReportData Pointer to a HID report data structure to be filled - */ -void CreateMouseReport(USB_MouseReport_Data_t* ReportData) +uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData) { + USB_MouseReport_Data_t* MouseReport = (USB_MouseReport_Data_t*)ReportData; + uint8_t JoyStatus_LCL = Joystick_GetStatus(); uint8_t ButtonStatus_LCL = Buttons_GetStatus(); - - /* Clear the report contents */ - memset(ReportData, 0, sizeof(USB_MouseReport_Data_t)); if (JoyStatus_LCL & JOY_UP) - ReportData->Y = -1; + MouseReport->Y = -1; else if (JoyStatus_LCL & JOY_DOWN) - ReportData->Y = 1; + MouseReport->Y = 1; if (JoyStatus_LCL & JOY_RIGHT) - ReportData->X = 1; + MouseReport->X = 1; else if (JoyStatus_LCL & JOY_LEFT) - ReportData->X = -1; + MouseReport->X = -1; if (JoyStatus_LCL & JOY_PRESS) - ReportData->Button = (1 << 0); + MouseReport->Button = (1 << 0); if (ButtonStatus_LCL & BUTTONS_BUTTON1) - ReportData->Button |= (1 << 1); -} - -/** Sends the next HID report to the host, via the keyboard data endpoint. */ -void SendNextReport(void) -{ - static USB_MouseReport_Data_t PrevMouseReportData; - 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; - } + MouseReport->Button |= (1 << 1); - /* 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(); - } + return sizeof(USB_MouseReport_Data_t); } -/** 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) +void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize) { - 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(); - } + // Unused (but mandatory for the HID class driver) in this demo, since there are no Host->Device reports } diff --git a/Demos/Device/Mouse/Mouse.h b/Demos/Device/Mouse/Mouse.h index 65879da8ef..5c8049590b 100644 --- a/Demos/Device/Mouse/Mouse.h +++ b/Demos/Device/Mouse/Mouse.h @@ -46,37 +46,12 @@ #include "Descriptors.h" - #include // Library Version Information - #include // USB Functionality - #include // Joystick driver - #include // LEDs driver - #include // Board Buttons driver - #include // Simple scheduler for task management - - /* 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 + #include + #include + #include + #include + #include + #include /* Type Defines: */ /** 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 */ } USB_MouseReport_Data_t; - /* Enums: */ - /** Enum for the possible status codes for passing to the UpdateStatus() function. */ - enum Mouse_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: */ + #define LEDMASK_USB_NOTREADY LEDS_LED1 + #define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3) + #define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4) + #define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3) /* Function Prototypes: */ + void SetupHardware(void); + void EVENT_USB_Connect(void); void EVENT_USB_Disconnect(void); void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_UnhandledControlPacket(void); + void EVENT_USB_StartOfFrame(void); - void CreateMouseReport(USB_MouseReport_Data_t* ReportData); - 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 diff --git a/Demos/Device/Mouse/makefile b/Demos/Device/Mouse/makefile index 632bf91ae6..4c18f9d4ac 100644 --- a/Demos/Device/Mouse/makefile +++ b/Demos/Device/Mouse/makefile @@ -125,7 +125,6 @@ LUFA_PATH = ../../.. # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c \ Descriptors.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.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/USBTask.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.) CPPSRC = @@ -182,7 +181,7 @@ CSTANDARD = -std=gnu99 # Place -D or -U options here for C sources 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 += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" diff --git a/Demos/Device/RNDISEthernet/Lib/ARP.h b/Demos/Device/RNDISEthernet/Lib/ARP.h index 8551df85b2..f05d8f093a 100644 --- a/Demos/Device/RNDISEthernet/Lib/ARP.h +++ b/Demos/Device/RNDISEthernet/Lib/ARP.h @@ -38,9 +38,7 @@ /* Includes: */ #include - #include - - #include + #include #include "EthernetProtocols.h" #include "Ethernet.h" diff --git a/Demos/Device/RNDISEthernet/Lib/Ethernet.c b/Demos/Device/RNDISEthernet/Lib/Ethernet.c index 3d34f716a5..57380a0822 100644 --- a/Demos/Device/RNDISEthernet/Lib/Ethernet.c +++ b/Demos/Device/RNDISEthernet/Lib/Ethernet.c @@ -38,12 +38,6 @@ #include "Ethernet.h" /* 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. */ 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 * 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 */ - 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* FrameINHeader = (Ethernet_Frame_Header_t*)&FrameIN->FrameData; + Ethernet_Frame_Header_t* FrameOUTHeader = (Ethernet_Frame_Header_t*)&FrameOUT->FrameData; int16_t RetSize = NO_RESPONSE; /* Ensure frame is addressed to either all (broadcast) or the virtual webserver, and is a type II frame */ if ((MAC_COMPARE(&FrameINHeader->Destination, &ServerMACAddress) || - MAC_COMPARE(&FrameINHeader->Destination, &BroadcastMACAddress)) && - (SwapEndian_16(FrameIN.FrameLength) > ETHERNET_VER2_MINSIZE)) + MAC_COMPARE(&FrameINHeader->Destination, &BroadcastMACAddress))) { /* Process the packet depending on its protocol */ switch (SwapEndian_16(FrameINHeader->EtherType)) { case ETHERTYPE_ARP: - RetSize = ARP_ProcessARPPacket(&FrameIN.FrameData[sizeof(Ethernet_Frame_Header_t)], - &FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t)]); + RetSize = ARP_ProcessARPPacket(&FrameIN->FrameData[sizeof(Ethernet_Frame_Header_t)], + &FrameOUT->FrameData[sizeof(Ethernet_Frame_Header_t)]); break; case ETHERTYPE_IPV4: - RetSize = IP_ProcessIPPacket(&FrameIN.FrameData[sizeof(Ethernet_Frame_Header_t)], - &FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t)]); + RetSize = IP_ProcessIPPacket(FrameIN, + &FrameIN->FrameData[sizeof(Ethernet_Frame_Header_t)], + &FrameOUT->FrameData[sizeof(Ethernet_Frame_Header_t)]); break; } @@ -100,8 +94,8 @@ void Ethernet_ProcessPacket(void) FrameOUTHeader->EtherType = FrameINHeader->EtherType; /* 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.FrameInBuffer = true; + FrameOUT->FrameLength = (sizeof(Ethernet_Frame_Header_t) + RetSize); + FrameOUT->FrameInBuffer = true; } } @@ -109,7 +103,7 @@ void Ethernet_ProcessPacket(void) if (RetSize != NO_PROCESS) { /* Clear the frame buffer */ - FrameIN.FrameInBuffer = false; + FrameIN->FrameInBuffer = false; } } diff --git a/Demos/Device/RNDISEthernet/Lib/Ethernet.h b/Demos/Device/RNDISEthernet/Lib/Ethernet.h index b360f07aed..b3002523a8 100644 --- a/Demos/Device/RNDISEthernet/Lib/Ethernet.h +++ b/Demos/Device/RNDISEthernet/Lib/Ethernet.h @@ -39,6 +39,8 @@ /* Includes: */ #include #include + + #include #include "EthernetProtocols.h" #include "ProtocolDecoders.h" @@ -50,6 +52,9 @@ #include "IP.h" /* 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 */ #define SERVER_MAC_ADDRESS {0x00, 0x01, 0x00, 0x01, 0x00, 0x01} @@ -64,12 +69,6 @@ * \return True if the addresses match, false otherwise */ #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 */ #define NO_RESPONSE 0 @@ -78,14 +77,6 @@ #define NO_PROCESS -1 /* 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 */ typedef struct { @@ -100,9 +91,6 @@ } Ethernet_Frame_Header_t; /* External Variables: */ - extern Ethernet_Frame_Info_t FrameIN; - extern Ethernet_Frame_Info_t FrameOUT; - extern const MAC_Address_t ServerMACAddress; extern const IP_Address_t ServerIPAddress; extern const MAC_Address_t BroadcastMACAddress; @@ -110,7 +98,7 @@ extern const IP_Address_t ClientIPAddress; /* 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); #endif diff --git a/Demos/Device/RNDISEthernet/Lib/EthernetProtocols.h b/Demos/Device/RNDISEthernet/Lib/EthernetProtocols.h index 3ff3433ae8..1ec5961e11 100644 --- a/Demos/Device/RNDISEthernet/Lib/EthernetProtocols.h +++ b/Demos/Device/RNDISEthernet/Lib/EthernetProtocols.h @@ -71,13 +71,7 @@ #define PROTOCOL_OSPF 89 #define PROTOCOL_SCTP 132 - /* 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 Defines: */ /** Type define for a protocol IP address of a device on a network */ typedef struct { diff --git a/Demos/Device/RNDISEthernet/Lib/ICMP.c b/Demos/Device/RNDISEthernet/Lib/ICMP.c index da4ffcfa18..ba6e1db681 100644 --- a/Demos/Device/RNDISEthernet/Lib/ICMP.c +++ b/Demos/Device/RNDISEthernet/Lib/ICMP.c @@ -45,7 +45,7 @@ * * \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* ICMPHeaderOUT = (ICMP_Header_t*)OutDataStart; @@ -62,7 +62,7 @@ int16_t ICMP_ProcessICMPPacket(void* InDataStart, void* OutDataStart) ICMPHeaderOUT->Id = ICMPHeaderIN->Id; 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 */ memcpy(&((uint8_t*)OutDataStart)[sizeof(ICMP_Header_t)], diff --git a/Demos/Device/RNDISEthernet/Lib/ICMP.h b/Demos/Device/RNDISEthernet/Lib/ICMP.h index b20a557e9c..56749c09c0 100644 --- a/Demos/Device/RNDISEthernet/Lib/ICMP.h +++ b/Demos/Device/RNDISEthernet/Lib/ICMP.h @@ -75,6 +75,6 @@ } ICMP_Header_t; /* Function Prototypes: */ - int16_t ICMP_ProcessICMPPacket(void* InDataStart, void* OutDataStart); + int16_t ICMP_ProcessICMPPacket(Ethernet_Frame_Info_t* FrameIN, void* InDataStart, void* OutDataStart); #endif diff --git a/Demos/Device/RNDISEthernet/Lib/IP.c b/Demos/Device/RNDISEthernet/Lib/IP.c index 8fb0b446d7..08500450cd 100644 --- a/Demos/Device/RNDISEthernet/Lib/IP.c +++ b/Demos/Device/RNDISEthernet/Lib/IP.c @@ -46,7 +46,7 @@ * response was generated, NO_PROCESS if the packet processing was deferred until the * 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); @@ -69,7 +69,8 @@ int16_t IP_ProcessIPPacket(void* InDataStart, void* OutDataStart) switch (IPHeaderIN->Protocol) { 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)]); break; case PROTOCOL_TCP: diff --git a/Demos/Device/RNDISEthernet/Lib/IP.h b/Demos/Device/RNDISEthernet/Lib/IP.h index fc1a46aefc..f77c772d87 100644 --- a/Demos/Device/RNDISEthernet/Lib/IP.h +++ b/Demos/Device/RNDISEthernet/Lib/IP.h @@ -88,6 +88,6 @@ } IP_Header_t; /* Function Prototypes: */ - int16_t IP_ProcessIPPacket(void* InDataStart, void* OutDataStart); + int16_t IP_ProcessIPPacket(Ethernet_Frame_Info_t* FrameIN, void* InDataStart, void* OutDataStart); #endif diff --git a/Demos/Device/RNDISEthernet/Lib/RNDIS.c b/Demos/Device/RNDISEthernet/Lib/RNDIS.c deleted file mode 100644 index c5202bcd10..0000000000 --- a/Demos/Device/RNDISEthernet/Lib/RNDIS.c +++ /dev/null @@ -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; - } -} diff --git a/Demos/Device/RNDISEthernet/Lib/TCP.c b/Demos/Device/RNDISEthernet/Lib/TCP.c index f259aad023..1ebd154358 100644 --- a/Demos/Device/RNDISEthernet/Lib/TCP.c +++ b/Demos/Device/RNDISEthernet/Lib/TCP.c @@ -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 * 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. */ @@ -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 */ - if (FrameOUT.FrameInBuffer) + if (RNDISInterfaceInfo->FrameOUT.FrameInBuffer) return; /* 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) && (ConnectionStateTable[CSTableEntry].Info.Buffer.Ready)) { - Ethernet_Frame_Header_t* FrameOUTHeader = (Ethernet_Frame_Header_t*)&FrameOUT.FrameData; - IP_Header_t* IPHeaderOUT = (IP_Header_t*)&FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t)]; - TCP_Header_t* TCPHeaderOUT = (TCP_Header_t*)&FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t) + - sizeof(IP_Header_t)]; - void* TCPDataOUT = &FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t) + - sizeof(IP_Header_t) + - sizeof(TCP_Header_t)]; + Ethernet_Frame_Header_t* FrameOUTHeader = (Ethernet_Frame_Header_t*)&RNDISInterfaceInfo->FrameOUT.FrameData; + IP_Header_t* IPHeaderOUT = (IP_Header_t*)&RNDISInterfaceInfo->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)]; + void* TCPDataOUT = &RNDISInterfaceInfo->FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t) + + sizeof(IP_Header_t) + + sizeof(TCP_Header_t)]; uint16_t PacketSize = ConnectionStateTable[CSTableEntry].Info.Buffer.Length; @@ -145,8 +145,8 @@ TASK(TCP_Task) PacketSize += sizeof(Ethernet_Frame_Header_t); /* Set the response length in the buffer and indicate that a response is ready to be sent */ - FrameOUT.FrameLength = PacketSize; - FrameOUT.FrameInBuffer = true; + RNDISInterfaceInfo->FrameOUT.FrameLength = PacketSize; + RNDISInterfaceInfo->FrameOUT.FrameInBuffer = true; ConnectionStateTable[CSTableEntry].Info.Buffer.Ready = false; diff --git a/Demos/Device/RNDISEthernet/Lib/TCP.h b/Demos/Device/RNDISEthernet/Lib/TCP.h index d4b72a519e..3448245ed2 100644 --- a/Demos/Device/RNDISEthernet/Lib/TCP.h +++ b/Demos/Device/RNDISEthernet/Lib/TCP.h @@ -38,9 +38,7 @@ /* Includes: */ #include - #include - - #include + #include #include "EthernetProtocols.h" #include "Ethernet.h" @@ -229,14 +227,12 @@ uint16_t Checksum; /**< TCP checksum */ uint16_t UrgentPointer; /**< Urgent data pointer */ } TCP_Header_t; - - /* Tasks: */ - TASK(TCP_Task); /* External Variables: */ TCP_PortState_t PortStateTable[MAX_OPEN_TCP_PORTS]; /* Function Prototypes: */ + void TCP_TCPTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); void TCP_Init(void); bool TCP_SetPortState(uint16_t Port, uint8_t State, void (*Handler)(TCP_ConnectionState_t*, TCP_ConnectionBuffer_t*)); uint8_t TCP_GetPortState(uint16_t Port); diff --git a/Demos/Device/RNDISEthernet/RNDISEthernet.c b/Demos/Device/RNDISEthernet/RNDISEthernet.c index b046f78703..3246cd8bc8 100644 --- a/Demos/Device/RNDISEthernet/RNDISEthernet.c +++ b/Demos/Device/RNDISEthernet/RNDISEthernet.c @@ -28,27 +28,50 @@ 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" -/* Scheduler Task List */ -TASK_LIST -{ - { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, - { .Task = Ethernet_Task , .TaskStatus = TASK_STOP }, - { .Task = TCP_Task , .TaskStatus = TASK_STOP }, - { .Task = RNDIS_Task , .TaskStatus = TASK_STOP }, -}; +USB_ClassInfo_RNDIS_t Ethernet_RNDIS_Interface = + { + .ControlInterfaceNumber = 0, -/** Main program entry point. This routine configures the hardware required by the application, then - * starts the scheduler to run the USB management task. - */ + .DataINEndpointNumber = CDC_TX_EPNUM, + .DataINEndpointSize = CDC_TXRX_EPSIZE, + + .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}, + }; + 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 */ MCUSR &= ~(1 << WDRF); @@ -60,279 +83,32 @@ int main(void) /* Hardware Initialization */ LEDs_Init(); 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(); - /* Scheduling - routine never returns, so put this last in the main function */ - Scheduler_Start(); + /* Initialize TCP and Webserver modules */ + 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) { - /* Start USB management task */ - Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); - - /* Indicate USB enumerating */ - UpdateStatus(Status_USBEnumerating); + LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); } -/** 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) { - /* Stop running TCP/IP and USB management tasks */ - 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); + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); } -/** 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) { - /* Setup CDC Notification, Rx and Tx Endpoints */ - Endpoint_ConfigureEndpoint(CDC_TX_EPNUM, EP_TYPE_BULK, - ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE, - ENDPOINT_BANK_SINGLE); + LEDs_SetAllLEDs(LEDMASK_USB_READY); - Endpoint_ConfigureEndpoint(CDC_RX_EPNUM, EP_TYPE_BULK, - ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE, - 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); + if (!(USB_RNDIS_ConfigureEndpoints(&Ethernet_RNDIS_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); } -/** 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) { - /* Process RNDIS class commands */ - 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); - } + USB_RNDIS_ProcessControlPacket(&Ethernet_RNDIS_Interface); } diff --git a/Demos/Device/RNDISEthernet/RNDISEthernet.h b/Demos/Device/RNDISEthernet/RNDISEthernet.h index 703af4003c..bc5004205b 100644 --- a/Demos/Device/RNDISEthernet/RNDISEthernet.h +++ b/Demos/Device/RNDISEthernet/RNDISEthernet.h @@ -45,56 +45,34 @@ #include #include "Descriptors.h" - - #include "Lib/RNDIS.h" + #include "Lib/Ethernet.h" #include "Lib/TCP.h" #include "Lib/ARP.h" #include "Lib/Webserver.h" - #include // Library Version Information - #include // USB Functionality - #include // LEDs driver - #include // Simple scheduler for task management - #include // Serial stream driver - - /* Macros: */ - /** Notification value to indicate that a frame is ready to be read by the host. */ - #define NOTIF_RESPONSE_AVAILABLE 0x01 + #include + #include + #include + #include + #include - /* Type Defines: */ - /** Type define for a RNDIS notification message, for transmission to the RNDIS host via the notification - * 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 */ - }; + /* Macros: */ + #define LEDMASK_USB_NOTREADY LEDS_LED1 + #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 - /* Tasks: */ - TASK(RNDIS_Task); - TASK(Ethernet_Task); - /* Function Prototypes: */ + void SetupHardware(void); + void EVENT_USB_Connect(void); void EVENT_USB_Disconnect(void); void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_UnhandledControlPacket(void); - - void UpdateStatus(uint8_t CurrentStatus); + void EVENT_USB_StartOfFrame(void); + + void CALLBACK_USB_RNDIS_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); #endif diff --git a/Demos/Device/RNDISEthernet/makefile b/Demos/Device/RNDISEthernet/makefile index f40c37b05a..3bcc37c8e4 100644 --- a/Demos/Device/RNDISEthernet/makefile +++ b/Demos/Device/RNDISEthernet/makefile @@ -125,7 +125,6 @@ LUFA_PATH = ../../.. # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c \ Descriptors.c \ - Lib/RNDIS.c \ Lib/Ethernet.c \ Lib/ProtocolDecoders.c \ Lib/ICMP.c \ @@ -135,7 +134,6 @@ SRC = $(TARGET).c \ Lib/ARP.c \ Lib/IP.c \ Lib/Webserver.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/Peripheral/SerialStream.c \ $(LUFA_PATH)/LUFA/Drivers/Peripheral/Serial.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/USBTask.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.) @@ -195,7 +193,7 @@ CSTANDARD = -std=gnu99 # Place -D or -U options here for C sources 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 += -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 diff --git a/Demos/Device/USBtoSerial/Descriptors.h b/Demos/Device/USBtoSerial/Descriptors.h index 41b44300ac..9e372e35b7 100644 --- a/Demos/Device/USBtoSerial/Descriptors.h +++ b/Demos/Device/USBtoSerial/Descriptors.h @@ -37,26 +37,12 @@ #define _DESCRIPTORS_H_ /* Includes: */ - #include - #include + #include + #include + /* Macros: */ - /** Macro to define a CDC class-specific functional descriptor. CDC functional descriptors have a - * uniform structure but variable sized data payloads, thus cannot be represented accurately by - * a single typedef struct. A macro is used instead so that functional descriptors can be created - * easily by specifying the size of the payload. This allows sizeof() to work correctly. - * - * \param DataSize Size in bytes of the CDC functional descriptor's data payload - */ - #define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \ - struct \ - { \ - USB_Descriptor_Header_t Header; \ - uint8_t SubType; \ - uint8_t Data[DataSize]; \ - } - /** Endpoint number of the CDC device-to-host notification IN endpoint. */ #define CDC_NOTIFICATION_EPNUM 2 diff --git a/Demos/Device/USBtoSerial/USBtoSerial.c b/Demos/Device/USBtoSerial/USBtoSerial.c index 7cef56560a..7c89278ef7 100644 --- a/Demos/Device/USBtoSerial/USBtoSerial.c +++ b/Demos/Device/USBtoSerial/USBtoSerial.c @@ -30,37 +30,54 @@ #include "USBtoSerial.h" -/* Scheduler Task List */ -TASK_LIST -{ - { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, - { .Task = CDC_Task , .TaskStatus = TASK_STOP }, -}; +RingBuff_t Rx_Buffer; +RingBuff_t Tx_Buffer; -/* 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 }; +USB_ClassInfo_CDC_t VirtualSerial_CDC_Interface = + { + .ControlInterfaceNumber = 0, -/** Ring (circular) buffer to hold the RX data - data from the host to the attached device on the serial port. */ -RingBuff_t Rx_Buffer; + .DataINEndpointNumber = CDC_TX_EPNUM, + .DataINEndpointSize = CDC_TXRX_EPSIZE, -/** Ring (circular) buffer to hold the TX data - data from the attached device on the serial port to the host. */ -RingBuff_t Tx_Buffer; + .DataOUTEndpointNumber = CDC_RX_EPNUM, + .DataOUTEndpointSize = CDC_TXRX_EPSIZE, -/** Flag to indicate if the USART is currently transmitting data from the Rx_Buffer circular buffer. */ -volatile bool Transmitting = false; + .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) +{ + 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 */ MCUSR &= ~(1 << WDRF); @@ -70,304 +87,61 @@ int main(void) clock_prescale_set(clock_div_1); /* Hardware Initialization */ + Joystick_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(); - - /* 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) { - /* Start USB management task */ - Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); - - /* Indicate USB enumerating */ - UpdateStatus(Status_USBEnumerating); + LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); } -/** 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); - - /* Reset Tx and Rx buffers, device disconnected */ - Buffer_Initialize(&Rx_Buffer); - Buffer_Initialize(&Tx_Buffer); - - /* Indicate USB not ready */ - UpdateStatus(Status_USBNotReady); + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); } -/** 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); + LEDs_SetAllLEDs(LEDMASK_USB_READY); - 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); + if (!(USB_CDC_ConfigureEndpoints(&VirtualSerial_CDC_Interface))) + LEDs_SetAllLEDs(LEDMASK_USB_ERROR); } -/** 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(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(); - } - } - } + USB_CDC_ProcessControlPacket(&VirtualSerial_CDC_Interface); } -/** 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) { - /* Only store received characters if the USB interface is connected */ if (USB_IsConnected) - { - /* Character received, store it into the buffer */ - Buffer_StoreElement(&Tx_Buffer, UDR1); - } + 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 - * 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) +void EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo) { uint8_t ConfigMask = 0; - /* Determine parity - non odd/even parity mode defaults to no parity */ - if (LineCoding.ParityType == Parity_Odd) + if (CDCInterfaceInfo->LineEncoding.ParityType == Parity_Odd) ConfigMask = ((1 << UPM11) | (1 << UPM10)); - else if (LineCoding.ParityType == Parity_Even) + else if (CDCInterfaceInfo->LineEncoding.ParityType == Parity_Even) ConfigMask = (1 << UPM11); - /* Determine stop bits - 1.5 stop bits is set as 1 stop bit due to hardware limitations */ - if (LineCoding.CharFormat == TwoStopBits) + if (CDCInterfaceInfo->LineEncoding.CharFormat == TwoStopBits) ConfigMask |= (1 << USBS1); - /* Determine data size - 5, 6, 7, or 8 bits are supported */ - if (LineCoding.DataBits == 6) + if (CDCInterfaceInfo->LineEncoding.DataBits == 6) ConfigMask |= (1 << UCSZ10); - else if (LineCoding.DataBits == 7) + else if (CDCInterfaceInfo->LineEncoding.DataBits == 7) ConfigMask |= (1 << UCSZ11); - else if (LineCoding.DataBits == 8) + else if (CDCInterfaceInfo->LineEncoding.DataBits == 8) ConfigMask |= ((1 << UCSZ11) | (1 << UCSZ10)); - /* Enable double speed, gives better error percentages at 8MHz */ - UCSR1A = (1 << U2X1); - - /* Enable transmit and receive modules and interrupts */ + UCSR1A = (1 << U2X1); UCSR1B = ((1 << RXCIE1) | (1 << TXEN1) | (1 << RXEN1)); - - /* Set the USART mode to the mask generated by the Line Coding options */ - UCSR1C = ConfigMask; - - /* Set the USART baud rate register to the desired baud rate value */ - UBRR1 = SERIAL_2X_UBBRVAL((uint16_t)LineCoding.BaudRateBPS); + UCSR1C = ConfigMask; + UBRR1 = SERIAL_2X_UBBRVAL((uint16_t)CDCInterfaceInfo->LineEncoding.BaudRateBPS); } diff --git a/Demos/Device/USBtoSerial/USBtoSerial.h b/Demos/Device/USBtoSerial/USBtoSerial.h index 8e7e8aed8c..7ff796e708 100644 --- a/Demos/Device/USBtoSerial/USBtoSerial.h +++ b/Demos/Device/USBtoSerial/USBtoSerial.h @@ -46,140 +46,28 @@ #include "Lib/RingBuff.h" - #include // Library Version Information - #include // USB Functionality - #include // USART driver - #include // LEDs driver - #include // Simple scheduler for task management + #include + #include + #include + #include + #include + #include /* 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) + #define LEDMASK_USB_NOTREADY LEDS_LED1 + #define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3) + #define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4) + #define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3) - /** 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: */ + void SetupHardware(void); + void EVENT_USB_Connect(void); void EVENT_USB_Disconnect(void); void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_UnhandledControlPacket(void); - - void ReconfigureUSART(void); - void UpdateStatus(uint8_t CurrentStatus); + void EVENT_USB_StartOfFrame(void); + + void EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo); #endif diff --git a/Demos/Device/USBtoSerial/makefile b/Demos/Device/USBtoSerial/makefile index 708e872463..5cf9c617eb 100644 --- a/Demos/Device/USBtoSerial/makefile +++ b/Demos/Device/USBtoSerial/makefile @@ -126,7 +126,6 @@ LUFA_PATH = ../../.. SRC = $(TARGET).c \ Descriptors.c \ Lib/RingBuff.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.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/USBTask.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.) @@ -184,7 +183,7 @@ CSTANDARD = -std=gnu99 # Place -D or -U options here for C sources 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 += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" diff --git a/Demos/Host/GenericHIDHost/makefile b/Demos/Host/GenericHIDHost/makefile index b17ae16417..b912b2ff8d 100644 --- a/Demos/Host/GenericHIDHost/makefile +++ b/Demos/Host/GenericHIDHost/makefile @@ -138,7 +138,7 @@ SRC = $(TARGET).c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.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.) diff --git a/Demos/Host/MassStorageHost/Lib/MassStoreCommands.c b/Demos/Host/MassStorageHost/Lib/MassStoreCommands.c index 95aafca8c7..f47e9f5ed9 100644 --- a/Demos/Host/MassStorageHost/Lib/MassStoreCommands.c +++ b/Demos/Host/MassStorageHost/Lib/MassStoreCommands.c @@ -119,10 +119,10 @@ static uint8_t MassStore_WaitForDataReceived(void) while (!(Pipe_IsINReceived())) { /* 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 */ - USB_INT_Clear(USB_INT_HSOFI); + FrameElapsed = false; TimeoutMSRem--; /* Check to see if the timeout period for the command has elapsed */ diff --git a/Demos/Host/StillImageHost/Lib/StillImageCommands.c b/Demos/Host/StillImageHost/Lib/StillImageCommands.c index 8f05e48f4a..f2f666bd13 100644 --- a/Demos/Host/StillImageHost/Lib/StillImageCommands.c +++ b/Demos/Host/StillImageHost/Lib/StillImageCommands.c @@ -109,10 +109,10 @@ uint8_t SImage_RecieveBlockHeader(void) while (!(Pipe_IsReadWriteAllowed())) { /* 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 */ - USB_INT_Clear(USB_INT_HSOFI); + FrameElapsed = false; TimeoutMSRem--; /* Check to see if the timeout period for the command has elapsed */ diff --git a/Demos/OTG/TestApp/TestApp.h b/Demos/OTG/TestApp/TestApp.h index de4d52612e..7ae5663d91 100644 --- a/Demos/OTG/TestApp/TestApp.h +++ b/Demos/OTG/TestApp/TestApp.h @@ -45,7 +45,6 @@ #include // Library Version Information #include // USB Functionality #include // Simple scheduler for task management - #include // Auto-defragmenting Dynamic Memory allocation #include // ANSI Terminal Escape Codes #include // ADC driver #include // USART Stream driver diff --git a/Demos/OTG/TestApp/makefile b/Demos/OTG/TestApp/makefile index dd6d8f43f4..a8bf4ac424 100644 --- a/Demos/OTG/TestApp/makefile +++ b/Demos/OTG/TestApp/makefile @@ -127,7 +127,6 @@ SRC = $(TARGET).c \ TestEvents.c \ Descriptors.c \ $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ - $(LUFA_PATH)/LUFA/MemoryAllocator/DynAlloc.c \ $(LUFA_PATH)/LUFA/Drivers/Board/Temperature.c \ $(LUFA_PATH)/LUFA/Drivers/Peripheral/SerialStream.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/USBTask.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.) @@ -189,7 +187,6 @@ CSTANDARD = -std=gnu99 # Place -D or -U options here for C sources CDEFS = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -CDEFS += -DNUM_BLOCKS=100 -DBLOCK_SIZE=8 -DNUM_HANDLES=20 # Place -D or -U options here for ASM sources diff --git a/LUFA.pnproj b/LUFA.pnproj index 235ccfa3b9..ae38c0bb96 100644 --- a/LUFA.pnproj +++ b/LUFA.pnproj @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/LUFA/ChangeLog.txt b/LUFA/ChangeLog.txt index ac675348bf..fe3b633609 100644 --- a/LUFA/ChangeLog.txt +++ b/LUFA/ChangeLog.txt @@ -4,6 +4,14 @@ * 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 * * \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 * - 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 + * - 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 diff --git a/LUFA/DirectorySummaries.txt b/LUFA/DirectorySummaries.txt index f439847608..3fae9c18ee 100644 --- a/LUFA/DirectorySummaries.txt +++ b/LUFA/DirectorySummaries.txt @@ -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 * 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 * \brief Library hardware and software drivers. * diff --git a/LUFA/Drivers/USB/Class/Device/Audio.c b/LUFA/Drivers/USB/Class/Device/Audio.c new file mode 100644 index 0000000000..b0800ba0f6 --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/Audio.c @@ -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(); +} diff --git a/LUFA/Drivers/USB/Class/Device/Audio.h b/LUFA/Drivers/USB/Class/Device/Audio.h new file mode 100644 index 0000000000..aa7b4069c6 --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/Audio.h @@ -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 + + /* 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 diff --git a/LUFA/Drivers/USB/Class/Device/CDC.c b/LUFA/Drivers/USB/Class/Device/CDC.c new file mode 100644 index 0000000000..8acaac7a1c --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/CDC.c @@ -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(); +} diff --git a/LUFA/Drivers/USB/Class/Device/CDC.h b/LUFA/Drivers/USB/Class/Device/CDC.h new file mode 100644 index 0000000000..bbe1c9838d --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/CDC.h @@ -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 + + /* 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 diff --git a/LUFA/Drivers/USB/Class/Device/HID.c b/LUFA/Drivers/USB/Class/Device/HID.c new file mode 100644 index 0000000000..fbc5e3a5c9 --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/HID.c @@ -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(); + } + } +} diff --git a/LUFA/Drivers/USB/Class/Device/HID.h b/LUFA/Drivers/USB/Class/Device/HID.h new file mode 100644 index 0000000000..8fdeb064a0 --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/HID.h @@ -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 + + /* 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 diff --git a/LUFA/Drivers/USB/Class/Device/MassStorage.c b/LUFA/Drivers/USB/Class/Device/MassStorage.c new file mode 100644 index 0000000000..1c41f6046d --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/MassStorage.c @@ -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; +} diff --git a/LUFA/Drivers/USB/Class/Device/MassStorage.h b/LUFA/Drivers/USB/Class/Device/MassStorage.h new file mode 100644 index 0000000000..c1874b218e --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/MassStorage.h @@ -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 + + /* 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 diff --git a/LUFA/Drivers/USB/Class/Device/RNDIS.c b/LUFA/Drivers/USB/Class/Device/RNDIS.c new file mode 100644 index 0000000000..49c7df01da --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/RNDIS.c @@ -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; + } +} diff --git a/Demos/Device/RNDISEthernet/Lib/RNDIS.h b/LUFA/Drivers/USB/Class/Device/RNDIS.h similarity index 65% rename from Demos/Device/RNDISEthernet/Lib/RNDIS.h rename to LUFA/Drivers/USB/Class/Device/RNDIS.h index 88c9a9eb95..73622a4dc0 100644 --- a/Demos/Device/RNDISEthernet/Lib/RNDIS.h +++ b/LUFA/Drivers/USB/Class/Device/RNDIS.h @@ -28,26 +28,16 @@ this software. */ -/** \file - * - * Header file for RNDIS.c. - */ - -#ifndef _RNDIS_H_ -#define _RNDIS_H_ +#ifndef _RNDIS_CLASS_H_ +#define _RNDIS_CLASS_H_ /* Includes: */ - #include - #include - - #include "RNDISEthernet.h" + #include + + #include "../../USB.h" #include "RNDISConstants.h" - #include "Ethernet.h" - + /* Macros: */ - /** Physical MAC Address of the USB network adapter */ - #define ADAPTER_MAC_ADDRESS {0x02, 0x00, 0x02, 0x00, 0x02, 0x00} - /** Implemented RNDIS Version Major */ #define REMOTE_NDIS_VERSION_MAJOR 0x01 @@ -60,6 +50,12 @@ /** RNDIS request to issue a device-to-host NDIS response */ #define REQ_GetEncapsulatedResponse 0x01 + #define RNDIS_MESSAGE_BUFFER_SIZE 128 + + #define ETHERNET_FRAME_SIZE_MAX 1500 + + #define NOTIF_ResponseAvailable 1 + /* Enums: */ /** Enum for the possible NDIS adapter states. */ enum RNDIS_States_t @@ -78,8 +74,14 @@ NdisHardwareStatusClosing, /**< Hardware currently closing */ NdisHardwareStatusNotReady /**< Hardware not ready to accept commands from the host */ }; - + /* 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 */ typedef struct { @@ -87,6 +89,14 @@ uint32_t MessageLength; /**< Total length of the RNDIS message, in bytes */ } 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 */ typedef struct { @@ -102,7 +112,31 @@ uint32_t VcHandle; uint32_t Reserved; } 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 */ typedef struct { @@ -208,19 +242,19 @@ uint32_t InformationBufferOffset; } 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: */ - void ProcessRNDISControlMessage(void); - - #if defined(INCLUDE_FROM_RNDIS_C) - static bool ProcessNDISQuery(uint32_t OId, void* QueryData, uint16_t QuerySize, - void* ResponseData, uint16_t* ResponseSize); - static bool ProcessNDISSet(uint32_t OId, void* SetData, uint16_t SetSize); + #if defined(INCLUDE_FROM_RNDIS_CLASS_C) + static void USB_RNDIS_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); + static bool USB_RNDIS_ProcessNDISQuery(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, + uint32_t OId, void* QueryData, uint16_t QuerySize, + void* ResponseData, uint16_t* ResponseSize); + static bool USB_RNDIS_ProcessNDISSet(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, uint32_t OId, + void* SetData, uint16_t SetSize); #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 diff --git a/Demos/Device/RNDISEthernet/Lib/RNDISConstants.h b/LUFA/Drivers/USB/Class/Device/RNDISConstants.h similarity index 100% rename from Demos/Device/RNDISEthernet/Lib/RNDISConstants.h rename to LUFA/Drivers/USB/Class/Device/RNDISConstants.h diff --git a/LUFA/Drivers/USB/Class/HIDParser.c b/LUFA/Drivers/USB/Class/Host/HIDParser.c similarity index 100% rename from LUFA/Drivers/USB/Class/HIDParser.c rename to LUFA/Drivers/USB/Class/Host/HIDParser.c diff --git a/LUFA/Drivers/USB/Class/HIDParser.h b/LUFA/Drivers/USB/Class/Host/HIDParser.h similarity index 97% rename from LUFA/Drivers/USB/Class/HIDParser.h rename to LUFA/Drivers/USB/Class/Host/HIDParser.h index 49e57c2958..4acce2462e 100644 --- a/LUFA/Drivers/USB/Class/HIDParser.h +++ b/LUFA/Drivers/USB/Class/Host/HIDParser.h @@ -63,7 +63,7 @@ #include "HIDReportData.h" - #include "../../../Common/Common.h" + #include "../../../../Common/Common.h" /* Enable C linkage for C++ Compilers: */ #if defined(__cplusplus) diff --git a/LUFA/Drivers/USB/Class/HIDReportData.h b/LUFA/Drivers/USB/Class/Host/HIDReportData.h similarity index 100% rename from LUFA/Drivers/USB/Class/HIDReportData.h rename to LUFA/Drivers/USB/Class/Host/HIDReportData.h diff --git a/LUFA/Drivers/USB/HighLevel/Events.h b/LUFA/Drivers/USB/HighLevel/Events.h index e6d2beaa77..ded027b12e 100644 --- a/LUFA/Drivers/USB/HighLevel/Events.h +++ b/LUFA/Drivers/USB/HighLevel/Events.h @@ -267,6 +267,11 @@ * \ref Group_USBManagement documentation). */ 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 /* 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_WakeUp(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 diff --git a/LUFA/Drivers/USB/HighLevel/USBInterrupt.c b/LUFA/Drivers/USB/HighLevel/USBInterrupt.c index 0b9d082236..0ccbe61557 100644 --- a/LUFA/Drivers/USB/HighLevel/USBInterrupt.c +++ b/LUFA/Drivers/USB/HighLevel/USBInterrupt.c @@ -180,6 +180,15 @@ ISR(USB_GEN_vect, ISR_BLOCK) 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 #if defined(USB_CAN_BE_HOST) @@ -232,6 +241,15 @@ ISR(USB_GEN_vect, ISR_BLOCK) 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 #if defined(USB_CAN_BE_BOTH) diff --git a/LUFA/Drivers/USB/HighLevel/USBTask.c b/LUFA/Drivers/USB/HighLevel/USBTask.c index e2b7e91d50..46fcd57096 100644 --- a/LUFA/Drivers/USB/HighLevel/USBTask.c +++ b/LUFA/Drivers/USB/HighLevel/USBTask.c @@ -42,7 +42,7 @@ USB_Request_Header_t USB_ControlRequest; volatile uint8_t USB_HostState; #endif -TASK(USB_USBTask) +void USB_USBTask(void) { #if defined(USB_HOST_ONLY) USB_HostTask(); diff --git a/LUFA/Drivers/USB/HighLevel/USBTask.h b/LUFA/Drivers/USB/HighLevel/USBTask.h index 1e1209a5f3..e4c8a02ae5 100644 --- a/LUFA/Drivers/USB/HighLevel/USBTask.h +++ b/LUFA/Drivers/USB/HighLevel/USBTask.h @@ -38,7 +38,6 @@ #include #include - #include "../../../Scheduler/Scheduler.h" #include "../LowLevel/LowLevel.h" #include "StdRequestType.h" #include "USBMode.h" @@ -122,11 +121,11 @@ extern volatile uint8_t USB_HostState; #endif - /* Tasks: */ + /* Function Prototypes: */ /** 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 * 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 task may be serviced at all times, or (for minimum CPU consumption): @@ -145,7 +144,7 @@ * * \ingroup Group_USBManagement */ - TASK(USB_USBTask); + void USB_USBTask(void); /* Private Interface - For use in library only: */ #if !defined(__DOXYGEN__) diff --git a/LUFA/Drivers/USB/LowLevel/Endpoint.c b/LUFA/Drivers/USB/LowLevel/Endpoint.c index 099022c1cf..d02071bbd5 100644 --- a/LUFA/Drivers/USB/LowLevel/Endpoint.c +++ b/LUFA/Drivers/USB/LowLevel/Endpoint.c @@ -80,8 +80,6 @@ uint8_t Endpoint_WaitUntilReady(void) uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS; #endif - USB_INT_Clear(USB_INT_SOFI); - for (;;) { if (Endpoint_GetEndpointDirection() == ENDPOINT_DIR_IN) @@ -100,9 +98,9 @@ uint8_t Endpoint_WaitUntilReady(void) else if (Endpoint_IsStalled()) return ENDPOINT_READYWAIT_EndpointStalled; - if (USB_INT_HasOccurred(USB_INT_SOFI)) + if (FrameElapsed) { - USB_INT_Clear(USB_INT_SOFI); + FrameElapsed = false; if (!(TimeoutMSRem--)) return ENDPOINT_READYWAIT_Timeout; diff --git a/LUFA/Drivers/USB/LowLevel/Host.c b/LUFA/Drivers/USB/LowLevel/Host.c index b606515e60..02a1c2171c 100644 --- a/LUFA/Drivers/USB/LowLevel/Host.c +++ b/LUFA/Drivers/USB/LowLevel/Host.c @@ -210,14 +210,13 @@ uint8_t USB_Host_WaitMS(uint8_t MS) bool BusSuspended = USB_Host_IsBusSuspended(); uint8_t ErrorCode = HOST_WAITERROR_Successful; - USB_INT_Clear(USB_INT_HSOFI); USB_Host_ResumeBus(); while (MS) { - if (USB_INT_HasOccurred(USB_INT_HSOFI)) + if (FrameElapsed) { - USB_INT_Clear(USB_INT_HSOFI); + FrameElapsed = false; MS--; } @@ -260,9 +259,10 @@ static void USB_Host_ResetDevice(void) USB_Host_ResetBus(); while (!(USB_Host_IsBusResetComplete())); - USB_INT_Clear(USB_INT_HSOFI); USB_Host_ResumeBus(); + FrameElapsed = false; + for (uint8_t MSRem = 10; MSRem != 0; MSRem--) { /* 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 present. */ - if (USB_INT_HasOccurred(USB_INT_HSOFI)) + if (FrameElapsed) { + FrameElapsed = false; + USB_INT_Clear(USB_INT_DDISCI); break; } diff --git a/LUFA/Drivers/USB/LowLevel/LowLevel.c b/LUFA/Drivers/USB/LowLevel/LowLevel.c index 8b395be98c..255a6ef299 100644 --- a/LUFA/Drivers/USB/LowLevel/LowLevel.c +++ b/LUFA/Drivers/USB/LowLevel/LowLevel.c @@ -38,6 +38,8 @@ volatile uint8_t USB_CurrentMode = USB_MODE_NONE; volatile uint8_t USB_Options; #endif +volatile bool FrameElapsed; + void USB_Init( #if defined(USB_CAN_BE_BOTH) const uint8_t Mode @@ -150,6 +152,8 @@ void USB_ResetInterface(void) USB_INT_DisableAllInterrupts(); USB_INT_ClearAllInterrupts(); + FrameElapsed = false; + USB_IsConnected = false; #if defined(USB_CAN_BE_HOST) @@ -224,6 +228,7 @@ void USB_ResetInterface(void) #if defined(USB_DEVICE_ONLY) USB_INT_Enable(USB_INT_SUSPEND); USB_INT_Enable(USB_INT_EORSTI); + USB_INT_Enable(USB_INT_SOFI); #if defined(CONTROL_ONLY_DEVICE) UENUM = ENDPOINT_CONTROLEP; @@ -240,11 +245,13 @@ void USB_ResetInterface(void) USB_INT_Enable(USB_INT_SRPI); USB_INT_Enable(USB_INT_BCERRI); + USB_INT_Enable(USB_INT_HSOFI); #else if (USB_CurrentMode == USB_MODE_DEVICE) { USB_INT_Enable(USB_INT_SUSPEND); USB_INT_Enable(USB_INT_EORSTI); + USB_INT_Enable(USB_INT_SOFI); #if defined(CONTROL_ONLY_DEVICE) UENUM = ENDPOINT_CONTROLEP; @@ -262,6 +269,7 @@ void USB_ResetInterface(void) USB_INT_Enable(USB_INT_SRPI); USB_INT_Enable(USB_INT_BCERRI); + USB_INT_Enable(USB_INT_HSOFI); } #endif } diff --git a/LUFA/Drivers/USB/LowLevel/LowLevel.h b/LUFA/Drivers/USB/LowLevel/LowLevel.h index 41b0ff5f67..4279ca3159 100644 --- a/LUFA/Drivers/USB/LowLevel/LowLevel.h +++ b/LUFA/Drivers/USB/LowLevel/LowLevel.h @@ -350,6 +350,9 @@ return USB_MODE_HOST; } #endif + + /* External Variables: */ + extern volatile bool FrameElapsed; #endif diff --git a/LUFA/Drivers/USB/LowLevel/Pipe.c b/LUFA/Drivers/USB/LowLevel/Pipe.c index 71a33d62f2..720da17723 100644 --- a/LUFA/Drivers/USB/LowLevel/Pipe.c +++ b/LUFA/Drivers/USB/LowLevel/Pipe.c @@ -76,8 +76,6 @@ uint8_t Pipe_WaitUntilReady(void) uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS; #endif - USB_INT_Clear(USB_INT_HSOFI); - for (;;) { if (Pipe_GetPipeToken() == PIPE_TOKEN_IN) @@ -96,9 +94,9 @@ uint8_t Pipe_WaitUntilReady(void) else if (!(USB_IsConnected)) return PIPE_READYWAIT_DeviceDisconnected; - if (USB_INT_HasOccurred(USB_INT_HSOFI)) + if (FrameElapsed) { - USB_INT_Clear(USB_INT_HSOFI); + FrameElapsed = false; if (!(TimeoutMSRem--)) return PIPE_READYWAIT_Timeout; diff --git a/LUFA/Drivers/USB/USB.h b/LUFA/Drivers/USB/USB.h index 6d66c4d143..3c8f062372 100644 --- a/LUFA/Drivers/USB/USB.h +++ b/LUFA/Drivers/USB/USB.h @@ -49,7 +49,6 @@ * - LUFA/Drivers/USB/HighLevel/USBInterrupt.c * - LUFA/Drivers/USB/HighLevel/USBTask.c * - LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c - * - LUFA/Drivers/USB/Class/HIDParser.c * * \section Module Description * Functions, macros, variables, enums and types related to the management of USB communications. @@ -97,7 +96,6 @@ #endif #include "HighLevel/ConfigDescriptor.h" - #include "Class/HIDParser.h" #endif diff --git a/LUFA/MemoryAllocator/DynAlloc.c b/LUFA/MemoryAllocator/DynAlloc.c deleted file mode 100644 index 4f1c82241b..0000000000 --- a/LUFA/MemoryAllocator/DynAlloc.c +++ /dev/null @@ -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; -} diff --git a/LUFA/MemoryAllocator/DynAlloc.h b/LUFA/MemoryAllocator/DynAlloc.h deleted file mode 100644 index acbfbd18a6..0000000000 --- a/LUFA/MemoryAllocator/DynAlloc.h +++ /dev/null @@ -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 - #include - #include - - /* 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 - -/** @} */ diff --git a/LUFA/Scheduler/Scheduler.c b/LUFA/Scheduler/Scheduler.c deleted file mode 100644 index ff8946a0d2..0000000000 --- a/LUFA/Scheduler/Scheduler.c +++ /dev/null @@ -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++; - } -} diff --git a/LUFA/Scheduler/Scheduler.h b/LUFA/Scheduler/Scheduler.h deleted file mode 100644 index 0da80bb275..0000000000 --- a/LUFA/Scheduler/Scheduler.h +++ /dev/null @@ -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 - * - * 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 - #include - - #include - - #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 - -/** @} */ diff --git a/LUFA/SchedulerOverview.txt b/LUFA/SchedulerOverview.txt deleted file mode 100644 index 5c031feac6..0000000000 --- a/LUFA/SchedulerOverview.txt +++ /dev/null @@ -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 does not need to be used 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. - */ diff --git a/LUFA/makefile b/LUFA/makefile index fc00097935..20f943aa03 100644 --- a/LUFA/makefile +++ b/LUFA/makefile @@ -15,13 +15,9 @@ LUFA_SRC_FILES = ./Drivers/USB/LowLevel/DevChapter9.c \ ./Drivers/USB/LowLevel/LowLevel.c \ ./Drivers/USB/LowLevel/Pipe.c \ ./Drivers/USB/HighLevel/Events.c \ - ./Drivers/USB/HighLevel/StdDescriptors.c \ ./Drivers/USB/HighLevel/USBInterrupt.c \ ./Drivers/USB/HighLevel/USBTask.c \ - ./Drivers/USB/Class/ConfigDescriptor.c \ - ./Drivers/USB/Class/HIDParser.c \ - ./Scheduler/Scheduler.c \ - ./MemoryAllocator/DynAlloc.c \ + ./Drivers/USB/HighLevel/ConfigDescriptor.c \ ./Drivers/Board/Temperature.c \ ./Drivers/Peripheral/Serial.c \ ./Drivers/Peripheral/SerialStream.c \ diff --git a/Projects/Magstripe/Descriptors.c b/Projects/Magstripe/Descriptors.c index 1dee58676f..52b2c098fb 100644 --- a/Projects/Magstripe/Descriptors.c +++ b/Projects/Magstripe/Descriptors.c @@ -142,7 +142,7 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .HIDSpec = VERSION_BCD(01.11), .CountryCode = 0x00, - .TotalHIDDescriptors = 1, + .TotalReportDescriptors = 1, .HIDReportType = DTYPE_Report, .HIDReportLength = sizeof(KeyboardReport) }, diff --git a/Projects/Magstripe/Descriptors.h b/Projects/Magstripe/Descriptors.h index 9948085a54..0fff2c2a84 100644 --- a/Projects/Magstripe/Descriptors.h +++ b/Projects/Magstripe/Descriptors.h @@ -38,34 +38,12 @@ #define _DESCRIPTORS_H_ /* Includes: */ - #include - #include - /* Type Defines: */ - /** Type define for the HID class specific HID descriptor. A HID descriptor is used in HID class devices - * to give information about the HID device, including the HID specification used, and the report descriptors - * the device contains to describe how the HID device should be controlled. - */ - typedef struct - { - USB_Descriptor_Header_t Header; /**< Standard USB descriptor header */ - - uint16_t HIDSpec; /**< HID specification implemented by the device, in BCD form */ - uint8_t CountryCode; /**< Country code for the country the HID device is localised for */ - - uint8_t TotalHIDDescriptors; /**< Total number of HID reports linked to this HID interface */ - - uint8_t HIDReportType; /**< Type of the first HID report descriptor */ - uint16_t HIDReportLength; /**< Length of the first HID report descriptor */ - } USB_Descriptor_HID_t; - - /** Type define for the data type used for the HID Report descriptor data elements. A HID report - * descriptor contains an array of this data type, indicating how the reports from and to the - * device are formatted and how the report data is to be used by the host. - */ - typedef uint8_t USB_Descriptor_HIDReport_Datatype_t; + #include + #include + /* Type Defines: */ /** Type define for the device configuration descriptor structure. This must be defined in the * application code, as the configuration descriptor contains several sub-descriptors which * vary between devices, and which describe the device's usage to the host. @@ -85,14 +63,8 @@ /** Size of the keyboard report endpoints, in bytes. */ #define KEYBOARD_EPSIZE 8 - /** Descriptor type value for a HID descriptor. */ - #define DTYPE_HID 0x21 - - /** Descriptor type value for a HID report. */ - #define DTYPE_Report 0x22 - /* Function Prototypes: */ uint16_t 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); #endif diff --git a/Projects/Magstripe/Magstripe.c b/Projects/Magstripe/Magstripe.c index e860d5aca6..5cd107e9a4 100644 --- a/Projects/Magstripe/Magstripe.c +++ b/Projects/Magstripe/Magstripe.c @@ -28,60 +28,37 @@ arising out of or in connection with the use or performance of this software. */ - -/** \file - * - * Main source file for the MagStripe application. This file contains the code which drives - * the USB keyboard interface from the magnetic card stripe reader device. - */ #include "Magstripe.h" -/* Scheduler Task List */ -TASK_LIST -{ - { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, - { .Task = USB_Keyboard_Report , .TaskStatus = TASK_STOP }, - { .Task = Magstripe_Read , .TaskStatus = TASK_STOP }, -}; - -/* Global Variables */ -/** Indicates if the device is using Report Protocol mode, instead of Boot Protocol mode. Boot Protocol mode - * is a special reporting mode used by compatible PC BIOS to support USB keyboards before a full OS and USB - * driver has been loaded, by using predefined report structures indicated in the USB HID standard. - */ -bool UsingReportProtocol = true; +BitBuffer_t TrackDataBuffers[3]; -/** Total idle period in milliseconds set by the host via a SetIdle request, used to silence the report endpoint - * until the report data changes or the idle period elapsed. Generally used to implement hardware key repeats, or - * by some BIOS to reduce the number of reports when in Boot Protocol mode. - */ -uint8_t IdleCount = 0; - -/** Milliseconds remaining counter for the HID class SetIdle and GetIdle requests, used to silence the report - * endpoint for an amount of time indicated by the host or until the report changes. - */ -uint16_t IdleMSRemaining = 0; - -/** Circular buffer to hold the read bits from track 1 of the inserted magnetic card. */ -BitBuffer_t Track1Data; +USB_ClassInfo_HID_t Keyboard_HID_Interface = + { + .InterfaceNumber = 0, -/** Circular buffer to hold the read bits from track 2 of the inserted magnetic card. */ -BitBuffer_t Track2Data; + .ReportINEndpointNumber = KEYBOARD_EPNUM, + .ReportINEndpointSize = KEYBOARD_EPSIZE, + }; -/** Circular buffer to hold the read bits from track 3 of the inserted magnetic card. */ -BitBuffer_t Track3Data; +int main(void) +{ + SetupHardware(); + + for (uint8_t Buffer = 0; Buffer < 3; Buffer++) + BitBuffer_Init(&TrackDataBuffers[Buffer]); -/** Delay counter between successive key strokes. This is to prevent the OS from ignoring multiple keys in a short - * period of time due to key repeats. Two milliseconds works for most OSes. - */ -uint8_t KeyDelayRemaining; + for (;;) + { + if (Magstripe_GetStatus() & MAG_CARDPRESENT) + ReadMagstripeData(); + USB_HID_USBTask(&Keyboard_HID_Interface); + USB_USBTask(); + } +} -/** 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) +void SetupHardware(void) { /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); @@ -92,330 +69,97 @@ int main(void) /* Hardware Initialization */ Magstripe_Init(); - - /* Buffer Initialization */ - BitBuffer_Init(&Track1Data); - BitBuffer_Init(&Track2Data); - BitBuffer_Init(&Track3Data); - - /* Millisecond timer initialization, with output compare interrupt enabled for the idle timing */ - OCR0A = 0xFA; - TCCR0A = (1 << WGM01); - TCCR0B = ((1 << CS01) | (1 << CS00)); - TIMSK0 = (1 << OCIE0A); - - /* Initialize Scheduler so that it can be used */ - Scheduler_Init(); - - /* Initialize USB Subsystem */ USB_Init(); - - /* Scheduling - routine never returns, so put this last in the main function */ - Scheduler_Start(); } -/** Event handler for the USB_Connect event. This starts the USB task. */ -void EVENT_USB_Connect(void) +void ReadMagstripeData(void) { - /* Start USB management task */ - Scheduler_SetTaskMode(USB_USBTask, TASK_RUN); -} + /* Arrays to hold the buffer pointers, clock and data bit masks for the separate card tracks */ + const struct + { + uint8_t ClockMask; + uint8_t DataMask; + } TrackInfo[] = {{MAG_T1_CLOCK, MAG_T1_DATA}, + {MAG_T2_CLOCK, MAG_T2_DATA}, + {MAG_T3_CLOCK, MAG_T3_DATA}}; -/** Event handler for the USB_Disconnect event. This stops the USB and keyboard report tasks. */ -void EVENT_USB_Disconnect(void) -{ - /* Stop running keyboard reporting, card reading and USB management tasks */ - Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_STOP); - Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); - Scheduler_SetTaskMode(Magstripe_Read, TASK_STOP); + uint8_t Magstripe_Prev = 0; + uint8_t Magstripe_LCL = Magstripe_GetStatus(); + + while (Magstripe_LCL & MAG_CARDPRESENT) + { + for (uint8_t Track = 0; Track < 3; Track++) + { + bool DataPinLevel = ((Magstripe_LCL & TrackInfo[Track].DataMask) != 0); + bool ClockPinLevel = ((Magstripe_LCL & TrackInfo[Track].ClockMask) != 0); + bool ClockLevelChanged = (((Magstripe_LCL ^ Magstripe_Prev) & TrackInfo[Track].ClockMask) != 0); + + if (ClockPinLevel && ClockLevelChanged) + BitBuffer_StoreNextBit(&TrackDataBuffers[Track], DataPinLevel); + } + + Magstripe_Prev = Magstripe_LCL; + Magstripe_LCL = Magstripe_GetStatus(); + } } -/** Event handler for the USB_ConfigurationChanged event. This configures the device's endpoints ready - * to relay reports to the host, and starts the keyboard report task. - */ void EVENT_USB_ConfigurationChanged(void) { - /* Setup Keyboard Keycode Report Endpoint */ - Endpoint_ConfigureEndpoint(KEYBOARD_EPNUM, EP_TYPE_INTERRUPT, - ENDPOINT_DIR_IN, KEYBOARD_EPSIZE, - ENDPOINT_BANK_SINGLE); - - /* Default to report protocol on connect */ - UsingReportProtocol = true; - - /* Start Keyboard reporting and card reading tasks */ - Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_RUN); - Scheduler_SetTaskMode(Magstripe_Read, TASK_RUN); + USB_HID_ConfigureEndpoints(&Keyboard_HID_Interface); } -/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific - * control requests that are not handled internally by the USB library, so that they can be handled appropriately - * for the application. - */ void EVENT_USB_UnhandledControlPacket(void) { - /* Handle HID Class specific requests */ - switch (USB_ControlRequest.bRequest) - { - case REQ_GetReport: - if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) - { - USB_KeyboardReport_Data_t KeyboardReportData; - - /* Create the next keyboard report for transmission to the host */ - GetNextReport(&KeyboardReportData); - - Endpoint_ClearSETUP(); - - /* 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_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 != 0x0000); - - /* 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; - } + USB_HID_ProcessControlPacket(&Keyboard_HID_Interface); } -/** ISR for the timer 0 compare vector. This ISR fires once each millisecond, and decrements the counter indicating - * the number of milliseconds left to idle (not send the host reports) if the device has been instructed to idle - * by the host via a SetIdle class specific request. - */ -ISR(TIMER0_COMPA_vect, ISR_BLOCK) +void EVENT_USB_StartOfFrame(void) { - /* One millisecond has elapsed, decrement the idle time remaining counter if it has not already elapsed */ - if (IdleMSRemaining) - IdleMSRemaining--; - - if (KeyDelayRemaining) - KeyDelayRemaining--; + USB_HID_RegisterStartOfFrame(&Keyboard_HID_Interface); } -/** Constructs a keyboard report indicating the currently pressed keyboard keys to the host. - * - * \param ReportData Pointer to a USB_KeyboardReport_Data_t report structure where the resulting report should - * be stored - * - * \return Boolean true if the current report is different to the previous report, false otherwise - */ -bool GetNextReport(USB_KeyboardReport_Data_t* ReportData) +uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData) { - static bool OddReport = false; - static bool MustRelease = false; - - BitBuffer_t* Buffer = NULL; - - /* Clear the report contents */ - memset(ReportData, 0, sizeof(USB_KeyboardReport_Data_t)); + static bool IsKeyReleaseReport; + static bool IsNewlineReport; - /* Get the next non-empty track data buffer */ - if (Track1Data.Elements) - Buffer = &Track1Data; - else if (Track2Data.Elements) - Buffer = &Track2Data; - else if (Track3Data.Elements) - Buffer = &Track3Data; - - if (Buffer != NULL) - { - /* Toggle the odd report number indicator */ - OddReport = !OddReport; + BitBuffer_t* Buffer = NULL; + USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData; - /* Set the flag indicating that a null report must eventually be sent to release all pressed keys */ - MustRelease = true; - - /* Only send the next key on odd reports, so that they are interspersed with null reports to release keys */ - if (OddReport) - { - /* Set the report key code to the key code for the next data bit */ - ReportData->KeyCode = BitBuffer_GetNextBit(Buffer) ? KEY_1 : KEY_0; - - /* If buffer is now empty, a new line must be sent instead of the terminating bit */ - if (!(Buffer->Elements)) - { - /* Set the keycode to the code for an enter key press */ - ReportData->KeyCode = KEY_ENTER; - } - } + /* Key reports must be interleaved with 0 Key Code reports to release the keys, or repeated keys will be ignored */ + IsKeyReleaseReport = !IsKeyReleaseReport; - return true; - } - else if (MustRelease) + if (IsKeyReleaseReport) { - /* Leave key code to null (0), to release all pressed keys */ - return true; + KeyboardReport->KeyCode = 0; } - - return false; -} - -/** Task to read out data from inserted magnetic cards and place the separate track data into their respective - * data buffers for later sending to the host as keyboard key presses. - */ -TASK(Magstripe_Read) -{ - /* Arrays to hold the buffer pointers, clock and data bit masks for the separate card tracks */ - const struct + else if (IsNewlineReport) { - BitBuffer_t* Buffer; - uint8_t ClockMask; - uint8_t DataMask; - } TrackInfo[] = {{&Track1Data, MAG_T1_CLOCK, MAG_T1_DATA}, - {&Track2Data, MAG_T2_CLOCK, MAG_T2_DATA}, - {&Track3Data, MAG_T3_CLOCK, MAG_T3_DATA}}; - - /* Previous magnetic card control line' status, for later comparison */ - uint8_t Magstripe_Prev = 0; - - /* Buffered current card reader control line' status */ - uint8_t Magstripe_LCL = Magstripe_GetStatus(); - - /* Exit the task early if no card is present in the reader */ - if (!(Magstripe_LCL & MAG_CARDPRESENT)) - return; - - /* Read out card data while a card is present */ - while (Magstripe_LCL & MAG_CARDPRESENT) + IsNewlineReport = false; + KeyboardReport->KeyCode = KEY_ENTER; + } + else { - /* Read out the next bit for each track of the card */ - for (uint8_t Track = 0; Track < 3; Track++) - { - /* Current data line status for the current card track */ - bool DataLevel = ((Magstripe_LCL & TrackInfo[Track].DataMask) != 0); - - /* Current clock line status for the current card track */ - bool ClockLevel = ((Magstripe_LCL & TrackInfo[Track].ClockMask) != 0); - - /* Current track clock transition check */ - bool ClockChanged = (((Magstripe_LCL ^ Magstripe_Prev) & TrackInfo[Track].ClockMask) != 0); - - /* Sample the next bit on the falling edge of the track's clock line, store key code into the track's buffer */ - if (ClockLevel && ClockChanged) - BitBuffer_StoreNextBit(TrackInfo[Track].Buffer, DataLevel); - } - - /* Retain the current card reader control line states for later edge detection */ - Magstripe_Prev = Magstripe_LCL; + if (TrackDataBuffers[0].Elements) + Buffer = &TrackDataBuffers[0]; + else if (TrackDataBuffers[1].Elements) + Buffer = &TrackDataBuffers[1]; + else if (TrackDataBuffers[2].Elements) + Buffer = &TrackDataBuffers[2]; + else + return 0; + + KeyboardReport->KeyCode = BitBuffer_GetNextBit(Buffer) ? KEY_1 : KEY_0; - /* Retrieve the new card reader control line states */ - Magstripe_LCL = Magstripe_GetStatus(); + /* If buffer now empty, next report must be a newline to seperate track data */ + if (!(Buffer->Elements)) + IsNewlineReport = true; } - /* Add terminators to the end of each track buffer */ - BitBuffer_StoreNextBit(&Track1Data, 0); - BitBuffer_StoreNextBit(&Track2Data, 0); - BitBuffer_StoreNextBit(&Track3Data, 0); + return sizeof(USB_KeyboardReport_Data_t); } -/** Task for the magnetic card reading and keyboard report generation. This task waits until a card is inserted, - * then reads off the card data and sends it to the host as a series of keyboard key presses via keyboard reports. - */ -TASK(USB_Keyboard_Report) +void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize) { - USB_KeyboardReport_Data_t KeyboardReportData; - bool SendReport = false; - - /* Check if the USB system is connected to a host */ - if (USB_IsConnected) - { - /* Select the Keyboard Report Endpoint */ - Endpoint_SelectEndpoint(KEYBOARD_EPNUM); - - /* Check if Keyboard Endpoint Ready for Read/Write */ - if (Endpoint_IsReadWriteAllowed()) - { - /* Only fetch the next key to send once the period between key presses has elapsed */ - if (!(KeyDelayRemaining)) - { - /* Create the next keyboard report for transmission to the host */ - SendReport = GetNextReport(&KeyboardReportData); - } - - /* Check if the idle period is set and has elapsed */ - if (IdleCount && !(IdleMSRemaining)) - { - /* Idle period elapsed, indicate that a report must be sent */ - SendReport = true; - - /* Reset the idle time remaining counter, must multiply by 4 to get the duration in milliseconds */ - IdleMSRemaining = (IdleCount << 2); - } - - /* Write the keyboard report if a report is to be sent to the host */ - if (SendReport) - { - /* Write Keyboard Report Data */ - Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(USB_KeyboardReport_Data_t)); - - /* Finalize the stream transfer to send the last packet */ - Endpoint_ClearIN(); - - /* Reset the key delay period counter */ - KeyDelayRemaining = 2; - } - } - } + // Unused (but mandatory for the HID class driver) in this demo, since there are no Host->Device reports } diff --git a/Projects/Magstripe/Magstripe.h b/Projects/Magstripe/Magstripe.h index c700bcaff5..b0e47d5965 100644 --- a/Projects/Magstripe/Magstripe.h +++ b/Projects/Magstripe/Magstripe.h @@ -40,46 +40,17 @@ /* Includes: */ #include #include - #include #include - #include - #include #include "Descriptors.h" - #include "Lib/MagstripeHW.h" #include "Lib/CircularBitBuffer.h" - #include // Library Version Information - #include // USB Functionality - #include // Simple scheduler for task management - - - /* Task Definitions: */ - /** Task definition for the keyboard and magnetic card reading task. */ - TASK(USB_Keyboard_Report); - - TASK(Magstripe_Read); + #include + #include + #include /* Macros: */ - /** HID Class Specific Request to get the current HID report from the device. */ - #define REQ_GetReport 0x01 - - /** HID Class Specific Request to get the current device idle count. */ - #define REQ_GetIdle 0x02 - - /** HID Class Specific Request to set the current HID report to the device. */ - #define REQ_SetReport 0x09 - - /** HID Class Specific Request to set the device's idle count. */ - #define REQ_SetIdle 0x0A - - /** HID Class Specific Request to get the current HID report protocol mode. */ - #define REQ_GetProtocol 0x03 - - /** HID Class Specific Request to set the current HID report protocol mode. */ - #define REQ_SetProtocol 0x0B - /** HID keyboard keycode to indicate that the "1" key is currently pressed. */ #define KEY_1 30 @@ -102,11 +73,15 @@ } USB_KeyboardReport_Data_t; /* Function Prototypes: */ - void EVENT_USB_Connect(void); - void EVENT_USB_Disconnect(void); + void SetupHardware(void); + void ReadMagstripeData(void); + void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_UnhandledControlPacket(void); - - bool GetNextReport(USB_KeyboardReport_Data_t* ReportData); + void EVENT_USB_StartOfFrame(void); + + 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 diff --git a/Projects/Magstripe/makefile b/Projects/Magstripe/makefile index 962c999b3f..138456fe8f 100644 --- a/Projects/Magstripe/makefile +++ b/Projects/Magstripe/makefile @@ -126,7 +126,6 @@ LUFA_PATH = ../.. SRC = $(TARGET).c \ Descriptors.c \ Lib/CircularBitBuffer.c \ - $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.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/USBTask.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.)