1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/ztimer/convert_muldiv64.c
2022-11-22 00:25:34 +01:00

135 lines
3.8 KiB
C

/*
* 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_ztimer_convert_muldiv64
* @{
*
* @file
* @brief ztimer frequency conversion module using 64bit division
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*
* @}
*/
#include <stdio.h>
#include "ztimer/convert.h"
#include "ztimer/convert_muldiv64.h"
#define ENABLE_DEBUG 0
#include "debug.h"
static void _ztimer_convert_muldiv64_set(ztimer_clock_t *ztimer, uint32_t val);
/* returns ceil(x/y) */
static uint64_t _integer_div_ceil(uint64_t x, uint64_t y)
{
if (x == 0) {
return 0;
}
return 1 + ((x - 1) / y);
}
static uint32_t _convert_muldiv64_set(
const ztimer_convert_muldiv64_t *ztimer_convert_muldiv64, uint32_t val)
{
uint64_t res = val;
if (ztimer_convert_muldiv64->mul > 1) {
res *= ztimer_convert_muldiv64->mul;
}
if (ztimer_convert_muldiv64->div > 1) {
res = _integer_div_ceil(res, ztimer_convert_muldiv64->div);
}
return res;
}
static uint32_t _convert_muldiv64_now(
const ztimer_convert_muldiv64_t *ztimer_convert_muldiv64, uint32_t val)
{
uint64_t res = val;
if (ztimer_convert_muldiv64->div > 1) {
res *= ztimer_convert_muldiv64->div;
}
if (ztimer_convert_muldiv64->mul > 1) {
res /= ztimer_convert_muldiv64->mul;
}
DEBUG("_convert_muldiv64_now(%u * %u / %u == %u\n", (unsigned)val,
(unsigned)ztimer_convert_muldiv64->div ? ztimer_convert_muldiv64->div : 1,
(unsigned)ztimer_convert_muldiv64->mul ? ztimer_convert_muldiv64->mul : 1,
(unsigned)res);
return res;
}
static void _ztimer_convert_muldiv64_set(ztimer_clock_t *ztimer, uint32_t val)
{
ztimer_convert_muldiv64_t *ztimer_convert_muldiv64 =
(ztimer_convert_muldiv64_t *)ztimer;
ztimer_set(ztimer_convert_muldiv64->super.lower,
&ztimer_convert_muldiv64->super.lower_entry, _convert_muldiv64_set(
ztimer_convert_muldiv64,
val));
}
static uint32_t _ztimer_convert_muldiv64_now(ztimer_clock_t *ztimer)
{
const ztimer_convert_muldiv64_t *ztimer_convert_muldiv64 =
(ztimer_convert_muldiv64_t *)ztimer;
return _convert_muldiv64_now(ztimer_convert_muldiv64,
ztimer_now(
ztimer_convert_muldiv64->super.lower));
}
static const ztimer_ops_t _ztimer_convert_muldiv64_ops = {
.set = _ztimer_convert_muldiv64_set,
.now = _ztimer_convert_muldiv64_now,
.cancel = ztimer_convert_cancel,
#if MODULE_ZTIMER_ONDEMAND
.start = ztimer_convert_start,
.stop = ztimer_convert_stop,
#endif
};
void ztimer_convert_muldiv64_init(
ztimer_convert_muldiv64_t *ztimer_convert_muldiv64, ztimer_clock_t *lower,
unsigned div, unsigned mul)
{
uint32_t max_value;
if (mul > div) {
max_value = (uint64_t)UINT32_MAX * div / mul;
}
else {
max_value = UINT32_MAX;
}
DEBUG(
"ztimer_convert_muldiv64_init() div=%u mul=%u lower_maxval=%" PRIu32 "\n",
div, mul, max_value);
ztimer_convert_init(&ztimer_convert_muldiv64->super, lower, max_value);
ztimer_convert_muldiv64->super.super.ops = &_ztimer_convert_muldiv64_ops;
ztimer_convert_muldiv64->div = div;
ztimer_convert_muldiv64->mul = mul;
#if !MODULE_ZTIMER_ONDEMAND
/* extend lower clock only if the ondemand driver isn't selected
* otherwise, the clock extension will be called with the first
* ztimer_acquire() call */
ztimer_init_extend(&ztimer_convert_muldiv64->super.super);
#endif
}