Instrument Neutral Distributed Interface INDI 2.2.5
instrumentation.h
Go to the documentation of this file.
1/*
2 Gemini Power Box Hub Advanced v3 INDI Driver
3
4 Copyright (C) 2026 Dieter R Kedrowitsch <[email protected]>
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2 of the License, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 You should have received a copy of the GNU General Public License along with
17 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 The full GNU General Public License is included in this distribution in the
21 file called LICENSE.
22*/
23
24#pragma once
25
26#include <atomic>
27#include <chrono>
28#include <condition_variable>
29#include <cstdint>
30#include <functional>
31#include <memory>
32#include <mutex>
33#include <string>
34#include <variant>
35#include <vector>
36
38{
39
40enum class Level
41{
42 Off = 0,
43 Error,
44 Info,
46 Verbose,
47 Trace
48};
49
63
71
72enum class FrameDirection { Tx, Rx };
75
87
99
101{
102 Starting,
104 Succeeded,
105 Cancelled,
107};
108
121
122using Value = std::variant<std::monostate, bool, std::int64_t, std::uint64_t, double, std::string>;
123
125{
126 std::string name;
128};
129
131{
132 std::string name;
135};
136
142
144{
146 std::string frame;
147 std::string token;
148 bool complete = true;
149};
150
152{
153 std::string frameType;
154 std::uint64_t sequence = 0;
155 std::vector<NamedValue> fields;
156};
157
159{
160 std::uint64_t sequence = 0;
161 std::vector<FieldChange> changes;
162};
163
171
177
184
186{
187 unsigned attempt = 0;
188 unsigned maxAttempts = 0;
189 std::chrono::milliseconds delayBeforeAttempt{0};
190 bool finalAttempt = false;
192};
193
195{
197 std::chrono::microseconds duration{0};
198 bool success = false;
199};
200
201using Payload = std::variant <
211
212struct Event
213{
216 std::chrono::system_clock::time_point wallTime;
217 std::chrono::steady_clock::time_point steadyTime;
218 std::string source;
219 std::uint64_t connectionGeneration = 0;
220 std::uint64_t sequence = 0;
222};
223
225{
226 public:
227 using Listener = std::function<void(const Event &)>;
228 using ListenerHandle = std::uint64_t;
229
231 ~Dispatcher();
232
233 Dispatcher(const Dispatcher &) = delete;
234 Dispatcher &operator=(const Dispatcher &) = delete;
235 Dispatcher(Dispatcher &&) = delete;
237
238 void setLevel(Level level);
239 Level level() const;
240 bool enabled(Level eventLevel) const;
241
243 bool removeListener(ListenerHandle handle);
244
245 void emit(Event event) noexcept;
246
247 private:
248 struct ListenerEntry;
249
250 void beginDispatch();
251 void endDispatch();
252
253 std::atomic<Level> level_{Level::Off};
254 std::atomic<std::size_t> listenerCount_{0};
255 std::mutex listenerMutex_;
256 std::vector<std::shared_ptr<ListenerEntry>> listeners_;
257 ListenerHandle nextListenerHandle_ = 1;
258
259 std::mutex dispatchMutex_;
260 std::condition_variable dispatchCv_;
261 bool dispatchInProgress_ = false;
262};
263
264Event makeEvent(Level level, EventType type, Payload payload);
265
266const char *toString(Level level);
267const char *toString(EventType type);
268const char *toString(ConnectionState state);
269const char *toString(FrameDirection direction);
270const char *toString(VerificationOperation operation);
271const char *toString(VerificationOutcome outcome);
272const char *toString(WarningCode code);
273const char *toString(ParserAnomalyCode code);
274const char *toString(ReconnectResult result);
275const char *toString(TimingOperation operation);
276
277std::string formatValue(const Value &value);
278std::string escapeFrame(const std::string &frame);
279
281{
282 public:
283 std::string format(const Event &event) const;
284};
285
287{
288 public:
289 using Sink = std::function<void(Level, const std::string &)>;
290
291 EventLogger() = default;
292 explicit EventLogger(Sink sink);
293
294 void setSink(Sink sink);
295 void operator()(const Event &event) const noexcept;
296
297 private:
298 Sink sink_;
299 EventFormatter formatter_;
300};
301
302} // namespace geminipbh::instrumentation
Dispatcher & operator=(const Dispatcher &)=delete
ListenerHandle registerListener(Listener listener)
Dispatcher(const Dispatcher &)=delete
bool removeListener(ListenerHandle handle)
std::function< void(const Event &)> Listener
Dispatcher & operator=(Dispatcher &&)=delete
bool enabled(Level eventLevel) const
std::string format(const Event &event) const
std::function< void(Level, const std::string &)> Sink
void operator()(const Event &event) const noexcept
const char * toString(Level level)
std::string escapeFrame(const std::string &frame)
std::string formatValue(const Value &value)
std::variant< ConnectionPayload, FramePayload, StatusDecodedPayload, FieldChangesPayload, VerificationPayload, WarningPayload, ParserAnomalyPayload, ReconnectAttemptPayload, TimingPayload > Payload
Event makeEvent(Level level, EventType type, Payload payload)
std::variant< std::monostate, bool, std::int64_t, std::uint64_t, double, std::string > Value
uint16_t type
Definition pwc-ioctl.h:0
std::chrono::system_clock::time_point wallTime
std::chrono::steady_clock::time_point steadyTime