aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/multiple/Win32/gdisp_lld.c55
-rw-r--r--gfx.mk1
-rw-r--r--gfxconf.example.h8
-rw-r--r--include/gfx.h10
-rw-r--r--include/gfx_rules.h12
-rw-r--r--include/gos/chibios.h37
-rw-r--r--include/gos/gos.h227
-rw-r--r--include/gos/win32.h74
-rw-r--r--include/gqueue/gqueue.h229
-rw-r--r--include/gqueue/options.h66
-rw-r--r--include/gwin/console.h29
-rw-r--r--include/gwin/options.h18
-rw-r--r--src/gos/chibios.c114
-rw-r--r--src/gos/win32.c81
-rw-r--r--src/gqueue/gqueue.c255
-rw-r--r--src/gqueue/gqueue.mk1
-rw-r--r--src/gwin/button.c4
-rw-r--r--src/gwin/console.c201
18 files changed, 1107 insertions, 315 deletions
diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c
index 221442ef..7364300a 100644
--- a/drivers/multiple/Win32/gdisp_lld.c
+++ b/drivers/multiple/Win32/gdisp_lld.c
@@ -24,6 +24,15 @@
#include <wingdi.h>
#include <assert.h>
+/* Our threading model - ChibiOS or Win32 */
+#ifndef GDISP_THREAD_CHIBIOS
+ #if GFX_USE_OS_WIN32
+ #define GDISP_THREAD_CHIBIOS FALSE
+ #else
+ #define GDISP_THREAD_CHIBIOS TRUE
+ #endif
+#endif
+
#ifndef GDISP_SCREEN_WIDTH
#define GDISP_SCREEN_WIDTH 640
#endif
@@ -230,10 +239,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
return 0;
}
-static DWORD WINAPI WindowThread(LPVOID lpParameter) {
- (void)lpParameter;
-
- MSG msg;
+static void InitWindow(void) {
HANDLE hInstance;
WNDCLASS wc;
RECT rect;
@@ -274,14 +280,39 @@ static DWORD WINAPI WindowThread(LPVOID lpParameter) {
ShowWindow(winRootWindow, SW_SHOW);
UpdateWindow(winRootWindow);
isReady = TRUE;
+}
- while(GetMessage(&msg, NULL, 0, 0) > 0) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
+#if GDISP_THREAD_CHIBIOS
+ static DECLARESTACK(waWindowThread, 1024);
+ static threadreturn_t WindowThread(void *param) {
+ (void)param;
+ MSG msg;
+
+ InitWindow();
+ do {
+ gfxSleepMilliseconds(1);
+ while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ } while (msg.message != WM_QUIT);
+ ExitProcess(0);
+ return msg.wParam;
}
- ExitProcess(0);
- return msg.wParam;
-}
+#else
+ static DWORD WINAPI WindowThread(LPVOID param) {
+ (void)param;
+ MSG msg;
+
+ InitWindow();
+ while(GetMessage(&msg, NULL, 0, 0) > 0) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ ExitProcess(0);
+ return msg.wParam;
+ }
+#endif
/*===========================================================================*/
/* Driver exported functions. */
@@ -312,7 +343,11 @@ bool_t gdisp_lld_init(void) {
wHeight = GDISP_SCREEN_HEIGHT;
/* Initialise the window */
+#if GDISP_THREAD_CHIBIOS
+ gfxCreateThread(waWindowThread, sizeof(waWindowThread), HIGH_PRIORITY, WindowThread, 0);
+#else
CreateThread(0, 0, WindowThread, 0, 0, 0);
+#endif
while (!isReady)
Sleep(1);
diff --git a/gfx.mk b/gfx.mk
index c476e096..7cd19d28 100644
--- a/gfx.mk
+++ b/gfx.mk
@@ -7,6 +7,7 @@ GFXINC += $(GFXLIB)/include
GFXSRC += $(GFXLIB)/src/gfx.c
include $(GFXLIB)/src/gos/gos.mk
+include $(GFXLIB)/src/gqueue/gqueue.mk
include $(GFXLIB)/src/gdisp/gdisp.mk
include $(GFXLIB)/src/tdisp/tdisp.mk
include $(GFXLIB)/src/gevent/gevent.mk
diff --git a/gfxconf.example.h b/gfxconf.example.h
index 5ba739a9..48e39b31 100644
--- a/gfxconf.example.h
+++ b/gfxconf.example.h
@@ -25,6 +25,7 @@
#define GFX_USE_GWIN FALSE
#define GFX_USE_GEVENT FALSE
#define GFX_USE_GTIMER FALSE
+#define GFX_USE_GQUEUE FALSE
#define GFX_USE_GINPUT FALSE
#define GFX_USE_GADC FALSE
#define GFX_USE_GAUDIN FALSE
@@ -90,6 +91,11 @@
/* Features for the GTIMER subsystem. */
/* NONE */
+/* Features for the GQUEUE subsystem. */
+#define GQUEUE_NEED_ASYNC FALSE
+#define GQUEUE_NEED_GSYNC FALSE
+#define GQUEUE_NEED_FSYNC FALSE
+
/* Features for the GINPUT subsystem. */
#define GINPUT_NEED_MOUSE FALSE
#define GINPUT_NEED_KEYBOARD FALSE
@@ -118,6 +124,8 @@
#define GTIMER_THREAD_WORKAREA_SIZE 512
#define GADC_MAX_LOWSPEED_DEVICES 4
#define GWIN_BUTTON_LAZY_RELEASE FALSE
+ #define GWIN_CONSOLE_USE_BASESTREAM FALSE
+ #define GWIN_CONSOLE_USE_FLOAT FALSE
*/
/* Optional Low Level Driver Definitions */
diff --git a/include/gfx.h b/include/gfx.h
index 84aec39f..ac9a5382 100644
--- a/include/gfx.h
+++ b/include/gfx.h
@@ -87,6 +87,14 @@
#define GFX_USE_GTIMER FALSE
#endif
/**
+ * @brief GFX Queue API
+ * @details Defaults to FALSE
+ * @details Provides queue management.
+ */
+ #ifndef GFX_USE_GQUEUE
+ #define GFX_USE_GQUEUE FALSE
+ #endif
+ /**
* @brief GFX Input Device API
* @details Defaults to FALSE
* @note Also add the specific hardware drivers to your makefile.
@@ -143,6 +151,7 @@
*/
#include "gos/options.h"
#include "gmisc/options.h"
+#include "gqueue/options.h"
#include "gevent/options.h"
#include "gtimer/options.h"
#include "gdisp/options.h"
@@ -164,6 +173,7 @@
*/
#include "gos/gos.h"
#include "gmisc/gmisc.h"
+#include "gqueue/gqueue.h"
#include "gevent/gevent.h"
#include "gtimer/gtimer.h"
#include "gdisp/gdisp.h"
diff --git a/include/gfx_rules.h b/include/gfx_rules.h
index 4fff2d21..4b7e9506 100644
--- a/include/gfx_rules.h
+++ b/include/gfx_rules.h
@@ -101,6 +101,15 @@
#if GDISP_NEED_MULTITHREAD && GDISP_NEED_ASYNC
#error "GDISP: Only one of GDISP_NEED_MULTITHREAD and GDISP_NEED_ASYNC should be defined."
#endif
+ #if GDISP_NEED_ASYNC && !(GFX_USE_GQUEUE && GQUEUE_NEED_GSYNC)
+ #if GFX_DISPLAY_RULE_WARNINGS
+ #warning "GDISP: GFX_USE_GQUEUE or GQUEUE_NEED_GSYNC is not TRUE. It has been turned on for you."
+ #endif
+ #undef GFX_USE_GQUEUE
+ #define GFX_USE_GQUEUE TRUE
+ #undef GQUEUE_NEED_GSYNC
+ #define GQUEUE_NEED_GSYNC TRUE
+ #endif
#endif
#if GFX_USE_TDISP
@@ -141,6 +150,9 @@
#if GFX_USE_GAUDOUT
#endif
+#if GFX_USE_GQUEUE
+#endif
+
#if GFX_USE_GMISC
#endif
diff --git a/include/gos/chibios.h b/include/gos/chibios.h
index 37bf93ee..1fa93141 100644
--- a/include/gos/chibios.h
+++ b/include/gos/chibios.h
@@ -67,17 +67,6 @@ typedef struct {
#define gfxMutex Mutex
-typedef struct gfxQueue {
- struct gfxQueueItem *head;
- struct gfxQueueItem *tail;
- Semaphore sem;
- } gfxQueue;
-
-typedef struct gfxQueueItem {
- struct gfxQueueItem *next;
- Semaphore sem;
- } gfxQueueItem;
-
/*===========================================================================*/
/* Function declarations. */
/*===========================================================================*/
@@ -90,30 +79,24 @@ extern "C" {
#define gfxExit() chSysHalt()
#define gfxAlloc(sz) chHeapAlloc(NULL, sz)
#define gfxFree(ptr) chHeapFree(ptr)
+#define gfxYield() chThdYield()
+#define gfxSystemTicks() chTimeNow()
+#define gfxMillisecondsToTicks(ms) MS2ST(ms)
+#define gfxSystemLock() chSysLock()
+#define gfxSystemUnlock() chSysUnlock()
+#define gfxMutexInit(pmutex) chMtxInit(pmutex)
+#define gfxMutexDestroy(pmutex) ;
+#define gfxMutexEnter(pmutex) chMtxLock(pmutex)
+#define gfxMutexExit(pmutex) chMtxUnlock()
void gfxSleepMilliseconds(delaytime_t ms);
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);
void gfxSemSignal(gfxSem *psem);
void gfxSemSignalI(gfxSem *psem);
#define gfxSemCounterI(psem) ((psem)->sem.s_cnt)
#define gfxSemCounter(psem) ((psem)->sem.s_cnt)
-#define gfxSystemTicks() chTimeNow()
-#define gfxMillisecondsToTicks(ms) MS2ST(ms)
-#define gfxYield() chThdYield()
-#define gfxSystemLock() chSysLock()
-#define gfxSystemUnlock() chSysUnlock()
-#define gfxMutexInit(pmutex) chMtxInit(pmutex)
-#define gfxMutexEnter(pmutex) chMtxLock(pmutex)
-#define gfxMutexExit(pmutex) chMtxUnlock()
-void gfxQueueInit(gfxQueue *pqueue);
-gfxQueueItem * gfxQueueGet(gfxQueue *pqueue, delaytime_t ms);
-bool_t gfxQueuePut(gfxQueue *pqueue, gfxQueueItem *pitem, delaytime_t ms);
-#define gfxQueuePop(q) gfxQueueGet(q)
-bool_t gfxQueuePush(gfxQueue *pqueue, gfxQueueItem *pitem, delaytime_t ms);
-void gfxQueueRemove(gfxQueue *pqueue, gfxQueueItem *pitem);
-bool_t gfxQueueIsEmpty(gfxQueue *pqueue);
-bool_t gfxQueueIsIn(gfxQueue *pqueue, gfxQueueItem *pitem);
bool_t gfxCreateThread(void *stackarea, size_t stacksz, threadpriority_t prio, gfxThreadFunction fn, void *param);
#ifdef __cplusplus
diff --git a/include/gos/gos.h b/include/gos/gos.h
index 04799540..d979cd27 100644
--- a/include/gos/gos.h
+++ b/include/gos/gos.h
@@ -37,11 +37,6 @@
/*===========================================================================*/
/**
- * @brief A function for a new thread to execute.
- */
- typedef threadreturn_t (*gfxThreadFunction)(void *param);
-
- /**
* @brief Various integer sizes
* @note Your platform may use slightly different definitions to these
* @{
@@ -67,6 +62,10 @@
typedef int threadreturn_t;
typedef int threadpriority_t;
/**
+ * @brief A function for a new thread to execute.
+ */
+ typedef threadreturn_t (*gfxThreadFunction)(void *param);
+ /**
* @}
*
* @brief Various platform (and operating system) constants
@@ -77,7 +76,7 @@
#define TRUE 1
#define TIME_IMMEDIATE 0
#define TIME_INFINITE ((delaytime_t)-1)
- #define MAX_SEMAPHORE_COUNT ((semcount_t)-1)
+ #define MAX_SEMAPHORE_COUNT ((semcount_t)(((unsigned long)((semcount_t)(-1))) >> 1))
#define LOW_PRIORITY 0
#define NORMAL_PRIORITY 1
#define HIGH_PRIORITY 2
@@ -96,18 +95,6 @@
*/
typedef struct {} gfxMutex;
- /**
- * @brief A queue
- * @note Your operating system will have a proper definition for this structure
- */
- typedef struct {} gfxQueue;
-
- /**
- * @brief A queue item
- * @note Your operating system will have a proper definition for this structure
- */
- typedef struct {} gfxQueueItem;
-
/*===========================================================================*/
/* Function declarations. */
/*===========================================================================*/
@@ -152,6 +139,15 @@
void gfxFree(void *ptr);
/**
+ * @brief Yield the current thread
+ * @details Give up the rest of the current time slice for this thread in order to give other threads
+ * a chance to run.
+ *
+ * @api
+ */
+ void gfxYield(void);
+
+ /**
* @brief Put the current thread to sleep for the specified period in milliseconds
*
* @param[in] ms The number milliseconds to sleep
@@ -177,83 +173,6 @@
void gfxSleepMicroseconds(delaytime_t ms);
/**
- * @brief Initialise a Counted Semaphore
- *
- * @param[in] psem A pointer to the semaphore
- * @param[in] val The initial value of the semaphore
- * @param[in] limit The maxmimum value of the semaphore
- *
- * @note Operations defined for counted semaphores:
- * Signal: 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
- * ignored.
- * Wait: The semaphore counter is decreased and if the result becomes negative the thread is queued
- * in the semaphore and suspended.
- *
- * @api
- */
- void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
-
- /**
- * @brief Wait on a semaphore
- * @details The semaphore counter is decreased and if the result becomes negative the thread waits for it to become
- * non-negative again
- * @return FALSE if the wait timeout occurred otherwise TRUE
- *
- * @param[in] psem A pointer to the semaphore
- * @param[in] ms The maxmimum time to wait for the semaphore
- *
- * @api
- */
- bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
-
- /**
- * @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
- * ignored.
- *
- * @param[in] psem A pointer to the semaphore
- *
- * @api
- */
- void gfxSemSignal(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
- * ignored.
- *
- * @param[in] psem A pointer to the semaphore
- *
- * @iclass
- * @api
- */
- void gfxSemSignalI(gfxSem *psem);
-
- /**
- * @brief Get the current semaphore count
- * @return The current semaphore count
- *
- * @param[in] psem A pointer to the semaphore
- *
- * @api
- */
- semcount_t gfxSemCounter(gfxSem *pSem);
-
- /**
- * @brief Get the current semaphore count
- * @return The current semaphore count
- *
- * @param[in] psem A pointer to the semaphore
- *
- * @iclass
- * @api
- */
- semcount_t gfxSemCounterI(gfxSem *pSem);
-
- /**
* @brief Get the current operating system tick time
* @return The current tick time
*
@@ -283,15 +202,6 @@
systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
/**
- * @brief Yield the current thread
- * @details Give up the rest of the current time slice for this thread in order to give other threads
- * a chance to run.
- *
- * @api
- */
- void gfxYield(void);
-
- /**
* @brief Lock the operating system to protect a sequence of code
*
* @note Calling this will lock out all other threads from executing even at interrupt level
@@ -327,6 +237,15 @@
void gfxMutexInit(gfxMutex *pmutex);
/**
+ * @brief Destroy a Mutex.
+ *
+ * @param[in] pmutex A pointer to the mutex
+ *
+ * @api
+ */
+ void gfxMutexDestroy(gfxMutex *pmutex);
+
+ /**
* @brief Enter the critical code region protected by the mutex.
* @details Blocks until there is no other thread in the critical region.
*
@@ -347,104 +266,92 @@
void gfxMutexExit(gfxMutex *pmutex);
/**
- * @brief Initialise a queue.
- *
- * @param[in] pqueue A pointer to the queue
- *
- * @note Whilst queues are normally FIFO, a GFX queue also supports push and pop operations.
- * A pop operation is the same as normal get from the queue but a push places the item
- * at the head of the queue instead of the tail (as a put would).
+ * @brief Initialise a Counted Semaphore
*
- * @api
- */
- void gfxQueueInit(gfxQueue *pqueue);
-
- /**
- * @brief Get an item from the head of the queue.
- * @return NULL if the timeout expires before an item is available
+ * @param[in] psem A pointer to the semaphore
+ * @param[in] val The initial value of the semaphore
+ * @param[in] limit The maxmimum value of the semaphore
*
- * @param[in] pqueue A pointer to the queue
- * @param[in] ms The maxmimum time to wait for an item
+ * @note Operations defined for counted semaphores:
+ * Signal: 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
+ * ignored.
+ * Wait: The semaphore counter is decreased and if the result becomes negative the thread is queued
+ * in the semaphore and suspended.
*
* @api
*/
- gfxQueueItem * gfxQueueGet(gfxQueue *pqueue, delaytime_t ms);
+ void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
/**
- * @brief Put an item on the end of the queue.
- * @return FALSE on timeout, otherwise TRUE
+ * @brief Destroy a Counted Semaphore
*
- * @param[in] pqueue A pointer to the queue
- * @param[in] pitem A pointer to the queue item
- * @param[in] ms The maxmimum time to wait for an item to be removed from the queue
+ * @param[in] psem A pointer to the semaphore
*
- * @note Use a delay time of TIME_IMMEDIATE if you don't want to wait until the
- * item is removed from the queue
+ * @note Any threads waiting on the semaphore will be released
*
* @api
*/
- bool_t gfxQueuePut(gfxQueue *pqueue, gfxQueueItem *pitem, delaytime_t ms);
+ void gfxSemDestroy(gfxSem *psem);
/**
- * @brief Pop an item from the head of the queue.
- * @return NULL if there are no more items on the queue
+ * @brief Wait on a semaphore
+ * @details The semaphore counter is decreased and if the result becomes negative the thread waits for it to become
+ * non-negative again
+ * @return FALSE if the wait timeout occurred otherwise TRUE
*
- * @param[in] pqueue A pointer to the queue
+ * @param[in] psem A pointer to the semaphore
+ * @param[in] ms The maxmimum time to wait for the semaphore
*
* @api
*/
- #define gfxQueuePop(pqueue, ms) gfxQueueGet(pqueue, ms)
+ bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
/**
- * @brief Push an item into the start of the queue.
- * @return FALSE on timeout, otherwise TRUE
- *
- * @param[in] pqueue A pointer to the queue
- * @param[in] pitem A pointer to the queue item
- * @param[in] ms The maxmimum time to wait for an item to be popped
+ * @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
+ * ignored.
*
- * @note Use a delay time of TIME_IMMEDIATE if you don't want to wait until the
- * item is removed from the queue
+ * @param[in] psem A pointer to the semaphore
*
* @api
*/
- bool_t gfxQueuePush(gfxQueue *pqueue, gfxQueueItem *pitem, delaytime_t ms);
+ void gfxSemSignal(gfxSem *psem);
/**
- * @brief Remove an item from the queue.
- * @note Removes the specified item from the queue whereever it is in the queue
- *
- * @param[in] pqueue A pointer to the queue
- * @param[in] pitem A pointer to the queue item
+ * @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
+ * ignored.
*
- * @note If the item isn't in the queue the routine just returns.
+ * @param[in] psem A pointer to the semaphore
*
+ * @iclass
* @api
*/
- void gfxQueueRemove(gfxQueue *pqueue, gfxQueueItem *pitem);
+ void gfxSemSignalI(gfxSem *psem);
/**
- * @brief Is the queue empty?
- * @return TRUE if the queue is empty
+ * @brief Get the current semaphore count
+ * @return The current semaphore count
*
- * @param[in] pqueue A pointer to the queue
+ * @param[in] psem A pointer to the semaphore
*
* @api
*/
- bool_t gfxQueueIsEmpty(gfxQueue *pqueue);
+ semcount_t gfxSemCounter(gfxSem *pSem);
/**
- * @brief Is an item in the queue?
- * @return TRUE if the item is in the queue?
- *
- * @param[in] pqueue A pointer to the queue
- * @param[in] pitem A pointer to the queue item
+ * @brief Get the current semaphore count
+ * @return The current semaphore count
*
- * @note This operation may be expensive.
+ * @param[in] psem A pointer to the semaphore
*
+ * @iclass
* @api
*/
- bool_t gfxQueueIsIn(gfxQueue *pqueue, gfxQueueItem *pitem);
+ semcount_t gfxSemCounterI(gfxSem *pSem);
/**
* @brief Start a new thread.
diff --git a/include/gos/win32.h b/include/gos/win32.h
index a6f28865..80a1f430 100644
--- a/include/gos/win32.h
+++ b/include/gos/win32.h
@@ -26,6 +26,80 @@
#define _GOS_WIN32_H
#if GFX_USE_OS_WIN32
+
+//#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+/**
+ * size_t
+ * TRUE, FALSE
+ * are already defined by Win32
+ */
+typedef __int8 bool_t;
+typedef __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef DWORD delaytime_t;
+typedef DWORD systemticks_t;
+typedef LONG semcount_t;
+#define threadreturn_t DWORD WINAPI
+typedef int threadpriority_t;
+
+typedef threadreturn_t (*gfxThreadFunction)(void *param);
+
+#define TIME_IMMEDIATE 0
+#define TIME_INFINITE INFINITE
+#define MAX_SEMAPHORE_COUNT ((semcount_t)(((unsigned long)((semcount_t)(-1))) >> 1))
+#define LOW_PRIORITY THREAD_PRIORITY_BELOW_NORMAL
+#define NORMAL_PRIORITY THREAD_PRIORITY_NORMAL
+#define HIGH_PRIORITY THREAD_PRIORITY_ABOVE_NORMAL
+#define DECLARESTACK(name, sz) uint8_t name[0];
+
+typedef HANDLE gfxSem;
+typedef HANDLE gfxMutex;
+
+#define gfxExit() ExitProcess(0)
+#define gfxAlloc(sz) malloc(sz)
+#define gfxFree(ptr) free(ptr)
+#define gfxSleepMilliseconds(ms) Sleep(ms)
+#define gfxYield() Sleep(0)
+#define gfxSystemTicks() GetTickCount()
+#define gfxMillisecondsToTicks(ms) (ms)
+#define gfxMutexInit(pmutex) *(pmutex) = CreateMutex(NULL, FALSE, NULL)
+#define gfxMutexDestory(pmutex) CloseHandle(*(pmutex))
+#define gfxMutexEnter(pmutex) WaitForSingleObject(*(pmutex), INFINITE)
+#define gfxMutexExit(pmutex) ReleaseMutex(*(pmutex))
+#define gfxSemInit(psem, val, limit) *(psem) = CreateSemaphore(NULL, val, limit, NULL)
+#define gfxSemDestory(psem) CloseHandle(*(psem))
+#define gfxSemSignal(psem) ReleaseSemaphore(*(psem), 1, NULL)
+#define gfxSemSignalI(psem) ReleaseSemaphore(*(psem), 1, NULL)
+#define gfxSemCounterI(psem) gfxSemCounter(psem)
+
+/*===========================================================================*/
+/* Function declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gfxHalt(const char *msg);
+void gfxSleepMicroseconds(delaytime_t ms);
+bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
+semcount_t gfxSemCounter(gfxSem *pSem);
+void gfxSystemLock(void);
+void gfxSystemUnlock(void);
+bool_t gfxCreateThread(void *stackarea, size_t stacksz, threadpriority_t prio, gfxThreadFunction fn, void *param);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
#endif /* GFX_USE_OS_WIN32 */
#endif /* _GOS_WIN32_H */
diff --git a/include/gqueue/gqueue.h b/include/gqueue/gqueue.h
new file mode 100644
index 00000000..deeca93b
--- /dev/null
+++ b/include/gqueue/gqueue.h
@@ -0,0 +1,229 @@
+/*
+ ChibiOS/GFX - Copyright (C) 2012, 2013
+ Joel Bodenmann aka Tectu <joel@unormal.org>
+
+ This file is part of ChibiOS/GFX.
+
+ ChibiOS/GFX is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/GFX is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @file include/gqueue/gqueue.h
+ * @brief GQUEUE header file.
+ *
+ * @addtogroup GQUEUE
+ * @brief GQUEUE provides queue management. There are 3 types of queues:
+ * <ul><li><b>Asynchronous Queues (ASync) </b> - Queue operations never block</li>
+ * <li><b>Get Synchronous Queues (GSync) </b> - Queue Get operations block until something is placed in the Queue</li>
+ * <li><b>Put Synchronous Queues (PSync)</b> - Queue Put operations block until the element is removed from the Queue</li>
+ * <li><b>Fully Synchronous Queues (FSync)</b> - Queue GET and Put operations block</li>
+ * </ul>
+ * We need 4 types of queues even though fully synchronous queues support all operations including asynchronous
+ * operations because fully synchronous queues have the highest storage requirements. The other queue types are
+ * optimizations. Efficiency IS important to use (particularly RAM efficiency).
+ * In practice we only implement ASync, GSync and FSync queues as PSync queues are of dubious value.
+ * @{
+ */
+
+#ifndef _GQUEUE_H
+#define _GQUEUE_H
+
+#if GFX_USE_GQUEUE || defined(__DOXYGEN__)
+
+/**
+ * @brief A queue
+ * @{
+ */
+typedef struct gfxQueueASync {
+ struct gfxQueueASyncItem *head;
+ struct gfxQueueASyncItem *tail;
+ } gfxQueueAsync;
+typedef struct gfxQueueGSync {
+ struct gfxQueueGSyncItem *head;
+ struct gfxQueueGSyncItem *tail;
+ gfxSem sem;
+ } gfxQueueGSync;
+typedef struct gfxQueueFSync {
+ struct gfxQueueFSyncItem *head;
+ struct gfxQueueFSyncItem *tail;
+ gfxSem sem;
+ } gfxQueueGSync;
+/* @} */
+
+/**
+ * @brief A queue item
+ * @{
+ */
+typedef struct gfxQueueASyncItem {
+ struct gfxQueueASyncItem *next;
+ } gfxQueueASyncItem;
+typedef struct gfxQueueGSyncItem {
+ struct gfxQueueGSyncItem *next;
+ } gfxQueueGSyncItem;
+typedef struct gfxQueueFSyncItem {
+ struct gfxQueueFSyncItem *next;
+ gfxSem sem;
+ } gfxQueueFSyncItem;
+/* @} */
+
+
+/*===========================================================================*/
+/* Function declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Initialise a queue.
+ *
+ * @param[in] pqueue A pointer to the queue
+ *
+ * @note Whilst queues are normally FIFO, a GFX queue also supports push and pop operations.
+ * A pop operation is the same as normal get from the queue but a push places the item
+ * at the head of the queue instead of the tail (as a put would).
+ *
+ * @api
+ * @{
+ */
+void gfxQueueASyncInit(gfxQueueASync *pqueue);
+void gfxQueueGSyncInit(gfxQueueGSync *pqueue);
+void gfxQueueFSyncInit(gfxQueueFSync *pqueue);
+/* @} */
+
+/**
+ * @brief Get an item from the head of the queue.
+ * @return NULL if the timeout expires before an item is available
+ *
+ * @param[in] pqueue A pointer to the queue
+ * @param[in] ms The maxmimum time to wait for an item. For ASync queues this parameter is
+ * not specified as TIME_IMMEDIATE is assumed.
+ *
+ * @api
+ * @{
+ */
+gfxQueueASyncItem *gfxQueueASyncGet(gfxQueueASync *pqueue);
+gfxQueueGSyncItem *gfxQueueGSyncGet(gfxQueueGSync *pqueue, delaytime_t ms);
+gfxQueueFSyncItem *gfxQueueFSyncGet(gfxQueueFSync *pqueue, delaytime_t ms);
+/* @} */
+
+/**
+ * @brief Put an item on the end of the queue.
+ * @return none for ASync and GSync queues; For FSync queues - FALSE on timeout, otherwise TRUE
+ *
+ * @param[in] pqueue A pointer to the queue
+ * @param[in] pitem A pointer to the queue item
+ * @param[in] ms The maxmimum time to wait for an item to be removed from the queue (only for FSync queues)
+ *
+ * @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.
+ *
+ * @api
+ * @{
+ */
+void gfxQueueASyncPut(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+void gfxQueueGSyncPut(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+bool_t gfxQueueFSyncPut(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms);
+/* @} */
+
+/**
+ * @brief Pop an item from the head of the queue.
+ * @detail This is exactly the same as the Get operation above.
+ *
+ * @api
+ * @{
+ */
+#define gfxQueueASyncPop(pqueue) gfxQueueASyncGet(pqueue)
+#define gfxQueueGSyncPop(pqueue, ms) gfxQueueGSyncGet(pqueue, ms)
+#define gfxQueueFSyncPop(pqueue, ms) gfxQueueFSyncGet(pqueue, ms)
+/* @} */
+
+/**
+ * @brief Push an item into the start of the queue.
+ * @return none for ASync and GSync queues; For FSync queues - FALSE on timeout, otherwise TRUE
+ *
+ * @param[in] pqueue A pointer to the queue
+ * @param[in] pitem A pointer to the queue item
+ * @param[in] ms The maxmimum time to wait for an item to be popped (only for FSync queues)
+ *
+ * @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.
+ *
+ * @api
+ * @{
+ */
+void gfxQueueASyncPush(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+void gfxQueueGSyncPush(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+bool_t gfxQueueFSyncPush(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms);
+/* @} */
+
+/**
+ * @brief Remove an item from the queue.
+ * @note Removes the specified item from the queue where-ever it is in the queue
+ *
+ * @param[in] pqueue A pointer to the queue
+ * @param[in] pitem A pointer to the queue item
+ *
+ * @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.
+ *
+ * @api
+ * @{
+ */
+void gfxQueueASyncRemove(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+void gfxQueueGSyncRemove(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+void gfxQueueFSyncRemove(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem);
+/* @} */
+
+/**
+ * @brief Is the queue empty?
+ * @return TRUE if the queue is empty
+ *
+ * @param[in] pqueue A pointer to the queue
+ *
+ * @api
+ * @{
+ */
+bool_t gfxQueueASyncIsEmpty(gfxQueueASync *pqueue);
+bool_t gfxQueueGSyncIsEmpty(gfxQueueGSync *pqueue);
+bool_t gfxQueueFSyncIsEmpty(gfxQueueFSync *pqueue);
+/* @} */
+
+/**
+ * @brief Is an item in the queue?
+ * @return TRUE if the item is in the queue?
+ *
+ * @param[in] pqueue A pointer to the queue
+ * @param[in] pitem A pointer to the queue item
+ *
+ * @note This operation may be expensive.
+ *
+ * @api
+ * @{
+ */
+bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem);
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GQUEUE */
+#endif /* _GQUEUE_H */
+/** @} */
diff --git a/include/gqueue/options.h b/include/gqueue/options.h
new file mode 100644
index 00000000..30ccdb46
--- /dev/null
+++ b/include/gqueue/options.h
@@ -0,0 +1,66 @@
+/*
+ ChibiOS/GFX - Copyright (C) 2012, 2013
+ Joel Bodenmann aka Tectu <joel@unormal.org>
+
+ This file is part of ChibiOS/GFX.
+
+ ChibiOS/GFX is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/GFX is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file include/gqueue/options.h
+ * @brief GQUEUE - Queue options header file.
+ *
+ * @addtogroup GQUEUE
+ * @{
+ */
+
+#ifndef _GQUEUE_OPTIONS_H
+#define _GQUEUE_OPTIONS_H
+
+/**
+ * @name GQUEUE Functions to include.
+ * @{
+ */
+ /**
+ * @brief Enable Asynchronous Queues
+ * @details Defaults to FALSE
+ */
+ #ifndef GQUEUE_NEED_ASYNC
+ #define GQUEUE_NEED_ASYNC FALSE
+ #endif
+ /**
+ * @brief Enable Get-Synchronous Queues
+ * @details Defaults to FALSE
+ */
+ #ifndef GQUEUE_NEED_GSYNC
+ #define GQUEUE_NEED_GSYNC FALSE
+ #endif
+ /**
+ * @brief Enable Fully Synchronous Queues
+ * @details Defaults to FALSE
+ */
+ #ifndef GQUEUE_NEED_FSYNC
+ #define GQUEUE_NEED_FSYNC FALSE
+ #endif
+/**
+ * @}
+ *
+ * @name GQUEUE Optional Sizing Parameters
+ * @{
+ */
+/** @} */
+
+#endif /* _GQUEUE_OPTIONS_H */
+/** @} */
diff --git a/include/gwin/console.h b/include/gwin/console.h
index 1fc19e42..4c317cdb 100644
--- a/include/gwin/console.h
+++ b/include/gwin/console.h
@@ -40,7 +40,7 @@
typedef struct GConsoleObject_t {
GWindowObject gwin;
- #if GFX_USE_OS_CHIBIOS
+ #if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
struct GConsoleWindowStream_t {
const struct GConsoleWindowVMT_t *vmt;
_base_asynchronous_channel_data
@@ -80,7 +80,7 @@ extern "C" {
*/
GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height, font_t font);
-#if GFX_USE_OS_CHIBIOS
+#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
/**
* @brief Get a stream from a console window suitable for use with chprintf().
* @return The stream handle or NULL if this is not a console window.
@@ -128,6 +128,31 @@ void gwinPutString(GHandle gh, const char *str);
*/
void gwinPutCharArray(GHandle gh, const char *str, size_t n);
+/**
+ * @brief Print a formatted string at the cursor position in the window. It will wrap lines as required.
+ * @details This function implements a minimal printf() like functionality
+ * The general parameters format is: %[-][width|*][.precision|*][l|L]p.
+ * The following parameter types (p) are supported:
+ * - <b>x</b> hexadecimal integer.
+ * - <b>X</b> hexadecimal long.
+ * - <b>o</b> octal integer.
+ * - <b>O</b> octal long.
+ * - <b>d</b> decimal signed integer.
+ * - <b>D</b> decimal signed long.
+ * - <b>u</b> decimal unsigned integer.
+ * - <b>U</b> decimal unsigned long.
+ * - <b>c</b> character.
+ * - <b>s</b> string.
+ * @note Uses the current foreground color to draw the string and fills the background using the background drawing color
+ *
+ * @param[in] gh The window handle (must be a console window)
+ * @param[in] fmt The format string (as per printf)
+ * @param[in] ... The format string arguments.
+ *
+ * @api
+ */
+void gwinPrintf(GHandle gh, const char *fmt, ...);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/gwin/options.h b/include/gwin/options.h
index 8d78a751..683a6e55 100644
--- a/include/gwin/options.h
+++ b/include/gwin/options.h
@@ -59,9 +59,27 @@
* @name GWIN Optional Parameters
* @{
*/
+ /**
+ * @brief Buttons should not insist the mouse is over the button on mouse release
+ * @details Defaults to FALSE
+ */
#ifndef GWIN_BUTTON_LAZY_RELEASE
#define GWIN_BUTTON_LAZY_RELEASE FALSE
#endif
+ /**
+ * @brief Console Windows need floating point support in @p gwinPrintf
+ * @details Defaults to FALSE
+ */
+ #ifndef GWIN_CONSOLE_USE_FLOAT
+ #define GWIN_CONSOLE_USE_FLOAT FALSE
+ #endif
+ /**
+ * @brief Console Windows need BaseStreamSequential support (ChibiOS only)
+ * @details Defaults to FALSE
+ */
+ #ifndef GWIN_CONSOLE_USE_BASESTREAM
+ #define GWIN_CONSOLE_USE_BASESTREAM FALSE
+ #endif
/** @} */
#endif /* _GWIN_OPTIONS_H */
diff --git a/src/gos/chibios.c b/src/gos/chibios.c
index 6e63a2a4..7e369824 100644
--- a/src/gos/chibios.c
+++ b/src/gos/chibios.c
@@ -57,13 +57,14 @@ void gfxSleepMicroseconds(delaytime_t ms) {
default: chThdSleepMicroseconds(ms); return;
}
}
-
void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit) {
if (val > limit) val = limit;
psem->limit = limit;
chSemInit(&psem->sem, val);
}
-
+void gfxSemDestroy(gfxSem *psem) {
+ chSemReset(&psem->sem, 1);
+}
bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
if (ms == TIME_INFINITE) {
chSemWait(&psem->sem);
@@ -85,115 +86,6 @@ void gfxSemSignalI(gfxSem *psem) {
chSemSignalI(&psem->sem);
}
-void gfxQueueInit(gfxQueue *pqueue) {
- pqueue->head = pqueue->tail = 0;
- chSemInit(&pqueue->sem, 0);
-}
-
-gfxQueueItem * gfxQueueGet(gfxQueue *pqueue, delaytime_t ms) {
- gfxQueueItem *pi;
-
- chSysLock();
- /* If someone else is waiting or if the queue is empty - wait ourselves */
- if (pqueue->sem.s_cnt < 0 || !pqueue->head) {
- if (chSemWaitTimeoutS(&pqueue->sem, ms == TIME_INFINITE ? TIME_INFINITE : MS2ST(ms)) == RDY_TIMEOUT) {
- chSysUnlock();
- return NULL;
- }
- }
- /* We can now get the head element */
- pi = pqueue->head;
- pqueue->head = pi;
- chSemSignalI(&pi->sem);
- chSysUnlock();
- return pi;
-}
-
-bool_t gfxQueuePut(gfxQueue *pqueue, gfxQueueItem *pitem, delaytime_t ms) {
- chSemInit(&pitem->sem, 0);
- chSysLock();
- pitem->next = 0;
- if (!pqueue->head) {
- pqueue->head = pqueue->tail = pitem;
- } else {
- pqueue->tail->next = pitem;
- pqueue->tail = pitem;
- }
- /* Wake up someone who is waiting */
- if (chSemGetCounterI(&pqueue->sem) < 0)
- chSemSignalI(&pqueue->sem);
- chSysUnlock();
- return chSemWaitTimeout(&pitem->sem, ms == TIME_INFINITE ? TIME_INFINITE : MS2ST(ms)) != RDY_TIMEOUT;
-}
-
-bool_t gfxQueuePush(gfxQueue *pqueue, gfxQueueItem *pitem, delaytime_t ms) {
- chSemInit(&pitem->sem, 0);
- chSysLock();
- pitem->next = pqueue->head;
- pqueue->head = pitem;
- if (!pitem->next)
- pqueue->tail = pitem;
- /* Wake up someone who is waiting */
- if (chSemGetCounterI(&pqueue->sem) < 0)
- chSemSignalI(&pqueue->sem);
- chSysUnlock();
- return chSemWaitTimeout(&pitem->sem, ms == TIME_INFINITE ? TIME_INFINITE : MS2ST(ms)) != RDY_TIMEOUT;
-}
-
-void gfxQueueRemove(gfxQueue *pqueue, gfxQueueItem *pitem) {
- gfxQueueItem *pi;
-
- chSysLock();
- if (pqueue->head) {
- if (pqueue->head == pitem) {
- pqueue->head = pitem->next;
- chSemSignalI(&pitem->sem);
- } else {
- for(pi = pqueue->head; pi->next; pi = pi->next) {
- if (pi->next == pitem) {
- pi->next = pitem->next;
- if (pqueue->tail == pitem)
- pqueue->tail = pi;
- chSemSignalI(&pitem->sem);
- break;
- }
- }
- }
- }
- chSysUnlock();
-}
-
-bool_t gfxQueueIsEmpty(gfxQueue *pqueue) {
- return pqueue->head == NULL;
-}
-
-bool_t gfxQueueIsIn(gfxQueue *pqueue, gfxQueueItem *pitem) {
- gfxQueueItem *pi;
-
- chSysLock();
- for(pi = pqueue->head; pi; pi = pi->next) {
- if (pi == pitem) {
- chSysUnlock();
- return TRUE;
- }
- }
- chSysUnlock();
- return FALSE;
-}
-
-/**
- * @brief Start a new thread.
- * @return Return TRUE if the thread was started, FALSE on an error
- *
- * @param[in] stackarea A pointer to the area for the new threads stack or NULL to dynamically allocate it
- * @param[in] stacksz The size of the thread stack. 0 means the default operating system size although this
- * is only valid when stackarea is dynamically allocated.
- * @param[in] prio The priority of the new thread
- * @param[in] fn The function the new thread will run
- * @param[in] param A parameter to pass the thread function.
- *
- * @api
- */
bool_t gfxCreateThread(void *stackarea, size_t stacksz, threadpriority_t prio, gfxThreadFunction fn, void *param) {
if (!stackarea) {
if (!stacksz) stacksz = 256;
diff --git a/src/gos/win32.c b/src/gos/win32.c
index 6cf803a2..bda57f6f 100644
--- a/src/gos/win32.c
+++ b/src/gos/win32.c
@@ -26,7 +26,86 @@
#if GFX_USE_OS_WIN32
-#error "GOS: WIN32 not supported yet"
+#include <stdio.h>
+
+static HANDLE SystemMutex;
+
+void _gosInit(void) {
+}
+
+void gfxHalt(const char *msg) {
+ fprintf(stderr, "%s\n", msg);
+ ExitProcess(1);
+}
+
+void gfxSleepMicroseconds(delaytime_t ms) {
+ static LARGE_INTEGER pcfreq;
+ static int initflag;
+ LARGE_INTEGER t1, t2, tdiff;
+
+ switch(ms) {
+ case TIME_IMMEDIATE: return;
+ case TIME_INFINITE: while(1) Sleep(1000); return;
+ }
+
+ if (!initflag) {
+ QueryPerformanceFrequency(&pcfreq);
+ initflag++;
+ }
+ tdiff.QuadPart = pcfreq.QuadPart * ms / 1000000;
+
+ QueryPerformanceCounter(&t1);
+ do {
+ QueryPerformanceCounter(&t2);
+ } while (t2.QuadPart - t1.QuadPart < tdiff.QuadPart);
+}
+
+void gfxSystemLock(void) {
+ if (!SystemMutex)
+ SystemMutex = CreateMutex(NULL, FALSE, NULL);
+ WaitForSingleObject(SystemMutex, INFINITE);
+}
+
+void gfxSystemUnlock(void) {
+ ReleaseMutex(SystemMutex);
+}
+
+bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
+ return WaitForSingleObject(*psem, ms) == WAIT_OBJECT_0;
+}
+
+typedef LONG __stdcall (*_NtQuerySemaphore)(
+ HANDLE SemaphoreHandle,
+ DWORD SemaphoreInformationClass, /* Would be SEMAPHORE_INFORMATION_CLASS */
+ PVOID SemaphoreInformation, /* but this is to much to dump here */
+ ULONG SemaphoreInformationLength,
+ PULONG ReturnLength OPTIONAL
+);
+
+semcount_t gfxSemCounter(gfxSem *pSem) {
+ static _NtQuerySemaphore NtQuerySemaphore;
+ struct _SEMAPHORE_BASIC_INFORMATION {
+ ULONG CurrentCount;
+ ULONG MaximumCount;
+ } BasicInfo;
+
+ if (!NtQuerySemaphore)
+ NtQuerySemaphore = (_NtQuerySemaphore)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySemaphore");
+
+ NtQuerySemaphore(*pSem, 0, &BasicInfo, sizeof(BasicInfo), NULL);
+ return BasicInfo.CurrentCount;
+}
+
+bool_t gfxCreateThread(void *stackarea, size_t stacksz, threadpriority_t prio, gfxThreadFunction fn, void *param) {
+ (void) stackarea;
+ HANDLE thd;
+
+ if (!(thd = CreateThread(NULL, stacksz, fn, param, CREATE_SUSPENDED, NULL)))
+ return FALSE;
+ SetThreadPriority(thd, prio);
+ ResumeThread(thd);
+ return TRUE;
+}
#endif /* GFX_USE_OS_WIN32 */
/** @} */
diff --git a/src/gqueue/gqueue.c b/src/gqueue/gqueue.c
new file mode 100644
index 00000000..d515a425
--- /dev/null
+++ b/src/gqueue/gqueue.c
@@ -0,0 +1,255 @@
+/*
+ ChibiOS/GFX - Copyright (C) 2012, 2013
+ Joel Bodenmann aka Tectu <joel@unormal.org>
+
+ This file is part of ChibiOS/GFX.
+
+ ChibiOS/GFX is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/GFX is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @file src/gqueue/gqueue.c
+ * @brief GQUEUE source file.
+ */
+#if GFX_USE_GQUEUE
+
+#if GQUEUE_NEED_ASYNC
+ void gfxQueueASyncInit(gfxQueueASync *pqueue) {
+ pqueue->head = pqueue->tail = 0;
+ }
+ gfxQueueASyncItem *gfxQueueASyncGet(gfxQueueASync *pqueue) {
+ gfxQueueASyncItem *pi;
+
+ if (!pqueue->head) return 0;
+ gfxSystemLock();
+ if ((pi = pqueue->head))
+ pqueue->head = pi->next;
+ gfxSytemUnlock();
+ return pi;
+ }
+ void gfxQueueASyncPut(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+ pitem->next = 0;
+
+ gfxSystemLock();
+ if (!pqueue->head) {
+ pqueue->head = pqueue->tail = pitem;
+ } else {
+ pqueue->tail->next = pitem;
+ pqueue->tail = pitem;
+ }
+ gfxSystemUnlock();
+ }
+ void gfxQueueASyncPush(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+ gfxSystemLock();
+ pitem->next = pqueue->head;
+ pqueue->head = pitem;
+ if (!pitem->next)
+ pqueue->tail = pitem;
+ gfxSystemUnlock();
+ }
+ void gfxQueueASyncRemove(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+ if (!pitem) return;
+ gfxSystemLock();
+ if (pqueue->head) {
+ if (pqueue->head == pitem) {
+ pqueue->head = pitem->next;
+ } else {
+ for(gfxQueueASyncItem *pi = pqueue->head; pi->next; pi = pi->next) {
+ if (pi->next == pitem) {
+ pi->next = pitem->next;
+ if (pqueue->tail == pitem)
+ pqueue->tail = pi;
+ break;
+ }
+ }
+ }
+ }
+ gfxSystemUnlock();
+ }
+ bool_t gfxQueueASyncIsEmpty(gfxQueueASync *pqueue) {
+ return pqueue->head == NULL;
+ }
+ bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+ gfxSystemLock();
+ for(gfxQueueASyncItem *pi = pqueue->head; pi; pi = pi->next) {
+ if (pi == pitem) {
+ gfxSystemUnlock();
+ return TRUE;
+ }
+ }
+ gfxSystemUnlock();
+ return FALSE;
+ }
+#endif
+
+#if GQUEUE_NEED_GSYNC
+ void gfxQueueGSyncInit(gfxQueueGSync *pqueue) {
+ pqueue->head = pqueue->tail = 0;
+ gfxSemInit(&pqueue->sem, 0, MAX_SEMAPHORE_COUNT);
+ }
+ gfxQueueGSyncItem *gfxQueueGSyncGet(gfxQueueGSync *pqueue, delaytime_t ms) {
+ gfxQueueGSyncItem *pi;
+
+ if (!gfxSemWait(&pqueue->sem, ms)) return 0;
+ gfxSystemLock();
+ pi = pqueue->head;
+ pqueue->head = pi->next;
+ gfxSytemUnlock();
+ return pi;
+ }
+ void gfxQueueGSyncPut(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+ pitem->next = 0;
+
+ gfxSystemLock();
+ if (!pqueue->head) {
+ pqueue->head = pqueue->tail = pitem;
+ } else {
+ pqueue->tail->next = pitem;
+ pqueue->tail = pitem;
+ }
+ gfxSystemUnlock();
+
+ gfxSemSignal(&pqueue->sem);
+ }
+ void gfxQueueGSyncPush(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+ gfxSystemLock();
+ pitem->next = pqueue->head;
+ pqueue->head = pitem;
+ if (!pitem->next)
+ pqueue->tail = pitem;
+ gfxSystemUnlock();
+
+ gfxSemSignal(&pqueue->sem);
+ }
+ void gfxQueueGSyncRemove(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+ if (!pitem) return;
+ gfxSystemLock();
+ if (pqueue->head) {
+ if (pqueue->head == pitem) {
+ pqueue->head = pitem->next;
+ } else {
+ for(gfxQueueGSyncItem *pi = pqueue->head; pi->next; pi = pi->next) {
+ if (pi->next == pitem) {
+ pi->next = pitem->next;
+ if (pqueue->tail == pitem)
+ pqueue->tail = pi;
+ break;
+ }
+ }
+ }
+ }
+ gfxSystemUnlock();
+ }
+ bool_t gfxQueueGSyncIsEmpty(gfxQueueGSync *pqueue) {
+ return pqueue->head == NULL;
+ }
+ bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+ gfxSystemLock();
+ for(gfxQueueGSyncItem *pi = pqueue->head; pi; pi = pi->next) {
+ if (pi == pitem) {
+ gfxSystemUnlock();
+ return TRUE;
+ }
+ }
+ gfxSystemUnlock();
+ return FALSE;
+ }
+#endif
+
+#if GQUEUE_NEED_FSYNC
+ void gfxQueueFSyncInit(gfxQueueFSync *pqueue) {
+ pqueue->head = pqueue->tail = 0;
+ gfxSemInit(&pqueue->sem, 0, MAX_SEMAPHORE_COUNT);
+ }
+ gfxQueueFSyncItem *gfxQueueFSyncGet(gfxQueueFSync *pqueue, delaytime_t ms) {
+ gfxQueueFSyncItem *pi;
+
+ if (!gfxSemWait(&pqueue->sem, ms)) return 0;
+ gfxSystemLock();
+ pi = pqueue->head;
+ pqueue->head = pi->next;
+ gfxSytemUnlock();
+
+ gfxSemSignalI(&pi->sem);
+ gfxSemDestroy(&pi->sem);
+ return pi;
+ }
+ bool_t gfxQueueFSyncPut(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms) {
+ gfxSemInit(&pitem->sem, 0, 1);
+ pitem->next = 0;
+
+ gfxSystemLock();
+ if (!pqueue->head) {
+ pqueue->head = pqueue->tail = pitem;
+ } else {
+ pqueue->tail->next = pitem;
+ pqueue->tail = pitem;
+ }
+ gfxSystemUnlock();
+
+ gfxSemSignal(&pqueue->sem);
+ return gfxSemWait(&pitem->sem, ms);
+ }
+ bool_t gfxQueueFSyncPush(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms) {
+ gfxSemInit(&pitem->sem, 0, 1);
+
+ gfxSystemLock();
+ pitem->next = pqueue->head;
+ pqueue->head = pitem;
+ if (!pitem->next)
+ pqueue->tail = pitem;
+ gfxSystemUnlock();
+
+ gfxSemSignal(&pqueue->sem);
+ return gfxSemWait(&pitem->sem, ms);
+ }
+ void gfxQueueFSyncRemove(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem) {
+ if (!pitem) return;
+ gfxSystemLock();
+ if (pqueue->head) {
+ if (pqueue->head == pitem) {
+ pqueue->head = pitem->next;
+ found:
+ gfxSystemUnlock();
+ gfxSemSignal(&pitem->sem);
+ gfxSemDestroy(&pitem->sem);
+ return;
+ }
+ for(gfxQueueFSyncItem *pi = pqueue->head; pi->next; pi = pi->next) {
+ if (pi->next == pitem) {
+ pi->next = pitem->next;
+ if (pqueue->tail == pitem)
+ pqueue->tail = pi;
+ goto found;
+ }
+ }
+ }
+ gfxSystemUnlock();
+ }
+ bool_t gfxQueueFSyncIsEmpty(gfxQueueFSync *pqueue) {
+ return pqueue->head == NULL;
+ }
+ bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem) {
+ gfxSystemLock();
+ for(gfxQueueFSyncItem *pi = pqueue->head; pi; pi = pi->next) {
+ if (pi == pitem) {
+ gfxSystemUnlock();
+ return TRUE;
+ }
+ }
+ gfxSystemUnlock();
+ return FALSE;
+ }
+#endif
+
+#endif /* GFX_USE_GQUEUE */
diff --git a/src/gqueue/gqueue.mk b/src/gqueue/gqueue.mk
new file mode 100644
index 00000000..ab8a0423
--- /dev/null
+++ b/src/gqueue/gqueue.mk
@@ -0,0 +1 @@
+GFXSRC += $(GFXLIB)/src/gqueue/gqueue.c
diff --git a/src/gwin/button.c b/src/gwin/button.c
index 19301698..cf5babc5 100644
--- a/src/gwin/button.c
+++ b/src/gwin/button.c
@@ -54,7 +54,7 @@ static void gwinButtonCallback(void *param, GEvent *pe) {
#define pbe ((GEventGWinButton *)pe)
// check if button is disabled
- if (gh->enabled == false)
+ if (!gh->enabled)
return;
switch (pe->type) {
@@ -150,7 +150,7 @@ GHandle gwinCreateButton(GButtonObject *gb, coord_t x, coord_t y, coord_t width,
geventRegisterCallback(&gb->listener, gwinButtonCallback, gb);
// buttons are enabled by default
- gb->gwin.enabled = true;
+ gb->gwin.enabled = TRUE;
return (GHandle)gb;
}
diff --git a/src/gwin/console.c b/src/gwin/console.c
index a01ed79d..32e4f35a 100644
--- a/src/gwin/console.c
+++ b/src/gwin/console.c
@@ -30,7 +30,7 @@
* Stream interface implementation. The interface is write only
*/
-#if GFX_USE_OS_CHIBIOS
+#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
#define Stream2GWindow(ip) ((GHandle)(((char *)(ip)) - (size_t)(&(((GConsoleObject *)0)->stream))))
static size_t GWinStreamWrite(void *ip, const uint8_t *bp, size_t n) { gwinPutCharArray(Stream2GWindow(ip), (const char *)bp, n); return RDY_OK; }
@@ -71,7 +71,7 @@ GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t widt
return (GHandle)gc;
}
-#if GFX_USE_OS_CHIBIOS
+#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
BaseSequentialStream *gwinGetConsoleStream(GHandle gh) {
if (gh->type != GW_CONSOLE)
return 0;
@@ -145,6 +145,203 @@ void gwinPutCharArray(GHandle gh, const char *str, size_t n) {
gwinPutChar(gh, *str++);
}
+#include <stdarg.h>
+
+#define MAX_FILLER 11
+#define FLOAT_PRECISION 100000
+
+static char *ltoa_wd(char *p, long num, unsigned radix, long divisor) {
+ int i;
+ char *q;
+
+ if (!divisor) divisor = num;
+
+ q = p + MAX_FILLER;
+ do {
+ i = (int)(num % radix);
+ i += '0';
+ if (i > '9')
+ i += 'A' - '0' - 10;
+ *--q = i;
+ num /= radix;
+ } while ((divisor /= radix) != 0);
+
+ i = (int)(p + MAX_FILLER - q);
+ do {
+ *p++ = *q++;
+ } while (--i);
+
+ return p;
+}
+
+#if GWIN_CONSOLE_USE_FLOAT
+ static char *ftoa(char *p, double num) {
+ long l;
+ unsigned long precision = FLOAT_PRECISION;
+
+ l = num;
+ p = ltoa_wd(p, l, 10, 0);
+ *p++ = '.';
+ l = (num - l) * precision;
+ return ltoa_wd(p, l, 10, precision / 10);
+ }
+#endif
+
+void gwinPrintf(GHandle gh, const char *fmt, ...) {
+ va_list ap;
+ char *p, *s, c, filler;
+ int i, precision, width;
+ bool_t is_long, left_align;
+ long l;
+ #if CHPRINTF_USE_FLOAT
+ float f;
+ char tmpbuf[2*MAX_FILLER + 1];
+ #else
+ char tmpbuf[MAX_FILLER + 1];
+ #endif
+
+ if (gh->type != GW_CONSOLE || !gh->font) return;
+
+ va_start(ap, fmt);
+ while (TRUE) {
+ c = *fmt++;
+ if (c == 0) {
+ va_end(ap);
+ return;
+ }
+ if (c != '%') {
+ gwinPutChar(gh, c);
+ continue;
+ }
+
+ p = tmpbuf;
+ s = tmpbuf;
+ left_align = FALSE;
+ if (*fmt == '-') {
+ fmt++;
+ left_align = TRUE;
+ }
+ filler = ' ';
+ if (*fmt == '.') {
+ fmt++;
+ filler = '0';
+ }
+ width = 0;
+
+ while (TRUE) {
+ c = *fmt++;
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c == '*')
+ c = va_arg(ap, int);
+ else
+ break;
+ width = width * 10 + c;
+ }
+ precision = 0;
+ if (c == '.') {
+ while (TRUE) {
+ c = *fmt++;
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c == '*')
+ c = va_arg(ap, int);
+ else
+ break;
+ precision = precision * 10 + c;
+ }
+ }
+ /* Long modifier.*/
+ if (c == 'l' || c == 'L') {
+ is_long = TRUE;
+ if (*fmt)
+ c = *fmt++;
+ }
+ else
+ is_long = (c >= 'A') && (c <= 'Z');
+
+ /* Command decoding.*/
+ switch (c) {
+ case 'c':
+ filler = ' ';
+ *p++ = va_arg(ap, int);
+ break;
+ case 's':
+ filler = ' ';
+ if ((s = va_arg(ap, char *)) == 0)
+ s = "(null)";
+ if (precision == 0)
+ precision = 32767;
+ for (p = s; *p && (--precision >= 0); p++);
+ break;
+ case 'D':
+ case 'd':
+ if (is_long)
+ l = va_arg(ap, long);
+ else
+ l = va_arg(ap, int);
+ if (l < 0) {
+ *p++ = '-';
+ l = -l;
+ }
+ p = ltoa_wd(p, l, 10, 0);
+ break;
+ #if CHPRINTF_USE_FLOAT
+ case 'f':
+ f = (float) va_arg(ap, double);
+ if (f < 0) {
+ *p++ = '-';
+ f = -f;
+ }
+ p = ftoa(p, f);
+ break;
+ #endif
+ case 'X':
+ case 'x':
+ c = 16;
+ goto unsigned_common;
+ case 'U':
+ case 'u':
+ c = 10;
+ goto unsigned_common;
+ case 'O':
+ case 'o':
+ c = 8;
+ unsigned_common:
+ if (is_long)
+ l = va_arg(ap, long);
+ else
+ l = va_arg(ap, int);
+ p = ltoa_wd(p, l, c, 0);
+ break;
+ default:
+ *p++ = c;
+ break;
+ }
+
+ i = (int)(p - s);
+ if ((width -= i) < 0)
+ width = 0;
+ if (left_align == FALSE)
+ width = -width;
+ if (width < 0) {
+ if (*s == '-' && filler == '0') {
+ gwinPutChar(gh, *s++);
+ i--;
+ }
+ do {
+ gwinPutChar(gh, filler);
+ } while (++width != 0);
+ }
+ while (--i >= 0)
+ gwinPutChar(gh, *s++);
+ while (width) {
+ gwinPutChar(gh, filler);
+ width--;
+ }
+ }
+}
+
#endif /* GFX_USE_GWIN && GWIN_NEED_CONSOLE */
/** @} */