This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C1294NCPDT: tivaware non rtos, send data on tcp clinent connection

Part Number: TM4C1294NCPDT

Hi,

I have used enet tcp echo server, i am getting client connection successful, on client connection in echo_accept function, it calls tcp_recv  which receives data from client successfully, now i want to transmit & receive data continuously, immediately after client connection.

TIVA WARE SDK version : TivaWare_C_Series-2.2.0.295

please help

REGARDS

sagart

  • Hi,

      The tcp echo server is meant to echo back anything that the client sends to it. If your client continuously send data to the server, the server will just transmit (echo back) the same data to the client. 

  • I want to transmit the data through ethernet only. Please provide me the example for this.

    Regards,

    sagar

  • The enet_tcpecho_server example will be the example that is closest to what you are looking for. You will need to adapt and modify it for your application. There are other Ethernet examples in TivaWare library.

  • //*****************************************************************************
    //
    // enet_tcp_echo_server.c - Sample Echo Server Application using lwIP.
    //
    // Copyright (c) 2019-2020 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 2.2.0.295 of the EK-TM4C1294XL Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/debug.h"
    #include "driverlib/flash.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "drivers/pinout.h"
    #include "lwip/tcp.h"
    #include "utils/locator.h"
    #include "utils/lwiplib.h"
    #include "utils/uartstdio.h"
    #include "driverlib/uart.h"
    #include "utils/ustdlib.h"
    
    
    uint32_t ui32SysClock;
    
    //*****************************************************************************
    //
    // Defines for setting up the system clock.
    //
    //*****************************************************************************
    #define SYSTICKHZ               100
    #define SYSTICKMS               (1000 / SYSTICKHZ)
    
    //*****************************************************************************
    //
    // Interrupt priority definitions.  The top 3 bits of these values are
    // significant with lower values indicating higher priority interrupts.
    //
    //*****************************************************************************
    #define SYSTICK_INT_PRIORITY    0x80
    #define ETHERNET_INT_PRIORITY   0xC0
    
    //*****************************************************************************
    //
    // The current IP address.
    //
    //*****************************************************************************
    uint32_t g_ui32IPAddress;
    
    //*****************************************************************************
    //
    // Global counter to keep track the duration the connection has been idle.
    //
    //*****************************************************************************
    uint32_t g_ui32tcpPollTick = 0;
    
    //*****************************************************************************
    //
    // Volatile global flag to manage LED blinking, since it is used in interrupt
    // and main application.  The LED blinks at the rate of SYSTICKHZ.
    //
    //*****************************************************************************
    volatile bool g_bLED;
    
    //*****************************************************************************
    //
    // This is the buffer to receive the TCP payload.  Data in this buffer is then
    // processed before echoing back to the host.
    //
    //*****************************************************************************
    char g_pctcpBuffer[4] = {0};
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    
    
    void systemClockConfigure(void)
    {
        //
        // Run from the PLL at 120 MHz.
        // Note: SYSCTL_CFG_VCO_240 is a new setting provided in TivaWare 2.2.x and
        // later to better reflect the actual VCO speed due to SYSCTL#22.
        //
        //ui32SysClock = 120000000
        ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |SYSCTL_OSC_MAIN |SYSCTL_USE_PLL |SYSCTL_CFG_VCO_480), 120000000);
    }
    //*****************************************************************************
    //
    // Display an lwIP type IP Address.
    //
    //*****************************************************************************
    void
    DisplayIPAddress(uint32_t ui32Addr)
    {
        char pcBuf[16];
    
        //
        // Convert the IP Address into a string.
        //
        usprintf(pcBuf, "%d.%d.%d.%d", ui32Addr & 0xff, (ui32Addr >> 8) & 0xff,
                (ui32Addr >> 16) & 0xff, (ui32Addr >> 24) & 0xff);
    
        //
        // Display the string.
        //
        UARTprintf(pcBuf);
    }
    
    //*****************************************************************************
    //
    // Required by lwIP library to support any host-related timer functions.
    //
    //*****************************************************************************
    void
    lwIPHostTimerHandler(void)
    {
        uint32_t ui32NewIPAddress;
    
        //
        // Get the current IP address.
        //
        ui32NewIPAddress = lwIPLocalIPAddrGet();
    
        //
        // See if the IP address has changed.
        //
        if(ui32NewIPAddress != g_ui32IPAddress)
        {
            //
            // See if there is an IP address assigned.
            //
            if(ui32NewIPAddress == 0xffffffff)
            {
                //
                // Indicate that there is no link.
                //
                UARTprintf("Waiting for link.\n");
            }
            else if(ui32NewIPAddress == 0)
            {
                //
                // There is no IP address, so indicate that the DHCP process is
                // running.
                //
                UARTprintf("Waiting for IP address.\n");
            }
            else
            {
                //
                // Display the new IP address.
                //
                UARTprintf("IP Address: ");
                DisplayIPAddress(ui32NewIPAddress);
                UARTprintf("\nEcho Server is ready.\n");
    
            }
    
            //
            // Save the new IP address.
            //
            g_ui32IPAddress = ui32NewIPAddress;
        }
    
        //
        // If there is not an IP address.
        //
        if((ui32NewIPAddress == 0) || (ui32NewIPAddress == 0xffffffff))
        {
            //
            // Do nothing and keep waiting.
            //
        }
    }
    
    //*****************************************************************************
    //
    // The interrupt handler for the SysTick interrupt.
    //
    //*****************************************************************************
    void
    SysTickIntHandler(void)
    {
        //
        // Call the lwIP timer handler.
        //
        lwIPTimer(SYSTICKMS);
    
        //
        // Tell the application to change the state of the LED (in other words
        // blink).
        //
        g_bLED = true;
    }
    
    //*****************************************************************************
    //
    // Callback function to close the connection.
    //
    //*****************************************************************************
    static void
    close_conn (struct tcp_pcb *pcb)
    {
        //
        // NULL will be passed to all other callback functions.
        //
        tcp_arg(pcb, NULL);
        //
        // NULL callback for the PCB when data is sent.
        //
        tcp_sent(pcb, NULL);
        //
        // NULL callback for the PCB when data is received.
        //
        tcp_recv(pcb, NULL);
        //
        // Closes the connection held by the PCB.
        //
        tcp_close(pcb);
    }
    
    //*****************************************************************************
    //
    // Callback function to indicate the number of bytes that were acknowledged by
    // last acknowledgment.
    //
    //*****************************************************************************
    static err_t echo_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
    {
      LWIP_UNUSED_ARG(arg);
    
    #if 0
      char *mydata="ACK\r\n";
      tcp_write(tpcb, mydata, strlen(mydata), 0);
      tcp_sent(tpcb, echo_sent);
    #endif
    
      //
      // Print a message indicating the number of bytes that has been acknowledged
      // by the remote host.
      //
      UARTprintf("\rBytes acknowledged by the remote host:%4d", len);
    
      return ERR_OK;
    }
    
    //*****************************************************************************
    //
    // Callback function to process the received data from the client.
    //
    //*****************************************************************************
    static err_t echo_recv( void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
    {
        uint32_t ui32index;
        uint32_t ui32len;
        char *pcpayLoad;
        char pcheaderMsg[4];
        uint32_t ui32statuslen;
    
        if (err == ERR_OK && p != NULL)
        {
            //
            // tcp_recved must be called when the application has processed the
            // data and is prepared to receive more.
            //
            tcp_recved(pcb, p->tot_len);
    
            //
            // Obtain the payload length and the pointer to the payload.
            //
            pcpayLoad = (char *)p->payload;
            ui32len = p->tot_len;
    
    
            //
            // First, find out the length of the header message that will be
            // prepended before echoing back the received data from the
            // host.
            //
            ui32statuslen = strlen(pcheaderMsg);
    
            //
            // Copy the received payload to a buffer for processing.
            //
            for(ui32index = ui32statuslen;ui32index < (ui32len + ui32statuslen);ui32index++)
            {
                        g_pctcpBuffer[ui32index] =
                            pcpayLoad[ui32index-ui32statuslen];
            }
    
    #if 0
            tcp_write(pcb, pcpayLoad, ui32len, 0);
            tcp_sent(pcb, echo_sent);
    #endif
    
    #if 1
            char *mydata="HELLO\r\n";
            tcp_write(pcb, mydata, strlen(mydata), 0);
            tcp_sent(pcb, echo_sent);
    #endif
    
            //
            // Dereference a pbuf chain.
            //
            pbuf_free(p);
    
        }
    
        //
        // If the remote host requests a connection close with p == NULL then
        // close the connection held by the PCB.
        //
        if(err == ERR_OK && p == NULL)
        {
            close_conn(pcb);
        }
    
        return ERR_OK;
    }
    
    //*****************************************************************************
    //
    // Callback function for tcp_accept when a new connection arrives.
    //
    //*****************************************************************************
    static err_t echo_accept(void *arg, struct tcp_pcb *pcb, err_t err)
    {
        LWIP_UNUSED_ARG(arg);
        LWIP_UNUSED_ARG(err);
    
        tcp_setprio(pcb, TCP_PRIO_MAX);
    
        //
        // Sets the callback function - echo_recv that will be called when new
        // data arrives on the connection associated with PCB.  The callback
        // function will be passed a NULL pbuf to indicate that the remote host
        // has closed the connection.
        //
        tcp_recv(pcb, echo_recv);
        tcp_sent(pcb, echo_sent);
    
        // Error callback function currently not implemented.
        //
        tcp_err(pcb, NULL);
    
        return ERR_OK;
    }
    
    //*****************************************************************************
    //
    // Create a new TCP connection on telenet port 23 and bind it any IP addressed
    // acquired by the DHCP server.
    //
    //*****************************************************************************
    void echo_init(void)
    {
        struct tcp_pcb *tcp_pcb;
    
        //
        // Creates a new TCP connection identifier (PCB).
        //
        tcp_pcb = tcp_new();
    
        //
        // Bind the PCB to all local IP addresses at port 23.
        //
        tcp_bind(tcp_pcb, IP_ADDR_ANY, 1000);
    
        //
        // Start listening for incoming connections.  tcp_listen()
        // returns a new connection identifier and the one passed as
        // an argument to the function will be deallocated.
        //
        tcp_pcb = tcp_listen(tcp_pcb);
    
        //
        // Specify the callback function - echo_accept that should be
        // called when a new connection arrives for a listening PCB.
        //
        tcp_accept(tcp_pcb, echo_accept);
    }
    
    void ethernetEnable(void)
    {
        uint8_t pui8MACArray[8];
    
        //
        // Initialize the UART and write initial status.
        //
        UARTStdioConfig(0, 115200, ui32SysClock);
        UARTprintf("Ethernet lwIP TCP echo example.\n\n");
    
        SysTickPeriodSet(ui32SysClock / SYSTICKHZ);
        SysTickEnable();
        SysTickIntEnable();
    
        //
        // Tell the user what we are waiting for.
        //
        UARTprintf("Waiting for IP.\n");
    
        //
        // Convert the 24/24 split MAC address from NV ram into a 32/16 split MAC
        // address needed to program the hardware registers, then program the MAC
        // address into the Ethernet Controller registers.
        //
        pui8MACArray[0] = 0x70;
        pui8MACArray[1] = 0xFF;
        pui8MACArray[2] = 0x76;
        pui8MACArray[3] = 0x1D;
        pui8MACArray[4] = 0x6B;
        pui8MACArray[5] = 0x17;
    
        // Initialize the lwIP library, using DHCP.
        lwIPInit(ui32SysClock, pui8MACArray, 0xC0A80187, 0xFFFFFF00, 0xc0a80101, IPADDR_USE_STATIC);
    
        // Initialize the Echo Server.
        echo_init();
    
        // Set the interrupt priorities.  We set the SysTick interrupt to a higher
        // priority than the Ethernet interrupt to ensure that the file system
        // tick is processed if SysTick occurs while the Ethernet handler is being
        // processed.  This is very likely since all the TCP/IP and HTTP work is
        // done in the context of the Ethernet interrupt.
        IntPrioritySet(INT_EMAC0, ETHERNET_INT_PRIORITY);
        IntPrioritySet(FAULT_SYSTICK, SYSTICK_INT_PRIORITY);
    
    }
    
    //*****************************************************************************
    //
    // This example demonstrates the use of the Ethernet Controller.
    //
    //*****************************************************************************
    int main(void)
    {
        systemClockConfigure();
    
        // Configure the device pins.
        PinoutSet(true, true);
    
        ethernetEnable();
    
    
        while(1)
        {
    #if 0
            char *mydata="HELLO\r\n";
            tcp_write(pcb, mydata, strlen(mydata), 0);
            tcp_sent(pcb, echo_sent);;
    #endif
        }
    }
    

    I have attached my source code here. 

    If I loopback the data sent from client, it gives proper response but when I try to send data (no readback) within while loop it does not happen and generates errors. 

    Regards,
    Sagar

  • Please see this thread answered by David Wilson. https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/319674/optimizing-udp-in-lwip-on-tiva---how-to-determine-when-a-packet-has-been-sent

    The biggest problem here is the fact that you are calling lwIP from a context other than the Ethernet interrupt handler. lwIP is not re-entrant so you must only call it from one context. When using an RTOS, this means only calling the lwIP APIs from a single thread. When not using an RTOS (like most of our examples), you must make calls in the context of the Ethernet interrupt handler.

    Also a heads-up, I will be on vacation until next Wednesday and my response will be delayed.