ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
sen0192.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4#ifndef PROTOCORE_SEN0192_H
5#define PROTOCORE_SEN0192_H
6
7#include "protocore_config.h" // the entry point: protocore_types.h for the widths
8
10
11/**
12 * @file sen0192.h
13 * @brief DFRobot SEN0192 10.525 GHz microwave Doppler motion sensor (PROTOCORE_ENABLE_SEN0192).
14 *
15 * The SEN0192 is a 3-pin part (V / G / digital OUT) whose OUT line asserts while it senses motion
16 * (Doppler shift) within its adjustable range. Unlike the framed serial of an LD2410, it carries no
17 * protocol - it is a single digital line - so the "driver" is a debounced presence tracker over that
18 * line: assert presence on an active sample and hold it for a configurable window after the last active
19 * sample, so brief gaps between Doppler returns don't make presence flap.
20 *
21 * The presence state machine (::Sen0192Motion) is pure and host-tested - it takes a sampled line level
22 * and a timestamp and needs no clock or GPIO. The binding reads PROTOCORE_SEN0192_PIN each poll (via
23 * protocore_millis()) and feeds it in; only that read reaches the pin seam. The OUT polarity and hold window come
24 * from ServerConfig (PROTOCORE_SEN0192_ACTIVE_HIGH / PROTOCORE_SEN0192_HOLD_MS / PROTOCORE_SEN0192_PIN).
25 *
26 * @c work is PROTOCORE_SEN0192_BORROW bytes the CALLER took, at an address it knows. It is not held past the call, so
27 * nothing here aliases it. How those bytes are carved is this module's and is never named here.
28 *
29 * @author Douglas Quigg (dstroy0)
30 * @date 2026
31 */
32
33/**
34 * @brief Debounced motion-presence tracker over a single digital line.
35 *
36 * Presence asserts on an active-level sample and is held for @c hold_ms after the last active sample; an
37 * inactive stretch longer than @c hold_ms clears it. Pure: time is passed in, so it is fully host-testable.
38 */
39typedef struct
40{
41 proto_bool present; ///< presence currently asserted (respecting the hold window)
42 proto_bool seeded; ///< a first sample has been fed (so the hold timing is meaningful)
43 proto_bool active_high; ///< the active (motion) state is a logic HIGH
44 uint32_t hold_ms; ///< presence is held this long after the last active sample
45 uint32_t last_active_ms; ///< timestamp of the last active-level sample
46 uint32_t motion_events; ///< count of clear -> present transitions (rising edges of presence)
48
49/** @brief Dispatch table. Addressed by offset, so the layout is asserted below. */
50typedef struct
51{
52 void (*motion_init)(uint8_t *, Sen0192Motion *, uint32_t, proto_bool);
53 proto_bool (*motion_update)(uint8_t *, Sen0192Motion *, proto_bool, uint32_t);
54 proto_bool (*motion_tick)(uint8_t *, Sen0192Motion *, uint32_t);
55 proto_bool (*motion_present)(uint8_t *, const Sen0192Motion *);
56 uint32_t (*motion_events)(uint8_t *, const Sen0192Motion *);
57 uint32_t (*motion_active_age_ms)(uint8_t *, const Sen0192Motion *, uint32_t);
58 proto_bool (*begin)(uint8_t *);
59 proto_bool (*poll)(uint8_t *);
60 void (*present)(uint8_t *);
61 void (*motion_count)(uint8_t *);
62} Sen0192Ns;
63PROTOCORE_NS_LAYOUT(Sen0192Ns, motion_init, motion_update, motion_tick, motion_present, motion_events,
64 motion_active_age_ms, begin, poll, present, motion_count);
65
66/**
67 * @brief Initialize a tracker: active_high sets the motion polarity, hold_ms .
68 * @param work PROTOCORE_SEN0192_BORROW bytes the caller took. Not held past the call.
69 * @param m M
70 * @param hold_ms Hold ms
71 * @param active_high Active high
72 */
73void protocore_sen0192_motion_init(uint8_t *work, Sen0192Motion *m, uint32_t hold_ms, proto_bool active_high);
74/**
75 * @brief Feed one sampled line level at now_ms.
76 * @param work PROTOCORE_SEN0192_BORROW bytes the caller took. Not held past the call.
77 * @param m M
78 * @param level_high Level high
79 * @param now_ms Now ms
80 * @return PROTO_TRUE on success.
81 */
82proto_bool protocore_sen0192_motion_update(uint8_t *work, Sen0192Motion *m, proto_bool level_high, uint32_t now_ms);
83/**
84 * @brief Re-evaluate presence against the hold window at now_ms without a .
85 * @param work PROTOCORE_SEN0192_BORROW bytes the caller took. Not held past the call.
86 * @param m M
87 * @param now_ms Now ms
88 * @return PROTO_TRUE on success.
89 */
90proto_bool protocore_sen0192_motion_tick(uint8_t *work, Sen0192Motion *m, uint32_t now_ms);
91/**
92 * @brief Current presence (respecting the hold window).
93 * @param work PROTOCORE_SEN0192_BORROW bytes the caller took. Not held past the call.
94 * @param m M
95 * @return PROTO_TRUE on success.
96 */
98/**
99 * @brief Number of clear -> present transitions since init.
100 * @param work PROTOCORE_SEN0192_BORROW bytes the caller took. Not held past the call.
101 * @param m M
102 * @return The uint32_t.
103 */
104uint32_t protocore_sen0192_motion_events(uint8_t *work, const Sen0192Motion *m);
105/**
106 * @brief Milliseconds since the last active-level sample (0 if none yet).
107 * @param work PROTOCORE_SEN0192_BORROW bytes the caller took. Not held past the call.
108 * @param m M
109 * @param now_ms Now ms
110 * @return The uint32_t.
111 */
112uint32_t protocore_sen0192_motion_active_age_ms(uint8_t *work, const Sen0192Motion *m, uint32_t now_ms);
113/**
114 * @brief Configure PROTOCORE_SEN0192_PIN as an input and start tracking .
115 * @param work PROTOCORE_SEN0192_BORROW bytes the caller took. Not held past the call.
116 * @return PROTO_TRUE on success.
117 */
119/**
120 * @brief Sample the pin now (via protocore_millis()). true iff a new .
121 * @param work PROTOCORE_SEN0192_BORROW bytes the caller took. Not held past the call.
122 * @return PROTO_TRUE on success.
123 */
125/**
126 * @brief Current presence.
127 * @param work PROTOCORE_SEN0192_BORROW bytes the caller took. Not held past the call.
128 */
129void protocore_sen0192_present(uint8_t *work);
130/**
131 * @brief Count of motion events (clear -> present transitions) since .
132 * @param work PROTOCORE_SEN0192_BORROW bytes the caller took. Not held past the call.
133 */
135
136/**
137 * @brief The PROTOCORE_SEN0192_BORROW bytes this module's state lives in.
138 *
139 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
140 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
141 * walks, so the state lasts the life of the program.
142 *
143 * @return the span.
144 */
146
147/** @brief Module namespace. */
158
160
161#endif // PROTOCORE_SEN0192_H
#define PROTOCORE_NS_LAYOUT(T,...)
Pin every dispatch slot of a table that is nothing but function pointers.
#define PROTOCORE_NS
Storage for a dispatch table. The const is load bearing.
proto_bool protocore_sen0192_motion_present(uint8_t *work, const Sen0192Motion *m)
Current presence (respecting the hold window).
proto_bool protocore_sen0192_begin(uint8_t *work)
Configure PROTOCORE_SEN0192_PIN as an input and start tracking .
void protocore_sen0192_present(uint8_t *work)
Current presence.
uint8_t * protocore_sen0192_span(void)
The PROTOCORE_SEN0192_BORROW bytes this module's state lives in.
uint32_t protocore_sen0192_motion_events(uint8_t *work, const Sen0192Motion *m)
Number of clear -> present transitions since init.
proto_bool protocore_sen0192_motion_tick(uint8_t *work, Sen0192Motion *m, uint32_t now_ms)
Re-evaluate presence against the hold window at now_ms without a .
void protocore_sen0192_motion_init(uint8_t *work, Sen0192Motion *m, uint32_t hold_ms, proto_bool active_high)
Initialize a tracker: active_high sets the motion polarity, hold_ms .
proto_bool protocore_sen0192_motion_update(uint8_t *work, Sen0192Motion *m, proto_bool level_high, uint32_t now_ms)
Feed one sampled line level at now_ms.
void protocore_sen0192_motion_count(uint8_t *work)
Count of motion events (clear -> present transitions) since .
uint32_t protocore_sen0192_motion_active_age_ms(uint8_t *work, const Sen0192Motion *m, uint32_t now_ms)
Milliseconds since the last active-level sample (0 if none yet).
PROTOCORE_NS Sen0192Ns Sen0192 PROTOCORE_UNUSED
Module namespace.
Definition sen0192.h:148
proto_bool protocore_sen0192_poll(uint8_t *work)
Sample the pin now (via protocore_millis()). true iff a new .
Debounced motion-presence tracker over a single digital line.
Definition sen0192.h:40
proto_bool seeded
a first sample has been fed (so the hold timing is meaningful)
Definition sen0192.h:42
uint32_t last_active_ms
timestamp of the last active-level sample
Definition sen0192.h:45
uint32_t motion_events
count of clear -> present transitions (rising edges of presence)
Definition sen0192.h:46
proto_bool active_high
the active (motion) state is a logic HIGH
Definition sen0192.h:43
uint32_t hold_ms
presence is held this long after the last active sample
Definition sen0192.h:44
proto_bool present
presence currently asserted (respecting the hold window)
Definition sen0192.h:41
Dispatch table. Addressed by offset, so the layout is asserted below.
Definition sen0192.h:51
void(* motion_init)(uint8_t *, Sen0192Motion *, uint32_t, proto_bool)
Definition sen0192.h:52
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97