//! \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