/*
 * IO.h
 *
 *  Created on: 11 июня 2015 г.
 *      Author: esaulenko
 */

#ifndef DRIVERS_IO_H_
#define DRIVERS_IO_H_

#include <cstdint>
#include "CommonTypes.h"
#include "Settings.h"
#include "Utils.h"

#if not defined CAN_FIRMWARE
#include "SysTimer.h"
#endif


typedef uint64_t	TInpMask;		// битовая маска логических входов
typedef uint64_t	TOutMask;		// битовая маска логических выходов

// макросы для более простого обращения к битовым маскам
#define oBIT(x)				BIT64(CIO::x)
#define iBIT(x)				BIT64(CIO::x)


class CIO
{
	#define iPIN(x)				(CSettings::x-CSettings::ipOFFSET)
	#define oNAME(x)			(CSettings::x-CSettings::oOFFSET)
	#define iNAME(x)			(CSettings::x-CSettings::iOFFSET)

public:

// Эта таблица источников для логических входов (функций)
#if defined MOBICAR_1_2

	enum TInPins {
		iRedBlack = iPIN(iRedBlack),		// Pin_Door_I
		iGreyBlack = iPIN(iGreyBlack),		// Pin_Trunk_I
		iBrownBlack = iPIN(iBrownBlack),	// Pin_Hood_I
		iGreen = iPIN(iGreen),				// Pin_Ignition
		iLBlueBlack = iPIN(iLBlueBlack),	// Pin_Parking_I
		iBlackWhite = iPIN(iBlackWhite),	// Pin_Foot_I
		iBlackPink = iPIN(iBlackPink),		// Pin_RPM_I
		iYellowBlue = iPIN(iYellowBlue),	// Pin_OutRes2
		iYellowWhite = iPIN(iYellowWhite),	// Pin_OutRes1

		ipCOUNT = CSettings::ipCOUNT,		// Общее кол-во физических источников

		iCAN = 0x7E,						// берется из CAN шины
		iNone = 0x7F						// никуда не подключен
	};

	enum TOutPins {
		oBrownGreen,						// Pin_Ign_O
		oBrownViolet,						// Pin_Ign1_O
		oBrownYellow,						// Pin_Start_O
		oBrownWhite,						// Pin_Acc_O
		oGreen,								// Pin_LockRelay	Relay3
		oYellow,							// Pin_UnlockRelay	Relay4
		oVioletYellow, 						// Pin_Light1Relay	Relay1
		oVioletBrown, 						// Pin_Light2Relay	Relay2
		oPink, 								// Pin_Relay5		Relay5
		oBlue,								// Pin_Immo_O
		oBrown,								// Pin_SirenOut
		oYellowBlue,						// Pin_OutRes2_O
		oYellowWhite,						// Pin_OutRes1_O
		oOrange,							// Kline1
		oOrangeBlack,						// KLine2
		opCOUNT,							// Общее кол-во физических выходов
		oCAN = 31,
	};

#elif defined MOBICAR_3 || defined MAGICAR_X

	enum TInPins {
		iRedBlack = iPIN(iRedBlack),
		iGreyBlack = iPIN(iGreyBlack),
		iBrownBlack = iPIN(iBrownBlack),
		iGreen = iPIN(iGreen),
		iLBlueBlack = iPIN(iLBlueBlack),
		iBlackWhite = iPIN(iBlackWhite),
		iBlackPink = iPIN(iBlackPink),
		iYellowBlue = iPIN(iYellowBlue),
		iYellowWhite = iPIN(iYellowWhite),

		ipCOUNT = CSettings::ipCOUNT,		// Общее кол-во физических источников

		iCAN = 0x7E,						// берется из CAN шины
		iNone = 0x7F						// никуда не подключен
	};

	enum TOutPins {
		oGreenRelay,
		oVioletRelay,
		oYellowRelay,
		oWhiteRelay,
		oBrownGreen,
		oBrownYellow,
		oBrownViolet,
		oBrownWhite,
		oOrangeBreak,			// разрыв Lin1
		oBlue,
		oBrown,
		oYellowBlue,			// вход/выход +/-
		oYellowWhite,			// вход/выход +/-
		oGreen,					// вход/выход
		oBlackWhite,			// вход/выход
		oPinkBreak,				// разрыв Lin2
		oOrange,				// Lin1
		oPink,					// Lin2
		oPinkWhite,				// Lin3

		opCOUNT,					// Общее кол-во физических выходов
		oCAN = 31					// Выход на CAN-прошивку
	};

#else
	#error IO pins: unknown model!
#endif

	enum TInputs {
		iDoorDrv = iNAME(iDoorDrv),
		iDoorFP = iNAME(iDoorFP),
		iDoorRL = iNAME(iDoorRL),
		iDoorRR = iNAME(iDoorRR),
		iTrunk = iNAME(iTrunk),
		iHood = iNAME(iHood),
		iIgn = iNAME(iIgn),
		iHBrake = iNAME(iHBrake),
		iLamp = iNAME(iLamp),
		iPark = iNAME(iPark),
		iBrake = iNAME(iBrake),
		iLeftTurnLight = iNAME(iLeftTurnLight),
		iRightTurnLight = iNAME(iRightTurnLight),
		iArm = iNAME(iArm),
		iSensorAlarm = iNAME(iSensorAlarm),
		iSensorNotify = iNAME(iSensorNotify),
		iEngine = iNAME(iEngine),
		iLock = iNAME(iLock),
		iPreHeater = iNAME(iPreHeater),
		iLowFuelLevel = iNAME(iLowFuelLevel),
		iACC = iNAME(iACC),
		iKeyIn = iNAME(iKeyIn),
		iSpark = iNAME(iSpark),
		iDoorsLamp = iNAME(iDoorsLamp),
		iTrunkLamp = iNAME(iTrunkLamp),
		iTrunkWindow = iNAME(iTrunkWindow),
		iStartStop = iNAME(iStartStop),
		iNeutral = iNAME(iNeutral),
		iLauncher = iNAME(iLauncher),
		iDisarm = iNAME(iDisarm),
		iUnTrunk = iNAME(iUnTrunk),
		iUnLock = iNAME(iUnLock),

		iDevice1 = iNAME(iDevice1),
		iDevice2 = iNAME(iDevice2),
		iDevice3 = iNAME(iDevice3),
		iDevice4 = iNAME(iDevice4),
		iDevice5 = iNAME(iDevice5),
		iDevice6 = iNAME(iDevice6),
		iDevice7 = iNAME(iDevice7),
		iDevice8 = iNAME(iDevice8),

		iCOUNT = CSettings::iCOUNT,

		iStateAtMt = 63			// особый вход: "трансмиссия автомат"
	};

// Виртуальные выходы на исполнительные устройства или
// выход на устройство выполняющее определенную функцию
	enum TOutputs {
	// Неопределенные устройства
		oDevice1 = oNAME(oDevice1),					// 0
		oDevice2 = oNAME(oDevice2),					// 1
		oDevice3 = oNAME(oDevice3),					// 2
		oDevice4 = oNAME(oDevice4),					// 3
		oDevice5 = oNAME(oDevice5),					// 4
		oDevice6 = oNAME(oDevice6),					// 5
		oDevice7 = oNAME(oDevice7),					// 6
		oDevice8 = oNAME(oDevice8),					// 7
	// Базовые устройства Охранной системы
		oSiren = oNAME(oSiren),						// 08 Сирена
		oHorn = oNAME(oHorn),						// 09 Клаксон
		oLights = oNAME(oLights),					// 10 Поворотники
		oLamp = oNAME(oLamp),						// 11 Головное освещение
		oPassiveBlockage = oNAME(oPassiveBlockage),	// 12 Пассивная блокировка (когда выключена, цепь разомкнута, блокировка включена)
		oActiveBlockage = oNAME(oActiveBlockage),	// 13 Активная блокировка (когда выключена, цепь замкнута, блокировка выключена)
		oLockDoors = oNAME(oLockDoors),				// 14 Запереть все двери
		oUnlockDoors = oNAME(oUnlockDoors),			// 15 Отпереть все двери
		oUnlockDoorDrv = oNAME(oUnlockDoorDrv),		// 16 Отпереть дверь водителя
		oLockTrunk = oNAME(oLockTrunk),				// 17 Запереть багажник
		oUnlockTrunk = oNAME(oUnlockTrunk),			// 18 Отпереть багажник
		oLockHood = oNAME(oLockHood),				// 19 Запереть Капот
		oUnLockHood = oNAME(oUnLockHood),			// 20 Отпереть капот
		oCloseWindows = oNAME(oCloseWindows),		// 21 Закрыть окна
		oPreHeaterOn = oNAME(oPreHeaterOn),			// 22 Включение предпускового подогревателя
		oPreHeaterOff = oNAME(oPreHeaterOff),		// 23 Выключение предпускового подогревателя
		oImmOn = oNAME(oImmOn),						// 24 Устройство включающее Иммобилайзер
		oImmOff = oNAME(oImmOff),					// 25 Устройство выключающее Иммобилайзер
		oService = oNAME(oService),					// 26 Устройство переводящее автомобиль в Сервисный режим
		oDisarm = oNAME(oDisarm),					// 27 Устройство осуществляющее снятие с Охраны (можно использовать как выход статической блокировки)
		oArm = oNAME(oArm),							// 28 Устройство осуществляющее постановку под Охрану (можно использовать как выход статической блокировки)
		oAlarm = oNAME(oAlarm),						// 29 Устройство осуществляющее включение тревоги (можно использовать как выход статической блокировки)
		oAutoStart = oNAME(oAutoStart),				// 30 Состояние Автозапуска
	// Базовые устройства АвтоЗапуска (подменяют или имитируют присутствие водителя в автомобиле)
		oDoorWag = oNAME(oDoorWag),					// 31 Устройство махающее дверью
		oIgn = oNAME(oIgn),							// 32 Включение зажигания
		oBrake = oNAME(oBrake),						// 33 Педаль тормоза
		oKeyIn = oNAME(oKeyIn),						// 34 Ключ в замке
		oAcc = oNAME(oAcc),							// 35 Аксессуары
//		oBrakeControl = oNAME(oBrakeControl),		// 36 Отключение контроля педали тормоза
		oAuxBrake = oNAME(oAuxBrake),				// 37 Дополнительная линия педали тормоза
		oAuxIgn = oNAME(oAuxIgn),					// 38 Дополнительная линия зажигания
		oSSButton = oNAME(oSSButton),				// 39 Кнопка Старт/Стоп
		oImmBypass = oNAME(oImmBypass),				// 40 Обходчик встроенного иммобилайзера
		oCrank = oNAME(oCrank),						// 41 Стартер
		oCrankDisable = oNAME(oCrankDisable),		// 42 Блокировка Стартера
	// Дополнительные
		oLockIgn = oNAME(oLockIgn),					// 43 Блокировка зажигания (когда включена, зажигание заблокировано)
		oUnLockIgn = oNAME(oUnLockIgn),				// 44 Разблокировка зажигания (когда включена, зажигание разблокировано)
		oKLine1Relay = oNAME(oKLine1Relay),			// 45 Устройство коммутирующее KLine интерфейс
		oAux1 = oNAME(oAux1),						// 46 Доп.канал #1
		oAux2 = oNAME(oAux2),						// 47 Доп.канал #2
		oAux3 = oNAME(oAux3),						// 48 Доп.канал #3
		oEmergencyBraking=oNAME(oEmergencyBraking),	// 49 Выход сигнала экстренного торможения
		oIllumination = oNAME(oIllumination),		// 50 Выход сигнала вежливой подсветки
		oFoldMirrors = oNAME(oFoldMirrors),			// 51 Сложить зеркала
		oUnfoldMirrors = oNAME(oUnfoldMirrors),		// 52 Разложить зеркала
		oCloseSunroof = oNAME(oCloseSunroof),		// 53 Закрыть люк
		oMoveSunroof = oNAME(oMoveSunroof),			// 54 Сдвинуть люк
		oHeatedSeats = oNAME(oHeatedSeats),			// 55 Обогрев сидений
		oTriggerDoors = oNAME(oTriggerDoors),		// 56 Триггерная кнопка ЦЗ
		oIgnSupport = oNAME(oIgnSupport),			// 57 Состояние поддержки зажигания
		oArmWithoutTag = oNAME(oArmWithoutTag),		// 58 Состояние "Охрана без метки"
		oHeatedWindows = oNAME(oHeatedWindows),		// 59 Обогрев окон
		oKLine2Relay = oNAME(oKLine2Relay),			// 60 m34x46: Коммутация Lin2
		oDVR = oNAME(oDVR),							// 61 m34x46: Выход на видеорегистратор
	// Общее кол-во виртуальных устройств
		oCOUNT = CSettings::oCOUNT,
	};

// режимы входов
	enum TInputActiveState {
		ActiveGND = 1		// Активное состояние, когда на входе GND
	};

// режимы подтяжек входов
	enum TInputPullupMode {
		PullNone = 0,
		PullDown = 2,
		PullUp = 3,
	};

	#undef iPIN
	#undef oNAME
	#undef iNAME

#ifndef CAN_FIRMWARE

	void Init(void);
	void UpdateSettings(const uint idSettings);

// проверка, что вход (физический) используется
	static bool IsInputMapped(TInPins aPhInput);

// чтение и обработка мгновенных состояний входов для получения устойчивых физических состояний
	uint32_t ReadInputPins(void);
// Конвертирование переданных физический состояний (REMAP) в соответствующие логические состояния
	TInpMask RemapInputs(uint32_t iPins);

// установка физических выходов
	void SetOutPhys(const TOutPins pin, const bool state);

// Установка логических выходов.
// Возвращает:
	enum TSetOutputResult : uint {
		soNone		= 0,	// нет такого выхода или он никуда не назначен
		soExist		= 1,	// Выход назначен, но состояние не изменилось
		soChanged	= 2		// выход назначен и состояние было изменено
	};
	TSetOutputResult SetOutput(const TOutputs aOutput, const bool state);
// Запрос текущего состояния логического выхода
	inline bool GetOutput(const TOutputs Output) const {return bbRAM(oStates,Output);};

// Вернуть состояние логических выходов (функций выходов)
	inline TOutMask GetOutputs(void) const {return oStates;}
// Вернуть состояние логических входов (функций входов)
	inline TInpMask GetInputs(void) const {return iStates;}
// Вернуть состояние физических выходов
	inline uint32_t GetOutPhys(void) const {return opStates;}
	inline bool GetOutPhys(const TOutPins pin) const
	{	return GetOutPhys() & BIT(pin);	}

// петля "тип коробки"
	static bool StateAtMt(void);

private:
	TOutMask oStates;				// сохраненные состояния логических выходов (всех функций выходов)
	TInpMask iStates;				// сохраненные состояния логических входов (всех функций входов)
	uint32_t ipStates, ipTemp;		// физические состояния входов, очищенные от дребезга...
	uint32_t opStates;				// физические состояния выходов

	struct TInputPin {
		TimerMs		Timer;
		uint16_t	TimeOut;
		uint8_t		Stage;
	};
	TInputPin iPin[ipCOUNT];

// получение мгновенных состояний со входов
	static uint32_t GetInputPins(void);

// управляет состояниями подтяжек на входах
	static void SetPullInput(TInPins Input, TInputPullupMode Mode);

	inline void ClrOutputState(TOutputs Output) {bbRAM(oStates,Output) = 0;};
	inline void SetOutputState(TOutputs Output) {bbRAM(oStates,Output) = 1;};

#endif	// ! CAN_FIRMWARE
};

// глобальный объект портов ввода-вывода
extern CIO	gIO;

#endif /* DRIVERS_IO_H_ */
