Program Listing for File remote.hpp

Return to documentation for file (src/tap/communication/serial/remote.hpp)

/*
 * Copyright (c) 2020-2022 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_REMOTE_HPP_
#define TAPROOT_REMOTE_HPP_

#include <cstdint>

#ifndef PLATFORM_HOSTED
#include "modm/platform.hpp"
#endif

#include "tap/util_macros.hpp"

namespace tap
{
class Drivers;
}

namespace tap::communication::serial
{
class Remote
{
public:
    Remote(Drivers *drivers) : drivers(drivers) {}
    DISALLOW_COPY_AND_ASSIGN(Remote)
    mockable ~Remote() = default;

    enum class Channel
    {
        RIGHT_HORIZONTAL,
        RIGHT_VERTICAL,
        LEFT_HORIZONTAL,
        LEFT_VERTICAL,
        WHEEL
    };

    enum class Switch
    {
        LEFT_SWITCH,
        RIGHT_SWITCH
    };

    enum class SwitchState
    {
        UNKNOWN = 0,
        UP = 1,
        DOWN = 2,
        MID = 3,
    };

    enum class Key
    {
        W = 0,
        S,
        A,
        D,
        SHIFT,
        CTRL,
        Q,
        E,
        R,
        F,
        G,
        Z,
        X,
        C,
        V,
        B
    };

    mockable void initialize();

    mockable void read();

    mockable bool isConnected() const;

    mockable float getChannel(Channel ch) const;

    mockable SwitchState getSwitch(Switch sw) const;

    mockable inline int16_t getMouseX() const { return remote.mouse.x; }

    mockable inline int16_t getMouseY() const { return remote.mouse.y; }

    mockable inline int16_t getMouseZ() const { return remote.mouse.z; }

    mockable inline bool getMouseL() const { return remote.mouse.l; }

    mockable inline bool getMouseR() const { return remote.mouse.r; }

    mockable inline bool keyPressed(Key key) const
    {
        return (remote.key & (1 << static_cast<uint8_t>(key))) != 0;
    }

    mockable uint32_t getUpdateCounter() const;

private:
    static const int REMOTE_BUF_LEN = 18;
    static const int REMOTE_READ_TIMEOUT = 6;
    static const int REMOTE_DISCONNECT_TIMEOUT = 100;
    static const int REMOTE_INT_PRI = 12;
    static constexpr float ANALOG_MAX_VALUE = 660.0f;

    struct RemoteInfo
    {
        uint32_t updateCounter = 0;
        int16_t rightHorizontal = 0;
        int16_t rightVertical = 0;
        int16_t leftHorizontal = 0;
        int16_t leftVertical = 0;
        SwitchState leftSwitch = SwitchState::UNKNOWN;
        SwitchState rightSwitch = SwitchState::UNKNOWN;
        struct
        {
            int16_t x = 0;
            int16_t y = 0;
            int16_t z = 0;
            bool l = false;
            bool r = false;
        } mouse;
        uint16_t key = 0;
        int16_t wheel = 0;
    };

    Drivers *drivers;

    RemoteInfo remote;

    bool connected = false;

    uint8_t rxBuffer[REMOTE_BUF_LEN]{0};

    uint32_t lastRead = 0;

    uint8_t currentBufferIndex = 0;

    void parseBuffer();

    void clearRxBuffer();

    void reset();
};  // class Remote

}  // namespace tap::communication::serial

#endif  // TAPROOT_REMOTE_HPP_