#pragma once
#include "BKMPIDevice.h"

#include <thread>
#include <mutex>
#include <queue>
#include <condition_variable>


class CIRPS : public CBKMPIDevice
{
	protected:
		uint16_t            RX_CSR; // адрес регистра состояния приёмника (РСПР) доступ - чтение/запись
		uint16_t            RX_DAT; // адрес буферного регистра приёмника (БРПР) доступ - чтение, запись - игнорируется, но ошибки не вызывает
		uint16_t            TX_CSR; // адрес регистра состояния передатчика (РСПЕР) доступ - чтение/запись
		uint16_t            TX_DAT; // адрес буферного регистра передатчика (БРПЕР) доступ - чтение/запись.
		uint16_t            RX_VEC; // вектор прерывания приёмника
		uint16_t            TX_VEC; // вектор прерывания передатчика

		// RX
		uint8_t             m_chRXData; // принятые данные
		bool                m_bRX_Ready;  // terminal receiver ready, бит 7 RX_CSR
		bool                m_bRX_InterruptEnable, m_bRX_InterruptEnable_prev; // terminal receiver interrupt enable, бит 6 RX_CSR
		bool                m_bRX_Break;       // бит 0 RX_CSR
		bool                m_bRX_Overflow;    // бит 12 RX_CSR
		bool                m_bRX_ParityError; // бит 15 RX_CSR

		bool                m_bRX_ParityCheck; // true - проверять чётность, false - нет
		bool                m_bRX_PEV;         // true - контроль чётных битов, false - контроль нечётных.

		void                _int_ReceiveData(uint8_t data);

		// TX
		uint8_t             m_chTXData;
		bool                m_bTX_Ready;  // terminal transmitter ready, бит 7 TX_CSR
		bool                m_bTX_InterruptEnable, m_bTX_InterruptEnable_prev;       // terminal transmitter interrupt enable
		bool                m_bTX_Break;       // бит 0 TX_CSR
		bool                m_bTX_Loop;        // бит 2 TX_CSR


		OVERLAPPED          m_ovr;
		void                RXFunc();           // функция приёма символа
		void                TXFunc();           // функция передачи символа

		std::queue<uint8_t> m_RXQueue;          // очередь полученных данных

		// потоки ввода-вывода
		std::mutex          m_mutQRXThreadWork; // событие, означающее, что поток работает
		bool                m_bStopQRXThread;   // событие, что пора завершить работу потока
		std::thread         m_QRXthr;           // поток выдачи данных из очереди
		void                QRXThreadFunc();    // собственно функция
		std::condition_variable m_QRXcv;        // условная переменная, запуск потока
		std::mutex          m_QRXmutex;         // мутекс условной переменной

		std::mutex          m_mutCONThreadWork; // событие, означающее, что поток работает
		bool                m_bStopCONThread;   // событие, что пора завершить работу потока
		bool                m_bCONTrigger;      // флаг запуска потока
		std::thread         m_CONthr;           // поток выдачи данных из очереди
		void                CONThreadFunc();    // собственно функция
		std::condition_variable m_CONcv;        // условная переменная, запуск потока
		std::mutex          m_CONmutex;         // мутекс условной переменной


		std::mutex          m_mutEVTThreadWork; // событие, означающее, что поток работает
		bool                m_bStopEVTThread;   // событие, что пора завершить работу потока
		std::thread         m_EVTthr;           // поток обработки событий
		void                EVTThreadFunc();    // собственно функция

		bool                StartThreads();
		void                StopThreads();

		HANDLE              m_hPort;     // хэндл открытого порта, куда отображается ВП1-65
		HANDLE              OpenPort(CString &strCOM);  // откытие порта
		void                ClosePort(HANDLE &Port); // закрытие порта

		LARGE_INTEGER       m_liDelayMKS;
		void                CalcDelay();
		void                MakeDelay();
		HANDLE              m_hWaitableTimer;
		bool                CreateTimer();
		void                DeleteTimer();

	public:
		CIRPS();
		virtual ~CIRPS() override;
		virtual BK_DEV_MPI  GetBoardModel() override;
		void Configure(IRPS_MODE nMode);
		void Reconfigure();
		// Virtual method called after reset command
		virtual void        OnReset() override;

		// Methods for Set/Get byte/word
		virtual bool        GetByteT(uint16_t addr, uint8_t *pValue, int &nTC) override;
		virtual bool        GetWordT(uint16_t addr, uint16_t *pValue, int &nTC) override;
		virtual bool        SetByteT(uint16_t addr, uint8_t value, int &nTC) override;
		virtual bool        SetWordT(uint16_t addr, uint16_t value, int &nTC) override;

		virtual bool        GetByteIndirect(uint16_t addr, uint8_t *pValue) override;
		virtual bool        GetWordIndirect(uint16_t addr, uint16_t *pValue) override;

		void                ReceiveData(uint8_t data);

};

