Run, but status array regression

This commit is contained in:
Lucas 2024-09-26 00:19:16 +02:00
parent 703db561bb
commit 6ffaeb801a
6 changed files with 236 additions and 262 deletions

View file

@ -181,4 +181,80 @@ bool USkyPortalIO::IsFalsePositive() const
return (dif <= 2 || dif >= 254);
}
*/
*/
EPortalCommand GetPortalCommandFromChar(unsigned char Char)
{
switch (Char)
{
case 'A':
return EPortalCommand::A;
case 'C':
return EPortalCommand::C;
case 'J':
return EPortalCommand::J;
case 'L':
return EPortalCommand::L;
case 'M':
return EPortalCommand::M;
case 'Q':
return EPortalCommand::Q;
case 'R':
return EPortalCommand::R;
case 'S':
return EPortalCommand::S;
default:
// Handle the case when the character doesn't match any enum
// Return a default or invalid value, or handle the error
UE_LOG(LogSkyportalIO, Warning, TEXT("Invalid character for Portal Command: %c"), TCHAR(Char));
return EPortalCommand::S; // 'S' for Status as a default
}
}
FPortalStatusData ParsePortalStatus(const uint8* StatusResponse)
{
FPortalStatusData result;
result.Counter = StatusResponse[5];
result.bIsReady = (StatusResponse[6] == 0x01);
// Parse the figure status array (little-endian 32-bit integer)
uint32 FigureStatusArray = 0;
// Reading the 32-bit integer (character status array) from the buffer
FigureStatusArray |= StatusResponse[1]; // 1st byte
FigureStatusArray |= (StatusResponse[2] << 8); // 2nd byte
FigureStatusArray |= (StatusResponse[3] << 16); // 3rd byte
FigureStatusArray |= (StatusResponse[4] << 24); // 4th byte
bool bChangeBitsSet = false;
TStaticArray<EFigureStatus, 16> tempArray;
// For each of the 16 entries, extract the 2-bit status and map it to EFigureStatus
for (int32 i = 0; i < 16; ++i)
{
uint8 StatusBits = (FigureStatusArray >> (i * 2)) & 0b11; // Extract 2 bits
EFigureStatus FigureStatus;
switch (StatusBits)
{
case 0b00:
FigureStatus = EFigureStatus::NOT_PRESENT;
case 0b01:
FigureStatus = EFigureStatus::PRESENT;
case 0b11:
FigureStatus = EFigureStatus::ADDED;
case 0b10:
FigureStatus = EFigureStatus::REMOVED;
default:
FigureStatus = EFigureStatus::NOT_PRESENT; // Default case
}
// Add to the array of figure statuses
//PortalStatusData.StatusArray.Insert(FigureStatus, i);
tempArray[i] = FigureStatus;
}
result.StatusArray.SetNum(0);
result.StatusArray.Append(tempArray);
return result;
}

View file

@ -1,4 +1,5 @@
#include "SkyPortalRunner.h"
#include "SkyPortalFigure.h"
#include "SkyPortalSubsystem.h"
FPortalStatusChecker::FPortalStatusChecker(UEngineSubsystem* InSubsystem, float InCheckInterval)
@ -43,13 +44,57 @@ void FPortalStatusChecker::CheckPortalStatus()
// Ensure the subsystem is valid
if (SkyPortalSubsystemRef && Cast<USkyPortalSubsystem>(SkyPortalSubsystemRef))
{
USkyPortalIO* PortalHandleRef = Cast<USkyPortalSubsystem>(SkyPortalSubsystemRef)->PortalHandle;
USkyPortalSubsystem* subref = Cast<USkyPortalSubsystem>(SkyPortalSubsystemRef);
USkyPortalIO* PortalHandleRef = subref->PortalHandle;
UE_LOG(LogSkyportalIO, Verbose, TEXT("Check portal"));
if (PortalHandleRef && PortalHandleRef->bPortalReady)
{
// Call the subsystem function to get portal status
uint8* output = PortalHandleRef->Read();
EPortalCommand CommandResponse = GetPortalCommandFromChar(output[0]);
switch (CommandResponse)
{
case S:
CurrentStatusData = ParsePortalStatus(output);
Cast<USkyPortalSubsystem>(SkyPortalSubsystemRef);
//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() //filter conflicting infos
true) {
//FigureDataBlock FigureData;
switch (CurrentStatusData.StatusArray[i])
{
case EFigureStatus::NOT_PRESENT:
subref->OnSkylanderRemoved.Broadcast(00, i);
break;
case EFigureStatus::PRESENT:
//FigureData = ReadFigureBlocks(i);
//subref->OnSkylanderAdded.Broadcast(GetFigureID(FigureData), i);
break;
case EFigureStatus::ADDED:
//FigureData = ReadFigureBlocks(i);
//subref->OnSkylanderAdded.Broadcast(GetFigureID(FigureData), i);
case EFigureStatus::REMOVED:
subref->OnSkylanderRemoved.Broadcast(00, i);
}
}
}
OldStatusData = CurrentStatusData;
subref->StatusData = CurrentStatusData;
}
}
break;
default:
return;
}
// Do something with the status (log, notify, etc.)
UE_LOG(LogSkyportalIO, Verbose, TEXT("Portal Status:"));

View file

@ -13,7 +13,7 @@ void USkyPortalSubsystem::Initialize(FSubsystemCollectionBase& Collection)
Super::Initialize(Collection);
// Start the status checker thread
StatusChecker = new FPortalStatusChecker(this, 0.1f); // Check every 5 seconds
StatusChecker = new FPortalStatusChecker(this, 0.1f); // Check every 50 milliseconds
StatusCheckerThread = FRunnableThread::Create(StatusChecker, TEXT("PortalStatusCheckerThread"), 0, TPri_AboveNormal);
UE_LOG(LogTemp, Log, TEXT("SkyPortalSubsystem Initialized"));
@ -80,6 +80,24 @@ void USkyPortalSubsystem::PortalReady()
}
FPortalStatusData USkyPortalSubsystem::PortalStatus() {
FWriteBlock command;
memset(command.data, 0, write_buf_size); //maybe not needed here
command.data[1] = 'S';
uint8* output;
do {
PortalHandle->Write(&command);
output = PortalHandle->Read();
} while (output[0] != 'S');
return ParsePortalStatus(output);
}
#pragma region Color functions
@ -164,7 +182,7 @@ void USkyPortalSubsystem::ChangePortalColorSide(const FLinearColor& Color, const
FPortalStatusData USkyPortalSubsystem::ParsePortalStatus(const FWriteBlock& ResponseBlock)
FPortalStatusData USkyPortalSubsystem::OLDParsePortalStatus(const FWriteBlock& ResponseBlock)
{
FPortalStatusData PortalStatusData;
@ -221,167 +239,6 @@ void USkyPortalSubsystem::Sleep(int sleepMs) {
FPlatformProcess::Sleep(sleepMs * 0.0001);
}
/*
void USkyPortalSubsystem::CheckComplexResponse() {
if (!PortalDevice) {
return;
}
RWBlock req, res;
memset(command.data, 0, rw_buf_size);
command.data[1] = 'S';
Write(&req);
int BuffResponse = hid_read_timeout(PortalDevice, res.buf, rw_buf_size, TIMEOUT);
if (BuffResponse < 0) {
UE_LOG(LogSkyportalIO, Error, TEXT("Error.\n %s"), hid_error(PortalDevice));
return;
}
EPortalCommand CommandResponse = GetPortalCommandFromChar(res.buf[0]);
switch (CommandResponse)
{
case A:
break;
case C:
break;
case J:
break;
case L:
break;
case M:
break;
case Q:
break;
case R:
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() //filter conflicting infos
true) {
FigureDataBlock FigureData;
switch (CurrentStatusData.StatusArray[i])
{
case EFigureStatus::NOT_PRESENT:
OnSkylanderRemoved.Broadcast(00, i);
break;
case EFigureStatus::PRESENT:
FigureData = ReadFigureBlocks(i);
OnSkylanderAdded.Broadcast(GetFigureID(FigureData), i);
break;
case EFigureStatus::ADDED:
FigureData = ReadFigureBlocks(i);
OnSkylanderAdded.Broadcast(GetFigureID(FigureData), i);
case EFigureStatus::REMOVED:
OnSkylanderRemoved.Broadcast(00, i);
}
}
}
}
OldStatusData = CurrentStatusData;
}
break;
default:
break;
}
}
*/
/* Verify the command response, when only a character is sended by the portal.
*
bool USkyPortalSubsystem::CheckResponse(RWBlock* res, char expect)
{
if (!PortalDevice) {
return false;
}
int b = hid_read_timeout(PortalDevice, res->buf, rw_buf_size, TIMEOUT);
if (b < 0) {
UE_LOG(LogSkyportalIO, Error, TEXT("Error.\n %s"), hid_error(PortalDevice));
return false;
}
res->BytesTransferred = b;
// found wireless USB but portal is not connected
if (res->buf[0] == 'Z')
{
UE_LOG(LogSkyportalIO, Error, TEXT("found wireless USB but portal is not connected"));
return false;
}
// Status says no skylander on portal
if (res->buf[0] == 'Q' && res->buf[1] == 0) {
UE_LOG(LogSkyportalIO, Warning, TEXT("Status says no skylander on portal"));
}
if (res->buf[0] == 'R' && res->buf[1] == 0) {
UE_LOG(LogSkyportalIO, Warning, TEXT("Status says no skylander on portal"));
}
return (res->buf[0] != expect);
}
*/
EPortalCommand USkyPortalSubsystem::GetPortalCommandFromChar(unsigned char Char)
{
switch (Char)
{
case 'A':
return EPortalCommand::A;
case 'C':
return EPortalCommand::C;
case 'J':
return EPortalCommand::J;
case 'L':
return EPortalCommand::L;
case 'M':
return EPortalCommand::M;
case 'Q':
return EPortalCommand::Q;
case 'R':
return EPortalCommand::R;
case 'S':
return EPortalCommand::S;
default:
// Handle the case when the character doesn't match any enum
// Return a default or invalid value, or handle the error
UE_LOG(LogSkyportalIO, Warning, TEXT("Invalid character for Portal Command: %c"), TCHAR(Char));
return EPortalCommand::S; // 'S' for Status as a default
}
}
bool USkyPortalSubsystem::PortalConnect()
{
@ -407,18 +264,11 @@ bool USkyPortalSubsystem::IsPortalReady()
return false;
}
void USkyPortalSubsystem::SendPortalCommand(EPortalCommand Command)
SKYPORTAL_API void USkyPortalSubsystem::PortalMusic(const USoundWave* Sound)
{
return ;
}
void USkyPortalSubsystem::SendPortalSound(USoundWave* Sound)
{
}
/*
FigureDataBlock USkyPortalSubsystem::ReadFigureBlocks(uint8 FigureIndex)

View file

@ -4,9 +4,11 @@
*/
#include "CoreMinimal.h"
#include "hidapi.h"
#include "SkyPortalFigure.h"
#include "SkyPortalIO.generated.h"
#pragma region Definitions
DECLARE_LOG_CATEGORY_EXTERN(LogHIDApi, Log, All);
DECLARE_LOG_CATEGORY_EXTERN(LogSkyportalIO, Log, All);
@ -17,9 +19,71 @@ constexpr auto TIMEOUT = 30000; //milliseconds
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
UENUM(BlueprintType)
enum EPortalCommand {
A UMETA(DisplayName = "Activate"),
C UMETA(DisplayName = "Color"),
J UMETA(DisplayName = "Advanced color"),
L UMETA(DisplayName = "Trap color"),
M UMETA(DisplayName = "Music"),
Q UMETA(DisplayName = "Query"),
R UMETA(DisplayName = "Ready"),
S UMETA(DisplayName = "Status")
};
USTRUCT(BlueprintType)
struct FPortalStatusData
{
GENERATED_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),
bIsReady(true)
{
// Initialisation du tableau StatusArray avec 16 éléments par défaut
StatusArray.Init(DefaultStatus, ArraySize);
}
// Overload the == operator
// Different only between
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);
}
};
#pragma endregion
FPortalStatusData ParsePortalStatus(const uint8* StatusResponse);
EPortalCommand GetPortalCommandFromChar(unsigned char Char);
/* 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
*/
@ -69,6 +133,7 @@ public:
/* Close connection to Portal*/
void Close();
private:
/*TODO: Should not be here

View file

@ -1,55 +1,8 @@
#pragma once
#include "Core.h"
#include "HAL/Runnable.h"
#include "SkyPortalFigure.h"
#include "SkyPortalRunner.generated.h"
USTRUCT(BlueprintType)
struct FPortalStatusData
{
GENERATED_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 {
@ -66,7 +19,11 @@ public:
virtual void Stop() override;
virtual void Exit() override;
UPROPERTY(BlueprintReadOnly)
FPortalStatusData CurrentStatusData;
UPROPERTY(BlueprintReadOnly)
FPortalStatusData OldStatusData;
private:
// Pointer to the subsystem that contains PortalStatus()

View file

@ -17,18 +17,6 @@ enum EPortalSide {
TRAP UMETA(DisplayName = "Trap")
};
UENUM(BlueprintType)
enum EPortalCommand {
A UMETA(DisplayName = "Activate"),
C UMETA(DisplayName = "Color"),
J UMETA(DisplayName = "Advanced color"),
L UMETA(DisplayName = "Trap color"),
M UMETA(DisplayName = "Music"),
Q UMETA(DisplayName = "Query"),
R UMETA(DisplayName = "Ready"),
S UMETA(DisplayName = "Status")
};
@ -44,11 +32,6 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSkylanderRemovedDelegate, int32,
/*
* Handle all the blueprints functions and game logic.
*
@ -59,7 +42,6 @@ class USkyPortalSubsystem : public UEngineSubsystem
GENERATED_BODY()
public:
// Override initialization and deinitialization methods
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
@ -71,7 +53,7 @@ public:
/* The first function to run, before anything else.
* It will re-init and prepare the portal for receiving/sending inputs
*
* return false if portal is not found
* @return false if portal is not found
*/
UFUNCTION(BlueprintCallable, CallInEditor, meta = (Category = "SkyPortal"))
SKYPORTAL_API bool PortalConnect();
@ -103,21 +85,20 @@ public:
SKYPORTAL_API void ChangePortalColor(const FLinearColor& NextColor = FLinearColor::Green);
/*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"))
SKYPORTAL_API bool IsPortalReady();
UFUNCTION(BlueprintCallable, meta = (Category = "SkyPortal|NOT FUNCTIONING"))
SKYPORTAL_API void SendPortalCommand(EPortalCommand Command);
SKYPORTAL_API void PortalMusic(const USoundWave* Sound);
UFUNCTION(BlueprintCallable, meta = (Category = "SkyPortal|NOT FUNCTIONING"))
SKYPORTAL_API void SendPortalSound(USoundWave* Sound);
/**/
UFUNCTION(BlueprintCallable, CallInEditor, meta = (Category = "SkyPortal|Commands"))
SKYPORTAL_API FPortalStatusData PortalStatus();
/**
* Change the color of the portal, can separate side and even trap ligth
/* Change the color of the portal, can separate side and even trap ligth
* @param NextColor New color
* @param PortalSide The actors to record
* @param BlendTime Blend between current color and NextColor, in milliseconds
@ -125,6 +106,7 @@ public:
UFUNCTION(BlueprintCallable, CallInEditor, meta = (AutoCreateRefTerm = "NextColor", Category = "SkyPortal|Commands|Cosmetic", HideAlphaChannel))
SKYPORTAL_API void ChangePortalColorSide(const FLinearColor& NextColor = FLinearColor::Green, const EPortalSide PortalSide = EPortalSide::BOTH, const float BlendTime = 500.0f);
// Blueprint-assignable event property
UPROPERTY(BlueprintAssignable, Category = "SkyPortal|Skylander")
@ -135,16 +117,13 @@ public:
FOnSkylanderRemovedDelegate OnSkylanderRemoved;
UPROPERTY(BlueprintReadOnly)
FPortalStatusData CurrentStatusData;
UPROPERTY(BlueprintReadOnly)
FPortalStatusData OldStatusData;
FPortalStatusData StatusData;
/* Different for each portal model.
*
* SSA :
* GIANTS :
* SWAP FORCE : 0000547 ?
* SWAP FORCE : 0000547 ? , 515
* TRAP TEAM :
* SUPERCHARGERS :
* IMAGINATORS :
@ -166,10 +145,14 @@ public:
private:
FPortalStatusData ParsePortalStatus(const FWriteBlock& ResponseBlock);
// deprecated
FPortalStatusData OLDParsePortalStatus(const FWriteBlock& ResponseBlock); // deprecated
EPortalCommand GetPortalCommandFromChar(unsigned char Char); // deprecated
/* Sleep the system
*
@ -177,8 +160,6 @@ private:
*/
static void Sleep(int sleepMs);
FigureDataBlock ReadFigureBlocks(uint8 FigureIndex);
bool FalsePositive() const;
// Pointer to the status checker thread