Skip to content
6 changes: 6 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
BasedOnStyle: LLVM
IndentWidth: 4
---
Language: Cpp
ColumnLimit: 100
102 changes: 41 additions & 61 deletions controller/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,72 +296,52 @@ void Controller::inputFeedbackReceived(
rumble.setRightTrigger = true;
rumble.setLeftTrigger = true;

if (replayCount == 0 || gain == 0)
{
rumbleBuffer.put(rumble);
rumbleCondition.notify_one();

return;
}

Log::debug(
"Rumble strong: %d, weak: %d, direction: %d",
effect.u.rumble.strong_magnitude,
effect.u.rumble.weak_magnitude,
effect.direction
);

// Apply force feedback gain
uint16_t weak = static_cast<uint32_t>(
effect.u.rumble.strong_magnitude
) * gain / 0xffff;
uint16_t strong = static_cast<uint32_t>(
effect.u.rumble.weak_magnitude
) * gain / 0xffff;
if ((replayCount > 0) && (gain > 0)) {
Log::debug("Rumble strong: %d, weak: %d, direction: %d", effect.u.rumble.strong_magnitude,
effect.u.rumble.weak_magnitude, effect.direction);

// Apply force feedback gain
uint16_t weak = static_cast<uint32_t>(effect.u.rumble.strong_magnitude) * gain / 0xffff;
uint16_t strong = static_cast<uint32_t>(effect.u.rumble.weak_magnitude) * gain / 0xffff;

// Map effect's magnitudes to rumble power
rumble.left = weak * RUMBLE_MAX_POWER / 0xffff;
rumble.right = strong * RUMBLE_MAX_POWER / 0xffff;

// Upper half of the controller (from left to right)
if (effect.direction >= 0x4000 && effect.direction <= 0xc000) {
// Angle shifted by an eighth of a full circle
float angle = static_cast<float>(effect.direction) / 0xffff - 0.125;
float left = sin(2 * M_PI * angle);
float right = cos(2 * M_PI * angle);
uint8_t maxPower = rumble.left > rumble.right ? rumble.left : rumble.right;

// Limit values to left and right areas
left = left > 0 ? left : 0;
right = right < 0 ? -right : 0;

// The trigger motors are very strong
rumble.leftTrigger = left * maxPower / 2;
rumble.rightTrigger = right * maxPower / 2;
}

// Map effect's magnitudes to rumble power
rumble.left = weak * RUMBLE_MAX_POWER / 0xffff;
rumble.right = strong * RUMBLE_MAX_POWER / 0xffff;
uint16_t duration = effect.replay.length / 10;
uint16_t delay = effect.replay.delay / 10;

// Upper half of the controller (from left to right)
if (effect.direction >= 0x4000 && effect.direction <= 0xc000)
{
// Angle shifted by an eighth of a full circle
float angle = static_cast<float>(effect.direction) / 0xffff - 0.125;
float left = sin(2 * M_PI * angle);
float right = cos(2 * M_PI * angle);
uint8_t maxPower = rumble.left > rumble.right ?
rumble.left :
rumble.right;

// Limit values to left and right areas
left = left > 0 ? left : 0;
right = right < 0 ? -right : 0;

// The trigger motors are very strong
rumble.leftTrigger = left * maxPower / 2;
rumble.rightTrigger = right * maxPower / 2;
}

uint16_t duration = effect.replay.length / 10;
uint16_t delay = effect.replay.delay / 10;
// Use maximum duration if not specified or out of range
if (duration == 0x00 || duration > 0xff) {
duration = 0xff;
}

// Use maximum duration if not specified or out of range
if (duration == 0x00 || duration > 0xff)
{
duration = 0xff;
}
if (delay > 0xff) {
delay = 0xff;
}

if (delay > 0xff)
{
delay = 0xff;
// Time in multiples of 10 ms
rumble.duration = duration;
rumble.delay = delay;
rumble.repeat = replayCount - 1;
}

// Time in multiples of 10 ms
rumble.duration = duration;
rumble.delay = delay;
rumble.repeat = replayCount - 1;

rumbleBuffer.put(rumble);
rumbleCondition.notify_one();
}
4 changes: 0 additions & 4 deletions install/service.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@
Description=Xbox One Wireless Dongle Driver

[Service]
Type=idle
ExecStart=#BINDIR#/xow
DynamicUser=true
Restart=on-success

# Uncomment the following line to enable compatibility mode
# Environment="XOW_COMPATIBILITY=1"

[Install]
WantedBy=multi-user.target
5 changes: 5 additions & 0 deletions install/udev.rules
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="02e6", MODE:="0666
SUBSYSTEM=="usb", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="02fe", MODE:="0666"
SUBSYSTEM=="usb", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="091e", MODE:="0666"
KERNEL=="uinput", SUBSYSTEM=="misc", MODE:="0666"

# Start service when dongle is plugged in
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="02e6", TAG+="systemd", ENV{SYSTEMD_WANTS}="xow.service"
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="02fe", TAG+="systemd", ENV{SYSTEMD_WANTS}="xow.service"
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="091e", TAG+="systemd", ENV{SYSTEMD_WANTS}="xow.service"
15 changes: 10 additions & 5 deletions utils/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@

#pragma once

#include <memory>
#include <atomic>
#include <memory>
#include <mutex>

/*
* Single consumer/producer lock-free triple buffer implementation
* Concurrent access from multiple consumers or producers requires locking
* Lock-free triple buffer implementation
*/
template<typename T>
class Buffer
Expand All @@ -33,6 +33,8 @@ class Buffer

void put(const T &data)
{
std::lock_guard<std::mutex> lock(put_mutex);

*back = data;

// Swap middle buffer with back buffer
Expand All @@ -44,6 +46,8 @@ class Buffer

bool get(T &data)
{
std::lock_guard<std::mutex> lock(get_mutex);

if (!std::atomic_exchange(&queued, false))
{
return false;
Expand All @@ -59,6 +63,7 @@ class Buffer
}

private:
std::shared_ptr<T> back, middle, front;
std::atomic<bool> queued;
std::mutex put_mutex, get_mutex;
std::shared_ptr<T> back, middle, front;
std::atomic<bool> queued;
};
38 changes: 25 additions & 13 deletions utils/log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,19 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "log.h"
#include <iomanip>
#include <map>
#include <sstream>
#include <thread>

#include "bytes.h"
#include "log.h"

#include <sstream>
#include <iomanip>
static std::map<int, std::string> map_level = {
{LOG_DEBUG, "DEBUG"},
{LOG_INFO, "INFO"},
{LOG_ERROR, "ERROR"},
};

namespace Log
{
Expand All @@ -44,20 +52,24 @@ namespace Log
return output;
}

std::string formatLog(std::string level, std::string message)
{
std::string formatLog(const int syslog_level, std::string message) {
std::ostringstream stream;
std::time_t time = std::time(nullptr);
std::tm localTime = {};

// Add local time to output if available
if (localtime_r(&time, &localTime))
{
stream << std::put_time(&localTime, "%F %T") << " ";
// Add local time to output if available and not logging to journald
if (!getenv("JOURNAL_STREAM")) {
std::time_t time = std::time(nullptr);
std::tm localTime = {};
if (localtime_r(&time, &localTime)) {
stream << std::put_time(&localTime, "%F %T") << " ";
}
stream << "[" << std::left << std::setw(5);
stream << map_level[syslog_level] << "] [";
} else {
stream << "<" << syslog_level << ">[";
}

stream << std::left << std::setw(5);
stream << level << " - ";
stream << std::hex << std::setw(16) << std::right;
stream << std::this_thread::get_id() << "] - ";
stream << message << std::endl;

return stream.str();
Expand Down
18 changes: 11 additions & 7 deletions utils/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@

#include <string>

#define LOG_DEBUG 7
#define LOG_INFO 6
#define LOG_ERROR 3

class Bytes;

/*
Expand All @@ -29,7 +33,7 @@ class Bytes;
namespace Log
{
std::string formatBytes(const Bytes &bytes);
std::string formatLog(std::string level, std::string message);
std::string formatLog(const int syslog_level, std::string message);

inline void init()
{
Expand All @@ -40,7 +44,7 @@ namespace Log
inline void debug(std::string message)
{
#ifdef DEBUG
std::string output = formatLog("DEBUG", message);
std::string output = formatLog(LOG_DEBUG, message);
std::fputs(output.c_str(), stdout);
#endif
}
Expand All @@ -49,34 +53,34 @@ namespace Log
inline void debug(std::string message, Args... args)
{
#ifdef DEBUG
std::string output = formatLog("DEBUG", message);
std::string output = formatLog(LOG_DEBUG, message);
std::fprintf(stdout, output.c_str(), args...);
#endif
}

inline void info(std::string message)
{
std::string output = formatLog("INFO", message);
std::string output = formatLog(LOG_INFO, message);
std::fputs(output.c_str(), stdout);
}

template<typename... Args>
inline void info(std::string message, Args... args)
{
std::string output = formatLog("INFO", message);
std::string output = formatLog(LOG_INFO, message);
std::fprintf(stdout, output.c_str(), args...);
}

inline void error(std::string message)
{
std::string output = formatLog("ERROR", message);
std::string output = formatLog(LOG_ERROR, message);
std::fputs(output.c_str(), stderr);
}

template<typename... Args>
inline void error(std::string message, Args... args)
{
std::string output = formatLog("ERROR", message);
std::string output = formatLog(LOG_ERROR, message);
std::fprintf(stderr, output.c_str(), args...);
}
}