Add extra LUFA TAR archive export exclusions.
[pub/USBasp.git] / Demos / Device / LowLevel / AudioOutput / AudioOutput.c
index f2a8867..813108a 100644 (file)
@@ -1,21 +1,21 @@
 /*
              LUFA Library
 /*
              LUFA Library
-     Copyright (C) Dean Camera, 2010.
-              
+     Copyright (C) Dean Camera, 2012.
+
   dean [at] fourwalledcubicle [dot] com
   dean [at] fourwalledcubicle [dot] com
-      www.fourwalledcubicle.com
+           www.lufa-lib.org
 */
 
 /*
 */
 
 /*
-  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+  Copyright 2012  Dean Camera (dean [at] fourwalledcubicle [dot] com)
 
 
-  Permission to use, copy, modify, distribute, and sell this 
+  Permission to use, copy, modify, distribute, and sell this
   software and its documentation for any purpose is hereby granted
   software and its documentation for any purpose is hereby granted
-  without fee, provided that the above copyright notice appear in 
+  without fee, provided that the above copyright notice appear in
   all copies and that both that the copyright notice and this
   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 
+  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 without specific, written prior permission.
 
   The author disclaim all warranties with regard to this
  *  Main source file for the AudioOutput demo. This file contains the main tasks of the demo and
  *  is responsible for the initial application hardware configuration.
  */
  *  Main source file for the AudioOutput demo. This file contains the main tasks of the demo and
  *  is responsible for the initial application hardware configuration.
  */
+
 #include "AudioOutput.h"
 
 /** Flag to indicate if the streaming audio alternative interface has been selected by the host. */
 #include "AudioOutput.h"
 
 /** Flag to indicate if the streaming audio alternative interface has been selected by the host. */
-bool StreamingAudioInterfaceSelected = false;
+static bool StreamingAudioInterfaceSelected = false;
+
+/** Current audio sampling frequency of the streaming audio endpoint. */
+static uint32_t CurrentAudioSampleFrequency = 48000;
+
 
 /** Main program entry point. This routine contains the overall program flow, including initial
  *  setup of all components and the main program loop.
 
 /** Main program entry point. This routine contains the overall program flow, including initial
  *  setup of all components and the main program loop.
@@ -48,10 +52,9 @@ int main(void)
 
        LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
        sei();
 
        LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
        sei();
-       
+
        for (;;)
        {
        for (;;)
        {
-               USB_Audio_Task();
                USB_USBTask();
        }
 }
                USB_USBTask();
        }
 }
@@ -65,7 +68,7 @@ void SetupHardware(void)
 
        /* Disable clock division */
        clock_prescale_set(clock_div_1);
 
        /* Disable clock division */
        clock_prescale_set(clock_div_1);
-       
+
        /* Hardware Initialization */
        LEDs_Init();
        USB_Init();
        /* Hardware Initialization */
        LEDs_Init();
        USB_Init();
@@ -78,29 +81,30 @@ void EVENT_USB_Device_Connect(void)
 {
        /* Indicate USB enumerating */
        LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
 {
        /* Indicate USB enumerating */
        LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
-       
+
        /* Sample reload timer initialization */
        /* Sample reload timer initialization */
-       OCR0A   = (F_CPU / 8 / AUDIO_SAMPLE_FREQUENCY) - 1;
-       TCCR0A  = (1 << WGM01);  // CTC mode
-       TCCR0B  = (1 << CS01);   // Fcpu/8 speed
-                       
-#if defined(AUDIO_OUT_MONO)
+       TIMSK0 = (1 << OCIE0A);
+       OCR0A  = ((F_CPU / 8 / CurrentAudioSampleFrequency) - 1);
+       TCCR0A = (1 << WGM01);  // CTC mode
+       TCCR0B = (1 << CS01);   // Fcpu/8 speed
+
+       #if defined(AUDIO_OUT_MONO)
        /* Set speaker as output */
        /* Set speaker as output */
-       DDRC   |= (1 << 6);
-#elif defined(AUDIO_OUT_STEREO)
+       DDRC  |= (1 << 6);
+       #elif defined(AUDIO_OUT_STEREO)
        /* Set speakers as outputs */
        /* Set speakers as outputs */
-       DDRC   |= ((1 << 6) | (1 << 5));
-#elif defined(AUDIO_OUT_PORTC)
+       DDRC  |= ((1 << 6) | (1 << 5));
+       #elif defined(AUDIO_OUT_PORTC)
        /* Set PORTC as outputs */
        /* Set PORTC as outputs */
-       DDRC   |= 0xFF;
-#endif
+       DDRC  |= 0xFF;
+       #endif
 
 
-#if (defined(AUDIO_OUT_MONO) || defined(AUDIO_OUT_STEREO))
+       #if (defined(AUDIO_OUT_MONO) || defined(AUDIO_OUT_STEREO))
        /* PWM speaker timer initialization */
        /* PWM speaker timer initialization */
-       TCCR3A  = ((1 << WGM30) | (1 << COM3A1) | (1 << COM3A0)
-                               | (1 << COM3B1) | (1 << COM3B0)); // Set on match, clear on TOP
-       TCCR3B  = ((1 << WGM32) | (1 << CS30));  // Fast 8-Bit PWM, F_CPU speed
-#endif 
+       TCCR3A = ((1 << WGM30) | (1 << COM3A1) | (1 << COM3A0)
+                              | (1 << COM3B1) | (1 << COM3B0)); // Set on match, clear on TOP
+       TCCR3B = ((1 << WGM32) | (1 << CS30));  // Fast 8-Bit PWM, F_CPU speed
+       #endif
 }
 
 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
 }
 
 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
@@ -110,20 +114,20 @@ void EVENT_USB_Device_Disconnect(void)
 {
        /* Stop the timers */
        TCCR0B = 0;
 {
        /* Stop the timers */
        TCCR0B = 0;
-#if (defined(AUDIO_OUT_MONO) || defined(AUDIO_OUT_STEREO))
+       #if (defined(AUDIO_OUT_MONO) || defined(AUDIO_OUT_STEREO))
        TCCR3B = 0;
        TCCR3B = 0;
-#endif         
+       #endif
 
 
-#if defined(AUDIO_OUT_MONO)
+       #if defined(AUDIO_OUT_MONO)
        /* Set speaker as input to reduce current draw */
        /* Set speaker as input to reduce current draw */
-       DDRC   &= ~(1 << 6);
-#elif defined(AUDIO_OUT_STEREO)
+       DDRC  &= ~(1 << 6);
+       #elif defined(AUDIO_OUT_STEREO)
        /* Set speakers as inputs to reduce current draw */
        /* Set speakers as inputs to reduce current draw */
-       DDRC   &= ~((1 << 6) | (1 << 5));
-#elif defined(AUDIO_OUT_PORTC)
+       DDRC  &= ~((1 << 6) | (1 << 5));
+       #elif defined(AUDIO_OUT_PORTC)
        /* Set PORTC low */
        /* Set PORTC low */
-       PORTC  = 0x00;
-#endif
+       PORTC = 0x00;
+       #endif
 
        /* Indicate streaming audio interface not selected */
        StreamingAudioInterfaceSelected = false;
 
        /* Indicate streaming audio interface not selected */
        StreamingAudioInterfaceSelected = false;
@@ -137,23 +141,21 @@ void EVENT_USB_Device_Disconnect(void)
  */
 void EVENT_USB_Device_ConfigurationChanged(void)
 {
  */
 void EVENT_USB_Device_ConfigurationChanged(void)
 {
-       /* Indicate USB connected and ready */
-       LEDs_SetAllLEDs(LEDMASK_USB_READY);
+       bool ConfigSuccess = true;
 
 
-       /* Setup audio stream endpoint */
-       if (!(Endpoint_ConfigureEndpoint(AUDIO_STREAM_EPNUM, EP_TYPE_ISOCHRONOUS,
-                                            ENDPOINT_DIR_OUT, AUDIO_STREAM_EPSIZE,
-                                        ENDPOINT_BANK_DOUBLE)))
-       {
-               LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
-       }
+       /* Setup Audio Stream Endpoint */
+       ConfigSuccess &= Endpoint_ConfigureEndpoint(AUDIO_STREAM_EPNUM, EP_TYPE_ISOCHRONOUS, ENDPOINT_DIR_OUT,
+                                                   AUDIO_STREAM_EPSIZE, ENDPOINT_BANK_DOUBLE);
+
+       /* Indicate endpoint configuration success or failure */
+       LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
 }
 
 }
 
-/** Event handler for the USB_UnhandledControlRequest 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.
+/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
+ *  the device from the USB host before passing along unhandled control requests to the library for processing
+ *  internally.
  */
  */
-void EVENT_USB_Device_UnhandledControlRequest(void)
+void EVENT_USB_Device_ControlRequest(void)
 {
        /* Process General and Audio specific control requests */
        switch (USB_ControlRequest.bRequest)
 {
        /* Process General and Audio specific control requests */
        switch (USB_ControlRequest.bRequest)
@@ -163,45 +165,93 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                        if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE))
                        {
                                Endpoint_ClearSETUP();
                        if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE))
                        {
                                Endpoint_ClearSETUP();
-                               
+                               Endpoint_ClearStatusStage();
+
                                /* Check if the host is enabling the audio interface (setting AlternateSetting to 1) */
                                StreamingAudioInterfaceSelected = ((USB_ControlRequest.wValue) != 0);
                                /* Check if the host is enabling the audio interface (setting AlternateSetting to 1) */
                                StreamingAudioInterfaceSelected = ((USB_ControlRequest.wValue) != 0);
-                               
+                       }
+
+                       break;
+               case AUDIO_REQ_GetStatus:
+                       /* Get Status request can be directed at either the interface or endpoint, neither is currently used
+                        * according to the latest USB Audio 1.0 standard, but must be ACKed with no data when requested */
+                       if ((USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) ||
+                           (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_ENDPOINT)))
+                       {
+                               Endpoint_ClearSETUP();
                                Endpoint_ClearStatusStage();
                        }
 
                        break;
                                Endpoint_ClearStatusStage();
                        }
 
                        break;
+               case AUDIO_REQ_SetCurrent:
+                       if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_ENDPOINT))
+                       {
+                               /* Extract out the relevant request information to get the target Endpoint address and control being set */
+                               uint8_t EndpointAddress = (uint8_t)USB_ControlRequest.wIndex;
+                               uint8_t EndpointControl = (USB_ControlRequest.wValue >> 8);
+
+                               /* Only handle SET CURRENT requests to the audio endpoint's sample frequency property */
+                               if ((EndpointAddress == (ENDPOINT_DIR_OUT | AUDIO_STREAM_EPNUM)) && (EndpointControl == AUDIO_EPCONTROL_SamplingFreq))
+                               {
+                                       uint8_t SampleRate[3];
+
+                                       Endpoint_ClearSETUP();
+                                       Endpoint_Read_Control_Stream_LE(SampleRate, sizeof(SampleRate));
+                                       Endpoint_ClearOUT();
+
+                                       /* Set the new sampling frequency to the value given by the host */
+                                       CurrentAudioSampleFrequency = (((uint32_t)SampleRate[2] << 16) | ((uint32_t)SampleRate[1] << 8) | (uint32_t)SampleRate[0]);
+
+                                       /* Adjust sample reload timer to the new frequency */
+                                       OCR0A = ((F_CPU / 8 / CurrentAudioSampleFrequency) - 1);
+                               }
+                       }
+
+                       break;
+               case AUDIO_REQ_GetCurrent:
+                       if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_ENDPOINT))
+                       {
+                               /* Extract out the relevant request information to get the target Endpoint address and control being retrieved */
+                               uint8_t EndpointAddress = (uint8_t)USB_ControlRequest.wIndex;
+                               uint8_t EndpointControl = (USB_ControlRequest.wValue >> 8);
+
+                               /* Only handle GET CURRENT requests to the audio endpoint's sample frequency property */
+                               if ((EndpointAddress == (ENDPOINT_DIR_OUT | AUDIO_STREAM_EPNUM)) && (EndpointControl == AUDIO_EPCONTROL_SamplingFreq))
+                               {
+                                       uint8_t SampleRate[3];
+
+                                       /* Convert the sampling rate value into the 24-bit format the host expects for the property */
+                                       SampleRate[2] = (CurrentAudioSampleFrequency >> 16);
+                                       SampleRate[1] = (CurrentAudioSampleFrequency >> 8);
+                                       SampleRate[0] = (CurrentAudioSampleFrequency &  0xFF);
+
+                                       Endpoint_ClearSETUP();
+                                       Endpoint_Write_Control_Stream_LE(SampleRate, sizeof(SampleRate));
+                                       Endpoint_ClearOUT();
+                               }
+                       }
+
+                       break;
        }
 }
 
        }
 }
 
-/** Task to manage the Audio interface, reading in audio samples from the host, and outputting them to the speakers/LEDs as
- *  desired.
- */
-void USB_Audio_Task(void)
+/** ISR to handle the reloading of the PWM timer with the next sample. */
+ISR(TIMER0_COMPA_vect, ISR_BLOCK)
 {
 {
-       /* Device must be connected and configured for the task to run */
-       if (USB_DeviceState != DEVICE_STATE_Configured)
-         return;
-
-       /* Check to see if the streaming interface is selected, if not the host is not receiving audio */
-       if (!(StreamingAudioInterfaceSelected))
-         return;       
+       uint8_t PrevEndpoint = Endpoint_GetCurrentEndpoint();
 
        /* Select the audio stream endpoint */
        Endpoint_SelectEndpoint(AUDIO_STREAM_EPNUM);
 
        /* Select the audio stream endpoint */
        Endpoint_SelectEndpoint(AUDIO_STREAM_EPNUM);
-       
-       /* Check if the current endpoint can be read from (contains a packet) and that the next sample should be read */
-       if (Endpoint_IsOUTReceived() && (TIFR0 & (1 << OCF0A)))
-       {
-               /* Clear the sample reload timer */
-               TIFR0 |= (1 << OCF0A);
 
 
+       /* Check if the current endpoint can be read from (contains a packet) and the host is sending data */
+       if (Endpoint_IsOUTReceived() && StreamingAudioInterfaceSelected)
+       {
                /* Retrieve the signed 16-bit left and right audio samples, convert to 8-bit */
                /* Retrieve the signed 16-bit left and right audio samples, convert to 8-bit */
-               int8_t  LeftSample_8Bit   = ((int16_t)Endpoint_Read_Word_LE() >> 8);
-               int8_t  RightSample_8Bit  = ((int16_t)Endpoint_Read_Word_LE() >> 8);
+               int8_t LeftSample_8Bit   = ((int16_t)Endpoint_Read_16_LE() >> 8);
+               int8_t RightSample_8Bit  = ((int16_t)Endpoint_Read_16_LE() >> 8);
 
                /* Mix the two channels together to produce a mono, 8-bit sample */
 
                /* Mix the two channels together to produce a mono, 8-bit sample */
-               int8_t  MixedSample_8Bit  = (((int16_t)LeftSample_8Bit + (int16_t)RightSample_8Bit) >> 1);
+               int8_t MixedSample_8Bit  = (((int16_t)LeftSample_8Bit + (int16_t)RightSample_8Bit) >> 1);
 
                /* Check to see if the bank is now empty */
                if (!(Endpoint_IsReadWriteAllowed()))
 
                /* Check to see if the bank is now empty */
                if (!(Endpoint_IsReadWriteAllowed()))
@@ -210,17 +260,17 @@ void USB_Audio_Task(void)
                        Endpoint_ClearOUT();
                }
 
                        Endpoint_ClearOUT();
                }
 
-#if defined(AUDIO_OUT_MONO)
+               #if defined(AUDIO_OUT_MONO)
                /* Load the sample into the PWM timer channel */
                OCR3A = (MixedSample_8Bit ^ (1 << 7));
                /* Load the sample into the PWM timer channel */
                OCR3A = (MixedSample_8Bit ^ (1 << 7));
-#elif defined(AUDIO_OUT_STEREO)
+               #elif defined(AUDIO_OUT_STEREO)
                /* Load the dual 8-bit samples into the PWM timer channels */
                OCR3A = (LeftSample_8Bit  ^ (1 << 7));
                OCR3B = (RightSample_8Bit ^ (1 << 7));
                /* Load the dual 8-bit samples into the PWM timer channels */
                OCR3A = (LeftSample_8Bit  ^ (1 << 7));
                OCR3B = (RightSample_8Bit ^ (1 << 7));
-#elif defined(AUDIO_OUT_PORTC)
+               #elif defined(AUDIO_OUT_PORTC)
                /* Load the 8-bit mixed sample into PORTC */
                PORTC = MixedSample_8Bit;
                /* Load the 8-bit mixed sample into PORTC */
                PORTC = MixedSample_8Bit;
-#endif
+               #endif
 
                uint8_t LEDMask = LEDS_NO_LEDS;
 
 
                uint8_t LEDMask = LEDS_NO_LEDS;
 
@@ -236,4 +286,7 @@ void USB_Audio_Task(void)
 
                LEDs_SetAllLEDs(LEDMask);
        }
 
                LEDs_SetAllLEDs(LEDMask);
        }
+
+       Endpoint_SelectEndpoint(PrevEndpoint);
 }
 }
+