/*
 * CommonTypes.h
 *
 *  Created on: 16 апр. 2015 г.
 *      Author: esaulenko
 */

#ifndef COMMON_COMMONTYPES_H_
#define COMMON_COMMONTYPES_H_

#include <cstdint>

#define member_size(type, member) sizeof(((type*)nullptr)->member)

//typedef uint8_t 		byte;
//typedef uint16_t 		word;
typedef	unsigned int	uint;
typedef	unsigned long	ulong;

//#define bbRAM(Var,Bit)	((uint*)(((uint)&Var + 0x22000000/32)*32))[Bit]
#define bbRAM(Var,Bit)	((volatile uint*)(((uint)&Var + SRAM_BB_BASE/32)*32))[Bit]
// !!! Начиная с компилятора версии 7, что-то в оптимизаторе изменилось.. и теперь, без volatile
// программа компилируется неверно. Поэтому добавляем признак volatile !!!

#define KByte	*1024

union TSysStateRecord
{
	uint16_t Record;
	struct {
		uint8_t Value;		// Значение состояния Системы
		uint8_t Check;		// Проверка данных
	} __attribute__((packed));
} __attribute__((packed));

typedef TSysStateRecord TSysState[2 KByte / sizeof(TSysStateRecord)];

struct TFwRegions
{
#if defined MOBICAR_1_2
// страницы по 2 кбайта
	const uint8_t Boot[16 KByte];
	const uint8_t Core[96 KByte];
	const uint8_t CanFw[16 KByte];
	const uint8_t Upload[96 KByte];
	const uint8_t Settings1[4 KByte];
	const uint8_t Settings2[4 KByte];
	const uint8_t Reserved[20 KByte];
	const uint8_t ImmoLearn[2 KByte];
	const TSysState SysState;
#elif defined MOBICAR_3
	const uint8_t Boot[16 KByte];			// sector 0
	const uint8_t Settings1[16 KByte];		// sector 1
	const uint8_t Settings2[16 KByte];		// sector 2
	const uint8_t CanFw[16 KByte];			// sector 3
	struct {
		const uint8_t UploadAux[64 KByte - sizeof(TSysState)];	// sector 4
		const TSysState SysState;
	} __attribute__((packed));
	union {
		const uint8_t Upload[128 KByte];	// sector 5
		const uint8_t ImmoLearn[2 KByte];
	} __attribute__((packed));
	const uint8_t Core[2 * 128 KByte];		// sector 6, 7
#endif
};
#define FW_AREAS	((TFwRegions const *)0x08000000)

// специальное значение для контрольной суммы - используется только в отладочной прошивке
#define CHKSUM_DEBUG		0xDebac0ab

// битовая настройка, используется в модуле настроек. Для простоты реализации занимает в ОЗУ 1 байт.
typedef	uint8_t		bit_t;

// **********
// * Версия *
// **********
union TVersion
{
	uint32_t Value;
	struct {
		uint8_t		Day;
		uint8_t 	Month;
		uint8_t 	Year;
		uint8_t 	Version;
	} __attribute__((packed));
} __attribute__((packed));

struct TBootInfo {
	TVersion		Version;				// Версия загрузчика
	uint16_t 		Build;					// Номер билда загрузчика
	uint8_t			HwVer;					// Версия железа
	uint8_t			Model;					// Модель устройства. Mobicar1 = 0 (!), Mobicar2 = 2
	uint32_t		SerialNumber;			// Серийный номер устройства
	uint32_t		reserved2;

	uint8_t			FirmwareKey[32];		// Ключ дешифрования прошивки
	uint8_t			ServerRegKey[12];		// ключ регистрации на сервере
	uint8_t			ServerExchKey[16];		// ключ установки соединения с сервером
	uint32_t		BluetoothPairingCode;	// статический код для подшивания BLE устройств

	uint32_t		reserved[120];
} __attribute__((packed, aligned(4)));
#define	TBootInfoSize	__builtin_offsetof (TBootInfo, FirmwareKey)
static_assert (TBootInfoSize == 16, "TBootInfo changed!");

struct TCoreInfo {
	TVersion			Version;			// Версия ПО
	uint16_t			Build;				// Номер билда ядра
	uint16_t			reserved1;
	uint32_t const *	pCRC32;				// Адрес, где расположена CRC32 в прошивке Ядра
	uint32_t			reserved2;
	char				TextInfo[64];		// Текстовая информация о прошивке Ядра
} __attribute__((packed, aligned(4)));
static_assert (sizeof(TCoreInfo) == 80, "TCoreInfo changed!");

// Структура массива информации о CAN-прошивке
struct TCanFwInfo {
	TVersion			Version;			// Версия ПО
	uint32_t			Build;				// Хеш коммита в репозитории git
	uint32_t const *	pCRC32;				// Адрес, где расположена CRC32
	uint32_t			reserved2;
	uint8_t				TextInfo[64];		// Текстовая информация
} __attribute__((packed, aligned(4)));
static_assert (sizeof(TCanFwInfo) == 80, "TCanFwInfo changed!");

// ********************
// * НАСТРОЙКА ВХОДОВ *
// ********************
struct TInputPinSettings {
	uint16_t T1:14;	// период активного импульса
	uint16_t P1:2;	// Подтяжка: [xy]: непрограммируемая(x=0)/программируемая(x=1)/pulldown(y=0)/pullup(y=1).
	uint16_t T2:14;	// период пассивного импульса
	uint16_t P2:2;	// Подтяжка: [xy]: непрограммируемая(x=0)/программируемая(x=1)/pulldown(y=0)/pullup(y=1).
// Таблица истинности:
//	T1	P1	T2	P2	Debounce
//	0	p	0	x	tick	статика, без антидребезга
//	>0	p	0	x	T1		статика с периодом антидребезга равного T1
//	0	p	>0	p	tick	динамика, P1 включается на TICK, затем P2 включается на T2, без антидребезга.
//	>0	p	>0	p	T1		динамика, P1 включается на T1*2, затем P2 включается на T2, антидребезг T1.
} __attribute__((packed));

struct TInputSettings {
	uint8_t Input:7;	// номер физического входа
	uint8_t Invert:1;	// Инвертировать состояние

	bool operator== (const TInputSettings &other)
	{	return *((uint8_t*)this) == *((uint8_t*)(&other));	}
	bool operator!= (const TInputSettings &other)
	{	return ! (*this == other);							}
} __attribute__((packed));

enum {
	SequenceLength = 16,
	maxSequences = 32,		// кол-во импульсных последовательностей одновременно запущенных
};

// последовательности управления выходами
union TSequence {
	uint8_t Byte[SequenceLength];
	union {
		uint8_t Value;
		struct {
			uint8_t Mantissa:5;
			uint8_t Power:3;
		};
	} Step;
} __attribute__((packed));

typedef uint8_t TKeyAES[16];		// ключ шифрования радио

typedef uint8_t TVehicleID[17];		// VIN-код

//typedef uint8_t TImmoKey[124];		// ключ обходчика иммобилайзера
typedef uint8_t TImmoKey[32];		// ключ обходчика иммобилайзера


// настройка таймера запуска
struct TStartTimerSetting {
	uint16_t	Time;		// количество минут с начала суток. У выключенного таймера биты инвертированы
	uint8_t 	DayMask;	// Биты дней недели, когда разрешён запуск - 0..6. Для "старого" механизма устанавливается 0xFF
}  __attribute__((packed));

// CAN data forward declarations
struct TCanInit;
struct TCanPkt;

enum TCanChannel {
	CANch1 = 0,
	CANch2 = 1,
};

enum TLinChannel {
	LINch1 = 0,
	LINch2 = 1,
#if defined MOBICAR_3
	LINch3 = 2,
#endif
};

enum TGuardEvents {
	geSetSysMode				= 0,	// события о смене режима Системы
		geRESET						= 0,	// событие сброс по Питанию
		geTEST						= 1,	// включился режим Теста
		geSERVICE					= 2,	// включился режим Автосервис
		geDISARM					= 3,	// включился режим Вне Охраны
		geHIJACK					= 4,	// включился режим Антизахват
		geARM						= 5,	// включился режим Охрана
		geGM6						= 6,	// резерв
		geGM7						= 7,	// резерв
	aseSetMode					= 8,	// события о смене режима Автозапуска
		aseIDLE						= 8,	// Дежурный режим
		aseREADY					= 9,	// Включение поддержки зажигания
		asePRESTART_WaitForIgnOn	= 10,	// Подготовка к запуску двигателя: Ожидание включения Зажигания
		asePRESTART_WaitForIgnOff	= 11,	// Подготовка к запуску двигателя: Ожидание выключения Зажигания
		aseCRANK					= 12,	// Запуск двигателя (стартер)
		asePRESUPPORT				= 13,	//
		aseSUPPORT					= 14,	// Поддержка зажигания после запуска
		asePITSTOP					= 15,	// Режим PITSTOP
		aseSTOP						= 16,	// Режим STOP
		aseISOFF					= 17,	// Режим ISOFF
		aseDoorWag					= 18,	// Махание дверью
		aseStopDoorWag				= 19,	// Остановка процесса махания дверью
		aseSetIDLE					= 20,	// Переход в дежурный режим
		aseSetREADY					= 21,	// Переход в режим поддержки зажигания
		aseSetPITSTOP				= 22,	// Переход в режим PITSTOP
		aseSetPRESTART				= 23,	// Переход в режим подготовки к запуску двигателя
		aseSetSUPPORT				= 24,	// Переход в режим поддержки зажигания
		aseSetSTOP					= 25,	// Остановка двигателя
		aseSetISOFF					= 26,	// Выключение поддержки зажигания
		aseLauncher					= 27,	// Мотор запущен внешним запуском
		asePreHeater				= 28,	// Предпусковой подогреватель включен
		aseASM21					= 29,	// резерв
		aseReloadTimer				= 30,	// продление/перезагрузка времени режима
		aseCommandError				= 31,	// ошибка выполнения команды или не возможность выполнить команду
// Общие события
	geLocked					= 32,	// ЦЗ закрыт
	geUnLocked					= 33,	// ЦЗ открыт
	geBlockageOff				= 34,	// Блокировка выключена
	geBlockageOn				= 35,	// Блокировка включена
	geReservationOff			= 36,	// Резервирование выключено
	geReservationOn				= 37,	// Резервирование включено
	geEngineStopped				= 38,	// Двигатель остановился
	geEngineRuns				= 39,	// Двигатель завелся
	geTurboTimerEnd				= 40,	// Турботаймер завершился
	geTurboTimerStart			= 41,	// Турботаймер запустился
	gePanicOff					= 42,	// выключился режим Паника
	gePanicOn					= 43,	// включился режим Паника
	geArmDefeatZone				= 44,	// оповещение об открытых зонах во время постановки в Охрану
	geAlarmOff					= 45,	// выключился режим Тревоги
	geAlarmOn					= 46,	// включить тревогу снова
	geDoorsAlarm				= 47,	// включилась Тревога по дверям (салону)
	geTrunkAlarm				= 48,	// включилась Тревога по багажнику
	geHoodAlarm					= 49,	// включилась Тревога по капоту
	geIgnAlarm					= 50,	// включилась Тревога по зажиганию
	geShockAlarm				= 51,	// включилась Тревога по датчику Удара
	geResetAlarm				= 52,	// включилась Тревога по сбросу Питания
	geDoorsDefeated				= 53,	// отключилась охранная зона по двери
	geTrunkDefeated				= 54,	// отключилась охранная зона по багажнику
	geHoodDefeated				= 55,	// отключилась охранная зона по капоту
	geIgnDefeated				= 56,	// отключилась охранная зона по зажиганию
	geShockDefeated				= 57,	// отключилась охранная зона по датчику Удара
	geTrunkOpened				= 58,	// багажник открыт
	geTrunkClosed				= 59,	// багажник закрыт
	geShockNotify				= 60,	// предупреждение по датчику Удара
	geShockArmOff				= 61,	// оперативное отключение зоны датчика Удара
	geCarOwnerCall				= 62,	// вызов владельца автомобиля
	geTiltAlarm					= 63,	// включилась Тревога по датчику Наклона
	geTiltDefeated				= 64,	// отключилась охранная зона по датчику Наклона
	geValetArm					= 65,	// событие поставить в Охрану в режиме Автосервис
	geValetDisarm				= 66,	// событие снять с Охраны в режиме Автосервис
	geAlarmEnd					= 67,	// событие прекращения тревоги
	geTrunkUnLock				= 68,	// багажник отпирается или отперт
	geTrunkLock					= 69,	// багажник запирается или заперт
	geImHereOff					= 70,	// выключился механизм поиска Автомобиля на стоянке
	geImHereOn					= 71,	// включился механизм поиска Автомобиля на стоянке
	geMotionAlarm				= 72,	// включилась Тревога по датчику Перемещений
	geMotionDefeated			= 73,	// отключилась охранная зона по датчику Перемещений
	geArmed						= 74,	// Система встала под Охрану
	geArmReturnOff				= 75,	// Перепостановка отключена
	geArmReturnOn				= 76,	// Активирован режим перепостановки
	geAux1Off					= 77,	// Доп.канал #1 выключен
	geAux1On					= 78,	// Доп.канал #1 включен
	geAux2Off					= 79,	// Доп.канал #2 выключен
	geAux2On					= 80,	// Доп.канал #2 включен
	geAux3Off					= 81,	// Доп.канал #3 выключен
	geAux3On					= 82,	// Доп.канал #3 включен
	geSensorAlarm				= 83,	// тревога по внешнему Сенсору
	geSensorDefeated			= 84,	// отключилась охранная зона по входу от внешнего Сенсора
	geHandsfreeDisabled			= 85,	// сообщение о временном запрете Автопостановки/Автоснятия
	geHandsfreeEnabled			= 86,	// сообщение о разрешении Автопостановки/Автоснятия
	geValetDisabledByImm		= 87,	// включение режима Автосервис заблокировано по причине активированного Иммобилайзера
	geDisarmDisabledByTag		= 88,	// снятие с Охраны заблокировано по причине отсутствия Метки
	geUnTrunkDisabledByTag		= 89,	// отпирание багажника заблокировано по причине отсутствия Метки
	geImmoIndicationStart		= 90,	// индикация включенного иммобилайзера
	geSensorNotify				= 91,	// предупреждение по внешнему Сенсору
	geDrivingEnabled			= 92,	// поездка разрешена (иммобилайзер был отключен ПИН кодом)
	geTripFinish				= 93,	// Поездка закончилась
	geTripStart					= 94,	// Поездка началась
	geTripPaused				= 95,	// Поездка приостановилась

// Команды Брелока (176+)
	bcSendState					= 0xB0,	// Выслать текущий режим Системы (она же ресинхронизация)
	bcChangeSoundMode,					// Изменение режима выдачи звуков
	bcChangeShockMode,					// Изменение режима работы датчика Удара
	bcChangeAutomatics,					// Изменения в режимах работы Автоматических запусков
	bcChangeInternetOption,				// Изменения в режиме работы INTERNET опции
	bcProgMenuEnter,					// Перевести брелок в меню программирования
	bcProgMenuExit,						// Выход из меню программирования Брелока
	vmShowPinCode,						// Показать на индикаторе текущее значение ПИН-кода
	bcProgMenu2,						// Переход к меню 2
	bcBleMenuEnter,						// Переход к меню спаривания BLE
	bcHandsfreeModeChange,				// Изменение режима работы "Свободных рук"

	geDEBUG						= 0xFE,
	geNONE						= 0xFF	// нет события, т.е. его не нужно никуда отправлять
};

union TDiagnosticTroubleCode {
	uint16_t B1B0;
	uint8_t Byte[2];
	struct {
		uint8_t B0;
		uint8_t B1;
	} __attribute__((packed));
	struct {
		uint16_t X:4;
		uint16_t N:2;
		uint16_t K:2;
		uint16_t Z:4;
		uint16_t Y:4;
	} __attribute__((packed));
} __attribute__((packed));

#endif /* COMMON_COMMONTYPES_H_ */
