--- title: "πŸ“Ÿ Как ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ для Flipper Zero" date: 2023-03-27T21:42:08+03:00 draft: false tags: [tutorial, development, c, flipper zero] --- **Π­Ρ‚ΠΎ руководство полная копия [ΡΡ‚Π°Ρ‚ΡŒΠΈ](https://amperka.ru/blogs/projects/flipper-zero-app-programming-tutorial) с сайта amperka.ru**. Автор: **Максим Π”Π°Π½ΠΈΠ»ΠΈΠ½**. Написано: 25.01.2023 Π³ΠΎΠ΄Π°. # Как ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ для Flipper Zero ΠŸΡ€ΠΈΠ²Π΅Ρ‚! Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ разбСрёмся, ΠΊΠ°ΠΊ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΡΠΎΠ±ΡΡ‚Π²Π΅Π½Π½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ для Flipper Zero! Π‘Π΅Ρ€Π΄Ρ†Π΅ΠΌ Π³Π°Π΄ΠΆΠ΅Ρ‚Π° Flipper Zero являСтся 32-Π±ΠΈΡ‚Π½Ρ‹ΠΉ ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€ STM32. ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π”Π΅Π»ΡŒΡ„ΠΈΠ½Π° сильно отличаСтся ΠΎΡ‚ программирования ΠΏΡ€ΠΈΠ²Ρ‹Ρ‡Π½Ρ‹Ρ… Π½Π°ΠΌ Arduino. Помимо самого ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π° Π²ΠΎ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅ Π΅ΡΡ‚ΡŒ Ρ€Π°Π΄ΠΈΠΎΠΌΠΎΠ΄ΡƒΠ»ΡŒ, NFC-ΠΌΠΎΠ΄ΡƒΠ»ΡŒ, ΠΊΠ°Ρ€Π΄Ρ€ΠΈΠ΄Π΅Ρ€, ΠΌΠΎΠ΄ΡƒΠ»ΡŒ Bluetooth, дисплСй, микросхСма управлСния подсвСткой ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅. Π­Ρ„Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ всСми этими устройствами Π² ΠΎΠ΄Π½ΠΎΠΌ Ρ†ΠΈΠΊΠ»Π΅ `loop`, ΠΊΠ°ΠΊ это ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ выглядит Π² срСдС Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Arduino, ΡƒΠΆΠ΅ нСльзя. На ΠΏΠΎΠΌΠΎΡ‰ΡŒ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ [опСрационная систСма Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ](https://ru.wikipedia.org/wiki/%D0%9E%D0%BF%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D0%B0%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D1%80%D0%B5%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%B2%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%B8) ΠΈΠ»ΠΈ RTOS (real-time operating system). RTOS Ρ€Π°Π·Π³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ логичСскиС части всСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π² Ρ€Π°Π·Π½Ρ‹Π΅ ΠΏΠΎΡ‚ΠΎΠΊΠΈ ΠΈ сама осущСствляСт ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρƒ Π½ΠΈΠΌΠΈ, Π° Ρ‚Π°ΠΊΠΆΠ΅ выдСляСт Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² рСсурсы. Π’Π°ΠΊ ΠΊΠ°ΠΊ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€ построСн Π½Π° Ρ‡ΠΈΠΏΠ΅ STM32, Π² Π½Ρ‘ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ, Π½Π°Π²Π΅Ρ€Π½ΠΎΠ΅, самая популярная ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½ΠΊΠ° для этого Ρ‚ΠΈΠΏΠ° ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€ΠΎΠ² β€” [FreeRTOS](https://ru.wikipedia.org/wiki/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](https://docs.brew.sh/Homebrew-on-Linux). Ну Π° Ссли Π²Ρ‹ собираСтС ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΡƒ Π½Π° Windows ΠΈ ΡΡ‚ΠΎΠ»ΠΊΠ½ΡƒΠ»ΠΈΡΡŒ с трудностями, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ [WSL](https://ubuntu.com/wsl). ΠŸΠΈΡΠ°Ρ‚ΡŒ ΠΊΠΎΠ΄ для собствСнных ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π½Π° языкС программирования **C** Π½Π° Π½Π°ΡΡ‚ΠΎΠ»ΡŒΠ½ΠΎΠΌ ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π΅ ΠΏΠΎΠ΄ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ΠΌ Linux, Π° ΠΈΠΌΠ΅Π½Π½ΠΎ Ubuntu 22.04.1 LTS (Jammy Jellyfish). ## Установка Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ³ΠΎ софта ΠŸΠ΅Ρ€Π΅Π΄ Ρ‚Π΅ΠΌ ΠΊΠ°ΠΊ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Π½Π°ΠΌ придётся Π½Π°ΡƒΡ‡ΠΈΡ‚ΡŒΡΡ ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ всю ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΡƒ ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π°. Π‘ΠΏΠ΅Ρ€Π²Π° скачаСм ΠΈ установим ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ [qFlipper](https://docs.flipperzero.one/basics/firmware-update#yK3zg) для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Π€Π»ΠΈΠΏΠΏΠ΅Ρ€ΠΎΠΌ Ρ‡Π΅Ρ€Π΅Π· графичСский интСрфСйс. ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ qFlipper для ΡƒΠ΄ΠΎΠ±Π½ΠΎΠΉ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Π½Π°ΡˆΠΈΡ… Π³ΠΎΡ‚ΠΎΠ²Ρ‹Ρ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π½Π° SD-ΠΊΠ°Ρ€Ρ‚Ρƒ Π²ΠΎ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅. Π‘ΠΊΠ°Ρ‡ΠΈΠ²Π°Π΅ΠΌ Π²Π΅Ρ€ΡΠΈΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ для OS Linux ΠΊΡƒΠ΄Π°-Π½ΠΈΠ±ΡƒΠ΄ΡŒ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π² домашнюю Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ. На ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π²Ρ‹Ρ…ΠΎΠ΄Π° ΡΡ‚Π°Ρ‚ΡŒΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° qFlipper ΠΈΠΌΠ΅Π΅Ρ‚ Π²Π΅Ρ€ΡΠΈΡŽ 1.2.2, Π° сам Ρ„Π°ΠΉΠ» называСтся `qFlipper-x86_64-1.2.2.AppImage`. Π’Π°ΠΊΠΆΠ΅ установитС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡƒΡŽ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ `libfuse2`, Ссли Π΅Ρ‘ Π½Π΅Ρ‚ Π² вашСй систСмС. ```sh 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-ΠΏΠΎΡ€Ρ‚Ρƒ для ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠ³ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ. Π˜Π½Π°Ρ‡Π΅ понадобится вСсти Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ ΠΎΡ‚ Π»ΠΈΡ†Π° ΡΡƒΠΏΠ΅Ρ€ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ, Ρ‡Ρ‚ΠΎ нСбСзопасно для всСй систСмы Π² случаС нСостороТности. ```sh sudo chmod +x qFlipper-x86_64-1.2.2.AppImage ./qFlipper-x86_64-1.2.2.AppImage rules install ``` ЗапуститС qFlipper ΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ ваш Flipper Zero ΠΊ ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Ρƒ ΠΏΠΎ USB. ```sh ./qFlipper-x86_64-1.2.2.AppImage ``` Π£Π±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ ваш Π€Π»ΠΈΠΏΠΏΠ΅Ρ€ появился Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ qFlipper, всё Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΎ ΠΈ установлСна свСТая ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠ°. ![](/content/images/2023/flipper-app/1.png) Для быстрой ΠΈ ΡƒΠ΄ΠΎΠ±Π½ΠΎΠΉ установки Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ³ΠΎ софта понадобится диспСтчСр ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ² [Homebrew](https://docs.brew.sh/Homebrew-on-Linux). УстановитС Homebrew: ```sh sudo apt install curl /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ``` ПослС установки Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ окруТСния `PATH`, `MANPATH` для Homebrew. Π­Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ, Π΄ΠΎΠ±Π°Π²ΠΈΠ² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΡƒΡŽ строку Π² Ρ„Π°ΠΉΠ»Π΅ `.profile` для вашСго ΡŽΠ·Π΅Ρ€Π°: ```sh echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> /home/$USER/.profile ``` ΠŸΡ€ΠΎΡˆΠΈΠ²ΠΊΠ° для Flipper Zero хранится Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ [flipperzero-firmware](https://github.com/flipperdevices/flipperzero-firmware) Π½Π° GitHub. Π‘ΠΊΠ»ΠΎΠ½ΠΈΡ€ΡƒΠΉΡ‚Π΅ ΠΊ сСбС Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠΈ Flipper Zero со всСми модулями. Π Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ Π·Π°ΠΉΠΌΠ΅Ρ‚ Ρ‡ΡƒΡ‚ΡŒ большС 2 Π“Π‘ пространства. ```sh git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git ``` УстановитС пСрСчислСнный Π² описании рСпозитория софт: ```sh sudo apt update sudo apt install openocd clang-format-13 dfu-util protobuf-compiler ``` ΠŸΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ рСпозитория ΠΈ установитС всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Homebrew: ```sh cd flipperzero-firmware brew bundle --verbose ``` Π“ΠΎΡ‚ΠΎΠ²ΠΎ! ΠŸΡ€ΠΎΡˆΠΈΠ²ΠΊΠ° для Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π°, ΠΊΠ°ΠΊ ΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ прилоТСния, ΡΠΎΠ±ΠΈΡ€Π°ΡŽΡ‚ΡΡ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ `fbt` (Flipper Build Tool). Для создания собствСнных ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π½Π΅Ρ‚ нСобходимости ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π· ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ всю ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΡƒ Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ, ΠΎΠ΄Π½Π°ΠΊΠΎ ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΌ запускС ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ `fbt` Π±ΡƒΠ΄ΡƒΡ‚ скачаны Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ `gcc-arm` Ρ‚ΡƒΠ»Ρ‡Π΅ΠΉΠ½Ρ‹. Π‘ΠΎΠ±Π΅Ρ€ΠΈΡ‚Π΅ ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΡƒ: ```sh ./fbt ``` ВсС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ сборки ΠΈ Π±ΠΈΠ½Π°Ρ€Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΠΎΠΌΠ΅Ρ‰Π΅Π½Ρ‹ Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ `./dist`. ## ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 1. ΠŸΡ€ΠΎΡΡ‚Π΅ΠΉΡˆΠ΅Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΏΡ€ΠΎΡΡ‚Π΅ΠΉΡˆΠ΅Π΅ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΡƒΠ΅ΠΌΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅. ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ‚ΠΈΠΏΠ° FAP (Flipper Application Package). Π“ΠΎΡ‚ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ этого Ρ‚ΠΈΠΏΠ° прСдставляСт собой Ρ„Π°ΠΉΠ» Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π° `.fap`. По сути, `.fap` ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ β€” это исполняСмый Ρ„Π°ΠΉΠ» `.elf` с Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ встроСнными Π΄Π°Π½Π½Ρ‹ΠΌΠΈ. **ΠšΡΡ‚Π°Ρ‚ΠΈ!** Π’Π΅ΡΡŒ исходный ΠΊΠΎΠ΄ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ ΠΈΠ· этой стати ΠΌΡ‹ Π²Ρ‹Π»ΠΎΠΆΠΈΠ»ΠΈ Π½Π° GitHub Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ [flipperzero-examples](https://github.com/amperka/flipperzero-examples). ΠŸΡ€ΠΈ создании ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ прилоТСния ΠΏΠΎΠΌΠ΅Ρ‰Π°ΡŽΡ‚ΡΡ Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ°ΠΏΠΊΠΈ Π² ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎ ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°Π½Π½ΡƒΡŽ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ `applications_user`: ![](/content/images/2023/flipper-app/2.png) ΠŸΡ€ΠΈΠ΄ΡƒΠΌΠ°ΠΉΡ‚Π΅ имя для прилоТСния. ΠœΡ‹ Π½Π°Π·Π²Π°Π»ΠΈ нашС ΠΏΠ΅Ρ€Π²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ `example_1`, этим ΠΆΠ΅ ΠΈΠΌΠ΅Π½Π΅ΠΌ Π½Π°Π·Π²Π°Π»ΠΈ ΠΈ ΠΏΠ°ΠΏΠΊΡƒ. Π’ Π½Π΅Ρ‘ ΠΏΠΎΠΌΠ΅Ρ‰Π°ΡŽΡ‚ΡΡ всС Ρ„Π°ΠΉΠ»Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ относятся ΠΊ Π²Π°ΡˆΠ΅ΠΌΡƒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ: исходный ΠΊΠΎΠ΄, изобраТСния ΠΈ ΠΏΡ€ΠΎΡ‡Π΅Π΅. Π’ ΠΏΠ°ΠΏΠΊΠ΅ `example_1` создадим Ρ„Π°ΠΉΠ» исходного ΠΊΠΎΠ΄Π° Π½Π° языкС Π‘ β€” `example_1_app.c`. Π’ΠΎΡ‚ ΠΊΠ°ΠΊ выглядит ΠΊΠΎΠ΄ ΠΏΡ€ΠΎΡΡ‚Π΅ΠΉΡˆΠ΅Π³ΠΎ прилоТСния. ```c #include 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** с ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΌΠΈ прилоТСниями: ![](/content/images/2023/flipper-app/3.png) МоТно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ΄Π½ΠΎ ΠΈΠ· ΡƒΠΆΠ΅ ΠΈΠΌΠ΅ΡŽΡ‰ΠΈΡ…ΡΡ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ, Π½ΠΎ всСгда Π»ΡƒΡ‡ΡˆΠ΅ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ своё. Π’ GIMP ΠΌΡ‹ нарисовали Π²ΠΎΡ‚ Ρ‚Π°ΠΊΠΎΠΉ смайл Π² Ρ‡Ρ‘Ρ€Π½Ρ‹Ρ… ΠΎΡ‡ΠΊΠ°Ρ…: ![](/content/images/2023/flipper-app/emoji_smile_icon_10x10px.png) ΠΠ°Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ свою ΠΈΠΊΠΎΠ½ΠΊΡƒ ΠΌΠΎΠΆΠ½ΠΎ ΠΈ Π² Paint. Π€Π°ΠΉΠ» изобраТСния ΠΏΠΎΠΌΠ΅Ρ‰Π°Π΅ΠΌ Π² ΠΏΠ°ΠΏΠΊΡƒ нашСго прилоТСния `example_1`. Помимо исходного ΠΊΠΎΠ΄Π° ΠΈ ΠΈΠΊΠΎΠ½ΠΊΠΈ Π½Π°ΠΌ Π½ΡƒΠΆΠ΅Π½ Ρ„Π°ΠΉΠ» манифСста прилоТСния β€” `application.fam`. Π­Ρ‚ΠΎΡ‚ Ρ„Π°ΠΉΠ» являСтся ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ. Наш манифСст прилоТСния ΠΈΠΌΠ΅Π΅Ρ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Π²ΠΈΠ΄: ```c 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** Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅. Если всС Ρ„Π°ΠΉΠ»Ρ‹ Π½Π° мСстС, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒ сборку прилоТСния. ![](/content/images/2023/flipper-app/4.png) Π’ Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ Π² ΠΊΠΎΡ€Π½Π΅Π²ΡƒΡŽ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠΈ `flipperzero-firmware`. Π‘Π±ΠΎΡ€ΠΊΠ° осущСствляСтся ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ `./fbt fap_{APPID}`, Π³Π΄Π΅ `{APPID}` β€” это **ID**, ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΉ Π² `.fam`-Ρ„Π°ΠΉΠ»Π΅ манифСста прилоТСния. ```sh ./fbt fap_example_1 ``` Π‘Π±ΠΈΠ»Π΄ΠΈΡ‚ΡŒ всС ΠΈΠΌΠ΅ΡŽΡ‰ΠΈΠ΅ΡΡ Π² ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠ΅ прилоТСния FAP ΠΌΠΎΠΆΠ½ΠΎ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ `./fbt faps`. Π“ΠΎΡ‚ΠΎΠ²ΠΎΠ΅ FAP-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ находится Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ `build` Π² скрытой Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ `.extapps`. Наш Ρ„Π°ΠΉΠ» прилоТСния называСтся `example_1.fap`. ![](/content/images/2023/flipper-app/5.png) Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ qFlipper, пСрСнСсём Ρ„Π°ΠΉΠ» прилоТСния Π½Π° SD-ΠΊΠ°Ρ€Ρ‚Ρƒ Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ `/apps/Misc`. Π€Π°ΠΉΠ» ΠΌΠΎΠΆΠ½ΠΎ пСрСнСсти ΠΌΡ‹ΡˆΠΊΠΎΠΉ прямо Π² ΠΎΠΊΠ½ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹. ![](/content/images/2023/flipper-app/6.png) ПослС послСднСго обновлСния всС прилоТСния FAP ΠΌΠΎΠΆΠ½ΠΎ ΡΠ±ΠΈΠ»Π΄ΠΈΡ‚ΡŒ ΠΈ пСрСнСсти Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€ ΠΎΠ΄Π½ΠΎΠΉ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ ΠΈΠ· консоли: ```sh ./fbt fap_deploy ``` Π“ΠΎΡ‚ΠΎΠ²ΠΎ! Π’Π΅ΠΏΠ΅Ρ€ΡŒ нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ появилось Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅ Π² Ρ€Π°Π·Π΄Π΅Π»Π΅ `Misc`: ![](/content/images/2023/flipper-app/7.png) Главная функция `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`. ```c #pragma once #include #include struct Example2App { Gui* gui; ViewPort* view_port; }; typedef struct Example2App Example2App; ``` Π’ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ ΠΌΡ‹ создали структуру `Example2App`, которая Π±ΡƒΠ΄Π΅Ρ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π½Π° всС Π²Π°ΠΆΠ½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ нашСго прилоТСния, ΠΈ Π²Π²Π΅Π»ΠΈ Π½ΠΎΠ²Ρ‹ΠΉ Ρ‚ΠΈΠΏ для этой структуры. Π’ структурС нашСго прилоТСния Π΅ΡΡ‚ΡŒ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π½Π° графичСский интСрфСйс `Gui` ΠΈ Π½Π° `ViewPort`. `ViewPort` β€” это структура, которая ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для отрисовки Π΅Π΄ΠΈΠ½ΠΈΡ‡Π½ΠΎΠ³ΠΎ ΠΏΠΎΠ»Π½ΠΎΠ³ΠΎ экрана. К Π½Π΅ΠΉ ΠΏΡ€ΠΈΠ²ΡΠ·Ρ‹Π²Π°ΡŽΡ‚ΡΡ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π½Π° `callback`-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ отрисовки графичСских ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π½Π° экранС ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… событий (`Events`), Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π½Π°ΠΆΠ°Ρ‚ΠΈΠ΅ клавиш. Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ прилоТСния Π² Ρ„Π°ΠΉΠ»Π΅ `example_2_app.c` Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ выглядит Ρ‚Π°ΠΊ: ```c #include "example_2_app.h" #include #include 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; } ``` РазбСрёмся, Ρ‡Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ Ρ‡Ρ‚ΠΎ. ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΠΎΠ΄ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€ ΠΎΡ‡Π΅Π½ΡŒ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΠΊ рСсурсам ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ систСмы, ΠΈ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π·Π° этим ΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ. Π­Ρ‚ΠΎ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Π»ΠΎ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ ΠΈ Π½Π΅ Π²Ρ‹Π·Ρ‹Π²Π°Π»ΠΎ зависаний ΠΈ глюков. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ, Ссли ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ интСрфСйс, Ρ‚ΠΎ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ выдСляСм ΠΏΠΎΠ΄ это ΠΏΠ°ΠΌΡΡ‚ΡŒ, Π° ΠΊΠΎΠ³Π΄Π° удаляСм β€” освобоТдаСм. ΠžΠΏΠΈΡΡ‹Π²Π°Π΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π΄Π΅Π»ΡΡ‚ΡŒ ΠΏΠ°ΠΌΡΡ‚ΡŒ ΠΏΠΎΠ΄ структуру нашСго прилоТСния ΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ: ```c Example2App* example_2_app_alloc() ``` И Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая освобоТдаСт Π·Π°Π½ΡΡ‚ΡƒΡŽ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ ΠΏΠ°ΠΌΡΡ‚ΡŒ: ```c void example_2_app_free(Example2App* app) ``` Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ выдСлСния памяти ΠΌΡ‹ сначала выдСляСм ΠΏΠ°ΠΌΡΡ‚ΡŒ ΠΏΠΎΠ΄ структуру `app` Ρ‚ΠΈΠΏΠ° `Example2App` для нашСго прилоТСния. Π—Π°Ρ‚Π΅ΠΌ выдСляСм ΠΏΠ°ΠΌΡΡ‚ΡŒ для `view_port`: ```c app->view_port = view_port_alloc(); ``` ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ `Gui` Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π° β€” `gui`. ΠŸΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚Ρ‹Π²Π°Π΅ΠΌ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ `Gui` ΠΈ Π³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ систСмС, Ρ‡Ρ‚ΠΎ Ρƒ нашСго прилоТСния Π΅ΡΡ‚ΡŒ Π½Π΅ΠΊΠΈΠΉ интСрфСйс c отрисовкой экрана `view_port` ΠΈ ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Π΅Π³ΠΎ ΠΎΡ‚ΠΎΠ±Ρ€Π°Π·ΠΈΡ‚ΡŒ. ```c app->gui = furi_record_open(RECORD_GUI); gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen); ``` Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ освобоТдСния памяти ΠΌΡ‹, соотвСтствСнно, Ρ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ Π² ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΌ Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠΈ. Π’Ρ‹ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Ρ€Π΅Π½Π΄Π΅Ρ€ нашСго `view_port`: ```c view_port_enabled_set(app->view_port, false); ``` ΠžΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ `view_port` ΠΎΡ‚ `Gui` ΠΈ освобоТдаСм ΠΏΠ°ΠΌΡΡ‚ΡŒ, Π·Π°Π½ΡΡ‚ΡƒΡŽ `view_port`: ```c gui_remove_view_port(app->gui, app->view_port); view_port_free(app->view_port); ``` Π’ ΠΊΠΎΠ½Ρ†Π΅ ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘ΠΌ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ графичСским интСрфСйсом ΠΎΡ‚ нашСго прилоТСния ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ систСмС: ```c furi_record_close(RECORD_GUI); ``` Π’Π°ΠΊ ΠΊΠ°ΠΊ ΠΌΡ‹ пишСм Π½Π° Π‘ ΠΈ рСгулярно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ, Π² ядрС FURI сущСствуСт ΠΊΡ€Π°ΠΉΠ½Π΅ полСзная для нас функция `furi_assert()`, которая экстрСнно остановит Ρ€Π°Π±ΠΎΡ‚Ρƒ прилоТСния ΠΈ выдаст сообщСниС, Ссли ΠΌΡ‹ Π²Π΄Ρ€ΡƒΠ³ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΄ΠΈΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° пустой участок памяти. Π’ΠΎΡ‡ΠΊΠΎΠΉ Π²Ρ…ΠΎΠ΄Π° прилоТСния Π½Π° этот Ρ€Π°Π· Π±ΡƒΠ΄Π΅Ρ‚ функция с ΠΈΠΌΠ΅Π½Π΅ΠΌ `example_2_app`: ```c 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`. ```c 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", ) ``` Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅: ```sh ./fbt fap_example_2 ``` Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ qFlipper, пСрСнСсём Π½ΠΎΠ²ΠΎΠ΅ FAP-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ· ΠΏΠ°ΠΏΠΊΠΈ `build` Π½Π° SD-ΠΊΠ°Ρ€Ρ‚Ρƒ Π² ΠΏΠ°ΠΏΠΊΡƒ `/apps/Misc`. Или ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π» ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ `./fbt fap_deploy`. Находим Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² спискС ΠΈ запускаСм Π΅Π³ΠΎ: ![](/content/images/2023/flipper-app/8.png) БСйчас для нашСго `ViewPort` Π½Π΅ описаны ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ отрисовки графичСских ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ². ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° прилоТСния просто ΠΎΡ‚ΠΎΠ±Ρ€Π°Π·ΠΈΡ‚ пустой графичСский интСрфСйс Π² Ρ‚Π΅Ρ‡Π΅Π½ΠΈΠ΅ 10 сСкунд ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎ: https://youtu.be/7LlnIKkdM8s. ## ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 3. ВСкст ΠΈ изобраТСния Π”ΠΎΠ±Π°Π²ΠΈΠΌ Π² интСрфСйс нашСго прилоТСния ΠΊΠ°ΠΊΠΈΠ΅-Π½ΠΈΠ±ΡƒΠ΄ΡŒ графичСскиС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹. НСкоторыС графичСскиС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ ΠΌΠΎΠ³ΡƒΡ‚ ΠΈΠΌΠ΅Ρ‚ΡŒ довольно ΡΠ»ΠΎΠΆΠ½ΡƒΡŽ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€: мСню, Π²Ρ‹ΠΏΠ°Π΄Π°ΡŽΡ‰ΠΈΠ΅ списки, Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹Π΅ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ‹, Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ Ρ„ΠΎΡ€ΠΌΡ‹ Π²Π²ΠΎΠ΄Π°. ΠœΡ‹ ΠΆΠ΅ Π½Π°Ρ‡Π½Ρ‘ΠΌ с простых ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ². Π‘Π½ΠΎΠ²Π° создадим копию ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π³ΠΎ прилоТСния, Π½ΠΎ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΠΎΠ΄ ΠΈΠΌΠ΅Π½Π΅ΠΌ `example_3`. Для Ρ€Π΅Π½Π΄Π΅Ρ€Π° графичСских ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² создадим Π² исходном Ρ„Π°ΠΉΠ»Π΅ `example_3_app.c` `callback`-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ отрисовки `example_3_app_draw_callback`: ```c static void example_3_app_draw_callback(Canvas* canvas, void* ctx) { UNUSED(ctx); canvas_clear(canvas); } ``` Callback-функция ΠΈΠΌΠ΅Π΅Ρ‚ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΡƒΡŽ сигнатуру ΠΈ Π΄Π²Π° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π° `canvas`, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ «холст», Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ, ΠΈ контСкст `ctx`. ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ΠΎΠΌ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Π΅, Π² зависимости ΠΎΡ‚ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… рСндСрится `canvas`. Пока Ρ‡Ρ‚ΠΎ ΠΌΡ‹ оставим контСкст Π½Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Π½Ρ‹ΠΌ, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ `UNUSED`. ΠŸΠ΅Ρ€Π²Ρ‹ΠΌ Π΄Π΅Π»ΠΎΠΌ ΠΏΠ΅Ρ€Π΅Π΄ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΎΠΌ очистим наш экран: ```c canvas_clear(canvas); ``` ГрафичСскиС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ Ρ€Π°Π·ΠΌΠ΅Ρ‰Π°ΡŽΡ‚ΡΡ Π½Π° экранС согласно систСмС ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚. Π­ΠΊΡ€Π°Π½ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π° ΠΈΠΌΠ΅Π΅Ρ‚ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ **128Γ—64**, Π° Π½Π°Ρ‡Π°Π»ΠΎ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ находится Π² Π»Π΅Π²ΠΎΠΌ Π²Π΅Ρ€Ρ…Π½Π΅ΠΌ ΡƒΠ³Π»Ρƒ: ![](/content/images/2023/flipper-app/9.png) Π”ΠΎΠ±Π°Π²ΠΈΠΌ тСкст Π² интСрфСйс нашСго прилоТСния. ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» с графичСскими тСкстовыми элСмСнтами `gui/elements.h`. ВСкст отрисовываСтся Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ `canvas_draw_str()` с ΡƒΠΊΠ°Π·Π°Π½ΠΈΠ΅ΠΌ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ (`x` ΠΈ `y`) исходной Ρ‚ΠΎΡ‡ΠΊΠΈ тСкста ΠΈ, собствСнно, самой строки. Π’ΠΎΠ·ΠΌΠΎΠΆΠ΅Π½ Π²Ρ‹Π±ΠΎΡ€ ΡˆΡ€ΠΈΡ„Ρ‚Π° для тСкста. Π¨Ρ€ΠΈΡ„Ρ‚ устанавливаСтся Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ `canvas_set_font()`. Π¨Ρ€ΠΈΡ„Ρ‚ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π³Π»Π°Π²Π½Ρ‹ΠΌ β€” `FontPrimary` (высота 8 пиксСлСй), второстСпСнным β€” `FontSecondary` (высота 7 пиксСлСй), `FontKeyboard` ΠΈΠ»ΠΈ `FontBigNumbers`. ΠŸΡ€ΠΈ ΠΆΠ΅Π»Π°Π½ΠΈΠΈ Π²Ρ‹ смоТСтС ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΈ собствСнный ΡˆΡ€ΠΈΡ„Ρ‚. НапримСр, напишСм Π³Π»Π°Π²Π½Ρ‹ΠΌ ΡˆΡ€ΠΈΡ„Ρ‚ΠΎΠΌ строку Β«**This is an example app!**Β» Π²Π²Π΅Ρ€Ρ…Ρƒ экрана ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ ΠΏΠΎ Ρ†Π΅Π½Ρ‚Ρ€Ρƒ, ΠΏΠΎ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π°ΠΌ (`4` ΠΈ `8`). По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π½Π°Ρ‡Π°Π»ΠΎ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ тСкста находится Π² Π»Π΅Π²ΠΎΠΌ Π½ΠΈΠΆΠ½Π΅ΠΌ ΡƒΠ³Π»Ρƒ. ```c 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()`: ```c 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** пиксСлСй: ![](/content/images/2023/flipper-app/amperka_ru_logo_128x35px.png) Π’ ΠΏΠ°ΠΏΠΊΠ΅ с вашим ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ создайтС ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΡƒΡŽ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ для хранСния ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ. НапримСр, ΠΌΡ‹ Π½Π°Π·Π²Π°Π»ΠΈ свою ΠΏΠ°ΠΏΠΊΡƒ `images`. Π’ Π΄Π°Π½Π½ΡƒΡŽ ΠΏΠ°ΠΏΠΊΡƒ помСститС всС изобраТСния, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠ»Π°Π½ΠΈΡ€ΡƒΠ΅Ρ‚Π΅ Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ΡŒ Π½Π° экран. ΠœΡ‹ Π½Π°Π·Π²Π°Π»ΠΈ Π½Π°ΡˆΡƒ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΡƒ `amperka_ru_logo_128x35px.png` ΠΈ помСстили Π΅Ρ‘ Π² ΡΠΎΠ·Π΄Π°Π½Π½ΡƒΡŽ ΠΏΠ°ΠΏΠΊΡƒ `images`: ![](/content/images/2023/flipper-app/10.png) Π’ манифСстС прилоТСния `application.fam` добавляСм Π½ΠΎΠ²Ρ‹ΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ `fap_icon_assets` с ΠΏΡƒΡ‚Ρ‘ΠΌ Π΄ΠΎ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ с изобраТСниями: ```c 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`. Π”ΠΎΠ±Π°Π²ΠΈΠΌ Π΄Π°Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ прилоТСния: ```c #include "example_3_icons.h" ``` Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° ΠΎΠ±Π»Π°ΡΡ‚ΡŒ памяти, Π³Π΄Π΅ хранится нашС ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π² Π²ΠΈΠ΄Π΅ массива Π±Π°ΠΉΡ‚ΠΎΠ². Имя указатСля Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΠΌΠ΅Π½ΠΈ самого Ρ„Π°ΠΉΠ»Π° изобраТСния, Π½ΠΎ с приставкой `I_ИМЯ_Π’ΠΠ¨Π•Π“Πž_ЀАЙЛА`. Для нашСй ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠΈ с ΠΈΠΌΠ΅Π½Π΅ΠΌ `amperka_ru_logo_128x35px.png` имя указатСля Π±ΡƒΠ΄Π΅Ρ‚ `I_amperka_ru_logo_128x35px`. Π’Π΅ΠΏΠ΅Ρ€ΡŒ, имСя адрСс изобраТСния, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΡ‚Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ‚ΡŒ Π΅Π³ΠΎ Π½Π° экранС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ `canvas_draw_icon()`. Π’Ρ‹Π²Π΅Π΄Π΅ΠΌ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π²Π½ΠΈΠ·Ρƒ экрана ΠΏΠΎ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π°ΠΌ (`0` ΠΈ `29`): ```c canvas_draw_icon(canvas, 0, 29, &I_amperka_ru_logo_128x35px); ``` Пока Ρ‡Ρ‚ΠΎ Ρ…Π²Π°Ρ‚ΠΈΡ‚ графичСских элСмСнтов. Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ: ![](/content/images/2023/flipper-app/11.png) Наша `callback`-функция отрисовки Π³ΠΎΡ‚ΠΎΠ²Π°, ΠΈ Π΅Ρ‘ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΡ€ΠΈΠ²ΡΠ·Π°Ρ‚ΡŒ ΠΊ структурС `ViewPort` нашСго прилоТСния. Π­Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ нашСго прилоТСния сразу послС выдСлСния памяти ΠΏΠΎΠ΄ `ViewPort`. Π’ качСствС контСкста ΠΌΡ‹ Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ отправляСм (`NULL`). ПослС привязки ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ Ρ€Π°Π· `callback`-функция Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π° автоматичСски. ```c view_port_draw_callback_set(app->view_port, example_3_app_draw_callback, NULL); ``` Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» нашСго Ρ‚Ρ€Π΅Ρ‚ΡŒΠ΅Π³ΠΎ прилоТСния Π½Π΅ измСнился, Π·Π° ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ΠΌ ΠΈΠΌΠ΅Π½ΠΈ прилоТСния ΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌΠΎΠ³ΠΎ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ° с изобраТСниями. Код `example_3_app.h`: ```c #pragma once #include #include #include "example_3_icons.h" struct Example3App { Gui* gui; ViewPort* view_port; }; typedef struct Example3App Example3App; ``` Код `example_3_app.с`: ```c #include "example_3_app.h" #include #include #include 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 сСкунд ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ свою Ρ€Π°Π±ΠΎΡ‚Ρƒ, Π½ΠΎ Π½Π° этот Ρ€Π°Π· Ρƒ нас Π±ΡƒΠ΄Π΅Ρ‚ Π³Ρ€Π°Ρ„ΠΈΠΊΠ°. Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅: ```sh ./fbt fap_example_3 ``` Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ qFlipper, пСрСнСсём Π½ΠΎΠ²ΠΎΠ΅ FAP-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ· ΠΏΠ°ΠΏΠΊΠΈ `build` Π½Π° SD-ΠΊΠ°Ρ€Ρ‚Ρƒ Π² ΠΏΠ°ΠΏΠΊΡƒ `/apps/Misc`. Или ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π» ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ `./fbt fap_deploy`. Находим Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² спискС ΠΈ запускаСм Π΅Π³ΠΎ: ![](/content/images/2023/flipper-app/12.png) Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎ: https://youtu.be/RNyTfBK4074. ## ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 4. Кнопки РазбСрёмся, ΠΊΠ°ΠΊ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ наТатия ΠΊΠ½ΠΎΠΏΠΎΠΊ Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅. ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Π΅ΠΌ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ΄ Π½ΠΎΠ²Ρ‹ΠΌ ΠΈΠΌΠ΅Π½Π΅ΠΌ `example_4`. Для использования ΠΊΠ½ΠΎΠΏΠΎΠΊ Π½Π°ΠΌ понадобится ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ сообщСний (`MessageQueue`) ΠΈ Π΅Ρ‰Ρ‘ ΠΎΠ΄Π½Π° `callback`-функция для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ этой ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ. **Π—Π°Ρ‡Π΅ΠΌ Π½ΡƒΠΆΠ½Π° ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ сообщСний?** ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Π·Π° нас Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ опСрационная систСма, Ρ‚ΠΎ `callback`-функция Π²Π²ΠΎΠ΄Π° с ΠΊΠ½ΠΎΠΏΠΎΠΊ, ΠΊΠ°ΠΊ ΠΈ `callback`-функция Ρ€Π΅Π½Π΄Π΅Ρ€Π° Π³Ρ€Π°Ρ„ΠΈΠΊΠΈ выполняСтся Π² контСкстС Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² ОБ Flipper Zero, Π° Π½Π΅ Π² ΠΏΠΎΡ‚ΠΎΠΊΠ΅ нашСго прилоТСния. ΠŸΠΎΡ‚ΠΎΠΊ, ΠΎΡ‚Π²Π΅Ρ‡Π°ΡŽΡ‰ΠΈΠΉ Π·Π° Π½Π°ΠΆΠ°Ρ‚ΠΈΠ΅ ΠΊΠ½ΠΎΠΏΠΎΠΊ, Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ ΠΊΠ°ΠΊΡƒΡŽ-Π»ΠΈΠ±ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ ΠΈΠ· нашСго прилоТСния. Но ΠΏΠΎΡ‚ΠΎΠΊΠΈ ΠΌΠΎΠ³ΡƒΡ‚ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ Π΄Ρ€ΡƒΠ³ Π΄Ρ€ΡƒΠ³Ρƒ сообщСния Π² любой ΠΌΠΎΠΌΠ΅Π½Ρ‚ выполнСния, этим ΠΌΡ‹ ΠΈ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡΡ. ДобавляСм Π² структуру нашСго прилоТСния `Example4App` ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ `event_queue` Ρ‚ΠΈΠΏΠ° `FuriMessageQueue`: ```c struct Example4App { Gui* gui; ViewPort* view_port; FuriMessageQueue* event_queue; }; ``` Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ прилоТСния `example_4_app_alloc()` выдСляСм ΠΏΠ°ΠΌΡΡ‚ΡŒ ΠΏΠΎΠ΄ Π½ΠΎΠ²ΡƒΡŽ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ. ```c app->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); ``` Наша ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ Π±ΡƒΠ΄Π΅Ρ‚ Π½Π° 8 сообщСний Ρ‚ΠΈΠΏΠ° `InputEvent`, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ Π·Π° Π½Π°ΠΆΠ°Ρ‚ΠΈΠ΅ клавиш. Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с сообщСниями ΠΎΡ‚ ΠΊΠ½ΠΎΠΏΠΎΠΊ находятся Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ `input/input.h`. Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ освобоТдСния памяти нашСго прилоТСния, соотвСтствСнно, освобоТдаСм Π·Π°Π½ΡΡ‚ΡƒΡŽ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒΡŽ ΠΏΠ°ΠΌΡΡ‚ΡŒ. ```c furi_message_queue_free(app->event_queue); ``` Π’Π΅ΠΏΠ΅Ρ€ΡŒ создадим `callback`-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ этой ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ. ```c 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`: ```c view_port_input_callback_set(app->view_port, example_4_app_input_callback, app->event_queue); ``` Π“ΠΎΡ‚ΠΎΠ²ΠΎ! Π’Π΅ΠΏΠ΅Ρ€ΡŒ информация ΠΎ состоянии ΠΊΠ½ΠΎΠΏΠΎΠΊ находится Π² нашСм распоряТСнии, ΠΈ Π΅Ρ‘ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ. БСйчас нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ 10 сСкунд, Π° Π·Π°Ρ‚Π΅ΠΌ Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ. Π”Π°Π²Π°ΠΉΡ‚Π΅ сдСлаСм Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π·Π°ΠΊΡ€Ρ‹Π²Π°Π»ΠΎΡΡŒ Π½Π΅ автоматичСски, Π° ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ Π½Π° ΠΊΠ»Π°Π²ΠΈΡˆΡƒ Β«**Назад**Β» Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π΅. ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ сообщСний ΠΈΠ· ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ напишСм Π² Π³Π»Π°Π²Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ нашСго прилоТСния (Ρ‚ΠΎΡ‡ΠΊΠ΅ Π²Ρ…ΠΎΠ΄Π°) Π² бСсконСчном Ρ†ΠΈΠΊΠ»Π΅: ```c 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`: ```c #pragma once #include #include #include "example_4_icons.h" struct Example4App { Gui* gui; ViewPort* view_port; FuriMessageQueue* event_queue; }; typedef struct Example4App Example4App; ``` Код `example_4_app.с`: ```c #include "example_4_app.h" #include #include #include #include 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. ```sh ./fbt fap_example_4 ./fbt fap_deploy ``` ![](/content/images/2023/flipper-app/13.png) Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎ: https://youtu.be/PlClOH5_yB0. ИзмСним нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π΅Ρ‰Ρ‘ ΠΏΠ°Ρ€Ρƒ ΠΊΠ½ΠΎΠΏΠΎΠΊ. НапримСр, Π±ΡƒΠ΄Π΅ΠΌ ΠΏΠΎ-Ρ€Π°Π·Π½ΠΎΠΌΡƒ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ‚ΡŒ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π½Π° экранС Π² зависимости ΠΎΡ‚ Π½Π°ΠΆΠ°Ρ‚ΠΎΠΉ ΠΊΠ½ΠΎΠΏΠΊΠΈ. ΠŸΡƒΡΡ‚ΡŒ Ρƒ нас Π±ΡƒΠ΄Π΅Ρ‚ Ρ‚Ρ€ΠΈ состояния интСрфСйса: рСндСрится Ρ‚ΠΎΠ»ΡŒΠΊΠΎ тСкст, рСндСрится Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅, Π»ΠΈΠ±ΠΎ рСндСрится ΠΈ Ρ‚ΠΎ, ΠΈ Π΄Ρ€ΡƒΠ³ΠΎΠ΅. ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒΡΡ ΠΌΠ΅ΠΆΠ΄Ρƒ этими Ρ€Π΅ΠΆΠΈΠΌΠ°ΠΌΠΈ Π±ΡƒΠ΄Π΅ΠΌ ΠΏΡ€ΠΈ Π΄ΠΎΠ»Π³ΠΎΠΌ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ Π½Π° ΠΊΠ½ΠΎΠΏΠΊΠΈ Β«Π’Π»Π΅Π²ΠΎΒ» ΠΈΠ»ΠΈ Β«Π’ΠΏΡ€Π°Π²ΠΎΒ». Π’Π²Π΅Π΄Ρ‘ΠΌ Π² структуру нашСго прилоТСния ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ, которая Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚Π²Π΅Ρ‡Π°Ρ‚ΡŒ Π·Π° Ρ‚ΠΎ, ΠΊΠ°ΠΊΠΎΠΉ Ρ€Π΅ΠΆΠΈΠΌ рСндСрится Π² Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚. НазовСм Π΅Ρ‘ `draw_mode`. ```c 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` Π² качСствС контСкста: ```c view_port_draw_callback_set(app->view_port, example_4_app_draw_callback, app); ``` Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠΌ саму `callback`-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ Ρ€Π΅Π½Π΄Π΅Ρ€Π°. ΠŸΡƒΡΡ‚ΡŒ Ρ€Π°Π·Π½Ρ‹Π΅ графичСскиС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ рСндСрятся Π² зависимости ΠΎΡ‚ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ значСния `draw_mode`: ```c 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"); } } ``` Π’ Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ Π½ΠΎΠ²Ρ‹Π΅ события ΠΊΠ½ΠΎΠΏΠΎΠΊ Π² бСсконСчном Ρ†ΠΈΠΊΠ»Π΅ Π³Π»Π°Π²Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ прилоТСния: ```c 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`: ```c struct Example5App { Gui* gui; ViewPort* view_port; FuriMessageQueue* event_queue; NotificationApp* notifications; DrawMode draw_mode; }; ``` Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ прилоТСния `example_5_app_alloc()` ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚Ρ‹Π²Π°Π΅ΠΌ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ оповСщСниями: ```c app->notifications = furi_record_open(RECORD_NOTIFICATION); ``` А Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ освобоТдСния памяти прилоТСния `example_5_app_free` ΠΎΡ‚Π΄Π°Ρ‘ΠΌ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ: ```c furi_record_close(RECORD_NOTIFICATION); ``` МоТно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ Π³ΠΎΡ‚ΠΎΠ²Ρ‹Π΅ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ сообщСний, Π° ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΈΡ… ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ, это нСслоТно. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» ΠΈ ΠΊΠ°ΠΊΠΈΠ΅ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Ρ‚Π°ΠΌ доступны. Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π½Π°ΡˆΡƒ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ сообщСний для управлСния RGB-свСтодиодом. НазовСм Π΅Ρ‘ `example_led_sequence` ΠΈ размСстим Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ΅ нашСго прилоТСния. ΠŸΡƒΡΡ‚ΡŒ свСтодиод ΠΌΠΈΠ³Π½Ρ‘Ρ‚ Ρ„ΠΈΠΎΠ»Π΅Ρ‚ΠΎΠ²Ρ‹ΠΌ Ρ†Π²Π΅Ρ‚ΠΎΠΌ **RGB(255, 0, 255)** Ρ‚Ρ€ΠΈ Ρ€Π°Π·Π° с ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»ΠΎΠΌ **500 мс**, Π° Π·Π°Ρ‚Π΅ΠΌ погаснСт. Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ: ```c 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 сСкунды, Π° Π·Π°Ρ‚Π΅ΠΌ Π²Ρ‹ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡΡ. ΠŸΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ сообщСний Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ Ρ‚Π°ΠΊ: ```c 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**: ![](/content/images/2023/flipper-app/sound.png) ΠŸΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ сообщСний с Π΄Π°Π½Π½ΠΎΠΉ ΠΌΠ΅Π»ΠΎΠ΄ΠΈΠ΅ΠΉ выглядит Ρ‚Π°ΠΊ: ```c 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()`: ```c 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()` с ΡƒΠΊΠ°Π·Π°Π½ΠΈΠ΅ΠΌ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΉ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ. Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅: ```sh ./fbt fap_example_5 ``` Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ qFlipper, пСрСносим Π½ΠΎΠ²Ρ‹ΠΉ FAP-Ρ„Π°ΠΉΠ» ΠΈΠ· ΠΏΠ°ΠΏΠΊΠΈ `build` Π½Π° SD-ΠΊΠ°Ρ€Ρ‚Ρƒ Π² ΠΏΠ°ΠΏΠΊΡƒ `/apps/Misc`. Или Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ `./fbt fap_deploy`. ЗапускаСм ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅: ![](/content/images/2023/flipper-app/14.png) Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎ: https://youtu.be/238dmsw5DA4. ## ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 6. GPIO На Flipper Zero 18 ΠΊΠΎΠ½Ρ‚Π°ΠΊΡ‚ΠΎΠ² **GPIO**, срСди ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π΅ΡΡ‚ΡŒ ΠΊΠ°ΠΊ ΠΏΠΈΠ½Ρ‹ питания, Ρ‚Π°ΠΊ ΠΈ ΠΏΠΈΠ½Ρ‹ Π²Π²ΠΎΠ΄Π°-Π²Ρ‹Π²ΠΎΠ΄Π°. ЛогичСскоС напряТСниС питания β€” **3,3Π’**, ΠΈ ΠΏΠΈΠ½Ρ‹ Π½Π΅Ρ‚ΠΎΠ»Π΅Ρ€Π°Π½Ρ‚Π½Ρ‹ ΠΊ **5Π’** (Π·Π° ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ΠΌ ΠΏΠΈΠ½Π° `iButton`). По сути, ΠΏΠΈΠ½Ρ‹ Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π° ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‚ ΠΏΠΈΠ½Π°ΠΌ установлСнного Π² Π½Ρ‘ΠΌ ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π° `STM32WB55` ΠΈ ΠΎΠ±Π»Π°Π΄Π°ΡŽΡ‚ Ρ‚Π΅ΠΌΠΈ ΠΆΠ΅ настраиваСмыми Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΌΠΈ функциями (`ADC`, `USART`, `SPI` ΠΈ Π΄Ρ€.). Распиновка Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π°: ![](/content/images/2023/flipper-app/pinout.png) ΠŸΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎΠ΅ Π½Π°Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΈΠ½ΠΎΠ² ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ `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Π’**. Установим свСтодиод ΠΈ ΠΊΠ½ΠΎΠΏΠΊΡƒ Π½Π° ΠΌΠ°ΠΊΠ΅Ρ‚Π½ΡƒΡŽ ΠΏΠ»Π°Ρ‚Ρƒ: ![](/content/images/2023/flipper-app/breadboard-1.jpg) Назовём Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ `example_6` ΠΈ сдСлаСм Π΅Π³ΠΎ Π½Π° основС нашСго ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° Π½ΠΎΠΌΠ΅Ρ€ 4. ΠŸΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΡƒΠ±Π΅Ρ€Ρ‘ΠΌ ΠΈΠ· прилоТСния всё, Ρ‡Ρ‚ΠΎ касаСтся ΠΎΠΏΠΎΠ²Π΅Ρ‰Π΅Π½ΠΈΠΉ, Ρ€Π΅Π½Π΄Π΅Ρ€Π° графичСских элСмСнтов ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΊΠ½ΠΎΠΏΠΎΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ остался пустой интСрфСйс. Для управлСния GPIO Π½Π°ΠΌ Π½ΡƒΠΆΠ΅Π½ HAL Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π°. ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Ρ„Π°ΠΉΠ» `furi_hal.h` Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ нашСго прилоТСния. Π’ Π³Π»Π°Π²Π½ΠΎΠΉ структурС `Example6App` нашСго прилоТСния создадим Π΄Π²Π° ΠΏΠΈΠ½Π° для Π²Ρ…ΠΎΠ΄Π° ΠΈ Π²Ρ‹Ρ…ΠΎΠ΄Π°: `input_pin`, `output_pin` ΠΈ Π΄Π²Π΅ Π±ΡƒΠ»Π΅Π²Ρ‹ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ для хранСния Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΡ… Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Π½Π° этих ΠΏΠΈΠ½Π°Ρ…: `input_value`, `output_value`. Наш Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Π²ΠΈΠ΄: ```c #pragma once #include #include #include 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`: ```c 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()` (ΠΈ ΠΏΠΎ ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΡ‚Π΅Π»ΡŒΡΡ‚Π²Ρƒ Π² нашСй Ρ‚ΠΎΡ‡ΠΊΠ΅ Π²Ρ…ΠΎΠ΄Π°) считываСм ΠΈ отправляСм ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ значСния Π² бСсконСчном Ρ†ΠΈΠΊΠ»Π΅: ```c furi_hal_gpio_write(app->output_pin, app->output_value); app->input_value = furi_hal_gpio_read(app->input_pin); ``` ΠŸΡƒΡΡ‚ΡŒ Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ зависит ΠΎΡ‚ состояния ΠΊΠ½ΠΎΠΏΠΊΠΈ «Ок» Π€Π»ΠΈΠΏΠΏΠ΅Ρ€Π°. Кнопка Π½Π°ΠΆΠ°Ρ‚Π° β€” сигнал Π΅ΡΡ‚ΡŒ, ΠΎΡ‚ΠΆΠ°Ρ‚Π° β€” сигнала Π½Π΅Ρ‚. Как ΠΈ ΠΏΡ€Π΅ΠΆΠ΄Π΅, клавишСй «Назад» Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅ΠΌ Ρ€Π°Π±ΠΎΡ‚Ρƒ прилоТСния. Π”ΠΎΠ±Π°Π²ΠΈΠΌ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΡƒΡŽ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ ΠΊΠ½ΠΎΠΏΠΊΠΈ «Ок» Π² бСсконСчный Ρ†ΠΈΠΊΠ» нашСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹: ```c 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`. Π’ качСствС контСкста ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘ΠΌ Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ отрисовки Π³Π»Π°Π²Π½ΡƒΡŽ структуру прилоТСния. ```c 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"); } ``` Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ Ρ‚Π°ΠΊ: ![](/content/images/2023/flipper-app/15.png) Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ Π΅Π³ΠΎ Π½Π° Π€Π»ΠΈΠΏΠΏΠ΅Ρ€: ```sh ./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/](https://github.com/flipperdevices/flipperzero-firmware/tree/dev/applications/plugins/signal_generator) ΠΈ Ρ€Π΅ΠΏΠ»ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ Π² вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅. А Π²ΠΎΡ‚ ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΉ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ Π½Π° Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ Π°Π½Π°Π»ΠΎΠ³ΠΎΠ²Ρ‹Ρ… сигналов ΠΏΠΎΠΊΠ° Π½Π΅Ρ‚. ΠšΡ€ΠΎΠΌΠ΅ этого Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π°Π½Π°Π»ΠΎΠ³ΠΎ-Ρ†ΠΈΡ„Ρ€ΠΎΠ²ΠΎΠ³ΠΎ прСобразоватСля Π½Π° ΠΏΠΈΠ½Π°Ρ… Π΅Ρ‰Ρ‘ Π½Π΅ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Ρ‹ Π² FURI HAL. Однако сам ADC Π½Π° ΠΌΠΈΠΊΡ€ΠΎΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π΅ STM32 ΠΈ Π΅Π³ΠΎ возмоТности Π½ΠΈΠΊΡƒΠ΄Π° ΠΎΡ‚ нас Π½Π΅ дСлись. На просторах ΠΈΠ½Ρ‚Π΅Ρ€Π½Π΅Ρ‚Π° ΠΌΡ‹ нашли ΠΏΡ€ΠΈΠΌΠ΅Ρ€ использования **ADC**. ΠœΡ‹ размСстили Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ с ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°ΠΌΠΈ [flipperzero-examples](https://github.com/amperka/flipperzero-examples) ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ [`adc_example`](https://github.com/amperka/flipperzero-examples/tree/main/applications/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!