/*! \file piiodevice.h * \brief Abstract input/output device */ /* PIP - Platform Independent Primitives Abstract input/output device Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PIIODEVICE_H #define PIIODEVICE_H #include "pitimer.h" // function executed from threaded read, pass ThreadedReadData, readedData, sizeOfData typedef bool (*ReadRetFunc)(void * , uchar * , int ); // events: // void opened() // void closed() // // handlers: // bool open() // bool open(const PIString & path) // bool open(const DeviceMode & type) // bool open(const PIString & path, const DeviceMode & type) // bool close() // bool initialize() // void flush() class PIP_EXPORT PIIODevice: public PIThread { PIOBJECT(PIIODevice) public: PIIODevice(); //! \brief Open modes for PIIODevice enum DeviceMode { ReadOnly /*! Device can only read */ = 0x01, WriteOnly /*! Device can only write */ = 0x02, ReadWrite /*! Device can both read and write */ = 0x03 }; PIIODevice(const PIString & path, DeviceMode type = ReadWrite, bool initNow = true); virtual ~PIIODevice() {stop(); write_thread.stop(); if (opened_) {closeDevice(); if (!opened_) closed();}} //! Current open mode of device DeviceMode mode() const {return mode_;} //! Current path of device PIString path() const {return path_;} //! return \b true if mode is ReadOnly or ReadWrite bool isReadable() const {return (mode_ & ReadOnly);} //! return \b true if mode is WriteOnly or ReadWrite bool isWriteable() const {return (mode_ & WriteOnly);} bool isInitialized() const {return init_;} //! return \b true if device is successfully opened bool isOpened() const {return opened_;} //! return \b true if device is closed bool isClosed() const {return !opened_;} //! return \b true if device can read \b now bool canRead() const {return opened_ && (mode_ & ReadOnly);} //! return \b true if device can write \b now bool canWrite() const {return opened_ && (mode_ & WriteOnly);} // Enable timer to periodically open device until it will be opened void setReopenEnabled(bool yes = true) {reopen_enabled_ = yes;} void setReopenTimeout(int msecs = 1000) {reopen_timeout_ = msecs;} bool isReopenEnabled() const {return reopen_enabled_;} int reopenTimeout() {return reopen_timeout_;} // set return function executed when successful read in thread void setThreadedReadSlot(ReadRetFunc func) {ret_func_ = func;} void setThreadedReadData(void * d) {ret_data_ = d;} void setThreadedReadBufferSize(int new_size) {buffer_tr.resize(new_size);} int threadedReadBufferSize() const {return buffer_tr.size_s();} const uchar * threadedReadBuffer() const {return buffer_tr.data();} bool isThreadedRead() const {return isRunning();} void startThreadedRead() {if (!isRunning()) start();} void startThreadedRead(ReadRetFunc func) {ret_func_ = func; if (!isRunning()) start();} bool isThreadedWrite() const {return write_thread.isRunning();} void startThreadedWrite() {if (!write_thread.isRunning()) write_thread.startOnce();} void stopThreadedWrite() {write_thread.stop();} void clearThreadedWriteQueue() {write_thread.lock(); write_queue.clear(); write_thread.unlock();} // Read from device to "read_to" maximum "max_size" bytes, return readed bytes count virtual int read(void * read_to, int max_size) {piCout << "[PIIODevice] \"read\" not implemented!"; return -2;} // Write to device "data" maximum "max_size" bytes, return written bytes count virtual int write(const void * data, int max_size) {piCout << "[PIIODevice] \"write\" not implemented!"; return -2;} // Read from device maximum "max_size" bytes and return them as PIByteArray PIByteArray read(int max_size) {buffer_in.resize(max_size); int ret = read(buffer_in.data(), max_size); if (ret < 0) return PIByteArray(); return buffer_in.resized(ret);} int write(const PIByteArray & data) {return write(data.data(), data.size_s());} ullong writeThreaded(const void * data, int max_size) {return writeThreaded(PIByteArray(data, uint(max_size)));} ullong writeThreaded(const PIByteArray & data); EVENT_HANDLER(bool, open) {if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;} EVENT_HANDLER1(bool, open, const PIString &, _path) {path_ = _path; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;} EVENT_HANDLER1(bool, open, const DeviceMode &, _type) {mode_ = _type; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;} EVENT_HANDLER2(bool, open, const PIString &, _path, const DeviceMode &, _type) {path_ = _path; mode_ = _type; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;} EVENT_HANDLER(bool, close) {opened_ = !closeDevice(); if (!opened_) closed(); return !opened_;} EVENT_HANDLER(bool, initialize) {init_ = init(); return init_;} EVENT_VHANDLER(void, flush) {;} EVENT(opened) EVENT(closed) EVENT2(threadedReadEvent, uchar * , readed, int, size) EVENT2(threadedWriteEvent, ullong, id, int, written_size) //! \handlers //! \{ //! \fn bool open() //! \brief Open device //! \fn bool open(const PIString & path) //! \brief Open device with path "path" //! \fn bool open(const DeviceMode & mode) //! \brief Open device with mode "mode" //! \fn bool open(const PIString & path, const DeviceMode & mode) //! \brief Open device with path "path" and mode "mode" //! \} //! \vhandlers //! \{ //! \fn void flush() //! \brief Immediate write all buffers //! \} //! \events //! \{ //! \fn void opened() //! \brief Raise if succesfull open //! \fn void closed() //! \brief Raise if succesfull close //! \fn void threadedReadEvent(uchar * readed, int size) //! \brief Raise if read thread succesfull read some data //! \fn void threadedWriteEvent(ullong id, int written_size) //! \brief Raise if write thread succesfull write some data of queue item with id "id" //! \} protected: // Function executed before first openDevice() or from constructor virtual bool init() {return true;} // Functions to open and close device, return value will set to "opened_" variable virtual bool openDevice() = 0; // use path_, type_, opened_, init_ variables virtual bool closeDevice() {return true;} // use path_, type_, opened_, init_ variables // Function executed when thread read some data, default implementation execute external slot "ret_func_" virtual bool threadedRead(uchar * readed, int size) {if (ret_func_ != 0) return ret_func_(ret_data_, readed, size); return true;} void terminate(); PIString path_; DeviceMode mode_; ReadRetFunc ret_func_; bool init_, opened_, thread_started_, reopen_enabled_; int reopen_timeout_; void * ret_data_; private: EVENT_HANDLER2(void, check_start, void * , data, int, delim); EVENT_HANDLER(void, write_func); void begin(); void run(); void end() {terminate();} PITimer timer; PIThread write_thread; PIByteArray buffer_in, buffer_tr; PIQueue > write_queue; ullong tri; int readed_; }; #endif // PIIODEVICE_H