Skip to content

marcinbor85/libcr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

libcr

Multiplatform asynchronous library for C. Usefull in embedded systems, where we can't halt main loop with simple sleep function. Helps to implement finite state machines and cooperative services.

Features:

  • easy to porting (also for embedded systems)
  • dynamic memory allocations for routines and schedulers objects
  • only one thread, hidden main loop operations
  • macro-based but easy to use without them
  • unlimited fast software timers
  • continous, periodic or future parametrized callbacks
  • easy to adapt and extend
  • simple and powerful
  • clear code and "no magic"

Examples:

Asynchronous and conditional wait:

#include <stdio.h>
#include <stdlib.h>

#include "cr/macros.h"

CR_DECLARE_ROUTINE(part2);
CR_DECLARE_ROUTINE(part3);

CR_DECLARE_ROUTINE(part1)
{
        printf("[%05ld] - %s - part1\n", cr_port_get_time(), scheduler->active_routine->name);
        cr_wait(1000, part2);
        printf("[%05ld] - %s - part2\n", cr_port_get_time(), scheduler->active_routine->name);
        cr_wait_for(cr_port_get_time() > 1500, part3);
        printf("[%05ld] - %s - part3\n", cr_port_get_time(), scheduler->active_routine->name);
        cr_end();
}

static void routine_repeat(struct cr_scheduler *scheduler, void *param)
{
        printf("[%05ld] - %s\n", cr_port_get_time(),  scheduler->active_routine->name);
}

static void loop(struct cr_scheduler *scheduler, void *param)
{
        if (cr_port_get_time() > 2000)
                cr_stop(scheduler);
}

int main(void)
{
        struct cr_scheduler *scheduler;

        scheduler = cr_new("main", loop);

        cr_new_routine(scheduler, "routine_long", part1, NULL);
        cr_repeat(scheduler, "routine_repeat", 300, 0, routine_repeat, NULL);

        puts("start");
        while (cr_service(scheduler) != false) {};
        puts("end");

        cr_delete(scheduler);

        return EXIT_SUCCESS;
}

Output:

start
[00000] - routine_repeat
[00000] - routine_long - part1
[00300] - routine_repeat
[00600] - routine_repeat
[00900] - routine_repeat
[01000] - routine_long - part2
[01200] - routine_repeat
[01500] - routine_repeat
[01501] - routine_long - part3
[01800] - routine_repeat
end

STM32 co-routines:

#include "stm32f0xx_nucleo.h"

#include "cr/macros.h"

static struct cr_routine *routine_led;

CR_DECLARE_ROUTINE(led_part2);
CR_DECLARE_ROUTINE(led_part3);
CR_DECLARE_ROUTINE(led_part4);

CR_DECLARE_ROUTINE(led_part1)
{
        STM_EVAL_LEDOn(LED2);
        cr_wait(100, led_part2);
        STM_EVAL_LEDOff(LED2);
        cr_wait(200, led_part3);
        STM_EVAL_LEDOn(LED2);
        cr_wait(100, led_part4);
        STM_EVAL_LEDOff(LED2);
        cr_wait_and_back(1000, led_part1);
}

CR_DECLARE_ROUTINE(button)
{
        if (!STM_EVAL_PBGetState(BUTTON_USER)) {
                cr_routine_halt(routine_led);
        } else {
                if (routine_led->state == CR_ROUTINE_STATE_HALT)
                        cr_routine_resume(routine_led);
        }
}

int main(void)
{
        struct cr_scheduler *scheduler;

        STM_EVAL_LEDInit(LED2);
        STM_EVAL_PBInit(BUTTON_USER, BUTTON_MODE_GPIO);

        scheduler = cr_new("main", NULL);

        routine_led = cr_new_routine(scheduler, "routine_led", led_part1, NULL);
        cr_new_routine(scheduler, "routine_button", button, NULL);

        while (1)
                cr_service(scheduler);
}

Basic co-routines:

#include <stdio.h>
#include <stdlib.h>

#include "cr/core.h"

static void routine1(struct cr_scheduler *scheduler, void *param)
{
        uint32_t time = 1000;
        const char *name = "slow";

        printf("[%05ld] - %s [%ld]\n", cr_port_get_time(), name, time);
        cr_routine_wait(scheduler->active_routine, time);
}

static void routine2(struct cr_scheduler *scheduler, void *param)
{
        uint32_t time = 300;
        const char *name = "fast";

        printf("[%05ld] - %s [%ld]\n", cr_port_get_time(), name, time);
        cr_routine_wait(scheduler->active_routine, time);
}

static void loop(struct cr_scheduler *scheduler, void *param)
{
        if (cr_port_get_time() > 3000)
                cr_stop(scheduler);
}

int main(void)
{
        struct cr_scheduler *scheduler;

        scheduler = cr_new("main", loop);

        cr_new_routine(scheduler, "routine_slow", routine1, NULL);
        cr_new_routine(scheduler, "routine_fast", routine2, NULL);

        puts("start");
        while (cr_service(scheduler) != false) {};
        puts("end");

        cr_delete(scheduler);

        return EXIT_SUCCESS;
}

Output:

start
[00000] - fast [300]
[00000] - slow [1000]
[00300] - fast [300]
[00600] - fast [300]
[00900] - fast [300]
[01000] - slow [1000]
[01200] - fast [300]
[01500] - fast [300]
[01800] - fast [300]
[02000] - slow [1000]
[02100] - fast [300]
[02400] - fast [300]
[02700] - fast [300]
[03000] - fast [300]
[03000] - slow [1000]
end

Future and periodic callbacks:

#include <stdio.h>
#include <stdlib.h>

#include "cr/core.h"

static void once(struct cr_scheduler *scheduler, void *param)
{
        printf("[%05ld] - num = %ld\n", cr_port_get_time(), *(uint32_t*)param);
}

static void routine(struct cr_scheduler *scheduler, void *param)
{
        static uint32_t num = 0;

        printf("[%05ld] - %s\n", cr_port_get_time(), scheduler->active_routine->name);
        cr_after(scheduler, "routine_once", 200, once, &num);
        num++;
}

static void loop(struct cr_scheduler *scheduler, void *param)
{
        if (cr_port_get_time() > 10000)
                cr_stop(scheduler);
}

int main(void)
{
        struct cr_scheduler *scheduler;

        scheduler = cr_new("main", loop);

        cr_repeat(scheduler, "routine_repeat", 1000, 5, routine, NULL);

        puts("start");
        while (cr_service(scheduler) != false) {};
        puts("end");

        cr_delete(scheduler);

        return EXIT_SUCCESS;
}

Output:

start
[00000] - routine_repeat
[00200] - num = 1
[01000] - routine_repeat
[01200] - num = 2
[02000] - routine_repeat
[02200] - num = 3
[03000] - routine_repeat
[03200] - num = 4
[04000] - routine_repeat
[04200] - num = 5
end

Co-routines management:

#include <stdio.h>
#include <stdlib.h>

#include "cr/core.h"

static struct cr_routine *routine;

static void callback(struct cr_scheduler *scheduler, void *param)
{
        printf("[%05ld] - %s\n", cr_port_get_time(), scheduler->active_routine->name);
}

static void control(struct cr_scheduler *scheduler, void *param)
{
        printf("[%05ld] - %s\n", cr_port_get_time(), scheduler->active_routine->name);

        if (param == NULL) {
                cr_routine_halt(routine);
        } else {
                cr_routine_resume(routine);
        }
}

static void loop(struct cr_scheduler *scheduler, void *param)
{
        if (cr_port_get_time() > 10000)
                cr_stop(scheduler);
}

int main(void)
{
        struct cr_scheduler *scheduler;

        scheduler = cr_new("main", loop);

        routine = cr_repeat(scheduler, "routine_repeat", 500, 0, callback, NULL);

        cr_after(scheduler, "halt", 3000, control, 0);
        cr_after(scheduler, "resume", 6000, control, 1);

        puts("start");
        while (cr_service(scheduler) != false) {};
        puts("end");

        cr_delete(scheduler);

        return EXIT_SUCCESS;
}

Output:

start
[00000] - routine_repeat
[00500] - routine_repeat
[01000] - routine_repeat
[01500] - routine_repeat
[02000] - routine_repeat
[02500] - routine_repeat
[03000] - halt
[06000] - resume
[06000] - routine_repeat
[06500] - routine_repeat
[07000] - routine_repeat
[07500] - routine_repeat
[08000] - routine_repeat
[08500] - routine_repeat
[09000] - routine_repeat
[09500] - routine_repeat
[10000] - routine_repeat
end

Releases

No releases published

Packages

No packages published

Languages