Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core Library Proposal: Watchdog-safe iterators #346

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
71 changes: 71 additions & 0 deletions fw/src/mgos_iterator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include <stdlib.h>
#include "mgos.h"
#include "mgos_iterator.h"
#include "mgos_timers.h"

struct mgos_iterator_ctx {
predicate has_next;
callable next;
mgos_timer_id timer_id;
void *param;
};

struct mgos_iterator_count {
int current;
int limit;
callable_with_index cb;
mgos_iterator_id iterator;
void *param;
};

static void mgos_iterator_step(void *arg) {
struct mgos_iterator_ctx *mi = (struct mgos_iterator_ctx *)arg;
if (mi->has_next(mi->param)) {
mi->next(mi->param);
} else {
mgos_clear_iterator((mgos_iterator_id)mi);
}
}

mgos_iterator_id mgos_iterator(int msecs, predicate has_next, timer_callback cb, void *param) {
struct mgos_iterator_ctx *mi = new struct mgos_iterator_ctx;
mi->has_next = has_next;
mi->next = (callable) cb;
mi->timer_id = mgos_set_timer(msecs, true, mgos_iterator_step, mi);
mi->param = param;
return (mgos_iterator_id) mi;
}

bool mgos_iterator_count_has_next(void *arg) {
struct mgos_iterator_count *ctx = (struct mgos_iterator_count *)arg;
return ctx->current < ctx->limit;
}

void mgos_iterator_count_next(void *arg) {
struct mgos_iterator_count *ctx = (struct mgos_iterator_count *)arg;
ctx->cb(ctx->param, ctx->current);
ctx->current += 1;
}

void mgos_clear_iterator_count(mgos_iterator_count_id arg) {
struct mgos_iterator_count *ctx = (struct mgos_iterator_count *)arg;
mgos_clear_iterator(ctx->iterator);
delete ctx;
}

mgos_iterator_count_id mgos_iterator_count(int msecs, int limit, callable_with_index cb, void *param) {
struct mgos_iterator_count *mic = new struct mgos_iterator_count;
LOG(LL_INFO, ("New count iterator w/ limit %d and param %p", limit, param));
mic->limit = limit;
mic->current = 0;
mic->cb = cb;
mic->param = param;
mic->iterator = mgos_iterator(msecs, mgos_iterator_count_has_next, mgos_iterator_count_next, mic);
return (mgos_iterator_count_id) mic;
}

void mgos_clear_iterator(mgos_iterator_id iterator_id) {
struct mgos_iterator_ctx *ctx = (struct mgos_iterator_ctx *)iterator_id;
mgos_clear_timer(ctx->timer_id);
delete ctx;
}
43 changes: 43 additions & 0 deletions fw/src/mgos_iterator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef _MGOS_ITERATOR_H_
#define _MGOS_ITERATOR_H_

#include <stdint.h>
#include <stdbool.h>
#include "mgos_timers.h"

typedef void (*callable)(void *param);
typedef bool (*predicate)(void *param);
typedef void (*callable_with_index)(void *param, int i);

typedef uintptr_t mgos_iterator_id;
typedef uintptr_t mgos_iterator_count_id;

/*
* Setup an iterator with `msecs` timeout (see mgos_set_timer).
*
* `has_next` is a predicate function to determine if this iterator has any work left to do
* `cb` is the callback that does the work for a given step
* `arg` is a parameter passed to `cb`.
* Returns an iterator id that can be used with `mgos_clear_iterator`
*/
mgos_iterator_id mgos_iterator(int msecs, predicate has_next, timer_callback cb, void *arg);

/*
* Setup a counted iteration.
*
* This iteration will run at most `limit` times and step every `msecs`.
*
* `cb` is a callback called with the `arg` and the current iteration value (0, 1, 2, ...)
*
* Returns an id that can be used with mgos_clear_iterator_count();
*/

mgos_iterator_count_id mgos_iterator_count(int msecs, int limit, callable_with_index cb, void *arg);

/* Clear an iterator created previously with `mgos_iterator_count` */
void mgos_clear_iterator_count(mgos_iterator_count_id arg);

/* Clear an iterator created previously with `mgos_iterator` */
void mgos_clear_iterator(mgos_iterator_id iterator_id);

#endif /* _MGOS_ITERATOR_H_ */