It appears to be working

This commit is contained in:
Benjamin Höglinger-Stelzer
2019-04-22 14:03:14 +02:00
parent 3f1286cbc9
commit 3408227bb1
7 changed files with 115 additions and 151 deletions

View File

@@ -22,10 +22,14 @@ VOID CALLBACK notification(
{
m.lock();
//std::cout.width(3);
//std::cout << (int)LargeMotor << " ";
//std::cout.width(3);
//std::cout << (int)SmallMotor << std::endl;
static int count = 1;
std::cout.width(3);
std::cout << count++ << " ";
std::cout.width(3);
std::cout << (int)LargeMotor << " ";
std::cout.width(3);
std::cout << (int)SmallMotor << std::endl;
m.unlock();
}

View File

@@ -22,6 +22,8 @@ typedef enum _VIGEM_TARGET_STATE
VIGEM_TARGET_DISCONNECTED
} VIGEM_TARGET_STATE, *PVIGEM_TARGET_STATE;
class NotificationRequestPool;
//
// Represents a virtual gamepad object.
//
@@ -35,14 +37,6 @@ typedef struct _VIGEM_TARGET_T
VIGEM_TARGET_TYPE Type;
DWORD_PTR Notification;
boost::shared_ptr<boost::asio::io_service> io_svc;
boost::shared_ptr<boost::asio::io_service::work> worker;
boost::shared_ptr<boost::thread_group> worker_threads;
boost::shared_ptr<boost::mutex> enqueue_lock;
std::shared_ptr<NotificationRequestPool> pool;
HANDLE WaitHandles[VIGEM_INVERTED_CALL_THREAD_COUNT];
std::vector<XusbNotificationRequest*> notify_req;
} VIGEM_TARGET;

View File

@@ -1,27 +1,48 @@
#include "NotificationRequestPool.h"
void NotificationRequestPool::strand_dispatch_worker() const
{
io_svc_->run();
}
NotificationRequestPool::NotificationRequestPool(
HANDLE bus,
const ULONG serial,
PFN_VIGEM_X360_NOTIFICATION callback) :
PVIGEM_CLIENT client,
PVIGEM_TARGET target,
PFN_VIGEM_X360_NOTIFICATION callback
) :
client_(client),
target_(target),
callback_(callback),
stop_(false)
{
// prepare array of handles and request wrappers
for (auto& wait_handle : wait_handles_)
{
// create auto-reset event
wait_handle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
XusbNotificationRequest req(bus, serial, wait_handle);
requests_.push_back(std::ref(req));
// create async pending I/O request wrapper
auto req = new XusbNotificationRequest(
client_->hBusDevice,
target_->SerialNo,
wait_handle
);
requests_.push_back(req);
}
// init ASIO
io_svc_.reset(new boost::asio::io_service());
worker_.reset(new boost::asio::io_service::work(*io_svc_));
worker_threads_.reset(new boost::thread_group());
// launch notification completion thread
thread_ = std::make_shared<boost::thread>(boost::ref(*this));
// launch boost I/O service dispatcher thread
worker_thread_ = std::make_shared<boost::thread>(
boost::bind(&NotificationRequestPool::strand_dispatch_worker, this));
// submit pending I/O to driver
for (auto& request : requests_)
request.get().request_async();
request->request_async();
}
NotificationRequestPool::~NotificationRequestPool()
@@ -29,46 +50,64 @@ NotificationRequestPool::~NotificationRequestPool()
for (auto& wait_handle : wait_handles_)
CloseHandle(wait_handle);
io_svc_->stop();
worker_thread_->join();
thread_->join();
}
void NotificationRequestPool::operator()()
{
// used to dispatch notification callback
boost::asio::io_service::strand strand(*io_svc_);
while (true)
{
// wait for the first pending I/O to signal its event
const auto ret = WaitForMultipleObjects(
requests_.size(),
wait_handles_,
FALSE,
INFINITE
25
);
// timeout has occurred...
if (ret == WAIT_TIMEOUT)
{
// ...check for termination request
boost::mutex::scoped_lock lock(m_);
if (stop_)
// exits function (terminates thread)
break;
// go for another round
continue;
}
// index of the request which just got completed
const auto index = ret - WAIT_OBJECT_0;
auto& req = requests_[index].get();
// grab associated request
const auto req = requests_[index];
//const boost::function<void(
// PVIGEM_CLIENT,
// PVIGEM_TARGET,
// UCHAR,
// UCHAR,
// UCHAR
// )> pfn = callback_;
// prepare queueing library caller notification callback
const boost::function<void(
PVIGEM_CLIENT,
PVIGEM_TARGET,
UCHAR,
UCHAR,
UCHAR)> pfn = callback_;
//strand.post(boost::bind(pfn,
// client,
// target,
// notify.LargeMotor,
// notify.SmallMotor,
// notify.LedNumber
//));
// submit callback for async yet ordered invocation
strand.post(boost::bind(pfn,
client_,
target_,
req->get_large_motor(),
req->get_small_motor(),
req->get_led_number()
));
req.request_async();
boost::mutex::scoped_lock lock(m_);
if (stop_)
break;
// submit another pending I/O
req->request_async();
}
}

View File

@@ -7,6 +7,7 @@
#include <vector>
#include "XusbNotificationRequest.h"
#include "ViGEm/Client.h"
#include "Internal.h"
#define VIGEM_INVERTED_CALL_THREAD_COUNT 20
@@ -14,8 +15,12 @@
class NotificationRequestPool
{
HANDLE wait_handles_[VIGEM_INVERTED_CALL_THREAD_COUNT]{};
PVIGEM_CLIENT client_;
PVIGEM_TARGET target_;
PFN_VIGEM_X360_NOTIFICATION callback_;
std::vector<std::reference_wrapper<XusbNotificationRequest>> requests_;
std::vector<XusbNotificationRequest*> requests_;
std::shared_ptr<boost::thread> thread_;
boost::mutex m_;
boost::condition_variable cv_;
@@ -23,10 +28,16 @@ class NotificationRequestPool
boost::shared_ptr<boost::asio::io_service> io_svc_;
boost::shared_ptr<boost::asio::io_service::work> worker_;
boost::shared_ptr<boost::thread_group> worker_threads_;
std::shared_ptr<boost::thread> worker_thread_;
void strand_dispatch_worker() const;
public:
NotificationRequestPool(HANDLE bus, ULONG serial, PFN_VIGEM_X360_NOTIFICATION callback);
NotificationRequestPool(
PVIGEM_CLIENT client,
PVIGEM_TARGET target,
PFN_VIGEM_X360_NOTIFICATION callback
);
~NotificationRequestPool();
void operator()();

View File

@@ -98,14 +98,6 @@ PVIGEM_TARGET FORCEINLINE VIGEM_TARGET_ALLOC_INIT(
target->State = VIGEM_TARGET_INITIALIZED;
target->Type = Type;
target->io_svc.reset(new boost::asio::io_service());
target->worker.reset(new boost::asio::io_service::work(*target->io_svc));
target->worker_threads.reset(new boost::thread_group());
target->enqueue_lock.reset(new boost::mutex());
for (auto& WaitHandle : target->WaitHandles)
WaitHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
return target;
}
@@ -139,81 +131,6 @@ LONG WINAPI vigem_internal_exception_handler(struct _EXCEPTION_POINTERS* apExcep
return EXCEPTION_CONTINUE_SEARCH;
}
void vigem_internal_x360_notification_worker(
PVIGEM_TARGET target,
PVIGEM_CLIENT client
)
{
DWORD error = ERROR_SUCCESS;
DWORD transferred = 0;
OVERLAPPED lOverlapped = { 0 };
lOverlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
boost::asio::io_service::strand strand(*target->io_svc);
XUSB_REQUEST_NOTIFICATION notify;
XUSB_REQUEST_NOTIFICATION_INIT(&notify, target->SerialNo);
static std::mutex m;
do
{
DeviceIoControl(client->hBusDevice,
IOCTL_XUSB_REQUEST_NOTIFICATION,
&notify,
notify.Size,
&notify,
notify.Size,
&transferred,
&lOverlapped);
if (GetOverlappedResult(client->hBusDevice, &lOverlapped, &transferred, TRUE) != 0)
{
m.lock();
auto timestamp = std::chrono::high_resolution_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::nanoseconds>(timestamp.time_since_epoch()).count() << " ";
std::cout.width(3);
std::cout << (int)notify.LargeMotor << " ";
std::cout.width(3);
std::cout << (int)notify.SmallMotor << std::endl;
m.unlock();
if (target->Notification == NULL)
{
if (lOverlapped.hEvent)
CloseHandle(lOverlapped.hEvent);
return;
}
target->enqueue_lock->lock();
const boost::function<void(
PVIGEM_CLIENT,
PVIGEM_TARGET,
UCHAR,
UCHAR,
UCHAR
)> pfn = PFN_VIGEM_X360_NOTIFICATION(target->Notification);
strand.post(boost::bind(pfn,
client,
target,
notify.LargeMotor,
notify.SmallMotor,
notify.LedNumber
));
target->enqueue_lock->unlock();
target->io_svc->poll();
}
else
{
error = GetLastError();
}
} while (error != ERROR_OPERATION_ABORTED && error != ERROR_ACCESS_DENIED);
if (lOverlapped.hEvent)
CloseHandle(lOverlapped.hEvent);
}
PVIGEM_CLIENT vigem_alloc()
{
SetUnhandledExceptionFilter(vigem_internal_exception_handler);
@@ -392,11 +309,7 @@ PVIGEM_TARGET vigem_target_ds4_alloc(void)
void vigem_target_free(PVIGEM_TARGET target)
{
if (target)
{
target->io_svc->stop();
free(target);
}
}
VIGEM_ERROR vigem_target_add(PVIGEM_CLIENT vigem, PVIGEM_TARGET target)
@@ -605,8 +518,8 @@ VIGEM_ERROR vigem_target_x360_register_notification(
//}
target->pool = std::make_shared<NotificationRequestPool>(
vigem->hBusDevice,
target->SerialNo,
vigem,
target,
PFN_VIGEM_X360_NOTIFICATION(target->Notification)
);

View File

@@ -5,41 +5,45 @@ XusbNotificationRequest::XusbNotificationRequest(
HANDLE bus,
ULONG serial,
HANDLE notification
) : parent_bus(bus),
payload(), transferred(0),
overlapped()
) : parent_bus_(bus),
payload_(),
overlapped_()
{
overlapped.hEvent = notification;
XUSB_REQUEST_NOTIFICATION_INIT(&payload, serial);
memset(&overlapped_, 0, sizeof(OVERLAPPED));
overlapped_.hEvent = notification;
XUSB_REQUEST_NOTIFICATION_INIT(&payload_, serial);
}
bool XusbNotificationRequest::request_async()
{
// queue request in driver
const auto ret = DeviceIoControl(
parent_bus,
parent_bus_,
IOCTL_XUSB_REQUEST_NOTIFICATION,
&payload,
payload.Size,
&payload,
payload.Size,
&payload_,
payload_.Size,
&payload_,
payload_.Size,
nullptr,
&overlapped
&overlapped_
);
return (!ret && GetLastError() == ERROR_IO_PENDING);
const auto error = GetLastError();
return (!ret && error == ERROR_IO_PENDING);
}
UCHAR XusbNotificationRequest::get_led_number() const
{
return payload.LedNumber;
return payload_.LedNumber;
}
UCHAR XusbNotificationRequest::get_large_motor() const
{
return payload.LargeMotor;
return payload_.LargeMotor;
}
UCHAR XusbNotificationRequest::get_small_motor() const
{
return payload.SmallMotor;
return payload_.SmallMotor;
}

View File

@@ -5,10 +5,9 @@
class XusbNotificationRequest
{
HANDLE parent_bus;
XUSB_REQUEST_NOTIFICATION payload;
DWORD transferred;
OVERLAPPED overlapped;
HANDLE parent_bus_;
XUSB_REQUEST_NOTIFICATION payload_;
OVERLAPPED overlapped_;
public:
XusbNotificationRequest(HANDLE bus, ULONG serial, HANDLE notification);