kengineer
Members-
Posts
79 -
Joined
-
Last visited
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
-
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.
-
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
-
Confirmed that this works on my platform.
-
I will pull the changes and test them on my platform ASAP.
-
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.
-
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.
-
Thank you for explaining that, makes sense.
-
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
-
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.
-
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); }
-
Sure I was thinking about doing that exactly, I'll get you one shortly.
-
I also confirm that this exact issue happens on a WIN32 build as well.
-
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?
-
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.
-
Yes my display does support readback, I just haven't enabled it yet. Thanks for the advice.