LinkedIn YouTube Facebook
Szukaj

Wstecz
SoM / SBC

Implementacja funkcji Screen Mirroring na platformach Raspberry Pi oraz SoMLabs VisionSOM-6ULL

Kiedy 8 lat temu w prasie zaczęły pojawiać się pierwsze informacje dotyczące komputera jednopłytkowego Raspberry Pi został on głośno okrzyknięty pogromcą typowych komputerów PC w zastosowaniach biurowych i edukacyjnych. Pomimo tego, że szumnie ogłaszana rewolucja nie nastąpiła, to komputer Raspberry Pi dość mocno wpisał się w najnowszą historię informatyki i jest obecnie coraz częściej spotykany w standardowym użyciu, nawet przez osoby nie związane zawodowo z systemami wbudowanymi. Niech potwierdzeniem tych słów będzie fakt, że w ostatnich miesiącach miałem przyjemność brać udział w nietechnicznym szkoleniu, którego prowadzący zdecydował się na wykorzystanie Raspberry Pi, jako niewielkiego i energooszczędnego zamiennika typowego komputera PC. Podczas prezentacji pojawiła się jednak potrzeba jednoczesnego zaprezentowania na rzutniku informacji zawartych na ekranie telefonu prowadzącego, jak i samej prezentacji – czy tak postawiony problem można rozwiązać w sposób czysto programowy, bez użycia dodatkowych konwerterów sprzętowych? Spróbujmy znaleźć odpowiedź na to pytanie.

W niniejszym artykule zaprezentowane zostaną dwa proste sposoby realizacji funkcjonalności Screen Mirroring, czyli przesłania i wyświetlenia zawartości ekranu urządzenia mobilnego na zewnętrznych ekranach stacjonarnych. Do realizacji tego zadania wykorzystany zostanie telefon z systemem Android oraz dwa komputery jednopłytkowe – wydajny pod kątem aplikacji multimedialnych Raspberry Pi 4, a także przystosowany głównie do zadań kontrolno-pomiarowych, zestaw SoMLabs VisionSOM-6ULL z energooszczędnym procesorem NXP i.MX6ULL. Wybór dwóch różnych platform sprzętowych pozwoli na dobór różnych rozwiązań programowych, dopasowanych pod kątem możliwości oferowanych przez sprzęt – od prostych wywołań z pakietu funkcji dostarczanych przez projekt GStreamer, aż do kompilacji otwarto-źródłowego i funkcjonalnego projektu scrcpy.

Screen Mirroring na platformie SoMLabs VisionSOM-6ULL

Proces implementacji funkcji realizującej Screen Mirroring rozpoczniemy od wykorzystania platformy VisionSOM-6ULL wraz z dedykowanym wyświetlaczem LCD oraz modułem wyposażonym w gniazdo karty pamięci SD. Pomimo, że procesory i.MX6ULL nie posiadają wyspecjalizowanych układów sprzętowych do dekodowania strumieni wideo i wsparcia dla grafiki 2D/3D (co przekłada się na znacznie niższy koszt procesora w porównania do lepiej wyposażonych układów z rodziny i.MX), możliwa jest wydajna implementacja obsługi przesyłania, a także dekodowania obrazu. Operacja ta wymaga jednak od użytkownika systemu nieco więcej zabiegów programowych w procesie przygotowania systemu.

Prace nad projektem rozpoczynamy od przygotowania karty z systemem operacyjnym Linux. Producent komputera – firma SoMLabs – na stronach Wiki swojego produktu dostarcza użytkownikowi wsparcie w postaci gotowych obrazów z dystrybucją Debian. Dostępny jest także opis budowy obrazów z wykorzystaniem takich narzędzi jak Buildroot oraz Yocto. W niniejszym artykule wykorzystamy gotowe obrazy systemu z dystrybucją Debian w wersji Stretch. Na stronie producenta udostępniono również nowszą wersję dystrybucji – Debian Buster – z wbudowaną obsługą dedykowanego wyświetlacza LCD.

Przygotowanie karty SD

Przygotowanie karty SD rozpoczynamy od pobrania obrazu systemu. W środowisku Linux operację tę można zrealizować poleceniem:

wget http://ftp.somlabs.com/debian-stretch-visionsom-6ull.img.xz

Po pobraniu pliku rozpakujmy jego zawartość za pomocą narzędzia unxz:

unxz debian-stretch-visionsom-6ull.img.xz

Po pobraniu oraz rozpakowaniu pliku można przystąpić do wgrania obrazu systemu na kartę micro-SD. Jedną najprostszych metod zapisania obrazu z pliku jest wykorzystanie linuksowego narzędzia dd.

sudo dd if=./debian-stretch-visionsom-6ull.img of=/dev/sdX bs=4M oflag=dsync

Po wgraniu obrazu na kartę, możemy zalogować się do konsoli systemu wykorzystując wbudowany w płytę bazową VisionCB-STD konwerter UART-USB oraz dowolny program emulatora terminalu:

picocom -b 115200 /dev/ttyUSBX

Po otwarciu połączenia należy zalogować się konto użytkownika root (bez hasła):

Debian GNU/Linux 9 localhost.localdomain ttymxc0
localhost login: root
root@localhost:~#

Wraz z obrazem Debian Stretch firma SoMLabs dostarcza użytkownikowi wygodne środowisko konfiguracji i kompilacji jądra systemu oraz plików Device Tree. Środowisko to zostało zbudowane w oparciu o narzędzia Qemu oraz chroot, co pozwala na uruchomienie na komputerze PC (np. x86) nienatywnych plików wykonywalnych (np. dla architektury ARM) w standardowy dla plików natywnych sposób, tj. poleceniem ./program. Do poprawnego działania środowiska w dystrybucji Ubuntu, niezbędna jest uprzednia instalacja pakietów qemu, binfmt-support oraz qemu-user-static:

apt-get install qemu binfmt-support qemu-user-static

Pobranie, rozpakowanie i uruchomienie (w tym wykonanie operacji chroot zmieniającej katalog główny) kompletnego środowiska:

wget http://ftp.somlabs.com/somlabs-visionsom-6ull-debian-rootfs-qemu.tar.xz
sudo tar xf somlabs-visionsom-6ull-debian-rootfs-qemu.tar.xz
sudo ./somlabs-debian/chtoolchain

Po uruchomieniu skryptu chtoolchain źródła systemu Linux są dostępne w katalogu /home/developer/source/kernel/linux-rel_imx_4.1.15_2.1.0_ga. Dla uproszczenia dalszego opisu, przejdźmy zatem do katalogu z kodem źródłowym:

cd /home/developer/source/kernel/linux-rel_imx_4.1.15_2.1.0_ga

W kolejnym kroku do katalogu arch/arm/configs należy skopiować domyślną konfigurację jądra (plik visionsom-6ull-linux_defconfig) udostępnioną przez producenta płytki:

cp ../../somlabs-dts-1.0/visionsom-6ull-linux_defconfig arch/arm/configs/

W odróżnieniu od najnowszej wersji obrazu systemu Debian (Buster) dla płytki VisionSOM, opis Device Tree (w postaci pliku arch/arm/boot/dts/somlabs-visionsom-6ull.dts) w obrazie Debian Stretch nie zawierał pełnego wsparcia dla dedykowanego ekranu LCD. Aby poprawnie uruchomić wyświetlacz, niezbędne jest zatem pobranie i zaaplikowanie dodatkowej łatki:

wget http://wiki.somlabs.com/images/c/cd/Enable-tft-lcd.zip
unzip Enable-tft-lcd.zip

patch arch/arm/boot/dts/somlabs-visionsom-6ull.dts ./enable-tft-lcd.patch

Kompilacja jądra i Device Tree

W tak przygotowanym środowisku można dokonać konfiguracji i kompilacji jądra oraz opisu Device Tree za pomocą następujących poleceń:

make ARCH=arm visionsom-6ull-linux_defconfig
make ARCH=arm menuconfig
make -j4 ARCH=arm zImage
make ARCH=arm somlabs-visionsom-6ull.dtb

Pliki wynikowe powyższych kompilacji, tj.:

arch/arm/boot/zImage
arch/arm/boot/dts/somlabs-visionsom-6ull.dtb

powinniśmy skopiować do katalogu /boot na karcie SD z obrazem systemu. Po podłączeniu wyświetlacza oraz kabla Ethernet płytka jest gotowa do dalszych działań.

Zanim przejdziemy do działań związanych bezpośrednio z dekodowaniem i wyświetlaniem obrazu z urządzenia mobilnego, należy rozwiązać problem „przechwycenia” takiego obrazu. Pierwszą z opcji jest wykorzystanie gotowych rozwiązań, np. w postaci standardu Miracast, wspieranego przez największych producentów urządzeń mobilnych. Niestety implementacja takich rozwiązań może być niezwykle czasochłonna i/lub wymagać odpowiednich certyfikatów. Alternatywnym rozwiązaniem jest przygotowanie własnej aplikacji dla systemu Android. Może ona wykorzystać udostępnione dla programistów programistów MediaProjection API umożliwiające przechwytywanie zawartości ekranu, a także odpowiednio skompresować i wysłać dane do komputera jednopłytkowego. Takie rozwiązanie, choć zapewniające pełną swobodę w wyborze kompresji obrazu czy protokołu komunikacji, wymaga od programisty pewnego doświadczenia z systemem Android oraz językami Java lub Kotlin.

Czy można ten problem rozwiązać znacznie prościej? Można, wykorzystując do tego celu narzędzie ADB (Android Debug Bridge), przeznaczone do komunikacji i zarządzania urządzeniami Android z poziomu komputera PC. Program ADB został udostępniony dla wszystkich najpopularniejszych systemów operacyjnych (Windows, Linux, macOS), jednak ze względu na swój konsolowy interfejs nie znajduje on zastosowania w powszechnym użytku. Oprócz szeregu funkcji związanych z kopiowaniem plików, instalacją pakietów APK czy odczytem logów systemowych, program ADB udostępnia również możliwość wykonania zrzutów oraz przechwycenia zawartości ekranu urządzenia mobilnego. Właśnie tą opcję wykorzystamy do realizacji postawionego zadania.

Instalacja i konfiguracja ADB

Instalacja pakietu ADB na module VisionSOM-6ULL z systemem Debian, sprowadza się wyłącznie do jednego wywołania narzędzia apt:

sudo apt install adb

Aby nawiązać komunikację z telefonem Android, niezbędne jest uprzednie odblokowanie na urządzeniu „Opcji programisty” oraz włączenie „Debugowania USB”. Włączenie opcji programisty można zrealizować poprzez siedmiokrotne kliknięcie opcji „Numer wersji” (lub „Numer kompilacji”) w Ustawieniach telefonu – rysunek 1.

Rys. 1. Odblokowanie „Opcji programisty” na urządzeniu mobilnym

Po odblokowaniu opcji programisty, włączeniu trybu debugowania oraz połączeniu telefonu z modułem VisionSOM-6ULL za pomocą kabla USB, możemy podjąć próbę sprawdzenia statusu połączenia pomiędzy urządzeniami. W tym celu w konsoli użytkownika wpisujemy polecenie adb devices. Wyświetli ono identyfikatory wszystkich podłączonych do komputera urządzeń z systemem Android. W przypadku wystąpienia problemów z nawiązaniem połączenia, warto sprawdzić komunikaty wyświetlane na ekranie telefonu. Mogą one wymagać potwierdzenia podpisu cyfrowego urządzenia lub udzielenia stosownych zezwoleń:

root@somlabs:~# adb devices
List of devices attached
ce091719631fe12f01         device

Do przechwycenia zawartości ekranu wykorzystamy polecenie adb shell screenrecord w postaci:

adb shell screenrecord --output-format=h264 --bit-rate 2M --size 800x480 -

Tym samym, strumień wyjściowy poddamy kompresji w formacie H.264. Przepływność danych ustawiono na wartość 2 Mbit/s (domyślna wartość 20 Mbit/s znacznie przekracza możliwości płynnej dekompresji obrazu), a rozdzielczość obrazu dopasowano do rozdzielczości podłączonego wyświetlacza. Ostatnim z argumentów polecenia jest nazwa pliku wyjściowego, do którego na bieżąco będzie zapisywany przechwytywany obraz. W przedstawionym przypadku ostatni argument ma wartość „-”, co oznacza, że strumień wyjściowy będzie bezpośrednio zapisywany na standardowe wyjście. Próba uruchomienia tak zdefiniowanego polecenia zakończy się wyłącznie wyświetleniem szeregu nieczytelnych znaków – uzyskane dane należy przekazac do odpowiedniego dekodera.

Dekodowanie wideo za pomocą GStreamer

Do zdekodowania strumienia wyjściowego wykorzystany zostanie pakiet GStreamer, którego kompleksowa instalacja w systemie może zostać zrealizowana za pomocą poleceń:

root@somlabs:~# apt-get install gstreamer1.0-x gstreamer1.0-tools
root@somlabs:~# apt-get install gstreamer1.0-plugins-good
root@somlabs:~# apt-get install gstreamer1.0-plugins-bad
root@somlabs:~# apt-get install gstreamer1.0-libav

Poprawność instalacji pakietów można przetestować komendą:

root@somlabs:~# gst-launch-1.0 videotestsrc ! fbdevsink

które wyświetli na dołączonym ekranie prosty wzór testowy – rysunek 2.

Rys. 2. Wyświetlenie wzoru testowego z wykorzystaniem funkcji GStreamer

Aby wspomóc procesor i.MX6ULL w operacjach związanych z grafiką i multimediami (wyświetlanie ekranu testowego z rysunku 2 realizowane jest w pełni programowo), niezbędne będzie zainstalowanie dodatkowych wtyczek dla pakietu GStreamer, dostarczanych i rozwijanych przez NXP. Zestaw wtyczek rozwijanych w ramach projektu gstreamer-imx, zawiera między innymi wsparcie dla sprzętowego modułu PXP (Pixel Processing Unit), wspomagającego operacje związane z przetwarzaniem obrazów 2D, konwersją przestrzeni kolorów, skalowaniem, itd. Zainstalujmy zatem w systemie pakiety i zależności niezbędne do poprawnej kompilacji projektu gstreamer-imx:

root@somlabs:~# apt-get install build-essential autoconf libtool
root@somlabs:~# apt-get install wget python pkg-config
root@somlabs:~# apt-get install libgstreamer1.0-dev
root@somlabs:~# apt-get install libgstreamer-plugins-base1.0-dev

Kolejny krok stanowi pobranie źródeł projektu:

root@somlabs:~# git clone git://github.com/Freescale/gstreamer-imx.git
Cloning into 'gstreamer-imx'...
remote: Counting objects: 4349, done.
remote: Total 4349 (delta 0), reused 0 (delta 0), pack-reused 4349
Receiving objects: 100% (4349/4349), 1.91 MiB | 1.35 MiB/s, done.
Resolving deltas: 100% (3129/3129), done.

Do kompilacji gstreamer-imx niezbędne jest również zainstalowanie w systemie plików nagłówkowych jądra Linux. Dla obrazu Debian Stretch udostępniono je w postaci pakietu DEB, wraz z opisanym na wstępie artykułu plikiem somlabs-visionsom-6ull-debian-rootfs-qemu.tar.xz:

root@somlabs:~# dpkg -i linux-headers-4.1.15_4.1.15-1_armhf.deb

Konfiguracja i kompilacja gstreamer-imx

Projekt gstreamer-imx wykorzystuje do procesu konfiguracji i kompilacji narzędzie Waf – pełny przebieg tego procesu przedstawiono poniżej:

root@somlabs:~# cd gstreamer-imx

root@somlabs:~/gstreamer-imx# ln -s /usr/lib/arm-linux-gnueabihf/gstreamer-1.0/ /usr/lib/gstreamer-1.0

root@somlabs:~/gstreamer-imx# ./waf configure --prefix=/usr --kernel-headers=/usr/src/linux-headers-4.1.15/include
Setting top to : /root/gstreamer-imx
Setting out to : /root/gstreamer-imx/build
Checking for 'gcc' (C compiler) : /usr/bin/gcc
Checking for compiler switch -O2 : yes
...
checking for linux/pxp_device.h : yes
PxP elements will be built
checking for linux/fb.h and the IPU header linux/ipu.h : yes
IPU elements will be built
Checking for 'libimxvpuapi >= 0.10.3' : not found
could not find installed imxvpuapi library - VPU elements will not be built
...
'configure' finished successfully (25.634s)

root@somlabs:~/gstreamer-imx# ./waf
Waf: Entering directory `/root/gstreamer-imx/build'
[ 1/35] Compiling src/common/canvas.c
[ 2/35] Compiling src/common/fd_object.c
[ 3/35] Compiling src/common/phys_mem_allocator.c
...
[34/35] Symlinking build/src/compositor/libgstimxcompositor.so
[35/35] Symlinking build/src/common/libgstimxcommon.so
Waf: Leaving directory `/root/gstreamer-imx/build'
'build' finished successfully (1m45.921s)

root@somlabs:~/gstreamer-imx# ./waf install
Waf: Entering directory `/root/gstreamer-imx/build'
+ install /usr/lib/libgstimxcommon.so.0.13.0
+ symlink /usr/lib/libgstimxcommon.so (to libgstimxcommon.so.0.13.0)
+ symlink /usr/lib/libgstimxcommon.so.0 (to libgstimxcommon.so.0.13.0)
+ install /usr/lib/pkgconfig/gstimxcommon.pc
...
Waf: Leaving directory `/root/gstreamer-imx/build'
'install' finished successfully (0.584s)

Po zakończonym procesie instalacji lista wtyczek dla projektu GStreamer powinna rozszerzyć się m. in. o wtyczkę imxpxpvideosink:

root@somlabs:~/gstreamer-imx# gst-inspect-1.0 imxpxpvideosink
Factory Details:
Rank                     primary + 1 (257)
Long-name                Freescale PxP video sink
Klass                    Sink/Video
Description              Video output using the Freescale PxP API
Author                   Carlos Rafael Giani <dv@pseudoterminal.org>
…

Element Properties:
name                : The name of the object
flags: readable, writable
String. Default: "imxpxpvideosink0"
parent              : The parent of the object
flags: readable, writable
Object of type "GstObject"

System wyposażono już w komplet narzędzi programowych. Poprawność działania wtyczek pakietu gstreamer-imx możemy w prosty sposób przetestować wyświetlając na ekranie fragment dowolnego filmu testowego (rysunek 3):

wget http://craftymind.com/factory/html5video/BigBuckBunny_640x360.mp4
gst-launch-1.0 filesrc location=BigBuckBunny_640x360.mp4 ! decodebin ! imxpxpvideosink use-vsync=true

Rys. 3. Wyświetlenie filmu testowego z wykorzystaniem wtyczki imxpxpvideosink

Aby zdekodować i wyświetlić na ekranie obraz generowany przez polecenie adb shell screenrecord, połączymy polecenia adb oraz gst-launch za pomocą operacji potoku „|”, a jako źródło strumienia wejściowego dla GStreamer’a, wskażemy standardowe wejście (fdsrc fd=0):

adb shell screenrecord --output-format=h264 --bit-rate 4M --size 800x480 - | gst-launch-1.0 fdsrc fd=0 ! decodebin ! imxpxpvideosink

Efekt działania powyższego polecenia przedstawiono na rysunku 4.

Rys. 4. Funkcja Screen Mirroring zbudowana z wykorzystaniem pakietów ADB oraz GStreamer

Przedstawiona powyżej metoda nie jest pozbawiona wad. Trzeba było obniżyć jakość przesyłanego obrazu ze względu na ograniczenia wynikające z dostępnych zasobów sprzętowych. Niemniej jednak pozwala ona na szybkie przesłanie zawartości ekranu telefonu do komputera z system Linux. Nie wymaga instalacji żadnego dodatkowego oprogramowania po stronie urządzenia mobilnego, a całość operacji jest realizowana za pomocą jednego polecenia. W przypadku większości dystrybucji systemu Linux, nie trzeba również instalować żadnego dodatkowego oprogramowania po stronie komputera (wspierany sprzętowo pakiet GStreamer jest instalowany domyślnie w większości dystrybucji), a zaprezentowana metoda może zostać również z powodzeniem wykorzystana na standardowych komputerach klasy PC z procesorami x86/x64.

Raspberry Pi – projekt scrcpy

Świat miłośników oprogramowania otwarto-źródłowego nie znosi pustki. Kwestią czasu było więc pojawienie się alternatywnych rozwiązań dla komercyjnego projektu Miracast czy niskopoziomowych rozwiązań jak to przedstawione powyżej. Jednym z takich otwartych projektów jest program scrcpy. Do realizacji zadania wykorzystuje on zarówno narzędzie ADB, jak i natywną aplikację dla systemu Android do przechwytywania i kompresji obrazu. Projekt ten dość intensywnie wykorzystuje funkcje dostarczane poprzez interfejs ADB, oferując tym samym nie tylko proste przesyłanie obrazu, ale jednocześnie obsługę wejścia (sterowanie telefonem z poziomu myszki i klawiatury na lustrzanej projekcji) czy instalację pakietów APK poprzez system Drag&Drop. Aplikacja jest dostępna dla systemów Windows, Linux oraz macOS. Nie jest jednak dostarczana w postaci gotowych pakietów dla platformy ARM – użytkownik musi samodzielnie wykonać kompilację kodu źródłowego.

Projekt scrcpy do dekodowania strumienia danych wykorzystuje biblioteki z projektu ffmpeg (libav), które na platformie i.MX6ULL nie posiada sprzętowego wsparcia. Całość obliczeń realizowania jest w sposób programowy, i jak przekonał się Autor, nie pozwala to uzyskać satysfakcjonujących wyników. Do kompilacji i uruchomienia projektu wykorzystamy więc komputer Raspberry Pi 4. Jego moc obliczeniowa jest w zupełności wystarcza do wygodnego korzystania z funkcji oferowanych przez scrcpy.

Przygotowanie platformy scrcpy

Po pobraniu i wgraniu na kartę SD obrazu systemu Raspberry Pi OS, proces przygotowania platformy rozpoczynamy od aktualizacji oprogramowania:

sudo apt-get update
sudo apt-get upgrade

Jak wspomniano, projekt scrcpy wykorzystuje funkcje oferowane przez narzędzie ADB, tak więc kolejny krok stanowi zainstalowanie brakujących pakietów oraz zależności niezbędnych do kompilacji programu:

sudo apt install adb meson libavformat-dev libsdl2-dev

Pobranie kodu źródłowego scrcpy za pomocą narzędzia git:

git clone https://github.com/Genymobile/scrcpy.git

Wraz z kodem źródłowym aplikacji dla systemów Windows i Linux, udostępniono również kod aplikacji dla systemu Android. Jej zadaniem jest przechwycenie, a także przesłanie obrazu. Aplikacja ta jest niezależna od architektury na jaką wykonujemy kompilację programu klienta. Deweloperzy umożliwili uproszczenie etapu konfiguracji i kompilacji projektu, poprzez udostępnienie gotowych plików APK:

cd scrcpy
wget https://github.com/Genymobile/scrcpy/releases/download/v1.14/scrcpy-server-v1.14

Aby wykorzystać pliki APK w procesie konfiguracji, za pomocą argumentu prebuilt_server, wskazujemy pobrany w uprzednim kroku plik dla systemu Android:

meson x --buildtype release --strip -Db_lto=true -Dprebuilt_server=scrcpy-server-v1.14

Kompilacja źródeł umieszczonych w folderze ‘x’:

ninja -C x

Zakończony proces kompilacji umożliwia nam bezpośrednie uruchomienie programu – bez potrzeby instalacji plików wynikowych:

./run x

Efekt uruchomienia aplikacji scrcpy przedstawiono na rysunku 5.

Rys. 5. Funkcja Screen Mirroring realizowana przez projekt scrcpy na platformie Raspberry Pi

Dodatkowo, program scrcpy dostarcza również szeregu opcji konfiguracyjnych związanych z ustawieniami rozdzielczości, przepływności, konfiguracją okna. Umożliwia również wygaszenie ekranu urządzenia mobilnego. Pełną listę opcji konfiguracyjnych uzyskamy po wydaniu polecenia:

./run x --help

Wykorzystując platformę Raspberry Pi warto również przetestować alternatywne rozwiązania. Są to modyfikacje metody wykorzystanej dla płytki VisionSOM-6ULL, polegające na podmienieniu pakietu GStreamer na wspierany sprzętowo odtwarzacz multimedialny omxplayer:

adb shell screenrecord --output-format=h264 --bit-rate 2M --size 800x480 - | omxplayer --no-keys -r pipe:0 -o hdmi
Łukasz Skalski - absolwent Politechniki Gdańskiej, miłośnik FLOSS, autor książki "Linux. Podstawy i aplikacje dla systemów embedded" oraz szeregu artykułów dotyczących programowania systemów wbudowanych. Zawodowo związany z firmą Samsung. Wszystkie wolne chwile poświęca projektowaniu i programowaniu urządzeń wyposażonych w mikroprocesory 8-/16- i 32-bitowe. Szczególnym zainteresowaniem obejmuje tematykę systemu Linux w aplikacjach na urządzenia embedded.