From d1e52660368d34d693131f6aff3c8fd8584162e5 Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Mon, 1 Jun 2009 11:03:39 +0000 Subject: Commit of new class abstraction APIs for all device demos other than the MIDI demo - not documented yet. Removed scheduler and memory allocation libraries. Added new EVENT_USB_StartOfFrame event in the library to indicate the start of each USB frame (when generated). Removed Tx interrupt from the USBtoSerial demo; now sends characters via polling to ensure more time for the Rx interrupt. --- Demos/Device/AudioInput/AudioInput.c | 188 +++------ Demos/Device/AudioInput/AudioInput.h | 36 +- Demos/Device/AudioInput/makefile | 3 +- Demos/Device/AudioOutput/AudioOutput.c | 277 +++++-------- Demos/Device/AudioOutput/AudioOutput.h | 33 +- Demos/Device/AudioOutput/makefile | 5 +- Demos/Device/CDC/CDC.c | 317 ++++----------- Demos/Device/CDC/CDC.h | 139 +------ Demos/Device/CDC/Descriptors.h | 22 +- Demos/Device/CDC/makefile | 5 +- Demos/Device/DualCDC/Descriptors.h | 20 +- Demos/Device/DualCDC/DualCDC.c | 370 ++++------------- Demos/Device/DualCDC/DualCDC.h | 75 +--- Demos/Device/DualCDC/makefile | 5 +- Demos/Device/GenericHID/Descriptors.h | 32 +- Demos/Device/GenericHID/GenericHID.c | 243 ++---------- Demos/Device/GenericHID/GenericHID.h | 40 +- Demos/Device/GenericHID/makefile | 5 +- Demos/Device/Joystick/Descriptors.h | 30 +- Demos/Device/Joystick/Joystick.c | 211 +++------- Demos/Device/Joystick/Joystick.h | 40 +- Demos/Device/Joystick/makefile | 5 +- Demos/Device/Keyboard/Descriptors.h | 30 +- Demos/Device/Keyboard/Keyboard.c | 437 ++++----------------- Demos/Device/Keyboard/Keyboard.h | 60 +-- Demos/Device/Keyboard/makefile | 5 +- Demos/Device/KeyboardMouse/Descriptors.h | 30 +- Demos/Device/KeyboardMouse/KeyboardMouse.c | 353 +++++------------ Demos/Device/KeyboardMouse/KeyboardMouse.h | 47 +-- Demos/Device/KeyboardMouse/makefile | 5 +- Demos/Device/MIDI/makefile | 2 +- Demos/Device/MassStorage/Lib/DataflashManager.c | 18 +- Demos/Device/MassStorage/Lib/DataflashManager.h | 4 +- Demos/Device/MassStorage/Lib/SCSI.c | 116 +++--- Demos/Device/MassStorage/Lib/SCSI.h | 25 +- Demos/Device/MassStorage/MassStorage.c | 331 ++-------------- Demos/Device/MassStorage/MassStorage.h | 103 +---- Demos/Device/MassStorage/makefile | 4 +- Demos/Device/Mouse/Descriptors.h | 30 +- Demos/Device/Mouse/Mouse.c | 309 ++------------- Demos/Device/Mouse/Mouse.h | 58 +-- Demos/Device/Mouse/makefile | 5 +- Demos/Device/RNDISEthernet/Lib/ARP.h | 4 +- Demos/Device/RNDISEthernet/Lib/Ethernet.c | 32 +- Demos/Device/RNDISEthernet/Lib/Ethernet.h | 24 +- Demos/Device/RNDISEthernet/Lib/EthernetProtocols.h | 8 +- Demos/Device/RNDISEthernet/Lib/ICMP.c | 4 +- Demos/Device/RNDISEthernet/Lib/ICMP.h | 2 +- Demos/Device/RNDISEthernet/Lib/IP.c | 5 +- Demos/Device/RNDISEthernet/Lib/IP.h | 2 +- Demos/Device/RNDISEthernet/Lib/RNDIS.c | 394 ------------------- Demos/Device/RNDISEthernet/Lib/RNDIS.h | 226 ----------- Demos/Device/RNDISEthernet/Lib/RNDISConstants.h | 99 ----- Demos/Device/RNDISEthernet/Lib/TCP.c | 22 +- Demos/Device/RNDISEthernet/Lib/TCP.h | 8 +- Demos/Device/RNDISEthernet/RNDISEthernet.c | 322 +++------------ Demos/Device/RNDISEthernet/RNDISEthernet.h | 56 +-- Demos/Device/RNDISEthernet/makefile | 6 +- Demos/Device/USBtoSerial/Descriptors.h | 20 +- Demos/Device/USBtoSerial/USBtoSerial.c | 346 +++------------- Demos/Device/USBtoSerial/USBtoSerial.h | 142 +------ Demos/Device/USBtoSerial/makefile | 5 +- Demos/Host/GenericHIDHost/makefile | 2 +- Demos/Host/MassStorageHost/Lib/MassStoreCommands.c | 4 +- Demos/Host/StillImageHost/Lib/StillImageCommands.c | 4 +- Demos/OTG/TestApp/TestApp.h | 1 - Demos/OTG/TestApp/makefile | 3 - 67 files changed, 1089 insertions(+), 4725 deletions(-) delete mode 100644 Demos/Device/RNDISEthernet/Lib/RNDIS.c delete mode 100644 Demos/Device/RNDISEthernet/Lib/RNDIS.h delete mode 100644 Demos/Device/RNDISEthernet/Lib/RNDISConstants.h (limited to 'Demos') diff --git a/Demos/Device/AudioInput/AudioInput.c b/Demos/Device/AudioInput/AudioInput.c index ecd8cdda8..bcfb04be1 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 a394492f0..e9f56b30a 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 c70e98e04..9d3adff69 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 40e376b52..0f193567a 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 d8725a07b..7d112db88 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 28f038f49..8ad1def4d 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 d7ebb9e6b..e6bc1a455 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 4c4ca74d5..b487813b0 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 41b44300a..1a9dbb5bf 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 bc22be5c0..bd4ff36b9 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 2c2311b9c..97165e5de 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 34d772ff0..26947f433 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 117af601e..3c1e29612 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 06d0e184b..5fbda61dd 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 023687032..bc4c68ae6 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 058d269fe..4dfb8e455 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 30354b756..27426431c 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 9c6c891cd..5cc4b4a43 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 6121295fa..1241ad14e 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 8c50a2c16..e073a87fd 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 9763cada3..461d0d0cc 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 aaf69e80b..826766c30 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 92eb7b884..0a95ca06e 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 6abd193f4..d8893bfaa 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 c4ed6e07c..eeb7be9b7 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 88e4de0e6..98cda2f89 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 43c345a21..152e5111a 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 25d633e43..8f6a573a6 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 e3f943402..a5c3c5db2 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 c6b34d96e..ddad7d24b 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 18fc3b154..485cdc710 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 4b624190f..87edef12b 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 1332fd3a3..b828051aa 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 5993a546d..8f3167a47 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 d7693cafb..3fd751dee 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 72a230219..8e2b9f450 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 cbd3cd931..a50edac99 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 93f895727..c4adfc9be 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 883ef31e8..ef3215ca6 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 32b12fc61..57c1aa114 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 65879da8e..5c8049590 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 632bf91ae..4c18f9d4a 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 8551df85b..f05d8f093 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 3d34f716a..57380a082 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 b360f07ae..b3002523a 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 3ff3433ae..1ec5961e1 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 da4ffcfa1..ba6e1db68 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 b20a557e9..56749c09c 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 8fb0b446d..08500450c 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 fc1a46aef..f77c772d8 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 c5202bcd1..000000000 --- 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/RNDIS.h b/Demos/Device/RNDISEthernet/Lib/RNDIS.h deleted file mode 100644 index 88c9a9eb9..000000000 --- a/Demos/Device/RNDISEthernet/Lib/RNDIS.h +++ /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. -*/ - -/** \file - * - * Header file for RNDIS.c. - */ - -#ifndef _RNDIS_H_ -#define _RNDIS_H_ - - /* Includes: */ - #include - #include - - #include "RNDISEthernet.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 - - /** Implemented RNDIS Version Minor */ - #define REMOTE_NDIS_VERSION_MINOR 0x00 - - /** RNDIS request to issue a host-to-device NDIS command */ - #define REQ_SendEncapsulatedCommand 0x00 - - /** RNDIS request to issue a device-to-host NDIS response */ - #define REQ_GetEncapsulatedResponse 0x01 - - /* Enums: */ - /** Enum for the possible NDIS adapter states. */ - enum RNDIS_States_t - { - RNDIS_Uninitialized = 0, /**< Adapter currently uninitialized */ - RNDIS_Initialized = 1, /**< Adapter currently initialized but not ready for data transfers */ - RNDIS_Data_Initialized = 2, /**< Adapter currently initialized and ready for data transfers */ - }; - - /** Enum for the NDIS hardware states */ - enum NDIS_Hardware_Status_t - { - NdisHardwareStatusReady, /**< Hardware Ready to accept commands from the host */ - NdisHardwareStatusInitializing, /**< Hardware busy initializing */ - NdisHardwareStatusReset, /**< Hardware reset */ - NdisHardwareStatusClosing, /**< Hardware currently closing */ - NdisHardwareStatusNotReady /**< Hardware not ready to accept commands from the host */ - }; - - /* Type Defines: */ - /** Type define for a RNDIS message header, sent before RNDIS messages */ - typedef struct - { - uint32_t MessageType; /**< RNDIS message type, a REMOTE_NDIS_*_MSG constant */ - uint32_t MessageLength; /**< Total length of the RNDIS message, in bytes */ - } RNDIS_Message_Header_t; - - /** Type define for a RNDIS packet message, used to encapsulate Ethernet packets sent to and from the adapter */ - typedef struct - { - uint32_t MessageType; - uint32_t MessageLength; - uint32_t DataOffset; - uint32_t DataLength; - uint32_t OOBDataOffset; - uint32_t OOBDataLength; - uint32_t NumOOBDataElements; - uint32_t PerPacketInfoOffset; - uint32_t PerPacketInfoLength; - uint32_t VcHandle; - uint32_t Reserved; - } RNDIS_PACKET_MSG_t; - - /** Type define for a RNDIS Initialize command message */ - typedef struct - { - uint32_t MessageType; - uint32_t MessageLength; - uint32_t RequestId; - - uint32_t MajorVersion; - uint32_t MinorVersion; - uint32_t MaxTransferSize; - } RNDIS_INITIALIZE_MSG_t; - - /** Type define for a RNDIS Initialize complete response message */ - typedef struct - { - uint32_t MessageType; - uint32_t MessageLength; - uint32_t RequestId; - uint32_t Status; - - uint32_t MajorVersion; - uint32_t MinorVersion; - uint32_t DeviceFlags; - uint32_t Medium; - uint32_t MaxPacketsPerTransfer; - uint32_t MaxTransferSize; - uint32_t PacketAlignmentFactor; - uint32_t AFListOffset; - uint32_t AFListSize; - } RNDIS_INITIALIZE_CMPLT_t; - - /** Type define for a RNDIS Keepalive command message */ - typedef struct - { - uint32_t MessageType; - uint32_t MessageLength; - uint32_t RequestId; - } RNDIS_KEEPALIVE_MSG_t; - - /** Type define for a RNDIS Keepalive complete message */ - typedef struct - { - uint32_t MessageType; - uint32_t MessageLength; - uint32_t RequestId; - uint32_t Status; - } RNDIS_KEEPALIVE_CMPLT_t; - - /** Type define for a RNDIS Reset complete message */ - typedef struct - { - uint32_t MessageType; - uint32_t MessageLength; - uint32_t Status; - - uint32_t AddressingReset; - } RNDIS_RESET_CMPLT_t; - - /** Type define for a RNDIS Set command message */ - typedef struct - { - uint32_t MessageType; - uint32_t MessageLength; - uint32_t RequestId; - - uint32_t Oid; - uint32_t InformationBufferLength; - uint32_t InformationBufferOffset; - uint32_t DeviceVcHandle; - } RNDIS_SET_MSG_t; - - /** Type define for a RNDIS Set complete response message */ - typedef struct - { - uint32_t MessageType; - uint32_t MessageLength; - uint32_t RequestId; - uint32_t Status; - } RNDIS_SET_CMPLT_t; - - /** Type define for a RNDIS Query command message */ - typedef struct - { - uint32_t MessageType; - uint32_t MessageLength; - uint32_t RequestId; - - uint32_t Oid; - uint32_t InformationBufferLength; - uint32_t InformationBufferOffset; - uint32_t DeviceVcHandle; - } RNDIS_QUERY_MSG_t; - - /** Type define for a RNDIS Query complete response message */ - typedef struct - { - uint32_t MessageType; - uint32_t MessageLength; - uint32_t RequestId; - uint32_t Status; - - uint32_t InformationBufferLength; - 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); - #endif - -#endif diff --git a/Demos/Device/RNDISEthernet/Lib/RNDISConstants.h b/Demos/Device/RNDISEthernet/Lib/RNDISConstants.h deleted file mode 100644 index ad66f62db..000000000 --- a/Demos/Device/RNDISEthernet/Lib/RNDISConstants.h +++ /dev/null @@ -1,99 +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 specification related constants. For more information on these - * constants, please refer to the Microsoft RNDIS specification. - */ - -#ifndef _RNDIS_CONSTANTS_H_ -#define _RNDIS_CONSTANTS_H_ - - /* Macros: */ - #define REMOTE_NDIS_PACKET_MSG 0x00000001UL - #define REMOTE_NDIS_INITIALIZE_MSG 0x00000002UL - #define REMOTE_NDIS_HALT_MSG 0x00000003UL - #define REMOTE_NDIS_QUERY_MSG 0x00000004UL - #define REMOTE_NDIS_SET_MSG 0x00000005UL - #define REMOTE_NDIS_RESET_MSG 0x00000006UL - #define REMOTE_NDIS_INDICATE_STATUS_MSG 0x00000007UL - #define REMOTE_NDIS_KEEPALIVE_MSG 0x00000008UL - - #define REMOTE_NDIS_INITIALIZE_CMPLT 0x80000002UL - #define REMOTE_NDIS_QUERY_CMPLT 0x80000004UL - #define REMOTE_NDIS_SET_CMPLT 0x80000005UL - #define REMOTE_NDIS_RESET_CMPLT 0x80000006UL - #define REMOTE_NDIS_KEEPALIVE_CMPLT 0x80000008UL - - #define REMOTE_NDIS_STATUS_SUCCESS 0x00000000UL - #define REMOTE_NDIS_STATUS_FAILURE 0xC0000001UL - #define REMOTE_NDIS_STATUS_INVALID_DATA 0xC0010015UL - #define REMOTE_NDIS_STATUS_NOT_SUPPORTED 0xC00000BBUL - #define REMOTE_NDIS_STATUS_MEDIA_CONNECT 0x4001000BUL - #define REMOTE_NDIS_STATUS_MEDIA_DISCONNECT 0x4001000CUL - - #define REMOTE_NDIS_MEDIA_STATE_CONNECTED 0x00000000UL - #define REMOTE_NDIS_MEDIA_STATE_DISCONNECTED 0x00000001UL - - #define REMOTE_NDIS_MEDIUM_802_3 0x00000000UL - - #define REMOTE_NDIS_DF_CONNECTIONLESS 0x00000001UL - #define REMOTE_NDIS_DF_CONNECTION_ORIENTED 0x00000002UL - - #define OID_GEN_SUPPORTED_LIST 0x00010101UL - #define OID_GEN_HARDWARE_STATUS 0x00010102UL - #define OID_GEN_MEDIA_SUPPORTED 0x00010103UL - #define OID_GEN_MEDIA_IN_USE 0x00010104UL - #define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106UL - #define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111UL - #define OID_GEN_LINK_SPEED 0x00010107UL - #define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010AUL - #define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010BUL - #define OID_GEN_VENDOR_ID 0x0001010CUL - #define OID_GEN_VENDOR_DESCRIPTION 0x0001010DUL - #define OID_GEN_CURRENT_PACKET_FILTER 0x0001010EUL - #define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111UL - #define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114UL - #define OID_GEN_PHYSICAL_MEDIUM 0x00010202UL - #define OID_GEN_XMIT_OK 0x00020101UL - #define OID_GEN_RCV_OK 0x00020102UL - #define OID_GEN_XMIT_ERROR 0x00020103UL - #define OID_GEN_RCV_ERROR 0x00020104UL - #define OID_GEN_RCV_NO_BUFFER 0x00020105UL - #define OID_802_3_PERMANENT_ADDRESS 0x01010101UL - #define OID_802_3_CURRENT_ADDRESS 0x01010102UL - #define OID_802_3_MULTICAST_LIST 0x01010103UL - #define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104UL - #define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101UL - #define OID_802_3_XMIT_ONE_COLLISION 0x01020102UL - #define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103UL - -#endif diff --git a/Demos/Device/RNDISEthernet/Lib/TCP.c b/Demos/Device/RNDISEthernet/Lib/TCP.c index f259aad02..1ebd15435 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 d4b72a519..3448245ed 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 b046f7870..3246cd8bc 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 703af4003..bc5004205 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 f40c37b05..3bcc37c8e 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 41b44300a..9e372e35b 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 7cef56560..7c89278ef 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 8e7e8aed8..7ff796e70 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 708e87246..5cf9c617e 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 b17ae1641..b912b2ff8 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 95aafca8c..f47e9f5ed 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 8f05e48f4..f2f666bd1 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 de4d52612..7ae5663d9 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 dd6d8f43f..a8bf4ac42 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 -- cgit v1.2.3