#include <appTimer.h>
#include <zdo.h>
#include <app.h>
#include <usart.h>
#include <taskManager.h>
#include <i2cPacket.h>
#include <bspLeds.h>
#include <stdlib.h>
#include <string.h>

static HAL_AppTimer_t timer;
static HAL_AppTimer_t receiveTimerLed;
static HAL_AppTimer_t transmitTimerLed;
static HAL_AppTimer_t transmitTimer;
static void receiveTimerLedFired(void);
static void transmitTimerLedFired(void);
static void transmitTimerFired(void);

static SimpleDescriptor_t simpleDescriptor;
static APS_RegisterEndpointReq_t endPoint;
static void initEndpoint(void);
void APS_DataInd(APS_DataInd_t *indData);
static uint8_t deviceType;
static void ZDO_StartNetworkConf(ZDO_StartNetworkConf_t *confirmInfo);
static ZDO_StartNetworkReq_t networkParams;

BEGIN_PACK
typedef struct _AppMessage_t{
	uint8_t header[APS_ASDU_OFFSET];
	uint8_t data[34];
	uint8_t footer[APS_AFFIX_LENGTH - APS_ASDU_OFFSET];
}PACK AppMessage_t;
END_PACK

void ZDO_StartNetworkConf(ZDO_StartNetworkConf_t *confirmInfo){
	if(ZDO_SUCCESS_STATUS == confirmInfo->status){
		CS_ReadParameter(CS_DEVICE_TYPE_ID,&deviceType);
		if(deviceType==DEV_TYPE_COORDINATOR){
			appWriteDataToUart((uint8_t*)"Koordinator\r\n",sizeof("Koordinator\r\n")-1);
		}
		BSP_OnLed(LED_ORANGE);
		}else{
		appWriteDataToUart((uint8_t*)"Fehler\n\r",sizeof("Fehler\n\r")-1);
	}
	SYS_PostTask(APL_TASK_ID);
}
static AppMessage_t transmitData;
APS_DataReq_t dataReq;
static void APS_DataConf(APS_DataConf_t *confInfo);
static void initTransmitData(void);



static uint16_t sht21TempDataBig;
static uint16_t sht21HumDataBig;


uint8_t sht21Temp_txt[8];
uint8_t sht21Hum_txt[8];
uint8_t sht21TempHum_txt[17];
static AppState_t appstate=APP_INIT_STATE;


struct
{
	uint8_t command[1];
	uint8_t temperatureArray[3];
	uint8_t humidityArray[3];
}sht;

static float humidity;
static float temperature;
void tempConvert(uint8_t * sensorData){
	sht21TempDataBig = (uint16_t)sensorData[0];
	sht21TempDataBig <<= 8;
	sht21TempDataBig |= (uint16_t)sensorData[1];
}

void humConvert(uint8_t * sensorData){
	sht21HumDataBig = (uint16_t)sensorData[0];
	sht21HumDataBig <<= 8;
	sht21HumDataBig |= (uint16_t)sensorData[1];
}
static void writeCommandi2C(uint8_t command);
static void read_done(bool result);
static void write_done(bool result);
static void readI2C(uint8_t * data);

/*static const char* st = CS_UID;
static int length, j;
int i, pot, csuid, res;
char csuid_array;

static void CS_UID_convert(){
	length = strlen(st);
	csuid_array=0;
	for (j=0; j < length; j++){
		if(j%2 != 0){
			
		}
}
*/
static void initEndpoint(void){
	simpleDescriptor.AppDeviceId=1;
	simpleDescriptor.AppProfileId=1;
	simpleDescriptor.endpoint=1;
	simpleDescriptor.AppDeviceVersion=1;
	endPoint.simpleDescriptor=&simpleDescriptor;
	endPoint.APS_DataInd=APS_DataInd;
	APS_RegisterEndpointReq(&endPoint);
}


static HAL_I2cDescriptor_t i2cdescriptor = {
	.tty = TWI_CHANNEL_0,
	.clockRate = I2C_CLOCK_RATE_62,
	.id=SHT_DEVICE_ADDRESS,
	.lengthAddr=HAL_NO_INTERNAL_ADDRESS
	
};
void APS_DataInd(APS_DataInd_t *indData){
	BSP_OnLed(LED_RED);
	HAL_StartAppTimer(&receiveTimerLed);
	appWriteDataToUart(indData->asdu,indData->asduLength);
	appWriteDataToUart((uint8_t*)"\r\n",2);
}

static void readI2C(uint8_t* data){
	i2cdescriptor.data=data;
	i2cdescriptor.f=read_done;
	i2cdescriptor.length=3;
	if (-1 == HAL_OpenI2cPacket(&i2cdescriptor))
	appWriteDataToUart((uint8_t*)"HAL_OpenI2cPacket fail at read\r\n",sizeof(
	"HAL_OpenI2cPacket fail at read\r\n")-1);
	if (-1 == HAL_ReadI2cPacket(&i2cdescriptor))
	appWriteDataToUart((uint8_t*)"HAL_ReadI2cPacket fail\r\n",sizeof(
	"HAL_ReadI2cPacket fail\r\n")-1);
	
	
}

static void read_done(bool result){
	HAL_CloseI2cPacket(&i2cdescriptor);
	if (result == false){
		appWriteDataToUart((uint8_t*)"write false\r\n",sizeof("write false\r\n")-1);
		appstate=APP_NOTHINGSTATE;
		}else{
		SYS_PostTask(APL_TASK_ID);
	}
}
static void write_done(bool result){
	if (result==false){
		appWriteDataToUart((uint8_t*)"write false\r\n",sizeof("write false\r\n")-1);
	}
	
	HAL_CloseI2cPacket(&i2cdescriptor);
	SYS_PostTask(APL_TASK_ID);
	
}
static void calcTemp(void) {
	
	//-- calculate temperature [°C] --
	temperature= -46.85 + 175.72/65536 *(float)sht21TempDataBig; //T= -46.85 + 175.72 * ST/2^16
	
	dtostrf(temperature,6,2,(char*)sht21Temp_txt);
	
	
}

static void calcHum(void){
	
	//-- calculate humidity [%RH] --
	humidity= -6.0+ 125.0/65536 *(float)sht21HumDataBig;
	dtostrf(humidity,6,2,(char*)sht21Hum_txt);
	
}

static void combineArrays(){
	sht21TempHum_txt[0]  = '1';
	sht21TempHum_txt[1]  =' ';
	for (i = 2; i < 8; i++)
	{
		sht21TempHum_txt[i]  =sht21Temp_txt[i] ;
		sht21TempHum_txt[i+10]=sht21Hum_txt[i];
	}
	
	
	sht21TempHum_txt[9]=' ';
	sht21TempHum_txt[10]='2';
	sht21TempHum_txt[11]=' ';

}

static void timer_fired(void) {
	appstate=APP_COMMAND_TEMP_STATE;
	SYS_PostTask(APL_TASK_ID);
}

static void init_timer(void) {
	timer.interval = 3000;
	timer.mode = TIMER_REPEAT_MODE;
	timer.callback = timer_fired;

	
	transmitTimerLed.interval=500;
	transmitTimerLed.mode=TIMER_ONE_SHOT_MODE;
	transmitTimerLed.callback=transmitTimerLedFired;
	
	receiveTimerLed.interval=500;
	receiveTimerLed.mode=TIMER_ONE_SHOT_MODE;
	receiveTimerLed.callback=receiveTimerLedFired;

}

static void transmitTimerLedFired(void){
	BSP_OffLed(LED_YELLOW);
}

static void receiveTimerLedFired(void){
	BSP_OffLed(LED_RED);
}


static void initTransmitData(void){
	dataReq.profileId=1;
	dataReq.dstAddrMode=APS_SHORT_ADDRESS;
	dataReq.dstAddress.shortAddress=CPU_TO_LE16(0);
	dataReq.dstEndpoint=1;
	dataReq.asdu=transmitData.data;
	dataReq.asduLength=sizeof(transmitData.data);
	dataReq.srcEndpoint=1;
	dataReq.APS_DataConf=APS_DataConf;
}

static void APS_DataConf(APS_DataConf_t *confInfo){
	if(confInfo->status==APS_SUCCESS_STATUS){
		BSP_OnLed(LED_YELLOW);
		HAL_StartAppTimer(&transmitTimerLed);
		appstate=APP_NOTHINGSTATE;
		SYS_PostTask(APL_TASK_ID);
	}
}



static void	writeCommandi2C(uint8_t command){
	sht.command[0]=command;
	i2cdescriptor.data=(uint8_t*)(&sht.command);
	i2cdescriptor.f=write_done;
	i2cdescriptor.length=1;
	if(-1 == HAL_OpenI2cPacket(&i2cdescriptor))
	appWriteDataToUart((uint8_t*)"HAL_OpenI2cPacket fail at write\r\n", sizeof(
	"HAL_OpenI2cPacket fail at write\r\n")-1);
	if (-1 == HAL_WriteI2cPacket(&i2cdescriptor))
	appWriteDataToUart((uint8_t*)"HAL_ReadI2cPacket fail\r\n",sizeof(
	"HAL_ReadI2cPacket fail\r\n")-1);

	
}

void APS_DataInd(APS_DataInd_t *indData);

void APL_TaskHandler(void) {
	
	switch (appstate) {
		
		case APP_INIT_STATE:
		
			appInitUARTManager();
			init_timer();
			BSP_OpenLeds();
			
			appstate=APP_START_NETWORK_STATE;
			SYS_PostTask(APL_TASK_ID);
			break;
			
		case APP_START_NETWORK_STATE:
		
			networkParams.ZDO_StartNetworkConf=ZDO_StartNetworkConf;
			ZDO_StartNetworkReq(&networkParams);
			appstate=APP_INIT_ENDPOINT_STATE;
			break;
		
		case APP_INIT_ENDPOINT_STATE:
		
			initEndpoint();
		
		//	#if CS_DEVICE_TYPE==DEV_TYPE_COORDINATOR
		//	appstate=APP_NOTHINGSTATE;
		
		//	#else
			appstate=APP_INIT_TRANSMITDATA_STATE;
		//	#endif
			SYS_PostTask(APL_TASK_ID);
			break;
		
		case APP_INIT_TRANSMITDATA_STATE:
			CS_UID_convert();

			initTransmitData();
			appstate=APP_COMMAND_TEMP_STATE;
			HAL_StartAppTimer(&timer);
			SYS_PostTask(APL_TASK_ID);
			break;
		
		
		
		case APP_COMMAND_TEMP_STATE:
		
			writeCommandi2C(SH_TEMPERATURE_COMMAND);
			appstate=APP_WRITE_TEMP_STATE;
			break;
		
		case APP_WRITE_TEMP_STATE:
		
			readI2C((uint8_t *)(&sht.temperatureArray));
			appstate = APP_COMMAND_HUM_STATE;
			break;
		
		case APP_COMMAND_HUM_STATE:
		
			writeCommandi2C(SH_HUMIDITY_COMMAND);
			appstate=APP_WRITE_HUM_STATE;
		
			break;
		
		case APP_WRITE_HUM_STATE:
		
			readI2C((uint8_t *)(&sht.humidityArray));
			appstate=APP_OUTPUT_STATE;
			break;
		
		case APP_OUTPUT_STATE:
			tempConvert((uint8_t *)(&sht.temperatureArray));
			humConvert((uint8_t *)(&sht.humidityArray));
			calcHum();
			calcTemp();
			combineArrays();
			strcpy((char*)transmitData.data,(char*)sht21TempHum_txt);
			APS_DataReq(&dataReq);
			case APP_NOTHINGSTATE:
			break;
		
	}
	
}

int main(void)
{
	
	SYS_SysInit();
	
	for(;;)
	{
		SYS_RunTask();
	}
}

void ZDO_MgmtNwkUpdateNotf(ZDO_MgmtNwkUpdateNotf_t *nwkP){nwkP=nwkP;}
void ZDO_WakeUpInd(void){}

#ifdef _BINDING_
void ZDO_BindIndication(ZDO_BindInd_t *bindI){(void)bindI;}
void ZDO_UnbindIndication(ZDO_UnbindInd_t *unbindI){(void)unbindI;}
#endif //_BINDING_

