LCOV - code coverage report
Current view: top level - zephyr/sys - linear_range.h Coverage Total Hit
Test: new.info Lines: 93.8 % 16 15
Test Date: 2025-09-05 20:47:19

            Line data    Source code
       1            0 : /*
       2              :  * Copyright (C) 2022, Nordic Semiconductor ASA
       3              :  * SPDX-License-Identifier: Apache-2.0
       4              :  */
       5              : 
       6              : #ifndef INCLUDE_ZEPHYR_SYS_LINEAR_RANGE_H_
       7              : #define INCLUDE_ZEPHYR_SYS_LINEAR_RANGE_H_
       8              : 
       9              : #include <errno.h>
      10              : #include <stdint.h>
      11              : #include <stdlib.h>
      12              : 
      13              : #include <zephyr/sys/util.h>
      14              : 
      15              : #ifdef __cplusplus
      16              : extern "C" {
      17              : #endif
      18              : 
      19              : /**
      20              :  * @defgroup linear_range Linear Range
      21              :  * @ingroup utilities
      22              :  *
      23              :  * The linear range API maps values in a linear range to a range index. A linear
      24              :  * range can be fully defined by four parameters:
      25              :  *
      26              :  * - Minimum value
      27              :  * - Step value
      28              :  * - Minimum index value
      29              :  * - Maximum index value
      30              :  *
      31              :  * For example, in a voltage regulator, supported voltages typically map to a
      32              :  * register index value like this:
      33              :  *
      34              :  * - 1000uV: 0x00
      35              :  * - 1250uV: 0x01
      36              :  * - 1500uV: 0x02
      37              :  * - ...
      38              :  * - 3000uV: 0x08
      39              :  *
      40              :  * In this case, we have:
      41              :  *
      42              :  * - Minimum value: 1000uV
      43              :  * - Step value: 250uV
      44              :  * - Minimum index value: 0x00
      45              :  * - Maximum index value: 0x08
      46              :  *
      47              :  * A linear range may also be constant, that is, step set to zero.
      48              :  *
      49              :  * It is often the case where the same device has discontinuous linear ranges.
      50              :  * The API offers utility functions to deal with groups of linear ranges as
      51              :  * well.
      52              :  *
      53              :  * Implementation uses fixed-width integers. Range is limited to [INT32_MIN,
      54              :  * INT32_MAX], while number of indices is limited to UINT16_MAX.
      55              :  *
      56              :  * Original idea borrowed from Linux.
      57              :  * @{
      58              :  */
      59              : 
      60              : /** @brief Linear range. */
      61            1 : struct linear_range {
      62              :         /** Minimum value. */
      63            1 :         int32_t min;
      64              :         /** Step value. */
      65            1 :         uint32_t step;
      66              :         /** Minimum index (must be <= maximum index). */
      67            1 :         uint16_t min_idx;
      68              :         /** Maximum index (must be >= minimum index). */
      69            1 :         uint16_t max_idx;
      70              : };
      71              : 
      72              : /**
      73              :  * @brief Initializer for @ref linear_range.
      74              :  *
      75              :  * @param _min Minimum value in range.
      76              :  * @param _step Step value.
      77              :  * @param _min_idx Minimum index.
      78              :  * @param _max_idx Maximum index.
      79              :  */
      80            1 : #define LINEAR_RANGE_INIT(_min, _step, _min_idx, _max_idx)                     \
      81              :         {                                                                      \
      82              :                 .min = (_min),                                                 \
      83              :                 .step = (_step),                                               \
      84              :                 .min_idx = (_min_idx),                                         \
      85              :                 .max_idx = (_max_idx),                                         \
      86              :         }
      87              : 
      88              : /**
      89              :  * @brief Obtain the number of values representable in a linear range.
      90              :  *
      91              :  * @param[in] r Linear range instance.
      92              :  *
      93              :  * @return Number of ranges representable by @p r.
      94              :  */
      95            1 : static inline uint32_t linear_range_values_count(const struct linear_range *r)
      96              : {
      97              :         return r->max_idx - r->min_idx + 1U;
      98              : }
      99              : 
     100              : /**
     101              :  * @brief Obtain the number of values representable by a group of linear ranges.
     102              :  *
     103              :  * @param[in] r Array of linear range instances.
     104              :  * @param r_cnt Number of linear range instances.
     105              :  *
     106              :  * @return Number of ranges representable by the @p r group.
     107              :  */
     108            1 : static inline uint32_t linear_range_group_values_count(
     109              :         const struct linear_range *r, size_t r_cnt)
     110              : {
     111              :         uint32_t values = 0U;
     112              : 
     113              :         for (size_t i = 0U; i < r_cnt; i++) {
     114              :                 values += linear_range_values_count(&r[i]);
     115              :         }
     116              : 
     117              :         return values;
     118              : }
     119              : 
     120              : /**
     121              :  * @brief Obtain the maximum value representable by a linear range.
     122              :  *
     123              :  * @param[in] r Linear range instance.
     124              :  *
     125              :  * @return Maximum value representable by @p r.
     126              :  */
     127            1 : static inline int32_t linear_range_get_max_value(const struct linear_range *r)
     128              : {
     129              :         return r->min + (int32_t)(r->step * (r->max_idx - r->min_idx));
     130              : }
     131              : 
     132              : /**
     133              :  * @brief Obtain value given a linear range index.
     134              :  *
     135              :  * @param[in] r Linear range instance.
     136              :  * @param idx Range index.
     137              :  * @param[out] val Where value will be stored.
     138              :  *
     139              :  * @retval 0 If successful
     140              :  * @retval -EINVAL If index is out of range.
     141              :  */
     142            1 : static inline int linear_range_get_value(const struct linear_range *r,
     143              :                                          uint16_t idx, int32_t *val)
     144              : {
     145              :         if ((idx < r->min_idx) || (idx > r->max_idx)) {
     146              :                 return -EINVAL;
     147              :         }
     148              : 
     149              :         *val = r->min + (int32_t)(r->step * (idx - r->min_idx));
     150              : 
     151              :         return 0;
     152              : }
     153              : 
     154              : /**
     155              :  * @brief Obtain value in a group given a linear range index.
     156              :  *
     157              :  * @param[in] r Array of linear range instances.
     158              :  * @param r_cnt Number of linear range instances.
     159              :  * @param idx Range index.
     160              :  * @param[out] val Where value will be stored.
     161              :  *
     162              :  * @retval 0 If successful
     163              :  * @retval -EINVAL If index is out of range.
     164              :  */
     165            1 : static inline int linear_range_group_get_value(const struct linear_range *r,
     166              :                                                size_t r_cnt, uint16_t idx,
     167              :                                                int32_t *val)
     168              : {
     169              :         int ret = -EINVAL;
     170              : 
     171              :         for (size_t i = 0U; (ret != 0) && (i < r_cnt); i++) {
     172              :                 ret = linear_range_get_value(&r[i], idx, val);
     173              :         }
     174              : 
     175              :         return ret;
     176              : }
     177              : 
     178              : /**
     179              :  * @brief Obtain index given a value.
     180              :  *
     181              :  * If the value falls outside the range, the nearest index will be stored and
     182              :  * -ERANGE returned. That is, if the value falls below or above the range, the
     183              :  * index will take the minimum or maximum value, respectively. For constant
     184              :  * ranges, the minimum index will be returned.
     185              :  *
     186              :  * @param[in] r Linear range instance.
     187              :  * @param val Value.
     188              :  * @param[out] idx Where index will be stored.
     189              :  *
     190              :  * @retval 0 If value falls within the range.
     191              :  * @retval -ERANGE If the value falls out of the range.
     192              :  */
     193            1 : static inline int linear_range_get_index(const struct linear_range *r,
     194              :                                          int32_t val, uint16_t *idx)
     195              : {
     196              :         if (val < r->min) {
     197              :                 *idx = r->min_idx;
     198              :                 return -ERANGE;
     199              :         }
     200              : 
     201              :         if (val > linear_range_get_max_value(r)) {
     202              :                 *idx = r->max_idx;
     203              :                 return -ERANGE;
     204              :         }
     205              : 
     206              :         if (r->step == 0U) {
     207              :                 *idx = r->min_idx;
     208              :         } else {
     209              :                 *idx = r->min_idx + DIV_ROUND_UP((uint32_t)(val - r->min),
     210              :                                                  r->step);
     211              :         }
     212              : 
     213              :         return 0;
     214              : }
     215              : 
     216              : /**
     217              :  * @brief Obtain index in a group given a value.
     218              :  *
     219              :  * This function works the same way as linear_range_get_index(), but considering
     220              :  * all ranges in the group.
     221              :  *
     222              :  * @param[in] r Linear range instances.
     223              :  * @param r_cnt Number of linear range instances.
     224              :  * @param val Value.
     225              :  * @param[out] idx Where index will be stored.
     226              :  *
     227              :  * @retval 0 If value falls within the range group.
     228              :  * @retval -ERANGE If the value falls out of the range group.
     229              :  * @retval -EINVAL If input is not valid (i.e. zero groups).
     230              :  */
     231            1 : static inline int linear_range_group_get_index(const struct linear_range *r,
     232              :                                                size_t r_cnt, int32_t val,
     233              :                                                uint16_t *idx)
     234              : {
     235              :         for (size_t i = 0U; i < r_cnt; i++) {
     236              :                 if ((val > linear_range_get_max_value(&r[i])) &&
     237              :                     (i < (r_cnt - 1U))) {
     238              :                         continue;
     239              :                 }
     240              : 
     241              :                 return linear_range_get_index(&r[i], val, idx);
     242              :         }
     243              : 
     244              :         return -EINVAL;
     245              : }
     246              : 
     247              : /**
     248              :  * @brief Obtain index given a window of values.
     249              :  *
     250              :  * If the window of values does not intersect with the range, -EINVAL will be
     251              :  * returned. If intersection is partial (any of the window edges does not
     252              :  * intersect), the nearest index will be stored and -ERANGE returned.
     253              :  *
     254              :  * @param[in] r Linear range instance.
     255              :  * @param val_min Minimum window value.
     256              :  * @param val_max Maximum window value.
     257              :  * @param[out] idx Where index will be stored.
     258              :  *
     259              :  * @retval 0 If a valid index is found within linear range.
     260              :  * @retval -ERANGE If the given window of values falls partially out of the
     261              :  * linear range.
     262              :  * @retval -EINVAL If the given window of values does not intersect with the
     263              :  * linear range or if they are too narrow.
     264              :  */
     265            1 : static inline int linear_range_get_win_index(const struct linear_range *r,
     266              :                                              int32_t val_min, int32_t val_max,
     267              :                                              uint16_t *idx)
     268              : {
     269              :         int32_t r_max = linear_range_get_max_value(r);
     270              : 
     271              :         if ((val_max < r->min) || (val_min > r_max)) {
     272              :                 return -EINVAL;
     273              :         }
     274              : 
     275              :         if (val_min < r->min) {
     276              :                 *idx = r->min_idx;
     277              :                 return -ERANGE;
     278              :         }
     279              : 
     280              :         if (val_max > r_max) {
     281              :                 *idx = r->max_idx;
     282              :                 return -ERANGE;
     283              :         }
     284              : 
     285              :         if (r->step == 0U) {
     286              :                 *idx = r->min_idx;
     287              :                 return 0;
     288              :         }
     289              : 
     290              :         *idx = r->min_idx + DIV_ROUND_UP((uint32_t)(val_min - r->min), r->step);
     291              :         if ((r->min + r->step * (*idx - r->min_idx)) > val_max) {
     292              :                 return -EINVAL;
     293              :         }
     294              : 
     295              :         return 0;
     296              : }
     297              : 
     298              : /**
     299              :  * @brief Obtain index in a group given a value that must be within a window of
     300              :  * values.
     301              :  *
     302              :  * This function works the same way as linear_range_get_win_index(), but
     303              :  * considering all ranges in the group.
     304              :  *
     305              :  * @param[in] r Linear range instances.
     306              :  * @param r_cnt Number of linear range instances.
     307              :  * @param val_min Minimum window value.
     308              :  * @param val_max Maximum window value.
     309              :  * @param[out] idx Where index will be stored.
     310              :  *
     311              :  * @retval 0 If a valid index is found within linear range group.
     312              :  * @retval -ERANGE If the given window of values falls partially out of the
     313              :  * linear range group.
     314              :  * @retval -EINVAL If the given window of values does not intersect with the
     315              :  * linear range group, if they are too narrow, or if input is invalid (i.e.
     316              :  * zero groups).
     317              :  */
     318            1 : static inline int linear_range_group_get_win_index(const struct linear_range *r,
     319              :                                                    size_t r_cnt,
     320              :                                                    int32_t val_min,
     321              :                                                    int32_t val_max,
     322              :                                                    uint16_t *idx)
     323              : {
     324              :         for (size_t i = 0U; i < r_cnt; i++) {
     325              :                 if (val_min > linear_range_get_max_value(&r[i])) {
     326              :                         continue;
     327              :                 }
     328              : 
     329              :                 return linear_range_get_win_index(&r[i], val_min, val_max, idx);
     330              :         }
     331              : 
     332              :         return -EINVAL;
     333              : }
     334              : 
     335              : /** @} */
     336              : 
     337              : #ifdef __cplusplus
     338              : }
     339              : #endif
     340              : 
     341              : #endif /* INCLUDE_ZEPHYR_SYS_LINEAR_RANGE_H_ */
        

Generated by: LCOV version 2.0-1