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