LCOV - code coverage report
Current view: top level - AP_OSD - AP_OSD_Screen.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 282 633 44.5 %
Date: 2026-09-09 11:02:08 Functions: 29 65 44.6 %

          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_config.h"
      23             : 
      24             : #if OSD_ENABLED
      25             : 
      26             : #include "AP_OSD.h"
      27             : #include "AP_OSD_Backend.h"
      28             : 
      29             : #include <AP_HAL/AP_HAL.h>
      30             : #include <AP_HAL/Util.h>
      31             : #include <AP_AHRS/AP_AHRS.h>
      32             : #include <AP_Math/AP_Math.h>
      33             : #include <AP_RSSI/AP_RSSI.h>
      34             : #include <AP_Notify/AP_Notify.h>
      35             : #include <AP_Stats/AP_Stats.h>
      36             : #include <AP_Common/Location.h>
      37             : #include <AP_BattMonitor/AP_BattMonitor.h>
      38             : #include <AP_GPS/AP_GPS.h>
      39             : #include <AP_RTC/AP_RTC.h>
      40             : #include <AP_MSP/msp.h>
      41             : #include <AP_OLC/AP_OLC.h>
      42             : #include <AP_VideoTX/AP_VideoTX.h>
      43             : #include <AP_Terrain/AP_Terrain.h>
      44             : #include <AP_RangeFinder/AP_RangeFinder.h>
      45             : #include <AP_Vehicle/AP_Vehicle.h>
      46             : #include <AP_RPM/AP_RPM.h>
      47             : #include <AP_MSP/AP_MSP.h>
      48             : #if APM_BUILD_TYPE(APM_BUILD_Rover)
      49             : #include <AP_WindVane/AP_WindVane.h>
      50             : #endif
      51             : #include <AP_Filesystem/AP_Filesystem.h>
      52             : 
      53             : #include <ctype.h>
      54             : #include <GCS_MAVLink/GCS.h>
      55             : #include <AC_Fence/AC_Fence.h>
      56             : 
      57             : #if AP_OSD_EXTENDED_LNK_STATS
      58             : // We need to this file to access the CRSF telemetry objects which contains the link stats data
      59             : #include <AP_RCProtocol/AP_RCProtocol_CRSF.h>   
      60             : #endif
      61             : 
      62             : const AP_Param::GroupInfo AP_OSD_Screen::var_info[] = {
      63             : 
      64             :     // @Param: ENABLE
      65             :     // @DisplayName: Enable screen
      66             :     // @Description: Enable this screen
      67             :     // @Values: 0:Disabled,1:Enabled
      68             :     // @User: Standard
      69             :     AP_GROUPINFO_FLAGS("ENABLE", 1, AP_OSD_Screen, enabled, 0, AP_PARAM_FLAG_ENABLE),
      70             : 
      71             :     // @Param: CHAN_MIN
      72             :     // @DisplayName: Transmitter switch screen minimum pwm
      73             :     // @Description: This sets the PWM lower limit for this screen
      74             :     // @Range: 900 2100
      75             :     // @User: Standard
      76             :     AP_GROUPINFO("CHAN_MIN", 2, AP_OSD_Screen, channel_min, 900),
      77             : 
      78             :     // @Param: CHAN_MAX
      79             :     // @DisplayName: Transmitter switch screen maximum pwm
      80             :     // @Description: This sets the PWM upper limit for this screen
      81             :     // @Range: 900 2100
      82             :     // @User: Standard
      83             :     AP_GROUPINFO("CHAN_MAX", 3, AP_OSD_Screen, channel_max, 2100),
      84             : 
      85             :     // @Param: ALTITUDE_EN
      86             :     // @DisplayName: ALTITUDE_EN
      87             :     // @Description: Enables display of altitude AGL
      88             :     // @Values: 0:Disabled,1:Enabled
      89             : 
      90             :     // @Param: ALTITUDE_X
      91             :     // @DisplayName: ALTITUDE_X
      92             :     // @Description: Horizontal position on screen
      93             :     // @Range: 0 59
      94             : 
      95             :     // @Param: ALTITUDE_Y
      96             :     // @DisplayName: ALTITUDE_Y
      97             :     // @Description: Vertical position on screen
      98             :     // @Range: 0 21
      99             :     AP_SUBGROUPINFO(altitude, "ALTITUDE", 4, AP_OSD_Screen, AP_OSD_Setting),
     100             : 
     101             :     // @Param: BAT_VOLT_EN
     102             :     // @DisplayName: BATVOLT_EN
     103             :     // @Description: Displays main battery voltage
     104             :     // @Values: 0:Disabled,1:Enabled
     105             : 
     106             :     // @Param: BAT_VOLT_X
     107             :     // @DisplayName: BATVOLT_X
     108             :     // @Description: Horizontal position on screen
     109             :     // @Range: 0 59
     110             : 
     111             :     // @Param: BAT_VOLT_Y
     112             :     // @DisplayName: BATVOLT_Y
     113             :     // @Description: Vertical position on screen
     114             :     // @Range: 0 21
     115             :     AP_SUBGROUPINFO(bat_volt, "BAT_VOLT", 5, AP_OSD_Screen, AP_OSD_Setting),
     116             : 
     117             :     // @Param: RSSI_EN
     118             :     // @DisplayName: RSSI_EN
     119             :     // @Description: Displays RC signal strength
     120             :     // @Values: 0:Disabled,1:Enabled
     121             : 
     122             :     // @Param: RSSI_X
     123             :     // @DisplayName: RSSI_X
     124             :     // @Description: Horizontal position on screen
     125             :     // @Range: 0 59
     126             : 
     127             :     // @Param: RSSI_Y
     128             :     // @DisplayName: RSSI_Y
     129             :     // @Description: Vertical position on screen
     130             :     // @Range: 0 21
     131             :     AP_SUBGROUPINFO(rssi, "RSSI", 6, AP_OSD_Screen, AP_OSD_Setting),
     132             : 
     133             :     // @Param: CURRENT_EN
     134             :     // @DisplayName: CURRENT_EN
     135             :     // @Description: Displays main battery current
     136             :     // @Values: 0:Disabled,1:Enabled
     137             : 
     138             :     // @Param: CURRENT_X
     139             :     // @DisplayName: CURRENT_X
     140             :     // @Description: Horizontal position on screen
     141             :     // @Range: 0 59
     142             : 
     143             :     // @Param: CURRENT_Y
     144             :     // @DisplayName: CURRENT_Y
     145             :     // @Description: Vertical position on screen
     146             :     // @Range: 0 21
     147             :     AP_SUBGROUPINFO(current, "CURRENT", 7, AP_OSD_Screen, AP_OSD_Setting),
     148             : 
     149             :     // @Param: BATUSED_EN
     150             :     // @DisplayName: BATUSED_EN
     151             :     // @Description: Displays primary battery mAh consumed
     152             :     // @Values: 0:Disabled,1:Enabled
     153             : 
     154             :     // @Param: BATUSED_X
     155             :     // @DisplayName: BATUSED_X
     156             :     // @Description: Horizontal position on screen
     157             :     // @Range: 0 59
     158             : 
     159             :     // @Param: BATUSED_Y
     160             :     // @DisplayName: BATUSED_Y
     161             :     // @Description: Vertical position on screen
     162             :     // @Range: 0 21
     163             :     AP_SUBGROUPINFO(batused, "BATUSED", 8, AP_OSD_Screen, AP_OSD_Setting),
     164             : 
     165             :     // @Param: SATS_EN
     166             :     // @DisplayName: SATS_EN
     167             :     // @Description: Displays number of acquired satellites
     168             :     // @Values: 0:Disabled,1:Enabled
     169             : 
     170             :     // @Param: SATS_X
     171             :     // @DisplayName: SATS_X
     172             :     // @Description: Horizontal position on screen
     173             :     // @Range: 0 59
     174             : 
     175             :     // @Param: SATS_Y
     176             :     // @DisplayName: SATS_Y
     177             :     // @Description: Vertical position on screen
     178             :     // @Range: 0 21
     179             :     AP_SUBGROUPINFO(sats, "SATS", 9, AP_OSD_Screen, AP_OSD_Setting),
     180             : 
     181             :     // @Param: FLTMODE_EN
     182             :     // @DisplayName: FLTMODE_EN
     183             :     // @Description: Displays flight mode
     184             :     // @Values: 0:Disabled,1:Enabled
     185             : 
     186             :     // @Param: FLTMODE_X
     187             :     // @DisplayName: FLTMODE_X
     188             :     // @Description: Horizontal position on screen
     189             :     // @Range: 0 59
     190             : 
     191             :     // @Param: FLTMODE_Y
     192             :     // @DisplayName: FLTMODE_Y
     193             :     // @Description: Vertical position on screen
     194             :     // @Range: 0 21
     195             :     AP_SUBGROUPINFO(fltmode, "FLTMODE", 10, AP_OSD_Screen, AP_OSD_Setting),
     196             : 
     197             :     // @Param: MESSAGE_EN
     198             :     // @DisplayName: MESSAGE_EN
     199             :     // @Description: Displays Mavlink messages
     200             :     // @Values: 0:Disabled,1:Enabled
     201             : 
     202             :     // @Param: MESSAGE_X
     203             :     // @DisplayName: MESSAGE_X
     204             :     // @Description: Horizontal position on screen
     205             :     // @Range: 0 59
     206             : 
     207             :     // @Param: MESSAGE_Y
     208             :     // @DisplayName: MESSAGE_Y
     209             :     // @Description: Vertical position on screen
     210             :     // @Range: 0 21
     211             :     AP_SUBGROUPINFO(message, "MESSAGE", 11, AP_OSD_Screen, AP_OSD_Setting),
     212             : 
     213             :     // @Param: GSPEED_EN
     214             :     // @DisplayName: GSPEED_EN
     215             :     // @Description: Displays GPS ground speed
     216             :     // @Values: 0:Disabled,1:Enabled
     217             : 
     218             :     // @Param: GSPEED_X
     219             :     // @DisplayName: GSPEED_X
     220             :     // @Description: Horizontal position on screen
     221             :     // @Range: 0 59
     222             : 
     223             :     // @Param: GSPEED_Y
     224             :     // @DisplayName: GSPEED_Y
     225             :     // @Description: Vertical position on screen
     226             :     // @Range: 0 21
     227             :     AP_SUBGROUPINFO(gspeed, "GSPEED", 12, AP_OSD_Screen, AP_OSD_Setting),
     228             : 
     229             :     // @Param: HORIZON_EN
     230             :     // @DisplayName: HORIZON_EN
     231             :     // @Description: Displays artificial horizon
     232             :     // @Values: 0:Disabled,1:Enabled
     233             : 
     234             :     // @Param: HORIZON_X
     235             :     // @DisplayName: HORIZON_X
     236             :     // @Description: Horizontal position on screen
     237             :     // @Range: 0 59
     238             : 
     239             :     // @Param: HORIZON_Y
     240             :     // @DisplayName: HORIZON_Y
     241             :     // @Description: Vertical position on screen
     242             :     // @Range: 0 21
     243             :     AP_SUBGROUPINFO(horizon, "HORIZON", 13, AP_OSD_Screen, AP_OSD_Setting),
     244             : 
     245             :     // @Param: HOME_EN
     246             :     // @DisplayName: HOME_EN
     247             :     // @Description: Displays distance and relative direction to HOME
     248             :     // @Values: 0:Disabled,1:Enabled
     249             : 
     250             :     // @Param: HOME_X
     251             :     // @DisplayName: HOME_X
     252             :     // @Description: Horizontal position on screen
     253             :     // @Range: 0 59
     254             : 
     255             :     // @Param: HOME_Y
     256             :     // @DisplayName: HOME_Y
     257             :     // @Description: Vertical position on screen
     258             :     // @Range: 0 21
     259             :     AP_SUBGROUPINFO(home, "HOME", 14, AP_OSD_Screen, AP_OSD_Setting),
     260             : 
     261             :     // @Param: HEADING_EN
     262             :     // @DisplayName: HEADING_EN
     263             :     // @Description: Displays heading
     264             :     // @Values: 0:Disabled,1:Enabled
     265             : 
     266             :     // @Param: HEADING_X
     267             :     // @DisplayName: HEADING_X
     268             :     // @Description: Horizontal position on screen
     269             :     // @Range: 0 59
     270             : 
     271             :     // @Param: HEADING_Y
     272             :     // @DisplayName: HEADING_Y
     273             :     // @Description: Vertical position on screen
     274             :     // @Range: 0 21
     275             :     AP_SUBGROUPINFO(heading, "HEADING", 15, AP_OSD_Screen, AP_OSD_Setting),
     276             : 
     277             :     // @Param: THROTTLE_EN
     278             :     // @DisplayName: THROTTLE_EN
     279             :     // @Description: Displays actual throttle percentage being sent to motor(s)
     280             :     // @Values: 0:Disabled,1:Enabled
     281             : 
     282             :     // @Param: THROTTLE_X
     283             :     // @DisplayName: THROTTLE_X
     284             :     // @Description: Horizontal position on screen
     285             :     // @Range: 0 59
     286             : 
     287             :     // @Param: THROTTLE_Y
     288             :     // @DisplayName: THROTTLE_Y
     289             :     // @Description: Vertical position on screen
     290             :     // @Range: 0 21
     291             :     AP_SUBGROUPINFO(throttle, "THROTTLE", 16, AP_OSD_Screen, AP_OSD_Setting),
     292             : 
     293             :     // @Param: COMPASS_EN
     294             :     // @DisplayName: COMPASS_EN
     295             :     // @Description: Enables display of compass rose
     296             :     // @Values: 0:Disabled,1:Enabled
     297             : 
     298             :     // @Param: COMPASS_X
     299             :     // @DisplayName: COMPASS_X
     300             :     // @Description: Horizontal position on screen
     301             :     // @Range: 0 59
     302             : 
     303             :     // @Param: COMPASS_Y
     304             :     // @DisplayName: COMPASS_Y
     305             :     // @Description: Vertical position on screen
     306             :     // @Range: 0 21
     307             :     AP_SUBGROUPINFO(compass, "COMPASS", 17, AP_OSD_Screen, AP_OSD_Setting),
     308             : 
     309             :     // @Param: WIND_EN
     310             :     // @DisplayName: WIND_EN
     311             :     // @Description: Displays wind speed and relative direction, on Rover this is the apparent wind speed and direction from the windvane, if fitted
     312             :     // @Values: 0:Disabled,1:Enabled
     313             : 
     314             :     // @Param: WIND_X
     315             :     // @DisplayName: WIND_X
     316             :     // @Description: Horizontal position on screen
     317             :     // @Range: 0 59
     318             : 
     319             :     // @Param: WIND_Y
     320             :     // @DisplayName: WIND_Y
     321             :     // @Description: Vertical position on screen
     322             :     // @Range: 0 21
     323             :     AP_SUBGROUPINFO(wind, "WIND", 18, AP_OSD_Screen, AP_OSD_Setting),
     324             : 
     325             : 
     326             :     // @Param: ASPEED_EN
     327             :     // @DisplayName: ASPEED_EN
     328             :     // @Description: Displays airspeed value being used by TECS (fused value)
     329             :     // @Values: 0:Disabled,1:Enabled
     330             : 
     331             :     // @Param: ASPEED_X
     332             :     // @DisplayName: ASPEED_X
     333             :     // @Description: Horizontal position on screen
     334             :     // @Range: 0 59
     335             : 
     336             :     // @Param: ASPEED_Y
     337             :     // @DisplayName: ASPEED_Y
     338             :     // @Description: Vertical position on screen
     339             :     // @Range: 0 21
     340             :     AP_SUBGROUPINFO(aspeed, "ASPEED", 19, AP_OSD_Screen, AP_OSD_Setting),
     341             : 
     342             :     // @Param: VSPEED_EN
     343             :     // @DisplayName: VSPEED_EN
     344             :     // @Description: Displays climb rate
     345             :     // @Values: 0:Disabled,1:Enabled
     346             : 
     347             :     // @Param: VSPEED_X
     348             :     // @DisplayName: VSPEED_X
     349             :     // @Description: Horizontal position on screen
     350             :     // @Range: 0 59
     351             : 
     352             :     // @Param: VSPEED_Y
     353             :     // @DisplayName: VSPEED_Y
     354             :     // @Description: Vertical position on screen
     355             :     // @Range: 0 21
     356             :     AP_SUBGROUPINFO(vspeed, "VSPEED", 20, AP_OSD_Screen, AP_OSD_Setting),
     357             : 
     358             : #if HAL_WITH_ESC_TELEM
     359             :     // @Param: ESCTEMP_EN
     360             :     // @DisplayName: ESCTEMP_EN
     361             :     // @Description: Displays highest temp of all active ESCs, or of a specific ECS if OSDx_ESC_IDX is set
     362             :     // @Values: 0:Disabled,1:Enabled
     363             : 
     364             :     // @Param: ESCTEMP_X
     365             :     // @DisplayName: ESCTEMP_X
     366             :     // @Description: Horizontal position on screen
     367             :     // @Range: 0 59
     368             : 
     369             :     // @Param: ESCTEMP_Y
     370             :     // @DisplayName: ESCTEMP_Y
     371             :     // @Description: Vertical position on screen
     372             :     // @Range: 0 21
     373             :     AP_SUBGROUPINFO(esc_temp, "ESCTEMP", 21, AP_OSD_Screen, AP_OSD_Setting),
     374             : 
     375             :     // @Param: ESCRPM_EN
     376             :     // @DisplayName: ESCRPM_EN
     377             :     // @Description: Displays highest rpm of all active ESCs, or of a specific ESC if OSDx_ESC_IDX is set
     378             :     // @Values: 0:Disabled,1:Enabled
     379             : 
     380             :     // @Param: ESCRPM_X
     381             :     // @DisplayName: ESCRPM_X
     382             :     // @Description: Horizontal position on screen
     383             :     // @Range: 0 59
     384             : 
     385             :     // @Param: ESCRPM_Y
     386             :     // @DisplayName: ESCRPM_Y
     387             :     // @Description: Vertical position on screen
     388             :     // @Range: 0 21
     389             :     AP_SUBGROUPINFO(esc_rpm, "ESCRPM", 22, AP_OSD_Screen, AP_OSD_Setting),
     390             : 
     391             :     // @Param: ESCAMPS_EN
     392             :     // @DisplayName: ESCAMPS_EN
     393             :     // @Description: Displays the current of the ESC with the highest rpm of all active ESCs, or of a specific ESC if OSDx_ESC_IDX is set
     394             :     // @Values: 0:Disabled,1:Enabled
     395             : 
     396             :     // @Param: ESCAMPS_X
     397             :     // @DisplayName: ESCAMPS_X
     398             :     // @Description: Horizontal position on screen
     399             :     // @Range: 0 59
     400             : 
     401             :     // @Param: ESCAMPS_Y
     402             :     // @DisplayName: ESCAMPS_Y
     403             :     // @Description: Vertical position on screen
     404             :     // @Range: 0 21
     405             :     AP_SUBGROUPINFO(esc_amps, "ESCAMPS", 23, AP_OSD_Screen, AP_OSD_Setting),
     406             : #endif
     407             :     // @Param: GPSLAT_EN
     408             :     // @DisplayName: GPSLAT_EN
     409             :     // @Description: Displays GPS latitude
     410             :     // @Values: 0:Disabled,1:Enabled
     411             : 
     412             :     // @Param: GPSLAT_X
     413             :     // @DisplayName: GPSLAT_X
     414             :     // @Description: Horizontal position on screen
     415             :     // @Range: 0 59
     416             : 
     417             :     // @Param: GPSLAT_Y
     418             :     // @DisplayName: GPSLAT_Y
     419             :     // @Description: Vertical position on screen
     420             :     // @Range: 0 21
     421             :     AP_SUBGROUPINFO(gps_latitude, "GPSLAT", 24, AP_OSD_Screen, AP_OSD_Setting),
     422             : 
     423             :     // @Param: GPSLONG_EN
     424             :     // @DisplayName: GPSLONG_EN
     425             :     // @Description: Displays GPS longitude
     426             :     // @Values: 0:Disabled,1:Enabled
     427             : 
     428             :     // @Param: GPSLONG_X
     429             :     // @DisplayName: GPSLONG_X
     430             :     // @Description: Horizontal position on screen
     431             :     // @Range: 0 59
     432             : 
     433             :     // @Param: GPSLONG_Y
     434             :     // @DisplayName: GPSLONG_Y
     435             :     // @Description: Vertical position on screen
     436             :     // @Range: 0 21
     437             :     AP_SUBGROUPINFO(gps_longitude, "GPSLONG", 25, AP_OSD_Screen, AP_OSD_Setting),
     438             : 
     439             :     // @Param: ROLL_EN
     440             :     // @DisplayName: ROLL_EN
     441             :     // @Description: Displays degrees of roll from level
     442             :     // @Values: 0:Disabled,1:Enabled
     443             : 
     444             :     // @Param: ROLL_X
     445             :     // @DisplayName: ROLL_X
     446             :     // @Description: Horizontal position on screen
     447             :     // @Range: 0 59
     448             : 
     449             :     // @Param: ROLL_Y
     450             :     // @DisplayName: ROLL_Y
     451             :     // @Description: Vertical position on screen
     452             :     // @Range: 0 21
     453             :     AP_SUBGROUPINFO(roll_angle, "ROLL", 26, AP_OSD_Screen, AP_OSD_Setting),
     454             : 
     455             :     // @Param: PITCH_EN
     456             :     // @DisplayName: PITCH_EN
     457             :     // @Description: Displays degrees of pitch from level
     458             :     // @Values: 0:Disabled,1:Enabled
     459             : 
     460             :     // @Param: PITCH_X
     461             :     // @DisplayName: PITCH_X
     462             :     // @Description: Horizontal position on screen
     463             :     // @Range: 0 59
     464             : 
     465             :     // @Param: PITCH_Y
     466             :     // @DisplayName: PITCH_Y
     467             :     // @Description: Vertical position on screen
     468             :     // @Range: 0 21
     469             :     AP_SUBGROUPINFO(pitch_angle, "PITCH", 27, AP_OSD_Screen, AP_OSD_Setting),
     470             : 
     471             :     // @Param: TEMP_EN
     472             :     // @DisplayName: TEMP_EN
     473             :     // @Description: Displays temperature reported by primary barometer
     474             :     // @Values: 0:Disabled,1:Enabled
     475             : 
     476             :     // @Param: TEMP_X
     477             :     // @DisplayName: TEMP_X
     478             :     // @Description: Horizontal position on screen
     479             :     // @Range: 0 59
     480             : 
     481             :     // @Param: TEMP_Y
     482             :     // @DisplayName: TEMP_Y
     483             :     // @Description: Vertical position on screen
     484             :     // @Range: 0 21
     485             :     AP_SUBGROUPINFO(temp, "TEMP", 28, AP_OSD_Screen, AP_OSD_Setting),
     486             : 
     487             :     // @Param: HDOP_EN
     488             :     // @DisplayName: HDOP_EN
     489             :     // @Description: Displays Horizontal Dilution Of Position
     490             :     // @Values: 0:Disabled,1:Enabled
     491             : 
     492             :     // @Param: HDOP_X
     493             :     // @DisplayName: HDOP_X
     494             :     // @Description: Horizontal position on screen
     495             :     // @Range: 0 59
     496             : 
     497             :     // @Param: HDOP_Y
     498             :     // @DisplayName: HDOP_Y
     499             :     // @Description: Vertical position on screen
     500             :     // @Range: 0 21
     501             :     AP_SUBGROUPINFO(hdop, "HDOP", 29, AP_OSD_Screen, AP_OSD_Setting),
     502             : 
     503             :     // @Param: WAYPOINT_EN
     504             :     // @DisplayName: WAYPOINT_EN
     505             :     // @Description: Displays bearing and distance to next waypoint
     506             :     // @Values: 0:Disabled,1:Enabled
     507             : 
     508             :     // @Param: WAYPOINT_X
     509             :     // @DisplayName: WAYPOINT_X
     510             :     // @Description: Horizontal position on screen
     511             :     // @Range: 0 59
     512             : 
     513             :     // @Param: WAYPOINT_Y
     514             :     // @DisplayName: WAYPOINT_Y
     515             :     // @Description: Vertical position on screen
     516             :     // @Range: 0 21
     517             :     AP_SUBGROUPINFO(waypoint, "WAYPOINT", 30, AP_OSD_Screen, AP_OSD_Setting),
     518             : 
     519             :     // @Param: XTRACK_EN
     520             :     // @DisplayName: XTRACK_EN
     521             :     // @Description: Displays crosstrack error
     522             :     // @Values: 0:Disabled,1:Enabled
     523             : 
     524             :     // @Param: XTRACK_X
     525             :     // @DisplayName: XTRACK_X
     526             :     // @Description: Horizontal position on screen
     527             :     // @Range: 0 59
     528             : 
     529             :     // @Param: XTRACK_Y
     530             :     // @DisplayName: XTRACK_Y
     531             :     // @Description: Vertical position on screen
     532             :     // @Range: 0 21
     533             :     AP_SUBGROUPINFO(xtrack_error, "XTRACK", 31, AP_OSD_Screen, AP_OSD_Setting),
     534             : 
     535             :     // @Param: DIST_EN
     536             :     // @DisplayName: DIST_EN
     537             :     // @Description: Displays total distance flown
     538             :     // @Values: 0:Disabled,1:Enabled
     539             : 
     540             :     // @Param: DIST_X
     541             :     // @DisplayName: DIST_X
     542             :     // @Description: Horizontal position on screen
     543             :     // @Range: 0 59
     544             : 
     545             :     // @Param: DIST_Y
     546             :     // @DisplayName: DIST_Y
     547             :     // @Description: Vertical position on screen
     548             :     // @Range: 0 21
     549             :     AP_SUBGROUPINFO(dist, "DIST", 32, AP_OSD_Screen, AP_OSD_Setting),
     550             : 
     551             :     // @Param: STATS_EN
     552             :     // @DisplayName: STATS_EN
     553             :     // @Description: Displays flight stats
     554             :     // @Values: 0:Disabled,1:Enabled
     555             : 
     556             :     // @Param: STATS_X
     557             :     // @DisplayName: STATS_X
     558             :     // @Description: Horizontal position on screen
     559             :     // @Range: 0 59
     560             : 
     561             :     // @Param: STATS_Y
     562             :     // @DisplayName: STATS_Y
     563             :     // @Description: Vertical position on screen
     564             :     // @Range: 0 21
     565             :     AP_SUBGROUPINFO(stat, "STATS", 33, AP_OSD_Screen, AP_OSD_Setting),
     566             : 
     567             :     // @Param: FLTIME_EN
     568             :     // @DisplayName: FLTIME_EN
     569             :     // @Description: Displays total flight time
     570             :     // @Values: 0:Disabled,1:Enabled
     571             : 
     572             :     // @Param: FLTIME_X
     573             :     // @DisplayName: FLTIME_X
     574             :     // @Description: Horizontal position on screen
     575             :     // @Range: 0 59
     576             : 
     577             :     // @Param: FLTIME_Y
     578             :     // @DisplayName: FLTIME_Y
     579             :     // @Description: Vertical position on screen
     580             :     // @Range: 0 21
     581             :     AP_SUBGROUPINFO(flightime, "FLTIME", 34, AP_OSD_Screen, AP_OSD_Setting),
     582             : 
     583             :     // @Param: CLIMBEFF_EN
     584             :     // @DisplayName: CLIMBEFF_EN
     585             :     // @Description: Displays climb efficiency (climb rate/current)
     586             :     // @Values: 0:Disabled,1:Enabled
     587             : 
     588             :     // @Param: CLIMBEFF_X
     589             :     // @DisplayName: CLIMBEFF_X
     590             :     // @Description: Horizontal position on screen
     591             :     // @Range: 0 59
     592             : 
     593             :     // @Param: CLIMBEFF_Y
     594             :     // @DisplayName: CLIMBEFF_Y
     595             :     // @Description: Vertical position on screen
     596             :     // @Range: 0 21
     597             :     AP_SUBGROUPINFO(climbeff, "CLIMBEFF", 35, AP_OSD_Screen, AP_OSD_Setting),
     598             : 
     599             :     // @Param: EFF_EN
     600             :     // @DisplayName: EFF_EN
     601             :     // @Description: Displays flight efficiency (mAh/km or /mi)
     602             :     // @Values: 0:Disabled,1:Enabled
     603             : 
     604             :     // @Param: EFF_X
     605             :     // @DisplayName: EFF_X
     606             :     // @Description: Horizontal position on screen
     607             :     // @Range: 0 59
     608             : 
     609             :     // @Param: EFF_Y
     610             :     // @DisplayName: EFF_Y
     611             :     // @Description: Vertical position on screen
     612             :     // @Range: 0 21
     613             :     AP_SUBGROUPINFO(eff, "EFF", 36, AP_OSD_Screen, AP_OSD_Setting),
     614             : 
     615             : #if BARO_MAX_INSTANCES > 1
     616             :     // @Param: BTEMP_EN
     617             :     // @DisplayName: BTEMP_EN
     618             :     // @Description: Displays temperature reported by secondary barometer
     619             :     // @Values: 0:Disabled,1:Enabled
     620             : 
     621             :     // @Param: BTEMP_X
     622             :     // @DisplayName: BTEMP_X
     623             :     // @Description: Horizontal position on screen
     624             :     // @Range: 0 59
     625             : 
     626             :     // @Param: BTEMP_Y
     627             :     // @DisplayName: BTEMP_Y
     628             :     // @Description: Vertical position on screen
     629             :     // @Range: 0 21
     630             :     AP_SUBGROUPINFO(btemp, "BTEMP", 37, AP_OSD_Screen, AP_OSD_Setting),
     631             : #endif
     632             : 
     633             :     // @Param: ATEMP_EN
     634             :     // @DisplayName: ATEMP_EN
     635             :     // @Description: Displays temperature reported by primary airspeed sensor
     636             :     // @Values: 0:Disabled,1:Enabled
     637             : 
     638             :     // @Param: ATEMP_X
     639             :     // @DisplayName: ATEMP_X
     640             :     // @Description: Horizontal position on screen
     641             :     // @Range: 0 59
     642             : 
     643             :     // @Param: ATEMP_Y
     644             :     // @DisplayName: ATEMP_Y
     645             :     // @Description: Vertical position on screen
     646             :     // @Range: 0 21
     647             :     AP_SUBGROUPINFO(atemp, "ATEMP", 38, AP_OSD_Screen, AP_OSD_Setting),
     648             : 
     649             :     // @Param: BAT2_VLT_EN
     650             :     // @DisplayName: BAT2VLT_EN
     651             :     // @Description: Displays battery2 voltage
     652             :     // @Values: 0:Disabled,1:Enabled
     653             : 
     654             :     // @Param: BAT2_VLT_X
     655             :     // @DisplayName: BAT2VLT_X
     656             :     // @Description: Horizontal position on screen
     657             :     // @Range: 0 59
     658             : 
     659             :     // @Param: BAT2_VLT_Y
     660             :     // @DisplayName: BAT2VLT_Y
     661             :     // @Description: Vertical position on screen
     662             :     // @Range: 0 21
     663             :     AP_SUBGROUPINFO(bat2_vlt, "BAT2_VLT", 39, AP_OSD_Screen, AP_OSD_Setting),
     664             : 
     665             :     // @Param: BAT2USED_EN
     666             :     // @DisplayName: BAT2USED_EN
     667             :     // @Description: Displays secondary battery mAh consumed
     668             :     // @Values: 0:Disabled,1:Enabled
     669             : 
     670             :     // @Param: BAT2USED_X
     671             :     // @DisplayName: BAT2USED_X
     672             :     // @Description: Horizontal position on screen
     673             :     // @Range: 0 59
     674             : 
     675             :     // @Param: BAT2USED_Y
     676             :     // @DisplayName: BAT2USED_Y
     677             :     // @Description: Vertical position on screen
     678             :     // @Range: 0 21
     679             :     AP_SUBGROUPINFO(bat2used, "BAT2USED", 40, AP_OSD_Screen, AP_OSD_Setting),
     680             : 
     681             : 
     682             :     // @Param: ASPD2_EN
     683             :     // @DisplayName: ASPD2_EN
     684             :     // @Description: Displays airspeed reported directly from secondary airspeed sensor
     685             :     // @Values: 0:Disabled,1:Enabled
     686             : 
     687             :     // @Param: ASPD2_X
     688             :     // @DisplayName: ASPD2_X
     689             :     // @Description: Horizontal position on screen
     690             :     // @Range: 0 59
     691             : 
     692             :     // @Param: ASPD2_Y
     693             :     // @DisplayName: ASPD2_Y
     694             :     // @Description: Vertical position on screen
     695             :     // @Range: 0 21
     696             :     AP_SUBGROUPINFO(aspd2, "ASPD2", 41, AP_OSD_Screen, AP_OSD_Setting),
     697             : 
     698             :     // @Param: ASPD1_EN
     699             :     // @DisplayName: ASPD1_EN
     700             :     // @Description: Displays airspeed reported directly from primary airspeed sensor
     701             :     // @Values: 0:Disabled,1:Enabled
     702             : 
     703             :     // @Param: ASPD1_X
     704             :     // @DisplayName: ASPD1_X
     705             :     // @Description: Horizontal position on screen
     706             :     // @Range: 0 59
     707             : 
     708             :     // @Param: ASPD1_Y
     709             :     // @DisplayName: ASPD1_Y
     710             :     // @Description: Vertical position on screen
     711             :     // @Range: 0 21
     712             :     AP_SUBGROUPINFO(aspd1, "ASPD1", 42, AP_OSD_Screen, AP_OSD_Setting),
     713             : 
     714             :     // @Param: CLK_EN
     715             :     // @DisplayName: CLK_EN
     716             :     // @Description: Displays a clock panel based on AP_RTC local time
     717             :     // @Values: 0:Disabled,1:Enabled
     718             : 
     719             :     // @Param: CLK_X
     720             :     // @DisplayName: CLK_X
     721             :     // @Description: Horizontal position on screen
     722             :     // @Range: 0 59
     723             : 
     724             :     // @Param: CLK_Y
     725             :     // @DisplayName: CLK_Y
     726             :     // @Description: Vertical position on screen
     727             :     // @Range: 0 21
     728             :     AP_SUBGROUPINFO(clk, "CLK", 43, AP_OSD_Screen, AP_OSD_Setting),
     729             : 
     730             : #if HAL_OSD_SIDEBAR_ENABLE || HAL_MSP_ENABLED
     731             :     // @Param: SIDEBARS_EN
     732             :     // @DisplayName: SIDEBARS_EN
     733             :     // @Description: Displays artificial horizon side bars
     734             :     // @Values: 0:Disabled,1:Enabled
     735             : 
     736             :     // @Param: SIDEBARS_X
     737             :     // @DisplayName: SIDEBARS_X
     738             :     // @Description: Horizontal position on screen
     739             :     // @Range: 0 59
     740             : 
     741             :     // @Param: SIDEBARS_Y
     742             :     // @DisplayName: SIDEBARS_Y
     743             :     // @Description: Vertical position on screen
     744             :     // @Range: 0 21
     745             :     AP_SUBGROUPINFO(sidebars, "SIDEBARS", 44, AP_OSD_Screen, AP_OSD_Setting),
     746             : #endif
     747             : 
     748             : #if HAL_MSP_ENABLED
     749             :     // @Param: CRSSHAIR_EN
     750             :     // @DisplayName: CRSSHAIR_EN
     751             :     // @Description: Displays artificial horizon crosshair (MSP OSD only)
     752             :     // @Values: 0:Disabled,1:Enabled
     753             : 
     754             :     // @Param: CRSSHAIR_X
     755             :     // @DisplayName: CRSSHAIR_X
     756             :     // @Description: Horizontal position on screen (MSP OSD only)
     757             :     // @Range: 0 59
     758             : 
     759             :     // @Param: CRSSHAIR_Y
     760             :     // @DisplayName: CRSSHAIR_Y
     761             :     // @Description: Vertical position on screen (MSP OSD only)
     762             :     // @Range: 0 21
     763             :     AP_SUBGROUPINFO(crosshair, "CRSSHAIR", 45, AP_OSD_Screen, AP_OSD_Setting),
     764             : 
     765             :     // @Param: HOMEDIST_EN
     766             :     // @DisplayName: HOMEDIST_EN
     767             :     // @Description: Displays distance from HOME (MSP OSD only)
     768             :     // @Values: 0:Disabled,1:Enabled
     769             : 
     770             :     // @Param: HOMEDIST_X
     771             :     // @DisplayName: HOMEDIST_X
     772             :     // @Description: Horizontal position on screen (MSP OSD only)
     773             :     // @Range: 0 59
     774             : 
     775             :     // @Param: HOMEDIST_Y
     776             :     // @DisplayName: HOMEDIST_Y
     777             :     // @Description: Vertical position on screen (MSP OSD only)
     778             :     // @Range: 0 21
     779             :     AP_SUBGROUPINFO(home_dist, "HOMEDIST", 46, AP_OSD_Screen, AP_OSD_Setting),
     780             : 
     781             :     // @Param: HOMEDIR_EN
     782             :     // @DisplayName: HOMEDIR_EN
     783             :     // @Description: Displays relative direction to HOME (MSP OSD only)
     784             :     // @Values: 0:Disabled,1:Enabled
     785             : 
     786             :     // @Param: HOMEDIR_X
     787             :     // @DisplayName: HOMEDIR_X
     788             :     // @Description: Horizontal position on screen
     789             :     // @Range: 0 59
     790             : 
     791             :     // @Param: HOMEDIR_Y
     792             :     // @DisplayName: HOMEDIR_Y
     793             :     // @Description: Vertical position on screen
     794             :     // @Range: 0 21
     795             :     AP_SUBGROUPINFO(home_dir, "HOMEDIR", 47, AP_OSD_Screen, AP_OSD_Setting),
     796             : 
     797             :     // @Param: POWER_EN
     798             :     // @DisplayName: POWER_EN
     799             :     // @Description: Displays power (MSP OSD only)
     800             :     // @Values: 0:Disabled,1:Enabled
     801             : 
     802             :     // @Param: POWER_X
     803             :     // @DisplayName: POWER_X
     804             :     // @Description: Horizontal position on screen
     805             :     // @Range: 0 59
     806             : 
     807             :     // @Param: POWER_Y
     808             :     // @DisplayName: POWER_Y
     809             :     // @Description: Vertical position on screen
     810             :     // @Range: 0 21
     811             :     AP_SUBGROUPINFO(power, "POWER", 48, AP_OSD_Screen, AP_OSD_Setting),
     812             : 
     813             :     // @Param: CELLVOLT_EN
     814             :     // @DisplayName: CELL_VOLT_EN
     815             :     // @Description: Displays average cell voltage (MSP OSD only)
     816             :     // @Values: 0:Disabled,1:Enabled
     817             : 
     818             :     // @Param: CELLVOLT_X
     819             :     // @DisplayName: CELL_VOLT_X
     820             :     // @Description: Horizontal position on screen
     821             :     // @Range: 0 59
     822             : 
     823             :     // @Param: CELLVOLT_Y
     824             :     // @DisplayName: CELL_VOLT_Y
     825             :     // @Description: Vertical position on screen
     826             :     // @Range: 0 21
     827             :     AP_SUBGROUPINFO(cell_volt, "CELLVOLT", 49, AP_OSD_Screen, AP_OSD_Setting),
     828             : 
     829             :     // @Param: BATTBAR_EN
     830             :     // @DisplayName: BATT_BAR_EN
     831             :     // @Description: Displays battery usage bar (MSP OSD only)
     832             :     // @Values: 0:Disabled,1:Enabled
     833             : 
     834             :     // @Param: BATTBAR_X
     835             :     // @DisplayName: BATT_BAR_X
     836             :     // @Description: Horizontal position on screen
     837             :     // @Range: 0 59
     838             : 
     839             :     // @Param: BATTBAR_Y
     840             :     // @DisplayName: BATT_BAR_Y
     841             :     // @Description: Vertical position on screen
     842             :     // @Range: 0 21
     843             :     AP_SUBGROUPINFO(batt_bar, "BATTBAR", 50, AP_OSD_Screen, AP_OSD_Setting),
     844             : 
     845             :     // @Param: ARMING_EN
     846             :     // @DisplayName: ARMING_EN
     847             :     // @Description: Displays arming status (MSP OSD only)
     848             :     // @Values: 0:Disabled,1:Enabled
     849             : 
     850             :     // @Param: ARMING_X
     851             :     // @DisplayName: ARMING_X
     852             :     // @Description: Horizontal position on screen
     853             :     // @Range: 0 59
     854             : 
     855             :     // @Param: ARMING_Y
     856             :     // @DisplayName: ARMING_Y
     857             :     // @Description: Vertical position on screen
     858             :     // @Range: 0 21
     859             :     AP_SUBGROUPINFO(arming, "ARMING", 51, AP_OSD_Screen, AP_OSD_Setting),
     860             : #endif //HAL_MSP_ENABLED
     861             : 
     862             : #if HAL_PLUSCODE_ENABLE
     863             :     // @Param: PLUSCODE_EN
     864             :     // @DisplayName: PLUSCODE_EN
     865             :     // @Description: Displays pluscode (OLC) element
     866             :     // @Values: 0:Disabled,1:Enabled
     867             : 
     868             :     // @Param: PLUSCODE_X
     869             :     // @DisplayName: PLUSCODE_X
     870             :     // @Description: Horizontal position on screen
     871             :     // @Range: 0 59
     872             : 
     873             :     // @Param: PLUSCODE_Y
     874             :     // @DisplayName: PLUSCODE_Y
     875             :     // @Description: Vertical position on screen
     876             :     // @Range: 0 21
     877             :     AP_SUBGROUPINFO(pluscode, "PLUSCODE", 52, AP_OSD_Screen, AP_OSD_Setting),
     878             : #endif
     879             : 
     880             : #if AP_OSD_CALLSIGN_FROM_SD_ENABLED
     881             :     // @Param: CALLSIGN_EN
     882             :     // @DisplayName: CALLSIGN_EN
     883             :     // @Description: Displays callsign from callsign.txt on microSD card
     884             :     // @Values: 0:Disabled,1:Enabled
     885             : 
     886             :     // @Param: CALLSIGN_X
     887             :     // @DisplayName: CALLSIGN_X
     888             :     // @Description: Horizontal position on screen
     889             :     // @Range: 0 59
     890             : 
     891             :     // @Param: CALLSIGN_Y
     892             :     // @DisplayName: CALLSIGN_Y
     893             :     // @Description: Vertical position on screen
     894             :     // @Range: 0 21
     895             :     AP_SUBGROUPINFO(callsign, "CALLSIGN", 53, AP_OSD_Screen, AP_OSD_Setting),
     896             : #endif
     897             : 
     898             :     // @Param: CURRENT2_EN
     899             :     // @DisplayName: CURRENT2_EN
     900             :     // @Description: Displays 2nd battery current
     901             :     // @Values: 0:Disabled,1:Enabled
     902             : 
     903             :     // @Param: CURRENT2_X
     904             :     // @DisplayName: CURRENT2_X
     905             :     // @Description: Horizontal position on screen
     906             :     // @Range: 0 59
     907             : 
     908             :     // @Param: CURRENT2_Y
     909             :     // @DisplayName: CURRENT2_Y
     910             :     // @Description: Vertical position on screen
     911             :     // @Range: 0 21
     912             :     AP_SUBGROUPINFO(current2, "CURRENT2", 54, AP_OSD_Screen, AP_OSD_Setting),
     913             : 
     914             : #if AP_VIDEOTX_ENABLED
     915             :     // @Param: VTX_PWR_EN
     916             :     // @DisplayName: VTX_PWR_EN
     917             :     // @Description: Displays VTX Power
     918             :     // @Values: 0:Disabled,1:Enabled
     919             : 
     920             :     // @Param: VTX_PWR_X
     921             :     // @DisplayName: VTX_PWR_X
     922             :     // @Description: Horizontal position on screen
     923             :     // @Range: 0 59
     924             : 
     925             :     // @Param: VTX_PWR_Y
     926             :     // @DisplayName: VTX_PWR_Y
     927             :     // @Description: Vertical position on screen
     928             :     // @Range: 0 21
     929             :     AP_SUBGROUPINFO(vtx_power, "VTX_PWR", 55, AP_OSD_Screen, AP_OSD_Setting),
     930             : #endif  // AP_VIDEOTX_ENABLED
     931             : 
     932             : #if AP_TERRAIN_AVAILABLE
     933             :     // @Param: TER_HGT_EN
     934             :     // @DisplayName: TER_HGT_EN
     935             :     // @Description: Displays Height above terrain
     936             :     // @Values: 0:Disabled,1:Enabled
     937             : 
     938             :     // @Param: TER_HGT_X
     939             :     // @DisplayName: TER_HGT_X
     940             :     // @Description: Horizontal position on screen
     941             :     // @Range: 0 59
     942             : 
     943             :     // @Param: TER_HGT_Y
     944             :     // @DisplayName: TER_HGT_Y
     945             :     // @Description: Vertical position on screen
     946             :     // @Range: 0 21
     947             :     AP_SUBGROUPINFO(hgt_abvterr, "TER_HGT", 56, AP_OSD_Screen, AP_OSD_Setting),
     948             : #endif
     949             : 
     950             :     // @Param: AVGCELLV_EN
     951             :     // @DisplayName: AVGCELLV_EN
     952             :     // @Description: Displays average cell voltage. WARNING: this can be inaccurate if the cell count is not detected or set properly. If the  the battery is far from fully charged the detected cell count might not be accurate if auto cell count detection is used (OSD_CELL_COUNT=0).
     953             :     // @Values: 0:Disabled,1:Enabled
     954             : 
     955             :     // @Param: AVGCELLV_X
     956             :     // @DisplayName: AVGCELLV_X
     957             :     // @Description: Horizontal position on screen
     958             :     // @Range: 0 59
     959             : 
     960             :     // @Param: AVGCELLV_Y
     961             :     // @DisplayName: AVGCELLV_Y
     962             :     // @Description: Vertical position on screen
     963             :     // @Range: 0 21
     964             :     AP_SUBGROUPINFO(avgcellvolt, "AVGCELLV", 57, AP_OSD_Screen, AP_OSD_Setting),
     965             : 
     966             :     // @Param: RESTVOLT_EN
     967             :     // @DisplayName: RESTVOLT_EN
     968             :     // @Description: Displays main battery resting voltage
     969             :     // @Values: 0:Disabled,1:Enabled
     970             : 
     971             :     // @Param: RESTVOLT_X
     972             :     // @DisplayName: RESTVOLT_X
     973             :     // @Description: Horizontal position on screen
     974             :     // @Range: 0 59
     975             : 
     976             :     // @Param: RESTVOLT_Y
     977             :     // @DisplayName: RESTVOLT_Y
     978             :     // @Description: Vertical position on screen
     979             :     // @Range: 0 21
     980             :     AP_SUBGROUPINFO(restvolt, "RESTVOLT", 58, AP_OSD_Screen, AP_OSD_Setting),
     981             : 
     982             :     // @Param: FENCE_EN
     983             :     // @DisplayName: FENCE_EN
     984             :     // @Description: Displays indication of fence enable and breach
     985             :     // @Values: 0:Disabled,1:Enabled
     986             : 
     987             :     // @Param: FENCE_X
     988             :     // @DisplayName: FENCE_X
     989             :     // @Description: Horizontal position on screen
     990             :     // @Range: 0 59
     991             : 
     992             :     // @Param: FENCE_Y
     993             :     // @DisplayName: FENCE_Y
     994             :     // @Description: Vertical position on screen
     995             :     // @Range: 0 21
     996             :     AP_SUBGROUPINFO(fence, "FENCE", 59, AP_OSD_Screen, AP_OSD_Setting),
     997             : 
     998             :     // @Param: RNGF_EN
     999             :     // @DisplayName: RNGF_EN
    1000             :     // @Description: Displays a rangefinder's distance in cm
    1001             :     // @Values: 0:Disabled,1:Enabled
    1002             : 
    1003             :     // @Param: RNGF_X
    1004             :     // @DisplayName: RNGF_X
    1005             :     // @Description: Horizontal position on screen
    1006             :     // @Range: 0 59
    1007             : 
    1008             :     // @Param: RNGF_Y
    1009             :     // @DisplayName: RNGF_Y
    1010             :     // @Description: Vertical position on screen
    1011             :     // @Range: 0 21
    1012             :     AP_SUBGROUPINFO(rngf, "RNGF", 60, AP_OSD_Screen, AP_OSD_Setting),
    1013             : 
    1014             :     // @Param: ACRVOLT_EN
    1015             :     // @DisplayName: ACRVOLT_EN
    1016             :     // @Description: Displays resting voltage for the average cell. WARNING: this can be inaccurate if the cell count is not detected or set properly. If the  the battery is far from fully charged the detected cell count might not be accurate if auto cell count detection is used (OSD_CELL_COUNT=0).
    1017             :     // @Values: 0:Disabled,1:Enabled
    1018             : 
    1019             :     // @Param: ACRVOLT_X
    1020             :     // @DisplayName: ACRVOLT_X
    1021             :     // @Description: Horizontal position on screen
    1022             :     // @Range: 0 59
    1023             : 
    1024             :     // @Param: ACRVOLT_Y
    1025             :     // @DisplayName: ACRVOLT_Y
    1026             :     // @Description: Vertical position on screen
    1027             :     // @Range: 0 21
    1028             :     AP_SUBGROUPINFO(avgcellrestvolt, "ACRVOLT", 61, AP_OSD_Screen, AP_OSD_Setting),
    1029             : 
    1030             : #if AP_RPM_ENABLED
    1031             :         // @Param: RPM_EN
    1032             :         // @DisplayName: RPM_EN
    1033             :         // @Description: Displays main rotor revs/min
    1034             :         // @Values: 0:Disabled,1:Enabled
    1035             : 
    1036             :         // @Param: RPM_X
    1037             :         // @DisplayName: RPM_X
    1038             :         // @Description: Horizontal position on screen
    1039             :         // @Range: 0 29
    1040             : 
    1041             :         // @Param: RPM_Y
    1042             :         // @DisplayName: RPM_Y
    1043             :         // @Description: Vertical position on screen
    1044             :         // @Range: 0 15
    1045             :         AP_SUBGROUPINFO(rrpm, "RPM", 62, AP_OSD_Screen, AP_OSD_Setting),
    1046             : #endif
    1047             : 
    1048             :     AP_GROUPEND
    1049             : };
    1050             : 
    1051             : const AP_Param::GroupInfo AP_OSD_Screen::var_info2[] = {
    1052             :     // duplicate of OSDn_ENABLE to ensure params are hidden when not enabled
    1053             :     AP_GROUPINFO_FLAGS("ENABLE", 2, AP_OSD_Screen, enabled, 0, AP_PARAM_FLAG_ENABLE | AP_PARAM_FLAG_HIDDEN),
    1054             : 
    1055             :     // @Param: LINK_Q_EN
    1056             :     // @DisplayName: LINK_Q_EN
    1057             :     // @Description: Displays Receiver link quality
    1058             :     // @Values: 0:Disabled,1:Enabled
    1059             : 
    1060             :     // @Param: LINK_Q_X
    1061             :     // @DisplayName: LINK_Q_X
    1062             :     // @Description: Horizontal position on screen
    1063             :     // @Range: 0 59
    1064             : 
    1065             :     // @Param: LINK_Q_Y
    1066             :     // @DisplayName: LINK_Q_Y
    1067             :     // @Description: Vertical position on screen
    1068             :     // @Range: 0 21
    1069             :     AP_SUBGROUPINFO(link_quality, "LINK_Q", 1, AP_OSD_Screen, AP_OSD_Setting),
    1070             : 
    1071             : #if HAL_WITH_MSP_DISPLAYPORT
    1072             :     // @Param: TXT_RES
    1073             :     // @DisplayName: Sets the overlay text resolution (MSP DisplayPort only)
    1074             :     // @Description: Sets the overlay text resolution for this screen to either SD 30x16 or HD 50x18/60x22 (MSP DisplayPort only)
    1075             :     // @Values: 0:30x16,1:50x18,2:60x22
    1076             :     // @User: Standard
    1077             :     AP_GROUPINFO("TXT_RES", 3, AP_OSD_Screen, txt_resolution, 0),
    1078             : 
    1079             :     // @Param: FONT
    1080             :     // @DisplayName: Sets the font index for this screen (MSP DisplayPort only)
    1081             :     // @Description: Sets the font index for this screen (MSP DisplayPort only)
    1082             :     // @Range: 0 21
    1083             :     // @User: Standard
    1084             :     AP_GROUPINFO("FONT", 4, AP_OSD_Screen, font_index, 0),
    1085             : #endif
    1086             : 
    1087             : #if AP_OSD_EXTENDED_LNK_STATS
    1088             :     // @Param: RC_PWR_EN
    1089             :     // @DisplayName: RC_PWR_EN
    1090             :     // @Description: Displays the RC link transmit (TX) power in mW or W, depending on level
    1091             :     // @Values: 0:Disabled,1:Enabled
    1092             : 
    1093             :     // @Param: RC_PWR_X
    1094             :     // @DisplayName: RC_PWR_X
    1095             :     // @Description: Horizontal position on screen
    1096             :     // @Range: 0 59
    1097             : 
    1098             :     // @Param: RC_PWR_Y
    1099             :     // @DisplayName: RC_PWR_Y
    1100             :     // @Description: Vertical position on screen
    1101             :     // @Range: 0 21
    1102             :     AP_SUBGROUPINFO(rc_tx_power, "RC_PWR", 5, AP_OSD_Screen, AP_OSD_Setting),
    1103             : 
    1104             :     // @Param: RSSIDBM_EN
    1105             :     // @DisplayName: RSSIDBM_EN
    1106             :     // @Description: Displays RC link signal strength in dBm
    1107             :     // @Values: 0:Disabled,1:Enabled
    1108             : 
    1109             :     // @Param: RSSIDBM_X
    1110             :     // @DisplayName: RSSIDBM_X
    1111             :     // @Description: Horizontal position on screen
    1112             :     // @Range: 0 59
    1113             : 
    1114             :     // @Param: RSSIDBM_Y
    1115             :     // @DisplayName: RSSIDBM_Y
    1116             :     // @Description: Vertical position on screen
    1117             :     // @Range: 0 21
    1118             :     AP_SUBGROUPINFO(rc_rssi_dbm, "RSSIDBM", 6, AP_OSD_Screen, AP_OSD_Setting),
    1119             : 
    1120             :     // @Param: RC_SNR_EN
    1121             :     // @DisplayName: RC_SNR_EN
    1122             :     // @Description: Displays RC link signal to noise ratio in dB
    1123             :     // @Values: 0:Disabled,1:Enabled
    1124             : 
    1125             :     // @Param: RC_SNR_X
    1126             :     // @DisplayName: RC_SNR_X
    1127             :     // @Description: Horizontal position on screen
    1128             :     // @Range: 0 59
    1129             : 
    1130             :     // @Param: RC_SNR_Y
    1131             :     // @DisplayName: RC_SNR_Y
    1132             :     // @Description: Vertical position on screen
    1133             :     // @Range: 0 21
    1134             :     AP_SUBGROUPINFO(rc_snr, "RC_SNR", 7, AP_OSD_Screen, AP_OSD_Setting),
    1135             : 
    1136             :     // @Param: RC_ANT_EN
    1137             :     // @DisplayName: RC_ANT_EN
    1138             :     // @Description: Displays the current RC link active antenna
    1139             :     // @Values: 0:Disabled,1:Enabled
    1140             : 
    1141             :     // @Param: RC_ANT_X
    1142             :     // @DisplayName: RC_ANT_X
    1143             :     // @Description: Horizontal position on screen
    1144             :     // @Range: 0 59
    1145             : 
    1146             :     // @Param: RC_ANT_Y
    1147             :     // @DisplayName: RC_ANT_Y
    1148             :     // @Description: Vertical position on screen
    1149             :     // @Range: 0 21
    1150             :     AP_SUBGROUPINFO(rc_active_antenna, "RC_ANT", 8, AP_OSD_Screen, AP_OSD_Setting),
    1151             : 
    1152             :     // @Param: RC_LQ_EN
    1153             :     // @DisplayName: RC_LQ_EN
    1154             :     // @Description: Displays the RC link quality (uplink, 0 to 100%) and also RF mode if bit 7 of OSD_OPTIONS is set
    1155             :     // @Values: 0:Disabled,1:Enabled
    1156             : 
    1157             :     // @Param: RC_LQ_X
    1158             :     // @DisplayName: RC_LQ_X
    1159             :     // @Description: Horizontal position on screen
    1160             :     // @Range: 0 59
    1161             : 
    1162             :     // @Param: RC_LQ_Y
    1163             :     // @DisplayName: RC_LQ_Y
    1164             :     // @Description: Vertical position on screen
    1165             :     // @Range: 0 21
    1166             :     AP_SUBGROUPINFO(rc_lq, "RC_LQ", 9, AP_OSD_Screen, AP_OSD_Setting),
    1167             : #endif
    1168             : 
    1169             : #if HAL_WITH_ESC_TELEM
    1170             :     // @Param: ESC_IDX
    1171             :     // @DisplayName: ESC_IDX
    1172             :     // @Description: Index of the ESC to use for displaying ESC information. 0 means use the ESC with the highest value.
    1173             :     // @Range: 0 32
    1174             :     AP_GROUPINFO("ESC_IDX", 10, AP_OSD_Screen, esc_index, 0),
    1175             : #endif
    1176             : 
    1177             :     AP_GROUPEND
    1178             : };
    1179             : 
    1180             : 
    1181             : uint8_t AP_OSD_AbstractScreen::symbols_lookup_table[AP_OSD_NUM_SYMBOLS];
    1182             : 
    1183             : // Symbol indexes to acces _symbols[index][set]
    1184             : #define SYM_M 0
    1185             : #define SYM_KM 1
    1186             : #define SYM_FT 2
    1187             : #define SYM_MI 3
    1188             : #define SYM_ALT_M 4
    1189             : #define SYM_ALT_FT 5
    1190             : #define SYM_BATT_FULL 6
    1191             : #define SYM_RSSI 7
    1192             : 
    1193             : #define SYM_VOLT 8
    1194             : #define SYM_AMP 9
    1195             : #define SYM_MAH 10
    1196             : #define SYM_MS 11
    1197             : #define SYM_FS 12
    1198             : #define SYM_KMH 13
    1199             : #define SYM_MPH 14
    1200             : #define SYM_DEGR 15
    1201             : #define SYM_PCNT 16
    1202             : #define SYM_RPM 17
    1203             : #define SYM_ASPD 18
    1204             : #define SYM_GSPD 19
    1205             : #define SYM_WSPD 20
    1206             : #define SYM_VSPD 21
    1207             : #define SYM_WPNO 22
    1208             : #define SYM_WPDIR 23
    1209             : #define SYM_WPDST 24
    1210             : #define SYM_FTMIN 25
    1211             : #define SYM_FTSEC 26
    1212             : 
    1213             : #define SYM_SAT_L 27
    1214             : #define SYM_SAT_R 28
    1215             : #define SYM_HDOP_L 29
    1216             : #define SYM_HDOP_R 30
    1217             : 
    1218             : #define SYM_HOME 31
    1219             : #define SYM_WIND 32
    1220             : 
    1221             : #define SYM_ARROW_START 33
    1222             : #define SYM_ARROW_COUNT 34
    1223             : #define SYM_AH_H_START 35
    1224             : #define SYM_AH_H_COUNT 36
    1225             : 
    1226             : #define SYM_AH_V_START 37
    1227             : #define SYM_AH_V_COUNT 38
    1228             : 
    1229             : #define SYM_AH_CENTER_LINE_LEFT 39
    1230             : #define SYM_AH_CENTER_LINE_RIGHT 40
    1231             : #define SYM_AH_CENTER 41
    1232             : 
    1233             : #define SYM_HEADING_N 42
    1234             : #define SYM_HEADING_S 43
    1235             : #define SYM_HEADING_E 44
    1236             : #define SYM_HEADING_W 45
    1237             : #define SYM_HEADING_DIVIDED_LINE 46
    1238             : #define SYM_HEADING_LINE 47
    1239             : 
    1240             : #define SYM_UP_UP 48
    1241             : #define SYM_UP 49
    1242             : #define SYM_DOWN 50
    1243             : #define SYM_DOWN_DOWN 51
    1244             : 
    1245             : #define SYM_DEGREES_C 52
    1246             : #define SYM_DEGREES_F 53
    1247             : #define SYM_GPS_LAT 54
    1248             : #define SYM_GPS_LONG 55
    1249             : #define SYM_ARMED 56
    1250             : #define SYM_DISARMED 57
    1251             : #define SYM_ROLL0 58
    1252             : #define SYM_ROLLR 59
    1253             : #define SYM_ROLLL 60
    1254             : #define SYM_PTCH0 61
    1255             : #define SYM_PTCHUP 62
    1256             : #define SYM_PTCHDWN 63
    1257             : #define SYM_XERR 64
    1258             : #define SYM_KN 65
    1259             : #define SYM_NM 66
    1260             : #define SYM_DIST 67
    1261             : #define SYM_FLY 68
    1262             : #define SYM_EFF 69
    1263             : #define SYM_AH 70
    1264             : #define SYM_MW 71
    1265             : #define SYM_CLK 72
    1266             : #define SYM_KILO 73
    1267             : #define SYM_TERALT 74
    1268             : #define SYM_FENCE_ENABLED 75
    1269             : #define SYM_FENCE_DISABLED 76
    1270             : #define SYM_RNGFD 77
    1271             : #define SYM_LQ 78
    1272             : 
    1273             : #define SYM_SIDEBAR_R_ARROW 79
    1274             : #define SYM_SIDEBAR_L_ARROW 80
    1275             : #define SYM_SIDEBAR_A 81
    1276             : #define SYM_SIDEBAR_B 82
    1277             : #define SYM_SIDEBAR_C 83
    1278             : #define SYM_SIDEBAR_D 84
    1279             : #define SYM_SIDEBAR_E 85
    1280             : #define SYM_SIDEBAR_F 86
    1281             : #define SYM_SIDEBAR_G 87
    1282             : #define SYM_SIDEBAR_H 88
    1283             : #define SYM_SIDEBAR_I 89
    1284             : #define SYM_SIDEBAR_J 90
    1285             : 
    1286             : #define SYM_WATT 91
    1287             : #define SYM_WH 92
    1288             : #define SYM_DB 93
    1289             : #define SYM_DBM 94
    1290             : #define SYM_SNR 95
    1291             : #define SYM_ANT 96
    1292             : #define SYM_ARROW_RIGHT 97
    1293             : #define SYM_ARROW_LEFT 98
    1294             : 
    1295             : #define SYM_G 99
    1296             : #define SYM_BATT_UNKNOWN 100
    1297             : #define SYM_ROLL 101
    1298             : #define SYM_PITCH 102
    1299             : #define SYM_DPS 103
    1300             : #define SYM_HEADING 104
    1301             : #define SYM_RADIUS 105
    1302             : #define SYM_FLAP 106
    1303             : 
    1304             : #define SYMBOL(n) AP_OSD_AbstractScreen::symbols_lookup_table[n]
    1305             : 
    1306             : // constructor
    1307        8244 : AP_OSD_Screen::AP_OSD_Screen()
    1308             : {
    1309        8244 :     AP_Param::setup_object_defaults(this, var_info);
    1310        8244 :     AP_Param::setup_object_defaults(this, var_info2);
    1311        8244 : }
    1312             : 
    1313         548 : void AP_OSD_AbstractScreen::set_backend(AP_OSD_Backend *_backend)
    1314             : {
    1315         548 :     backend = _backend;
    1316         548 :     osd = _backend->get_osd();
    1317         548 : };
    1318             : 
    1319        1934 : bool AP_OSD_AbstractScreen::check_option(uint32_t option)
    1320             : {
    1321        1934 :     return osd?(osd->options & option) != 0 : false;
    1322             : }
    1323             : 
    1324             : /*
    1325             :   get the right units icon given a unit
    1326             :  */
    1327        1934 : char AP_OSD_AbstractScreen::u_icon(enum unit_type unit)
    1328             : {
    1329             :     static const uint8_t icons_metric[UNIT_TYPE_LAST] {
    1330             :         SYM_ALT_M,    //ALTITUDE
    1331             :         SYM_KMH,      //SPEED
    1332             :         SYM_MS,       //VSPEED
    1333             :         SYM_M,        //DISTANCE
    1334             :         SYM_KM,       //DISTANCE_LONG
    1335             :         SYM_DEGREES_C //TEMPERATURE
    1336             :     };
    1337             :     static const uint8_t icons_imperial[UNIT_TYPE_LAST] {
    1338             :         SYM_ALT_FT,   //ALTITUDE
    1339             :         SYM_MPH,      //SPEED
    1340             :         SYM_FS,       //VSPEED
    1341             :         SYM_FT,       //DISTANCE
    1342             :         SYM_MI,       //DISTANCE_LONG
    1343             :         SYM_DEGREES_F //TEMPERATURE
    1344             :     };
    1345             :     static const uint8_t icons_SI[UNIT_TYPE_LAST] {
    1346             :         SYM_ALT_M,    //ALTITUDE
    1347             :         SYM_MS,       //SPEED
    1348             :         SYM_MS,       //VSPEED
    1349             :         SYM_M,        //DISTANCE
    1350             :         SYM_KM,       //DISTANCE_LONG
    1351             :         SYM_DEGREES_C //TEMPERATURE
    1352             :     };
    1353             :     static const uint8_t icons_aviation[UNIT_TYPE_LAST] {
    1354             :         SYM_ALT_FT,   //ALTITUDE Ft
    1355             :         SYM_KN,       //SPEED Knots
    1356             :         SYM_FTMIN,    //VSPEED
    1357             :         SYM_FT,       //DISTANCE
    1358             :         SYM_NM,       //DISTANCE_LONG Nm
    1359             :         SYM_DEGREES_C //TEMPERATURE
    1360             :     };
    1361             :     static const uint8_t* icons[AP_OSD::UNITS_LAST] = {
    1362             :         icons_metric,
    1363             :         icons_imperial,
    1364             :         icons_SI,
    1365             :         icons_aviation,
    1366             :     };
    1367        1934 :     return (char)SYMBOL(icons[constrain_int16(osd->units, 0, AP_OSD::UNITS_LAST-1)][unit]);
    1368             : }
    1369             : 
    1370             : /*
    1371             :   scale a value for the user selected units
    1372             :  */
    1373        2482 : float AP_OSD_AbstractScreen::u_scale(enum unit_type unit, float value)
    1374             : {
    1375             :     static const float scale_metric[UNIT_TYPE_LAST] = {
    1376             :         1.0,       //ALTITUDE m
    1377             :         3.6,       //SPEED km/hr
    1378             :         1.0,       //VSPEED m/s
    1379             :         1.0,       //DISTANCE m
    1380             :         1.0/1000,  //DISTANCE_LONG km
    1381             :         1.0,       //TEMPERATURE C
    1382             :     };
    1383             :     static const float scale_imperial[UNIT_TYPE_LAST] = {
    1384             :         3.28084,     //ALTITUDE ft
    1385             :         2.23694,     //SPEED mph
    1386             :         3.28084,     //VSPEED ft/s
    1387             :         3.28084,     //DISTANCE ft
    1388             :         1.0/1609.34, //DISTANCE_LONG miles
    1389             :         1.8,         //TEMPERATURE F
    1390             :     };
    1391             :     static const float offset_imperial[UNIT_TYPE_LAST] = {
    1392             :         0.0,          //ALTITUDE
    1393             :         0.0,          //SPEED
    1394             :         0.0,          //VSPEED
    1395             :         0.0,          //DISTANCE
    1396             :         0.0,          //DISTANCE_LONG
    1397             :         32.0,         //TEMPERATURE F
    1398             :     };
    1399             :     static const float scale_SI[UNIT_TYPE_LAST] = {
    1400             :         1.0,       //ALTITUDE m
    1401             :         1.0,       //SPEED m/s
    1402             :         1.0,       //VSPEED m/s
    1403             :         1.0,       //DISTANCE m
    1404             :         1.0/1000,  //DISTANCE_LONG km
    1405             :         1.0,       //TEMPERATURE C
    1406             :     };
    1407             :     static const float scale_aviation[UNIT_TYPE_LAST] = {
    1408             :         3.28084,   //ALTITUDE Ft
    1409             :         1.94384,   //SPEED Knots
    1410             :         196.85,    //VSPEED ft/min
    1411             :         3.28084,   //DISTANCE ft
    1412             :         0.000539957,  //DISTANCE_LONG Nm
    1413             :         1.0,       //TEMPERATURE C
    1414             :     };
    1415             :     static const float *scale[AP_OSD::UNITS_LAST] = {
    1416             :         scale_metric,
    1417             :         scale_imperial,
    1418             :         scale_SI,
    1419             :         scale_aviation
    1420             :     };
    1421             :     static const float *offsets[AP_OSD::UNITS_LAST] = {
    1422             :         nullptr,
    1423             :         offset_imperial,
    1424             :         nullptr,
    1425             :         nullptr
    1426             :     };
    1427        2482 :     uint8_t units = constrain_int16(osd->units, 0, AP_OSD::UNITS_LAST-1);
    1428        2482 :     return value * scale[units][unit] + (offsets[units]?offsets[units][unit]:0);
    1429             : }
    1430             : 
    1431         838 : char AP_OSD_Screen::get_arrow_font_index(int32_t angle_cd)
    1432             : {
    1433         838 :     uint32_t interval = 36000 / SYMBOL(SYM_ARROW_COUNT);
    1434         838 :     angle_cd = wrap_360_cd(angle_cd);
    1435             :     // if using BF font table must translate arrows
    1436         838 :     if (check_option(AP_OSD::OPTION_BF_ARROWS)) {
    1437           0 :         angle_cd = angle_cd > 18000? 54000 - angle_cd : 18000- angle_cd;
    1438             :     } 
    1439         838 :     return SYMBOL(SYM_ARROW_START) + ((angle_cd + interval / 2) / interval) % SYMBOL(SYM_ARROW_COUNT);
    1440             : }
    1441             : 
    1442         548 : void AP_OSD_Screen::draw_altitude(uint8_t x, uint8_t y)
    1443             : {
    1444             :     float alt;
    1445         548 :     AP_AHRS &ahrs = AP::ahrs();
    1446         548 :     WITH_SEMAPHORE(ahrs.get_semaphore());
    1447         548 :     ahrs.get_relative_position_D_home(alt);
    1448         548 :     alt = -alt;
    1449         548 :     backend->write(x, y, false, "%4d%c", (int)u_scale(ALTITUDE, alt), u_icon(ALTITUDE));
    1450         548 : }
    1451             : 
    1452             : #if AP_BATTERY_ENABLED
    1453         548 : void AP_OSD_Screen::draw_bat_volt(uint8_t instance, VoltageType type, uint8_t x, uint8_t y)
    1454             : {
    1455         548 :     AP_BattMonitor &battery = AP::battery();
    1456         548 :     float v = battery.voltage(instance);
    1457         548 :     float blinkvolt = osd->warn_batvolt;
    1458             :     uint8_t pct;
    1459         548 :     bool show_remaining_pct = battery.capacity_remaining_pct(pct);
    1460         548 :     uint8_t p = (100 - pct) / 16.6;
    1461         548 :     switch (type) {
    1462         548 :     case VoltageType::VOLTAGE: {
    1463         548 :         break;
    1464             :     }
    1465           0 :     case VoltageType::RESTING_VOLTAGE: {
    1466           0 :         v = battery.voltage_resting_estimate(instance);
    1467           0 :         blinkvolt = osd->warn_restvolt;
    1468           0 :         break;
    1469             :     }
    1470           0 :     case VoltageType::RESTING_CELL: { 
    1471           0 :         blinkvolt = osd->warn_avgcellrestvolt;
    1472           0 :         v = battery.voltage_resting_estimate(instance);
    1473             :         FALLTHROUGH;
    1474             :     }
    1475           0 :     case VoltageType::AVG_CELL: {         
    1476           0 :        if (type == VoltageType::AVG_CELL) { //for fallthrough of RESTING_CELL
    1477           0 :             blinkvolt = osd->warn_avgcellvolt;
    1478             :        }
    1479             :        // calculate cell count - WARNING this can be inaccurate if the LIPO/LIION  battery is far from 
    1480             :        // fully charged when attached and is used in this panel
    1481           0 :        osd->max_battery_voltage.set(MAX(osd->max_battery_voltage,v));
    1482           0 :        if (osd->cell_count > 0) {
    1483           0 :            v = v / osd->cell_count;
    1484           0 :        } else if (osd->cell_count < 0) { // user must decide on autodetect cell count or manually entered to display this panel since default is -1
    1485           0 :            backend->write(x,y, false, "%c---%c", SYMBOL(SYM_BATT_FULL) + p, SYMBOL(SYM_VOLT));
    1486          46 :            return;
    1487             :        } else {  // use autodetected cell count
    1488           0 :             v = v /  (uint8_t)(osd->max_battery_voltage * 0.2381 + 1);
    1489             :        }
    1490           0 :        break;
    1491             :     }
    1492             :     }    
    1493         548 :     if (!show_remaining_pct) {
    1494             :         // Do not show battery percentage
    1495          46 :         if (type == VoltageType::RESTING_CELL || type == VoltageType::AVG_CELL) {
    1496           0 :             backend->write(x,y, v < blinkvolt, "%1.2f%c", (double)v, SYMBOL(SYM_VOLT));
    1497             :         } else {
    1498          46 :             backend->write(x,y, v < blinkvolt, "%2.1f%c", (double)v, SYMBOL(SYM_VOLT));
    1499             :         }
    1500          46 :         return;
    1501             :     }
    1502         502 :     if (type == VoltageType::RESTING_CELL || type == VoltageType::AVG_CELL) {
    1503           0 :         backend->write(x,y, v < blinkvolt, "%c%1.2f%c", SYMBOL(SYM_BATT_FULL) + p, (double)v, SYMBOL(SYM_VOLT));
    1504             :     } else {
    1505         502 :         backend->write(x,y, v < blinkvolt, "%c%2.1f%c", SYMBOL(SYM_BATT_FULL) + p, (double)v, SYMBOL(SYM_VOLT));
    1506             :     }
    1507             : }
    1508             : 
    1509         548 : void AP_OSD_Screen::draw_bat_volt(uint8_t x, uint8_t y)
    1510             : {
    1511         548 :     draw_bat_volt(0,VoltageType::VOLTAGE,x,y);
    1512         548 : }
    1513             : 
    1514           0 : void AP_OSD_Screen::draw_avgcellvolt(uint8_t x, uint8_t y)
    1515             : {
    1516           0 :     draw_bat_volt(0,VoltageType::AVG_CELL,x,y);
    1517           0 : }
    1518             : 
    1519           0 : void AP_OSD_Screen::draw_avgcellrestvolt(uint8_t x, uint8_t y)
    1520             : {
    1521           0 :     draw_bat_volt(0,VoltageType::RESTING_CELL,x, y);
    1522           0 : }
    1523             : 
    1524           0 : void AP_OSD_Screen::draw_restvolt(uint8_t x, uint8_t y)
    1525             : {
    1526           0 :     draw_bat_volt(0,VoltageType::RESTING_VOLTAGE,x,y);
    1527           0 : }
    1528             : #endif  // AP_BATTERY_ENABLED
    1529             : 
    1530             : #if AP_RSSI_ENABLED
    1531         548 : void AP_OSD_Screen::draw_rssi(uint8_t x, uint8_t y)
    1532             : {
    1533         548 :     AP_RSSI *ap_rssi = AP_RSSI::get_singleton();
    1534         548 :     if (ap_rssi) {
    1535         548 :         const uint8_t rssiv = ap_rssi->read_receiver_rssi() * 100;
    1536         548 :         backend->write(x, y, rssiv < osd->warn_rssi, "%c%2d", SYMBOL(SYM_RSSI), rssiv);
    1537             :     }
    1538         548 : }
    1539             : 
    1540           0 : void AP_OSD_Screen::draw_link_quality(uint8_t x, uint8_t y)
    1541             : {
    1542           0 :     AP_RSSI *ap_rssi = AP_RSSI::get_singleton();
    1543           0 :     if (ap_rssi) {
    1544           0 :         const int16_t lqv = ap_rssi->read_receiver_link_quality();
    1545           0 :         if (lqv < 0){
    1546           0 :             backend->write(x, y, false, "%c--", SYMBOL(SYM_LQ));
    1547             :         } else {
    1548           0 :             backend->write(x, y, false, "%c%2d", SYMBOL(SYM_LQ), lqv);
    1549             :         }
    1550             :     }
    1551           0 : }
    1552             : #endif  // AP_RSSI_ENABLED
    1553             : 
    1554             : #if AP_BATTERY_ENABLED
    1555         548 : void AP_OSD_Screen::draw_current(uint8_t instance, uint8_t x, uint8_t y)
    1556             : {
    1557             :     float amps;
    1558         548 :     if (!AP::battery().current_amps(amps, instance)) {
    1559           0 :         osd->_stats.avg_current_a = 0;
    1560             :     }
    1561             :     //filter current and display with autoranging for low values
    1562         548 :     osd->_stats.avg_current_a= osd->_stats.avg_current_a + (amps - osd->_stats.avg_current_a) * 0.33;
    1563         548 :     if (osd->_stats.avg_current_a < 10.0) {
    1564         548 :         backend->write(x, y, false, "%2.2f%c", osd->_stats.avg_current_a, SYMBOL(SYM_AMP));
    1565             :     }
    1566             :     else {
    1567           0 :         backend->write(x, y, false, "%2.1f%c", osd->_stats.avg_current_a, SYMBOL(SYM_AMP));
    1568             :     }
    1569         548 : }
    1570             : 
    1571         548 : void AP_OSD_Screen::draw_current(uint8_t x, uint8_t y)
    1572             : {
    1573         548 :     draw_current(0, x, y);
    1574         548 : }
    1575             : #endif
    1576             : 
    1577         548 : void AP_OSD_Screen::draw_fltmode(uint8_t x, uint8_t y)
    1578             : {
    1579         548 :     AP_Notify * notify = AP_Notify::get_singleton();
    1580             :     char arm;
    1581         548 :     if (AP_Notify::flags.armed) {
    1582           0 :         arm = SYMBOL(SYM_ARMED);
    1583             :     } else {
    1584         548 :         arm = SYMBOL(SYM_DISARMED);
    1585             :     }
    1586         548 :     if (notify) {
    1587         548 :         backend->write(x, y, false, "%s%c", notify->get_flight_mode_str(), arm);
    1588             :     }
    1589         548 : }
    1590             : 
    1591         548 : void AP_OSD_Screen::draw_sats(uint8_t x, uint8_t y)
    1592             : {
    1593         548 :     AP_GPS & gps = AP::gps();
    1594         548 :     uint8_t nsat = gps.num_sats();
    1595         548 :     bool flash = (nsat < osd->warn_nsat) || (gps.status() < AP_GPS_FixType::FIX_3D);
    1596         548 :     backend->write(x, y, flash, "%c%c%2u", SYMBOL(SYM_SAT_L), SYMBOL(SYM_SAT_R), nsat);
    1597         548 : }
    1598             : 
    1599             : #if AP_BATTERY_ENABLED
    1600         548 : void AP_OSD_Screen::draw_batused(uint8_t instance, uint8_t x, uint8_t y)
    1601             : {
    1602             :     float mah;
    1603         548 :     if (!AP::battery().consumed_mah(mah, instance)) {
    1604           0 :         mah = 0;
    1605             :     }
    1606         548 :     if (mah <= 9999) {
    1607         548 :         backend->write(x,y, false, "%4d%c", (int)mah, SYMBOL(SYM_MAH));
    1608             :     } else {
    1609           0 :         const float ah = mah * 1e-3f;
    1610           0 :         backend->write(x,y, false, "%2.2f%c", (double)ah, SYMBOL(SYM_AH));
    1611             :     }
    1612         548 : }
    1613             : 
    1614         548 : void AP_OSD_Screen::draw_batused(uint8_t x, uint8_t y)
    1615             : {
    1616         548 :     draw_batused(0, x, y);
    1617         548 : }
    1618             : #endif
    1619             : 
    1620             : //Autoscroll message is the same as in minimosd-extra.
    1621             : //Thanks to night-ghost for the approach.
    1622         548 : void AP_OSD_Screen::draw_message(uint8_t x, uint8_t y)
    1623             : {
    1624         548 :     AP_Notify * notify = AP_Notify::get_singleton();
    1625         548 :     if (notify) {
    1626         548 :         int32_t visible_time = AP_HAL::millis() - notify->get_text_updated_millis();
    1627         548 :         if (visible_time < osd->msgtime_s *1000) {
    1628             :             char buffer[NOTIFY_TEXT_BUFFER_SIZE];
    1629         434 :             strncpy(buffer, notify->get_text(), sizeof(buffer));
    1630         434 :             int16_t len = strnlen(buffer, sizeof(buffer));
    1631             : 
    1632       11073 :             for (int16_t i=0; i<len; i++) {
    1633             :                 //converted to uppercase,
    1634             :                 //because we do not have small letter chars inside used font
    1635       10639 :                 buffer[i] = toupper(buffer[i]);
    1636             :                 //normalize whitespace
    1637       10639 :                 if (isspace(buffer[i])) {
    1638        1384 :                     buffer[i] = ' ';
    1639             :                 }
    1640             :             }
    1641             : 
    1642         434 :             int16_t start_position = 0;
    1643             :             //scroll if required
    1644             :             //scroll pattern: wait, scroll to the left, wait, scroll to the right
    1645         434 :             if (len > message_visible_width) {
    1646          98 :                 int16_t chars_to_scroll = len - message_visible_width;
    1647          98 :                 int16_t total_cycles = 2*message_scroll_delay + 2*chars_to_scroll;
    1648          98 :                 int16_t current_cycle = (visible_time / message_scroll_time_ms) % total_cycles;
    1649             : 
    1650             :                 //calculate scroll start_position
    1651          98 :                 if (current_cycle < total_cycles/2) {
    1652             :                     //move to the left
    1653          91 :                     start_position = current_cycle - message_scroll_delay;
    1654             :                 } else {
    1655             :                     //move to the right
    1656           7 :                     start_position = total_cycles - current_cycle;
    1657             :                 }
    1658          98 :                 start_position = constrain_int16(start_position, 0, chars_to_scroll);
    1659          98 :                 int16_t end_position = start_position + message_visible_width;
    1660             : 
    1661             :                 //ensure array boundaries
    1662          98 :                 start_position = MIN(start_position, int(sizeof(buffer)-1));
    1663          98 :                 end_position = MIN(end_position, int(sizeof(buffer)-1));
    1664             : 
    1665             :                 //trim invisible part
    1666          98 :                 buffer[end_position] = 0;
    1667             :             }
    1668             : 
    1669         434 :             backend->write(x, y, buffer + start_position);
    1670             :         }
    1671             :     }
    1672         548 : }
    1673             : 
    1674             : // draw a arrow at the given angle, and print the given magnitude
    1675         548 : void AP_OSD_Screen::draw_speed(uint8_t x, uint8_t y, float angle_rad, float magnitude)
    1676             : {
    1677         548 :     int32_t angle_cd = rad_to_cd(angle_rad);
    1678         548 :     char arrow = get_arrow_font_index(angle_cd);
    1679         548 :     if (u_scale(SPEED, magnitude) < 9.95) {
    1680         548 :         backend->write(x, y, false, "%c %1.1f%c", arrow, u_scale(SPEED, magnitude), u_icon(SPEED));
    1681             :     } else {
    1682           0 :         backend->write(x, y, false, "%c%3d%c", arrow, (int)roundf(u_scale(SPEED, magnitude)), u_icon(SPEED));
    1683             :     }
    1684         548 : }
    1685             : 
    1686         548 : void AP_OSD_Screen::draw_gspeed(uint8_t x, uint8_t y)
    1687             : {
    1688         548 :     AP_AHRS &ahrs = AP::ahrs();
    1689         548 :     WITH_SEMAPHORE(ahrs.get_semaphore());
    1690         548 :     Vector2f v = ahrs.groundspeed_vector();
    1691         548 :     backend->write(x, y, false, "%c", SYMBOL(SYM_GSPD));
    1692         548 :     float angle = 0;
    1693         548 :     const float length = v.length();
    1694         548 :     if (length > 1.0f) {
    1695             :         float roll_rad, pitch_rad, yaw_rad;
    1696           0 :         AP::vehicle()->get_osd_attitude_rad(roll_rad, pitch_rad, yaw_rad);
    1697           0 :         angle = wrap_2PI(atan2f(v.y, v.x) - yaw_rad);
    1698             :     }
    1699         548 :     draw_speed(x + 1, y, angle, length);
    1700         548 : }
    1701             : 
    1702             : //Thanks to betaflight/inav for simple and clean artificial horizon visual design
    1703         548 : void AP_OSD_Screen::draw_horizon(uint8_t x, uint8_t y)
    1704             : {
    1705         548 :     AP_AHRS &ahrs = AP::ahrs();
    1706         548 :     WITH_SEMAPHORE(ahrs.get_semaphore());
    1707             :     float roll;
    1708             :     float pitch;
    1709             :     float yaw;
    1710         548 :     bool inverted = false;
    1711         548 :     AP::vehicle()->get_osd_attitude_rad(roll, pitch, yaw);
    1712         548 :     pitch *= -1;
    1713             :     // Are we inverted? then flash horizon line
    1714         548 :     if (abs(roll) >= radians(90)) {
    1715           0 :        inverted = true;
    1716             :     }
    1717             :     // Aviation style AH instead of Betaflight FPV style
    1718         548 :     if (inverted && check_option(AP_OSD::OPTION_AVIATION_AH)) {
    1719           0 :         pitch = -pitch;            
    1720             :     }
    1721             :     //inverted roll AH (Russian HUD emulation)
    1722         548 :     if (check_option(AP_OSD::OPTION_INVERTED_AH_ROLL)) {
    1723           0 :         roll = -roll;
    1724             :     }
    1725             : 
    1726         548 :     pitch = constrain_float(pitch, -ah_max_pitch, ah_max_pitch);
    1727         548 :     float ky = sinf(roll);
    1728         548 :     float kx = cosf(roll);
    1729             : 
    1730         548 :     float ratio = backend->get_aspect_ratio_correction();
    1731             : 
    1732         548 :     if (fabsf(ky) < fabsf(kx)) {
    1733        5480 :         for (int dx = -4; dx <= 4; dx++) {
    1734        4932 :             float fy = (ratio * dx) * (ky/kx) + pitch * ah_pitch_rad_to_char + 0.5f;
    1735        4932 :             int dy = floorf(fy);
    1736        4932 :             char c = (fy - dy) * SYMBOL(SYM_AH_H_COUNT);
    1737             :             //chars in font in reversed order
    1738        4932 :             c = SYMBOL(SYM_AH_H_START) + ((SYMBOL(SYM_AH_H_COUNT) - 1) - c);
    1739        4932 :             if (dy >= -4 && dy <= 4) {
    1740        4932 :                 backend->write(x + dx, y - dy, inverted, "%c", c);
    1741             :             }
    1742             :         }
    1743             :     } else {
    1744           0 :         for (int dy=-4; dy<=4; dy++) {
    1745           0 :             float fx = ((dy / ratio) - pitch * ah_pitch_rad_to_char) * (kx/ky) + 0.5f;
    1746           0 :             int dx = floorf(fx);
    1747           0 :             char c = (fx - dx) * SYMBOL(SYM_AH_V_COUNT);
    1748           0 :             c = SYMBOL(SYM_AH_V_START) + c;
    1749           0 :             if (dx >= -4 && dx <=4) {
    1750           0 :                 backend->write(x + dx, y - dy, inverted, "%c", c);
    1751             :             }
    1752             :         }
    1753             :     }
    1754             : 
    1755         548 :     if (!check_option(AP_OSD::OPTION_DISABLE_CROSSHAIR)) {
    1756         548 :         backend->write(x-1,y, false, "%c%c%c", SYMBOL(SYM_AH_CENTER_LINE_LEFT), SYMBOL(SYM_AH_CENTER), SYMBOL(SYM_AH_CENTER_LINE_RIGHT));
    1757             :     }
    1758             : 
    1759         548 : }
    1760             : 
    1761         290 : void AP_OSD_Screen::draw_distance(uint8_t x, uint8_t y, float distance)
    1762             : {
    1763         290 :     char unit_icon = u_icon(DISTANCE);
    1764         290 :     float distance_scaled = u_scale(DISTANCE, distance);
    1765         290 :     const char *fmt = "%4.0f%c";
    1766         290 :     if (distance_scaled > 9999.0f || (osd->units == AP_OSD::UNITS_IMPERIAL && distance_scaled > 5280.0f && (osd->options & AP_OSD::OPTION_IMPERIAL_MILES))) {
    1767           0 :         distance_scaled = u_scale(DISTANCE_LONG, distance);
    1768           0 :         unit_icon= u_icon(DISTANCE_LONG);
    1769             :         //try to pack as many useful info as possible
    1770           0 :         if (distance_scaled<9.0f) {
    1771           0 :             fmt = "%1.3f%c";
    1772           0 :         } else if (distance_scaled < 99.0f) {
    1773           0 :             fmt = "%2.2f%c";
    1774           0 :         } else if (distance_scaled < 999.0f) {
    1775           0 :             fmt = "%3.1f%c";
    1776             :         } else {
    1777           0 :             fmt = "%4.0f%c";
    1778             :         }
    1779         290 :     } else if (distance_scaled < 10.0f) {
    1780         290 :         fmt = "% 3.1f%c";
    1781             :     }
    1782         290 :     backend->write(x, y, false, fmt, (double)distance_scaled, unit_icon);
    1783         290 : }
    1784             : 
    1785         548 : void AP_OSD_Screen::draw_home(uint8_t x, uint8_t y)
    1786             : {
    1787         548 :     AP_AHRS &ahrs = AP::ahrs();
    1788         548 :     WITH_SEMAPHORE(ahrs.get_semaphore());
    1789         548 :     Location loc;
    1790         548 :     if (ahrs.get_location(loc) && ahrs.home_is_set()) {
    1791         290 :         const Location &home_loc = ahrs.get_home();
    1792         290 :         float distance = home_loc.get_distance(loc);
    1793             :         float roll_rad, pitch_rad, yaw_rad;
    1794         290 :         AP::vehicle()->get_osd_attitude_rad(roll_rad, pitch_rad, yaw_rad);
    1795         290 :         int32_t angle_cd = loc.get_bearing_to(home_loc) - rad_to_cd(yaw_rad);
    1796         290 :         if (distance < 2.0f) {
    1797             :             //avoid fast rotating arrow at small distances
    1798         290 :             angle_cd = 0;
    1799             :         }
    1800         290 :         char arrow = get_arrow_font_index(angle_cd);
    1801         290 :         backend->write(x, y, false, "%c%c", SYMBOL(SYM_HOME), arrow);
    1802         290 :         draw_distance(x+2, y, distance);
    1803             :     } else {
    1804         258 :         backend->write(x, y, true, "%c", SYMBOL(SYM_HOME));
    1805             :     }
    1806         548 : }
    1807             : 
    1808         548 : void AP_OSD_Screen::draw_heading(uint8_t x, uint8_t y)
    1809             : {
    1810             :     float roll_rad, pitch_rad, yaw_rad;
    1811         548 :     AP::vehicle()->get_osd_attitude_rad(roll_rad, pitch_rad, yaw_rad);
    1812         548 :     uint16_t yaw = degrees(wrap_2PI(yaw_rad));
    1813         548 :     backend->write(x, y, false, "%3d%c", yaw, SYMBOL(SYM_DEGR));
    1814         548 : }
    1815             : 
    1816             : #if AP_RPM_ENABLED
    1817           0 : void AP_OSD_Screen::draw_rrpm(uint8_t x, uint8_t y)
    1818             : {
    1819             :     float _rrpm;
    1820           0 :     const AP_RPM *rpm = AP_RPM::get_singleton();
    1821           0 :     if (rpm != nullptr) {
    1822           0 :             if (!rpm->get_rpm(0, _rrpm)) {
    1823             :                 // No valid RPM data
    1824           0 :                 _rrpm = -1;
    1825             :             }
    1826             :         } else {
    1827             :             // No RPM because pointer is null
    1828           0 :             _rrpm = -1;
    1829             :         }
    1830           0 :     int r_rpm = static_cast<int>(_rrpm);
    1831           0 :     backend->write(x, y, false, "%4d%c", (int)r_rpm, SYMBOL(SYM_RPM));
    1832           0 : }
    1833             : #endif
    1834             : 
    1835         548 : void AP_OSD_Screen::draw_throttle(uint8_t x, uint8_t y)
    1836             : {
    1837         548 :     backend->write(x, y, false, "%3d%c", gcs().get_hud_throttle(), SYMBOL(SYM_PCNT));
    1838         548 : }
    1839             : 
    1840             : #if HAL_OSD_SIDEBAR_ENABLE
    1841             : 
    1842           0 : void AP_OSD_Screen::draw_sidebars(uint8_t x, uint8_t y)
    1843             : {
    1844           0 :     const int8_t total_sectors = 18;
    1845             :     static const uint8_t sidebar_sectors[total_sectors] = {
    1846             :         SYM_SIDEBAR_A,
    1847             :         SYM_SIDEBAR_B,
    1848             :         SYM_SIDEBAR_C,
    1849             :         SYM_SIDEBAR_D,
    1850             :         SYM_SIDEBAR_E,
    1851             :         SYM_SIDEBAR_F,
    1852             :         SYM_SIDEBAR_G,
    1853             :         SYM_SIDEBAR_E,
    1854             :         SYM_SIDEBAR_F,
    1855             :         SYM_SIDEBAR_G,
    1856             :         SYM_SIDEBAR_E,
    1857             :         SYM_SIDEBAR_F,
    1858             :         SYM_SIDEBAR_G,
    1859             :         SYM_SIDEBAR_E,
    1860             :         SYM_SIDEBAR_F,
    1861             :         SYM_SIDEBAR_H,
    1862             :         SYM_SIDEBAR_I,
    1863             :         SYM_SIDEBAR_J,
    1864             :     };
    1865             : 
    1866             :     // Get altitude and airspeed, scaled to appropriate units
    1867           0 :     float aspd = 0.0f;
    1868           0 :     float alt = 0.0f;
    1869           0 :     AP_AHRS &ahrs = AP::ahrs();
    1870           0 :     WITH_SEMAPHORE(ahrs.get_semaphore());
    1871           0 :     bool have_speed_estimate = ahrs.airspeed_EAS(aspd);
    1872           0 :     if (!have_speed_estimate) { aspd = 0.0f; }
    1873           0 :     ahrs.get_relative_position_D_home(alt);
    1874           0 :     float scaled_aspd = u_scale(SPEED, aspd);
    1875           0 :     float scaled_alt = u_scale(ALTITUDE, -alt);
    1876             :     static const int aspd_interval = 10; //units between large tick marks
    1877           0 :     int alt_interval = (osd->units == AP_OSD::UNITS_AVIATION || osd->units == AP_OSD::UNITS_IMPERIAL) ? 20 : 10;
    1878             : 
    1879             :     // Height values taking into account configurable vertical extension
    1880           0 :     const int bar_total_height = 7 + (osd->sidebar_v_ext * 2);
    1881           0 :     const int bar_middle = bar_total_height / 2;     // Integer division
    1882             : 
    1883             :     // render airspeed ladder
    1884           0 :     int aspd_symbol_index = fmodf(scaled_aspd, aspd_interval) / aspd_interval * total_sectors;
    1885           0 :     for (int i = 0; i < bar_total_height; i++){
    1886           0 :         if (i == bar_middle) {
    1887             :             // the middle section of the ladder with the currrent airspeed
    1888           0 :             backend->write(x, y+i, false, "%3d%c%c", (int) scaled_aspd, u_icon(SPEED), SYMBOL(SYM_SIDEBAR_R_ARROW));
    1889             :         } else {
    1890           0 :             backend->write(x+4, y+i, false,  "%c", SYMBOL(sidebar_sectors[aspd_symbol_index]));
    1891             :         }
    1892           0 :         aspd_symbol_index = (aspd_symbol_index + 12) % 18;
    1893             :     }
    1894             : 
    1895             :     // render the altitude ladder
    1896             :     // similar formula to above, but accounts for negative altitudes
    1897           0 :     int alt_symbol_index = fmodf(fmodf(scaled_alt, alt_interval) + alt_interval, alt_interval) / alt_interval * total_sectors;
    1898           0 :     for (int i = 0; i < bar_total_height; i++){
    1899           0 :         if (i == bar_middle) {
    1900             :             // the middle section of the ladder with the currrent altitude
    1901           0 :             backend->write(x + 16 + osd->sidebar_h_offset, y+i, false, "%c%d%c", SYMBOL(SYM_SIDEBAR_L_ARROW), (int) scaled_alt, u_icon(ALTITUDE));
    1902             :         } else {
    1903           0 :             backend->write(x + 16 + osd->sidebar_h_offset, y+i, false,  "%c", SYMBOL(sidebar_sectors[alt_symbol_index]));
    1904             :         }
    1905           0 :         alt_symbol_index = (alt_symbol_index + 12) % 18;
    1906             :     }
    1907           0 : }
    1908             : 
    1909             : #endif // HAL_OSD_SIDEBAR_ENABLE
    1910             : 
    1911             : //Thanks to betaflight/inav for simple and clean compass visual design
    1912         548 : void AP_OSD_Screen::draw_compass(uint8_t x, uint8_t y)
    1913             : {
    1914         548 :     const int8_t total_sectors = 16;
    1915             :     static const uint8_t compass_circle[total_sectors] = {
    1916             :         SYM_HEADING_N,
    1917             :         SYM_HEADING_LINE,
    1918             :         SYM_HEADING_DIVIDED_LINE,
    1919             :         SYM_HEADING_LINE,
    1920             :         SYM_HEADING_E,
    1921             :         SYM_HEADING_LINE,
    1922             :         SYM_HEADING_DIVIDED_LINE,
    1923             :         SYM_HEADING_LINE,
    1924             :         SYM_HEADING_S,
    1925             :         SYM_HEADING_LINE,
    1926             :         SYM_HEADING_DIVIDED_LINE,
    1927             :         SYM_HEADING_LINE,
    1928             :         SYM_HEADING_W,
    1929             :         SYM_HEADING_LINE,
    1930             :         SYM_HEADING_DIVIDED_LINE,
    1931             :         SYM_HEADING_LINE,
    1932             :     };
    1933             :     float roll_rad, pitch_rad, yaw_rad;
    1934         548 :     AP::vehicle()->get_osd_attitude_rad(roll_rad, pitch_rad, yaw_rad);
    1935         548 :     int32_t yaw = rad_to_cd(wrap_2PI(yaw_rad));
    1936         548 :     int32_t interval = 36000 / total_sectors;
    1937         548 :     int8_t center_sector = ((yaw + interval / 2) / interval) % total_sectors;
    1938        5480 :     for (int8_t i = -4; i <= 4; i++) {
    1939        4932 :         int8_t sector = center_sector + i;
    1940        4932 :         sector = (sector + total_sectors) % total_sectors;
    1941        4932 :         backend->write(x + i, y, false,  "%c", SYMBOL(compass_circle[sector]));
    1942             :     }
    1943         548 : }
    1944             : 
    1945           0 : void AP_OSD_Screen::draw_wind(uint8_t x, uint8_t y)
    1946             : {
    1947             : #if !APM_BUILD_TYPE(APM_BUILD_Rover)
    1948           0 :     AP_AHRS &ahrs = AP::ahrs();
    1949           0 :     WITH_SEMAPHORE(ahrs.get_semaphore());
    1950           0 :     Vector3f v;
    1951             :     // draw the estimate even if it is not marked valid, to preserve
    1952             :     // existing behaviour
    1953           0 :     IGNORE_RETURN(ahrs.get_wind(v));
    1954           0 :     float angle = 0;
    1955           0 :     const float length = v.length();
    1956           0 :     if (length > 1.0f) {
    1957           0 :         if (check_option(AP_OSD::OPTION_INVERTED_WIND)) {
    1958           0 :             angle = M_PI;
    1959             :         }
    1960             :         float roll_rad, pitch_rad, yaw_rad;
    1961           0 :         AP::vehicle()->get_osd_attitude_rad(roll_rad, pitch_rad, yaw_rad);
    1962           0 :         angle = wrap_2PI(angle + atan2f(v.y, v.x) - yaw_rad);
    1963             :     } 
    1964           0 :     draw_speed(x + 1, y, angle, length);
    1965             : 
    1966             : #else
    1967           0 :     const AP_WindVane* windvane = AP_WindVane::get_singleton();
    1968           0 :     if (windvane != nullptr) {
    1969           0 :         draw_speed(x + 1, y, windvane->get_apparent_wind_direction_rad() + M_PI, windvane->get_apparent_wind_speed());
    1970             :     }
    1971             : #endif
    1972             : 
    1973           0 :     backend->write(x, y, false, "%c", SYMBOL(SYM_WSPD));
    1974           0 : }
    1975             : 
    1976           0 : void AP_OSD_Screen::draw_aspeed(uint8_t x, uint8_t y)
    1977             : {
    1978           0 :     float aspd = 0.0f;
    1979           0 :     AP_AHRS &ahrs = AP::ahrs();
    1980           0 :     WITH_SEMAPHORE(ahrs.get_semaphore());
    1981           0 :     bool have_estimate = ahrs.airspeed_EAS(aspd);
    1982           0 :     if (have_estimate) {
    1983           0 :         backend->write(x, y, false, "%c%4d%c", SYMBOL(SYM_ASPD), (int)u_scale(SPEED, aspd), u_icon(SPEED));
    1984             :     } else {
    1985           0 :         backend->write(x, y, false, "%c ---%c", SYMBOL(SYM_ASPD), u_icon(SPEED));
    1986             :     }
    1987           0 : }
    1988             : 
    1989         548 : void AP_OSD_Screen::draw_vspeed(uint8_t x, uint8_t y)
    1990             : {
    1991         548 :     Vector3f v;
    1992             :     float vspd;
    1993             :     float vs_scaled;
    1994         548 :     AP_AHRS &ahrs = AP::ahrs();
    1995         548 :     WITH_SEMAPHORE(ahrs.get_semaphore());
    1996         548 :     if (ahrs.get_velocity_NED(v)) {
    1997         464 :         vspd = -v.z;
    1998             :     } else {
    1999          84 :         auto &baro = AP::baro();
    2000          84 :         WITH_SEMAPHORE(baro.get_semaphore());
    2001          84 :         vspd = baro.get_climb_rate();
    2002          84 :     }
    2003             :     char sym;
    2004         548 :     if (vspd > 3.0f) {
    2005           0 :         sym = SYMBOL(SYM_UP_UP);
    2006         548 :     } else if (vspd >=0.0f) {
    2007         413 :         sym = SYMBOL(SYM_UP);
    2008         135 :     } else if (vspd >= -3.0f) {
    2009         135 :         sym = SYMBOL(SYM_DOWN);
    2010             :     } else {
    2011           0 :         sym = SYMBOL(SYM_DOWN_DOWN);
    2012             :     }
    2013         548 :     vs_scaled = u_scale(VSPEED, fabsf(vspd));
    2014         548 :     if ((osd->units != AP_OSD::UNITS_AVIATION) && (vs_scaled < 9.95f)) {
    2015         548 :         backend->write(x, y, false, "%c%.1f%c", sym, (float)vs_scaled, u_icon(VSPEED));
    2016             :     } else {
    2017           0 :         const char *fmt = osd->units == AP_OSD::UNITS_AVIATION ? "%c%4d%c" : "%c%2d%c";
    2018           0 :         backend->write(x, y, false, fmt, sym, (int)roundf(vs_scaled), u_icon(VSPEED));
    2019             :     }
    2020         548 : }
    2021             : 
    2022             : #if HAL_WITH_ESC_TELEM
    2023           0 : void AP_OSD_Screen::draw_esc_temp(uint8_t x, uint8_t y)
    2024             : {
    2025             :     int16_t etemp;
    2026             : 
    2027           0 :     if (esc_index > 0) {
    2028           0 :         if (!AP::esc_telem().get_temperature(esc_index-1, etemp)) {
    2029           0 :             return;
    2030             :         }
    2031             :     }
    2032           0 :     else if (!AP::esc_telem().get_highest_temperature(etemp)) {
    2033           0 :         return;
    2034             :     }
    2035             : 
    2036           0 :     backend->write(x, y, false, "%3d%c", (int)u_scale(TEMPERATURE, etemp / 100), u_icon(TEMPERATURE));
    2037             : }
    2038             : 
    2039           0 : void AP_OSD_Screen::draw_esc_rpm(uint8_t x, uint8_t y)
    2040             : {
    2041             :     float rpm;
    2042           0 :     uint8_t esc = AP::esc_telem().get_max_rpm_esc();
    2043           0 :     if (esc_index > 0) {
    2044           0 :         if (!AP::esc_telem().get_rpm(esc_index-1, rpm)) {
    2045           0 :             return;
    2046             :         }
    2047           0 :     } else if (!AP::esc_telem().get_rpm(esc, rpm)) {
    2048           0 :         return;
    2049             :     }
    2050           0 :     float krpm = rpm * 0.001f;
    2051           0 :     const char *format = krpm < 9.995 ? "%.2f%c%c" : (krpm < 99.95 ? "%.1f%c%c" : "%.0f%c%c");
    2052           0 :     backend->write(x, y, false, format, krpm, SYMBOL(SYM_KILO), SYMBOL(SYM_RPM));
    2053             : }
    2054             : 
    2055           0 : void AP_OSD_Screen::draw_esc_amps(uint8_t x, uint8_t y)
    2056             : {
    2057             :     float amps;
    2058           0 :     uint8_t esc = AP::esc_telem().get_max_rpm_esc();
    2059           0 :     if (esc_index > 0) {
    2060           0 :         if (!AP::esc_telem().get_current(esc_index-1, amps)) {
    2061           0 :             return;
    2062             :         }
    2063           0 :     } else if (!AP::esc_telem().get_current(esc, amps)) {
    2064           0 :         return;
    2065             :     }
    2066           0 :     backend->write(x, y, false, "%4.1f%c", amps, SYMBOL(SYM_AMP));
    2067             : }
    2068             : #endif
    2069             : 
    2070             : #if AP_OSD_EXTENDED_LNK_STATS
    2071             : bool AP_OSD_Screen::is_btfl_fonts()
    2072             : {
    2073             :     const AP_MSP *p_msp = AP::msp();
    2074             :     return (p_msp != nullptr && p_msp->is_option_enabled(AP_MSP::Option::DISPLAYPORT_BTFL_SYMBOLS) && !p_msp->is_option_enabled(AP_MSP::Option::DISPLAYPORT_INAV_SYMBOLS));
    2075             : }
    2076             : 
    2077             : void AP_OSD_Screen::draw_rc_tx_power(uint8_t x, uint8_t y)
    2078             : {
    2079             :     const int16_t tx_power = AP::RC().get_link_status().tx_power;
    2080             :     bool btfl = is_btfl_fonts();
    2081             :     if (tx_power > 0) {
    2082             :         if (tx_power < 1000) {
    2083             :             if (btfl) {
    2084             :                 backend->write(x, y, false, "%3d%cW", tx_power, SYMBOL(SYM_ALT_M));  // SYM_ALT_M (0x0C) is the BTFL character for a small "m"
    2085             :             } else {
    2086             :                 backend->write(x, y, false, "%3d%c", tx_power, SYMBOL(SYM_MW));
    2087             :             }
    2088             :         } else {
    2089             :             const float value_w = float(tx_power) * 0.001f;
    2090             :             if (btfl) {
    2091             :                 backend->write(x, y, false, "%.2fW", value_w);
    2092             :             } else {
    2093             :                 backend->write(x, y, false, "%.2f%c", value_w, SYMBOL(SYM_WATT));
    2094             :             }
    2095             :         }
    2096             :     } else {
    2097             :         if (btfl) {
    2098             :             backend->write(x, y, false, "---%cW", SYMBOL(SYM_ALT_M));
    2099             :         } else {
    2100             :             backend->write(x, y, false, "---%c", SYMBOL(SYM_MW));
    2101             :         }
    2102             :     }
    2103             : }
    2104             : 
    2105             : void AP_OSD_Screen::draw_rc_rssi_dbm(uint8_t x, uint8_t y)
    2106             : {
    2107             :     const int8_t rssidbm = AP::RC().get_link_status().rssi_dbm;
    2108             :     const bool blink = -rssidbm < osd->warn_rssi;
    2109             :     bool btfl = is_btfl_fonts();
    2110             : 
    2111             :     backend->write(x, y, blink, "%c", SYMBOL(SYM_RSSI));
    2112             :     uint8_t new_x = x + 1;
    2113             :     if (rssidbm >= 0) {
    2114             :         if (btfl) {
    2115             :             backend->write(new_x, y, blink, "%4dDBM", -rssidbm);
    2116             :         } else {
    2117             :             backend->write(new_x, y, blink, "%4d%c", -rssidbm, SYMBOL(SYM_DBM));
    2118             :         }
    2119             :     } else {
    2120             :         if (btfl){
    2121             :             backend->write(new_x, y, blink, "----DBM");
    2122             :         } else {
    2123             :             backend->write(new_x, y, blink, "----%c", SYMBOL(SYM_DBM));
    2124             :         }
    2125             :     }
    2126             : }
    2127             : 
    2128             : void AP_OSD_Screen::draw_rc_snr(uint8_t x, uint8_t y)
    2129             : {
    2130             :     const int8_t snr = AP::RC().get_link_status().snr;
    2131             :     const bool blink = snr < osd->warn_snr;
    2132             :     bool btfl = is_btfl_fonts();
    2133             :     if (snr == INT8_MIN) {
    2134             :         if (btfl) {
    2135             :             backend->write(x, y, blink, "SNR---DB");
    2136             :         } else {
    2137             :             backend->write(x, y, blink, "%c---%c", SYMBOL(SYM_SNR), SYMBOL(SYM_DB));
    2138             :         }
    2139             :     } else {
    2140             :         if (btfl) {
    2141             :             backend->write(x, y, blink, "SNR%3dDB", snr);
    2142             :         } else {
    2143             :             backend->write(x, y, blink, "%c%3d%c", SYMBOL(SYM_SNR), snr, SYMBOL(SYM_DB));
    2144             :         }
    2145             :     }
    2146             : }
    2147             : 
    2148             : void AP_OSD_Screen::draw_rc_active_antenna(uint8_t x, uint8_t y)
    2149             : {
    2150             :     const int8_t active_antenna = AP::RC().get_link_status().active_antenna;
    2151             :     bool btfl = is_btfl_fonts();
    2152             :     if (active_antenna < 0) {
    2153             :         if (btfl) {
    2154             :             backend->write(x, y, false, "ANT-");
    2155             :         } else {
    2156             :             backend->write(x, y, false, "%c-", SYMBOL(SYM_ANT));
    2157             :         }
    2158             :     } else {
    2159             :         if (btfl) {
    2160             :             backend->write(x, y, false, "ANT%d", active_antenna + 1);
    2161             :         } else {
    2162             :             backend->write(x, y, false, "%c%d", SYMBOL(SYM_ANT), active_antenna + 1);
    2163             :         }
    2164             :     }
    2165             : }
    2166             : 
    2167             : void AP_OSD_Screen::draw_rc_lq(uint8_t x, uint8_t y)
    2168             : {    
    2169             :     const int16_t lqv = AP::RC().get_link_status().link_quality;
    2170             :     const bool blink = lqv < osd->warn_lq;
    2171             :     bool btfl = is_btfl_fonts();
    2172             :     bool prefix_rf = check_option(AP_OSD::OPTION_RF_MODE_ALONG_WITH_LQ);
    2173             :     const int16_t rf_mode = AP::crsf()->get_link_status().rf_mode;    
    2174             :     if (lqv < 0) {
    2175             :         if (btfl) {
    2176             :             if (prefix_rf) {
    2177             :                 backend->write(x, y, blink, "LQ--:--");
    2178             :             } else {
    2179             :                 backend->write(x, y, blink, "LQ--");
    2180             :             }
    2181             :         } else {
    2182             :             if (prefix_rf) {
    2183             :                 backend->write(x, y, blink, "%c--:--", SYMBOL(SYM_LQ));
    2184             :             } else {
    2185             :                 backend->write(x, y, blink, "%c--", SYMBOL(SYM_LQ));
    2186             :             }
    2187             :         }
    2188             :     } else {    
    2189             :         if (btfl) {
    2190             :             if (prefix_rf) {                    
    2191             :                 backend->write(x, y, blink, "LQ%2d:%2d", rf_mode, lqv);
    2192             :             } else {
    2193             :                 backend->write(x, y, blink, "LQ%2d", lqv);
    2194             :             }
    2195             :         } else {
    2196             :             if(prefix_rf) {
    2197             :                 backend->write(x, y, blink, "%c%2d:%2d", SYMBOL(SYM_LQ), rf_mode, lqv);
    2198             :             } else {
    2199             :                 backend->write(x, y, blink, "%c%2d", SYMBOL(SYM_LQ), lqv);
    2200             :             }
    2201             :         }
    2202             :     }
    2203             : }
    2204             : #endif  // AP_OSD_EXTENDED_LNK_STATS
    2205             : 
    2206         548 : void AP_OSD_Screen::draw_gps_latitude(uint8_t x, uint8_t y)
    2207             : {
    2208         548 :     AP_GPS & gps = AP::gps();
    2209         548 :     const Location &loc = gps.location();   // loc.lat and loc.lng
    2210             :     int32_t dec_portion, frac_portion;
    2211         548 :     int32_t abs_lat = labs(loc.lat);
    2212             : 
    2213         548 :     dec_portion = loc.lat / 10000000L;
    2214         548 :     frac_portion = abs_lat - labs(dec_portion)*10000000UL;
    2215             : 
    2216         548 :     backend->write(x, y, false, "%c%4ld.%07ld", SYMBOL(SYM_GPS_LAT), (long)dec_portion,(long)frac_portion);
    2217         548 : }
    2218             : 
    2219         548 : void AP_OSD_Screen::draw_gps_longitude(uint8_t x, uint8_t y)
    2220             : {
    2221         548 :     AP_GPS & gps = AP::gps();
    2222         548 :     const Location &loc = gps.location();   // loc.lat and loc.lng
    2223             :     int32_t dec_portion, frac_portion;
    2224         548 :     int32_t abs_lon = labs(loc.lng);
    2225             : 
    2226         548 :     dec_portion = loc.lng / 10000000L;
    2227         548 :     frac_portion = abs_lon - labs(dec_portion)*10000000UL;
    2228             : 
    2229         548 :     backend->write(x, y, false, "%c%4ld.%07ld", SYMBOL(SYM_GPS_LONG), (long)dec_portion,(long)frac_portion);
    2230         548 : }
    2231             : 
    2232           0 : void AP_OSD_Screen::draw_roll_angle(uint8_t x, uint8_t y)
    2233             : {
    2234             :     float roll_rad, pitch_rad, yaw_rad;
    2235           0 :     AP::vehicle()->get_osd_attitude_rad(roll_rad, pitch_rad, yaw_rad);
    2236           0 :     const float roll_deg = degrees(roll_rad);
    2237             :     char r;
    2238           0 :     if (roll_deg > 0.5) {
    2239           0 :         r = SYMBOL(SYM_ROLLR);
    2240           0 :     } else if (roll_deg < -0.5) {
    2241           0 :         r = SYMBOL(SYM_ROLLL);
    2242             :     } else {
    2243           0 :         r = SYMBOL(SYM_ROLL0);
    2244             :     }
    2245           0 :     backend->write(x, y, false, "%c%3d%c", r, int(fabsf(roll_deg)), SYMBOL(SYM_DEGR));
    2246           0 : }
    2247             : 
    2248           0 : void AP_OSD_Screen::draw_pitch_angle(uint8_t x, uint8_t y)
    2249             : {
    2250             :     float roll_rad, pitch_rad, yaw_rad;
    2251           0 :     AP::vehicle()->get_osd_attitude_rad(roll_rad, pitch_rad, yaw_rad);
    2252           0 :     const float pitch_deg = degrees(pitch_rad);
    2253             :     char p;
    2254           0 :     if (pitch_deg > 0.5) {
    2255           0 :         p = SYMBOL(SYM_PTCHUP);
    2256           0 :     } else if (pitch_deg < -0.5) {
    2257           0 :         p = SYMBOL(SYM_PTCHDWN);
    2258             :     } else {
    2259           0 :         p = SYMBOL(SYM_PTCH0);
    2260             :     }
    2261           0 :     backend->write(x, y, false, "%c%3d%c", p, int(fabsf(pitch_deg)), SYMBOL(SYM_DEGR));
    2262           0 : }
    2263             : 
    2264           0 : void AP_OSD_Screen::draw_temp(uint8_t x, uint8_t y)
    2265             : {
    2266           0 :     AP_Baro &barometer = AP::baro();
    2267           0 :     float tmp = barometer.get_temperature();
    2268           0 :     backend->write(x, y, false, "%3d%c", (int)u_scale(TEMPERATURE, tmp), u_icon(TEMPERATURE));
    2269           0 : }
    2270             : 
    2271             : 
    2272           0 : void AP_OSD_Screen::draw_hdop(uint8_t x, uint8_t y)
    2273             : {
    2274           0 :     AP_GPS & gps = AP::gps();
    2275           0 :     float hdp = gps.get_hdop() * 0.01f;
    2276           0 :     backend->write(x, y, false, "%c%c%3.2f", SYMBOL(SYM_HDOP_L), SYMBOL(SYM_HDOP_R), (double)hdp);
    2277           0 : }
    2278             : 
    2279           0 : void AP_OSD_Screen::draw_waypoint(uint8_t x, uint8_t y)
    2280             : {
    2281             :     float roll_rad, pitch_rad, yaw_rad;
    2282           0 :     AP::vehicle()->get_osd_attitude_rad(roll_rad, pitch_rad, yaw_rad);
    2283           0 :     int32_t angle_cd = osd->nav_info.wp_bearing - rad_to_cd(yaw_rad);
    2284           0 :     if (osd->nav_info.wp_distance < 2.0f) {
    2285             :         //avoid fast rotating arrow at small distances
    2286           0 :         angle_cd = 0;
    2287             :     }
    2288           0 :     char arrow = get_arrow_font_index(angle_cd);
    2289           0 :     backend->write(x,y, false, "%c%2u%c",SYMBOL(SYM_WPNO), osd->nav_info.wp_number, arrow);
    2290           0 :     draw_distance(x+4, y, osd->nav_info.wp_distance);
    2291           0 : }
    2292             : 
    2293           0 : void AP_OSD_Screen::draw_xtrack_error(uint8_t x, uint8_t y)
    2294             : {
    2295           0 :     backend->write(x, y, false, "%c", SYMBOL(SYM_XERR));
    2296           0 :     draw_distance(x+1, y, osd->nav_info.wp_xtrack_error);
    2297           0 : }
    2298             : 
    2299           0 : void AP_OSD_Screen::draw_stat(uint8_t x, uint8_t y)
    2300             : {
    2301           0 :     backend->write(x+2, y, false, "%c%c%c", 0x4d,0x41,0x58);
    2302           0 :     backend->write(x, y+1, false, "%c",SYMBOL(SYM_GSPD));
    2303           0 :     backend->write(x+1, y+1, false, "%4d%c", (int)u_scale(SPEED, osd->_stats.max_speed_mps), u_icon(SPEED));
    2304           0 :     backend->write(x, y+2, false, "%5.1f%c", (double)osd->_stats.max_current_a, SYMBOL(SYM_AMP));
    2305           0 :     backend->write(x, y+3, false, "%5d%c", (int)u_scale(ALTITUDE, osd->_stats.max_alt_m), u_icon(ALTITUDE));
    2306           0 :     backend->write(x, y+4, false, "%c", SYMBOL(SYM_HOME));
    2307           0 :     draw_distance(x+1, y+4, osd->_stats.max_dist_m);
    2308           0 :     backend->write(x, y+5, false, "%c", SYMBOL(SYM_DIST));
    2309           0 :     draw_distance(x+1, y+5, osd->_stats.last_distance_m);
    2310           0 : }
    2311             : 
    2312           0 : void AP_OSD_Screen::draw_dist(uint8_t x, uint8_t y)
    2313             : {
    2314           0 :     backend->write(x, y, false, "%c", SYMBOL(SYM_DIST));
    2315           0 :     draw_distance(x+1, y, osd->_stats.last_distance_m);
    2316           0 : }
    2317             : 
    2318           0 : void  AP_OSD_Screen::draw_flightime(uint8_t x, uint8_t y)
    2319             : {
    2320           0 :     AP_Stats *stats = AP::stats();
    2321           0 :     if (stats) {
    2322           0 :         uint32_t t = stats->get_flight_time_s();
    2323           0 :         backend->write(x, y, false, "%c%3u:%02u", SYMBOL(SYM_FLY), unsigned(t/60), unsigned(t%60));
    2324             :     }
    2325           0 : }
    2326             : 
    2327             : #if AP_BATTERY_ENABLED
    2328           0 : void AP_OSD_Screen::draw_eff(uint8_t x, uint8_t y)
    2329             : {
    2330           0 :     AP_BattMonitor &battery = AP::battery();
    2331           0 :     Vector2f v;
    2332             :     {
    2333           0 :         AP_AHRS &ahrs = AP::ahrs();
    2334           0 :         WITH_SEMAPHORE(ahrs.get_semaphore());
    2335           0 :         v = ahrs.groundspeed_vector();
    2336           0 :     }
    2337           0 :     float speed = u_scale(SPEED,v.length());
    2338             :     float current_amps;
    2339           0 :     if ((speed > 2.0) && battery.current_amps(current_amps)) {
    2340           0 :         backend->write(x, y, false, "%c%3d%c", SYMBOL(SYM_EFF),int(1000.0f*current_amps/speed),SYMBOL(SYM_MAH));
    2341             :     } else {
    2342           0 :         backend->write(x, y, false, "%c---%c", SYMBOL(SYM_EFF),SYMBOL(SYM_MAH));
    2343             :     }
    2344           0 : }
    2345             : #endif  // AP_BATTERY_ENABLED
    2346             : 
    2347             : #if AP_BATTERY_ENABLED
    2348           0 : void AP_OSD_Screen::draw_climbeff(uint8_t x, uint8_t y)
    2349             : {
    2350           0 :     char unit_icon = u_icon(DISTANCE);
    2351           0 :     Vector3f v;
    2352             :     float vspd;
    2353             :     do {
    2354             :         {
    2355           0 :             auto &ahrs = AP::ahrs();
    2356           0 :             WITH_SEMAPHORE(ahrs.get_semaphore());
    2357           0 :             if (ahrs.get_velocity_NED(v)) {
    2358           0 :                 vspd = -v.z;
    2359           0 :                 break;
    2360             :             }
    2361           0 :         }
    2362           0 :         auto &baro = AP::baro();
    2363           0 :         WITH_SEMAPHORE(baro.get_semaphore());
    2364           0 :         vspd = baro.get_climb_rate();
    2365           0 :     } while (false);
    2366           0 :     if (vspd < 0.0) {
    2367           0 :         vspd = 0.0;
    2368             :     }
    2369           0 :     AP_BattMonitor &battery = AP::battery();
    2370             :     float amps;
    2371           0 :     if (battery.current_amps(amps) && is_positive(amps)) {
    2372           0 :         backend->write(x, y, false,"%c%c%3.1f%c",SYMBOL(SYM_PTCHUP),SYMBOL(SYM_EFF),(double)(3.6f * u_scale(VSPEED,vspd)/amps),unit_icon);
    2373             :     } else {
    2374           0 :         backend->write(x, y, false,"%c%c---%c",SYMBOL(SYM_PTCHUP),SYMBOL(SYM_EFF),unit_icon);
    2375             :     }
    2376           0 : }
    2377             : #endif
    2378             : 
    2379             : #if BARO_MAX_INSTANCES > 1
    2380           0 : void AP_OSD_Screen::draw_btemp(uint8_t x, uint8_t y)
    2381             : {
    2382           0 :     AP_Baro &barometer = AP::baro();
    2383           0 :     float btmp = barometer.get_temperature(1);
    2384           0 :     backend->write(x, y, false, "%3d%c", (int)u_scale(TEMPERATURE, btmp), u_icon(TEMPERATURE));
    2385           0 : }
    2386             : #endif
    2387             : 
    2388           0 : void AP_OSD_Screen::draw_atemp(uint8_t x, uint8_t y)
    2389             : {
    2390             : #if AP_AIRSPEED_ENABLED
    2391           0 :     AP_Airspeed *airspeed = AP_Airspeed::get_singleton();
    2392           0 :     if (!airspeed) {
    2393           0 :         return;
    2394             :     }
    2395           0 :     float temperature = 0;
    2396           0 :     airspeed->get_temperature(temperature);
    2397           0 :     if (airspeed->healthy()) {
    2398           0 :         backend->write(x, y, false, "%3d%c", (int)u_scale(TEMPERATURE, temperature), u_icon(TEMPERATURE));
    2399             :     } else {
    2400           0 :         backend->write(x, y, false, "--%c", u_icon(TEMPERATURE));
    2401             :     }
    2402             : #endif
    2403             : }
    2404             : 
    2405           0 : void AP_OSD_Screen::draw_bat2_vlt(uint8_t x, uint8_t y)
    2406             : {
    2407           0 :     draw_bat_volt(1,VoltageType::VOLTAGE,x,y);
    2408           0 : }
    2409             : 
    2410           0 : void AP_OSD_Screen::draw_bat2used(uint8_t x, uint8_t y)
    2411             : {
    2412           0 :     draw_batused(1, x, y);
    2413           0 : }
    2414             : 
    2415           0 : void AP_OSD_Screen::draw_aspd1(uint8_t x, uint8_t y)
    2416             : {
    2417             : #if AP_AIRSPEED_ENABLED
    2418           0 :     AP_Airspeed *airspeed = AP_Airspeed::get_singleton();
    2419           0 :     if (!airspeed) {
    2420           0 :         return;
    2421             :     }
    2422           0 :     float asp1 = airspeed->get_airspeed();
    2423           0 :     if (airspeed != nullptr && airspeed->healthy()) {
    2424           0 :         backend->write(x, y, false, "%c%4d%c", SYMBOL(SYM_ASPD), (int)u_scale(SPEED, asp1), u_icon(SPEED));
    2425             :     } else {
    2426           0 :         backend->write(x, y, false, "%c ---%c", SYMBOL(SYM_ASPD), u_icon(SPEED));
    2427             :     }
    2428             : #endif
    2429             : }
    2430             : 
    2431           0 : void AP_OSD_Screen::draw_aspd2(uint8_t x, uint8_t y)
    2432             : {
    2433             : #if AP_AIRSPEED_ENABLED
    2434           0 :     AP_Airspeed *airspeed = AP_Airspeed::get_singleton();
    2435           0 :     if (!airspeed) {
    2436           0 :         return;
    2437             :     }
    2438           0 :     float asp2 = airspeed->get_airspeed(1);
    2439           0 :     if (airspeed != nullptr && airspeed->healthy(1)) {
    2440           0 :         backend->write(x, y, false, "%c%4d%c", SYMBOL(SYM_ASPD), (int)u_scale(SPEED, asp2), u_icon(SPEED));
    2441             :     } else {
    2442           0 :         backend->write(x, y, false, "%c ---%c", SYMBOL(SYM_ASPD), u_icon(SPEED));
    2443             :     }
    2444             : #endif
    2445             : }
    2446             : 
    2447             : #if AP_RTC_ENABLED
    2448           0 : void AP_OSD_Screen::draw_clk(uint8_t x, uint8_t y)
    2449             : {
    2450           0 :     AP_RTC &rtc = AP::rtc();
    2451             :     uint8_t hour, min, sec;
    2452             :     uint16_t ms;
    2453           0 :     if (!rtc.get_local_time(hour, min, sec, ms)) {
    2454           0 :     backend->write(x, y, false, "%c--:--", SYMBOL(SYM_CLK));
    2455             :     } else {
    2456           0 :     backend->write(x, y, false, "%c%02u:%02u", SYMBOL(SYM_CLK), hour, min);
    2457             :     }
    2458           0 : }
    2459             : #endif
    2460             : 
    2461             : #if HAL_PLUSCODE_ENABLE
    2462           0 : void AP_OSD_Screen::draw_pluscode(uint8_t x, uint8_t y)
    2463             : {
    2464           0 :     AP_GPS & gps = AP::gps();
    2465           0 :     const Location &loc = gps.location();
    2466             :     char buff[16];
    2467           0 :     if (gps.status() == AP_GPS_FixType::NO_GPS || gps.status() == AP_GPS_FixType::NONE){
    2468           0 :         backend->write(x, y, false, "--------+--");
    2469             :     } else {
    2470           0 :         AP_OLC::olc_encode(loc.lat, loc.lng, 10, buff, sizeof(buff));
    2471           0 :         backend->write(x, y, false, "%s", buff);
    2472             :     }
    2473           0 : }
    2474             : #endif
    2475             : 
    2476             : /*
    2477             :   support callsign display from a file called callsign.txt
    2478             :  */
    2479           0 : void AP_OSD_Screen::draw_callsign(uint8_t x, uint8_t y)
    2480             : {
    2481             : #if AP_OSD_CALLSIGN_FROM_SD_ENABLED
    2482           0 :     if (!callsign_data.load_attempted) {
    2483           0 :         callsign_data.load_attempted = true;
    2484           0 :         FileData *fd = AP::FS().load_file("callsign.txt");
    2485           0 :         if (fd != nullptr) {
    2486           0 :             uint32_t len = fd->length;
    2487             :             // trim off whitespace
    2488           0 :             while (len > 0 && isspace(fd->data[len-1])) {
    2489           0 :                 len--;
    2490             :             }
    2491           0 :             callsign_data.str = strndup((const char *)fd->data, len);
    2492           0 :             delete fd;
    2493             :         }
    2494             :     }
    2495           0 :     if (callsign_data.str != nullptr) {
    2496           0 :         backend->write(x, y, false, "%s", callsign_data.str);
    2497             :     }
    2498             : #endif
    2499           0 : }
    2500             : 
    2501           0 : void AP_OSD_Screen::draw_current2(uint8_t x, uint8_t y)
    2502             : {
    2503           0 :     draw_current(1, x, y);
    2504           0 : }
    2505             : 
    2506             : #if AP_VIDEOTX_ENABLED
    2507           0 : void AP_OSD_Screen::draw_vtx_power(uint8_t x, uint8_t y)
    2508             : {
    2509           0 :     AP_VideoTX *vtx = AP_VideoTX::get_singleton();
    2510           0 :     if (!vtx) {
    2511           0 :         return;
    2512             :     }
    2513           0 :     uint16_t powr = 0;
    2514             :     // If currently in pit mode, just render 0mW to the screen
    2515           0 :     if(!vtx->has_option(AP_VideoTX::VideoOptions::VTX_PITMODE)){
    2516             :         // prefer VTX-reported actual; SmartAudio returns -1 here
    2517           0 :         const int32_t actual_mw = vtx->get_actual_power_mw();
    2518           0 :         powr = actual_mw >= 0 ? uint16_t(actual_mw) : vtx->get_power_mw();
    2519             :     }
    2520           0 :     backend->write(x, y, !vtx->is_configuration_finished(), "%4hu%c", powr, SYMBOL(SYM_MW));
    2521             : }
    2522             : #endif  // AP_VIDEOTX_ENABLED
    2523             : 
    2524             : #if AP_TERRAIN_AVAILABLE
    2525           0 : void AP_OSD_Screen::draw_hgt_abvterr(uint8_t x, uint8_t y)
    2526             : {
    2527           0 :     AP_Terrain *terrain = AP::terrain();
    2528             : 
    2529             :     float terrain_altitude;
    2530           0 :     if (terrain != nullptr && terrain->height_above_terrain(terrain_altitude,true)) {
    2531           0 :         bool blink = (osd->warn_terr != -1)? (terrain_altitude < osd->warn_terr) : false; //blink if warn_terr is not disabled and alt above terrain is below warning value
    2532           0 :         backend->write(x, y, blink, "%4d%c%c", (int)u_scale(ALTITUDE, terrain_altitude), u_icon(ALTITUDE), SYMBOL(SYM_TERALT));
    2533             :      } else {
    2534           0 :         backend->write(x, y, false, " ---%c%c", u_icon(ALTITUDE),SYMBOL(SYM_TERALT));
    2535             :      }
    2536           0 : }
    2537             : #endif
    2538             : 
    2539             : #if AP_FENCE_ENABLED
    2540           0 : void AP_OSD_Screen::draw_fence(uint8_t x, uint8_t y)
    2541             : {
    2542           0 :     AC_Fence *fenceptr = AP::fence();
    2543           0 :     if (fenceptr == nullptr) {
    2544           0 :        return;
    2545             :     }
    2546           0 :     if (fenceptr->enabled() && fenceptr->present()) {
    2547           0 :         backend->write(x, y, fenceptr->get_breaches(), "%c", SYMBOL(SYM_FENCE_ENABLED));
    2548             :     } else {
    2549           0 :         backend->write(x, y, false, "%c", SYMBOL(SYM_FENCE_DISABLED));
    2550             :     }
    2551             : }
    2552             : #endif
    2553             : 
    2554             : #if AP_RANGEFINDER_ENABLED
    2555           0 : void AP_OSD_Screen::draw_rngf(uint8_t x, uint8_t y)
    2556             : {
    2557           0 :     RangeFinder *rangefinder = RangeFinder::get_singleton();
    2558           0 :     if (rangefinder == nullptr) {
    2559           0 :        return;
    2560             :     }
    2561           0 :     if (rangefinder->status_orient(ROTATION_PITCH_270) != RangeFinder::Status::Good) {
    2562           0 :         backend->write(x, y, false, "%c---%c", SYMBOL(SYM_RNGFD), u_icon(DISTANCE));
    2563             :     } else {
    2564           0 :         const float distance = rangefinder->distance_orient(ROTATION_PITCH_270);
    2565           0 :         backend->write(x, y, false, "%c%4.1f%c", SYMBOL(SYM_RNGFD), u_scale(DISTANCE, distance), u_icon(DISTANCE));
    2566             :     }
    2567             : }
    2568             : #endif
    2569             : 
    2570             : #define DRAW_SETTING(n) if (n.enabled) draw_ ## n(n.xpos, n.ypos)
    2571             : 
    2572             : #if HAL_WITH_OSD_BITMAP || HAL_WITH_MSP_DISPLAYPORT
    2573         548 : void AP_OSD_Screen::draw(void)
    2574             : {
    2575         548 :     if (!enabled || !backend) {
    2576           0 :         return;
    2577             :     }
    2578             :     //Note: draw order should be optimized.
    2579             :     //Big and less important items should be drawn first,
    2580             :     //so they will not overwrite more important ones.
    2581             : #if HAL_OSD_SIDEBAR_ENABLE
    2582         548 :     DRAW_SETTING(sidebars);
    2583             : #endif
    2584             : 
    2585         548 :     DRAW_SETTING(message);
    2586         548 :     DRAW_SETTING(horizon);
    2587         548 :     DRAW_SETTING(compass);
    2588         548 :     DRAW_SETTING(altitude);
    2589             : 
    2590             : #if AP_TERRAIN_AVAILABLE
    2591         548 :     DRAW_SETTING(hgt_abvterr);
    2592             : #endif
    2593             : 
    2594             : #if AP_RANGEFINDER_ENABLED
    2595         548 :     DRAW_SETTING(rngf);
    2596             : #endif
    2597         548 :     DRAW_SETTING(waypoint);
    2598         548 :     DRAW_SETTING(xtrack_error);
    2599         548 :     DRAW_SETTING(bat_volt);
    2600         548 :     DRAW_SETTING(bat2_vlt);
    2601         548 :     DRAW_SETTING(avgcellvolt);
    2602         548 :     DRAW_SETTING(avgcellrestvolt);
    2603         548 :     DRAW_SETTING(restvolt);
    2604             : #if AP_RSSI_ENABLED
    2605         548 :     DRAW_SETTING(rssi);
    2606         548 :     DRAW_SETTING(link_quality);
    2607             : #endif
    2608         548 :     DRAW_SETTING(current);
    2609         548 :     DRAW_SETTING(batused);
    2610         548 :     DRAW_SETTING(bat2used);
    2611         548 :     DRAW_SETTING(sats);
    2612         548 :     DRAW_SETTING(fltmode);
    2613         548 :     DRAW_SETTING(gspeed);
    2614         548 :     DRAW_SETTING(aspeed);
    2615         548 :     DRAW_SETTING(aspd1);
    2616         548 :     DRAW_SETTING(aspd2);
    2617         548 :     DRAW_SETTING(vspeed);
    2618         548 :     DRAW_SETTING(throttle);
    2619         548 :     DRAW_SETTING(heading);
    2620         548 :     DRAW_SETTING(wind);
    2621         548 :     DRAW_SETTING(home);
    2622             : #if AP_RPM_ENABLED
    2623         548 :     DRAW_SETTING(rrpm);
    2624             : #endif
    2625             : #if AP_FENCE_ENABLED
    2626         548 :     DRAW_SETTING(fence);
    2627             : #endif
    2628         548 :     DRAW_SETTING(roll_angle);
    2629         548 :     DRAW_SETTING(pitch_angle);
    2630         548 :     DRAW_SETTING(temp);
    2631             : #if BARO_MAX_INSTANCES > 1
    2632         548 :     DRAW_SETTING(btemp);
    2633             : #endif
    2634         548 :     DRAW_SETTING(atemp);
    2635         548 :     DRAW_SETTING(hdop);
    2636         548 :     DRAW_SETTING(flightime);
    2637             : #if AP_RTC_ENABLED
    2638         548 :     DRAW_SETTING(clk);
    2639             : #endif
    2640             : #if AP_VIDEOTX_ENABLED
    2641         548 :     DRAW_SETTING(vtx_power);
    2642             : #endif
    2643             : 
    2644             : #if HAL_WITH_ESC_TELEM
    2645         548 :     DRAW_SETTING(esc_temp);
    2646         548 :     DRAW_SETTING(esc_rpm);
    2647         548 :     DRAW_SETTING(esc_amps);
    2648             : #endif
    2649             : 
    2650         548 :     DRAW_SETTING(gps_latitude);
    2651         548 :     DRAW_SETTING(gps_longitude);
    2652             : #if HAL_PLUSCODE_ENABLE
    2653         548 :     DRAW_SETTING(pluscode);
    2654             : #endif
    2655         548 :     DRAW_SETTING(dist);
    2656         548 :     DRAW_SETTING(stat);
    2657         548 :     DRAW_SETTING(climbeff);
    2658         548 :     DRAW_SETTING(eff);
    2659         548 :     DRAW_SETTING(callsign);
    2660         548 :     DRAW_SETTING(current2);
    2661             : 
    2662             : #if AP_OSD_EXTENDED_LNK_STATS
    2663             :     DRAW_SETTING(rc_tx_power);
    2664             :     DRAW_SETTING(rc_rssi_dbm);
    2665             :     DRAW_SETTING(rc_snr);
    2666             :     DRAW_SETTING(rc_active_antenna);
    2667             :     DRAW_SETTING(rc_lq);
    2668             : #endif
    2669             : }
    2670             : #endif
    2671             : #endif // OSD_ENABLED

Generated by: LCOV version 1.14