Files
pip/libs/main/thread/pigrabberbase.h

245 lines
6.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \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 <http://www.gnu.org/licenses/>.
*/
#ifndef PIGRABBERBASE_H
#define PIGRABBERBASE_H
#include "pidiagnostics.h"
#include "pithread.h"
#include "pitime.h"
//! \~english Base class for data grabber threads
//! \~russian Базовый класс для потоков получения данных
template<typename T = PIByteArray>
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<T> que;
PIDiagnostics diag_;
mutable PIMutex que_mutex, last_mutex;
};
#endif // PIGRABBERBASE_H