?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 32

?prevdifflink? - Blame - ?getfile?

/*********************************************************************
 *
 *      UART <-> TCP Bridge Example
 *  Module for Microchip TCP/IP Stack
 *       -Transmits all incoming TCP bytes on a socket out the UART 
 *    module, all incoming UART bytes out of the TCP socket.
 *       -Reference: None (hopefully AN833 in the future)
 *
 *********************************************************************
 * FileName:        UART2TCPBridge.c
 * Dependencies:    TCP, Hardware UART module, ARP (optional), 
 *                                      DNS (optional)
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
 * Compiler:        Microchip C32 v1.05 or higher
 *                                      Microchip C30 v3.12 or higher
 *                                      Microchip C18 v3.30 or higher
 *                                      HI-TECH PICC-18 PRO 9.63PL2 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright (C) 2002-2009 Microchip Technology Inc.  All rights
 * reserved.
 *
 * Microchip licenses to you the right to use, modify, copy, and
 * distribute:
 * (i)  the Software when embedded on a Microchip microcontroller or
 *      digital signal controller product ("Device") which is
 *      integrated into Licensee's product; or
 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
 *              ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
 *              used in conjunction with a Microchip ethernet controller for
 *              the sole purpose of interfacing with the ethernet controller.
 *
 * You should refer to the license agreement accompanying this
 * Software for additional information regarding your rights and
 * obligations.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
 *
 * Author               Date            Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Howard Schlunder             06/12/07        Original
 ********************************************************************/
#define __UART2TCPBRIDGE_C

#include "TCPIPConfig.h"
#include "HardwareProfile.h"


// TCP listen port and UART baud rate settings.  Due to a current C18 
// preprocessor bug (tested on compiler 3.30), the BAUD_RATE definition needs 
// to be placed above the #if defined(STACK_USE_UART2TCP_BRIDGE) test.  
// Otherwise, it won't compile when STACK_USE_UART2TCP_BRIDGE is UNdefined.  
// Also, HardwareProfile.h also needs to be included before the 
// STACK_USE_UART2TCP_BRIDGE test.
#define UART2TCPBRIDGE_PORT     9761
#define BAUD_RATE                       19200


#if defined(STACK_USE_UART2TCP_BRIDGE)

#include "TCPIP Stack/TCPIP.h"

// Comment this define out if we are the server.  
// Insert the appropriate address if we are the client.
//#define USE_REMOTE_TCP_SERVER "192.168.2.50"

// Ring buffers for transfering data to and from the UART ISR:
//  - (Head pointer == Tail pointer) is defined as an empty FIFO
//  - (Head pointer == Tail pointer - 1), accounting for wraparound,
//    is defined as a completely full FIFO.  As a result, the max data 
//    in a FIFO is the buffer size - 1.
static BYTE vUARTRXFIFO[65];
static BYTE vUARTTXFIFO[17];
static volatile BYTE *RXHeadPtr = vUARTRXFIFO, *RXTailPtr = vUARTRXFIFO;
static volatile BYTE *TXHeadPtr = vUARTTXFIFO, *TXTailPtr = vUARTTXFIFO;


/*********************************************************************
 * Function:        void UART2TCPBridgeInit(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        Sets up the UART peripheral for this application
 *
 * Note:            Uses interrupts
 ********************************************************************/
void UART2TCPBridgeInit(void)
{
        // Initilize UART
#if defined(__18CXX)
    TXSTA = 0x20;
    RCSTA = 0x90;

        #define CLOSEST_SPBRG_VALUE ((GetPeripheralClock()+2ul*BAUD_RATE)/BAUD_RATE/4-1)
        #define BAUD_ACTUAL (GetPeripheralClock()/(CLOSEST_SPBRG_VALUE+1))
        #if (BAUD_ACTUAL > BAUD_RATE)
                #define BAUD_ERROR (BAUD_ACTUAL-BAUD_RATE)
        #else
                #define BAUD_ERROR (BAUD_RATE-BAUD_ACTUAL)
        #endif
        #define BAUD_ERROR_PRECENT      ((BAUD_ERROR*100+BAUD_RATE/2)/BAUD_RATE)
        #if BAUD_ERROR_PRECENT > 2
                // Use high speed (Fosc/4) 16-bit baud rate generator
                BAUDCONbits.BRG16 = 1;
                TXSTAbits.BRGH = 1;
                SPBRGH = ((GetPeripheralClock()+BAUD_RATE/2)/BAUD_RATE-1)>>8 & 0xFF;
                SPBRG = ((GetPeripheralClock()+BAUD_RATE/2)/BAUD_RATE-1) & 0xFF;
        #else
                // See if we can use the high baud (Fosc/16) 8-bit rate setting
                #if ((GetPeripheralClock()+2*BAUD_RATE)/BAUD_RATE/4 - 1) <= 255
                        SPBRG = (GetPeripheralClock()+2*BAUD_RATE)/BAUD_RATE/4 - 1;
                        TXSTAbits.BRGH = 1;
                #else   // Use the low baud rate 8-bit setting
                        SPBRG = (GetPeripheralClock()+8*BAUD_RATE)/BAUD_RATE/16 - 1;
                #endif
        #endif
        
        // Use high priority interrupt
        IPR1bits.TXIP = 1;

#else
        UARTTX_TRIS = 0;
        UARTRX_TRIS = 1;
        UMODE = 0x8000;                 // Set UARTEN.  Note: this must be done before setting UTXEN

        #if defined(__C30__)
                USTA = 0x0400;          // UTXEN set
                #define CLOSEST_UBRG_VALUE ((GetPeripheralClock()+8ul*BAUD_RATE)/16/BAUD_RATE-1)
                #define BAUD_ACTUAL (GetPeripheralClock()/16/(CLOSEST_UBRG_VALUE+1))
        #else   //defined(__C32__)
                IPC8bits.U2IP = 6;              // Priority level 6
                USTA = 0x00001400;              // RXEN set, TXEN set
                #define CLOSEST_UBRG_VALUE ((GetPeripheralClock()+8ul*BAUD_RATE)/16/BAUD_RATE-1)
                #define BAUD_ACTUAL (GetPeripheralClock()/16/(CLOSEST_UBRG_VALUE+1))
        #endif

        #define BAUD_ERROR ((BAUD_ACTUAL > BAUD_RATE) ? BAUD_ACTUAL-BAUD_RATE : BAUD_RATE-BAUD_ACTUAL)
        #define BAUD_ERROR_PRECENT      ((BAUD_ERROR*100+BAUD_RATE/2)/BAUD_RATE)
        #if (BAUD_ERROR_PRECENT > 3)
                #warning UART frequency error is worse than 3%
        #elif (BAUD_ERROR_PRECENT > 2)
                #warning UART frequency error is worse than 2%
        #endif

        UBRG = CLOSEST_UBRG_VALUE;
#endif

}


/*********************************************************************
 * 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;
        }
}


#if defined(__18CXX)
/*********************************************************************
 * Function:        void UART2TCPBridgeISR(void)
 *
 * PreCondition:    UART interrupt has occured
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        None
 *
 * Note:            This function is supposed to be called in the ISR 
 *                                      context.
 ********************************************************************/
void UART2TCPBridgeISR(void)
{
        // NOTE: All local variables used here should be declared static
        static BYTE i;

        // Store a received byte, if pending, if possible
        if(PIR1bits.RCIF)
        {
                // Get the byte
                i = RCREG;

                // Clear the interrupt flag so we don't keep entering this ISR
                PIR1bits.RCIF = 0;

                // Copy the byte into the local FIFO, if it won't cause an overflow
                if(RXHeadPtr != RXTailPtr - 1)
                {
                        if((RXHeadPtr != vUARTRXFIFO + sizeof(vUARTRXFIFO)) || (RXTailPtr != vUARTRXFIFO))
                        {
                                *RXHeadPtr++ = i;
                                if(RXHeadPtr >= vUARTRXFIFO + sizeof(vUARTRXFIFO))
                                        RXHeadPtr = (volatile BYTE*)vUARTRXFIFO;
                        }
                }
        }

        // Transmit a byte, if pending, if possible
        if(PIR1bits.TXIF)
        {
                if(TXHeadPtr != TXTailPtr)
                {
                        TXREG = *TXTailPtr++;
                        if(TXTailPtr >= vUARTTXFIFO + sizeof(vUARTTXFIFO))
                                TXTailPtr = (volatile BYTE*)vUARTTXFIFO;
                }
                else    // Disable the TX interrupt if we are done so that we don't keep entering this ISR
                {
                        PIE1bits.TXIE = 0;
                }
        }
}

#else
/*********************************************************************
 * Function:        void _ISR _U2RXInterrupt(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        Copies bytes to and from the local UART TX and 
 *                                      RX FIFOs
 *
 * Note:            None
 ********************************************************************/
#if __C30_VERSION__ >= 300
void _ISR __attribute__((__no_auto_psv__)) _U2RXInterrupt(void)
#elif defined(__C30__)
void _ISR _U2RXInterrupt(void)
#else
void _U2RXInterrupt(void)
#endif
{
        BYTE i;

        // Store a received byte, if pending, if possible
        // Get the byte
        i = U2RXREG;
        
        // Clear the interrupt flag so we don't keep entering this ISR
        IFS1bits.U2RXIF = 0;
        
        // Copy the byte into the local FIFO, if it won't cause an overflow
        if(RXHeadPtr != RXTailPtr - 1)
        {
                if((RXHeadPtr != vUARTRXFIFO + sizeof(vUARTRXFIFO)) || (RXTailPtr != vUARTRXFIFO))
                {
                        *RXHeadPtr++ = i;
                        if(RXHeadPtr >= vUARTRXFIFO + sizeof(vUARTRXFIFO))
                                RXHeadPtr = vUARTRXFIFO;
                }
        }
}
/*********************************************************************
 * Function:        void _ISR _U2TXInterrupt(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        Copies bytes to and from the local UART TX and 
 *                                      RX FIFOs
 *
 * Note:            None
 ********************************************************************/
#if __C30_VERSION__ >= 300
void _ISR __attribute__((__no_auto_psv__)) _U2TXInterrupt(void)
#elif defined(__C30__)
void _ISR _U2TXInterrupt(void)
#else
void _U2TXInterrupt(void)
#endif
{
        // Transmit a byte, if pending, if possible
        if(TXHeadPtr != TXTailPtr)
        {
                // Clear the TX interrupt flag before transmitting again
                IFS1bits.U2TXIF = 0;

                U2TXREG = *TXTailPtr++;
                if(TXTailPtr >= vUARTTXFIFO + sizeof(vUARTTXFIFO))
                        TXTailPtr = vUARTTXFIFO;
        }
        else    // Disable the TX interrupt if we are done so that we don't keep entering this ISR
        {
                IEC1bits.U2TXIE = 0;
        }
}


#if defined(__C32__)
void __attribute((interrupt(ipl6), vector(_UART2_VECTOR), nomips16)) U2Interrupt(void)
{
        if(IFS1bits.U2RXIF)
                _U2RXInterrupt();
        if(IEC1bits.U2TXIE)
        {
                if(IFS1bits.U2TXIF)
                        _U2TXInterrupt();
        }
}
#endif

#endif  // end of ISRs


#endif  //#if defined(STACK_USE_UART2TCP_BRIDGE)
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3