169 lines
4.3 KiB
C++
169 lines
4.3 KiB
C++
/*
|
||
* © Copyright 2014 – Urheberrechtshinweis
|
||
* Alle Rechte vorbehalten / All Rights Reserved
|
||
*
|
||
* Programmcode ist urheberrechtlich geschuetzt.
|
||
* Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner.
|
||
* Keine Verwendung ohne explizite Genehmigung.
|
||
* (vgl. § 106 ff UrhG / § 97 UrhG)
|
||
*/
|
||
|
||
#ifndef FILEPLAYER_H
|
||
#define FILEPLAYER_H
|
||
|
||
#include "FileReader.h"
|
||
#include <thread>
|
||
|
||
namespace Offline {
|
||
|
||
/**
|
||
* this class can be used to "play" previously recorded [so-called "offline"] files.
|
||
* one can attach itself as listener and is informed whenever new sensor data is available.
|
||
* one may choose whether to use full-speed playback [as many events as possible] or
|
||
* live-speed playback with the same timing the values were recorded with
|
||
*/
|
||
class FilePlayer {
|
||
|
||
private:
|
||
|
||
FileReader* reader;
|
||
|
||
bool realtime = false;
|
||
bool enabled;
|
||
std::thread thread;
|
||
|
||
/** the listener to inform */
|
||
Listener* listener = nullptr;
|
||
|
||
public:
|
||
|
||
/** empty ctor */
|
||
FilePlayer() : reader(nullptr), listener(nullptr) {
|
||
;
|
||
}
|
||
|
||
/** ctor */
|
||
FilePlayer(FileReader* reader, Listener* l) : reader(reader), listener(l) {
|
||
;
|
||
}
|
||
|
||
/** whether to use realtime playback or "as fast as possible" */
|
||
void setRealtime(const bool rt) {
|
||
this->realtime = rt;
|
||
}
|
||
|
||
/** set the offline-file-reader to use as data source */
|
||
void setReader(FileReader* r) {
|
||
this->reader = r;
|
||
}
|
||
|
||
/** set the event listener to inform */
|
||
void setListener(Listener* l) {
|
||
this->listener = l;
|
||
}
|
||
|
||
/** start playback */
|
||
void start() {
|
||
|
||
// sanity check
|
||
Assert::isNotNull(reader, "call FilePlayer::setReader() first");
|
||
Assert::isNotNull(listener, "call FilePlayer::setListener() first");
|
||
Assert::isFalse(reader->getEntries().empty(), "FileReader has no loaded entries for playback within the FilePlayer!");
|
||
|
||
enabled = true;
|
||
thread = std::thread(&FilePlayer::loop, this);
|
||
|
||
}
|
||
|
||
/** stop playback */
|
||
void stop() {
|
||
enabled = false;
|
||
}
|
||
|
||
/** wait for termination */
|
||
void join() {
|
||
thread.join();
|
||
}
|
||
|
||
|
||
/** manual ticking */
|
||
int tickPos = 0;
|
||
void tick() {
|
||
const std::vector<Entry>& events = reader->getEntries();
|
||
const Entry& e = events[tickPos];
|
||
trigger(Timestamp::fromMS(e.ts), e);
|
||
++tickPos;
|
||
}
|
||
|
||
private:
|
||
|
||
|
||
|
||
/** background loop */
|
||
void loop() {
|
||
|
||
// get all sensor events from the offline file
|
||
const std::vector<Entry>& events = reader->getEntries();
|
||
|
||
// reference time (system vs. first-event)
|
||
Timestamp tsRef1 = Timestamp::fromMS(events.front().ts);
|
||
Timestamp tsRef2 = Timestamp::fromRunningTime();
|
||
|
||
// process every event
|
||
for (const Entry& e : events) {
|
||
|
||
// aborted?
|
||
if (!enabled) {break;}
|
||
|
||
// timestamp
|
||
const Timestamp ts = Timestamp::fromMS(e.ts);
|
||
|
||
// ensure events happen occur fast as they did during recording
|
||
if (realtime) {
|
||
const Timestamp ts1 = ts-tsRef1;
|
||
const Timestamp ts2 = Timestamp::fromRunningTime() - tsRef2;
|
||
const Timestamp diff = ts1-ts2;
|
||
if (diff.ms() > 0) {std::this_thread::sleep_for(std::chrono::milliseconds(diff.ms()));}
|
||
}
|
||
|
||
trigger(ts, e);
|
||
|
||
}
|
||
|
||
// done
|
||
enabled = false;
|
||
|
||
}
|
||
|
||
|
||
|
||
void trigger(const Timestamp ts, const Entry& e) {
|
||
|
||
const int idx = e.idx;
|
||
|
||
#warning "some sensors todo:"
|
||
switch(e.type) {
|
||
case Sensor::ACC: listener->onAccelerometer(ts, reader->getAccelerometer()[idx].data); break;
|
||
case Sensor::BARO: listener->onBarometer(ts, reader->getBarometer()[idx].data); break;
|
||
case Sensor::BEACON: break;//listener->onBe(ts, reader->getBarometer()[idx].data); break;
|
||
case Sensor::COMPASS: listener->onCompass(ts, reader->getCompass()[idx].data); break;
|
||
case Sensor::MAGNETOMETER: listener->onMagnetometer(ts, reader->getMagnetometer()[idx].data); break;
|
||
case Sensor::GPS: listener->onGPS(ts, reader->getGPS()[idx].data); break;
|
||
case Sensor::GRAVITY: listener->onGravity(ts, reader->getGravity()[idx].data); break;
|
||
case Sensor::GYRO: listener->onGyroscope(ts, reader->getGyroscope()[idx].data); break;
|
||
case Sensor::LIN_ACC: break;//listener->on(ts, reader->getBarometer()[idx].data); break;
|
||
case Sensor::WIFI: listener->onWiFi(ts, reader->getWiFiGroupedByTime()[idx].data); break;
|
||
default: throw Exception("code error. found not-yet-implemented sensor");
|
||
}
|
||
|
||
}
|
||
|
||
|
||
};
|
||
|
||
|
||
|
||
}
|
||
|
||
#endif // FILEPLAYER_H
|