Skip to content

Commit

Permalink
sys/fmt: added format for fixed floating points
Browse files Browse the repository at this point in the history
  • Loading branch information
haukepetersen committed Mar 29, 2016
1 parent 03b8fb6 commit 95d26d3
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 10 deletions.
76 changes: 71 additions & 5 deletions sys/fmt/fmt.c
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
/**
/*
* Copyright (C) 2015 Kaspar Schleiser <[email protected]>
*
* 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_fmt
*/

/**
* @ingroup sys_fmt
* @{
*
* @file
* @brief String formatting library implementation
* @author Kaspar Schleiser <[email protected]>
* @brief String formatting library implementation
*
* @author Kaspar Schleiser <[email protected]>
*
* @}
*/

Expand All @@ -34,6 +39,17 @@ static inline int _is_digit(char c)
return (c >= '0' && c <= '9');
}

static inline unsigned pwr(unsigned val, unsigned exp)
{
unsigned res = 1;

for (unsigned i = 0; i < exp; i++) {
res *= val;
}

return res;
}

size_t fmt_byte_hex(char *out, uint8_t byte)
{
if (out) {
Expand Down Expand Up @@ -122,6 +138,56 @@ size_t fmt_s32_dec(char *out, int32_t val)
return fmt_u32_dec(out, val) + negative;
}

size_t fmt_s16_dec(char *out, int16_t val)
{
return fmt_s32_dec(out, val);
}

size_t fmt_s16_dfp(char *out, int16_t val, unsigned fp_digits)
{
int16_t absolute, divider;
size_t pos = 0;
size_t div_len, len;
unsigned e;
char tmp[4];

if (fp_digits > 4) {
return 0;
}
if (fp_digits == 0) {
return fmt_s16_dec(out, val);
}
if (val < 0) {
if (out) {
out[pos++] = '-';
}
val *= -1;
}

e = pwr(10, fp_digits);
absolute = (val / (int)e);
divider = val - (absolute * e);

pos += fmt_s16_dec(&out[pos], absolute);

if (!out) {
return pos + 1 + fp_digits; /* abs len + decimal point + divider */
}

out[pos++] = '.';
len = pos + fp_digits;
div_len = fmt_s16_dec(tmp, divider);

while (pos < (len - div_len)) {
out[pos++] = '0';
}
for (size_t i = 0; i < div_len; i++) {
out[pos++] = tmp[i];
}

return pos;
}

uint32_t scn_u32_dec(const char *str, size_t n)
{
uint32_t res = 0;
Expand Down
55 changes: 50 additions & 5 deletions sys/include/fmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
*/

/**
* @defgroup sys_fmt string formatting
* @ingroup sys
* @brief Provides simple string formatting functions
* @defgroup sys_fmt string formatting
* @ingroup sys
* @brief Provides simple string formatting functions
*
* @{
*
* @file
* @brief string formatting API
* @author Kaspar Schleiser <[email protected]>
* @brief String formatting API
*
* @author Kaspar Schleiser <[email protected]>
*/

#ifndef FMT_H_
Expand Down Expand Up @@ -127,6 +129,49 @@ size_t fmt_u16_dec(char *out, uint16_t val);
*/
size_t fmt_s32_dec(char *out, int32_t val);

/**
* @brief Convert a int16 value to decimal string.
*
* Will add a leading "-" if @p val is negative.
*
* If @p out is NULL, will only return the number of bytes that would have
* been written.
*
* @param[out] out Pointer to output buffer, or NULL
* @param[in] val Value to convert
*
* @return nr of characters written to (or needed in) @p out
*/
size_t fmt_s16_dec(char *out, int16_t val);

/**
* @brief Convert 16-bit fixed point number to a decimal string
*
* The input for this function is a signed 16-bit integer holding the fixed
* point value as well as an unsigned integer defining the position of the
* decimal point, so this value defines the number of decimal digits after the
* decimal point.
*
* The resulting string will always be patted with zeros after the decimal point.
*
* For example: if @p val is -3548 and @p fp_digits is 2, the resulting string
* will be "-35.48". For @p val := 12010 and @p fp_digits := 3 the result will
* be "12.010".
*
* Will add a leading "-" if @p val is negative.
*
* If @p out is NULL, will only return the number of bytes that would have
* been written.
*
* @param[out] out Pointer to the output buffer, or NULL
* @param[in] val Fixed point value, MUST be <= 4
* @param[in] fp_digits Number of digits after the decimal point
*
* @return Length of the resulting string
* @return 0 if @p fp_digits is > 4
*/
size_t fmt_s16_dfp(char *out, int16_t val, unsigned fp_digits);

/**
* @brief Count characters until '\0' (exclusive) in @p str
*
Expand Down

0 comments on commit 95d26d3

Please sign in to comment.