PIPKIT · Start Here

Как собрать библиотеку, настроить её, прогнать desktop simulator и вывести первый экран.

Исходный контент этой страницы берётся напрямую из API.md: требования к сборке, build-time флаги, desktop simulator, инициализация, подсветка и логотип.

Этот файл описывает актуальный публичный API PipGUI и PipCore, который есть в коде проекта.

Требования к компиляции (PlatformIO)

PipKit использует C++17. Для PlatformIO добавьте в platformio.ini:

build_unflags =
    -std=gnu++11
build_flags =
    -std=gnu++17

1. Build-time флаги

Низкий слой PipCore выбирает платформу, драйвер дисплея и optional backend-модули на этапе компиляции. Эти флаги задаются в include/config.hpp.

  • PIPCORE_DISPLAY
  • пример: #define PIPCORE_DISPLAY ST7789
  • поддерживаемые дисплеи: ST7789, ILI9488, SIMULATOR
  • PIPCORE_PLATFORM
  • пример: #define PIPCORE_PLATFORM ESP32
  • поддерживаемые платформы: ESP32, DESKTOP
  • PIPCORE_ENABLE_PREFS
  • 0 или 1
  • PIPCORE_ENABLE_WIFI
  • 0 или 1
  • PIPCORE_ENABLE_OTA
  • 0 или 1
  • PIPCORE_OTA_PROJECT_URL
  • базовый OTA URL для core-level OTA backend

Пример через include/config.hpp:

#define PIPCORE_PLATFORM ESP32
#define PIPCORE_DISPLAY ST7789
#define PIPCORE_ENABLE_PREFS 1
#define PIPCORE_ENABLE_WIFI 1
#define PIPCORE_ENABLE_OTA 1
#define PIPCORE_OTA_PROJECT_URL "https://example.com/fw/PipGUI"

Пример для ILI9488:

#define PIPCORE_PLATFORM ESP32
#define PIPCORE_DISPLAY ILI9488
#define PIPCORE_ENABLE_PREFS 1
#define PIPCORE_ENABLE_WIFI 1
#define PIPCORE_ENABLE_OTA 1
#define PIPCORE_OTA_PROJECT_URL "https://example.com/fw/PipGUI"

Что важно:

  • по умолчанию optional-модули PipCore выключены
  • если внешний код использует pipcore::net::* при PIPCORE_ENABLE_WIFI=0, сборка падает на этапе компиляции
  • если внешний код использует pipcore::ota::* при PIPCORE_ENABLE_OTA=0, сборка тоже падает на этапе компиляции
  • это намеренное поведение: выключенный модуль нельзя использовать "молча"
  • PIPGUI_* и PIPCORE_* это разные слои конфигурации: GUI и Core соответственно
  • если PipGUI реально использует Wi-Fi / OTA, соответствующие PIPCORE_ENABLE_* тоже должны быть включены явно

2. Desktop simulator

Симулятор нужен для локального прогона GUI на Windows без ESP32 и физического дисплея. Он собирает проект в desktop-конфигурации и подменяет platform/display layer на DESKTOP + SIMULATOR.

Запуск:

powershell -ExecutionPolicy Bypass -File .\tools\sim-run.ps1

Полезные варианты:

powershell -ExecutionPolicy Bypass -File .\tools\sim-run.ps1 -Debug
powershell -ExecutionPolicy Bypass -File .\tools\sim-run.ps1 -NoRun

Что делает script:

  • собирает native desktop-версию в .sim/
  • по умолчанию сразу запускает pipgui-sim.exe
  • при -Debug собирает debug-вариант pipgui-sim-debug.exe
  • при -NoRun только собирает exe без запуска
  • если симулятор уже запущен, script сначала останавливает прошлый процесс и потом пересобирает новый

Что важно по окружению:

  • сейчас simulator-tooling рассчитан на Windows
  • нужен установленный Visual Studio C++ toolchain (Desktop development with C++)
  • для simulator build PipCore сначала пытается подключить config_sim.hpp, а если его нет, использует обычный config.hpp
  • host-обвязка simulator-а живёт внутри PipCore/Host/Desktop/

2.1. Build-time флаги simulator

  • PIPGUI_SIM_SCALE
  • масштаб окна simulator относительно логического framebuffer
  • по умолчанию 1
  • PIPGUI_SIM_DEFAULT_WIDTH
  • fallback-ширина simulator display, если проект не вызвал configDisplay().size(...)
  • по умолчанию 320
  • PIPGUI_SIM_DEFAULT_HEIGHT
  • fallback-высота simulator display, если проект не вызвал configDisplay().size(...)
  • по умолчанию 240
  • PIPGUI_SIM_BTN_PREV_PIN
  • какой virtual pin считать кнопкой Prev
  • по умолчанию 4
  • PIPGUI_SIM_BTN_NEXT_PIN
  • какой virtual pin считать кнопкой Next
  • по умолчанию 20
  • PIPGUI_SIM_BTN_SELECT_PIN
  • какой virtual pin считать кнопкой Select
  • по умолчанию 21

Пример:

#define PIPCORE_PLATFORM DESKTOP
#define PIPCORE_DISPLAY SIMULATOR

#define PIPGUI_SIM_SCALE 2
#define PIPGUI_SIM_DEFAULT_WIDTH 320
#define PIPGUI_SIM_DEFAULT_HEIGHT 240
#define PIPGUI_SIM_BTN_PREV_PIN 4
#define PIPGUI_SIM_BTN_NEXT_PIN 20
#define PIPGUI_SIM_BTN_SELECT_PIN 21

2.2. Управление в окне simulator

  • Left или A - кнопка Prev
  • Right или D - кнопка Next
  • Enter или Space - кнопка Select
  • F1 - перезапуск simulator-процесса
  • F2 - сохранить PNG-скриншот в .sim/shots/
  • F3 - начать/остановить запись видео в .sim/videos/
  • клавиши 0..3 отправляются в serial input simulator-а как обычные символы

Ограничения и отличия от железа:

  • это desktop runtime, а не cycle-accurate эмулятор ESP32
  • timing, ввод и системные backend-ы могут отличаться от реального устройства
  • screenshot/video hotkeys simulator-а работают отдельно от встроенной screenshot-системы PipGUI
  • в simulator config по умолчанию выключены PIPGUI_WIFI, PIPGUI_OTA и built-in screenshots, даже если core-level backend оставлен включённым для совместимости сборки

2.3. Структура host-layer

Desktop simulator сейчас состоит из трёх частей:

  • PipCore/Platforms/Desktop - desktop platform/runtime backend
  • PipCore/Displays/Simulator - display driver, который рисует framebuffer в desktop runtime
  • PipCore/Host/Desktop - host-обвязка для запуска Arduino-style app на ПК

Что лежит в PipCore/Host/Desktop:

  • include/Compat.hpp - основной desktop compat-layer для Arduino-style API (String, Serial, millis(), delay() и т.д.)
  • include/Arduino.h - тонкий wrapper для совместимости с обычным #include <Arduino.h>
  • src/Globals.cpp - desktop-глобалы compat-layer (Serial, ESP)
  • src/Runner.cpp - desktop entrypoint, который вызывает setup() и потом крутит loop()

2.4. Что нужно проекту для симуляции

Если проект пишет графику через PipCore / PipGUI, для simulator обычно достаточно следующего:

  • config_sim.hpp, где выбраны PIPCORE_PLATFORM DESKTOP и PIPCORE_DISPLAY SIMULATOR
  • host include path, чтобы компилятор видел PipCore/Host/Desktop compat-layer
  • desktop build script или CMake, который собирает:
  • код PipCore
  • код самого проекта
  • PipCore/Host/Desktop/src/Runner.cpp
  • PipCore/Host/Desktop/src/Globals.cpp

Что важно:

  • если UI-код опирается только на PipCore / PipGUI, этого достаточно для графической симуляции
  • если проект использует прямые ESP32-only вызовы, для них всё равно нужны desktop stub/compat-реализации или абстракция через PipCore

3. Инициализация

3.1. Конфигурация дисплея

Полный пример:

ui.configDisplay()
    .pins(11, 12, 10, 9, -1)   // mosi, sclk, cs, dc, rst
    .size(240, 320)            // width, height
    .hz(80000000)              // частота SPI
    .order("RGB")              // "RGB" или "BGR"
    .invert(true)              // инверсия панели
    .swap(false)               // swap байтов RGB565
    .offset(0, 0);             // смещение активной области

Минимальный пример:

ui.configDisplay()
    .pins(11, 12, 10, 9, -1)
    .size(240, 320);

Можно не писать и оставить display-specific дефолты core/drivers:

  • hz(freq):
  • ST7789 по умолчанию 80000000
  • ILI9488 по умолчанию 60000000
  • order("RGB"):
  • ST7789 по умолчанию RGB
  • ILI9488 по умолчанию BGR
  • invert(bool) по умолчанию true
  • swap(bool) по умолчанию false
  • offset(x, y) по умолчанию (0, 0)

Что важно:

  • если hz(...) или order(...) не заданы, используются именно дефолты выбранного драйвера в PipCore
  • это особенно важно для ILI9488, потому что его рабочие дефолты отличаются от ST7789

Обязательно указать:

  • pins(...) задаёт пины SPI и управляющие пины дисплея.
  • size(width, height) задаёт логический размер панели.

Пример для ILI9488:

ui.configDisplay()
    .pins(11, 12, 10, 9, 14)
    .size(320, 480);

3.2. Запуск GUI

После конфигурации дисплея вызывается begin():

ui.begin(0);        // rotation: 0..3
// ui.begin(0, true);  // forceTiles: принудительно включить tiled-mode (2 горизонтальных тайла)
  • rotation принимает значения 0..3.
  • forceTiles=true включает tiled-mode даже если хватает памяти на полный screen-buffer.
  • если полный screen-buffer выделить не получилось, библиотека автоматически включает tiled-mode: выделяет буфер screenWidth × ceil(screenHeight/2) и рисует кадр в 2 прохода (верх/низ).
  • стартовый фон GUI фиксированно чёрный (0x0000).

Ограничения tiled-mode:

  • screen-transition анимации отключены (требуют полного screen-buffer).
  • rotation-transition анимация отключена.

Проверить текущий режим можно через ui.tiledMode().

Runtime-поворот экрана

ui.setRotation(0);        // повернуть экран сразу или с анимацией по умолчанию
ui.setRotation(1, 620);   // тот же поворот, но со своей длительностью

ui.screenRotation();              // текущая ориентация 0..3
ui.rotationTransitionActive();    // идёт ли сейчас анимация переворота
  • setRotation(...) меняет ориентацию уже после begin(), без повторного configDisplay()
  • библиотека держит физическую конфигурацию дисплея как есть и поворачивает GUI логически, пересобирая внутренний sprite под новый размер
  • если GUI сейчас в обычном steady-state, поворот идёт с анимацией как у телефона: текущий кадр схлопывается, в середине меняется ориентация, затем новый кадр раскрывается
  • если в этот момент активны boot, error, screen transition или overlay-состояния, библиотека делает безопасный мгновенный поворот без анимации
  • screenRotation() возвращает текущий runtime rotation 0..3
  • rotationTransitionActive() позволяет не запускать свой второй переход поверх уже идущего переворота

3.3. Подсветка и яркость

ui.setBacklight()
    .pin(48)          // pin
    .channel(0)       // PWM channel
    .freq(5000)       // PWM frequency
    .resolution(12);  // PWM resolution bits

Что важно:

  • pin - обязательный
  • channel, frequency и resolution можно не указывать
  • после setBacklight(...) boot-анимация LightFade уже сама управляет яркостью
  • если backlight не настроен, LightFade управлять нечем

Максимальная яркость

ui.setMaxBrightness(70);   // ограничить максимум 70%
  • диапазон 0..100
  • это верхний лимит яркости, библиотека использует этот лимит, когда сама меняет яркость
  • на текущей ESP32-платформе значение сохраняется и потом подгружается автоматически

Текущая яркость

ui.setBrightness(35);
  • диапазон 0..100
  • сразу отправляет новое значение в текущий backlight runtime, то есть эффект виден без перезапуска GUI
  • если backlight настроен через setBacklight(...) или setBacklightHandler(...), библиотека сразу применяет новый уровень к активной подсветке
  • значение всегда clamp-ится сверху через maxBrightness(), поэтому setBrightness(90) при setMaxBrightness(70) даст фактические 70
ui.brightness();
  • возвращает именно текущее runtime-значение, а не сохранённый лимит
  • это временное пользовательское состояние на текущую сессию: после reboot оно не восстанавливается из prefs автоматически
  • если нужен сохраняемый предел яркости, для этого используется setMaxBrightness(...)

Низкоуровневые helpers

void myBacklight(uint16_t level) {
    // свой способ применить яркость
}

ui.setBacklightHandler(myBacklight);
  • setBacklightHandler(...) позволяет подставить свой handler для управления подсветкой
  • callback имеет сигнатуру void (*)(uint16_t level)
  • level это целевой уровень яркости, который библиотека хочет применить
  • это low-level хук для своего драйвера подсветки, если стандартного setBacklight() недостаточно
  • обычно этот API не нужен, если хватает setBacklight()

4. Логотип

ui.showLogo()
    .text("PISPPUS", "Digital Thermometer")
    .anim(FadeIn);

showLogo() запускает полноэкранную boot-анимацию с логотипом. Размер текста библиотека подбирает сама под текущее разрешение экрана.

Параметры:

  • text(title, subtitle) — две строки логотипа;
  • anim(...)None, FadeIn, LightFade;

Что делают анимации:

  • None - просто сразу показывает логотип без анимации
  • FadeIn - плавно проявляет текст из цвета фона
  • LightFade - плавно поднимает яркость подсветки; для неё backlight должен быть заранее настроен

Code copied