Skip to content

Commit cafb83c

Browse files
authored
Merge pull request #2680 from mavlink/pr-int64-json
mavlink_direct: handle (u)int > 2^32
2 parents 320d800 + 24a3aac commit cafb83c

File tree

3 files changed

+102
-29
lines changed

3 files changed

+102
-29
lines changed

src/mavsdk/plugins/mavlink_direct/mavlink_direct_impl.cpp

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -233,37 +233,20 @@ bool MavlinkDirectImpl::json_to_libmav_message(
233233
const Json::Value& field_value = json[field_name];
234234

235235
// Convert JSON values to appropriate types and set in message
236-
if (field_value.isInt()) {
237-
auto result = msg.set(field_name, static_cast<int32_t>(field_value.asInt()));
236+
// libmav handles type casting based on field definition, so we just need to pass
237+
// int64/uint64
238+
if (field_value.isInt() || field_value.isInt64()) {
239+
int64_t value = field_value.asInt64();
240+
auto result = msg.set(field_name, value);
238241
if (result != ::mav::MessageResult::Success) {
239-
// Try as other integer types
240-
if (msg.set(field_name, static_cast<uint32_t>(field_value.asUInt())) !=
241-
::mav::MessageResult::Success &&
242-
msg.set(field_name, static_cast<int16_t>(field_value.asInt())) !=
243-
::mav::MessageResult::Success &&
244-
msg.set(field_name, static_cast<uint16_t>(field_value.asUInt())) !=
245-
::mav::MessageResult::Success &&
246-
msg.set(field_name, static_cast<int8_t>(field_value.asInt())) !=
247-
::mav::MessageResult::Success &&
248-
msg.set(field_name, static_cast<uint8_t>(field_value.asUInt())) !=
249-
::mav::MessageResult::Success) {
250-
LogWarn() << "Failed to set integer field " << field_name << " = "
251-
<< field_value.asInt();
252-
}
242+
LogWarn() << "Failed to set integer field " << field_name << " = " << value;
253243
}
254-
} else if (field_value.isUInt()) {
255-
auto result = msg.set(field_name, static_cast<uint32_t>(field_value.asUInt()));
244+
} else if (field_value.isUInt() || field_value.isUInt64()) {
245+
uint64_t value = field_value.asUInt64();
246+
auto result = msg.set(field_name, value);
256247
if (result != ::mav::MessageResult::Success) {
257-
// Try as other unsigned integer types
258-
if (msg.set(field_name, static_cast<uint64_t>(field_value.asUInt64())) !=
259-
::mav::MessageResult::Success &&
260-
msg.set(field_name, static_cast<uint16_t>(field_value.asUInt())) !=
261-
::mav::MessageResult::Success &&
262-
msg.set(field_name, static_cast<uint8_t>(field_value.asUInt())) !=
263-
::mav::MessageResult::Success) {
264-
LogWarn() << "Failed to set unsigned integer field " << field_name << " = "
265-
<< field_value.asUInt();
266-
}
248+
LogWarn() << "Failed to set unsigned integer field " << field_name << " = "
249+
<< value;
267250
}
268251
} else if (field_value.isNull() || field_value.isDouble()) {
269252
// Handle float/double values (including null -> NaN)

src/system_tests/intercept.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ TEST(SystemTest, InterceptJsonOutgoing)
335335
// Publish GPS data from autopilot
336336
LogInfo() << "Publishing GPS data from autopilot...";
337337
TelemetryServer::RawGps raw_gps{};
338-
raw_gps.timestamp_us = 1234567890;
338+
raw_gps.timestamp_us = 1234567890123456789;
339339
raw_gps.latitude_deg = 47.3977421; // Zurich coordinates
340340
raw_gps.longitude_deg = 8.5455938;
341341
raw_gps.absolute_altitude_m = 488.0f;

src/system_tests/mavlink_direct.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,3 +1217,93 @@ TEST(SystemTest, MavlinkDirectMultipleSubscriptions)
12171217
receiver_mavlink_direct.unsubscribe_message(handle_heartbeat);
12181218
std::this_thread::sleep_for(std::chrono::milliseconds(100));
12191219
}
1220+
1221+
TEST(SystemTest, MavlinkDirectLargeUint64)
1222+
{
1223+
// Test GPS_RAW_INT with time_usec field > 2^32 to verify proper uint64 handling
1224+
1225+
Mavsdk mavsdk_groundstation{Mavsdk::Configuration{ComponentType::GroundStation}};
1226+
Mavsdk mavsdk_autopilot{Mavsdk::Configuration{ComponentType::Autopilot}};
1227+
1228+
ASSERT_EQ(
1229+
mavsdk_groundstation.add_any_connection("udpin://0.0.0.0:17011"),
1230+
ConnectionResult::Success);
1231+
ASSERT_EQ(
1232+
mavsdk_autopilot.add_any_connection("udpout://127.0.0.1:17011"), ConnectionResult::Success);
1233+
1234+
// Ground station discovers the autopilot system
1235+
auto maybe_system = mavsdk_groundstation.first_autopilot(10.0);
1236+
ASSERT_TRUE(maybe_system);
1237+
auto system = maybe_system.value();
1238+
ASSERT_TRUE(system->has_autopilot());
1239+
1240+
// Wait for autopilot instance to discover the connection to the ground station
1241+
LogInfo() << "Waiting for autopilot system to connect...";
1242+
while (mavsdk_autopilot.systems().size() == 0) {
1243+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
1244+
}
1245+
1246+
auto groundstation_system = mavsdk_autopilot.systems().at(0);
1247+
ASSERT_EQ(groundstation_system->component_ids()[0], 190);
1248+
1249+
auto receiver_mavlink_direct = MavlinkDirect{system};
1250+
auto sender_mavlink_direct = MavlinkDirect{groundstation_system};
1251+
1252+
auto prom = std::promise<MavlinkDirect::MavlinkMessage>();
1253+
auto fut = prom.get_future();
1254+
1255+
// Subscribe to GPS_RAW_INT messages
1256+
auto handle = receiver_mavlink_direct.subscribe_message(
1257+
"GPS_RAW_INT", [&prom](MavlinkDirect::MavlinkMessage message) {
1258+
LogInfo() << "Received GPS_RAW_INT: " << message.fields_json;
1259+
prom.set_value(message);
1260+
});
1261+
1262+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
1263+
1264+
// Send GPS_RAW_INT with time_usec > 2^32 (5000000000 microseconds = ~83 minutes)
1265+
// This value requires full uint64 representation
1266+
MavlinkDirect::MavlinkMessage gps_raw_message;
1267+
gps_raw_message.message_name = "GPS_RAW_INT";
1268+
gps_raw_message.system_id = 1;
1269+
gps_raw_message.component_id = 1;
1270+
gps_raw_message.target_system_id = 0;
1271+
gps_raw_message.target_component_id = 0;
1272+
gps_raw_message.fields_json =
1273+
R"({"time_usec":5000000000,"fix_type":3,"lat":473977418,"lon":-1223974560,"alt":100500,"eph":100,"epv":150,"vel":500,"cog":18000,"satellites_visible":12})";
1274+
1275+
LogInfo() << "Sending GPS_RAW_INT with time_usec=5000000000 (> 2^32)";
1276+
auto result = sender_mavlink_direct.send_message(gps_raw_message);
1277+
EXPECT_EQ(result, MavlinkDirect::Result::Success);
1278+
1279+
// Wait for message to be received
1280+
ASSERT_EQ(fut.wait_for(std::chrono::seconds(5)), std::future_status::ready);
1281+
1282+
auto received_message = fut.get();
1283+
1284+
EXPECT_EQ(received_message.message_name, "GPS_RAW_INT");
1285+
EXPECT_EQ(received_message.system_id, 1);
1286+
EXPECT_EQ(received_message.component_id, 1);
1287+
1288+
// Parse JSON to verify uint64 field value is preserved
1289+
Json::Value json;
1290+
Json::Reader reader;
1291+
ASSERT_TRUE(reader.parse(received_message.fields_json, json))
1292+
<< "Failed to parse received JSON: " << received_message.fields_json;
1293+
1294+
// Verify time_usec field is present and has the correct large value
1295+
ASSERT_TRUE(json.isMember("time_usec")) << "time_usec field missing from JSON";
1296+
EXPECT_EQ(json["time_usec"].asUInt64(), 5000000000ULL)
1297+
<< "time_usec value incorrect: expected 5000000000, got " << json["time_usec"].asUInt64();
1298+
1299+
// Verify other fields for completeness
1300+
EXPECT_EQ(json["fix_type"].asUInt(), 3u);
1301+
EXPECT_EQ(json["lat"].asInt(), 473977418);
1302+
EXPECT_EQ(json["lon"].asInt(), -1223974560);
1303+
EXPECT_EQ(json["alt"].asInt(), 100500);
1304+
EXPECT_EQ(json["satellites_visible"].asUInt(), 12u);
1305+
1306+
LogInfo() << "Successfully verified uint64 handling for time_usec > 2^32";
1307+
receiver_mavlink_direct.unsubscribe_message(handle);
1308+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
1309+
}

0 commit comments

Comments
 (0)