520 lines
13 KiB
C++
520 lines
13 KiB
C++
#include "headers/climbingrace.h"
|
|
|
|
/*
|
|
* manages:
|
|
* - global state
|
|
* - timers
|
|
* - sounds
|
|
* - next start action
|
|
* - next start action delay progress
|
|
* - settings (remote and local)
|
|
*/
|
|
|
|
ClimbingRace::ClimbingRace(QObject *parent) : QObject(parent)
|
|
{
|
|
this->state = IDLE;
|
|
this->mode = LOCAL;
|
|
|
|
this->appSettings = new AppSettings;
|
|
this->baseConn = new BaseConn;
|
|
|
|
this->baseConn->setIP(pGlobalAppSettings->loadSetting("baseStationIpAdress"));
|
|
connect(this->baseConn, &BaseConn::stateChanged, this, &ClimbingRace::baseStationStateChanged);
|
|
connect(this->baseConn, &BaseConn::connectionsChanged, this, &ClimbingRace::baseStationConnectionsChanged);
|
|
|
|
this->speedTimers.append( new SpeedTimer );
|
|
|
|
this->player = new QMediaPlayer;
|
|
this->date = new QDateTime;
|
|
|
|
this->nextStartActionTimer = new QTimer(this);
|
|
nextStartActionTimer->setSingleShot(true);
|
|
|
|
this->baseStationSyncTimer = new QTimer();
|
|
this->baseStationSyncTimer->setInterval(100);
|
|
this->baseStationSyncTimer->setSingleShot(true);
|
|
this->baseStationSyncTimer->connect(this->baseStationSyncTimer, &QTimer::timeout, this, &ClimbingRace::syncWithBaseStation);
|
|
this->baseStationSyncTimer->start();
|
|
|
|
this->timerTextRefreshTimer = new QTimer();
|
|
this->timerTextRefreshTimer->setInterval(1);
|
|
this->timerTextRefreshTimer->setSingleShot(true);
|
|
this->timerTextRefreshTimer->connect(this->timerTextRefreshTimer, &QTimer::timeout, this, &ClimbingRace::refreshTimerText);
|
|
this->refreshTimerText();
|
|
}
|
|
|
|
// --------------------------
|
|
// --- Main Functionality ---
|
|
// --------------------------
|
|
|
|
int ClimbingRace::startRace() {
|
|
|
|
if(this->state != IDLE) {
|
|
return 904;
|
|
}
|
|
|
|
this->refreshMode();
|
|
|
|
qDebug() << "+ --- starting race";
|
|
|
|
int returnCode = 900;
|
|
|
|
switch (this->mode) {
|
|
case LOCAL:
|
|
{
|
|
|
|
this->setState(STARTING);
|
|
|
|
this->nextStartAction = -1;
|
|
this->playSoundsAndStartRace();
|
|
|
|
returnCode = 200;
|
|
|
|
break;
|
|
}
|
|
case REMOTE:
|
|
{
|
|
QVariantMap reply = this->baseConn->sendCommand(1000);
|
|
|
|
if(reply["status"] != 200){
|
|
//handle Error!!
|
|
returnCode = reply["status"].toInt();
|
|
}
|
|
else {
|
|
|
|
returnCode = 200;
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return returnCode;
|
|
}
|
|
|
|
int ClimbingRace::stopRace(int type) {
|
|
|
|
if(this->state != RUNNING && this->state != STARTING) {
|
|
return 904;
|
|
}
|
|
|
|
// type can be:
|
|
// 0: stopp
|
|
// 1: cancel
|
|
// 2: fail (fase start)
|
|
|
|
this->refreshMode();
|
|
|
|
qDebug() << "+ --- stopping race";
|
|
|
|
int returnCode = 900;
|
|
|
|
switch (this->mode) {
|
|
case LOCAL:
|
|
{
|
|
|
|
if(type == 1){
|
|
this->nextStartActionTimer->stop();
|
|
this->player->stop();
|
|
this->nextStartAction = -1;
|
|
}
|
|
|
|
returnCode = this->speedTimers[0]->stop(type) ? 200:904;
|
|
|
|
if(returnCode == 200) {
|
|
this->setState(STOPPED);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case REMOTE:
|
|
{
|
|
QVariantMap reply = this->baseConn->sendCommand(1001);
|
|
|
|
if(reply["status"] != 200){
|
|
//handle Error!!
|
|
returnCode = reply["status"].toInt();
|
|
}
|
|
else {
|
|
returnCode = 200;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return returnCode;
|
|
}
|
|
|
|
int ClimbingRace::resetRace() {
|
|
|
|
if(this->state != STOPPED) {
|
|
return 904;
|
|
}
|
|
|
|
this->refreshMode();
|
|
|
|
qDebug() << "+ --- resetting race";
|
|
|
|
int returnCode = 900;
|
|
|
|
|
|
switch (this->mode) {
|
|
case LOCAL:
|
|
{
|
|
returnCode = this->speedTimers[0]->reset() ? 200:904;
|
|
|
|
if(returnCode == 200){
|
|
this->setState(IDLE);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case REMOTE:
|
|
{
|
|
|
|
QVariantMap reply = this->baseConn->sendCommand(1002);
|
|
|
|
if(reply["status"] != 200){
|
|
//handle Error!!
|
|
returnCode = reply["status"].toInt();
|
|
}
|
|
else {
|
|
returnCode = 200;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return returnCode;
|
|
}
|
|
|
|
// -------------------------
|
|
// --- Base Station sync ---
|
|
// -------------------------
|
|
|
|
void ClimbingRace::syncWithBaseStation() {
|
|
|
|
this->baseConn->refreshConnections();
|
|
|
|
if(this->baseConn->state != "connected"){
|
|
this->baseStationSyncTimer->start();
|
|
return;
|
|
}
|
|
|
|
QVariantMap tmpReply = this->baseConn->sendCommand(2000);
|
|
|
|
if(tmpReply["status"] != 200){
|
|
this->baseStationSyncTimer->start();
|
|
return;
|
|
}
|
|
|
|
this->setState( raceState( tmpReply["data"].toInt() ) );
|
|
|
|
switch (this->state) {
|
|
case 0:
|
|
{
|
|
// case IDLE
|
|
if(speedTimers[0]->state != 0){
|
|
speedTimers[0]->setState(SpeedTimer::IDLE);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
// case STARTING
|
|
if(speedTimers[0]->state != 1){
|
|
speedTimers[0]->setState(SpeedTimer::STARTING);
|
|
}
|
|
|
|
tmpReply = this->baseConn->sendCommand(2005);
|
|
if(tmpReply["status"] != 200){
|
|
//handle error!!
|
|
qDebug() << "+ --- getting next start action progress from basestation failed";
|
|
this->baseStationSyncTimer->start();
|
|
return;
|
|
}
|
|
else {
|
|
this->nextStartActionDelayProgress = tmpReply["data"].toDouble() > 0 ? tmpReply["data"].toDouble():0;
|
|
this->nextStartActionDelayProgressChanged();
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
|
|
// get current time
|
|
tmpReply = this->baseConn->sendCommand(2007);
|
|
if(tmpReply["status"] != 200){
|
|
//handle error!!
|
|
qDebug() << "+ --- getting timers from basestation failed";
|
|
this->baseStationSyncTimer->start();
|
|
return;
|
|
}
|
|
else {
|
|
QVariantList timers = tmpReply["data"].toList();
|
|
|
|
speedTimers[0]->startTime = this->date->currentMSecsSinceEpoch() - timers[0].toMap()["currTime"].toDouble();
|
|
speedTimers[0]->stoppedTime = timers[0].toMap()["currTime"].toDouble();
|
|
speedTimers[0]->reactionTime = timers[0].toMap()["reactTime"].toDouble();
|
|
|
|
speedTimers[0]->setState(SpeedTimer::timerState(timers[0].toMap()["state"].toInt()));
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
this->baseStationSyncTimer->start();
|
|
}
|
|
|
|
// ------------------------
|
|
// --- helper functions ---
|
|
// ------------------------
|
|
|
|
void ClimbingRace::playSoundsAndStartRace() {
|
|
qDebug() << "next Action: " << nextStartAction;
|
|
|
|
nextStartActionTimer->disconnect(nextStartActionTimer, SIGNAL(timeout()), this, SLOT(playSoundsAndStartRace()));
|
|
|
|
switch (this->nextStartAction) {
|
|
case 0:
|
|
{
|
|
if(!playSound("qrc:/sounds/at_marks_1.wav")){
|
|
return;
|
|
}
|
|
if(appSettings->loadSetting("ready_en") == "true"){
|
|
nextStartAction = 1;
|
|
nextStartActionTimer->setInterval(appSettings->loadSetting("ready_delay").toInt() <= 0 ? 1:appSettings->loadSetting("ready_delay").toInt());
|
|
}
|
|
else{
|
|
nextStartAction = 2;
|
|
nextStartActionTimer->setInterval(1);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
if(!playSound("qrc:/sounds/ready_1.wav")){
|
|
return;
|
|
}
|
|
nextStartAction = 2;
|
|
nextStartActionTimer->setInterval(1);
|
|
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
if(!playSound("qrc:/sounds/OFFICAL_IFSC_STARTIGNAL.wav")){
|
|
return;
|
|
}
|
|
nextStartAction = -1;
|
|
nextStartActionTimer->disconnect(nextStartActionTimer, SIGNAL(timeout()), this, SLOT(playSoundsAndStartRace()));
|
|
|
|
this->setState(RUNNING);
|
|
speedTimers[0]->start();
|
|
|
|
return;
|
|
}
|
|
default:
|
|
{
|
|
this->speedTimers[0]->setState(SpeedTimer::STARTING);
|
|
if(appSettings->loadSetting("at_marks_en") == "true"){
|
|
nextStartAction = 0;
|
|
nextStartActionTimer->setInterval(appSettings->loadSetting("at_marks_delay").toInt() <= 0 ? 1:appSettings->loadSetting("at_marks_delay").toInt());
|
|
}
|
|
else if(appSettings->loadSetting("ready_en") == "true"){
|
|
nextStartAction = 1;
|
|
nextStartActionTimer->setInterval(appSettings->loadSetting("ready_delay").toInt() <= 0 ? 1:appSettings->loadSetting("ready_delay").toInt());
|
|
}
|
|
else{
|
|
nextStartAction = 2;
|
|
nextStartActionTimer->setInterval(1);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
nextStartActionTimer->connect(nextStartActionTimer, SIGNAL(timeout()), this, SLOT(playSoundsAndStartRace()));
|
|
nextStartActionTimer->start();
|
|
}
|
|
|
|
bool ClimbingRace::playSound(QString path) {
|
|
|
|
player->setMedia(QUrl(path));
|
|
player->setVolume(50);
|
|
player->play();
|
|
|
|
QTimer timer;
|
|
timer.setInterval(1);
|
|
timer.setSingleShot(true);
|
|
|
|
QEventLoop loop;
|
|
loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
|
|
|
while (player->mediaStatus() == QMediaPlayer::LoadingMedia || player->mediaStatus() == QMediaPlayer::BufferingMedia || player->mediaStatus() == QMediaPlayer::BufferedMedia) {
|
|
timer.start();
|
|
loop.exec();
|
|
}
|
|
|
|
if(player->mediaStatus() == QMediaPlayer::EndOfMedia){
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void ClimbingRace::setState(raceState newState) {
|
|
|
|
if(newState != this->state) {
|
|
this->state = newState;
|
|
this->stateChanged(newState);
|
|
}
|
|
}
|
|
|
|
void ClimbingRace::refreshMode() {
|
|
raceMode newMode;
|
|
if(this->baseConn->state == "connected"){
|
|
newMode = REMOTE;
|
|
}
|
|
else {
|
|
newMode = LOCAL;
|
|
}
|
|
|
|
if(this->mode != newMode){
|
|
this->mode = newMode;
|
|
emit this->modeChanged();
|
|
}
|
|
|
|
}
|
|
|
|
void ClimbingRace::refreshTimerText() {
|
|
|
|
// --- refresh timer text ---
|
|
|
|
QVariantList newTimerTextList;
|
|
|
|
foreach(SpeedTimer * timer, this->speedTimers){
|
|
QVariantMap timerMap = {{"text",timer->getText()}, {"reacttime", timer->reactionTime}};
|
|
newTimerTextList.append(timerMap);
|
|
}
|
|
|
|
if(newTimerTextList != this->qmlTimers){
|
|
this->qmlTimers = newTimerTextList;
|
|
emit timerTextChanged();
|
|
}
|
|
|
|
// --- refresh next start action delay progress ---
|
|
|
|
if(this->mode == LOCAL){
|
|
QString totalStr;
|
|
|
|
if(nextStartAction == 0){
|
|
totalStr = appSettings->loadSetting("at_marks_delay");
|
|
}
|
|
else if (nextStartAction == 1) {
|
|
totalStr = appSettings->loadSetting("ready_delay");
|
|
}
|
|
|
|
double remaining = this->nextStartActionTimer->remainingTime();
|
|
double total = totalStr.toDouble();
|
|
//qDebug() << "DELAY_PROG: " << "total: " << total << " remaining: " << remaining << " prog: " << remaining / total;
|
|
if(remaining > 0){
|
|
this->nextStartActionDelayProgress = remaining / total;
|
|
emit this->nextStartActionDelayProgressChanged();
|
|
}
|
|
else {
|
|
this->nextStartActionDelayProgress = 0;
|
|
emit this->nextStartActionDelayProgressChanged();
|
|
}
|
|
}
|
|
else if (this->mode == REMOTE && this->state == IDLE) {
|
|
this->nextStartActionDelayProgress = 0;
|
|
emit this->nextStartActionDelayProgressChanged();
|
|
}
|
|
|
|
this->timerTextRefreshTimer->start();
|
|
}
|
|
|
|
// -------------------------
|
|
// --- functions for qml ---
|
|
// -------------------------
|
|
|
|
int ClimbingRace::getState() {
|
|
return this->state;
|
|
}
|
|
|
|
int ClimbingRace::getMode() {
|
|
return this->mode;
|
|
}
|
|
|
|
QVariant ClimbingRace::getTimerTextList() {
|
|
return this->qmlTimers;
|
|
// QVariantList test;
|
|
// QVariantMap test2 = {{"text", "1234"}, {"reacttime", 2.0}};
|
|
// test.append(test2);
|
|
// return test;
|
|
}
|
|
|
|
double ClimbingRace::getNextStartActionDelayProgress() {
|
|
return this->nextStartActionDelayProgress;
|
|
}
|
|
|
|
void ClimbingRace::writeSetting(QString key, QVariant value) {
|
|
this->refreshMode();
|
|
|
|
if(this->mode == REMOTE && this->remoteSettings.contains(key)){
|
|
this->baseConn->writeRemoteSetting(key, value.toString());
|
|
}
|
|
else {
|
|
this->appSettings->writeSetting(key, value);
|
|
}
|
|
|
|
}
|
|
|
|
QString ClimbingRace::readSetting(QString key) {
|
|
this->refreshMode();
|
|
|
|
if(this->mode == REMOTE && this->remoteSettings.contains(key)){
|
|
QVariantMap reply = this->baseConn->sendCommand(3001, key);
|
|
if(reply["status"] != 200){
|
|
return "false";
|
|
}
|
|
return reply["data"].toString();
|
|
}
|
|
else {
|
|
return this->appSettings->loadSetting(key);
|
|
}
|
|
}
|
|
|
|
bool ClimbingRace::connectBaseStation() {
|
|
this->reloadBaseStationIpAdress();
|
|
return this->baseConn->connectToHost();
|
|
}
|
|
|
|
void ClimbingRace::disconnectBaseStation() {
|
|
this->baseConn->closeConnection();
|
|
}
|
|
|
|
QString ClimbingRace::getBaseStationState() {
|
|
return this->baseConn->getState();
|
|
}
|
|
|
|
QVariant ClimbingRace::getBaseStationConnections() {
|
|
return baseConn->getConnections();
|
|
}
|
|
|
|
bool ClimbingRace::reloadBaseStationIpAdress() {
|
|
if(this->baseConn->state == "disconnected"){
|
|
this->baseConn->setIP(pGlobalAppSettings->loadSetting("baseStationIpAdress"));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|