a lot of rework, doesnt compile yet
This commit is contained in:
parent
be72994dc0
commit
8ba30675be
7 changed files with 275 additions and 306 deletions
|
@ -1,10 +1,18 @@
|
||||||
#include "SkyPortalIO.h"
|
#include "SkyPortalIO.h"
|
||||||
#include "Engine/Engine.h"
|
|
||||||
|
|
||||||
DEFINE_LOG_CATEGORY(LogHIDApi);
|
DEFINE_LOG_CATEGORY(LogHIDApi);
|
||||||
DEFINE_LOG_CATEGORY(LogSkyportalIO);
|
DEFINE_LOG_CATEGORY(LogSkyportalIO);
|
||||||
|
|
||||||
bool OpenPortalHandle() {
|
|
||||||
|
//Constructor
|
||||||
|
USkyPortalIO::USkyPortalIO()
|
||||||
|
{
|
||||||
|
OpenPortalHandle();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USkyPortalIO::OpenPortalHandle() {
|
||||||
//reset
|
//reset
|
||||||
if (PortalDevice) {
|
if (PortalDevice) {
|
||||||
hid_close(PortalDevice);
|
hid_close(PortalDevice);
|
||||||
|
@ -67,3 +75,92 @@ bool OpenPortalHandle() {
|
||||||
UE_LOG(LogHIDApi, Error, TEXT("No Portals found"));
|
UE_LOG(LogHIDApi, Error, TEXT("No Portals found"));
|
||||||
return false;
|
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 <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"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
void USkyPortalIO::Write(FWriteBlock* pb) {
|
||||||
|
|
||||||
|
if (!ensure(PortalDevice)) {
|
||||||
|
UE_LOG(LogSkyportalIO, Error, TEXT("No Portal found"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pb->buf[0] = 0; // Use report 0
|
||||||
|
|
||||||
|
|
||||||
|
ensureMsgf(hid_write(PortalDevice, pb->data, read_buf_size) != -1, TEXT("Unable to write to Portal, %s"), hid_error(PortalDevice));
|
||||||
|
UE_LOG(LogSkyportalIO, Error, TEXT("Unable to write to Portal. error:\n %s"), hid_error(PortalDevice));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void USkyPortalIO::WriteRaw(FWriteBlock* block)
|
||||||
|
{
|
||||||
|
int res = hid_write(PortalDevice, block->data, write_buf_size);
|
||||||
|
if (res == -1)
|
||||||
|
{
|
||||||
|
UE_LOG(LogSkyportalIO, Error, TEXT("Unable to write raw data to Portal. error:\n %s"), hid_error(PortalDevice));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
block->BytesTransferred = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8* USkyPortalIO::Read()
|
||||||
|
{
|
||||||
|
uint8* output = 0;
|
||||||
|
hid_read_timeout(PortalDevice, output, 0x20, TIMEOUT);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USkyPortalIO::Close() {
|
||||||
|
if (PortalDevice) {
|
||||||
|
hid_close(PortalDevice);
|
||||||
|
}
|
||||||
|
}
|
2
Source/SkyPortal/Private/SkyPortalRunner.cpp
Normal file
2
Source/SkyPortal/Private/SkyPortalRunner.cpp
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#include "SkyPortalRunner.h"
|
||||||
|
|
|
@ -48,9 +48,9 @@ void USkyPortalSubsystem::Deinitialize()
|
||||||
// Antenna up / activate
|
// Antenna up / activate
|
||||||
void USkyPortalSubsystem::ActivatePortal(int active)
|
void USkyPortalSubsystem::ActivatePortal(int active)
|
||||||
{
|
{
|
||||||
RWBlock req, res;
|
FWriteBlock req, res;
|
||||||
|
|
||||||
memset(req.buf, 0, rw_buf_size);
|
memset(req.data, 0, write_buf_size);
|
||||||
req.buf[1] = 'A';
|
req.buf[1] = 'A';
|
||||||
req.buf[2] = active;
|
req.buf[2] = active;
|
||||||
do { Write(&req); } while (CheckResponse(&res, 'A'));
|
do { Write(&req); } while (CheckResponse(&res, 'A'));
|
||||||
|
@ -58,88 +58,24 @@ void USkyPortalSubsystem::ActivatePortal(int active)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start portal
|
// Start portal
|
||||||
void USkyPortalSubsystem::RestartPortal()
|
void USkyPortalSubsystem::Ready()
|
||||||
{
|
{
|
||||||
RWBlock req, res;
|
FWriteBlock command;
|
||||||
|
|
||||||
memset(req.buf, 0, rw_buf_size);
|
//memset(command.data, 0, write_buf_size);
|
||||||
req.buf[1] = 'R';
|
command.data[1] = 'R';
|
||||||
|
uint8* output;
|
||||||
|
do {
|
||||||
|
PortalHandle->Write(&command);
|
||||||
|
output = PortalHandle->Read();
|
||||||
|
} while (output[0] != 'R');
|
||||||
|
|
||||||
do { Write(&req); } while (CheckResponse(&res, 'R'));
|
uint16 _PortalId = ((output[1] << 8) + output[2]);
|
||||||
|
PortalId = _PortalId; //Need a conversion as uint16 is not supported in BP
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Number of endpoints : 2
|
|
||||||
found an IN End Point 0 with attributes interrupt and address 0x1
|
|
||||||
found an OUT End Point 1 with attributes interrupt and address 0x1
|
|
||||||
*/
|
|
||||||
bool USkyPortalSubsystem::OpenPortalHandle() {
|
|
||||||
|
|
||||||
//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;
|
|
||||||
}
|
|
||||||
//{ Region Color & light functions
|
//{ Region Color & light functions
|
||||||
void USkyPortalSubsystem::ChangePortalColor(const FLinearColor& Color)
|
void USkyPortalSubsystem::ChangePortalColor(const FLinearColor& Color)
|
||||||
{
|
{
|
||||||
|
@ -210,70 +146,7 @@ void USkyPortalSubsystem::ChangePortalColorside(const FLinearColor& Color, const
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
|
||||||
// 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 USkyPortalSubsystem::Write(RWBlock* 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->buf, 0x21,
|
|
||||||
(unsigned char*)pb->buf, 0x21,
|
|
||||||
&bytes_returned, &ol);
|
|
||||||
ensureMsgf(res, TEXT("Unable to write to Portal"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
void USkyPortalSubsystem::Write(RWBlock* pb) {
|
|
||||||
|
|
||||||
if (!ensure(PortalDevice)) {
|
|
||||||
UE_LOG(LogSkyportalIO, Error, TEXT("No Portal found"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pb->buf[0] = 0; // Use report 0
|
|
||||||
|
|
||||||
|
|
||||||
ensureMsgf(hid_write(PortalDevice, pb->buf, 0x21) != -1, TEXT("Unable to write to Portal, %s"), hid_error(PortalDevice));
|
|
||||||
UE_LOG(LogSkyportalIO, Error, TEXT("Unable to write to Portal. error:\n %s"), hid_error(PortalDevice));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
FPortalStatusData USkyPortalSubsystem::ParsePortalStatus(const RWBlock& ResponseBlock)
|
FPortalStatusData USkyPortalSubsystem::ParsePortalStatus(const RWBlock& ResponseBlock)
|
||||||
|
@ -488,39 +361,6 @@ bool USkyPortalSubsystem::CheckResponse(RWBlock* res, char expect)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool USkyPortalSubsystem::WriteBlock(unsigned int block, unsigned char data[0x10], int skylander) {
|
|
||||||
RWBlock req, res; //request and response buffer
|
|
||||||
unsigned char verify[0x10]; // A 16-byte array used to verify the data that was written to the portal.
|
|
||||||
|
|
||||||
UE_LOG(LogSkyportalIO, Verbose, TEXT("Trying to write the current block :%X\n"), block);
|
|
||||||
|
|
||||||
// Trying to write 3 times
|
|
||||||
for (int retries = 0; retries < 3; retries++) {
|
|
||||||
// Write request
|
|
||||||
// W 57 10 <block number> <0x10 bytes of data>
|
|
||||||
memset(req.buf, 0, rw_buf_size);//Reset request buffer
|
|
||||||
req.buf[1] = 'W';
|
|
||||||
req.buf[2] = 0x10 + skylander;
|
|
||||||
req.buf[3] = (unsigned char)block;
|
|
||||||
memcpy(req.buf + 4, data, 0x10);
|
|
||||||
|
|
||||||
do { Write(&req); } while (CheckResponse(&res, 'W'));
|
|
||||||
|
|
||||||
Sleep(100); //Wait 0.1 seconds for write to take effect
|
|
||||||
|
|
||||||
memset(verify, 0xCD, sizeof(verify)); // 0xCD is a placeholder value
|
|
||||||
ReadBlock(block, verify, skylander);
|
|
||||||
|
|
||||||
if (memcmp(data, verify, sizeof(verify))) {
|
|
||||||
UE_LOG(LogSkyportalIO, Error, TEXT("verification of the written block failed"));
|
|
||||||
continue; //retry
|
|
||||||
}
|
|
||||||
UE_LOG(LogSkyportalIO, Verbose, TEXT("block successfully written"));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
UE_LOG(LogSkyportalIO, Fatal, TEXT("failed to write block"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EPortalCommand USkyPortalSubsystem::GetPortalCommandFromChar(unsigned char Char)
|
EPortalCommand USkyPortalSubsystem::GetPortalCommandFromChar(unsigned char Char)
|
||||||
|
@ -606,18 +446,17 @@ bool USkyPortalSubsystem::ReadBlock(unsigned int block, unsigned char data[0x10]
|
||||||
|
|
||||||
bool USkyPortalSubsystem::ConnectPortal()
|
bool USkyPortalSubsystem::ConnectPortal()
|
||||||
{
|
{
|
||||||
|
PortalHandle = NewObject<USkyPortalIO>();
|
||||||
bPortalConnected = OpenPortalHandle();
|
if (IsValidLowLevelFast(PortalHandle)) {
|
||||||
if (bPortalConnected) {
|
UE_LOG(LogSkyportalIO, Log, TEXT("Portal connected: "));
|
||||||
RestartPortal();
|
Ready();
|
||||||
ActivatePortal(1);
|
ActivatePortal(1);
|
||||||
|
|
||||||
Sleep(500);
|
Sleep(500);
|
||||||
ChangePortalColor(FLinearColor(0.5, 0.5, 0.5));
|
ChangePortalColor(FLinearColor(0.5, 0.5, 0.5));
|
||||||
|
return true;
|
||||||
UE_LOG(LogSkyportalIO, Log, TEXT("Portal connected: "));
|
|
||||||
}
|
}
|
||||||
return bPortalConnected;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USkyPortalSubsystem::bIsPortalReady()
|
bool USkyPortalSubsystem::bIsPortalReady()
|
||||||
|
|
|
@ -3,6 +3,14 @@
|
||||||
//#include "SkyPortalFigure.generated.h"
|
//#include "SkyPortalFigure.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
UENUM(BlueprintType)
|
||||||
|
enum class EFigureStatus : uint8
|
||||||
|
{
|
||||||
|
NOT_PRESENT = 0b00 UMETA(DisplayName = "Not Present"),
|
||||||
|
PRESENT = 0b01 UMETA(DisplayName = "Present"),
|
||||||
|
ADDED = 0b11 UMETA(DisplayName = "Added"),
|
||||||
|
REMOVED = 0b10 UMETA(DisplayName = "Removed")
|
||||||
|
};
|
||||||
|
|
||||||
#define FIGURE_TOTAL_BLOCKS 64
|
#define FIGURE_TOTAL_BLOCKS 64
|
||||||
#define FIGURE_BLOCK_SIZE 16
|
#define FIGURE_BLOCK_SIZE 16
|
||||||
|
@ -31,12 +39,12 @@ public:
|
||||||
uint16 ATQA; //always set to 0x01 0x0F
|
uint16 ATQA; //always set to 0x01 0x0F
|
||||||
FString ProductionYear; //last 2 digits of the year that the tag was manufactured as Binary-coded decimal
|
FString ProductionYear; //last 2 digits of the year that the tag was manufactured as Binary-coded decimal
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
int16 ID;
|
|
||||||
#pragma region Toy code
|
#pragma region Toy code
|
||||||
uint32 ToyCodeNumber1, ToyCodeNumber2;
|
uint32 ToyCodeNumber1, ToyCodeNumber2;
|
||||||
uint64 FullToyCodeNumber;
|
uint64 FullToyCodeNumber;
|
||||||
FString ToyCode;
|
FString ToyCode;
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
int16 ID;
|
||||||
int16 VariantID;
|
int16 VariantID;
|
||||||
#pragma region counters
|
#pragma region counters
|
||||||
uint8 counter1;
|
uint8 counter1;
|
||||||
|
|
|
@ -10,24 +10,62 @@
|
||||||
DECLARE_LOG_CATEGORY_EXTERN(LogHIDApi, Log, All);
|
DECLARE_LOG_CATEGORY_EXTERN(LogHIDApi, Log, All);
|
||||||
DECLARE_LOG_CATEGORY_EXTERN(LogSkyportalIO, Log, All);
|
DECLARE_LOG_CATEGORY_EXTERN(LogSkyportalIO, Log, All);
|
||||||
|
|
||||||
UCLASS(MinimalAPI)
|
constexpr auto write_buf_size = 0x21;
|
||||||
class SkyPortalIO : public UObjectBase
|
constexpr auto TIMEOUT = 30000; //milliseconds
|
||||||
|
|
||||||
|
/* Portal physicial device IDs */
|
||||||
|
const int VendorIds[4] = { 0x12ba, 0x54c, 0x1430, 0x1430 };
|
||||||
|
const int ProductIds[4] = { 0x150, 0x967, 0x1f17 };
|
||||||
|
|
||||||
|
/* WriteBlock
|
||||||
|
*
|
||||||
|
* Contain all the data that pass inside hidapi write + the number of bytes in case of successful write
|
||||||
|
* @param data all the block data, should be 0x21 sized
|
||||||
|
* @param BytesTransferred In case of successful write, print the number of byte transfered. Could be used for verifications
|
||||||
|
*/
|
||||||
|
USTRUCT()
|
||||||
|
struct FWriteBlock {
|
||||||
|
GENERATED_BODY()
|
||||||
|
unsigned char data[write_buf_size];
|
||||||
|
int BytesTransferred;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
/* This class will contain and handle all the low-lewel functions
|
||||||
|
* Should be able to be called anywhere
|
||||||
|
*/
|
||||||
|
UCLASS()
|
||||||
|
class USkyPortalIO : public UObject
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SkyPortalIO()
|
/* hidapi will write error message in here*/
|
||||||
{
|
UPROPERTY(BlueprintReadOnly)
|
||||||
OpenPortalHandle();
|
FString HidError;
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
/*Portal ready to be listened or to receive commands*/
|
||||||
|
UPROPERTY(BlueprintReadOnly)
|
||||||
|
bool bPortalReady;
|
||||||
|
|
||||||
|
/* Connect to Portal - will write the PortalDevice var if success */
|
||||||
bool OpenPortalHandle();
|
bool OpenPortalHandle();
|
||||||
|
|
||||||
//Portal ref used in the subsystem
|
void Write(FWriteBlock* Block);
|
||||||
hid_device* PortalDevice;
|
void WriteRaw(FWriteBlock* Block);
|
||||||
|
|
||||||
|
/* Listen to portal
|
||||||
|
* @return The data sended by the portal device
|
||||||
|
*/
|
||||||
|
UFUNCTION()
|
||||||
|
uint8* Read();
|
||||||
|
|
||||||
|
void Close();
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Portal ref used in the subsystem */
|
||||||
|
hid_device* PortalDevice;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
81
Source/SkyPortal/Public/SkyPortalRunner.h
Normal file
81
Source/SkyPortal/Public/SkyPortalRunner.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "HAL/Runnable.h"
|
||||||
|
#include "SkyPortalFigure.h"
|
||||||
|
|
||||||
|
class SkyPortalRunner
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
USTRUCT(BlueprintType)
|
||||||
|
struct FPortalStatusData
|
||||||
|
{
|
||||||
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
|
// Array of statuses
|
||||||
|
UPROPERTY(BlueprintReadOnly, EditFixedSize, Category = "SkyPortal|Figure", meta = (EditFixedOrder))
|
||||||
|
TArray<EFigureStatus> StatusArray;
|
||||||
|
|
||||||
|
// timestamp.
|
||||||
|
// only one byte long. This means that after the value 0xFF, it overflows back to 0x00.
|
||||||
|
// Since these are so far apart, it can be assumed that 0x00 is newer than anything in the range 0xF0 - 0xFF.
|
||||||
|
UPROPERTY(BlueprintReadOnly, Category = "SkyPortal|Figure")
|
||||||
|
uint8 Counter;
|
||||||
|
|
||||||
|
// Should always be true
|
||||||
|
UPROPERTY(BlueprintReadOnly, Category = "SkyPortal|Figure")
|
||||||
|
bool bIsReady;
|
||||||
|
|
||||||
|
explicit FPortalStatusData(uint8 ArraySize = 16, EFigureStatus DefaultStatus = EFigureStatus::NOT_PRESENT) :
|
||||||
|
Counter(0), // Utilisation correcte de l'initialisation directe
|
||||||
|
bIsReady(true) // Utilisation correcte de l'initialisation directe
|
||||||
|
{
|
||||||
|
// Initialisation du tableau StatusArray avec 16 éléments par défaut
|
||||||
|
StatusArray.Init(DefaultStatus, ArraySize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload the == operator
|
||||||
|
bool operator==(const FPortalStatusData& Other) const
|
||||||
|
{
|
||||||
|
if (bIsReady == Other.bIsReady && Counter == Other.Counter) {
|
||||||
|
if (StatusArray == Other.StatusArray) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload the != operator
|
||||||
|
bool operator!=(const FPortalStatusData& Other) const
|
||||||
|
{
|
||||||
|
return !(*this == Other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class FPortalStatusChecker : public FRunnable {
|
||||||
|
public:
|
||||||
|
// Constructor: pass the subsystem and desired check interval (in seconds)
|
||||||
|
FPortalStatusChecker(USkyPortalSubsystem* InSubsystem, float InCheckInterval);
|
||||||
|
|
||||||
|
// FRunnable interface
|
||||||
|
virtual bool Init() override;
|
||||||
|
virtual uint32 Run() override;
|
||||||
|
virtual void Stop() override;
|
||||||
|
virtual void Exit() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Pointer to the subsystem that contains PortalStatus()
|
||||||
|
USkyPortalSubsystem* SkyPortalSubsystem;
|
||||||
|
|
||||||
|
// Time interval (in seconds) for status checking
|
||||||
|
float CheckInterval;
|
||||||
|
|
||||||
|
// Thread control variables
|
||||||
|
FThreadSafeBool bShouldRun;
|
||||||
|
|
||||||
|
// Helper function to check portal status
|
||||||
|
void CheckPortalStatus();
|
||||||
|
};
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Subsystems/EngineSubsystem.h"
|
#include "Subsystems/EngineSubsystem.h"
|
||||||
#include "hidapi.h"
|
#include "SkyPortalRunner.h"
|
||||||
#include "HAL/Runnable.h"
|
|
||||||
#include "SkyPortalFigure.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include "SkyPortalSubsystem.generated.h"
|
#include "SkyPortalSubsystem.generated.h"
|
||||||
|
@ -30,68 +28,10 @@ enum EPortalCommand {
|
||||||
S UMETA(DisplayName = "Status")
|
S UMETA(DisplayName = "Status")
|
||||||
};
|
};
|
||||||
|
|
||||||
UENUM(BlueprintType)
|
|
||||||
enum class EFigureStatus : uint8
|
|
||||||
{
|
|
||||||
NOT_PRESENT = 0b00 UMETA(DisplayName = "Not Present"),
|
|
||||||
PRESENT = 0b01 UMETA(DisplayName = "Present"),
|
|
||||||
ADDED = 0b11 UMETA(DisplayName = "Added"),
|
|
||||||
REMOVED = 0b10 UMETA(DisplayName = "Removed")
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
|
||||||
struct FPortalStatusData
|
|
||||||
{
|
|
||||||
GENERATED_USTRUCT_BODY()
|
|
||||||
|
|
||||||
// Array of statuses
|
|
||||||
UPROPERTY(BlueprintReadOnly, EditFixedSize, Category = "SkyPortal|Figure", meta = (EditFixedOrder))
|
|
||||||
TArray<EFigureStatus> StatusArray;
|
|
||||||
|
|
||||||
// timestamp.
|
|
||||||
// only one byte long. This means that after the value 0xFF, it overflows back to 0x00.
|
|
||||||
// Since these are so far apart, it can be assumed that 0x00 is newer than anything in the range 0xF0 - 0xFF.
|
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "SkyPortal|Figure")
|
|
||||||
uint8 Counter;
|
|
||||||
|
|
||||||
// Should always be true
|
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "SkyPortal|Figure")
|
|
||||||
bool bIsReady;
|
|
||||||
|
|
||||||
explicit FPortalStatusData(uint8 ArraySize = 16, EFigureStatus DefaultStatus = EFigureStatus::NOT_PRESENT) :
|
|
||||||
Counter(0), // Utilisation correcte de l'initialisation directe
|
|
||||||
bIsReady(true) // Utilisation correcte de l'initialisation directe
|
|
||||||
{
|
|
||||||
// Initialisation du tableau StatusArray avec 16 éléments par défaut
|
|
||||||
StatusArray.Init(DefaultStatus, ArraySize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overload the == operator
|
|
||||||
bool operator==(const FPortalStatusData& Other) const
|
|
||||||
{
|
|
||||||
if (bIsReady == Other.bIsReady && Counter == Other.Counter) {
|
|
||||||
if (StatusArray == Other.StatusArray) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overload the != operator
|
|
||||||
bool operator!=(const FPortalStatusData& Other) const
|
|
||||||
{
|
|
||||||
return !(*this == Other);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Macro constants Definitions */
|
|
||||||
#define rw_buf_size 0x21
|
|
||||||
#define TIMEOUT 30000
|
|
||||||
#define DEBUG true
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned char buf[rw_buf_size]; int BytesTransferred;
|
|
||||||
} RWBlock;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,51 +42,21 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSkylanderRemovedDelegate, int32,
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
|
|
||||||
class FPortalStatusChecker : public FRunnable {
|
|
||||||
public:
|
|
||||||
// Constructor: pass the subsystem and desired check interval (in seconds)
|
|
||||||
FPortalStatusChecker(USkyPortalSubsystem* InSubsystem, float InCheckInterval);
|
|
||||||
|
|
||||||
// FRunnable interface
|
|
||||||
virtual bool Init() override;
|
|
||||||
virtual uint32 Run() override;
|
|
||||||
virtual void Stop() override;
|
|
||||||
virtual void Exit() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Pointer to the subsystem that contains PortalStatus()
|
|
||||||
USkyPortalSubsystem* SkyPortalSubsystem;
|
|
||||||
|
|
||||||
// Time interval (in seconds) for status checking
|
|
||||||
float CheckInterval;
|
|
||||||
|
|
||||||
// Thread control variables
|
|
||||||
FThreadSafeBool bShouldRun;
|
|
||||||
|
|
||||||
// Helper function to check portal status
|
|
||||||
void CheckPortalStatus();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle all the blueprints functions and game logic.
|
||||||
/* Handle all the portal I/O
|
*
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
UCLASS(MinimalAPI)
|
UCLASS(MinimalAPI)
|
||||||
class USkyPortalSubsystem : public UEngineSubsystem
|
class USkyPortalSubsystem : public UEngineSubsystem
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
//Portal ref used in the subsystem
|
|
||||||
hid_device* PortalDevice;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Override initialization and deinitialization methods
|
// Override initialization and deinitialization methods
|
||||||
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||||
|
@ -162,6 +72,10 @@ public:
|
||||||
UFUNCTION(BlueprintCallable, CallInEditor, meta = (Category = "SkyPortal"))
|
UFUNCTION(BlueprintCallable, CallInEditor, meta = (Category = "SkyPortal"))
|
||||||
SKYPORTAL_API bool ConnectPortal();
|
SKYPORTAL_API bool ConnectPortal();
|
||||||
|
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, CallInEditor, meta = (Category = "SkyPortal|Commands"))
|
||||||
|
SKYPORTAL_API void Ready();
|
||||||
|
|
||||||
/*Send a **Status** command, to see if the portal is ready to receive new commands*/
|
/*Send a **Status** command, to see if the portal is ready to receive new commands*/
|
||||||
UFUNCTION(BlueprintCallable, BlueprintPure, meta = (Category = "SkyPortal|NOT FUNCTIONING"))
|
UFUNCTION(BlueprintCallable, BlueprintPure, meta = (Category = "SkyPortal|NOT FUNCTIONING"))
|
||||||
SKYPORTAL_API bool bIsPortalReady();
|
SKYPORTAL_API bool bIsPortalReady();
|
||||||
|
@ -202,26 +116,25 @@ public:
|
||||||
UPROPERTY(BlueprintReadOnly)
|
UPROPERTY(BlueprintReadOnly)
|
||||||
FPortalStatusData OldStatusData;
|
FPortalStatusData OldStatusData;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadOnly)
|
||||||
|
uint32 PortalId;
|
||||||
|
|
||||||
EPortalCommand GetPortalCommandFromChar(unsigned char Char);
|
EPortalCommand GetPortalCommandFromChar(unsigned char Char);
|
||||||
|
|
||||||
|
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||||
bool bPortalConnected = false;
|
bool bPortalConnected = false;
|
||||||
|
|
||||||
FString HidError;
|
|
||||||
|
|
||||||
bool ReadBlock(unsigned int block, unsigned char data[0x10], int skylander);
|
|
||||||
bool WriteBlock(unsigned int, unsigned char[0x10], int);
|
|
||||||
bool CheckResponse(RWBlock*, char);
|
|
||||||
void CheckComplexResponse();
|
|
||||||
|
|
||||||
|
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
TArray<uint8> QueryBlock(uint8 characterIndex, uint8 block = 0x00);
|
TArray<uint8> QueryBlock(uint8 characterIndex, uint8 block = 0x00);
|
||||||
|
|
||||||
|
USkyPortalIO* PortalHandle;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FPortalStatusData ParsePortalStatus(const RWBlock& ResponseBlock);
|
FPortalStatusData ParsePortalStatus(const WriteBlock& ResponseBlock);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -231,12 +144,12 @@ private:
|
||||||
|
|
||||||
void ActivatePortal(int active);
|
void ActivatePortal(int active);
|
||||||
|
|
||||||
void RestartPortal();
|
|
||||||
|
|
||||||
|
|
||||||
// Block/byte related data write/read functions
|
// Block/byte related data write/read functions
|
||||||
bool OpenPortalHandle();
|
|
||||||
void Write(RWBlock*);
|
|
||||||
FigureDataBlock ReadFigureBlocks(uint8 FigureIndex);
|
FigureDataBlock ReadFigureBlocks(uint8 FigureIndex);
|
||||||
bool FalsePositive() const;
|
bool FalsePositive() const;
|
||||||
|
|
||||||
|
@ -247,15 +160,6 @@ private:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
//Constants
|
|
||||||
const int VendorIds[4] = { 0x12ba, 0x54c, 0x1430, 0x1430 };
|
|
||||||
const int ProductIds[4] = { 0x150, 0x967, 0x1f17 };
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////Defaults values, should not be used
|
|
||||||
//const int VendorId = 5168;
|
|
||||||
//const int ProductId = 336;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue