Czy próbowaliście kiedyś skompilować jeden i ten sam kod pod dwie różne platformy? Z pozoru może wydawać się to trudne, zwłaszcza w przypadku tak różnych od siebie platform jak mikrokontroler ESP32 i system Windows, ale tutaj pokażę, że podstawowy mechanizm kompilacji takiego programu wcale nie musi być skomplikowany. Zacznę tu od prostego 'Hello world' na ESP32 a potem spróbuję je przenieść na Windows tak, aby oba projekty można było kompilować z poziomu PIO bez przełączania plików i edycji kodu.
Punktem wyjściowym jest Hello World na ESP32:
Kod: C / C++
Mamy wtedy następujący plik platformio.ini:
Kod: Ini
Taki kod się kompiluje, wgrywa na ESP32 i kolejno odlicza:
Hello world [0]
Hello world [1]
Hello world [2]
Hello world [3]
Teraz pytanie, jak do tego dodać drugą platformę?
Dodajemy osobne środowisko w platformio - natywne. GCC musi być w ścieżce PATH systemowej i działać z poziomu linii komend.
Kod: Ini
Po chwili pojawi się nowy "task" projektu:
Tam też mamy opcję Build, czyli kompilacji - teraz zakończy się ona błędami:
Wynika to z tego, że kod z ESP32 nie zadziała sam z siebie na Windows - brakuje nagłówków, funkcji, bibliotek. Nie mamy m. in:
- Arduino.h
- millis()
- delay()
- nie ma co wywoływać loop i setup(), zamiast tego jest main, itd.
Trzeba te funkcje zastąpić. Kolejno:
- nagłówki załączam obecne na Windows - <stdio.h> itd
- millis() zastąpiłem poprzez użycie time(NULL) z nagłówka time.h, objąłem to funkcją tak by móc pobierać czas w sekundach od startu programu
- delay zastąpiłem poprzez Sleep (na systemach unixowych jest z kolei usleep)
- loop i setup ręcznie wywołałem z main()
Rezultat:
Kod: C / C++
Kompilujemy, uruchamiamy exe i... działa:
W ten sposób mamy dwie bardzo różne platformy w jednym projekcie. Teraz należałoby dodać jakąś prostą warstwę abstrakcji i wydzielić ją do osobnych plików i nagłówków, ale o tym innym razem...
Podsumowując, PlatformIO jest w stanie obsłużyć wiele środowisk w ramach jednego projektu i pozwala na współdzielenie kodu między zupełnie różnymi platformami – od mikrokontrolera aż po system operacyjny. Dzięki sprytnemu wykorzystaniu dyrektyw preprocesora całość można ładnie wydzielić i opakować, co wkrótce też pokażę.
Czy widzicie jakieś zastosowania dla tego typu mechanizmu?
Mi przychodzi na myśl stary temat o API pogody:
Jak pobrać pogodę z OpenWeatherMap API na samych socketach? Tutorial API, JSON, C
Tam powoływałem się na zgodność podstawowego API socketów na różnych platformach i pokazywałem, jak można to wykorzystać.
Fajne? Ranking DIY Pomogłem? Kup mi kawę.