依然话不多说,直接上代码,有需要直接拿去使用!!!!!

#pragma once

#include <cstdint>
#include <cstring>
#include <string>
#include <sstream>
#include <fcntl.h>
#include <functional>
#include <vector>
#include <unistd.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/joystick.h>
#include <stdlib.h>

#include "Thread.h"

enum class F710_EVENT_TYPE
{
    Button = 1,
    Axis = 2,
    ButtonHeartBeat = 129,
    AxisHeartBeat = 130,
};

enum class F710KeyD : uint8_t
{
    LeftThumbX = 0,
    LeftThumbY = 1,
    RightThumbX = 2,
    RightThumbY = 3,
    PadX = 4,
    PadY = 5,

    ButtonX = 0,
    ButtonA = 1,
    ButtonB = 2,
    ButtonY = 3,
    LeftBumper = 4,
    RightBumper = 5,
    LeftTrigger = 6,
    RightTrigger = 7,
    ButtonBack = 8,
    ButtonStart = 9,
    LeftStick = 10,
    RighttStick = 11
};

enum class F710KeyX : uint8_t
{
    LeftThumbX = 0,
    LeftThumbY = 1,
    LeftTrigger = 2,
    RightThumbX = 3,
    RightThumbY = 4,
    RightTrigger = 5,
    PadX = 6,
    PadY = 7,

    ButtonA = 0,
    ButtonB = 1,
    ButtonX = 2,
    ButtonY = 3,
    LeftBumper = 4,
    RightBumper = 5,
    ButtonBack = 6,
    ButtonStart = 7,
    ButtonHome = 8,
    LeftStick = 9,
    RighttStick = 10
};

class F710MCD 
{
public:
    ~F710MCD();

    bool init() override;
    void addMCDCallback(const ChasisCodeCallback& chasisCallback, const OperatorCodeCallback& opCallback) override;

private:
    void f710Process();
    bool checkF710(const std::string& dirName);
    bool openF710();
    timespec timespecFromMs(uint32_t millis);
    bool waitReadable(uint32_t timeout);
    void callbackHandleDMode(js_event inputKey);
    void callbackHandleXMode(js_event inputKey);

    std::vector<ChasisCodeCallback> m_chasisCodeCallback;
    std::vector<OperatorCodeCallback> m_operatorCodeCallback;

    OperatorCodeMsg m_operatorCodeMsg;
    ChasisCodeMsg m_chasisCodeMsg;

    vcs::common::thread::Thread m_f710MCDThread;
    int32_t m_keysFd;
    bool m_findF710Flag = false;
    bool m_isXmode;
    bool m_isFrontButtonDown = false;
    bool m_isBackButtonDown = false;
    bool m_leftMoveAcc = false;
    bool m_rightMoveAcc = false;
    int32_t m_RightThumbXValue = 0;
    int32_t m_RightThumbYValue = 0;

    bool m_useMCD = true;
};

#include "F710MCD.h"

#include <string>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <errno.h>

const int32_t CHECK_F710_TIME = 5;
const double PI = 3.1415926;

F710MCD::~F710MCD()
{
    m_f710MCDThread.stop();
}

bool F710MCD::init()
{
    m_f710MCDThread.assignTask(std::bind(&F710MCD::f710Process, this));
    m_f710MCDThread.start();

    return true;
}

void F710MCD::addMCDCallback(const ChasisCodeCallback& chasisCallback,
                             const OperatorCodeCallback& opCallback)
{
    if (chasisCallback)
    {
        m_chasisCodeCallback.emplace_back(chasisCallback);
    }
    if (opCallback)
    {
        m_operatorCodeCallback.emplace_back(opCallback);
    }
}

bool F710MCD::checkF710(const std::string& dirName)
{
    DIR* p_Dir;
    bool isCheckF710 = false;
    struct dirent* p_Dirent;
    const char* dirStr = dirName.c_str();
    p_Dir = opendir(dirStr);

    if (p_Dir == NULL)
    {
        AERROR_EVERY(500) << " open dev " + dirName + " false";
        isCheckF710 = false;
    }

    while ((p_Dirent = readdir(p_Dir)) != NULL)
    {
        if (strcmp(p_Dirent->d_name, "js0") == 0)
        {
            isCheckF710 = true;
        }
    }

    if (!isCheckF710)
    {
        AERROR_EVERY(500) << " find F710 faile ";
    }

    closedir(p_Dir);

    return isCheckF710;
}

bool F710MCD::openF710()
{
    char devName[100];

    strcpy(devName, "/dev/input/js0");
    m_keysFd = open(devName, O_RDONLY | O_NONBLOCK); //O_NONBLOCK:非阻塞式打开
    if (m_keysFd <= 0)
    {
        AERROR << "open " << devName << " device error!";
        close(m_keysFd);
        m_findF710Flag = false;
        return false;
    }

    //read设置为非阻塞
    if (fcntl(m_keysFd, F_SETFL, O_NONBLOCK) == -1)
    {
        AERROR << "set " << devName << " device property error!";
        close(m_keysFd);
        m_findF710Flag = false;
        return false;
    }

    m_findF710Flag = true;
    char name[128];

    if (ioctl(m_keysFd, JSIOCGNAME(sizeof(name)), name) < 0)
    {
        strncpy(name, "Unknown", sizeof(name));
    }
    std::string testName(name);
    if (!testName.compare("Logitech Gamepad F710"))
    {
        m_isXmode = true;
    }
    else
    {
        m_isXmode = false;
    }

    return true;
}

timespec F710MCD::timespecFromMs(uint32_t millis)
{
    timespec time;
    time.tv_sec = millis / 1e3;
    time.tv_nsec = (millis - (time.tv_sec * 1e3)) * 1e6;

    return time;
}

bool F710MCD::waitReadable(uint32_t timeout)
{
    //Setup a select call to block for serial data or a timeout
    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(m_keysFd, &readfds);

    timespec timeout_ts(timespecFromMs(timeout));
    int32_t r = pselect(m_keysFd + 1, &readfds, nullptr, nullptr, &timeout_ts, nullptr);

    if (r < 0)
    {
        //Select was interrupted
        if (errno == EINTR)
        {
            return false;
        }
    }
    //Timeout occurred
    if (r == 0)
    {
        return false;
    }
    //This shouldn't happen, if r > 0 our fd has to be in the list!
    if (!FD_ISSET(m_keysFd, &readfds))
    {
        AERROR << "This shouldnot happen in waitReadable()";
        return false;
    }
    // Data available to read.
    return true;
}

void F710MCD::f710Process()
{
    uint32_t startTime = Time::now().toSecond();

    struct js_event inputKey;

    AINFO << "Enter F710 handle process.";
    for (;;)
    {
        if (m_f710MCDThread.isExiting(5))
        {
            break;
        }

        if (VehicleStateProvider::instance()->isInSystem())
        {
            continue;
        }

        if (!checkF710("/dev/input/"))
        {
            m_findF710Flag = false;
            continue;
        }

        if ((Time::now().toSecond() - startTime) > CHECK_F710_TIME && !m_findF710Flag)
        {
            openF710();
            startTime = Time::now().toSecond();
        }

        if (!m_findF710Flag)
        {
            AERROR << " m_findF710Flag = FALSE ";
            if (m_chasisCodeMsg.value == 1)
            {
                m_chasisCodeMsg.code = ChasisCode::MoveFront;
                m_chasisCodeMsg.value = 0;

                for (const auto& callback : m_chasisCodeCallback)
                {
                    callback(m_chasisCodeMsg);
                }
            }
            vcs::common::util::sleep(CHECK_F710_TIME * 1000);
        }
        else
        {
            if (::read(m_keysFd, &inputKey, sizeof(inputKey)) == sizeof(inputKey))
            {
                if (inputKey.type == static_cast<uint8_t>(F710_EVENT_TYPE::Button) ||
                    inputKey.type == static_cast<uint8_t>(F710_EVENT_TYPE::Axis))
                {
                    if (m_isXmode)
                    {
                        callbackHandleXMode(inputKey);
                    }
                    else
                    {
                        callbackHandleDMode(inputKey);
                    }
                }
            }
        }
    }
}

void F710MCD::callbackHandleDMode(js_event inputKey)
{
    bool isOperatorMsg = false;
    bool isChasisMsg = false;

    m_operatorCodeMsg.value = inputKey.value;
    m_chasisCodeMsg.value = inputKey.value;

    if (inputKey.type == static_cast<uint8_t>(F710_EVENT_TYPE::Button))
    {
        if (inputKey.number == static_cast<uint8_t>(F710KeyD::ButtonA))
        {
            isOperatorMsg = true;
            m_operatorCodeMsg.code = OperatorCode::Down;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::ButtonY))
        {
            isOperatorMsg = true;
            m_operatorCodeMsg.code = OperatorCode::Up;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::ButtonX))
        {
            isOperatorMsg = true;
            m_operatorCodeMsg.code = OperatorCode::Left;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::ButtonB))
        {
            isOperatorMsg = true;
            m_operatorCodeMsg.code = OperatorCode::Right;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::LeftBumper))
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::TurnLeft;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::RightBumper))
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::TurnRight;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::LeftTrigger))
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::MoveFront;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::RightTrigger))
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::MoveBack;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::ButtonStart))
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::RightDiffMode;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::ButtonBack))
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::LeftDiffMode;
        }
        else
        {
            isChasisMsg = true;
            m_chasisCodeMsg.value = 0;
        }
    }
    else
    {
        if (inputKey.number == static_cast<uint8_t>(F710KeyD::PadY) && inputKey.value <= 0)
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::MoveFront;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::PadY) && inputKey.value > 0)
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::MoveBack;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::PadX) && inputKey.value <= 0)
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::TurnLeft;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::PadX) && inputKey.value > 0)
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::TurnRight;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::LeftThumbY))
        {
            if (inputKey.value > 0)
            {
                isChasisMsg = true;
                m_chasisCodeMsg.code = ChasisCode::MoveBack;
            }
            else
            {
                isChasisMsg = true;
                m_chasisCodeMsg.code = ChasisCode::MoveFront;
            }
            m_chasisCodeMsg.value = ((fabs(inputKey.value) > 0) ? 1 : 0);
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyD::RightThumbX))
        {
            if (inputKey.value > 0)
            {
                isChasisMsg = true;
                m_chasisCodeMsg.code = ChasisCode::TurnRight;
            }
            else
            {
                isChasisMsg = true;
                m_chasisCodeMsg.code = ChasisCode::TurnLeft;
            }
            m_chasisCodeMsg.value = ((fabs(inputKey.value) > 0) ? 1 : 0);
        }
        else
        {
            isChasisMsg = true;
            m_chasisCodeMsg.value = 0;
        }
    }

    if (isOperatorMsg)
    {
        for (const auto& callback : m_operatorCodeCallback)
        {
            callback(m_operatorCodeMsg);
        }
    }

    if (isChasisMsg)
    {
        for (const auto& callback : m_chasisCodeCallback)
        {
            callback(m_chasisCodeMsg);
        }
    }
}

void F710MCD::callbackHandleXMode(js_event inputKey)
{
    bool isOperatorMsg = false;
    bool isChasisMsg = false;

    m_operatorCodeMsg.value = inputKey.value;
    m_chasisCodeMsg.value = inputKey.value;

    if (inputKey.type == static_cast<uint8_t>(F710_EVENT_TYPE::Button))
    {
        if (inputKey.number == static_cast<uint8_t>(F710KeyX::ButtonA))
        {
            isOperatorMsg = true;
            m_operatorCodeMsg.code = OperatorCode::Down;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::ButtonY))
        {
            isOperatorMsg = true;
            m_operatorCodeMsg.code = OperatorCode::Up;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::ButtonX))
        {
            isOperatorMsg = true;
            m_operatorCodeMsg.code = OperatorCode::Left;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::ButtonB))
        {
            isOperatorMsg = true;
            m_operatorCodeMsg.code = OperatorCode::Right;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::ButtonHome))
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::BackToZero;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::ButtonStart))
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::RightDiffMode;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::ButtonBack))
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::LeftDiffMode;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::LeftBumper))
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::TurnLeft;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::RightBumper))
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::TurnRight;
        }
        else
        {
            isChasisMsg = true;
            m_chasisCodeMsg.value = 0;
        }
    }
    else
    {
        if (inputKey.number == static_cast<uint8_t>(F710KeyX::PadY) && inputKey.value <= 0)
        {
            if (inputKey.value != 0)
            {
                m_isFrontButtonDown = true;
            }
            else
            {
                m_isFrontButtonDown = false;
                m_isBackButtonDown = false;
                m_leftMoveAcc = false;
                m_rightMoveAcc = false;
            }

            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::MoveFront;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::PadY) && inputKey.value > 0)
        {
            if (inputKey.value != 0)
            {
                m_isBackButtonDown = true;
            }

            isChasisMsg = true;
            m_chasisCodeMsg.value *= -1;
            m_chasisCodeMsg.code = ChasisCode::MoveBack;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::PadX) && inputKey.value <= 0)
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::TurnLeft;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::PadX) && inputKey.value > 0)
        {
            isChasisMsg = true;
            m_chasisCodeMsg.code = ChasisCode::TurnRight;
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::LeftTrigger))
        {

            if ((m_isFrontButtonDown || m_isBackButtonDown) && !m_rightMoveAcc)
            {
                if (m_chasisCodeMsg.value > 5000 && m_chasisCodeMsg.code != ChasisCode::MoveACC)
                {
                    m_leftMoveAcc = true;
                    isChasisMsg = true;
                    m_chasisCodeMsg.code = ChasisCode::MoveACC;
                }
                else if (m_chasisCodeMsg.value < -5000 && m_leftMoveAcc)
                {
                    m_leftMoveAcc = false;
                    m_rightMoveAcc = false;
                    if (m_isFrontButtonDown)
                    {
                        isChasisMsg = true;
                        m_chasisCodeMsg.code = ChasisCode::MoveFront;
                    }
                    else if (m_isBackButtonDown)
                    {
                        isChasisMsg = true;
                        m_chasisCodeMsg.code = ChasisCode::MoveBack;
                    }
                }
            }
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::RightTrigger))
        {
            if ((m_isFrontButtonDown || m_isBackButtonDown) && !m_leftMoveAcc)
            {
                if (m_chasisCodeMsg.value > 5000 && m_chasisCodeMsg.code != ChasisCode::MoveACC)
                {
                    m_rightMoveAcc = true;
                    isChasisMsg = true;
                    m_chasisCodeMsg.code = ChasisCode::MoveACC;
                }
                else if (m_chasisCodeMsg.value < -5000 && m_rightMoveAcc)
                {
                    m_leftMoveAcc = false;
                    m_rightMoveAcc = false;
                    if (m_isFrontButtonDown)
                    {
                        isChasisMsg = true;
                        m_chasisCodeMsg.code = ChasisCode::MoveFront;
                    }
                    else if (m_isBackButtonDown)
                    {
                        isChasisMsg = true;
                        m_chasisCodeMsg.code = ChasisCode::MoveBack;
                    }
                }
            }
        }
        else if (inputKey.number == static_cast<uint8_t>(F710KeyX::RightThumbX) ||
                 inputKey.number == static_cast<uint8_t>(F710KeyX::RightThumbY))
        {
            if (inputKey.number == static_cast<uint8_t>(F710KeyX::RightThumbX))
            {
                m_RightThumbXValue = (fabs(inputKey.value) <= 1000 ? 0 : inputKey.value);
            }
            else
            {
                m_RightThumbYValue = (fabs(inputKey.value) <= 1000 ? 0 : -inputKey.value);
            }

            double alpha =
                normalizeRadianAngle(atan2(m_RightThumbYValue + 1e-6, m_RightThumbXValue) - PI / 2);

            double m_steerAngle = normalizeDegreeAngle(alpha * 360 / PI / 2) * 1000;

            isChasisMsg = true;
            m_chasisCodeMsg.value =
                static_cast<int32_t>(std::max(std::min(m_steerAngle, 90000.0), -90000.0));

            if (m_steerAngle <= 0)
            {
                m_chasisCodeMsg.code = ChasisCode::AbsoluteTurnRight;
            }
            else
            {
                m_chasisCodeMsg.code = ChasisCode::AbsoluteTurnLeft;
            }
        }
        else
        {
            isChasisMsg = true;
            m_chasisCodeMsg.value = 0;
        }
    }

    if (isOperatorMsg)
    {
        for (const auto& callback : m_operatorCodeCallback)
        {
            callback(m_operatorCodeMsg);
        }
    }

    if (isChasisMsg)
    {
        for (const auto& callback : m_chasisCodeCallback)
        {
            callback(m_chasisCodeMsg);
        }
    }
}

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐