Jump to content

steved

Members
  • Posts

    64
  • Joined

  • Last visited

Posts posted by steved

  1. Looks like there could be two problems!

    Initially the popup frame was created without a 'close' button (or min/max).

    On investigation, the _frameDestroy() routine 'disconnects' the frame listener regardless. So I added a check:

    static void _frameDestroy(GHandle gh) {
    // Following added
    if ((gh->flags & (GWIN_FRAME_CLOSE_BTN|GWIN_FRAME_MINMAX_BTN))) {
    /* Deregister the button callback */
    geventRegisterCallback(&gh2obj->gl, NULL, NULL);
    geventDetachSource(&gh2obj->gl, NULL);
    }
    /* call the gcontainer standard destroy routine */
    _gcontainerDestroy(gh);
    }

    ... and everything works fine.

    I then enabled the frame 'Close' button - and the problem recurred.

    So there may be a problem with the operation of geventRegisterCallback(&gh2obj->gl, NULL, NULL);

  2. I'm implementing a pop-up window, in a similar manner to that described at http://wiki.ugfx.org/index.php?title=Frame#Overlay. Using chibios (V3 SVN)

    I get a semaphore-related system crash during destruction of the popup, which appears to be triggered within the event handler. Not managed to pin it down yet, but it looks as if maybe the event listener created by the popup window isn't getting fully destroyed. Code crashes on line 156 of gevent.c:


    gfxSemWait(&psl->pListener->eventlock, TIME_INFINITE); // Obtain a lock on the listener event buffer

    The create and destroy code all runs on the main ugfx event handler loop.

    To create the popup:


    gwinSetEnabled(ghFrameScreen, FALSE); // Disable main screen - all elements are in a container
    ghFramePopup = createKeypadDisplay(0, "Access Code"); // Add some buttons in a frame

    To destroy the popup, and reinstate the main screen (in response to a button press on the popup):


    gwinDestroy(ghFramePopup);
    ghFramePopup = NULL;
    gwinSetEnabled(ghFrameScreen, TRUE);

    The call stack is as follows:

    gfxSemWait() (chibios.c:121)

    geventRegisterCallback() (gevent.c:129)

    _frameDestroy() (frame.c:42)

    gwinDestroy() (gwin.c:175)

    At one point the crash didn't occur until the first button press on the main screen (after the popup was destroyed). I added a line of code after line 44 in gevent.c:


    44: psl->pListener = 0;
    45: psl->pSource = 0; // Added as experiment

    At the time that appeared to make a difference; then the problem returned.

    I'm still trying to thread my way through the event code

    Has anyone else experienced something like this?

  3. I've added an option to widgets to assign a 'tag' value (as is done in Delphi) which can greatly simplify event handling - overall it may well save both RAM and code space in some applications - no need to do lots of comparisons with widget pointers.

    For example, a keypad can assign tags which convert readily to ASCII characters, permitting use of generic decoding routines.

    The notes in the attached files give an example.

    Very simple addition.

    event_handling_using_tags.zip

  4. Following on from my previous post, I've written some code for a general-purpose registry for small chunks of data; generally as the discussions in that thread.

    Not properly integrated into ugfx, but works for me!

    I'm using the code on ChibiOS with a small I2C FRAM (similar to an EEPROM) - limiting data size to about 250 bytes for simplicity at the I2C level. There's also a skeleton interface to GFILE.

    Each registry entry is assigned a 'tag' (16-bit value), with two ways of using the code:

    a) With a list of predetermined tags. (Very small code overhead)

    b) More as a crude (but simple) file system, where any tag value is allowed.

    The code also introduces another idea - a set of ugfx-wide error/result codes, which may generate some comment!

    ugfx_updates_010714.zip

  5. After some more days of thinking I came to the conclusion that GREGISTRY might still be better than GCONF so we don't confuse new people with the configuration of the uGFX modules themself (gfxconf.h) etc.

    ~ Tectu

    I agree - the term 'Registry' seemed to describe the function of the module well, so having a different name for the module and its entry points then seems perverse.

  6. What do you think of GREGISTRY or GCONFIG as the module name?

    GREGISTRY sounds the best choice to me

    As GFILE is light (it is not a full file-system just a shim layer) it makes sense to have GFILE able to access the raw devices as just a block of raw data/memory/device and then use GFILE to implement GREGISTRY. It gives a lot of flexibility to the implementation.

    Once the API is defined, it shouldn't matter whether GFILE is used or not; obviously helpful to some if there is a GFIL-based implementation. (My own applications may well want to manage NVR themselves, rather than letting GFILE do it).

    A uint16 tag identifier sounds great. I would suggest tags > GREGISTRY_MAX_USER_TAG be reserved for ugfx. That way the user can number their own blocks starting from 0 (nicer for the application).

    Sounds reasonable. To avoid losing registry data if GREGISTRY_MAX_USER_TAG is redefined during a code upgrade, I'd then assign uGfx tags growing down from GREGISTRY_MAX_TAG_VALUE (which will be 65535) - as with stack and heap.

    Using a null pointer on the read call to get the size certainly works. More complicated from an API perspective but it seems to be the way most os's do that sort of thing. It is less obvious though.

    It's a refinement which should be simple to implement; as I envisage the use of this module, most callers will already know the size or maximum size of the data. And if returning a 'buffer too small' error in response to a normal read, we could return the actual size of the data (discussion point - its a somewhat inconsistent return).

    I personally have a pet hate for "errno" style of error reporting (where the error is saved in a global variable). It is not thread-safe and it is non-obvious.

    I personally also am not keen on passing by ref to get what is effectively a return value. I realise that conflicts with the above statement but that is just my particular design style. Of the two I am more opposed to the "errno" system.

    Me too.

    I am wondering however for an embedded registry if it really matters why the read or write failed. It is good enough to know that it did and that you didn't get the setting you wanted. Debugging the system will have long ago told you of any systemic problem. For an embedded system fall-back in this type of situation really doesn't need to know why it failed, simply that it did.

    At the most basic level, you are absolutely right. However, I have found from experience that logging the more detailed error code can help diagnose any subsequent problems - on low-volume systems debugging rarely covers all possible use cases (and sometimes, regardless of the amount of debugging/testing, coding errors can lurk undetected for years!). The logging need not be complex; a simple memory location which holds the last error encountered can be sufficient. And using a large number of different error codes can help home in on precisely where an error occurred. (Consider reading back data - a 'buffer too small' error will require different remedial action to 'storage device failure').

    Note that use of uint8_t. I am thinking that registry data should always be small. Is 255 bytes a reasonable limit or should this be a uint16_t with a GREGSITRY_MAX_DATA_SIZE #define?

    I considered the same question, and concluded that a reasonable limit is actually 256 bytes! Its a much more useful size than 255. So unless we have a special case of zero really meaning 256 (ugh) we need uint16_t with GREGISTRY_MAX_DATA_SIZE.

  7. I'd see GFILE as an option, rather than the only solution - for myself, initial implementation will write calibration and other information to non-volatile memory, without a file system in sight. This is probably typical of many embedded systems, which don't need the complexity/code space of a file system (even if someone's already solved the problem!). Although if its easy to point GFILE at an block of non-volatile memory.... (I use a small FRAM, communicating over I2C, since speed isn't at all important for small blocks of data. Each data block includes a size and a checksum). Keeping the general principle of ugfx, maybe we support GFILE and various direct memory-based arrangements using drivers.

    The various comments seem to be building on the principle quite nicely:

    1. We call it a 'registry' - so my data identifier becomes some sort of tag. We could leave the tag as a unit8_t, or extend it to uint16_t to give more flexibility. Split the tag's number space into two blocks; one for ugfx-related devices (first 64 tags, say), and one for user tags. It's then up to the registry driver how to assign a storage location; a simple non-volatile memory driver might have a table relating tags to start addresses, while a file system might create a file name based on the tag.

    2. A separate 'get data size' call seems sensible for those situations where the data size is variable. Some (most?) uses will have a fixed or known maximum data size, and not need to use this call.

    3. The read routine would certainly need to check that its not going to overflow the passed buffer. If we pass the buffer size by reference, it can then be filled in with the actual size of the data block on return, and either a 'success' return code or a 'buffer too small' error code.

    (I don't think we want to get into passing data in chunks - that's surely a case for direct file system access. I would expect registry entries to be quite small.)

    So the API becomes three entries:

    gfxError_t gfxSaveRegistryData(uint16_t tag, const uint8_t *data, uint16_t dataSize);
    gfxError_t gfxReadRegistryData(uint16_t tag, uint8_t *data, uint16_t *dataSize);
    gfxError_t gfxReadRegistrySize(uint16_t tag, uint16_t *dataSize);

    I've deliberately adopted the format for gfxReadRegistrySize() for consistency and helpfulness; it gives the opportunity to return error codes for 'invalid tag' and maybe 'no data stored', which is less ambiguous than simply returning zero for both these cases.

    Edit: As an alternative to gfxReadRegistrySize(), if gfxReadRegistryData() accepts a null pointer for the data buffer, it could just return the data size.

  8. I've been looking at loading and saving touch screen calibration data, and making the interface more generic.

    It comes down to streams of bytes, so the same interface could be used with displays and other I/O devices as general configuration data (e.g. setting a display type or resolution)

    I propose the following interface:


    gfxError_t gfxSaveDeviceConfig(uint8_t deviceID, const uint8_t *data, uint16_t dataSize);
    gfxError_t gfxReadDeviceConfig(uint8_t deviceID, uint8_t *data, uint16_t dataSize);

    gfxError_t is a result/error code type whose values are to be determined (also on the TODO list); with codes for success, possibly 'not implemented', and various reasons for failure.

    The caller can then take action (or ignore) as is appropriate - for example on failing to read touch screen calibration data, the calibration screen is displayed.

    The underlying routines can then access whatever non-volatile store is available, and possibly even provide sensible defaults in some cases.

    deviceID needs defining in some way, so that it can reliably reference input devices, displays and so on. Maybe a simple block of values for each device type; for example:

    0x00..0x07 - touchscreens

    0x08..0x0f - dials

    0x80..0x83 - displays

    Any comments?

  9. Bit of an open-ended question here - I'm trying to get a feel for how much processing power I'll need to provide a responsive display using uGFX.

    Looking at the Displaytech INT070ATFT-TS, which is a 800x480 display with touch screen, using the SSD1963 controller and MAX11802 touch screen interface.

    The graphics side is pretty undemanding - mostly simple coloured boxes with text in them - no images and no animation, and little user interaction.

    Main need for responsiveness comes when the user is entering configuration data, which I envisage being a selection of the elements supported by GWIN - radio buttons, checkboxes, lists and some numeric entry, with data entry solely by touch screen.

    The processor will be doing very little apart from servicing the display - a modest amount of I2C comms and that's all.

    I've used the ST 32F051 with ChibiOS on another project, so that processor, or if necessary a more powerful one from the 32F family, is the favoured choice provided its likely to be adequate.

    Can anyone give any advice based on practical experience?

    Thanks

×
×
  • Create New...