-
-
Notifications
You must be signed in to change notification settings - Fork 1
Examples
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.
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.
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.
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.
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.
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!

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
}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
}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().
TBD
All examples can also be found under examples in the repo!