File syn_pt.h¶
Go to the documentation of this file
#ifndef SYN_PT_H
#define SYN_PT_H
#include "../common/syn_compiler.h"
#include "../common/syn_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/* ── Protothread continuation ───────────────────────────────────────────── */
typedef struct {
uint16_t lc;
} SYN_PT;
/* ── Return status ──────────────────────────────────────────────────────── */
typedef enum {
PT_WAITING = 0,
PT_YIELDED = 1,
PT_EXITED = 2,
PT_ENDED = 3,
} SYN_PT_Status;
/* ── Core macros ────────────────────────────────────────────────────────── */
#define PT_INIT(pt) ((pt)->lc = 0)
#define PT_BEGIN(pt) \
do { \
char _pt_yield_flag = 1; \
(void)_pt_yield_flag; \
switch ((pt)->lc) { \
case 0:
#define PT_END(pt) \
} \
_pt_yield_flag = 0; \
PT_INIT(pt); \
return PT_EXITED; \
} \
while (0)
#define PT_WAIT_UNTIL(pt, cond) \
do { \
(pt)->lc = __LINE__; \
SYN_FALLTHROUGH; /* intentional Duff's device */ \
case __LINE__: \
if (!(cond)) { \
return PT_WAITING; \
} \
} while (0)
#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL(pt, !(cond))
#define PT_YIELD(pt) \
do { \
_pt_yield_flag = 0; \
(pt)->lc = __LINE__; \
SYN_FALLTHROUGH; \
case __LINE__: \
if (_pt_yield_flag == 0) { \
return PT_YIELDED; \
} \
} while (0)
#define PT_YIELD_UNTIL(pt, cond) \
do { \
_pt_yield_flag = 0; \
(pt)->lc = __LINE__; \
SYN_FALLTHROUGH; \
case __LINE__: \
if ((_pt_yield_flag == 0) || !(cond)) { \
return PT_YIELDED; \
} \
} while (0)
#define PT_EXIT(pt) \
do { \
PT_INIT(pt); \
return PT_ENDED; \
} while (0)
#define PT_RESTART(pt) \
do { \
PT_INIT(pt); \
return PT_WAITING; \
} while (0)
/* ── Child / sub-protothread ────────────────────────────────────────────── */
#define PT_SPAWN(pt, child, func) \
do { \
PT_INIT(child); \
(pt)->lc = __LINE__; \
SYN_FALLTHROUGH; \
case __LINE__: \
if ((func) < PT_EXITED) { \
return PT_WAITING; \
} \
} while (0)
/* ── Timer-aware delay (requires task descriptor) ───────────────────────── */
/*
* PT_DELAY_MS needs access to both the tick source and a place to store
* the delay target. When used with the scheduler (syn_task.h), the
* SYN_Task struct provides `delay_until`. For standalone use, provide
* your own uint32_t target variable.
*/
#define PT_DELAY_MS(pt, target, ms) \
do { \
*(target) = syn_port_get_tick_ms() + (uint32_t)(ms); \
PT_WAIT_UNTIL(pt, (int32_t)(syn_port_get_tick_ms() - *(target)) >= 0); \
} while (0)
#define PT_TASK_DELAY_MS(pt, task, ms) PT_DELAY_MS(pt, &(task)->delay_until, ms)
#define PT_DEFER(pt, task) \
do { \
(task)->state = (uint8_t)SYN_TASK_DEFERRED; \
PT_YIELD(pt); \
} while (0)
#define PT_BLOCK_EVENT(pt, task, grp, mask) \
do { \
(task)->wait_event = (SYN_EventFlags *)(grp); \
(task)->wait_mask = (mask); \
(task)->state = (uint8_t)SYN_TASK_BLOCKED; \
PT_YIELD(pt); \
(grp)->flags &= ~(mask); /* Auto-clear matched */ \
} while (0)
/* ── Query macros ───────────────────────────────────────────────────────── */
#define PT_IS_RUNNING(pt) ((pt)->lc != 0)
#define PT_IS_IDLE(pt) ((pt)->lc == 0)
#ifdef __cplusplus
}
#endif
#endif /* SYN_PT_H */