• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

BehaviorTree / BehaviorTree.CPP / 21685310357

04 Feb 2026 07:27PM UTC coverage: 78.018% (-1.8%) from 79.835%
21685310357

Pull #1109

github

web-flow
Merge 1450df827 into facf5a0f4
Pull Request #1109: Fix clang-tidy warnings across tests, examples, and samples

0 of 2 new or added lines in 1 file covered. (0.0%)

107 existing lines in 2 files now uncovered.

4614 of 5914 relevant lines covered (78.02%)

22473.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/include/behaviortree_cpp/loggers/groot2_protocol.h
1
#pragma once
2

3
#include "behaviortree_cpp/basic_types.h"
4
#include "behaviortree_cpp/contrib/json.hpp"
5

6
#include <array>
7
#include <condition_variable>
8
#include <cstdint>
9
#include <cstring>
10
#include <memory>
11
#include <mutex>
12
#include <random>
13
#include <stdexcept>
14

15
namespace BT::Monitor
16
{
17

18
/*
19
 * All the messages exchange with the BT executor are multipart ZMQ request-replies.
20
 *
21
 * The first part of the request and the reply have fixed size and are described below.
22
 * The request and reply must have the same value of the fields:
23
 *
24
 *  - request_id
25
 *  - request_type
26
 *  - protocol_id
27
 */
28

29
enum RequestType : uint8_t
30
{
31
  // Request the entire tree definition as XML
32
  FULLTREE = 'T',
33
  // Request the status of all the nodes
34
  STATUS = 'S',
35
  // retrieve the values in a set of blackboards
36
  BLACKBOARD = 'B',
37

38
  // Groot requests the insertion of a hook
39
  HOOK_INSERT = 'I',
40
  // Groot requests to remove a hook
41
  HOOK_REMOVE = 'R',
42
  // Notify Groot that we reached a breakpoint
43
  BREAKPOINT_REACHED = 'N',
44
  // Groot will unlock a breakpoint
45
  BREAKPOINT_UNLOCK = 'U',
46
  // receive the existing hooks in JSON format
47
  HOOKS_DUMP = 'D',
48

49
  // Remove all hooks. To be done before disconnecting Groot
50
  REMOVE_ALL_HOOKS = 'A',
51

52
  DISABLE_ALL_HOOKS = 'X',
53

54
  // start/stop recordong
55
  TOGGLE_RECORDING = 'r',
56
  // get all transitions when recording
57
  GET_TRANSITIONS = 't',
58

59
  UNDEFINED = 0,
60
};
61

62
inline const char* ToString(const RequestType& type)
63
{
64
  switch(type)
65
  {
66
    case RequestType::FULLTREE:
67
      return "full_tree";
68
    case RequestType::STATUS:
69
      return "status";
70
    case RequestType::BLACKBOARD:
71
      return "blackboard";
72

73
    case RequestType::HOOK_INSERT:
74
      return "hook_insert";
75
    case RequestType::HOOK_REMOVE:
76
      return "hook_remove";
77
    case RequestType::BREAKPOINT_REACHED:
78
      return "breakpoint_reached";
79
    case RequestType::BREAKPOINT_UNLOCK:
80
      return "breakpoint_unlock";
81
    case RequestType::REMOVE_ALL_HOOKS:
82
      return "hooks_remove_all";
83
    case RequestType::HOOKS_DUMP:
84
      return "hooks_dump";
85
    case RequestType::DISABLE_ALL_HOOKS:
86
      return "disable_hooks";
87
    case RequestType::TOGGLE_RECORDING:
88
      return "toggle_recording";
89
    case RequestType::GET_TRANSITIONS:
90
      return "get_transitions";
91

92
    case RequestType::UNDEFINED:
93
      return "undefined";
94
  }
95
  return "undefined";
96
}
97

98
constexpr uint8_t kProtocolID = 2;
99
using TreeUniqueUUID = std::array<char, 16>;
100

101
struct RequestHeader
102
{
103
  uint32_t unique_id = 0;
104
  uint8_t protocol = kProtocolID;
105
  RequestType type = RequestType::UNDEFINED;
106

107
  static size_t size()
×
108
  {
109
    return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t);
×
110
  }
111

112
  RequestHeader() = default;
113

114
  RequestHeader(RequestType type) : type(type)
×
115
  {
116
    // a random number for request_id will do
117
    static std::random_device rd;
×
118
    std::mt19937 mt(rd());
×
119
    std::uniform_int_distribution<uint32_t> dist;
×
120
    unique_id = dist(mt);
×
121
  }
×
122

123
  bool operator==(const RequestHeader& other) const
124
  {
125
    return type == other.type && unique_id == other.unique_id;
126
  }
127
  bool operator!=(const RequestHeader& other) const
128
  {
129
    return !(*this == other);
130
  }
131
};
132

133
struct ReplyHeader
134
{
135
  RequestHeader request;
136
  TreeUniqueUUID tree_id = {};
137

138
  static size_t size()
139
  {
140
    return RequestHeader::size() + 16;
141
  }
142
};
143

144
template <typename T>
UNCOV
145
inline unsigned Serialize(char* buffer, unsigned offset, T value)
×
146
{
UNCOV
147
  memcpy(buffer + offset, &value, sizeof(T));
×
UNCOV
148
  return sizeof(T);
×
149
}
150

151
template <typename T>
152
inline unsigned Deserialize(const char* buffer, unsigned offset, T& value)
×
153
{
154
  memcpy(&value, buffer + offset, sizeof(T));
×
155
  return sizeof(T);
×
156
}
157

158
inline std::string SerializeHeader(const RequestHeader& header)
×
159
{
160
  std::string buffer;
×
161
  buffer.resize(6);
×
162
  unsigned offset = 0;
×
163
  offset += Serialize(buffer.data(), offset, header.protocol);
×
164
  offset += Serialize(buffer.data(), offset, uint8_t(header.type));
×
165
  offset += Serialize(buffer.data(), offset, header.unique_id);
×
166
  return buffer;
×
167
}
×
168

169
inline std::string SerializeHeader(const ReplyHeader& header)
×
170
{
171
  // copy the first part directly (6 bytes)
172
  std::string buffer = SerializeHeader(header.request);
×
173
  // add the following 16 bytes
174
  unsigned const offset = 6;
×
175
  buffer.resize(offset + 16);
×
176
  Serialize(buffer.data(), offset, header.tree_id);
×
177
  return buffer;
×
178
}
×
179

180
inline RequestHeader DeserializeRequestHeader(const std::string& buffer)
×
181
{
182
  RequestHeader header;
×
183
  unsigned offset = 0;
×
184
  offset += Deserialize(buffer.data(), offset, header.protocol);
×
185
  uint8_t type = 0;
×
186
  offset += Deserialize(buffer.data(), offset, type);
×
187
  header.type = static_cast<Monitor::RequestType>(type);
×
188
  offset += Deserialize(buffer.data(), offset, header.unique_id);
×
189
  return header;
×
190
}
191

192
inline ReplyHeader DeserializeReplyHeader(const std::string& buffer)
193
{
194
  ReplyHeader header;
195
  header.request = DeserializeRequestHeader(buffer);
196
  unsigned const offset = 6;
197
  Deserialize(buffer.data(), offset, header.tree_id);
198
  return header;
199
}
200

201
struct Hook
202
{
203
  using Ptr = std::shared_ptr<Hook>;
204

205
  // used to enable/disable the breakpoint
206
  bool enabled = true;
207

208
  enum class Position
209
  {
210
    PRE = 0,
211
    POST = 1
212
  };
213

214
  Position position = Position::PRE;
215

216
  uint16_t node_uid = 0;
217

218
  enum class Mode
219
  {
220
    BREAKPOINT = 0,
221
    REPLACE = 1
222
  };
223

224
  // interactive breakpoints are unblocked using unlockBreakpoint()
225
  Mode mode = Mode::BREAKPOINT;
226

227
  // used by interactive breakpoints to wait for unlocking
228
  std::condition_variable wakeup;
229

230
  std::mutex mutex;
231

232
  // set to true to unlock an interactive breakpoint
233
  bool ready = false;
234

235
  // once finished self-destroy
236
  bool remove_when_done = false;
237

238
  // result to be returned
239
  NodeStatus desired_status = NodeStatus::SKIPPED;
240
};
241

242
inline void to_json(nlohmann::json& js, const Hook& bp)
×
243
{
244
  js = nlohmann::json{ { "enabled", bp.enabled },
×
245
                       { "uid", bp.node_uid },
×
246
                       { "mode", int(bp.mode) },
×
247
                       { "once", bp.remove_when_done },
×
248
                       { "desired_status", toStr(bp.desired_status) },
×
249
                       { "position", int(bp.position) } };
×
250
}
×
251

252
inline void from_json(const nlohmann::json& js, Hook& bp)
×
253
{
254
  js.at("enabled").get_to(bp.enabled);
×
255
  js.at("uid").get_to(bp.node_uid);
×
256
  js.at("once").get_to(bp.remove_when_done);
×
257
  bp.mode = static_cast<Hook::Mode>(js.at("mode").get<int>());
×
258
  bp.position = static_cast<Hook::Position>(js.at("position").get<int>());
×
259

260
  const std::string desired_value = js.at("desired_status").get<std::string>();
×
261
  bp.desired_status = convertFromString<NodeStatus>(desired_value);
×
262
}
×
263

264
}  // namespace BT::Monitor
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc