#include "SkyPortalIO.h" DEFINE_LOG_CATEGORY(LogHIDApi); DEFINE_LOG_CATEGORY(LogSkyportalIO); //Constructor USkyPortalIO::USkyPortalIO() { bPortalReady = OpenPortalHandle(); } bool USkyPortalIO::OpenPortalHandle() { //reset if (PortalDevice) { hid_close(PortalDevice); bPortalReady = false; } /* 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); 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; } // 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 #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")); pb->BytesTransferred = bytes_returned; } #else void USkyPortalIO::Write(FWriteBlock* pb) { if (!ensure(PortalDevice)) { UE_LOG(LogSkyportalIO, Error, TEXT("No Portal found")); return; } pb->data[0] = 0; // Use report 0 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; } #endif void USkyPortalIO::WriteRaw(const TArray* block) { ; int res = hid_write(PortalDevice, block->GetData(), block->GetAllocatedSize()); //return the number of byte written 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 = new byte[0x20]; hid_read(PortalDevice, output, 0x20); return output; } TArray USkyPortalIO::QueryBlock(uint8 characterIndex, uint8 block) { return TArray(); } void USkyPortalIO::Close() { if (PortalDevice) { hid_close(PortalDevice); } bPortalReady = false; } /* TODO: Should not be here bool USkyPortalIO::IsFalsePositive() const { int dif = FMath::Abs(CurrentStatusData.Counter - OldStatusData.Counter); return (dif <= 2 || dif >= 254); } */