Program Listing for File state_hud_indicator.hpp

Return to documentation for file (src/tap/communication/referee/state_hud_indicator.hpp)

/*
 * Copyright (c) 2020-2021 Advanced Robotics at the University of Washington <robomstr@uw.edu>
 *
 * This file is part of Taproot.
 *
 * Taproot is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Taproot is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Taproot.  If not, see <https://www.gnu.org/licenses/>.
 */

#ifndef TAPROOT_STATE_HUD_INDICATOR_HPP_
#define TAPROOT_STATE_HUD_INDICATOR_HPP_

#include "tap/architecture/timeout.hpp"
#include "tap/communication/serial/ref_serial.hpp"
#include "tap/communication/serial/ref_serial_transmitter.hpp"

#include "modm/processing/resumable.hpp"

namespace tap
{
class Drivers;
}

namespace tap::communication::referee
{
template <typename T>
class StateHUDIndicator : public modm::Resumable<2>
{
public:
    using UpdateHUDIndicatorState =
        void (*)(T state, tap::communication::serial::RefSerial::Tx::Graphic1Message *graphic);

    static constexpr uint32_t MIN_UPDATE_PERIOD = 500;

    StateHUDIndicator(
        tap::communication::serial::RefSerialTransmitter &refSerialTransmitter,
        tap::communication::serial::RefSerial::Tx::Graphic1Message *graphic,
        UpdateHUDIndicatorState updateFunction,
        T initialState)
        : refSerialTransmitter(refSerialTransmitter),
          graphic(graphic),
          updateFunction(updateFunction),
          initialState(initialState),
          indicatorState(initialState)
    {
        minUpdatePeriodTimeout.stop();
    }

    modm::ResumableResult<bool> initialize()
    {
        RF_BEGIN(0);

        indicatorState = initialState;

        // Initially add the graphic
        graphic->graphicData.operation = tap::communication::serial::RefSerial::Tx::GRAPHIC_ADD;
        RF_CALL(refSerialTransmitter.sendGraphic(graphic));
        // In future calls to sendGraphic only modify the graphic
        graphic->graphicData.operation = tap::communication::serial::RefSerial::Tx::GRAPHIC_MODIFY;

        delayTimeout.restart(
            tap::communication::serial::RefSerialData::Tx::getWaitTimeAfterGraphicSendMs(graphic));
        RF_WAIT_UNTIL(delayTimeout.execute());

        RF_END_RETURN(true);
    }

    modm::ResumableResult<bool> draw()
    {
        RF_BEGIN(1);
        if (indicatorChanged)
        {
            // resend graphic if color changed
            RF_CALL(refSerialTransmitter.sendGraphic(graphic));
            indicatorChanged = false;
            delayTimeout.restart(
                tap::communication::serial::RefSerialData::Tx::getWaitTimeAfterGraphicSendMs(
                    graphic));
            RF_WAIT_UNTIL(delayTimeout.execute());
        }
        RF_END_RETURN(true);
    }

    void setIndicatorState(T newIndicatorState)
    {
        if (minUpdatePeriodTimeout.isExpired() || minUpdatePeriodTimeout.isStopped())
        {
            if (indicatorState != newIndicatorState)
            {
                indicatorState = newIndicatorState;
                updateFunction(indicatorState, graphic);
                indicatorChanged = true;
                minUpdatePeriodTimeout.restart(MIN_UPDATE_PERIOD);
            }
        }
    }

private:
    tap::communication::serial::RefSerialTransmitter &refSerialTransmitter;

    tap::communication::serial::RefSerial::Tx::Graphic1Message *graphic;

    UpdateHUDIndicatorState updateFunction;

    const T initialState;
    T indicatorState;
    bool indicatorChanged = false;

    tap::arch::MilliTimeout delayTimeout;

    tap::arch::MilliTimeout minUpdatePeriodTimeout;
};

using BooleanHUDIndicator = StateHUDIndicator<bool>;

}  // namespace tap::communication::referee

#endif  // TAPROOT_STATE_HUD_INDICATOR_HPP_