{"id":183058,"date":"2024-07-30T07:37:38","date_gmt":"2024-07-30T07:37:38","guid":{"rendered":"https:\/\/innovationspace.ansys.com\/knowledge\/?post_type=topic&#038;p=183058"},"modified":"2025-02-26T17:02:39","modified_gmt":"2025-02-26T17:02:39","slug":"scade-smart-boiler-control-integrating-a-next-gen-hmi-onto-a-hardware-target","status":"publish","type":"topic","link":"https:\/\/innovationspace.ansys.com\/knowledge\/forums\/topic\/scade-smart-boiler-control-integrating-a-next-gen-hmi-onto-a-hardware-target\/","title":{"rendered":"SCADE Smart Boiler Control \u2013 Integrating a next-gen HMI onto a hardware target"},"content":{"rendered":"<hr \/>\n<p>This article is part of an <strong>embedded Human Machine Interface (HMI) design blog series<\/strong>. It details the process of designing a next generation embedded HMI for the control of an industrial steam boiler and implementing it with Ansys SCADE. You can find links to each part below:<\/p>\n<ul>\n<li><a href=\"https:\/\/innovationspace.ansys.com\/knowledge\/forums\/topic\/scade-smart-boiler-control-designing-a-next-gen-embedded-hmi\/\">Part 1 &#8211; Designing a next-gen embedded HMI<\/a><\/li>\n<li><a href=\"https:\/\/innovationspace.ansys.com\/knowledge\/forums\/topic\/scade-smart-boiler-control-implementing-a-next-gen-hmi-in-scade-display\/\">Part 2 &#8211; Implementing a next-gen HMI in SCADE Display<\/a><\/li>\n<li><a href=\"https:\/\/innovationspace.ansys.com\/knowledge\/forums\/topic\/scade-smart-boiler-control-powering-a-next-gen-hmi-with-scade-suite\/\">Part 3 &#8211; Powering a next-gen HMI with SCADE Suite<\/a><\/li>\n<li><a href=\"https:\/\/innovationspace.ansys.com\/knowledge\/forums\/topic\/scade-smart-boiler-control-integrating-a-next-gen-hmi-onto-a-hardware-target\/\">Part 4 &#8211; Integrating a next-gen HMI onto a hardware target<\/a><\/li>\n<\/ul>\n<hr \/>\n<h3  id=\"INTRODUCTION\">Introduction<\/h3>\n<p>This article presents an overview of the integration of a SCADE-developed HMI for an industrial steam boiler onto a realistic hardware target.<\/p>\n<p>The steam boiler is like the one you&#8217;d find in a nuclear power plant. It uses a heat source (e.g. nuclear fuel) to produce steam. It is controlled by a reactive control loop that balances sensor readings (temperature, steam pressure, water level) within acceptable parameters by using actuators (water injection valves).<\/p>\n<p>In our previous article, we used SCADE Display to implement the HMI panel and SCADE Suite for the panel behavior. We will now use the SCADE certified code generators to generate C code from our models. We&#8217;ll then embed it onto a hardware target.<\/p>\n<p>As a reminder, here is what our graphical panel looks like:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2024\/07\/scade-016-hmi-overview.jpg\" style=\"max-height: 500px !important\" \/><br \/>\n    <em>Overview of our HMI panel in rescue mode<\/em>\n<\/p>\n<h3  id=\"HARDWARE-TARGET\">Hardware target <\/h3>\n<p>In the world of safety-critical applications, application code usually runs on specialized technological platforms. Hardware tends to be ruggedized to resist adverse conditions: vibration, wide temperature ranges or even harsh radiation. CPUs may use reduced instruction set (RISC) architectures instead of the ubiquitous x86 architecture found in desktops and laptops. Operating systems tend to be real-time (RTOS), as the timely computation of results matters as much as the results themselves.<\/p>\n<p>In our case, we will be using two distinct environments:<\/p>\n<ul>\n<li>Our development machine is a laptop with an Intel Core-i7 x86-64 CPU and an RTX A2000 GPU, running Windows 11.<\/li>\n<li>Our Smart Boiler hardware is an i.MX 8 board with an ARM Cortex-A53 CPU and a GC7000 GPU, running a Linux OS. We will be using an external display screen connected to the board via an HDMI connector.<\/li>\n<\/ul>\n<h3  id=\"CODE-GENERATION-IN-SCADE\">Code generation in SCADE<\/h3>\n<p>SCADE relies on qualified code generators to generate safe, embeddable, platform-independent C code. Let&#8217;s unpack this:<\/p>\n<ul>\n<li>The code is <strong>safe<\/strong> because the Scade language avoids many categories of bugs by construction (e.g. uninitialized memory access), and because our KCG code generator is qualified to the highest levels of safety with key safety standards (such as DO-178C, ISO26262, EN50128 or IEC 61508).<\/li>\n<li>The code is <strong>embeddable<\/strong> because it&#8217;s ready to be compiled and executed on various hardware platforms without modification. For SCADE Display graphical panels, the target just needs to support some flavor of OpenGL.<\/li>\n<li>The code is <strong>platform-independent<\/strong> because no system calls are made in it. Aside from drawing calls for graphical panel code, there are no I\/Os, no filesystem interaction, no dynamic memory allocation, no networking. Interaction with the outside world (e.g. through input devices) is managed by reading\/writing pre-allocated structures.<\/li>\n<\/ul>\n<h4  id=\"CODE-INTEGRATION\">Code Integration<\/h4>\n<p>Running a program built with SCADE Display &amp; SCADE Suite requires a small integration layer that performs the program&#8217;s initialization phase. This code performs the following activities:<\/p>\n<ul>\n<li>Allocate a known, static amount of memory for the program<\/li>\n<li>Create and initialize structures that will be used by the generated code<\/li>\n<li>Initialize display drivers<\/li>\n<li>Initialize input devices<\/li>\n<li>Call the model&#8217;s entry-point operator.<\/li>\n<\/ul>\n<p>For real-time operating systems that use a task scheduler, integration code must create and launch a task to run the SCADE model&#8217;s main operator.<\/p>\n<p>SCADE Suite includes wrappers for Windows host and a selection of widely-used embedded targets. These wrappers automatically generate the integration code as part of the push-button build from the SCADE Display IDE.<\/p>\n<h4  id=\"GRAPHICS-DRIVERS\">Graphics drivers<\/h4>\n<p>SCADE Display supports many flavors of OpenGL (vanilla, ES, SC) in different versions. Each one has a slightly different API shape: the embedded and safety-critical flavors offer less functions. To accommodate this, SCADE relies on a middleware library called OGLX.<\/p>\n<p>In practice, this is the flow of drawing calls in a SCADE Display program:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2024\/07\/scade-016-call-stack.svg\" style=\"max-height: 500px !important\" \/><br \/>\n    <em>Drawing call flow for a SCADE Display program<\/em>\n<\/p>\n<p>SGL is a higher-level interface provided for graphical calls by OGLX. They allow the SCADE program to speak a &#8220;common language&#8221; that can then be adapted by the library into calls in the corresponding OpenGL flavor.<\/p>\n<p>OGLX is written in C. Its source code is certifiable to the highest levels of safety with key safety standards. Sources are delivered with SCADE and must be configured, compiled and linked for the target hardware. This is typically achieved from a Windows host computer with correct parameters for cross-compilation to the desired target.<\/p>\n<h4  id=\"COMPILATION-PIPELINE\">Compilation pipeline<\/h4>\n<p>Overall, the generation and compilation pipeline looks like this:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2024\/07\/scade-016-integration-overview.svg\" style=\"max-height: 500px !important\" \/><br \/>\n    <em>Overall generation pipeline for a SCADE Suite \/ SCADE Display program<\/em>\n<\/p>\n<h4  id=\"GENERATING-FOR-WINDOWS-HOST\">Generating for Windows host<\/h4>\n<p>While developing and testing a SCADE application, engineers need to run it frequently. Since the SCADE IDE runs on Windows, generating code and building it for a Windows host target is a common use case. It is therefore supported as a &#8220;push button&#8221; activity.<\/p>\n<p>In our Smart Boiler example, the SCADE Display model includes the SCADE Suite model as a library. So, the whole process is triggered from a SCADE Display Generator Configuration.<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2024\/07\/scade-016-display-gen-conf-windows.png\" style=\"max-height: 500px !important\" \/><br \/>\n    <em>Windows executable generation configuration in SCADE Display<\/em>\n<\/p>\n<p>This configuration triggers the whole process: code generation using KCG Display for the Display model and KCG for the Suite model, generation of integration code for a Windows host, compilation and linking of the program for a Windows host, and launch of the finalized program in a new window.<\/p>\n<p>Note: to save time in this case, the OGLX library is precompiled.<\/p>\n<p>In addition to the Windows generation configuration, you can see above another one called Simulation. This simulation launches the program with debugging enabled. An integrated window allows to run the program at various speeds, pause it, interact with the HMI, and watch underlying variables.<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2024\/07\/scade-016-display-co-simulation.png\" style=\"max-height: 500px !important\" \/><br \/>\n    <em>Interactive co-simulation window<\/em>\n<\/p>\n<h4  id=\"GENERATING-FOR-LINUX-IMX-8\">Generating for Linux iMX 8<\/h4>\n<p>Now, let&#8217;s look at generating the program for its intended embedded target. For our Smart Boiler, we have chosen a widely-used hardware platform:<\/p>\n<ul>\n<li>Hardware platform:  NXP i.MX 8QuadMax MEK <\/li>\n<li>Graphics: GC7000 &#8211; Vivante<\/li>\n<li>CPU: ARM Cortex-A53<\/li>\n<li>OS: Yocto Linux 4.14.78<\/li>\n<li>Graphics Driver: OpenGL SC 2.0 &#8211; CoreAVI <\/li>\n<li>Display: external HDMI screen<\/li>\n<\/ul>\n<p>We start by launching the Code generation configuration from SCADE Display. This generates C code for the SCADE Display and SCADE Suite models.<\/p>\n<h4  id=\"OGLX-CONFIGURATION-FOR-LINUX-IMX8\">OGLX configuration for Linux iMX8<\/h4>\n<p>Next, we retrieve the OGLX source code and ready it for cross-compilation via the included <code>oglx_port.h<\/code> file. While the file can be modified to accommodate the desired target, in our case, we can simply rely on one of the pre-included macros to control common target restrictions and build features.<\/p>\n<p>Our target has no specific restriction, so we don&#8217;t need to define any of the following macros:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"color: #999988;font-style: italic\">\/*****************************************************************************************************************<\/span>\r\n<span style=\"color: #999988;font-style: italic\"> Specific OGLX porting macro definitions<\/span>\r\n\r\n<span style=\"color: #999988;font-style: italic\"> Following macros can be defined if the user environment does not provide a feature<\/span>\r\n<span style=\"color: #999988;font-style: italic\">     OGLX_NO_VERTEX_ARRAY | Vertex arrays are not provided by the used OpenGL driver<\/span>\r\n<span style=\"color: #999988;font-style: italic\">     OGLX_NO_GLCLIPPLANE  | Clip planes are not provided by the used OpenGL driver<\/span>\r\n<span style=\"color: #999988;font-style: italic\">     OGLX_NO_64_BITS      | 64 bits integers are not provided by the compiler environment<\/span>\r\n<span style=\"color: #999988;font-style: italic\">     OGLX_NO_FTOL2        | Cast between float and 64 bits integers is not provided by the compiler environment<\/span>\r\n<span style=\"color: #999988;font-style: italic\"> Following macros can be undefined if the user environment does not provide a feature<\/span>\r\n<span style=\"color: #999988;font-style: italic\">     OGLX_FBO             | Static mechanism uses frame buffer objects (To undefine if FBOs are not provided)<\/span>\r\n<span style=\"color: #999988;font-style: italic\">     OGLX_DISPLAY_LISTS   | Static mechanism uses display lists (To undefine if display lists are not provided)<\/span>\r\n\r\n<span style=\"color: #999988;font-style: italic\">*****************************************************************************************************************\/<\/span>\r\n<\/pre>\n<\/div>\n<p>We want to use an OpenGL SC2 driver, so we define the <code>SC2_DEV_ENV<\/code> macro: <\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"color: #999999;font-weight: bold\">#elif defined(SC2_DEV_ENV)<\/span>\r\n<span style=\"color: #999999;font-weight: bold\">#include<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #999988;font-style: italic\">&lt;GLSC2\/glsc2.h&gt;<\/span>\r\n<span style=\"color: #999999;font-weight: bold\">#define OGLX_FBO<\/span>\r\n<span style=\"color: #999999;font-weight: bold\">#define OGLX_MASK_FFFF 0xFFFF<\/span>\r\n<\/pre>\n<\/div>\n<p>With this single change, we can pre-compile OGLX as a static library (<code>liboglx.a<\/code>).<\/p>\n<h4  id=\"MAIN-FUNCTION-FOR-LINUX-IMX8\">Main function for Linux iMX8<\/h4>\n<p>We now need to write a <code>main.c<\/code> file to tie everything together.<\/p>\n<p>Our main function&#8217;s job is to:<\/p>\n<ul>\n<li>Initialize the display in the correct resolution<\/li>\n<li>Initialize OGLX and the underlying display driver<\/li>\n<li>Start an infinite rendering loop to:\n<ul>\n<li>Render the next frame into a hidden graphical buffer<\/li>\n<li>Swap the hidden and screen buffers to display our new frame<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>We also elect to start our main function in its own thread, but we will leave details out for simplicity&#8217;s sake. Here&#8217;s what the code for our main function looks like:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"color: #445588;font-weight: bold\">void<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #990000;font-weight: bold\">sampleApp1Thread<\/span>(<span style=\"color: #445588;font-weight: bold\">void<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>pHead)\r\n{\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Initialize required structures *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span>uint32<span style=\"color: #bbbbbb\"> <\/span>threadId<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>((uint32<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>)pHead);\r\n<span style=\"color: #bbbbbb\">    <\/span>EGLDisplay<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>dpy<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #999999\">NULL<\/span>;\r\n<span style=\"color: #bbbbbb\">    <\/span>EGLContext<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>ctx<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #999999\">NULL<\/span>;\r\n<span style=\"color: #bbbbbb\">    <\/span>EGLConfig<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>cfg<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #999999\">NULL<\/span>;\r\n<span style=\"color: #bbbbbb\">    <\/span>EGLSurface<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>sfc<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #999999\">NULL<\/span>;\r\n<span style=\"color: #bbbbbb\">    <\/span>EGLNativeDisplayType<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>dpyId<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #999999\">NULL<\/span>;\r\n<span style=\"color: #bbbbbb\">    <\/span>EGLBoolean<span style=\"color: #bbbbbb\"> <\/span>errorStatus<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>EGL_TRUE;\r\n<span style=\"color: #bbbbbb\">    <\/span>GLuint<span style=\"color: #bbbbbb\"> <\/span>shaderProgram<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">0<\/span>;\r\n<span style=\"color: #bbbbbb\">    <\/span>GLint<span style=\"color: #bbbbbb\"> <\/span>aVertex<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">0<\/span>;\r\n<span style=\"color: #bbbbbb\">    <\/span>GLint<span style=\"color: #bbbbbb\"> <\/span>aVertexColor<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">0<\/span>;\r\n<span style=\"color: #bbbbbb\">    <\/span>GLint<span style=\"color: #bbbbbb\"> <\/span>aTexCoord<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">0<\/span>;\r\n<span style=\"color: #bbbbbb\">    <\/span>GLint<span style=\"color: #bbbbbb\"> <\/span>uTexUnit<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">0<\/span>;\r\n<span style=\"color: #bbbbbb\">    <\/span>GLint<span style=\"color: #bbbbbb\"> <\/span>uRotation<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">0<\/span>;\r\n<span style=\"color: #bbbbbb\"> <\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span>dpy<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">&amp;<\/span>f_dpy;\r\n<span style=\"color: #bbbbbb\">    <\/span>ctx<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">&amp;<\/span>f_eglContext;\r\n<span style=\"color: #bbbbbb\">    <\/span>cfg<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">&amp;<\/span>f_config;\r\n<span style=\"color: #bbbbbb\">    <\/span>sfc<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">&amp;<\/span>f_surface;\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Initialize a display using EGL *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span>errorStatus<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>egl_init(dpy,<span style=\"color: #bbbbbb\"> <\/span>ctx,<span style=\"color: #bbbbbb\"> <\/span>cfg,<span style=\"color: #bbbbbb\"> <\/span>sfc);\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"font-weight: bold\">if<\/span><span style=\"color: #bbbbbb\"> <\/span>(EGL_FALSE<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">==<\/span><span style=\"color: #bbbbbb\"> <\/span>errorStatus)\r\n<span style=\"color: #bbbbbb\">    <\/span>{\r\n<span style=\"color: #bbbbbb\">        <\/span>printf(<span style=\"color: #bb8844\">&quot;[SampleApp1:Thread%d] Display failed creation. Aborting\\n&quot;<\/span>,<span style=\"color: #bbbbbb\"> <\/span>threadId);\r\n<span style=\"color: #bbbbbb\">        <\/span><span style=\"font-weight: bold\">return<\/span>;\r\n<span style=\"color: #bbbbbb\">    <\/span>}\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Initialize OGLX *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span>oglx_init();\r\n<span style=\"color: #bbbbbb\">    <\/span>init_scene();\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Main loop proper *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"font-weight: bold\">while<\/span><span style=\"color: #bbbbbb\"> <\/span>(TRUE)\r\n<span style=\"color: #bbbbbb\">    <\/span>{\r\n<span style=\"color: #bbbbbb\">        <\/span><span style=\"color: #999988;font-style: italic\">\/* Render the next frame into a buffer *\/<\/span>\r\n<span style=\"color: #bbbbbb\">        <\/span>display_callback();\r\n\r\n<span style=\"color: #bbbbbb\">        <\/span><span style=\"color: #999988;font-style: italic\">\/* Swap buffers to display the next frame *\/<\/span>\r\n<span style=\"color: #bbbbbb\">        <\/span><span style=\"font-weight: bold\">if<\/span><span style=\"color: #bbbbbb\"> <\/span>(EGL_TRUE<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">!=<\/span><span style=\"color: #bbbbbb\"> <\/span>eglSwapBuffers(<span style=\"font-weight: bold\">*<\/span>dpy,<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>sfc))\r\n<span style=\"color: #bbbbbb\">        <\/span>{\r\n<span style=\"color: #bbbbbb\">            <\/span>printf(<span style=\"color: #bb8844\">&quot;[SampleApp1] ERROR: eglSwapBuffers() unexpected error rendering to display %d&quot;<\/span>,<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>((uint32<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>)dpy));\r\n<span style=\"color: #bbbbbb\">        <\/span>}\r\n<span style=\"color: #bbbbbb\">    <\/span>}\r\n}\r\n<\/pre>\n<\/div>\n<p>Now, let&#8217;s dive further into interesting details of what happens under the hood.<\/p>\n<h5  id=\"CREATE-A-DISPLAY-USING-EGL\">Create a display using EGL<\/h5>\n<p>EGL is a native platform interface that connects the windowing systems to one of Khronos&#8217; APIs, e.g. OpenGL SC 2.<\/p>\n<p>Before getting to OpenGL, we first need to set it up. We will create an EGL render context using OpenGL SC as the client API connecting to the &#8220;display&#8221;. The term display may sound a bit odd at first if you&#8217;re used to Windows. It may be more familiar if you&#8217;re coming from Linux.<\/p>\n<p>Let&#8217;s look at some key things happening inside of our <code>egl_init(...)<\/code> function call above.<\/p>\n<p>First, we get a device context from our window and connect it to the EGL display:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Obtain an EGL Display *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"font-weight: bold\">if<\/span><span style=\"color: #bbbbbb\"> <\/span>(EGL_TRUE<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">==<\/span><span style=\"color: #bbbbbb\"> <\/span>errorStatus)\r\n<span style=\"color: #bbbbbb\">    <\/span>{\r\n<span style=\"color: #bbbbbb\">        <\/span><span style=\"font-weight: bold\">*<\/span>dpy<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>eglGetDisplay((EGLNativeDisplayType)<span style=\"font-weight: bold\">&amp;<\/span>nativeDisplay);\r\n\r\n<span style=\"color: #bbbbbb\">        <\/span><span style=\"font-weight: bold\">if<\/span><span style=\"color: #bbbbbb\"> <\/span>(EGL_NO_DISPLAY<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">==<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>dpy)\r\n<span style=\"color: #bbbbbb\">        <\/span>{\r\n<span style=\"color: #bbbbbb\">            <\/span>printf(<span style=\"color: #bb8844\">&quot;[SampleApp1] ERROR: Failed to obtain EGL display\\n&quot;<\/span>);\r\n<span style=\"color: #bbbbbb\">            <\/span>errorStatus<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>EGL_FALSE;\r\n<span style=\"color: #bbbbbb\">        <\/span>}\r\n<span style=\"color: #bbbbbb\">    <\/span>}\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Initialize EGL *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"font-weight: bold\">if<\/span><span style=\"color: #bbbbbb\"> <\/span>(EGL_TRUE<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">==<\/span><span style=\"color: #bbbbbb\"> <\/span>errorStatus)\r\n<span style=\"color: #bbbbbb\">    <\/span>{\r\n<span style=\"color: #bbbbbb\">        <\/span>errorStatus<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>eglInitialize(<span style=\"font-weight: bold\">*<\/span>dpy,<span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">0<\/span>,<span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">0<\/span>);\r\n<span style=\"color: #bbbbbb\">    <\/span>}\r\n<\/pre>\n<\/div>\n<p>Then, we select a valid EGL configuration that supports our requested client API and fits our description. This is similar to finding a suitable pixel format for context creation in OpenGL:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"font-weight: bold\">static<\/span><span style=\"color: #bbbbbb\"> <\/span>EGLint<span style=\"color: #bbbbbb\">           <\/span>f_attribs[]<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>{<span style=\"color: #bbbbbb\"> <\/span>EGL_BUFFER_SIZE,<span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">32<\/span>,<span style=\"color: #bbbbbb\"> <\/span>EGL_DEPTH_SIZE,<span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">16<\/span>,<span style=\"color: #bbbbbb\"> <\/span>EGL_SAMPLE_BUFFERS,<span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">1<\/span>,<span style=\"color: #bbbbbb\"> <\/span>EGL_SAMPLES,<span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">4<\/span>,<span style=\"color: #bbbbbb\"> <\/span>EGL_NONE<span style=\"color: #bbbbbb\"> <\/span>};\r\n<\/pre>\n<\/div>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Obtain the first configuration with a buffer size of 32 bits *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"font-weight: bold\">if<\/span><span style=\"color: #bbbbbb\"> <\/span>(EGL_TRUE<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">==<\/span><span style=\"color: #bbbbbb\"> <\/span>errorStatus)\r\n<span style=\"color: #bbbbbb\">    <\/span>{\r\n<span style=\"color: #bbbbbb\">        <\/span>errorStatus<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>eglChooseConfig(<span style=\"font-weight: bold\">*<\/span>dpy,<span style=\"color: #bbbbbb\"> <\/span>f_attribs,<span style=\"color: #bbbbbb\"> <\/span>cfg,<span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">1<\/span>,<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">&amp;<\/span>numCfgs);\r\n<span style=\"color: #bbbbbb\">    <\/span>}\r\n<\/pre>\n<\/div>\n<p>Once we&#8217;ve got a valid configuration, we can create a window surface that&#8217;ll be used for rendering:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Create an EGL Surface *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"font-weight: bold\">if<\/span><span style=\"color: #bbbbbb\"> <\/span>(EGL_TRUE<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">==<\/span><span style=\"color: #bbbbbb\"> <\/span>errorStatus)\r\n<span style=\"color: #bbbbbb\">    <\/span>{\r\n<span style=\"color: #bbbbbb\">        <\/span><span style=\"font-weight: bold\">*<\/span>sfc<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>eglCreateWindowSurface(<span style=\"font-weight: bold\">*<\/span>dpy,<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>cfg,<span style=\"color: #bbbbbb\"> <\/span>win,<span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #999999\">NULL<\/span>);\r\n\r\n<span style=\"color: #bbbbbb\">        <\/span><span style=\"font-weight: bold\">if<\/span><span style=\"color: #bbbbbb\"> <\/span>(EGL_NO_SURFACE<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">==<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>sfc)\r\n<span style=\"color: #bbbbbb\">        <\/span>{\r\n<span style=\"color: #bbbbbb\">            <\/span>printf(<span style=\"color: #bb8844\">&quot;[SampleApp1] ERROR: Failed to create EGL window surface\\n&quot;<\/span>);\r\n<span style=\"color: #bbbbbb\">            <\/span>errorStatus<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>EGL_FALSE;\r\n<span style=\"color: #bbbbbb\">        <\/span>}\r\n<span style=\"color: #bbbbbb\">    <\/span>}\r\n<\/pre>\n<\/div>\n<p>Getting back to OpenGL terminology, we&#8217;re now ready to create our OpenGL SC rendering context:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Create an EGL Context *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"font-weight: bold\">if<\/span><span style=\"color: #bbbbbb\"> <\/span>(EGL_TRUE<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">==<\/span><span style=\"color: #bbbbbb\"> <\/span>errorStatus)\r\n<span style=\"color: #bbbbbb\">    <\/span>{\r\n<span style=\"color: #bbbbbb\">        <\/span><span style=\"font-weight: bold\">*<\/span>ctx<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>eglCreateContext(<span style=\"font-weight: bold\">*<\/span>dpy,<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>cfg,<span style=\"color: #bbbbbb\"> <\/span>EGL_NO_CONTEXT,<span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #999999\">NULL<\/span>);\r\n<span style=\"color: #bbbbbb\">       <\/span><span style=\"color: #999988;font-style: italic\">\/\/ *ctx = eglCreateContext(*dpy, *cfg, EGL_NO_CONTEXT, f_contextAttribs);<\/span>\r\n<span style=\"color: #bbbbbb\">        <\/span>\r\n\r\n<span style=\"color: #bbbbbb\">        <\/span><span style=\"font-weight: bold\">if<\/span><span style=\"color: #bbbbbb\"> <\/span>(EGL_NO_CONTEXT<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">==<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>ctx)\r\n<span style=\"color: #bbbbbb\">        <\/span>{\r\n<span style=\"color: #bbbbbb\">            <\/span>printf(<span style=\"color: #bb8844\">&quot;[SampleApp1] ERROR: Failed to create EGL context\\n&quot;<\/span>);\r\n<span style=\"color: #bbbbbb\">            <\/span>errorStatus<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>EGL_FALSE;\r\n<span style=\"color: #bbbbbb\">        <\/span>}\r\n<span style=\"color: #bbbbbb\">    <\/span>}\r\n<\/pre>\n<\/div>\n<p>Finally, we need to make our EGL context current:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Make this EGL context current *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"font-weight: bold\">if<\/span><span style=\"color: #bbbbbb\"> <\/span>(EGL_TRUE<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">==<\/span><span style=\"color: #bbbbbb\"> <\/span>errorStatus)\r\n<span style=\"color: #bbbbbb\">    <\/span>{\r\n<span style=\"color: #bbbbbb\">        <\/span>errorStatus<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>eglMakeCurrent(<span style=\"font-weight: bold\">*<\/span>dpy,<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>sfc,<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>sfc,<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>ctx);\r\n\r\n<span style=\"color: #bbbbbb\">        <\/span><span style=\"color: #999988;font-style: italic\">\/* Setting swap interval to 1 will rely on vsync *\/<\/span>\r\n<span style=\"color: #bbbbbb\">        <\/span>eglSwapInterval(<span style=\"font-weight: bold\">*<\/span>dpy,<span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">1<\/span>);\r\n<span style=\"color: #bbbbbb\">    <\/span>}\r\n<\/pre>\n<\/div>\n<h5  id=\"INITIALIZE-OGLX\">Initialize OGLX<\/h5>\n<p>We&#8217;re almost ready to put something on the screen. We first need to initialize OGLX before rendering in our EGL context:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"color: #999988;font-style: italic\">\/*+ FUNCTION DESCRIPTION ----------------------------------------------<\/span>\r\n<span style=\"color: #999988;font-style: italic\">    NAME:           oglx_init<\/span>\r\n<span style=\"color: #999988;font-style: italic\">    DESCRIPTION:    Complete initialization sequence for OGLX<\/span>\r\n<span style=\"color: #999988;font-style: italic\">---------------------------------------------------------------------+*\/<\/span>\r\n<span style=\"color: #445588;font-weight: bold\">void<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #990000;font-weight: bold\">oglx_init<\/span>()\r\n{\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Initialize OGLX *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"font-weight: bold\">static<\/span><span style=\"color: #bbbbbb\"> <\/span>SGLbyte<span style=\"color: #bbbbbb\"> <\/span>glob_tub_texture_buffer[<span style=\"color: #009999\">4<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span><span style=\"color: #bbbbbb\"> <\/span>SGL_TEXTURE_MAX_WIDTH<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span><span style=\"color: #bbbbbb\"> <\/span>SGL_TEXTURE_MAX_HEIGHT];\r\n<span style=\"color: #bbbbbb\">    <\/span>sgl_texture_attrib<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>glob_texture_attrib<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>malloc(<span style=\"font-weight: bold\">sizeof<\/span>(sgl_texture_attrib)<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span><span style=\"color: #bbbbbb\"> <\/span>getTextureTableSize());\r\n<span style=\"color: #bbbbbb\">    <\/span>sgl_gradient_attrib<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span>glob_gradient_attrib<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>malloc(<span style=\"font-weight: bold\">sizeof<\/span>(sgl_gradient_attrib)<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span><span style=\"color: #bbbbbb\"> <\/span>getGradientTableSize());\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"font-weight: bold\">static<\/span><span style=\"color: #bbbbbb\"> <\/span>sgl_parameters<span style=\"color: #bbbbbb\"> <\/span>lParameters;\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span>lParameters.ul_screen_width<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>getW();\r\n<span style=\"color: #bbbbbb\">    <\/span>lParameters.ul_screen_height<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>getH();\r\n<span style=\"color: #bbbbbb\">    <\/span>lParameters.pb_texture_buffer<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>glob_tub_texture_buffer;\r\n<span style=\"color: #bbbbbb\">    <\/span>lParameters.ul_texture_max_width<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>SGL_TEXTURE_MAX_WIDTH;\r\n<span style=\"color: #bbbbbb\">    <\/span>lParameters.ul_texture_max_height<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>SGL_TEXTURE_MAX_HEIGHT;\r\n<span style=\"color: #bbbbbb\">    <\/span>lParameters.p_texture_attrib<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>glob_texture_attrib;\r\n<span style=\"color: #bbbbbb\">    <\/span>lParameters.ul_number_of_textures<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>getTextureTableSize();\r\n<span style=\"color: #bbbbbb\">    <\/span>lParameters.p_gradient_attrib<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>glob_gradient_attrib;\r\n<span style=\"color: #bbbbbb\">    <\/span>lParameters.ul_number_of_gradients<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>getGradientTableSize();\r\n<span style=\"color: #bbbbbb\">    <\/span>lParameters.ul_binary_format<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>GL_PROGRAM_BINARY_COREAVI;\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span>sglInit(<span style=\"font-weight: bold\">&amp;<\/span>glob_s_context,<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">&amp;<\/span>lParameters);\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Load the color table *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span>sglColorPointerf(getColorTable(),<span style=\"color: #bbbbbb\"> <\/span>getColorTableSize());\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/*sglSetRenderMode(SGL_RAW_OPENGL_LINES);*\/<\/span>\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span>sglLineWidthPointerf(getLineWidthTable(),<span style=\"color: #bbbbbb\"> <\/span>getLineWidthTableSize());\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Load the line stipple table *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span>sglLineStipplePointer(getLineStippleTable(),<span style=\"color: #bbbbbb\"> <\/span>getLineStippleTableSize());\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Load the fonts table *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span>sgluLoadFonts(getFontTable());\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span>sglViewport(<span style=\"color: #009999\">0L<\/span>,<span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">0L<\/span>,<span style=\"color: #bbbbbb\"> <\/span>getW(),<span style=\"color: #bbbbbb\"> <\/span>getH());\r\n<span style=\"color: #bbbbbb\">    <\/span>sglOrtho(<span style=\"color: #009999\">0<\/span>,<span style=\"color: #bbbbbb\"> <\/span>(<span style=\"color: #445588;font-weight: bold\">float<\/span>)<span style=\"color: #bbbbbb\"> <\/span>(getW()<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span><span style=\"color: #bbbbbb\"> <\/span>getRatioX()<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">\/<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">1.0F<\/span>),<span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">0<\/span>,<span style=\"color: #bbbbbb\"> <\/span>(<span style=\"color: #445588;font-weight: bold\">float<\/span>)<span style=\"color: #bbbbbb\"> <\/span>(getH()<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">*<\/span><span style=\"color: #bbbbbb\"> <\/span>getRatioY()<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">\/<\/span><span style=\"color: #bbbbbb\"> <\/span><span style=\"color: #009999\">1.0F<\/span>));\r\n\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"color: #999988;font-style: italic\">\/* Check if there is an OpenGL error after OGLX initialization *\/<\/span>\r\n<span style=\"color: #bbbbbb\">    <\/span>glErrorStatus<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">=<\/span><span style=\"color: #bbbbbb\"> <\/span>glGetError();\r\n<span style=\"color: #bbbbbb\">    <\/span><span style=\"font-weight: bold\">if<\/span><span style=\"color: #bbbbbb\"> <\/span>(glErrorStatus<span style=\"color: #bbbbbb\"> <\/span><span style=\"font-weight: bold\">!=<\/span><span style=\"color: #bbbbbb\"> <\/span>GL_NO_ERROR)<span style=\"color: #bbbbbb\"> <\/span>{\r\n<span style=\"color: #bbbbbb\">        <\/span>printf(<span style=\"color: #bb8844\">&quot;\\nError %d raised during OGLX initialization\\n\\n&quot;<\/span>,<span style=\"color: #bbbbbb\"> <\/span>glErrorStatus);\r\n<span style=\"color: #bbbbbb\">    <\/span>}\r\n}\r\n<\/pre>\n<\/div>\n<h4  id=\"COMPILATION-AT-LAST\">Compilation, at last<\/h4>\n<p>We are now ready to cross-compile and link our complete program. For this, we use a makefile distributed by the graphics driver provider.<\/p>\n<p>After compilation, we obtain a single binary executable file, built from our generated sources, our integration code, and the pre-compiled OGLX static library.<\/p>\n<p>We place this file in a predefined folder of our Linux distribution and copy everything onto an SD card. We insert the SD card into our i.MX 8 board, boot it up, and&#8230;<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2024\/07\/scade-016-photo.jpg\" style=\"max-height: 500px !important\" \/><br \/>\n    <em>Our Smart Boiler model in action on an i.MX 8 board<\/em>\n<\/p>\n<p>There we have it! Our embedded HMI is running on its hardware target. Note that, despite our best efforts, we were not able to procure a nuclear reactor steam boiler for a photo-op in our offices<a href=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2024\/07\/scade-016-nuclear-reactor.gif\">.<\/a> The pictured configuration therefore relies on the software plant model, running on the i.MX 8 board as part of the SCADE program.<\/p>\n<h3  id=\"THANK-YOU-FOR-READING\">Thank you for reading<\/h3>\n<p>In this blog, we looked at the integration of the logic for an embedded HMI, developed in SCADE Display and SCADE Suite. This concludes our Smart Boiler blog series.<\/p>\n<p>If you have a SCADE installation and if you&#8217;d like to play with the Smart Boiler model yourself, you may find it <a href=\"https:\/\/smart-boiler-control.examples.scade.docs.pyansys.com\/\">here on the Ansys GitHub<\/a>.<\/p>\n<p>If you&#8217;d like to learn more about Ansys Embedded Display solutions, we&#8217;d love to hear from you! Get in touch on our <a href=\"https:\/\/www.ansys.com\/products\/embedded-software\/ansys-scade-display\">SCADE Display product page<\/a>.<\/p>\n<h3  id=\"ABOUT-THE-AUTHORS\">About the authors<\/h3>\n<table style=\"border: none !important\">\n<tr>\n<td style=\"border: none !important\">\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2024\/09\/scade-ludovic-oddos.png\" style=\"max-height: 150px !important\" \/>\n        <\/td>\n<td style=\"border: none !important\">\n<p><strong>Ludovic Oddos<\/strong> (<a href=\"https:\/\/www.linkedin.com\/in\/ludovicoddos\/\">LinkedIn<\/a>) is a Lead Product Specialist at Ansys. He has been supporting SCADE field engagements, in many industries, for more than 15 years. He has deep expertise in embedded software and its integration into various target environments.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td style=\"border: none !important\">\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2024\/09\/scade-francois-couadau.png\" style=\"max-height: 150px !important\" \/>\n        <\/td>\n<td style=\"border: none !important\">\n<p><strong>Fran\u00e7ois Couadau<\/strong> (<a href=\"https:\/\/www.linkedin.com\/in\/fcouadau\/\">LinkedIn<\/a>) is a Senior Product Manager at Ansys. He works on embedded HMI software aspects in the SCADE and Scade One products. His past experience includes distributed systems and telecommunications.<\/p>\n<\/td>\n<\/tr>\n<\/table>\n","protected":false},"template":"","class_list":["post-183058","topic","type-topic","status-publish","hentry","topic-tag-hmi","topic-tag-logic","topic-tag-scade","topic-tag-suite","topic-tag-ui-ux"],"aioseo_notices":[],"acf":[],"custom_fields":[{"0":{"_edit_lock":["1740589277:1769"],"_edit_last":["1769"],"filter_by_optics_product":["Lumerical"],"_filter_by_optics_product":["field_64fb192ba3121"],"application_name":[""],"_application_name":["field_64a80903c8e15"],"family":[""],"_family":["field_64a809229a857"],"siebel_km_number":[""],"_siebel_km_number":["field_63ecbffce60db"],"salesforce_km_number":[""],"_salesforce_km_number":["field_63ecc018e60dc"],"km_published_date":[""],"_km_published_date":["field_64c77704499dd"],"product_version":[""],"_product_version":["field_64c776cb4fd2e"],"_bbp_forum_id":["27825"],"_bbp_topic_id":["196302"],"_bbp_author_ip":["192.104.24.227"],"_bbp_last_reply_id":["0"],"_bbp_last_active_id":["183059"],"_bbp_last_active_time":["2024-07-30 07:37:38"],"_bbp_reply_count":["0"],"_bbp_reply_count_hidden":["0"],"_bbp_voice_count":["0"],"_yoast_wpseo_content_score":["90"],"_yoast_wpseo_estimated-reading-time-minutes":["10"],"_yoast_wpseo_wordproof_timestamp":[""],"_btv_view_count":["2505"],"_bbp_likes_count":["6"],"_aioseo_title":[null],"_aioseo_description":[null],"_aioseo_keywords":["a:0:{}"],"_aioseo_og_title":[null],"_aioseo_og_description":[null],"_aioseo_og_article_section":[""],"_aioseo_og_article_tags":["a:0:{}"],"_aioseo_twitter_title":[null],"_aioseo_twitter_description":[null]},"test":"solution"}],"_links":{"self":[{"href":"https:\/\/innovationspace.ansys.com\/knowledge\/wp-json\/wp\/v2\/topics\/183058","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/innovationspace.ansys.com\/knowledge\/wp-json\/wp\/v2\/topics"}],"about":[{"href":"https:\/\/innovationspace.ansys.com\/knowledge\/wp-json\/wp\/v2\/types\/topic"}],"version-history":[{"count":8,"href":"https:\/\/innovationspace.ansys.com\/knowledge\/wp-json\/wp\/v2\/topics\/183058\/revisions"}],"predecessor-version":[{"id":196302,"href":"https:\/\/innovationspace.ansys.com\/knowledge\/wp-json\/wp\/v2\/topics\/183058\/revisions\/196302"}],"wp:attachment":[{"href":"https:\/\/innovationspace.ansys.com\/knowledge\/wp-json\/wp\/v2\/media?parent=183058"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}