INSTINCT Code Coverage Report


Directory: src/
File: Nodes/DataLink/udpSend.cpp
Date: 2025-07-19 10:51:51
Exec Total Coverage
Lines: 12 104 11.5%
Functions: 4 13 30.8%
Branches: 9 188 4.8%

Line Branch Exec Source
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 "udpSend.hpp"
10
11 #include "NodeData/GNSS/GnssObs.hpp"
12 #include "NodeData/State/PosVelAtt.hpp"
13 #include "internal/Node/Pin.hpp"
14 #include "internal/NodeManager.hpp"
15 namespace nm = NAV::NodeManager;
16 #include "internal/FlowManager.hpp"
17 #include "NodeRegistry.hpp"
18
19 #include "util/Logger.hpp"
20 #include "internal/gui/widgets/imgui_ex.hpp"
21 #include "internal/gui/NodeEditorApplication.hpp"
22
23 #include <cstring>
24 #include <string>
25 #include <vector>
26
27 // ---------------------------------------------------------- Private variabels ------------------------------------------------------------
28
29 namespace NAV
30 {
31 /// List of supported data identifiers
32 const std::vector<std::string> supportedDataIdentifier{
33 PosVelAtt::type(),
34 PosVel::type(),
35 Pos::type(),
36 GnssObs::type()
37 };
38
39 } // namespace NAV
40
41 // ---------------------------------------------------------- Member functions -------------------------------------------------------------
42
43 114 NAV::UdpSend::UdpSend()
44
6/12
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 114 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 114 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 114 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 114 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 114 times.
✗ Branch 20 not taken.
114 : Node(typeStatic()), _socket(_io_context, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0)), _resolver(_io_context)
45 {
46 LOG_TRACE("{}: called", name);
47
48 114 _hasConfig = true;
49 114 _guiConfigDefaultWindowSize = { 202, 96 };
50
51
1/2
✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
114 nm::CreateInputPin(this, "Data", Pin::Type::Flow, supportedDataIdentifier, &UdpSend::receiveData);
52 114 }
53
54 228 NAV::UdpSend::~UdpSend()
55 {
56 LOG_TRACE("{}: called", nameId());
57 228 }
58
59 228 std::string NAV::UdpSend::typeStatic()
60 {
61
1/2
✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
456 return "UdpSend";
62 }
63
64 std::string NAV::UdpSend::type() const
65 {
66 return typeStatic();
67 }
68
69 114 std::string NAV::UdpSend::category()
70 {
71
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
228 return "Data Link";
72 }
73
74 void NAV::UdpSend::guiConfig()
75 {
76 ImGui::SetNextItemWidth(150 * gui::NodeEditorApplication::windowFontRatio());
77 if (ImGui::InputInt4L(fmt::format("IPv4##{}", size_t(id)).c_str(), _ip.data(), IP_LIMITS[0], IP_LIMITS[1]))
78 {
79 flow::ApplyChanges();
80 }
81 ImGui::SetNextItemWidth(150 * gui::NodeEditorApplication::windowFontRatio());
82 if (ImGui::InputIntL(fmt::format("Port##{}", size_t(id)).c_str(), &_port, UdpUtil::PORT_LIMITS[0], UdpUtil::PORT_LIMITS[1]))
83 {
84 flow::ApplyChanges();
85 }
86 }
87
88 bool NAV::UdpSend::resetNode()
89 {
90 return true;
91 }
92
93 json NAV::UdpSend::save() const
94 {
95 LOG_TRACE("{}: called", nameId());
96
97 json j;
98
99 j["ip"] = _ip;
100 j["port"] = _port;
101
102 return j;
103 }
104
105 void NAV::UdpSend::restore(json const& j)
106 {
107 LOG_TRACE("{}: called", nameId());
108 if (j.contains("ip"))
109 {
110 j.at("ip").get_to(_ip);
111 }
112 if (j.contains("port"))
113 {
114 j.at("port").get_to(_port);
115 }
116 }
117
118 bool NAV::UdpSend::initialize()
119 {
120 LOG_TRACE("{}: called", nameId());
121
122 std::string ipString{};
123 for (size_t i = 0; i < 4; i++)
124 {
125 ipString.append(std::to_string(_ip.at(i)));
126 i < 3 ? ipString.append(".") : ipString.append("");
127 }
128
129 _endpoints = _resolver.resolve(boost::asio::ip::udp::v4(), ipString, std::to_string(_port));
130
131 return true;
132 }
133
134 void NAV::UdpSend::deinitialize()
135 {
136 _io_context.stop();
137
138 LOG_TRACE("{}: called", nameId());
139 }
140
141 void NAV::UdpSend::receiveData(NAV::InputPin::NodeDataQueue& queue, size_t /* pinIdx */)
142 {
143 auto data = queue.extract_front();
144
145 std::vector<char> data2send{};
146
147 // Identify message type
148 if (NAV::NodeRegistry::NodeDataTypeAnyIsChildOf({ data->getType() }, { PosVelAtt::type() }))
149 {
150 _msgType = UdpUtil::MessageType::PosVelAtt;
151 data2send.resize(UdpUtil::Size::TOTAL_POSVELATT);
152 setMsgTypeAndTime(data2send, data->insTime);
153 }
154 else if (NAV::NodeRegistry::NodeDataTypeAnyIsChildOf({ data->getType() }, { PosVel::type() }))
155 {
156 _msgType = UdpUtil::MessageType::PosVel;
157 data2send.resize(UdpUtil::Size::TOTAL_POSVEL);
158 setMsgTypeAndTime(data2send, data->insTime);
159 }
160 else if (NAV::NodeRegistry::NodeDataTypeAnyIsChildOf({ data->getType() }, { Pos::type() }))
161 {
162 _msgType = UdpUtil::MessageType::Pos;
163 data2send.resize(UdpUtil::Size::TOTAL_POS);
164 setMsgTypeAndTime(data2send, data->insTime);
165 }
166 else if (NAV::NodeRegistry::NodeDataTypeAnyIsChildOf({ data->getType() }, { GnssObs::type() }))
167 {
168 _msgType = UdpUtil::MessageType::GnssObs;
169 }
170
171 // Copy data
172 if (_msgType == UdpUtil::MessageType::Pos)
173 {
174 auto pos = std::static_pointer_cast<const Pos>(data);
175 std::memcpy(data2send.data() + UdpUtil::Offset::POS, pos->lla_position().data(), UdpUtil::Size::POS);
176 }
177 else if (_msgType == UdpUtil::MessageType::PosVel)
178 {
179 auto posVel = std::static_pointer_cast<const PosVel>(data);
180 std::memcpy(data2send.data() + UdpUtil::Offset::POS, posVel->lla_position().data(), UdpUtil::Size::POS);
181 std::memcpy(data2send.data() + UdpUtil::Offset::VEL, posVel->n_velocity().data(), UdpUtil::Size::VEL);
182 }
183 else if (_msgType == UdpUtil::MessageType::PosVelAtt)
184 {
185 auto posVelAtt = std::static_pointer_cast<const PosVelAtt>(data);
186 std::memcpy(data2send.data() + UdpUtil::Offset::POS, posVelAtt->lla_position().data(), UdpUtil::Size::POS);
187 std::memcpy(data2send.data() + UdpUtil::Offset::VEL, posVelAtt->n_velocity().data(), UdpUtil::Size::VEL);
188 std::memcpy(data2send.data() + UdpUtil::Offset::QUAT, &posVelAtt->n_Quat_b().x(), UdpUtil::Size::QUAT);
189 std::memcpy(data2send.data() + UdpUtil::Offset::QUAT + UdpUtil::Size::QUAT, &posVelAtt->n_Quat_b().y(), UdpUtil::Size::QUAT);
190 std::memcpy(data2send.data() + UdpUtil::Offset::QUAT + 2 * UdpUtil::Size::QUAT, &posVelAtt->n_Quat_b().z(), UdpUtil::Size::QUAT);
191 std::memcpy(data2send.data() + UdpUtil::Offset::QUAT + 3 * UdpUtil::Size::QUAT, &posVelAtt->n_Quat_b().w(), UdpUtil::Size::QUAT);
192 }
193 else if (_msgType == UdpUtil::MessageType::GnssObs)
194 {
195 auto gnssObs = std::static_pointer_cast<const GnssObs>(data);
196 const size_t sizeGnssData = UdpUtil::Size::SINGLE_OBSERVATION_DATA * gnssObs->data.size();
197
198 auto sizeTotal = sizeGnssData + UdpUtil::Size::MSGTYPE + UdpUtil::Size::GPSCYCLE + UdpUtil::Size::GPSWEEK + UdpUtil::Size::GPSTOW + UdpUtil::Size::SIZE;
199 if (sizeTotal > UdpUtil::MAXIMUM_BYTES)
200 {
201 LOG_ERROR("{}: gnssObs msg is bigger than the maximum size of a single UDP package: {} bytes.", nameId(), sizeTotal);
202 }
203
204 data2send.resize(sizeTotal);
205
206 setMsgTypeAndTime(data2send, data->insTime);
207
208 std::memcpy(data2send.data() + UdpUtil::Offset::SIZE, &sizeGnssData, UdpUtil::Size::SIZE);
209 std::memcpy(data2send.data() + UdpUtil::Offset::GNSSDATA, gnssObs->data.data(), sizeGnssData);
210 }
211 _socket.send_to(boost::asio::buffer(data2send), *_endpoints.begin());
212 }
213
214 void NAV::UdpSend::setMsgTypeAndTime(std::vector<char>& data2send, const InsTime& insTime)
215 {
216 auto gpsCycle = insTime.toGPSweekTow().gpsCycle;
217 auto gpsWeek = insTime.toGPSweekTow().gpsWeek;
218 auto gpsTow = static_cast<double>(insTime.toGPSweekTow().tow);
219
220 std::memcpy(data2send.data(), &_msgType, UdpUtil::Size::MSGTYPE);
221
222 std::memcpy(data2send.data() + UdpUtil::Offset::GPSCYCLE, &gpsCycle, UdpUtil::Size::GPSCYCLE);
223 std::memcpy(data2send.data() + UdpUtil::Offset::GPSWEEK, &gpsWeek, UdpUtil::Size::GPSWEEK);
224 std::memcpy(data2send.data() + UdpUtil::Offset::GPSTOW, &gpsTow, UdpUtil::Size::GPSTOW);
225 }
226