forked from mfulz_github/qmk_firmware
Commit of new class abstraction APIs for all device demos other than the MIDI demo - not documented yet.
Removed scheduler and memory allocation libraries. Added new EVENT_USB_StartOfFrame event in the library to indicate the start of each USB frame (when generated). Removed Tx interrupt from the USBtoSerial demo; now sends characters via polling to ensure more time for the Rx interrupt.
This commit is contained in:
parent
2440ca268a
commit
d1e5266036
|
@ -124,7 +124,6 @@ SRC = $(TARGET).c \
|
|||
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \
|
||||
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/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.)
|
||||
|
|
|
@ -124,7 +124,6 @@ SRC = $(TARGET).c \
|
|||
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \
|
||||
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c \
|
||||
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c \
|
||||
$(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c \
|
||||
|
||||
|
||||
# List C++ source files here. (C dependencies are automatically generated.)
|
||||
|
|
|
@ -124,7 +124,6 @@ SRC = $(TARGET).c \
|
|||
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \
|
||||
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c \
|
||||
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c \
|
||||
$(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c \
|
||||
|
||||
|
||||
# List C++ source files here. (C dependencies are automatically generated.)
|
||||
|
|
|
@ -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 =
|
||||
{
|
||||
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
|
||||
{ .Task = USB_Audio_Task , .TaskStatus = TASK_STOP },
|
||||
.InterfaceNumber = 0,
|
||||
|
||||
.DataINEndpointNumber = AUDIO_STREAM_EPNUM,
|
||||
.DataINEndpointSize = AUDIO_STREAM_EPSIZE,
|
||||
};
|
||||
|
||||
|
||||
/** Main program entry point. This routine configures the hardware required by the application, then
|
||||
* starts the scheduler to run the application tasks.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
SetupHardware();
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (Microphone_Audio_Interface.InterfaceEnabled)
|
||||
ProcessNextSample();
|
||||
|
||||
USB_USBTask();
|
||||
}
|
||||
}
|
||||
|
||||
void SetupHardware(void)
|
||||
{
|
||||
/* Disable watchdog if enabled by bootloader/fuses */
|
||||
MCUSR &= ~(1 << WDRF);
|
||||
|
@ -58,145 +64,18 @@ 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();
|
||||
|
||||
/* 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)
|
||||
void ProcessNextSample(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
|
||||
}
|
||||
|
||||
/** 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)
|
||||
if ((TIFR0 & (1 << OCF0A)) && USB_Audio_IsReadyForNextSample(&Microphone_Audio_Interface))
|
||||
{
|
||||
/* Stop the sample reload timer */
|
||||
TCCR0B = 0;
|
||||
|
||||
/* Stop running audio and USB management tasks */
|
||||
Scheduler_SetTaskMode(USB_Audio_Task, TASK_STOP);
|
||||
Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);
|
||||
|
||||
/* Indicate USB not ready */
|
||||
UpdateStatus(Status_USBNotReady);
|
||||
}
|
||||
|
||||
/** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration
|
||||
* of the USB device after enumeration - the device endpoints are configured.
|
||||
*/
|
||||
void EVENT_USB_ConfigurationChanged(void)
|
||||
{
|
||||
/* Setup audio stream endpoint */
|
||||
Endpoint_ConfigureEndpoint(AUDIO_STREAM_EPNUM, EP_TYPE_ISOCHRONOUS,
|
||||
ENDPOINT_DIR_IN, AUDIO_STREAM_EPSIZE,
|
||||
ENDPOINT_BANK_DOUBLE);
|
||||
|
||||
/* Indicate USB connected and ready */
|
||||
UpdateStatus(Status_USBReady);
|
||||
}
|
||||
|
||||
/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific
|
||||
* control requests that are not handled internally by the USB library (including the Audio class-specific
|
||||
* requests) so that they can be handled appropriately for the application.
|
||||
*/
|
||||
void EVENT_USB_UnhandledControlPacket(void)
|
||||
{
|
||||
/* Process General and Audio specific control requests */
|
||||
switch (USB_ControlRequest.bRequest)
|
||||
{
|
||||
case REQ_SetInterface:
|
||||
/* Set Interface is not handled by the library, as its function is application-specific */
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
/* Check if the host is enabling the audio interface (setting AlternateSetting to 1) */
|
||||
if (USB_ControlRequest.wValue)
|
||||
{
|
||||
/* Start audio task */
|
||||
Scheduler_SetTaskMode(USB_Audio_Task, TASK_RUN);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Stop audio task */
|
||||
Scheduler_SetTaskMode(USB_Audio_Task, TASK_STOP);
|
||||
}
|
||||
|
||||
/* Acknowledge status stage */
|
||||
while (!(Endpoint_IsINReady()));
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
|
||||
* log to a serial port, or anything else that is suitable for status updates.
|
||||
*
|
||||
* \param CurrentStatus Current status of the system, from the AudioInput_StatusCodes_t enum
|
||||
*/
|
||||
void UpdateStatus(uint8_t CurrentStatus)
|
||||
{
|
||||
uint8_t LEDMask = LEDS_NO_LEDS;
|
||||
|
||||
/* Set the LED mask to the appropriate LED mask based on the given status code */
|
||||
switch (CurrentStatus)
|
||||
{
|
||||
case Status_USBNotReady:
|
||||
LEDMask = (LEDS_LED1);
|
||||
break;
|
||||
case Status_USBEnumerating:
|
||||
LEDMask = (LEDS_LED1 | LEDS_LED2);
|
||||
break;
|
||||
case Status_USBReady:
|
||||
LEDMask = (LEDS_LED2 | LEDS_LED4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the board LEDs to the new LED mask */
|
||||
LEDs_SetAllLEDs(LEDMask);
|
||||
}
|
||||
|
||||
/** Task to manage the Audio interface, reading in ADC samples from the microphone, and them to the host. */
|
||||
TASK(USB_Audio_Task)
|
||||
{
|
||||
/* Select the audio stream endpoint */
|
||||
Endpoint_SelectEndpoint(AUDIO_STREAM_EPNUM);
|
||||
|
||||
/* Check if the current endpoint can be written to and that the next sample should be stored */
|
||||
if (Endpoint_IsINReady() && (TIFR0 & (1 << OCF0A)))
|
||||
{
|
||||
/* Clear the sample reload timer */
|
||||
TIFR0 |= (1 << OCF0A);
|
||||
|
||||
/* Audio sample is ADC value scaled to fit the entire range */
|
||||
|
@ -207,14 +86,37 @@ TASK(USB_Audio_Task)
|
|||
AudioSample -= (SAMPLE_MAX_RANGE / 2));
|
||||
#endif
|
||||
|
||||
/* Write the sample to the buffer */
|
||||
Endpoint_Write_Word_LE(AudioSample);
|
||||
USB_Audio_WriteSample16(AudioSample);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check to see if the bank is now full */
|
||||
if (!(Endpoint_IsReadWriteAllowed()))
|
||||
void EVENT_USB_Connect(void)
|
||||
{
|
||||
/* Send the full packet to the host */
|
||||
Endpoint_ClearIN();
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
|
||||
|
||||
/* Sample reload timer initialization */
|
||||
OCR0A = (F_CPU / AUDIO_SAMPLE_FREQUENCY) - 1;
|
||||
TCCR0A = (1 << WGM01); // CTC mode
|
||||
TCCR0B = (1 << CS00); // Fcpu speed
|
||||
}
|
||||
|
||||
void EVENT_USB_Disconnect(void)
|
||||
{
|
||||
/* Stop the sample reload timer */
|
||||
TCCR0B = 0;
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
}
|
||||
|
||||
void EVENT_USB_ConfigurationChanged(void)
|
||||
{
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||
|
||||
if (!(USB_Audio_ConfigureEndpoints(&Microphone_Audio_Interface)))
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
}
|
||||
|
||||
void EVENT_USB_UnhandledControlPacket(void)
|
||||
{
|
||||
USB_Audio_ProcessControlPacket(&Microphone_Audio_Interface);
|
||||
}
|
||||
|
|
|
@ -43,11 +43,12 @@
|
|||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
|
||||
#include <LUFA/Drivers/Peripheral/ADC.h> // ADC driver
|
||||
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Joystick.h>
|
||||
#include <LUFA/Drivers/Peripheral/ADC.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/Audio.h>
|
||||
|
||||
/* Macros: */
|
||||
/** ADC channel number for the microphone input. */
|
||||
|
@ -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
|
||||
|
|
|
@ -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.)
|
||||
|
|
|
@ -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
|
||||
USB_ClassInfo_Audio_t Speaker_Audio_Interface =
|
||||
{
|
||||
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
|
||||
{ .Task = USB_Audio_Task , .TaskStatus = TASK_STOP },
|
||||
.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)
|
||||
void ProcessNextSample(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)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
|
|
@ -43,10 +43,12 @@
|
|||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
|
||||
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Joystick.h>
|
||||
#include <LUFA/Drivers/Peripheral/ADC.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/Audio.h>
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
USB_ClassInfo_CDC_t VirtualSerial_CDC_Interface =
|
||||
{
|
||||
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
|
||||
{ .Task = CDC_Task , .TaskStatus = TASK_STOP },
|
||||
.ControlInterfaceNumber = 0,
|
||||
|
||||
.DataINEndpointNumber = CDC_TX_EPNUM,
|
||||
.DataINEndpointSize = CDC_TXRX_EPSIZE,
|
||||
|
||||
.DataOUTEndpointNumber = CDC_RX_EPNUM,
|
||||
.DataOUTEndpointSize = CDC_TXRX_EPSIZE,
|
||||
|
||||
.NotificationEndpointNumber = CDC_NOTIFICATION_EPNUM,
|
||||
.NotificationEndpointSize = CDC_NOTIFICATION_EPSIZE,
|
||||
};
|
||||
|
||||
/* 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 };
|
||||
|
||||
/** String to print through the virtual serial port when the joystick is pressed upwards. */
|
||||
char JoystickUpString[] = "Joystick Up\r\n";
|
||||
|
||||
/** String to print through the virtual serial port when the joystick is pressed downward. */
|
||||
char JoystickDownString[] = "Joystick Down\r\n";
|
||||
|
||||
/** String to print through the virtual serial port when the joystick is pressed left. */
|
||||
char JoystickLeftString[] = "Joystick Left\r\n";
|
||||
|
||||
/** String to print through the virtual serial port when the joystick is pressed right. */
|
||||
char JoystickRightString[] = "Joystick Right\r\n";
|
||||
|
||||
/** String to print through the virtual serial port when the joystick is pressed inwards. */
|
||||
char JoystickPressedString[] = "Joystick Pressed\r\n";
|
||||
|
||||
/** Main program entry point. This routine configures the hardware required by the application, then
|
||||
* starts the scheduler to run the application tasks.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
SetupHardware();
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
CheckJoystickMovement();
|
||||
|
||||
uint16_t BytesToDiscard = USB_CDC_BytesReceived(&VirtualSerial_CDC_Interface);
|
||||
while (BytesToDiscard--)
|
||||
USB_CDC_ReceiveByte(&VirtualSerial_CDC_Interface);
|
||||
|
||||
USB_CDC_USBTask(&VirtualSerial_CDC_Interface);
|
||||
USB_USBTask();
|
||||
}
|
||||
}
|
||||
|
||||
void SetupHardware(void)
|
||||
{
|
||||
/* Disable watchdog if enabled by bootloader/fuses */
|
||||
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)
|
||||
void CheckJoystickMovement(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)
|
||||
{
|
||||
uint8_t LEDMask = LEDS_NO_LEDS;
|
||||
|
||||
/* Set the LED mask to the appropriate LED mask based on the given status code */
|
||||
switch (CurrentStatus)
|
||||
{
|
||||
case Status_USBNotReady:
|
||||
LEDMask = (LEDS_LED1);
|
||||
break;
|
||||
case Status_USBEnumerating:
|
||||
LEDMask = (LEDS_LED1 | LEDS_LED2);
|
||||
break;
|
||||
case Status_USBReady:
|
||||
LEDMask = (LEDS_LED2 | LEDS_LED4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the board LEDs to the new LED mask */
|
||||
LEDs_SetAllLEDs(LEDMask);
|
||||
}
|
||||
|
||||
/** Function to manage CDC data transmission and reception to and from the host. */
|
||||
TASK(CDC_Task)
|
||||
{
|
||||
char* ReportString = NULL;
|
||||
uint8_t JoyStatus_LCL = Joystick_GetStatus();
|
||||
char* ReportString = NULL;
|
||||
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)
|
||||
{
|
||||
ReportString = JoystickStrings[4];
|
||||
else
|
||||
ActionSent = false;
|
||||
}
|
||||
else if (ActionSent == false)
|
||||
|
||||
if ((ReportString != NULL) && (ActionSent == false))
|
||||
{
|
||||
ActionSent = true;
|
||||
|
||||
/* Select the Serial Tx Endpoint */
|
||||
Endpoint_SelectEndpoint(CDC_TX_EPNUM);
|
||||
USB_CDC_SendString(&VirtualSerial_CDC_Interface, ReportString, strlen(ReportString));
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the String to the Endpoint */
|
||||
Endpoint_Write_Stream_LE(ReportString, strlen(ReportString));
|
||||
|
||||
/* Remember if the packet to send completely fills the endpoint */
|
||||
bool IsFull = (Endpoint_BytesInEndpoint() == CDC_TXRX_EPSIZE);
|
||||
|
||||
/* Finalize the stream transfer to send the last packet */
|
||||
Endpoint_ClearIN();
|
||||
|
||||
/* If the last packet filled the endpoint, send an empty packet to release the buffer on
|
||||
* the receiver (otherwise all data will be cached until a non-full packet is received) */
|
||||
if (IsFull)
|
||||
void EVENT_USB_Connect(void)
|
||||
{
|
||||
/* 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();
|
||||
}
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
|
||||
}
|
||||
|
||||
/* 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_Disconnect(void)
|
||||
{
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
}
|
||||
|
||||
void EVENT_USB_ConfigurationChanged(void)
|
||||
{
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||
|
||||
if (!(USB_CDC_ConfigureEndpoints(&VirtualSerial_CDC_Interface)))
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
}
|
||||
|
||||
void EVENT_USB_UnhandledControlPacket(void)
|
||||
{
|
||||
USB_CDC_ProcessControlPacket(&VirtualSerial_CDC_Interface);
|
||||
}
|
||||
|
|
|
@ -44,139 +44,26 @@
|
|||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Board/Joystick.h> // Joystick driver
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
|
||||
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Joystick.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/CDC.h>
|
||||
|
||||
/* Macros: */
|
||||
/** CDC Class specific request to get the current virtual serial port configuration settings. */
|
||||
#define REQ_GetLineEncoding 0x21
|
||||
|
||||
/** CDC Class specific request to set the current virtual serial port configuration settings. */
|
||||
#define REQ_SetLineEncoding 0x20
|
||||
|
||||
/** CDC Class specific request to set the current virtual serial port handshake line states. */
|
||||
#define REQ_SetControlLineState 0x22
|
||||
|
||||
/** Notification type constant for a change in the virtual serial port handshake line states, for
|
||||
* use with a USB_Notification_Header_t notification structure when sent to the host via the CDC
|
||||
* notification endpoint.
|
||||
*/
|
||||
#define NOTIF_SerialState 0x20
|
||||
|
||||
/** Mask for the DTR handshake line for use with the REQ_SetControlLineState class specific request
|
||||
* from the host, to indicate that the DTR line state should be high.
|
||||
*/
|
||||
#define CONTROL_LINE_OUT_DTR (1 << 0)
|
||||
|
||||
/** Mask for the RTS handshake line for use with the REQ_SetControlLineState class specific request
|
||||
* from the host, to indicate that theRTS line state should be high.
|
||||
*/
|
||||
#define CONTROL_LINE_OUT_RTS (1 << 1)
|
||||
|
||||
/** Mask for the DCD handshake line for use with the a NOTIF_SerialState class specific notification
|
||||
* from the device to the host, to indicate that the DCD line state is currently high.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_DCD (1 << 0)
|
||||
|
||||
/** Mask for the DSR handshake line for use with the a NOTIF_SerialState class specific notification
|
||||
* from the device to the host, to indicate that the DSR line state is currently high.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_DSR (1 << 1)
|
||||
|
||||
/** Mask for the BREAK handshake line for use with the a NOTIF_SerialState class specific notification
|
||||
* from the device to the host, to indicate that the BREAK line state is currently high.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_BREAK (1 << 2)
|
||||
|
||||
/** Mask for the RING handshake line for use with the a NOTIF_SerialState class specific notification
|
||||
* from the device to the host, to indicate that the RING line state is currently high.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_RING (1 << 3)
|
||||
|
||||
/** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host,
|
||||
* to indicate that a framing error has occurred on the virtual serial port.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_FRAMEERROR (1 << 4)
|
||||
|
||||
/** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host,
|
||||
* to indicate that a parity error has occurred on the virtual serial port.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_PARITYERROR (1 << 5)
|
||||
|
||||
/** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host,
|
||||
* to indicate that a data overrun error has occurred on the virtual serial port.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_OVERRUNERROR (1 << 6)
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the virtual serial port line encoding settings, for storing the current USART configuration
|
||||
* as set by the host via a class specific request.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t BaudRateBPS; /**< Baud rate of the virtual serial port, in bits per second */
|
||||
uint8_t CharFormat; /**< Character format of the virtual serial port, a value from the
|
||||
* CDCDevice_CDC_LineCodingFormats_t enum
|
||||
*/
|
||||
uint8_t ParityType; /**< Parity setting of the virtual serial port, a value from the
|
||||
* CDCDevice_LineCodingParity_t enum
|
||||
*/
|
||||
uint8_t DataBits; /**< Bits of data per character of the virtual serial port */
|
||||
} CDC_Line_Coding_t;
|
||||
|
||||
/** Type define for a CDC notification, sent to the host via the CDC notification endpoint to indicate a
|
||||
* change in the device state asynchronously.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t NotificationType; /**< Notification type, a mask of REQDIR_*, REQTYPE_* and REQREC_* constants
|
||||
* from the library StdRequestType.h header
|
||||
*/
|
||||
uint8_t Notification; /**< Notification value, a NOTIF_* constant */
|
||||
uint16_t wValue; /**< Notification wValue, notification-specific */
|
||||
uint16_t wIndex; /**< Notification wIndex, notification-specific */
|
||||
uint16_t wLength; /**< Notification wLength, notification-specific */
|
||||
} USB_Notification_Header_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible line encoding formats of a virtual serial port. */
|
||||
enum CDCDevice_CDC_LineCodingFormats_t
|
||||
{
|
||||
OneStopBit = 0, /**< Each frame contains one stop bit */
|
||||
OneAndAHalfStopBits = 1, /**< Each frame contains one and a half stop bits */
|
||||
TwoStopBits = 2, /**< Each frame contains two stop bits */
|
||||
};
|
||||
|
||||
/** Enum for the possible line encoding parity settings of a virtual serial port. */
|
||||
enum CDCDevice_LineCodingParity_t
|
||||
{
|
||||
Parity_None = 0, /**< No parity bit mode on each frame */
|
||||
Parity_Odd = 1, /**< Odd parity bit mode on each frame */
|
||||
Parity_Even = 2, /**< Even parity bit mode on each frame */
|
||||
Parity_Mark = 3, /**< Mark parity bit mode on each frame */
|
||||
Parity_Space = 4, /**< Space parity bit mode on each frame */
|
||||
};
|
||||
|
||||
/** Enum for the possible status codes for passing to the UpdateStatus() function. */
|
||||
enum CDC_StatusCodes_t
|
||||
{
|
||||
Status_USBNotReady = 0, /**< USB is not ready (disconnected from a USB host) */
|
||||
Status_USBEnumerating = 1, /**< USB interface is enumerating */
|
||||
Status_USBReady = 2, /**< USB interface is connected and ready */
|
||||
};
|
||||
|
||||
/* Tasks: */
|
||||
TASK(CDC_Task);
|
||||
#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 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
|
||||
|
|
|
@ -37,26 +37,12 @@
|
|||
#define _DESCRIPTORS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
/* 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 <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/CDC.h>
|
||||
|
||||
/* Macros: */
|
||||
/** Endpoint number of the CDC device-to-host notification IN endpoint. */
|
||||
#define CDC_NOTIFICATION_EPNUM 2
|
||||
|
||||
|
|
|
@ -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)"
|
||||
|
||||
|
|
|
@ -37,26 +37,12 @@
|
|||
#define _DESCRIPTORS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
/* 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 <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/CDC.h>
|
||||
|
||||
/* Macros: */
|
||||
/** Endpoint number of the first CDC interface's device-to-host notification IN endpoint. */
|
||||
#define CDC1_NOTIFICATION_EPNUM 3
|
||||
|
||||
|
|
|
@ -28,68 +28,61 @@
|
|||
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
|
||||
USB_ClassInfo_CDC_t VirtualSerial1_CDC_Interface =
|
||||
{
|
||||
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
|
||||
{ .Task = CDC1_Task , .TaskStatus = TASK_STOP },
|
||||
{ .Task = CDC2_Task , .TaskStatus = TASK_STOP },
|
||||
.ControlInterfaceNumber = 0,
|
||||
|
||||
.DataINEndpointNumber = CDC1_TX_EPNUM,
|
||||
.DataINEndpointSize = CDC_TXRX_EPSIZE,
|
||||
|
||||
.DataOUTEndpointNumber = CDC1_RX_EPNUM,
|
||||
.DataOUTEndpointSize = CDC_TXRX_EPSIZE,
|
||||
|
||||
.NotificationEndpointNumber = CDC1_NOTIFICATION_EPNUM,
|
||||
.NotificationEndpointSize = CDC_NOTIFICATION_EPSIZE,
|
||||
};
|
||||
|
||||
/* 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 };
|
||||
USB_ClassInfo_CDC_t VirtualSerial2_CDC_Interface =
|
||||
{
|
||||
.ControlInterfaceNumber = 0,
|
||||
|
||||
/** 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 };
|
||||
.DataINEndpointNumber = CDC2_TX_EPNUM,
|
||||
.DataINEndpointSize = CDC_TXRX_EPSIZE,
|
||||
|
||||
/** String to print through the first virtual serial port when the joystick is pressed upwards. */
|
||||
char JoystickUpString[] = "Joystick Up\r\n";
|
||||
.DataOUTEndpointNumber = CDC2_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 = CDC2_NOTIFICATION_EPNUM,
|
||||
.NotificationEndpointSize = CDC_NOTIFICATION_EPSIZE,
|
||||
};
|
||||
|
||||
/** String to print through the first virtual serial port when the joystick is pressed left. */
|
||||
char JoystickLeftString[] = "Joystick Left\r\n";
|
||||
|
||||
/** String to print through the first virtual serial port when the joystick is pressed right. */
|
||||
char JoystickRightString[] = "Joystick Right\r\n";
|
||||
|
||||
/** String to print through the first virtual serial port when the joystick is pressed inwards. */
|
||||
char JoystickPressedString[] = "Joystick Pressed\r\n";
|
||||
|
||||
/** Main program entry point. This routine configures the hardware required by the application, then
|
||||
* starts the scheduler to run the application tasks.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
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)
|
||||
void CheckJoystickMovement(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)
|
||||
{
|
||||
char* ReportString = NULL;
|
||||
uint8_t JoyStatus_LCL = Joystick_GetStatus();
|
||||
char* ReportString = NULL;
|
||||
static bool ActionSent = false;
|
||||
|
||||
/* Determine if a joystick action has occurred */
|
||||
if (JoyStatus_LCL & JOY_UP)
|
||||
ReportString = JoystickUpString;
|
||||
else if (JoyStatus_LCL & JOY_DOWN)
|
||||
ReportString = JoystickDownString;
|
||||
else if (JoyStatus_LCL & JOY_LEFT)
|
||||
ReportString = JoystickLeftString;
|
||||
else if (JoyStatus_LCL & JOY_RIGHT)
|
||||
ReportString = JoystickRightString;
|
||||
else if (JoyStatus_LCL & JOY_PRESS)
|
||||
ReportString = JoystickPressedString;
|
||||
|
||||
/* Flag management - Only allow one string to be sent per action */
|
||||
if (ReportString == NULL)
|
||||
char* JoystickStrings[] =
|
||||
{
|
||||
"Joystick Up\r\n",
|
||||
"Joystick Down\r\n",
|
||||
"Joystick Left\r\n",
|
||||
"Joystick Right\r\n",
|
||||
"Joystick Pressed\r\n",
|
||||
};
|
||||
|
||||
if (JoyStatus_LCL & JOY_UP)
|
||||
ReportString = JoystickStrings[0];
|
||||
else if (JoyStatus_LCL & JOY_DOWN)
|
||||
ReportString = JoystickStrings[1];
|
||||
else if (JoyStatus_LCL & JOY_LEFT)
|
||||
ReportString = JoystickStrings[2];
|
||||
else if (JoyStatus_LCL & JOY_RIGHT)
|
||||
ReportString = JoystickStrings[3];
|
||||
else if (JoyStatus_LCL & JOY_PRESS)
|
||||
ReportString = JoystickStrings[4];
|
||||
else
|
||||
ActionSent = false;
|
||||
}
|
||||
else if (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);
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
|
||||
}
|
||||
|
||||
/* Check to see if any data has been received */
|
||||
if (Endpoint_IsOUTReceived())
|
||||
void EVENT_USB_Disconnect(void)
|
||||
{
|
||||
/* 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);
|
||||
|
||||
/* Finalize the stream transfer to send the last packet */
|
||||
Endpoint_ClearOUT();
|
||||
|
||||
/* Select the Serial Tx Endpoint */
|
||||
Endpoint_SelectEndpoint(CDC2_TX_EPNUM);
|
||||
|
||||
/* Write the received data to the endpoint */
|
||||
Endpoint_Write_Stream_LE(&Buffer, DataLength);
|
||||
|
||||
/* Finalize the stream transfer to send the last packet */
|
||||
Endpoint_ClearIN();
|
||||
|
||||
/* Wait until the endpoint is ready for the next packet */
|
||||
while (!(Endpoint_IsINReady()));
|
||||
|
||||
/* Send an empty packet to prevent host buffering */
|
||||
Endpoint_ClearIN();
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
}
|
||||
|
||||
void EVENT_USB_ConfigurationChanged(void)
|
||||
{
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||
|
||||
if (!(USB_CDC_ConfigureEndpoints(&VirtualSerial1_CDC_Interface)))
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
|
||||
if (!(USB_CDC_ConfigureEndpoints(&VirtualSerial2_CDC_Interface)))
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
}
|
||||
|
||||
void EVENT_USB_UnhandledControlPacket(void)
|
||||
{
|
||||
USB_CDC_ProcessControlPacket(&VirtualSerial1_CDC_Interface);
|
||||
USB_CDC_ProcessControlPacket(&VirtualSerial2_CDC_Interface);
|
||||
}
|
||||
|
|
|
@ -44,75 +44,26 @@
|
|||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Board/Joystick.h> // Joystick driver
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
|
||||
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Joystick.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/CDC.h>
|
||||
|
||||
/* Macros: */
|
||||
/** CDC Class specific request to get the current virtual serial port configuration settings. */
|
||||
#define REQ_GetLineEncoding 0x21
|
||||
|
||||
/** CDC Class specific request to set the current virtual serial port configuration settings. */
|
||||
#define REQ_SetLineEncoding 0x20
|
||||
|
||||
/** CDC Class specific request to set the current virtual serial port handshake line states. */
|
||||
#define REQ_SetControlLineState 0x22
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the virtual serial port line encoding settings, for storing the current USART configuration
|
||||
* as set by the host via a class specific request.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t BaudRateBPS; /**< Baud rate of the virtual serial port, in bits per second */
|
||||
uint8_t CharFormat; /**< Character format of the virtual serial port, a value from the
|
||||
* CDCDevice_CDC_LineCodingFormats_t enum
|
||||
*/
|
||||
uint8_t ParityType; /**< Parity setting of the virtual serial port, a value from the
|
||||
* CDCDevice_LineCodingParity_t enum
|
||||
*/
|
||||
uint8_t DataBits; /**< Bits of data per character of the virtual serial port */
|
||||
} CDC_Line_Coding_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible line encoding formats of a virtual serial port. */
|
||||
enum CDCDevice_CDC_LineCodingFormats_t
|
||||
{
|
||||
OneStopBit = 0, /**< Each frame contains one stop bit */
|
||||
OneAndAHalfStopBits = 1, /**< Each frame contains one and a half stop bits */
|
||||
TwoStopBits = 2, /**< Each frame contains two stop bits */
|
||||
};
|
||||
|
||||
/** Enum for the possible line encoding parity settings of a virtual serial port. */
|
||||
enum CDCDevice_LineCodingParity_t
|
||||
{
|
||||
Parity_None = 0, /**< No parity bit mode on each frame */
|
||||
Parity_Odd = 1, /**< Odd parity bit mode on each frame */
|
||||
Parity_Even = 2, /**< Even parity bit mode on each frame */
|
||||
Parity_Mark = 3, /**< Mark parity bit mode on each frame */
|
||||
Parity_Space = 4, /**< Space parity bit mode on each frame */
|
||||
};
|
||||
|
||||
/** Enum for the possible status codes for passing to the UpdateStatus() function. */
|
||||
enum DualCDC_StatusCodes_t
|
||||
{
|
||||
Status_USBNotReady = 0, /**< USB is not ready (disconnected from a USB host) */
|
||||
Status_USBEnumerating = 1, /**< USB interface is enumerating */
|
||||
Status_USBReady = 2, /**< USB interface is connected and ready */
|
||||
};
|
||||
|
||||
/* Tasks: */
|
||||
TASK(CDC1_Task);
|
||||
TASK(CDC2_Task);
|
||||
#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 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
|
||||
|
|
|
@ -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)"
|
||||
|
||||
|
|
|
@ -37,30 +37,12 @@
|
|||
#define _DESCRIPTORS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
/* 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 <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/HID.h>
|
||||
|
||||
/** 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.
|
||||
|
@ -87,12 +69,6 @@
|
|||
/** 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);
|
||||
|
|
|
@ -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
|
||||
USB_ClassInfo_HID_t Generic_HID_Interface =
|
||||
{
|
||||
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
|
||||
{ .Task = USB_HID_Report , .TaskStatus = TASK_STOP },
|
||||
.InterfaceNumber = 0,
|
||||
|
||||
.ReportINEndpointNumber = GENERIC_IN_EPNUM,
|
||||
.ReportINEndpointSize = GENERIC_EPSIZE,
|
||||
|
||||
.ReportOUTEndpointNumber = GENERIC_OUT_EPNUM,
|
||||
.ReportOUTEndpointSize = GENERIC_EPSIZE,
|
||||
|
||||
.ReportBufferSize = GENERIC_REPORT_SIZE,
|
||||
|
||||
.UsingReportProtocol = true,
|
||||
};
|
||||
|
||||
/** 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];
|
||||
|
||||
|
||||
/** 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)
|
||||
USB_HID_ProcessControlPacket(&Generic_HID_Interface);
|
||||
}
|
||||
|
||||
void EVENT_USB_StartOfFrame(void)
|
||||
{
|
||||
case REQ_GetReport:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
USB_HID_RegisterStartOfFrame(&Generic_HID_Interface);
|
||||
}
|
||||
|
||||
uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData)
|
||||
{
|
||||
uint8_t GenericData[GENERIC_REPORT_SIZE];
|
||||
// Create generic HID report here
|
||||
|
||||
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();
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetReport:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize)
|
||||
{
|
||||
uint8_t GenericData[GENERIC_REPORT_SIZE];
|
||||
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
/* Wait until the generic report has been sent by the host */
|
||||
while (!(Endpoint_IsOUTReceived()));
|
||||
|
||||
Endpoint_Read_Control_Stream_LE(&GenericData, sizeof(GenericData));
|
||||
|
||||
ProcessGenericHIDReport(GenericData);
|
||||
|
||||
/* Clear the endpoint data */
|
||||
Endpoint_ClearOUT();
|
||||
|
||||
/* Wait until the host is ready to receive the request confirmation */
|
||||
while (!(Endpoint_IsINReady()));
|
||||
|
||||
/* Handshake the request by sending an empty IN packet */
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
|
||||
* log to a serial port, or anything else that is suitable for status updates.
|
||||
*
|
||||
* \param CurrentStatus Current status of the system, from the GenericHID_StatusCodes_t enum
|
||||
*/
|
||||
void UpdateStatus(uint8_t CurrentStatus)
|
||||
{
|
||||
uint8_t LEDMask = LEDS_NO_LEDS;
|
||||
|
||||
/* Set the LED mask to the appropriate LED mask based on the given status code */
|
||||
switch (CurrentStatus)
|
||||
{
|
||||
case Status_USBNotReady:
|
||||
LEDMask = (LEDS_LED1);
|
||||
break;
|
||||
case Status_USBEnumerating:
|
||||
LEDMask = (LEDS_LED1 | LEDS_LED2);
|
||||
break;
|
||||
case Status_USBReady:
|
||||
LEDMask = (LEDS_LED2 | LEDS_LED4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the board LEDs to the new LED mask */
|
||||
LEDs_SetAllLEDs(LEDMask);
|
||||
}
|
||||
|
||||
/** Function to process the lest received report from the host.
|
||||
*
|
||||
* \param DataArray Pointer to a buffer where the last report data is stored
|
||||
*/
|
||||
void ProcessGenericHIDReport(uint8_t* DataArray)
|
||||
{
|
||||
/*
|
||||
This is where you need to process the reports being sent from the host to the device.
|
||||
DataArray is an array holding the last report from the host. This function is called
|
||||
each time the host has sent a report to the device.
|
||||
*/
|
||||
|
||||
for (uint8_t i = 0; i < GENERIC_REPORT_SIZE; i++)
|
||||
LastReceived[i] = DataArray[i];
|
||||
}
|
||||
|
||||
/** 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)
|
||||
{
|
||||
/*
|
||||
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
|
||||
}
|
||||
|
|
|
@ -46,38 +46,28 @@
|
|||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/HID.h>
|
||||
|
||||
/* 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 */
|
||||
};
|
||||
|
||||
/* Task Definitions: */
|
||||
TASK(USB_HID_Report);
|
||||
#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
|
||||
|
|
|
@ -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)"
|
||||
|
||||
|
|
|
@ -37,30 +37,12 @@
|
|||
#define _DESCRIPTORS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/HID.h>
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
|
||||
* specification for details on the structure elements.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
USB_Descriptor_Header_t Header;
|
||||
|
||||
uint16_t HIDSpec;
|
||||
uint8_t CountryCode;
|
||||
|
||||
uint8_t TotalReportDescriptors;
|
||||
|
||||
uint8_t HIDReportType;
|
||||
uint16_t HIDReportLength;
|
||||
} USB_Descriptor_HID_t;
|
||||
|
||||
/** Type define for the data type used to store HID report descriptor elements. */
|
||||
typedef uint8_t USB_Descriptor_HIDReport_Datatype_t;
|
||||
|
||||
/** Type define for the device configuration descriptor structure. This must be defined in the
|
||||
* 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);
|
||||
|
|
|
@ -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
|
||||
USB_ClassInfo_HID_t Joystick_HID_Interface =
|
||||
{
|
||||
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
|
||||
{ .Task = USB_Joystick_Report , .TaskStatus = TASK_STOP },
|
||||
.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();
|
||||
USB_HID_ProcessControlPacket(&Joystick_HID_Interface);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
void EVENT_USB_StartOfFrame(void)
|
||||
{
|
||||
USB_HID_RegisterStartOfFrame(&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)
|
||||
uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData)
|
||||
{
|
||||
static uint8_t PrevJoyStatus = 0;
|
||||
static uint8_t PrevButtonStatus = 0;
|
||||
USB_JoystickReport_Data_t* JoystickReport = (USB_JoystickReport_Data_t*)ReportData;
|
||||
|
||||
uint8_t JoyStatus_LCL = Joystick_GetStatus();
|
||||
uint8_t ButtonStatus_LCL = Buttons_GetStatus();
|
||||
bool InputChanged = false;
|
||||
|
||||
/* Clear the report contents */
|
||||
memset(ReportData, 0, sizeof(USB_JoystickReport_Data_t));
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -44,19 +44,12 @@
|
|||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Board/Joystick.h> // Joystick driver
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
|
||||
#include <LUFA/Drivers/Board/Buttons.h> // Board Buttons driver
|
||||
#include <LUFA/Scheduler/Scheduler.h> // 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 <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/Joystick.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Buttons.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/HID.h>
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -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)"
|
||||
|
||||
|
|
|
@ -38,30 +38,12 @@
|
|||
#define _DESCRIPTORS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/HID.h>
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
|
||||
* specification for details on the structure elements.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
USB_Descriptor_Header_t Header;
|
||||
|
||||
uint16_t HIDSpec;
|
||||
uint8_t CountryCode;
|
||||
|
||||
uint8_t TotalReportDescriptors;
|
||||
|
||||
uint8_t HIDReportType;
|
||||
uint16_t HIDReportLength;
|
||||
} USB_Descriptor_HID_t;
|
||||
|
||||
/** Type define for the data type used to store HID report descriptor elements. */
|
||||
typedef uint8_t USB_Descriptor_HIDReport_Datatype_t;
|
||||
|
||||
/** Type define for the device configuration descriptor structure. This must be defined in the
|
||||
* 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);
|
||||
|
|
|
@ -29,43 +29,37 @@
|
|||
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
|
||||
USB_ClassInfo_HID_t Keyboard_HID_Interface =
|
||||
{
|
||||
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
|
||||
{ .Task = USB_Keyboard_Report , .TaskStatus = TASK_STOP },
|
||||
.InterfaceNumber = 0,
|
||||
|
||||
.ReportINEndpointNumber = KEYBOARD_EPNUM,
|
||||
.ReportINEndpointSize = KEYBOARD_EPSIZE,
|
||||
|
||||
.ReportOUTEndpointNumber = KEYBOARD_LEDS_EPNUM,
|
||||
.ReportOUTEndpointSize = KEYBOARD_EPSIZE,
|
||||
|
||||
.ReportBufferSize = sizeof(USB_KeyboardReport_Data_t),
|
||||
|
||||
.IdleCount = 500,
|
||||
};
|
||||
|
||||
/* 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;
|
||||
|
||||
/** 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;
|
||||
|
||||
/** Current Idle period remaining. When the IdleCount value is set, this tracks the remaining number of idle
|
||||
* milliseconds. This is separate to the IdleCount timer and is incremented and compared as the host may request
|
||||
* the current idle period via a Get Idle HID class request, thus its value must be preserved.
|
||||
*/
|
||||
uint16_t IdleMSRemaining = 0;
|
||||
|
||||
|
||||
/** Main program entry point. This routine configures the hardware required by the application, then
|
||||
* starts the scheduler to run the USB management task.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
SetupHardware();
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
USB_HID_USBTask(&Keyboard_HID_Interface);
|
||||
USB_USBTask();
|
||||
}
|
||||
}
|
||||
|
||||
void SetupHardware()
|
||||
{
|
||||
/* Disable watchdog if enabled by bootloader/fuses */
|
||||
MCUSR &= ~(1 << WDRF);
|
||||
|
@ -77,348 +71,77 @@ int main(void)
|
|||
/* 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();
|
||||
|
||||
/* Initialize USB Subsystem */
|
||||
Buttons_Init();
|
||||
USB_Init();
|
||||
|
||||
/* Scheduling - routine never returns, so put this last in the main function */
|
||||
Scheduler_Start();
|
||||
}
|
||||
|
||||
/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
|
||||
* starts the library USB task to begin the enumeration and USB management process.
|
||||
*/
|
||||
void EVENT_USB_Connect(void)
|
||||
{
|
||||
/* 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);
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||
|
||||
/* Setup Keyboard LED Report Endpoint */
|
||||
Endpoint_ConfigureEndpoint(KEYBOARD_LEDS_EPNUM, EP_TYPE_INTERRUPT,
|
||||
ENDPOINT_DIR_OUT, KEYBOARD_EPSIZE,
|
||||
ENDPOINT_BANK_SINGLE);
|
||||
|
||||
/* Indicate USB connected and ready */
|
||||
UpdateStatus(Status_USBReady);
|
||||
|
||||
/* Start running keyboard reporting task */
|
||||
Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_RUN);
|
||||
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();
|
||||
USB_HID_ProcessControlPacket(&Keyboard_HID_Interface);
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetReport:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
void EVENT_USB_StartOfFrame(void)
|
||||
{
|
||||
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();
|
||||
USB_HID_RegisterStartOfFrame(&Keyboard_HID_Interface);
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_GetProtocol:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData)
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData;
|
||||
|
||||
/* Write the current protocol flag to the host */
|
||||
Endpoint_Write_Byte(UsingReportProtocol);
|
||||
|
||||
/* Send the flag to the host */
|
||||
Endpoint_ClearIN();
|
||||
|
||||
/* Acknowledge status stage */
|
||||
while (!(Endpoint_IsOUTReceived()));
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetProtocol:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
/* Set or clear the flag depending on what the host indicates that the current Protocol should be */
|
||||
UsingReportProtocol = (USB_ControlRequest.wValue != 0);
|
||||
|
||||
/* Acknowledge status stage */
|
||||
while (!(Endpoint_IsINReady()));
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetIdle:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
/* Get idle period in MSB */
|
||||
IdleCount = (USB_ControlRequest.wValue >> 8);
|
||||
|
||||
/* Acknowledge status stage */
|
||||
while (!(Endpoint_IsINReady()));
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_GetIdle:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
/* Write the current idle duration to the host */
|
||||
Endpoint_Write_Byte(IdleCount);
|
||||
|
||||
/* Send the flag to the host */
|
||||
Endpoint_ClearIN();
|
||||
|
||||
/* Acknowledge status stage */
|
||||
while (!(Endpoint_IsOUTReceived()));
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** ISR for the timer 0 compare vector. This ISR fires once each millisecond, and increments the
|
||||
* scheduler elapsed idle period counter when the host has set an idle period.
|
||||
*/
|
||||
ISR(TIMER0_COMPA_vect, ISR_BLOCK)
|
||||
{
|
||||
/* One millisecond has elapsed, decrement the idle time remaining counter if it has not already elapsed */
|
||||
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));
|
||||
uint8_t ButtonStatus_LCL = Buttons_GetStatus();
|
||||
|
||||
if (JoyStatus_LCL & JOY_UP)
|
||||
ReportData->KeyCode[0] = 0x04; // A
|
||||
KeyboardReport->KeyCode[0] = 0x04; // A
|
||||
else if (JoyStatus_LCL & JOY_DOWN)
|
||||
ReportData->KeyCode[0] = 0x05; // B
|
||||
KeyboardReport->KeyCode[0] = 0x05; // B
|
||||
|
||||
if (JoyStatus_LCL & JOY_LEFT)
|
||||
ReportData->KeyCode[0] = 0x06; // C
|
||||
KeyboardReport->KeyCode[0] = 0x06; // C
|
||||
else if (JoyStatus_LCL & JOY_RIGHT)
|
||||
ReportData->KeyCode[0] = 0x07; // D
|
||||
KeyboardReport->KeyCode[0] = 0x07; // D
|
||||
|
||||
if (JoyStatus_LCL & JOY_PRESS)
|
||||
ReportData->KeyCode[0] = 0x08; // E
|
||||
KeyboardReport->KeyCode[0] = 0x08; // E
|
||||
|
||||
if (ButtonStatus_LCL & BUTTONS_BUTTON1)
|
||||
KeyboardReport->KeyCode[0] = 0x09; // F
|
||||
|
||||
return sizeof(USB_KeyboardReport_Data_t);
|
||||
}
|
||||
|
||||
/** Processes a received LED report, and updates the board LEDs states to match.
|
||||
*
|
||||
* \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();
|
||||
}
|
||||
}
|
||||
|
||||
/** 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)
|
||||
void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize)
|
||||
{
|
||||
uint8_t LEDMask = LEDS_NO_LEDS;
|
||||
uint8_t* LEDReport = (uint8_t*)ReportData;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
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 board LEDs to the new LED mask */
|
||||
LEDs_SetAllLEDs(LEDMask);
|
||||
}
|
||||
|
||||
/** Function to manage HID report generation and transmission to the host, when in report mode. */
|
||||
TASK(USB_Keyboard_Report)
|
||||
{
|
||||
/* Check if the USB system is connected to a host */
|
||||
if (USB_IsConnected)
|
||||
{
|
||||
/* Send the next keypress report to the host */
|
||||
SendNextReport();
|
||||
|
||||
/* Process the LED report sent from the host */
|
||||
ReceiveNextReport();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,36 +47,12 @@
|
|||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Board/Joystick.h> // Joystick driver
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // 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 <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/Joystick.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Buttons.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/HID.h>
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -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)"
|
||||
|
||||
|
|
|
@ -38,30 +38,12 @@
|
|||
#define _DESCRIPTORS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/HID.h>
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
|
||||
* specification for details on the structure elements.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
USB_Descriptor_Header_t Header;
|
||||
|
||||
uint16_t HIDSpec;
|
||||
uint8_t CountryCode;
|
||||
|
||||
uint8_t TotalReportDescriptors;
|
||||
|
||||
uint8_t HIDReportType;
|
||||
uint16_t HIDReportLength;
|
||||
} USB_Descriptor_HID_t;
|
||||
|
||||
/** Type define for the data type used to store HID report descriptor elements. */
|
||||
typedef uint8_t USB_Descriptor_HIDReport_Datatype_t;
|
||||
|
||||
/** Type define for the device configuration descriptor structure. This must be defined in the
|
||||
* 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);
|
||||
|
|
|
@ -29,33 +29,51 @@
|
|||
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
|
||||
USB_ClassInfo_HID_t Keyboard_HID_Interface =
|
||||
{
|
||||
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
|
||||
{ .Task = USB_Mouse , .TaskStatus = TASK_RUN },
|
||||
{ .Task = USB_Keyboard , .TaskStatus = TASK_RUN },
|
||||
.InterfaceNumber = 0,
|
||||
|
||||
.ReportINEndpointNumber = KEYBOARD_IN_EPNUM,
|
||||
.ReportINEndpointSize = HID_EPSIZE,
|
||||
|
||||
.ReportOUTEndpointNumber = KEYBOARD_OUT_EPNUM,
|
||||
.ReportOUTEndpointSize = HID_EPSIZE,
|
||||
|
||||
.ReportBufferSize = sizeof(USB_KeyboardReport_Data_t),
|
||||
|
||||
.IdleCount = 500,
|
||||
};
|
||||
|
||||
/* Global Variables */
|
||||
/** Global structure to hold the current keyboard interface HID report, for transmission to the host */
|
||||
USB_KeyboardReport_Data_t KeyboardReportData;
|
||||
USB_ClassInfo_HID_t Mouse_HID_Interface =
|
||||
{
|
||||
.InterfaceNumber = 0,
|
||||
|
||||
/** Global structure to hold the current mouse interface HID report, for transmission to the host */
|
||||
USB_MouseReport_Data_t MouseReportData;
|
||||
.ReportINEndpointNumber = MOUSE_IN_EPNUM,
|
||||
.ReportINEndpointSize = HID_EPSIZE,
|
||||
|
||||
.ReportBufferSize = sizeof(USB_MouseReport_Data_t),
|
||||
|
||||
.ReportOUTEndpointNumber = 0,
|
||||
.ReportOUTEndpointSize = 0,
|
||||
};
|
||||
|
||||
/** Main program entry point. This routine configures the hardware required by the application, then
|
||||
* starts the scheduler to run the USB management task.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
/** 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);
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||
|
||||
/* Setup Keyboard LED Report Endpoint */
|
||||
Endpoint_ConfigureEndpoint(KEYBOARD_OUT_EPNUM, EP_TYPE_INTERRUPT,
|
||||
ENDPOINT_DIR_OUT, HID_EPSIZE,
|
||||
ENDPOINT_BANK_SINGLE);
|
||||
if (!(USB_HID_ConfigureEndpoints(&Keyboard_HID_Interface)))
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
|
||||
/* 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(&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;
|
||||
USB_HID_ProcessControlPacket(&Keyboard_HID_Interface);
|
||||
USB_HID_ProcessControlPacket(&Mouse_HID_Interface);
|
||||
}
|
||||
|
||||
/* Handle HID Class specific requests */
|
||||
switch (USB_ControlRequest.bRequest)
|
||||
void EVENT_USB_StartOfFrame(void)
|
||||
{
|
||||
case REQ_GetReport:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
USB_HID_RegisterStartOfFrame(&Keyboard_HID_Interface);
|
||||
USB_HID_RegisterStartOfFrame(&Mouse_HID_Interface);
|
||||
}
|
||||
|
||||
/* Determine if it is the mouse or the keyboard data that is being requested */
|
||||
if (!(USB_ControlRequest.wIndex))
|
||||
uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData)
|
||||
{
|
||||
ReportData = (uint8_t*)&KeyboardReportData;
|
||||
ReportSize = sizeof(KeyboardReportData);
|
||||
uint8_t JoyStatus_LCL = Joystick_GetStatus();
|
||||
uint8_t ButtonStatus_LCL = Buttons_GetStatus();
|
||||
|
||||
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)
|
||||
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
|
||||
|
||||
return sizeof(USB_KeyboardReport_Data_t);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReportData = (uint8_t*)&MouseReportData;
|
||||
ReportSize = sizeof(MouseReportData);
|
||||
}
|
||||
USB_MouseReport_Data_t* MouseReport = (USB_MouseReport_Data_t*)ReportData;
|
||||
|
||||
/* Write the report data to the control endpoint */
|
||||
Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
|
||||
/* If first board button being held down, no mouse report */
|
||||
if (ButtonStatus_LCL & BUTTONS_BUTTON1)
|
||||
return 0;
|
||||
|
||||
/* Clear the report data afterwards */
|
||||
memset(ReportData, 0, ReportSize);
|
||||
|
||||
/* Finalize the stream transfer to send the last packet or clear the host abort */
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetReport:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
/* Wait until the LED report has been sent by the host */
|
||||
while (!(Endpoint_IsOUTReceived()));
|
||||
|
||||
/* Read in the LED report from the host */
|
||||
uint8_t LEDStatus = Endpoint_Read_Byte();
|
||||
uint8_t LEDMask = LEDS_LED2;
|
||||
|
||||
if (LEDStatus & 0x01) // NUM Lock
|
||||
LEDMask |= LEDS_LED1;
|
||||
|
||||
if (LEDStatus & 0x02) // CAPS Lock
|
||||
LEDMask |= LEDS_LED3;
|
||||
|
||||
if (LEDStatus & 0x04) // SCROLL Lock
|
||||
LEDMask |= LEDS_LED4;
|
||||
|
||||
/* Set the status LEDs to the current HID LED status */
|
||||
LEDs_SetAllLEDs(LEDMask);
|
||||
|
||||
/* Clear the endpoint data */
|
||||
Endpoint_ClearOUT();
|
||||
|
||||
/* Acknowledge status stage */
|
||||
while (!(Endpoint_IsINReady()));
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
|
||||
* log to a serial port, or anything else that is suitable for status updates.
|
||||
*
|
||||
* \param CurrentStatus Current status of the system, from the KeyboardMouse_StatusCodes_t enum
|
||||
*/
|
||||
void UpdateStatus(uint8_t CurrentStatus)
|
||||
{
|
||||
uint8_t LEDMask = LEDS_NO_LEDS;
|
||||
|
||||
/* Set the LED mask to the appropriate LED mask based on the given status code */
|
||||
switch (CurrentStatus)
|
||||
{
|
||||
case Status_USBNotReady:
|
||||
LEDMask = (LEDS_LED1);
|
||||
break;
|
||||
case Status_USBEnumerating:
|
||||
LEDMask = (LEDS_LED1 | LEDS_LED2);
|
||||
break;
|
||||
case Status_USBReady:
|
||||
LEDMask = (LEDS_LED2 | LEDS_LED4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the board LEDs to the new LED mask */
|
||||
LEDs_SetAllLEDs(LEDMask);
|
||||
}
|
||||
|
||||
/** Keyboard task. This generates the next keyboard HID report for the host, and transmits it via the
|
||||
* keyboard IN endpoint when the host is ready for more data. Additionally, it processes host LED status
|
||||
* reports sent to the device via the keyboard OUT reporting endpoint.
|
||||
*/
|
||||
TASK(USB_Keyboard)
|
||||
{
|
||||
uint8_t JoyStatus_LCL = Joystick_GetStatus();
|
||||
|
||||
/* Check if board button is not pressed, if so mouse mode enabled */
|
||||
if (!(Buttons_GetStatus() & BUTTONS_BUTTON1))
|
||||
{
|
||||
if (JoyStatus_LCL & JOY_UP)
|
||||
KeyboardReportData.KeyCode[0] = 0x04; // A
|
||||
MouseReport->Y = -1;
|
||||
else if (JoyStatus_LCL & JOY_DOWN)
|
||||
KeyboardReportData.KeyCode[0] = 0x05; // B
|
||||
|
||||
if (JoyStatus_LCL & JOY_LEFT)
|
||||
KeyboardReportData.KeyCode[0] = 0x06; // C
|
||||
else if (JoyStatus_LCL & JOY_RIGHT)
|
||||
KeyboardReportData.KeyCode[0] = 0x07; // D
|
||||
|
||||
if (JoyStatus_LCL & JOY_PRESS)
|
||||
KeyboardReportData.KeyCode[0] = 0x08; // E
|
||||
}
|
||||
|
||||
/* Check if the USB system is connected to a host and report protocol mode is enabled */
|
||||
if (USB_IsConnected)
|
||||
{
|
||||
/* 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));
|
||||
}
|
||||
|
||||
/* Select the Keyboard LED Report Endpoint */
|
||||
Endpoint_SelectEndpoint(KEYBOARD_OUT_EPNUM);
|
||||
|
||||
/* Check if Keyboard LED Endpoint Ready for Read/Write */
|
||||
if (Endpoint_IsReadWriteAllowed())
|
||||
{
|
||||
/* Read in the LED report from the host */
|
||||
uint8_t LEDStatus = Endpoint_Read_Byte();
|
||||
uint8_t LEDMask = LEDS_LED2;
|
||||
|
||||
if (LEDStatus & 0x01) // NUM Lock
|
||||
LEDMask |= LEDS_LED1;
|
||||
|
||||
if (LEDStatus & 0x02) // CAPS Lock
|
||||
LEDMask |= LEDS_LED3;
|
||||
|
||||
if (LEDStatus & 0x04) // SCROLL Lock
|
||||
LEDMask |= LEDS_LED4;
|
||||
|
||||
/* Set the status LEDs to the current Keyboard LED status */
|
||||
LEDs_SetAllLEDs(LEDMask);
|
||||
|
||||
/* Handshake the OUT Endpoint - clear endpoint and ready for next report */
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Mouse task. This generates the next mouse HID report for the host, and transmits it via the
|
||||
* mouse IN endpoint when the host is ready for more data.
|
||||
*/
|
||||
TASK(USB_Mouse)
|
||||
{
|
||||
uint8_t JoyStatus_LCL = Joystick_GetStatus();
|
||||
|
||||
/* Check if board button is pressed, if so mouse mode enabled */
|
||||
if (Buttons_GetStatus() & BUTTONS_BUTTON1)
|
||||
{
|
||||
if (JoyStatus_LCL & JOY_UP)
|
||||
MouseReportData.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)
|
||||
{
|
||||
/* Select the Mouse Report Endpoint */
|
||||
Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
|
||||
|
||||
/* Check if Mouse Endpoint Ready for Read/Write */
|
||||
if (Endpoint_IsReadWriteAllowed())
|
||||
if (HIDInterfaceInfo == &Keyboard_HID_Interface)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
/* Clear the report data afterwards */
|
||||
memset(&MouseReportData, 0, sizeof(MouseReportData));
|
||||
}
|
||||
if (*LEDReport & 0x02) // CAPS Lock
|
||||
LEDMask |= LEDS_LED3;
|
||||
|
||||
if (*LEDReport & 0x04) // SCROLL Lock
|
||||
LEDMask |= LEDS_LED4;
|
||||
|
||||
LEDs_SetAllLEDs(LEDMask);
|
||||
}
|
||||
}
|
|
@ -41,38 +41,18 @@
|
|||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Board/Joystick.h> // Joystick driver
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
|
||||
#include <LUFA/Drivers/Board/Buttons.h> // Board Buttons driver
|
||||
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
|
||||
|
||||
/* Task Definitions: */
|
||||
TASK(USB_Keyboard);
|
||||
TASK(USB_Mouse);
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible status codes for passing to the UpdateStatus() function. */
|
||||
enum KeyboardMouse_StatusCodes_t
|
||||
{
|
||||
Status_USBNotReady = 0, /**< USB is not ready (disconnected from a USB host) */
|
||||
Status_USBEnumerating = 1, /**< USB interface is enumerating */
|
||||
Status_USBReady = 2, /**< USB interface is connected and ready */
|
||||
};
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/Joystick.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Buttons.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/HID.h>
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -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)"
|
||||
|
||||
|
|
|
@ -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)"
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -342,10 +342,6 @@ void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t Tota
|
|||
|
||||
/* 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 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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
@ -127,18 +127,14 @@ void SCSI_DecodeSCSICommand(void)
|
|||
/* 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);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Command failed - set the CSW status - failed command function updates the SENSE key */
|
||||
CommandStatus.Status = Command_Fail;
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -165,19 +161,18 @@ 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;
|
||||
}
|
||||
|
|
|
@ -40,9 +40,8 @@
|
|||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <LUFA/Common/Common.h> // Function Attribute, Atomic, Debug and ISR Macros
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/MassStorage.h>
|
||||
|
||||
#include "MassStorage.h"
|
||||
#include "Descriptors.h"
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
USB_ClassInfo_MS_t Disk_MS_Interface =
|
||||
{
|
||||
{ .Task = USB_MassStorage , .TaskStatus = TASK_STOP },
|
||||
.InterfaceNumber = 0,
|
||||
|
||||
.DataINEndpointNumber = MASS_STORAGE_IN_EPNUM,
|
||||
.DataINEndpointSize = MASS_STORAGE_IO_EPSIZE,
|
||||
|
||||
.DataOUTEndpointNumber = MASS_STORAGE_OUT_EPNUM,
|
||||
.DataOUTEndpointSize = MASS_STORAGE_IO_EPSIZE,
|
||||
|
||||
.TotalLUNs = TOTAL_LUNS,
|
||||
};
|
||||
|
||||
/* Global Variables */
|
||||
/** Structure to hold the latest Command Block Wrapper issued by the host, containing a SCSI command to execute. */
|
||||
CommandBlockWrapper_t CommandBlock;
|
||||
|
||||
/** 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 };
|
||||
|
||||
/** Flag to asynchronously abort any in-progress data transfers upon the reception of a mass storage reset command. */
|
||||
volatile bool IsMassStoreReset = false;
|
||||
|
||||
/** Main program entry point. This routine configures the hardware required by the application, then
|
||||
* starts the scheduler to run the application tasks.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
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);
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||
|
||||
Endpoint_ConfigureEndpoint(MASS_STORAGE_OUT_EPNUM, EP_TYPE_BULK,
|
||||
ENDPOINT_DIR_OUT, MASS_STORAGE_IO_EPSIZE,
|
||||
ENDPOINT_BANK_DOUBLE);
|
||||
|
||||
/* 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)
|
||||
USB_MS_ProcessControlPacket(&Disk_MS_Interface);
|
||||
}
|
||||
|
||||
bool CALLBACK_USB_MS_SCSICommandReceived(USB_ClassInfo_MS_t* MSInterfaceInfo)
|
||||
{
|
||||
case REQ_MassStorageReset:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
bool CommandSuccess;
|
||||
|
||||
/* Indicate that the current transfer should be aborted */
|
||||
IsMassStoreReset = true;
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
|
||||
CommandSuccess = SCSI_DecodeSCSICommand(MSInterfaceInfo);
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/** Returns the filled Command Status Wrapper back to the host via the bulk data IN endpoint, waiting for the host to clear any
|
||||
* stalled data endpoints as needed.
|
||||
*/
|
||||
static void ReturnCommandStatus(void)
|
||||
{
|
||||
/* Select the Data Out endpoint */
|
||||
Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM);
|
||||
|
||||
/* While data pipe is stalled, wait until the host issues a control request to clear the stall */
|
||||
while (Endpoint_IsStalled())
|
||||
{
|
||||
/* Check if the current command is being aborted by the host */
|
||||
if (IsMassStoreReset)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Select the Data In endpoint */
|
||||
Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM);
|
||||
|
||||
/* While data pipe is stalled, wait until the host issues a control request to clear the stall */
|
||||
while (Endpoint_IsStalled())
|
||||
{
|
||||
/* Check if the current command is being aborted by the host */
|
||||
if (IsMassStoreReset)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Write the CSW to the endpoint */
|
||||
Endpoint_Write_Stream_LE(&CommandStatus, sizeof(CommandStatus),
|
||||
StreamCallback_AbortOnMassStoreReset);
|
||||
|
||||
/* Check if the current command is being aborted by the host */
|
||||
if (IsMassStoreReset)
|
||||
return;
|
||||
|
||||
/* Finalize the stream transfer to send the last packet */
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
/** Stream callback function for the Endpoint stream read and write functions. This callback will abort the current stream transfer
|
||||
* if a Mass Storage Reset request has been issued to the control endpoint.
|
||||
*/
|
||||
uint8_t StreamCallback_AbortOnMassStoreReset(void)
|
||||
{
|
||||
/* Abort if a Mass Storage reset command was received */
|
||||
if (IsMassStoreReset)
|
||||
return STREAMCALLBACK_Abort;
|
||||
|
||||
/* Continue with the current stream operation */
|
||||
return STREAMCALLBACK_Continue;
|
||||
return CommandSuccess;
|
||||
}
|
||||
|
|
|
@ -46,104 +46,33 @@
|
|||
#include "Lib/SCSI.h"
|
||||
#include "Lib/DataflashManager.h"
|
||||
|
||||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
|
||||
#include <LUFA/Drivers/Board/Dataflash.h> // Dataflash chip driver
|
||||
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/Joystick.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Buttons.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/MassStorage.h>
|
||||
|
||||
/* Macros: */
|
||||
/** Mass Storage Class specific request to reset the Mass Storage interface, ready for the next command. */
|
||||
#define REQ_MassStorageReset 0xFF
|
||||
#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
|
||||
|
||||
/** 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
|
||||
|
||||
/** Total number of Logical Units (drives) in the device. The total device capacity is shared equally between
|
||||
* each drive - this can be set to any positive non-zero amount.
|
||||
*/
|
||||
#define TOTAL_LUNS 2
|
||||
|
||||
/** Blocks in each LUN, calculated from the total capacity divided by the total number of Logical Units in the device. */
|
||||
#define LUN_MEDIA_BLOCKS (VIRTUAL_MEMORY_BLOCKS / TOTAL_LUNS)
|
||||
|
||||
/** Magic signature for a Command Block Wrapper used in the Mass Storage Bulk-Only transport protocol. */
|
||||
#define CBW_SIGNATURE 0x43425355UL
|
||||
|
||||
/** Magic signature for a Command Status Wrapper used in the Mass Storage Bulk-Only transport protocol. */
|
||||
#define CSW_SIGNATURE 0x53425355UL
|
||||
|
||||
/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from host-to-device. */
|
||||
#define COMMAND_DIRECTION_DATA_OUT (0 << 7)
|
||||
|
||||
/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from device-to-host. */
|
||||
#define COMMAND_DIRECTION_DATA_IN (1 << 7)
|
||||
|
||||
/* Type defines: */
|
||||
/** Type define for a Command Block Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t Signature; /**< Command block signature, must be CBW_SIGNATURE to indicate a valid Command Block */
|
||||
uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */
|
||||
uint32_t DataTransferLength; /** Length of the optional data portion of the issued command, in bytes */
|
||||
uint8_t Flags; /**< Command block flags, indicating command data direction */
|
||||
uint8_t LUN; /**< Logical Unit number this command is issued to */
|
||||
uint8_t SCSICommandLength; /**< Length of the issued SCSI command within the SCSI command data array */
|
||||
uint8_t SCSICommandData[MAX_SCSI_COMMAND_LENGTH]; /**< Issued SCSI command in the Command Block */
|
||||
} CommandBlockWrapper_t;
|
||||
|
||||
/** Type define for a Command Status Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t Signature; /**< Status block signature, must be CSW_SIGNATURE to indicate a valid Command Status */
|
||||
uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */
|
||||
uint32_t DataTransferResidue; /**< Number of bytes of data not processed in the SCSI command */
|
||||
uint8_t Status; /**< Status code of the issued command - a value from the MassStorage_CommandStatusCodes_t enum */
|
||||
} CommandStatusWrapper_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible command status wrapper return status codes. */
|
||||
enum MassStorage_CommandStatusCodes_t
|
||||
{
|
||||
Command_Pass = 0, /**< Command completed with no error */
|
||||
Command_Fail = 1, /**< Command failed to complete - host may check the exact error via a SCSI REQUEST SENSE command */
|
||||
Phase_Error = 2 /**< Command failed due to being invalid in the current phase */
|
||||
};
|
||||
|
||||
/** Enum for the possible status codes for passing to the UpdateStatus() function. */
|
||||
enum MassStorage_StatusCodes_t
|
||||
{
|
||||
Status_USBNotReady = 0, /**< USB is not ready (disconnected from a USB host) */
|
||||
Status_USBEnumerating = 1, /**< USB interface is enumerating */
|
||||
Status_USBReady = 2, /**< USB interface is connected and ready */
|
||||
Status_CommandBlockError = 3, /**< Processing a SCSI command block from the host */
|
||||
Status_ProcessingCommandBlock = 4, /**< Error during the processing of a SCSI command block from the host */
|
||||
};
|
||||
|
||||
/* Global Variables: */
|
||||
extern CommandBlockWrapper_t CommandBlock;
|
||||
extern CommandStatusWrapper_t CommandStatus;
|
||||
extern volatile bool IsMassStoreReset;
|
||||
|
||||
/* Task Definitions: */
|
||||
TASK(USB_MassStorage);
|
||||
|
||||
/* Function Prototypes: */
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -37,30 +37,12 @@
|
|||
#define _DESCRIPTORS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/HID.h>
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
|
||||
* specification for details on the structure elements.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
USB_Descriptor_Header_t Header;
|
||||
|
||||
uint16_t HIDSpec;
|
||||
uint8_t CountryCode;
|
||||
|
||||
uint8_t TotalReportDescriptors;
|
||||
|
||||
uint8_t HIDReportType;
|
||||
uint16_t HIDReportLength;
|
||||
} USB_Descriptor_HID_t;
|
||||
|
||||
/** Type define for the data type used to store HID report descriptor elements. */
|
||||
typedef uint8_t USB_Descriptor_HIDReport_Datatype_t;
|
||||
|
||||
/** Type define for the device configuration descriptor structure. This must be defined in the
|
||||
* 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);
|
||||
|
|
|
@ -28,43 +28,32 @@
|
|||
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
|
||||
USB_ClassInfo_HID_t Mouse_HID_Interface =
|
||||
{
|
||||
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
|
||||
{ .Task = USB_Mouse_Report , .TaskStatus = TASK_STOP },
|
||||
.InterfaceNumber = 0,
|
||||
|
||||
.ReportINEndpointNumber = MOUSE_EPNUM,
|
||||
.ReportINEndpointSize = MOUSE_EPSIZE,
|
||||
|
||||
.ReportBufferSize = sizeof(USB_MouseReport_Data_t),
|
||||
};
|
||||
|
||||
/* 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;
|
||||
|
||||
/** 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;
|
||||
|
||||
/** Current Idle period remaining. When the IdleCount value is set, this tracks the remaining number of idle
|
||||
* milliseconds. This is separate to the IdleCount timer and is incremented and compared as the host may request
|
||||
* the current idle period via a Get Idle HID class request, thus its value must be preserved.
|
||||
*/
|
||||
uint16_t IdleMSRemaining = 0;
|
||||
|
||||
|
||||
/** Main program entry point. This routine configures the hardware required by the application, then
|
||||
* starts the scheduler to run the application tasks.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
SetupHardware();
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
USB_HID_USBTask(&Mouse_HID_Interface);
|
||||
USB_USBTask();
|
||||
}
|
||||
}
|
||||
|
||||
void SetupHardware(void)
|
||||
{
|
||||
/* Disable watchdog if enabled by bootloader/fuses */
|
||||
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);
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||
|
||||
/* Indicate USB connected and ready */
|
||||
UpdateStatus(Status_USBReady);
|
||||
|
||||
/* 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();
|
||||
USB_HID_ProcessControlPacket(&Mouse_HID_Interface);
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_GetProtocol:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
void EVENT_USB_StartOfFrame(void)
|
||||
{
|
||||
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();
|
||||
USB_HID_RegisterStartOfFrame(&Mouse_HID_Interface);
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetProtocol:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData)
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
USB_MouseReport_Data_t* MouseReport = (USB_MouseReport_Data_t*)ReportData;
|
||||
|
||||
/* Set or clear the flag depending on what the host indicates that the current Protocol should be */
|
||||
UsingReportProtocol = (USB_ControlRequest.wValue != 0);
|
||||
|
||||
/* Acknowledge status stage */
|
||||
while (!(Endpoint_IsINReady()));
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetIdle:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
/* Get idle period in MSB */
|
||||
IdleCount = (USB_ControlRequest.wValue >> 8);
|
||||
|
||||
/* Acknowledge status stage */
|
||||
while (!(Endpoint_IsINReady()));
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_GetIdle:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
/* Write the current idle duration to the host */
|
||||
Endpoint_Write_Byte(IdleCount);
|
||||
|
||||
/* Send the flag to the host */
|
||||
Endpoint_ClearIN();
|
||||
|
||||
/* Acknowledge status stage */
|
||||
while (!(Endpoint_IsOUTReceived()));
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** ISR for the timer 0 compare vector. This ISR fires once each millisecond, and increments the
|
||||
* scheduler elapsed idle period counter when the host has set an idle period.
|
||||
*/
|
||||
ISR(TIMER0_COMPA_vect, ISR_BLOCK)
|
||||
{
|
||||
/* One millisecond has elapsed, decrement the idle time remaining counter if it has not already elapsed */
|
||||
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 CreateMouseReport(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);
|
||||
MouseReport->Button |= (1 << 1);
|
||||
|
||||
return sizeof(USB_MouseReport_Data_t);
|
||||
}
|
||||
|
||||
/** Sends the next HID report to the host, via the keyboard data endpoint. */
|
||||
void SendNextReport(void)
|
||||
void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* Select the Mouse Report Endpoint */
|
||||
Endpoint_SelectEndpoint(MOUSE_EPNUM);
|
||||
|
||||
/* Check if Mouse Endpoint Ready for Read/Write and if we should send a new report */
|
||||
if (Endpoint_IsReadWriteAllowed() && SendReport)
|
||||
{
|
||||
/* Write Mouse Report Data */
|
||||
Endpoint_Write_Stream_LE(&MouseReportData, sizeof(MouseReportData));
|
||||
|
||||
/* Finalize the stream transfer to send the last packet */
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
}
|
||||
|
||||
/** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
|
||||
* log to a serial port, or anything else that is suitable for status updates.
|
||||
*
|
||||
* \param CurrentStatus Current status of the system, from the Mouse_StatusCodes_t enum
|
||||
*/
|
||||
void UpdateStatus(uint8_t CurrentStatus)
|
||||
{
|
||||
uint8_t LEDMask = LEDS_NO_LEDS;
|
||||
|
||||
/* Set the LED mask to the appropriate LED mask based on the given status code */
|
||||
switch (CurrentStatus)
|
||||
{
|
||||
case Status_USBNotReady:
|
||||
LEDMask = (LEDS_LED1);
|
||||
break;
|
||||
case Status_USBEnumerating:
|
||||
LEDMask = (LEDS_LED1 | LEDS_LED2);
|
||||
break;
|
||||
case Status_USBReady:
|
||||
LEDMask = (LEDS_LED2 | LEDS_LED4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the board LEDs to the new LED mask */
|
||||
LEDs_SetAllLEDs(LEDMask);
|
||||
}
|
||||
|
||||
/** Task to manage HID report generation and transmission to the host, when in report mode. */
|
||||
TASK(USB_Mouse_Report)
|
||||
{
|
||||
/* Check if the USB system is connected to a host */
|
||||
if (USB_IsConnected)
|
||||
{
|
||||
/* Send the next mouse report to the host */
|
||||
SendNextReport();
|
||||
}
|
||||
// Unused (but mandatory for the HID class driver) in this demo, since there are no Host->Device reports
|
||||
}
|
||||
|
|
|
@ -46,37 +46,12 @@
|
|||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Board/Joystick.h> // Joystick driver
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
|
||||
#include <LUFA/Drivers/Board/Buttons.h> // Board Buttons driver
|
||||
#include <LUFA/Scheduler/Scheduler.h> // 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 <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/Joystick.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Buttons.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/HID.h>
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -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)"
|
||||
|
||||
|
|
|
@ -40,8 +40,6 @@
|
|||
#include <avr/io.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <LUFA/Scheduler/Scheduler.h>
|
||||
|
||||
#include "EthernetProtocols.h"
|
||||
#include "Ethernet.h"
|
||||
#include "ProtocolDecoders.h"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
#include <avr/io.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <LUFA/Drivers/USB/Class/Device/RNDIS.h>
|
||||
|
||||
#include "EthernetProtocols.h"
|
||||
#include "ProtocolDecoders.h"
|
||||
#include "ICMP.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}
|
||||
|
||||
|
@ -65,12 +70,6 @@
|
|||
*/
|
||||
#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
|
||||
|
|
|
@ -72,12 +72,6 @@
|
|||
#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 define for a protocol IP address of a device on a network */
|
||||
typedef struct
|
||||
{
|
||||
|
|
|
@ -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)],
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,394 +0,0 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* RNDIS command handler functions. This handles RNDIS commands according to
|
||||
* the Microsoft RNDIS specification, creating a USB Ethernet network adapter.
|
||||
*/
|
||||
|
||||
#define INCLUDE_FROM_RNDIS_C
|
||||
#include "RNDIS.h"
|
||||
|
||||
/* Global Variables: */
|
||||
/** Physical MAC address of the network adapter, which becomes the MAC address of the host for packets sent to the adapter. */
|
||||
static MAC_Address_t PROGMEM AdapterMACAddress = {ADAPTER_MAC_ADDRESS};
|
||||
|
||||
/** Vendor description of the adapter. This is overridden by the INF file required to install the appropriate RNDIS drivers for
|
||||
* the device, but may still be used by the OS in some circumstances.
|
||||
*/
|
||||
static char PROGMEM AdapterVendorDescription[] = "LUFA RNDIS Adapter";
|
||||
|
||||
/** List of RNDIS OID commands supported by this adapter. */
|
||||
static const uint32_t PROGMEM AdapterSupportedOIDList[] =
|
||||
{
|
||||
OID_GEN_SUPPORTED_LIST,
|
||||
OID_GEN_PHYSICAL_MEDIUM,
|
||||
OID_GEN_HARDWARE_STATUS,
|
||||
OID_GEN_MEDIA_SUPPORTED,
|
||||
OID_GEN_MEDIA_IN_USE,
|
||||
OID_GEN_MAXIMUM_FRAME_SIZE,
|
||||
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
||||
OID_GEN_LINK_SPEED,
|
||||
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
||||
OID_GEN_RECEIVE_BLOCK_SIZE,
|
||||
OID_GEN_VENDOR_ID,
|
||||
OID_GEN_VENDOR_DESCRIPTION,
|
||||
OID_GEN_CURRENT_PACKET_FILTER,
|
||||
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
||||
OID_GEN_MEDIA_CONNECT_STATUS,
|
||||
OID_GEN_XMIT_OK,
|
||||
OID_GEN_RCV_OK,
|
||||
OID_GEN_XMIT_ERROR,
|
||||
OID_GEN_RCV_ERROR,
|
||||
OID_GEN_RCV_NO_BUFFER,
|
||||
OID_802_3_PERMANENT_ADDRESS,
|
||||
OID_802_3_CURRENT_ADDRESS,
|
||||
OID_802_3_MULTICAST_LIST,
|
||||
OID_802_3_MAXIMUM_LIST_SIZE,
|
||||
OID_802_3_RCV_ERROR_ALIGNMENT,
|
||||
OID_802_3_XMIT_ONE_COLLISION,
|
||||
OID_802_3_XMIT_MORE_COLLISIONS,
|
||||
};
|
||||
|
||||
/** Buffer for RNDIS messages (as distinct from Ethernet frames sent through the adapter. This must be big enough to hold the entire
|
||||
* Supported OID list, plus the response header. The buffer is half-duplex, and is written to as it is read to save on SRAM - for this
|
||||
* reason, care must be taken when constructing RNDIS responses that unread data is not overwritten when writing in responses.
|
||||
*/
|
||||
uint8_t RNDISMessageBuffer[sizeof(AdapterSupportedOIDList) + sizeof(RNDIS_QUERY_CMPLT_t)];
|
||||
|
||||
/** Pointer to the RNDIS message header at the top of the RNDIS message buffer, for convenience. */
|
||||
RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISMessageBuffer;
|
||||
|
||||
/** Indicates if a RNDIS message response is ready to be sent back to the host. */
|
||||
bool ResponseReady = false;
|
||||
|
||||
/** Current RNDIS adapter state, a value from the RNDIS_States_t enum. */
|
||||
uint8_t CurrRNDISState = RNDIS_Uninitialized;
|
||||
|
||||
/** Current Ethernet packet filter mask. This is non-zero when the adapter is initialized, or zero when disabled. */
|
||||
uint32_t CurrPacketFilter = 0;
|
||||
|
||||
|
||||
/** Processes the RNDIS message received by the host and stored in the RNDISMessageBuffer global buffer. If a response is
|
||||
* created, the ResponseReady global is updated so that the response is written back to the host upon request.
|
||||
*/
|
||||
void ProcessRNDISControlMessage(void)
|
||||
{
|
||||
/* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of
|
||||
this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */
|
||||
|
||||
switch (MessageHeader->MessageType)
|
||||
{
|
||||
case REMOTE_NDIS_INITIALIZE_MSG:
|
||||
/* Initialize the adapter - return information about the supported RNDIS version and buffer sizes */
|
||||
|
||||
ResponseReady = true;
|
||||
|
||||
RNDIS_INITIALIZE_MSG_t* INITIALIZE_Message = (RNDIS_INITIALIZE_MSG_t*)&RNDISMessageBuffer;
|
||||
RNDIS_INITIALIZE_CMPLT_t* INITIALIZE_Response = (RNDIS_INITIALIZE_CMPLT_t*)&RNDISMessageBuffer;
|
||||
|
||||
INITIALIZE_Response->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
|
||||
INITIALIZE_Response->MessageLength = sizeof(RNDIS_INITIALIZE_CMPLT_t);
|
||||
INITIALIZE_Response->RequestId = INITIALIZE_Message->RequestId;
|
||||
INITIALIZE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||
|
||||
INITIALIZE_Response->MajorVersion = REMOTE_NDIS_VERSION_MAJOR;
|
||||
INITIALIZE_Response->MinorVersion = REMOTE_NDIS_VERSION_MINOR;
|
||||
INITIALIZE_Response->DeviceFlags = REMOTE_NDIS_DF_CONNECTIONLESS;
|
||||
INITIALIZE_Response->Medium = REMOTE_NDIS_MEDIUM_802_3;
|
||||
INITIALIZE_Response->MaxPacketsPerTransfer = 1;
|
||||
INITIALIZE_Response->MaxTransferSize = (sizeof(RNDIS_PACKET_MSG_t) + ETHERNET_FRAME_SIZE_MAX);
|
||||
INITIALIZE_Response->PacketAlignmentFactor = 0;
|
||||
INITIALIZE_Response->AFListOffset = 0;
|
||||
INITIALIZE_Response->AFListSize = 0;
|
||||
|
||||
CurrRNDISState = RNDIS_Initialized;
|
||||
|
||||
break;
|
||||
case REMOTE_NDIS_HALT_MSG:
|
||||
/* Halt the adapter, reset the adapter state - note that no response should be returned when completed */
|
||||
|
||||
ResponseReady = false;
|
||||
MessageHeader->MessageLength = 0;
|
||||
|
||||
CurrRNDISState = RNDIS_Uninitialized;
|
||||
|
||||
break;
|
||||
case REMOTE_NDIS_QUERY_MSG:
|
||||
/* Request for information about a parameter about the adapter, specified as an OID token */
|
||||
|
||||
ResponseReady = true;
|
||||
|
||||
RNDIS_QUERY_MSG_t* QUERY_Message = (RNDIS_QUERY_MSG_t*)&RNDISMessageBuffer;
|
||||
RNDIS_QUERY_CMPLT_t* QUERY_Response = (RNDIS_QUERY_CMPLT_t*)&RNDISMessageBuffer;
|
||||
uint32_t Query_Oid = QUERY_Message->Oid;
|
||||
|
||||
void* QueryData = &RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
|
||||
QUERY_Message->InformationBufferOffset];
|
||||
void* ResponseData = &RNDISMessageBuffer[sizeof(RNDIS_QUERY_CMPLT_t)];
|
||||
uint16_t ResponseSize;
|
||||
|
||||
QUERY_Response->MessageType = REMOTE_NDIS_QUERY_CMPLT;
|
||||
QUERY_Response->MessageLength = sizeof(RNDIS_QUERY_CMPLT_t);
|
||||
|
||||
if (ProcessNDISQuery(Query_Oid, QueryData, QUERY_Message->InformationBufferLength,
|
||||
ResponseData, &ResponseSize))
|
||||
{
|
||||
QUERY_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||
QUERY_Response->MessageLength += ResponseSize;
|
||||
|
||||
QUERY_Response->InformationBufferLength = ResponseSize;
|
||||
QUERY_Response->InformationBufferOffset = (sizeof(RNDIS_QUERY_CMPLT_t) - sizeof(RNDIS_Message_Header_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
QUERY_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
|
||||
|
||||
QUERY_Response->InformationBufferLength = 0;
|
||||
QUERY_Response->InformationBufferOffset = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
case REMOTE_NDIS_SET_MSG:
|
||||
/* Request to set a parameter of the adapter, specified as an OID token */
|
||||
|
||||
ResponseReady = true;
|
||||
|
||||
RNDIS_SET_MSG_t* SET_Message = (RNDIS_SET_MSG_t*)&RNDISMessageBuffer;
|
||||
RNDIS_SET_CMPLT_t* SET_Response = (RNDIS_SET_CMPLT_t*)&RNDISMessageBuffer;
|
||||
uint32_t SET_Oid = SET_Message->Oid;
|
||||
|
||||
SET_Response->MessageType = REMOTE_NDIS_SET_CMPLT;
|
||||
SET_Response->MessageLength = sizeof(RNDIS_SET_CMPLT_t);
|
||||
SET_Response->RequestId = SET_Message->RequestId;
|
||||
|
||||
void* SetData = &RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
|
||||
SET_Message->InformationBufferOffset];
|
||||
|
||||
if (ProcessNDISSet(SET_Oid, SetData, SET_Message->InformationBufferLength))
|
||||
SET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||
else
|
||||
SET_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
|
||||
|
||||
break;
|
||||
case REMOTE_NDIS_RESET_MSG:
|
||||
/* Soft reset the adapter */
|
||||
|
||||
ResponseReady = true;
|
||||
|
||||
RNDIS_RESET_CMPLT_t* RESET_Response = (RNDIS_RESET_CMPLT_t*)&RNDISMessageBuffer;
|
||||
|
||||
RESET_Response->MessageType = REMOTE_NDIS_RESET_CMPLT;
|
||||
RESET_Response->MessageLength = sizeof(RNDIS_RESET_CMPLT_t);
|
||||
RESET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||
RESET_Response->AddressingReset = 0;
|
||||
|
||||
break;
|
||||
case REMOTE_NDIS_KEEPALIVE_MSG:
|
||||
/* Keep alive message sent to the adapter every 5 seconds when idle to ensure it is still responding */
|
||||
|
||||
ResponseReady = true;
|
||||
|
||||
RNDIS_KEEPALIVE_MSG_t* KEEPALIVE_Message = (RNDIS_KEEPALIVE_MSG_t*)&RNDISMessageBuffer;
|
||||
RNDIS_KEEPALIVE_CMPLT_t* KEEPALIVE_Response = (RNDIS_KEEPALIVE_CMPLT_t*)&RNDISMessageBuffer;
|
||||
|
||||
KEEPALIVE_Response->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
|
||||
KEEPALIVE_Response->MessageLength = sizeof(RNDIS_KEEPALIVE_CMPLT_t);
|
||||
KEEPALIVE_Response->RequestId = KEEPALIVE_Message->RequestId;
|
||||
KEEPALIVE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Processes RNDIS query commands, retrieving information from the adapter and reporting it back to the host. The requested
|
||||
* parameter is given as an OID value.
|
||||
*
|
||||
* \param OId OId value of the parameter being queried
|
||||
* \param QueryData Pointer to any extra query data being sent by the host to the device inside the RNDIS message buffer
|
||||
* \param QuerySize Size in bytes of the extra query data being sent by the host
|
||||
* \param ResponseData Pointer to the start of the query response inside the RNDIS message buffer
|
||||
* \param ResponseSize Pointer to the size in bytes of the response data being sent to the host
|
||||
*
|
||||
* \return Boolean true if the query was handled, false otherwise
|
||||
*/
|
||||
static bool ProcessNDISQuery(uint32_t OId, void* QueryData, uint16_t QuerySize,
|
||||
void* ResponseData, uint16_t* ResponseSize)
|
||||
{
|
||||
/* Handler for REMOTE_NDIS_QUERY_MSG messages */
|
||||
|
||||
switch (OId)
|
||||
{
|
||||
case OID_GEN_SUPPORTED_LIST:
|
||||
*ResponseSize = sizeof(AdapterSupportedOIDList);
|
||||
|
||||
/* Copy the list of supported NDIS OID tokens to the response buffer */
|
||||
memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList));
|
||||
|
||||
return true;
|
||||
case OID_GEN_PHYSICAL_MEDIUM:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Indicate that the device is a true ethernet link */
|
||||
*((uint32_t*)ResponseData) = 0;
|
||||
|
||||
return true;
|
||||
case OID_GEN_HARDWARE_STATUS:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Always indicate hardware ready */
|
||||
*((uint32_t*)ResponseData) = NdisHardwareStatusReady;
|
||||
|
||||
return true;
|
||||
case OID_GEN_MEDIA_SUPPORTED:
|
||||
case OID_GEN_MEDIA_IN_USE:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Indicate 802.3 (Ethernet) supported by the adapter */
|
||||
*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIUM_802_3;
|
||||
|
||||
return true;
|
||||
case OID_GEN_VENDOR_ID:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */
|
||||
*((uint32_t*)ResponseData) = 0x00FFFFFF;
|
||||
|
||||
return true;
|
||||
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
||||
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
||||
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Indicate that the maximum frame size is the size of the ethernet frame buffer */
|
||||
*((uint32_t*)ResponseData) = ETHERNET_FRAME_SIZE_MAX;
|
||||
|
||||
return true;
|
||||
case OID_GEN_VENDOR_DESCRIPTION:
|
||||
*ResponseSize = sizeof(AdapterVendorDescription);
|
||||
|
||||
/* Copy vendor description string to the response buffer */
|
||||
memcpy_P(ResponseData, AdapterVendorDescription, sizeof(AdapterVendorDescription));
|
||||
|
||||
return true;
|
||||
case OID_GEN_MEDIA_CONNECT_STATUS:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Always indicate that the adapter is connected to a network */
|
||||
*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIA_STATE_CONNECTED;
|
||||
|
||||
return true;
|
||||
case OID_GEN_LINK_SPEED:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Indicate 10Mb/s link speed */
|
||||
*((uint32_t*)ResponseData) = 100000;
|
||||
|
||||
return true;
|
||||
case OID_802_3_PERMANENT_ADDRESS:
|
||||
case OID_802_3_CURRENT_ADDRESS:
|
||||
*ResponseSize = sizeof(MAC_Address_t);
|
||||
|
||||
/* Copy over the fixed adapter MAC to the response buffer */
|
||||
memcpy_P(ResponseData, &AdapterMACAddress, sizeof(MAC_Address_t));
|
||||
|
||||
return true;
|
||||
case OID_802_3_MAXIMUM_LIST_SIZE:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Indicate only one multicast address supported */
|
||||
*((uint32_t*)ResponseData) = 1;
|
||||
|
||||
return true;
|
||||
case OID_GEN_CURRENT_PACKET_FILTER:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Indicate the current packet filter mask */
|
||||
*((uint32_t*)ResponseData) = CurrPacketFilter;
|
||||
|
||||
return true;
|
||||
case OID_GEN_XMIT_OK:
|
||||
case OID_GEN_RCV_OK:
|
||||
case OID_GEN_XMIT_ERROR:
|
||||
case OID_GEN_RCV_ERROR:
|
||||
case OID_GEN_RCV_NO_BUFFER:
|
||||
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
||||
case OID_802_3_XMIT_ONE_COLLISION:
|
||||
case OID_802_3_XMIT_MORE_COLLISIONS:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Unused statistic OIDs - always return 0 for each */
|
||||
*((uint32_t*)ResponseData) = 0;
|
||||
|
||||
return true;
|
||||
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */
|
||||
*((uint32_t*)ResponseData) = (sizeof(RNDISMessageBuffer) + ETHERNET_FRAME_SIZE_MAX);
|
||||
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Processes RNDIS set commands, setting adapter parameters to values given by the host. The requested parameter is given
|
||||
* as an OID value.
|
||||
*
|
||||
* \param OId OId value of the parameter being set
|
||||
* \param SetData Pointer to the parameter value in the RNDIS message buffer
|
||||
* \param SetSize Size in bytes of the parameter value being sent by the host
|
||||
*
|
||||
* \return Boolean true if the set was handled, false otherwise
|
||||
*/
|
||||
static bool ProcessNDISSet(uint32_t OId, void* SetData, uint16_t SetSize)
|
||||
{
|
||||
/* Handler for REMOTE_NDIS_SET_MSG messages */
|
||||
|
||||
switch (OId)
|
||||
{
|
||||
case OID_GEN_CURRENT_PACKET_FILTER:
|
||||
/* Save the packet filter mask in case the host queries it again later */
|
||||
CurrPacketFilter = *((uint32_t*)SetData);
|
||||
|
||||
/* Set the RNDIS state to initialized if the packet filter is non-zero */
|
||||
CurrRNDISState = ((CurrPacketFilter) ? RNDIS_Data_Initialized : RNDIS_Data_Initialized);
|
||||
|
||||
return true;
|
||||
case OID_802_3_MULTICAST_LIST:
|
||||
/* Do nothing - throw away the value from the host as it is unused */
|
||||
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -56,7 +56,7 @@ TCP_ConnectionState_t ConnectionStateTable[MAX_TCP_CONNECTIONS];
|
|||
* level. If an application produces a response, this task constructs the appropriate Ethernet frame and places it into the Ethernet OUT
|
||||
* 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,11 +86,11 @@ 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) +
|
||||
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 = &FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t) +
|
||||
void* TCPDataOUT = &RNDISInterfaceInfo->FrameOUT.FrameData[sizeof(Ethernet_Frame_Header_t) +
|
||||
sizeof(IP_Header_t) +
|
||||
sizeof(TCP_Header_t)];
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -40,8 +40,6 @@
|
|||
#include <avr/io.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <LUFA/Scheduler/Scheduler.h>
|
||||
|
||||
#include "EthernetProtocols.h"
|
||||
#include "Ethernet.h"
|
||||
#include "ProtocolDecoders.h"
|
||||
|
@ -230,13 +228,11 @@
|
|||
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);
|
||||
|
|
|
@ -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
|
||||
USB_ClassInfo_RNDIS_t Ethernet_RNDIS_Interface =
|
||||
{
|
||||
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
|
||||
{ .Task = Ethernet_Task , .TaskStatus = TASK_STOP },
|
||||
{ .Task = TCP_Task , .TaskStatus = TASK_STOP },
|
||||
{ .Task = RNDIS_Task , .TaskStatus = TASK_STOP },
|
||||
.ControlInterfaceNumber = 0,
|
||||
|
||||
.DataINEndpointNumber = CDC_TX_EPNUM,
|
||||
.DataINEndpointSize = CDC_TXRX_EPSIZE,
|
||||
|
||||
.DataOUTEndpointNumber = CDC_RX_EPNUM,
|
||||
.DataOUTEndpointSize = CDC_TXRX_EPSIZE,
|
||||
|
||||
.NotificationEndpointNumber = CDC_NOTIFICATION_EPNUM,
|
||||
.NotificationEndpointSize = CDC_NOTIFICATION_EPSIZE,
|
||||
|
||||
.AdapterVendorDescription = "LUFA RNDIS Demo Adapter",
|
||||
.AdapterMACAddress = {ADAPTER_MAC_ADDRESS},
|
||||
};
|
||||
|
||||
/** Main program entry point. This routine configures the hardware required by the application, then
|
||||
* starts the scheduler to run the USB management task.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -46,55 +46,33 @@
|
|||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include "Lib/RNDIS.h"
|
||||
#include "Lib/Ethernet.h"
|
||||
#include "Lib/TCP.h"
|
||||
#include "Lib/ARP.h"
|
||||
#include "Lib/Webserver.h"
|
||||
|
||||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
|
||||
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
|
||||
#include <LUFA/Drivers/Peripheral/SerialStream.h> // Serial stream driver
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Joystick.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/RNDIS.h>
|
||||
|
||||
/* Macros: */
|
||||
/** Notification value to indicate that a frame is ready to be read by the host. */
|
||||
#define NOTIF_RESPONSE_AVAILABLE 0x01
|
||||
|
||||
/* 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 */
|
||||
};
|
||||
|
||||
/* Tasks: */
|
||||
TASK(RNDIS_Task);
|
||||
TASK(Ethernet_Task);
|
||||
#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
|
||||
|
||||
/* 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 CALLBACK_USB_RNDIS_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -37,26 +37,12 @@
|
|||
#define _DESCRIPTORS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
/* 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 <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/CDC.h>
|
||||
|
||||
/* Macros: */
|
||||
/** Endpoint number of the CDC device-to-host notification IN endpoint. */
|
||||
#define CDC_NOTIFICATION_EPNUM 2
|
||||
|
||||
|
|
|
@ -30,37 +30,54 @@
|
|||
|
||||
#include "USBtoSerial.h"
|
||||
|
||||
/* Scheduler Task List */
|
||||
TASK_LIST
|
||||
{
|
||||
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
|
||||
{ .Task = CDC_Task , .TaskStatus = TASK_STOP },
|
||||
};
|
||||
|
||||
/* Globals: */
|
||||
/** Contains the current baud rate and other settings of the virtual serial port.
|
||||
*
|
||||
* These values are set by the host via a class-specific request, and the physical USART should be reconfigured to match the
|
||||
* new settings each time they are changed by the host.
|
||||
*/
|
||||
CDC_Line_Coding_t LineCoding = { .BaudRateBPS = 9600,
|
||||
.CharFormat = OneStopBit,
|
||||
.ParityType = Parity_None,
|
||||
.DataBits = 8 };
|
||||
|
||||
/** Ring (circular) buffer to hold the RX data - data from the host to the attached device on the serial port. */
|
||||
RingBuff_t Rx_Buffer;
|
||||
|
||||
/** Ring (circular) buffer to hold the TX data - data from the attached device on the serial port to the host. */
|
||||
RingBuff_t Tx_Buffer;
|
||||
|
||||
/** Flag to indicate if the USART is currently transmitting data from the Rx_Buffer circular buffer. */
|
||||
volatile bool Transmitting = false;
|
||||
USB_ClassInfo_CDC_t VirtualSerial_CDC_Interface =
|
||||
{
|
||||
.ControlInterfaceNumber = 0,
|
||||
|
||||
.DataINEndpointNumber = CDC_TX_EPNUM,
|
||||
.DataINEndpointSize = CDC_TXRX_EPSIZE,
|
||||
|
||||
.DataOUTEndpointNumber = CDC_RX_EPNUM,
|
||||
.DataOUTEndpointSize = CDC_TXRX_EPSIZE,
|
||||
|
||||
.NotificationEndpointNumber = CDC_NOTIFICATION_EPNUM,
|
||||
.NotificationEndpointSize = CDC_NOTIFICATION_EPSIZE,
|
||||
};
|
||||
|
||||
/** Main program entry point. This routine configures the hardware required by the application, then
|
||||
* starts the scheduler to run the application tasks.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
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);
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||
|
||||
Endpoint_ConfigureEndpoint(CDC_TX_EPNUM, EP_TYPE_BULK,
|
||||
ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE,
|
||||
ENDPOINT_BANK_SINGLE);
|
||||
|
||||
Endpoint_ConfigureEndpoint(CDC_RX_EPNUM, EP_TYPE_BULK,
|
||||
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();
|
||||
USB_CDC_ProcessControlPacket(&VirtualSerial_CDC_Interface);
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetLineEncoding:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
/* Acknowledge the SETUP packet, ready for data transfer */
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
/* Read the line coding data in from the host into the global struct */
|
||||
Endpoint_Read_Control_Stream_LE(LineCodingData, sizeof(LineCoding));
|
||||
|
||||
/* Finalize the stream transfer to clear the last packet from the host */
|
||||
Endpoint_ClearIN();
|
||||
|
||||
/* Reconfigure the USART with the new settings */
|
||||
ReconfigureUSART();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetControlLineState:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
/* Acknowledge the SETUP packet, ready for data transfer */
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
/* NOTE: Here you can read in the line state mask from the host, to get the current state of the output handshake
|
||||
lines. The mask is read in from the wValue parameter in USB_ControlRequest, and can be masked against the
|
||||
CONTROL_LINE_OUT_* masks to determine the RTS and DTR line states using the following code:
|
||||
*/
|
||||
|
||||
/* Acknowledge status stage */
|
||||
while (!(Endpoint_IsINReady()));
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Task to manage CDC data transmission and reception to and from the host, from and to the physical USART. */
|
||||
TASK(CDC_Task)
|
||||
{
|
||||
if (USB_IsConnected)
|
||||
{
|
||||
#if 0
|
||||
/* NOTE: Here you can use the notification endpoint to send back line state changes to the host, for the special RS-232
|
||||
handshake signal lines (and some error states), via the CONTROL_LINE_IN_* masks and the following code:
|
||||
*/
|
||||
|
||||
USB_Notification_Header_t Notification = (USB_Notification_Header_t)
|
||||
{
|
||||
.NotificationType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.Notification = NOTIF_SerialState,
|
||||
.wValue = 0,
|
||||
.wIndex = 0,
|
||||
.wLength = sizeof(uint16_t),
|
||||
};
|
||||
|
||||
uint16_t LineStateMask;
|
||||
|
||||
// Set LineStateMask here to a mask of CONTROL_LINE_IN_* masks to set the input handshake line states to send to the host
|
||||
|
||||
Endpoint_SelectEndpoint(CDC_NOTIFICATION_EPNUM);
|
||||
Endpoint_Write_Stream_LE(&Notification, sizeof(Notification));
|
||||
Endpoint_Write_Stream_LE(&LineStateMask, sizeof(LineStateMask));
|
||||
Endpoint_ClearIN();
|
||||
#endif
|
||||
|
||||
/* Select the Serial Rx Endpoint */
|
||||
Endpoint_SelectEndpoint(CDC_RX_EPNUM);
|
||||
|
||||
/* Check to see if a packet has been received from the host */
|
||||
if (Endpoint_IsOUTReceived())
|
||||
{
|
||||
/* Read the bytes in from the endpoint into the buffer while space is available */
|
||||
while (Endpoint_BytesInEndpoint() && (BUFF_STATICSIZE - Rx_Buffer.Elements))
|
||||
{
|
||||
/* Store each character from the endpoint */
|
||||
Buffer_StoreElement(&Rx_Buffer, Endpoint_Read_Byte());
|
||||
}
|
||||
|
||||
/* Check to see if all bytes in the current packet have been read */
|
||||
if (!(Endpoint_BytesInEndpoint()))
|
||||
{
|
||||
/* Clear the endpoint buffer */
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if Rx buffer contains data - if so, send it */
|
||||
if (Rx_Buffer.Elements)
|
||||
Serial_TxByte(Buffer_GetElement(&Rx_Buffer));
|
||||
|
||||
/* Select the Serial Tx Endpoint */
|
||||
Endpoint_SelectEndpoint(CDC_TX_EPNUM);
|
||||
|
||||
/* Check if the Tx buffer contains anything to be sent to the host */
|
||||
if (Tx_Buffer.Elements)
|
||||
{
|
||||
/* Wait until Serial Tx Endpoint Ready for Read/Write */
|
||||
while (!(Endpoint_IsReadWriteAllowed()));
|
||||
|
||||
/* Write the bytes from the buffer to the endpoint while space is available */
|
||||
while (Tx_Buffer.Elements && (Endpoint_BytesInEndpoint() < CDC_TXRX_EPSIZE))
|
||||
{
|
||||
/* Write each byte retreived from the buffer to the endpoint */
|
||||
Endpoint_Write_Byte(Buffer_GetElement(&Tx_Buffer));
|
||||
}
|
||||
|
||||
/* Remember if the packet to send completely fills the endpoint */
|
||||
bool IsFull = (Endpoint_BytesInEndpoint() == CDC_TXRX_EPSIZE);
|
||||
|
||||
/* Send the data */
|
||||
Endpoint_ClearIN();
|
||||
|
||||
/* If no more data to send and the last packet filled the endpoint, send an empty packet to release
|
||||
* the buffer on the receiver (otherwise all data will be cached until a non-full packet is received) */
|
||||
if (IsFull && !(Tx_Buffer.Elements))
|
||||
{
|
||||
/* Wait until Serial Tx Endpoint Ready for Read/Write */
|
||||
while (!(Endpoint_IsReadWriteAllowed()));
|
||||
|
||||
/* Send an empty packet to terminate the transfer */
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** ISR to handle the USART receive complete interrupt, fired each time the USART has received a character. This stores the received
|
||||
* character into the Tx_Buffer circular buffer for later transmission to the host.
|
||||
*/
|
||||
ISR(USART1_RX_vect, ISR_BLOCK)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 */
|
||||
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);
|
||||
UBRR1 = SERIAL_2X_UBBRVAL((uint16_t)CDCInterfaceInfo->LineEncoding.BaudRateBPS);
|
||||
}
|
||||
|
|
|
@ -46,140 +46,28 @@
|
|||
|
||||
#include "Lib/RingBuff.h"
|
||||
|
||||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Drivers/Peripheral/Serial.h> // USART driver
|
||||
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
|
||||
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Joystick.h>
|
||||
#include <LUFA/Drivers/Peripheral/Serial.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/Device/CDC.h>
|
||||
|
||||
/* Macros: */
|
||||
/** CDC Class specific request to get the current virtual serial port configuration settings. */
|
||||
#define REQ_GetLineEncoding 0x21
|
||||
|
||||
/** CDC Class specific request to set the current virtual serial port configuration settings. */
|
||||
#define REQ_SetLineEncoding 0x20
|
||||
|
||||
/** CDC Class specific request to set the current virtual serial port handshake line states. */
|
||||
#define REQ_SetControlLineState 0x22
|
||||
|
||||
/** Notification type constant for a change in the virtual serial port handshake line states, for
|
||||
* use with a USB_Notification_Header_t notification structure when sent to the host via the CDC
|
||||
* notification endpoint.
|
||||
*/
|
||||
#define NOTIF_SerialState 0x20
|
||||
|
||||
/** Mask for the DTR handshake line for use with the REQ_SetControlLineState class specific request
|
||||
* from the host, to indicate that the DTR line state should be high.
|
||||
*/
|
||||
#define CONTROL_LINE_OUT_DTR (1 << 0)
|
||||
|
||||
/** Mask for the RTS handshake line for use with the REQ_SetControlLineState class specific request
|
||||
* from the host, to indicate that theRTS line state should be high.
|
||||
*/
|
||||
#define CONTROL_LINE_OUT_RTS (1 << 1)
|
||||
|
||||
/** Mask for the DCD handshake line for use with the a NOTIF_SerialState class specific notification
|
||||
* from the device to the host, to indicate that the DCD line state is currently high.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_DCD (1 << 0)
|
||||
|
||||
/** Mask for the DSR handshake line for use with the a NOTIF_SerialState class specific notification
|
||||
* from the device to the host, to indicate that the DSR line state is currently high.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_DSR (1 << 1)
|
||||
|
||||
/** Mask for the BREAK handshake line for use with the a NOTIF_SerialState class specific notification
|
||||
* from the device to the host, to indicate that the BREAK line state is currently high.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_BREAK (1 << 2)
|
||||
|
||||
/** Mask for the RING handshake line for use with the a NOTIF_SerialState class specific notification
|
||||
* from the device to the host, to indicate that the RING line state is currently high.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_RING (1 << 3)
|
||||
|
||||
/** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host,
|
||||
* to indicate that a framing error has occurred on the virtual serial port.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_FRAMEERROR (1 << 4)
|
||||
|
||||
/** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host,
|
||||
* to indicate that a parity error has occurred on the virtual serial port.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_PARITYERROR (1 << 5)
|
||||
|
||||
/** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host,
|
||||
* to indicate that a data overrun error has occurred on the virtual serial port.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_OVERRUNERROR (1 << 6)
|
||||
|
||||
/* 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);
|
||||
#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 ReconfigureUSART(void);
|
||||
void UpdateStatus(uint8_t CurrentStatus);
|
||||
void EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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)"
|
||||
|
||||
|
|
|
@ -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.)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include <LUFA/Version.h> // Library Version Information
|
||||
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
|
||||
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
|
||||
#include <LUFA/MemoryAllocator/DynAlloc.h> // Auto-defragmenting Dynamic Memory allocation
|
||||
#include <LUFA/Drivers/Misc/TerminalCodes.h> // ANSI Terminal Escape Codes
|
||||
#include <LUFA/Drivers/Peripheral/ADC.h> // ADC driver
|
||||
#include <LUFA/Drivers/Peripheral/SerialStream.h> // USART Stream driver
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -4,6 +4,14 @@
|
|||
* documentation pages. It is not a project source file.
|
||||
*/
|
||||
|
||||
========== TODO: ===========
|
||||
- Document new class drivers
|
||||
- Re-document all demos now that they have changed
|
||||
- Add standardized descriptor names to class driver structures, controlled by USE_NONSTANDARD_DESCRIPTOR_NAMES
|
||||
- Add C++ compatibility to class drivers
|
||||
- Disable JTAG in demos
|
||||
============================
|
||||
|
||||
/** \page Page_ChangeLog Project Changelog
|
||||
*
|
||||
* \section Sec_ChangeLogXXXXXX Version XXXXXX
|
||||
|
@ -30,6 +38,8 @@
|
|||
* LUFA/Drivers/USB/Class/ directory to LUFA/Drivers/USB/HighLevel/ in preperation for the new USB class APIs
|
||||
* - Moved out each demos' functionality library files (e.g. Ring Buffer library) to /Lib directories for a better directory structure
|
||||
* - Removed Tx interrupt from the USBtoSerial demo; now sends characters via polling to ensure more time for the Rx interrupt
|
||||
* - Added new EVENT_USB_StartOfFrame event in the library to indicate the start of each USB frame (when generated)
|
||||
* - Removed psuedo-scheduler, dynamic memory block allocator from the library (no longer needed and not used respectively)
|
||||
*
|
||||
*
|
||||
* \section Sec_ChangeLog090510 Version 090510
|
||||
|
|
|
@ -10,19 +10,6 @@
|
|||
* This folder contains header files which are common to all parts of the LUFA library. They may be used freely in
|
||||
* user applications.
|
||||
*
|
||||
* \dir MemoryAllocator
|
||||
* \brief Auto-defragmenting dynamic memory allocation library.
|
||||
*
|
||||
* This folder contains a simple handle-based dynamic memory allocation library, capable of handing out memory in
|
||||
* block chunks. As new memory is allocated, the library will defragment the already allocated memory to ensure
|
||||
* optimal memory usage. It is not used within the LUFA library, and is provided as a convenience for user applications.
|
||||
*
|
||||
* \dir Scheduler
|
||||
* \brief Simple round-robbin scheduler.
|
||||
*
|
||||
* This folder contains the simple LUFA round-robbin scheduler, provided as a convenience for user applications. It
|
||||
* is very simple in design, and is intended to make code easier to read, rather than providing a complete RTOS kernel.
|
||||
*
|
||||
* \dir Drivers
|
||||
* \brief Library hardware and software drivers.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
#include "Audio.h"
|
||||
|
||||
void USB_Audio_ProcessControlPacket(USB_ClassInfo_Audio_t* AudioInterfaceInfo)
|
||||
{
|
||||
if (!(Endpoint_IsSETUPReceived()))
|
||||
return;
|
||||
|
||||
// if (USB_ControlRequest.wIndex != AudioInterfaceInfo->InterfaceNumber)
|
||||
// return;
|
||||
|
||||
switch (USB_ControlRequest.bRequest)
|
||||
{
|
||||
case REQ_SetInterface:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
AudioInterfaceInfo->InterfaceEnabled = (USB_ControlRequest.wValue != 0);
|
||||
|
||||
while (!(Endpoint_IsINReady()));
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool USB_Audio_ConfigureEndpoints(USB_ClassInfo_Audio_t* AudioInterfaceInfo)
|
||||
{
|
||||
if (AudioInterfaceInfo->DataINEndpointNumber)
|
||||
{
|
||||
if (!(Endpoint_ConfigureEndpoint(AudioInterfaceInfo->DataINEndpointNumber, EP_TYPE_ISOCHRONOUS,
|
||||
ENDPOINT_DIR_IN, AudioInterfaceInfo->DataINEndpointSize,
|
||||
ENDPOINT_BANK_DOUBLE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (AudioInterfaceInfo->DataOUTEndpointNumber)
|
||||
{
|
||||
if (!(Endpoint_ConfigureEndpoint(AudioInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_ISOCHRONOUS,
|
||||
ENDPOINT_DIR_OUT, AudioInterfaceInfo->DataOUTEndpointSize,
|
||||
ENDPOINT_BANK_DOUBLE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int8_t USB_Audio_ReadSample8(void)
|
||||
{
|
||||
int8_t Sample;
|
||||
|
||||
Sample = Endpoint_Read_Byte();
|
||||
|
||||
if (!(Endpoint_IsReadWriteAllowed()))
|
||||
Endpoint_ClearOUT();
|
||||
|
||||
return Sample;
|
||||
}
|
||||
|
||||
int16_t USB_Audio_ReadSample16(void)
|
||||
{
|
||||
int16_t Sample;
|
||||
|
||||
Sample = (int16_t)Endpoint_Read_Word_LE();
|
||||
|
||||
if (!(Endpoint_IsReadWriteAllowed()))
|
||||
Endpoint_ClearOUT();
|
||||
|
||||
return Sample;
|
||||
}
|
||||
|
||||
int32_t USB_Audio_ReadSample24(void)
|
||||
{
|
||||
int32_t Sample;
|
||||
|
||||
Sample = (((uint32_t)Endpoint_Read_Byte() << 16) | Endpoint_Read_Word_LE());
|
||||
|
||||
if (!(Endpoint_IsReadWriteAllowed()))
|
||||
Endpoint_ClearOUT();
|
||||
|
||||
return Sample;
|
||||
}
|
||||
|
||||
void USB_Audio_WriteSample8(int8_t Sample)
|
||||
{
|
||||
Endpoint_Write_Byte(Sample);
|
||||
|
||||
if (!(Endpoint_IsReadWriteAllowed()))
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
void USB_Audio_WriteSample16(int16_t Sample)
|
||||
{
|
||||
Endpoint_Write_Word_LE(Sample);
|
||||
|
||||
if (!(Endpoint_IsReadWriteAllowed()))
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
void USB_Audio_WriteSample24(int32_t Sample)
|
||||
{
|
||||
Endpoint_Write_Byte(Sample >> 16);
|
||||
Endpoint_Write_Word_LE(Sample);
|
||||
|
||||
if (!(Endpoint_IsReadWriteAllowed()))
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
bool USB_Audio_IsSampleReceived(USB_ClassInfo_Audio_t* AudioInterfaceInfo)
|
||||
{
|
||||
Endpoint_SelectEndpoint(AudioInterfaceInfo->DataOUTEndpointNumber);
|
||||
return Endpoint_IsOUTReceived();
|
||||
}
|
||||
|
||||
bool USB_Audio_IsReadyForNextSample(USB_ClassInfo_Audio_t* AudioInterfaceInfo)
|
||||
{
|
||||
Endpoint_SelectEndpoint(AudioInterfaceInfo->DataINEndpointNumber);
|
||||
return Endpoint_IsINReady();
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
#ifndef _AUDIO_CLASS_H_
|
||||
#define _AUDIO_CLASS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include "../../USB.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Macros: */
|
||||
|
||||
/* Enums: */
|
||||
|
||||
/* Type Defines: */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t InterfaceNumber;
|
||||
|
||||
uint8_t DataINEndpointNumber;
|
||||
uint16_t DataINEndpointSize;
|
||||
|
||||
uint8_t DataOUTEndpointNumber;
|
||||
uint16_t DataOUTEndpointSize;
|
||||
|
||||
bool InterfaceEnabled;
|
||||
} USB_ClassInfo_Audio_t;
|
||||
|
||||
/* Function Prototypes: */
|
||||
bool USB_Audio_ConfigureEndpoints(USB_ClassInfo_Audio_t* AudioInterfaceInfo);
|
||||
void USB_Audio_ProcessControlPacket(USB_ClassInfo_Audio_t* AudioInterfaceInfo);
|
||||
void USB_Audio_USBTask(USB_ClassInfo_Audio_t* AudioInterfaceInfo);
|
||||
|
||||
int8_t USB_Audio_ReadSample8(void);
|
||||
int16_t USB_Audio_ReadSample16(void);
|
||||
int32_t USB_Audio_ReadSample24(void);
|
||||
void USB_Audio_WriteSample8(int8_t Sample);
|
||||
void USB_Audio_WriteSample16(int16_t Sample);
|
||||
void USB_Audio_WriteSample24(int32_t Sample);
|
||||
bool USB_Audio_IsSampleReceived(USB_ClassInfo_Audio_t* AudioInterfaceInfo);
|
||||
bool USB_Audio_IsReadyForNextSample(USB_ClassInfo_Audio_t* AudioInterfaceInfo);
|
||||
#endif
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
#define INCLUDE_FROM_CDC_CLASS_C
|
||||
#include "CDC.h"
|
||||
|
||||
void USB_CDC_Event_Stub(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void USB_CDC_ProcessControlPacket(USB_ClassInfo_CDC_t* CDCInterfaceInfo)
|
||||
{
|
||||
if (!(Endpoint_IsSETUPReceived()))
|
||||
return;
|
||||
|
||||
if (USB_ControlRequest.wIndex != CDCInterfaceInfo->ControlInterfaceNumber)
|
||||
return;
|
||||
|
||||
switch (USB_ControlRequest.bRequest)
|
||||
{
|
||||
case REQ_GetLineEncoding:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
Endpoint_Write_Control_Stream_LE(&CDCInterfaceInfo->LineEncoding, sizeof(CDCInterfaceInfo->LineEncoding));
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetLineEncoding:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
Endpoint_Read_Control_Stream_LE(&CDCInterfaceInfo->LineEncoding, sizeof(CDCInterfaceInfo->LineEncoding));
|
||||
Endpoint_ClearIN();
|
||||
|
||||
EVENT_USB_CDC_LineEncodingChanged(CDCInterfaceInfo);
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetControlLineState:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
CDCInterfaceInfo->ControlLineState = USB_ControlRequest.wValue;
|
||||
|
||||
EVENT_USB_CDC_ControLineStateChanged();
|
||||
|
||||
while (!(Endpoint_IsINReady()));
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool USB_CDC_ConfigureEndpoints(USB_ClassInfo_CDC_t* CDCInterfaceInfo)
|
||||
{
|
||||
if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK,
|
||||
ENDPOINT_DIR_IN, CDCInterfaceInfo->DataINEndpointSize,
|
||||
ENDPOINT_BANK_SINGLE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK,
|
||||
ENDPOINT_DIR_OUT, CDCInterfaceInfo->DataOUTEndpointSize,
|
||||
ENDPOINT_BANK_SINGLE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->NotificationEndpointNumber, EP_TYPE_INTERRUPT,
|
||||
ENDPOINT_DIR_IN, CDCInterfaceInfo->NotificationEndpointSize,
|
||||
ENDPOINT_BANK_SINGLE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void USB_CDC_USBTask(USB_ClassInfo_CDC_t* CDCInterfaceInfo)
|
||||
{
|
||||
if (!(USB_IsConnected))
|
||||
return;
|
||||
|
||||
Endpoint_SelectEndpoint(CDCInterfaceInfo->DataINEndpointNumber);
|
||||
|
||||
if (!(Endpoint_BytesInEndpoint()))
|
||||
return;
|
||||
|
||||
if (!(Endpoint_IsReadWriteAllowed()))
|
||||
{
|
||||
Endpoint_ClearIN();
|
||||
while (!(Endpoint_IsReadWriteAllowed()));
|
||||
}
|
||||
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
void USB_CDC_SendString(USB_ClassInfo_CDC_t* CDCInterfaceInfo, char* Data, uint16_t Length)
|
||||
{
|
||||
Endpoint_SelectEndpoint(CDCInterfaceInfo->DataINEndpointNumber);
|
||||
Endpoint_Write_Stream_LE(Data, Length, NO_STREAM_CALLBACK);
|
||||
}
|
||||
|
||||
void USB_CDC_SendByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint8_t Data)
|
||||
{
|
||||
Endpoint_SelectEndpoint(CDCInterfaceInfo->DataINEndpointNumber);
|
||||
|
||||
if (!(Endpoint_IsReadWriteAllowed()))
|
||||
{
|
||||
Endpoint_ClearIN();
|
||||
while (!(Endpoint_IsReadWriteAllowed()));
|
||||
}
|
||||
|
||||
Endpoint_Write_Byte(Data);
|
||||
}
|
||||
|
||||
uint16_t USB_CDC_BytesReceived(USB_ClassInfo_CDC_t* CDCInterfaceInfo)
|
||||
{
|
||||
Endpoint_SelectEndpoint(CDCInterfaceInfo->DataOUTEndpointNumber);
|
||||
|
||||
return Endpoint_BytesInEndpoint();
|
||||
}
|
||||
|
||||
uint8_t USB_CDC_ReceiveByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo)
|
||||
{
|
||||
Endpoint_SelectEndpoint(CDCInterfaceInfo->DataOUTEndpointNumber);
|
||||
|
||||
uint8_t DataByte = Endpoint_Read_Byte();
|
||||
|
||||
if (!(Endpoint_BytesInEndpoint()))
|
||||
Endpoint_ClearOUT();
|
||||
|
||||
return DataByte;
|
||||
}
|
||||
|
||||
void USB_CDC_SendSerialLineStateChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint16_t LineStateMask)
|
||||
{
|
||||
Endpoint_SelectEndpoint(CDCInterfaceInfo->NotificationEndpointNumber);
|
||||
|
||||
USB_Request_Header_t Notification = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = NOTIF_SerialState,
|
||||
.wValue = 0,
|
||||
.wIndex = 0,
|
||||
.wLength = sizeof(uint16_t),
|
||||
};
|
||||
|
||||
Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK);
|
||||
Endpoint_Write_Stream_LE(&LineStateMask, sizeof(LineStateMask), NO_STREAM_CALLBACK);
|
||||
Endpoint_ClearIN();
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
#ifndef _CDC_CLASS_H_
|
||||
#define _CDC_CLASS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include "../../USB.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Macros: */
|
||||
/** CDC Class specific request to get the current virtual serial port configuration settings. */
|
||||
#define REQ_GetLineEncoding 0x21
|
||||
|
||||
/** CDC Class specific request to set the current virtual serial port configuration settings. */
|
||||
#define REQ_SetLineEncoding 0x20
|
||||
|
||||
/** CDC Class specific request to set the current virtual serial port handshake line states. */
|
||||
#define REQ_SetControlLineState 0x22
|
||||
|
||||
/** Notification type constant for a change in the virtual serial port handshake line states, for
|
||||
* use with a USB_Notification_Header_t notification structure when sent to the host via the CDC
|
||||
* notification endpoint.
|
||||
*/
|
||||
#define NOTIF_SerialState 0x20
|
||||
|
||||
/** Mask for the DTR handshake line for use with the REQ_SetControlLineState class specific request
|
||||
* from the host, to indicate that the DTR line state should be high.
|
||||
*/
|
||||
#define CONTROL_LINE_OUT_DTR (1 << 0)
|
||||
|
||||
/** Mask for the RTS handshake line for use with the REQ_SetControlLineState class specific request
|
||||
* from the host, to indicate that theRTS line state should be high.
|
||||
*/
|
||||
#define CONTROL_LINE_OUT_RTS (1 << 1)
|
||||
|
||||
/** Mask for the DCD handshake line for use with the a NOTIF_SerialState class specific notification
|
||||
* from the device to the host, to indicate that the DCD line state is currently high.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_DCD (1 << 0)
|
||||
|
||||
/** Mask for the DSR handshake line for use with the a NOTIF_SerialState class specific notification
|
||||
* from the device to the host, to indicate that the DSR line state is currently high.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_DSR (1 << 1)
|
||||
|
||||
/** Mask for the BREAK handshake line for use with the a NOTIF_SerialState class specific notification
|
||||
* from the device to the host, to indicate that the BREAK line state is currently high.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_BREAK (1 << 2)
|
||||
|
||||
/** Mask for the RING handshake line for use with the a NOTIF_SerialState class specific notification
|
||||
* from the device to the host, to indicate that the RING line state is currently high.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_RING (1 << 3)
|
||||
|
||||
/** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host,
|
||||
* to indicate that a framing error has occurred on the virtual serial port.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_FRAMEERROR (1 << 4)
|
||||
|
||||
/** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host,
|
||||
* to indicate that a parity error has occurred on the virtual serial port.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_PARITYERROR (1 << 5)
|
||||
|
||||
/** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host,
|
||||
* to indicate that a data overrun error has occurred on the virtual serial port.
|
||||
*/
|
||||
#define CONTROL_LINE_IN_OVERRUNERROR (1 << 6)
|
||||
|
||||
/** Macro to define a CDC class-specific functional descriptor. CDC functional descriptors have a
|
||||
* uniform structure but variable sized data payloads, thus cannot be represented accurately by
|
||||
* a single typedef struct. A macro is used instead so that functional descriptors can be created
|
||||
* easily by specifying the size of the payload. This allows sizeof() to work correctly.
|
||||
*
|
||||
* \param DataSize Size in bytes of the CDC functional descriptor's data payload
|
||||
*/
|
||||
#define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \
|
||||
struct \
|
||||
{ \
|
||||
USB_Descriptor_Header_t Header; \
|
||||
uint8_t SubType; \
|
||||
uint8_t Data[DataSize]; \
|
||||
}
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible line encoding formats of a virtual serial port. */
|
||||
enum CDCDevice_CDC_LineCodingFormats_t
|
||||
{
|
||||
OneStopBit = 0, /**< Each frame contains one stop bit */
|
||||
OneAndAHalfStopBits = 1, /**< Each frame contains one and a half stop bits */
|
||||
TwoStopBits = 2, /**< Each frame contains two stop bits */
|
||||
};
|
||||
|
||||
/** Enum for the possible line encoding parity settings of a virtual serial port. */
|
||||
enum CDCDevice_LineCodingParity_t
|
||||
{
|
||||
Parity_None = 0, /**< No parity bit mode on each frame */
|
||||
Parity_Odd = 1, /**< Odd parity bit mode on each frame */
|
||||
Parity_Even = 2, /**< Even parity bit mode on each frame */
|
||||
Parity_Mark = 3, /**< Mark parity bit mode on each frame */
|
||||
Parity_Space = 4, /**< Space parity bit mode on each frame */
|
||||
};
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the virtual serial port line encoding settings, for storing the current USART configuration
|
||||
* as set by the host via a class specific request.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t ControlInterfaceNumber; /**< Interface number of the CDC control interface within the device */
|
||||
|
||||
uint8_t DataINEndpointNumber; /**< Endpoint number of the CDC interface's IN data endpoint */
|
||||
uint16_t DataINEndpointSize; /**< Size in bytes of the CDC interface's IN data endpoint */
|
||||
|
||||
uint8_t DataOUTEndpointNumber; /**< Endpoint number of the CDC interface's OUT data endpoint */
|
||||
uint16_t DataOUTEndpointSize; /**< Size in bytes of the CDC interface's OUT data endpoint */
|
||||
|
||||
uint8_t NotificationEndpointNumber; /**< Endpoint number of the CDC interface's IN notification endpoint, if used */
|
||||
uint16_t NotificationEndpointSize; /**< Size in bytes of the CDC interface's IN notification endpoint, if used */
|
||||
|
||||
uint8_t ControlLineState;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t BaudRateBPS; /**< Baud rate of the virtual serial port, in bits per second */
|
||||
uint8_t CharFormat; /**< Character format of the virtual serial port, a value from the
|
||||
* CDCDevice_CDC_LineCodingFormats_t enum
|
||||
*/
|
||||
uint8_t ParityType; /**< Parity setting of the virtual serial port, a value from the
|
||||
* CDCDevice_LineCodingParity_t enum
|
||||
*/
|
||||
uint8_t DataBits; /**< Bits of data per character of the virtual serial port */
|
||||
} LineEncoding;
|
||||
} USB_ClassInfo_CDC_t;
|
||||
|
||||
/* Function Prototypes: */
|
||||
#if defined(INCLUDE_FROM_CDC_CLASS_C)
|
||||
void USB_CDC_Event_Stub(void);
|
||||
void EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo)
|
||||
ATTR_WEAK ATTR_ALIAS(USB_CDC_Event_Stub);
|
||||
void EVENT_USB_CDC_ControLineStateChanged(void) ATTR_WEAK ATTR_ALIAS(USB_CDC_Event_Stub);;
|
||||
#endif
|
||||
|
||||
void USB_CDC_USBTask(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||
bool USB_CDC_ConfigureEndpoints(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||
void USB_CDC_ProcessControlPacket(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||
void USB_CDC_USBTask(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||
|
||||
void EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||
void EVENT_USB_CDC_ControLineStateChanged(void);
|
||||
|
||||
void USB_CDC_SendString(USB_ClassInfo_CDC_t* CDCInterfaceInfo, char* Data, uint16_t Length);
|
||||
void USB_CDC_SendByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint8_t Data);
|
||||
uint16_t USB_CDC_BytesReceived(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||
uint8_t USB_CDC_ReceiveByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||
void USB_CDC_SendSerialLineStateChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint16_t LineStateMask);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
#include "HID.h"
|
||||
|
||||
void USB_HID_ProcessControlPacket(USB_ClassInfo_HID_t* HIDInterfaceInfo)
|
||||
{
|
||||
if (!(Endpoint_IsSETUPReceived()))
|
||||
return;
|
||||
|
||||
if (USB_ControlRequest.wIndex != HIDInterfaceInfo->InterfaceNumber)
|
||||
return;
|
||||
|
||||
switch (USB_ControlRequest.bRequest)
|
||||
{
|
||||
case REQ_GetReport:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
uint8_t ReportINData[HIDInterfaceInfo->ReportBufferSize];
|
||||
uint16_t ReportINSize;
|
||||
|
||||
memset(ReportINData, 0, sizeof(ReportINData));
|
||||
|
||||
ReportINSize = CALLBACK_USB_HID_CreateNextHIDReport(HIDInterfaceInfo, ReportINData);
|
||||
|
||||
Endpoint_Write_Control_Stream_LE(ReportINData, ReportINSize);
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetReport:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
uint16_t ReportOUTSize = USB_ControlRequest.wLength;
|
||||
uint8_t ReportOUTData[ReportOUTSize];
|
||||
|
||||
Endpoint_Read_Control_Stream_LE(ReportOUTData, ReportOUTSize);
|
||||
Endpoint_ClearIN();
|
||||
|
||||
CALLBACK_USB_HID_ProcessReceivedHIDReport(HIDInterfaceInfo, ReportOUTData, ReportOUTSize);
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_GetProtocol:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
Endpoint_Write_Byte(HIDInterfaceInfo->UsingReportProtocol);
|
||||
Endpoint_ClearIN();
|
||||
|
||||
while (!(Endpoint_IsOUTReceived()));
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetProtocol:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
HIDInterfaceInfo->UsingReportProtocol = (USB_ControlRequest.wValue != 0x0000);
|
||||
|
||||
while (!(Endpoint_IsINReady()));
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_SetIdle:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
HIDInterfaceInfo->IdleCount = ((USB_ControlRequest.wValue >> 8) << 2);
|
||||
|
||||
while (!(Endpoint_IsINReady()));
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_GetIdle:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
Endpoint_Write_Byte(HIDInterfaceInfo->IdleCount >> 2);
|
||||
Endpoint_ClearIN();
|
||||
|
||||
while (!(Endpoint_IsOUTReceived()));
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool USB_HID_ConfigureEndpoints(USB_ClassInfo_HID_t* HIDInterfaceInfo)
|
||||
{
|
||||
HIDInterfaceInfo->UsingReportProtocol = true;
|
||||
|
||||
if (!(Endpoint_ConfigureEndpoint(HIDInterfaceInfo->ReportINEndpointNumber, EP_TYPE_INTERRUPT,
|
||||
ENDPOINT_DIR_IN, HIDInterfaceInfo->ReportINEndpointSize, ENDPOINT_BANK_SINGLE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HIDInterfaceInfo->ReportOUTEndpointNumber)
|
||||
{
|
||||
if (!(Endpoint_ConfigureEndpoint(HIDInterfaceInfo->ReportOUTEndpointNumber, EP_TYPE_INTERRUPT,
|
||||
ENDPOINT_DIR_OUT, HIDInterfaceInfo->ReportOUTEndpointSize, ENDPOINT_BANK_SINGLE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void USB_HID_RegisterStartOfFrame(USB_ClassInfo_HID_t* HIDInterfaceInfo)
|
||||
{
|
||||
if (HIDInterfaceInfo->IdleMSRemaining)
|
||||
HIDInterfaceInfo->IdleMSRemaining--;
|
||||
}
|
||||
|
||||
void USB_HID_USBTask(USB_ClassInfo_HID_t* HIDInterfaceInfo)
|
||||
{
|
||||
if (!(USB_IsConnected))
|
||||
return;
|
||||
|
||||
Endpoint_SelectEndpoint(HIDInterfaceInfo->ReportINEndpointNumber);
|
||||
|
||||
if (Endpoint_IsReadWriteAllowed() &&
|
||||
!(HIDInterfaceInfo->IdleCount && HIDInterfaceInfo->IdleMSRemaining))
|
||||
{
|
||||
if (HIDInterfaceInfo->IdleCount && !(HIDInterfaceInfo->IdleMSRemaining))
|
||||
HIDInterfaceInfo->IdleMSRemaining = HIDInterfaceInfo->IdleCount;
|
||||
|
||||
uint8_t ReportINData[HIDInterfaceInfo->ReportBufferSize];
|
||||
uint16_t ReportINSize;
|
||||
|
||||
memset(ReportINData, 0, sizeof(ReportINData));
|
||||
|
||||
ReportINSize = CALLBACK_USB_HID_CreateNextHIDReport(HIDInterfaceInfo, ReportINData);
|
||||
|
||||
if (ReportINSize)
|
||||
{
|
||||
Endpoint_Write_Stream_LE(ReportINData, ReportINSize
|
||||
#if !defined(NO_STREAM_CALLBACKS)
|
||||
, NO_STREAM_CALLBACK
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
if (HIDInterfaceInfo->ReportOUTEndpointNumber)
|
||||
{
|
||||
Endpoint_SelectEndpoint(HIDInterfaceInfo->ReportOUTEndpointNumber);
|
||||
|
||||
if (Endpoint_IsOUTReceived())
|
||||
{
|
||||
uint16_t ReportOUTSize = Endpoint_BytesInEndpoint();
|
||||
uint8_t ReportOUTData[ReportOUTSize];
|
||||
|
||||
if (ReportOUTSize)
|
||||
{
|
||||
Endpoint_Read_Stream_LE(ReportOUTData, ReportOUTSize
|
||||
#if !defined(NO_STREAM_CALLBACKS)
|
||||
, NO_STREAM_CALLBACK
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
CALLBACK_USB_HID_ProcessReceivedHIDReport(HIDInterfaceInfo, ReportOUTData, ReportOUTSize);
|
||||
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
#ifndef _HID_CLASS_H_
|
||||
#define _HID_CLASS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include "../../USB.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Macros: */
|
||||
/** HID Class Specific Request to get the current HID report from the device. */
|
||||
#define REQ_GetReport 0x01
|
||||
|
||||
/** HID Class Specific Request to get the current device idle count. */
|
||||
#define REQ_GetIdle 0x02
|
||||
|
||||
/** HID Class Specific Request to set the current HID report to the device. */
|
||||
#define REQ_SetReport 0x09
|
||||
|
||||
/** HID Class Specific Request to set the device's idle count. */
|
||||
#define REQ_SetIdle 0x0A
|
||||
|
||||
/** HID Class Specific Request to get the current HID report protocol mode. */
|
||||
#define REQ_GetProtocol 0x03
|
||||
|
||||
/** HID Class Specific Request to set the current HID report protocol mode. */
|
||||
#define REQ_SetProtocol 0x0B
|
||||
|
||||
/** Descriptor header type value, to indicate a HID class HID descriptor. */
|
||||
#define DTYPE_HID 0x21
|
||||
|
||||
/** Descriptor header type value, to indicate a HID class HID report descriptor. */
|
||||
#define DTYPE_Report 0x22
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
|
||||
* specification for details on the structure elements.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
USB_Descriptor_Header_t Header;
|
||||
|
||||
uint16_t HIDSpec;
|
||||
uint8_t CountryCode;
|
||||
|
||||
uint8_t TotalReportDescriptors;
|
||||
|
||||
uint8_t HIDReportType;
|
||||
uint16_t HIDReportLength;
|
||||
} USB_Descriptor_HID_t;
|
||||
|
||||
/** Type define for the data type used to store HID report descriptor elements. */
|
||||
typedef uint8_t USB_Descriptor_HIDReport_Datatype_t;
|
||||
|
||||
/** Class state structure. An instance of this structure should be made for each HID interface
|
||||
* within the user application, and passed to each of the HID class driver functions as the
|
||||
* HIDInterfaceInfo parameter. The contents of this structure should be set to their correct
|
||||
* values when used, or ommitted to force the library to use default values.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t InterfaceNumber; /**< Interface number of the HID interface within the device */
|
||||
|
||||
uint8_t ReportINEndpointNumber; /**< Endpoint number of the HID interface's IN report endpoint */
|
||||
uint16_t ReportINEndpointSize; /**< Size in bytes of the HID interface's IN report endpoint */
|
||||
|
||||
uint8_t ReportOUTEndpointNumber; /**< Endpoint number of the HID interface's OUT report endpoint, if used */
|
||||
uint16_t ReportOUTEndpointSize; /**< Size in bytes of the HID interface's OUT report endpoint, if used */
|
||||
|
||||
uint8_t ReportBufferSize;
|
||||
|
||||
bool UsingReportProtocol; /**< Indicates if the HID interface is set to Boot or Report protocol mode */
|
||||
uint16_t IdleCount; /**< Report idle period, in ms, set by the host */
|
||||
uint16_t IdleMSRemaining; /**< Total number of ms remaining before the idle period elapses */
|
||||
} USB_ClassInfo_HID_t;
|
||||
|
||||
/* Function Prototypes: */
|
||||
bool USB_HID_ConfigureEndpoints(USB_ClassInfo_HID_t* HIDInterfaceInfo);
|
||||
void USB_HID_ProcessControlPacket(USB_ClassInfo_HID_t* HIDInterfaceInfo);
|
||||
void USB_HID_RegisterStartOfFrame(USB_ClassInfo_HID_t* HIDInterfaceInfo);
|
||||
void USB_HID_USBTask(USB_ClassInfo_HID_t* HIDInterfaceInfo);
|
||||
|
||||
uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData);
|
||||
void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
#define INCLUDE_FROM_MS_CLASS_C
|
||||
#include "MassStorage.h"
|
||||
|
||||
static USB_ClassInfo_MS_t* CallbackMSInterfaceInfo;
|
||||
|
||||
void USB_MS_ProcessControlPacket(USB_ClassInfo_MS_t* MSInterfaceInfo)
|
||||
{
|
||||
if (!(Endpoint_IsSETUPReceived()))
|
||||
return;
|
||||
|
||||
if (USB_ControlRequest.wIndex != MSInterfaceInfo->InterfaceNumber)
|
||||
return;
|
||||
|
||||
switch (USB_ControlRequest.bRequest)
|
||||
{
|
||||
case REQ_MassStorageReset:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
MSInterfaceInfo->IsMassStoreReset = true;
|
||||
|
||||
while (!(Endpoint_IsINReady()));
|
||||
Endpoint_ClearIN();
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_GetMaxLUN:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
Endpoint_Write_Byte(MSInterfaceInfo->TotalLUNs - 1);
|
||||
|
||||
Endpoint_ClearIN();
|
||||
|
||||
while (!(Endpoint_IsOUTReceived()));
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool USB_MS_ConfigureEndpoints(USB_ClassInfo_MS_t* MSInterfaceInfo)
|
||||
{
|
||||
if (!(Endpoint_ConfigureEndpoint(MSInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK,
|
||||
ENDPOINT_DIR_IN, MSInterfaceInfo->DataINEndpointSize,
|
||||
ENDPOINT_BANK_SINGLE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(Endpoint_ConfigureEndpoint(MSInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK,
|
||||
ENDPOINT_DIR_OUT, MSInterfaceInfo->DataOUTEndpointSize,
|
||||
ENDPOINT_BANK_SINGLE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void USB_MS_USBTask(USB_ClassInfo_MS_t* MSInterfaceInfo)
|
||||
{
|
||||
if (!(USB_IsConnected))
|
||||
return;
|
||||
|
||||
Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber);
|
||||
|
||||
if (Endpoint_IsReadWriteAllowed())
|
||||
{
|
||||
if (USB_MS_ReadInCommandBlock(MSInterfaceInfo))
|
||||
{
|
||||
if (MSInterfaceInfo->CommandBlock.Flags & COMMAND_DIRECTION_DATA_IN)
|
||||
Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber);
|
||||
|
||||
MSInterfaceInfo->CommandStatus.Status = CALLBACK_USB_MS_SCSICommandReceived(MSInterfaceInfo) ?
|
||||
Command_Pass : Command_Fail;
|
||||
MSInterfaceInfo->CommandStatus.Signature = CSW_SIGNATURE;
|
||||
MSInterfaceInfo->CommandStatus.Tag = MSInterfaceInfo->CommandBlock.Tag;
|
||||
MSInterfaceInfo->CommandStatus.DataTransferResidue = MSInterfaceInfo->CommandBlock.DataTransferLength;
|
||||
|
||||
if ((MSInterfaceInfo->CommandStatus.Status == Command_Fail) && (MSInterfaceInfo->CommandStatus.DataTransferResidue))
|
||||
Endpoint_StallTransaction();
|
||||
|
||||
USB_MS_ReturnCommandStatus(MSInterfaceInfo);
|
||||
|
||||
if (MSInterfaceInfo->IsMassStoreReset)
|
||||
{
|
||||
Endpoint_ResetFIFO(MSInterfaceInfo->DataOUTEndpointNumber);
|
||||
Endpoint_ResetFIFO(MSInterfaceInfo->DataINEndpointNumber);
|
||||
|
||||
Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber);
|
||||
Endpoint_ClearStall();
|
||||
Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber);
|
||||
Endpoint_ClearStall();
|
||||
|
||||
MSInterfaceInfo->IsMassStoreReset = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool USB_MS_ReadInCommandBlock(USB_ClassInfo_MS_t* MSInterfaceInfo)
|
||||
{
|
||||
Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber);
|
||||
|
||||
CallbackMSInterfaceInfo = MSInterfaceInfo;
|
||||
Endpoint_Read_Stream_LE(&MSInterfaceInfo->CommandBlock,
|
||||
(sizeof(CommandBlockWrapper_t) - MAX_SCSI_COMMAND_LENGTH),
|
||||
StreamCallback_AbortOnMassStoreReset);
|
||||
|
||||
if ((MSInterfaceInfo->CommandBlock.Signature != CBW_SIGNATURE) ||
|
||||
(MSInterfaceInfo->CommandBlock.LUN >= MSInterfaceInfo->TotalLUNs) ||
|
||||
(MSInterfaceInfo->CommandBlock.SCSICommandLength > MAX_SCSI_COMMAND_LENGTH))
|
||||
{
|
||||
Endpoint_StallTransaction();
|
||||
Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber);
|
||||
Endpoint_StallTransaction();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CallbackMSInterfaceInfo = MSInterfaceInfo;
|
||||
Endpoint_Read_Stream_LE(&MSInterfaceInfo->CommandBlock.SCSICommandData,
|
||||
MSInterfaceInfo->CommandBlock.SCSICommandLength,
|
||||
StreamCallback_AbortOnMassStoreReset);
|
||||
|
||||
Endpoint_ClearOUT();
|
||||
|
||||
if (MSInterfaceInfo->IsMassStoreReset)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void USB_MS_ReturnCommandStatus(USB_ClassInfo_MS_t* MSInterfaceInfo)
|
||||
{
|
||||
Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber);
|
||||
|
||||
while (Endpoint_IsStalled())
|
||||
{
|
||||
USB_USBTask();
|
||||
|
||||
if (MSInterfaceInfo->IsMassStoreReset)
|
||||
return;
|
||||
}
|
||||
|
||||
Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber);
|
||||
|
||||
while (Endpoint_IsStalled())
|
||||
{
|
||||
USB_USBTask();
|
||||
|
||||
if (MSInterfaceInfo->IsMassStoreReset)
|
||||
return;
|
||||
}
|
||||
|
||||
CallbackMSInterfaceInfo = MSInterfaceInfo;
|
||||
Endpoint_Write_Stream_LE(&MSInterfaceInfo->CommandStatus, sizeof(CommandStatusWrapper_t),
|
||||
StreamCallback_AbortOnMassStoreReset);
|
||||
|
||||
Endpoint_ClearIN();
|
||||
|
||||
if (MSInterfaceInfo->IsMassStoreReset)
|
||||
return;
|
||||
}
|
||||
|
||||
static uint8_t StreamCallback_AbortOnMassStoreReset(void)
|
||||
{
|
||||
USB_MS_USBTask(CallbackMSInterfaceInfo);
|
||||
|
||||
if (CallbackMSInterfaceInfo->IsMassStoreReset)
|
||||
return STREAMCALLBACK_Abort;
|
||||
else
|
||||
return STREAMCALLBACK_Continue;
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
#ifndef _MS_CLASS_H_
|
||||
#define _MS_CLASS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include "../../USB.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Macros: */
|
||||
/** Mass Storage Class specific request to reset the Mass Storage interface, ready for the next command. */
|
||||
#define REQ_MassStorageReset 0xFF
|
||||
|
||||
/** Mass Storage Class specific request to retrieve the total number of Logical Units (drives) in the SCSI device. */
|
||||
#define REQ_GetMaxLUN 0xFE
|
||||
|
||||
/** Maximum length of a SCSI command which can be issued by the device or host in a Mass Storage bulk wrapper. */
|
||||
#define MAX_SCSI_COMMAND_LENGTH 16
|
||||
|
||||
/** Magic signature for a Command Block Wrapper used in the Mass Storage Bulk-Only transport protocol. */
|
||||
#define CBW_SIGNATURE 0x43425355UL
|
||||
|
||||
/** Magic signature for a Command Status Wrapper used in the Mass Storage Bulk-Only transport protocol. */
|
||||
#define CSW_SIGNATURE 0x53425355UL
|
||||
|
||||
/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from host-to-device. */
|
||||
#define COMMAND_DIRECTION_DATA_OUT (0 << 7)
|
||||
|
||||
/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from device-to-host. */
|
||||
#define COMMAND_DIRECTION_DATA_IN (1 << 7)
|
||||
|
||||
/* Type defines: */
|
||||
/** Type define for a Command Block Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t Signature; /**< Command block signature, must be CBW_SIGNATURE to indicate a valid Command Block */
|
||||
uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */
|
||||
uint32_t DataTransferLength; /** Length of the optional data portion of the issued command, in bytes */
|
||||
uint8_t Flags; /**< Command block flags, indicating command data direction */
|
||||
uint8_t LUN; /**< Logical Unit number this command is issued to */
|
||||
uint8_t SCSICommandLength; /**< Length of the issued SCSI command within the SCSI command data array */
|
||||
uint8_t SCSICommandData[MAX_SCSI_COMMAND_LENGTH]; /**< Issued SCSI command in the Command Block */
|
||||
} CommandBlockWrapper_t;
|
||||
|
||||
/** Type define for a Command Status Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t Signature; /**< Status block signature, must be CSW_SIGNATURE to indicate a valid Command Status */
|
||||
uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */
|
||||
uint32_t DataTransferResidue; /**< Number of bytes of data not processed in the SCSI command */
|
||||
uint8_t Status; /**< Status code of the issued command - a value from the MassStorage_CommandStatusCodes_t enum */
|
||||
} CommandStatusWrapper_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible command status wrapper return status codes. */
|
||||
enum MassStorage_CommandStatusCodes_t
|
||||
{
|
||||
Command_Pass = 0, /**< Command completed with no error */
|
||||
Command_Fail = 1, /**< Command failed to complete - host may check the exact error via a SCSI REQUEST SENSE command */
|
||||
Phase_Error = 2 /**< Command failed due to being invalid in the current phase */
|
||||
};
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the virtual serial port line encoding settings, for storing the current USART configuration
|
||||
* as set by the host via a class specific request.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t InterfaceNumber; /**< Interface number of the Mass Storage interface within the device */
|
||||
|
||||
uint8_t DataINEndpointNumber; /**< Endpoint number of the Mass Storage interface's IN data endpoint */
|
||||
uint16_t DataINEndpointSize; /**< Size in bytes of the Mass Storage interface's IN data endpoint */
|
||||
|
||||
uint8_t DataOUTEndpointNumber; /**< Endpoint number of the Mass Storage interface's OUT data endpoint */
|
||||
uint16_t DataOUTEndpointSize; /**< Size in bytes of the Mass Storage interface's OUT data endpoint */
|
||||
|
||||
uint8_t TotalLUNs;
|
||||
|
||||
CommandBlockWrapper_t CommandBlock;
|
||||
CommandStatusWrapper_t CommandStatus;
|
||||
|
||||
bool IsMassStoreReset;
|
||||
} USB_ClassInfo_MS_t;
|
||||
|
||||
/* Function Prototypes: */
|
||||
#if defined(INCLUDE_FROM_MS_CLASS_C)
|
||||
static void USB_MS_ReturnCommandStatus(USB_ClassInfo_MS_t* MSInterfaceInfo);
|
||||
static bool USB_MS_ReadInCommandBlock(USB_ClassInfo_MS_t* MSInterfaceInfo);
|
||||
static uint8_t StreamCallback_AbortOnMassStoreReset(void);
|
||||
#endif
|
||||
|
||||
void USB_MS_USBTask(USB_ClassInfo_MS_t* MSInterfaceInfo);
|
||||
bool USB_MS_ConfigureEndpoints(USB_ClassInfo_MS_t* MSInterfaceInfo);
|
||||
void USB_MS_ProcessControlPacket(USB_ClassInfo_MS_t* MSInterfaceInfo);
|
||||
|
||||
bool CALLBACK_USB_MS_SCSICommandReceived(USB_ClassInfo_MS_t* MSInterfaceInfo);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,456 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
#define INCLUDE_FROM_RNDIS_CLASS_C
|
||||
#include "RNDIS.h"
|
||||
|
||||
static const uint32_t PROGMEM AdapterSupportedOIDList[] =
|
||||
{
|
||||
OID_GEN_SUPPORTED_LIST,
|
||||
OID_GEN_PHYSICAL_MEDIUM,
|
||||
OID_GEN_HARDWARE_STATUS,
|
||||
OID_GEN_MEDIA_SUPPORTED,
|
||||
OID_GEN_MEDIA_IN_USE,
|
||||
OID_GEN_MAXIMUM_FRAME_SIZE,
|
||||
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
||||
OID_GEN_LINK_SPEED,
|
||||
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
||||
OID_GEN_RECEIVE_BLOCK_SIZE,
|
||||
OID_GEN_VENDOR_ID,
|
||||
OID_GEN_VENDOR_DESCRIPTION,
|
||||
OID_GEN_CURRENT_PACKET_FILTER,
|
||||
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
||||
OID_GEN_MEDIA_CONNECT_STATUS,
|
||||
OID_GEN_XMIT_OK,
|
||||
OID_GEN_RCV_OK,
|
||||
OID_GEN_XMIT_ERROR,
|
||||
OID_GEN_RCV_ERROR,
|
||||
OID_GEN_RCV_NO_BUFFER,
|
||||
OID_802_3_PERMANENT_ADDRESS,
|
||||
OID_802_3_CURRENT_ADDRESS,
|
||||
OID_802_3_MULTICAST_LIST,
|
||||
OID_802_3_MAXIMUM_LIST_SIZE,
|
||||
OID_802_3_RCV_ERROR_ALIGNMENT,
|
||||
OID_802_3_XMIT_ONE_COLLISION,
|
||||
OID_802_3_XMIT_MORE_COLLISIONS,
|
||||
};
|
||||
|
||||
void USB_RNDIS_ProcessControlPacket(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo)
|
||||
{
|
||||
if (!(Endpoint_IsSETUPReceived()))
|
||||
return;
|
||||
|
||||
if (USB_ControlRequest.wIndex != RNDISInterfaceInfo->ControlInterfaceNumber)
|
||||
return;
|
||||
|
||||
switch (USB_ControlRequest.bRequest)
|
||||
{
|
||||
case REQ_SendEncapsulatedCommand:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
Endpoint_Read_Control_Stream_LE(RNDISInterfaceInfo->RNDISMessageBuffer, USB_ControlRequest.wLength);
|
||||
Endpoint_ClearIN();
|
||||
|
||||
USB_RNDIS_ProcessRNDISControlMessage(RNDISInterfaceInfo);
|
||||
}
|
||||
|
||||
break;
|
||||
case REQ_GetEncapsulatedResponse:
|
||||
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||
{
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||
|
||||
if (!(MessageHeader->MessageLength))
|
||||
{
|
||||
RNDISInterfaceInfo->RNDISMessageBuffer[0] = 0;
|
||||
MessageHeader->MessageLength = 1;
|
||||
}
|
||||
|
||||
Endpoint_Write_Control_Stream_LE(RNDISInterfaceInfo->RNDISMessageBuffer, MessageHeader->MessageLength);
|
||||
Endpoint_ClearOUT();
|
||||
|
||||
MessageHeader->MessageLength = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool USB_RNDIS_ConfigureEndpoints(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo)
|
||||
{
|
||||
if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK,
|
||||
ENDPOINT_DIR_IN, RNDISInterfaceInfo->DataINEndpointSize,
|
||||
ENDPOINT_BANK_SINGLE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK,
|
||||
ENDPOINT_DIR_OUT, RNDISInterfaceInfo->DataOUTEndpointSize,
|
||||
ENDPOINT_BANK_SINGLE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->NotificationEndpointNumber, EP_TYPE_INTERRUPT,
|
||||
ENDPOINT_DIR_IN, RNDISInterfaceInfo->NotificationEndpointSize,
|
||||
ENDPOINT_BANK_SINGLE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void USB_RNDIS_USBTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo)
|
||||
{
|
||||
if (!(USB_IsConnected))
|
||||
return;
|
||||
|
||||
RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||
|
||||
Endpoint_SelectEndpoint(RNDISInterfaceInfo->NotificationEndpointNumber);
|
||||
|
||||
if (Endpoint_IsINReady() && RNDISInterfaceInfo->ResponseReady)
|
||||
{
|
||||
USB_Request_Header_t Notification = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = NOTIF_ResponseAvailable,
|
||||
.wValue = 0,
|
||||
.wIndex = 0,
|
||||
.wLength = 0,
|
||||
};
|
||||
|
||||
Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK);
|
||||
|
||||
Endpoint_ClearIN();
|
||||
|
||||
RNDISInterfaceInfo->ResponseReady = false;
|
||||
}
|
||||
|
||||
if ((RNDISInterfaceInfo->CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength))
|
||||
{
|
||||
RNDIS_PACKET_MSG_t RNDISPacketHeader;
|
||||
|
||||
Endpoint_SelectEndpoint(RNDISInterfaceInfo->DataOUTEndpointNumber);
|
||||
|
||||
if (Endpoint_IsOUTReceived() && !(RNDISInterfaceInfo->FrameIN.FrameInBuffer))
|
||||
{
|
||||
Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t), NO_STREAM_CALLBACK);
|
||||
|
||||
if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX)
|
||||
{
|
||||
Endpoint_StallTransaction();
|
||||
return;
|
||||
}
|
||||
|
||||
Endpoint_Read_Stream_LE(RNDISInterfaceInfo->FrameIN.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK);
|
||||
|
||||
Endpoint_ClearOUT();
|
||||
|
||||
RNDISInterfaceInfo->FrameIN.FrameLength = RNDISPacketHeader.DataLength;
|
||||
|
||||
RNDISInterfaceInfo->FrameIN.FrameInBuffer = true;
|
||||
}
|
||||
|
||||
Endpoint_SelectEndpoint(RNDISInterfaceInfo->DataINEndpointNumber);
|
||||
|
||||
if (Endpoint_IsINReady() && RNDISInterfaceInfo->FrameOUT.FrameInBuffer)
|
||||
{
|
||||
memset(&RNDISPacketHeader, 0, sizeof(RNDIS_PACKET_MSG_t));
|
||||
|
||||
RNDISPacketHeader.MessageType = REMOTE_NDIS_PACKET_MSG;
|
||||
RNDISPacketHeader.MessageLength = (sizeof(RNDIS_PACKET_MSG_t) + RNDISInterfaceInfo->FrameOUT.FrameLength);
|
||||
RNDISPacketHeader.DataOffset = (sizeof(RNDIS_PACKET_MSG_t) - sizeof(RNDIS_Message_Header_t));
|
||||
RNDISPacketHeader.DataLength = RNDISInterfaceInfo->FrameOUT.FrameLength;
|
||||
|
||||
Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t), NO_STREAM_CALLBACK);
|
||||
Endpoint_Write_Stream_LE(RNDISInterfaceInfo->FrameOUT.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK);
|
||||
Endpoint_ClearIN();
|
||||
|
||||
RNDISInterfaceInfo->FrameOUT.FrameInBuffer = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void USB_RNDIS_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo)
|
||||
{
|
||||
/* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of
|
||||
this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */
|
||||
|
||||
RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||
|
||||
switch (MessageHeader->MessageType)
|
||||
{
|
||||
case REMOTE_NDIS_INITIALIZE_MSG:
|
||||
RNDISInterfaceInfo->ResponseReady = true;
|
||||
|
||||
RNDIS_INITIALIZE_MSG_t* INITIALIZE_Message = (RNDIS_INITIALIZE_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||
RNDIS_INITIALIZE_CMPLT_t* INITIALIZE_Response = (RNDIS_INITIALIZE_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||
|
||||
INITIALIZE_Response->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
|
||||
INITIALIZE_Response->MessageLength = sizeof(RNDIS_INITIALIZE_CMPLT_t);
|
||||
INITIALIZE_Response->RequestId = INITIALIZE_Message->RequestId;
|
||||
INITIALIZE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||
|
||||
INITIALIZE_Response->MajorVersion = REMOTE_NDIS_VERSION_MAJOR;
|
||||
INITIALIZE_Response->MinorVersion = REMOTE_NDIS_VERSION_MINOR;
|
||||
INITIALIZE_Response->DeviceFlags = REMOTE_NDIS_DF_CONNECTIONLESS;
|
||||
INITIALIZE_Response->Medium = REMOTE_NDIS_MEDIUM_802_3;
|
||||
INITIALIZE_Response->MaxPacketsPerTransfer = 1;
|
||||
INITIALIZE_Response->MaxTransferSize = (sizeof(RNDIS_PACKET_MSG_t) + ETHERNET_FRAME_SIZE_MAX);
|
||||
INITIALIZE_Response->PacketAlignmentFactor = 0;
|
||||
INITIALIZE_Response->AFListOffset = 0;
|
||||
INITIALIZE_Response->AFListSize = 0;
|
||||
|
||||
RNDISInterfaceInfo->CurrRNDISState = RNDIS_Initialized;
|
||||
|
||||
break;
|
||||
case REMOTE_NDIS_HALT_MSG:
|
||||
RNDISInterfaceInfo->ResponseReady = false;
|
||||
MessageHeader->MessageLength = 0;
|
||||
|
||||
RNDISInterfaceInfo->CurrRNDISState = RNDIS_Uninitialized;
|
||||
|
||||
break;
|
||||
case REMOTE_NDIS_QUERY_MSG:
|
||||
RNDISInterfaceInfo->ResponseReady = true;
|
||||
|
||||
RNDIS_QUERY_MSG_t* QUERY_Message = (RNDIS_QUERY_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||
RNDIS_QUERY_CMPLT_t* QUERY_Response = (RNDIS_QUERY_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||
uint32_t Query_Oid = QUERY_Message->Oid;
|
||||
|
||||
void* QueryData = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
|
||||
QUERY_Message->InformationBufferOffset];
|
||||
void* ResponseData = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_QUERY_CMPLT_t)];
|
||||
uint16_t ResponseSize;
|
||||
|
||||
QUERY_Response->MessageType = REMOTE_NDIS_QUERY_CMPLT;
|
||||
QUERY_Response->MessageLength = sizeof(RNDIS_QUERY_CMPLT_t);
|
||||
|
||||
if (USB_RNDIS_ProcessNDISQuery(RNDISInterfaceInfo, Query_Oid, QueryData, QUERY_Message->InformationBufferLength,
|
||||
ResponseData, &ResponseSize))
|
||||
{
|
||||
QUERY_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||
QUERY_Response->MessageLength += ResponseSize;
|
||||
|
||||
QUERY_Response->InformationBufferLength = ResponseSize;
|
||||
QUERY_Response->InformationBufferOffset = (sizeof(RNDIS_QUERY_CMPLT_t) - sizeof(RNDIS_Message_Header_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
QUERY_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
|
||||
|
||||
QUERY_Response->InformationBufferLength = 0;
|
||||
QUERY_Response->InformationBufferOffset = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
case REMOTE_NDIS_SET_MSG:
|
||||
RNDISInterfaceInfo->ResponseReady = true;
|
||||
|
||||
RNDIS_SET_MSG_t* SET_Message = (RNDIS_SET_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||
RNDIS_SET_CMPLT_t* SET_Response = (RNDIS_SET_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||
uint32_t SET_Oid = SET_Message->Oid;
|
||||
|
||||
SET_Response->MessageType = REMOTE_NDIS_SET_CMPLT;
|
||||
SET_Response->MessageLength = sizeof(RNDIS_SET_CMPLT_t);
|
||||
SET_Response->RequestId = SET_Message->RequestId;
|
||||
|
||||
void* SetData = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
|
||||
SET_Message->InformationBufferOffset];
|
||||
|
||||
if (USB_RNDIS_ProcessNDISSet(RNDISInterfaceInfo, SET_Oid, SetData, SET_Message->InformationBufferLength))
|
||||
SET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||
else
|
||||
SET_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
|
||||
|
||||
break;
|
||||
case REMOTE_NDIS_RESET_MSG:
|
||||
RNDISInterfaceInfo->ResponseReady = true;
|
||||
|
||||
RNDIS_RESET_CMPLT_t* RESET_Response = (RNDIS_RESET_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||
|
||||
RESET_Response->MessageType = REMOTE_NDIS_RESET_CMPLT;
|
||||
RESET_Response->MessageLength = sizeof(RNDIS_RESET_CMPLT_t);
|
||||
RESET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||
RESET_Response->AddressingReset = 0;
|
||||
|
||||
break;
|
||||
case REMOTE_NDIS_KEEPALIVE_MSG:
|
||||
RNDISInterfaceInfo->ResponseReady = true;
|
||||
|
||||
RNDIS_KEEPALIVE_MSG_t* KEEPALIVE_Message = (RNDIS_KEEPALIVE_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||
RNDIS_KEEPALIVE_CMPLT_t* KEEPALIVE_Response = (RNDIS_KEEPALIVE_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||
|
||||
KEEPALIVE_Response->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
|
||||
KEEPALIVE_Response->MessageLength = sizeof(RNDIS_KEEPALIVE_CMPLT_t);
|
||||
KEEPALIVE_Response->RequestId = KEEPALIVE_Message->RequestId;
|
||||
KEEPALIVE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool USB_RNDIS_ProcessNDISQuery(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo,
|
||||
uint32_t OId, void* QueryData, uint16_t QuerySize,
|
||||
void* ResponseData, uint16_t* ResponseSize)
|
||||
{
|
||||
switch (OId)
|
||||
{
|
||||
case OID_GEN_SUPPORTED_LIST:
|
||||
*ResponseSize = sizeof(AdapterSupportedOIDList);
|
||||
|
||||
memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList));
|
||||
|
||||
return true;
|
||||
case OID_GEN_PHYSICAL_MEDIUM:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Indicate that the device is a true ethernet link */
|
||||
*((uint32_t*)ResponseData) = 0;
|
||||
|
||||
return true;
|
||||
case OID_GEN_HARDWARE_STATUS:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
*((uint32_t*)ResponseData) = NdisHardwareStatusReady;
|
||||
|
||||
return true;
|
||||
case OID_GEN_MEDIA_SUPPORTED:
|
||||
case OID_GEN_MEDIA_IN_USE:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIUM_802_3;
|
||||
|
||||
return true;
|
||||
case OID_GEN_VENDOR_ID:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */
|
||||
*((uint32_t*)ResponseData) = 0x00FFFFFF;
|
||||
|
||||
return true;
|
||||
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
||||
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
||||
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
*((uint32_t*)ResponseData) = ETHERNET_FRAME_SIZE_MAX;
|
||||
|
||||
return true;
|
||||
case OID_GEN_VENDOR_DESCRIPTION:
|
||||
*ResponseSize = (strlen(RNDISInterfaceInfo->AdapterVendorDescription) + 1);
|
||||
|
||||
memcpy(ResponseData, RNDISInterfaceInfo->AdapterVendorDescription, *ResponseSize);
|
||||
|
||||
return true;
|
||||
case OID_GEN_MEDIA_CONNECT_STATUS:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIA_STATE_CONNECTED;
|
||||
|
||||
return true;
|
||||
case OID_GEN_LINK_SPEED:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Indicate 10Mb/s link speed */
|
||||
*((uint32_t*)ResponseData) = 100000;
|
||||
|
||||
return true;
|
||||
case OID_802_3_PERMANENT_ADDRESS:
|
||||
case OID_802_3_CURRENT_ADDRESS:
|
||||
*ResponseSize = sizeof(MAC_Address_t);
|
||||
|
||||
memcpy(ResponseData, &RNDISInterfaceInfo->AdapterMACAddress, sizeof(MAC_Address_t));
|
||||
|
||||
return true;
|
||||
case OID_802_3_MAXIMUM_LIST_SIZE:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Indicate only one multicast address supported */
|
||||
*((uint32_t*)ResponseData) = 1;
|
||||
|
||||
return true;
|
||||
case OID_GEN_CURRENT_PACKET_FILTER:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
*((uint32_t*)ResponseData) = RNDISInterfaceInfo->CurrPacketFilter;
|
||||
|
||||
return true;
|
||||
case OID_GEN_XMIT_OK:
|
||||
case OID_GEN_RCV_OK:
|
||||
case OID_GEN_XMIT_ERROR:
|
||||
case OID_GEN_RCV_ERROR:
|
||||
case OID_GEN_RCV_NO_BUFFER:
|
||||
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
||||
case OID_802_3_XMIT_ONE_COLLISION:
|
||||
case OID_802_3_XMIT_MORE_COLLISIONS:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Unused statistic OIDs - always return 0 for each */
|
||||
*((uint32_t*)ResponseData) = 0;
|
||||
|
||||
return true;
|
||||
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
||||
*ResponseSize = sizeof(uint32_t);
|
||||
|
||||
/* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */
|
||||
*((uint32_t*)ResponseData) = (RNDIS_MESSAGE_BUFFER_SIZE + ETHERNET_FRAME_SIZE_MAX);
|
||||
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool USB_RNDIS_ProcessNDISSet(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, uint32_t OId, void* SetData, uint16_t SetSize)
|
||||
{
|
||||
switch (OId)
|
||||
{
|
||||
case OID_GEN_CURRENT_PACKET_FILTER:
|
||||
RNDISInterfaceInfo->CurrPacketFilter = *((uint32_t*)SetData);
|
||||
RNDISInterfaceInfo->CurrRNDISState = ((RNDISInterfaceInfo->CurrPacketFilter) ?
|
||||
RNDIS_Data_Initialized : RNDIS_Data_Initialized);
|
||||
|
||||
return true;
|
||||
case OID_802_3_MULTICAST_LIST:
|
||||
/* Do nothing - throw away the value from the host as it is unused */
|
||||
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -28,26 +28,16 @@
|
|||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Header file for RNDIS.c.
|
||||
*/
|
||||
|
||||
#ifndef _RNDIS_H_
|
||||
#define _RNDIS_H_
|
||||
#ifndef _RNDIS_CLASS_H_
|
||||
#define _RNDIS_CLASS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <avr/io.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "RNDISEthernet.h"
|
||||
#include "../../USB.h"
|
||||
#include "RNDISConstants.h"
|
||||
#include "Ethernet.h"
|
||||
|
||||
/* Macros: */
|
||||
/** Physical MAC Address of the USB network adapter */
|
||||
#define ADAPTER_MAC_ADDRESS {0x02, 0x00, 0x02, 0x00, 0x02, 0x00}
|
||||
|
||||
/** Implemented RNDIS Version Major */
|
||||
#define REMOTE_NDIS_VERSION_MAJOR 0x01
|
||||
|
||||
|
@ -60,6 +50,12 @@
|
|||
/** RNDIS request to issue a device-to-host NDIS response */
|
||||
#define REQ_GetEncapsulatedResponse 0x01
|
||||
|
||||
#define RNDIS_MESSAGE_BUFFER_SIZE 128
|
||||
|
||||
#define ETHERNET_FRAME_SIZE_MAX 1500
|
||||
|
||||
#define NOTIF_ResponseAvailable 1
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible NDIS adapter states. */
|
||||
enum RNDIS_States_t
|
||||
|
@ -80,6 +76,12 @@
|
|||
};
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for a physical MAC address of a device on a network */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t Octets[6]; /**< Individual bytes of a MAC address */
|
||||
} MAC_Address_t;
|
||||
|
||||
/** Type define for a RNDIS message header, sent before RNDIS messages */
|
||||
typedef struct
|
||||
{
|
||||
|
@ -87,6 +89,14 @@
|
|||
uint32_t MessageLength; /**< Total length of the RNDIS message, in bytes */
|
||||
} RNDIS_Message_Header_t;
|
||||
|
||||
/** Type define for an Ethernet frame buffer. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t FrameData[ETHERNET_FRAME_SIZE_MAX]; /**< Ethernet frame contents */
|
||||
uint16_t FrameLength; /**< Length in bytes of the Ethernet frame stored in the buffer */
|
||||
bool FrameInBuffer; /**< Indicates if a frame is currently stored in the buffer */
|
||||
} Ethernet_Frame_Info_t;
|
||||
|
||||
/** Type define for a RNDIS packet message, used to encapsulate Ethernet packets sent to and from the adapter */
|
||||
typedef struct
|
||||
{
|
||||
|
@ -103,6 +113,30 @@
|
|||
uint32_t Reserved;
|
||||
} RNDIS_PACKET_MSG_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t ControlInterfaceNumber; /**< Interface number of the CDC control interface within the device */
|
||||
|
||||
uint8_t DataINEndpointNumber; /**< Endpoint number of the CDC interface's IN data endpoint */
|
||||
uint16_t DataINEndpointSize; /**< Size in bytes of the CDC interface's IN data endpoint */
|
||||
|
||||
uint8_t DataOUTEndpointNumber; /**< Endpoint number of the CDC interface's OUT data endpoint */
|
||||
uint16_t DataOUTEndpointSize; /**< Size in bytes of the CDC interface's OUT data endpoint */
|
||||
|
||||
uint8_t NotificationEndpointNumber; /**< Endpoint number of the CDC interface's IN notification endpoint, if used */
|
||||
uint16_t NotificationEndpointSize; /**< Size in bytes of the CDC interface's IN notification endpoint, if used */
|
||||
|
||||
char* AdapterVendorDescription;
|
||||
MAC_Address_t AdapterMACAddress;
|
||||
|
||||
uint8_t RNDISMessageBuffer[RNDIS_MESSAGE_BUFFER_SIZE];
|
||||
bool ResponseReady;
|
||||
uint8_t CurrRNDISState;
|
||||
uint32_t CurrPacketFilter;
|
||||
Ethernet_Frame_Info_t FrameIN;
|
||||
Ethernet_Frame_Info_t FrameOUT;
|
||||
} USB_ClassInfo_RNDIS_t;
|
||||
|
||||
/** Type define for a RNDIS Initialize command message */
|
||||
typedef struct
|
||||
{
|
||||
|
@ -208,19 +242,19 @@
|
|||
uint32_t InformationBufferOffset;
|
||||
} RNDIS_QUERY_CMPLT_t;
|
||||
|
||||
/* External Variables: */
|
||||
extern uint8_t RNDISMessageBuffer[];
|
||||
extern RNDIS_Message_Header_t* MessageHeader;
|
||||
extern bool ResponseReady;
|
||||
extern uint8_t CurrRNDISState;
|
||||
|
||||
/* Function Prototypes: */
|
||||
void ProcessRNDISControlMessage(void);
|
||||
|
||||
#if defined(INCLUDE_FROM_RNDIS_C)
|
||||
static bool ProcessNDISQuery(uint32_t OId, void* QueryData, uint16_t QuerySize,
|
||||
#if defined(INCLUDE_FROM_RNDIS_CLASS_C)
|
||||
static void USB_RNDIS_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo);
|
||||
static bool USB_RNDIS_ProcessNDISQuery(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo,
|
||||
uint32_t OId, void* QueryData, uint16_t QuerySize,
|
||||
void* ResponseData, uint16_t* ResponseSize);
|
||||
static bool ProcessNDISSet(uint32_t OId, void* SetData, uint16_t SetSize);
|
||||
static bool USB_RNDIS_ProcessNDISSet(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, uint32_t OId,
|
||||
void* SetData, uint16_t SetSize);
|
||||
#endif
|
||||
|
||||
void USB_RNDIS_USBTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo);
|
||||
bool USB_RNDIS_ConfigureEndpoints(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo);
|
||||
void USB_RNDIS_ProcessControlPacket(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo);
|
||||
void USB_RNDIS_USBTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo);
|
||||
|
||||
#endif
|
|
@ -63,7 +63,7 @@
|
|||
|
||||
#include "HIDReportData.h"
|
||||
|
||||
#include "../../../Common/Common.h"
|
||||
#include "../../../../Common/Common.h"
|
||||
|
||||
/* Enable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
|
@ -267,6 +267,11 @@
|
|||
* \ref Group_USBManagement documentation).
|
||||
*/
|
||||
void EVENT_USB_Reset(void);
|
||||
|
||||
/** Event for the USB start of frame interrupt, firing once each millisecond in either device or host
|
||||
* mode, while USB frames are being generated or recieved.
|
||||
*/
|
||||
void EVENT_USB_StartOfFrame(void);
|
||||
#endif
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
|
@ -303,6 +308,7 @@
|
|||
void EVENT_USB_Suspend(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub);
|
||||
void EVENT_USB_WakeUp(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub);
|
||||
void EVENT_USB_Reset(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub);
|
||||
void EVENT_USB_StartOfFrame(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -180,6 +180,15 @@ ISR(USB_GEN_vect, ISR_BLOCK)
|
|||
|
||||
EVENT_USB_Reset();
|
||||
}
|
||||
|
||||
if (USB_INT_HasOccurred(USB_INT_SOFI) && USB_INT_IsEnabled(USB_INT_SOFI))
|
||||
{
|
||||
USB_INT_Clear(USB_INT_SOFI);
|
||||
|
||||
FrameElapsed = true;
|
||||
|
||||
EVENT_USB_StartOfFrame();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USB_CAN_BE_HOST)
|
||||
|
@ -232,6 +241,15 @@ ISR(USB_GEN_vect, ISR_BLOCK)
|
|||
|
||||
USB_ResetInterface();
|
||||
}
|
||||
|
||||
if (USB_INT_HasOccurred(USB_INT_HSOFI) && USB_INT_IsEnabled(USB_INT_HSOFI))
|
||||
{
|
||||
USB_INT_Clear(USB_INT_HSOFI);
|
||||
|
||||
FrameElapsed = true;
|
||||
|
||||
EVENT_USB_StartOfFrame();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USB_CAN_BE_BOTH)
|
||||
|
|
|
@ -42,7 +42,7 @@ USB_Request_Header_t USB_ControlRequest;
|
|||
volatile uint8_t USB_HostState;
|
||||
#endif
|
||||
|
||||
TASK(USB_USBTask)
|
||||
void USB_USBTask(void)
|
||||
{
|
||||
#if defined(USB_HOST_ONLY)
|
||||
USB_HostTask();
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../../../Scheduler/Scheduler.h"
|
||||
#include "../LowLevel/LowLevel.h"
|
||||
#include "StdRequestType.h"
|
||||
#include "USBMode.h"
|
||||
|
@ -122,11 +121,11 @@
|
|||
extern volatile uint8_t USB_HostState;
|
||||
#endif
|
||||
|
||||
/* Tasks: */
|
||||
/* Function Prototypes: */
|
||||
/** This is the main USB management task. The USB driver requires that this task be executed
|
||||
* continuously when the USB system is active (device attached in host mode, or attached to a host
|
||||
* in device mode) in order to manage USB communications. This task may be executed inside an RTOS,
|
||||
* scheduler (e.g. the simple LUFA Scheduler), fast timer ISR or the main user application loop.
|
||||
* fast timer ISR or the main user application loop.
|
||||
*
|
||||
* The USB task must be serviced within 30ms while in device mode, or within 1ms while in host mode.
|
||||
* The task may be serviced at all times, or (for minimum CPU consumption):
|
||||
|
@ -145,7 +144,7 @@
|
|||
*
|
||||
* \ingroup Group_USBManagement
|
||||
*/
|
||||
TASK(USB_USBTask);
|
||||
void USB_USBTask(void);
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
|
|
@ -80,8 +80,6 @@ uint8_t Endpoint_WaitUntilReady(void)
|
|||
uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS;
|
||||
#endif
|
||||
|
||||
USB_INT_Clear(USB_INT_SOFI);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (Endpoint_GetEndpointDirection() == ENDPOINT_DIR_IN)
|
||||
|
@ -100,9 +98,9 @@ uint8_t Endpoint_WaitUntilReady(void)
|
|||
else if (Endpoint_IsStalled())
|
||||
return ENDPOINT_READYWAIT_EndpointStalled;
|
||||
|
||||
if (USB_INT_HasOccurred(USB_INT_SOFI))
|
||||
if (FrameElapsed)
|
||||
{
|
||||
USB_INT_Clear(USB_INT_SOFI);
|
||||
FrameElapsed = false;
|
||||
|
||||
if (!(TimeoutMSRem--))
|
||||
return ENDPOINT_READYWAIT_Timeout;
|
||||
|
|
|
@ -210,14 +210,13 @@ uint8_t USB_Host_WaitMS(uint8_t MS)
|
|||
bool BusSuspended = USB_Host_IsBusSuspended();
|
||||
uint8_t ErrorCode = HOST_WAITERROR_Successful;
|
||||
|
||||
USB_INT_Clear(USB_INT_HSOFI);
|
||||
USB_Host_ResumeBus();
|
||||
|
||||
while (MS)
|
||||
{
|
||||
if (USB_INT_HasOccurred(USB_INT_HSOFI))
|
||||
if (FrameElapsed)
|
||||
{
|
||||
USB_INT_Clear(USB_INT_HSOFI);
|
||||
FrameElapsed = false;
|
||||
MS--;
|
||||
}
|
||||
|
||||
|
@ -260,9 +259,10 @@ static void USB_Host_ResetDevice(void)
|
|||
USB_Host_ResetBus();
|
||||
while (!(USB_Host_IsBusResetComplete()));
|
||||
|
||||
USB_INT_Clear(USB_INT_HSOFI);
|
||||
USB_Host_ResumeBus();
|
||||
|
||||
FrameElapsed = false;
|
||||
|
||||
for (uint8_t MSRem = 10; MSRem != 0; MSRem--)
|
||||
{
|
||||
/* Workaround for powerless-pull-up devices. After a USB bus reset,
|
||||
|
@ -270,8 +270,10 @@ static void USB_Host_ResetDevice(void)
|
|||
looked for - if it is found within 10ms, the device is still
|
||||
present. */
|
||||
|
||||
if (USB_INT_HasOccurred(USB_INT_HSOFI))
|
||||
if (FrameElapsed)
|
||||
{
|
||||
FrameElapsed = false;
|
||||
|
||||
USB_INT_Clear(USB_INT_DDISCI);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ volatile uint8_t USB_CurrentMode = USB_MODE_NONE;
|
|||
volatile uint8_t USB_Options;
|
||||
#endif
|
||||
|
||||
volatile bool FrameElapsed;
|
||||
|
||||
void USB_Init(
|
||||
#if defined(USB_CAN_BE_BOTH)
|
||||
const uint8_t Mode
|
||||
|
@ -150,6 +152,8 @@ void USB_ResetInterface(void)
|
|||
USB_INT_DisableAllInterrupts();
|
||||
USB_INT_ClearAllInterrupts();
|
||||
|
||||
FrameElapsed = false;
|
||||
|
||||
USB_IsConnected = false;
|
||||
|
||||
#if defined(USB_CAN_BE_HOST)
|
||||
|
@ -224,6 +228,7 @@ void USB_ResetInterface(void)
|
|||
#if defined(USB_DEVICE_ONLY)
|
||||
USB_INT_Enable(USB_INT_SUSPEND);
|
||||
USB_INT_Enable(USB_INT_EORSTI);
|
||||
USB_INT_Enable(USB_INT_SOFI);
|
||||
|
||||
#if defined(CONTROL_ONLY_DEVICE)
|
||||
UENUM = ENDPOINT_CONTROLEP;
|
||||
|
@ -240,11 +245,13 @@ void USB_ResetInterface(void)
|
|||
|
||||
USB_INT_Enable(USB_INT_SRPI);
|
||||
USB_INT_Enable(USB_INT_BCERRI);
|
||||
USB_INT_Enable(USB_INT_HSOFI);
|
||||
#else
|
||||
if (USB_CurrentMode == USB_MODE_DEVICE)
|
||||
{
|
||||
USB_INT_Enable(USB_INT_SUSPEND);
|
||||
USB_INT_Enable(USB_INT_EORSTI);
|
||||
USB_INT_Enable(USB_INT_SOFI);
|
||||
|
||||
#if defined(CONTROL_ONLY_DEVICE)
|
||||
UENUM = ENDPOINT_CONTROLEP;
|
||||
|
@ -262,6 +269,7 @@ void USB_ResetInterface(void)
|
|||
|
||||
USB_INT_Enable(USB_INT_SRPI);
|
||||
USB_INT_Enable(USB_INT_BCERRI);
|
||||
USB_INT_Enable(USB_INT_HSOFI);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -351,6 +351,9 @@
|
|||
}
|
||||
#endif
|
||||
|
||||
/* External Variables: */
|
||||
extern volatile bool FrameElapsed;
|
||||
|
||||
#endif
|
||||
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
|
|
|
@ -76,8 +76,6 @@ uint8_t Pipe_WaitUntilReady(void)
|
|||
uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS;
|
||||
#endif
|
||||
|
||||
USB_INT_Clear(USB_INT_HSOFI);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (Pipe_GetPipeToken() == PIPE_TOKEN_IN)
|
||||
|
@ -96,9 +94,9 @@ uint8_t Pipe_WaitUntilReady(void)
|
|||
else if (!(USB_IsConnected))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
if (USB_INT_HasOccurred(USB_INT_HSOFI))
|
||||
if (FrameElapsed)
|
||||
{
|
||||
USB_INT_Clear(USB_INT_HSOFI);
|
||||
FrameElapsed = false;
|
||||
|
||||
if (!(TimeoutMSRem--))
|
||||
return PIPE_READYWAIT_Timeout;
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
* - LUFA/Drivers/USB/HighLevel/USBInterrupt.c
|
||||
* - LUFA/Drivers/USB/HighLevel/USBTask.c
|
||||
* - LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c
|
||||
* - LUFA/Drivers/USB/Class/HIDParser.c
|
||||
*
|
||||
* \section Module Description
|
||||
* Functions, macros, variables, enums and types related to the management of USB communications.
|
||||
|
@ -97,7 +96,6 @@
|
|||
#endif
|
||||
|
||||
#include "HighLevel/ConfigDescriptor.h"
|
||||
#include "Class/HIDParser.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,226 +0,0 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
#define INCLUDE_FROM_DYNALLOC_C
|
||||
#include "DynAlloc.h"
|
||||
|
||||
struct
|
||||
{
|
||||
char Mem_Heap[NUM_BLOCKS * BLOCK_SIZE];
|
||||
void* Mem_Handles[NUM_HANDLES];
|
||||
uint8_t Mem_Block_Flags[(NUM_BLOCKS / 4) + ((NUM_BLOCKS % 4) ? 1 : 0)];
|
||||
uint8_t FlagMaskLookupMask[4];
|
||||
uint8_t FlagMaskLookupNum[4];
|
||||
} Mem_MemData = {.FlagMaskLookupMask = {(3 << 0), (3 << 2), (3 << 4), (3 << 6)},
|
||||
.FlagMaskLookupNum = { 0, 2, 4, 6}};
|
||||
|
||||
static uint8_t Mem_GetBlockFlags(const Block_Number_t BlockNum)
|
||||
{
|
||||
const Block_Number_t BlockIndex = (BlockNum >> 2);
|
||||
const uint8_t FlagMask = Mem_MemData.FlagMaskLookupMask[BlockNum & 0x03];
|
||||
const uint8_t FlagMaskShift = Mem_MemData.FlagMaskLookupNum[BlockNum & 0x03];
|
||||
|
||||
return ((Mem_MemData.Mem_Block_Flags[BlockIndex] & FlagMask) >> FlagMaskShift);
|
||||
}
|
||||
|
||||
static void Mem_SetBlockFlags(const Block_Number_t BlockNum, const uint8_t Flags)
|
||||
{
|
||||
const Block_Number_t BlockIndex = (BlockNum >> 2);
|
||||
const uint8_t FlagMask = Mem_MemData.FlagMaskLookupMask[BlockNum & 0x03];
|
||||
const uint8_t FlagMaskShift = Mem_MemData.FlagMaskLookupNum[BlockNum & 0x03];
|
||||
|
||||
Mem_MemData.Mem_Block_Flags[BlockIndex] &= ~FlagMask;
|
||||
Mem_MemData.Mem_Block_Flags[BlockIndex] |= (Flags << FlagMaskShift);
|
||||
}
|
||||
|
||||
static inline void Mem_Defrag(void)
|
||||
{
|
||||
Block_Number_t FreeStartBlock = 0;
|
||||
char* FreeStartPtr = NULL;
|
||||
char* UsedStartPtr = NULL;
|
||||
Block_Number_t CurrBlock;
|
||||
|
||||
for (CurrBlock = 0; CurrBlock < NUM_BLOCKS; CurrBlock++)
|
||||
{
|
||||
if (!(Mem_GetBlockFlags(CurrBlock) & BLOCK_USED_MASK))
|
||||
{
|
||||
FreeStartPtr = &Mem_MemData.Mem_Heap[CurrBlock * BLOCK_SIZE];
|
||||
FreeStartBlock = CurrBlock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (FreeStartPtr == NULL)
|
||||
return;
|
||||
|
||||
while (++CurrBlock < NUM_BLOCKS)
|
||||
{
|
||||
uint8_t CurrBlockFlags = Mem_GetBlockFlags(CurrBlock);
|
||||
|
||||
if (CurrBlockFlags & BLOCK_USED_MASK)
|
||||
{
|
||||
UsedStartPtr = &Mem_MemData.Mem_Heap[CurrBlock * BLOCK_SIZE];
|
||||
|
||||
for (Handle_Number_t HandleNum = 0; HandleNum < NUM_HANDLES; HandleNum++)
|
||||
{
|
||||
if (Mem_MemData.Mem_Handles[HandleNum] == UsedStartPtr)
|
||||
{
|
||||
Mem_MemData.Mem_Handles[HandleNum] = FreeStartPtr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(FreeStartPtr, UsedStartPtr, BLOCK_SIZE);
|
||||
FreeStartPtr += BLOCK_SIZE;
|
||||
|
||||
Mem_SetBlockFlags(FreeStartBlock++, CurrBlockFlags);
|
||||
Mem_SetBlockFlags(CurrBlock, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool Mem_FindFreeBlocks(Block_Number_t* const RetStartPtr, const Block_Number_t Blocks)
|
||||
{
|
||||
Block_Number_t FreeInCurrSec = 0;
|
||||
|
||||
for (Block_Number_t CurrBlock = 0; CurrBlock < NUM_BLOCKS; CurrBlock++)
|
||||
{
|
||||
if (Mem_GetBlockFlags(CurrBlock) & BLOCK_USED_MASK)
|
||||
FreeInCurrSec = 0;
|
||||
else
|
||||
FreeInCurrSec++;
|
||||
|
||||
if (FreeInCurrSec >= Blocks)
|
||||
{
|
||||
*RetStartPtr = CurrBlock;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Mem_Handle_t Mem_Alloc(const Alloc_Size_t Bytes)
|
||||
{
|
||||
Block_Number_t ReqBlocks = (Bytes / BLOCK_SIZE);
|
||||
Block_Number_t StartBlock;
|
||||
|
||||
if (Bytes % BLOCK_SIZE)
|
||||
ReqBlocks++;
|
||||
|
||||
if (!(Mem_FindFreeBlocks(&StartBlock, ReqBlocks)))
|
||||
{
|
||||
Mem_Defrag();
|
||||
|
||||
if (!(Mem_FindFreeBlocks(&StartBlock, ReqBlocks)))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (Block_Number_t UsedBlock = 0; UsedBlock < (ReqBlocks - 1); UsedBlock++)
|
||||
Mem_SetBlockFlags((StartBlock + UsedBlock), (BLOCK_USED_MASK | BLOCK_LINKED_MASK));
|
||||
|
||||
Mem_SetBlockFlags((StartBlock + (ReqBlocks - 1)), BLOCK_USED_MASK);
|
||||
|
||||
for (Handle_Number_t AllocEntry = 0; AllocEntry < NUM_HANDLES; AllocEntry++)
|
||||
{
|
||||
Mem_Handle_t CurrHdl = (Mem_Handle_t)&Mem_MemData.Mem_Handles[AllocEntry];
|
||||
|
||||
if (DEREF(CurrHdl, void*) == NULL)
|
||||
{
|
||||
DEREF(CurrHdl, void*) = &Mem_MemData.Mem_Heap[StartBlock * BLOCK_SIZE];
|
||||
return CurrHdl;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Mem_Handle_t Mem_Realloc(Mem_Handle_t CurrAllocHdl, const Alloc_Size_t Bytes)
|
||||
{
|
||||
Mem_Free(CurrAllocHdl);
|
||||
return Mem_Alloc(Bytes);
|
||||
}
|
||||
|
||||
Mem_Handle_t Mem_Calloc(const Alloc_Size_t Bytes)
|
||||
{
|
||||
Mem_Handle_t AllocHdl = Mem_Alloc(Bytes);
|
||||
|
||||
if (AllocHdl != NULL)
|
||||
memset(DEREF(AllocHdl, void*), 0x00, Bytes);
|
||||
|
||||
return AllocHdl;
|
||||
}
|
||||
|
||||
void Mem_Free(Mem_Handle_t CurrAllocHdl)
|
||||
{
|
||||
char* MemBlockPtr = DEREF(CurrAllocHdl, char*);
|
||||
Block_Number_t CurrBlock = ((uint16_t)(MemBlockPtr - Mem_MemData.Mem_Heap) / BLOCK_SIZE);
|
||||
uint8_t CurrBlockFlags;
|
||||
|
||||
if ((CurrAllocHdl == NULL) || (MemBlockPtr == NULL))
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
CurrBlockFlags = Mem_GetBlockFlags(CurrBlock);
|
||||
Mem_SetBlockFlags(CurrBlock, 0);
|
||||
|
||||
CurrBlock++;
|
||||
}
|
||||
while (CurrBlockFlags & BLOCK_LINKED_MASK);
|
||||
|
||||
DEREF(CurrAllocHdl, void*) = NULL;
|
||||
}
|
||||
|
||||
Block_Number_t Mem_TotalFreeBlocks(void)
|
||||
{
|
||||
Block_Number_t FreeBlocks = 0;
|
||||
|
||||
for (Block_Number_t CurrBlock = 0; CurrBlock < NUM_BLOCKS; CurrBlock++)
|
||||
{
|
||||
if (!(Mem_GetBlockFlags(CurrBlock) & BLOCK_USED_MASK))
|
||||
FreeBlocks++;
|
||||
}
|
||||
|
||||
return FreeBlocks;
|
||||
}
|
||||
|
||||
Handle_Number_t Mem_TotalFreeHandles(void)
|
||||
{
|
||||
Handle_Number_t FreeHandles = 0;
|
||||
|
||||
for (Handle_Number_t CurrHandle = 0; CurrHandle < NUM_HANDLES; CurrHandle++)
|
||||
{
|
||||
if (Mem_MemData.Mem_Handles[CurrHandle] == NULL)
|
||||
FreeHandles++;
|
||||
}
|
||||
|
||||
return FreeHandles;
|
||||
}
|
|
@ -1,198 +0,0 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Dynamic, auto-defragmenting block memory allocator library. This library provides a convenient replacement for
|
||||
* the standard avr-libc dynamic memory allocation routines. Memory is handed out in block chunks, to reduce the
|
||||
* management memory overhead.
|
||||
*/
|
||||
|
||||
/** @defgroup Group_MemoryAllocator Dynamic Block Memory Allocator - LUFA/MemoryAllocator/DynAlloc.h
|
||||
*
|
||||
* \section Sec_Dependencies Module Source Dependencies
|
||||
* The following files must be built with any user project that uses this module:
|
||||
* - LUFA/MemoryAllocator/DynAlloc.c
|
||||
*
|
||||
* \section Module Description
|
||||
* Dynamic, auto-defragmenting block memory allocator library. This library provides a convenient replacement for
|
||||
* the standard avr-libc dynamic memory allocation routines. Memory is handed out in block chunks, to reduce the
|
||||
* management memory overhead.
|
||||
*
|
||||
* Unlike the normal memory allocation routines, this library gives out handles to memory which must be dereferenced
|
||||
* at the exact time of use, rather than handing back direct memory pointers. By using library managed handles
|
||||
* instead of pointers, allocated memory blocks can be shifted around as needed transparently to defragment the
|
||||
* memory as more blocks are requested.
|
||||
*
|
||||
* The memory heap is static, thus the total memory usage of the compiled application (as reported by the avr-size
|
||||
* tool of the AVR-GCC toolchain) includes the dynamic memory heap.
|
||||
*
|
||||
* The constants NUM_BLOCKS, BLOCK_SIZE and NUM_HANDLES must be defined in the project makefile (and passed to the
|
||||
* preprocessor via the -D GCC switch) for this library to compile.
|
||||
*
|
||||
* NUM_BLOCKS indicates the number of memory blocks in the memory psudoheap which can be chained together and handed
|
||||
* to the application via a memory handle. NUM_HANDLES is the maximum number of memory handles (pointing to one or
|
||||
* more chained memory blocks) which can be handed out simultaneously before requiring a handle (and its associated
|
||||
* memory) to be freed. BLOCK_SIZE gives the number of bytes in each memory block.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __DYN_ALLOC__
|
||||
#define __DYN_ALLOC__
|
||||
|
||||
/* Includes : */
|
||||
#include <avr/io.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Preprocessor Checks: */
|
||||
#if (!defined(NUM_BLOCKS) || !defined(BLOCK_SIZE) || !defined(NUM_HANDLES))
|
||||
#error NUM_BLOCKS, BLOCK_SIZE and NUM_HANDLES must be defined before use via makefile.
|
||||
#endif
|
||||
|
||||
/* Public Interface - May be used in end-application: */
|
||||
/* Macros: */
|
||||
/** Macro to dereference a given memory handle into the given type. The given type should be a pointer
|
||||
* if the memory is to contain an array of items, or should be a standard type (such as a primitive or
|
||||
* structure) if the memory is to hold a single item of a single type. */
|
||||
#define DEREF(handle, type) (*(type*)handle)
|
||||
|
||||
/** Constant, giving the total heap size in bytes. */
|
||||
#define ALLOCABLE_BYTES (1UL * NUM_BLOCKS * BLOCK_SIZE)
|
||||
|
||||
/* Type Defines: */
|
||||
/** Memory handle type, used to store handles given by the library functions. */
|
||||
typedef const void** Mem_Handle_t;
|
||||
|
||||
#if (ALLOCABLE_BYTES > 0xFFFF) || defined(__DOXYGEN__)
|
||||
/** Type define for the size (in bytes) for an allocation for passing to the library functions.
|
||||
* The exact type width varies depending on the value of ALLOCABLE_BYTES to ensure that a single
|
||||
* allocation can request the entire heap if needed.
|
||||
*/
|
||||
typedef uint32_t Alloc_Size_t;
|
||||
#elif (ALLOCABLE_BYTES > 0xFF)
|
||||
typedef uint16_t Alloc_Size_t;
|
||||
#else
|
||||
typedef uint8_t Alloc_Size_t;
|
||||
#endif
|
||||
|
||||
#if (NUM_BLOCKS > 0xFFFF) || defined(__DOXYGEN__)
|
||||
/** Type define for a block number in the heap. The exact type width varies depending on the
|
||||
* value of NUM_BLOCKS to ensure that the type can store an index to any block in the block pool.
|
||||
*/
|
||||
typedef uint32_t Block_Number_t;
|
||||
#elif (NUM_BLOCKS > 0xFF)
|
||||
typedef uint16_t Block_Number_t;
|
||||
#else
|
||||
typedef uint8_t Block_Number_t;
|
||||
#endif
|
||||
|
||||
#if (NUM_HANDLES > 0xFFFF) || defined(__DOXYGEN__)
|
||||
/** Type define for a handle number. The exact type width varies depending on the value of NUM_HANDLES
|
||||
* to ensure that the type can store the index of any handle in the handle pool.
|
||||
*/
|
||||
typedef uint32_t Handle_Number_t;
|
||||
#elif (NUM_HANDLES > 0xFF)
|
||||
typedef uint16_t Handle_Number_t;
|
||||
#else
|
||||
typedef uint8_t Handle_Number_t;
|
||||
#endif
|
||||
|
||||
/* Function Prototypes: */
|
||||
/** Allocates a given number of blocks from the heap (calculated from the requested number of bytes) and
|
||||
* returns a handle to the newly allocated memory.
|
||||
*
|
||||
* \param Bytes The number of bytes requested to be allocated from the heap
|
||||
*
|
||||
* \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds
|
||||
*/
|
||||
Mem_Handle_t Mem_Alloc(const Alloc_Size_t Bytes);
|
||||
|
||||
/** Allocates a given number of blocks from the heap (calculated from the requested number of bytes) and
|
||||
* returns a handle to the newly allocated memory. Calloced memory is automatically cleared to all 0x00
|
||||
* values at the time of allocation.
|
||||
*
|
||||
* \param Bytes The number of pre-cleared bytes requested to be allocated from the heap
|
||||
*
|
||||
* \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds
|
||||
*/
|
||||
Mem_Handle_t Mem_Calloc(const Alloc_Size_t Bytes);
|
||||
|
||||
/** Deallocates a given memory handle, and attempts to allocates the given number of blocks from the heap
|
||||
* (calculated from the requested number of bytes) immediately following the deallocation. The new memory
|
||||
* may be located in the same area as the previous memory, but this is not guaranteed.
|
||||
*
|
||||
* \param CurrAllocHdl Handle to an already allocated section of memory in the heap to deallocate
|
||||
* \param Bytes The number of bytes requested to be allocated from the heap following the
|
||||
* deallocation
|
||||
*
|
||||
* \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds
|
||||
*
|
||||
* \warning Even if the allocation fails, the deallocation will still occur. Care should be taken to ensure
|
||||
* that the previously allocated memory is not used following an unsuccessful realloc().
|
||||
*/
|
||||
Mem_Handle_t Mem_Realloc(Mem_Handle_t CurrAllocHdl, const Alloc_Size_t Bytes);
|
||||
|
||||
/** Deallocates a given previously allocated section of memory from the heap.
|
||||
*
|
||||
* \param CurrAllocHdl Handle to a previously allocated section of memory in the heap
|
||||
*/
|
||||
void Mem_Free(Mem_Handle_t CurrAllocHdl);
|
||||
|
||||
/** Returns the total number of unallocated blocks in the heap.
|
||||
*
|
||||
* \return Number of free blocks in the heap, as a Block_Number_t integer
|
||||
*/
|
||||
Block_Number_t Mem_TotalFreeBlocks(void);
|
||||
|
||||
/** Returns the total number of unallocated handles in the handle pool.
|
||||
*
|
||||
* \return Number of free handles in the handle pool, as a Handle_Number_t integer
|
||||
*/
|
||||
Handle_Number_t Mem_TotalFreeHandles(void);
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
/* Macros: */
|
||||
#define BLOCK_USED_MASK (1 << 0)
|
||||
#define BLOCK_LINKED_MASK (1 << 1)
|
||||
|
||||
/* Function Prototypes: */
|
||||
#if defined(INCLUDE_FROM_DYNALLOC_C)
|
||||
static uint8_t Mem_GetBlockFlags(const Block_Number_t BlockNum);
|
||||
static void Mem_SetBlockFlags(const Block_Number_t BlockNum, const uint8_t Flags);
|
||||
static void Mem_Defrag(void);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
#include "Scheduler.h"
|
||||
|
||||
volatile SchedulerDelayCounter_t Scheduler_TickCounter;
|
||||
volatile uint8_t Scheduler_TotalTasks;
|
||||
|
||||
bool Scheduler_HasDelayElapsed(const uint16_t Delay, SchedulerDelayCounter_t* const DelayCounter)
|
||||
{
|
||||
SchedulerDelayCounter_t CurrentTickValue_LCL;
|
||||
SchedulerDelayCounter_t DelayCounter_LCL;
|
||||
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
{
|
||||
CurrentTickValue_LCL = Scheduler_TickCounter;
|
||||
}
|
||||
|
||||
DelayCounter_LCL = *DelayCounter;
|
||||
|
||||
if (CurrentTickValue_LCL >= DelayCounter_LCL)
|
||||
{
|
||||
if ((CurrentTickValue_LCL - DelayCounter_LCL) >= Delay)
|
||||
{
|
||||
*DelayCounter = CurrentTickValue_LCL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((MAX_DELAYCTR_COUNT - DelayCounter_LCL) + CurrentTickValue_LCL) >= Delay)
|
||||
{
|
||||
*DelayCounter = CurrentTickValue_LCL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Scheduler_SetTaskMode(const TaskPtr_t Task, const bool TaskStatus)
|
||||
{
|
||||
TaskEntry_t* CurrTask = &Scheduler_TaskList[0];
|
||||
|
||||
while (CurrTask != &Scheduler_TaskList[Scheduler_TotalTasks])
|
||||
{
|
||||
if (CurrTask->Task == Task)
|
||||
{
|
||||
CurrTask->TaskStatus = TaskStatus;
|
||||
break;
|
||||
}
|
||||
|
||||
CurrTask++;
|
||||
}
|
||||
}
|
||||
|
||||
void Scheduler_SetGroupTaskMode(const uint8_t GroupID, const bool TaskStatus)
|
||||
{
|
||||
TaskEntry_t* CurrTask = &Scheduler_TaskList[0];
|
||||
|
||||
while (CurrTask != &Scheduler_TaskList[Scheduler_TotalTasks])
|
||||
{
|
||||
if (CurrTask->GroupID == GroupID)
|
||||
CurrTask->TaskStatus = TaskStatus;
|
||||
|
||||
CurrTask++;
|
||||
}
|
||||
}
|
|
@ -1,285 +0,0 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2009.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Simple round-robbin cooperative scheduler for use in basic projects where non real-time tasks need
|
||||
* to be executed. Each task is executed in sequence, and can be enabled or disabled individually or as a group.
|
||||
*/
|
||||
|
||||
/** @defgroup Group_Scheduler Simple Task Scheduler - LUFA/Scheduler/Scheduler.h
|
||||
*
|
||||
* \section Sec_Dependencies Module Source Dependencies
|
||||
* The following files must be built with any user project that uses this module:
|
||||
* - LUFA/Scheduler/Scheduler.c
|
||||
*
|
||||
* \section Module Description
|
||||
* Simple round-robbin cooperative scheduler for use in basic projects where non real-time tasks need
|
||||
* to be executed. Each task is executed in sequence, and can be enabled or disabled individually or as a group.
|
||||
*
|
||||
* For a task to yield it must return, thus each task should have persistent data marked with the static attribute.
|
||||
*
|
||||
* Usage Example:
|
||||
* \code
|
||||
* #include <LUFA/Scheduler/Scheduler.h>
|
||||
*
|
||||
* TASK(MyTask1);
|
||||
* TASK(MyTask2);
|
||||
*
|
||||
* TASK_LIST
|
||||
* {
|
||||
* { .Task = MyTask1, .TaskStatus = TASK_RUN, .GroupID = 1 },
|
||||
* { .Task = MyTask2, .TaskStatus = TASK_RUN, .GroupID = 1 },
|
||||
* }
|
||||
*
|
||||
* int main(void)
|
||||
* {
|
||||
* Scheduler_Start();
|
||||
* }
|
||||
*
|
||||
* TASK(MyTask1)
|
||||
* {
|
||||
* // Implementation Here
|
||||
* }
|
||||
*
|
||||
* TASK(MyTask2)
|
||||
* {
|
||||
* // Implementation Here
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __SCHEDULER_H__
|
||||
#define __SCHEDULER_H__
|
||||
|
||||
/* Includes: */
|
||||
#include <avr/io.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <util/atomic.h>
|
||||
|
||||
#include "../Common/Common.h"
|
||||
|
||||
/* Enable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Public Interface - May be used in end-application: */
|
||||
/* Macros: */
|
||||
/** Creates a new scheduler task body or prototype. Should be used in the form:
|
||||
* \code
|
||||
* TASK(TaskName); // Prototype
|
||||
*
|
||||
* TASK(TaskName)
|
||||
* {
|
||||
* // Task body
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
#define TASK(name) void name (void)
|
||||
|
||||
/** Defines a task list array, containing one or more task entries of the type TaskEntry_t. Each task list
|
||||
* should be encased in curly braces and ended with a comma.
|
||||
*
|
||||
* Usage Example:
|
||||
* \code
|
||||
* TASK_LIST
|
||||
* {
|
||||
* { .Task = MyTask1, .TaskStatus = TASK_RUN, .GroupID = 1 },
|
||||
* // More task entries here
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
#define TASK_LIST TaskEntry_t Scheduler_TaskList[] =
|
||||
|
||||
/** Constant, giving the maximum delay in scheduler ticks which can be stored in a variable of type
|
||||
* SchedulerDelayCounter_t.
|
||||
*/
|
||||
#define TASK_MAX_DELAY (MAX_DELAYCTR_COUNT - 1)
|
||||
|
||||
/** Task status mode constant, for passing to Scheduler_SetTaskMode() or Scheduler_SetGroupTaskMode(). */
|
||||
#define TASK_RUN true
|
||||
|
||||
/** Task status mode constant, for passing to Scheduler_SetTaskMode() or Scheduler_SetGroupTaskMode(). */
|
||||
#define TASK_STOP false
|
||||
|
||||
/* Pseudo-Function Macros: */
|
||||
#if defined(__DOXYGEN__)
|
||||
/** Starts the scheduler in its infinite loop, executing running tasks. This should be placed at the end
|
||||
* of the user application's main() function, as it can never return to the calling function.
|
||||
*/
|
||||
void Scheduler_Start(void);
|
||||
|
||||
/** Initializes the scheduler so that the scheduler functions can be called before the scheduler itself
|
||||
* is started. This must be executed before any scheduler function calls other than Scheduler_Start(),
|
||||
* and can be omitted if no such functions could be called before the scheduler is started.
|
||||
*/
|
||||
void Scheduler_Init(void);
|
||||
#else
|
||||
#define Scheduler_Start() Scheduler_GoSchedule(TOTAL_TASKS);
|
||||
|
||||
#define Scheduler_Init() Scheduler_InitScheduler(TOTAL_TASKS);
|
||||
#endif
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for a pointer to a scheduler task. */
|
||||
typedef void (*TaskPtr_t)(void);
|
||||
|
||||
/** Type define for a variable which can hold a tick delay value for the scheduler up to the maximum delay
|
||||
* possible.
|
||||
*/
|
||||
typedef uint16_t SchedulerDelayCounter_t;
|
||||
|
||||
/** Structure for holding a single task's information in the scheduler task list. */
|
||||
typedef struct
|
||||
{
|
||||
TaskPtr_t Task; /**< Pointer to the task to execute. */
|
||||
bool TaskStatus; /**< Status of the task (either TASK_RUN or TASK_STOP). */
|
||||
uint8_t GroupID; /**< Group ID of the task so that its status can be changed as a group. */
|
||||
} TaskEntry_t;
|
||||
|
||||
/* Global Variables: */
|
||||
/** Task entry list, containing the scheduler tasks, task statuses and group IDs. Each entry is of type
|
||||
* TaskEntry_t and can be manipulated as desired, although it is preferential that the proper Scheduler
|
||||
* functions should be used instead of direct manipulation.
|
||||
*/
|
||||
extern TaskEntry_t Scheduler_TaskList[];
|
||||
|
||||
/** Contains the total number of tasks in the task list, irrespective of if the task's status is set to
|
||||
* TASK_RUN or TASK_STOP.
|
||||
*
|
||||
* \note This value should be treated as read-only, and never altered in user-code.
|
||||
*/
|
||||
extern volatile uint8_t Scheduler_TotalTasks;
|
||||
|
||||
/** Contains the current scheduler tick count, for use with the delay functions. If the delay functions
|
||||
* are used in the user code, this should be incremented each tick period so that the delays can be
|
||||
* calculated.
|
||||
*/
|
||||
extern volatile SchedulerDelayCounter_t Scheduler_TickCounter;
|
||||
|
||||
/* Inline Functions: */
|
||||
/** Resets the delay counter value to the current tick count. This should be called to reset the period
|
||||
* for a delay in a task which is dependant on the current tick value.
|
||||
*
|
||||
* \param DelayCounter Counter which is storing the starting tick count for a given delay.
|
||||
*/
|
||||
static inline void Scheduler_ResetDelay(SchedulerDelayCounter_t* const DelayCounter)
|
||||
ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline void Scheduler_ResetDelay(SchedulerDelayCounter_t* const DelayCounter)
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
{
|
||||
*DelayCounter = Scheduler_TickCounter;
|
||||
}
|
||||
}
|
||||
|
||||
/* Function Prototypes: */
|
||||
/** Determines if the given tick delay has elapsed, based on the given .
|
||||
*
|
||||
* \param Delay The delay to test for, measured in ticks
|
||||
* \param DelayCounter The counter which is storing the starting tick value for the delay
|
||||
*
|
||||
* \return Boolean true if the delay has elapsed, false otherwise
|
||||
*
|
||||
* Usage Example:
|
||||
* \code
|
||||
* static SchedulerDelayCounter_t DelayCounter = 10000; // Force immediate run on start-up
|
||||
*
|
||||
* // Task runs every 10000 ticks, 10 seconds for this demo
|
||||
* if (Scheduler_HasDelayElapsed(10000, &DelayCounter))
|
||||
* {
|
||||
* // Code to execute after delay interval elapsed here
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
bool Scheduler_HasDelayElapsed(const uint16_t Delay,
|
||||
SchedulerDelayCounter_t* const DelayCounter)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Sets the task mode for a given task.
|
||||
*
|
||||
* \param Task Name of the task whose status is to be changed
|
||||
* \param TaskStatus New task status for the task (TASK_RUN or TASK_STOP)
|
||||
*/
|
||||
void Scheduler_SetTaskMode(const TaskPtr_t Task, const bool TaskStatus);
|
||||
|
||||
/** Sets the task mode for a given task group ID, allowing for an entire group of tasks to have their
|
||||
* statuses changed at once.
|
||||
*
|
||||
* \param GroupID Value of the task group ID whose status is to be changed
|
||||
* \param TaskStatus New task status for tasks in the specified group (TASK_RUN or TASK_STOP)
|
||||
*/
|
||||
void Scheduler_SetGroupTaskMode(const uint8_t GroupID, const bool TaskStatus);
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
/* Macros: */
|
||||
#define TOTAL_TASKS (sizeof(Scheduler_TaskList) / sizeof(TaskEntry_t))
|
||||
#define MAX_DELAYCTR_COUNT 0xFFFF
|
||||
|
||||
/* Inline Functions: */
|
||||
static inline void Scheduler_InitScheduler(const uint8_t TotalTasks) ATTR_ALWAYS_INLINE;
|
||||
static inline void Scheduler_InitScheduler(const uint8_t TotalTasks)
|
||||
{
|
||||
Scheduler_TotalTasks = TotalTasks;
|
||||
}
|
||||
|
||||
static inline void Scheduler_GoSchedule(const uint8_t TotalTasks) ATTR_NO_RETURN ATTR_ALWAYS_INLINE;
|
||||
static inline void Scheduler_GoSchedule(const uint8_t TotalTasks)
|
||||
{
|
||||
Scheduler_InitScheduler(TotalTasks);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
TaskEntry_t* CurrTask = &Scheduler_TaskList[0];
|
||||
|
||||
while (CurrTask != &Scheduler_TaskList[TotalTasks])
|
||||
{
|
||||
if (CurrTask->TaskStatus == TASK_RUN)
|
||||
CurrTask->Task();
|
||||
|
||||
CurrTask++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
|
@ -1,31 +0,0 @@
|
|||
/** \file
|
||||
*
|
||||
* This file contains special DoxyGen information for the generation of the main page and other special
|
||||
* documentation pages. It is not a project source file.
|
||||
*/
|
||||
|
||||
/** \page Page_SchedulerOverview LUFA Scheduler Overview
|
||||
*
|
||||
* The LUFA library comes with a small, basic round-robbin scheduler which allows for small "tasks" to be executed
|
||||
* continuously in sequence, and enabled/disabled at runtime. Unlike a conventional, complex RTOS scheduler, the
|
||||
* LUFA scheduler is very simple in design and operation and is essentially a loop conditionally executing a series
|
||||
* of functions.
|
||||
*
|
||||
* Each LUFA scheduler task should be written similar to an ISR; it should execute quickly (so that no one task
|
||||
* hogs the processor, preventing another from running before some sort of timeout is exceeded). Unlike normal RTOS
|
||||
* tasks, each LUFA scheduler task is a regular function, and thus must be designed to be called, and designed to
|
||||
* return to the calling scheduler function repeatedly. Data which must be preserved between task calls should be
|
||||
* declared as global or (preferably) as a static local variable inside the task.
|
||||
*
|
||||
* The scheduler consists of a task list, listing all the tasks which can be executed by the scheduler. Once started,
|
||||
* each task is then called one after another, unless the task is stopped by another running task or interrupt.
|
||||
*
|
||||
*
|
||||
* If desired, the LUFA scheduler <b>does not need to be used</b> in a LUFA powered application. A more conventional
|
||||
* approach to application design can be used, or a proper scheduling RTOS inserted in the place of the LUFA scheduler.
|
||||
* In the case of the former the USB task must be run manually repeatedly to maintain USB communications, and in the
|
||||
* case of the latter a proper RTOS task must be set up to do the same.
|
||||
*
|
||||
*
|
||||
* For more information on the LUFA scheduler, see the Scheduler.h file documentation.
|
||||
*/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue