Skip to content

Commit fa03742

Browse files
committed
Add watchdog example
1 parent 8571ce2 commit fa03742

File tree

5 files changed

+251
-2
lines changed

5 files changed

+251
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [0-based versioning](https://0ver.org/).
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Watchdog example
13+
1014
## v0.14.2 - 13-September-2025
1115

1216
### Changed

apps/examples/meson.build

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,17 @@ smokers = executable(
155155
]
156156
)
157157

158+
watchdog = executable(
159+
'watchdog',
160+
['watchdog' / 'main.c'],
161+
dependencies: [
162+
libhsm_dep,
163+
libao_preemptive_dep,
164+
libpal_dep,
165+
libassert_dep,
166+
]
167+
)
168+
158169
if pal != 'stubs'
159170
test('smokers', smokers, suite: 'smokers')
160171
test('workers', workers, suite: 'workers')

apps/examples/watchdog/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Watchdog example.
2+
3+
The console output:
4+
5+
```
6+
EVT_WDT_FEED sent
7+
EVT_WDT_FEED received
8+
EVT_WDT_FEED sent
9+
EVT_WDT_FEED received
10+
EVT_WDT_FEED sent
11+
EVT_WDT_FEED received
12+
WATCHED TASK FAILED!
13+
```
14+
15+

apps/examples/watchdog/main.c

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) Adel Mamin
5+
*
6+
* Source: https://github.com/adel-mamin/amast
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
* SOFTWARE.
25+
*/
26+
27+
/*
28+
* A task 'watched' is monitored by a watchdog task 'wdt'.
29+
* The 'watched' tasks works fine for 3 seconds, after which
30+
* it fails to feed 'wdt' in time.
31+
*/
32+
33+
#include <stdio.h>
34+
#include <stdint.h>
35+
#include <stdlib.h>
36+
#include <string.h>
37+
38+
#include "common/macros.h"
39+
#include "event/event.h"
40+
#include "timer/timer.h"
41+
#include "ao/ao.h"
42+
#include "pal/pal.h"
43+
#include "hsm/hsm.h"
44+
45+
#define AM_WDT_FEED_TIMEOUT_MS 1000
46+
#define AM_WDT_BARK_TIMEOUT_MS (AM_WDT_FEED_TIMEOUT_MS + 100)
47+
48+
enum evt {
49+
EVT_WATCHED_TIMEOUT = AM_EVT_USER,
50+
EVT_WDT_FEED,
51+
EVT_WDT_BARK,
52+
};
53+
54+
struct watched {
55+
struct am_ao ao;
56+
struct am_timer timer_wdt_feed;
57+
int feeds_num;
58+
};
59+
60+
struct wdt {
61+
struct am_ao ao;
62+
struct am_timer timer_wdt_bark;
63+
};
64+
65+
/* tasks */
66+
static struct watched m_watched;
67+
static struct wdt m_wdt;
68+
69+
/* task event queues */
70+
static const struct am_event *m_queue_watched[1];
71+
static const struct am_event *m_queue_wdt[2];
72+
73+
/* task events */
74+
static const struct am_event m_evt_wdt_feed = {.id = EVT_WDT_FEED};
75+
76+
/* 'watched' task */
77+
78+
static int watched_proc(struct watched *me, const struct am_event *event) {
79+
switch (event->id) {
80+
case AM_EVT_ENTRY: {
81+
am_timer_arm_ms(
82+
&me->timer_wdt_feed, AM_WDT_FEED_TIMEOUT_MS, AM_WDT_FEED_TIMEOUT_MS
83+
);
84+
return AM_HSM_HANDLED();
85+
}
86+
case EVT_WATCHED_TIMEOUT: {
87+
if (me->feeds_num < 3) {
88+
am_pal_printff("EVT_WDT_FEED sent\n");
89+
am_ao_post_fifo(&m_wdt.ao, &m_evt_wdt_feed);
90+
++me->feeds_num;
91+
}
92+
return AM_HSM_HANDLED();
93+
}
94+
default:
95+
break;
96+
}
97+
return AM_HSM_SUPER(am_hsm_top);
98+
}
99+
100+
static int watched_init(struct watched *me, const struct am_event *event) {
101+
(void)event;
102+
am_timer_ctor(
103+
&me->timer_wdt_feed,
104+
EVT_WATCHED_TIMEOUT,
105+
AM_PAL_TICK_DOMAIN_DEFAULT,
106+
/*owner=*/&me->ao
107+
);
108+
return AM_HSM_TRAN(watched_proc);
109+
}
110+
111+
static void watched_ctor(struct watched *me) {
112+
memset(me, 0, sizeof(*me));
113+
am_ao_ctor(&me->ao, AM_HSM_STATE_CTOR(watched_init));
114+
}
115+
116+
/* 'wdt' task */
117+
118+
static int wdt_proc(struct wdt *me, const struct am_event *event) {
119+
switch (event->id) {
120+
case AM_EVT_ENTRY: {
121+
am_timer_arm_ms(
122+
&me->timer_wdt_bark, AM_WDT_BARK_TIMEOUT_MS, /*interval=*/0
123+
);
124+
return AM_HSM_HANDLED();
125+
}
126+
case EVT_WDT_FEED: {
127+
am_pal_printff("EVT_WDT_FEED received\n");
128+
/* re-arm bark timer */
129+
am_timer_arm_ms(
130+
&me->timer_wdt_bark, AM_WDT_BARK_TIMEOUT_MS, /*interval=*/0
131+
);
132+
return AM_HSM_HANDLED();
133+
}
134+
case EVT_WDT_BARK: {
135+
am_pal_printff("WATCHED TASK FAILED!\n");
136+
exit(-1);
137+
}
138+
default:
139+
break;
140+
}
141+
return AM_HSM_SUPER(am_hsm_top);
142+
}
143+
144+
static int wdt_init(struct wdt *me, const struct am_event *event) {
145+
(void)event;
146+
am_timer_ctor(
147+
&me->timer_wdt_bark,
148+
EVT_WDT_BARK,
149+
AM_PAL_TICK_DOMAIN_DEFAULT,
150+
/*owner=*/&me->ao
151+
);
152+
return AM_HSM_TRAN(wdt_proc);
153+
}
154+
155+
static void wdt_ctor(struct wdt *me) {
156+
memset(me, 0, sizeof(*me));
157+
am_ao_ctor(&me->ao, AM_HSM_STATE_CTOR(wdt_init));
158+
}
159+
160+
/* timer task to drive timers */
161+
162+
static void ticker_task(void *param) {
163+
(void)param;
164+
165+
am_pal_task_wait_all();
166+
167+
uint32_t now_ticks = am_pal_time_get_tick(AM_PAL_TICK_DOMAIN_DEFAULT);
168+
while (am_ao_get_cnt() > 0) {
169+
am_pal_sleep_till_ticks(AM_PAL_TICK_DOMAIN_DEFAULT, now_ticks + 1);
170+
now_ticks += 1;
171+
am_timer_tick(AM_PAL_TICK_DOMAIN_DEFAULT);
172+
}
173+
}
174+
175+
int main(void) {
176+
am_ao_state_ctor(/*cfg=*/NULL);
177+
178+
watched_ctor(&m_watched);
179+
wdt_ctor(&m_wdt);
180+
181+
am_ao_start(
182+
&m_watched.ao,
183+
(struct am_ao_prio){.ao = AM_AO_PRIO_MAX, .task = AM_AO_PRIO_MAX},
184+
/*queue=*/m_queue_watched,
185+
/*nqueue=*/AM_COUNTOF(m_queue_watched),
186+
/*stack=*/NULL,
187+
/*stack_size=*/0,
188+
/*name=*/"watched",
189+
/*init_event=*/NULL
190+
);
191+
192+
am_ao_start(
193+
&m_wdt.ao,
194+
(struct am_ao_prio){.ao = AM_AO_PRIO_MIN, .task = AM_AO_PRIO_MIN},
195+
/*queue=*/m_queue_wdt,
196+
/*nqueue=*/AM_COUNTOF(m_queue_wdt),
197+
/*stack=*/NULL,
198+
/*stack_size=*/0,
199+
/*name=*/"wdt",
200+
/*init_event=*/NULL
201+
);
202+
203+
am_pal_task_create(
204+
"ticker",
205+
/*prio=*/AM_AO_PRIO_MIN,
206+
/*stack=*/NULL,
207+
/*stack_size=*/0,
208+
/*entry=*/ticker_task,
209+
/*arg=*/NULL
210+
);
211+
212+
while (am_ao_get_cnt() > 0) {
213+
am_ao_run_all();
214+
}
215+
216+
am_ao_state_dtor();
217+
218+
return EXIT_SUCCESS;
219+
}

meson.build

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ project('amast', 'c',
2929
default_options : [
3030
'c_std=c99',
3131
'warning_level=3',
32-
'buildtype=release',
32+
'buildtype=debug',
3333
'werror=true',
34-
'b_lto=true',
34+
# 'b_lto=true',
3535
'default_library=static',
3636
'b_sanitize=address,undefined'
3737
],

0 commit comments

Comments
 (0)