Найти в Дзене
narod stream

ESP32 Урок 27. Wi-Fi. STA. Простой HTTP Server

Продолжаем работу с протоколами модели OSI и на данном уроке мы попытаемся создать простой сервер HTTP, который позволит нам принять запрос документа от клиента, обработать его и в ответ направить клиенту нужную информацию. Также мы раньше подобные задачи решали с использованием других контроллеров, в том числе и родственного ESP8266, поэтому думаю, что с данной задачей мы без особого труда справимся. Сервер считается простым, так как отвечать он будет на запросы не любых документов, а только главной страницы и иконки приложения. Также мы для упрощения задачи не используем шифрование. Дисплей нам на данном уроке не потребуется, поэтому схема наша будет состоять только из отладочной платы с контроллером ESP32, подключенной к USB-порту компьютера Проект за основу мы возьмём из прошлого урока с именем WIFI_STA_TCP_SERVER и присвоим ему имя WIFI_STA_HTTP_SERVER. Откроем проект в Espressif IDE и удалим файлы lcd2004.h, lcd2004.c, i2c_user.h и i2c_user.c, так как с дисплеем мы работать не бу

Продолжаем работу с протоколами модели OSI и на данном уроке мы попытаемся создать простой сервер HTTP, который позволит нам принять запрос документа от клиента, обработать его и в ответ направить клиенту нужную информацию. Также мы раньше подобные задачи решали с использованием других контроллеров, в том числе и родственного ESP8266, поэтому думаю, что с данной задачей мы без особого труда справимся. Сервер считается простым, так как отвечать он будет на запросы не любых документов, а только главной страницы и иконки приложения. Также мы для упрощения задачи не используем шифрование.

Дисплей нам на данном уроке не потребуется, поэтому схема наша будет состоять только из отладочной платы с контроллером ESP32, подключенной к USB-порту компьютера

Проект за основу мы возьмём из прошлого урока с именем WIFI_STA_TCP_SERVER и присвоим ему имя WIFI_STA_HTTP_SERVER.

Откроем проект в Espressif IDE и удалим файлы lcd2004.hlcd2004.ci2c_user.h и i2c_user.c, так как с дисплеем мы работать не будем. Также подключение данных модулей мы удалим и в файле CMakeLists.txt

set(COMPONENT_SRCS "main.c wifi.c tcp.c i2c_user.c lcd2004.c")

В файле Kconfig.projbuild удалим секции, отвечающие за ножки I2C

config SDA_GPIO
  int "SDA GPIO number"
  range 0 48
  default 21
  help
  GPIO number SDA.

config SCL_GPIO
  int "SCL GPIO number"
  range 0 48
  default 22
  help
  GPIO number SCL.

Зайдём в конфигуратор и изменим порт на значение по умолчанию для работы с протоколом HTTP

-2

Удалим подключение заголовочного файла из main.h и tcp.h

#include "lcd2004.h"

В функции app_main файла main.c удалим строки связанные с инициализацией дисплея

ret = i2c_ini();
ESP_LOGI(TAG, "i2c_ini: %d", ret);
LCD_ini();

Файлы tcp.h и tcp.c переименуем соответственно в http.h и http.c.

Изменим подключение модуля также в файле CMakeLists.txt

set(COMPONENT_SRCS "main.c wifi.c http.c")

Перейдём в файл http.c и удалим функцию vLCDTask вместе с телом.

Удалим также и функцию client_socket_task.

Структуры и очереди нам также не потребуются

typedef struct struct_client_socket_t {
  struct sockaddr_in cliaddr;
  socklen_t sockaddrsize;
  int accept_sock;
  uint16_t y_pos;
} struct_client_socket;
struct_client_socket client_socket01;
//-------------------------------------------------------------
typedef struct
{
  unsigned char y_pos;
  unsigned char x_pos;
  char *str;
} qLCDData;
//------------------------------------------------
xQueueHandle lcd_string_queue = NULL, xQueueClose = NULL, xQueueCloseAsk = NULL;

Переименуем строку

static const char *TAG = "http";

Также переименуем функцию задачи

void http_task(void *pvParameters)

Не забываем также о прототипе в заголовочном файле. Также в функции app_main файла main.c переименуем аргументы в создании задачи

xTaskCreate(http_task, «http_task«, 4096, NULL, 5, NULL);

Вернёмся в файл http.c и в функции http_task удалим объявление хендла задачи дисплея

TaskHandle_t xLCDTaskHandle = NULL;

Удалим инициализацию позиции

unsigned char y_pos = 0;

Удалим также вот эти строки

qLCDData xLCDData;
char str1[21];
xLCDData.y_pos = 1;
xLCDData.str = str1;

Удалим и вот эти строки, также связанные с дисплеем

lcd_string_queue = xQueueCreate(10, sizeof(qLCDData));
xQueueClose = xQueueCreate(10, sizeof(unsigned char));
xQueueCloseAsk = xQueueCreate(10, sizeof(unsigned char));
xTaskCreate(vLCDTask, «vLCDTask», 2048, NULL, 2, &xLCDTaskHandle);

Здесь удалим перевод строки, чтобы не создавалась лишняя, в функции для вывода логов строки переводятся автоматически

ESP_LOGI(TAG, «Create socket…\n«);

ESP_LOGE(TAG, «socket not created\n«);

Тут исправим грамматическую ошибочку

//Свяжем сокет с адресом сервера

В следующем условии удалим уничтожение задачи и очереди

vQueueDelete(lcd_string_queue);
vTaskDelete(NULL);

Тело следующего условия удалим полностью

if(accept_sock >= 0)
{
  client_socket01.accept_sock = accept_sock;
  client_socket01.cliaddr = cliaddr;
  client_socket01.sockaddrsize = sockaddrsize;
  client_socket01.y_pos = y_pos%4;
  xTaskCreate(client_socket_task, "client_socket_task", 4096, (void*)&client_socket01, 5, NULL);
  y_pos++;
}

В конце тела функции удалим вот эти строки

sprintf(str1, "Disonnected");
xQueueSendToBack(lcd_string_queue, &xLCDData, 0);
vTaskDelay(2000 / portTICK_RATE_MS);
vTaskDelete(xLCDTaskHandle);
vQueueDelete(lcd_string_queue);

Теперь у нас хотя бы будет собираться код.

Добавим переменную в объявление

int sockfd, accept_sock, ret;

Объявим указатель на буфер, а также объявим и инициализируем длину буфера

В условии, тело которого мы удалили, запросим память для буфера и попытаемся принять от клиента пакет

Теперь нам надо будет подготовить документы, которые мы будем предоставлять клиенту на его запросы.

Сделаем мы это так, как делали раньше с AVR, подготовив массив с помощью утилиты makefsdata (в конце страницы будет ссылка на архив утилиты с примерами страницы и иконки). Содержимое страницы и заголовка HTTP мы поместим в глобальные массивы

С иконкой поступим немного по-другому. Мы её не будем собирать из двух массивов, а создадим для неё общий массив вместе с заголовком. Памяти лишней мы не истратим, так как иконка у нас одна. Зато передавать мы её будем сразу из исходного массива

Вернёмся в функцию http_task и поместим наш ответ на запрос главной страницы в буфер, соединив наши массивы заголовка и контента страницы, а перед этим отфильтровав всё ненужное

Отправим пакет клиенту

А если запрос был на иконку, то передадим наш массив сразу, ничего не копируя и не соединяя

Выйдем из условия наличия ненулевого пакета (посчитайте закрывающие скобки) и разъединимся с клиентом, а затем освободим память, данную нам под буфер

В принципе, это весь код нашего простенького сервера HTTP. Соберём проект, прошьём контроллер и в терминале запомним сетевой адрес нашего сервера (отладочной платы)

-3

Попытаемся в браузере запросить страницу и, если всё нормально, то мы получим и страницу и иконку

-4

В анализаторе трафика у нас тоже всё нормально. Все ответы пришли, порты после получения документов отключились

-5

Итак, на данном уроке нам удалось создать простейший HTTP-сервер, который может обрабатывать запрос документов от клиента и передавать ему их в форме пакета HTTP.

Всем спасибо за внимание!

Оригинал статьи находится здесь.

<<Предыдущий урок | Следующий урок>>

Исходный код

Утилита для получения двоичного кода страниц и других файлов: makefsdata

Недорогие отладочные платы ESP32 можно купить здесь
Недорогие отладочные платы ESP32/ESP32-C3/ESP32-S3 можно купить
здесь
Логический анализатор 16 каналов можно приобрести
здесь
Многофункциональный переходник CJMCU FT232H USB к JTAG UART FIFO SPI I2C можно купить
здесь

Видео в Rutube

Программирование МК ESP32. Урок 27. Wi-Fi. STA. Простой HTTP Server

Видео в Дзен

Видео в Youtube