-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
218 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
.. _lilka-lib: | ||
|
||
Бібліотека ``lilka`` | ||
==================== | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
Написання програм на C++ | ||
======================== | ||
|
||
.. contents:: Зміст | ||
:local: | ||
|
||
Що таке програма в Keira? | ||
------------------------- | ||
|
||
Keira написана на C++, і вона містить ряд вбудованих програм. Програма в Keira - це клас, який наслідує клас :cpp:class:`App` та визначає метод :cpp:func:`App::run`. Цей метод викликається при запуску програми. | ||
|
||
Всі програми є вбудованими, тобто вони мають бути частиною Keira. Це означає, що ви не можете додати свою програму до Keira, якщо не зміните код Keira і не перепрошиєте Лілку новим кодом. | ||
|
||
Ви можете використовувати будь-які функції з :ref:`бібліотеки Lilka <lilka-lib>`. | ||
|
||
.. note:: | ||
|
||
*Чи можу я написати свою програму на C++ окремо від Keira, якось скомпілювати її і запустити в Keira з SD-карти?* | ||
|
||
Ні. Динамічне завантаження програм у вбудованих системах - це дуже складний процес. Keira наразі не підтримує цю функцію. Але це може змінитись в майбутньому. | ||
|
||
Якщо ви хочете писати програми, не перепрошиваючи Лілку, ми радимо спробувати вам Lua: :ref:`lua-intro`. | ||
|
||
Клас :cpp:class:`App` | ||
--------------------- | ||
|
||
Для створення власної програми вам потрібно наслідувати клас :cpp:class:`App` та визначити метод :cpp:func:`App::run`. Цей метод буде викликатися при запуску програми. | ||
|
||
.. doxygenclass:: App | ||
:members: | ||
:protected-members: | ||
:private-members: | ||
|
||
Приклад програми | ||
---------------- | ||
|
||
Давайте створимо просту програму, яка буде малювати круг на екрані, який можна переміщувати за допомогою кнопок. | ||
|
||
Для цього створіть два нові файли в директорії ``firmware/keira/src/apps``: | ||
|
||
.. code-block:: cpp | ||
:caption: myapp.h | ||
#include <lilka.h> | ||
#include "app.h" | ||
class MyApp : public App { | ||
public: | ||
MyApp(); | ||
private: | ||
void run() override; | ||
}; | ||
.. code-block:: cpp | ||
:caption: myapp.cpp | ||
#include "myapp.h" | ||
MyApp::MyApp() : App("Моя програма") { | ||
} | ||
void MyApp::run() { | ||
int16_t x = canvas->width() / 2; | ||
int16_t y = canvas->height() / 2; | ||
while (true) { | ||
// читаємо стан кнопок | ||
lilka::State state = lilka::controller.getState(); | ||
if (state.up.pressed) { | ||
y--; | ||
} else if (state.down.pressed) { | ||
y++; | ||
} | ||
if (state.left.pressed) { | ||
x--; | ||
} else if (state.right.pressed) { | ||
x++; | ||
} | ||
if (state.a.pressed) { | ||
// Завершуємо програму | ||
return; | ||
} | ||
// заповнюємо екран чорним кольором | ||
canvas->fillScreen(canvas->color565(0, 0, 0)); | ||
// малюємо білий круг | ||
canvas->fillCircle(x, y, 10, canvas->color565(255, 255, 255)); | ||
// повідомляємо Keira, що буфер змінився і його потрібно перемалювати | ||
queueDraw(); | ||
} | ||
} | ||
Давайте розберемося з кодом. | ||
|
||
1. Ми створили клас ``MyApp``, який наслідує клас ``App``. | ||
|
||
``App`` містить в собі віртуальний метод ``run``, який викликається при запуску програми. | ||
|
||
Також ``App`` автоматично створює об'єкт ``canvas``, який представляє собою буфер для малювання. Ви повинні малювати саме на ньому, а не на екрані. Детальніше про це - згодом. | ||
|
||
2. Весь код нашої програми знаходиться в методі ``run``. Він автоматично викликається при запуску програми. | ||
|
||
Програма виконується в циклі ``while (true)``. Це означає, що вона буде виконуватися постійно, поки ви не викличете ``return``. | ||
|
||
3. Ми читаємо стан кнопок за допомогою ``lilka::controller.getState()``. Це повертає об'єкт ``lilka::State``, який містить в собі стан кожної кнопки. | ||
|
||
Наприклад, ``state.up.pressed`` - це ``true``, якщо кнопка ``up`` натиснута. | ||
|
||
4. Ми щоразу заповнюємо екран чорним кольором, малюємо білий круг, а потім викликаємо ``queueDraw()``. | ||
|
||
Цей метод повідомляє Keira, що буфер змінився і його потрібно перемалювати. | ||
|
||
.. note:: | ||
|
||
*Чому ми не малюємо безпосередньо на екрані, і чому щоразу заповнюємо його чорним кольором? І що таке** ``queueDraw()``? | ||
|
||
Це все пов'язано з тим, що Keira - це мультизадачна операційна система, і різні програми можуть намагатись одночасно малювати щось на екрані. | ||
|
||
Щоб уникнути конфліктів, Keira використовує `подвійну буферизацію <https://uk.wikipedia.org/wiki/%D0%91%D0%B0%D0%B3%D0%B0%D1%82%D0%BE%D0%BA%D1%80%D0%B0%D1%82%D0%BD%D0%B0_%D0%B1%D1%83%D1%84%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D1%96%D1%8F#%D0%9F%D0%BE%D0%B4%D0%B2%D1%96%D0%B9%D0%BD%D0%B0_%D0%B1%D1%83%D1%84%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D1%96%D1%8F_%D1%83_%D0%BA%D0%BE%D0%BC%D0%BF'%D1%8E%D1%82%D0%B5%D1%80%D0%BD%D1%96%D0%B9_%D0%B3%D1%80%D0%B0%D1%84%D1%96%D1%86%D1%96>`_. | ||
Це означає, що кожна програма має два власні буфери: один ("передній") для малювання, а інший ("задній") - для відображення на екрані. | ||
|
||
- ``canvas`` - це передній буфер. Саме на ньому ваша програма малює все, що ви хочете побачити на екрані. | ||
- ``backCanvas`` - це задній буфер. Вам не потрібно ним керувати. | ||
|
||
Коли ви викликаєте метод ``queueDraw()``, Keira міняє місцями передній і задній буфери і через деякий час починає малювати задній буфер на екрані в фоновому режимі. | ||
Таким чином ваша програма ніколи не малює безпосередньо на екрані: це робить Keira, а конкретніше - клас ``AppManager``. | ||
|
||
``canvas`` завжди вказує на передній буфер, тому ви повинні малювати саме на ньому. | ||
Але оскільки ці буфери постійно міняються місцями, ваша програма не повинна робити жодних припущень про те, що було намальовано в попередній ітерації. | ||
|
||
Тому після кожного виклику ``queueDraw()`` кожна програма повинна знову малювати все, що ви хочете побачити на екрані, | ||
оскільки ``canvas`` буде містити "сміття", а не те, що ви малювали в попередній ітерації, | ||
і завжди відставатиме на одну ітерацію від того, що відображається на екрані. | ||
|
||
Це дає можливість не лише здійснювати конкурентне малювання на екрані з декількох програм, але й використовувати для цього обидва ядра процесора: | ||
одне ядро виконує вашу програму, а інше - перемальовує екран. | ||
Це збільшує FPS (кількість кадрів в секунду) і дозволяє досягнути максимальної утилізації процесора. | ||
|
||
Майте на увазі, що виклик ``queueDraw()`` може заблокувати вашу програму на деякий час. | ||
Це ставатиметься в ситуаціях, коли Кіра ще не завершила малювати на екрані попередній буфер, а ви вже викликаєте ``queueDraw()`` знову. | ||
Це - не проблема, але варто про це пам'ятати. | ||
|
||
В середньому, малювання займає близько 1/30 секунди. Це означає, що ви можете викликати ``queueDraw()`` близько 30 разів в секунду без блокування вашої програми. | ||
|
||
Реєстрація програми в меню програм | ||
---------------------------------- | ||
|
||
Основна програма, що запускається при завантаженні Кіри, називається ``Launcher``. Вона відповідає за відображення меню програм, налаштувань, інформації, а такоє запуск програм. | ||
|
||
Щоб програма з'явилася в меню програм, вам потрібно зареєструвати її в одному з меню ``Launcher``. Найпростіший спосіб - це додати вашу програму в меню додатків. | ||
Для цього знайдіть наступний код у файлі ``launcher.cpp`` та додайте вашу програму в список програм: | ||
|
||
.. code-block:: cpp | ||
:linenos: | ||
:emphasize-lines: 1, 7, 21 | ||
:caption: launcher.cpp | ||
#include "myapp.h" // <--- підключаємо вашу програму | ||
// ... | ||
// всередині функції appsMenu: | ||
String titles[] = { | ||
"Моя програма", // <--- назва вашої програми | ||
"Лінії", | ||
"Шайба", | ||
"Перетворення", | ||
"М'ячик", | ||
"Епілепсія", | ||
"Летріс", | ||
"Клавіатура", | ||
"Тест SPI", | ||
"I2C-сканер", | ||
"<< Назад", | ||
}; | ||
// vector of functions | ||
APP_CLASS_LIST classes = { | ||
APP_CLASS(MyApp), // <--- клас вашої програми | ||
APP_CLASS(DemoLines), | ||
APP_CLASS(DiskApp), | ||
APP_CLASS(TransformApp), | ||
APP_CLASS(BallApp), | ||
APP_CLASS(EpilepsyApp), | ||
APP_CLASS(LetrisApp), | ||
APP_CLASS(KeyboardApp), | ||
APP_CLASS(UserSPIApp), | ||
APP_CLASS(ScanI2CApp), | ||
}; | ||
Після цього перепрошийте Лілку, і ваша програма з'явиться в меню програм. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,5 +13,6 @@ Keira OS | |
features | ||
flashing | ||
sdcard | ||
custom_apps | ||
lua/intro | ||
lua/reference/index |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters