Dengan munculnya berbagai jenis soket pintar, bola lampu, dan perangkat serupa lainnya ke dalam kehidupan kita, kebutuhan akan situs web pada mikrokontroler menjadi tidak dapat disangkal. Dan berkat proyek lwIP (dan adik laki-lakinya, uIP), Anda tidak akan mengejutkan siapa pun dengan fungsi seperti itu. Tetapi karena lwIP ditujukan untuk meminimalkan sumber daya, dalam hal desain, fungsionalitas, serta kegunaan dan pengembangan, situs semacam itu tertinggal jauh dari yang biasa kita gunakan. Bahkan untuk sistem tertanam, bandingkan, misalnya, dengan situs administrasi pada router termurah. Pada artikel ini kami akan mencoba mengembangkan situs di Linux untuk beberapa perangkat pintar dan menjalankannya di mikrokontroler.
Untuk berjalan di mikrokontroler, kita akan menggunakan Embox . RTOS ini mencakup server HTTP berkemampuan CGI. Kami akan menggunakan server HTTP yang dibangun ke dalam python sebagai server HTTP di Linux.
python3 -m http.server -d <site folder>
Situs statis
Mari kita mulai dengan situs statis sederhana yang terdiri dari satu atau lebih halaman.
Semuanya sederhana di sini, mari buat folder dan index.html di dalamnya. File ini akan diunduh secara default jika hanya alamat situs yang ditentukan di browser.
$ ls website/ em_big.png index.html
Situs ini juga akan berisi logo Embox, file "em_big.png", yang akan kita sematkan di html.
Mari mulai server http:
python3 -m http.server -d website/
Masuk ke localhost: 8000 di browser
Sekarang tambahkan situs statis kita ke sistem file Embox. Ini dapat dilakukan dengan menyalin folder kita ke folder rootfs / template (template saat ini ada di folder conf / rootfs). Atau buat modul yang menentukan file untuk rootf di dalamnya.
$ ls website/ em_big.png index.html Mybuild
Konten Mybuild.
package embox.demo module website { @InitFS source "index.html", "em_big.png", }
Demi kesederhanaan, kami akan meletakkan situs kami langsung di folder root (penjelasan @InitFs tanpa parameter).
Kami juga perlu memasukkan situs kami ke dalam file konfigurasi mods.conf dan menambahkan server httd itu sendiri di sana:
include embox.cmd.net.httpd include embox.demo.website
Juga, mari kita mulai server dengan situs web kita selama startup sistem. Untuk melakukan ini, tambahkan baris ke file conf / system_start.inc:
"service httpd /",
Secara alami, semua manipulasi ini perlu dilakukan dengan konfigurasi untuk papan. Setelah itu, kita kumpulkan dan lari. Kami masuk ke browser ke alamat papan Anda. Dalam kasus saya, 192.168.2.128
Dan kami memiliki gambaran yang sama dengan situs lokal
Kami bukan spesialis dalam pengembangan web, tetapi telah mendengar bahwa berbagai kerangka digunakan untuk membuat situs web yang indah. Misalnya, AngularJS sering digunakan . Oleh karena itu, kami akan memberikan contoh lebih lanjut tentang penggunaannya. Namun di saat yang sama, kami tidak akan membahas secara detail dan mohon maaf terlebih dahulu jika di suatu tempat kami telah sangat menyesuaikan dengan desain web.
Apapun konten statis yang kita taruh di folder situs, misalnya file js atau css, kita bisa menggunakannya tanpa usaha tambahan.
Mari tambahkan app.js (situs sudut) ke situs kita dan di dalamnya beberapa tab. Kami akan meletakkan halaman untuk tab ini di folder parsial, gambar di folder gambar /, dan file css di css /.
$ ls website/ app.js css images index.html Mybuild partials
Mari luncurkan situs web kami.
Setuju, situs tersebut terlihat jauh lebih akrab dan menyenangkan. Dan semua ini dilakukan di sisi browser. Seperti yang kami katakan, seluruh konteksnya masih statis. Dan kami dapat mengembangkannya di host seperti situs web biasa.
Secara alami, Anda dapat menggunakan semua alat pengembangan dari pengembang web umum. Jadi, membuka konsol di browser, kami menemukan pesan kesalahan bahwa favicon.ico tidak ada: Kami
menemukan bahwa ini adalah ikon yang ditampilkan di tab browser. Anda dapat, tentu saja, meletakkan file dengan nama ini, tetapi terkadang Anda tidak ingin menghabiskan uang untuk tempat ini. Izinkan saya mengingatkan Anda bahwa kami ingin menjalankan juga di mikrokontroler yang memiliki sedikit memori.
Pencarian di Internet segera menunjukkan bahwa Anda dapat melakukannya tanpa file, Anda hanya perlu menambahkan baris ke bagian kepala html. Meskipun kesalahan tidak mengganggu, selalu menyenangkan untuk membuat situs sedikit lebih baik. Dan yang paling penting, kami memastikan bahwa alat pengembang biasa cukup dapat diterapkan dengan pendekatan yang diusulkan.
Konten dinamis
CGI
Mari beralih ke konten dinamis. Common Gateway Interface (CGI) adalah antarmuka untuk interaksi server web dengan utilitas baris perintah, yang memungkinkan pembuatan konten dinamis. Dengan kata lain, CGI memungkinkan Anda menggunakan keluaran utilitas untuk menghasilkan konten dinamis.
Mari kita lihat beberapa skrip 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"
Pertama, kepala http dicetak ke keluaran standar, kemudian data halaman itu sendiri dicetak. keluaran dapat diarahkan ke mana saja. Anda cukup menjalankan skrip ini dari konsol. Kami akan melihat yang berikut ini:
./cgi-bin/gettime
HTTP/1.1 200 OK
Content-Type: application/json
Connection: Connection: close
"Fri Feb 5 20:58:19 2021"
Dan jika bukan keluaran standarnya adalah soket, maka browser akan menerima data ini.
CGI sering diimplementasikan dengan skrip, bahkan skrip cgi dikatakan. Tetapi ini tidak perlu, hanya saja dalam bahasa scripting hal-hal seperti itu lebih cepat dan lebih nyaman. Sebuah utilitas yang menyediakan CGI dapat diimplementasikan dalam bahasa apapun. Dan karena kami fokus pada mikrokontroler, oleh karena itu, kami mencoba untuk berhati-hati dalam menghemat sumber daya. Mari lakukan hal yang sama di C.
#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;
}
Jika kita mengkompilasi kode ini dan menjalankannya, kita akan melihat keluaran yang persis sama seperti pada kasus skrip.
Di app.js kita, mari tambahkan penangan untuk memanggil skrip CGI untuk salah satu tab kita:
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();
}]);
Nuansa kecil untuk berjalan di Linux menggunakan server python built-in. Kita perlu menambahkan argumen --cgi ke baris peluncuran kita untuk mendukung CGI:
python3 -m http.server --cgi -d .
Pembaruan otomatis konten dinamis
Sekarang mari kita lihat properti lain yang sangat penting dari situs dinamis - pembaruan konten otomatis. Ada beberapa mekanisme pelaksanaannya:
- Server Side Includes (SSI)
- Acara yang Dikirim Server (SSE)
- WebSockets
- Dll
Server Side Includes (SSI)
Server Side Includes (SSI) . Ini adalah bahasa yang tidak rumit untuk membuat halaman web secara dinamis. Biasanya file yang menggunakan SSI dalam format .shtml.
SSI sendiri bahkan punya arahan kontrol, kalau lagi, dan seterusnya. Tetapi di sebagian besar contoh mikrokontroler yang kami temukan, digunakan sebagai berikut. Sebuah direktif dimasukkan ke dalam halaman .shtml yang memuat ulang seluruh halaman secara berkala. Ini bisa jadi, misalnya:
<meta http-equiv="refresh" content="1">
Atau:
<BODY onLoad="window.setTimeout("location.href='runtime.shtml'",2000)">
Dan dengan satu atau lain cara, konten dihasilkan, misalnya, dengan menyetel penangan khusus.
Keuntungan dari metode ini adalah kesederhanaannya dan kebutuhan sumber daya yang minimal. Namun di sisi lain, berikut adalah contoh tampilannya.
Refresh halaman (lihat tab) sangat terlihat. Dan memuat ulang seluruh halaman tampak seperti tindakan yang terlalu berlebihan.
Contoh standar dari FreeRTOS disediakan - https://www.freertos.org/FreeRTOS-For-STM32-Connectivity-Line-With-WEB-Server-Example.html
Acara yang dikirim server
Server-sent Events (SSE) adalah mekanisme yang memungkinkan koneksi setengah dupleks (satu arah) antara klien dan server. Klien dalam hal ini membuka koneksi dan server menggunakannya untuk mentransfer data ke klien. Pada saat yang sama, tidak seperti skrip CGI klasik, yang tujuannya adalah untuk menghasilkan dan mengirim respons ke klien, dan kemudian menyelesaikannya, SSE menawarkan mode "berkelanjutan". Artinya, server dapat mengirim data sebanyak yang diperlukan hingga selesai sendiri, atau klien menutup koneksi.
Ada beberapa perbedaan kecil dari skrip CGI biasa. Pertama, header http akan sedikit berbeda:
"Content-Type: text/event-stream\r\n"
"Cache-Control: no-cache\r\n"
"Connection: keep-alive\r\n"
Koneksi, seperti yang Anda lihat, tidak dekat, tetapi tetap hidup, yaitu koneksi yang sedang berlangsung. Untuk mencegah browser menyimpan data dalam cache, Anda perlu menentukan Cache-Control no-cache. Terakhir, Anda perlu menentukan bahwa jenis data khusus Jenis konten teks / aliran acara digunakan.
Tipe data ini adalah format khusus untuk SSE :
: this is a test stream data: some text data: another message data: with two lines
Dalam kasus kami, data perlu dikemas ke dalam baris berikut:
data: { βtimeβ: β<real date>β}
Skrip CGI kita akan terlihat seperti:
#!/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
Output jika Anda menjalankan skrip:
$ ./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"}
Dan seterusnya, sekali dalam satu detik.
Hal yang sama di C:
#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;
}
Dan terakhir, kita juga perlu memberi tahu angular bahwa kita memiliki SSE, yaitu memodifikasi kode untuk controller kita:
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();
}]);
Kami meluncurkan situs, kami melihat yang berikut:
Terlihat bahwa, tidak seperti menggunakan SSI, halaman tidak membebani secara berlebihan, dan data diperbarui dengan lancar dan menyenangkan bagi mata.
Demo
Tentu saja contoh yang diberikan tidak nyata karena sangat sederhana. Tujuan mereka adalah untuk menunjukkan perbedaan antara pendekatan yang digunakan pada mikrokontroler dan sistem lain.
Kami membuat demo kecil dengan tugas nyata. Mengontrol LED, menerima data waktu nyata dari sensor kecepatan sudut (giroskop) dan tab dengan informasi sistem.
Situs ini dikembangkan di host. Anda hanya perlu membuat colokan kecil untuk meniru LED dan data dari sensor. Data sensor hanyalah nilai acak yang diterima melalui ACAK standar
#!/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
Kami hanya menyimpan status LED dalam sebuah file.
#!/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))
Hal yang sama diimplementasikan dengan mudah pada varian C. Jika mau, Anda dapat melihat kode di folder repositori (proyek / situs web).
Pada mikrokontroler, tentunya digunakan implementasi yang berinteraksi dengan periferal nyata. Tetapi karena ini hanyalah perintah dan driver, mereka di-debug secara terpisah. Oleh karena itu, transfer situs ke mikrokontroler tidak memakan waktu.
Tangkapan layar yang berjalan pada host terlihat seperti ini.
Dalam video singkat Anda dapat melihat pekerjaan pada mikrokontroler yang sebenarnya. Perhatikan bahwa tidak hanya ada komunikasi melalui http, tetapi juga, misalnya, mengatur tanggal menggunakan ntp dari baris perintah di Embox, dan tentu saja menangani periferal.
Secara mandiri, semua yang diberikan dalam artikel dapat direproduksi sesuai dengan instruksi di wiki kami
Kesimpulan
Dalam artikel tersebut, kami menunjukkan bahwa dimungkinkan untuk mengembangkan situs interaktif yang indah dan menjalankannya di mikrokontroler. Selain itu, ini dapat dilakukan dengan mudah dan cepat menggunakan semua alat pengembangan untuk host dan kemudian dijalankan dari mikrokontroler. Secara alami, pengembangan situs dapat dilakukan oleh perancang web profesional, sedangkan pengembang yang tertanam akan menerapkan logika perangkat. Yang sangat nyaman dan menghemat waktu ke pasar.
Tentu, Anda harus membayar untuk ini. Ya, SSE akan membutuhkan sumber daya yang sedikit lebih banyak daripada SSI. Tetapi dengan bantuan Embox, kami dengan mudah masuk ke STM32F4 tanpa pengoptimalan dan hanya menggunakan RAM 128 KB. Mereka tidak memeriksa apa pun yang kurang. Jadi biaya overhead tidak terlalu besar. Dan kenyamanan pengembangan dan kualitas situs itu sendiri jauh lebih tinggi. Dan pada saat yang sama, tentu saja, jangan lupa bahwa mikrokontroler modern telah berkembang pesat dan terus melakukannya. Lagi pula, perangkat dituntut untuk semakin cerdas.