LCOV - code coverage report
Current view: top level - AP_Mount - AP_Mount.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 281 505 55.6 %
Date: 2026-09-09 11:02:08 Functions: 45 67 67.2 %

          Line data    Source code
       1             : #include "AP_Mount_config.h"
       2             : 
       3             : #if HAL_MOUNT_ENABLED
       4             : 
       5             : #include <AP_Common/AP_Common.h>
       6             : #include <AP_Param/AP_Param.h>
       7             : #include "AP_Mount.h"
       8             : 
       9             : #include "AP_Mount_Backend.h"
      10             : #include "AP_Mount_Servo.h"
      11             : #include "AP_Mount_SoloGimbal.h"
      12             : #include "AP_Mount_Alexmos.h"
      13             : #include "AP_Mount_SToRM32.h"
      14             : #include "AP_Mount_SToRM32_serial.h"
      15             : #include "AP_Mount_MAVLink.h"
      16             : #include "AP_Mount_Siyi.h"
      17             : #include "AP_Mount_Scripting.h"
      18             : #include "AP_Mount_Xacti.h"
      19             : #include "AP_Mount_Viewpro.h"
      20             : #include "AP_Mount_Topotek.h"
      21             : #include "AP_Mount_CADDX.h"
      22             : #include "AP_Mount_XFRobot.h"
      23             : #include <stdio.h>
      24             : #include <AP_Math/location.h>
      25             : #include <SRV_Channel/SRV_Channel.h>
      26             : #include <AP_Logger/AP_Logger.h>
      27             : 
      28             : const AP_Param::GroupInfo AP_Mount::var_info[] = {
      29             : 
      30             :     // @Group: 1
      31             :     // @Path: AP_Mount_Params.cpp
      32             :     AP_SUBGROUPINFO(_params[0], "1", 43, AP_Mount, AP_Mount_Params),
      33             : 
      34             : #if AP_MOUNT_MAX_INSTANCES > 1
      35             :     // @Group: 2
      36             :     // @Path: AP_Mount_Params.cpp
      37             :     AP_SUBGROUPINFO(_params[1], "2", 44, AP_Mount, AP_Mount_Params),
      38             : #endif
      39             : 
      40             :     AP_GROUPEND
      41             : };
      42             : 
      43        6183 : AP_Mount::AP_Mount()
      44             : {
      45        2061 :     if (_singleton != nullptr) {
      46             : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
      47           0 :         AP_HAL::panic("Mount must be singleton");
      48             : #endif
      49           0 :         return;
      50             :     }
      51        2061 :     _singleton = this;
      52             : 
      53        2061 :     AP_Param::setup_object_defaults(this, var_info);
      54             : }
      55             : 
      56             : // init - detect and initialise all mounts
      57        2059 : void AP_Mount::init()
      58             : {
      59             :     // check init has not been called before
      60        2059 :     if (_num_instances != 0) {
      61           0 :         return;
      62             :     }
      63             : 
      64             :     // primary is reset to the first instantiated mount
      65        2059 :     bool primary_set = false;
      66             : 
      67             :     // keep track of number of serial instances for initialisation
      68        2059 :     uint8_t serial_instance = 0;
      69             : 
      70             :     // create each instance
      71        6177 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
      72        4118 :         switch (get_mount_type(instance)) {
      73        4006 :         case Type::None:
      74        4006 :             break;
      75             : #if HAL_MOUNT_SERVO_ENABLED
      76          16 :         case Type::Servo:
      77          16 :             _backends[instance] = NEW_NOTHROW AP_Mount_Servo(*this, _params[instance], true, instance);
      78          16 :             _num_instances++;
      79          16 :             break;
      80             : #endif
      81             : #if HAL_SOLO_GIMBAL_ENABLED
      82           1 :         case Type::SoloGimbal:
      83           1 :             _backends[instance] = NEW_NOTHROW AP_Mount_SoloGimbal(*this, _params[instance], instance);
      84           1 :             _num_instances++;
      85           1 :             break;
      86             : #endif // HAL_SOLO_GIMBAL_ENABLED
      87             : 
      88             : #if HAL_MOUNT_ALEXMOS_ENABLED
      89           0 :         case Type::Alexmos:
      90           0 :             _backends[instance] = NEW_NOTHROW AP_Mount_Alexmos(*this, _params[instance], instance);
      91           0 :             _num_instances++;
      92           0 :             break;
      93             : #endif
      94             : 
      95             : #if HAL_MOUNT_STORM32MAVLINK_ENABLED
      96             :         // check for SToRM32 mounts using MAVLink protocol
      97           0 :         case Type::SToRM32:
      98           0 :             _backends[instance] = NEW_NOTHROW AP_Mount_SToRM32(*this, _params[instance], instance);
      99           0 :             _num_instances++;
     100           0 :             break;
     101             : #endif
     102             : 
     103             : #if HAL_MOUNT_STORM32SERIAL_ENABLED
     104             :         // check for SToRM32 mounts using serial protocol
     105           0 :         case Type::SToRM32_serial:
     106           0 :             _backends[instance] = NEW_NOTHROW AP_Mount_SToRM32_serial(*this, _params[instance], instance, serial_instance);
     107           0 :             _num_instances++;
     108           0 :             serial_instance++;
     109           0 :             break;
     110             : #endif
     111             : 
     112             : #if HAL_MOUNT_MAVLINK_ENABLED
     113             :         // check for MAVLink mounts
     114           5 :         case Type::MAVLink:
     115           5 :             _backends[instance] = NEW_NOTHROW AP_Mount_MAVLink(*this, _params[instance], instance);
     116           5 :             _num_instances++;
     117           5 :             break;
     118             : #endif // HAL_MOUNT_MAVLINK_ENABLED
     119             : 
     120             : #if HAL_MOUNT_SERVO_ENABLED
     121             :         // check for BrushlessPWM mounts (uses Servo backend)
     122          82 :         case Type::BrushlessPWM:
     123          82 :             _backends[instance] = NEW_NOTHROW AP_Mount_Servo(*this, _params[instance], false, instance);
     124          82 :             _num_instances++;
     125          82 :             break;
     126             : #endif
     127             : 
     128             : #if HAL_MOUNT_SIYI_ENABLED
     129             :         // check for Siyi gimbal
     130           1 :         case Type::Siyi:
     131           1 :             _backends[instance] = NEW_NOTHROW AP_Mount_Siyi(*this, _params[instance], instance, serial_instance);
     132           1 :             _num_instances++;
     133           1 :             serial_instance++;
     134           1 :             break;
     135             : #endif // HAL_MOUNT_SIYI_ENABLED
     136             : 
     137             : #if HAL_MOUNT_SCRIPTING_ENABLED
     138             :         // check for Scripting gimbal
     139           4 :         case Type::Scripting:
     140           4 :             _backends[instance] = NEW_NOTHROW AP_Mount_Scripting(*this, _params[instance], instance);
     141           4 :             _num_instances++;
     142           4 :             break;
     143             : #endif // HAL_MOUNT_SCRIPTING_ENABLED
     144             : 
     145             : #if HAL_MOUNT_XACTI_ENABLED
     146             :         // check for Xacti gimbal
     147           0 :         case Type::Xacti:
     148           0 :             _backends[instance] = NEW_NOTHROW AP_Mount_Xacti(*this, _params[instance], instance);
     149           0 :             _num_instances++;
     150           0 :             break;
     151             : #endif // HAL_MOUNT_XACTI_ENABLED
     152             : 
     153             : #if HAL_MOUNT_VIEWPRO_ENABLED
     154             :         // check for Xacti gimbal
     155           1 :         case Type::Viewpro:
     156           1 :             _backends[instance] = NEW_NOTHROW AP_Mount_Viewpro(*this, _params[instance], instance, serial_instance);
     157           1 :             _num_instances++;
     158           1 :             serial_instance++;
     159           1 :             break;
     160             : #endif // HAL_MOUNT_VIEWPRO_ENABLED
     161             : 
     162             : #if HAL_MOUNT_TOPOTEK_ENABLED
     163             :         // check for Topotek gimbal
     164           2 :         case Type::Topotek:
     165           2 :             _backends[instance] = NEW_NOTHROW AP_Mount_Topotek(*this, _params[instance], instance, serial_instance);
     166           2 :             _num_instances++;
     167           2 :             serial_instance++;
     168           2 :             break;
     169             : #endif // HAL_MOUNT_TOPOTEK_ENABLED
     170             : 
     171             : #if HAL_MOUNT_CADDX_ENABLED
     172             :         // check for CADDX gimbal
     173           0 :         case Type::CADDX:
     174           0 :             _backends[instance] = NEW_NOTHROW AP_Mount_CADDX(*this, _params[instance], instance, serial_instance);
     175           0 :             _num_instances++;
     176           0 :             serial_instance++;
     177           0 :             break;
     178             : #endif // HAL_MOUNT_CADDX_ENABLED
     179             : 
     180             : #if HAL_MOUNT_XFROBOT_ENABLED
     181             :         // check for XFRobot gimbal
     182           0 :         case Type::XFRobot:
     183           0 :             _backends[instance] = NEW_NOTHROW AP_Mount_XFRobot(*this, _params[instance], instance, serial_instance);
     184           0 :             _num_instances++;
     185           0 :             serial_instance++;
     186           0 :             break;
     187             : #endif // HAL_MOUNT_XFROBOT_ENABLED
     188             :         }
     189             : 
     190             :         // init new instance
     191        4118 :         if (_backends[instance] != nullptr) {
     192         112 :             if (!primary_set) {
     193         110 :                 _primary = instance;
     194         110 :                 primary_set = true;
     195             :             }
     196             :         }
     197             :     }
     198             : 
     199             :     // init each instance, do it after all instances were created, so that they all know things
     200        6177 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
     201        4118 :         if (_backends[instance] != nullptr) {
     202         112 :             _backends[instance]->init();
     203         112 :             set_mode_to_default(instance);
     204             :         }
     205             :     }
     206             : 
     207             :     (void)serial_instance;
     208             : }
     209             : 
     210             : // update - give mount opportunity to update servos.  should be called at 10hz or higher
     211     7438628 : void AP_Mount::update()
     212             : {
     213             :     // update each instance
     214    22315884 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
     215    14877256 :         if (_backends[instance] != nullptr) {
     216      399951 :             _backends[instance]->update();
     217             :         }
     218             :     }
     219     7438628 : }
     220             : 
     221             : // used for gimbals that need to read INS data at full rate
     222    32593131 : void AP_Mount::update_fast()
     223             : {
     224             :     // update each instance
     225    97779393 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
     226    65186262 :         if (_backends[instance] != nullptr) {
     227     3181628 :             _backends[instance]->update_fast();
     228             :         }
     229             :     }
     230    32593131 : }
     231             : 
     232             : // get_mount_type - returns the type of mount
     233      266868 : AP_Mount::Type AP_Mount::get_mount_type(uint8_t instance) const
     234             : {
     235      266868 :     if (instance >= AP_MOUNT_MAX_INSTANCES) {
     236           0 :         return Type::None;
     237             :     }
     238             : 
     239      266868 :     return (Type)_params[instance].type.get();
     240             : }
     241             : 
     242             : // has_pan_control - returns true if the mount has yaw control (required for copters)
     243          42 : bool AP_Mount::has_pan_control(uint8_t instance) const
     244             : {
     245          42 :     const auto *backend = get_instance(instance);
     246          42 :     if (backend == nullptr) {
     247           6 :         return false;
     248             :     }
     249             : 
     250             :     // ask backend if it support pan
     251          36 :     return backend->has_pan_control();
     252             : }
     253             : 
     254             : // get_mode - returns current mode of mount (i.e. Retracted, Neutral, RC_Targeting, GPS Point)
     255          67 : MAV_MOUNT_MODE AP_Mount::get_mode(uint8_t instance) const
     256             : {
     257          67 :     const auto *backend = get_instance(instance);
     258          67 :     if (backend == nullptr) {
     259           0 :         return MAV_MOUNT_MODE_RETRACT;
     260             :     }
     261             : 
     262             :     // ask backend its mode
     263          67 :     return backend->get_mode();
     264             : }
     265             : 
     266             : // set_mode_to_default - restores the mode to it's default mode held in the MNTx__DEFLT_MODE parameter
     267             : //      this operation requires 60us on a Pixhawk/PX4
     268         358 : void AP_Mount::set_mode_to_default(uint8_t instance)
     269             : {
     270         358 :     auto *backend = get_instance(instance);
     271         358 :     if (backend == nullptr) {
     272         163 :         return;
     273             :     }
     274         195 :     backend->set_mode((enum MAV_MOUNT_MODE)_params[instance].default_mode.get());
     275             : }
     276             : 
     277             : // set_mode - sets mount's mode
     278          83 : void AP_Mount::set_mode(uint8_t instance, enum MAV_MOUNT_MODE mode)
     279             : {
     280          83 :     auto *backend = get_instance(instance);
     281          83 :     if (backend == nullptr) {
     282           0 :         return;
     283             :     }
     284             : 
     285             :     // call backend's set_mode
     286          83 :     backend->set_mode(mode);
     287             : }
     288             : 
     289             : // set yaw_lock used in RC_TARGETING mode.  If true, the gimbal's yaw target is maintained in earth-frame meaning it will lock onto an earth-frame heading (e.g. North)
     290             : // If false (aka "follow") the gimbal's yaw is maintained in body-frame meaning it will rotate with the vehicle
     291           0 : void AP_Mount::set_yaw_lock(uint8_t instance, bool yaw_lock)
     292             : {
     293           0 :     auto *backend = get_instance(instance);
     294           0 :     if (backend == nullptr) {
     295           0 :         return;
     296             :     }
     297             : 
     298             :     // call backend's set_yaw_lock
     299           0 :     backend->set_yaw_lock(yaw_lock);
     300             : }
     301             : 
     302             : // set roll_lock used in RC_TARGETING mode.  If true, the gimbal's roll target is maintained in earth-frame
     303             : // If false (aka "follow") the gimbal's roll is maintained in body-frame meaning it will rotate with the vehicle
     304           0 : void AP_Mount::set_roll_lock(uint8_t instance, bool roll_lock)
     305             : {
     306           0 :     auto *backend = get_instance(instance);
     307           0 :     if (backend == nullptr) {
     308           0 :         return;
     309             :     }
     310             : 
     311             :     // call backend's set_roll_lock
     312           0 :     backend->set_roll_lock(roll_lock);
     313             : }
     314             : 
     315             : // set pitch_lock used in RC_TARGETING mode.  If true, the gimbal's tilt target is maintained in earth-frame
     316             : // If false (aka "follow") the gimbal's tilt is maintained in body-frame meaning it will tilt with the vehicle
     317           0 : void AP_Mount::set_pitch_lock(uint8_t instance, bool pitch_lock)
     318             : {
     319           0 :     auto *backend = get_instance(instance);
     320           0 :     if (backend == nullptr) {
     321           0 :         return;
     322             :     }
     323             : 
     324             :     // call backend's set_pitch_lock
     325           0 :     backend->set_pitch_lock(pitch_lock);
     326             : }
     327             : 
     328             : 
     329             : // set angle target in degrees
     330             : // roll and pitch are in earth-frame
     331             : // yaw_is_earth_frame (aka yaw_lock) should be true if yaw angle is earth-frame, false if body-frame
     332          83 : void AP_Mount::set_angle_target(uint8_t instance, float roll_deg, float pitch_deg, float yaw_deg, bool yaw_is_earth_frame)
     333             : {
     334          83 :     auto *backend = get_instance(instance);
     335          83 :     if (backend == nullptr) {
     336           0 :         return;
     337             :     }
     338             : 
     339             :     // send command to backend
     340          83 :     backend->set_angle_target(roll_deg, pitch_deg, yaw_deg, yaw_is_earth_frame);
     341             : }
     342             : 
     343             : // sets rate target in deg/s
     344             : // yaw_lock should be true if the yaw rate is earth-frame, false if body-frame (e.g. rotates with body of vehicle)
     345           0 : void AP_Mount::set_rate_target(uint8_t instance, float roll_degs, float pitch_degs, float yaw_degs, bool yaw_lock)
     346             : {
     347           0 :     auto *backend = get_instance(instance);
     348           0 :     if (backend == nullptr) {
     349           0 :         return;
     350             :     }
     351             : 
     352             :     // send command to backend
     353           0 :     backend->set_rate_target(roll_degs, pitch_degs, yaw_degs, yaw_lock);
     354             : }
     355             : 
     356         374 : MAV_RESULT AP_Mount::handle_command_do_mount_configure(const mavlink_command_int_t &packet)
     357             : {
     358         374 :     auto *backend = get_primary();
     359         374 :     if (backend == nullptr) {
     360           0 :         return MAV_RESULT_FAILED;
     361             :     }
     362             : 
     363         374 :     backend->set_mode((MAV_MOUNT_MODE)packet.param1);
     364             : 
     365         374 :     return MAV_RESULT_ACCEPTED;
     366             : }
     367             : 
     368             : 
     369          36 : MAV_RESULT AP_Mount::handle_command_do_mount_control(const mavlink_command_int_t &packet)
     370             : {
     371          36 :     auto *backend = get_primary();
     372          36 :     if (backend == nullptr) {
     373           0 :         return MAV_RESULT_FAILED;
     374             :     }
     375             : 
     376          36 :     return backend->handle_command_do_mount_control(packet);
     377             : }
     378             : 
     379          10 : MAV_RESULT AP_Mount::handle_command_do_gimbal_manager_pitchyaw(const mavlink_command_int_t &packet)
     380             : {
     381          10 :     auto *backend = mount_device_from_mavlink_gimbal_id(packet.z);
     382             : 
     383          10 :     if (backend == nullptr) {
     384           0 :         return MAV_RESULT_FAILED;
     385             :     }
     386             : 
     387             :     // check flags for change to RETRACT
     388          10 :     const uint32_t flags = packet.x;
     389          10 :     if ((flags & GIMBAL_MANAGER_FLAGS_RETRACT) > 0) {
     390           0 :         backend->set_mode(MAV_MOUNT_MODE_RETRACT);
     391           0 :         return MAV_RESULT_ACCEPTED;
     392             :     }
     393             :     // check flags for change to NEUTRAL
     394          10 :     if ((flags & GIMBAL_MANAGER_FLAGS_NEUTRAL) > 0) {
     395           0 :         backend->set_mode(MAV_MOUNT_MODE_NEUTRAL);
     396           0 :         return MAV_RESULT_ACCEPTED;
     397             :     }
     398             : 
     399             :     // param1 : pitch_angle (in degrees)
     400             :     // param2 : yaw angle (in degrees)
     401          10 :     const float pitch_angle_deg = packet.param1;
     402          10 :     const float yaw_angle_deg = packet.param2;
     403          10 :     if (!isnan(pitch_angle_deg) && !isnan(yaw_angle_deg)) {
     404           9 :         backend->set_angle_target(0, pitch_angle_deg, yaw_angle_deg, flags & GIMBAL_MANAGER_FLAGS_YAW_LOCK);
     405           9 :         return MAV_RESULT_ACCEPTED;
     406             :     }
     407             : 
     408             :     // param3 : pitch_rate (in deg/s)
     409             :     // param4 : yaw rate (in deg/s)
     410           1 :     const float pitch_rate_degs = packet.param3;
     411           1 :     const float yaw_rate_degs = packet.param4;
     412           1 :     if (!isnan(pitch_rate_degs) && !isnan(yaw_rate_degs)) {
     413           1 :         backend->set_rate_target(0, pitch_rate_degs, yaw_rate_degs, flags & GIMBAL_MANAGER_FLAGS_YAW_LOCK);
     414           1 :         return MAV_RESULT_ACCEPTED;
     415             :     }
     416             : 
     417             :     // if neither angles nor rates were provided set the RC_TARGETING yaw lock state
     418           0 :     if (isnan(pitch_angle_deg) && isnan(yaw_angle_deg) && isnan(pitch_rate_degs) && isnan(yaw_rate_degs)) {
     419           0 :         backend->set_yaw_lock(flags & GIMBAL_MANAGER_FLAGS_YAW_LOCK);
     420           0 :         return MAV_RESULT_ACCEPTED;
     421             :     }
     422             : 
     423           0 :     return MAV_RESULT_FAILED;
     424             : }
     425             : 
     426             : // handle mav_cmd_do_gimbal_manager_configure for deconflicting different mavlink message senders
     427           8 : MAV_RESULT AP_Mount::handle_command_do_gimbal_manager_configure(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
     428             : {
     429           8 :     auto *backend = mount_device_from_mavlink_gimbal_id(packet.z);
     430             : 
     431           8 :     if (backend == nullptr) {
     432           0 :         return MAV_RESULT_FAILED;
     433             :     }
     434             : 
     435           8 :     return backend->handle_command_do_gimbal_manager_configure(packet, msg);
     436             : }
     437             : 
     438           0 : void AP_Mount::handle_gimbal_manager_set_attitude(const mavlink_message_t &msg)
     439             : {
     440             :     mavlink_gimbal_manager_set_attitude_t packet;
     441           0 :     mavlink_msg_gimbal_manager_set_attitude_decode(&msg,&packet);
     442             : 
     443           0 :     auto *backend = mount_device_from_mavlink_gimbal_id(packet.gimbal_device_id);
     444             : 
     445           0 :     if (backend == nullptr) {
     446           0 :         return;
     447             :     }
     448             : 
     449             :     // check flags for change to RETRACT
     450           0 :     const uint32_t flags = packet.flags;
     451           0 :     if ((flags & GIMBAL_MANAGER_FLAGS_RETRACT) > 0) {
     452           0 :         backend->set_mode(MAV_MOUNT_MODE_RETRACT);
     453           0 :         return;
     454             :     }
     455             : 
     456             :     // check flags for change to NEUTRAL
     457           0 :     if ((flags & GIMBAL_MANAGER_FLAGS_NEUTRAL) > 0) {
     458           0 :         backend->set_mode(MAV_MOUNT_MODE_NEUTRAL);
     459           0 :         return;
     460             :     }
     461             : 
     462           0 :     const Quaternion att_quat{packet.q};
     463             :     const Vector3f att_rate_degs {
     464             :         packet.angular_velocity_x,
     465             :         packet.angular_velocity_y,
     466             :         packet.angular_velocity_z
     467           0 :     };
     468             : 
     469             :     // ensure that we are only demanded to a specific attitude or to
     470             :     // achieve a specific rate.  Do not allow both to be specified at
     471             :     // the same time:
     472           0 :     if (!att_quat.is_nan() && !att_rate_degs.is_nan()) {
     473           0 :         return;
     474             :     }
     475             : 
     476           0 :     if (!att_quat.is_nan()) {
     477             :         // convert quaternion to euler angles
     478           0 :         Vector3f attitude;
     479           0 :         att_quat.to_euler(attitude);  // attitude is in radians here
     480           0 :         attitude *= RAD_TO_DEG;  // convert to degrees
     481             : 
     482           0 :         backend->set_angle_target(attitude.x, attitude.y, attitude.z, flags & GIMBAL_MANAGER_FLAGS_YAW_LOCK);
     483           0 :         return;
     484             :     }
     485             : 
     486             :     {
     487           0 :         const float roll_rate_degs = degrees(packet.angular_velocity_x);
     488           0 :         const float pitch_rate_degs = degrees(packet.angular_velocity_y);
     489           0 :         const float yaw_rate_degs = degrees(packet.angular_velocity_z);
     490           0 :         backend->set_rate_target(roll_rate_degs, pitch_rate_degs, yaw_rate_degs, flags & GIMBAL_MANAGER_FLAGS_YAW_LOCK);
     491           0 :         return;
     492             :     }
     493             : }
     494             : 
     495           0 : void AP_Mount::handle_gimbal_manager_set_pitchyaw(const mavlink_message_t &msg)
     496             : {
     497             :     mavlink_gimbal_manager_set_pitchyaw_t packet;
     498           0 :     mavlink_msg_gimbal_manager_set_pitchyaw_decode(&msg,&packet);
     499             : 
     500           0 :     auto *backend = mount_device_from_mavlink_gimbal_id(packet.gimbal_device_id);
     501             : 
     502           0 :     if (backend == nullptr) {
     503           0 :         return;
     504             :     }
     505             : 
     506             :     // check flags for change to RETRACT
     507           0 :     uint32_t flags = (uint32_t)packet.flags;
     508           0 :     if ((flags & GIMBAL_MANAGER_FLAGS_RETRACT) > 0) {
     509           0 :         backend->set_mode(MAV_MOUNT_MODE_RETRACT);
     510           0 :         return;
     511             :     }
     512             :     // check flags for change to NEUTRAL
     513           0 :     if ((flags & GIMBAL_MANAGER_FLAGS_NEUTRAL) > 0) {
     514           0 :         backend->set_mode(MAV_MOUNT_MODE_NEUTRAL);
     515           0 :         return;
     516             :     }
     517             : 
     518             :     // Do not allow both angle and rate to be specified at the same time
     519           0 :     if (!isnan(packet.pitch) && !isnan(packet.yaw) && !isnan(packet.pitch_rate) && !isnan(packet.yaw_rate)) {
     520           0 :         return;
     521             :     }
     522             : 
     523             :     // pitch and yaw from packet are in radians
     524           0 :     if (!isnan(packet.pitch) && !isnan(packet.yaw)) {
     525           0 :         const float pitch_angle_deg = degrees(packet.pitch);
     526           0 :         const float yaw_angle_deg = degrees(packet.yaw);
     527           0 :         backend->set_angle_target(0, pitch_angle_deg, yaw_angle_deg, flags & GIMBAL_MANAGER_FLAGS_YAW_LOCK);
     528           0 :         return;
     529             :     }
     530             : 
     531             :     // pitch_rate and yaw_rate from packet are in rad/s
     532           0 :     if (!isnan(packet.pitch_rate) && !isnan(packet.yaw_rate)) {
     533           0 :         const float pitch_rate_degs = degrees(packet.pitch_rate);
     534           0 :         const float yaw_rate_degs = degrees(packet.yaw_rate);
     535           0 :         backend->set_rate_target(0, pitch_rate_degs, yaw_rate_degs, flags & GIMBAL_MANAGER_FLAGS_YAW_LOCK);
     536           0 :         return;
     537             :     }
     538             : 
     539             :     // if neither angles nor rates were provided set the RC_TARGETING yaw lock state
     540           0 :     if (isnan(packet.pitch) && isnan(packet.yaw) && isnan(packet.pitch_rate) && isnan(packet.yaw_rate)) {
     541           0 :         backend->set_yaw_lock(flags & GIMBAL_MANAGER_FLAGS_YAW_LOCK);
     542           0 :         return;
     543             :     }
     544             : }
     545             : 
     546           9 : MAV_RESULT AP_Mount::handle_command_do_set_roi_sysid(const mavlink_command_int_t &packet)
     547             : {
     548           9 :     set_target_sysid((uint8_t)packet.param1);
     549           9 :     return MAV_RESULT_ACCEPTED;
     550             : }
     551             : 
     552         437 : MAV_RESULT AP_Mount::handle_command(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
     553             : {
     554         437 :     switch (packet.command) {
     555         374 :     case MAV_CMD_DO_MOUNT_CONFIGURE:
     556         374 :         return handle_command_do_mount_configure(packet);
     557          36 :     case MAV_CMD_DO_MOUNT_CONTROL:
     558          36 :         return handle_command_do_mount_control(packet);
     559          10 :     case MAV_CMD_DO_GIMBAL_MANAGER_PITCHYAW:
     560          10 :         return handle_command_do_gimbal_manager_pitchyaw(packet);
     561           8 :     case MAV_CMD_DO_GIMBAL_MANAGER_CONFIGURE:
     562           8 :         return handle_command_do_gimbal_manager_configure(packet, msg);
     563           9 :     case MAV_CMD_DO_SET_ROI_SYSID:
     564           9 :         return handle_command_do_set_roi_sysid(packet);
     565           0 :     default:
     566           0 :         return MAV_RESULT_UNSUPPORTED;
     567             :     }
     568             : }
     569             : 
     570             : /// Change the configuration of the mount
     571        2801 : void AP_Mount::handle_global_position_int(const mavlink_message_t &msg)
     572             : {
     573             :     mavlink_global_position_int_t packet;
     574        2801 :     mavlink_msg_global_position_int_decode(&msg, &packet);
     575             : 
     576        2801 :     if (!check_latlng(packet.lat, packet.lon)) {
     577           0 :         return;
     578             :     }
     579             : 
     580        8403 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
     581        5602 :         if (_backends[instance] != nullptr) {
     582          12 :             _backends[instance]->handle_global_position_int(msg.sysid, packet);
     583             :         }
     584             :     }
     585             : }
     586             : 
     587             : #if HAL_GCS_ENABLED
     588             : // send a GIMBAL_DEVICE_ATTITUDE_STATUS message to GCS
     589     1115995 : void AP_Mount::send_gimbal_device_attitude_status(mavlink_channel_t chan)
     590             : {
     591             :     // call send_gimbal_device_attitude_status for each instance
     592     3347985 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
     593     2231990 :         if (_backends[instance] != nullptr) {
     594       65396 :             _backends[instance]->send_gimbal_device_attitude_status(chan);
     595             :         }
     596             :     }
     597     1115995 : }
     598             : 
     599             : // send a GIMBAL_MANAGER_INFORMATION message to GCS
     600           0 : void AP_Mount::send_gimbal_manager_information(mavlink_channel_t chan)
     601             : {
     602             :     // call send_gimbal_device_attitude_status for each instance
     603           0 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
     604           0 :         if (_backends[instance] != nullptr) {
     605           0 :             _backends[instance]->send_gimbal_manager_information(chan);
     606             :         }
     607             :     }
     608           0 : }
     609             : 
     610             : // send a GIMBAL_MANAGER_STATUS message to GCS
     611          25 : void AP_Mount::send_gimbal_manager_status(mavlink_channel_t chan)
     612             : {
     613             :     // call send_gimbal_device_attitude_status for each instance
     614          75 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
     615          50 :         if (_backends[instance] != nullptr) {
     616          25 :             _backends[instance]->send_gimbal_manager_status(chan);
     617             :         }
     618             :     }
     619          25 : }
     620             : #endif  // HAL_GCS_ENABLED
     621             : 
     622             : #if AP_MOUNT_POI_TO_LATLONALT_ENABLED
     623             : // get poi information.  Returns true on success and fills in gimbal attitude, location and poi location
     624           0 : bool AP_Mount::get_poi(uint8_t instance, Quaternion &quat, Location &loc, Location &poi_loc) const
     625             : {
     626           0 :     auto *backend = get_instance(instance);
     627           0 :     if (backend == nullptr) {
     628           0 :         return false;
     629             :     }
     630           0 :     return backend->get_poi(instance, quat, loc, poi_loc);
     631             : }
     632             : #endif
     633             : 
     634             : #if AP_MOUNT_POI_LOCK_ENABLED
     635             : // lock currently viewed GPS point and switch to GPS Targeting mode
     636           4 : void AP_Mount::set_poi_lock(uint8_t instance)
     637             : {
     638           4 :     auto *backend = get_instance(instance);
     639           4 :     if (backend == nullptr) {
     640           0 :         return;
     641             :     }
     642             : 
     643             :     // call backend's set_poi_lock
     644           4 :     backend->set_poi_lock();
     645             : }
     646             : 
     647           2 : void AP_Mount::clear_poi_lock(uint8_t instance)
     648             : {
     649           2 :     auto *backend = get_instance(instance);
     650           2 :     if (backend == nullptr) {
     651           2 :         return;
     652             :     }
     653             : 
     654             :     // call backend's clear_poi_lock
     655           0 :     backend->clear_poi_lock();
     656             : }
     657             : 
     658           7 : void AP_Mount::suspend_poi_lock(uint8_t instance)
     659             : {
     660           7 :     auto *backend = get_instance(instance);
     661           7 :     if (backend == nullptr) {
     662           1 :         return;
     663             :     }
     664             : 
     665             :     // call backend's suspend_poi_lock
     666           6 :     backend->suspend_poi_lock();
     667             : }
     668             : #endif // AP_MOUNT_POI_LOCK_ENABLED
     669             : 
     670             : // get attitude as a quaternion.  returns true on success.
     671             : // att_quat will be an earth-frame quaternion rotated such that
     672             : // yaw is in body-frame.
     673       77801 : bool AP_Mount::get_attitude_quaternion(uint8_t instance, Quaternion& att_quat)
     674             : {
     675       77801 :     auto *backend = get_instance(instance);
     676       77801 :     if (backend == nullptr) {
     677           0 :         return false;
     678             :     }
     679       77801 :     return backend->get_attitude_quaternion(att_quat);
     680             : }
     681             : 
     682             : // get mount's current attitude in euler angles in degrees.  yaw angle is in body-frame
     683             : // returns true on success
     684       77801 : bool AP_Mount::get_attitude_euler(uint8_t instance, float& roll_deg, float& pitch_deg, float& yaw_bf_deg)
     685             : {
     686             :     // re-use get_attitude_quaternion and convert to Euler angles
     687       77801 :     Quaternion att_quat;
     688       77801 :     if (!get_attitude_quaternion(instance, att_quat)) {
     689         227 :         return false;
     690             :     }
     691             : 
     692             :     float roll_rad, pitch_rad, yaw_rad;
     693       77574 :     att_quat.to_euler(roll_rad, pitch_rad, yaw_rad);
     694       77574 :     roll_deg = degrees(roll_rad);
     695       77574 :     pitch_deg = degrees(pitch_rad);
     696       77574 :     yaw_bf_deg = degrees(yaw_rad);
     697       77574 :     return true;
     698             : }
     699             : 
     700             : // run pre-arm check.  returns false on failure and fills in failure_msg
     701             : // any failure_msg returned will not include a prefix
     702      131378 : bool AP_Mount::pre_arm_checks(char *failure_msg, uint8_t failure_msg_len)
     703             : {
     704             :     // check type parameters
     705      394098 :     for (uint8_t i=0; i<AP_MOUNT_MAX_INSTANCES; i++) {
     706      262738 :         if ((get_mount_type(i) != Type::None) && (_backends[i] == nullptr)) {
     707          18 :             strncpy(failure_msg, "check TYPE", failure_msg_len);
     708          18 :             return false;
     709             :         }
     710             :     }
     711             : 
     712             :     // return true if no mount configured
     713      131360 :     if (_num_instances == 0) {
     714      130534 :         return true;
     715             :     }
     716             : 
     717             :     // check healthy
     718        2436 :     for (uint8_t i=0; i<AP_MOUNT_MAX_INSTANCES; i++) {
     719        1631 :         if ((_backends[i] != nullptr) && !_backends[i]->healthy()) {
     720          21 :             strncpy(failure_msg, "not healthy", failure_msg_len);
     721          21 :             return false;
     722             :         }
     723             :     }
     724             : 
     725         805 :     return true;
     726             : }
     727             : 
     728             : #if AP_SCRIPTING_ENABLED
     729             : // get target rate in deg/sec. returns true on success
     730           0 : bool AP_Mount::get_rate_target(uint8_t instance, float& roll_degs, float& pitch_degs, float& yaw_degs, bool& yaw_is_earth_frame)
     731             : {
     732           0 :     auto *backend = get_instance(instance);
     733           0 :     if (backend == nullptr) {
     734           0 :         return false;
     735             :     }
     736           0 :     return backend->get_rate_target(roll_degs, pitch_degs, yaw_degs, yaw_is_earth_frame);
     737             : }
     738             : 
     739             : // get target angle in deg. returns true on success
     740        1195 : bool AP_Mount::get_angle_target(uint8_t instance, float& roll_deg, float& pitch_deg, float& yaw_deg, bool& yaw_is_earth_frame)
     741             : {
     742        1195 :     auto *backend = get_instance(instance);
     743        1195 :     if (backend == nullptr) {
     744           0 :         return false;
     745             :     }
     746        1195 :     return backend->get_angle_target(roll_deg, pitch_deg, yaw_deg, yaw_is_earth_frame);
     747             : }
     748             : 
     749             : // get mount target location. returns true on success
     750          67 : bool AP_Mount::get_location_target(uint8_t instance, Location& target_loc)
     751             : {
     752          67 :     auto *backend = get_instance(instance);
     753          67 :     if (backend == nullptr) {
     754           0 :         return false;
     755             :     }
     756          67 :     return backend->get_location_target(target_loc);
     757             : }
     758             : #endif
     759             : 
     760             : // accessory for scripting backends and logging
     761        2548 : void AP_Mount::set_attitude_euler(uint8_t instance, float roll_deg, float pitch_deg, float yaw_bf_deg)
     762             : {
     763        2548 :     auto *backend = get_instance(instance);
     764        2548 :     if (backend == nullptr) {
     765           0 :         return;
     766             :     }
     767        2548 :     backend->set_attitude_euler(roll_deg, pitch_deg, yaw_bf_deg);
     768             : }
     769             : 
     770             : #if AP_SCRIPTING_ENABLED
     771           1 : void AP_Mount::set_natively_supported_mount_target_types(uint8_t instance, uint8_t types_mask)
     772             : {
     773           1 :     auto *backend = get_instance(instance);
     774           1 :     if (backend == nullptr) {
     775           0 :         return;
     776             :     }
     777           1 :     backend->set_natively_supported_mount_target_types(types_mask);
     778             : }
     779             : #endif  // AP_SCRIPTING_ENABLED
     780             : 
     781             : #if HAL_LOGGING_ENABLED
     782             : // write mount log packet for all backends
     783     1392105 : void AP_Mount::write_log()
     784             : {
     785             :     // each instance writes log
     786     4176315 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
     787     2784210 :         if (_backends[instance] != nullptr) {
     788       77783 :             _backends[instance]->write_log(0);
     789             :         }
     790             :     }
     791     1392105 : }
     792             : 
     793          66 : void AP_Mount::write_log(uint8_t instance, uint64_t timestamp_us)
     794             : {
     795          66 :     auto *backend = get_instance(instance);
     796          66 :     if (backend == nullptr) {
     797          49 :         return;
     798             :     }
     799          17 :     backend->write_log(timestamp_us);
     800             : }
     801             : #endif
     802             : 
     803             : // point at system ID sysid
     804           9 : void AP_Mount::set_target_sysid(uint8_t instance, uint8_t sysid)
     805             : {
     806           9 :     auto *backend = get_instance(instance);
     807           9 :     if (backend == nullptr) {
     808           0 :         return;
     809             :     }
     810             :     // call instance's set target SYSID cmd
     811           9 :     backend->set_target_sysid(sysid);
     812             : }
     813             : 
     814             : // set_roi_target - sets target location that mount should attempt to point towards
     815          34 : void AP_Mount::set_roi_target(uint8_t instance, const Location &target_loc)
     816             : {
     817          34 :     auto *backend = get_instance(instance);
     818          34 :     if (backend == nullptr) {
     819           6 :         return;
     820             :     }
     821          28 :     backend->set_roi_target(target_loc);
     822             : }
     823             : 
     824             : // clear_roi_target - clears target location that mount should attempt to point towards
     825          18 : void AP_Mount::clear_roi_target(uint8_t instance)
     826             : {
     827          18 :     auto *backend = get_instance(instance);
     828          18 :     if (backend == nullptr) {
     829           6 :         return;
     830             :     }
     831          12 :     backend->clear_roi_target();
     832             : }
     833             : 
     834             : #if AP_MOUNT_ROI_WPNEXT_OFFSET_ENABLED
     835           3 : void AP_Mount::set_roi_target_wpnext_offset(uint8_t instance, const Vector3f &rpy)
     836             : {
     837           3 :     auto *backend = get_instance(instance);
     838           3 :     if (backend == nullptr) {
     839           0 :         return;
     840             :     }
     841           3 :     backend->set_roi_target_wpnext_offset(rpy);
     842             : }
     843             : #endif  // AP_MOUNT_ROI_WPNEXT_OFFSET_ENABLED
     844             : 
     845             : //
     846             : // camera controls for gimbals that include a camera
     847             : //
     848             : 
     849             : // take a picture.  returns true on success
     850           0 : bool AP_Mount::take_picture(uint8_t instance)
     851             : {
     852           0 :     auto *backend = get_instance(instance);
     853           0 :     if (backend == nullptr) {
     854           0 :         return false;
     855             :     }
     856           0 :     return backend->take_picture();
     857             : }
     858             : 
     859             : // start or stop video recording.  returns true on success
     860             : // set start_recording = true to start record, false to stop recording
     861           0 : bool AP_Mount::record_video(uint8_t instance, bool start_recording)
     862             : {
     863           0 :     auto *backend = get_instance(instance);
     864           0 :     if (backend == nullptr) {
     865           0 :         return false;
     866             :     }
     867           0 :     return backend->record_video(start_recording);
     868             : }
     869             : 
     870             : // set zoom specified as a rate or percentage
     871           0 : bool AP_Mount::set_zoom(uint8_t instance, ZoomType zoom_type, float zoom_value)
     872             : {
     873           0 :     auto *backend = get_instance(instance);
     874           0 :     if (backend == nullptr) {
     875           0 :         return false;
     876             :     }
     877           0 :     return backend->set_zoom(zoom_type, zoom_value);
     878             : }
     879             : 
     880             : // set focus specified as rate, percentage or auto
     881             : // focus in = -1, focus hold = 0, focus out = 1
     882           0 : SetFocusResult AP_Mount::set_focus(uint8_t instance, FocusType focus_type, float focus_value)
     883             : {
     884           0 :     auto *backend = get_instance(instance);
     885           0 :     if (backend == nullptr) {
     886           0 :         return SetFocusResult::FAILED;
     887             :     }
     888           0 :     return backend->set_focus(focus_type, focus_value);
     889             : }
     890             : 
     891             : // set tracking to none, point or rectangle (see TrackingType enum)
     892             : // if POINT only p1 is used, if RECTANGLE then p1 is top-left, p2 is bottom-right
     893             : // p1,p2 are in range 0 to 1.  0 is left or top, 1 is right or bottom
     894           0 : bool AP_Mount::set_tracking(uint8_t instance, TrackingType tracking_type, const Vector2f& p1, const Vector2f& p2)
     895             : {
     896           0 :     auto *backend = get_instance(instance);
     897           0 :     if (backend == nullptr) {
     898           0 :         return false;
     899             :     }
     900           0 :     return backend->set_tracking(tracking_type, p1, p2);
     901             : }
     902             : 
     903             : // set camera lens as a value from 0 to 5
     904           0 : bool AP_Mount::set_lens(uint8_t instance, uint8_t lens)
     905             : {
     906           0 :     auto *backend = get_instance(instance);
     907           0 :     if (backend == nullptr) {
     908           0 :         return false;
     909             :     }
     910           0 :     return backend->set_lens(lens);
     911             : }
     912             : 
     913             : #if HAL_MOUNT_SET_CAMERA_SOURCE_ENABLED
     914             : // set_camera_source is functionally the same as set_lens except primary and secondary lenses are specified by type
     915             : // primary and secondary sources use the AP_Camera::CameraSource enum cast to uint8_t
     916           0 : bool AP_Mount::set_camera_source(uint8_t instance, uint8_t primary_source, uint8_t secondary_source)
     917             : {
     918           0 :     auto *backend = get_instance(instance);
     919           0 :     if (backend == nullptr) {
     920           0 :         return false;
     921             :     }
     922           0 :     return backend->set_camera_source(primary_source, secondary_source);
     923             : }
     924             : #endif
     925             : 
     926             : // send camera information message to GCS
     927           5 : void AP_Mount::send_camera_information(uint8_t instance, mavlink_channel_t chan) const
     928             : {
     929           5 :     auto *backend = get_instance(instance);
     930           5 :     if (backend == nullptr) {
     931           0 :         return;
     932             :     }
     933           5 :     backend->send_camera_information(chan);
     934             : }
     935             : 
     936             : // send camera settings message to GCS
     937           0 : void AP_Mount::send_camera_settings(uint8_t instance, mavlink_channel_t chan) const
     938             : {
     939           0 :     auto *backend = get_instance(instance);
     940           0 :     if (backend == nullptr) {
     941           0 :         return;
     942             :     }
     943           0 :     backend->send_camera_settings(chan);
     944             : }
     945             : 
     946             : // send camera capture status message to GCS
     947           0 : void AP_Mount::send_camera_capture_status(uint8_t instance, mavlink_channel_t chan) const
     948             : {
     949           0 :     auto *backend = get_instance(instance);
     950           0 :     if (backend == nullptr) {
     951           0 :         return;
     952             :     }
     953           0 :     backend->send_camera_capture_status(chan);
     954             : }
     955             : 
     956             : #if AP_MOUNT_SEND_THERMAL_RANGE_ENABLED
     957             : // send camera thermal range message to GCS
     958           0 : void AP_Mount::send_camera_thermal_range(uint8_t instance, mavlink_channel_t chan) const
     959             : {
     960           0 :     auto *backend = get_instance(instance);
     961           0 :     if (backend == nullptr) {
     962           0 :         return;
     963             :     }
     964           0 :     backend->send_camera_thermal_range(chan);
     965             : }
     966             : #endif
     967             : 
     968             : // change camera settings not normally used by autopilot
     969             : // setting values from AP_Camera::Setting enum
     970           0 : bool AP_Mount::change_setting(uint8_t instance, CameraSetting setting, float value)
     971             : {
     972           0 :     auto *backend = get_instance(instance);
     973           0 :     if (backend == nullptr) {
     974           0 :         return false;
     975             :     }
     976           0 :     return backend->change_setting(setting, value);
     977             : }
     978             : 
     979             : // get rangefinder distance.  Returns true on success
     980           0 : bool AP_Mount::get_rangefinder_distance(uint8_t instance, float& distance_m) const
     981             : {
     982           0 :     auto *backend = get_instance(instance);
     983           0 :     if (backend == nullptr) {
     984           0 :         return false;
     985             :     }
     986           0 :     return backend->get_rangefinder_distance(distance_m);
     987             : }
     988             : 
     989             : // enable/disable rangefinder.  Returns true on success
     990           0 : bool AP_Mount::set_rangefinder_enable(uint8_t instance, bool enable)
     991             : {
     992           0 :     auto *backend = get_instance(instance);
     993           0 :     if (backend == nullptr) {
     994           0 :         return false;
     995             :     }
     996           0 :     return backend->set_rangefinder_enable(enable);
     997             : }
     998             : 
     999         428 : AP_Mount_Backend *AP_Mount::get_primary() const
    1000             : {
    1001         428 :     return get_instance(_primary);
    1002             : }
    1003             : 
    1004       82821 : AP_Mount_Backend *AP_Mount::get_instance(uint8_t instance) const
    1005             : {
    1006       82821 :     if (instance >= ARRAY_SIZE(_backends)) {
    1007           0 :         return nullptr;
    1008             :     }
    1009       82821 :     return _backends[instance];
    1010             : }
    1011             : 
    1012             : // This is the mapping between gimbal_device_id (defined by MAVLink) and actual devices (aka 'instances', 'backends')
    1013          18 : AP_Mount_Backend *AP_Mount::mount_device_from_mavlink_gimbal_id(uint8_t gimbal_device_id) const
    1014             : {
    1015             :     // FIXME: This function's behavior when gimbal_device_id == 0 is a bug. (That should indicate 'all mounts', not 'primary'.)
    1016             :     // Affects: Users working with multiple mounts.
    1017             :     // Workaround: Leave this as-is until it can be fixed in synchrony with upstream to prevent unexpected behavior-change.
    1018             :     // See: https://github.com/ArduPilot/ardupilot/issues/31940
    1019          18 :     if (gimbal_device_id == 0) {
    1020          18 :         return get_primary();
    1021             :     }
    1022           0 :     return get_instance(gimbal_device_id - 1);
    1023             : }
    1024             : 
    1025             : // pass a GIMBAL_REPORT message to the backend
    1026       18195 : void AP_Mount::handle_gimbal_report(mavlink_channel_t chan, const mavlink_message_t &msg)
    1027             : {
    1028       54585 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
    1029       36390 :         if (_backends[instance] != nullptr) {
    1030       18195 :             _backends[instance]->handle_gimbal_report(chan, msg);
    1031             :         }
    1032             :     }
    1033       18195 : }
    1034             : 
    1035       23720 : void AP_Mount::handle_message(mavlink_channel_t chan, const mavlink_message_t &msg)
    1036             : {
    1037       23720 :     switch (msg.msgid) {
    1038       18195 :     case MAVLINK_MSG_ID_GIMBAL_REPORT:
    1039       18195 :         handle_gimbal_report(chan, msg);
    1040       18195 :         break;
    1041        2801 :     case MAVLINK_MSG_ID_GLOBAL_POSITION_INT:
    1042        2801 :         handle_global_position_int(msg);
    1043        2801 :         break;
    1044           0 :     case MAVLINK_MSG_ID_GIMBAL_MANAGER_SET_ATTITUDE:
    1045           0 :         handle_gimbal_manager_set_attitude(msg);
    1046           0 :         break;
    1047           0 :     case MAVLINK_MSG_ID_GIMBAL_MANAGER_SET_PITCHYAW:
    1048           0 :         handle_gimbal_manager_set_pitchyaw(msg);
    1049           0 :         break;
    1050           4 :     case MAVLINK_MSG_ID_GIMBAL_DEVICE_INFORMATION:
    1051           4 :         handle_gimbal_device_information(msg);
    1052           4 :         break;
    1053        2720 :     case MAVLINK_MSG_ID_GIMBAL_DEVICE_ATTITUDE_STATUS:
    1054        2720 :         handle_gimbal_device_attitude_status(msg);
    1055        2720 :         break;
    1056           0 :     default:
    1057             : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
    1058           0 :         AP_HAL::panic("Unhandled mount case");
    1059             : #endif
    1060           0 :         break;
    1061             :     }
    1062       23720 : }
    1063             : 
    1064             : // handle PARAM_VALUE
    1065          26 : void AP_Mount::handle_param_value(const mavlink_message_t &msg)
    1066             : {
    1067          78 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
    1068          52 :         if (_backends[instance] != nullptr) {
    1069          26 :             _backends[instance]->handle_param_value(msg);
    1070             :         }
    1071             :     }
    1072          26 : }
    1073             : 
    1074             : 
    1075             : // handle GIMBAL_DEVICE_INFORMATION message
    1076           4 : void AP_Mount::handle_gimbal_device_information(const mavlink_message_t &msg)
    1077             : {
    1078          12 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
    1079           8 :         if (_backends[instance] != nullptr) {
    1080           8 :             _backends[instance]->handle_gimbal_device_information(msg);
    1081             :         }
    1082             :     }
    1083           4 : }
    1084             : 
    1085             : // handle GIMBAL_DEVICE_ATTITUDE_STATUS message
    1086        2720 : void AP_Mount::handle_gimbal_device_attitude_status(const mavlink_message_t &msg)
    1087             : {
    1088        8160 :     for (uint8_t instance=0; instance<AP_MOUNT_MAX_INSTANCES; instance++) {
    1089        5440 :         if (_backends[instance] != nullptr) {
    1090        5400 :             _backends[instance]->handle_gimbal_device_attitude_status(msg);
    1091             :         }
    1092             :     }
    1093        2720 : }
    1094             : 
    1095             : // singleton instance
    1096             : AP_Mount *AP_Mount::_singleton;
    1097             : 
    1098             : namespace AP {
    1099             : 
    1100     1275068 : AP_Mount *mount()
    1101             : {
    1102     1275068 :     return AP_Mount::get_singleton();
    1103             : }
    1104             : 
    1105             : };
    1106             : 
    1107             : #endif /* HAL_MOUNT_ENABLED */

Generated by: LCOV version 1.14