Ethernet TCP Server Example
(This example is based on using a wired Ethernet port, the setup and event_handler would need adapting to use for the WiFi port)
#include <stdio.h>
#include <string.h>
#include <sys/fcntl.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_system.h"
#include "esp_err.h"
#include "esp_event_loop.h"
#include "freertos/event_groups.h"
#include "esp_event.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_eth.h"
#include "rom/ets_sys.h"
#include "rom/gpio.h"
#include "soc/dport_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/gpio_reg.h"
#include "soc/gpio_sig_map.h"
#include "tcpip_adapter.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "eth_phy/phy_lan8720.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_lan8720_default_ethernet_config
// #define PIN_PHY_POWER CONFIG_PHY_POWER_PIN //not needed for our board configuration
#define PIN_SMI_MDC GPIO_NUM_23
#define PIN_SMI_MDIO GPIO_NUM_18
#define TCP_SERVER_PORT 3000
//******************************************
//******************************************
//********** ETHERNET GPIO CONFIG **********
//******************************************
//******************************************
static void ethernet_gpio_config_rmii(void)
{
//RMII data pins are fixed:
// TXD0 = GPIO19
// TXD1 = GPIO22
// TX_EN = GPIO21
// RXD0 = GPIO25
// RXD1 = GPIO26
// CLK == GPIO0
phy_rmii_configure_data_interface_pins();
phy_rmii_smi_configure_pins(PIN_SMI_MDC, PIN_SMI_MDIO);
}
//*****************************************
//*****************************************
//********** ETHERNET INITIALISE **********
//*****************************************
//*****************************************
void ethernet_initialise (void)
{
esp_err_t ret = ESP_OK;
tcpip_adapter_init();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG;
config.phy_addr = CONFIG_PHY_ADDRESS; //Set the PHY address in configuration
config.gpio_config = ethernet_gpio_config_rmii;
config.tcpip_input = tcpip_adapter_eth_input;
ret = esp_eth_init(&config);
if(ret == ESP_OK)
{
esp_eth_enable();
tcpserver_event_group = xEventGroupCreate();
xTaskCreate(&tcp_server, "tcp_server", 4096, NULL, 5, NULL);
}
}
//***************************************
//***************************************
//********** ESP EVENT HANDLER **********
//***************************************
//***************************************
//Call this at startup:
//ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id)
{
case SYSTEM_EVENT_ETH_CONNECTED:
//Ethernet phy link up
xEventGroupSetBits(tcpserver_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
//Ethernet phy link down
xEventGroupClearBits(tcpserver_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_ETH_GOT_IP:
//Ethernet got IP from connected AP
break;
default:
break;
}
return ESP_OK;
}
//********************************
//********************************
//********** TCP SERVER **********
//********************************
//********************************
void tcp_server(void *pvParam)
{
int socket_id;
int bytes_received;
char recv_buf[64];
int client_socket;
ESP_LOGI(EthernetLogTag,"tcp_server task started \n");
struct sockaddr_in tcpServerAddr;
tcpServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
tcpServerAddr.sin_family = AF_INET;
tcpServerAddr.sin_port = htons( TCP_SERVER_PORT );
static struct sockaddr_in remote_addr;
static unsigned int socklen;
socklen = sizeof(remote_addr);
//----- WAIT FOR ETHERNET CONNECTED -----
ESP_LOGI(EthernetLogTag, "... waiting for ethernet connect \n");
xEventGroupWaitBits(tcpserver_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
while(1)
{
//----- ALLOCATE SOCKET -----
socket_id = socket(AF_INET, SOCK_STREAM, 0);
if(socket_id < 0)
{
//Couldn't allocate socket
ESP_LOGE(EthernetLogTag, "... Failed to allocate socket.\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(EthernetLogTag, "... allocated socket\n");
//----- BIND -----
if(bind(socket_id, (struct sockaddr *)&tcpServerAddr, sizeof(tcpServerAddr)) != 0)
{
ESP_LOGE(EthernetLogTag, "... socket bind failed errno=%d \n", errno);
close(socket_id);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(EthernetLogTag, "... socket bind done \n");
//----- LISTEN -----
if(listen (socket_id, 2) != 0)
{
ESP_LOGE(EthernetLogTag, "... socket listen failed errno=%d \n", errno);
close(socket_id);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
while (1)
{
//Once the socket has been created it doesn't matter if the network connection is lost, the Ethernet cable is unplugged and then re-plugged in,
//this while loop will still continue to work the next time a client connects
//----- WAIT FOR A CLIENT CONNECTION -----
ESP_LOGI(EthernetLogTag,"Waiting for new client connection...");
client_socket = accept(socket_id,(struct sockaddr *)&remote_addr, &socklen); //<<<< WE STALL HERE WAITING FOR CONNECTION
//----- A CLIENT HAS CONNECTED -----
ESP_LOGI(EthernetLogTag,"New client connection");
//Optionally set O_NONBLOCK
//If O_NONBLOCK is set then recv() will return, otherwise it will stall until data is received or the connection is lost.
//fcntl(client_socket,F_SETFL,O_NONBLOCK);
bzero(recv_buf, sizeof(recv_buf));
while (1)
{
bytes_received = recv(client_socket, recv_buf, sizeof(recv_buf)-1, 0); //<<<< WE STALL HERE WAITING FOR BYTES RECEIVED
if (bytes_received == 0)
{
//----- CONNECTION LOST -----
//There is no client any more - must have disconnected
ESP_LOGI(EthernetLogTag,"Client connection lost");
break;
}
else if (bytes_received < 0)
{
//----- NO DATA WAITING -----
//We'll only get here if O_NONBLOCK was set
//vTaskDelay(50 / portTICK_PERIOD_MS); //Release to RTOS scheduler
}
else
{
//----- DATA RECEIVED -----
ESP_LOGI(EthernetLogTag,"Data received:");
for(int i = 0; i < bytes_received; i++)
putchar(recv_buf[i]);
ESP_LOGI(EthernetLogTag,"Data receive complete");
//Clear the buffer for next time (not acutally needed but may as well)
bzero(recv_buf, sizeof(recv_buf));
//----- TRANSMIT -----
if (write(client_socket , "Hello!" , strlen("Hello!")) < 0)
{
ESP_LOGE(EthernetLogTag, "Transmit failed");
close(socket_id);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(EthernetLogTag, "Transmit complete");
}
} //while (1)
//We won't actually get here, the while loop never exits (unless its implementation gets changed!)
//----- CLOSE THE SOCKET -----
ESP_LOGI(EthernetLogTag, "Closing socket");
close(client_socket);
}
ESP_LOGI(EthernetLogTag, "TCP server will be opened again in 3 secs...");
vTaskDelay(3000 / portTICK_PERIOD_MS);
}
ESP_LOGI(EthernetLogTag, "TCP client task closed\n");
}
