From dcc81ec8ccd1e4561ca77c291f6c3c89d9fadd18 Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Mon, 27 Mar 2023 22:47:27 +0300 Subject: [PATCH] flipper app examples --- content/posts/2023/flipper-zero/make-app.md | 1552 +++++++++++++++++++ 1 file changed, 1552 insertions(+) create mode 100644 content/posts/2023/flipper-zero/make-app.md diff --git a/content/posts/2023/flipper-zero/make-app.md b/content/posts/2023/flipper-zero/make-app.md new file mode 100644 index 0000000..ec15a3d --- /dev/null +++ b/content/posts/2023/flipper-zero/make-app.md @@ -0,0 +1,1552 @@ +--- +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!