Jeff,
I'm experimenting with EK-TM4C1294XL launchpad and wanted to setup the board for UDP and constantly transmit "TEST".
Using the "enet_io" example project for this board I made some modification to how I think UDP is set up with lwIP.
Is it possible for you to help me out. I think i'm doing this all wrong.
I'm including the "enet_io.c" code i'm using.
Regards,
Alonso
//***************************************************************************** // // enet_io.c - I/O control via a web server. // // Copyright (c) 2013-2014 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.1.0.12573 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 "inc/hw_nvic.h" #include "inc/hw_types.h" #include "driverlib/flash.h" #include "driverlib/gpio.h" #include "driverlib/interrupt.h" #include "driverlib/sysctl.h" #include "driverlib/systick.h" #include "driverlib/timer.h" #include "driverlib/rom_map.h" #include "utils/locator.h" #include "utils/lwiplib.h" #include "utils/uartstdio.h" #include "utils/ustdlib.h" #include "httpserver_raw/httpd.h" #include "drivers/pinout.h" #include "io.h" #include "cgifuncs.h" //***************************************************************************** // //! \addtogroup example_list //! <h1>Ethernet-based I/O Control (enet_io)</h1> //! //! This example application demonstrates web-based I/O control using the //! Tiva Ethernet controller and the lwIP TCP/IP Stack. DHCP is used to //! obtain an Ethernet address. If DHCP times out without obtaining an //! address, a static IP address will be chosen using AutoIP. The address that //! is selected will be shown on the UART allowing you to access the //! internal web pages served by the application via your normal web browser. //! //! Two different methods of controlling board peripherals via web pages are //! illustrated via pages labeled ``IO Control Demo 1'' and ``IO Control //! Demo 2'' in the navigation menu on the left of the application's home page. //! In both cases, the example allows you to toggle the state of the user LED //! on the board and set the speed of a blinking LED. //! //! ``IO Control Demo 1'' uses JavaScript running in the web browser to send //! HTTP requests for particular special URLs. These special URLs are //! intercepted in the file system support layer (io_fs.c) and used to //! control the LED and animation LED. Responses generated by the board are //! returned to the browser and inserted into the page HTML dynamically by //! more JavaScript code. //! //! ``IO Control Demo 2'' uses standard HTML forms to pass parameters to CGI //! (Common Gateway Interface) handlers running on the board. These handlers //! process the form data and control the animation and LED as requested before //! sending a response page (in this case, the original form) back to the //! browser. The application registers the names and handlers for each of its //! CGIs with the HTTPD server during initialization and the server calls //! these handlers after parsing URL parameters each time one of the CGI URLs //! is requested. //! //! Information on the state of the various controls in the second demo is //! inserted into the served HTML using SSI (Server Side Include) tags which //! are parsed by the HTTPD server in the application. As with the CGI //! handlers, the application registers its list of SSI tags and a handler //! function with the web server during initialization and this handler is //! called whenever any registered tag is found in a .shtml, .ssi, .shtm or //! .xml file being served to the browser. //! //! In addition to LED and animation speed control, the second example also //! allows a line of text to be sent to the board for output to the UART. //! This is included to illustrate the decoding of HTTP text strings. //! //! Note that the web server used by this example has been modified from the //! example shipped with the basic lwIP package. Additions include SSI and //! CGI support along with the ability to have the server automatically insert //! the HTTP headers rather than having these built in to the files in the //! file system image. //! //! Source files for the internal file system image can be found in the ``fs'' //! directory. If any of these files are changed, the file system image //! (io_fsdata.h) should be rebuilt by running the following command from the //! enet_io directory: //! //! ../../../../tools/bin/makefsfile -i fs -o io_fsdata.h -r -h -q //! //! For additional details on lwIP, refer to the lwIP web page at: //! http://savannah.nongnu.org/projects/lwip/ // //***************************************************************************** //***************************************************************************** // // 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 //***************************************************************************** // // A set of flags. The flag bits are defined as follows: // // 0 -> An indicator that the animation timer interrupt has occurred. // //***************************************************************************** #define FLAG_TICK 0 static volatile unsigned long g_ulFlags; //***************************************************************************** // // External Application references. // //***************************************************************************** extern void httpd_init(void); extern void udp_init(void); //***************************************************************************** // // SSI tag indices for each entry in the g_pcSSITags array. // //***************************************************************************** #define SSI_INDEX_LEDSTATE 0 #define SSI_INDEX_FORMVARS 1 #define SSI_INDEX_SPEED 2 //***************************************************************************** // // This array holds all the strings that are to be recognized as SSI tag // names by the HTTPD server. The server will call SSIHandler to request a // replacement string whenever the pattern <!--#tagname--> (where tagname // appears in the following array) is found in ".ssi", ".shtml" or ".shtm" // files that it serves. // //***************************************************************************** static const char *g_pcConfigSSITags[] = { "LEDtxt", // SSI_INDEX_LEDSTATE "FormVars", // SSI_INDEX_FORMVARS "speed" // SSI_INDEX_SPEED }; //***************************************************************************** // // The number of individual SSI tags that the HTTPD server can expect to // find in our configuration pages. // //***************************************************************************** #define NUM_CONFIG_SSI_TAGS (sizeof(g_pcConfigSSITags) / sizeof (char *)) //***************************************************************************** // // Prototypes for the various CGI handler functions. // //***************************************************************************** static char *ControlCGIHandler(int32_t iIndex, int32_t i32NumParams, char *pcParam[], char *pcValue[]); static char *SetTextCGIHandler(int32_t iIndex, int32_t i32NumParams, char *pcParam[], char *pcValue[]); //***************************************************************************** // // Prototype for the main handler used to process server-side-includes for the // application's web-based configuration screens. // //***************************************************************************** static int32_t SSIHandler(int32_t iIndex, char *pcInsert, int32_t iInsertLen); //***************************************************************************** // // CGI URI indices for each entry in the g_psConfigCGIURIs array. // //***************************************************************************** #define CGI_INDEX_CONTROL 0 #define CGI_INDEX_TEXT 1 //***************************************************************************** // // This array is passed to the HTTPD server to inform it of special URIs // that are treated as common gateway interface (CGI) scripts. Each URI name // is defined along with a pointer to the function which is to be called to // process it. // //***************************************************************************** static const tCGI g_psConfigCGIURIs[] = { { "/iocontrol.cgi", (tCGIHandler)ControlCGIHandler }, // CGI_INDEX_CONTROL { "/settxt.cgi", (tCGIHandler)SetTextCGIHandler } // CGI_INDEX_TEXT }; //***************************************************************************** // // The number of individual CGI URIs that are configured for this system. // //***************************************************************************** #define NUM_CONFIG_CGI_URIS (sizeof(g_psConfigCGIURIs) / sizeof(tCGI)) //***************************************************************************** // // The file sent back to the browser by default following completion of any // of our CGI handlers. Each individual handler returns the URI of the page // to load in response to it being called. // //***************************************************************************** #define DEFAULT_CGI_RESPONSE "/io_cgi.ssi" //***************************************************************************** // // The file sent back to the browser in cases where a parameter error is // detected by one of the CGI handlers. This should only happen if someone // tries to access the CGI directly via the broswer command line and doesn't // enter all the required parameters alongside the URI. // //***************************************************************************** #define PARAM_ERROR_RESPONSE "/perror.htm" #define JAVASCRIPT_HEADER \ "<script type='text/javascript' language='JavaScript'><!--\n" #define JAVASCRIPT_FOOTER \ "//--></script>\n" //***************************************************************************** // // Timeout for DHCP address request (in seconds). // //***************************************************************************** #ifndef DHCP_EXPIRE_TIMER_SECS #define DHCP_EXPIRE_TIMER_SECS 5 // was 45 #endif //***************************************************************************** // // The current IP address. // //***************************************************************************** uint32_t g_ui32IPAddress; //***************************************************************************** // // The system clock frequency. Used by the SD card driver. // //***************************************************************************** uint32_t g_ui32SysClock; struct udp_pcb *remote_pcb; struct pbuf* pbuf1; char buf [120]; //***************************************************************************** // // The error routine that is called if the driver library encounters an error. // //***************************************************************************** #ifdef DEBUG void __error__(char *pcFilename, uint32_t ui32Line) { } #endif //***************************************************************************** // // This CGI handler is called whenever the web browser requests iocontrol.cgi. // //***************************************************************************** static char * ControlCGIHandler(int32_t iIndex, int32_t i32NumParams, char *pcParam[], char *pcValue[]) { int32_t i32LEDState, i32Speed; bool bParamError; // // We have not encountered any parameter errors yet. // bParamError = false; // // Get each of the expected parameters. // i32LEDState = FindCGIParameter("LEDOn", pcParam, i32NumParams); i32Speed = GetCGIParam("speed_percent", pcParam, pcValue, i32NumParams, &bParamError); // // Was there any error reported by the parameter parser? // if(bParamError || (i32Speed < 0) || (i32Speed > 100)) { return(PARAM_ERROR_RESPONSE); } // // We got all the parameters and the values were within the expected ranges // so go ahead and make the changes. // io_set_led((i32LEDState == -1) ? false : true); io_set_animation_speed(i32Speed); // // Send back the default response page. // return(DEFAULT_CGI_RESPONSE); } //***************************************************************************** // // This CGI handler is called whenever the web browser requests settxt.cgi. // //***************************************************************************** static char * SetTextCGIHandler(int32_t i32Index, int32_t i32NumParams, char *pcParam[], char *pcValue[]) { long lStringParam; char pcDecodedString[48]; // // Find the parameter that has the string we need to display. // lStringParam = FindCGIParameter("DispText", pcParam, i32NumParams); // // If the parameter was not found, show the error page. // if(lStringParam == -1) { return(PARAM_ERROR_RESPONSE); } // // The parameter is present. We need to decode the text for display. // DecodeFormString(pcValue[lStringParam], pcDecodedString, 48); // // Print sting over the UART // UARTprintf(pcDecodedString); UARTprintf("\n"); // // Tell the HTTPD server which file to send back to the client. // return(DEFAULT_CGI_RESPONSE); } //***************************************************************************** // // This function is called by the HTTP server whenever it encounters an SSI // tag in a web page. The iIndex parameter provides the index of the tag in // the g_pcConfigSSITags array. This function writes the substitution text // into the pcInsert array, writing no more than iInsertLen characters. // //***************************************************************************** static int32_t SSIHandler(int32_t iIndex, char *pcInsert, int32_t iInsertLen) { // // Which SSI tag have we been passed? // switch(iIndex) { case SSI_INDEX_LEDSTATE: io_get_ledstate(pcInsert, iInsertLen); break; case SSI_INDEX_FORMVARS: usnprintf(pcInsert, iInsertLen, "%sls=%d;\nsp=%d;\n%s", JAVASCRIPT_HEADER, io_is_led_on(), io_get_animation_speed(), JAVASCRIPT_FOOTER); break; case SSI_INDEX_SPEED: io_get_animation_speed_string(pcInsert, iInsertLen); break; default: usnprintf(pcInsert, iInsertLen, "??"); break; } // // Tell the server how many characters our insert string contains. // return(strlen(pcInsert)); } //***************************************************************************** // // The interrupt handler for the SysTick interrupt. // //***************************************************************************** void SysTickIntHandler(void) { // // Call the lwIP timer handler. // lwIPTimer(SYSTICKMS); } //***************************************************************************** // // The interrupt handler for the timer used to pace the animation. // //***************************************************************************** void AnimTimerIntHandler(void) { // // Clear the timer interrupt. // MAP_TimerIntClear(TIMER2_BASE, TIMER_TIMA_TIMEOUT); // // Indicate that a timer interrupt has occurred. // HWREGBITW(&g_ulFlags, FLAG_TICK) = 1; } //***************************************************************************** // // 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 ui32Idx, 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("\n"); UARTprintf("Open a browser and enter the IP address.\n"); } // // Save the new IP address. // g_ui32IPAddress = ui32NewIPAddress; } // // If there is not an IP address. // if((ui32NewIPAddress == 0) || (ui32NewIPAddress == 0xffffffff)) { // // Loop through the LED animation. // for(ui32Idx = 1; ui32Idx < 100; ui32Idx++) //was < 17 { // // Toggle the GPIO // MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, (MAP_GPIOPinRead(GPIO_PORTN_BASE, GPIO_PIN_1) ^ GPIO_PIN_1)); SysCtlDelay(g_ui32SysClock/(ui32Idx << 1)); } } } //***************************************************************************** // // This example demonstrates the use of the Ethernet Controller and lwIP // TCP/IP stack to control various peripherals on the board via a web // browser. // //***************************************************************************** int main(void) { uint32_t ui32User0, ui32User1; uint8_t pui8MACArray[8]; // // Make sure the main oscillator is enabled because this is required by // the PHY. The system must have a 25MHz crystal attached to the OSC // pins. The SYSCTL_MOSC_HIGHFREQ parameter is used when the crystal // frequency is 10MHz or higher. // SysCtlMOSCConfigSet(SYSCTL_MOSC_HIGHFREQ); // // Run from the PLL at 120 MHz. // g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000); // // Configure the device pins. // PinoutSet(true, false); // // Configure debug port for internal use. // UARTStdioConfig(0, 115200, g_ui32SysClock); // // Clear the terminal and print a banner. // UARTprintf("\033[2J\033[H"); UARTprintf("Ethernet IO Example\n\n"); // // Configure SysTick for a periodic interrupt. // MAP_SysTickPeriodSet(g_ui32SysClock / SYSTICKHZ); MAP_SysTickEnable(); MAP_SysTickIntEnable(); // // Configure the hardware MAC address for Ethernet Controller filtering of // incoming packets. The MAC address will be stored in the non-volatile // USER0 and USER1 registers. // MAP_FlashUserGet(&ui32User0, &ui32User1); if((ui32User0 == 0xffffffff) || (ui32User1 == 0xffffffff)) { // // Let the user know there is no MAC address // UARTprintf("No MAC programmed!\n"); while(1) { } } // // Tell the user what we are doing just now. // 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] = ((ui32User0 >> 0) & 0xff); pui8MACArray[1] = ((ui32User0 >> 8) & 0xff); pui8MACArray[2] = ((ui32User0 >> 16) & 0xff); pui8MACArray[3] = ((ui32User1 >> 0) & 0xff); pui8MACArray[4] = ((ui32User1 >> 8) & 0xff); pui8MACArray[5] = ((ui32User1 >> 16) & 0xff); // // Initialze the lwIP library, using DHCP. // lwIPInit(g_ui32SysClock, pui8MACArray, 0, 0, 0, IPADDR_USE_AUTOIP); // // Setup the device locator service. // LocatorInit(); LocatorMACAddrSet(pui8MACArray); LocatorAppTitleSet("EK-TM4C1294XL enet_io"); // // Initialize a sample httpd server. // httpd_init(); udp_init(); struct udp_pcb * mypcb; mypcb = udp_new(); if (mypcb == NULL) { UARTprintf("udp failed.\n"); } else { UARTprintf("udp up.\n"); } if (udp_bind(mypcb, IP_ADDR_ANY, 8760) != ERR_OK) { UARTprintf("udp bind failed.\n"); } // // 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. // MAP_IntPrioritySet(INT_EMAC0, ETHERNET_INT_PRIORITY); MAP_IntPrioritySet(FAULT_SYSTICK, SYSTICK_INT_PRIORITY); // // Pass our tag information to the HTTP server. // http_set_ssi_handler((tSSIHandler)SSIHandler, g_pcConfigSSITags, NUM_CONFIG_SSI_TAGS); // // Pass our CGI handlers to the HTTP server. // http_set_cgi_handlers(g_psConfigCGIURIs, NUM_CONFIG_CGI_URIS); // // Initialize IO controls // io_init(); // // Loop forever, processing the on-screen animation. All other work is // done in the interrupt handlers. // while(1) { // // Wait for a new tick to occur. // while(!g_ulFlags) { // // Do nothing. // } // // Clear the flag now that we have seen it. // HWREGBITW(&g_ulFlags, FLAG_TICK) = 0; // // Toggle the GPIO // MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, (MAP_GPIOPinRead(GPIO_PORTN_BASE, GPIO_PIN_1) ^ GPIO_PIN_1)); // // Transmit to UDP // static int n = 0; pbuf1 = pbuf_alloc(PBUF_TRANSPORT, 100, PBUF_RAM); pbuf1->payload = (void*)buf; pbuf1->tot_len = 15; pbuf1->len = 15; buf[0] = 0x10; buf[1] = 0; usprintf(&buf[4], " test %d", n++); udp_send(remote_pcb, pbuf1); pbuf_free(pbuf1); } }