Skip to content
Daniel Heater edited this page Nov 2, 2015 · 17 revisions

#Motivation This tutorial will walk you through some of the basics of building an application using libSPRITE.

libSPRITE provides for scheduling and deterministic data routing for multi-tasking applications on POSIX compliant operating systems. It also allows you to configure and control applications using the Lua scripting language.

libSPRITE hides some of the complexity of building multi-threaded applications and attempts to reduce the errors and indeterminism associated with concurrent programming. Especially when running on multi-core machines.

#Prereqisites

  • A C++ compiler
  • CMake
  • Lua development tools
  • Download and install libSPRITE.

#Hello World!

Step 1

A good first step is to build a simple, straight forward application that prints "Hello World!"

Create a file called sprite_main.cpp. For this first step, we are not going to use the SCALE Lua interface. We will stick with straight C/C++.

Start by creating a directory called task. This is where we will put source code for SRTX tasks. The write the following two source files.

Hello.hpp

#ifndef task_Hello_hpp
#define task_Hello_hpp

#include "SRTX/Task.h"

namespace task {
    class Hello : public SRTX::Task {

      public:
        /**
         * Constructor.
         * @param name Task name.
         */
        Hello(const char *const name);

        /**
         * Initialization routine.
         * @return true on success or false on failure.
         */
        bool init();

        /**
         * This the the function that gets executed on a periodic basis
         * each time this task is scheduler to run.
         * @return Return true to continue execution or false to terminate
         * the task.
         */
        bool execute();

        /**
         * Terminate routine.
         */
        void terminate();
    };

} // namespace

#endif // task_Hello_hpp

and Hello.cpp

#include "task/Hello.hpp"
#include "base/XPRINTF.h"

namespace task {

    Hello::Hello(const char *const name)
        : SRTX::Task(name)
    {
    }

    bool Hello::init()
    {
        return true;
    }

    bool Hello::execute()
    {
        IPRINTF("Hello World\n");
        return true;
    }

    void Hello::terminate()
    {
    }

} // namespace

In the top level directory, create the file sprite_main.cpp

#include <SRTX/Scheduler.h>
#include <base/XPRINTF.h>
#include <signal.h>

#include "task/Hello.hpp"

static volatile bool done(false);

static void kill_me_now(int)
{
    done = true;
}

static units::Nanoseconds HZ_to_period(unsigned int hz)
{
    return units::Nanoseconds(1*units::SEC / hz);
}

int main(void)
{
    /* Set up the signal handler for control-C.
     */
    signal(SIGINT, kill_me_now);

    /* Declare the task properties.
     */
    SRTX::Task_properties tp;
    SRTX::priority_t priority = SRTX::MAX_PRIO;

    /* Create the scheduler
     */
    tp.prio = priority;
    tp.period = HZ_to_period(1);
    SRTX::Scheduler &s = SRTX::Scheduler::get_instance();
    s.set_properties(tp);

    /* Create the "Hello World!" task
     */
    --tp.prio;
    task::Hello hello("Hello");
    hello.set_properties(tp);

    s.start();
    hello.start();

    while(!done)
    {
        ;
    }

    hello.stop();
    s.stop();

    return 0;
}

Then add a CMakeLists.txt file at the top level to build the project.

cmake_minimum_required(VERSION 2.8)

# I like to have the warning level set high.
add_definitions("-Wall -Wextra -Wparentheses -Wuninitialized -Wcomment -Wformat -Weffc++")

# Add the source tree directory to the search path for include files.
# Add the path to the libSPRITE header files.
include_directories(${CMAKE_CURRENT_SOURCE_DIR} "/usr/local/include/SPRITE")

# Set libSPRITE in the libraries path.
link_directories(/usr/local/lib/SPRITE)

# Add the executable and it's source.
add_executable(sprite_main sprite_main.cpp
               task/Hello.cpp)

# Specify libraries to link.
target_link_libraries(sprite_main SPRITE_SRTX pthread)

To build the executable, create a directory called build and cd into that directory. Execute cmake .. to generate the Makefiles. Then enter make to create an executable called sprite_main.

You must have root privledges to run the executable. This is required because tasks are set to real-time priorities. If you are not root, you will get a warning to run using sudo.

So what happens here. Well, we've created an executable that has one task called Hello. There is also a scheduler task running in the system and the Hello task is registered with the scheduler. Both the scheduler and the Hello task are set to run at 1 Hz with the scheduler running at the highest priority in the system and the Hello task running a the highest priority minus 1 --tp.prio.

The scheduler and Hello tasks are both started and continue to run until control-C is entered, at which point the Hello task and the scheduler are stopped and the program exits.

Bonus tip

So what's up with the IPRINTF("Hello World!\n")? The definition comes from the base/XPRINTF.h file in libSPRITE/base. It is a macro that can be turned on and off. IPRINTF stands for "information print". The base/XPRINTF.h header also contains macros for DPRINTF (debug), WPRINTF (warning), and EPRINTF (error).

By adding the line set_property(SOURCE task/Hello.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -DNO_PRINT_INFO") to CMakeLists.txt, you can turn off the print statement. This can be quite useful in controlling the level of verbosity on a file by file or system wide basis. Just use -DPRINT_DEBUG, -DNO_PRINT_WARNING, and -DNO_PRINT_ERROR to change the default behavior of DPRINTF, WPRINTF, and EPRINTF macros respectively. Note that the default behavior of DPRINTF is to not print.

Clone this wiki locally