EtherCAT SubDevice
 
Loading...
Searching...
No Matches
Webserver Example

Scope

This example covers how to integrate a HTML webserver with help of the Ethernet over EtherCAT (EoE) mailbox protocol and LWIP. To learn more about EoE, please refer to the Ethernet over EtherCAT FAQ.

Related Files

ecSubDeviceWebserver.c
ecSubDeviceWebserver.h
EtherCAT_SubDevice_Webserver.c
ESL_eoeDemo.c
ESL_eoeDemoData.h

LWIP

LWIP is a Lightweight TCP/IP stack. It is written in ANSI C and provides the following features:

  • IPv4 and IPv6 with UDP, TCP, ICMP and IGMP
  • Ethernet and IPv4/IPv6 over IEEE 802.3
  • DNS
  • SNTP
  • DHCP
  • UDP and TCP SOCKET API
  • IPv4 and IPv6 multicast

The LWIP project is distributed under the BSD-3-Clause license. The project can be downloaded here. It is also part of the MCU+SDK.

LWIP settings

The LWIP settings for the Webserver Example can be found in the files located in the source/industrial_comms/ethercat_slave/stack/lwip/lwip-config/ directory.

  • lwiphooks.h: This file contains hooks into the LWIP stack that allow the application to interact with it. For example, the application can handle the incoming UDP packet and extract the data from it.
  • lwipopts.h: This file contains the configuration options for the LWIP stack. The options can be set to enable or disable certain features, to adjust memory allocation, and to fine-tune the stack for specific use cases.
  • lwippools.h: This file contains the memory pools used by the LWIP stack. The memory pools define the size and number of memory blocks allocated for different protocols in the LWIP stack. For example, the Ethernet layer may have a pool of memory blocks for managing Ethernet frames. The application can adjust the size and number of memory blocks in the pool to optimize the performance and memory usage of the LWIP stack.

More information on these files can be found in the official LWIP documentation. Changes to these files require a rebuild of the LWIP libraries. This can be achieved through the makefile delivered with the SDK under source/industrial_comms/ethercat_slave/stack/lwip/. The command to (re-)build the libraries is:

make -s -f makefile.amxxx.r5f

Make sure make is in your systems path variable. Otherwise you can use the make binary which is part of the MCU+SDK.

The resulting libraries can be found in the /lib folder.

LWIP debugging

LWIP debugging can be enabled in the lwipopts.h file by setting the LWIP_DEBUG macro to a non-zero value and selecting the needed depth of debug prints.

#define LWIP_DEBUG 1
#ifdef LWIP_DEBUG
//#define MEM_STATS 0
#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL
#define PPP_DEBUG LWIP_DBG_ON
#define MEM_DEBUG LWIP_DBG_ON
#define MEMP_DEBUG LWIP_DBG_ON
...
#define IP_REASS_DEBUG LWIP_DBG_ON
#define ICMP_DEBUG LWIP_DBG_ON
#define IGMP_DEBUG LWIP_DBG_ON
#define UDP_DEBUG LWIP_DBG_ON
#define TCP_DEBUG LWIP_DBG_ON
#define TCP_INPUT_DEBUG LWIP_DBG_ON
#define TCP_OUTPUT_DEBUG LWIP_DBG_ON
...
#define TCP_RST_DEBUG LWIP_DBG_ON
#define ETHARP_DEBUG LWIP_DBG_ON
#endif

Webserver Example

The Webserver example distinguishes itself from the Simple example by creating

  • an additional thread to initialize and run the webserver
  • an additional thread to handle the incoming Ethernet frames
  • using the LWIP library / functions to achieve the webserver functionality
  • using the EoE APIs to receive and send the EoE settings and messages

After running the application and setting up TwinCAT (or some other MainDevice capable of EoE) and reloading the SubDevice, you should be able to connect to the webserver. To do this, you need to type the correct IP address in the address bar of a web browser of your choice. There are three different pages which can be displayed depending on the requested file:

  • xxx.xxx.xxx.xxx/main.html:
Main page
  • xxx.xxx.xxx.xxx/favicon.icon: A small Texas Instrument logo appears.
  • In case of any other requested file, a 404 Error page will be displayed:
404 Error page

Thread overview

EoE thread overview

EC_SLV_APP_SS_loopTask

The relevant parts for the Webserver Application are the registration of the EoE callbacks (and the callback handling, which is done by the stack in the background):

  • The callback EC_API_SLV_EoE_cbRegisterReceiveHandler is registering the function EC_SLV_APP_EoE_SS_receiveHandler, which is called every time a EoE message with an ethernet frame is received. The ethernet frame is then passed to the global netif structure of LWIP, allowing further processing.
bool EC_SLV_APP_EoE_SS_receiveHandler(void *pContext, uint16_t *pData, uint16_t size)
{
[...]
LOCK_TCPIP_CORE();
struct pbuf *p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL);
DebugP_assert(p != NULL);
pbuf_take(p, (const void *)pData, size);
if (gnetif.input(p, &gnetif) != ERR_OK)
{
pbuf_free(p);
p = NULL;
}
UNLOCK_TCPIP_CORE();
return true;
}
  • The callback EC_API_SLV_EoE_cbRegisterSettingIndHandler is registering the function EC_SLV_APP_EoE_SS_settingIndHandler, which is called every time a EoE message with network settings is received:
bool EC_SLV_APP_EoE_SS_settingIndHandler(void *pContext, uint16_t *pMac, uint16_t *pIp, uint16_t *pSubNet, uint16_t *pDefaultGateway, uint16_t *pDnsIp)
{
[...]
ip4_addr_t ip;
ip4_addr_t subnet;
ip4_addr_t gateway;
ip4_addr_t dns;
eoeContext_s.settingsReceived = 1;
//Values received from EtherCAT MainDevice
gnetif.hwaddr[0] = pMac[0] >> 8;
gnetif.hwaddr[1] = pMac[0] & 0xFF;
gnetif.hwaddr[2] = pMac[1] >> 8;
gnetif.hwaddr[3] = pMac[1] & 0xFF;
gnetif.hwaddr[4] = pMac[2] >> 8;
gnetif.hwaddr[5] = pMac[2] & 0xFF;
IP4_ADDR(&ip,
pIp[0] & 0xFF, pIp[0] >> 8,
pIp[1] & 0xFF, pIp[1] >> 8);
IP4_ADDR(&subnet,
pSubNet[0] & 0xFF, pSubNet[0] >> 8,
pSubNet[1] & 0xFF, pSubNet[1] >> 8);
IP4_ADDR(&gateway,
pDefaultGateway[0] & 0xFF, pDefaultGateway[0] >> 8,
pDefaultGateway[1] & 0xFF, pDefaultGateway[1] >> 8);
IP4_ADDR(&dns,
pDnsIp[0] & 0xFF, pDnsIp[0] >> 8,
pDnsIp[1] & 0xFF, pDnsIp[1] >> 8);
LOCK_TCPIP_CORE();
netif_set_addr(&gnetif, &ip, &subnet, &gateway);
UNLOCK_TCPIP_CORE();
return true;
}

The function copies the received MAC, IP, subnet, gateway, and DNS addresses to the corresponding variables of the global netif structure of LWIP.

EC_SLV_APP_EoE_SS_Task

This task can be torn down into three segments:

  • Initialize the virtual network interface with netif_if_init
  • Initialize the webserver with EC_SLV_APP_EoE_SS_initializeWebServer and
  • The actual webserver application, which interprets the received TCP/IP data and sends the corresponding html pages to the client.

It is important to notice that these functions are only called once network settings are received and the corresponding flag is set in the eoeContext_s handler. Otherwise, the EC_SLV_APP_EoE_SS_task is idle.

The function netif_if_init creates a semaphore to properly initialize the LWIP TCP/IP thread with tcpip_init(). This is necessary to run LWIP in an OS environment. Once the initialization is done, the semaphore is freed and the actual network interface is added with the LWIP function netif_add(). The function sets the IP, subnet, and gateway addresses, as well as the type of incoming frames with the parameter ethernet_input. This is important because EoE sends its data in Ethernet packages. Other flags that are set include the MAC address, the instruction to handle ARP packets, and the registration of the low-level output function. This function calls the EC_API_SLV_EoE_sendFrame API to send Ethernet frames through EoE. Finally, other necessary netif functions are called.

Network Interface Initialization

The function EC_SLV_APP_EoE_SS_initializeWebServer creates the socket structure and binds it to a port, then listens to it. The bind function in LWIP is used to associate a socket with a local address. In this case, the socket is bound to the port number 80, which is the standard port used by HTTP servers. The listen function is used to set the socket in a state in which it is listening for incoming connections. In the LWIP implementation, this call also sets the socket in a state in which it is ready to accept incoming connections.

After the webserver is initialized, the application enters a loop in which it waits for incoming TCP/IP requests. The function accept is called to accept a connection from a client. Once a connection is accepted, the LWIP recv function is called to receive a TCP/IP frame. If a TCP/IP frame is received, the application checks the frame to see if it is a GET request. A GET request is used to retrieve a specific resource from the server.

In the context of the EoE webserver example, the application handles two types of GET requests:

  • A request for the main web page: /main.html
  • A request for the favicon: /favicon.ico

In either cases the function EC_SLV_APP_EoE_SS_WebSrvProcessGetAndRespond is called and responds with response_200_content_html or response_200_content_image back to the client. If the received frame is a GET request for any other resource, the application sends the content of the response_404 back to the client.

The loop ends with closing the connection. Once a connection is closed, the application returns to waiting for a new connection. This cycle of accepting a connection, receiving a frame, processing the frame, and responding continues until the application is stopped.

Debug

The source code contains some disabled serial printouts which can be helpful when debugging. To enable them, define the macro EOE_DEBUG_PRINTS in ESL_eoeDemo.h.