#include "parse.h"

float unpackFloat(const void *buf)
{
    const unsigned char *b = (const unsigned char *)buf;
    uint32_t temp = 0;
    temp = ((b[0] << 24) |
            (b[1] << 16) |
            (b[2] <<  8) |
             b[3]);
    return *((float *) &temp);
}

bool check_float(float data_in, float data_min, float data_max)
{
	if((data_in >= data_min) && (data_in <= data_max))
	{
		return true;
	}
	return false;
}

uint16_t unpackUint16(const void *buf)
{
    const unsigned char *b = (const unsigned char *)buf;
    uint16_t temp = 0;
    temp = ((b[2] <<  8) | b[3]);
    return *((uint16_t *) &temp);
}

bool check_uint16(uint16_t data_in, uint16_t data_min, uint16_t data_max)
{
	if((data_in >= data_min) && (data_in <= data_max))
	{
		return true;
	}
	return false;
}

uint8_t unpackUint8(const void *buf)
{
    const unsigned char *b = (const unsigned char *)buf;
    uint8_t temp = 0;
    temp = b[3];
    return *((uint8_t *) &temp);
}

bool check_uint8(uint8_t data_in, uint8_t data_min, uint8_t data_max)
{
	if((data_in >= data_min) && (data_in <= data_max))
	{
		return true;
	}
	return false;
}

uint32_t unpackUint32(const void *buf)
{
    const unsigned char *b = (const unsigned char *)buf;
    uint32_t temp = 0;
    temp = ((b[0] << 24) |
            (b[1] << 16) |
            (b[2] <<  8) |
             b[3]);
    return *((uint32_t *) &temp);
}

bool check_uint32(uint32_t data_in, uint32_t data_min, uint32_t data_max)
{
	if((data_in >= data_min) && (data_in <= data_max))
	{
		return true;
	}
	return false;
}

void parse_command(uint8_t* buf, icd_str * icd_str)
{
	float fdata = -1.0;
	if((buf[0] == 0x55) && (buf[6] == 0x77))
	{
		switch (buf[1])
		{
			//float min_tres
			case 0x01:
			{
				fdata = unpackFloat(&buf[2]);
				if(check_float(fdata, 0.1, 10.0))//fixme сделал большую вариабельность
				{
					if(fdata < icd_str->max_tres)
					// проверили что меньше максимального порога
					icd_str->min_tres = fdata;
				}
			}
			break;
			//float max_tres
			case 0x02:
			{
				fdata = unpackFloat(&buf[2]);
				if(check_float(fdata, 1.5, 20.0))//fixme сделал большую вариабельность
				{
					if(fdata > icd_str->min_tres)
					// проверили что больше минимального порога
					icd_str->max_tres = fdata;
				}
			}
			break;
			//float square_coef
			case 0x03:
			{
				fdata = unpackFloat(&buf[2]);
				if(check_float(fdata, 0.25, 0.75))
				{
					icd_str->square_coef = fdata;
				}
			}
			break;
			//float triangle_coef
			case 0x04:
			{
				fdata = unpackFloat(&buf[2]);
				// min max triangle coef???? const 0.85
				if(check_float(fdata, 0.8, 0.9))
				{
					icd_str->triangle_coef = fdata;
				}

			}
			break;
			//start_up_time
			case 0x05:
			{
				uint8_t idata = unpackUint8(&buf[2]);
				if(check_uint8(idata, 0, 2))
				{
					icd_str->work_set_mode = idata;
					//fixme тут нужно написать сброс всего и вся
					if(idata == Monitor)
					{
						icd_str->fibr_cnt 		= 0;
						icd_str->tachy_2_cnt	= 0;
						icd_str->tachy_1_cnt	= 0;
						icd_str->fibr_cnt 		= 0;
					}
				}
			}
			break;
			//base_time
			case 0x06:
			{
				uint16_t idata = unpackUint16(&buf[2]);
				// min max???? const 300
				if(check_uint16(idata, 100, 400))
				{
					icd_str->base_time = idata/5;
				}
			}
			break;
			//square_time
			case 0x07:
			{
				uint16_t idata = unpackUint16(&buf[2]);
				// 350
				if(check_uint16(idata, 300, 400))
				{
					icd_str->square_time = idata/5;
				}
			}
			break;
			//triangle_time
			case 0x08:
			{
//				uint16_t idata = unpackUint16(&buf[2]);
//				// 300
//				if(check_uint16(idata, 200, 400))
//				{
//					icd_str->triangle_time = idata;
//				}
			}
			break;
			//triangle_step_time сделаю тут максимальное время на цикл лучше
			case 0x09:
			{
				uint16_t idata = unpackUint16(&buf[2]);
				if(check_uint16(idata, 500, 2000))//границы берём из графического интерфейса лучше переделатьь в дефайны
				{
					icd_str->max_time = idata/5;
				}
//				uint16_t idata = unpackUint16(&buf[2]);
//				// 50
//				if(check_uint16(idata, 40, 60))
//				{
//					icd_str->triangle_step_time = idata;
//				}
			}
			break;
			//lv_mode_time
			case 0x0A:
			{
//				uint16_t idata = unpackUint16(&buf[2]);
//				// ????
//				if(check_uint16(idata, 40, 60))
//				{
//					icd_str->lv_mode_time = idata;
//				}

			}
			break;
			//lv_start_time
			case 0x0B:
			{
//				uint16_t idata = unpackUint16(&buf[2]);
//				icd_str->lv_start_time = idata;
//

			}
			break;
			//lv_stop_time
			case 0x0C:
			{
//				uint16_t idata = unpackUint16(&buf[2]);
//				icd_str->lv_stop_time = idata;

			}
			break;
			//max_time
			case 0x0D:
			{
				uint16_t idata = unpackUint16(&buf[2]);
				if(check_uint16(idata, 120, 200))//fixme расширю границы берём из графического интерфейса лучше переделатьь в дефайны
				{
					icd_str->max_search_time = idata/5;
				}
			}
			break;
			//bool LV_on //bool HV_on
			case 0x0E:
			{
				// не стала делать, не используется же пока

			}
			break;

			//fibr_tres
			case 0x10:
			{
				uint16_t idata = unpackUint16(&buf[2]);
				if(check_uint16(idata, FIBR_PERIOD_MIN, FIBR_PERIOD_MAX))
				{
					idata/=5;
					//если меньше тахи2 и тахи 1
					if((idata < icd_str->tachy_2_tres) && (idata < icd_str->tachy_1_tres))
					// проверили что меньше максимального порога
						icd_str->fibr_tres = idata;
				}

			}
			break;
			//tachy_2_tres
			case 0x11:
			{
				uint16_t idata = unpackUint16(&buf[2]);
				if(check_uint16(idata, TACHY_2_PERIOD_MIN, TACHY_2_PERIOD_MAX))
				{
					idata/=5;
					//если больше фибр и меньше тахи 1
					if((idata > icd_str->fibr_tres) && (idata < icd_str->tachy_1_tres))
					// проверили что меньше максимального порога
						icd_str->tachy_2_tres = idata;
				}
			}
			break;
			//tachy_1_tres
			case 0x12:
			{
				uint16_t idata = unpackUint16(&buf[2]);
				if(check_uint16(idata, TACHY_1_PERIOD_MIN, TACHY_1_PERIOD_MAX))
				{
					idata/=5;
					//если больше фибр и больше тахи 2
					if((idata > icd_str->fibr_tres) && (idata > icd_str->tachy_2_tres))
					// проверили что меньше максимального порога
						icd_str->tachy_1_tres = idata;
				}
			}
			break;
			//fibr_max_tres
			case 0x13:
			{
				uint8_t idata = unpackUint8(&buf[2]);
				if(check_uint8(idata, 10, 60))
				{
					icd_str->fibr_max_tres = idata;
				}
			}
			break;
			//hv_step_number
			case 0x14:
			{
				uint8_t idata = unpackUint8(&buf[2]);
				if(check_uint8(idata, 1, 8))
				{
					icd_str->hv_step_number = idata;
				}
			}
			break;
			//min_energy
			case 0x15:
			{
				uint16_t idata = unpackUint16(&buf[2]);
				if(check_uint16(idata, 2, 19))
				{
					icd_str->min_energy = idata*10;
				}
			}
			break;
			//max_energy
			case 0x16:
			{
				uint16_t idata = unpackUint16(&buf[2]);
				if(check_uint16(idata, 20, 80))
				{
					if(idata*10 > icd_str->min_energy)
					icd_str->max_energy = idata*10;
				}
			}
			break;
			//cap_polarity
			case 0x17:
			{
				//не делала
			}
			break;
			//hv_blind_time
			case 0x18:
			{
				uint16_t idata = unpackUint16(&buf[2]);
				if(check_uint16(idata, 100, 5000))
				{
					icd_str->hv_blind_time = idata/5;
				}
			}
			break;
			//redet_num
			case 0x19:
			{
				uint8_t idata = unpackUint8(&buf[2]);
				if(check_uint8(idata, 4, 10))
				{
					icd_str->redet_num = idata;
				}
			}
			break;
			//redet_bad
			case 0x1A:
			{
				uint8_t idata = unpackUint8(&buf[2]);
				if(check_uint8(idata, 2, 8))
				{
					icd_str->redet_bad = idata;
				}
			}
			break;
			case 0x1B:
			{
				uint32_t idata = unpackUint32(&buf[2]);
				if(check_uint32(idata, 10, 3600))
				{
					icd_str->standby_timer = idata*1000;
				}
			}
			break;

			case 0x1C:
			{
				uint8_t idata = unpackUint8(&buf[2]);
				if(check_uint8(idata, 0, 255))
				{
					icd_str->spi_pot_set = idata;
				}
			}
			break;

			case 0x1D:
			{
				uint8_t idata = unpackUint8(&buf[2]);
				if(check_uint8(idata, 0, 255))
				{
					if(idata > 0)
						NVIC_SystemReset();//перезагрузка
				}
			}
			break;
			//с фильтром без фильтра
			case 0x1E:
			{
				uint8_t idata = unpackUint8(&buf[2]);
				if(check_uint8(idata, 0, 1))
				{
					icd_str->filter_on = (bool)idata;
				}
			}
			break;

			//с какой канал используем
			case 0x1F:
			{
				uint8_t idata = unpackUint8(&buf[2]);
				if(check_uint8(idata, 0, 3))
				{
					icd_str->active_ch = idata;
				}
			}
			break;

			//использование SD карты
			case 0x20:
			{
				uint8_t idata = unpackUint8(&buf[2]);
				if(check_uint8(idata, 0, 1))
				{
					icd_str->sd_card = (bool)idata;
				}
			}
			break;

			//вычитание постоянной составляющей
			case 0x21:
			{
				uint8_t idata = unpackUint8(&buf[2]);
				if(check_uint8(idata, 0, 1))
				{
					icd_str->dc_cut = (bool)idata;
				}
			}
			break;

			default:
			{
				//код неверный
			}
		}
	}
}
