aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2014-03-14 07:38:02 +1000
committerinmarket <andrewh@inmarket.com.au>2014-03-14 07:38:02 +1000
commit6f54bde79c553301a35535a0a71a4a09b181abfa (patch)
tree1408ad80459cd09da47960b4905d50195916639d /src
parent6d372f13528f44919ec193d03248d55a53484968 (diff)
parentea5a1b849df6e5085a92957ad387f9e653674415 (diff)
downloaduGFX-6f54bde79c553301a35535a0a71a4a09b181abfa.tar.gz
uGFX-6f54bde79c553301a35535a0a71a4a09b181abfa.tar.bz2
uGFX-6f54bde79c553301a35535a0a71a4a09b181abfa.zip
Merge branch 'master' into freertos
Diffstat (limited to 'src')
-rw-r--r--src/gaudin/driver.h102
-rw-r--r--src/gaudin/gaudin.c158
-rw-r--r--src/gaudin/sys_defs.h174
-rw-r--r--src/gaudin/sys_make.mk1
-rw-r--r--src/gaudin/sys_options.h32
-rw-r--r--src/gaudin/sys_rules.h30
-rw-r--r--src/gaudio/driver_play.h126
-rw-r--r--src/gaudio/driver_record.h108
-rw-r--r--src/gaudio/gaudio.c318
-rw-r--r--src/gaudio/sys_defs.h340
-rw-r--r--src/gaudio/sys_make.mk1
-rw-r--r--src/gaudio/sys_options.h44
-rw-r--r--src/gaudio/sys_rules.h54
-rw-r--r--src/gaudout/gaudout.c33
-rw-r--r--src/gaudout/sys_defs.h45
-rw-r--r--src/gaudout/sys_make.mk1
-rw-r--r--src/gaudout/sys_options.h32
-rw-r--r--src/gaudout/sys_rules.h23
-rw-r--r--src/gevent/sys_defs.h3
-rw-r--r--src/gfx.c22
-rw-r--r--src/ginput/mouse.c2
-rw-r--r--src/gmisc/sys_defs.h10
-rw-r--r--src/gos/chibios.c7
-rw-r--r--src/gos/chibios.h1
-rw-r--r--src/gos/linux.h1
-rw-r--r--src/gos/osx.h1
-rw-r--r--src/gos/raw32.c7
-rw-r--r--src/gos/raw32.h1
-rw-r--r--src/gos/sys_defs.h13
-rw-r--r--src/gos/win32.h1
-rw-r--r--src/gqueue/gqueue.c137
-rw-r--r--src/gqueue/sys_defs.h37
-rw-r--r--src/gwin/console.c189
-rw-r--r--src/gwin/console.h6
-rw-r--r--src/gwin/sys_options.h19
35 files changed, 1364 insertions, 715 deletions
diff --git a/src/gaudin/driver.h b/src/gaudin/driver.h
deleted file mode 100644
index bd04858a..00000000
--- a/src/gaudin/driver.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- * http://ugfx.org/license.html
- */
-
-/**
- * @file src/gaudin/driver.h
- * @brief GAUDIN - Audio Input driver header file.
- *
- * @defgroup Driver Driver
- * @ingroup GAUDIN
- * @{
- */
-
-#ifndef _GAUDIN_LLD_H
-#define _GAUDIN_LLD_H
-
-#include "gfx.h"
-
-#if GFX_USE_GAUDIN || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Type definitions */
-/*===========================================================================*/
-
-/**
- * @brief The structure passed to start a audio conversion
- * @note We use the structure instead of parameters purely to save
- * interrupt stack space which is very limited in some platforms.
- * @{
- */
-typedef struct gaudin_params_t {
- uint16_t channel;
- uint32_t frequency;
- audin_sample_t *buffer;
- size_t bufcount;
- size_t samplesPerEvent;
- } gaudin_params;
-/** @} */
-
-/**
- * @brief These routines are the callbacks that the driver uses.
- * @details Defined in the high level GAUDIN code.
- *
- * @iclass
- * @notapi
- *
- * @{
- */
-
-/**
- * @param[in] buffer The buffer
- * @param[in] n The amount of samples
- * */
-extern void GAUDIN_ISR_CompleteI(audin_sample_t *buffer, size_t n);
-
-extern void GAUDIN_ISR_ErrorI(void);
-/**
- * @}
- */
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief Initialise the driver
- *
- * @param[in] paud Initialisation parameters
- *
- * @api
- */
-void gaudin_lld_init(const gaudin_params *paud);
-
-/**
- * @brief Start the audio input sampling
- *
- * @api
- */
-void gadc_lld_start(void);
-
-/**
- * @brief Stop the audio input sampling
- *
- * @api
- */
-void gadc_lld_stop(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GADC */
-
-#endif /* _GADC_LLD_H */
-/** @} */
diff --git a/src/gaudin/gaudin.c b/src/gaudin/gaudin.c
deleted file mode 100644
index c9ed1c7f..00000000
--- a/src/gaudin/gaudin.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- * http://ugfx.org/license.html
- */
-
-/**
- * @file src/gaudin/gaudin.c
- * @brief GAUDIN sub-system code.
- *
- * @addtogroup GAUDIN
- * @{
- */
-#include "gfx.h"
-
-#if GFX_USE_GAUDIN
-
-/* Include the driver defines */
-#include "src/gaudin/driver.h"
-
-static gaudin_params aud;
-static gfxSem *paudSem;
-static GEventAudioIn *paudEvent;
-static audin_sample_t *lastbuffer;
-static size_t lastcount;
-static uint16_t audFlags;
- #define AUDFLG_RUNNING 0x0001
- #define AUDFLG_USE_EVENTS 0x0002
-
-#if GFX_USE_GEVENT
- static GTimer AudGTimer;
-
- static void AudGTimerCallback(void *param) {
- (void) param;
- GSourceListener *psl;
- GEventADC *pe;
-
- psl = 0;
- while ((psl = geventGetSourceListener((GSourceHandle)(&aud), psl))) {
- if (!(pe = (GEventAudioIn *)geventGetEventBuffer(psl))) {
- // This listener is missing - save this.
- psl->srcflags |= GADC_AUDIO_IN_LOSTEVENT;
- continue;
- }
-
- pe->type = GEVENT_AUDIO_IN;
- pe->channel = aud.channel;
- pe->count = lastcount;
- pe->buffer = lastbuffer;
- pe->flags = psl->srcflags;
- psl->srcflags = 0;
- geventSendEvent(psl);
- }
- }
-#endif
-
-void GAUDIN_ISR_CompleteI(audin_sample_t *buffer, size_t n) {
- /* Save the details */
- lastcount = n;
- lastbuffer = buffer;
-
- /* Signal the user with the data */
- if (paudEvent) {
- #if GFX_USE_GEVENT
- paudEvent->type = GEVENT_AUDIO_IN;
- #endif
- paudEvent->channel = aud.channel;
- paudEvent->count = lastcount;
- paudEvent->buffer = lastbuffer;
- paudEvent->flags = 0;
- }
-
- /* Our two signalling mechanisms */
- if (paudSem)
- gfxSemSignalI(paudSem);
-
- #if GFX_USE_GEVENT
- if (audFlags & AUDFLG_USE_EVENTS)
- gtimerJabI(&AudGTimer);
- #endif
-}
-
-void GAUDIN_ISR_ErrorI(void) {
- /* Ignore any errors for now */
-}
-
-void _gaudinInit(void)
-{
- #if GFX_USE_GEVENT
- gtimerInit(&AudGTimer);
- #endif
-}
-
-void _gaudinDeinit(void)
-{
- // Commented stuff still ToDo
- #if GFX_USE_GEVENT
- gtimerDeinit(&AudGTimer);
- #endif
-}
-
-bool_t gaudinInit(uint16_t channel, uint32_t frequency, audin_sample_t *buffer, size_t bufcount, size_t samplesPerEvent) {
- /* Check the channel is valid */
- if (channel >= GAUDIN_NUM_CHANNELS || frequency > GAUDIN_MAX_SAMPLE_FREQUENCY)
- return FALSE;
-
- /* Stop any existing transfers */
- if ((audFlags & AUDFLG_RUNNING))
- gadc_lld_stop();
- audFlags = 0;
-
- /* Initialise everything */
- aud.channel = channel;
- aud.frequency = frequency;
- aud.buffer = buffer;
- aud.bufcount = bufcount;
- aud.samplesPerEvent = samplesPerEvent;
- paudSem = 0;
- paudEvent = 0;
-
- /* Set up the low level driver */
- gaudin_lld_init(&aud);
- return TRUE;
-}
-
-#if GFX_USE_GEVENT
- GSourceHandle gaudinGetSource(void) {
- if (!gtimerIsActive(&AudGTimer))
- gtimerStart(&AudGTimer, AudGTimerCallback, 0, TRUE, TIME_INFINITE);
- audFlags |= AUDFLG_USE_EVENTS;
- return (GSourceHandle)&aud;
- }
-#endif
-
-void gaudinSetBSem(gfxSem *pbsem, GEventAudioIn *pEvent) {
- gfxSystemLock();
- paudSem = pbsem;
- paudEvent = pEvent;
- gfxSystemUnlock();
-}
-
-void gaudinStart(void) {
- if (!(audFlags & AUDFLG_RUNNING)) {
- audFlags |= AUDFLG_RUNNING;
- gadc_lld_start();
- }
-}
-
-void gaudinStop(void) {
- if ((audFlags & AUDFLG_RUNNING)) {
- gadc_lld_stop();
- audFlags &= ~AUDFLG_RUNNING;
- }
-}
-
-#endif /* GFX_USE_GAUDIN */
-/** @} */
diff --git a/src/gaudin/sys_defs.h b/src/gaudin/sys_defs.h
deleted file mode 100644
index 3f06fa6e..00000000
--- a/src/gaudin/sys_defs.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- * http://ugfx.org/license.html
- */
-
-/**
- * @file src/gaudin/sys_defs.h
- *
- * @addtogroup GAUDIN
- *
- * @brief Module to read audio inputs
- *
- * @{
- */
-
-#ifndef _GAUDIN_H
-#define _GAUDIN_H
-
-#include "gfx.h"
-
-#if GFX_USE_GAUDIN || defined(__DOXYGEN__)
-
-/* Include the driver defines */
-#include "gaudin_lld_config.h"
-
-/*===========================================================================*/
-/* Type definitions */
-/*===========================================================================*/
-
-// Event types for GAUDIN
-#define GEVENT_AUDIO_IN (GEVENT_GAUDIN_FIRST+0)
-
-/**
- * @brief The Audio Input event structure.
- * @{
- */
-typedef struct GEventAudioIn_t {
- #if GFX_USE_GEVENT || defined(__DOXYGEN__)
- /**
- * @brief The type of this event (GEVENT_AUDIO_IN)
- */
- GEventType type;
- #endif
- /**
- * @brief The current channel
- */
- uint16_t channel;
- /**
- * @brief The event flags
- */
- uint16_t flags;
- /**
- * @brief The event flag values.
- * @{
- */
- #define GADC_AUDIO_IN_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_IN event was lost */
- /** @} */
- /**
- * @brief The number of audio samples in the buffer
- */
- size_t count;
- /**
- * @brief The buffer containing the audio samples
- */
- audin_sample_t *buffer;
-} GEventAudioIn;
-/** @} */
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief Initialise (but not start) the Audio Input Subsystem.
- * @details Returns FALSE for an invalid channel or other invalid parameter.
- *
- * @param[in] channel The channel to convert. Can be set from 0 to GAUDIN_NUM_CHANNELS - 1.
- * @param[in] frequency The sample frequency
- * @param[in] buffer The static buffer to put the samples into.
- * @param[in] bufcount The total number of conversions that will fit in the buffer.
- * @param[in] samplesPerEvent The number of conversions to do before returning an event.
- *
- * @note Only one channel is active at a time. If an audio input is running it will be stopped.
- * The Event subsystem is disconnected from the audio subsystem and any binary semaphore
- * event is forgotten.
- * @note Some channels may be stereo channels which return twice as much sample data with
- * the left and right channel data interleaved. Other channels may be mono channels.
- * Where stereo channels exist it would be common for the low level driver to also
- * offer the left and right channels separately.
- * @note Due to a bug in Chibi-OS countPerEvent must be even if using the GADC low level audio driver.
- * If bufcount is not evenly divisable by countPerEvent, the remainder must also be even.
- * This requirement may not apply to other GAUDIN drivers.
- * @note The number of samples for stereo devices will be double the number of conversions.
- * Make sure you allocate your buffers large enough. Each channel is then interleaved
- * into the provided buffer. Note 'bufcount' and 'countPerEvent' parameters describe the
- * number of conversions not the number of samples.
- * @note The buffer is circular. When the end of the buffer is reached it will start
- * putting data into the beginning of the buffer again.
- * @note The event listener must process the event (and the data in it) before the
- * next event occurs. If not, the following event will be lost.
- * @note If bufcount is evenly divisable by countPerEvent, then every event will return
- * countPerEvent conversions. If bufcount is not evenly divisable, it will return
- * a block of samples containing less than countPerEvent samples when it reaches the
- * end of the buffer.
- *
- * @return FALSE if invalid channel or parameter
- *
- * @api
- */
-bool_t gaudinInit(uint16_t channel, uint32_t frequency, audin_sample_t *buffer, size_t bufcount, size_t samplesPerEvent);
-
-#if GFX_USE_GEVENT || defined(__DOXYGEN__)
- /**
- * @brief Turn on sending results to the GEVENT sub-system.
- * @details Returns a GSourceHandle to listen for GEVENT_AUDIO_IN events.
- *
- * @note The audio input will not use the GEVENT system unless this is
- * called first. This saves processing time if the application does
- * not want to use the GEVENT sub-system for audio input.
- * Once turned on it can only be turned off by calling @p gadcHighSpeedInit() again.
- * @note The audio input is capable of signalling via this method and a binary semaphore
- * at the same time.
- *
- * @return The GSourceHandle
- *
- * @api
- */
- GSourceHandle gaudinGetSource(void);
-#endif
-
-/**
- * @brief Allow retrieving of results from the audio input using a Binary Semaphore and a static event buffer.
- *
- * @param[in] pbsem The semaphore is signaled when data is available.
- * @param[in] pEvent The static event buffer to place the result information.
- *
- * @note Passing a NULL for pbsem or pEvent will turn off signalling via this method.
- * @note The audio input is capable of signalling via this method and the GEVENT
- * sub-system at the same time.
- *
- * @api
- */
-void gaudinSetBSem(gfxSem *pbsem, GEventAudioIn *pEvent);
-
-/**
- * @brief Start the audio input conversions.
- * @pre It must have been initialised first with @p gaudinInit()
- *
- * @api
- */
-void gaudinStart(void);
-
-/**
- * @brief Stop the audio input conversions.
- *
- * @api
- */
-void gaudinStop(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GAUDIN */
-
-#endif /* _GAUDIN_H */
-/** @} */
-
diff --git a/src/gaudin/sys_make.mk b/src/gaudin/sys_make.mk
deleted file mode 100644
index 16bb33b7..00000000
--- a/src/gaudin/sys_make.mk
+++ /dev/null
@@ -1 +0,0 @@
-GFXSRC += $(GFXLIB)/src/gaudin/gaudin.c
diff --git a/src/gaudin/sys_options.h b/src/gaudin/sys_options.h
deleted file mode 100644
index 305a6f8d..00000000
--- a/src/gaudin/sys_options.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- * http://ugfx.org/license.html
- */
-
-/**
- * @file src/gaudin/sys_options.h
- * @brief GAUDIN - Audio Input subsystem options header file.
- *
- * @addtogroup GAUDIN
- * @{
- */
-
-#ifndef _GAUDIN_OPTIONS_H
-#define _GAUDIN_OPTIONS_H
-
-/**
- * @name GAUDIN Functionality to be included
- * @{
- */
-/**
- * @}
- *
- * @name GAUDIN Optional Sizing Parameters
- * @{
- */
-/** @} */
-
-#endif /* _GAUDIN_OPTIONS_H */
-/** @} */
diff --git a/src/gaudin/sys_rules.h b/src/gaudin/sys_rules.h
deleted file mode 100644
index 21d2552f..00000000
--- a/src/gaudin/sys_rules.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- * http://ugfx.org/license.html
- */
-
-/**
- * @file src/gaudin/sys_rules.h
- * @brief GAUDIN safety rules header file.
- *
- * @addtogroup GAUDIN
- * @{
- */
-
-#ifndef _GAUDIN_RULES_H
-#define _GAUDIN_RULES_H
-
-#if GFX_USE_GAUDIN
- #if GFX_USE_GEVENT && !GFX_USE_GTIMER
- #if GFX_DISPLAY_RULE_WARNINGS
- #warning "GAUDIN: GFX_USE_GTIMER is required if GFX_USE_GAUDIN and GFX_USE_GEVENT are TRUE. It has been turned on for you."
- #endif
- #undef GFX_USE_GTIMER
- #define GFX_USE_GTIMER TRUE
- #endif
-#endif
-
-#endif /* _GAUDIN_RULES_H */
-/** @} */
diff --git a/src/gaudio/driver_play.h b/src/gaudio/driver_play.h
new file mode 100644
index 00000000..72ad4747
--- /dev/null
+++ b/src/gaudio/driver_play.h
@@ -0,0 +1,126 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file src/gaudio/driver_play.h
+ * @brief GAUDIO - Audio play driver header file.
+ *
+ * @defgroup Driver Driver
+ * @ingroup GAUDIO
+ * @{
+ */
+
+#ifndef _GAUDIO_PLAY_LLD_H
+#define _GAUDIO_PLAY_LLD_H
+
+#include "gfx.h"
+
+#if (GFX_USE_GAUDIO && GAUDIO_NEED_PLAY) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Get a block of audio data to play
+ * @return A pointer to the GAaudioData structure or NULL if none is currently available
+ *
+ * @note Defined in the high level GAUDIO code for use by the GAUDIO play drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+GAudioData *gaudioPlayGetDataBlockI(void);
+
+/**
+ * @brief Release a block of audio data to the free list
+ *
+ * @param[in] paud The GAudioData block to be released.
+ *
+ * @note Defined in the high level GAUDIO code for use by the GAUDIO play drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+void gaudioPlayReleaseDataBlockI(GAudioData *paud);
+
+/**
+ * @brief Signal that all playing has now stopped
+ *
+ * @note Defined in the high level GAUDIO code for use by the GAUDIO play drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+void gaudioPlayDoneI(void);
+
+/**
+ * @brief Initialise the play driver
+ * @return TRUE if the channel, frequency and format are valid.
+ *
+ * @param[in] channel The channel to use (see the driver for the available channels provided)
+ * @param[in] frequency The sample frequency to use
+ * @param[in] format The sample format
+ *
+ * @note The driver will always have been stopped and de-init before this is called.
+ *
+ * @api
+ */
+bool_t gaudio_play_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format);
+
+/**
+ * @brief Start the audio output playing
+ *
+ * @note This may be called at any stage including while the driver
+ * is already playing. The driver should check for data blocks
+ * to play using @p gaudioPlayGetDataBlockI().
+ *
+ * @api
+ */
+void gaudio_play_lld_start(void);
+
+/**
+ * @brief Stop the audio output playing.
+ *
+ * @note Some drivers may only stop playing at a data block boundary.
+ * @note It is possible but unlikely for it to be called when playing has already stopped.
+ * @note It should not return until all active buffers (currently in use by the driver)
+ * have been returned to the free-list and @p gaudioPlayDoneI() has been called.
+ *
+ * @api
+ */
+void gaudio_play_lld_stop(void);
+
+/**
+ * @brief Set the output volume.
+ * @return TRUE if successful.
+ *
+ * @param[in] 0->255 (0 = muted)
+ *
+ * @note Some drivers may not support this. They will return FALSE.
+ * @note For stereo devices, both channels are set to the same volume.
+ *
+ * @api
+ */
+bool_t gaudio_play_lld_set_volume(uint8_t vol);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */
+
+#endif /* _GAUDIO_PLAY_LLD_H */
+/** @} */
diff --git a/src/gaudio/driver_record.h b/src/gaudio/driver_record.h
new file mode 100644
index 00000000..252cae5c
--- /dev/null
+++ b/src/gaudio/driver_record.h
@@ -0,0 +1,108 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file src/gaudio/driver_record.h
+ * @brief GAUDIO - Audio Recording driver header file.
+ *
+ * @defgroup Driver Driver
+ * @ingroup GAUDIO
+ * @{
+ */
+
+#ifndef _GAUDIO_RECORD_LLD_H
+#define _GAUDIO_RECORD_LLD_H
+
+#include "gfx.h"
+
+#if (GFX_USE_GAUDIO && GAUDIO_NEED_RECORD) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions */
+/*===========================================================================*/
+
+/**
+ * @brief Get a free block of audio data that we can record into
+ * @return A pointer to the GAaudioData structure or NULL if none is currently available
+ *
+ * @note Defined in the high level GAUDIO code for use by the GAUDIO record drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+GAudioData *gaudioRecordGetFreeBlockI(void);
+
+/**
+ * @brief Save a block of recorded audio data ready for the application
+ *
+ * @param[in] paud The GAudioData block with data.
+ *
+ * @note Defined in the high level GAUDIO code for use by the GAUDIO record drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+void gaudioRecordSaveDataBlockI(GAudioData *paud);
+
+/**
+ * @brief Signal that all recording has now stopped
+ *
+ * @note Defined in the high level GAUDIO code for use by the GAUDIO record drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+void gaudioRecordDoneI(void);
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Initialise the record driver
+ * @return TRUE if the channel, frequency and format are valid.
+ *
+ * @param[in] channel The channel to use (see the driver for the available channels provided)
+ * @param[in] frequency The sample frequency to use
+ * @param[in] format The sample format
+ *
+ * @note The driver will always have been stopped and de-init before this is called.
+ *
+ * @api
+ */
+bool_t gaudio_record_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format);
+
+/**
+ * @brief Start the audio recording
+ *
+ * @api
+ */
+void gaudio_record_lld_start(void);
+
+/**
+ * @brief Stop the audio recording.
+ *
+ * @note Some drivers may only stop recording at a data block boundary.
+ * @note This routine should not return until any currently active buffers have been
+ * saved (even if with zero length) and @p gaudioRecordDoneI() has been called.
+ *
+ * @api
+ */
+void gaudio_record_lld_stop(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */
+
+#endif /* _GAUDIO_RECORD_LLD_H */
+/** @} */
diff --git a/src/gaudio/gaudio.c b/src/gaudio/gaudio.c
new file mode 100644
index 00000000..a83dcd85
--- /dev/null
+++ b/src/gaudio/gaudio.c
@@ -0,0 +1,318 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file src/gaudio/gaudio.c
+ * @brief GAUDIO sub-system code.
+ *
+ * @addtogroup GAUDIO
+ * @{
+ */
+#include "gfx.h"
+
+#if GFX_USE_GAUDIO
+
+static gfxQueueGSync freeList;
+
+#if GAUDIO_NEED_PLAY
+ #include "src/gaudio/driver_play.h"
+
+ static gfxQueueASync playList;
+ static gfxSem playComplete;
+ static uint16_t playFlags;
+ #define PLAYFLG_USEEVENTS 0x0001
+ #define PLAYFLG_PLAYING 0x0002
+ #define PLAYFLG_ISINIT 0x0004
+ #if GFX_USE_GEVENT
+ static GTimer playTimer;
+ static void PlayTimerCallback(void *param);
+ #endif
+#endif
+
+#if GAUDIO_NEED_RECORD
+ #include "src/gaudio/driver_record.h"
+
+ static gfxQueueGSync recordList;
+ static uint16_t recordFlags;
+ #define RECORDFLG_USEEVENTS 0x0001
+ #define RECORDFLG_RECORDING 0x0002
+ #define RECORDFLG_STALLED 0x0004
+ #define RECORDFLG_ISINIT 0x0008
+ #if GFX_USE_GEVENT
+ static GTimer recordTimer;
+ static void RecordTimerCallback(void *param);
+ #endif
+#endif
+
+
+void _gaudioInit(void)
+{
+ gfxQueueGSyncInit(&freeList);
+ #if GAUDIO_NEED_PLAY
+ gfxQueueASyncInit(&playList);
+ #if GFX_USE_GEVENT
+ gtimerInit(&playTimer);
+ #endif
+ gfxSemInit(&playComplete, 0, 0);
+ #endif
+ #if GAUDIO_NEED_RECORD
+ gfxQueueGSyncInit(&recordList);
+ #if GFX_USE_GEVENT
+ gtimerInit(&recordTimer);
+ #endif
+ #endif
+}
+
+void _gaudioDeinit(void)
+{
+ #if GAUDIO_NEED_PLAY
+ #if GFX_USE_GEVENT
+ gtimerDeinit(&playTimer);
+ #endif
+ gfxSemDestroy(&playComplete);
+ #endif
+ #if GAUDIO_NEED_RECORD
+ #if GFX_USE_GEVENT
+ gtimerDeinit(&recordTimer);
+ #endif
+ #endif
+}
+
+bool_t gaudioAllocBuffers(unsigned num, size_t size) {
+ GAudioData *paud;
+
+ if (num < 1)
+ return FALSE;
+
+ // Round up to a multiple of 4 to prevent problems with structure alignment
+ size = (size + 3) & ~0x03;
+
+ // Allocate the memory
+ if (!(paud = gfxAlloc((size+sizeof(GAudioData)) * num)))
+ return FALSE;
+
+ // Add each of them to our free list
+ for(;num--; paud = (GAudioData *)((char *)(paud+1)+size)) {
+ paud->size = size;
+ gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud);
+ }
+
+ return TRUE;
+}
+
+void gaudioReleaseBuffer(GAudioData *paud) {
+ gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud);
+}
+
+GAudioData *gaudioGetBuffer(delaytime_t ms) {
+ return (GAudioData *)gfxQueueGSyncGet(&freeList, ms);
+}
+
+#if GAUDIO_NEED_PLAY
+
+ bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) {
+ gaudioPlayStop();
+ playFlags &= ~PLAYFLG_ISINIT;
+ if (!gaudio_play_lld_init(channel, frequency, format))
+ return FALSE;
+ playFlags |= PLAYFLG_ISINIT;
+ return TRUE;
+ }
+
+ void gaudioPlay(GAudioData *paud) {
+ if (!(playFlags & PLAYFLG_ISINIT)) {
+ // Oops - init failed - return it directly to the free-list
+ if (paud) {
+ gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud);
+ gfxYield(); // Make sure we get no endless cpu hogging loops
+ }
+ return;
+ }
+
+ if (paud)
+ gfxQueueASyncPut(&playList, (gfxQueueASyncItem *)paud);
+ playFlags |= PLAYFLG_PLAYING;
+ gaudio_play_lld_start();
+ }
+
+ void gaudioPlayPause(void) {
+ if ((playFlags & (PLAYFLG_ISINIT|PLAYFLG_PLAYING)) == (PLAYFLG_ISINIT|PLAYFLG_PLAYING))
+ gaudio_play_lld_stop();
+ }
+
+ void gaudioPlayStop(void) {
+ GAudioData *paud;
+
+ if (playFlags & PLAYFLG_PLAYING)
+ gaudio_play_lld_stop();
+ while((paud = (GAudioData *)gfxQueueASyncGet(&playList)))
+ gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud);
+ }
+
+ bool_t gaudioPlaySetVolume(uint8_t vol) {
+ return gaudio_play_lld_set_volume(vol);
+ }
+
+ bool_t gaudioPlayWait(delaytime_t ms) {
+ if (!(playFlags & PLAYFLG_PLAYING))
+ return TRUE;
+ return gfxSemWait(&playComplete, ms);
+ }
+
+ #if GFX_USE_GEVENT
+ static void PlayTimerCallback(void *param) {
+ (void) param;
+ GSourceListener *psl;
+ GEventAudioPlay *pe;
+
+ psl = 0;
+ while ((psl = geventGetSourceListener((GSourceHandle)&playTimer, psl))) {
+ if (!(pe = (GEventAudioPlay *)geventGetEventBuffer(psl))) {
+ // This listener is missing - save this.
+ psl->srcflags |= GAUDIO_PLAY_LOSTEVENT;
+ continue;
+ }
+
+ pe->type = GEVENT_AUDIO_PLAY;
+ pe->flags = psl->srcflags;
+ psl->srcflags = 0;
+ if ((playFlags & PLAYFLG_PLAYING))
+ pe->flags |= GAUDIO_PLAY_PLAYING;
+ if (!gfxQueueGSyncIsEmpty(&freeList))
+ pe->flags |= GAUDIO_PLAY_FREEBLOCK;
+ geventSendEvent(psl);
+ }
+ }
+
+ GSourceHandle gaudioPlayGetSource(void) {
+ if (!gtimerIsActive(&playTimer))
+ gtimerStart(&playTimer, PlayTimerCallback, 0, TRUE, TIME_INFINITE);
+ playFlags |= PLAYFLG_USEEVENTS;
+ return (GSourceHandle)&playTimer;
+ }
+ #endif
+
+ /**
+ * Routines provided for use by drivers.
+ */
+
+ GAudioData *gaudioPlayGetDataBlockI(void) {
+ return (GAudioData *)gfxQueueASyncGetI(&playList);
+ }
+
+ void gaudioPlayReleaseDataBlockI(GAudioData *paud) {
+ gfxQueueGSyncPutI(&freeList, (gfxQueueGSyncItem *)paud);
+ #if GFX_USE_GEVENT
+ if (playFlags & PLAYFLG_USEEVENTS)
+ gtimerJabI(&playTimer);
+ #endif
+ }
+
+ void gaudioPlayDoneI(void) {
+ playFlags &= ~PLAYFLG_PLAYING;
+ #if GFX_USE_GEVENT
+ if (playFlags & PLAYFLG_USEEVENTS)
+ gtimerJabI(&playTimer);
+ #endif
+ gfxSemSignalI(&playComplete); // This should really be gfxSemSignalAllI(&playComplete);
+ }
+#endif
+
+#if GAUDIO_NEED_RECORD
+ bool_t gaudioRecordInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) {
+ gaudioRecordStop();
+ recordFlags &= ~RECORDFLG_ISINIT;
+ if (!gaudio_record_lld_init(channel, frequency, format))
+ return FALSE;
+ recordFlags |= RECORDFLG_ISINIT;
+ return TRUE;
+ }
+
+ void gaudioRecordStart(void) {
+ if (!(recordFlags & RECORDFLG_ISINIT))
+ return; // Oops - init failed
+
+ recordFlags |= RECORDFLG_RECORDING;
+ recordFlags &= ~RECORDFLG_STALLED;
+ gaudio_record_lld_start();
+ }
+
+ void gaudioRecordStop(void) {
+ GAudioData *paud;
+
+ if ((recordFlags & (RECORDFLG_RECORDING|RECORDFLG_STALLED)) == RECORDFLG_RECORDING)
+ gaudio_record_lld_stop();
+ recordFlags &= ~(RECORDFLG_RECORDING|RECORDFLG_STALLED);
+ while((paud = (GAudioData *)gfxQueueGSyncGet(&recordList, TIME_IMMEDIATE)))
+ gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud);
+ }
+
+ GAudioData *gaudioRecordGetData(delaytime_t ms) {
+ return (GAudioData *)gfxQueueGSyncGet(&recordList, ms);
+ }
+
+ #if GFX_USE_GEVENT
+ static void RecordTimerCallback(void *param) {
+ (void) param;
+ GSourceListener *psl;
+ GEventAudioRecord *pe;
+
+ psl = 0;
+ while ((psl = geventGetSourceListener((GSourceHandle)&recordTimer, psl))) {
+ if (!(pe = (GEventAudioRecord *)geventGetEventBuffer(psl))) {
+ // This listener is missing - save this.
+ psl->srcflags |= GAUDIO_RECORD_LOSTEVENT;
+ continue;
+ }
+ pe->type = GEVENT_AUDIO_RECORD;
+ pe->flags = psl->srcflags;
+ psl->srcflags = 0;
+ if ((recordFlags & RECORDFLG_RECORDING))
+ pe->flags |= GAUDIO_RECORD_RECORDING;
+ if ((recordFlags & RECORDFLG_STALLED))
+ pe->flags |= GAUDIO_RECORD_STALL;
+ if (!gfxQueueGSyncIsEmpty(&recordList))
+ pe->flags |= GAUDIO_RECORD_GOTBLOCK;
+ geventSendEvent(psl);
+ }
+ }
+
+ GSourceHandle gaudioRecordGetSource(void) {
+ if (!gtimerIsActive(&recordTimer))
+ gtimerStart(&recordTimer, RecordTimerCallback, 0, TRUE, TIME_INFINITE);
+ recordFlags |= RECORDFLG_USEEVENTS;
+ return (GSourceHandle)&recordTimer;
+ }
+ #endif
+
+ /**
+ * Routines provided for use by drivers.
+ */
+
+ GAudioData *gaudioRecordGetFreeBlockI(void) {
+ return (GAudioData *)gfxQueueGSyncGetI(&freeList);
+ }
+
+ void gaudioRecordSaveDataBlockI(GAudioData *paud) {
+ gfxQueueGSyncPutI(&recordList, (gfxQueueGSyncItem *)paud);
+ #if GFX_USE_GEVENT
+ if (recordFlags & RECORDFLG_USEEVENTS)
+ gtimerJabI(&recordTimer);
+ #endif
+ }
+
+ void gaudioRecordDoneI(void) {
+ recordFlags |= RECORDFLG_STALLED;
+ #if GFX_USE_GEVENT
+ if (recordFlags & RECORDFLG_USEEVENTS)
+ gtimerJabI(&recordTimer);
+ #endif
+ }
+#endif
+
+#endif /* GFX_USE_GAUDIO */
+/** @} */
diff --git a/src/gaudio/sys_defs.h b/src/gaudio/sys_defs.h
new file mode 100644
index 00000000..a9a951b7
--- /dev/null
+++ b/src/gaudio/sys_defs.h
@@ -0,0 +1,340 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file src/gaudio/sys_defs.h
+ *
+ * @addtogroup GAUDIO
+ *
+ * @brief Module to handle audio recording and play-back
+ *
+ * @{
+ */
+
+#ifndef _GAUDIO_H
+#define _GAUDIO_H
+
+#include "gfx.h"
+
+#if GFX_USE_GAUDIO || defined(__DOXYGEN__)
+
+/* Include the driver defines */
+#if GAUDIO_NEED_PLAY
+ #include "gaudio_play_config.h"
+#endif
+#if GAUDIO_NEED_RECORD
+ #include "gaudio_record_config.h"
+#endif
+
+/*===========================================================================*/
+/* Type definitions */
+/*===========================================================================*/
+
+/**
+ * @brief Contains Audio Data Samples
+ * @note This structure is followed immediately by the sample data itself.
+ * When allocating the buffers for the sample data put this structure
+ * at the beginning of the buffer.
+ */
+typedef struct GAudioData {
+ gfxQueueASyncItem next; // @< Used for queuing the buffers
+ size_t size; // @< The size of the buffer area following this structure (in bytes)
+ size_t len; // @< The length of the data in the buffer area (in bytes)
+} GAudioData;
+
+
+// Event types for GAUDIO
+#define GEVENT_AUDIO_PLAY (GEVENT_GAUDIO_FIRST+0)
+#define GEVENT_AUDIO_RECORD (GEVENT_GAUDIO_FIRST+1)
+
+#if GFX_USE_GEVENT || defined(__DOXYGEN__)
+ /**
+ * @brief The Audio play event structure.
+ * @{
+ */
+ typedef struct GEventAudioPlay_t {
+ /**
+ * @brief The type of this event (GEVENT_AUDIO_PLAY)
+ */
+ GEventType type;
+ /**
+ * @brief The event flags
+ */
+ uint16_t flags;
+ /**
+ * @brief The event flag values.
+ * @{
+ */
+ #define GAUDIO_PLAY_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_PLAY event was lost */
+ #define GAUDIO_PLAY_PLAYING 0x0002 /**< @brief The audio out system is currently playing */
+ #define GAUDIO_PLAY_FREEBLOCK 0x0004 /**< @brief An audio buffer has been freed */
+ /** @} */
+ } GEventAudioPlay;
+ /** @} */
+
+ /**
+ * @brief The Audio record event structure.
+ * @{
+ */
+ typedef struct GEventAudioRecord_t {
+ /**
+ * @brief The type of this event (GEVENT_AUDIO_RECORD)
+ */
+ GEventType type;
+ /**
+ * @brief The event flags
+ */
+ uint16_t flags;
+ /**
+ * @brief The event flag values.
+ * @{
+ */
+ #define GAUDIO_RECORD_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_IN event was lost */
+ #define GAUDIO_RECORD_RECORDING 0x0002 /**< @brief The audio recording system is currently recording */
+ #define GAUDIO_RECORD_GOTBLOCK 0x0004 /**< @brief An audio buffer is ready for processing */
+ #define GAUDIO_RECORD_STALL 0x0008 /**< @brief The recording process has stalled due to no free buffers */
+ /** @} */
+ } GEventAudioRecord;
+ /** @} */
+#endif
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Allocate some audio buffers and put them on the free list
+ * @return TRUE is it succeeded. FALSE on allocation failure.
+ *
+ * @param[in] num The number of buffers to allocate
+ * @param[in] size The size (in bytes) of each buffer
+ *
+ * @api
+ */
+bool_t gaudioAllocBuffers(unsigned num, size_t size);
+
+/**
+ * @brief Get an audio buffer from the free list
+ * @return A GAudioData pointer or NULL if the timeout is exceeded
+ *
+ * @params[in] ms The maximum amount of time in milliseconds to wait for a buffer if one is not available.
+ *
+ * @api
+ */
+GAudioData *gaudioGetBuffer(delaytime_t ms);
+
+/**
+ * @brief Release a buffer back to the free list
+ *
+ * @param[in] paud The buffer to put (back) on the free-list.
+ *
+ * @note This call should be used to return any buffers that were taken from
+ * the free-list once they have been finished with. It can also be used
+ * to put new buffers onto the free-list. Just make sure the "size" field
+ * of the GAudioData structure has been filled in first.
+ *
+ * @api
+ */
+void gaudioReleaseBuffer(GAudioData *paud);
+
+#if GAUDIO_NEED_PLAY || defined(__DOXYGEN__)
+ /**
+ * @brief Set the audio device to play on the specified channel and with the specified
+ * sample frequency.
+ * @return TRUE is successful, FALSE if the driver doesn't accept those parameters.
+ *
+ * @param[in] channel The audio output channel to use. Can be set from 0 to GAUDIO_PLAY_NUM_CHANNELS - 1
+ * @param[in] frequency The audio sample rate in samples per second
+ * @param[in] format The audio sample format
+ *
+ * @note Some channels are mono, and some are stereo. See your driver config file
+ * to determine which channels to use and whether they are stereo or not.
+ * @note Only one channel can be playing at a time. Calling this will stop any
+ * currently playing channel.
+ *
+ * @api
+ */
+ bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format);
+
+ /**
+ * @brief Play the specified sample data.
+ * @details The sample data is output to the audio channel. On completion the buffer is returned to the free-list.
+ * @pre @p gaudioPlayInit must have been called first to set the channel and sample frequency.
+ *
+ * @param[in] paud The audio sample buffer to play. It can be NULL (used to restart paused audio)
+ *
+ * @note Calling this will cancel any pause.
+ * @note Before calling this function the len field of the GAudioData structure must be
+ * specified (in bytes).
+ * @note For stereo channels the sample data is interleaved in the buffer.
+ * @note This call returns before the data has completed playing. Subject to available buffers (which
+ * can be obtained from the free-list), any number of buffers may be played. They will be queued
+ * for playing in the order they are supplied to this routine and played when previous buffers are
+ * complete. In this way continuous playing can be obtained without audio gaps.
+ *
+ * @api
+ */
+ void gaudioPlay(GAudioData *paud);
+
+ /**
+ * @brief Pause any currently playing sounds.
+ *
+ * @note If nothing is currently playing this routine does nothing. To restart playing call @p gaudioPlay()
+ * with or without a new sample buffer.
+ * @note Some drivers will not respond until a buffer boundary.
+ *
+ * @api
+ */
+ void gaudioPlayPause(void);
+
+ /**
+ * @brief Stop any currently playing sounds.
+ *
+ * @note This stops any playing sounds and returns any currently queued buffers back to the free-list.
+ * @note Some drivers will not respond until a buffer boundary.
+ *
+ * @api
+ */
+ void gaudioPlayStop(void);
+
+ /**
+ * @brief Set the output volume.
+ * @return TRUE if successful.
+ *
+ * @param[in] 0->255 (0 = muted)
+ *
+ * @note Some drivers may not support this. They will return FALSE.
+ * @note For stereo devices, both channels are set to the same volume.
+ *
+ * @api
+ */
+ bool_t gaudioPlaySetVolume(uint8_t vol);
+
+ #if GFX_USE_GEVENT || defined(__DOXYGEN__)
+ /**
+ * @brief Turn on sending results to the GEVENT sub-system.
+ * @details Returns a GSourceHandle to listen for GEVENT_AUDIO_OUT events.
+ *
+ * @note The audio output will not use the GEVENT system unless this is
+ * called first. This saves processing time if the application does
+ * not want to use the GEVENT sub-system for audio output.
+ * Once turned on it can only be turned off by calling @p gaudioPlayInit() again.
+ * @note The audio output is capable of signaling via this method and other methods
+ * at the same time.
+ *
+ * @return The GSourceHandle
+ *
+ * @api
+ */
+ GSourceHandle gaudioPlayGetSource(void);
+ #endif
+
+ /**
+ * @brief Wait for any currently playing sounds to complete
+ * @return TRUE if there is now nothing playing or FALSE if the timeout is exceeded
+ *
+ * @params[in] ms The maximum amount of time in milliseconds to wait for playing to complete.
+ *
+ * @api
+ */
+ bool_t gaudioPlayWait(delaytime_t ms);
+#endif
+
+#if GAUDIO_NEED_RECORD || defined(__DOXYGEN__)
+ /**
+ * @brief Initialise (but not start) the Audio Recording sub-system.
+ * @details Returns FALSE for an invalid channel or other invalid parameter.
+ *
+ * @param[in] channel The channel to convert. Can be set from 0 to GAUDIO_RECORD_NUM_CHANNELS - 1
+ * @param[in] frequency The sample frequency
+ * @param[in] format The audio sample format requested
+ *
+ * @note Only one channel is active at a time. If an audio input is running it will be stopped.
+ * The Event subsystem is disconnected from the audio subsystem and any binary semaphore
+ * event is forgotten.
+ * @note Some channels may be stereo channels which return twice as much sample data with
+ * the left and right channel data interleaved. Other channels may be mono channels.
+ * Where stereo channels exist the low level driver may also
+ * offer the left and right channels separately.
+ * @note Due to a bug in Chibi-OS each buffer on the free-list must contain an even number of
+ * samples and for stereo devices it must hold a number of samples that is evenly divisible by 4.
+ * This requirement applies only to ChibiOS where the audio driver uses
+ * a ChibiOS hal driver like the cpu ADC driver. This applies even it is used indirectly via
+ * the uGFX GADC driver.
+ * @note The number of samples for stereo devices will be double the number of conversions.
+ * Make sure you allocate your buffers large enough. Each channel is then interleaved
+ * into the provided buffer.
+ *
+ * @return FALSE if invalid channel or parameter
+ *
+ * @api
+ */
+ bool_t gaudioRecordInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format);
+
+ /**
+ * @brief Start the audio recording.
+ * @pre It must have been initialised first with @p gaudioRecordInit()
+ *
+ * @api
+ */
+ void gaudioRecordStart(void);
+
+ /**
+ * @brief Stop the audio recording.
+ *
+ * @note All audio recording data that has not yet been retrieved is automatically
+ * returned to the free-list.
+ * @api
+ */
+ void gaudioRecordStop(void);
+
+ /**
+ * @brief Get a filled audio buffer from the recording list
+ * @return A GAudioData pointer or NULL if the timeout is exceeded
+ *
+ * @params[in] ms The maximum amount of time in milliseconds to wait for data if some is not currently available.
+ *
+ * @note After processing the audio data, your application must return the buffer to the free-list so that
+ * it can be used to record more audio into. This can be done via the play list using @p gaudioPlay() or
+ * directly using @p gaudioReleaseBuffer().
+ * @api
+ */
+ GAudioData *gaudioRecordGetData(delaytime_t ms);
+
+ #if GFX_USE_GEVENT || defined(__DOXYGEN__)
+ /**
+ * @brief Turn on sending results to the GEVENT sub-system.
+ * @details Returns a GSourceHandle to listen for GEVENT_AUDIO_RECORD events.
+ *
+ * @note Audio recording will not use the GEVENT system unless this is
+ * called first. This saves processing time if the application does
+ * not want to use the GEVENT sub-system for audio recording.
+ * Once turned on it can only be turned off by calling @p gaudioRecordInit() again.
+ * @note The audio input is capable of signaling via this and other methods
+ * at the same time.
+ *
+ * @return The GSourceHandle
+ *
+ * @api
+ */
+ GSourceHandle gaudioRecordGetSource(void);
+ #endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GAUDIO */
+
+#endif /* _GAUDIO_H */
+/** @} */
+
diff --git a/src/gaudio/sys_make.mk b/src/gaudio/sys_make.mk
new file mode 100644
index 00000000..438892c0
--- /dev/null
+++ b/src/gaudio/sys_make.mk
@@ -0,0 +1 @@
+GFXSRC += $(GFXLIB)/src/gaudio/gaudio.c
diff --git a/src/gaudio/sys_options.h b/src/gaudio/sys_options.h
new file mode 100644
index 00000000..1363d703
--- /dev/null
+++ b/src/gaudio/sys_options.h
@@ -0,0 +1,44 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file src/gaudio/sys_options.h
+ * @brief GAUDIO - Audio subsystem options header file.
+ *
+ * @addtogroup GAUDIO
+ * @{
+ */
+
+#ifndef _GAUDIO_OPTIONS_H
+#define _GAUDOUT_OPTIONS_H
+
+/**
+ * @name GAUDIO Functionality to be included
+ * @{
+ */
+ /**
+ * @brief Audio Play capability is needed
+ */
+ #ifndef GAUDIO_NEED_PLAY
+ #define GAUDIO_NEED_PLAY FALSE
+ #endif
+ /**
+ * @brief Audio Recording capability is needed
+ */
+ #ifndef GAUDIO_NEED_RECORD
+ #define GAUDIO_NEED_RECORD FALSE
+ #endif
+/**
+ * @}
+ *
+ * @name GAUDIO Optional Sizing Parameters
+ * @{
+ */
+/** @} */
+
+#endif /* _GAUDIO_OPTIONS_H */
+/** @} */
diff --git a/src/gaudio/sys_rules.h b/src/gaudio/sys_rules.h
new file mode 100644
index 00000000..a3f0dffc
--- /dev/null
+++ b/src/gaudio/sys_rules.h
@@ -0,0 +1,54 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file src/gaudio/sys_rules.h
+ * @brief GAUDIO safety rules header file.
+ *
+ * @addtogroup GAUDIO
+ * @{
+ */
+
+#ifndef _GAUDIO_RULES_H
+#define _GAUDIO_RULES_H
+
+#if GFX_USE_GAUDIO
+ #if !GAUDIO_NEED_PLAY && !GAUDIO_NEED_RECORD
+ #error "GAUDIO: GAUDIO_NEED_PLAY and/or GAUDIO_NEED_RECORD is required if GFX_USE_GAUDIO is TRUE"
+ #endif
+ #if !GFX_USE_GQUEUE
+ #if GFX_DISPLAY_RULE_WARNINGS
+ #warning "GAUDIO: GFX_USE_GQUEUE is required if GFX_USE_GAUDIO is TRUE. It has been turned on for you."
+ #endif
+ #undef GFX_USE_GQUEUE
+ #define GFX_USE_GQUEUE TRUE
+ #endif
+ #if !GQUEUE_NEED_ASYNC
+ #if GFX_DISPLAY_RULE_WARNINGS
+ #warning "GAUDIO: GQUEUE_NEED_ASYNC is required if GFX_USE_GAUDIO is TRUE. It has been turned on for you."
+ #endif
+ #undef GQUEUE_NEED_ASYNC
+ #define GQUEUE_NEED_ASYNC TRUE
+ #endif
+ #if !GQUEUE_NEED_GSYNC
+ #if GFX_DISPLAY_RULE_WARNINGS
+ #warning "GAUDIO: GQUEUE_NEED_GSYNC is required if GFX_USE_GAUDIO is TRUE. It has been turned on for you."
+ #endif
+ #undef GQUEUE_NEED_GSYNC
+ #define GQUEUE_NEED_GSYNC TRUE
+ #endif
+ #if GFX_USE_GEVENT && !GFX_USE_GTIMER
+ #if GFX_DISPLAY_RULE_WARNINGS
+ #warning "GAUDIO: GFX_USE_GTIMER is required if GFX_USE_GAUDIO and GFX_USE_GEVENT are TRUE. It has been turned on for you."
+ #endif
+ #undef GFX_USE_GTIMER
+ #define GFX_USE_GTIMER TRUE
+ #endif
+#endif
+
+#endif /* _GAUDIO_RULES_H */
+/** @} */
diff --git a/src/gaudout/gaudout.c b/src/gaudout/gaudout.c
deleted file mode 100644
index 56692453..00000000
--- a/src/gaudout/gaudout.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- * http://ugfx.org/license.html
- */
-
-/**
- * @file src/gaudout/gaudout.c
- * @brief GAUDOUT sub-system code.
- *
- * @addtogroup GAUDOUT
- * @{
- */
-#include "gfx.h"
-
-#if GFX_USE_GAUDOUT || defined(__DOXYGEN__)
-
- #error "GAUDOUT: Not implemented yet"
-
-void _gaudoutInit(void)
-{
- /* ToDo */
-}
-
-void _gaudoutDeinit(void)
-{
- /* ToDo */
-}
-
-#endif /* GFX_USE_GAUDOUT */
-/** @} */
-
diff --git a/src/gaudout/sys_defs.h b/src/gaudout/sys_defs.h
deleted file mode 100644
index f22d269c..00000000
--- a/src/gaudout/sys_defs.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- * http://ugfx.org/license.html
- */
-
-/**
- * @file src/gaudout/sys_defs.h
- *
- * @addtogroup GAUDOUT
- *
- * @brief Module to output audio data (under development)
- *
- * @{
- */
-
-#ifndef _GAUDOUT_H
-#define _GAUDOUT_H
-
-#include "gfx.h"
-
-#if GFX_USE_GAUDOUT || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Type definitions */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GAUDOUT */
-
-#endif /* _GAUDOUT_H */
-/** @} */
-
diff --git a/src/gaudout/sys_make.mk b/src/gaudout/sys_make.mk
deleted file mode 100644
index 14f5bac3..00000000
--- a/src/gaudout/sys_make.mk
+++ /dev/null
@@ -1 +0,0 @@
-GFXSRC += $(GFXLIB)/src/gaudout/gaudout.c
diff --git a/src/gaudout/sys_options.h b/src/gaudout/sys_options.h
deleted file mode 100644
index 929bb42a..00000000
--- a/src/gaudout/sys_options.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- * http://ugfx.org/license.html
- */
-
-/**
- * @file src/gaudout/sys_options.h
- * @brief GAUDOUT - Audio Output subsystem options header file.
- *
- * @addtogroup GAUDOUT
- * @{
- */
-
-#ifndef _GAUDOUT_OPTIONS_H
-#define _GAUDOUT_OPTIONS_H
-
-/**
- * @name GAUDOUT Functionality to be included
- * @{
- */
-/**
- * @}
- *
- * @name GAUDOUT Optional Sizing Parameters
- * @{
- */
-/** @} */
-
-#endif /* _GAUDOUT_OPTIONS_H */
-/** @} */
diff --git a/src/gaudout/sys_rules.h b/src/gaudout/sys_rules.h
deleted file mode 100644
index 50b9a442..00000000
--- a/src/gaudout/sys_rules.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- * http://ugfx.org/license.html
- */
-
-/**
- * @file src/gaudout/sys_rules.h
- * @brief GAUDOUT safety rules header file.
- *
- * @addtogroup GAUDOUT
- * @{
- */
-
-#ifndef _GAUDOUT_RULES_H
-#define _GAUDOUT_RULES_H
-
-#if GFX_USE_GAUDOUT
-#endif
-
-#endif /* _GAUDOUT_RULES_H */
-/** @} */
diff --git a/src/gevent/sys_defs.h b/src/gevent/sys_defs.h
index 0e656145..c50dc5ae 100644
--- a/src/gevent/sys_defs.h
+++ b/src/gevent/sys_defs.h
@@ -38,8 +38,7 @@ typedef uint16_t GEventType;
#define GEVENT_GINPUT_FIRST 0x0100 // GINPUT events range from 0x0100 to 0x01FF
#define GEVENT_GWIN_FIRST 0x0200 // GWIN events range from 0x0200 to 0x02FF
#define GEVENT_GADC_FIRST 0x0300 // GADC events range from 0x0300 to 0x033F
- #define GEVENT_GAUDIN_FIRST 0x0340 // GAUDIN events range from 0x0340 to 0x037F
- #define GEVENT_GAUDOUT_FIRST 0x0380 // GAUDOUT events range from 0x0380 to 0x03BF
+ #define GEVENT_GAUDIO_FIRST 0x0340 // GAUDIO events range from 0x0340 to 0x037F
#define GEVENT_USER_FIRST 0x8000 // Any application defined events start at 0x8000
// This object can be typecast to any GEventXxxxx type to allow any sub-system (or the application) to create events.
diff --git a/src/gfx.c b/src/gfx.c
index d01d3b1f..8e92fc29 100644
--- a/src/gfx.c
+++ b/src/gfx.c
@@ -44,13 +44,9 @@ extern void _gosDeinit(void);
extern void _gadcInit(void);
extern void _gadcDeinit(void);
#endif
-#if GFX_USE_GAUDIN
- extern void _gaudinInit(void);
- extern void _gaudinDeinit(void);
-#endif
-#if GFX_USE_GAUDOUT
- extern void _gaudoutInit(void);
- extern void _gaudoutDeinit(void);
+#if GFX_USE_GAUDIO
+ extern void _gaudioInit(void);
+ extern void _gaudioDeinit(void);
#endif
#if GFX_USE_GMISC
extern void _gmiscInit(void);
@@ -88,11 +84,8 @@ void gfxInit(void)
#if GFX_USE_GADC
_gadcInit();
#endif
- #if GFX_USE_GAUDIN
- _gaudinInit();
- #endif
- #if GFX_USE_GAUDOUT
- _gaudoutInit();
+ #if GFX_USE_GAUDIO
+ _gaudioInit();
#endif
}
@@ -103,11 +96,8 @@ void gfxDeinit(void)
initDone = FALSE;
// We deinitialise the opposite way as we initialised
- #if GFX_USE_GAUDOUT
- _gaudoutDeinit();
- #endif
#if GFX_USE_GAUDIN
- _gaudinDeinit();
+ _gaudioDeinit();
#endif
#if GFX_USE_GADC
_gadcDeinit();
diff --git a/src/ginput/mouse.c b/src/ginput/mouse.c
index c7a20ec1..f7842e33 100644
--- a/src/ginput/mouse.c
+++ b/src/ginput/mouse.c
@@ -189,6 +189,8 @@ void _tsOrientClip(MouseReading *pt, GDisplay *g, bool_t doClip) {
break;
}
#else
+ (void) g;
+
c0 = cross[0].x;
c1 = cross[1].x;
c2 = cross[2].x;
diff --git a/src/gmisc/sys_defs.h b/src/gmisc/sys_defs.h
index cbb0111b..41a9bca6 100644
--- a/src/gmisc/sys_defs.h
+++ b/src/gmisc/sys_defs.h
@@ -40,6 +40,16 @@ typedef enum ArrayDataFormat_e {
} ArrayDataFormat;
/**
+ * @brief Is the sample data format a "signed" data format?
+ */
+#define gfxSampleFormatIsSigned(fmt) ((fmt) & 1)
+
+/**
+ * @brief How many bits are in the sample data format
+ */
+#define gfxSampleFormatBits(fmt) ((fmt) & ~1)
+
+/**
* @brief The type for a fixed point type.
* @details The top 16 bits are the integer component, the bottom 16 bits are the real component.
*/
diff --git a/src/gos/chibios.c b/src/gos/chibios.c
index cf02b3e2..7d64fe1c 100644
--- a/src/gos/chibios.c
+++ b/src/gos/chibios.c
@@ -89,6 +89,13 @@ bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
return chSemWaitTimeout(&psem->sem, MS2ST(ms)) != RDY_TIMEOUT;
}
+bool_t gfxSemWaitI(gfxSem *psem) {
+ if (chSemGetCounterI(&psem->sem) <= 0)
+ return FALSE;
+ chSemFastWaitI(&psem->sem);
+ return TRUE;
+}
+
void gfxSemSignal(gfxSem *psem) {
chSysLock();
diff --git a/src/gos/chibios.h b/src/gos/chibios.h
index 6373aa43..1db9482e 100644
--- a/src/gos/chibios.h
+++ b/src/gos/chibios.h
@@ -82,6 +82,7 @@ void gfxSleepMicroseconds(delaytime_t ms);
void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
void gfxSemDestroy(gfxSem *psem);
bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
+bool_t gfxSemWaitI(gfxSem *psem);
void gfxSemSignal(gfxSem *psem);
void gfxSemSignalI(gfxSem *psem);
#define gfxSemCounterI(psem) ((psem)->sem.s_cnt)
diff --git a/src/gos/linux.h b/src/gos/linux.h
index f8b049e9..f92fc4e9 100644
--- a/src/gos/linux.h
+++ b/src/gos/linux.h
@@ -46,6 +46,7 @@ typedef pthread_mutex_t gfxMutex;
#define gfxMutexDestroy(pmtx) pthread_mutex_destroy(pmtx)
#define gfxMutexEnter(pmtx) pthread_mutex_lock(pmtx)
#define gfxMutexExit(pmtx) pthread_mutex_unlock(pmtx)
+#define gfxSemWaitI(psem) gfxSemWait(psem, TIME_IMMEDIATE)
#define gfxSemSignalI(psem) gfxSemSignal(psem)
#define gfxSemCounterI(pSem) ((pSem)->cnt)
diff --git a/src/gos/osx.h b/src/gos/osx.h
index 56e0551e..80b07eec 100644
--- a/src/gos/osx.h
+++ b/src/gos/osx.h
@@ -45,6 +45,7 @@ typedef pthread_mutex_t gfxMutex;
#define gfxMutexDestroy(pmtx) pthread_mutex_destroy(pmtx)
#define gfxMutexEnter(pmtx) pthread_mutex_lock(pmtx)
#define gfxMutexExit(pmtx) pthread_mutex_unlock(pmtx)
+#define gfxSemWaitI(psem) gfxSemWait(psem, TIME_IMMEDIATE)
#define gfxSemSignalI(psem) gfxSemSignal(psem)
#define gfxSemCounterI(pSem) ((pSem)->cnt)
diff --git a/src/gos/raw32.c b/src/gos/raw32.c
index 61d09761..2fdfdf68 100644
--- a/src/gos/raw32.c
+++ b/src/gos/raw32.c
@@ -346,6 +346,13 @@ bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
return TRUE;
}
+bool_t gfxSemWaitI(gfxSem *psem) {
+ if (psem->cnt <= 0)
+ return FALSE;
+ psem->cnt--;
+ return TRUE;
+}
+
void gfxSemSignal(gfxSem *psem) {
INTERRUPTS_OFF();
gfxSemSignalI(psem);
diff --git a/src/gos/raw32.h b/src/gos/raw32.h
index eb5b5e18..d4e8e548 100644
--- a/src/gos/raw32.h
+++ b/src/gos/raw32.h
@@ -110,6 +110,7 @@ extern "C" {
void gfxMutexExit(gfxMutex *pmutex);
void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
+ bool_t gfxSemWaitI(gfxSem *psem);
void gfxSemSignal(gfxSem *psem);
void gfxSemSignalI(gfxSem *psem);
gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param);
diff --git a/src/gos/sys_defs.h b/src/gos/sys_defs.h
index b86d6d6a..4014e791 100644
--- a/src/gos/sys_defs.h
+++ b/src/gos/sys_defs.h
@@ -328,6 +328,19 @@
bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
/**
+ * @brief Test if a wait on a semaphore can be satisfied immediately
+ * @details Equivalent to @p gfxSemWait(psem, TIME_IMMEDIATE) except it can be called at interrupt level
+ * @return FALSE if the wait would occur occurred otherwise TRUE
+ *
+ * @param[in] psem A pointer to the semaphore
+ * @param[in] ms The maximum time to wait for the semaphore
+ *
+ * @iclass
+ * @api
+ */
+ bool_t gfxSemWaitI(gfxSem *psem);
+
+ /**
* @brief Signal a semaphore
* @details The semaphore counter is increased and if the result is non-positive then a waiting thread
* is queued for execution. Note that once the thread reaches "limit", further signals are
diff --git a/src/gos/win32.h b/src/gos/win32.h
index c704a288..8a5d9025 100644
--- a/src/gos/win32.h
+++ b/src/gos/win32.h
@@ -74,6 +74,7 @@ typedef HANDLE gfxThreadHandle;
#define gfxMutexExit(pmutex) ReleaseMutex(*(pmutex))
#define gfxSemInit(psem, val, limit) *(psem) = CreateSemaphore(0, val, limit, 0)
#define gfxSemDestroy(psem) CloseHandle(*(psem))
+#define gfxSemWaitI(psem) gfxSemWait((psem), TIME_IMMEDIATE)
#define gfxSemSignal(psem) ReleaseSemaphore(*(psem), 1, 0)
#define gfxSemSignalI(psem) ReleaseSemaphore(*(psem), 1, 0)
#define gfxSemCounterI(psem) gfxSemCounter(psem)
diff --git a/src/gqueue/gqueue.c b/src/gqueue/gqueue.c
index 2adfd9ff..b7ecb032 100644
--- a/src/gqueue/gqueue.c
+++ b/src/gqueue/gqueue.c
@@ -22,47 +22,64 @@
gfxQueueASyncItem *gfxQueueASyncGet(gfxQueueASync *pqueue) {
gfxQueueASyncItem *pi;
+ // This is just a shortcut to speed execution
if (!pqueue->head)
return 0;
gfxSystemLock();
- if ((pi = pqueue->head))
- pqueue->head = pi->next;
- pi->next = 0;
+ pi = gfxQueueASyncGetI(pqueue);
gfxSystemUnlock();
return pi;
}
+ gfxQueueASyncItem *gfxQueueASyncGetI(gfxQueueASync *pqueue) {
+ gfxQueueASyncItem *pi;
- void gfxQueueASyncPut(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
- pitem->next = 0;
+ if ((pi = pqueue->head)) {
+ pqueue->head = pi->next;
+ pi->next = 0;
+ }
+
+ return pi;
+ }
+ void gfxQueueASyncPut(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
gfxSystemLock();
+ gfxQueueASyncPutI(pqueue, pitem);
+ gfxSystemUnlock();
+ }
+ void gfxQueueASyncPutI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+ pitem->next = 0;
if (!pqueue->head) {
pqueue->head = pqueue->tail = pitem;
} else {
pqueue->tail->next = pitem;
pqueue->tail = pitem;
}
- gfxSystemUnlock();
}
void gfxQueueASyncPush(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
gfxSystemLock();
+ gfxQueueASyncPushI(pqueue, pitem);
+ gfxSystemUnlock();
+ }
+ void gfxQueueASyncPushI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
pitem->next = pqueue->head;
pqueue->head = pitem;
if (!pitem->next)
pqueue->tail = pitem;
- gfxSystemUnlock();
}
void gfxQueueASyncRemove(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+ gfxSystemLock();
+ gfxQueueASyncRemoveI(pqueue, pitem);
+ gfxSystemUnlock();
+ }
+ void gfxQueueASyncRemoveI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
gfxQueueASyncItem *pi;
if (!pitem)
return;
-
- gfxSystemLock();
if (pqueue->head) {
if (pqueue->head == pitem) {
pqueue->head = pitem->next;
@@ -79,25 +96,24 @@
}
}
}
- gfxSystemUnlock();
- }
-
- bool_t gfxQueueASyncIsEmpty(gfxQueueASync *pqueue) {
- return pqueue->head == 0;
}
bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem) {
- gfxQueueASyncItem *pi;
+ bool_t res;
gfxSystemLock();
+ res = gfxQueueASyncIsInI(pqueue, pitem);
+ gfxSystemUnlock();
+
+ return res;
+ }
+ bool_t gfxQueueASyncIsInI(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem) {
+ gfxQueueASyncItem *pi;
+
for(pi = pqueue->head; pi; pi = pi->next) {
- if (pi == pitem) {
- gfxSystemUnlock();
+ if (pi == pitem)
return TRUE;
- }
}
- gfxSystemUnlock();
-
return FALSE;
}
#endif
@@ -122,40 +138,57 @@
return pi;
}
+ gfxQueueGSyncItem *gfxQueueGSyncGetI(gfxQueueGSync *pqueue) {
+ gfxQueueGSyncItem *pi;
- void gfxQueueGSyncPut(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
- pitem->next = 0;
+ if (!gfxSemWaitI(&pqueue->sem))
+ return 0;
+ pi = pqueue->head;
+ pqueue->head = pi->next;
+ pi->next = 0;
+ return pi;
+ }
+
+ void gfxQueueGSyncPut(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
gfxSystemLock();
+ gfxQueueGSyncPutI(pqueue, pitem);
+ gfxSystemUnlock();
+ }
+ void gfxQueueGSyncPutI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+ pitem->next = 0;
if (!pqueue->head) {
pqueue->head = pqueue->tail = pitem;
} else {
pqueue->tail->next = pitem;
pqueue->tail = pitem;
}
- gfxSystemUnlock();
-
- gfxSemSignal(&pqueue->sem);
+ gfxSemSignalI(&pqueue->sem);
}
void gfxQueueGSyncPush(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
gfxSystemLock();
+ gfxQueueGSyncPushI(pqueue, pitem);
+ gfxSystemUnlock();
+ }
+ void gfxQueueGSyncPushI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
pitem->next = pqueue->head;
pqueue->head = pitem;
if (!pitem->next)
pqueue->tail = pitem;
- gfxSystemUnlock();
-
- gfxSemSignal(&pqueue->sem);
+ gfxSemSignalI(&pqueue->sem);
}
void gfxQueueGSyncRemove(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+ gfxSystemLock();
+ gfxQueueGSyncRemoveI(pqueue, pitem);
+ gfxSystemUnlock();
+ }
+ void gfxQueueGSyncRemoveI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
gfxQueueGSyncItem *pi;
if (!pitem)
return;
-
- gfxSystemLock();
if (pqueue->head) {
if (pqueue->head == pitem) {
pqueue->head = pitem->next;
@@ -172,25 +205,24 @@
}
}
}
- gfxSystemUnlock();
- }
-
- bool_t gfxQueueGSyncIsEmpty(gfxQueueGSync *pqueue) {
- return pqueue->head == 0;
}
bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem) {
- gfxQueueGSyncItem *pi;
+ bool_t res;
gfxSystemLock();
+ res = gfxQueueGSyncIsInI(pqueue, pitem);
+ gfxSystemUnlock();
+
+ return res;
+ }
+ bool_t gfxQueueGSyncIsInI(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem) {
+ gfxQueueGSyncItem *pi;
+
for(pi = pqueue->head; pi; pi = pi->next) {
- if (pi == pitem) {
- gfxSystemUnlock();
+ if (pi == pitem)
return TRUE;
- }
}
- gfxSystemUnlock();
-
return FALSE;
}
#endif
@@ -213,7 +245,7 @@
pi->next = 0;
gfxSystemUnlock();
- gfxSemSignalI(&pi->sem);
+ gfxSemSignal(&pi->sem);
gfxSemDestroy(&pi->sem);
return pi;
@@ -281,25 +313,24 @@
gfxSystemUnlock();
}
- bool_t gfxQueueFSyncIsEmpty(gfxQueueFSync *pqueue) {
- return pqueue->head == 0;
- }
-
bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem) {
- gfxQueueASyncItem *pi;
+ bool_t res;
gfxSystemLock();
+ res = gfxQueueFSyncIsInI(pqueue, pitem);
+ gfxSystemUnlock();
+
+ return res;
+ }
+ bool_t gfxQueueFSyncIsInI(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem) {
+ gfxQueueASyncItem *pi;
+
for(pi = pqueue->head; pi; pi = pi->next) {
- if (pi == pitem) {
- gfxSystemUnlock();
+ if (pi == pitem)
return TRUE;
- }
}
- gfxSystemUnlock();
-
return FALSE;
}
#endif
#endif /* GFX_USE_GQUEUE */
-
diff --git a/src/gqueue/sys_defs.h b/src/gqueue/sys_defs.h
index 447ea5be..4351d4ad 100644
--- a/src/gqueue/sys_defs.h
+++ b/src/gqueue/sys_defs.h
@@ -105,11 +105,15 @@ void gfxQueueFSyncInit(gfxQueueFSync *pqueue);
* @param[in] ms The maxmimum time to wait for an item. For ASync queues this parameter is
* not specified as TIME_IMMEDIATE is assumed.
*
+ * @note The routines ending in "I" are interrupt/system/iclass level routines.
+ *
* @api
* @{
*/
gfxQueueASyncItem *gfxQueueASyncGet(gfxQueueASync *pqueue);
+gfxQueueASyncItem *gfxQueueASyncGetI(gfxQueueASync *pqueue);
gfxQueueGSyncItem *gfxQueueGSyncGet(gfxQueueGSync *pqueue, delaytime_t ms);
+gfxQueueGSyncItem *gfxQueueGSyncGetI(gfxQueueGSync *pqueue);
gfxQueueFSyncItem *gfxQueueFSyncGet(gfxQueueFSync *pqueue, delaytime_t ms);
/* @} */
@@ -124,12 +128,15 @@ gfxQueueFSyncItem *gfxQueueFSyncGet(gfxQueueFSync *pqueue, delaytime_t ms);
* @note FSync: Use a delay time of TIME_IMMEDIATE if you don't want to wait until the
* item is removed from the queue. Note that even if the timeout occurs - the item
* remains in the queue.
+ * @note The routines ending in "I" are interrupt/system/iclass level routines.
*
* @api
* @{
*/
void gfxQueueASyncPut(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+void gfxQueueASyncPutI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
void gfxQueueGSyncPut(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+void gfxQueueGSyncPutI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
bool_t gfxQueueFSyncPut(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms);
/* @} */
@@ -141,6 +148,7 @@ bool_t gfxQueueFSyncPut(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delayti
* @{
*/
#define gfxQueueASyncPop(pqueue) gfxQueueASyncGet(pqueue)
+#define gfxQueueASyncPopI(pqueue) gfxQueueASyncGetI(pqueue)
#define gfxQueueGSyncPop(pqueue, ms) gfxQueueGSyncGet(pqueue, ms)
#define gfxQueueFSyncPop(pqueue, ms) gfxQueueFSyncGet(pqueue, ms)
/* @} */
@@ -156,12 +164,15 @@ bool_t gfxQueueFSyncPut(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delayti
* @note FSync: Use a delay time of TIME_IMMEDIATE if you don't want to wait until the
* item is removed from the queue. Note that even if the timeout occurs - the item
* remains in the queue.
+ * @note The routines ending in "I" are interrupt/system/iclass level routines.
*
* @api
* @{
*/
void gfxQueueASyncPush(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+void gfxQueueASyncPushI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
void gfxQueueGSyncPush(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+void gfxQueueGSyncPushI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
bool_t gfxQueueFSyncPush(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms);
/* @} */
@@ -175,12 +186,15 @@ bool_t gfxQueueFSyncPush(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delayt
* @note If the item isn't in the queue the routine just returns.
* @note If a process is waiting on the Put/Push operation for the item, that process
* will be signaled.
+ * @note The routines ending in "I" are interrupt/system/iclass level routines.
*
* @api
* @{
*/
void gfxQueueASyncRemove(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+void gfxQueueASyncRemoveI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
void gfxQueueGSyncRemove(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+void gfxQueueGSyncRemoveI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
void gfxQueueFSyncRemove(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem);
/* @} */
@@ -190,12 +204,17 @@ void gfxQueueFSyncRemove(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem);
*
* @param[in] pqueue A pointer to the queue
*
+ * @note The routines ending in "I" are interrupt/system/iclass level routines.
+ *
* @api
* @{
*/
-bool_t gfxQueueASyncIsEmpty(gfxQueueASync *pqueue);
-bool_t gfxQueueGSyncIsEmpty(gfxQueueGSync *pqueue);
-bool_t gfxQueueFSyncIsEmpty(gfxQueueFSync *pqueue);
+#define gfxQueueASyncIsEmpty(pqueue) ((pqueue)->head == 0)
+#define gfxQueueASyncIsEmptyI(pqueue) ((pqueue)->head == 0)
+#define gfxQueueGSyncIsEmpty(pqueue) ((pqueue)->head == 0)
+#define gfxQueueGSyncIsEmptyI(pqueue) ((pqueue)->head == 0)
+#define gfxQueueFSyncIsEmpty(pqueue) ((pqueue)->head == 0)
+#define gfxQueueFSyncIsEmptyI(pqueue) ((pqueue)->head == 0)
/* @} */
/**
@@ -206,13 +225,17 @@ bool_t gfxQueueFSyncIsEmpty(gfxQueueFSync *pqueue);
* @param[in] pitem A pointer to the queue item
*
* @note This operation may be expensive.
+ * @note The routines ending in "I" are interrupt/system/iclass level routines.
*
* @api
* @{
*/
bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem);
+bool_t gfxQueueASyncIsInI(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem);
bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem);
+bool_t gfxQueueGSyncIsInI(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem);
bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem);
+bool_t gfxQueueFSyncIsInI(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem);
/* @} */
/**
@@ -226,13 +249,17 @@ bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem);
* @note As that item is still on the queue, it should be treated as read-only. It could
* also be removed from the queue at any time by another thread (thereby altering the
* queue item).
+ * @note The routines ending in "I" are interrupt/system/iclass level routines.
*
* @api
* @{
*/
#define gfxQueueASyncPeek(pqueue) ((const gfxQueueASyncItem *)((pqueue)->head))
+#define gfxQueueASyncPeekI(pqueue) ((const gfxQueueASyncItem *)((pqueue)->head))
#define gfxQueueGSyncPeek(pqueue) ((const gfxQueueGSyncItem *)((pqueue)->head))
+#define gfxQueueGSyncPeekI(pqueue) ((const gfxQueueGSyncItem *)((pqueue)->head))
#define gfxQueueFSyncPeek(pqueue) ((const gfxQueueFSyncItem *)((pqueue)->head))
+#define gfxQueueFSyncPeekI(pqueue) ((const gfxQueueFSyncItem *)((pqueue)->head))
/* @} */
/**
@@ -246,13 +273,17 @@ bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem);
* @note As that item is still on the queue, it should be treated as read-only. It could
* also be removed from the queue at any time by another thread (thereby altering the
* queue item).
+ * @note The routines ending in "I" are interrupt/system/iclass level routines.
*
* @api
* @{
*/
#define gfxQueueASyncNext(pitem) ((const gfxQueueASyncItem *)((pitem)->next))
+#define gfxQueueASyncNextI(pitem) ((const gfxQueueASyncItem *)((pitem)->next))
#define gfxQueueGSyncNext(pitem) ((const gfxQueueGSyncItem *)((pitem)->next))
+#define gfxQueueGSyncNextI(pitem) ((const gfxQueueGSyncItem *)((pitem)->next))
#define gfxQueueFSyncNext(pitem) ((const gfxQueueFSyncItem *)((pitem)->next))
+#define gfxQueueFSyncNextI(pitem) ((const gfxQueueFSyncItem *)((pitem)->next))
/* @} */
#ifdef __cplusplus
diff --git a/src/gwin/console.c b/src/gwin/console.c
index 0fe4b722..fa93c79d 100644
--- a/src/gwin/console.c
+++ b/src/gwin/console.c
@@ -26,6 +26,14 @@
#define GCONSOLE_FLG_NOSTORE (GWIN_FIRST_CONTROL_FLAG<<0)
#define GCONSOLE_FLG_OVERRUN (GWIN_FIRST_CONTROL_FLAG<<1)
+// Meaning of our attribute bits.
+#define ESC_REDBIT 0x01
+#define ESC_GREENBIT 0x02
+#define ESC_BLUEBIT 0x04
+#define ESC_USECOLOR 0x08
+#define ESC_UNDERLINE 0x10
+#define ESC_BOLD 0x20
+
/*
* Stream interface implementation. The interface is write only
*/
@@ -58,6 +66,68 @@
};
#endif
+#if GWIN_CONSOLE_ESCSEQ
+ // Convert escape sequences to attributes
+ static bool_t ESCtoAttr(char c, uint8_t *pattr) {
+ uint8_t attr;
+
+ attr = pattr[0];
+ switch(c) {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ attr &= ~(ESC_REDBIT|ESC_GREENBIT|ESC_BLUEBIT);
+ attr |= (c - '0') | ESC_USECOLOR;
+ break;
+ case 'C':
+ attr &= ~(ESC_REDBIT|ESC_GREENBIT|ESC_BLUEBIT|ESC_USECOLOR);
+ break;
+ case 'u':
+ attr |= ESC_UNDERLINE;
+ break;
+ case 'U':
+ attr &= ~ESC_UNDERLINE;
+ break;
+ case 'b':
+ attr |= ESC_BOLD;
+ break;
+ case 'B':
+ attr &= ~ESC_BOLD;
+ break;
+ default:
+ return FALSE;
+ }
+ if (attr == pattr[0])
+ return FALSE;
+ pattr[0] = attr;
+ return TRUE;
+ }
+
+ static color_t ESCPrintColor(GConsoleObject *gcw) {
+ switch(gcw->currattr & (ESC_REDBIT|ESC_GREENBIT|ESC_BLUEBIT|ESC_USECOLOR)) {
+ case (ESC_USECOLOR):
+ return Black;
+ case (ESC_USECOLOR|ESC_REDBIT):
+ return Red;
+ case (ESC_USECOLOR|ESC_GREENBIT):
+ return Green;
+ case (ESC_USECOLOR|ESC_REDBIT|ESC_GREENBIT):
+ return Yellow;
+ case (ESC_USECOLOR|ESC_BLUEBIT):
+ return Blue;
+ case (ESC_USECOLOR|ESC_REDBIT|ESC_BLUEBIT):
+ return Magenta;
+ case (ESC_USECOLOR|ESC_GREENBIT|ESC_BLUEBIT):
+ return Cyan;
+ case (ESC_USECOLOR|ESC_REDBIT|ESC_GREENBIT|ESC_BLUEBIT):
+ return White;
+ default:
+ return gcw->g.color;
+ }
+ }
+#else
+ #define ESCPrintColor(gcw) ((gcw)->g.color)
+#endif
+
#if GWIN_CONSOLE_USE_HISTORY
static void HistoryDestroy(GWindowObject *gh) {
#define gcw ((GConsoleObject *)gh)
@@ -90,13 +160,25 @@
gcw->cx = 0;
gcw->cy = 0;
+ // Reset the current attributes
+ #if GWIN_CONSOLE_ESCSEQ
+ gcw->currattr = gcw->startattr;
+ #endif
+
// Print the buffer
gwinPutCharArray(gh, gcw->buffer, gcw->bufpos);
- #if !GWIN_CONSOLE_USE_CLEAR_LINES
+ #if GWIN_CONSOLE_USE_CLEAR_LINES
// Clear the remaining space
- if (gcw->cy + fy < gh->height)
- gdispGFillArea(gh->display, gh->x, gh->y+gcw->cy+fy, gh->width, gh->height-(gcw->cy+fy), gh->bgcolor);
+ {
+ coord_t y;
+
+ y = gcw->cy;
+ if (gcw->cx)
+ y += gdispGetFontMetric(gh->font, fontHeight);
+ if (y < gh->height)
+ gdispGFillArea(gh->display, gh->x, gh->y+y, gh->width, gh->height-y, gh->bgcolor);
+ }
#endif
// Turn back on storing of buffer contents
@@ -115,7 +197,7 @@
// Do we have enough space in the buffer
if (gcw->bufpos >= gcw->bufsize) {
- char * p;
+ char *p, *ep;
size_t dp;
/**
@@ -130,7 +212,13 @@
*/
// Remove one line from the start
- for(p = gcw->buffer; *p && *p != '\n'; p++);
+ ep = gcw->buffer+gcw->bufpos;
+ for(p = gcw->buffer; p < ep && *p != '\n'; p++) {
+ #if GWIN_CONSOLE_ESCSEQ
+ if (*p == 27)
+ ESCtoAttr(p[1], &gcw->startattr);
+ #endif
+ }
// Was there a newline?
if (*p != '\n')
@@ -153,7 +241,7 @@
* Scroll the history buffer by one line
*/
static void scrollBuffer(GConsoleObject *gcw) {
- char * p;
+ char *p, *ep;
size_t dp;
// Only scroll if we need to
@@ -167,7 +255,13 @@
}
// Remove one line from the start
- for(p = gcw->buffer; *p && *p != '\n'; p++);
+ ep = gcw->buffer+gcw->bufpos;
+ for(p = gcw->buffer; p < ep && *p != '\n'; p++) {
+ #if GWIN_CONSOLE_ESCSEQ
+ if (*p == 27)
+ ESCtoAttr(p[1], &gcw->startattr);
+ #endif
+ }
// Was there a newline, if not delete everything.
if (*p != '\n') {
@@ -205,6 +299,9 @@ static void AfterClear(GWindowObject *gh) {
gcw->cx = 0;
gcw->cy = 0;
clearBuffer(gcw);
+ #if GWIN_CONSOLE_ESCSEQ
+ gcw->startattr = gcw->currattr;
+ #endif
#undef gcw
}
@@ -239,6 +336,11 @@ GHandle gwinGConsoleCreate(GDisplay *g, GConsoleObject *gc, const GWindowInit *p
gc->cx = 0;
gc->cy = 0;
+ #if GWIN_CONSOLE_ESCSEQ
+ gc->startattr = gc->currattr = 0;
+ gc->escstate = 0;
+ #endif
+
gwinSetVisible((GHandle)gc, pInit->show);
return (GHandle)gc;
@@ -313,13 +415,54 @@ void gwinPutChar(GHandle gh, char c) {
#if GDISP_NEED_CLIP
gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height);
#endif
-
+
+ #if GWIN_CONSOLE_ESCSEQ
+ /**
+ * Handle escape sequences
+ * ESC color Change subsequent text color
+ * color: "0" = black, "1" = red, "2" = green, "3" = yellow, "4" = blue,
+ * "5" = magenta, "6" = cyan, "7" = white
+ * ESC C Revert subsequent text color to the window default
+ * ESC u Turn on underline
+ * ESC U Turn off underline
+ * ESC b Turn on bold
+ * ESC B Turn off bold
+ * ESC J Clear the window
+ */
+ switch (gcw->escstate) {
+ case 1:
+ gcw->escstate = 0;
+ if (ESCtoAttr(c, &gcw->currattr)) {
+ if (gcw->cx == 0 && gcw->cy == 0)
+ gcw->startattr = gcw->currattr;
+ else {
+ putCharInBuffer(gcw, 27);
+ putCharInBuffer(gcw, c);
+ }
+ } else {
+ switch(c) {
+ case 'J':
+ // Clear the console and reset the cursor
+ clearBuffer(gcw);
+ gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
+ gcw->cx = 0;
+ gcw->cy = 0;
+ gcw->startattr = gcw->currattr;
+ break;
+ }
+ }
+ return;
+ }
+ #endif
+
/**
* Special Characters:
*
* Carriage returns and line feeds (\r & \n) are handled in unix terminal cooked mode; that is,
* line feeds perform both actions and carriage-returns are ignored.
*
+ * if GWIN_CONSOLE_ESCSEQ is turned on then ESC is trapped ready for the escape command.
+ *
* All other characters are treated as printable.
*/
switch (c) {
@@ -339,12 +482,24 @@ void gwinPutChar(GHandle gh, char c) {
case '\r':
// gcw->cx = 0;
return;
+
+ #if GWIN_CONSOLE_ESCSEQ
+ case 27: // ESC
+ gcw->escstate = 1;
+ return;
+ #endif
}
// Characters with no width are ignored
if (!(width = gdispGetCharWidth(c, gh->font)))
return;
+ // Allow space for (very crude) bold
+ #if GWIN_CONSOLE_ESCSEQ
+ if ((gcw->currattr & ESC_BOLD))
+ width++;
+ #endif
+
// Do we need to go to the next line to fit this character?
if (gcw->cx + width >= gh->width) {
gcw->cx = 0;
@@ -378,6 +533,9 @@ void gwinPutChar(GHandle gh, char c) {
gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
gcw->cx = 0;
gcw->cy = 0;
+ #if GWIN_CONSOLE_ESCSEQ
+ gcw->startattr = gcw->currattr;
+ #endif
}
#endif
}
@@ -390,12 +548,23 @@ void gwinPutChar(GHandle gh, char c) {
// Draw the character
#if GWIN_CONSOLE_USE_FILLED_CHARS
- gdispGFillChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color, gh->bgcolor);
+ gdispGFillChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, ESCPrintColor(gcw), gh->bgcolor);
#else
- gdispGDrawChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color);
+ gdispGDrawChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, ESCPrintColor(gcw));
#endif
putCharInBuffer(gcw, c);
+ #if GWIN_CONSOLE_ESCSEQ
+ // Draw the underline
+ if ((gcw->currattr & ESC_UNDERLINE))
+ gdispGDrawLine(gh->display, gh->x + gcw->cx, gh->y + gcw->cy + fy - gdispGetFontMetric(gh->font, fontDescendersHeight),
+ gh->x + gcw->cx + width + gdispGetFontMetric(gh->font, fontCharPadding), gh->y + gcw->cy + fy - gdispGetFontMetric(gh->font, fontDescendersHeight),
+ ESCPrintColor(gcw));
+ // Bold (very crude)
+ if ((gcw->currattr & ESC_BOLD))
+ gdispGDrawChar(gh->display, gh->x + gcw->cx + 1, gh->y + gcw->cy, c, gh->font, ESCPrintColor(gcw));
+ #endif
+
// Update the cursor
gcw->cx += width + gdispGetFontMetric(gh->font, fontCharPadding);
diff --git a/src/gwin/console.h b/src/gwin/console.h
index 252b627e..14bc7eb3 100644
--- a/src/gwin/console.h
+++ b/src/gwin/console.h
@@ -31,6 +31,12 @@ typedef struct GConsoleObject {
GWindowObject g;
coord_t cx, cy; // Cursor position
+ #if GWIN_CONSOLE_ESCSEQ
+ uint8_t startattr; // ANSI-like escape sequences
+ uint8_t currattr;
+ uint16_t escstate;
+ #endif
+
#if GWIN_CONSOLE_USE_HISTORY
char * buffer; // buffer to store console content
size_t bufsize; // size of buffer
diff --git a/src/gwin/sys_options.h b/src/gwin/sys_options.h
index 02467916..e7bb93b4 100644
--- a/src/gwin/sys_options.h
+++ b/src/gwin/sys_options.h
@@ -160,6 +160,25 @@
#define GWIN_CONSOLE_USE_FLOAT FALSE
#endif
/**
+ * @brief Console windows support escape sequences to control display
+ * @details Defaults to FALSE
+ *
+ * @note
+ * Currently supported:
+ * ESC color Change subsequent text color
+ * color: "0" = black, "1" = red, "2" = green, "3" = yellow, "4" = blue,
+ * "5" = magenta, "6" = cyan, "7" = white
+ * ESC C Revert subsequent text color to the window default
+ * ESC u Turn on underline
+ * ESC U Turn off underline
+ * ESC b Turn on bold
+ * ESC B Turn off bold
+ * ESC J Clear the window
+ */
+ #ifndef GWIN_CONSOLE_ESCSEQ
+ #define GWIN_CONSOLE_ESCSEQ FALSE
+ #endif
+ /**
* @brief Console Windows need BaseStreamSequential support (ChibiOS only)
* @details Defaults to FALSE
* @note To use the ChibiOS basestream functions such as chprintf()