#include "xparameters.h"
#include "xbasic_types.h"
#include "xio.h"
#include "types.h"
#include "pcmu_l.h"
#include "phone.h"

static BYTE incr = 0;
BYTE packet[260];
unsigned int initPacketReceive(void);


#define BIAS 0x84   /* define the add-in bias for 16 bit samples */
#define CLIP 32635
short pkt_cntr = 0;
BYTE enable = 0;

void audio_int_handler(void * poop){  
  unsigned short linear_data;
  unsigned int ulaw;
  unsigned char packet_data;
  int16 sample_to_write;
  if(!enable){
    return;
  }else{

    //linear_data = XIo_In32(0xFEFE0000);
    //ulaw = l16_to_pcmu(linear_data);

    packet_data = packet[54 + pkt_cntr];
    //if( (pkt_cntr && 0x8) != 0 ){
    // print("\r\n");
    // putnum(pkt_cntr);
    // print(" ");
    //sample_to_write = pcmu_to_l16(packet_data);
    //putnum(sample_to_write);
    //}
    if(pkt_cntr < 159){
      pkt_cntr++;
    }else{
      enable = 0;
    }
    
    sample_to_write = (short) (pcmu_to_l16(packet_data) & 0xFFFF);
    
    XIo_Out32(0xFEFE2222,sample_to_write);
  }
}

void sendSRAMPacket(int start, int end) {
  int length = end-start;
  unsigned int i,j,k,addr,word;
  
  outnic(CR,0x22);
  
  
  //arp 596, 596+60

  outnic(RSAR0, 0); // set DMA starting address
  outnic(RSAR1, TXSTART);

  outnic(ISR, 0xFF); // clear ISR

  

  outnic(RBCR0, length*2); // set Remote DMA Byte Count
  outnic(RBCR1, 0);
  outnic(TBCR0, (length&0xff)); // set Transmit Byte Count
  outnic(TBCR1, (length>>8));


  outnic(CMDR, 0x12); // start the DMA write

//    print("\r\COPYING SRAM PACKET VALUES\r\n\r\n");

  for(i=start; i<end; i++){
    addr = 0xC00000 + (i<<1);
    j = XIo_In8(addr);
    i++;
    addr = 0xC00000 + ((i)<<1);
    k = XIo_In8(addr);

    word = (j) | (k<<8);
    outnic(DATAPORT, word);
    
  }


  if(innic(ISR)&0x40){
    print("OK\r\n");
  }
  else{
    print("Error! bad DMA); // . Restart the board\r\n\r\n");    
    //return;
  }
  
    outnic(TPSR, TXSTART); // set Transmit Page Start Register
    outnic(CMDR, 0x24); // start transmission


  
  j=1000;
  while(j-->0 && !(innic(ISR)&0x02));
  if(!j){
    return 1;
  }

  outnic(ISR,0xFF);



  outnic(CR,0x22);
}


#define  nextblock_ptr        0x01
static unsigned char nextPage;
static unsigned int currentRetrieveAddress;


int main()
{
  unsigned int i,j;
  unsigned char recvstatus, length;
//  BYTE packet[15];

  WORD word;
  int k,addr;
    
  //-----REGISTER INTERRUPT:
  microblaze_register_handler(audio_int_handler, (void *)0);


  //microblaze_enable_icache();

//  print("\r\n\r\n***** Ethernet Diagnostic *****\r\n\r\n");
//  diag();
//  print("\r\n\r\n***** Ethernet Configuration *****\r\n\r\n");
  
  // reset the NIC card
  if(!init_etherne()){
    print("Ethernet NIC not detected");
//        return;
  }
//  print("Done!\r\n");



  print("Writing headers to memory...");

/*
for (i=0; i<3; i++) {


// ------GRATUITOUS ARP REQUEST ------
sendSRAMPacket(596, 596+60);


  delay(15);

}

*/

// --------------SIP INVITE -----------------
sendSRAMPacket(0, 596);
  
//  delay(20);

// -----------SIP ACK ------------
//sendSRAMPacket(596+60, 404+596+60);







// RECEIVE


  microblaze_enable_interrupts();
while (1) {

//init_etherne();

//  print("receiving\r\n");

//  outnic(ISR, 0x00);
//  outnic(ISR, 0xff);


 
  recvstatus=0;


  //<<7, >>7 perform a modulo 2 (get last bit)
  while((recvstatus%2)!=1 || recvstatus==4) {  // || recvstatus == 9) {
//    delay(5);
    recvstatus =  innic(ISR);
    putnum(recvstatus);
    j = innic(RCR);
    print(" ");
    putnum(j);
    print("\r\n");
  }
  

  
  length = initPacketReceive();
  pkt_cntr = 0;
  enable = 1;

  if (length == 5) break;

  outnic(ISR, 0x40);
  outnic(CR, (RD2|START));

//delay(10);
recvstatus=0;


//    putnum(length);
//    print("\r\n\r\n");






}

    return 0;




}




// diagnostic that tests nic functionality
void diag(){
  int i;
/*  
  print("         Command Register Page Switching Test\r\n");
  print("Switching to page 1\r\n");
  outnic(CMDR, 0x61);

  print("Writing to and reading from 0x0D (value should be 0x4e): ");
  outnic(0x0D*2,0x4e);
  putnum(innic(0x0D*2));
  print("\r\n");

  print("Switching to page 0\r\n");
  outnic(CMDR, 0x21);

  print("Reading from reg offset 0x0D: ");
  putnum(innic(0x0D*2));
  print("\r\n");

  print("Switching to page 1\r\n");
  outnic(CMDR, 0x61);
  print("Reading from reg offset 0x0D (should be 0x4e): ");
  putnum(innic(0x0D*2));
  print("\r\n\r\n");

  print("         Default Value Test\r\n");
  print("Switching to page 0\r\n");
  outnic(CMDR,0x21);
  print("Reading from 0x16 (value should be 0x15): ");
  putnum(innic(0x16*2));
  print("\r\n");
  print("Reading from 0x12 (value should be 0x0c): ");
  putnum(innic(0x12*2));
  print("\r\n");
  print("Reading from 0x13 (value should be 0x12): ");
  putnum(innic(0x13*2));
  print("\r\n");
*/
}

int init_etherne()
{
  outnic(NE_RESET, innic(NE_RESET));  // Do reset
  print("Reset sent...\n\r");
  //delay(2);
  if ((innic(ISR) & 0x80) == 0)       // Report if failed
  {
//    print("Ethernet card failed to reset! Read (should be 0x80)\r\n");
//   putnum(innic(ISR));
    print("failed\r\n");
    return 0;
  }
  else
  {

//    print("Ethernet card reset successful!\r\n");
    resetnic(); // Reset Ethernet card,
//    print("Ethernet card intialization complete!\r\n");
//    diag();
  }

  return 1;
}








void resetnic(){
  int i, count;

  outnic(CMDR, RD2|STOP);  // Abort and DMA and stop the NIC
  delay(10);

  outnic(DCR, DCRVAL);   // Set word-wide access

  outnic(RBCR0, 0x00); // Clear the count regs
  outnic(RBCR1, 0x00);

  outnic(IMR, 0x00);   // Mask completion irq
  outnic(ISR, 0xFF);   // clear interrupt status register

  outnic(RCR, 0x20);   // 0x20  Set to monitor mode
//  outnic(RCR, 0x6f);
  
  //outnic(TCR, 0x02);  // put nic in normal operation

  // Set Rx start, Rx stop, Boundary and TX start regs
  outnic(BNRY, RXSTART);
  outnic(PSTART, RXSTART);
  outnic(PSTOP, RXSTOP);
  nextPage = RXSTART+1;
    
  outnic(CMDR, (PS0|RD2|STOP));
  //write mac
  outnic(PAR0+0, 0x00);
  outnic(PAR0+1, 0x08);
  outnic(PAR0+2, 0x02);
  outnic(PAR0+3, 0x62);
  outnic(PAR0+4, 0x30);
  outnic(PAR0+5, 0x5d); //laptop = 5d

  outnic(CURR, RXSTART+1);
  
  
  outnic(CMDR, (RD2|START));
  outnic(RCR, 0x40+0x10+8+4+2+1);
  
  //full duplex
  outnic(TCR, 0x80);

  outnic(TPSR, TXSTART);
  
  
  outnic(CMDR, (RD2|STOP));

  outnic(DCR, DCRVAL);   // Set word-wide access

  outnic(CMDR, (RD2|START));
  
  
  outnic(ISR, 0xFF);   // clear interrupt status register
  outnic(IMR, 0x01);   // Mask completion irq

  outnic(TCR, 0x80);


  // put nic in start mode
  outnic(CMDR, 0x22); // start nic
  outnic(TCR, 0x80);  // put nic in normal operation
  
  
}


unsigned int initPacketReceive(void)
{
//	unsigned char writePagePtr;
//	unsigned char readPagePtr;
//	unsigned char bnryPagePtr;
	unsigned char i, j;
	unsigned int k;
	int length;
	
	unsigned char pageheader[4];
	
	
	unsigned int rxlen, word;
	
	
	// read CURR from page 1
	// see below, unnecessary
	//outnic(CR,(PS0|RD2|START));
	//writePagePtr = innic(CURR);


	// read the boundary register from page 0
	//outnic(CR,(RD2|START));
	//bnryPagePtr = innic(BNRY);
	// first packet is at page bnryPagePtr+1
	// raj - but we nextPage global, so no need to retrieve bnrypage

	// just use nextPage everywhere and save space
	//readPagePtr = nextPage;
	
	//if(readPagePtr >= RXSTOP) readPagePtr = RXSTART;

	// return if there is no packet in the buffer
	// but we do this check elsewhere, so screw it
	//if( readPagePtr == writePagePtr )
	//{
	//	return 0;
	//}
	
	// clear the packet received interrupt flag
	outnic(ISR, 0x01);
	
	// if the boundary pointer is invalid,
	// reset the contents of the buffer and exit


	if( (nextPage < RXSTART) || (nextPage >= RXSTOP) )
	{
		outnic(BNRY, RXSTART);
		outnic(CR, (PS0|RD2|START));
		outnic(CURR, RXSTART+1);
		outnic(CR, (RD2|START));
		return 0;
	}



//	for (j=readPagePtr; j<readPagePtr+10; j++) {
//	j = readPagePtr;

//not sure if we need the delay
	//delay(5);


//	print("\r\n\r\ntesting: ");
//	putnum(j);
//	print("\r\n");

	// initiate DMA to transfer the RTL8019 packet header
	outnic(RBCR0, 4);
	outnic(RBCR1, 0);
	outnic(RSAR0, 0);
	outnic(RSAR1, nextPage);   //readPagePtr);
	outnic(CR, (RD0|START));
	
	//print("\r\nPacket header:\r\n");
	
	for(i=0;i<4;i++) {
		j = innic(DATAPORT);
//		pageheader[i+1] = j;
		pageheader[i] = (unsigned char)j;
		
	}
	
	// end the DMA operation
    	outnic(CR, (RD2|START));
    	for(i = 0; i <= 20; i++)
        	if(innic(ISR) & 0x40)
            		break;
    	outnic(ISR, 0x40);
	
	
	//using wrong pageheader reader, length is in pageheader[1]
	//length = pageheader[1]-4;

	//trying w/ correct - 2?
	length = pageheader[1]-4;
	 
	if (length > 255) length = 255;
	 
	currentRetrieveAddress = (nextPage<<8) + 2;
	  
	
	outnic(ISR, 0xFF); // clear ISR


	outnic(RBCR0, (unsigned char)length);
	outnic(RBCR1, (unsigned char)(length>>8));
	outnic(RSAR0, (unsigned char)currentRetrieveAddress);
	outnic(RSAR1, (unsigned char)(currentRetrieveAddress >> 8));
	outnic(CR, (RD0|START));
	
	for (i=0; i<length; i+=2) {
		k = innic(DATAPORT);
		packet[i] = (k); //lower 8
		packet[i+1] = (k>>8);//upper 8
		//switch i, i+1 for easy retransmission
	}


	outnic(CR, (RD2|START));
	for (i=0; i<=20; i++) {
		if (innic(ISR) & 0x40)
			break;
	}
	outnic(ISR, 0x40);
	
	
	
	
	
		

	//nextPage++ works, but not for longer/linked packets, me thinks
	//packets that extend beyond a single buffer page need
	//to obtain nextPage off the pageheader[]	
	/*
	nextPage++;
	
	bnryPagePtr = nextPage - 1;
	if(bnryPagePtr < RXSTART) {
		bnryPagePtr = RXSTOP-1;
		nextPage = RXSTOP;
	}
	
	outnic(BNRY, bnryPagePtr);		
	*/
	
//	nextPage++;
	i = nextPage;  //store temporarily b/c we try find linked buffers for a SIP 183
//	nextPage = pageheader[3];
	nextPage++;
	if (nextPage < RXSTART)
		nextPage = RXSTOP;
	outnic(BNRY, nextPage-1);



		
	//CHECK IF SIP OR RTP PACKET
	
	//RANDOM SIP NOTES:
	/* we don't need to get the RTP port out of the 183, we can just receive an
	   RTP packet, which is small, and find the source port; otherwise we'll have
	   to read extra linked buffer pages on the 183 ... screw that! */
	
	//DEBUGGING:
	/*
	print("page: ");
	putnum(nextPage);
	print("\r\n");
	for (i=42; i<48; i++) {
	putnum(packet[i]); //1 = 56
	print("\r\n");
	}
	return 0;
	*/
		

	/*
	//SIP
	if (packet[44] == 0x53) {
	
		j = (packet[52]-0x30)*100 + (packet[53]-0x30)*10 + (packet[54]-0x30);
		
		if (j==100) {
			print("SIP 100\r\n");
		} else if (j==183) {
			print("SIP 183\r\n");
			
			//the 183 packet is really long (includes SDP)...
			//going to have to find linked packets
			//the "TO" "TAG" should be in the 2nd buffer
			//and we need this tag from here b/c we need to send an ACK
			//response
	
			//i stores the old nextPage address that was overwritten above
			currentRetrieveAddress+=length; // += length; //((i+1)<<8) + 2;
			
			outnic(ISR, 0xFF); // clear ISR

			outnic(RBCR0, (unsigned char)200);
			outnic(RBCR1, (unsigned char)(200 >> 8));
			outnic(RSAR0, (unsigned char)currentRetrieveAddress);
			outnic(RSAR1, (unsigned char)(currentRetrieveAddress >> 8));
			outnic(CR, (RD0|START));
			
			//overwrite old packet to preserve space
			for (i=0; i<200; i+=2) {
				k = innic(DATAPORT);
				putnum(k);
				print("\r\n");
//				packet[i] = (k); //lower 8
//				packet[i+1] = (k>>8);//upper 8
			}
			
			return 5;
	
			outnic(CR, (RD2|START));
			
			for (i=0; i<=20; i++) {
				if (innic(ISR) & 0x40)
					break;
			}
			outnic(ISR, 0x40);

			
			
			i=0;
			for (j=0; j<length; j++) {
				//traverse looking for "To:"
				if (i!=1 && packet[j] == 0x0a && packet[j+1] == 0x54 && packet[j+2]==0x6f) {
					//"to" found at position a in packet
					i = 1;
					print("TO\r\n");
					
				} else if (i==1 && packet[j]==0x74 && packet[j+1]==0x61 && packet[j+2]==0x67) {
					print("TAG\r\n");
				}					
					
			}
			
			return 5;
			
			
			
		} //else {
		//	print("SIP?");
		//}


		return 4;		
	
	//RTP: 
	} else if (packet[41] == 0x80) {
		print("RTP!\r\n");	
	} else {
//		putnum(packet[44]);
		print("non\r\n");
	}
		
	//END CHECK
	*/
	return 0;
	
	
}


void delay(int mult){
  int i;
  int delay = 1000000*mult;
  for(i=0; i<delay; i++);
}

/*
* Convert 16 bit linear sample to 8-bit ulaw sample.
*/
/*
unsigned char l16_to_pcmu(short sample)
{
  static short exp_lut[256] = 
  {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
   4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
   5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
   5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
   6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
   6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
   6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
   6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
  int sign, exponent, mantissa;
  unsigned char ulawbyte;

  //Get the sample into sign-magnitude. 
  sign = (sample >> 8) & 0x80;      //set aside the sign 
  if (sign) sample = -sample;       // get magnitude 
  if (sample > CLIP) sample = CLIP; // clip the magnitude 

  // Convert from 16 bit linear to ulaw. 
  sample = sample + BIAS;
  exponent = exp_lut[( sample >> 7 ) & 0xFF];
  mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
  ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
#ifdef ZEROTRAP
  if (ulawbyte == 0) ulawbyte = 0x02;  // optional CCITT trap 
#endif

  return ulawbyte;
} 
*/
/* l16_to_pcmu */


/*
* Convert input of 8-bit ulaw to signed 16-bit linear sample.
*/
int16 pcmu_to_l16(unsigned int ulawbyte)
{
  static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
  int sign, exponent, mantissa, sample;

  ulawbyte = ~ ulawbyte;
  sign = ( ulawbyte & 0x80 );
  exponent = ( ulawbyte >> 4 ) & 0x07;
  mantissa = ulawbyte & 0x0F;
  sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
  if (sign) sample = -sample;

  return sample;
} /* pcmu_to_l16 */


