Skip to content

Examples

jake-is-ESD-protected edited this page May 20, 2026 · 14 revisions

Use-cases

jescore can be used for a variety of applications for and on embedded systems. Since multitasking and CLI are native, it opens up some possibilities for cool cross-platform applications.

Finite state machine

Does your project involve user-triggered tasks with sleep time in between? Perfect for jescore! Use interrupts to launch jobs that process your requests before going to sleep again. Since jescore deallocates memory for jobs which are done, you can expect that your sleep-overhead is close to zero. You won't have to worry about being fast because of the interrupt, because the job is quickly started there and then acts outside of the interrupt routine within the task scheduler.

Sampler with user input

Many devices in the realm of media streaming or measurement require a constant stream of data but also have to react to user input during runtime. Think of a digital oscilloscope which has to adjust its trigger value according to the users input while data is being sampled. jescore can take care of that. Define a sampler-job with a while(1) and UI-handler job which gets triggered by an interrupt, adjust some values within your trigger-job and exit.

Unit testing

Native CLI support enables easy cross-platform unit-testing. Using pyserial for python you can send commands to jescore via serial. This way, you can easily test your embedded systems internal calculation processes without being physically present.

Hardware virtualization

Ordered an expensive touchpad with a shipment time of 3 weeks? Would be a shame if you had to wait that long to resume programming your UI. With jescore you can define a job that reacts to an input call with arguments that abstract any information that your physical UI would later send. For example press icon 1 could envoke a job of name press that executes exactly the same thing your display would do later. When it finally arrives, you just have to envoke press icon 1 in the interrupt routine of your touch sensor. This makes UI-to-system coupling very shallow and simple and you can focus on building a cool looking UI without worrying about the boring backend stuff.

Blinky

Classic blinky example powered by jescore. Only this time, you can actually toggle the LED without any hardware. Simply install the jescore-cli and type jescore blink to toggle your controller from your PC like a big-boy OS via your keyboard. This example is also available at example_blink.cpp.

#include <Arduino.h>
#include "jescore.h"

#define LED_PIN 4


void blink(void* p){
    static uint8_t act = 0;
    act = !act;
    while(act){
        digitalWrite(LED_PIN, HIGH);
        delay(1000);
        digitalWrite(LED_PIN, LOW);
        delay(1000);
    }
}


void setup() {
    jes_init();
    pinMode(LED_PIN, OUTPUT);
    jes_register_and_launch_job("blink", 2048, 1, blink, 1, 1);
}

void loop() {

}

Now you can control your embedded system from your PC!
jescore_blink

CLI-driven FSM

Some systems operate purely on asynchronous input, such as a user action. Polling for an input that may occur once per day but is sampled every second is very inefficient. For this reason, interrupts can help to determine an asynchronous action and to activate the system whenever it is accessed and only then. jescore is no different. In this example, using the CLI triggers an UART interrupt which is then piped to jescore. This is a simple version of the classic "garage door" example, whereby the user requests one of two actions that co-depend on each other. Here, the action performed by a motor is represented by a fading LED. While the LED is changing its status, the process is blocked. Call jescore lights on to see the LED fade on. This example is also available at example_fsm_cli.cpp.

#include <Arduino.h>
#include "jescore.h"
#include <string.h>

#define LED_PIN 4

static bool is_on = false;
static bool processing = false;

void lights(void* p){
    /* 
    This function will be executed when the first word of your
    CLI command is "lights", as registered in line 60 below. All
    other words that follow, such as "on" or "off" will be passed
    as args to this job and can be retrieved as full string with
    jes_job_get_args().
    */
    char* args = jes_job_get_args();
    char* arg = strtok(args, " ");
    if (!arg){
        uart_unif_write("No argument specified! Use <on> or <off>\n\r");
        return;
    }
    if (strcmp(arg, "on") == 0){
        if(is_on) return; // nothing to do
        if(processing) return; // blocked by lights_off
        processing = true;
        for(uint8_t i = 0; i < 255; i++){
            analogWrite(LED_PIN, i);
            jes_delay_job_ms(5);
        }
        is_on = true;
        processing = false;
    }
    else if (strcmp(arg, "off") == 0){
        if(!is_on) return; // nothing to do
        if(processing) return; // blocked by lights_off
        processing = true;
        for(uint8_t i = 255; i > 0; i--){
            analogWrite(LED_PIN, i);
            jes_delay_job_ms(5);
        }
        is_on = false;
        processing = false;
    }
    else if (strcmp(arg, "state") == 0){
        uart_unif_writef("lights are %s\n\r",(is_on ? "on" : "off"));
    }
    else{
        uart_unif_write("unknown argument!\n\r");
    }
}

void setup() {
    jes_init();
    pinMode(LED_PIN, OUTPUT);
    jes_register_job("lights", 2048, 1, lights, 0, 1);
}

void loop() {
    // nothing to do here!
    // jescore is now purely controlled by the CLI
    // call `jescore lights on` to see the LED fade on
    // call `jescore lights status` to get a print
    // of the current status of the LED FSM
}

Synchronous job with asynchronous user input

More common on embedded systems, a synchronous conversion job of analog input or output data with equal time steps between them requires strict timing. This timing usually means that the job performing this action can't "wait" or poll for user input, as that would violate its timing restrictions. In such a case, jescore can be used to steer a synchronous job with an asynchronous one that interact via a shared resource. This example demonstrates how the classic blinky sketch can be modified in terms of its blinking speed by the user. Use jescore switch 500 to set the blinking rate to 500 ms. This example is also available at example_sync_async.cpp.

#include <Arduino.h>
#include "jescore.h"
#include <inttypes.h>

#define LED_PIN 5

static uint32_t blink_pause = 1000;

void blink_forever(void* p){
    /*
    This function is a placeholder for a  "time critical" loop 
    that does not have the capability of sampling user input. 
    This is the "sync"-job that we want to steer with the "async"-
    job. This job is an infinite, synchronous loop.
    */
    while(1){
        digitalWrite(LED_PIN, 1);
        jes_delay_job_ms(blink_pause);
        digitalWrite(LED_PIN, 0);
        jes_delay_job_ms(blink_pause);
    }
}

void blink_switch(void* p){
    /*
    This function handles "async" user input and applies it to
    the time critical job. In this very simple example, the shared
    resource is a single uint32_t variable "blink_pause". This job
    handles asynchronous user input and then exits.
    */
    char* arg = jes_job_arg_next();
    if(!arg){
        uart_unif_write("Usage: switch <time in ms>\r\n");
        return;
    }
    while(arg != NULL){
        blink_pause = atoi(arg);
        uart_unif_writef("Blink rate set to %s ms\n\r", arg);
        arg = jes_job_arg_next();
    }
}

void setup() {
    jes_init();
    pinMode(LED_PIN, OUTPUT);
    jes_register_job("switch", 2048, 1, blink_switch, 0, 1);
    jes_register_and_launch_job("blink", 2048, 1, blink_forever, 1, 1);
}

void loop() {
    // nothing to do here!
    // call `jescore switch <time in ms>` to see the LED change blink speed
}

STM32 Examples

jescore also supports STM32 platforms. Here are examples for specific STM32 Nucleo boards:

  • example_blink_stm32l476.c - Blinky example for STM32L476 Nucleo
  • example_blink_stm32g431.c - Blinky example for STM32G431 Nucleo
  • example_blink_stm32h753.c - Blinky example for STM32H753 Nucleo

These examples demonstrate the same blinky functionality adapted for STM32 HAL with jes_dispatch() called from main().

Advanced unit testing

TBD

All examples can also be found under examples in the repo!

Clone this wiki locally