GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/joels/Current/lispbm/src/buffer.c Lines: 0 127 0.0 %
Date: 2025-04-09 11:39:30 Branches: 0 12 0.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
void buffer_append_int16(uint8_t* buffer, int16_t number, int32_t *index) {
25
	buffer[(*index)++] = (uint8_t)(number >> 8);
26
	buffer[(*index)++] = (uint8_t)(number);
27
}
28
29
void buffer_append_uint16(uint8_t* buffer, uint16_t number, int32_t *index) {
30
	buffer[(*index)++] = (uint8_t)(number >> 8);
31
	buffer[(*index)++] = (uint8_t)(number);
32
}
33
34
void buffer_append_int32(uint8_t* buffer, int32_t number, int32_t *index) {
35
	buffer[(*index)++] = (uint8_t)(number >> 24);
36
	buffer[(*index)++] = (uint8_t)(number >> 16);
37
	buffer[(*index)++] = (uint8_t)(number >> 8);
38
	buffer[(*index)++] = (uint8_t)(number);
39
}
40
41
void buffer_append_uint32(uint8_t* buffer, uint32_t number, int32_t *index) {
42
	buffer[(*index)++] = (uint8_t)(number >> 24);
43
	buffer[(*index)++] = (uint8_t)(number >> 16);
44
	buffer[(*index)++] = (uint8_t)(number >> 8);
45
	buffer[(*index)++] = (uint8_t)(number);
46
}
47
48
void buffer_append_int64(uint8_t* buffer, int64_t number, int32_t *index) {
49
	buffer[(*index)++] = (uint8_t)(number >> 56);
50
	buffer[(*index)++] = (uint8_t)(number >> 48);
51
	buffer[(*index)++] = (uint8_t)(number >> 40);
52
	buffer[(*index)++] = (uint8_t)(number >> 32);
53
	buffer[(*index)++] = (uint8_t)(number >> 24);
54
	buffer[(*index)++] = (uint8_t)(number >> 16);
55
	buffer[(*index)++] = (uint8_t)(number >> 8);
56
	buffer[(*index)++] = (uint8_t)(number);
57
}
58
59
void buffer_append_uint64(uint8_t* buffer, uint64_t number, int32_t *index) {
60
	buffer[(*index)++] = (uint8_t)(number >> 56);
61
	buffer[(*index)++] = (uint8_t)(number >> 48);
62
	buffer[(*index)++] = (uint8_t)(number >> 40);
63
	buffer[(*index)++] = (uint8_t)(number >> 32);
64
	buffer[(*index)++] = (uint8_t)(number >> 24);
65
	buffer[(*index)++] = (uint8_t)(number >> 16);
66
	buffer[(*index)++] = (uint8_t)(number >> 8);
67
	buffer[(*index)++] = (uint8_t)(number);
68
}
69
70
71
void buffer_append_float16(uint8_t* buffer, float number, float scale, int32_t *index) {
72
    buffer_append_int16(buffer, (int16_t)(number * scale), index);
73
}
74
75
void buffer_append_float32(uint8_t* buffer, float number, float scale, int32_t *index) {
76
    buffer_append_int32(buffer, (int32_t)(number * scale), index);
77
}
78
79
void buffer_append_double64(uint8_t* buffer, double number, double scale, int32_t *index) {
80
	buffer_append_int64(buffer, (int64_t)(number * scale), index);
81
}
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
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
	if (fabsf(number) < 1.5e-38) {
127
		number = 0.0;
128
	}
129
130
	int e = 0;
131
	float sig = frexpf(number, &e);
132
	float sig_abs = fabsf(sig);
133
	uint32_t sig_i = 0;
134
135
	if (sig_abs >= 0.5) {
136
		sig_i = (uint32_t)((sig_abs - 0.5f) * 2.0f * 8388608.0f);
137
		e += 126;
138
	}
139
140
	uint32_t res = ((uint32_t)((e & 0xFF) << 23)) | (sig_i & 0x7FFFFF);
141
	if (sig < 0) {
142
		res |= 1U << 31;
143
	}
144
145
	buffer_append_uint32(buffer, res, index);
146
}
147
148
void buffer_append_float64_auto(uint8_t* buffer, double number, int32_t *index) {
149
	float n = (float)number;
150
	float err = (float)(number - (double)n);
151
	buffer_append_float32_auto(buffer, n, index);
152
	buffer_append_float32_auto(buffer, err, index);
153
}
154
155
int16_t buffer_get_int16(const uint8_t *buffer, int32_t *index) {
156
  int16_t res =	(int16_t)((buffer[*index] << 8) |
157
                          buffer[*index + 1]);
158
  *index += 2;
159
  return res;
160
}
161
162
uint16_t buffer_get_uint16(const uint8_t *buffer, int32_t *index) {
163
  uint16_t res = 	(uint16_t)((buffer[*index] << 8) |
164
                                   buffer[*index + 1]);
165
  *index += 2;
166
  return res;
167
}
168
169
int32_t buffer_get_int32(const uint8_t *buffer, int32_t *index) {
170
  int32_t res =	(int32_t)((buffer[*index] << 24) |
171
                          (buffer[*index + 1] << 16) |
172
                          (buffer[*index + 2] << 8) |
173
                          buffer[*index + 3]);
174
  *index += 4;
175
  return res;
176
}
177
178
uint32_t buffer_get_uint32(const uint8_t *buffer, int32_t *index) {
179
	uint32_t res =	((uint32_t) buffer[*index]) << 24 |
180
					((uint32_t) buffer[*index + 1]) << 16 |
181
					((uint32_t) buffer[*index + 2]) << 8 |
182
					((uint32_t) buffer[*index + 3]);
183
	*index += 4;
184
	return res;
185
}
186
187
int64_t buffer_get_int64(const uint8_t *buffer, int32_t *index) {
188
  int64_t res =	(int64_t)(((uint64_t)buffer[*index] << 56) |
189
                          ((uint64_t)buffer[*index + 1] << 48) |
190
                          ((uint64_t)buffer[*index + 2] << 40) |
191
                          ((uint64_t)buffer[*index + 3] << 32) |
192
                          ((uint64_t)buffer[*index + 4] << 24) |
193
                          ((uint64_t)buffer[*index + 5] << 16) |
194
                          ((uint64_t)buffer[*index + 6] << 8) |
195
                          ((uint64_t)buffer[*index + 7]));
196
  *index += 8;
197
  return res;
198
}
199
200
uint64_t buffer_get_uint64(const uint8_t *buffer, int32_t *index) {
201
	uint64_t res =	((uint64_t) buffer[*index]) << 56 |
202
					((uint64_t) buffer[*index + 1]) << 48 |
203
					((uint64_t) buffer[*index + 2]) << 40 |
204
					((uint64_t) buffer[*index + 3]) << 32 |
205
					((uint64_t) buffer[*index + 4]) << 24 |
206
					((uint64_t) buffer[*index + 5]) << 16 |
207
					((uint64_t) buffer[*index + 6]) << 8 |
208
					((uint64_t) buffer[*index + 7]);
209
	*index += 8;
210
	return res;
211
}
212
213
float buffer_get_float16(const uint8_t *buffer, float scale, int32_t *index) {
214
    return (float)buffer_get_int16(buffer, index) / scale;
215
}
216
217
float buffer_get_float32(const uint8_t *buffer, float scale, int32_t *index) {
218
    return (float)buffer_get_int32(buffer, index) / scale;
219
}
220
221
double buffer_get_double64(const uint8_t *buffer, double scale, int32_t *index) {
222
    return (double)buffer_get_int64(buffer, index) / scale;
223
}
224
225
float buffer_get_float32_auto(const uint8_t *buffer, int32_t *index) {
226
	uint32_t res = buffer_get_uint32(buffer, index);
227
228
	int e = (res >> 23) & 0xFF;
229
	uint32_t sig_i = res & 0x7FFFFF;
230
	bool neg = res & (1U << 31);
231
232
	float sig = 0.0;
233
	if (e != 0 || sig_i != 0) {
234
		sig = (float)sig_i / (8388608.0f * 2.0f) + 0.5f;
235
		e -= 126;
236
	}
237
238
	if (neg) {
239
		sig = -sig;
240
	}
241
242
	return ldexpf(sig, e);
243
}
244
245
double buffer_get_float64_auto(const uint8_t *buffer, int32_t *index) {
246
	double n = buffer_get_float32_auto(buffer, index);
247
	double err = buffer_get_float32_auto(buffer, index);
248
	return n + err;
249
}