Skip to content

Conversation

@MrD-RC
Copy link
Member

@MrD-RC MrD-RC commented Nov 5, 2025

User description

This brings the SmartPort flight modes in line with what is shown on the OSD and CRSF telemetry.

I am working on updating the OpenTX Telemetry Widget. All new modes have been tested, except Turtle, using SmartPort. I just need to test with CRSF and create the voice files. iNavFlight/OpenTX-Telemetry-Widget#193

I've also added a small correction to the OSD display of the GEO mode.


PR Type

Enhancement, Bug fix


Description

  • Expand SmartPort telemetry flight mode support to 32-bit range

  • Add new flight modes: Turtle, FW Autoland, Angle Hold, Waypoint RTH

  • Refine existing mode conditions with airplane state checks

  • Fix GEO mode display padding in OSD


Diagram Walkthrough

flowchart LR
  A["SmartPort Flight Mode<br/>Detection"] -->|"Expand to 32-bit"| B["Support Additional<br/>Flight Modes"]
  B -->|"Add Modes"| C["Turtle, FW Autoland,<br/>Angle Hold, WP RTH"]
  B -->|"Refine Conditions"| D["Airplane State Checks<br/>for PosHold & RTH"]
  E["OSD Display"] -->|"Fix Padding"| F["GEO Mode<br/>Alignment"]
Loading

File Walkthrough

Relevant files
Enhancement
smartport.c
Expand SmartPort flight mode detection to 32-bit                 

src/main/telemetry/smartport.c

  • Changed frskyGetFlightMode() return type from uint16_t to uint32_t to
    support expanded flight mode range
  • Added hundred thousands column for new modes: NAV_FW_AUTOLAND
    (100000), TURTLE_MODE (200000), NAV_SEND_TO (400000), and
    airplane-specific NAV_POSHOLD_MODE (800000)
  • Added million column for Waypoint Mission RTH (1000000) and
    ANGLEHOLD_MODE (2000000)
  • Refined NAV_POSHOLD_MODE condition to exclude airplane mode and
    NAV_RTH_MODE to exclude waypoint missions
+20/-4   
Bug fix
osd.c
Fix GEO mode display padding                                                         

src/main/io/osd.c

  • Added trailing space to GEO mode display string for consistent
    alignment with other 4-character mode labels
+1/-1     

This brings the SmartPort flight modes in line with what is shown on the OSD and CRSF telemetry.

I am working on updating the OpenTX Telemetry Widget. All have been tested, except Turtle, using SmartPort. I just need to test with CRSF.
@MrD-RC MrD-RC added this to the 9.0 milestone Nov 5, 2025
@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Nov 5, 2025

PR Compliance Guide 🔍

(Compliance updated until commit cc33f44)

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No audit logs: New telemetry state changes (e.g., home reset HRST emission control) are introduced
without any corresponding audit logging, but this code path may not be part of a
security-audited surface.

Referred Code
    static uint8_t hrstSent = 0;

    // use same logic as OSD, so telemetry displays same flight text as OSD when armed
    const char *flightMode = "OK";
    if (ARMING_FLAG(ARMED)) {
        flightMode = "ACRO";
#ifdef USE_FW_AUTOLAND
        if (FLIGHT_MODE(NAV_FW_AUTOLAND)) {
            flightMode = "LAND";
        } else
#endif
        if (FLIGHT_MODE(FAILSAFE_MODE)) {
            flightMode = "!FS!";
        } else if (IS_RC_MODE_ACTIVE(BOXHOMERESET) && hrstSent < 4 && !FLIGHT_MODE(NAV_RTH_MODE) && !FLIGHT_MODE(NAV_WP_MODE)) {
            flightMode = "HRST";
            hrstSent++;
        } else if (FLIGHT_MODE(MANUAL_MODE)) {
            flightMode = "MANU";
#ifdef USE_GEOZONE
        } else if (FLIGHT_MODE(NAV_SEND_TO) && !FLIGHT_MODE(NAV_WP_MODE)) {
            flightMode = "GEO";


 ... (clipped 35 lines)
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status:
Vague identifier: The variable hrstSent is abbreviated and lacks context or comment, making its purpose and
bounds unclear though it may be conventional in this codebase.

Referred Code
    static uint8_t hrstSent = 0;

    // use same logic as OSD, so telemetry displays same flight text as OSD when armed
    const char *flightMode = "OK";
    if (ARMING_FLAG(ARMED)) {
        flightMode = "ACRO";
#ifdef USE_FW_AUTOLAND
        if (FLIGHT_MODE(NAV_FW_AUTOLAND)) {
            flightMode = "LAND";
        } else
#endif
        if (FLIGHT_MODE(FAILSAFE_MODE)) {
            flightMode = "!FS!";
        } else if (IS_RC_MODE_ACTIVE(BOXHOMERESET) && hrstSent < 4 && !FLIGHT_MODE(NAV_RTH_MODE) && !FLIGHT_MODE(NAV_WP_MODE)) {
            flightMode = "HRST";
            hrstSent++;
        } else if (FLIGHT_MODE(MANUAL_MODE)) {
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Edge case limits: The counter hrstSent caps HRST emissions at <4 but uses a static uint8_t without
overflow checks or timing reset strategy beyond RC mode off, which may miss edge cases
like rapid toggling.

Referred Code
    static uint8_t hrstSent = 0;

    // use same logic as OSD, so telemetry displays same flight text as OSD when armed
    const char *flightMode = "OK";
    if (ARMING_FLAG(ARMED)) {
        flightMode = "ACRO";
#ifdef USE_FW_AUTOLAND
        if (FLIGHT_MODE(NAV_FW_AUTOLAND)) {
            flightMode = "LAND";
        } else
#endif
        if (FLIGHT_MODE(FAILSAFE_MODE)) {
            flightMode = "!FS!";
        } else if (IS_RC_MODE_ACTIVE(BOXHOMERESET) && hrstSent < 4 && !FLIGHT_MODE(NAV_RTH_MODE) && !FLIGHT_MODE(NAV_WP_MODE)) {
            flightMode = "HRST";
            hrstSent++;
        } else if (FLIGHT_MODE(MANUAL_MODE)) {
            flightMode = "MANU";
#ifdef USE_GEOZONE
        } else if (FLIGHT_MODE(NAV_SEND_TO) && !FLIGHT_MODE(NAV_WP_MODE)) {
            flightMode = "GEO";


 ... (clipped 35 lines)
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

Previous compliance checks

Compliance check up to commit c520ff8
Security Compliance
Integer overflow

Description: Potential 32-bit integer overflow risk if future additions push the cumulative flight mode
bitfield beyond 2,147,483,647, since the function now uses uint32_t but sums large decimal
place values that could exceed 31 bits with new modes.
smartport.c [165-227]

Referred Code
static uint32_t frskyGetFlightMode(void)
{
    uint32_t tmpi = 0;

    // ones column
    if (!isArmingDisabled())
        tmpi += 1;
    else
        tmpi += 2;
    if (ARMING_FLAG(ARMED))
        tmpi += 4;

    // tens column
    if (FLIGHT_MODE(ANGLE_MODE))
        tmpi += 10;
    if (FLIGHT_MODE(HORIZON_MODE))
        tmpi += 20;
    if (FLIGHT_MODE(MANUAL_MODE))
        tmpi += 40;

    // hundreds column


 ... (clipped 42 lines)
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No auditing: The added telemetry/OSD logic introduces new state reporting for flight modes but does not
include any audit logging of critical actions; if such logging is required for this
context, it is absent in the new code.

Referred Code
static uint32_t frskyGetFlightMode(void)
{
    uint32_t tmpi = 0;

    // ones column
    if (!isArmingDisabled())
        tmpi += 1;
    else
        tmpi += 2;
    if (ARMING_FLAG(ARMED))
        tmpi += 4;

    // tens column
    if (FLIGHT_MODE(ANGLE_MODE))
        tmpi += 10;
    if (FLIGHT_MODE(HORIZON_MODE))
        tmpi += 20;
    if (FLIGHT_MODE(MANUAL_MODE))
        tmpi += 40;

    // hundreds column


 ... (clipped 41 lines)
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
No error handling: The new function logic calculates and returns a composite flight mode without validating
states or handling edge conditions (e.g., overflow from expanded bitfields), which may
require safeguards depending on upstream guarantees.

Referred Code
static uint32_t frskyGetFlightMode(void)
{
    uint32_t tmpi = 0;

    // ones column
    if (!isArmingDisabled())
        tmpi += 1;
    else
        tmpi += 2;
    if (ARMING_FLAG(ARMED))
        tmpi += 4;

    // tens column
    if (FLIGHT_MODE(ANGLE_MODE))
        tmpi += 10;
    if (FLIGHT_MODE(HORIZON_MODE))
        tmpi += 20;
    if (FLIGHT_MODE(MANUAL_MODE))
        tmpi += 40;

    // hundreds column


 ... (clipped 42 lines)
Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Input assumptions: The new code relies on external macros/functions (e.g., FLIGHT_MODE, STATE) and expands
the return width to 32-bit without explicit validation of inputs or bounds, which may be
acceptable in this embedded context but is not verifiable from the diff.

Referred Code
static uint32_t frskyGetFlightMode(void)
{
    uint32_t tmpi = 0;

    // ones column
    if (!isArmingDisabled())
        tmpi += 1;
    else
        tmpi += 2;
    if (ARMING_FLAG(ARMED))
        tmpi += 4;

    // tens column
    if (FLIGHT_MODE(ANGLE_MODE))
        tmpi += 10;
    if (FLIGHT_MODE(HORIZON_MODE))
        tmpi += 20;
    if (FLIGHT_MODE(MANUAL_MODE))
        tmpi += 40;

    // hundreds column


 ... (clipped 41 lines)

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Nov 5, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Refactor the fragile flight mode encoding

Refactor the flight mode encoding from a brittle decimal summation to a more
robust and scalable bitmask system. This change would improve maintainability
and align with modern telemetry practices.

Examples:

src/main/telemetry/smartport.c [165-228]
static uint32_t frskyGetFlightMode(void)
{
    uint32_t tmpi = 0;

    // ones column
    if (!isArmingDisabled())
        tmpi += 1;
    else
        tmpi += 2;
    if (ARMING_FLAG(ARMED))

 ... (clipped 54 lines)

Solution Walkthrough:

Before:

uint32_t frskyGetFlightMode(void)
{
    uint32_t tmpi = 0;

    // tens column
    if (FLIGHT_MODE(ANGLE_MODE))
        tmpi += 10;
    if (FLIGHT_MODE(HORIZON_MODE))
        tmpi += 20;

    // thousands column
    if (FLIGHT_MODE(NAV_RTH_MODE) && !isWaypointMissionRTHActive())
        tmpi += 1000;
    else if (FLIGHT_MODE(NAV_WP_MODE))
        tmpi += 2000;

    // hundred thousands column
    if (FLIGHT_MODE(TURTLE_MODE))
        tmpi += 200000;

    return tmpi;
}

After:

// Define bitmask values for flight modes
#define FRSKY_FM_ARM_DISABLED (1 << 1)
#define FRSKY_FM_ARMED        (1 << 2)
#define FRSKY_FM_ANGLE        (1 << 3)
#define FRSKY_FM_HORIZON      (1 << 4)
#define FRSKY_FM_RTH          (1 << 5)
#define FRSKY_FM_WP           (1 << 6)
#define FRSKY_FM_TURTLE       (1 << 7)
// ... etc for all modes

uint32_t frskyGetFlightMode(void)
{
    uint32_t flightModeMask = 0;
    if (!isArmingDisabled()) flightModeMask |= FRSKY_FM_ARM_READY; else flightModeMask |= FRSKY_FM_ARM_DISABLED;
    if (ARMING_FLAG(ARMED)) flightModeMask |= FRSKY_FM_ARMED;
    if (FLIGHT_MODE(ANGLE_MODE)) flightModeMask |= FRSKY_FM_ANGLE;
    if (FLIGHT_MODE(HORIZON_MODE)) flightModeMask |= FRSKY_FM_HORIZON;
    // ... etc for all modes
    return flightModeMask;
}
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a fragile, non-scalable decimal encoding for flight modes and proposes a robust bitmask-based refactoring, which is a significant improvement for code quality and future maintainability.

High
Possible issue
Prevent ambiguous flight mode values

To prevent ambiguous flight mode values, convert the series of if statements for
the "hundred thousands column" into a single if-else if chain to ensure only one
mode from the group can be active at a time.

src/main/telemetry/smartport.c [211-219]

 // hundred thousands column
 if (FLIGHT_MODE(NAV_FW_AUTOLAND))
     tmpi += 100000;
 if (FLIGHT_MODE(TURTLE_MODE))
     tmpi += 200000;
+else if (FLIGHT_MODE(NAV_SEND_TO))
+    tmpi += 400000;
 else if (FLIGHT_MODE(NAV_POSHOLD_MODE) && STATE(AIRPLANE))
     tmpi += 800000;
-if (FLIGHT_MODE(NAV_SEND_TO))
-    tmpi += 400000;
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a logical flaw where multiple independent if statements can lead to an ambiguous flight mode value, which would be undecodable by telemetry scripts. Enforcing mutual exclusivity with an if-else if chain is the correct approach for this type of encoding, significantly improving the correctness of the telemetry data.

Medium
  • Update

@MrD-RC
Copy link
Member Author

MrD-RC commented Nov 5, 2025

Refactor the fragile flight mode encoding
It has been done this way for a long time. We are looking at enhancing some things in SmartPort for the ETHOS Telemetry Dashboard in INAV 10. Perhaps this can be updated at that time. It isn't worth messing with so close to the INAV 9 RC release. As the LUA may need a lot of work to integrate this.

Prevent ambiguous flight mode values
Not needed. Only the modes activated at the time will be selected. So no ambiguity.

@MrD-RC
Copy link
Member Author

MrD-RC commented Nov 5, 2025

I need to update the document.

Added back home reset. But added a safety that it will only be sent for 5 packets. So that it will not block actual flight modes.
@sensei-hacker sensei-hacker merged commit b6c4ff8 into master Nov 8, 2025
22 checks passed
@MrD-RC MrD-RC deleted the MrD_Update-SmartPort-modes-to-include-new-modes branch November 9, 2025 00:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants