/****************************************************************/
/*			    	  		TMS320C32							*/
/* 	======             BIOS, КЛАИН, КЛВСП              ====== 	*/
/* 	 		   		ЦНИИ СЭТ	  (с) 1998-2000 г.				*/
/****************************************************************
  Bios.c
 **************************************************************
                     Основные комманды BIOS	*
					   дла работы с RS232
****************************************************************/
#include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
#include "RS485.h"
#include "bios_dsp.h" 
#include "crc16.h"
#include "spise2p.h"
#include "i2c.h"

//#include "flash_tools.h"
//#include "spartan_tools.h"
//#include "big_dsp_module.h"
                  
int flag_DEBUG = false;	/* Флаг отладочного режима */


//static unsigned int *RecvPtr;
//static int BS_LoadOK = false;  /** Флаг успешности приема блока */

/**********************************************************/
/* Прототипы функций, используемых и определенных в файле */
/**********************************************************/
//static int _getbyte(int *addr, int offs);

unsigned int read_memory(unsigned long addr)
{
   return (*(volatile int *)(addr));
}

void write_memory(unsigned long addr, unsigned int data)
{
   (*(volatile int *)( addr )) = data;
}


/** Возвращает номер комманды, если есть или -1 если транзакций не было */
int get_command(RS_DATA *rs_arr)
{              
  int cmd;
  unsigned int crc, rcrc;

	if(rs_arr->RS_DataReady)			// Данные по RS пришли
	{               
		rs_arr->RS_DataReady = false;
		cmd = rs_arr->RS_Header[1];		// Прочитали номер команды
		
		// Провераем длину команды дла считываниа CRC
		if((RS_Len[cmd]<3) || (RS_Len[cmd]>MAX_RECEIVE_LENGTH))
		{
		    RS_Line_to_receive(rs_arr);	// режим приема RS485
			RS_SetBitMode(rs_arr,9);
			return -1;
		}

		if(cmd == CMD_LOAD)		// Если команда загрузки
		{
			rs_arr->RS_PrevCmd = cmd;
			return cmd; 		// Нет проверки crc
		}
		else                    // Все остальные команды
		{
			// Считываем crc из посылки
			crc  =	(rs_arr->RS_Header[RS_Len[cmd]-1] << 8) | 
					(rs_arr->RS_Header[RS_Len[cmd]-2]) ;
		}
        // Рассчитываем crc из посылки
		rcrc = 0xffff;
		rcrc = get_crc_16( rcrc, rs_arr->RS_Header, (RS_Len[cmd]-2) );

		if(crc == rcrc)				// Провераем crc
		{
			rs_arr->RS_PrevCmd = cmd;
			return cmd;
		}
		else
		{
		    RS_Line_to_receive(rs_arr);	// режим приема RS485
		    RS_SetBitMode(rs_arr,9);
	}	} 

	return -1;
}

/** Стандартный ответ, без параметров */
void Answer(RS_DATA *rs_arr,int n)
{
	int crc;

	flag_DEBUG = true;	// Флаг отладочного режима

	rs_arr->buffer[0] =  rs_arr->addr_recive; //CNTRL_ADDR;
	rs_arr->buffer[1] =  n;

    crc = 0xffff;
	crc = get_crc_16( crc, rs_arr->buffer, 2);

	rs_arr->buffer[2] = LOBYTE(crc);
	rs_arr->buffer[3] = HIBYTE(crc);
	
	rs_arr->buffer[4] = 0;
	rs_arr->buffer[5] = 0;
	RS_Send(rs_arr,rs_arr->buffer, 6);
}

/* Внутреннаа ф-циа */
static char _getbyte(unsigned int *addr, int32 offs)
{
  unsigned int *address;
  unsigned int byte;

	address = addr + offs/2;
	byte = *address;
	if(offs%2)	return LOBYTE(byte);
	else		return HIBYTE(byte);
}


/* начальные установки (не работает)*/
void init(RS_DATA *rs_arr) 
{
/*
	if(rs_arr->RS_Header[2]==3)
	{
		if (rs_arr->curr_baud!=57600)
		{	RS_SetLineSpeed(rs_arr,57600);
			rs_arr->curr_baud= 57600;
	}	}   
	
	if(rs_arr->RS_Header[2]==4)
	{
		if (rs_arr->curr_baud!=115200)
		{	RS_SetLineSpeed(rs_arr,115200);
			rs_arr->curr_baud= 115200;
	}	}

    Answer(rs_arr,CMD_INIT);
    rs_arr->BS_LoadOK = false;
*/
}

/**@name Комманды
* Комманды, вызываемые через последовательный канал
*/
//@{

/** Инициировать загрузку блока.
 Настраивает прием блока данных */
void initload(RS_DATA *rs_arr) 
{
	unsigned long Address;

	Address = rs_arr->RS_Header[5] & 0xFF;
	Address = (Address<<8) | (rs_arr->RS_Header[4] & 0xFF);
	Address = (Address<<8) | (rs_arr->RS_Header[3] & 0xFF);
	Address = (Address<<8) | (rs_arr->RS_Header[2] & 0xFF);

	rs_arr->RS_Length = rs_arr->RS_Header[9] & 0xFF;
	rs_arr->RS_Length = (rs_arr->RS_Length<<8) | (rs_arr->RS_Header[8] & 0xFF);
	rs_arr->RS_Length = (rs_arr->RS_Length<<8) | (rs_arr->RS_Header[7] & 0xFF);
	rs_arr->RS_Length = (rs_arr->RS_Length<<8) | (rs_arr->RS_Header[6] & 0xFF);

	rs_arr->RS_Length += 2;
	rs_arr->pRS_RecvPtr = (unsigned int *)Address; //(unsigned int *)Address; 
	rs_arr->pRecvPtr = (unsigned int *)Address; //(unsigned int *)Address;

    Answer(rs_arr,CMD_INITLOAD);
}

/** Загрузка блока. 
 Вызываетса после загрузки блока через RS */
void load(RS_DATA *rs_arr)
{
	unsigned int rcrc, crc;

    crc = (_getbyte(rs_arr->pRecvPtr, rs_arr->RS_Length-1) << 8) + 
    	   _getbyte(rs_arr->pRecvPtr, rs_arr->RS_Length-2);

	rs_arr->RS_Header[0] = rs_arr->addr_recive;
	
//	CNTRL_ADDR;                                           
	rs_arr->RS_Header[1]=CMD_LOAD;

	rcrc = 0xffff;
	rcrc = get_crc_16( rcrc, rs_arr->RS_Header, 2);
	rcrc = get_crc_16b( rcrc, rs_arr->pRecvPtr, rs_arr->RS_Length-2);

	if(rcrc == crc)
	{
    	Answer(rs_arr,CMD_LOAD);
    	rs_arr->BS_LoadOK = true;
    }
    else 
    {
    	rs_arr->BS_LoadOK = false;
    	RS_Line_to_receive(rs_arr);	// режим приема RS485
    	RS_SetBitMode(rs_arr,9);
}	}

/** Выполнить программу в формате Serial Boot.
 @precondition Должна быть произведена загрузка блока
 Адрес программы беретса из заголовка и 
 сравниваетса с переменной RecvPtr, заполнаемой в ф-ции load
 @see load */
void run (RS_DATA *rs_arr) 
{            
	return;     
}

/** Прочитать  ачейку памати */
void peek(RS_DATA *rs_arr)
{
	unsigned long Address;
	unsigned int Data, crc;
	
	flag_DEBUG = true;	// Флаг отладочного режима
	
	Address = rs_arr->RS_Header[5] & 0xFF;
	Address = (Address<<8) | (rs_arr->RS_Header[4] & 0xFF);
	Address = (Address<<8) | (rs_arr->RS_Header[3] & 0xFF);
	Address = (Address<<8) | (rs_arr->RS_Header[2] & 0xFF);


	if(Address>=0x20000000)
	{
		Address&=0xFFFFFFF;
		Data = I2CA_ReadData(Address);
	}
	else
	if(Address>=0x10000000)
	{
		Address&=0xFFFFFFF;
		Seeprom_read(Address,(unsigned int *)&Data,2);
	}
	else
	{
		Address&=0xFFFFFFF;
		Data = read_memory(Address);
	}

	rs_arr->buffer[0] = rs_arr->addr_recive; //CNTRL_ADDR;
	rs_arr->buffer[1] = CMD_PEEK;

	rs_arr->buffer[2] = LOBYTE(Data);
	rs_arr->buffer[3] = HIBYTE(Data);

	rs_arr->buffer[4] = 0;//LOBYTE(CpuTimer2.InterruptCount);
	rs_arr->buffer[5] = 0;//HIBYTE(CpuTimer2.InterruptCount);

    crc = 0xffff;
	crc = get_crc_16(crc, rs_arr->buffer, 6);

	rs_arr->buffer[6] = LOBYTE(crc);
	rs_arr->buffer[7] = HIBYTE(crc);
	rs_arr->buffer[8] = 0;  
	rs_arr->buffer[9] = 0;  
	
   	RS_Send(rs_arr,rs_arr->buffer, 10);

}

/** Записать в ачейку памати */
void poke(RS_DATA *rs_arr) 
{
	unsigned long Address;
	unsigned int Data;

	Address = rs_arr->RS_Header[5] & 0xFF;
	Address = (Address<<8) | (rs_arr->RS_Header[4] & 0xFF);
	Address = (Address<<8) | (rs_arr->RS_Header[3] & 0xFF);
	Address = (Address<<8) | (rs_arr->RS_Header[2] & 0xFF);

    Data = 0;
	Data = (Data<<8) | (rs_arr->RS_Header[7] & 0xFF);
	Data = (Data<<8) | (rs_arr->RS_Header[6] & 0xFF);

	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);
	}
    
	Answer(rs_arr,CMD_POKE);
}

/** Передать блок памати */
void upload(RS_DATA *rs_arr) 
{
  int32 Address, Length, crc;
	
	flag_DEBUG = true;	// Флаг отладочного режима
//	stopp=1;

	Address = rs_arr->RS_Header[5] & 0xFF;
	Address = (Address<<8) | (rs_arr->RS_Header[4] & 0xFF);
	Address = (Address<<8) | (rs_arr->RS_Header[3] & 0xFF);
	Address = (Address<<8) | (rs_arr->RS_Header[2] & 0xFF);

	Length = rs_arr->RS_Header[9] & 0xFF;
	Length = (Length<<8) | (rs_arr->RS_Header[8] & 0xFF);
	Length = (Length<<8) | (rs_arr->RS_Header[7] & 0xFF);
	Length = (Length<<8) | (rs_arr->RS_Header[6] & 0xFF);

	rs_arr->buffer[0] = rs_arr->addr_recive; //CNTRL_ADDR;
    rs_arr->buffer[1] = CMD_UPLOAD;

    crc = 0xffff;
	crc = get_crc_16( crc, rs_arr->buffer, 2);	
	crc = get_crc_16b( crc, (unsigned int *)Address, Length);

   	RS_Send(rs_arr,rs_arr->buffer, 1);	// <=2 байт по флагу
   	
   	rs_arr->buffer[0] = CMD_UPLOAD;                    
   	RS_Send(rs_arr,rs_arr->buffer, 1);	// <=2 байт по флагу
   	
   	RS_Wait4OK(rs_arr);
	RS_BSend(rs_arr,(unsigned int*)Address, Length);
	RS_Wait4OK(rs_arr);

	rs_arr->buffer[0] = LOBYTE(crc);
	rs_arr->buffer[1] = HIBYTE(crc);
	rs_arr->buffer[2] = 0;
	rs_arr->buffer[3] = 0;
	RS_Send(rs_arr,rs_arr->buffer, 4+2);

}

/** Прошить XILINX. 
 @precondition Должна быть произведена загрузка блока
 Адрес и длина прошивки беретса из заголовка и 
 сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load,
 так же смотрит магическое слово в начале прошивки
 @see load */
void xflash(RS_DATA *rs_arr) 
{
	return;
}

/** Прошить TMS.
 @precondition Должна быть произведена загрузка блока
 Адрес и длина прошивки беретса из заголовка и 
 сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load
 @see load */
void tflash(RS_DATA *rs_arr) 
{
//	volatile unsigned long Address1,Address2;
//	volatile unsigned long Length, LengthW;
/*
    if(!rs_arr->BS_LoadOK) 
    {
      RS_Line_to_receive(rs_arr);	// режим приема RS485
      RS_SetBitMode(rs_arr,9);
      return;
    }

	Address1 = rs_arr->RS_Header[5] & 0xFF;
	Address1 = (Address1<<8) | (rs_arr->RS_Header[4] & 0xFF);
	Address1 = (Address1<<8) | (rs_arr->RS_Header[3] & 0xFF);
	Address1 = (Address1<<8) | (rs_arr->RS_Header[2] & 0xFF);

	Address2 = rs_arr->RS_Header[9] & 0xFF;
	Address2 = (Address2<<8) | (rs_arr->RS_Header[8] & 0xFF);
	Address2 = (Address2<<8) | (rs_arr->RS_Header[7] & 0xFF);
	Address2 = (Address2<<8) | (rs_arr->RS_Header[6] & 0xFF);

	Length = rs_arr->RS_Header[13] & 0xFF;
	Length = (Length<<8) | (rs_arr->RS_Header[12] & 0xFF);
	Length = (Length<<8) | (rs_arr->RS_Header[11] & 0xFF);
	Length = (Length<<8) | (rs_arr->RS_Header[10] & 0xFF);

    LengthW = Length/2;
	if (LengthW*2<Length) LengthW++;

	if(	(Address2 < 0x100000) || (Address2 > 0x180000)  || ((Address2+LengthW) > 0x180000)  ) 
    {
      RS_Line_to_receive(rs_arr);	// режим приема RS485
      RS_SetBitMode(rs_arr,9);
      return;
    }

    run_flash_data(Address1,Address2, LengthW );

    Answer(rs_arr,CMD_TFLASH);
*/    
    return;
}

/** Прошить TMS.
 @precondition Должна быть произведена загрузка блока
 Адрес и длина прошивки беретса из заголовка и 
 сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load
 @see load */
void extendbios(RS_DATA *rs_arr) 
{
	volatile unsigned long Address1,Address2,Length;
	unsigned int code;

	Address1 = rs_arr->RS_Header[5] & 0xFF;
	Address1 = (Address1<<8) | (rs_arr->RS_Header[4] & 0xFF);
	Address1 = (Address1<<8) | (rs_arr->RS_Header[3] & 0xFF);
	Address1 = (Address1<<8) | (rs_arr->RS_Header[2] & 0xFF);

	Address2 = rs_arr->RS_Header[9] & 0xFF;
	Address2 = (Address2<<8) | (rs_arr->RS_Header[8] & 0xFF);
	Address2 = (Address2<<8) | (rs_arr->RS_Header[7] & 0xFF);
	Address2 = (Address2<<8) | (rs_arr->RS_Header[6] & 0xFF);

	Length = rs_arr->RS_Header[13] & 0xFF;
	Length = (Length<<8) | (rs_arr->RS_Header[12] & 0xFF);
	Length = (Length<<8) | (rs_arr->RS_Header[11] & 0xFF);
	Length = (Length<<8) | (rs_arr->RS_Header[10] & 0xFF);

    code=rs_arr->RS_Header[14] & 0xFF;
	
	switch ( code )
	{
	//		Прошиваем EPROM Из RAM
	case 4:	Seeprom_write(Address1,(unsigned int*)Address2,Length);
			break;	
	//		Читаем из  EPROM в RAM
	case 5:	Seeprom_read(Address1,(unsigned int*)Address2,Length);
			break;	

	default:
			return;
	}

	Answer(rs_arr,CMD_EXTEND);
	return;
}

//@}
