#pragma once
#include "BKMPIDevice.h"

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

#define TTY_RX_BRK  1           // бит 0 RX_CSR
#define TTY_RX_INT  0100        // разрешение прерывания, бит 6 RX_CSR
#define TTY_RX_RDY  0200        // terminal receiver ready, бит 7 RX_CSR
#define TTY_RX_OVRFL 010000     // бит 12 RX_CSR
#define TTY_RX_PER  0100000     // бит 15 RX_CSR

#define TTY_TX_BRK  1           // бит 0 TX_CSR
#define TTY_TX_LOOP 4           // бит 2 TX_CSR
#define TTY_TX_INT  0100        // разрешение прерывания, бит 6 TX_CSR
#define TTY_TX_RDY  0200        // terminal transmitter ready, бит 7 TX_CSR

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
		volatile uint8_t    m_chRXData;         // принятые данные
		volatile uint16_t   m_wRXcsr;           // регистр управления
		bool                m_bRX_InterruptEnable_prev;

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

		// TX
		volatile uint8_t    m_chTXData;
		volatile uint16_t   m_wTXcsr;
		bool                m_bTX_InterruptEnable_prev;

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

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

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

		bool                StartThreads();
		void                StopThreads();

		HANDLE              m_hPort;     // хэндл открытого порта, куда отображается ВП1-65
		HANDLE              OpenPort(CString &strCOM);  // открытие порта
		bool                ByteIn(uint8_t *data);
		bool                ByteOut(uint8_t data);
		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(const uint16_t addr, uint8_t *pValue, int &nTC) override;
		virtual bool        GetWordT(const uint16_t addr, uint16_t *pValue, int &nTC) override;
		virtual bool        SetByteT(const uint16_t addr, uint8_t value, int &nTC) override;
		virtual bool        SetWordT(const uint16_t addr, uint16_t value, int &nTC) override;

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

		void                ReceiveData(uint8_t data);

};

