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



В предыдущей части занятия мы создали и настроили проект, написали и проверили код WEB-сервера, а также написали и проверили код для использования SSI.

 

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

Для этого у нас уже есть другой документ led.html

 

led.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head><title>LED</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta content="MSHTML 6.00.2800.1561" name="GENERATOR">
<style ="font-weight: normal; font-family: Verdana;"></style></head>
<body>
<h4  style="text-align: center;">LED Form</h4>
<br>
<form align="center" method="get" action="/leds.cgi">
<input value="1" name="led" type="checkbox">LED1<br>
<input value="2" name="led" type="checkbox">LED2<br>
<input value="3" name="led" type="checkbox">LED3<br>
<input value="4" name="led" type="checkbox">LED4<br>
<br>
<input value="Send" type="submit"> </form>
</body></html>

 

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

Чтобы это всё работало, перейдём в проект и добавим ещё несколько глобальных переменных и прототип

 

uint32_t n=0;

const char * LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]);

const tCGI LEDS_CGI={"/leds.cgi", LEDS_CGI_Handler};

tCGI CGI_TAB[1];

uint8_t ledstate=0;

 

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

 

 

Добавим обработчик запроса после обработчика SSI

 

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

const char * LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[])

{

  uint32_t i=0;

  if (iIndex==0)

  {

    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);

    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET);

    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);

    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET);

    ledstate = 0;

    for (i=0; i<iNumParams; i++)

    {

      if (strcmp(pcParam[i] , "led")==0)

      {

        if(strcmp(pcValue[i], "1") ==0)

        {

          ledstate |= 1;

          HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);

        }

        else if(strcmp(pcValue[i], "2") ==0)

        {

          HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);

          ledstate |= 2;

        }

        else if(strcmp(pcValue[i], "3") ==0)

        {

          HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);

          ledstate |= 4;

        }

        else if(strcmp(pcValue[i], "4") ==0)

        {

          HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET);

          ledstate |= 8;

        }

      }

    }

  }

  return "/led.html";

}

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

 

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

Но это не всё. Надо ещё в main() кое-что проделать

 

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

CGI_TAB[0] = LEDS_CGI;

http_set_cgi_handlers(CGI_TAB, 1);

 

Мы инициализировали элемент массива и обработчик.

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

 

 

Установим галки в любые чекбоксы и нажмём кнопку «Send». У нас будут доджны загореться соответствующие светодиоды

 

 

Только не понравилось мне одно. После нажатия кнопки и перезагрузки документа галки убираются, хотелось бы, чтобы они остались на месте. Я долго думал как это реализовать. Но всё же выход нашел. Я применил здесь SSI, который вернёт в качестве параметра все, что нам надо. Для этого-то и был придуман статус.

 

 

Вызывать в браузере мы будем уже другой документ — led.shtml со следующим кодом

 

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head><title>LED</title>

<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta content="MSHTML 6.00.2800.1561" name="GENERATOR">
<style ="font-weight: normal; font-family: Verdana;"></style></head>
<body>
<h4  style="text-align: center;">LED Form</h4>
<br>
<form align="center" method="get" action="/leds.cgi">
<!--#p--> LED1<br>
<!--#r--> LED2<br>
<!--#s--> LED3<br>
<!--#t--> LED4<br>
<br>
<input value="Send" type="submit"> </form>
</body></html>

 

В данном документе у нас уже отстуствуют теги и вместо них находятся комментарии с маркерами.

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

Смысл в том, что для того, чтобы чекбокс был с галкой, мы должны в тег input вставить свойство в виде атрибута без параметра. Это атрибут checked.

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

 

uint8_t ledstate=0;

char htmstr1[] = "<input value=\"";

char htmstr2[] = "\" name=\"led\" type=\"checkbox\"";

 

В фукнции-обработчике SSI SSI_Handler закомментируем весь код кроме последней строки с возвратом нулевой длины и добавим другой код

 

SSI_Handler

*/

strcpy(pcInsert,htmstr1);

if (iIndex ==0)

{

  strcat(pcInsert,"1");

  strcat(pcInsert,htmstr2);

  if(ledstate&0x01)

  {

    strcat(pcInsert," checked> ");

  }

  else

  {

    strcat(pcInsert,"> ");

  }

  return strlen(pcInsert);

}

else if (iIndex ==1)

{

  strcat(pcInsert,"2");

  strcat(pcInsert,htmstr2);

  if(ledstate&0x02)

  {

    strcat(pcInsert," checked> ");

  }

  else

  {

    strcat(pcInsert,"> ");

  }

  return strlen(pcInsert);

}

else if (iIndex ==2)

{

  strcat(pcInsert,"3");

  strcat(pcInsert,htmstr2);

  if(ledstate&0x04)

  {

    strcat(pcInsert," checked> ");

  }

  else

  {

    strcat(pcInsert,"> ");

  }

  return strlen(pcInsert);

}

else if (iIndex ==3)

{

  strcat(pcInsert,"4");

  strcat(pcInsert,htmstr2);

  if(ledstate&0x08)

  {

    strcat(pcInsert," checked> ");

  }

  else

  {

    strcat(pcInsert,"> ");

  }

  return strlen(pcInsert);

}

return 0;

 

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

Но нет, вообще-то не совсем всё. В функции LEDS_CGI_Handler не забываем изменить расширение документа при возврате, а то мы вернем не тот документ

 

  return "/led.shtml";

}

 

Собираем код, прошиваем контроллер и смотрим результат, вызывая в браузере конечно led.shtml

 

 

Код отлично работает!

У нас также управляются светодиоды и галки уже из чекбоксов при перезагрузке страницы никуда не пропадают.

Таким образом, мы сегодня научились создавать простой HTTP-сервер, а также научились использовать функционал данного сервера по работе с CGI и SSI, причем также и одновременно с обоими.

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

 

 

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

 

Исходный код

 

 

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

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

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

 

 

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

 

STM LAN8720. LWIP. HTTP RAW

Один комментарий на “STM Урок 102. LAN8720. LWIP. HTTP RAW. Часть 2
  1. Георгий:

    STM32Cube_FW_F4_V1.26.2 жалуется на отсутствие файла «fsdata_custom.c»…
    Файла в проекте нет.Заработало после замены на «../../../apps/httpd/fsdata.c»
    после перезаписи проекта из куба строку надо менять заново…
    Что за файл «fsdata_custom.c» где искать?

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

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

*