Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[platformio.ini]
indent_style = tab
[{CMakeLists.txt,*.cmake}]
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1 @@
lib/** linguist-vendored
components/** linguist-vendored
64 changes: 28 additions & 36 deletions .github/workflows/firmware.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,21 @@ permissions:
jobs:
keira:
runs-on: ubuntu-latest
# Must match KEIRA_IDF_VERSION in boards/lilka_v2/board.cmake
container: espressif/idf:v4.4.7
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
submodules: true

- uses: actions/cache@v3
- uses: actions/cache@v4
with:
path: |
~/.cache/pip
~/.platformio/.cache
./.pio
key: ${{ runner.os }}-keira

- uses: actions/setup-python@v4
with:
python-version: '3.9'

- name: Install PlatformIO Core
run: pip install --upgrade platformio
path: .ccache
key: ccache-${{ hashFiles('.gitmodules', 'boards/**') }}-${{ github.sha }}
restore-keys: ccache-${{ hashFiles('.gitmodules', 'boards/**') }}-

- name: Extract version and generate Keira header
id: version
Expand Down Expand Up @@ -79,6 +74,8 @@ jobs:
#endif // KEIRA_VERSION_AUTO_GEN_H
EOF

echo "VERSION_TYPE=$VERSION_TYPE" >> "$GITHUB_OUTPUT"

echo "Generated version:"
cat src/keira/keira_version_auto_gen.h

Expand All @@ -89,34 +86,29 @@ jobs:

- name: Build and package firmware
run: |
# container: jobs skip the image entrypoint, so set up the IDF environment here
. "$IDF_PATH/export.sh"
export CCACHE_DIR="$GITHUB_WORKSPACE/.ccache"

# build <build dir> <suffix> [compile flags]
build() {
idf.py -B "$1" -DKEIRA_BUILD_FLAGS="$3" build
cp "$1/keira.bin" "out/keira$2.bin"
cp "$1/partition_table/partition-table.bin" out/partitions.bin
cp "$1/bootloader/bootloader.bin" out/bootloader.bin
(cd "$1" && esptool.py --chip esp32s3 merge_bin -o "$GITHUB_WORKSPACE/out/KeiraOS_merged$2.bin" @flash_args)
}

mkdir -p out
if [[ "${{ steps.version.outputs.VERSION_TYPE }}" != "KEIRA_VERSION_TYPE_DEV" ]]; then
echo "Tag detected - building for all languages"
for lang in $(cat languages.txt); do
echo "Building for $lang"
PLATFORMIO_BUILD_FLAGS=-D$lang pio run -e v2
cp .pio/build/v2/firmware.bin out/keira_${lang}.bin
cp .pio/build/v2/partitions.bin out/partitions.bin
cp .pio/build/v2/bootloader.bin out/bootloader.bin
pip install esptool
esptool.py --chip esp32s3 merge_bin \
-o out/KeiraOS_merged_${lang}.bin \
0x0 out/bootloader.bin \
0x8000 out/partitions.bin \
0x10000 out/keira_${lang}.bin
build "build-$lang" "_$lang" "-D$lang"
done
else
echo "Main branch or PR - building for default language only"
pio run -e v2
cp .pio/build/v2/firmware.bin out/keira.bin
cp .pio/build/v2/partitions.bin out/partitions.bin
cp .pio/build/v2/bootloader.bin out/bootloader.bin
pip install esptool
esptool.py --chip esp32s3 merge_bin \
-o out/KeiraOS_merged.bin \
0x0 out/bootloader.bin \
0x8000 out/partitions.bin \
0x10000 out/keira.bin
build build ""
fi

# Manifest used by Keira OTA updater, available at:
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.pio
.vscode
*.cache*
compile_commands.json
build/
build-*/
build.log
48 changes: 48 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
[submodule "components/arduino"]
path = components/arduino
url = https://github.com/espressif/arduino-esp32.git
shallow = true
[submodule "components/Arduino_GFX/Arduino_GFX"]
path = components/Arduino_GFX/Arduino_GFX
url = https://github.com/moononournation/Arduino_GFX.git
shallow = true
[submodule "components/ArduinoJson/ArduinoJson"]
path = components/ArduinoJson/ArduinoJson
url = https://github.com/bblanchon/ArduinoJson.git
shallow = true
[submodule "components/ESPTelnet/ESPTelnet"]
path = components/ESPTelnet/ESPTelnet
url = https://github.com/LennartHennigs/ESPTelnet.git
shallow = true
[submodule "components/ESP8266Audio/ESP8266Audio"]
path = components/ESP8266Audio/ESP8266Audio
url = https://github.com/earlephilhower/ESP8266Audio.git
shallow = true
[submodule "components/AnimatedGIF/AnimatedGIF"]
path = components/AnimatedGIF/AnimatedGIF
url = https://github.com/bitbank2/AnimatedGIF.git
shallow = true
[submodule "components/JPEGDEC/JPEGDEC"]
path = components/JPEGDEC/JPEGDEC
url = https://github.com/bitbank2/JPEGDEC.git
shallow = true
[submodule "components/lua/arduino-lua"]
path = components/lua/arduino-lua
url = https://github.com/mischief/arduino-lua.git
shallow = true
[submodule "components/U8g2/U8g2_Arduino"]
path = components/U8g2/U8g2_Arduino
url = https://github.com/olikraus/U8g2_Arduino.git
shallow = true
[submodule "components/nofrendo/arduino-nofrendo"]
path = components/nofrendo/arduino-nofrendo
url = https://github.com/lilka-dev/arduino-nofrendo.git
shallow = true
[submodule "components/arduino_tinyusb/tinyusb"]
path = components/arduino_tinyusb/tinyusb
url = https://github.com/hathach/tinyusb.git
shallow = true
[submodule "components/esp-dsp"]
path = components/esp-dsp
url = https://github.com/espressif/esp-dsp.git
shallow = true
4 changes: 2 additions & 2 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
"espressif.esp-idf-extension"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
"platformio.platformio-ide"
]
}
21 changes: 16 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,25 @@
## What not to touch

- `src/keira/keira_version_auto_gen.h` — auto-generated at build time
- `.pio/` — generated by PlatformIO
- `lib/mJS/` and `lib/SimpleFTPServer/` — vendored, don't reformat
- `build/` — generated by ESP-IDF
- Submodules under `components/` (see `.gitmodules`) — pinned upstream code, never edit in place; bump the submodule instead
- `components/lilka/src/` — vendored Lilka SDK, re-sync from upstream instead of editing. Local patches (keep them when re-syncing until upstreamed): `Controller::setVirtualPressed()` in `controller.{h,cpp}`, used by `UARTInputService`
- `components/arduino_tinyusb/` — vendored TinyUSB glue from esp32-arduino-lib-builder
- `components/mJS/` and `components/SimpleFTPServer/` — vendored, don't reformat

## Build gotchas

- The [Lilka SDK](https://github.com/lilka-dev/sdk) must be checked out as a **sibling directory** to `keira/` — `lib_dir = ../../sdk/lib` in `platformio.ini`
- **v2** (ESP32-S3) is the primary target — default in PlatformIO and the one to test against
- **v1** (ESP32-C3) is legacy — only touch if explicitly asked
- Native ESP-IDF CMake project: `make build` (local ESP-IDF) or `make docker-build` (pinned `espressif/idf` image); `make help` lists everything
- ESP-IDF version is pinned per board in `boards/<board>/board.cmake` and enforced at configure time — currently **v4.4.7** with arduino-esp32 **2.0.17** as an IDF component
- Layout: `src/` is the Keira IDF component (`src/CMakeLists.txt`, explicit `REQUIRES`); `components/<name>/` is one component per library — our `CMakeLists.txt` plus the upstream code as a shallow git submodule inside (`components/arduino` and `components/esp-dsp` are submodules that are IDF components themselves)
- `data/spiffs/` becomes the internal filesystem image (`make flash-fs`); `data/img/` and `data/assets/` are repo-only images and design sources
- The Lilka SDK is vendored (not a submodule): `components/lilka/src/` is a verbatim copy of upstream `lib/lilka/src`. Don't edit it in place — to bump, replace the whole dir with the new tag's `lib/lilka/src` and update `LILKA_SDK_VERSION` in `components/lilka/CMakeLists.txt`
- A board is a `boards/<board>/` dir with `board.cmake`, `sdkconfig.defaults` and `partitions.csv`; select it with `make BOARD=<board>`
- Build dirs: `build/` (default board, same as plain `idf.py`), `build-<board>/` for others, `<dir>-docker/` for Docker builds — never mix host and Docker builds in one dir
- Local ESP-IDF must be the pinned tag with matching submodules (`git submodule update --init --recursive`) and its own CMake 3.x (`idf_tools.py install cmake`); CMake 4 is rejected at configure time
- sdkconfig is generated in the build dir and is not refreshed from defaults; after changing `boards/<board>/sdkconfig.defaults` run `make fullclean`
- One-off compile flags: `make FLAGS="-DLANG_EN -DFMANAGER_DEBUG"` (`-DKEIRA_BUILD_FLAGS=...` for `idf.py`)
- **v2** (ESP32-S3) is the only supported board; v1 support was removed
- `clang-format` and `cppcheck` are enforced in CI — run `make clang-format` and `make cppcheck` before committing

## Arduino vs esp-idf
Expand Down
68 changes: 68 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Keira OS — ESP-IDF project.
#
# Build: idf.py build (board defaults to lilka_v2)
# idf.py -DKEIRA_BOARD=<name> build (any directory under boards/)
# or via make, see make help
#
# Layout: src/ is the Keira component; components/<name>/ wraps each library, with the
# upstream code as a pinned git submodule inside. The ESP-IDF version is pinned per
# board in boards/<name>/board.cmake and checked below.

cmake_minimum_required(VERSION 3.16)

# ESP-IDF 4.4 does not configure with CMake 4 (dropped compatibility with its old cmake_minimum_required calls)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 4.0)
message(FATAL_ERROR "CMake ${CMAKE_VERSION} is not supported by ESP-IDF 4.4, use the CMake shipped with it: "
"run '$IDF_PATH/tools/idf_tools.py install cmake', then re-source export.sh "
"(or build with 'make docker-build').")
endif()

set(KEIRA_BOARD "lilka_v2" CACHE STRING "Target board, one of boards/<name>")
set(KEIRA_BOARD_DIR "${CMAKE_CURRENT_LIST_DIR}/boards/${KEIRA_BOARD}")
if(NOT EXISTS "${KEIRA_BOARD_DIR}/board.cmake")
message(FATAL_ERROR "Unknown board '${KEIRA_BOARD}': ${KEIRA_BOARD_DIR}/board.cmake not found")
endif()

# Sets IDF_TARGET, KEIRA_IDF_VERSION and KEIRA_BOARD_DEFINITIONS
include("${KEIRA_BOARD_DIR}/board.cmake")

# Extra flags for a single build, e.g. -DKEIRA_BUILD_FLAGS="-DLANG_EN;-DFMANAGER_DEBUG"
set(KEIRA_BUILD_FLAGS "" CACHE STRING "Extra compile flags (semicolon separated)")

set(SDKCONFIG_DEFAULTS "${KEIRA_BOARD_DIR}/sdkconfig.defaults")
# Keep the generated sdkconfig next to the build, so switching boards is just switching build dirs
set(SDKCONFIG "${CMAKE_BINARY_DIR}/sdkconfig")

# components/* is picked up automatically
set(EXTRA_COMPONENT_DIRS
"${CMAKE_CURRENT_LIST_DIR}/src"
"$ENV{IDF_PATH}/examples/common_components/qrcode"
)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)

set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}")
if(NOT idf_version VERSION_EQUAL KEIRA_IDF_VERSION AND NOT "$ENV{KEIRA_SKIP_IDF_VERSION_CHECK}")
message(FATAL_ERROR "Board ${KEIRA_BOARD} requires ESP-IDF v${KEIRA_IDF_VERSION}, "
"but IDF_PATH points to v${idf_version}. "
"Set KEIRA_SKIP_IDF_VERSION_CHECK=1 to build anyway.")
endif()

foreach(def ${KEIRA_BOARD_DEFINITIONS})
idf_build_set_property(COMPILE_DEFINITIONS "-D${def}" APPEND)
endforeach()
foreach(flag ${KEIRA_BUILD_FLAGS})
idf_build_set_property(COMPILE_OPTIONS "${flag}" APPEND)
endforeach()
idf_build_set_property(CXX_COMPILE_OPTIONS "-Wno-pmf-conversions" APPEND)

project(keira)

# IDF builds with -Werror=all; Keira and its libraries were never built that way under PlatformIO.
# The option list is evaluated at generate time, so dropping it here applies to every component.
idf_build_get_property(compile_options COMPILE_OPTIONS)
list(REMOVE_ITEM compile_options "-Werror=all")
idf_build_set_property(COMPILE_OPTIONS "${compile_options}")

# Filesystem image from data/spiffs/, flashed on demand only (idf.py spiffs-flash) so user files are not wiped
spiffs_create_partition_image(spiffs "${CMAKE_CURRENT_LIST_DIR}/data/spiffs")
Loading
Loading