Added XboxdrvDaemon class, split controller code into XboxdrvThread
This commit is contained in:
parent
d9e1741f84
commit
52de13c105
8 changed files with 600 additions and 215 deletions
|
@ -23,6 +23,7 @@ else:
|
|||
CPPPATH=["src/"])
|
||||
|
||||
env.ParseConfig("pkg-config --cflags --libs libusb-1.0 | sed 's/-I/-isystem/g'")
|
||||
env.ParseConfig("pkg-config --cflags --libs libudev | sed 's/-I/-isystem/g'")
|
||||
|
||||
f = open("VERSION")
|
||||
package_version = f.read()
|
||||
|
|
8
TODO
8
TODO
|
@ -83,6 +83,14 @@ Stuff to do before 0.6.5 release:
|
|||
multiple controllers directly in xboxdrv
|
||||
|
||||
|
||||
XboxdrvDaemon
|
||||
=============
|
||||
|
||||
* add --no-detach
|
||||
|
||||
* add --create-pid (look how other daemons do it)
|
||||
|
||||
|
||||
Stuff to do before 0.6.x release:
|
||||
=================================
|
||||
|
||||
|
|
271
src/xboxdrv.cpp
271
src/xboxdrv.cpp
|
@ -16,6 +16,8 @@
|
|||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "xboxdrv.hpp"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
@ -35,40 +37,26 @@
|
|||
#include <unistd.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "modifier/autofire_modifier.hpp"
|
||||
#include "modifier/axis_sensitivty_modifier.hpp"
|
||||
#include "modifier/axismap_modifier.hpp"
|
||||
#include "modifier/button_map_modifier.hpp"
|
||||
#include "modifier/calibration_modifier.hpp"
|
||||
#include "modifier/deadzone_modifier.hpp"
|
||||
#include "modifier/dpad_rotation_modifier.hpp"
|
||||
#include "modifier/four_way_restrictor_modifier.hpp"
|
||||
#include "modifier/relativeaxis_modifier.hpp"
|
||||
#include "modifier/square_axis_modifier.hpp"
|
||||
|
||||
#include "command_line_options.hpp"
|
||||
#include "evdev_controller.hpp"
|
||||
#include "evdev_helper.hpp"
|
||||
#include "firestorm_dual_controller.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "options.hpp"
|
||||
#include "saitek_p2500_controller.hpp"
|
||||
#include "uinput.hpp"
|
||||
#include "xboxmsg.hpp"
|
||||
#include "xbox_controller.hpp"
|
||||
#include "xbox360_controller.hpp"
|
||||
#include "xbox360_wireless_controller.hpp"
|
||||
#include "firestorm_dual_controller.hpp"
|
||||
#include "saitek_p2500_controller.hpp"
|
||||
#include "evdev_controller.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "evdev_helper.hpp"
|
||||
#include "command_line_options.hpp"
|
||||
#include "options.hpp"
|
||||
#include "xbox_controller.hpp"
|
||||
#include "xbox_generic_controller.hpp"
|
||||
|
||||
#include "xboxdrv.hpp"
|
||||
#include "xboxdrv_daemon.hpp"
|
||||
#include "xboxdrv_thread.hpp"
|
||||
#include "xboxmsg.hpp"
|
||||
|
||||
// Some ugly global variables, needed for sigint catching
|
||||
bool global_exit_xboxdrv = false;
|
||||
XboxGenericController* global_controller = 0;
|
||||
|
||||
// FIXME: isolate problametic code to a separate file, instead of pragma
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
|
||||
void on_sigint(int)
|
||||
{
|
||||
if (global_exit_xboxdrv)
|
||||
|
@ -99,16 +87,6 @@ void on_sigterm(int)
|
|||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void set_rumble(XboxGenericController* controller, int gain, uint8_t lhs, uint8_t rhs)
|
||||
{
|
||||
lhs = std::min(lhs * gain / 255, 255);
|
||||
rhs = std::min(rhs * gain / 255, 255);
|
||||
|
||||
//std::cout << (int)lhs << " " << (int)rhs << std::endl;
|
||||
|
||||
controller->set_rumble(lhs, rhs);
|
||||
}
|
||||
|
||||
void
|
||||
Xboxdrv::run_list_controller()
|
||||
{
|
||||
|
@ -317,169 +295,6 @@ Xboxdrv::find_xbox360_controller(int id, libusb_device** xbox_device, XPadDevice
|
|||
}
|
||||
|
||||
void
|
||||
Xboxdrv::controller_loop(GamepadType type, uInput* uinput, XboxGenericController* controller, const Options& opts)
|
||||
{
|
||||
int timeout = 0; // 0 == no timeout
|
||||
XboxGenericMsg oldmsg; // last data send to uinput
|
||||
XboxGenericMsg oldrealmsg; // last data read from the device
|
||||
|
||||
std::vector<ModifierPtr> modifier;
|
||||
|
||||
// Create filter
|
||||
if (!opts.calibration_map.empty())
|
||||
modifier.push_back(ModifierPtr(new CalibrationModifier(opts.calibration_map)));
|
||||
|
||||
if (opts.deadzone != 0 || opts.deadzone_trigger != 0)
|
||||
modifier.push_back(ModifierPtr(new DeadzoneModifier(opts.deadzone, opts.deadzone_trigger)));
|
||||
|
||||
if (opts.square_axis)
|
||||
modifier.push_back(ModifierPtr(new SquareAxisModifier()));
|
||||
|
||||
if (!opts.axis_sensitivity_map.empty())
|
||||
modifier.push_back(ModifierPtr(new AxisSensitivityModifier(opts.axis_sensitivity_map)));
|
||||
|
||||
if (opts.four_way_restrictor)
|
||||
modifier.push_back(ModifierPtr(new FourWayRestrictorModifier()));
|
||||
|
||||
if (opts.dpad_rotation)
|
||||
modifier.push_back(ModifierPtr(new DpadRotationModifier(opts.dpad_rotation)));
|
||||
|
||||
if (!opts.autofire_map.empty())
|
||||
modifier.push_back(ModifierPtr(new AutoFireModifier(opts.autofire_map)));
|
||||
|
||||
if (!opts.relative_axis_map.empty())
|
||||
modifier.push_back(ModifierPtr(new RelativeAxisModifier(opts.relative_axis_map)));
|
||||
|
||||
if (!opts.button_map.empty())
|
||||
modifier.push_back(ModifierPtr(new ButtonMapModifier(opts.button_map)));
|
||||
|
||||
if (!opts.axis_map.empty())
|
||||
modifier.push_back(ModifierPtr(new AxismapModifier(opts.axis_map)));
|
||||
|
||||
// how long to wait for a controller event before taking care of autofire etc.
|
||||
timeout = 25;
|
||||
|
||||
memset(&oldmsg, 0, sizeof(oldmsg));
|
||||
memset(&oldrealmsg, 0, sizeof(oldrealmsg));
|
||||
|
||||
pid_t pid = -1;
|
||||
|
||||
if (!opts.exec.empty())
|
||||
{ // launch program if one was given
|
||||
pid = fork();
|
||||
if (pid == 0)
|
||||
{
|
||||
char** argv = static_cast<char**>(malloc(sizeof(char*) * opts.exec.size() + 1));
|
||||
for(size_t i = 0; i < opts.exec.size(); ++i)
|
||||
{
|
||||
argv[i] = strdup(opts.exec[i].c_str());
|
||||
}
|
||||
argv[opts.exec.size()] = NULL;
|
||||
|
||||
if (execvp(opts.exec[0].c_str(), argv) == -1)
|
||||
{
|
||||
std::cout << "error: " << opts.exec[0] << ": " << strerror(errno) << std::endl;
|
||||
// FIXME: must signal the parent process
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t last_time = get_time();
|
||||
while(!global_exit_xboxdrv)
|
||||
{
|
||||
XboxGenericMsg msg;
|
||||
|
||||
if (controller->read(msg, opts.verbose, timeout))
|
||||
{
|
||||
oldrealmsg = msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no new data read, so copy the last read data
|
||||
msg = oldrealmsg;
|
||||
}
|
||||
|
||||
// Calc changes in time
|
||||
uint32_t this_time = get_time();
|
||||
int msec_delta = this_time - last_time;
|
||||
last_time = this_time;
|
||||
|
||||
// run the controller message through all modifier
|
||||
for(std::vector<ModifierPtr>::iterator i = modifier.begin(); i != modifier.end(); ++i)
|
||||
{
|
||||
(*i)->update(msec_delta, msg);
|
||||
}
|
||||
|
||||
if (memcmp(&msg, &oldmsg, sizeof(XboxGenericMsg)) != 0)
|
||||
{ // Only send a new event out if something has changed,
|
||||
// this is useful since some controllers send events
|
||||
// even if nothing has changed, deadzone can cause this
|
||||
// too
|
||||
oldmsg = msg;
|
||||
|
||||
if (!opts.silent)
|
||||
std::cout << msg << std::endl;
|
||||
|
||||
if (uinput)
|
||||
uinput->send(msg);
|
||||
|
||||
if (opts.rumble)
|
||||
{
|
||||
if (type == GAMEPAD_XBOX)
|
||||
{
|
||||
set_rumble(controller, opts.rumble_gain, msg.xbox.lt, msg.xbox.rt);
|
||||
}
|
||||
else if (type == GAMEPAD_XBOX360 ||
|
||||
type == GAMEPAD_XBOX360_WIRELESS)
|
||||
{
|
||||
set_rumble(controller, opts.rumble_gain, msg.xbox360.lt, msg.xbox360.rt);
|
||||
}
|
||||
else if (type == GAMEPAD_FIRESTORM ||
|
||||
type == GAMEPAD_FIRESTORM_VSB)
|
||||
{
|
||||
set_rumble(controller, opts.rumble_gain,
|
||||
std::min(255, abs((msg.xbox360.y1>>8)*2)),
|
||||
std::min(255, abs((msg.xbox360.y2>>8)*2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uinput)
|
||||
{
|
||||
uinput->update(msec_delta);
|
||||
}
|
||||
|
||||
if (pid != -1)
|
||||
{
|
||||
int status = 0;
|
||||
int w = waitpid(pid, &status, WNOHANG);
|
||||
|
||||
if (w > 0)
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
{
|
||||
if (WEXITSTATUS(status) != 0)
|
||||
{
|
||||
std::cout << "error: child program has stopped with exit status " << WEXITSTATUS(status) << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "child program exited successful" << std::endl;
|
||||
}
|
||||
global_exit_xboxdrv = true;
|
||||
}
|
||||
else if (WIFSIGNALED(status))
|
||||
{
|
||||
std::cout << "error: child program was terminated by " << WTERMSIG(status) << std::endl;
|
||||
global_exit_xboxdrv = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Xboxdrv::find_controller(libusb_device** dev,
|
||||
XPadDevice& dev_type,
|
||||
const Options& opts) const
|
||||
|
@ -546,6 +361,19 @@ Xboxdrv::find_controller(libusb_device** dev,
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: duplicate code
|
||||
namespace {
|
||||
void set_rumble(XboxGenericController* controller, int gain, uint8_t lhs, uint8_t rhs)
|
||||
{
|
||||
lhs = std::min(lhs * gain / 255, 255);
|
||||
rhs = std::min(rhs * gain / 255, 255);
|
||||
|
||||
//std::cout << (int)lhs << " " << (int)rhs << std::endl;
|
||||
|
||||
controller->set_rumble(lhs, rhs);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void
|
||||
Xboxdrv::run_main(const Options& opts)
|
||||
{
|
||||
|
@ -585,9 +413,6 @@ Xboxdrv::run_main(const Options& opts)
|
|||
{
|
||||
throw std::runtime_error("-- failure --"); // FIXME
|
||||
}
|
||||
|
||||
//FIXME:usb_find_busses();
|
||||
//FIXME:usb_find_devices();
|
||||
|
||||
libusb_device* dev = 0; // FIXME: this must be libusb_unref_device()'ed, child code must not keep a copy around
|
||||
|
||||
|
@ -707,7 +532,9 @@ Xboxdrv::run_main(const Options& opts)
|
|||
}
|
||||
|
||||
global_exit_xboxdrv = false;
|
||||
controller_loop(dev_type.type, uinput.get(), controller.get(), opts);
|
||||
|
||||
XboxdrvThread loop;
|
||||
loop.controller_loop(dev_type.type, uinput.get(), controller.get(), opts);
|
||||
|
||||
if (!opts.quiet)
|
||||
std::cout << "Shutdown complete" << std::endl;
|
||||
|
@ -875,19 +702,39 @@ Xboxdrv::run_help_devices()
|
|||
void
|
||||
Xboxdrv::run_daemon(const Options& opts)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid < 0) exit(EXIT_FAILURE); /* fork error */
|
||||
if (pid > 0) exit(EXIT_SUCCESS); /* parent exits */
|
||||
|
||||
pid_t sid = setsid();
|
||||
std::cout << "Sid: " << sid << std::endl;
|
||||
if (chdir("/") != 0)
|
||||
if (true /* no_detatch */)
|
||||
{
|
||||
throw std::runtime_error(strerror(errno));
|
||||
XboxdrvDaemon daemon;
|
||||
daemon.run();
|
||||
}
|
||||
else
|
||||
{
|
||||
pid_t pid = fork();
|
||||
|
||||
run_main(opts);
|
||||
if (pid < 0)
|
||||
{ // fork error
|
||||
perror("fork");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (pid > 0)
|
||||
{ // parent, just exit
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else
|
||||
{ // child, run daemon
|
||||
pid_t sid = setsid();
|
||||
|
||||
std::cout << "Sid: " << sid << std::endl;
|
||||
|
||||
if (chdir("/") != 0)
|
||||
{
|
||||
throw std::runtime_error(strerror(errno));
|
||||
}
|
||||
|
||||
XboxdrvDaemon daemon;
|
||||
daemon.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Xboxdrv::Xboxdrv() :
|
||||
|
|
|
@ -42,9 +42,6 @@ private:
|
|||
void print_info(libusb_device* dev,
|
||||
const XPadDevice& dev_type,
|
||||
const Options& opts) const;
|
||||
void controller_loop(GamepadType type, uInput* uinput,
|
||||
XboxGenericController* controller,
|
||||
const Options& opts);
|
||||
|
||||
bool find_controller_by_path(const std::string& busid, const std::string& devid,libusb_device** xbox_device) const;
|
||||
void find_controller(libusb_device** dev,
|
||||
|
|
203
src/xboxdrv_daemon.cpp
Normal file
203
src/xboxdrv_daemon.cpp
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
** Xbox360 USB Gamepad Userspace Driver
|
||||
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
|
||||
**
|
||||
** This program 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.
|
||||
**
|
||||
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "xboxdrv_daemon.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string.h>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <stdio.h>
|
||||
|
||||
XboxdrvDaemon::XboxdrvDaemon() :
|
||||
m_udev(0),
|
||||
m_monitor(0)
|
||||
{
|
||||
m_udev = udev_new();
|
||||
|
||||
if (!m_udev)
|
||||
{
|
||||
throw std::runtime_error("udev init failure");
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: add enumerate here, see libudev example on how to avoid
|
||||
// race condition
|
||||
m_monitor = udev_monitor_new_from_netlink(m_udev, "udev");
|
||||
udev_monitor_enable_receiving(m_monitor);
|
||||
|
||||
udev_monitor_filter_add_match_subsystem_devtype(m_monitor, "usb", "usb_device");
|
||||
}
|
||||
}
|
||||
|
||||
XboxdrvDaemon::~XboxdrvDaemon()
|
||||
{
|
||||
udev_monitor_unref(m_monitor);
|
||||
udev_unref(m_udev);
|
||||
}
|
||||
|
||||
void
|
||||
XboxdrvDaemon::run()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
struct udev_device* device = udev_monitor_receive_device(m_monitor);
|
||||
|
||||
if (!device)
|
||||
{
|
||||
// seem to be normal, do we get this when the given device is filtered out?
|
||||
std::cout << "udev device couldn't be read: " << device << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* action = udev_device_get_action(device);
|
||||
|
||||
if (action && strcmp(action, "add") == 0)
|
||||
{
|
||||
// 1) Match vendor/product against the xpad list
|
||||
// value = udev_device_get_property_value(device, "ID_VENDOR_ID"); // 045e
|
||||
// value = udev_device_get_property_value(device, "ID_MODEL_ID"); // 028e
|
||||
// value = udev_device_get_property_value(device, "ID_REVISION"); // 0110 aka bcd
|
||||
// PRODUCT = "45e/28e/110"
|
||||
|
||||
const char* product_str = udev_device_get_property_value(device, "PRODUCT");
|
||||
if (product_str)
|
||||
{
|
||||
unsigned int vendor = 0;
|
||||
unsigned int product = 0;
|
||||
unsigned int bcd = 0;
|
||||
if (sscanf(product_str, "%x/%x/%x", &vendor, &product, &bcd) != 3)
|
||||
{
|
||||
std::cout << "[XboxdrvDaemon] couldn't parse PRODUCT = " << product_str << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Product parse: "
|
||||
<< boost::format("%03x/%03x/%03x == %s") % vendor % product % bcd % product_str
|
||||
<< std::endl;
|
||||
|
||||
// 2) Get busnum and devnum
|
||||
// FIXME: are those dec or hex?
|
||||
const char* busnum_str = udev_device_get_property_value(device, "BUSNUM");
|
||||
const char* devnum_str = udev_device_get_property_value(device, "DEVNUM");
|
||||
|
||||
if (busnum_str && devnum_str)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 3) Launch thread to handle the device
|
||||
launch_xboxdrv(boost::lexical_cast<int>(busnum_str),
|
||||
boost::lexical_cast<int>(devnum_str));
|
||||
}
|
||||
catch(const std::exception& err)
|
||||
{
|
||||
std::cout << "[XboxdrvDaemon] child thread lauch failure: " << err.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
udev_device_unref(device);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XboxdrvDaemon::print_info(struct udev_device* device)
|
||||
{
|
||||
std::cout << "/---------------------------------------------" << std::endl;
|
||||
std::cout << "devpath: " << udev_device_get_devpath(device) << std::endl;
|
||||
std::cout << "action: " << udev_device_get_action(device) << std::endl;
|
||||
//std::cout << "init: " << udev_device_get_is_initialized(device) << std::endl;
|
||||
|
||||
if (strcmp(udev_device_get_action(device), "add") == 0)
|
||||
{
|
||||
if (udev_device_get_subsystem(device))
|
||||
std::cout << "subsystem: " << udev_device_get_subsystem(device) << std::endl;
|
||||
|
||||
if (udev_device_get_devtype(device))
|
||||
std::cout << "devtype: " << udev_device_get_devtype(device) << std::endl;
|
||||
|
||||
if (udev_device_get_syspath(device))
|
||||
std::cout << "syspath: " << udev_device_get_syspath(device) << std::endl;
|
||||
|
||||
if (udev_device_get_sysname(device))
|
||||
std::cout << "sysname: " << udev_device_get_sysname(device) << std::endl;
|
||||
|
||||
if (udev_device_get_sysnum(device))
|
||||
std::cout << "sysnum: " << udev_device_get_sysnum(device) << std::endl;
|
||||
|
||||
if (udev_device_get_devnode(device))
|
||||
std::cout << "devnode: " << udev_device_get_devnode(device) << std::endl;
|
||||
|
||||
if (udev_device_get_driver(device))
|
||||
std::cout << "driver: " << udev_device_get_driver(device) << std::endl;
|
||||
|
||||
if (udev_device_get_action(device))
|
||||
std::cout << "action: " << udev_device_get_action(device) << std::endl;
|
||||
|
||||
udev_device_get_sysattr_value(device, "busnum");
|
||||
udev_device_get_sysattr_value(device, "devnum");
|
||||
|
||||
{
|
||||
std::cout << "list: " << std::endl;
|
||||
struct udev_list_entry* it = udev_device_get_tags_list_entry(device);
|
||||
while((it = udev_list_entry_get_next(it)) != 0)
|
||||
{
|
||||
std::cout << " "
|
||||
<< udev_list_entry_get_name(it) << " = "
|
||||
<< udev_list_entry_get_value(it)
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "properties: " << std::endl;
|
||||
struct udev_list_entry* it = udev_device_get_properties_list_entry(device);
|
||||
while((it = udev_list_entry_get_next(it)) != 0)
|
||||
{
|
||||
std::cout << " "
|
||||
<< udev_list_entry_get_name(it) << " = "
|
||||
<< udev_list_entry_get_value(it)
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "devlist: " << std::endl;
|
||||
struct udev_list_entry* it = udev_device_get_tags_list_entry(device);
|
||||
while((it = udev_list_entry_get_next(it)) != 0)
|
||||
{
|
||||
std::cout << " "
|
||||
<< udev_list_entry_get_name(it) << " = "
|
||||
<< udev_list_entry_get_value(it)
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "\\----------------------------------------------" << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
XboxdrvDaemon::launch_xboxdrv(uint8_t busnum, uint8_t devnum)
|
||||
{
|
||||
std::cout << "[XboxdrvDaemon] launching " << boost::format("%03d:%03d") % busnum % devnum << std::endl;
|
||||
}
|
||||
|
||||
/* EOF */
|
48
src/xboxdrv_daemon.hpp
Normal file
48
src/xboxdrv_daemon.hpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
** Xbox360 USB Gamepad Userspace Driver
|
||||
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
|
||||
**
|
||||
** This program 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.
|
||||
**
|
||||
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HEADER_XBOXDRV_XBOXDRV_DAEMON_HPP
|
||||
#define HEADER_XBOXDRV_XBOXDRV_DAEMON_HPP
|
||||
|
||||
#include <libudev.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class XboxdrvDaemon
|
||||
{
|
||||
private:
|
||||
struct udev* m_udev;
|
||||
struct udev_monitor* m_monitor;
|
||||
|
||||
public:
|
||||
XboxdrvDaemon();
|
||||
~XboxdrvDaemon();
|
||||
|
||||
void run();
|
||||
|
||||
private:
|
||||
void print_info(struct udev_device* device);
|
||||
void launch_xboxdrv(uint8_t busnum, uint8_t devnum);
|
||||
|
||||
private:
|
||||
XboxdrvDaemon(const XboxdrvDaemon&);
|
||||
XboxdrvDaemon& operator=(const XboxdrvDaemon&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
236
src/xboxdrv_thread.cpp
Normal file
236
src/xboxdrv_thread.cpp
Normal file
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
** Xbox360 USB Gamepad Userspace Driver
|
||||
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
|
||||
**
|
||||
** This program 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.
|
||||
**
|
||||
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "xboxdrv_thread.hpp"
|
||||
|
||||
#include <errno.h>
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <vector>
|
||||
|
||||
#include "helper.hpp"
|
||||
#include "modifier.hpp"
|
||||
#include "options.hpp"
|
||||
#include "uinput.hpp"
|
||||
#include "xbox_generic_controller.hpp"
|
||||
|
||||
#include "modifier/autofire_modifier.hpp"
|
||||
#include "modifier/axis_sensitivty_modifier.hpp"
|
||||
#include "modifier/axismap_modifier.hpp"
|
||||
#include "modifier/button_map_modifier.hpp"
|
||||
#include "modifier/calibration_modifier.hpp"
|
||||
#include "modifier/deadzone_modifier.hpp"
|
||||
#include "modifier/dpad_rotation_modifier.hpp"
|
||||
#include "modifier/four_way_restrictor_modifier.hpp"
|
||||
#include "modifier/relativeaxis_modifier.hpp"
|
||||
#include "modifier/square_axis_modifier.hpp"
|
||||
|
||||
extern bool global_exit_xboxdrv;
|
||||
|
||||
// FIXME: isolate problametic code to a separate file, instead of pragma
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
|
||||
XboxdrvThread::XboxdrvThread()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
XboxdrvThread::run()
|
||||
{
|
||||
}
|
||||
|
||||
// FIXME: duplicate code
|
||||
namespace {
|
||||
void set_rumble(XboxGenericController* controller, int gain, uint8_t lhs, uint8_t rhs)
|
||||
{
|
||||
lhs = std::min(lhs * gain / 255, 255);
|
||||
rhs = std::min(rhs * gain / 255, 255);
|
||||
|
||||
//std::cout << (int)lhs << " " << (int)rhs << std::endl;
|
||||
|
||||
controller->set_rumble(lhs, rhs);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void
|
||||
XboxdrvThread::controller_loop(GamepadType type, uInput* uinput, XboxGenericController* controller,
|
||||
const Options& opts)
|
||||
{
|
||||
int timeout = 0; // 0 == no timeout
|
||||
XboxGenericMsg oldmsg; // last data send to uinput
|
||||
XboxGenericMsg oldrealmsg; // last data read from the device
|
||||
|
||||
std::vector<ModifierPtr> modifier;
|
||||
|
||||
// Create filter
|
||||
if (!opts.calibration_map.empty())
|
||||
modifier.push_back(ModifierPtr(new CalibrationModifier(opts.calibration_map)));
|
||||
|
||||
if (opts.deadzone != 0 || opts.deadzone_trigger != 0)
|
||||
modifier.push_back(ModifierPtr(new DeadzoneModifier(opts.deadzone, opts.deadzone_trigger)));
|
||||
|
||||
if (opts.square_axis)
|
||||
modifier.push_back(ModifierPtr(new SquareAxisModifier()));
|
||||
|
||||
if (!opts.axis_sensitivity_map.empty())
|
||||
modifier.push_back(ModifierPtr(new AxisSensitivityModifier(opts.axis_sensitivity_map)));
|
||||
|
||||
if (opts.four_way_restrictor)
|
||||
modifier.push_back(ModifierPtr(new FourWayRestrictorModifier()));
|
||||
|
||||
if (opts.dpad_rotation)
|
||||
modifier.push_back(ModifierPtr(new DpadRotationModifier(opts.dpad_rotation)));
|
||||
|
||||
if (!opts.autofire_map.empty())
|
||||
modifier.push_back(ModifierPtr(new AutoFireModifier(opts.autofire_map)));
|
||||
|
||||
if (!opts.relative_axis_map.empty())
|
||||
modifier.push_back(ModifierPtr(new RelativeAxisModifier(opts.relative_axis_map)));
|
||||
|
||||
if (!opts.button_map.empty())
|
||||
modifier.push_back(ModifierPtr(new ButtonMapModifier(opts.button_map)));
|
||||
|
||||
if (!opts.axis_map.empty())
|
||||
modifier.push_back(ModifierPtr(new AxismapModifier(opts.axis_map)));
|
||||
|
||||
// how long to wait for a controller event before taking care of autofire etc.
|
||||
timeout = 25;
|
||||
|
||||
memset(&oldmsg, 0, sizeof(oldmsg));
|
||||
memset(&oldrealmsg, 0, sizeof(oldrealmsg));
|
||||
|
||||
pid_t pid = -1;
|
||||
|
||||
if (!opts.exec.empty())
|
||||
{ // launch program if one was given
|
||||
pid = fork();
|
||||
if (pid == 0)
|
||||
{
|
||||
char** argv = static_cast<char**>(malloc(sizeof(char*) * opts.exec.size() + 1));
|
||||
for(size_t i = 0; i < opts.exec.size(); ++i)
|
||||
{
|
||||
argv[i] = strdup(opts.exec[i].c_str());
|
||||
}
|
||||
argv[opts.exec.size()] = NULL;
|
||||
|
||||
if (execvp(opts.exec[0].c_str(), argv) == -1)
|
||||
{
|
||||
std::cout << "error: " << opts.exec[0] << ": " << strerror(errno) << std::endl;
|
||||
// FIXME: must signal the parent process
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t last_time = get_time();
|
||||
while(!global_exit_xboxdrv)
|
||||
{
|
||||
XboxGenericMsg msg;
|
||||
|
||||
if (controller->read(msg, opts.verbose, timeout))
|
||||
{
|
||||
oldrealmsg = msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no new data read, so copy the last read data
|
||||
msg = oldrealmsg;
|
||||
}
|
||||
|
||||
// Calc changes in time
|
||||
uint32_t this_time = get_time();
|
||||
int msec_delta = this_time - last_time;
|
||||
last_time = this_time;
|
||||
|
||||
// run the controller message through all modifier
|
||||
for(std::vector<ModifierPtr>::iterator i = modifier.begin(); i != modifier.end(); ++i)
|
||||
{
|
||||
(*i)->update(msec_delta, msg);
|
||||
}
|
||||
|
||||
if (memcmp(&msg, &oldmsg, sizeof(XboxGenericMsg)) != 0)
|
||||
{ // Only send a new event out if something has changed,
|
||||
// this is useful since some controllers send events
|
||||
// even if nothing has changed, deadzone can cause this
|
||||
// too
|
||||
oldmsg = msg;
|
||||
|
||||
if (!opts.silent)
|
||||
std::cout << msg << std::endl;
|
||||
|
||||
if (uinput)
|
||||
uinput->send(msg);
|
||||
|
||||
if (opts.rumble)
|
||||
{
|
||||
if (type == GAMEPAD_XBOX)
|
||||
{
|
||||
set_rumble(controller, opts.rumble_gain, msg.xbox.lt, msg.xbox.rt);
|
||||
}
|
||||
else if (type == GAMEPAD_XBOX360 ||
|
||||
type == GAMEPAD_XBOX360_WIRELESS)
|
||||
{
|
||||
set_rumble(controller, opts.rumble_gain, msg.xbox360.lt, msg.xbox360.rt);
|
||||
}
|
||||
else if (type == GAMEPAD_FIRESTORM ||
|
||||
type == GAMEPAD_FIRESTORM_VSB)
|
||||
{
|
||||
set_rumble(controller, opts.rumble_gain,
|
||||
std::min(255, abs((msg.xbox360.y1>>8)*2)),
|
||||
std::min(255, abs((msg.xbox360.y2>>8)*2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uinput)
|
||||
{
|
||||
uinput->update(msec_delta);
|
||||
}
|
||||
|
||||
if (pid != -1)
|
||||
{
|
||||
int status = 0;
|
||||
int w = waitpid(pid, &status, WNOHANG);
|
||||
|
||||
if (w > 0)
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
{
|
||||
if (WEXITSTATUS(status) != 0)
|
||||
{
|
||||
std::cout << "error: child program has stopped with exit status " << WEXITSTATUS(status) << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "child program exited successful" << std::endl;
|
||||
}
|
||||
global_exit_xboxdrv = true;
|
||||
}
|
||||
else if (WIFSIGNALED(status))
|
||||
{
|
||||
std::cout << "error: child program was terminated by " << WTERMSIG(status) << std::endl;
|
||||
global_exit_xboxdrv = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* EOF */
|
45
src/xboxdrv_thread.hpp
Normal file
45
src/xboxdrv_thread.hpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
** Xbox360 USB Gamepad Userspace Driver
|
||||
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
|
||||
**
|
||||
** This program 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.
|
||||
**
|
||||
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HEADER_XBOXDRV_XBOXDRV_THREAD_HPP
|
||||
#define HEADER_XBOXDRV_XBOXDRV_THREAD_HPP
|
||||
|
||||
#include "xboxmsg.hpp"
|
||||
|
||||
class Options;
|
||||
class uInput;
|
||||
class XboxGenericController;
|
||||
|
||||
class XboxdrvThread // FIXME: find a better name, XboxdrvControllerLoop?!
|
||||
{
|
||||
private:
|
||||
public:
|
||||
XboxdrvThread();
|
||||
|
||||
void controller_loop(GamepadType type, uInput* uinput, XboxGenericController* controller,
|
||||
const Options& opts);
|
||||
void run();
|
||||
|
||||
private:
|
||||
XboxdrvThread(const XboxdrvThread&);
|
||||
XboxdrvThread& operator=(const XboxdrvThread&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
Loading…
Reference in a new issue