SatCat5
log_cbor.cc
1 // Copyright 2023-2025 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <satcat5/datetime.h>
7 #include <satcat5/eth_dispatch.h>
8 #include <satcat5/log_cbor.h>
9 #include <satcat5/udp_dispatch.h>
10 
11 // Start of conditional compilation...
12 #if SATCAT5_CBOR_ENABLE
13 #include <qcbor/qcbor_decode.h>
14 #include <qcbor/qcbor_encode.h>
17 using satcat5::net::Type;
18 
19 // Set the size of the working buffer.
20 #ifndef SATCAT5_QCBOR_BUFFER
21 #define SATCAT5_QCBOR_BUFFER 1500
22 #endif
23 
24 FromCbor::FromCbor(
26  satcat5::net::Type filter)
27  : satcat5::net::Protocol(filter)
28  , m_src(src)
29 {
30  // Register our incoming message handler.
31  m_src->add(this);
32 }
33 
34 #if SATCAT5_ALLOW_DELETION
35 FromCbor::~FromCbor() {
36  // Unregister our incoming message handler.
37  m_src->remove(this);
38 }
39 #endif
40 
41 inline bool int_or_null(const QCBORItem& item) {
42  return item.uDataType == QCBOR_TYPE_NULL
43  || item.uDataType == QCBOR_TYPE_INT64;
44 }
45 
47  // Working buffer and QCBOR decoder state.
48  u8 buff[SATCAT5_QCBOR_BUFFER];
49  QCBORDecodeContext cbor;
50  QCBORItem item;
51  int errcode = 0;
52  s8 priority = 0;
53 
54  // Read the frame contents, discarding oversize messages.
55  unsigned plen = src.get_read_ready();
56  if (plen > SATCAT5_QCBOR_BUFFER) return;
57  if (!src.read_bytes(plen, buff)) return;
58 
59  // Open a QCBOR parser object.
60  QCBORDecode_Init(&cbor, {buff, plen}, QCBOR_DECODE_MODE_NORMAL);
61 
62  // First item should be the argument array.
63  // (Silently discard any messages that don't match expected format.)
64  errcode = QCBORDecode_GetNext(&cbor, &item);
65  if (errcode || item.uDataType != QCBOR_TYPE_ARRAY) return;
66 
67  // Within that context, read the message parameters...
68  // (Silently discard any messages that don't match expected format.)
69  errcode = QCBORDecode_GetNext(&cbor, &item); // Payload-ID
70  if (errcode || !int_or_null(item)) return;
71  errcode = QCBORDecode_GetNext(&cbor, &item); // GPS time-of-week
72  if (errcode || !int_or_null(item)) return;
73  errcode = QCBORDecode_GetNext(&cbor, &item); // Priority code
74  if (errcode || item.uDataType != QCBOR_TYPE_INT64) return;
75  errcode = QCBOR_Int64ToInt8(item.val.int64, &priority);
76  // Ignore messages with priority below minimum level.
77  if (errcode || priority < m_min_priority) return;
78  errcode = QCBORDecode_GetNext(&cbor, &item); // Message string
79  if (errcode || item.uDataType != QCBOR_TYPE_TEXT_STRING) return;
80 
81  // Success! Call the log_event handler.
82  log_event(priority, item.val.string.len, (const char*)item.val.string.ptr);
83 }
84 
85 void FromCbor::log_event(s8 priority, unsigned nbytes, const char* msg) {
86  // Built-in default handler creates a local log::Log message object.
87  satcat5::log::Log(priority, msg, nbytes);
88 }
89 
91  : m_dst(dst)
92 {
93  // Nothing else to initialize.
94 }
95 
96 void ToCbor::log_event(s8 priority, unsigned nbytes, const char* msg) {
97  // Ignore messages with priority below minimum level
98  if (priority < m_min_priority) return;
99 
100  // Allocate a fixed-size working buffer.
101  u8 buff[SATCAT5_QCBOR_BUFFER];
102 
103  // Construct the CBOR data structure.
104  QCBOREncodeContext cbor;
105  QCBOREncode_Init(&cbor, UsefulBuf_FROM_BYTE_ARRAY(buff));
106  QCBOREncode_OpenArray(&cbor);
107  QCBOREncode_AddNULL(&cbor); // Payload type
108  auto now = satcat5::datetime::clock.gps(); // Timestamp
109  QCBOREncode_AddInt64(&cbor, now.tow);
110  QCBOREncode_AddInt64(&cbor, priority); // Priority
111  QCBOREncode_AddText(&cbor, {msg, nbytes}); // Message
112  QCBOREncode_CloseArray(&cbor);
113 
114  // Generate the final encoded message.
115  UsefulBufC encoded;
116  QCBORError error = QCBOREncode_Finish(&cbor, &encoded);
117  if (error) return;
118 
119  // Write data to the network interface.
120  m_dst->write_packet(encoded.len, encoded.ptr);
121 }
122 
124  satcat5::eth::Dispatch* iface,
125  const satcat5::eth::MacType& typ)
126  : satcat5::log::FromCbor(iface, Type(typ.value))
127 {
128  // No other initialization required.
129 }
130 
133  const satcat5::eth::MacType& typ)
134  : satcat5::eth::AddressContainer(eth)
135  , satcat5::log::ToCbor(&m_addr)
136 {
137  // Default to broadcast mode.
138  connect(satcat5::eth::MACADDR_BROADCAST, typ);
139 }
140 
142  satcat5::udp::Dispatch* iface,
143  const satcat5::udp::Port& port)
144  : satcat5::log::FromCbor(iface, Type(port.value))
145 {
146  // No other initialization required.
147 }
148 
151  const satcat5::udp::Port& dstport)
152  : satcat5::udp::AddressContainer(udp)
153  , satcat5::log::ToCbor(&m_addr)
154 {
155  // Default to broadcast mode.
156  connect(satcat5::ip::ADDR_BROADCAST, dstport);
157 }
158 
159 #endif // SATCAT5_CBOR_ENABLE
satcat5::datetime::GpsTime gps() const
Current time as GPS week number and time-of-week.
Definition: datetime.h:195
Inheritable container for a eth::Address.
Definition: eth_address.h:60
Implemention of "net::Dispatch" for Ethernet frames.
Definition: eth_dispatch.h:21
LogFromCbor(satcat5::eth::Dispatch *iface, const satcat5::eth::MacType &typ)
Constructor binds to a specific interface and EtherType.
Definition: log_cbor.cc:123
void connect(const satcat5::eth::MacAddr &addr, const satcat5::eth::MacType &type)
Set the destination address.
Definition: log_cbor.h:128
LogToCbor(satcat5::eth::Dispatch *eth, const satcat5::eth::MacType &typ)
Constructor binds to a specific interface and EtherType.
Definition: log_cbor.cc:131
Limited read of next N bytes.
Definition: io_readable.h:255
bool read_bytes(unsigned nbytes, void *dst) override
Read 0 or more bytes into a buffer.
Definition: io_readable.cc:296
unsigned get_read_ready() const override
How many bytes can be read without blocking?
Definition: io_readable.cc:293
Read CBOR-formatted network messages and copy to the local log.
Definition: log_cbor.h:41
virtual void log_event(s8 priority, unsigned nbytes, const char *msg)
Event handler for validated messages.
Definition: log_cbor.cc:85
satcat5::net::Dispatch *const m_src
Pointer to the interface object.
Definition: log_cbor.h:61
void frame_rcvd(satcat5::io::LimitedRead &src) override
Event handler for incoming messages.
Definition: log_cbor.cc:46
The Log class creates and formats one log message.
Definition: log.h:195
Write local logs to a CBOR-formatted network message.
Definition: log_cbor.h:80
ToCbor(satcat5::net::Address *dst)
Only children can safely access constructor/destructor.
Definition: log_cbor.cc:90
void log_event(s8 priority, unsigned nbytes, const char *msg) override
Callback for each formatted Log message.
Definition: log_cbor.cc:96
Defines a generic API for sending data to a specific destination, such as a MAC address,...
Definition: net_address.h:30
bool write_packet(unsigned nbytes, const void *data)
All-in-one call that writes an entire packet.
Definition: net_address.cc:11
The "Dispatch" is a generic interface that knows how to read a designated protocol layer and sort inc...
Definition: net_dispatch.h:36
void add(satcat5::net::Protocol *proto)
Register a Protocol object.
Definition: net_dispatch.h:55
void remove(satcat5::net::Protocol *proto)
Unregister a Protocol object.
Definition: net_dispatch.h:59
Inheritable container for a udp::Address.
Definition: udp_core.h:149
Dispatcher sorts incoming UDP messages by port index.
Definition: udp_dispatch.h:20
LogFromCbor(satcat5::udp::Dispatch *iface, const satcat5::udp::Port &port)
Constructor binds to a specific incoming UDP port.
Definition: log_cbor.cc:141
void connect(const satcat5::udp::Addr &dstaddr, const satcat5::udp::Port &dstport)
Set the destination address.
Definition: log_cbor.h:167
LogToCbor(satcat5::udp::Dispatch *udp, const satcat5::udp::Port &dstport)
Constructor binds to a specific interface and port number.
Definition: log_cbor.cc:149
Real-time clock conversion functions.
#define SATCAT5_QCBOR_BUFFER
Set the default size for the QCBOR buffer.
Definition: io_cbor.h:52
CBOR-encoded network logging.
EtherType field (uint16) is used a protocol-ID [1536..65535].
Definition: eth_header.h:96
UDP and TCP ports are both 16-bit unsigned integers.
Definition: ip_core.h:119
Multipurpose filter for matching fields in network packets.
Definition: net_type.h:38