Arduino standardní knihovna vznikla dávno před rokem 2011, takže nové best practices v C++ a nové styly API tam prostě nejsou a nebudou. A vycházela ještě ze starších projektů Processing a Wiring.
Cílová skupina pro Arduino navíc nejsou profesionální embedded vývojáři. Primárně s ním začali umělci a akademici. Bez wifi (ESP přišlo až mnohem později). A i dnes je spousta kódu od bastířů, hardwerářů a lidí co napíšou co potřebují pro svůj problém (motto: scratch your own itch). Takže ten komentář "Dodělám později" není nic neobvyklého.
Už jsme na to narazili v diskuzi o Fish. Lidi nemají obecně motivaci přepisovat starý kód do nového stylu, pokud to neopraví něco zásadního. A staré styly API snadno nezměníte, protože by to rozbilo veškerý starý kód (dekádu trvající přechod Python 2 vs. 3 nám buď varováním).
Takže ano, ty vysokoúrovňové Arduino abstrakce neumí využít ten hardware naplno nebo neumožní libovolné skládání více asynchronních úloh (nebo neumí low power provoz).
Pokud jste si nikdy nevšiml, průmyslové embedded kontroléry se snaží multitaskingu vyhnout! Superloop styl s pollingem je velice obvyklý. Nikdy jste se nezamyslel nad významem Arduino základních metod setup a loop?
https://en.wikibooks.org/wiki/Embedded_Systems/Super_Loop_Architecture
Mimochodem, zrovna ten ESP wifi koprocesor polling umí, jen si ho musíte zakomponovat do smyčky sám. Arduino vysokoúrovňové API je úmyslně jednoduché (viz cílová skupina).
https://github.com/arduino/ArduinoCore-renesas/blob/main/libraries/WiFiS3/src/WiFi.cpp - je to jen práce se sériovou linkou.
Komunita jako taková pak umí napsat i kvalitní kód, třeba EtlCPP (https://www.etlcpp.com/) je implementace STL kontejnerů a algoritmů pro prostředí bez dynamické alokace.
Pro lidi více na profesionální straně spektra je tu pak třeba možnost použít PlatformIO (https://platformio.org/) a vyhnout se Arduino IDE úplně.
Takže až příště budete nadávat na API a kvalitu, zamyslete se nad tím co používáte. On je totiž rozdíl mezi hobby a průmyslovým "nářadím". Arduino tudíž ani nemůže přejít na profesionální a detalní API, protože by tím odřízlo svoji cílovou skupinu (a staré projekty).
V tom prvním máte určitě pravdu, že staré API se špatně opravuje a jediná schůdná cesta je pak přes nové alternativní API, které zase vede k nutnosti udržovat obě. A rozumím, není to jednoduché.
Taky můj rozbor digitalWrite a pinMode nebyl míněn jako kritika, ale jako určité vyjádření pochopení. Já bych si představoval něco jako pinModeEx(pin, mode), která by třeba mohla nastavit pin do libovolného z výše uvedených stavů, kdy HIGH a LOW jsou také chápány jako móde. Pak by se mi líbil systém transkačních nastavení pinů, kdy nastavím víc pinů a jednorázově to commitnu, a někdo under hood zařídí operaci atomicky. Je to rozšíření API
Namítám ale jednu věc. Arduino R4 UNO (Minima i Wifi) byly uvedeny v červnu 2023. Předpokládejme že vývoj SW probíhal rok, tedy bavíme se o programátorských standardech z roku 2022. Navíc pro překladač, který v té době už 6 let podporuje C++17. Ty programátorské styly které se tam používají byly platné před rokem 2011, to je nějaký 12 let!!!! Kritika je na místě
Bridge mezi ESP32 a Renesas je softwarové vybavení které vzniklo přímo určené pro Arduino R4, jinde se nepoužívá . Github tohoto projektu začíná 16. května 2023
https://github.com/arduino/uno-r4-wifi-usb-bridge/commit/9d2e7d71183d8a6e3e7e3511237dd7e0f2a7aa58
Takže se prosím přestaňme vymlouvat na stará API a neexistenci ESP čipů. Ten kód je z brusu nový.
Pak bych potřeboval vysvětlit ty poznámky kolem superlooup. Jestli jse z toho pochopil, že mi chybí multitasking - nic takového jsem neříkal, je rozdíl mezi "parallel a concurrency". Stejně tak když někde zmíním asynchroní přístup, nemyslím s tím multithreading. Právě asynchronní přístup umožnuje dobře navrhnout superloop. Ten jen není pevně danný, ale dynamicky provádí to, co je požadováno. Typicky mohu superloop použít pro eventové řízení. V rámci superloopu se zjistí změna stavu nějakého čidla a vygeneruje se event. Asynchronní kód pak může vypadat takto
co_await wait_pin(1, HIGH); //čekej na až bude pin 1 na HIGH
přitém co_await vrací řízení do superloopu. To je concurrency, to je asynchronní řízení. Pokud nemám co_await, mohu postaru použít callbacky, třeba
on_pin(1, HIGH, [=]{... /* dělej něco */ ...});
I to je asynchronní přístup.
Scan network by šel realizovat
WiFi.scanNetwork( [=] (auto result) {... zpracuj vysledek ...} );
S tím, že lambda callback se zavolá jakmile je scan hotový a kód mezitím dělá něco jiného. Samozřejmě se callback zavolá ze superloopu když se zjistí, že operace je dokončena.
A tím se dostávám k poolingu nad ESP. Nemáte pravdu, pooling tam nejde zapnout, nebo jen pro některé operace. Ano WiFiServer.available() tam je, stejně jako WiFiClient.available() ale to je všechno. Třeba WiFi.localIP je blokující s timeoutem až 10 sekund. WiFi.begin() je blokující, ale timeout si mohu nastavit (naštestí), WiFiClient.send() je blokující, pokud ESP zrovna loví signál a nemá kam data odeslat
Aby ten bridge byl plně asynchroní, musel by ten protokol vypadat jinak. API by muselo používat callbacky nebo korutiny (C++20), Muselo by se v superloopu volat nějaké udělátko co zjišťuje, jestli ESP už dokončil činost. V protokolu by na to musel existovat nějaká krátká zpráva, která by se na serial portu neztratila. Třeba znak. Jakmile by se ten znak objevil, ze strany Renesas by se poslal command na přečtení výsledku.
To by pak umožnilo superloopu vyvolávat asynchronní callbacky na požadované operace.
Uvažoval jsem, že bych to samozřejmě celé přepsal, ale pro koho? Kdo to ocení? Já zřejmě žádný další projekt zatím dělat nebudu.
(navíc bych musel asi přepsat i ten bridge, změnit protokol)
Doufám, že si teď rozumíme.
Renesas podpora sice je relativně nová, ale ten stejný kód (API) funguje pořád i na původní AVR Arduino Uno. A taky na dalších deskách s jinými cpu - MSP430, ESP, Tiva, STM, .. A ne všechny ty desky se chovají stejně nebo mají stejný přístup k nastavování GPIO. AVR třeba neumí open-drain a musí se emulovat. MSP a STM32 open drain umí atd.
Korutiny jsem právě na mysli neměl. Měl jsem na mysli opravdu čistý polling, kde je garantováno pořadí v jakém se veškerý kód provede, a to včetně časování.
- přečíst vstupy
- vypočítat akce (něco jako serial buffer = "wifi connecting")
- nastavit výstupy (serial write "get wifi status")
- znovu nebo čekat
Podívejte se na kód té WiFi třídy. Ta polling část se dá realizovat pomocí toho objektu modem. Jediné co to dělá je posílání a příjem dat přes sériovou linku. Takže pošlete dotaz na stav. A pollujete odpověď.
Co se nových C++17 vlastností týče.. cílová skupina pro Arduino prostě C++ korutiny nezvládá. (Popravdě, ta [=] syntaxe je hrozná, ale to je asi o zvyku). A souhlasím, že zrovna ten wifi bridge je hrozně nečitelný. A to ani nemusím komentovat C++, ono je to nečitelné i z pohledu C.
Intenzivně se zabývám programováním zejména v jazyce C++. Vyvíjím vlastní knihovny, vzory, techniky, používám šablony, to vše proto, aby se mi usnadnil život při návrhu aplikací. Pracoval jsem jako programátor ve společnosti Seznam.cz. Nyní jsem se usadil v jednom startupu, kde vyvíjím serverové komponenty a informační systémy v C++
Přečteno 57 601×
Přečteno 27 720×
Přečteno 26 403×
Přečteno 24 367×
Přečteno 22 864×