#include "main.h"
#include "usart.h"
#include "tim.h"
#include "usart_tools.h"
#include "struc.h"
#include "crc16.h"
//#include "stdint.h"
#include "flash_tools.h"

uint16_t modbus[Modbus_LEN+1];

uint8_t UART_Buffer[All_Buffer_Len*2];

int RS_Len[70]={0};

//	The memory area into which the information arrays will be loaded.
//	There's only one; it is assumed that arrays will not be loaded on both ports at the same time.
uint8_t * Array_Load_Address = (uint8_t *)0x10000000;

uint8_t Array_Load[0x8000];

uint8_t UART_get_command(UART_HandleTypeDef *huart)
{
  int com=0;
	
	if(huart->RxState == HAL_UART_STATE_BUSY)
	{
		com = Buffer_in[1];
		huart->RxState = HAL_UART_STATE_READY;
	}
	return com;
}

void HAL_UART_Receive_IT_user_handler(UART_HandleTypeDef *huart)
{
  uint8_t gotten_byte;
  static uint16_t C_crc, R_rcrc;
	
	if(!__HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE)) return;
	
	gotten_byte = huart->Instance->DR; 

	huart->Timeout_counter = 0;
	
	if (huart->RxState == HAL_UART_STATE_BUSY) return;
	
	if (huart->RxState == HAL_UART_STATE_READY)
	{
		huart->RxState = HAL_UART_STATE_BUSY_RX;
		huart->RxEventType = Package_type;	//	Not array again, just a package
		huart->RxXferCount=0;
		C_crc = 0xFFFF;
	}

//	Not array yet, just a package	
	if(huart->RxEventType == Package_type) Buffer_in[huart->RxXferCount] = gotten_byte;

//	Now it's time to receive an array	
	if(huart->RxEventType == Array_type) Array_Load_Address[huart->RxXferCount-2] = gotten_byte;
		
	if( (huart->RxXferCount > 2) && (huart->RxXferCount >= huart->RxXferSize-2) )
	{
		if(huart->RxXferCount == huart->RxXferSize-2) LOBYTE(R_rcrc) = gotten_byte;
		if(huart->RxXferCount == huart->RxXferSize-1 ) HIBYTE(R_rcrc) = gotten_byte;
	}
	else C_crc = get_crc_one(C_crc, gotten_byte);
	
	huart->RxXferCount++;

	if(huart->RxXferCount == 1)
	{
		if(gotten_byte != Mode)
		if(gotten_byte != UNIVERSAL_ADDR)
//			We don't know such an address		
			huart->RxState = HAL_UART_STATE_READY;
		
		return;
	}

	if(huart->RxXferCount == 2) 
	{
		if(gotten_byte == CMD_LOAD)
		{
			huart->RxEventType = Array_type;	//	Now it's time to receive an array
		}
		else
		{
			huart->RxXferSize = RS_Len[gotten_byte];
		
			if(huart->RxXferSize == 0) 
//				We don't know such a command
				huart->RxState = HAL_UART_STATE_READY;
	}	}
	
	if(huart->RxXferCount >= huart->RxXferSize)
	{
		if(R_rcrc == C_crc) huart->RxState = HAL_UART_STATE_BUSY;	// Received successfully
		else				huart->RxState = HAL_UART_STATE_READY;	// Received improperly
}	}

void HAL_UART_timeout_check()
{
#ifdef TIMEOUT_ON	
	
	if(huart2.RxState == HAL_UART_STATE_BUSY_RX)
	if(huart2.Timeout_counter++ >= TIMEOUT_EDGE)
	{
		huart2.RxState = HAL_UART_STATE_READY;	//	enough waiting!
		huart2.Timeout_counter= 0;
	}

	if(huart3.RxState == HAL_UART_STATE_BUSY_RX)
	if(huart3.Timeout_counter++ >= TIMEOUT_EDGE)
	{	
		huart3.RxState = HAL_UART_STATE_READY;	//	enough waiting!
		huart3.Timeout_counter= 0;
	}
#endif	
}

void Setup_cmd_length()
{
	RS_Len[CMD_LOAD]   = 12;	// is
	RS_Len[CMD_UPLOAD] = 12;	// is
	RS_Len[CMD_RUN] = 8;
	RS_Len[CMD_XFLASH] = 9;
	RS_Len[CMD_TFLASH] = 16;	// is
	RS_Len[CMD_PEEK] = 8;	// is
	RS_Len[CMD_POKE] = 12;	// is
	RS_Len[CMD_INITLOAD] = 12;	// is
	RS_Len[CMD_INIT] = 5;	// is
	RS_Len[CMD_VECTOR] = sizeof(CMD_TO_TMS)-2;
	RS_Len[CMD_STD] = sizeof(CMD_TO_TMS)-1;  
	RS_Len[CMD_IMPULSE] = 8;
	RS_Len[CMD_MODBUS_3] = 8;	// is
	RS_Len[CMD_MODBUS_6] = 8;	// is
	RS_Len[CMD_MODBUS_16] = 13;
	RS_Len[CMD_MODBUS_15] = 27;
	RS_Len[CMD_EXTEND] = 18;	// is
}

void HAL_UART_user_setup()
{
	Setup_cmd_length();
	
	huart2.pRxBuffPtr = UART_Buffer;
	huart3.pRxBuffPtr = UART_Buffer + All_Buffer_Len;
	
//	These flags are not used for their intended purpose. 
//	But only to tell if we have to switch the direction of this port.
	huart2.ReceptionType = RS485;	//	RS485, would be switched
	huart3.ReceptionType = RS232;	//	RS232, no need to switch

//	These flags are not used for their intended purpose. 
//	But only to tell if we are receiving an array of data or just a package
	huart2.RxEventType = Package_type;	//	Not array yet, just a package
	huart3.RxEventType = Package_type;	//	Not array yet, just a package

	huart2.RxState  = HAL_UART_STATE_READY;
	huart3.RxState  = HAL_UART_STATE_READY;

	huart2.Timeout_counter= 0;
	huart3.Timeout_counter= 0;
	
	RS485_in;
	
/*	Enable the UART Data Register not empty Interrupt */
  __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE);
	
/*	Enable the UART Data Register not empty Interrupt */
  __HAL_UART_ENABLE_IT(&huart3, UART_IT_RXNE);
	
}

static inline void switch_RS485_out(UART_HandleTypeDef *huart)
{
	if(huart->ReceptionType == RS485) 
	{
		RS485_out; 
		usDelay(100);
}	}

static inline void CMD_answer(UART_HandleTypeDef *huart, uint8_t CMD)
{
  uint16_t crc;

	Buffer_out[0] = Buffer_in[0];
	Buffer_out[1] = CMD;
	
	crc = get_crc_16(Buffer_out, 2);

	Buffer_out[2] = LOBYTE(crc);
	Buffer_out[3] = HIBYTE(crc);
	
	switch_RS485_out(huart);
	
	HAL_UART_Transmit_IT(huart,Buffer_out,4);	
}


void peek(UART_HandleTypeDef *huart)
{
  uint32_t Address, Data;
  uint16_t crc;

	BYTE0(Address) = Buffer_in[2];
	BYTE1(Address) = Buffer_in[3];
	BYTE2(Address) = Buffer_in[4];
	BYTE3(Address) = Buffer_in[5];
/*	
	if(Address>=0x10000000)
	{
		Address &= 0xFFFFFFF;
//		Data = watInTheFlash(FLASH_EEPROM_BASE + Address);		
	}
	else*/	Data = (*(volatile int *)(Address));

	Buffer_out[0] = Buffer_in[0];
	Buffer_out[1] = CMD_PEEK;

	Buffer_out[2] = BYTE0(Data);
	Buffer_out[3] = BYTE1(Data);
	Buffer_out[4] = BYTE2(Data);
	Buffer_out[5] = BYTE3(Data);

	crc = get_crc_16(Buffer_out, 6);

	Buffer_out[6] = LOBYTE(crc);
	Buffer_out[7] = HIBYTE(crc);
	
	switch_RS485_out(huart);
	
	HAL_UART_Transmit_IT(huart,Buffer_out,8);	
}

void poke(UART_HandleTypeDef *huart) 
{
  uint32_t Address;
  uint16_t Data;

	BYTE0(Address) = Buffer_in[2];
	BYTE1(Address) = Buffer_in[3];
	BYTE2(Address) = Buffer_in[4];
	BYTE3(Address) = Buffer_in[5];

	HIBYTE(Data) = Buffer_in[7];
	LOBYTE(Data) = Buffer_in[6];

/*
	if(Address>=0x2000000)
	{
		Address&=0xFFFFFF;
		I2CA_WriteData(Address,Data);
	}
	else
	if(Address>=0x1000000)
	{
		Address&=0xFFFFFF;
		Seeprom_write(Address,(unsigned int *)&Data,2);
	}
	else
	{
		Address&=0xFFFFFF;
		write_memory(Address,Data);
	}
*/	
	*(volatile uint16_t *)Address = Data;
	
	CMD_answer(huart,CMD_POKE);	
}

void initload(UART_HandleTypeDef *huart) 
{
  uint32_t Address, Length;

	BYTE0(Address) = Buffer_in[2];
	BYTE1(Address) = Buffer_in[3];
	BYTE2(Address) = Buffer_in[4];
	BYTE3(Address) = Buffer_in[5];

	BYTE0(Length) = Buffer_in[6];
	BYTE1(Length) = Buffer_in[7];
	BYTE2(Length) = Buffer_in[8];
	BYTE3(Length) = Buffer_in[9];
	
	Array_Load_Address = Array_Load;//(uint8_t *)Address;

	huart->RxXferSize = Length + 4; // +2 header, +2 crc
	
	CMD_answer(huart,CMD_INITLOAD);	
}

void load(UART_HandleTypeDef *huart)
{
   	CMD_answer(huart, CMD_LOAD);
}

void extendbios(UART_HandleTypeDef *huart) 
{
	uint32_t Address1,Address2,Length;
	uint8_t Code;

	BYTE0(Address1) = Buffer_in[2];
	BYTE1(Address1) = Buffer_in[3];
	BYTE2(Address1) = Buffer_in[4];
	BYTE3(Address1) = Buffer_in[5];
	
	BYTE0(Address1) = Buffer_in[6];
	BYTE1(Address1) = Buffer_in[7];
	BYTE2(Address1) = Buffer_in[8];
	BYTE3(Address1) = Buffer_in[9];
	
	BYTE0(Length) = Buffer_in[10];
	BYTE1(Length) = Buffer_in[11];
	BYTE2(Length) = Buffer_in[12];
	BYTE3(Length) = Buffer_in[13];

    Code = Buffer_in[14];
	
	switch ( Code )
	{
	//		????????? EPROM ?? RAM
	case 4:	//Seeprom_write(Address1,(unsigned int*)Address2,Length);
		
		Put_Program_to_FLESH(Array_Load, Length);

		
		
			break;	
	//		?????? ??  EPROM ? RAM
//	case 5:	Seeprom_read(Address1,(unsigned int*)Address2,Length);
//			break;	

	}

	CMD_answer(huart,CMD_EXTEND);
}

/***************************************************************/
/*  Передача данных по протоколу ModBus - команда 3
    Чтение ачеек данных    		*/
/***************************************************************/
void ReceiveCommandModbus3(UART_HandleTypeDef *huart)
{
  uint16_t Address, Length, crc;
  uint8_t i;

//	получили начальный адрес чтениа
	HIBYTE(Address) = Buffer_in[2];
	LOBYTE(Address) = Buffer_in[3];

//	получили количество слов данных
	HIBYTE(Length) = Buffer_in[4];
	LOBYTE(Length) = Buffer_in[5];

	/////////////////////////////////////////////////
	// Отсылка
	/* Посчитали контрольную сумму перед самой посылкой */	

	Buffer_out[0] =  Buffer_in[0];
	Buffer_out[1] =  Buffer_in[1];
	Buffer_out[2] =  Length*2;

	for (i=0;i<Length;i++)
	{
   		Buffer_out[3+i*2  ] = HIBYTE(modbus[Address+i]);
   		Buffer_out[3+i*2+1] = LOBYTE(modbus[Address+i]);
	}

	crc = get_crc_16(Buffer_out, Length*2+3);

	Buffer_out[Length*2+3] = LOBYTE(crc);
	Buffer_out[Length*2+4] = HIBYTE(crc);

	switch_RS485_out(huart);

	HAL_UART_Transmit_IT(huart,Buffer_out,Length*2+5);	
	
	return;
}

void ReceiveCommandModbus6(UART_HandleTypeDef *huart)
{
  uint16_t Address, Data;
  uint8_t i;

	/////////////////////////////////////////////////
	// Отсылка
	/* Отправлаем назад то же самое */	

	for (i=0;i<8;i++)
	Buffer_out[i] = Buffer_in[i];

//	получили начальный адрес записи
	HIBYTE(Address) = Buffer_in[2];
	LOBYTE(Address) = Buffer_in[3];
	
//	получили слово данных
	HIBYTE(Data) = Buffer_in[4];
	LOBYTE(Data) = Buffer_in[5];

	if(Address < Modbus_LEN)
	modbus[Address] = Data;

	switch_RS485_out(huart);

	HAL_UART_Transmit_IT(huart,Buffer_out,8);	
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->ReceptionType == RS485) 
	if(RS485_dir) RS485_in;
}

