diff --git a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp index 9373016..8e0b2a1 100644 --- a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp +++ b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp @@ -14,6 +14,7 @@ void USkyPortalSubsystem::Initialize(FSubsystemCollectionBase& Collection) UE_LOG(LogTemp, Log, TEXT("SkyPortalSubsystem Initialized")); // Initialize HIDAPI + /*May be not needed int res = hid_init(); if (res == 0) { @@ -26,6 +27,7 @@ void USkyPortalSubsystem::Initialize(FSubsystemCollectionBase& Collection) HidError = hid_error(NULL); UE_LOG(LogHIDApi, Error, TEXT("%s"), *HidError); } + */ } @@ -42,6 +44,34 @@ void USkyPortalSubsystem::Deinitialize() Super::Deinitialize(); } +// Antenna up / activate +void USkyPortalSubsystem::ActivatePortal(int active) +{ + RWBlock req, res; + + memset(req.buf, 0, rw_buf_size); + req.buf[1] = 'A'; + req.buf[2] = active; + do { Write(&req); } while (CheckResponse(&res, 'A')); + +} + +// Start portal +void USkyPortalSubsystem::RestartPortal() +{ + RWBlock req, res; + + memset(req.buf, 0, rw_buf_size); + req.buf[1] = 'R'; + + // Wait until the device is ready + while (PortalStatus() == 0) { + FPlatformProcess::Sleep(0.05f); // Sleep for 50ms and try again + } + + do { Write(&req); } while (CheckResponse(&res, 'R')); + +} /* @@ -49,7 +79,13 @@ 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::ConnectPortal() { +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, @@ -90,7 +126,7 @@ bool USkyPortalSubsystem::ConnectPortal() { // Free the device list hid_free_enumeration(list); - bPortalConnected = true; + //bPortalConnected = true; return true; } @@ -128,27 +164,28 @@ void USkyPortalSubsystem::ChangePortalColor(const FLinearColor& Color) Write(&req); } -void USkyPortalSubsystem::Write(RWBlock* pb) { - // TODO: Need to make this function async - if (!ensure(PortalDevice)) { - UE_LOG(LogSkyportalIO, Error, TEXT("No Portal found")); - return; - } +void USkyPortalSubsystem::Write(RWBlock *pb) { - pb->buf[0] = 0; // Use report 0 - - /* - for (int attempt = 0; attempt < 10; attempt++) { - if (hid_write(PortalDevice, pb->buf, 0x21) == -1) { - Sleep(100); - } - else { + if (!ensure(PortalDevice)) { + UE_LOG(LogSkyportalIO, Error, TEXT("No Portal found")); return; } - } - */ - ensureMsgf(hid_write(PortalDevice, pb->buf, 0x21) != -1, TEXT("Unable to write to Portal, %s"), hid_error(PortalDevice)); - UE_LOG(LogSkyportalIO, Verbose, TEXT("Writed")); + + pb->buf[0] = 0; // Use report 0 + + + for (int attempt = 0; attempt < 10; attempt++) { + if (hid_write(PortalDevice, pb->buf, 0x21) == -1) { + UE_LOG(LogSkyportalIO, Warning, TEXT("Attempt %d: Failed to write to Portal, retrying..."), attempt + 1); + FPlatformProcess::Sleep(0.1f); + } + else { + UE_LOG(LogSkyportalIO, Verbose, TEXT("Successfully wrote to the Portal on attempt %d."), attempt + 1); + return; + } + } + //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 after multiple attempts. error:\n %s"), hid_error(PortalDevice)); } @@ -157,7 +194,7 @@ void USkyPortalSubsystem::Sleep(int sleepMs) { } -bool USkyPortalSubsystem::CheckResponse(RWBlock* res, char expect) +bool USkyPortalSubsystem::CheckResponse(RWBlock *res, char expect) { if (!PortalDevice) { return false; @@ -284,4 +321,31 @@ bool USkyPortalSubsystem::ReadBlock(unsigned int block, unsigned char data[0x10] UE_LOG(LogSkyportalIO, Fatal, TEXT("PortalIO:ReadBlock failed after retries")); ensureMsgf(false, TEXT("PortalIO: Failed to read block after multiple retries")); return false; +} + +bool USkyPortalSubsystem::ConnectPortal() +{ + + bPortalConnected = OpenPortalHandle(); + if (bPortalConnected) { + RestartPortal(); + ActivatePortal(1); + ChangePortalColor(FLinearColor(0xC8, 0xC8, 0xC8)); + + UE_LOG(LogSkyportalIO, Log, TEXT("Portal Status: %d\n"), PortalStatus()); + } + return bPortalConnected; +} + + + +unsigned char USkyPortalSubsystem::PortalStatus() +{ + RWBlock req, res; + + memset(req.buf, 0, rw_buf_size); + req.buf[1] = 'S'; + do { Write(&req); } while (CheckResponse(&res, 'S')); + + return res.buf[1]; } \ No newline at end of file diff --git a/Source/SkyPortal/Public/SkyPortalSubsystem.h b/Source/SkyPortal/Public/SkyPortalSubsystem.h index 75ca7ae..8afbd75 100644 --- a/Source/SkyPortal/Public/SkyPortalSubsystem.h +++ b/Source/SkyPortal/Public/SkyPortalSubsystem.h @@ -22,15 +22,22 @@ class SKYPORTAL_API USkyPortalSubsystem : public UEngineSubsystem { GENERATED_BODY() + //Portal ref used in the subsystem + hid_device* PortalDevice; + public: // Override initialization and deinitialization methods virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; + + // Connect to Portal, return false if portal is not found UFUNCTION(BlueprintCallable, CallInEditor, meta = (Category = "SkyPortal")) bool ConnectPortal(); + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly) bool bPortalConnected = false; @@ -42,14 +49,13 @@ public: - + unsigned char PortalStatus(); private: - //Portal ref used in the subsystem - hid_device* PortalDevice; + typedef struct { unsigned char buf[rw_buf_size]; int BytesTransferred; @@ -58,12 +64,17 @@ private: static void Sleep(int sleepMs); + void ActivatePortal(int active); + + void RestartPortal(); + // Block/byte related data write/read functions + bool OpenPortalHandle(); bool ReadBlock(unsigned int block, unsigned char data[0x10], int skylander); bool WriteBlock(unsigned int, unsigned char[0x10], int); - bool CheckResponse(RWBlock* res, char expect); - void Write(RWBlock* pb); + bool CheckResponse(RWBlock *, char); + void Write(RWBlock *); protected: