//! \file pigrabberbase.h
//! \ingroup Thread
//! \brief
//! \~english Abstract class for creating grabbers
//! \~russian Базовый класс для создания грабберов
//!
//! \details
//! \~english Base class for thread-based data acquisition with queue support.
//! \~russian Базовый класс для получения данных в потоке с поддержкой очереди.
/*
PIP - Platform Independent Primitives
Abstract class for create grabbers
Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
#ifndef PIGRABBERBASE_H
#define PIGRABBERBASE_H
#include "pidiagnostics.h"
#include "pithread.h"
#include "pitime.h"
//! \~english Base class for data grabber threads
//! \~russian Базовый класс для потоков получения данных
template
class PIGrabberBase: public PIThread {
PIOBJECT_SUBCLASS(PIGrabberBase, PIThread);
public:
//! \~english Constructs grabber
//! \~russian Создает граббер
PIGrabberBase() {
is_opened = false;
is_recording = false;
}
//! \~english Destroys grabber
//! \~russian Уничтожает граббер
virtual ~PIGrabberBase() { stopGrabber(false); }
//! \~english Returns if grabber is opened
//! \~russian Возвращает открыт ли граббер
virtual bool isOpened() const { return is_opened; }
//! \~english Returns if grabber is recording
//! \~russian Возвращает записывает ли граббер
virtual bool isRecording() const { return is_recording; }
//! \~english Start recording to file
//! \~russian Начинает запись в файл
virtual void startRecord(const PIString & filename) {
if (!isOpened()) return;
if (isRecording()) return;
rec_mutex.lock();
startRecordInternal(filename);
is_recording = true;
rec_mutex.unlock();
}
//! \~english Stop recording
//! \~russian Останавливает запись
virtual void stopRecord() {
if (!isOpened()) return;
if (!isRecording()) return;
rec_mutex.lock();
is_recording = false;
stopRecordInternal();
rec_mutex.unlock();
}
//! \~english Returns last grabbed data
//! \~russian Возвращает последние полученные данные
T last() const {
T ret;
last_mutex.lock();
ret = last_;
last_mutex.unlock();
return ret;
}
//! \~english Returns if queue is empty
//! \~russian Возвращает пустая ли очередь
bool isEmpty() {
bool ret;
que_mutex.lock();
ret = que.isEmpty();
que_mutex.unlock();
return ret;
}
//! \~english Returns queue size
//! \~russian Возвращает размер очереди
int queSize() {
int ret;
que_mutex.lock();
ret = que.size();
que_mutex.unlock();
return ret;
}
//! \~english Dequeues data from queue
//! \~russian Извлекает данные из очереди
T dequeue() {
T ret;
// piCoutObj << "start";
que_mutex.lock();
if (!que.isEmpty()) {
// piCoutObj << "dequeue";
ret = que.dequeue();
}
// piCoutObj << "end";
que_mutex.unlock();
return ret;
}
//! \~english Stop grabber thread
//! \~russian Останавливает поток граббера
void stopGrabber(bool wait_forever = true) {
if (isRunning()) {
stop();
if (wait_forever)
waitForFinish();
else {
if (!waitForFinish(100)) terminate();
stopRecord();
close();
}
}
}
//! \~english Open grabber
//! \~russian Открывает граббер
bool open() {
bool ret = openInternal();
if (!is_opened && ret) opened();
is_opened = ret;
return ret;
}
//! \~english Close grabber
//! \~russian Закрывает граббер
void close() {
bool em = is_opened;
closeInternal();
last_ = T();
if (em) closed();
is_opened = false;
}
//! \~english Returns diagnostics
//! \~russian Возвращает диагностику
const PIDiagnostics & diag() const { return diag_; }
//! \~english Clear queue
//! \~russian Очищает очередь
void clear() {
que_mutex.lock();
que.clear();
que_mutex.unlock();
}
//! \~english Restart grabber
//! \~russian Перезапускает граббер
void restart() {
clear();
close();
}
EVENT(dataReady);
EVENT(opened);
EVENT(closed);
protected:
virtual void init() {}
virtual bool openInternal() = 0;
virtual void closeInternal() = 0;
virtual int get(T & val) = 0;
virtual void record(const T & val) {}
virtual void startRecordInternal(const PIString & filename) {}
virtual void stopRecordInternal() {}
bool is_opened, is_recording;
mutable PIMutex rec_mutex;
private:
void begin() override { init(); }
void run() override {
if (!isOpened()) {
open();
diag_.reset();
if (!is_opened) piMSleep(200);
}
if (isOpened()) {
T c;
int ret = get(c);
if (ret < 0) {
close();
return;
}
if (ret > 0) {
piMinSleep();
return;
}
diag_.received(1);
que_mutex.lock();
que.enqueue(c);
que_mutex.unlock();
if (isRecording()) {
rec_mutex.lock();
record(c);
rec_mutex.unlock();
diag_.sended(1);
}
last_mutex.lock();
last_ = c;
last_mutex.unlock();
dataReady();
}
}
void end() override {
stopRecord();
close();
}
T last_;
PIQueue que;
PIDiagnostics diag_;
mutable PIMutex que_mutex, last_mutex;
};
#endif // PIGRABBERBASE_H