STM Урок 102. LAN8720. LWIP. HTTP RAW. Часть 1



Продолжаем работать со стеком протоколов LWIP и микросхемой LAN8720.

И теперь мы попробуем создать небольшой, но вполне функциональный и полезный HTTP-сервер на основе нашей микросхемы и контроллера. Использовать мы будем ту же самую отладочную плату STM32F4-Discovery и плату расширения STM32F4DIS-BB. У кого нет такой платы, то вполне может использовать модуль от WaveShare. Просто мне с этой платой гораздо легче и комфортнее работать и если что, то не придется сетовать на плохие соединения с модулем из-за некачественных проводов.

Работаем мы также с RAW API, но проект мы лучше создадим заново, так как нам теперь не потребуется дисплей да и создать новый проект не так то и сложно.

Запустим Cube MX и создаём новый проект, выбрав наш контроллер

 

 

Настроим RCC

 

 

Выберем отладчик

 

 

Включим Ethernet

 

 

Затем LWIP

 

 

Включим ножки светодиодов на выход, они нам также потребуются

 

 

Перейдём в Clock Configuration и настроим делители и умножители для установки требуемых частот (нажмите на картинку для увеличения изображения)

 

 

Переходим в Configuration.

Сначала настроим ETH. Здесь, как обычно, MAC-адрес и адрес PHY

 

 

Далее LWIP. Заполним сначала General Settings

 

 

Затем Key Options

 

 

Настройки все те же, как и в уроке по TCP.

 

 

Теперь переходим в закладку HTTPD и включим его, также включим поддержку CGI и SSI

 

 

 

Зайдём в настройки проекта, увеличим стек и кучу и настроим генерацию проекта для System Workbench, ну и дадим нашему проекту имя

 

 

Применим настройки, сгенерируем проект, перейдём в System Workbench, подключим там наш сгенерированный проект, зайдём в его настройки, уберём всю отладочную конфигурацию, если таковая имеется, а также уровень оптимизации, как обычно, установим в 1.

Попробуем собрать наш проект.

Только он вряд ли соберётся, так как потребует наличия файла fsdata.c. Это происходит потому, что сервер HTTP работает с документами, а следовательно и с файлами. А мы никакой носитель и файловые системы не подключали. Оказывается, для этого предусмотрено хранение образов файлов во флеш-памяти контроллера как раз-то через вот такой файл. Как этот файл формируется, мы скорее всего помним из предыдущих занятий по HTTP. А формируется он с помощью утилиты makefsdata, которую найти несложно, она представляет из себя всего лишь исполняемый файл. Также она может потребовать наличие runtime библиотеки msvcr, которую можно также предоставить утилите в виде файла динамически-линкуемой библиотеки, который можно положить в папку с утилитой.

Откроем папку проекта, а в ней папку по пути «Папка с проектом/Middlewares/Third_Party/LwIP/src/apps/httpd/» и скопируем утилиту и, если потребуется файл msvcr100d.dll, в неё. Создадим также в данной палке папку с именем «fs» и скопируем в неё все нужные нам файлы сервера — веб-странички, рисунки и прочее. Только следите, чтобы всё это вместе не занимало слишком много размера, так как флеш-память у контроллера не резиновая. Запустим на выполнение теперь файл makefsdata.exe и у нас сформируется нужный нам файл fsdata.c. А как подключать настоящие файлы, используя носитель и файловую систему в RAW API, я, к сожалению, пока не разобрался. Но, думаю, нам достаточно будет и этого для того, чтобы немного разобраться с сервером HTTP, и причём не совсем немного.

Вернёмся в проект, сделаем Refresh, сделать это можно также выделив имя проекта в дереве проектов и нажав клавишу «F5«. Только теперь у нас проект тем более не соберётся. Важно знать, что файл fsdata.c должен видеться, но компилироваться не должен. Для этого вызовем на нём контекстное меню, кликнув по нем правой кнопкой мыши и зайдём в его свойства. Выберем пункт C/C++ Build и установим галочку напротив надписи «Exclude resource from build«

 

 

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

Поэтому зайдём в main.c и для начала подключим необходимые библиотеки

 

/* USER CODE BEGIN Includes */

#include "lwip/apps/httpd.h"

#include <string.h>

/* USER CODE END Includes */

 

В функции main() инициализируем сервер

 

/* USER CODE BEGIN 2 */

httpd_init();

/* USER CODE END 2 */

 

А в бесконечном цикле вызовем соответствующую функцию

 

  /* USER CODE BEGIN 3 */

  MX_LWIP_Process();

}

 

Соберём код, прошьём контроллер, в браузере в адресную строку введём IP-адрес нашего сервера, нажмём «Enter» и у нас откроется главная страничка

 

 

Также попробуем открыть страничку со ссылками на несколько рисунков. Я вставил только 4. так как у нас тольо 5 сокетов. Ну думаю, нам этого вполне достаточно

 

 

Вот как всё, оказывается, просто, когда используем LWIP.

 

 

Казалось бы, на этом можно было бы успокоиться, но мы же не такие, чтоб от нас так просто отделаться. Оказывается, наш сервер умеет работать также с передачей параметров в браузер и из браузера, то есть поддерживает CGI и SSI. Ну разве можно такое обойти?

Сначала мы попробуем поотправлять какие-нибудь параметры из нашего сервера в браузер. Параметров может быть сколько угодно. В примере в репозитории параметр был только один, нам так неинтересно. Мы конечно же захотим отправить сразу несколько. Для этого мы создали специальную страничку, в которую будут приходить данные в определённые места. Данные определённые места в веб-документе помечаются специально в виде комментария и заключенным в них какими-нибудь символьными строками или даже одной буквой. Вот по этому маркеру сервер и будет наполнять страницу данными и затем её отправлять. Недостаток CGI и SSI в том, что каждый раз, когда приходят данные, серверу приходится отправлять всю страницу. У нас страницы будут небольшие, без картинок, поэтому это некритично. А если страницы большие, навороченные стилями и текстом, то тогда есть для этого технология AJAX, которую мы в RAW использовать не сможем, а в Netcon скорей всего когда-нибудь и попробуем. Хотя она предусматривает наличие поддержки PHP на сервере, но мы это как-нибудь попробуем обойти. Ну пока CGI и SSI. А, чуть не забыл. Расширение документов для SSI должно быть shtml иначе ничего работать не будет. Вот так вот будет выглядеть код нашей странички counter.shtml

 

counter.shtml

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
<html>
<head>
<title>STM32F4xxADC</title>
<meta http-equiv="Content-Language" content="ru">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="refresh" content="1">
<meta content="MSHTML 6.00.2900.3698" name="GENERATOR">
</head>
<body>
<h4 style="text-align: center;">Счетчик STM32</h4>
<br>
<table align="center" border="1" cellpadding="5" cellspacing="1">
<tbody>
<tr>
<td>Счетчик</td>
<td><!--#p-->&nbsp </td>
<td><!--#r-->&nbsp </td>
<td><!--#s-->&nbsp </td>
<td><!--#t-->&nbsp </td>
</tr>
</tbody>
</table>
</body></html>

 

Я выделил тег, в котором мы задаём период, через который будет обновляться страничка, а следовательно и данные, у нас будет 1 секунда. Можно реже, чаще нельзя.

комментарии с маркерами. Вот туда и будут вставляться значения параметров. Мы организуем обычный счётчик, который будет наращиваться при каждом попадании в обработчик получения параметра для отправки клиента.

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

 

/* Private variables ---------------------------------------------------------*/

char const* TAGCHAR[]={"p","r","s","t"};

char const** TAGS=TAGCHAR;

uint32_t n=0;

/* USER CODE END PV */

 

Мы добавили массив со строками маркеров, которые у нас содержат только по одной букве, можно и несколько, но хватит и одной, также добавили указатель на этот массив. Ну и также добавили переменную для счётчика.

Добавим обработчик для SSI

 

//--------------------------------------------------------

uint16_t SSI_Handler(int iIndex, char *pcInsert, int iInsertLen)

{

  return 0;

}

//--------------------------------------------------------

 

Напишем тело данного обработчика

 

uint16_t SSI_Handler(int iIndex, char *pcInsert, int iInsertLen)

{

  if (iIndex ==0)

  {

    n++;

    sprintf(pcInsert,"%lu",n);

    return strlen(pcInsert);

  }

  else if (iIndex ==1)

  {

    sprintf(pcInsert,"%lu",n+5);

    return strlen(pcInsert);

  }

  else if (iIndex ==2)

  {

    sprintf(pcInsert,"%lu",n+10);

    return strlen(pcInsert);

  }

  else if (iIndex ==3)

  {

    sprintf(pcInsert,"%lu",n+15);

    return strlen(pcInsert);

  }

  return 0;

 

Мы проверяем входной парамет iIndex, который содержит индекс маркера, которые считаются по порядку, которому они расположены в глобальном строковом массиве. И мы обрабатываем каждый индекс возвращая строку с цифрой счёта. Так как каждое обновление страницы породит столько вхождений в данный обработчик, сколько у нас маркеров, то инкрементируем мы счётчик только в одном из них, а потом мы преобразуем в строку значение переменной счёта, а в остальных значение переменной, увеличенное на определённую величину. И затем мы должны возвратить длину нашей строки.

Входные параметры, надеюсь, понятны.

Обработчик готов.

Теперь в main() мы объявим указатель на наш обработчик с помощью специальной функции

 

httpd_init();

http_set_ssi_handler(SSI_Handler, (char const **)TAGS, 4);

 

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

 

 

Счетчик наш отсчитывает секунда синхронно в каждой ячейке таблицы, то есть передаются и располагаются куда надо в документе HTML (а вернее SHTML) все наши 4 параметра, переданных из программы.

Отлично!

 

В следующей части занятия мы изучим и попробуем на практике технологию CGI, а затем также попробуем их общее использование для достижения некоторых целей.

 

 

Предыдущий урок Программирование МК STM32 Следующая часть

 

 

Отладочную плату можно приобрести здесь: STM32F4-DISCOVERY

Модуль LAN можно приобрести здесь: LAN8720

Плату расширения можно приобрести здесь: STM32F4DIS-BB

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

STM LAN8720. LWIP. HTTP RAW

8 комментариев на “STM Урок 102. LAN8720. LWIP. HTTP RAW. Часть 1
  1. Александр:

    Подскажите пожалуйста: в чём отличия SSI new style от old style? Или ткните носом куда копать. Беглый поиск по гуглу не дал особо никаких результатов.

  2. Александр:

    Добрый день.
    Подскажите, почему может вебсервер не отвечать. Пишет Соединение было сброшено. Контроллер пингуется, пробовал подключаться через роутер по локальной сети, так и напрямую к компьютеру. Адреса и маски настроил корректно.
    Делал все как в вашем примере, до момента добавления картинок.

  3. Max77:

    Испытываю сложности с makefsdata.exe, у меня при создании ругается на отсутствие dll файла в 10у я его поставь прописать так и не смог. Можно ли узнать fsdata_custom.c создаётся снова ,а какие изменение в fsdata.c вносит?
    Пока пробую создавать файл из Perl файлом makefsdata.pl. Вашу страницу переделать практически не возможно.

  4. Indra:

    How to use long url like «192.168.1.100/menu/config»?

    Thank you.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*