//#############################################################################################################################################################################################################
#include "IDIBUS_IMPL.h"
#include "EEMEM.h"
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// At the request of the customer
volatile char IDUBUS_SPEC_FRAZE_RU[] = "мекегрэ   !!!";
volatile char IDUBUS_SPEC_FRAZE_EN[] = "HANDS OFF !!!";
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#ifdef _LONG_ADDR_SPACE_
void IDIBUS_ModuleInit(USART_INTERFACE_TYPE *USART_INTERFACE, uint_farptr_t PROGMEM_SN)
#else
void IDIBUS_ModuleInit(USART_INTERFACE_TYPE *USART_INTERFACE, uint8_t *PROGMEM_SN)
#endif
{
	if (IDUBUS_SPEC_FRAZE_RU[0]) {}
	if (IDUBUS_SPEC_FRAZE_EN[0]) {}

	IDIBUS_MODULE.USI = USART_INTERFACE;

	IDIBUS_CustomInit();

	IDIBUS_MODULE.FreezeMemState = IDISTATUS_B0S_ST_STATE_StOperate;
	IDIBUS_MODULE.LONG_OP.Type = IDIBUS_LONGOP_NOPE;
	IDIBUS_MODULE.LONG_OP.Switch = 0;
	IDIBUS_MODULE.LONG_OP.State = IDILONGOP_STATE_COMPLETE_NO_ERR;
	IDIBUS_MODULE.Error = IDIER_NOPE;
	IDIBUS_MODULE.c_InitAssignGroup = IDIBUS_GROUP_0_ADDR;

	// SN read ------------------------------------------------------------------------------------------------------>
	IDIBUS_MODULE.STATUS.SNfix = PROGMEM_SN;
	IDIBUS_MODULE.STATUS.SNvar = &EEBLOCK.EEPROM_SN;
	//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	uint8_t InitAssignGroup = eeprom_read_byte(&EEBLOCK.EEPROM_IDIBUS_InitGroup);

	if ( (InitAssignGroup > IDIBUS_GROUP_0_ADDR ) && (InitAssignGroup <= IDIBUS_GROUP_15_ADDR) )
	{
		for (uint8_t Dev = 0; Dev < IDIBUS_MODULE.DevicesCount; Dev++)
		{
			for (uint8_t Ch = 0; Ch<IDIBUS_MODULE.Devices[Dev].ChannelsCount; Ch++) { IDIBUS_MODULE.Devices[Dev].Channels[Ch].BcastAddr = InitAssignGroup; }
		}
		eeprom_write_byte(&EEBLOCK.EEPROM_IDIBUS_InitGroup, 0xFF);
	}
}
//=============================================================================================================================================================================================================
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//=============================================================================================================================================================================================================
void IDIBUS_ModuleBackgroundHandler(void)
{
	// Long Operation Routine ------------------------>
	switch ( IDIBUS_MODULE.LONG_OP.Type )
	{
		case (IDIBUS_LONGOP_VARSN_IP_WRITE) : {
			if (IDIBUS_MODULE.LONG_OP.Switch == 0){
				EEPROM_WriteEepBuf(IDISN_VARP_IPv4_Length+IDISN_VARP_IPv6_Length,&EEBLOCK.EEPROM_SN[IDISN_VARP_IPv4_Pos]);
			}
		break; }

		case (IDIBUS_LONGOP_VARSN_VERIF_EXP_WRITE) : {
			if (IDIBUS_MODULE.LONG_OP.Switch == 0){
				EEPROM_WriteEepBuf(IDISN_VARP_EXPIR_DATE_Length+IDISN_VARP_VERIF_DATE_Length,&EEBLOCK.EEPROM_SN[IDISN_VARP_VERIF_DATE_Pos]);
			}
		break; }

		case (IDIBUS_LONGOP_VARSN_AES_WRITE) : {
			if (IDIBUS_MODULE.LONG_OP.Switch == 0){
				EEPROM_WriteEepBuf(IDISN_VARP_AES256_Length,&EEBLOCK.EEPROM_SN[IDISN_VARP_AES256_Pos]);
			}
		break; }

		case (IDIBUS_LONGOP_INIT) : {

			if ( IDIBUS_MODULE.c_InitAssignGroup != IDIBUS_GROUP_0_ADDR )
			eeprom_write_byte(&EEBLOCK.EEPROM_IDIBUS_InitGroup,IDIBUS_MODULE.c_InitAssignGroup);

			uint8_t TimeoutMS = 200;
			while ( (!eeprom_is_ready() || IDIBUS_MODULE.USI->IsTxActive()) && (TimeoutMS != 0) ) { TimeoutMS--; _delay_ms(1); }
			System_SWReboot();
		break; }

		default : {}
	}

	// Error Handler Routine ------------------------>
	if ( IDIBUS_MODULE.LONG_OP.State == IDILONGOP_STATE_IN_PROC )
	{
		if ( System_GetSysTickDifference(IDIBUS_MODULE.LONG_OP.StartTimeInstanceMS) > IDIBUS_MODULE.LONG_OP.DurationMS )
		{
			// Long Operation terminate function
			IDIBUS_MODULE.LONG_OP.State  = IDILONGOP_STATE_COMPLETE_WITH_ERR;
			IDIBUS_MODULE.LONG_OP.Type   = IDIBUS_LONGOP_NOPE;
			IDIBUS_MODULE.LONG_OP.Switch = 0;
		}
	}
}
//=============================================================================================================================================================================================================
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//=============================================================================================================================================================================================================
void IDIBUS_ModuleCommandHandler(IDIBUS_FARG_TYPE *farg)
{
	// If there is special command we don't care about any error in this place
	if ( (farg->ComFunc != IDIMMES_COM_C_Init) && (farg->ComFunc != IDIMMES_COM_C_ShtDown) && (farg->ComFunc != IDIMMES_COM_C_SetAlarmL) )
	{
		// IF we somehow managed to come to the freeze state, we need to exit from freeze state
		if ( IDIBUS_MODULE.STATUS.STATE.B0S.StState == IDISTATUS_B0S_ST_STATE_StFreeze )
		{
			if ( farg->ComFunc != IDIMMES_COM_C_Resume ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_IN_FREEZE); return; }
		} // If not special command or freeze but long Operation and command not DummyModule
		else if ( IDIBUS_MODULE.Error != IDIER_NOPE ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIBUS_MODULE.Error); return; }
		else if ( IDIBUS_MODULE.LONG_OP.State == IDILONGOP_STATE_IN_PROC )
		{
			if ( farg->ComFunc != IDIMMES_COM_C_CheckModuleLongOp ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_LONG_OP_IN_PROC); return; }
		}
	}

	// There is no prohibited command if this place - just handle it
	switch ( farg->ComFunc )
	{
		case (IDIMMES_COM_C_DummyModule) : {
			if ( farg->InpDataLength != 0 ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else 							  { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIER_NOPE); }
		break; }

		case ( IDIMMES_COM_C_Init ) : {
			if ( farg->InpDataLength > 1 ) 													      { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else if ( (farg->InpDataLength == 1) && (farg->InpData[0] > IDIBUS_GROUP_LAST_NUMBER) ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_PARAM); }
			//Some custom error???!!
			//else if ( 0 /* CTRL_SelectedMode == _CTRL_MODE_MANUAL_ */ )                                     { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIBUS_CUSTDEF_ERCODE_NO_ACCESS); }
			else
			{
				if ( farg->InpDataLength == 1 ) { IDIBUS_MODULE.c_InitAssignGroup = (uint8_t)( farg->InpData[0] + IDIBUS_GROUP_0_ADDR ); }
				IDIBUS_MODULE.LONG_OP.Type = IDIBUS_LONGOP_INIT;
				IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIER_NOPE);
			}
		break; }

		case ( IDIMMES_COM_C_ShtDown ) : {
			if ( farg->InpDataLength != 0 ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			//Some custom error???!!
			//else if ( 0 /* CTRL_SelectedMode == _CTRL_MODE_MANUAL_ */ ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIBUS_CUSTDEF_ERCODE_NO_ACCESS); }
			else
			{
				//IDIBUS_CustomShutdown();
				IDIBUS_MODULE.STATUS.STATE.B0S.StState = IDISTATUS_B0S_ST_STATE_StNoInit;
				IDIBUS_MODULE.Error = IDIERSLV_NO_INIT;
				IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIER_NOPE);
			}
		break; }

		case (IDIMMES_COM_C_Freeze) : {
			if ( farg->InpDataLength != 0 ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else
			{
				IDIBUS_MODULE.FreezeMemState = IDIBUS_MODULE.STATUS.STATE.B0S.StState;
				IDIBUS_MODULE.STATUS.STATE.B0S.StState = IDISTATUS_B0S_ST_STATE_StFreeze;
				IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIER_NOPE);
			}
		break; }

		case (IDIMMES_COM_C_Resume) : {
			if ( farg->InpDataLength != 0 ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else
			{
				IDIBUS_MODULE.STATUS.STATE.B0S.StState = (uint8_t)(IDIBUS_MODULE.FreezeMemState & 0x07U);
				IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIBUS_MODULE.Error);
			}
		break; }

		case (IDIMMES_COM_C_ReadDevFullSN_MS) : {
			if ( farg->InpDataLength != 0 ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else
			{
				uint8_t ResponseLength = IDISN_FULL_LENGTH - IDISN_VARP_AES256_Length + 2;
				uint8_t Response[ResponseLength];
				Response[IDISTATUS_B0S_Pos] = (uint8_t) (
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B0S.StError      << IDISTATUS_B0S_ST_ERROR_Pos)      |
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B0S.StState      << IDISTATUS_B0S_ST_STATE_Pos)      |
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B0S.AesSupported << IDISTATUS_B0S_AES_SUPPORTED_Pos) |
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B0S.AesInstalled << IDISTATUS_B0S_AES_INSTALLED_Pos) |
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B0S.SendAlarmL0  << IDISTATUS_B0S_SEND_ALARM_L0_Pos) |
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B0S.SendAlarmL1  << IDISTATUS_B0S_SEND_ALARM_L1_Pos) |
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B0S.StState      << IDISTATUS_B0S_ST_STATE_Pos) );
				Response[IDISTATUS_B1S_Pos] = (uint8_t) (
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B1S.ModuleType      << IDISTATUS_B1S_MODULE_TYPE_Pos)       |
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B1S.BridgeConnected << IDISTATUS_B1S_BRIDGE_CONNECTED_Pos ) |
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B1S.SelfInit        << IDISTATUS_B1S_SELF_INIT_Pos )        |
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B1S.TimeoutLed      << IDISTATUS_B1S_TIMEOUT_LED_Pos )      |
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B1S.NoMMESTimeout   << IDISTATUS_B1S_NO_MMES_TIMEOUT_Pos )  |
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B1S.CatchAlarmL0    << IDISTATUS_B1S_CATCH_ALARM_L0_Pos )   |
				((uint8_t)IDIBUS_MODULE.STATUS.STATE.B1S.CatchAlarmL1    << IDISTATUS_B1S_CATCH_ALARM_L1_Pos ) );
				for (uint8_t pos=0; pos < IDISN_FIXP_LENGTH; pos++) {Response[IDISTATUS_SN_Pos+pos] = flash_read_byte(IDIBUS_MODULE.STATUS.SNfix,IDISN_FIXP_Pos+pos);}
				for (uint8_t pos=0; pos < IDISN_VARP_LENGTH-IDISN_VARP_AES256_Length; pos++) {Response[IDISTATUS_SN_Pos+IDISN_FIXP_LENGTH+pos] = eeprom_read_byte(&IDIBUS_MODULE.STATUS.SNvar[pos]);}
				IDIBUS_ResponseProtectedWrite(farg, Response, ResponseLength, IDIER_NOPE);
			}
		break; }

		case (IDIMMES_COM_C_CheckModuleLongOp) : {
			if ( farg->InpDataLength != 0 ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else
			{
				uint8_t Response[IDILONGOP_MES_DATA_LENGTH];
				Response[IDILONGOP_STATE_Pos] = IDIBUS_MODULE.LONG_OP.State;
				uint32_t Countdown;
				if ( IDIBUS_MODULE.LONG_OP.State == IDILONGOP_STATE_IN_PROC )
				{
					uint32_t TimeFromStart = System_GetSysTickDifference(IDIBUS_MODULE.LONG_OP.StartTimeInstanceMS);
					if ( IDIBUS_MODULE.LONG_OP.DurationMS > TimeFromStart ) { Countdown = IDIBUS_MODULE.LONG_OP.DurationMS - TimeFromStart; }
					else                                                    { Countdown = 0; }
				}
				else { Countdown = 0; }
				Response[IDILONGOP_REMAIN_TIME_Pos]     = (uint8_t)(Countdown >> 24);
				Response[IDILONGOP_REMAIN_TIME_Pos + 1] = (uint8_t)(Countdown >> 16);
				Response[IDILONGOP_REMAIN_TIME_Pos + 2] = (uint8_t)(Countdown >> 8);
				Response[IDILONGOP_REMAIN_TIME_Pos + 3] = (uint8_t)(Countdown);
				IDIBUS_ResponseProtectedWrite(farg, Response, IDILONGOP_MES_DATA_LENGTH, IDIER_NOPE);
			}
		break; }

		case (IDIMMES_COM_C_SendTimeDate) : {
			if ( farg->InpDataLength != IDIMMES_C_DATETIME_LENGTH ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else
			{
				if  (
				( farg->InpData[IDIMMES_C_DATETIME_TIME_Pos + IDITIME_FORMAT_SECONDS_Pos] > 60U ) ||
				( farg->InpData[IDIMMES_C_DATETIME_TIME_Pos + IDITIME_FORMAT_MINUTES_Pos] > 60U ) ||
				( farg->InpData[IDIMMES_C_DATETIME_TIME_Pos + IDITIME_FORMAT_HOURS_Pos]   > 23U ) ||
				( (int8_t)farg->InpData[IDIMMES_C_DATETIME_TIME_Pos + IDITIME_FORMAT_TIMEZONE_Pos] > IDITIME_FORMAT_TIMEZONE_MAX ) ||
				( (int8_t)farg->InpData[IDIMMES_C_DATETIME_TIME_Pos + IDITIME_FORMAT_TIMEZONE_Pos] < IDITIME_FORMAT_TIMEZONE_MIN ) ||
				( farg->InpData[IDIMMES_C_DATETIME_DATE_Pos + IDIDATE_FORMAT_DAY_Pos] > 31 )      ||
				( farg->InpData[IDIMMES_C_DATETIME_DATE_Pos + IDIDATE_FORMAT_DAY_Pos] == 0 )      ||
				( farg->InpData[IDIMMES_C_DATETIME_DATE_Pos + IDIDATE_FORMAT_MONTH_Pos] > 31 )    ||
				( farg->InpData[IDIMMES_C_DATETIME_DATE_Pos + IDIDATE_FORMAT_MONTH_Pos] == 0 )    ||
				( farg->InpData[IDIMMES_C_DATETIME_DATE_Pos + IDIDATE_FORMAT_CENTURY_Pos] > 99 )  ||
				( farg->InpData[IDIMMES_C_DATETIME_DATE_Pos + IDIDATE_FORMAT_YEAR99_Pos]  > 99 )
				)
				{
					IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_PARAM);
				}
				else { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIER_NOPE); }
			}
		break; }

		// LONG OPERATION FUNCS -------------------------------------------------------------->
		case (IDIMMES_COM_C_WriteSnIPv4IPv6) : {
			if ( farg->InpDataLength != (IDISN_VARP_IPv4_Length + IDISN_VARP_IPv6_Length) ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else
			{
				memcpy(&EEPROM_BUF, farg->InpData, farg->InpDataLength);
				IDIBUS_MODULE.LONG_OP.Type = IDIBUS_LONGOP_VARSN_IP_WRITE;
				IDIBUS_MODULE.LONG_OP.Switch = 0;
				IDIBUS_MODULE.LONG_OP.State = IDILONGOP_STATE_IN_PROC;
				IDIBUS_MODULE.LONG_OP.StartTimeInstanceMS = System_GetTimeInstance();
				IDIBUS_MODULE.LONG_OP.DurationMS = IDIBUS_LONGOP_VARSN_IP_WRITE_DURATION_MS;
				farg->LongOpState = 1;
				IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIER_NOPE);
			}
		break; }

		case (IDIMMES_COM_C_WriteSnVerifyDates) : {
			if ( farg->InpDataLength != (IDIDATE_FORMAT_LENGTH * 2) ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else if (
			(farg->InpData[IDIDATE_FORMAT_DAY_Pos] == 0)||(farg->InpData[IDIDATE_FORMAT_DAY_Pos] > 31) ||
			(farg->InpData[IDIDATE_FORMAT_MONTH_Pos] == 0 )||(farg->InpData[IDIDATE_FORMAT_MONTH_Pos] > 12) ||
			(farg->InpData[IDIDATE_FORMAT_CENTURY_Pos] > 99 ) ||
			(farg->InpData[IDIDATE_FORMAT_YEAR99_Pos] > 99) ||
			(farg->InpData[IDIDATE_FORMAT_DAY_Pos+IDIDATE_FORMAT_LENGTH] == 0)||(farg->InpData[IDIDATE_FORMAT_DAY_Pos+IDIDATE_FORMAT_LENGTH] > 31) ||
			(farg->InpData[IDIDATE_FORMAT_MONTH_Pos+IDIDATE_FORMAT_LENGTH] == 0 )||(farg->InpData[IDIDATE_FORMAT_MONTH_Pos+IDIDATE_FORMAT_LENGTH] > 12) ||
			(farg->InpData[IDIDATE_FORMAT_CENTURY_Pos+IDIDATE_FORMAT_LENGTH] > 99 ) ||
			(farg->InpData[IDIDATE_FORMAT_YEAR99_Pos+IDIDATE_FORMAT_LENGTH] > 99)
			)
			{
				IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_PARAM);
			}
			else {
				//memcpy(&EEPROM_BUF, farg->InpData, (IDIDATE_FORMAT_LENGTH * 2));
				memcpy(&EEPROM_BUF, farg->InpData, farg->InpDataLength);
				IDIBUS_MODULE.LONG_OP.Type = IDIBUS_LONGOP_VARSN_VERIF_EXP_WRITE;
				IDIBUS_MODULE.LONG_OP.Switch = 0;
				IDIBUS_MODULE.LONG_OP.State = IDILONGOP_STATE_IN_PROC;
				IDIBUS_MODULE.LONG_OP.StartTimeInstanceMS = System_GetTimeInstance();
				IDIBUS_MODULE.LONG_OP.DurationMS = IDIBUS_LONGOP_VARSN_VERF_EXP_WRITE_DURATION_MS;
				farg->LongOpState = 1;
				IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIER_NOPE);
			}
		break; }

		case (IDIMMES_COM_C_WriteSnAES256) : {
			if ( farg->InpDataLength != IDISN_VARP_AES256_Length ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else
			{
				//!!!memcpy(&IDIBUS_MODULE.STATUS.SN[IDISN_VARP_AES256_Pos], farg->InpData, farg->InpDataLength);
				memcpy(&EEPROM_BUF, farg->InpData, farg->InpDataLength);
				IDIBUS_MODULE.LONG_OP.Type = IDIBUS_LONGOP_VARSN_AES_WRITE;
				IDIBUS_MODULE.LONG_OP.Switch = 0;
				IDIBUS_MODULE.LONG_OP.State = IDILONGOP_STATE_IN_PROC;
				IDIBUS_MODULE.LONG_OP.StartTimeInstanceMS = System_GetTimeInstance();
				IDIBUS_MODULE.LONG_OP.DurationMS = IDIBUS_LONGOP_VARSN_AES_WRITE_DURATION_MS;
				farg->LongOpState = 1;
				IDIBUS_MODULE.STATUS.STATE.B0S.AesInstalled = 0;
				for ( uint8_t I = 0; I < IDISN_VARP_AES256_Length; I++ )
				{
					if ( /*IDIBUS_MODULE.STATUS.SN[IDISN_VARP_AES256_Pos + I] != 0 */ 0 /* TODO */ ) { IDIBUS_MODULE.STATUS.STATE.B0S.AesInstalled = 1; break; }
				}
				IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIER_NOPE);
			}
		break; }
		case (IDIMMES_COM_C_EnterBootloader) : {
			const uint8_t packageSize = IDISN_FIXP_MODULE_TYPE_Length+IDISN_FIXP_HW_REV_Length+IDISN_FIXP_SERIAL_Length;
			if ( farg->InpDataLength != packageSize) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else
			{
				uint8_t Check = 1;
				for (uint8_t pos=0; pos < packageSize; pos++) {
					if (farg->InpData[pos] != flash_read_byte(IDIBUS_MODULE.STATUS.SNfix,IDISN_FIXP_MODULE_TYPE_Pos+pos))
						Check = 0;		
				}

				if (Check == 1){
					IDIBUS_MODULE.LONG_OP.Type = IDIBUS_LONGOP_INIT;
					eeprom_write_byte(&EEBLOCK.BOOTFLAG, 0xB0);
					IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIER_NOPE);
				} else {
					IDIBUS_ResponseProtectedWrite(farg,NULL,0,IDIERSLV_INVALID_RX_PARAM);
				}
			}
		break; }


		default : { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_UNSUPPORTED_FUNC_NUM); }
	}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void IDIBUS_ChannelBackgroundHandler (void)
{

	// Error Handler ------------------------>
	for ( uint8_t Dev=0; Dev < IDIBUS_MODULE.DevicesCount; Dev++ )
	{
		for ( uint8_t Ch=0; Ch<IDIBUS_MODULE.Devices[Dev].ChannelsCount; Ch++ )
		{
			IDIBUS_CHANNEL *CH = &IDIBUS_MODULE.Devices[Dev].Channels[Ch];
			if ( CH->LONG_OP.State == IDILONGOP_STATE_IN_PROC )
			{
				if ( System_GetSysTickDifference(CH->LONG_OP.StartTimeInstanceMS) > CH->LONG_OP.DurationMS )
				{
					// Long Operation terminate function
					CH->LONG_OP.State  = IDILONGOP_STATE_COMPLETE_WITH_ERR;
					CH->LONG_OP.Type   = IDIBUS_LONGOP_NOPE;
				}
			}
		}
	}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
uint8_t IDIBUS_CnannelStaticFunc(struct IDIBUS_CHANNEL_STR* CH, IDIBUS_FARG_TYPE *farg)
{
	if ( CH->LONG_OP.State == IDILONGOP_STATE_IN_PROC )
	{
		farg->LongOpState = 1;
		if ( farg->ComFunc != IDIMMES_COM_C_CheckChannelLongOp ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERDEV_LONG_OP_IN_PROC); return 1; }
	}

	if ( farg->ComFunc < IDIMMES_COM_START_NUM ) { return 0; }	// If Not channel command

	switch (farg->ComFunc)
	{
		case (IDIMMES_COM_C_Dummy) : {
			if ( farg->InpDataLength != 0 ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else                            { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIER_NOPE); }
		break; }

		case (IDIMMES_COM_C_AssignGroup) : {
			if ( (farg->InpDataLength != 1) || (farg->InpData[0] > IDIBUS_GROUP_LAST_NUMBER) ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else
			{
				CH->BcastAddr = (uint8_t)( farg->InpData[0] + IDIBUS_GROUP_0_ADDR );
				IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIER_NOPE);
			}
		break; }

		case (IDIMMES_COM_C_CheckChannelLongOp) : {
			if ( farg->InpDataLength != 0 ) { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_INVALID_RX_REQUEST_FORMAT); }
			else
			{
				uint8_t Response[IDILONGOP_MES_DATA_LENGTH];
				Response[IDILONGOP_STATE_Pos] = CH->LONG_OP.State;
				uint32_t Countdown;
				if ( CH->LONG_OP.State == IDILONGOP_STATE_IN_PROC )
				{
					uint32_t TimeFromStart = System_GetSysTickDifference( CH->LONG_OP.StartTimeInstanceMS );
					if ( CH->LONG_OP.DurationMS > TimeFromStart ) { Countdown = CH->LONG_OP.DurationMS - TimeFromStart; }
					else                                          { Countdown = 0; }
				}
				else { Countdown = 0; }
				Response[IDILONGOP_REMAIN_TIME_Pos]     = (uint8_t)(Countdown >> 24);
				Response[IDILONGOP_REMAIN_TIME_Pos + 1] = (uint8_t)(Countdown >> 16);
				Response[IDILONGOP_REMAIN_TIME_Pos + 2] = (uint8_t)(Countdown >> 8);
				Response[IDILONGOP_REMAIN_TIME_Pos + 3] = (uint8_t)(Countdown);
				IDIBUS_ResponseProtectedWrite(farg, Response, IDILONGOP_MES_DATA_LENGTH, IDIER_NOPE);
			}
		break; }

		default : { IDIBUS_ResponseProtectedWrite(farg, NULL, 0, IDIERSLV_UNSUPPORTED_FUNC_NUM); }
	}
	return 1;
}
//=============================================================================================================================================================================================================
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//=============================================================================================================================================================================================================
void IDIBUS_ResponseProtectedWrite(IDIBUS_FARG_TYPE *farg, uint8_t *Data, uint16_t DataLength, uint8_t ErrorCode)
{
	if (farg->OutData != NULL)
	{
		if ( ErrorCode != IDIER_NOPE ) { IDIBUS_MODULE.STATUS.STATE.B0S.StError = 1;  farg->ErrorState = 1; }
		else 							{ IDIBUS_MODULE.STATUS.STATE.B0S.StError = 0; }
		farg->OutData[farg->ErrorPos] = ErrorCode;
		farg->ErrorPos = (uint16_t)(farg->ErrorPos + 1);
		farg->OutDataLength = (uint16_t)(farg->OutDataLength + 1);

		if ( (DataLength != 0) && (Data != NULL) )
		{
			memcpy(&farg->OutData[farg->OutDataPos], Data, DataLength);
			farg->OutDataPos = (uint16_t)( farg->OutDataPos + DataLength );
			farg->OutDataLength = (uint16_t)(farg->OutDataLength + DataLength);
		}
	}
}
//=============================================================================================================================================================================================================
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//=============================================================================================================================================================================================================
void IDIBUS_ServiceFunc (uint8_t *InpData, uint16_t InpDataLength, uint8_t *OutData, uint16_t *OutDataLength)
{

}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//#############################################################################################################################################################################################################
