245 lines
6.0 KiB
C++
245 lines
6.0 KiB
C++
//! \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
|