/* * Copyright (C) 2018 Eistec AB * 2020 Kaspar Schleiser * 2020 Freie UniversitÀt Berlin * 2020 Inria * * This file is subject to the terms and conditions of the GNU Lesser General * Public License v2.1. See the file LICENSE in the top level directory for more * details. */ /** * @ingroup sys_ztimer_mock * * @{ * * @file * @brief ztimer mock implementation * * @author Joakim NohlgÄrd * @} */ #include #include #include "assert.h" #include "ztimer/mock.h" #define ENABLE_DEBUG 0 #include "debug.h" /* Functions for controlling the mock clock below */ void ztimer_mock_advance(ztimer_mock_t *self, uint32_t val) { DEBUG( "zmock_advance: start now=0x%08" PRIx32 " + 0x%08" PRIx32 ", target=0x%08" PRIx32 " (%u)\n", self->now, val, self->target, self->armed); while (val) { uint32_t step = self->armed ? (self->target < val ? self->target : val) : val; DEBUG( "zmock_advance: step now=0x%08" PRIx32 " + 0x%08" PRIx32 ", target=0x%08" PRIx32 " (%u)\n", self->now, step, self->target, self->armed); self->now = (self->now + step) & self->mask; if (self->armed) { /* Update target */ if (step >= self->target) { /* Target was hit */ ztimer_mock_fire(self); } else { self->target -= step; } } val -= step; } DEBUG( "zmock_advance: done now=0x%08" PRIx32 " + 0x%08" PRIx32 ", target=0x%08" PRIx32 " (%u)\n", self->now, val, self->target, self->armed); } void ztimer_mock_jump(ztimer_mock_t *self, uint32_t target) { self->now = target & self->mask; DEBUG("zmock_jump: now=0x%08" PRIx32 ", target=0x%08" PRIx32 " (%u)\n", self->now, self->target, self->armed); /* Do not touch target */ } void ztimer_mock_fire(ztimer_mock_t *self) { DEBUG("zmock_fire: now=0x%08" PRIx32 ", target=0x%08" PRIx32 " (%u)\n", self->now, self->target, self->armed); self->target = 0; self->armed = 0; /* Execute ztimer core interrupt handler */ ztimer_handler(&self->super); } /* Implementations for the standard ztimer operations below */ static void ztimer_mock_op_set(ztimer_clock_t *clock, uint32_t val) { ztimer_mock_t *self = (ztimer_mock_t *)clock; assert(self->running == 1); ++self->calls.set; self->target = val & self->mask; self->armed = 1; DEBUG( "zmock_set: %3u now=0x%08" PRIx32 ", target=0x%08" PRIx32 " (%u)\n", self->calls.set, self->now, self->target, self->armed); } static uint32_t ztimer_mock_op_now(ztimer_clock_t *clock) { ztimer_mock_t *self = (ztimer_mock_t *)clock; ++self->calls.now; DEBUG( "zmock_now: %3u now=0x%08" PRIx32 ", target=0x%08" PRIx32 " (%u)\n", self->calls.now, self->now, self->target, self->armed); return self->now; } static void ztimer_mock_op_cancel(ztimer_clock_t *clock) { ztimer_mock_t *self = (ztimer_mock_t *)clock; assert(self->running == 1); ++self->calls.cancel; DEBUG( "zmock_cancel: %3u now=0x%08" PRIx32 ", target=0x%08" PRIx32 " (%u)\n", self->calls.cancel, self->now, self->target, self->armed); self->armed = 0; } #if MODULE_ZTIMER_ONDEMAND static void ztimer_mock_op_start(ztimer_clock_t *clock) { ztimer_mock_t *self = (ztimer_mock_t *)clock; ++self->calls.start; DEBUG("zmock_start: %3u\n", self->calls.start); self->running = 1; } static void ztimer_mock_op_stop(ztimer_clock_t *clock) { ztimer_mock_t *self = (ztimer_mock_t *)clock; assert(self->armed == 0); ++self->calls.stop; DEBUG("zmock_stop: %3u\n", self->calls.stop); self->running = 0; } #endif static const ztimer_ops_t ztimer_mock_ops = { .set = ztimer_mock_op_set, .now = ztimer_mock_op_now, .cancel = ztimer_mock_op_cancel, #if MODULE_ZTIMER_ONDEMAND .start = ztimer_mock_op_start, .stop = ztimer_mock_op_stop, #endif }; void ztimer_mock_init(ztimer_mock_t *self, unsigned width) { uint32_t max_value = (~((uint32_t)0ul)) >> (32 - width); *self = (ztimer_mock_t){ .mask = max_value, .super = { .ops = &ztimer_mock_ops, .max_value = max_value }, }; #if !MODULE_ZTIMER_ONDEMAND /* turn the timer on by default if ondemand feature is not used */ self->running = 1; #endif DEBUG("zmock_init: %p width=%u mask=0x%08" PRIx32 " running=%u\n", (void *)self, width, self->mask, self->running); if (max_value < UINT32_MAX) { self->super.ops->set(&self->super, self->super.max_value >> 1); } }