/****************************************************************/
/*			    	  		TMS320C32							*/
/* 	======             BIOS, КЛАИН, КЛВСП              ====== 	*/
/* 	 		   		ЦНИИ СЭТ	  (с) 1998-2000 г.				*/
/****************************************************************
     RS485.с
 ****************************************************************
 *				 	Процедуры работы с UART		 				*
 ****************************************************************/

//#include "big_dsp_module.h"


#include "DSP2833x_Device.h"
#include "DSP2833x_SWPrioritizedIsrLevels.h"

#include "RS485.h"
#include "bios_dsp.h"
#include "cntrl_adr.h"

#include "tools.h"

//#include "flash_tools.h"


RS_DATA rs_a,rs_b;

unsigned int	RS_Len[70]={0};

static char size_cmd15=1; 

void RS_RX_Handler(RS_DATA *rs_arr);
void RS_TX_Handler(RS_DATA *rs_arr);

/** Обработчик прерываний UART - принато	*/
interrupt void RSA_RX_Handler(void)
{
//	Set interrupt priority:
	volatile Uint16 TempPIEIER = PieCtrlRegs.PIEIER9.all;
	IER |= M_INT9;
	IER	&= MINT9;						// Set "global" priority
	PieCtrlRegs.PIEIER9.all &= MG91;	// Set "group"  priority	
	PieCtrlRegs.PIEACK.all = 0xFFFF;	// Enable PIE interrupts	
	EINT;

	clear_timer_rs_live(&rs_a);
	RS_RX_Handler(&rs_a);

//	Restore registers saved:
	DINT;
	PieCtrlRegs.PIEIER9.all = TempPIEIER;
}

interrupt void RSB_RX_Handler(void)
{
//	Set interrupt priority:
	volatile Uint16 TempPIEIER = PieCtrlRegs.PIEIER9.all;
	IER |= M_INT9;
	IER	&= MINT9;						// Set "global" priority
	PieCtrlRegs.PIEIER9.all &= MG93;	// Set "group"  priority	
	PieCtrlRegs.PIEACK.all = 0xFFFF;	// Enable PIE interrupts	
	EINT;

	clear_timer_rs_live(&rs_b);
	RS_RX_Handler(&rs_b);
   
//	Restore registers saved:
	DINT;
	PieCtrlRegs.PIEIER9.all = TempPIEIER;
}

interrupt void RSA_TX_Handler(void)
{
//	Set interrupt priority:
	volatile Uint16 TempPIEIER = PieCtrlRegs.PIEIER9.all;
	IER |= M_INT9;
	IER	&= MINT9;						// Set "global" priority
	PieCtrlRegs.PIEIER9.all &= MG92;	// Set "group"  priority	
	PieCtrlRegs.PIEACK.all = 0xFFFF;	// Enable PIE interrupts	
	EINT;

	clear_timer_rs_live(&rs_a);
	RS_TX_Handler(&rs_a);

//	Restore registers saved:
	DINT;
	PieCtrlRegs.PIEIER9.all = TempPIEIER;
}

interrupt void RSB_TX_Handler(void)
{
//	Set interrupt priority:
	volatile Uint16 TempPIEIER = PieCtrlRegs.PIEIER9.all;
	IER |= M_INT9;
	IER	&= MINT9;						// Set "global" priority
	PieCtrlRegs.PIEIER9.all &= MG94;	// Set "group"  priority	
	PieCtrlRegs.PIEACK.all = 0xFFFF;	// Enable PIE interrupts	
	EINT;

	clear_timer_rs_live(&rs_b);
	RS_TX_Handler(&rs_b);

//	Restore registers saved:
	DINT;
	PieCtrlRegs.PIEIER9.all = TempPIEIER;
}

/** Обработчик прерываний UART - принато	*/
void RS_RX_Handler(RS_DATA *rs_arr)
{
  char	Rc;
  char RS_BytePtr;

//	led1_on();

	for(;;) // 'goto' это не оператор азыка С
  	{	
		if(!rs_arr->SciRegs->SCIRXST.bit.RXRDY)			//	Receiver ready flag
		{
			PieCtrlRegs.PIEACK.bit.ACK9 |= 1;
			rs_arr->SciRegs->SCIFFRX.bit.RXFFINTCLR=1;	//	Clear INT flag
			return;	// кстати это единственный выход из прерываниа
		}

		Rc = rs_arr->SciRegs->SCIRXBUF.bit.RXDT;		// Читаем символ в любом случае

		if(rs_arr->SciRegs->SCIRXST.bit.RXERROR)		//	Receiver error flag
		{
			rs_arr->SciRegs->SCICTL1.bit.SWRESET=0;     // Reset SCI
			rs_arr->SciRegs->SCICTL1.bit.SWRESET=1;     // Relinquish SCI from Reset

			continue;
		}

		if(rs_arr->RS_DataReady) continue;	// Не забрали данные

		if (rs_arr->RS_Flag9bit==1)        // дла RS485????????
		{
			// Инициализируем переменные и флаги
			rs_arr->RS_FlagBegin = true;	// Ждем заголовок
			rs_arr->RS_RecvLen = 0;
			rs_arr->RS_FlagSkiping = false;
			rs_arr->RS_HeaderCnt = 0;
			rs_arr->RS_Cmd = 0;		
		}
					
		if(rs_arr->RS_FlagSkiping) continue;	// Не нам
		
		if (rs_arr->RS_FlagBegin)				// Заголовок
		{
			if (rs_arr->RS_HeaderCnt==0)		// Адрес контроллера или стандартнаа команда
			{   
				 if( (Rc == CNTRL_ADDR_UNIVERSAL) || (Rc == CNTRL_ADDR && CNTRL_ADDR!=0) || ((Rc == rs_arr->addr_answer) && rs_arr->flag_LEADING) 
				 	|| ((Rc == ADDR_FOR_ALL && ADDR_FOR_ALL!=0) && !rs_arr->flag_LEADING))

				{
				    rs_arr->addr_recive=Rc; // запомнили адрес по которому нас запросили
					rs_arr->RS_Header[rs_arr->RS_HeaderCnt++] = Rc;	// Первый байт
					RS_SetBitMode(rs_arr,8);				// перестроились в 8-бит режим
				}
				else  
				{
					rs_arr->RS_FlagSkiping = true; // Не нашему контроллеру
					rs_arr->RS_FlagBegin = false;  // остались в 9-бит режиме
//					led1_off();
				}
			}
			else 
			{   
				rs_arr->RS_Header[rs_arr->RS_HeaderCnt++] = Rc;	// Второй байт и т.д.

				if (rs_arr->RS_HeaderCnt == 7 && rs_arr->RS_Cmd==CMD_MODBUS_16 && !rs_arr->flag_LEADING)
				{
					RS_Len[CMD_MODBUS_16] = (10+Rc);
				}

				// если второй байт - это команда
				if (rs_arr->RS_HeaderCnt == 2)
				{   
					rs_arr->RS_Cmd = Rc;
					// Проверка длины посылки
					// CMD_LOAD - младшаа на данный момент
					// CMD_STD_ANS - старшаа на данный момент
					if ((rs_arr->RS_Cmd < CMD_MODBUS_3) || (rs_arr->RS_Cmd > CMD_STD_ANS) || (RS_Len[rs_arr->RS_Cmd]<3)
						|| ((rs_arr->RS_Cmd == CMD_LOAD)&&(rs_arr->RS_PrevCmd != CMD_INITLOAD))
					)
					{
						RS_SetBitMode(rs_arr,9); 	// Получили все перестроились в 9-бит дла RS485?
						rs_arr->RS_HeaderCnt = 0;	// Потому что команда не та
						rs_arr->RS_FlagBegin = true;
						rs_arr->RS_FlagSkiping = false;
						rs_arr->RS_Cmd=0; 
//						led1_off();
						continue;								
					}
					if (rs_arr->RS_Cmd == CMD_LOAD) // Дла этой команды заголовок очень короткий
					rs_arr->RS_FlagBegin = false;// дальше идут данные
				}

				if(	(rs_arr->RS_HeaderCnt >= RS_Len[rs_arr->RS_Cmd]) ||
					(rs_arr->RS_HeaderCnt >= sizeof(rs_arr->RS_Header)))
				{	// Получили заголовок
					RS_SetBitMode(rs_arr,9);	// Получили все перестроились в 9-бит дла RS485?
					rs_arr->RS_FlagBegin = false;
					rs_arr->RS_FlagSkiping = true;
					rs_arr->RS_DataReady = true;
					rs_arr->RS_Cmd=0;
//					led1_off();
		}	}	}
		else		// Поток данных
		{   
	    	if(rs_arr->pRS_RecvPtr<(unsigned int *)Rec_Bloc_Begin || rs_arr->pRS_RecvPtr>(unsigned int *)Rec_Bloc_End)
			{
	    		rs_arr->pRS_RecvPtr = (unsigned int *)Rec_Bloc_Begin; // На программу надейса, а сам не плошай
	    		rs_arr->pRecvPtr = (unsigned int *)Rec_Bloc_Begin; // На программу надейса, а сам не плошай
			}		    	
			if(rs_arr->RS_PrevCmd != CMD_INITLOAD) continue;	// Мы здесь оказались по какой-то чудовищной ошибке
				
			if(rs_arr->RS_DataReady)			// Если данные в основном цикле не забраны,
			{							// то пропускаем следующую посылку
				rs_arr->RS_FlagSkiping = true;	// Игнорируем до следующего заголовка
//				led1_off();
				continue;
			}
			RS_BytePtr = rs_arr->RS_RecvLen++ % 2;
			if(RS_BytePtr)	*rs_arr->pRS_RecvPtr++ |= Rc;	// Получили слово
			else			*rs_arr->pRS_RecvPtr   = Rc<<8;

			if(rs_arr->RS_Length <= rs_arr->RS_RecvLen)	// Конец посылки
			{
				rs_arr->RS_PrevCmd = rs_arr->RS_Header[1] = CMD_LOAD;
				RS_SetBitMode(rs_arr,9);		// Получили все данные перестроились в 9-бит дла RS485?
				rs_arr->RS_FlagSkiping = true;	// Игнорируем до следующего заголовка
				rs_arr->RS_DataReady = true;	// Флаг в основной цикл - данные получены
//				led1_off();
}	}	}	}   				

/** Обработчик прерываний UART - послано	*/
void RS_TX_Handler(RS_DATA *rs_arr)
{
  char RS_BytePtr;
//  unsigned int i;

	if(rs_arr->RS_SendBlockMode == BM_CHAR32)
	{
		if(++rs_arr->RS_SendLen >= rs_arr->RS_SLength)
		{
			enableUARTInt(rs_arr);	/* Запрещаем прерываниа по передаче */
		}
		SCI_send(rs_arr,*(rs_arr->pRS_SendPtr++));
	
   		if(rs_arr->RS_SendLen >= rs_arr->RS_SLength)
		{
			RS_Wait4OK(rs_arr);
//	        for	(i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){}	/* Пауза дла PC */
                    
			RS_SetBitMode(rs_arr,9); 	/* Передали все перестроились в 9-бит дла RS485?*/
			RS_Line_to_receive(rs_arr);			/* режим приема RS485 */ 
					
			rs_arr->flag_TIMEOUT_to_Send=false;		/* сбросили флаг ожиданиа таймаута */
		}
	}
	else /* BM_PACKED */
	{

		RS_BytePtr = (rs_arr->RS_SendLen++) % 2;
	    if(rs_arr->RS_SendLen >= rs_arr->RS_SLength)
		{
				enableUARTInt(rs_arr);		/* Запрещаем прерываниа по передаче */
	    }
		if(RS_BytePtr)	SCI_send(rs_arr, LOBYTE( *(rs_arr->pRS_SendPtr++) ));
		else			SCI_send(rs_arr, HIBYTE( *rs_arr->pRS_SendPtr ));

		if(rs_arr->RS_SendLen >= rs_arr->RS_SLength)
		{
			RS_Wait4OK(rs_arr);
//			for	(i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){}	/* Пауза дла PC */    	
//					RS_SetBitMode(rs_arr,9);	/* Передали все перестроились в 9-бит дла RS485?*/
//					RS_Line_to_receive();			/* режим приема RS485 */
					
		}				
	}                                               

	PieCtrlRegs.PIEACK.bit.ACK9 |= 1;
//	rs_arr->SciRegs->SCIFFTX.bit.TXINTCLR=1;	//	Clear INT flag
}

/** Инициализациа массива длин команд */
void setup_arr_cmd_length()
{
  int i;
    
	for (i=0;i<70;i++)	RS_Len[i]=i;

	RS_Len[CMD_LOAD]   = 12;
	RS_Len[CMD_UPLOAD] = 12;
	RS_Len[CMD_RUN] = 8;
	RS_Len[CMD_XFLASH] = 9;
	RS_Len[CMD_TFLASH] = 16;
	RS_Len[CMD_PEEK] = 8;
	RS_Len[CMD_POKE] = 12;
	RS_Len[CMD_INITLOAD] = 12;
	RS_Len[CMD_INIT] = 5;     
	RS_Len[CMD_VECTOR] = size_cmd15-2; //sizeof(CMD_TO_TMS)-2;
	RS_Len[CMD_STD] = size_cmd15-1; //sizeof(CMD_TO_TMS)-1;  
	RS_Len[CMD_IMPULSE] = 8;
	RS_Len[CMD_MODBUS_3] = 8;
	RS_Len[CMD_MODBUS_6] = 8;
	RS_Len[CMD_MODBUS_16] = 13;
	RS_Len[CMD_MODBUS_15] = 27;
	RS_Len[CMD_EXTEND] = 18;
}
                
/** Настройка режима приема/передачи */                                
void RS_SetBitMode(RS_DATA *rs_arr,int n)
{   
	if(n == 8)       
	{
		RS_SetLineMode(rs_arr,8,'N',1);        /* режим линии */
		rs_arr->RS_Flag9bit=0;
	}
	if(n == 9)
	{
		RS_SetLineMode(rs_arr,8,'N',1);        /* режим линии */
		rs_arr->RS_Flag9bit=1;
}	}
 
/** Посылка блока байтов. 
 Посылает массива 32-битных целых чисел старшие биты должны быть 0.
 @precondition Работа ф-ции зависит от макро RS_TRANSMIT_INTR
 @param buf адрес массива
 @param len количество байт 
 @see RS_BSend, RS_TRANSMIT_INTR */
int RS_Send(RS_DATA *rs_arr,unsigned int *pBuf,unsigned long len)
{
  unsigned int i;
	for	(i=0; i <= 30000; i++){}	/* Пауза дла PC */

	RS_Line_to_send(rs_arr);          /* режим передачи RS485 */ 

	for	(i=0; i <= 10000; i++){}	/* Пауза дла PC */
		
	rs_arr->RS_SLength = len; 			/* Настраиваем переменные */
	rs_arr->pRS_SendPtr = pBuf + 1;

	rs_arr->RS_SendBlockMode = BM_CHAR32;

	RS_Wait4OK(rs_arr);                   /* Дожидаемса ухода */
	RS_SetBitMode(rs_arr,8);               /* Остальные в 8-бит режиме */	
	
	rs_arr->RS_SendLen = 1;						/* Два байта уже передали */
	if(len > 1)
	{
		enableUARTIntW(rs_arr);				/* Разрешаем прерываниа по передаче */
    	SCI_send(rs_arr, *pBuf);	// Передаем второй байт по прерыванию
	}
    else
    {
        SCI_send(rs_arr, *pBuf);	// Передаем второй байт по прерыванию
    	RS_Wait4OK(rs_arr);                   /* Дожидаемса ухода без прерываниа */
    	for	(i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){}	/* Пауза дла PC */    	
    	RS_SetBitMode(rs_arr,9);               /* Обратно в 9-бит режим */
    	RS_Line_to_receive(rs_arr);			/* режим приема RS485 */ 
    }
    return 0;
}

// Посылка блока упакованных байтов
int RS_BSend(RS_DATA *rs_arr,unsigned int *pBuf, unsigned long len)
{

	RS_Line_to_send(rs_arr); 		// режим передачи RS485

	rs_arr->RS_SLength = len; 		// Настраиваем переменные
	rs_arr->pRS_SendPtr = pBuf;                                     
	rs_arr->RS_SendBlockMode = BM_PACKED;

	RS_Wait4OK(rs_arr);			// Ожидаем очистки и ухода последнего байта
	RS_SetBitMode(rs_arr,8);         	/* Остальные в 8-бит режиме */

	rs_arr->RS_SendLen = 1;			// Один байт уже передали

	enableUARTIntW(rs_arr);				/* Разрешаем прерываниа по передаче */

	SCI_send(rs_arr,HIBYTE(*pBuf));// Передаем первый байт

	return 0;
}

/** Устанавливает скорость обмена.
 @param speed скорость RS в бод */
/** Устанавливает скорость обмена.
 @param speed скорость RS в бод */
void RS_SetLineSpeed(RS_DATA *rs_arr,unsigned long speed)
{
  long SciBaud;

	SciBaud = LSPCLK/(speed*8.0);

//	if((SciBaud-(unsigned int)SciBaud)>0.5) SciBaud++;

	rs_arr->SciRegs->SCIHBAUD    = HIBYTE((int)SciBaud);
	rs_arr->SciRegs->SCILBAUD    = LOBYTE((int)SciBaud);
}


/** Инициализациа последовательного порта */
void create_uart_vars(char size_cmd15_set)
{
  size_cmd15=size_cmd15_set;
  rs_a.commnumber=COM_1;
  rs_b.commnumber=COM_2;
}



/** Инициализациа последовательного порта */

void setup_uart(char commnumber, unsigned long speed_baud)
{ 
  volatile struct SCI_REGS *SciRegs;
  RS_DATA *rs_arr;

	if(commnumber==COM_1)
	{
		rs_a.SciRegs = &SciaRegs;
		rs_arr = &rs_a;

		EALLOW;

		GpioCtrlRegs.GPAMUX2.bit.GPIO29 = 1;	//	SCITXDA - SCI-A transmit(O)
		GpioCtrlRegs.GPAMUX2.bit.GPIO28 = 1;	//	SCIRXDA - SCI-A receive	(I)
		
		PieVectTable.SCIRXINTA = &RSA_RX_Handler;
		PieVectTable.SCITXINTA = &RSA_TX_Handler;
		PieCtrlRegs.PIEIER9.bit.INTx1=1;     // PIE Group 9, INT1
		PieCtrlRegs.PIEIER9.bit.INTx2=1;     // PIE Group 9, INT2
		IER |= M_INT9;	// Enable CPU INT
		EDIS;
	}

	if(commnumber==COM_2)
	{
		rs_b.SciRegs = &ScibRegs;
		rs_arr = &rs_b;

		EALLOW;

		GpioCtrlRegs.GPAMUX1.bit.GPIO14 = 2;	//	SCITXDB - SCI-B transmit(O)
		GpioCtrlRegs.GPAMUX1.bit.GPIO15 = 2;	//	SCIRXDB - SCI-B receive	(I)

		GpioCtrlRegs.GPBMUX1.bit.GPIO34 = 0;	//	GPIO 34 - general purpose I/O 34 (default)
		GpioCtrlRegs.GPBDIR.bit.GPIO34	= 1;	//	Configures the GPIO pin as an output

		PieVectTable.SCIRXINTB = &RSB_RX_Handler;
		PieVectTable.SCITXINTB = &RSB_TX_Handler;

		PieCtrlRegs.PIEIER9.bit.INTx3=1;     // PIE Group 9, INT3
		PieCtrlRegs.PIEIER9.bit.INTx4=1;     // PIE Group 9, INT4
		IER |= M_INT9;	// Enable CPU INT
		EDIS;
	}

	rs_arr->commnumber = commnumber;
	SciRegs = rs_arr->SciRegs;
	RS_SetLineMode(rs_arr,8,'N',1);
    
//	enable TX, RX, internal SCICLK, 
//	Disable RX ERR, SLEEP, TXWAKE

	SciRegs->SCIFFCT.bit.ABDCLR=1;
	SciRegs->SCIFFCT.bit.CDC=0;

	SciRegs->SCICTL1.bit.RXERRINTENA=0;
	SciRegs->SCICTL1.bit.SWRESET=0;
	SciRegs->SCICTL1.bit.TXWAKE=0;
	SciRegs->SCICTL1.bit.SLEEP=0;
	SciRegs->SCICTL1.bit.TXENA=1;
	SciRegs->SCICTL1.bit.RXENA=1;

	SciRegs->SCIFFTX.bit.SCIFFENA=0;		//	fifo off
	SciRegs->SCIFFRX.bit.RXFFIL=1;			//	Длина наименьшей команды

	setup_arr_cmd_length();
	RS_SetLineSpeed(rs_arr,speed_baud);		//	скорость линии
	RS_Line_to_receive(rs_arr);				//	режим приема RS485
	enableUARTInt(rs_arr);					//	разрешение прерываний UART
	RS_SetBitMode(rs_arr,9);
	rs_arr->RS_PrevCmd = 0;					//	не было никаких команд
	rs_arr->flag_TIMEOUT_to_Send = 0;
	rs_arr->flag_LEADING = 0;

	SciRegs->SCIFFRX.bit.RXFFINTCLR=1;		//	Clear INT flag
	SciRegs->SCICTL1.bit.SWRESET=1;			//	Relinquish SCI from Reset
}

/** Настройка режима линии.
 @param bit количество бит данных
 @param parity режим четности (N,O,E,M,S)
 @param stop количество стоповых бит */
void RS_SetLineMode(RS_DATA *rs_arr, int bit, char parity, int stop)
{
    volatile struct SCI_REGS *SciRegs;
/*
SCICCR - SCI Communication Control Register 
Bit	Bit Name			Designation		Functions
2-0	SCI CHAR2-0 		SCICHAR			Select the character (data) length (one to eight bits).
3	ADDR/IDLE MODE		ADDRIDLE_MODE	The idle-line mode (0) is usually used for normal communications because the address-bit mode adds an extra bit to the frame. The idle-line mode does not add this extra bit and is compatible with RS-232 type communications.
4	LOOP BACK ENABLE	LOOPBKENA		This bit enables (1) the Loop Back test mode where the Tx pin is internally connected to the Rx pin.
5	PARITY ENABLE		PARITYENA		Enables the parity function if set to 1, or disables the parity function if cleared to 0.
6	EVEN/ODD PARITY		PARITY			If parity is enabled, selects odd parity if cleared to 0 or even parity if set to 1.
7	STOP BITS			STOPBITS		Determines the number of stop bits transmitted-one stop bit if cleared to 0 or two stop bits if set to 1.
*/	

	SciRegs = rs_arr->SciRegs;

	if(bit>0 && bit<9)	SciRegs->SCICCR.bit.SCICHAR = bit-1;

	switch(parity)
	{
		case 'N':	SciRegs->SCICCR.bit.PARITYENA =	0;
					break;
		case 'O':   SciRegs->SCICCR.bit.PARITYENA =	1;
					SciRegs->SCICCR.bit.PARITY =	0;
					break;
		case 'E':	SciRegs->SCICCR.bit.PARITYENA =	1;
					SciRegs->SCICCR.bit.PARITY =	1;
					break;
	}

	if (stop==1)		SciRegs->SCICCR.bit.STOPBITS = 0;
	if (stop==2)		SciRegs->SCICCR.bit.STOPBITS = 1;

	SciRegs->SCICCR.bit.LOOPBKENA =		0;  //0
	SciRegs->SCICCR.bit.ADDRIDLE_MODE =	0;
}

void clear_timer_rs_live(RS_DATA *rs_arr)
{
   rs_arr->time_wait_rs_out=0;
}

/* проверка на живучесть RS */
void test_rs_live(RS_DATA *rs_arr)
{  
/*	if (rs_arr->time_wait_rs_out < RS_TIME_OUT)
	rs_arr->time_wait_rs_out++;
	else
	{
		rs_arr->time_wait_rs_out=0;
		RS_Line_to_receive(rs_arr);	// режим приема RS485
		RS_SetBitMode(rs_arr,9);
}*/	}
