GCC Code Coverage Report


Directory: ../src/
File: /home/joels/Current/lispbm/src/buffer.c
Date: 2025-08-08 18:10:24
Exec Total Coverage
Lines: 138 138 100.0%
Functions: 22 22 100.0%
Branches: 12 12 100.0%

Line Branch Exec Source
1 /*
2 Copyright 2016 Benjamin Vedder benjamin@vedder.se
3
4 This file is part of the VESC firmware.
5
6 The VESC firmware is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 The VESC firmware is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "buffer.h"
21 #include <math.h>
22 #include <stdbool.h>
23
24 28 void buffer_append_int16(uint8_t* buffer, int16_t number, int32_t *index) {
25 28 buffer[(*index)++] = (uint8_t)(number >> 8);
26 28 buffer[(*index)++] = (uint8_t)(number);
27 28 }
28
29 32 void buffer_append_uint16(uint8_t* buffer, uint16_t number, int32_t *index) {
30 32 buffer[(*index)++] = (uint8_t)(number >> 8);
31 32 buffer[(*index)++] = (uint8_t)(number);
32 32 }
33
34 326 void buffer_append_int32(uint8_t* buffer, int32_t number, int32_t *index) {
35 326 buffer[(*index)++] = (uint8_t)(number >> 24);
36 326 buffer[(*index)++] = (uint8_t)(number >> 16);
37 326 buffer[(*index)++] = (uint8_t)(number >> 8);
38 326 buffer[(*index)++] = (uint8_t)(number);
39 326 }
40
41 931 void buffer_append_uint32(uint8_t* buffer, uint32_t number, int32_t *index) {
42 931 buffer[(*index)++] = (uint8_t)(number >> 24);
43 931 buffer[(*index)++] = (uint8_t)(number >> 16);
44 931 buffer[(*index)++] = (uint8_t)(number >> 8);
45 931 buffer[(*index)++] = (uint8_t)(number);
46 931 }
47
48 36 void buffer_append_int64(uint8_t* buffer, int64_t number, int32_t *index) {
49 36 buffer[(*index)++] = (uint8_t)(number >> 56);
50 36 buffer[(*index)++] = (uint8_t)(number >> 48);
51 36 buffer[(*index)++] = (uint8_t)(number >> 40);
52 36 buffer[(*index)++] = (uint8_t)(number >> 32);
53 36 buffer[(*index)++] = (uint8_t)(number >> 24);
54 36 buffer[(*index)++] = (uint8_t)(number >> 16);
55 36 buffer[(*index)++] = (uint8_t)(number >> 8);
56 36 buffer[(*index)++] = (uint8_t)(number);
57 36 }
58
59 9 void buffer_append_uint64(uint8_t* buffer, uint64_t number, int32_t *index) {
60 9 buffer[(*index)++] = (uint8_t)(number >> 56);
61 9 buffer[(*index)++] = (uint8_t)(number >> 48);
62 9 buffer[(*index)++] = (uint8_t)(number >> 40);
63 9 buffer[(*index)++] = (uint8_t)(number >> 32);
64 9 buffer[(*index)++] = (uint8_t)(number >> 24);
65 9 buffer[(*index)++] = (uint8_t)(number >> 16);
66 9 buffer[(*index)++] = (uint8_t)(number >> 8);
67 9 buffer[(*index)++] = (uint8_t)(number);
68 9 }
69
70
71 18 void buffer_append_float16(uint8_t* buffer, float number, float scale, int32_t *index) {
72 18 buffer_append_int16(buffer, (int16_t)(number * scale), index);
73 18 }
74
75 28 void buffer_append_float32(uint8_t* buffer, float number, float scale, int32_t *index) {
76 28 buffer_append_int32(buffer, (int32_t)(number * scale), index);
77 28 }
78
79 28 void buffer_append_double64(uint8_t* buffer, double number, double scale, int32_t *index) {
80 28 buffer_append_int64(buffer, (int64_t)(number * scale), index);
81 28 }
82
83 /*
84 * See my question:
85 * http://stackoverflow.com/questions/40416682/portable-way-to-serialize-float-as-32-bit-integer
86 *
87 * Regarding the float32_auto functions:
88 *
89 * Noticed that frexp and ldexp fit the format of the IEEE float representation, so
90 * they should be quite fast. They are (more or less) equivalent with the following:
91 *
92 * float frexp_slow(float f, int *e) {
93 * if (f == 0.0) {
94 * *e = 0;
95 * return 0.0;
96 * }
97 *
98 * *e = ceilf(log2f(fabsf(f)));
99 * float res = f / powf(2.0, (float)*e);
100 *
101 * if (res >= 1.0) {
102 * res -= 0.5;
103 * *e += 1;
104 * }
105 *
106 * if (res <= -1.0) {
107 * res += 0.5;
108 * *e += 1;
109 * }
110 *
111 * return res;
112 * }
113 *
114 * float ldexp_slow(float f, int e) {
115 * return f * powf(2.0, (float)e);
116 * }
117 *
118 * 8388608.0 is 2^23, which scales the result to fit within 23 bits if sig_abs < 1.0.
119 *
120 * This should be a relatively fast and efficient way to serialize
121 * floating point numbers in a fully defined manner.
122 */
123 536 void buffer_append_float32_auto(uint8_t* buffer, float number, int32_t *index) {
124 // Set subnormal numbers to 0 as they are not handled properly
125 // using this method.
126
2/2
✓ Branch 0 taken 161 times.
✓ Branch 1 taken 375 times.
536 if (fabsf(number) < 1.5e-38) {
127 161 number = 0.0;
128 }
129
130 536 int e = 0;
131 536 float sig = frexpf(number, &e);
132 536 float sig_abs = fabsf(sig);
133 536 uint32_t sig_i = 0;
134
135
2/2
✓ Branch 0 taken 375 times.
✓ Branch 1 taken 161 times.
536 if (sig_abs >= 0.5) {
136 375 sig_i = (uint32_t)((sig_abs - 0.5f) * 2.0f * 8388608.0f);
137 375 e += 126;
138 }
139
140 536 uint32_t res = ((uint32_t)((e & 0xFF) << 23)) | (sig_i & 0x7FFFFF);
141
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 397 times.
536 if (sig < 0) {
142 139 res |= 1U << 31;
143 }
144
145 536 buffer_append_uint32(buffer, res, index);
146 536 }
147
148 8 void buffer_append_float64_auto(uint8_t* buffer, double number, int32_t *index) {
149 8 float n = (float)number;
150 8 float err = (float)(number - (double)n);
151 8 buffer_append_float32_auto(buffer, n, index);
152 8 buffer_append_float32_auto(buffer, err, index);
153 8 }
154
155 28 int16_t buffer_get_int16(const uint8_t *buffer, int32_t *index) {
156 28 int16_t res = (int16_t)((buffer[*index] << 8) |
157 28 buffer[*index + 1]);
158 28 *index += 2;
159 28 return res;
160 }
161
162 85 uint16_t buffer_get_uint16(const uint8_t *buffer, int32_t *index) {
163 85 uint16_t res = (uint16_t)((buffer[*index] << 8) |
164 85 buffer[*index + 1]);
165 85 *index += 2;
166 85 return res;
167 }
168
169 5583 int32_t buffer_get_int32(const uint8_t *buffer, int32_t *index) {
170 5583 int32_t res = (int32_t)((buffer[*index] << 24) |
171 5583 (buffer[*index + 1] << 16) |
172 5583 (buffer[*index + 2] << 8) |
173 5583 buffer[*index + 3]);
174 5583 *index += 4;
175 5583 return res;
176 }
177
178 8422 uint32_t buffer_get_uint32(const uint8_t *buffer, int32_t *index) {
179 8422 uint32_t res = ((uint32_t) buffer[*index]) << 24 |
180 8422 ((uint32_t) buffer[*index + 1]) << 16 |
181 8422 ((uint32_t) buffer[*index + 2]) << 8 |
182 8422 ((uint32_t) buffer[*index + 3]);
183 8422 *index += 4;
184 8422 return res;
185 }
186
187 36 int64_t buffer_get_int64(const uint8_t *buffer, int32_t *index) {
188 36 int64_t res = (int64_t)(((uint64_t)buffer[*index] << 56) |
189 36 ((uint64_t)buffer[*index + 1] << 48) |
190 36 ((uint64_t)buffer[*index + 2] << 40) |
191 36 ((uint64_t)buffer[*index + 3] << 32) |
192 36 ((uint64_t)buffer[*index + 4] << 24) |
193 36 ((uint64_t)buffer[*index + 5] << 16) |
194 36 ((uint64_t)buffer[*index + 6] << 8) |
195 36 ((uint64_t)buffer[*index + 7]));
196 36 *index += 8;
197 36 return res;
198 }
199
200 9 uint64_t buffer_get_uint64(const uint8_t *buffer, int32_t *index) {
201 9 uint64_t res = ((uint64_t) buffer[*index]) << 56 |
202 9 ((uint64_t) buffer[*index + 1]) << 48 |
203 9 ((uint64_t) buffer[*index + 2]) << 40 |
204 9 ((uint64_t) buffer[*index + 3]) << 32 |
205 9 ((uint64_t) buffer[*index + 4]) << 24 |
206 9 ((uint64_t) buffer[*index + 5]) << 16 |
207 9 ((uint64_t) buffer[*index + 6]) << 8 |
208 9 ((uint64_t) buffer[*index + 7]);
209 9 *index += 8;
210 9 return res;
211 }
212
213 18 float buffer_get_float16(const uint8_t *buffer, float scale, int32_t *index) {
214 18 return (float)buffer_get_int16(buffer, index) / scale;
215 }
216
217 28 float buffer_get_float32(const uint8_t *buffer, float scale, int32_t *index) {
218 28 return (float)buffer_get_int32(buffer, index) / scale;
219 }
220
221 28 double buffer_get_double64(const uint8_t *buffer, double scale, int32_t *index) {
222 28 return (double)buffer_get_int64(buffer, index) / scale;
223 }
224
225 769 float buffer_get_float32_auto(const uint8_t *buffer, int32_t *index) {
226 769 uint32_t res = buffer_get_uint32(buffer, index);
227
228 769 int e = (res >> 23) & 0xFF;
229 769 uint32_t sig_i = res & 0x7FFFFF;
230 769 bool neg = res & (1U << 31);
231
232 769 float sig = 0.0;
233
4/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 707 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 60 times.
769 if (e != 0 || sig_i != 0) {
234 709 sig = (float)sig_i / (8388608.0f * 2.0f) + 0.5f;
235 709 e -= 126;
236 }
237
238
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 679 times.
769 if (neg) {
239 90 sig = -sig;
240 }
241
242 769 return ldexpf(sig, e);
243 }
244
245 8 double buffer_get_float64_auto(const uint8_t *buffer, int32_t *index) {
246 8 double n = buffer_get_float32_auto(buffer, index);
247 8 double err = buffer_get_float32_auto(buffer, index);
248 8 return n + err;
249 }
250