LCOV - code coverage report
Current view: top level - AP_Camera - AP_Camera.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 239 554 43.1 %
Date: 2026-09-09 11:02:08 Functions: 24 52 46.2 %

          Line data    Source code
       1             : #include "AP_Camera.h"
       2             : 
       3             : #if AP_CAMERA_ENABLED
       4             : 
       5             : #include <GCS_MAVLink/GCS.h>
       6             : #include <AP_Math/AP_Math.h>
       7             : #include <AP_HAL/AP_HAL.h>
       8             : #include <SRV_Channel/SRV_Channel.h>
       9             : #include <AP_Vehicle/AP_Vehicle.h>
      10             : #include "AP_Camera_Backend.h"
      11             : #include "AP_Camera_Servo.h"
      12             : #include "AP_Camera_Relay.h"
      13             : #include "AP_Camera_SoloGimbal.h"
      14             : #include "AP_Camera_Mount.h"
      15             : #include "AP_Camera_MAVLink.h"
      16             : #include "AP_Camera_MAVLinkCamV2.h"
      17             : #include "AP_Camera_Scripting.h"
      18             : #include "AP_RunCam.h"
      19             : 
      20             : const AP_Param::GroupInfo AP_Camera::var_info[] = {
      21             : 
      22             :     // @Param: _MAX_ROLL
      23             :     // @DisplayName: Maximum photo roll angle.
      24             :     // @Description: Postpone shooting if roll is greater than limit. (0=Disable, will shoot regardless of roll).
      25             :     // @User: Standard
      26             :     // @Units: deg
      27             :     // @Range: 0 180
      28             :     AP_GROUPINFO("_MAX_ROLL",  7, AP_Camera, _max_roll, 0),
      29             : 
      30             :     // @Param: _AUTO_ONLY
      31             :     // @DisplayName: Distance-trigging in AUTO mode only
      32             :     // @Description: When enabled, trigging by distance is done in AUTO mode only.
      33             :     // @Values: 0:Always,1:Only when in AUTO
      34             :     // @User: Standard
      35             :     AP_GROUPINFO("_AUTO_ONLY",  10, AP_Camera, _auto_mode_only, 0),
      36             : 
      37             :     // @Group: 1
      38             :     // @Path: AP_Camera_Params.cpp
      39             :     AP_SUBGROUPINFO(_params[0], "1", 12, AP_Camera, AP_Camera_Params),
      40             : 
      41             : #if AP_CAMERA_MAX_INSTANCES > 1
      42             :     // @Group: 2
      43             :     // @Path: AP_Camera_Params.cpp
      44             :     AP_SUBGROUPINFO(_params[1], "2", 13, AP_Camera, AP_Camera_Params),
      45             : #endif
      46             : #if AP_CAMERA_RUNCAM_ENABLED
      47             :     // @Group: 1_RC_
      48             :     // @Path: AP_RunCam.cpp
      49             :     AP_SUBGROUPVARPTR(_backends[0], "1_RC_", 14, AP_Camera, _backend_var_info[0]),
      50             : 
      51             : #if AP_CAMERA_MAX_INSTANCES > 1
      52             :     // @Group: 2_RC_
      53             :     // @Path: AP_RunCam.cpp
      54             :     AP_SUBGROUPVARPTR(_backends[1], "2_RC_", 15, AP_Camera, _backend_var_info[1]),
      55             : #endif
      56             : #endif
      57             :     AP_GROUPEND
      58             : };
      59             : 
      60             : #if AP_CAMERA_RUNCAM_ENABLED
      61             : const AP_Param::GroupInfo *AP_Camera::_backend_var_info[AP_CAMERA_MAX_INSTANCES];
      62             : #endif
      63             : 
      64             : extern const AP_HAL::HAL& hal;
      65             : 
      66        2061 : AP_Camera::AP_Camera(uint32_t _log_camera_bit) :
      67        6183 :     log_camera_bit(_log_camera_bit)
      68             : {
      69        2061 :     AP_Param::setup_object_defaults(this, var_info);
      70        2061 :     _singleton = this;
      71        2061 : }
      72             : 
      73             : // momentary switch to change camera between picture and video modes
      74           0 : void AP_Camera::cam_mode_toggle()
      75             : {
      76           0 :     WITH_SEMAPHORE(_rsem);
      77             : 
      78           0 :     if (primary == nullptr) {
      79           0 :         return;
      80             :     }
      81           0 :     primary->cam_mode_toggle();
      82           0 : }
      83             : 
      84             : // take a picture
      85           6 : bool AP_Camera::take_picture()
      86             : {
      87           6 :     WITH_SEMAPHORE(_rsem);
      88             : 
      89             :     // call for each instance
      90           6 :     bool success = false;
      91          18 :     for (uint8_t i = 0; i < AP_CAMERA_MAX_INSTANCES; i++) {
      92          12 :         if (_backends[i] != nullptr) {
      93           6 :             success |= _backends[i]->take_picture();
      94             :         }
      95             :     }
      96             : 
      97             :     // return true if at least once pic taken
      98          12 :     return success;
      99           6 : }
     100             : 
     101           1 : bool AP_Camera::take_picture(uint8_t instance)
     102             : {
     103           1 :     WITH_SEMAPHORE(_rsem);
     104             : 
     105           1 :     auto *backend = get_instance(instance);
     106           1 :     if (backend == nullptr) {
     107           0 :         return false;
     108             :     }
     109           1 :     return backend->take_picture();
     110           1 : }
     111             : 
     112             : // take multiple pictures, time_interval between two consecutive pictures is in miliseconds
     113             : // if instance is not provided, all available cameras affected
     114             : // time_interval_ms must be positive
     115             : // total_num is number of pictures to be taken, -1 means capture forever
     116             : // returns true if at least one camera is successful
     117           0 : bool AP_Camera::take_multiple_pictures(uint32_t time_interval_ms, int16_t total_num)
     118             : {
     119           0 :     WITH_SEMAPHORE(_rsem);
     120             : 
     121             :     // sanity check time interval
     122           0 :     if (time_interval_ms == 0) {
     123           0 :         return false;
     124             :     }
     125             : 
     126             :     // call for all instances
     127           0 :     bool success = false;
     128           0 :     for (uint8_t i = 0; i < AP_CAMERA_MAX_INSTANCES; i++) {
     129           0 :         if (_backends[i] != nullptr) {
     130           0 :             _backends[i]->take_multiple_pictures(time_interval_ms, total_num);
     131           0 :             success = true;
     132             :         }
     133             :     }
     134             : 
     135             :     // return true if at least once backend was successful
     136           0 :     return success;
     137           0 : }
     138             : 
     139           2 : bool AP_Camera::take_multiple_pictures(uint8_t instance, uint32_t time_interval_ms, int16_t total_num)
     140             : {
     141           2 :     WITH_SEMAPHORE(_rsem);
     142             : 
     143             :     // sanity check time interval
     144           2 :     if (time_interval_ms == 0) {
     145           0 :         return false;
     146             :     }
     147             : 
     148           2 :     auto *backend = get_instance(instance);
     149           2 :     if (backend == nullptr) {
     150           0 :         return false;
     151             :     }
     152           2 :     backend->take_multiple_pictures(time_interval_ms, total_num);
     153           2 :     return true;
     154           2 : }
     155             : 
     156             : // stop capturing multiple image sequence
     157           0 : void AP_Camera::stop_capture()
     158             : {
     159           0 :     WITH_SEMAPHORE(_rsem);
     160             : 
     161             :     // call for each instance
     162           0 :     for (uint8_t i = 0; i < AP_CAMERA_MAX_INSTANCES; i++) {
     163           0 :         if (_backends[i] != nullptr) {
     164           0 :             _backends[i]->stop_capture();
     165             :         }
     166             :     }
     167           0 : }
     168             : 
     169           1 : bool AP_Camera::stop_capture(uint8_t instance)
     170             : {
     171           1 :     WITH_SEMAPHORE(_rsem);
     172             : 
     173           1 :     auto *backend = get_instance(instance);
     174           1 :     if (backend == nullptr) {
     175           0 :         return false;
     176             :     }
     177           1 :     backend->stop_capture();
     178           1 :     return true;
     179           1 : }
     180             : 
     181             : // start/stop recording video
     182             : // start_recording should be true to start recording, false to stop recording
     183           0 : bool AP_Camera::record_video(bool start_recording)
     184             : {
     185           0 :     WITH_SEMAPHORE(_rsem);
     186             : 
     187           0 :     if (primary == nullptr) {
     188           0 :         return false;
     189             :     }
     190           0 :     return primary->record_video(start_recording);
     191           0 : }
     192             : 
     193             : // detect and initialise backends
     194        2059 : void AP_Camera::init()
     195             : {
     196             :     // check init has not been called before
     197        2059 :     if (primary != nullptr) {
     198           0 :         return;
     199             :     }
     200             : 
     201             :     // perform any required parameter conversion
     202        2059 :     convert_params();
     203             : #if AP_CAMERA_RUNCAM_ENABLED && (AP_CAMERA_MAX_INSTANCES > 1)
     204        2059 :     convert_runcam_params();
     205             : #endif // AP_CAMERA_RUNCAM_ENABLED && (AP_CAMERA_MAX_INSTANCES > 1)
     206             : 
     207             :     // create each instance
     208        6177 :     for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
     209        4118 :         switch ((CameraType)_params[instance].type.get()) {
     210             : #if AP_CAMERA_SERVO_ENABLED
     211           5 :         case CameraType::SERVO:
     212           5 :             _backends[instance] = NEW_NOTHROW AP_Camera_Servo(*this, _params[instance], instance);
     213           5 :             break;
     214             : #endif
     215             : #if AP_CAMERA_RELAY_ENABLED
     216           0 :         case CameraType::RELAY:
     217           0 :             _backends[instance] = NEW_NOTHROW AP_Camera_Relay(*this, _params[instance], instance);
     218           0 :             break;
     219             : #endif
     220             : #if AP_CAMERA_SOLOGIMBAL_ENABLED
     221             :         // check for GoPro in Solo camera
     222           0 :         case CameraType::SOLOGIMBAL:
     223           0 :             _backends[instance] = NEW_NOTHROW AP_Camera_SoloGimbal(*this, _params[instance], instance);
     224           0 :             break;
     225             : #endif
     226             : #if AP_CAMERA_MOUNT_ENABLED
     227             :         // check for Mount camera
     228           5 :         case CameraType::MOUNT:
     229           5 :             _backends[instance] = NEW_NOTHROW AP_Camera_Mount(*this, _params[instance], instance);
     230           5 :             break;
     231             : #endif
     232             : #if AP_CAMERA_MAVLINK_ENABLED
     233             :         // check for MAVLink enabled camera driver
     234           1 :         case CameraType::MAVLINK:
     235           1 :             _backends[instance] = NEW_NOTHROW AP_Camera_MAVLink(*this, _params[instance], instance);
     236           1 :             break;
     237             : #endif
     238             : #if AP_CAMERA_MAVLINKCAMV2_ENABLED
     239             :         // check for MAVLink Camv2 driver
     240           4 :         case CameraType::MAVLINK_CAMV2:
     241           4 :             _backends[instance] = NEW_NOTHROW AP_Camera_MAVLinkCamV2(*this, _params[instance], instance);
     242           4 :             break;
     243             : #endif
     244             : #if AP_CAMERA_SCRIPTING_ENABLED
     245             :         // check for Scripting driver
     246           0 :         case CameraType::SCRIPTING:
     247           0 :             _backends[instance] = NEW_NOTHROW AP_Camera_Scripting(*this, _params[instance], instance);
     248           0 :             break;
     249             : #endif
     250             : #if AP_CAMERA_RUNCAM_ENABLED
     251             :         // check for RunCam driver
     252           6 :         case CameraType::RUNCAM:
     253           6 :             if (_backends[instance] == nullptr) { // may have already been created by the conversion code
     254           6 :                 _backends[instance] = NEW_NOTHROW AP_RunCam(*this, _params[instance], instance, _runcam_instances);
     255           6 :                 _backend_var_info[instance] = AP_RunCam::var_info;
     256           6 :                 AP_Param::load_object_from_eeprom(_backends[instance], _backend_var_info[instance]);
     257           6 :                 _runcam_instances++;
     258             :             }
     259           6 :             break;
     260             : #endif
     261        4097 :         case CameraType::NONE:
     262        4097 :             break;
     263             :         }
     264             : 
     265             :         // set primary to first non-null instance
     266        4118 :         if (primary == nullptr) {
     267        4099 :             primary = _backends[instance];
     268             :         }
     269             :     }
     270             : 
     271             :     // init each instance, do it after all instances were created, so that they all know things
     272        6177 :     for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
     273        4118 :         if (_backends[instance] != nullptr) {
     274          21 :             _backends[instance]->init();
     275             :         }
     276             :     }
     277             : }
     278             : 
     279             : // handle incoming mavlink messages
     280           5 : void AP_Camera::handle_message(mavlink_channel_t chan, const mavlink_message_t &msg)
     281             : {
     282           5 :     WITH_SEMAPHORE(_rsem);
     283             : 
     284           5 :     if (msg.msgid == MAVLINK_MSG_ID_DIGICAM_CONTROL) {
     285             :         // decode deprecated MavLink message that controls camera.
     286             :         __mavlink_digicam_control_t packet;
     287           1 :         mavlink_msg_digicam_control_decode(&msg, &packet);
     288           1 :         control(packet.session, packet.zoom_pos, packet.zoom_step, packet.focus_lock, packet.shot, packet.command_id);
     289           1 :         return;
     290             :     }
     291             : 
     292             :     // call each instance
     293          12 :     for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
     294           8 :         if (_backends[instance] != nullptr) {
     295           8 :             _backends[instance]->handle_message(chan, msg);
     296             :         }
     297             :     }
     298           5 : }
     299             : 
     300             : #if HAL_MAVLINK_BINDINGS_ENABLED
     301             : // a method which handles mavlink-style semantics for instance_id; if
     302             : // instance_id is zero or matches backend instance ID code is run
     303          15 : MAV_RESULT AP_Camera::handle_mav_DO_SET_CAM_TRIGG_DISTANCE(uint8_t instance_id, bool trigger, float dist_m)
     304             : {
     305          45 :     for (uint8_t i=0; i<AP_CAMERA_MAX_INSTANCES; i++) {
     306          30 :         if (_backends[i] == nullptr) {
     307          22 :             continue;
     308             :         }
     309             :         // honour packet instance number:
     310           8 :         if (instance_id != 0 && i+1 != instance_id) {
     311           2 :             continue;
     312             :         }
     313           6 :         _backends[i]->set_trigger_distance(dist_m);
     314           6 :         if (trigger) {
     315           4 :             _backends[i]->take_picture();
     316             :         }
     317             :     }
     318             : 
     319          15 :     return MAV_RESULT_ACCEPTED;
     320             : }
     321             : 
     322           5 : MAV_RESULT AP_Camera::handle_mav_SET_CAMERA_ZOOM(uint8_t instance_id, CAMERA_ZOOM_TYPE mav_zoom_type, float zoom_value)
     323             : {
     324             :     ZoomType zoom_type;
     325           5 :     switch (mav_zoom_type) {
     326           0 :     case ZOOM_TYPE_CONTINUOUS:
     327           0 :         zoom_type = ZoomType::RATE;
     328           0 :         break;
     329           5 :     case ZOOM_TYPE_RANGE:
     330           5 :         zoom_type = ZoomType::PCT;
     331           5 :         break;
     332           0 :     default:
     333             :         // invalid param1
     334           0 :         return MAV_RESULT_DENIED;
     335             :     }
     336             : 
     337           5 :     MAV_RESULT result = MAV_RESULT_ACCEPTED;
     338          15 :     for (uint8_t i=0; i<AP_CAMERA_MAX_INSTANCES; i++) {
     339          10 :         if (_backends[i] == nullptr) {
     340           0 :             continue;
     341             :         }
     342             :         // honour packet instance number:
     343          10 :         if (instance_id != 0 && i+1 != instance_id) {
     344           4 :             continue;
     345             :         }
     346             :         // all backends must succeed:
     347           6 :         if (!_backends[i]->set_zoom(zoom_type, zoom_value)) {
     348           0 :             result = MAV_RESULT_FAILED;
     349             :         }
     350             :     }
     351             : 
     352           5 :     return result;
     353             : }
     354             : 
     355           5 : MAV_RESULT AP_Camera::handle_mav_SET_CAMERA_FOCUS(uint8_t instance_id, SET_FOCUS_TYPE mav_focus_type, float focus_value)
     356             : {
     357             :     // note: focus_value can be modified before it is used
     358             : 
     359             :     FocusType focus_type;
     360           5 :     switch (mav_focus_type) {
     361           0 :     case FOCUS_TYPE_AUTO:
     362             :     case FOCUS_TYPE_AUTO_SINGLE:
     363             :     case FOCUS_TYPE_AUTO_CONTINUOUS:
     364             :         // accept any of the auto focus types
     365           0 :         focus_type = FocusType::AUTO;
     366           0 :         focus_value = 0;
     367           0 :         break;
     368           0 :     case FOCUS_TYPE_CONTINUOUS:
     369             :         // accept continuous manual focus
     370           0 :         focus_type = FocusType::RATE;
     371           0 :         break;
     372           5 :     case FOCUS_TYPE_RANGE:
     373             :         // accept focus as percentage
     374           5 :         focus_type = FocusType::PCT;
     375           5 :         break;
     376           0 :     case SET_FOCUS_TYPE_ENUM_END:
     377             :     case FOCUS_TYPE_STEP:
     378             :     case FOCUS_TYPE_METERS:
     379             :     default:  // mav_focus_type comes off the wire so could be anything
     380             :         // unsupported focus (bad parameter)
     381           0 :         return MAV_RESULT_DENIED;
     382             :     }
     383             : 
     384           5 :     MAV_RESULT result = MAV_RESULT_ACCEPTED;
     385          15 :     for (uint8_t i=0; i<AP_CAMERA_MAX_INSTANCES; i++) {
     386          10 :         if (_backends[i] == nullptr) {
     387           0 :             continue;
     388             :         }
     389             :         // honour packet instance number:
     390          10 :         if (instance_id != 0 && i+1 != instance_id) {
     391           4 :             continue;
     392             :         }
     393             :         // all backends must succeed.  If any fail we pass back the
     394             :         // result from the last camera that failed.
     395           6 :         const SetFocusResult backend_result = _backends[i]->set_focus(focus_type, focus_value);
     396           6 :         if (backend_result != SetFocusResult::ACCEPTED) {
     397             :             // for now FocusResult can just be cast into MAV_RESULT:
     398           0 :             result = (MAV_RESULT)backend_result;
     399             :         }
     400             :     }
     401             : 
     402           5 :     return result;
     403             : }
     404             : #endif  // HAL_MAVLINK_BINDINGS_ENABLED
     405             : 
     406             : // handle command_long mavlink messages
     407          13 : MAV_RESULT AP_Camera::handle_command(const mavlink_command_int_t &packet)
     408             : {
     409          13 :     switch (packet.command) {
     410           2 :     case MAV_CMD_DO_DIGICAM_CONFIGURE:
     411           2 :         configure(packet.param1, packet.param2, packet.param3, packet.param4, packet.x, packet.y, packet.z);
     412           2 :         return MAV_RESULT_ACCEPTED;
     413           2 :     case MAV_CMD_DO_DIGICAM_CONTROL:
     414           2 :         control(packet.param1, packet.param2, packet.param3, packet.param4, packet.x, packet.y);
     415           2 :         return MAV_RESULT_ACCEPTED;
     416           3 :     case MAV_CMD_DO_SET_CAM_TRIGG_DIST:
     417           3 :         return handle_mav_DO_SET_CAM_TRIGG_DISTANCE(
     418           3 :             packet.param4,                  // instance
     419           3 :             is_equal(packet.param3, 1.0f),  // trigger
     420           3 :             packet.param1                   // distance
     421           3 :         );
     422           3 :     case MAV_CMD_SET_CAMERA_ZOOM:
     423           3 :         return handle_mav_SET_CAMERA_ZOOM(
     424           3 :             packet.param3,                   // instance
     425           3 :             CAMERA_ZOOM_TYPE(packet.param1), // zoom type
     426           3 :             packet.param2                    // zoom level
     427           3 :         );
     428           3 :     case MAV_CMD_SET_CAMERA_FOCUS:
     429           3 :         return handle_mav_SET_CAMERA_FOCUS(
     430           3 :             packet.param3,                   // instance
     431           3 :             SET_FOCUS_TYPE(packet.param1),   // focus type
     432           3 :             packet.param2                    // focus value
     433           3 :         );
     434             : 
     435             : #if AP_CAMERA_SET_CAMERA_SOURCE_ENABLED
     436           0 :     case MAV_CMD_SET_CAMERA_SOURCE:
     437             :         // sanity check instance
     438           0 :         if (is_negative(packet.param1) || packet.param1 > AP_CAMERA_MAX_INSTANCES) {
     439           0 :             return MAV_RESULT_DENIED;
     440             :         }
     441           0 :         if (is_zero(packet.param1)) {
     442             :             // set camera source for all backends
     443           0 :             bool accepted = false;
     444           0 :             for (uint8_t i = 0; i < ARRAY_SIZE(_backends); i++) {
     445           0 :                 if (_backends[i] != nullptr) {
     446           0 :                     accepted |= set_camera_source(i, (AP_Camera::CameraSource)packet.param2, (AP_Camera::CameraSource)packet.param3);
     447             :                 }
     448             :             }
     449           0 :             return accepted ? MAV_RESULT_ACCEPTED : MAV_RESULT_DENIED;
     450             :         }
     451           0 :         if (set_camera_source(packet.param1-1, (AP_Camera::CameraSource)packet.param2, (AP_Camera::CameraSource)packet.param3)) {
     452           0 :             return MAV_RESULT_ACCEPTED;
     453             :         }
     454           0 :         return MAV_RESULT_DENIED;
     455             : #endif
     456             : 
     457           0 :     case MAV_CMD_IMAGE_START_CAPTURE:
     458             :         // param1 : camera id
     459             :         // param2 : interval (in seconds)
     460             :         // param3 : total num images
     461             :         // sanity check instance
     462           0 :         if (is_negative(packet.param1)) {
     463           0 :             return MAV_RESULT_UNSUPPORTED;
     464             :         }
     465             :         // check if this is a single picture request (e.g. total images is 1 or interval and total images are zero)
     466           0 :         if (is_equal(packet.param3, 1.0f) ||
     467           0 :             (is_zero(packet.param2) && is_zero(packet.param3))) {
     468           0 :             if (is_zero(packet.param1)) {
     469             :                 // take pictures for every backend
     470           0 :                 return take_picture() ? MAV_RESULT_ACCEPTED : MAV_RESULT_FAILED;
     471             :             }
     472             :             // take picture for specified instance
     473           0 :             return take_picture(packet.param1-1) ? MAV_RESULT_ACCEPTED : MAV_RESULT_FAILED;
     474           0 :         } else if (is_zero(packet.param3)) {
     475             :             // multiple picture request, take pictures forever
     476           0 :             if (is_zero(packet.param1)) {
     477             :                 // take pictures for every backend
     478           0 :                 return take_multiple_pictures(packet.param2*1000, -1) ? MAV_RESULT_ACCEPTED : MAV_RESULT_FAILED;
     479             :             }
     480           0 :             return take_multiple_pictures(packet.param1-1, packet.param2*1000, -1) ? MAV_RESULT_ACCEPTED : MAV_RESULT_FAILED;
     481             :         } else {
     482             :             // take multiple pictures equal to the number specified in param3
     483           0 :             if (is_zero(packet.param1)) {
     484             :                 // take pictures for every backend
     485           0 :                 return take_multiple_pictures(packet.param2*1000, packet.param3) ? MAV_RESULT_ACCEPTED : MAV_RESULT_FAILED;
     486             :             }
     487           0 :             return take_multiple_pictures(packet.param1-1, packet.param2*1000, packet.param3) ? MAV_RESULT_ACCEPTED : MAV_RESULT_FAILED;
     488             :         }
     489           0 :     case MAV_CMD_IMAGE_STOP_CAPTURE:
     490             :         // param1 : camera id
     491           0 :         if (is_negative(packet.param1)) {
     492           0 :             return MAV_RESULT_UNSUPPORTED;
     493             :         }
     494           0 :         if (is_zero(packet.param1)) {
     495             :             // stop capture for every backend
     496           0 :             stop_capture();
     497           0 :             return MAV_RESULT_ACCEPTED;
     498             :         }
     499           0 :         if (stop_capture(packet.param1-1)) {
     500           0 :             return MAV_RESULT_ACCEPTED;
     501             :         }
     502           0 :         return MAV_RESULT_UNSUPPORTED;
     503           0 :     case MAV_CMD_CAMERA_TRACK_POINT:
     504           0 :         if (set_tracking(TrackingType::TRK_POINT, Vector2f{packet.param1, packet.param2}, Vector2f{})) {
     505           0 :             return MAV_RESULT_ACCEPTED;
     506             :         }
     507           0 :         return MAV_RESULT_UNSUPPORTED;
     508           0 :     case MAV_CMD_CAMERA_TRACK_RECTANGLE:
     509           0 :         if (set_tracking(TrackingType::TRK_RECTANGLE, Vector2f{packet.param1, packet.param2}, Vector2f{packet.param3, packet.param4})) {
     510           0 :             return MAV_RESULT_ACCEPTED;
     511             :         }
     512           0 :         return MAV_RESULT_UNSUPPORTED;
     513           0 :     case MAV_CMD_CAMERA_STOP_TRACKING:
     514           0 :         if (set_tracking(TrackingType::TRK_NONE, Vector2f{}, Vector2f{})) {
     515           0 :             return MAV_RESULT_ACCEPTED;
     516             :         }
     517           0 :         return MAV_RESULT_UNSUPPORTED;
     518           0 :     case MAV_CMD_VIDEO_START_CAPTURE:
     519             :     case MAV_CMD_VIDEO_STOP_CAPTURE:
     520             :     {
     521           0 :         bool success = false;
     522           0 :         const bool start_recording = (packet.command == MAV_CMD_VIDEO_START_CAPTURE);
     523           0 :         const uint8_t stream_id = packet.param1;  // Stream ID
     524           0 :         if (stream_id == 0) {
     525             :             // stream id of 0 interpreted as primary camera
     526           0 :             success = record_video(start_recording);
     527             :         } else {
     528             :             // convert stream id to instance id
     529           0 :             success = record_video(stream_id - 1, start_recording);
     530             :         }
     531           0 :         if (success) {
     532           0 :             return MAV_RESULT_ACCEPTED;
     533             :         } else {
     534           0 :             return MAV_RESULT_FAILED;
     535             :         }
     536             :     }
     537           0 :     default:
     538           0 :         return MAV_RESULT_UNSUPPORTED;
     539             :     }
     540             : }
     541             : 
     542             : // send a mavlink message; returns false if there was not space to
     543             : // send the message, true otherwise
     544        2884 : bool AP_Camera::send_mavlink_message(GCS_MAVLINK &link, const enum ap_message msg_id)
     545             : {
     546        2884 :     const auto chan = link.get_chan();
     547             : 
     548        2884 :     switch (msg_id) {
     549        2869 :     case MSG_CAMERA_FEEDBACK:
     550        2869 :         CHECK_PAYLOAD_SIZE2(CAMERA_FEEDBACK);
     551        2869 :         send_feedback(chan);
     552        2869 :         break;
     553          13 :     case MSG_CAMERA_INFORMATION:
     554          13 :         CHECK_PAYLOAD_SIZE2(CAMERA_INFORMATION);
     555          13 :         if (_camera_information_send_instance >= 0) {
     556           8 :             const int16_t instance = _camera_information_send_instance;
     557           8 :             _camera_information_send_instance = -1;
     558           8 :             send_camera_information((uint8_t)instance, chan);
     559             :         } else {
     560           5 :             send_camera_information(chan);
     561             :         }
     562          13 :         break;
     563           0 :     case MSG_CAMERA_SETTINGS:
     564           0 :         CHECK_PAYLOAD_SIZE2(CAMERA_SETTINGS);
     565           0 :         send_camera_settings(chan);
     566           0 :         break;
     567             : #if AP_CAMERA_SEND_FOV_STATUS_ENABLED
     568           0 :     case MSG_CAMERA_FOV_STATUS:
     569           0 :         CHECK_PAYLOAD_SIZE2(CAMERA_FOV_STATUS);
     570           0 :         send_camera_fov_status(chan);
     571           0 :         break;
     572             : #endif
     573           2 :     case MSG_CAMERA_CAPTURE_STATUS:
     574           2 :         CHECK_PAYLOAD_SIZE2(CAMERA_CAPTURE_STATUS);
     575           2 :         send_camera_capture_status(chan);
     576           2 :         break;
     577             : #if AP_CAMERA_SEND_THERMAL_RANGE_ENABLED
     578           0 :     case MSG_CAMERA_THERMAL_RANGE:
     579           0 :         CHECK_PAYLOAD_SIZE2(CAMERA_THERMAL_RANGE);
     580           0 :         send_camera_thermal_range(chan);
     581           0 :         break;
     582             : #endif
     583             : #if AP_MAVLINK_MSG_VIDEO_STREAM_INFORMATION_ENABLED
     584           0 :     case MSG_VIDEO_STREAM_INFORMATION:
     585           0 :         CHECK_PAYLOAD_SIZE2(VIDEO_STREAM_INFORMATION);
     586           0 :         send_video_stream_information(chan);
     587           0 :         break;
     588             : #endif // AP_MAVLINK_MSG_VIDEO_STREAM_INFORMATION_ENABLED
     589             : 
     590           0 :     default:
     591             :         // should not reach this; should only be called for specific IDs
     592           0 :         break;
     593             :     }
     594             : 
     595        2884 :     return true;
     596             : }
     597             : 
     598             : // set camera trigger distance in a mission
     599           0 : void AP_Camera::set_trigger_distance(uint8_t instance, float distance_m)
     600             : {
     601           0 :     WITH_SEMAPHORE(_rsem);
     602             : 
     603           0 :     auto *backend = get_instance(instance);
     604           0 :     if (backend == nullptr) {
     605           0 :         return;
     606             :     }
     607             : 
     608             :     // call backend
     609           0 :     backend->set_trigger_distance(distance_m);
     610           0 : }
     611             : 
     612             : // momentary switch to change camera between picture and video modes
     613           0 : void AP_Camera::cam_mode_toggle(uint8_t instance)
     614             : {
     615           0 :     WITH_SEMAPHORE(_rsem);
     616             : 
     617           0 :     auto *backend = get_instance(instance);
     618           0 :     if (backend == nullptr) {
     619           0 :         return;
     620             :     }
     621             : 
     622             :     // call backend
     623           0 :     backend->cam_mode_toggle();
     624           0 : }
     625             : 
     626             : // configure camera
     627           2 : void AP_Camera::configure(float shooting_mode, float shutter_speed, float aperture, float ISO, int32_t exposure_type, int32_t cmd_id, float engine_cutoff_time)
     628             : {
     629           2 :     WITH_SEMAPHORE(_rsem);
     630             : 
     631           2 :     if (primary == nullptr) {
     632           0 :         return;
     633             :     }
     634           2 :     primary->configure(shooting_mode, shutter_speed, aperture, ISO, exposure_type, cmd_id, engine_cutoff_time);
     635           2 : }
     636             : 
     637           0 : void AP_Camera::configure(uint8_t instance, float shooting_mode, float shutter_speed, float aperture, float ISO, int32_t exposure_type, int32_t cmd_id, float engine_cutoff_time)
     638             : {
     639           0 :     WITH_SEMAPHORE(_rsem);
     640             : 
     641           0 :     auto *backend = get_instance(instance);
     642           0 :     if (backend == nullptr) {
     643           0 :         return;
     644             :     }
     645             : 
     646             :     // call backend
     647           0 :     backend->configure(shooting_mode, shutter_speed, aperture, ISO, exposure_type, cmd_id, engine_cutoff_time);
     648           0 : }
     649             : 
     650             : // handle camera control
     651           4 : void AP_Camera::control(float session, float zoom_pos, float zoom_step, float focus_lock, int32_t shooting_cmd, int32_t cmd_id)
     652             : {
     653           4 :     WITH_SEMAPHORE(_rsem);
     654             : 
     655           4 :     if (primary == nullptr) {
     656           1 :         return;
     657             :     }
     658           3 :     primary->control(session, zoom_pos, zoom_step, focus_lock, shooting_cmd, cmd_id);
     659           4 : }
     660             : 
     661           0 : void AP_Camera::control(uint8_t instance, float session, float zoom_pos, float zoom_step, float focus_lock, int32_t shooting_cmd, int32_t cmd_id)
     662             : {
     663           0 :     WITH_SEMAPHORE(_rsem);
     664             : 
     665           0 :     auto *backend = get_instance(instance);
     666           0 :     if (backend == nullptr) {
     667           0 :         return;
     668             :     }
     669             : 
     670             :     // call backend
     671           0 :     backend->control(session, zoom_pos, zoom_step, focus_lock, shooting_cmd, cmd_id);
     672           0 : }
     673             : 
     674             : /*
     675             :   Send camera feedback to the GCS
     676             :  */
     677        2869 : void AP_Camera::send_feedback(mavlink_channel_t chan)
     678             : {
     679        2869 :     WITH_SEMAPHORE(_rsem);
     680             : 
     681             :     // call each instance
     682        8607 :     for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
     683        5738 :         if (_backends[instance] != nullptr) {
     684        2917 :             _backends[instance]->send_camera_feedback(chan);
     685             :         }
     686             :     }
     687        2869 : }
     688             : 
     689             : // send camera information message to GCS
     690           5 : void AP_Camera::send_camera_information(mavlink_channel_t chan)
     691             : {
     692           5 :     WITH_SEMAPHORE(_rsem);
     693             : 
     694             :     // call each instance
     695          15 :     for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
     696          10 :         if (_backends[instance] != nullptr) {
     697           5 :             _backends[instance]->send_camera_information(chan);
     698             :         }
     699             :     }
     700           5 : }
     701             : 
     702             : // send camera information for a specific instance to GCS
     703           8 : void AP_Camera::send_camera_information(uint8_t instance, mavlink_channel_t chan)
     704             : {
     705           8 :     WITH_SEMAPHORE(_rsem);
     706             : 
     707           8 :     auto *backend = get_instance(instance);
     708           8 :     if (backend == nullptr) {
     709           0 :         return;
     710             :     }
     711           8 :     backend->send_camera_information(chan);
     712           8 : }
     713             : 
     714             : #if AP_MAVLINK_MSG_VIDEO_STREAM_INFORMATION_ENABLED
     715             : // send video stream information message to GCS
     716           0 : void AP_Camera::send_video_stream_information(mavlink_channel_t chan)
     717             : {
     718           0 :     WITH_SEMAPHORE(_rsem);
     719             : 
     720             :     // call each instance
     721           0 :     for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
     722           0 :         if (_backends[instance] != nullptr) {
     723           0 :             _backends[instance]->send_video_stream_information(chan);
     724             :         }
     725             :     }
     726           0 : }
     727             : #endif // AP_MAVLINK_MSG_VIDEO_STREAM_INFORMATION_ENABLED
     728             : 
     729             : // send camera settings message to GCS
     730           0 : void AP_Camera::send_camera_settings(mavlink_channel_t chan)
     731             : {
     732           0 :     WITH_SEMAPHORE(_rsem);
     733             : 
     734             :     // call each instance
     735           0 :     for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
     736           0 :         if (_backends[instance] != nullptr) {
     737           0 :             _backends[instance]->send_camera_settings(chan);
     738             :         }
     739             :     }
     740           0 : }
     741             : 
     742             : #if AP_CAMERA_SEND_FOV_STATUS_ENABLED
     743             : // send camera field of view status
     744           0 : void AP_Camera::send_camera_fov_status(mavlink_channel_t chan)
     745             : {
     746           0 :     WITH_SEMAPHORE(_rsem);
     747             : 
     748             :     // call each instance
     749           0 :     for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
     750           0 :         if (_backends[instance] != nullptr) {
     751           0 :             _backends[instance]->send_camera_fov_status(chan);
     752             :         }
     753             :     }
     754           0 : }
     755             : #endif
     756             : 
     757             : // send camera capture status message to GCS
     758           2 : void AP_Camera::send_camera_capture_status(mavlink_channel_t chan)
     759             : {
     760           2 :     WITH_SEMAPHORE(_rsem);
     761             : 
     762             :     // call each instance
     763           6 :     for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
     764           4 :         if (_backends[instance] != nullptr) {
     765           4 :             _backends[instance]->send_camera_capture_status(chan);
     766             :         }
     767             :     }
     768           2 : }
     769             : 
     770             : #if AP_CAMERA_SEND_THERMAL_RANGE_ENABLED
     771             : // send camera thermal range message to GCS
     772           0 : void AP_Camera::send_camera_thermal_range(mavlink_channel_t chan)
     773             : {
     774           0 :     WITH_SEMAPHORE(_rsem);
     775             : 
     776             :     // call each instance
     777           0 :     for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
     778           0 :         if (_backends[instance] != nullptr) {
     779           0 :             _backends[instance]->send_camera_thermal_range(chan);
     780             :         }
     781             :     }
     782           0 : }
     783             : #endif
     784             : 
     785             : /*
     786             :   update; triggers by distance moved and camera trigger
     787             : */
     788     7438628 : void AP_Camera::update()
     789             : {
     790     7438628 :     WITH_SEMAPHORE(_rsem);
     791             : 
     792             :     // call each instance
     793    22315884 :     for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
     794    14877256 :         if (_backends[instance] != nullptr) {
     795       70356 :             _backends[instance]->update();
     796             :         }
     797             :     }
     798     7438628 : }
     799             : 
     800             : // start/stop recording video.  returns true on success
     801             : // start_recording should be true to start recording, false to stop recording
     802           0 : bool AP_Camera::record_video(uint8_t instance, bool start_recording)
     803             : {
     804           0 :     WITH_SEMAPHORE(_rsem);
     805             : 
     806           0 :     auto *backend = get_instance(instance);
     807           0 :     if (backend == nullptr) {
     808           0 :         return false;
     809             :     }
     810             : 
     811             :     // call backend
     812           0 :     return backend->record_video(start_recording);
     813           0 : }
     814             : 
     815             : // zoom specified as a rate or percentage
     816           0 : bool AP_Camera::set_zoom(ZoomType zoom_type, float zoom_value)
     817             : {
     818           0 :     WITH_SEMAPHORE(_rsem);
     819             : 
     820           0 :     if (primary == nullptr) {
     821           0 :         return false;
     822             :     }
     823           0 :     return primary->set_zoom(zoom_type, zoom_value);
     824           0 : }
     825             : 
     826             : // zoom specified as a rate or percentage
     827           0 : bool AP_Camera::set_zoom(uint8_t instance, ZoomType zoom_type, float zoom_value)
     828             : {
     829           0 :     WITH_SEMAPHORE(_rsem);
     830             : 
     831           0 :     auto *backend = get_instance(instance);
     832           0 :     if (backend == nullptr) {
     833           0 :         return false;
     834             :     }
     835             : 
     836             :     // call each instance
     837           0 :     return backend->set_zoom(zoom_type, zoom_value);
     838           0 : }
     839             : 
     840             : 
     841             : // set focus specified as rate, percentage or auto
     842             : // focus in = -1, focus hold = 0, focus out = 1
     843           0 : SetFocusResult AP_Camera::set_focus(FocusType focus_type, float focus_value)
     844             : {
     845           0 :     WITH_SEMAPHORE(_rsem);
     846             : 
     847           0 :     if (primary == nullptr) {
     848           0 :         return SetFocusResult::FAILED;
     849             :     }
     850           0 :     return primary->set_focus(focus_type, focus_value);
     851           0 : }
     852             : 
     853             : // set focus specified as rate, percentage or auto
     854             : // focus in = -1, focus hold = 0, focus out = 1
     855           0 : SetFocusResult AP_Camera::set_focus(uint8_t instance, FocusType focus_type, float focus_value)
     856             : {
     857           0 :     WITH_SEMAPHORE(_rsem);
     858             : 
     859           0 :     auto *backend = get_instance(instance);
     860           0 :     if (backend == nullptr) {
     861           0 :         return SetFocusResult::FAILED;
     862             :     }
     863             : 
     864             :     // call each instance
     865           0 :     return backend->set_focus(focus_type, focus_value);
     866           0 : }
     867             : 
     868             : // set tracking to none, point or rectangle (see TrackingType enum)
     869             : // if POINT only p1 is used, if RECTANGLE then p1 is top-left, p2 is bottom-right
     870             : // p1,p2 are in range 0 to 1.  0 is left or top, 1 is right or bottom
     871           0 : bool AP_Camera::set_tracking(TrackingType tracking_type, const Vector2f& p1, const Vector2f& p2)
     872             : {
     873           0 :     WITH_SEMAPHORE(_rsem);
     874             : 
     875           0 :     if (primary == nullptr) {
     876           0 :         return false;
     877             :     }
     878           0 :     return primary->set_tracking(tracking_type, p1, p2);
     879           0 : }
     880             : 
     881             : // set tracking to none, point or rectangle (see TrackingType enum)
     882             : // if POINT only p1 is used, if RECTANGLE then p1 is top-left, p2 is bottom-right
     883             : // p1,p2 are in range 0 to 1.  0 is left or top, 1 is right or bottom
     884           0 : bool AP_Camera::set_tracking(uint8_t instance, TrackingType tracking_type, const Vector2f& p1, const Vector2f& p2)
     885             : {
     886           0 :     WITH_SEMAPHORE(_rsem);
     887             : 
     888           0 :     auto *backend = get_instance(instance);
     889           0 :     if (backend == nullptr) {
     890           0 :         return false;
     891             :     }
     892             : 
     893             :     // call each instance
     894           0 :     return backend->set_tracking(tracking_type, p1, p2);
     895           0 : }
     896             : 
     897             : #if AP_CAMERA_SET_CAMERA_SOURCE_ENABLED
     898             : // set camera lens as a value from 0 to 5
     899           0 : bool AP_Camera::set_lens(uint8_t lens)
     900             : {
     901           0 :     WITH_SEMAPHORE(_rsem);
     902             : 
     903           0 :     if (primary == nullptr) {
     904           0 :         return false;
     905             :     }
     906           0 :     return primary->set_lens(lens);
     907           0 : }
     908             : 
     909           0 : bool AP_Camera::set_lens(uint8_t instance, uint8_t lens)
     910             : {
     911           0 :     WITH_SEMAPHORE(_rsem);
     912             : 
     913           0 :     auto *backend = get_instance(instance);
     914           0 :     if (backend == nullptr) {
     915           0 :         return false;
     916             :     }
     917             : 
     918             :     // call instance
     919           0 :     return backend->set_lens(lens);
     920           0 : }
     921             : 
     922             : // set_camera_source is functionally the same as set_lens except primary and secondary lenses are specified by type
     923           0 : bool AP_Camera::set_camera_source(uint8_t instance, CameraSource primary_source, CameraSource secondary_source)
     924             : {
     925           0 :     WITH_SEMAPHORE(_rsem);
     926             : 
     927           0 :     auto *backend = get_instance(instance);
     928           0 :     if (backend == nullptr) {
     929           0 :         return false;
     930             :     }
     931             : 
     932             :     // call instance
     933           0 :     return backend->set_camera_source(primary_source, secondary_source);
     934           0 : }
     935             : #endif // AP_CAMERA_SET_CAMERA_SOURCE_ENABLED
     936             : 
     937             : #if AP_CAMERA_SCRIPTING_ENABLED
     938             : // accessor to allow scripting backend to retrieve state
     939             : // returns true on success and cam_state is filled in
     940           0 : bool AP_Camera::get_state(uint8_t instance, camera_state_t& cam_state)
     941             : {
     942           0 :     WITH_SEMAPHORE(_rsem);
     943             : 
     944           0 :     auto *backend = get_instance(instance);
     945           0 :     if (backend == nullptr) {
     946           0 :         return false;
     947             :     }
     948           0 :     return backend->get_state(cam_state);
     949           0 : }
     950             : 
     951             : // change camera settings not normally used by autopilot
     952           0 : bool AP_Camera::change_setting(uint8_t instance, CameraSetting setting, float value)
     953             : {
     954           0 :     WITH_SEMAPHORE(_rsem);
     955             : 
     956           0 :     auto *backend = get_instance(instance);
     957           0 :     if (backend == nullptr) {
     958           0 :         return false;
     959             :     }
     960           0 :     return backend->change_setting(setting, value);
     961           0 : }
     962             : 
     963             : #endif // #if AP_CAMERA_SCRIPTING_ENABLED
     964             : 
     965             : 
     966             : #if AP_CAMERA_INFO_FROM_SCRIPT_ENABLED
     967           0 : void AP_Camera::set_camera_information(mavlink_camera_information_t camera_info)
     968             : {
     969           0 :     WITH_SEMAPHORE(_rsem);
     970             : 
     971           0 :     if (primary == nullptr) {
     972           0 :         return;
     973             :     }
     974           0 :     return primary->set_camera_information(camera_info);
     975           0 : }
     976             : 
     977           0 : void AP_Camera::set_camera_information(uint8_t instance, mavlink_camera_information_t camera_info)
     978             : {
     979           0 :     WITH_SEMAPHORE(_rsem);
     980             : 
     981           0 :     auto *backend = get_instance(instance);
     982           0 :     if (backend == nullptr) {
     983           0 :         return;
     984             :     }
     985             : 
     986             :     // call instance
     987           0 :     backend->set_camera_information(camera_info);
     988           0 : }
     989             : 
     990           0 : void AP_Camera::set_stream_information(mavlink_video_stream_information_t stream_info)
     991             : {
     992           0 :     WITH_SEMAPHORE(_rsem);
     993             : 
     994           0 :     if (primary == nullptr) {
     995           0 :         return;
     996             :     }
     997           0 :     return primary->set_stream_information(stream_info);
     998           0 : }
     999             : 
    1000           0 : void AP_Camera::set_stream_information(uint8_t instance, mavlink_video_stream_information_t stream_info)
    1001             : {
    1002           0 :     WITH_SEMAPHORE(_rsem);
    1003             : 
    1004           0 :     auto *backend = get_instance(instance);
    1005           0 :     if (backend == nullptr) {
    1006           0 :         return;
    1007             :     }
    1008             : 
    1009             :     // call instance
    1010           0 :     backend->set_stream_information(stream_info);
    1011           0 : }
    1012             : #endif // AP_CAMERA_INFO_FROM_SCRIPT_ENABLED
    1013             : 
    1014             : // return backend for instance number
    1015          12 : AP_Camera_Backend *AP_Camera::get_instance(uint8_t instance) const
    1016             : {
    1017          12 :     if (instance >= ARRAY_SIZE(_backends)) {
    1018           0 :         return nullptr;
    1019             :     }
    1020          12 :     return _backends[instance];
    1021             : }
    1022             : 
    1023             : #if AP_CAMERA_RUNCAM_ENABLED && (AP_CAMERA_MAX_INSTANCES > 1)
    1024             : // Convert to runcam specific backend
    1025        2059 : void AP_Camera::convert_runcam_params()
    1026             : {
    1027             :     // exit immediately if CAM2_TYPE has already been configured
    1028        2059 :     if (_params[1].type.configured()) {
    1029        1768 :         return;
    1030             :     }
    1031             : 
    1032             :     // PARAMETER_CONVERSION - Added: Dec-2024 for ArduPilot-4.7
    1033             : 
    1034             :     // Since slot 1 is essentially used by the trigger type, we will use slot 2 for runcam
    1035         291 :     int8_t rc_type = 0;
    1036             :     // find vehicle's top level key
    1037             :     uint16_t k_param_vehicle_key;
    1038         291 :     if (!AP_Param::find_top_level_key_by_pointer(AP::vehicle(), k_param_vehicle_key)) {
    1039           0 :         return;
    1040             :     }
    1041             : 
    1042             :     // RunCam protocol configured so set cam type to RunCam
    1043         291 :     bool rc_protocol_configured = false;
    1044         291 :     AP_SerialManager *serial_manager = AP_SerialManager::get_singleton();
    1045         291 :     if (serial_manager && serial_manager->find_serial(AP_SerialManager::SerialProtocol_RunCam, 0)) {
    1046           0 :         rc_protocol_configured = true;
    1047             :     }
    1048             : 
    1049         291 :     const AP_Param::ConversionInfo rc_type_info = {
    1050             :         k_param_vehicle_key, AP_GROUP_ELEM_IDX(1, 1), AP_PARAM_INT8, "CAM_RC_TYPE"
    1051         291 :     };
    1052         291 :     AP_Int8 rc_type_old;
    1053         291 :     const bool found_rc_type = AP_Param::find_old_parameter(&rc_type_info, &rc_type_old);
    1054             : 
    1055         291 :     if (rc_protocol_configured || (found_rc_type && rc_type_old.get() > 0)) {
    1056           0 :         rc_type = int8_t(CameraType::RUNCAM);
    1057           0 :         _backends[1] = NEW_NOTHROW AP_RunCam(*this, _params[1], 1, _runcam_instances);
    1058           0 :         _backend_var_info[1] = AP_RunCam::var_info;
    1059           0 :         AP_Param::convert_class(k_param_vehicle_key, &_backends[1], _backend_var_info[1], 1, false);
    1060           0 :         AP_Param::invalidate_count();
    1061           0 :         _runcam_instances++;
    1062             :     }
    1063             : 
    1064         291 :     _params[1].type.set_and_save(rc_type);
    1065             : 
    1066             : }
    1067             : #endif // AP_CAMERA_RUNCAM_ENABLED && (AP_CAMERA_MAX_INSTANCES > 1)
    1068             : 
    1069             : // perform any required parameter conversion
    1070        2059 : void AP_Camera::convert_params()
    1071             : {
    1072             :     // exit immediately if CAM1_TYPE has already been configured
    1073        2059 :     if (_params[0].type.configured()) {
    1074        1768 :         return;
    1075             :     }
    1076             : 
    1077             :     // PARAMETER_CONVERSION - Added: Feb-2023 for ArduPilot-4.4
    1078             : 
    1079             :     // convert CAM_TRIGG_TYPE to CAM1_TYPE
    1080         291 :     int8_t cam_trigg_type = 0;
    1081         291 :     int8_t cam1_type = 0;
    1082         291 :     IGNORE_RETURN(AP_Param::get_param_by_index(this, 0, AP_PARAM_INT8, &cam_trigg_type));
    1083         291 :     if ((cam_trigg_type == 0) && SRV_Channels::function_assigned(SRV_Channel::k_cam_trigger)) {
    1084             :         // CAM_TRIGG_TYPE was 0 (Servo) and camera trigger servo function was assigned so set CAM1_TYPE = 1 (Servo)
    1085           0 :         cam1_type = 1;
    1086             :     }
    1087         291 :     if ((cam_trigg_type >= 1) && (cam_trigg_type <= 3)) {
    1088             :         // CAM_TRIGG_TYPE was set to Relay, GoPro or Mount
    1089           0 :         cam1_type = cam_trigg_type + 1;
    1090             :     }
    1091         291 :     _params[0].type.set_and_save(cam1_type);
    1092             : 
    1093             :     // convert CAM_DURATION (in deci-seconds) to CAM1_DURATION (in seconds)
    1094         291 :     int8_t cam_duration = 0;
    1095         291 :     if (AP_Param::get_param_by_index(this, 1, AP_PARAM_INT8, &cam_duration) && (cam_duration > 0)) {
    1096           0 :         _params[0].trigger_duration.set_and_save(cam_duration * 0.1);
    1097             :     }
    1098             : 
    1099             :     // convert CAM_MIN_INTERVAL (in milliseconds) to CAM1__INTRVAL_MIN (in seconds)
    1100         291 :     int16_t cam_min_interval = 0;
    1101         291 :     if (AP_Param::get_param_by_index(this, 6, AP_PARAM_INT16, &cam_min_interval) && (cam_min_interval > 0)) {
    1102           0 :         _params[0].interval_min.set_and_save(cam_min_interval * 0.001f);
    1103             :     }
    1104             : 
    1105             :     // find Camera's top level key
    1106             :     uint16_t k_param_camera_key;
    1107         291 :     if (!AP_Param::find_top_level_key_by_pointer(this, k_param_camera_key)) {
    1108           0 :         return;
    1109             :     }
    1110             : 
    1111             :     // table parameters to convert without scaling
    1112             :     static const AP_Param::ConversionInfo camera_param_conversion_info[] {
    1113             :         { k_param_camera_key, 2, AP_PARAM_INT16, "CAM1_SERVO_ON" },
    1114             :         { k_param_camera_key, 3, AP_PARAM_INT16, "CAM1_SERVO_OFF" },
    1115             :         { k_param_camera_key, 4, AP_PARAM_FLOAT, "CAM1_TRIGG_DIST" },
    1116             :         { k_param_camera_key, 5, AP_PARAM_INT8, "CAM1_RELAY_ON" },
    1117             :         { k_param_camera_key, 8, AP_PARAM_INT8, "CAM1_FEEDBAK_PIN" },
    1118             :         { k_param_camera_key, 9, AP_PARAM_INT8, "CAM1_FEEDBAK_POL" },
    1119         291 :     };
    1120         291 :     uint8_t table_size = ARRAY_SIZE(camera_param_conversion_info);
    1121        2037 :     for (uint8_t i=0; i<table_size; i++) {
    1122        1746 :         AP_Param::convert_old_parameter(&camera_param_conversion_info[i], 1.0f);
    1123             :     }
    1124             : }
    1125             : 
    1126             : #if AP_RELAY_ENABLED
    1127             : // Return true and the relay index if relay camera backend is selected, used for conversion to relay functions
    1128        2059 : bool AP_Camera::get_legacy_relay_index(int8_t &index) const
    1129             : {
    1130             :     // PARAMETER_CONVERSION - Added: Dec-2023
    1131             : 
    1132             :     // Note that this assumes that the camera param conversion has already been done
    1133             :     // Copter, Plane, Sub and Rover all have both relay and camera and all init relay first
    1134             :     // This will only be a issue if the relay and camera conversion were done at once, if the user skipped 4.4
    1135        6177 :     for (uint8_t i = 0; i < AP_CAMERA_MAX_INSTANCES; i++) {
    1136             : #if AP_CAMERA_RELAY_ENABLED
    1137        4118 :         if ((CameraType)_params[i].type.get() == CameraType::RELAY) {
    1138             :             // Camera was hard coded to relay 0
    1139           0 :             index = 0;
    1140           0 :             return true;
    1141             :         }
    1142             : #endif
    1143             :     }
    1144        2059 :     return false;
    1145             : }
    1146             : #endif
    1147             : 
    1148             : // singleton instance
    1149             : AP_Camera *AP_Camera::_singleton;
    1150             : 
    1151             : namespace AP {
    1152             : 
    1153        4996 : AP_Camera *camera()
    1154             : {
    1155        4996 :     return AP_Camera::get_singleton();
    1156             : }
    1157             : 
    1158             : }
    1159             : 
    1160             : #endif

Generated by: LCOV version 1.14