/**
  ******************************************************************************
  * @file           : system_implementation.c
  * @brief          : Simple example for showing overall system implementation when using iQ.Controller
  ******************************************************************************
  * @attention
  *
  * Copyright (c) Kuenzler Technologies GbR
  * All rights reserved.
  *
  *
  ******************************************************************************
*/

/*==============================================================================*/
/* Includes                                                                  	*/
/*==============================================================================*/
#include "system_implementation.h"
#include "rdm_implementation.h"
#include "dmx_implementation.h"
#include "variables.h"
#include "defines.h"

#include "bootloader.h"
#include "output.h"

#include "libIqMeshSpiInterface.h"
#include "libRdmInterface.h"
#include "button.h"

/*==============================================================================*/
/* Defines & Macros                                                           	*/
/*==============================================================================*/

#define BUTTONTURNONTIMEMS	700
#define BUTTONTURNOFFTIMEMS	2000
#define BUTTONACTIVESTATE	false

/*==============================================================================*/
/* Private functions                                                          	*/
/*==============================================================================*/

static void InitIqMesh(void);
static void ReceiveRdm(input_source_t source,const uint8_t* rdmData,uint16_t rdmLength);
static void ReceiveDmx(input_source_t source,uint8_t iqDmxMode, const uint8_t* dmxData,uint16_t dmxLength);
static void CountTimer(uint32_t tickMs);
static void SerialNumberCallback(void);
static void SystemStateCallback(void);
static void IqMeshDmxReceivedCallback(uint8_t personality, const uint8_t *buf,uint16_t length);
static void IqMeshRdmReceivedCallback(const uint8_t *buf, uint16_t length);
static void IqMeshDfuFlagReceivedCallback(iqmesh_dfu_flag_t flag);
static void IqMeshDfuDataReceivedCallback(uint16_t packetNr, const uint8_t *buf,uint16_t length);
static void RdmAnswerCallback(const uint8_t *msg, uint16_t length,bool sentBreak, uint8_t id);
static void ButtonLongPress1Callback(void);
static void ButtonLongPress2Callback(void);
static void ButtonDoubleClickCallback(void);

/*==============================================================================*/
/* Private variables                                                          	*/
/*==============================================================================*/

static bool deviceHourTimeSet;
static uint32_t deviceHourLastTime;

/*==============================================================================*/
/* Function definitions                                                     	*/
/*==============================================================================*/

void InitSystem()
{
	/* This example should give you an understanding how the fixture have to behave using the iQ.Controller -  此示例应该让您了解灯具如何使用 iQ.Controller 进行操作
	 * Also it shows how to use the prepared Libraries - 它还展示了如何使用准备好的库*/
	/* Initialize Variables, load flash,.. - 初始化变量，加载闪存*/
	InitVariables();
	/* Initialize RDM library and example implementation - 初始化RDM库和示例实现*/
	InitRdmImp(&RdmAnswerCallback);
	/* Initialize dmx example implementation - 初始化 dmx 示例实现*/
	InitDmxImp();
	/* Initialize iQ.Controller SPI Library - 初始化 iQ.Controller SPI 库*/
	InitIqMesh();
	/* Initialize output example implementation in order to control the LED - 初始化输出示例实现以控制 LED*/
	InitOutput();

	button_callbacks_t btnCallbacks;
	memset(&btnCallbacks,0,sizeof(button_callbacks_t));
	btnCallbacks.ButtonLongPress1 = &ButtonLongPress1Callback;
	btnCallbacks.ButtonLongPress2= &ButtonLongPress2Callback;
	btnCallbacks.ButtonDoubleClick = &ButtonDoubleClickCallback;
	InitButton(btnCallbacks, BUTTONTURNONTIMEMS, BUTTONTURNOFFTIMEMS - BUTTONTURNONTIMEMS, BUTTONACTIVESTATE);

	/* Register System Callbacks - 注册系统回调*/
	register_notify_systemState(&SystemStateCallback);
	register_notify_serial(&SerialNumberCallback);
}

void SystemTask(uint32_t tickMs)
{
	ButtonTask();

	switch(*get_systemState())
	{
	case SYSTEM_STATE_NORMAL:
		CountTimer(tickMs);
	case SYSTEM_STATE_SLEEP:
		/* Fall-through	*/
	case SYSTEM_STATE_WAKEUP:
		/* Do some tasks - 做一些任务*/
		/* Returns true if there is nothing todo - 如果没有任何待办事项，则返回 true*/
		if(iqMesh_task(tickMs))
		{
			VariablesTask();
			RdmTask(tickMs);
			DmxImpTask(tickMs);
			OutputTask(tickMs);
		}
		if(*get_systemState() == SYSTEM_STATE_WAKEUP && !HardwareSystemGpioReadMainWakeUpPin())
		{
			// Go Back Sleeping
			set_systemState(SYSTEM_STATE_OFF);
		}
		break;
	case SYSTEM_STATE_TURN_OFF:
		if(!OutputTask(tickMs))
		{
			set_systemState(SYSTEM_STATE_OFF);
		}
		break;
	case SYSTEM_STATE_OFF:
		// Enter Sleep Mode
		//HardwareSystemEnterSleep();
	break;
	}


}

void SystemIqMeshSpiTxRxComplete(uint8_t* receivedDataBuffer, uint16_t receivedDataLength)
{
	iqMesh_extSpiEvent(SPI_EVENT_COMPLETION, receivedDataBuffer, receivedDataLength);
}

void SystemIqMeshIrqPinIrq(bool set)
{
	if(set)
	{
		iqMesh_extIrqInterupt(SPIEXT_IRQ_EDGE_RISING);
	} else
	{
		iqMesh_extIrqInterupt(SPIEXT_IRQ_EDGE_FALLING);
	}
}

void SystemIqMeshMainWakeUpPinIrq(bool set)
{
	if(set)
	{
		if(*get_systemState() == SYSTEM_STATE_OFF)
		{
			set_systemState(SYSTEM_STATE_WAKEUP);
		}
	}
}

void SystemButtonPinIrq(bool set)
{
	ButtonInteruptIrq(set);
}

void SystemButtonWaitTimeElapsed()
{
	ButtonWaitTimeElapsed();
}

/*==============================================================================*/
/* Private Functions			                                               	*/
/*==============================================================================*/

static void InitIqMesh()
{
	/* Register callbacks needed for iQ.Controller SPI Library - 注册 iQ.Controller SPI 库所需的回调 */
	iqmesh_callbacks_t callbacks;
	callbacks.DfuDataReceived = &IqMeshDfuDataReceivedCallback;
	callbacks.DfuFlagReceived = &IqMeshDfuFlagReceivedCallback;
	callbacks.DmxReceived = &IqMeshDmxReceivedCallback;
	callbacks.RdmReceived = &IqMeshRdmReceivedCallback;
	/* Initialize iQ.Controller SPI Library - 初始化 iQ.Controller SPI 库*/
	iqMesh_init(get_rdmid().array, 100, true, callbacks);
}

static void ReceiveDmx(input_source_t source,uint8_t iqDmxMode, const uint8_t* dmxData,uint16_t dmxLength)
{
	/* Receive Dmx function. Handle DMX only when input Source is correct - 接收Dmx功能。仅当输入源正确时才处理 DMX*/
	/* In this example only iQ.Mesh is completly implemented. DMX512 physical input is not implemented - 在此示例中，仅完整实现了 iQ.Mesh。 DMX512物理输入未实现*/
	if(*get_inputSource() == source)
	{
		//HandleDMX
		SetDmx(iqDmxMode,dmxData,dmxLength);

		//Write DMX to iQMesh
		iqMesh_writeDmx(dmxData, dmxLength);
	}


}

static void ReceiveRdm(input_source_t source,const uint8_t* rdmData,uint16_t rdmLength)
{
	/* Always handle and answer RDM from all sources - 始终处理并回答所有来源的 RDM*/
	RdmSet(rdmData,rdmLength, (uint8_t)source);
}

static void CountTimer(uint32_t tickMs)
{
	if(!deviceHourTimeSet)
	{
		deviceHourLastTime = tickMs;
		deviceHourTimeSet = true;
	}
	else if(tickMs >= deviceHourLastTime + MINUTES_MS)
	{
		rdm_counter_t counter = *get_counter();
		counter.deviceCounterMinutes++;
		set_counter(counter);
		deviceHourLastTime = tickMs;
	}
	else if(tickMs < deviceHourLastTime)
	{
		deviceHourLastTime = tickMs;
	}
}

static void CountPowerCycle(void)
{
	rdm_counter_t counter = *get_counter();
			counter.devicePowercycle++;
			set_counter(counter);
}

/*==============================================================================*/
/* Callback Functions			                                               	*/
/*==============================================================================*/

static void SystemStateCallback()
{
	switch(*get_systemState())
	{
		case SYSTEM_STATE_NORMAL:
			CountPowerCycle();
			OutputEnable(true);
			HarwareIqMeshGpioSetFixtureIsOnPin(true);
			HardwareSystemGpioSetSignalLedPin(true);
		break;
		case SYSTEM_STATE_SLEEP:
			OutputEnable(false);
			/* iQController stays on in order to wake fixture out of sleep mode - iQController 保持打开状态以便将灯具从睡眠模式中唤醒。*/
		break;
		case SYSTEM_STATE_WAKEUP:

		break;
		case SYSTEM_STATE_TURN_OFF:
			OutputEnable(false);
		break;
		case SYSTEM_STATE_OFF:
			/* State off. Turn everything off, relay switch is off - 关闭状态。关闭一切，继电器开关关闭 */
			HarwareIqMeshGpioSetFixtureIsOnPin(false);
			HardwareSystemGpioSetSignalLedPin(false);
		break;
	}
}

static void SerialNumberCallback()
{
	/* Serialnumber changed. Recalculate RDMID and update all references - 序列号已更改。重新计算 RDMID 并更新所有引用 */
	rdmid_t id = get_rdmid();
	iqMesh_setRdmId(id.array);
	rdm_setRdmId(id.array);
}

/* Implementation from RDM Library. Provide the answer to the received message. 来自 RDM 库的实现。提供收到消息的答案。*/
static void RdmAnswerCallback(const uint8_t *msg, uint16_t length,bool sentBreak, uint8_t id)
{
	if(id == INPUT_SOURCE_IQ_MESH)
	{
		iqMesh_writeRdm(msg, length);
	}
	(void) sentBreak;
}

static void ButtonLongPress1Callback(void)
{
	if(*get_systemState() == SYSTEM_STATE_OFF)
	{
		/* If system is in state off and relay is switched on start system - 如果系统处于关闭状态并且继电器打开则启动系统*/
		set_systemState(SYSTEM_STATE_NORMAL);
	}
}
static void ButtonLongPress2Callback(void)
{
	if(*get_systemState() == SYSTEM_STATE_NORMAL && get_features()->antitheftMode == RDMIQANTITHEFT_OFF)
	{
		/* If system is in state off and relay is switched on start system - 如果系统处于关闭状态并且继电器打开则启动系统*/
		set_systemState(SYSTEM_STATE_TURN_OFF);
	}
}
static void ButtonDoubleClickCallback(void)
{
	if(get_features()->antitheftMode == RDMIQANTITHEFT_OFF)
	{
		iqMesh_unlinkIqData();
	}
}

static void IqMeshDmxReceivedCallback(uint8_t personality, const uint8_t *buf,uint16_t length)
{
	/* Handle DMX Data received from iQ.Controller - 处理从 iQ.Controller 接收到的 DMX 数据 */
	ReceiveDmx(INPUT_SOURCE_IQ_MESH, personality, buf, length);
}
static void IqMeshRdmReceivedCallback(const uint8_t *buf, uint16_t length)
{
	/* Handle RDM Data received from iQ.Controller - 处理从 iQ.Controller 接收到的 RDM 数据 */
	ReceiveRdm(INPUT_SOURCE_IQ_MESH, buf, length);
}

static void IqMeshDfuFlagReceivedCallback(iqmesh_dfu_flag_t flag)
{
	/* Handle DFU (Device Firmware Update) flags received from iQ.Controller - 处理从 iQ.Controller 接收到的 DFU（设备固件更新）标志 */
	if (flag == IQMESH_DFUFLAG_STOP)
	{
		/* In this example DFU data is not handled directly. The bootloader is started which handles DFU - 在此示例中，不直接处理 DFU 数据。启动处理 DFU 的引导加载程序。 */
		/* Because we are here means something did go wrong or there is no bootloader available - 因为我们在这里意味着出了问题或者没有可用的引导加载程序 */
		/* So answer with DFU_ERROR_NOT_IMPLEMENTED	- 所以回答 DFU 错误未实现	 */
		iqMesh_writeDfu(DFU_ERROR_NOT_IMPLEMENTED);
	}
	if (flag == IQMESH_DFUFLAG_START)
	{
		#ifdef RELEASEBL
			/* Jump to the bootloader - 跳转到引导加载程序*/
			JumpToBootloader();
		#endif

		/* Bootloader not available - 引导加载程序不可用*/
		iqMesh_writeDfu(DFU_ERROR_NOT_IMPLEMENTED);
	}
}
static void IqMeshDfuDataReceivedCallback(uint16_t packetNr, const uint8_t *buf,uint16_t length)
{
	/* In this example DFU data is not handled directly. The bootloader is started which handles DFU - 在此示例中，不直接处理 DFU 数据。启动处理 DFU 的引导加载程序。 */
	(void) packetNr;
	(void) buf;
	(void) length;
}















