[Разработка веб-сайтов, Программирование, Сетевые технологии, Программирование микроконтроллеров] Разрабатываем web-site для микроконтроллера
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
С приходом в нашу жизнь различного рода умных розеток, лампочек и других подобных устройств, необходимость наличия веб-сайтов на микроконтроллерах стала неоспоримой. А благодаря проекту lwIP (и его младшему брату uIP) подобным функционалом никого не удивишь. Но поскольку lwIP направлен на минимизацию ресурсов, то с точки зрения дизайна, функционала, а также удобства использования и разработки, подобные сайты сильно отстают от тех, к которым мы привыкли. Даже для встроенных систем, сравнить, например, с сайтом для администрирования на самых дешевых роутерах. В данной статье мы попробуем разработать сайт на Линуксе для какого-нибудь умного устройства и запустить его на микроконтроллере.
Для запуска на микроконтроллере будем использовать Embox. В состав этой RTOS входит HTTP сервер с поддержкой CGI. В качестве HTTP сервера на Linux будем использовать встроенный в python HTTP сервер.
python3 -m http.server -d <site folder>
Статический сайт
Начнем с простого статического сайта, состоящего из одной или нескольких страниц.
Тут все просто, давайте создадим папку и в ней index.html. Этот файл будет скачиваться по умолчанию, если в браузере задан только адрес сайта.
$ ls website/
em_big.png index.html
Сайт еще будет содержать логотип Embox, файл “em_big.png”, который мы встроим в html.
Запустим http сервер
python3 -m http.server -d website/
Зайдем в браузере на localhost:8000
Теперь добавим наш статический сайт в файловую систему Embox. Это можно сделать скопировав нашу папку в папку rootfs/ темплейта (текущий темплейт в папке conf/rootfs). Или создать модуль указав в нем файлы для rootfs.
$ ls website/
em_big.png index.html Mybuild
Содержимое Mybuild.
package embox.demo
module website {
@InitFS
source "index.html",
"em_big.png",
}
Для простоты мы положим наш сайт прямо в корневую папку (аннотация @InitFs без параметров).
Нам также нужно включить наш сайт в конфигурационном файле mods.conf и туда же добавить сам httd сервер
include embox.cmd.net.httpd
include embox.demo.website
Кроме того, давайте запустим сервер с нашим сайтом во время старта системы. Для этого добавим строчку в файл conf/system_start.inc
"service httpd /",
Естественно все эти манипуляции нужно делать с конфигом для платы. После этого собираем и запускаем. Заходим в браузере на адрес вашей платы. В моем случае это 192.168.2.128
И имеем такую же картинку как и для локального сайта
Мы не являемся специалистами по веб-разработке, но слышали, что для создания красивых веб сайтов используются различные фреймворки. Например, часто используется AngularJS. Поэтому дальнейшие примеры мы будем приводить с его использованием. Но при этом мы не будем вдаваться в детали и заранее извиняемся если где-то сильно налажали с веб дизайном.
Какой-бы статический контент не положили в папку с сайтом, например, js или css файлы, мы можем его использовать без каких-либо дополнительных усилий.
Добавим в наш сайт app.js (сайт на angular) и в нем пару вкладок. Страницы для этих вкладок положим в папку partials, изображения в папку images/, а css файлы в css/.
$ ls website/
app.js css images index.html Mybuild partials
Запустим наш сайт.
Согласитесь, сайт выглядит гораздо привычнее и приятнее. Причем все это сделано на стороне браузера. Как мы и сказали, весь контекст все еще статический. И мы его можем разрабатывать на хосте как обычный сайт.
Естественно, при этом можно использовать все средства разработки обычных веб-девелоперов. Так, открыв консоль в браузере, мы обнаружили сообщение об ошибке, о том что не хватает favicon.ico:
Выяснили, что это иконка которая отображается во вкладке браузера. Можно конечно положить файл с этим именем, но порой не хочется тратить на это место. Напоминаю, что хотим запускаться в том числе и на микроконтроллерах, где памяти мало.
Поиск в интернете сразу выдал, что можно обойтись и без файла, нужно всего лишь добавить строку в head секцию html. Хотя ошибка не мешала, но сделать сайт чуть лучше всегда приятно. И главное, что мы убедились, что обычные средства разработчика вполне применимы при предлагаемом подходе.
Динамический контент
CGI
Перейдем к динамическому контенту. Common Gateway Interface (CGI) интерфейс взаимодействия web-сервера с утилитами командной строки, позволяющий создавать динамический контент. Иными словами, CGI позволяет использовать вывод утилит для генерации динамического контента.
Давайте взглянем на какой-нибудь CGI скрипт
#!/bin/bash
echo -ne "HTTP/1.1 200 OK\r\n"
echo -ne "Content-Type: application/json\r\n"
echo -ne "Connection: Connection: close\r\n"
echo -ne "\r\n"
tm=`LC_ALL=C date +%c`
echo -ne ""$tm"\n\n"
Вначале в стандартный output печатается http заголовок, а затем печатаются данные самой страницы. output может быть перенаправлен куда угодно. Можно просто запустить этот скрипт из консоли. Увидим следующее:
./cgi-bin/gettime
HTTP/1.1 200 OK
Content-Type: application/json
Connection: Connection: close
"Fri Feb 5 20:58:19 2021"
А если вместо стандартного output это будет socket то браузер получит эти данные.
CGI часто реализуют с помощью скриптов, даже говорят cgi scripts. Но это не обязательно, просто на скриптовых языках подобные вещи делать быстрее и удобнее. Утилита предоставляющая CGI может быть реализована на любом языке. И так как мы ориентируемся на микроконтроллеры, следовательно, стараемся заботиться об экономии ресурсов. Давайте то же самое реализуем на С.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[]) {
char buf[128];
char *pbuf;
struct timeval tv;
time_t time;
printf(
"HTTP/1.1 200 OK\r\n"
"Content-Type: application/json\r\n"
"Connection: Connection: close\r\n"
"\r\n"
);
pbuf = buf;
pbuf += sprintf(pbuf, """);
gettimeofday(&tv, NULL);
time = tv.tv_sec;
ctime_r(&time, pbuf);
strcat(pbuf, ""\n\n");
printf("%s", buf);
return 0;
}
Если скомпилировать данный код и запустить, мы увидим точно такой же вывод как и в случае со скриптом.
В наш app.js добавим обработчик для вызова CGI скрипта для одной из нашей вкладки
app.controller("SystemCtrl", ['$scope', '$http', function($scope, $http) {
$scope.time = null;
$scope.update = function() {
$http.get('cgi-bin/gettime').then(function (r) {
$scope.time = r.data;
});
};
$scope.update();
}]);
Небольшой нюанс по запуску на Linux с помощью встроенного сервера python. В нашу строку запуска нужно добавить аргумент --cgi для поддержки CGI:
python3 -m http.server --cgi -d .
Автоматическое обновление динамического контента
Теперь давайте разберемся с еще одним очень важным свойством динамического сайта — автоматическим обновлением содержимого. Есть несколько механизмов для его реализации:
- Server Side Includes (SSI)
- Server-sent Events (SSE)
- WebSockets
- И так далее
Server Side Includes (SSI).
Server Side Includes (SSI). Это несложный язык для динамического создания веб-страниц. Обычно файлы использующие SSI имеют формат .shtml.
Сам SSI имеет даже директивы управления, if else и так далее. Но в большинстве примеров для микроконтроллеров, которые мы находили, он используется следующим образом. В .shtml страницу вставляется директива, которая периодически перегружает всю страницу. Это может быть, например
<meta http-equiv="refresh" content="1">
Или
<BODY onLoad="window.setTimeout("location.href='runtime.shtml'",2000)">
И тем или иным образом происходит генерация контента, например, с помощью задания специального обработчика.
Преимуществом этого метода является его простота и минимальные требования по ресурсам. Но с другой стороны, вот пример как это выглядит.
Обновление страницы (см. вкладку) сильно заметно. И перезагружать всю страницу, выглядит как чрезмерно избыточное действие.
Приведен стандартный пример из FreeRTOS — https://www.freertos.org/FreeRTOS-For-STM32-Connectivity-Line-With-WEB-Server-Example.html
Server-sent Events
Server-sent Events (SSE) это механизм, который позволяет установить полудуплексное (одностороннее) соединение между клиентом и сервером. Клиент в этом случае открывает соединение, и сервер использует его для передачи данных клиенту. При этом, в отличие от классических CGI скриптов, цель которых сформировать и отправить ответ клиенту, после чего завершиться, SSE предлагает “непрерывный” режим. То есть сервер может отправлять сколько угодно данных до тех пор пока либо не завершится самостоятельно, либо клиент не закроет соединение.
Есть несколько небольших отличий от обычных CGI скриптов. Во-первых, http заголовок будет немного другой:
"Content-Type: text/event-stream\r\n"
"Cache-Control: no-cache\r\n"
"Connection: keep-alive\r\n"
Connection, как видно, не close, а keep-alive, то есть продолжающееся соединение. Чтобы браузер не кешировал данные нужно указать Cache-Control no-cache. Ну и наконец, нужно указать что используется специальный тип данных Content-Type text/event-stream.
Этот тип данных представляет из себя специальный формат для SSE:
: this is a test stream
data: some text
data: another message
data: with two lines
В нашем случае данные нужно упаковать в следующую строку
data: { “time”: “<real date>”}
Наш CGI скрипт будет выглядеть
#!/bin/bash
echo -ne "HTTP/1.1 200 OK\r\n"
echo -ne "Content-Type: text/event-stream\r\n"
echo -ne "Cache-Control: no-cache\r\n"
echo -ne "Connection: keep-alive\r\n"
echo -ne "\r\n"
while true; do
tm=`LC_ALL=C date +%c`
echo -ne "data: {"time" : "$tm"}\n\n" 2>/dev/null || exit 0
sleep 1
done
Вывод если запустить скрипт
$ ./cgi-bin/gettime
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
data: {"time" : "Fri Feb 5 21:48:11 2021"}
data: {"time" : "Fri Feb 5 21:48:12 2021"}
data: {"time" : "Fri Feb 5 21:48:13 2021"}
И так далее раз в секунду
Тоже самое на С
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[]) {
char buf[128];
char *pbuf;
struct timeval tv;
time_t time;
printf(
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/event-stream\r\n"
"Cache-Control: no-cache\r\n"
"Connection: keep-alive\r\n"
"\r\n"
);
while (1) {
pbuf = buf;
pbuf += sprintf(pbuf, "data: {"time" : "");
gettimeofday(&tv, NULL);
time = tv.tv_sec;
ctime_r(&time, pbuf);
strcat(pbuf, ""}\n\n");
if (0 > printf("%s", buf)) {
break;
}
sleep(1);
}
return 0;
}
И наконец, нужно еще сообщить angular, что у нас SSE, то есть модифицировать код для нашего контроллера
app.controller("SystemCtrl", ['$scope', '$http', function($scope, $http) {
$scope.time = null;
var eventCallbackTime = function (msg) {
$scope.$apply(function () {
$scope.time = JSON.parse(msg.data).time
});
}
var source_time = new EventSource('/cgi-bin/gettime');
source_time.addEventListener('message', eventCallbackTime);
$scope.$on('$destroy', function () {
source_time.close();
});
$scope.update = function() {
};
$scope.update();
}]);
Запускаем сайт, видим следующее:
Заметно, что в отличие от использования SSI, страница не перегружается, и данные плавно и приятно для глаза обновляются.
Демо
Конечно приведенные примеры не реальные поскольку очень простые. Их цель показать разницу между используемыми на микроконтроллерах и в остальных системах подходов.
Мы сделали небольшую демонстрацию с реальными задачами. Управлением светодиодами, получением данных в реальном времени с датчика угловой скорости (гироскопа) и вкладкой с системной информацией.
Разработка сайта велась на хосте. Нужно было только сделать маленькие заглушки для эмуляции светодиодов и данных с датчика. Данные с датчика это просто случайные значения получаемые через стандартный RANDOM
#!/bin/bash
echo -ne "HTTP/1.1 200 OK\r\n"
echo -ne "Content-Type: text/event-stream\r\n"
echo -ne "Cache-Control: no-cache\r\n"
echo -ne "Connection: keep-alive\r\n"
echo -ne "\r\n"
while true; do
x=$((1 + $RANDOM % 15000))
y=$((1 + $RANDOM % 15000))
z=$((1 + $RANDOM % 15000))
echo -ne "data: {"rate" : "x:$x y:$y z:$z"}\n\n" 2>/dev/null || exit 0
sleep 1
done
Состояние светодиодов просто храним в файле.
#!/bin/python3
import cgi
import sys
print("HTTP/1.1 200 OK")
print("Content-Type: text/plain")
print("Connection: close")
print()
form = cgi.FieldStorage()
cmd = form['cmd'].value
if cmd == 'serialize_states':
with open('cgi-bin/leds.txt', 'r') as f:
print('[' + f.read() + ']')
elif cmd == 'clr' or cmd == 'set':
led_nr = int(form['led'].value)
with open('cgi-bin/leds.txt', 'r+') as f:
leds = f.read().split(',')
leds[led_nr] = str(1 if cmd == 'set' else 0)
f.seek(0)
f.write(','.join(leds))
То же самое тривиально реализовано и в C варианте. При желании можно посмотреть код в репозитории папка (project/website).
На микроконтроллере конечно используются реализации взаимодействующие с реальной периферией. Но так как это просто команды и драйвера, они были отлажены отдельно. Поэтому сам перенос сайта на микроконтроллер, не занял времени.
Скриншот запущенный на хосте выглядит так
На коротком видео можно увидеть работу на реальном микроконтроллере. Отмечу, что происходит не только общение по http, но и например установка даты с помощью ntp из командной строки в Embox, и конечно обращение с периферией.
Извините, данный ресурс не поддреживается. :(
Самостоятельно все приведенное в статье можно воспроизвести по инструкции на нашем вики
Заключение
В статье мы показали, что возможно разрабатывать красивые интерактивные сайты и запускать их на микроконтроллерах. Причем делать это легко и быстро используя все средства разработки под хост и затем запускать из на микроконтроллерах. Естественно, разработкой сайта может заниматься профессиональный веб-дизайнер, в то время как embedded разработчик будет реализовывать логику работы устройства. Что очень удобно и сильно экономит время выхода на рынок.
Естественно за это придется расплачиваться. Да SSE потребует немного больше ресурсов чем SSI. Но мы с помощью Embox легко вместились в STM32F4 причем без оптимизации и использовали всего 128 кб ОЗУ. Меньше просто проверять не стали. Так что накладные расходы не такие уж большие. А удобство разработки и качество самого сайта сильно выше. И при этом конечно не стоит забывать, что современные микроконтроллеры заметно подросли и продолжают это делать. Ведь от устройств требуют быть все более умными.
===========
Источник:
habr.com
===========
Похожие новости:
- [Программирование, DevOps, Kubernetes] Круглый стол «Нужно ли разработчику знать Kubernetes» 11 февраля
- [Разработка веб-сайтов, PHP, Программирование] Tagged Unions в PHP (примерно как в Rust)
- [Программирование, Java] Вы часто используете null? А он у нас в спецификации
- [Разработка веб-сайтов, CSS] Минимальный размер содержимого в CSS Grid (перевод)
- [Информационная безопасность, Сетевые технологии] Исследование вредоносного трафика
- [Разработка веб-сайтов, Управление продуктом, Логические игры] Пока в мире гремел сериал «Ход королевы», мы пилили сервис, чтобы дети учились шахматам на удобной платформе
- [JavaScript, Программирование, Учебный процесс в IT] Решение забавной задачки на JavaScript (перевод)
- [Системное администрирование, Сетевые технологии, Облачные сервисы, Сетевое оборудование] Настройка WPA2 Enterprise c RADIUS
- [Разработка веб-сайтов, JavaScript, Программирование, .NET] Рабочий прототип секретного мессенджера
- [Программирование, Java] Шпаргалка по Spring Boot WebClient (перевод)
Теги для поиска: #_razrabotka_vebsajtov (Разработка веб-сайтов), #_programmirovanie (Программирование), #_setevye_tehnologii (Сетевые технологии), #_programmirovanie_mikrokontrollerov (Программирование микроконтроллеров), #_embox, #_mcu, #_stm32, #_website, #_blog_kompanii_embox (
Блог компании Embox
), #_razrabotka_vebsajtov (
Разработка веб-сайтов
), #_programmirovanie (
Программирование
), #_setevye_tehnologii (
Сетевые технологии
), #_programmirovanie_mikrokontrollerov (
Программирование микроконтроллеров
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 05:56
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
С приходом в нашу жизнь различного рода умных розеток, лампочек и других подобных устройств, необходимость наличия веб-сайтов на микроконтроллерах стала неоспоримой. А благодаря проекту lwIP (и его младшему брату uIP) подобным функционалом никого не удивишь. Но поскольку lwIP направлен на минимизацию ресурсов, то с точки зрения дизайна, функционала, а также удобства использования и разработки, подобные сайты сильно отстают от тех, к которым мы привыкли. Даже для встроенных систем, сравнить, например, с сайтом для администрирования на самых дешевых роутерах. В данной статье мы попробуем разработать сайт на Линуксе для какого-нибудь умного устройства и запустить его на микроконтроллере. Для запуска на микроконтроллере будем использовать Embox. В состав этой RTOS входит HTTP сервер с поддержкой CGI. В качестве HTTP сервера на Linux будем использовать встроенный в python HTTP сервер. python3 -m http.server -d <site folder>
Статический сайт Начнем с простого статического сайта, состоящего из одной или нескольких страниц. Тут все просто, давайте создадим папку и в ней index.html. Этот файл будет скачиваться по умолчанию, если в браузере задан только адрес сайта. $ ls website/
em_big.png index.html Сайт еще будет содержать логотип Embox, файл “em_big.png”, который мы встроим в html. Запустим http сервер python3 -m http.server -d website/
Зайдем в браузере на localhost:8000 Теперь добавим наш статический сайт в файловую систему Embox. Это можно сделать скопировав нашу папку в папку rootfs/ темплейта (текущий темплейт в папке conf/rootfs). Или создать модуль указав в нем файлы для rootfs. $ ls website/
em_big.png index.html Mybuild Содержимое Mybuild. package embox.demo
module website { @InitFS source "index.html", "em_big.png", } Для простоты мы положим наш сайт прямо в корневую папку (аннотация @InitFs без параметров). Нам также нужно включить наш сайт в конфигурационном файле mods.conf и туда же добавить сам httd сервер include embox.cmd.net.httpd
include embox.demo.website Кроме того, давайте запустим сервер с нашим сайтом во время старта системы. Для этого добавим строчку в файл conf/system_start.inc "service httpd /",
Естественно все эти манипуляции нужно делать с конфигом для платы. После этого собираем и запускаем. Заходим в браузере на адрес вашей платы. В моем случае это 192.168.2.128 И имеем такую же картинку как и для локального сайта Мы не являемся специалистами по веб-разработке, но слышали, что для создания красивых веб сайтов используются различные фреймворки. Например, часто используется AngularJS. Поэтому дальнейшие примеры мы будем приводить с его использованием. Но при этом мы не будем вдаваться в детали и заранее извиняемся если где-то сильно налажали с веб дизайном. Какой-бы статический контент не положили в папку с сайтом, например, js или css файлы, мы можем его использовать без каких-либо дополнительных усилий. Добавим в наш сайт app.js (сайт на angular) и в нем пару вкладок. Страницы для этих вкладок положим в папку partials, изображения в папку images/, а css файлы в css/. $ ls website/
app.js css images index.html Mybuild partials Запустим наш сайт. Согласитесь, сайт выглядит гораздо привычнее и приятнее. Причем все это сделано на стороне браузера. Как мы и сказали, весь контекст все еще статический. И мы его можем разрабатывать на хосте как обычный сайт. Естественно, при этом можно использовать все средства разработки обычных веб-девелоперов. Так, открыв консоль в браузере, мы обнаружили сообщение об ошибке, о том что не хватает favicon.ico: Выяснили, что это иконка которая отображается во вкладке браузера. Можно конечно положить файл с этим именем, но порой не хочется тратить на это место. Напоминаю, что хотим запускаться в том числе и на микроконтроллерах, где памяти мало. Поиск в интернете сразу выдал, что можно обойтись и без файла, нужно всего лишь добавить строку в head секцию html. Хотя ошибка не мешала, но сделать сайт чуть лучше всегда приятно. И главное, что мы убедились, что обычные средства разработчика вполне применимы при предлагаемом подходе. Динамический контент CGI Перейдем к динамическому контенту. Common Gateway Interface (CGI) интерфейс взаимодействия web-сервера с утилитами командной строки, позволяющий создавать динамический контент. Иными словами, CGI позволяет использовать вывод утилит для генерации динамического контента. Давайте взглянем на какой-нибудь CGI скрипт #!/bin/bash
echo -ne "HTTP/1.1 200 OK\r\n" echo -ne "Content-Type: application/json\r\n" echo -ne "Connection: Connection: close\r\n" echo -ne "\r\n" tm=`LC_ALL=C date +%c` echo -ne ""$tm"\n\n" Вначале в стандартный output печатается http заголовок, а затем печатаются данные самой страницы. output может быть перенаправлен куда угодно. Можно просто запустить этот скрипт из консоли. Увидим следующее: ./cgi-bin/gettime
HTTP/1.1 200 OK Content-Type: application/json Connection: Connection: close "Fri Feb 5 20:58:19 2021" А если вместо стандартного output это будет socket то браузер получит эти данные. CGI часто реализуют с помощью скриптов, даже говорят cgi scripts. Но это не обязательно, просто на скриптовых языках подобные вещи делать быстрее и удобнее. Утилита предоставляющая CGI может быть реализована на любом языке. И так как мы ориентируемся на микроконтроллеры, следовательно, стараемся заботиться об экономии ресурсов. Давайте то же самое реализуем на С. #include <stdio.h>
#include <unistd.h> #include <string.h> int main(int argc, char *argv[]) { char buf[128]; char *pbuf; struct timeval tv; time_t time; printf( "HTTP/1.1 200 OK\r\n" "Content-Type: application/json\r\n" "Connection: Connection: close\r\n" "\r\n" ); pbuf = buf; pbuf += sprintf(pbuf, """); gettimeofday(&tv, NULL); time = tv.tv_sec; ctime_r(&time, pbuf); strcat(pbuf, ""\n\n"); printf("%s", buf); return 0; } Если скомпилировать данный код и запустить, мы увидим точно такой же вывод как и в случае со скриптом. В наш app.js добавим обработчик для вызова CGI скрипта для одной из нашей вкладки app.controller("SystemCtrl", ['$scope', '$http', function($scope, $http) {
$scope.time = null; $scope.update = function() { $http.get('cgi-bin/gettime').then(function (r) { $scope.time = r.data; }); }; $scope.update(); }]); Небольшой нюанс по запуску на Linux с помощью встроенного сервера python. В нашу строку запуска нужно добавить аргумент --cgi для поддержки CGI: python3 -m http.server --cgi -d .
Автоматическое обновление динамического контента Теперь давайте разберемся с еще одним очень важным свойством динамического сайта — автоматическим обновлением содержимого. Есть несколько механизмов для его реализации:
Server Side Includes (SSI). Server Side Includes (SSI). Это несложный язык для динамического создания веб-страниц. Обычно файлы использующие SSI имеют формат .shtml. Сам SSI имеет даже директивы управления, if else и так далее. Но в большинстве примеров для микроконтроллеров, которые мы находили, он используется следующим образом. В .shtml страницу вставляется директива, которая периодически перегружает всю страницу. Это может быть, например <meta http-equiv="refresh" content="1">
Или <BODY onLoad="window.setTimeout("location.href='runtime.shtml'",2000)">
И тем или иным образом происходит генерация контента, например, с помощью задания специального обработчика. Преимуществом этого метода является его простота и минимальные требования по ресурсам. Но с другой стороны, вот пример как это выглядит. Обновление страницы (см. вкладку) сильно заметно. И перезагружать всю страницу, выглядит как чрезмерно избыточное действие. Приведен стандартный пример из FreeRTOS — https://www.freertos.org/FreeRTOS-For-STM32-Connectivity-Line-With-WEB-Server-Example.html Server-sent Events Server-sent Events (SSE) это механизм, который позволяет установить полудуплексное (одностороннее) соединение между клиентом и сервером. Клиент в этом случае открывает соединение, и сервер использует его для передачи данных клиенту. При этом, в отличие от классических CGI скриптов, цель которых сформировать и отправить ответ клиенту, после чего завершиться, SSE предлагает “непрерывный” режим. То есть сервер может отправлять сколько угодно данных до тех пор пока либо не завершится самостоятельно, либо клиент не закроет соединение. Есть несколько небольших отличий от обычных CGI скриптов. Во-первых, http заголовок будет немного другой: "Content-Type: text/event-stream\r\n"
"Cache-Control: no-cache\r\n" "Connection: keep-alive\r\n" Connection, как видно, не close, а keep-alive, то есть продолжающееся соединение. Чтобы браузер не кешировал данные нужно указать Cache-Control no-cache. Ну и наконец, нужно указать что используется специальный тип данных Content-Type text/event-stream. Этот тип данных представляет из себя специальный формат для SSE: : this is a test stream
data: some text data: another message data: with two lines В нашем случае данные нужно упаковать в следующую строку data: { “time”: “<real date>”}
Наш CGI скрипт будет выглядеть #!/bin/bash
echo -ne "HTTP/1.1 200 OK\r\n" echo -ne "Content-Type: text/event-stream\r\n" echo -ne "Cache-Control: no-cache\r\n" echo -ne "Connection: keep-alive\r\n" echo -ne "\r\n" while true; do tm=`LC_ALL=C date +%c` echo -ne "data: {"time" : "$tm"}\n\n" 2>/dev/null || exit 0 sleep 1 done Вывод если запустить скрипт $ ./cgi-bin/gettime
HTTP/1.1 200 OK Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive data: {"time" : "Fri Feb 5 21:48:11 2021"} data: {"time" : "Fri Feb 5 21:48:12 2021"} data: {"time" : "Fri Feb 5 21:48:13 2021"} И так далее раз в секунду Тоже самое на С #include <stdio.h>
#include <unistd.h> #include <string.h> int main(int argc, char *argv[]) { char buf[128]; char *pbuf; struct timeval tv; time_t time; printf( "HTTP/1.1 200 OK\r\n" "Content-Type: text/event-stream\r\n" "Cache-Control: no-cache\r\n" "Connection: keep-alive\r\n" "\r\n" ); while (1) { pbuf = buf; pbuf += sprintf(pbuf, "data: {"time" : ""); gettimeofday(&tv, NULL); time = tv.tv_sec; ctime_r(&time, pbuf); strcat(pbuf, ""}\n\n"); if (0 > printf("%s", buf)) { break; } sleep(1); } return 0; } И наконец, нужно еще сообщить angular, что у нас SSE, то есть модифицировать код для нашего контроллера app.controller("SystemCtrl", ['$scope', '$http', function($scope, $http) {
$scope.time = null; var eventCallbackTime = function (msg) { $scope.$apply(function () { $scope.time = JSON.parse(msg.data).time }); } var source_time = new EventSource('/cgi-bin/gettime'); source_time.addEventListener('message', eventCallbackTime); $scope.$on('$destroy', function () { source_time.close(); }); $scope.update = function() { }; $scope.update(); }]); Запускаем сайт, видим следующее: Заметно, что в отличие от использования SSI, страница не перегружается, и данные плавно и приятно для глаза обновляются. Демо Конечно приведенные примеры не реальные поскольку очень простые. Их цель показать разницу между используемыми на микроконтроллерах и в остальных системах подходов. Мы сделали небольшую демонстрацию с реальными задачами. Управлением светодиодами, получением данных в реальном времени с датчика угловой скорости (гироскопа) и вкладкой с системной информацией. Разработка сайта велась на хосте. Нужно было только сделать маленькие заглушки для эмуляции светодиодов и данных с датчика. Данные с датчика это просто случайные значения получаемые через стандартный RANDOM #!/bin/bash
echo -ne "HTTP/1.1 200 OK\r\n" echo -ne "Content-Type: text/event-stream\r\n" echo -ne "Cache-Control: no-cache\r\n" echo -ne "Connection: keep-alive\r\n" echo -ne "\r\n" while true; do x=$((1 + $RANDOM % 15000)) y=$((1 + $RANDOM % 15000)) z=$((1 + $RANDOM % 15000)) echo -ne "data: {"rate" : "x:$x y:$y z:$z"}\n\n" 2>/dev/null || exit 0 sleep 1 done Состояние светодиодов просто храним в файле. #!/bin/python3
import cgi import sys print("HTTP/1.1 200 OK") print("Content-Type: text/plain") print("Connection: close") print() form = cgi.FieldStorage() cmd = form['cmd'].value if cmd == 'serialize_states': with open('cgi-bin/leds.txt', 'r') as f: print('[' + f.read() + ']') elif cmd == 'clr' or cmd == 'set': led_nr = int(form['led'].value) with open('cgi-bin/leds.txt', 'r+') as f: leds = f.read().split(',') leds[led_nr] = str(1 if cmd == 'set' else 0) f.seek(0) f.write(','.join(leds)) То же самое тривиально реализовано и в C варианте. При желании можно посмотреть код в репозитории папка (project/website). На микроконтроллере конечно используются реализации взаимодействующие с реальной периферией. Но так как это просто команды и драйвера, они были отлажены отдельно. Поэтому сам перенос сайта на микроконтроллер, не занял времени. Скриншот запущенный на хосте выглядит так На коротком видео можно увидеть работу на реальном микроконтроллере. Отмечу, что происходит не только общение по http, но и например установка даты с помощью ntp из командной строки в Embox, и конечно обращение с периферией. Извините, данный ресурс не поддреживается. :( Самостоятельно все приведенное в статье можно воспроизвести по инструкции на нашем вики Заключение В статье мы показали, что возможно разрабатывать красивые интерактивные сайты и запускать их на микроконтроллерах. Причем делать это легко и быстро используя все средства разработки под хост и затем запускать из на микроконтроллерах. Естественно, разработкой сайта может заниматься профессиональный веб-дизайнер, в то время как embedded разработчик будет реализовывать логику работы устройства. Что очень удобно и сильно экономит время выхода на рынок. Естественно за это придется расплачиваться. Да SSE потребует немного больше ресурсов чем SSI. Но мы с помощью Embox легко вместились в STM32F4 причем без оптимизации и использовали всего 128 кб ОЗУ. Меньше просто проверять не стали. Так что накладные расходы не такие уж большие. А удобство разработки и качество самого сайта сильно выше. И при этом конечно не стоит забывать, что современные микроконтроллеры заметно подросли и продолжают это делать. Ведь от устройств требуют быть все более умными. =========== Источник: habr.com =========== Похожие новости:
Блог компании Embox ), #_razrabotka_vebsajtov ( Разработка веб-сайтов ), #_programmirovanie ( Программирование ), #_setevye_tehnologii ( Сетевые технологии ), #_programmirovanie_mikrokontrollerov ( Программирование микроконтроллеров ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 05:56
Часовой пояс: UTC + 5