Skip to content

Commit 6eb5395

Browse files
committed
Initial C++ NT backend
1 parent 00b6996 commit 6eb5395

File tree

4 files changed

+324
-2
lines changed

4 files changed

+324
-2
lines changed

ntcore/src/main/java/edu/wpi/first/networktables/NetworkTablesTelemetryBackend.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ public class NetworkTablesTelemetryBackend implements TelemetryBackend {
1818
private final String m_prefix;
1919
private static final Map<String, Entry> s_entries = new HashMap<>();
2020

21+
/**
22+
* Construct.
23+
*
24+
* @param inst NetworkTables instance
25+
* @param prefix prefix to put in front of logged path in NT
26+
*/
2127
public NetworkTablesTelemetryBackend(NetworkTableInstance inst, String prefix) {
2228
m_inst = inst;
2329
m_prefix = prefix;
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
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+
#include "networktables/NetworkTablesTelemetryBackend.h"
6+
7+
#include <atomic>
8+
#include <string>
9+
#include <string_view>
10+
11+
#include <fmt/format.h>
12+
#include <wpi/json.h>
13+
#include <wpi/mutex.h>
14+
#include <wpi/telemetry/TelemetryEntry.h>
15+
16+
#include "networktables/GenericEntry.h"
17+
#include "networktables/NetworkTableInstance.h"
18+
19+
using namespace nt;
20+
21+
class NetworkTablesTelemetryBackend::Entry : public wpi::TelemetryEntry {
22+
public:
23+
Entry(NetworkTableInstance& inst, std::string_view prefix,
24+
std::string_view path)
25+
: m_inst{inst}, m_path{fmt::format("{}{}", prefix, path)} {}
26+
27+
void KeepDuplicates() override {
28+
m_keepDuplicates = true;
29+
// TODO: update publisher
30+
}
31+
32+
void SetProperty(std::string_view key, std::string_view value) override {
33+
std::scoped_lock lock{m_mutex};
34+
auto& curValue = m_properties[key];
35+
if (curValue == value) {
36+
return;
37+
}
38+
curValue = value;
39+
// TODO
40+
}
41+
42+
void LogBoolean(bool value) override {
43+
std::scoped_lock lock{m_mutex};
44+
if (!m_pub) {
45+
m_pub = m_inst.GetTopic(m_path).GenericPublishEx(
46+
"boolean", m_properties, {.keepDuplicates = m_keepDuplicates});
47+
}
48+
if (!m_pub.SetBoolean(value)) {
49+
// TODO: warn?
50+
}
51+
}
52+
53+
void LogInt64(int64_t value) override {
54+
std::scoped_lock lock{m_mutex};
55+
if (!m_pub) {
56+
m_pub = m_inst.GetTopic(m_path).GenericPublishEx(
57+
"int", m_properties, {.keepDuplicates = m_keepDuplicates});
58+
}
59+
if (!m_pub.SetInteger(value)) {
60+
// TODO: warn?
61+
}
62+
}
63+
64+
void LogFloat(float value) override {
65+
std::scoped_lock lock{m_mutex};
66+
if (!m_pub) {
67+
m_pub = m_inst.GetTopic(m_path).GenericPublishEx(
68+
"float", m_properties, {.keepDuplicates = m_keepDuplicates});
69+
}
70+
if (!m_pub.SetFloat(value)) {
71+
// TODO: warn?
72+
}
73+
}
74+
75+
void LogDouble(double value) override {
76+
std::scoped_lock lock{m_mutex};
77+
if (!m_pub) {
78+
m_pub = m_inst.GetTopic(m_path).GenericPublishEx(
79+
"double", m_properties, {.keepDuplicates = m_keepDuplicates});
80+
}
81+
if (!m_pub.SetDouble(value)) {
82+
// TODO: warn?
83+
}
84+
}
85+
86+
void LogString(std::string_view value, std::string_view typeString) override {
87+
std::scoped_lock lock{m_mutex};
88+
if (!m_pub) {
89+
m_typeString = typeString;
90+
m_pub = m_inst.GetTopic(m_path).GenericPublishEx(
91+
typeString, m_properties, {.keepDuplicates = m_keepDuplicates});
92+
}
93+
if (m_typeString != typeString || !m_pub.SetString(value)) {
94+
// TODO: warn?
95+
}
96+
}
97+
98+
void LogBooleanArray(std::span<const bool> value) override {
99+
std::scoped_lock lock{m_mutex};
100+
if (!m_pub) {
101+
m_pub = m_inst.GetTopic(m_path).GenericPublishEx(
102+
"boolean[]", m_properties, {.keepDuplicates = m_keepDuplicates});
103+
}
104+
if (!m_pub.SetBooleanArray(value)) {
105+
// TODO: warn?
106+
}
107+
}
108+
109+
void LogBooleanArray(std::span<const int> value) override {
110+
std::scoped_lock lock{m_mutex};
111+
if (!m_pub) {
112+
m_pub = m_inst.GetTopic(m_path).GenericPublishEx(
113+
"boolean[]", m_properties, {.keepDuplicates = m_keepDuplicates});
114+
}
115+
if (!m_pub.SetBooleanArray(value)) {
116+
// TODO: warn?
117+
}
118+
}
119+
120+
void LogInt16Array(std::span<const int16_t> value) override {
121+
// TODO
122+
}
123+
124+
void LogInt32Array(std::span<const int32_t> value) override {
125+
// TODO
126+
}
127+
128+
void LogInt64Array(std::span<const int64_t> value) override {
129+
std::scoped_lock lock{m_mutex};
130+
if (!m_pub) {
131+
m_pub = m_inst.GetTopic(m_path).GenericPublishEx(
132+
"int[]", m_properties, {.keepDuplicates = m_keepDuplicates});
133+
}
134+
if (!m_pub.SetIntegerArray(value)) {
135+
// TODO: warn?
136+
}
137+
}
138+
139+
void LogFloatArray(std::span<const float> value) override {
140+
std::scoped_lock lock{m_mutex};
141+
if (!m_pub) {
142+
m_pub = m_inst.GetTopic(m_path).GenericPublishEx(
143+
"float[]", m_properties, {.keepDuplicates = m_keepDuplicates});
144+
}
145+
if (!m_pub.SetFloatArray(value)) {
146+
// TODO: warn?
147+
}
148+
}
149+
150+
void LogDoubleArray(std::span<const double> value) override {
151+
std::scoped_lock lock{m_mutex};
152+
if (!m_pub) {
153+
m_pub = m_inst.GetTopic(m_path).GenericPublishEx(
154+
"double[]", m_properties, {.keepDuplicates = m_keepDuplicates});
155+
}
156+
if (!m_pub.SetDoubleArray(value)) {
157+
// TODO: warn?
158+
}
159+
}
160+
161+
void LogStringArray(std::span<const std::string> value) override {
162+
std::scoped_lock lock{m_mutex};
163+
if (!m_pub) {
164+
m_pub = m_inst.GetTopic(m_path).GenericPublishEx(
165+
"string[]", m_properties, {.keepDuplicates = m_keepDuplicates});
166+
}
167+
if (!m_pub.SetStringArray(value)) {
168+
// TODO: warn?
169+
}
170+
}
171+
172+
void LogStringArray(std::span<const std::string_view> value) override {
173+
// TODO
174+
}
175+
176+
void LogRaw(std::span<const uint8_t> value,
177+
std::string_view typeString) override {
178+
std::scoped_lock lock{m_mutex};
179+
if (!m_pub) {
180+
m_typeString = typeString;
181+
m_pub = m_inst.GetTopic(m_path).GenericPublishEx(
182+
typeString, m_properties, {.keepDuplicates = m_keepDuplicates});
183+
}
184+
if (m_typeString != typeString || !m_pub.SetRaw(value)) {
185+
// TODO: warn?
186+
}
187+
}
188+
189+
private:
190+
NetworkTableInstance& m_inst;
191+
std::string m_path;
192+
wpi::mutex m_mutex;
193+
GenericPublisher m_pub;
194+
std::string m_typeString;
195+
std::atomic_bool m_keepDuplicates{false};
196+
wpi::json m_properties = wpi::json::object();
197+
};
198+
199+
NetworkTablesTelemetryBackend::NetworkTablesTelemetryBackend(
200+
NetworkTableInstance& inst, std::string_view prefix)
201+
: m_inst{inst}, m_prefix{prefix} {}
202+
203+
NetworkTablesTelemetryBackend::~NetworkTablesTelemetryBackend() = default;
204+
205+
wpi::TelemetryEntry& NetworkTablesTelemetryBackend::GetEntry(
206+
std::string_view path) {
207+
std::scoped_lock lock{m_mutex};
208+
return m_entries.try_emplace(path, m_inst, m_prefix, path).first->second;
209+
}
210+
211+
bool NetworkTablesTelemetryBackend::HasSchema(
212+
std::string_view schemaName) const {
213+
return m_inst.HasSchema(schemaName);
214+
}
215+
216+
void NetworkTablesTelemetryBackend::AddSchema(std::string_view schemaName,
217+
std::string_view type,
218+
std::span<const uint8_t> schema) {
219+
m_inst.AddSchema(schemaName, type, schema);
220+
}
221+
222+
void NetworkTablesTelemetryBackend::AddSchema(std::string_view schemaName,
223+
std::string_view type,
224+
std::string_view schema) {
225+
m_inst.AddSchema(schemaName, type, schema);
226+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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 <wpi/mutex.h>
8+
#include <wpi/telemetry/TelemetryBackend.h>
9+
#include <wpi/StringMap.h>
10+
11+
namespace nt {
12+
13+
class NetworkTableInstance;
14+
15+
/** A telemetry backend that sends logged data to a DataLog. */
16+
class NetworkTablesTelemetryBackend : public wpi::TelemetryBackend {
17+
public:
18+
/**
19+
* Construct.
20+
*
21+
* @param inst NetworkTables instance
22+
* @param prefix prefix to put in front of logged path in NT
23+
*/
24+
NetworkTablesTelemetryBackend(NetworkTableInstance& inst,
25+
std::string_view prefix);
26+
27+
~NetworkTablesTelemetryBackend() override;
28+
29+
/**
30+
* Create an entry for the given path.
31+
*
32+
* @param path full name
33+
* @return telemetry entry
34+
*/
35+
wpi::TelemetryEntry& GetEntry(std::string_view path) override;
36+
37+
/**
38+
* Returns whether there is a data schema already registered with the given
39+
* name. This does NOT perform a check as to whether the schema has already
40+
* been published by another node on the network.
41+
*
42+
* @param schemaName Name (the string passed as the data type for topics using
43+
* this schema)
44+
* @return True if schema already registered
45+
*/
46+
bool HasSchema(std::string_view schemaName) const override;
47+
48+
/**
49+
* Registers a data schema. Data schemas provide information for how a
50+
* certain data type string can be decoded. The type string of a data schema
51+
* indicates the type of the schema itself (e.g. "protobuf" for protobuf
52+
* schemas, "struct" for struct schemas, etc). In NetworkTables, schemas are
53+
* published just like normal topics, with the name being generated from the
54+
* provided name: "/.schema/<name>". Duplicate calls to this function with
55+
* the same name are silently ignored.
56+
*
57+
* @param schemaName Name (the string passed as the data type for topics using
58+
* this schema)
59+
* @param type Type of schema (e.g. "protobuf", "struct", etc)
60+
* @param schema Schema data
61+
*/
62+
void AddSchema(std::string_view schemaName, std::string_view type,
63+
std::span<const uint8_t> schema) override;
64+
65+
/**
66+
* Registers a data schema. Data schemas provide information for how a
67+
* certain data type string can be decoded. The type string of a data schema
68+
* indicates the type of the schema itself (e.g. "protobuf" for protobuf
69+
* schemas, "struct" for struct schemas, etc). In NetworkTables, schemas are
70+
* published just like normal topics, with the name being generated from the
71+
* provided name: "/.schema/<name>". Duplicate calls to this function with
72+
* the same name are silently ignored.
73+
*
74+
* @param schemaName Name (the string passed as the data type for topics using
75+
* this schema)
76+
* @param type Type of schema (e.g. "protobuf", "struct", etc)
77+
* @param schema Schema data
78+
*/
79+
void AddSchema(std::string_view schemaName, std::string_view type,
80+
std::string_view schema) override;
81+
82+
private:
83+
class Entry;
84+
85+
NetworkTableInstance& m_inst;
86+
std::string m_prefix;
87+
wpi::mutex m_mutex;
88+
wpi::StringMap<Entry> m_entries;
89+
};
90+
91+
} // namespace nt

wpiutil/src/main/native/include/wpi/datalog/DataLogTelemetryBackend.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44

55
#pragma once
66

7-
#include "wpi/telemetry/TelemetryBackend.h"
8-
97
#include "wpi/mutex.h"
8+
#include "wpi/telemetry/TelemetryBackend.h"
109
#include "wpi/StringMap.h"
1110

1211
namespace wpi {

0 commit comments

Comments
 (0)