From 8c47f68f665a400fd0489041d707b4371308a67e Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 15 Jul 2014 13:47:12 +1000 Subject: [PATCH 01/28] Only destroy the listener in a frame window if it actually was initialised. --- src/gwin/frame.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gwin/frame.c b/src/gwin/frame.c index c10aaea3..356da3b9 100644 --- a/src/gwin/frame.c +++ b/src/gwin/frame.c @@ -38,8 +38,10 @@ static coord_t BorderSizeT(GHandle gh) { return (gh->flags & GWIN_FRAME_BORDER) static void _frameDestroy(GHandle gh) { /* Deregister the button callback */ - geventRegisterCallback(&gh2obj->gl, NULL, NULL); - geventDetachSource(&gh2obj->gl, NULL); + if ((flags & (GWIN_FRAME_CLOSE_BTN|GWIN_FRAME_MINMAX_BTN))) { + geventRegisterCallback(&gh2obj->gl, NULL, NULL); + geventDetachSource(&gh2obj->gl, NULL); + } /* call the gcontainer standard destroy routine */ _gcontainerDestroy(gh); From 679961a25ebfe5f6f858811c9a27dd3ddc3fb9aa Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 15 Jul 2014 14:38:49 +1000 Subject: [PATCH 02/28] Try to prevent type definition conflicts with standard headers --- src/gos/raw32.h | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/gos/raw32.h b/src/gos/raw32.h index 6eb5f26e..5a6a2aa7 100644 --- a/src/gos/raw32.h +++ b/src/gos/raw32.h @@ -42,14 +42,20 @@ /*===========================================================================*/ typedef unsigned char bool_t; -typedef char int8_t; -typedef unsigned char uint8_t; -typedef short int16_t; -typedef unsigned short uint16_t; -typedef int int32_t; -typedef unsigned int uint32_t; -typedef uint32_t size_t; +#ifndef _STDINT_H + typedef char int8_t; + typedef unsigned char uint8_t; + typedef short int16_t; + typedef unsigned short uint16_t; + typedef int int32_t; + typedef unsigned int uint32_t; +#endif + +#if !defined (__need_size_t) && !defined (_STDDEF_H_) + typedef uint32_t size_t; +#endif + typedef uint32_t delaytime_t; typedef uint32_t systemticks_t; typedef short semcount_t; From 0587e351692741cb4c68e161a345def2e2dcea5c Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 15 Jul 2014 16:38:13 +1000 Subject: [PATCH 03/28] Add widget tag support (and fix a couple of doxygen problems) --- gfxconf.example.h | 1 + src/gwin/button.c | 3 +++ src/gwin/button.h | 3 +++ src/gwin/checkbox.c | 3 +++ src/gwin/checkbox.h | 3 +++ src/gwin/gwidget.c | 14 +++++++++++++ src/gwin/gwidget.h | 45 +++++++++++++++++++++++++++++++++++++++--- src/gwin/list.c | 3 +++ src/gwin/list.h | 3 +++ src/gwin/radio.c | 3 +++ src/gwin/radio.h | 3 +++ src/gwin/slider.c | 3 +++ src/gwin/slider.h | 3 +++ src/gwin/sys_options.h | 9 +++++++++ 14 files changed, 96 insertions(+), 3 deletions(-) diff --git a/gfxconf.example.h b/gfxconf.example.h index ef6bedbe..8754ba32 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -166,6 +166,7 @@ // #define GWIN_NEED_PROGRESSBAR FALSE // #define GWIN_PROGRESSBAR_AUTO FALSE // #define GWIN_FLAT_STYLING FALSE +// #define GWIN_WIDGET_TAGS FALSE //#define GWIN_NEED_CONTAINERS FALSE // #define GWIN_NEED_CONTAINER FALSE diff --git a/src/gwin/button.c b/src/gwin/button.c index d489ecb0..fc1cb976 100644 --- a/src/gwin/button.c +++ b/src/gwin/button.c @@ -39,6 +39,9 @@ static void SendButtonEvent(GWidgetObject *gw) { continue; pbe->type = GEVENT_GWIN_BUTTON; pbe->button = (GHandle)gw; + #if GWIN_WIDGET_TAGS + pbe->tag = gw->tag; + #endif geventSendEvent(psl); } diff --git a/src/gwin/button.h b/src/gwin/button.h index 73d5f9f1..077b50f4 100644 --- a/src/gwin/button.h +++ b/src/gwin/button.h @@ -38,6 +38,9 @@ typedef struct GEventGWinButton { GEventType type; // The type of this event (GEVENT_GWIN_BUTTON) GHandle button; // The button that has been depressed (actually triggered on release) + #if GWIN_WIDGET_TAGS + WidgetTag tag; // The button tag + #endif } GEventGWinButton; /** diff --git a/src/gwin/checkbox.c b/src/gwin/checkbox.c index f162d8fc..7914ee82 100644 --- a/src/gwin/checkbox.c +++ b/src/gwin/checkbox.c @@ -33,6 +33,9 @@ static void SendCheckboxEvent(GWidgetObject *gw) { pce->type = GEVENT_GWIN_CHECKBOX; pce->checkbox = &gw->g; pce->isChecked = (gw->g.flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE; + #if GWIN_WIDGET_TAGS + pce->tag = gw->tag; + #endif geventSendEvent(psl); } diff --git a/src/gwin/checkbox.h b/src/gwin/checkbox.h index 2b1fb801..ebd35a0b 100644 --- a/src/gwin/checkbox.h +++ b/src/gwin/checkbox.h @@ -38,6 +38,9 @@ typedef struct GEventGWinCheckbox { GEventType type; // The type of this event (GEVENT_GWIN_CHECKBOX) GHandle checkbox; // The checkbox that has been depressed (actually triggered on release) bool_t isChecked; // Is the checkbox currently checked or unchecked? + #if GWIN_WIDGET_TAGS + WidgetTag tag; // The checkbox tag + #endif } GEventGWinCheckbox; /* A Checkbox window */ diff --git a/src/gwin/gwidget.c b/src/gwin/gwidget.c index 8ccb47fc..a2e6f472 100644 --- a/src/gwin/gwidget.c +++ b/src/gwin/gwidget.c @@ -242,6 +242,9 @@ GHandle _gwidgetCreate(GDisplay *g, GWidgetObject *pgw, const GWidgetInit *pInit pgw->fnDraw = pInit->customDraw ? pInit->customDraw : vmt->DefaultDraw; pgw->fnParam = pInit->customParam; pgw->pstyle = pInit->customStyle ? pInit->customStyle : defaultStyle; + #if GWIN_WIDGET_TAGS + pgw->tag = pInit->tag; + #endif return &pgw->g; } @@ -473,5 +476,16 @@ bool_t gwinAttachListener(GListener *pl) { } #endif +#if GWIN_WIDGET_TAGS + void gwinSetTag(GHandle gh, WidgetTag tag) { + if ((gh->flags & GWIN_FLG_WIDGET)) + gw->tag = tag; + } + + WidgetTag gwinGetTag(GHandle gh) { + return ((gh->flags & GWIN_FLG_WIDGET)) ? gw->tag : 0; + } +#endif + #endif /* GFX_USE_GWIN && GWIN_NEED_WIDGET */ /** @} */ diff --git a/src/gwin/gwidget.h b/src/gwin/gwidget.h index 0a7bc72f..bd1ea4c8 100644 --- a/src/gwin/gwidget.h +++ b/src/gwin/gwidget.h @@ -72,6 +72,11 @@ extern const GWidgetStyle WhiteWidgetStyle; */ typedef void (*CustomWidgetDrawFunction)(struct GWidgetObject *gw, void *param); +/** + * @brief Defines a the type of a tag on a widget + */ +typedef uint16_t WidgetTag; + /** * @brief The structure to initialise a widget. * @@ -92,6 +97,9 @@ typedef struct GWidgetInit { CustomWidgetDrawFunction customDraw; // @< A custom draw function - use NULL for the standard void * customParam; // @< A parameter for the custom draw function (default = NULL) const GWidgetStyle * customStyle; // @< A custom style to use - use NULL for the default style + #if GWIN_WIDGET_TAGS || defined(__DOXYGEN__) + WidgetTag tag; // @< The tag to associate with the widget + #endif } GWidgetInit; /** @} */ @@ -110,6 +118,9 @@ typedef struct GWidgetObject { CustomWidgetDrawFunction fnDraw; // @< The current draw function void * fnParam; // @< A parameter for the current draw function const GWidgetStyle * pstyle; // @< The current widget style colors + #if GWIN_WIDGET_TAGS || defined(__DOXYGEN__) + WidgetTag tag; // @< The widget tag + #endif } GWidgetObject; /** @} */ @@ -187,6 +198,34 @@ void gwinSetText(GHandle gh, const char *text, bool_t useAlloc); */ const char *gwinGetText(GHandle gh); +#if GWIN_WIDGET_TAGS || defined(__DOXYGEN__) + /** + * @brief Set the tag of a widget. + * + * @param[in] gh The widget handle + * @param[in] tag The tag to set. + * + * @note Non-widgets will ignore this call. + * + * @pre Requires GWIN_WIDGET_TAGS to be TRUE + * + * @api + */ + void gwinSetTag(GHandle gh, WidgetTag tag); + + /** + * @brief Get the tag of a widget. + * @return The widget tag value (or 0 if it is not a widget) + * + * @param[in] gh The widget handle + * + * @pre Requires GWIN_WIDGET_TAGS to be TRUE + * + * @api + */ + WidgetTag gwinGetTag(GHandle gh); +#endif + /** * @brief Set the style of a widget. * @@ -235,7 +274,7 @@ void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param); */ bool_t gwinAttachListener(GListener *pl); -#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE +#if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) || defined(__DOXYGEN__) /** * @brief Set the mouse to be used to control the widgets * @return TRUE on success @@ -249,7 +288,7 @@ bool_t gwinAttachListener(GListener *pl); bool_t gwinAttachMouse(uint16_t instance); #endif -#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE +#if (GFX_USE_GINPUT && GINPUT_NEED_TOGGLE) || defined(__DOXYGEN__) /** * @brief Attach a toggle to a widget * @return TRUE on success @@ -267,7 +306,7 @@ bool_t gwinAttachListener(GListener *pl); bool_t gwinAttachToggle(GHandle gh, uint16_t role, uint16_t instance); #endif -#if GFX_USE_GINPUT && GINPUT_NEED_DIAL +#if (GFX_USE_GINPUT && GINPUT_NEED_DIAL) || defined(__DOXYGEN__) /** * @brief Attach a toggle to a widget * @return TRUE on success diff --git a/src/gwin/list.c b/src/gwin/list.c index c2a857e3..98ec2ed5 100644 --- a/src/gwin/list.c +++ b/src/gwin/list.c @@ -66,6 +66,9 @@ static void sendListEvent(GWidgetObject *gw, int item) { ple->type = GEVENT_GWIN_LIST; ple->list = (GHandle)gw; ple->item = item; + #if GWIN_WIDGET_TAGS + ple->tag = gw->tag; + #endif geventSendEvent(psl); } diff --git a/src/gwin/list.h b/src/gwin/list.h index 9e31bf2a..1eae3c19 100644 --- a/src/gwin/list.h +++ b/src/gwin/list.h @@ -40,6 +40,9 @@ typedef struct GEventGWinList { GEventType type; // The type of this event (GEVENT_GWIN_LIST) GHandle list; // The list int item; // The item that has been selected (or unselected in a multi-select listbox) + #if GWIN_WIDGET_TAGS + WidgetTag tag; // The list tag + #endif } GEventGWinList; // A list window diff --git a/src/gwin/radio.c b/src/gwin/radio.c index af7b877d..557061e4 100644 --- a/src/gwin/radio.c +++ b/src/gwin/radio.c @@ -38,6 +38,9 @@ static void SendRadioEvent(GWidgetObject *gw) { pbe->type = GEVENT_GWIN_RADIO; pbe->radio = (GHandle)gw; pbe->group = ((GRadioObject *)gw)->group; + #if GWIN_WIDGET_TAGS + pbe->tag = gw->tag; + #endif geventSendEvent(psl); } diff --git a/src/gwin/radio.h b/src/gwin/radio.h index 196f8e27..eb7ee719 100644 --- a/src/gwin/radio.h +++ b/src/gwin/radio.h @@ -37,6 +37,9 @@ typedef struct GEventGWinRadio { GEventType type; // The type of this event (GEVENT_GWIN_RADIO) GHandle radio; // The radio button that has been depressed uint16_t group; // The group for this radio button + #if GWIN_WIDGET_TAGS + WidgetTag tag; // The radio tag + #endif } GEventGWinRadio; /** diff --git a/src/gwin/slider.c b/src/gwin/slider.c index b488f823..7ce7b83f 100644 --- a/src/gwin/slider.c +++ b/src/gwin/slider.c @@ -38,6 +38,9 @@ static void SendSliderEvent(GWidgetObject *gw) { pse->type = GEVENT_GWIN_SLIDER; pse->slider = (GHandle)gw; pse->position = ((GSliderObject *)gw)->pos; + #if GWIN_WIDGET_TAGS + pse->tag = gw->tag; + #endif geventSendEvent(psl); } diff --git a/src/gwin/slider.h b/src/gwin/slider.h index 41244186..32161d62 100644 --- a/src/gwin/slider.h +++ b/src/gwin/slider.h @@ -30,6 +30,9 @@ typedef struct GEventGWinSlider { GEventType type; // The type of this event (GEVENT_GWIN_BUTTON) GHandle slider; // The slider that is returning results int position; + #if GWIN_WIDGET_TAGS + WidgetTag tag; // The slider tag + #endif } GEventGWinSlider; // There are currently no GEventGWinSlider listening flags - use 0 diff --git a/src/gwin/sys_options.h b/src/gwin/sys_options.h index b1b58a68..d5240556 100644 --- a/src/gwin/sys_options.h +++ b/src/gwin/sys_options.h @@ -127,6 +127,15 @@ * @name GWIN Optional Parameters * @{ */ + /** + * @brief Add a tag to each widget + * @details Defaults to FALSE + * @note Adds a tag member to each widget. Any events created include this tag. + * The enables switch based application logic to detect the event source. + */ + #ifndef GWIN_WIDGET_TAGS + #define GWIN_WIDGET_TAGS FALSE + #endif /** * @brief Use flat styling for controls rather than a 3D look * @details Defaults to FALSE From 0a5bfdd6eca2e94187f5f452ca6a04584897705b Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 15 Jul 2014 16:38:33 +1000 Subject: [PATCH 04/28] Fix compile warning --- src/gfile/gfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gfile/gfile.c b/src/gfile/gfile.c index 6aadda09..abffd410 100644 --- a/src/gfile/gfile.c +++ b/src/gfile/gfile.c @@ -542,7 +542,7 @@ bool_t gfileSync(GFILE *f) { 0, 0, 0, 0, 0, 0, StringRead, StringWrite, 0, 0, 0, - 0, 0 + 0, 0, 0 }; #endif From 949290c01d52907222e6f7af8eb8a0e906f09a93 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 16 Jul 2014 16:42:37 +1000 Subject: [PATCH 05/28] typo --- src/gwin/frame.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gwin/frame.c b/src/gwin/frame.c index 356da3b9..3f41c69f 100644 --- a/src/gwin/frame.c +++ b/src/gwin/frame.c @@ -38,7 +38,7 @@ static coord_t BorderSizeT(GHandle gh) { return (gh->flags & GWIN_FRAME_BORDER) static void _frameDestroy(GHandle gh) { /* Deregister the button callback */ - if ((flags & (GWIN_FRAME_CLOSE_BTN|GWIN_FRAME_MINMAX_BTN))) { + if ((gh->flags & (GWIN_FRAME_CLOSE_BTN|GWIN_FRAME_MINMAX_BTN))) { geventRegisterCallback(&gh2obj->gl, NULL, NULL); geventDetachSource(&gh2obj->gl, NULL); } From 1d4d9b4c9492f25744ffd6b798101e7a875562bb Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 16 Jul 2014 16:44:19 +1000 Subject: [PATCH 06/28] Rebuild GEvent. It should be faster, have less contention problems, use less memory and allow reentrancy from a callback handler. --- src/gevent/gevent.c | 98 ++++++++++++++++++++++++++++--------------- src/gevent/sys_defs.h | 21 ++++++++-- 2 files changed, 82 insertions(+), 37 deletions(-) diff --git a/src/gevent/gevent.c b/src/gevent/gevent.c index 779f63a0..f1dab064 100644 --- a/src/gevent/gevent.c +++ b/src/gevent/gevent.c @@ -22,26 +22,40 @@ #define GEVENT_ASSERT(x) #endif +/* Flags in the listener structure */ +#define GLISTENER_EVENTBUSY 0x0001 // The event buffer is busy +#define GLISTENER_WAITING 0x0002 // The listener is waiting for a signal +#define GLISTENER_WITHSOURCE 0x0004 // The listener is being looked at by a source for a possible event + /* This mutex protects access to our tables */ static gfxMutex geventMutex; /* Our table of listener/source pairs */ static GSourceListener Assignments[GEVENT_MAX_SOURCE_LISTENERS]; +/* Send an exit event if possible. */ +/* We already have the geventMutex */ +static void doExitEvent(GListener *pl) { + // Don't do the exit if someone else currently has the event lock + if ((pl->flags & (GLISTENER_WAITING|GLISTENER_EVENTBUSY)) == GLISTENER_WAITING) { + pl->flags |= GLISTENER_EVENTBUSY; // Event buffer is in use + pl->event.type = GEVENT_EXIT; // Set up the EXIT event + pl->flags &= ~GLISTENER_WAITING; // Wake up the listener (with data) + gfxSemSignal(&pl->waitqueue); + } +} + /* Loop through the assignment table deleting this listener/source pair. */ /* Null is treated as a wildcard. */ +/* We already have the geventMutex */ static void deleteAssignments(GListener *pl, GSourceHandle gsh) { GSourceListener *psl; for(psl = Assignments; psl < Assignments+GEVENT_MAX_SOURCE_LISTENERS; psl++) { if ((!pl || psl->pListener == pl) && (!gsh || psl->pSource == gsh)) { - if (gfxSemCounter(&psl->pListener->waitqueue) < 0) { - gfxSemWait(&psl->pListener->eventlock, TIME_INFINITE); // Obtain the buffer lock - psl->pListener->event.type = GEVENT_EXIT; // Set up the EXIT event - gfxSemSignal(&psl->pListener->waitqueue); // Wake up the listener - gfxSemSignal(&psl->pListener->eventlock); // Release the buffer lock - } + doExitEvent(psl->pListener); psl->pListener = 0; + psl->pSource = 0; } } } @@ -58,9 +72,9 @@ void _geventDeinit(void) void geventListenerInit(GListener *pl) { gfxSemInit(&pl->waitqueue, 0, MAX_SEMAPHORE_COUNT); // Next wait'er will block - gfxSemInit(&pl->eventlock, 1, 1); // Only one thread at a time looking at the event buffer pl->callback = 0; // No callback active pl->event.type = GEVENT_NULL; // Always safety + pl->flags = 0; } bool_t geventAttachSource(GListener *pl, GSourceHandle gsh, unsigned flags) { @@ -80,9 +94,7 @@ bool_t geventAttachSource(GListener *pl, GSourceHandle gsh, unsigned flags) { if (pl == psl->pListener && gsh == psl->pSource) { // Just update the flags - gfxSemWait(&pl->eventlock, TIME_INFINITE); // Safety first - just in case a source is using it psl->listenflags = flags; - gfxSemSignal(&pl->eventlock); // Release this lock gfxMutexExit(&geventMutex); return TRUE; } @@ -106,33 +118,37 @@ void geventDetachSource(GListener *pl, GSourceHandle gsh) { if (pl) { gfxMutexEnter(&geventMutex); deleteAssignments(pl, gsh); - if (!gsh && gfxSemCounter(&pl->waitqueue) < 0) { - gfxSemWait(&pl->eventlock, TIME_INFINITE); // Obtain the buffer lock - pl->event.type = GEVENT_EXIT; // Set up the EXIT event - gfxSemSignal(&pl->waitqueue); // Wake up the listener - gfxSemSignal(&pl->eventlock); // Release the buffer lock - } + if (!gsh) + doExitEvent(pl); gfxMutexExit(&geventMutex); } } GEvent *geventEventWait(GListener *pl, delaytime_t timeout) { - if (pl->callback || gfxSemCounter(&pl->waitqueue) < 0) + gfxMutexEnter(&geventMutex); + // Don't allow waiting if we are on callbacks or if there is already a thread waiting + if (pl->callback || (pl->flags & GLISTENER_WAITING)) { + gfxMutexExit(&geventMutex); return 0; + } + pl->flags &= ~GLISTENER_EVENTBUSY; // Event buffer is definitely not busy + pl->flags |= GLISTENER_WAITING; // We will now be waiting on the thread + gfxMutexExit(&geventMutex); return gfxSemWait(&pl->waitqueue, timeout) ? &pl->event : 0; } +void geventEventComplete(GListener *pl) { + pl->flags &= ~GLISTENER_EVENTBUSY; +} + void geventRegisterCallback(GListener *pl, GEventCallbackFn fn, void *param) { if (pl) { gfxMutexEnter(&geventMutex); - gfxSemWait(&pl->eventlock, TIME_INFINITE); // Obtain the buffer lock - pl->param = param; // Set the param - pl->callback = fn; // Set the callback function - if (gfxSemCounter(&pl->waitqueue) < 0) { - pl->event.type = GEVENT_EXIT; // Set up the EXIT event - gfxSemSignal(&pl->waitqueue); // Wake up the listener - } - gfxSemSignal(&pl->eventlock); // Release the buffer lock + doExitEvent(pl); + pl->param = param; // Set the param + pl->callback = fn; // Set the callback function + if (fn) + pl->flags &= ~GLISTENER_EVENTBUSY; // The event buffer is immediately available gfxMutexExit(&geventMutex); } } @@ -146,14 +162,13 @@ GSourceListener *geventGetSourceListener(GSourceHandle gsh, GSourceListener *las gfxMutexEnter(&geventMutex); - // Unlock the last listener event buffer - if (lastlr) - gfxSemSignal(&lastlr->pListener->eventlock); + // Unlock the last listener event buffer if it wasn't used. + if (lastlr && lastlr->pListener && (lastlr->pListener->flags & GLISTENER_WITHSOURCE)) + lastlr->pListener->flags &= ~(GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY); // Loop through the table looking for attachments to this source for(psl = lastlr ? (lastlr+1) : Assignments; psl < Assignments+GEVENT_MAX_SOURCE_LISTENERS; psl++) { if (gsh == psl->pSource) { - gfxSemWait(&psl->pListener->eventlock, TIME_INFINITE); // Obtain a lock on the listener event buffer gfxMutexExit(&geventMutex); return psl; } @@ -163,21 +178,38 @@ GSourceListener *geventGetSourceListener(GSourceHandle gsh, GSourceListener *las } GEvent *geventGetEventBuffer(GSourceListener *psl) { - // We already know we have the event lock - return &psl->pListener->callback || gfxSemCounter(&psl->pListener->waitqueue) < 0 ? &psl->pListener->event : 0; + gfxMutexEnter(&geventMutex); + if ((psl->pListener->flags & GLISTENER_EVENTBUSY)) { + // Oops - event buffer is still in use + gfxMutexExit(&geventMutex); + return 0; + } + + // Allocate the event buffer + psl->pListener->flags |= (GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY); + gfxMutexExit(&geventMutex); + return &psl->pListener->event; } void geventSendEvent(GSourceListener *psl) { gfxMutexEnter(&geventMutex); - if (psl->pListener->callback) { // This test needs to be taken inside the mutex + if (psl->pListener->callback) { + + // Mark it back as free and as sent. This is early to be marking as free but it protects + // if the callback alters the listener in any way + psl->pListener->flags &= ~(GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY); gfxMutexExit(&geventMutex); - // We already know we have the event lock + + // Do the callback psl->pListener->callback(psl->pListener->param, &psl->pListener->event); } else { // Wake up the listener - if (gfxSemCounter(&psl->pListener->waitqueue) <= 0) + if ((psl->pListener->flags & GLISTENER_WAITING)) { + psl->pListener->flags &= ~(GLISTENER_WITHSOURCE|GLISTENER_WAITING); gfxSemSignal(&psl->pListener->waitqueue); + // The listener thread will free the event buffer when ready + } gfxMutexExit(&geventMutex); } } diff --git a/src/gevent/sys_defs.h b/src/gevent/sys_defs.h index c50dc5ae..9f1f4dde 100644 --- a/src/gevent/sys_defs.h +++ b/src/gevent/sys_defs.h @@ -56,7 +56,7 @@ typedef void (*GEventCallbackFn)(void *param, GEvent *pe); // The Listener Object typedef struct GListener { gfxSem waitqueue; // Private: Semaphore for the listener to wait on. - gfxSem eventlock; // Private: Protect against more than one sources trying to use this event lock at the same time + uint16_t flags; // Private: Flags for operation GEventCallbackFn callback; // Private: Call back Function void *param; // Private: Parameter for the callback function. GEvent event; // Public: The event object into which the event information is stored. @@ -149,9 +149,11 @@ void geventDetachSource(GListener *pl, GSourceHandle gsh); * timeout specifies the time to wait in system ticks. * TIME_INFINITE means no timeout - wait forever for an event. * TIME_IMMEDIATE means return immediately - * @note The GEvent buffer is staticly allocated within the GListener so the event does not - * need to be dynamicly freed however it will get overwritten by the next call to - * this routine. + * @note The returned GEvent is released when this routine is called again + * or when optionally @p geventEventComplete() is called. Calling @p geventEventComplete() + * allows the GEvent object to be reused earlier which can reduce missed events. The GEvent + * object MUST NOT be used after this function is called (and is blocked waiting for the next + * event) or after geventEventComplete() is called. * * @param[in] pl The listener * @param[in] timeout The timeout @@ -160,6 +162,17 @@ void geventDetachSource(GListener *pl, GSourceHandle gsh); */ GEvent *geventEventWait(GListener *pl, delaytime_t timeout); +/** + * @brief Release the GEvent buffer associated with a listener. + * @details The GEvent returned by @p geventEventWait() is released. + * @note The GEvent pointer returned by @p geventEventWait() is released when @p geventEventWait() + * is called again or when this function is called. The GEvent + * object MUST NOT be used after this function is called. + * + * @param[in] pl The listener + */ +void geventEventComplete(GListener *pl); + /* @brief Register a callback for an event on a listener from an assigned source. * @details The type of the event should be checked (pevent->type) and then pevent should be typecast to the * actual event type if it needs to be processed. From 0d982a55785c189764dd51ec86a073e440e9d863 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 17 Jul 2014 18:17:34 +1000 Subject: [PATCH 07/28] trunet contributed R61505U gdisp driver --- .../gdisp/R61505U/board_R61505U_template.h | 60 +++ drivers/gdisp/R61505U/gdisp_lld.mk | 2 + drivers/gdisp/R61505U/gdisp_lld_R61505U.c | 385 ++++++++++++++++++ drivers/gdisp/R61505U/gdisp_lld_config.h | 26 ++ 4 files changed, 473 insertions(+) create mode 100644 drivers/gdisp/R61505U/board_R61505U_template.h create mode 100644 drivers/gdisp/R61505U/gdisp_lld.mk create mode 100644 drivers/gdisp/R61505U/gdisp_lld_R61505U.c create mode 100644 drivers/gdisp/R61505U/gdisp_lld_config.h diff --git a/drivers/gdisp/R61505U/board_R61505U_template.h b/drivers/gdisp/R61505U/board_R61505U_template.h new file mode 100644 index 00000000..a4787730 --- /dev/null +++ b/drivers/gdisp/R61505U/board_R61505U_template.h @@ -0,0 +1,60 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef GDISP_LLD_BOARD_H +#define GDISP_LLD_BOARD_H + +static inline void init_board(GDisplay *g) { + (void) g; +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void) percent; +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + (void) index; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + (void) data; +} + +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return 0; +} + +#endif /* GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/R61505U/gdisp_lld.mk b/drivers/gdisp/R61505U/gdisp_lld.mk new file mode 100644 index 00000000..ff0d0bf4 --- /dev/null +++ b/drivers/gdisp/R61505U/gdisp_lld.mk @@ -0,0 +1,2 @@ +GFXINC += $(GFXLIB)/drivers/gdisp/R61505U +GFXSRC += $(GFXLIB)/drivers/gdisp/R61505U/gdisp_lld_R61505U.c diff --git a/drivers/gdisp/R61505U/gdisp_lld_R61505U.c b/drivers/gdisp/R61505U/gdisp_lld_R61505U.c new file mode 100644 index 00000000..dd966c03 --- /dev/null +++ b/drivers/gdisp/R61505U/gdisp_lld_R61505U.c @@ -0,0 +1,385 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#include "gfx.h" + +#if GFX_USE_GDISP + +/* This controller is only ever used with a 240 x 320 display */ +#if defined(GDISP_SCREEN_HEIGHT) + #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." + #undef GDISP_SCREEN_HEIGHT +#endif +#if defined(GDISP_SCREEN_WIDTH) + #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." + #undef GDISP_SCREEN_WIDTH +#endif + +#define GDISP_DRIVER_VMT GDISPVMT_R61505U +#include "drivers/gdisp/R61505U/gdisp_lld_config.h" +#include "src/gdisp/driver.h" + +#include "board_R61505U.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 320 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 240 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#define dummy_read(g) { volatile uint16_t dummy; dummy = read_data(g); (void) dummy; } +#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } + +static void set_cursor(GDisplay *g) { + switch(g->g.Orientation) { + default: + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + write_reg(g, 0x20, g->p.x); + write_reg(g, 0x21, g->p.y); + break; + + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + write_reg(g, 0x20, g->p.y); + write_reg(g, 0x21, g->p.x); + break; + } + write_index(g, 0x22); +} + +static void set_viewport(GDisplay *g) { + switch(g->g.Orientation) { + default: + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + write_reg(g, 0x50, g->p.x); + write_reg(g, 0x51, g->p.x + g->p.cx - 1); + write_reg(g, 0x52, g->p.y); + write_reg(g, 0x53, g->p.y + g->p.cy - 1); + break; + + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + write_reg(g, 0x50, g->p.y); + write_reg(g, 0x51, g->p.y + g->p.cy - 1); + write_reg(g, 0x52, g->p.x); + write_reg(g, 0x53, g->p.x + g->p.cx - 1); + break; + } +} + +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + uint16_t cver; + + // No private area for this controller + g->priv = 0; + + // Initialise the board interface + init_board(g); + + /* Hardware reset */ + setpin_reset(g, TRUE); + gfxSleepMicroseconds(1000); + setpin_reset(g, FALSE); + gfxSleepMicroseconds(1000); + + acquire_bus(g); + write_index(g, 0); // Get controller version + setreadmode(g); + dummy_read(g); + cver = read_data(g); + setwritemode(g); + + /* initializing funciton */ + write_reg(g, 0xe5,0x8000); /* Set the internal vcore voltage */ + write_reg(g, 0x00,0x0001); /* start OSC */ + write_reg(g, 0x2b,0x0010); /* Set the frame rate as 80 when the internal resistor is used for oscillator circuit */ + write_reg(g, 0x01,0x0100); /* s720 to s1 ; G1 to G320 */ + write_reg(g, 0x02,0x0700); /* set the line inversion */ + write_reg(g, 0x03,0x1018); /* 65536 colors */ + write_reg(g, 0x04,0x0000); + write_reg(g, 0x08,0x0202); /* specify the line number of front and back porch periods respectively */ + write_reg(g, 0x09,0x0000); + write_reg(g, 0x0a,0x0000); + write_reg(g, 0x0c,0x0000); /* select internal system clock */ + write_reg(g, 0x0d,0x0000); + write_reg(g, 0x0f,0x0000); + write_reg(g, 0x50,0x0000); /* set windows adress */ + write_reg(g, 0x51,0x00ef); + write_reg(g, 0x52,0x0000); + write_reg(g, 0x53,0x013f); + write_reg(g, 0x60,0x2700); + write_reg(g, 0x61,0x0001); + write_reg(g, 0x6a,0x0000); + write_reg(g, 0x80,0x0000); + write_reg(g, 0x81,0x0000); + write_reg(g, 0x82,0x0000); + write_reg(g, 0x83,0x0000); + write_reg(g, 0x84,0x0000); + write_reg(g, 0x85,0x0000); + write_reg(g, 0x90,0x0010); + write_reg(g, 0x92,0x0000); + write_reg(g, 0x93,0x0003); + write_reg(g, 0x95,0x0110); + write_reg(g, 0x97,0x0000); + write_reg(g, 0x98,0x0000); + /* power setting function */ + write_reg(g, 0x10,0x0000); + write_reg(g, 0x11,0x0000); + write_reg(g, 0x12,0x0000); + write_reg(g, 0x13,0x0000); + gfxSleepMicroseconds(100); + write_reg(g, 0x10,0x17b0); + write_reg(g, 0x11,0x0004); + gfxSleepMicroseconds(50); + write_reg(g, 0x12,0x013e); + gfxSleepMicroseconds(50); + write_reg(g, 0x13,0x1f00); + write_reg(g, 0x29,0x000f); + gfxSleepMicroseconds(50); + write_reg(g, 0x20,0x0000); + write_reg(g, 0x21,0x0000); + + /* initializing function */ + write_reg(g, 0x30,0x0204); + write_reg(g, 0x31,0x0001); + write_reg(g, 0x32,0x0000); + write_reg(g, 0x35,0x0206); + write_reg(g, 0x36,0x0600); + write_reg(g, 0x37,0x0500); + write_reg(g, 0x38,0x0505); + write_reg(g, 0x39,0x0407); + write_reg(g, 0x3c,0x0500); + write_reg(g, 0x3d,0x0503); + + /* display on */ + write_reg(g, 0x07,0x0173); + + gfxSleepMicroseconds(50); + + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(g); + + // Turn on the backlight + set_backlight(g, GDISP_INITIAL_BACKLIGHT); + + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; + return TRUE; +} + +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + #if !GDISP_HARDWARE_STREAM_POS + set_cursor(g); + #endif + } + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_data(g, gdispColor2Native(g->p.color)); + } + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + release_bus(g); + } + #if GDISP_HARDWARE_STREAM_POS + LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { + set_cursor(g); + } + #endif +#endif + +#if GDISP_HARDWARE_STREAM_READ + LLDSPEC void gdisp_lld_read_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + set_cursor(g); + setreadmode(g); + dummy_read(g); + } + LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { + uint16_t data; + + data = read_data(g); + return gdispNative2Color(data); + } + LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { + setwritemode(g); + release_bus(g); + } +#endif + +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + acquire_bus(g); + write_reg(g, 0x07, 0x0000); + write_reg(g, 0x10, 0x0000); + write_reg(g, 0x11, 0x0000); + write_reg(g, 0x12, 0x0000); + write_reg(g, 0x13, 0x0000); + release_bus(g); + + set_backlight(g, 0); + break; + + case powerOn: + //*************Power On sequence ******************// + acquire_bus(g); + write_reg(g, 0x10, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ + write_reg(g, 0x11, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(g, 0x12, 0x0000); /* VREG1OUT voltage */ + write_reg(g, 0x13, 0x0000); /* VDV[4:0] for VCOM amplitude */ + gfxSleepMicroseconds(2000); /* Dis-charge capacitor power voltage */ + write_reg(g, 0x10, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ + write_reg(g, 0x11, 0x0147); /* DC1[2:0], DC0[2:0], VC[2:0] */ + gfxSleepMicroseconds(500); + write_reg(g, 0x12, 0x013C); /* VREG1OUT voltage */ + gfxSleepMicroseconds(500); + write_reg(g, 0x13, 0x0E00); /* VDV[4:0] for VCOM amplitude */ + write_reg(g, 0x29, 0x0009); /* VCM[4:0] for VCOMH */ + gfxSleepMicroseconds(500); + write_reg(g, 0x07, 0x0173); /* 262K color and display ON */ + release_bus(g); + + set_backlight(g, g->g.Backlight); + break; + + case powerSleep: + acquire_bus(g); + write_reg(g, 0x07, 0x0000); /* display OFF */ + write_reg(g, 0x10, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + write_reg(g, 0x11, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(g, 0x12, 0x0000); /* VREG1OUT voltage */ + write_reg(g, 0x13, 0x0000); /* VDV[4:0] for VCOM amplitude */ + gfxSleepMicroseconds(2000); /* Dis-charge capacitor power voltage */ + write_reg(g, 0x10, 0x0002); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + release_bus(g); + + set_backlight(g, 0); + break; + + case powerDeepSleep: + acquire_bus(g); + write_reg(g, 0x07, 0x0000); /* display OFF */ + write_reg(g, 0x10, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + write_reg(g, 0x11, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(g, 0x12, 0x0000); /* VREG1OUT voltage */ + write_reg(g, 0x13, 0x0000); /* VDV[4:0] for VCOM amplitude */ + gfxSleepMicroseconds(2000); /* Dis-charge capacitor power voltage */ + write_reg(g, 0x10, 0x0004); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + release_bus(g); + + set_backlight(g, 0); + break; + + default: + return; + } + g->g.Powermode = (powermode_t)g->p.ptr; + return; + + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + acquire_bus(g); + write_reg(g, 0x01, 0x0100); + write_reg(g, 0x03, 0x1038); + write_reg(g, 0x60, 0x2700); + release_bus(g); + + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + + case GDISP_ROTATE_90: + acquire_bus(g); + write_reg(g, 0x01, 0x0000); + write_reg(g, 0x03, 0x1030); + write_reg(g, 0x60, 0x2700); + release_bus(g); + + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + + case GDISP_ROTATE_180: + acquire_bus(g); + write_reg(g, 0x01, 0x0000); + write_reg(g, 0x03, 0x1030); + write_reg(g, 0x60, 0x2700); + release_bus(g); + + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + + case GDISP_ROTATE_270: + acquire_bus(g); + write_reg(g, 0x01, 0x0100); + write_reg(g, 0x03, 0x1038); + write_reg(g, 0x60, 0xA700); + release_bus(g); + + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + set_backlight(g, (unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; + default: + return; + } + } +#endif + +#endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/R61505U/gdisp_lld_config.h b/drivers/gdisp/R61505U/gdisp_lld_config.h new file mode 100644 index 00000000..04834079 --- /dev/null +++ b/drivers/gdisp/R61505U/gdisp_lld_config.h @@ -0,0 +1,26 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef GDISP_LLD_CONFIG_H +#define GDISP_LLD_CONFIG_H + +#if GFX_USE_GDISP + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +#define GDISP_HARDWARE_STREAM_WRITE TRUE +#define GDISP_HARDWARE_STREAM_READ TRUE +//#define GDISP_HARDWARE_STREAM_POS TRUE +#define GDISP_HARDWARE_CONTROL TRUE + +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_LLD_CONFIG_H */ From ae50541fd7114cc12e9d520f43065b41d4a5d597 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 18 Jul 2014 09:28:52 +1000 Subject: [PATCH 08/28] Update releases documentation --- docs/releases.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/releases.txt b/docs/releases.txt index 2d5bb648..737ea552 100644 --- a/docs/releases.txt +++ b/docs/releases.txt @@ -15,6 +15,9 @@ FEATURE: Added support for eCos FEATURE: Added PCF8812 gdisp driver FEATURE: Added PCD8544 gdisp driver FEATURE: Added Raspberry Pi board support +FEATURE: Added R61505U gdisp driver +FIX: Fix threading issues in GEvent for callbacks +FEATURE: Added geventEventComplete() *** Release 2.1 *** From 05dd4f404b6e5586c29141a7aa3dd5b54b1c88d6 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Wed, 23 Jul 2014 18:20:54 +0200 Subject: [PATCH 09/28] Win32 readme fix --- drivers/multiple/Win32/readme.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/multiple/Win32/readme.txt b/drivers/multiple/Win32/readme.txt index 353f5a5b..932deb8b 100644 --- a/drivers/multiple/Win32/readme.txt +++ b/drivers/multiple/Win32/readme.txt @@ -16,7 +16,14 @@ optionally a touchscreen driver, and optionally a toggle driver. 2. To your makefile add the following lines: include $(GFXLIB)/gfx.mk - include $(GFXLIB)/drivers/multiple/Win32/gdisp_lld.mk + include $(GFXLIB)/drivers/multiple/Win32/driver.mk + + However, consider using the Win32 board file instead as this does include all + the possible drivers that can be used (eg. for the GAUDIO module) by using: + + include $(GFXLIB)/gfx.mk + include $(GFXLIB)/boards/base/Win32/board.mk + 3. Modify your makefile to add -lws2_32 and -lgdi32 to the DLIBS line. i.e. DLIBS = -lws2_32 -lgdi32 From ed14e4ca568ae632cf8fc9e4b46ce4da81a40282 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 29 Jul 2014 10:57:01 +1000 Subject: [PATCH 10/28] Some improvements for the Kiel C compiler --- src/gdisp/gdisp.c | 6 +++++- src/gwin/class_gwin.h | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index e9ede8ab..b8b4a847 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -21,7 +21,11 @@ #if 1 #undef INLINE - #define INLINE inline + #if defined(__KEIL__) || defined(__C51__) + #define INLINE __inline + #else + #define INLINE inline + #endif #else #undef INLINE #define INLINE diff --git a/src/gwin/class_gwin.h b/src/gwin/class_gwin.h index 995121b7..b32e4da2 100644 --- a/src/gwin/class_gwin.h +++ b/src/gwin/class_gwin.h @@ -23,6 +23,10 @@ #if GFX_USE_GWIN || defined(__DOXYGEN__) +#if defined(__KEIL__) || defined(__C51__) + #pragma anon_unions +#endif + /** * @brief The predefined flags for a Window * @{ From f08f35a9e478f5290989e3ec01a9eb96b4014dbb Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 29 Jul 2014 11:01:08 +1000 Subject: [PATCH 11/28] Support for rawrtos real time operating system --- docs/releases.txt | 2 +- src/gos/rawrtos.c | 79 +++++++++++++++++++++++++++++++++++++++++++++ src/gos/rawrtos.h | 77 +++++++++++++++++++++++++++++++++++++++++++ src/gos/sys_defs.h | 2 ++ src/gos/sys_rules.h | 4 +-- 5 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 src/gos/rawrtos.c create mode 100644 src/gos/rawrtos.h diff --git a/docs/releases.txt b/docs/releases.txt index 737ea552..46a58ab4 100644 --- a/docs/releases.txt +++ b/docs/releases.txt @@ -18,7 +18,7 @@ FEATURE: Added Raspberry Pi board support FEATURE: Added R61505U gdisp driver FIX: Fix threading issues in GEvent for callbacks FEATURE: Added geventEventComplete() - +FEATURE: Added support for the rawrtos real time operating system *** Release 2.1 *** FIX: Significant improvements to the way the MCU touch driver works. diff --git a/src/gos/rawrtos.c b/src/gos/rawrtos.c new file mode 100644 index 00000000..688828c9 --- /dev/null +++ b/src/gos/rawrtos.c @@ -0,0 +1,79 @@ +#include "gfx.h" + +#if GFX_USE_OS_RAWRTOS + +#include +#include "raw_api.h" +#include "raw_config.h" + +#if CONFIG_RAW_MUTEX != 1 + #error "GOS: CONFIG_RAW_MUTEX must be defined in raw_config.h" +#endif + +#if CONFIG_RAW_SEMAPHORE != 1 + #error "GOS: CONFIG_RAW_SEMAPHORE must be defined in raw_config.h" +#endif + + +void _gosInit(void) +{ + // The user must call raw_os_start() himself before he calls gfxInit(). +} + +void _gosDeinit(void) +{ +} + + +void gfxSleepMilliseconds(delaytime_t ms) +{ + systemticks_t ticks = ms*RAW_TICKS_PER_SECOND/1000; + if(!ticks)ticks = 1; + raw_sleep(ticks); +} + +void gfxSleepMicroseconds(delaytime_t us) +{ + systemticks_t ticks = (us/1000)*RAW_TICKS_PER_SECOND/1000; + if(!ticks)ticks = 1; + raw_sleep(ticks); +} + +bool_t gfxSemWait(gfxSem* psem, delaytime_t ms) +{ + systemticks_t ticks = ms*RAW_TICKS_PER_SECOND/1000; + if(!ticks)ticks=1; + if(raw_semaphore_get((psem), ticks)==RAW_SUCCESS) + return TRUE; + return FALSE; +} + +bool_t gfxSemWaitI(gfxSem* psem) +{ + if(raw_semaphore_get((psem), TIME_IMMEDIATE)==RAW_SUCCESS) + return TRUE; + return FALSE; +} + +gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) +{ + RAW_U16 ret; + gfxThreadHandle taskobj; + + taskobj = gfxAlloc(sizeof(RAW_TASK_OBJ)); + ret = raw_task_create(taskobj, (RAW_U8 *)"uGFX_TASK", param, + prio, 0, stackarea, + stacksz/sizeof(PORT_STACK) , fn, 1); + + if (ret != RAW_SUCCESS) { + for (;;); + } + + return (taskobj); +} + + +#endif + + + diff --git a/src/gos/rawrtos.h b/src/gos/rawrtos.h new file mode 100644 index 00000000..eeb5119d --- /dev/null +++ b/src/gos/rawrtos.h @@ -0,0 +1,77 @@ +#ifndef _GOS_RAWRTOS_H +#define _GOS_RAWRTOS_H + +#if GFX_USE_OS_RAWRTOS + +#include "raw_api.h" +#include + +#define TIME_IMMEDIATE (RAW_NO_WAIT) +#define TIME_INFINITE (RAW_WAIT_FOREVER) +typedef int8_t bool_t; +typedef uint32_t delaytime_t; +typedef RAW_TICK_TYPE systemticks_t; +typedef int32_t semcount_t; +typedef uint32_t threadreturn_t; +typedef RAW_U8 threadpriority_t; +typedef uint32_t size_t; + +#define MAX_SEMAPHORE_COUNT RAW_SEMAPHORE_COUNT +#define LOW_PRIORITY (CONFIG_RAW_PRIO_MAX-2) +#define NORMAL_PRIORITY (CONFIG_RAW_PRIO_MAX/2) +#define HIGH_PRIORITY 1 + +typedef RAW_SEMAPHORE gfxSem; +typedef RAW_MUTEX gfxMutex; +typedef RAW_TASK_OBJ* gfxThreadHandle; + +#define DECLARE_THREAD_FUNCTION(fnName, param) threadreturn_t fnName(void *param) +#define DECLARE_THREAD_STACK(name, sz) PORT_STACK name[sz]; + +#define gfxHalt(msg) for(;;) +#define gfxExit() for(;;) +#define gfxAlloc(sz) raw_malloc(sz) +#define gfxRealloc(p,osz,nsz) raw_calloc(p, nsz) +#define gfxFree(ptr) raw_free(ptr) +#define gfxYield() raw_sleep(0) +#define gfxSystemTicks() raw_system_time_get() +#define gfxMillisecondsToTicks(ms) (ms*RAW_TICKS_PER_SECOND/1000) +#define gfxSystemLock() {} +#define gfxSystemUnlock() {} +#define gfxMutexInit(pmutex) raw_mutex_create(pmutex, (RAW_U8 *)"", RAW_MUTEX_INHERIT_POLICY, 3) +#define gfxMutexDestroy(pmutex) raw_mutex_delete(pmutex) +#define gfxMutexEnter(pmutex) raw_mutex_get(pmutex, TIME_INFINITE) +#define gfxMutexExit(pmutex) raw_mutex_put(pmutex) +#define gfxSemInit(psem, val, limit) raw_semaphore_create(psem, "", val) +#define gfxSemDestroy(psem) raw_semaphore_delete(psem) +#define gfxSemSignal(psem) raw_semaphore_put((psem)) +#define gfxSemSignalI(psem) raw_semaphore_put_all((psem)) +#define gfxSemCounterI(psem) ((psem)->count) +#define gfxThreadMe() {(unsigned int)raw_task_identify()} +#define gfxThreadClose(thread) {} + +extern RAW_VOID *raw_malloc(RAW_U32 size); +extern RAW_VOID raw_free(void *ptr); +extern RAW_VOID *raw_calloc(RAW_U32 nmemb, RAW_U32 size); + +extern RAW_U16 raw_sleep(RAW_TICK_TYPE dly); +extern RAW_TICK_TYPE raw_system_time_get(void); + +extern RAW_U16 raw_mutex_create(RAW_MUTEX *mutex_ptr, RAW_U8 *name_ptr, RAW_U8 policy, RAW_U8 ceiling_prio); +extern RAW_U16 raw_mutex_delete(RAW_MUTEX *mutex_ptr); +extern RAW_U16 raw_mutex_get(RAW_MUTEX *mutex_ptr, RAW_TICK_TYPE wait_option); +extern RAW_U16 raw_mutex_put(RAW_MUTEX *mutex_ptr); +extern RAW_U16 raw_semaphore_create(RAW_SEMAPHORE *semaphore_ptr, RAW_U8 *name_ptr, RAW_U32 initial_count); +extern RAW_U16 raw_semaphore_delete(RAW_SEMAPHORE *semaphore_ptr); +extern RAW_U16 raw_semaphore_get(RAW_SEMAPHORE *semaphore_ptr, RAW_TICK_TYPE wait_option); +extern RAW_U16 raw_semaphore_put(RAW_SEMAPHORE *semaphore_ptr); + +void gfxSleepMilliseconds(delaytime_t ms); +void gfxSleepMicroseconds(delaytime_t us); +bool_t gfxSemWait(gfxSem* psem, delaytime_t ms); +bool_t gfxSemWaitI(gfxSem* psem); +gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param); + +#endif + +#endif diff --git a/src/gos/sys_defs.h b/src/gos/sys_defs.h index 9da9dff0..dcd445e4 100644 --- a/src/gos/sys_defs.h +++ b/src/gos/sys_defs.h @@ -439,6 +439,8 @@ * All the above was just for the doxygen documentation. All the implementation of the above * (without any of the documentation overheads) is in the files below. */ +#elif GFX_USE_OS_RAWRTOS + #include "src/gos/rawrtos.h" #elif GFX_USE_OS_CHIBIOS #include "src/gos/chibios.h" #elif GFX_USE_OS_FREERTOS diff --git a/src/gos/sys_rules.h b/src/gos/sys_rules.h index 0da01ff2..6d6c7845 100644 --- a/src/gos/sys_rules.h +++ b/src/gos/sys_rules.h @@ -16,7 +16,7 @@ #ifndef _GOS_RULES_H #define _GOS_RULES_H -#if !GFX_USE_OS_CHIBIOS && !GFX_USE_OS_WIN32 && !GFX_USE_OS_LINUX && !GFX_USE_OS_OSX && !GFX_USE_OS_RAW32 && !GFX_USE_OS_FREERTOS && !GFX_USE_OS_ECOS +#if !GFX_USE_OS_CHIBIOS && !GFX_USE_OS_WIN32 && !GFX_USE_OS_LINUX && !GFX_USE_OS_OSX && !GFX_USE_OS_RAW32 && !GFX_USE_OS_FREERTOS && !GFX_USE_OS_ECOS && !GFX_USE_OS_RAWRTOS #if GFX_DISPLAY_RULE_WARNINGS #warning "GOS: No Operating System has been defined. ChibiOS (GFX_USE_OS_CHIBIOS) has been turned on for you." #endif @@ -24,7 +24,7 @@ #define GFX_USE_OS_CHIBIOS TRUE #endif -#if GFX_USE_OS_CHIBIOS + GFX_USE_OS_WIN32 + GFX_USE_OS_LINUX + GFX_USE_OS_OSX + GFX_USE_OS_RAW32 + GFX_USE_OS_FREERTOS + GFX_USE_OS_ECOS != 1 * TRUE +#if GFX_USE_OS_CHIBIOS + GFX_USE_OS_WIN32 + GFX_USE_OS_LINUX + GFX_USE_OS_OSX + GFX_USE_OS_RAW32 + GFX_USE_OS_FREERTOS + GFX_USE_OS_ECOS + GFX_USE_OS_RAWRTOS != 1 * TRUE #error "GOS: More than one operation system has been defined as TRUE." #endif From 4ce658b022bbafe129d5ed3a571017c7d34b3892 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 29 Jul 2014 11:13:46 +1000 Subject: [PATCH 12/28] Oops - add rawrtos into the makefile --- src/gos/sys_make.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gos/sys_make.mk b/src/gos/sys_make.mk index 9e24f875..5ad2370b 100644 --- a/src/gos/sys_make.mk +++ b/src/gos/sys_make.mk @@ -4,5 +4,6 @@ GFXSRC += $(GFXLIB)/src/gos/chibios.c \ $(GFXLIB)/src/gos/linux.c \ $(GFXLIB)/src/gos/osx.c \ $(GFXLIB)/src/gos/raw32.c \ - $(GFXLIB)/src/gos/ecos.c + $(GFXLIB)/src/gos/ecos.c \ + $(GFXLIB)/src/gos/rawrtos.c From 9826378b9608362c4ad6efa3271e6f6de1e2b30e Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 29 Jul 2014 12:00:47 +1000 Subject: [PATCH 13/28] Operating System initialisation can now be turned off in gfxconf.h --- docs/releases.txt | 1 + gfxconf.example.h | 3 +++ src/gos/chibios.c | 27 +++++++++++++++------------ src/gos/ecos.c | 7 +++++-- src/gos/freertos.c | 8 ++++++-- src/gos/linux.c | 1 + src/gos/osx.c | 1 + src/gos/raw32.c | 6 ++++++ src/gos/rawrtos.c | 6 +++++- src/gos/sys_options.h | 14 ++++++++++++++ src/gos/win32.c | 2 +- 11 files changed, 58 insertions(+), 18 deletions(-) diff --git a/docs/releases.txt b/docs/releases.txt index 46a58ab4..d658deee 100644 --- a/docs/releases.txt +++ b/docs/releases.txt @@ -19,6 +19,7 @@ FEATURE: Added R61505U gdisp driver FIX: Fix threading issues in GEvent for callbacks FEATURE: Added geventEventComplete() FEATURE: Added support for the rawrtos real time operating system +FEATURE: Operating System initialisation is now optional *** Release 2.1 *** FIX: Significant improvements to the way the MCU touch driver works. diff --git a/gfxconf.example.h b/gfxconf.example.h index 8754ba32..8163b6f5 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -38,6 +38,9 @@ // #define INTERRUPTS_OFF() optional_code // #define INTERRUPTS_ON() optional_code +// Options that (should where relevant) apply to all operating systems +// #define GFX_NO_OS_INIT FALSE + /////////////////////////////////////////////////////////////////////////// // GDISP // diff --git a/src/gos/chibios.c b/src/gos/chibios.c index 468c012c..9d1a86da 100644 --- a/src/gos/chibios.c +++ b/src/gos/chibios.c @@ -33,18 +33,21 @@ void _gosInit(void) { - /* Don't initialise if the user already has */ - - #if CH_KERNEL_MAJOR == 2 - if (!chThdSelf()) { - halInit(); - chSysInit(); - } - #elif CH_KERNEL_MAJOR == 3 - if (!chThdGetSelfX()) { - halInit(); - chSysInit(); - } + #if !GFX_NO_OS_INIT + /* Don't Initialize if the user already has */ + #if CH_KERNEL_MAJOR == 2 + if (!chThdSelf()) { + halInit(); + chSysInit(); + } + #elif CH_KERNEL_MAJOR == 3 + if (!chThdGetSelfX()) { + halInit(); + chSysInit(); + } + #endif + #else + #warning "GOS: Operating System initialization has been turned off. Make sure you call halInit() and chSysInit() before gfxInit() in your application!" #endif } diff --git a/src/gos/ecos.c b/src/gos/ecos.c index 5b94497a..16ce821b 100644 --- a/src/gos/ecos.c +++ b/src/gos/ecos.c @@ -11,8 +11,11 @@ void _gosInit(void) { - /* Don't initialise if the user already has */ - //cyg_scheduler_start(); + #if !GFX_NO_OS_INIT + #error "GOS: Operating System initialization for eCos is not yet implemented in uGFX. Please set GFX_NO_OS_INIT to TRUE in your gfxconf.h" + #else + #warning "GOS: Operating System initialization has been turned off. Make sure you call cyg_scheduler_start() before gfxInit() in your application!" + #endif } void _gosDeinit(void) diff --git a/src/gos/freertos.c b/src/gos/freertos.c index f2c03eec..dbdfd22e 100644 --- a/src/gos/freertos.c +++ b/src/gos/freertos.c @@ -18,13 +18,17 @@ #error "GOS: configUSE_MUTEXES must be defined in FreeRTOSConfig.h" #endif -#if configUSE_COUNTING_SEMAPHORES != 1 +#if configUSE_COUNTING_SEMAPHORES != 1 #error "GOS: configUSE_COUNTING_SEMAPHORES must be defined in FreeRTOSConfig.h" #endif void _gosInit(void) { - // The user must call vTaskStartScheduler() himself before he calls gfxInit(). + #if !GFX_NO_OS_INIT + #error "GOS: Operating System initialization for FreeRTOS is not yet implemented in uGFX. Please set GFX_NO_OS_INIT to TRUE in your gfxconf.h" + #else + #warning "GOS: Operating System initialization has been turned off. Make sure you call vTaskStartScheduler() before gfxInit() in your application!" + #endif } void _gosDeinit(void) diff --git a/src/gos/linux.c b/src/gos/linux.c index d127fbe1..59b7f9c8 100644 --- a/src/gos/linux.c +++ b/src/gos/linux.c @@ -18,6 +18,7 @@ static gfxMutex SystemMutex; void _gosInit(void) { + /* No initialization of the operating system itself is needed */ gfxMutexInit(&SystemMutex); } diff --git a/src/gos/osx.c b/src/gos/osx.c index dccd49c9..50b06530 100644 --- a/src/gos/osx.c +++ b/src/gos/osx.c @@ -35,6 +35,7 @@ void get_ticks(mach_timespec_t *mts){ void _gosInit(void) { + /* No initialization of the operating system itself is needed */ gfxMutexInit(&SystemMutex); } diff --git a/src/gos/raw32.c b/src/gos/raw32.c index c75342d4..22c753aa 100644 --- a/src/gos/raw32.c +++ b/src/gos/raw32.c @@ -24,6 +24,12 @@ static void _gosThreadsInit(void); void _gosInit(void) { + /* No initialization of the operating system itself is needed as there isn't one. + * On the other hand the C runtime should still already be initialized before + * getting here! + */ + #warning "GOS: Raw32 - Make sure you initialize your hardware and the C runtime before calling gfxInit() in your application!" + // Set up the heap allocator _gosHeapInit(); diff --git a/src/gos/rawrtos.c b/src/gos/rawrtos.c index 688828c9..cd684208 100644 --- a/src/gos/rawrtos.c +++ b/src/gos/rawrtos.c @@ -17,7 +17,11 @@ void _gosInit(void) { - // The user must call raw_os_start() himself before he calls gfxInit(). + #if !GFX_NO_OS_INIT + #error "GOS: Operating System initialization for RawRTOS is not yet implemented in uGFX. Please set GFX_NO_OS_INIT to TRUE in your gfxconf.h" + #else + #warning "GOS: Operating System initialization has been turned off. Make sure you call raw_os_start() before gfxInit() in your application!" + #endif } void _gosDeinit(void) diff --git a/src/gos/sys_options.h b/src/gos/sys_options.h index 7937e082..ead1f3f7 100644 --- a/src/gos/sys_options.h +++ b/src/gos/sys_options.h @@ -75,6 +75,20 @@ * @name GOS Optional Parameters * @{ */ + /** + * @brief Should uGFX avoid initializing the operating system + * @details Defaults to FALSE + * @note This is not relevant to all operating systems eg Win32 never initializes the + * operating system as uGFX runs as an application outside the boot process. + * @note Operating system initialization is not necessarily implemented for all + * operating systems yet even when it is relevant. These operating systems + * will display a compile warning reminding you to initialize the operating + * system in your application code. Note that on these operating systems the + * demo applications will not work without modification. + */ + #ifndef GFX_NO_OS_INIT + #define GFX_NO_OS_INIT FALSE + #endif /** * @brief Should uGFX stuff be added to the FreeRTOS+Tracer * @details Defaults to FALSE diff --git a/src/gos/win32.c b/src/gos/win32.c index 3a3f2517..ffa7fac5 100644 --- a/src/gos/win32.c +++ b/src/gos/win32.c @@ -19,7 +19,7 @@ static HANDLE SystemMutex; void _gosInit(void) { - + /* No initialization of the operating system itself is needed */ } void _gosDeinit(void) From 89d0d4ecaed5a8ca53214f111c9b70ed070d87f8 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Tue, 5 Aug 2014 10:00:54 +0200 Subject: [PATCH 14/28] whitespaces --- docs/releases.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/releases.txt b/docs/releases.txt index d658deee..aaf820e9 100644 --- a/docs/releases.txt +++ b/docs/releases.txt @@ -21,6 +21,7 @@ FEATURE: Added geventEventComplete() FEATURE: Added support for the rawrtos real time operating system FEATURE: Operating System initialisation is now optional + *** Release 2.1 *** FIX: Significant improvements to the way the MCU touch driver works. FEATURE: Add support for edge to edge touch calibration. From 110191f68ded132b9c527734eb74f80e301c7089 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Tue, 5 Aug 2014 10:02:03 +0200 Subject: [PATCH 15/28] updated license to v1.2 --- license.html | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/license.html b/license.html index f6d39eb7..091dc9bd 100644 --- a/license.html +++ b/license.html @@ -2,7 +2,7 @@ - GFX License, version 1.1 + GFX License, version 1.2 @@ -100,7 +100,7 @@
1.12. Commercial Use

means any use of the Works that may result in income or equivalent benefit in any form. Examples of Commercial Use include; selling an Application or Device containing the Works, offering paid support to modify the Works, selling a library containing the Works. Examples of use that are NOT Commercial Use include; using the Works for Education, use of the Works in hobbyist projects that have no expectation of income, use of the Works in building what will later become a Commercial Use product. - Note that Commercial Use does not the prototyping and preparation for income generating activities - only the income producing activity itself.

+ Note that Commercial Use does not include the prototyping and preparation for income generating activities - only the income producing activity itself.

2. Non Commercial Use

@@ -116,7 +116,7 @@

2.2. Distribution of Executable form

If You distribute the Works in an Executable form then:

    -
  1. and You must inform recipients of the Executable form that it contains the Works and how they can obtain a copy of the Works in Source Code Form from the License Owners master repository; and

  2. +
  3. You must inform recipients of the Executable form that it contains the Works and how they can obtain a copy of the Works in Source Code Form from the License Owners master repository; and

  4. Any modification to the Works must be contributed to the License Owners as per Section 4 prior to distribution; and

  5. You may distribute such Executable form under the terms of this License, or license it under different terms, provided that the license for the Executable form does not allow for Commercial Use of the Works or attempt to limit or alter the recipients' rights in the Source Code Form under this License.

@@ -125,7 +125,7 @@

3.1. Commercial Use Agreement

A "Commercial Use Agreement" explicitly signed by the License Owner will override any specified terms of this License for the party to the agreement under the terms of the agreement. All other terms of this License will still apply.

3.2. Distribution

-

Other than as provided for in a signed "Commercial Use Agreement", where there is a Commercial Use involved or implied; you are not permitted to distribute the Works, in any form, either in source code or Executable form, +

Other than as provided for in a signed "Commercial Use Agreement", where there is a Commercial Use involved or implied, you are not permitted to distribute the Works in any form, either in source code or Executable form, either as software or on a device or in any other way.

4. Contributions

@@ -177,7 +177,8 @@

You may distribute the Works under the terms of the version of the License under which You originally received the Works, or under the terms of any subsequent version published by the license steward.

12.3. Modified Versions

If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the License Owner (except to note that such modified license differs from this License).

- +

13. Source Code License Notice

+

Where ever possible the source code for the Works is to contain a header as per Exhibit A. Where this would be syntactically incorrect then modifications to allow syntactic parsing by a compiler are allowed but only to the extent that they allow correct syntactic parsing. If it is not possible to put the notice in a particular file, then You may include the notice in a location where a recipient would be likely to look for such a notice such as a “license.txt” file in a relevant directory.

Exhibit A - Source Code Form License Notice

/*
  * This file is subject to the terms of the GFX License. If a copy of
@@ -186,7 +187,5 @@
  *              http://ugfx.com/license.html
  */
 
-

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

- From 265e6f75c11eca4c5ba12afda74024e6b2809059 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Tue, 5 Aug 2014 10:07:57 +0200 Subject: [PATCH 16/28] license typo fix --- license.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/license.html b/license.html index 091dc9bd..953e4bbf 100644 --- a/license.html +++ b/license.html @@ -67,7 +67,7 @@ -

GFX License
Version 1.1

+

GFX License
Version 1.2

1. Definitions

1.1. Works
From b2b09319e47fe37dc293a0c80bb7ac3a563f13e2 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Wed, 6 Aug 2014 18:21:44 +0200 Subject: [PATCH 17/28] doc --- docs/releases.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/releases.txt b/docs/releases.txt index aaf820e9..5840efab 100644 --- a/docs/releases.txt +++ b/docs/releases.txt @@ -18,7 +18,7 @@ FEATURE: Added Raspberry Pi board support FEATURE: Added R61505U gdisp driver FIX: Fix threading issues in GEvent for callbacks FEATURE: Added geventEventComplete() -FEATURE: Added support for the rawrtos real time operating system +FEATURE: Added support for the RawOS real time operating system FEATURE: Operating System initialisation is now optional From d15c63abdbded078f0fa5b6bbfa782c1dfe9e22b Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 7 Aug 2014 11:22:14 +1000 Subject: [PATCH 18/28] Any visible window that obscures another window now prevents the underlying window from receiving mouse event. --- src/gwin/gwidget.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/gwin/gwidget.c b/src/gwin/gwidget.c index a2e6f472..c9fff50e 100644 --- a/src/gwin/gwidget.c +++ b/src/gwin/gwidget.c @@ -86,6 +86,7 @@ static void gwidgetEvent(void *param, GEvent *pe) { #define pte ((GEventToggle *)pe) #define pde ((GEventDial *)pe) + GHandle h; GHandle gh; #if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL) uint16_t role; @@ -99,32 +100,38 @@ static void gwidgetEvent(void *param, GEvent *pe) { case GEVENT_MOUSE: case GEVENT_TOUCH: // Cycle through all windows - for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { + for(gh = 0, h = gwinGetNextWindow(0); h; h = gwinGetNextWindow(h)) { - // check if the widget matches this display - if (gh->display != pme->display) + // The window must be on this display and visible to be relevant + if (h->display != pme->display || !(h->flags & GWIN_FLG_SYSVISIBLE)) continue; - // check if it is a widget that is enabled and visible - if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) - continue; - - // Are we captured? - if ((gw->g.flags & GWIN_FLG_MOUSECAPTURE)) { + // Is the mouse currently captured by this widget? + if ((h->flags & (GWIN_FLG_WIDGET|GWIN_FLG_MOUSECAPTURE)) == (GWIN_FLG_WIDGET|GWIN_FLG_MOUSECAPTURE)) { + gh = h; if ((pme->last_buttons & ~pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) { - gw->g.flags &= ~GWIN_FLG_MOUSECAPTURE; + gh->flags &= ~GWIN_FLG_MOUSECAPTURE; if (wvmt->MouseUp) - wvmt->MouseUp(gw, pme->x - gw->g.x, pme->y - gw->g.y); + wvmt->MouseUp(gw, pme->x - gh->x, pme->y - gh->y); } else if (wvmt->MouseMove) - wvmt->MouseMove(gw, pme->x - gw->g.x, pme->y - gw->g.y); + wvmt->MouseMove(gw, pme->x - gh->x, pme->y - gh->y); - // We are not captured - look for mouse downs over the widget - } else if ((~pme->last_buttons & pme->current_buttons & GINPUT_MOUSE_BTN_LEFT) - && pme->x >= gw->g.x && pme->x < gw->g.x + gw->g.width - && pme->y >= gw->g.y && pme->y < gw->g.y + gw->g.height) { - gw->g.flags |= GWIN_FLG_MOUSECAPTURE; + // There is only ever one captured mouse. Prevent normal mouse processing if there is a captured mouse + gh = 0; + break; + } + + // Save the highest z-order window that the mouse is over + if (pme->x >= h->x && pme->x < h->x + h->width && pme->y >= h->y && pme->y < h->y + h->height) + gh = h; + } + + // Process any mouse down over the highest order window if it is an enabled widget + if (gh && (gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) == (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) { + if ((~pme->last_buttons & pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) { + gh->flags |= GWIN_FLG_MOUSECAPTURE; if (wvmt->MouseDown) - wvmt->MouseDown(gw, pme->x - gw->g.x, pme->y - gw->g.y); + wvmt->MouseDown(gw, pme->x - gh->x, pme->y - gh->y); } } break; From f94b496c0c1ace25491893702c856219825d9355 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Thu, 7 Aug 2014 22:57:18 +0200 Subject: [PATCH 19/28] Added optional transparency to container --- src/gwin/gcontainer.c | 14 +++++++++----- src/gwin/gcontainer.h | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/gwin/gcontainer.c b/src/gwin/gcontainer.c index 46e89032..0cca4092 100644 --- a/src/gwin/gcontainer.c +++ b/src/gwin/gcontainer.c @@ -93,11 +93,15 @@ coord_t gwinGetInnerHeight(GHandle gh) { static coord_t BorderSize(GHandle gh) { return (gh->flags & GWIN_CONTAINER_BORDER) ? 2 : 0; } static void DrawSimpleContainer(GWidgetObject *gw, void *param) { - (void) param; - gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); - if ((gw->g.flags & GWIN_CONTAINER_BORDER)) - gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge); -} + (void)param; + + if ((gw->g.flags & GWIN_CONTAINER_TRANSPARENT) == 0) { + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); + } + + if ((gw->g.flags & GWIN_CONTAINER_BORDER)) + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge); +} // The container VMT table static const gcontainerVMT containerVMT = { diff --git a/src/gwin/gcontainer.h b/src/gwin/gcontainer.h index efba83f9..942cf8c0 100644 --- a/src/gwin/gcontainer.h +++ b/src/gwin/gcontainer.h @@ -105,6 +105,7 @@ extern "C" { * @{ */ #define GWIN_CONTAINER_BORDER 0x00000001 + #define GWIN_CONTAINER_TRANSPARENT 0x00000002 /** @} */ /** From 52f40d76184be08df198f9e53340590c938297b7 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Thu, 7 Aug 2014 23:11:44 +0200 Subject: [PATCH 20/28] Fixing compile bug for NATIVE image format --- src/gdisp/image_native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gdisp/image_native.c b/src/gdisp/image_native.c index c458531e..81344642 100644 --- a/src/gdisp/image_native.c +++ b/src/gdisp/image_native.c @@ -90,7 +90,7 @@ gdispImageError gdispImageCache_NATIVE(gdispImage *img) { return GDISP_IMAGE_ERR_OK; } -gdispImageError gdispImageGDraw_NATIVE(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { +gdispImageError gdispGImageDraw_NATIVE(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { coord_t mx, mcx; size_t pos, len; From d85375c4b4aa793192f68c656fa46a19cdab6c98 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 8 Aug 2014 09:47:19 +0200 Subject: [PATCH 21/28] doc --- docs/releases.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/releases.txt b/docs/releases.txt index 5840efab..0b30dd0b 100644 --- a/docs/releases.txt +++ b/docs/releases.txt @@ -20,6 +20,7 @@ FIX: Fix threading issues in GEvent for callbacks FEATURE: Added geventEventComplete() FEATURE: Added support for the RawOS real time operating system FEATURE: Operating System initialisation is now optional +FEATURE: Added optional transparency to container *** Release 2.1 *** From 56f55af6eacd8a9be42559669c9b39cabe37a83a Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 8 Aug 2014 09:47:41 +0200 Subject: [PATCH 22/28] FreeRTOS type definitions for versions older than 8 --- src/gos/freertos.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/gos/freertos.h b/src/gos/freertos.h index ccda4cbd..34ef548e 100644 --- a/src/gos/freertos.h +++ b/src/gos/freertos.h @@ -24,6 +24,18 @@ /* Type definitions */ /*===========================================================================*/ +/* Additional types are required when FreeRTOS 7.x is used */ +#if !defined(tskKERNEL_VERSION_MAJOR) && !tskKERNEL_VERSION_MAJOR == 8 + typedef signed char int8_t + typedef unsigned char uint8_t + typedef signed int int16_t + typedef unsigned int uint16_t + typedef signed long int int32_t + typedef unsigned long int uint32_t + typedef signed long long int int64_t + typedef unsigned long long int uint64_t +#endif + /** * bool_t, * int8_t, uint8_t, From e65b1db192c264093663bbae093754e619ac333f Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 8 Aug 2014 10:46:42 +0200 Subject: [PATCH 23/28] Adding prefix to port files to avoid file name conflicts on case insensitive systems --- src/gos/{chibios.c => gfx_chibios.c} | 0 src/gos/{chibios.h => gfx_chibios.h} | 0 src/gos/{ecos.c => gfx_ecos.c} | 0 src/gos/{ecos.h => gfx_ecos.h} | 0 src/gos/{freertos.c => gfx_freertos.c} | 0 src/gos/{freertos.h => gfx_freertos.h} | 0 src/gos/{linux.c => gfx_linux.c} | 0 src/gos/{linux.h => gfx_linux.h} | 0 src/gos/{osx.c => gfx_osx.c} | 0 src/gos/{osx.h => gfx_osx.h} | 0 src/gos/{raw32.c => gfx_raw32.c} | 0 src/gos/{raw32.h => gfx_raw32.h} | 0 src/gos/{rawrtos.c => gfx_rawrtos.c} | 0 src/gos/{rawrtos.h => gfx_rawrtos.h} | 0 src/gos/{win32.c => gfx_win32.c} | 0 src/gos/{win32.h => gfx_win32.h} | 0 src/gos/sys_defs.h | 16 ++++++++-------- src/gos/sys_make.mk | 16 ++++++++-------- 18 files changed, 16 insertions(+), 16 deletions(-) rename src/gos/{chibios.c => gfx_chibios.c} (100%) rename src/gos/{chibios.h => gfx_chibios.h} (100%) rename src/gos/{ecos.c => gfx_ecos.c} (100%) rename src/gos/{ecos.h => gfx_ecos.h} (100%) rename src/gos/{freertos.c => gfx_freertos.c} (100%) rename src/gos/{freertos.h => gfx_freertos.h} (100%) rename src/gos/{linux.c => gfx_linux.c} (100%) rename src/gos/{linux.h => gfx_linux.h} (100%) rename src/gos/{osx.c => gfx_osx.c} (100%) rename src/gos/{osx.h => gfx_osx.h} (100%) rename src/gos/{raw32.c => gfx_raw32.c} (100%) rename src/gos/{raw32.h => gfx_raw32.h} (100%) rename src/gos/{rawrtos.c => gfx_rawrtos.c} (100%) rename src/gos/{rawrtos.h => gfx_rawrtos.h} (100%) rename src/gos/{win32.c => gfx_win32.c} (100%) rename src/gos/{win32.h => gfx_win32.h} (100%) diff --git a/src/gos/chibios.c b/src/gos/gfx_chibios.c similarity index 100% rename from src/gos/chibios.c rename to src/gos/gfx_chibios.c diff --git a/src/gos/chibios.h b/src/gos/gfx_chibios.h similarity index 100% rename from src/gos/chibios.h rename to src/gos/gfx_chibios.h diff --git a/src/gos/ecos.c b/src/gos/gfx_ecos.c similarity index 100% rename from src/gos/ecos.c rename to src/gos/gfx_ecos.c diff --git a/src/gos/ecos.h b/src/gos/gfx_ecos.h similarity index 100% rename from src/gos/ecos.h rename to src/gos/gfx_ecos.h diff --git a/src/gos/freertos.c b/src/gos/gfx_freertos.c similarity index 100% rename from src/gos/freertos.c rename to src/gos/gfx_freertos.c diff --git a/src/gos/freertos.h b/src/gos/gfx_freertos.h similarity index 100% rename from src/gos/freertos.h rename to src/gos/gfx_freertos.h diff --git a/src/gos/linux.c b/src/gos/gfx_linux.c similarity index 100% rename from src/gos/linux.c rename to src/gos/gfx_linux.c diff --git a/src/gos/linux.h b/src/gos/gfx_linux.h similarity index 100% rename from src/gos/linux.h rename to src/gos/gfx_linux.h diff --git a/src/gos/osx.c b/src/gos/gfx_osx.c similarity index 100% rename from src/gos/osx.c rename to src/gos/gfx_osx.c diff --git a/src/gos/osx.h b/src/gos/gfx_osx.h similarity index 100% rename from src/gos/osx.h rename to src/gos/gfx_osx.h diff --git a/src/gos/raw32.c b/src/gos/gfx_raw32.c similarity index 100% rename from src/gos/raw32.c rename to src/gos/gfx_raw32.c diff --git a/src/gos/raw32.h b/src/gos/gfx_raw32.h similarity index 100% rename from src/gos/raw32.h rename to src/gos/gfx_raw32.h diff --git a/src/gos/rawrtos.c b/src/gos/gfx_rawrtos.c similarity index 100% rename from src/gos/rawrtos.c rename to src/gos/gfx_rawrtos.c diff --git a/src/gos/rawrtos.h b/src/gos/gfx_rawrtos.h similarity index 100% rename from src/gos/rawrtos.h rename to src/gos/gfx_rawrtos.h diff --git a/src/gos/win32.c b/src/gos/gfx_win32.c similarity index 100% rename from src/gos/win32.c rename to src/gos/gfx_win32.c diff --git a/src/gos/win32.h b/src/gos/gfx_win32.h similarity index 100% rename from src/gos/win32.h rename to src/gos/gfx_win32.h diff --git a/src/gos/sys_defs.h b/src/gos/sys_defs.h index dcd445e4..d116826f 100644 --- a/src/gos/sys_defs.h +++ b/src/gos/sys_defs.h @@ -440,21 +440,21 @@ * (without any of the documentation overheads) is in the files below. */ #elif GFX_USE_OS_RAWRTOS - #include "src/gos/rawrtos.h" + #include "src/gos/gfx_rawrtos.h" #elif GFX_USE_OS_CHIBIOS - #include "src/gos/chibios.h" + #include "src/gos/gfx_chibios.h" #elif GFX_USE_OS_FREERTOS - #include "src/gos/freertos.h" + #include "src/gos/gfx_freertos.h" #elif GFX_USE_OS_WIN32 - #include "src/gos/win32.h" + #include "src/gos/gfx_win32.h" #elif GFX_USE_OS_LINUX - #include "src/gos/linux.h" + #include "src/gos/gfx_linux.h" #elif GFX_USE_OS_OSX - #include "src/gos/osx.h" + #include "src/gos/gfx_osx.h" #elif GFX_USE_OS_RAW32 - #include "src/gos/raw32.h" + #include "src/gos/gfx_raw32.h" #elif GFX_USE_OS_ECOS - #include "src/gos/ecos.h" + #include "src/gos/gfx_ecos.h" #else #error "Your operating system is not supported yet" #endif diff --git a/src/gos/sys_make.mk b/src/gos/sys_make.mk index 5ad2370b..5efa7f80 100644 --- a/src/gos/sys_make.mk +++ b/src/gos/sys_make.mk @@ -1,9 +1,9 @@ -GFXSRC += $(GFXLIB)/src/gos/chibios.c \ - $(GFXLIB)/src/gos/freertos.c \ - $(GFXLIB)/src/gos/win32.c \ - $(GFXLIB)/src/gos/linux.c \ - $(GFXLIB)/src/gos/osx.c \ - $(GFXLIB)/src/gos/raw32.c \ - $(GFXLIB)/src/gos/ecos.c \ - $(GFXLIB)/src/gos/rawrtos.c +GFXSRC += $(GFXLIB)/src/gos/gfx_chibios.c \ + $(GFXLIB)/src/gos/gfx_freertos.c \ + $(GFXLIB)/src/gos/gfx_win32.c \ + $(GFXLIB)/src/gos/gfx_linux.c \ + $(GFXLIB)/src/gos/gfx_osx.c \ + $(GFXLIB)/src/gos/gfx_raw32.c \ + $(GFXLIB)/src/gos/gfx_ecos.c \ + $(GFXLIB)/src/gos/gfx_rawrtos.c From 1012ab75a4fb49aee0a42f8d24f1e76844a6c319 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 8 Aug 2014 19:01:44 +1000 Subject: [PATCH 24/28] Adjust code styling to match all other code --- src/gwin/gcontainer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gwin/gcontainer.c b/src/gwin/gcontainer.c index 0cca4092..2d711ffd 100644 --- a/src/gwin/gcontainer.c +++ b/src/gwin/gcontainer.c @@ -95,9 +95,8 @@ static coord_t BorderSize(GHandle gh) { return (gh->flags & GWIN_CONTAINER_BORDE static void DrawSimpleContainer(GWidgetObject *gw, void *param) { (void)param; - if ((gw->g.flags & GWIN_CONTAINER_TRANSPARENT) == 0) { + if (!(gw->g.flags & GWIN_CONTAINER_TRANSPARENT)) gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); - } if ((gw->g.flags & GWIN_CONTAINER_BORDER)) gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge); From 14f372bef8db5d919a35d8b8db48583ca1aeb8ce Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 8 Aug 2014 19:02:07 +1000 Subject: [PATCH 25/28] doco --- docs/releases.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/releases.txt b/docs/releases.txt index 0b30dd0b..6814fd0b 100644 --- a/docs/releases.txt +++ b/docs/releases.txt @@ -21,6 +21,7 @@ FEATURE: Added geventEventComplete() FEATURE: Added support for the RawOS real time operating system FEATURE: Operating System initialisation is now optional FEATURE: Added optional transparency to container +FEATURE: Prevent mouse events going to obscured widgets *** Release 2.1 *** From 052a8e033c345e9b6a9449023aaeb3a2f0f72086 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 8 Aug 2014 14:04:49 +0200 Subject: [PATCH 26/28] Fixing color in gwin widgets demo --- demos/modules/gwin/widgets/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/modules/gwin/widgets/main.c b/demos/modules/gwin/widgets/main.c index 641625e6..783ed548 100644 --- a/demos/modules/gwin/widgets/main.c +++ b/demos/modules/gwin/widgets/main.c @@ -194,7 +194,7 @@ static void createWidgets(void) { wi.g.width = ScrWidth/2 - 2*border; ghConsole = gwinConsoleCreate(0, &wi.g); gwinSetColor(ghConsole, Black); - gwinSetBgColor(ghConsole, 0xF0F0F0); + gwinSetBgColor(ghConsole, HTML2COLOR(0xF0F0F0)); // Buttons wi.g.parent = ghPgButtons; From 6ff7d90500bf5939252eb39272558706da1b8f44 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 8 Aug 2014 14:18:07 +0200 Subject: [PATCH 27/28] Updating SSD1963 driver --- drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c | 147 +++++++++++++++++----- drivers/gdisp/SSD1963/gdisp_lld_config.h | 2 +- drivers/gdisp/SSD1963/ssd1963.h | 9 ++ 3 files changed, 124 insertions(+), 34 deletions(-) diff --git a/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c b/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c index 74fa3e3e..f465b47d 100644 --- a/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c +++ b/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c @@ -16,6 +16,7 @@ #define CALC_PERIOD(w,b,f,p) (p+b+w+f) #define CALC_FPR(w,h,hb,hf,hp,vb,vf,vp,fps) ((fps * CALC_PERIOD(w,hb,hf,hp) * CALC_PERIOD(h,vb,vf,vp) * 1048576)/100000000) + typedef struct LCD_Parameters { coord_t width, height; // Panel width and height uint16_t hbporch; // Horizontal Back Porch @@ -27,6 +28,26 @@ typedef struct LCD_Parameters { uint16_t vpulse; // Vertical Pulse uint16_t vperiod; // Vertical Period (Total) uint32_t fpr; // Calculated FPR + uint16_t flags; // For command "SSD1963_SET_GDISP_MODE" + /* Set the pannel data width */ + #define LCD_PANEL_DATA_WIDTH_24BIT (1<<5) // 18bit default + /* Set the color deeph enhancement */ + #define LCD_PANEL_ENABLE_FRC ((1<<3) | (1<<4)) + #define LCD_PANEL_ENABLE_DITHERING (1<<4) // no enhancement default + /* Set the dot clock pulse polarity */ + #define LCD_PANEL_LSHIFT_FALLING_EDGE (1<<2) // default rising edge + /* Set the horizontal sync pulse polarity */ + #define LCD_PANEL_LLINE_ACTIVE_HIGH (1<<1) // default active low + /* Set the vertical sync pulse polarity */ + #define LCD_PANEL_LFRAME_ACTIVE_HIGH (1<0) // default active low + /* Set the lcd panel mode */ + #define LCD_PANEL_MODE_TTL ((1<<7) << 8) // default mode is Hsync+Vsync +DE + /* Set the lcd panel interface type */ // default TFT mode + #define LCD_PANEL_TYPE_SERIAL_RGB_MODE ((1<<6) << 8) // Serial RGB mode + #define LCD_PANEL_TYPE_SERIAL_RGB_DUMMY_MODE (((1<<5) | (1<<6)) << 8) // Serial RGB+dummy mode + + + } LCD_Parameters; #include "board_SSD1963.h" @@ -48,17 +69,55 @@ typedef struct LCD_Parameters { #include "drivers/gdisp/SSD1963/ssd1963.h" +#define dummy_read(g) { volatile uint16_t dummy; dummy = read_data(g); (void) dummy; } #define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } #define write_data16(g, data) { write_data(g, (data)>>8); write_data(g, (data) & 0xFF); } static inline void set_viewport(GDisplay* g) { - write_index(g, SSD1963_SET_PAGE_ADDRESS); - write_data16(g, g->p.y); - write_data16(g, g->p.y+g->p.cy-1); - write_index(g, SSD1963_SET_COLUMN_ADDRESS); - write_data16(g, g->p.x); - write_data16(g, g->p.x+g->p.cx-1); - write_index(g, SSD1963_WRITE_MEMORY_START); + + switch(g->g.Orientation) { + default: + case GDISP_ROTATE_0: + write_index(g, SSD1963_SET_COLUMN_ADDRESS); + write_data16(g, g->p.x); + write_data16(g, g->p.x+g->p.cx-1); + write_index(g, SSD1963_SET_PAGE_ADDRESS); + write_data16(g, g->p.y); + write_data16(g, g->p.y+g->p.cy-1); + write_index(g, SSD1963_WRITE_MEMORY_START); + break; + case GDISP_ROTATE_90: + write_index(g, SSD1963_SET_COLUMN_ADDRESS); + write_data16(g, g->p.y); + write_data16(g, g->p.y+g->p.cy-1); + write_index(g, SSD1963_SET_PAGE_ADDRESS); + write_data16(g, GDISP_SCREEN_HEIGHT-1 - (g->p.x+g->p.cx-1) ); + write_data16(g, GDISP_SCREEN_HEIGHT-1 - (g->p.x)); + write_index(g, SSD1963_WRITE_MEMORY_START); + break; + case GDISP_ROTATE_180: + write_index(g, SSD1963_SET_COLUMN_ADDRESS); + write_data16(g, GDISP_SCREEN_WIDTH-1 - (g->p.x+g->p.cx-1)); + write_data16(g, GDISP_SCREEN_WIDTH-1 - (g->p.x)); + write_index(g, SSD1963_SET_PAGE_ADDRESS); + write_data16(g, GDISP_SCREEN_HEIGHT-1 - (g->p.y+g->p.cy-1)); + write_data16(g, GDISP_SCREEN_HEIGHT-1 - (g->p.y)); + write_index(g, SSD1963_WRITE_MEMORY_START); + break; + case GDISP_ROTATE_270: + write_index(g, SSD1963_SET_COLUMN_ADDRESS); + write_data16(g, GDISP_SCREEN_WIDTH-1 - (g->p.y+g->p.cy-1)); + write_data16(g, GDISP_SCREEN_WIDTH-1 - (g->p.y)); + write_index(g, SSD1963_SET_PAGE_ADDRESS); + write_data16(g, g->p.x); + write_data16(g, g->p.x+g->p.cx-1); + write_index(g, SSD1963_WRITE_MEMORY_START); + break; + } + + + + } /** @@ -71,12 +130,18 @@ static inline void set_backlight(GDisplay *g, uint8_t percent) { //Check your LCD's hardware, the PWM connection is default left open and instead //connected to a LED connection on the breakout board write_index(g, SSD1963_SET_PWM_CONF); //set PWM for BackLight - write_data(g, 0x01); - write_data(g, (55+percent*2) & 0x00FF); - write_data(g, 0x01); //controlled by host (not DBC), enabled - write_data(g, 0xFF); - write_data(g, 0x60); //don't let it go too dark, avoid a useless LCD - write_data(g, 0x0F); //prescaler ??? + write_data(g, 4); // PWMF[7:0] = 4, + // PWM signal frequency = PLL clock / (256 * (PWMF[7:0] + 1)) / 256 + // = aprox 366Hz for a PLL freq = 120MHz + if ( percent==0xFF ) // use percent==0xFF to turn off SSD1963 pwm in power SLEEP or DEEP SLEEP mode + write_data(g, 0x00); + else + write_data(g, (55+percent*2) & 0x00FF); + write_data(g, 0x01); // controlled by host (not DBC), enabled + write_data(g, 0x00); // DBC manual brightness; Set the brightness level: 00 Dimmest, FF Brightest + write_data(g, 0x00); // DBC minimum brightness; Set the minimum brightness level: 00 Dimmest, FF Brightest + write_data(g, 0x00); // Brightness prescaler of Transition Effect; Set the brightness prescaler: 0 Dimmest, F Brightest + } /*===========================================================================*/ @@ -121,10 +186,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { write_index(g, SSD1963_SOFT_RESET); gfxSleepMilliseconds(5); - /* Screen size */ + /* LCD panel parameters */ write_index(g, SSD1963_SET_GDISP_MODE); - write_data(g, 0x18); //Enabled dithering - write_data(g, 0x00); + write_data(g, lcdp->flags & 0xFF); + write_data(g, (lcdp->flags >> 8) & 0xFF); write_data16(g, lcdp->width-1); write_data16(g, lcdp->height-1); write_data(g, 0x00); // RGB @@ -155,9 +220,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { /* Tear effect indicator ON. This is used to tell the host MCU when the driver is not refreshing the panel (during front/back porch) */ write_reg(g, SSD1963_SET_TEAR_ON, 0x00); + /* Turn on */ write_index(g, SSD1963_SET_DISPLAY_ON); - + /* Turn on the back-light */ set_backlight(g, GDISP_INITIAL_BACKLIGHT); @@ -190,8 +256,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { } #endif -// Not implemented yet. -#if 0 && GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL LLDSPEC void gdisp_lld_control(GDisplay *g) { switch(g->p.x) { case GDISP_CONTROL_POWER: @@ -200,23 +265,34 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { switch((powermode_t)g->p.ptr) { case powerOff: acquire_bus(g); - write_index(g, SSD1963_EXIT_SLEEP_MODE); // leave sleep mode - gfxSleepMilliseconds(5); - write_index(g, SSD1963_SET_DISPLAY_OFF); - write_index(g, SSD1963_SET_DEEP_SLEEP); // enter deep sleep mode release_bus(g); break; case powerOn: acquire_bus(g); - read_reg(0x0000); gfxSleepMilliseconds(5); // 2x Dummy reads to wake up from deep sleep - read_reg(0x0000); gfxSleepMilliseconds(5); - write_index(g, SSD1963_SET_DISPLAY_ON); + dummy_read(g); + dummy_read(g); + /* Wait for 1msec to let the PLL stable if was stopped by deep sleep mode */ + gfxSleepMilliseconds(100); + write_index(g, SSD1963_EXIT_SLEEP_MODE); + gfxSleepMilliseconds(5); + /* Restore the back-light */ + set_backlight(g, gdispGGetBacklight(g)); release_bus(g); break; case powerSleep: acquire_bus(g); - write_index(g, SSD1963_SET_DISPLAY_OFF); - write_index(g, SSD1963_ENTER_SLEEP_MODE); // enter sleep mode + /* Turn off the back-light pwm from SSD1963 */ + set_backlight(g, 0xFF); + write_index(g, SSD1963_ENTER_SLEEP_MODE); + gfxSleepMilliseconds(5); + release_bus(g); + break; + case powerDeepSleep: + acquire_bus(g); + /* Turn off the back-light pwm from SSD1963 */ + set_backlight(g, 0xFF); + write_index(g, SSD1963_ENTER_SLEEP_MODE); + write_index(g, SSD1963_SET_DEEP_SLEEP); release_bus(g); break; default: @@ -228,30 +304,35 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { case GDISP_CONTROL_ORIENTATION: if (g->g.Orientation == (orientation_t)g->p.ptr) return; + switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: acquire_bus(g); - /* Code here */ + write_index(g, SSD1963_SET_ADDRESS_MODE); + write_data(g, 0x00); release_bus(g); g->g.Height = ((LCD_Parameters *)g->priv)->height; g->g.Width = ((LCD_Parameters *)g->priv)->width; break; case GDISP_ROTATE_90: acquire_bus(g); - /* Code here */ + write_index(g, SSD1963_SET_ADDRESS_MODE); + write_data(g, SSD1963_ADDR_MODE_PAGE_ADDR_ORDER | SSD1963_ADDR_MODE_PAG_COL_ADDR_ORDER ); release_bus(g); g->g.Height = ((LCD_Parameters *)g->priv)->width; g->g.Width = ((LCD_Parameters *)g->priv)->height; break; case GDISP_ROTATE_180: acquire_bus(g); - /* Code here */ + write_index(g, SSD1963_SET_ADDRESS_MODE); + write_data(g, SSD1963_ADDR_MODE_PAGE_ADDR_ORDER | SSD1963_ADDR_MODE_COL_ADDR_ORDER); release_bus(g); g->g.Height = ((LCD_Parameters *)g->priv)->height; g->g.Width = ((LCD_Parameters *)g->priv)->width; break; case GDISP_ROTATE_270: acquire_bus(g); - /* Code here */ + write_index(g, SSD1963_SET_ADDRESS_MODE); + write_data(g, SSD1963_ADDR_MODE_COL_ADDR_ORDER | SSD1963_ADDR_MODE_PAG_COL_ADDR_ORDER ); release_bus(g); g->g.Height = ((LCD_Parameters *)g->priv)->width; g->g.Width = ((LCD_Parameters *)g->priv)->height; @@ -259,7 +340,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { default: return; } - g->g.Orientation = (orientation_t)g->p.ptr; + g->g.Orientation = (orientation_t)g->p.ptr; return; case GDISP_CONTROL_BACKLIGHT: diff --git a/drivers/gdisp/SSD1963/gdisp_lld_config.h b/drivers/gdisp/SSD1963/gdisp_lld_config.h index f1b61702..7dfd0627 100644 --- a/drivers/gdisp/SSD1963/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1963/gdisp_lld_config.h @@ -15,7 +15,7 @@ /*===========================================================================*/ #define GDISP_HARDWARE_STREAM_WRITE TRUE -//#define GDISP_HARDWARE_CONTROL TRUE // Not Yet. +#define GDISP_HARDWARE_CONTROL TRUE #define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 diff --git a/drivers/gdisp/SSD1963/ssd1963.h b/drivers/gdisp/SSD1963/ssd1963.h index 2d1ac55f..eec2ae99 100644 --- a/drivers/gdisp/SSD1963/ssd1963.h +++ b/drivers/gdisp/SSD1963/ssd1963.h @@ -93,4 +93,13 @@ #define SSD1963_PDI_9BIT 6 #define SSD1963_GET_PIXEL_DATA_INTERFACE 0x00F1 +#define SSD1963_ADDR_MODE_FLIP_VERT (1 << 0) +#define SSD1963_ADDR_MODE_FLIP_HORZ (1 << 1) +#define SSD1963_ADDR_MODE_LATCH_RIGHT_TO_LEFT (1 << 2) +#define SSD1963_ADDR_MODE_BGR (1 << 3) +#define SSD1963_ADDR_MODE_REFRESH_BOTTOM_UP (1 << 4) +#define SSD1963_ADDR_MODE_PAG_COL_ADDR_ORDER (1 << 5) +#define SSD1963_ADDR_MODE_COL_ADDR_ORDER (1 << 6) +#define SSD1963_ADDR_MODE_PAGE_ADDR_ORDER (1 << 7) + #endif From 10902154aec652a3fcdf028b2c6ff16743464973 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 12 Aug 2014 16:43:45 +1000 Subject: [PATCH 28/28] GFILE: restructure files, add File Listing, add C String files Fix compile error for ChibiOS BaseStreamFile based GFILES'. --- docs/releases.txt | 2 + gfxconf.example.h | 7 +- src/gfile/gfile.c | 794 ++++++-------------------------------- src/gfile/inc_chibiosfs.c | 33 +- src/gfile/inc_fatfs.c | 81 +++- src/gfile/inc_memfs.c | 21 +- src/gfile/inc_nativefs.c | 116 +++++- src/gfile/inc_printg.c | 261 +++++++++++++ src/gfile/inc_romfs.c | 61 ++- src/gfile/inc_scang.c | 257 ++++++++++++ src/gfile/inc_stdio.c | 45 +++ src/gfile/inc_strings.c | 69 ++++ src/gfile/sys_defs.h | 136 ++++++- src/gfile/sys_options.h | 14 +- 14 files changed, 1183 insertions(+), 714 deletions(-) create mode 100644 src/gfile/inc_printg.c create mode 100644 src/gfile/inc_scang.c create mode 100644 src/gfile/inc_stdio.c create mode 100644 src/gfile/inc_strings.c diff --git a/docs/releases.txt b/docs/releases.txt index 6814fd0b..2908535e 100644 --- a/docs/releases.txt +++ b/docs/releases.txt @@ -22,6 +22,8 @@ FEATURE: Added support for the RawOS real time operating system FEATURE: Operating System initialisation is now optional FEATURE: Added optional transparency to container FEATURE: Prevent mouse events going to obscured widgets +FEATURE: Add GFILE support for file lists +FEATURE: Add GFILE support for C strings as files *** Release 2.1 *** diff --git a/gfxconf.example.h b/gfxconf.example.h index 8163b6f5..2abcf0b4 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -224,10 +224,8 @@ //#define GFILE_NEED_PRINTG FALSE //#define GFILE_NEED_SCANG FALSE //#define GFILE_NEED_STRINGS FALSE +//#define GFILE_NEED_FILELISTS FALSE //#define GFILE_NEED_STDIO FALSE -// #define GFILE_ALLOW_FLOATS FALSE -// #define GFILE_ALLOW_DEVICESPECIFIC FALSE -// #define GFILE_MAX_GFILES 3 //#define GFILE_NEED_NOAUTOMOUNT FALSE //#define GFILE_NEED_NOAUTOSYNC FALSE @@ -238,6 +236,9 @@ //#define GFILE_NEED_NATIVEFS FALSE //#define GFILE_NEED_CHBIOSFS FALSE +//#define GFILE_ALLOW_FLOATS FALSE +//#define GFILE_ALLOW_DEVICESPECIFIC FALSE +//#define GFILE_MAX_GFILES 3 /////////////////////////////////////////////////////////////////////////// // GADC // diff --git a/src/gfile/gfile.c b/src/gfile/gfile.c index abffd410..caf7f22f 100644 --- a/src/gfile/gfile.c +++ b/src/gfile/gfile.c @@ -35,6 +35,11 @@ struct GFILE { long int pos; }; +struct gfileList { + const struct GFILEVMT * vmt; + bool_t dirs; +}; + typedef struct GFILEVMT { const struct GFILEVMT * next; uint8_t flags; @@ -59,6 +64,11 @@ typedef struct GFILEVMT { bool_t (*mount) (const char *drive); bool_t (*unmount) (const char *drive); bool_t (*sync) (GFILE *f); + #if GFILE_NEED_FILELISTS + gfileList * (*flopen) (const char *path, bool_t dirs); + const char *(*flread) (gfileList *pfl); + void (*flclose) (gfileList *pfl); + #endif } GFILEVMT; // The chain of FileSystems @@ -70,6 +80,9 @@ GFILE *gfileStdIn; GFILE *gfileStdOut; GFILE *gfileStdErr; +// Forward definition used by some special open calls +static GFILE *findemptyfile(const char *mode); + /** * The order of the file-systems below determines the order * that they are searched to find a file. @@ -118,6 +131,34 @@ GFILE *gfileStdErr; #include "src/gfile/inc_romfs.c" #endif +/******************************************************** + * The virtual string file VMT + ********************************************************/ +#if GFILE_NEED_STRINGS + #include "src/gfile/inc_strings.c" +#endif + +/******************************************************** + * Printg Routines + ********************************************************/ +#if GFILE_NEED_PRINTG + #include "src/gfile/inc_printg.c" +#endif + +/******************************************************** + * Scang Routines + ********************************************************/ +#if GFILE_NEED_SCANG + #include "src/gfile/inc_scang.c" +#endif + +/******************************************************** + * Stdio Emulation Routines + ********************************************************/ +#if GFILE_NEED_STDIO + #include "src/gfile/inc_stdio.c" +#endif + /******************************************************** * IO routines ********************************************************/ @@ -251,39 +292,48 @@ bool_t gfileRename(const char *oldname, const char *newname) { return FALSE; } -static uint16_t mode2flags(const char *mode) { - uint16_t flags; +static GFILE *findemptyfile(const char *mode) { + GFILE * f; - switch(mode[0]) { - case 'r': - flags = GFILEFLG_READ|GFILEFLG_MUSTEXIST; - while (*++mode) { + // First find an available GFILE slot. + for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) { + if (!(f->flags & GFILEFLG_OPEN)) { + // Get the flags switch(mode[0]) { - case '+': flags |= GFILEFLG_WRITE; break; - case 'b': flags |= GFILEFLG_BINARY; break; + case 'r': + f->flags = GFILEFLG_READ|GFILEFLG_MUSTEXIST; + while (*++mode) { + switch(mode[0]) { + case '+': f->flags |= GFILEFLG_WRITE; break; + case 'b': f->flags |= GFILEFLG_BINARY; break; + } + } + break; + case 'w': + f->flags = GFILEFLG_WRITE|GFILEFLG_TRUNC; + while (*++mode) { + switch(mode[0]) { + case '+': f->flags |= GFILEFLG_READ; break; + case 'b': f->flags |= GFILEFLG_BINARY; break; + case 'x': f->flags |= GFILEFLG_MUSTNOTEXIST; break; + } + } + break; + case 'a': + f->flags = GFILEFLG_WRITE|GFILEFLG_APPEND; + while (*++mode) { + switch(mode[0]) { + case '+': f->flags |= GFILEFLG_READ; break; + case 'b': f->flags |= GFILEFLG_BINARY; break; + case 'x': f->flags |= GFILEFLG_MUSTNOTEXIST; break; + } + } + break; + default: + return 0; } + return f; } - return flags; - case 'w': - flags = GFILEFLG_WRITE|GFILEFLG_TRUNC; - while (*++mode) { - switch(mode[0]) { - case '+': flags |= GFILEFLG_READ; break; - case 'b': flags |= GFILEFLG_BINARY; break; - case 'x': flags |= GFILEFLG_MUSTNOTEXIST; break; - } - } - return flags; - case 'a': - flags = GFILEFLG_WRITE|GFILEFLG_APPEND; - while (*++mode) { - switch(mode[0]) { - case '+': flags |= GFILEFLG_READ; break; - case 'b': flags |= GFILEFLG_BINARY; break; - case 'x': flags |= GFILEFLG_MUSTNOTEXIST; break; - } - } - return flags; } return 0; } @@ -307,112 +357,34 @@ static bool_t testopen(const GFILEVMT *p, GFILE *f, const char *fname) { } GFILE *gfileOpen(const char *fname, const char *mode) { - uint16_t flags; GFILE * f; const GFILEVMT *p; - // Get the requested mode - if (!(flags = mode2flags(mode))) + // Get an empty file and set the flags + if (!(f = findemptyfile(mode))) return 0; #if GFILE_ALLOW_DEVICESPECIFIC if (fname[0] && fname[1] == '|') { - // First find an available GFILE slot. - for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) { - if (!(f->flags & GFILEFLG_OPEN)) { - // Try to open the file - f->flags = flags; - for(p = FsChain; p; p = p->next) { - if (p->prefix == fname[0]) - return testopen(p, f, fname+2) ? f : 0; - } - // File not found - break; - } + for(p = FsChain; p; p = p->next) { + if (p->prefix == fname[0]) + return testopen(p, f, fname+2) ? f : 0; } - // No available slot + // File not found return 0; } #endif - // First find an available GFILE slot. - for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) { - if (!(f->flags & GFILEFLG_OPEN)) { - - // Try to open the file - f->flags = flags; - for(p = FsChain; p; p = p->next) { - if (testopen(p, f, fname)) - return f; - } - // File not found - break; - } + for(p = FsChain; p; p = p->next) { + if (testopen(p, f, fname)) + return f; } - // No available slot + // File not found return 0; } -#if GFILE_NEED_CHIBIOSFS && GFX_USE_OS_CHIBIOS - GFILE * gfileOpenBaseFileStream(void *BaseFileStreamPtr, const char *mode) { - GFILE * f; - - // First find an available GFILE slot. - for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) { - if (!(f->flags & GFILEFLG_OPEN)) { - // Get the flags - if (!(f->flags = mode2flags(mode))) - return 0; - - // If we want write but the fs doesn't allow it then return - if ((f->flags & GFILEFLG_WRITE) && !(FsCHIBIOSVMT.flags & GFSFLG_WRITEABLE)) - return 0; - - // File is open - fill in all the details - f->vmt = &FsCHIBIOSVMT; - f->obj = BaseFileStreamPtr; - f->pos = 0; - f->flags |= GFILEFLG_OPEN|GFILEFLG_CANSEEK; - return f; - } - } - - // No available slot - return 0; - } -#endif - -#if GFILE_NEED_MEMFS - GFILE * gfileOpenMemory(void *memptr, const char *mode) { - GFILE * f; - - // First find an available GFILE slot. - for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) { - if (!(f->flags & GFILEFLG_OPEN)) { - // Get the flags - if (!(f->flags = mode2flags(mode))) - return 0; - - // If we want write but the fs doesn't allow it then return - if ((f->flags & GFILEFLG_WRITE) && !(FsMemVMT.flags & GFSFLG_WRITEABLE)) - return 0; - - // File is open - fill in all the details - f->vmt = &FsMemVMT; - f->obj = memptr; - f->pos = 0; - f->flags |= GFILEFLG_OPEN|GFILEFLG_CANSEEK; - return f; - } - } - - // No available slot - return 0; - } -#endif - void gfileClose(GFILE *f) { if (!f || !(f->flags & GFILEFLG_OPEN)) return; @@ -512,579 +484,35 @@ bool_t gfileSync(GFILE *f) { return f->vmt->sync(f); } -/******************************************************** - * String VMT routines - ********************************************************/ -#if GFILE_NEED_STRINGS && (GFILE_NEED_PRINTG || GFILE_NEED_SCANG) - #include +#if GFILE_NEED_FILELISTS + gfileList *gfileOpenFileList(char fs, const char *path, bool_t dirs) { + const GFILEVMT *p; + gfileList * pfl; - // Special String VMT - static int StringRead(GFILE *f, void *buf, int size) { - (void) size; - - // size must be 1 for a complete read - if (!((char *)f->obj)[f->pos]) - return 0; - ((char *)buf)[0] = ((char *)f->obj)[f->pos]; - return 1; - } - static int StringWrite(GFILE *f, const void *buf, int size) { - (void) size; - - // size must be 1 for a complete write - ((char *)f->obj)[f->pos] = ((char *)buf)[0]; - return 1; - } - static const GFILEVMT StringVMT = { - 0, // next - 0, // flags - '_', // prefix - 0, 0, 0, 0, - 0, 0, StringRead, StringWrite, - 0, 0, 0, - 0, 0, 0 - }; -#endif - -/******************************************************** - * printg routines - ********************************************************/ -#if GFILE_NEED_PRINTG - #include - - #define MAX_FILLER 11 - #define FLOAT_PRECISION 100000 - - int fnprintg(GFILE *f, int maxlen, const char *fmt, ...) { - int res; - va_list ap; - - va_start(ap, fmt); - res = vfnprintg(f, maxlen, fmt, ap); - va_end(ap); - return res; - } - - 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; - } - - int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg) { - int ret; - char *p, *s, c, filler; - int i, precision, width; - bool_t is_long, left_align; - long l; - #if GFILE_ALLOW_FLOATS - float f; - char tmpbuf[2*MAX_FILLER + 1]; - #else - char tmpbuf[MAX_FILLER + 1]; - #endif - - ret = 0; - if (maxlen < 0) - return 0; - if (!maxlen) - maxlen = -1; - - while (*fmt) { - if (*fmt != '%') { - gfileWrite(f, fmt, 1); - ret++; if (!--maxlen) return ret; - fmt++; - continue; - } - fmt++; - - p = s = tmpbuf; - left_align = FALSE; - filler = ' '; - width = 0; - precision = 0; - - if (*fmt == '-') { - fmt++; - left_align = TRUE; - } - if (*fmt == '.') { - fmt++; - filler = '0'; - } - - while (1) { - c = *fmt++; - if (c >= '0' && c <= '9') { - c -= '0'; - width = width * 10 + c; - } else if (c == '*') - width = va_arg(arg, int); - else - break; - } - if (c == '.') { - while (1) { - c = *fmt++; - if (c >= '0' && c <= '9') { - c -= '0'; - precision = precision * 10 + c; - } else if (c == '*') - precision = va_arg(arg, int); - else - break; - } - } - /* 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 0: - return ret; - case 'c': - filler = ' '; - *p++ = va_arg(arg, int); - break; - case 's': - filler = ' '; - if ((s = va_arg(arg, 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(arg, long); - else - l = va_arg(arg, int); - if (l < 0) { - *p++ = '-'; - l = -l; - } - p = ltoa_wd(p, l, 10, 0); - break; - #if GFILE_ALLOW_FLOATS - case 'f': - f = (float) va_arg(arg, double); - if (f < 0) { - *p++ = '-'; - f = -f; - } - l = f; - p = ltoa_wd(p, l, 10, 0); - *p++ = '.'; - l = (f - l) * FLOAT_PRECISION; - p = ltoa_wd(p, l, 10, FLOAT_PRECISION / 10); - 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(arg, long); - else - l = va_arg(arg, 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') { - gfileWrite(f, s++, 1); - ret++; if (!--maxlen) return ret; - i--; - } - do { - gfileWrite(f, &filler, 1); - ret++; if (!--maxlen) return ret; - } while (++width != 0); - } - while (--i >= 0) { - gfileWrite(f, s++, 1); - ret++; if (!--maxlen) return ret; - } - while (width) { - gfileWrite(f, &filler, 1); - ret++; if (!--maxlen) return ret; - width--; - } - } - return ret; - } - - #if GFILE_NEED_STRINGS - int snprintg(char *buf, int maxlen, const char *fmt, ...) { - int res; - GFILE f; - va_list ap; - - if (maxlen <= 1) { - if (maxlen == 1) { - *buf = 0; + // Find the correct VMT + for(p = FsChain; p; p = p->next) { + if (p->prefix == fs) { + if (!p->flopen) return 0; + pfl = p->flopen(path, dirs); + if (pfl) { + pfl->vmt = p; + pfl->dirs = dirs; } - maxlen += 1; - } - f.flags = GFILEFLG_OPEN|GFILEFLG_WRITE; - f.vmt = &StringVMT; - f.pos = 0; - f.obj = buf; - va_start(ap, fmt); - res = vfnprintg(&f, maxlen-1, fmt, ap); - va_end(ap); - buf[res] = 0; - return res; - } - int vsnprintg(char *buf, int maxlen, const char *fmt, va_list arg) { - int res; - GFILE f; - - if (maxlen <= 1) { - if (maxlen == 1) { - *buf = 0; - return 0; - } - maxlen += 1; - } - f.flags = GFILEFLG_OPEN|GFILEFLG_WRITE; - f.vmt = &StringVMT; - f.pos = 0; - f.obj = buf; - res = vfnprintg(&f, maxlen-1, fmt, arg); - buf[res] = 0; - return res; - } - #endif -#endif - -/******************************************************** - * scang routines - ********************************************************/ -#if GFILE_NEED_SCANG - int fscang(GFILE *f, const char *fmt, ...) { - int res; - va_list ap; - - va_start(ap, fmt); - res = vfscang(f, fmt, ap); - va_end(ap); - return res; - } - - int vfscang(GFILE *f, const char *fmt, va_list arg) { - int res, width, size, base; - unsigned long num; - char c; - bool_t assign, negate; - char *p; - - for(res = 0; *fmt; fmt++) { - switch(*fmt) { - case ' ': case '\t': case '\r': case '\n': case '\v': case '\f': - break; - - case '%': - fmt++; - assign = TRUE; - negate = FALSE; - width = 0; - size = 1; - num = 0; - - if (*fmt == '*') { - fmt++; - assign = FALSE; - } - while(*fmt >= '0' && *fmt <= '9') - width = width * 10 + (*fmt++ - '0'); - if (*fmt == 'h') { - fmt++; - size = 0; - } else if (*fmt == 'l') { - fmt++; - size = 2; - } else if (*fmt == 'L') { - fmt++; - size = 3; - } - switch(*fmt) { - case 0: - return res; - case '%': - goto matchchar; - case 'c': - if (!width) { - while(1) { - if (!gfileRead(f, &c, 1)) return res; - switch(c) { - case ' ': case '\t': case '\r': - case '\n': case '\v': case '\f': continue; - } - break; - } - width = 1; - } else { - if (!gfileRead(f, &c, 1)) return res; - } - if (assign) { - p = va_arg(arg, char *); - res++; - *p++ = c; - } - while(--width) { - if (!gfileRead(f, &c, 1)) return res; - if (assign) *p++ = c; - } - break; - case 's': - while(1) { - if (!gfileRead(f, &c, 1)) return res; - switch(c) { - case ' ': case '\t': case '\r': - case '\n': case '\v': case '\f': continue; - } - break; - } - if (assign) { - p = va_arg(arg, char *); - res++; - *p++ = c; - } - if (width) { - while(--width) { - if (!gfileRead(f, &c, 1)) { - if (assign) *((char *)p) = 0; - return res; - } - if (assign) *p++ = c; - } - } else { - while(1) { - if (!gfileRead(f, &c, 1)) { - if (assign) *((char *)p) = 0; - return res; - } - switch(c) { - case ' ': case '\t': case '\r': - case '\n': case '\v': case '\f': break; - default: - if (assign) *p++ = c; - continue; - } - break; - } - //ungetch(c); - } - if (assign) *p = 0; - break; - case 'd': base = 10; goto getnum; - case 'i': base = -1; goto getnum; - case 'o': base = 8; goto getnum; - case 'u': base = 10; goto getnum; - case 'x': base = 16; goto getnum; - case 'b': base = 2; - getnum: - while(1) { - if (!gfileRead(f, &c, 1)) return res; - switch(c) { - case ' ': case '\t': case '\r': - case '\n': case '\v': case '\f': continue; - } - break; - } - if (c == '-' && *fmt != 'u') { - negate = TRUE; - if ((width && !--width) || !gfileRead(f, &c, 1)) return res; - } - if (base == -1) { - if (c == '0') { - if ((width && !--width) || !gfileRead(f, &c, 1)) goto assignnum; - switch(c) { - case 'x': case 'X': - base = 16; - if ((width && !--width) || !gfileRead(f, &c, 1)) return res; - break; - case 'b': case 'B': - base = 2; - if ((width && !--width) || !gfileRead(f, &c, 1)) return res; - break; - default: - base = 8; - break; - } - } else - base = 10; - } - while(1) { - if (c >= '0' && c <= '9' && c - '0' < base) - num = num * base + (c - '0'); - else if (c >= 'A' && c <= 'F' && base == 16) - num = num * base + (c - ('A'-10)); - else if (c >= 'a' && c <= 'f' && base == 16) - num = num * base + (c - ('a'-10)); - else { - // ungetch(c) - break; - } - if ((width && !--width) || !gfileRead(f, &c, 1)) - break; - } - - assignnum: - if (negate) - num = -num; - - if (assign) { - switch(size) { - case 0: // short - p = (char *)va_arg(arg, short *); - res++; - *((short *)p) = (short)num; - case 1: // int - p = (char *)va_arg(arg, int *); - res++; - *((int *)p) = (int)num; - case 2: case 3: // long - p = (char *)va_arg(arg, long *); - res++; - *((long *)p) = (long)num; - } - } - break; - - #if GFILE_ALLOW_FLOATS - case 'e': case 'f': case 'g': - // TODO - #endif - default: - return res; - } - - break; - - default: - matchchar: - while(1) { - if (!gfileRead(f, &c, 1)) return res; - switch(c) { - case ' ': case '\t': case '\r': - case '\n': case '\v': case '\f': continue; - } - break; - } - if (c != *fmt) return res; - break; + return pfl; } } - return res; - } - - #if GFILE_NEED_STRINGS - int sscang(const char *buf, const char *fmt, ...) { - int res; - GFILE f; - va_list ap; - - f.flags = GFILEFLG_OPEN|GFILEFLG_READ; - f.vmt = &StringVMT; - f.pos = 0; - f.obj = (void *)buf; - va_start(ap, fmt); - res = vfscang(&f, fmt, ap); - va_end(ap); - return res; - } - - int vsscang(const char *buf, const char *fmt, va_list arg) { - int res; - GFILE f; - - f.flags = GFILEFLG_OPEN|GFILEFLG_READ; - f.vmt = &StringVMT; - f.pos = 0; - f.obj = (void *)buf; - res = vfscang(&f, fmt, arg); - return res; - } - #endif -#endif - -/******************************************************** - * stdio emulation routines - ********************************************************/ -#if GFILE_NEED_STDIO - size_t gstdioRead(void * ptr, size_t size, size_t count, FILE *f) { - return gfileRead(f, ptr, size*count)/size; - } - size_t gstdioWrite(const void * ptr, size_t size, size_t count, FILE *f) { - return gfileWrite(f, ptr, size*count)/size; - } - int gstdioSeek(FILE *f, size_t offset, int origin) { - switch(origin) { - case SEEK_SET: - break; - case SEEK_CUR: - offset += f->pos; - break; - case SEEK_END: - offset += gfileGetSize(f); - break; - default: - return -1; - } - return gfileSetPos(f, offset) ? 0 : -1; - } - int gstdioGetpos(FILE *f, long int *pos) { - if (!(f->flags & GFILEFLG_OPEN)) - return -1; - *pos = f->pos; return 0; } + + const char *gfileReadFileList(gfileList *pfl) { + return pfl->vmt->flread ? pfl->vmt->flread(pfl) : 0; + } + + void gfileCloseFileList(gfileList *pfl) { + if (pfl->vmt->flclose) + pfl->vmt->flclose(pfl); + } #endif #endif /* GFX_USE_GFILE */ diff --git a/src/gfile/inc_chibiosfs.c b/src/gfile/inc_chibiosfs.c index 8d321b33..13ae6cac 100644 --- a/src/gfile/inc_chibiosfs.c +++ b/src/gfile/inc_chibiosfs.c @@ -27,22 +27,39 @@ static const GFILEVMT FsCHIBIOSVMT = { 0, 0, 0, 0, 0, ChibiOSBFSClose, ChibiOSBFSRead, ChibiOSBFSWrite, ChibiOSBFSSetpos, ChibiOSBFSGetsize, ChibiOSBFSEof, - 0, 0, - 0 + 0, 0, 0, + #if GFILE_NEED_FILELISTS + 0, 0, 0, + #endif }; static void ChibiOSBFSClose(GFILE *f) { - chFileStreamClose(((BaseFileStream *)f->fd)); + chFileStreamClose(((BaseFileStream *)f->obj)); } static int ChibiOSBFSRead(GFILE *f, void *buf, int size) { - return chSequentialStreamRead(((BaseFileStream *)f->fd), (uint8_t *)buf, size); + return chSequentialStreamRead(((BaseFileStream *)f->obj), (uint8_t *)buf, size); } static int ChibiOSBFSWrite(GFILE *f, const void *buf, int size) { - return chSequentialStreamWrite(((BaseFileStream *)f->fd), (uint8_t *)buf, size); + return chSequentialStreamWrite(((BaseFileStream *)f->obj), (uint8_t *)buf, size); } static bool_t ChibiOSBFSSetpos(GFILE *f, long int pos) { - chFileStreamSeek(((BaseFileStream *)f->fd), pos); + chFileStreamSeek(((BaseFileStream *)f->obj), pos); return TRUE; } -static long int ChibiOSBFSGetsize(GFILE *f) { return chFileStreamGetSize(((BaseFileStream *)f->fd)); } -static bool_t ChibiOSBFSEof(GFILE *f) { return f->pos >= chFileStreamGetSize(((BaseFileStream *)f->fd)); } +static long int ChibiOSBFSGetsize(GFILE *f) { return chFileStreamGetSize(((BaseFileStream *)f->obj)); } +static bool_t ChibiOSBFSEof(GFILE *f) { return f->pos >= chFileStreamGetSize(((BaseFileStream *)f->obj)); } + +GFILE * gfileOpenBaseFileStream(void *BaseFileStreamPtr, const char *mode) { + GFILE * f; + + // Get an empty file and set the flags + if (!(f = findemptyfile(mode))) + return 0; + + // File is open - fill in all the details + f->vmt = &FsCHIBIOSVMT; + f->obj = BaseFileStreamPtr; + f->pos = 0; + f->flags |= GFILEFLG_OPEN|GFILEFLG_CANSEEK; + return f; +} diff --git a/src/gfile/inc_fatfs.c b/src/gfile/inc_fatfs.c index 8d7233e7..c8db0e64 100644 --- a/src/gfile/inc_fatfs.c +++ b/src/gfile/inc_fatfs.c @@ -30,6 +30,11 @@ static bool_t fatfsEOF(GFILE* f); static bool_t fatfsMount(const char* drive); static bool_t fatfsUnmount(const char* drive); static bool_t fatfsSync(GFILE* f); +#if _FS_MINIMIZE <= 1 && GFILE_NEED_FILELISTS + static gfileList *fatfsFlOpen(const char *path, bool_t dirs); + static const char *fatfsFlRead(gfileList *pfl); + static void fatfsFlClose(gfileList *pfl); +#endif static const GFILEVMT FsFatFSVMT = { GFILE_CHAINHEAD, @@ -46,14 +51,29 @@ static const GFILEVMT FsFatFSVMT = { fatfsSetPos, fatfsGetSize, fatfsEOF, - fatfsMount, - fatfsUnmount, - fatfsSync + fatfsMount, fatfsUnmount, fatfsSync, + #if GFILE_NEED_FILELISTS + #if _FS_MINIMIZE <= 1 + fatfsFlOpen, fatfsFlRead, fatfsFlClose + #else + 0, 0, 0 + #endif + #endif }; #undef GFILE_CHAINHEAD #define GFILE_CHAINHEAD &FsFatFSVMT +// Our directory list structure +typedef struct fatfsList { + gfileList fl; // This must be the first element. + DIR dir; + FILINFO fno; + #if _USE_LFN + char lfn[_MAX_LFN + 1]; /* Buffer to store the LFN */ + #endif +} fatfsList; + // optimize these later on. Use an array to have multiple FatFS static bool_t fatfs_mounted = FALSE; static FATFS fatfs_fs; @@ -245,3 +265,58 @@ static bool_t fatfsSync(GFILE *f) return TRUE; } +#if _FS_MINIMIZE <= 1 && GFILE_NEED_FILELISTS + static gfileList *fatfsFlOpen(const char *path, bool_t dirs) { + fatfsList *p; + (void) dirs; + + if (!(p = gfxAlloc(sizeof(fatfsList)))) + return 0; + + if (f_opendir(&p->dir, path) != FR_OK) { + gfxFree(p); + return 0; + } + return &p->fl; + } + + static const char *fatfsFlRead(gfileList *pfl) { + #define ffl ((fatfsList *)pfl) + + while(1) { + #if _USE_LFN + ffl->fno.lfname = ffl->lfn; + ffl->fno.lfsize = sizeof(ffl->lfn); + #endif + + // Read the next entry + if (f_readdir(&ffl->dir, &ffl->fno) != FR_OK || !ffl->fno.fname[0]) + return 0; + + /* Ignore dot entries */ + if (ffl->fno.fname[0] == '.') continue; + + /* Is it a directory */ + if (ffl->fl.dirs) { + if ((ffl->fno.fattrib & AM_DIR)) + break; + } else { + if (!(ffl->fno.fattrib & AM_DIR)) + break; + } + } + + #if _USE_LFN + return ffl->fno.lfname[0] ? ffl->fno.lfname : ffl->fno.fname; + #else + return ffl->fno.fname; + #endif + #undef ffl + } + + static void fatfsFlClose(gfileList *pfl) { + f_closedir(&((fatfsList *)pfl)->dir); + gfxFree(pfl); + } + +#endif diff --git a/src/gfile/inc_memfs.c b/src/gfile/inc_memfs.c index baeb0e97..6177b7d8 100644 --- a/src/gfile/inc_memfs.c +++ b/src/gfile/inc_memfs.c @@ -26,8 +26,10 @@ static const GFILEVMT FsMemVMT = { 0, 0, 0, 0, 0, 0, MEMRead, MEMWrite, MEMSetpos, 0, 0, - 0, 0, - 0 + 0, 0, 0, + #if GFILE_NEED_FILELISTS + 0, 0, 0, + #endif }; static int MEMRead(GFILE *f, void *buf, int size) { @@ -43,3 +45,18 @@ static bool_t MEMSetpos(GFILE *f, long int pos) { (void) pos; return TRUE; } + +GFILE * gfileOpenMemory(void *memptr, const char *mode) { + GFILE *f; + + // Get an empty file and set the flags + if (!(f = findemptyfile(mode))) + return 0; + + // File is open - fill in all the details + f->vmt = &FsMemVMT; + f->obj = memptr; + f->pos = 0; + f->flags |= GFILEFLG_OPEN|GFILEFLG_CANSEEK; + return f; +} diff --git a/src/gfile/inc_nativefs.c b/src/gfile/inc_nativefs.c index 6845cb71..8c28480b 100644 --- a/src/gfile/inc_nativefs.c +++ b/src/gfile/inc_nativefs.c @@ -33,6 +33,11 @@ static int NativeWrite(GFILE *f, const void *buf, int size); static bool_t NativeSetpos(GFILE *f, long int pos); static long int NativeGetsize(GFILE *f); static bool_t NativeEof(GFILE *f); +#if GFILE_NEED_FILELISTS + static gfileList *NativeFlOpen(const char *path, bool_t dirs); + static const char *NativeFlRead(gfileList *pfl); + static void NativeFlClose(gfileList *pfl); +#endif static const GFILEVMT FsNativeVMT = { GFILE_CHAINHEAD, // next @@ -46,8 +51,10 @@ static const GFILEVMT FsNativeVMT = { NativeDel, NativeExists, NativeFilesize, NativeRen, NativeOpen, NativeClose, NativeRead, NativeWrite, NativeSetpos, NativeGetsize, NativeEof, - 0, 0, - 0 + 0, 0, 0, + #if GFILE_NEED_FILELISTS + NativeFlOpen, NativeFlRead, NativeFlClose + #endif }; #undef GFILE_CHAINHEAD #define GFILE_CHAINHEAD &FsNativeVMT @@ -102,3 +109,108 @@ static long int NativeGetsize(GFILE *f) { if (fstat(fileno((FILE *)f->obj), &st)) return -1; return st.st_size; } + +#if GFILE_NEED_FILELISTS + #if defined(WIN32) || GFX_USE_OS_WIN32 + typedef struct NativeFileList { + gfileList fl; + HANDLE d; + WIN32_FIND_DATA f; + bool_t first; + } NativeFileList; + + static gfileList *NativeFlOpen(const char *path, bool_t dirs) { + NativeFileList *p; + (void) dirs; + + if (!(p = gfxAlloc(sizeof(NativeFileList)))) + return 0; + if ((p->d = FindFirstFile(path, &p->f)) == INVALID_HANDLE_VALUE) { + gfxFree(p); + return 0; + } + p->first = TRUE; + return &p->fl; + } + + static const char *NativeFlRead(gfileList *pfl) { + #define nfl ((NativeFileList *)pfl) + while(1) { + if (!nfl->first && !FindNextFile(nfl->d, &nfl->f)) + return 0; + nfl->first = FALSE; + if (nfl->f.cFileName[0] == '.') + continue; + if (nfl->fl.dirs) { + if ((nfl->f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + break; + } else { + if (!(nfl->f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + break; + } + } + return nfl->f.cFileName; + #undef nfl + } + + static void NativeFlClose(gfileList *pfl) { + CloseHandle(((NativeFileList *)pfl)->d); + gfxFree(pfl); + } + + #else + #include + + typedef struct NativeFileList { + gfileList fl; + DIR * d; + struct dirent * f; + } NativeFileList; + + static gfileList *NativeFlOpen(const char *path, bool_t dirs) { + NativeFileList *p; + (void) dirs; + + if (!(p = gfxAlloc(sizeof(NativeFileList)))) + return 0; + if (!(p->d = opendir(path))) { + gfxFree(p); + return 0; + } + return &p->fl; + } + + static const char *NativeFlRead(gfileList *pfl) { + #define nfl ((NativeFileList *)pfl) + while(1) { + if (!(nfl->f = readdir(nfl->d))) + return 0; + if (nfl->f->d_name[0] == '.') + continue; + + #ifdef _DIRENT_HAVE_D_TYPE + if (nfl->fl.dirs) { + if (nfl->f->d_type == DT_DIR) + break; + } else { + if (nfl->f->d_type == DT_REG) + break; + } + #else + // Oops - no type field. We could use stat() here but that would mean + // concatting the supplied path to the found filename. + // That all just seems too hard. Instead we just don't + // distinguish between files and directories. + break; + #endif + } + return nfl->f->d_name; + #undef nfl + } + + static void NativeFlClose(gfileList *pfl) { + closedir(((NativeFileList *)pfl)->d); + gfxFree(pfl); + } + #endif +#endif diff --git a/src/gfile/inc_printg.c b/src/gfile/inc_printg.c new file mode 100644 index 00000000..8d24b347 --- /dev/null +++ b/src/gfile/inc_printg.c @@ -0,0 +1,261 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * This file is included by src/gfile/gfile.c + */ + +/******************************************************** + * Printg Routines + ********************************************************/ + +#include + +#define MAX_FILLER 11 +#define FLOAT_PRECISION 100000 + +int fnprintg(GFILE *f, int maxlen, const char *fmt, ...) { + int res; + va_list ap; + + va_start(ap, fmt); + res = vfnprintg(f, maxlen, fmt, ap); + va_end(ap); + return res; +} + +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; +} + +int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg) { + int ret; + char *p, *s, c, filler; + int i, precision, width; + bool_t is_long, left_align; + long l; + #if GFILE_ALLOW_FLOATS + float f; + char tmpbuf[2*MAX_FILLER + 1]; + #else + char tmpbuf[MAX_FILLER + 1]; + #endif + + ret = 0; + if (maxlen < 0) + return 0; + if (!maxlen) + maxlen = -1; + + while (*fmt) { + if (*fmt != '%') { + gfileWrite(f, fmt, 1); + ret++; if (!--maxlen) return ret; + fmt++; + continue; + } + fmt++; + + p = s = tmpbuf; + left_align = FALSE; + filler = ' '; + width = 0; + precision = 0; + + if (*fmt == '-') { + fmt++; + left_align = TRUE; + } + if (*fmt == '.') { + fmt++; + filler = '0'; + } + + while (1) { + c = *fmt++; + if (c >= '0' && c <= '9') { + c -= '0'; + width = width * 10 + c; + } else if (c == '*') + width = va_arg(arg, int); + else + break; + } + if (c == '.') { + while (1) { + c = *fmt++; + if (c >= '0' && c <= '9') { + c -= '0'; + precision = precision * 10 + c; + } else if (c == '*') + precision = va_arg(arg, int); + else + break; + } + } + /* 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 0: + return ret; + case 'c': + filler = ' '; + *p++ = va_arg(arg, int); + break; + case 's': + filler = ' '; + if ((s = va_arg(arg, 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(arg, long); + else + l = va_arg(arg, int); + if (l < 0) { + *p++ = '-'; + l = -l; + } + p = ltoa_wd(p, l, 10, 0); + break; + #if GFILE_ALLOW_FLOATS + case 'f': + f = (float) va_arg(arg, double); + if (f < 0) { + *p++ = '-'; + f = -f; + } + l = f; + p = ltoa_wd(p, l, 10, 0); + *p++ = '.'; + l = (f - l) * FLOAT_PRECISION; + p = ltoa_wd(p, l, 10, FLOAT_PRECISION / 10); + 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(arg, long); + else + l = va_arg(arg, 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') { + gfileWrite(f, s++, 1); + ret++; if (!--maxlen) return ret; + i--; + } + do { + gfileWrite(f, &filler, 1); + ret++; if (!--maxlen) return ret; + } while (++width != 0); + } + while (--i >= 0) { + gfileWrite(f, s++, 1); + ret++; if (!--maxlen) return ret; + } + while (width) { + gfileWrite(f, &filler, 1); + ret++; if (!--maxlen) return ret; + width--; + } + } + return ret; +} + +#if GFILE_NEED_STRINGS + int snprintg(char *buf, int maxlen, const char *fmt, ...) { + int res; + GFILE f; + va_list ap; + + if (maxlen <= 1) { + if (maxlen == 1) { + *buf = 0; + return 0; + } + maxlen += 1; + } + + f.flags = GFILEFLG_WRITE|GFILEFLG_TRUNC; + gfileOpenStringFromStaticGFILE(&f, buf); + + va_start(ap, fmt); + res = vfnprintg(&f, maxlen-1, fmt, ap); + va_end(ap); + return res; + } + int vsnprintg(char *buf, int maxlen, const char *fmt, va_list arg) { + GFILE f; + + if (maxlen <= 1) { + if (maxlen == 1) { + *buf = 0; + return 0; + } + maxlen += 1; + } + + f.flags = GFILEFLG_WRITE|GFILEFLG_TRUNC; + gfileOpenStringFromStaticGFILE(&f, buf); + + return vfnprintg(&f, maxlen-1, fmt, arg); + } +#endif diff --git a/src/gfile/inc_romfs.c b/src/gfile/inc_romfs.c index 167430ce..97d26239 100644 --- a/src/gfile/inc_romfs.c +++ b/src/gfile/inc_romfs.c @@ -31,11 +31,15 @@ typedef struct ROMFS_DIRENTRY { } ROMFS_DIRENTRY; #define ROMFS_DIRENTRY_HEAD 0 - #include "romfs_files.h" - static const ROMFS_DIRENTRY const *FsROMHead = ROMFS_DIRENTRY_HEAD; +typedef struct ROMFileList { + gfileList fl; + const ROMFS_DIRENTRY *pdir; +} ROMFileList; + + static bool_t ROMExists(const char *fname); static long int ROMFilesize(const char *fname); static bool_t ROMOpen(GFILE *f, const char *fname); @@ -44,6 +48,11 @@ static int ROMRead(GFILE *f, void *buf, int size); static bool_t ROMSetpos(GFILE *f, long int pos); static long int ROMGetsize(GFILE *f); static bool_t ROMEof(GFILE *f); +#if GFILE_NEED_FILELISTS + static gfileList *ROMFlOpen(const char *path, bool_t dirs); + static const char *ROMFlRead(gfileList *pfl); + static void ROMFlClose(gfileList *pfl); +#endif static const GFILEVMT FsROMVMT = { GFILE_CHAINHEAD, // next @@ -52,8 +61,10 @@ static const GFILEVMT FsROMVMT = { 0, ROMExists, ROMFilesize, 0, ROMOpen, ROMClose, ROMRead, 0, ROMSetpos, ROMGetsize, ROMEof, - 0, 0, - 0 + 0, 0, 0, + #if GFILE_NEED_FILELISTS + ROMFlOpen, ROMFlRead, ROMFlClose + #endif }; #undef GFILE_CHAINHEAD #define GFILE_CHAINHEAD &FsROMVMT @@ -122,3 +133,45 @@ static bool_t ROMEof(GFILE *f) { return f->pos >= ((const ROMFS_DIRENTRY *)f->obj)->size; } + +#if GFILE_NEED_FILELISTS + static gfileList *ROMFlOpen(const char *path, bool_t dirs) { + ROMFileList * p; + (void) path; + + // We don't support directories or path searching + if (dirs) + return 0; + + // Allocate the list buffer + if (!(p = gfxAlloc(sizeof(ROMFileList)))) + return 0; + + // Initialize it and return it. + p->pdir = 0; + return &p->fl; + } + + static const char *ROMFlRead(gfileList *pfl) { + #define rfl ((ROMFileList *)pfl) + + // Is it the first entry + if (!rfl->pdir) { + rfl->pdir = FsROMHead; + return FsROMHead->name; + } + + // Is it not the last entry + if (rfl->pdir->next) { + rfl->pdir = rfl->pdir->next; + return rfl->pdir->name; + } + + return 0; + #undef rfl + } + + static void ROMFlClose(gfileList *pfl) { + gfxFree(pfl); + } +#endif diff --git a/src/gfile/inc_scang.c b/src/gfile/inc_scang.c new file mode 100644 index 00000000..8dcc8d0f --- /dev/null +++ b/src/gfile/inc_scang.c @@ -0,0 +1,257 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * This file is included by src/gfile/gfile.c + */ + +/******************************************************** + * Scang Routines + ********************************************************/ + +int fscang(GFILE *f, const char *fmt, ...) { + int res; + va_list ap; + + va_start(ap, fmt); + res = vfscang(f, fmt, ap); + va_end(ap); + return res; +} + +int vfscang(GFILE *f, const char *fmt, va_list arg) { + int res, width, size, base; + unsigned long num; + char c; + bool_t assign, negate; + char *p; + + for(res = 0; *fmt; fmt++) { + switch(*fmt) { + case ' ': case '\t': case '\r': case '\n': case '\v': case '\f': + break; + + case '%': + fmt++; + assign = TRUE; + negate = FALSE; + width = 0; + size = 1; + num = 0; + + if (*fmt == '*') { + fmt++; + assign = FALSE; + } + while(*fmt >= '0' && *fmt <= '9') + width = width * 10 + (*fmt++ - '0'); + if (*fmt == 'h') { + fmt++; + size = 0; + } else if (*fmt == 'l') { + fmt++; + size = 2; + } else if (*fmt == 'L') { + fmt++; + size = 3; + } + switch(*fmt) { + case 0: + return res; + case '%': + goto matchchar; + case 'c': + if (!width) { + while(1) { + if (!gfileRead(f, &c, 1)) return res; + switch(c) { + case ' ': case '\t': case '\r': + case '\n': case '\v': case '\f': continue; + } + break; + } + width = 1; + } else { + if (!gfileRead(f, &c, 1)) return res; + } + if (assign) { + p = va_arg(arg, char *); + res++; + *p++ = c; + } + while(--width) { + if (!gfileRead(f, &c, 1)) return res; + if (assign) *p++ = c; + } + break; + case 's': + while(1) { + if (!gfileRead(f, &c, 1)) return res; + switch(c) { + case ' ': case '\t': case '\r': + case '\n': case '\v': case '\f': continue; + } + break; + } + if (assign) { + p = va_arg(arg, char *); + res++; + *p++ = c; + } + if (width) { + while(--width) { + if (!gfileRead(f, &c, 1)) { + if (assign) *((char *)p) = 0; + return res; + } + if (assign) *p++ = c; + } + } else { + while(1) { + if (!gfileRead(f, &c, 1)) { + if (assign) *((char *)p) = 0; + return res; + } + switch(c) { + case ' ': case '\t': case '\r': + case '\n': case '\v': case '\f': break; + default: + if (assign) *p++ = c; + continue; + } + break; + } + //ungetch(c); + } + if (assign) *p = 0; + break; + case 'd': base = 10; goto getnum; + case 'i': base = -1; goto getnum; + case 'o': base = 8; goto getnum; + case 'u': base = 10; goto getnum; + case 'x': base = 16; goto getnum; + case 'b': base = 2; + getnum: + while(1) { + if (!gfileRead(f, &c, 1)) return res; + switch(c) { + case ' ': case '\t': case '\r': + case '\n': case '\v': case '\f': continue; + } + break; + } + if (c == '-' && *fmt != 'u') { + negate = TRUE; + if ((width && !--width) || !gfileRead(f, &c, 1)) return res; + } + if (base == -1) { + if (c == '0') { + if ((width && !--width) || !gfileRead(f, &c, 1)) goto assignnum; + switch(c) { + case 'x': case 'X': + base = 16; + if ((width && !--width) || !gfileRead(f, &c, 1)) return res; + break; + case 'b': case 'B': + base = 2; + if ((width && !--width) || !gfileRead(f, &c, 1)) return res; + break; + default: + base = 8; + break; + } + } else + base = 10; + } + while(1) { + if (c >= '0' && c <= '9' && c - '0' < base) + num = num * base + (c - '0'); + else if (c >= 'A' && c <= 'F' && base == 16) + num = num * base + (c - ('A'-10)); + else if (c >= 'a' && c <= 'f' && base == 16) + num = num * base + (c - ('a'-10)); + else { + // ungetch(c) + break; + } + if ((width && !--width) || !gfileRead(f, &c, 1)) + break; + } + + assignnum: + if (negate) + num = -num; + + if (assign) { + switch(size) { + case 0: // short + p = (char *)va_arg(arg, short *); + res++; + *((short *)p) = (short)num; + case 1: // int + p = (char *)va_arg(arg, int *); + res++; + *((int *)p) = (int)num; + case 2: case 3: // long + p = (char *)va_arg(arg, long *); + res++; + *((long *)p) = (long)num; + } + } + break; + + #if GFILE_ALLOW_FLOATS + case 'e': case 'f': case 'g': + // TODO + #endif + default: + return res; + } + + break; + + default: + matchchar: + while(1) { + if (!gfileRead(f, &c, 1)) return res; + switch(c) { + case ' ': case '\t': case '\r': + case '\n': case '\v': case '\f': continue; + } + break; + } + if (c != *fmt) return res; + break; + } + } + return res; +} + +#if GFILE_NEED_STRINGS + int sscang(const char *buf, const char *fmt, ...) { + int res; + GFILE f; + va_list ap; + + f.flags = GFILEFLG_READ; + gfileOpenStringFromStaticGFILE(&f, (char *)buf); + + va_start(ap, fmt); + res = vfscang(&f, fmt, ap); + va_end(ap); + return res; + } + + int vsscang(const char *buf, const char *fmt, va_list arg) { + GFILE f; + + f.flags = GFILEFLG_READ; + gfileOpenStringFromStaticGFILE(&f, (char *)buf); + + return vfscang(&f, fmt, arg); + } +#endif diff --git a/src/gfile/inc_stdio.c b/src/gfile/inc_stdio.c new file mode 100644 index 00000000..8dc44dcb --- /dev/null +++ b/src/gfile/inc_stdio.c @@ -0,0 +1,45 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * This file is included by src/gfile/gfile.c + */ + +/******************************************************** + * Stdio Emulation Routines + ********************************************************/ + +size_t gstdioRead(void * ptr, size_t size, size_t count, FILE *f) { + return gfileRead(f, ptr, size*count)/size; +} + +size_t gstdioWrite(const void * ptr, size_t size, size_t count, FILE *f) { + return gfileWrite(f, ptr, size*count)/size; +} + +int gstdioSeek(FILE *f, size_t offset, int origin) { + switch(origin) { + case SEEK_SET: + break; + case SEEK_CUR: + offset += f->pos; + break; + case SEEK_END: + offset += gfileGetSize(f); + break; + default: + return -1; + } + return gfileSetPos(f, offset) ? 0 : -1; +} + +int gstdioGetpos(FILE *f, long int *pos) { + if (!(f->flags & GFILEFLG_OPEN)) + return -1; + *pos = f->pos; + return 0; +} diff --git a/src/gfile/inc_strings.c b/src/gfile/inc_strings.c new file mode 100644 index 00000000..692d2dd3 --- /dev/null +++ b/src/gfile/inc_strings.c @@ -0,0 +1,69 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * This file is included by src/gfile/gfile.c + */ + +/******************************************************** + * The virtual string file VMT + ********************************************************/ + +#include + +// Special String VMT +static int StringRead(GFILE *f, void *buf, int size) { + int res; + char *p; + + p = ((char *)f->obj) + f->pos; + for(res = 0; res < size && *p; res++, p++, buf = ((char *)buf)+1) + ((char *)buf)[0] = *p; + return res; +} +static int StringWrite(GFILE *f, const void *buf, int size) { + if ((f->flags & GFILEFLG_APPEND)) { + while(((char *)f->obj)[f->pos]) + f->pos++; + } + memcpy(((char *)f->obj)+f->pos, buf, size); + ((char *)f->obj)[f->pos+size] = 0; + return size; +} +static const GFILEVMT StringVMT = { + 0, // next + 0, // flags + '_', // prefix + 0, 0, 0, 0, + 0, 0, StringRead, StringWrite, + 0, 0, 0, + 0, 0, 0, + #if GFILE_NEED_FILELISTS + 0, 0, 0, + #endif +}; + +static void gfileOpenStringFromStaticGFILE(GFILE *f, char *str) { + if ((f->flags & GFILEFLG_TRUNC)) + str[0] = 0; + f->vmt = &StringVMT; + f->obj = str; + f->pos = 0; + f->flags |= GFILEFLG_OPEN|GFILEFLG_CANSEEK; +} + +GFILE *gfileOpenString(char *str, const char *mode) { + GFILE *f; + + // Get an empty file and set the flags + if (!(f = findemptyfile(mode))) + return 0; + + // File is open - fill in all the details + gfileOpenStringFromStaticGFILE(f, str); + return f; +} diff --git a/src/gfile/sys_defs.h b/src/gfile/sys_defs.h index 0c5bac0c..81d72ac8 100644 --- a/src/gfile/sys_defs.h +++ b/src/gfile/sys_defs.h @@ -33,8 +33,10 @@ #ifndef GFILE_IMPLEMENTATION typedef void GFILE; + typedef void gfileList; #else typedef struct GFILE GFILE; + typedef struct gfileList gfileList; #endif extern GFILE *gfileStdIn; @@ -98,14 +100,33 @@ extern "C" { /** * @brief Open file * @details A file must be opened before it can be accessed - * @details ToDo (document possible modes) * @details The resulting GFILE will be used for all functions that access the file. * * @param[in] fname The file name - * @param[in] mode The mode + * @param[in] mode The mode. * * @return Valid GFILE on success, 0 otherwise * + * @note The modes follow the c library fopen() standard. + * The valid modes are:
+ *
  • r - Open for read, the file must exist
  • + *
  • w - Open for write, the file is truncated if it exists
  • + *
  • wx - Open for write, the file must not exist
  • + *
  • a - Open for append, the file is truncated if it exists
  • + *
  • ax - Open for append, the file must not exists
  • + *

+ * THe following flags can also be added to the above modes:
+ *
  • + - Open for both read and write
  • + *
  • b - Open as a binary file rather than a text file
  • + *
      + * @note Not all file-systems support all modes. For example, write + * is not available with the ROM file-system. Similarly few platforms + * distinguish between binary and text files. + * @note Even though binary vs text is relevant only for a small number of platforms + * the "b" flag should always be specified for binary files such as images. + * This ensures portability to other platforms. The extra flag will be ignored + * on platforms where it is not relevant. + * * @api */ GFILE * gfileOpen(const char *fname, const char *mode); @@ -239,15 +260,118 @@ extern "C" { */ bool_t gfileSync(GFILE *f); - #if GFILE_NEED_CHIBIOSFS && GFX_USE_OS_CHIBIOS + #if GFILE_NEED_FILELISTS || defined(__DOXYGEN__) + /** + * @brief Open a file list + * + * @param[in] fs The file system (F for FatFS) + * @param[in] path Path information to pass to the file system + * @param[in] dirs Pass TRUE to get directories only, FALSE to get files only + * + * @return A pointer to a file list on success, NULL otherwise + * + * @note The path parameter is handled in a file-system specific way. It could be + * treated as a directory name, it may be treated as a file pattern, or it + * may be ignored. Passing NULL will always return the full list of files + * in at least the top level directory. + * @note For file systems that do not support directories, passing TRUE for dirs + * will return an error. + * @note You must call @p gfileCloseFileList() when you have finished with the + * file list in order to free resources. + * + * @api + */ + gfileList *gfileOpenFileList(char fs, const char *path, bool_t dirs); + + /** + * @brief Get the next file in a file list. + * + * @param[in] pfl Pointer to a file list returned by @p gfileOpenFileList() + * + * @return A pointer to a file (or directory) name. Returns NULL if there are no more. + * + * @note The file name may contain the full directory path or may not depending + * on how the file system treats directories. + * @note The returned buffer may be destroyed by the next call to any of + * @p gfileOpenFileList(), @p gfileReadFileList() or @p gfileCloseFileList(). + * Do not use this pointer after one of those calls. + * + * @api + */ + const char *gfileReadFileList(gfileList *pfl); + + /** + * @brief Close a file list. + * + * @param[in] pfl Pointer to a file list returned by @p gfileOpenFileList() + * + * @api + */ + void gfileCloseFileList(gfileList *pfl); + #endif + + #if (GFILE_NEED_CHIBIOSFS && GFX_USE_OS_CHIBIOS) || defined(__DOXYGEN__) + /** + * @brief Open file from a ChibiOS BaseFileStream + * + * @param[in] BaseFileStreamPtr The BaseFileStream to open as a GFILE + * @param[in] mode The mode. + * + * @return Valid GFILE on success, 0 otherwise + * + * @note The modes are the same modes as in @p gfileOpen(). The + * open mode is NOT compared against the BaseFileStream capabilities. + * @note Supported operations are: read, write, getpos, setpos, eof and getsize + * + * @api + */ GFILE * gfileOpenBaseFileStream(void *BaseFileStreamPtr, const char *mode); #endif - #if GFILE_NEED_MEMFS + #if GFILE_NEED_MEMFS || defined(__DOXYGEN__) + /** + * @brief Open file from a memory pointer + * + * @param[in] memptr The pointer to the memory + * @param[in] mode The mode. + * + * @return Valid GFILE on success, 0 otherwise + * + * @note The modes are the same modes as in @p gfileOpen(). Note there is + * no concept of file-size. Be careful not to overwrite other memory or + * to read from inaccessible sections of memory. + * @note Supported operations are: read, write, getpos, setpos + * + * @api + */ GFILE * gfileOpenMemory(void *memptr, const char *mode); #endif - #if GFILE_NEED_PRINTG + #if GFILE_NEED_STRINGS || defined(__DOXYGEN__) + /** + * @brief Open file from a null terminated C string + * + * @param[in] memptr The pointer to the string or string buffer + * @param[in] mode The mode. + * + * @return Valid GFILE on success, 0 otherwise + * + * @note The modes are the same modes as in @p gfileOpen(). Note there is + * no concept of file-size. Be careful not to overwrite other memory or + * to read from inaccessible sections of memory. + * @note Reading will return EOF when the NULL character is reached. + * @note Writing will always place a NULL in the next character effectively terminating the + * string at the character just written. + * @note Supported operations are: read, write, append, getpos, setpos + * @note Be careful with setpos and getpos. They do not check for the end of the string. + * @note Reading and Writing will read/write a maximum of one character at a time. + * + * @api + */ + GFILE * gfileOpenString(char *str, const char *mode); + #endif + + #if GFILE_NEED_PRINTG || defined(__DOXYGEN__) #include int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg); @@ -265,7 +389,7 @@ extern "C" { #endif #endif - #if GFILE_NEED_SCANG + #if GFILE_NEED_SCANG || defined(__DOXYGEN__) #include int vfscang(GFILE *f, const char *fmt, va_list arg); diff --git a/src/gfile/sys_options.h b/src/gfile/sys_options.h index ee52298c..ff1e5d4c 100644 --- a/src/gfile/sys_options.h +++ b/src/gfile/sys_options.h @@ -46,6 +46,7 @@ /** * @brief Include printg, fprintg etc functions * @details Defaults to FALSE + * @pre To get the string sprintg functions you also need to define @p GFILE_NEED_STRINGS */ #ifndef GFILE_NEED_PRINTG #define GFILE_NEED_PRINTG FALSE @@ -53,15 +54,14 @@ /** * @brief Include scang, fscang etc functions * @details Defaults to FALSE + * @pre To get the string sscang functions you also need to define @p GFILE_NEED_STRINGS */ #ifndef GFILE_NEED_SCANG #define GFILE_NEED_SCANG FALSE #endif /** - * @brief Include the string sprintg/sscang functions + * @brief Include the string based file functions * @details Defaults to FALSE - * @pre To get sprintg functions you also need to define @p GFILE_NEED_PRINTG - * @pre To get sscang functions you also need to define @p GFILE_NEED_SCANG */ #ifndef GFILE_NEED_STRINGS #define GFILE_NEED_STRINGS FALSE @@ -146,6 +146,14 @@ #ifndef GFILE_NEED_MEMFS #define GFILE_NEED_MEMFS FALSE #endif + /** + * @brief Include support for file list functions + * @details Defaults to FALSE + * @note Adds support for @p gfileOpenFileList(), @p gfileReadFileList() and @p gfileCloseFileList(). + */ + #ifndef GFILE_NEED_FILELISTS + #define GFILE_NEED_FILELISTS FALSE + #endif /** * @} *