/***************************************************************************/
//               Общие функции для режимов BasicCAN и PeliCAN
//                                                       v1.0
//                                 ЭЛКУС, 2002г.
/***************************************************************************/
#include "can200.h"

unsigned int far BASE; // Базовый адрес канала платы
unsigned char far ResetRequest(unsigned char);
unsigned char far TestResetRequest(void);


void far chBaseAddress(unsigned int far newBaseAddress)
{
 BASE=newBaseAddress;
 return;
}


unsigned char far SetWorkMode(unsigned char newWorkMode)
{
 if (newWorkMode!=BasicCAN && newWorkMode!=PeliCAN) return 1;
 if (TestResetRequest()==NormalMode)
  {                          // если канал находится в рабочем режиме
	ResetRequest(ResetMode); // переводим его в режим сброса
	while(TestResetRequest()!=ResetMode);
  }
							 // меняем режим работы на заданный
  outportb(BASE+0x1F,( (inportb(BASE+0x1F)&0x7F)+(newWorkMode<<7) ) );
  ResetRequest(NormalMode);  // переводим канал в рабочий режим
  return 0;
}

unsigned char far GetWorkMode(void)
{
   if( (inportb(BASE+0x1F)&0x80)==0) return BasicCAN;
	else return PeliCAN;
}


void far HardReset(void)
{
 outportb(BASE+30,1);
 return;
}

void far SetDriverMode(unsigned char Mode)
{
 if(TestResetRequest()!=1)     /* если канал находится в рабочем режиме */
  {                            /* переводим его в режим сброса          */
	ResetRequest(ResetMode);
	while(TestResetRequest()!=ResetMode);
  }
 outportb(BASE+8,Mode);        /* установка режима вых. формирователя */
 ResetRequest(NormalMode);     /* перевод канала в рабочий режим      */
 return;
}

unsigned char far SetCANSpeed(unsigned int CANSpeed)
{
 if(TestResetRequest()!=1)     /* если канал находится в рабочем режиме */
  {                            /* переводим его в режим сброса          */
	ResetRequest(ResetMode);
	while(TestResetRequest()!=ResetMode);
  }
  switch(CANSpeed)
  {
	case 1000: outportb(BASE+6,0x40); outportb(BASE+7,0x23); break;
	case 800:  outportb(BASE+6,0x40); outportb(BASE+7,0x25); break;
	case 500:  outportb(BASE+6,0x40); outportb(BASE+7,0x2B); break;
	case 250:  outportb(BASE+6,0x41); outportb(BASE+7,0x2B); break;
	case 125:  outportb(BASE+6,0x43); outportb(BASE+7,0x2B); break;
	case 50:   outportb(BASE+6,0x49); outportb(BASE+7,0x2B); break;
	case 20:   outportb(BASE+6,0x58); outportb(BASE+7,0x2B); break;
	case 10:   outportb(BASE+6,0x71); outportb(BASE+7,0x2B); break;
	default:   ResetRequest(NormalMode); return 1;
  }

   ResetRequest(NormalMode);
   return 0;
}

unsigned char far GetStatus(void)
{
  return inportb(BASE+0x02);
}

unsigned char far GetInterruptSource(void)
{
  return inportb(BASE+0x03);
}

void far SetInterruptSource(unsigned char mask)
{
  if(GetWorkMode()==BasicCAN)   // если канал находится в режиме BasicCAN
   {
	 mask&=0x0F;                // оставляем только младшие четыре бита
	 if(TestResetRequest()!=1)  // если канал находится в рабочем режиме
	  {                         // переводим его в режим сброса
		ResetRequest(ResetMode);
		while(TestResetRequest()!=ResetMode);
	  }
	 outportb(BASE,(mask<<1) ); // запись маски прерывания
   }
  else          				// если канал находится в режиме PeliCAN
	 outportb(BASE+4,mask);     // запись маски прерывания

  ResetRequest(NormalMode);     // перевод канала в рабочий режим
  return;
}


unsigned char far SetTxBuffer(struct Buffer far *TxBuffer)
{
	unsigned char temp;
	// проверки на корректность полей структуры
	if(TxBuffer->FF!=0 && TxBuffer->FF!=1)            return 2;
	if(TxBuffer->FF==0 && TxBuffer->sID>0x7FF)        return 2;
	if(TxBuffer->FF==1 && TxBuffer->extID>0x1FFFFFFF) return 2;
	if(TxBuffer->RTR!=0 && TxBuffer->RTR!=1)          return 2;
	if(TxBuffer->DLC>8)                              return 2;
	// проверка на доступность буфера передачи
	if( (inportb(BASE+0x02)&0x04)==0 ) return 1;
	// в режиме BasicCAN можно мередавать только стандартные кадры
	if( GetWorkMode()==BasicCAN && TxBuffer->FF==1 )  return 3;

  ResetRequest(NormalMode);

  if(GetWorkMode()==BasicCAN)   // если канал находится в режиме BasicCAN
   {
	outportb(BASE+10,(TxBuffer->sID>>3));
	temp=((TxBuffer->sID&0x07)<<5)+(TxBuffer->RTR<<4)+TxBuffer->DLC;
	outportb(BASE+11,temp);
	for(temp=0;temp<TxBuffer->DLC;temp++)
	 outportb(BASE+12+temp,TxBuffer->DataByte[temp]);
   }
  else
   {    // для режима PeliCAN
	 if(TxBuffer->FF==0)
	  {
		   // для стандартного кадра
		 temp=(TxBuffer->RTR<<6)+TxBuffer->DLC;
		 outportb(BASE+16,temp);
		 outportb(BASE+17,(TxBuffer->sID>>3));
		 outportb(BASE+18,(((TxBuffer->sID)&0x07)<<5));
		 for(temp=0;temp<TxBuffer->DLC;temp++)
		 outportb(BASE+19+temp,TxBuffer->DataByte[temp]);
	  }
	 else
	  {   // для расширенного кадра
		 temp=0x80+(TxBuffer->RTR<<6)+TxBuffer->DLC;
		 outportb(BASE+16,temp);
		 outportb(BASE+17,((TxBuffer->extID<<3)>>24) );
		 outportb(BASE+18,((TxBuffer->extID<<3)>>16) );
		 outportb(BASE+19,((TxBuffer->extID<<3)>>8) );
		 outportb(BASE+20,(TxBuffer->extID<<3));

		 for(temp=0;temp<TxBuffer->DLC;temp++)
		 outportb(BASE+21+temp,TxBuffer->DataByte[temp]);
	  }
	}
  return 0;
}

struct Buffer * far GetRxBuffer(void)
{
  static struct Buffer RxBuffer;
  unsigned char temp;

  if(GetWorkMode()==BasicCAN)
   {  // для режима BasicCAN
	  RxBuffer.FF=0; // в режиме BasicCAN идет обмен только станд. кадрами
	  temp=inportb(BASE+21);
	  RxBuffer.sID=(inportb(BASE+20)<<3)+(temp>>5);
	  RxBuffer.RTR=((temp>>4)&0x01);
	  RxBuffer.DLC=(temp&0x0F);
	  for(temp=0;temp<RxBuffer.DLC && temp<8;temp++)
	   RxBuffer.DataByte[temp]=inportb(BASE+22+temp);
   }
  else
   {       // для режима PeliCAN
	 if( (inportb(BASE+16)&0x80)==0)
	  {
		   // для стандартного кадра
		 RxBuffer.FF=0;
		 temp=inportb(BASE+16);
		 RxBuffer.RTR=((temp>>6)&0x01);
		 RxBuffer.DLC=(temp&0x0F);
		 RxBuffer.sID=(inportb(BASE+17)<<3)+((inportb(BASE+18)>>5)&0x07);
		 for(temp=0;temp<RxBuffer.DLC && temp<8;temp++)
		  RxBuffer.DataByte[temp]=inportb(BASE+19+temp);
	  }
	 else
	  {   // для расширенного кадра
		 RxBuffer.FF=1;
		 temp=inportb(BASE+16);
		 RxBuffer.RTR=((temp>>6)&0x01);
		 RxBuffer.DLC=(temp&0x0F);
		 RxBuffer.extID=( ((long)inportb(BASE+17))<<21);
		 RxBuffer.extID+=( ((long)inportb(BASE+18))<<13);
		 RxBuffer.extID+=( ((long)inportb(BASE+19))<<5);
		 RxBuffer.extID+=( ((long)inportb(BASE+20))>>3);

		 for(temp=0;temp<RxBuffer.DLC && temp<8;temp++)
		  RxBuffer.DataByte[temp]=inportb(BASE+21+temp);
	  }
   }

  return &RxBuffer;
}


void far SetCommand(unsigned char Command)
{
  outportb(BASE+1,Command);
  return;
}

