Jump to content

David Kibble

Members
  • Posts

    32
  • Joined

  • Last visited

Posts posted by David Kibble

  1. Thanks Guys.

    Done and working, just detached the source when screen back light goes off then I use a periodic check on the ginputGetMouseStatus() to detect a touch and re-attach the listener. Did that so that it doesn't matter where on the panel is touched.

  2. Hi Guys.

    I'm after some advice on where and how to modify the ginput code so that I can catch and if necessary block a mouse (touch) event. The reason for wanting to do this is that for bedroom usage I need to turn off the backlight of a control panel, that's easy - if no use for > some timeout turn off the backlight. So when it comes to turning back on, I can easily capture a touch event, BUT the problem then is the user might have touched a button without being able to see it triggering an action they may not want, so we need to say "If backlight is off, catch touch event and turn backlight back on but do not pass that touch event to any widgets for processing".

    I can see a few places where I could add that sort of code, such as within the gmouse_lld_linux_event.c (I'm using a Linux board) or within ginput_mouse.c itself. 

    Or is there a better way to tackle this?

    Many thanks in advance.

    Dave

  3. Hi Guys.

    Could you please give me an official steer on the use of local GHandles. Your examples and Studio always generate global scope vars for all GHandles, but is there actually any problem in taking the approach of using local (within a function) GHandles for graphic entities which are transient and modal such as dialogue boxes? For example you could have a function;

    showDialogBox(...)
    {
      GHandle container;
      GHandle button1;
      GHandle button2;

    etc etc
      gwinShow(container);

      <event loop waiting and processing modal events for button 1 and 2>

      gwinDestroy(container);
    }

    I prefer this style wise as it contains the variables and logic, reduces the sheer volume of global vars which you end up with on a large UI project and creates a more easily reusable component.

    But - are there any negative side effects within uGFX of doing this? I ask because I'm getting some odd behavior now on a large UI where container hierarchies are not redrawn properly and before I start diving into my code, it occurred to me I should check the above pattern with you guys.

    Thanks

  4. Hi Guys.

    Not having much luck with this. Following the above advice my project makefile looks like this;

    GFXBOARD                = Linux-Framebuffer-Touch_A13
    ...
    include /home/dkibble/workspace/TouchControl/Linux-Framebuffer-Touch_A13/board.mk

    The TouchControl/Linux-Framebuffer-Touch_A13/board.mk looks like this:

    GFXINC  += /home/dkibble/workspace/TouchControl/Linux-Framebuffer-Touch_A13
    GFXSRC  +=
    GFXDEFS += -DGFX_USE_OS_LINUX=TRUE
    GFXLIBS += rt

    include /home/dkibble/workspace/TouchControl/Linux-Framebuffer_A13/board.mk
    include $(GFXLIB)/drivers/ginput/touch/Linux-Event/driver.mk

     

    and the TouchControl/Linux-Framebuffer_A13/board.mk looks like thisl

    GFXINC  += /home/dkibble/workspace/TouchControl/Linux-Framebuffer_A13
    GFXSRC  +=
    GFXDEFS += -DGFX_USE_OS_LINUX=TRUE
    GFXLIBS += rt

    include $(GFXLIB)/drivers/gdisp/framebuffer/driver.mk
     

    Alas when I execute make I just get;

    make -f makefile.arm clean 
    /home/dkibble/ugfx/ugfx/gfx.mk:38: /home/dkibble/ugfx/ugfx/boards/base/Linux-Framebuffer-Touch_A13/board.mk: No such file or directory
    make: *** No rule to make target '/home/dkibble/ugfx/ugfx/boards/base/Linux-Framebuffer-Touch_A13/board.mk'.  Stop.
     

    and that line in the gfx.mk is;

    # Include the boards and drivers
    ifneq ($(GFXBOARD),)
        include $(GFXLIB)/boards/base/$(GFXBOARD)/board.mk
    endif
     

    Which was my original starting place.

    Any ideas? I've copied the board.mk files from the ugfx source as that seemed logical. Is that my error? What should a custom board.mk look like?

    Many thanks

  5. Is cost the main concern for you and do you have stringent real time constraints? If not - maybe look at other embedded Linux boards such as those from Olimex (a20, a13 etc). These boards offer a huge amount of processing power and memory along with good i/o and various LCD interfaces including direct RGB for a reasonable price and size. I've used the A20 and A13 along with RGB 4.3" and 5" 800x480 LCDs from China alongside uGFX. The BuyDisplays LCDs are pretty good in my experience (have used 2.8" SPI + 4.3" RGB models). Touch screens work fine with uGFX as they use the Linux touch driver included by Olimex in their Debian build. The great thing with these types of embedded Linux boards is you can easily move from testing on your Linux PC to the real hardware with good confidence things will work exactly the same. Yes there are some odd differences, but it's a much easier road in my experience compared with truly dedicated hardware. 

    Just an idea in case you are not wedded to the STM32.

  6. Hi Guys.

    Going back to the original question - did you solve the problem of the double redraw? I'm having something similar on multi-container UIs. Switching between 'screens' using the guiShowPage(...) type approach generates two redraws, the first after the gwinHide, the second after the gwinShow I think. You mention trying different GWIN_REDRAW_IMMEDIATE modes, what did you conclude?

    Many thanks

  7. Hi Guys.

    I've got a simple problem which there must be a simple answer to, but I've not found it yet. With the 2.7 release of uGFX I took the opportunity to tidy up my projects and code so that I would not have any modified or non-uGFX files within the uGFX source tree. I have a custom board file for my production hardware which I moved to my project source tree and I use the standard Linux-SDL board for PC based testing. My problem is gfx.mk, it has the section;

    # Include the boards and drivers
    ifneq ($(GFXBOARD),)
        include $(GFXLIB)/boards/base/$(GFXBOARD)/board.mk
    endif

    So fairly obviously that fails to find my custom board in my source tree, but works fine when I switch to the standard "Linux-SDL" board.

    I can modify gfx.mk to work with both my project based board and the standard UGFX boards, but that's breaking my aspiration to not fiddle with anything in the uGFX source tree.

    What am I missing / not doing here? I've read the Wiki section on custom boards, but it doesn't seem to have any additional steps which I'm missing. My dev environment is Eclipse CDT running on Debian 8.

    Many thanks

    Dave

  8. Hi Joel.

    I could certainly move this to a GTimer but as I wasn't using that module and my hardware is pretty fast I went the dedicated thread route.

    I hope someone finds this helpful, even if thats just for learning uGFX basics.

    Dave

  9. Hi All.

    Not sure if this is the right place to share code, but please find attached some simple code to create a 'spinner'. By spinner I mean a visual indicator of the system being busy or processing, much like the hour glass in old Windows or the rotating circle in Linux, Android etc. It's fairly basic but does the job for me. The code is hopefully self explanatory but just to give a quick summary. The spinner is displayed by a gfxThread which is created the first time you call showSpinner(...), that function takes two params, one is a Boolean (bool_t) which controls if the spinner is made visible or not and the second is a GHandle for the parent under which the spinner is drawn. There are functions to control, colour, size and style of the spinner. I've coded 3 styles, a spinning pie segment, a spinning arc segment and a horizontal bar "knight rider" style. If for any reason you need to stop the thread which runs the spinner just call stopSpinnerThread(), this may save resources on very low spec hardware instead of just hiding the spinner using showSpinner(FALSE,...). I've left a few printfs in there so you can see the thread startup and exit. Just take them out if you don't want them.

    To use the code just include "spinner.h" in your code, add the spinner.c to your source code folder, add spinner.c to your makefile and then just call showSpinner(TRUE,<parent>) from your code. You can pass NULL for <parent> in which case my code redraws the whole display, e.g. showSpinner(TRUE,NULL); The spinner will run until you call showSpinner(FALSE,<parent>). The speed of the spinner is hard coded, but you can easily change it by altering the usleep(...) in spinner.c line 149. The code has been written and tested on Linux host and targets and uses the default thread stack size with low priority. You can experiment with these values if you need to.

    You'll need to enable a few things in your gfxconf.h
    #define GDISP_NEED_CIRCLE                       TRUE
    #define GDISP_NEED_ARC                            TRUE
    #define GDISP_NEED_MULTITHREAD            TRUE

    Good luck.

    Dave

    spinner.c

    spinner.h

  10. Hi.

    OK - that is a good call. I'd missed the non-filled gdispGDrawStringBox(...) function. Using that makes the code a lot simpler as now I don't need all the lower level supporting gdisp code for my custom gdispGFillStringBox(...), also thanks for the design guidance re "no gwin calls from gdisp". I'm going to have a look at the streaming API when I get a chance, but the rendering is only taking around 400us max for a whole screen and about 80us for an individual label so it's not a pressing performance issue.

    Many thanks

    Dave

  11. 2 hours ago, inmarket said:

    I think there is a misunderstanding here. There is more than one mutex involved.

    1. The low level gdisp calls maintain a mutex to protect the GDisplay structure. You should never play with this mutex unless you are writing low level gdisp code.

    2. There is a seperate mutex that protects GWIN structures and drawing. This mutex is held by the  gwin code during any gwin drawing routines.

    So, within a GWIN custom draw routine you are not allowed to use GWIN drawing routines such as gwinDrawLine as that would attempt to take the gwin mutex again resulting in deadlock. You ARE allowed to use GDISP calls such as gdispDrawLine because that does not touch the gwin mutex.

    For new GDISP calls they can either directly use other gdisp calls or they can take the GDisplay mutex and use low level functions available only in gdisp.c such as line_clip. They should NEVER reference anything to do with the GWIN structures as they are below that level.

    A GWIN custom draw however should NEVER be touching the GDisplay mutex as that mutex is only for use by the gdisp calls. It should also never touch the GWIN mutex as that is managed by the gwin code itself. A gwin custom draw should only make use of gdisp drawing calls.

    As you are looking to change color on every pixel you can either use the gdispDrawPixel call  (or whatever it is called), or you can make use of the more efficient gdisp streaming calls (see the gdisp streaming demo).

    The final option is to write a new gradient gdisp area fill call and then use that within your custom draw however that is probably the most complex way of doing things. If you want to try that approach, first try writing it using the gdisp streaming calls and then translate that code block into a proper gdisp call. Using the gdisp streaming calls you don't need to worry about mutexes or driver models, all the nasty hardware and mutex stuff is already taken care of for you allowing you to concentrate on your real code.

    Hi - I'm not sure I'm getting you on this;

    Here's the standard line draw code;
    void gdispGDrawLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) {
        MUTEX_ENTER(g);
        g->p.x = x0;
        g->p.y = y0;
        g->p.x1 = x1;
        g->p.y1 = y1;
        g->p.color = color;
        line_clip(g);
        autoflush(g);
        MUTEX_EXIT(g);
    }

    MUTEX is on GDisplay

    Here's the standard gdispFillStringBox which is called by the standard label rendering routine:
        void gdispGFillStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify) {
            #if GDISP_NEED_TEXT_WORDWRAP
                wrapParameters_t wrapParameters;
                uint16_t nbrLines;
            #endif

            MUTEX_ENTER(g);

            g->p.cx = cx;
            g->p.cy = cy;
            g->t.font = font;
            g->t.clipx0 = g->p.x = x;
            g->t.clipy0 = g->p.y = y;
            g->t.clipx1 = x+cx;
            g->t.clipy1 = y+cy;
            g->t.color = color;
            g->t.bgcolor = g->p.color = bgcolor;

            TEST_CLIP_AREA(g) {

                // background fill
                fillarea(g);

    Again MUTEX on GDisplay - or am I wrong?

    So - my problem is that as I want to use gdispDrawLine from my gradient code which is called from my cusomised FillStringBox the MUTEX on GDisplay is already locked. Hence my workaround to unlock it prior to my gradient draw and then re-lock it all within my cusomised FillStringBox. This is absolutely the problem as a simple GDB session shows and is all at the gdisp layer not the gwin layer. Yes - the cusom label rendering as the gwin layer, but that MUST call the FillStringBox routine in gdisp to repaint the background.

    Now it's quite possible I'm missing your point, so apologies in that case, but as far as I can tell there is no separate gwin MUTEX at play in the problem here.

    On the streaming front - I'll take a look at that when I have a bit of spare time. Performance on my Cortex A8 board is absolutely fine, can't even see the slightest hint of the redraw occurring.

    Many thanks for the help with this.

    Dave

  12. Hi Guys.

    I'm having to partially give up on this approach. I looked at the low level innards of the line drawing routines and to utilize them I'd either have to pull a huge chunk of the internal gdisp code into my codebase or directly modify your gdisp code. Both of those would be a PITA when the next version of uGFX comes along. So for now what I've done is quite simple and I cannot believe I missed it before;

    void gdispGGradFillStringBox(GWidgetObject * gw, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify)
    {
        GDisplay * g = (GDisplay *)gw->g.display;
        MUTEX_ENTER(g)
    
        #if GDISP_NEED_TEXT_WORDWRAP
            wrapParameters_t wrapParameters;
            uint16_t nbrLines;
        #endif
    
        g->p.cx = cx;
        g->p.cy = cy;
        g->t.font = font;
        g->t.clipx0 = g->p.x = x;
        g->t.clipy0 = g->p.y = y;
        g->t.clipx1 = x+cx;
        g->t.clipy1 = y+cy;
        g->t.color = color;
        g->t.bgcolor = g->p.color = bgcolor;
    
        TEST_CLIP_AREA(g) {
            MUTEX_EXIT(g)
            gradientPartialRendering(gw,&mainFormGradConfig);
            MUTEX_ENTER(g);
            // background fill
            //fillarea(g);

    So it's a bit of a hack - but gives very little window of opportunity for other threads to corrupt 'g'

    If you can either expose the internal functions or make the MUTEX's controllable (or have any other ideas how I can link my code to your code without mods) then I can come back to this. For now though, the above works fine for my multi-threaded app.

    Just to recap in case anyone else is reading..... The problem here was how to override the rendering of the label component. Easy to create a custom rendering function for the label, but that custom rendering cannot easily use high level gdisp functions like DrawLine because the Label rendering routine itself uses the same MUTEX as the other gdisp functions. Hence if you lift and shift the existing label rendering to modify it, you get stuck in a mutual dependency of MUTEX's.

    Thanks for the idea and info though, all much appreciated.

    Dave

  13. Many thanks - I'll take a look at moving my gradient draw routines to the low level functions. Once I'm happy with all of this I do still plan to share my gradient code, I guess I'm a bit of a perfectionist so didn't want to pass it on until I'd shaken out all these sorts of issues.

    Dave.

  14. When I looked at this I took away that a buffer is really no more than a shared memory block. You can certainly use buffers as a means to move data between threads or functions but it depends what functionality you want. Queues are FIFO so preserve sequence which may be important to you. Also queues take care of next available and empty functionality. Mutex's can be used with both to control thread behaviour but generally I haven't needed them with queues other than for when I'm searching a queue and want to stop other threads adding / removing at the same time. Concurrent queue processing is fine, the get functions are atomic.

    I think without knowing more about your requirements its hard to say which would be most appropriate. If you aren't sure and you don't need random access most of the time I'd go with queues. I'm using queues for command processing and message queuing and have found uGFX to be very solid. 

    Dave

  15. Hi Guys.

    Sorry for posting an update so soon but I've been having more of a poke around this. I've changed the code in my custom gdisp function to look like this;

    void gdispGGradFillStringBox(GWidgetObject * gw, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify)
    {
        GDisplay * g = (GDisplay *)gw->g.display;

        #if GDISP_NEED_TEXT_WORDWRAP
            wrapParameters_t wrapParameters;
            uint16_t nbrLines;
        #endif

        g->p.cx = cx;
        g->p.cy = cy;
        g->t.font = font;
        g->t.clipx0 = g->p.x = x;
        g->t.clipy0 = g->p.y = y;
        g->t.clipx1 = x+cx;
        g->t.clipy1 = y+cy;
        g->t.color = color;
        g->t.bgcolor = g->p.color = bgcolor;

        TEST_CLIP_AREA(g) {
            gradientPartialRendering(gw,&mainFormGradConfig);

            // Moved to avoid the MUTEX which locks on (g)
            MUTEX_ENTER(g);
            // background fill
            //fillarea(g);

    I added the gw widget param to make it easier to drive my gradientPartialRendering function but the main thing I wanted to check is what is the risk around moving the MUTEX_ENTER(g) in the way I have? Without pouring over the low level code it's hard to know. Just FYI - my application does do a small amount of GUI updates via a background thread with the bulk of the work being on a single GUI thread. I'm assuming that's why you have the MUTEX in there?

    Anyway - the result is perfect and is attached. Note the clock in the lower right corner.

    Dave

    TransparentLabel.png

  16. Hi Folks.

    Over the past month or so I've implemented a number of custom rending routines for uGFX but now I've hit on a problem. I've created a set of very nice looking gradient fill and partial gradient fill rendering routines which I'm using without issue. However - I now want to use my partial gradient fill (fills a specific area of the screen with a gradient colour to match the gradient colour of the background at that point) to produce a label which would therefore appear 'transparent'. The label background is my custom gradient fill and the text is as per normal. It's use would be great for something like a digital clock which although functional without this enhancement looks a bit clumsy with a solid background over the gradient.

    So first up this took a bit more doing than most of the other customisation I've done as the standard label fill comes from the gdispGFillStringBox function which is buried down in the gdisp code and seems to come with a lot of dependencies when you pull it out. Anyway - sorted that and have my own renamed gdispGFillStringBox and all associated functions out in my own codebase. All compiles and works fine. :-) Now the problem. (Finally I hear you cry !)

    My custom rendering uses gdispDrawLine and gdispDrawLine's first instruction is MUTEX_ENTER(g), unfortunately that MUTEX_ENTER(g) is also executed by the gdispGFillStringBox and thus as it stands gdispGFillStringBox cannot therefore call my custom gradient function which uses gdispDrawLine as the MUTEX is already locked.

    I hope that makes sense? So at this point I'm really open to some expert guidance on how to solve this. I can see that the gdispGFillStringBox uses some low level functions for it's fill and the gdispGDrawLine uses line_clip(g), but should I try to implement my custom gradient rendering using those low level functions? I guess its not that hard to do, but before I go off and figure it out I'd really appreciate some advice from the experts as to what the correct approach in this sort of situation would be? Have I for example gone off on completely the wrong track here?

    Many thanks

    Dave

  17. On 27/10/2016 at 06:55, Joel Bodenmann said:

    This has nothing to do with the Qt installation on the µGFX-Studio user's computer. The package is supposed to contain anything required to run a stand-alone application without any dependencies. There is no need to install Qt or any other 3rd party software or library in order to run the µGFX-Studio.

    As @David Kibble mentioned the issue is related to improper packaging of the application. That's a fault on our side that we can, have to and will correct.

    Thanks Joel. Let me know if I can help in any way.

    Dave

  18. Hi Guys.

    I've just downloaded the fixed update and I have the exact same error as matthgyver;

    /opt/ugfx-studio/ugfx_studio_0.15_linux/./ugfx_studio/uGFX-Studio: relocation error: /opt/ugfx-studio/ugfx_studio_0.15_linux/./ugfx_studio/uGFX-Studio: symbol _ZN10QJsonArray7detach2Ej, version Qt_5 not defined in file libQt5Core.so.5 with link time reference

    From my modest knowledge of QT I'd say you have a dynamic link in there somewhere which can't be resolved on our machines. I do have QT5 on the box I'm running uGFX Studio on, but obviously the o/s can't resolve the missing symbol.

    Interestingly - it is possible to create and save a new proejct, but once done you cannot re-open it. Hope that helps narrow this down?

    Many thanks

    Dave

×
×
  • Create New...