WarpTwin
Documentation for WarpTwin models and classes.
Loading...
Searching...
No Matches
Telemetry.h
Go to the documentation of this file.
1/******************************************************************************
2* Copyright (c) ATTX INC 2025. All Rights Reserved.
3*
4* This software and associated documentation (the "Software") are the
5* proprietary and confidential information of ATTX, INC. The Software is
6* furnished under a license agreement between ATTX and the user organization
7* and may be used or copied only in accordance with the terms of the agreement.
8* Refer to 'license/attx_license.adoc' for standard license terms.
9*
10* EXPORT CONTROL NOTICE: THIS SOFTWARE MAY INCLUDE CONTENT CONTROLLED UNDER THE
11* INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) OR THE EXPORT ADMINISTRATION
12* REGULATIONS (EAR99). No part of the Software may be used, reproduced, or
13* transmitted in any form or by any means, for any purpose, without the express
14* written permission of ATTX, INC.
15******************************************************************************/
16/*
17Telemetry Macro header file
18
19Author: Alex Reynolds
20Secondary Contributor: James Tabony
21*/
22
23#ifndef FLIGHT_TELEMETRY_H
24#define FLIGHT_TELEMETRY_H
25
26#include <string.h>
27
29#include "utils/stringutils.hpp"
30#include "configuration.h"
31
32// The minimum allowable value of the last 4 bits of a command APID
33#define CMD_APID_MIN_ALLOWABLE 0x1
34// The maximum allowable value of the last 4 bits of a command APID
35#define CMD_APID_MAX_ALLOWABLE 0xB
36// The minimum allowable value of the last 4 bits of a telemetry APID
37#define TLM_APID_MIN_ALLOWABLE 0xC
38// The maximum allowable value of the last 4 bits of a command APID
39#define TLM_APID_MAX_ALLOWABLE 0xF
40
49 virtual uint16 apid() const {return 0;}
50 virtual uint16 size() const {return 0;}
51 virtual void packetize(uint8* out) const {return;}
52 virtual void depacketize(const uint8* out) {return;}
53 virtual int16 str(char* output, uint16 size) const {return 0;}
54};
55
56#define CMD_TLM_COMMON(NAME, APID, SIZE, ...) \
57 struct NAME : public cmd_tlm_base { \
58 /* mutable to allow modification within the const str() member function */ \
59 mutable char temp_buf[MAX_TLM_FIELD_CHAR_BUF_SIZE]; \
60 \
61 EXPAND_VAL(FOR_EACH(DECLARE_FIELD, __VA_ARGS__)) \
62 \
63 uint16 apid() const override { return APID; } \
64 \
65 uint16 size() const override { return SIZE; } \
66 \
67 void packetize(uint8* out) const override { \
68 uint8* ptr = out; \
69 EXPAND_VAL(FOR_EACH(PACKETIZE_FIELD, __VA_ARGS__)) \
70 } \
71 \
72 void depacketize(const uint8* in) override { \
73 const uint8* ptr = in; \
74 EXPAND_VAL(FOR_EACH(DEPACKETIZE_FIELD, __VA_ARGS__)) \
75 } \
76 \
77 int16 str(char* output, uint16 size) const override { \
78 char* ptr = output; \
79 EXPAND_VAL(FOR_EACH(STR_FIELD, __VA_ARGS__)) \
80 *(ptr - 1) = '\0'; \
81 return NO_ERROR; \
82 } \
83 };
84
85// Strip parentheses from complex types
86#define STRIP_PARENS(X) STRIP_PARENS_IMPL X
87#define STRIP_PARENS_IMPL(...) __VA_ARGS__
88
89// Field declarations
90#define DECLARE_FIELD(pair) DECLARE_FIELD_ pair
91#define DECLARE_FIELD_(type, name) STRIP_PARENS(type) name;
92
93// Packetize
94#define PACKETIZE_FIELD(pair) PACKETIZE_FIELD_ pair
95#define PACKETIZE_FIELD_(type, name) do { \
96 STRIP_PARENS(type) temp = this->name; \
97 if (sizeof(STRIP_PARENS(type)) > 1 && !IS_BIG_ENDIAN) temp = warpos::changeEndian(temp);\
98 memcpy(ptr, &temp, sizeof(temp)); \
99 ptr += sizeof(temp); \
100} while (0)
101
102// Depacketize
103#define DEPACKETIZE_FIELD(pair) DEPACKETIZE_FIELD_ pair
104#define DEPACKETIZE_FIELD_(type, name) do { \
105 STRIP_PARENS(type) temp; \
106 memcpy(&temp, ptr, sizeof(temp)); \
107 if (sizeof(STRIP_PARENS(type)) > 1 && !IS_BIG_ENDIAN) temp = warpos::changeEndian(temp);\
108 this->name = temp; \
109 ptr += sizeof(temp); \
110} while (0)
111
112// Stringify helpers
113#define STR_FIELD(pair) STR_FIELD_ pair
114#define STR_FIELD_(type, name) do { \
115 int16 status = clockwerk::numberToString(this->name, temp_buf, sizeof(temp_buf)); \
116 if (status != NO_ERROR) return status; \
117 size_t len = strlen(temp_buf); \
118 if ((size_t)(ptr - output) + len + 2 > size) return ERROR_DIMENSIONS; /* not enough space */\
119 memcpy(ptr, temp_buf, len); \
120 ptr += len; \
121 *ptr++ = ','; \
122} while (0)
123
124// FOR_EACH utilities (handles up to 10 fields)
125#define EXPAND_VAL(x) x
126#define FOR_EACH_1(M, x) M(x);
127#define FOR_EACH_2(M, x, ...) M(x); FOR_EACH_1(M, __VA_ARGS__)
128#define FOR_EACH_3(M, x, ...) M(x); FOR_EACH_2(M, __VA_ARGS__)
129#define FOR_EACH_4(M, x, ...) M(x); FOR_EACH_3(M, __VA_ARGS__)
130#define FOR_EACH_5(M, x, ...) M(x); FOR_EACH_4(M, __VA_ARGS__)
131#define FOR_EACH_6(M, x, ...) M(x); FOR_EACH_5(M, __VA_ARGS__)
132#define FOR_EACH_7(M, x, ...) M(x); FOR_EACH_6(M, __VA_ARGS__)
133#define FOR_EACH_8(M, x, ...) M(x); FOR_EACH_7(M, __VA_ARGS__)
134#define FOR_EACH_9(M, x, ...) M(x); FOR_EACH_8(M, __VA_ARGS__)
135#define FOR_EACH_10(M, x, ...) M(x); FOR_EACH_9(M, __VA_ARGS__)
136#define FOR_EACH_11(M, x, ...) M(x); FOR_EACH_10(M, __VA_ARGS__)
137#define FOR_EACH_12(M, x, ...) M(x); FOR_EACH_11(M, __VA_ARGS__)
138#define FOR_EACH_13(M, x, ...) M(x); FOR_EACH_12(M, __VA_ARGS__)
139#define FOR_EACH_14(M, x, ...) M(x); FOR_EACH_13(M, __VA_ARGS__)
140#define FOR_EACH_15(M, x, ...) M(x); FOR_EACH_14(M, __VA_ARGS__)
141#define FOR_EACH_16(M, x, ...) M(x); FOR_EACH_15(M, __VA_ARGS__)
142#define FOR_EACH_17(M, x, ...) M(x); FOR_EACH_16(M, __VA_ARGS__)
143#define FOR_EACH_18(M, x, ...) M(x); FOR_EACH_17(M, __VA_ARGS__)
144#define FOR_EACH_19(M, x, ...) M(x); FOR_EACH_18(M, __VA_ARGS__)
145#define FOR_EACH_20(M, x, ...) M(x); FOR_EACH_19(M, __VA_ARGS__)
146#define FOR_EACH_21(M, x, ...) M(x); FOR_EACH_20(M, __VA_ARGS__)
147#define FOR_EACH_22(M, x, ...) M(x); FOR_EACH_21(M, __VA_ARGS__)
148#define FOR_EACH_23(M, x, ...) M(x); FOR_EACH_22(M, __VA_ARGS__)
149#define FOR_EACH_24(M, x, ...) M(x); FOR_EACH_23(M, __VA_ARGS__)
150#define FOR_EACH_25(M, x, ...) M(x); FOR_EACH_24(M, __VA_ARGS__)
151#define FOR_EACH_26(M, x, ...) M(x); FOR_EACH_25(M, __VA_ARGS__)
152#define FOR_EACH_27(M, x, ...) M(x); FOR_EACH_26(M, __VA_ARGS__)
153#define FOR_EACH_28(M, x, ...) M(x); FOR_EACH_27(M, __VA_ARGS__)
154#define FOR_EACH_29(M, x, ...) M(x); FOR_EACH_28(M, __VA_ARGS__)
155#define FOR_EACH_30(M, x, ...) M(x); FOR_EACH_29(M, __VA_ARGS__)
156#define FOR_EACH_31(M, x, ...) M(x); FOR_EACH_30(M, __VA_ARGS__)
157#define FOR_EACH_32(M, x, ...) M(x); FOR_EACH_31(M, __VA_ARGS__)
158#define FOR_EACH_33(M, x, ...) M(x); FOR_EACH_32(M, __VA_ARGS__)
159#define FOR_EACH_34(M, x, ...) M(x); FOR_EACH_33(M, __VA_ARGS__)
160#define FOR_EACH_35(M, x, ...) M(x); FOR_EACH_34(M, __VA_ARGS__)
161#define FOR_EACH_36(M, x, ...) M(x); FOR_EACH_35(M, __VA_ARGS__)
162#define FOR_EACH_37(M, x, ...) M(x); FOR_EACH_36(M, __VA_ARGS__)
163#define FOR_EACH_38(M, x, ...) M(x); FOR_EACH_37(M, __VA_ARGS__)
164#define FOR_EACH_39(M, x, ...) M(x); FOR_EACH_38(M, __VA_ARGS__)
165#define FOR_EACH_40(M, x, ...) M(x); FOR_EACH_39(M, __VA_ARGS__)
166#define FOR_EACH_41(M, x, ...) M(x); FOR_EACH_40(M, __VA_ARGS__)
167#define FOR_EACH_42(M, x, ...) M(x); FOR_EACH_41(M, __VA_ARGS__)
168#define FOR_EACH_43(M, x, ...) M(x); FOR_EACH_42(M, __VA_ARGS__)
169#define FOR_EACH_44(M, x, ...) M(x); FOR_EACH_43(M, __VA_ARGS__)
170#define FOR_EACH_45(M, x, ...) M(x); FOR_EACH_44(M, __VA_ARGS__)
171#define FOR_EACH_46(M, x, ...) M(x); FOR_EACH_45(M, __VA_ARGS__)
172#define FOR_EACH_47(M, x, ...) M(x); FOR_EACH_46(M, __VA_ARGS__)
173#define FOR_EACH_48(M, x, ...) M(x); FOR_EACH_47(M, __VA_ARGS__)
174#define FOR_EACH_49(M, x, ...) M(x); FOR_EACH_48(M, __VA_ARGS__)
175#define FOR_EACH_50(M, x, ...) M(x); FOR_EACH_49(M, __VA_ARGS__)
176
177
178#define GET_FOR_EACH_MACRO( \
179 _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
180 _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
181 _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
182 _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
183 _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
184 NAME, ...) NAME
185// This macro selects the appropriate FOR_EACH macro based on the number of arguments
186#define FOR_EACH(M, ...) \
187 EXPAND_VAL(GET_FOR_EACH_MACRO(__VA_ARGS__, \
188 FOR_EACH_50, FOR_EACH_49, FOR_EACH_48, FOR_EACH_47, FOR_EACH_46,\
189 FOR_EACH_45, FOR_EACH_44, FOR_EACH_43, FOR_EACH_42, FOR_EACH_41,\
190 FOR_EACH_40, FOR_EACH_39, FOR_EACH_38, FOR_EACH_37, FOR_EACH_36,\
191 FOR_EACH_35, FOR_EACH_34, FOR_EACH_33, FOR_EACH_32, FOR_EACH_31,\
192 FOR_EACH_30, FOR_EACH_29, FOR_EACH_28, FOR_EACH_27, FOR_EACH_26,\
193 FOR_EACH_25, FOR_EACH_24, FOR_EACH_23, FOR_EACH_22, FOR_EACH_21,\
194 FOR_EACH_20, FOR_EACH_19, FOR_EACH_18, FOR_EACH_17, FOR_EACH_16,\
195 FOR_EACH_15, FOR_EACH_14, FOR_EACH_13, FOR_EACH_12, FOR_EACH_11,\
196 FOR_EACH_10, FOR_EACH_9, FOR_EACH_8, FOR_EACH_7, FOR_EACH_6, \
197 FOR_EACH_5, FOR_EACH_4, FOR_EACH_3, FOR_EACH_2, FOR_EACH_1) \
198 (M, __VA_ARGS__))
199
297#define TELEMETRY(NAME, APID, SIZE, ...) \
298 static_assert(((APID) & 0x00F) >= TLM_APID_MIN_ALLOWABLE && ((APID) & 0x00F) <= TLM_APID_MAX_ALLOWABLE, \
299 "Creating TLM NAME failed. APID must be between TLM_APID_MIN_ALLOWABLE and TLM_APID_MAX_ALLOWABLE"); \
300 static_assert(SIZE <= CMD_TLM_PKT_MAX_SIZE_BYTES, "Creating TLM NAME failed. SIZE must be <=> configuration/CMD_TLM_PKT_MAX_SIZE_BYTES");\
301 CMD_TLM_COMMON(NAME, APID, SIZE, __VA_ARGS__)
302
303#endif
Base struct in definition of command and telemetry packets.
Definition Telemetry.h:48
virtual uint16 size() const
Definition Telemetry.h:50
virtual void depacketize(const uint8 *out)
Definition Telemetry.h:52
virtual uint16 apid() const
Definition Telemetry.h:49
virtual int16 str(char *output, uint16 size) const
Definition Telemetry.h:53
virtual void packetize(uint8 *out) const
Definition Telemetry.h:51