#define CS_ENC PIN_C1

#ifndef SPI_DO
   #define SPI_DO PIN_C7
   #define SPI_DI PIN_B0
   #define SPI_CLK PIN_B1
#endif

#if USE_SPI_HW
   #use spi(MASTER,CLK=SPI_CLK, DO=SPI_DO, DI=SPI_DI, BITS=8, MODE=0, FORCE_HW, stream=SPI_BUS)
#else
   #use spi(MASTER,CLK=SPI_CLK, DO=SPI_DO, DI=SPI_DI, BITS=8, MODE=0, FORCE_SW, MSB_FIRST, stream=SPI_BUS)
#endif


#define RX_BUF_START 0
#define RX_BUF_END   6499   
#define TX_BUF_START 6500

// MAC
#define MY_MAC1     0x00
#define MY_MAC2     0x04
#define MY_MAC3     0xA3
#define MY_MAC4     0x00
#define MY_MAC5     0x00
#define MY_MAC6     0x00

// IP
#define MY_IP1      10
#define MY_IP2      0
#define MY_IP3      0
#define MY_IP4      5

#define Type_ARP 0x806
#define Type_IP 0x800

char MAC_Dest[6];
long PacketStart, RdPt=0;


/* Brief 
*/
void ENC_WriteReg(char Reg, char Data){
   output_low(CS_ENC);
   spi_xfer(SPI_BUS,WCR|Reg);
   spi_xfer(SPI_BUS,Data);
   output_high(CS_ENC);
}

char ENC_ReadMAC(Char Reg){
char b;
   output_low(CS_ENC);
   spi_xfer(SPI_BUS,RCR|Reg);
   spi_xfer(SPI_BUS,0x00);
   b =spi_xfer(SPI_BUS);
   output_high(CS_ENC);
   return(b);
}

char ENC_ReadETH(char Reg){
char b;
   output_low(CS_ENC);
   spi_xfer(SPI_BUS,RCR|Reg);
   b =spi_xfer(SPI_BUS);
   output_high(CS_ENC);
   return(b);
}

void ENC_BFCReg(char Reg,char Data){
   output_low(CS_ENC);
   spi_xfer(SPI_BUS,BFC|Reg);
   spi_xfer(SPI_BUS,Data);
   output_high(CS_ENC);
}

void ENC_BFSReg(char Reg, char Data){
   output_low(CS_ENC);
   spi_xfer(SPI_BUS,BFS|Reg);
   spi_xfer(SPI_BUS,Data);
   output_high(CS_ENC);
}

void ENC_SetBank(char Bank){
     ENC_BFCReg(ECON1,0x02);
     ENC_BFSReg(ECON1,Bank);
}


void ENCPut(char Data){  
   output_low(CS_ENC);
   spi_xfer(SPI_BUS,WBM);
   spi_xfer(SPI_BUS,Data);
   output_high(CS_ENC);  
}

char ENCGet(void){  
char b;
   output_low(CS_ENC);
   spi_xfer(SPI_BUS,RBM);
   b=spi_xfer(SPI_BUS);
   output_high(CS_ENC);   
   return(b);
}

void ENC_SendReset(void){
   output_low(CS_ENC);
   spi_xfer(SPI_BUS,SRC);
   output_high(CS_ENC); 
}

void ENC_GetArray(char *Buffer, long Len){
   output_low(CS_ENC);
   spi_xfer(SPI_BUS,RBM);
   while(Len--){
      *Buffer++=spi_xfer(SPI_BUS);
   }
   output_high(CS_ENC);
}

void ENC_PutArray(char *Buffer,long Len){
   //bufSize += len;
   output_low(CS_ENC);
   spi_xfer(SPI_BUS,WBM);  
   while(Len--){
      spi_xfer(SPI_BUS,*Buffer++);
   }
   output_high(CS_ENC);
}


void ENC_WritePHY(char Reg, long Data){
   ENC_SetBank(2);
   ENC_WriteReg(MIREGADR,Reg);
   ENC_WriteReg(MIWRL,Data);
   ENC_WriteReg(MIWRH,(Data>>8));

   ENC_SetBank(3);
   while(bit_test(ENC_ReadMAC(MISTAT),0));
}

long ENC_ReadPHY(char Reg){
char h,l;
   ENC_SetBank(2);
   ENC_WriteReg(MIREGADR,Reg);
   ENC_WriteReg(MICMD, 0x01);   

   ENC_SetBank(3);
   while(bit_test(ENC_ReadMAC(MISTAT),0));

   ENC_SetBank(2);
   ENC_WriteReg(MICMD,0x00);   
   h=ENC_ReadMAC(MIRDH);
   l=ENC_ReadMAC(MIRDL);
   return(make16(h,l));
}

void Init_ENC(void){

   setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_XMIT_L_TO_H);
   delay_us(1);

   ENC_WritePHY(PHLCON,0b0000110110110000);     // configurazione LED  (per test)


   ENC_SetBank(0);
   ENC_WriteReg(ERXSTL,RX_BUF_START);   //
   ENC_WriteReg(ERXSTH,(RX_BUF_START>>8));  // Inicio Buffer de lectura
   ENC_WriteReg(ERXRDPTL,RX_BUF_END);     //
   ENC_WriteReg(ERXRDPTH,(RX_BUF_END>>8));    // Puntero de Buffer de Lectura
   ENC_WriteReg(ERXNDL,RX_BUF_END);     //
   ENC_WriteReg(ERXNDH,(RX_BUF_END>>8));    // Fin Buffer de Lectura
   ENC_WriteReg(ETXSTL,TX_BUF_START);   //
   ENC_WriteReg(ETXSTH,(TX_BUF_START>>8));  // Incicio de Buffer de Escritura.-


   ENC_SetBank(2);
   ENC_WriteReg(MACON1,0x0D);           // MARXEN  TXPAUS  RXPAUS
   ENC_WriteReg(MACON3,0x30);          // Half Duplex, Padding 60byte, CRC
   ENC_WriteReg(MAIPGL,0x12);             //
   ENC_WriteReg(MAIPGH,0x0C);             //
   ENC_WriteReg(MABBIPG,0x12);             // Inter-Packet Gap


   ENC_WriteReg(MAMXFLL,1500);   
   ENC_WriteReg(MAMXFLH,(1500>>8));


   ENC_SetBank(3);
   ENC_WriteReg(MAADR1, MY_MAC1);
   ENC_WriteReg(MAADR2, MY_MAC2);
   ENC_WriteReg(MAADR3, MY_MAC3);
   ENC_WriteReg(MAADR4, MY_MAC4);
   ENC_WriteReg(MAADR5, MY_MAC5);
   ENC_WriteReg(MAADR6, MY_MAC6);

   ENC_WritePHY(PHCON2,0b0000000100000000);  // disabilita il loopback
   ENC_WritePHY(PHCON1,0);                  // habilita il PHY

   ENC_SetBank(1);
   ENC_WriteReg(ERXFCON,0b10100001);             // imposta i filtri di ricezione
   ENC_BFSReg(ECON1,0b100);                     // abilita la ricezione

   ENC_WriteReg(EIR,0);
   ENC_WriteReg(EIE,0b11000000);               // abilita l'interrupt RX
}

void ENC_MACPutHeader(char *MacDest,long type){
char i;

   ENC_SetBank(0);
   ENC_WriteReg(EWRPTL,make8(TX_BUF_START,0));
   ENC_WriteReg(EWRPTL,make8(TX_BUF_START,1));
   output_low(CS_ENC);
   spi_xfer(SPI_BUS,WBM);
   spi_xfer(SPI_BUS,0x00);
   for(i=0;i<6;i++){
      spi_xfer(SPI_BUS,*MacDest++);
   }
   spi_xfer(SPI_BUS,MY_MAC1);
   spi_xfer(SPI_BUS,MY_MAC2);
   spi_xfer(SPI_BUS,MY_MAC3);
   spi_xfer(SPI_BUS,MY_MAC4);
   spi_xfer(SPI_BUS,MY_MAC5);
   spi_xfer(SPI_BUS,MY_MAC6);
   spi_xfer(SPI_BUS,make8(type,0));
   spi_xfer(SPI_BUS,make8(type,1));
   output_high(CS_ENC);
}

void ENC_MACSend(long BufferSize){

   ENC_SetBank(0);
   if((ENC_ReadETH(EIR))&0x02){
      ENC_BFSReg(ECON1, 0b10000000); //
      ENC_BFCReg(ECON1, 0b10000000); // reposiciona el TX
   }
   while((ENC_ReadETH(ECON1))&0x08){} // Se espera que este listo para enviar.-
   ENC_WriteReg(ETXNDL,make8(((long)(TX_BUF_START +BufferSize)),0));
   ENC_WriteReg(ETXNDH,make8(((long)(TX_BUF_START +BufferSize)),1));
   ENC_BFSReg(ECON1,0x08); // Se envia.-
}

void ENC_MACGetHeader(){
char Buffer[14];
long NewRdPt;

   PacketStart=RdPt;
   ENC_SetBank(0);
   ENC_WriteReg(ERDPTL,make8(RdPt,0));
   ENC_WriteReg(ERDPTH,make8(RdPt,1));
   ENC_GetArray(&Buffer[0],6); // Lee 6 bytes de control.-
   RdPt=make16(Buffer[1],Buffer[0]); // Apuntador a proximo paquete.-
   ENC_GetArray(&Buffer[0],14);
   printf("Se ha recibido paquete:\r\n");
   printf("Mac Destino:%X,%X,%X,%X,%X,%X\r\n",Buffer[0],Buffer[1],Buffer[2],Buffer[3],Buffer[4],Buffer[5]);
   printf("Mac Remitente:%X,%X,%X,%X,%X,%X\r\n",Buffer[6],Buffer[7],Buffer[8],Buffer[9],Buffer[10],Buffer[11]);
   printf("Type:0x%X\r\n\r\n",make16(Buffer[13],Buffer[12]));
   NewRdPt=RdPt-1;
   if ((NewRdPt > RX_BUF_END) || (NewRdPt < RX_BUF_START)){ NewRdPt = RX_BUF_END;}
   ENC_SetBank(0);
   ENC_BFSReg(ECON2, 0b01000000); // decremento EPKTCNT
   ENC_WriteReg(ERXRDPTL, make8(NewRdPt,0));
   ENC_WriteReg(ERXRDPTH, make8(NewRdPt,1)); // libera el espacio del buffer
}


/*void MACGetHeader(MAC_Header* header){
u8 buf[6];
packetStart = RdPt; // salva RdPt in packetStart
setBank(0);
writeReg(ERDPTL, LOW(RdPt)); //
writeReg(ERDPTH, HIGH(RdPt)); // ERDPT = RdPt
encGetArray(&buf[0], 6); // lee los 6 byte de control
RdPt = (u16)((u16)buf[0] | ((u16)buf[1] << 8 )); // apuntador próximo paquete
encGetArray((u8*)header, sizeof(MAC_Header)); // lee la intestación MAC
header->type = htons(header->type); // swappa el campo type
}*/
