ZZ-Cat / CRSFforArduino

An Arduino Library for communicating with ExpressLRS and TBS Crossfire receivers.
GNU Affero General Public License v3.0
143 stars 24 forks source link

refactor(library): Flight Modes API and Custom Flight Modes integration, plus code and comments clean-up #84

Closed ZZ-Cat closed 7 months ago

ZZ-Cat commented 7 months ago

Overview

This Pull Request is the "final touches" I need to do with the code-base before it's released.
It brings in some much needed housekeeping, and quality-of-life fixes.

Details

Deleted...

Disabled...

Fixes...

Re-factors...

API changes

Flight Modes API

Both standard and custom flight modes are registered with this function:

Both standard Flight Modes and custom Flight Modes are written out using this function:

An example usage situation looks like this:

#include "Arduino.h"
#include "CRSFforArduino.hpp"

/* Define our modes up here, including putting ARM on Channel 5 (Aux1). */
#define FLIGHT_MODE_ARM_CHANNEL 5
#define FLIGHT_MODE_ARM_MIN     1000
#define FLIGHT_MODE_ARM_MAX     1800

#define FLIGHT_MODE_NORMAL_CHANNEL 6
#define FLIGHT_MODE_NORMAL_MIN     750
#define FLIGHT_MODE_NORMAL_MAX     1250

#define FLIGHT_MODE_IDLEUP1_CHANNEL 6
#define FLIGHT_MODE_IDLEUP1_MIN     1250
#define FLIGHT_MODE_IDLEUP1_MAX     1750

#define FLIGHT_MODE_IDLEUP2_CHANNEL 6
#define FLIGHT_MODE_IDLEUP2_MIN     1750
#define FLIGHT_MODE_IDLEUP2_MAX     2250

/* Pointer to CRSF for Arduino. */
CRSFforArduino *crsf = nullptr;

/* Our Flight Modes handler may be declared here. */
void onFlightModeUpdate(serialReceiverLayer::flightModeId_t);

void setup()
{
    /* Initialise the native USB port and wait for it to be ready. */
    Serial.begin(115200);
    while (!Serial)
    {
        delay(10);
    }

    Serial.println("[Sketch | INFO]: CRSF for Arduino Example");

    /* Create a new CRSF for Arduino object and initialise it. */
    crsf = new CRSFforArduino();
    if (!crsf->begin())
    {
        /* CRSF for Arduino failed to initialise.
        Tear-down and clean up any resources what were allocated. */
        crsf->end();
        delete crsf;
        crsf = nullptr;

        Serial.println("[Sketch | ERROR]: CRSF failed to initialise.");
    }
    else
    {
        /* CRSF for Arduino successfully initialised.
        Now, register the custom flight modes, along with the Disarmed mode. */
        crsf->setFlightMode(serialReceiverLayer::FLIGHT_MODE_DISARMED, FLIGHT_MODE_ARM_CHANNEL, FLIGHT_MODE_ARM_MIN, FLIGHT_MODE_ARM_MAX);
        crsf->setFlightMode(serialReceiverLayer::CUSTOM_FLIGHT_MODE1, "Normal", FLIGHT_MODE_NORMAL_CHANNEL, FLIGHT_MODE_NORMAL_MIN, FLIGHT_MODE_NORMAL_MAX);
        crsf->setFlightMode(serialReceiverLayer::CUSTOM_FLIGHT_MODE2, "Idle-Up 1", FLIGHT_MODE_IDLEUP1_CHANNEL, FLIGHT_MODE_IDLEUP1_MIN, FLIGHT_MODE_IDLEUP1_MAX);
        crsf->setFlightMode(serialReceiverLayer::CUSTOM_FLIGHT_MODE3, "Idle-Up 2", FLIGHT_MODE_IDLEUP2_CHANNEL, FLIGHT_MODE_IDLEUP2_MIN, FLIGHT_MODE_IDLEUP2_MAX);

        /* Set the Flight Modes callback. */
        crsf->setFlightModeCallback(onFlightModeUpdate);

        Serial.println("[Sketch | INFO]: CRSF initialised.");
    }
}

void loop()
{
    /* Guard CRSF for Arduino. */
    if (crsf != nullptr)
    {
        /* Update CRSF for Arduino. */
        crsf->update();
    }
}

void onFlightModeUpdate(serialReceiverLayer::flightModeId_t flightMode)
{
    /* This is our Flight Modes callback that we declared earlier.
    Whenever a Flight Mode is changed, this is what gets called.
    You may write your own Flight Modes implementation using this callback function.
    For the purposes of this example, simply relaying the flight modes back to the handset is shown here,
    and the modes are printed to the Serial Monitor. */

    /* Are we disarmed? */
    bool isDisarmed = true;
    if (flightMode != serialReceiverLayer::FLIGHT_MODE_DISARMED)
    {
        isDisarmed = false;
    }
    else if (isFailsafeActive)
    {
        isDisarmed = true;
    }

    /* Update the flight mode telemetry with the new value. */
    crsf->telemetryWriteFlightMode(flightMode, isDisarmed);

    /* Print the flight mode to the Serial Monitor, but only if the flight mode has changed. */
    static serialReceiverLayer::flightModeId_t lastFlightMode = serialReceiverLayer::FLIGHT_MODE_DISARMED;
    if (flightMode != lastFlightMode)
    {
        lastFlightMode = flightMode;

        Serial.print("[Sketch | INFO]: Flight Mode: ");
        switch (flightMode)
        {
            case serialReceiverLayer::FLIGHT_MODE_DISARMED:
                Serial.println("Disarmed");
                break;
            case serialReceiverLayer::CUSTOM_FLIGHT_MODE1:
                Serial.println("Normal");
                break;
            case serialReceiverLayer::CUSTOM_FLIGHT_MODE2:
                Serial.println("Idle Up 1");
                break;
            case serialReceiverLayer::CUSTOM_FLIGHT_MODE3:
                Serial.println("Idle Up 2");
                break;
            default:
                Serial.println("Unknown");
                break;
        }
    }
}

In order to use the API above, you MUST have the following flags set in CFA_Config.hpp:

This is also assuming that you have CRSF_RC_ENABLED set to 1 (which is the default, by the way. Because the entire library relies on this for everything), and you have CRSF_TELEMETRY_ENABLED set to 1 if you want your Flight Modes to be fed back to your controller.

Additional

Now that this is complete. All that is left is the documentation.
Then, CRSF for Arduino version 1.0.0 will be released to the public.

Thank you all from the bottom of my heart for being here, and using my library in your projects.
A huge thanks to those daring enough to try out CRSF for Arduino in its various stages of jankiness-to-refinement and everything in between.

ZZ-Cat commented 7 months ago

Ugh! =-/.(\=
A bug on Adafruit's end has tripped my continuous integration for testing CRSF for Arduino on supported Arduino platforms.
I am actually thinking about disabling it entirely, because it actually no longer compile-tests on the platforms that CRSF for Arduino is currently compatible with. It only compile-tests for the Metro M4 Express. CRSF for Arduino supports a more diverse range of targets now, compared to when I started this project a year or two ago.