LCOV - code coverage report
Current view: top level - AP_OSD - AP_OSD_ParamScreen.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 5 271 1.8 %
Date: 2026-09-09 11:02:08 Functions: 1 11 9.1 %

          Line data    Source code
       1             : /*
       2             :  * This file is free software: you can redistribute it and/or modify it
       3             :  * under the terms of the GNU General Public License as published by the
       4             :  * Free Software Foundation, either version 3 of the License, or
       5             :  * (at your option) any later version.
       6             :  *
       7             :  * This file is distributed in the hope that it will be useful, but
       8             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      10             :  * See the GNU General Public License for more details.
      11             :  *
      12             :  * You should have received a copy of the GNU General Public License along
      13             :  * with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  *
      15             :  * AP_OSD partially based on betaflight and inav osd.c implemention.
      16             :  * clarity.mcm font is taken from inav configurator.
      17             :  * Many thanks to their authors.
      18             :  */
      19             : /*
      20             :   parameter settings for one screen
      21             :  */
      22             : #include "AP_OSD.h"
      23             : #include "AP_OSD_Backend.h"
      24             : 
      25             : #include <AP_HAL/AP_HAL.h>
      26             : #include <AP_HAL/Util.h>
      27             : #include <limits.h>
      28             : #include <ctype.h>
      29             : #include <AP_Vehicle/AP_Vehicle_Type.h>
      30             : #include <AP_Arming/AP_Arming.h>
      31             : #include <AP_Vehicle/AP_Vehicle_Type.h>
      32             : #include <GCS_MAVLink/GCS.h>
      33             : 
      34             : extern const AP_HAL::HAL& hal;
      35             : 
      36             : #if OSD_PARAM_ENABLED
      37             : 
      38             : const AP_Param::GroupInfo AP_OSD_ParamScreen::var_info[] = {
      39             : 
      40             :     // @Param: ENABLE
      41             :     // @DisplayName: Enable screen
      42             :     // @Description: Enable this screen
      43             :     // @Values: 0:Disabled,1:Enabled
      44             :     // @User: Standard
      45             :     AP_GROUPINFO_FLAGS("ENABLE", 1, AP_OSD_ParamScreen, enabled, 0, AP_PARAM_FLAG_ENABLE),
      46             : 
      47             :     // @Param: CHAN_MIN
      48             :     // @DisplayName: Transmitter switch screen minimum pwm
      49             :     // @Description: This sets the PWM lower limit for this screen
      50             :     // @Range: 900 2100
      51             :     // @User: Standard
      52             :     AP_GROUPINFO("CHAN_MIN", 2, AP_OSD_ParamScreen, channel_min, 900),
      53             : 
      54             :     // @Param: CHAN_MAX
      55             :     // @DisplayName: Transmitter switch screen maximum pwm
      56             :     // @Description: This sets the PWM upper limit for this screen
      57             :     // @Range: 900 2100
      58             :     // @User: Standard
      59             :     AP_GROUPINFO("CHAN_MAX", 3, AP_OSD_ParamScreen, channel_max, 2100),
      60             : 
      61             :     // @Group: PARAM1
      62             :     // @Path: AP_OSD_ParamSetting.cpp
      63             :     AP_SUBGROUPINFO(params[0], "PARAM1", 4, AP_OSD_ParamScreen, AP_OSD_ParamSetting),
      64             : 
      65             :     // @Group: PARAM2
      66             :     // @Path: AP_OSD_ParamSetting.cpp
      67             :     AP_SUBGROUPINFO(params[1], "PARAM2", 5, AP_OSD_ParamScreen, AP_OSD_ParamSetting),
      68             : 
      69             :     // @Group: PARAM3
      70             :     // @Path: AP_OSD_ParamSetting.cpp
      71             :     AP_SUBGROUPINFO(params[2], "PARAM3", 6, AP_OSD_ParamScreen, AP_OSD_ParamSetting),
      72             : 
      73             :     // @Group: PARAM4
      74             :     // @Path: AP_OSD_ParamSetting.cpp
      75             :     AP_SUBGROUPINFO(params[3], "PARAM4", 7, AP_OSD_ParamScreen, AP_OSD_ParamSetting),
      76             : 
      77             :     // @Group: PARAM5
      78             :     // @Path: AP_OSD_ParamSetting.cpp
      79             :     AP_SUBGROUPINFO(params[4], "PARAM5", 8, AP_OSD_ParamScreen, AP_OSD_ParamSetting),
      80             : 
      81             :     // @Group: PARAM6
      82             :     // @Path: AP_OSD_ParamSetting.cpp
      83             :     AP_SUBGROUPINFO(params[5], "PARAM6", 9, AP_OSD_ParamScreen, AP_OSD_ParamSetting),
      84             : 
      85             :     // @Group: PARAM7
      86             :     // @Path: AP_OSD_ParamSetting.cpp
      87             :     AP_SUBGROUPINFO(params[6], "PARAM7", 10, AP_OSD_ParamScreen, AP_OSD_ParamSetting),
      88             : 
      89             :     // @Group: PARAM8
      90             :     // @Path: AP_OSD_ParamSetting.cpp
      91             :     AP_SUBGROUPINFO(params[7], "PARAM8", 11, AP_OSD_ParamScreen, AP_OSD_ParamSetting),
      92             : 
      93             :     // @Group: PARAM9
      94             :     // @Path: AP_OSD_ParamSetting.cpp
      95             :     AP_SUBGROUPINFO(params[8], "PARAM9", 12, AP_OSD_ParamScreen, AP_OSD_ParamSetting),
      96             : 
      97             :     // @Param: SAVE_X
      98             :     // @DisplayName: SAVE_X
      99             :     // @Description: Horizontal position of Save button on screen
     100             :     // @Range: 0 25
     101             :     // @User: Advanced
     102             :     AP_GROUPINFO("SAVE_X", 13, AP_OSD_ParamScreen, save_x, 23),
     103             : 
     104             :     // @Param: SAVE_Y
     105             :     // @DisplayName: SAVE_Y
     106             :     // @Description: Vertical position of Save button on screen
     107             :     // @Range: 0 15
     108             :     // @User: Advanced
     109             :     AP_GROUPINFO("SAVE_Y", 14, AP_OSD_ParamScreen, save_y, 11),
     110             : 
     111             :     AP_GROUPEND
     112             : };
     113             : 
     114             : #define OSD_HOLD_BUTTON_PRESS_DELAY 100
     115             : #define OSD_HOLD_BUTTON_PRESS_COUNT 18
     116             : 
     117             : #define OSD_PARAM_DEBUG 0
     118             : 
     119             : #if OSD_PARAM_DEBUG
     120             : static const char* event_names[5] = {
     121             :         "NONE", "MENU_ENTER", "MENU_UP", "MENU_DOWN", "IN_MENU_EXIT"
     122             : };
     123             : #define debug(fmt, args ...) do { hal.console->printf("OSD: " fmt, args); } while (0)
     124             : #else
     125             : #define debug(fmt, args ...)
     126             : #endif
     127             : 
     128             : static const AP_OSD_ParamSetting::Initializer PARAM_DEFAULTS[AP_OSD_NUM_PARAM_SCREENS][AP_OSD_ParamScreen::NUM_PARAMS] {
     129             : #if APM_BUILD_COPTER_OR_HELI
     130             :     {
     131             :         { 1, { 102, 0, 4033 }, AP_OSD_ParamSetting::Type::NONE },            // ATC_RAT_RLL_P
     132             :         { 2, { 102, 0, 129  }, AP_OSD_ParamSetting::Type::NONE },            // ATC_RAT_RLL_D
     133             :         { 3, { 102, 0, 705  }, AP_OSD_ParamSetting::Type::NONE },            // ATC_RAT_RLL_FLTD
     134             :         { 4, { 102, 0, 4034 }, AP_OSD_ParamSetting::Type::NONE },            // ATC_RAT_PIT_P
     135             :         { 5, { 102, 0, 130  }, AP_OSD_ParamSetting::Type::NONE },            // ATC_RAT_PIT_D
     136             :         { 6, { 102, 0, 706  }, AP_OSD_ParamSetting::Type::NONE },            // ATC_RAT_PIT_FLTD
     137             :         { 7, { 102, 0, 4035 }, AP_OSD_ParamSetting::Type::NONE },            // ATC_RAT_YAW_P
     138             :         { 8, { 102, 0, 131  }, AP_OSD_ParamSetting::Type::NONE },            // ATC_RAT_YAW_D
     139             :         { 9, { 102, 0, 643  }, AP_OSD_ParamSetting::Type::NONE }             // ATC_RAT_YAW_FLTE
     140             :     },
     141             :     {
     142             :         { 1, { 3, 0, 231 }, AP_OSD_ParamSetting::Type::NONE },               // INS_LOG_BAT_OPT
     143             :         { 2, { 3, 0, 167 }, AP_OSD_ParamSetting::Type::NONE },               // INS_LOG_BAT_MASK
     144             :         { 3, { 60, 0, 0  }, AP_OSD_ParamSetting::Type::NONE },               // LOG_BITMASK
     145             :         { 4, { 3, 0, 18  }, AP_OSD_ParamSetting::Type::NONE },               // INS_GYRO_FILT
     146             :         { 5, { 102, 0, 6 }, AP_OSD_ParamSetting::Type::NONE },               // ATC_THR_MIX_MAN
     147             :         { 6, { 102, 0, 5 }, AP_OSD_ParamSetting::Type::NONE },               // ATC_THR_MIX_MAX
     148             :         { 7, { 6, 0, 25041 }, AP_OSD_ParamSetting::Type::AUX_FUNCTION },     // RC7_OPTION
     149             :         { 8, { 6, 0, 25105 }, AP_OSD_ParamSetting::Type::AUX_FUNCTION },     // RC8_OPTION
     150             :         { 9, { 36, 0, 1047 }, AP_OSD_ParamSetting::Type::FAILSAFE_ACTION_2 } // BATT_FS_LOW_ACT
     151             :     }
     152             : #elif APM_BUILD_TYPE(APM_BUILD_ArduPlane)
     153             :     {
     154             :         { 1, { 232, 0, 265 }, AP_OSD_ParamSetting::Type::NONE },             // RLL_RATE_FF
     155             :         { 2, { 232, 0, 4041 }, AP_OSD_ParamSetting::Type::NONE },            // RLL_RATE_P
     156             :         { 3, { 232, 0, 73 }, AP_OSD_ParamSetting::Type::NONE },              // RLL_RATE_I
     157             :         { 4, { 233, 0, 267 }, AP_OSD_ParamSetting::Type::NONE },             // PTCH_RATE_FF
     158             :         { 5, { 233, 0, 4043 }, AP_OSD_ParamSetting::Type::NONE },            // PTCH_RATE_P
     159             :         { 6, { 233, 0, 75 }, AP_OSD_ParamSetting::Type::NONE },              // PTCH_RATE_I
     160             :         { 7, { 233, 0, 6 }, AP_OSD_ParamSetting::Type::NONE },               // PTCH2SRV_RLL
     161             :         { 8, { 199, 0, 1 }, AP_OSD_ParamSetting::Type::NONE },               // TUNE_PARAM
     162             :         { 9, { 199, 0, 320 }, AP_OSD_ParamSetting::Type::NONE }              // TUNE_RANGE
     163             :     },
     164             :     {
     165             :         { 1, { 185, 0, 0 }, AP_OSD_ParamSetting::Type::NONE },               // TRIM_THROTTLE
     166             :         { 2, { 155, 0, 0 }, AP_OSD_ParamSetting::Type::NONE },               // AIRSPEED_CRUISE
     167             :         { 3, { 4, 0, 1094 }, AP_OSD_ParamSetting::Type::NONE },              // SERVO_AUTO_TRIM
     168             :         { 4, { 120, 0, 0 }, AP_OSD_ParamSetting::Type::NONE},                // AIRSPEED_MIN
     169             :         { 5, { 121, 0, 0 }, AP_OSD_ParamSetting::Type::NONE },               // AIRSPEED_MAX
     170             :         { 6, { 156, 0, 0 }, AP_OSD_ParamSetting::Type::NONE },               // RTL_ALTITUDE
     171             :         { 7, { 140, 2, 8 }, AP_OSD_ParamSetting::Type::NONE },               // AHRS_TRIM_Y
     172             :         { 8, { 182, 0, 0 }, AP_OSD_ParamSetting::Type::NONE },               // THR_MAX
     173             :         { 9, { 189, 0, 0 }, AP_OSD_ParamSetting::Type::NONE }                // THR_SLEWRATE
     174             :     }
     175             : #else
     176             :     {
     177             :         { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, { 8 }, { 9 },
     178             :     },
     179             :     {
     180             :         { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, { 8 }, { 9 }
     181             :     }
     182             : #endif
     183             : };
     184             : 
     185       41220 : AP_OSD_ParamScreen::AP_OSD_ParamScreen(uint8_t index)
     186             : {
     187       41220 :     for (uint8_t i = 0; i < NUM_PARAMS; i++) {
     188       37098 :         params[i] = PARAM_DEFAULTS[index][i];
     189             :     }
     190        4122 :     AP_Param::setup_object_defaults(this, var_info);
     191        4122 : }
     192             : 
     193           0 : AP_OSD_ParamSetting* AP_OSD_ParamScreen::get_setting(uint8_t param_idx)
     194             : {
     195           0 :     if (param_idx >= NUM_PARAMS) {
     196           0 :         return nullptr;
     197             :     }
     198           0 :     params[param_idx].update(); // make sure we are fresh
     199           0 :     return &params[param_idx];
     200             : }
     201             : 
     202             : #if OSD_ENABLED
     203           0 : void AP_OSD_ParamScreen::draw_parameter(uint8_t number, uint8_t x, uint8_t y)
     204             : {
     205           0 :     bool param_blink = false;
     206           0 :     bool value_blink = false;
     207           0 :     const bool selected = number == _selected_param;
     208             : 
     209           0 :     switch(_menu_state) {
     210           0 :     case MenuState::PARAM_SELECT:
     211           0 :         param_blink = selected;
     212           0 :         break;
     213           0 :     case MenuState::PARAM_VALUE_MODIFY:
     214           0 :         value_blink = selected;
     215           0 :         break;
     216           0 :     case MenuState::PARAM_PARAM_MODIFY:
     217           0 :         param_blink = value_blink = selected;
     218           0 :         break;
     219             :     }
     220             : 
     221           0 :     if (number >= NUM_PARAMS + 1) {
     222           0 :         backend->write(x, y, param_blink, "%s", _requires_save ? "  SAVE" : "REBOOT");
     223           0 :         return;
     224             :     }
     225             : 
     226           0 :     AP_OSD_ParamSetting& setting = params[number-1];
     227           0 :     setting.update();
     228             : 
     229           0 :     ap_var_type type = setting._param_type;
     230           0 :     AP_Param* p =  setting._param;
     231           0 :     if (p != nullptr) {
     232             :         // grab the name of the parameter
     233             :         char name[17];
     234           0 :         setting.copy_name(name, 17);
     235             : 
     236           0 :         const AP_OSD_ParamSetting::ParamMetadata* metadata = setting.get_custom_metadata();
     237             : 
     238           0 :         uint16_t value_pos = 19;
     239           0 :         backend->write(x, y, param_blink, "%s:", name);
     240             : 
     241           0 :         switch (type) {
     242           0 :         case AP_PARAM_INT8: {
     243           0 :             int8_t val = ((AP_Int8*)p)->get();
     244           0 :             if (metadata != nullptr && val >= 0 && val < metadata->values_max) {
     245           0 :                 backend->write(value_pos, y, value_blink, "%s", metadata->values[val]);
     246             :             } else {
     247           0 :                 backend->write(value_pos, y, value_blink, "%hhd", val);
     248             :             }
     249           0 :             break;
     250             :         }
     251           0 :         case AP_PARAM_INT16: {
     252           0 :             int16_t val = ((AP_Int16*)p)->get();
     253           0 :             if (metadata != nullptr && val >= 0 && val < metadata->values_max) {
     254           0 :                 backend->write(value_pos, y, value_blink, "%s", metadata->values[val]);
     255             :             } else {
     256           0 :                 backend->write(value_pos, y, value_blink, "%hd", val);
     257             :             }
     258           0 :             break;
     259             :         }
     260           0 :         case AP_PARAM_INT32: {
     261           0 :            int32_t val = ((AP_Int32*)p)->get();
     262           0 :             if (metadata != nullptr && val >= 0 && val < metadata->values_max) {
     263           0 :                 backend->write(value_pos, y, value_blink, "%s", metadata->values[val]);
     264             :             } else {
     265           0 :                 backend->write(value_pos, y, value_blink, "%d", (signed)val);
     266             :             }
     267           0 :             break;
     268             :         }
     269           0 :         case AP_PARAM_FLOAT: {
     270           0 :             const float val = ((AP_Float*)p)->get();
     271             :             // cope with really small value
     272           0 :             if (val < 0.01 && !is_zero(val)) {
     273           0 :                 backend->write(value_pos, y, value_blink, "%.4f", val);
     274           0 :             } else if (val < 0.001 && !is_zero(val)) {
     275           0 :                 backend->write(value_pos, y, value_blink, "%.5f", val);
     276             :             } else {
     277           0 :                 backend->write(value_pos, y, value_blink, "%.3f", val);
     278             :             }
     279           0 :             break;
     280             :         }
     281           0 :         case AP_PARAM_VECTOR3F:
     282             :         case AP_PARAM_NONE:
     283             :         case AP_PARAM_GROUP:
     284           0 :             break;
     285             :         }
     286             :     }
     287             : }
     288             : 
     289             : // modify the selected parameter number
     290           0 : void AP_OSD_ParamScreen::modify_parameter(uint8_t number, Event ev)
     291             : {
     292           0 :     if (number > NUM_PARAMS) {
     293           0 :         return;
     294             :     }
     295             : 
     296           0 :     const AP_OSD_ParamSetting& setting = params[number-1];
     297           0 :     AP_Param* p = setting._param;
     298             : 
     299           0 :     if (p == nullptr || p->is_read_only()) {
     300           0 :         return;
     301             :     }
     302             : 
     303           0 :     _requires_save |= 1 << (number-1);
     304             : 
     305           0 :     const float incr = setting._param_incr * ((ev == Event::MENU_DOWN) ? -1.0f : 1.0f);
     306           0 :     const int32_t incr_int = int32_t(roundf(incr));
     307           0 :     const int32_t max_int = int32_t(roundf(setting._param_max));
     308           0 :     const int32_t min_int = int32_t(roundf(setting._param_min));
     309             : 
     310           0 :     switch (setting._param_type) {
     311             :         // there is no way to validate the ranges, so as a rough guess prevent
     312             :         // integer types going below -1;
     313           0 :         case AP_PARAM_INT8: {
     314           0 :             AP_Int8* param = (AP_Int8*)p;
     315           0 :             param->set(constrain_int16(param->get() + incr_int, min_int, max_int));
     316           0 :             break;
     317             :         }
     318           0 :         case AP_PARAM_INT16: {
     319           0 :             AP_Int16* param = (AP_Int16*)p;
     320           0 :             param->set(constrain_int16(param->get() + incr_int, min_int, max_int));
     321           0 :             break;
     322             :         }
     323           0 :         case AP_PARAM_INT32: {
     324           0 :             AP_Int32* param = (AP_Int32*)p;
     325           0 :             param->set(constrain_int32(param->get() + incr_int, min_int, max_int));
     326           0 :             break;
     327             :         }
     328           0 :         case AP_PARAM_FLOAT: {
     329           0 :             AP_Float* param = (AP_Float*)p;
     330           0 :             param->set(constrain_float(param->get() + incr, setting._param_min, setting._param_max));
     331           0 :             break;
     332             :         }
     333           0 :         case AP_PARAM_VECTOR3F:
     334             :         case AP_PARAM_NONE:
     335             :         case AP_PARAM_GROUP:
     336           0 :             break;
     337             :     }
     338             : 
     339             : }
     340             : 
     341             : // modify which parameter is configured for the given selection
     342           0 : void AP_OSD_ParamScreen::modify_configured_parameter(uint8_t number, Event ev)
     343             : {
     344           0 :     if (number > NUM_PARAMS) {
     345           0 :         return;
     346             :     }
     347             : 
     348           0 :     _requires_save |= 1 << (number-1);
     349             : 
     350           0 :     AP_OSD_ParamSetting& setting = params[number-1];
     351             :     AP_Param* param;
     352             : 
     353           0 :     if (ev == Event::MENU_DOWN) {
     354           0 :         param = AP_Param::next_scalar(&setting._current_token, &setting._param_type);
     355             :     } else {
     356             :         // going backwards is somewhat convoluted as the param code is geared for going forward
     357           0 :         ap_var_type type = AP_PARAM_NONE, prev_type = AP_PARAM_NONE, prev_prev_type = AP_PARAM_NONE;
     358           0 :         AP_Param::ParamToken token {}, prev_token, prev_prev_token;
     359             : 
     360           0 :         for (param = AP_Param::first(&token, &type);
     361           0 :             param && (setting._current_token.key != token.key
     362           0 :                 || setting._current_token.idx != token.idx
     363           0 :                 || setting._current_token.group_element != token.group_element);
     364           0 :             param = AP_Param::next_scalar(&token, &type)) {
     365           0 :             prev_prev_token = prev_token;
     366           0 :             prev_prev_type = prev_type;
     367           0 :             prev_token = token;
     368           0 :             prev_type = type;
     369             :         }
     370           0 :         if (param != nullptr) {
     371           0 :             param = AP_Param::next_scalar(&prev_prev_token, &prev_prev_type);
     372           0 :             setting._current_token = prev_prev_token;
     373           0 :             setting._param_type = prev_prev_type;
     374             :         }
     375             :     }
     376             : 
     377           0 :     if (param != nullptr) {
     378             :         // update the stored index
     379           0 :         setting._param_group.set(setting._current_token.group_element);
     380           0 :         setting._param_key.set(AP_Param::get_persistent_key(setting._current_token.key));
     381           0 :         setting._param_idx.set(setting._current_token.idx);
     382           0 :         setting._param = param;
     383           0 :         setting._type.set(AP_OSD_ParamSetting::Type::NONE);
     384             :         // force update() to refresh the token
     385           0 :         setting._current_token.key = 0;
     386           0 :         setting._current_token.idx = 0;
     387           0 :         setting._current_token.group_element = 0;
     388             :     }
     389             : }
     390             : 
     391             : // map rc input to an event
     392           0 : AP_OSD_ParamScreen::Event AP_OSD_ParamScreen::map_rc_input_to_event() const
     393             : {
     394           0 :     const RC_Channel::AuxSwitchPos throttle = rc().get_throttle_channel().get_stick_gesture_pos();
     395           0 :     const RC_Channel::AuxSwitchPos yaw = rc().get_yaw_channel().get_stick_gesture_pos();
     396           0 :     const RC_Channel::AuxSwitchPos roll = rc().get_roll_channel().get_stick_gesture_pos();
     397           0 :     const RC_Channel::AuxSwitchPos pitch = rc().get_pitch_channel().get_stick_gesture_pos();
     398             : 
     399           0 :     Event result = Event::NONE;
     400             : 
     401           0 :     if (yaw != RC_Channel::AuxSwitchPos::MIDDLE || throttle != RC_Channel::AuxSwitchPos::LOW) {
     402           0 :         return result;
     403             :     }
     404             : 
     405           0 :     if (pitch == RC_Channel::AuxSwitchPos::MIDDLE && roll == RC_Channel::AuxSwitchPos::LOW) {
     406           0 :         result = Event::MENU_EXIT;
     407           0 :     } else if (pitch == RC_Channel::AuxSwitchPos::MIDDLE && roll == RC_Channel::AuxSwitchPos::HIGH) {
     408           0 :         result = Event::MENU_ENTER;
     409           0 :     } else if (pitch == RC_Channel::AuxSwitchPos::LOW && roll == RC_Channel::AuxSwitchPos::MIDDLE) {
     410           0 :         result = Event::MENU_UP;
     411           0 :     } else if (pitch == RC_Channel::AuxSwitchPos::HIGH && roll == RC_Channel::AuxSwitchPos::MIDDLE) {
     412           0 :         result = Event::MENU_DOWN;
     413             :     } else {
     414             :         // OSD option has not changed so assume stick re-centering
     415           0 :         result = Event::NONE;
     416             :     }
     417           0 :     return result;
     418             : }
     419             : 
     420             : // update the state machine when disarmed
     421           0 : void AP_OSD_ParamScreen::update_state_machine()
     422             : {
     423           0 :     const uint32_t now = AP_HAL::millis();
     424           0 :     if ((now - _transition_start_ms) < _transition_timeout_ms) {
     425           0 :         return;
     426             :     }
     427             : 
     428           0 :     const Event ev = map_rc_input_to_event();
     429             :     // only take action on transitions
     430           0 :     if (ev == Event::NONE && ev == _last_rc_event) {
     431           0 :         return;
     432             :     }
     433             : 
     434             :     debug("update_state_machine(%s)\n", event_names[int(ev)]);
     435             : 
     436           0 :     _transition_start_ms = now;
     437           0 :     if (ev == _last_rc_event) {
     438           0 :         _transition_timeout_ms = OSD_HOLD_BUTTON_PRESS_DELAY;
     439           0 :         _transition_count++;
     440             :     } else {
     441           0 :         _transition_timeout_ms = osd->button_delay_ms;
     442           0 :         _transition_count = 0;
     443             :     }
     444           0 :     _last_rc_event = ev;
     445             : 
     446             :     // if we were armed then there is no selected parameter - so find one
     447           0 :     if (_selected_param == 0) {
     448           0 :         _selected_param = 1;
     449           0 :         for (uint8_t i = 0; i < NUM_PARAMS && !params[_selected_param-1].enabled; i++) {
     450           0 :             _selected_param++;
     451             :         }
     452             :     }
     453             : 
     454           0 :     switch (ev) {
     455           0 :     case Event::MENU_ENTER:
     456           0 :         switch(_menu_state) {
     457           0 :         case MenuState::PARAM_SELECT:
     458           0 :             if (_selected_param == SAVE_PARAM) {
     459           0 :                 if (_transition_count >= OSD_HOLD_BUTTON_PRESS_COUNT) {
     460           0 :                     save_parameters();
     461           0 :                     hal.scheduler->reboot();
     462             :                 } else {
     463           0 :                     save_parameters();
     464             :                 }
     465             :             } else {
     466           0 :                 _menu_state = MenuState::PARAM_VALUE_MODIFY;
     467             :             }
     468           0 :             break;
     469           0 :         case MenuState::PARAM_VALUE_MODIFY:
     470           0 :             if (_transition_count >= OSD_HOLD_BUTTON_PRESS_COUNT) {
     471           0 :                 _menu_state = MenuState::PARAM_PARAM_MODIFY;
     472             :             }
     473           0 :             break;
     474           0 :         case MenuState::PARAM_PARAM_MODIFY:
     475           0 :             break;
     476             :         }
     477           0 :         break;
     478           0 :     case Event::MENU_UP:
     479           0 :         switch (_menu_state) {
     480           0 :         case MenuState::PARAM_SELECT:
     481           0 :             _selected_param--;
     482           0 :             if (_selected_param < 1) {
     483           0 :                 _selected_param = SAVE_PARAM;
     484             :             }
     485             :             // skip over parameters that are not enabled
     486           0 :             for (uint8_t i = 0; i < NUM_PARAMS + 1 && (_selected_param != SAVE_PARAM && !params[_selected_param-1].enabled); i++) {
     487           0 :                 _selected_param--;
     488           0 :                 if (_selected_param < 1) {
     489           0 :                     _selected_param = SAVE_PARAM;
     490             :                 }
     491             :             }
     492             :             // repeat at the standard rate
     493           0 :             _transition_timeout_ms = osd->button_delay_ms;
     494           0 :             break;
     495           0 :         case MenuState::PARAM_VALUE_MODIFY:
     496           0 :             modify_parameter(_selected_param, ev);
     497           0 :             break;
     498           0 :         case MenuState::PARAM_PARAM_MODIFY:
     499           0 :             modify_configured_parameter(_selected_param, ev);
     500           0 :             break;
     501             :         }
     502           0 :         break;
     503           0 :     case Event::MENU_DOWN:
     504           0 :         switch (_menu_state) {
     505           0 :         case MenuState::PARAM_SELECT:
     506           0 :             _selected_param++;
     507           0 :             if (_selected_param > SAVE_PARAM) {
     508           0 :                 _selected_param = 1;
     509             :             }
     510             :             // skip over parameters that are not enabled
     511           0 :             for (uint8_t i = 0; i < NUM_PARAMS + 1 && (_selected_param != SAVE_PARAM && !params[_selected_param-1].enabled); i++) {
     512           0 :                 _selected_param++;
     513           0 :                 if (_selected_param > SAVE_PARAM) {
     514           0 :                     _selected_param = 1;
     515             :                 }
     516             :             }
     517             :             // repeat at the standard rate
     518           0 :             _transition_timeout_ms = osd->button_delay_ms;
     519           0 :             break;
     520           0 :         case MenuState::PARAM_VALUE_MODIFY:
     521           0 :             modify_parameter(_selected_param, ev);
     522           0 :             break;
     523           0 :         case MenuState::PARAM_PARAM_MODIFY:
     524           0 :             modify_configured_parameter(_selected_param, ev);
     525           0 :             break;
     526             :         }
     527           0 :         break;
     528           0 :     case Event::MENU_EXIT:
     529           0 :         switch(_menu_state) {
     530           0 :         case MenuState::PARAM_SELECT:
     531           0 :             break;
     532           0 :         case MenuState::PARAM_VALUE_MODIFY:
     533           0 :             _menu_state = MenuState::PARAM_SELECT;
     534           0 :             break;
     535           0 :         case MenuState::PARAM_PARAM_MODIFY:
     536           0 :             _menu_state = MenuState::PARAM_VALUE_MODIFY;
     537           0 :             break;
     538             :         }
     539           0 :         break;
     540           0 :     case Event::NONE:
     541           0 :         break;
     542             :     }
     543             : }
     544             : 
     545             : #if HAL_WITH_OSD_BITMAP || HAL_WITH_MSP_DISPLAYPORT
     546           0 : void AP_OSD_ParamScreen::draw(void)
     547             : {
     548           0 :     if (!enabled || !backend) {
     549           0 :         return;
     550             :     }
     551             : 
     552             :     // first update the state machine
     553           0 :     if (!AP::arming().is_armed()) {
     554           0 :         update_state_machine();
     555             :     } else {
     556           0 :         _selected_param = 0;
     557             :     }
     558             : 
     559           0 :     for (uint8_t i = 0; i < NUM_PARAMS; i++) {
     560           0 :         AP_OSD_ParamSetting n = params[i];
     561           0 :         if (n.enabled) {
     562           0 :             draw_parameter(n._param_number, n.xpos, n.ypos);
     563             :         }
     564             :     }
     565             :     // the save button
     566           0 :     draw_parameter(SAVE_PARAM, save_x, save_y);
     567             : }
     568             : #endif
     569             : 
     570             : #endif // OSD_ENABLED
     571             : 
     572             : // save all of the parameters
     573           0 : void AP_OSD_ParamScreen::save_parameters()
     574             : {
     575           0 :     if (!_requires_save) {
     576           0 :         return;
     577             :     }
     578             : 
     579           0 :     for (uint8_t i = 0; i < NUM_PARAMS; i++) {
     580           0 :         if (params[i].enabled && (_requires_save & (1 << i))) {
     581           0 :             AP_Param* p = params[i]._param;
     582           0 :             if (p != nullptr) {
     583           0 :                 p->save();
     584             :             }
     585           0 :             params[i].save_as_new();
     586             :         }
     587             :     }
     588           0 :     _requires_save = 0;
     589             : }
     590             : 
     591             : // handle OSD configuration messages
     592             : #if HAL_GCS_ENABLED
     593           0 : void AP_OSD_ParamScreen::handle_write_msg(const mavlink_osd_param_config_t& packet, const class GCS_MAVLINK& link)
     594             : {
     595             :     // request out of range - return an error
     596           0 :     if (packet.osd_index < 1 || packet.osd_index > AP_OSD_ParamScreen::NUM_PARAMS) {
     597           0 :         mavlink_msg_osd_param_config_reply_send(link.get_chan(), packet.request_id, OSD_PARAM_INVALID_PARAMETER_INDEX);
     598           0 :         return;
     599             :     }
     600             :     // set the parameter
     601           0 :     bool ret = params[packet.osd_index - 1].set_by_name(packet.param_id, packet.config_type, packet.min_value, packet.max_value, packet.increment);
     602           0 :     mavlink_msg_osd_param_config_reply_send(link.get_chan(), packet.request_id, ret ? OSD_PARAM_SUCCESS : OSD_PARAM_INVALID_PARAMETER);
     603             : }
     604             : 
     605             : // handle OSD show configuration messages
     606           0 : void AP_OSD_ParamScreen::handle_read_msg(const mavlink_osd_param_show_config_t& packet, const class GCS_MAVLINK& link)
     607             : {
     608             :     // request out of range - return an error
     609           0 :     if (packet.osd_index < 1 || packet.osd_index > AP_OSD_ParamScreen::NUM_PARAMS) {
     610           0 :         mavlink_msg_osd_param_show_config_reply_send(link.get_chan(), packet.request_id, OSD_PARAM_INVALID_PARAMETER_INDEX,
     611             :             nullptr, uint8_t(AP_OSD_ParamSetting::Type::NONE), 0, 0, 0);
     612           0 :         return;
     613             :     }
     614             :     // get the parameter and make sure it is fresh
     615           0 :     AP_OSD_ParamSetting& param = params[packet.osd_index - 1];
     616           0 :     param.update();
     617             : 
     618             :     // check for bad things
     619           0 :     if (param._param == nullptr) {
     620           0 :         mavlink_msg_osd_param_show_config_reply_send(link.get_chan(), packet.request_id, OSD_PARAM_INVALID_PARAMETER_INDEX,
     621             :             nullptr, uint8_t(AP_OSD_ParamSetting::Type::NONE), 0, 0, 0);
     622           0 :         return;
     623             :     }
     624             :     // get the name and send back the details
     625             :     char buf[AP_MAX_NAME_SIZE+1];
     626           0 :     param._param->copy_name_token(param._current_token, buf, AP_MAX_NAME_SIZE);
     627           0 :     buf[AP_MAX_NAME_SIZE] = 0;
     628           0 :     mavlink_msg_osd_param_show_config_reply_send(link.get_chan(), packet.request_id, OSD_PARAM_SUCCESS,
     629             :         buf, param._type, param._param_min, param._param_max, param._param_incr);
     630             : }
     631             : #endif
     632             : 
     633             : #endif // OSD_PARAM_ENABLED

Generated by: LCOV version 1.14