Goby3 3.4.0
2026.04.13
Loading...
Searching...
No Matches
application.h
Go to the documentation of this file.
1// Copyright 2025-2026:
2// GobySoft, LLC (2013-)
3// Community contributors (see AUTHORS file)
4// File authors:
5// Toby Schneider <toby@gobysoft.org>
6//
7//
8// This file is part of the Goby Underwater Autonomy Project Libraries
9// ("The Goby Libraries").
10//
11// The Goby Libraries are free software: you can redistribute them and/or modify
12// them under the terms of the GNU Lesser General Public License as published by
13// the Free Software Foundation, either version 2.1 of the License, or
14// (at your option) any later version.
15//
16// The Goby Libraries are distributed in the hope that they will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU Lesser General Public License for more details.
20//
21// You should have received a copy of the GNU Lesser General Public License
22// along with Goby. If not, see <http://www.gnu.org/licenses/>.
23
24#include <jlcxx/functions.hpp>
25#include <jlcxx/jlcxx.hpp>
26
30#include "goby/time.h"
31
32namespace goby
33{
34namespace middleware
35{
36namespace julia
37{
38
39enum class PubSubLayer
40{
41 INTERTHREAD = 0,
42 INTERPROCESS = 1,
43 INTERMODULE = 2
44};
45
46template <typename AppBase> class Application : public AppBase
47{
48 public:
49 Application() { loop_ = std::make_unique<jlcxx::JuliaFunction>("cxx_loop", "Goby"); }
50 void loop() override { (*loop_)(); }
51
52 private:
53 std::unique_ptr<jlcxx::JuliaFunction> loop_;
54};
55
63
64bool operator==(const Identifier& i1, const Identifier& i2)
65{
66 return i1.layer == i2.layer && i1.type_name == i2.type_name && i1.scheme == i2.scheme &&
67 i1.group == i2.group;
68}
69
70template <typename App> class ApplicationWrapper
71{
72 public:
73 ApplicationWrapper(std::string config)
74 {
75 typename App::ConfigType cfg;
76 google::protobuf::TextFormat::Parser parser;
77 goby::util::FlexOStreamErrorCollector error_collector(config);
78 parser.RecordErrorsTo(&error_collector);
79 parser.AllowPartialMessage(false);
80 parser.ParseFromString(config, &cfg);
81
82 App::app_cfg_.reset(new typename App::ConfigType(cfg));
83 App::app3_base_configuration_.reset(new goby::middleware::protobuf::AppConfig(cfg.app()));
84
85 // TODO - don't copy from middleware/application/interface.h if possible
86 if (App::app3_base_configuration_->simulation().time().use_sim_time())
87 {
90 App::app3_base_configuration_->simulation().time().warp_factor();
91 if (App::app3_base_configuration_->simulation().time().has_reference_microtime())
93 std::chrono::system_clock::time_point(std::chrono::microseconds(
94 App::app3_base_configuration_->simulation().time().reference_microtime()));
95 }
96
97 app_ptr_.reset(new App);
98 }
99
100 void run() { app_ptr_->__run(); }
101
102 ApplicationWrapper& interprocess() { return *this; }
103
104 void publish(PubSubLayer layer, std::string type_name, int scheme, std::string group,
105 const std::vector<std::uint8_t>& bytes)
106 {
107 app_ptr_->publish(Identifier(layer, type_name, scheme, group), bytes);
108 }
109
110 void subscribe(PubSubLayer layer, std::string type_name, int scheme, std::string group,
111 std::string func, std::string module)
112 {
113 app_ptr_->subscribe(Identifier(layer, type_name, scheme, group), func, module);
114 }
115
116 void set_loop_frequency_hertz(double freq) { app_ptr_->set_loop_frequency_hertz(freq); }
117
118 std::vector<std::uint8_t> cfg_serialized()
119 {
120 std::vector<std::uint8_t> v(app_ptr_->app_cfg().ByteSizeLong());
121 app_ptr_->app_cfg().SerializeToArray(&v[0], v.size());
122 return v;
123 }
124
125 private:
126 std::unique_ptr<App> app_ptr_;
127 std::map<std::string, goby::middleware::DynamicGroup> subscription_groups_;
128};
129
130template <typename App>
131inline void define_julia_module(jlcxx::Module& types, const std::string& app_name)
132{
133 types.add_bits<PubSubLayer>("PubSubLayer", jlcxx::julia_type("CppEnum"));
134 types.set_const("INTERTHREAD", PubSubLayer::INTERTHREAD);
135 types.set_const("INTERPROCESS", PubSubLayer::INTERPROCESS);
136 types.set_const("INTERMODULE", PubSubLayer::INTERMODULE);
137
138 types.add_bits<MarshallingScheme::MarshallingSchemeEnum>("MarshallingScheme",
139 jlcxx::julia_type("CppEnum"));
140 types.set_const("NULL_SCHEME", MarshallingScheme::NULL_SCHEME);
141 types.set_const("PROTOBUF", MarshallingScheme::PROTOBUF);
142 types.set_const("JSON", MarshallingScheme::JSON);
143
144 types.template add_type<ApplicationWrapper<App>>(app_name)
145 .template constructor<std::string>()
146 .method("cxx_run", &ApplicationWrapper<App>::run)
147 .method("cxx_publish", &ApplicationWrapper<App>::publish)
148 .method("cxx_subscribe", &ApplicationWrapper<App>::subscribe)
149 .method("cxx_set_loop_frequency_hertz", &ApplicationWrapper<App>::set_loop_frequency_hertz)
150 .method("cxx_cfg_serialized", &ApplicationWrapper<App>::cfg_serialized);
151}
152
153template <typename DataType, int scheme>
154std::vector<std::uint8_t> serialize_uint8(const DataType& msg)
155{
156 std::vector<char> out =
158 return std::vector<std::uint8_t>(out.begin(), out.end());
159}
160
161} // namespace julia
162} // namespace middleware
163} // namespace goby
164
165std::ostream& operator<<(std::ostream& os, const goby::middleware::julia::Identifier& i)
166{
167 std::string layer;
168
169 switch (i.layer)
170 {
171 case goby::middleware::julia::PubSubLayer::INTERTHREAD: layer = "interthread"; break;
172 case goby::middleware::julia::PubSubLayer::INTERPROCESS: layer = "interprocess"; break;
173 case goby::middleware::julia::PubSubLayer::INTERMODULE: layer = "intermodule"; break;
174 }
175
176 return (os << "layer: " << layer << ", type_name: \"" << i.type_name
178 << ", group: \"" << i.group << "\"");
179}
180
181// Macros for use by the autogenerated code to define the C++ side of the pub/sub setup
182#define GOBY_JULIA_IF_PUBLICATION(SCHEME, LAYER_ENUM, LAYER_FUNCTION, GROUP, TYPE) \
183 if (id == goby::middleware::julia::Identifier{ \
184 goby::middleware::julia::PubSubLayer::LAYER_ENUM, TYPE::descriptor()->name(), \
185 goby::middleware::MarshallingScheme::SCHEME, GROUP}) \
186 { \
187 decltype(bytes.end()) actual_end; \
188 auto msg = goby::middleware::SerializerParserHelper< \
189 TYPE, goby::middleware::MarshallingScheme::SCHEME>::parse(bytes.begin(), bytes.end(), \
190 actual_end); \
191 LAYER_FUNCTION().publish<GROUP>(msg); \
192 return; \
193 }
194
195#define GOBY_JULIA_IF_SUBSCRIPTION(SCHEME, LAYER_ENUM, LAYER_FUNCTION, GROUP, TYPE) \
196 if (id == goby::middleware::julia::Identifier( \
197 goby::middleware::julia::PubSubLayer::LAYER_ENUM, TYPE::descriptor()->name(), \
198 goby::middleware::MarshallingScheme::SCHEME, GROUP)) \
199 { \
200 LAYER_FUNCTION().subscribe<GROUP>( \
201 [=](const TYPE& pb) \
202 { \
203 std::vector<std::uint8_t> bytes = goby::middleware::julia::serialize_uint8< \
204 TYPE, goby::middleware::MarshallingScheme::SCHEME>(pb); \
205 jlcxx::JuliaFunction cb(func, module); \
206 cb(id.layer, id.type_name, id.scheme, id.group, bytes); \
207 }); \
208 return; \
209 }
210
211#define GOBY_JULIA_FAIL(PUBLISH_OR_SUBSCRIBE) \
212 goby::glog.is_die() && \
213 goby::glog << PUBLISH_OR_SUBSCRIBE " not defined for these parameters: [" << id \
214 << "]. Please include in interfaces.yml and re-generate to include them." \
215 << std::endl;
216
217// used to stringify application name
218#define GOBY_JULIA_QUOTE(name) #name
219#define GOBY_JULIA_DEFINE_MODULE(APPLICATION_NAME) \
220 JLCXX_MODULE define_julia_module(jlcxx::Module& types) \
221 { \
222 goby::middleware::julia::define_julia_module<APPLICATION_NAME>( \
223 types, GOBY_JULIA_QUOTE(APPLICATION_NAME)); \
224 }
void subscribe(PubSubLayer layer, std::string type_name, int scheme, std::string group, std::string func, std::string module)
void publish(PubSubLayer layer, std::string type_name, int scheme, std::string group, const std::vector< std::uint8_t > &bytes)
std::vector< std::uint8_t > cfg_serialized()
goby::util::logger::GroupSetter group(std::string n)
void define_julia_module(jlcxx::Module &types, const std::string &app_name)
bool operator==(const Identifier &i1, const Identifier &i2)
Definition application.h:64
std::vector< std::uint8_t > serialize_uint8(const DataType &msg)
constexpr int scheme()
Placeholder to provide an interface for the scheme() function family.
Definition cstr.h:65
The global namespace for the Goby project.
extern ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< ::PROTOBUF_NAMESPACE_ID::MessageOptions, ::PROTOBUF_NAMESPACE_ID::internal::MessageTypeTraits< ::goby::GobyMessageOptions >, 11, false > msg
MarshallingSchemeEnum
Marshalilng schemes implemented in Goby.
Definition interface.h:49
static std::string to_string(int e)
Convert a known marshalling scheme to a human-readable string or an unknown scheme to the string repr...
Definition interface.h:67
static std::vector< char > serialize(const DataType &)
Given data, produce a vector of bytes.
Definition interface.h:100
goby::middleware::julia::PubSubLayer layer
Definition application.h:58
static bool using_sim_time
Enables simulation time if true (if false, none of the remaining parameters are used)
Definition simulation.h:38
static std::chrono::system_clock::time_point reference_time
Reference time when calculating SystemClock::now(). If this is unset, the default is 1 January of the...
Definition simulation.h:42
static int warp_factor
Warp factor to speed up (or slow time) the time values returned by SteadyClock::now() and SystemClock...
Definition simulation.h:40