#pragma once
#include "BKMPIDevice.h"

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

#define TTY_RX_RDY  (1<<7)      // флаг состояния приёмника, бит 7 RX_CSR
#define TTY_RX_INT  (1<<6)      // разрешение прерывания, бит 6 RX_CSR
#define TTY_RX_BRK  1           // бит 0 RX_CSR
#define TTY_RX_OVRFL (1<<12)    // флаг ошибки переполнения, бит 12 RX_CSR
#define TTY_RX_PER  (1<<15)     // флаг ошибки в посылке, бит 15 RX_CSR

#define TTY_TX_RDY  (1<<7)      // флаг состояния передатчика, бит 7 TX_CSR
#define TTY_TX_INT  (1<<6)      // разрешение прерывания, бит 6 TX_CSR
#define TTY_TX_BRK  1           // разрыв линии, бит 0 TX_CSR
#define TTY_TX_LOOP (1<<2)      // проверка работы, бит 2 TX_CSR


class RCSR
{
		std::mutex m;
		uint16_t v;
	public:
		RCSR()
			: v(0)
		{}
		~RCSR()
		{}
		void setValue(uint16_t val)
		{
			std::lock_guard<std::mutex> lk(m);
			v = val;
		}

		uint16_t getValue()
		{
			std::lock_guard<std::mutex> lk(m);
			return v;
		}

		uint16_t getBit(uint16_t mask)
		{
			std::lock_guard<std::mutex> lk(m);
			return v & mask;
		}

		void setBit(uint16_t mask, uint16_t bit)
		{
			std::lock_guard<std::mutex> lk(m);
			v &= ~mask;
			v |= (bit & mask);
		}

		void setBit(uint16_t bit)
		{
			std::lock_guard<std::mutex> lk(m);
			v |= bit;
		}

		void clrBit(uint16_t mask)
		{
			std::lock_guard<std::mutex> lk(m);
			v &= ~mask;
		}
};




class CIRPS : public CBKMPIDevice
{
		DECLARE_DYNAMIC(CIRPS)

	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;         // принятые данные
		RCSR                m_wRXcsr;           // регистр управления приёмником

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

		// TX
		uint8_t             m_chTXData;         // данные для передачи
		RCSR                m_wTXcsr;           // регистр управления передатчиком

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

		// потоки ввода-вывода
		std::mutex          m_mutTXThreadWork;  // событие, означающее, что поток работает
		bool                m_bStopTXThread;    // событие, что пора завершить работу потока
		bool                m_bTXTrigger;       // флаг запуска потока
		std::thread         m_TXthr;            // поток выдачи данных из очереди
		void                TXThreadFunc();     // собственно функция
		std::condition_variable m_TXcv;         // условная переменная, запуск потока
		std::mutex          m_TXmutex;          // мутекс условной переменной

		std::mutex          m_mutRXThreadWork;  // событие, означающее, что поток работает
		bool                m_bStopRXThread;    // событие, что пора завершить работу потока
		std::thread         m_RXthr;            // поток выдачи данных из очереди
		void                RXThreadFunc();     // собственно функция
		std::mutex          m_RXmutex;          // мутекс условной переменной
		std::mutex          m_mutSafeDelay;

		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 bool        InitialSetDevice() override;

		virtual BK_DEV_MPI GetBoardModel() const override
		{
			return BK_DEV_MPI::IRPS;
		}

		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);

};

