LCOV - code coverage report
Current view: top level - SITL - SIM_ADSB_Sagetech_MXS.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 183 223 82.1 %
Date: 2026-09-09 11:02:08 Functions: 25 28 89.3 %

          Line data    Source code
       1             : #include "SIM_config.h"
       2             : 
       3             : #if AP_SIM_ADSB_SAGETECH_MXS_ENABLED
       4             : 
       5             : #include "SIM_ADSB_Sagetech_MXS.h"
       6             : 
       7             : #include <AP_Common/Location.h>
       8             : #include <GCS_MAVLink/GCS.h>
       9             : #include <AP_InternalError/AP_InternalError.h>
      10             : #include "SITL.h"
      11             : #include <ctype.h>
      12             : #include "SIM_Aircraft.h"
      13             : #include "SIM_ADSB.h"
      14             : 
      15             : #include <errno.h>
      16             : 
      17             : static const uint8_t FIRST_BYTE { 0xAA };
      18             : 
      19             : using namespace SITL;
      20             : 
      21        2191 : void ADSB_Sagetech_MXS::move_preamble_in_buffer(uint8_t search_start_pos)
      22             : {
      23             :     uint8_t i;
      24        2191 :     for (i=search_start_pos; i<buflen; i++) {
      25           4 :         if ((uint8_t)msg.buffer[i] == FIRST_BYTE) {
      26           4 :             break;
      27             :         }
      28             :     }
      29        2191 :     if (i == 0) {
      30        2169 :         return;
      31             :     }
      32          22 :     memmove(msg.buffer, &msg.buffer[i], buflen-i);
      33          22 :     buflen = buflen - i;
      34             : }
      35             : 
      36       13427 : void ADSB_Sagetech_MXS::update_serial_input()
      37             : {
      38       13427 :     const ssize_t n = read_from_autopilot(&msg.buffer[buflen], ARRAY_SIZE(msg.buffer) - buflen - 1);
      39       13427 :     if (n < 0) {
      40             :         // TODO: do better here
      41           0 :         if (errno != EAGAIN && errno != EWOULDBLOCK && errno != 0) {
      42           0 :             AP_HAL::panic("Failed to read from autopilot");
      43             :         }
      44             :     } else {
      45       13427 :         buflen += n;
      46             :     }
      47             : 
      48             : 
      49             :     // GCS_SEND_TEXT(MAV_SEVERITY_INFO, "read (%u) bytes", (unsigned)n);
      50             : 
      51       13427 :     switch (input_state) {
      52        2169 :     case InputState::WANT_START_BYTE:
      53        2169 :         move_preamble_in_buffer();
      54        2169 :         if (buflen == 0) {
      55        2168 :             return;
      56             :         }
      57           1 :         set_input_state(InputState::WANT_PREAMBLE);
      58             :         FALLTHROUGH;
      59       11259 :     case InputState::WANT_PREAMBLE:
      60       11259 :         if (buflen < sizeof(msg.preamble)) {
      61       11237 :             return;
      62             :         }
      63          22 :         set_input_state(InputState::WANT_PAYLOAD);
      64             :         FALLTHROUGH;
      65          22 :     case InputState::WANT_PAYLOAD: {
      66             :         // 1 preamble, 2 flags, 1 msg + payload
      67          22 :         const uint8_t want_len = 4 + msg.preamble.payload_length;
      68          22 :         if (buflen < want_len) {
      69           0 :             return;
      70             :         }
      71          22 :         set_input_state(InputState::WANT_CHECKSUM);
      72             :         FALLTHROUGH;
      73             :     }
      74          22 :     case InputState::WANT_CHECKSUM: {
      75             :         // 1 start byte, 1 msg type, 1 msgid, 1 payload len
      76          22 :         const uint8_t want_len = sizeof(msg.preamble) + msg.preamble.payload_length + 1;
      77          22 :         if (buflen < want_len) {
      78           0 :             return;
      79             :         }
      80          22 :         const uint8_t received_checksum = msg.buffer[want_len-1];
      81             : 
      82          22 :         uint8_t calculated_checksum = 0;
      83         852 :         for (uint8_t i=0; i<sizeof(msg.preamble)+msg.preamble.payload_length; i++) {
      84         830 :             calculated_checksum += msg.buffer[i];
      85             :         }
      86             : 
      87          22 :         if (calculated_checksum == received_checksum) {
      88             :             // GCS_SEND_TEXT(MAV_SEVERITY_INFO, "sim-MXS: Got one (%u)!", (unsigned)msg.preamble.msgtype);
      89          22 :             handle_message();
      90          22 :             move_preamble_in_buffer(want_len);
      91             :         } else {
      92           0 :             GCS_SEND_TEXT(MAV_SEVERITY_INFO, "sim-MXS: Bad checksum");
      93           0 :             move_preamble_in_buffer(1);
      94             :         }
      95             :         // consume these bytes
      96          22 :         set_input_state(InputState::WANT_PREAMBLE);
      97          22 :         return;
      98             :     }
      99             :     }
     100             : }
     101             : 
     102          22 : bool ADSB_Sagetech_MXS::_handle_message()
     103             : {
     104          22 :     switch (msg.preamble.msgtype) {
     105           1 :     case MsgType::INSTALLATION:
     106           1 :         return handle_message(msg.packed_installation.msg);
     107           1 :     case MsgType::FLIGHTID:
     108           1 :         return handle_message(msg.packed_flightidmessage.msg);
     109          10 :     case MsgType::OPMSG:
     110          10 :         return handle_message(msg.packed_operating.msg);
     111           9 :     case MsgType::GPS:
     112           9 :         return handle_message(msg.packed_gps.msg);
     113           0 :     case MsgType::DATAREQ:
     114           0 :         return handle_message(msg.packed_data_req.msg);
     115           1 :     case MsgType::TARGETREQUEST:
     116           1 :         return handle_message(msg.packed_target_req.msg);
     117             : 
     118           0 :     case MsgType::ACK:
     119             :     case MsgType::STATEVECTORREPORT:
     120             :     case MsgType::MODESTATUSREPORT:
     121             :         // we should never receive one of these?
     122           0 :         INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
     123           0 :         break;
     124             :     }
     125             : 
     126             :     // we should handle all messages:
     127           0 :     INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
     128             : 
     129           0 :     return false;
     130             : }
     131             : 
     132          22 : void ADSB_Sagetech_MXS::handle_message()
     133             : {
     134          22 :     if (!_handle_message()) {
     135           0 :         return;
     136             :     }
     137             : 
     138             :     // store ack info for sending an ack later:
     139          22 :     ack_info.ackType = msg.preamble.msgtype;
     140          22 :     ack_info.ackId = msg.preamble.msgid;
     141          22 :     ack_info.send = true;
     142             : }
     143             : 
     144           1 : bool ADSB_Sagetech_MXS::handle_message(const SITL::ADSB_Sagetech_MXS::Installation& opmsg)
     145             : {
     146             :     ASSERT_STORAGE_SIZE(Installation, 36);
     147             : 
     148           1 :     if (operating_mode != OperatingMode::OFF &&
     149           0 :         operating_mode != OperatingMode::MAINTENANCE) {
     150             :         // see page 10 - ignored if not in one of those.  We could
     151             :         // return silently here if there are race conditions
     152           0 :         INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
     153             :     }
     154             : 
     155             :     // do something!
     156             : 
     157           1 :     return true;
     158             : }
     159             : 
     160           1 : void ADSB_Sagetech_MXS::assert_good_flight_id()
     161             : {
     162             :     static_assert(sizeof(flight_id) == 8, "correct storage size");
     163             : 
     164           1 :     bool space_seen = false;
     165           9 :     for (uint8_t i=0; i<sizeof(flight_id); i++) {
     166             :         // this doesn't seem right; they really allow any ASCII
     167             :         // character?  vertical tabs, for example?!  The standard is
     168             :         // ~US$750.  Null (0x0) is a valid ascii character!
     169           8 :         if (!isascii(flight_id[i])) {
     170           0 :             INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
     171             :         }
     172           8 :         if (flight_id[i] == ' ') {
     173           0 :             space_seen = true;
     174             :         }
     175           8 :         if (space_seen && flight_id[i] != ' ') {
     176           0 :             INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
     177             :         }
     178             :     }
     179           1 : }
     180             : 
     181           1 : bool ADSB_Sagetech_MXS::handle_message(const SITL::ADSB_Sagetech_MXS::FlightIDMessage& _msg)
     182             : {
     183             :     ASSERT_STORAGE_SIZE(FlightIDMessage, 12);
     184             : 
     185             :     // do something!
     186           1 :     flight_id_set_time_ms = AP_HAL::millis();
     187           1 :     memcpy(flight_id, _msg.flight_id, sizeof(flight_id));
     188           1 :     assert_good_flight_id();
     189             : 
     190           1 :     return true;
     191             : }
     192             : 
     193          10 : bool ADSB_Sagetech_MXS::handle_message(const SITL::ADSB_Sagetech_MXS::Operating& _msg)
     194             : {
     195             :     ASSERT_STORAGE_SIZE(Operating, 12);
     196             : 
     197             :     // do something!
     198             : 
     199          10 :     return true;
     200             : }
     201             : 
     202             : #define ORD(x) (x - '0')
     203             : 
     204             : // buffer contains DDDMM.MMMMM (degrees, minutes including fraction)
     205           9 : double ADSB_Sagetech_MXS::lon_string_to_double(const uint8_t *str)
     206             : {
     207           9 :     return ORD(str[0]) * 100 + lat_string_to_double(&str[1]);
     208             : }
     209             : 
     210             : // buffer contains DDMM.MMMMM (degrees, minutes including fraction)
     211          18 : double ADSB_Sagetech_MXS::lat_string_to_double(const uint8_t *str)
     212             : {
     213          18 :     double degrees = ORD(str[0]) * 10 + ORD(str[1]);
     214          18 :     double minutes = ORD(str[2]) * 10.0 + ORD(str[3]) + ORD(str[5])*0.1 + ORD(str[6])*0.01 + ORD(str[7]) * 0.001 + ORD(str[8]) * 0.0001 + ORD(str[9]) * 0.00001;
     215          18 :     return degrees + minutes/60.0;
     216             : }
     217             : 
     218             : #undef ORD
     219             : 
     220           9 : bool ADSB_Sagetech_MXS::handle_message(const SITL::ADSB_Sagetech_MXS::GPS& _msg)
     221             : {
     222             :     ASSERT_STORAGE_SIZE(GPS, 63);
     223             : 
     224             :     // store data to transmit via ADSB
     225           9 :     info_from_vehicle.gps.lat = lat_string_to_double(_msg.latitude);
     226           9 :     info_from_vehicle.gps.lng = lon_string_to_double(_msg.longitude);
     227             : 
     228           9 :     return true;
     229             : }
     230             : 
     231           0 : bool ADSB_Sagetech_MXS::handle_message(const SITL::ADSB_Sagetech_MXS::DataRequest& _msg)
     232             : {
     233             :     ASSERT_STORAGE_SIZE(DataRequest, 4);
     234             : 
     235             :     // handle request to send data to vehicle.  Note that the
     236             :     // specification says (on page 32) that the ack is sent before the
     237             :     // data.
     238             : 
     239           0 :     return true;
     240             : }
     241             : 
     242           1 : bool ADSB_Sagetech_MXS::handle_message(const SITL::ADSB_Sagetech_MXS::TargetRequest& _msg)
     243             : {
     244             :     ASSERT_STORAGE_SIZE(TargetRequest, 7);
     245             : 
     246             :     // handle request to send adsb data to vehicle as it is received
     247             : 
     248           1 :     return true;
     249             : }
     250             : 
     251             : 
     252       13427 : void ADSB_Sagetech_MXS::update_serial_output(const Aircraft *sitl_model)
     253             : {
     254             :     // TODO: space checks here
     255             : 
     256       13427 :     if (ack_info.send) {
     257          22 :         uint8_t alt[3] {};
     258          22 :         uint8_t state = 0;
     259             :         Ack ack{
     260             :             ack_info.ackType,
     261          22 :             ack_info.ackId,
     262             :             state,  // bitmask field
     263             :             alt
     264          22 :         };
     265          22 :         const PackedMessage<Ack> packed { ack, MsgType::ACK, msgid++ };
     266          22 :         write_to_autopilot((const char*)&packed, sizeof(packed));
     267          22 :         ack_info.send = false;
     268             :     }
     269             : 
     270       13427 :     update_serial_output_vehicles(sitl_model);
     271       13427 : }
     272             : 
     273             : 
     274       13427 : void ADSB_Sagetech_MXS::update_serial_output_vehicles(const SITL::Aircraft *sitl_model)
     275             : {
     276       13427 :     if (sitl_model->adsb == nullptr) {
     277           0 :         return;
     278             :     }
     279       80557 :     for (uint8_t i=0; i<sitl_model->adsb->num_vehicles; i++) {
     280       67130 :         const ADSB_Vehicle &vehicle = sitl_model->adsb->vehicles[i];
     281       67130 :         if (!vehicle.initialised) {
     282           3 :             continue;
     283             :         }
     284       67127 :         send_vehicle_message(vehicle);
     285             :     }
     286             : }
     287             : 
     288             : // pack a floating-point latitude or longitude into three bytes
     289             : // according to Sagetech definitions:
     290      134254 : void ADSB_Sagetech_MXS::pack_scaled_geocoord(uint8_t buf[3], float coord)
     291             : {
     292      134254 :     const int32_t scaled = coord * (1U<<23) / 180.0;
     293      134254 :     pack_int32_into_uint8_ts(scaled, buf);
     294      134254 : }
     295             : 
     296             : // pack a floating-point altitude in metres into three bytes
     297             : // according to Sagetech definitions:
     298       67127 : void ADSB_Sagetech_MXS::pack_scaled_alt(uint8_t buf[3], float alt_m)
     299             : {
     300       67127 :     const int32_t scaled = METRES_TO_FEET*alt_m * (1/0.015625);
     301       67127 :     pack_int32_into_uint8_ts(scaled, buf);
     302       67127 : }
     303             : 
     304             : // discards the top 8 bits from source and shoves the rest into dest
     305      335635 : void ADSB_Sagetech_MXS::pack_int32_into_uint8_ts(int32_t source, uint8_t dest[3])
     306             : {
     307             :     // FIXME: cast &source instead?
     308      335635 :     dest[0] = source >> 16;
     309      335635 :     dest[1] = source >> 8;
     310      335635 :     dest[2] = source >> 0;
     311      335635 : }
     312             : 
     313           0 : uint8_t ADSB_Sagetech_MXS::scaled_groundspeed(float speed_m_s) const
     314             : {
     315           0 :     if (is_zero(speed_m_s)) {
     316           0 :         return 0x01;
     317             :     }
     318           0 :     const float knots = M_PER_SEC_TO_KNOTS * speed_m_s;
     319           0 :     if (knots < 0.125) {
     320           0 :         return 0x02;
     321             :     }
     322             :     static const struct Threshold {
     323             :         float min;
     324             :         uint8_t code;
     325             :         float increment;
     326             :     } thresholds[] {
     327             :         {   0.125, 0x03, 0.146 },
     328             :         {   1,     0x09, 0.25 },
     329             :         {   2,     0x0D, 0.50 },
     330             :         {  15,     0x27, 1 },
     331             :         {  70,     0x5e, 2 },
     332             :         { 100,     0x6d, 5 },
     333             :         { 175,     0x7c, 0 },
     334             :     };
     335           0 :     auto *entry = &thresholds[0];
     336           0 :     for (uint8_t i=1; i<ARRAY_SIZE(thresholds); i++) {
     337           0 :         auto *next_entry = &thresholds[i];
     338           0 :         if (knots > entry->min && knots < next_entry->min) {
     339           0 :             const uint8_t code_delta = next_entry->code - entry->code;
     340           0 :             return entry->code + uint8_t((knots - entry->min) / code_delta);
     341             :         }
     342           0 :         entry = next_entry;
     343             :     }
     344           0 :     return 0x7c;
     345             : }
     346           0 : void ADSB_Sagetech_MXS::pack_scaled_groundspeed(uint8_t dest[1], float speed_m_s) const
     347             : {
     348           0 :     dest[0] = scaled_groundspeed(speed_m_s);
     349           0 :     GCS_SEND_TEXT(MAV_SEVERITY_INFO, "speed in: %f", speed_m_s);
     350           0 : }
     351             : 
     352      134254 : void ADSB_Sagetech_MXS::pack_scaled_airspeed(uint8_t dest[2], float speed_m_s) const
     353             : {
     354      134254 :     const int16_t scaled = M_PER_SEC_TO_KNOTS * speed_m_s * 8;
     355      134254 :     dest[0] = scaled >> 8;
     356      134254 :     dest[1] = scaled >> 0;
     357      134254 : }
     358             : 
     359       67127 : void ADSB_Sagetech_MXS::pack_scaled_vertical_rate(uint8_t dest[2], float speed_m_s) const
     360             : {
     361       67127 :     const int16_t scaled = METRES_TO_FEET * speed_m_s;
     362       67127 :     dest[0] = scaled >> 8;
     363       67127 :     dest[1] = scaled >> 0;
     364       67127 : }
     365             : 
     366       67127 : void ADSB_Sagetech_MXS::send_vehicle_message(const SITL::ADSB_Vehicle &vehicle)
     367             : {
     368       67127 :     send_vehicle_message_state_vector(vehicle);
     369       67127 :     send_vehicle_message_status_report(vehicle);
     370       67127 : }
     371             : 
     372       67127 : void ADSB_Sagetech_MXS::send_vehicle_message_state_vector(const SITL::ADSB_Vehicle &vehicle)
     373             : {
     374             :     enum class SVR_ValidityFlag : uint8_t {
     375             :         LatitudeAndLongitude =      (1U << 7),
     376             :         Altitude_Geometric =        (1U << 6),
     377             :         NS_and_EW_Velocity =        (1U << 5),
     378             :         GroundSpeedWhileOnSurface = (1U << 4),
     379             :         HeadingWhileOnSurface     = (1U << 3),
     380             :         Altitude_Barometric       = (1U << 2),
     381             :         VerticalRate_Geometric    = (1U << 1),
     382             :         VerticalRate_Barometric   = (1U << 0),
     383             :     };
     384             :     enum class SVR_EstimateValidityFlag : uint8_t {
     385             :         LatitudeAndLongitude =      (1U << 7),
     386             :         NS_and_EW_Velocity =        (1U << 6),
     387             :     };
     388             : 
     389             :     // this struct-based approach may prove to be too inflexible
     390             :     // if we want to change the shape of the report at runtime for
     391             :     // some reason.
     392             :     struct PACKED {
     393             :         StateVectorReport_ReportStructure report_structure;
     394             :         uint8_t validity_flags;  // see SVR_ValidityFlag enum
     395             :         uint8_t estimated_validity_flags;  // see SVR_EstimateValidityFlag enum
     396             :         uint8_t participant_address[3];
     397             :         uint8_t address_qualifier;
     398             :         uint16_t epos_toa;
     399             :         uint16_t pos_toa;
     400             :         uint16_t vel_toa;
     401             :         uint8_t latitude[3];
     402             :         uint8_t longitude[3];
     403             :         uint8_t alt_geometric[3];
     404             :         uint8_t ns_velocity[2];
     405             :         uint8_t ew_velocity[2];
     406             :         uint8_t up_velocity[2];
     407             :         // uint8_t groundspeed;
     408             :         // uint8_t ground_heading;
     409       67127 :     } my_report {};
     410             : 
     411       67127 :     my_report.report_structure.rs0.msn = 1;
     412             : 
     413             :     // note that the Sagetech SDK parser requires all of these fields
     414             :     // to be 1 to be an airborne vehicle::
     415       67127 :     my_report.report_structure.rs0.time_of_applicability_for_estimated_positon = 1;
     416       67127 :     my_report.report_structure.rs0.position_time_of_applicability = 1;
     417       67127 :     my_report.report_structure.rs0.velocity_time_of_applicability = 1;
     418             : 
     419       67127 :     my_report.report_structure.rs2.estimated_longitude = 0;
     420             : 
     421       67127 :     my_report.validity_flags = 0;
     422             : 
     423       67127 :     pack_int32_into_uint8_ts(vehicle.ICAO_address, my_report.participant_address);
     424       67127 :     my_report.address_qualifier = 0x02;  // aircraft
     425             : 
     426       67127 :     Location loc = vehicle.get_location();
     427             : 
     428             :     // pack in latitude/longitude:
     429       67127 :     pack_scaled_geocoord(my_report.latitude, loc.lat * 1e-7);
     430       67127 :     pack_scaled_geocoord(my_report.longitude, loc.lng * 1e-7);
     431       67127 :     my_report.report_structure.rs0.lat_and_lng = 1;
     432       67127 :     my_report.validity_flags |= (uint8_t)SVR_ValidityFlag::LatitudeAndLongitude;
     433             : 
     434             :     // pack in altitude:
     435       67127 :     pack_scaled_alt(my_report.alt_geometric, loc.alt*0.01);
     436       67127 :     my_report.report_structure.rs1.altitude_geometric = 1;
     437       67127 :     my_report.validity_flags |= (uint8_t)SVR_ValidityFlag::Altitude_Geometric;
     438             : 
     439             :     // pack in north/south and east/west velocity
     440       67127 :     pack_scaled_airspeed(my_report.ns_velocity, vehicle.velocity_ef.x);
     441       67127 :     pack_scaled_airspeed(my_report.ew_velocity, vehicle.velocity_ef.y);
     442       67127 :     my_report.report_structure.rs1.north_south_east_west_vel = 1;
     443       67127 :     my_report.validity_flags |= (uint8_t)SVR_ValidityFlag::NS_and_EW_Velocity;
     444             : 
     445             :     // pack in surface speed and heading:
     446             :     // pack_scaled_groundspeed(&my_report.groundspeed, vehicle.velocity_ef.length());
     447             :     // my_report.report_structure.rs1.ground_speed_on_ground = 1;
     448             :     // my_report.validity_flags |= (uint8_t)SVR_ValidityFlag::GroundSpeedWhileOnSurface;
     449             :     // my_report.report_structure.rs1.heading_on_ground = 1;
     450             :     // my_report.ground_heading = wrap_180(vehicle.velocity_ef.xy().angle()) / 1.40625;
     451             :     // my_report.validity_flags |= (uint8_t)SVR_ValidityFlag::HeadingWhileOnSurface;
     452             : 
     453             :     // pack in vertical rate
     454       67127 :     pack_scaled_vertical_rate(my_report.up_velocity, -vehicle.velocity_ef.z);
     455       67127 :     my_report.report_structure.rs1.vertical_rate_geometric_barometric = 1;
     456       67127 :     my_report.validity_flags |= (uint8_t)SVR_ValidityFlag::VerticalRate_Geometric;
     457             : 
     458             :     StateVectorReportBuffer<sizeof(my_report)> report;
     459       67127 :     memcpy(report.buffer, &my_report, sizeof(report.buffer));
     460             : 
     461             :     const PackedMessage<StateVectorReportBuffer<sizeof(my_report)>> packed {
     462             :         report,
     463             :         MsgType::STATEVECTORREPORT,
     464       67127 :         msgid++
     465       67127 :     };
     466       67127 :     write_to_autopilot((const char*)&packed, sizeof(packed));
     467       67127 : }
     468             : 
     469       67127 : void ADSB_Sagetech_MXS::send_vehicle_message_status_report(const SITL::ADSB_Vehicle &vehicle)
     470             : {
     471             :     enum class RS0 : uint8_t {
     472             :         TimeOfApplicability       = (1U << 3),
     473             :         ADSB_Version              = (1U << 2),
     474             :         CallSign                  = (1U << 1),
     475             :         EmitterCategory           = (1U << 0),
     476             :     };
     477             :     enum class RS1 : uint8_t {
     478             :         AVLengthAndWidthCode    = (1U << 7),
     479             :         EmergencyPriorityStatus = (1U << 6),
     480             :         CapabilityCodes         = (1U << 5),
     481             :         OperationalMode         = (1U << 4),
     482             :         SVQualityNACp           = (1U << 3),
     483             :         SVQualityNACv           = (1U << 2),
     484             :         SVQualitySIL            = (1U << 1),
     485             :         SQQualtity_GVA          = (1U << 0),
     486             :     };
     487             :     enum class RS2 : uint8_t {
     488             :         SVQualityNICbaro        = (1U << 7),
     489             :         TrueMagneticHeading     = (1U << 6),
     490             :         VerticalRateType        = (1U << 5),
     491             :         FlightModeSpecific      = (1U << 4),
     492             :         Reserved3               = (1U << 3),
     493             :         Reserved2               = (1U << 2),
     494             :         Reserved1               = (1U << 1),
     495             :         Reserved0               = (1U << 0),
     496             :     };
     497             : 
     498             :     // this struct-based approach may prove to be too inflexible
     499             :     // if we want to change the shape of the report at runtime for
     500             :     // some reason.
     501             :     struct PACKED {
     502             :         uint32_t report_structure : 24;
     503             :         uint8_t validity_flags;  // see SVR_ValidityFlag enum
     504             :         uint8_t participant_address[3];
     505             :         uint8_t address_qualifier;
     506             :         uint8_t callsign[8];
     507       67127 :     } my_report {};
     508             : 
     509       67127 :     my_report.report_structure = uint8_t(RS0::CallSign) | (0x2 << 4);
     510       67127 :     my_report.validity_flags = 0;
     511             : 
     512       67127 :     pack_int32_into_uint8_ts(vehicle.ICAO_address, my_report.participant_address);
     513       67127 :     my_report.address_qualifier = 0x02;  // aircraft
     514             : 
     515       67127 :     memset(my_report.callsign, '\0', ARRAY_SIZE(my_report.callsign));
     516       67127 :     memcpy(my_report.callsign, vehicle.callsign, MIN(ARRAY_SIZE(vehicle.callsign), ARRAY_SIZE(my_report.callsign)));
     517             : 
     518             :     ModeStatusReportBuffer<sizeof(my_report)> report;
     519       67127 :     memcpy(report.buffer, &my_report, sizeof(report.buffer));
     520             : 
     521             :     const PackedMessage<ModeStatusReportBuffer<sizeof(my_report)>> packed {
     522             :         report,
     523             :         MsgType::MODESTATUSREPORT,
     524       67127 :         msgid++
     525       67127 :     };
     526       67127 :     write_to_autopilot((const char*)&packed, sizeof(packed));
     527       67127 : }
     528             : 
     529       13427 : void ADSB_Sagetech_MXS::update_rf_input()
     530             : {
     531             :     // could selectivly copy from sitl->adsb here
     532       13427 : }
     533             : 
     534       13427 : void ADSB_Sagetech_MXS::update_rf_output()
     535             : {
     536             :     // print a message here when we are transmitting
     537       13427 : }
     538             : 
     539       14460 : void ADSB_Sagetech_MXS::update(const SITL::Aircraft *sitl_model)
     540             : {
     541             :     // see if we should do a report.
     542       14460 :     if ((AP::sitl()->adsb_types & (1U << (uint8_t)SIM::ADSBType::SageTechMXS)) == 0) {
     543        1033 :         return;
     544             :     }
     545             : 
     546       13427 :     update_serial_input();
     547       13427 :     update_serial_output(sitl_model);
     548             : 
     549       13427 :     update_rf_input();
     550       13427 :     update_rf_output();
     551             : }
     552             : 
     553             : #endif  // AP_SIM_ADSB_SAGETECH_MXS_ENABLED

Generated by: LCOV version 1.14