mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-25 01:41:43 +00:00
[wpiutil] Change C++ protobuf to nanopb (#7309)
The Google C++ protobuf implementation has issues with dynamic linkage across DLL boundaries because it uses global variables. It also has a compile-time dependency because the protoc version must exactly match the libprotobuf version. Using nanopb with a customized generator fixes both of these issues. Co-authored-by: Gold856 <117957790+Gold856@users.noreply.github.com>
This commit is contained in:
@@ -8,10 +8,13 @@
|
||||
#include <wpi/protobuf/Protobuf.h>
|
||||
|
||||
#include "frc/system/plant/DCMotor.h"
|
||||
#include "wpimath/protobuf/plant.npb.h"
|
||||
|
||||
template <>
|
||||
struct WPILIB_DLLEXPORT wpi::Protobuf<frc::DCMotor> {
|
||||
static google::protobuf::Message* New(google::protobuf::Arena* arena);
|
||||
static frc::DCMotor Unpack(const google::protobuf::Message& msg);
|
||||
static void Pack(google::protobuf::Message* msg, const frc::DCMotor& value);
|
||||
using MessageStruct = wpi_proto_ProtobufDCMotor;
|
||||
using InputStream = wpi::ProtoInputStream<frc::DCMotor>;
|
||||
using OutputStream = wpi::ProtoOutputStream<frc::DCMotor>;
|
||||
static std::optional<frc::DCMotor> Unpack(InputStream& stream);
|
||||
static bool Pack(OutputStream& stream, const frc::DCMotor& value);
|
||||
};
|
||||
|
||||
@@ -5,48 +5,84 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <wpi/ProtoHelper.h>
|
||||
#include <wpi/protobuf/Protobuf.h>
|
||||
#include <wpi/protobuf/ProtobufCallbacks.h>
|
||||
|
||||
#include "frc/proto/MatrixProto.h"
|
||||
#include "frc/system/LinearSystem.h"
|
||||
#include "system.pb.h"
|
||||
#include "wpimath/protobuf/system.npb.h"
|
||||
|
||||
template <int States, int Inputs, int Outputs>
|
||||
struct wpi::Protobuf<frc::LinearSystem<States, Inputs, Outputs>> {
|
||||
static google::protobuf::Message* New(google::protobuf::Arena* arena) {
|
||||
return wpi::CreateMessage<wpi::proto::ProtobufLinearSystem>(arena);
|
||||
}
|
||||
using MessageStruct = wpi_proto_ProtobufLinearSystem;
|
||||
using InputStream =
|
||||
wpi::ProtoInputStream<frc::LinearSystem<States, Inputs, Outputs>>;
|
||||
using OutputStream =
|
||||
wpi::ProtoOutputStream<frc::LinearSystem<States, Inputs, Outputs>>;
|
||||
|
||||
static frc::LinearSystem<States, Inputs, Outputs> Unpack(
|
||||
const google::protobuf::Message& msg) {
|
||||
auto m = static_cast<const wpi::proto::ProtobufLinearSystem*>(&msg);
|
||||
if (m->num_states() != States || m->num_inputs() != Inputs ||
|
||||
m->num_outputs() != Outputs) {
|
||||
throw std::invalid_argument(fmt::format(
|
||||
"Tried to unpack message with {} states and {} inputs and {} outputs "
|
||||
"into LinearSystem with {} states and {} inputs and {} outputs",
|
||||
m->num_states(), m->num_inputs(), m->num_outputs(), States, Inputs,
|
||||
Outputs));
|
||||
static std::optional<frc::LinearSystem<States, Inputs, Outputs>> Unpack(
|
||||
InputStream& stream) {
|
||||
wpi::UnpackCallback<frc::Matrixd<States, States>> a;
|
||||
a.SetLimits(wpi::DecodeLimits::Fail);
|
||||
wpi::UnpackCallback<frc::Matrixd<States, Inputs>> b;
|
||||
a.SetLimits(wpi::DecodeLimits::Fail);
|
||||
wpi::UnpackCallback<frc::Matrixd<Outputs, States>> c;
|
||||
a.SetLimits(wpi::DecodeLimits::Fail);
|
||||
wpi::UnpackCallback<frc::Matrixd<Outputs, Inputs>> d;
|
||||
a.SetLimits(wpi::DecodeLimits::Fail);
|
||||
|
||||
wpi_proto_ProtobufLinearSystem msg;
|
||||
msg.a = a.Callback();
|
||||
msg.b = b.Callback();
|
||||
msg.c = c.Callback();
|
||||
msg.d = d.Callback();
|
||||
|
||||
if (!stream.Decode(msg)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (msg.num_inputs != Inputs || msg.num_outputs != Outputs ||
|
||||
msg.num_states != States) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto ai = a.Items();
|
||||
auto bi = b.Items();
|
||||
auto ci = c.Items();
|
||||
auto di = d.Items();
|
||||
|
||||
if (ai.empty() || bi.empty() || ci.empty() || di.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return frc::LinearSystem<States, Inputs, Outputs>{
|
||||
wpi::UnpackProtobuf<frc::Matrixd<States, States>>(m->wpi_a()),
|
||||
wpi::UnpackProtobuf<frc::Matrixd<States, Inputs>>(m->wpi_b()),
|
||||
wpi::UnpackProtobuf<frc::Matrixd<Outputs, States>>(m->wpi_c()),
|
||||
wpi::UnpackProtobuf<frc::Matrixd<Outputs, Inputs>>(m->wpi_d())};
|
||||
std::move(ai[0]),
|
||||
std::move(bi[0]),
|
||||
std::move(ci[0]),
|
||||
std::move(di[0]),
|
||||
};
|
||||
}
|
||||
|
||||
static void Pack(google::protobuf::Message* msg,
|
||||
static bool Pack(OutputStream& stream,
|
||||
const frc::LinearSystem<States, Inputs, Outputs>& value) {
|
||||
auto m = static_cast<wpi::proto::ProtobufLinearSystem*>(msg);
|
||||
m->set_num_states(States);
|
||||
m->set_num_inputs(Inputs);
|
||||
m->set_num_outputs(Outputs);
|
||||
wpi::PackProtobuf(m->mutable_a(), value.A());
|
||||
wpi::PackProtobuf(m->mutable_b(), value.B());
|
||||
wpi::PackProtobuf(m->mutable_c(), value.C());
|
||||
wpi::PackProtobuf(m->mutable_d(), value.D());
|
||||
wpi::PackCallback a{&value.A()};
|
||||
wpi::PackCallback b{&value.B()};
|
||||
wpi::PackCallback c{&value.C()};
|
||||
wpi::PackCallback d{&value.D()};
|
||||
|
||||
wpi_proto_ProtobufLinearSystem msg{
|
||||
.num_states = States,
|
||||
.num_inputs = Inputs,
|
||||
.num_outputs = Outputs,
|
||||
.a = a.Callback(),
|
||||
.b = b.Callback(),
|
||||
.c = c.Callback(),
|
||||
.d = d.Callback(),
|
||||
};
|
||||
|
||||
return stream.Encode(msg);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user