/* | |
******************************************************************************** | |
* TERN, Inc. | |
* (c) Copyright 2005, http://www.tern.com | |
* | |
* MODIFIED BY RICHARD BARRY TO ADD SEMAPHORE FOR COMMUNICATION BETWEEN THE | |
* WIZnet ISR AND THE HTTP TASK. | |
* | |
* - Derived based on development version provided by Wiznet. | |
* | |
* Filename : socket.h | |
* Programmer(s): | |
* Created : 2002/06/20 | |
* Modified : | |
* 2002/09/27 : - Renaming | |
* INT_STATUS --> INT_REG | |
* STATUS(i) --> INT_STATUS(i) | |
* C_STATUS(i) --> SOCK_STATUS(i) | |
* 2003/11/06 : Ported for use with TERN controller. Note all byte access is at even addresses | |
* 2005/10/8 : Modified constants for easier initialization. | |
* | |
* Description : Header file of W3100A for TERN embedded controller | |
******************************************************************************** | |
*/ | |
/* | |
############################################################################### | |
File Include Section | |
############################################################################### | |
*/ | |
#include "i2chip_hw.h" | |
#include "socket.h" | |
#include "types.h" | |
#include <string.h> | |
#include <stdio.h> | |
#include <FreeRTOS.h> | |
#include <semphr.h> | |
#include <portasm.h> | |
/* | |
############################################################################### | |
Local Variable Declaration Section | |
############################################################################### | |
*/ | |
u_char I_STATUS[4]; // Store Interrupt Status according to channels | |
u_int Local_Port; // Designate Local Port | |
union un_l2cval SEQ_NUM; // Set initial sequence number | |
u_long SMASK[MAX_SOCK_NUM]; // Variable to store MASK of Tx in each channel, | |
// on setting dynamic memory size. | |
u_long RMASK[MAX_SOCK_NUM]; // Variable to store MASK of Rx in each channel, | |
// on setting dynamic memory size. | |
int SSIZE[MAX_SOCK_NUM]; // Maximun Tx memory size by each channel | |
int RSIZE[MAX_SOCK_NUM]; // Maximun Rx memory size by each channel | |
u_int SBUFBASEADDRESS[MAX_SOCK_NUM]; // Maximun Tx memory base address by each channel | |
u_int RBUFBASEADDRESS[MAX_SOCK_NUM]; // Maximun Rx memory base address by each channel | |
/* | |
############################################################################### | |
Function Implementation Section | |
############################################################################### | |
*/ | |
/* | |
******************************************************************************** | |
* Interrupt handling function of the W3100A | |
* | |
* Description : | |
* Stores the status information that each function waits for in the global variable I_STATUS | |
* for transfer. I_STATUS stores the interrupt status value for each channel. | |
* Arguments : None | |
* Returns : None | |
* Note : Internal Function | |
******************************************************************************** | |
*/ | |
portBASE_TYPE prvProcessISR( void ) | |
{ | |
unsigned char status; | |
extern SemaphoreHandle_t xTCPSemaphore; | |
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; | |
#ifdef I2CHIP_WINDOW | |
u_int current_window = i2chip_get_window(); | |
#endif | |
status = READ_VALUE(INT_REG); | |
if (status) | |
{ | |
xHigherPriorityTaskWoken = pdTRUE; | |
// channel 0 interrupt(sysinit, sockinit, established, closed, timeout, send_ok, recv_ok) | |
if (status & 0x01) | |
{ | |
I_STATUS[0] = READ_VALUE(INT_STATUS(0)); | |
// if (I_STATUS[0] & SESTABLISHED) | |
// ISR_ESTABLISHED(0); | |
// if (I_STATUS[0] & SCLOSED) | |
// ISR_CLOSED(0); | |
WRITE_VALUE(INT_REG, 0x01); | |
} | |
// channel 1 interrupt(sysinit, sockinit, established, closed, timeout, send_ok, recv_ok) | |
if (status & 0x02) | |
{ | |
I_STATUS[1] = READ_VALUE(INT_STATUS(1)); | |
// if (I_STATUS[1] & SESTABLISHED) | |
// ISR_ESTABLISHED(1); | |
// if (I_STATUS[1] & SCLOSED) | |
// ISR_CLOSED(1); | |
WRITE_VALUE(INT_REG, 0x02); | |
} | |
// channel 2 interrupt(sysinit, sockinit, established, closed, timeout, send_ok, recv_ok) | |
if (status & 0x04) | |
{ | |
I_STATUS[2] = READ_VALUE(INT_STATUS(2)); | |
// if (I_STATUS[2] & SESTABLISHED) | |
// ISR_ESTABLISHED(2); | |
// if (I_STATUS[2] & SCLOSED) | |
// ISR_CLOSED(2); | |
WRITE_VALUE(INT_REG, 0x04); | |
} | |
// channel 3 interrupt(sysinit, sockinit, established, closed, timeout, send_ok, recv_ok) | |
if (status & 0x08) | |
{ | |
I_STATUS[3] = READ_VALUE(INT_STATUS(3)); | |
// if (I_STATUS[3] & SESTABLISHED) ISR_ESTABLISHED(3); | |
// if (I_STATUS[3] & SCLOSED) ISR_CLOSED(3); | |
WRITE_VALUE(INT_REG, 0x08); | |
} | |
// channel 0 receive interrupt | |
if (status & 0x10) | |
{ | |
// ISR_RX(0); | |
WRITE_VALUE(INT_REG, 0x10); | |
} | |
// channel 1 receive interrupt | |
if (status & 0x20) | |
{ | |
// ISR_RX(1); | |
WRITE_VALUE(INT_REG, 0x20); | |
} | |
// channel 2 receive interrupt | |
if (status & 0x40) | |
{ | |
// ISR_RX(2); | |
WRITE_VALUE(INT_REG, 0x40); | |
} | |
// channel 3 receive interrupt | |
if (status & 0x80) | |
{ | |
// ISR_RX(3); | |
WRITE_VALUE(INT_REG, 0x80); | |
} | |
status = READ_VALUE(INT_REG); | |
} | |
WRITE_VALUE(INT_REG, 0xFF); | |
#ifdef I2CHIP_WINDOW | |
i2chip_set_window(current_window); | |
#endif | |
if( xHigherPriorityTaskWoken == pdTRUE ) | |
{ | |
xSemaphoreGiveFromISR( xTCPSemaphore, &xHigherPriorityTaskWoken ); | |
} | |
return xHigherPriorityTaskWoken; | |
} | |
void far interrupt in4_isr_i2chip(void) | |
{ | |
if( prvProcessISR() == pdTRUE ) | |
{ | |
portEND_SWITCHING_ISR(); | |
} | |
INT_EOI; | |
} | |
/* | |
**************************************************************************************************** | |
* Established connection interrupt handling function. | |
* | |
* Description : | |
* Called upon connection establishment, and may be inserted in user code if needed by | |
* the programmer. | |
* Arguments : None | |
* Returns : None | |
* Note : Internal Function | |
**************************************************************************************************** | |
*/ | |
/* | |
void ISR_ESTABLISHED(SOCKET s) | |
{ | |
// TO ADD YOUR CODE | |
} | |
*/ | |
/* | |
**************************************************************************************************** | |
* Closed connection interrupt handling function | |
* | |
* Description : | |
* Called upon connection closure, and may be inserted in user code if needed by the programmer. | |
* Arguments : None | |
* Returns : None | |
* Note : Internal Function | |
**************************************************************************************************** | |
*/ | |
/* | |
void ISR_CLOSED(SOCKET s) | |
{ | |
// TO ADD YOUR CODE | |
} | |
*/ | |
/* | |
**************************************************************************************************** | |
* Received data interrupt handling function | |
* | |
* Description : | |
* Called upon receiving data, and may be inserted in user code if needed by the programmer. | |
* Arguments : None | |
* Returns : None | |
* Note : Internal Function | |
**************************************************************************************************** | |
*/ | |
/* | |
void ISR_RX(SOCKET s) | |
{ | |
// TO ADD YOUR CODE | |
} | |
*/ | |
/* | |
**************************************************************************************************** | |
* W3100A Initialization Function | |
* | |
* Description: Reset of W3100A S/W and Registeration of i386 interrupt | |
* Arguments : None. | |
* Returns : None. | |
* Note : | |
**************************************************************************************************** | |
*/ | |
void initW3100A(void) | |
{ | |
// Install interrupt handler for i2Chip | |
INT_INIT(in4_isr_i2chip); | |
Local_Port = 1000; // This default value will be set if you didn't designate it when you | |
// create a socket. If you don't designate port number and create a | |
// socket continuously, the port number will be assigned with | |
// incremented by one to Local_Port | |
SEQ_NUM.lVal = 4294967293ul; // Sets the initial SEQ# to be used for TCP communication. | |
// (It should be ramdom value) | |
WRITE_VALUE(COMMAND(0), CSW_RESET); // Software RESET | |
} | |
/* | |
**************************************************************************************************** | |
* W3100A initialization function | |
* | |
* Description : | |
* Sets the Tx, Rx memory size by each channel, source MAC, source IP, gateway, and subnet mask | |
* to be used by the W3100A to the designated values. | |
* May be called when reflecting modified network information or Tx, Rx memory size on the W3100A | |
* Include Ping Request for ARP update (In case that a device embedding W3100A is directly | |
* connected to Router) | |
* Arguments : sbufsize - Tx memory size (00 - 1KByte, 01- 2KBtye, 10 - 4KByte, 11 - 8KByte) | |
* bit 1-0 : Tx memory size of channel #0 | |
* bit 3-2 : Tx memory size of channel #1 | |
* bit 5-4 : Tx memory size of channel #2 | |
* bit 7-6 : Tx memory size of channel #3 | |
* rbufsize - Rx memory size (00 - 1KByte, 01- 2KBtye, 10 - 4KByte, 11 - 8KByte) | |
* bit 1-0 : Rx memory size of channel #0 | |
* bit 3-2 : Rx memory size of channel #1 | |
* bit 5-4 : Rx memory size of channel #2 | |
* bit 7-6 : Rx memory size of channel #3 | |
* Returns : None | |
* Note : API Function | |
* Maximum memory size for Tx, Rx in W3100A is 8KBytes, | |
* In the range of 8KBytes, the memory size could be allocated dynamically by | |
* each channel | |
* Be attentive to sum of memory size shouldn't exceed 8Kbytes | |
* and to data transmission and receiption from non-allocated channel may cause | |
* some problems. | |
* If 8KBytes memory already is assigned to centain channel, other 3 channels | |
* couldn't be used, for there's no available memory. | |
* If two 4KBytes memory are assigned to two each channels, other 2 channels couldn't | |
* be used, for there's no available memory. | |
* (Example of memory assignment) | |
* sbufsize => 00000011, rbufsize => 00000011 : | |
* Assign 8KBytes for Tx and Rx to channel #0, Cannot use channel #1,#2,#3 | |
* sbufsize => 00001010, rbufsize => 00001010 : | |
* Assign 4KBytes for Tx and Rx to each channel #0,#1 respectively. Cannot use | |
* channel #2,#3 | |
* sbufsize => 01010101, rbufsize => 01010101 : | |
* Assign 2KBytes for Tx and Rx to each all channels respectively. | |
* sbufsize => 00010110, rbufsize => 01010101 : | |
* Assign 4KBytes for Tx, 2KBytes for Rx to channel #0 | |
* s 2KBytes for Tx, 2KBytes for Rx to channel #1 | |
* 2KBytes for Tx, 2KBytes for Rx to channel #2 | |
* 2KBytes is available exclusively for Rx in channel #3. There's no memory for Tx. | |
**************************************************************************************************** | |
*/ | |
void sysinit(u_char sbufsize, u_char rbufsize) | |
{ | |
char i; | |
int ssum,rsum; | |
ssum = 0; | |
rsum = 0; | |
// Set Tx memory size for each channel | |
WRITE_VALUE(TX_DMEM_SIZE, sbufsize); | |
// Set Rx memory size for each channel | |
WRITE_VALUE(RX_DMEM_SIZE, rbufsize); | |
// Set Base Address of Tx memory for channel #0 | |
SBUFBASEADDRESS[0] = 0; | |
// Set Base Address of Rx memory for channel #0 | |
RBUFBASEADDRESS[0] = 0; | |
// Set maximum memory size for Tx and Rx, mask, base address of memory by each channel | |
for(i = 0 ; i < MAX_SOCK_NUM; i++) | |
{ | |
SSIZE[i] = 0; | |
RSIZE[i] = 0; | |
if(ssum < 8192) | |
{ | |
switch((sbufsize >> i*2) & 0x03) // Set maximum Tx memory size | |
{ | |
case 0: | |
SSIZE[i] = 1024; | |
SMASK[i] = 0x000003FF; | |
break; | |
case 1: | |
SSIZE[i] = 2048; | |
SMASK[i] = 0x000007FF; | |
break; | |
case 2: | |
SSIZE[i] = 4096; | |
SMASK[i] = 0x00000FFF; | |
break; | |
case 3: | |
SSIZE[i] = 8192; | |
SMASK[i] = 0x00001FFF; | |
break; | |
} | |
} | |
if(rsum < 8192) | |
{ | |
switch((rbufsize >> i*2) & 0x03) // Set maximum Rx memory size | |
{ | |
case 0: | |
RSIZE[i] = 1024; | |
RMASK[i] = 0x000003FF; | |
break; | |
case 1: | |
RSIZE[i] = 2048; | |
RMASK[i] = 0x000007FF; | |
break; | |
case 2: | |
RSIZE[i] = 4096; | |
RMASK[i] = 0x00000FFF; | |
break; | |
case 3: | |
RSIZE[i] = 8192; | |
RMASK[i] = 0x00001FFF; | |
break; | |
} | |
} | |
ssum += SSIZE[i]; | |
rsum += RSIZE[i]; | |
// Set base address of Tx and Rx memory for channel #1,#2,#3 | |
if(i != 0) | |
{ | |
SBUFBASEADDRESS[i] = ssum - SSIZE[i]; | |
RBUFBASEADDRESS[i] = rsum - RSIZE[i]; | |
} | |
} | |
WRITE_VALUE(COMMAND(0), CSYS_INIT); | |
while(!(I_STATUS[0] & SSYS_INIT_OK)) | |
I2CHIP_POLL_ISR(in4_isr_i2chip); | |
#ifdef __PING__ | |
{ | |
u_char xdata pingbuf[8]; | |
setIPprotocol(0, IPPROTO_ICMP); | |
socket(0, SOCK_IPL_RAW, 3000,0); // Create a socket for ARP update | |
pingbuf[0] = 8; // ICMP TYPE | |
pingbuf[1] = 0; // ICMP CODE | |
pingbuf[2] = 0xf7; // CHECKSUM (already calculated) | |
pingbuf[3] = 0xfd; | |
pingbuf[4] = 0; // ID | |
pingbuf[5] = 1; | |
pingbuf[6] = 0; // SEQ # | |
pingbuf[7] = 1; | |
pingbuf[8] = 0; // Data 1 Byte | |
sendto(0, pingbuf, 9, GATEWAY_PTR,3000); // Ping Request | |
close(0); | |
printf("Route MAC Update Success"); | |
} | |
#endif | |
} | |
/* | |
**************************************************************************************************** | |
* Function to set subnet mask | |
* | |
* Description: | |
* Arguments : addr--> Pointer that has the value to be set | |
* Returns : None. | |
* Note : | |
**************************************************************************************************** | |
*/ | |
void setsubmask(u_char * addr) | |
{ | |
u_char i; | |
u_char far* sm_ptr = SUBNET_MASK_PTR; // We can only convert to 'regular' | |
// pointer if we're confident arithmetic | |
// won't take us out of current window. | |
for (i = 0; i < 4; i++) | |
{ | |
WRITE_VALUE(sm_ptr + SA_OFFSET(i), addr[i]); | |
} | |
} | |
/* | |
**************************************************************************************************** | |
* Function to set gateway IP | |
* | |
* Description: | |
* Arguments : addr--> Pointer that has Gateway IP to be set | |
* Returns : None. | |
* Note : | |
**************************************************************************************************** | |
*/ | |
void setgateway(u_char * addr) | |
{ | |
u_char i; | |
u_char far* gw_ptr = GATEWAY_PTR; // We can only convert to 'regular' | |
// pointer if we're confident arithmetic | |
// won't take us out of current window. | |
for (i = 0; i < 4; i++) | |
{ | |
WRITE_VALUE(gw_ptr + SA_OFFSET(i), addr[i]); | |
} | |
} | |
/* | |
**************************************************************************************************** | |
* Function to set W3100A IP | |
* | |
* Description: | |
* Arguments : addr--> Pointer that has Source IP to be set | |
* Returns : None. | |
* Note : | |
**************************************************************************************************** | |
*/ | |
void setIP(u_char * addr) | |
{ | |
u_char i; | |
u_char far* src_ptr = SRC_IP_PTR; // We can only convert to 'regular' | |
// pointer if we're confident arithmetic | |
// won't take us out of current window. | |
for (i = 0; i < 4; i++) | |
{ | |
WRITE_VALUE(src_ptr + SA_OFFSET(i), addr[i]); | |
} | |
} | |
// DEBUG | |
void getIP(u_char* addr) | |
{ | |
u_char i; | |
u_char far* src_ptr = SRC_IP_PTR; // We can only convert to 'regular' | |
// pointer if we're confident arithmetic | |
// won't take us out of current window. | |
for (i = 0; i < 4; i++) | |
addr[i] = READ_VALUE(src_ptr + SA_OFFSET(i)); | |
} | |
/* | |
**************************************************************************************************** | |
* Function to set MAC | |
* | |
* Description: | |
* Arguments : addr--> Pointer that has MAC to be set | |
* Returns : None. | |
* Note : | |
**************************************************************************************************** | |
*/ | |
void setMACAddr(u_char * addr) | |
{ | |
u_char i; | |
u_char far* ha_ptr = SRC_HA_PTR; // We can only convert to 'regular' | |
// pointer if we're confident arithmetic | |
// won't take us out of current window. | |
for (i = 0; i < 6; i++) | |
{ | |
WRITE_VALUE(ha_ptr + SA_OFFSET(i), addr[i]); | |
} | |
} | |
/* | |
**************************************************************************************************** | |
* Function to set TCP timeout | |
* | |
* Description: The function that used to adjust time to resend TCP | |
* Arguments : val --> Pointer that has the value to be set | |
* Upper 2 byte:Initial timeout value | |
* Last 1 byte:The count to retry till timeout | |
* Returns : None. | |
* Note : | |
**************************************************************************************************** | |
*/ | |
void settimeout(u_char * val) | |
{ | |
u_char i; | |
u_char far* tout_ptr = TIMEOUT_PTR; // We can only convert to 'regular' | |
// pointer if we're confident arithmetic | |
// won't take us out of current window. | |
for (i = 0; i < 3; i++) | |
{ | |
WRITE_VALUE(tout_ptr + SA_OFFSET(i), val[i]); | |
} | |
} | |
/* | |
**************************************************************************************************** | |
* Function to set interrupt mask. | |
* | |
* Description: | |
* Arguments : mask--> Mask value to be set ('1'-> interrupt ) | |
* Returns : None. | |
* Note : | |
**************************************************************************************************** | |
*/ | |
void setINTMask(u_char mask) | |
{ | |
WRITE_VALUE(INTMASK, mask); | |
} | |
/* | |
**************************************************************************************************** | |
* Function to set enable in sending and receiving of broadcast data | |
* | |
* Description: Enable to process of broadcating data in UDP or IP RAW mode. | |
* Arguments : s --> Channel No. to be set | |
* Returns : None. | |
* Note : | |
**************************************************************************************************** | |
*/ | |
void setbroadcast(SOCKET s) | |
{ | |
u_char val = READ_VALUE(OPT_PROTOCOL(s)); | |
WRITE_VALUE(OPT_PROTOCOL(s), val | SOCKOPT_BROADCAST); | |
} | |
/* | |
**************************************************************************************************** | |
* Function to set process protocol in IP RAW mode. | |
* | |
* Description: | |
* Arguments : s--> Channel No. to be set | |
* tos-->Protocol Value to be set | |
* Returns : None. | |
* Note : | |
**************************************************************************************************** | |
*/ | |
void setTOS(SOCKET s, u_char tos) | |
{ | |
WRITE_VALUE(TOS(s), tos); | |
} | |
/* | |
**************************************************************************************************** | |
* Upper layer protocol setup function in IP RAW Mode | |
* | |
* Description : Upper layer protocol setup function in protocol field of IP header when | |
* developing upper layer protocol like ICMP, IGMP, EGP etc. by using IP Protocol | |
* Arguments : s - Channel number | |
* ipprotocol - Upper layer protocol setting value of IP Protocol | |
* (Possible to use designated IPPROTO_ in header file) | |
* Returns : None | |
* Note : API Function | |
* This function should be called before calling socket() that is, before | |
* socket initialization. | |
**************************************************************************************************** | |
*/ | |
void setIPprotocol(SOCKET s, u_char ipprotocol) | |
{ | |
WRITE_VALUE(IP_PROTOCOL(s), ipprotocol); | |
} | |
/* | |
**************************************************************************************************** | |
* Initialization function to appropriate channel | |
* | |
* Description : Initialize designated channel and wait until W3100 has done. | |
* Arguments : s - channel number | |
* protocol - designate protocol for channel | |
* SOCK_STREAM(0x01) -> TCP. | |
* SOCK_DGRAM(0x02) -> UDP. | |
* SOCK_IPL_RAW(0x03) -> IP LAYER RAW. | |
* SOCK_MACL_RAW(0x04) -> MAC LAYER RAW. | |
* port - designate source port for appropriate channel | |
* flag - designate option to be used in appropriate. | |
* SOCKOPT_BROADCAST(0x80) -> Send/receive broadcast message in UDP | |
* SOCKOPT_NDTIMEOUT(0x40) -> Use register value which designated TIMEOUT | |
* value | |
* SOCKOPT_NDACK(0x20) -> When not using no delayed ack | |
* SOCKOPT_SWS(0x10) -> When not using silly window syndrome | |
* Returns : When succeeded : Channel number, failed :-1 | |
* Note : API Function | |
**************************************************************************************************** | |
*/ | |
char socket(SOCKET s, u_char protocol, u_int port, u_char flag) | |
{ | |
u_char k; | |
//Designate socket protocol and option | |
WRITE_VALUE(OPT_PROTOCOL(s), protocol | flag); | |
// setup designated port number | |
if (port != 0) | |
{ | |
k = (u_char)((port & 0xff00) >> 8); | |
WRITE_VALUE(SRC_PORT_PTR(s), k); | |
k = (u_char)(port & 0x00ff); | |
WRITE_VALUE(SRC_PORT_PTR(s) + SA_OFFSET(1), k); | |
} | |
else | |
{ | |
// Designate random port number which is managed by local when you didn't designate source port | |
Local_Port++; | |
WRITE_VALUE(SRC_PORT_PTR(s), (u_char)((Local_Port & 0xff00) >> 8)); | |
WRITE_VALUE(SRC_PORT_PTR(s) + SA_OFFSET(1), (u_char)(Local_Port & 0x00ff)); | |
} | |
// SOCK_INIT | |
I_STATUS[s] = 0; | |
WRITE_VALUE(COMMAND(s), CSOCK_INIT); | |
// Waiting Interrupt to CSOCK_INIT | |
while (I_STATUS[s] == 0) | |
I2CHIP_POLL_ISR(in4_isr_i2chip); | |
if (!(I_STATUS[s] & SSOCK_INIT_OK)) | |
return(-1); | |
initseqnum(s); // Use initial seq# with random number | |
return(s); | |
} | |
/* | |
**************************************************************************************************** | |
* Connection establishing function to designated peer. | |
* | |
* Description : This function establish a connection to the peer by designated channel, | |
* and wait until the connection is established successfully. (TCP client mode) | |
* Arguments : s - channel number | |
* addr - destination IP Address | |
* port - destination Port Number | |
* Returns : when succeeded : 1, failed : -1 | |
* Note : API Function | |
**************************************************************************************************** | |
*/ | |
char connect(SOCKET s, u_char far * addr, u_int port) | |
{ | |
if (port != 0) | |
{ //designate destination port | |
WRITE_VALUE(DST_PORT_PTR(s), (u_char)((port & 0xff00) >> 8)); | |
WRITE_VALUE(DST_PORT_PTR(s) + SA_OFFSET(1), (u_char)(port & 0x00ff)); | |
} | |
else | |
return(-1); | |
WRITE_VALUE(DST_IP_PTR(s), addr[0]); //designate destination IP address | |
WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(1), addr[1]); | |
WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(2), addr[2]); | |
WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(3), addr[3]); | |
I_STATUS[s] = 0; | |
WRITE_VALUE(COMMAND(s), CCONNECT); // CONNECT | |
I2CHIP_POLL_ISR(in4_isr_i2chip); | |
// Wait until connection is established successfully | |
while (I_STATUS[s] == 0) | |
{ | |
// When failed, appropriate channel will be closed and return an error | |
if (select(s, SEL_CONTROL) == SOCK_CLOSED) | |
return -1; | |
} | |
if (!(I_STATUS[s] & SESTABLISHED)) | |
return(-1); | |
return(1); | |
} | |
/* | |
**************************************************************************************************** | |
* Connection establishing function to designated peer. (Non-blocking Mode) | |
* | |
* Description : This function establish a connection to the peer by designated channel. | |
* | |
* Arguments : s - channel number | |
* addr - destination IP Address | |
* port - destination Port Number | |
* Returns : when succeeded : 1, failed : -1 | |
* Note : API Function | |
**************************************************************************************************** | |
*/ | |
char NBconnect(SOCKET s, u_char far * addr, u_int port) | |
{ | |
if (port != 0) | |
{ //designate destination port | |
WRITE_VALUE(DST_PORT_PTR(s), (u_char) ((port & 0xff00) >> 8) ); | |
WRITE_VALUE(DST_PORT_PTR(s) + SA_OFFSET(1), (u_char)(port & 0x00ff)); | |
} | |
else | |
return(-1); | |
WRITE_VALUE(DST_IP_PTR(s), addr[0]); //designate destination IP address | |
WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(1), addr[1]); | |
WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(2), addr[2]); | |
WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(3), addr[3]); | |
I_STATUS[s] = 0; | |
WRITE_VALUE(COMMAND(s), CCONNECT); // CONNECT | |
return(1); | |
} | |
/* | |
**************************************************************************************************** | |
* Waits for connection request from a peer (Blocking Mode) | |
* | |
* Description : Wait for connection request from a peer through designated channel (TCP Server mode) | |
* Arguments : s - channel number | |
* addr - IP Address of the peer when a connection is established | |
* port - Port number of the peer when a connection is established | |
* Returns : When succeeded : 1, failed : -1 | |
* Note : API Function | |
**************************************************************************************************** | |
*/ | |
/* | |
char listen(SOCKET s, u_char far * addr, u_int far * port) | |
{ | |
u_int i; | |
I_STATUS[s] = 0; | |
// LISTEN | |
COMMAND(s) = CLISTEN; | |
// Wait until connection is established | |
while (I_STATUS[s] == 0) | |
{ | |
// When failed to connect, the designated channel will be closed and return an error. | |
if (select(s, SEL_CONTROL) == SOCK_CLOSED) | |
return -1; | |
} | |
// Receive IP address and port number of the peer connected | |
if (I_STATUS[s] & SESTABLISHED) | |
{ | |
i = *DST_PORT_PTR(s); | |
*port = (u_int)((i & 0xff00) >> 8); | |
i = *(DST_PORT_PTR(s) + 2); | |
i = (u_int)(i & 0x00ff); | |
*port += (i << 8); | |
addr[0] = *DST_IP_PTR(s); | |
addr[1] = *(DST_IP_PTR(s) + 2); | |
addr[2] = *(DST_IP_PTR(s) + 4); | |
addr[3] = *(DST_IP_PTR(s) + 6); | |
} | |
else | |
return(-1); | |
return(1); | |
} | |
*/ | |
/* | |
**************************************************************************************************** | |
* Waits for connection request from a peer (Non-blocking Mode) | |
* | |
* Description : Wait for connection request from a peer through designated channel (TCP Server mode) | |
* Arguments : s - channel number | |
* Returns : None | |
* Note : API Function | |
**************************************************************************************************** | |
*/ | |
char NBlisten(SOCKET s) | |
{ | |
I_STATUS[s] = 0; | |
// LISTEN | |
WRITE_VALUE(COMMAND(s), CLISTEN); | |
return(1); | |
} | |
/* | |
**************************************************************************************************** | |
* Create random value for initial Seq# when establishing TCP connection | |
* | |
* Description : In this function, you can add some source codes to create random number for | |
* initial Seq#. In real, TCP initial SEQ# should be random value. | |
* (Currently, we're using static value in EVB/DK.) | |
* Arguments : s - channel number | |
* Returns : None | |
* Note : API Function | |
**************************************************************************************************** | |
*/ | |
void initseqnum(SOCKET s) | |
{ | |
// Designate initial seq# | |
// If you have random number generation function, assign random number instead of SEQ_NUM.lVal++. | |
SEQ_NUM.lVal++; | |
//randomize(); | |
//SEQ_NUM.lVal = rand(); | |
WRITE_VALUE(TX_WR_PTR(s), SEQ_NUM.cVal[0]); | |
WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(1), SEQ_NUM.cVal[1]); | |
WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(2), SEQ_NUM.cVal[2]); | |
WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(3), SEQ_NUM.cVal[3]); | |
delay0(2); | |
WRITE_VALUE(TX_RD_PTR(s), SEQ_NUM.cVal[0]); | |
WRITE_VALUE(TX_RD_PTR(s) + SA_OFFSET(1), SEQ_NUM.cVal[1]); | |
WRITE_VALUE(TX_RD_PTR(s) + SA_OFFSET(2), SEQ_NUM.cVal[2]); | |
WRITE_VALUE(TX_RD_PTR(s) + SA_OFFSET(3), SEQ_NUM.cVal[3]); | |
delay0(2); | |
WRITE_VALUE(TX_ACK_PTR(s), SEQ_NUM.cVal[0]); | |
WRITE_VALUE(TX_ACK_PTR(s) + SA_OFFSET(1), SEQ_NUM.cVal[1]); | |
WRITE_VALUE(TX_ACK_PTR(s) + SA_OFFSET(2), SEQ_NUM.cVal[2]); | |
WRITE_VALUE(TX_ACK_PTR(s) + SA_OFFSET(3), SEQ_NUM.cVal[3]); | |
delay0(2); | |
} | |
/* | |
**************************************************************************************************** | |
* Function for sending TCP data. | |
* | |
* Description : Function for sending TCP data and Composed of the send() and send_in() functions. | |
* The send() function is an application I/F function. | |
* It continues to call the send_in() function to complete the sending of the data up to the | |
* size of the data to be sent when the application is called. | |
* The send_in() function receives the return value (the size of the data sent), calculates | |
* the size of the data to be sent, and calls the send_in() function again if there is any | |
* data left to be sent. | |
* Arguments : s - channel number | |
* buf - Pointer pointing data to send | |
* len - data size to send | |
* Returns : Succeed: sent data size, Failed: -1; | |
* Note : API Function | |
**************************************************************************************************** | |
*/ | |
int send(SOCKET s, u_char far * buf, u_int len) | |
{ | |
int ptr, size; | |
u_char huge* huge_buf = (u_char huge*)buf; | |
u_char far* local_buf = (u_char far*)huge_buf; | |
if (len <= 0) | |
return (0); | |
else | |
{ | |
ptr = 0; | |
do | |
{ | |
size = send_in(s, local_buf + ptr, len); | |
if (size == -1) | |
return -1; | |
len = len - size; | |
ptr += size; | |
} while ( len > 0); | |
} | |
return ptr; | |
} | |
/* | |
**************************************************************************************************** | |
* Internal function for sending TCP data. | |
* | |
* Description : Called by the send() function for TCP transmission. | |
* It first calculates the free transmit buffer size | |
* and compares it with the size of the data to be transmitted to determine the transmission size. | |
* After calculating the data size, it copies data from TX_WR_PTR. | |
* It waits if there is a previous send command in process. | |
* When the send command is cleared, it updates the TX_WR_PTR up to the size to be transmitted | |
and performs the send command. | |
* Arguments : s - channel number | |
* buf - Pointer pointing data to send | |
* len - data size to send | |
* Returns : Succeeded: sent data size, Failed: -1 | |
* Note : Internal Function | |
**************************************************************************************************** | |
*/ | |
int send_in(SOCKET s, u_char far * buf, u_int len) | |
{ | |
u_char k; | |
u_int size; | |
union un_l2cval wr_ptr, ack_ptr; | |
unsigned int offset; | |
S_START: | |
disable(); // CT: Shadow register access should not conflict with ISR. | |
k = READ_VALUE(SHADOW_TXWR_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
wr_ptr.cVal[3] = READ_VALUE(TX_WR_PTR(s)); | |
wr_ptr.cVal[2] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(1)); | |
wr_ptr.cVal[1] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(2)); | |
wr_ptr.cVal[0] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(3)); | |
k = READ_VALUE(SHADOW_TXACK_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
ack_ptr.cVal[3] = READ_VALUE(TX_ACK_PTR(s)); | |
ack_ptr.cVal[2] = READ_VALUE(TX_ACK_PTR(s) + SA_OFFSET(1)); | |
ack_ptr.cVal[1] = READ_VALUE(TX_ACK_PTR(s) + SA_OFFSET(2)); | |
ack_ptr.cVal[0] = READ_VALUE(TX_ACK_PTR(s) + SA_OFFSET(3)); | |
enable(); | |
// Suppress compiler errors that k is not used | |
k = k; | |
// Calculate send free buffer size | |
if (wr_ptr.lVal >= ack_ptr.lVal) | |
size = (u_int)(SSIZE[s] - (wr_ptr.lVal - ack_ptr.lVal)); | |
else | |
size = (u_int)(SSIZE[s] - (0 - ack_ptr.lVal + wr_ptr.lVal)); | |
// Recalulate after some delay because of error in pointer calculation | |
if (size > SSIZE[s]) | |
{ | |
if (select(s, SEL_CONTROL) != SOCK_ESTABLISHED) | |
return -1; | |
delay_ms(1); | |
goto S_START; | |
} | |
// Wait when previous sending has not finished yet and there's no free buffer | |
if (size == 0) | |
{ | |
if (select(s, SEL_CONTROL) != SOCK_ESTABLISHED) | |
return -1; | |
delay_ms(1); | |
goto S_START; | |
} | |
else if (size < len) | |
{ | |
len = size; | |
} | |
// Calculate pointer to data copy | |
offset = (UINT)(wr_ptr.lVal & SMASK[s]); | |
// copy data | |
write_data(s, buf, offset, len); | |
while (READ_VALUE(COMMAND(s)) & CSEND) | |
{ | |
// Confirm previous send command | |
if (select(s, SEL_CONTROL) != SOCK_ESTABLISHED) | |
return -1; | |
} | |
// update tx_wr_ptr | |
wr_ptr.lVal = wr_ptr.lVal + len; | |
WRITE_VALUE(TX_WR_PTR(s), wr_ptr.cVal[3]); | |
WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(1), wr_ptr.cVal[2]); | |
WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(2), wr_ptr.cVal[1]); | |
WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(3), wr_ptr.cVal[0]); | |
delay0(1); | |
// SEND | |
WRITE_VALUE(COMMAND(s), CSEND); | |
return(len); | |
} | |
/* | |
**************************************************************************************************** | |
* TCP data receiving function. | |
* | |
* Description : This function is to clear out any received TCP data. | |
* Arguments : s - channel number | |
* Returns : None | |
* Note : API Fcuntion | |
**************************************************************************************************** | |
*/ | |
void recv_clear(SOCKET s) | |
{ | |
u_char k; | |
u_int size; | |
union un_l2cval wr_ptr, rd_ptr; | |
disable(); | |
k = READ_VALUE(SHADOW_RXWR_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
wr_ptr.cVal[3] = READ_VALUE(RX_WR_PTR(s)); | |
wr_ptr.cVal[2] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(1)); | |
wr_ptr.cVal[1] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(2)); | |
wr_ptr.cVal[0] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(3)); | |
k = READ_VALUE(SHADOW_RXRD_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
rd_ptr.cVal[3] = READ_VALUE(RX_RD_PTR(s)); | |
rd_ptr.cVal[2] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(1)); | |
rd_ptr.cVal[1] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(2)); | |
rd_ptr.cVal[0] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(3)); | |
enable(); | |
// Suppress compiler errors that k is not used | |
k = k; | |
// calculate received data size | |
if (wr_ptr.lVal >= rd_ptr.lVal) | |
size = (u_int)(wr_ptr.lVal - rd_ptr.lVal); | |
else | |
size = (u_int)(0 - rd_ptr.lVal + wr_ptr.lVal); | |
// Update rx_rd_ptr | |
rd_ptr.lVal += size; | |
WRITE_VALUE(RX_RD_PTR(s), rd_ptr.cVal[3]); | |
WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(1), rd_ptr.cVal[2]); | |
WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(2), rd_ptr.cVal[1]); | |
WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(3), rd_ptr.cVal[0]); | |
// RECV | |
WRITE_VALUE(COMMAND(s), CRECV); | |
} | |
/* | |
**************************************************************************************************** | |
* TCP data receiving function. | |
* | |
* Description : This function is for receiving TCP data. | |
* The recv() function is an application I/F function. It will read up to len chars if there are | |
enough characters in the buffer, otherwise will onl read the number of characters availiable | |
* Arguments : s - channel number | |
* buf - Pointer where the data to be received is copied | |
* len - Size of the data to be received | |
* Returns : Succeeded: received data size, Failed: -1 | |
* Note : API Fcuntion | |
**************************************************************************************************** | |
*/ | |
int recv(SOCKET s, u_char far * buf, u_int len) | |
{ | |
u_char k; | |
u_int size; | |
union un_l2cval wr_ptr, rd_ptr; | |
unsigned int offset; | |
// If out length is 0, then we do not need to do anything | |
if (len <= 0) | |
return (0); | |
disable(); | |
k = READ_VALUE(SHADOW_RXWR_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
wr_ptr.cVal[3] = READ_VALUE(RX_WR_PTR(s)); | |
wr_ptr.cVal[2] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(1)); | |
wr_ptr.cVal[1] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(2)); | |
wr_ptr.cVal[0] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(3)); | |
k = READ_VALUE(SHADOW_RXRD_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
rd_ptr.cVal[3] = READ_VALUE(RX_RD_PTR(s)); | |
rd_ptr.cVal[2] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(1)); | |
rd_ptr.cVal[1] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(2)); | |
rd_ptr.cVal[0] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(3)); | |
enable(); | |
// Suppress compiler errors that k is not used | |
k = k; | |
// calculate IIM7010A received data size | |
if (wr_ptr.lVal == rd_ptr.lVal) | |
return(0); | |
else if (wr_ptr.lVal >= rd_ptr.lVal) | |
size = (u_int)(wr_ptr.lVal - rd_ptr.lVal); | |
else | |
size = (u_int)(0 - rd_ptr.lVal + wr_ptr.lVal); | |
// Make sure we do not try to read more characters than what is availiable in the IIM7010 buffer | |
if (size < len) | |
len = size; | |
// Calculate pointer to be copied received data | |
offset = ((UINT)(rd_ptr.lVal & RMASK[s])); | |
// Copy received data | |
size = read_data(s, offset, buf, len); | |
// Update rx_rd_ptr | |
rd_ptr.lVal += size; | |
WRITE_VALUE(RX_RD_PTR(s), rd_ptr.cVal[3]); | |
WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(1), rd_ptr.cVal[2]); | |
WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(2), rd_ptr.cVal[1]); | |
WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(3), rd_ptr.cVal[0]); | |
// RECV | |
WRITE_VALUE(COMMAND(s), CRECV); | |
return(size); | |
} | |
/* | |
**************************************************************************************************** | |
* UDP data sending function. | |
* | |
* Description : Composed of the sendto()and sendto_in() functions. | |
* The send() function is an application I/F function. | |
* It continues to call the send_in() function to complete the sending of the data up to the | |
* size of the data to be sent | |
* when the application is called.Unlike TCP transmission, it designates the destination address | |
* and the port. | |
* Arguments : s - channel port | |
* buf - Pointer pointing data to send | |
* len - data size to send | |
* addr - destination IP address to send data | |
* port - destination port number to send data | |
* Returns : Sent data size | |
* Note : API Function | |
**************************************************************************************************** | |
*/ | |
u_int sendto(SOCKET s, u_char far * buf, u_int len, u_char * addr, u_int port) | |
{ | |
//char val; | |
u_int ptr, size; | |
// Wait until previous send commnad has completed. | |
while(READ_VALUE(COMMAND(s)) & CSEND) | |
{ | |
if(select(s, SEL_CONTROL) == SOCK_CLOSED) | |
return -1; // Error. | |
} | |
// Designate destination port number. | |
if (port != 0) | |
{ | |
WRITE_VALUE(DST_PORT_PTR(s), (u_char)((port & 0xff00) >> 8)); | |
WRITE_VALUE(DST_PORT_PTR(s) + SA_OFFSET(1), (u_char)(port & 0x00ff)); | |
} | |
// Designate destination IP address | |
WRITE_VALUE(DST_IP_PTR(s), addr[0]); | |
WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(1), addr[1]); | |
WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(2), addr[2]); | |
WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(3), addr[3]); | |
if (len <= 0) | |
return (0); | |
else | |
{ | |
ptr = 0; | |
do | |
{ | |
size = sendto_in(s, buf + ptr, len); | |
len = len - size; | |
ptr += size; | |
} while ( len > 0); | |
} | |
return ptr; | |
} | |
/* | |
**************************************************************************************************** | |
* UDP data sending function. | |
* | |
* Description : An internal function that is the same as the send_in() function of the TCP. | |
* Arguments : s - Channel number | |
* buf - Pointer indicating the data to send | |
* len - data size to send | |
* Returns : Sent data size | |
* Note : Internal Function | |
**************************************************************************************************** | |
*/ | |
u_int sendto_in(SOCKET s, u_char far * buf, u_int len) | |
{ | |
u_char k; | |
u_int size; | |
union un_l2cval wr_ptr, rd_ptr; | |
unsigned int offset; | |
S2_START: | |
disable(); | |
k = READ_VALUE(SHADOW_TXWR_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
wr_ptr.cVal[3] = READ_VALUE(TX_WR_PTR(s)); | |
wr_ptr.cVal[2] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(1)); | |
wr_ptr.cVal[1] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(2)); | |
wr_ptr.cVal[0] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(3)); | |
k = READ_VALUE(SHADOW_TXRD_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
rd_ptr.cVal[3] = READ_VALUE(TX_RD_PTR(s)); | |
rd_ptr.cVal[2] = READ_VALUE(TX_RD_PTR(s) + SA_OFFSET(1)); | |
rd_ptr.cVal[1] = READ_VALUE(TX_RD_PTR(s) + SA_OFFSET(2)); | |
rd_ptr.cVal[0] = READ_VALUE(TX_RD_PTR(s) + SA_OFFSET(3)); | |
enable(); | |
// Suppress compiler errors that k is not used | |
k = k; | |
// Calculate free buffer size to send | |
if (wr_ptr.lVal >= rd_ptr.lVal) | |
size = (u_int)(SSIZE[s] - (wr_ptr.lVal - rd_ptr.lVal)); | |
else | |
size = (u_int)(SSIZE[s] - (0 - rd_ptr.lVal + wr_ptr.lVal)); | |
// Recalulate after some delay because of error in pointer caluation | |
if (size > SSIZE[s]) | |
{ | |
delay_ms(1); | |
goto S2_START; | |
} | |
// Wait when previous sending has not finished yet and there's no free buffer | |
if (size == 0) | |
{ | |
delay_ms(1); | |
goto S2_START; | |
} | |
else if (size < len) | |
{ | |
len = size; | |
} | |
// Calculate pointer to copy data pointer | |
offset =(UINT)(wr_ptr.lVal & SMASK[s]); | |
// copy data | |
write_data(s, buf, offset, len); | |
// Confirm previous send command | |
while (READ_VALUE(COMMAND(s)) & CSEND) | |
{ | |
if(select(s, SEL_CONTROL)==SOCK_CLOSED) | |
return -1; // Error | |
} | |
// update tx_wr_ptr | |
wr_ptr.lVal = wr_ptr.lVal + len; | |
WRITE_VALUE(TX_WR_PTR(s), wr_ptr.cVal[3]); | |
WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(1), wr_ptr.cVal[2]); | |
WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(2), wr_ptr.cVal[1]); | |
WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(3), wr_ptr.cVal[0]); | |
delay0(1); | |
// SEND | |
WRITE_VALUE(COMMAND(s), CSEND); | |
return(len); | |
} | |
/* | |
**************************************************************************************************** | |
* UDP data receiving function. | |
* | |
* Description : Function for receiving UDP and IP layer RAW mode data, and handling the data header. | |
* Arguments : s - channel number | |
* buf - Pointer where the data to be received is copied | |
* len - Size of the data to be received | |
* addr - Peer IP address for receiving | |
* port - Peer port number for receiving | |
* Returns : Received data size | |
* Note : API Function | |
**************************************************************************************************** | |
*/ | |
u_int recvfrom(SOCKET s, u_char far *buf, u_int len, u_char *addr, u_int *port) | |
{ | |
struct _UDPHeader // When receiving UDP data, header added by W3100A | |
{ | |
union | |
{ | |
struct | |
{ | |
u_int size; | |
u_char addr[4]; | |
u_int port; | |
} header; | |
u_char stream[8]; | |
} u; | |
} UDPHeader; | |
u_int ret; | |
union un_l2cval wr_ptr, rd_ptr; | |
u_long size; | |
u_char k; | |
unsigned int offset; | |
if(select(s,SEL_CONTROL)==SOCK_CLOSED) | |
return -1; | |
disable(); | |
k = READ_VALUE(SHADOW_RXWR_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
wr_ptr.cVal[3] = READ_VALUE(RX_WR_PTR(s)); | |
wr_ptr.cVal[2] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(1)); | |
wr_ptr.cVal[1] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(2)); | |
wr_ptr.cVal[0] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(3)); | |
k = READ_VALUE(SHADOW_RXRD_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
rd_ptr.cVal[3] = READ_VALUE(RX_RD_PTR(s)); | |
rd_ptr.cVal[2] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(1)); | |
rd_ptr.cVal[1] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(2)); | |
rd_ptr.cVal[0] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(3)); | |
enable(); | |
// Suppress compiler errors that k is not used | |
k = k; | |
// Calculate received data size | |
if (len <= 0) | |
return (0); | |
else if (wr_ptr.lVal >= rd_ptr.lVal) | |
size = wr_ptr.lVal - rd_ptr.lVal; | |
else | |
size = 0 - rd_ptr.lVal + wr_ptr.lVal; | |
if (size == 0) | |
return 0; | |
// Calulate received data pointer | |
offset = ((UINT)(rd_ptr.lVal & RMASK[s])); | |
// When UDP data | |
if (( READ_VALUE(OPT_PROTOCOL(s)) & 0x07) == SOCK_DGRAM) | |
{ | |
// Copy W3100A UDP header | |
read_data(s, offset, UDPHeader.u.stream, 8); | |
// Read UDP Packet size | |
size = UDPHeader.u.stream[0]; | |
size = (size << 8) + UDPHeader.u.stream[1]; | |
// Read IP address of the peer | |
addr[0] = UDPHeader.u.header.addr[0]; | |
addr[1] = UDPHeader.u.header.addr[1]; | |
addr[2] = UDPHeader.u.header.addr[2]; | |
addr[3] = UDPHeader.u.header.addr[3]; | |
// Read Port number of the peer | |
*port = UDPHeader.u.stream[6]; | |
*port = (*port << 8) + UDPHeader.u.stream[7]; | |
// Increase read pointer by 8, because already read as UDP header size | |
rd_ptr.lVal += 8; | |
// Calculate UDP data copy pointer | |
offset = ((UINT)(rd_ptr.lVal & RMASK[s])); | |
// Calculate data size of current UDP Packet from UDP header | |
size = size - 8; | |
// Copy one UDP data packet to user-specific buffer | |
ret = read_data(s, offset, buf, (u_int)size); | |
// Increase read pointer by UDP packet data size | |
rd_ptr.lVal += ret; | |
} | |
else if ((READ_VALUE(OPT_PROTOCOL(s)) & 0x07) == SOCK_IPL_RAW) // When IP layer RAW mode data | |
{ | |
// Copy W3100A IP Raw header | |
read_data(s, offset, UDPHeader.u.stream, 6); | |
// Read IP layer RAW Packet size | |
size = UDPHeader.u.stream[0]; | |
size = (size << 8) + UDPHeader.u.stream[1]; | |
// Read IP address of the peer | |
addr[0] = UDPHeader.u.header.addr[0]; | |
addr[1] = UDPHeader.u.header.addr[1]; | |
addr[2] = UDPHeader.u.header.addr[2]; | |
addr[3] = UDPHeader.u.header.addr[3]; | |
// Increase read pointer by 6, because already read as IP RAW header size | |
rd_ptr.lVal += 6; | |
// Calculate IP layer raw mode data pointer | |
offset = ((UINT)(rd_ptr.lVal & RMASK[s])); | |
// Copy one IP Raw data packet to user-specific buffer | |
ret = read_data(s, offset, buf, (u_int)size); | |
rd_ptr.lVal = rd_ptr.lVal + (ret - 4); | |
} | |
// Update rx_rd_ptr | |
WRITE_VALUE(RX_RD_PTR(s), rd_ptr.cVal[3]); | |
WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(1), rd_ptr.cVal[2]); | |
WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(2), rd_ptr.cVal[1]); | |
WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(3), rd_ptr.cVal[0]); | |
// RECV | |
WRITE_VALUE(COMMAND(s), CRECV); | |
// Real received size return | |
return(ret); | |
} | |
/* | |
**************************************************************************************************** | |
* Channel closing function. | |
* | |
* Description : Function for closing the connection of the designated channel. | |
* Arguments : s - channel number | |
* Returns : None | |
* Note : API Function | |
**************************************************************************************************** | |
*/ | |
void close(SOCKET s) | |
{ | |
u_int len; | |
short sAttempts = 0; | |
I_STATUS[s] = 0; | |
if (select(s, SEL_CONTROL) == SOCK_CLOSED) | |
return; // Already closed | |
// When closing, if there's data which have not processed, Insert some source codes to handle this | |
// Or before application call close(), handle those data first and call close() later. | |
len = select(s, SEL_SEND); | |
if (len == SSIZE[s]) | |
{ | |
// CLOSE | |
WRITE_VALUE(COMMAND(s), CCLOSE); | |
// TODO: The 'SCLOSED' status value is only set briefly as part of the close, | |
// and will otherwise quickly return to normal. That means your code might | |
// become 'stuck' at this point even if the packet has closed normally. | |
// Rather than a while() call, it might be preferred to time out on this | |
// close check and return to the application after some time. | |
while(!(I_STATUS[s] & SCLOSED)) | |
{ | |
sAttempts++; | |
if( sAttempts > 10 ) | |
{ | |
break; | |
} | |
I2CHIP_POLL_ISR(in4_isr_i2chip); | |
} | |
} | |
} | |
u_char tx_empty(SOCKET s) | |
{ | |
return (select(s, SEL_SEND) == SSIZE[s]); | |
} | |
/* | |
**************************************************************************************************** | |
* Channel closing function. | |
* | |
* Description : Function for closing the connection of the designated channel. | |
* Arguments : s - channel number | |
* Returns : None | |
* Note : API Function | |
**************************************************************************************************** | |
*/ | |
char reset_sock(SOCKET s) | |
{ | |
u_char c; | |
c = 1 << s; | |
// RESET | |
WRITE_VALUE(RESETSOCK, c); | |
return (1); | |
} | |
/* | |
**************************************************************************************************** | |
* Function handling the channel socket information. | |
* | |
* Description : Return socket information of designated channel | |
* Arguments : s - channel number | |
* func - SEL_CONTROL(0x00) -> return socket status | |
* SEL_SEND(0x01) -> return free transmit buffer size | |
* SEL_RECV(0x02) -> return received data size | |
* Returns : socket status or free transmit buffer size or received data size | |
* Note : API Function | |
**************************************************************************************************** | |
*/ | |
u_int select(SOCKET s, u_char func) | |
{ | |
u_int val; | |
union un_l2cval rd_ptr, wr_ptr, ack_ptr; | |
u_char k; | |
switch (func) | |
{ | |
// socket status information | |
case SEL_CONTROL : | |
val = READ_VALUE(SOCK_STATUS(s)); | |
break; | |
// Calculate send free buffer size | |
case SEL_SEND : | |
disable(); | |
k = READ_VALUE(SHADOW_TXWR_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
wr_ptr.cVal[3] = READ_VALUE(TX_WR_PTR(s)); | |
wr_ptr.cVal[2] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(1)); | |
wr_ptr.cVal[1] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(2)); | |
wr_ptr.cVal[0] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(3)); | |
if (( READ_VALUE(OPT_PROTOCOL(s)) & 0x07) == SOCK_STREAM) // TCP | |
{ | |
k = READ_VALUE(SHADOW_TXACK_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
ack_ptr.cVal[3] = READ_VALUE(TX_ACK_PTR(s)); | |
ack_ptr.cVal[2] = READ_VALUE(TX_ACK_PTR(s) + SA_OFFSET(1)); | |
ack_ptr.cVal[1] = READ_VALUE(TX_ACK_PTR(s) + SA_OFFSET(2)); | |
ack_ptr.cVal[0] = READ_VALUE(TX_ACK_PTR(s) + SA_OFFSET(3)); | |
enable(); | |
if (wr_ptr.lVal >= ack_ptr.lVal) | |
val = (u_int)(SSIZE[s] - (wr_ptr.lVal - ack_ptr.lVal)); | |
else | |
val = (u_int)(SSIZE[s] - (0 - ack_ptr.lVal + wr_ptr.lVal)); | |
} | |
else // UDP, IP RAW ... (except TCP) | |
{ | |
k = READ_VALUE(SHADOW_TXRD_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
rd_ptr.cVal[3] = READ_VALUE(TX_RD_PTR(s)); | |
rd_ptr.cVal[2] = READ_VALUE(TX_RD_PTR(s) + SA_OFFSET(1)); | |
rd_ptr.cVal[1] = READ_VALUE(TX_RD_PTR(s) + SA_OFFSET(2)); | |
rd_ptr.cVal[0] = READ_VALUE(TX_RD_PTR(s) + SA_OFFSET(3)); | |
enable(); | |
if (wr_ptr.lVal >= rd_ptr.lVal) | |
val = (u_int)(SSIZE[s] - (wr_ptr.lVal - rd_ptr.lVal)); | |
else | |
val = (u_int)(SSIZE[s] - (0 - rd_ptr.lVal + wr_ptr.lVal)); | |
} | |
break; | |
// Calculate received data size | |
case SEL_RECV : | |
disable(); | |
k = READ_VALUE(SHADOW_RXWR_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
wr_ptr.cVal[3] = READ_VALUE(RX_WR_PTR(s)); | |
wr_ptr.cVal[2] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(1)); | |
wr_ptr.cVal[1] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(2)); | |
wr_ptr.cVal[0] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(3)); | |
k = READ_VALUE(SHADOW_RXRD_PTR(s)); | |
WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. | |
delay0(2); | |
rd_ptr.cVal[3] = READ_VALUE(RX_RD_PTR(s)); | |
rd_ptr.cVal[2] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(1)); | |
rd_ptr.cVal[1] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(2)); | |
rd_ptr.cVal[0] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(3)); | |
enable(); | |
if (wr_ptr.lVal == rd_ptr.lVal) | |
val = 0; | |
else if (wr_ptr.lVal > rd_ptr.lVal) | |
val = (u_int)(wr_ptr.lVal - rd_ptr.lVal); | |
else | |
val = (u_int)(0 - rd_ptr.lVal + wr_ptr.lVal); | |
break; | |
default : | |
val = -1; | |
break; | |
} | |
// Suppress compiler errors that k is not used | |
k = k; | |
return(val); | |
} | |
// | |
// unsigned char dma_read_i2chip (unsigned int i2_segm, unsigned int i2_offs, | |
// unsigned int cnt, unsigned int des_segm, unsigned int des_offs); | |
// Using DMA0 to read data from i2chip buffer into destination SRAM. | |
// where: | |
// unsigned int cnt = number of sectors, 512-byte per sector | |
// unsigned int des_segm = segment of destination SRAM data memory | |
// unsigned int des_offs = offset of destination SRAM data memory | |
// unsigned int i2_segm = segment of i2chip buffer mapped in memory | |
// unsigned int i2_offs = offset of i2chip buffer mapped in memory | |
// return DMA counter value | |
// | |
unsigned int dma_read_i2chip(u_char far* i2_src, u_char far* des, u_int cnt) | |
{ | |
u_int des_segm, des_offs; | |
u_int i2_segm, i2_offs; | |
u_long temp; | |
temp = ((long)FP_SEG(des) << 4) + ((long)FP_OFF(des)); | |
des_segm = (u_int)(temp >> 16); | |
des_offs = (u_int)(temp & 0xffff); | |
temp = ((long)FP_SEG(i2_src) << 4) + ((long)FP_OFF(i2_src)); | |
i2_segm = (u_int)(temp >> 16); | |
i2_offs = (u_int)(temp & 0xffff); | |
outport(0xffc6, des_segm); /* D0DSTH destination SRAM segment */ | |
outport(0xffc4, des_offs); /* D0DSTL destination SRAM offset */ | |
outport(0xffc2, i2_segm); /* D0SRCH=SP0RD */ | |
outport(0xffc0, i2_offs); /* D0SRCL=SP0RD */ | |
outport(0xffc8, cnt); // D0TC counter | |
outport(0xfff8,0x0504); // PLLCON, 0203=10M,050f=40M, 051f=80MHz | |
// DMA0 mem-mem, 16-bit, unsync, Start moving data line below | |
outport(0xffca, 0xb60e); /* D0CON 1011 0110 0000 1111 */ | |
// outport(0xffca, 0xb42e); // 1011 0100 0010 1110 | |
while( inport(0xffc8) ); /* D0TC counter=0, DMA complete */ | |
outport(0xfff8,0x051f); // PLLCON, 0203=10M,050f=40M, 051f=80MHz | |
return( inport(0xffc8) ); // counter | |
} | |
// | |
// unsigned int dma_write_i2chip (unsigned int src_segm, unsigned int src_offs, | |
// unsigned int cnt, unsigned int i2_segm, unsigned int i2_offs); | |
// Using DMA0 to write data from memory into i2chip. | |
// where: | |
// unsigned int cnt = number of 16-bit DMA transfers | |
// unsigned int src_segm = segment of the source SRAM data memory | |
// unsigned int src_offs = offset of the source SRAM data memory | |
// unsigned int i2_segm = segment of i2chip buffer mapped in memory | |
// unsigned int i2_offs = offset of i2chip buffer mapped in memory | |
// return DMA counter value | |
// | |
unsigned int dma_write_i2chip(u_char far* src, u_char far* i2_dest, u_int cnt) | |
{ | |
u_int src_segm, src_offs; | |
u_int i2_segm, i2_offs; | |
u_long temp; | |
temp = (FP_SEG(src) << 4) + (FP_OFF(src)); | |
src_segm = (u_int)(temp >> 4); | |
src_offs = (u_int)(temp & 0xffff); | |
temp = (FP_SEG(i2_dest) << 4) + (FP_OFF(i2_dest)); | |
i2_segm = (u_int)(temp >> 4); | |
i2_offs = (u_int)(temp & 0xffff); | |
outport(0xffc8, cnt); // D0TC counter | |
outport(0xffc6, i2_segm); // D0DSTH=i2chip buffer segment | |
outport(0xffc4, i2_offs); // D0DSTL=i2chip buffer offset | |
outport(0xffc2, src_segm); /* D0SRCH=SP0RD */ | |
outport(0xffc0, src_offs); /* D0SRCL=SP0RD */ | |
// outport(0xfff8,0x050f); // PLLCON, 0203=10M,050f=40M, 051f=80MHz | |
// DMA0 mem-mem, 16-bit, unsync, Start moving data line below | |
outport(0xffca, 0xb60f); /* D0CON 1011 0110 0000 1111 */ | |
while( inport(0xffc8) ); /* D0TC counter=0, DMA complete */ | |
// outport(0xfff8,0x051f); // PLLCON, 0203=10M,050f=40M, 051f=80MHz | |
return( inport(0xffc8) ); // counter | |
} | |
/* | |
**************************************************************************************************** | |
* Copies the receive buffer data of the W3100A to the system buffer. | |
* | |
* Description : Copies the receive buffer data of the W3100A to the system buffer. | |
* It is called from the recv()or recvfrom() function. | |
* Arguments : s - channel number | |
* src - receive buffer pointer of W3100A | |
* dst - system buffer pointer | |
* len - data size to copy | |
* Returns : copied data size | |
* Note : Internal Function | |
**************************************************************************************************** | |
*/ | |
u_int read_data(SOCKET s, u_int offset, u_char far * dst, u_int len) | |
{ | |
u_int i, size, size1; | |
u_char far* src = (u_char far*)(MK_FP_WINDOW(RECV_DATA_BUF, | |
RBUFBASEADDRESS[s] + offset)); | |
// src = (u_char far*)(MK_FP_WINDOW(RECV_DATA_BUF, | |
// 0)); | |
if (len == 0) | |
{ | |
WINDOW_RESTORE_BASE; // Needed whenever we do a call to MK_FP_WINDOW. | |
return 0; | |
} | |
if ((offset + len) > RSIZE[s]) | |
{ | |
size = (u_int)(RSIZE[s] - offset); | |
if (size > TERN_RDMA_THRES) | |
{ | |
dma_read_i2chip(src, dst, size); | |
} | |
else | |
{ | |
for (i = 0; i < size; i++) | |
{ | |
*dst++ = READ_VALUE(src); | |
WINDOW_PTR_INC(src); | |
} | |
} | |
size1 = len - size; | |
src = (u_char far *)(MK_FP_WINDOW(RECV_DATA_BUF, (RBUFBASEADDRESS[s]))); | |
if (size1 > TERN_RDMA_THRES) | |
{ | |
dma_read_i2chip(src, dst, size); | |
} | |
else | |
{ | |
for (i = 0; i < size1; i++) | |
{ | |
*dst++ = READ_VALUE(src); | |
WINDOW_PTR_INC(src); | |
} | |
} | |
} | |
else | |
{ | |
if (len > TERN_RDMA_THRES) | |
{ | |
dma_read_i2chip(src, dst, size); | |
} | |
else | |
{ | |
for (i = 0; i < len; i++) | |
{ | |
*dst++ = READ_VALUE(src); | |
WINDOW_PTR_INC(src); | |
} | |
} | |
} | |
WINDOW_RESTORE_BASE; // Needed whenever we do a call to MK_FP_WINDOW. | |
return len; | |
} | |
/* | |
**************************************************************************************************** | |
* Copies the system buffer data to the transmit buffer of the W3100A. | |
* | |
* Description : Copies the system buffer data to the transmit buffer of the W3100A. | |
* It is called from the send_in()or sendto_in() function. | |
* Arguments : s - channel number | |
* src - system buffer pointer | |
* dst - send buffer pointer of W3100A | |
* len - data size to copy | |
* Returns : copied data size | |
* Note : Internal Function | |
**************************************************************************************************** | |
*/ | |
u_int write_data(SOCKET s, u_char far * src, u_int offset, u_int len) | |
{ | |
u_int i, size, size1; | |
u_char far* dst = (u_char far*)MK_FP_WINDOW(SEND_DATA_BUF, | |
SBUFBASEADDRESS[s] + offset); | |
if (len == 0) | |
{ | |
WINDOW_RESTORE_BASE; // Needed whenever we do a call to MK_FP_WINDOW. | |
return 0; | |
} | |
if ((offset + len) > SSIZE[s]) | |
{ | |
size = (u_int)(SSIZE[s] - offset); | |
for (i = 0; i < size; i++) | |
{ | |
WRITE_VALUE(dst, *src++); | |
WINDOW_PTR_INC(dst); | |
} | |
size1 = len - size; | |
dst = (u_char far *)(MK_FP_WINDOW(SEND_DATA_BUF, (SBUFBASEADDRESS[s]))); | |
for (i = 0; i < size1; i++) | |
{ | |
WRITE_VALUE(dst, *src++); | |
WINDOW_PTR_INC(dst); | |
} | |
} | |
else | |
{ | |
for (i = 0; i < len; i++) | |
{ | |
WRITE_VALUE(dst, *src++); | |
WINDOW_PTR_INC(dst); | |
} | |
} | |
WINDOW_RESTORE_BASE; // Needed whenever we do a call to MK_FP_WINDOW. | |
return len; | |
} | |