Commit 33a01847 authored by Dean Camera's avatar Dean Camera
Browse files

Converted device mode low-level demos to schedulerless.

parent 2793c88f
...@@ -36,18 +36,27 @@ ...@@ -36,18 +36,27 @@
#include "AudioInput.h" #include "AudioInput.h"
/* Scheduler Task List */ /** Flag to indicate if the streaming audio alternative interface has been selected by the host. */
TASK_LIST bool StreamingAudioInterfaceSelected = false;
{
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
{ .Task = USB_Audio_Task , .TaskStatus = TASK_STOP },
};
/** Main program entry point. This routine configures the hardware required by the application, then /** Main program entry point. This routine contains the overall program flow, including initial
* starts the scheduler to run the application tasks. * setup of all components and the main program loop.
*/ */
int main(void) int main(void)
{
SetupHardware();
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
for (;;)
{
USB_Audio_Task();
USB_USBTask();
}
}
/** Configures the board hardware and chip peripherals for the demo's functionality. */
void SetupHardware(void)
{ {
/* Disable watchdog if enabled by bootloader/fuses */ /* Disable watchdog if enabled by bootloader/fuses */
MCUSR &= ~(1 << WDRF); MCUSR &= ~(1 << WDRF);
...@@ -60,21 +69,10 @@ int main(void) ...@@ -60,21 +69,10 @@ int main(void)
LEDs_Init(); LEDs_Init();
ADC_Init(ADC_FREE_RUNNING | ADC_PRESCALE_32); ADC_Init(ADC_FREE_RUNNING | ADC_PRESCALE_32);
ADC_SetupChannel(MIC_IN_ADC_CHANNEL); ADC_SetupChannel(MIC_IN_ADC_CHANNEL);
USB_Init();
/* Start the ADC conversion in free running mode */ /* Start the ADC conversion in free running mode */
ADC_StartReading(ADC_REFERENCE_AVCC | ADC_RIGHT_ADJUSTED | MIC_IN_ADC_CHANNEL); ADC_StartReading(ADC_REFERENCE_AVCC | ADC_RIGHT_ADJUSTED | MIC_IN_ADC_CHANNEL);
/* Indicate USB not ready */
UpdateStatus(Status_USBNotReady);
/* Initialize Scheduler so that it can be used */
Scheduler_Init();
/* Initialize USB Subsystem */
USB_Init();
/* Scheduling - routine never returns, so put this last in the main function */
Scheduler_Start();
} }
/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs, and /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs, and
...@@ -82,16 +80,13 @@ int main(void) ...@@ -82,16 +80,13 @@ int main(void)
*/ */
void EVENT_USB_Connect(void) void EVENT_USB_Connect(void)
{ {
/* Start USB management task */
Scheduler_SetTaskMode(USB_USBTask, TASK_RUN);
/* Indicate USB enumerating */ /* Indicate USB enumerating */
UpdateStatus(Status_USBEnumerating); LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
/* Sample reload timer initialization */ /* Sample reload timer initialization */
OCR0A = (F_CPU / AUDIO_SAMPLE_FREQUENCY) - 1; OCR0A = (F_CPU / AUDIO_SAMPLE_FREQUENCY) - 1;
TCCR0A = (1 << WGM01); // CTC mode TCCR0A = (1 << WGM01); // CTC mode
TCCR0B = (1 << CS00); // Fcpu speed 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 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
...@@ -102,12 +97,11 @@ void EVENT_USB_Disconnect(void) ...@@ -102,12 +97,11 @@ void EVENT_USB_Disconnect(void)
/* Stop the sample reload timer */ /* Stop the sample reload timer */
TCCR0B = 0; TCCR0B = 0;
/* Stop running audio and USB management tasks */ /* Indicate streaming audio interface not selected */
Scheduler_SetTaskMode(USB_Audio_Task, TASK_STOP); StreamingAudioInterfaceSelected = false;
Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);
/* Indicate USB not ready */ /* 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 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration
...@@ -121,7 +115,7 @@ void EVENT_USB_ConfigurationChanged(void) ...@@ -121,7 +115,7 @@ void EVENT_USB_ConfigurationChanged(void)
ENDPOINT_BANK_DOUBLE); ENDPOINT_BANK_DOUBLE);
/* Indicate USB connected and ready */ /* Indicate USB connected and ready */
UpdateStatus(Status_USBReady); LEDs_SetAllLEDs(LEDMASK_USB_READY);
} }
/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific
...@@ -140,16 +134,7 @@ void EVENT_USB_UnhandledControlPacket(void) ...@@ -140,16 +134,7 @@ void EVENT_USB_UnhandledControlPacket(void)
Endpoint_ClearSETUP(); Endpoint_ClearSETUP();
/* Check if the host is enabling the audio interface (setting AlternateSetting to 1) */ /* Check if the host is enabling the audio interface (setting AlternateSetting to 1) */
if (USB_ControlRequest.wValue) StreamingAudioInterfaceSelected = ((USB_ControlRequest.wValue) != 0);
{
/* Start audio task */
Scheduler_SetTaskMode(USB_Audio_Task, TASK_RUN);
}
else
{
/* Stop audio task */
Scheduler_SetTaskMode(USB_Audio_Task, TASK_STOP);
}
/* Acknowledge status stage */ /* Acknowledge status stage */
while (!(Endpoint_IsINReady())); while (!(Endpoint_IsINReady()));
...@@ -160,36 +145,13 @@ void EVENT_USB_UnhandledControlPacket(void) ...@@ -160,36 +145,13 @@ void EVENT_USB_UnhandledControlPacket(void)
} }
} }
/** 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 to manage the Audio interface, reading in ADC samples from the microphone, and them to the host. */
TASK(USB_Audio_Task) void USB_Audio_Task(void)
{ {
/* Check to see if the streaming interface is selected, if not the host is not receiving audio */
if (!(StreamingAudioInterfaceSelected))
return;
/* Select the audio stream endpoint */ /* Select the audio stream endpoint */
Endpoint_SelectEndpoint(AUDIO_STREAM_EPNUM); Endpoint_SelectEndpoint(AUDIO_STREAM_EPNUM);
......
...@@ -43,11 +43,10 @@ ...@@ -43,11 +43,10 @@
#include "Descriptors.h" #include "Descriptors.h"
#include <LUFA/Version.h> // Library Version Information #include <LUFA/Version.h>
#include <LUFA/Drivers/USB/USB.h> // USB Functionality #include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver #include <LUFA/Drivers/Board/LEDs.h>
#include <LUFA/Drivers/Peripheral/ADC.h> // ADC driver #include <LUFA/Drivers/Peripheral/ADC.h>
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
/* Macros: */ /* Macros: */
/** ADC channel number for the microphone input. */ /** ADC channel number for the microphone input. */
...@@ -59,24 +58,25 @@ ...@@ -59,24 +58,25 @@
/** Maximum ADC range for the microphone input. */ /** Maximum ADC range for the microphone input. */
#define ADC_MAX_RANGE 0x3FF #define ADC_MAX_RANGE 0x3FF
/* Enums: */ /** LED mask for the library LED driver, to indicate that the USB interface is not ready. */
/** Enum for the possible status codes for passing to the UpdateStatus() function. */ #define LEDMASK_USB_NOTREADY LEDS_LED1
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: */ /** LED mask for the library LED driver, to indicate that the USB interface is enumerating. */
TASK(USB_Audio_Task); #define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3)
/** LED mask for the library LED driver, to indicate that the USB interface is ready. */
#define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4)
/** LED mask for the library LED driver, to indicate that an error has occurred in the USB interface. */
#define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3)
/* Function Prototypes: */ /* Function Prototypes: */
void SetupHardware(void);
void USB_Audio_Task(void);
void EVENT_USB_Connect(void); void EVENT_USB_Connect(void);
void EVENT_USB_Disconnect(void); void EVENT_USB_Disconnect(void);
void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_ConfigurationChanged(void);
void EVENT_USB_UnhandledControlPacket(void); void EVENT_USB_UnhandledControlPacket(void);
void UpdateStatus(uint8_t CurrentStatus);
#endif #endif
...@@ -119,13 +119,12 @@ OBJDIR = . ...@@ -119,13 +119,12 @@ OBJDIR = .
# Path to the LUFA library # Path to the LUFA library
LUFA_PATH = ../../.. LUFA_PATH = ../../../..
# List C source files here. (C dependencies are automatically generated.) # List C source files here. (C dependencies are automatically generated.)
SRC = $(TARGET).c \ SRC = $(TARGET).c \
Descriptors.c \ Descriptors.c \
$(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c \
...@@ -136,7 +135,6 @@ SRC = $(TARGET).c \ ...@@ -136,7 +135,6 @@ SRC = $(TARGET).c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c \
$(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c \
# List C++ source files here. (C dependencies are automatically generated.) # List C++ source files here. (C dependencies are automatically generated.)
......
...@@ -36,18 +36,27 @@ ...@@ -36,18 +36,27 @@
#include "AudioOutput.h" #include "AudioOutput.h"
/* Scheduler Task List */ /** Flag to indicate if the streaming audio alternative interface has been selected by the host. */
TASK_LIST bool StreamingAudioInterfaceSelected = false;
{
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
{ .Task = USB_Audio_Task , .TaskStatus = TASK_STOP },
};
/** Main program entry point. This routine configures the hardware required by the application, then /** Main program entry point. This routine contains the overall program flow, including initial
* starts the scheduler to run the application tasks. * setup of all components and the main program loop.
*/ */
int main(void) int main(void)
{
SetupHardware();
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
for (;;)
{
USB_Audio_Task();
USB_USBTask();
}
}
/** Configures the board hardware and chip peripherals for the demo's functionality. */
void SetupHardware(void)
{ {
/* Disable watchdog if enabled by bootloader/fuses */ /* Disable watchdog if enabled by bootloader/fuses */
MCUSR &= ~(1 << WDRF); MCUSR &= ~(1 << WDRF);
...@@ -55,21 +64,10 @@ int main(void) ...@@ -55,21 +64,10 @@ int main(void)
/* Disable clock division */ /* Disable clock division */
clock_prescale_set(clock_div_1); clock_prescale_set(clock_div_1);
/* Hardware Initialization */ /* Hardware Initialization */
LEDs_Init(); LEDs_Init();
/* Indicate USB not ready */
UpdateStatus(Status_USBNotReady);
/* Initialize Scheduler so that it can be used */
Scheduler_Init();
/* Initialize USB Subsystem */
USB_Init(); USB_Init();
/* Scheduling - routine never returns, so put this last in the main function */
Scheduler_Start();
} }
/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs, and /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs, and
...@@ -77,11 +75,8 @@ int main(void) ...@@ -77,11 +75,8 @@ int main(void)
*/ */
void EVENT_USB_Connect(void) void EVENT_USB_Connect(void)
{ {
/* Start USB management task */
Scheduler_SetTaskMode(USB_USBTask, TASK_RUN);
/* Indicate USB enumerating */ /* Indicate USB enumerating */
UpdateStatus(Status_USBEnumerating); LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
/* Sample reload timer initialization */ /* Sample reload timer initialization */
OCR0A = (F_CPU / AUDIO_SAMPLE_FREQUENCY) - 1; OCR0A = (F_CPU / AUDIO_SAMPLE_FREQUENCY) - 1;
...@@ -129,12 +124,11 @@ void EVENT_USB_Disconnect(void) ...@@ -129,12 +124,11 @@ void EVENT_USB_Disconnect(void)
PORTC = 0x00; PORTC = 0x00;
#endif #endif
/* Stop running audio and USB management tasks */ /* Indicate streaming audio interface not selected */
Scheduler_SetTaskMode(USB_Audio_Task, TASK_STOP); StreamingAudioInterfaceSelected = false;
Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);
/* Indicate USB not ready */ /* 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 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration
...@@ -148,7 +142,7 @@ void EVENT_USB_ConfigurationChanged(void) ...@@ -148,7 +142,7 @@ void EVENT_USB_ConfigurationChanged(void)
ENDPOINT_BANK_DOUBLE); ENDPOINT_BANK_DOUBLE);
/* Indicate USB connected and ready */ /* Indicate USB connected and ready */
UpdateStatus(Status_USBReady); LEDs_SetAllLEDs(LEDMASK_USB_READY);
} }
/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific
...@@ -167,16 +161,7 @@ void EVENT_USB_UnhandledControlPacket(void) ...@@ -167,16 +161,7 @@ void EVENT_USB_UnhandledControlPacket(void)
Endpoint_ClearSETUP(); Endpoint_ClearSETUP();
/* Check if the host is enabling the audio interface (setting AlternateSetting to 1) */ /* Check if the host is enabling the audio interface (setting AlternateSetting to 1) */
if (USB_ControlRequest.wValue) StreamingAudioInterfaceSelected = ((USB_ControlRequest.wValue) != 0);
{
/* Start audio task */
Scheduler_SetTaskMode(USB_Audio_Task, TASK_RUN);
}
else
{
/* Stop audio task */
Scheduler_SetTaskMode(USB_Audio_Task, TASK_STOP);
}
/* Acknowledge status stage */ /* Acknowledge status stage */
while (!(Endpoint_IsINReady())); while (!(Endpoint_IsINReady()));
...@@ -187,38 +172,15 @@ void EVENT_USB_UnhandledControlPacket(void) ...@@ -187,38 +172,15 @@ void EVENT_USB_UnhandledControlPacket(void)
} }
} }
/** 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 /** Task to manage the Audio interface, reading in audio samples from the host, and outputting them to the speakers/LEDs as
* desired. * desired.
*/ */
TASK(USB_Audio_Task) void USB_Audio_Task(void)
{ {
/* Check to see if the streaming interface is selected, if not the host is not receiving audio */
if (!(StreamingAudioInterfaceSelected))
return;
/* Select the audio stream endpoint */ /* Select the audio stream endpoint */
Endpoint_SelectEndpoint(AUDIO_STREAM_EPNUM); Endpoint_SelectEndpoint(AUDIO_STREAM_EPNUM);
......
...@@ -43,10 +43,9 @@ ...@@ -43,10 +43,9 @@
#include "Descriptors.h" #include "Descriptors.h"
#include <LUFA/Version.h> // Library Version Information #include <LUFA/Version.h>
#include <LUFA/Drivers/USB/USB.h> // USB Functionality #include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver #include <LUFA/Drivers/Board/LEDs.h>
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
/* Macros: */ /* Macros: */
#if defined(USB_FULL_CONTROLLER) || defined(USB_MODIFIED_FULL_CONTROLLER) #if defined(USB_FULL_CONTROLLER) || defined(USB_MODIFIED_FULL_CONTROLLER)
...@@ -96,24 +95,25 @@ ...@@ -96,24 +95,25 @@
#define CSx0 CS10 #define CSx0 CS10
#endif #endif
/* Enums: */ /** LED mask for the library LED driver, to indicate that the USB interface is not ready. */
/** Enum for the possible status codes for passing to the UpdateStatus() function. */ #define LEDMASK_USB_NOTREADY LEDS_LED1
enum AudioOutput_StatusCodes_t
{ /** LED mask for the library LED driver, to indicate that the USB interface is enumerating. */
Status_USBNotReady = 0, /**< USB is not ready (disconnected from a USB host) */ #define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3)
Status_USBEnumerating = 1, /**< USB interface is enumerating */
Status_USBReady = 2, /**< USB interface is connected and ready */ /** LED mask for the library LED driver, to indicate that the USB interface is ready. */
}; #define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4)
/* Task Definitions: */ /** LED mask for the library LED driver, to indicate that an error has occurred in the USB interface. */
TASK(USB_Audio_Task); #define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3)
/* Function Prototypes: */ /* Function Prototypes: */
void SetupHardware(void);
void USB_Audio_Task(void);
void EVENT_USB_Connect(void); void EVENT_USB_Connect(void);
void EVENT_USB_Disconnect(void); void EVENT_USB_Disconnect(void);
void EVENT_USB_ConfigurationChanged(void); void EVENT_USB_ConfigurationChanged(void);
void EVENT_USB_UnhandledControlPacket(void); void EVENT_USB_UnhandledControlPacket(void);
void UpdateStatus(uint8_t CurrentStatus);
#endif #endif
...@@ -119,13 +119,12 @@ OBJDIR = . ...@@ -119,13 +119,12 @@ OBJDIR = .
# Path to the LUFA library # Path to the LUFA library
LUFA_PATH = ../../.. LUFA_PATH = ../../../..
# List C source files here. (C dependencies are automatically generated.) # List C source files here. (C dependencies are automatically generated.)
SRC = $(TARGET).c \ SRC = $(TARGET).c \
Descriptors.c \ Descriptors.c \
$(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c \
...@@ -136,7 +135,6 @@ SRC = $(TARGET).c \ ...@@ -136,7 +135,6 @@ SRC = $(TARGET).c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c \ $(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c \
$(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c \
# List C++ source files here. (C dependencies are automatically generated.) # List C++ source files here. (C dependencies are automatically generated.)
......
...@@ -36,13 +36,6 @@ ...@@ -36,13 +36,6 @@
#include "CDC.h" #include "CDC.h"
/* Scheduler Task List */
TASK_LIST
{
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP },
{ .Task = CDC_Task , .TaskStatus = TASK_STOP },