Alan Chang Posted October 11, 2017 Report Share Posted October 11, 2017 Hello, I want to use a small area of the screen to show the information menu. User can switch the different information by a hardware button. Is it a good way to use "console"? Here is my "console" code. GHandle ghMode1; void Mode1Infom(void) { GWindowInit wi1; gwinClearInit(&wi1); // create console windows: ghMode1 wi1.show = TRUE; wi1.x = 0; wi1.y = 140; wi1.width = 240; wi1.height = 24; ghMode1 = gwinConsoleCreate(0, &wi1); gwinSetFont(ghMode1, font1); gwinSetColor(ghMode1, Green); gwinSetBgColor(ghMode1, Red); } void guiShowMode(unsigned pageIndex) { gwinClear(ghMode1); switch (pageIndex) { case 1: gwinPrintf(ghMode1, "Hello1 123\n"); break; case 2: gwinPrintf(ghMode1, "Hello2 456\n"); break; } Then attach toogle. gwinAttachToggle(ghMode1, 0, 0); Is this code OK? Also what is the event type for "console"? Please give me some suggestion. Thanks. Link to comment Share on other sites More sharing options...
Alan Chang Posted October 11, 2017 Author Report Share Posted October 11, 2017 Hello, I found a video which I want to do for reference. https://www.youtube.com/watch?v=9dCVJIUPspM Thanks. Link to comment Share on other sites More sharing options...
Joel Bodenmann Posted October 11, 2017 Report Share Posted October 11, 2017 Using the console widget is definitely a bad choice in any case. The console widget is not really meant for text that changes, labels are more suited for that. The console widget doesn't generate any events (in developer terms it's a window, not a widget). For this kind of thing you usually want to implement a custom widget (unless a label is enough, which it seems to be the case here so far). Link to comment Share on other sites More sharing options...
Alan Chang Posted October 12, 2017 Author Report Share Posted October 12, 2017 Hi Joel, Thanks for your reply. I will try to use the custom widget. Thanks. Link to comment Share on other sites More sharing options...
Joel Bodenmann Posted October 12, 2017 Report Share Posted October 12, 2017 I hope you found the documentation: https://wiki.ugfx.io/index.php/Creating_a_widget Link to comment Share on other sites More sharing options...
Alan Chang Posted October 13, 2017 Author Report Share Posted October 13, 2017 Hi Joel, Thanks for your information. If I need to use hardware button to control my custom widget, should I use " gwinAttachToggle" to assign? There will be many pages in my custom widget, and I want to change the page by a hardware button. Thanks. Link to comment Share on other sites More sharing options...
Joel Bodenmann Posted October 13, 2017 Report Share Posted October 13, 2017 Hello Alan, Yes, that is exactly correct! You use gwinAttachToggle() to attach your hardware button to the widget and inside your custom widget you can add the functions to handle the toggle input in the VMT as described in the wiki. Link to comment Share on other sites More sharing options...
Alan Chang Posted October 16, 2017 Author Report Share Posted October 16, 2017 Hi Joel, I am creating my custom widget. When I make a gwidgetVMT, I can not understand something. How does the widget get the toogle (hardware button) status? I refer to the gwin_button.c. I found "ButtonToggleOn". static void ButtonToggleOn(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags |= GBUTTON_FLG_PRESSED; _gwinUpdate((GHandle)gw); // Trigger the event on button down (different than for mouse/touch) _gwinSendEvent(&gw->g, GEVENT_GWIN_BUTTON); } Is the toggle status saved in "gw->g.flags"? And is this status from "ginputGetToggle()" in the ginput_toggle.c file? Hope you can understand my question. Thanks. Link to comment Share on other sites More sharing options...
Joel Bodenmann Posted October 16, 2017 Report Share Posted October 16, 2017 Hello Alan, The gwidgetVMT allows you to register functions for the following toggle events (copied from the documentation): uint16_t toggleroles; /**< The roles supported for toggles (0->toggleroles-1) */ void (*ToggleAssign) (GWidgetObject *gw, uint16_t role, uint16_t instance); /**< Assign a toggle to a role (optional) */ uint16_t (*ToggleGet) (GWidgetObject *gw, uint16_t role); /**< Return the instance for a particular role (optional) */ void (*ToggleOff) (GWidgetObject *gw, uint16_t role); /**< Process toggle off events (optional) */ void (*ToggleOn) (GWidgetObject *gw, uint16_t role); /**< Process toggle on events (optional) */ The toggle status is not saved in gw->g.flags. A toggle can have two states: on and off (true or false, 1 or 0, ...). You get a call to ToggleOn() and ToggleOff() accordingly. It's up to you as a developer to decide what to do with that information afterwards. In case of the existing pushbutton widget we just change the internal flag of the pushbutton that keeps track of the pressed/unpressed state. But in your widget you do whatever you think is best. ToggleOn() and ToggleOff() just inform you that the state of the toggle (the hardware button) changed. The rest is up to you. Link to comment Share on other sites More sharing options...
Alan Chang Posted October 17, 2017 Author Report Share Posted October 17, 2017 Hi Joel, Thanks for your explanation. But I still do not know how the "on" state of hardware button pass to the widget. In other words, how does the widget get the "on" state and start ToggleOn() ? Hope you can explain. Thanks. Link to comment Share on other sites More sharing options...
Joel Bodenmann Posted October 17, 2017 Report Share Posted October 17, 2017 You need to attach the toggle to the widget by using gwinAttachToggle(). Have a look at the API reference and /demos/modules/gwin/widgets. Link to comment Share on other sites More sharing options...
Alan Chang Posted October 17, 2017 Author Report Share Posted October 17, 2017 Hello Joel, Thanks for your information. I think my custom widget has some issue and can not be attached well with gwinAttachToggle(). There is no response when executed, so I traced the code. I found this part is always be "TRUE". bool_t gwinAttachToggle(GHandle gh, uint16_t role, uint16_t instance) { ... if (instance == oi) return TRUE; ... } However, I tried to create a win button(gwinButtonCreate()), and check the oi value. It is always have a value which is 65535. I think the value of oi is given here. oi = wvmt->ToggleGet(gw, role); static uint16_t ButtonToggleGet(GWidgetObject *gw, uint16_t role) { (void) role; return ((GButtonObject *)gw)->toggle; } When is the value put in "((GButtonObject *)gw)->toggle" ? Here is my widget VMT. static const gwidgetVMT modeVMT = { { //gwindowVMT g part start------ "Mode", // The classname sizeof(ModeObject), // The object size _gwidgetDestroy, // The destroy routine _gwidgetRedraw, // The redraw routine 0, // The after-clear routine }, //gwindowVMT g part end------ modeDraw_Default, // The default drawing routine #if GINPUT_NEED_MOUSE { 0, // Process mouse down events 0, // Process mouse up events 0, // Process mouse move events }, #endif #if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD { 0 // Process keyboard events }, #endif #if GINPUT_NEED_TOGGLE { 1, // Toggle role uModeToggleAssign, // Assign Toggles uModeToggleGet, // Get Toggles 0, // Process toggle off events uModeToggleOn, // Process toggle on events }, #endif #if GINPUT_NEED_DIAL { 0, // No dial roles 0, // Assign Dials 0, // Get Dials 0, // Process dial move events }, #endif }; and static void uModeToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) { (void) role; ((ModeObject *)gw)->toggle = instance; } static uint16_t uModeToggleGet(GWidgetObject *gw, uint16_t role) { (void) role; return ((ModeObject *)gw)->toggle; } Is anything wrong in my code? Please help. Thanks. Link to comment Share on other sites More sharing options...
Alan Chang Posted October 25, 2017 Author Report Share Posted October 25, 2017 Hello, I used gwinAttachToggle to assign the toggle for my widget. When the hardware button is pressed, the listener will receive an event and call "the page change" function. I use the geventEventWait to wait the event. pe = geventEventWait(&_glistener, TIME_INFINITE); However, this function only keeps waiting an event. If I do not press the button, I want the information of current page can continue update. Also wait for the event at same. What can I do in my code? Thanks. Link to comment Share on other sites More sharing options...
Joel Bodenmann Posted October 25, 2017 Report Share Posted October 25, 2017 Hello Alan, I'm not sure whether you want a custom widget to receive & handle the toggle or whether you just want a generic toggle event in your applications event processing loop. Can you please clarify this? Did you properly use gwinAttachToggle() to attach the toggle to your custom widget? Did you check for the return value of that function? It returns FALSE if attaching failed. Note that pressing the toggle will not generate an event that you receive through the regular geventEventWait() setup. Your widget's toggle handling functions will be called. You can process the toggle event there and if you like you can create an event there. Did you make sure that your toggle board file is correct? I'd recommend you to properly debug this by setting breakpoints in the corresponding functions. Link to comment Share on other sites More sharing options...
inmarket Posted October 25, 2017 Report Share Posted October 25, 2017 The 2nd parameter to geventEventWait is a timeout. You can specify a timeout in milliseconds for geventEventWait to wait for an event. If it hasn't found an event during that time it returns NULL rather than the event pointer. By placing geventEventWait in a loop with a suitable timeout period, and by handling the NULL that can now be returned, you can now do other things as well in the loop. Link to comment Share on other sites More sharing options...
inmarket Posted October 25, 2017 Report Share Posted October 25, 2017 Another way is to create a separate thread to run other tasks; or put geventEventWait into the new thread and use the main thread to do your other tasks. If you use this thread approach and are using a cooperative schedular (like in the RAW32 or Arduino ports) don't forget to run gfxYield periodically to give other threads a chance to run. Link to comment Share on other sites More sharing options...
Alan Chang Posted October 26, 2017 Author Report Share Posted October 26, 2017 Hi guys , Very thanks for your information. My application will be similar like this video. https://www.youtube.com/watch?v=9dCVJIUPspM I designed my custom widget for these two things below. 1. Change pages by a hardware button. 2. Show the latest information in every page. So it will be always updates the data. I tested the gwinAttachToggle() and there was no FALSE returned. The pages can be changed. So I think toggle is working with my custom widget well. Now if I do not change page, the information of this present page still need to update all the time. Just when I tried to update the information, the loop was blocked in geventEventWait. It was waiting for the toggle event. However, I think I can not set a specific time in geventEventWait. Because I do not know when the user press the hardware button, and some information like clock and clock can be really changed very quickly. Is there any return value of some API which I can handle during the geventEventWait loop? Or I only can solve by create a new thread. Hope you can give me some suggestion. By the way, I am using FreeRTOS. Thank you. Link to comment Share on other sites More sharing options...
Joel Bodenmann Posted October 26, 2017 Report Share Posted October 26, 2017 Hello Alan, For things like this, you can use a software timer. The GTIMER module provides those. They are extremely simple to use: Write your function, create a GTIMER object and specify the interval --> https://wiki.ugfx.io/index.php/GTIMER Software timers are less flexible and less precise than threads. However, for things like updating the UI they are usually more than sufficient. If you feel like that's not the case, then go straight for a dedicated thread. There are demos on how to create threads with the µGFX API (gfxThreadCreate()). µGFX will directly use the underlying threads provided by FreeRTOS in your case. Link to comment Share on other sites More sharing options...
Alan Chang Posted October 27, 2017 Author Report Share Posted October 27, 2017 Hi Joel, Thanks for your suggestion. I will try them. Thanks. Link to comment Share on other sites More sharing options...
Alan Chang Posted November 2, 2017 Author Report Share Posted November 2, 2017 Hi Joel, Can I build two "gtimerStart" functions at same time? Like this. gtimerStart(>imer_Demo, auto_Demo, 0, TRUE, AUTO_DEMO_INTERVAL); gtimerStart(>imer_UpdateItem, updateModeItem, 0, TRUE, UPDATE_ITEM_INTERVAL); Now when I executed this program, the second one did not work. Thanks. Link to comment Share on other sites More sharing options...
Joel Bodenmann Posted November 2, 2017 Report Share Posted November 2, 2017 Hello Alan, Yes, you can have as many running GTimers as you want (it's fine to have two gtimerStart()). However, don't forget to call gtimerInit() on each GTimer object. It should look like this: GTimer gtimer_Demo; GTimer gtimer_UpdateItem; gtimerInit(>imer_Demo); gtimerInit(>imer_UpdateItem); gtimerStart(>imer_Demo, auto_Demo, 0, TRUE, AUTO_DEMO_INTERVAL); gtimerStart(>imer_UpdateItem, updateModeItem, 0, TRUE, UPDATE_ITEM_INTERVAL); Did you do that? If this was not the problem: How did you check that the second one didn't work? Keep in mind that unlike threads, all GTimers are executed in one thread (the thread internally created & maintained by the GTIMER module). Each GTimer instance will run on the same stack and the same priority. So make sure that GTIMER_THREAD_WORKAREA_SIZE is set accordingly. Link to comment Share on other sites More sharing options...
Alan Chang Posted November 2, 2017 Author Report Share Posted November 2, 2017 Hi Joel, Thanks for your quick reply. And Yes, I did the function code same as yours below when used the gtimer. GTimer gtimer_Demo; GTimer gtimer_UpdateItem; gtimerInit(>imer_Demo); gtimerInit(>imer_UpdateItem); gtimerStart(>imer_Demo, auto_Demo, 0, TRUE, AUTO_DEMO_INTERVAL); gtimerStart(>imer_UpdateItem, updateModeItem, 0, TRUE, UPDATE_ITEM_INTERVAL); How did you check that the second one didn't work? ==> I used "printf()" in the call back function to output a simple message on PuTTY for debug. And there is no output in second "gtimerStart()". In gfxconf.h the GTIMER configuration is below. /////////////////////////////////////////////////////////////////////////// // GTIMER // /////////////////////////////////////////////////////////////////////////// #define GFX_USE_GTIMER TRUE #define GTIMER_THREAD_PRIORITY HIGH_PRIORITY #define GTIMER_THREAD_WORKAREA_SIZE 2048 Is there any issue? Thanks. Link to comment Share on other sites More sharing options...
Joel Bodenmann Posted November 2, 2017 Report Share Posted November 2, 2017 Can you please show us the implementation of auto_Demo() and updateModeItem()? Also, what's the value of UPDATE_ITEM_INTERVAL? Link to comment Share on other sites More sharing options...
Alan Chang Posted November 3, 2017 Author Report Share Posted November 3, 2017 Hi Joel, The autoDemo() function actually is from the part of the dial widget example. And I add the digital number ICON display function which is display3DigitalNumber(). The updateModeItem() is for update the clock. void autoDemo(void) { uint16_t dialAngle = dialGetAngle(ghDial); printf("456"); //alan test display3DigitalNumber(150); gfxSleepMilliseconds(80); display3DigitalNumber(151); gfxSleepMilliseconds(80); // Increment the dial position and handle overflows if (dialAngle >= 180) { dialAngle = 0; } else { dialAngle++; } // Apply the new dial needle position dialSetAngle(ghDial, dialAngle); } void updateModeItem(void) { printf("123"); //alan test modeClockUpdate(); //update clock } Then I used gtimeStart() to call them. gtimerStart(>imer_Demo, auto_Demo, 0, TRUE, AUTO_DEMO_INTERVAL); gtimerStart(>imer_UpdateItem, updateModeItem, 0, TRUE, UPDATE_ITEM_INTERVAL); The video of the result is blow. MOV_0365.mp4 Today I found this. If I deleted the code in the autoDemo(). //display3DigitalNumber(150); //gfxSleepMilliseconds(80); //display3DigitalNumber(151); //gfxSleepMilliseconds(80); Every thing works well. MOV_0369.mp4 The display3DigitalNumber() is built by the gdispImageOpenFile(), gdispImageDraw() and gdispImageClose(). Such as this. switch (number){ case 0: gdispImageOpenFile(&_Digtal_num0, "rsc/P0_48x68.bmp"); gdispImageDraw(&_Digtal_num0, p_x, p_y, gdispGetWidth(),gdispGetHeight(), 0, 0); //show image file gdispImageClose(&_Digtal_num0); break; case 1: gdispImageOpenFile(&_Digtal_num1, "rsc/P1_48x68.bmp"); gdispImageDraw(&_Digtal_num1, p_x, p_y, gdispGetWidth(),gdispGetHeight(), 0, 0); //show image file gdispImageClose(&_Digtal_num1); break; Will it delay the timer when open the image file? How can I solve this? By the way, the UPDATE_ITEM_INTERVAL means the interal time to update the clock for my custom widget. I set 100 here. Thanks. Link to comment Share on other sites More sharing options...
inmarket Posted November 3, 2017 Report Share Posted November 3, 2017 gtimer runs on its own thread. This means that if one timer job takes a long time then that will definitely delay other timer jobs that are ready to run. For a cooperative os like raw32 the same also applies to work done in any other thread. The key point here however is that the delay caused is only after a task is ready to run. It doesn't delay when the task is ready to run. E.g... A timer task at 35000ms system time is set to run in 100ms. This means the task is "ready" to run at 35100ms system time. No matter what else is happening in other tasks that doesn't change. The timer task will then be run at the first available opportunity after 35100ms system time. Having other busy tasks will only delay that first opportunity. The advantage of this is if you set a repeating timer then the cycle rate will average that period even if a specific timer event is delayed due to the cpu being busy doing other things. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now