mirror of
https://github.com/sigmasternchen/seaboot
synced 2025-03-15 04:08:54 +00:00
program structure (init, loop, ...) event handling, timer, error handling
This commit is contained in:
parent
abbfee699e
commit
e8e0f1ea6f
5 changed files with 521 additions and 0 deletions
8
Makefile.am
Normal file
8
Makefile.am
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
noinst_LIBRARIES = bin/libseaboot.a
|
||||||
|
bin_libseaboot_a_SOURCES = src/seaboot.c
|
||||||
|
|
||||||
|
|
||||||
|
bin_PROGRAMS = bin/example
|
||||||
|
bin_example_SOURCES = src/example.c
|
||||||
|
bin_example_LDADD = bin/libseaboot.a
|
||||||
|
bin_example_LDFLAGS = -lrt
|
11
configure.ac
Normal file
11
configure.ac
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
AC_INIT([seaboot], [0.1])
|
||||||
|
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
|
||||||
|
AC_PROG_CC
|
||||||
|
AM_PROG_AR
|
||||||
|
AC_PROG_RANLIB
|
||||||
|
#LT_INIT
|
||||||
|
AC_CONFIG_HEADERS([config.h])
|
||||||
|
AC_CONFIG_FILES([
|
||||||
|
Makefile
|
||||||
|
])
|
||||||
|
AC_OUTPUT
|
41
src/example.c
Normal file
41
src/example.c
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include <config.h>
|
||||||
|
#include "seaboot.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
BOOT(init);
|
||||||
|
|
||||||
|
void eventHandler(event_t event) {
|
||||||
|
fprintf(stderr, "Got event %d.\n", event);
|
||||||
|
}
|
||||||
|
void shutdownHandler(event_t event) {
|
||||||
|
fprintf(stderr, "Shuting down.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void intervalHandler() {
|
||||||
|
static int count = 0;
|
||||||
|
count++;
|
||||||
|
fprintf(stderr, "interval count %d.\n", count);
|
||||||
|
if (count > 4) {
|
||||||
|
fprintf(stderr, "Provoking error.\n");
|
||||||
|
boot.enableSignal(SHUTDOWN); // SHUTDOWN is not a signal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
printf("Hello World!\n");
|
||||||
|
|
||||||
|
boot.mode = WAIT;
|
||||||
|
boot.debug = true;
|
||||||
|
|
||||||
|
boot.addEventListener(SHUTDOWN, shutdownHandler);
|
||||||
|
boot.addEventListener(SIGUSR1, eventHandler);
|
||||||
|
boot.enableSignal(SIGUSR1);
|
||||||
|
|
||||||
|
timer_t timer = boot.createSignalTimer(SIGUSR1);
|
||||||
|
boot.startTimer(timer, 5000);
|
||||||
|
|
||||||
|
timer_t interval = boot.createThreadTimer(&intervalHandler);
|
||||||
|
boot.startInterval(interval, 2000);
|
||||||
|
}
|
366
src/seaboot.c
Normal file
366
src/seaboot.c
Normal file
|
@ -0,0 +1,366 @@
|
||||||
|
#include <config.h>
|
||||||
|
#include "seaboot.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
static const char* getEventName(event_t event) {
|
||||||
|
if (IS_SIGNAL(event))
|
||||||
|
return strsignal(event);
|
||||||
|
switch(event) {
|
||||||
|
case SHUTDOWN: return "Shutdown"; break;
|
||||||
|
case LIBERROR: return "Lib-Error"; break;
|
||||||
|
default: return "Unknown"; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool addEventListener(event_t, eventListener_t);
|
||||||
|
static bool removeEventListener(event_t, eventListener_t);
|
||||||
|
static bool enableSignal(event_t);
|
||||||
|
static bool disableSignal(event_t);
|
||||||
|
|
||||||
|
static nstime_t getRealTime(void);
|
||||||
|
static nstime_t getRelativeTime(void);
|
||||||
|
static nstime_t getProcessTime(void);
|
||||||
|
static nstime_t getThreadTime(void);
|
||||||
|
static nstime_t timer(void (*)(void));
|
||||||
|
|
||||||
|
static timer_t createSignalTimer(event_t);
|
||||||
|
static timer_t createThreadTimer(void (*)(void));
|
||||||
|
static void startTimer(timer_t, unsigned long);
|
||||||
|
static void startInterval(timer_t, unsigned long);
|
||||||
|
static void stopTimer(timer_t);
|
||||||
|
static void deleteTimer(timer_t);
|
||||||
|
|
||||||
|
static void eventHandler(event_t);
|
||||||
|
|
||||||
|
struct boot boot = {
|
||||||
|
.addEventListener = addEventListener,
|
||||||
|
.removeEventListener = removeEventListener,
|
||||||
|
.enableSignal = enableSignal,
|
||||||
|
.disableSignal = disableSignal,
|
||||||
|
|
||||||
|
.getRealTime = getRealTime,
|
||||||
|
.getRelativeTime = getRelativeTime,
|
||||||
|
.getProcessTime = getProcessTime,
|
||||||
|
.getThreadTime = getThreadTime,
|
||||||
|
.timer = timer,
|
||||||
|
|
||||||
|
.createSignalTimer = createSignalTimer,
|
||||||
|
.createThreadTimer = createThreadTimer,
|
||||||
|
.startTimer = startTimer,
|
||||||
|
.startInterval = startInterval,
|
||||||
|
.stopTimer = stopTimer,
|
||||||
|
.deleteTimer = deleteTimer,
|
||||||
|
|
||||||
|
.mode = STANDARD,
|
||||||
|
.debug = false
|
||||||
|
};
|
||||||
|
|
||||||
|
struct listener {
|
||||||
|
int number;
|
||||||
|
eventListener_t* listeners;
|
||||||
|
bool override;
|
||||||
|
|
||||||
|
bool isSignalHandler;
|
||||||
|
struct sigaction defaultHandler;
|
||||||
|
struct sigaction handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct listener events[NUMBER_OF_EVENTS];
|
||||||
|
|
||||||
|
static void debug(const char* format, ...) {
|
||||||
|
if (!boot.debug)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_list arguments;
|
||||||
|
|
||||||
|
int done;
|
||||||
|
|
||||||
|
va_start(arguments, format);
|
||||||
|
|
||||||
|
fprintf(stderr, "[seaboot] ");
|
||||||
|
done = vfprintf(stderr, format, arguments);
|
||||||
|
|
||||||
|
va_end(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool addEventListener(event_t event, eventListener_t listener) {
|
||||||
|
if (event >= NUMBER_OF_EVENTS) {
|
||||||
|
boot.error = "No such event (addEventListener).";
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (events[event].override) {
|
||||||
|
events[event].override = false;
|
||||||
|
events[event].number = 0;
|
||||||
|
}
|
||||||
|
events[event].listeners = realloc(events[event].listeners, (events[event].number + 1) * sizeof(eventListener_t)); // TODO replace with own function
|
||||||
|
events[event].listeners[events[event].number] = listener;
|
||||||
|
debug("New event listener for event %d (%s) on position %d.\n", event, getEventName(event), events[event].number);
|
||||||
|
events[event].number++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool removeEventListener(event_t event, eventListener_t listener) {
|
||||||
|
if (event >= NUMBER_OF_EVENTS) {
|
||||||
|
boot.error = "No such event (removeEventListener).";
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
bool enableSignal(event_t signal) {
|
||||||
|
if (!IS_SIGNAL(signal)) {
|
||||||
|
boot.error = "Not a signal (enableSignal).";
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (sigaction(signal, &(events[signal].handler), NULL) < 0) {
|
||||||
|
boot.error = "Setting signal failed (sigaction).";
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
debug("Signal %d (%s) is enabled.\n", signal, getEventName(signal));
|
||||||
|
events[signal].isSignalHandler = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool disableSignal(event_t signal) {
|
||||||
|
if (!IS_SIGNAL(signal)) {
|
||||||
|
boot.error = "Not a signal (enableSignal).";
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (sigaction(signal, &(events[signal].defaultHandler), NULL) < 0) {
|
||||||
|
boot.error = "Setting signal failed (sigaction).";
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
debug("Signal %d (%s) is disabled.\n", signal, getEventName(signal));
|
||||||
|
events[signal].isSignalHandler = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void eventHandler(event_t event) {
|
||||||
|
debug("Event handler for event %d (%s).\n", event, getEventName(event));
|
||||||
|
debug("Event has %d registered handler(s).\n", events[event].number);
|
||||||
|
for (int i = 0; i < events[event].number; i++) {
|
||||||
|
if (events[event].listeners[i] == NULL)
|
||||||
|
continue;
|
||||||
|
debug("Found handler %d.\n", i);
|
||||||
|
events[event].listeners[i](event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nstime_t getRealTime() {
|
||||||
|
struct timespec time;
|
||||||
|
clock_gettime(CLOCK_REALTIME, &time);
|
||||||
|
return time.tv_sec * 1000000000 + time.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
nstime_t getRelativeTime() {
|
||||||
|
struct timespec time;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &time);
|
||||||
|
return time.tv_sec * 1000000000 + time.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
nstime_t getProcessTime() {
|
||||||
|
struct timespec time;
|
||||||
|
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time);
|
||||||
|
return time.tv_sec * 1000000000 + time.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
nstime_t getThreadTime() {
|
||||||
|
struct timespec time;
|
||||||
|
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time);
|
||||||
|
return time.tv_sec * 1000000000 + time.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
nstime_t timer(void (*function)(void)) {
|
||||||
|
nstime_t start = getRelativeTime();
|
||||||
|
function();
|
||||||
|
nstime_t end = getRelativeTime();
|
||||||
|
return end - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timerHandler(union sigval target) {
|
||||||
|
debug("Timer handler: Starting target.\n");
|
||||||
|
((void (*)(void))(target.sival_ptr))();
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_t createSignalTimer(event_t signal) {
|
||||||
|
debug("Creating signal timer (%d)\n", signal);
|
||||||
|
|
||||||
|
struct sigevent sevp;
|
||||||
|
sevp.sigev_notify = SIGEV_SIGNAL;
|
||||||
|
sevp.sigev_signo = signal;
|
||||||
|
|
||||||
|
timer_t timer;
|
||||||
|
|
||||||
|
if (timer_create(CLOCK_BOOTTIME, &sevp, &timer) < 0) {
|
||||||
|
boot.error = strerror(errno);
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
|
||||||
|
timer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timer;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_t createThreadTimer(void (*handler)(void)) {
|
||||||
|
debug("Creating thread timer\n");
|
||||||
|
|
||||||
|
struct sigevent sevp;
|
||||||
|
sevp.sigev_notify = SIGEV_THREAD;
|
||||||
|
sevp.sigev_notify_function = timerHandler;
|
||||||
|
sevp.sigev_value.sival_ptr = handler;
|
||||||
|
|
||||||
|
timer_t timer;
|
||||||
|
|
||||||
|
if (timer_create(CLOCK_BOOTTIME, &sevp, &timer) < 0) {
|
||||||
|
boot.error = strerror(errno);
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
timer = NULL;
|
||||||
|
}
|
||||||
|
return timer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void startTimer(timer_t timer, unsigned long ms) {
|
||||||
|
debug("Starting timer %x (%d ms)\n", timer, ms);
|
||||||
|
|
||||||
|
struct itimerspec time, old;
|
||||||
|
|
||||||
|
time.it_value.tv_sec = ms / 1000;
|
||||||
|
time.it_value.tv_nsec = ((ms % 1000) * 1000000);
|
||||||
|
time.it_interval.tv_sec = 0;
|
||||||
|
time.it_interval.tv_nsec = 0;
|
||||||
|
|
||||||
|
if (timer_settime(timer, 0, &time, &old) < 0) {
|
||||||
|
boot.error = strerror(errno);
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void startInterval(timer_t timer, unsigned long ms) {
|
||||||
|
debug("Starting timer (interval) %x (%d ms)\n", timer, ms);
|
||||||
|
|
||||||
|
struct itimerspec time, old;
|
||||||
|
|
||||||
|
time.it_value.tv_sec = ms / 1000;
|
||||||
|
time.it_value.tv_nsec = ((ms % 1000) * 1000000);
|
||||||
|
time.it_interval.tv_sec = ms / 1000;
|
||||||
|
time.it_interval.tv_nsec = ((ms % 1000) * 1000000);
|
||||||
|
|
||||||
|
if (timer_settime(timer, 0, &time, &old) < 0) {
|
||||||
|
boot.error = strerror(errno);
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopTimer(timer_t timer) {
|
||||||
|
debug("Stoping timer %x\n", timer);
|
||||||
|
|
||||||
|
struct itimerspec time, old;
|
||||||
|
|
||||||
|
time.it_value.tv_sec = 0;
|
||||||
|
time.it_value.tv_nsec = 0;
|
||||||
|
time.it_interval.tv_sec = 0;
|
||||||
|
time.it_interval.tv_nsec = 0;
|
||||||
|
|
||||||
|
if (timer_settime(timer, 0, &time, &old) < 0) {
|
||||||
|
boot.error = strerror(errno);
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteTimer(timer_t timer) {
|
||||||
|
debug("Deleting timer %x\n", timer);
|
||||||
|
if (timer_delete(timer) < 0) {
|
||||||
|
boot.error = strerror(errno);
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void signalHandler(int signal) {
|
||||||
|
debug("Got signal %d (%s). Involking event handler.\n", signal, getEventName(signal));
|
||||||
|
eventHandler(signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exitHandler(void) {
|
||||||
|
eventHandler(SHUTDOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void errorHandler(event_t event) {
|
||||||
|
fprintf(stderr, "\n[seaboot] Error: %s\n", boot.error);
|
||||||
|
fprintf(stderr, "[seaboot] No error handler given.\n");
|
||||||
|
fprintf(stderr, "[seaboot] Shuting down.\n");
|
||||||
|
exit(EXIT_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(char** argv, int argc) {
|
||||||
|
for(int i = 0; i < NUMBER_OF_EVENTS; i++) {
|
||||||
|
debug("Setup %s %d (%s)...\n", IS_SIGNAL(i) ? "signal" : "event", i, getEventName(i));
|
||||||
|
events[i].number = 0;
|
||||||
|
events[i].listeners = malloc(1 * sizeof(eventListener_t)); // TODO replace by own function
|
||||||
|
events[i].listeners[0] = NULL;
|
||||||
|
events[i].override = false;
|
||||||
|
events[i].isSignalHandler = false;
|
||||||
|
if (IS_SIGNAL(i)) {
|
||||||
|
sigaction(i, NULL, &events[i].defaultHandler);
|
||||||
|
|
||||||
|
boot.error = "Setting exit handler failed (atexit).";
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
events[i].handler.sa_handler = &signalHandler;
|
||||||
|
sigemptyset(&(events[i].handler.sa_mask));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("Setup default error handler.\n");
|
||||||
|
addEventListener(LIBERROR, errorHandler);
|
||||||
|
events[LIBERROR].override = true;
|
||||||
|
|
||||||
|
debug("Setup exit handler.\n");
|
||||||
|
if (atexit(exitHandler) != 0) {
|
||||||
|
boot.error = "Setting exit handler failed (atexit).";
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// start init
|
||||||
|
if (boot.init == NULL) {
|
||||||
|
boot.error = "No init handler given (main).";
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
} else {
|
||||||
|
boot.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boot.mode == LOOP) {
|
||||||
|
if (boot.loop == NULL) {
|
||||||
|
boot.error = "No loop handler given (loop).";
|
||||||
|
eventHandler(LIBERROR);
|
||||||
|
} else {
|
||||||
|
nstime_t last = getRelativeTime();
|
||||||
|
nstime_t current;
|
||||||
|
while(true) {
|
||||||
|
current = getRelativeTime();
|
||||||
|
boot.loop(current - last);
|
||||||
|
last = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (boot.mode == WAIT) {
|
||||||
|
while(true)
|
||||||
|
sleep(60);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
95
src/seaboot.h
Normal file
95
src/seaboot.h
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#ifndef SEABOOT_H
|
||||||
|
#define SEABOOT_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#define EXIT_SUCCESS 0
|
||||||
|
#define EXIT_ERROR 3
|
||||||
|
|
||||||
|
#define BOOT(i) void i(void); __attribute__((constructor)) static void seaboot_init() { boot.init = &i; }
|
||||||
|
#define LOOP(i) void i(void); __attribute__((constructor)) static void seaboot_loop() { boot.loop = &i; }
|
||||||
|
|
||||||
|
#define IS_SIGNAL(v) (v >= 1 && v <= 31)
|
||||||
|
|
||||||
|
typedef unsigned long long int nstime_t;
|
||||||
|
|
||||||
|
typedef enum bootmode {
|
||||||
|
STANDARD,
|
||||||
|
LOOP,
|
||||||
|
WAIT
|
||||||
|
} bootmode_t;
|
||||||
|
|
||||||
|
#define NUMBER_OF_EVENTS 33
|
||||||
|
typedef enum event {
|
||||||
|
SIGHUP = 1,
|
||||||
|
SIGINT = 2,
|
||||||
|
SIGQUIT = 3,
|
||||||
|
SIGILL = 4,
|
||||||
|
SIGTRAP = 5,
|
||||||
|
SIGABRT = 6,
|
||||||
|
SIGIOT = 6,
|
||||||
|
SIGBUS = 7,
|
||||||
|
SIGFPE = 8,
|
||||||
|
SIGKILL = 9,
|
||||||
|
SIGUSR1 = 10,
|
||||||
|
SIGSEGV = 11,
|
||||||
|
SIGUSR2 = 12,
|
||||||
|
SIGPIPE = 13,
|
||||||
|
SIGALRM = 14,
|
||||||
|
SIGTERM = 15,
|
||||||
|
SIGSTKFLT = 16,
|
||||||
|
SIGCHLD = 17,
|
||||||
|
SIGCLD = 17,
|
||||||
|
SIGCONT = 18,
|
||||||
|
SIGSTOP = 19,
|
||||||
|
SIGTSTP = 20,
|
||||||
|
SIGTTIN = 21,
|
||||||
|
SIGTTOU = 22,
|
||||||
|
SIGURG = 23,
|
||||||
|
SIGXCPU = 24,
|
||||||
|
SIGXFSZ = 25,
|
||||||
|
SIGVTALRM = 26,
|
||||||
|
SIGPROF = 27,
|
||||||
|
SIGWINCH = 28,
|
||||||
|
SIGIO = 29,
|
||||||
|
SIGPOLL = 29,
|
||||||
|
SIGPWR = 30,
|
||||||
|
SIGSYS = 31,
|
||||||
|
|
||||||
|
SHUTDOWN = 0,
|
||||||
|
LIBERROR = 32
|
||||||
|
} event_t;
|
||||||
|
|
||||||
|
typedef void (*eventListener_t)(event_t);
|
||||||
|
typedef void (*init_t)(void);
|
||||||
|
typedef void (*loop_t)(nstime_t);
|
||||||
|
|
||||||
|
extern struct boot {
|
||||||
|
init_t init;
|
||||||
|
loop_t loop;
|
||||||
|
bool (*addEventListener)(event_t, eventListener_t);
|
||||||
|
bool (*removeEventListener)(event_t, eventListener_t);
|
||||||
|
bool (*enableSignal)(event_t);
|
||||||
|
bool (*disableSignal)(event_t);
|
||||||
|
|
||||||
|
nstime_t (*getRealTime)(void);
|
||||||
|
nstime_t (*getRelativeTime)(void);
|
||||||
|
nstime_t (*getProcessTime)(void);
|
||||||
|
nstime_t (*getThreadTime)(void);
|
||||||
|
nstime_t (*timer)(void (*)(void));
|
||||||
|
|
||||||
|
timer_t (*createSignalTimer)(event_t);
|
||||||
|
timer_t (*createThreadTimer)(void (*)(void));
|
||||||
|
void (*startTimer)(timer_t, unsigned long);
|
||||||
|
void (*startInterval)(timer_t, unsigned long);
|
||||||
|
void (*stopTimer)(timer_t);
|
||||||
|
void (*deleteTimer)(timer_t);
|
||||||
|
|
||||||
|
bootmode_t mode;
|
||||||
|
bool debug;
|
||||||
|
|
||||||
|
const char* error;
|
||||||
|
} boot;
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue