Dorim să realizăm firmware-ul pentru un dispozitiv IoT de monitorizare GPS (emulat printr-un script Python) folosind un Raspberry PI (de asemenea, emulat folosind qemu).
Pe scurt, va trebui să realizați o imagine incorporabilă cu Linux ce va implementa o aplicație de achiziție a datelor de la un senzor GPS conectat printr-o interfață UART (protocolul textual NMEA pentru GPS, detalii mai jos) și expune pe rețea un server HTTP cu o pagină web de vizualizare a datelor capturate.
Exemplu de frontend web (aspectul nu contează, dar puteți să faceți ceva drăguț dacă aveți timp/chef):
Pas inițial: realizarea unei imagini de bază de Linux (kernel + rootfs) ce va fi folosită ca punct de plecare / suport pentru programele & serviciile cerute de restul cerințelor:
rootfs
(atât printre cele studiate la laborator, cât și celelalte populare în industrie):500MB ~ 1GB
) și vor fi depunctate (-20p
);debootstrap
, însă se vor obține imagini mult mai mici (recomandat pentru avansați, puteți folosi scriptul alpine-chroot-install dat citiți-i codul înainte)!LOCALVERSION="-si-<prenume.nume>"
(altfel se depunctează! vedeți mai jos);AArch64
(i.e.: arm64
) și să poată fi rulat în qemu
folosind machine type raspi3b
(recomandat) sau raspi4b
; vedeți mai jos config-uri de kernel testate deja pentru compatibilitate + script de rulare recomandat;70MB
, creați disk SD de 128MB
).Sistemul trebuie să conțină următoarele configurații de bază (ne ajută pe noi, în special, să automatizăm partea de testare):
root
cu parola tema2
(obligatoriu: să ne putem autentifica în consola emulată);tema2
;net.ifnames=0
, astfel încât numele primei interfețe să fie eth0
pentru o configurație portabilă – parametru deja prezent în scriptul de rulare din schelet);root
+ parolă, aka setarea PermitRootLogin
!);tema2.local
(opțional, dar ne ajută la testare; setupul pe host se face mai dificil, însă pe mașina emulată, însă este suficient să fie compilat/instalat pachetul avahi-daemon
- sau echivalentul în distribuția aleasă - și testa cu ping tema2.local
).
Rezolvarea acestei cerințe este OBLIGATORIE pentru obținerea oricărui fel de punctaj (altfel nu avem ce testa ⇒ 0p
)!
Pentru rootfs-ul construite prin tehnică de package-based bootstrapping, puteți copia ulterior acest overlay folosind cp -ar
sau rsync -a
.
Pentru BuildRoot, citiți recomandările oficiale de customizare (folosiți OVERLAY, e cel mai ușor + elegant).
+ citiți enunțul până la capăt pentru a vedea cerințele finale!
qemu
! Deci evitați (vedeți mai jos, folosiți mainline-ul lui Torvalds)!
Recomandăm folosirea kernelului mainline
, descărcabil de pe https://kernel.org/ (sau Github, torvalds/linux). NU LUAȚI MASTER-ul sau alte branch-uri experimentale! Folosiți un branch/tag de versiune (e.g., v6.12
).
La configurarea kernelului, va trebui să setați parametrul LOCALVERSION
la valoarea -si-<prenume.nume>
(folosiți username-ul de pe Moodle în loc de placeholderl <prenume.nume>
, e.g. -si-florin.stoian
!). Vedeți aici variabilele implicate, TLDR: nu uitați să dezactivați LOCALVERSION_AUTO
pentru a putea set versiunea voastră custom!
Au fost testate versiunile v6.12
și v6.6
, compilate atât automat prin buildroot
(însă se configurează mai special, vedeți mai jos), cât și manual. Așadar, aveți două opțiuni de compilare:
Pentru o testare rapidă a sistemului rădăcină, puteți folosi imaginea vmlinuz-test
inclusă în scheletul de temă în scheletul de temă (atenție: nu a fost testată pe distribuții Debian cu systemd!).
Pur și simplu se descarcă codul sursă torvalds/linux de pe git (ori din GitHub release, arhivă .tar.gz mult mai mică) și să dă make
ca în laborator (nu uitați să modificați LOCALVERSION
!)!
ARCH=arm64
și configurația inițială a arhitecturii, defconfig
(pe mainline NU există bcm27*_defconfig
)!
Pentru a a nu avea probleme cu copierea/instalarea modulelor externe (e.g.: mmc
, să nu vadă rootfs-ul, sau să nu se încarce automat driverul de rețea usb-net
), recomandăm dezactivarea modulelor de kernel, adică MODULES=n
din menuconfig
– acest lucru va face integrarea tuturor driverelor în imaginea de kernel și va omite copierea lor pe sistemul rădăcină (în <rootfs>/lib/modules
).
Pentru cei care folosesc buildroot
, aveți opțiunea de a compila kernelul Linux (în menuconfig
, aveți BR2_LINUX_KERNEL
cu toate opțiunile de descărcare necesare).
Însă procesul de adaptare a configurației de kernel necesită pași + documentare suplimentară (still pretty much recommended!):
torvalds/linux
); se recomandă utilizarea unei reguli de descărcare a arhivei tar.gz
de pe GitHub (documentație aici cu ce să puneți la URL de descărcare) + exemplu la config-ul oficial Buildroot pentru raspberrypi;linux/linux.hash
și să adăugați hash-urile arhivei descărcate de pe GitHub asociate versiunii voastre, sau dezactiva de tot verificarea de hash prin opțiunea BR2_DOWNLOAD_FORCE_CHECK_HASHES=n
(însă este mai complicat și necesită modificarea variabilei BR_NO_CHECK_HASH_FOR
direct din Makefile, aceasta nu e expusă în Kconfig!!);systemd
, ori va trebui configurat EUDEV (recomandat), exemplu de config ce trebuie efectual (depinde de ce defconfig
ați ales dacă sunt prezente sau nu): # se poate alege și biblioteca ucLibC, însă am avut probleme cu python3-flask BR2_TOOLCHAIN_BUILDROOT_MUSL=y BR2_SHARED_STATIC_LIBS=y BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_EUDEV=y
MODULES=n
)!LOCALVERSION*
), aveți target-ul buildroot make linux-menuconfig
(atenție: nu uitați să faceți save / backup la config-ul de kernel după modificare, citiți în manual cum);
Deși e prezent în defconfig
(în caz că vreți să optimizați), nu uitați să includeți driver-ul pentru dispozitivul serial ce emulează dispozitivul GPS, model FTDI FT232H.
În final, la rularea prin qemu, trebuie să folosiți device tree-ul care începe cu bcm2837-
, deoarece rulați kernel-ul mainline. Vedeți explicația aici sau aici. DTB-ul îl puteți compila voi (din kernel: make dtbs
, sau, la Buildroot, aveți setare în meniu) sau prelua din altă parte (cât timp funcționează).
console=
al kernelului este incorect (încercați alt dispozitiv serial).
-10p
). Însă va trebuin să scrieți în README ce ați încercat și ce rezultate ați avut!
Dorim ca sistemul să expună un server HTTP pe portul 80 o interfață web minimalistă care să prezinte, în timp real, datele de la GPS primite (lat/long + dată/timp) prin UART:
* Sistemul va trebui să ruleze un server http ce va asculta pe portul 80;
npm
pentru NodeJS etc.)! Se poate, desigur, face cross compiling, însă trebuie folosit compilatorul de la Buildroot (same thing for Yocto)!
init
și manager de servicii, deci va trebui să creați un astfel de descriptor pentru aplicația web.
În BuildRoot
și Yocto
aveți mai multe opțiuni de init system-uri, la alegere: Busybox (cel mai light dintre toate, se scriu scripturi sh
), SysVInit (aka rc.d
/runlevels
) sau SystemD (mai popular și bine documentat, însă trebuie compilat și poate adăuga ~1-2h în plus la timpul de compilare, depinde de puterea de calcul a sistemului).
Buildroot
, dacă folosiți un interpretor / limbaj care necesită dependințe externe, citiți secțiunea Adding Packages.
Pentru Python aveți incluse deja o mulțime de biblioteci populare.
Pentru Golang, citiți secțiunea Infrastructure for Go packages a manualului.
În general, pentru cei care doresc să folosească un limbaj compilat, este util ghidul general de generare a pachetelor compilate pentru build system-ul lui standard.
Datele de la GPS le veți prelua de la un alt serviciu, descris în subsecțiune următoare. Dacă nu doriți să rezolvați acel task, puteți să prezentați pur și simplu câteva date de test (i.e. hardcodate) în interfața Web.
Pe lângă serviciul web, va trebui să dezvoltați un daemon de achiziție a datelor de pe un dispozitiv serial (emulat prin QEmu ca usb-serial
model FTDI FT232H, vizibil în guest Linux ca /dev/ttyUSB0
);
bash
:D ):gps-daemon
și să pornească automat cu sistemul!<hint> Fiind serială emulată, baud rate-ul configurat nu contează! (merge aproape orice e standard).
Instalați picocom
în imagine pentru depanare facilă!</hint>
Dispozitivul serial emulat va trimite informații codificate în ASCII folosind standardul NMEA, câte o linie per tip citire, un mesaj fiind terminat prin secvența newline CRLF
(i.e. \r\n
).
Exemplu date:
$GPGGA,115357.00,4419.000,N,02636.013,E,1,12,0.92,15.2,M,32.5,M,,*69 $GPGSA,A,3,25,24,07,17,03,01,27,14,30,26,29,12,1.56,0.92,1.25*00 $GPGSV,4,1,15,08,04,320,58,29,00,328,47,06,67,141,51,11,66,056,66*7D $GPGSV,4,2,15,01,48,001,68,07,85,075,16,30,69,342,59,17,40,340,16*71 $GPGSV,4,3,15,03,62,124,05,14,04,320,40,25,44,340,66,12,46,287,06*71 $GPGSV,4,4,15,26,35,180,68,24,46,202,49,27,90,060,36*4E $GPGLL,4419.000,N,02636.013,E,115357.000,A,A*56 $GPRMC,115357.000,A,4419.000,N,02636.013,E,10.500,90.0,151224,,,A*6D $GPHDT,90.0,T*0C $GPVTG,90.0,T,,M,10.5,N,19.4,K*51 $GPZDA,115357.000,15,12,2024,0,0*51
Va trebui să filtrați aceste date (e.g., să extrageți coordonatele GPS și data/timpul și să le convertiți într-un format prezentabil în interfața web).
Vedeți aici un tutorial al formatului NMEA 0183. Este suficient să parsați/preluați doar tipurile GGA
(latitudine/longitudine) și ZDA
(dată + timp UTC), însă ar fi nice to have și informațiile despre viteză / vector de deplasare.
qemu
!
Este recomandat să faceți parsarea liniilor tolarabilă la erori (e.g., să nu crape daemon-ul când primesc un fragment parțial al unui senzor, doar să îl ignore), altfel riscați să fiți depunctați dacă se ajunge la vreun race condition!
Ca și punct de pornire, puteți descărca un schelet inițial cu scripturi + structură recomandată (v0.1). Aceasta conține:
Makefile
util pentru construirea arhivelor; obligatoriu să-l studiați + editați, nu face ce trebuie nemodificat!launch-tema2.sh
pe sistemul gazdă (va rula qemu
cu fișierele kernel+imagine, vedeți mai jos, la conținutul arhivei, ce denumiri folosește);gps-emu.py
ce emulează datele de la dispozitiv, integrat cu launch-tema2.sh
(comunică printr-un FIFO în /tmp
, vedeți cod sursă);vmlinuz-test
compilată ca monolit (MODULES=n
) cu strictul necesar de drivere (consolă serială, PL011, 8250, FT232, USBNET, DHCP etc.);Deoarece Moodle nu acceptă dimensiuni foarte mari, soluția temei va fi împărțită și trimisă în două moduri (vă rugăm să respectați convențiile de denumire cu exactitate!):
url.txt
);
Arhiva cu binarele (.tar.*z
pls; se acceptă gz
și xz
) trebuie să conțină (obligatoriu: să folosiți strict aceste denumiri de fișiere):
tema2.img
: imaginea finală (format raw
!); poate conține sau nu partiții (dar va trebui să adaptați scriptul de rulare).vmlinuz-tema2
: imaginea kernel-ului compatibil cu QEMU;launch-tema2.sh
: script de pornire QEMU (vedeți scheletul dat);6-20 GB
!), DOAR artefactele finale (copiați-le manual sau folosiți ceva similar ca în Makefile-ul din schelet)!500MB
(folosiți tar.xz pentru rată de compresie bună).
Noi avem scripturi care automatizează descărcarea, veți fi depunctați dacă nu urmați aceste convenții!
Ar trebui să meargă descărcate automat punând &download=1
la finalul URL-ului ;)
Arhiva cu fișierele sursă (.zip
pls) OBLIGATORIU să conțină:
rootfs
(orice ați inclus extra peste sistemul de bază – de preferat, organizat într-o structură Unix-like: ./etc/
, ./usr/bin
, ./opt/*
etc.); NU COPIAȚI ROOTFS-UL GENERAT! (doar OVERLAY-ul, dacă ați folosit);.config
) ale kernel și/sau buildroot – obligatoriu dacă e cazul! folosiți numele kernel_config
și buildroot_config
în arhiva cu sursele (în niciun caz nu le lăsați hidden!);README.txt
cu explicații referitoare la modul de construire al imaginii, arhitectura soluției, configurații speciale de optimizare folosite etc.url.txt
cu URL către arhiva .tar.*z a binarelor de pe Sharepoint! (uploadată anterior);checksum.txt
care să conțină hash-ul SHA256 al arhivei cu binarele (obținut cu sha256sum
); ATENȚIE: verificați și re-verificați (de încă 2 ori) conținutul fișierului la încărcare pe Moodle cu hash-ul real deoarece tema nu va fi punctată dacă diferă!make source_archive
, pur și simplu copiați-l pe rădăcină (sau într-un director care nu este ignorat – verificați Makefile-ul din schelet)!1MB
(aveți restricție pe Moodle).
Din 100p total, aveți:
-20p
depunctare pentru imagine/rootfs (contorizat fără kernel, ce poate avea max. 64M
– deși nu e imposibil să-l faceți s depășească această dimensiune, încercați să nu) ce depășește 256MB (testat cu interpretorul Python în Buildroot, tot se încadrează în limită!);-10p
depunctare pentru kernel necompilat de voi (ori îl folosiți pe cel furnizat de noi în schelet, ori cel furnizat de voi nu conține LOCALVERSION="-si-<prenume.nume>"
);qemu
este obligatoriu pentru a lua restul de puncte acordate pe task-urile următoare!Bonus: