More GOS module changes
GQUEUE as a seperate module GOS changes including basic Win32 O/S support
This commit is contained in:
parent
7fbfde42aa
commit
8fcbf4e5d5
18 changed files with 1159 additions and 367 deletions
|
@ -24,6 +24,15 @@
|
||||||
#include <wingdi.h>
|
#include <wingdi.h>
|
||||||
#include <assert.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
|
#ifndef GDISP_SCREEN_WIDTH
|
||||||
#define GDISP_SCREEN_WIDTH 640
|
#define GDISP_SCREEN_WIDTH 640
|
||||||
#endif
|
#endif
|
||||||
|
@ -230,10 +239,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD WINAPI WindowThread(LPVOID lpParameter) {
|
static void InitWindow(void) {
|
||||||
(void)lpParameter;
|
|
||||||
|
|
||||||
MSG msg;
|
|
||||||
HANDLE hInstance;
|
HANDLE hInstance;
|
||||||
WNDCLASS wc;
|
WNDCLASS wc;
|
||||||
RECT rect;
|
RECT rect;
|
||||||
|
@ -274,7 +280,31 @@ static DWORD WINAPI WindowThread(LPVOID lpParameter) {
|
||||||
ShowWindow(winRootWindow, SW_SHOW);
|
ShowWindow(winRootWindow, SW_SHOW);
|
||||||
UpdateWindow(winRootWindow);
|
UpdateWindow(winRootWindow);
|
||||||
isReady = TRUE;
|
isReady = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static DWORD WINAPI WindowThread(LPVOID param) {
|
||||||
|
(void)param;
|
||||||
|
MSG msg;
|
||||||
|
|
||||||
|
InitWindow();
|
||||||
while(GetMessage(&msg, NULL, 0, 0) > 0) {
|
while(GetMessage(&msg, NULL, 0, 0) > 0) {
|
||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
|
@ -282,6 +312,7 @@ static DWORD WINAPI WindowThread(LPVOID lpParameter) {
|
||||||
ExitProcess(0);
|
ExitProcess(0);
|
||||||
return msg.wParam;
|
return msg.wParam;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Driver exported functions. */
|
/* Driver exported functions. */
|
||||||
|
@ -312,7 +343,11 @@ bool_t gdisp_lld_init(void) {
|
||||||
wHeight = GDISP_SCREEN_HEIGHT;
|
wHeight = GDISP_SCREEN_HEIGHT;
|
||||||
|
|
||||||
/* Initialise the window */
|
/* Initialise the window */
|
||||||
|
#if GDISP_THREAD_CHIBIOS
|
||||||
|
gfxCreateThread(waWindowThread, sizeof(waWindowThread), HIGH_PRIORITY, WindowThread, 0);
|
||||||
|
#else
|
||||||
CreateThread(0, 0, WindowThread, 0, 0, 0);
|
CreateThread(0, 0, WindowThread, 0, 0, 0);
|
||||||
|
#endif
|
||||||
while (!isReady)
|
while (!isReady)
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
|
|
||||||
|
|
1
gfx.mk
1
gfx.mk
|
@ -7,6 +7,7 @@ GFXINC += $(GFXLIB)/include
|
||||||
GFXSRC += $(GFXLIB)/src/gfx.c
|
GFXSRC += $(GFXLIB)/src/gfx.c
|
||||||
|
|
||||||
include $(GFXLIB)/src/gos/gos.mk
|
include $(GFXLIB)/src/gos/gos.mk
|
||||||
|
include $(GFXLIB)/src/gqueue/gqueue.mk
|
||||||
include $(GFXLIB)/src/gdisp/gdisp.mk
|
include $(GFXLIB)/src/gdisp/gdisp.mk
|
||||||
include $(GFXLIB)/src/tdisp/tdisp.mk
|
include $(GFXLIB)/src/tdisp/tdisp.mk
|
||||||
include $(GFXLIB)/src/gevent/gevent.mk
|
include $(GFXLIB)/src/gevent/gevent.mk
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#define GFX_USE_GWIN FALSE
|
#define GFX_USE_GWIN FALSE
|
||||||
#define GFX_USE_GEVENT FALSE
|
#define GFX_USE_GEVENT FALSE
|
||||||
#define GFX_USE_GTIMER FALSE
|
#define GFX_USE_GTIMER FALSE
|
||||||
|
#define GFX_USE_GQUEUE FALSE
|
||||||
#define GFX_USE_GINPUT FALSE
|
#define GFX_USE_GINPUT FALSE
|
||||||
#define GFX_USE_GADC FALSE
|
#define GFX_USE_GADC FALSE
|
||||||
#define GFX_USE_GAUDIN FALSE
|
#define GFX_USE_GAUDIN FALSE
|
||||||
|
@ -90,6 +91,11 @@
|
||||||
/* Features for the GTIMER subsystem. */
|
/* Features for the GTIMER subsystem. */
|
||||||
/* NONE */
|
/* 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. */
|
/* Features for the GINPUT subsystem. */
|
||||||
#define GINPUT_NEED_MOUSE FALSE
|
#define GINPUT_NEED_MOUSE FALSE
|
||||||
#define GINPUT_NEED_KEYBOARD FALSE
|
#define GINPUT_NEED_KEYBOARD FALSE
|
||||||
|
@ -118,6 +124,8 @@
|
||||||
#define GTIMER_THREAD_WORKAREA_SIZE 512
|
#define GTIMER_THREAD_WORKAREA_SIZE 512
|
||||||
#define GADC_MAX_LOWSPEED_DEVICES 4
|
#define GADC_MAX_LOWSPEED_DEVICES 4
|
||||||
#define GWIN_BUTTON_LAZY_RELEASE FALSE
|
#define GWIN_BUTTON_LAZY_RELEASE FALSE
|
||||||
|
#define GWIN_CONSOLE_USE_BASESTREAM FALSE
|
||||||
|
#define GWIN_CONSOLE_USE_FLOAT FALSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Optional Low Level Driver Definitions */
|
/* Optional Low Level Driver Definitions */
|
||||||
|
|
|
@ -86,6 +86,14 @@
|
||||||
#ifndef GFX_USE_GTIMER
|
#ifndef GFX_USE_GTIMER
|
||||||
#define GFX_USE_GTIMER FALSE
|
#define GFX_USE_GTIMER FALSE
|
||||||
#endif
|
#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
|
* @brief GFX Input Device API
|
||||||
* @details Defaults to FALSE
|
* @details Defaults to FALSE
|
||||||
|
@ -143,6 +151,7 @@
|
||||||
*/
|
*/
|
||||||
#include "gos/options.h"
|
#include "gos/options.h"
|
||||||
#include "gmisc/options.h"
|
#include "gmisc/options.h"
|
||||||
|
#include "gqueue/options.h"
|
||||||
#include "gevent/options.h"
|
#include "gevent/options.h"
|
||||||
#include "gtimer/options.h"
|
#include "gtimer/options.h"
|
||||||
#include "gdisp/options.h"
|
#include "gdisp/options.h"
|
||||||
|
@ -164,6 +173,7 @@
|
||||||
*/
|
*/
|
||||||
#include "gos/gos.h"
|
#include "gos/gos.h"
|
||||||
#include "gmisc/gmisc.h"
|
#include "gmisc/gmisc.h"
|
||||||
|
#include "gqueue/gqueue.h"
|
||||||
#include "gevent/gevent.h"
|
#include "gevent/gevent.h"
|
||||||
#include "gtimer/gtimer.h"
|
#include "gtimer/gtimer.h"
|
||||||
#include "gdisp/gdisp.h"
|
#include "gdisp/gdisp.h"
|
||||||
|
|
|
@ -101,6 +101,15 @@
|
||||||
#if GDISP_NEED_MULTITHREAD && GDISP_NEED_ASYNC
|
#if GDISP_NEED_MULTITHREAD && GDISP_NEED_ASYNC
|
||||||
#error "GDISP: Only one of GDISP_NEED_MULTITHREAD and GDISP_NEED_ASYNC should be defined."
|
#error "GDISP: Only one of GDISP_NEED_MULTITHREAD and GDISP_NEED_ASYNC should be defined."
|
||||||
#endif
|
#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
|
#endif
|
||||||
|
|
||||||
#if GFX_USE_TDISP
|
#if GFX_USE_TDISP
|
||||||
|
@ -141,6 +150,9 @@
|
||||||
#if GFX_USE_GAUDOUT
|
#if GFX_USE_GAUDOUT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if GFX_USE_GQUEUE
|
||||||
|
#endif
|
||||||
|
|
||||||
#if GFX_USE_GMISC
|
#if GFX_USE_GMISC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -67,17 +67,6 @@ typedef struct {
|
||||||
|
|
||||||
#define gfxMutex Mutex
|
#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. */
|
/* Function declarations. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -90,30 +79,24 @@ extern "C" {
|
||||||
#define gfxExit() chSysHalt()
|
#define gfxExit() chSysHalt()
|
||||||
#define gfxAlloc(sz) chHeapAlloc(NULL, sz)
|
#define gfxAlloc(sz) chHeapAlloc(NULL, sz)
|
||||||
#define gfxFree(ptr) chHeapFree(ptr)
|
#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 gfxSleepMilliseconds(delaytime_t ms);
|
||||||
void gfxSleepMicroseconds(delaytime_t ms);
|
void gfxSleepMicroseconds(delaytime_t ms);
|
||||||
void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
|
void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
|
||||||
|
void gfxSemDestroy(gfxSem *psem);
|
||||||
bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
|
bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
|
||||||
void gfxSemSignal(gfxSem *psem);
|
void gfxSemSignal(gfxSem *psem);
|
||||||
void gfxSemSignalI(gfxSem *psem);
|
void gfxSemSignalI(gfxSem *psem);
|
||||||
#define gfxSemCounterI(psem) ((psem)->sem.s_cnt)
|
#define gfxSemCounterI(psem) ((psem)->sem.s_cnt)
|
||||||
#define gfxSemCounter(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);
|
bool_t gfxCreateThread(void *stackarea, size_t stacksz, threadpriority_t prio, gfxThreadFunction fn, void *param);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -36,11 +36,6 @@
|
||||||
/* Type definitions */
|
/* Type definitions */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A function for a new thread to execute.
|
|
||||||
*/
|
|
||||||
typedef threadreturn_t (*gfxThreadFunction)(void *param);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Various integer sizes
|
* @brief Various integer sizes
|
||||||
* @note Your platform may use slightly different definitions to these
|
* @note Your platform may use slightly different definitions to these
|
||||||
|
@ -66,6 +61,10 @@
|
||||||
typedef short semcount_t;
|
typedef short semcount_t;
|
||||||
typedef int threadreturn_t;
|
typedef int threadreturn_t;
|
||||||
typedef int threadpriority_t;
|
typedef int threadpriority_t;
|
||||||
|
/**
|
||||||
|
* @brief A function for a new thread to execute.
|
||||||
|
*/
|
||||||
|
typedef threadreturn_t (*gfxThreadFunction)(void *param);
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*
|
*
|
||||||
|
@ -77,7 +76,7 @@
|
||||||
#define TRUE 1
|
#define TRUE 1
|
||||||
#define TIME_IMMEDIATE 0
|
#define TIME_IMMEDIATE 0
|
||||||
#define TIME_INFINITE ((delaytime_t)-1)
|
#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 LOW_PRIORITY 0
|
||||||
#define NORMAL_PRIORITY 1
|
#define NORMAL_PRIORITY 1
|
||||||
#define HIGH_PRIORITY 2
|
#define HIGH_PRIORITY 2
|
||||||
|
@ -96,18 +95,6 @@
|
||||||
*/
|
*/
|
||||||
typedef struct {} gfxMutex;
|
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. */
|
/* Function declarations. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -151,6 +138,15 @@
|
||||||
*/
|
*/
|
||||||
void gfxFree(void *ptr);
|
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
|
* @brief Put the current thread to sleep for the specified period in milliseconds
|
||||||
*
|
*
|
||||||
|
@ -176,6 +172,99 @@
|
||||||
*/
|
*/
|
||||||
void gfxSleepMicroseconds(delaytime_t ms);
|
void gfxSleepMicroseconds(delaytime_t ms);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the current operating system tick time
|
||||||
|
* @return The current tick time
|
||||||
|
*
|
||||||
|
* @note A "tick" is an arbitrary period of time that the operating
|
||||||
|
* system uses to mark time.
|
||||||
|
* @note The absolute value of this call is relatively meaningless. Its usefulness
|
||||||
|
* is in calculating periods between two calls to this function.
|
||||||
|
* @note As the value from this function can wrap it is important that any periods are calculated
|
||||||
|
* as t2 - t1 and then compared to the desired period rather than comparing
|
||||||
|
* t1 + period to t2
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
systemticks_t gfxSystemTicks(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert a given number of millseconds to a number of operating system ticks
|
||||||
|
* @return The period in system ticks.
|
||||||
|
*
|
||||||
|
* @note A "tick" is an arbitrary period of time that the operating
|
||||||
|
* system uses to mark time.
|
||||||
|
*
|
||||||
|
* @param[in] ms The number of millseconds
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
* within the GFX system. On hardware this may be implemented as a disabling of interrupts,
|
||||||
|
* however in an operating system which hides real interrupt level code it may simply use a
|
||||||
|
* mutex lock.
|
||||||
|
* @note The thread MUST NOT block whilst the system is locked. It must execute in this state for
|
||||||
|
* as short a period as possible as this can seriously affect interrupt latency on some
|
||||||
|
* platforms.
|
||||||
|
* @note While locked only interrupt level (iclass) GFX routines may be called.
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
void gfxSystemLock(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlock the operating system previous locked by gfxSystemLock()
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
void gfxSystemUnlock(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialise a mutex to protect a region of code from other threads.
|
||||||
|
*
|
||||||
|
* @param[in] pmutex A pointer to the mutex
|
||||||
|
*
|
||||||
|
* @note Whilst a counting semaphore with a limit of 1 can be used for similiar purposes
|
||||||
|
* on many operating systems using a seperate mutex structure is more efficient.
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param[in] pmutex A pointer to the mutex
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
void gfxMutexEnter(gfxMutex *pmutex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exit the critical code region protected by the mutex.
|
||||||
|
* @details May cause another thread waiting on the mutex to now be placed into the run queue.
|
||||||
|
*
|
||||||
|
* @param[in] pmutex A pointer to the mutex
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
void gfxMutexExit(gfxMutex *pmutex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialise a Counted Semaphore
|
* @brief Initialise a Counted Semaphore
|
||||||
*
|
*
|
||||||
|
@ -194,6 +283,17 @@
|
||||||
*/
|
*/
|
||||||
void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
|
void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy a Counted Semaphore
|
||||||
|
*
|
||||||
|
* @param[in] psem A pointer to the semaphore
|
||||||
|
*
|
||||||
|
* @note Any threads waiting on the semaphore will be released
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
void gfxSemDestroy(gfxSem *psem);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Wait on a semaphore
|
* @brief Wait on a semaphore
|
||||||
* @details The semaphore counter is decreased and if the result becomes negative the thread waits for it to become
|
* @details The semaphore counter is decreased and if the result becomes negative the thread waits for it to become
|
||||||
|
@ -253,199 +353,6 @@
|
||||||
*/
|
*/
|
||||||
semcount_t gfxSemCounterI(gfxSem *pSem);
|
semcount_t gfxSemCounterI(gfxSem *pSem);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the current operating system tick time
|
|
||||||
* @return The current tick time
|
|
||||||
*
|
|
||||||
* @note A "tick" is an arbitrary period of time that the operating
|
|
||||||
* system uses to mark time.
|
|
||||||
* @note The absolute value of this call is relatively meaningless. Its usefulness
|
|
||||||
* is in calculating periods between two calls to this function.
|
|
||||||
* @note As the value from this function can wrap it is important that any periods are calculated
|
|
||||||
* as t2 - t1 and then compared to the desired period rather than comparing
|
|
||||||
* t1 + period to t2
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
systemticks_t gfxSystemTicks(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Convert a given number of millseconds to a number of operating system ticks
|
|
||||||
* @return The period in system ticks.
|
|
||||||
*
|
|
||||||
* @note A "tick" is an arbitrary period of time that the operating
|
|
||||||
* system uses to mark time.
|
|
||||||
*
|
|
||||||
* @param[in] ms The number of millseconds
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
* within the GFX system. On hardware this may be implemented as a disabling of interrupts,
|
|
||||||
* however in an operating system which hides real interrupt level code it may simply use a
|
|
||||||
* mutex lock.
|
|
||||||
* @note The thread MUST NOT block whilst the system is locked. It must execute in this state for
|
|
||||||
* as short a period as possible as this can seriously affect interrupt latency on some
|
|
||||||
* platforms.
|
|
||||||
* @note While locked only interrupt level (iclass) GFX routines may be called.
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
void gfxSystemLock(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Unlock the operating system previous locked by gfxSystemLock()
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
void gfxSystemUnlock(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initialise a mutex to protect a region of code from other threads.
|
|
||||||
*
|
|
||||||
* @param[in] pmutex A pointer to the mutex
|
|
||||||
*
|
|
||||||
* @note Whilst a counting semaphore with a limit of 1 can be used for similiar purposes
|
|
||||||
* on many operating systems using a seperate mutex structure is more efficient.
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
void gfxMutexInit(gfxMutex *pmutex);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enter the critical code region protected by the mutex.
|
|
||||||
* @details Blocks until there is no other thread in the critical region.
|
|
||||||
*
|
|
||||||
* @param[in] pmutex A pointer to the mutex
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
void gfxMutexEnter(gfxMutex *pmutex);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Exit the critical code region protected by the mutex.
|
|
||||||
* @details May cause another thread waiting on the mutex to now be placed into the run queue.
|
|
||||||
*
|
|
||||||
* @param[in] pmutex A pointer to the mutex
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
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).
|
|
||||||
*
|
|
||||||
* @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] pqueue A pointer to the queue
|
|
||||||
* @param[in] ms The maxmimum time to wait for an item
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
gfxQueueItem * gfxQueueGet(gfxQueue *pqueue, delaytime_t ms);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Put an item on the end 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 removed from the queue
|
|
||||||
*
|
|
||||||
* @note Use a delay time of TIME_IMMEDIATE if you don't want to wait until the
|
|
||||||
* item is removed from the queue
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
bool_t gfxQueuePut(gfxQueue *pqueue, gfxQueueItem *pitem, delaytime_t ms);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Pop an item from the head of the queue.
|
|
||||||
* @return NULL if there are no more items on the queue
|
|
||||||
*
|
|
||||||
* @param[in] pqueue A pointer to the queue
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
#define gfxQueuePop(pqueue, ms) gfxQueueGet(pqueue, 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
|
|
||||||
*
|
|
||||||
* @note Use a delay time of TIME_IMMEDIATE if you don't want to wait until the
|
|
||||||
* item is removed from the queue
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
bool_t gfxQueuePush(gfxQueue *pqueue, gfxQueueItem *pitem, delaytime_t ms);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*
|
|
||||||
* @note If the item isn't in the queue the routine just returns.
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
void gfxQueueRemove(gfxQueue *pqueue, gfxQueueItem *pitem);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Is the queue empty?
|
|
||||||
* @return TRUE if the queue is empty
|
|
||||||
*
|
|
||||||
* @param[in] pqueue A pointer to the queue
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
bool_t gfxQueueIsEmpty(gfxQueue *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 gfxQueueIsIn(gfxQueue *pqueue, gfxQueueItem *pitem);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start a new thread.
|
* @brief Start a new thread.
|
||||||
* @return Return TRUE if the thread was started, FALSE on an error
|
* @return Return TRUE if the thread was started, FALSE on an error
|
||||||
|
|
|
@ -26,6 +26,80 @@
|
||||||
#define _GOS_WIN32_H
|
#define _GOS_WIN32_H
|
||||||
|
|
||||||
#if GFX_USE_OS_WIN32
|
#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 /* GFX_USE_OS_WIN32 */
|
||||||
|
|
||||||
#endif /* _GOS_WIN32_H */
|
#endif /* _GOS_WIN32_H */
|
||||||
|
|
229
include/gqueue/gqueue.h
Normal file
229
include/gqueue/gqueue.h
Normal file
|
@ -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 */
|
||||||
|
/** @} */
|
66
include/gqueue/options.h
Normal file
66
include/gqueue/options.h
Normal file
|
@ -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 */
|
||||||
|
/** @} */
|
|
@ -40,7 +40,7 @@
|
||||||
typedef struct GConsoleObject_t {
|
typedef struct GConsoleObject_t {
|
||||||
GWindowObject gwin;
|
GWindowObject gwin;
|
||||||
|
|
||||||
#if GFX_USE_OS_CHIBIOS
|
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
|
||||||
struct GConsoleWindowStream_t {
|
struct GConsoleWindowStream_t {
|
||||||
const struct GConsoleWindowVMT_t *vmt;
|
const struct GConsoleWindowVMT_t *vmt;
|
||||||
_base_asynchronous_channel_data
|
_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);
|
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().
|
* @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.
|
* @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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -58,10 +58,28 @@
|
||||||
*
|
*
|
||||||
* @name GWIN Optional Parameters
|
* @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
|
#ifndef GWIN_BUTTON_LAZY_RELEASE
|
||||||
#define GWIN_BUTTON_LAZY_RELEASE FALSE
|
#define GWIN_BUTTON_LAZY_RELEASE FALSE
|
||||||
#endif
|
#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 */
|
#endif /* _GWIN_OPTIONS_H */
|
||||||
|
|
|
@ -57,13 +57,14 @@ void gfxSleepMicroseconds(delaytime_t ms) {
|
||||||
default: chThdSleepMicroseconds(ms); return;
|
default: chThdSleepMicroseconds(ms); return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit) {
|
void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit) {
|
||||||
if (val > limit) val = limit;
|
if (val > limit) val = limit;
|
||||||
psem->limit = limit;
|
psem->limit = limit;
|
||||||
chSemInit(&psem->sem, val);
|
chSemInit(&psem->sem, val);
|
||||||
}
|
}
|
||||||
|
void gfxSemDestroy(gfxSem *psem) {
|
||||||
|
chSemReset(&psem->sem, 1);
|
||||||
|
}
|
||||||
bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
|
bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
|
||||||
if (ms == TIME_INFINITE) {
|
if (ms == TIME_INFINITE) {
|
||||||
chSemWait(&psem->sem);
|
chSemWait(&psem->sem);
|
||||||
|
@ -85,115 +86,6 @@ void gfxSemSignalI(gfxSem *psem) {
|
||||||
chSemSignalI(&psem->sem);
|
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) {
|
bool_t gfxCreateThread(void *stackarea, size_t stacksz, threadpriority_t prio, gfxThreadFunction fn, void *param) {
|
||||||
if (!stackarea) {
|
if (!stackarea) {
|
||||||
if (!stacksz) stacksz = 256;
|
if (!stacksz) stacksz = 256;
|
||||||
|
|
|
@ -26,7 +26,86 @@
|
||||||
|
|
||||||
#if GFX_USE_OS_WIN32
|
#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 */
|
#endif /* GFX_USE_OS_WIN32 */
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
255
src/gqueue/gqueue.c
Normal file
255
src/gqueue/gqueue.c
Normal file
|
@ -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 */
|
1
src/gqueue/gqueue.mk
Normal file
1
src/gqueue/gqueue.mk
Normal file
|
@ -0,0 +1 @@
|
||||||
|
GFXSRC += $(GFXLIB)/src/gqueue/gqueue.c
|
|
@ -54,7 +54,7 @@ static void gwinButtonCallback(void *param, GEvent *pe) {
|
||||||
#define pbe ((GEventGWinButton *)pe)
|
#define pbe ((GEventGWinButton *)pe)
|
||||||
|
|
||||||
// check if button is disabled
|
// check if button is disabled
|
||||||
if (gh->enabled == false)
|
if (!gh->enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (pe->type) {
|
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);
|
geventRegisterCallback(&gb->listener, gwinButtonCallback, gb);
|
||||||
|
|
||||||
// buttons are enabled by default
|
// buttons are enabled by default
|
||||||
gb->gwin.enabled = true;
|
gb->gwin.enabled = TRUE;
|
||||||
|
|
||||||
return (GHandle)gb;
|
return (GHandle)gb;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
* Stream interface implementation. The interface is write only
|
* 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))))
|
#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; }
|
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;
|
return (GHandle)gc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GFX_USE_OS_CHIBIOS
|
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
|
||||||
BaseSequentialStream *gwinGetConsoleStream(GHandle gh) {
|
BaseSequentialStream *gwinGetConsoleStream(GHandle gh) {
|
||||||
if (gh->type != GW_CONSOLE)
|
if (gh->type != GW_CONSOLE)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -145,6 +145,203 @@ void gwinPutCharArray(GHandle gh, const char *str, size_t n) {
|
||||||
gwinPutChar(gh, *str++);
|
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 */
|
#endif /* GFX_USE_GWIN && GWIN_NEED_CONSOLE */
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue