mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #16928 from kaspar030/ztimer64
sys/ztimer64: initial PR
This commit is contained in:
commit
d959ce7eea
@ -49,7 +49,7 @@ extern "C" {
|
||||
* to avoid not printing of debug in interrupts
|
||||
*/
|
||||
#ifndef THREAD_STACKSIZE_IDLE
|
||||
#ifdef MODULE_XTIMER
|
||||
#if MODULE_XTIMER || MODULE_ZTIMER64
|
||||
/* xtimer's 64 bit arithmetic doesn't perform well on 8 bit archs. In order to
|
||||
* prevent a stack overflow when an timer triggers while the idle thread is
|
||||
* running, we have to increase the stack size then
|
||||
|
@ -165,7 +165,9 @@ PSEUDOMODULES += wakaama_objects_%
|
||||
PSEUDOMODULES += wifi_enterprise
|
||||
PSEUDOMODULES += xtimer_on_ztimer
|
||||
PSEUDOMODULES += zptr
|
||||
PSEUDOMODULES += ztimer%
|
||||
PSEUDOMODULES += ztimer
|
||||
PSEUDOMODULES += ztimer_%
|
||||
PSEUDOMODULES += ztimer64_%
|
||||
|
||||
# ztimer's main module is called "ztimer_core"
|
||||
NO_PSEUDOMODULES += ztimer_core
|
||||
|
@ -84,6 +84,7 @@ rsource "usb_board_reset/Kconfig"
|
||||
rsource "vfs/Kconfig"
|
||||
rsource "xtimer/Kconfig"
|
||||
rsource "ztimer/Kconfig"
|
||||
rsource "ztimer64/Kconfig"
|
||||
|
||||
config MODULE_CPP
|
||||
bool "Use CPP compiler"
|
||||
|
@ -755,10 +755,15 @@ ifneq (,$(filter suit_%,$(USEMODULE)))
|
||||
endif
|
||||
|
||||
# include ztimer dependencies
|
||||
ifneq (,$(filter ztimer% %ztimer,$(USEMODULE)))
|
||||
ifneq (,$(filter ztimer ztimer_% %ztimer,$(USEMODULE)))
|
||||
include $(RIOTBASE)/sys/ztimer/Makefile.dep
|
||||
endif
|
||||
|
||||
# include ztimer64 dependencies
|
||||
ifneq (,$(filter ztimer64%,$(USEMODULE)))
|
||||
include $(RIOTBASE)/sys/ztimer64/Makefile.dep
|
||||
endif
|
||||
|
||||
ifneq (,$(filter evtimer,$(USEMODULE)))
|
||||
ifneq (,$(filter evtimer_on_ztimer,$(USEMODULE)))
|
||||
USEMODULE += ztimer_msec
|
||||
|
@ -33,6 +33,11 @@ void auto_init(void)
|
||||
void ztimer_init(void);
|
||||
ztimer_init();
|
||||
}
|
||||
if (IS_USED(MODULE_AUTO_INIT_ZTIMER64)) {
|
||||
LOG_DEBUG("Auto init ztimer64.\n");
|
||||
void ztimer64_init(void);
|
||||
ztimer64_init();
|
||||
}
|
||||
if (IS_USED(MODULE_AUTO_INIT_XTIMER) &&
|
||||
!IS_USED(MODULE_ZTIMER_XTIMER_COMPAT)) {
|
||||
LOG_DEBUG("Auto init xtimer.\n");
|
||||
|
534
sys/include/ztimer64.h
Normal file
534
sys/include/ztimer64.h
Normal file
@ -0,0 +1,534 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Inria
|
||||
* 2021 Freie Universität Berlin
|
||||
* 2021 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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
|
||||
* @defgroup sys_ztimer64 ztimer 64bit version
|
||||
* @brief ztimer 64bit version
|
||||
*
|
||||
* # Introduction
|
||||
*
|
||||
* This module implements a 64bit version of the ztimer API.
|
||||
* All ztimer_* functions have a ztimer64_* equivalent that behaves the same,
|
||||
* but allowing offsets >= 2^32.
|
||||
*
|
||||
* In addition to that, ztimer64 offers functions taking absolute target times
|
||||
* as parameter.
|
||||
* If the absolute target time is in the past, a timer would trigger right away.
|
||||
*
|
||||
* Here's a table for absolute variants:
|
||||
*
|
||||
* | relative version | absolute version |
|
||||
* |--------------------------------|--------------------------------|
|
||||
* | ztimer64_set() | ztimer64_set_at() |
|
||||
* | ztimer64_sleep() | ztimer64_sleep_until() |
|
||||
* | ztimer64_set_msg() | ztimer64_set_msg_at() |
|
||||
* | ztimer64_set_wakeup() | ztimer64_set_wakeup_at() |
|
||||
* | ztimer64_set_timeout_flag() | ztimer64_set_timeout_flag_at() |
|
||||
* | ztimer64_msg_receive_timeout() | ztimer64_msg_receive_until() |
|
||||
* | ztimer64_mutex_lock_timeout() | ztimer64_mutex_lock_until() |
|
||||
* | ztimer64_rmutex_lock_timeout() | ztimer64_rmutex_lock_until() |
|
||||
*
|
||||
* ## ztimer64 clocks
|
||||
*
|
||||
* ztimer64 provides automatic setup of ZTIMER64_SEC, ZTIMER64_MSEC and
|
||||
* ZTIMER64_USEC, using the ztimer(32) clocks as base clocks.
|
||||
* Enable them by depending on ztimer64_sec, ztimer64_msec and / or ztimer64_usec.
|
||||
*
|
||||
* @warning ztimer64 always keeps a timer running on the base clock. Depending
|
||||
* on the base clock, this blocks low-power sleep modes. If the hardware
|
||||
* supports it, the msec and sec timers should be using a low-power capable
|
||||
* timer (e.g., periph_rtt). ztimer64_usec will almost certainly block
|
||||
* low-power sleep.
|
||||
*
|
||||
* TODO:
|
||||
* - some explicit power management
|
||||
* - implement adjust_set and adjust_sleep API
|
||||
* - implement setting a 64bit reference time (epoch)
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief ztimer 64bit API
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*/
|
||||
|
||||
#ifndef ZTIMER64_H
|
||||
#define ZTIMER64_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mutex.h"
|
||||
#include "msg.h"
|
||||
#include "ztimer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ztimer64_t forward declaration
|
||||
*/
|
||||
typedef struct ztimer64_base ztimer64_base_t;
|
||||
/**
|
||||
* @brief ztimer64_clock_t forward declaration
|
||||
*/
|
||||
typedef struct ztimer64_clock ztimer64_clock_t;
|
||||
|
||||
/**
|
||||
* @brief Minimum information for each timer
|
||||
*/
|
||||
struct ztimer64_base {
|
||||
ztimer64_base_t *next; /**< next timer in list */
|
||||
uint64_t target; /**< absolute target time */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief ztimer64 structure
|
||||
*
|
||||
* This type represents an instance of a timer, which is set on an
|
||||
* underlying clock object
|
||||
*/
|
||||
typedef struct {
|
||||
ztimer64_base_t base; /**< clock list entry */
|
||||
void (*callback)(void *arg); /**< timer callback function pointer */
|
||||
void *arg; /**< timer callback argument */
|
||||
} ztimer64_t;
|
||||
|
||||
/**
|
||||
* @brief ztimer64 clock structure
|
||||
*/
|
||||
struct ztimer64_clock {
|
||||
ztimer64_base_t *first; /**< list of active timers */
|
||||
ztimer_clock_t *base_clock; /**< 32bit clock backend */
|
||||
ztimer_t base_timer; /**< 32bit backend timer */
|
||||
uint64_t checkpoint; /**< lower timer checkpoint offset */
|
||||
uint16_t adjust_set; /**< will be subtracted on every set() */
|
||||
uint16_t adjust_sleep; /**< will be subtracted on every sleep(),
|
||||
in addition to adjust_set */
|
||||
#if MODULE_PM_LAYERED || DOXYGEN
|
||||
uint8_t block_pm_mode; /**< min. pm mode to block for the clock to run */
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get the current time from a clock
|
||||
*
|
||||
* @param[in] clock ztimer clock to operate on
|
||||
*
|
||||
* @return Current count on @p clock
|
||||
*/
|
||||
uint64_t ztimer64_now(ztimer64_clock_t *clock);
|
||||
|
||||
/**
|
||||
* @brief Get absolute target time for a clock given offset
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in] offset relative target time
|
||||
*
|
||||
* @returns absolute target time
|
||||
*/
|
||||
static inline uint64_t ztimer64_offset2absolute(ztimer64_clock_t *clock,
|
||||
uint64_t offset)
|
||||
{
|
||||
unsigned state = irq_disable();
|
||||
uint64_t result = ztimer64_now(clock) + offset;
|
||||
|
||||
irq_restore(state);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a timer on a clock (absolute version)
|
||||
*
|
||||
* This will place @p timer in the timer targets queue of @p clock.
|
||||
*
|
||||
* @note The memory pointed to by @p timer is not copied and must
|
||||
* remain in scope until the callback is fired or the timer
|
||||
* is removed via @ref ztimer64_remove
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in] timer timer entry to set
|
||||
* @param[in] target absolute target time
|
||||
*/
|
||||
void ztimer64_set_at(ztimer64_clock_t *clock, ztimer64_t *timer,
|
||||
uint64_t target);
|
||||
|
||||
/**
|
||||
* @brief Set a timer on a clock (relative version)
|
||||
*
|
||||
* This will place @p timer in the timer targets queue of @p clock.
|
||||
*
|
||||
* @note The memory pointed to by @p timer is not copied and must
|
||||
* remain in scope until the callback is fired or the timer
|
||||
* is removed via @ref ztimer64_remove
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in] timer timer entry to set
|
||||
* @param[in] offset relative target time
|
||||
*/
|
||||
static inline void ztimer64_set(ztimer64_clock_t *clock, ztimer64_t *timer,
|
||||
uint64_t offset)
|
||||
{
|
||||
ztimer64_set_at(clock, timer,
|
||||
ztimer64_offset2absolute(clock, offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if a timer is currently active
|
||||
*
|
||||
* @param[in] timer timer to check
|
||||
*
|
||||
* @return 1 if timer is active
|
||||
* @return 0 if timer is not active
|
||||
*/
|
||||
unsigned ztimer64_is_set(const ztimer64_t *timer);
|
||||
|
||||
/**
|
||||
* @brief Remove a timer from a clock
|
||||
*
|
||||
* This will place @p timer in the timer targets queue for @p clock.
|
||||
*
|
||||
* This function does nothing if @p timer is not found in the timer queue of
|
||||
* @p clock.
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in] timer timer entry to remove
|
||||
*/
|
||||
void ztimer64_remove(ztimer64_clock_t *clock, ztimer64_t *timer);
|
||||
|
||||
/**
|
||||
* @brief Post a message at a specified time
|
||||
*
|
||||
* This function sets a timer that will send a message at time @p target.
|
||||
*
|
||||
* @note The memory pointed to by @p timer and @p msg will not be copied, i.e.
|
||||
* `*timer` and `*msg` needs to remain valid until the timer has triggered.
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in] timer ztimer64 timer struct to use
|
||||
* @param[in] target absolute target time
|
||||
* @param[in] msg pointer to msg that will be sent
|
||||
* @param[in] target_pid pid the message will be sent to
|
||||
*/
|
||||
void ztimer64_set_msg_at(ztimer64_clock_t *clock, ztimer64_t *timer,
|
||||
uint64_t target,
|
||||
msg_t *msg, kernel_pid_t target_pid);
|
||||
|
||||
/**
|
||||
* @brief Post a message after a delay (relative version)
|
||||
*
|
||||
* This function sets a timer that will send a message @p offset ticks
|
||||
* from now.
|
||||
*
|
||||
* @note The memory pointed to by @p timer and @p msg will not be copied, i.e.
|
||||
* `*timer` and `*msg` needs to remain valid until the timer has triggered.
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in] timer ztimer64 timer struct to use
|
||||
* @param[in] offset relative target time
|
||||
* @param[in] msg pointer to msg that will be sent
|
||||
* @param[in] target_pid pid the message will be sent to
|
||||
*/
|
||||
static inline void ztimer64_set_msg(ztimer64_clock_t *clock, ztimer64_t *timer,
|
||||
uint64_t offset,
|
||||
msg_t *msg, kernel_pid_t target_pid)
|
||||
{
|
||||
ztimer64_set_msg_at(clock, timer,
|
||||
ztimer64_offset2absolute(clock, offset),
|
||||
msg, target_pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief receive a message (blocking, with absolute timeout)
|
||||
*
|
||||
* Similar to msg_receive(), but with a timeout parameter.
|
||||
* The function will return after waiting at most until @p target.
|
||||
*
|
||||
* @note: This might function might leave a message with type MSG_ZTIMER64 in the
|
||||
* thread's message queue, which must be handled (ignored).
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[out] msg pointer to buffer which will be filled if a
|
||||
* message is received
|
||||
* @param[in] target absolute target, in @p clock time
|
||||
*
|
||||
* @return >=0 if a message was received
|
||||
* @return -ETIME on timeout
|
||||
*/
|
||||
int ztimer64_msg_receive_until(ztimer64_clock_t *clock, msg_t *msg,
|
||||
uint64_t target);
|
||||
|
||||
/**
|
||||
* @brief receive a message (blocking, with relative timeout)
|
||||
*
|
||||
* Similar to msg_receive(), but with a timeout parameter.
|
||||
* The function will return after waiting at most @p timeout ticks.
|
||||
*
|
||||
* @note: This might function might leave a message with type MSG_ZTIMER64 in the
|
||||
* thread's message queue, which must be handled (ignored).
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[out] msg pointer to buffer which will be filled if a
|
||||
* message is received
|
||||
* @param[in] timeout relative timeout, in @p clock time units
|
||||
*
|
||||
* @return >=0 if a message was received
|
||||
* @return -ETIME on timeout
|
||||
*/
|
||||
static inline int ztimer64_msg_receive_timeout(ztimer64_clock_t *clock,
|
||||
msg_t *msg,
|
||||
uint64_t timeout)
|
||||
{
|
||||
return ztimer64_msg_receive_until(clock, msg,
|
||||
ztimer64_offset2absolute(clock, timeout));
|
||||
}
|
||||
|
||||
#define MSG_ZTIMER64 0xc83f /**< msg type used by ztimer64_msg_receive_timeout */
|
||||
|
||||
/**
|
||||
* @brief Suspend the calling thread until the time (@p last_wakeup + @p period)
|
||||
*
|
||||
* This function can be used to create periodic wakeups.
|
||||
*
|
||||
* When the function returns, @p last_wakeup is set to
|
||||
* (@p last_wakeup + @p period).
|
||||
*
|
||||
* @c last_wakeup should be set to ztimer64_now(@p clock) before first call of the
|
||||
* function.
|
||||
*
|
||||
* If the time (@p last_wakeup + @p period) has already passed, the function
|
||||
* sets @p last_wakeup to @p last_wakeup + @p period and returns immediately.
|
||||
*
|
||||
* @note if you period is smaller than 2^32 ticks, consider using the 32bit version.
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in] last_wakeup base time stamp for the wakeup
|
||||
* @param[in] period time in ticks that will be added to @p last_wakeup
|
||||
*/
|
||||
void ztimer64_periodic_wakeup(ztimer64_clock_t *clock, uint64_t *last_wakeup,
|
||||
uint64_t period);
|
||||
|
||||
/**
|
||||
* @brief Put the calling thread to sleep until the specified time
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to use
|
||||
* @param[in] target wakeup time, in @p clock time
|
||||
*/
|
||||
void ztimer64_sleep_until(ztimer64_clock_t *clock, uint64_t target);
|
||||
|
||||
/**
|
||||
* @brief Put the calling thread to sleep for the specified number of ticks
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to use
|
||||
* @param[in] duration duration of sleep, in @p ztimer time units
|
||||
*/
|
||||
static inline void ztimer64_sleep(ztimer64_clock_t *clock, uint64_t duration)
|
||||
{
|
||||
ztimer64_sleep_until(clock, ztimer64_offset2absolute(clock, duration));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Busy-wait until specified target time
|
||||
*
|
||||
* @note: This blocks lower priority threads. Use only for *very* short delays.
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to use
|
||||
* @param[in] target time when spinning should end, in @p clock time
|
||||
*/
|
||||
static inline void ztimer64_spin_until(ztimer64_clock_t *clock, uint64_t target)
|
||||
{
|
||||
while (ztimer64_now(clock) <= target) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a timer that wakes up a thread (absolute version)
|
||||
*
|
||||
* This function sets a timer that will wake up a thread when the timer has
|
||||
* expired.
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in] timer timer struct to work with.
|
||||
* @param[in] target wakeup time
|
||||
* @param[in] pid pid of the thread that will be woken up
|
||||
*/
|
||||
void ztimer64_set_wakeup_at(ztimer64_clock_t *clock, ztimer64_t *timer,
|
||||
uint64_t target,
|
||||
kernel_pid_t pid);
|
||||
|
||||
/**
|
||||
* @brief Set a timer that wakes up a thread (relative version)
|
||||
*
|
||||
* This function sets a timer that will wake up a thread when the timer has
|
||||
* expired.
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in] timer timer struct to work with.
|
||||
* @param[in] offset clock ticks from now
|
||||
* @param[in] pid pid of the thread that will be woken up
|
||||
*/
|
||||
static inline void ztimer64_set_wakeup(ztimer64_clock_t *clock,
|
||||
ztimer64_t *timer, uint64_t offset,
|
||||
kernel_pid_t pid)
|
||||
{
|
||||
ztimer64_set_wakeup_at(clock, timer,
|
||||
ztimer64_offset2absolute(clock, offset), pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set timeout thread flag at @p target time
|
||||
*
|
||||
* This function will set THREAD_FLAG_TIMEOUT on the current thread at time
|
||||
* @p target.
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in] timer timer struct to use
|
||||
* @param[in] target target in @p clock time
|
||||
*/
|
||||
void ztimer64_set_timeout_flag_at(ztimer64_clock_t *clock, ztimer64_t *timer,
|
||||
uint64_t target);
|
||||
|
||||
/**
|
||||
* @brief Set timeout thread flag after @p timeout
|
||||
*
|
||||
* This function will set THREAD_FLAG_TIMEOUT on the current thread after @p
|
||||
* timeout usec have passed.
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in] timer timer struct to use
|
||||
* @param[in] timeout timeout in ztimer64_clock's ticks
|
||||
*/
|
||||
static inline void ztimer64_set_timeout_flag(ztimer64_clock_t *clock,
|
||||
ztimer64_t *timer,
|
||||
uint64_t timeout)
|
||||
{
|
||||
ztimer64_set_timeout_flag_at(clock, timer,
|
||||
ztimer64_offset2absolute(clock, timeout));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Try to lock the given mutex, but give up at @p target time
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in,out] mutex Mutex object to lock
|
||||
* @param[in] target time after which to give up
|
||||
*
|
||||
* @retval 0 Success, caller has the mutex
|
||||
* @retval -ECANCELED Failed to obtain mutex within @p timeout
|
||||
*/
|
||||
int ztimer64_mutex_lock_until(ztimer64_clock_t *clock, mutex_t *mutex,
|
||||
uint64_t target);
|
||||
|
||||
/**
|
||||
* @brief Try to lock the given mutex, but give up after @p timeout
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in,out] mutex Mutex object to lock
|
||||
* @param[in] timeout timeout after which to give up
|
||||
*
|
||||
* @retval 0 Success, caller has the mutex
|
||||
* @retval -ECANCELED Failed to obtain mutex within @p timeout
|
||||
*/
|
||||
static inline int ztimer64_mutex_lock_timeout(ztimer64_clock_t *clock,
|
||||
mutex_t *mutex,
|
||||
uint64_t timeout)
|
||||
{
|
||||
return ztimer64_mutex_lock_until(clock, mutex,
|
||||
ztimer64_offset2absolute(clock, timeout));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Try to lock the given rmutex, but give up at @p time
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in,out] rmutex rmutex object to lock
|
||||
* @param[in] target time after which to give up
|
||||
*
|
||||
* @retval 0 Success, caller has the rmutex
|
||||
* @retval -ECANCELED Failed to obtain rmutex before @p time
|
||||
*/
|
||||
int ztimer64_rmutex_lock_until(ztimer64_clock_t *clock, rmutex_t *rmutex,
|
||||
uint64_t target);
|
||||
|
||||
/**
|
||||
* @brief Try to lock the given rmutex, but give up after @p timeout
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in,out] rmutex rmutex object to lock
|
||||
* @param[in] timeout timeout after which to give up
|
||||
*
|
||||
* @retval 0 Success, caller has the rmutex
|
||||
* @retval -ECANCELED Failed to obtain rmutex within @p timeout
|
||||
*/
|
||||
static inline int ztimer64_rmutex_lock_timeout(ztimer64_clock_t *clock,
|
||||
rmutex_t *rmutex,
|
||||
uint64_t timeout)
|
||||
{
|
||||
return ztimer64_rmutex_lock_until(clock, rmutex,
|
||||
ztimer64_offset2absolute(clock, timeout));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update ztimer clock head list offset
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param[in] clock ztimer clock to work on
|
||||
*/
|
||||
void ztimer64_update_head_offset(ztimer64_clock_t *clock);
|
||||
|
||||
/**
|
||||
* @brief Initialize the board-specific default ztimer configuration
|
||||
*/
|
||||
void ztimer64_init(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize @p clock to be run from @p base_clock
|
||||
* @param[in,out] clock Clock to initialize
|
||||
* @param[in] base_clock Base clock to use
|
||||
*/
|
||||
void ztimer64_clock_init(ztimer64_clock_t *clock, ztimer_clock_t *base_clock);
|
||||
|
||||
/* default ztimer virtual devices */
|
||||
/**
|
||||
* @brief Default ztimer microsecond clock
|
||||
*/
|
||||
extern ztimer64_clock_t *const ZTIMER64_USEC;
|
||||
|
||||
/**
|
||||
* @brief Default ztimer millisecond clock
|
||||
*/
|
||||
extern ztimer64_clock_t *const ZTIMER64_MSEC;
|
||||
|
||||
/**
|
||||
* @brief Default ztimer second clock
|
||||
*/
|
||||
extern ztimer64_clock_t *const ZTIMER64_SEC;
|
||||
|
||||
/**
|
||||
* @brief Measure ztimer64 overhead
|
||||
*
|
||||
* This function can be used to measure the overhead incurred by ztimer64.
|
||||
* It will configure a callback to trigger after @p base ticks, then return the
|
||||
* number of ticks that have passed, minus @p base.
|
||||
*
|
||||
* @param[in] clock ztimer64 clock to operate on
|
||||
* @param[in] base base interval to use
|
||||
* @return (time from ztimer64_set() until callback) - base
|
||||
*/
|
||||
int64_t ztimer64_overhead(ztimer64_clock_t *clock, uint64_t base);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZTIMER64_H */
|
||||
/** @} */
|
@ -24,6 +24,17 @@
|
||||
#include "irq.h"
|
||||
#include "ztimer/periph_timer.h"
|
||||
|
||||
#ifndef ZTIMER_PERIPH_TIMER_OFFSET
|
||||
/* This can be used for testing. E.g.,
|
||||
*
|
||||
* CFLAGS="-DZTIMER_PERIPH_TIMER_OFFSET=4000000000LU" make ...
|
||||
*
|
||||
* The value will be added to every lower level timer read.
|
||||
* @note this breaks if the low-level timer doesn't have 32bit width!
|
||||
*/
|
||||
#define ZTIMER_PERIPH_TIMER_OFFSET 0LU
|
||||
#endif
|
||||
|
||||
static void _ztimer_periph_timer_set(ztimer_clock_t *clock, uint32_t val)
|
||||
{
|
||||
ztimer_periph_timer_t *ztimer_periph = (ztimer_periph_timer_t *)clock;
|
||||
@ -51,7 +62,7 @@ static uint32_t _ztimer_periph_timer_now(ztimer_clock_t *clock)
|
||||
{
|
||||
ztimer_periph_timer_t *ztimer_periph = (ztimer_periph_timer_t *)clock;
|
||||
|
||||
return timer_read(ztimer_periph->dev);
|
||||
return timer_read(ztimer_periph->dev) + ZTIMER_PERIPH_TIMER_OFFSET;
|
||||
}
|
||||
|
||||
static void _ztimer_periph_timer_cancel(ztimer_clock_t *clock)
|
||||
|
47
sys/ztimer64/Kconfig
Normal file
47
sys/ztimer64/Kconfig
Normal file
@ -0,0 +1,47 @@
|
||||
# Copyright (c) 2021 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.
|
||||
#
|
||||
|
||||
menu "ztimer64 - High level timer abstraction layer"
|
||||
|
||||
# TODO: this extra indirection in the entry point for ztimer_usec is required
|
||||
# to allow xtimer compatibility modules to depend on ztimer being there while
|
||||
# still selecting ztimer_usec.
|
||||
config ZTIMER64_USEC
|
||||
bool "Microseconds 64bit Timer"
|
||||
select ZTIMER_USEC
|
||||
select MODULE_ZTIMER64
|
||||
select MODULE_ZTIMER64_USEC
|
||||
|
||||
config MODULE_ZTIMER64_USEC
|
||||
bool
|
||||
select MODULE_ZTIMER_USEC
|
||||
|
||||
config MODULE_ZTIMER64_MSEC
|
||||
bool "Milliseconds 64bit Timer"
|
||||
select MODULE_ZTIMER_MSEC
|
||||
|
||||
config MODULE_ZTIMER64_SEC
|
||||
bool "Milliseconds 64bit Timer"
|
||||
select MODULE_ZTIMER_SEC
|
||||
|
||||
config MODULE_ZTIMER64_INIT
|
||||
bool
|
||||
|
||||
config MODULE_ZTIMER64
|
||||
bool
|
||||
depends on TEST_KCONFIG
|
||||
|
||||
if MODULE_ZTIMER64
|
||||
config MODULE_AUTO_INIT_ZTIMER64
|
||||
bool "Auto initialize ztimer64"
|
||||
depends on MODULE_AUTO_INIT
|
||||
select MODULE_ZTIMER_INIT
|
||||
select MODULE_ZTIMER64_INIT
|
||||
default y
|
||||
endif # MODULE_ZTIMER64
|
||||
|
||||
endmenu
|
1
sys/ztimer64/Makefile
Normal file
1
sys/ztimer64/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
20
sys/ztimer64/Makefile.dep
Normal file
20
sys/ztimer64/Makefile.dep
Normal file
@ -0,0 +1,20 @@
|
||||
#
|
||||
# ztimer64 dependencies
|
||||
#
|
||||
USEMODULE += ztimer
|
||||
USEMODULE += ztimer64
|
||||
|
||||
ifneq (,$(filter ztimer64_usec,$(USEMODULE)))
|
||||
DEFAULT_MODULE += auto_init_ztimer64
|
||||
USEMODULE += ztimer_usec
|
||||
endif
|
||||
|
||||
ifneq (,$(filter ztimer64_msec,$(USEMODULE)))
|
||||
DEFAULT_MODULE += auto_init_ztimer64
|
||||
USEMODULE += ztimer_msec
|
||||
endif
|
||||
|
||||
ifneq (,$(filter ztimer64_sec,$(USEMODULE)))
|
||||
DEFAULT_MODULE += auto_init_ztimer64
|
||||
USEMODULE += ztimer_sec
|
||||
endif
|
50
sys/ztimer64/overhead.c
Normal file
50
sys/ztimer64/overhead.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* 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_ztimer64
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief ztimer64 overhead measurement functions
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "atomic_utils.h"
|
||||
#include "ztimer64.h"
|
||||
|
||||
typedef struct {
|
||||
ztimer64_clock_t *clock;
|
||||
volatile uint64_t *val;
|
||||
} callback_arg_t;
|
||||
|
||||
static void _callback(void *arg)
|
||||
{
|
||||
callback_arg_t *callback_arg = (callback_arg_t *)arg;
|
||||
|
||||
atomic_store_u64(callback_arg->val, ztimer64_now(callback_arg->clock));
|
||||
}
|
||||
|
||||
int64_t ztimer64_overhead(ztimer64_clock_t *clock, uint64_t base)
|
||||
{
|
||||
volatile uint64_t after = 0;
|
||||
uint64_t pre;
|
||||
|
||||
callback_arg_t arg = { .clock = clock, .val = &after };
|
||||
ztimer64_t t = { .callback = _callback, .arg = &arg };
|
||||
|
||||
pre = ztimer64_now(clock);
|
||||
ztimer64_set(clock, &t, base);
|
||||
while (!atomic_load_u64(&after)) {}
|
||||
return after - pre - base;
|
||||
}
|
192
sys/ztimer64/util.c
Normal file
192
sys/ztimer64/util.c
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* 2021 Inria
|
||||
* 2021 Freie Universität Berlin
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sys_ztimer64_util ztimer64 utility functions
|
||||
* @ingroup sys_ztimer64
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief ztimer64 high-level utility function implementations
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "irq.h"
|
||||
#include "mutex.h"
|
||||
#include "rmutex.h"
|
||||
#include "thread.h"
|
||||
#include "ztimer64.h"
|
||||
|
||||
static void _callback_unlock_mutex(void *arg)
|
||||
{
|
||||
mutex_t *mutex = (mutex_t *)arg;
|
||||
|
||||
mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
void ztimer64_sleep_until(ztimer64_clock_t *clock, uint64_t target)
|
||||
{
|
||||
assert(!irq_is_in());
|
||||
mutex_t mutex = MUTEX_INIT_LOCKED;
|
||||
|
||||
ztimer64_t timer = {
|
||||
.callback = _callback_unlock_mutex,
|
||||
.arg = (void *)&mutex,
|
||||
};
|
||||
|
||||
ztimer64_set_at(clock, &timer, target);
|
||||
mutex_lock(&mutex);
|
||||
}
|
||||
|
||||
void ztimer64_periodic_wakeup(ztimer64_clock_t *clock, uint64_t *last_wakeup,
|
||||
uint64_t period)
|
||||
{
|
||||
unsigned state = irq_disable();
|
||||
uint64_t now = ztimer64_now(clock);
|
||||
uint64_t target = *last_wakeup + period;
|
||||
|
||||
irq_restore(state);
|
||||
|
||||
if (target > now) {
|
||||
ztimer64_sleep_until(clock, target);
|
||||
*last_wakeup = target;
|
||||
}
|
||||
else {
|
||||
*last_wakeup = now;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MODULE_CORE_MSG
|
||||
static void _callback_msg(void *arg)
|
||||
{
|
||||
msg_t *msg = (msg_t *)arg;
|
||||
|
||||
msg_send_int(msg, msg->sender_pid);
|
||||
}
|
||||
|
||||
static inline void _setup_msg(ztimer64_t *timer, msg_t *msg,
|
||||
kernel_pid_t target_pid)
|
||||
{
|
||||
timer->callback = _callback_msg;
|
||||
timer->arg = (void *)msg;
|
||||
|
||||
/* use sender_pid field to get target_pid into callback function */
|
||||
msg->sender_pid = target_pid;
|
||||
}
|
||||
|
||||
void ztimer64_set_msg_at(ztimer64_clock_t *clock, ztimer64_t *timer,
|
||||
uint64_t target,
|
||||
msg_t *msg, kernel_pid_t target_pid)
|
||||
{
|
||||
_setup_msg(timer, msg, target_pid);
|
||||
ztimer64_set_at(clock, timer, target);
|
||||
}
|
||||
|
||||
int ztimer64_msg_receive_until(ztimer64_clock_t *clock, msg_t *msg,
|
||||
uint64_t target)
|
||||
{
|
||||
if (msg_try_receive(msg) == 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ztimer64_t t;
|
||||
msg_t m = { .type = MSG_ZTIMER, .content.ptr = &m };
|
||||
|
||||
ztimer64_set_msg_at(clock, &t, target, &m, thread_getpid());
|
||||
|
||||
msg_receive(msg);
|
||||
ztimer64_remove(clock, &t);
|
||||
if (msg->type == MSG_ZTIMER64 && msg->content.ptr == &m) {
|
||||
/* we hit the timeout */
|
||||
return -ETIME;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MODULE_CORE_MSG */
|
||||
|
||||
#ifdef MODULE_CORE_THREAD_FLAGS
|
||||
static void _set_timeout_flag_callback(void *arg)
|
||||
{
|
||||
thread_flags_set(arg, THREAD_FLAG_TIMEOUT);
|
||||
}
|
||||
|
||||
void ztimer64_set_timeout_flag_at(ztimer64_clock_t *clock, ztimer64_t *t,
|
||||
uint64_t target)
|
||||
{
|
||||
t->callback = _set_timeout_flag_callback;
|
||||
t->arg = thread_get_active();
|
||||
thread_flags_clear(THREAD_FLAG_TIMEOUT);
|
||||
ztimer64_set(clock, t, target);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _callback_wakeup(void *arg)
|
||||
{
|
||||
thread_wakeup((kernel_pid_t)((intptr_t)arg));
|
||||
}
|
||||
|
||||
void ztimer64_set_wakeup_at(ztimer64_clock_t *clock, ztimer64_t *timer,
|
||||
uint64_t target,
|
||||
kernel_pid_t pid)
|
||||
{
|
||||
ztimer64_remove(clock, timer);
|
||||
|
||||
timer->callback = _callback_wakeup;
|
||||
timer->arg = (void *)((intptr_t)pid);
|
||||
|
||||
ztimer64_set_at(clock, timer, target);
|
||||
}
|
||||
|
||||
static void timeout_cb(void *arg)
|
||||
{
|
||||
mutex_cancel(arg);
|
||||
}
|
||||
|
||||
int ztimer64_mutex_lock_until(ztimer64_clock_t *clock, mutex_t *mutex,
|
||||
uint64_t target)
|
||||
{
|
||||
if (mutex_trylock(mutex)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mutex_cancel_t mc = mutex_cancel_init(mutex);
|
||||
ztimer64_t t = { .callback = timeout_cb, .arg = &mc };
|
||||
|
||||
ztimer64_set_at(clock, &t, target);
|
||||
if (mutex_lock_cancelable(&mc)) {
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
ztimer64_remove(clock, &t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ztimer64_rmutex_lock_until(ztimer64_clock_t *clock, rmutex_t *rmutex,
|
||||
uint64_t target)
|
||||
{
|
||||
if (rmutex_trylock(rmutex)) {
|
||||
return 0;
|
||||
}
|
||||
if (ztimer64_mutex_lock_until(clock, &rmutex->mutex, target) == 0) {
|
||||
atomic_store_explicit(&rmutex->owner,
|
||||
thread_getpid(), memory_order_relaxed);
|
||||
rmutex->refcount++;
|
||||
return 0;
|
||||
}
|
||||
return -ECANCELED;
|
||||
}
|
300
sys/ztimer64/ztimer64.c
Normal file
300
sys/ztimer64/ztimer64.c
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* 2021 Freie Universität Berlin
|
||||
* 2021 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_ztimer64
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief ztimer64 core functionality
|
||||
*
|
||||
* This file contains ztimer64's main API implementation and functionality
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "ztimer64.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
/* Checkpointing interval, don't change. See `ztimer64_now()` for an explanation
|
||||
* of the checkpointing.
|
||||
*/
|
||||
#define ZTIMER64_CHECKPOINT_INTERVAL (1LU << 31)
|
||||
|
||||
static int _add_entry_to_list(ztimer64_clock_t *clock, ztimer64_base_t *entry);
|
||||
static int _del_entry_from_list(ztimer64_clock_t *clock,
|
||||
ztimer64_base_t *entry);
|
||||
static void _ztimer64_update(ztimer64_clock_t *clock);
|
||||
|
||||
/* debug aid */
|
||||
void ztimer64_clock_print(const ztimer64_clock_t *clock);
|
||||
|
||||
static unsigned _is_set(const ztimer64_t *t)
|
||||
{
|
||||
/* no timer can ever trigger at `target==0`, so we use that
|
||||
* as marker */
|
||||
return !!(t->base.target);
|
||||
}
|
||||
|
||||
unsigned ztimer64_is_set(const ztimer64_t *timer)
|
||||
{
|
||||
return _is_set(timer);
|
||||
}
|
||||
|
||||
void ztimer64_remove(ztimer64_clock_t *clock, ztimer64_t *timer)
|
||||
{
|
||||
unsigned state = irq_disable();
|
||||
|
||||
if (_is_set(timer)) {
|
||||
if (_del_entry_from_list(clock, &timer->base) == 0) {
|
||||
_ztimer64_update(clock);
|
||||
}
|
||||
}
|
||||
|
||||
irq_restore(state);
|
||||
}
|
||||
|
||||
void ztimer64_set_at(ztimer64_clock_t *clock, ztimer64_t *timer, uint64_t val)
|
||||
{
|
||||
unsigned state = irq_disable();
|
||||
|
||||
if (_is_set(timer)) {
|
||||
_del_entry_from_list(clock, &timer->base);
|
||||
}
|
||||
|
||||
/* optionally subtract a configurable adjustment value */
|
||||
/* there is no API to set this ATM */
|
||||
if (val > clock->adjust_set) {
|
||||
val -= clock->adjust_set;
|
||||
}
|
||||
else {
|
||||
val = 0;
|
||||
}
|
||||
|
||||
timer->base.target = val;
|
||||
|
||||
/* NOTE: if val is 0 at this point, this will be fixed to "now()" in _ztimer64_update() */
|
||||
|
||||
if (_add_entry_to_list(clock, &timer->base)) {
|
||||
_ztimer64_update(clock);
|
||||
}
|
||||
|
||||
irq_restore(state);
|
||||
}
|
||||
|
||||
static int _add_entry_to_list(ztimer64_clock_t *clock, ztimer64_base_t *entry)
|
||||
{
|
||||
ztimer64_base_t *pos = clock->first;
|
||||
|
||||
if (pos) {
|
||||
if (pos->target > entry->target) {
|
||||
/* special case: new entry's target is earlier than old list head */
|
||||
entry->next = pos;
|
||||
clock->first = entry;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
/* Jump past all entries which are set to an earlier target than the new entry */
|
||||
while (pos->next && pos->next->target <= entry->target) {
|
||||
pos = pos->next;
|
||||
}
|
||||
entry->next = pos->next;
|
||||
pos->next = entry;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* adding first entry */
|
||||
entry->next = 0;
|
||||
clock->first = entry;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int _del_entry_from_list(ztimer64_clock_t *clock, ztimer64_base_t *entry)
|
||||
{
|
||||
DEBUG("_del_entry_from_list()\n");
|
||||
assert(_is_set((ztimer64_t *)entry));
|
||||
if (clock->first == entry) {
|
||||
/* special case: removing first entry */
|
||||
clock->first = entry->next;
|
||||
entry->next = 0;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
ztimer64_base_t *pos = clock->first;
|
||||
|
||||
while (pos->next) {
|
||||
if (pos->next == entry) {
|
||||
pos->next = entry->next;
|
||||
break;
|
||||
}
|
||||
pos = pos->next;
|
||||
}
|
||||
|
||||
entry->next = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ztimer64_now(ztimer64_clock_t *clock)
|
||||
{
|
||||
uint64_t now;
|
||||
unsigned state = irq_disable();
|
||||
uint32_t base_now = ztimer_now(clock->base_clock);
|
||||
|
||||
/* ztimer64 checkpointing works by storing
|
||||
* the upper 33 bits in clock->checkpoint.
|
||||
* The final time is the lower 32bit time ORed
|
||||
* with that checkpoint.
|
||||
* The highest bit of the lower 32bit is used
|
||||
* as control bit. If the checkpoint and 32bit
|
||||
* time both have that bit set (or not), no correction is necessary.
|
||||
* If checkpoint and 32bit time disagree on that bit,
|
||||
* the checkpoint lags behind, and needs to be updated.
|
||||
* This works as long as the checkpoint is at most (2**32-1) behind,
|
||||
* which is ensured by setting the base clock timer at most
|
||||
* ZTIMER64_CHECKPOINT_INTERVAL into the future.
|
||||
*/
|
||||
if ((clock->checkpoint & ZTIMER64_CHECKPOINT_INTERVAL)
|
||||
^ (base_now & ZTIMER64_CHECKPOINT_INTERVAL)) {
|
||||
clock->checkpoint += ZTIMER64_CHECKPOINT_INTERVAL;
|
||||
}
|
||||
|
||||
now = clock->checkpoint | base_now;
|
||||
|
||||
irq_restore(state);
|
||||
return now;
|
||||
}
|
||||
|
||||
static void _ztimer64_update(ztimer64_clock_t *clock)
|
||||
{
|
||||
uint64_t now = ztimer64_now(clock);
|
||||
uint64_t next_checkpoint = clock->checkpoint + ZTIMER64_CHECKPOINT_INTERVAL;
|
||||
uint64_t target;
|
||||
|
||||
if (next_checkpoint < now) {
|
||||
next_checkpoint = now;
|
||||
}
|
||||
|
||||
if (!clock->first) {
|
||||
target = next_checkpoint;
|
||||
}
|
||||
else {
|
||||
uint64_t next = clock->first->target;
|
||||
if (next > now) {
|
||||
if (next < next_checkpoint) {
|
||||
/* timer within range */
|
||||
target = next;
|
||||
}
|
||||
else {
|
||||
/* timer out of range */
|
||||
target = next_checkpoint;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* timer has passed already, trigger ASAP */
|
||||
target = now;
|
||||
|
||||
/* if we arrive here due to a timer with "target==0" being set,
|
||||
* fix this here to consider it "set".
|
||||
*/
|
||||
if (next == 0) {
|
||||
clock->first->target = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ztimer_set(clock->base_clock, &clock->base_timer, target - now);
|
||||
}
|
||||
|
||||
void ztimer64_handler(void *arg)
|
||||
{
|
||||
ztimer64_clock_t *clock = arg;
|
||||
|
||||
while (clock->first) {
|
||||
uint64_t now = ztimer64_now(clock);
|
||||
if (clock->first->target <= now) {
|
||||
ztimer64_t *timer = (ztimer64_t *)clock->first;
|
||||
/* remove timer from list */
|
||||
clock->first = clock->first->next;
|
||||
/* clear timer struct so it can be re-set */
|
||||
timer->base.next = NULL;
|
||||
timer->base.target = 0;
|
||||
|
||||
/* shoot callback */
|
||||
timer->callback(timer->arg);
|
||||
}
|
||||
else {
|
||||
/* timer target is in the future */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_ztimer64_update(clock);
|
||||
}
|
||||
|
||||
void ztimer64_clock_init(ztimer64_clock_t *clock, ztimer_clock_t *base_clock)
|
||||
{
|
||||
*clock =
|
||||
(ztimer64_clock_t){ .base_clock = base_clock,
|
||||
.base_timer =
|
||||
{ .callback = ztimer64_handler, .arg = clock } };
|
||||
|
||||
/* initialize checkpointing */
|
||||
_ztimer64_update(clock);
|
||||
}
|
||||
|
||||
#if MODULE_ZTIMER64_USEC
|
||||
static ztimer64_clock_t _ztimer64_usec;
|
||||
ztimer64_clock_t *const ZTIMER64_USEC = &_ztimer64_usec;
|
||||
#endif
|
||||
#if MODULE_ZTIMER64_MSEC
|
||||
static ztimer64_clock_t _ztimer64_msec;
|
||||
ztimer64_clock_t *const ZTIMER64_MSEC = &_ztimer64_msec;
|
||||
#endif
|
||||
#if MODULE_ZTIMER64_SEC
|
||||
static ztimer64_clock_t _ztimer64_sec;
|
||||
ztimer64_clock_t *const ZTIMER64_SEC = &_ztimer64_sec;
|
||||
#endif
|
||||
|
||||
void ztimer64_init(void)
|
||||
{
|
||||
#if MODULE_ZTIMER64_USEC
|
||||
ztimer64_clock_init(ZTIMER64_USEC, ZTIMER_USEC);
|
||||
#endif
|
||||
#if MODULE_ZTIMER64_MSEC
|
||||
ztimer64_clock_init(ZTIMER64_MSEC, ZTIMER_MSEC);
|
||||
#endif
|
||||
#if MODULE_ZTIMER64_SEC
|
||||
ztimer64_clock_init(ZTIMER64_SEC, ZTIMER_SEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ztimer64_clock_print(const ztimer64_clock_t *clock)
|
||||
{
|
||||
const ztimer64_base_t *entry = clock->first;
|
||||
|
||||
while (entry) {
|
||||
printf("0x%08x:%" PRIu64 "\n", (unsigned)entry,
|
||||
entry->target);
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
puts("");
|
||||
}
|
6
tests/unittests/tests-ztimer64/Makefile
Normal file
6
tests/unittests/tests-ztimer64/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# avoid clang warning in tests-ztimer/tests-ztimer-extend.c:141
|
||||
ifeq (llvm,$(TOOLCHAIN))
|
||||
CFLAGS += -Wno-gnu-folding-constant
|
||||
endif
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
3
tests/unittests/tests-ztimer64/Makefile.include
Normal file
3
tests/unittests/tests-ztimer64/Makefile.include
Normal file
@ -0,0 +1,3 @@
|
||||
USEMODULE += ztimer_core
|
||||
USEMODULE += ztimer_mock
|
||||
USEMODULE += ztimer64
|
216
tests/unittests/tests-ztimer64/tests-ztimer64-core.c
Normal file
216
tests/unittests/tests-ztimer64/tests-ztimer64-core.c
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Unittests for ztimer64
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ztimer.h"
|
||||
#include "ztimer64.h"
|
||||
#include "ztimer/mock.h"
|
||||
|
||||
#include "embUnit/embUnit.h"
|
||||
|
||||
#include "tests-ztimer64.h"
|
||||
|
||||
#define ZTIMER64_CHECKPOINT_INTERVAL (1LLU << 31)
|
||||
|
||||
/**
|
||||
* @brief Simple callback for counting alarms
|
||||
*/
|
||||
static void cb_incr(void *arg)
|
||||
{
|
||||
uint32_t *ptr = arg;
|
||||
|
||||
*ptr += 1;
|
||||
}
|
||||
|
||||
static ztimer_mock_t zmock;
|
||||
static ztimer_clock_t *z = &zmock.super;
|
||||
static ztimer64_clock_t z64mock;
|
||||
static ztimer64_clock_t *z64 = &z64mock;
|
||||
|
||||
static void setup(void)
|
||||
{
|
||||
memset(&zmock, '\0', sizeof(ztimer_mock_t));
|
||||
memset(&z64mock, '\0', sizeof(ztimer64_clock_t));
|
||||
/* ztimer base clock is already extended to 32bit */
|
||||
ztimer_mock_init(&zmock, 32);
|
||||
ztimer64_clock_init(z64, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
static void test_ztimer64_now(void)
|
||||
{
|
||||
uint64_t now64 = ztimer64_now(z64);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, now64);
|
||||
|
||||
ztimer_mock_advance(&zmock, 123);
|
||||
now64 = ztimer64_now(z64);
|
||||
TEST_ASSERT_EQUAL_INT(123, now64);
|
||||
|
||||
ztimer_mock_jump(&zmock, 0x10000000ul);
|
||||
now64 = ztimer64_now(z64);
|
||||
TEST_ASSERT_EQUAL_INT(0x10000000ul, now64);
|
||||
|
||||
ztimer_mock_advance(&zmock, 0x98765432ul);
|
||||
now64 = ztimer64_now(z64);
|
||||
TEST_ASSERT_EQUAL_INT(0xa8765432ul, now64);
|
||||
/* 32bit overflow */
|
||||
ztimer_mock_advance(&zmock, 0x41234567ul);
|
||||
ztimer_mock_advance(&zmock, 0x40000000ul);
|
||||
now64 = ztimer64_now(z64);
|
||||
TEST_ASSERT_EQUAL_INT(0x129999999ul, now64);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Testing 32 bit wide mock clock set functionality
|
||||
*/
|
||||
static void test_ztimer64_set(void)
|
||||
{
|
||||
uint64_t now64 = ztimer64_now(z64);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, now64);
|
||||
|
||||
uint32_t count = 0;
|
||||
ztimer64_t alarm = { .callback = cb_incr, .arg = &count, };
|
||||
|
||||
ztimer64_set(z64, &alarm, 1000);
|
||||
ztimer_mock_advance(&zmock, 1); /* now = 1*/
|
||||
TEST_ASSERT_EQUAL_INT(0, count);
|
||||
ztimer_mock_advance(&zmock, 100); /* now = 101 */
|
||||
TEST_ASSERT_EQUAL_INT(0, count);
|
||||
ztimer_mock_advance(&zmock, 898); /* now = 999 */
|
||||
now64 = ztimer64_now(z64);
|
||||
TEST_ASSERT_EQUAL_INT(999, now64);
|
||||
TEST_ASSERT_EQUAL_INT(0, count);
|
||||
ztimer_mock_advance(&zmock, 1); /* now = 1000*/
|
||||
TEST_ASSERT_EQUAL_INT(1, count);
|
||||
ztimer_mock_advance(&zmock, 1); /* now = 1001*/
|
||||
TEST_ASSERT_EQUAL_INT(1, count);
|
||||
ztimer_mock_advance(&zmock, 1000); /* now = 2001*/
|
||||
TEST_ASSERT_EQUAL_INT(1, count);
|
||||
ztimer64_set(z64, &alarm, 3);
|
||||
ztimer_mock_advance(&zmock, 999); /* now = 3000*/
|
||||
TEST_ASSERT_EQUAL_INT(2, count);
|
||||
ztimer64_set(z64, &alarm, 4000001000ul);
|
||||
ztimer_mock_advance(&zmock, 1000); /* now = 4000*/
|
||||
TEST_ASSERT_EQUAL_INT(2, count);
|
||||
ztimer_mock_advance(&zmock, 4000000000ul); /* now = 4000004000*/
|
||||
now64 = ztimer64_now(z64);
|
||||
TEST_ASSERT_EQUAL_INT(4000004000ul, now64);
|
||||
TEST_ASSERT_EQUAL_INT(3, count);
|
||||
/* 32bit overflow */
|
||||
ztimer64_set(z64, &alarm, 8000000000ul);
|
||||
ztimer_mock_advance(&zmock, 4000000000ul);
|
||||
ztimer_mock_advance(&zmock, 3999999999ul); /* now = 12000003999*/
|
||||
TEST_ASSERT_EQUAL_INT(3, count);
|
||||
ztimer_mock_advance(&zmock, 1ul); /* now = 12000004000*/
|
||||
TEST_ASSERT_EQUAL_INT(4, count);
|
||||
ztimer64_set(z64, &alarm, 15);
|
||||
ztimer_mock_advance(&zmock, 14);
|
||||
ztimer64_remove(z64, &alarm);
|
||||
ztimer_mock_advance(&zmock, 1000);
|
||||
TEST_ASSERT_EQUAL_INT(4, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Testing 32 bit wide mock clock set functionality
|
||||
*/
|
||||
static void test_ztimer64_set_0(void)
|
||||
{
|
||||
uint64_t now64 = ztimer64_now(z64);
|
||||
TEST_ASSERT_EQUAL_INT(0, now64);
|
||||
|
||||
uint32_t count = 0;
|
||||
ztimer64_t alarm = { .callback = cb_incr, .arg = &count, };
|
||||
|
||||
/* should trigger asap, note that for a real timer this will be
|
||||
to minimal value that guarantees the ISR not to be missed,
|
||||
e.g: CONFIG_ZTIMER_USEC_MIN or RTT_MIN_OFFSET */
|
||||
ztimer64_set(z64, &alarm, 0);
|
||||
ztimer_mock_advance(&zmock, 1); /* now = 1*/
|
||||
TEST_ASSERT_EQUAL_INT(1, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Testing timers set in the past
|
||||
*/
|
||||
static void test_ztimer64_set_at(void)
|
||||
{
|
||||
uint64_t now64 = ztimer64_now(z64);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, now64);
|
||||
|
||||
uint32_t count = 0;
|
||||
ztimer64_t alarm = { .callback = cb_incr, .arg = &count, };
|
||||
|
||||
/* test setting an offset that is now in the past, should trigger asap */
|
||||
ztimer_mock_advance(&zmock, 1010); /* now = 1010 */
|
||||
ztimer64_set_at(z64, &alarm, 1000);
|
||||
/* should trigger on next tick */
|
||||
ztimer_mock_advance(&zmock, 1); /* now = 1011 */
|
||||
TEST_ASSERT_EQUAL_INT(1, count);
|
||||
}
|
||||
|
||||
static void test_ztimer64_checkpoint(void)
|
||||
{
|
||||
uint64_t now64 = ztimer64_now(z64);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, now64);
|
||||
|
||||
/* base_now is 0x7fff_ffff */
|
||||
ztimer_mock_jump(&zmock, ZTIMER64_CHECKPOINT_INTERVAL - 1);
|
||||
now64 = ztimer64_now(z64);
|
||||
TEST_ASSERT_EQUAL_INT(ZTIMER64_CHECKPOINT_INTERVAL - 1, now64);
|
||||
/* base_now is 0x8000_0000 */
|
||||
ztimer_mock_jump(&zmock, ZTIMER64_CHECKPOINT_INTERVAL);
|
||||
now64 = ztimer64_now(z64);
|
||||
TEST_ASSERT_EQUAL_INT(ZTIMER64_CHECKPOINT_INTERVAL, now64);
|
||||
/* base_now is 0x0000_0000 */
|
||||
ztimer_mock_jump(&zmock, 0);
|
||||
now64 = ztimer64_now(z64);
|
||||
/* overflow is caught in checkpoint */
|
||||
TEST_ASSERT_EQUAL_INT(2 * ZTIMER64_CHECKPOINT_INTERVAL, now64);
|
||||
/* base_now is 0xffff_ffff, max jump that can be caught */
|
||||
ztimer_mock_jump(&zmock, UINT32_MAX);
|
||||
now64 = ztimer64_now(z64);
|
||||
/* overflow is caught in checkpoint */
|
||||
TEST_ASSERT_EQUAL_INT(2 * ZTIMER64_CHECKPOINT_INTERVAL + UINT32_MAX, now64);
|
||||
/* overflow is missed, 2**32 ticks elapsed
|
||||
- microseconds: 4293 seconds
|
||||
- nanoseconds: 4.29 seconds (e.g.: ptp) -> should not use ztimer as base.
|
||||
*/
|
||||
ztimer_mock_jump(&zmock, UINT32_MAX);
|
||||
TEST_ASSERT_EQUAL_INT(2 * ZTIMER64_CHECKPOINT_INTERVAL + UINT32_MAX, now64);
|
||||
}
|
||||
|
||||
Test *tests_ztimer64_tests(void)
|
||||
{
|
||||
EMB_UNIT_TESTFIXTURES(fixtures) {
|
||||
new_TestFixture(test_ztimer64_now),
|
||||
new_TestFixture(test_ztimer64_set),
|
||||
new_TestFixture(test_ztimer64_set_0),
|
||||
new_TestFixture(test_ztimer64_set_at),
|
||||
new_TestFixture(test_ztimer64_checkpoint),
|
||||
};
|
||||
|
||||
EMB_UNIT_TESTCALLER(ztimer64_tests, setup, NULL, fixtures);
|
||||
|
||||
return (Test *)&ztimer64_tests;
|
||||
}
|
||||
|
||||
/** @} */
|
25
tests/unittests/tests-ztimer64/tests-ztimer64.c
Normal file
25
tests/unittests/tests-ztimer64/tests-ztimer64.c
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Unittest entry point for the ztimer64 test group
|
||||
*
|
||||
*/
|
||||
|
||||
#include "embUnit/embUnit.h"
|
||||
|
||||
#include "tests-ztimer64.h"
|
||||
|
||||
Test *tests_ztimer64_tests(void);
|
||||
|
||||
void tests_ztimer64(void)
|
||||
{
|
||||
TESTS_RUN(tests_ztimer64_tests());
|
||||
}
|
||||
/** @} */
|
34
tests/unittests/tests-ztimer64/tests-ztimer64.h
Normal file
34
tests/unittests/tests-ztimer64/tests-ztimer64.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup unittests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Unittests for ztimer64
|
||||
*
|
||||
*/
|
||||
#ifndef TESTS_ZTIMER64_H
|
||||
#define TESTS_ZTIMER64_H
|
||||
|
||||
#include "embUnit.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The entry point of this test suite.
|
||||
*/
|
||||
void tests_ztimer(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TESTS_ZTIMER64_H */
|
||||
/** @} */
|
11
tests/ztimer64_msg/Makefile
Normal file
11
tests/ztimer64_msg/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
include ../Makefile.tests_common
|
||||
|
||||
USEMODULE += ztimer64_usec
|
||||
|
||||
# uncomment this to test using ztimer64 msec on rtt
|
||||
#USEMODULE += ztimer64_msec ztimer_periph_rtt
|
||||
|
||||
# uncomment this to test using ztimer64 sec on rtc
|
||||
#USEMODULE += ztimer64_sec ztimer_periph_rtc
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
12
tests/ztimer64_msg/Makefile.ci
Normal file
12
tests/ztimer64_msg/Makefile.ci
Normal file
@ -0,0 +1,12 @@
|
||||
BOARD_INSUFFICIENT_MEMORY := \
|
||||
arduino-duemilanove \
|
||||
arduino-leonardo \
|
||||
arduino-nano \
|
||||
arduino-uno \
|
||||
atmega328p \
|
||||
atmega328p-xplained-mini \
|
||||
nucleo-f031k6 \
|
||||
nucleo-l011k4 \
|
||||
samd10-xmini \
|
||||
stm32f030f4-demo \
|
||||
#
|
9
tests/ztimer64_msg/README.md
Normal file
9
tests/ztimer64_msg/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Overview
|
||||
|
||||
This test application is a direct translation of ztimer_msg to the ztimer64API.
|
||||
It is meant mostly as a means to do size comparisons, thus tries to be as close
|
||||
as possible to the original.
|
||||
|
||||
One notable change is the option to choose a different ztimer clock.
|
||||
By default, the test will use ZTIMER64_USEC, unless ZTIMER64_MSEC is compiled in,
|
||||
which will be used in that case.
|
3
tests/ztimer64_msg/app.config.test
Normal file
3
tests/ztimer64_msg/app.config.test
Normal file
@ -0,0 +1,3 @@
|
||||
# this file enables modules defined in Kconfig. Do not use this file for
|
||||
# application configuration. This is only needed during migration.
|
||||
CONFIG_ZTIMER64_USEC=y
|
152
tests/ztimer64_msg/main.c
Normal file
152
tests/ztimer64_msg/main.c
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (C) 2015-19 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* 2013 INRIA
|
||||
* 2017 HAW Hamburg
|
||||
*
|
||||
* 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 tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief ztimer64_msg test application
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
||||
* @author Christian Mehlis <mehlis@inf.fu-berlin.de>
|
||||
* @author Sebastian Meiling <s@mlng.net>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ztimer64.h"
|
||||
#include "thread.h"
|
||||
#include "msg.h"
|
||||
#include "timex.h"
|
||||
|
||||
#include "test_utils/expect.h"
|
||||
|
||||
#ifdef MODULE_ZTIMER64_SEC
|
||||
#define ZTIMER64 ZTIMER64_SEC
|
||||
#define TICKS_PER_SEC 1
|
||||
#elif MODULE_ZTIMER64_MSEC
|
||||
#define ZTIMER64 ZTIMER64_MSEC
|
||||
#define TICKS_PER_SEC MS_PER_SEC
|
||||
#else
|
||||
#define ZTIMER64 ZTIMER64_USEC
|
||||
#define TICKS_PER_SEC US_PER_SEC
|
||||
#endif
|
||||
|
||||
char timer_stack[THREAD_STACKSIZE_DEFAULT];
|
||||
char timer_stack_local[THREAD_STACKSIZE_DEFAULT];
|
||||
|
||||
struct timer_msg {
|
||||
ztimer64_t timer;
|
||||
uint64_t interval;
|
||||
char *text;
|
||||
msg_t msg;
|
||||
};
|
||||
|
||||
struct timer_msg msg_a = { .interval = (2 * TICKS_PER_SEC),
|
||||
.text = "Hello World" };
|
||||
struct timer_msg msg_b = { .interval = (5 * TICKS_PER_SEC),
|
||||
.text = "This is a Test" };
|
||||
|
||||
void *timer_thread(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
printf("This is thread %" PRIkernel_pid "\n", thread_getpid());
|
||||
|
||||
/* The queue is required to avoid loss of a 2nd message, when the 1st is
|
||||
* still processed. The timing ensures that at most 1 message is queued.
|
||||
*/
|
||||
msg_t msgq[1];
|
||||
|
||||
msg_init_queue(msgq, 1);
|
||||
|
||||
while (1) {
|
||||
msg_t m;
|
||||
msg_receive(&m);
|
||||
struct timer_msg *tmsg = m.content.ptr;
|
||||
uint64_t now = ztimer64_now(ZTIMER64);
|
||||
/* casts are needed to solve for sometimes TICKS_PER_SEC being UL
|
||||
* result of / and % of uint32_t will always fit into uint32_t
|
||||
*/
|
||||
printf(
|
||||
"now=%" PRIu32 ":%" PRIu32 " -> every %" PRIu32 ".%" PRIu32 "s: %s\n",
|
||||
(uint32_t)(now / TICKS_PER_SEC),
|
||||
(uint32_t)(now % TICKS_PER_SEC),
|
||||
(uint32_t)(tmsg->interval / TICKS_PER_SEC),
|
||||
(uint32_t)(tmsg->interval % TICKS_PER_SEC),
|
||||
tmsg->text);
|
||||
|
||||
tmsg->msg.type = 12345;
|
||||
tmsg->msg.content.ptr = tmsg;
|
||||
ztimer64_set_msg(ZTIMER64, &tmsg->timer, tmsg->interval, &tmsg->msg,
|
||||
thread_getpid());
|
||||
}
|
||||
}
|
||||
|
||||
void *timer_thread_local(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
printf("This is thread %" PRIkernel_pid "\n", thread_getpid());
|
||||
|
||||
while (1) {
|
||||
msg_t m;
|
||||
msg_receive(&m);
|
||||
|
||||
uint64_t now = ztimer64_now(ZTIMER64);
|
||||
uint32_t sec = now / TICKS_PER_SEC;
|
||||
uint32_t min = sec / 60;
|
||||
uint32_t hr = sec / 3600;
|
||||
printf("sec=%" PRIu32 " min=%" PRIu32 " hour=%" PRIu32 "\n", sec, min,
|
||||
hr);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
msg_t m;
|
||||
kernel_pid_t pid = thread_create(
|
||||
timer_stack,
|
||||
sizeof(timer_stack),
|
||||
THREAD_PRIORITY_MAIN - 1,
|
||||
THREAD_CREATE_STACKTEST,
|
||||
timer_thread,
|
||||
NULL,
|
||||
"timer");
|
||||
|
||||
expect(pid_is_valid(pid));
|
||||
|
||||
puts("sending 1st msg");
|
||||
m.content.ptr = &msg_a;
|
||||
msg_try_send(&m, pid);
|
||||
|
||||
puts("sending 2nd msg");
|
||||
m.content.ptr = &msg_b;
|
||||
msg_try_send(&m, pid);
|
||||
|
||||
kernel_pid_t pid2 = thread_create(
|
||||
timer_stack_local,
|
||||
sizeof(timer_stack_local),
|
||||
THREAD_PRIORITY_MAIN - 1,
|
||||
THREAD_CREATE_STACKTEST,
|
||||
timer_thread_local,
|
||||
NULL,
|
||||
"timer local");
|
||||
|
||||
expect(pid_is_valid(pid2));
|
||||
|
||||
while (1) {
|
||||
ztimer64_sleep(ZTIMER64, 1LLU * TICKS_PER_SEC);
|
||||
msg_try_send(&m, pid2);
|
||||
}
|
||||
}
|
30
tests/ztimer64_msg/tests/01-run.py
Executable file
30
tests/ztimer64_msg/tests/01-run.py
Executable file
@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2017 HAW Hamburg
|
||||
#
|
||||
# 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.
|
||||
|
||||
import sys
|
||||
from testrunner import run
|
||||
|
||||
|
||||
def testfunc(child):
|
||||
# 1st check for periodic 2s Hello World message, i.e., 2 output + 1 msg
|
||||
for _ in range(7):
|
||||
child.expect(r"sec=\d+ min=\d+ hour=\d+")
|
||||
child.expect(r"sec=\d+ min=\d+ hour=\d+")
|
||||
child.expect(r"now=\d+:\d+ -> every 2.0s: Hello World")
|
||||
# 2nd check for periodic 5s test message, i.e., 5 output + 1 msg
|
||||
for _ in range(3):
|
||||
child.expect(r"sec=\d+ min=\d+ hour=\d+")
|
||||
child.expect(r"sec=\d+ min=\d+ hour=\d+")
|
||||
child.expect(r"sec=\d+ min=\d+ hour=\d+")
|
||||
child.expect(r"sec=\d+ min=\d+ hour=\d+")
|
||||
child.expect(r"sec=\d+ min=\d+ hour=\d+")
|
||||
child.expect(r"now=\d+:\d+ -> every 5.0s: This is a Test")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run(testfunc))
|
Loading…
Reference in New Issue
Block a user