#pragma once

#define OUT_CMNBUS_DBG_LOG 1
//#include <mutex>

constexpr auto CMNB_MAX_OBJECTS = 32;

class CMNB_SIGNAL
{
	public:
		//std::mutex lck;   //замедляет работу в два раза
		int nObjNumber;     //количество зарегистрированных объектов. Для упрощения, будем считать что их может быть максимум 32
		bool bCurrValue;    //текущее значение сигнала
		bool pObjVal[CMNB_MAX_OBJECTS];

		void SetSignal(int nIndex, bool bValue)
		{
			//lck.lock();
			pObjVal[nIndex] = bValue;
			register bool bRes = true;

			for (int i = 0; i < nObjNumber; ++i)
			{
				register bool t = pObjVal[i];
				bRes = bRes && t;

				if (!t)
				{
					break;
				}
			}

			bCurrValue = bRes;
			//lck.unlock();
		}

		bool GetSignal()
		{
			//lck.lock();
			//register bool b = bCurrValue;
			//lck.unlock();
			//return b;
			return bCurrValue;
		}
};

class CMNB_DATA
{
	public:
		//std::mutex lck;
		int nObjNumber;     //количество зарегистрированных объектов. Для упрощения, будем считать что их может быть максимум 32
		uint32_t nCurrValue;   //текущее значение сигнала
		uint32_t pObjVal[CMNB_MAX_OBJECTS];

		void SetSignal(int nIndex, uint32_t nValue)
		{
			//lck.lock();
			pObjVal[nIndex] = nValue;
			register uint32_t dw = -1;

			for (int i = 0; i < nObjNumber; ++i)
			{
				dw &= pObjVal[i];
			}

			nCurrValue = dw;
			//lck.unlock();
		}

		uint32_t GetSignal()
		{
			//lck.lock();
			//register uint32_t dw = nCurrValue;
			//lck.unlock();
			//return dw;
			return nCurrValue;
		}
};

//класс Общая шина, в состав которой входит и МПИ
class CCommonBus
{
	public:
		//перечисление всех возможных сигналов
		enum CMNBUS_DATA : int
		{
			MPI_DATA_nAD,      //адрес-данные АД15-АД0                             АДх     ведущий-ведомый
			//адрес расширенный А23-А16                         АРх     ведущий-ведомый
			CMNBUS_DATA_NUMBER  //количество элементов в енуме, чтобы вручную не считать
		};
		enum CMNBUS_LINES : int
		{
			//шина управления обменом
			MPI_LINE_nSYNC,    //синхронизация обмена                              ОБМ     ведущий-все устройства
			MPI_LINE_nDIN,     //чтение данных                                     ДЧТ     ведущий-ведомый
			MPI_LINE_nDOUT,    //запись данных                                     ДЗП     ведущий-ведомый
			MPI_LINE_nRPLY,    //ответ устройства                                  ОТВ     ведомый-ведущий
			MPI_LINE_nWTBT,    //признак "запись-байт"                             ПЗП     ведущий-ведомый
			MPI_LINE_nBS7,     //выбор устройства                                  ВУ      ведущий-ведомый
			MPI_LINE_nREF,     //признак "блочный обмен-регенерация"               РГН     активное устройство-динамическая память
			//шина передачи управления
			MPI_LINE_nDMR,     //запрос магистрали                                 ЗМ      активное устройство-процессор
			//дополнительный запрос магистрали                  ЗМД     активное устройство-процессор
			MPI_LINE_nDMGO,    //разрешение на захват магистрали                   РЗМ     процессор-активное устройство
			//дополнительное разрешение на захват магистрали    РЗМД    процессор-активное устройство
			MPI_LINE_nSACK,    //подтверждение запроса                             ПЗ      ведущий-процессор
			//шина прерывания
			MPI_LINE_nIRQ0,    //запрос на прерывание                              ЗПР4    устройство-процессор
			MPI_LINE_nIRQ1,    //запрос на прерывание                              ЗПР5    устройство-процессор
			MPI_LINE_nIRQ2,    //запрос на прерывание                              ЗПР6    устройство-процессор
			MPI_LINE_nIRQ3,    //запрос на прерывание                              ЗПР7    устройство-процессор
			MPI_LINE_nIAK0,    //разрешение прерывания                             ПРР4    процессор-устройство
			MPI_LINE_nIAK1,    //разрешение прерывания                             ПРР5    процессор-устройство
			MPI_LINE_nIAK2,    //разрешение прерывания                             ПРР6    процессор-устройство
			MPI_LINE_nIAK3,    //разрешение прерывания                             ПРР7    процессор-устройство
			MPI_LINE_nEVNT,    //прерывание по внешнему событию                    ПВС     устройство-процессор
			//вспомогательная шина
			MPI_LINE_nINIT,    //установка                                         УСТ     пульт, процессор-все устройства
			MPI_LINE_nHALT,    //останов                                           ОСТ     пульт-процессор
			MPI_LINE_nACLO,    //авария сетевого питания                   ACLO    АСП     блок питания-процессор
			MPI_LINE_nDCLO,    //авария источника питания                  DCLO    АИП     блок питания-все устройства
			//остальные сигналы, их вроде как и не сюда надо, но пока пусть тут будут.
			CMN_LINE_nDMGI,    // bus granted input
			CMN_LINE_nBSY,     // bus busy flag
			CMN_LINE_nSEL1,
			CMN_LINE_nSEL2,

			CMNBUS_LINES_NUMBER, //количество элементов в енуме, чтобы вручную не считать
		};

		struct CMNB_DATASET
		{
			bool bSet;
			CMNBUS_DATA nData;
			int nIndex;
		};
		struct CMNB_LINESET
		{
			bool bSet;
			CMNBUS_LINES nLine;
			int nIndex;
		};


	protected:
#if (OUT_CMNBUS_DBG_LOG)
		FILE        *m_pLog;
#endif

		CMNB_DATA   m_pCMNData[CMNBUS_DATA_NUMBER]; //массив объектов данных
		CMNB_SIGNAL m_pCMNLine[CMNBUS_LINES_NUMBER]; //массив объектов сигналов

		void initArrays();
		void deinitArrays();

	public:
		CCommonBus();
		~CCommonBus();

#if (OUT_CMNBUS_DBG_LOG)
		void OutLog(int nClk, const char *str = "  ");
#endif

		/*
		 * каждое устройство должно зарегистрировать свои сигналы на шине,
		 * чтобы остальные устройства могли их получать.
		 * Вход: nData - тип регистрируемого сигнала
		 * Выход: true - норм, false - ошибка, индекс превысил макс значение
		 **/
		bool RegisterSignal(CMNB_DATASET *DataSet, CMNBUS_DATA nData);
		//установка данных
		void SetSignal(CMNB_DATASET *DataSet, uint32_t nValue);
		void SetSignalOE(CMNB_DATASET *DataSet, bool bEnable, uint32_t nValue);
		//выдача данных.
		uint32_t GetSignal(CMNBUS_DATA nData);

		bool RegisterSignal(CMNB_LINESET *LineSet, CMNBUS_LINES nLine);
		//установка линии
		void SetSignal(CMNB_LINESET *LineSet, bool bValue);
		void SetSignalOE(CMNB_LINESET *LineSet, bool benable, bool bValue = false);
		//выдача линии.
		bool GetSignal(CMNBUS_LINES nLine);
};


