can someone give alternate design in C?
The "standard" way would be to use printf
and scanf
to create an ascii representation of the data:
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <assert.h>
#include <float.h>
struct AMG_ANGLES {
float yaw;
float pitch;
float roll;
};
// declare a buffer at least this long to be sure encode works properly
#define AMG_ANGLES_BUFSIZE ( \
3 * ( /* 3 floats */ \
2 + /* digit and dot */ \
FLT_DECIMAL_DIG - 1 + /* digits after dot */ \
4 /* the 'e±dd' part */ \
) \
+ 2 /* spaces */ \
+ 1 /* zero terminating character */ \
)
int encode(char *dest, size_t destsize, const struct AMG_ANGLES *a) {
return snprintf(dest, destsize, "%.*e %.*e %.*e",
FLT_DECIMAL_DIG - 1, a->yaw,
FLT_DECIMAL_DIG - 1, a->pitch,
FLT_DECIMAL_DIG - 1, a->roll);
// my pedantic self wants to add `assert(snprintf_ret < AMG_ANGLES_BUFSIZE);`
}
int decode(struct AMG_ANGLES *dest, const char *data) {
return sscanf(data, "%e %e %e", &dest->yaw, &dest->pitch, &dest->roll) == 3 ? 0 : -1;
}
int main() {
char buf[AMG_ANGLES_BUFSIZE];
const struct AMG_ANGLES a = { FLT_MIN, FLT_MAX, FLT_MIN };
encode(buf, sizeof(buf), &a);
struct AMG_ANGLES b;
const int decoderet = decode(&b, buf);
assert(decoderet == 0);
assert(b.yaw == FLT_MIN);
assert(b.pitch == FLT_MAX);
assert(b.roll == FLT_MIN);
}
However in bare-metal embedded I try not to use scanf
- it's a big function with some dependencies. So it's better to call strtof
itself, but it needs some thinking:
int decode2(struct AMG_ANGLES *dest, const char *data) {
errno = 0;
char *endptr = NULL;
dest->yaw = strtof(data, &endptr);
if (errno != 0 || endptr == data) return -1;
if (*endptr != ' ') return -1;
data = endptr + 1;
dest->pitch = strtof(data, &endptr);
if (errno != 0 || endptr == data) return -1;
if (*endptr != ' ') return -1;
data = endptr + 1;
dest->roll = strtof(data, &endptr);
if (errno != 0 || endptr == data) return -1;
if (*endptr != '\0') return -1;
return 0;
}
or with removed code duplication:
int decode2(struct AMG_ANGLES *dest, const char *data) {
// array of pointers to floats to fill
float * const dests[] = { &dest->yaw, &dest->pitch, &dest->roll };
const size_t dests_cnt = sizeof(dests)/sizeof(*dests);
errno = 0;
for (int i = 0; i < dests_cnt; ++i) {
char *endptr = NULL;
*dests[i] = strtof(data, &endptr);
if (errno != 0 || endptr == data) return -1;
// space separates numbers, last number is followed by zero
const char should_be_char = i != dests_cnt - 1 ? ' ' : '\0';
if (*endptr != should_be_char) return -1;
data = endptr + 1;
}
return 0;
}
I needed to use some google and re-read chux answers to properly recall how to use FLT_DECIMAL_DIG
in printf
to print floats, that's most probably because I rarely worked with floats.