Dual Targeting and Agile Prototyping of Embedded Software on Windows

share on: 
QWin prototype on Windows
Table of Contents

When developing embedded code for devices with non-trivial user interfaces, it often pays off to build a prototype (virtual prototype) of the embedded system of a PC. The strategy is called “dual targeting”, because you develop software on one machine (e.g., Windows PC) and run it on a deeply embedded target, as well as on the PC. Dual targeting is the main strategy for avoiding the “target system bottleneck” in the agile embedded software development, popularized in the book “Test-Driven Development for Embedded C” by James Grenning.

Avoiding Target Hardware Bottleneck with Dual Targeting

Please note that dual targeting does not mean that the embedded device has anything to do with the PC. Neither it means that the simulation must be cycle-exact with the embedded target CPU.

Dual targeting simply means that from day one, your embedded code (typically in C) is designed to run on at least two platforms: the final target hardware and your PC. All you really need for this is two C compilers: one for the PC and another for the embedded device.

However, the dual targeting strategy does require a specific way of designing the embedded software such that any target hardware dependencies are handled through a well-defined interface often called the Board Support Package (BSP). This interface has at least two implementations: one for the actual target and one for the PC, for example running Windows. With such interface in place, the bulk of the embedded code can remain completely unaware which BSP implementation it is linked to and so it can be developed quickly on the PC, but can also run on the target hardware without any changes.

While some embedded programmers can view dual targeting as a self-inflicted burden, the more experienced developers generally agree that paying attention to the boundaries between software and hardware is actually beneficial, because it results in more modular, more portable, and more maintainable software with much longer useful lifetime. The investment in dual targeting has also an immediate payback in the vastly accelerated compile-run-debug cycle, which is much faster and more productive on the powerful PC compared to much slower, recourse-constrained deeply embedded target with limited visibility into the running code.

Agile Rapid Prototyping of Embedded Software with Dual Targeting

Dual targeting can have many different objectives. For example, in the test-driven development (TDD) of embedded software, the objective is to build relatively concise unit tests and execute them on the desktop as console-type applications. The main challenge is management of the inter-module dependencies and flexibility of tests, but the overall architecture of the final product is of lesser concerns, as the unit tests are executed in isolation using special test harnesses.

However, dual targeting can also be used for (rapid) prototyping and simulating the whole embedded devices on the PC, not just executing unit tests. In this case, the objective is to build a possibly complete prototype of the embedded device as a GUI-type application. This approach is particularly interesting for embedded systems with non-trivial user interfaces, such as: home appliances, office equipment, thermostats, medical devices, industrial controllers, etc. As it turns out, significant percentage of the code embedded in all those devices is devoted to the user interface and can be, or even should be, developed on the desktop.

QWIN GUI Toolkit

When developing embedded code for devices with non-trivial user interfaces, one often runs into the problem of representing the embedded front panels as GUI elements on the PC. The problem is so common, that I’m really surprised that my internet search couldn’t uncover any simple C-only interface to the basic elements, such as LCDs, buttons, and LEDs. I’ve posted questions on StackOverflow, and other such forums, but again, I got recommendations for .NET, C#, VisualBasic, and many expensive proprietary tools, none of which provided an easy, direct binding to C. My objective is not really that complicated, yet it seems that every embedded developer has to re-invent this wheel over and over again.

QWin prototype on Windows

So, to help embedded developers interested in prototyping embedded devices on Windows, I have created a QWIN GUI Toolkit and have posted on GitHub (as part of the QTools collection). This toolkit relies only on the raw Win32 API in C and currently provides the following elements:

  • Graphic display for an efficient, pixel-addressable displays such as graphical LCDs, OLEDs, etc. with full 24-bit color.
  • Segment display for segmented display such as segment LCDs, and segment LEDs with generic, custom bitmaps for the segments.
  • Owner-drawn buttons with custom “depressed” and “released” bitmaps and capable of generating separate events when depressed and when released.

The toolkit comes with an Application Note, showing how to handle input from the owner-drawn buttons, regular buttons, keyboard, and the mouse. You can also view a 1-minute YouTube video “Flyn ‘n’ Shoot game on windows” that shows a virtual embedded board running a game.

Regarding the size and complexity of the QWIN GUI Toolkit, the implementation of the aforementioned GUI elements takes only about 250 lines of C. The example with all sources of input and a lot of comments amounts to some 300 lines of C. The toolkit has been tested with the free Microsoft Visual Studio Community IDE. Enjoy!


7 Responses

  1. It’s great to see this published. We’ve been doing dual targeting with more or less beatiful front-ends for the last 7 years. It is huge productivity booster for large class of embedded products, and especially those with hmi. It allows fast iterations, every stakeholder gets early feedback as there’s something visual, design is way more modular, it can be used as a training tool, you can nail down of the user interface very quickly, you can run test very easily on virtual platform, we also end up doing most of the debugging on virtual target (especially for communication with subsystems), … and the list goes on.

    Thanks Miro for spreading the word.

  2. This is very useful indeed.

    What is unclear to me is how TDD is implemented with the QP framework.

    Do I have to test the topology of a statechart? Which would mean that I’d have to call a QStateHandler under test, check that it returns Q_RET_TRAN or Q_SUPER or … and also test if the temp attribute of the statechart is set to the expected state. So I’d need a special mocking framework that checks for this and could be invoked like this:

    myStatechart_EXPECT(##expected statehandler in temp here##, ##expected RET-macro here’##);
    myStateHandler(myStatechart, myEvt);

    so for example testStatechart has two states stateA and stateB. A trans to B on TEST_SIG:

    testStatechart_EXPECT(stateB, Q_RET_TRAN);
    stateA(testStatechart, testEvt);

    On one hand that seems really tedious, especially if QM is used. On the other hand the topology is the core of the programs logic and TDD doesn’t seem to make much sense if its not tested.
    Personally I dont like the idea of testing the topology. Very few errors are made here anyway and even if there is an error the test will not catch them because from the perspective of the test everything is in order.

    1. The TDD is a fascinating subject, especially when applied to an active object framework like QP, which seems to be a natural fit for TDD. I certainly plan to write/blog about it in the future.

      But this blog post is actually not about TDD or QP. If you actually read the Application Note that I refer in this blog, you will see that the provided example is a simple timed “superloop” without any framework or RTOS. The main purpose is to show how to use the Front Panel Win32 Toolkit to implement a simple, but non-trivial embedded user interface. The example code shows also how to apply Dual Targeting in practice, so that the same code can be run on Windows and on the embedded board (Stellaris EK-LM3S811 in this case).

      But going back to TDD and QP, I only want to mention that I don’t think that a unit for testing is a state handler in this case. A natural unit test is an active object. So testing consists of (1) bringing the AO to a specific state (setup), (2) injecting event(s) to it and (3) verifying the behavior.

      1. I am also very interested in you perspective on TDD. You mentioned a while back in another comment that you planned to do a post on TDD with QP. I continually check back to see if you have written anything on it, as well as to see what else you have to say. I have read “Test Driven Development in Embedded C” several times and am trying to understand and implement everything I read. I am very interested to read more of your thought on the subject as I am not sure how to get the two to work together. I have also been doing some reading on using TDD and DBC together, and would be very interested in you thoughts on that also. Thanks for all your great posts. This GUI tool looks great. I have only recently started using dual targeting, and am excited to try it out.

Leave a Reply