0.5.1
Loading...
Searching...
No Matches
ArubaSensor.cpp
Go to the documentation of this file.
1// This file is part of INSTINCT, the INS Toolkit for Integrated
2// Navigation Concepts and Training by the Institute of Navigation of
3// the University of Stuttgart, Germany.
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9#include "ArubaSensor.hpp"
10
12#include "util/Logger.hpp"
13#include <libssh/libssh.h>
14#include <regex>
15#include <sstream>
16
18
20
22 : Node(typeStatic())
23{
24 LOG_TRACE("{}: called", name);
25
26 _onlyRealTime = true;
27 _hasConfig = true;
28 _guiConfigDefaultWindowSize = { 710, 220 };
29
31}
32
34{
35 LOG_TRACE("{}: called", nameId());
36}
37
39{
40 return "ArubaSensor";
41}
42
43std::string NAV::ArubaSensor::type() const
44{
45 return typeStatic();
46}
47
49{
50 return "Data Provider";
51}
52
54{
55 if (ImGui::InputTextWithHint("SSH Host", "192.168.0.0", &_sshHost))
56 {
57 LOG_DEBUG("{}: ssh host changed to {}", nameId(), _sshHost);
60 }
61 if (ImGui::InputTextWithHint("SSH User", "admin", &_sshUser))
62 {
63 LOG_DEBUG("{}: ssh admin changed to {}", nameId(), _sshUser);
66 }
67 if (ImGui::InputText("SSH Password", &_sshPassword))
68 {
69 LOG_DEBUG("{}: ssh password changed to {}", nameId(), _sshPassword);
72 }
73 if (ImGui::InputText("SSH Host Keys", &_sshHostkeys))
74 {
75 LOG_DEBUG("{}: ssh host keys changed to {}", nameId(), _sshHostkeys);
78 }
79 if (ImGui::InputText("SSH Key Exchange", &_sshKeyExchange))
80 {
81 LOG_DEBUG("{}: ssh key exchange changed to {}", nameId(), _sshKeyExchange);
84 }
85 if (ImGui::InputText("SSH Publickey Accepted Types", &_sshPublickeyAcceptedTypes))
86 {
87 LOG_DEBUG("{}: ssh publickey accepted types changed to {}", nameId(), _sshPublickeyAcceptedTypes);
90 }
91 ImGui::Spacing(); // Add spacing here
92 ImGui::Separator(); // Add a horizontal line
93 if (ImGui::InputInt("Output interval [ms]", &_outputInterval))
94 {
95 LOG_DEBUG("{}: output interval changed to {}", nameId(), _outputInterval);
97 }
98}
99
100[[nodiscard]] json NAV::ArubaSensor::save() const
101{
102 LOG_TRACE("{}: called", nameId());
103
104 json j;
105
106 j["sshHost"] = _sshHost;
107 j["sshUser"] = _sshUser;
108 j["sshPassword"] = _sshPassword;
109 j["sshHostkeys"] = _sshHostkeys;
110 j["sshKeyExchange"] = _sshKeyExchange;
111 j["sshPublickeyAcceptedTypes"] = _sshPublickeyAcceptedTypes;
112 j["outputInterval"] = _outputInterval;
113
114 return j;
115}
116
118{
119 LOG_TRACE("{}: called", nameId());
120
121 if (j.contains("sshHost"))
122 {
123 j.at("sshHost").get_to(_sshHost);
124 }
125 if (j.contains("sshUser"))
126 {
127 j.at("sshUser").get_to(_sshUser);
128 }
129 if (j.contains("sshPassword"))
130 {
131 j.at("sshPassword").get_to(_sshPassword);
132 }
133 if (j.contains("sshHostkeys"))
134 {
135 j.at("sshHostkeys").get_to(_sshHostkeys);
136 }
137 if (j.contains("sshKeyExchange"))
138 {
139 j.at("sshKeyExchange").get_to(_sshKeyExchange);
140 }
141 if (j.contains("sshPublickeyAcceptedTypes"))
142 {
143 j.at("sshPublickeyAcceptedTypes").get_to(_sshPublickeyAcceptedTypes);
144 }
145 if (j.contains("outputInterval"))
146 {
147 j.at("outputInterval").get_to(_outputInterval);
148 }
149}
150
152{
153 return true;
154}
155
157{
158 LOG_TRACE("{}: called", nameId());
159
160 // SSH session
161 _session = ssh_new();
162 if (_session == nullptr)
163 {
164 LOG_INFO("{}: Failed to create SSH _session", nameId());
165 return false;
166 }
167 LOG_DEBUG("{}: Successfully created SSH _session", nameId());
168
169 ssh_options_set(_session, SSH_OPTIONS_HOST, "192.168.178.45");
170 ssh_options_set(_session, SSH_OPTIONS_USER, "admin");
171 ssh_options_set(_session, SSH_OPTIONS_HOSTKEYS, "ssh-rsa");
172 ssh_options_set(_session, SSH_OPTIONS_KEY_EXCHANGE, "ecdh-sha2-nistp256");
173 ssh_options_set(_session, SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES, "ssh-rsa");
174
175 // connect
176 if (ssh_connect(_session) != SSH_OK)
177 {
178 LOG_INFO("{}: Failed to connect to the router", nameId());
179 ssh_free(_session);
180 return false;
181 }
182 LOG_DEBUG("{}: Successfully connected to the router", nameId());
183
184 // authenticate
185 if (ssh_userauth_password(_session, nullptr, _sshPassword.c_str()) != SSH_AUTH_SUCCESS)
186 {
187 LOG_INFO("{}: Authentication failed", nameId());
188 ssh_disconnect(_session);
189 ssh_free(_session);
190 return false;
191 }
192 LOG_DEBUG("{}: Authentication succeeded", nameId());
193
194 // channel
195 _channel = ssh_channel_new(_session);
196 if (_channel == nullptr)
197 {
198 LOG_INFO("{}: Failed to create SSH channel", nameId());
199 ssh_disconnect(_session);
200 ssh_free(_session);
201 return false;
202 }
203 LOG_DEBUG("{}: Successfully created SSH channel", nameId());
204
205 // open _session
206 if (ssh_channel_open_session(_channel) != SSH_OK)
207 {
208 LOG_INFO("{}: Failed to open an SSH _session", nameId());
209 ssh_channel_free(_channel);
210 ssh_disconnect(_session);
211 ssh_free(_session);
212 return false;
213 }
214 LOG_DEBUG("{}: Successfully opened an SSH _session", nameId());
215
216 // pty
217 if (ssh_channel_request_pty(_channel) != SSH_OK)
218 {
219 LOG_INFO("{}: Failed to open pty", nameId());
220 ssh_channel_free(_channel);
221 ssh_disconnect(_session);
222 ssh_free(_session);
223 return false;
224 }
225 LOG_DEBUG("{}: Successfully opened pty", nameId());
226
227 // shell
228 if (ssh_channel_request_shell(_channel) != SSH_OK)
229 {
230 LOG_INFO("{}: Failed to open shell", nameId());
231 ssh_channel_free(_channel);
232 ssh_disconnect(_session);
233 ssh_free(_session);
234 return false;
235 }
236 LOG_DEBUG("{}: Successfully opened shell", nameId());
237
239
240 return true;
241}
242
244{
245 LOG_TRACE("{}: called", nameId());
246
247 if (!isInitialized())
248 {
249 return;
250 }
251
252 ssh_channel_write(_channel, "exit\n", strlen("exit\n"));
253 ssh_channel_free(_channel);
254 ssh_disconnect(_session);
255 ssh_free(_session);
256
257 if (_timer.is_running())
258 {
259 _timer.stop();
260 }
261}
262
264{
265 auto* node = static_cast<ArubaSensor*>(userData);
266 auto obs = std::make_shared<WiFiObs>();
267
268 std::array<char, 1024> buffer{};
269 std::string receivedData;
270 size_t bytesRead = 0;
271 // Send command to access point
272 ssh_channel_write(node->_channel, "show ap range scanning-results\n", strlen("show ap range scanning-results\n"));
273 // Read output
274 do {
275 bytesRead = static_cast<size_t>(ssh_channel_read_timeout(node->_channel, buffer.data(), sizeof(buffer), 0, 10)); // timeout in ms
276 if (bytesRead > 0)
277 {
278 receivedData.append(buffer.data(), bytesRead);
279 }
280 } while (bytesRead > 0);
281 // Send command to clear output
282 ssh_channel_write(node->_channel, "clear range-scanning-result\n", strlen("clear range-scanning-result\n"));
283
284 // Parse the received data
285 std::istringstream iss(receivedData);
286 std::string line;
287
288 while (std::getline(iss, line) && line.find("Peer-bssid") == std::string::npos) {} // Skip lines until the header "Peer-bssid" is found
289
290 // Skip the header lines
291 std::getline(iss, line);
292 std::getline(iss, line);
293
294 // MAC address validation
295 std::regex macRegex("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$");
296
297 while (std::getline(iss, line) && !line.empty())
298 {
299 std::istringstream lineStream(line);
300 std::string value;
301 std::string macAddress;
302 lineStream >> macAddress;
303
304 int rtt = 0;
305 int rssi = 0;
306 int stdValue = 0;
307
308 lineStream >> rtt >> rssi >> stdValue;
309
310 std::regex timeRegex(R"(\d{4}-\d{2}-\d{2})"); // Time format: YYYY-MM-DD
311 std::string timeStamp1;
312 std::string timeStamp2;
313 lineStream >> timeStamp1;
314 lineStream >> timeStamp2;
315 while (lineStream >> value)
316 {
317 if (std::regex_match(value, timeRegex)) // Check if the value is a time stamp
318 {
319 timeStamp1 = value;
320 break;
321 }
322 }
323 lineStream >> value;
324 timeStamp2 = value;
325 double measuredDistance = static_cast<double>(rtt) * 1e-9 / 2 * InsConst::C_AIR;
326 double measuredDistanceStd = static_cast<double>(stdValue) * 1e-9 / 2 * InsConst::C_AIR;
327 if (std::regex_match(macAddress, macRegex)) // Check if the MAC address is valid
328 {
329 InsTime_YMDHMS yearMonthDayHMS(std::stoi(timeStamp1.substr(0, 4)), std::stoi(timeStamp1.substr(5, 2)), std::stoi(timeStamp1.substr(8, 2)), std::stoi(timeStamp2.substr(0, 2)), std::stoi(timeStamp2.substr(3, 2)), std::stoi(timeStamp2.substr(6, 2)));
330 InsTime timeOfMeasurement(yearMonthDayHMS, UTC);
331 std::ranges::transform(macAddress, macAddress.begin(), ::toupper); // Convert to uppercase
332 obs->distance = measuredDistance;
333 obs->distanceStd = measuredDistanceStd;
334 obs->macAddress = macAddress;
335 obs->insTime = timeOfMeasurement;
336 // obs->insTime = util::time::GetCurrentInsTime(); // if you want to use the instinct time instead
337 node->invokeCallbacks(OUTPUT_PORT_INDEX_WIFI_OBS, obs);
338 }
339 }
340}
Aruba Sensor Class.
Save/Load the Nodes.
nlohmann::json json
json namespace
Utility class for logging to console and file.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
Definition Logger.hpp:67
#define LOG_INFO
Info to the user on the state of the program.
Definition Logger.hpp:69
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Definition Logger.hpp:65
Keeps track of the current real/simulation time.
Espressif Observation Class.
std::string type() const override
String representation of the Class Type.
std::string _sshHost
Ssh options.
ssh_session _session
SSH session.
static constexpr size_t OUTPUT_PORT_INDEX_WIFI_OBS
Flow (WiFiObs)
CallbackTimer _timer
Timer object to handle async data requests.
~ArubaSensor() override
Destructor.
void guiConfig() override
ImGui config window which is shown on double click.
std::string _sshPublickeyAcceptedTypes
Public key type.
static void readSensorDataThread(void *userData)
Function which performs the async data reading.
void restore(const json &j) override
Restores the node from a json object.
void deinitialize() override
Deinitialize the node.
static std::string category()
String representation of the Class Category.
static std::string typeStatic()
String representation of the Class Type.
json save() const override
Saves the node into a json object.
std::string _sshHostkeys
SSH encryption.
std::string _sshPassword
User credentials.
ArubaSensor()
Default constructor.
std::string _sshKeyExchange
Key exchange.
ssh_channel _channel
SSH channel.
bool resetNode() override
Resets the node. It is guaranteed that the node is initialized when this is called.
int _outputInterval
Output interval in ms.
std::string _sshUser
User name.
bool initialize() override
Initialize the node.
static constexpr double C_AIR
Speed of light in air: CGPM defined speed of light divided by approximate refractory index of dry air...
Definition Constants.hpp:37
The class is responsible for all time-related tasks.
Definition InsTime.hpp:710
bool isInitialized() const
Checks if the node is initialized.
Definition Node.cpp:574
bool doDeinitialize(bool wait=false)
Asks the node worker to deinitialize the node.
Definition Node.cpp:465
ImVec2 _guiConfigDefaultWindowSize
Definition Node.hpp:522
Node(std::string name)
Constructor.
Definition Node.cpp:29
OutputPin * CreateOutputPin(const char *name, Pin::Type pinType, const std::vector< std::string > &dataIdentifier, OutputPin::PinData data=static_cast< void * >(nullptr), int idx=-1)
Create an Output Pin object.
Definition Node.cpp:278
std::string nameId() const
Node name and id.
Definition Node.cpp:323
std::string name
Name of the Node.
Definition Node.hpp:507
bool _onlyRealTime
Whether the node can run in post-processing or only real-time.
Definition Node.hpp:531
bool _hasConfig
Flag if the config window should be shown.
Definition Node.hpp:525
static std::string type()
Returns the type of the data class.
Definition WiFiObs.hpp:27
void ApplyChanges()
Signals that there have been changes to the flow.
@ UTC
Coordinated Universal Time.
Universal Time Coordinated [UTC].
Definition InsTime.hpp:465
@ Flow
NodeData Trigger.
Definition Pin.hpp:52