/*
 * megatec.c
 *
 *  Created on: 22.05.2017
 *      Author: balbekova
 */
#include "FreeRTOS.h"
#include "task.h"
#include "usart.h"
#include "megatec.h"
#include "log.h"
#include "snmp_api.h"
#ifdef PRINTF_STDLIB
#include <stdio.h>
#endif
#ifdef PRINTF_CUSTOM
#include "tinystdio.h"
#endif

#include <string.h>
#include <math.h>



#define UPS_PDU_MAX_LEN 50

float TimeParamFloat = 0;
uint16_t TimeParam = 0;
uint16_t TimeParam2 = 0;
bool megatec_send = true;
UPS_value_t UPS;

enum {
	NORMAL = 0x00,
	VER_ERROR = 0x01,
	CHKSUM_ERROR = 0x02,
	LCHKSUM_ERROR = 0x03,
	CID2_INVALID = 0x04,
	CMD_FMT_ERROR = 0x05,
	INVALID_DATA = 0x06,
};

static struct {
	uint8_t data[UPS_PDU_MAX_LEN];
	uint16_t len;
} ups_pdu;


const char* MegaTecCMD[] =
{
		"Q1\r",
		"T\r",
		"TL\r",
		"T",
		"Q\r",
		"S",
		"R",
		"C\r",
		"CT\r",
		"I\r",
		"F\r",
		"Q2\r"
};

extern bool flUpdateLog;


void init_UPS_value(void)
{
	UPS.Freq_in = 0;
	UPS.VAC_in = 0;
	UPS.VAC_out = 0;
	UPS.Temp = 0;
	UPS.Load = 0;
	UPS.SOC = 0;
	UPS.work_time = 0;
	UPS.Status = 0;
	UPS.Alarm = 0;
	UPS.cnt_err_ups = 0;
	UPS.Flag_Present = false;
	UPS.Present = false;

	memset(UPS.model, 0, 11);
	memset(UPS.vertion, 0, 11);
}

void send_MegaTec_cmd(cmdMegaTecEnums_t command)
{
	if(command == ups_test_time){
		uint8_t req[10];

		memset(req, 0, 10);
		sprintf(req, "%s%d\r", MegaTecCMD[command], TimeParam);
		ups_send_block(req, strlen(req));
	}
	else if(command == ups_shutdown){
		uint8_t req[10];

		memset(req, 0, 10);
		if(TimeParamFloat >= 1 && TimeParamFloat < 10)
		{
			sprintf(req, "%s0%f\r", MegaTecCMD[command], TimeParamFloat);
		}
		else if(TimeParamFloat < 1){
			sprintf(req, "%s.%f\r", MegaTecCMD[command], 10*TimeParamFloat);
		}
		else{
			sprintf(req, "%s%f\r", MegaTecCMD[command], TimeParamFloat);
		}
		ups_send_block(req, strlen(req));
	}
	else if(command == ups_shutdown_restore){
		uint8_t req[10];

		memset(req, 0, 10);
		sprintf(req, "%s.%d%s%d\r", MegaTecCMD[command-1], TimeParam, MegaTecCMD[command], TimeParam2);
		ups_send_block(req, strlen(req));
	}
	else{
        // TODO Согласовать изменения
		//ups_send_block(MegaTecCMD[command], strlen(MegaTecCMD[command]));
        ups_send_block((void*)MegaTecCMD[command], strlen(MegaTecCMD[command]));
	}
}

bool ups_megatec_rx_pdu(void)
{
	int c = 0;

	ups_pdu.len = 0;

	while ((ups_pdu.len < UPS_PDU_MAX_LEN) && (c != 0x0d)) {
		c = ups_getchar(500);//portMAX_DELAY
		if(c < 0)
		{
			ups_pdu.len = 0;
			break;
		}
		ups_pdu.data[ups_pdu.len++] = c;
	}

	if (ups_pdu.len == 0)
		return false;

	return true;
}

void ups_status_response(char *data)
{
	uint8_t i;
	char *endValue;
	char value[10];
	uint8_t len = 0;
	if(data[0] != '(')
		return;

	UPS.Present = true;
	UPS.Flag_Present = true;
	UPS.cnt_err_ups = 0;

	if(flUpdateLog){
		flUpdateLog = false;
		log_add(data);
	}

	data++;

	memset(value, 0, 10);
	endValue = strpbrk(data," ");
	len = endValue - data;
	strncpy(value, data, len);
	data += (len + 1);
	UPS.VAC_in = atof(value);

	//TODO
	memset(value, 0, 10);
	endValue = strpbrk(data," ");
	len = endValue - data;
	strncpy(value, data, len);
	data += (len + 1);

	memset(value, 0, 10);
	endValue = strpbrk(data," ");
	len = endValue - data;
	strncpy(value, data, len);
	data += (len + 1);
	UPS.VAC_out = atof(value);

	memset(value, 0, 10);
	endValue = strpbrk(data," ");
	len = endValue - data;
	strncpy(value, data, len);
	data += (len + 1);
	UPS.Load = atoi(value);

	memset(value, 0, 10);
	endValue = strpbrk(data," ");
	len = endValue - data;
	strncpy(value, data, len);
	data += (len + 1);
	UPS.Freq_in = atof(value);

	//TODO
	memset(value, 0, 10);
	endValue = strpbrk(data," ");
	len = endValue - data;
	strncpy(value, data, len);
	data += (len + 1);
	UPS.SOC = 100*((atof(value)) - 1.6)/0.7;

	memset(value, 0, 10);
	endValue = strpbrk(data," ");
	len = endValue - data;
	strncpy(value, data, len);
	data += (len + 1);
	UPS.Temp = atof(value);

	memset(value, 0, 10);
	endValue = strpbrk(data,"\r");
	len = endValue - data;
	strncpy(value, data, len);
	uint8_t stat = 0;
	for(i = 0; i < len; i ++)
	{
		stat |= (value[i] - 0x30) << (7-i);
	}
	UPS.Status = stat;
}

void ups_info_response(char *data)
{
	uint8_t i = 0;
	char *endValue;
	uint8_t len = 0;
	if(data[0] != '#')
		return;

	UPS.Present = true;
	UPS.Flag_Present = true;
	UPS.cnt_err_ups = 0;

	data++;

	data += 16;

	while(data[0] == ' '){
		data ++;
		i ++;
	}
	if(i < 11){
		endValue = strpbrk(data," ");
		len = endValue - data;
		if(UPS.model[0] == 0){
			strncpy(UPS.model, data, len);
			SNMP_SetObjDescr();
		}
		else{
			strncpy(UPS.model, data, len);
		}

		data += (len + 1);
	}
	else
	{
		if(UPS.model[0] == 0){
			strcpy(UPS.model, "RTMP II");
			SNMP_SetObjDescr();
		}
		else{
			strcpy(UPS.model, "RTMP II");
		}
	}

	endValue = strpbrk(data,"\r");
	len = endValue - data;
	strncpy(UPS.vertion, data, len);

}

void ups_remain_time_response(char *data)
{
	char value[10];
	if(data[0] != '(')
		return;

	UPS.Present = true;
	UPS.Flag_Present = true;
	UPS.cnt_err_ups = 0;

	data++;

	memset(value, 0, 10);
	strcpy(value, data);
	UPS.work_time = atof(value);
}

void ups_megatec_process_pdu(cmdMegaTecEnums_t command)
{
	switch(command)
	{
	case ups_status_req:
		ups_status_response(ups_pdu.data);
		break;
	case ups_info:
		ups_info_response(ups_pdu.data);
		break;
	case ups_rating_info:

		break;
	case ups_remain_time_reg:
		ups_remain_time_response(ups_pdu.data);
		break;
	default:
		break;
	}
}

int ups_metac_service_pdu(cmdMegaTecEnums_t command)
{
	while(!megatec_send)
	{
		vTaskDelay(50);
	}
	megatec_send = false;
	send_MegaTec_cmd(command);
	if (ups_megatec_rx_pdu())
	{
		megatec_send = true;
		if(strncmp(ups_pdu.data, "ACK", 3) == 0)
			return 1;
		else if(strncmp(ups_pdu.data, "NCK", 3) == 0)
			return 0;

	}
	return -1;
}

// TODO Согласовать изменения
//void request_task(void)
void request_task(void* params)
{

		for(;;)
		{
			if(UPS.Present == true){
				if(UPS.Flag_Present == false)
				{
					if(UPS.cnt_err_ups != 2)
						UPS.cnt_err_ups++;
					else{
						UPS.Freq_in = 0;
						UPS.VAC_in = 0;
						UPS.VAC_out = 0;
						UPS.Temp = 0;
						UPS.Load = 0;
						UPS.SOC = 0;
						UPS.work_time = 0;
						UPS.Status = 0;
						UPS.Alarm = 0;
						UPS.Present = false;

						//memset(UPS.model, 0, 11);
						memset(UPS.vertion, 0, 11);
					}
				}
			}
			if(megatec_send){
				megatec_send= false;
				UPS.Flag_Present = false;
				send_MegaTec_cmd(ups_status_req);
				if (ups_megatec_rx_pdu())
					ups_megatec_process_pdu(ups_status_req);

				megatec_send=true;
			}
			if(megatec_send){
				memset(ups_pdu.data, 0, UPS_PDU_MAX_LEN);
				megatec_send= false;
				UPS.Flag_Present = false;
				send_MegaTec_cmd(ups_remain_time_reg);
				if (ups_megatec_rx_pdu())
					ups_megatec_process_pdu(ups_remain_time_reg);

				megatec_send=true;
			}
			//vTaskDelay(100);
			if(megatec_send){
				megatec_send = false;
				UPS.Flag_Present = false;
				 send_MegaTec_cmd(ups_info);
				if (ups_megatec_rx_pdu())
					ups_megatec_process_pdu(ups_info);
				megatec_send = true;
			}

	        vTaskDelay(1000);

		}
}

void ups_megatec_init(void) {
	init_UPS_value();
	UPS.Present = true;
	xTaskCreate(request_task, ( char * ) "request_task", configMINIMAL_STACK_SIZE * 2, NULL, tskIDLE_PRIORITY, NULL);

}
