Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored FPP Remote time processing #396

Merged
merged 6 commits into from
Oct 20, 2021
2 changes: 2 additions & 0 deletions ESPixelStick/src/input/InputFPPRemote.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ bool c_InputFPPRemote::SetConfig (JsonObject & jsonConfig)
pInputFPPRemotePlayItem->SetSyncOffsetMS (SyncOffsetMS);
}

FPPDiscovery.SetSyncOffsetMS (SyncOffsetMS);

// DEBUG_V ("Config Processing");
// Clear outbuffer on config change
memset (OutputMgr.GetBufferAddress(), 0x0, OutputMgr.GetBufferUsedSize ());
Expand Down
143 changes: 96 additions & 47 deletions ESPixelStick/src/input/InputFPPRemotePlayFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,31 @@
#include "../service/FPPDiscovery.h"
#include "../service/fseq.h"

static void TimerHandler (void * p)
{
reinterpret_cast<c_InputFPPRemotePlayFile*>(p)->IsrPoll ();

}// TimerHandler

//-----------------------------------------------------------------------------
c_InputFPPRemotePlayFile::c_InputFPPRemotePlayFile (c_InputMgr::e_InputChannelIds InputChannelId) :
c_InputFPPRemotePlayItem (InputChannelId)
{
// DEBUG_START;

fsm_PlayFile_state_Idle_imp.Init (this);

LastIsrTimeStampMS = millis ();
MsTicker.attach_ms (uint32_t (25), &TimerHandler, (void*)this); // Add ISR Function

// DEBUG_END;
} // c_InputFPPRemotePlayFile

//-----------------------------------------------------------------------------
c_InputFPPRemotePlayFile::~c_InputFPPRemotePlayFile ()
{
// DEBUG_START;

MsTicker.detach ();
for (uint32_t LoopCount = 10000; (LoopCount != 0) && (!IsIdle ()); LoopCount--)
{
Stop ();
Expand Down Expand Up @@ -71,44 +81,62 @@ void c_InputFPPRemotePlayFile::Sync (String & FileName, uint32_t FrameId)
{
// DEBUG_START;

SyncCount++;
SyncControl.SyncCount++;
if (pCurrentFsmState->Sync (FileName, FrameId))
{
SyncAdjustmentCount++;
SyncControl.SyncAdjustmentCount++;
}

// DEBUG_END;

} // Sync

//-----------------------------------------------------------------------------
void c_InputFPPRemotePlayFile::Poll (uint8_t * Buffer, size_t BufferSize)
void c_InputFPPRemotePlayFile::Poll (uint8_t * _Buffer, size_t _BufferSize)
{
// DEBUG_START;
// xDEBUG_START;

Buffer = _Buffer;
BufferSize = _BufferSize;

InitTimeCorrectionFactor ();
pCurrentFsmState->Poll (Buffer, BufferSize);
pCurrentFsmState->Poll ();

// DEBUG_END;
// xDEBUG_END;

} // Poll

//-----------------------------------------------------------------------------
void c_InputFPPRemotePlayFile::IsrPoll ()
{
// xDEBUG_START;

uint32_t now = millis ();
uint32_t elapsedMS = now - LastIsrTimeStampMS;
LastIsrTimeStampMS = now;
FrameControl.ElapsedPlayTimeMS += elapsedMS;
pCurrentFsmState->IsrPoll ();

// xDEBUG_END;

} // IsrPoll

//-----------------------------------------------------------------------------
void c_InputFPPRemotePlayFile::GetStatus (JsonObject& JsonStatus)
{
// DEBUG_START;
// xDEBUG_START;

// uint32_t mseconds = millis () - StartTimeMS;
time_t AdjustedFrameStepTimeMS = time_t (float (FrameStepTimeMS) * TimeCorrectionFactor);
uint32_t mseconds = AdjustedFrameStepTimeMS * LastPlayedFrameId;
uint32_t msecondsTotal = FrameStepTimeMS * TotalNumberOfFramesInSequence;
time_t AdjustedFrameStepTimeMS = time_t (float (FrameControl.FrameStepTimeMS) * SyncControl.TimeCorrectionFactor);
uint32_t mseconds = AdjustedFrameStepTimeMS * FrameControl.LastPlayedFrameId;
uint32_t msecondsTotal = FrameControl.FrameStepTimeMS * FrameControl.TotalNumberOfFramesInSequence;

uint32_t secs = mseconds / 1000;
uint32_t secsTot = msecondsTotal / 1000;

JsonStatus[F ("SyncCount")] = SyncCount;
JsonStatus[F ("SyncAdjustmentCount")] = SyncAdjustmentCount;
JsonStatus[F ("TimeOffset")] = TimeCorrectionFactor;
JsonStatus[F ("SyncCount")] = SyncControl.SyncCount;
JsonStatus[F ("SyncAdjustmentCount")] = SyncControl.SyncAdjustmentCount;
JsonStatus[F ("TimeOffset")] = SyncControl.TimeCorrectionFactor;

String temp = GetFileName ();

Expand All @@ -135,47 +163,53 @@ void c_InputFPPRemotePlayFile::GetStatus (JsonObject& JsonStatus)

JsonStatus[CN_errors] = LastFailedPlayStatusMsg;

// DEBUG_END;
// xDEBUG_END;

} // GetStatus

//-----------------------------------------------------------------------------
uint32_t c_InputFPPRemotePlayFile::CalculateFrameId (time_t now, int32_t SyncOffsetMS)
uint32_t c_InputFPPRemotePlayFile::CalculateFrameId (int32_t SyncOffsetMS)
{
// DEBUG_START;

time_t CurrentPlayTime = now - StartTimeMS;
uint32_t CurrentFrameId = 0;

// has the counter wrapped?
if (now < StartTimeMS)
do // once
{
CurrentPlayTime = now + (0 - StartTimeMS);
}
if (FrameControl.ElapsedPlayTimeMS < FrameControl.FrameStepTimeMS)
{
break;
}

uint32_t AdjustedPlayTime = FrameControl.ElapsedPlayTimeMS + SyncOffsetMS;
// DEBUG_V (String ("AdjustedPlayTime: ") + String (AdjustedPlayTime));
if ((0 > SyncOffsetMS) && (FrameControl.ElapsedPlayTimeMS < abs(SyncOffsetMS)))
{
break;
}

time_t AdjustedPlayTime = CurrentPlayTime + SyncOffsetMS;
time_t AdjustedFrameStepTimeMS = time_t (float (FrameStepTimeMS) * TimeCorrectionFactor);
uint32_t CurrentFrameId = AdjustedPlayTime / AdjustedFrameStepTimeMS;
CurrentFrameId = (AdjustedPlayTime / SyncControl.AdjustedFrameStepTimeMS);
// DEBUG_V (String (" CurrentFrameId: ") + String (CurrentFrameId));

} while (false);

// DEBUG_END;

return max (CurrentFrameId, LastPlayedFrameId);
return CurrentFrameId;

} // CalculateFrameId

//-----------------------------------------------------------------------------
void c_InputFPPRemotePlayFile::CalculatePlayStartTime ()
void c_InputFPPRemotePlayFile::CalculatePlayStartTime (uint32_t StartingFrameId)
{
// DEBUG_START;

time_t now = millis ();
time_t StartOffset = time_t ((float (FrameStepTimeMS) * TimeCorrectionFactor) * float (LastPlayedFrameId));
StartTimeMS = now - StartOffset;
// DEBUG_V (String (" now: ") + String (now));
// DEBUG_V (String (" StartOffset: ") + String (StartOffset));
// DEBUG_V (String (" FrameStepTimeMS: ") + String (FrameStepTimeMS));
// DEBUG_V (String ("TimeCorrectionFactor: ") + String (TimeCorrectionFactor));
// DEBUG_V (String (" LastPlayedFrameId: ") + String (LastPlayedFrameId));
// DEBUG_V (String (" StartTimeMS: ") + String (StartTimeMS));
FrameControl.ElapsedPlayTimeMS = uint32_t ((float (FrameControl.FrameStepTimeMS) * SyncControl.TimeCorrectionFactor) * float (StartingFrameId));

// DEBUG_V (String (" FrameStepTimeMS: ") + String (FrameControl.FrameStepTimeMS));
// DEBUG_V (String ("TimeCorrectionFactor: ") + String (SyncControl.TimeCorrectionFactor));
// DEBUG_V (String (" StartingFrameId: ") + String (StartingFrameId));
// DEBUG_V (String (" ElapsedPlayTIme: ") + String (FrameControl.ElapsedPlayTimeMS));

// DEBUG_END;

Expand Down Expand Up @@ -264,12 +298,12 @@ bool c_InputFPPRemotePlayFile::ParseFseqFile ()
break;
}

// FrameStepTimeMS = max ((uint8_t)1, fsqParsedHeader.stepTime) * 30;
FrameStepTimeMS = max ((uint8_t)1, fsqParsedHeader.stepTime);
TotalNumberOfFramesInSequence = fsqParsedHeader.TotalNumberOfFramesInSequence;
FrameControl.FrameStepTimeMS = max ((uint8_t)25, fsqParsedHeader.stepTime);
FrameControl.TotalNumberOfFramesInSequence = fsqParsedHeader.TotalNumberOfFramesInSequence;
SyncControl.AdjustedFrameStepTimeMS = uint32_t (float (FrameControl.FrameStepTimeMS) * SyncControl.TimeCorrectionFactor);

DataOffset = fsqParsedHeader.dataOffset;
ChannelsPerFrame = fsqParsedHeader.channelCount;
FrameControl.DataOffset = fsqParsedHeader.dataOffset;
FrameControl.ChannelsPerFrame = fsqParsedHeader.channelCount;

memset ((void*)&SparseRanges, 0x00, sizeof (SparseRanges));
if (fsqParsedHeader.numSparseRanges)
Expand Down Expand Up @@ -369,13 +403,13 @@ void c_InputFPPRemotePlayFile::InitTimeCorrectionFactor ()

do // once
{
if (INVALID_TIME_CORRECTION_FACTOR != SavedTimeCorrectionFactor)
if (INVALID_TIME_CORRECTION_FACTOR != SyncControl.SavedTimeCorrectionFactor)
{
break;
}

// only do this once after boot.
TimeCorrectionFactor = SavedTimeCorrectionFactor = INITIAL_TIME_CORRECTION_FACTOR;
SyncControl.TimeCorrectionFactor = SyncControl.SavedTimeCorrectionFactor = INITIAL_TIME_CORRECTION_FACTOR;

String FileData;
FileMgr.ReadSdFile (String (CN_time), FileData);
Expand All @@ -402,8 +436,8 @@ void c_InputFPPRemotePlayFile::InitTimeCorrectionFactor ()
// extern void PrettyPrint (JsonObject & jsonStuff, String Name);
// PrettyPrint (JsonData, String ("InitTimeCorrectionFactor"));

setFromJSON (TimeCorrectionFactor, JsonData, CN_time);
SavedTimeCorrectionFactor = TimeCorrectionFactor;
setFromJSON (SyncControl.TimeCorrectionFactor, JsonData, CN_time);
SyncControl.SavedTimeCorrectionFactor = SyncControl.TimeCorrectionFactor;
// DEBUG_V (String ("TimeCorrectionFactor: ") + String (TimeCorrectionFactor, 10));

} while (false);
Expand All @@ -419,7 +453,7 @@ void c_InputFPPRemotePlayFile::SaveTimeCorrectionFactor ()

do // once
{
if (fabs (SavedTimeCorrectionFactor - TimeCorrectionFactor) < 0.000005F )
if (fabs (SyncControl.SavedTimeCorrectionFactor - SyncControl.TimeCorrectionFactor) < 0.000005F )
{
// DEBUG_V ("Nothing to save");
break;
Expand All @@ -429,8 +463,8 @@ void c_InputFPPRemotePlayFile::SaveTimeCorrectionFactor ()
JsonObject JsonData = jsonDoc.createNestedObject ("x");
// JsonObject JsonData = jsonDoc.as<JsonObject> ();

JsonData[CN_time] = TimeCorrectionFactor;
SavedTimeCorrectionFactor = TimeCorrectionFactor;
JsonData[CN_time] = SyncControl.TimeCorrectionFactor;
SyncControl.SavedTimeCorrectionFactor = SyncControl.TimeCorrectionFactor;

// extern void PrettyPrint (JsonObject & jsonStuff, String Name);
// PrettyPrint (JsonData, String ("SaveTimeCorrectionFactor"));
Expand All @@ -445,3 +479,18 @@ void c_InputFPPRemotePlayFile::SaveTimeCorrectionFactor ()
// DEBUG_END;

} // SaveTimeCorrectionFactor

//-----------------------------------------------------------------------------
void c_InputFPPRemotePlayFile::ClearFileInfo()
{
PlayItemName = String ("");
FrameControl.StartingFrameId = 0;
FrameControl.LastPlayedFrameId = 0;
RemainingPlayCount = 0;
SyncControl.LastRcvdSyncFrameId = 0;
FrameControl.DataOffset = 0;
FrameControl.ChannelsPerFrame = 0;
FrameControl.FrameStepTimeMS = 25;
FrameControl.TotalNumberOfFramesInSequence = 0;
FrameControl.ElapsedPlayTimeMS = 0;
} // ClearFileInfo
52 changes: 37 additions & 15 deletions ESPixelStick/src/input/InputFPPRemotePlayFile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "InputFPPRemotePlayItem.hpp"
#include "InputFPPRemotePlayFileFsm.hpp"
#include "../service/fseq.h"
#include <Ticker.h>

class c_InputFPPRemotePlayFile : public c_InputFPPRemotePlayItem
{
Expand All @@ -36,16 +37,20 @@ class c_InputFPPRemotePlayFile : public c_InputFPPRemotePlayItem
virtual void Poll (uint8_t* Buffer, size_t BufferSize);
virtual void GetStatus (JsonObject & jsonStatus);
virtual bool IsIdle () { return (pCurrentFsmState == &fsm_PlayFile_state_Idle_imp); }

void IsrPoll ();

uint32_t GetLastFrameId () { return LastPlayedFrameId; }
float GetTimeCorrectionFactor () { return TimeCorrectionFactor; }
uint32_t GetLastFrameId () { return FrameControl.LastPlayedFrameId; }
float GetTimeCorrectionFactor () { return SyncControl.TimeCorrectionFactor; }

private:
#define INVALID_TIME_CORRECTION_FACTOR -1.0
#define INITIAL_TIME_CORRECTION_FACTOR 1.0
#define ELAPSED_PLAY_TIMER_INTERVAL_MS 10

void InitTimeCorrectionFactor ();
void SaveTimeCorrectionFactor ();
void ClearFileInfo ();

friend class fsm_PlayFile_state_Idle;
friend class fsm_PlayFile_state_Starting;
Expand All @@ -61,23 +66,40 @@ class c_InputFPPRemotePlayFile : public c_InputFPPRemotePlayItem
fsm_PlayFile_state * pCurrentFsmState = &fsm_PlayFile_state_Idle_imp;

c_FileMgr::FileId FileHandleForFileBeingPlayed = 0;
uint32_t LastPlayedFrameId = 0;
uint32_t LastRcvdSyncFrameId = 0;
size_t DataOffset = 0;
uint32_t ChannelsPerFrame = 0;
time_t FrameStepTimeMS = 1;
uint32_t TotalNumberOfFramesInSequence = 0;
uint32_t StartTimeMS = 0;
double TimeCorrectionFactor = INITIAL_TIME_CORRECTION_FACTOR;
double SavedTimeCorrectionFactor = INVALID_TIME_CORRECTION_FACTOR;
uint32_t SyncCount = 0;
uint32_t SyncAdjustmentCount = 0;

struct FrameControl_t
{
size_t DataOffset = 0;
uint32_t ChannelsPerFrame = 0;
time_t FrameStepTimeMS = 1;
uint32_t TotalNumberOfFramesInSequence = 0;
uint32_t ElapsedPlayTimeMS = 0;

uint32_t StartingFrameId = 0;
uint32_t LastPlayedFrameId = 0;
} FrameControl;

struct SyncControl_t
{
uint32_t SyncCount = 0;
uint32_t SyncAdjustmentCount = 0;
uint32_t LastRcvdSyncFrameId = 0;

double TimeCorrectionFactor = INITIAL_TIME_CORRECTION_FACTOR;
double SavedTimeCorrectionFactor = INVALID_TIME_CORRECTION_FACTOR;
uint32_t AdjustedFrameStepTimeMS = 0;
} SyncControl;

uint8_t * Buffer = nullptr;
size_t BufferSize = 0;
Ticker MsTicker;
uint32_t LastIsrTimeStampMS = 0;

#define MAX_NUM_SPARSE_RANGES 5
FSEQParsedRangeEntry SparseRanges[MAX_NUM_SPARSE_RANGES];

uint32_t CalculateFrameId (time_t now, int32_t SyncOffsetMS = 0);
void CalculatePlayStartTime ();
uint32_t CalculateFrameId (int32_t SyncOffsetMS = 0);
void CalculatePlayStartTime (uint32_t FrameId);
bool ParseFseqFile ();

String LastFailedPlayStatusMsg;
Expand Down
Loading