Tag Archives: SynthOS primitive

SynthOS Callback Solution

Yes, I know this title is somewhat confusing, since a SynthOS-generated system is not based on a typical callback architecture. You may think the title should actually be “SynthOS vs. a Callback solution.” But in fact, SynthOS can create an application that in many respects will work the same way, and have the same capabilities, as a callback architecture. Callback architecture is commonly used when a system requires asynchronous operation. Depending on the application, a task can request a callback (or a message) when a specific asynchronous operation ends, or a specific event is detected. The typical callback architecture uses a function pointer to specify the target for the callback. This is very powerful in C/C++ programing where you can use pointers to a structure or object that includes the function pointers and the data or status information.

SynthOS doesn’t specifically support a callback architecture, but given the flexibility of SynthOS and the way it analyzes the SynthOS primitives within the specific context in the program, it can give you comparable performance to a callback implementation. We will start by reviewing the SynthOS_wait(<condition>) primitive in a simple timer implementation. In a callback system, the user has to send a request to a timer service. The request specifies a time delta or an absolute time and the function pointer to be called-back once the time elapses. Using SynthOS_wait() you can directly wait on a global clock variable or encapsulate it in a function returning the time and wait for that task. The calling task will be suspended and put into the task queue by the scheduler. The timing condition will be tested every time the timer is updated. Once the wait condition is valid, the task will be activated and put into the execution queue based on its priority or system scheduling. The system will return to the command following the SynthOS_wait() primitive in the code.

void loopTask (void) {
    printf ("loopTask1 %dn", clk);
    wait (400);
    printf ("loopTask1: Donen");
}
void wait (unsigned t) {
    unsigned sv_clk = clk;
    SynthOS_wait (clk - sv_clk >= t);
}
void clock_interrupt (void) {
    clk ++;
}

This example shows the use of SynthOS_wait() primitive, but we can get the same behavior by using the SynthOS_call() primitive and calling the function that you would like to call the task back once it is done. Both those options provide the capability for blocking callback, where the execution of the calling task is suspended until the callback happens. SynthOS can also support non-blocking callback functionality by using the SynthOS_start() primitive. This option is very useful in the case of asynchronous communication or an interrupt based system. The main task can initiate another task that will send a callback message once it is done, but the main task operation is not suspended; it can continue processing in parallel until it is ready to wait for the callback.

void loopTask(void) {
    unsigned data = 1;
    printf("Loop task.n");

    SynthOS_start(startTask(data));
    printf("Loop task continues.n");

    // Show that other tasks
    // can also run in parallel
    SynthOS_sleep();
    printf("Loop task waits for callback.n");

    // Wait for callback
    SynthOS_wait(startTask);
    printf("Loop task got callback & continues.n");
}
void startTask(int Data) {
     printf("Start task is running.n");

     SynthOS_sleep();

     printf("Start task is done.n");
     printf("Terminate and send callback.n");
}

These examples show the way you can use SynthOS primitives and their behavior to support different system architectures. The power of the SynthOS-generated system is the support for embedded systems’ diverse requirements while delivering tested and reliable software that is highly efficient.

Jacob Harel
VP of Product Management
Zeidman Technologies