---
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 <furi.h>

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

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

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

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

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

![](/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 <furi.h>
#include <gui/gui.h>

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

typedef struct Example2App Example2App;
```

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

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

```c
#include "example_2_app.h"

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

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

    app->view_port = view_port_alloc();

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

    return app;
}

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

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

    furi_record_close(RECORD_GUI);
}

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

    furi_delay_ms(10000);

    example_2_app_free(app);
    return 0;
}
```

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

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

```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 <furi.h>
#include <gui/gui.h>

#include "example_3_icons.h"

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

typedef struct Example3App Example3App;
```

Код `example_3_app.с`:

```c
#include "example_3_app.h"

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

#include <gui/elements.h>

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

    canvas_clear(canvas);

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

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

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

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

    app->view_port = view_port_alloc();

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

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

    return app;
}

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

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

    furi_record_close(RECORD_GUI);
}

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

    furi_delay_ms(10000);

    example_3_app_free(app);
    return 0;
}
```

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

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

```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 <furi.h>
#include <gui/gui.h>

#include "example_4_icons.h"

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

typedef struct Example4App Example4App;
```

Код `example_4_app.с`:

```c
#include "example_4_app.h"

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

#include <input/input.h>

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

    canvas_clear(canvas);

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

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

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

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

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

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

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

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

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

    return app;
}

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

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

    furi_message_queue_free(app->event_queue);

    furi_record_close(RECORD_GUI);
}

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

    InputEvent event;

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

    example_4_app_free(app);
    return 0;
}
```

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

```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 <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>

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

    const GpioPin* input_pin;
    const GpioPin* output_pin;

    bool input_value;
    bool output_value;
};

typedef struct Example6App Example6App;
```

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

```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!