@@ -1437,7 +1437,7 @@ ssize_t getServoPacket(
14371437 int counter = 0 ;
14381438 while (true )
14391439 {
1440- TServoPacket last_pkt;
1440+ TServoPacket last_pkt{} ;
14411441 auto recvSize_last = _sock.recv (&last_pkt, sizeof (TServoPacket), 0ul );
14421442 if (recvSize_last == -1 )
14431443 {
@@ -1482,42 +1482,17 @@ bool gz::sim::systems::ArduPilotPlugin::ReceiveServoPacket()
14821482 waitMs = 1 ;
14831483 }
14841484
1485- // 16 / 32 channel compatibility
1486- uint16_t pkt_magic{0 };
1487- uint16_t pkt_frame_rate{0 };
1488- uint16_t pkt_frame_count{0 };
1489- std::array<uint16_t , 32 > pkt_pwm;
1490- ssize_t recvSize{-1 };
1491- if (this ->dataPtr ->have32Channels )
1492- {
1493- servo_packet_32 pkt;
1494- recvSize = getServoPacket (
1495- this ->dataPtr ->sock ,
1496- this ->dataPtr ->fcu_address ,
1497- this ->dataPtr ->fcu_port_out ,
1498- waitMs,
1499- this ->dataPtr ->modelName ,
1500- pkt);
1501- pkt_magic = pkt.magic ;
1502- pkt_frame_rate = pkt.frame_rate ;
1503- pkt_frame_count = pkt.frame_count ;
1504- std::copy (std::begin (pkt.pwm ), std::end (pkt.pwm ), std::begin (pkt_pwm));
1505- }
1506- else
1507- {
1508- servo_packet_16 pkt;
1509- recvSize = getServoPacket (
1510- this ->dataPtr ->sock ,
1511- this ->dataPtr ->fcu_address ,
1512- this ->dataPtr ->fcu_port_out ,
1513- waitMs,
1514- this ->dataPtr ->modelName ,
1515- pkt);
1516- pkt_magic = pkt.magic ;
1517- pkt_frame_rate = pkt.frame_rate ;
1518- pkt_frame_count = pkt.frame_count ;
1519- std::copy (std::begin (pkt.pwm ), std::end (pkt.pwm ), std::begin (pkt_pwm));
1520- }
1485+ // Always receive into the largest packet buffer (servo_packet_32, 72 bytes).
1486+ // The channel count is determined afterward from the magic field; this removes
1487+ // the need to keep <have_32_channels> in sync with the SITL configuration.
1488+ servo_packet_32 pkt{};
1489+ ssize_t recvSize = getServoPacket (
1490+ this ->dataPtr ->sock ,
1491+ this ->dataPtr ->fcu_address ,
1492+ this ->dataPtr ->fcu_port_out ,
1493+ waitMs,
1494+ this ->dataPtr ->modelName ,
1495+ pkt);
15211496
15221497 // didn't receive a packet, increment timeout count if online, then return
15231498 if (recvSize == -1 )
@@ -1547,6 +1522,75 @@ bool gz::sim::systems::ArduPilotPlugin::ReceiveServoPacket()
15471522 return false ;
15481523 }
15491524
1525+ // Infer 16 vs 32 channels directly from the magic value in the packet.
1526+ // Values come from SIM_JSON.h in the ArduPilot SITL library.
1527+ constexpr uint16_t magic_16 = 18458 ;
1528+ constexpr uint16_t magic_32 = 29569 ;
1529+ const size_t recvSizeBytes = static_cast <size_t >(recvSize);
1530+ bool detected32Channels;
1531+ if (pkt.magic == magic_32)
1532+ {
1533+ detected32Channels = true ;
1534+ }
1535+ else if (pkt.magic == magic_16)
1536+ {
1537+ detected32Channels = false ;
1538+ }
1539+ else
1540+ {
1541+ gzwarn << " Incorrect protocol magic "
1542+ << pkt.magic << " (expected "
1543+ << magic_16 << " or " << magic_32 << " ), dropping packet.\n " ;
1544+ return false ;
1545+ }
1546+
1547+ if (detected32Channels && recvSizeBytes != sizeof (servo_packet_32))
1548+ {
1549+ gzwarn << " [" << this ->dataPtr ->modelName << " ] "
1550+ << " Got 32-channel magic with unexpected packet size "
1551+ << recvSize << " (expected " << sizeof (servo_packet_32)
1552+ << " ), dropping packet.\n " ;
1553+ return false ;
1554+ }
1555+
1556+ if (!detected32Channels && recvSizeBytes != sizeof (servo_packet_16))
1557+ {
1558+ gzwarn << " [" << this ->dataPtr ->modelName << " ] "
1559+ << " Got 16-channel magic with unexpected packet size "
1560+ << recvSize << " (expected " << sizeof (servo_packet_16)
1561+ << " ), dropping packet.\n " ;
1562+ return false ;
1563+ }
1564+
1565+ // If the SDF-configured value disagrees with the auto-detected one, override
1566+ // it and log a warning. <have_32_channels> is retained for backward
1567+ // compatibility and debug purposes only.
1568+ if (detected32Channels != this ->dataPtr ->have32Channels )
1569+ {
1570+ gzwarn << " [" << this ->dataPtr ->modelName << " ] "
1571+ << " <have_32_channels>=" << this ->dataPtr ->have32Channels
1572+ << " does not match packet magic"
1573+ << " (detected " << (detected32Channels ? 32 : 16 ) << " channels)."
1574+ << " Overriding from packet.\n " ;
1575+ this ->dataPtr ->have32Channels = detected32Channels;
1576+ }
1577+
1578+ const uint16_t pkt_frame_rate = pkt.frame_rate ;
1579+ const uint32_t pkt_frame_count = pkt.frame_count ;
1580+
1581+ // Build a unified 32-element PWM array, zero-initialised.
1582+ // For a 16-channel packet the upper 16 slots remain at zero.
1583+ std::array<uint16_t , 32 > pkt_pwm{};
1584+ if (detected32Channels)
1585+ {
1586+ std::copy (std::begin (pkt.pwm ), std::end (pkt.pwm ), std::begin (pkt_pwm));
1587+ }
1588+ else
1589+ {
1590+ std::copy (std::begin (pkt.pwm ), std::begin (pkt.pwm ) + 16 ,
1591+ std::begin (pkt_pwm));
1592+ }
1593+
15501594#if DEBUG_JSON_IO
15511595 int max_servo_channels = this ->dataPtr ->have32Channels ? 32 : 16 ;
15521596
@@ -1555,7 +1599,7 @@ bool gz::sim::systems::ArduPilotPlugin::ReceiveServoPacket()
15551599 oss << " recv " << recvSize << " bytes from "
15561600 << this ->dataPtr ->fcu_address << " :"
15571601 << this ->dataPtr ->fcu_port_out << " \n " ;
1558- // oss << "magic: " << pkt_magic << "\n";
1602+ // oss << "magic: " << pkt.magic << "\n";
15591603 // oss << "frame_rate: " << pkt_frame_rate << "\n";
15601604 oss << " frame_count: " << pkt_frame_count << " \n " ;
15611605 // oss << "pwm: [";
@@ -1566,18 +1610,6 @@ bool gz::sim::systems::ArduPilotPlugin::ReceiveServoPacket()
15661610 gzdbg << " \n " << oss.str ();
15671611#endif
15681612
1569- // check magic, return if invalid
1570- constexpr uint16_t magic_16 = 18458 ;
1571- constexpr uint16_t magic_32 = 29569 ;
1572- uint16_t magic = this ->dataPtr ->have32Channels ? magic_32 : magic_16;
1573- if (magic != pkt_magic)
1574- {
1575- gzwarn << " Incorrect protocol magic "
1576- << pkt_magic << " should be "
1577- << magic << " \n " ;
1578- return false ;
1579- }
1580-
15811613 // the controller is online
15821614 if (!this ->dataPtr ->arduPilotOnline )
15831615 {
0 commit comments