Integrating Legacy C Applications with the redBlocks Simulator

We strongly recommend to choose the implementation language C++ and use the redBlocks Component Library when starting an embedded software application development from scratch.

However, there is a lot of application code out there that is implemented in C. In order to take advantage of the redBlocks Simulator’s convenient test automation features, existing embedded applications can easily be integrated with the redBlocks Simulator by using the C Target Simulation API.

Prerequisites

The key concept when working with the redBlocks Simulator is this: There must be a clean separation between the hardware dependent code (typically hardware drivers) and hardware independent software modules (application layer functionality). Refer to Platform Abstraction for a more detailed description of this concept.

If this concept is in place, the hardware independent source code can be left unmodified, no matter whether it is linked with the real hardware drivers or the driver stubs that are needed for integration with the redBlocks Simulator.

Integrating a legacy application with the redBlocks Simulator basically requires two things:

  • Software-in-the-Loop (SiL) Environment Setup
  • Driver Layer Replacement

Software-in-the-Loop (SiL) Environment Setup

The main() routine of an embedded software application typically needs to take care of hardware initialization tasks. When running the embedded software application with the redBlocks Simulator, it needs to take care of the SiL environment setup instead.

Therefore, we need to link our application code with a different main() routine that establishes a connection to the redBlocks Simulator, initializes the driver stubs and finally starts the application. The following code snippet shows the setup, if the embedded application runs in the POSIX host simulation environment and connects via TPC port 10000 to the redBlocks Simulator.

#include <Application.h>
#include <Platform.h>
#include <libredBlocks_sim_posix.h>

/*
 * Initializes all driver stubs
 */
extern void Platform_initSimulation( void );

int main()
{
  rb_sim_posix_initTcp( "127.0.0.1", 10000 );
  Platform_initSimulation();
  rb_sim_initDone();
  Application_run();
  return 0;
}

Driver Layer Replacement

As the embedded software application does not access the target hardware in the simulation environment, but interacts via simulation stubs with the redBlocks Simulator, these simulation stubs need to be implemented. They must provide exactly the same API as the driver layer for the real hardware target.

Here are some example code snippets for a pretty simple hardware target that provides a digital output with an LED and a digital input with a Push Button that generates interrupts. Note that the driver layer should provide the right abstraction for the application code: The application code will not directly call a driver function that sets pin 5 of port A when switching the LED but the function Platform_Led_setValue.

Interface definition:

#ifndef PLATFORM_H_
#define PLATFORM_H_
void Platform_Led_setValue( unsigned char value );
void Platform_PushButton_setIsrCallback(void (*cbk)( void ));
unsigned char Platform_PushButton_getValue( void );
void Platform_PushButton_enableInterrupt( void );
void Platform_PushButton_disableInterrupt( void );
#endif

The implementation assumes that the LED is represented in the redBlock Simulator as a digital output with index 0 and the Push Button as a digital input with index 0. The push button’s digital input generates an interrupt callback on each rising edge (RB_TRIGGER_EDGE_RISING).

#include <libredBlocks_sim.h>
#include <Platform.h>
#define ID_LED 0
#define ID_PUSH_BUTTON 0
void Platform_initSimulation( void )
{
  rb_sim_DigitalOutput_add( ID_LED, 0 );
  rb_sim_DigitalInput_add( ID_PUSH_BUTTON, RB_TRIGGER_EDGE_RISING, NULL );
}
void Platform_Led_setValue( unsigned char value )
{
  rb_sim_DigitalOutput_setValue(ID_LED, value);
}
void Platform_PushButton_setIsrCallback(void (*cbk)( void ))
{
  rb_sim_DigitalInput_setCallback(ID_PUSH_BUTTON, cbk);
}
void Platform_PushButton_enableInterrupt()
{
  rb_sim_DigitalInput_enableCallback(ID_PUSH_BUTTON);
}
void Platform_PushButton_disableInterrupt()
{
  rb_sim_DigitalInput_disableCallback(ID_PUSH_BUTTON);
}
unsigned char Platform_PushButton_getValue()
{
  return rb_sim_DigitalInput_getValue(ID_PUSH_BUTTON);
}

For simplicity reasons, these code snippets refer to a very trivial example with only a digital input and output. However, stubs for much more sophisticated drivers (e. g. an RFID reader chip) can be implemented in exactly the same way. They typically use a communication channel in order to exchange data with a Python script running in the context of the redBlocks Simulator.

Sources for More Information

A more thorough explanation and the complete description of the C Target Simulation API can be found in the redBlocks Simulator’s documentation (see Programming Interfaces -> Target Simulation Library -> C Target Simulation API) that can be accessed via the menu "Help" in the redBlocks Simulator that comes with the redBlocks Eval Package.

We also provide support services in order to help you integrate your legacy application with the redBlocks Simulator. Feel free to contact us for more information about the services we offer.