/*
 * CanFwInterface.h
 *
 *  Created on: 13 мая 2015 г.
 *      Author: esaulenko
 */

#ifndef CANFWINTERFACE_H_
#define CANFWINTERFACE_H_

#include "CommonTypes.h"

// размер области памяти под переменные CAN-прошивки
enum { gCanFwMemSize = 2048 };

// объявляем структуры заранее, чтобы не было взаимных ссылок
struct TCanPkt;

union TLinInit;
struct TLinFrame;

#if CAN_FIRMWARE
	struct TCanFwMem;
#else	// Core
	typedef char TCanFwMem[gCanFwMemSize];
#endif

// команды ядра, которые может вызывать CAN-прошивка
enum TCoreCommands : uint8_t {
	CoreCmdDisarm = 1,				// команда снятия с охраны Параметр: b00CHASFL
									// бит 0(L) - отпирать замки;
									// бит 1(F) - мигать поворотниками;
									// бит 2(S) - гудеть сиреной;
									// бит 3(A) - если команда подана в режиме тревоги, прекратить ее, не снимая с охраны;
									// бит 4(H) - режим Handsfree, позволяет сниматься с Охраны в любой момент начала Автозапуска и блокирует Перепостановку;
									// бит 5(C) - выдавать сигналы управления функциями Комфорта.
	CoreCmdArm = 2,					// команда постановки на охрану Параметр: b00C00SFL
									// бит 0(L) - запирать замки;
									// бит 1(F) - мигать поворотниками;
									// бит 2(S) - гудеть сиреной;
									// бит 5(C) - выдавать сигналы управления функциями Комфорта.
	CoreCmdTrunkOpened = 3,			// команда оповещения Системы о том, что багажник открыт: b00000SF0
	//CoreCmdAlarm = 6,				// не реализовано
	CoreCmdDisableShockSens = 7,	// Отключить реакцию на датчик Удара в течении <Параметр> времени в мсек
	CoreCmdDisableDoorSens = 8,		// Задержать реакцию на концевики дверей в течении <Параметр> времени в мсек
	CoreCmdLauncherOn = 9,			// команда оповещения Системы о включении внешнего запуска: <Параметр> - время ожидания запуска в сек
	CoreCmdLauncherOff = 10,		// команда оповещения Системы о выключении внешнего запуска: <Параметр> - время ожидания глушения или перезапуска в сек
	CoreCmdDisableTrunkSens = 11,	// Задержать реакцию на концевики багажника в течении <Параметр> времени в мсек
	CoreCmdImmoLearnRes = 12,		// Результат обучения иммобилайзера: 0 - успех, нужно запомнить VIN, 0x80 - успех, VIN не нужен, другое - ошибка
	CoreCmdImmoLearnContinue = 13,	// Управление обучением иммо: 1 - перезапуск таймаута; 2 - необходимо выключить зажигание; 3 - подать сигнал антенным модулем
	CoreCmdStartStop = 14,			// Управление запуском со штатного брелока (например, трехкратным нажатием на кнопку закрыть)
	CoreCmdMenuResult = 15,			// Результат выполнения команды из меню антенны: 0 - успех, 1 - ошибка
};

// Список команд предназначеных/определенных/известных CAN прошивке
enum TCanFwCommands : uint8_t {
	ccNone					= 0,	// нет команды/не команда, либо команда неизвестна/неопределена...
	ccLockDoors				= 1,	// Запереть все двери
	ccUnLockDoors			= 2,	// Отпереть все двери
	ccUnLockDoorDrv			= 3,	// Отпереть дверь водителя
	ccLockTrunk				= 4,	// Запереть багажник
	ccUnLockTrunk			= 5,	// Отпереть багажник
	ccLockHood				= 6,	// Запереть капот
	ccUnLockHood			= 7,	// Отпереть капот
	ccCloseWindows			= 8,	// Закрыть окна
	ccOpenWindows			= 9,	// Открыть окна
	ccService				= 10,	// включение режима Автосервис
	ccDisarm				= 11,	// выключение режима Охраны
	//reserved				= 12,
	ccArm					= 13,	// включение режима Охраны
	//reserved				= 14,
	//reserved				= 15,
	ccAlarmOff				= 16,	// выключить Тревогу
	ccAlarmOn				= 17,	// включить Тревогу
	ccPanicOff				= 18,	// выключение режима Паника
	ccPanicOn				= 19,	// включение режима Паника
	ccImmobilizerOff		= 20,	// выключить Иммобилайзер
	ccImmobilizerOn			= 21,	// включить Иммобилайзер
	ccIgnSupportOff			= 22,	// выключение поддержки зажигания
	ccIgnSupportOn			= 23,	// включение поддержки зажигания
	ccBlockageOff			= 24,	// выключить блокировку
	ccBlockageOn			= 25,	// включить блокировку
	ccEngineStart			= 26,	// запуск двигателя (по ошибке, стало событием)
	ccEngineStop			= 27,	// глушение двигателя (по ошибке, стало событием)
	ccTestMode				= 28,	// включение Тест-режима
	ccFoldMirrors			= 29,	// сложить зеркала
	ccUnFoldMirrors			= 30,	// разложить зеркала
	ccCloseSunroof			= 31,	// закрыть люк
	ccHeatedSeatsOn			= 32,	// включить подогрев сидений
	ccHeatedSeatsOff		= 33,	// выключить подогрев сидений
	ccPreHeaterOff			= 34,	// выключить предпусковой подогреватель
	ccPreHeaterOn			= 35,	// включить предпусковой подогреватель
	ccAutoStartOff			= 36,	// выключение запуска
	ccAutoStartOn			= 37,	// включение запуска
	ccAutoStartDone			= 38,	// успешный запуск
	ccKillEngine			= 39,	// заглушить двигатель!
	ccImmoBypass			= 40,	// обходчик иммобилайзера: бит 0 - включить; бит 1 - режим обучения
	ccUpdateVin				= 41,	// обновить VIN-код
	ccSendObdReq			= 42,	// запрос OBD-диагностики
	ccValetMenuCmd			= 43,	// команда из меню антенны
	ccHeatedWindowsOn		= 44,	// включить подогрев окон
	ccHeatedWindowsOff		= 45,	// выключить подогрев окон
};

// Параметры команд для CAN прошивки, битовая маска (всего 24 бита)
enum TCanFwCommandParam : uint32_t {
	mccReserved				= (1 << 0),	// резерв
	mccSilent				= (1 << 1),	// беззвучное исполнение команды
	mccPriority				= (1 << 2),	// приоритетное открытие двери водителя (ccDisarm)
	mccDriveBuiltinSystem	= (1 << 3),	// разрешено управлять штатной охранной системой (ccLockTrunk/ccUnLockTrunk)
};

// данные, которые CAN-прошивка может передать в ядро
enum TCanFwData : uint8_t {

	CanData_RPM				= 0,	// обороты, об/мин
	CanData_Speed			= 1,	// скорость, км/ч
	CanData_Odometer		= 2,	// пробег, 1 ед = 100 метров

	CanData_Accelerator		= 3,	// положение педали газа, проценты
	CanData_BrakeForce		= 4,	// положение педали тормоза, проценты
	CanData_WheelAngle		= 5,	// положение руля

	CanData_FuelLevel		= 6,	// уровень топлива, проценты
	CanData_FuelConsumption	= 7,	// мгновенный расход, миллилитры

	CanData_CoolantTemp		= 8,	// температура двигателя, со смещением 40 градусов

	CanData_VIN				= 9,	// VIN-код

	CanData_FuelLevelRaw	= 10,	// уровень топлива, без калибровки 0..255

	CanData_COUNT,					// количество возможных полей с данными
	CanData_Invalid			= 0x80,
};

// описание CAN-прошивки
extern const TCanFwInfo gCanFwInfo;

// структура с функциями CAN, которые вызываются из ядра
struct TCanFunctions
{
	TCanFwInfo	const *			pCanFwInfo;
	uint8_t		const *			pSettingsTable;
	char		const * const *	pSettingsNames;

	void (*Init)(TCanFwMem * vars);

	void (*Periodic)(TCanFwMem * vars);

	void (*SettingChanged)(TCanFwMem * vars, uint16_t id);
	void (*Reserved6)();

	void (*InputChanged)(TCanFwMem * vars, uint32_t aInput, bool aSwitchedOn);
	void (*OutputChanged)(TCanFwMem * vars, uint32_t aOutput, bool aSwitchedOn);
	void (*GuardEvent)(TCanFwMem * vars, TGuardEvents aEvent);

	void (*Can1Received)(TCanFwMem * vars, TCanPkt *apPkt);
	void (*Can2Received)(TCanFwMem * vars, TCanPkt *apPkt);

	void (*SequenceStart)(TCanFwMem * vars, uint32_t aOutputNum);
	void (*SequenceStop)(TCanFwMem * vars, uint32_t aOutputNum);

	void (*Command)(TCanFwMem * vars, TCanFwCommands aCmd, uint32_t aCmdParam);

	void (*Lin1Received)(TCanFwMem* vars, TLinFrame* apFrame);
	void (*Lin2Received)(TCanFwMem* vars, TLinFrame* apFrame);
	void (*Lin1Transmitted)(TCanFwMem* vars, uint8_t aFrameId);
	void (*Lin2Transmitted)(TCanFwMem* vars, uint8_t aFrameId);
#if defined MOBICAR_1_2
	void (*Reserved19)();
	void (*Reserved20)();
#elif defined MOBICAR_3 || defined MAGICAR_X
	void (*Lin3Received)(TCanFwMem * vars, TLinFrame *apFrame);
	void (*Lin3Transmitted)(TCanFwMem * vars, uint8_t aFrameId);
#endif

	void (*Reserved21)();
	void (*Reserved22)();
	void (*Reserved23)();
	void (*Reserved24)();
	void (*Reserved25)();
	void (*Reserved26)();
	void (*Reserved27)();
	void (*Reserved28)();
	void (*Reserved29)();
	void (*Reserved30)();
	void (*Reserved31)();
};
static_assert (sizeof(TCanFunctions) == 4*32, "В таблице должно быть 32 поля");

// структура с функциями ядра, которые вызываются из CAN-прошивки
struct TCoreFunctions
{
	const TCoreInfo* pCoreInfo;

	uint32_t (*GetTickMs) ();

	uint32_t (*CanInit) (TCanChannel aCh, const TCanInit* apInit);
	uint32_t (*CanSend) (TCanChannel aCh, TCanPkt* apPkt, uint32_t timeout);

	uint64_t (*GetInputs) ();
	uint64_t (*GetOutputs) ();
#if defined MOBICAR_3 && 1		// Только для отладки (работает только с отладочной или спец. прошивками)
	typedef struct {
		uint8_t BlinkOff;	// [50ms]
		uint8_t BlinkOn;	// [50ms]
		uint8_t BeepTime;	// [50ms]
		uint8_t BeepTone;
	} TDebugIndicate;
	void (*DebugIndicate)(TDebugIndicate const & aIndicate, const uint8_t nBlink);
#else
	void (*Reserved6)();
#endif

	uint32_t (*Command) (TCoreCommands aCmd, uint32_t aParam);
	uint32_t (*RunSequence) (uint32_t aOutput, uint32_t aSequenceNum);

	uint32_t (*SetPeriod) (uint32_t aPeriod);

	uint32_t (*SetOutput) (uint32_t aOutput, bool On);

	uint32_t (*InputState) (uint32_t aInput, bool On);
	uint32_t (*DataValue) (uint32_t aDataIdx, int32_t aValue);

	uint32_t (*CanGetRxTimeout) (TCanChannel aCh);

	uint32_t (*LinInit) (TLinChannel aCh, const TLinInit* apInit);
	uint32_t (*LinSend) (TLinChannel aCh, const TLinFrame* apFrame);
	uint32_t (*LinSleep) (TLinChannel aCh, bool aSleep);
	void (*Reserved17)();

	uint32_t (*DataValueArr) (uint32_t aDataIdx, const void * data);
	bool (*CheckVinValid) ();
	bool (*SaveSetting) (uint16_t id, const void * apData, uint16_t aDataSize);
	const void *(*GetSetting) (uint16_t id);

	bool (*SaveImmoLearn) (const void *data, uint32_t dataSize);

	void (*Reserved23)();
	void (*Reserved24)();
	void (*Reserved25)();
	void (*Reserved26)();
	void (*Reserved27)();
	void (*Reserved28)();
	void (*Reserved29)();
	void (*Reserved30)();

	void (*DebugConsole)(const char *, ...);
};
static_assert (sizeof(TCoreFunctions) == 4*32, "В таблице должно быть 32 поля");

// таблица с доступными функциями ядра
	#define CoreFunc	((TCoreFunctions*) ((uint32_t) &FW_AREAS->Core + 512) )   // 16K + 512

#if defined CAN_FIRMWARE
// объявление функций CAN-прошивки

void Init (TCanFwMem * vars);
void SettingChanged (TCanFwMem * vars, uint16_t id);

void Can1Received (TCanFwMem * vars, TCanPkt *apPkt);
void Can2Received (TCanFwMem * vars, TCanPkt *apPkt);

void InputChanged  (TCanFwMem * vars, uint32_t aInputNum, bool aSwitchedOn);
void OutputChanged (TCanFwMem * vars, uint32_t aOutputNum, bool aSwitchedOn);
void GuardEvent (TCanFwMem * vars, TGuardEvents aEvent);

void SequenceStart (TCanFwMem * vars, uint32_t aEvent);
void SequenceStop (TCanFwMem * vars, uint32_t aEvent);

void Command (TCanFwMem * vars, TCanFwCommands aCmd, uint32_t aCmdParam);

void PeriodicProcess (TCanFwMem * vars);

void Lin1Received (TCanFwMem * vars, TLinFrame *apFrame);
void Lin2Received (TCanFwMem * vars, TLinFrame *apFrame);
void Lin3Received (TCanFwMem * vars, TLinFrame *apFrame);

void Lin1Transmitted (TCanFwMem * vars, uint8_t aFrameId);
void Lin2Transmitted (TCanFwMem * vars, uint8_t aFrameId);
void Lin3Transmitted (TCanFwMem * vars, uint8_t aFrameId);

#else	// core

// таблица с доступными функциями CAN-прошивки, лежит в её начале
	#define CanFwFunc	((TCanFunctions*) &FW_AREAS->CanFw)

#endif

#endif /* CANFWINTERFACE_H_ */
