DIY Logging Volt/Ampmeter
util.c
Go to the documentation of this file.
1 /***************************************************************************//**
2  * @file util.c
3  * @brief Utility functionality for high-precision logging voltage/current meter.
4  * @version 1.0
5  * @author Brecht Van Eeckhoudt
6  *
7  * ******************************************************************************
8  *
9  * @section Versions
10  *
11  * @li v1.0: Initial version.
12  *
13  * ******************************************************************************
14  *
15  * @section License
16  *
17  * **Copyright (C) 2021 - Brecht Van Eeckhoudt**
18  *
19  * This program is free software: you can redistribute it and/or modify
20  * it under the terms of the **GNU General Public License** as published by
21  * the Free Software Foundation, either **version 3** of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * *A copy of the GNU General Public License can be found in the `LICENSE`
30  * file along with this source code.*
31  *
32  ******************************************************************************/
33 
34 
35 #include "util.h" /* Include corresponding header file */
36 
37 #include <stdint.h> /* (u)intXX_t */
38 
39 
40 /* Local definitions */
41 /* Macro definition that returns a character when given a value */
42 #define TO_DEC(i) (i <= 9 ? '0' + i : '?') /* return "?" if out of range */
43 
44 
45 /* Local variables */
46 // None
47 
48 
49 /* Local prototypes */
50 // None
51 
52 
53 /**************************************************************************//**
54  * @brief
55  * Convert four bytes into a float.
56  *
57  * @param[in] byte0
58  * First byte.
59  *
60  * @param[in] byte1
61  * Second byte.
62  *
63  * @param[in] byte2
64  * Third byte.
65  *
66  * @param[in] byte3
67  * Fourth byte.
68  *
69  * @return
70  * The converted float-value.
71  *****************************************************************************/
72 float bytes_to_float(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3)
73 {
74  /* Define union */
75  union
76  {
77  float fValue;
78  uint8_t byte[4];
79  } data;
80 
81  /* Assign the four bytes to the union array */
82  data.byte[0]=byte0;
83  data.byte[1]=byte1;
84  data.byte[2]=byte2;
85  data.byte[3]=byte3;
86 
87  return (data.fValue);
88 }
89 
90 
91 /**************************************************************************//**
92  * @brief
93  * Split a `float` value in two `uint` values (before and after the comma).
94  *
95  * @param[in] fValue
96  * The float value to convert.
97  *
98  * @param[in,out] beforeComma
99  * Pointer to the `uint16_t` value before the comma.
100  *
101  * @param[in,out] afterComma
102  * Pointer to the `uint16_t` value after the comma.
103  *
104  * @param[in] decimalPlaces
105  * Amount of decimal places to use after the comma.
106  *****************************************************************************/
107 void splitFloat(float fValue, uint16_t *beforeComma, uint16_t *afterComma, uint8_t decimalPlaces)
108 {
109  /* Separate value before comma */
110  *beforeComma = (uint16_t)fValue;
111 
112  /* Separate value after comma according to given argument */
113  float multiplicationFactor = 1.0;
114  for (uint8_t counter = 0; counter < decimalPlaces; counter++) multiplicationFactor *= 10.0;
115  *afterComma = (uint16_t)((float)(fValue-(*beforeComma))*multiplicationFactor);
116 
117  /* Round up if necessary */
118  uint8_t roundingNumber = (uint8_t)(((float)(fValue-(*beforeComma))*(multiplicationFactor*10.0))-(*afterComma)*10);
119  if (roundingNumber > 4)
120  {
121  (*afterComma)++;
122  if ((decimalPlaces == 1) && (*afterComma) == 10)
123  {
124  (*beforeComma)++;
125  (*afterComma) = 0;
126  }
127  }
128 }
129 
130 
131 /**************************************************************************//**
132  * @brief
133  * Convert a `uint32_t` value to a decimal char array (string).
134  *
135  * @details
136  * This method can also add a specific amount of leading zero's if necessary.
137  *
138  * @param[out] buf
139  * The buffer to put the resulting string in.@n
140  * **This needs to have a length of 10: `char buf[10];`!**
141  *
142  * @param[in] value
143  * The `uint32_t` value to convert to a string.
144  *
145  * @param [in] totalChars
146  * Total amount of characters, to be filled with leading zero's if necessary. @n
147  * **If a value <= 1 is given, no zero's will be added**
148  *****************************************************************************/
149 void uint32_to_charDec(char *buf, uint32_t value, uint8_t totalChars)
150 {
151  if (value == 0)
152  {
153  uint8_t counter;
154  for (counter = 0; counter < totalChars; counter++)
155  {
156  buf[counter] = '0';
157  }
158 
159  buf[counter++] = '\0'; /* NULL termination character */
160  }
161  else
162  {
163  /* MAX uint32_t value = FFFFFFFFh = 4294967295d (10 decimal chars) */
164  char backwardsBuf[10];
165 
166  uint32_t calcval = value;
167  uint8_t length = 0;
168  uint8_t lengthCounter = 0;
169 
170 
171  /* Loop until the value is zero (separate characters 0-9) and calculate length */
172  while (calcval)
173  {
174  uint32_t rem = calcval % 10;
175  backwardsBuf[length] = TO_DEC(rem); /* Convert to ASCII character */
176  length++;
177 
178  calcval = calcval - rem;
179  calcval = calcval / 10;
180  }
181 
182  uint8_t index = 0;
183  uint8_t addedZeros = 0;
184 
185  /* Add leading zero's if necessary */
186  if (totalChars > 1)
187  {
188  /* Calculate power */
189  uint16_t power = 1;
190  while (totalChars != 1) {
191  power *= 10;
192  totalChars--;
193  }
194 
195  /* Print leading zero's if necessary */
196  if (value < power)
197  {
198  /* Add the correct amount of zero's */
199  uint16_t checkValue = value;
200  while (checkValue < power)
201  {
202  buf[index] = '0';
203  addedZeros++;
204  checkValue *= 10;
205  index++;
206  }
207  }
208  }
209 
210  /* Backwards counter */
211  lengthCounter = length;
212 
213  /* Reverse the characters in the buffer for the final string */
214  while (index < (length + addedZeros))
215  {
216  buf[index] = backwardsBuf[lengthCounter-1];
217  lengthCounter--;
218  index++;
219  }
220 
221  /* Add NULL termination character */
222  buf[(length + addedZeros)] = '\0';
223  }
224 }
uint32_to_charDec
void uint32_to_charDec(char *buf, uint32_t value, uint8_t totalChars)
Convert a uint32_t value to a decimal char array (string).
Definition: util.c:149
data
struct Data_t data
bytes_to_float
float bytes_to_float(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3)
Convert four bytes into a float.
Definition: util.c:72
splitFloat
void splitFloat(float fValue, uint16_t *beforeComma, uint16_t *afterComma, uint8_t decimalPlaces)
Split a float value in two uint values (before and after the comma).
Definition: util.c:107
TO_DEC
#define TO_DEC(i)
Definition: util.c:42
util.h
Utility functionality for high-precision logging voltage/current meter.