πŸ΄β€β˜ οΈ
Башка β˜•
Blog  Tags 
πŸ’€ πŸ”΅ πŸ”΄

πŸ“Ÿ Как ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ для Flipper Zero

ΠžΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Π½ΠΎ: 27 ΠΌΠ°Ρ€Ρ‚Π° 2023 Π³.

Π­Ρ‚ΠΎ руководство полная копия ΡΡ‚Π°Ρ‚ΡŒΠΈ с сайта amperka.ru.
Автор: Максим Π”Π°Π½ΠΈΠ»ΠΈΠ½. Написано: 25.01.2023 Π³ΠΎΠ΄Π°.

Как ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ для Flipper Zero

ΠŸΡ€ΠΈΠ²Π΅Ρ‚!

Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ разбСрёмся, ΠΊΠ°ΠΊ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΡΠΎΠ±ΡΡ‚Π²Π΅Π½Π½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ для Flipper Zero!

Π‘Π΅Ρ€Π΄Ρ†Π΅ΠΌ Π³Π°Π΄ΠΆΠ΅Ρ‚Π° Flipper Zero являСтся 32-Π±ΠΈΡ‚Π½Ρ‹ΠΉ ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€ STM32. ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π”Π΅Π»ΡŒΡ„ΠΈΠ½Π° сильно отличаСтся ΠΎΡ‚ программирования ΠΏΡ€ΠΈΠ²Ρ‹Ρ‡Π½Ρ‹Ρ… Π½Π°ΠΌ Arduino. Помимо самого ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π° Π²ΠΎ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅ Π΅ΡΡ‚ΡŒ Ρ€Π°Π΄ΠΈΠΎΠΌΠΎΠ΄ΡƒΠ»ΡŒ, NFC-ΠΌΠΎΠ΄ΡƒΠ»ΡŒ, ΠΊΠ°Ρ€Π΄Ρ€ΠΈΠ΄Π΅Ρ€, ΠΌΠΎΠ΄ΡƒΠ»ΡŒ Bluetooth, дисплСй, микросхСма управлСния подсвСткой ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅. Π­Ρ„Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ всСми этими устройствами Π² ΠΎΠ΄Π½ΠΎΠΌ Ρ†ΠΈΠΊΠ»Π΅ loop, ΠΊΠ°ΠΊ это ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ выглядит Π² срСдС Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Arduino, ΡƒΠΆΠ΅ нСльзя.

На ΠΏΠΎΠΌΠΎΡ‰ΡŒ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ опСрационная систСма Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ ΠΈΠ»ΠΈ RTOS (real-time operating system). RTOS Ρ€Π°Π·Π³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ логичСскиС части всСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π² Ρ€Π°Π·Π½Ρ‹Π΅ ΠΏΠΎΡ‚ΠΎΠΊΠΈ ΠΈ сама осущСствляСт ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρƒ Π½ΠΈΠΌΠΈ, Π° Ρ‚Π°ΠΊΠΆΠ΅ выдСляСт Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² рСсурсы.

Π’Π°ΠΊ ΠΊΠ°ΠΊ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€ построСн Π½Π° Ρ‡ΠΈΠΏΠ΅ STM32, Π² Π½Ρ‘ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ, Π½Π°Π²Π΅Ρ€Π½ΠΎΠ΅, самая популярная ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½ΠΊΠ° для этого Ρ‚ΠΈΠΏΠ° ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€ΠΎΠ² β€” FreeRTOS.

ΠœΡ‹ Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ Ρ€Π°Π·Π±ΠΈΡ€Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π° опСрационная систСма Π½Π° Flipper Zero, Π° Π»ΡƒΡ‡ΡˆΠ΅ сосрСдоточимся Π½Π° написании ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ.

Π­Ρ‚ΠΎ Π²Π°ΠΆΠ½ΠΎ! ΠŸΡ€ΠΎΠ΅ΠΊΡ‚ Flipper Zero Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎ развиваСтся, ΠΈ Π½Π° ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π²Ρ‹Ρ…ΠΎΠ΄Π° Π΄Π°Π½Π½ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠΈ ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΉ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ ΠΏΠΎ созданию собствСнных ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π½Π΅Ρ‚, Π° сам API ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ Π½Π΅ описан. Однако ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ построСния ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π²ΠΏΠΎΠ»Π½Π΅ понятСн Π² процСссС изучСния исходного ΠΊΠΎΠ΄Π° встроСнных Π² Π€Π»ΠΈΠΏΠΏΠ΅Ρ€ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ. Π’ΠΏΠΎΠ»Π½Π΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, Ρ‡Ρ‚ΠΎ со Π²Ρ€Π΅ΠΌΠ΅Π½Π΅ΠΌ API измСнится, ΠΈ ΠΊΠΎΠ΄ ΠΈΠ· этой ΡΡ‚Π°Ρ‚ΡŒΠΈ станСт Π½Π΅Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½Ρ‹ΠΌ. Π Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ Flipper Zero ΠΎΠ±Π΅Ρ‰Π°ΡŽΡ‚, Ρ‡Ρ‚ΠΎ докумСнтация появится, ΠΊΠΎΠ³Π΄Π° стабилизируСтся API. Π‘Ρ‚Π°Ρ‚ΡŒΡ Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½Π° для ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠΈ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π° 0.75.0.

ΠŸΡ€ΠΎΡˆΠΈΠ²ΠΊΡƒ ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ Π½Π° ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ°Ρ…:

  • Windows 10+ с PowerShell ΠΈ Git (Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° x86_64).
  • macOS 12+ с Command Line tools (Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° x86_64 ΠΈ arm64).
  • Ubuntu 20.04+ с build-essential ΠΈ Git (Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° x86_64).

Π£ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ macOS Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ со сборкой ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠΈ благодаря Homebrew. Ну Π° Ссли Π²Ρ‹ собираСтС ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΡƒ Π½Π° Windows ΠΈ ΡΡ‚ΠΎΠ»ΠΊΠ½ΡƒΠ»ΠΈΡΡŒ с трудностями, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ WSL.

ΠŸΠΈΡΠ°Ρ‚ΡŒ ΠΊΠΎΠ΄ для собствСнных ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π½Π° языкС программирования C Π½Π° Π½Π°ΡΡ‚ΠΎΠ»ΡŒΠ½ΠΎΠΌ ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π΅ ΠΏΠΎΠ΄ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ΠΌ Linux, Π° ΠΈΠΌΠ΅Π½Π½ΠΎ Ubuntu 22.04.1 LTS (Jammy Jellyfish).

Установка Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ³ΠΎ софта

ΠŸΠ΅Ρ€Π΅Π΄ Ρ‚Π΅ΠΌ ΠΊΠ°ΠΊ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Π½Π°ΠΌ придётся Π½Π°ΡƒΡ‡ΠΈΡ‚ΡŒΡΡ ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ всю ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΡƒ ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π°.

Π‘ΠΏΠ΅Ρ€Π²Π° скачаСм ΠΈ установим ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ qFlipper для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Π€Π»ΠΈΠΏΠΏΠ΅Ρ€ΠΎΠΌ Ρ‡Π΅Ρ€Π΅Π· графичСский интСрфСйс. ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ qFlipper для ΡƒΠ΄ΠΎΠ±Π½ΠΎΠΉ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Π½Π°ΡˆΠΈΡ… Π³ΠΎΡ‚ΠΎΠ²Ρ‹Ρ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π½Π° SD-ΠΊΠ°Ρ€Ρ‚Ρƒ Π²ΠΎ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅.

Π‘ΠΊΠ°Ρ‡ΠΈΠ²Π°Π΅ΠΌ Π²Π΅Ρ€ΡΠΈΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ для OS Linux ΠΊΡƒΠ΄Π°-Π½ΠΈΠ±ΡƒΠ΄ΡŒ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π² домашнюю Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ. На ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π²Ρ‹Ρ…ΠΎΠ΄Π° ΡΡ‚Π°Ρ‚ΡŒΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° qFlipper ΠΈΠΌΠ΅Π΅Ρ‚ Π²Π΅Ρ€ΡΠΈΡŽ 1.2.2, Π° сам Ρ„Π°ΠΉΠ» называСтся qFlipper-x86_64-1.2.2.AppImage. Π’Π°ΠΊΠΆΠ΅ установитС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡƒΡŽ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ libfuse2, Ссли Π΅Ρ‘ Π½Π΅Ρ‚ Π² вашСй систСмС.

wget https://update.flipperzero.one/builds/qFlipper/1.2.2/qFlipper-x86_64-1.2.2.AppImage
sudo apt install libfuse2

УстановитС Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ Π½Π° запуск qFlipper ΠΈ Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Π² систСму udev ΠΏΡ€Π°Π²ΠΈΠ»Π° доступа ΠΊ USB Serial-ΠΏΠΎΡ€Ρ‚Ρƒ для ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠ³ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ. Π˜Π½Π°Ρ‡Π΅ понадобится вСсти Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ ΠΎΡ‚ Π»ΠΈΡ†Π° ΡΡƒΠΏΠ΅Ρ€ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ, Ρ‡Ρ‚ΠΎ нСбСзопасно для всСй систСмы Π² случаС нСостороТности.

sudo chmod +x qFlipper-x86_64-1.2.2.AppImage
./qFlipper-x86_64-1.2.2.AppImage rules install

ЗапуститС qFlipper ΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ ваш Flipper Zero ΠΊ ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Ρƒ ΠΏΠΎ USB.

./qFlipper-x86_64-1.2.2.AppImage

Π£Π±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ ваш Π€Π»ΠΈΠΏΠΏΠ΅Ρ€ появился Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ qFlipper, всё Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΎ ΠΈ установлСна свСТая ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠ°.

Для быстрой ΠΈ ΡƒΠ΄ΠΎΠ±Π½ΠΎΠΉ установки Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ³ΠΎ софта понадобится диспСтчСр ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ² Homebrew.

УстановитС Homebrew:

sudo apt install curl
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

ПослС установки Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ окруТСния PATH, MANPATH для Homebrew.
Π­Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ, Π΄ΠΎΠ±Π°Π²ΠΈΠ² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΡƒΡŽ строку Π² Ρ„Π°ΠΉΠ»Π΅ .profile для вашСго ΡŽΠ·Π΅Ρ€Π°:

echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> /home/$USER/.profile

ΠŸΡ€ΠΎΡˆΠΈΠ²ΠΊΠ° для Flipper Zero хранится Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ flipperzero-firmware Π½Π° GitHub.

Π‘ΠΊΠ»ΠΎΠ½ΠΈΡ€ΡƒΠΉΡ‚Π΅ ΠΊ сСбС Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠΈ Flipper Zero со всСми модулями. Π Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ Π·Π°ΠΉΠΌΠ΅Ρ‚ Ρ‡ΡƒΡ‚ΡŒ большС 2 Π“Π‘ пространства.

git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git

УстановитС пСрСчислСнный Π² описании рСпозитория софт:

sudo apt update
sudo apt install openocd clang-format-13 dfu-util protobuf-compiler

ΠŸΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ рСпозитория ΠΈ установитС всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Homebrew:

cd flipperzero-firmware
brew bundle --verbose

Π“ΠΎΡ‚ΠΎΠ²ΠΎ! ΠŸΡ€ΠΎΡˆΠΈΠ²ΠΊΠ° для Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π°, ΠΊΠ°ΠΊ ΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ прилоТСния, ΡΠΎΠ±ΠΈΡ€Π°ΡŽΡ‚ΡΡ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ fbt (Flipper Build Tool). Для создания собствСнных ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π½Π΅Ρ‚ нСобходимости ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π· ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ всю ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΡƒ Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ, ΠΎΠ΄Π½Π°ΠΊΠΎ ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΌ запускС ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ fbt Π±ΡƒΠ΄ΡƒΡ‚ скачаны Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ gcc-arm Ρ‚ΡƒΠ»Ρ‡Π΅ΠΉΠ½Ρ‹.

Π‘ΠΎΠ±Π΅Ρ€ΠΈΡ‚Π΅ ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΡƒ:

./fbt

ВсС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ сборки ΠΈ Π±ΠΈΠ½Π°Ρ€Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΠΎΠΌΠ΅Ρ‰Π΅Π½Ρ‹ Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ ./dist.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 1. ΠŸΡ€ΠΎΡΡ‚Π΅ΠΉΡˆΠ΅Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅

Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΏΡ€ΠΎΡΡ‚Π΅ΠΉΡˆΠ΅Π΅ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΡƒΠ΅ΠΌΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.

ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ‚ΠΈΠΏΠ° FAP (Flipper Application Package). Π“ΠΎΡ‚ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ этого Ρ‚ΠΈΠΏΠ° прСдставляСт собой Ρ„Π°ΠΉΠ» Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π° .fap. По сути, .fap ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ β€” это исполняСмый Ρ„Π°ΠΉΠ» .elf с Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ встроСнными Π΄Π°Π½Π½Ρ‹ΠΌΠΈ.

ΠšΡΡ‚Π°Ρ‚ΠΈ! Π’Π΅ΡΡŒ исходный ΠΊΠΎΠ΄ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ ΠΈΠ· этой стати ΠΌΡ‹ Π²Ρ‹Π»ΠΎΠΆΠΈΠ»ΠΈ Π½Π° GitHub Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ flipperzero-examples.

ΠŸΡ€ΠΈ создании ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ прилоТСния ΠΏΠΎΠΌΠ΅Ρ‰Π°ΡŽΡ‚ΡΡ Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ°ΠΏΠΊΠΈ Π² ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎ ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°Π½Π½ΡƒΡŽ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ applications_user:

ΠŸΡ€ΠΈΠ΄ΡƒΠΌΠ°ΠΉΡ‚Π΅ имя для прилоТСния. ΠœΡ‹ Π½Π°Π·Π²Π°Π»ΠΈ нашС ΠΏΠ΅Ρ€Π²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ example_1, этим ΠΆΠ΅ ΠΈΠΌΠ΅Π½Π΅ΠΌ Π½Π°Π·Π²Π°Π»ΠΈ ΠΈ ΠΏΠ°ΠΏΠΊΡƒ. Π’ Π½Π΅Ρ‘ ΠΏΠΎΠΌΠ΅Ρ‰Π°ΡŽΡ‚ΡΡ всС Ρ„Π°ΠΉΠ»Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ относятся ΠΊ Π²Π°ΡˆΠ΅ΠΌΡƒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ: исходный ΠΊΠΎΠ΄, изобраТСния ΠΈ ΠΏΡ€ΠΎΡ‡Π΅Π΅.

Π’ ΠΏΠ°ΠΏΠΊΠ΅ example_1 создадим Ρ„Π°ΠΉΠ» исходного ΠΊΠΎΠ΄Π° Π½Π° языкС Π‘ β€” example_1_app.c. Π’ΠΎΡ‚ ΠΊΠ°ΠΊ выглядит ΠΊΠΎΠ΄ ΠΏΡ€ΠΎΡΡ‚Π΅ΠΉΡˆΠ΅Π³ΠΎ прилоТСния.

#include <furi.h>

int32_t example_1_app(void* p) {
    UNUSED(p);
    return 0;
}

ΠšΠΎΠ½Π²Π΅Π½Ρ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎ Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ Ρ‚ΠΎΡ‡ΠΊΠΎΠΉ Π²Ρ…ΠΎΠ΄Π° являСтся функция, которая ΠΈΠΌΠ΅Π΅Ρ‚ имя прилоТСния ΠΈ суффикс app. Π’ΠΎΡ‡ΠΊΠ° Π²Ρ…ΠΎΠ΄Π° Π² нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ β€” функция example_1_app. Главная функция Ρ‚Ρ€Π°Π΄ΠΈΡ†ΠΈΠΎΠ½Π½ΠΎ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΊΠΎΠ΄ ошибки числом Ρ‚ΠΈΠΏΠ° int32_t. Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹ΠΉ ноль сообщаСт ΠΎΠ± отсутствии ошибок.

ΠŸΡ€ΠΈ компиляции ΠΊΠΎΠ΄Π° для Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π° любой warning воспринимаСтся ΠΊΠ°ΠΊ ошибка. Π”Π°, ваш ΠΊΠΎΠ΄ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ Ρ‡ΠΈΡΡ‚Π΅Π½ΡŒΠΊΠΈΠΌ. ΠΠ΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‚ warning, поэтому для обозначСния Π½Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠ³ΠΎ указатСля p ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ макрос UNUSED. РСализация Π΄Π°Π½Π½ΠΎΠ³ΠΎ макроса описана Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ΅ furi.h. FURI Ρ€Π°ΡΡˆΠΈΡ„Ρ€ΠΎΠ²Ρ‹Π²Π°Π΅Ρ‚ΡΡ ΠΊΠ°ΠΊ Β«Flipper Universal Registry ImplementationΒ». Π­Ρ‚ΠΈΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΌ Ρ„Π°ΠΉΠ»ΠΎΠΌ ΠΌΡ‹, ΠΏΠΎ сути, ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Π²ce core API Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π°.

ΠΠ°ΡˆΠ΅ΠΌΡƒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ понадобится ΠΈΠΊΠΎΠ½ΠΊΠ°. Для ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΡ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ находятся Π½Π° самом Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅ Π² Ρ€Π°Π·Π΄Π΅Π»Π΅ Applications, Π² качСствС ΠΈΠΊΠΎΠ½ΠΎΠΊ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ изобраТСния PNG с Π³Π»ΡƒΠ±ΠΈΠ½ΠΎΠΉ Ρ†Π²Π΅Ρ‚Π° 1 Π±ΠΈΡ‚ (Ρ‡Ρ‘Ρ€Π½ΠΎ-Π±Π΅Π»Ρ‹Π΅) ΠΈ Ρ€Π°Π·ΠΌΠ΅Ρ€ΠΎΠΌ 10Γ—10 пиксСлСй.

Π Π°Π·Π΄Π΅Π» Apllications с ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΌΠΈ прилоТСниями:

МоТно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ΄Π½ΠΎ ΠΈΠ· ΡƒΠΆΠ΅ ΠΈΠΌΠ΅ΡŽΡ‰ΠΈΡ…ΡΡ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ, Π½ΠΎ всСгда Π»ΡƒΡ‡ΡˆΠ΅ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ своё. Π’ GIMP ΠΌΡ‹ нарисовали Π²ΠΎΡ‚ Ρ‚Π°ΠΊΠΎΠΉ смайл Π² Ρ‡Ρ‘Ρ€Π½Ρ‹Ρ… ΠΎΡ‡ΠΊΠ°Ρ…:

ΠΠ°Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ свою ΠΈΠΊΠΎΠ½ΠΊΡƒ ΠΌΠΎΠΆΠ½ΠΎ ΠΈ Π² Paint. Π€Π°ΠΉΠ» изобраТСния ΠΏΠΎΠΌΠ΅Ρ‰Π°Π΅ΠΌ Π² ΠΏΠ°ΠΏΠΊΡƒ нашСго прилоТСния example_1.

Помимо исходного ΠΊΠΎΠ΄Π° ΠΈ ΠΈΠΊΠΎΠ½ΠΊΠΈ Π½Π°ΠΌ Π½ΡƒΠΆΠ΅Π½ Ρ„Π°ΠΉΠ» манифСста прилоТСния β€” application.fam. Π­Ρ‚ΠΎΡ‚ Ρ„Π°ΠΉΠ» являСтся ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ. Наш манифСст прилоТСния ΠΈΠΌΠ΅Π΅Ρ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Π²ΠΈΠ΄:

App(
    appid="example_1",
    name="Example 1 application",
    apptype=FlipperAppType.EXTERNAL,
    entry_point="example_1_app",
    cdefines=["APP_EXAMPLE_1"],
    stack_size=1 * 1024,
    order=90,
    fap_icon="emoji_smile_icon_10x10px.png",
    fap_category="Misc",
)

РазбСрёмся, Π·Π° Ρ‡Ρ‚ΠΎ ΠΎΡ‚Π²Π΅Ρ‡Π°ΡŽΡ‚ Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹. ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ для всСх Π²ΠΈΠ΄ΠΎΠ² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ:

  • appid β€” строка, которая ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΊΠ°ΠΊ ID прилоТСния ΠΏΡ€ΠΈ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ сборки fbt, Π° Ρ‚Π°ΠΊΠΆΠ΅ для Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ зависимостСй ΠΈ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΠΎΠ². Π•ΡΡ‚ΡŒ смысл ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ здСсь нСпосрСдствСнно имя вашСго прилоТСния.
  • name β€” Ρ‡ΠΈΡ‚Π°Π±Π΅Π»ΡŒΠ½ΠΎΠ΅ имя прилоТСния, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒΡΡ Π² мСню ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅.
  • apptype β€” Ρ‚ΠΈΠΏ прилоТСния. Π‘ΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‚ Ρ€Π°Π·Π½Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ для тСстовых, систСмных, сСрвисных, Π°Ρ€Ρ…ΠΈΠ²Π½Ρ‹Ρ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ ΠΈ для ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Π² Π³Π»Π°Π²Π½ΠΎΠΌ мСню Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π°. Π’ ΠΊΠΎΠ½Ρ†Π΅ сборки нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Ρ‚ΠΈΠΏΠ° FAP. Для ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΎΠ³ΠΎ Ρ€ΠΎΠ΄Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Ρ‚ΠΈΠΏ EXTERNAL (FlipperAppType.EXTERNAL).
  • entry_point β€” Ρ‚ΠΎΡ‡ΠΊΠ° Π²Ρ…ΠΎΠ΄Π° прилоТСния. Имя Π³Π»Π°Π²Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, с выполнСния ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ начнётся Ρ€Π°Π±ΠΎΡ‚Π° вашСго прилоТСния. Если Π² качСствС Ρ‚ΠΎΡ‡ΠΊΠΈ Π²Ρ…ΠΎΠ΄Π° Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ C++, Ρ‚ΠΎ ΠΎΠ½Π° Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ ΠΎΠ±Ρ‘Ρ€Π½ΡƒΡ‚Π° Π² extern "C".
  • cdefines β€” прСпроцСссорноС глобальноС объявлСниС для Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ, ΠΊΠΎΠ³Π΄Π° Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΎ Π² Π°ΠΊΡ‚ΠΈΠ²Π½ΡƒΡŽ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ сборки.
  • stack_size β€” Ρ€Π°Π·ΠΌΠ΅Ρ€ стСка Π² Π±Π°ΠΉΡ‚Π°Ρ…, выдСляСмый для прилоТСния ΠΏΡ€ΠΈ Π΅Π³ΠΎ запускС. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ Π²Ρ‹Π΄Π΅Π»Π΅Π½ΠΈΠ΅ слишком малСнького стСка ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Ρ‚ ΠΊ сбою систСмы ΠΈΠ·-Π·Π° пСрСполнСния стСка, Π° Π²Ρ‹Π΄Π΅Π»Π΅Π½ΠΈΠ΅ слишком большого ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΡ‚ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹ΠΉ ΠΎΠ±ΡŠΡ‘ΠΌ heap-памяти для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π΄Π°Π½Π½Ρ‹Ρ… прилоТСниями.
  • order β€” порядок прилоТСния Π²Π½ΡƒΡ‚Ρ€ΠΈ своСй Π³Ρ€ΡƒΠΏΠΏΡ‹ ΠΏΡ€ΠΈ сортировкС записСй. Π§Π΅ΠΌ Π½ΠΈΠΆΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, Ρ‚Π΅ΠΌ Π²Ρ‹ΡˆΠ΅ ΠΏΠΎ списку окаТСтся вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.

ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ для Π²Π½Π΅ΡˆΠ½ΠΈΡ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Ρ‚ΠΈΠΏΠ° EXTERNAL:

  • fap_icon β€” ΠΏΡƒΡ‚ΡŒ ΠΈ имя PNG-изобраТСния Ρ€Π°Π·ΠΌΠ΅Ρ€ΠΎΠΌ 10Γ—10 пиксСлСй, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΊΠ°ΠΊ ΠΈΠΊΠΎΠ½ΠΊΠ°. Π—Π΄Π΅ΡΡŒ пишСм ΠΏΡƒΡ‚ΡŒ ΠΈ имя нашСй PNG-ΠΈΠΊΠΎΠ½ΠΊΠΈ.
  • fap_category β€” подкатСгория прилоТСния. ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅Ρ‚ ΠΏΡƒΡ‚ΡŒ .fap-Ρ„Π°ΠΉΠ»Π° Π² ΠΏΠ°ΠΏΠΊΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π² Ρ„Π°ΠΉΠ»ΠΎΠ²ΠΎΠΉ систСмС. ΠœΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ пустым. ΠœΡ‹ помСстили нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΡŽ Misc Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅.

Если всС Ρ„Π°ΠΉΠ»Ρ‹ Π½Π° мСстС, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒ сборку прилоТСния.

Π’ Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ Π² ΠΊΠΎΡ€Π½Π΅Π²ΡƒΡŽ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠΈ flipperzero-firmware. Π‘Π±ΠΎΡ€ΠΊΠ° осущСствляСтся ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ ./fbt fap_{APPID}, Π³Π΄Π΅ {APPID} β€” это ID, ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΉ Π² .fam-Ρ„Π°ΠΉΠ»Π΅ манифСста прилоТСния.

./fbt fap_example_1

Π‘Π±ΠΈΠ»Π΄ΠΈΡ‚ΡŒ всС ΠΈΠΌΠ΅ΡŽΡ‰ΠΈΠ΅ΡΡ Π² ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠ΅ прилоТСния FAP ΠΌΠΎΠΆΠ½ΠΎ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ ./fbt faps.

Π“ΠΎΡ‚ΠΎΠ²ΠΎΠ΅ FAP-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ находится Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ build Π² скрытой Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ .extapps. Наш Ρ„Π°ΠΉΠ» прилоТСния называСтся example_1.fap.

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ qFlipper, пСрСнСсём Ρ„Π°ΠΉΠ» прилоТСния Π½Π° SD-ΠΊΠ°Ρ€Ρ‚Ρƒ Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ /apps/Misc. Π€Π°ΠΉΠ» ΠΌΠΎΠΆΠ½ΠΎ пСрСнСсти ΠΌΡ‹ΡˆΠΊΠΎΠΉ прямо Π² ΠΎΠΊΠ½ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹.

ПослС послСднСго обновлСния всС прилоТСния FAP ΠΌΠΎΠΆΠ½ΠΎ ΡΠ±ΠΈΠ»Π΄ΠΈΡ‚ΡŒ ΠΈ пСрСнСсти Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€ ΠΎΠ΄Π½ΠΎΠΉ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ ΠΈΠ· консоли:

./fbt fap_deploy

Π“ΠΎΡ‚ΠΎΠ²ΠΎ! Π’Π΅ΠΏΠ΅Ρ€ΡŒ нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ появилось Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅ Π² Ρ€Π°Π·Π΄Π΅Π»Π΅ Misc:

Главная функция example_1_app() сСйчас пуста, поэтому ΠΏΡ€ΠΈ запускС прилоТСния ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° просто Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ свою Ρ€Π°Π±ΠΎΡ‚Ρƒ ΠΈ ΠΌΡ‹ Π½Π΅ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ Π½ΠΈΠΊΠ°ΠΊΠΈΡ… ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π½Π° экранС.

Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎ: https://youtu.be/qfpTYmIwJbA.

Как Π²ΠΈΠ΄Π½ΠΎ, вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ вовсС Π½Π΅ ΠΈΠΌΠ΅Ρ‚ΡŒ графичСского интСрфСйса ΠΈ ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ ΠΊΠ°ΠΊ Π±Ρ‹ Β«Π·Π° кулисами». Но Ρƒ нашСго Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π° Π΅ΡΡ‚ΡŒ экранчик, поэтому нСльзя Π½Π΅ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ графичСский интСрфСйс.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 2. ГрафичСский интСрфСйс

Π”ΠΎΠ±Π°Π²ΠΈΠΌ Π½Π°ΡˆΠ΅ΠΌΡƒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ графичСский интСрфСйс.

Π§Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΏΡƒΡ‚Π°Ρ‚ΡŒΡΡ ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΏΡƒΠ½ΠΊΡ‚Π°ΠΌΠΈ ΡΡ‚Π°Ρ‚ΡŒΠΈ, ΠΌΡ‹ сдСлаСм Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ с ΠΈΠΌΠ΅Π½Π΅ΠΌ example_2, Π½ΠΎ ΠΏΠΎ сути Π±ΡƒΠ΄Π΅ΠΌ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Ρ‚ΡŒ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.

НовоС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ помСстим Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ applications_user/example_2. БоотвСтствСнно, Ρ„Π°ΠΉΠ» с исходным ΠΊΠΎΠ΄ΠΎΠΌ прилоТСния ΠΈΠΌΠ΅Π΅Ρ‚ имя example_2_app.c.

Для создания графичСского интСрфСйса Π²Π°ΠΌ придётся Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Ρ€Π°ΡΡˆΠΈΡ€ΠΈΡ‚ΡŒ исходный ΠΊΠΎΠ΄ прилоТСния. Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ прилоТСния Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» example_2_app.h для описания Ρ‚ΠΈΠΏΠΎΠ² Π΄Π°Π½Π½Ρ‹Ρ…, структур ΠΈ ΠΏΡ€ΠΎΡ‚ΠΎΡ‚ΠΈΠΏΠΎΠ² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ.

Π’ΠΊΠ»ΡŽΡ‡ΠΈΠΌ ΡƒΠΆΠ΅ Π·Π½Π°ΠΊΠΎΠΌΡ‹ΠΉ Π½Π°ΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» ядра furi.h. Для графичСского интСрфСйса понадобится Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ gui/gui.h.

#pragma once

#include <furi.h>
#include <gui/gui.h>

struct Example2App {
    Gui* gui;
    ViewPort* view_port;
};

typedef struct Example2App Example2App;

Π’ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ ΠΌΡ‹ создали структуру Example2App, которая Π±ΡƒΠ΄Π΅Ρ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π½Π° всС Π²Π°ΠΆΠ½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ нашСго прилоТСния, ΠΈ Π²Π²Π΅Π»ΠΈ Π½ΠΎΠ²Ρ‹ΠΉ Ρ‚ΠΈΠΏ для этой структуры. Π’ структурС нашСго прилоТСния Π΅ΡΡ‚ΡŒ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π½Π° графичСский интСрфСйс Gui ΠΈ Π½Π° ViewPort. ViewPort β€” это структура, которая ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для отрисовки Π΅Π΄ΠΈΠ½ΠΈΡ‡Π½ΠΎΠ³ΠΎ ΠΏΠΎΠ»Π½ΠΎΠ³ΠΎ экрана. К Π½Π΅ΠΉ ΠΏΡ€ΠΈΠ²ΡΠ·Ρ‹Π²Π°ΡŽΡ‚ΡΡ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π½Π° callback-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ отрисовки графичСских ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π½Π° экранС ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… событий (Events), Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π½Π°ΠΆΠ°Ρ‚ΠΈΠ΅ клавиш.

Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ прилоТСния Π² Ρ„Π°ΠΉΠ»Π΅ example_2_app.c Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ выглядит Ρ‚Π°ΠΊ:

#include "example_2_app.h"

#include <furi.h>
#include <gui/gui.h>

Example2App* example_2_app_alloc() {
    Example2App* app = malloc(sizeof(Example2App));

    app->view_port = view_port_alloc();

    app->gui = furi_record_open(RECORD_GUI);
    gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen);

    return app;
}

void example_2_app_free(Example2App* app) {
    furi_assert(app);

    view_port_enabled_set(app->view_port, false);
    gui_remove_view_port(app->gui, app->view_port);
    view_port_free(app->view_port);

    furi_record_close(RECORD_GUI);
}

int32_t example_2_app(void *p) {
    UNUSED(p);
    Example2App* app = example_2_app_alloc();

    furi_delay_ms(10000);

    example_2_app_free(app);
    return 0;
}

РазбСрёмся, Ρ‡Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ Ρ‡Ρ‚ΠΎ. ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΠΎΠ΄ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€ ΠΎΡ‡Π΅Π½ΡŒ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΠΊ рСсурсам ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ систСмы, ΠΈ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π·Π° этим ΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ. Π­Ρ‚ΠΎ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Π»ΠΎ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ ΠΈ Π½Π΅ Π²Ρ‹Π·Ρ‹Π²Π°Π»ΠΎ зависаний ΠΈ глюков. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ, Ссли ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ интСрфСйс, Ρ‚ΠΎ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ выдСляСм ΠΏΠΎΠ΄ это ΠΏΠ°ΠΌΡΡ‚ΡŒ, Π° ΠΊΠΎΠ³Π΄Π° удаляСм β€” освобоТдаСм.

ΠžΠΏΠΈΡΡ‹Π²Π°Π΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π΄Π΅Π»ΡΡ‚ΡŒ ΠΏΠ°ΠΌΡΡ‚ΡŒ ΠΏΠΎΠ΄ структуру нашСго прилоТСния ΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ:

Example2App* example_2_app_alloc()

И Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая освобоТдаСт Π·Π°Π½ΡΡ‚ΡƒΡŽ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ ΠΏΠ°ΠΌΡΡ‚ΡŒ:

void example_2_app_free(Example2App* app)

Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ выдСлСния памяти ΠΌΡ‹ сначала выдСляСм ΠΏΠ°ΠΌΡΡ‚ΡŒ ΠΏΠΎΠ΄ структуру app Ρ‚ΠΈΠΏΠ° Example2App для нашСго прилоТСния. Π—Π°Ρ‚Π΅ΠΌ выдСляСм ΠΏΠ°ΠΌΡΡ‚ΡŒ для view_port:

app->view_port = view_port_alloc();

ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ Gui Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π° β€” gui. ΠŸΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚Ρ‹Π²Π°Π΅ΠΌ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Gui ΠΈ Π³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ систСмС, Ρ‡Ρ‚ΠΎ Ρƒ нашСго прилоТСния Π΅ΡΡ‚ΡŒ Π½Π΅ΠΊΠΈΠΉ интСрфСйс c отрисовкой экрана view_port ΠΈ ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Π΅Π³ΠΎ ΠΎΡ‚ΠΎΠ±Ρ€Π°Π·ΠΈΡ‚ΡŒ.

app->gui = furi_record_open(RECORD_GUI);
gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen);

Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ освобоТдСния памяти ΠΌΡ‹, соотвСтствСнно, Ρ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ Π² ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΌ Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠΈ. Π’Ρ‹ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Ρ€Π΅Π½Π΄Π΅Ρ€ нашСго view_port:

view_port_enabled_set(app->view_port, false);

ΠžΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ view_port ΠΎΡ‚ Gui ΠΈ освобоТдаСм ΠΏΠ°ΠΌΡΡ‚ΡŒ, Π·Π°Π½ΡΡ‚ΡƒΡŽ view_port:

gui_remove_view_port(app->gui, app->view_port);
view_port_free(app->view_port);

Π’ ΠΊΠΎΠ½Ρ†Π΅ ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘ΠΌ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ графичСским интСрфСйсом ΠΎΡ‚ нашСго прилоТСния ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ систСмС:

furi_record_close(RECORD_GUI);

Π’Π°ΠΊ ΠΊΠ°ΠΊ ΠΌΡ‹ пишСм Π½Π° Π‘ ΠΈ рСгулярно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ, Π² ядрС FURI сущСствуСт ΠΊΡ€Π°ΠΉΠ½Π΅ полСзная для нас функция furi_assert(), которая экстрСнно остановит Ρ€Π°Π±ΠΎΡ‚Ρƒ прилоТСния ΠΈ выдаст сообщСниС, Ссли ΠΌΡ‹ Π²Π΄Ρ€ΡƒΠ³ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΄ΠΈΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° пустой участок памяти.

Π’ΠΎΡ‡ΠΊΠΎΠΉ Π²Ρ…ΠΎΠ΄Π° прилоТСния Π½Π° этот Ρ€Π°Π· Π±ΡƒΠ΄Π΅Ρ‚ функция с ΠΈΠΌΠ΅Π½Π΅ΠΌ example_2_app:

int32_t example_2_app(void *p) {
    UNUSED(p);
    Example2App* app = example_2_app_alloc();

    furi_delay_ms(10000);

    example_2_app_free(app);
    return 0;
}

ΠŸΡ€ΠΈ запускС прилоТСния ΠΌΡ‹ Π°Π»Π»ΠΎΡ†ΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΠ°ΠΌΡΡ‚ΡŒ для структуры прилоТСния, ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚Ρ‹Π²Π°Π΅ΠΌ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Gui ΠΈ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠΌ наш ViewPort. ПослС этого ΠΌΡ‹ простаиваСм 10 сСкунд Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ furi_delay_ms(), освобоТдаСм всС занятыС рСсурсы, ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘ΠΌ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Gui ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ систСмС ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅ΠΌ Ρ€Π°Π±ΠΎΡ‚Ρƒ прилоТСния.

ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, Ρƒ нас получился Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΉ шаблон с Π²Ρ‹Π΄Π΅Π»Π΅Π½ΠΈΠ΅ΠΌ/освобоТдСниСм памяти для Π±ΡƒΠ΄ΡƒΡ‰ΠΈΡ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ.

Π˜ΠΊΠΎΠ½ΠΊΡƒ для прилоТСния оставляСм ΠΏΡ€Π΅ΠΆΠ½Π΅ΠΉ.

Вносим ΠΏΡ€Π°Π²ΠΊΠΈ Π² Ρ„Π°ΠΉΠ» манифСста прилоТСния application.fam. Π—Π΄Π΅ΡΡŒ всё остаётся ΠΏΡ€Π΅ΠΆΠ½ΠΈΠΌ, Π·Π° ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ΠΌ Π½ΠΎΠ²ΠΎΠ³ΠΎ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° requires. Π’ этом ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π΅ ΠΌΡ‹ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ Π½Π°ΡˆΠ΅ΠΌΡƒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ Π½ΡƒΠΆΠ΅Π½ сСрвис, ΠΎΡ‚Π²Π΅Ρ‡Π°ΡŽΡ‰ΠΈΠΉ Π·Π° графичСскиС интСрфСйсы gui.

App(
    appid="example_2",
    name="Example 2 application",
    apptype=FlipperAppType.EXTERNAL,
    entry_point="example_2_app",
    cdefines=["APP_EXAMPLE_2"],
    requires=[
        "gui",
    ],
    stack_size=1 * 1024,
    order=90,
    fap_icon="emoji_smile_icon_10x10px.png",
    fap_category="Misc",
)

Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅:

./fbt fap_example_2

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ qFlipper, пСрСнСсём Π½ΠΎΠ²ΠΎΠ΅ FAP-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ· ΠΏΠ°ΠΏΠΊΠΈ build Π½Π° SD-ΠΊΠ°Ρ€Ρ‚Ρƒ Π² ΠΏΠ°ΠΏΠΊΡƒ /apps/Misc. Или ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π» ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ ./fbt fap_deploy.

Находим Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² спискС ΠΈ запускаСм Π΅Π³ΠΎ:

БСйчас для нашСго ViewPort Π½Π΅ описаны ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ отрисовки графичСских ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ². ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° прилоТСния просто ΠΎΡ‚ΠΎΠ±Ρ€Π°Π·ΠΈΡ‚ пустой графичСский интСрфСйс Π² Ρ‚Π΅Ρ‡Π΅Π½ΠΈΠ΅ 10 сСкунд ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ.

Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎ: https://youtu.be/7LlnIKkdM8s.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 3. ВСкст ΠΈ изобраТСния

Π”ΠΎΠ±Π°Π²ΠΈΠΌ Π² интСрфСйс нашСго прилоТСния ΠΊΠ°ΠΊΠΈΠ΅-Π½ΠΈΠ±ΡƒΠ΄ΡŒ графичСскиС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹. НСкоторыС графичСскиС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ ΠΌΠΎΠ³ΡƒΡ‚ ΠΈΠΌΠ΅Ρ‚ΡŒ довольно ΡΠ»ΠΎΠΆΠ½ΡƒΡŽ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€: мСню, Π²Ρ‹ΠΏΠ°Π΄Π°ΡŽΡ‰ΠΈΠ΅ списки, Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹Π΅ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ‹, Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ Ρ„ΠΎΡ€ΠΌΡ‹ Π²Π²ΠΎΠ΄Π°. ΠœΡ‹ ΠΆΠ΅ Π½Π°Ρ‡Π½Ρ‘ΠΌ с простых ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ².

Π‘Π½ΠΎΠ²Π° создадим копию ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π³ΠΎ прилоТСния, Π½ΠΎ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΠΎΠ΄ ΠΈΠΌΠ΅Π½Π΅ΠΌ example_3.

Для Ρ€Π΅Π½Π΄Π΅Ρ€Π° графичСских ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² создадим Π² исходном Ρ„Π°ΠΉΠ»Π΅ example_3_app.c callback-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ отрисовки example_3_app_draw_callback:

static void example_3_app_draw_callback(Canvas* canvas, void* ctx) {
    UNUSED(ctx);
    canvas_clear(canvas);
}

Callback-функция ΠΈΠΌΠ΅Π΅Ρ‚ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΡƒΡŽ сигнатуру ΠΈ Π΄Π²Π° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π° canvas, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ «холст», Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ, ΠΈ контСкст ctx. ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ΠΎΠΌ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Π΅, Π² зависимости ΠΎΡ‚ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… рСндСрится canvas. Пока Ρ‡Ρ‚ΠΎ ΠΌΡ‹ оставим контСкст Π½Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Π½Ρ‹ΠΌ, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ UNUSED.

ΠŸΠ΅Ρ€Π²Ρ‹ΠΌ Π΄Π΅Π»ΠΎΠΌ ΠΏΠ΅Ρ€Π΅Π΄ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΎΠΌ очистим наш экран:

canvas_clear(canvas);

ГрафичСскиС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ Ρ€Π°Π·ΠΌΠ΅Ρ‰Π°ΡŽΡ‚ΡΡ Π½Π° экранС согласно систСмС ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚. Π­ΠΊΡ€Π°Π½ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π° ΠΈΠΌΠ΅Π΅Ρ‚ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ 128Γ—64, Π° Π½Π°Ρ‡Π°Π»ΠΎ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ находится Π² Π»Π΅Π²ΠΎΠΌ Π²Π΅Ρ€Ρ…Π½Π΅ΠΌ ΡƒΠ³Π»Ρƒ:

Π”ΠΎΠ±Π°Π²ΠΈΠΌ тСкст Π² интСрфСйс нашСго прилоТСния.

ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» с графичСскими тСкстовыми элСмСнтами gui/elements.h. ВСкст отрисовываСтся Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ canvas_draw_str() с ΡƒΠΊΠ°Π·Π°Π½ΠΈΠ΅ΠΌ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ (x ΠΈ y) исходной Ρ‚ΠΎΡ‡ΠΊΠΈ тСкста ΠΈ, собствСнно, самой строки. Π’ΠΎΠ·ΠΌΠΎΠΆΠ΅Π½ Π²Ρ‹Π±ΠΎΡ€ ΡˆΡ€ΠΈΡ„Ρ‚Π° для тСкста. Π¨Ρ€ΠΈΡ„Ρ‚ устанавливаСтся Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ canvas_set_font(). Π¨Ρ€ΠΈΡ„Ρ‚ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π³Π»Π°Π²Π½Ρ‹ΠΌ β€” FontPrimary (высота 8 пиксСлСй), второстСпСнным β€” FontSecondary (высота 7 пиксСлСй), FontKeyboard ΠΈΠ»ΠΈ FontBigNumbers. ΠŸΡ€ΠΈ ΠΆΠ΅Π»Π°Π½ΠΈΠΈ Π²Ρ‹ смоТСтС ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΈ собствСнный ΡˆΡ€ΠΈΡ„Ρ‚.

НапримСр, напишСм Π³Π»Π°Π²Π½Ρ‹ΠΌ ΡˆΡ€ΠΈΡ„Ρ‚ΠΎΠΌ строку Β«This is an example app!Β» Π²Π²Π΅Ρ€Ρ…Ρƒ экрана ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ ΠΏΠΎ Ρ†Π΅Π½Ρ‚Ρ€Ρƒ, ΠΏΠΎ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π°ΠΌ (4 ΠΈ 8). По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π½Π°Ρ‡Π°Π»ΠΎ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ тСкста находится Π² Π»Π΅Π²ΠΎΠΌ Π½ΠΈΠΆΠ½Π΅ΠΌ ΡƒΠ³Π»Ρƒ.

canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 4, 8, "This is an example app!");

Π’ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ gui/elements.h ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ для отрисовки простых элСмСнтов, скроллбаров, ΠΊΠ½ΠΎΠΏΠΎΠΊ ΠΈΠ»ΠΈ выравнивания тСкста.

НапримСр, снизу ΠΎΡ‚ нашСй ΠΏΠ΅Ρ€Π²ΠΎΠΉ надписи размСстим Π΄Π»ΠΈΠ½Π½Ρ‹ΠΉ двухстрочный тСкст Β«Some long long long long aligned multiline textΒ», написанный второстСпСнным ΡˆΡ€ΠΈΡ„Ρ‚ΠΎΠΌ ΠΈ автоматичСски Π²Ρ‹Ρ€ΠΎΠ²Π½Π΅Π½Π½Ρ‹ΠΉ ΠΏΠΎ Π²Π΅Ρ€Ρ…Π½Π΅ΠΉ ΠΈ ΠΏΡ€Π°Π²ΠΎΠΉ Π³Ρ€Π°Π½ΠΈΡ†Π°ΠΌ. Для этого Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡΡ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ elements_multiline_text_aligned():

canvas_set_font(canvas, FontSecondary);
elements_multiline_text_aligned(canvas, 127, 15, AlignRight, AlignTop, "Some long long long long \n aligned multiline text");

Π’Π΅ΠΏΠ΅Ρ€ΡŒ разбСрёмся, ΠΊΠ°ΠΊ вывСсти Π½Π° экран ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΡƒ.

Для экспСримСнта ΠΌΡ‹ нарисовали Ρ‡Ρ‘Ρ€Π½ΠΎ-Π±Π΅Π»Ρ‹ΠΉ Π»ΠΎΠ³ΠΎΡ‚ΠΈΠΏ АмпСрки Π² PNG Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ΠΌ Π² 128Γ—35 пиксСлСй:

Π’ ΠΏΠ°ΠΏΠΊΠ΅ с вашим ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ создайтС ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΡƒΡŽ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ для хранСния ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ. НапримСр, ΠΌΡ‹ Π½Π°Π·Π²Π°Π»ΠΈ свою ΠΏΠ°ΠΏΠΊΡƒ images. Π’ Π΄Π°Π½Π½ΡƒΡŽ ΠΏΠ°ΠΏΠΊΡƒ помСститС всС изобраТСния, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠ»Π°Π½ΠΈΡ€ΡƒΠ΅Ρ‚Π΅ Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ΡŒ Π½Π° экран. ΠœΡ‹ Π½Π°Π·Π²Π°Π»ΠΈ Π½Π°ΡˆΡƒ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΡƒ amperka_ru_logo_128x35px.png ΠΈ помСстили Π΅Ρ‘ Π² ΡΠΎΠ·Π΄Π°Π½Π½ΡƒΡŽ ΠΏΠ°ΠΏΠΊΡƒ images:

Π’ манифСстС прилоТСния application.fam добавляСм Π½ΠΎΠ²Ρ‹ΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ fap_icon_assets с ΠΏΡƒΡ‚Ρ‘ΠΌ Π΄ΠΎ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ с изобраТСниями:

App(
    appid="example_3",
    name="Example 3 application",
    apptype=FlipperAppType.EXTERNAL,
    entry_point="example_3_app",
    cdefines=["APP_EXAMPLE_3"],
    requires=[
        "gui",
    ],
    stack_size=1 * 1024,
    order=90,
    fap_icon="emoji_smile_icon_10x10px.png",
    fap_category="Misc",
    fap_icon_assets="images",
)

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΡ€ΠΈ сборкС прилоТСния всС изобраТСния ΠΈΠ· ΠΏΠ°ΠΏΠΊΠΈ images Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΠ΅Ρ€Π΅Π²Π΅Π΄Π΅Π½Ρ‹ Π² ΠΊΠΎΠ΄, Π° сам ΠΊΠΎΠ΄ Π±ΡƒΠ΄Π΅Ρ‚ сгСнСрирован Π² ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ с ΠΈΠΌΠ΅Π½Π΅ΠΌ {APPID}_icons.h, Π³Π΄Π΅ {APPID} β€” это ID, ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΉ Π² .fam-Ρ„Π°ΠΉΠ»Π΅ манифСста прилоТСния.

НашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠΌΠ΅Π΅Ρ‚ ID example_3, Π·Π½Π°Ρ‡ΠΈΡ‚ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ имя example_3_icons.h. Π”ΠΎΠ±Π°Π²ΠΈΠΌ Π΄Π°Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ прилоТСния:

#include "example_3_icons.h"

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° ΠΎΠ±Π»Π°ΡΡ‚ΡŒ памяти, Π³Π΄Π΅ хранится нашС ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π² Π²ΠΈΠ΄Π΅ массива Π±Π°ΠΉΡ‚ΠΎΠ². Имя указатСля Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΠΌΠ΅Π½ΠΈ самого Ρ„Π°ΠΉΠ»Π° изобраТСния, Π½ΠΎ с приставкой I_ИМЯ_Π’ΠΠ¨Π•Π“Πž_ЀАЙЛА. Для нашСй ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠΈ с ΠΈΠΌΠ΅Π½Π΅ΠΌ amperka_ru_logo_128x35px.png имя указатСля Π±ΡƒΠ΄Π΅Ρ‚ I_amperka_ru_logo_128x35px.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ, имСя адрСс изобраТСния, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΡ‚Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ‚ΡŒ Π΅Π³ΠΎ Π½Π° экранС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ canvas_draw_icon(). Π’Ρ‹Π²Π΅Π΄Π΅ΠΌ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π²Π½ΠΈΠ·Ρƒ экрана ΠΏΠΎ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π°ΠΌ (0 ΠΈ 29):

canvas_draw_icon(canvas, 0, 29, &I_amperka_ru_logo_128x35px);

Пока Ρ‡Ρ‚ΠΎ Ρ…Π²Π°Ρ‚ΠΈΡ‚ графичСских элСмСнтов. Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

Наша callback-функция отрисовки Π³ΠΎΡ‚ΠΎΠ²Π°, ΠΈ Π΅Ρ‘ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΡ€ΠΈΠ²ΡΠ·Π°Ρ‚ΡŒ ΠΊ структурС ViewPort нашСго прилоТСния. Π­Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ нашСго прилоТСния сразу послС выдСлСния памяти ΠΏΠΎΠ΄ ViewPort. Π’ качСствС контСкста ΠΌΡ‹ Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ отправляСм (NULL). ПослС привязки ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ Ρ€Π°Π· callback-функция Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π° автоматичСски.

view_port_draw_callback_set(app->view_port, example_3_app_draw_callback, NULL);

Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» нашСго Ρ‚Ρ€Π΅Ρ‚ΡŒΠ΅Π³ΠΎ прилоТСния Π½Π΅ измСнился, Π·Π° ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ΠΌ ΠΈΠΌΠ΅Π½ΠΈ прилоТСния ΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌΠΎΠ³ΠΎ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ° с изобраТСниями.

Код example_3_app.h:

#pragma once

#include <furi.h>
#include <gui/gui.h>

#include "example_3_icons.h"

struct Example3App {
    Gui* gui;
    ViewPort* view_port;
};

typedef struct Example3App Example3App;

Код example_3_app.с:

#include "example_3_app.h"

#include <furi.h>
#include <gui/gui.h>

#include <gui/elements.h>

static void example_3_app_draw_callback(Canvas* canvas, void* ctx) {
    UNUSED(ctx);

    canvas_clear(canvas);

    canvas_draw_icon(canvas, 0, 29, &I_amperka_ru_logo_128x35px);

    canvas_set_font(canvas, FontPrimary);
    canvas_draw_str(canvas, 4, 8, "This is an example app!");

    canvas_set_font(canvas, FontSecondary);
    elements_multiline_text_aligned(canvas, 127, 15, AlignRight, AlignTop, "Some long long long long \n aligned multiline text");
}

Example3App* example_3_app_alloc() {
    Example3App* app = malloc(sizeof(Example3App));

    app->view_port = view_port_alloc();

    view_port_draw_callback_set(app->view_port, example_3_app_draw_callback, NULL);

    app->gui = furi_record_open(RECORD_GUI);
    gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen);

    return app;
}

void example_3_app_free(Example3App* app) {
    furi_assert(app);

    view_port_enabled_set(app->view_port, false);
    gui_remove_view_port(app->gui, app->view_port);
    view_port_free(app->view_port);

    furi_record_close(RECORD_GUI);
}

int32_t example_3_app(void *p) {
    UNUSED(p);
    Example3App* app = example_3_app_alloc();

    furi_delay_ms(10000);

    example_3_app_free(app);
    return 0;
}

Π“Π»Π°Π²Π½ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ прилоТСния example_3_app оставляСм ΠΊΠ°ΠΊ Π΅ΡΡ‚ΡŒ. ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ снова ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ 10 сСкунд ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ свою Ρ€Π°Π±ΠΎΡ‚Ρƒ, Π½ΠΎ Π½Π° этот Ρ€Π°Π· Ρƒ нас Π±ΡƒΠ΄Π΅Ρ‚ Π³Ρ€Π°Ρ„ΠΈΠΊΠ°.

Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅:

./fbt fap_example_3

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ qFlipper, пСрСнСсём Π½ΠΎΠ²ΠΎΠ΅ FAP-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ· ΠΏΠ°ΠΏΠΊΠΈ build Π½Π° SD-ΠΊΠ°Ρ€Ρ‚Ρƒ Π² ΠΏΠ°ΠΏΠΊΡƒ /apps/Misc. Или ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π» ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ ./fbt fap_deploy.

Находим Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² спискС ΠΈ запускаСм Π΅Π³ΠΎ:

Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎ: https://youtu.be/RNyTfBK4074.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 4. Кнопки

РазбСрёмся, ΠΊΠ°ΠΊ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ наТатия ΠΊΠ½ΠΎΠΏΠΎΠΊ Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅.

ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Π΅ΠΌ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ΄ Π½ΠΎΠ²Ρ‹ΠΌ ΠΈΠΌΠ΅Π½Π΅ΠΌ example_4.

Для использования ΠΊΠ½ΠΎΠΏΠΎΠΊ Π½Π°ΠΌ понадобится ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ сообщСний (MessageQueue) ΠΈ Π΅Ρ‰Ρ‘ ΠΎΠ΄Π½Π° callback-функция для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ этой ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ.

Π—Π°Ρ‡Π΅ΠΌ Π½ΡƒΠΆΠ½Π° ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ сообщСний? ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Π·Π° нас Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ опСрационная систСма, Ρ‚ΠΎ callback-функция Π²Π²ΠΎΠ΄Π° с ΠΊΠ½ΠΎΠΏΠΎΠΊ, ΠΊΠ°ΠΊ ΠΈ callback-функция Ρ€Π΅Π½Π΄Π΅Ρ€Π° Π³Ρ€Π°Ρ„ΠΈΠΊΠΈ выполняСтся Π² контСкстС Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² ОБ Flipper Zero, Π° Π½Π΅ Π² ΠΏΠΎΡ‚ΠΎΠΊΠ΅ нашСго прилоТСния. ΠŸΠΎΡ‚ΠΎΠΊ, ΠΎΡ‚Π²Π΅Ρ‡Π°ΡŽΡ‰ΠΈΠΉ Π·Π° Π½Π°ΠΆΠ°Ρ‚ΠΈΠ΅ ΠΊΠ½ΠΎΠΏΠΎΠΊ, Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ ΠΊΠ°ΠΊΡƒΡŽ-Π»ΠΈΠ±ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ ΠΈΠ· нашСго прилоТСния. Но ΠΏΠΎΡ‚ΠΎΠΊΠΈ ΠΌΠΎΠ³ΡƒΡ‚ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ Π΄Ρ€ΡƒΠ³ Π΄Ρ€ΡƒΠ³Ρƒ сообщСния Π² любой ΠΌΠΎΠΌΠ΅Π½Ρ‚ выполнСния, этим ΠΌΡ‹ ΠΈ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡΡ.

ДобавляСм Π² структуру нашСго прилоТСния Example4App ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ event_queue Ρ‚ΠΈΠΏΠ° FuriMessageQueue:

struct Example4App {
    Gui* gui;
    ViewPort* view_port;
    FuriMessageQueue* event_queue;
};

Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ прилоТСния example_4_app_alloc() выдСляСм ΠΏΠ°ΠΌΡΡ‚ΡŒ ΠΏΠΎΠ΄ Π½ΠΎΠ²ΡƒΡŽ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ.

app->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));

Наша ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ Π±ΡƒΠ΄Π΅Ρ‚ Π½Π° 8 сообщСний Ρ‚ΠΈΠΏΠ° InputEvent, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ Π·Π° Π½Π°ΠΆΠ°Ρ‚ΠΈΠ΅ клавиш. Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с сообщСниями ΠΎΡ‚ ΠΊΠ½ΠΎΠΏΠΎΠΊ находятся Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ input/input.h.

Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ освобоТдСния памяти нашСго прилоТСния, соотвСтствСнно, освобоТдаСм Π·Π°Π½ΡΡ‚ΡƒΡŽ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒΡŽ ΠΏΠ°ΠΌΡΡ‚ΡŒ.

furi_message_queue_free(app->event_queue);

Π’Π΅ΠΏΠ΅Ρ€ΡŒ создадим callback-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ этой ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ.

static void example_4_app_input_callback(InputEvent* input_event, void* ctx) {
    furi_assert(ctx);

    FuriMessageQueue* event_queue = ctx;
    furi_message_queue_put(event_queue, input_event, FuriWaitForever);
}

Как ΠΈ Π² случаС с callback-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ отрисовки, эта ΠΈΠΌΠ΅Π΅Ρ‚ Π΄Π²Π° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°: input_event ΠΈ контСкст ctx. Π‘ΠΎΠ±Ρ‹Ρ‚ΠΈΠ΅ input_event сигнализируСт ΠΎ ΠΊΠ°ΠΊΠΎΠΌ-Π»ΠΈΠ±ΠΎ взаимодСйствии с ΠΊΠ½ΠΎΠΏΠΊΠ°ΠΌΠΈ. Π’ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ отрисовки, Π² этот Ρ€Π°Π· контСкст Π½Π΅ пустой. ΠœΡ‹ ΠΏΠΎΠ»ΠΎΠΆΠΈΠ»ΠΈ Π² контСкст ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ сообщСний нашСго прилоТСния. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½Ρ‹Π΅ события Π²Π²ΠΎΠ΄Π° с ΠΊΠ½ΠΎΠΏΠΎΠΊ окаТутся Π² ΠΏΠΎΡ‚ΠΎΠΊΠ΅ нашСго прилоТСния.

ΠŸΡ€ΠΈΠ²ΡΠ·Ρ‹Π²Π°Π΅ΠΌ Π½ΠΎΠ²ΡƒΡŽ callback-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΊ графичСскому интСрфСйсу ViewPort нашСго прилоТСния. Π’ качСствС контСкста ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ сообщСний прилоТСния event_queue:

view_port_input_callback_set(app->view_port, example_4_app_input_callback, app->event_queue);

Π“ΠΎΡ‚ΠΎΠ²ΠΎ! Π’Π΅ΠΏΠ΅Ρ€ΡŒ информация ΠΎ состоянии ΠΊΠ½ΠΎΠΏΠΎΠΊ находится Π² нашСм распоряТСнии, ΠΈ Π΅Ρ‘ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ.

БСйчас нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ 10 сСкунд, Π° Π·Π°Ρ‚Π΅ΠΌ Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ. Π”Π°Π²Π°ΠΉΡ‚Π΅ сдСлаСм Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π·Π°ΠΊΡ€Ρ‹Π²Π°Π»ΠΎΡΡŒ Π½Π΅ автоматичСски, Π° ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ Π½Π° ΠΊΠ»Π°Π²ΠΈΡˆΡƒ «Назад» Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅.

ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ сообщСний ΠΈΠ· ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ напишСм Π² Π³Π»Π°Π²Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ нашСго прилоТСния (Ρ‚ΠΎΡ‡ΠΊΠ΅ Π²Ρ…ΠΎΠ΄Π°) Π² бСсконСчном Ρ†ΠΈΠΊΠ»Π΅:

while (1) {
    if (furi_message_queue_get(app->event_queue, &event, 100) == FuriStatusOk) {
        if (event.type == InputTypePress) {
            if (event.key == InputKeyBack)
                break;
        }
    }
}

Пока ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ пуста, крутимся Π² бСсконСчном Ρ†ΠΈΠΊΠ»Π΅. Если Π² нашСй ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ Π΅ΡΡ‚ΡŒ событиС (FuriStatusOk), наТалась ΠΊΠ½ΠΎΠΏΠΊΠ° (InputTypePress), ΠΈ это Π±Ρ‹Π»Π° ΠΊΠ½ΠΎΠΏΠΊΠ° «Назад» (InputKeyBack), Ρ‚ΠΎ Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ ΠΈΠ· Ρ†ΠΈΠΊΠ»Π° ΠΈ, ΠΊΠ°ΠΊ слСдствиС, двиТСмся ΠΊ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡŽ Ρ€Π°Π±ΠΎΡ‚Ρ‹ прилоТСния.

Код example_4_app.h:

#pragma once

#include <furi.h>
#include <gui/gui.h>

#include "example_4_icons.h"

struct Example4App {
    Gui* gui;
    ViewPort* view_port;
    FuriMessageQueue* event_queue;
};

typedef struct Example4App Example4App;

Код example_4_app.с:

#include "example_4_app.h"

#include <furi.h>
#include <gui/gui.h>
#include <gui/elements.h>

#include <input/input.h>

static void example_4_app_draw_callback(Canvas* canvas, void* ctx) {
    UNUSED(ctx);

    canvas_clear(canvas);

    canvas_draw_icon(canvas, 0, 29, &I_amperka_ru_logo_128x35px);

    canvas_set_font(canvas, FontPrimary);
    canvas_draw_str(canvas, 4, 8, "This is an example app!");

    canvas_set_font(canvas, FontSecondary);
    elements_multiline_text_aligned(canvas, 127, 15, AlignRight, AlignTop, "Some long long long long \n aligned multiline text");
}

static void example_4_app_input_callback(InputEvent* input_event, void* ctx) {
    furi_assert(ctx);

    FuriMessageQueue* event_queue = ctx;
    furi_message_queue_put(event_queue, input_event, FuriWaitForever);
}

Example4App* example_4_app_alloc() {
    Example4App* app = malloc(sizeof(Example4App));

    app->view_port = view_port_alloc();
    app->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));

    view_port_draw_callback_set(app->view_port, example_4_app_draw_callback, NULL);
    view_port_input_callback_set(app->view_port, example_4_app_input_callback, app->event_queue);

    app->gui = furi_record_open(RECORD_GUI);
    gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen);

    return app;
}

void example_4_app_free(Example4App* app) {
    furi_assert(app);

    view_port_enabled_set(app->view_port, false);
    gui_remove_view_port(app->gui, app->view_port);
    view_port_free(app->view_port);

    furi_message_queue_free(app->event_queue);

    furi_record_close(RECORD_GUI);
}

int32_t example_4_app(void *p) {
    UNUSED(p);
    Example4App* app = example_4_app_alloc();

    InputEvent event;

    while (1) {
        if (furi_message_queue_get(app->event_queue, &event, 100) == FuriStatusOk) {
            if (event.type == InputTypePress) {
                if (event.key == InputKeyBack)
                    break;
            }
        }
    }

    example_4_app_free(app);
    return 0;
}

Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ пСрСносим Π΅Π³ΠΎ Π½Π° Flipper Zero.

./fbt fap_example_4
./fbt fap_deploy

Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎ: https://youtu.be/PlClOH5_yB0.

ИзмСним нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π΅Ρ‰Ρ‘ ΠΏΠ°Ρ€Ρƒ ΠΊΠ½ΠΎΠΏΠΎΠΊ.

НапримСр, Π±ΡƒΠ΄Π΅ΠΌ ΠΏΠΎ-Ρ€Π°Π·Π½ΠΎΠΌΡƒ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ‚ΡŒ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π½Π° экранС Π² зависимости ΠΎΡ‚ Π½Π°ΠΆΠ°Ρ‚ΠΎΠΉ ΠΊΠ½ΠΎΠΏΠΊΠΈ.

ΠŸΡƒΡΡ‚ΡŒ Ρƒ нас Π±ΡƒΠ΄Π΅Ρ‚ Ρ‚Ρ€ΠΈ состояния интСрфСйса: рСндСрится Ρ‚ΠΎΠ»ΡŒΠΊΠΎ тСкст, рСндСрится Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅, Π»ΠΈΠ±ΠΎ рСндСрится ΠΈ Ρ‚ΠΎ, ΠΈ Π΄Ρ€ΡƒΠ³ΠΎΠ΅. ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒΡΡ ΠΌΠ΅ΠΆΠ΄Ρƒ этими Ρ€Π΅ΠΆΠΈΠΌΠ°ΠΌΠΈ Π±ΡƒΠ΄Π΅ΠΌ ΠΏΡ€ΠΈ Π΄ΠΎΠ»Π³ΠΎΠΌ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ Π½Π° ΠΊΠ½ΠΎΠΏΠΊΠΈ Β«Π’Π»Π΅Π²ΠΎΒ» ΠΈΠ»ΠΈ Β«Π’ΠΏΡ€Π°Π²ΠΎΒ».

Π’Π²Π΅Π΄Ρ‘ΠΌ Π² структуру нашСго прилоТСния ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ, которая Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚Π²Π΅Ρ‡Π°Ρ‚ΡŒ Π·Π° Ρ‚ΠΎ, ΠΊΠ°ΠΊΠΎΠΉ Ρ€Π΅ΠΆΠΈΠΌ рСндСрится Π² Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚. НазовСм Π΅Ρ‘ draw_mode.

typedef enum {
    DRAW_ALL,
    DRAW_ONLY_TEXT,
    DRAW_ONLY_PICTURES,
    TOTAL_DRAW_MODES = 3,
} DrawMode;

struct Example4App {
    Gui* gui;
    ViewPort* view_port;
    FuriMessageQueue* event_queue;

    DrawMode draw_mode;
};

Π§Ρ‚ΠΎΠ±Ρ‹ draw_mode Π±Ρ‹Π» доступСн для нашСй callback-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Ρ€Π΅Π½Π΄Π΅Ρ€Π° экрана, ΠΏΠ΅Ρ€Π΅Π΄Π°Π΄ΠΈΠΌ Π² Π½Π΅Ρ‘ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° всю структуру прилоТСния app Π² качСствС контСкста:

view_port_draw_callback_set(app->view_port, example_4_app_draw_callback, app);

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠΌ саму callback-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ Ρ€Π΅Π½Π΄Π΅Ρ€Π°. ΠŸΡƒΡΡ‚ΡŒ Ρ€Π°Π·Π½Ρ‹Π΅ графичСскиС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ рСндСрятся Π² зависимости ΠΎΡ‚ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ значСния draw_mode:

static void example_4_app_draw_callback(Canvas* canvas, void* ctx) {
    furi_assert(ctx);
    Example4App* app = ctx;

    canvas_clear(canvas);

    DrawMode mode = app->draw_mode;
    if (mode == DRAW_ONLY_PICTURES || mode == DRAW_ALL)
        canvas_draw_icon(canvas, 0, 29, &I_amperka_ru_logo_128x35px);
    if (mode == DRAW_ONLY_TEXT|| mode == DRAW_ALL) {
        canvas_set_font(canvas, FontPrimary);
        canvas_draw_str(canvas, 4, 8, "This is an example app!");
        canvas_set_font(canvas, FontSecondary);
        elements_multiline_text_aligned(canvas, 127, 15, AlignRight, AlignTop, "Some long long long long \n aligned multiline text");
    }
}

Π’ Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ Π½ΠΎΠ²Ρ‹Π΅ события ΠΊΠ½ΠΎΠΏΠΎΠΊ Π² бСсконСчном Ρ†ΠΈΠΊΠ»Π΅ Π³Π»Π°Π²Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ прилоТСния:

while (1) {
    if (furi_message_queue_get(app->event_queue, &event, 100) == FuriStatusOk) {
        if (event.type == InputTypePress) {
            if (event.key == InputKeyBack)
                break;
        } else if (event.type == InputTypeLong) {
            DrawMode mode = app->draw_mode;
            if (event.key == InputKeyLeft)
                app->draw_mode = (mode - 1 + TOTAL_DRAW_MODES) % TOTAL_DRAW_MODES;
            else if (event.key == InputKeyRight)
                app->draw_mode = (mode + 1) % TOTAL_DRAW_MODES;

            view_port_update(app->view_port);
        }
    }
}

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Ссли Π±ΡƒΠ΄Π΅Ρ‚ зарСгистрировано событиС Π΄Π»ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ наТатия (InputTypeLong) ΠΊΠ½ΠΎΠΏΠΊΠΈ Β«Π’Π»Π΅Π²ΠΎΒ» (InputKeyLeft) ΠΈΠ»ΠΈ Β«Π’ΠΏΡ€Π°Π²ΠΎΒ» (InputKeyRight), наш Ρ€Π΅ΠΆΠΈΠΌ отрисовки app->draw_mode Π±ΡƒΠ΄Π΅Ρ‚ ΠΌΠ΅Π½ΡΡ‚ΡŒΡΡ ΠΎΡ‚ 0 Π΄ΠΎ TOTAL_DRAW_MODES.

Ѐункция view_port_update() запускаСт Ρ€Π΅Ρ€Π΅Π½Π΄Π΅Ρ€ нашСго интСрфСйса view_port. Ѐункция Π½Π΅ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Π°Ρ, опСрационная систСма сама ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚ Ρ€Π΅Ρ€Π΅Π½Π΄Π΅Ρ€ Ρ€Π°Π· Π² нСсколько миллисСкунд, Π½ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Ρ„ΠΎΡ€ΡΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ это Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ.

Π‘ΠΎΠ±Π΅Ρ€Ρ‘ΠΌ ΠΎΠ±Π½ΠΎΠ²Π»Ρ‘Π½Π½ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ Π΅Π³ΠΎ Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€, запустим ΠΈ посмотрим Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚:

Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎ: https://youtu.be/7EBGrZNekXM.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 5. ΠžΠΏΠΎΠ²Π΅Ρ‰Π΅Π½ΠΈΡ

Помимо дисплСя Flipper Zero ΠΈΠΌΠ΅Π΅Ρ‚ ΠΈ Π΄Ρ€ΡƒΠ³ΠΎΠΉ способ ΡΠΎΠΎΠ±Ρ‰Π°Ρ‚ΡŒ Π½Π°ΠΌ ΠΎ происходящих Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ событиях β€” оповСщСния (Notifications). Нам доступно ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌΠΈ встроСнными дСвайсами:

  • RGB-cΠ²Π΅Ρ‚ΠΎΠ΄ΠΈΠΎΠ΄.
  • Π’ΠΈΠ±Ρ€ΠΎΠΌΠΎΡ‚ΠΎΡ€.
  • ΠŸΡŒΠ΅Π·ΠΎΠΏΠΈΡ‰Π°Π»ΠΊΠ°.

ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Π΅ΠΌ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ΄ Π½ΠΎΠ²Ρ‹ΠΌ ΠΈΠΌΠ΅Π½Π΅ΠΌ example_5.

Π—Π° оповСщСния Π² ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ систСмС Flipper Zero ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠΎΡ‚ΠΎΠΊ, ΠΈ ΠΌΡ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ Π΅Π³ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ· нашСго прилоТСния Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ. Но ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΡ‚ΡΡ‹Π»Π°Ρ‚ΡŒ Π² этот ΠΏΠΎΡ‚ΠΎΠΊ сообщСния β€” NotificationMessage. Из этих сообщСний Ρ„ΠΎΡ€ΠΌΠΈΡ€ΡƒΡŽΡ‚ΡΡ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ NotificationSequence, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡƒΠΆΠ΅ нСпосрСдствСнно ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡŽΡ‚ΡΡ Π² ΠΏΠΎΡ‚ΠΎΠΊ.

ОписаниС структур сообщСний ΠΈ ΠΈΡ… ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚Π΅ΠΉ находится Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ notification/notification_messages.h, добавляСм Π΅Π³ΠΎ Π² нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.

Π’ Π³Π»Π°Π²Π½ΠΎΠΉ структурС ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ собираСтся ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ оповСщСния NotificationApp:

struct Example5App {
    Gui* gui;
    ViewPort* view_port;
    FuriMessageQueue* event_queue;
    NotificationApp* notifications;

    DrawMode draw_mode;
};

Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ прилоТСния example_5_app_alloc() ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚Ρ‹Π²Π°Π΅ΠΌ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ оповСщСниями:

app->notifications = furi_record_open(RECORD_NOTIFICATION);

А Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ освобоТдСния памяти прилоТСния example_5_app_free ΠΎΡ‚Π΄Π°Ρ‘ΠΌ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ:

furi_record_close(RECORD_NOTIFICATION);

МоТно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ Π³ΠΎΡ‚ΠΎΠ²Ρ‹Π΅ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ сообщСний, Π° ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΈΡ… ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ, это нСслоТно. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» ΠΈ ΠΊΠ°ΠΊΠΈΠ΅ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Ρ‚Π°ΠΌ доступны.

Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π½Π°ΡˆΡƒ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ сообщСний для управлСния RGB-свСтодиодом. НазовСм Π΅Ρ‘ example_led_sequence ΠΈ размСстим Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ΅ нашСго прилоТСния.

ΠŸΡƒΡΡ‚ΡŒ свСтодиод ΠΌΠΈΠ³Π½Ρ‘Ρ‚ Ρ„ΠΈΠΎΠ»Π΅Ρ‚ΠΎΠ²Ρ‹ΠΌ Ρ†Π²Π΅Ρ‚ΠΎΠΌ RGB(255, 0, 255) Ρ‚Ρ€ΠΈ Ρ€Π°Π·Π° с ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»ΠΎΠΌ 500 мс, Π° Π·Π°Ρ‚Π΅ΠΌ погаснСт. Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

const NotificationSequence example_led_sequence = {
    &message_red_255,
    &message_blue_255,
    &message_delay_500,
    &message_red_0,
    &message_blue_0,
    &message_delay_500,
    &message_red_255,
    &message_blue_255,
    &message_delay_500,
    &message_red_0,
    &message_blue_0,
    &message_delay_500,
    &message_red_255,
    &message_blue_255,
    &message_delay_500,
    &message_red_0,
    &message_blue_0,
    NULL,
};

ΠŸΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ сообщСний для управлСния Π²ΠΈΠ±Ρ€ΠΎΠΌΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΡΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‚ΡΡ схоТим ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ. Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ для Π²ΠΈΠ±Ρ€ΠΎΠΌΠΎΡ‚ΠΎΡ€Π° с ΠΈΠΌΠ΅Π½Π΅ΠΌ example_vibro_sequence ΠΈ размСстим Π΅Ρ‘ Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ΅.

ΠŸΡƒΡΡ‚ΡŒ ΠΏΠΎ сигналу наш Π²ΠΈΠ±Ρ€ΠΎΠΌΠΎΡ‚ΠΎΡ€ Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡΡ Π½Π° 3 сСкунды, Π° Π·Π°Ρ‚Π΅ΠΌ Π²Ρ‹ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡΡ. ΠŸΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ сообщСний Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ Ρ‚Π°ΠΊ:

const NotificationSequence example_vibro_sequence = {
    &message_vibro_on,
    &message_do_not_reset,
    &message_delay_1000,
    &message_delay_1000,
    &message_delay_1000,
    &message_vibro_off,
    NULL,
};

По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ максимально долгая описанная Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° составляСт 1 сСкунду, поэтому ΠΌΡ‹ Ρ‚Ρ€ΠΈ Ρ€Π°Π·Π° использовали сообщСниС message_delay_1000.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ создадим ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ сообщСний для пьСзодинамика. НазовСм Π΅Ρ‘ example_sound_sequence.

Π—Π΄Π΅ΡΡŒ Π½Π°ΠΌ ΡƒΠΆΠ΅ доступна полная MIDI-ΠΊΠ»Π°Π²ΠΈΠ°Ρ‚ΡƒΡ€Π° прямо ΠΈΠ· ΠΊΠΎΡ€ΠΎΠ±ΠΊΠΈ! ОписаниС всСх Π½ΠΎΡ‚ ΠΈ ΠΈΡ… частот ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ notification_messages_notes.h.

Π”ΠΎΠ±Π°Π²ΠΈΠΌ Π² наш Π€Π»ΠΈΠΏΠΏΠ΅Ρ€ ΠΊΠ»Π°ΡΡΠΈΡ‡Π΅ΡΠΊΡƒΡŽ мСлодию Π·Π²ΠΎΠ½ΠΊΠ° Ρ‚Π΅Π»Π΅Ρ„ΠΎΠ½ΠΎΠ² Nokia:

ΠŸΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ сообщСний с Π΄Π°Π½Π½ΠΎΠΉ ΠΌΠ΅Π»ΠΎΠ΄ΠΈΠ΅ΠΉ выглядит Ρ‚Π°ΠΊ:

const NotificationSequence example_sound_sequence = {
    &message_note_e5,
    &message_delay_100,
    &message_note_d5,
    &message_delay_100,
    &message_note_fs4,
    &message_delay_250,
    &message_note_gs4,
    &message_delay_250,
    &message_note_cs5,
    &message_delay_100,
    &message_note_b4,
    &message_delay_100,
    &message_note_d4,
    &message_delay_250,
    &message_note_e4,
    &message_delay_250,
    &message_note_b4,
    &message_delay_100,
    &message_note_a4,
    &message_delay_100,
    &message_note_cs4,
    &message_delay_250,
    &message_note_e4,
    &message_delay_250,
    &message_note_a4,
    &message_delay_500,
    NULL,
};

ΠžΡ‚Π»ΠΈΡ‡Π½ΠΎ! Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π½ΡƒΠΆΠ½ΠΎ Ρ€Π΅ΡˆΠΈΡ‚ΡŒ, ΠΊΠΎΠ³Π΄Π° Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ оповСщСния. ΠŸΡƒΡΡ‚ΡŒ ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ Π½Π° ΠΊΠ½ΠΎΠΏΠΊΡƒ Β«Π’Π²Π΅Ρ€Ρ…Β» (InputKeyUp) Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡΡ свСтодиод, ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ Π½Π° ΠΊΠ½ΠΎΠΏΠΊΡƒ Β«Π’Π½ΠΈΠ·Β» (InputKeyDown) Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡΡ Π²ΠΈΠ±Ρ€ΠΎΠΌΠΎΡ‚ΠΎΡ€, Π° ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ Π½Π° ΠΊΠ½ΠΎΠΏΠΊΡƒ «Ок» (InputKeyOk) Π·Π°ΠΈΠ³Ρ€Π°Π΅Ρ‚ мСлодия.

ДобавляСм ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ для Π½ΠΎΠ²Ρ‹Ρ… ΠΊΠ½ΠΎΠΏΠΎΠΊ Π² бСсконСчный Ρ†ΠΈΠΊΠ» Π² Π³Π»Π°Π²Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ нашСго прилоТСния example_5_app():

while (1) {
    if (furi_message_queue_get(app->event_queue, &event, 100) == FuriStatusOk) {
        if (event.type == InputTypePress) {
            if (event.key == InputKeyBack)
                break;
            else if (event.key == InputKeyUp)
                notification_message(app->notifications, &example_led_sequence);
            else if (event.key == InputKeyDown)
                notification_message(app->notifications, &example_vibro_sequence);
            else if (event.key == InputKeyOk)
                notification_message(app->notifications, &example_sound_sequence);

        } else if (event.type == InputTypeLong) {
            DrawMode mode = app->draw_mode;
            if (event.key == InputKeyLeft)
                app->draw_mode = (mode - 1 + TOTAL_DRAW_MODES) % TOTAL_DRAW_MODES;
            else if (event.key == InputKeyRight)
                app->draw_mode = (mode + 1) % TOTAL_DRAW_MODES;

            view_port_update(app->view_port);
        }
    }
}

ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° сообщСний осущСствляСтся Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ notification_message() с ΡƒΠΊΠ°Π·Π°Π½ΠΈΠ΅ΠΌ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΉ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ.

Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅:

./fbt fap_example_5

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ qFlipper, пСрСносим Π½ΠΎΠ²Ρ‹ΠΉ FAP-Ρ„Π°ΠΉΠ» ΠΈΠ· ΠΏΠ°ΠΏΠΊΠΈ build Π½Π° SD-ΠΊΠ°Ρ€Ρ‚Ρƒ Π² ΠΏΠ°ΠΏΠΊΡƒ /apps/Misc. Или Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ ./fbt fap_deploy.

ЗапускаСм ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅:

Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎ: https://youtu.be/238dmsw5DA4.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 6. GPIO

На Flipper Zero 18 ΠΊΠΎΠ½Ρ‚Π°ΠΊΡ‚ΠΎΠ² GPIO, срСди ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π΅ΡΡ‚ΡŒ ΠΊΠ°ΠΊ ΠΏΠΈΠ½Ρ‹ питания, Ρ‚Π°ΠΊ ΠΈ ΠΏΠΈΠ½Ρ‹ Π²Π²ΠΎΠ΄Π°-Π²Ρ‹Π²ΠΎΠ΄Π°. ЛогичСскоС напряТСниС питания β€” 3,3Π’, ΠΈ ΠΏΠΈΠ½Ρ‹ Π½Π΅Ρ‚ΠΎΠ»Π΅Ρ€Π°Π½Ρ‚Π½Ρ‹ ΠΊ 5Π’ (Π·Π° ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ΠΌ ΠΏΠΈΠ½Π° iButton). По сути, ΠΏΠΈΠ½Ρ‹ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π° ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‚ ΠΏΠΈΠ½Π°ΠΌ установлСнного Π² Π½Ρ‘ΠΌ ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π° STM32WB55 ΠΈ ΠΎΠ±Π»Π°Π΄Π°ΡŽΡ‚ Ρ‚Π΅ΠΌΠΈ ΠΆΠ΅ настраиваСмыми Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΌΠΈ функциями (ADC, USART, SPI ΠΈ Π΄Ρ€.).

Распиновка Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π°:

ΠŸΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎΠ΅ Π½Π°Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΈΠ½ΠΎΠ² ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ furi_hal_resources.h. FURI HAL β€” ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΉ HAL Flipper Zero, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΡ€ΠΈΠ·Π²Π°Π½ ΡƒΠΏΡ€ΠΎΡΡ‚ΠΈΡ‚ΡŒ для нас взаимодСйствиС с ΠΆΠ΅Π»Π΅Π·ΠΎΠΌ.

Π’ FURI HAL GPIO-структура ΠΈΠΌΠ΅Π΅Ρ‚ имя GpioPin. Π‘Π΅Π· Ρ€Π°Π·Π±ΠΎΡ€ΠΊΠΈ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π° Π½Π° куски Π½Π°ΠΌ доступны:

  • const GpioPin gpio_ext_pc0 β€” ΠΏΠΎΡ€Ρ‚ GPIOC, ΠΏΠΈΠ½ 0 (Π½ΠΎΠΌΠ΅Ρ€ 16 Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅).
  • const GpioPin gpio_ext_pc1 β€” ΠΏΠΎΡ€Ρ‚ GPIOC, ΠΏΠΈΠ½ 1 (Π½ΠΎΠΌΠ΅Ρ€ 15 Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅).
  • const GpioPin gpio_ext_pc3 β€” ΠΏΠΎΡ€Ρ‚ GPIOC, ΠΏΠΈΠ½ 3 (Π½ΠΎΠΌΠ΅Ρ€ 7 Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅).
  • const GpioPin gpio_ext_pb2 β€” ΠΏΠΎΡ€Ρ‚ GPIOB, ΠΏΠΈΠ½ 2 (Π½ΠΎΠΌΠ΅Ρ€ 6 Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅).
  • const GpioPin gpio_ext_pb3 β€” ΠΏΠΎΡ€Ρ‚ GPIOB, ΠΏΠΈΠ½ 3 (Π½ΠΎΠΌΠ΅Ρ€ 5 Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅).
  • const GpioPin gpio_ext_pa4 β€” ΠΏΠΎΡ€Ρ‚ GPIOA, ΠΏΠΈΠ½ 4 (Π½ΠΎΠΌΠ΅Ρ€ 4 Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅).
  • const GpioPin gpio_ext_pa6 β€” ΠΏΠΎΡ€Ρ‚ GPIOA, ΠΏΠΈΠ½ 6 (Π½ΠΎΠΌΠ΅Ρ€ 3 Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅).
  • const GpioPin gpio_ext_pa7 β€” ΠΏΠΎΡ€Ρ‚ GPIOA, ΠΏΠΈΠ½ 7 (Π½ΠΎΠΌΠ΅Ρ€ 2 Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅).
  • const GpioPin ibutton_gpio β€” ΠΏΠΎΡ€Ρ‚ GPIOB, ΠΏΠΈΠ½ 14 (Π½ΠΎΠΌΠ΅Ρ€ 17 Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅).

Π’Π°ΠΊΠΆΠ΅ доступны ΠΏΠΈΠ½Ρ‹ с Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ USART ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ:

  • const GpioPin gpio_usart_tx β€” ΠΏΠΎΡ€Ρ‚ GPIOB, ΠΏΠΈΠ½ 6 (Π½ΠΎΠΌΠ΅Ρ€ 13 Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅).
  • const GpioPin gpio_usart_rx β€” ΠΏΠΎΡ€Ρ‚ GPIOB, ΠΏΠΈΠ½ 7 (Π½ΠΎΠΌΠ΅Ρ€ 14 Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅).

Π•Ρ‰Ρ‘ Π΅ΡΡ‚ΡŒ ΠΏΠΈΠ½Ρ‹ интСрфСйса SWD (Serial Wire Debug) для ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ, ΠΌΠ°Ρ€ΠΊΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Π½Π° корпусС ΠΊΠ°ΠΊ SIO, SWC. ВсС ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠΈΠ½Ρ‹ ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ для управлСния Π½Π°Ρ‡ΠΈΠ½ΠΊΠΎΠΉ Flipper Zero: дисплССм, ΠΊΠ½ΠΎΠΏΠΊΠ°ΠΌΠΈ, USB, NFC, IΒ²C, SPI ΠΈ Ρ‚.Π΄.

Π‘Π΄Π΅Π»Π°Π΅ΠΌ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Ρ‡Π΅Ρ€Π΅Π· ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΌΡ‹ смоТСм ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ GPIO. Π‘ΠΏΠ΅Ρ€Π²Π° сдСлаСм простой DigitalWrite, DigitalRead. Π§ΠΈΡ‚Π°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅ΠΌ с ΠΏΠΈΠ½Π° А6, Π° ΠΏΠΈΡΠ°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π² ΠΏΠΈΠ½ А7.

ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠΌ ΠΊ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Ρƒ ΠΏΡ€ΠΎΡΡ‚ΡƒΡŽ ΠΊΠ½ΠΎΠΏΠΊΡƒ ΠΊ ΠΏΠΈΠ½Ρƒ А6 ΠΈ свСтодиод ΠΊ ΠΏΠΈΠ½Ρƒ А7. ΠœΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ‚ΠΎΠΊ Π½Π° ΠΏΠΈΠ½Π΅ β€” 20 мА, для свСтодиода Ρ…Π²Π°Ρ‚ΠΈΡ‚. ΠŸΠΈΡ‚Π°Π½ΠΈΠ΅ Π±Π΅Ρ€Ρ‘ΠΌ с ΡˆΠΈΠ½Ρ‹ 3,3Π’. Установим свСтодиод ΠΈ ΠΊΠ½ΠΎΠΏΠΊΡƒ Π½Π° ΠΌΠ°ΠΊΠ΅Ρ‚Π½ΡƒΡŽ ΠΏΠ»Π°Ρ‚Ρƒ:

Назовём Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ example_6 ΠΈ сдСлаСм Π΅Π³ΠΎ Π½Π° основС нашСго ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° Π½ΠΎΠΌΠ΅Ρ€ 4. ΠŸΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΡƒΠ±Π΅Ρ€Ρ‘ΠΌ ΠΈΠ· прилоТСния всё, Ρ‡Ρ‚ΠΎ касаСтся ΠΎΠΏΠΎΠ²Π΅Ρ‰Π΅Π½ΠΈΠΉ, Ρ€Π΅Π½Π΄Π΅Ρ€Π° графичСских элСмСнтов ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΊΠ½ΠΎΠΏΠΎΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ остался пустой интСрфСйс.

Для управлСния GPIO Π½Π°ΠΌ Π½ΡƒΠΆΠ΅Π½ HAL Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π°. ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Ρ„Π°ΠΉΠ» furi_hal.h Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ нашСго прилоТСния.

Π’ Π³Π»Π°Π²Π½ΠΎΠΉ структурС Example6App нашСго прилоТСния создадим Π΄Π²Π° ΠΏΠΈΠ½Π° для Π²Ρ…ΠΎΠ΄Π° ΠΈ Π²Ρ‹Ρ…ΠΎΠ΄Π°: input_pin, output_pin ΠΈ Π΄Π²Π΅ Π±ΡƒΠ»Π΅Π²Ρ‹ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ для хранСния Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΡ… Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Π½Π° этих ΠΏΠΈΠ½Π°Ρ…: input_value, output_value.

Наш Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Π²ΠΈΠ΄:

#pragma once

#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>

struct Example6App {
    Gui* gui;
    ViewPort* view_port;
    FuriMessageQueue* event_queue;

    const GpioPin* input_pin;
    const GpioPin* output_pin;

    bool input_value;
    bool output_value;
};

typedef struct Example6App Example6App;

Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ прилоТСния example_6_app_alloc() Π·Π°Π΄Π°Ρ‘ΠΌ Π½ΠΎΠΌΠ΅Ρ€Π° ΠΏΠΈΠ½ΠΎΠ². Π€ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ furi_hal_gpio_init() ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»Π·ΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΠΈΠ½Ρ‹. Для Π²Π²ΠΎΠ΄Π° устанавливаСм Ρ€Π΅ΠΆΠΈΠΌ GpioModeInput ΠΈ Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ подтяТку GpioPullUp, Π° для Π²Ρ‹Π²ΠΎΠ΄Π° Ρ€Π΅ΠΆΠΈΠΌ GpioModeOutputPushPull ΠΈ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ подтяТку GpioPullNo. Оба ΠΏΠΈΠ½Π° ΠΎΠΏΡ€Π°ΡˆΠΈΠ²Π°ΡŽΡ‚ΡΡ Π½Π° максимальной скорости GpioSpeedVeryHigh:

app->input_pin = &gpio_ext_pa6;
app->output_pin = &gpio_ext_pa7;

furi_hal_gpio_init(app->input_pin, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh);
furi_hal_gpio_init(app->output_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);

Π’ Π³Π»Π°Π²Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ прилоТСния example_6_app() (ΠΈ ΠΏΠΎ ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΡ‚Π΅Π»ΡŒΡΡ‚Π²Ρƒ Π² нашСй Ρ‚ΠΎΡ‡ΠΊΠ΅ Π²Ρ…ΠΎΠ΄Π°) считываСм ΠΈ отправляСм ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ значСния Π² бСсконСчном Ρ†ΠΈΠΊΠ»Π΅:

furi_hal_gpio_write(app->output_pin, app->output_value);
app->input_value = furi_hal_gpio_read(app->input_pin);

ΠŸΡƒΡΡ‚ΡŒ Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ зависит ΠΎΡ‚ состояния ΠΊΠ½ΠΎΠΏΠΊΠΈ «Ок» Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π°. Кнопка Π½Π°ΠΆΠ°Ρ‚Π° β€” сигнал Π΅ΡΡ‚ΡŒ, ΠΎΡ‚ΠΆΠ°Ρ‚Π° β€” сигнала Π½Π΅Ρ‚. Как ΠΈ ΠΏΡ€Π΅ΠΆΠ΄Π΅, клавишСй «Назад» Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅ΠΌ Ρ€Π°Π±ΠΎΡ‚Ρƒ прилоТСния. Π”ΠΎΠ±Π°Π²ΠΈΠΌ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΡƒΡŽ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ ΠΊΠ½ΠΎΠΏΠΊΠΈ «Ок» Π² бСсконСчный Ρ†ΠΈΠΊΠ» нашСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹:

if (furi_message_queue_get(app->event_queue, &event, 100) == FuriStatusOk) {
    if (event.key == InputKeyBack) {
        if (event.type == InputTypePress)
            break;

    } else if (event.key == InputKeyOk) {
        if (event.type == InputTypePress)
            app->output_value = true;
        else if (event.type == InputTypeRelease)
            app->output_value = false;
    }

НаконСц, Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ Π³Ρ€Π°Ρ„ΠΈΠΊΠΈ Π² callback-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ отрисовки интСрфСйса. ΠŸΡ€ΠΎΡΡ‚ΠΎ Π²Ρ‹Π²Π΅Π΄Π΅ΠΌ тСкстом Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ Π²Ρ…ΠΎΠ΄Π½ΠΎΠ΅ ΠΈ Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅. Для отрисовки Π±ΠΎΠ»ΡŒΡˆΠΈΡ… Ρ†ΠΈΡ„Ρ€ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡˆΡ€ΠΈΡ„Ρ‚ FontBigNumbers. Π’ качСствС контСкста ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘ΠΌ Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ отрисовки Π³Π»Π°Π²Π½ΡƒΡŽ структуру прилоТСния.

static void example_6_app_draw_callback(Canvas* canvas, void* ctx) {
    furi_assert(ctx);
    Example6App* app = ctx;

    canvas_clear(canvas);
    canvas_set_font(canvas, FontSecondary);
    elements_multiline_text_aligned(canvas, 32, 17, AlignCenter, AlignTop, "Output PA7:");
    elements_multiline_text_aligned(canvas, 96, 17, AlignCenter, AlignTop, "Input PA6:");

    canvas_set_font(canvas, FontBigNumbers);
    elements_multiline_text_aligned(canvas, 32, 32, AlignCenter, AlignTop, app->output_value ? "1" : "0");
    elements_multiline_text_aligned(canvas, 96, 32, AlignCenter, AlignTop, app->input_value ? "1" : "0");
}

Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ Ρ‚Π°ΠΊ:

Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ Π΅Π³ΠΎ Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€:

./fbt fap_example_6
./fbt fap_deploy

Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎ: https://youtu.be/6k5D1TGZm0Q.

PWM ΠΈ ADC Π‘ Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠ΅ΠΉ ШИМ-сигналов всё обстоит Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ слоТнСС. Π—Π΄Π΅ΡΡŒ ΡƒΠΆΠ΅ Π½Π΅ ΠΎΠ±ΠΎΠΉΡ‚ΠΈΡΡŒ ΠΎΠ΄Π½ΠΎΠΉ-двумя функциями ΠΈΠ· FURI HAL, Π° сам ΠΊΠΎΠ΄ сильно разрастаСтся.

Π’ ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠ΅ Flipper Zero ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Signal Generator для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ ШИМ-сигнала Π½Π° ΠΏΠΈΠ½Π°Ρ… PA7 ΠΈ PA4. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒ исходный ΠΊΠΎΠ΄ для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ ШИМ Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ applications/plugins/signal_generator/ ΠΈ Ρ€Π΅ΠΏΠ»ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ Π² вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.

А Π²ΠΎΡ‚ ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΉ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ Π½Π° Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ Π°Π½Π°Π»ΠΎΠ³ΠΎΠ²Ρ‹Ρ… сигналов ΠΏΠΎΠΊΠ° Π½Π΅Ρ‚. ΠšΡ€ΠΎΠΌΠ΅ этого Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π°Π½Π°Π»ΠΎΠ³ΠΎ-Ρ†ΠΈΡ„Ρ€ΠΎΠ²ΠΎΠ³ΠΎ прСобразоватСля Π½Π° ΠΏΠΈΠ½Π°Ρ… Π΅Ρ‰Ρ‘ Π½Π΅ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Ρ‹ Π² FURI HAL. Однако сам ADC Π½Π° ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π΅ STM32 ΠΈ Π΅Π³ΠΎ возмоТности Π½ΠΈΠΊΡƒΠ΄Π° ΠΎΡ‚ нас Π½Π΅ дСлись.

На просторах ΠΈΠ½Ρ‚Π΅Ρ€Π½Π΅Ρ‚Π° ΠΌΡ‹ нашли ΠΏΡ€ΠΈΠΌΠ΅Ρ€ использования ADC. ΠœΡ‹ размСстили Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ с ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°ΠΌΠΈ flipperzero-examples ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ adc_example, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ cΡ‡ΠΈΡ‚Ρ‹Π²Π°Π΅Ρ‚ Π°Π½Π°Π»ΠΎΠ³ΠΎΠ²ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ с ΠΏΠΈΠ½Π° PC3 ΠΈ Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ Π΅Π³ΠΎ Π½Π° экран. Код Π΅Ρ‰Ρ‘ нуТдаСтся Π² Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠ΅, ΠΈ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ Π² своих прилоТСниях, ΠΎΠ΄Π½Π°ΠΊΠΎ ΠΌΡ‹ совСтуСм Π΄ΠΎΠΆΠ΄Π°Ρ‚ΡŒΡΡ ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΉ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ².

ΠžΠΏΠΎΡ€Π½Ρ‹ΠΌ напряТСниСм являСтся Π²Ρ‹Π±ΠΎΡ€ΠΎΡ‡Π½ΠΎ ΠΈΠ»ΠΈ 2.5Π’ ΠΈΠ»ΠΈ 2.048Π’. ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠ² ΠΊ Ρ„Π»ΠΈΠΏΠΏΠ΅Ρ€Ρƒ ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠΎΠΌΠ΅Ρ‚Ρ€ ΠΈ взяв ΠΏΠΈΡ‚Π°Π½ΠΈΠ΅ с ΠΏΠΈΠ½Π° 3.3Π’ понадобится простой Π΄Π΅Π»ΠΈΡ‚Π΅Π»ΡŒ напряТСния Π² ΠΏΡ€Π΅Π΄Π΅Π»Π°Ρ… тысячи Ом. Π Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ АЦП - 12 Π±ΠΈΡ‚.

Π§ΠΈΡ‚Π°Π΅ΠΌ напряТСниС ΠΎΡ‚ 0 Π΄ΠΎ 2.5Π’ Π½Π° ΠΏΠΈΠ½Π΅ PC3 ΠΈ мСняСм Π΅Π³ΠΎ ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠΎΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ:

Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎ: https://youtu.be/k2DK9xAi9QQ.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

На этом ΠΌΡ‹ Π·Π°ΠΊΠ°Π½Ρ‡ΠΈΠ²Π°Π΅ΠΌ Π±Π°Π·ΠΎΠ²ΠΎΠ΅ знакомство с ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΌΠΈ прилоТСниями для Flipper Zero.

Покопавшись Π² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ, Π½Π°ΠΌ ΡƒΠ΄Π°Π»ΠΎΡΡŒ Π·Π°ΠΉΡ‚ΠΈ подальшС банального Β«Hello, world!Β» ΠΈ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ нСсколько ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ для ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° Ρ€Π°Π±ΠΎΡ‚Ρ‹ с GUI, ΠΊΠ½ΠΎΠΏΠΊΠ°ΠΌΠΈ ΠΈ встроСнной ΠΏΠ΅Ρ€ΠΈΡ„Π΅Ρ€ΠΈΠ΅ΠΉ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π° β€” RGB-свСтодиодом, Π²ΠΈΠ±Ρ€ΠΎΠΌΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΈ Π±Π°Π·Π·Π΅Ρ€ΠΎΠΌ.

Π–Π΄Ρ‘ΠΌ обновлСния ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΉ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ Π³Π°Π΄ΠΆΠ΅Ρ‚Π° ΠΈ надССмся, Ρ‡Ρ‚ΠΎ наши ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΏΠΎΠΌΠΎΠ³ΡƒΡ‚ Π²Π°ΠΌ Π² создании своих ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ для Flipper Zero!