Ubuntu16.04下适配使用LogitechF710手柄,实际项目使用
·
依然话不多说,直接上代码,有需要直接拿去使用!!!!!
#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);
}
}
}
更多推荐
所有评论(0)