Skip to content

Commit 93ede76

Browse files
committed
watchdogtimer: refactor to new api
This refactors the WatchDogTimer API to use the format proposed in #2933 (comment) Signed-off-by: Sean Cross <[email protected]>
1 parent 794d7be commit 93ede76

File tree

13 files changed

+308
-149
lines changed

13 files changed

+308
-149
lines changed

ports/nrf/common-hal/microcontroller/__init__.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,14 @@ const nvm_bytearray_obj_t common_hal_mcu_nvm_obj = {
117117
#endif
118118

119119
#if CIRCUITPY_WATCHDOG
120-
// The singleton nvm.WatchDogTimer object.
121-
const watchdog_obj_t common_hal_mcu_watchdog_obj = {
120+
// The singleton watchdog.WatchDogTimer object.
121+
watchdog_watchdogtimer_obj_t common_hal_mcu_watchdogtimer_obj = {
122122
.base = {
123-
.type = &watchdog_type,
123+
.type = &watchdog_watchdogtimer_type,
124124
},
125-
.watchdogtimer = (mp_obj_t)&mp_const_none_obj,
125+
.timeout = 0.0f,
126+
.sleep = false,
127+
.mode = WATCHDOGMODE_NONE,
126128
};
127129
#endif
128130

ports/nrf/common-hal/watchdog/WatchDogMode.c

Whitespace-only changes.

ports/nrf/common-hal/watchdog/WatchDogTimer.c

Lines changed: 138 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@
4141
#include "nrfx_timer.h"
4242
#include "nrf/timers.h"
4343

44-
STATIC watchdog_watchdogtimer_obj_t *wdt_singleton;
45-
STATIC mp_obj_t watchdog_watchdogtimer_feed(mp_obj_t self_in);
4644
STATIC uint8_t timer_refcount = 0;
4745
#define WATCHDOG_RELOAD_COUNT 2
4846
STATIC nrfx_timer_t *timer = NULL;
@@ -80,7 +78,7 @@ NORETURN void mp_raise_WatchDogTimeout(void) {
8078
nlr_raise(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_watchdog_exception)));
8179
}
8280

83-
STATIC void watchdogtimer_event_handler(nrf_timer_event_t event_type, void *p_context) {
81+
STATIC void watchdogtimer_timer_event_handler(nrf_timer_event_t event_type, void *p_context) {
8482
(void)p_context;
8583
if (event_type != NRF_TIMER_EVENT_COMPARE0) {
8684
// Spurious event.
@@ -105,107 +103,20 @@ void watchdog_watchdogtimer_reset(void) {
105103
timer_refcount = 0;
106104
}
107105

108-
//| class WDT:
109-
//| """Watchdog Timer"""
110-
//|
111-
//| def __init__(self, ):
112-
//| """This class represents the system's Watchdog Timer. It is a
113-
//| singleton and will always return the same instance.
114-
//|
115-
//| """
116-
//| ...
117-
//|
118-
STATIC mp_obj_t watchdog_watchdogtimer_make_new(const mp_obj_type_t *type, size_t n_args,
119-
const mp_obj_t *pos_args,
120-
mp_map_t *kw_args) {
121-
enum { ARG_timeout, ARG_sleep, ARG_hardware };
122-
static const mp_arg_t allowed_args[] = {
123-
{MP_QSTR_timeout, MP_ARG_OBJ | MP_ARG_REQUIRED},
124-
{MP_QSTR_sleep, MP_ARG_BOOL, {.u_bool = false}},
125-
{MP_QSTR_hardware, MP_ARG_BOOL, {.u_bool = false}},
126-
};
127-
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
128-
mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_watchdog_exception)));
129-
130-
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args),
131-
allowed_args, args);
132-
mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
133-
bool hardware = args[ARG_hardware].u_bool;
134-
bool sleep = args[ARG_sleep].u_bool;
135-
136-
// If the hardware timer is already running, return that timer.
137-
// If the parameters have changed, then ignore them, but print
138-
// an error.
139-
if (wdt_singleton && hardware) {
140-
if ((sleep != wdt_singleton->sleep)
141-
|| (hardware != wdt_singleton->hardware)
142-
|| fabsf(timeout - wdt_singleton->timeout) > 0.01f) {
143-
// Print a warning indicating things aren't quite right
144-
// mp_printf(&mp_stderr_print, translate("warning: hardware timer was already running"));
145-
}
146-
watchdogtimer_hardware_feed();
147-
return wdt_singleton;
148-
}
149-
150-
if (timeout <= 0) {
151-
mp_raise_ValueError(translate("watchdog timeout must be greater than 0"));
152-
}
153-
154-
watchdog_watchdogtimer_obj_t *self = m_new_obj(watchdog_watchdogtimer_obj_t);
155-
self->base.type = &watchdog_watchdogtimer_type;
156-
self->timeout = timeout;
157-
self->sleep = sleep;
158-
self->hardware = hardware;
159-
160-
if (hardware) {
161-
watchdogtimer_hardware_init(self->timeout, self->sleep);
162-
wdt_singleton = self;
163-
} else {
164-
uint64_t ticks = timeout * 31250ULL;
165-
if (ticks > UINT32_MAX) {
166-
mp_raise_ValueError(translate("timeout duration exceeded the maximum supported value"));
167-
}
168-
169-
if (timer_refcount == 0) {
170-
timer = nrf_peripherals_allocate_timer_or_throw();
171-
}
172-
timer_refcount++;
173-
174-
nrfx_timer_config_t timer_config = {
175-
.frequency = NRF_TIMER_FREQ_31250Hz,
176-
.mode = NRF_TIMER_MODE_TIMER,
177-
.bit_width = NRF_TIMER_BIT_WIDTH_32,
178-
.interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY,
179-
.p_context = self,
180-
};
181-
182-
nrfx_timer_init(timer, &timer_config, &watchdogtimer_event_handler);
183-
184-
// true enables interrupt.
185-
nrfx_timer_clear(timer);
186-
nrfx_timer_compare(timer, NRF_TIMER_CC_CHANNEL0, ticks, true);
187-
nrfx_timer_resume(timer);
188-
}
189-
190-
// Feed the watchdog, in case there's a timer that's already running
191-
// and it's only partially finished.
192-
mp_obj_t *self_obj = MP_OBJ_FROM_PTR(self);
193-
watchdog_watchdogtimer_feed(self_obj);
194-
return self_obj;
195-
}
196-
197106
//| def feed(self):
198107
//| """Feed the watchdog timer. This must be called regularly, otherwise
199-
//| the system will reset."""
108+
//| the timer will expire."""
200109
//| ...
201110
//|
202111
STATIC mp_obj_t watchdog_watchdogtimer_feed(mp_obj_t self_in) {
203112
watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in);
204113

205-
if (self->hardware) {
114+
if (self->mode == WATCHDOGMODE_RESET) {
206115
watchdogtimer_hardware_feed();
207-
} else {
116+
} else if (self->mode == WATCHDOGMODE_RAISE) {
208117
nrfx_timer_clear(timer);
118+
} else if (self->mode == WATCHDOGMODE_NONE) {
119+
mp_raise_ValueError(translate("WatchDogTimer is not currently running"));
209120
}
210121
return mp_const_none;
211122
}
@@ -219,71 +130,178 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_feed_obj, watchdog_watch
219130
STATIC mp_obj_t watchdog_watchdogtimer_deinit(mp_obj_t self_in) {
220131
watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in);
221132

222-
if (!self->hardware) {
133+
if (self->mode == WATCHDOGMODE_RAISE) {
223134
timer_refcount--;
224135
if (timer_refcount == 0) {
225136
nrf_peripherals_free_timer(timer);
226137
timer = NULL;
227138
}
139+
} else if (self->mode == WATCHDOGMODE_RESET) {
140+
mp_raise_NotImplementedError(translate("WatchDogTimer cannot be deinitialized once mode is set to RESET"));
228141
}
229142

230143
return mp_const_none;
231144
}
232145
STATIC MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_deinit_obj, watchdog_watchdogtimer_deinit);
233146

234-
//| timeout: int = ...
235-
//| """The maximum number of milliseconds that can elapse between calls
147+
//| timeout: float = ...
148+
//| """The maximum number of seconds that can elapse between calls
236149
//| to feed()"""
237150
//|
238-
STATIC mp_obj_t watchdog_watchdogtimer_get_timeout(mp_obj_t self_in) {
151+
STATIC mp_obj_t watchdog_watchdogtimer_obj_get_timeout(mp_obj_t self_in) {
239152
watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in);
240153
return mp_obj_new_float(self->timeout);
241154
}
242-
MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_get_timeout_obj, watchdog_watchdogtimer_get_timeout);
155+
MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_get_timeout_obj, watchdog_watchdogtimer_obj_get_timeout);
156+
157+
STATIC mp_obj_t watchdog_watchdogtimer_obj_set_timeout(mp_obj_t self_in, mp_obj_t timeout_obj) {
158+
watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in);
159+
mp_float_t timeout = mp_obj_get_float(timeout_obj);
160+
161+
if (timeout <= 0) {
162+
mp_raise_ValueError(translate("watchdog timeout must be greater than 0"));
163+
}
164+
165+
if (self->mode == WATCHDOGMODE_RESET) {
166+
// If the WatchDogTimer is already running in "RESET" mode, raise an error
167+
// since the mode cannot be changed once started.
168+
mp_raise_TypeError(translate("Cannot change the timeout once mode is WatchDogMode.RESET"));
169+
} else if (self->mode == WATCHDOGMODE_RAISE) {
170+
// If the WatchDogTimer is already running in "RAISE" mode, reset the timer
171+
// with the new value.
172+
uint64_t ticks = timeout * 31250ULL;
173+
if (ticks > UINT32_MAX) {
174+
mp_raise_ValueError(translate("timeout duration exceeded the maximum supported value"));
175+
}
176+
nrfx_timer_clear(timer);
177+
nrfx_timer_compare(timer, NRF_TIMER_CC_CHANNEL0, ticks, true);
178+
}
179+
180+
self->timeout = timeout;
181+
return mp_const_none;
182+
}
183+
MP_DEFINE_CONST_FUN_OBJ_2(watchdog_watchdogtimer_set_timeout_obj, watchdog_watchdogtimer_obj_set_timeout);
243184

244185
const mp_obj_property_t watchdog_watchdogtimer_timeout_obj = {
245186
.base.type = &mp_type_property,
246187
.proxy = {(mp_obj_t)&watchdog_watchdogtimer_get_timeout_obj,
247-
(mp_obj_t)&mp_const_none_obj,
188+
(mp_obj_t)&watchdog_watchdogtimer_set_timeout_obj,
248189
(mp_obj_t)&mp_const_none_obj},
249190
};
250191

251-
mp_obj_t watchdog_watchdogtimer___enter__(mp_obj_t self_in) {
192+
//| mode: watchdog.WatchDogMode = ...
193+
//| """The current operating mode of the WatchDogTimer `watchdog.WatchDogMode`.
194+
//|
195+
//| Setting a WatchDogMode activates the WatchDog::
196+
//|
197+
//| import microcontroller
198+
//| import watchdog
199+
//|
200+
//| w = microcontroller.watchdog
201+
//| w.timeout = 5
202+
//| w.mode = watchdog.WatchDogMode.RAISE
203+
//|
204+
//|
205+
//| Once set, the WatchDogTimer will perform the specified action if the timer expires.
206+
//|
207+
STATIC mp_obj_t watchdog_watchdogtimer_obj_get_mode(mp_obj_t self_in) {
252208
watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in);
253-
254-
if (!self->hardware) {
255-
nrfx_timer_resume(timer);
209+
switch (self->mode) {
210+
case WATCHDOGMODE_NONE: default: return (mp_obj_t)MP_ROM_PTR(&watchdog_watchdogmode_none_obj);
211+
case WATCHDOGMODE_RAISE: return (mp_obj_t)MP_ROM_PTR(&watchdog_watchdogmode_raise_obj);
212+
case WATCHDOGMODE_RESET: return (mp_obj_t)MP_ROM_PTR(&watchdog_watchdogmode_reset_obj);
256213
}
257-
watchdog_watchdogtimer_feed(self_in);
258-
return self_in;
259214
}
260-
MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer___enter___obj, watchdog_watchdogtimer___enter__);
261-
262-
STATIC mp_obj_t watchdog_watchdogtimer___exit__(size_t n_args, const mp_obj_t *args) {
263-
(void)n_args;
264-
watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(args[0]);
265-
if (!self->hardware) {
266-
if (timer) {
267-
nrfx_timer_pause(timer);
215+
MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_get_mode_obj, watchdog_watchdogtimer_obj_get_mode);
216+
217+
STATIC mp_obj_t watchdog_watchdogtimer_obj_set_mode(mp_obj_t self_in, mp_obj_t mode_obj) {
218+
watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in);
219+
watchdog_watchdogmode_obj_t *mode = MP_OBJ_TO_PTR(mode_obj);
220+
if (mode == MP_ROM_PTR(&watchdog_watchdogmode_none_obj)) {
221+
if (self->mode == WATCHDOGMODE_RESET) {
222+
mp_raise_TypeError(translate("WatchDogTimer mode cannot be changed once set to WatchDogMode.RESET"));
223+
}
224+
else if (self->mode == WATCHDOGMODE_RAISE) {
225+
timer_refcount--;
226+
if (timer_refcount == 0) {
227+
nrf_peripherals_free_timer(timer);
228+
timer = NULL;
229+
}
230+
}
231+
self->mode = WATCHDOGMODE_NONE;
232+
233+
} else if (mode == MP_ROM_PTR(&watchdog_watchdogmode_raise_obj)) {
234+
if (self->timeout <= 0) {
235+
mp_raise_ValueError(translate("watchdog timeout must be greater than 0"));
236+
}
237+
if (self->mode == WATCHDOGMODE_RESET) {
238+
mp_raise_ValueError(translate("WatchDogTimer mode cannot be changed once set to WatchDogMode.RESET"));
239+
}
240+
else if (self->mode == WATCHDOGMODE_NONE) {
241+
uint64_t ticks = self->timeout * 31250ULL;
242+
if (ticks > UINT32_MAX) {
243+
mp_raise_ValueError(translate("timeout duration exceeded the maximum supported value"));
244+
}
245+
246+
if (timer_refcount == 0) {
247+
timer = nrf_peripherals_allocate_timer_or_throw();
248+
}
249+
timer_refcount++;
250+
251+
nrfx_timer_config_t timer_config = {
252+
.frequency = NRF_TIMER_FREQ_31250Hz,
253+
.mode = NRF_TIMER_MODE_TIMER,
254+
.bit_width = NRF_TIMER_BIT_WIDTH_32,
255+
.interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY,
256+
.p_context = self,
257+
};
258+
259+
nrfx_timer_init(timer, &timer_config, &watchdogtimer_timer_event_handler);
260+
261+
// true enables interrupt.
262+
nrfx_timer_clear(timer);
263+
nrfx_timer_compare(timer, NRF_TIMER_CC_CHANNEL0, ticks, true);
264+
nrfx_timer_resume(timer);
268265
}
266+
self->mode = WATCHDOGMODE_RAISE;
267+
268+
} else if (mode == MP_ROM_PTR(&watchdog_watchdogmode_reset_obj)) {
269+
if (self->timeout <= 0) {
270+
mp_raise_ValueError(translate("watchdog timeout must be greater than 0"));
271+
}
272+
if (self->mode == WATCHDOGMODE_RAISE) {
273+
timer_refcount--;
274+
if (timer_refcount == 0) {
275+
nrf_peripherals_free_timer(timer);
276+
timer = NULL;
277+
}
278+
}
279+
watchdogtimer_hardware_init(self->timeout, self->sleep);
280+
self->mode = WATCHDOGMODE_RESET;
269281
}
282+
270283
return mp_const_none;
271284
}
272-
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(watchdog_watchdogtimer___exit___obj, 4, 4, watchdog_watchdogtimer___exit__);
285+
MP_DEFINE_CONST_FUN_OBJ_2(watchdog_watchdogtimer_set_mode_obj, watchdog_watchdogtimer_obj_set_mode);
286+
287+
const mp_obj_property_t watchdog_watchdogtimer_mode_obj = {
288+
.base.type = &mp_type_property,
289+
.proxy = {(mp_obj_t)&watchdog_watchdogtimer_get_mode_obj,
290+
(mp_obj_t)&watchdog_watchdogtimer_set_mode_obj,
291+
(mp_obj_t)&mp_const_none_obj},
292+
};
273293

274294
STATIC const mp_rom_map_elem_t watchdog_watchdogtimer_locals_dict_table[] = {
275295
{ MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&watchdog_watchdogtimer_feed_obj) },
276296
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&watchdog_watchdogtimer_deinit_obj) },
277297
{ MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&watchdog_watchdogtimer_timeout_obj) },
278-
// { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
279-
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&watchdog_watchdogtimer___enter___obj) },
280-
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&watchdog_watchdogtimer___exit___obj) },
298+
{ MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&watchdog_watchdogtimer_mode_obj) },
281299
};
282300
STATIC MP_DEFINE_CONST_DICT(watchdog_watchdogtimer_locals_dict, watchdog_watchdogtimer_locals_dict_table);
283301

284302
const mp_obj_type_t watchdog_watchdogtimer_type = {
285303
{ &mp_type_type },
286304
.name = MP_QSTR_WatchDogTimer,
287-
.make_new = watchdog_watchdogtimer_make_new,
305+
// .make_new = watchdog_watchdogtimer_make_new,
288306
.locals_dict = (mp_obj_dict_t*)&watchdog_watchdogtimer_locals_dict,
289307
};

ports/nrf/common-hal/watchdog/WatchDogTimer.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@
2929

3030
#include "py/obj.h"
3131
#include "shared-bindings/watchdog/WatchDogTimer.h"
32+
#include "shared-bindings/watchdog/WatchDogMode.h"
3233

3334
typedef struct _watchdog_watchdogtimer_obj_t {
3435
mp_obj_base_t base;
3536
mp_float_t timeout;
3637
bool sleep;
37-
bool hardware;
38+
watchdog_watchdogmode_t mode;
3839
} watchdog_watchdogtimer_obj_t;
3940

4041
#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H

ports/nrf/common-hal/watchdog/__init__.c

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,3 @@
2323
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2424
* THE SOFTWARE.
2525
*/
26-
27-
#include "py/obj.h"
28-
#include "common-hal/watchdog/__init__.h"
29-
#include "common-hal/watchdog/WatchDogTimer.h"
30-
31-
STATIC const mp_rom_map_elem_t watchdog_locals_dict_table[] = {
32-
{MP_ROM_QSTR(MP_QSTR_WatchDogTimer), MP_ROM_PTR(&watchdog_watchdogtimer_type) },
33-
};
34-
STATIC MP_DEFINE_CONST_DICT(watchdog_locals_dict, watchdog_locals_dict_table);
35-
36-
const mp_obj_type_t watchdog_type = {
37-
{ &mp_type_type },
38-
.name = MP_QSTR_watchdog,
39-
// .make_new = watchdog_watchdogtimer_make_new,
40-
.locals_dict = (mp_obj_dict_t*)&watchdog_locals_dict,
41-
};
42-

py/circuitpy_defns.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ SRC_COMMON_HAL_ALL = \
306306
supervisor/Runtime.c \
307307
supervisor/__init__.c \
308308
watchdog/__init__.c \
309+
watchdog/WatchDogMode.c \
309310
watchdog/WatchDogTimer.c \
310311

311312
SRC_COMMON_HAL = $(filter $(SRC_PATTERNS), $(SRC_COMMON_HAL_ALL))

0 commit comments

Comments
 (0)