Esempio n. 1
0
/****************************************************************************
  Function:
    unsigned int ChipKITClientPutSz(TCP_SOCKET hTCP, const char * sz, unsigned int cSecTimout)

  Description:
    This routine writes out a string on to the wire.

  Precondition:
    hTCP must be open and valid.

  Parameters:
    hTCP - The socket to check
	sz - a zero terminated string to write out
	cSecTimout - The number of seconds to wait before aborting the write.

  Returns:
    Returns the number of character written, zero if none.

  Remarks:
	This is to match functionality of the Arduino Client class write method
	A flush to push the bytes out on the wire is done.
  ***************************************************************************/
unsigned int ChipKITClientPutSz(TCP_SOCKET hTCP, const char * sz, unsigned int cSecTimout)
{
	DWORD t = 0;
	char * szCur = (char *) sz;
	char * szLast = szCur;

	// there is a rare potential that this could loop forever
	// if the connection stays active yet the otherside does not read
	// the buffer.

	// loop until this is written out, or timeout
	t = TickGet();
	while(*szCur !=0x00) 
	{
		// if we lost the connection, get out
		if( !TCPIsConnected(hTCP) )
		{
			break;
		}

		// try to write some char out
		szCur = TCPPutString(hTCP, szCur);

		// if we are done, get out.
		if(*szCur == 0x00)
		{
			break;
		}
		
		// we did move forward, so reset our timers and pointers.
		else if(szCur != szLast)
		{
			szLast = szCur;	// last written location
			t = TickGet();	// reset wait timer, we are moving forward
		}

		// we have not moved forward, so check our timeout value
		else if((TickGet() - t) >= (cSecTimout * TICK_SECOND)) 
		{
			break;
		}
			
		// if the buffer is full, it should automatically flush
		// so we should not need to write TCPFlush
		// run our tasks so things can be put out and come in.
		ChipKITPeriodicTasks();
	}

	if(TCPIsConnected(hTCP))
	{
		TCPFlush(hTCP);				// flush any remaining stuff out
	}

	ChipKITPeriodicTasks();		// run the tasks to get it done
	return( ((unsigned int) (szCur - sz)) / sizeof(char) ); // return # char written
}
Esempio n. 2
0
void sendStringEthernet( char * p, char newLine )
{

	int l = 0;
	WORD wMaxPut;
	
	// Make sure the Socket is connected to something!
	if(!TCPIsConnected(MySocket)) return;
	
	// Find the length of the string
	while (*(p+l) != 0x00) l++;
	
	if(l)
	{
		wMaxPut = TCPIsPutReady(MySocket);
		if(wMaxPut < l)
		{
			#ifdef __DEBUG
			while(1);	// Hold here while debugging
			#endif
		}
		else
		{
			// Transfer the data out of our local processing buffer and into the TCP TX FIFO.
			TCPPutArray(MySocket, (BYTE*)p, l);
		}		
	}
	if(newLine) TCPPut(MySocket, 10);
		
	
	TCPFlush(MySocket); // Send the data immediatly!

}	
/***	int TcpServer::availableClients(void)
**
**	Synopsis:   
**      Checks to see how many pending clients are availabe to be accepted.
**
**	Parameters:
**      None
**
**	Return Values:
**      The number of waiting TcpClients to be accepted.
**
**	Errors:
**      None
**
**  Notes:
**
**      This is the workhorse of the TcpServer Class
**      It will update pending clients if a connection is detected
**      It will attempt to start listening if a socket comes avalialbe for listening
**      It will clean up disconnected clients
*/
int TcpServer::availableClients(void)
{
    int i = 0;

    EthernetPeriodicTasks();

    if(isListening() && TCPIsConnected(_rghTCP[_cPending]))
    {
        _cPending++;      
    }

    // now look for not Connected ones and remove them out of the list
    while(i < _cPending)
    {
        // see if we need to clear this one
        if((_rghTCP[i] >= INVALID_SOCKET) || (!TCPIsConnected(_rghTCP[i]) && (TCPIsGetReady(_rghTCP[i]) == 0)) )
        {
            int j = i;

            // shift everyone from this location down.
            // include everything possible (_cPendingMax), even things beyond _cPending
            // because I want to shift the listening one at _rghUDP[_cPending] as well
            for(; j < _cPendingMax-1; j++)
            {
                _rghTCP[j] = _rghTCP[j+1];
            }

            // make sure the last one in the list is made an invalid socket
            _rghTCP[_cPendingMax-1] = INVALID_SOCKET;

            // reduce the pending count
            _cPending--;
        }
        else
        {
            i++;
        }
    }

    // if we are supposed to be listening, then try to listening
    if(_fListening)
    {
         resumeListening();
    }

    return(_cPending);
}
Esempio n. 4
0
/*****************************************************************************
  Function:
	bool TCPIsEstablished(SOCKET * pSocket, IPSTATUS * pStatus)

  Description:
        This is sort of like TCPIsConnected except it is for the established state. Think
        of being connected as being in the process of getting or closing a connection and being established.
        Established is a fully connected duplex condtion where both sides are ready to send and receive data.

  Parameters:
	pSocket:        The socket to see if it is in the established state
        pStatus:        A pointer to a status variable to recieve the status of the connection
                        This may be NULL if you don't care about the status

  Returns:
        true if the connection is established and you can send/write data,
        false if the conneciton is not established
  ***************************************************************************/
bool TCPIsEstablished(HSOCKET hSocket, IPSTATUS * pStatus)
{
    IPSTATUS    status;

    TCPIsConnected(hSocket, &status);
    AssignStatusSafely(pStatus, status);
    return(status == IPStatusFromTCPState(tcpEstablished));
}
Esempio n. 5
0
/*****************************************************************************
  Function:
	SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen)

  Summary:
	This function accepts connection requests queued for a listening socket.

  Description:
	The accept function is used to accept connection requests
	queued for a listening socket. If a connection request is
	pending, accept removes the request from the queue, and a new
	socket is created for the connection. The original listening
	socket remains open and continues to queue new connection
	requests. The socket must be a SOCK_STREAM type socket.

  Precondition:
	listen function should be called.

  Parameters:
	s - Socket descriptor returned from a previous call to
	socket. must be bound to a local name and in listening mode.
	addr - Optional pointer to a buffer that receives the address
	of the connecting entity.
	addrlen - Optional pointer to an integer that contains the
	length of the address addr

  Returns:
	If the accept function succeeds, it returns a non-negative
	integer that is a descriptor for the accepted socket.
	Otherwise, the value INVALID_SOCKET is returned.

  Remarks:
	None.
  ***************************************************************************/
SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen)
{
	struct BSDSocket *pListenSock;
	SOCKET_INFO *remoteSockInfo;
	struct sockaddr_in *addrRemote;
	unsigned int sockCount;
	TCP_SOCKET hTCP;

	if( s >= BSD_SOCKET_COUNT )
		return INVALID_SOCKET;

	pListenSock = &BSDSocketArray[s]; /* Get the pointer to listening server socket */

	if ( pListenSock->bsdState != SKT_BSD_LISTEN )
		return INVALID_SOCKET;
	if ( pListenSock->SocketType != SOCK_STREAM )
		return INVALID_SOCKET;

	for(sockCount = 0; sockCount < BSD_SOCKET_COUNT; sockCount++)
	{
		if(BSDSocketArray[sockCount].bsdState != SKT_LISTEN)
			continue;

		if(BSDSocketArray[sockCount].localPort != pListenSock->localPort)
			continue;

		hTCP = BSDSocketArray[sockCount].SocketID;
		
		// We don't care about connections and disconnections before we can 
		// process them, so clear the reset flag
		TCPWasReset(hTCP);	
		
		if(TCPIsConnected(hTCP))
		{
			remoteSockInfo = TCPGetRemoteInfo(hTCP);
			if(addr)
			{
				if(addrlen)
				{
					if((unsigned int)*addrlen < sizeof(struct sockaddr_in))
						return INVALID_SOCKET;
					addrRemote = (struct sockaddr_in *)addr;
					addrRemote->sin_addr.S_un.S_addr = remoteSockInfo->remote.IPAddr.Val;
					addrRemote->sin_port = remoteSockInfo->remotePort.Val;
					*addrlen = sizeof(struct sockaddr_in);
				}
			}
			BSDSocketArray[sockCount].remotePort = remoteSockInfo->remotePort.Val;
			BSDSocketArray[sockCount].remoteIP   = remoteSockInfo->remote.IPAddr.Val;
			BSDSocketArray[sockCount].bsdState = SKT_EST;
			return sockCount;
		}
	}

	return INVALID_SOCKET;
}
/***	bool TCPSocket::getRemoteMAC(MAC *pRemoteMAC)
**
**	Synopsis:   
**      Gets the MAC address of the remote endpoint
**
**	Parameters:
**      pRemoteMAC  A pointer to a MAC to receive the remote MAC address
**
**	Return Values:
**      true    The remote MAC was returned.
**      false   The remote MAC is not known, usually because the connection was not set up yet.
**
**	Errors:
**      None
**
**  Notes:
**
**      If false is returned, then *pRemoteMAC will be garbage.
**
**      This is the MAC address as returned by ARP, it will be the actual MAC address
**      for any machine on the local area netowrk, but will typically be the MAC address
**      of your router if the remote connection is not local to your network.
**
*/
bool TCPSocket::getRemoteMAC(MACADDR& remoteMAC)
{
    if(!TCPIsConnected(&_socket, NULL))
    {
        return(false);
    }

    SKTGetRemoteMAC(&_socket, &remoteMAC);
    return((memcmp(&remoteMAC, &MACNONE, sizeof(MACADDR)) != 0));
}
Esempio n. 7
0
static BOOL Quit(void)
{
    switch(smFTPCommand)
    {
    case SM_FTP_CMD_IDLE:
#if defined(FTP_PUT_ENABLED)
        if ( smFTPCommand == SM_FTP_CMD_RECEIVE )
            MPFSClose();
#endif

        if ( FTPDataSocket != INVALID_SOCKET )
        {
#if defined(FTP_PUT_ENABLED)
            MPFSClose();
#endif
            TCPDisconnect(FTPDataSocket);
            smFTPCommand = SM_FTP_CMD_WAIT;
        }
        else
            goto Quit_Done;
        break;

    case SM_FTP_CMD_WAIT:
        if ( !TCPIsConnected(FTPDataSocket) )
        {
Quit_Done:
            FTPResponse = FTP_RESP_QUIT_OK;
            smFTPCommand = SM_FTP_CMD_WAIT_FOR_DISCONNECT;
        }
        break;

    case SM_FTP_CMD_WAIT_FOR_DISCONNECT:
        if ( TCPIsPutReady(FTPSocket) )
        {
            if ( TCPIsConnected(FTPSocket) )
                TCPDisconnect(FTPSocket);
        }
        break;

    }
    return FALSE;
}
/***	bool TCPSocket::getRemoteEndPoint(IPEndPoint *pRemoteEP)
**
**	Synopsis:   
**      Gets the endpoint for the remote connection
**
**	Parameters:
**      pRemoteEP  A pointer to an IPEndPoint to receive the remote endpoint information.
**
**	Return Values:
**      true    The remote endpoint was returned.
**      false   The remote endpoint is not known, usually because the connection was not set up yet.
**
**	Errors:
**      None
**
**  Notes:
**
**      If false is returned, then *pRemoteEP will be garbage.
**
**      If true it will be the remote endpoint information even for machines not on the local area network.
**
*/
bool TCPSocket::getRemoteEndPoint(IPEndPoint& epRemote)
{
    if(!TCPIsConnected(&_socket, NULL))
    {
        return(false);
    }
    SKTGetRemoteIPv4(&_socket, &epRemote.ip);
    epRemote.port = SKTGetRemotePort(&_socket);

    return(true);
}
/***	bool TCPSocket::getLocalEndPoint(IPEndPoint *pLocalEP)
**
**	Synopsis:   
**      Gets the endpoint for this connection. It will be the local machines IP address
**      and the port by this machine to talk to the remote machine.
**
**	Parameters:
**      pLocalEP  A pointer to an IPEndPoint to receive the local endpoint information.
**
**	Return Values:
**      true    The local endpoint was returned.
**      false   The local endpoint is not known, usually because the connection was not set up yet.
**
**	Errors:
**      None
**
**  Notes:
**
**      If false is returned, then *pLocalEP will be garbage.
**
*/
bool TCPSocket::getLocalEndPoint(IPEndPoint& epLocal)
{
    if(!TCPIsConnected(&_socket, NULL))
    {
        return(false);
    }
    ILGetMyIP(_socket.s.pLLAdp, &epLocal.ip);
    epLocal.port = SKTGetLocalPort(&_socket);

    return(true);
}
Esempio n. 10
0
/****************************************************************************
  Function:
    BOOL ChipKITClientConnected(TCP_SOCKET hTCP)

  Description:
    This routine checks to see if the socket is still connected

  Precondition:
    none

  Parameters:
    hTCP - The socket to check

  Returns:
    TRUE is the socket is open and connected, FALSE otherwise.

  Remarks:
	This is to match functionality of the Arduino Client class Connected method.
	This will return TRUE even if the socket is no longer connected yet there are still
	some unread bytes in the socket buffer. This is to match Arduino functionality
  ***************************************************************************/
BOOL ChipKITClientConnected(TCP_SOCKET hTCP)
{
	// even though we are disconnected we may 
	// still have data in the input buffer
	// Arduino defines this as still open
	// so check to see if we have stuff. 
	if(TCPIsGetReady(hTCP) == 0)
	{
		// nothing in the buffer, return the truth about the connection
		return(TCPIsConnected(hTCP));
	}
	// still have stuff in the buffer, say we are connected.
	else
	{
		return(TRUE);
	}
}
Esempio n. 11
0
/*****************************************************************************
*
*  exoHAL_SocketClose
*
*  \param  socket - socket handle
*
*  \return None
*
*  \brief  Closes a socket
*
*****************************************************************************/
void
exoHAL_SocketClose(long socket)
{
  // Send everything immediately
  if (GenericTCPState == EX_DISCONNECT)
  {
    if (TCPIsConnected((TCP_SOCKET)exSocket) && socket_crush == 1)
    {
      TCPClose((TCP_SOCKET)exSocket);
      socket_crush = 0;
      exSocket = INVALID_SOCKET;
      socket = exSocket;
    }
    send_count = 0;
    GenericTCPState = EX_DONE;
  }
  return;
}
Esempio n. 12
0
/****************************************************************************
  Function:
    ChipKITClientPutByte(TCP_SOCKET hTCP, BYTE b)

  Description:
    This routine write 1 byte out on the socket

  Precondition:
    hTCP must be open and valid.

  Parameters:
    hTCP - The socket to check
	b - the byte to write out.

  Returns:
    True if it succeeded, false otherwise.

  Remarks:
	This is to match functionality of the Arduino Client class write method
	This is an expensive function to call as it flushes the1 byte out; we don't know
	how many bytes will be written, and the Arduino code expects the byte to go out.
	Also, this will run the periodic tasks, so a lot of over head is used for this task.
  ***************************************************************************/
BOOL ChipKITClientPutByte(TCP_SOCKET hTCP, BYTE b)
{
	BOOL fRet = FALSE;
	
	// really don't care if it is connected or not
	// just return the error
	fRet = TCPPut(hTCP, b);

	// this is very expensive!
	if(TCPIsConnected(hTCP))
	{
		TCPFlush(hTCP);				// flush any remaining stuff out
	}

	// run our tasks so things can be put out and come in.
	ChipKITPeriodicTasks();

	return(fRet);
}
Esempio n. 13
0
/****************************************************************************
  Function:
   TCP_SOCKET ChipKITClientConnect(unsigned int dwOpenVal, BYTE vRemoteHostType, unsigned short wPort, unsigned int cSecTimout)

  Description:
    This routine opens a socket and for clients only, attempts to connect to the server.
	DNS lookups are done if a URL is specifed for dwOpenVal and vRemoteHostType == TCP_OPEN_RAM_HOST
	
  Precondition:
    None

  Parameters:
    dwOpenVal		- Same as in TCPOpen
	vRemoteHostType	- Same as in TCPOpen
	wPort			- Same as in TCPOpen
	cSecTimout		- If this is a client connecting to a host, this is the number of seconds to wait for a 
						successful connection to occur

  Returns:
   	The valid socket if the open was successful, or INVALID_SOCKET if no sockets were avaiable or 
	the connection was not made (in the case of a client)

  Remarks:
	This routine will attempt to wait until the connection is made for client, but will return immediately for servers as servers
	listen for connections. For the client case, if cSecTimout is exceeded, the connection is close and the socket released back to
	the stack for reuse.
   ***************************************************************************/
TCP_SOCKET ChipKITClientConnect(unsigned int dwOpenVal, BYTE vRemoteHostType, unsigned short wPort, unsigned int cSecTimout)
{
	TCP_SOCKET hTCP = UNKNOWN_SOCKET;
	DWORD t = 0;

	hTCP = TCPOpen((DWORD) dwOpenVal, vRemoteHostType, (WORD) wPort, TCP_PURPOSE_DEFAULT);
	ChipKITPeriodicTasks();

	// if it just fails, don't even attempt a retry
	if(hTCP == INVALID_SOCKET)
	{
		return(hTCP);
	}

	// if this is a client, we have to wait until we connect
	// No need to do this for servers as they connect when some one comes in on the listen
	if(vRemoteHostType != TCP_OPEN_SERVER) 
	{
		t = TickGet(); // so we don't loop forever
		while(!TCPIsConnected(hTCP))
		{
		 	ChipKITPeriodicTasks();
	
			// if after 10 seconds we do not connect, just fail and clean up
			if( (TickGet() - t) >= (cSecTimout * TICK_SECOND))
			{
				TCPClose(hTCP);
				TCPDiscard(hTCP);
				hTCP = INVALID_SOCKET;
				
				// make sure we run tasks again to get for the close to take effect
				// so don't return here, break out of the while to clean up
				break;  
			}
		}
				
		ChipKITPeriodicTasks();
	}

	return(hTCP);
}
Esempio n. 14
0
/*****************************************************************************
*
*  exoHAL_ServerConnect
*
*  \param  None
*
*  \return socket - socket handle
*
*  \brief  The function opens a TCP socket
*
*****************************************************************************/
long
exoHAL_ServerConnect(long sock)
{
  if (GenericTCPState == EX_SOCKET_OBTAINED)
  {
    // Wait for the remote server to accept our connection request
    if (!TCPIsConnected(sock))
    {
      wait_count++;
      if (wait_count > 10)
      {
        socket_crush = 1;
        GenericTCPState = EX_DISCONNECT;
        wait_count = 0;
        return -1;
      }
    }
    GenericTCPState = EX_PACKAGE_SEND;
  }

  return (long)sock;
}
Esempio n. 15
0
/****************************************************************************
  Function:
    void ChipKITClientStop(TCP_SOCKET hTCP)

  Description:
    This routine closes the socket, discards the input buffer, and returns the socket to the TCPIP stack.

  Precondition:
    hTCP must be open and valid.

  Parameters:
    hTCP - The socket to close

  Returns:
    none

  Remarks:
	This is to match functionality of the Arduino Client class stop method
  ***************************************************************************/
void ChipKITClientStop(TCP_SOCKET hTCP)
{

	// the MAL can hang if you attempt to close an invalid socket
	if(hTCP == INVALID_SOCKET || hTCP == UNKNOWN_SOCKET)
	{
		return;
	}

	// close the handle
	TCPClose(hTCP);

	// empty the receive buffer because we are killing it.
	TCPDiscard(hTCP);

	// loop until it is acknowledged to be closed
	do
	{
		ChipKITPeriodicTasks();
	} while(TCPIsConnected(hTCP));	

}
Esempio n. 16
0
/*****************************************************************************
  Function:
	SOCKET accept( SOCKET s, struct sockaddr* addr, int* addrlen )

  Summary:
	This function accepts connection requests queued for a listening socket.

  Description:
	The accept function is used to accept connection requests
	queued for a listening socket. If a connection request is
    pending, accept removes the request from the queue, and a new
    socket is created for the connection. The original listening
    socket remains open and continues to queue new connection
    requests. The socket must be a SOCK_STREAM type socket.

  Precondition:
	listen function should be called.

  Parameters:
	s - Socket descriptor returned from a previous call to
    socket. must be bound to a local name and in listening mode.
    addr - Optional pointer to a buffer that receives the address
    of the connecting entity.
    addrlen - Optional pointer to an integer that contains the
    length of the address addr
    
  Returns:
	If the accept function succeeds, it returns a non-negative
    integer that is a descriptor for the accepted socket.
    Otherwise, the value INVALID_SOCKET is returned.

  Remarks:
	None.
  ***************************************************************************/
SOCKET accept( SOCKET s,
               struct sockaddr* addr,
               int* addrlen )
{
    struct BSDSocket *pListenSock;
    SOCKET_INFO *remoteSockInfo;
    struct sockaddr_in *addrRemote;
    unsigned int sockCount;
   
    if( s >= BSD_SOCKET_COUNT )
        return INVALID_SOCKET;

    pListenSock = &BSDSocketArray[s]; /* Get the pointer to listening server socket */

    if ( pListenSock->bsdState < SKT_LISTEN )
        return INVALID_SOCKET;

    for(sockCount = 0; sockCount < BSD_SOCKET_COUNT; sockCount++)
    {
        if((BSDSocketArray[sockCount].bsdState == SKT_LISTEN) && (BSDSocketArray[sockCount].isServer == TRUE))
        {
            if(TCPIsConnected(BSDSocketArray[sockCount].SocketID))
            {
                remoteSockInfo = TCPGetRemoteInfo(BSDSocketArray[sockCount].SocketID);
                addrRemote = (struct sockaddr_in *)addr;
                addrRemote->sin_addr.S_un.S_addr = remoteSockInfo->remote.IPAddr.Val;
                addrRemote->sin_port = remoteSockInfo->remotePort.Val;
                *addrlen = sizeof(struct sockaddr_in);
                BSDSocketArray[sockCount].remotePort = addrRemote->sin_port;
                BSDSocketArray[sockCount].remoteIP   = addrRemote->sin_addr.S_un.S_addr;
                BSDSocketArray[sockCount].bsdState = SKT_EST;
                return sockCount;
            }
            
        }
    }

    return INVALID_SOCKET;
}
Esempio n. 17
0
/***	int TCPServer::availableClients(void)
**
**	Synopsis:   
**      Checks to see how many pending clients are availabe to be accepted.
**
**	Parameters:
**      None
**
**	Return Values:
**      The number of waiting TCPSockets to be accepted.
**
**	Errors:
**      None
**
**  Notes:
**
**      This is the workhorse of the TCPServer Class
**      It will update pending clients if a connection is detected
**      It will attempt to start listening if a socket comes avalialbe for listening
**      It will clean up disconnected clients
*/
int TCPServer::availableClients(int& cListening, int& cWaiting, IPSTATUS * pStatus)
{
    int cAvailable = 0;
    cWaiting = 0;
    cListening = 0;

    FFLL *      pffllSocket = NULL;

   if(_pDEIPcK == NULL)
   {
       AssignStatusSafely(pStatus, ipsNotInitialized);
       return(0);
   }

    if(ILIsIPNetworkReady(_pDEIPcK->_pLLAdp, pStatus))
    {
        while((pffllSocket = (FFLL *) FFNext(&_ffptSockets, pffllSocket)) != NULL)
        {
            TCPSocket& tcpSocket = *((TCPSocket *) (pffllSocket->_this));   // for syntax sake

            if(TCPIsEstablished(&tcpSocket._socket, NULL))
            {
                cAvailable++;
            }
            else if(TCPIsConnected(&tcpSocket._socket, NULL))
            {
                cWaiting++;
            }
            else if(tcpSocket._socket.tcpState == tcpListen)
            {
                cListening++;
            }
         }
    }

    return(cAvailable);
}
Esempio n. 18
0
/*****************************************************************************
*
*  exoHAL_SocketRecv
*
*  \param  socket - socket handle; buffer - string buffer to put info we
*          receive; len - size of buffer in bytes;
*
*  \return Number of bytes received
*
*  \brief  Receives data from the internet
*
*****************************************************************************/
unsigned char
exoHAL_SocketRecv(long socket, char * buffer, unsigned char len)
{
  WORD w, wGetLen;

  if (GenericTCPState == EX_PACKAGE_SEND && send_count >= 4)
  {
    TCPFlush((TCP_SOCKET)exSocket);
    GenericTCPState++;
  }

  if (GenericTCPState == EX_PROCESS_RESPONSE)
  {
    if (!TCPIsConnected(socket))
    {
      return 0;
    }

    w = TCPIsGetReady((TCP_SOCKET)exSocket);
    if (!w)
        return 0;
    buffer[0] = 0;
    if (w)
    {
      wGetLen = w;
      TCPGetArray((TCP_SOCKET)exSocket, (BYTE *)buffer, len);
      if (send_count >= 4 && w < len)
      {
        GenericTCPState = EX_DISCONNECT;
      }
      socket = (long)exSocket;
      return len;
    }
  }

  return 0;
}
Esempio n. 19
0
/*****************************************************************************
  Function:
	int connect( SOCKET s, struct sockaddr* name, int namelen )

  Summary:
	This function connects to the peer communications end point.

  Description:
	The connect function assigns the address of the peer
	communications endpoint. For stream sockets, connection is
	established between the endpoints. For datagram sockets, an
	address filter is established between the endpoints until
	changed with another connect() function.

  Precondition:
	socket function should be called.

  Parameters:
	s - Socket descriptor returned from a previous call to socket.
	name - pointer to the sockaddr structure containing the
	peer address and port number.
	namelen - length of the sockaddr structure.

  Returns:
	If the connect() function succeeds, it returns 0. Otherwise,
	the value SOCKET_ERROR is returned to indicate an error
	condition. For stream based socket, if the connection is not
	established yet, connect returns SOCKET_CNXN_IN_PROGRESS.

  Remarks:
	None.
  ***************************************************************************/
int connect( SOCKET s, struct sockaddr* name, int namelen )
{
	struct BSDSocket *socket;
	struct sockaddr_in *addr;
	DWORD remoteIP;
	WORD remotePort;
	WORD localPort;

	if( s >= BSD_SOCKET_COUNT )
		return SOCKET_ERROR;

	socket = &BSDSocketArray[s];

	if( socket->bsdState < SKT_CREATED )
		return SOCKET_ERROR;

	if( (unsigned int)namelen < sizeof(struct sockaddr_in))
		return SOCKET_ERROR;

	addr = (struct sockaddr_in *)name;
	remotePort 	= addr->sin_port;
	remoteIP 	= addr->sin_addr.S_un.S_addr;

	if( remoteIP == 0u || remotePort == 0u )
		return SOCKET_ERROR;

	if( socket->SocketType == SOCK_STREAM )
	{
		switch(socket->bsdState)
		{
		case SKT_EST:
			return 0; // already established

		case SKT_IN_PROGRESS:
			if(HandlePossibleTCPDisconnection(s))
				return SOCKET_ERROR;

			if(!TCPIsConnected(socket->SocketID))
				return SOCKET_CNXN_IN_PROGRESS;

			socket->bsdState = SKT_EST;
			return 0; //success

		case SKT_CREATED:
		case SKT_BOUND:
			socket->SocketID = TCPOpen(remoteIP, TCP_OPEN_IP_ADDRESS, remotePort, TCP_PURPOSE_BERKELEY_CLIENT);
			if(socket->SocketID == INVALID_SOCKET)
				return SOCKET_ERROR;

			// Clear the first reset flag
			TCPWasReset(socket->SocketID);

			socket->isServer = FALSE;
			socket->bsdState = SKT_IN_PROGRESS;
			return SOCKET_CNXN_IN_PROGRESS;

		default:
			return SOCKET_ERROR;
		}
	}
	else
	{
		// If not explicitly bound to a local port, implicitly do the binding
		if(socket->bsdState == SKT_CREATED)
		{
			localPort = gAutoPortNumber++;
	        if(gAutoPortNumber > 5000u) // reset the port numbers
				gAutoPortNumber = 1024;

			//socket->SocketID = UDPOpen(localPort, NULL, remotePort);
			
			socket->SocketID = UDPOpenEx(0,UDP_OPEN_SERVER,localPort, remotePort);
			if(socket->SocketID == INVALID_UDP_SOCKET)
				return SOCKET_ERROR;
			socket->bsdState = SKT_BOUND;
		}
		if(socket->bsdState != SKT_BOUND)
			return SOCKET_ERROR;

		// UDP: remote port is used as a filter. Need to call connect when using
		// send/recv calls. No need to call 'connect' if using sendto/recvfrom 
		// calls.
		socket->remotePort = remotePort;
		socket->remoteIP = remoteIP;
		return 0; //success
	}
	return SOCKET_ERROR;
}
Esempio n. 20
0
/****************************************************************************
  Function:
    unsigned int ChipKITClientPutBuff(TCP_SOCKET hTCP, const BYTE * rgBuff, unsigned short cbWrite, unsigned int cSecTimeout)

  Description:
    This routine write out a buffer onto the wire

  Precondition:
    hTCP must be open and valid.

  Parameters:
    hTCP - The socket to check
	rgBuff - the buffer to write out.
	cbWrite - the number of bytes to write out.
	cSecTimout - The number of seconds to wait before aborting the write.

  Returns:
    Returns the number of bytes written, zero if none.

  Remarks:
	This is to match functionality of the Arduino Client class write method
	A flush to push the bytes out on the wire is done.
  ***************************************************************************/
unsigned int ChipKITClientPutBuff(TCP_SOCKET hTCP, const BYTE * rgBuff, unsigned short cbWrite, unsigned int cSecTimeout)
{
	WORD cbReady = 0;
	WORD cbPut = 0;
	WORD cbToWrite = 0;
	WORD cbPutTotal = 0;
	DWORD t = 0;

	// loop until this is written out, or timeout
	t = TickGet();
	while(cbWrite > 0) 
	{
		// get out if we lost connection
		if(!TCPIsConnected(hTCP))
		{
			break;
		}

		// see how much buffer space is available
		if((cbReady = TCPIsPutReady(hTCP)) > 0)
		{
			// only put out what we can
			cbToWrite = cbWrite > cbReady ? cbReady : cbWrite;

			// put the data out
			cbPut = TCPPutArray(hTCP, (BYTE *) &rgBuff[cbPutTotal], cbToWrite);

			// update our loop counters
			cbPutTotal += cbPut;
			cbWrite -= cbPut;
		}

		// if we are done get out
		if(cbWrite == 0)
		{
			break;
		}

		// check to see if we are moving forward
		else if(cbPut > 0) 
		{
			t = TickGet();	// reset wait timer, we are moving forward
		}

		// didn't move forward, see if we are timing out
		else if((TickGet() - t) >= (cSecTimeout * TICK_SECOND)) 
		{
			break;
		}

		// run our tasks so things can be put out and come in.
		cbPut = 0;	// to see if we are moving forward
		ChipKITPeriodicTasks();
	}
	
	if(TCPIsConnected(hTCP))
	{
		TCPFlush(hTCP);				// flush any remaining stuff out
	}

	ChipKITPeriodicTasks();		// run tasks to do it
	return(cbPutTotal);
}
Esempio n. 21
0
/*****************************************************************************
  Function:
	void SMTPTask(void)

  Summary:
	Performs any pending SMTP client tasks

  Description:
	This function handles periodic tasks associated with the SMTP client,
	such as processing initial connections and command sequences.

  Precondition:
	None

  Parameters:
	None

  Returns:
	None

  Remarks:
	This function acts as a task (similar to one in an RTOS).  It
	performs its task in a co-operative manner, and the main application
	must call this function repeatedly to ensure that all open or new
	connections are served in a timely fashion.
  ***************************************************************************/
void SMTPTask(void)
{
	BYTE			i;
	WORD			w;
	BYTE			vBase64Buffer[4];
	static DWORD	Timer;
	static BYTE		RXBuffer[4];
	static ROM BYTE *ROMStrPtr, *ROMStrPtr2;
	static BYTE 	*RAMStrPtr;
	static WORD		wAddressLength;

 WORD tmp;

	switch(TransportState)
	{
		case TRANSPORT_HOME:
			// SMTPBeginUsage() is the only function which will kick 
			// the state machine into the next state
			break;

		case TRANSPORT_BEGIN:
			// Wait for the user to program all the pointers and then 
			// call SMTPSendMail()
			if(!SMTPFlags.bits.ReadyToStart)
				break;

			// Obtain ownership of the DNS resolution module
			if(!DNSBeginUsage())
				break;

			// Obtain the IP address associated with the SMTP mail server
			if(SMTPClient.Server.szRAM || SMTPClient.Server.szROM)
			{
				if(SMTPClient.ROMPointers.Server)
					DNSResolveROM(SMTPClient.Server.szROM, DNS_TYPE_A);
				else
					DNSResolve(SMTPClient.Server.szRAM, DNS_TYPE_A);
			}
			else
			{
				// If we don't have a mail server, try to send the mail 
				// directly to the destination SMTP server
				if(SMTPClient.To.szRAM && !SMTPClient.ROMPointers.To)
				{
					SMTPClient.Server.szRAM = (BYTE*)strchr((char*)SMTPClient.To.szRAM, '@');
					SMTPClient.ROMPointers.Server = 0;
				}
				else if(SMTPClient.To.szROM && SMTPClient.ROMPointers.To)
				{
					SMTPClient.Server.szROM = (ROM BYTE*)strchrpgm((ROM char*)SMTPClient.To.szROM, '@');
					SMTPClient.ROMPointers.Server = 1;
				}

				if(!(SMTPClient.Server.szRAM || SMTPClient.Server.szROM))
				{
					if(SMTPClient.CC.szRAM && !SMTPClient.ROMPointers.CC)
					{
						SMTPClient.Server.szRAM = (BYTE*)strchr((char*)SMTPClient.CC.szRAM, '@');
						SMTPClient.ROMPointers.Server = 0;
					}
					else if(SMTPClient.CC.szROM && SMTPClient.ROMPointers.CC)
					{
						SMTPClient.Server.szROM = (ROM BYTE*)strchrpgm((ROM char*)SMTPClient.CC.szROM, '@');
						SMTPClient.ROMPointers.Server = 1;
					}
				}

				if(!(SMTPClient.Server.szRAM || SMTPClient.Server.szROM))
				{
					if(SMTPClient.BCC.szRAM && !SMTPClient.ROMPointers.BCC)
					{
						SMTPClient.Server.szRAM = (BYTE*)strchr((char*)SMTPClient.BCC.szRAM, '@');
						SMTPClient.ROMPointers.Server = 0;
					}
					else if(SMTPClient.BCC.szROM && SMTPClient.ROMPointers.BCC)
					{
						SMTPClient.Server.szROM = (ROM BYTE*)strchrpgm((ROM char*)SMTPClient.BCC.szROM, '@');
						SMTPClient.ROMPointers.Server = 1;
					}
				}

				// See if we found a hostname anywhere which we could resolve
				if(!(SMTPClient.Server.szRAM || SMTPClient.Server.szROM))
				{
					DNSEndUsage();
					ResponseCode = SMTP_RESOLVE_ERROR;
					TransportState = TRANSPORT_HOME;
					break;
				}

				// Skip over the @ sign and resolve the host name
				if(SMTPClient.ROMPointers.Server)
				{
					SMTPClient.Server.szROM++;
					DNSResolveROM(SMTPClient.Server.szROM, DNS_TYPE_MX);
				}
				else
				{
					SMTPClient.Server.szRAM++;
					DNSResolve(SMTPClient.Server.szRAM, DNS_TYPE_MX);
				}
			}
			
			Timer = TickGet();
			TransportState++;
			break;

		case TRANSPORT_NAME_RESOLVE:
			// Wait for the DNS server to return the requested IP address
			if(!DNSIsResolved(&SMTPServer))
			{
				// Timeout after 6 seconds of unsuccessful DNS resolution
				if(TickGet() - Timer > 6*TICK_SECOND)
				{
					ResponseCode = SMTP_RESOLVE_ERROR;
					TransportState = TRANSPORT_HOME;
					DNSEndUsage();
				}
				break;
			}

			// Release the DNS module, we no longer need it
			if(!DNSEndUsage())
			{
				// An invalid IP address was returned from the DNS 
				// server.  Quit and fail permanantly if host is not valid.
				ResponseCode = SMTP_RESOLVE_ERROR;
				TransportState = TRANSPORT_HOME;
				break;
			}

			TransportState++;
			// No need to break here

		case TRANSPORT_OBTAIN_SOCKET:
			// Connect a TCP socket to the remote SMTP server
			MySocket = TCPOpen(SMTPServer.Val, TCP_OPEN_IP_ADDRESS, SMTPClient.ServerPort, TCP_PURPOSE_DEFAULT);
			
			// Abort operation if no TCP sockets are available
			// If this ever happens, add some more 
			// TCP_PURPOSE_DEFAULT sockets in TCPIPConfig.h
			if(MySocket == INVALID_SOCKET)
				break;

			TransportState++;
			Timer = TickGet();
			// No break; fall into TRANSPORT_SOCKET_OBTAINED
			
		#if defined(STACK_USE_SSL_CLIENT)
		case TRANSPORT_SECURING_SOCKET:		
			if(!TCPIsConnected(MySocket))
			{
				// Don't stick around in the wrong state if the
				// server was connected, but then disconnected us.
				// Also time out if we can't establish the connection 
				// to the SMTP server
				if((LONG)(TickGet()-Timer) > (LONG)(SMTP_SERVER_REPLY_TIMEOUT))
				{
					ResponseCode = SMTP_CONNECT_ERROR;
					TransportState = TRANSPORT_CLOSE;
				}

				break;
			}
			SMTPFlags.bits.ConnectedOnce = TRUE;
			
			// Start SSL if needed for this connection
			if(SMTPClient.UseSSL && !TCPStartSSLClient(MySocket,NULL))
				break;
			
			// Move on to main state
			Timer = TickGet();
			TransportState++;
			break;		
		#endif

		case TRANSPORT_SOCKET_OBTAINED:
			if(!TCPIsConnected(MySocket))
			{
				// Don't stick around in the wrong state if the
				// server was connected, but then disconnected us.
				// Also time out if we can't establish the connection 
				// to the SMTP server
				if(SMTPFlags.bits.ConnectedOnce || ((LONG)(TickGet()-Timer) > (LONG)(SMTP_SERVER_REPLY_TIMEOUT)))
				{
					ResponseCode = SMTP_CONNECT_ERROR;
					TransportState = TRANSPORT_CLOSE;
				}

				break;
			}
			SMTPFlags.bits.ConnectedOnce = TRUE;
			
			#if defined(STACK_USE_SSL_CLIENT)
			// Make sure the SSL handshake has completed
			if(SMTPClient.UseSSL && TCPSSLIsHandshaking(MySocket))
				break;
			#endif

			// See if the server sent us anything
			while(TCPIsGetReady(MySocket))
			{
				TCPGet(MySocket, &i);
				switch(RXParserState)
				{
					case RX_BYTE_0:
					case RX_BYTE_1:
					case RX_BYTE_2:
						RXBuffer[RXParserState] = i;
						RXParserState++;
						break;
	
					case RX_BYTE_3:
						switch(i)
						{
							case ' ':
								SMTPFlags.bits.RXSkipResponse = FALSE;
								RXParserState++;
								break;
							case '-':
								SMTPFlags.bits.RXSkipResponse = TRUE;
								RXParserState++;
								break;
							case '\r':
								RXParserState = RX_SEEK_LF;
								break;
						}
						break;
	
					case RX_SEEK_CR:
						if(i == '\r')
							RXParserState++;
						break;
	
					case RX_SEEK_LF:
						// If we received the whole command
						if(i == '\n')
						{
							RXParserState = RX_BYTE_0;

							if(!SMTPFlags.bits.RXSkipResponse)
							{
								// The server sent us a response code
								// Null terminate the ASCII reponse code so we can convert it to an integer
								RXBuffer[3] = 0;
								ResponseCode = atoi((char*)RXBuffer);

								// Handle the response
								switch(SMTPState)
								{
									case SMTP_HELO_ACK:
										if(ResponseCode >= 200u && ResponseCode <= 299u)
										{
											if(SMTPClient.Username.szRAM || SMTPClient.Username.szROM)
												SMTPState = SMTP_AUTH_LOGIN;
											else
												SMTPState = SMTP_MAILFROM;
										}
										else
											SMTPState = SMTP_QUIT_INIT;
										break;


									case SMTP_AUTH_LOGIN_ACK:
									case SMTP_AUTH_USERNAME_ACK:
										if(ResponseCode == 334u)
											SMTPState++;
										else
											SMTPState = SMTP_QUIT_INIT;
										break;

									case SMTP_AUTH_PASSWORD_ACK:
										if(ResponseCode == 235u)
											SMTPState++;
										else
											SMTPState = SMTP_QUIT_INIT;
										break;

									case SMTP_HOME:
									case SMTP_MAILFROM_ACK:
									case SMTP_RCPTTO_ACK:
									case SMTP_RCPTTOCC_ACK:
									case SMTP_RCPTTOBCC_ACK:
                                                                            tmp = SMTPState;
										if(ResponseCode >= 200u && ResponseCode <= 299u)
											SMTPState++;
										else
											SMTPState = SMTP_QUIT_INIT;
										break;
							
									case SMTP_DATA_ACK:
										if(ResponseCode == 354u)
											SMTPState++;
										else
											SMTPState = SMTP_QUIT_INIT;
										break;
							
									case SMTP_DATA_BODY_ACK:
										if(ResponseCode >= 200u && ResponseCode <= 299u)
											SMTPFlags.bits.SentSuccessfully = TRUE;
							
										SMTPState = SMTP_QUIT_INIT;
										break;

									// Default case needed to supress compiler diagnostics
									default:
										break;
								}
							}
						}
						else if(i != '\r')
							RXParserState--;
	
						break;
				}
			}

			// Generate new data in the TX buffer, as needed, if possible
			if(TCPIsPutReady(MySocket) < 64u)
				break;

			switch(SMTPState)
			{
				case SMTP_HELO:
					if(SMTPClient.Username.szROM == NULL)
						TCPPutROMString(MySocket, (ROM BYTE*)"HELO MCHPBOARD\r\n");
					else
						TCPPutROMString(MySocket, (ROM BYTE*)"EHLO MCHPBOARD\r\n");
					TCPFlush(MySocket);
					SMTPState++;
					break;

				case SMTP_AUTH_LOGIN:
					// Note: This state is only entered from SMTP_HELO_ACK if the application 
					// has specified a Username to use (either SMTPClient.Username.szROM or 
					// SMTPClient.Username.szRAM is non-NULL)
					TCPPutROMString(MySocket, (ROM BYTE*)"AUTH LOGIN\r\n");
					TCPFlush(MySocket);
					SMTPState++;
					break;

				case SMTP_AUTH_USERNAME:
					// Base 64 encode and transmit the username.
					if(SMTPClient.ROMPointers.Username)
					{
						ROMStrPtr = SMTPClient.Username.szROM;
						w = strlenpgm((ROM char*)ROMStrPtr);
					}
					else
					{
						RAMStrPtr = SMTPClient.Username.szRAM;
						w = strlen((char*)RAMStrPtr);
					}

					while(w)
					{
						i = 0;
						while((i < w) && (i < sizeof(vBase64Buffer)*3/4))
						{
							if(SMTPClient.ROMPointers.Username)
								vBase64Buffer[i] = *ROMStrPtr++;
							else
								vBase64Buffer[i] = *RAMStrPtr++;
							i++;
						}
						w -= i;					
						Base64Encode(vBase64Buffer, i, vBase64Buffer, sizeof(vBase64Buffer));
						TCPPutArray(MySocket, vBase64Buffer, sizeof(vBase64Buffer));
					}
					TCPPutROMString(MySocket, (ROM BYTE*)"\r\n");
					TCPFlush(MySocket);
					SMTPState++;
					break;

				case SMTP_AUTH_PASSWORD:
					// Base 64 encode and transmit the password
					if(SMTPClient.ROMPointers.Password)
					{
						ROMStrPtr = SMTPClient.Password.szROM;
						w = strlenpgm((ROM char*)ROMStrPtr);
					}
					else
					{
						RAMStrPtr = SMTPClient.Password.szRAM;
						w = strlen((char*)RAMStrPtr);
					}

					while(w)
					{
						i = 0;
						while((i < w) && (i < sizeof(vBase64Buffer)*3/4))
						{
							if(SMTPClient.ROMPointers.Password)
								vBase64Buffer[i] = *ROMStrPtr++;
							else
								vBase64Buffer[i] = *RAMStrPtr++;
							i++;
						}
						w -= i;					
						Base64Encode(vBase64Buffer, i, vBase64Buffer, sizeof(vBase64Buffer));
						TCPPutArray(MySocket, vBase64Buffer, sizeof(vBase64Buffer));
					}
					TCPPutROMString(MySocket, (ROM BYTE*)"\r\n");
					TCPFlush(MySocket);
					SMTPState++;
					break;

				case SMTP_MAILFROM:
					// Send MAIL FROM header.  Note that this is for the SMTP server validation, 
					// not what actually will be displayed in the recipients mail client as a 
					// return address.
					TCPPutROMString(MySocket, (ROM BYTE*)"MAIL FROM:<");
					if(SMTPClient.ROMPointers.From)
					{
						ROMStrPtr = FindROMEmailAddress(SMTPClient.From.szROM, &wAddressLength);
						TCPPutROMArray(MySocket, ROMStrPtr, wAddressLength);
					}
					else
					{
						RAMStrPtr = FindEmailAddress(SMTPClient.From.szRAM, &wAddressLength);
						TCPPutArray(MySocket, RAMStrPtr, wAddressLength);
					}
					TCPPutROMString(MySocket, (ROM BYTE*)">\r\n");
					TCPFlush(MySocket);
					SMTPState++;
					break;

				case SMTP_RCPTTO_INIT:
					// See if there are any (To) recipients to process
					if(SMTPClient.To.szRAM && !SMTPClient.ROMPointers.To)
					{
						RAMStrPtr = FindEmailAddress(SMTPClient.To.szRAM, &wAddressLength);
						if(wAddressLength)
						{
							SMTPState = SMTP_RCPTTO;
							break;
						}
					}
					if(SMTPClient.To.szROM && SMTPClient.ROMPointers.To)
					{
						ROMStrPtr = FindROMEmailAddress(SMTPClient.To.szROM, &wAddressLength);
						if(wAddressLength)
						{
							SMTPState = SMTP_RCPTTO;
							break;
						}
					}
					
					SMTPState = SMTP_RCPTTOCC_INIT;
					break;

				case SMTP_RCPTTO:
				case SMTP_RCPTTOCC:
				case SMTP_RCPTTOBCC:
					TCPPutROMString(MySocket, (ROM BYTE*)"RCPT TO:<");
					if(	(SMTPClient.ROMPointers.To  && (SMTPState == SMTP_RCPTTO)) || 
						(SMTPClient.ROMPointers.CC  && (SMTPState == SMTP_RCPTTOCC)) || 
						(SMTPClient.ROMPointers.BCC && (SMTPState == SMTP_RCPTTOBCC)) )
						TCPPutROMArray(MySocket, ROMStrPtr, wAddressLength);
					else
						TCPPutArray(MySocket, RAMStrPtr, wAddressLength);
					TCPPutROMString(MySocket, (ROM BYTE*)">\r\n");
					TCPFlush(MySocket);
					SMTPState++;
					break;

				case SMTP_RCPTTO_ISDONE:
					// See if we have any more (To) recipients to process
					// If we do, we must roll back a couple of states
					if(SMTPClient.ROMPointers.To)
						ROMStrPtr = FindROMEmailAddress(ROMStrPtr+wAddressLength, &wAddressLength);
					else
						RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength);
	
					if(wAddressLength)
					{
						SMTPState = SMTP_RCPTTO;
						break;
					}

					// All done with To field
					SMTPState++;
					//No break

				case SMTP_RCPTTOCC_INIT:
					// See if there are any Carbon Copy (CC) recipients to process
					if(SMTPClient.CC.szRAM && !SMTPClient.ROMPointers.CC)
					{
						RAMStrPtr = FindEmailAddress(SMTPClient.CC.szRAM, &wAddressLength);
						if(wAddressLength)
						{
							SMTPState = SMTP_RCPTTOCC;
							break;
						}
					}
					if(SMTPClient.CC.szROM && SMTPClient.ROMPointers.CC)
					{
						ROMStrPtr = FindROMEmailAddress(SMTPClient.CC.szROM, &wAddressLength);
						if(wAddressLength)
						{
							SMTPState = SMTP_RCPTTOCC;
							break;
						}
					}
					
					SMTPState = SMTP_RCPTTOBCC_INIT;
					break;

				case SMTP_RCPTTOCC_ISDONE:
					// See if we have any more Carbon Copy (CC) recipients to process
					// If we do, we must roll back a couple of states
					if(SMTPClient.ROMPointers.CC)
						ROMStrPtr = FindROMEmailAddress(ROMStrPtr+wAddressLength, &wAddressLength);
					else
						RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength);

					if(wAddressLength)
					{
						SMTPState = SMTP_RCPTTOCC;
						break;
					}

					// All done with CC field
					SMTPState++;
					//No break

				case SMTP_RCPTTOBCC_INIT:
					// See if there are any Blind Carbon Copy (BCC) recipients to process
					if(SMTPClient.BCC.szRAM && !SMTPClient.ROMPointers.BCC)
					{
						RAMStrPtr = FindEmailAddress(SMTPClient.BCC.szRAM, &wAddressLength);
						if(wAddressLength)
						{
							SMTPState = SMTP_RCPTTOBCC;
							break;
						}
					}
					if(SMTPClient.BCC.szROM && SMTPClient.ROMPointers.BCC)
					{
						ROMStrPtr = FindROMEmailAddress(SMTPClient.BCC.szROM, &wAddressLength);
						if(wAddressLength)
						{
							SMTPState = SMTP_RCPTTOBCC;
							break;
						}
					}

					// All done with BCC field
					SMTPState = SMTP_DATA;
					break;

				case SMTP_RCPTTOBCC_ISDONE:
					// See if we have any more Blind Carbon Copy (CC) recipients to process
					// If we do, we must roll back a couple of states
					if(SMTPClient.ROMPointers.BCC)
						ROMStrPtr = FindROMEmailAddress(ROMStrPtr+wAddressLength, &wAddressLength);
					else
						RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength);

					if(wAddressLength)
					{
						SMTPState = SMTP_RCPTTOBCC;
						break;
					}

					// All done with BCC field
					SMTPState++;
					//No break

				case SMTP_DATA:
					TCPPutROMString(MySocket, (ROM BYTE*)"DATA\r\n");
					SMTPState++;
					PutHeadersState = PUTHEADERS_FROM_INIT;
					TCPFlush(MySocket);
					break;

				case SMTP_DATA_HEADER:
					while((PutHeadersState != PUTHEADERS_DONE) && (TCPIsPutReady(MySocket) > 64u))
					{
						switch(PutHeadersState)
						{
							case PUTHEADERS_FROM_INIT:
								if(SMTPClient.From.szRAM || SMTPClient.From.szROM)
								{
									PutHeadersState = PUTHEADERS_FROM;
									TCPPutROMString(MySocket, (ROM BYTE*)"From: ");
								}
								else
								{
									PutHeadersState = PUTHEADERS_TO_INIT;
								}
								break;
								
							case PUTHEADERS_FROM:
								if(SMTPClient.ROMPointers.From)
								{
									SMTPClient.From.szROM = TCPPutROMString(MySocket, SMTPClient.From.szROM);
									if(*SMTPClient.From.szROM == 0u)
										PutHeadersState = PUTHEADERS_TO_INIT;
								}
								else
								{
									SMTPClient.From.szRAM = TCPPutString(MySocket, SMTPClient.From.szRAM);
									if(*SMTPClient.From.szRAM == 0u)
										PutHeadersState = PUTHEADERS_TO_INIT;
								}
								break;

							case PUTHEADERS_TO_INIT:
								if(SMTPClient.To.szRAM || SMTPClient.To.szROM)
								{
									PutHeadersState = PUTHEADERS_TO;
									TCPPutROMString(MySocket, (ROM BYTE*)"\r\nTo: ");
								}
								else
								{
									PutHeadersState = PUTHEADERS_CC_INIT;
								}
								break;
								
							case PUTHEADERS_TO:
								if(SMTPClient.ROMPointers.To)
								{
									SMTPClient.To.szROM = TCPPutROMString(MySocket, SMTPClient.To.szROM);
									if(*SMTPClient.To.szROM == 0u)
										PutHeadersState = PUTHEADERS_CC_INIT;
								}
								else
								{
									SMTPClient.To.szRAM = TCPPutString(MySocket, SMTPClient.To.szRAM);
									if(*SMTPClient.To.szRAM == 0u)
										PutHeadersState = PUTHEADERS_CC_INIT;
								}
								break;

							case PUTHEADERS_CC_INIT:
								if(SMTPClient.CC.szRAM || SMTPClient.CC.szROM)
								{
									PutHeadersState = PUTHEADERS_CC;
									TCPPutROMString(MySocket, (ROM BYTE*)"\r\nCC: ");
								}
								else
								{
									PutHeadersState = PUTHEADERS_SUBJECT_INIT;
								}
								break;
								
							case PUTHEADERS_CC:
								if(SMTPClient.ROMPointers.CC)
								{
									SMTPClient.CC.szROM = TCPPutROMString(MySocket, SMTPClient.CC.szROM);
									if(*SMTPClient.CC.szROM == 0u)
										PutHeadersState = PUTHEADERS_SUBJECT_INIT;
								}
								else
								{
									SMTPClient.CC.szRAM = TCPPutString(MySocket, SMTPClient.CC.szRAM);
									if(*SMTPClient.CC.szRAM == 0u)
										PutHeadersState = PUTHEADERS_SUBJECT_INIT;
								}
								break;

							case PUTHEADERS_SUBJECT_INIT:
								if(SMTPClient.Subject.szRAM || SMTPClient.Subject.szROM)
								{
									PutHeadersState = PUTHEADERS_SUBJECT;
									TCPPutROMString(MySocket, (ROM BYTE*)"\r\nSubject: ");
								}
								else
								{
									PutHeadersState = PUTHEADERS_OTHER_INIT;
								}
								break;
								
							case PUTHEADERS_SUBJECT:
								if(SMTPClient.ROMPointers.Subject)
								{
									SMTPClient.Subject.szROM = TCPPutROMString(MySocket, SMTPClient.Subject.szROM);
									if(*SMTPClient.Subject.szROM == 0u)
										PutHeadersState = PUTHEADERS_OTHER_INIT;
								}
								else
								{
									SMTPClient.Subject.szRAM = TCPPutString(MySocket, SMTPClient.Subject.szRAM);
									if(*SMTPClient.Subject.szRAM == 0u)
										PutHeadersState = PUTHEADERS_OTHER_INIT;
								}
								break;

							case PUTHEADERS_OTHER_INIT:
								TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2);
								if(SMTPClient.OtherHeaders.szRAM || SMTPClient.OtherHeaders.szROM)
								{
									PutHeadersState = PUTHEADERS_OTHER;
								}
								else
								{
									TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2);
									PutHeadersState = PUTHEADERS_DONE;
									SMTPState++;
								}
								break;
								
							case PUTHEADERS_OTHER:
								if(SMTPClient.ROMPointers.OtherHeaders)
								{
									SMTPClient.OtherHeaders.szROM = TCPPutROMString(MySocket, SMTPClient.OtherHeaders.szROM);
									if(*SMTPClient.OtherHeaders.szROM == 0u)
									{
										TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2);
										PutHeadersState = PUTHEADERS_DONE;
										SMTPState++;
									}
								}
								else
								{
									SMTPClient.OtherHeaders.szRAM = TCPPutString(MySocket, SMTPClient.OtherHeaders.szRAM);
									if(*SMTPClient.OtherHeaders.szRAM == 0u)
									{
										TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2);
										PutHeadersState = PUTHEADERS_DONE;
										SMTPState++;
									}
								}
								break;
							
							// Default case needed to supress compiler diagnostics
							default:
								break;
						}
					}
					TCPFlush(MySocket);
					break;
		
				case SMTP_DATA_BODY_INIT:
					SMTPState++;
					RAMStrPtr = SMTPClient.Body.szRAM;
					ROMStrPtr2 = (ROM BYTE*)"\r\n.\r\n";
					CRPeriod.Pos = NULL;
					if(RAMStrPtr)
						CRPeriod.Pos = (BYTE*)strstrrampgm((char*)RAMStrPtr, (ROM char*)"\r\n.");
					// No break here
		
				case SMTP_DATA_BODY:
					if(SMTPClient.Body.szRAM || SMTPClient.Body.szROM)
					{
						if(*ROMStrPtr2)
						{
							// Put the application data, doing the transparancy replacement of "\r\n." with "\r\n.."
							while(CRPeriod.Pos)
							{
								CRPeriod.Pos += 3;
								RAMStrPtr += TCPPutArray(MySocket, RAMStrPtr, CRPeriod.Pos-RAMStrPtr);
								if(RAMStrPtr == CRPeriod.Pos)
								{
									if(!TCPPut(MySocket, '.'))
									{
										CRPeriod.Pos -= 3;
										break;
									}
								}
								else
								{
									CRPeriod.Pos -= 3;
									break;
								}
								CRPeriod.Pos = (BYTE*)strstrrampgm((char*)RAMStrPtr, (ROM char*)"\r\n.");
							}
							
							// If we get down here, either all replacements have been made or there is no remaining space in the TCP output buffer
							RAMStrPtr = TCPPutString(MySocket, RAMStrPtr);
							ROMStrPtr2 = TCPPutROMString(MySocket, ROMStrPtr2);
							TCPFlush(MySocket);
						}
					}
					else
					{
						if(SMTPFlags.bits.ReadyToFinish)
						{
							if(*ROMStrPtr2)
							{
								ROMStrPtr2 = TCPPutROMString(MySocket, ROMStrPtr2);
								TCPFlush(MySocket);
							}
		
						}
					}

					if(*ROMStrPtr2 == 0u)
					{
						SMTPState++;
					}
					break;
		
				case SMTP_QUIT_INIT:
					SMTPState++;
					ROMStrPtr = (ROM BYTE*)"QUIT\r\n";
					// No break here

				case SMTP_QUIT:
					if(*ROMStrPtr)
					{
						ROMStrPtr = TCPPutROMString(MySocket, ROMStrPtr);
						TCPFlush(MySocket);
					}

					if(*ROMStrPtr == 0u)
					{
						TransportState = TRANSPORT_CLOSE;
					}
					break;
				
				// Default case needed to supress compiler diagnostics
				default:
					break;
			}
			break;

		case TRANSPORT_CLOSE:
			// Close the socket so it can be used by other modules
			TCPDisconnect(MySocket);
			MySocket = INVALID_SOCKET;

			// Go back to doing nothing
			TransportState = TRANSPORT_HOME;
			break;
	}
}
Esempio n. 22
0
/*********************************************************************
 * Function:        void UART2TCPBridgeTask(void)
 *
 * PreCondition:    Stack is initialized()
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        None
 *
 * Note:            None
 ********************************************************************/
void UART2TCPBridgeTask(void)
{
	static enum _BridgeState
	{
		SM_HOME = 0,
		SM_SOCKET_OBTAINED
	} BridgeState = SM_HOME;
	static TCP_SOCKET MySocket = INVALID_SOCKET;
	WORD wMaxPut, wMaxGet, w;
	BYTE *RXHeadPtrShadow, *RXTailPtrShadow;
	BYTE *TXHeadPtrShadow, *TXTailPtrShadow;


	switch(BridgeState)
	{
		case SM_HOME:
			#if defined(USE_REMOTE_TCP_SERVER)
				// Connect a socket to the remote TCP server
				MySocket = TCPOpen((DWORD)USE_REMOTE_TCP_SERVER, TCP_OPEN_ROM_HOST, UART2TCPBRIDGE_PORT, TCP_PURPOSE_UART_2_TCP_BRIDGE);
			#else
				MySocket = TCPOpen(0, TCP_OPEN_SERVER, UART2TCPBRIDGE_PORT, TCP_PURPOSE_UART_2_TCP_BRIDGE);
			#endif
			
			// Abort operation if no TCP socket of type TCP_PURPOSE_UART_2_TCP_BRIDGE is available
			// If this ever happens, you need to go add one to TCPIPConfig.h
			if(MySocket == INVALID_SOCKET)
				break;

			// Eat the first TCPWasReset() response so we don't 
			// infinitely create and reset/destroy client mode sockets
			TCPWasReset(MySocket);
			
			// We have a socket now, advance to the next state
			BridgeState = SM_SOCKET_OBTAINED;
			break;

		case SM_SOCKET_OBTAINED:
			// Reset all buffers if the connection was lost
			if(TCPWasReset(MySocket))
			{
				// Optionally discard anything in the UART FIFOs
				//RXHeadPtr = vUARTRXFIFO;
				//RXTailPtr = vUARTRXFIFO;
				//TXHeadPtr = vUARTTXFIFO;
				//TXTailPtr = vUARTTXFIFO;
				
				// If we were a client socket, close the socket and attempt to reconnect
				#if defined(USE_REMOTE_TCP_SERVER)
					TCPDisconnect(MySocket);
					MySocket = INVALID_SOCKET;
					BridgeState = SM_HOME;
					break;
				#endif
			}
		
			// Don't do anything if nobody is connected to us
			if(!TCPIsConnected(MySocket))
				break;
			
			
			// Make sure to clear UART errors so they don't block all future operations
			#if defined(__18CXX)
			if(RCSTAbits.OERR)
			{
				RCSTAbits.CREN = 0;
				RCSTAbits.CREN = 1;
				LED1_IO ^= 1;
			}
			if(RCSTAbits.FERR)
			{
				BYTE dummy = RCREG;
				LED2_IO ^= 1;
			}
			#else
			if(U2STAbits.OERR)
				U2STAbits.OERR = 0;
			#endif
			

			// Read FIFO pointers into a local shadow copy.  Some pointers are volatile 
			// (modified in the ISR), so we must do this safely by disabling interrupts
			RXTailPtrShadow = (BYTE*)RXTailPtr;
			TXHeadPtrShadow = (BYTE*)TXHeadPtr;
			#if defined(__18CXX)
			PIE1bits.RCIE = 0;
			PIE1bits.TXIE = 0;
			#else
			IEC1bits.U2RXIE = 0;
			IEC1bits.U2TXIE = 0;
			#endif
			RXHeadPtrShadow = (BYTE*)RXHeadPtr;
			TXTailPtrShadow = (BYTE*)TXTailPtr;
			#if defined(__18CXX)
			PIE1bits.RCIE = 1;
			if(TXHeadPtrShadow != TXTailPtrShadow)
				PIE1bits.TXIE = 1;
			#else
			IEC1bits.U2RXIE = 1;
			if(TXHeadPtrShadow != TXTailPtrShadow)
				IEC1bits.U2TXIE = 1;
			#endif

			//
			// Transmit pending data that has been placed into the UART RX FIFO (in the ISR)
			//
			wMaxPut = TCPIsPutReady(MySocket);	// Get TCP TX FIFO space
			wMaxGet = RXHeadPtrShadow - RXTailPtrShadow;	// Get UART RX FIFO byte count
			if(RXHeadPtrShadow < RXTailPtrShadow)
				wMaxGet += sizeof(vUARTRXFIFO);
			if(wMaxPut > wMaxGet)				// Calculate the lesser of the two
				wMaxPut = wMaxGet;
			if(wMaxPut)							// See if we can transfer anything
			{
				// Transfer the data over.  Note that a two part put 
				// may be needed if the data spans the vUARTRXFIFO 
				// end to start address.
				w = vUARTRXFIFO + sizeof(vUARTRXFIFO) - RXTailPtrShadow;
				if(wMaxPut >= w)
				{
					TCPPutArray(MySocket, RXTailPtrShadow, w);
					RXTailPtrShadow = vUARTRXFIFO;
					wMaxPut -= w;
				}
				TCPPutArray(MySocket, RXTailPtrShadow, wMaxPut);
				RXTailPtrShadow += wMaxPut;

				// No flush.  The stack will automatically flush and do 
				// transmit coallescing to minimize the number of TCP 
				// packets that get sent.  If you explicitly call TCPFlush()
				// here, latency will go down, but so will max throughput 
				// and bandwidth efficiency.
			}

			//
			// Transfer received TCP data into the UART TX FIFO for future transmission (in the ISR)
			//
			wMaxGet = TCPIsGetReady(MySocket);	// Get TCP RX FIFO byte count
			wMaxPut = TXTailPtrShadow - TXHeadPtrShadow - 1;// Get UART TX FIFO free space
			if(TXHeadPtrShadow >= TXTailPtrShadow)
				wMaxPut += sizeof(vUARTTXFIFO);
			if(wMaxPut > wMaxGet)				// Calculate the lesser of the two
				wMaxPut = wMaxGet;
			if(wMaxPut)							// See if we can transfer anything
			{
				// Transfer the data over.  Note that a two part put 
				// may be needed if the data spans the vUARTTXFIFO 
				// end to start address.
				w = vUARTTXFIFO + sizeof(vUARTTXFIFO) - TXHeadPtrShadow;
				if(wMaxPut >= w)
				{
					TCPGetArray(MySocket, TXHeadPtrShadow, w);
					TXHeadPtrShadow = vUARTTXFIFO;
					wMaxPut -= w;
				}
				TCPGetArray(MySocket, TXHeadPtrShadow, wMaxPut);
				TXHeadPtrShadow += wMaxPut;
			}
			
			// Write local shadowed FIFO pointers into the volatile FIFO pointers.
			#if defined(__18CXX)
			PIE1bits.RCIE = 0;
			PIE1bits.TXIE = 0;
			#else
			IEC1bits.U2RXIE = 0;
			IEC1bits.U2TXIE = 0;
			#endif
			RXTailPtr = (volatile BYTE*)RXTailPtrShadow;
			TXHeadPtr = (volatile BYTE*)TXHeadPtrShadow;
			#if defined(__18CXX)
			PIE1bits.RCIE = 1;
			if(TXHeadPtrShadow != TXTailPtrShadow)
				PIE1bits.TXIE = 1;
			#else
			IEC1bits.U2RXIE = 1;
			if(TXHeadPtrShadow != TXTailPtrShadow)
				IEC1bits.U2TXIE = 1;
			#endif

			break;
	}
}
void twatchTasks(char frameAdvance){ //this state machine services the #twatch

   static enum _twatchState
	{
		TWATCH_INIT=0,
		TWATCH_IDLE,
		TWATCH_TRENDS_TCP_START,
		TWATCH_TRENDS_TCP_SOCKET_OBTAINED,
		TWATCH_TRENDS_TCP_PROCESS_RESPONSE,
		TWATCH_TRENDS_TCP_DISCONNECT,
		TWATCH_SEARCH_TCP_START,
		TWATCH_SEARCH_TCP_SOCKET_OBTAINED,
		TWATCH_SEARCH_TCP_PROCESS_RESPONSE,
		TWATCH_SEARCH_TCP_DISCONNECT,
	} twatchState = TWATCH_INIT; //massive twitter parsing state machine

   static enum _HTTPstatus
	{
		UNKNOWN=0,
		OK,
		ERROR,
	} HTTPstatus = UNKNOWN; //get and track HTTP status and handle errors
	static unsigned char HTTPheaderBuf[20]; //used to store HTTP headers 
	static unsigned char HTTPheaderBufCnt; //pointer

	static BYTE refreshFeeds=0, HTTPretry=0, URLencode[]="%20";//extra static vars for twitter parser

	BYTE 				i,k;
	WORD				w;
	BYTE				vBuffer[51];
	BYTE				cnt;
	static TICK			Timer;
	static TCP_SOCKET	MySocket = INVALID_SOCKET;
	
	if(frameAdvance==1) refreshFeeds++; //counts the minutes

	switch(twatchState)
	{
		case TWATCH_INIT:
			trendParser.success=0; //clear these flag on first run
			searchParser.success=0;//display IP address and info until valid connection
			twatchState=TWATCH_TRENDS_TCP_START; //start TCP data grabber next cycle
			break;
		case TWATCH_IDLE:	//if this variable set, then start the refresh process		
			if(refreshFeeds>TWATCH_REFRESH_INTERVAL){ //if it has been at least 5 minutes, get new trends and tweet search results
				refreshFeeds=0;
				HTTPretry=0; //reset the number of retries
				twatchState=TWATCH_TRENDS_TCP_START; //start TCP data grabber next cycle
			}
			break;
		case TWATCH_TRENDS_TCP_START:
			//connect to twitter server
			MySocket = TCPOpen((DWORD)&ServerName[0], TCP_OPEN_RAM_HOST, ServerPort, TCP_PURPOSE_GENERIC_TCP_CLIENT);
			
			if(MySocket == INVALID_SOCKET) break; //abort if error, try again next time
			
			trendParser.updatingData=1; //updating data flag (probably not used anywhere)
			displayMode=UPDATE; //next LCD refresh will draw the update screen and then idle
			twatchState=TWATCH_TRENDS_TCP_SOCKET_OBTAINED;
			Timer = TickGet();
			break;

		case TWATCH_TRENDS_TCP_SOCKET_OBTAINED:
			// Wait for the remote server to accept our connection request
			if(!TCPIsConnected(MySocket))
			{
				// Time out if too much time is spent in this state
				if(TickGet()-Timer > 5*TICK_SECOND)
				{
					// Close the socket so it can be used by other modules
					TCPDisconnect(MySocket);
					MySocket = INVALID_SOCKET;
					twatchState--;
				}
				break;
			}

			Timer = TickGet();

			if(TCPIsPutReady(MySocket) < 125u) break; //if socket error, break and wait
	
			//form our trending topics JSON datafeed request
			TCPPutROMString(MySocket, (ROM BYTE*)"GET ");
			TCPPutROMString(MySocket, TrendURL); //use the trend URL
			TCPPutROMString(MySocket, (ROM BYTE*)" HTTP/1.0\r\nHost: ");
			TCPPutString(MySocket, ServerName);
			TCPPutROMString(MySocket, (ROM BYTE*)"\r\nConnection: close\r\n\r\n");

			TCPFlush(MySocket); //send HTTP request to Twitter
			
			//setup/clear the parser struct
			trendParser.bufWritePointer=0;
			trendParser.foundTag=0;
			trendParser.tagCharMatchCnt=0;
			trendParser.tagTotalCnt=0;
			trendParser.bufWritePointer=0;
			searchParser.bufWritePointer=0;//reset the tweet buffer write pointer
			searchParser.term=0; //reset the number of terns in the tweet search parser structure
			for(i=0; i<MAX_TREND_TERMS; i++) searchParser.bufValueEndPosition[i]=0;//reset all buffer positions to 0
			HTTPstatus = UNKNOWN; //reset the http status checker
			HTTPheaderBufCnt=0; //status checker buffer counter

			twatchState=TWATCH_TRENDS_TCP_PROCESS_RESPONSE; //next time process any incoming data
			break;

		case TWATCH_TRENDS_TCP_PROCESS_RESPONSE:

			if(!TCPIsConnected(MySocket)) twatchState = TWATCH_TRENDS_TCP_DISCONNECT; //check if we're still connected // Do not break;  We might still have data in the TCP RX FIFO waiting for us
	
			w = TCPIsGetReady(MySocket);//how many bytes waiting?	
	
			//process the server reply
			i = sizeof(vBuffer)-1;
			vBuffer[i] = '\0';
			while(w){
				if(w < i){
					i = w;
					vBuffer[i] = '\0';
				}
				w -= TCPGetArray(MySocket, vBuffer, i);

				for(cnt=0;cnt<i;cnt++){
					//---------------//
					switch(HTTPstatus){ //check the first few bytes for HTTP/1.1 200 OK
						case UNKNOWN: //cache until a line break, then check header for response code before extracting tags
							HTTPheaderBuf[HTTPheaderBufCnt]=vBuffer[cnt];//add to the headerbuf array
							if(HTTPheaderBufCnt<19) HTTPheaderBufCnt++; //if it won't overrun the array, increment the counter
						
							if(vBuffer[cnt]==0x0d){//if current character is a line break, examine the header for the response code
								//is it HTTP?
								if(HTTPheaderBuf[0]=='H' &&	HTTPheaderBuf[1]=='T' && 
								HTTPheaderBuf[2]=='T' && HTTPheaderBuf[3]=='P' ){						
									//loop past /1.x and space
									HTTPheaderBufCnt=4;
									while(HTTPheaderBuf[HTTPheaderBufCnt]!=' '){
										HTTPheaderBufCnt++;
										if(HTTPheaderBufCnt>19) break; //buffer overrun
									}
									HTTPheaderBufCnt++;
									//is it 200? (should be a ASCII->int loop that gets the actual value for error handling.... check for overrun
									if( (HTTPheaderBufCnt <=17 ) && HTTPheaderBuf[HTTPheaderBufCnt]=='2' &&	HTTPheaderBuf[HTTPheaderBufCnt+1]=='0' && 
										HTTPheaderBuf[HTTPheaderBufCnt+2]=='0'){
										HTTPstatus=OK;//200 OK
									}else{
										HTTPstatus=ERROR; //other status, error
									}
								}
							}
							break;
						case OK: //HTTP is OK, process the byte
							procTrend(vBuffer[cnt]); //json parsing state maching
							break;
						case ERROR://do nothing because we need to clear the buffer
							break;
					}
					//------------------//
				}//for loop
				
				if(twatchState == TWATCH_TRENDS_TCP_PROCESS_RESPONSE) break;
			}//while
	
			break;
	
		case TWATCH_TRENDS_TCP_DISCONNECT:
			TCPDisconnect(MySocket); //close the socket
			MySocket = INVALID_SOCKET;
	
			//did not get valid HTML, retry, got no tags, retry
			if(HTTPstatus!=OK || trendParser.tagTotalCnt==0 ){
				HTTPretry++;
				if(HTTPretry>HTTP_MAX_RETRY){//retry 3 times, then wait a minute....
					twatchState = TWATCH_IDLE;
					LCD_CursorPosition(21); //display waiting error
					LCD_WriteString("*Error, waiting 5min");
					break;
				}
				LCD_CursorPosition(21); //display retry error
				LCD_WriteString("*Error, reconnecting");
				twatchState = TWATCH_TRENDS_TCP_START;
				break;
			}
			HTTPretry=0;
		
			addToTrendBuffer(' ');//add trailing space
			
			trendParser.updatingData=0; //data update complete, clear update flag
			if(trendParser.success==0){ //if this is the first time throuigh, set the success flag
				trendParser.success=1; //set success flag, used to identify the very first successful xfer and clear IP address screen
				LCD_refresh(); //clear IP, show update screen
			}
			displayMode=NEWSCROLL;//start scrolling the terms, tweets will show when available in the parser struct
			twatchState = TWATCH_SEARCH_TCP_START; //will start searching on each term next time. searchParser.term set to 0 above...
			break;

		case TWATCH_SEARCH_TCP_START: //begins searching for recent tweets for each trending term
			
			//don't continue if there's no more term, an error, or overrun
			if(searchParser.term>=trendParser.tagTotalCnt || searchParser.term>=MAX_TREND_TERMS ){//don't continue if there's no more terms left to search
				twatchState = TWATCH_IDLE; //go back to idle
				break;
			}
			
			//skip if 0 length term
			if(trendParser.bufValueStartPosition[searchParser.term]==trendParser.bufValueEndPosition[searchParser.term]) {
				searchParser.term++; //increment to next trend term
				twatchState = TWATCH_SEARCH_TCP_START; //try again with the next trend term
				break;
			}
		
			//connect to twitter
			MySocket = TCPOpen((DWORD)&ServerName[0], TCP_OPEN_RAM_HOST, ServerPort, TCP_PURPOSE_GENERIC_TCP_CLIENT);

			if(MySocket == INVALID_SOCKET) break; //abort on error

			twatchState=TWATCH_SEARCH_TCP_SOCKET_OBTAINED;
			Timer = TickGet();
			break;

		case TWATCH_SEARCH_TCP_SOCKET_OBTAINED:
			// Wait for the remote server to accept our connection request
			if(!TCPIsConnected(MySocket)){
				// Time out if too much time is spent in this state
				if(TickGet()-Timer > 5*TICK_SECOND){
					// Close the socket so it can be used by other modules
					TCPDisconnect(MySocket);
					MySocket = INVALID_SOCKET;
					twatchState--;
					//searchParser.term++; //increment to next trend term, don't get stuck in loop
										//should add retries
				}
				break;
			}

			Timer = TickGet();

			if(TCPIsPutReady(MySocket) < 125u) break; //socket ready for writes?

			
			TCPPutROMString(MySocket, (ROM BYTE*)"GET "); //setup the HTTP GET request 
			TCPPutROMString(MySocket, SearchURL);	//JSON search datafeed URL
			#ifndef JSON_DEBUG
			//add the search term to the JSON search URL. Requires urlencoding
			i=trendParser.bufValueStartPosition[searchParser.term]; //get the starting position of the term in the trend term buffer
			k=trendParser.bufValueEndPosition[searchParser.term]-1; //end position is one less because of auto increment
			//add each character of the trend term to the search URL
			while((i<k) && i<TREND_PARSER_BUFFER ){ //append each byte to the URL until the end position
				//URLencode anything not a-zA-Z0-9 -_.!~*'()
				if(URLencodeChar(trendParser.buf[i], &URLencode[0])==0){
					TCPPut(MySocket, trendParser.buf[i]); //no URLencode required;
				}else{
					TCPPutString(MySocket, URLencode); //use the URLencoded character now in URLencode array
				}
				i++;
			}
			#endif
			//form the rest of the HTTP request
			TCPPutROMString(MySocket, (ROM BYTE*)" HTTP/1.0\r\nHost: ");
			TCPPutString(MySocket, ServerName);
			TCPPutROMString(MySocket, (ROM BYTE*)"\r\nConnection: close\r\n\r\n");

			TCPFlush(MySocket); //send the HTTP request to the Twitter server

			//setup the search parser struct
			searchParser.foundTag=0;
			searchParser.tagCharMatchCnt=0;
			searchParser.tagTotalCnt=0;
			searchParser.escape=0;
			HTTPstatus = UNKNOWN; //clear the HTTP status checker
			HTTPheaderBufCnt=0;

			addToSearchBuffer(0xff); //add beginning block to the text

			twatchState=TWATCH_SEARCH_TCP_PROCESS_RESPONSE;
			break;

		case TWATCH_SEARCH_TCP_PROCESS_RESPONSE:
			if(!TCPIsConnected(MySocket)) twatchState = TWATCH_SEARCH_TCP_DISCONNECT; //check for connection // Do not break;  We might still have data in the TCP RX FIFO waiting for us
	
			w = TCPIsGetReady(MySocket);	//how many bytes waiting?
	
			i = sizeof(vBuffer)-1;
			vBuffer[i] = '\0'; //add trailing 0 to array.

			while(w){ //process server reply
				if(w < i){
					i = w;
					vBuffer[i] = '\0';
				}
				w -= TCPGetArray(MySocket, vBuffer, i);

				for(cnt=0;cnt<i;cnt++){
					//---------------//
					switch(HTTPstatus){
						case UNKNOWN: //check header for response code before extracting tags
							HTTPheaderBuf[HTTPheaderBufCnt]=vBuffer[cnt];//add to the headerbuf array
							if(HTTPheaderBufCnt<19) HTTPheaderBufCnt++; //if it won't overrun the array, increment the counter
						
							if(vBuffer[cnt]==0x0d){//current character is a line break, examine the header for the response code
								//is it HTTP?
								if(HTTPheaderBuf[0]=='H' &&	HTTPheaderBuf[1]=='T' && 
								HTTPheaderBuf[2]=='T' && HTTPheaderBuf[3]=='P' ){						
									//loop past /1.x and space
									HTTPheaderBufCnt=4;
									while(HTTPheaderBuf[HTTPheaderBufCnt]!=' '){
										HTTPheaderBufCnt++;
										if(HTTPheaderBufCnt>19) break; //buffer overrun
									}
									HTTPheaderBufCnt++;
									//is it 200? (should be a ASCII->int loop that gets the actual value for error handling....
									if( ((HTTPheaderBufCnt+2) < 20) && HTTPheaderBuf[HTTPheaderBufCnt]=='2' &&	HTTPheaderBuf[HTTPheaderBufCnt+1]=='0' && 
										HTTPheaderBuf[HTTPheaderBufCnt+2]=='0'){
										HTTPstatus=OK;
									}else{
										HTTPstatus=ERROR;
									}
								}
							}
							break;
						case OK:
							procSearch(vBuffer[cnt]);
							break;
						case ERROR://do nothing because we need to clear the buffer
							break;
					}
					//------------------//
				}//for loop
				
				if(twatchState == TWATCH_SEARCH_TCP_PROCESS_RESPONSE) break;
			}//while
	
			break;
	
		case TWATCH_SEARCH_TCP_DISCONNECT:
			TCPDisconnect(MySocket); //close the socket
			MySocket = INVALID_SOCKET;

			//did not get valid HTML, retry, got no tags, retry once if no tags
			if(HTTPstatus!=OK ){
				HTTPretry++;
				if(HTTPretry>HTTP_MAX_RETRY){//retry, then wait till next time...
					twatchState = TWATCH_IDLE;
					break;
				}
				twatchState = TWATCH_SEARCH_TCP_START;
				break;
			}
			HTTPretry=0; //success, clear number or retries

			//repeat for each trend term
			searchParser.success=1;
			searchParser.term++;
			twatchState = TWATCH_SEARCH_TCP_START;
			break;

	}//switch
	
}//function
/// @cond debug
//****************************************************************************
//	TCPIsConn callback function
//****************************************************************************
int cTCPisConn()
{
	xBool = TCPIsConnected(xSocket);
	return xBool;
}
Esempio n. 25
0
/*
 * Main entry point.
 */
void main(void)
{
    static TICK8 t = 0;

#ifdef	HEATHERD
	NODE_INFO tcpServerNode;
	static TCP_SOCKET tcpSocketUser = INVALID_SOCKET;
	BYTE c;
#endif

    static BYTE testLED;
    testLED = 1;

    //Set SWDTEN bit, this will enable the watch dog timer
    WDTCON_SWDTEN = 1;
    aliveCntrMain = 0xff;   //Disable alive counter during initialization. Setting to 0xff disables it.

    //Initialize any application specific hardware.
    InitializeBoard();

    //Initialize all stack related components. Following steps must
    //be performed for all applications using PICmicro TCP/IP Stack.
    TickInit();    

    //Initialize buses
    busInit();

    //Initialize serial ports early, because they could be required for debugging
    if (appcfgGetc(APPCFG_USART1_CFG & APPCFG_USART_ENABLE)) {
        appcfgUSART();              //Configure the USART1
    }

    if (appcfgGetc(APPCFG_USART2_CFG & APPCFG_USART_ENABLE)) {
        appcfgUSART2();             //Configure the USART2
    }

    //After initializing all modules that use interrupts, enable global interrupts
    INTCON_GIEH = 1;
    INTCON_GIEL = 1;

    //Initialize file system.
    fsysInit();

    //Intialize HTTP Execution unit
    htpexecInit();

    //Initialize Stack and application related NV variables.
    appcfgInit();

    //First call appcfgCpuIOValues() and then only appcfgCpuIO()!!! This ensures the value are set, before enabling ports.
    appcfgCpuIOValues();    //Configure the CPU's I/O port pin default values
    appcfgCpuIO();          //Configure the CPU's I/O port pin directions - input or output
    
    appcfgADC();            //Configure ADC unit
    appcfgPWM();            //Configure PWM Channels

    //Serial configuration menu - display it for configured time and allow user to enter configuration menu
    scfInit(appcfgGetc(APPCFG_STARTUP_SER_DLY));
    
    //LCD Display Initialize
    lcdInit();

    //Initialize expansion board
    appcfgXboard();

    StackInit();

#if defined(STACK_USE_HTTP_SERVER)
    HTTPInit();
#endif

#if defined(STACK_USE_FTP_SERVER)
    FTPInit();
#endif

    //Intialise network componet of buses - only call after StackInit()!
    busNetInit();

    //Initializes events.
    evtInit();

    //Initializes "UDP Command Port" and "UDP Even Port".
    cmdInit();

    ioInit();

    #if (DEBUG_MAIN >= LOG_DEBUG)
        debugPutMsg(1); //@mxd:1:Starting main loop
    #endif

    /*
     * Once all items are initialized, go into infinite loop and let
     * stack items execute their tasks.
     * If application needs to perform its own task, it should be
     * done at the end of while loop.
     * Note that this is a "co-operative mult-tasking" mechanism
     * where every task performs its tasks (whether all in one shot
     * or part of it) and returns so that other tasks can do their
     * job.
     * If a task needs very long time to do its job, it must broken
     * down into smaller pieces so that other tasks can have CPU time.
     */

#ifdef HEATHERD
    //Create a TCP socket that listens on port 54123
    tcpSocketUser = TCPListen(HEATHERD);

#define HEATHERD_ENABLE (!(appcfgGetc(APPCFG_TRISA) & 1))
#define HEATHERD_WRITE_ENABLE (!(appcfgGetc(APPCFG_TRISA) & 2))

#endif
    
    while(1)
    {
        aliveCntrMain = 38;     //Reset if not services in 52.42ms x 38 = 2 seconds

        //Blink SYSTEM LED every second.
        if (appcfgGetc(APPCFG_SYSFLAGS) & APPCFG_SYSFLAGS_BLINKB6) {
            //Configure RB6 as output, and blink it every 500ms
            if ( TickGetDiff8bit(t) >= ((TICK8)TICKS_PER_SECOND / (TICK8)2) )
            {
                t = TickGet8bit();
                
                //If B6 is configured as input, change to output
                if (appcfgGetc(APPCFG_TRISB) & 0x40) {
                    appcfgPutc(APPCFG_TRISB, appcfgGetc(APPCFG_TRISB) & 0b10111111);
                }
          
                TRISB_RB6 = 0;
                LATB6 ^= 1;     //Toggle
                
                //Toggle IOR5E LED, if IOR5E is present
                if (appcfgGetc(APPCFG_XBRD_TYPE) == XBRD_TYPE_IOR5E) {
                    ior5eLatchData.bits.ledPWR ^= 1;    // Toggle
                }
            }
        }

        //This task performs normal stack task including checking for incoming packet,
        //type of packet and calling appropriate stack entity to process it.
        StackTask();

        //Service LCD display
        lcdService();
        
        //Process commands
        cmdTask();
        
        //Process events
        evtTask();

        //Process serial busses
        busTask();

        //I2C Task
        i2cTask();


#ifdef HEATHERD
        //Has a remote node made connection with the port we are listening on
        if ((tcpSocketUser != INVALID_SOCKET) && TCPIsConnected(tcpSocketUser)) {
    		if (HEATHERD_ENABLE) {
	
	            //Is there any data waiting for us on the TCP socket?
	            //Because of the design of the Modtronix TCP/IP stack we have to
	            //consume all data sent to us as soon as we detect it.
	            while(TCPIsGetReady(tcpSocketUser)) {
	                //We are only interrested in the first byte of the message.
	                TCPGet(tcpSocketUser, &c);
					if (HEATHERD_WRITE_ENABLE) serPutByte(c);
	            }
	            //Discard the socket buffer.
	            TCPDiscard(tcpSocketUser);
			    while (serIsGetReady() && TCPIsPutReady(tcpSocketUser)) {
					TCPPut(tcpSocketUser,serGetByte());
				}
				TCPFlush(tcpSocketUser);
	        } else {
				TCPDisconnect(tcpSocketUser);
			}
		}
#endif

#if defined(STACK_USE_HTTP_SERVER)
        //This is a TCP application.  It listens to TCP port 80
        //with one or more sockets and responds to remote requests.
        HTTPServer();
#endif

#if defined(STACK_USE_FTP_SERVER)
        FTPServer();
#endif

#if defined(STACK_USE_ANNOUNCE)
        DiscoveryTask();
#endif

#if defined(STACK_USE_NBNS)
        NBNSTask();
#endif

        //Add your application speicifc tasks here.
        ProcessIO();

        //For DHCP information, display how many times we have renewed the IP
        //configuration since last reset.
        if ( DHCPBindCount != myDHCPBindCount )
        {
            #if (DEBUG_MAIN >= LOG_INFO)
                debugPutMsg(2); //@mxd:2:DHCP Bind Count = %D
                debugPutByteHex(DHCPBindCount);
            #endif
            
            //Display new IP address
            #if (DEBUG_MAIN >= LOG_INFO)
                debugPutMsg(3); //@mxd:3:DHCP complete, IP = %D.%D.%D.%D
                debugPutByteHex(AppConfig.MyIPAddr.v[0]);
                debugPutByteHex(AppConfig.MyIPAddr.v[1]);
                debugPutByteHex(AppConfig.MyIPAddr.v[2]);
                debugPutByteHex(AppConfig.MyIPAddr.v[3]);
            #endif
            myDHCPBindCount = DHCPBindCount;
            
            #if defined(STACK_USE_ANNOUNCE)
                AnnounceIP();
            #endif             
        }
    }
}
Esempio n. 26
0
/*****************************************************************************
  Function:
	void GenericTCPClient(void)

  Summary:
	Implements a simple HTTP client (over TCP).

  Description:
	This function implements a simple HTTP client, which operates over TCP.
	The function is called periodically by the stack, and waits for BUTTON1
	to be pressed.  When the button is pressed, the application opens a TCP
	connection to an Internet search engine, performs a search for the word
	"Microchip" on "microchip.com", and prints the resulting HTML page to
	the UART.

	This example can be used as a model for many TCP and HTTP client
	applications.

  Precondition:
	TCP is initialized.

  Parameters:
	None

  Returns:
  	None
  ***************************************************************************/
void GenericTCPClient(void)
{
    BYTE 				i;
    WORD				w;
    BYTE				vBuffer[9];
    static DWORD		Timer;
    static TCP_SOCKET	MySocket = INVALID_SOCKET;
    static enum _GenericTCPExampleState
    {
        SM_HOME = 0,
        SM_SOCKET_OBTAINED,
        SM_PROCESS_RESPONSE,
        SM_DISCONNECT,
        SM_DONE
    } GenericTCPExampleState = SM_DONE;

    switch(GenericTCPExampleState)
    {
    case SM_HOME:
        // Connect a socket to the remote TCP server
        MySocket = TCPOpen((DWORD)&ServerName[0], TCP_OPEN_RAM_HOST, ServerPort, TCP_PURPOSE_GENERIC_TCP_CLIENT);

        // Abort operation if no TCP socket of type TCP_PURPOSE_GENERIC_TCP_CLIENT is available
        // If this ever happens, you need to go add one to TCPIPConfig.h
        if(MySocket == INVALID_SOCKET)
            break;

#if defined(STACK_USE_UART)
        putrsUART((ROM char*)"\r\n\r\nConnecting using Microchip TCP API...\r\n");
#endif

        GenericTCPExampleState++;
        Timer = TickGet();
        break;

    case SM_SOCKET_OBTAINED:
        // Wait for the remote server to accept our connection request
        if(!TCPIsConnected(MySocket))
        {
            // Time out if too much time is spent in this state
            if(TickGet()-Timer > 5*TICK_SECOND)
            {
                // Close the socket so it can be used by other modules
                TCPDisconnect(MySocket);
                MySocket = INVALID_SOCKET;
                GenericTCPExampleState--;
            }
            break;
        }

        Timer = TickGet();

        // Make certain the socket can be written to
        if(TCPIsPutReady(MySocket) < 125u)
            break;

        // Place the application protocol data into the transmit buffer.  For this example, we are connected to an HTTP server, so we'll send an HTTP GET request.
        TCPPutROMString(MySocket, (ROM BYTE*)"GET ");
        TCPPutROMString(MySocket, RemoteURL);
        TCPPutROMString(MySocket, (ROM BYTE*)" HTTP/1.0\r\nHost: ");
        TCPPutString(MySocket, ServerName);
        TCPPutROMString(MySocket, (ROM BYTE*)"\r\nConnection: close\r\n\r\n");

        // Send the packet
        TCPFlush(MySocket);
        GenericTCPExampleState++;
        break;

    case SM_PROCESS_RESPONSE:
        // Check to see if the remote node has disconnected from us or sent us any application data
        // If application data is available, write it to the UART
        if(!TCPIsConnected(MySocket))
        {
            GenericTCPExampleState = SM_DISCONNECT;
            // Do not break;  We might still have data in the TCP RX FIFO waiting for us
        }

        // Get count of RX bytes waiting
        w = TCPIsGetReady(MySocket);

        // Obtian and print the server reply
        i = sizeof(vBuffer)-1;
        vBuffer[i] = '\0';
        while(w)
        {
            if(w < i)
            {
                i = w;
                vBuffer[i] = '\0';
            }
            w -= TCPGetArray(MySocket, vBuffer, i);
#if defined(STACK_USE_UART)
            putsUART((char*)vBuffer);
#endif

            // putsUART is a blocking call which will slow down the rest of the stack
            // if we shovel the whole TCP RX FIFO into the serial port all at once.
            // Therefore, let's break out after only one chunk most of the time.  The
            // only exception is when the remote node disconncets from us and we need to
            // use up all the data before changing states.
            if(GenericTCPExampleState == SM_PROCESS_RESPONSE)
                break;
        }

        break;

    case SM_DISCONNECT:
        // Close the socket so it can be used by other modules
        // For this application, we wish to stay connected, but this state will still get entered if the remote server decides to disconnect
        TCPDisconnect(MySocket);
        MySocket = INVALID_SOCKET;
        GenericTCPExampleState = SM_DONE;
        break;

    case SM_DONE:
        // Do nothing unless the user pushes BUTTON1 and wants to restart the whole connection/download process
        if(BUTTON1_IO == 0u)
            GenericTCPExampleState = SM_HOME;
        break;
    }
}
Esempio n. 27
0
void ReceiveEthernetCmds()
{
	
	WORD wMaxGet, wBytesRead;
	BYTE b;
	static enum _TCPServerState
	{
		SM_HOME = 0,
		SM_LISTENING,
        SM_CLOSING,
	} TCPServerState = SM_HOME;
	
	switch(TCPServerState)
	{
		case SM_HOME:
			// Allocate a socket for this server to listen and accept connections on
			MySocket = TCPOpen(0, TCP_OPEN_SERVER, SERVER_PORT, TCP_PURPOSE_GENERIC_TCP_SERVER);
			if(MySocket == INVALID_SOCKET)
				return;

			TCPServerState = SM_LISTENING;
			break;

		case SM_LISTENING:
			// See if anyone is connected to us
			if(!TCPIsConnected(MySocket))
				return;
				
			// Figure out how many bytes have been received and how many we can transmit.
			wMaxGet = TCPIsGetReady(MySocket);	// Get TCP RX FIFO byte count
			
			
			// Read the data into the buffer
			wBytesRead = 0;
			while (wBytesRead < wMaxGet)
			{
				if(!TCPGet(MySocket, &b)) 
					break;	// Byte NOT read... (No connection or no data to read)
				
				if(b == 10 || b == 13)
				{
					// Ignore newline characters
				}
				else
				{
					EthernetBuffer[EB_Write] = b;
					if( (EB_Write+1) % ETHERNET_BUFFER_SIZE != EB_Read)	// check if buffer full
						EB_Write++;
					EB_Write %= ETHERNET_BUFFER_SIZE;
				}
				wBytesRead++;
			}	
	
			break;
			
		case SM_CLOSING:
			// Close the socket connection.
            TCPClose(MySocket);

			TCPServerState = SM_HOME;
			break;
	}
	
	ProcessBufferData();
	
}	
bool TcpClient::isConnected(unsigned long msBlockMax, DNETcK::STATUS * pStatus)
{
    unsigned long tStart = 0;
    bool fConnected = false;
    DNETcK::STATUS statusT = DNETcK::WaitingReConnect;

    // we want this to be PeriodicTasks and not StackTasks because we
    // want to run all of the applications when IsConnected is called
    // because this is a common call and we want to keep all things running
    EthernetPeriodicTasks();

    // see if we ever supplied info for a connection
    if(_hTCP >= INVALID_SOCKET)
    {
        if(pStatus != NULL) *pStatus = DNETcK::SocketError;
        return(false);
    }

    switch(_classState)
    {
        case DNETcK::Connected:
        case DNETcK::WaitingReConnect:
        case DNETcK::LostConnect:
            if(!DNETcK_IsMacConnected(&statusT))
            {
                _classState = statusT;
                if(pStatus != NULL) *pStatus = statusT;
                return(false);
            }
            else if(TCPIsConnected(_hTCP))
            {
                _classState = DNETcK::Connected;
                if(pStatus != NULL) *pStatus = DNETcK::Connected;
                return(true);
            }
            else
            {
               _classState = DNETcK::LostConnect;
               if(pStatus != NULL) *pStatus = DNETcK::LostConnect;
               return(false);
            }
            break;

        case DNETcK::NotConnected:
            _classState = DNETcK::WaitingConnect;

            // fall thru to get connected

        case DNETcK::WaitingConnect:

            // loop until connected, or the timeout
            tStart = millis();
            do {
                    // in order to know what connection state we have
                    // we must run the stack tasks
                    EthernetPeriodicTasks();

                    if(TCPIsConnected(_hTCP))
                    {                         
                        // now that we are connected, we can setup the endpoints
                        if(!_fEndPointsSetUp)
                        {
                            // we just Connected, there should be nothing in the flush buffers
                            // and we should have our remote endpoints all set up.
                            GetTcpSocketEndPoints(_hTCP, &_remoteEP.ip, &_remoteMAC, &_remoteEP.port, &_localEP.port);
                            DNETcK::getMyIP(&_localEP.ip);
                            _fEndPointsSetUp = true;
                        }

                       // we are connected
                        _classState = DNETcK::Connected;
                       if(pStatus != NULL) *pStatus = DNETcK::Connected;
                       return(true);
                    }

            } while(!hasTimeElapsed(tStart, msBlockMax, millis()));

            // clearly not connected, return our state
            if(pStatus != NULL) *pStatus = _classState;
            return(false);
            break;

        default:
            if(pStatus != NULL) *pStatus = _classState;
            return(false);
           break;
    }
}
void twatchTasks(void){ //this state machine services the #twatch

   static enum _twitterTCPstate{
		TWITTER_INIT=0,
		HOLD_COLOR,
		TWITTER_IDLE,
		TWITTER_SEARCH_TCP_START,
		TWITTER_SEARCH_TCP_SOCKET_OBTAINED,
		TWITTER_SEARCH_TCP_PROCESS_RESPONSE,
		TWITTER_SEARCH_TCP_DISCONNECT,
	} twitterTCPstate = TWITTER_INIT; //massive twitter parsing state machine

   static enum _HTTPstatus{
		UNKNOWN=0,
		OK,
		ERROR,
	} HTTPstatus = UNKNOWN; //get and track HTTP status and handle errors
	static unsigned char HTTPheaderBuf[20]; //used to store HTTP headers 
	static unsigned char HTTPheaderBufCnt; //pointer

	static BYTE HTTPretry=0, gotID=0;//extra static vars for twitter parser

	unsigned char tcpReadBytes, cnt;
	unsigned int	tcpTotalBytes; //for TCPsocket length, can be >256
	#define TCPBUF_LENGTH 50 //best size
	unsigned char	tcpBuf[TCPBUF_LENGTH];
	static DWORD		Timer;
	static TCP_SOCKET	TCPSocket = INVALID_SOCKET;

	static struct _timekeeper{
		DWORD	ticks;
		unsigned char minutes;
		unsigned char seconds;
		unsigned char runsec; //running seconds counter
	} time;

	//a minutes counter for determining when to refresh the search results
	if(TickGet() - time.ticks >= TICK_SECOND){
		time.ticks = TickGet();
		time.seconds++;
		time.runsec++;
		if(time.seconds>59){
			time.seconds=0;
			time.minutes++;
			if(time.minutes>59){
				time.minutes=0;
			}
		}
	}

	switch(twitterTCPstate){

		case TWITTER_INIT: //setup JSON parser structs on first run
			searchParser.searchTag=textTag;//tag to search for
			searchParser.searchTagLength=(sizeof(textTag)-1);//length of search tag
			searchParser.valueBuffer=tweetBuf; //assign buffer to this struct
			searchParser.valueBufferLength=TWEETCHARS;//buffer length
			searchParser.valueEndChar='"'; //text tag, value ends with "

			nameParser.searchTag=nameTag;//tag to name for
			nameParser.searchTagLength=(sizeof(nameTag)-1);//length of name tag
			nameParser.valueBuffer=nameBuf; //assign buffer to this struct
			nameParser.valueBufferLength=NAMECHARS;//buffer length
			nameParser.valueEndChar='"'; //text tag, value ends with "

			max_idParser.searchTag=max_idTag;//tag to search for
			max_idParser.searchTagLength=(sizeof(max_idTag)-1);//length of search tag
			max_idParser.valueBuffer=lastidTempBuf; //assign buffer to this struct
			max_idParser.valueBufferLength=MAX_IDCHARS;//buffer length
			max_idParser.valueEndChar=','; //text tag, value ends with "
			max_idParser.valueBuffer[20]='\0'; //ensure 0 termination

			//zero the last ID before first call
			lastidBuf[0]='\0';
			lastidBuf[1]='\0';

			//reset printer
			UARTTX(0x1b);
			UARTTX('@');
			//Control parameter command
			UARTTX(0x1b);
			UARTTX(0x37);
			UARTTX(0x07);//max printing dots
			UARTTX(0xFF);//heating time
			UARTTX(0x05);	//heating interval
			twitterTCPstate=TWITTER_SEARCH_TCP_START; //start TCP data grabber next cycle

			break;
		case HOLD_COLOR:
			if(time.runsec<HOLD_SECONDS){
				break;
			}		
			twitterTCPstate=TWITTER_IDLE;	
		case TWITTER_IDLE:	//if this variable set, then start the refresh process		
			//have we played all the buffered text
			if(T.cnt>0 && UART_EMPTY()){//step through text when idle
				
				if(T.t[T.read]==0xFF){//0xFF, end of tweet. reset line counter
					T.lncnt=0;
				}else{
					UARTTX(T.t[T.read]);
					T.lncnt++;

					//send a LF at the end of each X characters
					if(T.lncnt==PRINTER_WIDTH){
						UARTTX(0x0a);
						T.lncnt=0;
						
						twitterTCPstate=HOLD_COLOR;//next time hold solid color
					}
				}

				T.read++;
				//is this the final text?
				T.cnt--;
				if(T.cnt==0){//done with text
					time.runsec=0;//clear running counter for pause
					#ifndef DEBUG
						UARTTX(0x0a);
						UARTTX(0x0a);
						twitterTCPstate=HOLD_COLOR;//next time hold solid color
					#endif
				}

			}else if(time.seconds>=REFRESH_INTERVAL){ //if it has been at least X minutes, get tweet search results
				time.seconds=0;
				HTTPretry=0; //reset the number of retries	
				twitterTCPstate=TWITTER_SEARCH_TCP_START; //start TCP data grabber next cycle
			}			
			break;
		case TWITTER_SEARCH_TCP_START: //begins search for tweets 
			//setup the search parser struct
			resetJSONparser(&nameParser);
			resetJSONparser(&searchParser);
			resetJSONparser(&max_idParser);
			gotID=0; //reset the ID finder
			T.cnt=0; //reset the tweet letter counter	
			T.read=0; //reset the read pointer	
			HTTPstatus = UNKNOWN; //clear the HTTP status checker
			HTTPheaderBufCnt=0;
					
			//connect to twitter
			TCPSocket = TCPOpen((DWORD)&ServerName[0], TCP_OPEN_RAM_HOST, ServerPort, TCP_PURPOSE_GENERIC_TCP_CLIENT);

			if(TCPSocket == INVALID_SOCKET) break; //abort on error

			twitterTCPstate=TWITTER_SEARCH_TCP_SOCKET_OBTAINED;
			Timer = TickGet();
			break;

		case TWITTER_SEARCH_TCP_SOCKET_OBTAINED:
			//wait for server, with timeout
			if(!TCPIsConnected(TCPSocket)){
				if(TickGet()-Timer > 5*TICK_SECOND){
					TCPDisconnect(TCPSocket);
					TCPSocket = INVALID_SOCKET;
					twitterTCPstate--;
				}
				break;
			}

			Timer = TickGet();

			if(TCPIsPutReady(TCPSocket) < 125u) break; //socket ready for writes?
			
			TCPPutROMString(TCPSocket, (ROM BYTE*)"GET "); //setup the HTTP GET request 
			TCPPutROMString(TCPSocket, SearchURL);	//JSON search datafeed URL

			//add the last ID to the JSON search URL. (usually requires urlencoding, but we have numbers only)
			//#ifdef 0
			if(lastidBuf[0]!='\0'){ //don't put 0 length IDs into TCP, kills socket
				TCPPutString(TCPSocket, lastidBuf); //put the string in the TCP buffer
			}
			//#endif

			//form the rest of the HTTP request
			TCPPutROMString(TCPSocket, (ROM BYTE*)" HTTP/1.0\r\nHost: ");
			TCPPutString(TCPSocket, ServerName);
			TCPPutROMString(TCPSocket, (ROM BYTE*)"\r\nConnection: close\r\n\r\n");

			TCPFlush(TCPSocket); //send the HTTP request to the Twitter server

			twitterTCPstate=TWITTER_SEARCH_TCP_PROCESS_RESPONSE;
			break;

		case TWITTER_SEARCH_TCP_PROCESS_RESPONSE:
			if(!TCPIsConnected(TCPSocket)) twitterTCPstate = TWITTER_SEARCH_TCP_DISCONNECT; //check for connection // Do not break;  We might still have data in the TCP RX FIFO waiting for us

			tcpTotalBytes = TCPIsGetReady(TCPSocket);	//how many bytes waiting?
			tcpReadBytes = TCPBUF_LENGTH;

			while(tcpTotalBytes){ //process server reply
				if(tcpTotalBytes < tcpReadBytes){
					tcpReadBytes = tcpTotalBytes;
				}
				tcpTotalBytes -= TCPGetArray(TCPSocket, tcpBuf, tcpReadBytes);

				for(cnt=0;cnt<tcpReadBytes;cnt++){
					UART2TX(tcpBuf[cnt]);
					//---------------//
					switch(HTTPstatus){
						case UNKNOWN: //check header for response code before extracting tags
							HTTPheaderBuf[HTTPheaderBufCnt]=tcpBuf[cnt];//add to the headerbuf array
							if(HTTPheaderBufCnt<19) HTTPheaderBufCnt++; //if it won't overrun the array, increment the counter
						
							if(tcpBuf[cnt]==0x0d){//current character is a line break, examine the header for the response code
								//is it HTTP?
								if(HTTPheaderBuf[0]=='H' &&	HTTPheaderBuf[1]=='T' && 
								HTTPheaderBuf[2]=='T' && HTTPheaderBuf[3]=='P' ){						
									//loop past /1.x and space
									HTTPheaderBufCnt=4;
									while(HTTPheaderBuf[HTTPheaderBufCnt]!=' '){
										HTTPheaderBufCnt++;
										if(HTTPheaderBufCnt>19) break; //buffer overrun
									}
									HTTPheaderBufCnt++;
									//is it 200? (should be a ASCII->int loop that gets the actual value for error handling....
									if( ((HTTPheaderBufCnt+2) < 20) && HTTPheaderBuf[HTTPheaderBufCnt]=='2' &&	HTTPheaderBuf[HTTPheaderBufCnt+1]=='0' && 
										HTTPheaderBuf[HTTPheaderBufCnt+2]=='0'){
										HTTPstatus=OK;
									}else{
										HTTPstatus=ERROR;
									}
								}
							}
							break;
						case OK:
							if(tagSearch(tcpBuf[cnt], &nameParser)){//process the tweet for color data
								processname(nameParser.valueBufferCounter);
							}
							if(tagSearch(tcpBuf[cnt], &searchParser)){//process the tweet for color data
								processtweet(searchParser.valueBufferCounter);
							}
							if(gotID==0){//get only the first (highest) tweet ID to append to the URL next time
								if(tagSearch(tcpBuf[cnt], &max_idParser)){
									addValueByte('\0', &max_idParser);
									for(gotID=0; gotID<21; gotID++){
										lastidBuf[gotID]=lastidTempBuf[gotID];//only overwrite if comlete
									}
									gotID=1;
								}
							}
							break;
						case ERROR://do nothing because we need to clear the buffer
							break;
					}
					//------------------//
				}//for loop
				
				if(twitterTCPstate == TWITTER_SEARCH_TCP_PROCESS_RESPONSE) break;
			}//while
	
			break;
	
		case TWITTER_SEARCH_TCP_DISCONNECT:
			TCPDisconnect(TCPSocket); //close the socket
			TCPSocket = INVALID_SOCKET;

			//did not get valid HTML, retry, got no tags, retry once if no tags
			if(HTTPstatus!=OK ){
				HTTPretry++;
				if(HTTPretry>(HTTP_MAX_RETRY-1)){//retry, then wait till next time...
					twitterTCPstate = TWITTER_IDLE;
					time.seconds=0;
					break;
				}
				twitterTCPstate = TWITTER_SEARCH_TCP_START;
				break;
			}
			HTTPretry=0; //success, clear number or retries

			twitterTCPstate = TWITTER_IDLE;
			break;

	}//switch
	
/*********************************************************************
 * void IO2TCPBridgeTask(void)
 *
 * PreCondition:    Stack is initialized()
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        None
 *
 * Note:            None
 ********************************************************************/
void IO2TCPBridgeTask(void)
{
	static enum _BridgeState
	{
		SM_HOME = 0,
		SM_SOCKET_OBTAINED
	} BridgeState = SM_HOME;
	static TCP_SOCKET MySocket = INVALID_SOCKET;
	WORD wMaxPut, wMaxGet, w;
	BYTE *RXHeadPtrShadow, *RXTailPtrShadow;
	BYTE *TXHeadPtrShadow, *TXTailPtrShadow;


	switch(BridgeState)
	{
		case SM_HOME:
			#if defined(USE_REMOTE_TCP_SERVER)
				// Connect a socket to the remote TCP server
				MySocket = TCPOpen((DWORD)USE_REMOTE_TCP_SERVER, TCP_OPEN_ROM_HOST, UART2TCPBRIDGE_PORT, TCP_PURPOSE_UART_2_TCP_BRIDGE);
			#else
				MySocket = TCPOpen(0, TCP_OPEN_SERVER, UART2TCPBRIDGE_PORT, TCP_PURPOSE_UART_2_TCP_BRIDGE);
			#endif
			
			// Abort operation if no TCP socket of type TCP_PURPOSE_UART_2_TCP_BRIDGE is available
			// If this ever happens, you need to go add one to TCPIPConfig.h
			if(MySocket == INVALID_SOCKET)
				break;

			// Eat the first TCPWasReset() response so we don't 
			// infinitely create and reset/destroy client mode sockets
			TCPWasReset(MySocket);
			
			// We have a socket now, advance to the next state
			BridgeState = SM_SOCKET_OBTAINED;
			break;

		case SM_SOCKET_OBTAINED:
			// Reset all buffers if the connection was lost
			if(TCPWasReset(MySocket))
			{
				// Optionally discard anything in the UART FIFOs
				//RXHeadPtr = vUARTRXFIFO;
				//RXTailPtr = vUARTRXFIFO;
				//TXHeadPtr = vUARTTXFIFO;
				//TXTailPtr = vUARTTXFIFO;
				
				// If we were a client socket, close the socket and attempt to reconnect
				#if defined(USE_REMOTE_TCP_SERVER)
					TCPDisconnect(MySocket);
					MySocket = INVALID_SOCKET;
					BridgeState = SM_HOME;
					break;
				#endif
			}
		
			// Don't do anything if nobody is connected to us
			if(!TCPIsConnected(MySocket))
				break;
			
			if(TRUE == TxData)
			{
				//TCPPutArray(MySocket, keyinfo, 1);
				TCPPut(MySocket, keyinfo);
				TxData = FALSE;
			}	

			// No flush.  The stack will automatically flush and do 
			// transmit coallescing to minimize the number of TCP 
			// packets that get sent.  If you explicitly call TCPFlush()
			// here, latency will go down, but so will max throughput 
			// and bandwidth efficiency.
			break;
	}
}