/************************************************************************ MeOS - Orienteering Software Copyright (C) 2009-2020 Melin Software HB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Melin Software HB - software@melin.nu - www.melin.nu Eksoppsvägen 16, SE-75646 UPPSALA, Sweden ************************************************************************/ #include "stdafx.h" #include #include "oEvent.h" #include "autotask.h" #include "TabAuto.h" #include "TabSI.h" #include "meos_util.h" #include "socket.h" #include "meosexception.h" const int SYNC_FACTOR = 4; //#define DEBUGPRINT //#define NODELAY AutoTask::AutoTask(HWND hWnd, oEvent &oeIn, gdioutput &gdiIn) : hWndMain(hWnd), oe(oeIn), gdi(gdiIn) { currentRevision = 0; lock = false; lastSynchTime = 0; lastTriedSynchTime = 0; autoSaveTimeBase = autoSaveTime = oe.getPropertyInt("AutoSaveTimeOut", (3*60+15)*1000); synchBaseTime = oe.getPropertyInt("SynchronizationTimeOut", 2500); maxDelay = oe.getPropertyInt("MaximumSpeakerDelay", 10000)/SYNC_FACTOR; } void AutoTask::autoSave() { if (!oe.empty()) { wstring msg; try { if (oe.getNumRunners() > 500) gdi.setWaitCursor(true); DWORD tic = GetTickCount(); oe.save(); DWORD toc = GetTickCount(); if (toc > tic) { int timeToSave = toc - tic; int interval = max(autoSaveTimeBase, timeToSave * 10); if (abs(interval - autoSaveTime) > 4000) { autoSaveTime = interval; resetSaveTimer(); } } } catch (meosException &ex) { msg = ex.wwhat(); } catch(std::exception &ex) { msg = gdi.widen(ex.what()); } catch(...) { msg = L"Ett okänt fel inträffade."; } if (!msg.empty()) { gdi.alert(msg); } else gdi.addInfoBox("", L"Tävlingsdata har sparats.", 10); gdi.setWaitCursor(false); } } void AutoTask::resetSaveTimer() { KillTimer(hWndMain, 1); SetTimer(hWndMain, 1, autoSaveTime, 0); //Autosave } void AutoTask::setTimers() { SetTimer(hWndMain, 2, 100, 0); //Interface timeout SetTimer(hWndMain, 3, synchBaseTime, 0); //DataSync } void AutoTask::interfaceTimeout(const vector &windows) { TabAuto *tabAuto = dynamic_cast(gdi.getTabs().get(TAutoTab)); TabSI *tabSI = dynamic_cast(gdi.getTabs().get(TSITab)); if (lock) return; lock = true; wstring msg; try { DWORD tick = GetTickCount(); for (size_t k = 0; kCheckInterfaceTimeouts(tick); } if (tabAuto) tabAuto->timerCallback(gdi); if (tabSI) while(tabSI->checkpPrintQueue(gdi)); } catch (meosException &ex) { msg = ex.wwhat(); } catch(std::exception &ex) { msg = gdi.widen(ex.what()); } catch(...) { msg = L"Ett okänt fel inträffade."; } if (!msg.empty()) { gdi.alert(msg); gdi.setWaitCursor(false); } lock = false; } void AutoTask::addSynchTime(DWORD tick) { if (tick > 1000 * 60) return; // Ignore extreme times if (synchQueue.size () > 8) synchQueue.pop_front(); synchQueue.push_back(tick); } DWORD AutoTask::getAvgSynchTime() { #ifdef NODELAY return 0; #else double res = 0; for (size_t k = 0; k < synchQueue.size(); k++) { double sq = synchQueue[k]; res += sq*sq; } if (res > 0) res = sqrt(res) / double(synchQueue.size()); return min(int(res), maxDelay); #endif } void AutoTask::synchronize(const vector &windows) { DWORD tic = GetTickCount(); DWORD avg = getAvgSynchTime(); //OutputDebugString(("AVG Update Time: " + itos(avg)).c_str()); if (tic > lastSynchTime) { DWORD since = tic - lastSynchTime; if (since < avg * SYNC_FACTOR) { //OutputDebugString((" skipped: " + itos(since) + "\n").c_str()); return; } //else //OutputDebugString((" check: tsl = " + itos(since) + "\n").c_str()); } else lastSynchTime = tic; if (oe.hasDirectSocket()) { // Clear any incomming messages (already in db) vector pi; oe.getDirectSocket().getPunchQueue(pi); } // Store last time we tried to synch lastTriedSynchTime = tic; if (synchronizeImpl(windows)) { DWORD toc = GetTickCount(); if (toc > tic) addSynchTime(toc-tic); lastSynchTime = toc; #ifdef DEBUGPRINT OutputDebugString((" updated: " + itos(toc-tic) + "\n").c_str()); #endif } //OutputDebugString(" no update\n"); } void AutoTask::advancePunchInformation(const vector &windows) { DWORD tic = GetTickCount(); DWORD avg = getAvgSynchTime(); //OutputDebugString(("Direct Update Time: " + itos(avg)).c_str()); if (tic > lastSynchTime) { DWORD since = tic-lastSynchTime; if (since < avg * SYNC_FACTOR) { //OutputDebugString((" skipped: " + itos(since) + "\n").c_str()); return; } } else lastSynchTime = tic; DWORD since = tic - lastTriedSynchTime; if (since > DWORD(synchBaseTime*4)) { // Synchronize all instead. synchronize(windows); return; } if (advancePunchInformationImpl(windows)) { DWORD toc = GetTickCount(); if (toc > tic) addSynchTime(toc-tic); lastSynchTime = toc; #ifdef DEBUGPRINT OutputDebugString((" direct update: " + itos(toc-tic) + "\n").c_str()); #endif } } bool AutoTask::synchronizeImpl(const vector &windows) { if (lock) return false; lock = true; DWORD d=0; bool doSync = false; bool doSyncPunch = false; TabAuto *tabAuto = dynamic_cast(gdi.getTabs().get(TAutoTab)); for (size_t k = 0; kgetData("DataSync", d)) { doSync = true; } if (windows[k] && windows[k]->getData("PunchSync", d)) { doSyncPunch = true; doSync = true; } } wstring msg; bool ret = false; try { if (doSync || (tabAuto && tabAuto->synchronize)) { if (tabAuto && tabAuto->synchronizePunches) doSyncPunch = true; if ( oe.autoSynchronizeLists(doSyncPunch) || oe.getRevision() != currentRevision) { ret = true; if (getAvgSynchTime() > 1000) gdi.setWaitCursor(true); if (doSync) { for (size_t k = 0; kmakeEvent("DataUpdate", "autosync", 0, 0, false); } catch (meosException &ex) { msg = ex.wwhat(); } catch(std::exception &ex) { msg = gdi.widen(ex.what()); } catch(...) { msg = L"Ett okänt fel inträffade."; } } } } if (tabAuto) tabAuto->syncCallback(gdi); } } oe.resetSQLChanged(false, true); } catch (meosException &ex) { msg = ex.wwhat(); } catch (std::exception &ex) { msg = gdi.widen(ex.what()); } catch (...) { msg = L"Ett okänt fel inträffade."; } currentRevision = oe.getRevision(); if (!msg.empty()) { gdi.alert(msg); } lock = false; gdi.setWaitCursor(false); return ret; } bool AutoTask::advancePunchInformationImpl(const vector &windows) { DWORD d=0; bool doSync = false; bool doSyncPunch = false; for (size_t k = 0; kgetData("DataSync", d)) { doSync = true; } if (windows[k] && windows[k]->getData("PunchSync", d)) { doSyncPunch = true; doSync = true; } } //string msg; try { if (oe.hasDirectSocket()) { //OutputDebugString("Advance punch info\n"); vector pi; oe.getDirectSocket().getPunchQueue(pi); bool ret = oe.advancePunchInformation(windows, pi, doSyncPunch, doSync); if (ret) oe.resetSQLChanged(false, true); return ret; } } catch (meosException &ex) { wstring msg = ex.wwhat(); OutputDebugString(msg.c_str()); } catch (std::exception &ex) { wstring str; string2Wide(ex.what(), str); OutputDebugString(str.c_str()); } catch (...) { } return false; }