aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gfx_compilers.h1
-rw-r--r--src/gmisc/gmisc.h2
-rw-r--r--src/gos/gos_x_heap.c112
-rw-r--r--src/gos/gos_x_threads.c7
-rw-r--r--src/gos/gos_x_threads.h2
-rw-r--r--src/gos/gos_x_threads_cortexm01.h57
-rw-r--r--src/gos/gos_x_threads_cortexm347.h33
-rw-r--r--src/gos/gos_x_threads_cortexm47fp.h37
-rw-r--r--src/gtimer/gtimer.c2
-rw-r--r--src/gwin/gwin.c14
-rw-r--r--src/gwin/gwin.h34
11 files changed, 186 insertions, 115 deletions
diff --git a/src/gfx_compilers.h b/src/gfx_compilers.h
index 2449c05e..46d6c8b1 100644
--- a/src/gfx_compilers.h
+++ b/src/gfx_compilers.h
@@ -625,6 +625,7 @@
#pragma diag_remark 767 // Turn off warning: conversion from pointer to smaller integer
#pragma diag_remark 188 // Turn off warning: enumerated type mixed with another type
#pragma diag_remark 68 // Turn off warning: integer conversion resulted in a change of sign
+ #pragma diag_remark 111 // Turn off warning: statement is unreachable
#ifndef GFXINLINE // Get the Keil definition for inline
#define GFXINLINE __inline
#endif
diff --git a/src/gmisc/gmisc.h b/src/gmisc/gmisc.h
index f805345c..21178774 100644
--- a/src/gmisc/gmisc.h
+++ b/src/gmisc/gmisc.h
@@ -473,7 +473,7 @@ extern "C" {
* @note This function works both with convex and concave polygons
*
* @param[in] pntarray The array of points that form the polygon
- * @param[in] cnt The number of points in the point array @pntarray
+ * @param[in] cnt The number of points in the point array @p pntarray
* @param[in] p The point to test
*
* @return @p TRUE if the point @p p is inside or on the edge of the polygon @p pntarray, @p FALSE otherwise.
diff --git a/src/gos/gos_x_heap.c b/src/gos/gos_x_heap.c
index 7e79d1c6..813d0199 100644
--- a/src/gos/gos_x_heap.c
+++ b/src/gos/gos_x_heap.c
@@ -34,7 +34,6 @@
// Slot structure - user memory follows
typedef struct memslot {
- struct memslot *next; // The next memslot
size_t sz; // Includes the size of this memslot.
} memslot;
@@ -48,13 +47,10 @@
#define Ptr2Slot(p) ((memslot *)(p) - 1)
#define Slot2Ptr(pslot) ((pslot)+1)
- static memslot * firstSlot;
- static memslot * lastSlot;
static memslot * freeSlots;
static char heap[GFX_OS_HEAP_SIZE];
void _gosHeapInit(void) {
- lastSlot = 0;
gfxAddHeapBlock(heap, GFX_OS_HEAP_SIZE);
}
@@ -62,18 +58,12 @@
if (sz < sizeof(memslot)+sizeof(freeslot))
return;
- if (lastSlot)
- lastSlot->next = (memslot *)ptr;
- else
- firstSlot = lastSlot = freeSlots = (memslot *)ptr;
-
- lastSlot->next = 0;
- lastSlot->sz = sz;
- NextFree(lastSlot) = 0;
+ ((memslot *)ptr)->sz = sz;
+ gfxFree(Slot2Ptr((memslot *)ptr));
}
void *gfxAlloc(size_t sz) {
- register memslot *prev, *p, *new;
+ register memslot *prev, *p, *pnew;
if (!sz) return 0;
sz = GetSlotSize(sz);
@@ -81,23 +71,22 @@
// Loop till we have a block big enough
if (p->sz < sz)
continue;
+
// Can we save some memory by splitting this block?
if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
- new = (memslot *)((char *)p + sz);
- new->next = p->next;
- p->next = new;
- new->sz = p->sz - sz;
+ pnew = (memslot *)((char *)p + sz);
+ pnew->sz = p->sz - sz;
p->sz = sz;
- if (lastSlot == p)
- lastSlot = new;
- NextFree(new) = NextFree(p);
- NextFree(p) = new;
+ NextFree(pnew) = NextFree(p);
+ NextFree(p) = pnew;
}
+
// Remove it from the free list
if (prev)
NextFree(prev) = NextFree(p);
else
freeSlots = NextFree(p);
+
// Return the result found
return Slot2Ptr(p);
}
@@ -106,7 +95,7 @@
}
void *gfxRealloc(void *ptr, size_t oldsz, size_t sz) {
- register memslot *prev, *p, *new;
+ register memslot *prev, *p, *pfree;
(void) oldsz;
if (!ptr)
@@ -120,19 +109,14 @@
sz = GetSlotSize(sz);
// If the next slot is free (and contiguous) merge it into this one
- if ((char *)p + p->sz == (char *)p->next) {
- for (prev = 0, new = freeSlots; new != 0; prev = new, new = NextFree(new)) {
- if (new == p->next) {
- p->next = new->next;
- p->sz += new->sz;
- if (prev)
- NextFree(prev) = NextFree(new);
- else
- freeSlots = NextFree(new);
- if (lastSlot == new)
- lastSlot = p;
- break;
- }
+ for (prev = 0, pfree = freeSlots; pfree != 0; prev = pfree, pfree = NextFree(pfree)) {
+ if (pfree == (memslot *)((char *)p + p->sz)) {
+ p->sz += pfree->sz;
+ if (prev)
+ NextFree(prev) = NextFree(pfree);
+ else
+ freeSlots = NextFree(pfree);
+ break;
}
}
@@ -140,50 +124,54 @@
if (sz < p->sz) {
// Can we save some memory by splitting this block?
if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
- new = (memslot *)((char *)p + sz);
- new->next = p->next;
- p->next = new;
- new->sz = p->sz - sz;
+ pfree = (memslot *)((char *)p + sz);
+ pfree->sz = p->sz - sz;
p->sz = sz;
- if (lastSlot == p)
- lastSlot = new;
- NextFree(new) = freeSlots;
- freeSlots = new;
+ NextFree(pfree) = freeSlots;
+ freeSlots = pfree;
}
return Slot2Ptr(p);
}
// We need to do this the hard way
- new = gfxAlloc(sz);
- if (new)
+ pfree = gfxAlloc(sz);
+ if (pfree)
return 0;
- memcpy(new, ptr, p->sz - sizeof(memslot));
+ memcpy(pfree, ptr, p->sz - sizeof(memslot));
gfxFree(ptr);
- return new;
+ return pfree;
}
void gfxFree(void *ptr) {
- register memslot *prev, *p, *new;
+ register memslot *prev, *p, *pfree;
if (!ptr)
return;
p = Ptr2Slot(ptr);
- // If the next slot is free (and contiguous) merge it into this one
- if ((char *)p + p->sz == (char *)p->next) {
- for (prev = 0, new = freeSlots; new != 0; prev = new, new = NextFree(new)) {
- if (new == p->next) {
- p->next = new->next;
- p->sz += new->sz;
- if (prev)
- NextFree(prev) = NextFree(new);
- else
- freeSlots = NextFree(new);
- if (lastSlot == new)
- lastSlot = p;
- break;
- }
+ // Find a free slot that is contiguous precceding and merge it into us
+ for (prev = 0, pfree = freeSlots; pfree != 0; prev = pfree, pfree = NextFree(pfree)) {
+ if (p == (memslot *)((char *)pfree + pfree->sz)) {
+ pfree->sz += p->sz;
+ if (prev)
+ NextFree(prev) = NextFree(pfree);
+ else
+ freeSlots = NextFree(pfree);
+ p = pfree;
+ break;
+ }
+ }
+
+ // Find a free slot that is contiguous after and merge it into this one
+ for (prev = 0, pfree = freeSlots; pfree != 0; prev = pfree, pfree = NextFree(pfree)) {
+ if (pfree == (memslot *)((char *)p + p->sz)) {
+ p->sz += pfree->sz;
+ if (prev)
+ NextFree(prev) = NextFree(pfree);
+ else
+ freeSlots = NextFree(pfree);
+ break;
}
}
diff --git a/src/gos/gos_x_threads.c b/src/gos/gos_x_threads.c
index 7afd224a..b696ee77 100644
--- a/src/gos/gos_x_threads.c
+++ b/src/gos/gos_x_threads.c
@@ -122,6 +122,7 @@ void gfxSleepMilliseconds(delaytime_t ms) {
case TIME_INFINITE:
while(1)
gfxYield();
+ return;
}
// Convert our delay to ticks
@@ -143,6 +144,7 @@ void gfxSleepMicroseconds(delaytime_t ms) {
case TIME_INFINITE:
while(1)
gfxYield();
+ return;
}
// Convert our delay to ticks
@@ -212,12 +214,12 @@ static thread mainthread; // The main thread context
* If they don't exist compile them to be the standard setjmp() function.
* Similarly for longjmp().
*/
- #if (!defined(setjmp) && !defined(_setjmp)) || GFX_COMPILER == GFX_COMPILER_KEIL
+ #if (!defined(setjmp) && !defined(_setjmp)) || GFX_COMPILER == GFX_COMPILER_KEIL || GFX_COMPILER == GFX_COMPILER_MINGW32 || GFX_COMPILER == GFX_COMPILER_MINGW64
#define CXT_SAVE setjmp
#else
#define CXT_SAVE _setjmp
#endif
- #if (!defined(longjmp) && !defined(_longjmp)) || GFX_COMPILER == GFX_COMPILER_KEIL
+ #if (!defined(longjmp) && !defined(_longjmp)) || GFX_COMPILER == GFX_COMPILER_KEIL || GFX_COMPILER == GFX_COMPILER_MINGW32 || GFX_COMPILER == GFX_COMPILER_MINGW64
#define CXT_RESTORE longjmp
#else
#define CXT_RESTORE _longjmp
@@ -346,6 +348,7 @@ static thread mainthread; // The main thread context
uint32_t i;
// Copy the stack frame
+ s = 0;
#if AUTO_DETECT_STACKFRAME
if (STACK_DIR_UP) { // Stack grows up
nf = (char *)(t) + sizeof(thread) + sizeof(jmp_buf) + STACK_BASE;
diff --git a/src/gos/gos_x_threads.h b/src/gos/gos_x_threads.h
index ee7a9cd0..585585c5 100644
--- a/src/gos/gos_x_threads.h
+++ b/src/gos/gos_x_threads.h
@@ -90,7 +90,7 @@ extern "C" {
threadreturn_t gfxThreadWait(gfxThreadHandle thread);
gfxThreadHandle gfxThreadMe(void);
- /** The following is not part of the public ugfx API has some operating systems
+ /** The following is not part of the public ugfx API as some operating systems
* simply do not provide this capability.
* For RAW32 we need it anyway so we might as well declare it here.
*/
diff --git a/src/gos/gos_x_threads_cortexm01.h b/src/gos/gos_x_threads_cortexm01.h
index 8a44bd35..15a90b2a 100644
--- a/src/gos/gos_x_threads_cortexm01.h
+++ b/src/gos/gos_x_threads_cortexm01.h
@@ -27,8 +27,10 @@
"mov r6, r10 \n\t"
"mov r7, r11 \n\t"
"push {r4, r5, r6, r7} \n\t"
- "str sp, %[oldtcxt] \n\t"
- "ldr sp, %[newtcxt] \n\t"
+ "mov r4, sp \n\t"
+ "str r4, %[oldtcxt] \n\t"
+ "ldr r4, %[newtcxt] \n\t"
+ "mov sp, r4 \n\t"
"pop {r4, r5, r6, r7} \n\t"
"mov r8, r4 \n\t"
"mov r9, r5 \n\t"
@@ -41,15 +43,17 @@
}
static __attribute__((pcs("aapcs"),naked)) void _gfxStartThread(thread *oldt, thread *newt) {
- newt->cxt = (char *)newt + newt->size;
+ newt->cxt = (void *)(((unsigned)newt + newt->size) & ~7);
__asm__ volatile ( "push {r4, r5, r6, r7, lr} \n\t"
"mov r4, r8 \n\t"
"mov r5, r9 \n\t"
"mov r6, r10 \n\t"
"mov r7, r11 \n\t"
"push {r4, r5, r6, r7} \n\t"
- "str sp, %[oldtcxt] \n\t"
- "ldr sp, %[newtcxt] \n\t"
+ "mov r4, sp \n\t"
+ "str r4, %[oldtcxt] \n\t"
+ "ldr r4, %[newtcxt] \n\t"
+ "mov sp, r4 \n\t"
: [newtcxt] "=m" (newt->cxt)
: [oldtcxt] "m" (oldt->cxt)
: "memory");
@@ -59,8 +63,12 @@
}
#elif GFX_COMPILER == GFX_COMPILER_KEIL || GFX_COMPILER == GFX_COMPILER_ARMCC
+ #define GFX_THREADS_DONE
+ #define _gfxThreadsInit()
static __asm void _gfxTaskSwitch(thread *oldt, thread *newt) {
+ PRESERVE8
+
// Save the old context
push {r4, r5, r6, r7, lr}
mov r4, r8
@@ -68,10 +76,12 @@
mov r6, r10
mov r7, r11
push {r4, r5, r6, r7}
- str sp, [r0,#__cpp(offsetof(thread,cxt))] // oldt->cxt
+ mov r4, sp
+ str r4, [r0,#__cpp(offsetof(thread,cxt))] // oldt->cxt
// Load the new context
- ldr sp, [r1,#__cpp(offsetof(thread,cxt))] // newt->cxt
+ ldr r4, [r1,#__cpp(offsetof(thread,cxt))] // newt->cxt
+ mov sp, r4
pop {r4, r5, r6, r7}
mov r8, r4
mov r9, r5
@@ -81,11 +91,14 @@
}
static __asm void _gfxStartThread(thread *oldt, thread *newt) {
+ PRESERVE8
+
// Calculate where to generate the new context
- // newt->cxt = (char *)newt + newt->size;
- ldr r2,[r1,#__cpp(offsetof(thread,size))]
- add r2,r2,r1
- str r2,[r1,#__cpp(offsetof(thread,cxt))]
+ // newt->cxt = (void *)(((unsigned)newt + newt->size) & ~7);
+ ldr r2,[r1,#__cpp(offsetof(thread,size))]
+ add r2,r2,r1
+ and r2, r2, #0xFFFFFFF8
+ str r2,[r1,#__cpp(offsetof(thread,cxt))]
// Save the old context
push {r4, r5, r6, r7, lr}
@@ -94,20 +107,24 @@
mov r6, r10
mov r7, r11
push {r4, r5, r6, r7}
- str sp, [r0,#__cpp(offsetof(thread,cxt))] // oldt->cxt
+ mov r4, sp
+ str r4, [r0,#__cpp(offsetof(thread,cxt))] // oldt->cxt
// Load the new (imcomplete) context
- ldr sp, [r1,#__cpp(offsetof(thread,cxt))] // newt->cxt
+ ldr r4, [r1,#__cpp(offsetof(thread,cxt))] // newt->cxt
+ mov sp, r4
// Run the users function - we save some code because gfxThreadExit() never returns
// gfxThreadExit(_gfxCurrentThread->fn(_gfxCurrentThread->param));
- LDR r2,__cpp(&_gfxCurrentThread)
- LDR r2,[r2,#0]
- LDR r0,[r2,#__cpp(offsetof(thread,param))]
- LDR r1,[r2,#__cpp(offsetof(thread,fn))]
- BLX r1
- MOV r4,r0
- BL gfxThreadExit
+ ldr r2,=__cpp(&_gfxCurrentThread)
+ ldr r2,[r2,#0]
+ ldr r0,[r2,#__cpp(offsetof(thread,param))]
+ ldr r1,[r2,#__cpp(offsetof(thread,fn))]
+ blx r1
+ mov r4,r0
+ bl __cpp(gfxThreadExit)
+
+ ALIGN
}
#else
diff --git a/src/gos/gos_x_threads_cortexm347.h b/src/gos/gos_x_threads_cortexm347.h
index 03c13052..40d30138 100644
--- a/src/gos/gos_x_threads_cortexm347.h
+++ b/src/gos/gos_x_threads_cortexm347.h
@@ -32,7 +32,7 @@
}
static __attribute__((pcs("aapcs"),naked)) void _gfxStartThread(thread *oldt, thread *newt) {
- newt->cxt = (char *)newt + newt->size;
+ newt->cxt = (void *)(((unsigned)newt + newt->size) & ~7);
__asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t"
"str sp, %[oldtcxt] \n\t"
"ldr sp, %[newtcxt] \n\t"
@@ -45,8 +45,12 @@
}
#elif GFX_COMPILER == GFX_COMPILER_KEIL || GFX_COMPILER == GFX_COMPILER_ARMCC
+ #define GFX_THREADS_DONE
+ #define _gfxThreadsInit()
static __asm void _gfxTaskSwitch(thread *oldt, thread *newt) {
+ PRESERVE8
+
// Save the old context
push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
str sp, [r0,#__cpp(offsetof(thread,cxt))] // oldt->cxt
@@ -57,11 +61,14 @@
}
static __asm void _gfxStartThread(thread *oldt, thread *newt) {
+ PRESERVE8
+
// Calculate where to generate the new context
- // newt->cxt = (char *)newt + newt->size;
- ldr r2,[r1,#__cpp(offsetof(thread,size))]
- add r2,r2,r1
- str r2,[r1,#__cpp(offsetof(thread,cxt))]
+ // newt->cxt = (void *)(((unsigned)newt + newt->size) & ~7);
+ ldr r2,[r1,#__cpp(offsetof(thread,size))]
+ add r2,r2,r1
+ and r2, r2, #0xFFFFFFF8
+ str r2,[r1,#__cpp(offsetof(thread,cxt))]
// Save the old context
push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
@@ -72,13 +79,15 @@
// Run the users function - we save some code because gfxThreadExit() never returns
// gfxThreadExit(_gfxCurrentThread->fn(_gfxCurrentThread->param));
- LDR r2,__cpp(&_gfxCurrentThread)
- LDR r2,[r2,#0]
- LDR r0,[r2,#__cpp(offsetof(thread,param))]
- LDR r1,[r2,#__cpp(offsetof(thread,fn))]
- BLX r1
- MOV r4,r0
- BL gfxThreadExit
+ ldr r2,=__cpp(&_gfxCurrentThread)
+ ldr r2,[r2,#0]
+ ldr r0,[r2,#__cpp(offsetof(thread,param))]
+ ldr r1,[r2,#__cpp(offsetof(thread,fn))]
+ blx r1
+ mov r4,r0
+ bl __cpp(gfxThreadExit)
+
+ ALIGN
}
#else
diff --git a/src/gos/gos_x_threads_cortexm47fp.h b/src/gos/gos_x_threads_cortexm47fp.h
index 9767ac9a..f5eeff80 100644
--- a/src/gos/gos_x_threads_cortexm47fp.h
+++ b/src/gos/gos_x_threads_cortexm47fp.h
@@ -12,10 +12,6 @@
* The context is saved at the current stack location and a pointer is maintained in the thread structure.
*/
-#if !CORTEX_USE_FPU
- #warning "GOS Threads: You have specified GFX_CPU=GFX_CPU_CORTX_M?_FP with hardware floating point support but CORTEX_USE_FPU is FALSE. Try using GFX_CPU_GFX_CPU_CORTEX_M? instead"
-#endif
-
#if GFX_COMPILER == GFX_COMPILER_GCC || GFX_COMPILER == GFX_COMPILER_CYGWIN || GFX_COMPILER == GFX_COMPILER_MINGW32 || GFX_COMPILER == GFX_COMPILER_MINGW64
#define GFX_THREADS_DONE
#define _gfxThreadsInit()
@@ -33,7 +29,7 @@
}
static __attribute__((pcs("aapcs-vfp"),naked)) void _gfxStartThread(thread *oldt, thread *newt) {
- newt->cxt = (char *)newt + newt->size;
+ newt->cxt = (void *)(((unsigned)newt + newt->size) & ~7);
__asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t"
"vpush {s16-s31} \n\t"
"str sp, %[oldtcxt] \n\t"
@@ -47,8 +43,12 @@
}
#elif GFX_COMPILER == GFX_COMPILER_KEIL || GFX_COMPILER == GFX_COMPILER_ARMCC
+ #define GFX_THREADS_DONE
+ #define _gfxThreadsInit()
static __asm void _gfxTaskSwitch(thread *oldt, thread *newt) {
+ PRESERVE8
+
// Save the old context
push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
vpush {s16-s31}
@@ -61,11 +61,14 @@
}
static __asm void _gfxStartThread(thread *oldt, thread *newt) {
+ PRESERVE8
+
// Calculate where to generate the new context
- // newt->cxt = (char *)newt + newt->size;
- ldr r2,[r1,#__cpp(offsetof(thread,size))]
- add r2,r2,r1
- str r2,[r1,#__cpp(offsetof(thread,cxt))]
+ // newt->cxt = (void *)(((unsigned)newt + newt->size) & ~7);
+ ldr r2,[r1,#__cpp(offsetof(thread,size))]
+ add r2,r2,r1
+ and r2, r2, #0xFFFFFFF8
+ str r2,[r1,#__cpp(offsetof(thread,cxt))]
// Save the old context
push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
@@ -77,13 +80,15 @@
// Run the users function - we save some code because gfxThreadExit() never returns
// gfxThreadExit(_gfxCurrentThread->fn(_gfxCurrentThread->param));
- LDR r2,__cpp(&_gfxCurrentThread)
- LDR r2,[r2,#0]
- LDR r0,[r2,#__cpp(offsetof(thread,param))]
- LDR r1,[r2,#__cpp(offsetof(thread,fn))]
- BLX r1
- MOV r4,r0
- BL gfxThreadExit
+ ldr r2,=__cpp(&_gfxCurrentThread)
+ ldr r2,[r2,#0]
+ ldr r0,[r2,#__cpp(offsetof(thread,param))]
+ ldr r1,[r2,#__cpp(offsetof(thread,fn))]
+ blx r1
+ mov r4,r0
+ bl __cpp(gfxThreadExit)
+
+ ALIGN
}
#else
diff --git a/src/gtimer/gtimer.c b/src/gtimer/gtimer.c
index eda88d5a..22ec9ed2 100644
--- a/src/gtimer/gtimer.c
+++ b/src/gtimer/gtimer.c
@@ -109,7 +109,7 @@ static DECLARE_THREAD_FUNCTION(GTimerThreadHandler, arg) {
lastTime = tm;
gfxMutexExit(&mutex);
}
-// THREAD_RETURN(0);
+ THREAD_RETURN(0);
}
void _gtimerInit(void)
diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c
index 586636ec..c5082ea0 100644
--- a/src/gwin/gwin.c
+++ b/src/gwin/gwin.c
@@ -281,6 +281,14 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
}
#endif
+#if GDISP_NEED_DUALCIRCLE
+ void gwinFillDualCircle(GHandle gh, coord_t x, coord_t y, coord_t radius1, coord_t radius2) {
+ if (!_gwinDrawStart(gh)) return;
+ gdispGFillDualCircle(gh->display, gh->x+x, gh->y+y, radius1, gh->bgcolor, radius2, gh->color);
+ _gwinDrawEnd(gh);
+ }
+#endif
+
#if GDISP_NEED_ELLIPSE
void gwinDrawEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) {
if (!_gwinDrawStart(gh)) return;
@@ -307,6 +315,12 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
gdispGFillArc(gh->display, gh->x+x, gh->y+y, radius, startangle, endangle, gh->color);
_gwinDrawEnd(gh);
}
+
+ void gwinDrawThickArc(GHandle gh, coord_t x, coord_t y, coord_t startradius, coord_t endradius, coord_t startangle, coord_t endangle) {
+ if (!_gwinDrawStart(gh)) return;
+ gdispGDrawThickArc(gh->display, gh->x+x, gh->y+y, startradius, endradius, startangle, endangle, gh->color);
+ _gwinDrawEnd(gh);
+ }
#endif
#if GDISP_NEED_ARCSECTORS
diff --git a/src/gwin/gwin.h b/src/gwin/gwin.h
index 5912046b..c3d18c31 100644
--- a/src/gwin/gwin.h
+++ b/src/gwin/gwin.h
@@ -718,6 +718,24 @@ extern "C" {
void gwinFillCircle(GHandle gh, coord_t x, coord_t y, coord_t radius);
#endif
+ #if GDISP_NEED_DUALCIRCLE || defined(__DOXYGEN__)
+ /**
+ * @brief Draw two filled circles with the same centre in the window.
+ * @note Uses the current foreground color to draw the inner circle
+ * @note Uses the current background color to draw the outer circle
+ * @note May leave GDISP clipping to this window's dimensions
+ * @pre GDISP_NEED_DUALCIRCLE must be TRUE in your gfxconf.h
+ *
+ * @param[in] gh The window handle
+ * @param[in] x,y The center of the circle
+ * @param[in] radius1 The radius of the larger circle
+ * @param[in] radius2 The radius of the smaller circle
+ *
+ * @api
+ */
+ void gwinFillDualCircle(GHandle gh, coord_t x, coord_t y, coord_t radius1, coord_t radius2);
+ #endif
+
#if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__)
/**
* @brief Draw an ellipse.
@@ -776,6 +794,22 @@ extern "C" {
* @api
*/
void gwinFillArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle);
+
+ /*
+ * @brief Draw a thick arc in the window.
+ * @note Uses the current foreground color to draw the thick arc
+ * @note May leave GDISP clipping to this window's dimensions
+ *
+ * @param[in] gh The window handle
+ * @param[in] x,y The center point
+ * @param[in] startradius The inner radius of the thick arc
+ * @param[in] endradius The outer radius of the thick arc
+ * @param[in] startangle The start angle (0 to 360)
+ * @param[in] endangle The end angle (0 to 360)
+ *
+ * @api
+ */
+ void gwinDrawThickArc(GHandle gh, coord_t x, coord_t y, coord_t startradius, coord_t endradius, coord_t startangle, coord_t endangle);
#endif
#if GDISP_NEED_ARCSECTORS || defined(__DOXYGEN__)