klv is a header-only C++23 library that decodes and encodes KLV (SMPTE 336) metadata. It includes definitions for MISB ST 0601 (UAS Datalink Local Set) and these other MISB standards:
- ST 0102 (Security Local Set and Universal Set)
- ST 0602 (Annotation Metadata Set)
- ST 0603 (MISP Time System and Timestamps)
- ST 0806 (Remote Video Terminal)
- ST 0809 (Meteorological Metadata)
- ST 0902 (Motion Imagery Sensor Minimum Metadata Set)
- ST 0903 (VMTI)
- ST 1002 (Range Image)
- ST 1107 (Metric Geopositioning)
- ST 1108 (Interpretability and Quality)
- ST 1204 (MIIS Core Identifier)
- ST 1206 (SAR Motion Imagery)
- ST 1301 (MIIS Augmentation Identifiers)
- ST 1403 (SARMI Threshold Metadata Sets)
- ST 1504 (Natural Representation of Orbital State Vectors)
- ST 1507 (Motion Imagery Sensor Timing)
- ST 1601 (Geo-Registration)
- ST 1602 (Composite Imaging)
- ST 1603 (Time Transfer Metadata)
- ST 1607 (Segment and Amend)
#include <klv/klv.hpp>
namespace kv = klv::misb0601;
void handle(std::span<std::byte const> bytes) {
for (auto const& packet : klv::decode_packets<kv::uas_datalink_ls>(bytes)) {
if (!packet) {
// packet.error().message, packet.error().offset
continue;
}
auto const* uas = std::get_if<klv::record<kv::uas_datalink_ls>>(&*packet);
if (!uas) {
continue;
}
// get<E>() returns std::expected<T, klv::field_error>
if (auto const& latitude = uas->get<kv::sensor_latitude>()) {
use(*latitude);
}
}
}decode_packets splits a buffer into packets, checks the universal key and the
checksum, and continues at the next universal label after a malformed packet. A
field can have no value. Its field_error gives the reason, for example
absent, empty (length of zero), error_indicator, or bad_length.
decode_packets also accepts universal sets, such as the ST 0102 Security
Universal Set, and standalone items, such as
misb0603::precision_time_stamp_item.
A set can hold some fields more than once, for example the ST 0601 Segment
Local Set. Such a field has a list value with one item for each occurrence, and
record::add appends an item.
The ST 0601 Segment and Amend Local Sets (ST 1607) hold records of the ST 0601
set, so a child set can hold other child sets. misb1607::merge applies a
child set to its parent. An empty field in an Amend Local Set clears the parent
value. A child field that does not decode keeps the parent value. The merged
set holds the child sets of the child, not those of the parent. A set more than klv::max_nesting_depth (16) levels deep does not
decode.
auto uas = klv::record<kv::uas_datalink_ls>{};
uas.set<kv::precision_time_stamp>(timestamp);
uas.set<kv::mission_id>("Mission 12");
uas.set<kv::sensor_latitude>(60.1768);
auto const bytes = klv::encode_packet(uas); // result<byte_vector>The encoder writes the fields in definition order and adds the checksum as the last field. Each set uses the checksum of its standard. ST 0601 and ST 0903 use a 16-bit sum, ST 1002, ST 1107, ST 1108, ST 1504, and ST 1507 use CRC-16-CCITT, and ST 0806 uses CRC-32/MPEG-2. ST 0102, ST 0602, ST 0809, and ST 1301 have no checksum.
A set inside another set has no checksum, as ST 0903.6 and ST 1002.3 require. The checksum of the parent packet covers the nested bytes. The decoder keeps a nested checksum value that a producer sends anyway, but does not verify it.
All metadata is static. Each field is a struct with a tag or a key, a name, optional units, and a constexpr codec object. Each set is a list of fields. The compiler builds the dispatch table and a typed record for each set, and rejects duplicate tags or keys and access to a field that is not in the set.
struct platform_heading_angle {
static constexpr uint32_t tag = 5;
static constexpr std::string_view name = "Platform Heading Angle";
static constexpr std::string_view units = "deg";
static constexpr klv::codec::mapped<uint16_t> format{0.0, 360.0};
};
struct my_set {
static constexpr std::string_view name = "My Set";
static constexpr klv::universal_key key = klv::ul("06 0E 2B 34 ...");
using fields = klv::field_list<platform_heading_angle /* , ... */>;
};A set with a checksum names its checksum_field. It can also name a
checksum_function, for example klv::crc32_mpeg2. Without it, the set uses
the ST 0601 16-bit sum.
The built-in base codecs are:
integerber_oidmappedimapb(MISB ST 1201)imapb_value(MISB ST 1201, with the byte length in the value)stringutf16_string(UTF-16 text, RFC 2781)timestampnano_timestampieee754ieee754_variableenumerationbytesuuidnested(a local set inside a field)repeated(a field that a set can hold more than once)series(length-prefixed elements)ber_oid_listmdarray(MISB ST 1303)sdcc_flp(MISB ST 1010)
A new value format is one new codec type. Each codec has its own header in
include/klv/codecs/. The MISB definitions are in
dedicated folders, such as include/klv/misb0601/.
See the BUILDING document.
See the CONTRIBUTING document.