WPILibC++ 2027.0.0-alpha-5
Loading...
Searching...
No Matches
ProtobufTopic.hpp
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <stdint.h>
8
9#include <atomic>
10#include <span>
11#include <utility>
12#include <vector>
13
15#include "wpi/nt/Topic.hpp"
16#include "wpi/nt/ntcore_cpp.hpp"
17#include "wpi/util/SmallVector.hpp"
18#include "wpi/util/mutex.hpp"
20
21namespace wpi::util {
22class json;
23} // namespace wpi::util
24
25namespace wpi::nt {
26
27template <wpi::util::ProtobufSerializable T>
28class ProtobufTopic;
29
30/**
31 * NetworkTables protobuf-encoded value subscriber.
32 */
33template <wpi::util::ProtobufSerializable T>
35 public:
37 using ValueType = T;
38 using ParamType = const T&;
40
41 ProtobufSubscriber() = default;
42
43 /**
44 * Construct from a subscriber handle; recommended to use
45 * ProtobufTopic::Subscribe() instead.
46 *
47 * @param handle Native handle
48 * @param msg Protobuf message
49 * @param defaultValue Default value
50 */
52 T defaultValue)
53 : Subscriber{handle},
54 m_msg{std::move(msg)},
55 m_defaultValue{std::move(defaultValue)} {}
56
59
61 : Subscriber{std::move(rhs)},
62 m_msg{std::move(rhs.m_msg)},
63 m_defaultValue{std::move(rhs.m_defaultValue)} {}
64
66 Subscriber::operator=(std::move(rhs));
67 m_msg = std::move(rhs.m_msg);
68 m_defaultValue = std::move(rhs.m_defaultValue);
69 return *this;
70 }
71
72 /**
73 * Get the last published value.
74 * If no value has been published or the value cannot be unpacked, returns the
75 * stored default value.
76 *
77 * @return value
78 */
79 ValueType Get() const { return Get(m_defaultValue); }
80
81 /**
82 * Get the last published value.
83 * If no value has been published or the value cannot be unpacked, returns the
84 * passed defaultValue.
85 *
86 * @param defaultValue default value to return if no value has been published
87 * @return value
88 */
89 ValueType Get(const T& defaultValue) const {
90 return GetAtomic(defaultValue).value;
91 }
92
93 /**
94 * Get the last published value, replacing the contents in place of an
95 * existing object. If no value has been published or the value cannot be
96 * unpacked, does not replace the contents and returns false.
97 *
98 * @param[out] out object to replace contents of
99 * @return true if successful
100 */
101 bool GetInto(T* out) {
102 wpi::util::SmallVector<uint8_t, 128> buf;
104 if (view.value.empty()) {
105 return false;
106 } else {
107 std::scoped_lock lock{m_mutex};
108 return m_msg.UnpackInto(out, view.value);
109 }
110 }
111
112 /**
113 * Get the last published value along with its timestamp
114 * If no value has been published or the value cannot be unpacked, returns the
115 * stored default value and a timestamp of 0.
116 *
117 * @return timestamped value
118 */
119 TimestampedValueType GetAtomic() const { return GetAtomic(m_defaultValue); }
120
121 /**
122 * Get the last published value along with its timestamp.
123 * If no value has been published or the value cannot be unpacked, returns the
124 * passed defaultValue and a timestamp of 0.
125 *
126 * @param defaultValue default value to return if no value has been published
127 * @return timestamped value
128 */
129 TimestampedValueType GetAtomic(const T& defaultValue) const {
130 wpi::util::SmallVector<uint8_t, 128> buf;
132 if (!view.value.empty()) {
133 std::scoped_lock lock{m_mutex};
134 if (auto optval = m_msg.Unpack(view.value)) {
135 return {view.time, view.serverTime, *optval};
136 }
137 }
138 return {0, 0, defaultValue};
139 }
140
141 /**
142 * Get an array of all valid value changes since the last call to ReadQueue.
143 * Also provides a timestamp for each value. Values that cannot be unpacked
144 * are dropped.
145 *
146 * @note The "poll storage" subscribe option can be used to set the queue
147 * depth.
148 *
149 * @return Array of timestamped values; empty array if no valid new changes
150 * have been published since the previous call.
151 */
152 std::vector<TimestampedValueType> ReadQueue() {
154 std::vector<TimestampedValueType> rv;
155 rv.reserve(raw.size());
156 std::scoped_lock lock{m_mutex};
157 for (auto&& r : raw) {
158 if (auto optval = m_msg.Unpack(r.value)) {
159 rv.emplace_back(r.time, r.serverTime, *optval);
160 }
161 }
162 return rv;
163 }
164
165 /**
166 * Get the corresponding topic.
167 *
168 * @return Topic
169 */
173
174 private:
175 mutable wpi::util::mutex m_mutex;
176 mutable wpi::util::ProtobufMessage<T> m_msg;
177 ValueType m_defaultValue;
178};
179
180/**
181 * NetworkTables protobuf-encoded value publisher.
182 */
183template <wpi::util::ProtobufSerializable T>
185 public:
187 using ValueType = T;
188 using ParamType = const T&;
189
191
192 ProtobufPublisher() = default;
193
194 /**
195 * Construct from a publisher handle; recommended to use
196 * ProtobufTopic::Publish() instead.
197 *
198 * @param handle Native handle
199 * @param msg Protobuf message
200 */
203 : Publisher{handle}, m_msg{std::move(msg)} {}
204
207
209 : Publisher{std::move(rhs)},
210 m_msg{std::move(rhs.m_msg)},
211 m_schemaPublished{rhs.m_schemaPublished.load()} {}
212
214 Publisher::operator=(std::move(rhs));
215 m_msg = std::move(rhs.m_msg);
216 m_schemaPublished.store(
217 rhs.m_schemaPublished.load(std::memory_order_relaxed),
218 std::memory_order_relaxed);
219 return *this;
220 }
221
222 /**
223 * Publish a new value.
224 *
225 * @param value value to publish
226 * @param time timestamp; 0 indicates current NT time should be used
227 */
228 void Set(const T& value, int64_t time = 0) {
229 wpi::util::SmallVector<uint8_t, 128> buf;
230 {
231 std::scoped_lock lock{m_mutex};
232 if (!m_schemaPublished.exchange(true, std::memory_order_relaxed)) {
233 GetTopic().GetInstance().template AddProtobufSchema<T>(m_msg);
234 }
235 m_msg.Pack(buf, value);
236 }
237 ::wpi::nt::SetRaw(m_pubHandle, buf, time);
238 }
239
240 /**
241 * Publish a default value.
242 * On reconnect, a default value will never be used in preference to a
243 * published value.
244 *
245 * @param value value
246 */
247 void SetDefault(const T& value) {
248 wpi::util::SmallVector<uint8_t, 128> buf;
249 {
250 std::scoped_lock lock{m_mutex};
251 if (!m_schemaPublished.exchange(true, std::memory_order_relaxed)) {
252 GetTopic().GetInstance().template AddProtobufSchema<T>(m_msg);
253 }
254 m_msg.Pack(buf, value);
255 }
257 }
258
259 /**
260 * Get the corresponding topic.
261 *
262 * @return Topic
263 */
267
268 private:
269 wpi::util::mutex m_mutex;
271 std::atomic_bool m_schemaPublished{false};
272};
273
274/**
275 * NetworkTables protobuf-encoded value entry.
276 *
277 * @note Unlike NetworkTableEntry, the entry goes away when this is destroyed.
278 */
279template <wpi::util::ProtobufSerializable T>
280class ProtobufEntry final : public ProtobufSubscriber<T>,
281 public ProtobufPublisher<T> {
282 public:
286 using ValueType = T;
287 using ParamType = const T&;
288
290
291 ProtobufEntry() = default;
292
293 /**
294 * Construct from an entry handle; recommended to use
295 * ProtobufTopic::GetEntry() instead.
296 *
297 * @param handle Native handle
298 * @param msg Protobuf message
299 * @param defaultValue Default value
300 */
302 T defaultValue)
303 : ProtobufSubscriber<T>{handle, std::move(msg), std::move(defaultValue)},
305
306 /**
307 * Determines if the native handle is valid.
308 *
309 * @return True if the native handle is valid, false otherwise.
310 */
311 explicit operator bool() const { return this->m_subHandle != 0; }
312
313 /**
314 * Gets the native handle for the entry.
315 *
316 * @return Native handle
317 */
318 NT_Entry GetHandle() const { return this->m_subHandle; }
319
320 /**
321 * Get the corresponding topic.
322 *
323 * @return Topic
324 */
328
329 /**
330 * Stops publishing the entry if it's published.
331 */
333};
334
335/**
336 * NetworkTables protobuf-encoded value topic.
337 */
338template <wpi::util::ProtobufSerializable T>
339class ProtobufTopic final : public Topic {
340 public:
344 using ValueType = T;
345 using ParamType = const T&;
347
348 ProtobufTopic() = default;
349
350 /**
351 * Construct from a topic handle; recommended to use
352 * NetworkTableInstance::GetProtobufTopic() instead.
353 *
354 * @param handle Native handle
355 */
356 explicit ProtobufTopic(NT_Topic handle) : Topic{handle} {}
357
358 /**
359 * Construct from a generic topic.
360 *
361 * @param topic Topic
362 */
363 explicit ProtobufTopic(Topic topic) : Topic{topic} {}
364
365 /**
366 * Create a new subscriber to the topic.
367 *
368 * <p>The subscriber is only active as long as the returned object
369 * is not destroyed.
370 *
371 * @note Subscribers that do not match the published data type do not return
372 * any values. To determine if the data type matches, use the appropriate
373 * Topic functions.
374 *
375 * @param defaultValue default value used when a default is not provided to a
376 * getter function
377 * @param options subscribe options
378 * @return subscriber
379 */
380 [[nodiscard]]
382 T defaultValue, const PubSubOptions& options = DEFAULT_PUB_SUB_OPTIONS) {
384 auto typeString = msg.GetTypeString();
386 ::wpi::nt::Subscribe(m_handle, NT_RAW, typeString, options),
387 std::move(msg), std::move(defaultValue)};
388 }
389
390 /**
391 * Create a new publisher to the topic.
392 *
393 * The publisher is only active as long as the returned object
394 * is not destroyed.
395 *
396 * @note It is not possible to publish two different data types to the same
397 * topic. Conflicts between publishers are typically resolved by the
398 * server on a first-come, first-served basis. Any published values that
399 * do not match the topic's data type are dropped (ignored). To determine
400 * if the data type matches, use the appropriate Topic functions.
401 *
402 * @param options publish options
403 * @return publisher
404 */
405 [[nodiscard]]
407 const PubSubOptions& options = DEFAULT_PUB_SUB_OPTIONS) {
409 auto typeString = msg.GetTypeString();
411 ::wpi::nt::Publish(m_handle, NT_RAW, typeString, options),
412 std::move(msg)};
413 }
414
415 /**
416 * Create a new publisher to the topic, with type string and initial
417 * properties.
418 *
419 * The publisher is only active as long as the returned object
420 * is not destroyed.
421 *
422 * @note It is not possible to publish two different data types to the same
423 * topic. Conflicts between publishers are typically resolved by the
424 * server on a first-come, first-served basis. Any published values that
425 * do not match the topic's data type are dropped (ignored). To determine
426 * if the data type matches, use the appropriate Topic functions.
427 *
428 * @param properties JSON properties
429 * @param options publish options
430 * @return publisher
431 */
432 [[nodiscard]]
434 const wpi::util::json& properties,
435 const PubSubOptions& options = DEFAULT_PUB_SUB_OPTIONS) {
437 auto typeString = msg.GetTypeString();
439 ::wpi::nt::PublishEx(m_handle, NT_RAW, typeString, properties, options),
440 std::move(msg)};
441 }
442
443 /**
444 * Create a new entry for the topic.
445 *
446 * Entries act as a combination of a subscriber and a weak publisher. The
447 * subscriber is active as long as the entry is not destroyed. The publisher
448 * is created when the entry is first written to, and remains active until
449 * either Unpublish() is called or the entry is destroyed.
450 *
451 * @note It is not possible to use two different data types with the same
452 * topic. Conflicts between publishers are typically resolved by the
453 * server on a first-come, first-served basis. Any published values that
454 * do not match the topic's data type are dropped (ignored), and the entry
455 * will show no new values if the data type does not match. To determine
456 * if the data type matches, use the appropriate Topic functions.
457 *
458 * @param defaultValue default value used when a default is not provided to a
459 * getter function
460 * @param options publish and/or subscribe options
461 * @return entry
462 */
463 [[nodiscard]]
464 EntryType GetEntry(T defaultValue,
465 const PubSubOptions& options = DEFAULT_PUB_SUB_OPTIONS) {
467 auto typeString = msg.GetTypeString();
468 return ProtobufEntry<T>{
469 ::wpi::nt::GetEntry(m_handle, NT_RAW, typeString, options),
470 std::move(msg), std::move(defaultValue)};
471 }
472};
473
474} // namespace wpi::nt
NetworkTables protobuf-encoded value entry.
Definition ProtobufTopic.hpp:281
const T & ParamType
Definition ProtobufTopic.hpp:287
ProtobufPublisher< T > PublisherType
Definition ProtobufTopic.hpp:284
ProtobufEntry()=default
void Unpublish()
Stops publishing the entry if it's published.
Definition ProtobufTopic.hpp:332
NT_Entry GetHandle() const
Gets the native handle for the entry.
Definition ProtobufTopic.hpp:318
TopicType GetTopic() const
Get the corresponding topic.
Definition ProtobufTopic.hpp:325
Timestamped< T > TimestampedValueType
Definition ProtobufTopic.hpp:289
ProtobufEntry(NT_Entry handle, wpi::util::ProtobufMessage< T > msg, T defaultValue)
Construct from an entry handle; recommended to use ProtobufTopic::GetEntry() instead.
Definition ProtobufTopic.hpp:301
T ValueType
Definition ProtobufTopic.hpp:286
ProtobufTopic< T > TopicType
Definition ProtobufTopic.hpp:285
ProtobufSubscriber< T > SubscriberType
Definition ProtobufTopic.hpp:283
NetworkTables protobuf-encoded value publisher.
Definition ProtobufTopic.hpp:184
const T & ParamType
Definition ProtobufTopic.hpp:188
ProtobufPublisher(const ProtobufPublisher &)=delete
ProtobufPublisher(ProtobufPublisher &&rhs)
Definition ProtobufTopic.hpp:208
Timestamped< T > TimestampedValueType
Definition ProtobufTopic.hpp:190
ProtobufPublisher & operator=(const ProtobufPublisher &)=delete
ProtobufTopic< T > TopicType
Definition ProtobufTopic.hpp:186
T ValueType
Definition ProtobufTopic.hpp:187
void Set(const T &value, int64_t time=0)
Publish a new value.
Definition ProtobufTopic.hpp:228
void SetDefault(const T &value)
Publish a default value.
Definition ProtobufTopic.hpp:247
ProtobufPublisher(NT_Publisher handle, wpi::util::ProtobufMessage< T > msg)
Construct from a publisher handle; recommended to use ProtobufTopic::Publish() instead.
Definition ProtobufTopic.hpp:201
TopicType GetTopic() const
Get the corresponding topic.
Definition ProtobufTopic.hpp:264
ProtobufPublisher & operator=(ProtobufPublisher &&rhs)
Definition ProtobufTopic.hpp:213
NetworkTables protobuf-encoded value subscriber.
Definition ProtobufTopic.hpp:34
ProtobufSubscriber & operator=(const ProtobufSubscriber &)=delete
ValueType Get(const T &defaultValue) const
Get the last published value.
Definition ProtobufTopic.hpp:89
bool GetInto(T *out)
Get the last published value, replacing the contents in place of an existing object.
Definition ProtobufTopic.hpp:101
const T & ParamType
Definition ProtobufTopic.hpp:38
std::vector< TimestampedValueType > ReadQueue()
Get an array of all valid value changes since the last call to ReadQueue.
Definition ProtobufTopic.hpp:152
ProtobufSubscriber(const ProtobufSubscriber &)=delete
ProtobufTopic< T > TopicType
Definition ProtobufTopic.hpp:36
TimestampedValueType GetAtomic() const
Get the last published value along with its timestamp If no value has been published or the value can...
Definition ProtobufTopic.hpp:119
Timestamped< T > TimestampedValueType
Definition ProtobufTopic.hpp:39
T ValueType
Definition ProtobufTopic.hpp:37
TimestampedValueType GetAtomic(const T &defaultValue) const
Get the last published value along with its timestamp.
Definition ProtobufTopic.hpp:129
ProtobufSubscriber & operator=(ProtobufSubscriber &&rhs)
Definition ProtobufTopic.hpp:65
ProtobufSubscriber(ProtobufSubscriber &&rhs)
Definition ProtobufTopic.hpp:60
ProtobufSubscriber(NT_Subscriber handle, wpi::util::ProtobufMessage< T > msg, T defaultValue)
Construct from a subscriber handle; recommended to use ProtobufTopic::Subscribe() instead.
Definition ProtobufTopic.hpp:51
TopicType GetTopic() const
Get the corresponding topic.
Definition ProtobufTopic.hpp:170
ValueType Get() const
Get the last published value.
Definition ProtobufTopic.hpp:79
NetworkTables protobuf-encoded value topic.
Definition ProtobufTopic.hpp:339
ProtobufEntry< T > EntryType
Definition ProtobufTopic.hpp:343
PublisherType PublishEx(const wpi::util::json &properties, const PubSubOptions &options=DEFAULT_PUB_SUB_OPTIONS)
Create a new publisher to the topic, with type string and initial properties.
Definition ProtobufTopic.hpp:433
SubscriberType Subscribe(T defaultValue, const PubSubOptions &options=DEFAULT_PUB_SUB_OPTIONS)
Create a new subscriber to the topic.
Definition ProtobufTopic.hpp:381
const T & ParamType
Definition ProtobufTopic.hpp:345
PublisherType Publish(const PubSubOptions &options=DEFAULT_PUB_SUB_OPTIONS)
Create a new publisher to the topic.
Definition ProtobufTopic.hpp:406
ProtobufTopic(Topic topic)
Construct from a generic topic.
Definition ProtobufTopic.hpp:363
ProtobufTopic(NT_Topic handle)
Construct from a topic handle; recommended to use NetworkTableInstance::GetProtobufTopic() instead.
Definition ProtobufTopic.hpp:356
EntryType GetEntry(T defaultValue, const PubSubOptions &options=DEFAULT_PUB_SUB_OPTIONS)
Create a new entry for the topic.
Definition ProtobufTopic.hpp:464
T ValueType
Definition ProtobufTopic.hpp:344
ProtobufSubscriber< T > SubscriberType
Definition ProtobufTopic.hpp:341
Timestamped< T > TimestampedValueType
Definition ProtobufTopic.hpp:346
ProtobufPublisher< T > PublisherType
Definition ProtobufTopic.hpp:342
Publisher(const Publisher &)=delete
Publisher & operator=(const Publisher &)=delete
NT_Publisher m_pubHandle
NetworkTables handle.
Definition Topic.hpp:443
Subscriber(const Subscriber &)=delete
NT_Subscriber m_subHandle
Definition Topic.hpp:388
Subscriber & operator=(const Subscriber &)=delete
NT_Topic m_handle
Definition Topic.hpp:319
NetworkTableInstance GetInstance() const
Gets the instance for the topic.
Topic()=default
Ease of use wrapper to make nanopb streams more opaque to the user.
Definition Protobuf.hpp:309
std::string GetTypeString() const
Gets the type string for the message.
Definition Protobuf.hpp:372
Definition json.hpp:85
bool SetRaw(NT_Handle pubentry, std::span< const uint8_t > value, int64_t time=0)
Publish a new value.
std::vector< TimestampedRaw > ReadQueueRaw(NT_Handle subentry)
Get an array of all value changes since the last call to ReadQueue.
TimestampedRaw GetAtomicRaw(NT_Handle subentry, std::span< const uint8_t > defaultValue)
Get the last published value along with its timestamp.
bool SetDefaultRaw(NT_Handle pubentry, std::span< const uint8_t > defaultValue)
Publish a default value.
NT_Handle NT_Topic
Definition ntcore_c.h:42
NT_Handle NT_Subscriber
Definition ntcore_c.h:43
NT_Handle NT_Publisher
Definition ntcore_c.h:44
NT_Handle NT_Entry
Definition ntcore_c.h:37
@ NT_RAW
Definition ntcore_c.h:55
Timestamped< std::span< uint8_t > > TimestampedRawView
Timestamped Raw view (for wpi::util::SmallVector-taking functions).
Definition ntcore_cpp_types.hpp:469
constexpr PubSubOptions DEFAULT_PUB_SUB_OPTIONS
Default publish/subscribe options.
Definition ntcore_cpp.hpp:388
NT_Entry GetEntry(NT_Inst inst, std::string_view name)
Get Entry Handle.
NT_Topic GetTopicFromHandle(NT_Handle pubsubentry)
Gets the topic handle from an entry/subscriber/publisher handle.
NT_Subscriber Subscribe(NT_Topic topic, NT_Type type, std::string_view typeStr, const PubSubOptions &options=DEFAULT_PUB_SUB_OPTIONS)
Creates a new subscriber to value changes on a topic.
void Unpublish(NT_Handle pubentry)
Stops publisher.
NT_Publisher PublishEx(NT_Topic topic, NT_Type type, std::string_view typeStr, const wpi::util::json &properties, const PubSubOptions &options=DEFAULT_PUB_SUB_OPTIONS)
Creates a new publisher to a topic.
NT_Publisher Publish(NT_Topic topic, NT_Type type, std::string_view typeStr, const PubSubOptions &options=DEFAULT_PUB_SUB_OPTIONS)
Creates a new publisher to a topic.
Definition StringMap.hpp:773
NetworkTables (ntcore) namespace.
Definition NTSendable.hpp:9
Definition raw_os_ostream.hpp:19
::std::mutex mutex
Definition mutex.hpp:17
NetworkTables publish/subscribe options.
Definition ntcore_cpp.hpp:303
Timestamped value.
Definition ntcore_cpp_types.hpp:30
int64_t serverTime
Time in server time base.
Definition ntcore_cpp_types.hpp:43
T value
Value.
Definition ntcore_cpp_types.hpp:48
int64_t time
Time in local time base.
Definition ntcore_cpp_types.hpp:38