QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
UBXConfigKeys.h
Go to the documentation of this file.
1// Configuration keys as the u-blox interface descriptions (F9 HPG, M10, X20) define them.
2#pragma once
3
4#include <array>
5#include <cstddef>
6#include <cstdint>
7#include <optional>
8#include <span>
9#include <type_traits>
10
11#include "LittleEndian.h"
12
13namespace UBX {
14
16[[nodiscard]] constexpr size_t cfgKeyValueBytes(uint32_t keyId)
17{
18 switch ((keyId >> 28) & 0x7) {
19 case 1: // A one-bit value still occupies a byte.
20 case 2:
21 return 1;
22 case 3:
23 return 2;
24 case 4:
25 return 4;
26 case 5:
27 return 8;
28 default:
29 return 0;
30 }
31}
32
34template <typename T>
35struct CfgKey
36{
37 static_assert(std::is_arithmetic_v<T>);
38
39 uint32_t id;
40};
41
43template <typename T, uint32_t Id>
44[[nodiscard]] consteval CfgKey<T> cfgKey()
45{
46 static_assert(cfgKeyValueBytes(Id) == sizeof(T), "the value type size must match the key id size bits");
47 return {Id};
48}
49
51enum class MsgOutPort : uint32_t
52{
53 UART1 = 1,
54 USB = 3,
55};
56
59{
61
62 [[nodiscard]] constexpr CfgKey<uint8_t> port(MsgOutPort port) const
63 {
64 return {i2c.id + static_cast<uint32_t>(port)};
65 }
66};
67
68} // namespace UBX
69
70// Each key is followed by its type in the interface description.
71namespace UBX::Cfg {
72inline constexpr auto ITFM_ENABLE = cfgKey<uint8_t, 0x1041000d>(); // L
73inline constexpr auto NAVHPG_DGNSSMODE = cfgKey<uint8_t, 0x20140011>(); // E1
74inline constexpr auto NAVSPG_DYNMODEL = cfgKey<uint8_t, 0x20110021>(); // E1
75inline constexpr auto NAVSPG_FIXMODE = cfgKey<uint8_t, 0x20110011>(); // E1
76inline constexpr auto NAVSPG_UTCSTANDARD = cfgKey<uint8_t, 0x2011001c>(); // E1
77inline constexpr auto ODO_OUTLPCOG = cfgKey<uint8_t, 0x10220004>(); // L
78inline constexpr auto ODO_OUTLPVEL = cfgKey<uint8_t, 0x10220003>(); // L
79inline constexpr auto ODO_USE_COG = cfgKey<uint8_t, 0x10220002>(); // L
80inline constexpr auto ODO_USE_ODO = cfgKey<uint8_t, 0x10220001>(); // L
81inline constexpr auto RATE_MEAS = cfgKey<uint16_t, 0x30210001>(); // U2
82inline constexpr auto RATE_NAV = cfgKey<uint16_t, 0x30210002>(); // U2
83inline constexpr auto RATE_TIMEREF = cfgKey<uint8_t, 0x20210003>(); // E1
84inline constexpr auto SEC_JAMDET_SENSITIVITY_HI = cfgKey<uint8_t, 0x10f60051>(); // L
85inline constexpr auto SIGNAL_HEALTH_L5 = cfgKey<uint8_t, 0x10320001>(); // L
86inline constexpr auto TMODE_FIXED_POS_ACC = cfgKey<uint32_t, 0x4003000f>(); // U4
87inline constexpr auto TMODE_HEIGHT = cfgKey<int32_t, 0x4003000b>(); // I4
88inline constexpr auto TMODE_HEIGHT_HP = cfgKey<int8_t, 0x2003000e>(); // I1
89inline constexpr auto TMODE_LAT = cfgKey<int32_t, 0x40030009>(); // I4
90inline constexpr auto TMODE_LAT_HP = cfgKey<int8_t, 0x2003000c>(); // I1
91inline constexpr auto TMODE_LON = cfgKey<int32_t, 0x4003000a>(); // I4
92inline constexpr auto TMODE_LON_HP = cfgKey<int8_t, 0x2003000d>(); // I1
93inline constexpr auto TMODE_MODE = cfgKey<uint8_t, 0x20030001>(); // E1
94inline constexpr auto TMODE_POS_TYPE = cfgKey<uint8_t, 0x20030002>(); // E1
95inline constexpr auto TMODE_SVIN_ACC_LIMIT = cfgKey<uint32_t, 0x40030011>(); // U4
96inline constexpr auto TMODE_SVIN_MIN_DUR = cfgKey<uint32_t, 0x40030010>(); // U4
97inline constexpr auto UART1INPROT_NMEA = cfgKey<uint8_t, 0x10730002>(); // L
98inline constexpr auto UART1INPROT_RTCM3X = cfgKey<uint8_t, 0x10730004>(); // L
99inline constexpr auto UART1INPROT_SPARTN = cfgKey<uint8_t, 0x10730005>(); // L
100inline constexpr auto UART1INPROT_UBX = cfgKey<uint8_t, 0x10730001>(); // L
101inline constexpr auto UART1OUTPROT_NMEA = cfgKey<uint8_t, 0x10740002>(); // L
102inline constexpr auto UART1OUTPROT_RTCM3X = cfgKey<uint8_t, 0x10740004>(); // L
103inline constexpr auto UART1OUTPROT_UBX = cfgKey<uint8_t, 0x10740001>(); // L
104inline constexpr auto UART1_BAUDRATE = cfgKey<uint32_t, 0x40520001>(); // U4
105inline constexpr auto UART1_DATABITS = cfgKey<uint8_t, 0x20520003>(); // E1
106inline constexpr auto UART1_PARITY = cfgKey<uint8_t, 0x20520004>(); // E1
107inline constexpr auto UART1_STOPBITS = cfgKey<uint8_t, 0x20520002>(); // E1
108inline constexpr auto USBINPROT_NMEA = cfgKey<uint8_t, 0x10770002>(); // L
109inline constexpr auto USBINPROT_RTCM3X = cfgKey<uint8_t, 0x10770004>(); // L
110inline constexpr auto USBINPROT_SPARTN = cfgKey<uint8_t, 0x10770005>(); // L
111inline constexpr auto USBINPROT_UBX = cfgKey<uint8_t, 0x10770001>(); // L
112inline constexpr auto USBOUTPROT_NMEA = cfgKey<uint8_t, 0x10780002>(); // L
113inline constexpr auto USBOUTPROT_RTCM3X = cfgKey<uint8_t, 0x10780004>(); // L
114inline constexpr auto USBOUTPROT_UBX = cfgKey<uint8_t, 0x10780001>(); // L
115
116inline constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1005{cfgKey<uint8_t, 0x209102bd>()};
117static_assert(MSGOUT_RTCM_3X_TYPE1005.port(MsgOutPort::UART1).id == 0x209102be);
118static_assert(MSGOUT_RTCM_3X_TYPE1005.port(MsgOutPort::USB).id == 0x209102c0);
119inline constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1074{cfgKey<uint8_t, 0x2091035e>()};
120static_assert(MSGOUT_RTCM_3X_TYPE1074.port(MsgOutPort::UART1).id == 0x2091035f);
121static_assert(MSGOUT_RTCM_3X_TYPE1074.port(MsgOutPort::USB).id == 0x20910361);
122inline constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1077{cfgKey<uint8_t, 0x209102cc>()};
123static_assert(MSGOUT_RTCM_3X_TYPE1077.port(MsgOutPort::UART1).id == 0x209102cd);
124static_assert(MSGOUT_RTCM_3X_TYPE1077.port(MsgOutPort::USB).id == 0x209102cf);
125inline constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1084{cfgKey<uint8_t, 0x20910363>()};
126static_assert(MSGOUT_RTCM_3X_TYPE1084.port(MsgOutPort::UART1).id == 0x20910364);
127static_assert(MSGOUT_RTCM_3X_TYPE1084.port(MsgOutPort::USB).id == 0x20910366);
128inline constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1087{cfgKey<uint8_t, 0x209102d1>()};
129static_assert(MSGOUT_RTCM_3X_TYPE1087.port(MsgOutPort::UART1).id == 0x209102d2);
130static_assert(MSGOUT_RTCM_3X_TYPE1087.port(MsgOutPort::USB).id == 0x209102d4);
131inline constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1094{cfgKey<uint8_t, 0x20910368>()};
132static_assert(MSGOUT_RTCM_3X_TYPE1094.port(MsgOutPort::UART1).id == 0x20910369);
133static_assert(MSGOUT_RTCM_3X_TYPE1094.port(MsgOutPort::USB).id == 0x2091036b);
134inline constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1097{cfgKey<uint8_t, 0x20910318>()};
135static_assert(MSGOUT_RTCM_3X_TYPE1097.port(MsgOutPort::UART1).id == 0x20910319);
136static_assert(MSGOUT_RTCM_3X_TYPE1097.port(MsgOutPort::USB).id == 0x2091031b);
137inline constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1124{cfgKey<uint8_t, 0x2091036d>()};
138static_assert(MSGOUT_RTCM_3X_TYPE1124.port(MsgOutPort::UART1).id == 0x2091036e);
139static_assert(MSGOUT_RTCM_3X_TYPE1124.port(MsgOutPort::USB).id == 0x20910370);
140inline constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1127{cfgKey<uint8_t, 0x209102d6>()};
141static_assert(MSGOUT_RTCM_3X_TYPE1127.port(MsgOutPort::UART1).id == 0x209102d7);
142static_assert(MSGOUT_RTCM_3X_TYPE1127.port(MsgOutPort::USB).id == 0x209102d9);
143inline constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1230{cfgKey<uint8_t, 0x20910303>()};
144static_assert(MSGOUT_RTCM_3X_TYPE1230.port(MsgOutPort::UART1).id == 0x20910304);
145static_assert(MSGOUT_RTCM_3X_TYPE1230.port(MsgOutPort::USB).id == 0x20910306);
146inline constexpr MsgOutKey MSGOUT_UBX_MON_RF{cfgKey<uint8_t, 0x20910359>()};
147static_assert(MSGOUT_UBX_MON_RF.port(MsgOutPort::UART1).id == 0x2091035a);
148static_assert(MSGOUT_UBX_MON_RF.port(MsgOutPort::USB).id == 0x2091035c);
149inline constexpr MsgOutKey MSGOUT_UBX_NAV_DOP{cfgKey<uint8_t, 0x20910038>()};
150static_assert(MSGOUT_UBX_NAV_DOP.port(MsgOutPort::UART1).id == 0x20910039);
151static_assert(MSGOUT_UBX_NAV_DOP.port(MsgOutPort::USB).id == 0x2091003b);
152inline constexpr MsgOutKey MSGOUT_UBX_NAV_EOE{cfgKey<uint8_t, 0x2091015f>()};
153static_assert(MSGOUT_UBX_NAV_EOE.port(MsgOutPort::UART1).id == 0x20910160);
154static_assert(MSGOUT_UBX_NAV_EOE.port(MsgOutPort::USB).id == 0x20910162);
155inline constexpr MsgOutKey MSGOUT_UBX_NAV_HPPOSLLH{cfgKey<uint8_t, 0x20910033>()};
156static_assert(MSGOUT_UBX_NAV_HPPOSLLH.port(MsgOutPort::UART1).id == 0x20910034);
157static_assert(MSGOUT_UBX_NAV_HPPOSLLH.port(MsgOutPort::USB).id == 0x20910036);
158inline constexpr MsgOutKey MSGOUT_UBX_NAV_PVT{cfgKey<uint8_t, 0x20910006>()};
159static_assert(MSGOUT_UBX_NAV_PVT.port(MsgOutPort::UART1).id == 0x20910007);
160static_assert(MSGOUT_UBX_NAV_PVT.port(MsgOutPort::USB).id == 0x20910009);
161inline constexpr MsgOutKey MSGOUT_UBX_NAV_RELPOSNED{cfgKey<uint8_t, 0x2091008d>()};
162static_assert(MSGOUT_UBX_NAV_RELPOSNED.port(MsgOutPort::UART1).id == 0x2091008e);
163static_assert(MSGOUT_UBX_NAV_RELPOSNED.port(MsgOutPort::USB).id == 0x20910090);
164inline constexpr MsgOutKey MSGOUT_UBX_NAV_SAT{cfgKey<uint8_t, 0x20910015>()};
165static_assert(MSGOUT_UBX_NAV_SAT.port(MsgOutPort::UART1).id == 0x20910016);
166static_assert(MSGOUT_UBX_NAV_SAT.port(MsgOutPort::USB).id == 0x20910018);
167inline constexpr MsgOutKey MSGOUT_UBX_NAV_STATUS{cfgKey<uint8_t, 0x2091001a>()};
168static_assert(MSGOUT_UBX_NAV_STATUS.port(MsgOutPort::UART1).id == 0x2091001b);
169static_assert(MSGOUT_UBX_NAV_STATUS.port(MsgOutPort::USB).id == 0x2091001d);
170inline constexpr MsgOutKey MSGOUT_UBX_NAV_SVIN{cfgKey<uint8_t, 0x20910088>()};
171static_assert(MSGOUT_UBX_NAV_SVIN.port(MsgOutPort::UART1).id == 0x20910089);
172static_assert(MSGOUT_UBX_NAV_SVIN.port(MsgOutPort::USB).id == 0x2091008b);
173inline constexpr MsgOutKey MSGOUT_UBX_NAV_TIMEGPS{cfgKey<uint8_t, 0x20910047>()};
174static_assert(MSGOUT_UBX_NAV_TIMEGPS.port(MsgOutPort::UART1).id == 0x20910048);
175static_assert(MSGOUT_UBX_NAV_TIMEGPS.port(MsgOutPort::USB).id == 0x2091004a);
176inline constexpr MsgOutKey MSGOUT_UBX_RXM_RAWX{cfgKey<uint8_t, 0x209102a4>()};
177static_assert(MSGOUT_UBX_RXM_RAWX.port(MsgOutPort::UART1).id == 0x209102a5);
178static_assert(MSGOUT_UBX_RXM_RAWX.port(MsgOutPort::USB).id == 0x209102a7);
179inline constexpr MsgOutKey MSGOUT_UBX_RXM_SFRBX{cfgKey<uint8_t, 0x20910231>()};
180static_assert(MSGOUT_UBX_RXM_SFRBX.port(MsgOutPort::UART1).id == 0x20910232);
181static_assert(MSGOUT_UBX_RXM_SFRBX.port(MsgOutPort::USB).id == 0x20910234);
182inline constexpr MsgOutKey MSGOUT_UBX_SEC_SIG{cfgKey<uint8_t, 0x20910634>()};
183static_assert(MSGOUT_UBX_SEC_SIG.port(MsgOutPort::UART1).id == 0x20910635);
184static_assert(MSGOUT_UBX_SEC_SIG.port(MsgOutPort::USB).id == 0x20910637);
185} // namespace UBX::Cfg
186
187// CFG-VALSET and CFG-VALGET key/value encoding.
188namespace UBX {
189
191[[nodiscard]] constexpr unsigned configurationValueBytes(uint32_t key)
192{
193 const size_t width = cfgKeyValueBytes(key);
194 return width <= sizeof(uint32_t) ? static_cast<unsigned>(width) : 0;
195}
196
198{
199 uint32_t key;
200 uint32_t value;
201
202 bool operator==(const ConfigurationValue&) const = default;
203};
204
207{
208public:
209 explicit ConfigurationValueCursor(std::span<const uint8_t> entries)
210 : _remaining(entries)
211 {}
212
213 bool empty() const { return _remaining.empty(); }
214
215 std::optional<ConfigurationValue> next()
216 {
217 if (!_valid || empty()) {
218 return std::nullopt;
219 }
220 const auto key = LittleEndian::read<uint32_t>(_remaining, 0);
221 const unsigned width = key ? configurationValueBytes(*key) : 0;
222 if (!width || _remaining.size() < sizeof(uint32_t) + width) {
223 _valid = false;
224 return std::nullopt;
225 }
226 uint32_t value = 0;
227 for (unsigned byte = 0; byte < width; ++byte) {
228 value |= uint32_t(_remaining[sizeof(uint32_t) + byte]) << (8 * byte);
229 }
230 if ((*key >> 28) == 1 && value > 1) {
231 _valid = false;
232 return std::nullopt;
233 }
234 _remaining = _remaining.subspan(sizeof(uint32_t) + width);
235 return ConfigurationValue{*key, value};
236 }
237
238private:
239 std::span<const uint8_t> _remaining;
240 bool _valid = true;
241};
242
245{
247 static constexpr size_t MAX_KEYS = 9;
248
249 std::array<ConfigurationValue, MAX_KEYS> values{};
250 size_t count = 0;
251};
252
254[[nodiscard]] inline std::optional<ConfigurationValues> decodeConfigurationValues(std::span<const uint8_t> payload)
255{
256 if (payload.size() < 4 || payload[0] != 1 || payload[1] || payload[2] || payload[3]) {
257 return std::nullopt;
258 }
259 ConfigurationValues result;
260 ConfigurationValueCursor cursor(payload.subspan(4));
261 while (!cursor.empty()) {
262 const auto entry = cursor.next();
263 if (!entry || result.count == result.values.size()) {
264 return std::nullopt;
265 }
266 result.values[result.count++] = *entry;
267 }
268 return result;
269}
270
273template <size_t Capacity>
275{
276 static_assert(Capacity >= 4);
277 std::array<uint8_t, Capacity> bytes{0, 1}; // RAM layer; no persistent writes.
278 size_t size = 4;
279 bool valid = true;
280
281 std::span<const uint8_t> payload() const
282 {
283 return valid && size > 4 ? std::span<const uint8_t>(bytes).first(size) : std::span<const uint8_t>{};
284 }
285
287 std::span<const uint8_t> entries() const { return std::span<const uint8_t>(bytes).subspan(4, size - 4); }
288
289 bool append(uint32_t key, uint32_t value)
290 {
291 const unsigned width = configurationValueBytes(key);
292 if (!valid || !width || (width < 4 && value >= (1u << (width * 8))) || ((key >> 28) == 1 && value > 1) ||
293 sizeof(key) + width > bytes.size() - size) {
294 valid = false;
295 return false;
296 }
297 (void) LittleEndian::write(bytes, size, key);
298 for (unsigned byte = 0; byte < width; ++byte) {
299 bytes[size + sizeof(key) + byte] = static_cast<uint8_t>(value >> (8 * byte));
300 }
301 size += sizeof(key) + width;
302 return true;
303 }
304};
305} // namespace UBX
Reads only key/value entries; VALSET and VALGET validate their different headers separately.
ConfigurationValueCursor(std::span< const uint8_t > entries)
std::optional< ConfigurationValue > next()
constexpr bool write(std::span< uint8_t > bytes, std::size_t offset, T value)
Encode an unaligned little-endian scalar. Insufficient space leaves the destination unchanged.
constexpr MsgOutKey MSGOUT_UBX_NAV_PVT
constexpr auto TMODE_LON_HP
constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1005
constexpr auto USBINPROT_SPARTN
constexpr auto USBOUTPROT_UBX
constexpr auto TMODE_SVIN_MIN_DUR
constexpr auto TMODE_FIXED_POS_ACC
constexpr MsgOutKey MSGOUT_UBX_RXM_SFRBX
constexpr auto ITFM_ENABLE
constexpr auto USBINPROT_NMEA
constexpr MsgOutKey MSGOUT_UBX_NAV_SVIN
constexpr auto ODO_OUTLPCOG
constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1097
constexpr auto TMODE_HEIGHT
constexpr auto UART1OUTPROT_NMEA
constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1094
constexpr auto USBINPROT_UBX
constexpr auto UART1_BAUDRATE
constexpr auto NAVSPG_UTCSTANDARD
constexpr auto TMODE_HEIGHT_HP
constexpr auto SEC_JAMDET_SENSITIVITY_HI
constexpr MsgOutKey MSGOUT_UBX_NAV_RELPOSNED
constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1087
constexpr auto RATE_NAV
constexpr MsgOutKey MSGOUT_UBX_RXM_RAWX
constexpr auto UART1_PARITY
constexpr auto TMODE_POS_TYPE
constexpr auto UART1_STOPBITS
constexpr auto TMODE_MODE
constexpr auto TMODE_SVIN_ACC_LIMIT
constexpr auto UART1INPROT_SPARTN
constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1084
constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1077
constexpr auto USBINPROT_RTCM3X
constexpr auto SIGNAL_HEALTH_L5
constexpr auto UART1OUTPROT_RTCM3X
constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1124
constexpr MsgOutKey MSGOUT_UBX_NAV_STATUS
constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1230
constexpr auto TMODE_LON
constexpr MsgOutKey MSGOUT_UBX_NAV_DOP
constexpr auto UART1INPROT_RTCM3X
constexpr auto NAVHPG_DGNSSMODE
constexpr auto USBOUTPROT_NMEA
constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1127
constexpr MsgOutKey MSGOUT_UBX_NAV_EOE
constexpr MsgOutKey MSGOUT_RTCM_3X_TYPE1074
constexpr auto NAVSPG_FIXMODE
constexpr auto UART1OUTPROT_UBX
constexpr MsgOutKey MSGOUT_UBX_MON_RF
constexpr auto ODO_USE_COG
constexpr auto NAVSPG_DYNMODEL
constexpr auto UART1INPROT_UBX
constexpr auto TMODE_LAT
constexpr auto UART1_DATABITS
constexpr auto UART1INPROT_NMEA
constexpr auto ODO_USE_ODO
constexpr auto TMODE_LAT_HP
constexpr MsgOutKey MSGOUT_UBX_NAV_TIMEGPS
constexpr auto USBOUTPROT_RTCM3X
constexpr MsgOutKey MSGOUT_UBX_NAV_SAT
constexpr auto RATE_TIMEREF
constexpr MsgOutKey MSGOUT_UBX_SEC_SIG
constexpr auto RATE_MEAS
constexpr MsgOutKey MSGOUT_UBX_NAV_HPPOSLLH
constexpr auto ODO_OUTLPVEL
u-blox receivers over UBX: CFG-VALSET configuration from protocol 27, CFG-MSG and CFG-TMODE3 before i...
std::optional< ConfigurationValues > decodeConfigurationValues(std::span< const uint8_t > payload)
Decodes a CFG-VALGET response (version 1, RAM layer) of at most ConfigurationValues::MAX_KEYS values.
consteval CfgKey< T > cfgKey()
Builds every key below, so each one checks its value type against the size bits of its id.
constexpr size_t cfgKeyValueBytes(uint32_t keyId)
Value size in bytes from bits 28-30 of a configuration key id, or 0 for a reserved size.
constexpr unsigned configurationValueBytes(uint32_t key)
Value width in bytes of key; 0 for reserved sizes and for 8-byte values, which QGC never reads or wri...
MsgOutPort
A port's CFG-MSGOUT key is the family's I2C key id plus the port's offset.
A configuration key whose value is written and read as T.
uint32_t id
std::span< const uint8_t > entries() const
The appended key/value entries, without the header.
bool append(uint32_t key, uint32_t value)
std::array< uint8_t, Capacity > bytes
std::span< const uint8_t > payload() const
bool operator==(const ConfigurationValue &) const =default
The values of one CFG-VALGET poll or response.
std::array< ConfigurationValue, MAX_KEYS > values
static constexpr size_t MAX_KEYS
One poll reads at most this many keys.
A CFG-MSGOUT output rate key family, named by its I2C key.
CfgKey< uint8_t > i2c
constexpr CfgKey< uint8_t > port(MsgOutPort port) const