2024-09-24 16:24:05 +00:00
|
|
|
#include "SkyPortalIO.h"
|
|
|
|
|
|
|
|
DEFINE_LOG_CATEGORY(LogHIDApi);
|
|
|
|
DEFINE_LOG_CATEGORY(LogSkyportalIO);
|
|
|
|
|
2024-09-24 22:17:52 +00:00
|
|
|
|
|
|
|
//Constructor
|
|
|
|
USkyPortalIO::USkyPortalIO()
|
|
|
|
{
|
|
|
|
OpenPortalHandle();
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool USkyPortalIO::OpenPortalHandle() {
|
2024-09-24 16:24:05 +00:00
|
|
|
//reset
|
|
|
|
if (PortalDevice) {
|
|
|
|
hid_close(PortalDevice);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
Declare two pointers to hold information about HID devices.
|
|
|
|
"list" will point to the head of the linked list of devices,
|
|
|
|
"attributes" will be used to iterate through the list.
|
|
|
|
*/
|
|
|
|
struct hid_device_info* list, * attributes;
|
|
|
|
|
|
|
|
list = hid_enumerate(0x0, 0x0);
|
|
|
|
// If `list` is NULL, that means no devices were found or there was an error.
|
|
|
|
// In this case, print an error message and terminate the program.
|
|
|
|
if (!list) {
|
|
|
|
UE_LOG(LogHIDApi, Error, TEXT("No devices found"));
|
|
|
|
// Get the error message from the HIDAPI
|
|
|
|
HidError = hid_error(NULL);
|
|
|
|
UE_LOG(LogHIDApi, Error, TEXT("%s"), *HidError);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
attributes = list;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Iterate through the linked list of devices
|
|
|
|
int vendorCount = sizeof(VendorIds) / sizeof(VendorIds[0]);
|
|
|
|
int productCount = sizeof(ProductIds) / sizeof(ProductIds[0]);
|
|
|
|
|
|
|
|
while (attributes) {
|
|
|
|
// Check if the devices match any of vendor_id and product_id
|
|
|
|
for (int i = 0; i < vendorCount; i++) {
|
|
|
|
for (int j = 0; j < productCount; j++) {
|
|
|
|
if (attributes->vendor_id == VendorIds[i] && attributes->product_id == ProductIds[j]) {
|
|
|
|
UE_LOG(LogHIDApi, Display, TEXT("Portal found"));
|
|
|
|
UE_LOG(LogHIDApi, Log, TEXT("Vendor ID: 0x%x, Product ID: 0x%x"), attributes->vendor_id, attributes->product_id);
|
|
|
|
|
|
|
|
PortalDevice = hid_open(attributes->vendor_id, attributes->product_id, NULL);
|
|
|
|
if (PortalDevice) {
|
|
|
|
UE_LOG(LogHIDApi, Display, TEXT("Successful connection to Portal."));
|
|
|
|
|
|
|
|
// Free the device list
|
|
|
|
hid_free_enumeration(list);
|
|
|
|
//bPortalConnected = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move to the next device in the list
|
|
|
|
attributes = attributes->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free the device list
|
|
|
|
hid_free_enumeration(list);
|
|
|
|
UE_LOG(LogHIDApi, Error, TEXT("No Portals found"));
|
|
|
|
return false;
|
|
|
|
}
|
2024-09-24 22:17:52 +00:00
|
|
|
|
|
|
|
// write function need to be different on windows, as hid_write doesn't work with the way windows handle I/O
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
|
|
|
|
#include <Windows.h>
|
|
|
|
|
|
|
|
#define HID_CTL_CODE(id) \
|
|
|
|
CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_NEITHER, FILE_ANY_ACCESS)
|
|
|
|
#define HID_IN_CTL_CODE(id) \
|
|
|
|
CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
|
|
|
#define IOCTL_HID_SET_OUTPUT_REPORT HID_IN_CTL_CODE(101)
|
|
|
|
|
|
|
|
struct hid_device_ {
|
|
|
|
HANDLE device_handle;
|
|
|
|
BOOL blocking;
|
|
|
|
USHORT output_report_length;
|
|
|
|
unsigned char* write_buf;
|
|
|
|
size_t input_report_length;
|
|
|
|
USHORT feature_report_length;
|
|
|
|
unsigned char* feature_buf;
|
|
|
|
wchar_t* last_error_str;
|
|
|
|
BOOL read_pending;
|
|
|
|
char* read_buf;
|
|
|
|
OVERLAPPED ol;
|
|
|
|
OVERLAPPED write_ol;
|
|
|
|
struct hid_device_info* device_info;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void USkyPortalIO::Write(FWriteBlock* pb)
|
|
|
|
{
|
|
|
|
if (!ensure(PortalDevice)) {
|
|
|
|
UE_LOG(LogSkyportalIO, Error, TEXT("No Portal found"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
BOOL res;
|
|
|
|
|
|
|
|
OVERLAPPED ol;
|
|
|
|
memset(&ol, 0, sizeof(ol));
|
|
|
|
|
|
|
|
DWORD bytes_returned;
|
|
|
|
|
|
|
|
res = DeviceIoControl(PortalDevice->device_handle,
|
|
|
|
IOCTL_HID_SET_OUTPUT_REPORT,
|
|
|
|
(unsigned char*)pb->data, write_buf_size,
|
|
|
|
(unsigned char*)pb->data, write_buf_size,
|
|
|
|
&bytes_returned, &ol);
|
|
|
|
ensureMsgf(res, TEXT("Unable to write to Portal"));
|
2024-09-25 11:47:11 +00:00
|
|
|
pb->BytesTransferred = bytes_returned;
|
|
|
|
|
2024-09-24 22:17:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
void USkyPortalIO::Write(FWriteBlock* pb) {
|
|
|
|
|
|
|
|
if (!ensure(PortalDevice)) {
|
|
|
|
UE_LOG(LogSkyportalIO, Error, TEXT("No Portal found"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-09-25 11:47:11 +00:00
|
|
|
pb->data[0] = 0; // Use report 0
|
2024-09-24 22:17:52 +00:00
|
|
|
|
2024-09-25 11:47:11 +00:00
|
|
|
res = hid_write(PortalDevice, pb->data, write_buf_size);
|
|
|
|
ensureMsgf(res != -1, TEXT("Unable to write to Portal, %s"), hid_error(PortalDevice));
|
|
|
|
pb->BytesTransferred = res;
|
2024-09-24 22:17:52 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-09-25 11:47:11 +00:00
|
|
|
void USkyPortalIO::WriteRaw(const TArray<uint8> block)
|
2024-09-24 22:17:52 +00:00
|
|
|
{
|
2024-09-25 11:47:11 +00:00
|
|
|
block.GetData;
|
|
|
|
int res = hid_write(PortalDevice, block, block.GetAllocatedSize()); //return the number of byte written
|
2024-09-24 22:17:52 +00:00
|
|
|
if (res == -1)
|
|
|
|
{
|
|
|
|
UE_LOG(LogSkyportalIO, Error, TEXT("Unable to write raw data to Portal. error:\n %s"), hid_error(PortalDevice));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8* USkyPortalIO::Read()
|
|
|
|
{
|
|
|
|
uint8* output = 0;
|
|
|
|
hid_read_timeout(PortalDevice, output, 0x20, TIMEOUT);
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
void USkyPortalIO::Close() {
|
|
|
|
if (PortalDevice) {
|
|
|
|
hid_close(PortalDevice);
|
|
|
|
}
|
2024-09-25 11:47:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* TODO: Should not be here
|
|
|
|
bool USkyPortalIO::IsFalsePositive() const
|
|
|
|
{
|
|
|
|
int dif = FMath::Abs(CurrentStatusData.Counter - OldStatusData.Counter);
|
|
|
|
return (dif <= 2 || dif >= 254);
|
|
|
|
|
|
|
|
}
|
|
|
|
*/
|