aboutsummaryrefslogtreecommitdiff
path: root/shared/protocol.c
blob: c1217b2bcba9ad90615eb9ee62e3db76830c8523 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stddef.h>

#include "protocol.h"

#ifdef __cplusplus
extern "C" {
#endif

cd_cmd_id_t g_cd_protocol_fresh_message_id = 0;

size_t cd_cmd_sizeof(uint8_t data[CD_SERIAL_READ_BUFFER_SIZE], uint8_t data_length) {
	cd_cmd_opcode_t opcode = data[0];
	if (CD_CMD_HANDLERS_SIZE[opcode] > 0) return CD_CMD_HANDLERS_SIZE[opcode];

	cd_s_bin *copy = cd_bin_s_alloc(data_length, data);
	size_t length  = (*CD_CMD_HANDLERS_SIZEOF[opcode])(copy);

	CD_FREE(copy);

	return length;
}

/**
 * @brief macro to calculate size of message based on struct with member to
 * indicate length of dynamic (last) field
 *
 * @param data  cd_s_bin pointer to currently received data
 * @param struct_t  message struct
 * @param length_field  struct field with dynamic length
 *
 * @return size_t with calculated size
 *
 * equivalent c code:
 *
 * size_t size = sizeof(struct_t);
 * size_t dyn_member_offset = offsetof(struct_t, length_field);
 * size_t dyn_member_size = sizeof(((struct_t*)0)->length_field);
 * if (data->bytes >= (dyn_member_offset + dyn_member_size))
 *     size += cd_bin_ntohd(&data->data[dyn_member_offset], dyn_member_size);
 * return size;
 */
#define CD_DYN_MEMBER_SIZEOF(data, struct_t, length_field)                                                                                                                         \
	sizeof(struct_t) + ((data->bytes >= (offsetof(struct_t, length_field) + sizeof(((struct_t *)0)->length_field)))                                                                \
							? (cd_bin_ntohd(&data->data[offsetof(struct_t, length_field)], sizeof(((struct_t *)0)->length_field)))                                                 \
							: 0);

size_t cd_cmd_response_sizeof(cd_s_bin *data) { return CD_DYN_MEMBER_SIZEOF(data, cd_s_cmd_response, response_size); }

cd_cmd_id_t cd_protocol_fresh_message_id() { return g_cd_protocol_fresh_message_id++; }

#ifdef __cplusplus
}
#endif