Jump to content

kengineer

Members
  • Posts

    79
  • Joined

  • Last visited

Everything posted by kengineer

  1. In the current implementation, during calibration, ugfx will attempt to open 2 calibration fonts. If either of these are missing, they will be replaced with a wildcard font open. In my particular case, this is problematic because I am not including the calibration font types and the wildcard font that gets opened happens to be a user font I've defined that isn't valid for displaying calibration text dialogs. I see two solutions to this: Add #defines to allow user to define calibration fonts 1 & 2 in gfxconf.h Add an api call to allow user to set default calibration fonts at runtime.
  2. I've found an issue with the online font converter (or maybe rather mcufont that is running on your server). I was trying to convert Dejavusans to a 32 size font sorted "0" - ":" characters however I've noticed you can also use "Numbers" filtering as well to reproduce the issue. The problem is when generated, the font structure contains an invalid value for "baseline x." It should be "2" but is actually outputting "-2." Since baseline is unsigned, this ends up being 254 and the result is the font doesn't display! I've attached the original ttf file for you to try as well. const struct mf_rlefont_s mf_rlefont_DejaVuSans32 = { { "DejaVu Sans Book 32", "DejaVuSans32", 17, /* width */ 23, /* height */ 20, /* min x advance */ 20, /* max x advance */ -2, /* baseline x */ 23, /* baseline y */ 37, /* line height */ 3, /* flags */ 32, /* fallback character */ &mf_rlefont_character_width, &mf_rlefont_render_character, }, 4, /* version */ mf_rlefont_DejaVuSans32_dictionary_data, mf_rlefont_DejaVuSans32_dictionary_offsets, 28, /* rle dict count */ 36, /* total dict count */ 1, /* char range count */ mf_rlefont_DejaVuSans32_char_ranges, }; DejaVuSans.ttf
  3. I will pull the changes and test them on my platform ASAP.
  4. I believe it may be defined by the FreeRTOS type StackType_t which is defined in the individual port of FreeRTOS. Looks like they get sizeof and multiply it by the stack depth passed when they malloc tasks for creation. This is defined is the tasks.c which is the generic (not platform specific) set of functions: //(tasks.c prvAllocateTCBAndStack function) /* Allocate space for the stack used by the task being created. The base of the stack memory stored in the TCB so the task can be deleted later if required. */ pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), puxStackBuffer ); In the port for my platform, this is defined and typedef'd as follows: #define portSTACK_TYPE uint32_t typedef portSTACK_TYPE StackType_t; Since each FreeRTOS port adjusts this type for the destination platform/compiler, I would think that using sizeof(StackType_t) would be sufficient.
  5. The xTaskCreate function is called in ugfx from the GOS layer when creating a thread. This function will be called to create the GTIMER thread with a default intended stack size of 2048 bytes. However, the usStackDepth as defined by FreeRTOS is: // usStackDepth - the stack size DEFINED IN WORDS. Which will be dependent on the platform and port base type size. On my current 32 bit Cortex-M0+ platform, passing a stack size of 2048 will actually allocate 8192 bytes on the FreeRTOS heap! I was wondering why ugfx was gobbling up so much memory in this thread. I have reduced this by defining the GTIMER_THREAD_WORKAREA_SIZE symbol as 512, however, just something to keep in mind as I'm sure this wasn't intended.
  6. Thank you for explaining that, makes sense.
  7. With wordwrap enabled for text/labels, I have found that spaces (and dashes) directly preceding an explicit line break character (like \n) will actually result in two lines breaks. This appears to be due to the following function: static bool is_wrap_space(uint16_t c) { return c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '-'; } I haven't dug into the use of this function but seems like it may be trying to determine if it is safe to break the line at this character (if necessary because of width). However, it means that if you have a space/dash and then a newline character, you will get two line breaks. See various cases below showing string and result: Case 1: Line break immediately follows non-space characters. Wrap reads a single line break. char x[] = "hello world\nA"; hello world A Case 2: Linebreak follows space character. Wrap interprets space as a line break as well resulting in two breaks. char x[] = "hello world \nA"; hello world A Case 3: Single character before line break (similar to case 1 but just showing the problem more clearly). char x[] = "hello world 1\nA"; hello world 1 A Case 4: Another character that is interpreted as an additional line break if preceding newline. char x[] = "hello world -\nA"; Hello world - A
  8. I just wanted to confirm my thoughts here. I am currently using uGFX 2.6 on a FreeRTOS system successfully. I was trying to make my application more portable and so wanted to use the gfxThreadCreate() function in place of xTaskCreate(). Since FreeRTOS init is not currently supported in uGFX, and according to the warning in uGFX "GOS: Operating System initialization has been turned off. Make sure you call vTaskStartScheduler() before gfxInit() in your application" and considering vTaskStartScheduler() does not normally return, I will need to create at least one task using xTaskCreate() (where gfxInit() will be called) and then I can create the others with gfxThreadCreate(). To clarify the statement, I must create my initial task that it initing uGFX the normal FreeRTOS way and then all other tasks can be created using the gfxThreadCreate() function. Please confirm if this statement is correct, thanks.
  9. Alright, I wrote some code that replicates it. Maybe this has something to do with calling the next event too quickly? Because in the main screen function if you replace time_immediate with the 1000 ms wait you won't see the bug. However with TIME_IMMEDIATE as soon as you jump to the next screen function if you observe the printfs you will see it does not wait anymore for an event as the event is return immediately. In this example eventBugExample in main #include "gfx.h" typedef enum { MAIN_SCREEN, SCREEN_A, SCREEN_B } SELECTED_SCREEN_t; static SELECTED_SCREEN_t selected_screen = MAIN_SCREEN; /* Function protos */ static void createWidgets(void); static void mainScreen(void); static void screenA(void); static void screenB(void); /* Container stuff */ static GHandle Container_Window_Handle; static GContainerObject Container_Window_Object; /* Button stuff */ static GHandle ButtonA_Handle, ButtonB_Handle, Back_Button_Handle; static GButtonObject ButtonA_Object, ButtonB_Object, Back_Button_Object; /* Event stuff */ static GListener gl; /* Event wait period */ #define EVENT_MAX_WAIT_MS 1000 static void createWidgets(void) { GWidgetInit wi; // Apply the container parameters gwinWidgetClearInit(&wi); wi.g.show = FALSE; wi.g.width = 320; wi.g.height = 240; wi.g.x = 0; wi.g.y = 0; Container_Window_Handle = gwinContainerCreate(&Container_Window_Object, &wi, 0); gwinWidgetClearInit(&wi); wi.g.show = FALSE; wi.g.width = 120; wi.g.height = 40; wi.text = "A"; wi.g.x = 100; wi.g.y = 20; wi.g.parent = Container_Window_Handle; ButtonA_Handle = gwinButtonCreate(&ButtonA_Object, &wi); gwinWidgetClearInit(&wi); wi.g.show = FALSE; wi.g.width = 120; wi.g.height = 40; wi.text = "B"; wi.g.x = 100; wi.g.y = 80; wi.g.parent = Container_Window_Handle; ButtonB_Handle = gwinButtonCreate(&ButtonB_Object, &wi); gwinWidgetClearInit(&wi); wi.g.show = FALSE; wi.g.width = 120; wi.g.height = 40; wi.text = "Back"; wi.g.x = 100; wi.g.y = 20; wi.g.parent = Container_Window_Handle; Back_Button_Handle = gwinButtonCreate(&Back_Button_Object, &wi); } void eventBugExample(void) { gfxInit(); // Set the widget defaults gwinSetDefaultFont(gdispOpenFont("*")); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); createWidgets(); /* Init and attach our listener to gwin system */ geventListenerInit(&gl); gwinAttachListener(&gl); gdispClear(White); /* Show our main window */ gwinShow(Container_Window_Handle); while(1) { /* Run through our screens */ switch(selected_screen) { case MAIN_SCREEN: { mainScreen(); break; } case SCREEN_A: { screenA(); break; } case SCREEN_B: { screenB(); break; } } } } static void mainScreen(void) { GEvent* pe; int flag = 0; gwinShow(ButtonA_Handle); gwinShow(ButtonB_Handle); printf("In main screen\n\r"); while(!flag) { pe = geventEventWait(&gl, TIME_IMMEDIATE); if(NULL != pe) { if(GEVENT_GWIN_BUTTON == pe->type) { if(((GEventGWinButton*)pe)->gwin == ButtonA_Handle) { selected_screen = SCREEN_A; printf("Selected screen A!\n\r"); flag = 1; } else if(((GEventGWinButton*)pe)->gwin == ButtonB_Handle) { selected_screen = SCREEN_B; printf("Selected screen B!\n\r"); flag = 1; } } } } gwinHide(ButtonA_Handle); gwinHide(ButtonB_Handle); } static void screenA(void) { GEvent* pe; int flag = 0; gwinShow(Back_Button_Handle); while(!flag) { printf("In screen A\n\r"); pe = geventEventWait(&gl, EVENT_MAX_WAIT_MS); if(NULL != pe) { if(GEVENT_GWIN_BUTTON == pe->type) { if(((GEventGWinButton*)pe)->gwin == Back_Button_Handle) { selected_screen = MAIN_SCREEN; printf("Go back to main!\n\r"); flag = 1; } } } } gwinHide(Back_Button_Handle); } static void screenB(void) { GEvent* pe; int flag = 0; gwinShow(Back_Button_Handle); while(!flag) { printf("In screen B\n\r"); pe = geventEventWait(&gl, EVENT_MAX_WAIT_MS); if(NULL != pe) { if(GEVENT_GWIN_BUTTON == pe->type) { if(((GEventGWinButton*)pe)->gwin == Back_Button_Handle) { selected_screen = MAIN_SCREEN; printf("Go back to main!\n\r"); flag = 1; } } } } gwinHide(Back_Button_Handle); }
  10. Sure I was thinking about doing that exactly, I'll get you one shortly.
  11. I also confirm that this exact issue happens on a WIN32 build as well.
  12. I noticed when building my application for WIN32 that at the bottom of the application window there are greyboxes that you can click. I'm guessing these are toggles since I have the GINPUT toggle option enabled. I've used these in an embedded application, but if these are toggles, how do I register and use them them (ginputGetToggle to get their handle) in this case? Do I need a different board file?
  13. Did you guys ever get a chance to look at this? Also, I noticed something that you should be doing in your examples for all GEVENT related functions: From button example: // Get an Event pe = geventEventWait(&gl, TIME_INFINITE); switch(pe->type) { case GEVENT_GWIN_BUTTON: if (((GEventGWinButton*)pe)->gwin == ghButton1) { // Our button has been pressed if (++which >= sizeof(orients)/sizeof(orients[0])) which = 0; // Setting the orientation during run-time is a bit naughty particularly with // GWIN windows. In this case however we know that the button is in the top-left // corner which should translate safely into any orientation. gdispSetOrientation(orients[which]); gdispClear(White); gwinRedrawDisplay(GDISP, FALSE); } from gEventWait: // Timeout - clear the waiting flag. // We know this is safe as any other thread will still think there is someone waiting. gfxMutexEnter(&geventMutex); pl->flags &= ~GLISTENER_WAITING; gfxMutexExit(&geventMutex); return 0; There's no check in the examples to see if pe is NULL. This probably wouldn't be a problem is that example since we're waiting forever (unless the event is busy like in the problem I'm having) however pe would definitely be NULL in the case of a timeout or immediate return. This doesn't crash on my embedded platform but I recently got this working on a WIN32 platform and switching on pe-type when pe is NULL does crash. I think you should add a check to your examples.
  14. Yes my display does support readback, I just haven't enabled it yet. Thanks for the advice.
  15. I was wondering if there was a good way to write the display to a bitmap file on FATFS. Seems like there could be several different ways to do this (pix maps which are then written to a file or a dedicated display driver that writes to a file) however I was wondering what the easiest way to do this would be.
  16. I'm using FreeRTOS. Yes I was trying to debug it but debugging a multithreaded system is hard enough let alone one I'm not familiar with. Looking forward to you reply, thanks!
  17. I find that at times the GLISTENER_WAITING flag is not being cleared and so the geventEventWait() call returns immediately. In my application, multiple functions are calling geventEventWait() however these functions are all on the same thread. I'm trying to track down the issue, but since I'm not super familiar with the inner workings of the event system just wanted to run this by you guys first and see if anything came to mind that would cause the flag not to be cleared other than calling geventEventWait() on the same listener from two different threads. Also, if the event system does get an event after waiting, what actually clears the waiting flag? (from geventEventWait) // No - wait for one. pl->flags &= ~GLISTENER_EVENTBUSY; // Event buffer is definitely not busy pl->flags |= GLISTENER_WAITING; // We will now be waiting on the thread gfxMutexExit(&geventMutex); if (gfxSemWait(&pl->waitqueue, timeout)) return &pl->event; The flag is set and if the semaphore is received during the wait period, how is it cleared as it immediately returns? Then when the wait function re-enters in another function, the flag is still set so it immediately returns. I see that this flag is cleared in some of the geventSendEvent() statements: (from geventSendEvent) if ((psl->pListener->flags & GLISTENER_WAITING)) { psl->pListener->flags &= ~(GLISTENER_WAITING|GLISTENER_PENDING); gfxSemSignal(&psl->pListener->waitqueue); } else psl->pListener->flags |= GLISTENER_PENDING; However as you can see there are cases in that statement where it is not cleared and I'm not familiar enough with the subsystem to make a good judgement on where or when it might not be getting cleared.
  18. Why does the gwinProgressbarDecrement() function decrement by both the resolution and the minimum? Shouldn't it be one or the other, and if anything I would think we would always decrement by the resolution and cap it at the min. This also will allow the progress bar to fall outside the min range as an additional decrement of the step always occurs no matter what not to mention that if I want to decrement by 1 normally it will always decrement more. void gwinProgressbarDecrement(GHandle gh) { #define gsw ((GProgressbarObject *)gh) if (gh->vmt != (gwinVMT *)&progressbarVMT) return; if (gsw->pos > gsw->res) gsw->pos -= gsw->min; else gsw->pos = gsw->min; gsw->pos -= gsw->res; PBResetDisplayPos(gsw); _gwinUpdate(gh); #undef gsw } I would think it should be something more like this: void gwinProgressbarDecrement(GHandle gh) { #define gsw ((GProgressbarObject *)gh) if (gh->vmt != (gwinVMT *)&progressbarVMT) return; if (gsw->pos > gsw->min) gsw->pos -= gsw->res; else gsw->pos = gsw->min; PBResetDisplayPos(gsw); _gwinUpdate(gh); #undef gsw } Please clarify if I'm not understanding the use of this correctly.
  19. I'm looking into using the GQUEUE system for an application with uGFX and wanted to hear your opinions of the best uses (examples) of queues vs. buffers (gfxbuffers). I'm looking for comparison of for operations that need to share data that occur on the same thread and operations in different threads as well as thread safety and advantages and disadvantages of each. In this specific use case I would be sharing data with two functions on the same thread but I could see needing other uses in the future so want to be sure I choose the right architecture. It seems that GQUEUES would maybe be a good choice as they have a lot more flexibility and options for multiple applications but wanted to hear opinions as this doesn't seem like a topic that's been explored very much by other users on the forums. Thanks!
  20. Just confirmed, so here's the fix: static bool mf_countline_callback(mf_str line, uint16_t count, void *state) { uint16_t *linecount = (uint16_t*)state; (*linecount)++; return TRUE; }
  21. I think I figured it out, there's a bug here. In mf_countline_callback, you are casting the void pointer as an int type which technically would vary by platform (int32_t on my platform). IF you go up a couple of function calls, you'll find: mf_wordwrap(font, cx, str, mf_countline_callback, &nbrLines); Where nbrLines is defined as a uint16_t. This is the problem, you're passing a uint16_t pointer in this case, and casting it as a 32 (at least on this platform) resulting in not incrementing the same part of memory we think we are. Upon modifying this, I don't get a hard fault anymore, so I'm going to see if the text wrap actually works now. Please verify this and move to the bug reports area.
  22. It seems that I'm getting some hard faults upon setting GDISP_NEED_TEXT_WORDWRAP to true. I'm still working on figuring out the exact cause, but it appears it's when I do anything related to drawing labels, specifically in this function call: static bool mf_countline_callback(mf_str line, uint16_t count, void *state) { int *linecount = (int*)state; (*linecount)++; return TRUE; } The fault specifically happens immediately after calling (*linecount)++; Still looking into this but was wondering if anyone had any advice. FYI I'm using uGFX v2.4
  23. Is there a function to check if a GFILE volume is mounted or list the current mounted volumes? I know I can just use a flag or something myself to do this but was wondering if there was any native functionality that already handled this.
×
×
  • Create New...