1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/lupyuen-lvgl-wasm

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Это зеркальный репозиторий, синхронизируется ежедневно с исходного репозитория.
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

PineTime Watch Face Simulator с портом LVGL для WebAssembly

Симулятор PineTime Watch Face в веб-браузере (с использованием WebAssembly) для упрощения разработки пользовательских циферблатов.

Онлайн-демонстрация: https://appkaki.github.io/lvgl-wasm/lvgl.html

Исходный код циферблата на C++: clock/Clock.cpp

Прочитайте статью...

«Предварительный просмотр циферблатов PineTime в вашем веб-браузёре с помощью WebAssembly» https://lupyuen.github.io/pinetime-rust-mynewt/articles/simulator

Для циферблатов на основе Rust см. ветку rust https://github.com/AppKaki/lvgl-wasm/blob/rust/README.md

Особенности

  1. Компилирует реальный циферблат PineTime из C++ в WebAssembly: Clock.cpp был преобразован в WebAssembly clock.

  2. Автоматически преобразует любой циферблат PineTime из C++ в WebAssembly с помощью sed и GitHub Actions / GitLab CD. Демонстрация пользовательского циферблата https://appkaki.github.io/lvgl-wasm/lvgl2.html / Исходный код clock/Clock2.cpp.

  3. Использует рабочий процесс GitHub Actions для сборки любого форка [InfiniTime Watch Face] (https://github.com/JF002/Pinetime) в WebAssembly.

  4. Отображает LVGL на HTML Canvas напрямую через WebAssembly, без использования SDL2. См. lvgl.html#L1296-L1357.

  5. Включает шрифты и символы PineTime из LittleVgl.cpp (https://github.com/JF002/Pinetime/blob/master/src/DisplayApp/LittleVgl.cpp).

  6. Поддерживает формат фреймбуфера RGB565, используемый контроллером дисплея PineTime, чтобы растровые изображения отображались правильно. Демонстрация растрового изображения https://appkaki.github.io/lvgl-wasm/lvgl2.html / Исходный код clock/Clock2.cpp.

  7. Показывает текущую дату и время.

Как создать и предварительно просмотреть циферблат PineTime с помощью GitHub или GitLab

  1. Мы создаём форк репозитория PineTime InfiniTime Firmware на GitHub (или GitLab): https://github.com/JF002/Pinetime.

  2. Включаем публикацию GitHub Pages (или GitLab Pages) для ветки master, папки docs.

  3. Добавляем __рабочий процесс GitHub Actions (или GitLab CD): .github/workflows/simulate.yml* (https://github.com/lupyuen/pinetime-lab/blob/master/.github/workflows/simulate.yml).

  4. Активируем рабочий процесс.

  5. Мы редактируем DisplayApp/Screens/Clock.cpp в веб-браузёре через GitHub (или веб-IDE GitLab).

  6. Это запускает сборку PineTime Firmware в GitHub Actions (или GitLab CD), при условии, что установлен .github/workflows/main.yml (https://github.com/lupyuen/pinetime-lab/blob/master/.github/workflows/main.yml).

  7. Также собирается симулятор PineTime Watch Face в WebAssembly.

  8. Затем файлы WebAssembly отправляются в GitHub Pages (или GitLab Pages).

  9. Мы предварительно просматриваем циферблат PineTime через симулятор в веб-браузёре: https://YOUR_ACCOUNT.github.io/Pinetime (см. Онлайн-демонстрацию).

  10. Если нас устраивает циферблат, мы загружаем собранную прошивку на PineTime через Bluetooth. См. «Тестируем нашу прошивку PineTime» (https://lupyuen.github.io/pinetime-rust-mynewt/articles/cloud#download-and-test-our-pinetime-firmware).

Предстоящие функции

  1. Обработка сенсорного ввода для LVGL.

  2. Преобразование Clock.cpp из C++ в Rust с помощью lvgl-rs (https://github.com/rafaelcaricio/lvgl-rs).

    См. ветку rust проекта lvgl-asm (https://github.com/AppKaki/lvgl-wasm/blob/rust/README.md).

  3. Позволить создавать циферблаты PineTime онлайн на Rust с предварительным просмотром.

Ссылки

  • «Предварительный просмотр циферблатов PineTime в вашем веб-браузёре с помощью WebAssembly».

  • Программирование с PineTime

Сборка прошивки PineTime в облаке с помощью GitHub Actions

Как собрать симулятор часов PineTime

Чтобы собрать симулятор циферблата часов PineTime на Linux x64 или Arm64, выполните следующие шаги:

  1. Установите emscripten и wabt. Следуйте инструкциям ниже.

  2. Введите...

git clone https://github.com/AppKaki/lvgl-wasm
cd lvgl-wasm
  1. Только для Arm64 (Raspberry Pi 64, Pinebook Pro):

Необходимо предотвратить параллельное выполнение команд make, так как это может привести к зависанию машины из-за высокой нагрузки на ввод-вывод.

Отредактируйте файл wasm/lvgl.sh и измените...

make -j

На...

make
  1. Скопируйте файл DisplayApp/Screens/Clock.cpp из нашего форка репозитория InfiniTime в папку clock/Clock.cpp:
# Предположим, что наш форк InfiniTime находится в ~/Pinetime
cp ~/Pinetime/src/DisplayApp/Screens/Clock.cpp clock/Clock.cpp

Этот файл будет встроен в симулятор.

  1. Соберите приложение LVGL WebAssembly, содержащее наш циферблат часов:
# Сборка приложения LVGL: wasm/lvgl.html, lvgl.js, lvgl.wasm
wasm/lvgl.sh

Вы должны увидеть...

...
clock/ClockTmp.cpp:172:32: warning: format specifies type 'unsigned long' but the argument has type 'unsigned int' [-Wformat]
        sprintf(stepBuffer, "%lu", stepCount.Get());
                            ~~~   ^~~~~~~~~~~~~~~
                            %u
17 warnings generated.
+ wasm-objdump -x wasm/lvgl.wasm
+ mv wasm/lvgl.html wasm/lvgl.old.html

Это создаст файлы wasm/lvgl.html, wasm/lvgl.js и wasm/lvgl.wasm.

  1. Скопируйте сгенерированные файлы WebAssembly в папку docs (используется GitHub Pages):
cp wasm/lvgl.js wasm/lvgl.wasm docs

Нам не нужен lvgl.html, потому что папка docs уже содержит версию lvgl.html с пользовательским JavaScript.

  1. Запустите веб-сервер для папки docs, поскольку WebAssembly не работает при открытии из файловой системы.

Для Arm64: Используйте darkhttpd...

darkhttpd docs

Для x64: используйте расширение Chrome Web Server for Chrome и установите папку в docs.

  1. Откройте веб-браузер и перейдите по URL, указанному darkhttpd или Web Server for Chrome.

Введите lvgl.html в адресной строке, чтобы просмотреть симулятор циферблата PineTime.

В случае возникновения проблем сравните с журналом сборки GitHub Actions (https://github.com/AppKaki/lvgl-wasm/actions?query=workflow%3A%22C%2FC%2B%2B+CI%22).

Принцип работы

Симулятор циферблата часов PineTime был скомпилирован из C и C++ в WebAssembly с использованием emscripten.

Рассмотрим скрипт сборки: wasm/lvgl.sh. Toolchain для emscripten

rustup default nightly
rustup target add wasm32-unknown-emscripten

Сборка модулей Rust с совместимостью с emscripten

cargo build --target=wasm32-unknown-emscripten

Создание примера приложения Rust: wasm/test_rust.html, test_rust.js, test_rust.wasm

emcc * -g* * wasm/test_rust.c* * -s WASM=1* * -s "EXPORTED_FUNCTIONS=[ '_main', '_get_display_buffer', '_get_display_width', '_get_display_height', '_test_display', '_test_c', '_test_c_set_buffer', '_test_c_get_buffer', '_test_c_buffer_address', '_test_rust', '_test_rust2', '_test_rust3', '_test_rust_set_buffer', '_test_rust_get_buffer' ]"* * -o wasm/test_rust.html* * -I src/lv_core* * target/wasm32-unknown-emscripten/debug/liblvgl_wasm_rust.a*

Дамп модулей WebAssembly

wasm-objdump -x wasm/test_rust.wasm >wasm/test_rust.txt

Переименование файлов HTML, чтобы не перезаписывать обновления

mv wasm/test_rust.html wasm/test_rust.old.html

InfiniTime Sandbox

PineTime Web Simulator работает в веб-браузере на основе WebAssembly (что-то вроде Java Applets).

Clock.cpp — это наш класс C++, который содержит код Watch Face. Clock.cpp вызывает функции из двух провайдеров...

  1. LVGL UI Toolkit Library

  2. InfiniTime Operating System, основанная на FreeRTOS

lvgl-wasm имитирует минимальный набор функций InfiniTime, необходимых для рендеринга Watch Faces. (FreeRTOS не поддерживается симулятором).

Следовательно, lvgl-wasm работает как Sandbox. Вот как работает песочница InfiniTime...

Экспортированные функции

Песочница экспортирует следующие функции WebAssembly из C в JavaScript...

Функции часов

Эти функции создают класс часов из Clock.cpp, отображают виджеты LVGL на циферблате и обновляют время...

  • create_clock()

    Создаёт экземпляр часов.

    Из clock/ClockHelper.cpp

  • refresh_clock()

    Перерисовывает часы.

    Из clock/ClockHelper.cpp

  • update_clock(year, month, day, hour, minute, second)

    Устанавливает текущую дату и время в DateTimeController. Время необходимо скорректировать для текущего часового пояса, см. ниже вызов JavaScript для update_clock().

    Из clock/ClockHelper.cpp

Дисплейные функции

Эти функции инициализируют библиотеку LVGL и отображают виджеты LVGL в буфере отображения WebAssembly...

  • init_display()

    Инициализирует дисплей LVGL.

    Из wasm/lvgl.c

  • render_display()

    Отображает дисплей LVGL в 16-битном формате RGB565. Из wasm/lvgl.c

    Вызывает драйвер дисплея WebAssembly, определённый в wasm/lv_port_disp.c, который вызывает put_display_px(), чтобы нарисовать отдельные пиксели в буфер отображения WebAssembly: wasm/lvgl.c.

Буфер отображения

Драйвер дисплея WebAssembly поддерживает буфер отображения: массив пикселей 240 x 240, 4 байта на пиксель, в формате цвета RGBA: wasm/lvgl.c:

///  RGBA WebAssembly Display Buffer that will be rendered to HTML Canvas
#define LV_HOR_RES_MAX          240
#define LV_VER_RES_MAX          240
#define DISPLAY_BYTES_PER_PIXEL 4
uint8_t display_buffer[LV_HOR_RES_MAX * LV_VER_RES_MAX * DISPLAY_BYTES_PER_PIXEL];

Наш код JavaScript копирует буфер отображения из памяти WebAssembly и отображает его на холсте HTML, вызывая следующие функции...

  • get_display_width()

    Возвращает 240 — ширину буфера отображения WebAssembly.

    Из wasm/lvgl.c

  • get_display_height()

    Возвращает 240 — высоту буфера отображения WebAssembly.

    Из wasm/lvgl.c

  • get_display_buffer()

    Возвращает адрес буфера отображения WebAssembly.

    Из wasm/lvgl.c Символы.h

Символы циферблата часов.

Основан на DisplayApp/Screens/Symbols.h.

date.h

Функции даты.

Основан на libs/date/includes/date/date.h.

Стили Sandbox

InfiniTime Sandbox предоставляет два стиля LVGL...

  1. Стиль по умолчанию, определённый в lv_conf.h, со шрифтом jetbrains_mono_bold_20.

    Примечание: Используйте базовую тему, определённую в LittleVgl.cpp. Она не работает с LVGL версии 7, поскольку для LVGL 7 нужны функции обратного вызова стилей.

  2. LabelBigStyle, определённый в LittleVgl.cpp, со шрифтом jetbrains_mono_extrabold_compressed.

Симулятор JavaScript

Здесь функции JavaScript вызывают экспортированные функции WebAssembly для отображения циферблата часов. Из docs/lvgl.html.

Инициализация WebAssembly

Мы регистрируем обратный вызов в API emscripten, чтобы получать уведомления о загрузке модуля WebAssembly lvgl.wasm.

// В JavaScript: дождитесь инициализации emscripten
Module.onRuntimeInitialized = function() {
  // Рендеринг LVGL на HTML Canvas
  render_canvas();
};

Инициализация дисплея LVGL

После загрузки модуля WebAssembly lvgl.wasm мы вызываем функцию WebAssembly init_display(), чтобы инициализировать дисплей LVGL.

/// В JavaScript: создайте циферблат часов в WebAssembly
function render_canvas() {
  // Инициализируйте дисплей LVGL
  Module._init_display();

Создание циферблата часов

Затем мы создаём класс циферблата часов LVGL из Clock.cpp.

  // Создайте циферблат часов в WebAssembly
  Module._create_clock();

Обновление времени циферблата часов

Каждую минуту мы обновляем время циферблата часов в DateTimeController.

/// В JavaScript: обновите время циферблата часов в WebAssembly и отобразите буфер отображения WebAssembly на холсте HTML
function updateCanvas() {
  // Обновите дату и время WebAssembly: год, месяц, день, час, минута, секунда
  const localTime = new Date();
  const timezoneOffset = localTime.getTimezoneOffset(); // В минутах
  // Компенсируйте часовой пояс
  const now = new Date(
    localTime.valueOf() // Преобразуйте время в миллисекунды
    - (timezoneOffset * 60 * 1000) // Преобразуем минуты в миллисекунды
  );
  Module._update_clock(
    now.getFullYear(),
    now.getMonth() - 1, // getMonth() возвращает от 1 до 12
    now.getDay(),
    now.getHours(),
    now.getMinutes(),
    now.getSeconds()
  );

Обратите внимание, что нам нужно компенсировать часовой пояс.

Перерисовка циферблата часов

И перерисовываем циферблат часов в Clock.cpp.

  // Обновите время циферблата часов в WebAssembly
  Module._refresh_clock();

Рендеринг виджетов LVGL в буфер отображения WebAssembly

Вызываем LVGL для рендеринга виджетов в буфер отображения WebAssembly.

  // Отрендерите виджеты LVGL в буфер отображения WebAssembly
  Module._render_display();

Изменение размера холста HTML

Изменяем размер холста HTML до разрешения PineTime 240 x 240, масштабированного в 2 раза.

  const DISPLAY_SCALE = 2; // Масштабируйте ширину и высоту холста

  // Получите размеры PineTime из буфера отображения WebAssembly
  var width = Module._get_display_width();
  var height = Module._get_get_display_height();

  // Измените размер холста до размеров PineTime (240 x 240)
  if (
    Module.canvas.width != width * DISPLAY_SCALE ||
    Module.canvas.height != height * DISPLAY_SCALE
  ) {
    Module.canvas.width = width * DISPLAY_SCALE;
    Module.canvas.height = height * DISPAY_SCALE;
  }

Получение холста HTML

Получаем холст HTML.

  // Получаем пиксели холста
  var ctx = Module.canvas.getContext('2d');
  var... ## Копирование буфера отображения WebAssembly на холст HTML

Мы копируем пиксели из буфера отображения WebAssembly на HTML-холст (который использует 24-битный формат RGBA)...

```javascript
  const DISPLAY_SCALE = 2;  //  Масштабируем ширину и высоту холста
  const DISPLAY_BYTES_PER_PIXEL = 4;  //  4 байта на пиксель: RGBA

  // Копируем пиксели из буфера отображения WebAssembly на канвас
  var addr = Module._get_display_buffer();
  Module.print(`В JavaScript: get_display_buffer() вернул ${toHex(addr)}`);          
  for (var y = 0; y < height; y++) {
    // Масштабируем пиксели по вертикали, чтобы заполнить холст
    for (var ys = 0; ys < DISPLAY_SCALE; ys++) {
      for (var x = 0; x < width; x++) {
        // Копируем из источника в место назначения с масштабированием
        const src = ((y * width) + x) * DISPLAY_BYTES_PER_PIXEL;
        const dest = ((((y * DISPLAY_SCALE + ys) * width) + x) * DISPLAY_BYTES_PER_PIXEL) 
          * DISPLAY_SCALE;
        // Масштабируем пиксели по горизонтали, чтобы заполнить холст
        for (var xs = 0; xs < DISPLAY_SCALE; xs++) {
          const dest2 = dest + xs * DISPLAY_BYTES_PER_PIXEL;
          // Копируем 4 байта: RGBA
          for (var b = 0; b < DISPLAY_BYTES_PER_PIXEL; b++) {
            data[dest2 + b] = Module.HEAPU8[addr + src + b];
          }
        }
      }
    }
  }

Обратите внимание, что JavaScript может читать и записывать в память WebAssembly (рассматривая её как массив байтов JavaScript в Module.HEAPU8[]). Но WebAssembly не может получить доступ к любой памяти JavaScript.

Вот почему мы разработали функции буфера отображения для управления памятью WebAssembly.

Рисуем на холсте HTML

Наконец, мы обновляем холст HTML...

  // Рисуем холст
  ctx.putImageData(imageData, 0, 0);
}

Установка emscripten на Ubuntu x64

См. GitHub Actions Workflow...

.github/workflows/ccpp.yml

Ищите шаги...

  1. «Установить emscripten».

  2. «Установите wabt».

Измените /tmp на постоянный путь, например ~.

Затем добавьте emscripten и wabt в PATH...

# Добавляем emscripten и wabt в PATH
source ~/emsdk/emsdk_env.sh
export PATH=$PATH:~/wabt/build

Установка emscripten на Arch Linux / Manjaro Arm64

Работает на Pinebook Pro с Manjaro...

sudo pacman -S emscripten
sudo pacman -S wabt
source /etc/profile.d/emscripten.sh
emcc --version
# Показывает версию emscripten 1.39.20
wasm-as --version
# Показывает binaryen версии 95

Для версий emscripten 1.40.x и новее

emscripten и binaryen, вероятно, будут работать, пропустите остальную часть этого раздела.

Для версий emscripten 1.39.x и binaryen версии 95 только

Это не удастся во время сборки, потому что emscripten 1.39 нужен binaryen версии 93, а не 95.

Можно установить binaryen версии 93... Но emcc завершится ошибкой с сообщением «stackSave уже существует». Это связано с тем, что binaryen 93 генерирует «stackSave», который конфликтует с emscripten 1.39.20. Подробнее здесь.

Чтобы это исправить, устанавливаем binaryen версии 94, но переименовываем его в версию 93...

# Скачиваем binaryen 94
git clone --branch version_94 https://github.com/WebAssembly/binaryen
cd binaryen
nano CMakeLists.txt

Изменить

   project(binaryen LANGUAGES C CXX VERSION 94)

На

   project(binaryen LANGUAGES C CXX VERSION 93)

Затем соберите и установите binaryen...

cmake .
make -j 5
sudo cp bin/* /usr/bin
sudo cp lib/* /usr/lib
wasm-as --version
# Показывает двоичный файл «версия 93 (версия_94)»

Теперь binaryen имеет версию 93, которая является правильной. Перейдите к сборке приложения...

cd lvgl-wasm
rm -rf ~/.emscripten_cache
make clean
make -j 5

Сборка приложения должна завершиться успешно.

Ошибка emcc: Неожиданная версия binaryen

Если мы увидим эту ошибку...

   emcc: error: unexpected binaryen version: 95 (expected 93) [-Wversion-check] [-Werror]
   FAIL: Compilation failed!: ['/usr/lib/emscripten/emcc', '-D_GNU_SOURCE', '-o', '/tmp/tmpbe4ik5na.js', '/tmp/tmpzu5jusdg.c', '-O0', '--js-opts',

*В этом тексте есть фрагменты кода, которые не удалось перевести. Вероятно, они содержат синтаксические ошибки или специальные символы.* 0, --memory-init-file, 0, -Werror, -Wno-format, -s, BOOTSTRAPPING_STRUCT_INFO=1, -s, WARN_ON_UNDEFINED_SYMBOLS=0, -s, STRICT=1, -s, SINGLE_FILE=1]

emcc Error: stackSave уже существует

Затем нам нужно установить правильную версию binaryen (см. выше).

Если мы видим эту ошибку...

Fatal: Module::addExport: stackSave already exists
emcc: error: '/usr/bin/wasm-emscripten-finalize --detect-features --global-base=1024 --check-stack-overflow /tmp/emscripten_temp_84xtyzya/tmpzet09r88.wasm -o /tmp/emscripten_temp_84xtyzya/tmpzet09r88.wasm.o.wasm' failed (1)
FAIL: Compilation failed!: ['/usr/lib/emscripten/emcc', '-D_GNU_SOURCE', '-o', '/tmp/tmpzet09r88.js', '/tmp/tmpxk8zxvza.c', '-O0', '--js-opts', '0', '--memory-init-file', '0', '-Werror', '-Wno-format', '-s', 'BOOTSTRAPPING_STRUCT_INFO=1', '-s', 'WARN_ON_UNDEFINED_SYMBOLS=0', '-s', 'STRICT=1', '-s', 'SINGLE_FILE=1']

Это означает, что binaryen 93 генерирует «stackSave», который конфликтует с emscripten 1.39.20. Подробнее здесь.

Нам нужно установить ветку version_94 binaryen, изменить версию в CMakeLists.txt на версию 93 (см. выше).

Установить emscripten на macOS (не работает)

Введите следующие команды...

brew install emscripten
brew install binaryen
# Обновить llvm до 10.0.0
brew install llvm
brew upgrade llvm
nano /usr/local/Cellar/emscripten/1.40.1/libexec/.emscripten

Измените BINARYEN_ROOT и LLVM_ROOT на

BINARYEN_ROOT = os.path.expanduser(os.getenv('BINARYEN', '/usr/local')) # каталог
LLVM_ROOT = os.path.expanduser(os.getenv('LLVM', '/usr/local/opt/llvm/bin')) # каталог

Выходит ошибка:

emcc: warning: LLVM version appears incorrect (seeing "10.0", expected "12.0") [-Wversion-check]
shared:INFO: (Emscripten: Running sanity checks)
clang-10: error: unknown argument: '-fignore-exceptions'
emcc: error: '/usr/local/opt/llvm/bin/clang -target wasm32-unknown-emscripten -D__EMSCRIPTEN_major__=1 -D__EMSCRIPTEN_minor__=40 -D__EMSCRIPTEN_tiny__=1 -D_LIBCPP_ABI_VERSION=2 -Dunix -D__unix -D__unix__ -Werror=implicit-function-declaration -Xclang -nostdsysteminc -Xclang -isystem/usr/local/Cellar/emscripten/1.40.1/libexec/system/include/compat -Xclang -isystem/usr/local/Cellar/emscripten/1.40.1/libexec/system/include -Xclang -isystem/usr/local/Cellar/emscripten/1.40.1/libexec/system/include/libc -Xclang -isystem/usr/local/Cellar/emscripten/1.40.1/libexec/system/lib/libc/musl/arch/emscripten -Xclang -isystem/usr/local/Cellar/emscripten/1.40.1/libexec/system/local/include -Xclang -isystem/usr/local/Cellar/emscripten/1.40.1/libexec/system/include/SSE -Xclang -isystem/usr/local/Cellar/emscripten/1.40.1/libexec/system/lib/compiler-rt/include -Xclang -isystem/usr/local/Cellar/emscripten/1.40.1/libexec/system/lib/libunwind/include -Xclang -isystem/usr/local/Cellar/emscripten/1.40.1/libexec/cache/wasm/include -DEMSCRIPTEN -fignore-exceptions -Isrc/lv_core -D LV_USE_DEMO_WIDGETS ././src/lv_core/lv_group.c -Xclang -isystem/usr/local/Cellar/emscripten/1.40.1/libexec/system/include/SDL -c -o /var/folders/gp/jb0b68fn3b187mgyyrjml3km0000gn/T/emscripten_temp_caxv1fls/lv_group_0.o -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr' failed (1)

Трассировка стека WebAssembly для PineTime Watch Face

Вот пример трассировки стека WebAssembly, которая появляется в веб-браузере. Это происходит, когда мы не инициализируем стиль LVGL LabelBigStyle, используемый Clock.cpp.

lvgl.js:1839 Fetch finished loading: GET "http://127.0.0.1:8887/lvgl.wasm".
instantiateAsync @ lvgl.js:1839
createWasm @ lvgl.js:1866
(anonymous) @ lvgl.js:2113
lvgl2.html:1237 In JavaScript: render_canvas()
lvgl2.html:1237 In C: Init display...
lvgl2.html:1237 Init display...
​ Uncaught RuntimeError: memory access out of bounds
    at _lv_style_get_int (http://127.0.0.1:8887/lvgl.wasm:wasm-function[229]:0x21bfb)
    at _lv_style_list_get_int (http://127.0.0.1:8887/lvgl.wasm:wasm-function[234]:0x22bf7)
    at _lv_obj_get_style_int
``` **Миграция с LVGL версии 6 на версию 7**

PineTime работает на LVGL версии 6, в то время как наш порт WebAssembly работает на LVGL версии 7. Программы, созданные для LVGL версии 6, не будут компилироваться с версией 7.

Вот как мы перенесли код с LVGL версии 6...

* Оригинальный PineTime Clock.cpp (https://github.com/JF002/Pinetime/blob/master/src/DisplayApp/Screens/Clock.cpp).

* Оригинальный PineTime LittleVgl.cpp (https://github.com/JF002/Pinetime/blob/master/src/DisplayApp/LittleVgl.cpp).

На LVGL версии 7...

* Преобразованный WebAssembly Clock.cpp (clock/Clock.cpp).

* Преобразованный WebAssembly LittleVgl.cpp (clock/LittleVgl.cpp).

Сравните оригинальные и преобразованные файлы...

* Clock.cpp: LVGL версия 6 против версии 7 (https://github.com/AppKaki/lvgl-wasm/compare/clock_before...master#diff-9a3204013cda108f0edc5647e908ea82). Нажмите «Файлы изменены», затем «Изменённые файлы» и найдите Clock/Clock.cpp.

* LittleVgl.cpp: LVGL версия 6 против версии 7 (https://github.com/AppKaki/lvgl-wasm/compare/AppKaki:littlevgl_before...master#diff-c2a76b9cd8a6d2fd824f1441a1e2ed34). Нажмите «Файлы изменены», затем «Изменённые файлы» и найдите Clock/LittleVgl.cpp.

**Миграция lv_label_set_style**

Код, использующий lv_label_set_style...

```c++
lv_label_set_style(label_time, LV_LABEL_STYLE_MAIN, LabelBigStyle);

Следует изменить на lv_obj_reset_style_list и lv_obj_add_style...

//  Удалить стили, поступающие из темы
lv_obj_reset_style_list(label_time, LV_LABEL_PART_MAIN);
//  Затем добавить стиль
lv_obj_add_style(label_time, LV_LABEL_PART_MAIN, LabelBigStyle);

Или определите макрос следующим образом...

/// Изменить LVGL v6 lv_label_set_style() на LVGL v7 lv_obj_reset_style_list() и lv_obj_add_style()
#define lv_label_set_style(label, style_type, style) \
{ \
    lv_obj_reset_style_list(label, LV_LABEL_PART_MAIN); \
    lv_obj_add_style(label, LV_LABEL_PART_MAIN, style); \
}
lv_label_set_style(label_time, LV_LABEL_STYLE_MAIN, LabelBigStyle);

Миграция LVGL lv_style_plain

lv_style_plain был удалён в LVGL 7. Код вроде этого...

lv_style_copy(&def, &lv_style_plain);

Следует заменить на...

lv_style_init(&def);

Перенос тем LVGL

В LVL 6 было легко установить шрифт по умолчанию для темы...

lv_style_init(&def);
lv_style_set_text_font(&def, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
...
lv_theme_set_current(&theme);

Но в LVL 7 нам нужно использовать Theme Callback. Функции](https://docs.lvgl.io/latest/en/html/overview/style.html?highlight=theme#themes) для применения стиля.

Более простое решение — задать шрифт по умолчанию в lv_conf.h...

#define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(jetbrains_mono_bold_20)
#define LV_THEME_DEFAULT_FONT_SMALL         &jetbrains_mono_bold_20
#define LV_THEME_DEFAULT_FONT_NORMAL        &jetbrains_mono_bold_20
#define LV_THEME_DEFAULT_FONT_SUBTITLE      &jetbrains_mono_bold_20
#define LV_THEME_DEFAULT_FONT_TITLE         &jetbrains_mono_bold_20

Миграция стилей LVGL

Изменение стиля LVL 6...

lv_style_copy(&bg, &lv_style_plain);
bg.body.main_color = LV_COLOR_BLACK;
bg.body.grad_color = LV_COLOR_BLACK;
bg.text.color      = LV_COLOR_WHITE;
bg.text.font       = font;
bg.image.color     = LV_COLOR_WHITE;

На стиль LVL 7...

lv_style_init(&bg);
lv_style_set_bg_color(&bg, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_style_set_bg_grad_color(&bg, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_style_set_text_color(&bg, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_text_font(&bg, LV_STATE_DEFAULT, font);
lv_style_set_image_recolor(&bg, LV_STATE_DEFAULT, LV_COLOR_WHITE);

Изменение стиля LVL 6...

lv_style_copy(&panel, &bg);
panel.body.main_color     = lv_color_hsv_to_rgb(hue, 11, 18);
panel.body.grad_color     = lv_color_hsv_to_rgb(hue, 11, 18);
panel.body.radius         = LV_DPI / 20;
panel.body.border.color   = lv_color_hsv_to_rgb(hue, 10, 25);
panel.body.border.width   = 1;
panel.body.border.opa     = LV_OPA_COVER;
panel.body.padding.left   = LV_DPI / 10;
panel.body.padding.right  = LV_DPI / 10;
panel.body.padding.top    = LV_DPI / 10;
panel.body.padding.bottom = LV_DPI / 10;
panel.line.color          = lv_color_hsv_to_rgb(hue, 20, 40);
panel.line.width          = 1;

На стиль LVL 7...

lv_style_copy(&panel, &bg);
lv_style_set_bg_color(&panel, LV_STATE_DEFAULT,       lv_color_hsv_to_rgb(hue, 11, 18)); 
lv_style_set_bg_grad_color(&panel, LV_STATE_DEFAULT,  lv_color_hsv_to_rgb(hue, 11, 18)); 
lv_style_set_radius(&panel, LV_STATE_DEFAULT,         LV_DPI / 20); 
lv_style_set_border_color(&panel, LV_STATE_DEFAULT,   lv_color_hsv_to_rgb(hue, 10, 25)); 
lv_style_set_border_width(&panel, LV_STATE_DEFAULT,   1); 
lv_style_set_border_opa(&panel, LV_STATE_DEFAULT,     LV_OPA_COVER); 
lv_style_set_pad_left(&panel, LV_STATE_DEFAULT,       LV_DPI / 10); 
lv_style_set_pad_right(&panel, LV_STATE_DEFAULT,      LV_DPI / 10); 
lv_style_set_pad_top(&panel, LV_STATE_DEFAULT,        LV_DPI / 10); 
lv_style_set_pad_bottom(&panel, LV_STATE_DEFAULT,     LV_DPI / 10); 
lv_style_set_line_color(&panel, LV_STATE_DEFAULT,     lv_color_hsv_to_rgb(hue, 20, 40)); 
lv_style_set_line_width(&panel, LV_STATE_DEFAULT,     1); 

Дополнительные примеры миграции стилей LVL см. в...

LittleVgl.cpp: LVGL Version 6 vs Version 7

Нажмите «Файлы изменены», затем «Изменённые файлы» и найдите «Clock/LittleVgl.cpp».

LVGL — лёгкая и универсальная графическая библиотека

LVGL предоставляет всё необходимое для создания встроенного графического интерфейса пользователя с удобными в использовании графическими элементами, красивыми визуальными эффектами и низким потреблением памяти.

Веб-сайт · Онлайн-демонстрация · Документация · Форум


Особенности

  • Мощные строительные блоки: кнопки, диаграммы, списки, ползунки, изображения и т. д.
  • Расширенная графика: анимация, сглаживание, прозрачность, плавная прокрутка
  • Использование различных устройств ввода: сенсорный экран, мышь, клавиатура, энкодер, кнопки и т.д.
  • Использование нескольких дисплеев: например, монохромный и цветной дисплей
  • Аппаратное обеспечение LVGL: кроссплатформенный фреймворк для создания графических интерфейсов

Независимый для использования с любым микроконтроллером или дисплеем

Масштабируемый для работы с небольшим объёмом памяти (64 КБ Flash, 10 КБ RAM)

Многоязыковая поддержка с обработкой UTF-8, поддержкой двунаправленного текста и арабского письма

Полностью настраиваемые графические элементы через CSS-подобные стили

Поддержка ОС, внешней памяти и GPU, но не обязательно

Плавный рендеринг даже с одним буфером кадра

Написан на C для максимальной совместимости (совместим с C++)

Micropython Binding предоставляет доступ к LVGL API в Micropython

Симулятор для разработки на ПК без встроенного оборудования

Примеры и учебные пособия для быстрой разработки

Документация и справочные материалы по API

Требования

В целом, подходит любой современный контроллер, способный управлять дисплеем. Минимальные требования:

Имя Минимальное Рекомендуемое
Архитектура 16, 32 или 64 битный микроконтроллер или процессор
Тактовая частота > 16 МГц > 48 МГц
Flash/ROM > 64 КБ > 180 КБ
Статическая RAM > 2 КБ > 4 КБ
Стек > 2 КБ > 8 КБ
Куча > 2 КБ > 8 КБ
Буфер дисплея > 1 * hor. res. пикселей > 10 * hor. res. пикселей
Компилятор C99 или новее

Обратите внимание, что использование памяти может варьироваться в зависимости от архитектуры, компилятора и параметров сборки.

Вот некоторые платформы, которые можно использовать:

— STM32F1, STM32F3, STM32F4, STM32F7, STM32L4, STM32L5, STM32H7;

— Microchip dsPIC33, PIC24, PIC32MX, PIC32MZ;

— NXP: Kinetis, LPC, iMX, iMX RT;

— Linux frame buffer (/dev/fb);

— Raspberry Pi;

— Espressif ESP32;

— Infineon Aurix;

— Nordic NRF52 Bluetooth модули;

— Quectel модемы.

Начало работы

Этот список показывает рекомендуемый способ изучения библиотеки:

  1. Проверьте онлайн-демонстрации, чтобы увидеть LVGL в действии (3 минуты).

  2. Прочитайте страницу «Введение» документации (5 минут).

  3. Ознакомьтесь с основами на странице «Краткий обзор» (15 минут).

  4. Настройте симулятор (10 минут).

  5. Попробуйте примеры.

  6. Перенесите LVGL на плату. См. руководство по переносу или готовые проекты.

  7. Прочитайте страницу обзора, чтобы лучше понять библиотеку (2–3 часа).

  8. Изучите документацию виджетов, чтобы узнать об их функциях и использовании.

  9. Если у вас есть вопросы, перейдите на форум.

  10. Прочитайте руководство по внесению вклада, чтобы узнать, как вы можете помочь улучшить LVGL (15 минут). ### Создание кнопки с надписью

lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL); /*Добавить кнопку на текущий экран*/
lv_obj_set_pos(btn, 10, 10);                       /*Установить её положение*/
lv_obj_set_size(btn, 100, 50);                     /*Установить её размер*/
lv_obj_set_event_cb(btn, btn_event_cb);           /*Присвоить кнопке обратный вызов*/

lv_obj_t * label = lv_label_create(btn, NULL);     /*Добавить надпись к кнопке*/
lv_label_set_text(label, "Button");               /*Задать текст надписи*/

...

void btn_event_cb(lv_obj_t * btn, lv_event_t event)
{
    if (event == LV_EVENT_CLICKED) {
        printf("Clicked\n");
    }
}

Пример кнопки LVGL с надписью

Пример кнопки LVGL с надписью

LVGL из Micropython

Подробнее о Micropython.

# Создать кнопку и надпись
scr = lv.obj()
btn = lv.btn(scr)
btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text("Button")

# Загрузить экран
lv.scr_load(scr)

Вклад в проект

LVGL — это открытый проект, и мы приветствуем вклад от всех желающих. Есть много способов внести свой вклад: от простого рассказа о своём проекте до написания примеров, улучшения документации, исправления ошибок или создания собственного проекта на основе LVGL.

Подробное описание возможностей для вклада можно найти в разделе Вклад документации.

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Симулятор циферблата часов PineTime с использованием LVGL, портированный на WebAssembly. Расширить Свернуть
MIT
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://gitlife.ru/oschina-mirror/lupyuen-lvgl-wasm.git
git@gitlife.ru:oschina-mirror/lupyuen-lvgl-wasm.git
oschina-mirror
lupyuen-lvgl-wasm
lupyuen-lvgl-wasm
master