WPILibC++ 2027.0.0-alpha-3
Loading...
Searching...
No Matches
ProtobufTopic.h
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
14#include <wpi/SmallVector.h>
15#include <wpi/json_fwd.h>
16#include <wpi/mutex.h>
18
20#include "networktables/Topic.h"
21#include "ntcore_cpp.h"
22
23namespace nt {
24
25template <wpi::ProtobufSerializable T>
26class ProtobufTopic;
27
28/**
29 * NetworkTables protobuf-encoded value subscriber.
30 */
31template <wpi::ProtobufSerializable T>
33 public:
35 using ValueType = T;
36 using ParamType = const T&;
38
39 ProtobufSubscriber() = default;
40
41 /**
42 * Construct from a subscriber handle; recommended to use
43 * ProtobufTopic::Subscribe() instead.
44 *
45 * @param handle Native handle
46 * @param msg Protobuf message
47 * @param defaultValue Default value
48 */
50 T defaultValue)
51 : Subscriber{handle},
52 m_msg{std::move(msg)},
53 m_defaultValue{std::move(defaultValue)} {}
54
57
59 : Subscriber{std::move(rhs)},
60 m_msg{std::move(rhs.m_msg)},
61 m_defaultValue{std::move(rhs.m_defaultValue)} {}
62
64 Subscriber::operator=(std::move(rhs));
65 m_msg = std::move(rhs.m_msg);
66 m_defaultValue = std::move(rhs.m_defaultValue);
67 return *this;
68 }
69
70 /**
71 * Get the last published value.
72 * If no value has been published or the value cannot be unpacked, returns the
73 * stored default value.
74 *
75 * @return value
76 */
77 ValueType Get() const { return Get(m_defaultValue); }
78
79 /**
80 * Get the last published value.
81 * If no value has been published or the value cannot be unpacked, returns the
82 * passed defaultValue.
83 *
84 * @param defaultValue default value to return if no value has been published
85 * @return value
86 */
87 ValueType Get(const T& defaultValue) const {
88 return GetAtomic(defaultValue).value;
89 }
90
91 /**
92 * Get the last published value, replacing the contents in place of an
93 * existing object. If no value has been published or the value cannot be
94 * unpacked, does not replace the contents and returns false.
95 *
96 * @param[out] out object to replace contents of
97 * @return true if successful
98 */
99 bool GetInto(T* out) {
100 wpi::SmallVector<uint8_t, 128> buf;
102 if (view.value.empty()) {
103 return false;
104 } else {
105 std::scoped_lock lock{m_mutex};
106 return m_msg.UnpackInto(out, view.value);
107 }
108 }
109
110 /**
111 * Get the last published value along with its timestamp
112 * If no value has been published or the value cannot be unpacked, returns the
113 * stored default value and a timestamp of 0.
114 *
115 * @return timestamped value
116 */
117 TimestampedValueType GetAtomic() const { return GetAtomic(m_defaultValue); }
118
119 /**
120 * Get the last published value along with its timestamp.
121 * If no value has been published or the value cannot be unpacked, returns the
122 * passed defaultValue and a timestamp of 0.
123 *
124 * @param defaultValue default value to return if no value has been published
125 * @return timestamped value
126 */
127 TimestampedValueType GetAtomic(const T& defaultValue) const {
128 wpi::SmallVector<uint8_t, 128> buf;
130 if (!view.value.empty()) {
131 std::scoped_lock lock{m_mutex};
132 if (auto optval = m_msg.Unpack(view.value)) {
133 return {view.time, view.serverTime, *optval};
134 }
135 }
136 return {0, 0, defaultValue};
137 }
138
139 /**
140 * Get an array of all valid value changes since the last call to ReadQueue.
141 * Also provides a timestamp for each value. Values that cannot be unpacked
142 * are dropped.
143 *
144 * @note The "poll storage" subscribe option can be used to set the queue
145 * depth.
146 *
147 * @return Array of timestamped values; empty array if no valid new changes
148 * have been published since the previous call.
149 */
150 std::vector<TimestampedValueType> ReadQueue() {
152 std::vector<TimestampedValueType> rv;
153 rv.reserve(raw.size());
154 std::scoped_lock lock{m_mutex};
155 for (auto&& r : raw) {
156 if (auto optval = m_msg.Unpack(r.value)) {
157 rv.emplace_back(r.time, r.serverTime, *optval);
158 }
159 }
160 return rv;
161 }
162
163 /**
164 * Get the corresponding topic.
165 *
166 * @return Topic
167 */
171
172 private:
173 mutable wpi::mutex m_mutex;
174 mutable wpi::ProtobufMessage<T> m_msg;
175 ValueType m_defaultValue;
176};
177
178/**
179 * NetworkTables protobuf-encoded value publisher.
180 */
181template <wpi::ProtobufSerializable T>
183 public:
185 using ValueType = T;
186 using ParamType = const T&;
187
189
190 ProtobufPublisher() = default;
191
192 /**
193 * Construct from a publisher handle; recommended to use
194 * ProtobufTopic::Publish() instead.
195 *
196 * @param handle Native handle
197 * @param msg Protobuf message
198 */
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::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 ::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::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::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::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 */
298 ProtobufEntry(NT_Entry handle, wpi::ProtobufMessage<T> msg, T defaultValue)
299 : ProtobufSubscriber<T>{handle, std::move(msg), std::move(defaultValue)},
301
302 /**
303 * Determines if the native handle is valid.
304 *
305 * @return True if the native handle is valid, false otherwise.
306 */
307 explicit operator bool() const { return this->m_subHandle != 0; }
308
309 /**
310 * Gets the native handle for the entry.
311 *
312 * @return Native handle
313 */
314 NT_Entry GetHandle() const { return this->m_subHandle; }
315
316 /**
317 * Get the corresponding topic.
318 *
319 * @return Topic
320 */
324
325 /**
326 * Stops publishing the entry if it's published.
327 */
329};
330
331/**
332 * NetworkTables protobuf-encoded value topic.
333 */
334template <wpi::ProtobufSerializable T>
335class ProtobufTopic final : public Topic {
336 public:
340 using ValueType = T;
341 using ParamType = const T&;
343
344 ProtobufTopic() = default;
345
346 /**
347 * Construct from a topic handle; recommended to use
348 * NetworkTableInstance::GetProtobufTopic() instead.
349 *
350 * @param handle Native handle
351 */
352 explicit ProtobufTopic(NT_Topic handle) : Topic{handle} {}
353
354 /**
355 * Construct from a generic topic.
356 *
357 * @param topic Topic
358 */
359 explicit ProtobufTopic(Topic topic) : Topic{topic} {}
360
361 /**
362 * Create a new subscriber to the topic.
363 *
364 * <p>The subscriber is only active as long as the returned object
365 * is not destroyed.
366 *
367 * @note Subscribers that do not match the published data type do not return
368 * any values. To determine if the data type matches, use the appropriate
369 * Topic functions.
370 *
371 * @param defaultValue default value used when a default is not provided to a
372 * getter function
373 * @param options subscribe options
374 * @return subscriber
375 */
376 [[nodiscard]]
378 T defaultValue, const PubSubOptions& options = kDefaultPubSubOptions) {
380 auto typeString = msg.GetTypeString();
382 ::nt::Subscribe(m_handle, NT_RAW, typeString, options), std::move(msg),
383 std::move(defaultValue)};
384 }
385
386 /**
387 * Create a new publisher to the topic.
388 *
389 * The publisher is only active as long as the returned object
390 * is not destroyed.
391 *
392 * @note It is not possible to publish two different data types to the same
393 * topic. Conflicts between publishers are typically resolved by the
394 * server on a first-come, first-served basis. Any published values that
395 * do not match the topic's data type are dropped (ignored). To determine
396 * if the data type matches, use the appropriate Topic functions.
397 *
398 * @param options publish options
399 * @return publisher
400 */
401 [[nodiscard]]
404 auto typeString = msg.GetTypeString();
406 ::nt::Publish(m_handle, NT_RAW, typeString, options), std::move(msg)};
407 }
408
409 /**
410 * Create a new publisher to the topic, with type string and initial
411 * properties.
412 *
413 * The publisher is only active as long as the returned object
414 * is not destroyed.
415 *
416 * @note It is not possible to publish two different data types to the same
417 * topic. Conflicts between publishers are typically resolved by the
418 * server on a first-come, first-served basis. Any published values that
419 * do not match the topic's data type are dropped (ignored). To determine
420 * if the data type matches, use the appropriate Topic functions.
421 *
422 * @param properties JSON properties
423 * @param options publish options
424 * @return publisher
425 */
426 [[nodiscard]]
428 const wpi::json& properties,
429 const PubSubOptions& options = kDefaultPubSubOptions) {
431 auto typeString = msg.GetTypeString();
433 ::nt::PublishEx(m_handle, NT_RAW, typeString, properties, options),
434 std::move(msg)};
435 }
436
437 /**
438 * Create a new entry for the topic.
439 *
440 * Entries act as a combination of a subscriber and a weak publisher. The
441 * subscriber is active as long as the entry is not destroyed. The publisher
442 * is created when the entry is first written to, and remains active until
443 * either Unpublish() is called or the entry is destroyed.
444 *
445 * @note It is not possible to use two different data types with the same
446 * topic. Conflicts between publishers are typically resolved by the
447 * server on a first-come, first-served basis. Any published values that
448 * do not match the topic's data type are dropped (ignored), and the entry
449 * will show no new values if the data type does not match. To determine
450 * if the data type matches, use the appropriate Topic functions.
451 *
452 * @param defaultValue default value used when a default is not provided to a
453 * getter function
454 * @param options publish and/or subscribe options
455 * @return entry
456 */
457 [[nodiscard]]
458 EntryType GetEntry(T defaultValue,
459 const PubSubOptions& options = kDefaultPubSubOptions) {
461 auto typeString = msg.GetTypeString();
462 return ProtobufEntry<T>{
463 ::nt::GetEntry(m_handle, NT_RAW, typeString, options), std::move(msg),
464 std::move(defaultValue)};
465 }
466};
467
468} // namespace nt
NetworkTables protobuf-encoded value entry.
Definition ProtobufTopic.h:278
ProtobufEntry()=default
NT_Entry GetHandle() const
Gets the native handle for the entry.
Definition ProtobufTopic.h:314
void Unpublish()
Stops publishing the entry if it's published.
Definition ProtobufTopic.h:328
TopicType GetTopic() const
Get the corresponding topic.
Definition ProtobufTopic.h:321
T ValueType
Definition ProtobufTopic.h:283
ProtobufEntry(NT_Entry handle, wpi::ProtobufMessage< T > msg, T defaultValue)
Construct from an entry handle; recommended to use ProtobufTopic::GetEntry() instead.
Definition ProtobufTopic.h:298
const T & ParamType
Definition ProtobufTopic.h:284
NetworkTables protobuf-encoded value publisher.
Definition ProtobufTopic.h:182
T ValueType
Definition ProtobufTopic.h:185
ProtobufPublisher(const ProtobufPublisher &)=delete
ProtobufPublisher()=default
void SetDefault(const T &value)
Publish a default value.
Definition ProtobufTopic.h:244
ProtobufPublisher(NT_Publisher handle, wpi::ProtobufMessage< T > msg)
Construct from a publisher handle; recommended to use ProtobufTopic::Publish() instead.
Definition ProtobufTopic.h:199
void Set(const T &value, int64_t time=0)
Publish a new value.
Definition ProtobufTopic.h:225
TopicType GetTopic() const
Get the corresponding topic.
Definition ProtobufTopic.h:261
ProtobufPublisher(ProtobufPublisher &&rhs)
Definition ProtobufTopic.h:205
const T & ParamType
Definition ProtobufTopic.h:186
ProtobufPublisher & operator=(ProtobufPublisher &&rhs)
Definition ProtobufTopic.h:210
ProtobufPublisher & operator=(const ProtobufPublisher &)=delete
NetworkTables protobuf-encoded value subscriber.
Definition ProtobufTopic.h:32
TimestampedValueType GetAtomic(const T &defaultValue) const
Get the last published value along with its timestamp.
Definition ProtobufTopic.h:127
bool GetInto(T *out)
Get the last published value, replacing the contents in place of an existing object.
Definition ProtobufTopic.h:99
ValueType Get(const T &defaultValue) const
Get the last published value.
Definition ProtobufTopic.h:87
TimestampedValueType GetAtomic() const
Get the last published value along with its timestamp If no value has been published or the value can...
Definition ProtobufTopic.h:117
std::vector< TimestampedValueType > ReadQueue()
Get an array of all valid value changes since the last call to ReadQueue.
Definition ProtobufTopic.h:150
ProtobufSubscriber & operator=(const ProtobufSubscriber &)=delete
TopicType GetTopic() const
Get the corresponding topic.
Definition ProtobufTopic.h:168
const T & ParamType
Definition ProtobufTopic.h:36
ProtobufSubscriber & operator=(ProtobufSubscriber &&rhs)
Definition ProtobufTopic.h:63
ProtobufSubscriber(const ProtobufSubscriber &)=delete
ProtobufSubscriber(ProtobufSubscriber &&rhs)
Definition ProtobufTopic.h:58
ProtobufSubscriber(NT_Subscriber handle, wpi::ProtobufMessage< T > msg, T defaultValue)
Construct from a subscriber handle; recommended to use ProtobufTopic::Subscribe() instead.
Definition ProtobufTopic.h:49
ProtobufSubscriber()=default
T ValueType
Definition ProtobufTopic.h:35
ValueType Get() const
Get the last published value.
Definition ProtobufTopic.h:77
NetworkTables protobuf-encoded value topic.
Definition NetworkTable.h:36
ProtobufTopic()=default
EntryType GetEntry(T defaultValue, const PubSubOptions &options=kDefaultPubSubOptions)
Create a new entry for the topic.
Definition ProtobufTopic.h:458
ProtobufTopic(Topic topic)
Construct from a generic topic.
Definition ProtobufTopic.h:359
SubscriberType Subscribe(T defaultValue, const PubSubOptions &options=kDefaultPubSubOptions)
Create a new subscriber to the topic.
Definition ProtobufTopic.h:377
PublisherType PublishEx(const wpi::json &properties, const PubSubOptions &options=kDefaultPubSubOptions)
Create a new publisher to the topic, with type string and initial properties.
Definition ProtobufTopic.h:427
ProtobufTopic(NT_Topic handle)
Construct from a topic handle; recommended to use NetworkTableInstance::GetProtobufTopic() instead.
Definition ProtobufTopic.h:352
T ValueType
Definition ProtobufTopic.h:340
PublisherType Publish(const PubSubOptions &options=kDefaultPubSubOptions)
Create a new publisher to the topic.
Definition ProtobufTopic.h:402
const T & ParamType
Definition ProtobufTopic.h:341
NetworkTables publisher.
Definition Topic.h:393
Publisher & operator=(const Publisher &)=delete
NT_Publisher m_pubHandle
NetworkTables handle.
Definition Topic.h:441
NetworkTables subscriber.
Definition Topic.h:321
Subscriber & operator=(const Subscriber &)=delete
NT_Subscriber m_subHandle
Definition Topic.h:386
NetworkTables Topic.
Definition Topic.h:28
NT_Topic m_handle
Definition Topic.h:317
NetworkTableInstance GetInstance() const
Gets the instance for the topic.
Ease of use wrapper to make nanopb streams more opaque to the user.
Definition Protobuf.h:307
std::string GetTypeString() const
Gets the type string for the message.
Definition Protobuf.h:370
bool SetDefaultRaw(NT_Handle pubentry, std::span< const uint8_t > defaultValue)
Publish a default value.
std::vector< TimestampedRaw > ReadQueueRaw(NT_Handle subentry)
Get an array of all value changes since the last call to ReadQueue.
bool SetRaw(NT_Handle pubentry, std::span< const uint8_t > value, int64_t time=0)
Publish a new value.
TimestampedRaw GetAtomicRaw(NT_Handle subentry, std::span< const uint8_t > defaultValue)
Get the last published value along with its timestamp.
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
constexpr PubSubOptions kDefaultPubSubOptions
Default publish/subscribe options.
Definition ntcore_cpp.h:390
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 PublishEx(NT_Topic topic, NT_Type type, std::string_view typeStr, const wpi::json &properties, const PubSubOptions &options=kDefaultPubSubOptions)
Creates a new publisher to a topic.
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_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.
NetworkTables (ntcore) namespace.
Definition ntcore_cpp.h:36
Definition PointerIntPair.h:280
::std::mutex mutex
Definition mutex.h:17
NetworkTables publish/subscribe options.
Definition ntcore_cpp.h:305
Timestamped value.
Definition ntcore_cpp_types.h:30
int64_t time
Time in local time base.
Definition ntcore_cpp_types.h:38
int64_t serverTime
Time in server time base.
Definition ntcore_cpp_types.h:43
T value
Value.
Definition ntcore_cpp_types.h:48