Goby3 3.3.0
2025.07.10
Loading...
Searching...
No Matches
application.h
Go to the documentation of this file.
1// Copyright 2025:
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 void loop() override
50 {
51 if (loop_)
52 (*loop_)();
53 }
54
55 void set_loop_function_name(std::string loop_function)
56 {
57 if (!loop_function.empty())
58 loop_ = std::make_unique<jlcxx::JuliaFunction>(loop_function);
59 }
60
61 private:
62 std::unique_ptr<jlcxx::JuliaFunction> loop_;
63};
64
72
73bool operator==(const Identifier& i1, const Identifier& i2)
74{
75 return i1.layer == i2.layer && i1.type_name == i2.type_name && i1.scheme == i2.scheme &&
76 i1.group == i2.group;
77}
78
79template <typename App> class ApplicationWrapper
80{
81 public:
82 ApplicationWrapper(std::string config) : ApplicationWrapper(config, std::string()) {}
83 ApplicationWrapper(std::string config, std::string loop_function_name)
84 {
85 typename App::ConfigType cfg;
86 google::protobuf::TextFormat::Parser parser;
87 goby::util::FlexOStreamErrorCollector error_collector(config);
88 parser.RecordErrorsTo(&error_collector);
89 parser.AllowPartialMessage(false);
90 parser.ParseFromString(config, &cfg);
91
92 App::app_cfg_.reset(new typename App::ConfigType(cfg));
93 App::app3_base_configuration_.reset(new goby::middleware::protobuf::AppConfig(cfg.app()));
94
95 // TODO - don't copy from middleware/application/interface.h if possible
96 if (App::app3_base_configuration_->simulation().time().use_sim_time())
97 {
100 App::app3_base_configuration_->simulation().time().warp_factor();
101 if (App::app3_base_configuration_->simulation().time().has_reference_microtime())
103 std::chrono::system_clock::time_point(std::chrono::microseconds(
104 App::app3_base_configuration_->simulation().time().reference_microtime()));
105 }
106
107 app_ptr_.reset(new App);
108 app_ptr_->set_loop_function_name(loop_function_name);
109 }
110
111 void run() { app_ptr_->__run(); }
112
113 ApplicationWrapper& interprocess() { return *this; }
114
115 void publish(PubSubLayer layer, std::string type_name, int scheme, std::string group,
116 const std::vector<std::uint8_t>& bytes)
117 {
118 app_ptr_->publish(Identifier(layer, type_name, scheme, group), bytes);
119 }
120
121 void subscribe(PubSubLayer layer, std::string type_name, int scheme, std::string group,
122 std::string func, std::string module)
123 {
124 app_ptr_->subscribe(Identifier(layer, type_name, scheme, group), func, module);
125 }
126
127 private:
128 std::unique_ptr<App> app_ptr_;
129 std::map<std::string, goby::middleware::DynamicGroup> subscription_groups_;
130};
131
132template <typename App>
133inline void define_julia_module(jlcxx::Module& types, const std::string& app_name)
134{
135 types.add_bits<PubSubLayer>("PubSubLayer", jlcxx::julia_type("CppEnum"));
136 types.set_const("INTERTHREAD", PubSubLayer::INTERTHREAD);
137 types.set_const("INTERPROCESS", PubSubLayer::INTERPROCESS);
138 types.set_const("INTERMODULE", PubSubLayer::INTERMODULE);
139
140 types.add_bits<MarshallingScheme::MarshallingSchemeEnum>("MarshallingScheme",
141 jlcxx::julia_type("CppEnum"));
142 types.set_const("NULL_SCHEME", MarshallingScheme::NULL_SCHEME);
143 types.set_const("PROTOBUF", MarshallingScheme::PROTOBUF);
144 types.set_const("JSON", MarshallingScheme::JSON);
145
146 types.template add_type<ApplicationWrapper<App>>(app_name)
147 .template constructor<std::string>()
148 .template constructor<std::string, std::string>()
149 .method("run", &ApplicationWrapper<App>::run)
150 .method("cxx_publish", &ApplicationWrapper<App>::publish)
151 .method("cxx_subscribe", &ApplicationWrapper<App>::subscribe);
152}
153
154template <typename DataType, int scheme>
155std::vector<std::uint8_t> serialize_uint8(const DataType& msg)
156{
157 std::vector<char> out =
159 return std::vector<std::uint8_t>(out.begin(), out.end());
160}
161
162} // namespace julia
163} // namespace middleware
164} // namespace goby
165
166std::ostream& operator<<(std::ostream& os, const goby::middleware::julia::Identifier& i)
167{
168 std::string layer;
169
170 switch (i.layer)
171 {
172 case goby::middleware::julia::PubSubLayer::INTERTHREAD: layer = "interthread"; break;
173 case goby::middleware::julia::PubSubLayer::INTERPROCESS: layer = "interprocess"; break;
174 case goby::middleware::julia::PubSubLayer::INTERMODULE: layer = "intermodule"; break;
175 }
176
177 return (os << "layer: " << layer << ", type_name: \"" << i.type_name
179 << ", group: \"" << i.group << "\"");
180}
181
182// Macros for use by the autogenerated code to define the C++ side of the pub/sub setup
183#define GOBY_JULIA_IF_PUBLICATION(SCHEME, LAYER_ENUM, LAYER_FUNCTION, GROUP, TYPE) \
184 if (id == goby::middleware::julia::Identifier{ \
185 goby::middleware::julia::PubSubLayer::LAYER_ENUM, TYPE::descriptor()->name(), \
186 goby::middleware::MarshallingScheme::SCHEME, GROUP}) \
187 { \
188 decltype(bytes.end()) actual_end; \
189 auto msg = goby::middleware::SerializerParserHelper< \
190 TYPE, goby::middleware::MarshallingScheme::SCHEME>::parse(bytes.begin(), bytes.end(), \
191 actual_end); \
192 LAYER_FUNCTION().publish<GROUP>(msg); \
193 return; \
194 }
195
196#define GOBY_JULIA_IF_SUBSCRIPTION(SCHEME, LAYER_ENUM, LAYER_FUNCTION, GROUP, TYPE) \
197 if (id == goby::middleware::julia::Identifier( \
198 goby::middleware::julia::PubSubLayer::LAYER_ENUM, TYPE::descriptor()->name(), \
199 goby::middleware::MarshallingScheme::SCHEME, GROUP)) \
200 { \
201 LAYER_FUNCTION().subscribe<GROUP>( \
202 [=](const TYPE& pb) \
203 { \
204 std::vector<std::uint8_t> bytes = goby::middleware::julia::serialize_uint8< \
205 TYPE, goby::middleware::MarshallingScheme::SCHEME>(pb); \
206 jlcxx::JuliaFunction cb(func, module); \
207 cb(id.layer, id.type_name, id.scheme, id.group, bytes); \
208 }); \
209 return; \
210 }
211
212#define GOBY_JULIA_FAIL(PUBLISH_OR_SUBSCRIBE) \
213 goby::glog.is_die() && \
214 goby::glog << PUBLISH_OR_SUBSCRIBE " not defined for these parameters: [" << id \
215 << "]. Please include in interfaces.yml and re-generate to include them." \
216 << std::endl;
217
218// used to stringify application name
219#define GOBY_JULIA_QUOTE(name) #name
220#define GOBY_JULIA_DEFINE_MODULE(APPLICATION_NAME) \
221 JLCXX_MODULE define_julia_module(jlcxx::Module& types) \
222 { \
223 goby::middleware::julia::define_julia_module<APPLICATION_NAME>( \
224 types, GOBY_JULIA_QUOTE(APPLICATION_NAME)); \
225 }
ApplicationWrapper(std::string config, std::string loop_function_name)
Definition application.h:83
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)
void set_loop_function_name(std::string loop_function)
Definition application.h:55
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:73
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
STL namespace.
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:67
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