HT-005-Platform Integration Embedded Wizard How-To Document How To Integrate Embedded Wizard Applications Into Your Platform HowTo-No.: EmWi Version: Doc. Version: Date: Authors: 005 6.10 6.0 21th November 2011 Steffen Hermann, Mario Stefanutti, Manfred Schweyer Keywords: Platform Integration, Initialization, Application Loop, Core::KeyEvent, Core::CursorEvent, Event Dispatcher, Message Handling, Event Handling, Events, Timers, Signals, Memory Management, Garbage Collection, Mouse, Touch Panel, Guestures, Error Handling, Fatal Error, EwPanic, Endless Loop Introduction Embedded Wizard (EmWi) is a platform independent solution for developing and prototyping of state of the art graphical user interfaces (GUI) on embedded systems. It can be used to solve almost any 2D GUI task - moreover, with its lightweight 3D functionality the GUI appearance can be enriched significantly. This how-to document describes the principles of the integration of an Embedded Wizard generated GUI application into a certain hardware platform and the communication between the GUI application and the main application. Please note, that this document describes the integration of all Embedded Wizard applications using the class library Mosaic 2.0 and using a Platform Package based on Graphics Engine 2.0. Within Embedded Wizard a complete GUI application is created in a platform independent manner – by using the platform independent programming language Chora. The platform dependence is realized and covered by so-called Platform Packages. These packages can be considered as a bridge between the platform independent GUI application and the particular target system. The following figure demonstrates this approach. The components of the Platform Package are shown here as gray blocks: www.embedded-wizard.de Copyright TARA Systems GmbH Page 1 HT-005-Platform Integration Each Platform Package consists therefore of following main components: Code Generator It evaluates the entire GUI application and translates it into the ANSI C code optimized for the particular target C compiler. This generated code can be compiled for the target system. Bitmap Converter It adapts all bitmap resources (image files used in the project) to the graphical capabilities of the target system. This conversion can include a color reduction, a dithering and a compression. Finally the converter generates ANSI C code, which can be compiled for the target system. Depending on the type of the converter, the generated C code can contain the pixel data of the bitmap or only a simple reference to an external image file, which can be loaded at the runtime by an external image loader. Font Converter It adapts all font resources (TrueType fonts used in the project) to the graphical capabilities of the target system. This conversion can include a quality reduction and a compression. Finally the converter generates ANSI C code, which can be compiled for the target system. Depending on the type of the converter, the generated C code can contain the pixel data of all affected font glyphs or a simple reference to an external TrueType file, which can be loaded at the runtime by an external TrueType font engine. Graphics Engine It provides the GUI application with the common graphical functionality, like the drawing of lines, filling of rectangles, copying of bitmaps, 3D projection and text output. www.embedded-wizard.de Copyright TARA Systems GmbH Page 2 HT-005-Platform Integration Unlike the converters described above, this functionality is needed at the runtime in the target system. Thus, the Graphics Engine is delivered in C code, which can be compiled and linked together with the remaining generated C code files. Runtime Environment It provides the GUI application with the common runtime functionality, like the memory allocation, the time evaluation or mathematical operations. Unlike the converters described above, this functionality is needed at the runtime in the target system. Thus, the Runtime Environment is delivered in C code, which can be compiled and linked together with the remaining generated C code files. All Platform Package components described above are developed, maintained and distributed by TARA Systems. Depending on your target system, its graphical capabilities, the used color format, CPU architecture or the used C compiler TARA Systems will provide you with optimal matched combination of these components. For example, the ready-to-use OpenGL ES 2.0 Platform Package makes it possible to run the GUI applications on OpenGL ES 2.0 capable target system. In contrast the DirectFB Platform Package is optimized for the Linux DirectFB API. Installation and Preparation Work First of all, we have to ensure that all necessary Embedded Wizard components are available and up-to-date. Please follow these steps: • Download the latest version of Embedded Wizard from our Embedded Wizard download center and execute the setup (if not already done...). • Install the Platform Package setup for the desired target platform. The version of the Platform Package has to correspond to the version of Embedded Wizard. • Ensure that your Embedded Wizard license is activated for generating code for your target platform. In case you received an activation file from TARA Systems, please follow these steps in order to activate your Embedded Wizard dongle: 1.) Save the provided *.rfp on your harddisk. 2.) Start the program activate.exe, which you will find in your Embedded Wizard installation directory. 3.) Plug-in your dongle on your PC and load the *.rfp file into the activate.exe program and upgrade the dongle. Generating Code for Your Platform The following explanations and intended to describe the principles of generating code of a sample application for your target platform. The concrete implementation might differ from target to target, but the principles are the same for every platform. Please follow these steps: • Start the Embedded Wizard application. • Open one of the installed examples from the directory \Examples_Mosaic20 (e.g. AnimationEffects). • Create a new profile brick within your project and rename it to the name of your target e.g. 'PlatformXYZ' www.embedded-wizard.de Copyright TARA Systems GmbH Page 3 HT-005-Platform Integration • Select the new profile, set the attribute 'PlatformPackage' to the value of the installed Platform Package e.g. 'PlatformXYZ.Generic.RGBA8888' (you can easily select it from the drop-down list within the Inspector window) and change the attribute 'ScreenSize' to the size which corresponds to the size of the display used within your target system. • Select the new profile 'PlatformXYZ' within the profile selection box (the combobox between Composer window and menu bar). • Now you can start the Prototyper (Ctrl+F5) to run the application as simulation. Please note, that if the ScreenSize of your display does not correspond to the www.embedded-wizard.de Copyright TARA Systems GmbH Page 4 HT-005-Platform Integration • • size of the example, only parts may be visible (in case your display is smaller) or only parts of your display are covered by the application (in case your display is larger). But we can ignore this for the first bring-up. Now you can generate the code for your target: To start the code generator, select the menu items 'Build' - 'Build this profile'. Within the subdirectory \Examples_Mosaic20\AnimationEffects\PlatformXYZ you will find a set of header files and 'C' source files. This is the generated code of the GUI application. Integrating the Code into Your Makefile The following explanations are intended to describe the integration in general rather than referring to a specific hardware platform. The concrete integration into your build environment depends on your toolchain and might differ from target to target. After the code generation, the resulting C files of the GUI application are now compiled together with the source code of Runtime Environment and Graphics Engine for your hardware platform by using a target compiler. Please follow these steps: • Copy all files from the directory \Platforms\PlatformXYZ\Generic\RGBA8888\GFX into your build system into the subdirectory /GFX. These are the files of the Graphics Engine. Add all C-files into your makefile: # compile all files of the Graphics Engine (GFX) EMWI_GFX_C = ewextbmp_RGBA8888.c ewextfnt.c ewextgfx.c ewextpxl_RGBA8888.c ewgfx.c ewgfxattrtext.c ewgfxcore.c ewgfxdriver.c ewgfxtasks.c • Copy all files from the directory \Platforms\PlatfromXYZ\Generic\RTE into your build system into the subdirectory /RTE. These are the files of the Runtime Environment. Add all C-files into your makefile: # compile all files of the Runtime Environment (RTE) EMWI_RTE_C = ewcolor.c ewdebug.c ewextrte.c ewobject.c ewpoint.c ewrect.c ewref.c ewresource.c ewscalars.c ewslot.c ewstring.c ewtimer.c • \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Copy all the generated code from the directory \Examples_Mosaic20\AnimationEffects\PlatformXYZ into your build system into www.embedded-wizard.de Copyright TARA Systems GmbH Page 5 HT-005-Platform Integration the subdirectory /APP. In principle, you can add all C files into your makefile. However, there is more convenient way: During code generation, Embedded Wizard generates a list of all C source files within the file ewfiles.inc. You can just add this file to your makefile. This makes it possible to use the same makefile for different GUI applications or samples without any modification! # automatically compile all files generated by Embedded Wizard include $(APP_EMWI_PATH)/ewfiles.inc APP_EMWI_C = $(EMWIFILES) • • Add the above subdirectories to your include path within your makefile in order to find all necessary header files. Add EMWI_GFX_C, EMWI_RTE_C and APP_EMWI_C to the list of objects. In theory, the makefile is now prepared so that the application could be compiled and linked. But there is still something missing… Integrating the Code into Your Application This chapter is intended to describe the integration of the Embedded Wizard generated GUI application into your main application. With other words, we will now try to launch the GUI application and to provide it with all necessary events. General remarks: The both subdirectories RTE and GFX contain C files for the Runtime Environment and the Graphics Engine. All of these files are maintained by TARA Systems so any modification of these files should be strongly avoided. Additionally, please avoid the modification of generated code, because it will be overwritten next time when you start the code generation within Embedded Wizard. Important note: Please be aware that every Embedded Wizard GUI application requires the execution in a single GUI task. Includes First of all, some header files from the appropriate platform package directory have to be included into your main.c file. From the runtime environment (RTE): #include "ewrte.h" From the graphics engine (GE): #include "ewgfx.h" #include "ewextgfx.h" #include "ewgfxdefs.h" After that, some generated C files from Mosaic class library have to be included: #include "Core.h" #include "Graphics.h" www.embedded-wizard.de Copyright TARA Systems GmbH Page 6 HT-005-Platform Integration In order to find all of the above header files during the compilation of your main.c file, the include path has to be set correctly within your makefile. In case of a GCC compiler, this is typically done by using the -I compiler flag. Initialization of the GUI Application Before the Embedded Wizard generated GUI application can be executed on the target platform, the frame buffer and the Graphics Engine have to be initialized. The initialization of the frame buffer depends completely on your target system and the underlying graphics API. For example in case of DirectFB, a DirectFB surface needs to be created, in case of OpenGL ES 2.0 the frame buffer is typically created via EGL. In order to simplify this task, TARA Systems typically delivers a template of a main.c file including the necessary initialization together with a Platform Package. Nevertheless, the following code snippet illustrates the necessary steps to initialize the EmWi generated GUI application: int main( int argc, char **argv ) { CoreRoot rootObject; XViewport* viewport; YourFramebuffer framebuffer; int w, h; /* Startup your subsystem and obtain the frame buffer or display device*/ framebuffer = YourSubsystem_Initialize(); /* Query the size of your frame buffer or display device*/ GetSize( framebuffer, &w, &h ); /* Initialize the Graphics Engine and the Runtime Environment */ EwInitGraphicsEngine( &framebuffer ); /* Create the applications root object ... */ rootObject = (CoreRoot)EwNewObjectIndirect( EwApplicationClass, 0 ); EwLockObject( rootObject ); /* ... and initialize the application object. */ CoreRoot__Initialize( rootObject, EwScreenSize ); /* Create the viewport object to provide access to the framebuffer */ viewport = EwInitViewport( EwScreenSize, EwNewRect( 0, 0, w, h ), 0, 255, framebuffer, 0, 0, 0 ); ... The Parameter EwScreenSize is an automatically generated constant in the module Core.c of type XPoint. This value contains the size of the screen as it was defined in the attribute ScreenSize within the EmWi profile for that the code was generated. The Parameter EwApplicationClass, contains the root object of the GUI application. This application class is also defined within the attribute ApplicationClass of the profile. Implementing the Main Loop Embedded Wizard generated UI applications are running in an (endless) loop, which drives the UI application. This main loop is responsible to provide all user inputs to the www.embedded-wizard.de Copyright TARA Systems GmbH Page 7 HT-005-Platform Integration UI application, to start the processing of timers and signals, to take care for the update of the display and finally to start the garbage collection. The main loop can be implemented within your main() function or it can be implemented as a separate OS task. However, it is absolutely important, that the complete Embedded Wizard generated UI is running within one task! Splitting the different actions in several tasks (e.g. to start the garbage collection from another task) will cause unpredictable results… The following code snipped shows the typical implementation of a main loop: ... XEnum cmd = CoreKeyCodeNoKey; /* Enless loop, until the 'power' key is pressed... */ while ( cmd != CoreKeyCodePower ) { int events = 0; int timers = 0; int signals = 0; int touch; XPoint point; /* Step 1: Receive user inputs (key events)... */ cmd = GetKeyCommand(); /* ...and provide it to the application. */ if ( cmd != CoreKeyCodeNoKey ) { /* Create Mosaic key event object. */ CoreKeyEvent event = EwNewObject( CoreKeyEvent, 0 ); CoreKeyEvent__Initialize( event, cmd, 1 ); /* Insert the event to the root object. */ CoreGroup__DispatchEvent( rootObject, (CoreEvent)event ); /* Set a flag to indicate that event was processed. */ events = 1; } /* Step 2: Receive cursor inputs (mouse/touch events)... */ touch = GetTouchEvent( &point ); /* ...and provide it to the application. */ if ( touch > 0 ) { /* Begin of touch cycle */ if ( touch == 1 ) CoreRoot__DriveCursorHitting( rootObject, 1, 0, pos ); /* Movement during touch cycle */ else if ( touch == 2 ) CoreRoot__DriveCursorMovement( rootObject, pos ); /* End of touch cycle */ else if ( touch == 3 ) CoreRoot__DriveCursorHitting( rootObject, 0, 0, pos ); /* Set a flag to indicate that event was processed. */ www.embedded-wizard.de Copyright TARA Systems GmbH Page 8 HT-005-Platform Integration events = 1; } /* Step 3: Process expired timers */ timers = EwProcessTimers(); /* Step 4: Process the pending signals */ signals = EwProcessSignals(); /* Update screen and memory, only if something has changed */ if ( timers || signals || events ) { /* Step 5: Refresh the screen and draw its content */ Update( viewport, rootObject ); /* Step 6: Start the garbage collection */ EwReclaimMemory(); } /* Otherwise suspend for a while */ else usleep( 1 ); } In the following, we want to have a closer look into the single steps of this main loop. Step 1: Processing Key Events Depending on the operating system or generally speaking the application runtime environment, the input device drivers (keyboard, remote control, etc.) will generate messages when the input device state changes (e. g. a remote control button is pressed). Typically, the input task will have to write the input data into a message queue and the applications main loop can then process these events out of this queue independently. If an event is in the message queue (e.g. a remote control key pressed event) the main application first has to examine the event. This means, the event information has to be translated into a Mosaic key code. This has to be done within the function GetKeyCommand(): all key events which are needed within your UI application, needs to be translated into a Mosaic key code. For this purpose, the Mosaic class library contains a set of predefined keys in the enumeration KeyCode of unit Core. For example, the identifier CoreKeyCodeOk corresponds to the Ok key on the remote control or the ENTER key on a keyboard. When the main application has translated the incoming key into an appropriate key code, a new event object is created. An event object is an object of the Mosaic class Core::Event or a derived class. This event object has to be filled with the key code and is then passed to the UI application. Step 2: Processing Cursor Events Some devices are cursor operated (e.g. touch panels, joysticks or mouse). In this case a device driver will generate cursor information and write it into a message queue. www.embedded-wizard.de Copyright TARA Systems GmbH Page 9 HT-005-Platform Integration Similar to key events, the input task will have to write the mouse or touch events into a message queue and the applications main loop can then process these events out of this queue independently. For convenience, the Mosaic base class for applications provides the methods DriveCursorHitting() and DriveCursorMovement(). Since cursor events are very common tasks, the method implementation takes care of creating the corresponding event object and identifying the appropriate view to handle it. Please also refer to the methods inline documentation. Step 3: Processing Timers Within an EmWi generated UI application all timer objects, that are currently running, are stored in a timer list. In this step, the timer list is traversed and all expired timers are handled. The number of processed timers is returned by this function. In order to activate the timer processing, the following function of the runtime environment has to be called: int timers = EwProcessTimers(); Step 4: Processing Signals In an EmWi generated UI application, signals can be sent in order to trigger slot methods with certain behavior. Besides the regular signals, which are processed immediately, special post signals and idle signals are collected and executed right before, respectively after a screen update is performed. The processing of the deferred signals is done by calling: int signals = EwProcessSignals(); Step 5: Updating the Screen In reaction to any key / cursor event, signal or expired timers the UI application can change its look and for example open a new dialog box or move a bitmap across the screen. In that case, all affected objects are marked as invalid. During the update of the root object, all invalid areas are examined and changes to the visible objects are processed. Finally, the resulting display is shown within the visible frame buffer. The following function contains the complete display update cycle: static void Update( XViewport* aViewport, CoreRoot aApplication ) { XBitmap* bitmap = EwBeginUpdate( aViewport ); GraphicsCanvas canvas = EwNewObject( GraphicsCanvas, 0 ); XRect updateRect = {{ 0, 0 }, { 0, 0 }}; /* Let's redraw the dirty area of the screen. Cover the returned bitmap objects within a canvas, so Mosaic can draw to it. */ if ( bitmap && canvas ) { GraphicsCanvas__AttachBitmap( canvas, (XUInt32)bitmap ); updateRect = CoreRoot__UpdateGE20( aApplication, canvas ); GraphicsCanvas__DetachBitmap( canvas ); } www.embedded-wizard.de Copyright TARA Systems GmbH Page 10 HT-005-Platform Integration /* Complete the update */ if ( bitmap ) EwEndUpdate( aViewport, updateRect ); } Step 6: Triggering the Garbage Collection In the last step of the main loop the garbage collection is only triggered if any processing has happened. The following function of the runtime environment is called: EwReclaimMemory(); De-Initialization of the EmWi Application When the application is finished, the unused resources have to be released using the following commands: /* Finished -> release unused resources... */ EwDoneViewport( viewport ); EwUnlockObject( rootObject ); EwReclaimMemory(); /* ... and deinitialize the Graphics Engine */ EwDoneGraphicsEngine(); /* Finally, shutdown your graphics subsystem */ YourSubsystem_Deinitialize(); return 0; } www.embedded-wizard.de Copyright TARA Systems GmbH Page 11 HT-005-Platform Integration Communication between the EmWi Application and the Main Application The common way to send commands from the EmWi application to the main application is to embed native C code within the EmWi application. Native statements can either be implemented within a special “native method” or within a regular method, marked as native code. By using native code, functions of the main application can be accessed. The communication in the opposite direction – i.e. from the main application to the EmWi application – is done via events, which are created in the main application and sent to the EmWi application. EmWi Application Main Application method native void CallExampleFunction() { ExampleFunction(); } void ExampleFunction() { ... } HandleEvent() Method Create & Dispatch Event Native methods A native method is created in Embedded Wizard in two steps. At first, the “Method” brick is dragged from the Gallery and dropped into a class shown in the Composer. Then, in Inspector, the attribute “native” of the new method has to be given the value “true”. Now the EmWi considers this method as native, i.e. the method can contain native C code, together with Chora code. During code generation, the C statements of the method will not be translated, but directly taken over into the generated C source code. Therefore, native methods can be used to call functions and statements in the main application. Native code in regular methods Similar to native methods, functions of the main application can be called directly within regular methods. To achieve that, the native C code has to be embedded within the “native” statement. Necessary parameters can be passed in brackets as shown in this example:. native( aNumber ) { //native C statements... printf( “Number %d”, aNumber ); } www.embedded-wizard.de Copyright TARA Systems GmbH Page 12 HT-005-Platform Integration Chora and Custom Events To communicate with the EmWi application, the main application can generate event objects, i.e. objects of the Mosaic class Core::Event or a derived class, can fill it with certain values and can insert it into the EmWi application. An event can either be broadcasted by using the BroadcastEvent() method of an EmWi object or can be sent along the current focus path with the DispatchEvent() method of an object. Beside the existing event classes in Mosaic, like Core::KeyEvent or Core::LanguageEvent, developers can create their own event classes for specific purposes. The new event class has to be derived from the class Core::Event to inherit the event’s functionality and can then be equipped with certain variables, used to pass values from the main application to the EmWi application. In the following example a look is taken on a Set Top Box equipped with a flash card slot. If a new flash card is inserted, the main application has to create an event, called - for example – MyUnit::CardEvent. This class contains a variable Type, which stores the type of the card and a variable WriteProtection. The creation and initialization of the event has to be realized as follows: MyUnitCardEvent event = EwNewObject(MyUnitCardEvent,0); MyUnitCardEvent__Initialize(event, Type, WriteProtection); CoreGroup__DispatchEvent(Application, (CoreEvent)event); Note: This kind of custom events can’t be prototyped. Therefore the recommended way is to use a user event (USER0-USER19) or the function keys (key F1-F10) and read the required parameter in case of such an event via a native call from a corresponding API function. Otherwise everybody who works or supports this project needs a target development environment that can send this event. www.embedded-wizard.de Copyright TARA Systems GmbH Page 13 HT-005-Platform Integration Error Handling EmWi includes a special error handling to react on serious errors. The function EwPanic() will be called automatically by the Run Time Environment if a fatal system failure is detected. By default it prints an error message and stays in an endless loop. Even if this should never happen in a tested product, the default implementation is intended for debugging purpose. If EwPanic() is called you can set a breakpoint and investigate the callstack, parameters or memory content. Since each customer might react in a different way on fatal errors, the function EwPanic() should be changed by each customer, up to their requirements. The default endless loop could be sufficient if such a situation is handled by a watchdog timer, but it is recommended to do an error logging in a non volatile memory storage and execute a hardware or software reset afterwards. It is also possible to call a system error handler that is already available in your Software. Further Information For a first start, we recommend to study the Embedded Wizard User Manual including the “Quick Tour”. The Embedded Wizard User Manual is part of the Embedded Wizard installation (please see subdirectory \EmbeddedWizard\Doc) and it is available at http://www.embedded-wizard.de within the section Documentation. To help you, to get familiar with Embedded Wizard faster, we have created several tutorials for beginners as well as advanced users including step-by-step example projects. These tutorials are part of the Embedded Wizard installation (please see subdirectory \EmbeddedWizard\Tutorial_Mosaic20) and they are also provided at http://www.embedded-wizard.de as part of the available Documentation. For specific questions related to your project, please visit the Help & Support page. You will find a collection of Frequently Asked Questions as well as information to contact our support team. www.embedded-wizard.de Copyright TARA Systems GmbH Page 14
© Copyright 2024