311 lines
9.8 KiB
C++
Executable File
311 lines
9.8 KiB
C++
Executable File
/**
|
|
* Exercises Handler - Handle all information which is needed for AVS to create the proper AV-Streams for a specific context
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Christian Ehrlicher, SLSE, 2016-10-20
|
|
*/
|
|
|
|
#include "exercise_handler.h"
|
|
|
|
#include "exercises_handler.h"
|
|
#include "dds_handler.h"
|
|
#include "main_handler.h"
|
|
#include <LtsUtilsCore/json_object.h>
|
|
#include <chrono>
|
|
|
|
using LtsUtils::JsonObject;
|
|
|
|
namespace
|
|
{
|
|
|
|
QString avRootName() { return QStringLiteral("ECRS"); }
|
|
QString avRecordReplayDefintion() { return QStringLiteral("mode=1;rootfilepath=/data/AVS"); }
|
|
QString avController() { return QStringLiteral("EXCAVS01"); }
|
|
|
|
bool isActive(ExerciseManagement::ExerciseState state)
|
|
{
|
|
return (state == ExerciseManagement::ExerciseState::Started ||
|
|
state == ExerciseManagement::ExerciseState::Paused);
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
namespace AudioVideoManagement
|
|
{
|
|
|
|
ExerciseHandler::ExerciseHandler(MainHandler *mainHandler, int exerciseId)
|
|
: QObject()
|
|
, m_exContext(exerciseId)
|
|
, m_curExerciseState(ExerciseManagement::ExerciseState::Unknown)
|
|
, m_curAVOperatingMode(AVControl::OperatingMode::Unknown)
|
|
, m_mainHandler(mainHandler)
|
|
, m_updateTimer(new QTimer(this))
|
|
, m_lastSeenTimer(new QTimer(this))
|
|
, m_bWarnedOnce(false)
|
|
, m_logger(getLogger("ExerciseHandler"))
|
|
{
|
|
m_updateTimer->setSingleShot(true);
|
|
connect(m_updateTimer, &QTimer::timeout, this, &ExerciseHandler::onUpdateTimerTimeout);
|
|
|
|
m_lastSeenTimer->setSingleShot(false);
|
|
m_lastSeenTimer->setInterval(std::chrono::milliseconds(std::chrono::minutes(10)).count());
|
|
connect(m_lastSeenTimer, &QTimer::timeout, this, &ExerciseHandler::onLastSeenTimerTimeout);
|
|
m_lastSeenTimer->start();
|
|
|
|
connect(avControl(), &AVControl::operatingModeChanged, this, &ExerciseHandler::onOperatingModeChanged);
|
|
connect(avControl(), &AVControl::successfullyLoggedIn, this, &ExerciseHandler::onAvSuccessfullyLoggedIn);
|
|
connect(fmControl(), &FMControl::fileDeletionCompleted, this, &ExerciseHandler::onContextFilesDeleted);
|
|
}
|
|
|
|
/**
|
|
* Called whenever the exercise state changed unless the new state is Terminated.
|
|
* We make sure that for this exercise the Record- and PlaybackSession-entries
|
|
* exist in avm.device_config.
|
|
*/
|
|
void ExerciseHandler::checkForRecordPlaybackSession()
|
|
{
|
|
if (m_recordSession.id <= 0) // new
|
|
{
|
|
m_recordSession.context = m_exContext.toString();
|
|
m_recordSession.controller = avController();
|
|
m_recordSession.definition = avRecordReplayDefintion();
|
|
m_recordSession.name = avRootName();
|
|
m_recordSession.type = avTypeRecordSession();
|
|
if (!db()->insert(m_recordSession))
|
|
{
|
|
ERROR_LOG(m_logger) << m_exContext << " Error adding AvmDeviceConfig - aborting";
|
|
return;
|
|
}
|
|
emit avDbReloadNeeded();
|
|
}
|
|
if (m_replaySession.id <= 0)
|
|
{
|
|
m_replaySession.context = m_exContext.toString();
|
|
m_replaySession.controller = avController();
|
|
m_replaySession.definition = avRecordReplayDefintion();
|
|
m_replaySession.name = avRootName();
|
|
m_replaySession.type = avTypePlaybackSession();
|
|
if (!db()->insert(m_replaySession))
|
|
{
|
|
ERROR_LOG(m_logger) << m_exContext << " Error adding AvmDeviceConfig - aborting";
|
|
return;
|
|
}
|
|
emit avDbReloadNeeded();
|
|
}
|
|
}
|
|
|
|
void ExerciseHandler::setNewExerciseState(ExerciseManagement::ExerciseState newState)
|
|
{
|
|
Q_ASSERT(newState != ExerciseManagement::ExerciseState::Unknown);
|
|
INFO_LOG(m_logger) << m_exContext << ": state change: " << m_curExerciseState << " -> " << newState;
|
|
|
|
if (m_curExerciseState == newState)
|
|
return;
|
|
|
|
Q_ASSERT(m_curExerciseState != ExerciseManagement::ExerciseState::Terminated); // No transition from Terminated to some other state allowed.
|
|
|
|
if (newState != ExerciseManagement::ExerciseState::Terminated)
|
|
checkForRecordPlaybackSession();
|
|
else
|
|
{
|
|
// We are about to terminate the session. OperatingMode will be switched to Cleanup.
|
|
// Once the AVS has removed all relevant files it will signal onContextFilesDelete().
|
|
// Then, Record- and PlaybackSession will be removed and the deletion of this is triggered.
|
|
}
|
|
|
|
bool currentIsActive = isActive(m_curExerciseState);
|
|
bool newIsActive = isActive(newState);
|
|
if (newIsActive != currentIsActive)
|
|
{
|
|
if (newIsActive)
|
|
{
|
|
DEBUG_LOG(m_logger) << m_exContext << " activated";
|
|
emit contextActivated();
|
|
}
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << m_exContext << " deactivated";
|
|
emit contextDeactivated();
|
|
}
|
|
}
|
|
|
|
m_curExerciseState = newState;
|
|
m_updateTimer->start(0);
|
|
}
|
|
|
|
void ExerciseHandler::setLastSeen(const Database::AvmExerciseLastSeen &lastSeen)
|
|
{
|
|
Q_ASSERT(lastSeen.id > 0);
|
|
m_lastSeen = lastSeen;
|
|
}
|
|
|
|
void ExerciseHandler::addDeviceConfig(const Database::AvmDeviceConfig &config)
|
|
{
|
|
if (config.type == avTypeRecordSession())
|
|
m_recordSession = config;
|
|
else if (config.type == avTypePlaybackSession())
|
|
m_replaySession = config;
|
|
else
|
|
Q_ASSERT(false);
|
|
}
|
|
|
|
bool ExerciseHandler::isTerminating() const
|
|
{
|
|
return m_curExerciseState == ExerciseManagement::ExerciseState::Terminated;
|
|
}
|
|
|
|
void ExerciseHandler::onUpdateTimerTimeout()
|
|
{
|
|
// check current state and make sure AVS has the same state
|
|
const AVControl::OperatingMode desiredOperatingMode = avModeFromExerciseState(m_curExerciseState);
|
|
|
|
if (m_curAVOperatingMode == desiredOperatingMode)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "Context: " << m_exContext << " Try switching to " << desiredOperatingMode;
|
|
if (!avControl()->setOperatingModeForContext(m_exContext, desiredOperatingMode))
|
|
{
|
|
if (!m_bWarnedOnce)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Context: " << m_exContext
|
|
<< " - could not change operating mode, maybe not yet connected to AVS - trying again in 5 seconds";
|
|
m_bWarnedOnce = true;
|
|
}
|
|
m_updateTimer->start(5000); // retry in 5sec
|
|
}
|
|
else
|
|
m_bWarnedOnce = false;
|
|
}
|
|
|
|
void ExerciseHandler::onLastSeenTimerTimeout()
|
|
{
|
|
if (isTerminating())
|
|
return;
|
|
|
|
// we check if the exercise is still available on dds
|
|
// if this is not the case, we first switch to AVControl::OperatingMode::Cleanup
|
|
// and remove all device_config entries except the record/replay session
|
|
// when the cleanup is finished (signal from A/V) we remove also the last two sessions and delete our self
|
|
auto ex = exmDtc()->exercise(m_exContext.id());
|
|
if (ex.id() == m_exContext.id())
|
|
{
|
|
// found -> update last seen timestamp
|
|
m_lastSeen.context = m_exContext.toString();
|
|
m_lastSeen.lastSeen = QDateTime::currentDateTimeUtc();
|
|
if (m_lastSeen.id > 0)
|
|
db()->update(m_lastSeen);
|
|
else
|
|
db()->insert(m_lastSeen);
|
|
return;
|
|
}
|
|
|
|
// not found, check for last seen information
|
|
if (m_lastSeen.id == 0 ||
|
|
m_lastSeen.lastSeen.isNull() ||
|
|
m_lastSeen.lastSeen.addDays(1) < QDateTime::currentDateTimeUtc())
|
|
{
|
|
INFO_LOG(m_logger) << "Exercise with id " << m_exContext.id()
|
|
<< " not seen since more than 1 day -> removing";
|
|
// not seen at all or not since more than 1 day -> remove
|
|
setNewExerciseState(ExerciseManagement::ExerciseState::Terminated);
|
|
// now wait for finished signal from AVS ...
|
|
}
|
|
}
|
|
|
|
void ExerciseHandler::onOperatingModeChanged(const ExerciseContext &context,
|
|
AVControl::Component comp,
|
|
AVControl::OperatingMode om)
|
|
{
|
|
if (context != m_exContext)
|
|
return;
|
|
|
|
const AVControl::OperatingMode desiredOperatingMode = avModeFromExerciseState(m_curExerciseState);
|
|
|
|
if (desiredOperatingMode != om)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Context: " << context << " Got " << om
|
|
<< " for " << comp << " but expected " << desiredOperatingMode;
|
|
m_updateTimer->start(100);
|
|
}
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << "Context: " << context << " Got " << om
|
|
<< " for " << comp << " which is the expected value";
|
|
m_updateTimer->stop();
|
|
}
|
|
m_curAVOperatingMode = om;
|
|
}
|
|
|
|
void ExerciseHandler::onContextFilesDeleted(const ExerciseContext &context)
|
|
{
|
|
if (context != m_exContext)
|
|
return;
|
|
|
|
if (!isTerminating())
|
|
return;
|
|
|
|
// all files were deleted, so we are ready with cleaning up - the only thing which is left now
|
|
// is to remove the record/replay session from db and delete ourself
|
|
if (m_recordSession.id > 0)
|
|
db()->removeAvmDeviceConfig(m_recordSession.id);
|
|
if (m_replaySession.id > 0)
|
|
db()->removeAvmDeviceConfig(m_replaySession.id);
|
|
m_recordSession = Database::AvmDeviceConfig();
|
|
m_replaySession = Database::AvmDeviceConfig();
|
|
|
|
if (m_lastSeen.id > 0)
|
|
db()->removeAvmExerciseLastSeen(m_lastSeen.id);
|
|
|
|
emit removeMeImFinished(m_exContext.id());
|
|
}
|
|
|
|
AVControl::OperatingMode ExerciseHandler::avModeFromExerciseState(ExerciseManagement::ExerciseState state)
|
|
{
|
|
switch (state.underlying())
|
|
{
|
|
case ExerciseManagement::ExerciseState::Unknown:
|
|
case ExerciseManagement::ExerciseState::Created:
|
|
return AVControl::OperatingMode::Initialization;
|
|
case ExerciseManagement::ExerciseState::Started:
|
|
return AVControl::OperatingMode::Recording;
|
|
case ExerciseManagement::ExerciseState::Paused:
|
|
return AVControl::OperatingMode::Pause;
|
|
case ExerciseManagement::ExerciseState::Stopped:
|
|
return AVControl::OperatingMode::SaveData;
|
|
case ExerciseManagement::ExerciseState::Terminated:
|
|
return AVControl::OperatingMode::Cleanup;
|
|
}
|
|
return AVControl::OperatingMode::Unknown;
|
|
}
|
|
|
|
AVControl *ExerciseHandler::avControl() const
|
|
{
|
|
return m_mainHandler->avControl();
|
|
}
|
|
|
|
FMControl *ExerciseHandler::fmControl() const
|
|
{
|
|
return m_mainHandler->fmControl();
|
|
}
|
|
|
|
DatabaseInterface *ExerciseHandler::db() const
|
|
{
|
|
return m_mainHandler->db();
|
|
}
|
|
|
|
ExerciseManagement::Interface::Dtc *ExerciseHandler::exmDtc() const
|
|
{
|
|
return m_mainHandler->ddsHandler()->exmDtc();
|
|
}
|
|
|
|
void ExerciseHandler::onAvSuccessfullyLoggedIn()
|
|
{
|
|
m_updateTimer->start();
|
|
m_curAVOperatingMode = AVControl::OperatingMode::Unknown;
|
|
}
|
|
|
|
} // namespace AudioVideoManagement
|
|
|