API Documentation - jake-is-ESD-protected/jescore GitHub Wiki

Imports

jescore is a C/C++ library built on top of FreeRTOS. It is developed in the PlatformIO development environment and can be easily integrated into other projects based on that framework:

; platformio.ini:
[env:my_board]
...
lib_deps = 
    https://github.com/jake-is-ESD-protected/jescore

Right now, jescore supports any board which is compatible with the Arduino FW ports of other FWs. Up until now, it has only been actually tested on a few ESP32s:

  • ESP32-WROOM
  • ESP32-C3
  • ESP32-S3

You can now import jescore:

// your_project/src/main.cpp

...
#include <jescore.h>

void setup(){
}

void loop(){
}

For other IDEs, you can clone the repo with git clone https://github.com/jake-is-ESD-protected/jescore and append the libraries to your Makefile like you would with any other source files.

Functions

void your_function(void* p)

jescore is all about the user, but you still have to adhere to its rules if you want to use it. For this reason, all functions you intend to run with it have to have the mentioned signature. No return, a single void* as parameter, similar to FreeRTOS (you can guess why). However, this parameter p is always loaded with the handle to the job which belongs to the function, as it may be useful from within the function, if you know what you are doing, see Backend documentation. But for most cases, especially for simple jobs, this can be ignored.


jes_err_t jes_init()

Brief: Start the core and all of its abilities.
Returns: Status. Returns e_err_no_err in case of successful launch.

Use jes_init() in your setup() or any other initialization code. jescore needs dynamic memory and will tell you if not enough is available. Be sure to always check the return value of jes_err_t! The error types are explained in jes_err_t.


jes_err_t register_job(const char* name, uint32_t mem_size, uint8_t priority, void (*function)(void* p), uint8_t is_loop)

Brief: Add a job (function block) to the list of all known jobs.
name: Name of job. Can't be longer than MAX_JOB_NAME_LEN_BYTE.
mem_size: Dynamic memory size for job.
priority: Priority of the job (1 is highest).
function: Function to run when the job is called. Has to be of signature void my_func(void* p).
is_loop: Flag which describes the lifetime of the job.
Returns: Status. Returns e_err_no_err in case of successful registration.

Use register_job() to make one of your functions known to jescore. By registering it, you append it to the core's list of known jobs and it gets passed to the task scheduler of FreeRTOS. You can give your function a name, which can later be called by the CLI, see CLI documentation, if you want that. Be sure that your name does not contain whitespaces, because jescore uses those to determine additional arguments in your CLI calls. It also should not be longer than MAX_JOB_NAME_LEN_BYTE. Start with a generous memory size, as FreeRTOS keeps a limited stack for each of your registered functions. The size is determined by the amount of local or static variables in your function and the depth of its calls, so estimating a good memory size is quite hard. Start larger than you might initially think, and then lower it over time if everything runs as expected. You also have to specify whether your function has an infinite loop or ends at some point. Be sure to set this truthfully, as it may mess with the CLI, if you use that.


jes_err_t launch_job(const char* name)

Brief: Start a registered job.
name: String name of job as set in register_job().
Returns: Status. Returns e_err_no_err in case of successful launch.

To launch a job, use launch_job() and give it the name of the job you previously registered. If you find this step redundant, see register_and_launch_job().


jes_err_t launch_job_args(const char* name, const char* args)

Brief: Start a registered job with arguments.
name: String name of job as set in register_job(). args: String of arguments delimited by whitespaces. Can't be longer than MAX_JOB_ARGS_LEN_BYTE. Returns: Status. Returns e_err_no_err in case of successful launch.

Launch a job with arguments. This is useful if you have runtime-dependent launch sequences or want to mimic a CLI call. This makes jescore powerful: during development, the CLI can be used to trigger actions on the MCU. If hardware is added, its interrupt or callback can trigger the exact same job with arguments that the CLI would perform before the input hardware was added.


jes_err_t register_and_launch_job(const char* name, uint32_t mem_size, uint8_t priority, void (*function)(void* p), uint8_t is_loop)

Brief: Add a job (function block) to the list of all known jobs and launch it. name: Name of job. Can't be longer than MAX_JOB_NAME_LEN_BYTE.
mem_size: Dynamic memory size for job.
priority: Priority of the job (1 is highest).
function: Function to run when the job is called. has to be of signature void my_func(void* p).
is_loop: flag which describes the lifetime of the job.
Returns: Status. Returns e_err_no_err in case of successful launch.

Use this function to combine the two above. This makes sense for all jobs which get started during the boot process of your project.


jes_err_t set_args(char* s)

Brief: Set the field args of the job.
s: String to insert into args field.
Returns: status, e_err_no_err if OK.

Each job contains a field of fixed memory size, called args. Its size depends on MAX_JOB_ARGS_LEN_BYTE. It is normally used to store the CLI arguments passed to that particular job, but there might be cases in which this array may be loaded by a program snippet rather than a user handling the CLI. Use this function to put an arbitrary C-string into that buffer. If the string is too long, the error return will tell you that.


char* get_args(void)

Brief: Get the field args of the job.
Returns: Pointer to args field of the job.

This function returns a pointer to the args buffer of the calling job. Since this function is intended to be called from within a job, the memory of the job struct persists, which makes a copy of the arg string redundant. If, however, something goes wrong, this function will return NULL. Use this function to retrieve anything that has been put into the args buffer by either set_args() or the CLI.


jes_err_t set_param(void* p)

Brief: Set the field optional of the job.
p: Arbitrary reference to parameter.
Returns: status, e_err_no_err if OK.

For any arbitrary argument you might pass to a job, the field optional can be used. It is declared as void*, so you can pass anything to it. Keep in mind that you

  1. need to have persistent storage for the content of the pointer, because jescore does not copy it
  2. make sure that you cast it back into the original type correctly.
    In most use-cases, you might pass the reference to a struct to this parameter, because a struct has addressable fields as opposed to an "arbitrary" array length, which means that a single pointer is sufficient to describe it completely.

void* job_get_param(void)

Brief: Get the field optional of the job.
Returns: Pointer to optional field of the job.

Use this function to retrieve whatever you put into the optional field in your job with set_param(). Be careful, this value might be NULL if you never called set_param() with anything other than NULL.


void notify_job(const char* name, void* notification)

Brief: Notify a job with an optional message.
name: Name of job which should be notified.
notification: Optional pointer to notification value.

Call this function to notify a different job. For a job to accept notifications, it has to be waiting for one, see wait_for_notification(). If you don't want to send a notification value, pass NULL to notification.


void notify_job_ISR(const char* name, void* notification)

Brief: Notify a job with an optional message.
name: Name of job which should be notified.
notification: Optional pointer to notification value.

Same as notify_job() but for interrupt service routines. Call this from within an interrupt.


void* wait_for_notification(void)

Brief: Wait for an incoming message.
Returns: Optional message pointer given in notify_job().

This stalls the calling task but is not blocking. The task is simply suspended from execution until a notification arrives. From there on, the task will resume, regardless of the contents of the optional return notification. However, it can be useful to tell the waiting task what to do next.

Types

jes_err_t

This is the standard return type of most jescore functions. They describe if a function call was successful or failed in one or more ways. The errors are shown below:

typedef enum jes_err{
    e_err_no_err,
    e_err_mem_null,
    e_err_is_zero,
    e_err_param,
    e_err_peripheral_block,
    e_err_core_fail,
    e_err_duplicate,
    e_err_too_long,
    e_err_unknown_job,
    e_err_leading_whitespace,
    e_err_prohibited
}jes_err_t;

e_err_no_err: No error, everything worked.
e_err_mem_null: Dynamic memory operation returned NULL, out of memory.
e_err_is_zero: Given value is 0 or NULL or a value that should never be 0 is 0 regardless.
e_err_param: An incorrect parameter was given.
e_err_peripheral_block: Calling a hardware peripheral failed because it is busy.
e_err_core_fail: The core dealt with a hard fault.
e_err_duplicate: A job has been registered twice by accident or a job which can only have one launch at a time has been launched twice.
e_err_too_long: A given string argument is too long. Can be caused by both API and CLI usage.
e_err_unknown_job: An unregistered job tried to launch. This is typical for typing errors.
e_err_leading_whitespace: CLI only. A command with a leading whitespace was sent. Whitespaces are used to separate arguments, so this can cause issues.
e_err_prohibited: You tried to call a core job by the API. This is forbidden, as it may crash the system.

Macros

MAX_JOB_NAME_LEN_BYTE

This macro is used to allocate a character buffer in every job struct. The names of your jobs can never be longer than this, and register_job() will return e_err_too_long in such a case. You can overwrite the default value of 32 bytes by defining MAX_JOB_NAME_LEN_BYTE yourself:

#define MAX_JOB_NAME_LEN_BYTE 64

void setup(){

}
void loop(){

}

This will of course cause every job_struct_t to become bigger.

MAX_JOB_ARGS_LEN_BYTE

Similar to MAX_JOB_NAME_LEN_BYTE you can change MAX_JOB_ARGS_LEN_BYTE. This is also a character buffer which holds arguments in string format. Both the set_args() and get_args() use this buffer as well as any usage of the CLI.

⚠️ **GitHub.com Fallback** ⚠️