From aed30481ea802205e53c9e1d3dc0f00285343d1e Mon Sep 17 00:00:00 2001 From: LUCASTUCIOUS Date: Mon, 23 Sep 2024 23:55:43 +0200 Subject: [PATCH] wip:reading figure --- .../SkyPortal/Private/SkyPortalSubsystem.cpp | 100 +++++++++++++++++- Source/SkyPortal/Public/SkyPortalFigure.h | 3 + Source/SkyPortal/Public/SkyPortalSubsystem.h | 36 ++++++- 3 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 Source/SkyPortal/Public/SkyPortalFigure.h diff --git a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp index d48edea..ca80fd3 100644 --- a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp +++ b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp @@ -367,7 +367,35 @@ void USkyPortalSubsystem::CheckComplexResponse() { break; case S: CurrentStatusData = ParsePortalStatus(res); + //Send delegate when new informations are received + if (OldStatusData != CurrentStatusData) { + + for (int i = 0; i < CurrentStatusData.StatusArray.Num(); i++) { + if (CurrentStatusData.StatusArray[i] != OldStatusData.StatusArray[i]) { + if (!FalsePositive()) { + switch (CurrentStatusData.StatusArray[i]) + { + case EFigureStatus::NOT_PRESENT: + break; + case EFigureStatus::PRESENT: + break; + case EFigureStatus::ADDED: + //get SkylandID + //ReadBlock; + OnSkylanderAdded.Broadcast(01, i); + case EFigureStatus::REMOVED: + OnSkylanderRemoved.Broadcast(01, i) + } + } + } + } + + + OldStatusData = CurrentStatusData; + } + + break; default: break; @@ -375,6 +403,12 @@ void USkyPortalSubsystem::CheckComplexResponse() { } +bool USkyPortalSubsystem::FalsePositive() +{ + int dif = FMath::Abs(CurrentStatusData.Counter - OldStatusData.Counter); + return (dif <= 2 || dif > 254); +} + /* Verify the command response, when only a character is sended by the portal. @@ -491,7 +525,7 @@ EPortalCommand USkyPortalSubsystem::GetPortalCommandFromChar(unsigned char Char) } -bool USkyPortalSubsystem::ReadBlock(unsigned int block, unsigned char data[0x10], int skylander) { +bool USkyPortalSubsystem::ReadBlock(unsigned int block, unsigned char data[0x10], int skylanderIndex) { RWBlock req, res; //request and response buffers unsigned char followup; @@ -513,7 +547,7 @@ bool USkyPortalSubsystem::ReadBlock(unsigned int block, unsigned char data[0x10] memset(req.buf, 0, rw_buf_size); // Clear the request buffer (initialize all bytes to zero) req.buf[1] = 'Q'; - followup = 0x10 + skylander; + followup = 0x10 + skylanderIndex; req.buf[2] = followup; if (block == 0) { req.buf[2] = followup + 0x10; // may not be needed @@ -629,3 +663,65 @@ void FPortalStatusChecker::CheckPortalStatus() } } +FigureDataBlock USkyPortalSubsystem::ReadFigureBlocks(uint8 FigureIndex) +{ + FigureDataBlock FigureData; + FigureData.error = false; // Initialize error flag + + RWBlock req, res; + + // Loop over all 64 blocks + for (uint8 BlockIndex = 0; BlockIndex < FIGURE_TOTAL_BLOCKS; ++BlockIndex) + { + // Prepare the request buffer + memset(req.buf, 0, rw_buf_size); + req.buf[1] = 'Q'; // Command character + req.buf[2] = FigureIndex; // Figure index (0x00 to 0x0F) + req.buf[3] = BlockIndex; // Block index (0x00 to 0x3F) + + // Send the request + Write(&req); + + // Read the response + int BuffResponse = hid_read_timeout(PortalDevice, res.buf, rw_buf_size, TIMEOUT); + + // Check if the response was received successfully + if (BuffResponse < rw_buf_size) + { + FigureData.error = true; // Mark error flag + UE_LOG(LogSkyportalIO, Warning, TEXT("Error receiving data for block %d of figure %d"), BlockIndex, FigureIndex); + break; + } + + // Parse the response status + uint8 StatusByte = res.buf[2]; + uint8 ReturnedBlockIndex = res.buf[3]; + + // Check for errors in the status byte + if (StatusByte == 0x01) // Error in response + { + FigureData.error = true; + UE_LOG(LogSkyportalIO, Warning, TEXT("Error reading block %d for figure %d"), BlockIndex, FigureIndex); + break; + } + else if (StatusByte != (0x10 + 'Q')) // Unexpected status byte + { + FigureData.error = true; + UE_LOG(LogSkyportalIO, Warning, TEXT("Unexpected status byte 0x%02X for block %d"), StatusByte, BlockIndex); + break; + } + + // Verify that the block index matches the requested block + if (ReturnedBlockIndex != BlockIndex) + { + FigureData.error = true; + UE_LOG(LogSkyportalIO, Warning, TEXT("Mismatched block index. Expected %d, got %d"), BlockIndex, ReturnedBlockIndex); + break; + } + + // Copy block data into FigureData + memcpy(FigureData.blockdata[BlockIndex], &res.buf[4], FIGURE_BLOCK_SIZE); + } + + return FigureData; // Return the complete figure data +} \ No newline at end of file diff --git a/Source/SkyPortal/Public/SkyPortalFigure.h b/Source/SkyPortal/Public/SkyPortalFigure.h new file mode 100644 index 0000000..4c690bc --- /dev/null +++ b/Source/SkyPortal/Public/SkyPortalFigure.h @@ -0,0 +1,3 @@ +#pragma once + +#include "SkyPortalFigure.generated.h" \ No newline at end of file diff --git a/Source/SkyPortal/Public/SkyPortalSubsystem.h b/Source/SkyPortal/Public/SkyPortalSubsystem.h index b70a8cc..bae6e45 100644 --- a/Source/SkyPortal/Public/SkyPortalSubsystem.h +++ b/Source/SkyPortal/Public/SkyPortalSubsystem.h @@ -4,6 +4,7 @@ #include "Subsystems/EngineSubsystem.h" #include "hidapi.h" #include "HAL/Runnable.h" +#include "SkyPortalFigure.h" #include "SkyPortalSubsystem.generated.h" @@ -49,7 +50,7 @@ struct FPortalStatusData TArray StatusArray; // timestamp. - //only one byte long. This means that after the value 0xFF, it overflows back to 0x00. + // 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; @@ -57,17 +58,40 @@ struct FPortalStatusData // Should always be true UPROPERTY(BlueprintReadOnly, Category = "SkyPortal|Figure") bool bIsReady; + + // 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 +#define FIGURE_TOTAL_BLOCKS 64 +#define FIGURE_BLOCK_SIZE 16 typedef struct { unsigned char buf[rw_buf_size]; int BytesTransferred; } RWBlock; +typedef struct { + unsigned char blockdata[FIGURE_TOTAL_BLOCKS][FIGURE_BLOCK_SIZE]; bool error; +} FigureDataBlock; + DECLARE_LOG_CATEGORY_EXTERN(LogHIDApi, Log, All); DECLARE_LOG_CATEGORY_EXTERN(LogSkyportalIO, Log, All); @@ -148,6 +172,8 @@ public: UFUNCTION(BlueprintCallable, meta = (Category = "SkyPortal|NOT FUNCTIONING")) SKYPORTAL_API void SendPortalSound(USoundWave* Sound); + + /* Change portal color, ideally should be called just at the start.For gameplay usage, use ChangePortalColorside()*/ UFUNCTION(BlueprintCallable, CallInEditor, meta = (AutoCreateRefTerm = "Color", Category = "SkyPortal|Cosmetic")) SKYPORTAL_API void ChangePortalColor(const FLinearColor& Color = FLinearColor::Green); @@ -173,6 +199,9 @@ public: UPROPERTY(BlueprintReadOnly) FPortalStatusData CurrentStatusData; + UPROPERTY(BlueprintReadOnly) + FPortalStatusData OldStatusData; + EPortalCommand GetPortalCommandFromChar(unsigned char Char); @@ -185,7 +214,7 @@ public: bool WriteBlock(unsigned int, unsigned char[0x10], int); bool CheckResponse(RWBlock*, char); void CheckComplexResponse(); - + @@ -207,7 +236,8 @@ private: // Block/byte related data write/read functions bool OpenPortalHandle(); void Write(RWBlock*); - + FigureDataBlock ReadFigureBlocks(uint8 FigureIndex); + bool FalsePositive(); // Pointer to the status checker thread FPortalStatusChecker* StatusChecker;