Jedną ze strategii szybkiego wdrażania nowych produktów wbudowanych na rynek jest wykorzystanie zunifikowanych platform. Mając plan działania identyfikujący rozwiązania, które zostaną wpuszczone do obiegu, np. w ciągu najbliższych kilku lat, można z powodzeniem stworzyć ww. ujęcie. Ponieważ różni klienci chcą nieco innych funkcji, konfiguracji i dostosowań, opracowywanie pojedynczych produktów jest niepraktyczne. Zamiast tego, jeśli postawi się na opcję z wieloma rozwiązaniami ze wspólnym oprogramowaniem podstawowym, które można rozszerzyć i rekonfigurować, uda się radykalnie obniżyć koszty inżynieryjne. A także skrócić czas przygotowywania nowych produktów. Przyjrzyjmy się w poniższym tekście pięciu sugestiom dotyczącym pisania konfigurowalnego oprogramowania układowego, które diametralnie poprawią jego jakość.
Wskazówka nr 1 — zacznij od podejścia odgórnego
Zespoły zajmujące się tym zagadnieniem często mają trudności z przyszykowaniem elastycznego oprogramowania, ponieważ myślą o tym ujęciu od podstaw. Podejście do tego od strony sprzętu stawia tenże, a nie aplikację lub użytkownika w centrum konceptu. Rezultatem jest często ściśle powiązany kod, który ma niewielką lub żadną konfigurowalność. To jest dokładnie to, czego powinniśmy unikać, aby stworzyć elastyczne oprogramowanie systemu wbudowanego.
Inna postawa w tym zakresie może zmienić wszystko. Deweloperzy będą zmuszeni do zastanowienia się, w jaki sposób ich klienci mają zamiar korzystać z produktu. Bardzo często spojrzenie na rozwiązanie oczami różnych jednostek pozwala natychmiast określić, gdzie konieczna jest konfigurowalność. Jeden klient może potrzebować ustawienia prędkości silnika A, podczas gdy inny szybkości silnika B. W przypadku utknięcia jednostki napędowej, jedna osoba może chcieć, aby dioda LED świeciła światłem ciągłym, podczas gdy druga, aby migała z częstotliwością 5 Hz.
Rozpoczynając od góry, od klienta (lub klientów) i przechodząc do sprzętu, można poprawić konfigurowalność tworzonego oprogramowania. Kluczowe jest jednak zorientowanie na użytkownika końcowego.
Wskazówka nr 2 — wykorzystaj pliki konfiguracyjne
Jeśli spojrzymy poza branżę, przekonamy się, że programiści używają na ogół plików konfiguracyjnych do dostosowania swojego oprogramowania do konkretnej aplikacji. Te mogą pomóc w dyktowaniu tego, jak ma się zachowywać tworzone rozwiązanie w odmiennych wariantach w zależności od ustawień. Oczywiście plik konfiguracyjny zapewniać może różne poziomy dostosowania oprogramowania. Poprawia to możliwości ponownego wykorzystania aplikacji i może obniżyć ogólne koszty wdrażania systemu.
Twórcy oprogramowania układowego mogą umieszczać niektóre parametry konfiguracyjne w pamięci nieulotnej, aby umożliwić dostosowania, jednak te wpływają tylko na zachowanie systemu w czasie pracy. A co z konfiguracją, która całkowicie zmienia funkcjonowanie podstawowego kodu? Chodzi tutaj o możliwość ustawienia logiki oprogramowania wbudowanego.
Interesującą techniką, często używaną do poprawy elastyczności, jest wykorzystanie plików konfiguracyjnych, które automatycznie formułują kod programu. Na przykład można spożytkować napisany w Pythonie zestaw dodatkowych narzędzi odczytujący plik YAML z informacjami o konfiguracji wątków i generujący kod C/C++, który jest kompilowany dla aplikacji na mikrokontrolerze. Jeśli oprogramowanie dla danego klienta wymaga niestandardowych funkcji, nowy wątek może zostać dodany do konfiguracji i automatycznie włączony do kompilacji, a sama jego logika tylko opisana ręcznie. Pomysł ten można wykorzystać do ustawienia również wszystkiego poza wątkami i zastosować dany schemat do informacji specyficznych dla produktu, takich jak liczba silników, przekaźników, obecny lub nieobecny sprzęt i tak dalej.
Rys.1. Przykładowa architektura korzystania z konfiguracji i szablonów wprowadzonych do generatora, który przygotowuje kod źródłowy na podstawie ustawień.
Jeśli rozejrzeć się po ekosystemach dedykowanych do tworzenia oprogramowania dla mikrokontrolerów, zauważymy, że większość z nich posiada wbudowaną tego rodzaju funkcjonalność, przynajmniej do pewnego stopnia. Czym innym jest np. automatyczna inicjalizacja stosu, sterty czy nawet wybranych peryferii w układzie lub konfiguracja trybów i opcji wejść/wyjść (np. w taki sposób, jak robi to STM32CubeMX dla układów STM32 czy PsoC Creator dla rodziny jednostek PSoC). Środowiska wyposażone w te funkcje często pozwalają na ustawienia z poziomu interfejsu graficznego. Zapewnia to bardzo wygodny i szybki sposób konfiguracji.
Wskazówka nr 3 — twórz tabele konfiguracji w swoim kodzie
Techniką, która najczęściej używana jest przez większość programistów do pisania elastycznego kodu, jest tworzenie i stosowanie tabel konfiguracyjnych. Te ostatnie są zwykle definiowane jako tablica lub struktury. Na przykład, jeśli chcemy utworzyć tabelę konfiguracji dla cyfrowego urządzenia peryferyjnego wejścia/wyjścia, można zdeterminować strukturę, która wygląda podobnie do następującego kodu (w zależności od obsługiwanych funkcji):
Powyższe ujęcie definiuje charakterystykę pinu Dio, która przeważnie byłaby używana do jego inicjalizacji. Następnie można utworzyć tablicę struktury z informacjami konfiguracyjnymi dla każdego pinu Dio w systemie, co będzie wyglądało mniej więcej tak:
Wszyscy powinni stosować tego rodzaju rozwiązania z kilku powodów:
* Są czytelne dla człowieka, co świetnie sprawdza się przy przeglądach kodu;
* Mogą być generowane przez skrypt czytający plik YAML, JSON itp.;
* W razie potrzeby mogą być edytowane ręcznie przez człowieka;
* Kod inicjujący jest uproszczony przez zapętlenie po tablicy;
* Tabele są przenośne, wielokrotnego użytku i skalowalne;
* Mogą być stosowane do konfiguracji urządzeń, jak i logiki i parametrów oprogramowania.
Wskazówka nr 4 — wykorzystuj warstwy abstrakcji
Jednym z problemów, które można zauważyć w przypadku wielu przykładów oprogramowania układowego, jest to, że jest ono ściśle skorelowane ze sprzętem. Często wiąże się kod swojej aplikacji bezpośrednio z urządzeniem, co utrudnia przenoszenie i ponowne używanie oprogramowania wbudowanego. Jak wielu z nas miało okazję nauczyć się podczas obecnego niedoboru chipów, że jeśli trzeba znów przygotować rozwiązanie do współdziałania z nowym układem, powrót i dalsze wykorzystanie całego kodu może być koszmarem. Aby tego uniknąć, koniecznie trzeba mieć możliwość łatwego skonfigurowania aplikacji do pracy z dowolnym sprzętem.
Jedną z opcji dla rozwikłania tego problemu jest użycie warstwy abstrakcji. Ta tworzy interfejs dostępu do urządzenia, którego muszą przestrzegać sterowniki. Kod aplikacji wywołuje funkcje na poziomie tej abstrakcji. Pomysł ten jest znany jako zasada odwrócenia zależności. Ta jest częścią reguł SOLID dotyczących projektowania obiektowego. Używając interfejsu między sprzętem a kodem aplikacji, odwraca się dependencję, aby przełamać zależność urządzenie/rozwiązanie. A więc sprawić, aby oprogramowanie i sprzęt były bardziej konfigurowalne oraz od siebie niezależne.
Wskazówka nr 5 — polimorfizm jest twoim przyjacielem
Jeśli jesteś programistą C, możesz pomyśleć, że polimorfizm to słowo na coś złego lub coś, co nie istnieje w tym języku. W obu przypadkach nie miałbyś racji.
Polimorfizm to potężna technika, która pozwala konfigurować zachowanie danej aplikacji w czasie kompilacji (polimorfizm statyczny) lub w trakcie wykonywania (polimorfizm dynamiczny). Metoda ta umożliwia jednemu interfejsowi reprezentować różne typy obiektów. Załóżmy na przykład, że oprogramowujemy produkt, który miga diodą LED. Ta ostatnia może być podłączona do sprzętu przez port Dio, do kanału PWM, do zewnętrznego ekspandera wejść/wyjść dołączonego do SPI lub I²C i tak dalej. W zależności od konkretnej wersji platformy sprzętowej lub wymagań klienta może ulec zmianie sposób jej podpięcia. Chociaż wydaje się to irytującym problemem konfiguracyjnym, programista może użyć polimorfizmu do napisania kodu aplikacji, który nie dba o sposób podłączenia. Technika ta może poprawić konfigurowalność, a ponadto możliwość ponownego użycia kodu i jego elastyczność.
Podsumowanie
Dzisiejsze produkty wbudowane nie są już jednorazowymi projektami, które są wytwarzane przez wiele lat. Innowacje i zmiany w technologii mają charakter wykładniczy, a zespoły muszą opracowywać kod dla platformy, który będzie można ponownie wykorzystać do wprowadzenia na rynek sporej liczby rozwiązań w nadchodzących latach. Aby sprostać tej potrzebie, trzeba uwzględnić konfigurowalność oprogramowania układowego. W niektórych przypadkach nacisk na ww. elastyczność zwiększy złożoność i koszty początkowe. A być może nawet będzie to mniej efektywne z punktu widzenia pamięci i wydajności. Jednak konfigurowalność zapewni firmom opracowującym produkty wbudowane uniwersalność i skalowalność, aby sprostać przyszłym wyzwaniom klientów.
Źródło: https://www.embedded.com/5-tips-for-writing-configurable-firmware/
Wskazówka nr 1 — zacznij od podejścia odgórnego
Zespoły zajmujące się tym zagadnieniem często mają trudności z przyszykowaniem elastycznego oprogramowania, ponieważ myślą o tym ujęciu od podstaw. Podejście do tego od strony sprzętu stawia tenże, a nie aplikację lub użytkownika w centrum konceptu. Rezultatem jest często ściśle powiązany kod, który ma niewielką lub żadną konfigurowalność. To jest dokładnie to, czego powinniśmy unikać, aby stworzyć elastyczne oprogramowanie systemu wbudowanego.
Inna postawa w tym zakresie może zmienić wszystko. Deweloperzy będą zmuszeni do zastanowienia się, w jaki sposób ich klienci mają zamiar korzystać z produktu. Bardzo często spojrzenie na rozwiązanie oczami różnych jednostek pozwala natychmiast określić, gdzie konieczna jest konfigurowalność. Jeden klient może potrzebować ustawienia prędkości silnika A, podczas gdy inny szybkości silnika B. W przypadku utknięcia jednostki napędowej, jedna osoba może chcieć, aby dioda LED świeciła światłem ciągłym, podczas gdy druga, aby migała z częstotliwością 5 Hz.
Rozpoczynając od góry, od klienta (lub klientów) i przechodząc do sprzętu, można poprawić konfigurowalność tworzonego oprogramowania. Kluczowe jest jednak zorientowanie na użytkownika końcowego.
Wskazówka nr 2 — wykorzystaj pliki konfiguracyjne
Jeśli spojrzymy poza branżę, przekonamy się, że programiści używają na ogół plików konfiguracyjnych do dostosowania swojego oprogramowania do konkretnej aplikacji. Te mogą pomóc w dyktowaniu tego, jak ma się zachowywać tworzone rozwiązanie w odmiennych wariantach w zależności od ustawień. Oczywiście plik konfiguracyjny zapewniać może różne poziomy dostosowania oprogramowania. Poprawia to możliwości ponownego wykorzystania aplikacji i może obniżyć ogólne koszty wdrażania systemu.
Twórcy oprogramowania układowego mogą umieszczać niektóre parametry konfiguracyjne w pamięci nieulotnej, aby umożliwić dostosowania, jednak te wpływają tylko na zachowanie systemu w czasie pracy. A co z konfiguracją, która całkowicie zmienia funkcjonowanie podstawowego kodu? Chodzi tutaj o możliwość ustawienia logiki oprogramowania wbudowanego.
Interesującą techniką, często używaną do poprawy elastyczności, jest wykorzystanie plików konfiguracyjnych, które automatycznie formułują kod programu. Na przykład można spożytkować napisany w Pythonie zestaw dodatkowych narzędzi odczytujący plik YAML z informacjami o konfiguracji wątków i generujący kod C/C++, który jest kompilowany dla aplikacji na mikrokontrolerze. Jeśli oprogramowanie dla danego klienta wymaga niestandardowych funkcji, nowy wątek może zostać dodany do konfiguracji i automatycznie włączony do kompilacji, a sama jego logika tylko opisana ręcznie. Pomysł ten można wykorzystać do ustawienia również wszystkiego poza wątkami i zastosować dany schemat do informacji specyficznych dla produktu, takich jak liczba silników, przekaźników, obecny lub nieobecny sprzęt i tak dalej.

Rys.1. Przykładowa architektura korzystania z konfiguracji i szablonów wprowadzonych do generatora, który przygotowuje kod źródłowy na podstawie ustawień.
Jeśli rozejrzeć się po ekosystemach dedykowanych do tworzenia oprogramowania dla mikrokontrolerów, zauważymy, że większość z nich posiada wbudowaną tego rodzaju funkcjonalność, przynajmniej do pewnego stopnia. Czym innym jest np. automatyczna inicjalizacja stosu, sterty czy nawet wybranych peryferii w układzie lub konfiguracja trybów i opcji wejść/wyjść (np. w taki sposób, jak robi to STM32CubeMX dla układów STM32 czy PsoC Creator dla rodziny jednostek PSoC). Środowiska wyposażone w te funkcje często pozwalają na ustawienia z poziomu interfejsu graficznego. Zapewnia to bardzo wygodny i szybki sposób konfiguracji.
Wskazówka nr 3 — twórz tabele konfiguracji w swoim kodzie
Techniką, która najczęściej używana jest przez większość programistów do pisania elastycznego kodu, jest tworzenie i stosowanie tabel konfiguracyjnych. Te ostatnie są zwykle definiowane jako tablica lub struktury. Na przykład, jeśli chcemy utworzyć tabelę konfiguracji dla cyfrowego urządzenia peryferyjnego wejścia/wyjścia, można zdeterminować strukturę, która wygląda podobnie do następującego kodu (w zależności od obsługiwanych funkcji):
Code: c
Powyższe ujęcie definiuje charakterystykę pinu Dio, która przeważnie byłaby używana do jego inicjalizacji. Następnie można utworzyć tablicę struktury z informacjami konfiguracyjnymi dla każdego pinu Dio w systemie, co będzie wyglądało mniej więcej tak:
Code: c
Wszyscy powinni stosować tego rodzaju rozwiązania z kilku powodów:
* Są czytelne dla człowieka, co świetnie sprawdza się przy przeglądach kodu;
* Mogą być generowane przez skrypt czytający plik YAML, JSON itp.;
* W razie potrzeby mogą być edytowane ręcznie przez człowieka;
* Kod inicjujący jest uproszczony przez zapętlenie po tablicy;
* Tabele są przenośne, wielokrotnego użytku i skalowalne;
* Mogą być stosowane do konfiguracji urządzeń, jak i logiki i parametrów oprogramowania.
Wskazówka nr 4 — wykorzystuj warstwy abstrakcji
Jednym z problemów, które można zauważyć w przypadku wielu przykładów oprogramowania układowego, jest to, że jest ono ściśle skorelowane ze sprzętem. Często wiąże się kod swojej aplikacji bezpośrednio z urządzeniem, co utrudnia przenoszenie i ponowne używanie oprogramowania wbudowanego. Jak wielu z nas miało okazję nauczyć się podczas obecnego niedoboru chipów, że jeśli trzeba znów przygotować rozwiązanie do współdziałania z nowym układem, powrót i dalsze wykorzystanie całego kodu może być koszmarem. Aby tego uniknąć, koniecznie trzeba mieć możliwość łatwego skonfigurowania aplikacji do pracy z dowolnym sprzętem.
Jedną z opcji dla rozwikłania tego problemu jest użycie warstwy abstrakcji. Ta tworzy interfejs dostępu do urządzenia, którego muszą przestrzegać sterowniki. Kod aplikacji wywołuje funkcje na poziomie tej abstrakcji. Pomysł ten jest znany jako zasada odwrócenia zależności. Ta jest częścią reguł SOLID dotyczących projektowania obiektowego. Używając interfejsu między sprzętem a kodem aplikacji, odwraca się dependencję, aby przełamać zależność urządzenie/rozwiązanie. A więc sprawić, aby oprogramowanie i sprzęt były bardziej konfigurowalne oraz od siebie niezależne.
Wskazówka nr 5 — polimorfizm jest twoim przyjacielem
Jeśli jesteś programistą C, możesz pomyśleć, że polimorfizm to słowo na coś złego lub coś, co nie istnieje w tym języku. W obu przypadkach nie miałbyś racji.
Polimorfizm to potężna technika, która pozwala konfigurować zachowanie danej aplikacji w czasie kompilacji (polimorfizm statyczny) lub w trakcie wykonywania (polimorfizm dynamiczny). Metoda ta umożliwia jednemu interfejsowi reprezentować różne typy obiektów. Załóżmy na przykład, że oprogramowujemy produkt, który miga diodą LED. Ta ostatnia może być podłączona do sprzętu przez port Dio, do kanału PWM, do zewnętrznego ekspandera wejść/wyjść dołączonego do SPI lub I²C i tak dalej. W zależności od konkretnej wersji platformy sprzętowej lub wymagań klienta może ulec zmianie sposób jej podpięcia. Chociaż wydaje się to irytującym problemem konfiguracyjnym, programista może użyć polimorfizmu do napisania kodu aplikacji, który nie dba o sposób podłączenia. Technika ta może poprawić konfigurowalność, a ponadto możliwość ponownego użycia kodu i jego elastyczność.
Podsumowanie
Dzisiejsze produkty wbudowane nie są już jednorazowymi projektami, które są wytwarzane przez wiele lat. Innowacje i zmiany w technologii mają charakter wykładniczy, a zespoły muszą opracowywać kod dla platformy, który będzie można ponownie wykorzystać do wprowadzenia na rynek sporej liczby rozwiązań w nadchodzących latach. Aby sprostać tej potrzebie, trzeba uwzględnić konfigurowalność oprogramowania układowego. W niektórych przypadkach nacisk na ww. elastyczność zwiększy złożoność i koszty początkowe. A być może nawet będzie to mniej efektywne z punktu widzenia pamięci i wydajności. Jednak konfigurowalność zapewni firmom opracowującym produkty wbudowane uniwersalność i skalowalność, aby sprostać przyszłym wyzwaniom klientów.
Źródło: https://www.embedded.com/5-tips-for-writing-configurable-firmware/
Cool? Ranking DIY