This sample runs work after a delay, in three common shapes: a debounce, where every edge of a button pushes the work back; a timeout, which keeps its first delay; and a heartbeat that schedules itself again without drifting, until it is canceled.
pbl_delayed_work_cancel_sync() returns with the heartbeat stopped for good,
although its function schedules it again: what a driver calls before freeing
the object the work lives in.
pbl samples samples/kernel/delayed_work
every board
#include <pbl/kernel/delay.h>
#include <pbl/kernel/work.h>
#include <pbl/logging/logging.h>
#define DEBOUNCE_MS 200
#define HEARTBEAT_MS 20
static unsigned int s_presses;
static unsigned int s_heartbeats;
static void prv_button_settled(struct pbl_work *work) {
s_presses++;
PBL_LOG_INFO("button: settled, press %u", s_presses);
}
static void prv_heartbeat(struct pbl_work *work);
static PBL_DELAYED_WORK_DEFINE(s_debounce, prv_button_settled);
static PBL_DELAYED_WORK_DEFINE(s_heartbeat, prv_heartbeat);
/* Unlike a timer callback this runs on a thread, and may block or take locks. */
static void prv_heartbeat(struct pbl_work *work) {
s_heartbeats++;
/* Counts from the last expiry, not from now, so the period does not drift. */
pbl_delayed_work_schedule_next(&s_heartbeat, pbl_ms_to_ticks(HEARTBEAT_MS));
}
/* What a button interrupt would do on every edge, bounces included. */
static void prv_button_edge(void) {
pbl_delayed_work_reschedule(&pbl_sys_workq, &s_debounce, PBL_MSEC(DEBOUNCE_MS));
}
int main(void) {
bool kept;
PBL_LOG_INFO("main: five edges 5 ms apart, each pushing the work back");
for (unsigned int i = 0; i < 5; i++) {
prv_button_edge();
pbl_sleep_ms(5);
}
pbl_sleep_ms(2 * DEBOUNCE_MS);
/* schedule() keeps a delay that is running, where reschedule() replaces it. */
pbl_delayed_work_schedule(&pbl_sys_workq, &s_debounce, PBL_MSEC(DEBOUNCE_MS));
kept = !pbl_delayed_work_schedule(&pbl_sys_workq, &s_debounce, PBL_SEC(10));
PBL_LOG_INFO("main: scheduled twice, first delay kept: %s", kept ? "yes" : "no");
pbl_sleep_ms(2 * DEBOUNCE_MS);
pbl_delayed_work_schedule(&pbl_sys_workq, &s_heartbeat, PBL_MSEC(HEARTBEAT_MS));
pbl_sleep_ms(5 * HEARTBEAT_MS + HEARTBEAT_MS / 2);
/* Stops it for good, even though its function schedules it again. */
pbl_delayed_work_cancel_sync(&s_heartbeat);
PBL_LOG_INFO("main: heartbeat stopped after %u beats, pending: %s", s_heartbeats,
pbl_delayed_work_is_pending(&s_heartbeat) ? "yes" : "no");
PBL_LOG_INFO("Sample done");
return 0;
}
main: five edges 5 ms apart, each pushing the work back
button: settled, press 1
main: scheduled twice, first delay kept: yes
button: settled, press 2
main: heartbeat stopped after \d beats, pending: no
Sample done
Generated from PebbleOS f4926c952. This page is maintained in the pebbleos repository: docs/samples/kernel/delayed_work.md.