diff options
| author | ailurux <ailuruxx@gmail.com> | 2024-05-10 13:06:20 +1000 |
|---|---|---|
| committer | ailurux <ailuruxx@gmail.com> | 2024-05-10 13:06:20 +1000 |
| commit | 3f177cdb8880abf199f4445f1398cd69fb813892 (patch) | |
| tree | e20de4949b1344c826e5af41ab701f3db75b21bc /src | |
| parent | 8019c7691889cde4c3d40bbd78d485a92d713bbf (diff) | |
| parent | e4ce7c4ac23402e09be8d6a52e0f739c0dff4ff0 (diff) | |
| download | tangara-fw-3f177cdb8880abf199f4445f1398cd69fb813892.tar.gz | |
Merge branch 'main' into file-browser
Diffstat (limited to 'src')
| -rw-r--r-- | src/app_console/CMakeLists.txt | 9 | ||||
| -rw-r--r-- | src/audio/CMakeLists.txt | 14 | ||||
| -rw-r--r-- | src/audio/audio_decoder.cpp | 148 | ||||
| -rw-r--r-- | src/audio/fatfs_audio_input.cpp | 161 | ||||
| -rw-r--r-- | src/audio/include/audio_decoder.hpp | 56 | ||||
| -rw-r--r-- | src/audio/include/fatfs_audio_input.hpp | 66 | ||||
| -rw-r--r-- | src/battery/CMakeLists.txt | 10 | ||||
| -rw-r--r-- | src/codecs/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/codecs/codec.cpp | 2 | ||||
| -rw-r--r-- | src/codecs/dr_flac.cpp | 2 | ||||
| -rw-r--r-- | src/codecs/include/codec.hpp | 13 | ||||
| -rw-r--r-- | src/codecs/include/dr_flac.hpp | 8 | ||||
| -rw-r--r-- | src/codecs/include/mad.hpp | 4 | ||||
| -rw-r--r-- | src/codecs/include/opus.hpp | 6 | ||||
| -rw-r--r-- | src/codecs/include/source_buffer.hpp | 9 | ||||
| -rw-r--r-- | src/codecs/include/vorbis.hpp | 6 | ||||
| -rw-r--r-- | src/codecs/include/wav.hpp | 2 | ||||
| -rw-r--r-- | src/codecs/mad.cpp | 10 | ||||
| -rw-r--r-- | src/codecs/opus.cpp | 2 | ||||
| -rw-r--r-- | src/codecs/source_buffer.cpp | 10 | ||||
| -rw-r--r-- | src/codecs/test/test_mad.cpp | 6 | ||||
| -rw-r--r-- | src/codecs/vorbis.cpp | 2 | ||||
| -rw-r--r-- | src/codecs/wav.cpp | 59 | ||||
| -rw-r--r-- | src/database/CMakeLists.txt | 22 | ||||
| -rw-r--r-- | src/dev_console/CMakeLists.txt | 9 | ||||
| -rw-r--r-- | src/drivers/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/drivers/adc.cpp | 2 | ||||
| -rw-r--r-- | src/drivers/bluetooth.cpp | 19 | ||||
| -rw-r--r-- | src/drivers/display.cpp | 8 | ||||
| -rw-r--r-- | src/drivers/display_init.cpp | 2 | ||||
| -rw-r--r-- | src/drivers/gpios.cpp | 4 | ||||
| -rw-r--r-- | src/drivers/haptics.cpp | 12 | ||||
| -rw-r--r-- | src/drivers/i2c.cpp | 2 | ||||
| -rw-r--r-- | src/drivers/i2s_dac.cpp | 27 | ||||
| -rw-r--r-- | src/drivers/include/drivers/a2dp_audio_output.hpp (renamed from src/drivers/include/a2dp_audio_output.hpp) | 0 | ||||
| -rw-r--r-- | src/drivers/include/drivers/adc.hpp (renamed from src/drivers/include/adc.hpp) | 0 | ||||
| -rw-r--r-- | src/drivers/include/drivers/bluetooth.hpp (renamed from src/drivers/include/bluetooth.hpp) | 5 | ||||
| -rw-r--r-- | src/drivers/include/drivers/bluetooth_types.hpp (renamed from src/drivers/include/bluetooth_types.hpp) | 0 | ||||
| -rw-r--r-- | src/drivers/include/drivers/display.hpp (renamed from src/drivers/include/display.hpp) | 4 | ||||
| -rw-r--r-- | src/drivers/include/drivers/display_init.hpp (renamed from src/drivers/include/display_init.hpp) | 0 | ||||
| -rw-r--r-- | src/drivers/include/drivers/fatfs_audio_input.hpp (renamed from src/drivers/include/fatfs_audio_input.hpp) | 0 | ||||
| -rw-r--r-- | src/drivers/include/drivers/gpios.hpp (renamed from src/drivers/include/gpios.hpp) | 0 | ||||
| -rw-r--r-- | src/drivers/include/drivers/haptics.hpp (renamed from src/drivers/include/haptics.hpp) | 0 | ||||
| -rw-r--r-- | src/drivers/include/drivers/i2c.hpp (renamed from src/drivers/include/i2c.hpp) | 0 | ||||
| -rw-r--r-- | src/drivers/include/drivers/i2s_dac.hpp (renamed from src/drivers/include/i2s_dac.hpp) | 8 | ||||
| -rw-r--r-- | src/drivers/include/drivers/nvs.hpp (renamed from src/drivers/include/nvs.hpp) | 3 | ||||
| -rw-r--r-- | src/drivers/include/drivers/samd.hpp (renamed from src/drivers/include/samd.hpp) | 0 | ||||
| -rw-r--r-- | src/drivers/include/drivers/spi.hpp (renamed from src/drivers/include/spi.hpp) | 0 | ||||
| -rw-r--r-- | src/drivers/include/drivers/spiffs.hpp (renamed from src/drivers/include/spiffs.hpp) | 0 | ||||
| -rw-r--r-- | src/drivers/include/drivers/storage.hpp (renamed from src/drivers/include/storage.hpp) | 2 | ||||
| -rw-r--r-- | src/drivers/include/drivers/touchwheel.hpp (renamed from src/drivers/include/touchwheel.hpp) | 2 | ||||
| -rw-r--r-- | src/drivers/include/drivers/wm8523.hpp (renamed from src/drivers/include/wm8523.hpp) | 0 | ||||
| -rw-r--r-- | src/drivers/nvs.cpp | 25 | ||||
| -rw-r--r-- | src/drivers/samd.cpp | 4 | ||||
| -rw-r--r-- | src/drivers/spi.cpp | 2 | ||||
| -rw-r--r-- | src/drivers/spiffs.cpp | 2 | ||||
| -rw-r--r-- | src/drivers/storage.cpp | 4 | ||||
| -rw-r--r-- | src/drivers/test/test_dac.cpp | 4 | ||||
| -rw-r--r-- | src/drivers/test/test_gpio_expander.cpp | 4 | ||||
| -rw-r--r-- | src/drivers/test/test_storage.cpp | 8 | ||||
| -rw-r--r-- | src/drivers/touchwheel.cpp | 4 | ||||
| -rw-r--r-- | src/drivers/wm8523.cpp | 4 | ||||
| -rw-r--r-- | src/events/CMakeLists.txt | 9 | ||||
| -rw-r--r-- | src/graphics/CMakeLists.txt | 7 | ||||
| -rw-r--r-- | src/graphics/font_fusion_10.c (renamed from src/ui/font_fusion_10.c) | 0 | ||||
| -rw-r--r-- | src/graphics/font_fusion_12.c (renamed from src/ui/font_fusion_12.c) | 0 | ||||
| -rw-r--r-- | src/graphics/splash.c (renamed from src/ui/splash.c) | 0 | ||||
| -rw-r--r-- | src/input/CMakeLists.txt | 13 | ||||
| -rw-r--r-- | src/input/include/lvgl_input_driver.hpp | 60 | ||||
| -rw-r--r-- | src/input/lvgl_input_driver.cpp | 127 | ||||
| -rw-r--r-- | src/locale/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/locale/include/collation.hpp | 2 | ||||
| -rw-r--r-- | src/lua/CMakeLists.txt | 13 | ||||
| -rw-r--r-- | src/main/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/main/main.cpp | 12 | ||||
| -rw-r--r-- | src/memory/include/himem.hpp | 6 | ||||
| -rw-r--r-- | src/system_fsm/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | src/tangara/CMakeLists.txt | 22 | ||||
| -rw-r--r-- | src/tangara/app_console/app_console.cpp (renamed from src/app_console/app_console.cpp) | 36 | ||||
| -rw-r--r-- | src/tangara/app_console/app_console.hpp (renamed from src/app_console/include/app_console.hpp) | 12 | ||||
| -rw-r--r-- | src/tangara/audio/README.md (renamed from src/audio/README.md) | 0 | ||||
| -rw-r--r-- | src/tangara/audio/audio_decoder.cpp | 199 | ||||
| -rw-r--r-- | src/tangara/audio/audio_decoder.hpp | 60 | ||||
| -rw-r--r-- | src/tangara/audio/audio_events.hpp (renamed from src/audio/include/audio_events.hpp) | 37 | ||||
| -rw-r--r-- | src/tangara/audio/audio_fsm.cpp (renamed from src/audio/audio_fsm.cpp) | 346 | ||||
| -rw-r--r-- | src/tangara/audio/audio_fsm.hpp (renamed from src/audio/include/audio_fsm.hpp) | 64 | ||||
| -rw-r--r-- | src/tangara/audio/audio_sink.hpp (renamed from src/audio/include/audio_sink.hpp) | 1 | ||||
| -rw-r--r-- | src/tangara/audio/audio_source.cpp (renamed from src/audio/audio_source.cpp) | 10 | ||||
| -rw-r--r-- | src/tangara/audio/audio_source.hpp (renamed from src/audio/include/audio_source.hpp) | 7 | ||||
| -rw-r--r-- | src/tangara/audio/bt_audio_output.cpp (renamed from src/audio/bt_audio_output.cpp) | 14 | ||||
| -rw-r--r-- | src/tangara/audio/bt_audio_output.hpp (renamed from src/audio/include/bt_audio_output.hpp) | 10 | ||||
| -rw-r--r-- | src/tangara/audio/fatfs_source.cpp (renamed from src/audio/fatfs_source.cpp) | 12 | ||||
| -rw-r--r-- | src/tangara/audio/fatfs_source.hpp (renamed from src/audio/include/fatfs_source.hpp) | 4 | ||||
| -rw-r--r-- | src/tangara/audio/fatfs_stream_factory.cpp | 104 | ||||
| -rw-r--r-- | src/tangara/audio/fatfs_stream_factory.hpp | 53 | ||||
| -rw-r--r-- | src/tangara/audio/i2s_audio_output.cpp (renamed from src/audio/i2s_audio_output.cpp) | 21 | ||||
| -rw-r--r-- | src/tangara/audio/i2s_audio_output.hpp (renamed from src/audio/include/i2s_audio_output.hpp) | 8 | ||||
| -rw-r--r-- | src/tangara/audio/processor.cpp (renamed from src/audio/audio_converter.cpp) | 132 | ||||
| -rw-r--r-- | src/tangara/audio/processor.hpp (renamed from src/audio/include/audio_converter.hpp) | 37 | ||||
| -rw-r--r-- | src/tangara/audio/readahead_source.cpp (renamed from src/audio/readahead_source.cpp) | 8 | ||||
| -rw-r--r-- | src/tangara/audio/readahead_source.hpp (renamed from src/audio/include/readahead_source.hpp) | 4 | ||||
| -rw-r--r-- | src/tangara/audio/resample.cpp (renamed from src/audio/resample.cpp) | 6 | ||||
| -rw-r--r-- | src/tangara/audio/resample.hpp (renamed from src/audio/include/resample.hpp) | 8 | ||||
| -rw-r--r-- | src/tangara/audio/stream_cues.cpp | 65 | ||||
| -rw-r--r-- | src/tangara/audio/stream_cues.hpp | 49 | ||||
| -rw-r--r-- | src/tangara/audio/test/CMakeLists.txt (renamed from src/audio/test/CMakeLists.txt) | 0 | ||||
| -rw-r--r-- | src/tangara/audio/track_queue.cpp (renamed from src/audio/track_queue.cpp) | 14 | ||||
| -rw-r--r-- | src/tangara/audio/track_queue.hpp (renamed from src/audio/include/track_queue.hpp) | 6 | ||||
| -rw-r--r-- | src/tangara/battery/battery.cpp (renamed from src/battery/battery.cpp) | 10 | ||||
| -rw-r--r-- | src/tangara/battery/battery.hpp (renamed from src/battery/include/battery.hpp) | 4 | ||||
| -rw-r--r-- | src/tangara/database/database.cpp (renamed from src/database/database.cpp) | 24 | ||||
| -rw-r--r-- | src/tangara/database/database.hpp (renamed from src/database/include/database.hpp) | 10 | ||||
| -rw-r--r-- | src/tangara/database/db_events.hpp (renamed from src/database/include/db_events.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/database/env_esp.cpp (renamed from src/database/env_esp.cpp) | 6 | ||||
| -rw-r--r-- | src/tangara/database/env_esp.hpp (renamed from src/database/include/env_esp.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/database/file_gatherer.cpp (renamed from src/database/file_gatherer.cpp) | 4 | ||||
| -rw-r--r-- | src/tangara/database/file_gatherer.hpp (renamed from src/database/include/file_gatherer.hpp) | 12 | ||||
| -rw-r--r-- | src/tangara/database/future_fetcher.hpp (renamed from src/database/include/future_fetcher.hpp) | 2 | ||||
| -rw-r--r-- | src/tangara/database/index.cpp (renamed from src/database/index.cpp) | 21 | ||||
| -rw-r--r-- | src/tangara/database/index.hpp (renamed from src/database/include/index.hpp) | 7 | ||||
| -rw-r--r-- | src/tangara/database/records.cpp (renamed from src/database/records.cpp) | 8 | ||||
| -rw-r--r-- | src/tangara/database/records.hpp (renamed from src/database/include/records.hpp) | 6 | ||||
| -rw-r--r-- | src/tangara/database/tag_parser.cpp (renamed from src/database/tag_parser.cpp) | 4 | ||||
| -rw-r--r-- | src/tangara/database/tag_parser.hpp (renamed from src/database/include/tag_parser.hpp) | 2 | ||||
| -rw-r--r-- | src/tangara/database/test/CMakeLists.txt (renamed from src/database/test/CMakeLists.txt) | 0 | ||||
| -rw-r--r-- | src/tangara/database/test/test_database.cpp (renamed from src/database/test/test_database.cpp) | 16 | ||||
| -rw-r--r-- | src/tangara/database/test/test_records.cpp (renamed from src/database/test/test_records.cpp) | 2 | ||||
| -rw-r--r-- | src/tangara/database/track.cpp (renamed from src/database/track.cpp) | 10 | ||||
| -rw-r--r-- | src/tangara/database/track.hpp (renamed from src/database/include/track.hpp) | 9 | ||||
| -rw-r--r-- | src/tangara/dev_console/console.cpp (renamed from src/dev_console/console.cpp) | 2 | ||||
| -rw-r--r-- | src/tangara/dev_console/console.hpp (renamed from src/dev_console/include/console.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/events/event_queue.cpp (renamed from src/events/event_queue.cpp) | 9 | ||||
| -rw-r--r-- | src/tangara/events/event_queue.hpp (renamed from src/events/include/event_queue.hpp) | 6 | ||||
| -rw-r--r-- | src/tangara/input/device_factory.cpp (renamed from src/input/device_factory.cpp) | 14 | ||||
| -rw-r--r-- | src/tangara/input/device_factory.hpp (renamed from src/input/include/device_factory.hpp) | 10 | ||||
| -rw-r--r-- | src/tangara/input/feedback_device.hpp (renamed from src/input/include/feedback_device.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/input/feedback_haptics.cpp (renamed from src/input/feedback_haptics.cpp) | 4 | ||||
| -rw-r--r-- | src/tangara/input/feedback_haptics.hpp (renamed from src/input/include/feedback_haptics.hpp) | 4 | ||||
| -rw-r--r-- | src/tangara/input/input_device.hpp (renamed from src/input/include/input_device.hpp) | 8 | ||||
| -rw-r--r-- | src/tangara/input/input_hook.cpp (renamed from src/input/input_hook.cpp) | 36 | ||||
| -rw-r--r-- | src/tangara/input/input_hook.hpp (renamed from src/input/include/input_hook.hpp) | 18 | ||||
| -rw-r--r-- | src/tangara/input/input_hook_actions.cpp (renamed from src/input/input_hook_actions.cpp) | 6 | ||||
| -rw-r--r-- | src/tangara/input/input_hook_actions.hpp (renamed from src/input/include/input_hook_actions.hpp) | 2 | ||||
| -rw-r--r-- | src/tangara/input/input_nav_buttons.cpp (renamed from src/input/input_nav_buttons.cpp) | 15 | ||||
| -rw-r--r-- | src/tangara/input/input_nav_buttons.hpp (renamed from src/input/include/input_nav_buttons.hpp) | 14 | ||||
| -rw-r--r-- | src/tangara/input/input_touch_dpad.cpp (renamed from src/input/input_touch_dpad.cpp) | 28 | ||||
| -rw-r--r-- | src/tangara/input/input_touch_dpad.hpp (renamed from src/input/include/input_touch_dpad.hpp) | 12 | ||||
| -rw-r--r-- | src/tangara/input/input_touch_wheel.cpp (renamed from src/input/input_touch_wheel.cpp) | 68 | ||||
| -rw-r--r-- | src/tangara/input/input_touch_wheel.hpp (renamed from src/input/include/input_touch_wheel.hpp) | 16 | ||||
| -rw-r--r-- | src/tangara/input/input_trigger.cpp (renamed from src/input/input_trigger.cpp) | 55 | ||||
| -rw-r--r-- | src/tangara/input/input_trigger.hpp (renamed from src/input/include/input_trigger.hpp) | 8 | ||||
| -rw-r--r-- | src/tangara/input/input_volume_buttons.cpp (renamed from src/input/input_volume_buttons.cpp) | 11 | ||||
| -rw-r--r-- | src/tangara/input/input_volume_buttons.hpp (renamed from src/input/include/input_volume_buttons.hpp) | 12 | ||||
| -rw-r--r-- | src/tangara/input/lvgl_input_driver.cpp | 258 | ||||
| -rw-r--r-- | src/tangara/input/lvgl_input_driver.hpp | 112 | ||||
| -rw-r--r-- | src/tangara/lua/bridge.cpp (renamed from src/lua/bridge.cpp) | 35 | ||||
| -rw-r--r-- | src/tangara/lua/bridge.hpp (renamed from src/lua/include/bridge.hpp) | 9 | ||||
| -rw-r--r-- | src/tangara/lua/file_iterator.cpp (renamed from src/lua/file_iterator.cpp) | 0 | ||||
| -rw-r--r-- | src/tangara/lua/file_iterator.hpp (renamed from src/lua/include/file_iterator.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/lua/lua_controls.cpp (renamed from src/lua/lua_controls.cpp) | 6 | ||||
| -rw-r--r-- | src/tangara/lua/lua_controls.hpp (renamed from src/lua/include/lua_controls.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/lua/lua_database.cpp (renamed from src/lua/lua_database.cpp) | 36 | ||||
| -rw-r--r-- | src/tangara/lua/lua_database.hpp (renamed from src/lua/include/lua_database.hpp) | 2 | ||||
| -rw-r--r-- | src/tangara/lua/lua_filesystem.cpp (renamed from src/lua/lua_filesystem.cpp) | 0 | ||||
| -rw-r--r-- | src/tangara/lua/lua_filesystem.hpp (renamed from src/lua/include/lua_filesystem.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/lua/lua_queue.cpp (renamed from src/lua/lua_queue.cpp) | 20 | ||||
| -rw-r--r-- | src/tangara/lua/lua_queue.hpp (renamed from src/lua/include/lua_queue.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/lua/lua_registry.hpp (renamed from src/lua/include/lua_registry.hpp) | 6 | ||||
| -rw-r--r-- | src/tangara/lua/lua_screen.cpp (renamed from src/lua/lua_screen.cpp) | 20 | ||||
| -rw-r--r-- | src/tangara/lua/lua_screen.hpp (renamed from src/lua/include/lua_screen.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/lua/lua_theme.cpp (renamed from src/lua/lua_theme.cpp) | 25 | ||||
| -rw-r--r-- | src/tangara/lua/lua_theme.hpp (renamed from src/lua/include/lua_theme.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/lua/lua_thread.cpp (renamed from src/lua/lua_thread.cpp) | 16 | ||||
| -rw-r--r-- | src/tangara/lua/lua_thread.hpp (renamed from src/lua/include/lua_thread.hpp) | 2 | ||||
| -rw-r--r-- | src/tangara/lua/lua_version.cpp (renamed from src/lua/lua_version.cpp) | 6 | ||||
| -rw-r--r-- | src/tangara/lua/lua_version.hpp (renamed from src/lua/include/lua_version.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/lua/property.cpp (renamed from src/lua/property.cpp) | 12 | ||||
| -rw-r--r-- | src/tangara/lua/property.hpp (renamed from src/lua/include/property.hpp) | 6 | ||||
| -rw-r--r-- | src/tangara/lua/registry.cpp (renamed from src/lua/registry.cpp) | 10 | ||||
| -rw-r--r-- | src/tangara/system_fsm/booting.cpp (renamed from src/system_fsm/booting.cpp) | 42 | ||||
| -rw-r--r-- | src/tangara/system_fsm/idle.cpp (renamed from src/system_fsm/idle.cpp) | 20 | ||||
| -rw-r--r-- | src/tangara/system_fsm/running.cpp (renamed from src/system_fsm/running.cpp) | 84 | ||||
| -rw-r--r-- | src/tangara/system_fsm/service_locator.cpp (renamed from src/system_fsm/service_locator.cpp) | 8 | ||||
| -rw-r--r-- | src/tangara/system_fsm/service_locator.hpp (renamed from src/system_fsm/include/service_locator.hpp) | 22 | ||||
| -rw-r--r-- | src/tangara/system_fsm/system_events.hpp (renamed from src/system_fsm/include/system_events.hpp) | 18 | ||||
| -rw-r--r-- | src/tangara/system_fsm/system_fsm.cpp (renamed from src/system_fsm/system_fsm.cpp) | 16 | ||||
| -rw-r--r-- | src/tangara/system_fsm/system_fsm.hpp (renamed from src/system_fsm/include/system_fsm.hpp) | 39 | ||||
| -rw-r--r-- | src/tangara/ui/fonts.hpp (renamed from src/ui/include/fonts.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/ui/lvgl_task.cpp (renamed from src/ui/lvgl_task.cpp) | 16 | ||||
| -rw-r--r-- | src/tangara/ui/lvgl_task.hpp (renamed from src/ui/include/lvgl_task.hpp) | 10 | ||||
| -rw-r--r-- | src/tangara/ui/modal.cpp (renamed from src/ui/modal.cpp) | 14 | ||||
| -rw-r--r-- | src/tangara/ui/modal.hpp (renamed from src/ui/include/modal.hpp) | 2 | ||||
| -rw-r--r-- | src/tangara/ui/screen.cpp (renamed from src/ui/screen.cpp) | 2 | ||||
| -rw-r--r-- | src/tangara/ui/screen.hpp (renamed from src/ui/include/screen.hpp) | 0 | ||||
| -rw-r--r-- | src/tangara/ui/screen_lua.cpp (renamed from src/ui/screen_lua.cpp) | 8 | ||||
| -rw-r--r-- | src/tangara/ui/screen_lua.hpp (renamed from src/ui/include/screen_lua.hpp) | 4 | ||||
| -rw-r--r-- | src/tangara/ui/screen_splash.cpp (renamed from src/ui/screen_splash.cpp) | 2 | ||||
| -rw-r--r-- | src/tangara/ui/screen_splash.hpp (renamed from src/ui/include/screen_splash.hpp) | 2 | ||||
| -rw-r--r-- | src/tangara/ui/themes.cpp (renamed from src/ui/themes.cpp) | 25 | ||||
| -rw-r--r-- | src/tangara/ui/themes.hpp (renamed from src/ui/include/themes.hpp) | 3 | ||||
| -rw-r--r-- | src/tangara/ui/ui_events.hpp (renamed from src/ui/include/ui_events.hpp) | 10 | ||||
| -rw-r--r-- | src/tangara/ui/ui_fsm.cpp (renamed from src/ui/ui_fsm.cpp) | 133 | ||||
| -rw-r--r-- | src/tangara/ui/ui_fsm.hpp (renamed from src/ui/include/ui_fsm.hpp) | 54 | ||||
| -rw-r--r-- | src/tasks/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/tasks/tasks.cpp | 10 | ||||
| -rw-r--r-- | src/tasks/tasks.hpp | 8 | ||||
| -rw-r--r-- | src/ui/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | src/ui/font_symbols.c | 425 | ||||
| -rw-r--r-- | src/ui/icons/battery_20.c | 52 | ||||
| -rw-r--r-- | src/ui/icons/battery_40.c | 52 | ||||
| -rw-r--r-- | src/ui/icons/battery_60.c | 52 | ||||
| -rw-r--r-- | src/ui/icons/battery_80.c | 52 | ||||
| -rw-r--r-- | src/ui/icons/battery_empty.c | 52 | ||||
| -rw-r--r-- | src/ui/icons/battery_full.c | 52 | ||||
| -rw-r--r-- | src/ui/icons/bluetooth.c | 54 | ||||
| -rw-r--r-- | src/ui/icons/pause.c | 54 | ||||
| -rw-r--r-- | src/ui/icons/play.c | 54 | ||||
| -rw-r--r-- | src/ui/include/ui_tick.hpp | 11 | ||||
| -rw-r--r-- | src/util/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/util/include/debug.hpp | 5 | ||||
| -rw-r--r-- | src/util/random.cpp | 4 |
221 files changed, 2180 insertions, 2821 deletions
diff --git a/src/app_console/CMakeLists.txt b/src/app_console/CMakeLists.txt deleted file mode 100644 index 1a2ae8d6..00000000 --- a/src/app_console/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2023 jacqueline <me@jacqueline.id.au> -# -# SPDX-License-Identifier: GPL-3.0-only - -idf_component_register( - SRCS "app_console.cpp" - INCLUDE_DIRS "include" - REQUIRES "dev_console" "events" "database") -target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt deleted file mode 100644 index 8ed5efbb..00000000 --- a/src/audio/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2023 jacqueline <me@jacqueline.id.au> -# -# SPDX-License-Identifier: GPL-3.0-only - -idf_component_register( - SRCS "audio_decoder.cpp" "fatfs_audio_input.cpp" "i2s_audio_output.cpp" - "track_queue.cpp" "audio_fsm.cpp" "audio_converter.cpp" "resample.cpp" - "fatfs_source.cpp" "bt_audio_output.cpp" "readahead_source.cpp" - "audio_source.cpp" - INCLUDE_DIRS "include" - REQUIRES "codecs" "drivers" "cbor" "result" "tasks" "span" "memory" "tinyfsm" - "database" "system_fsm" "speexdsp" "millershuffle" "libcppbor") - -target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/audio/audio_decoder.cpp b/src/audio/audio_decoder.cpp deleted file mode 100644 index 90c69c16..00000000 --- a/src/audio/audio_decoder.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2023 jacqueline <me@jacqueline.id.au> - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#include "audio_decoder.hpp" -#include <stdint.h> - -#include <cstdint> -#include <cstdlib> - -#include <algorithm> -#include <cmath> -#include <cstddef> -#include <cstdint> -#include <cstring> -#include <deque> -#include <memory> -#include <variant> - -#include "cbor.h" -#include "esp_err.h" -#include "esp_heap_caps.h" -#include "esp_log.h" -#include "freertos/portmacro.h" -#include "freertos/projdefs.h" -#include "freertos/queue.h" -#include "freertos/ringbuf.h" -#include "i2s_dac.hpp" -#include "span.hpp" - -#include "audio_converter.hpp" -#include "audio_events.hpp" -#include "audio_fsm.hpp" -#include "audio_sink.hpp" -#include "audio_source.hpp" -#include "codec.hpp" -#include "event_queue.hpp" -#include "fatfs_audio_input.hpp" -#include "sample.hpp" -#include "tasks.hpp" -#include "track.hpp" -#include "types.hpp" -#include "ui_fsm.hpp" - -namespace audio { - -[[maybe_unused]] static const char* kTag = "audio_dec"; - -static constexpr std::size_t kCodecBufferLength = - drivers::kI2SBufferLengthFrames * sizeof(sample::Sample); - -auto Decoder::Start(std::shared_ptr<IAudioSource> source, - std::shared_ptr<SampleConverter> sink) -> Decoder* { - Decoder* task = new Decoder(source, sink); - tasks::StartPersistent<tasks::Type::kAudioDecoder>([=]() { task->Main(); }); - return task; -} - -Decoder::Decoder(std::shared_ptr<IAudioSource> source, - std::shared_ptr<SampleConverter> mixer) - : source_(source), converter_(mixer), codec_(), current_format_() { - ESP_LOGI(kTag, "allocating codec buffer, %u KiB", kCodecBufferLength / 1024); - codec_buffer_ = { - reinterpret_cast<sample::Sample*>(heap_caps_calloc( - kCodecBufferLength, sizeof(sample::Sample), MALLOC_CAP_DMA)), - kCodecBufferLength}; -} - -void Decoder::Main() { - for (;;) { - if (source_->HasNewStream() || !stream_) { - std::shared_ptr<TaggedStream> new_stream = source_->NextStream(); - if (new_stream && BeginDecoding(new_stream)) { - stream_ = new_stream; - } else { - continue; - } - } - - if (ContinueDecoding()) { - stream_.reset(); - } - } -} - -auto Decoder::BeginDecoding(std::shared_ptr<TaggedStream> stream) -> bool { - // Ensure any previous codec is freed before creating a new one. - codec_.reset(); - codec_.reset(codecs::CreateCodecForType(stream->type()).value_or(nullptr)); - if (!codec_) { - ESP_LOGE(kTag, "no codec found for stream"); - return false; - } - - auto open_res = codec_->OpenStream(stream, stream->Offset()); - if (open_res.has_error()) { - ESP_LOGE(kTag, "codec failed to start: %s", - codecs::ICodec::ErrorString(open_res.error()).c_str()); - return false; - } - stream->SetPreambleFinished(); - current_sink_format_ = IAudioOutput::Format{ - .sample_rate = open_res->sample_rate_hz, - .num_channels = open_res->num_channels, - .bits_per_sample = 16, - }; - - std::optional<uint32_t> duration; - if (open_res->total_samples) { - duration = open_res->total_samples.value() / open_res->num_channels / - open_res->sample_rate_hz; - } - - converter_->beginStream(std::make_shared<TrackInfo>(TrackInfo{ - .tags = stream->tags(), - .uri = stream->Filepath(), - .duration = duration, - .start_offset = stream->Offset(), - .bitrate_kbps = open_res->sample_rate_hz, - .encoding = stream->type(), - .format = *current_sink_format_, - })); - - return true; -} - -auto Decoder::ContinueDecoding() -> bool { - auto res = codec_->DecodeTo(codec_buffer_); - if (res.has_error()) { - converter_->endStream(); - return true; - } - - if (res->samples_written > 0) { - converter_->continueStream(codec_buffer_.first(res->samples_written)); - } - - if (res->is_stream_finished) { - converter_->endStream(); - codec_.reset(); - } - - return res->is_stream_finished; -} - -} // namespace audio diff --git a/src/audio/fatfs_audio_input.cpp b/src/audio/fatfs_audio_input.cpp deleted file mode 100644 index 29d32390..00000000 --- a/src/audio/fatfs_audio_input.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2023 jacqueline <me@jacqueline.id.au> - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#include "fatfs_audio_input.hpp" - -#include <algorithm> -#include <climits> -#include <cstddef> -#include <cstdint> -#include <functional> -#include <future> -#include <memory> -#include <mutex> -#include <string> -#include <variant> - -#include "esp_heap_caps.h" -#include "esp_log.h" -#include "ff.h" -#include "freertos/portmacro.h" -#include "freertos/projdefs.h" -#include "readahead_source.hpp" -#include "span.hpp" - -#include "audio_events.hpp" -#include "audio_fsm.hpp" -#include "audio_source.hpp" -#include "codec.hpp" -#include "event_queue.hpp" -#include "fatfs_source.hpp" -#include "future_fetcher.hpp" -#include "spi.hpp" -#include "tag_parser.hpp" -#include "tasks.hpp" -#include "track.hpp" -#include "types.hpp" - -[[maybe_unused]] static const char* kTag = "SRC"; - -namespace audio { - -FatfsAudioInput::FatfsAudioInput(database::ITagParser& tag_parser, - tasks::WorkerPool& bg_worker) - : IAudioSource(), - tag_parser_(tag_parser), - bg_worker_(bg_worker), - new_stream_mutex_(), - new_stream_(), - has_new_stream_(false) {} - -FatfsAudioInput::~FatfsAudioInput() {} - -auto FatfsAudioInput::SetPath(std::optional<std::string> path) -> void { - if (path) { - SetPath(*path); - } else { - SetPath(); - } -} - -auto FatfsAudioInput::SetPath(const std::string& path,uint32_t offset) -> void { - std::lock_guard<std::mutex> guard{new_stream_mutex_}; - if (OpenFile(path, offset)) { - has_new_stream_ = true; - has_new_stream_.notify_one(); - } -} - -auto FatfsAudioInput::SetPath() -> void { - std::lock_guard<std::mutex> guard{new_stream_mutex_}; - new_stream_.reset(); - has_new_stream_ = true; - has_new_stream_.notify_one(); -} - -auto FatfsAudioInput::HasNewStream() -> bool { - return has_new_stream_; -} - -auto FatfsAudioInput::NextStream() -> std::shared_ptr<TaggedStream> { - while (true) { - has_new_stream_.wait(false); - - { - std::lock_guard<std::mutex> guard{new_stream_mutex_}; - if (!has_new_stream_.exchange(false)) { - // If the new stream went away, then we need to go back to waiting. - continue; - } - - if (new_stream_ == nullptr) { - continue; - } - - auto stream = new_stream_; - new_stream_ = nullptr; - return stream; - } - } -} - -auto FatfsAudioInput::OpenFile(const std::string& path,uint32_t offset) -> bool { - ESP_LOGI(kTag, "opening file %s", path.c_str()); - - auto tags = tag_parser_.ReadAndParseTags(path); - if (!tags) { - ESP_LOGE(kTag, "failed to read tags"); - return false; - } - if (!tags->title()) { - tags->title(path); - } - - auto stream_type = ContainerToStreamType(tags->encoding()); - if (!stream_type.has_value()) { - ESP_LOGE(kTag, "couldn't match container to stream"); - return false; - } - - std::unique_ptr<FIL> file = std::make_unique<FIL>(); - FRESULT res; - - { - auto lock = drivers::acquire_spi(); - res = f_open(file.get(), path.c_str(), FA_READ); - } - - if (res != FR_OK) { - ESP_LOGE(kTag, "failed to open file! res: %i", res); - return false; - } - - auto source = - std::make_unique<FatfsSource>(stream_type.value(), std::move(file)); - new_stream_.reset(new TaggedStream(tags, std::move(source), path, offset)); - return true; -} - -auto FatfsAudioInput::ContainerToStreamType(database::Container enc) - -> std::optional<codecs::StreamType> { - switch (enc) { - case database::Container::kMp3: - return codecs::StreamType::kMp3; - case database::Container::kWav: - return codecs::StreamType::kWav; - case database::Container::kOgg: - return codecs::StreamType::kVorbis; - case database::Container::kFlac: - return codecs::StreamType::kFlac; - case database::Container::kOpus: - return codecs::StreamType::kOpus; - case database::Container::kUnsupported: - default: - return {}; - } -} - -} // namespace audio diff --git a/src/audio/include/audio_decoder.hpp b/src/audio/include/audio_decoder.hpp deleted file mode 100644 index 89f0f43c..00000000 --- a/src/audio/include/audio_decoder.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2023 jacqueline <me@jacqueline.id.au> - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include <cstdint> -#include <memory> - -#include "audio_converter.hpp" -#include "audio_events.hpp" -#include "audio_sink.hpp" -#include "audio_source.hpp" -#include "codec.hpp" -#include "track.hpp" -#include "types.hpp" - -namespace audio { - -/* - * Handle to a persistent task that takes bytes from the given source, decodes - * them into sample::Sample (normalised to 16 bit signed PCM), and then - * forwards the resulting stream to the given converter. - */ -class Decoder { - public: - static auto Start(std::shared_ptr<IAudioSource> source, - std::shared_ptr<SampleConverter> converter) -> Decoder*; - - auto Main() -> void; - - Decoder(const Decoder&) = delete; - Decoder& operator=(const Decoder&) = delete; - - private: - Decoder(std::shared_ptr<IAudioSource> source, - std::shared_ptr<SampleConverter> converter); - - auto BeginDecoding(std::shared_ptr<TaggedStream>) -> bool; - auto ContinueDecoding() -> bool; - - std::shared_ptr<IAudioSource> source_; - std::shared_ptr<SampleConverter> converter_; - - std::shared_ptr<codecs::IStream> stream_; - std::unique_ptr<codecs::ICodec> codec_; - - std::optional<codecs::ICodec::OutputFormat> current_format_; - std::optional<IAudioOutput::Format> current_sink_format_; - - cpp::span<sample::Sample> codec_buffer_; -}; - -} // namespace audio diff --git a/src/audio/include/fatfs_audio_input.hpp b/src/audio/include/fatfs_audio_input.hpp deleted file mode 100644 index 10b7433e..00000000 --- a/src/audio/include/fatfs_audio_input.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2023 jacqueline <me@jacqueline.id.au> - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include <cstddef> -#include <cstdint> -#include <future> -#include <memory> -#include <string> - -#include "ff.h" -#include "freertos/portmacro.h" - -#include "audio_source.hpp" -#include "codec.hpp" -#include "future_fetcher.hpp" -#include "tag_parser.hpp" -#include "tasks.hpp" -#include "types.hpp" - -namespace audio { - -/* - * Audio source that fetches data from a FatFs (or exfat i guess) filesystem. - * - * All public methods are safe to call from any task. - */ -class FatfsAudioInput : public IAudioSource { - public: - explicit FatfsAudioInput(database::ITagParser&, tasks::WorkerPool&); - ~FatfsAudioInput(); - - /* - * Immediately cease reading any current source, and begin reading from the - * given file path. - */ - auto SetPath(std::optional<std::string>) -> void; - auto SetPath(const std::string&,uint32_t offset = 0) -> void; - auto SetPath() -> void; - - auto HasNewStream() -> bool override; - auto NextStream() -> std::shared_ptr<TaggedStream> override; - - FatfsAudioInput(const FatfsAudioInput&) = delete; - FatfsAudioInput& operator=(const FatfsAudioInput&) = delete; - - private: - auto OpenFile(const std::string& path,uint32_t offset) -> bool; - - auto ContainerToStreamType(database::Container) - -> std::optional<codecs::StreamType>; - - database::ITagParser& tag_parser_; - tasks::WorkerPool& bg_worker_; - - std::mutex new_stream_mutex_; - std::shared_ptr<TaggedStream> new_stream_; - - std::atomic<bool> has_new_stream_; -}; - -} // namespace audio diff --git a/src/battery/CMakeLists.txt b/src/battery/CMakeLists.txt deleted file mode 100644 index 313a3731..00000000 --- a/src/battery/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2023 jacqueline <me@jacqueline.id.au> -# -# SPDX-License-Identifier: GPL-3.0-only - -idf_component_register( - SRCS "battery.cpp" - INCLUDE_DIRS "include" - REQUIRES "drivers" "events") - -target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/codecs/CMakeLists.txt b/src/codecs/CMakeLists.txt index b6481bd1..a1221adf 100644 --- a/src/codecs/CMakeLists.txt +++ b/src/codecs/CMakeLists.txt @@ -6,7 +6,7 @@ idf_component_register( SRCS "dr_flac.cpp" "codec.cpp" "mad.cpp" "opus.cpp" "vorbis.cpp" "source_buffer.cpp" "sample.cpp" "wav.cpp" INCLUDE_DIRS "include" - REQUIRES "result" "span" "libmad" "drflac" "tremor" "opusfile" "memory" "util" + REQUIRES "result" "libmad" "drflac" "tremor" "opusfile" "memory" "util" "komihash") target_compile_options("${COMPONENT_LIB}" PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/codecs/codec.cpp b/src/codecs/codec.cpp index a51c40d6..c8e1a72c 100644 --- a/src/codecs/codec.cpp +++ b/src/codecs/codec.cpp @@ -9,8 +9,8 @@ #include <memory> #include <optional> -#include "mad.hpp" #include "dr_flac.hpp" +#include "mad.hpp" #include "opus.hpp" #include "types.hpp" #include "vorbis.hpp" diff --git a/src/codecs/dr_flac.cpp b/src/codecs/dr_flac.cpp index 2f9acf8c..9341e938 100644 --- a/src/codecs/dr_flac.cpp +++ b/src/codecs/dr_flac.cpp @@ -100,7 +100,7 @@ auto DrFlacDecoder::OpenStream(std::shared_ptr<IStream> input, uint32_t offset) return format; } -auto DrFlacDecoder::DecodeTo(cpp::span<sample::Sample> output) +auto DrFlacDecoder::DecodeTo(std::span<sample::Sample> output) -> cpp::result<OutputInfo, Error> { size_t frames_to_read = output.size() / flac_->channels / 2; diff --git a/src/codecs/include/codec.hpp b/src/codecs/include/codec.hpp index e48e3c58..4d588a98 100644 --- a/src/codecs/include/codec.hpp +++ b/src/codecs/include/codec.hpp @@ -6,19 +6,16 @@ #pragma once -#include <stdint.h> -#include <sys/_stdint.h> - #include <cstddef> #include <cstdint> #include <memory> #include <optional> +#include <span> #include <string> #include <utility> #include "result.hpp" #include "sample.hpp" -#include "span.hpp" #include "types.hpp" #include "memory_resource.hpp" @@ -35,7 +32,7 @@ class IStream { auto type() -> StreamType { return t_; } - virtual auto Read(cpp::span<std::byte> dest) -> ssize_t = 0; + virtual auto Read(std::span<std::byte> dest) -> ssize_t = 0; virtual auto CanSeek() -> bool = 0; @@ -54,7 +51,7 @@ class IStream { /* * Called by codecs to indicate that they've finished parsing any header data * within this stream, and are about to begin decoding. - * + * * Currently used as a hint to the readahead stream to begin prefetching file * data. */ @@ -117,7 +114,7 @@ class ICodec { * Decodes metadata or headers from the given input stream, and returns the * format for the samples that will be decoded from it. */ - virtual auto OpenStream(std::shared_ptr<IStream> input,uint32_t offset) + virtual auto OpenStream(std::shared_ptr<IStream> input, uint32_t offset) -> cpp::result<OutputFormat, Error> = 0; struct OutputInfo { @@ -128,7 +125,7 @@ class ICodec { /* * Writes PCM samples to the given output buffer. */ - virtual auto DecodeTo(cpp::span<sample::Sample> destination) + virtual auto DecodeTo(std::span<sample::Sample> destination) -> cpp::result<OutputInfo, Error> = 0; }; diff --git a/src/codecs/include/dr_flac.hpp b/src/codecs/include/dr_flac.hpp index 547876f4..ac46e92f 100644 --- a/src/codecs/include/dr_flac.hpp +++ b/src/codecs/include/dr_flac.hpp @@ -10,13 +10,13 @@ #include <cstdint> #include <memory> #include <optional> +#include <span> #include <string> #include <utility> #include "dr_flac.h" #include "sample.hpp" #include "source_buffer.hpp" -#include "span.hpp" #include "codec.hpp" @@ -27,10 +27,10 @@ class DrFlacDecoder : public ICodec { DrFlacDecoder(); ~DrFlacDecoder(); - auto OpenStream(std::shared_ptr<IStream> input,uint32_t offset) + auto OpenStream(std::shared_ptr<IStream> input, uint32_t offset) -> cpp::result<OutputFormat, Error> override; - auto DecodeTo(cpp::span<sample::Sample> destination) + auto DecodeTo(std::span<sample::Sample> destination) -> cpp::result<OutputInfo, Error> override; DrFlacDecoder(const DrFlacDecoder&) = delete; @@ -38,7 +38,7 @@ class DrFlacDecoder : public ICodec { private: std::shared_ptr<IStream> input_; - drflac *flac_; + drflac* flac_; }; } // namespace codecs diff --git a/src/codecs/include/mad.hpp b/src/codecs/include/mad.hpp index ead0b2a2..d1d0aac5 100644 --- a/src/codecs/include/mad.hpp +++ b/src/codecs/include/mad.hpp @@ -11,11 +11,11 @@ #include <optional> #include <string> #include <utility> +#include <span> #include "mad.h" #include "sample.hpp" #include "source_buffer.hpp" -#include "span.hpp" #include "codec.hpp" @@ -29,7 +29,7 @@ class MadMp3Decoder : public ICodec { auto OpenStream(std::shared_ptr<IStream> input,uint32_t offset) -> cpp::result<OutputFormat, Error> override; - auto DecodeTo(cpp::span<sample::Sample> destination) + auto DecodeTo(std::span<sample::Sample> destination) -> cpp::result<OutputInfo, Error> override; MadMp3Decoder(const MadMp3Decoder&) = delete; diff --git a/src/codecs/include/opus.hpp b/src/codecs/include/opus.hpp index de2f7131..200b2d44 100644 --- a/src/codecs/include/opus.hpp +++ b/src/codecs/include/opus.hpp @@ -10,12 +10,12 @@ #include <cstdint> #include <memory> #include <optional> +#include <span> #include <string> #include <utility> #include "opusfile.h" #include "sample.hpp" -#include "span.hpp" #include "codec.hpp" @@ -26,10 +26,10 @@ class XiphOpusDecoder : public ICodec { XiphOpusDecoder(); ~XiphOpusDecoder(); - auto OpenStream(std::shared_ptr<IStream> input,uint32_t offset) + auto OpenStream(std::shared_ptr<IStream> input, uint32_t offset) -> cpp::result<OutputFormat, Error> override; - auto DecodeTo(cpp::span<sample::Sample> destination) + auto DecodeTo(std::span<sample::Sample> destination) -> cpp::result<OutputInfo, Error> override; XiphOpusDecoder(const XiphOpusDecoder&) = delete; diff --git a/src/codecs/include/source_buffer.hpp b/src/codecs/include/source_buffer.hpp index 7834834d..6444dd2c 100644 --- a/src/codecs/include/source_buffer.hpp +++ b/src/codecs/include/source_buffer.hpp @@ -9,8 +9,7 @@ #include <cstddef> #include <cstdint> #include <functional> - -#include "span.hpp" +#include <span> #include "codec.hpp" @@ -22,15 +21,15 @@ class SourceBuffer { ~SourceBuffer(); auto Refill(IStream* src) -> bool; - auto AddBytes(std::function<size_t(cpp::span<std::byte>)> writer) -> void; - auto ConsumeBytes(std::function<size_t(cpp::span<std::byte>)> reader) -> void; + auto AddBytes(std::function<size_t(std::span<std::byte>)> writer) -> void; + auto ConsumeBytes(std::function<size_t(std::span<std::byte>)> reader) -> void; auto Empty() -> void; SourceBuffer(const SourceBuffer&) = delete; SourceBuffer& operator=(const SourceBuffer&) = delete; private: - const cpp::span<std::byte> buffer_; + const std::span<std::byte> buffer_; size_t bytes_in_buffer_; size_t offset_of_bytes_; }; diff --git a/src/codecs/include/vorbis.hpp b/src/codecs/include/vorbis.hpp index 3cf0f9ce..e6f393dc 100644 --- a/src/codecs/include/vorbis.hpp +++ b/src/codecs/include/vorbis.hpp @@ -10,12 +10,12 @@ #include <cstdint> #include <memory> #include <optional> +#include <span> #include <string> #include <utility> #include "ivorbisfile.h" #include "sample.hpp" -#include "span.hpp" #include "codec.hpp" @@ -26,10 +26,10 @@ class TremorVorbisDecoder : public ICodec { TremorVorbisDecoder(); ~TremorVorbisDecoder(); - auto OpenStream(std::shared_ptr<IStream> input,uint32_t offset) + auto OpenStream(std::shared_ptr<IStream> input, uint32_t offset) -> cpp::result<OutputFormat, Error> override; - auto DecodeTo(cpp::span<sample::Sample> destination) + auto DecodeTo(std::span<sample::Sample> destination) -> cpp::result<OutputInfo, Error> override; TremorVorbisDecoder(const TremorVorbisDecoder&) = delete; diff --git a/src/codecs/include/wav.hpp b/src/codecs/include/wav.hpp index 40138968..c09a3bb3 100644 --- a/src/codecs/include/wav.hpp +++ b/src/codecs/include/wav.hpp @@ -34,7 +34,7 @@ class WavDecoder : public ICodec { auto OpenStream(std::shared_ptr<IStream> input,uint32_t offset) -> cpp::result<OutputFormat, Error> override; - auto DecodeTo(cpp::span<sample::Sample> destination) + auto DecodeTo(std::span<sample::Sample> destination) -> cpp::result<OutputInfo, Error> override; WavDecoder(const WavDecoder&) = delete; diff --git a/src/codecs/mad.cpp b/src/codecs/mad.cpp index e44e9922..01b2f721 100644 --- a/src/codecs/mad.cpp +++ b/src/codecs/mad.cpp @@ -74,7 +74,7 @@ auto MadMp3Decoder::OpenStream(std::shared_ptr<IStream> input, uint32_t offset) while (!eof && !got_header) { eof = buffer_.Refill(input_.get()); - buffer_.ConsumeBytes([&](cpp::span<std::byte> buf) -> size_t { + buffer_.ConsumeBytes([&](std::span<std::byte> buf) -> size_t { mad_stream_buffer(stream_.get(), reinterpret_cast<const unsigned char*>(buf.data()), buf.size_bytes()); @@ -130,7 +130,7 @@ auto MadMp3Decoder::OpenStream(std::shared_ptr<IStream> input, uint32_t offset) } need_refill = false; - buffer_.ConsumeBytes([&](cpp::span<std::byte> buf) -> size_t { + buffer_.ConsumeBytes([&](std::span<std::byte> buf) -> size_t { mad_stream_buffer(stream_.get(), reinterpret_cast<const unsigned char*>(buf.data()), buf.size()); @@ -156,13 +156,13 @@ auto MadMp3Decoder::OpenStream(std::shared_ptr<IStream> input, uint32_t offset) return output; } -auto MadMp3Decoder::DecodeTo(cpp::span<sample::Sample> output) +auto MadMp3Decoder::DecodeTo(std::span<sample::Sample> output) -> cpp::result<OutputInfo, Error> { if (current_sample_ < 0 && !is_eos_) { if (!is_eof_) { is_eof_ = buffer_.Refill(input_.get()); if (is_eof_) { - buffer_.AddBytes([&](cpp::span<std::byte> buf) -> size_t { + buffer_.AddBytes([&](std::span<std::byte> buf) -> size_t { if (buf.size() < MAD_BUFFER_GUARD) { is_eof_ = false; return 0; @@ -174,7 +174,7 @@ auto MadMp3Decoder::DecodeTo(cpp::span<sample::Sample> output) } } - buffer_.ConsumeBytes([&](cpp::span<std::byte> buf) -> size_t { + buffer_.ConsumeBytes([&](std::span<std::byte> buf) -> size_t { mad_stream_buffer(stream_.get(), reinterpret_cast<const unsigned char*>(buf.data()), buf.size()); diff --git a/src/codecs/opus.cpp b/src/codecs/opus.cpp index a5220c4b..b5e7c3fc 100644 --- a/src/codecs/opus.cpp +++ b/src/codecs/opus.cpp @@ -140,7 +140,7 @@ auto XiphOpusDecoder::OpenStream(std::shared_ptr<IStream> input, }; } -auto XiphOpusDecoder::DecodeTo(cpp::span<sample::Sample> output) +auto XiphOpusDecoder::DecodeTo(std::span<sample::Sample> output) -> cpp::result<OutputInfo, Error> { int samples_written = op_read_stereo(opus_, output.data(), output.size()); diff --git a/src/codecs/source_buffer.cpp b/src/codecs/source_buffer.cpp index 0a986bc3..9cd648cd 100644 --- a/src/codecs/source_buffer.cpp +++ b/src/codecs/source_buffer.cpp @@ -39,7 +39,7 @@ auto SourceBuffer::Refill(IStream* src) -> bool { return false; } bool eof = false; - AddBytes([&](cpp::span<std::byte> buf) -> size_t { + AddBytes([&](std::span<std::byte> buf) -> size_t { ssize_t bytes_read = src->Read(buf); // Treat read errors as EOF. eof = bytes_read <= 0; @@ -48,7 +48,7 @@ auto SourceBuffer::Refill(IStream* src) -> bool { return eof; } -auto SourceBuffer::AddBytes(std::function<size_t(cpp::span<std::byte>)> writer) +auto SourceBuffer::AddBytes(std::function<size_t(std::span<std::byte>)> writer) -> void { if (offset_of_bytes_ > 0) { std::memmove(buffer_.data(), buffer_.data() + offset_of_bytes_, @@ -61,9 +61,9 @@ auto SourceBuffer::AddBytes(std::function<size_t(cpp::span<std::byte>)> writer) } auto SourceBuffer::ConsumeBytes( - std::function<size_t(cpp::span<std::byte>)> reader) -> void { - size_t bytes_consumed = std::invoke( - reader, buffer_.subspan(offset_of_bytes_, bytes_in_buffer_)); + std::function<size_t(std::span<std::byte>)> reader) -> void { + size_t bytes_consumed = + std::invoke(reader, buffer_.subspan(offset_of_bytes_, bytes_in_buffer_)); assert(bytes_consumed <= bytes_in_buffer_); bytes_in_buffer_ -= bytes_consumed; diff --git a/src/codecs/test/test_mad.cpp b/src/codecs/test/test_mad.cpp index e8c714e7..15c96eae 100644 --- a/src/codecs/test/test_mad.cpp +++ b/src/codecs/test/test_mad.cpp @@ -8,14 +8,14 @@ #include <algorithm> #include <cstdint> +#include <span> #include "catch2/catch.hpp" -#include "span.hpp" #include "test.mp3.hpp" -void load_mp3(cpp::span<std::byte> dest) { - cpp::span<std::byte> src(reinterpret_cast<std::byte*>(test_mp3), +void load_mp3(std::span<std::byte> dest) { + std::span<std::byte> src(reinterpret_cast<std::byte*>(test_mp3), test_mp3_len); std::copy(src.begin(), src.begin() + dest.size(), dest.begin()); } diff --git a/src/codecs/vorbis.cpp b/src/codecs/vorbis.cpp index 9131451b..0b2af691 100644 --- a/src/codecs/vorbis.cpp +++ b/src/codecs/vorbis.cpp @@ -129,7 +129,7 @@ auto TremorVorbisDecoder::OpenStream(std::shared_ptr<IStream> input, }; } -auto TremorVorbisDecoder::DecodeTo(cpp::span<sample::Sample> output) +auto TremorVorbisDecoder::DecodeTo(std::span<sample::Sample> output) -> cpp::result<OutputInfo, Error> { int unused = 0; long bytes_written = diff --git a/src/codecs/wav.cpp b/src/codecs/wav.cpp index 714ec237..f5b9d789 100644 --- a/src/codecs/wav.cpp +++ b/src/codecs/wav.cpp @@ -20,24 +20,24 @@ namespace codecs { [[maybe_unused]] static const char kTag[] = "wav"; -static inline auto bytes_to_u16(cpp::span<std::byte const, 2> bytes) +static inline auto bytes_to_u16(std::span<std::byte const, 2> bytes) -> uint16_t { return (uint16_t)bytes[0] | (uint16_t)bytes[1] << 8; } -static inline auto bytes_to_u32(cpp::span<std::byte const, 4> bytes) +static inline auto bytes_to_u32(std::span<std::byte const, 4> bytes) -> uint32_t { return (uint32_t)bytes[0] | (uint32_t)bytes[1] << 8 | (uint32_t)bytes[2] << 16 | (uint32_t)bytes[3] << 24; } -static inline auto bytes_to_str(cpp::span<std::byte const> bytes) +static inline auto bytes_to_str(std::span<std::byte const> bytes) -> std::string { return std::string(reinterpret_cast<const char*>(bytes.data()), - bytes.size_bytes()); + bytes.size_bytes()); } -static int16_t convert_f32_to_16_bit(cpp::span<const std::byte> bytes) { +static int16_t convert_f32_to_16_bit(std::span<const std::byte> bytes) { uint64_t val = 0; val = (uint8_t)bytes[3]; val = (val << 8) | (uint8_t)bytes[2]; @@ -57,7 +57,7 @@ static int16_t convert_f32_to_16_bit(cpp::span<const std::byte> bytes) { return sample::FromDouble(*fval); } -static int16_t convert_f64_to_16_bit(cpp::span<const std::byte> bytes) { +static int16_t convert_f64_to_16_bit(std::span<const std::byte> bytes) { uint64_t val = 0; val = (uint8_t)bytes[7]; val = (val << 8) | (uint8_t)bytes[6]; @@ -71,7 +71,7 @@ static int16_t convert_f64_to_16_bit(cpp::span<const std::byte> bytes) { return sample::FromDouble(*fval); } -static int16_t convert_to_16_bit(cpp::span<const std::byte> bytes) { +static int16_t convert_to_16_bit(std::span<const std::byte> bytes) { int depth = bytes.size(); int32_t val = 0; // If 8-bit Assume Unsigned @@ -82,10 +82,13 @@ static int16_t convert_to_16_bit(cpp::span<const std::byte> bytes) { switch (depth) { case 4: val = (uint8_t)bytes[3]; + [[fallthrough]]; case 3: val = (val << 8) | (uint8_t)bytes[2]; + [[fallthrough]]; case 2: val = (val << 8) | (uint8_t)bytes[1]; + [[fallthrough]]; case 1: val = (val << 8) | (uint8_t)bytes[0]; } @@ -98,7 +101,7 @@ WavDecoder::WavDecoder() : input_(), buffer_() {} WavDecoder::~WavDecoder() {} -auto WavDecoder::OpenStream(std::shared_ptr<IStream> input,uint32_t offset) +auto WavDecoder::OpenStream(std::shared_ptr<IStream> input, uint32_t offset) -> cpp::result<OutputFormat, Error> { input_ = input; @@ -123,7 +126,7 @@ auto WavDecoder::OpenStream(std::shared_ptr<IStream> input,uint32_t offset) // - end of this part, next header we care about is 'data' // - and then the next 4 bytes = 32 bit int = size of data - auto buffer_span = cpp::span{buf}; + auto buffer_span = std::span{buf}; std::string riff = bytes_to_str(buffer_span.subspan(0, 4)); if (riff != "RIFF") { @@ -131,7 +134,7 @@ auto WavDecoder::OpenStream(std::shared_ptr<IStream> input,uint32_t offset) return cpp::fail(Error::kMalformedData); } - uint32_t file_size = bytes_to_u32(buffer_span.subspan(4, 4)) + 8; + // uint32_t file_size = bytes_to_u32(buffer_span.subspan(4, 4)) + 8; std::string fmt_header = bytes_to_str(buffer_span.subspan(12, 4)); ESP_LOGI(kTag, "fmt header found? %s", @@ -142,9 +145,9 @@ auto WavDecoder::OpenStream(std::shared_ptr<IStream> input,uint32_t offset) } // Size of the fmt header, should be 16, 18 or 40 - uint32_t fmt_header_size = bytes_to_u32(buffer_span.subspan(16, 4)); + // uint32_t fmt_header_size = bytes_to_u32(buffer_span.subspan(16, 4)); - wave_format_ = bytes_to_u16(buffer_span.subspan(20, 2)); + wave_format_ = bytes_to_u16(buffer_span.subspan<20, 2>()); if (wave_format_ == kWaveFormatPCM) { ESP_LOGD(kTag, "wave format: PCM"); } else if (wave_format_ == kWaveFormatExtensible) { @@ -156,17 +159,17 @@ auto WavDecoder::OpenStream(std::shared_ptr<IStream> input,uint32_t offset) return cpp::fail(Error::kUnsupportedFormat); } - num_channels_ = bytes_to_u16(buffer_span.subspan(22, 2)); + num_channels_ = bytes_to_u16(buffer_span.subspan<22, 2>()); - uint32_t samples_per_second = bytes_to_u32(buffer_span.subspan(24, 4)); + uint32_t samples_per_second = bytes_to_u32(buffer_span.subspan<24, 4>()); - uint32_t avg_bytes_per_second = bytes_to_u32(buffer_span.subspan(28, 4)); + // uint32_t avg_bytes_per_second = bytes_to_u32(buffer_span.subspan(28, 4)); - uint16_t block_align = bytes_to_u16(buffer_span.subspan(32, 2)); + uint16_t block_align = bytes_to_u16(buffer_span.subspan<32, 2>()); bytes_per_sample_ = block_align / num_channels_; - uint16_t bits_per_sample = bytes_to_u16(buffer_span.subspan(34, 2)); + // uint16_t bits_per_sample = bytes_to_u16(buffer_span.subspan(34, 2)); // find the start of the data chunk std::array<std::byte, 4> data_tag = {std::byte{0x64}, std::byte{0x61}, @@ -180,7 +183,7 @@ auto WavDecoder::OpenStream(std::shared_ptr<IStream> input,uint32_t offset) int data_chunk_index = std::distance(buffer_span.begin(), data_loc.begin()); uint32_t data_chunk_size = - bytes_to_u32(buffer_span.subspan(data_chunk_index + 4, 4)); + bytes_to_u32(buffer_span.subspan(data_chunk_index + 4, 4).first<4>()); // calculate number of samples int number_of_samples = data_chunk_size / bytes_per_sample_; @@ -188,20 +191,20 @@ auto WavDecoder::OpenStream(std::shared_ptr<IStream> input,uint32_t offset) // extension to the fmt chunk size (0 or 22) uint16_t extension_size = 0; if (wave_format_ == kWaveFormatExtensible) { - extension_size = bytes_to_u16(buffer_span.subspan(36, 2)); + extension_size = bytes_to_u16(buffer_span.subspan<36, 2>()); } // Parse extension if applicable if (extension_size == 22) { // Valid bits per sample - uint16_t valid_bits_per_sample = bytes_to_u16(buffer_span.subspan(38, 2)); + // uint16_t valid_bits_per_sample = bytes_to_u16(buffer_span.subspan(38, + // 2)); - uint32_t speaker_mask = bytes_to_u32(buffer_span.subspan(40, 4)); + // uint32_t speaker_mask = bytes_to_u32(buffer_span.subspan(40, 4)); // Parse subformat - subformat_ = bytes_to_u16(buffer_span.subspan(44, 2)); - if (!(subformat_ == kWaveFormatPCM || - subformat_ == kWaveFormatIEEEFloat)) { + subformat_ = bytes_to_u16(buffer_span.subspan<44, 2>()); + if (!(subformat_ == kWaveFormatPCM || subformat_ == kWaveFormatIEEEFloat)) { ESP_LOGW(kTag, "WAVE extensible subformat_ not supported"); return cpp::fail(Error::kUnsupportedFormat); } @@ -210,7 +213,8 @@ auto WavDecoder::OpenStream(std::shared_ptr<IStream> input,uint32_t offset) int64_t data_offset = offset * samples_per_second * bytes_per_sample_; // Seek track to start of data - input->SeekTo(data_chunk_index + 8 + data_offset, IStream::SeekFrom::kStartOfStream); + input->SeekTo(data_chunk_index + 8 + data_offset, + IStream::SeekFrom::kStartOfStream); output_format_ = {.num_channels = (uint8_t)num_channels_, .sample_rate_hz = samples_per_second, @@ -219,12 +223,12 @@ auto WavDecoder::OpenStream(std::shared_ptr<IStream> input,uint32_t offset) return output_format_; } -auto WavDecoder::DecodeTo(cpp::span<sample::Sample> output) +auto WavDecoder::DecodeTo(std::span<sample::Sample> output) -> cpp::result<OutputInfo, Error> { bool is_eof = buffer_.Refill(input_.get()); size_t samples_written = 0; - buffer_.ConsumeBytes([&](cpp::span<std::byte> buf) -> size_t { + buffer_.ConsumeBytes([&](std::span<std::byte> buf) -> size_t { size_t bytes_read = buf.size_bytes(); size_t frames_read = bytes_read / bytes_per_sample_ / output_format_.num_channels; @@ -254,7 +258,6 @@ auto WavDecoder::DecodeTo(cpp::span<sample::Sample> output) return samples_written * bytes_per_sample_; }); - return OutputInfo{.samples_written = samples_written, .is_stream_finished = samples_written == 0 && is_eof}; } diff --git a/src/database/CMakeLists.txt b/src/database/CMakeLists.txt deleted file mode 100644 index 26c14815..00000000 --- a/src/database/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2023 jacqueline <me@jacqueline.id.au> -# -# SPDX-License-Identifier: GPL-3.0-only - -idf_component_register( - SRCS "env_esp.cpp" "database.cpp" "track.cpp" "records.cpp" - "file_gatherer.cpp" "tag_parser.cpp" "index.cpp" - INCLUDE_DIRS "include" - REQUIRES "result" "span" "esp_psram" "fatfs" "libtags" "komihash" "cbor" - "tasks" "memory" "util" "tinyfsm" "events" "opusfile" "libcppbor") - -target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) - -set(LEVELDB_BUILD_TESTS OFF) -set(LEVELDB_BUILD_BENCHMARKS OFF) -set(LEVELDB_INSTALL OFF) - -set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) - -add_subdirectory($ENV{PROJ_PATH}/lib/leveldb ${CMAKE_CURRENT_BINARY_DIR}/leveldb) - -target_link_libraries(${COMPONENT_LIB} PUBLIC leveldb) diff --git a/src/dev_console/CMakeLists.txt b/src/dev_console/CMakeLists.txt deleted file mode 100644 index 5555bf61..00000000 --- a/src/dev_console/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2023 jacqueline <me@jacqueline.id.au> -# -# SPDX-License-Identifier: GPL-3.0-only - -idf_component_register( - SRCS "console.cpp" - INCLUDE_DIRS "include" - REQUIRES "console" "memory") -target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt index 891115d4..91534edb 100644 --- a/src/drivers/CMakeLists.txt +++ b/src/drivers/CMakeLists.txt @@ -7,6 +7,6 @@ idf_component_register( "i2c.cpp" "bluetooth.cpp" "spi.cpp" "display.cpp" "display_init.cpp" "samd.cpp" "wm8523.cpp" "nvs.cpp" "haptics.cpp" "spiffs.cpp" INCLUDE_DIRS "include" - REQUIRES "esp_adc" "fatfs" "result" "lvgl" "span" "tasks" "nvs_flash" "spiffs" - "bt" "tinyfsm" "util") + REQUIRES "esp_adc" "fatfs" "result" "lvgl" "nvs_flash" "spiffs" "bt" + "tasks" "tinyfsm" "util" "libcppbor") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/drivers/adc.cpp b/src/drivers/adc.cpp index 3379a1ae..3038f7f6 100644 --- a/src/drivers/adc.cpp +++ b/src/drivers/adc.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "adc.hpp" +#include "drivers/adc.hpp" #include <cstdint> #include "esp_adc/adc_cali.h" diff --git a/src/drivers/bluetooth.cpp b/src/drivers/bluetooth.cpp index 5d1b35fa..fcb764f6 100644 --- a/src/drivers/bluetooth.cpp +++ b/src/drivers/bluetooth.cpp @@ -1,4 +1,4 @@ -#include "bluetooth.hpp" +#include "drivers/bluetooth.hpp" #include <stdint.h> @@ -25,12 +25,11 @@ #include "freertos/portmacro.h" #include "freertos/projdefs.h" #include "freertos/timers.h" -#include "sample.hpp" #include "tinyfsm/include/tinyfsm.hpp" -#include "bluetooth_types.hpp" +#include "drivers/bluetooth_types.hpp" +#include "drivers/nvs.hpp" #include "memory_resource.hpp" -#include "nvs.hpp" #include "tasks.hpp" namespace drivers { @@ -39,6 +38,7 @@ namespace drivers { DRAM_ATTR static StreamBufferHandle_t sStream = nullptr; DRAM_ATTR static std::atomic<float> sVolumeFactor = 1.f; +DRAM_ATTR static std::atomic<uint32_t> sSamplesUsed = 0; static tasks::WorkerPool* sBgWorker; @@ -74,6 +74,13 @@ IRAM_ATTR auto a2dp_data_cb(uint8_t* buf, int32_t buf_size) -> int32_t { } size_t bytes_received = xStreamBufferReceive(stream, buf, buf_size, 0); + size_t samples_received = bytes_received / 2; + if (UINT32_MAX - sSamplesUsed < samples_received) { + sSamplesUsed = samples_received - (UINT32_MAX - sSamplesUsed); + } else { + sSamplesUsed += samples_received; + } + // Apply software volume scaling. int16_t* samples = reinterpret_cast<int16_t*>(buf); float factor = sVolumeFactor.load(); @@ -166,6 +173,10 @@ auto Bluetooth::SetVolumeFactor(float f) -> void { sVolumeFactor = f; } +auto Bluetooth::SamplesUsed() -> uint32_t { + return sSamplesUsed; +} + auto Bluetooth::SetEventHandler(std::function<void(bluetooth::Event)> cb) -> void { auto lock = bluetooth::BluetoothState::lock(); diff --git a/src/drivers/display.cpp b/src/drivers/display.cpp index 5c686811..b0a97b30 100644 --- a/src/drivers/display.cpp +++ b/src/drivers/display.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "display.hpp" +#include "drivers/display.hpp" #include <stdint.h> #include <cmath> @@ -31,11 +31,11 @@ #include "hal/spi_types.h" #include "lvgl/lvgl.h" -#include "display_init.hpp" -#include "gpios.hpp" +#include "drivers/display_init.hpp" +#include "drivers/gpios.hpp" +#include "drivers/spi.hpp" #include "misc/lv_color.h" #include "soc/soc.h" -#include "spi.hpp" #include "tasks.hpp" [[maybe_unused]] static const char* kTag = "DISPLAY"; diff --git a/src/drivers/display_init.cpp b/src/drivers/display_init.cpp index a69826fa..edd36a8d 100644 --- a/src/drivers/display_init.cpp +++ b/src/drivers/display_init.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "display_init.hpp" +#include "drivers/display_init.hpp" namespace drivers { namespace displays { diff --git a/src/drivers/gpios.cpp b/src/drivers/gpios.cpp index aab932a7..64ba26a7 100644 --- a/src/drivers/gpios.cpp +++ b/src/drivers/gpios.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "gpios.hpp" +#include "drivers/gpios.hpp" #include <cstdint> @@ -15,7 +15,7 @@ #include "esp_intr_alloc.h" #include "hal/gpio_types.h" -#include "i2c.hpp" +#include "drivers/i2c.hpp" namespace drivers { diff --git a/src/drivers/haptics.cpp b/src/drivers/haptics.cpp index f7b18086..55fa9ad8 100644 --- a/src/drivers/haptics.cpp +++ b/src/drivers/haptics.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "haptics.hpp" +#include "drivers/haptics.hpp" #include <stdint.h> #include <cstdint> @@ -21,7 +21,7 @@ #include "hal/gpio_types.h" #include "hal/i2c_types.h" -#include "i2c.hpp" +#include "drivers/i2c.hpp" namespace drivers { @@ -54,7 +54,8 @@ Haptics::Haptics(const std::variant<ErmMotor, LraMotor>& motor) { // Set library // TODO(robin): try the other libraries and test response. C is marginal, D // too much? - WriteRegister(Register::kWaveformLibrary, static_cast<uint8_t>(kDefaultErmLibrary)); + WriteRegister(Register::kWaveformLibrary, + static_cast<uint8_t>(kDefaultErmLibrary)); } else if (std::holds_alternative<LraMotor>(motor)) { ESP_LOGI(kTag, "Setting up LRA motor..."); @@ -75,7 +76,8 @@ Haptics::Haptics(const std::variant<ErmMotor, LraMotor>& motor) { ControlMask::kLraOpenLoop); // Set library; only option is the LRA one for, well, LRA motors. - WriteRegister(Register::kWaveformLibrary, static_cast<uint8_t>(Library::LRA)); + WriteRegister(Register::kWaveformLibrary, + static_cast<uint8_t>(Library::LRA)); } // Set mode (internal trigger, on writing 1 to Go register) @@ -123,7 +125,6 @@ auto Haptics::SetWaveformEffect(Effect effect) -> void { current_effect_ = effect; } - auto Haptics::TourEffects() -> void { TourEffects(Effect::kFirst, Effect::kLast, kDefaultErmLibrary); } @@ -174,7 +175,6 @@ auto Haptics::TourLibraries(Effect from, Effect to) -> void { } } - auto Haptics::PowerDown() -> void { WriteRegister(Register::kMode, static_cast<uint8_t>(Mode::kInternalTrigger) | ModeMask::kStandby); diff --git a/src/drivers/i2c.cpp b/src/drivers/i2c.cpp index 7d25717a..793ce9f9 100644 --- a/src/drivers/i2c.cpp +++ b/src/drivers/i2c.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "i2c.hpp" +#include "drivers/i2c.hpp" #include <cstdint> diff --git a/src/drivers/i2s_dac.cpp b/src/drivers/i2s_dac.cpp index aef466c2..e5efe198 100644 --- a/src/drivers/i2s_dac.cpp +++ b/src/drivers/i2s_dac.cpp @@ -4,7 +4,8 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "i2s_dac.hpp" +#include "drivers/i2s_dac.hpp" +#include <stdint.h> #include <cmath> #include <cstdint> @@ -25,11 +26,11 @@ #include "hal/gpio_types.h" #include "hal/i2c_types.h" -#include "gpios.hpp" +#include "drivers/gpios.hpp" +#include "drivers/i2c.hpp" +#include "drivers/wm8523.hpp" #include "hal/i2s_types.h" -#include "i2c.hpp" #include "soc/clk_tree_defs.h" -#include "wm8523.hpp" namespace drivers { @@ -140,7 +141,7 @@ auto I2SDac::SetPaused(bool paused) -> void { } } -static volatile bool sSwapWords = false; +DRAM_ATTR static volatile bool sSwapWords = false; auto I2SDac::Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate) -> void { @@ -207,7 +208,7 @@ auto I2SDac::Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate) } } -auto I2SDac::WriteData(const cpp::span<const std::byte>& data) -> void { +auto I2SDac::WriteData(const std::span<const std::byte>& data) -> void { std::size_t bytes_written = 0; esp_err_t err = i2s_channel_write(i2s_handle_, data.data(), data.size_bytes(), &bytes_written, portMAX_DELAY); @@ -216,6 +217,8 @@ auto I2SDac::WriteData(const cpp::span<const std::byte>& data) -> void { } } +DRAM_ATTR static volatile uint32_t sSamplesRead = 0; + extern "C" IRAM_ATTR auto callback(i2s_chan_handle_t handle, i2s_event_data_t* event, void* user_ctx) -> bool { @@ -234,6 +237,14 @@ extern "C" IRAM_ATTR auto callback(i2s_chan_handle_t handle, size_t bytes_written = xStreamBufferReceiveFromISR(src, buf, event->size, &ret); + // Assume 16 bit samples. + size_t samples = bytes_written / 2; + if (UINT32_MAX - sSamplesRead < samples) { + sSamplesRead = samples - (UINT32_MAX - sSamplesRead); + } else { + sSamplesRead = sSamplesRead + samples; + } + // The ESP32's I2S peripheral has a different endianness to its processors. // ESP-IDF handles this difference for stereo channels, but not for mono // channels. We therefore sometimes need to swap each pair of words as they're @@ -275,6 +286,10 @@ auto I2SDac::SetSource(StreamBufferHandle_t buffer) -> void { } } +auto I2SDac::SamplesUsed() -> uint32_t { + return sSamplesRead; +} + auto I2SDac::set_channel(bool enabled) -> void { if (i2s_active_ == enabled) { return; diff --git a/src/drivers/include/a2dp_audio_output.hpp b/src/drivers/include/drivers/a2dp_audio_output.hpp index 010470c6..010470c6 100644 --- a/src/drivers/include/a2dp_audio_output.hpp +++ b/src/drivers/include/drivers/a2dp_audio_output.hpp diff --git a/src/drivers/include/adc.hpp b/src/drivers/include/drivers/adc.hpp index 3e94a9ee..3e94a9ee 100644 --- a/src/drivers/include/adc.hpp +++ b/src/drivers/include/drivers/adc.hpp diff --git a/src/drivers/include/bluetooth.hpp b/src/drivers/include/drivers/bluetooth.hpp index 8da5ce2e..ad61fcc1 100644 --- a/src/drivers/include/bluetooth.hpp +++ b/src/drivers/include/drivers/bluetooth.hpp @@ -12,11 +12,11 @@ #include <freertos/FreeRTOS.h> #include <freertos/stream_buffer.h> #include <stdint.h> -#include "bluetooth_types.hpp" +#include "drivers/bluetooth_types.hpp" +#include "drivers/nvs.hpp" #include "esp_a2dp_api.h" #include "esp_avrc_api.h" #include "esp_gap_bt_api.h" -#include "nvs.hpp" #include "tasks.hpp" #include "tinyfsm.hpp" #include "tinyfsm/include/tinyfsm.hpp" @@ -44,6 +44,7 @@ class Bluetooth { auto SetSource(StreamBufferHandle_t) -> void; auto SetVolumeFactor(float) -> void; + auto SamplesUsed() -> uint32_t; auto SetEventHandler(std::function<void(bluetooth::Event)> cb) -> void; }; diff --git a/src/drivers/include/bluetooth_types.hpp b/src/drivers/include/drivers/bluetooth_types.hpp index 7cfb236f..7cfb236f 100644 --- a/src/drivers/include/bluetooth_types.hpp +++ b/src/drivers/include/drivers/bluetooth_types.hpp diff --git a/src/drivers/include/display.hpp b/src/drivers/include/drivers/display.hpp index d2e18a5c..6dc78e01 100644 --- a/src/drivers/include/display.hpp +++ b/src/drivers/include/drivers/display.hpp @@ -15,8 +15,8 @@ #include "result.hpp" #include "tasks.hpp" -#include "display_init.hpp" -#include "gpios.hpp" +#include "drivers/display_init.hpp" +#include "drivers/gpios.hpp" namespace drivers { diff --git a/src/drivers/include/display_init.hpp b/src/drivers/include/drivers/display_init.hpp index 9bf5b3f5..9bf5b3f5 100644 --- a/src/drivers/include/display_init.hpp +++ b/src/drivers/include/drivers/display_init.hpp diff --git a/src/drivers/include/fatfs_audio_input.hpp b/src/drivers/include/drivers/fatfs_audio_input.hpp index 705f6e7d..705f6e7d 100644 --- a/src/drivers/include/fatfs_audio_input.hpp +++ b/src/drivers/include/drivers/fatfs_audio_input.hpp diff --git a/src/drivers/include/gpios.hpp b/src/drivers/include/drivers/gpios.hpp index e27a3ade..e27a3ade 100644 --- a/src/drivers/include/gpios.hpp +++ b/src/drivers/include/drivers/gpios.hpp diff --git a/src/drivers/include/haptics.hpp b/src/drivers/include/drivers/haptics.hpp index 940c3c6d..940c3c6d 100644 --- a/src/drivers/include/haptics.hpp +++ b/src/drivers/include/drivers/haptics.hpp diff --git a/src/drivers/include/i2c.hpp b/src/drivers/include/drivers/i2c.hpp index 0dc1e7c0..0dc1e7c0 100644 --- a/src/drivers/include/i2c.hpp +++ b/src/drivers/include/drivers/i2c.hpp diff --git a/src/drivers/include/i2s_dac.hpp b/src/drivers/include/drivers/i2s_dac.hpp index bd837ca0..0776dbab 100644 --- a/src/drivers/include/i2s_dac.hpp +++ b/src/drivers/include/drivers/i2s_dac.hpp @@ -11,6 +11,7 @@ #include <functional> #include <memory> #include <optional> +#include <span> #include <utility> #include "driver/i2s_std.h" @@ -20,9 +21,8 @@ #include "freertos/portmacro.h" #include "freertos/stream_buffer.h" #include "result.hpp" -#include "span.hpp" -#include "gpios.hpp" +#include "drivers/gpios.hpp" #include "sys/_stdint.h" namespace drivers { @@ -68,9 +68,11 @@ class I2SDac { auto Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate) -> void; - auto WriteData(const cpp::span<const std::byte>& data) -> void; + auto WriteData(const std::span<const std::byte>& data) -> void; auto SetSource(StreamBufferHandle_t buffer) -> void; + auto SamplesUsed() -> uint32_t; + // Not copyable or movable. I2SDac(const I2SDac&) = delete; I2SDac& operator=(const I2SDac&) = delete; diff --git a/src/drivers/include/nvs.hpp b/src/drivers/include/drivers/nvs.hpp index 7c74ceb0..83bb8097 100644 --- a/src/drivers/include/nvs.hpp +++ b/src/drivers/include/drivers/nvs.hpp @@ -13,9 +13,8 @@ #include "esp_err.h" #include "nvs.h" -#include "bluetooth_types.hpp" +#include "drivers/bluetooth_types.hpp" #include "lru_cache.hpp" -#include "tasks.hpp" namespace drivers { diff --git a/src/drivers/include/samd.hpp b/src/drivers/include/drivers/samd.hpp index 55ea513c..55ea513c 100644 --- a/src/drivers/include/samd.hpp +++ b/src/drivers/include/drivers/samd.hpp diff --git a/src/drivers/include/spi.hpp b/src/drivers/include/drivers/spi.hpp index 60638f71..60638f71 100644 --- a/src/drivers/include/spi.hpp +++ b/src/drivers/include/drivers/spi.hpp diff --git a/src/drivers/include/spiffs.hpp b/src/drivers/include/drivers/spiffs.hpp index 04478590..04478590 100644 --- a/src/drivers/include/spiffs.hpp +++ b/src/drivers/include/drivers/spiffs.hpp diff --git a/src/drivers/include/storage.hpp b/src/drivers/include/drivers/storage.hpp index 836bbbdc..3aefff2d 100644 --- a/src/drivers/include/storage.hpp +++ b/src/drivers/include/drivers/storage.hpp @@ -15,7 +15,7 @@ #include "ff.h" #include "result.hpp" -#include "gpios.hpp" +#include "drivers/gpios.hpp" namespace drivers { diff --git a/src/drivers/include/touchwheel.hpp b/src/drivers/include/drivers/touchwheel.hpp index 18ace2b4..60902087 100644 --- a/src/drivers/include/touchwheel.hpp +++ b/src/drivers/include/drivers/touchwheel.hpp @@ -12,7 +12,7 @@ #include "esp_err.h" #include "result.hpp" -#include "gpios.hpp" +#include "drivers/gpios.hpp" namespace drivers { diff --git a/src/drivers/include/wm8523.hpp b/src/drivers/include/drivers/wm8523.hpp index a64f6bac..a64f6bac 100644 --- a/src/drivers/include/wm8523.hpp +++ b/src/drivers/include/drivers/wm8523.hpp diff --git a/src/drivers/nvs.cpp b/src/drivers/nvs.cpp index c8befe48..1389fd0d 100644 --- a/src/drivers/nvs.cpp +++ b/src/drivers/nvs.cpp @@ -4,22 +4,19 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "nvs.hpp" -#include <stdint.h> -#include <sys/_stdint.h> +#include "drivers/nvs.hpp" #include <cstdint> #include <memory> -#include "bluetooth.hpp" -#include "bluetooth_types.hpp" #include "cppbor.h" #include "cppbor_parse.h" +#include "drivers/bluetooth.hpp" +#include "drivers/bluetooth_types.hpp" +#include "drivers/wm8523.hpp" #include "esp_log.h" #include "nvs.h" #include "nvs_flash.h" -#include "tasks.hpp" -#include "wm8523.hpp" namespace drivers { @@ -42,8 +39,8 @@ static constexpr char kKeyDisplayRows[] = "disprows"; static constexpr char kKeyHapticMotorType[] = "hapticmtype"; static constexpr char kKeyDbAutoIndex[] = "dbautoindex"; -static auto nvs_get_string(nvs_handle_t nvs, const char* key) - -> std::optional<std::string> { +static auto nvs_get_string(nvs_handle_t nvs, + const char* key) -> std::optional<std::string> { size_t len = 0; if (nvs_get_blob(nvs, key, NULL, &len) != ESP_OK) { return {}; @@ -190,8 +187,7 @@ auto NvsStorage::Read() -> void { lock_polarity_.read(handle_); display_cols_.read(handle_); display_rows_.read(handle_); - haptic_motor_type_.read(handle_), - brightness_.read(handle_); + haptic_motor_type_.read(handle_), brightness_.read(handle_); sensitivity_.read(handle_); amp_max_vol_.read(handle_); amp_cur_vol_.read(handle_); @@ -208,8 +204,7 @@ auto NvsStorage::Write() -> bool { lock_polarity_.write(handle_); display_cols_.write(handle_); display_rows_.write(handle_); - haptic_motor_type_.write(handle_), - brightness_.write(handle_); + haptic_motor_type_.write(handle_), brightness_.write(handle_); sensitivity_.write(handle_); amp_max_vol_.write(handle_); amp_cur_vol_.write(handle_); @@ -290,8 +285,8 @@ auto NvsStorage::BluetoothVolume(const bluetooth::mac_addr_t& mac) -> uint8_t { return bt_volumes_.Get(mac).value_or(50); } -auto NvsStorage::BluetoothVolume(const bluetooth::mac_addr_t& mac, uint8_t vol) - -> void { +auto NvsStorage::BluetoothVolume(const bluetooth::mac_addr_t& mac, + uint8_t vol) -> void { std::lock_guard<std::mutex> lock{mutex_}; bt_volumes_dirty_ = true; bt_volumes_.Put(mac, vol); diff --git a/src/drivers/samd.cpp b/src/drivers/samd.cpp index e47d9cfe..c5e8c08a 100644 --- a/src/drivers/samd.cpp +++ b/src/drivers/samd.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "samd.hpp" +#include "drivers/samd.hpp" #include <cstdint> #include <optional> @@ -15,7 +15,7 @@ #include "hal/gpio_types.h" #include "hal/i2c_types.h" -#include "i2c.hpp" +#include "drivers/i2c.hpp" enum Registers : uint8_t { kSamdFirmwareVersion = 0, diff --git a/src/drivers/spi.cpp b/src/drivers/spi.cpp index ae6f83a2..f4d3ea6e 100644 --- a/src/drivers/spi.cpp +++ b/src/drivers/spi.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "spi.hpp" +#include "drivers/spi.hpp" #include "driver/sdspi_host.h" #include "driver/spi_common.h" diff --git a/src/drivers/spiffs.cpp b/src/drivers/spiffs.cpp index f03d2f68..30a2db33 100644 --- a/src/drivers/spiffs.cpp +++ b/src/drivers/spiffs.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "spiffs.hpp" +#include "drivers/spiffs.hpp" #include "esp_err.h" #include "esp_log.h" diff --git a/src/drivers/storage.cpp b/src/drivers/storage.cpp index b3588130..b2b7174e 100644 --- a/src/drivers/storage.cpp +++ b/src/drivers/storage.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "storage.hpp" +#include "drivers/storage.hpp" #include <atomic> #include <memory> @@ -23,7 +23,7 @@ #include "hal/spi_types.h" #include "sdmmc_cmd.h" -#include "gpios.hpp" +#include "drivers/gpios.hpp" #include "memory_resource.hpp" [[maybe_unused]] static const char* kTag = "SDSTORAGE"; diff --git a/src/drivers/test/test_dac.cpp b/src/drivers/test/test_dac.cpp index e8d8dd94..2269f280 100644 --- a/src/drivers/test/test_dac.cpp +++ b/src/drivers/test/test_dac.cpp @@ -10,8 +10,8 @@ #include "catch2/catch.hpp" -#include "gpios.hpp" -#include "i2c.hpp" +#include "drivers/gpios.hpp" +#include "drivers/i2c.hpp" #include "i2c_fixture.hpp" namespace drivers { diff --git a/src/drivers/test/test_gpio_expander.cpp b/src/drivers/test/test_gpio_expander.cpp index 972bcf09..7c323313 100644 --- a/src/drivers/test/test_gpio_expander.cpp +++ b/src/drivers/test/test_gpio_expander.cpp @@ -4,11 +4,11 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "gpios.hpp" +#include "drivers/gpios.hpp" #include "catch2/catch.hpp" -#include "i2c.hpp" +#include "drivers/i2c.hpp" #include "i2c_fixture.hpp" namespace drivers { diff --git a/src/drivers/test/test_storage.cpp b/src/drivers/test/test_storage.cpp index 062de3af..f97a0a85 100644 --- a/src/drivers/test/test_storage.cpp +++ b/src/drivers/test/test_storage.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "storage.hpp" +#include "drivers/storage.hpp" #include <dirent.h> @@ -14,10 +14,10 @@ #include "catch2/catch.hpp" -#include "gpios.hpp" -#include "i2c.hpp" +#include "drivers/gpios.hpp" +#include "drivers/i2c.hpp" +#include "drivers/spi.hpp" #include "i2c_fixture.hpp" -#include "spi.hpp" #include "spi_fixture.hpp" namespace drivers { diff --git a/src/drivers/touchwheel.cpp b/src/drivers/touchwheel.cpp index 41b9a6af..5d55c6f2 100644 --- a/src/drivers/touchwheel.cpp +++ b/src/drivers/touchwheel.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "touchwheel.hpp" +#include "drivers/touchwheel.hpp" #include <stdint.h> #include <cstdint> @@ -18,7 +18,7 @@ #include "hal/gpio_types.h" #include "hal/i2c_types.h" -#include "i2c.hpp" +#include "drivers/i2c.hpp" namespace drivers { diff --git a/src/drivers/wm8523.cpp b/src/drivers/wm8523.cpp index 9fe3e001..26316387 100644 --- a/src/drivers/wm8523.cpp +++ b/src/drivers/wm8523.cpp @@ -3,14 +3,14 @@ * * SPDX-License-Identifier: GPL-3.0-only */ -#include "wm8523.hpp" +#include "drivers/wm8523.hpp" #include <cstdint> #include "esp_err.h" +#include "drivers/i2c.hpp" #include "hal/i2c_types.h" -#include "i2c.hpp" namespace drivers { namespace wm8523 { diff --git a/src/events/CMakeLists.txt b/src/events/CMakeLists.txt deleted file mode 100644 index 132c39c7..00000000 --- a/src/events/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2023 jacqueline <me@jacqueline.id.au> -# -# SPDX-License-Identifier: GPL-3.0-only - -idf_component_register( - SRCS "event_queue.cpp" - INCLUDE_DIRS "include" - REQUIRES "tinyfsm" "ui") -target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/graphics/CMakeLists.txt b/src/graphics/CMakeLists.txt new file mode 100644 index 00000000..5b2c5d58 --- /dev/null +++ b/src/graphics/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright 2024 jacqueline <me@jacqueline.id.au> +# +# SPDX-License-Identifier: GPL-3.0-only + +idf_component_register( + SRCS "font_fusion_10.c" "font_fusion_12.c" "splash.c" + REQUIRES "lvgl") diff --git a/src/ui/font_fusion_10.c b/src/graphics/font_fusion_10.c index 67143440..67143440 100644 --- a/src/ui/font_fusion_10.c +++ b/src/graphics/font_fusion_10.c diff --git a/src/ui/font_fusion_12.c b/src/graphics/font_fusion_12.c index 97c311b8..97c311b8 100644 --- a/src/ui/font_fusion_12.c +++ b/src/graphics/font_fusion_12.c diff --git a/src/ui/splash.c b/src/graphics/splash.c index 61eff739..61eff739 100644 --- a/src/ui/splash.c +++ b/src/graphics/splash.c diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt deleted file mode 100644 index 4754ba47..00000000 --- a/src/input/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2023 jacqueline <me@jacqueline.id.au> -# -# SPDX-License-Identifier: GPL-3.0-only - -idf_component_register( - SRCS "input_touch_wheel.cpp" "input_touch_dpad.cpp" "input_trigger.cpp" - "input_volume_buttons.cpp" "lvgl_input_driver.cpp" "feedback_haptics.cpp" - "device_factory.cpp" "input_nav_buttons.cpp" "input_hook.cpp" - "input_hook_actions.cpp" - INCLUDE_DIRS "include" - REQUIRES "drivers" "lvgl" "events" "system_fsm") - -target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/input/include/lvgl_input_driver.hpp b/src/input/include/lvgl_input_driver.hpp deleted file mode 100644 index 9f43d27f..00000000 --- a/src/input/include/lvgl_input_driver.hpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2023 jacqueline <me@jacqueline.id.au> - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include <cstdint> -#include <deque> -#include <memory> -#include <set> - -#include "core/lv_group.h" -#include "device_factory.hpp" -#include "feedback_device.hpp" -#include "gpios.hpp" -#include "hal/lv_hal_indev.h" - -#include "input_device.hpp" -#include "nvs.hpp" -#include "property.hpp" -#include "touchwheel.hpp" - -namespace input { - -/* - * Implementation of an LVGL input device. This class composes multiple - * IInputDevice and IFeedbackDevice instances together into a single LVGL - * device. - */ -class LvglInputDriver { - public: - LvglInputDriver(drivers::NvsStorage& nvs, DeviceFactory&); - - auto mode() -> lua::Property& { return mode_; } - - auto read(lv_indev_data_t* data) -> void; - auto feedback(uint8_t) -> void; - - auto registration() -> lv_indev_t* { return registration_; } - auto lock(bool l) -> void { is_locked_ = l; } - - auto pushHooks(lua_State* L) -> int; - - private: - drivers::NvsStorage& nvs_; - DeviceFactory& factory_; - - lua::Property mode_; - lv_indev_drv_t driver_; - lv_indev_t* registration_; - - std::vector<std::shared_ptr<IInputDevice>> inputs_; - std::vector<std::shared_ptr<IFeedbackDevice>> feedbacks_; - - bool is_locked_; -}; - -} // namespace input diff --git a/src/input/lvgl_input_driver.cpp b/src/input/lvgl_input_driver.cpp deleted file mode 100644 index 61a85fa5..00000000 --- a/src/input/lvgl_input_driver.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2023 jacqueline <me@jacqueline.id.au> - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#include "lvgl_input_driver.hpp" -#include <stdint.h> - -#include <cstdint> -#include <memory> -#include <variant> - -#include "device_factory.hpp" -#include "feedback_haptics.hpp" -#include "input_touch_wheel.hpp" -#include "input_trigger.hpp" -#include "input_volume_buttons.hpp" -#include "lauxlib.h" -#include "lua.h" -#include "lvgl.h" -#include "nvs.hpp" -#include "property.hpp" - -[[maybe_unused]] static constexpr char kTag[] = "input"; - -namespace input { - -static void read_cb(lv_indev_drv_t* drv, lv_indev_data_t* data) { - LvglInputDriver* instance = - reinterpret_cast<LvglInputDriver*>(drv->user_data); - instance->read(data); -} - -static void feedback_cb(lv_indev_drv_t* drv, uint8_t event) { - LvglInputDriver* instance = - reinterpret_cast<LvglInputDriver*>(drv->user_data); - instance->feedback(event); -} - -auto intToMode(int raw) -> std::optional<drivers::NvsStorage::InputModes> { - switch (raw) { - case 0: - return drivers::NvsStorage::InputModes::kButtonsOnly; - case 1: - return drivers::NvsStorage::InputModes::kButtonsWithWheel; - case 2: - return drivers::NvsStorage::InputModes::kDirectionalWheel; - case 3: - return drivers::NvsStorage::InputModes::kRotatingWheel; - default: - return {}; - } -} - -LvglInputDriver::LvglInputDriver(drivers::NvsStorage& nvs, - DeviceFactory& factory) - : nvs_(nvs), - factory_(factory), - mode_(static_cast<int>(nvs.PrimaryInput()), - [&](const lua::LuaValue& val) { - if (!std::holds_alternative<int>(val)) { - return false; - } - auto mode = intToMode(std::get<int>(val)); - if (!mode) { - return false; - } - nvs.PrimaryInput(*mode); - inputs_ = factory.createInputs(*mode); - return true; - }), - driver_(), - registration_(nullptr), - inputs_(factory.createInputs(nvs.PrimaryInput())), - feedbacks_(factory.createFeedbacks()), - is_locked_(false) { - lv_indev_drv_init(&driver_); - driver_.type = LV_INDEV_TYPE_ENCODER; - driver_.read_cb = read_cb; - driver_.feedback_cb = feedback_cb; - driver_.user_data = this; - driver_.long_press_time = kLongPressDelayMs; - driver_.long_press_repeat_time = kRepeatDelayMs; - - registration_ = lv_indev_drv_register(&driver_); -} - -auto LvglInputDriver::read(lv_indev_data_t* data) -> void { - // TODO: we should pass lock state on to the individual devices, since they - // may wish to either ignore the lock state, or power down until unlock. - if (is_locked_) { - return; - } - for (auto&& device : inputs_) { - device->read(data); - } -} - -auto LvglInputDriver::feedback(uint8_t event) -> void { - if (is_locked_) { - return; - } - for (auto&& device : feedbacks_) { - device->feedback(event); - } -} - -auto LvglInputDriver::pushHooks(lua_State* L) -> int { - lua_newtable(L); - - for (auto& dev : inputs_) { - lua_pushlstring(L, dev->name().data(), dev->name().size()); - lua_newtable(L); - - for (auto& hook : dev->hooks()) { - lua_pushlstring(L, hook.name().data(), hook.name().size()); - hook.pushHooks(L); - lua_rawset(L, -3); - } - - lua_rawset(L, -3); - } - return 1; -} - -} // namespace input diff --git a/src/locale/CMakeLists.txt b/src/locale/CMakeLists.txt index 627ca314..9c1c2619 100644 --- a/src/locale/CMakeLists.txt +++ b/src/locale/CMakeLists.txt @@ -6,6 +6,6 @@ idf_component_register( SRCS "collation.cpp" "strxfrm_l.c" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "priv_include" - REQUIRES "span" "esp_partition" "spi_flash") + REQUIRES "esp_partition" "spi_flash") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/locale/include/collation.hpp b/src/locale/include/collation.hpp index b666860d..88f499c4 100644 --- a/src/locale/include/collation.hpp +++ b/src/locale/include/collation.hpp @@ -9,10 +9,10 @@ #include <cstddef> #include <memory> #include <optional> +#include <span> #include <string> #include "esp_partition.h" -#include "span.hpp" #include "strxfrm.h" diff --git a/src/lua/CMakeLists.txt b/src/lua/CMakeLists.txt deleted file mode 100644 index 4aa5a123..00000000 --- a/src/lua/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2023 jacqueline <me@jacqueline.id.au> -# -# SPDX-License-Identifier: GPL-3.0-only - -idf_component_register( - SRCS "lua_theme.cpp" "lua_thread.cpp" "bridge.cpp" "property.cpp" "lua_database.cpp" - "lua_queue.cpp" "lua_version.cpp" "lua_theme.cpp" "lua_controls.cpp" "registry.cpp" - "lua_screen.cpp" "lua_filesystem.cpp" "file_iterator.cpp" - INCLUDE_DIRS "include" - REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" "fatfs" - "esp_timer" "battery" "esp-idf-lua" "luavgl" "lua-linenoise" "lua-term" - "esp_app_format") -target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt index 3ae92ac2..9019c254 100644 --- a/src/main/CMakeLists.txt +++ b/src/main/CMakeLists.txt @@ -2,8 +2,5 @@ # # SPDX-License-Identifier: GPL-3.0-only -idf_component_register( - SRCS "main.cpp" - INCLUDE_DIRS "." - REQUIRES "audio" "ui" "system_fsm" "events") +idf_component_register(SRCS "main.cpp" INCLUDE_DIRS "." REQUIRES "tangara") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/main/main.cpp b/src/main/main.cpp index cf27b132..8c7565f3 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -7,14 +7,14 @@ #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" -#include "i2c.hpp" -#include "system_events.hpp" #include "tinyfsm.hpp" -#include "audio_fsm.hpp" -#include "event_queue.hpp" -#include "system_fsm.hpp" -#include "ui_fsm.hpp" +#include "audio/audio_fsm.hpp" +#include "drivers/i2c.hpp" +#include "events/event_queue.hpp" +#include "system_fsm/system_events.hpp" +#include "system_fsm/system_fsm.hpp" +#include "ui/ui_fsm.hpp" extern "C" void app_main(void) { ESP_ERROR_CHECK(drivers::init_i2c()); diff --git a/src/memory/include/himem.hpp b/src/memory/include/himem.hpp index 81166e0d..f70648a9 100644 --- a/src/memory/include/himem.hpp +++ b/src/memory/include/himem.hpp @@ -8,9 +8,9 @@ #include <cstddef> #include <cstdint> +#include <span> #include "esp32/himem.h" -#include "span.hpp" /* * Wrapper around an ESP-IDF himem allocation, which uses RAII to clean up after @@ -62,14 +62,14 @@ class MappableRegion { } } - auto Get() -> cpp::span<std::byte> { + auto Get() -> std::span<std::byte> { if (bytes_ == nullptr) { return {}; } return {bytes_, size}; } - auto Map(const HimemAlloc<size>& alloc) -> cpp::span<std::byte> { + auto Map(const HimemAlloc<size>& alloc) -> std::span<std::byte> { assert(bytes_ == nullptr); ESP_ERROR_CHECK(esp_himem_map(alloc.handle, range_handle, 0, 0, size, 0, reinterpret_cast<void**>(&bytes_))); diff --git a/src/system_fsm/CMakeLists.txt b/src/system_fsm/CMakeLists.txt deleted file mode 100644 index e98d4653..00000000 --- a/src/system_fsm/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2023 jacqueline <me@jacqueline.id.au> -# -# SPDX-License-Identifier: GPL-3.0-only - -idf_component_register( - SRCS "system_fsm.cpp" "running.cpp" "booting.cpp" "idle.cpp" - "service_locator.cpp" - INCLUDE_DIRS "include" - REQUIRES "tinyfsm" "drivers" "database" "ui" "result" "events" "audio" - "app_console" "battery" "locale") -target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/tangara/CMakeLists.txt b/src/tangara/CMakeLists.txt new file mode 100644 index 00000000..fb8d1041 --- /dev/null +++ b/src/tangara/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright 2024 jacqueline <me@jacqueline.id.au> +# +# SPDX-License-Identifier: GPL-3.0-only + +idf_component_register( + SRC_DIRS "app_console" "audio" "battery" "database" "dev_console" "events" + "input" "lua" "system_fsm" "ui" + INCLUDE_DIRS "." + REQUIRES "codecs" "drivers" "locale" "memory" "tasks" "util" "graphics" + "tinyfsm" "lvgl" "esp_timer" "luavgl" "esp_app_format" "libcppbor" "libtags" + "komihash" "result" "esp_psram" "fatfs" "millershuffle" "speexdsp" "console" + "esp-idf-lua" "lua-linenoise" "lua-term") +target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) + +set(LEVELDB_BUILD_TESTS OFF) +set(LEVELDB_BUILD_BENCHMARKS OFF) +set(LEVELDB_INSTALL OFF) + +set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + +add_subdirectory($ENV{PROJ_PATH}/lib/leveldb ${CMAKE_CURRENT_BINARY_DIR}/leveldb) +target_link_libraries(${COMPONENT_LIB} PUBLIC leveldb) diff --git a/src/app_console/app_console.cpp b/src/tangara/app_console/app_console.cpp index 7c7c1abc..e3048ba2 100644 --- a/src/app_console/app_console.cpp +++ b/src/tangara/app_console/app_console.cpp @@ -4,11 +4,9 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "app_console.hpp" +#include "app_console/app_console.hpp" #include <dirent.h> -#include <stdint.h> -#include <sys/_stdint.h> #include <algorithm> #include <cstdint> @@ -21,11 +19,7 @@ #include <string> #include "FreeRTOSConfig.h" -#include "audio_events.hpp" -#include "audio_fsm.hpp" -#include "bluetooth.hpp" -#include "bluetooth_types.hpp" -#include "database.hpp" + #include "esp_app_desc.h" #include "esp_console.h" #include "esp_err.h" @@ -34,19 +28,25 @@ #include "esp_intr_alloc.h" #include "esp_log.h" #include "esp_system.h" -#include "event_queue.hpp" #include "ff.h" -#include "freertos/FreeRTOSConfig_arch.h" #include "freertos/projdefs.h" -#include "haptics.hpp" -#include "index.hpp" -#include "lua_registry.hpp" + +#include "drivers/bluetooth.hpp" +#include "drivers/bluetooth_types.hpp" +#include "drivers/haptics.hpp" +#include "drivers/samd.hpp" #include "memory_resource.hpp" -#include "samd.hpp" -#include "service_locator.hpp" -#include "system_events.hpp" -#include "track.hpp" -#include "ui_events.hpp" + +#include "audio/audio_events.hpp" +#include "audio/audio_fsm.hpp" +#include "database/database.hpp" +#include "database/index.hpp" +#include "database/track.hpp" +#include "events/event_queue.hpp" +#include "lua/lua_registry.hpp" +#include "system_fsm/service_locator.hpp" +#include "system_fsm/system_events.hpp" +#include "ui/ui_events.hpp" namespace console { diff --git a/src/app_console/include/app_console.hpp b/src/tangara/app_console/app_console.hpp index 5981cc04..b88b1330 100644 --- a/src/app_console/include/app_console.hpp +++ b/src/tangara/app_console/app_console.hpp @@ -8,12 +8,12 @@ #include <memory> -#include "bluetooth.hpp" -#include "console.hpp" -#include "database.hpp" -#include "samd.hpp" -#include "service_locator.hpp" -#include "track_queue.hpp" +#include "audio/track_queue.hpp" +#include "drivers/bluetooth.hpp" +#include "dev_console/console.hpp" +#include "database/database.hpp" +#include "drivers/samd.hpp" +#include "system_fsm/service_locator.hpp" namespace console { diff --git a/src/audio/README.md b/src/tangara/audio/README.md index 218be2c4..218be2c4 100644 --- a/src/audio/README.md +++ b/src/tangara/audio/README.md diff --git a/src/tangara/audio/audio_decoder.cpp b/src/tangara/audio/audio_decoder.cpp new file mode 100644 index 00000000..ee06d984 --- /dev/null +++ b/src/tangara/audio/audio_decoder.cpp @@ -0,0 +1,199 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "audio/audio_decoder.hpp" + +#include <cassert> +#include <cmath> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <deque> +#include <memory> +#include <span> +#include <variant> + +#include "esp_err.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "freertos/portmacro.h" +#include "freertos/projdefs.h" +#include "freertos/queue.h" + +#include "audio/audio_events.hpp" +#include "audio/audio_fsm.hpp" +#include "audio/audio_sink.hpp" +#include "audio/audio_source.hpp" +#include "audio/processor.hpp" +#include "codec.hpp" +#include "database/track.hpp" +#include "drivers/i2s_dac.hpp" +#include "events/event_queue.hpp" +#include "sample.hpp" +#include "tasks.hpp" +#include "types.hpp" +#include "ui/ui_fsm.hpp" + +namespace audio { + +static const char* kTag = "decoder"; + +/* + * The size of the buffer used for holding decoded samples. This buffer is + * allocated in internal memory for greater speed, so be careful when + * increasing its size. + */ +static constexpr std::size_t kCodecBufferLength = + drivers::kI2SBufferLengthFrames * sizeof(sample::Sample); + +auto Decoder::Start(std::shared_ptr<SampleProcessor> sink) -> Decoder* { + Decoder* task = new Decoder(sink); + tasks::StartPersistent<tasks::Type::kAudioDecoder>([=]() { task->Main(); }); + return task; +} + +auto Decoder::open(std::shared_ptr<TaggedStream> stream) -> void { + NextStream* next = new NextStream(); + next->stream = stream; + // The decoder services its queue very quickly, so blocking on this write + // should be fine. If we discover contention here, then adding more space for + // items to next_stream_ should be fine too. + xQueueSend(next_stream_, &next, portMAX_DELAY); +} + +Decoder::Decoder(std::shared_ptr<SampleProcessor> processor) + : processor_(processor), next_stream_(xQueueCreate(1, sizeof(void*))) { + ESP_LOGI(kTag, "allocating codec buffer, %u KiB", kCodecBufferLength / 1024); + codec_buffer_ = { + reinterpret_cast<sample::Sample*>(heap_caps_calloc( + kCodecBufferLength, sizeof(sample::Sample), MALLOC_CAP_DMA)), + kCodecBufferLength}; +} + +/* + * Main decoding loop. Handles watching for new streams, or continuing to nudge + * along the current stream if we have one. + */ +void Decoder::Main() { + for (;;) { + // Check whether there's a new stream to begin. If we're idle, then we + // simply park and wait forever for a stream to arrive. + TickType_t wait_time = stream_ ? 0 : portMAX_DELAY; + NextStream* next; + if (xQueueReceive(next_stream_, &next, wait_time)) { + // Copy the data out of the queue, then clean up the item. + std::shared_ptr<TaggedStream> new_stream = next->stream; + delete next; + + // If we were already decoding, then make sure we finish up the current + // file gracefully. + if (stream_) { + finishDecode(true); + } + + // Ensure there's actually stream data; we might have been given nullptr + // as a signal to stop. + if (!new_stream) { + continue; + } + + // Start decoding the new stream. + prepareDecode(new_stream); + } + + if (!continueDecode()) { + finishDecode(false); + } + } +} + +auto Decoder::prepareDecode(std::shared_ptr<TaggedStream> stream) -> void { + auto stub_track = std::make_shared<TrackInfo>(TrackInfo{ + .tags = stream->tags(), + .uri = stream->Filepath(), + .duration = {}, + .start_offset = {}, + .bitrate_kbps = {}, + .encoding = stream->type(), + .format = {}, + }); + + codec_.reset(codecs::CreateCodecForType(stream->type()).value_or(nullptr)); + if (!codec_) { + ESP_LOGE(kTag, "no codec found for stream"); + events::Audio().Dispatch( + internal::DecodingFailedToStart{.track = stub_track}); + return; + } + + auto open_res = codec_->OpenStream(stream, stream->Offset()); + if (open_res.has_error()) { + ESP_LOGE(kTag, "codec failed to start: %s", + codecs::ICodec::ErrorString(open_res.error()).c_str()); + events::Audio().Dispatch( + internal::DecodingFailedToStart{.track = stub_track}); + return; + } + + // Decoding started okay! Fill out the rest of the track info for this + // stream. + stream_ = stream; + track_ = std::make_shared<TrackInfo>(TrackInfo{ + .tags = stream->tags(), + .uri = stream->Filepath(), + .duration = {}, + .start_offset = stream->Offset(), + .bitrate_kbps = {}, + .encoding = stream->type(), + .format = + { + .sample_rate = open_res->sample_rate_hz, + .num_channels = open_res->num_channels, + .bits_per_sample = 16, + }, + }); + + if (open_res->total_samples) { + track_->duration = open_res->total_samples.value() / + open_res->num_channels / open_res->sample_rate_hz; + } + + events::Audio().Dispatch(internal::DecodingStarted{.track = track_}); + processor_->beginStream(track_); +} + +auto Decoder::continueDecode() -> bool { + auto res = codec_->DecodeTo(codec_buffer_); + if (res.has_error()) { + return false; + } + + if (res->samples_written > 0) { + processor_->continueStream(codec_buffer_.first(res->samples_written)); + } + + return !res->is_stream_finished; +} + +auto Decoder::finishDecode(bool cancel) -> void { + assert(track_); + + // Tell everyone we're finished. + if (cancel) { + events::Audio().Dispatch(internal::DecodingCancelled{.track = track_}); + } else { + events::Audio().Dispatch(internal::DecodingFinished{.track = track_}); + } + processor_->endStream(cancel); + + // Clean up after ourselves. + stream_.reset(); + codec_.reset(); + track_.reset(); +} + +} // namespace audio diff --git a/src/tangara/audio/audio_decoder.hpp b/src/tangara/audio/audio_decoder.hpp new file mode 100644 index 00000000..64561d9d --- /dev/null +++ b/src/tangara/audio/audio_decoder.hpp @@ -0,0 +1,60 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "audio/audio_events.hpp" +#include "audio/audio_sink.hpp" +#include "audio/audio_source.hpp" +#include "audio/processor.hpp" +#include "codec.hpp" +#include "database/track.hpp" +#include "types.hpp" + +namespace audio { + +/* + * Handle to a persistent task that takes encoded bytes from arbitrary sources, + * decodes them into sample::Sample (normalised to 16 bit signed PCM), and then + * streams them onward to the sample processor. + */ +class Decoder { + public: + static auto Start(std::shared_ptr<SampleProcessor>) -> Decoder*; + + auto open(std::shared_ptr<TaggedStream>) -> void; + + Decoder(const Decoder&) = delete; + Decoder& operator=(const Decoder&) = delete; + + private: + Decoder(std::shared_ptr<SampleProcessor>); + + auto Main() -> void; + + auto prepareDecode(std::shared_ptr<TaggedStream>) -> void; + auto continueDecode() -> bool; + auto finishDecode(bool cancel) -> void; + + std::shared_ptr<SampleProcessor> processor_; + + // Struct used with the next_stream_ queue. + struct NextStream { + std::shared_ptr<TaggedStream> stream; + }; + QueueHandle_t next_stream_; + + std::shared_ptr<codecs::IStream> stream_; + std::unique_ptr<codecs::ICodec> codec_; + std::shared_ptr<TrackInfo> track_; + + std::span<sample::Sample> codec_buffer_; +}; + +} // namespace audio diff --git a/src/audio/include/audio_events.hpp b/src/tangara/audio/audio_events.hpp index b8a0dba6..f7eaba67 100644 --- a/src/audio/include/audio_events.hpp +++ b/src/tangara/audio/audio_events.hpp @@ -12,10 +12,10 @@ #include <optional> #include <string> -#include "audio_sink.hpp" +#include "audio/audio_sink.hpp" #include "tinyfsm.hpp" -#include "track.hpp" +#include "database/track.hpp" #include "types.hpp" namespace audio { @@ -84,13 +84,6 @@ struct PlaybackUpdate : tinyfsm::Event { struct SetTrack : tinyfsm::Event { std::variant<std::string, database::TrackId, std::monostate> new_track; std::optional<uint32_t> seek_to_second; - - enum Transition { - kHardCut, - kGapless, - // TODO: kCrossFade - }; - Transition transition; }; struct TogglePlayPause : tinyfsm::Event { @@ -138,17 +131,33 @@ struct OutputModeChanged : tinyfsm::Event {}; namespace internal { +struct DecodingStarted : tinyfsm::Event { + std::shared_ptr<TrackInfo> track; +}; + +struct DecodingFailedToStart : tinyfsm::Event { + std::shared_ptr<TrackInfo> track; +}; + +struct DecodingCancelled : tinyfsm::Event { + std::shared_ptr<TrackInfo> track; +}; + +struct DecodingFinished : tinyfsm::Event { + std::shared_ptr<TrackInfo> track; +}; + struct StreamStarted : tinyfsm::Event { std::shared_ptr<TrackInfo> track; - IAudioOutput::Format src_format; - IAudioOutput::Format dst_format; + IAudioOutput::Format sink_format; + uint32_t cue_at_sample; }; -struct StreamUpdate : tinyfsm::Event { - uint32_t samples_sunk; +struct StreamEnded : tinyfsm::Event { + uint32_t cue_at_sample; }; -struct StreamEnded : tinyfsm::Event {}; +struct StreamHeartbeat : tinyfsm::Event {}; } // namespace internal diff --git a/src/audio/audio_fsm.cpp b/src/tangara/audio/audio_fsm.cpp index ffb462f8..71f41938 100644 --- a/src/audio/audio_fsm.cpp +++ b/src/tangara/audio/audio_fsm.cpp @@ -4,15 +4,13 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "audio_fsm.hpp" -#include <stdint.h> +#include "audio/audio_fsm.hpp" +#include <cstdint> #include <future> #include <memory> #include <variant> -#include "audio_sink.hpp" -#include "bluetooth_types.hpp" #include "cppbor.h" #include "cppbor_parse.h" #include "esp_heap_caps.h" @@ -20,25 +18,28 @@ #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" #include "freertos/projdefs.h" +#include "tinyfsm.hpp" -#include "audio_converter.hpp" -#include "audio_decoder.hpp" -#include "audio_events.hpp" -#include "bluetooth.hpp" -#include "bt_audio_output.hpp" -#include "event_queue.hpp" -#include "fatfs_audio_input.hpp" -#include "future_fetcher.hpp" -#include "i2s_audio_output.hpp" -#include "i2s_dac.hpp" -#include "nvs.hpp" +#include "audio/audio_decoder.hpp" +#include "audio/audio_events.hpp" +#include "audio/audio_sink.hpp" +#include "audio/bt_audio_output.hpp" +#include "audio/fatfs_stream_factory.hpp" +#include "audio/i2s_audio_output.hpp" +#include "audio/stream_cues.hpp" +#include "audio/track_queue.hpp" +#include "database/future_fetcher.hpp" +#include "database/track.hpp" +#include "drivers/bluetooth.hpp" +#include "drivers/bluetooth_types.hpp" +#include "drivers/i2s_dac.hpp" +#include "drivers/nvs.hpp" +#include "drivers/storage.hpp" +#include "drivers/wm8523.hpp" +#include "events/event_queue.hpp" #include "sample.hpp" -#include "service_locator.hpp" -#include "system_events.hpp" -#include "tinyfsm.hpp" -#include "track.hpp" -#include "track_queue.hpp" -#include "wm8523.hpp" +#include "system_fsm/service_locator.hpp" +#include "system_fsm/system_events.hpp" namespace audio { @@ -46,12 +47,14 @@ namespace audio { std::shared_ptr<system_fsm::ServiceLocator> AudioState::sServices; -std::shared_ptr<FatfsAudioInput> AudioState::sFileSource; +std::shared_ptr<FatfsStreamFactory> AudioState::sStreamFactory; + std::unique_ptr<Decoder> AudioState::sDecoder; -std::shared_ptr<SampleConverter> AudioState::sSampleConverter; +std::shared_ptr<SampleProcessor> AudioState::sSampleProcessor; + +std::shared_ptr<IAudioOutput> AudioState::sOutput; std::shared_ptr<I2SAudioOutput> AudioState::sI2SOutput; std::shared_ptr<BluetoothAudioOutput> AudioState::sBtOutput; -std::shared_ptr<IAudioOutput> AudioState::sOutput; // Two seconds of samples for two channels, at a representative sample rate. constexpr size_t kDrainLatencySamples = 48000 * 2 * 2; @@ -61,30 +64,33 @@ constexpr size_t kDrainBufferSize = StreamBufferHandle_t AudioState::sDrainBuffer; std::optional<IAudioOutput::Format> AudioState::sDrainFormat; -std::shared_ptr<TrackInfo> AudioState::sCurrentTrack; -uint64_t AudioState::sCurrentSamples; -bool AudioState::sCurrentTrackIsFromQueue; +StreamCues AudioState::sStreamCues; -std::shared_ptr<TrackInfo> AudioState::sNextTrack; -uint64_t AudioState::sNextTrackCueSamples; -bool AudioState::sNextTrackIsFromQueue; - -bool AudioState::sIsResampling; bool AudioState::sIsPaused = true; -auto AudioState::currentPositionSeconds() -> std::optional<uint32_t> { - if (!sCurrentTrack || !sDrainFormat) { - return {}; +auto AudioState::emitPlaybackUpdate(bool paused) -> void { + std::optional<uint32_t> position; + auto current = sStreamCues.current(); + if (current.first && sDrainFormat) { + position = (current.second / + (sDrainFormat->num_channels * sDrainFormat->sample_rate)) + + current.first->start_offset.value_or(0); } - return sCurrentSamples / - (sDrainFormat->num_channels * sDrainFormat->sample_rate); + + PlaybackUpdate event{ + .current_track = current.first, + .track_position = position, + .paused = paused, + }; + + events::System().Dispatch(event); + events::Ui().Dispatch(event); } void AudioState::react(const QueueUpdate& ev) { SetTrack cmd{ .new_track = std::monostate{}, .seek_to_second = {}, - .transition = SetTrack::Transition::kHardCut, }; auto current = sServices->track_queue().current(); @@ -97,20 +103,13 @@ void AudioState::react(const QueueUpdate& ev) { if (!ev.current_changed) { return; } - sNextTrackIsFromQueue = true; - cmd.transition = SetTrack::Transition::kHardCut; break; case QueueUpdate::kRepeatingLastTrack: - sNextTrackIsFromQueue = true; - cmd.transition = SetTrack::Transition::kGapless; break; case QueueUpdate::kTrackFinished: if (!ev.current_changed) { cmd.new_track = std::monostate{}; - } else { - sNextTrackIsFromQueue = true; } - cmd.transition = SetTrack::Transition::kGapless; break; case QueueUpdate::kDeserialised: default: @@ -123,32 +122,9 @@ void AudioState::react(const QueueUpdate& ev) { } void AudioState::react(const SetTrack& ev) { - // Remember the current track if there is one, since we need to preserve some - // of the state if it turns out this SetTrack event corresponds to seeking - // within the current track. - std::string prev_uri; - bool prev_from_queue = false; - if (sCurrentTrack) { - prev_uri = sCurrentTrack->uri; - prev_from_queue = sCurrentTrackIsFromQueue; - } - - if (ev.transition == SetTrack::Transition::kHardCut) { - sCurrentTrack.reset(); - sCurrentSamples = 0; - sCurrentTrackIsFromQueue = false; - clearDrainBuffer(); - } - if (std::holds_alternative<std::monostate>(ev.new_track)) { ESP_LOGI(kTag, "playback finished, awaiting drain"); - sFileSource->SetPath(); - awaitEmptyDrainBuffer(); - sCurrentTrack.reset(); - sDrainFormat.reset(); - sCurrentSamples = 0; - sCurrentTrackIsFromQueue = false; - transit<states::Standby>(); + sDecoder->open({}); return; } @@ -157,96 +133,76 @@ void AudioState::react(const SetTrack& ev) { auto new_track = ev.new_track; uint32_t seek_to = ev.seek_to_second.value_or(0); sServices->bg_worker().Dispatch<void>([=]() { - std::optional<std::string> path; + std::shared_ptr<TaggedStream> stream; if (std::holds_alternative<database::TrackId>(new_track)) { - auto db = sServices->database().lock(); - if (db) { - path = db->getTrackPath(std::get<database::TrackId>(new_track)); - } + stream = sStreamFactory->create(std::get<database::TrackId>(new_track), + seek_to); } else if (std::holds_alternative<std::string>(new_track)) { - path = std::get<std::string>(new_track); + stream = + sStreamFactory->create(std::get<std::string>(new_track), seek_to); } - if (path) { - if (*path == prev_uri) { - // This was a seek or replay within the same track; don't forget where - // the track originally came from. - sNextTrackIsFromQueue = prev_from_queue; - } - sFileSource->SetPath(*path, seek_to); - } else { - sFileSource->SetPath(); - } + sDecoder->open(stream); }); } void AudioState::react(const TogglePlayPause& ev) { sIsPaused = !ev.set_to.value_or(sIsPaused); - if (!sIsPaused && is_in_state<states::Standby>() && sCurrentTrack) { + if (!sIsPaused && is_in_state<states::Standby>() && + sStreamCues.current().first) { transit<states::Playback>(); } else if (sIsPaused && is_in_state<states::Playback>()) { transit<states::Standby>(); } } -void AudioState::react(const internal::StreamStarted& ev) { - sDrainFormat = ev.dst_format; - sIsResampling = ev.src_format != ev.dst_format; - - sNextTrack = ev.track; - sNextTrackCueSamples = sCurrentSamples + (kDrainLatencySamples / 2); - - ESP_LOGI(kTag, "new stream %s %u ch @ %lu hz (resample=%i)", - ev.track->uri.c_str(), sDrainFormat->num_channels, - sDrainFormat->sample_rate, sIsResampling); -} - -void AudioState::react(const internal::StreamEnded&) { - ESP_LOGI(kTag, "stream ended"); - - if (sCurrentTrackIsFromQueue) { - sServices->track_queue().finish(); - } else { - tinyfsm::FsmList<AudioState>::dispatch(SetTrack{ - .new_track = std::monostate{}, - .seek_to_second = {}, - .transition = SetTrack::Transition::kGapless, - }); - } +void AudioState::react(const internal::DecodingFinished& ev) { + // If we just finished playing whatever's at the front of the queue, then we + // need to advanve and start playing the next one ASAP in order to continue + // gaplessly. + sServices->bg_worker().Dispatch<void>([=]() { + auto& queue = sServices->track_queue(); + auto current = queue.current(); + if (!current) { + return; + } + auto db = sServices->database().lock(); + if (!db) { + return; + } + auto path = db->getTrackPath(*current); + if (!path) { + return; + } + if (*path == ev.track->uri) { + queue.finish(); + } + }); } -void AudioState::react(const internal::StreamUpdate& ev) { - sCurrentSamples += ev.samples_sunk; - - if (sNextTrack && sCurrentSamples >= sNextTrackCueSamples) { - ESP_LOGI(kTag, "next track is now sinking"); - sCurrentTrack = sNextTrack; - sCurrentSamples -= sNextTrackCueSamples; - sCurrentSamples += sNextTrack->start_offset.value_or(0) * - (sDrainFormat->num_channels * sDrainFormat->sample_rate); - sCurrentTrackIsFromQueue = sNextTrackIsFromQueue; - - sNextTrack.reset(); - sNextTrackCueSamples = 0; - sNextTrackIsFromQueue = false; +void AudioState::react(const internal::StreamStarted& ev) { + if (sDrainFormat != ev.sink_format) { + sDrainFormat = ev.sink_format; + ESP_LOGI(kTag, "sink_format=%u ch @ %lu hz", sDrainFormat->num_channels, + sDrainFormat->sample_rate); } - if (sCurrentTrack) { - PlaybackUpdate event{ - .current_track = sCurrentTrack, - .track_position = currentPositionSeconds(), - .paused = !is_in_state<states::Playback>(), - }; - events::System().Dispatch(event); - events::Ui().Dispatch(event); - } + sStreamCues.addCue(ev.track, ev.cue_at_sample); - if (sCurrentTrack && !sIsPaused && !is_in_state<states::Playback>()) { - ESP_LOGI(kTag, "ready to play!"); + if (!sIsPaused && !is_in_state<states::Playback>()) { transit<states::Playback>(); + } else { + // Make sure everyone knows we've got a track ready to go, even if we're + // not playing it yet. This mostly matters when restoring the queue from + // disk after booting. + emitPlaybackUpdate(true); } } +void AudioState::react(const internal::StreamEnded& ev) { + sStreamCues.addCue({}, ev.cue_at_sample); +} + void AudioState::react(const system_fsm::BluetoothEvent& ev) { if (ev.event != drivers::bluetooth::Event::kConnectionStateChanged) { return; @@ -282,14 +238,6 @@ void AudioState::react(const StepDownVolume& ev) { } } -void AudioState::react(const system_fsm::HasPhonesChanged& ev) { - if (ev.has_headphones) { - ESP_LOGI(kTag, "headphones in!"); - } else { - ESP_LOGI(kTag, "headphones out!"); - } -} - void AudioState::react(const SetVolume& ev) { if (ev.db.has_value()) { if (sOutput->SetVolumeDb(ev.db.value())) { @@ -349,7 +297,7 @@ void AudioState::react(const OutputModeChanged& ev) { break; } sOutput->mode(IAudioOutput::Modes::kOnPaused); - sSampleConverter->SetOutput(sOutput); + sSampleProcessor->SetOutput(sOutput); // Bluetooth volume isn't 'changed' until we've connected to a device. if (new_mode == drivers::NvsStorage::Output::kHeadphones) { @@ -360,43 +308,6 @@ void AudioState::react(const OutputModeChanged& ev) { } } -auto AudioState::clearDrainBuffer() -> void { - // Tell the decoder to stop adding new samples. This might not take effect - // immediately, since the decoder might currently be stuck waiting for space - // to become available in the drain buffer. - sFileSource->SetPath(); - - auto mode = sOutput->mode(); - if (mode == IAudioOutput::Modes::kOnPlaying) { - // If we're currently playing, then the drain buffer will be actively - // draining on its own. Just keep trying to reset until it works. - while (xStreamBufferReset(sDrainBuffer) != pdPASS) { - } - } else { - // If we're not currently playing, then we need to actively pull samples - // out of the drain buffer to unblock the decoder. - while (!xStreamBufferIsEmpty(sDrainBuffer)) { - // Read a little to unblock the decoder. - uint8_t drain[2048]; - xStreamBufferReceive(sDrainBuffer, drain, sizeof(drain), 0); - - // Try to quickly discard the rest. - xStreamBufferReset(sDrainBuffer); - } - } -} - -auto AudioState::awaitEmptyDrainBuffer() -> void { - if (is_in_state<states::Playback>()) { - for (int i = 0; i < 10 && !xStreamBufferIsEmpty(sDrainBuffer); i++) { - vTaskDelay(pdMS_TO_TICKS(250)); - } - } - if (!xStreamBufferIsEmpty(sDrainBuffer)) { - clearDrainBuffer(); - } -} - auto AudioState::commitVolume() -> void { auto mode = sServices->nvs().OutputMode(); auto vol = sOutput->GetVolume(); @@ -427,8 +338,7 @@ void Uninitialised::react(const system_fsm::BootComplete& ev) { sDrainBuffer = xStreamBufferCreateStatic( kDrainBufferSize, sizeof(sample::Sample), storage, meta); - sFileSource.reset( - new FatfsAudioInput(sServices->tag_parser(), sServices->bg_worker())); + sStreamFactory.reset(new FatfsStreamFactory(*sServices)); sI2SOutput.reset(new I2SAudioOutput(sDrainBuffer, sServices->gpios())); sBtOutput.reset(new BluetoothAudioOutput(sDrainBuffer, sServices->bluetooth(), sServices->bg_worker())); @@ -462,10 +372,10 @@ void Uninitialised::react(const system_fsm::BootComplete& ev) { .left_bias = nvs.AmpLeftBias(), }); - sSampleConverter.reset(new SampleConverter()); - sSampleConverter->SetOutput(sOutput); + sSampleProcessor.reset(new SampleProcessor(sDrainBuffer)); + sSampleProcessor->SetOutput(sOutput); - Decoder::Start(sFileSource, sSampleConverter); + sDecoder.reset(Decoder::Start(sSampleProcessor)); transit<Standby>(); } @@ -477,7 +387,8 @@ void Standby::react(const system_fsm::KeyLockChanged& ev) { if (!ev.locking) { return; } - sServices->bg_worker().Dispatch<void>([this]() { + auto current = sStreamCues.current(); + sServices->bg_worker().Dispatch<void>([=]() { auto db = sServices->database().lock(); if (!db) { return; @@ -490,17 +401,24 @@ void Standby::react(const system_fsm::KeyLockChanged& ev) { } db->put(kQueueKey, queue.serialise()); - if (sCurrentTrack) { + if (current.first && sDrainFormat) { + uint32_t seconds = (current.second / (sDrainFormat->num_channels * + sDrainFormat->sample_rate)) + + current.first->start_offset.value_or(0); cppbor::Array current_track{ - cppbor::Tstr{sCurrentTrack->uri}, - cppbor::Uint{currentPositionSeconds().value_or(0)}, + cppbor::Tstr{current.first->uri}, + cppbor::Uint{seconds}, }; db->put(kCurrentFileKey, current_track.toString()); } }); } -void Standby::react(const system_fsm::StorageMounted& ev) { +void Standby::react(const system_fsm::SdStateChanged& ev) { + auto state = sServices->sd(); + if (state != drivers::SdState::kMounted) { + return; + } sServices->bg_worker().Dispatch<void>([]() { auto db = sServices->database().lock(); if (!db) { @@ -524,7 +442,6 @@ void Standby::react(const system_fsm::StorageMounted& ev) { events::Audio().Dispatch(SetTrack{ .new_track = filename, .seek_to_second = pos, - .transition = SetTrack::Transition::kHardCut, }); } } @@ -540,32 +457,47 @@ void Standby::react(const system_fsm::StorageMounted& ev) { }); } +static TimerHandle_t sHeartbeatTimer; + +static void heartbeat(TimerHandle_t) { + events::Audio().Dispatch(internal::StreamHeartbeat{}); +} + void Playback::entry() { ESP_LOGI(kTag, "audio output resumed"); sOutput->mode(IAudioOutput::Modes::kOnPlaying); + emitPlaybackUpdate(false); - PlaybackUpdate event{ - .current_track = sCurrentTrack, - .track_position = currentPositionSeconds(), - .paused = false, - }; - - events::System().Dispatch(event); - events::Ui().Dispatch(event); + if (!sHeartbeatTimer) { + sHeartbeatTimer = + xTimerCreate("stream", pdMS_TO_TICKS(250), true, NULL, heartbeat); + } + xTimerStart(sHeartbeatTimer, portMAX_DELAY); } void Playback::exit() { ESP_LOGI(kTag, "audio output paused"); + xTimerStop(sHeartbeatTimer, portMAX_DELAY); sOutput->mode(IAudioOutput::Modes::kOnPaused); + emitPlaybackUpdate(true); +} - PlaybackUpdate event{ - .current_track = sCurrentTrack, - .track_position = currentPositionSeconds(), - .paused = true, - }; +void Playback::react(const system_fsm::SdStateChanged& ev) { + if (sServices->sd() != drivers::SdState::kMounted) { + transit<Standby>(); + } +} - events::System().Dispatch(event); - events::Ui().Dispatch(event); +void Playback::react(const internal::StreamHeartbeat& ev) { + sStreamCues.update(sOutput->samplesUsed()); + + if (sStreamCues.hasStream()) { + emitPlaybackUpdate(false); + } else { + // Finished the current stream, and there's nothing upcoming. We must be + // finished. + transit<Standby>(); + } } } // namespace states diff --git a/src/audio/include/audio_fsm.hpp b/src/tangara/audio/audio_fsm.hpp index 60afb321..03aaddcb 100644 --- a/src/audio/include/audio_fsm.hpp +++ b/src/tangara/audio/audio_fsm.hpp @@ -11,24 +11,25 @@ #include <memory> #include <vector> -#include "audio_sink.hpp" -#include "service_locator.hpp" +#include "audio/stream_cues.hpp" #include "tinyfsm.hpp" -#include "audio_decoder.hpp" -#include "audio_events.hpp" -#include "bt_audio_output.hpp" -#include "database.hpp" -#include "display.hpp" -#include "fatfs_audio_input.hpp" -#include "gpios.hpp" -#include "i2s_audio_output.hpp" -#include "i2s_dac.hpp" -#include "storage.hpp" -#include "system_events.hpp" -#include "tag_parser.hpp" -#include "track.hpp" -#include "track_queue.hpp" +#include "audio/audio_decoder.hpp" +#include "audio/audio_events.hpp" +#include "audio/audio_sink.hpp" +#include "audio/bt_audio_output.hpp" +#include "audio/fatfs_stream_factory.hpp" +#include "audio/i2s_audio_output.hpp" +#include "audio/track_queue.hpp" +#include "database/database.hpp" +#include "database/tag_parser.hpp" +#include "database/track.hpp" +#include "drivers/display.hpp" +#include "drivers/gpios.hpp" +#include "drivers/i2s_dac.hpp" +#include "drivers/storage.hpp" +#include "system_fsm/service_locator.hpp" +#include "system_fsm/system_events.hpp" namespace audio { @@ -46,13 +47,13 @@ class AudioState : public tinyfsm::Fsm<AudioState> { void react(const SetTrack&); void react(const TogglePlayPause&); + void react(const internal::DecodingFinished&); void react(const internal::StreamStarted&); - void react(const internal::StreamUpdate&); void react(const internal::StreamEnded&); + virtual void react(const internal::StreamHeartbeat&) {} void react(const StepUpVolume&); void react(const StepDownVolume&); - virtual void react(const system_fsm::HasPhonesChanged&); void react(const SetVolume&); void react(const SetVolumeLimit&); @@ -62,40 +63,28 @@ class AudioState : public tinyfsm::Fsm<AudioState> { virtual void react(const system_fsm::BootComplete&) {} virtual void react(const system_fsm::KeyLockChanged&){}; - virtual void react(const system_fsm::StorageMounted&) {} + virtual void react(const system_fsm::SdStateChanged&) {} virtual void react(const system_fsm::BluetoothEvent&); protected: - auto clearDrainBuffer() -> void; - auto awaitEmptyDrainBuffer() -> void; - - auto playTrack(database::TrackId id) -> void; + auto emitPlaybackUpdate(bool paused) -> void; auto commitVolume() -> void; static std::shared_ptr<system_fsm::ServiceLocator> sServices; - static std::shared_ptr<FatfsAudioInput> sFileSource; + static std::shared_ptr<FatfsStreamFactory> sStreamFactory; static std::unique_ptr<Decoder> sDecoder; - static std::shared_ptr<SampleConverter> sSampleConverter; + static std::shared_ptr<SampleProcessor> sSampleProcessor; static std::shared_ptr<I2SAudioOutput> sI2SOutput; static std::shared_ptr<BluetoothAudioOutput> sBtOutput; static std::shared_ptr<IAudioOutput> sOutput; static StreamBufferHandle_t sDrainBuffer; - static std::shared_ptr<TrackInfo> sCurrentTrack; - static uint64_t sCurrentSamples; + static StreamCues sStreamCues; static std::optional<IAudioOutput::Format> sDrainFormat; - static bool sCurrentTrackIsFromQueue; - - static std::shared_ptr<TrackInfo> sNextTrack; - static uint64_t sNextTrackCueSamples; - static bool sNextTrackIsFromQueue; - static bool sIsResampling; static bool sIsPaused; - - auto currentPositionSeconds() -> std::optional<uint32_t>; }; namespace states { @@ -111,7 +100,7 @@ class Uninitialised : public AudioState { class Standby : public AudioState { public: void react(const system_fsm::KeyLockChanged&) override; - void react(const system_fsm::StorageMounted&) override; + void react(const system_fsm::SdStateChanged&) override; using AudioState::react; }; @@ -121,6 +110,9 @@ class Playback : public AudioState { void entry() override; void exit() override; + void react(const system_fsm::SdStateChanged&) override; + void react(const internal::StreamHeartbeat&) override; + using AudioState::react; }; diff --git a/src/audio/include/audio_sink.hpp b/src/tangara/audio/audio_sink.hpp index f31d0d75..0b133a8d 100644 --- a/src/audio/include/audio_sink.hpp +++ b/src/tangara/audio/audio_sink.hpp @@ -75,6 +75,7 @@ class IAudioOutput { virtual auto PrepareFormat(const Format&) -> Format = 0; virtual auto Configure(const Format& format) -> void = 0; + virtual auto samplesUsed() -> uint32_t = 0; auto stream() -> StreamBufferHandle_t { return stream_; } diff --git a/src/audio/audio_source.cpp b/src/tangara/audio/audio_source.cpp index d9e8e04a..4989c470 100644 --- a/src/audio/audio_source.cpp +++ b/src/tangara/audio/audio_source.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "audio_source.hpp" +#include "audio/audio_source.hpp" #include "codec.hpp" #include "types.hpp" @@ -14,13 +14,17 @@ TaggedStream::TaggedStream(std::shared_ptr<database::TrackTags> t, std::unique_ptr<codecs::IStream> w, std::string filepath, uint32_t offset) - : codecs::IStream(w->type()), tags_(t), wrapped_(std::move(w)), filepath_(filepath), offset_(offset) {} + : codecs::IStream(w->type()), + tags_(t), + wrapped_(std::move(w)), + filepath_(filepath), + offset_(offset) {} auto TaggedStream::tags() -> std::shared_ptr<database::TrackTags> { return tags_; } -auto TaggedStream::Read(cpp::span<std::byte> dest) -> ssize_t { +auto TaggedStream::Read(std::span<std::byte> dest) -> ssize_t { return wrapped_->Read(dest); } diff --git a/src/audio/include/audio_source.hpp b/src/tangara/audio/audio_source.hpp index b38acd7a..2433da46 100644 --- a/src/audio/include/audio_source.hpp +++ b/src/tangara/audio/audio_source.hpp @@ -8,7 +8,7 @@ #include <memory> #include "codec.hpp" -#include "track.hpp" +#include "database/track.hpp" #include "types.hpp" namespace audio { @@ -18,12 +18,11 @@ class TaggedStream : public codecs::IStream { TaggedStream(std::shared_ptr<database::TrackTags>, std::unique_ptr<codecs::IStream> wrapped, std::string path, - uint32_t offset = 0 - ); + uint32_t offset = 0); auto tags() -> std::shared_ptr<database::TrackTags>; - auto Read(cpp::span<std::byte> dest) -> ssize_t override; + auto Read(std::span<std::byte> dest) -> ssize_t override; auto CanSeek() -> bool override; diff --git a/src/audio/bt_audio_output.cpp b/src/tangara/audio/bt_audio_output.cpp index 229a38bb..f1b4c26c 100644 --- a/src/audio/bt_audio_output.cpp +++ b/src/tangara/audio/bt_audio_output.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "bt_audio_output.hpp" +#include "audio/bt_audio_output.hpp" #include <algorithm> #include <cmath> @@ -18,12 +18,12 @@ #include "freertos/portmacro.h" #include "freertos/projdefs.h" -#include "gpios.hpp" -#include "i2c.hpp" -#include "i2s_dac.hpp" +#include "drivers/gpios.hpp" +#include "drivers/i2c.hpp" +#include "drivers/i2s_dac.hpp" +#include "drivers/wm8523.hpp" #include "result.hpp" #include "tasks.hpp" -#include "wm8523.hpp" [[maybe_unused]] static const char* kTag = "BTOUT"; @@ -121,4 +121,8 @@ auto BluetoothAudioOutput::Configure(const Format& fmt) -> void { // No configuration necessary; the output format is fixed. } +auto BluetoothAudioOutput::samplesUsed() -> uint32_t { + return bluetooth_.SamplesUsed(); +} + } // namespace audio diff --git a/src/audio/include/bt_audio_output.hpp b/src/tangara/audio/bt_audio_output.hpp index cc3b2462..c5681f9a 100644 --- a/src/audio/include/bt_audio_output.hpp +++ b/src/tangara/audio/bt_audio_output.hpp @@ -13,10 +13,10 @@ #include "result.hpp" -#include "audio_sink.hpp" -#include "bluetooth.hpp" -#include "gpios.hpp" -#include "i2s_dac.hpp" +#include "audio/audio_sink.hpp" +#include "drivers/bluetooth.hpp" +#include "drivers/gpios.hpp" +#include "drivers/i2s_dac.hpp" #include "tasks.hpp" namespace audio { @@ -45,6 +45,8 @@ class BluetoothAudioOutput : public IAudioOutput { auto PrepareFormat(const Format&) -> Format override; auto Configure(const Format& format) -> void override; + auto samplesUsed() -> uint32_t override; + BluetoothAudioOutput(const BluetoothAudioOutput&) = delete; BluetoothAudioOutput& operator=(const BluetoothAudioOutput&) = delete; diff --git a/src/audio/fatfs_source.cpp b/src/tangara/audio/fatfs_source.cpp index 72c3940d..fb6a684d 100644 --- a/src/audio/fatfs_source.cpp +++ b/src/tangara/audio/fatfs_source.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "fatfs_source.hpp" +#include "audio/fatfs_source.hpp" #include <sys/_stdint.h> #include <cstddef> @@ -12,13 +12,13 @@ #include <memory> #include "esp_log.h" -#include "event_queue.hpp" +#include "events/event_queue.hpp" #include "ff.h" -#include "audio_source.hpp" +#include "audio/audio_source.hpp" #include "codec.hpp" -#include "spi.hpp" -#include "system_events.hpp" +#include "drivers/spi.hpp" +#include "system_fsm/system_events.hpp" #include "types.hpp" namespace audio { @@ -33,7 +33,7 @@ FatfsSource::~FatfsSource() { f_close(file_.get()); } -auto FatfsSource::Read(cpp::span<std::byte> dest) -> ssize_t { +auto FatfsSource::Read(std::span<std::byte> dest) -> ssize_t { auto lock = drivers::acquire_spi(); if (f_eof(file_.get())) { return 0; diff --git a/src/audio/include/fatfs_source.hpp b/src/tangara/audio/fatfs_source.hpp index 45ab34c6..32650880 100644 --- a/src/audio/include/fatfs_source.hpp +++ b/src/tangara/audio/fatfs_source.hpp @@ -13,7 +13,7 @@ #include "codec.hpp" #include "ff.h" -#include "audio_source.hpp" +#include "audio/audio_source.hpp" namespace audio { @@ -26,7 +26,7 @@ class FatfsSource : public codecs::IStream { FatfsSource(codecs::StreamType, std::unique_ptr<FIL> file); ~FatfsSource(); - auto Read(cpp::span<std::byte> dest) -> ssize_t override; + auto Read(std::span<std::byte> dest) -> ssize_t override; auto CanSeek() -> bool override; diff --git a/src/tangara/audio/fatfs_stream_factory.cpp b/src/tangara/audio/fatfs_stream_factory.cpp new file mode 100644 index 00000000..db08e68c --- /dev/null +++ b/src/tangara/audio/fatfs_stream_factory.cpp @@ -0,0 +1,104 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "audio/fatfs_stream_factory.hpp" + +#include <cstdint> +#include <memory> +#include <string> + +#include "database/database.hpp" +#include "esp_log.h" +#include "ff.h" +#include "freertos/portmacro.h" +#include "freertos/projdefs.h" + +#include "audio/audio_source.hpp" +#include "audio/fatfs_source.hpp" +#include "codec.hpp" +#include "database/tag_parser.hpp" +#include "database/track.hpp" +#include "drivers/spi.hpp" +#include "system_fsm/service_locator.hpp" +#include "tasks.hpp" +#include "types.hpp" + +[[maybe_unused]] static const char* kTag = "SRC"; + +namespace audio { + +FatfsStreamFactory::FatfsStreamFactory(system_fsm::ServiceLocator& services) + : services_(services) {} + +auto FatfsStreamFactory::create(database::TrackId id, uint32_t offset) + -> std::shared_ptr<TaggedStream> { + auto db = services_.database().lock(); + if (!db) { + return {}; + } + auto path = db->getTrackPath(id); + if (!path) { + return {}; + } + return create(*path, offset); +} + +auto FatfsStreamFactory::create(std::string path, uint32_t offset) + -> std::shared_ptr<TaggedStream> { + auto tags = services_.tag_parser().ReadAndParseTags(path); + if (!tags) { + ESP_LOGE(kTag, "failed to read tags"); + return {}; + } + + if (!tags->title()) { + tags->title(path); + } + + auto stream_type = ContainerToStreamType(tags->encoding()); + if (!stream_type.has_value()) { + ESP_LOGE(kTag, "couldn't match container to stream"); + return {}; + } + + std::unique_ptr<FIL> file = std::make_unique<FIL>(); + FRESULT res; + + { + auto lock = drivers::acquire_spi(); + res = f_open(file.get(), path.c_str(), FA_READ); + } + + if (res != FR_OK) { + ESP_LOGE(kTag, "failed to open file! res: %i", res); + return {}; + } + + return std::make_shared<TaggedStream>( + tags, std::make_unique<FatfsSource>(stream_type.value(), std::move(file)), + path, offset); +} + +auto FatfsStreamFactory::ContainerToStreamType(database::Container enc) + -> std::optional<codecs::StreamType> { + switch (enc) { + case database::Container::kMp3: + return codecs::StreamType::kMp3; + case database::Container::kWav: + return codecs::StreamType::kWav; + case database::Container::kOgg: + return codecs::StreamType::kVorbis; + case database::Container::kFlac: + return codecs::StreamType::kFlac; + case database::Container::kOpus: + return codecs::StreamType::kOpus; + case database::Container::kUnsupported: + default: + return {}; + } +} + +} // namespace audio diff --git a/src/tangara/audio/fatfs_stream_factory.hpp b/src/tangara/audio/fatfs_stream_factory.hpp new file mode 100644 index 00000000..858d2131 --- /dev/null +++ b/src/tangara/audio/fatfs_stream_factory.hpp @@ -0,0 +1,53 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include <stdint.h> +#include <cstddef> +#include <cstdint> +#include <future> +#include <memory> +#include <string> + +#include "database/database.hpp" +#include "database/track.hpp" +#include "ff.h" +#include "freertos/portmacro.h" + +#include "audio/audio_source.hpp" +#include "codec.hpp" +#include "database/future_fetcher.hpp" +#include "database/tag_parser.hpp" +#include "system_fsm/service_locator.hpp" +#include "tasks.hpp" +#include "types.hpp" + +namespace audio { + +/* + * Utility to create streams that read from files on the sd card. + */ +class FatfsStreamFactory { + public: + explicit FatfsStreamFactory(system_fsm::ServiceLocator&); + + auto create(database::TrackId, uint32_t offset = 0) + -> std::shared_ptr<TaggedStream>; + auto create(std::string, uint32_t offset = 0) + -> std::shared_ptr<TaggedStream>; + + FatfsStreamFactory(const FatfsStreamFactory&) = delete; + FatfsStreamFactory& operator=(const FatfsStreamFactory&) = delete; + + private: + auto ContainerToStreamType(database::Container) + -> std::optional<codecs::StreamType>; + + system_fsm::ServiceLocator& services_; +}; + +} // namespace audio diff --git a/src/audio/i2s_audio_output.cpp b/src/tangara/audio/i2s_audio_output.cpp index bf1c3e5e..684bfa92 100644 --- a/src/audio/i2s_audio_output.cpp +++ b/src/tangara/audio/i2s_audio_output.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "i2s_audio_output.hpp" +#include "audio/i2s_audio_output.hpp" #include <stdint.h> #include <algorithm> @@ -18,12 +18,12 @@ #include "freertos/portmacro.h" #include "freertos/projdefs.h" -#include "audio_sink.hpp" -#include "gpios.hpp" -#include "i2c.hpp" -#include "i2s_dac.hpp" +#include "audio/audio_sink.hpp" +#include "drivers/gpios.hpp" +#include "drivers/i2c.hpp" +#include "drivers/i2s_dac.hpp" +#include "drivers/wm8523.hpp" #include "result.hpp" -#include "wm8523.hpp" [[maybe_unused]] static const char* kTag = "I2SOUT"; @@ -120,7 +120,7 @@ auto I2SAudioOutput::SetVolumePct(uint_fast8_t val) -> bool { if (val > 100) { return false; } - uint16_t vol = (val * (max_volume_ - kMinVolume))/100 + kMinVolume; + uint16_t vol = (val * (max_volume_ - kMinVolume)) / 100 + kMinVolume; SetVolume(vol); return true; } @@ -133,7 +133,8 @@ auto I2SAudioOutput::GetVolumeDb() -> int_fast16_t { } auto I2SAudioOutput::SetVolumeDb(int_fast16_t val) -> bool { - SetVolume(val * 4 + static_cast<int>(drivers::wm8523::kLineLevelReferenceVolume) - 2); + SetVolume(val * 4 + + static_cast<int>(drivers::wm8523::kLineLevelReferenceVolume) - 2); return true; } @@ -229,4 +230,8 @@ auto I2SAudioOutput::Configure(const Format& fmt) -> void { current_config_ = fmt; } +auto I2SAudioOutput::samplesUsed() -> uint32_t { + return dac_->SamplesUsed(); +} + } // namespace audio diff --git a/src/audio/include/i2s_audio_output.hpp b/src/tangara/audio/i2s_audio_output.hpp index 7954257a..bd7d62fb 100644 --- a/src/audio/include/i2s_audio_output.hpp +++ b/src/tangara/audio/i2s_audio_output.hpp @@ -11,9 +11,9 @@ #include <memory> #include <vector> -#include "audio_sink.hpp" -#include "gpios.hpp" -#include "i2s_dac.hpp" +#include "audio/audio_sink.hpp" +#include "drivers/gpios.hpp" +#include "drivers/i2s_dac.hpp" #include "result.hpp" namespace audio { @@ -43,6 +43,8 @@ class I2SAudioOutput : public IAudioOutput { auto PrepareFormat(const Format&) -> Format override; auto Configure(const Format& format) -> void override; + auto samplesUsed() -> uint32_t override; + I2SAudioOutput(const I2SAudioOutput&) = delete; I2SAudioOutput& operator=(const I2SAudioOutput&) = delete; diff --git a/src/audio/audio_converter.cpp b/src/tangara/audio/processor.cpp index eb1cde80..dd96c892 100644 --- a/src/audio/audio_converter.cpp +++ b/src/tangara/audio/processor.cpp @@ -4,23 +4,24 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "audio_converter.hpp" +#include "audio/processor.hpp" #include <stdint.h> #include <algorithm> #include <cmath> #include <cstdint> +#include <limits> -#include "audio_events.hpp" -#include "audio_sink.hpp" +#include "audio/audio_events.hpp" +#include "audio/audio_sink.hpp" +#include "drivers/i2s_dac.hpp" #include "esp_heap_caps.h" #include "esp_log.h" -#include "event_queue.hpp" +#include "events/event_queue.hpp" #include "freertos/portmacro.h" #include "freertos/projdefs.h" -#include "i2s_dac.hpp" -#include "resample.hpp" +#include "audio/resample.hpp" #include "sample.hpp" #include "tasks.hpp" @@ -32,14 +33,15 @@ static constexpr std::size_t kSourceBufferLength = kSampleBufferLength * 2; namespace audio { -SampleConverter::SampleConverter() +SampleProcessor::SampleProcessor(StreamBufferHandle_t sink) : commands_(xQueueCreate(1, sizeof(Args))), resampler_(nullptr), source_(xStreamBufferCreateWithCaps(kSourceBufferLength, sizeof(sample::Sample) * 2, MALLOC_CAP_DMA)), + sink_(sink), leftover_bytes_(0), - samples_sunk_(0) { + samples_written_(0) { input_buffer_ = { reinterpret_cast<sample::Sample*>(heap_caps_calloc( kSampleBufferLength, sizeof(sample::Sample), MALLOC_CAP_DMA)), @@ -55,47 +57,52 @@ SampleConverter::SampleConverter() tasks::StartPersistent<tasks::Type::kAudioConverter>([&]() { Main(); }); } -SampleConverter::~SampleConverter() { +SampleProcessor::~SampleProcessor() { vQueueDelete(commands_); vStreamBufferDelete(source_); } -auto SampleConverter::SetOutput(std::shared_ptr<IAudioOutput> output) -> void { - // FIXME: We should add synchronisation here, but we should be careful about - // not impacting performance given that the output will change only very - // rarely (if ever). - sink_ = output; +auto SampleProcessor::SetOutput(std::shared_ptr<IAudioOutput> output) -> void { + assert(xStreamBufferIsEmpty(sink_)); + // FIXME: We should add synchronisation here, but we should be careful + // about not impacting performance given that the output will change only + // very rarely (if ever). + output_ = output; + samples_written_ = output_->samplesUsed(); } -auto SampleConverter::beginStream(std::shared_ptr<TrackInfo> track) -> void { +auto SampleProcessor::beginStream(std::shared_ptr<TrackInfo> track) -> void { Args args{ .track = new std::shared_ptr<TrackInfo>(track), .samples_available = 0, .is_end_of_stream = false, + .clear_buffers = false, }; xQueueSend(commands_, &args, portMAX_DELAY); } -auto SampleConverter::continueStream(cpp::span<sample::Sample> input) -> void { +auto SampleProcessor::continueStream(std::span<sample::Sample> input) -> void { Args args{ .track = nullptr, .samples_available = input.size(), .is_end_of_stream = false, + .clear_buffers = false, }; xQueueSend(commands_, &args, portMAX_DELAY); xStreamBufferSend(source_, input.data(), input.size_bytes(), portMAX_DELAY); } -auto SampleConverter::endStream() -> void { +auto SampleProcessor::endStream(bool cancelled) -> void { Args args{ .track = nullptr, .samples_available = 0, .is_end_of_stream = true, + .clear_buffers = cancelled, }; xQueueSend(commands_, &args, portMAX_DELAY); } -auto SampleConverter::Main() -> void { +auto SampleProcessor::Main() -> void { for (;;) { Args args; while (!xQueueReceive(commands_, &args, portMAX_DELAY)) { @@ -109,43 +116,44 @@ auto SampleConverter::Main() -> void { handleContinueStream(args.samples_available); } if (args.is_end_of_stream) { - handleEndStream(); + handleEndStream(args.clear_buffers); } } } -auto SampleConverter::handleBeginStream(std::shared_ptr<TrackInfo> track) +auto SampleProcessor::handleBeginStream(std::shared_ptr<TrackInfo> track) -> void { if (track->format != source_format_) { - resampler_.reset(); source_format_ = track->format; + // The new stream has a different format to the previous stream (or there + // was no previous stream). + // First, clean up our filters. + resampler_.reset(); leftover_bytes_ = 0; - auto new_target = sink_->PrepareFormat(track->format); - if (new_target != target_format_) { - // The new format is different to the old one. Wait for the sink to - // drain before continuing. - while (!xStreamBufferIsEmpty(sink_->stream())) { - ESP_LOGI(kTag, "waiting for sink stream to drain..."); - // TODO(jacqueline): Get the sink drain ISR to notify us of this - // via semaphore instead of busy-ish waiting. - vTaskDelay(pdMS_TO_TICKS(10)); - } - - sink_->Configure(new_target); + // If the output is idle, then we can reconfigure it to the closest format + // to our new source. + // If the output *wasn't* idle, then we can't reconfigure without an + // audible gap in playback. So instead, we simply keep the same target + // format and begin resampling. + if (xStreamBufferIsEmpty(sink_)) { + target_format_ = output_->PrepareFormat(track->format); + output_->Configure(target_format_); } - target_format_ = new_target; } - samples_sunk_ = 0; + if (xStreamBufferIsEmpty(sink_)) { + samples_written_ = output_->samplesUsed(); + } + events::Audio().Dispatch(internal::StreamStarted{ .track = track, - .src_format = source_format_, - .dst_format = target_format_, + .sink_format = target_format_, + .cue_at_sample = samples_written_, }); } -auto SampleConverter::handleContinueStream(size_t samples_available) -> void { +auto SampleProcessor::handleContinueStream(size_t samples_available) -> void { // Loop until we finish reading all the bytes indicated. There might be // leftovers from each iteration, and from this process as a whole, // depending on the resampling stage. @@ -182,7 +190,7 @@ auto SampleConverter::handleContinueStream(size_t samples_available) -> void { } } -auto SampleConverter::handleSamples(cpp::span<sample::Sample> input) -> size_t { +auto SampleProcessor::handleSamples(std::span<sample::Sample> input) -> size_t { if (source_format_ == target_format_) { // The happiest possible case: the input format matches the output // format already. @@ -192,7 +200,7 @@ auto SampleConverter::handleSamples(cpp::span<sample::Sample> input) -> size_t { size_t samples_used = 0; while (samples_used < input.size()) { - cpp::span<sample::Sample> output_source; + std::span<sample::Sample> output_source; if (source_format_.sample_rate != target_format_.sample_rate) { if (resampler_ == nullptr) { ESP_LOGI(kTag, "creating new resampler for %lu -> %lu", @@ -223,8 +231,8 @@ auto SampleConverter::handleSamples(cpp::span<sample::Sample> input) -> size_t { return samples_used; } -auto SampleConverter::handleEndStream() -> void { - if (resampler_) { +auto SampleProcessor::handleEndStream(bool clear_bufs) -> void { + if (resampler_ && !clear_bufs) { size_t read, written; std::tie(read, written) = resampler_->Process({}, resampled_buffer_, true); @@ -233,33 +241,31 @@ auto SampleConverter::handleEndStream() -> void { } } - // Send a final update to finish off this stream's samples. - if (samples_sunk_ > 0) { - events::Audio().Dispatch(internal::StreamUpdate{ - .samples_sunk = samples_sunk_, - }); - samples_sunk_ = 0; + if (clear_bufs) { + assert(xStreamBufferReset(sink_)); + samples_written_ = output_->samplesUsed(); } + + // FIXME: This discards any leftover samples, but there probably shouldn't be + // any leftover samples. Can this be an assert instead? leftover_bytes_ = 0; - events::Audio().Dispatch(internal::StreamEnded{}); + events::Audio().Dispatch(internal::StreamEnded{ + .cue_at_sample = samples_written_, + }); } -auto SampleConverter::sendToSink(cpp::span<sample::Sample> samples) -> void { - // Update the number of samples sunk so far *before* actually sinking them, - // since writing to the stream buffer will block when the buffer gets full. - samples_sunk_ += samples.size(); - if (samples_sunk_ >= - target_format_.sample_rate * target_format_.num_channels) { - events::Audio().Dispatch(internal::StreamUpdate{ - .samples_sunk = samples_sunk_, - }); - samples_sunk_ = 0; - } +auto SampleProcessor::sendToSink(std::span<sample::Sample> samples) -> void { + auto data = std::as_bytes(samples); + xStreamBufferSend(sink_, data.data(), data.size(), portMAX_DELAY); - xStreamBufferSend(sink_->stream(), - reinterpret_cast<std::byte*>(samples.data()), - samples.size_bytes(), portMAX_DELAY); + uint32_t samples_before_overflow = + std::numeric_limits<uint32_t>::max() - samples_written_; + if (samples_before_overflow < samples.size()) { + samples_written_ = samples.size() - samples_before_overflow; + } else { + samples_written_ += samples.size(); + } } } // namespace audio diff --git a/src/audio/include/audio_converter.hpp b/src/tangara/audio/processor.hpp index 232b5d8e..1bd6beff 100644 --- a/src/audio/include/audio_converter.hpp +++ b/src/tangara/audio/processor.hpp @@ -10,11 +10,11 @@ #include <cstdint> #include <memory> -#include "audio_events.hpp" -#include "audio_sink.hpp" -#include "audio_source.hpp" +#include "audio/audio_events.hpp" +#include "audio/audio_sink.hpp" +#include "audio/audio_source.hpp" +#include "audio/resample.hpp" #include "codec.hpp" -#include "resample.hpp" #include "sample.hpp" namespace audio { @@ -25,49 +25,52 @@ namespace audio { * format of the current output device. The resulting samples are forwarded * to the output device's sink stream. */ -class SampleConverter { +class SampleProcessor { public: - SampleConverter(); - ~SampleConverter(); + SampleProcessor(StreamBufferHandle_t sink); + ~SampleProcessor(); auto SetOutput(std::shared_ptr<IAudioOutput>) -> void; auto beginStream(std::shared_ptr<TrackInfo>) -> void; - auto continueStream(cpp::span<sample::Sample>) -> void; - auto endStream() -> void; + auto continueStream(std::span<sample::Sample>) -> void; + auto endStream(bool cancelled) -> void; private: auto Main() -> void; auto handleBeginStream(std::shared_ptr<TrackInfo>) -> void; auto handleContinueStream(size_t samples_available) -> void; - auto handleEndStream() -> void; + auto handleEndStream(bool cancel) -> void; - auto handleSamples(cpp::span<sample::Sample>) -> size_t; + auto handleSamples(std::span<sample::Sample>) -> size_t; - auto sendToSink(cpp::span<sample::Sample>) -> void; + auto sendToSink(std::span<sample::Sample>) -> void; struct Args { std::shared_ptr<TrackInfo>* track; size_t samples_available; bool is_end_of_stream; + bool clear_buffers; }; QueueHandle_t commands_; std::unique_ptr<Resampler> resampler_; StreamBufferHandle_t source_; - cpp::span<sample::Sample> input_buffer_; - cpp::span<std::byte> input_buffer_as_bytes_; + StreamBufferHandle_t sink_; - cpp::span<sample::Sample> resampled_buffer_; + std::span<sample::Sample> input_buffer_; + std::span<std::byte> input_buffer_as_bytes_; - std::shared_ptr<IAudioOutput> sink_; + std::span<sample::Sample> resampled_buffer_; + + std::shared_ptr<IAudioOutput> output_; IAudioOutput::Format source_format_; IAudioOutput::Format target_format_; size_t leftover_bytes_; - uint32_t samples_sunk_; + uint32_t samples_written_; }; } // namespace audio diff --git a/src/audio/readahead_source.cpp b/src/tangara/audio/readahead_source.cpp index fe7ac3bd..602ec0b1 100644 --- a/src/audio/readahead_source.cpp +++ b/src/tangara/audio/readahead_source.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "readahead_source.hpp" +#include "audio/readahead_source.hpp" #include <cstddef> #include <cstdint> @@ -14,10 +14,10 @@ #include "esp_log.h" #include "ff.h" -#include "audio_source.hpp" +#include "audio/audio_source.hpp" #include "codec.hpp" +#include "drivers/spi.hpp" #include "freertos/portmacro.h" -#include "spi.hpp" #include "tasks.hpp" #include "types.hpp" @@ -41,7 +41,7 @@ ReadaheadSource::~ReadaheadSource() { vStreamBufferDeleteWithCaps(buffer_); } -auto ReadaheadSource::Read(cpp::span<std::byte> dest) -> ssize_t { +auto ReadaheadSource::Read(std::span<std::byte> dest) -> ssize_t { size_t bytes_written = 0; // Fill the destination from our buffer, until either the buffer is drained // or the destination is full. diff --git a/src/audio/include/readahead_source.hpp b/src/tangara/audio/readahead_source.hpp index 3e18a989..bbaf9f75 100644 --- a/src/audio/include/readahead_source.hpp +++ b/src/tangara/audio/readahead_source.hpp @@ -15,7 +15,7 @@ #include "ff.h" #include "freertos/stream_buffer.h" -#include "audio_source.hpp" +#include "audio/audio_source.hpp" #include "codec.hpp" #include "tasks.hpp" @@ -30,7 +30,7 @@ class ReadaheadSource : public codecs::IStream { ReadaheadSource(tasks::WorkerPool&, std::unique_ptr<codecs::IStream>); ~ReadaheadSource(); - auto Read(cpp::span<std::byte> dest) -> ssize_t override; + auto Read(std::span<std::byte> dest) -> ssize_t override; auto CanSeek() -> bool override; diff --git a/src/audio/resample.cpp b/src/tangara/audio/resample.cpp index a3a34ee7..143ce230 100644 --- a/src/audio/resample.cpp +++ b/src/tangara/audio/resample.cpp @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: GPL-3.0-only */ -#include "resample.hpp" +#include "audio/resample.hpp" #include <algorithm> #include <cmath> @@ -38,8 +38,8 @@ Resampler::~Resampler() { speex_resampler_destroy(resampler_); } -auto Resampler::Process(cpp::span<sample::Sample> input, - cpp::span<sample::Sample> output, +auto Resampler::Process(std::span<sample::Sample> input, + std::span<sample::Sample> output, bool end_of_data) -> std::pair<size_t, size_t> { uint32_t samples_used = input.size() / num_channels_; uint32_t samples_produced = output.size() / num_channels_; diff --git a/src/audio/include/resample.hpp b/src/tangara/audio/resample.hpp index a9464cb1..4d48d47f 100644 --- a/src/audio/include/resample.hpp +++ b/src/tangara/audio/resample.hpp @@ -7,9 +7,9 @@ #pragma once #include <cstdint> +#include <span> #include <vector> -#include "span.hpp" #include "speex/speex_resampler.h" #include "sample.hpp" @@ -24,8 +24,8 @@ class Resampler { ~Resampler(); - auto Process(cpp::span<sample::Sample> input, - cpp::span<sample::Sample> output, + auto Process(std::span<sample::Sample> input, + std::span<sample::Sample> output, bool end_of_data) -> std::pair<size_t, size_t>; private: @@ -34,4 +34,4 @@ class Resampler { uint8_t num_channels_; }; -} // namespace audio
\ No newline at end of file +} // namespace audio diff --git a/src/tangara/audio/stream_cues.cpp b/src/tangara/audio/stream_cues.cpp new file mode 100644 index 00000000..7a6a1426 --- /dev/null +++ b/src/tangara/audio/stream_cues.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2024 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "audio/stream_cues.hpp" + +#include <cstdint> +#include <memory> + +namespace audio { + +StreamCues::StreamCues() : now_(0) {} + +auto StreamCues::update(uint32_t sample) -> void { + if (sample < now_) { + // The current time must have overflowed. Deal with any cues between now_ + // and UINT32_MAX, then proceed as normal. + while (!upcoming_.empty() && upcoming_.front().start_at > now_) { + current_ = upcoming_.front(); + upcoming_.pop_front(); + } + } + now_ = sample; + + while (!upcoming_.empty() && upcoming_.front().start_at <= now_) { + current_ = upcoming_.front(); + upcoming_.pop_front(); + } +} + +auto StreamCues::addCue(std::shared_ptr<TrackInfo> track, uint32_t sample) + -> void { + if (sample == now_) { + current_ = {track, now_}; + } else { + upcoming_.push_back(Cue{ + .track = track, + .start_at = sample, + }); + } +} + +auto StreamCues::current() -> std::pair<std::shared_ptr<TrackInfo>, uint32_t> { + if (!current_) { + return {}; + } + + uint32_t duration; + if (now_ < current_->start_at) { + // now_ overflowed since this track started. + duration = now_ + (UINT32_MAX - current_->start_at); + } else { + duration = now_ - current_->start_at; + } + + return {current_->track, duration}; +} + +auto StreamCues::hasStream() -> bool { + return current_ || !upcoming_.empty(); +} + +} // namespace audio diff --git a/src/tangara/audio/stream_cues.hpp b/src/tangara/audio/stream_cues.hpp new file mode 100644 index 00000000..cd0782b0 --- /dev/null +++ b/src/tangara/audio/stream_cues.hpp @@ -0,0 +1,49 @@ +/* + * Copyright 2024 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include <stdint.h> +#include <cstdint> +#include <deque> +#include <memory> + +#include "audio/audio_events.hpp" + +namespace audio { + +/* + * Utility for tracking which track is currently being played (and how long it + * has been playing for) based on counting samples that are put into and taken + * out of the audio processor's output buffer. + */ +class StreamCues { + public: + StreamCues(); + + /* Updates the current track given the new most recently played sample. */ + auto update(uint32_t sample) -> void; + + /* Returns the current track, and how long it has been playing for. */ + auto current() -> std::pair<std::shared_ptr<TrackInfo>, uint32_t>; + + auto hasStream() -> bool; + + auto addCue(std::shared_ptr<TrackInfo>, uint32_t start_at) -> void; + + private: + uint32_t now_; + + struct Cue { + std::shared_ptr<TrackInfo> track; + uint32_t start_at; + }; + + std::optional<Cue> current_; + std::deque<Cue> upcoming_; +}; + +} // namespace audio diff --git a/src/audio/test/CMakeLists.txt b/src/tangara/audio/test/CMakeLists.txt index 4d580b1c..4d580b1c 100644 --- a/src/audio/test/CMakeLists.txt +++ b/src/tangara/audio/test/CMakeLists.txt diff --git a/src/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index dbe283c4..603b0de1 100644 --- a/src/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "track_queue.hpp" +#include "audio/track_queue.hpp" #include <stdint.h> #include <algorithm> @@ -18,16 +18,16 @@ #include "MillerShuffle.h" #include "esp_random.h" -#include "audio_events.hpp" -#include "audio_fsm.hpp" +#include "audio/audio_events.hpp" +#include "audio/audio_fsm.hpp" #include "cppbor.h" #include "cppbor_parse.h" -#include "database.hpp" -#include "event_queue.hpp" +#include "database/database.hpp" +#include "database/track.hpp" +#include "events/event_queue.hpp" #include "memory_resource.hpp" #include "tasks.hpp" -#include "track.hpp" -#include "ui_fsm.hpp" +#include "ui/ui_fsm.hpp" namespace audio { diff --git a/src/audio/include/track_queue.hpp b/src/tangara/audio/track_queue.hpp index 5b7c9448..427d5f75 100644 --- a/src/audio/include/track_queue.hpp +++ b/src/tangara/audio/track_queue.hpp @@ -12,11 +12,11 @@ #include <shared_mutex> #include <vector> -#include "audio_events.hpp" +#include "audio/audio_events.hpp" #include "cppbor_parse.h" -#include "database.hpp" +#include "database/database.hpp" +#include "database/track.hpp" #include "tasks.hpp" -#include "track.hpp" namespace audio { diff --git a/src/battery/battery.cpp b/src/tangara/battery/battery.cpp index debef9e6..2d2fff56 100644 --- a/src/battery/battery.cpp +++ b/src/tangara/battery/battery.cpp @@ -4,15 +4,15 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "battery.hpp" +#include "battery/battery.hpp" #include <cstdint> -#include "adc.hpp" -#include "event_queue.hpp" +#include "drivers/adc.hpp" +#include "drivers/samd.hpp" +#include "events/event_queue.hpp" #include "freertos/portmacro.h" -#include "samd.hpp" -#include "system_events.hpp" +#include "system_fsm/system_events.hpp" namespace battery { diff --git a/src/battery/include/battery.hpp b/src/tangara/battery/battery.hpp index 314cd373..80b0f2d2 100644 --- a/src/battery/include/battery.hpp +++ b/src/tangara/battery/battery.hpp @@ -11,8 +11,8 @@ #include "freertos/FreeRTOS.h" #include "freertos/timers.h" -#include "adc.hpp" -#include "samd.hpp" +#include "drivers/adc.hpp" +#include "drivers/samd.hpp" namespace battery { diff --git a/src/database/database.cpp b/src/tangara/database/database.cpp index 48fb0c63..4064c3ed 100644 --- a/src/database/database.cpp +++ b/src/tangara/database/database.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "database.hpp" +#include "database/database.hpp" #include <stdint.h> #include <sys/_stdint.h> @@ -23,10 +23,10 @@ #include "collation.hpp" #include "cppbor.h" #include "cppbor_parse.h" +#include "database/index.hpp" #include "esp_log.h" #include "ff.h" #include "freertos/projdefs.h" -#include "index.hpp" #include "komihash.h" #include "leveldb/cache.h" #include "leveldb/db.h" @@ -36,17 +36,17 @@ #include "leveldb/status.h" #include "leveldb/write_batch.h" -#include "db_events.hpp" -#include "env_esp.hpp" -#include "event_queue.hpp" -#include "file_gatherer.hpp" +#include "database/db_events.hpp" +#include "database/env_esp.hpp" +#include "database/file_gatherer.hpp" +#include "database/records.hpp" +#include "database/tag_parser.hpp" +#include "database/track.hpp" +#include "drivers/spi.hpp" +#include "events/event_queue.hpp" #include "memory_resource.hpp" -#include "records.hpp" #include "result.hpp" -#include "spi.hpp" -#include "tag_parser.hpp" #include "tasks.hpp" -#include "track.hpp" namespace database { @@ -63,8 +63,8 @@ static const char kKeyTrackId[] = "next_track_id"; static std::atomic<bool> sIsDbOpen(false); -static auto CreateNewDatabase(leveldb::Options& options, locale::ICollator& col) - -> leveldb::DB* { +static auto CreateNewDatabase(leveldb::Options& options, + locale::ICollator& col) -> leveldb::DB* { Database::Destroy(); leveldb::DB* db; options.create_if_missing = true; diff --git a/src/database/include/database.hpp b/src/tangara/database/database.hpp index 35b76a13..d2de7c72 100644 --- a/src/database/include/database.hpp +++ b/src/tangara/database/database.hpp @@ -19,19 +19,19 @@ #include "collation.hpp" #include "cppbor.h" -#include "file_gatherer.hpp" -#include "index.hpp" +#include "database/file_gatherer.hpp" +#include "database/index.hpp" +#include "database/records.hpp" +#include "database/tag_parser.hpp" +#include "database/track.hpp" #include "leveldb/cache.h" #include "leveldb/db.h" #include "leveldb/iterator.h" #include "leveldb/options.h" #include "leveldb/slice.h" #include "memory_resource.hpp" -#include "records.hpp" #include "result.hpp" -#include "tag_parser.hpp" #include "tasks.hpp" -#include "track.hpp" namespace database { diff --git a/src/database/include/db_events.hpp b/src/tangara/database/db_events.hpp index a1aefc27..a1aefc27 100644 --- a/src/database/include/db_events.hpp +++ b/src/tangara/database/db_events.hpp diff --git a/src/database/env_esp.cpp b/src/tangara/database/env_esp.cpp index f7a5637a..86a30613 100644 --- a/src/database/env_esp.cpp +++ b/src/tangara/database/env_esp.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "env_esp.hpp" +#include "database/env_esp.hpp" #include <atomic> #include <cerrno> @@ -36,12 +36,12 @@ #include "leveldb/slice.h" #include "leveldb/status.h" -#include "spi.hpp" +#include "drivers/spi.hpp" #include "tasks.hpp" namespace leveldb { -tasks::WorkerPool *sBackgroundThread = nullptr; +tasks::WorkerPool* sBackgroundThread = nullptr; std::string ErrToStr(FRESULT err) { switch (err) { diff --git a/src/database/include/env_esp.hpp b/src/tangara/database/env_esp.hpp index 472a72a6..472a72a6 100644 --- a/src/database/include/env_esp.hpp +++ b/src/tangara/database/env_esp.hpp diff --git a/src/database/file_gatherer.cpp b/src/tangara/database/file_gatherer.cpp index b7b7271e..75a1af27 100644 --- a/src/database/file_gatherer.cpp +++ b/src/tangara/database/file_gatherer.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "file_gatherer.hpp" +#include "database/file_gatherer.hpp" #include <deque> #include <functional> @@ -13,8 +13,8 @@ #include "ff.h" +#include "drivers/spi.hpp" #include "memory_resource.hpp" -#include "spi.hpp" namespace database { diff --git a/src/database/include/file_gatherer.hpp b/src/tangara/database/file_gatherer.hpp index 685bdb2c..38558b9e 100644 --- a/src/database/include/file_gatherer.hpp +++ b/src/tangara/database/file_gatherer.hpp @@ -17,20 +17,18 @@ namespace database { class IFileGatherer { public: - virtual ~IFileGatherer(){}; + virtual ~IFileGatherer() {}; virtual auto FindFiles( const std::string& root, - std::function<void(std::string_view, const FILINFO&)> cb) - -> void = 0; + std::function<void(std::string_view, const FILINFO&)> cb) -> void = 0; }; class FileGathererImpl : public IFileGatherer { public: - virtual auto FindFiles( - const std::string& root, - std::function<void(std::string_view, const FILINFO&)> cb) - -> void override; + virtual auto FindFiles(const std::string& root, + std::function<void(std::string_view, const FILINFO&)> + cb) -> void override; }; } // namespace database diff --git a/src/database/include/future_fetcher.hpp b/src/tangara/database/future_fetcher.hpp index e8ce9729..a27101f1 100644 --- a/src/database/include/future_fetcher.hpp +++ b/src/tangara/database/future_fetcher.hpp @@ -9,7 +9,7 @@ #include <memory> #include <utility> -#include "database.hpp" +#include "database/database.hpp" namespace database { diff --git a/src/database/index.cpp b/src/tangara/database/index.cpp index 857fbcc5..93a2b1c2 100644 --- a/src/database/index.cpp +++ b/src/tangara/database/index.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "index.hpp" +#include "database/index.hpp" #include <sys/_stdint.h> #include <cstdint> @@ -21,8 +21,8 @@ #include "komihash.h" #include "leveldb/write_batch.h" -#include "records.hpp" -#include "track.hpp" +#include "database/records.hpp" +#include "database/track.hpp" namespace database { @@ -61,11 +61,11 @@ class Indexer { private: auto handleLevel(const IndexKey::Header& header, - cpp::span<const Tag> components) -> void; + std::span<const Tag> components) -> void; auto handleItem(const IndexKey::Header& header, std::variant<std::pmr::string, uint32_t> item, - cpp::span<const Tag> components) -> void; + std::span<const Tag> components) -> void; auto missing_value(Tag tag) -> TagValue { switch (tag) { @@ -111,7 +111,7 @@ auto Indexer::index() -> std::vector<std::pair<IndexKey, std::string>> { } auto Indexer::handleLevel(const IndexKey::Header& header, - cpp::span<const Tag> components) -> void { + std::span<const Tag> components) -> void { Tag component = components.front(); TagValue value = track_.tags().get(component); if (std::holds_alternative<std::monostate>(value)) { @@ -129,7 +129,7 @@ auto Indexer::handleLevel(const IndexKey::Header& header, } else if constexpr (std::is_same_v<T, uint32_t>) { handleItem(header, arg, components); } else if constexpr (std::is_same_v< - T, cpp::span<const std::pmr::string>>) { + T, std::span<const std::pmr::string>>) { for (const auto& i : arg) { handleItem(header, i, components); } @@ -140,7 +140,7 @@ auto Indexer::handleLevel(const IndexKey::Header& header, auto Indexer::handleItem(const IndexKey::Header& header, std::variant<std::pmr::string, uint32_t> item, - cpp::span<const Tag> components) -> void { + std::span<const Tag> components) -> void { IndexKey key{ .header = header, .item = {}, @@ -183,8 +183,9 @@ auto Indexer::handleItem(const IndexKey::Header& header, } } -auto Index(locale::ICollator& c, const IndexInfo& i, const Track& t) - -> std::vector<std::pair<IndexKey, std::string>> { +auto Index(locale::ICollator& c, + const IndexInfo& i, + const Track& t) -> std::vector<std::pair<IndexKey, std::string>> { Indexer indexer{c, t, i}; return indexer.index(); } diff --git a/src/database/include/index.hpp b/src/tangara/database/index.hpp index 45dae464..8f78439b 100644 --- a/src/database/include/index.hpp +++ b/src/tangara/database/index.hpp @@ -17,9 +17,9 @@ #include "leveldb/db.h" #include "leveldb/slice.h" +#include "database/track.hpp" #include "leveldb/write_batch.h" #include "memory_resource.hpp" -#include "track.hpp" namespace database { @@ -61,8 +61,9 @@ struct IndexKey { std::optional<TrackId> track; }; -auto Index(locale::ICollator&, const IndexInfo&, const Track&) - -> std::vector<std::pair<IndexKey, std::string>>; +auto Index(locale::ICollator&, + const IndexInfo&, + const Track&) -> std::vector<std::pair<IndexKey, std::string>>; auto ExpandHeader(const IndexKey::Header&, const std::optional<std::pmr::string>&) -> IndexKey::Header; diff --git a/src/database/records.cpp b/src/tangara/database/records.cpp index a1efb568..88ddbd91 100644 --- a/src/database/records.cpp +++ b/src/tangara/database/records.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "records.hpp" +#include "database/records.hpp" #include <stdint.h> #include <sys/_stdint.h> @@ -21,10 +21,10 @@ #include "cppbor_parse.h" #include "esp_log.h" -#include "index.hpp" +#include "database/index.hpp" +#include "database/track.hpp" #include "komihash.h" #include "memory_resource.hpp" -#include "track.hpp" // As LevelDB is a key-value store, each record in the database consists of a // key and an optional value. @@ -248,7 +248,7 @@ auto TrackIdToBytes(TrackId id) -> std::string { return cppbor::Uint{id}.toString(); } -auto BytesToTrackId(cpp::span<const char> bytes) -> std::optional<TrackId> { +auto BytesToTrackId(std::span<const char> bytes) -> std::optional<TrackId> { auto [res, unused, err] = cppbor::parse( reinterpret_cast<const uint8_t*>(bytes.data()), bytes.size()); if (!res || res->type() != cppbor::UINT) { diff --git a/src/database/include/records.hpp b/src/tangara/database/records.hpp index 87034059..db18fe2f 100644 --- a/src/database/include/records.hpp +++ b/src/tangara/database/records.hpp @@ -15,9 +15,9 @@ #include "leveldb/db.h" #include "leveldb/slice.h" -#include "index.hpp" +#include "database/index.hpp" +#include "database/track.hpp" #include "memory_resource.hpp" -#include "track.hpp" namespace database { @@ -80,6 +80,6 @@ auto TrackIdToBytes(TrackId id) -> std::string; * Converts a track id encoded via TrackIdToBytes back into a TrackId. May * return nullopt if parsing fails. */ -auto BytesToTrackId(cpp::span<const char> bytes) -> std::optional<TrackId>; +auto BytesToTrackId(std::span<const char> bytes) -> std::optional<TrackId>; } // namespace database diff --git a/src/database/tag_parser.cpp b/src/tangara/database/tag_parser.cpp index cbcbdcb5..2df2d90f 100644 --- a/src/database/tag_parser.cpp +++ b/src/tangara/database/tag_parser.cpp @@ -4,16 +4,16 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "tag_parser.hpp" +#include "database/tag_parser.hpp" #include <cstdint> #include <cstdlib> #include <iomanip> #include <mutex> +#include "drivers/spi.hpp" #include "esp_log.h" #include "ff.h" -#include "spi.hpp" #include "tags.h" #include "memory_resource.hpp" diff --git a/src/database/include/tag_parser.hpp b/src/tangara/database/tag_parser.hpp index 966258b5..ccbc0ea9 100644 --- a/src/database/include/tag_parser.hpp +++ b/src/tangara/database/tag_parser.hpp @@ -8,8 +8,8 @@ #include <string> +#include "database/track.hpp" #include "lru_cache.hpp" -#include "track.hpp" namespace database { diff --git a/src/database/test/CMakeLists.txt b/src/tangara/database/test/CMakeLists.txt index a9f2cedb..a9f2cedb 100644 --- a/src/database/test/CMakeLists.txt +++ b/src/tangara/database/test/CMakeLists.txt diff --git a/src/database/test/test_database.cpp b/src/tangara/database/test/test_database.cpp index 6aec9bfb..09e19a43 100644 --- a/src/database/test/test_database.cpp +++ b/src/tangara/database/test/test_database.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "database.hpp" +#include "database/database.hpp" #include <stdint.h> #include <iomanip> @@ -13,14 +13,14 @@ #include <string> #include "catch2/catch.hpp" +#include "database/file_gatherer.hpp" +#include "database/tag_parser.hpp" +#include "database/track.hpp" #include "driver_cache.hpp" #include "esp_log.h" -#include "file_gatherer.hpp" #include "i2c_fixture.hpp" #include "leveldb/db.h" #include "spi_fixture.hpp" -#include "tag_parser.hpp" -#include "track.hpp" namespace database { @@ -28,8 +28,8 @@ class TestBackends : public IFileGatherer, public ITagParser { public: std::map<std::pmr::string, TrackTags> tracks; - auto MakeTrack(const std::pmr::string& path, const std::pmr::string& title) - -> void { + auto MakeTrack(const std::pmr::string& path, + const std::pmr::string& title) -> void { TrackTags tags; tags.encoding = Encoding::kMp3; tags.title = title; @@ -44,8 +44,8 @@ class TestBackends : public IFileGatherer, public ITagParser { } } - auto ReadAndParseTags(const std::pmr::string& path, TrackTags* out) - -> bool override { + auto ReadAndParseTags(const std::pmr::string& path, + TrackTags* out) -> bool override { if (tracks.contains(path)) { *out = tracks.at(path); return true; diff --git a/src/database/test/test_records.cpp b/src/tangara/database/test/test_records.cpp index 2f59489c..f8eb980f 100644 --- a/src/database/test/test_records.cpp +++ b/src/tangara/database/test/test_records.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "records.hpp" +#include "database/records.hpp" #include <stdint.h> #include <iomanip> diff --git a/src/database/track.cpp b/src/tangara/database/track.cpp index a2bd05d3..5bf8c3e2 100644 --- a/src/database/track.cpp +++ b/src/tangara/database/track.cpp @@ -4,11 +4,12 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "track.hpp" +#include "database/track.hpp" #include <iomanip> #include <iostream> #include <memory_resource> +#include <span> #include <sstream> #include <string> @@ -16,7 +17,6 @@ #include "komihash.h" #include "memory_resource.hpp" -#include "span.hpp" namespace database { @@ -55,7 +55,7 @@ auto tagHash(const TagValue& t) -> uint64_t { } else if constexpr (std::is_same_v<T, uint32_t>) { return komihash(&arg, sizeof(arg), 0); } else if constexpr (std::is_same_v< - T, cpp::span<const std::pmr::string>>) { + T, std::span<const std::pmr::string>>) { komihash_stream_t hash; komihash_stream_init(&hash, 0); for (const auto& i : arg) { @@ -79,7 +79,7 @@ auto tagToString(const TagValue& val) -> std::string { } else if constexpr (std::is_same_v<T, uint32_t>) { return std::to_string(arg); } else if constexpr (std::is_same_v< - T, cpp::span<const std::pmr::string>>) { + T, std::span<const std::pmr::string>>) { std::ostringstream builder{}; for (const auto& str : arg) { builder << std::string{str.data(), str.size()} << ","; @@ -225,7 +225,7 @@ auto TrackTags::albumOrder() const -> uint32_t { return (disc_.value_or(0) << 16) | track_.value_or(0); } -auto TrackTags::genres() const -> cpp::span<const std::pmr::string> { +auto TrackTags::genres() const -> std::span<const std::pmr::string> { return genres_; } diff --git a/src/database/include/track.hpp b/src/tangara/database/track.hpp index 76b1c56e..b097ab52 100644 --- a/src/database/include/track.hpp +++ b/src/tangara/database/track.hpp @@ -6,12 +6,12 @@ #pragma once -#include <stdint.h> -#include <sys/_stdint.h> +#include <cstdint> #include <map> #include <memory> #include <optional> +#include <span> #include <string> #include <unordered_map> #include <utility> @@ -19,7 +19,6 @@ #include "leveldb/db.h" #include "memory_resource.hpp" -#include "span.hpp" namespace database { @@ -62,7 +61,7 @@ enum class Tag { using TagValue = std::variant<std::monostate, std::pmr::string, uint32_t, - cpp::span<const std::pmr::string>>; + std::span<const std::pmr::string>>; auto tagName(Tag) -> std::string; auto tagHash(const TagValue&) -> uint64_t; @@ -112,7 +111,7 @@ class TrackTags { auto albumOrder() const -> uint32_t; - auto genres() const -> cpp::span<const std::pmr::string>; + auto genres() const -> std::span<const std::pmr::string>; auto genres(const std::string_view) -> void; /* diff --git a/src/dev_console/console.cpp b/src/tangara/dev_console/console.cpp index f2b1efea..cee68b49 100644 --- a/src/dev_console/console.cpp +++ b/src/tangara/dev_console/console.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "console.hpp" +#include "dev_console/console.hpp" #include <stdio.h> #include <string.h> diff --git a/src/dev_console/include/console.hpp b/src/tangara/dev_console/console.hpp index fedf3632..fedf3632 100644 --- a/src/dev_console/include/console.hpp +++ b/src/tangara/dev_console/console.hpp diff --git a/src/events/event_queue.cpp b/src/tangara/events/event_queue.cpp index d3a62ef6..e4751398 100644 --- a/src/events/event_queue.cpp +++ b/src/tangara/events/event_queue.cpp @@ -4,14 +4,15 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "event_queue.hpp" +#include "events/event_queue.hpp" -#include "audio_fsm.hpp" #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" #include "freertos/queue.h" -#include "system_fsm.hpp" -#include "ui_fsm.hpp" + +#include "audio/audio_fsm.hpp" +#include "system_fsm/system_fsm.hpp" +#include "ui/ui_fsm.hpp" namespace events { diff --git a/src/events/include/event_queue.hpp b/src/tangara/events/event_queue.hpp index 78b21d53..aa7f472d 100644 --- a/src/events/include/event_queue.hpp +++ b/src/tangara/events/event_queue.hpp @@ -11,14 +11,14 @@ #include <queue> #include <type_traits> -#include "audio_fsm.hpp" +#include "audio/audio_fsm.hpp" #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" #include "freertos/queue.h" -#include "system_fsm.hpp" +#include "system_fsm/system_fsm.hpp" #include "tinyfsm.hpp" -#include "ui_fsm.hpp" +#include "ui/ui_fsm.hpp" namespace events { diff --git a/src/input/device_factory.cpp b/src/tangara/input/device_factory.cpp index 65f4d785..8e1c5155 100644 --- a/src/input/device_factory.cpp +++ b/src/tangara/input/device_factory.cpp @@ -4,16 +4,16 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "device_factory.hpp" +#include "input/device_factory.hpp" #include <memory> -#include "feedback_haptics.hpp" -#include "input_device.hpp" -#include "input_nav_buttons.hpp" -#include "input_touch_dpad.hpp" -#include "input_touch_wheel.hpp" -#include "input_volume_buttons.hpp" +#include "input/feedback_haptics.hpp" +#include "input/input_device.hpp" +#include "input/input_nav_buttons.hpp" +#include "input/input_touch_dpad.hpp" +#include "input/input_touch_wheel.hpp" +#include "input/input_volume_buttons.hpp" namespace input { diff --git a/src/input/include/device_factory.hpp b/src/tangara/input/device_factory.hpp index dd9c7133..5044d025 100644 --- a/src/input/include/device_factory.hpp +++ b/src/tangara/input/device_factory.hpp @@ -9,11 +9,11 @@ #include <cstdint> #include <memory> -#include "feedback_device.hpp" -#include "input_device.hpp" -#include "input_touch_wheel.hpp" -#include "nvs.hpp" -#include "service_locator.hpp" +#include "input/feedback_device.hpp" +#include "input/input_device.hpp" +#include "input/input_touch_wheel.hpp" +#include "drivers/nvs.hpp" +#include "system_fsm/service_locator.hpp" namespace input { diff --git a/src/input/include/feedback_device.hpp b/src/tangara/input/feedback_device.hpp index 4faeeafd..4faeeafd 100644 --- a/src/input/include/feedback_device.hpp +++ b/src/tangara/input/feedback_device.hpp diff --git a/src/input/feedback_haptics.cpp b/src/tangara/input/feedback_haptics.cpp index 5e83d0d6..e690eb9f 100644 --- a/src/input/feedback_haptics.cpp +++ b/src/tangara/input/feedback_haptics.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "feedback_haptics.hpp" +#include "input/feedback_haptics.hpp" #include <cstdint> @@ -13,7 +13,7 @@ #include "core/lv_event.h" #include "esp_log.h" -#include "haptics.hpp" +#include "drivers/haptics.hpp" namespace input { diff --git a/src/input/include/feedback_haptics.hpp b/src/tangara/input/feedback_haptics.hpp index a307a429..bde5f345 100644 --- a/src/input/include/feedback_haptics.hpp +++ b/src/tangara/input/feedback_haptics.hpp @@ -8,8 +8,8 @@ #include <cstdint> -#include "feedback_device.hpp" -#include "haptics.hpp" +#include "drivers/haptics.hpp" +#include "input/feedback_device.hpp" namespace input { diff --git a/src/input/include/input_device.hpp b/src/tangara/input/input_device.hpp index 59456351..e3d17c6c 100644 --- a/src/input/include/input_device.hpp +++ b/src/tangara/input/input_device.hpp @@ -11,8 +11,8 @@ #include <vector> #include "hal/lv_hal_indev.h" -#include "input_hook.hpp" -#include "property.hpp" +#include "input/input_hook.hpp" +#include "lua/property.hpp" namespace input { @@ -29,7 +29,9 @@ class IInputDevice { virtual auto read(lv_indev_data_t* data) -> void = 0; virtual auto name() -> std::string = 0; - virtual auto hooks() -> std::vector<TriggerHooks> { return {}; } + virtual auto triggers() -> std::vector<std::reference_wrapper<TriggerHooks>> { + return {}; + } }; } // namespace input diff --git a/src/input/input_hook.cpp b/src/tangara/input/input_hook.cpp index 1bb92196..95ff8f2c 100644 --- a/src/input/input_hook.cpp +++ b/src/tangara/input/input_hook.cpp @@ -4,13 +4,15 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "input_hook.hpp" +#include "input/input_hook.hpp" #include <functional> #include <optional> + #include "hal/lv_hal_indev.h" -#include "input_trigger.hpp" -#include "lua.h" +#include "lua.hpp" + +#include "input/input_trigger.hpp" namespace input { @@ -39,10 +41,12 @@ auto Hook::callback() -> std::optional<HookCallback> { TriggerHooks::TriggerHooks(std::string name, std::optional<HookCallback> click, + std::optional<HookCallback> double_click, std::optional<HookCallback> long_press, std::optional<HookCallback> repeat) : name_(name), click_("click", click), + double_click_("double_click", double_click), long_press_("long_press", long_press), repeat_("repeat", repeat) {} @@ -51,6 +55,9 @@ auto TriggerHooks::update(bool pressed, lv_indev_data_t* d) -> void { case Trigger::State::kClick: click_.invoke(d); break; + case Trigger::State::kDoubleClick: + double_click_.invoke(d); + break; case Trigger::State::kLongPress: long_press_.invoke(d); break; @@ -85,23 +92,12 @@ auto TriggerHooks::name() const -> const std::string& { return name_; } -auto TriggerHooks::pushHooks(lua_State* L) -> void { - lua_newtable(L); - - auto add_trigger = [&](Hook& h) { - lua_pushlstring(L, h.name().data(), h.name().size()); - auto cb = h.callback(); - if (cb) { - lua_pushlstring(L, cb->name.data(), cb->name.size()); - } else { - lua_pushnil(L); - } - lua_rawset(L, -3); - }; - - add_trigger(click_); - add_trigger(long_press_); - add_trigger(repeat_); +auto TriggerHooks::hooks() -> std::vector<std::reference_wrapper<Hook>> { + return {click_, long_press_, repeat_}; +} + +auto TriggerHooks::cancel() -> void { + trigger_.cancel(); } } // namespace input diff --git a/src/input/include/input_hook.hpp b/src/tangara/input/input_hook.hpp index 81eb80d9..06fcb037 100644 --- a/src/input/include/input_hook.hpp +++ b/src/tangara/input/input_hook.hpp @@ -13,7 +13,7 @@ #include "hal/lv_hal_indev.h" #include "lua.hpp" -#include "input_trigger.hpp" +#include "input/input_trigger.hpp" namespace input { @@ -32,6 +32,10 @@ class Hook { auto name() const -> const std::string& { return name_; } auto callback() -> std::optional<HookCallback>; + // Not copyable or movable. + Hook(const Hook&) = delete; + Hook& operator=(const Hook&) = delete; + private: std::string name_; std::optional<HookCallback> default_; @@ -41,9 +45,10 @@ class Hook { class TriggerHooks { public: TriggerHooks(std::string name, std::optional<HookCallback> cb) - : TriggerHooks(name, cb, cb, cb) {} + : TriggerHooks(name, cb, cb, cb, cb) {} TriggerHooks(std::string name, std::optional<HookCallback> click, + std::optional<HookCallback> double_click, std::optional<HookCallback> long_press, std::optional<HookCallback> repeat); @@ -51,13 +56,20 @@ class TriggerHooks { auto override(Trigger::State, std::optional<HookCallback>) -> void; auto name() const -> const std::string&; - auto pushHooks(lua_State*) -> void; + auto hooks() -> std::vector<std::reference_wrapper<Hook>>; + + auto cancel() -> void; + + // Not copyable or movable. + TriggerHooks(const TriggerHooks&) = delete; + TriggerHooks& operator=(const TriggerHooks&) = delete; private: std::string name_; Trigger trigger_; Hook click_; + Hook double_click_; Hook long_press_; Hook repeat_; }; diff --git a/src/input/input_hook_actions.cpp b/src/tangara/input/input_hook_actions.cpp index 26075c4c..bc3760ac 100644 --- a/src/input/input_hook_actions.cpp +++ b/src/tangara/input/input_hook_actions.cpp @@ -4,14 +4,14 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "input_hook_actions.hpp" +#include "input/input_hook_actions.hpp" #include <cstdint> #include "hal/lv_hal_indev.h" -#include "event_queue.hpp" -#include "ui_events.hpp" +#include "events/event_queue.hpp" +#include "ui/ui_events.hpp" namespace input { namespace actions { diff --git a/src/input/include/input_hook_actions.hpp b/src/tangara/input/input_hook_actions.hpp index 105bd10d..71a560bc 100644 --- a/src/input/include/input_hook_actions.hpp +++ b/src/tangara/input/input_hook_actions.hpp @@ -7,7 +7,7 @@ #pragma once #include "hal/lv_hal_indev.h" -#include "input_hook.hpp" +#include "input/input_hook.hpp" namespace input { namespace actions { diff --git a/src/input/input_nav_buttons.cpp b/src/tangara/input/input_nav_buttons.cpp index 7e579a16..ba1f4b74 100644 --- a/src/input/input_nav_buttons.cpp +++ b/src/tangara/input/input_nav_buttons.cpp @@ -4,19 +4,19 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "input_nav_buttons.hpp" +#include "input/input_nav_buttons.hpp" -#include "event_queue.hpp" -#include "gpios.hpp" +#include "drivers/gpios.hpp" +#include "events/event_queue.hpp" #include "hal/lv_hal_indev.h" -#include "input_hook_actions.hpp" +#include "input/input_hook_actions.hpp" namespace input { NavButtons::NavButtons(drivers::IGpios& gpios) : gpios_(gpios), - up_("upper", actions::scrollUp(), actions::select(), {}), - down_("lower", actions::scrollDown(), actions::select(), {}) {} + up_("upper", {}, actions::scrollUp(), actions::select(), {}), + down_("lower", {}, actions::scrollDown(), actions::select(), {}) {} auto NavButtons::read(lv_indev_data_t* data) -> void { up_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyUp), data); @@ -27,7 +27,8 @@ auto NavButtons::name() -> std::string { return "buttons"; } -auto NavButtons::hooks() -> std::vector<TriggerHooks> { +auto NavButtons::triggers() + -> std::vector<std::reference_wrapper<TriggerHooks>> { return {up_, down_}; } diff --git a/src/input/include/input_nav_buttons.hpp b/src/tangara/input/input_nav_buttons.hpp index 4e4952c9..ce2312a0 100644 --- a/src/input/include/input_nav_buttons.hpp +++ b/src/tangara/input/input_nav_buttons.hpp @@ -8,14 +8,14 @@ #include <cstdint> -#include "gpios.hpp" +#include "drivers/gpios.hpp" #include "hal/lv_hal_indev.h" -#include "haptics.hpp" -#include "input_device.hpp" -#include "input_hook.hpp" -#include "input_trigger.hpp" -#include "touchwheel.hpp" +#include "drivers/haptics.hpp" +#include "input/input_device.hpp" +#include "input/input_hook.hpp" +#include "input/input_trigger.hpp" +#include "drivers/touchwheel.hpp" namespace input { @@ -26,7 +26,7 @@ class NavButtons : public IInputDevice { auto read(lv_indev_data_t* data) -> void override; auto name() -> std::string override; - auto hooks() -> std::vector<TriggerHooks> override; + auto triggers() -> std::vector<std::reference_wrapper<TriggerHooks>> override; private: drivers::IGpios& gpios_; diff --git a/src/input/input_touch_dpad.cpp b/src/tangara/input/input_touch_dpad.cpp index f0805993..5d8e2dab 100644 --- a/src/input/input_touch_dpad.cpp +++ b/src/tangara/input/input_touch_dpad.cpp @@ -4,28 +4,29 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "input_touch_dpad.hpp" +#include "input/input_touch_dpad.hpp" #include <cstdint> #include "hal/lv_hal_indev.h" -#include "event_queue.hpp" -#include "haptics.hpp" -#include "input_device.hpp" -#include "input_hook_actions.hpp" -#include "input_touch_dpad.hpp" -#include "touchwheel.hpp" +#include "drivers/haptics.hpp" +#include "drivers/touchwheel.hpp" + +#include "events/event_queue.hpp" +#include "input/input_device.hpp" +#include "input/input_hook_actions.hpp" +#include "input/input_touch_dpad.hpp" namespace input { TouchDPad::TouchDPad(drivers::TouchWheel& wheel) : wheel_(wheel), - centre_("centre", actions::select(), {}, {}), - up_("up", actions::scrollUp()), - right_("right", {}, {}, {}), - down_("down", actions::scrollDown()), - left_("left", actions::goBack()) {} + centre_("centre", actions::select(), {}, {}, {}), + up_("up", actions::scrollUp(), {}, {}, actions::scrollUp()), + right_("right", actions::select(), {}, {}, {}), + down_("down", actions::scrollDown(), {}, {}, actions::scrollDown()), + left_("left", actions::goBack(), {}, {}, {}) {} auto TouchDPad::read(lv_indev_data_t* data) -> void { wheel_.Update(); @@ -55,7 +56,8 @@ auto TouchDPad::name() -> std::string { return "dpad"; } -auto TouchDPad::hooks() -> std::vector<TriggerHooks> { +auto TouchDPad::triggers() + -> std::vector<std::reference_wrapper<TriggerHooks>> { return {centre_, up_, right_, down_, left_}; } diff --git a/src/input/include/input_touch_dpad.hpp b/src/tangara/input/input_touch_dpad.hpp index 691e3243..8fb14832 100644 --- a/src/input/include/input_touch_dpad.hpp +++ b/src/tangara/input/input_touch_dpad.hpp @@ -10,11 +10,11 @@ #include "hal/lv_hal_indev.h" -#include "haptics.hpp" -#include "input_device.hpp" -#include "input_hook.hpp" -#include "input_trigger.hpp" -#include "touchwheel.hpp" +#include "drivers/haptics.hpp" +#include "input/input_device.hpp" +#include "input/input_hook.hpp" +#include "input/input_trigger.hpp" +#include "drivers/touchwheel.hpp" namespace input { @@ -25,7 +25,7 @@ class TouchDPad : public IInputDevice { auto read(lv_indev_data_t* data) -> void override; auto name() -> std::string override; - auto hooks() -> std::vector<TriggerHooks> override; + auto triggers() -> std::vector<std::reference_wrapper<TriggerHooks>> override; private: drivers::TouchWheel& wheel_; diff --git a/src/input/input_touch_wheel.cpp b/src/tangara/input/input_touch_wheel.cpp index 121b1ee5..75159320 100644 --- a/src/input/input_touch_wheel.cpp +++ b/src/tangara/input/input_touch_wheel.cpp @@ -4,22 +4,22 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "input_touch_wheel.hpp" +#include "input/input_touch_wheel.hpp" #include <cstdint> #include <variant> #include "hal/lv_hal_indev.h" -#include "event_queue.hpp" -#include "haptics.hpp" -#include "input_device.hpp" -#include "input_hook_actions.hpp" -#include "input_trigger.hpp" -#include "nvs.hpp" -#include "property.hpp" -#include "touchwheel.hpp" -#include "ui_events.hpp" +#include "drivers/haptics.hpp" +#include "drivers/nvs.hpp" +#include "drivers/touchwheel.hpp" +#include "events/event_queue.hpp" +#include "input/input_device.hpp" +#include "input/input_hook_actions.hpp" +#include "input/input_trigger.hpp" +#include "lua/property.hpp" +#include "ui/ui_events.hpp" namespace input { @@ -39,11 +39,11 @@ TouchWheel::TouchWheel(drivers::NvsStorage& nvs, drivers::TouchWheel& wheel) threshold_ = calculateThreshold(int_val); return true; }), - centre_("centre", actions::select(), {}, {}), - up_("up", {}, actions::scrollToTop(), actions::scrollUp()), - right_("right", {}, {}, {}), - down_("down", {}, actions::scrollToBottom(), actions::scrollDown()), - left_("left", {}, actions::goBack(), {}), + centre_("centre", actions::select(), {}, {}, {}), + up_("up", {}, {}, actions::scrollToTop(), {}), + right_("right", {}), + down_("down", {}, {}, actions::scrollToBottom(), {}), + left_("left", {}, {}, actions::goBack(), {}), is_scrolling_(false), threshold_(calculateThreshold(nvs.ScrollSensitivity())), is_first_read_(true), @@ -68,31 +68,39 @@ auto TouchWheel::read(lv_indev_data_t* data) -> void { data->enc_diff = 0; } - centre_.update(!is_scrolling_ && wheel_data.is_button_touched, data); + centre_.update(wheel_data.is_button_touched && !wheel_data.is_wheel_touched, + data); // If the user is touching the wheel but not scrolling, then they may be // clicking on one of the wheel's cardinal directions. - bool pressing = wheel_data.is_wheel_touched && !is_scrolling_; - - up_.update(pressing && drivers::TouchWheel::isAngleWithin( - wheel_data.wheel_position, 0, 32), - data); - right_.update(pressing && drivers::TouchWheel::isAngleWithin( - wheel_data.wheel_position, 192, 32), - data); - down_.update(pressing && drivers::TouchWheel::isAngleWithin( - wheel_data.wheel_position, 128, 32), - data); - left_.update(pressing && drivers::TouchWheel::isAngleWithin( - wheel_data.wheel_position, 64, 32), + if (is_scrolling_) { + up_.cancel(); + right_.cancel(); + down_.cancel(); + left_.cancel(); + } else { + bool pressing = wheel_data.is_wheel_touched; + up_.update(pressing && drivers::TouchWheel::isAngleWithin( + wheel_data.wheel_position, 0, 32), data); + right_.update(pressing && drivers::TouchWheel::isAngleWithin( + wheel_data.wheel_position, 192, 32), + data); + down_.update(pressing && drivers::TouchWheel::isAngleWithin( + wheel_data.wheel_position, 128, 32), + data); + left_.update(pressing && drivers::TouchWheel::isAngleWithin( + wheel_data.wheel_position, 64, 32), + data); + } } auto TouchWheel::name() -> std::string { return "wheel"; } -auto TouchWheel::hooks() -> std::vector<TriggerHooks> { +auto TouchWheel::triggers() + -> std::vector<std::reference_wrapper<TriggerHooks>> { return {centre_, up_, right_, down_, left_}; } diff --git a/src/input/include/input_touch_wheel.hpp b/src/tangara/input/input_touch_wheel.hpp index 1f116da9..d023873a 100644 --- a/src/input/include/input_touch_wheel.hpp +++ b/src/tangara/input/input_touch_wheel.hpp @@ -11,13 +11,13 @@ #include "hal/lv_hal_indev.h" -#include "haptics.hpp" -#include "input_device.hpp" -#include "input_hook.hpp" -#include "input_trigger.hpp" -#include "nvs.hpp" -#include "property.hpp" -#include "touchwheel.hpp" +#include "drivers/haptics.hpp" +#include "input/input_device.hpp" +#include "input/input_hook.hpp" +#include "input/input_trigger.hpp" +#include "lua/property.hpp" +#include "drivers/nvs.hpp" +#include "drivers/touchwheel.hpp" namespace input { @@ -28,7 +28,7 @@ class TouchWheel : public IInputDevice { auto read(lv_indev_data_t* data) -> void override; auto name() -> std::string override; - auto hooks() -> std::vector<TriggerHooks> override; + auto triggers() -> std::vector<std::reference_wrapper<TriggerHooks>> override; auto sensitivity() -> lua::Property&; diff --git a/src/input/input_trigger.cpp b/src/tangara/input/input_trigger.cpp index 9485ecb4..eb67bcca 100644 --- a/src/input/input_trigger.cpp +++ b/src/tangara/input/input_trigger.cpp @@ -4,38 +4,54 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "input_trigger.hpp" -#include <sys/_stdint.h> +#include "input/input_trigger.hpp" #include <cstdint> -#include "esp_log.h" + #include "esp_timer.h" namespace input { -Trigger::Trigger() : touch_time_ms_(), times_fired_(0) {} +Trigger::Trigger() + : touch_time_ms_(), + was_pressed_(false), + was_double_click_(false), + times_long_pressed_(0) {} auto Trigger::update(bool is_pressed) -> State { // Bail out early if we're in a steady-state of not pressed. - if (!is_pressed && !touch_time_ms_) { + if (!is_pressed && !was_pressed_) { + was_double_click_ = false; + times_long_pressed_ = 0; return State::kNone; } uint64_t now_ms = esp_timer_get_time() / 1000; - // Initial press of this key: record the current time, and report that we - // haven't triggered yet. - if (is_pressed && !touch_time_ms_) { + // This key wasn't being pressed, but now it is. + if (is_pressed && !was_pressed_) { + // Is this a double click? + if (now_ms - *touch_time_ms_ < kDoubleClickDelayMs) { + // Don't update touch_time_ms_, since we don't want triple clicks to + // register as double clicks. + was_double_click_ = true; + was_pressed_ = true; + return State::kDoubleClick; + } + // Not a double click; update our accounting info and wait for the next + // call. touch_time_ms_ = now_ms; - times_fired_ = 0; + was_double_click_ = false; + times_long_pressed_ = 0; + was_pressed_ = true; return State::kNone; } // The key was released. If there were no long-press events fired during the // press, then this was a standard click. - if (!is_pressed && touch_time_ms_) { - touch_time_ms_.reset(); - if (times_fired_ == 0) { + if (!is_pressed && was_pressed_) { + was_pressed_ = false; + if (!was_double_click_ && times_long_pressed_ == 0) { return State::kClick; } else { return State::kNone; @@ -43,10 +59,10 @@ auto Trigger::update(bool is_pressed) -> State { } // Now the more complicated case: the user is continuing to press the button. - if (times_fired_ == 0) { + if (times_long_pressed_ == 0) { // We haven't fired yet, so we wait for the long-press event. if (now_ms - *touch_time_ms_ >= kLongPressDelayMs) { - times_fired_++; + times_long_pressed_++; return State::kLongPress; } } else { @@ -60,8 +76,8 @@ auto Trigger::update(bool is_pressed) -> State { // kRepeatDelayMs since the long-press event. uint16_t expected_times_fired = 1 + (time_since_long_press / kRepeatDelayMs); - if (times_fired_ < expected_times_fired) { - times_fired_++; + if (times_long_pressed_ < expected_times_fired) { + times_long_pressed_++; return State::kRepeatPress; } } @@ -69,4 +85,11 @@ auto Trigger::update(bool is_pressed) -> State { return State::kNone; } +auto Trigger::cancel() -> void { + touch_time_ms_.reset(); + was_pressed_ = false; + was_double_click_ = false; + times_long_pressed_ = 0; +} + } // namespace input diff --git a/src/input/include/input_trigger.hpp b/src/tangara/input/input_trigger.hpp index 599b796b..1b0e681d 100644 --- a/src/input/include/input_trigger.hpp +++ b/src/tangara/input/input_trigger.hpp @@ -13,6 +13,7 @@ namespace input { +const uint16_t kDoubleClickDelayMs = 500; const uint16_t kLongPressDelayMs = LV_INDEV_DEF_LONG_PRESS_TIME; const uint16_t kRepeatDelayMs = LV_INDEV_DEF_LONG_PRESS_REP_TIME; @@ -21,6 +22,7 @@ class Trigger { enum class State { kNone, kClick, + kDoubleClick, kLongPress, kRepeatPress, }; @@ -28,10 +30,14 @@ class Trigger { Trigger(); auto update(bool is_pressed) -> State; + auto cancel() -> void; private: std::optional<uint64_t> touch_time_ms_; - uint16_t times_fired_; + bool was_pressed_; + + bool was_double_click_; + uint16_t times_long_pressed_; }; } // namespace input diff --git a/src/input/input_volume_buttons.cpp b/src/tangara/input/input_volume_buttons.cpp index 607f81f1..3c3fb2a3 100644 --- a/src/input/input_volume_buttons.cpp +++ b/src/tangara/input/input_volume_buttons.cpp @@ -4,10 +4,10 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "input_volume_buttons.hpp" -#include "event_queue.hpp" -#include "gpios.hpp" -#include "input_hook_actions.hpp" +#include "input/input_volume_buttons.hpp" +#include "drivers/gpios.hpp" +#include "events/event_queue.hpp" +#include "input/input_hook_actions.hpp" namespace input { @@ -25,7 +25,8 @@ auto VolumeButtons::name() -> std::string { return "buttons"; } -auto VolumeButtons::hooks() -> std::vector<TriggerHooks> { +auto VolumeButtons::triggers() + -> std::vector<std::reference_wrapper<TriggerHooks>> { return {up_, down_}; } diff --git a/src/input/include/input_volume_buttons.hpp b/src/tangara/input/input_volume_buttons.hpp index a684aa48..22a8acf2 100644 --- a/src/input/include/input_volume_buttons.hpp +++ b/src/tangara/input/input_volume_buttons.hpp @@ -8,13 +8,13 @@ #include <cstdint> -#include "gpios.hpp" +#include "drivers/gpios.hpp" #include "hal/lv_hal_indev.h" -#include "haptics.hpp" -#include "input_device.hpp" -#include "input_hook.hpp" -#include "touchwheel.hpp" +#include "drivers/haptics.hpp" +#include "input/input_device.hpp" +#include "input/input_hook.hpp" +#include "drivers/touchwheel.hpp" namespace input { @@ -25,7 +25,7 @@ class VolumeButtons : public IInputDevice { auto read(lv_indev_data_t* data) -> void override; auto name() -> std::string override; - auto hooks() -> std::vector<TriggerHooks> override; + auto triggers() -> std::vector<std::reference_wrapper<TriggerHooks>> override; private: drivers::IGpios& gpios_; diff --git a/src/tangara/input/lvgl_input_driver.cpp b/src/tangara/input/lvgl_input_driver.cpp new file mode 100644 index 00000000..8d10bb13 --- /dev/null +++ b/src/tangara/input/lvgl_input_driver.cpp @@ -0,0 +1,258 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "input/lvgl_input_driver.hpp" + +#include <cstdint> +#include <memory> +#include <variant> + +#include "lua.hpp" +#include "lvgl.h" + +#include "drivers/nvs.hpp" + +#include "input/device_factory.hpp" +#include "input/feedback_haptics.hpp" +#include "input/input_hook.hpp" +#include "input/input_touch_wheel.hpp" +#include "input/input_trigger.hpp" +#include "input/input_volume_buttons.hpp" +#include "lua/lua_thread.hpp" +#include "lua/property.hpp" + +[[maybe_unused]] static constexpr char kTag[] = "input"; + +static constexpr char kLuaTriggerMetatableName[] = "input_trigger"; +static constexpr char kLuaOverrideText[] = "lua_callback"; + +namespace input { + +static void read_cb(lv_indev_drv_t* drv, lv_indev_data_t* data) { + LvglInputDriver* instance = + reinterpret_cast<LvglInputDriver*>(drv->user_data); + instance->read(data); +} + +static void feedback_cb(lv_indev_drv_t* drv, uint8_t event) { + LvglInputDriver* instance = + reinterpret_cast<LvglInputDriver*>(drv->user_data); + instance->feedback(event); +} + +auto intToMode(int raw) -> std::optional<drivers::NvsStorage::InputModes> { + switch (raw) { + case 0: + return drivers::NvsStorage::InputModes::kButtonsOnly; + case 1: + return drivers::NvsStorage::InputModes::kButtonsWithWheel; + case 2: + return drivers::NvsStorage::InputModes::kDirectionalWheel; + case 3: + return drivers::NvsStorage::InputModes::kRotatingWheel; + default: + return {}; + } +} + +LvglInputDriver::LvglInputDriver(drivers::NvsStorage& nvs, + DeviceFactory& factory) + : nvs_(nvs), + factory_(factory), + mode_(static_cast<int>(nvs.PrimaryInput()), + [&](const lua::LuaValue& val) { + if (!std::holds_alternative<int>(val)) { + return false; + } + auto mode = intToMode(std::get<int>(val)); + if (!mode) { + return false; + } + nvs.PrimaryInput(*mode); + inputs_ = factory.createInputs(*mode); + return true; + }), + driver_(), + registration_(nullptr), + inputs_(factory.createInputs(nvs.PrimaryInput())), + feedbacks_(factory.createFeedbacks()), + is_locked_(false) { + lv_indev_drv_init(&driver_); + driver_.type = LV_INDEV_TYPE_ENCODER; + driver_.read_cb = read_cb; + driver_.feedback_cb = feedback_cb; + driver_.user_data = this; + driver_.long_press_time = kLongPressDelayMs; + driver_.long_press_repeat_time = kRepeatDelayMs; + + registration_ = lv_indev_drv_register(&driver_); +} + +auto LvglInputDriver::read(lv_indev_data_t* data) -> void { + // TODO: we should pass lock state on to the individual devices, since they + // may wish to either ignore the lock state, or power down until unlock. + if (is_locked_) { + return; + } + for (auto&& device : inputs_) { + device->read(data); + } +} + +auto LvglInputDriver::feedback(uint8_t event) -> void { + if (is_locked_) { + return; + } + for (auto&& device : feedbacks_) { + device->feedback(event); + } +} + +LvglInputDriver::LuaTrigger::LuaTrigger(LvglInputDriver& driver, + IInputDevice& dev, + TriggerHooks& trigger) + : driver_(&driver), device_(dev.name()), trigger_(trigger.name()) { + for (auto& hook : trigger.hooks()) { + auto cb = hook.get().callback(); + if (cb) { + hooks_[hook.get().name()] = hook.get().callback()->name; + } else { + hooks_[hook.get().name()] = ""; + } + } +} + +auto LvglInputDriver::LuaTrigger::get(lua_State* L, int idx) -> LuaTrigger& { + return **reinterpret_cast<LuaTrigger**>( + luaL_checkudata(L, idx, kLuaTriggerMetatableName)); +} + +auto LvglInputDriver::LuaTrigger::luaGc(lua_State* L) -> int { + LuaTrigger& trigger = LuaTrigger::get(L, 1); + delete &trigger; + return 0; +} + +auto LvglInputDriver::LuaTrigger::luaToString(lua_State* L) -> int { + LuaTrigger& trigger = LuaTrigger::get(L, 1); + std::stringstream out; + out << "{ "; + for (const auto& hook : trigger.hooks_) { + if (!hook.second.empty()) { + out << hook.first << "=" << hook.second << " "; + } + } + out << "}"; + lua_pushlstring(L, out.str().data(), out.str().size()); + return 1; +} + +auto LvglInputDriver::LuaTrigger::luaNewIndex(lua_State* L) -> int { + LuaTrigger& trigger = LuaTrigger::get(L, 1); + luaL_checktype(L, 3, LUA_TFUNCTION); + + size_t len = 0; + const char* str = luaL_checklstring(L, 2, &len); + if (!str) { + return 0; + } + OverrideSelector selector{ + .device_name = trigger.device_, + .trigger_name = trigger.trigger_, + .hook_name = std::string{str, len}, + }; + for (const auto& hook : trigger.hooks_) { + if (hook.first == selector.hook_name) { + trigger.driver_->setOverride(L, selector); + trigger.hooks_[hook.first] = kLuaOverrideText; + return 0; + } + } + return 0; +} + +auto LvglInputDriver::pushHooks(lua_State* L) -> int { + if (luaL_getmetatable(L, kLuaTriggerMetatableName) == LUA_TNIL) { + luaL_newmetatable(L, kLuaTriggerMetatableName); + luaL_setfuncs(L, LuaTrigger::kFuncs, 0); + lua_pop(L, 1); + } + lua_pop(L, 1); + + lua_newtable(L); + + for (auto& dev : inputs_) { + lua_pushlstring(L, dev->name().data(), dev->name().size()); + lua_newtable(L); + + for (auto& trigger : dev->triggers()) { + lua_pushlstring(L, trigger.get().name().data(), + trigger.get().name().size()); + LuaTrigger** lua_obj = reinterpret_cast<LuaTrigger**>( + lua_newuserdatauv(L, sizeof(LuaTrigger*), 0)); + *lua_obj = new LuaTrigger(*this, *dev, trigger); + luaL_setmetatable(L, kLuaTriggerMetatableName); + lua_rawset(L, -3); + } + + lua_rawset(L, -3); + } + + return 1; +} + +auto LvglInputDriver::setOverride(lua_State* L, + const OverrideSelector& selector) -> void { + if (overrides_.contains(selector)) { + LuaOverride& prev = overrides_[selector]; + luaL_unref(prev.L, LUA_REGISTRYINDEX, prev.ref); + } + + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + LuaOverride override{ + .L = L, + .ref = ref, + }; + overrides_[selector] = override; + applyOverride(selector, override); +} + +auto LvglInputDriver::applyOverride(const OverrideSelector& selector, + LuaOverride& override) -> void { + // In general, this algorithm is a very slow approach. We could do better + // by maintaing maps from [device|trigger|hook]_name to the relevant + // trigger, but in practice I expect maybe like 5 overrides total ever, + // spread across 2 devices with 2 or 5 hooks each. So it's not that big a + // deal. Don't worry about it!! + + // Look for a matching device. + for (auto& device : inputs_) { + if (device->name() != selector.device_name) { + continue; + } + // Look for a matching trigger + for (auto& trigger : device->triggers()) { + if (trigger.get().name() != selector.trigger_name) { + continue; + } + // Look for a matching hook + for (auto& hook : trigger.get().hooks()) { + if (hook.get().name() != selector.hook_name) { + continue; + } + // We found the target! Apply the override. + auto lua_callback = [=](lv_indev_data_t* d) { + lua_rawgeti(override.L, LUA_REGISTRYINDEX, override.ref); + lua::CallProtected(override.L, 0, 0); + }; + hook.get().override( + HookCallback{.name = kLuaOverrideText, .fn = lua_callback}); + } + } + } +} + +} // namespace input diff --git a/src/tangara/input/lvgl_input_driver.hpp b/src/tangara/input/lvgl_input_driver.hpp new file mode 100644 index 00000000..8ede1855 --- /dev/null +++ b/src/tangara/input/lvgl_input_driver.hpp @@ -0,0 +1,112 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include <cstdint> +#include <deque> +#include <memory> +#include <set> + +#include "core/lv_group.h" +#include "drivers/gpios.hpp" +#include "hal/lv_hal_indev.h" +#include "input/device_factory.hpp" +#include "input/feedback_device.hpp" + +#include "input/input_device.hpp" +#include "input/input_hook.hpp" +#include "lua/lua_thread.hpp" +#include "lua/property.hpp" +#include "drivers/nvs.hpp" +#include "drivers/touchwheel.hpp" + +namespace input { + +/* + * Implementation of an LVGL input device. This class composes multiple + * IInputDevice and IFeedbackDevice instances together into a single LVGL + * device. + */ +class LvglInputDriver { + public: + LvglInputDriver(drivers::NvsStorage& nvs, DeviceFactory&); + + auto mode() -> lua::Property& { return mode_; } + + auto read(lv_indev_data_t* data) -> void; + auto feedback(uint8_t) -> void; + + auto registration() -> lv_indev_t* { return registration_; } + auto lock(bool l) -> void { is_locked_ = l; } + + auto pushHooks(lua_State* L) -> int; + + private: + drivers::NvsStorage& nvs_; + DeviceFactory& factory_; + + lua::Property mode_; + lv_indev_drv_t driver_; + lv_indev_t* registration_; + + std::vector<std::shared_ptr<IInputDevice>> inputs_; + std::vector<std::shared_ptr<IFeedbackDevice>> feedbacks_; + + /* + * Key for identifying which device, trigger, and specific hook are being + * overriden by Lua. + */ + struct OverrideSelector { + std::string device_name; + std::string trigger_name; + std::string hook_name; + + friend bool operator<(const OverrideSelector& l, + const OverrideSelector& r) { + return std::tie(l.device_name, l.trigger_name, l.hook_name) < + std::tie(r.device_name, r.trigger_name, r.hook_name); + } + }; + + /* Userdata object for tracking the Lua mirror of a TriggerHooks object. */ + class LuaTrigger { + public: + LuaTrigger(LvglInputDriver&, IInputDevice&, TriggerHooks&); + + static auto get(lua_State*, int idx) -> LuaTrigger&; + static auto luaGc(lua_State*) -> int; + static auto luaToString(lua_State*) -> int; + static auto luaNewIndex(lua_State*) -> int; + + static constexpr struct luaL_Reg kFuncs[] = {{"__gc", luaGc}, + {"__tostring", luaToString}, + {"__newindex", luaNewIndex}, + {NULL, NULL}}; + + private: + LvglInputDriver* driver_; + + std::string device_; + std::string trigger_; + std::map<std::string, std::string> hooks_; + }; + + /* A hook override implemented as a lua callback */ + struct LuaOverride { + lua_State* L; + int ref; + }; + + std::map<OverrideSelector, LuaOverride> overrides_; + + auto setOverride(lua_State* L, const OverrideSelector&) -> void; + auto applyOverride(const OverrideSelector&, LuaOverride&) -> void; + + bool is_locked_; +}; + +} // namespace input diff --git a/src/lua/bridge.cpp b/src/tangara/lua/bridge.cpp index a84eb0c1..07c299a7 100644 --- a/src/lua/bridge.cpp +++ b/src/tangara/lua/bridge.cpp @@ -4,34 +4,33 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "bridge.hpp" -#include <sys/_stdint.h> +#include "lua/bridge.hpp" +#include <cstdint> #include <memory> #include <string> -#include "database.hpp" +#include "database/database.hpp" +#include "database/index.hpp" #include "esp_log.h" -#include "index.hpp" #include "lauxlib.h" #include "lua.h" #include "lua.hpp" -#include "lua_controls.hpp" -#include "lua_database.hpp" -#include "lua_filesystem.hpp" -#include "lua_queue.hpp" -#include "lua_screen.hpp" -#include "lua_version.hpp" -#include "lua_theme.hpp" +#include "lua/lua_controls.hpp" +#include "lua/lua_database.hpp" +#include "lua/lua_queue.hpp" +#include "lua/lua_screen.hpp" +#include "lua/lua_theme.hpp" +#include "lua/lua_version.hpp" #include "lvgl.h" #include "font/lv_font_loader.h" #include "luavgl.h" -#include "event_queue.hpp" -#include "property.hpp" -#include "service_locator.hpp" -#include "ui_events.hpp" +#include "events/event_queue.hpp" +#include "lua/property.hpp" +#include "system_fsm/service_locator.hpp" +#include "ui/ui_events.hpp" extern "C" { int luaopen_linenoise(lua_State* L); @@ -47,8 +46,9 @@ namespace lua { static constexpr char kBridgeKey[] = "bridge"; -static auto make_font_cb(const char* name, int size, int weight) - -> const lv_font_t* { +static auto make_font_cb(const char* name, + int size, + int weight) -> const lv_font_t* { if (std::string{"fusion"} == name) { if (size == 12) { return &font_fusion_12; @@ -85,7 +85,6 @@ auto Bridge::installBaseModules(lua_State* L) -> void { RegisterControlsModule(L); RegisterDatabaseModule(L); - RegisterFileSystemModule(L); RegisterQueueModule(L); RegisterVersionModule(L); RegisterThemeModule(L); diff --git a/src/lua/include/bridge.hpp b/src/tangara/lua/bridge.hpp index 64f14e0e..b4cfe503 100644 --- a/src/lua/include/bridge.hpp +++ b/src/tangara/lua/bridge.hpp @@ -10,9 +10,9 @@ #include <string> #include "lua.hpp" +#include "lua/property.hpp" #include "lvgl.h" -#include "property.hpp" -#include "service_locator.hpp" +#include "system_fsm/service_locator.hpp" namespace lua { @@ -39,9 +39,8 @@ class Bridge { auto installPropertyModule( lua_State* L, const std::string&, - std::vector< - std::pair<std::string, std::variant<LuaFunction, Property*>>>&) - -> void; + std::vector<std::pair<std::string, + std::variant<LuaFunction, Property*>>>&) -> void; Bridge(const Bridge&) = delete; Bridge& operator=(const Bridge&) = delete; diff --git a/src/lua/file_iterator.cpp b/src/tangara/lua/file_iterator.cpp index 194859a6..194859a6 100644 --- a/src/lua/file_iterator.cpp +++ b/src/tangara/lua/file_iterator.cpp diff --git a/src/lua/include/file_iterator.hpp b/src/tangara/lua/file_iterator.hpp index 82d6f397..82d6f397 100644 --- a/src/lua/include/file_iterator.hpp +++ b/src/tangara/lua/file_iterator.hpp diff --git a/src/lua/lua_controls.cpp b/src/tangara/lua/lua_controls.cpp index 2da0ed11..baf40891 100644 --- a/src/lua/lua_controls.cpp +++ b/src/tangara/lua/lua_controls.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "lua_controls.hpp" +#include "lua/lua_controls.hpp" #include <memory> #include <string> @@ -16,8 +16,8 @@ #include "lua.h" #include "lvgl.h" -#include "nvs.hpp" -#include "ui_events.hpp" +#include "drivers/nvs.hpp" +#include "ui/ui_events.hpp" namespace lua { diff --git a/src/lua/include/lua_controls.hpp b/src/tangara/lua/lua_controls.hpp index 18ad261d..18ad261d 100644 --- a/src/lua/include/lua_controls.hpp +++ b/src/tangara/lua/lua_controls.hpp diff --git a/src/lua/lua_database.cpp b/src/tangara/lua/lua_database.cpp index d0612fdd..1afb01f0 100644 --- a/src/lua/lua_database.cpp +++ b/src/tangara/lua/lua_database.cpp @@ -4,30 +4,30 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "lua_database.hpp" +#include "lua/lua_database.hpp" #include <memory> #include <string> #include <type_traits> #include <variant> -#include "bridge.hpp" #include "lua.hpp" +#include "lua/bridge.hpp" #include "esp_log.h" #include "lauxlib.h" #include "lua.h" -#include "lua_thread.hpp" +#include "lua/lua_thread.hpp" #include "lvgl.h" -#include "database.hpp" -#include "event_queue.hpp" -#include "index.hpp" -#include "property.hpp" -#include "records.hpp" -#include "service_locator.hpp" -#include "track.hpp" -#include "ui_events.hpp" +#include "database/database.hpp" +#include "database/index.hpp" +#include "database/records.hpp" +#include "database/track.hpp" +#include "events/event_queue.hpp" +#include "lua/property.hpp" +#include "system_fsm/service_locator.hpp" +#include "ui/ui_events.hpp" namespace lua { @@ -152,8 +152,8 @@ auto db_check_iterator(lua_State* L, int stack_pos) -> database::Iterator* { return it; } -static auto push_iterator(lua_State* state, const database::Iterator& it) - -> void { +static auto push_iterator(lua_State* state, + const database::Iterator& it) -> void { database::Iterator** data = reinterpret_cast<database::Iterator**>( lua_newuserdata(state, sizeof(uintptr_t))); *data = new database::Iterator(it); @@ -198,12 +198,10 @@ static auto db_iterator_gc(lua_State* state) -> int { return 0; } -static const struct luaL_Reg kDbIteratorFuncs[] = {{"next", db_iterate}, - {"prev", db_iterate_prev}, - {"clone", db_iterator_clone}, - {"__call", db_iterate}, - {"__gc", db_iterator_gc}, - {NULL, NULL}}; +static const struct luaL_Reg kDbIteratorFuncs[] = { + {"next", db_iterate}, {"prev", db_iterate_prev}, + {"clone", db_iterator_clone}, {"__call", db_iterate}, + {"__gc", db_iterator_gc}, {NULL, NULL}}; static auto record_text(lua_State* state) -> int { LuaRecord* data = reinterpret_cast<LuaRecord*>( diff --git a/src/lua/include/lua_database.hpp b/src/tangara/lua/lua_database.hpp index b0d2acbd..328004ef 100644 --- a/src/lua/include/lua_database.hpp +++ b/src/tangara/lua/lua_database.hpp @@ -8,7 +8,7 @@ #include "lua.hpp" -#include "database.hpp" +#include "database/database.hpp" namespace lua { diff --git a/src/lua/lua_filesystem.cpp b/src/tangara/lua/lua_filesystem.cpp index f0dbaf9a..f0dbaf9a 100644 --- a/src/lua/lua_filesystem.cpp +++ b/src/tangara/lua/lua_filesystem.cpp diff --git a/src/lua/include/lua_filesystem.hpp b/src/tangara/lua/lua_filesystem.hpp index 2a829405..2a829405 100644 --- a/src/lua/include/lua_filesystem.hpp +++ b/src/tangara/lua/lua_filesystem.hpp diff --git a/src/lua/lua_queue.cpp b/src/tangara/lua/lua_queue.cpp index dfb820c2..bc393aa5 100644 --- a/src/lua/lua_queue.cpp +++ b/src/tangara/lua/lua_queue.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "lua_database.hpp" +#include "lua/lua_database.hpp" #include <memory> #include <string> @@ -16,15 +16,15 @@ #include "lua.h" #include "lvgl.h" -#include "bridge.hpp" -#include "database.hpp" -#include "event_queue.hpp" -#include "index.hpp" -#include "property.hpp" -#include "service_locator.hpp" -#include "track.hpp" -#include "track_queue.hpp" -#include "ui_events.hpp" +#include "audio/track_queue.hpp" +#include "database/database.hpp" +#include "database/index.hpp" +#include "database/track.hpp" +#include "events/event_queue.hpp" +#include "lua/bridge.hpp" +#include "lua/property.hpp" +#include "system_fsm/service_locator.hpp" +#include "ui/ui_events.hpp" namespace lua { diff --git a/src/lua/include/lua_queue.hpp b/src/tangara/lua/lua_queue.hpp index c5cfe04d..c5cfe04d 100644 --- a/src/lua/include/lua_queue.hpp +++ b/src/tangara/lua/lua_queue.hpp diff --git a/src/lua/include/lua_registry.hpp b/src/tangara/lua/lua_registry.hpp index abc5063e..e556b6eb 100644 --- a/src/lua/include/lua_registry.hpp +++ b/src/tangara/lua/lua_registry.hpp @@ -11,9 +11,9 @@ #include "lua.hpp" -#include "bridge.hpp" -#include "lua_thread.hpp" -#include "service_locator.hpp" +#include "lua/bridge.hpp" +#include "lua/lua_thread.hpp" +#include "system_fsm/service_locator.hpp" namespace lua { diff --git a/src/lua/lua_screen.cpp b/src/tangara/lua/lua_screen.cpp index f17f6b1a..8d87eebd 100644 --- a/src/lua/lua_screen.cpp +++ b/src/tangara/lua/lua_screen.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "lua_screen.hpp" +#include "lua/lua_screen.hpp" #include <memory> #include <string> @@ -16,15 +16,15 @@ #include "lua.h" #include "lvgl.h" -#include "bridge.hpp" -#include "database.hpp" -#include "event_queue.hpp" -#include "index.hpp" -#include "property.hpp" -#include "service_locator.hpp" -#include "track.hpp" -#include "track_queue.hpp" -#include "ui_events.hpp" +#include "audio/track_queue.hpp" +#include "database/database.hpp" +#include "database/index.hpp" +#include "database/track.hpp" +#include "events/event_queue.hpp" +#include "lua/bridge.hpp" +#include "lua/property.hpp" +#include "system_fsm/service_locator.hpp" +#include "ui/ui_events.hpp" namespace lua { diff --git a/src/lua/include/lua_screen.hpp b/src/tangara/lua/lua_screen.hpp index 1c3bed1a..1c3bed1a 100644 --- a/src/lua/include/lua_screen.hpp +++ b/src/tangara/lua/lua_screen.hpp diff --git a/src/lua/lua_theme.cpp b/src/tangara/lua/lua_theme.cpp index 72434d97..5edde104 100644 --- a/src/lua/lua_theme.cpp +++ b/src/tangara/lua/lua_theme.cpp @@ -5,20 +5,20 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "lua_version.hpp" +#include "lua/lua_version.hpp" #include <string> -#include "bridge.hpp" #include "lua.hpp" +#include "lua/bridge.hpp" #include "esp_app_desc.h" #include "esp_log.h" #include "lauxlib.h" #include "lua.h" -#include "lua_thread.hpp" +#include "lua/lua_thread.hpp" #include "luavgl.h" -#include "themes.hpp" +#include "ui/themes.hpp" namespace lua { @@ -35,7 +35,7 @@ static auto set_style(lua_State* L) -> int { static auto set_theme(lua_State* L) -> int { std::string class_name; luaL_checktype(L, -1, LUA_TTABLE); - lua_pushnil(L); /* first key */ + lua_pushnil(L); /* first key */ while (lua_next(L, -2) != 0) { /* uses 'key' (at index -2) and 'value' (at index -1) */ if (lua_type(L, -2) == LUA_TSTRING) { @@ -43,11 +43,11 @@ static auto set_theme(lua_State* L) -> int { } if (lua_type(L, -1) == LUA_TTABLE) { // Nesting - lua_pushnil(L); // First key + lua_pushnil(L); // First key while (lua_next(L, -2) != 0) { // Nesting the second int selector = -1; - lua_pushnil(L); // First key + lua_pushnil(L); // First key while (lua_next(L, -2) != 0) { int idx = lua_tointeger(L, -2); if (idx == 1) { @@ -60,12 +60,13 @@ static auto set_theme(lua_State* L) -> int { ESP_LOGI("lua_theme", "Style was null or malformed"); return 0; } else { - ui::themes::Theme::instance()->AddStyle(class_name, selector, style); + ui::themes::Theme::instance()->AddStyle(class_name, selector, + style); } } - lua_pop(L, 1); + lua_pop(L, 1); } - lua_pop(L, 1); + lua_pop(L, 1); } } /* removes 'value'; keeps 'key' for next iteration */ @@ -74,7 +75,9 @@ static auto set_theme(lua_State* L) -> int { return 0; } -static const struct luaL_Reg kThemeFuncs[] = {{"set", set_theme}, {"set_style", set_style}, {NULL, NULL}}; +static const struct luaL_Reg kThemeFuncs[] = {{"set", set_theme}, + {"set_style", set_style}, + {NULL, NULL}}; static auto lua_theme(lua_State* L) -> int { luaL_newlib(L, kThemeFuncs); diff --git a/src/lua/include/lua_theme.hpp b/src/tangara/lua/lua_theme.hpp index fed710e0..fed710e0 100644 --- a/src/lua/include/lua_theme.hpp +++ b/src/tangara/lua/lua_theme.hpp diff --git a/src/lua/lua_thread.cpp b/src/tangara/lua/lua_thread.cpp index dd72e41d..77a46b45 100644 --- a/src/lua/lua_thread.cpp +++ b/src/tangara/lua/lua_thread.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "lua_thread.hpp" +#include "lua/lua_thread.hpp" #include <iostream> #include <memory> @@ -13,11 +13,11 @@ #include "esp_log.h" #include "lua.hpp" -#include "bridge.hpp" -#include "event_queue.hpp" +#include "events/event_queue.hpp" +#include "lua/bridge.hpp" #include "memory_resource.hpp" -#include "service_locator.hpp" -#include "ui_events.hpp" +#include "system_fsm/service_locator.hpp" +#include "ui/ui_events.hpp" namespace lua { @@ -42,8 +42,10 @@ class Allocator { size_t total_allocated_; }; -static auto lua_alloc(void* ud, void* ptr, size_t osize, size_t nsize) - -> void* { +static auto lua_alloc(void* ud, + void* ptr, + size_t osize, + size_t nsize) -> void* { Allocator* instance = reinterpret_cast<Allocator*>(ud); return instance->alloc(ptr, osize, nsize); } diff --git a/src/lua/include/lua_thread.hpp b/src/tangara/lua/lua_thread.hpp index 384de61d..d7602c1e 100644 --- a/src/lua/include/lua_thread.hpp +++ b/src/tangara/lua/lua_thread.hpp @@ -11,7 +11,7 @@ #include "lua.hpp" -#include "service_locator.hpp" +#include "system_fsm/service_locator.hpp" namespace lua { diff --git a/src/lua/lua_version.cpp b/src/tangara/lua/lua_version.cpp index e5f06bb5..b85a30a5 100644 --- a/src/lua/lua_version.cpp +++ b/src/tangara/lua/lua_version.cpp @@ -5,18 +5,18 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "lua_version.hpp" +#include "lua/lua_version.hpp" #include <string> -#include "bridge.hpp" #include "lua.hpp" +#include "lua/bridge.hpp" #include "esp_app_desc.h" #include "esp_log.h" #include "lauxlib.h" #include "lua.h" -#include "lua_thread.hpp" +#include "lua/lua_thread.hpp" namespace lua { diff --git a/src/lua/include/lua_version.hpp b/src/tangara/lua/lua_version.hpp index 4ba4be94..4ba4be94 100644 --- a/src/lua/include/lua_version.hpp +++ b/src/tangara/lua/lua_version.hpp diff --git a/src/lua/property.cpp b/src/tangara/lua/property.cpp index 634a6a26..2b93809d 100644 --- a/src/lua/property.cpp +++ b/src/tangara/lua/property.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "property.hpp" +#include "lua/property.hpp" #include <sys/_stdint.h> #include <cmath> @@ -14,15 +14,15 @@ #include <string> #include <variant> -#include "bluetooth_types.hpp" +#include "database/track.hpp" +#include "drivers/bluetooth_types.hpp" #include "lauxlib.h" #include "lua.h" #include "lua.hpp" -#include "lua_thread.hpp" +#include "lua/lua_thread.hpp" #include "lvgl.h" #include "memory_resource.hpp" -#include "service_locator.hpp" -#include "track.hpp" +#include "system_fsm/service_locator.hpp" #include "types.hpp" namespace lua { @@ -247,7 +247,7 @@ static auto pushTagValue(lua_State* L, const database::TagValue& val) -> void { if constexpr (std::is_same_v<T, std::pmr::string>) { lua_pushlstring(L, arg.data(), arg.size()); } else if constexpr (std::is_same_v< - T, cpp::span<const std::pmr::string>>) { + T, std::span<const std::pmr::string>>) { lua_createtable(L, 0, arg.size()); for (const auto& i : arg) { lua_pushlstring(L, i.data(), i.size()); diff --git a/src/lua/include/property.hpp b/src/tangara/lua/property.hpp index 724261be..9f925766 100644 --- a/src/lua/include/property.hpp +++ b/src/tangara/lua/property.hpp @@ -10,11 +10,11 @@ #include <memory> #include <string> -#include "audio_events.hpp" -#include "bluetooth_types.hpp" +#include "audio/audio_events.hpp" +#include "drivers/bluetooth_types.hpp" #include "lua.hpp" #include "lvgl.h" -#include "service_locator.hpp" +#include "system_fsm/service_locator.hpp" namespace lua { diff --git a/src/lua/registry.cpp b/src/tangara/lua/registry.cpp index a6487858..d33594a3 100644 --- a/src/lua/registry.cpp +++ b/src/tangara/lua/registry.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "lua_registry.hpp" +#include "lua/lua_registry.hpp" #include <iostream> #include <memory> @@ -13,11 +13,11 @@ #include "esp_log.h" #include "lua.hpp" -#include "bridge.hpp" -#include "event_queue.hpp" +#include "events/event_queue.hpp" +#include "lua/bridge.hpp" #include "memory_resource.hpp" -#include "service_locator.hpp" -#include "ui_events.hpp" +#include "system_fsm/service_locator.hpp" +#include "ui/ui_events.hpp" namespace lua { diff --git a/src/system_fsm/booting.cpp b/src/tangara/system_fsm/booting.cpp index 44700cc4..58f14706 100644 --- a/src/system_fsm/booting.cpp +++ b/src/tangara/system_fsm/booting.cpp @@ -5,9 +5,9 @@ */ #include "collation.hpp" -#include "haptics.hpp" -#include "spiffs.hpp" -#include "system_fsm.hpp" +#include "drivers/haptics.hpp" +#include "drivers/spiffs.hpp" +#include "system_fsm/system_fsm.hpp" #include <stdint.h> #include <memory> @@ -20,25 +20,25 @@ #include "freertos/projdefs.h" #include "freertos/timers.h" -#include "adc.hpp" -#include "audio_fsm.hpp" -#include "battery.hpp" -#include "bluetooth.hpp" -#include "bluetooth_types.hpp" -#include "display_init.hpp" -#include "event_queue.hpp" -#include "gpios.hpp" -#include "i2c.hpp" -#include "nvs.hpp" -#include "samd.hpp" -#include "service_locator.hpp" -#include "spi.hpp" -#include "system_events.hpp" -#include "tag_parser.hpp" +#include "audio/audio_fsm.hpp" +#include "audio/track_queue.hpp" +#include "battery/battery.hpp" +#include "database/tag_parser.hpp" +#include "drivers/adc.hpp" +#include "drivers/bluetooth.hpp" +#include "drivers/bluetooth_types.hpp" +#include "drivers/display_init.hpp" +#include "drivers/gpios.hpp" +#include "drivers/i2c.hpp" +#include "drivers/nvs.hpp" +#include "drivers/samd.hpp" +#include "drivers/spi.hpp" +#include "drivers/touchwheel.hpp" +#include "events/event_queue.hpp" +#include "system_fsm/service_locator.hpp" +#include "system_fsm/system_events.hpp" #include "tasks.hpp" -#include "touchwheel.hpp" -#include "track_queue.hpp" -#include "ui_fsm.hpp" +#include "ui/ui_fsm.hpp" namespace system_fsm { namespace states { diff --git a/src/system_fsm/idle.cpp b/src/tangara/system_fsm/idle.cpp index e28864b3..e499693d 100644 --- a/src/system_fsm/idle.cpp +++ b/src/tangara/system_fsm/idle.cpp @@ -4,20 +4,20 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "app_console.hpp" -#include "file_gatherer.hpp" +#include "app_console/app_console.hpp" +#include "database/file_gatherer.hpp" +#include "drivers/gpios.hpp" #include "freertos/portmacro.h" #include "freertos/projdefs.h" -#include "gpios.hpp" #include "result.hpp" -#include "audio_fsm.hpp" -#include "event_queue.hpp" -#include "samd.hpp" -#include "storage.hpp" -#include "system_events.hpp" -#include "system_fsm.hpp" -#include "ui_fsm.hpp" +#include "audio/audio_fsm.hpp" +#include "drivers/samd.hpp" +#include "drivers/storage.hpp" +#include "events/event_queue.hpp" +#include "system_fsm/system_events.hpp" +#include "system_fsm/system_fsm.hpp" +#include "ui/ui_fsm.hpp" namespace system_fsm { namespace states { diff --git a/src/system_fsm/running.cpp b/src/tangara/system_fsm/running.cpp index 796c96dc..ac36ec64 100644 --- a/src/system_fsm/running.cpp +++ b/src/tangara/system_fsm/running.cpp @@ -4,23 +4,24 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "app_console.hpp" -#include "audio_events.hpp" -#include "database.hpp" -#include "db_events.hpp" +#include "app_console/app_console.hpp" +#include "audio/audio_events.hpp" +#include "database/database.hpp" +#include "database/db_events.hpp" +#include "database/file_gatherer.hpp" +#include "drivers/gpios.hpp" +#include "drivers/spi.hpp" #include "ff.h" -#include "file_gatherer.hpp" #include "freertos/portmacro.h" #include "freertos/projdefs.h" -#include "gpios.hpp" #include "result.hpp" -#include "audio_fsm.hpp" -#include "event_queue.hpp" -#include "storage.hpp" -#include "system_events.hpp" -#include "system_fsm.hpp" -#include "ui_fsm.hpp" +#include "audio/audio_fsm.hpp" +#include "drivers/storage.hpp" +#include "events/event_queue.hpp" +#include "system_fsm/system_events.hpp" +#include "system_fsm/system_fsm.hpp" +#include "ui/ui_fsm.hpp" namespace system_fsm { namespace states { @@ -42,11 +43,7 @@ void Running::entry() { sUnmountTimer = xTimerCreate("unmount_timeout", kTicksBeforeUnmount, false, NULL, timer_callback); } - // Only mount our storage immediately if we know it's not currently in use - // by the SAMD. - if (!sServices->samd().UsbMassStorage()) { - mountStorage(); - } + mountStorage(); } void Running::exit() { @@ -80,10 +77,28 @@ void Running::react(const SdDetectChanged& ev) { if (ev.has_sd_card && !sStorage) { mountStorage(); } + // Don't automatically unmount, since this event seems to occasionally happen // supriously. FIXME: Why? - // (It doesn't matter too much; by the time we get this event the SD card has - // already been disconnected electrically.) + // Instead, check whether or not the card has actually gone away. + if (sStorage) { + FRESULT res; + FF_DIR dir; + { + auto lock = drivers::acquire_spi(); + res = f_opendir(&dir, "/"); + } + + if (res != FR_OK) { + ESP_LOGW(kTag, "sd card ejected unsafely!"); + unmountStorage(); + } + + { + auto lock = drivers::acquire_spi(); + f_closedir(&dir); + } + } } void Running::react(const SamdUsbMscChanged& ev) { @@ -134,25 +149,37 @@ auto Running::checkIdle() -> void { } } -auto Running::mountStorage() -> bool { +auto Running::updateSdState(drivers::SdState state) -> void { + sServices->sd(state); + events::Ui().Dispatch(SdStateChanged{}); + events::Audio().Dispatch(SdStateChanged{}); + events::System().Dispatch(SdStateChanged{}); +} + +auto Running::mountStorage() -> void { + // Only mount our storage if we know it's not currently in use by the SAMD. + if (sServices->samd().UsbMassStorage()) { + updateSdState(drivers::SdState::kNotMounted); + return; + } + ESP_LOGI(kTag, "mounting sd card"); auto storage_res = drivers::SdStorage::Create(sServices->gpios()); if (storage_res.has_error()) { ESP_LOGW(kTag, "failed to mount!"); switch (storage_res.error()) { case drivers::SdStorage::FAILED_TO_MOUNT: - sServices->sd(drivers::SdState::kNotFormatted); + updateSdState(drivers::SdState::kNotFormatted); break; case drivers::SdStorage::FAILED_TO_READ: default: - sServices->sd(drivers::SdState::kNotPresent); + updateSdState(drivers::SdState::kNotPresent); break; } - return false; + return; } sStorage.reset(storage_res.value()); - sServices->sd(drivers::SdState::kMounted); ESP_LOGI(kTag, "opening database"); sFileGatherer = new database::FileGathererImpl(); @@ -161,16 +188,14 @@ auto Running::mountStorage() -> bool { sServices->collator(), sServices->bg_worker()); if (database_res.has_error()) { unmountStorage(); - return false; + return; } sServices->database( std::unique_ptr<database::Database>{database_res.value()}); ESP_LOGI(kTag, "storage loaded okay"); - events::Ui().Dispatch(StorageMounted{}); - events::Audio().Dispatch(StorageMounted{}); - events::System().Dispatch(StorageMounted{}); + updateSdState(drivers::SdState::kMounted); // Tell the database to refresh so that we pick up any changes from the newly // mounted card. @@ -183,14 +208,13 @@ auto Running::mountStorage() -> bool { db->updateIndexes(); }); } - - return true; } auto Running::unmountStorage() -> void { ESP_LOGW(kTag, "unmounting storage"); sServices->database({}); sStorage.reset(); + updateSdState(drivers::SdState::kNotMounted); } } // namespace states diff --git a/src/system_fsm/service_locator.cpp b/src/tangara/system_fsm/service_locator.cpp index d8dcf44a..ef719930 100644 --- a/src/system_fsm/service_locator.cpp +++ b/src/tangara/system_fsm/service_locator.cpp @@ -4,13 +4,13 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "service_locator.hpp" +#include "system_fsm/service_locator.hpp" #include <memory> -#include "nvs.hpp" -#include "storage.hpp" -#include "touchwheel.hpp" +#include "drivers/nvs.hpp" +#include "drivers/storage.hpp" +#include "drivers/touchwheel.hpp" namespace system_fsm { diff --git a/src/system_fsm/include/service_locator.hpp b/src/tangara/system_fsm/service_locator.hpp index 5978578c..5b2205eb 100644 --- a/src/system_fsm/include/service_locator.hpp +++ b/src/tangara/system_fsm/service_locator.hpp @@ -8,19 +8,19 @@ #include <memory> -#include "battery.hpp" -#include "bluetooth.hpp" +#include "audio/track_queue.hpp" +#include "battery/battery.hpp" +#include "drivers/bluetooth.hpp" #include "collation.hpp" -#include "database.hpp" -#include "gpios.hpp" -#include "haptics.hpp" -#include "nvs.hpp" -#include "samd.hpp" -#include "storage.hpp" -#include "tag_parser.hpp" +#include "database/database.hpp" +#include "database/tag_parser.hpp" +#include "drivers/gpios.hpp" +#include "drivers/haptics.hpp" +#include "drivers/nvs.hpp" +#include "drivers/samd.hpp" +#include "drivers/storage.hpp" #include "tasks.hpp" -#include "touchwheel.hpp" -#include "track_queue.hpp" +#include "drivers/touchwheel.hpp" namespace system_fsm { diff --git a/src/system_fsm/include/system_events.hpp b/src/tangara/system_fsm/system_events.hpp index 22e3b6bd..3452e58e 100644 --- a/src/system_fsm/include/system_events.hpp +++ b/src/tangara/system_fsm/system_events.hpp @@ -8,13 +8,14 @@ #include <memory> -#include "battery.hpp" -#include "bluetooth_types.hpp" -#include "database.hpp" +#include "battery/battery.hpp" +#include "database/database.hpp" +#include "drivers/bluetooth_types.hpp" +#include "drivers/haptics.hpp" +#include "drivers/samd.hpp" +#include "drivers/storage.hpp" #include "ff.h" -#include "haptics.hpp" -#include "samd.hpp" -#include "service_locator.hpp" +#include "system_fsm/service_locator.hpp" #include "tinyfsm.hpp" namespace system_fsm { @@ -38,10 +39,7 @@ struct FatalError : tinyfsm::Event {}; struct OnIdle : tinyfsm::Event {}; -/* - * Sent by SysState when the system storage has been successfully mounted. - */ -struct StorageMounted : tinyfsm::Event {}; +struct SdStateChanged : tinyfsm::Event {}; struct StorageError : tinyfsm::Event { FRESULT error; diff --git a/src/system_fsm/system_fsm.cpp b/src/tangara/system_fsm/system_fsm.cpp index 59d41c73..2e819569 100644 --- a/src/system_fsm/system_fsm.cpp +++ b/src/tangara/system_fsm/system_fsm.cpp @@ -4,15 +4,15 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "system_fsm.hpp" -#include "audio_fsm.hpp" +#include "system_fsm/system_fsm.hpp" +#include "audio/audio_fsm.hpp" +#include "audio/track_queue.hpp" +#include "database/tag_parser.hpp" #include "driver/gpio.h" -#include "event_queue.hpp" -#include "gpios.hpp" -#include "service_locator.hpp" -#include "system_events.hpp" -#include "tag_parser.hpp" -#include "track_queue.hpp" +#include "drivers/gpios.hpp" +#include "events/event_queue.hpp" +#include "system_fsm/service_locator.hpp" +#include "system_fsm/system_events.hpp" [[maybe_unused]] static const char kTag[] = "system"; diff --git a/src/system_fsm/include/system_fsm.hpp b/src/tangara/system_fsm/system_fsm.hpp index f01afb3f..5c4157cd 100644 --- a/src/system_fsm/include/system_fsm.hpp +++ b/src/tangara/system_fsm/system_fsm.hpp @@ -8,27 +8,26 @@ #include <memory> -#include "app_console.hpp" -#include "audio_events.hpp" -#include "battery.hpp" -#include "bluetooth.hpp" -#include "database.hpp" -#include "db_events.hpp" -#include "display.hpp" -#include "gpios.hpp" -#include "nvs.hpp" -#include "samd.hpp" -#include "service_locator.hpp" -#include "storage.hpp" -#include "tag_parser.hpp" -#include "tinyfsm.hpp" -#include "touchwheel.hpp" - #include "freertos/FreeRTOS.h" #include "freertos/timers.h" -#include "system_events.hpp" -#include "track_queue.hpp" +#include "app_console/app_console.hpp" +#include "audio/audio_events.hpp" +#include "audio/track_queue.hpp" +#include "battery/battery.hpp" +#include "database/database.hpp" +#include "database/db_events.hpp" +#include "database/tag_parser.hpp" +#include "drivers/bluetooth.hpp" +#include "drivers/display.hpp" +#include "drivers/gpios.hpp" +#include "drivers/nvs.hpp" +#include "drivers/samd.hpp" +#include "drivers/storage.hpp" +#include "drivers/touchwheel.hpp" +#include "system_fsm/service_locator.hpp" +#include "system_fsm/system_events.hpp" +#include "tinyfsm.hpp" namespace system_fsm { @@ -56,7 +55,6 @@ class SystemState : public tinyfsm::Fsm<SystemState> { virtual void react(const DisplayReady&) {} virtual void react(const BootComplete&) {} - virtual void react(const StorageMounted&) {} virtual void react(const StorageError&) {} virtual void react(const KeyLockChanged&) {} virtual void react(const SdDetectChanged&) {} @@ -111,7 +109,8 @@ class Running : public SystemState { private: auto checkIdle() -> void; - auto mountStorage() -> bool; + auto updateSdState(drivers::SdState) -> void; + auto mountStorage() -> void; auto unmountStorage() -> void; bool storage_mounted_; diff --git a/src/ui/include/fonts.hpp b/src/tangara/ui/fonts.hpp index e4a8e139..e4a8e139 100644 --- a/src/ui/include/fonts.hpp +++ b/src/tangara/ui/fonts.hpp diff --git a/src/ui/lvgl_task.cpp b/src/tangara/ui/lvgl_task.cpp index 51da0179..448aa261 100644 --- a/src/ui/lvgl_task.cpp +++ b/src/tangara/ui/lvgl_task.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "lvgl_task.hpp" +#include "ui/lvgl_task.hpp" #include <dirent.h> #include <stdint.h> @@ -20,8 +20,9 @@ #include "core/lv_obj.h" #include "core/lv_obj_pos.h" #include "core/lv_obj_tree.h" +#include "drivers/touchwheel.hpp" #include "esp_log.h" -#include "event_queue.hpp" +#include "events/event_queue.hpp" #include "extra/themes/basic/lv_theme_basic.h" #include "font/lv_font.h" #include "freertos/portmacro.h" @@ -30,21 +31,20 @@ #include "hal/gpio_types.h" #include "hal/lv_hal_indev.h" #include "hal/spi_types.h" +#include "input/lvgl_input_driver.hpp" #include "lua.h" #include "lv_api_map.h" #include "lvgl/lvgl.h" -#include "lvgl_input_driver.hpp" #include "misc/lv_color.h" #include "misc/lv_style.h" #include "misc/lv_timer.h" -#include "modal.hpp" #include "tasks.hpp" -#include "touchwheel.hpp" -#include "ui_fsm.hpp" +#include "ui/modal.hpp" +#include "ui/ui_fsm.hpp" #include "widgets/lv_label.h" -#include "display.hpp" -#include "gpios.hpp" +#include "drivers/display.hpp" +#include "drivers/gpios.hpp" namespace ui { diff --git a/src/ui/include/lvgl_task.hpp b/src/tangara/ui/lvgl_task.hpp index 8efcbf35..fcf00ab1 100644 --- a/src/ui/include/lvgl_task.hpp +++ b/src/tangara/ui/lvgl_task.hpp @@ -14,11 +14,11 @@ #include "freertos/task.h" #include "freertos/timers.h" -#include "display.hpp" -#include "lvgl_input_driver.hpp" -#include "screen.hpp" -#include "themes.hpp" -#include "touchwheel.hpp" +#include "drivers/display.hpp" +#include "input/lvgl_input_driver.hpp" +#include "drivers/touchwheel.hpp" +#include "ui/screen.hpp" +#include "ui/themes.hpp" namespace ui { diff --git a/src/ui/modal.cpp b/src/tangara/ui/modal.cpp index ec541914..4f5a2432 100644 --- a/src/ui/modal.cpp +++ b/src/tangara/ui/modal.cpp @@ -5,7 +5,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "modal.hpp" +#include "ui/modal.hpp" #include "misc/lv_color.h" @@ -14,17 +14,17 @@ #include "core/lv_group.h" #include "core/lv_obj_pos.h" -#include "event_queue.hpp" +#include "database/index.hpp" +#include "events/event_queue.hpp" #include "extra/widgets/list/lv_list.h" #include "extra/widgets/menu/lv_menu.h" #include "extra/widgets/spinner/lv_spinner.h" #include "hal/lv_hal_disp.h" -#include "index.hpp" #include "misc/lv_area.h" -#include "screen.hpp" -#include "themes.hpp" -#include "ui_events.hpp" -#include "ui_fsm.hpp" +#include "ui/screen.hpp" +#include "ui/themes.hpp" +#include "ui/ui_events.hpp" +#include "ui/ui_fsm.hpp" #include "widgets/lv_label.h" namespace ui { diff --git a/src/ui/include/modal.hpp b/src/tangara/ui/modal.hpp index 6b7e792e..bd5209a7 100644 --- a/src/ui/include/modal.hpp +++ b/src/tangara/ui/modal.hpp @@ -13,7 +13,7 @@ #include "core/lv_obj_tree.h" #include "lvgl.h" -#include "screen.hpp" +#include "ui/screen.hpp" namespace ui { diff --git a/src/ui/screen.cpp b/src/tangara/ui/screen.cpp index a39aaf7e..8357cfbd 100644 --- a/src/ui/screen.cpp +++ b/src/tangara/ui/screen.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "screen.hpp" +#include "ui/screen.hpp" #include <memory> diff --git a/src/ui/include/screen.hpp b/src/tangara/ui/screen.hpp index 40284fda..40284fda 100644 --- a/src/ui/include/screen.hpp +++ b/src/tangara/ui/screen.hpp diff --git a/src/ui/screen_lua.cpp b/src/tangara/ui/screen_lua.cpp index 685e43cb..c6cda7ae 100644 --- a/src/ui/screen_lua.cpp +++ b/src/tangara/ui/screen_lua.cpp @@ -4,15 +4,15 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "screen_lua.hpp" +#include "ui/screen_lua.hpp" #include "core/lv_obj_tree.h" #include "lua.h" #include "lua.hpp" -#include "property.hpp" -#include "themes.hpp" +#include "lua/property.hpp" +#include "ui/themes.hpp" -#include "lua_thread.hpp" +#include "lua/lua_thread.hpp" #include "luavgl.h" namespace ui { diff --git a/src/ui/include/screen_lua.hpp b/src/tangara/ui/screen_lua.hpp index 8a463bad..d6bc20a2 100644 --- a/src/ui/include/screen_lua.hpp +++ b/src/tangara/ui/screen_lua.hpp @@ -8,8 +8,8 @@ #include "lua.hpp" -#include "property.hpp" -#include "screen.hpp" +#include "lua/property.hpp" +#include "ui/screen.hpp" namespace ui { namespace screens { diff --git a/src/ui/screen_splash.cpp b/src/tangara/ui/screen_splash.cpp index 48cfef88..651f00dd 100644 --- a/src/ui/screen_splash.cpp +++ b/src/tangara/ui/screen_splash.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "screen_splash.hpp" +#include "ui/screen_splash.hpp" #include "core/lv_obj.h" #include "core/lv_obj_style.h" diff --git a/src/ui/include/screen_splash.hpp b/src/tangara/ui/screen_splash.hpp index 6e746345..e56c915f 100644 --- a/src/ui/include/screen_splash.hpp +++ b/src/tangara/ui/screen_splash.hpp @@ -10,7 +10,7 @@ #include "lvgl.h" -#include "screen.hpp" +#include "ui/screen.hpp" namespace ui { namespace screens { diff --git a/src/ui/themes.cpp b/src/tangara/ui/themes.cpp index b13f226a..44638c55 100644 --- a/src/ui/themes.cpp +++ b/src/tangara/ui/themes.cpp @@ -1,4 +1,4 @@ -#include "themes.hpp" +#include "ui/themes.hpp" #include "core/lv_obj.h" #include "core/lv_obj_style.h" #include "core/lv_obj_tree.h" @@ -35,9 +35,9 @@ void Theme::Apply(void) { void Theme::Callback(lv_obj_t* obj) { // Find and apply base styles if (auto search = style_map.find("base"); search != style_map.end()) { - for (const auto& pair : search->second) { - lv_obj_add_style(obj, pair.second, pair.first); - } + for (const auto& pair : search->second) { + lv_obj_add_style(obj, pair.second, pair.first); + } } // Determine class name @@ -60,19 +60,18 @@ void Theme::Callback(lv_obj_t* obj) { // Apply all styles from class if (auto search = style_map.find(class_name); search != style_map.end()) { - for (const auto& pair : search->second) { - lv_obj_add_style(obj, pair.second, pair.first); - } + for (const auto& pair : search->second) { + lv_obj_add_style(obj, pair.second, pair.first); + } } - } void Theme::ApplyStyle(lv_obj_t* obj, std::string style_key) { if (auto search = style_map.find(style_key); search != style_map.end()) { - for (const auto& pair : search->second) { - lv_obj_remove_style(obj, pair.second, pair.first); - lv_obj_add_style(obj, pair.second, pair.first); - } + for (const auto& pair : search->second) { + lv_obj_remove_style(obj, pair.second, pair.first); + lv_obj_add_style(obj, pair.second, pair.first); + } } } @@ -85,7 +84,7 @@ void Theme::AddStyle(std::string key, int selector, lv_style_t* style) { style_map.try_emplace(key, std::vector<std::pair<int, lv_style_t*>>{}); if (auto search = style_map.find(key); search != style_map.end()) { // Key exists - auto &vec = search->second; + auto& vec = search->second; // Add it to the list vec.push_back(std::make_pair(selector, style)); } diff --git a/src/ui/include/themes.hpp b/src/tangara/ui/themes.hpp index 09b9cdce..fd576478 100644 --- a/src/ui/include/themes.hpp +++ b/src/tangara/ui/themes.hpp @@ -1,7 +1,7 @@ #pragma once -#include <string> #include <map> +#include <string> #include <vector> #include "lvgl.h" @@ -32,7 +32,6 @@ class Theme { Theme(); std::map<std::string, std::vector<std::pair<int, lv_style_t*>>> style_map; lv_theme_t theme_; - }; } // namespace themes } // namespace ui diff --git a/src/ui/include/ui_events.hpp b/src/tangara/ui/ui_events.hpp index 3d794edc..cb446cd2 100644 --- a/src/ui/include/ui_events.hpp +++ b/src/tangara/ui/ui_events.hpp @@ -7,12 +7,12 @@ #pragma once #include <memory> -#include "database.hpp" -#include "gpios.hpp" -#include "index.hpp" -#include "nvs.hpp" -#include "screen.hpp" +#include "database/database.hpp" +#include "database/index.hpp" +#include "drivers/gpios.hpp" +#include "drivers/nvs.hpp" #include "tinyfsm.hpp" +#include "ui/screen.hpp" namespace ui { diff --git a/src/ui/ui_fsm.cpp b/src/tangara/ui/ui_fsm.cpp index 1cbf1be4..17d6c511 100644 --- a/src/ui/ui_fsm.cpp +++ b/src/tangara/ui/ui_fsm.cpp @@ -4,63 +4,63 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "ui_fsm.hpp" +#include "ui/ui_fsm.hpp" #include <memory> #include <memory_resource> #include <variant> -#include "bluetooth_types.hpp" -#include "db_events.hpp" -#include "device_factory.hpp" -#include "display_init.hpp" -#include "esp_spp_api.h" -#include "feedback_haptics.hpp" -#include "freertos/portmacro.h" -#include "freertos/projdefs.h" -#include "input_device.hpp" -#include "input_touch_wheel.hpp" -#include "input_volume_buttons.hpp" -#include "lua.h" -#include "lua.hpp" +#include "FreeRTOSConfig.h" +#include "lvgl.h" -#include "audio_fsm.hpp" -#include "battery.hpp" #include "core/lv_group.h" #include "core/lv_obj.h" #include "core/lv_obj_tree.h" -#include "database.hpp" #include "esp_heap_caps.h" +#include "esp_spp_api.h" #include "esp_timer.h" -#include "haptics.hpp" -#include "lauxlib.h" -#include "lua_thread.hpp" +#include "freertos/portmacro.h" +#include "freertos/projdefs.h" +#include "lua.hpp" #include "luavgl.h" -#include "lvgl_input_driver.hpp" -#include "memory_resource.hpp" #include "misc/lv_gc.h" - -#include "audio_events.hpp" -#include "display.hpp" -#include "event_queue.hpp" -#include "gpios.hpp" -#include "lua_registry.hpp" -#include "lvgl_task.hpp" -#include "nvs.hpp" -#include "property.hpp" -#include "samd.hpp" -#include "screen.hpp" -#include "screen_lua.hpp" -#include "screen_splash.hpp" -#include "spiffs.hpp" -#include "storage.hpp" -#include "system_events.hpp" #include "tinyfsm.hpp" -#include "touchwheel.hpp" -#include "track_queue.hpp" -#include "ui_events.hpp" #include "widgets/lv_label.h" +#include "audio/audio_events.hpp" +#include "audio/audio_fsm.hpp" +#include "audio/track_queue.hpp" +#include "battery/battery.hpp" +#include "database/database.hpp" +#include "database/db_events.hpp" +#include "drivers/bluetooth_types.hpp" +#include "drivers/display.hpp" +#include "drivers/display_init.hpp" +#include "drivers/gpios.hpp" +#include "drivers/haptics.hpp" +#include "drivers/nvs.hpp" +#include "drivers/samd.hpp" +#include "drivers/spiffs.hpp" +#include "drivers/storage.hpp" +#include "drivers/touchwheel.hpp" +#include "events/event_queue.hpp" +#include "input/device_factory.hpp" +#include "input/feedback_haptics.hpp" +#include "input/input_device.hpp" +#include "input/input_touch_wheel.hpp" +#include "input/input_volume_buttons.hpp" +#include "input/lvgl_input_driver.hpp" +#include "lua/lua_registry.hpp" +#include "lua/lua_thread.hpp" +#include "lua/property.hpp" +#include "memory_resource.hpp" +#include "system_fsm/system_events.hpp" +#include "ui/lvgl_task.hpp" +#include "ui/screen.hpp" +#include "ui/screen_lua.hpp" +#include "ui/screen_splash.hpp" +#include "ui/ui_events.hpp" + namespace ui { [[maybe_unused]] static constexpr char kTag[] = "ui_fsm"; @@ -253,6 +253,8 @@ lua::Property UiState::sDatabaseAutoUpdate{ return true; }}; +lua::Property UiState::sSdMounted{false}; + lua::Property UiState::sUsbMassStorageEnabled{ false, [](const lua::LuaValue& val) { if (!std::holds_alternative<bool>(val)) { @@ -334,6 +336,10 @@ void UiState::react(const system_fsm::SamdUsbStatusChanged& ev) { drivers::Samd::UsbStatus::kAttachedBusy); } +void UiState::react(const system_fsm::SdStateChanged&) { + sSdMounted.setDirect(sServices->sd() == drivers::SdState::kMounted); +} + void UiState::react(const database::event::UpdateStarted&) { sDatabaseUpdating.setDirect(true); } @@ -444,7 +450,8 @@ void Splash::react(const system_fsm::BootComplete& ev) { sTask->input(sInput); } -void Splash::react(const system_fsm::StorageMounted&) { +void Splash::react(const system_fsm::SdStateChanged& ev) { + UiState::react(ev); transit<Lua>(); } @@ -517,6 +524,7 @@ void Lua::entry() { { {"push", [&](lua_State* s) { return PushLuaScreen(s); }}, {"pop", [&](lua_State* s) { return PopLuaScreen(s); }}, + {"reset", [&](lua_State* s) { return ResetLuaScreen(s); }}, }); registry.AddPropertyModule( "alerts", { @@ -533,6 +541,9 @@ void Lua::entry() { {"updating", &sDatabaseUpdating}, {"auto_update", &sDatabaseAutoUpdate}, }); + registry.AddPropertyModule("sd_card", { + {"mounted", &sSdMounted}, + }); registry.AddPropertyModule("usb", { {"msc_enabled", &sUsbMassStorageEnabled}, @@ -547,7 +558,9 @@ void Lua::entry() { sBluetoothDevices.setDirect(bt.KnownDevices()); sCurrentScreen.reset(); - sLua->RunScript("/sdcard/config.lua"); + if (sServices->sd() == drivers::SdState::kMounted) { + sLua->RunScript("/sdcard/config.lua"); + } sLua->RunScript("/lua/main.lua"); } } @@ -587,16 +600,6 @@ auto Lua::PushLuaScreen(lua_State* s) -> int { return 0; } -auto Lua::QueueNext(lua_State*) -> int { - sServices->track_queue().next(); - return 0; -} - -auto Lua::QueuePrevious(lua_State*) -> int { - sServices->track_queue().previous(); - return 0; -} - auto Lua::PopLuaScreen(lua_State* s) -> int { if (!sCurrentScreen->canPop()) { return 0; @@ -607,6 +610,30 @@ auto Lua::PopLuaScreen(lua_State* s) -> int { return 0; } +auto Lua::ResetLuaScreen(lua_State* s) -> int { + if (sCurrentScreen) { + if (!sCurrentScreen->canPop()) { + ESP_LOGW(kTag, "ignoring reset as popping is blocked"); + return 0; + } + sCurrentScreen->onHidden(); + } + while (!sScreens.empty()) { + sScreens.pop(); + } + return PushLuaScreen(s); +} + +auto Lua::QueueNext(lua_State*) -> int { + sServices->track_queue().next(); + return 0; +} + +auto Lua::QueuePrevious(lua_State*) -> int { + sServices->track_queue().previous(); + return 0; +} + auto Lua::Ticks(lua_State* s) -> int { lua_pushinteger(s, esp_timer_get_time() / 1000); return 1; diff --git a/src/ui/include/ui_fsm.hpp b/src/tangara/ui/ui_fsm.hpp index 325aea8f..af8d75fb 100644 --- a/src/ui/include/ui_fsm.hpp +++ b/src/tangara/ui/ui_fsm.hpp @@ -10,30 +10,31 @@ #include <memory> #include <stack> -#include "audio_events.hpp" -#include "battery.hpp" -#include "db_events.hpp" -#include "device_factory.hpp" -#include "display.hpp" -#include "feedback_haptics.hpp" -#include "gpios.hpp" -#include "input_touch_wheel.hpp" -#include "input_volume_buttons.hpp" -#include "lua_thread.hpp" -#include "lvgl_input_driver.hpp" -#include "lvgl_task.hpp" -#include "modal.hpp" -#include "nvs.hpp" -#include "property.hpp" -#include "screen.hpp" -#include "service_locator.hpp" -#include "storage.hpp" -#include "system_events.hpp" #include "tinyfsm.hpp" -#include "touchwheel.hpp" -#include "track.hpp" -#include "track_queue.hpp" -#include "ui_events.hpp" + +#include "audio/audio_events.hpp" +#include "audio/track_queue.hpp" +#include "battery/battery.hpp" +#include "database/db_events.hpp" +#include "database/track.hpp" +#include "drivers/display.hpp" +#include "drivers/gpios.hpp" +#include "drivers/nvs.hpp" +#include "drivers/storage.hpp" +#include "drivers/touchwheel.hpp" +#include "input/device_factory.hpp" +#include "input/feedback_haptics.hpp" +#include "input/input_touch_wheel.hpp" +#include "input/input_volume_buttons.hpp" +#include "input/lvgl_input_driver.hpp" +#include "lua/lua_thread.hpp" +#include "lua/property.hpp" +#include "system_fsm/service_locator.hpp" +#include "system_fsm/system_events.hpp" +#include "ui/lvgl_task.hpp" +#include "ui/modal.hpp" +#include "ui/screen.hpp" +#include "ui/ui_events.hpp" namespace ui { @@ -57,7 +58,7 @@ class UiState : public tinyfsm::Fsm<UiState> { virtual void react(const DumpLuaStack&) {} virtual void react(const internal::BackPressed&) {} virtual void react(const system_fsm::BootComplete&) {} - virtual void react(const system_fsm::StorageMounted&) {} + virtual void react(const system_fsm::SdStateChanged&); void react(const system_fsm::BatteryStateChanged&); void react(const audio::PlaybackUpdate&); @@ -136,6 +137,8 @@ class UiState : public tinyfsm::Fsm<UiState> { static lua::Property sDatabaseUpdating; static lua::Property sDatabaseAutoUpdate; + static lua::Property sSdMounted; + static lua::Property sUsbMassStorageEnabled; static lua::Property sUsbMassStorageBusy; }; @@ -147,7 +150,7 @@ class Splash : public UiState { void exit() override; void react(const system_fsm::BootComplete&) override; - void react(const system_fsm::StorageMounted&) override; + void react(const system_fsm::SdStateChanged&) override; using UiState::react; }; @@ -166,6 +169,7 @@ class Lua : public UiState { private: auto PushLuaScreen(lua_State*) -> int; auto PopLuaScreen(lua_State*) -> int; + auto ResetLuaScreen(lua_State*) -> int; auto ShowAlert(lua_State*) -> int; auto HideAlert(lua_State*) -> int; diff --git a/src/tasks/CMakeLists.txt b/src/tasks/CMakeLists.txt index 0fdacf78..814c9943 100644 --- a/src/tasks/CMakeLists.txt +++ b/src/tasks/CMakeLists.txt @@ -1,5 +1,5 @@ # Copyright 2023 jacqueline <me@jacqueline.id.au> # # SPDX-License-Identifier: GPL-3.0-only -idf_component_register(SRCS "tasks.cpp" INCLUDE_DIRS "." REQUIRES "span" "memory") +idf_component_register(SRCS "tasks.cpp" INCLUDE_DIRS "." REQUIRES "memory") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/tasks/tasks.cpp b/src/tasks/tasks.cpp index aa382655..d3937c68 100644 --- a/src/tasks/tasks.cpp +++ b/src/tasks/tasks.cpp @@ -33,12 +33,12 @@ auto Name<Type::kAudioConverter>() -> std::pmr::string { } template <Type t> -auto AllocateStack() -> cpp::span<StackType_t>; +auto AllocateStack() -> std::span<StackType_t>; // Decoders often require a very large amount of stack space, since they aren't // usually written with embedded use cases in mind. template <> -auto AllocateStack<Type::kAudioDecoder>() -> cpp::span<StackType_t> { +auto AllocateStack<Type::kAudioDecoder>() -> std::span<StackType_t> { constexpr std::size_t size = 20 * 1024; static StackType_t sStack[size]; return {sStack, size}; @@ -46,14 +46,14 @@ auto AllocateStack<Type::kAudioDecoder>() -> cpp::span<StackType_t> { // LVGL requires only a relatively small stack. Lua's stack is allocated // separately. template <> -auto AllocateStack<Type::kUi>() -> cpp::span<StackType_t> { +auto AllocateStack<Type::kUi>() -> std::span<StackType_t> { constexpr std::size_t size = 14 * 1024; static StackType_t sStack[size]; return {sStack, size}; } template <> // PCM conversion and resampling uses a very small amount of stack. -auto AllocateStack<Type::kAudioConverter>() -> cpp::span<StackType_t> { +auto AllocateStack<Type::kAudioConverter>() -> std::span<StackType_t> { constexpr std::size_t size = 4 * 1024; static StackType_t sStack[size]; return {sStack, size}; @@ -63,7 +63,7 @@ auto AllocateStack<Type::kAudioConverter>() -> cpp::span<StackType_t> { // cases, where large stack usage isn't so much of a concern. It therefore uses // an eye-wateringly large amount of stack. template <> -auto AllocateStack<Type::kBackgroundWorker>() -> cpp::span<StackType_t> { +auto AllocateStack<Type::kBackgroundWorker>() -> std::span<StackType_t> { std::size_t size = 64 * 1024; return {static_cast<StackType_t*>(heap_caps_malloc(size, MALLOC_CAP_SPIRAM)), size}; diff --git a/src/tasks/tasks.hpp b/src/tasks/tasks.hpp index 47f26837..566b5706 100644 --- a/src/tasks/tasks.hpp +++ b/src/tasks/tasks.hpp @@ -11,6 +11,7 @@ #include <future> #include <memory> #include <memory_resource> +#include <span> #include <string> #include "esp_heap_caps.h" @@ -19,7 +20,6 @@ #include "freertos/projdefs.h" #include "freertos/queue.h" #include "freertos/task.h" -#include "span.hpp" namespace tasks { @@ -46,7 +46,7 @@ enum class Type { template <Type t> auto Name() -> std::pmr::string; template <Type t> -auto AllocateStack() -> cpp::span<StackType_t>; +auto AllocateStack() -> std::span<StackType_t>; template <Type t> auto Priority() -> UBaseType_t; @@ -56,7 +56,7 @@ template <Type t> auto StartPersistent(const std::function<void(void)>& fn) -> void { StaticTask_t* task_buffer = static_cast<StaticTask_t*>(heap_caps_malloc( sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)); - cpp::span<StackType_t> stack = AllocateStack<t>(); + std::span<StackType_t> stack = AllocateStack<t>(); xTaskCreateStatic(&PersistentMain, Name<t>().c_str(), stack.size(), new std::function<void(void)>(fn), Priority<t>(), stack.data(), task_buffer); @@ -67,7 +67,7 @@ auto StartPersistent(BaseType_t core, const std::function<void(void)>& fn) -> void { StaticTask_t* task_buffer = static_cast<StaticTask_t*>(heap_caps_malloc( sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)); - cpp::span<StackType_t> stack = AllocateStack<t>(); + std::span<StackType_t> stack = AllocateStack<t>(); xTaskCreateStaticPinnedToCore(&PersistentMain, Name<t>().c_str(), stack.size(), new std::function<void(void)>(fn), Priority<t>(), stack.data(), task_buffer, core); diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt deleted file mode 100644 index 3814e9d5..00000000 --- a/src/ui/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2023 jacqueline <me@jacqueline.id.au> -# -# SPDX-License-Identifier: GPL-3.0-only - -idf_component_register( - SRCS "lvgl_task.cpp" "ui_fsm.cpp" "screen_splash.cpp" "themes.cpp" - "screen.cpp" "modal.cpp" "screen_lua.cpp" "splash.c" "font_fusion_12.c" - "font_fusion_10.c" - INCLUDE_DIRS "include" - REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" "esp_timer" "battery" "lua" "luavgl" "esp_app_format" "input") -target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/ui/font_symbols.c b/src/ui/font_symbols.c deleted file mode 100644 index abc380eb..00000000 --- a/src/ui/font_symbols.c +++ /dev/null @@ -1,425 +0,0 @@ -/******************************************************************************* - * Size: 12 px - * Bpp: 1 - * Opts: --font fonts/font-awesome/FontAwesome5-Solid+Brands+Regular.woff -r 0xf244,0xf243,0xf242,0xf241,0xf240 -r 0xf104,0xf0d7 -r 61441,61448,61451,61452,61452,61453,61457,61459,61461,61465 -r 61468,61473,61478,61479,61480,61502,61512,61515,61516,61517 -r 61521,61522,61523,61524,61543,61544,61550,61552,61553,61556 -r 61559,61560,61561,61563,61587,61589,61636,61637,61639,61671 -r 61674,61683,61724,61732,61787,61931,62016,62017,62018,62019 -r 62020,62087,62099,62212,62189,62810,63426,63650 --size 12 --bpp 1 --format lvgl -o font_symbols.c - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef FONT_SYMBOLS -#define FONT_SYMBOLS 1 -#endif - -#if FONT_SYMBOLS - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+F001 "" */ - 0x0, 0x70, 0x3f, 0x1f, 0xf1, 0xfb, 0x1c, 0x31, - 0x83, 0x18, 0x31, 0x83, 0x19, 0xf7, 0x9f, 0xf8, - 0x47, 0x0, - - /* U+F008 "" */ - 0xbf, 0xde, 0x7, 0xa0, 0x5e, 0x7, 0xbf, 0xde, - 0x7, 0xa0, 0x5e, 0x7, 0xbf, 0xd0, - - /* U+F00B "" */ - 0xf7, 0xf7, 0xbf, 0xfd, 0xfe, 0x0, 0xf, 0x7f, - 0x7b, 0xff, 0xdf, 0xc0, 0x0, 0xf7, 0xf7, 0xbf, - 0xfd, 0xfc, - - /* U+F00C "" */ - 0x0, 0x20, 0x7, 0x0, 0xe4, 0x1c, 0xe3, 0x87, - 0x70, 0x3e, 0x1, 0xc0, 0x8, 0x0, - - /* U+F00D "" */ - 0xc3, 0xe7, 0x7e, 0x3c, 0x3c, 0x7e, 0xe7, 0xc3, - - /* U+F011 "" */ - 0x6, 0x2, 0x64, 0x76, 0xe6, 0x66, 0xc6, 0x3c, - 0x63, 0xc6, 0x3c, 0x3, 0x60, 0x67, 0xe, 0x3f, - 0xc0, 0xf0, - - /* U+F013 "" */ - 0xe, 0x4, 0xf0, 0x7f, 0xef, 0xfe, 0x71, 0xe7, - 0xc, 0x71, 0xef, 0xfe, 0x7f, 0xe4, 0xf0, 0xe, - 0x0, - - /* U+F015 "" */ - 0x3, 0x30, 0x1e, 0xc1, 0xcf, 0xc, 0xcc, 0x6f, - 0xdb, 0x7f, 0xb3, 0xff, 0xf, 0x3c, 0x3c, 0xf0, - 0xf3, 0xc0, - - /* U+F019 "" */ - 0xe, 0x0, 0xe0, 0xe, 0x0, 0xe0, 0x3f, 0xc3, - 0xf8, 0x1f, 0x0, 0xe0, 0xf5, 0xff, 0xff, 0xff, - 0x5f, 0xff, - - /* U+F01C "" */ - 0x1f, 0xe0, 0xc0, 0xc6, 0x1, 0x90, 0x2, 0xf8, - 0x7f, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - - /* U+F021 "" */ - 0x0, 0x31, 0xf3, 0x71, 0xfc, 0x7, 0xc3, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0xfc, 0x3e, 0x3, 0xf8, - 0xec, 0xf8, 0xc0, 0x0, - - /* U+F026 "" */ - 0xc, 0x7f, 0xff, 0xff, 0xf1, 0xc3, - - /* U+F027 "" */ - 0xc, 0xe, 0x3f, 0x7f, 0x9f, 0xdf, 0xe0, 0x70, - 0x18, - - /* U+F028 "" */ - 0x0, 0x60, 0x1, 0x83, 0x34, 0x38, 0xdf, 0xda, - 0xfe, 0x57, 0xf6, 0xbf, 0x8d, 0x1c, 0xd0, 0x61, - 0x80, 0x18, - - /* U+F03E "" */ - 0xff, 0xf9, 0xff, 0x9f, 0xf9, 0xef, 0xfc, 0x7d, - 0x83, 0xc0, 0x38, 0x3, 0xff, 0xf0, - - /* U+F048 "" */ - 0xc3, 0xc7, 0xcf, 0xdf, 0xff, 0xff, 0xdf, 0xcf, - 0xc7, 0xc3, - - /* U+F04B "" */ - 0x0, 0x1c, 0x3, 0xe0, 0x7f, 0xf, 0xf9, 0xff, - 0xbf, 0xff, 0xfe, 0xff, 0x9f, 0xc3, 0xe0, 0x70, - 0x0, 0x0, - - /* U+F04C "" */ - 0xfb, 0xff, 0x7f, 0xef, 0xfd, 0xff, 0xbf, 0xf7, - 0xfe, 0xff, 0xdf, 0xfb, 0xff, 0x7c, - - /* U+F04D "" */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - - /* U+F051 "" */ - 0xc3, 0xe3, 0xf3, 0xfb, 0xff, 0xff, 0xfb, 0xf3, - 0xe3, 0xc3, - - /* U+F052 "" */ - 0xc, 0x3, 0xc0, 0x7c, 0x1f, 0xc7, 0xfd, 0xff, - 0xbf, 0xf0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x80, - - /* U+F053 "" */ - 0xc, 0x73, 0x9c, 0xe3, 0x87, 0xe, 0x1c, 0x30, - - /* U+F054 "" */ - 0x83, 0x87, 0xe, 0x1c, 0x73, 0x9c, 0xe2, 0x0, - - /* U+F067 "" */ - 0xe, 0x1, 0xc0, 0x38, 0x7, 0xf, 0xff, 0xff, - 0xc3, 0x80, 0x70, 0xe, 0x1, 0xc0, - - /* U+F068 "" */ - 0xff, 0xff, 0xfc, - - /* U+F06E "" */ - 0xf, 0x81, 0xc7, 0x1c, 0x1d, 0xc6, 0x7e, 0xfb, - 0xf7, 0xdd, 0xdd, 0xc7, 0x1c, 0xf, 0x80, - - /* U+F070 "" */ - 0x0, 0x1, 0xc0, 0x1, 0xdf, 0x0, 0xe3, 0x80, - 0xdb, 0x84, 0xfb, 0x9c, 0x77, 0x3c, 0x6e, 0x38, - 0x78, 0x38, 0x70, 0x1e, 0x30, 0x0, 0x30, 0x0, - 0x0, - - /* U+F071 "" */ - 0x3, 0x0, 0x1c, 0x0, 0xf8, 0x3, 0xf0, 0x1c, - 0xc0, 0x73, 0x83, 0xcf, 0x1f, 0xfc, 0x7c, 0xfb, - 0xf3, 0xef, 0xff, 0x80, - - /* U+F074 "" */ - 0x0, 0x0, 0x6, 0xe1, 0xff, 0x3f, 0x17, 0x60, - 0xe4, 0x1f, 0x6f, 0xbf, 0xf1, 0xf0, 0x6, 0x0, - 0x40, - - /* U+F077 "" */ - 0x0, 0x3, 0x1, 0xe0, 0xcc, 0x61, 0xb0, 0x30, - 0x0, - - /* U+F078 "" */ - 0x0, 0x30, 0x36, 0x18, 0xcc, 0x1e, 0x3, 0x0, - 0x0, - - /* U+F079 "" */ - 0x30, 0x0, 0xf7, 0xf3, 0xf0, 0x65, 0xa0, 0xc3, - 0x1, 0x86, 0xb, 0x4c, 0x1f, 0x9f, 0xde, 0x0, - 0x18, - - /* U+F07B "" */ - 0x78, 0xf, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - - /* U+F093 "" */ - 0x6, 0x0, 0xf0, 0x1f, 0x83, 0xfc, 0x7, 0x0, - 0x70, 0x7, 0x0, 0x70, 0xf7, 0xff, 0xff, 0xff, - 0x5f, 0xff, - - /* U+F095 "" */ - 0x0, 0x0, 0xf, 0x0, 0xf0, 0x1f, 0x0, 0xf0, - 0x6, 0x0, 0xe0, 0x1c, 0x73, 0xcf, 0xf8, 0xfe, - 0xf, 0xc0, 0x40, 0x0, - - /* U+F0C4 "" */ - 0x70, 0x5b, 0x3f, 0x6f, 0x3f, 0xc1, 0xf0, 0x3e, - 0x1f, 0xe6, 0xde, 0xd9, 0xee, 0x8, - - /* U+F0C5 "" */ - 0x1f, 0x43, 0xef, 0x7f, 0xef, 0xfd, 0xff, 0xbf, - 0xf7, 0xfe, 0xff, 0xdf, 0xf8, 0x3, 0xfc, 0x0, - - /* U+F0C7 "" */ - 0xff, 0x98, 0x1b, 0x3, 0xe0, 0x7c, 0xf, 0xff, - 0xfe, 0x7f, 0x8f, 0xf9, 0xff, 0xfc, - - /* U+F0D7 "" */ - 0xfe, 0xf8, 0xe0, 0x80, - - /* U+F0E7 "" */ - 0x78, 0x78, 0xf8, 0xf0, 0xff, 0xfe, 0xfc, 0x1c, - 0x18, 0x18, 0x10, 0x30, - - /* U+F0EA "" */ - 0x18, 0x3b, 0x8e, 0xe3, 0xf8, 0xe0, 0x3b, 0xae, - 0xe7, 0xbf, 0xef, 0xfb, 0xf0, 0xfc, 0x3f, - - /* U+F0F3 "" */ - 0x4, 0x0, 0x80, 0x7c, 0x1f, 0xc3, 0xf8, 0x7f, - 0x1f, 0xf3, 0xfe, 0x7f, 0xdf, 0xfc, 0x0, 0x7, - 0x0, - - /* U+F104 "" */ - 0x17, 0xec, 0xe7, 0x10, - - /* U+F11C "" */ - 0xff, 0xff, 0x52, 0xbd, 0x4a, 0xff, 0xff, 0xeb, - 0x5f, 0xff, 0xfd, 0x2, 0xf4, 0xb, 0xff, 0xfc, - - /* U+F124 "" */ - 0x0, 0x0, 0xf, 0x3, 0xf0, 0xfe, 0x3f, 0xef, - 0xfc, 0xff, 0xc0, 0x78, 0x7, 0x80, 0x78, 0x7, - 0x0, 0x70, 0x2, 0x0, - - /* U+F15B "" */ - 0xfa, 0x7d, 0xbe, 0xff, 0xf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - - /* U+F1EB "" */ - 0x7, 0xc0, 0x7f, 0xf1, 0xe0, 0xf7, 0x0, 0x70, - 0x7c, 0x3, 0xfe, 0x6, 0xc, 0x0, 0x0, 0x3, - 0x80, 0x7, 0x0, 0xe, 0x0, - - /* U+F240 "" */ - 0xff, 0xff, 0x80, 0x1f, 0x7f, 0xfe, 0xff, 0xbd, - 0xff, 0xf8, 0x1, 0xff, 0xff, 0x80, - - /* U+F241 "" */ - 0xff, 0xff, 0x80, 0x1f, 0x7f, 0x3e, 0xfe, 0x3d, - 0xfc, 0xf8, 0x1, 0xff, 0xff, 0x80, - - /* U+F242 "" */ - 0xff, 0xff, 0x80, 0x1f, 0x78, 0x3e, 0xf0, 0x3d, - 0xe0, 0xf8, 0x1, 0xff, 0xff, 0x80, - - /* U+F243 "" */ - 0xff, 0xff, 0x80, 0x1f, 0x60, 0x3e, 0xc0, 0x3d, - 0x80, 0xf8, 0x1, 0xff, 0xff, 0x80, - - /* U+F244 "" */ - 0xff, 0xff, 0x80, 0x1f, 0x0, 0x3e, 0x0, 0x3c, - 0x0, 0xf8, 0x1, 0xff, 0xff, 0x80, - - /* U+F287 "" */ - 0x0, 0xc0, 0x7, 0x80, 0x10, 0x7, 0x20, 0x6f, - 0xff, 0xfc, 0x41, 0x80, 0x40, 0x0, 0xb8, 0x0, - 0xf0, - - /* U+F293 "" */ - 0x3e, 0x3b, 0x9c, 0xdb, 0x7c, 0xbf, 0x1f, 0x9f, - 0x87, 0xd5, 0xf9, 0x9d, 0xc7, 0xc0, - - /* U+F2ED "" */ - 0xe, 0x1f, 0xfc, 0x0, 0x0, 0x7, 0xfc, 0xd5, - 0x9a, 0xb3, 0x56, 0x6a, 0xcd, 0x59, 0xab, 0x3f, - 0xe0, - - /* U+F304 "" */ - 0x0, 0x40, 0xe, 0x0, 0xf0, 0x37, 0x7, 0xa0, - 0xfc, 0x1f, 0x83, 0xf0, 0x7e, 0xf, 0xc0, 0xf8, - 0xf, 0x0, 0x80, 0x0, - - /* U+F55A "" */ - 0xf, 0xfe, 0x3f, 0xfc, 0xfb, 0x3b, 0xf0, 0xff, - 0xf3, 0xef, 0xc3, 0xcf, 0xb7, 0x8f, 0xff, 0xf, - 0xfe, - - /* U+F7C2 "" */ - 0x1f, 0x9a, 0xbe, 0xaf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, - - /* U+F8A2 "" */ - 0x0, 0x0, 0x3, 0x30, 0x37, 0x3, 0xff, 0xff, - 0xff, 0x70, 0x3, 0x0 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 192, .box_w = 12, .box_h = 12, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 18, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 32, .adv_w = 192, .box_w = 13, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 50, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 64, .adv_w = 132, .box_w = 8, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 72, .adv_w = 192, .box_w = 12, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 90, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 107, .adv_w = 216, .box_w = 14, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 125, .adv_w = 192, .box_w = 12, .box_h = 12, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 143, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 159, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 179, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 185, .adv_w = 144, .box_w = 9, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 194, .adv_w = 216, .box_w = 13, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 212, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 226, .adv_w = 168, .box_w = 8, .box_h = 10, .ofs_x = 1, .ofs_y = -1}, - {.bitmap_index = 236, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 254, .adv_w = 168, .box_w = 11, .box_h = 10, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 268, .adv_w = 168, .box_w = 11, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 282, .adv_w = 168, .box_w = 8, .box_h = 10, .ofs_x = 1, .ofs_y = -1}, - {.bitmap_index = 292, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 308, .adv_w = 120, .box_w = 6, .box_h = 10, .ofs_x = 1, .ofs_y = -1}, - {.bitmap_index = 316, .adv_w = 120, .box_w = 6, .box_h = 10, .ofs_x = 1, .ofs_y = -1}, - {.bitmap_index = 324, .adv_w = 168, .box_w = 11, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 338, .adv_w = 168, .box_w = 11, .box_h = 2, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 341, .adv_w = 216, .box_w = 13, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 356, .adv_w = 240, .box_w = 15, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 381, .adv_w = 216, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 401, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 418, .adv_w = 168, .box_w = 10, .box_h = 7, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 427, .adv_w = 168, .box_w = 10, .box_h = 7, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 436, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 453, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 467, .adv_w = 192, .box_w = 12, .box_h = 12, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 485, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 505, .adv_w = 168, .box_w = 11, .box_h = 10, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 519, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 535, .adv_w = 168, .box_w = 11, .box_h = 10, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 549, .adv_w = 120, .box_w = 7, .box_h = 4, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 553, .adv_w = 120, .box_w = 8, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 565, .adv_w = 168, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 580, .adv_w = 168, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 597, .adv_w = 96, .box_w = 4, .box_h = 7, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 601, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 617, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 637, .adv_w = 144, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 651, .adv_w = 240, .box_w = 15, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 672, .adv_w = 240, .box_w = 15, .box_h = 7, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 686, .adv_w = 240, .box_w = 15, .box_h = 7, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 700, .adv_w = 240, .box_w = 15, .box_h = 7, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 714, .adv_w = 240, .box_w = 15, .box_h = 7, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 728, .adv_w = 240, .box_w = 15, .box_h = 7, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 742, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 759, .adv_w = 168, .box_w = 9, .box_h = 12, .ofs_x = 1, .ofs_y = -2}, - {.bitmap_index = 773, .adv_w = 168, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 790, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, - {.bitmap_index = 810, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 827, .adv_w = 144, .box_w = 10, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, - {.bitmap_index = 841, .adv_w = 193, .box_w = 12, .box_h = 8, .ofs_x = 0, .ofs_y = 1} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x7, 0xa, 0xb, 0xc, 0x10, 0x12, 0x14, - 0x18, 0x1b, 0x20, 0x25, 0x26, 0x27, 0x3d, 0x47, - 0x4a, 0x4b, 0x4c, 0x50, 0x51, 0x52, 0x53, 0x66, - 0x67, 0x6d, 0x6f, 0x70, 0x73, 0x76, 0x77, 0x78, - 0x7a, 0x92, 0x94, 0xc3, 0xc4, 0xc6, 0xd6, 0xe6, - 0xe9, 0xf2, 0x103, 0x11b, 0x123, 0x15a, 0x1ea, 0x23f, - 0x240, 0x241, 0x242, 0x243, 0x286, 0x292, 0x2ec, 0x303, - 0x559, 0x7c1, 0x8a1 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 61441, .range_length = 2210, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 59, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LV_VERSION_CHECK(8, 0, 0) -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 1, - .bpp = 1, - .kern_classes = 0, - .bitmap_format = 0, -#if LV_VERSION_CHECK(8, 0, 0) - .cache = &cache -#endif -}; - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LV_VERSION_CHECK(8, 0, 0) -const lv_font_t font_symbols = { -#else -lv_font_t font_symbols = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 13, /*The maximum line height required by the font*/ - .base_line = 2, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = -4, - .underline_thickness = 1, -#endif - .dsc = &font_dsc /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -}; - - - -#endif /*#if FONT_SYMBOLS*/ - diff --git a/src/ui/icons/battery_20.c b/src/ui/icons/battery_20.c deleted file mode 100644 index 3be6b614..00000000 --- a/src/ui/icons/battery_20.c +++ /dev/null @@ -1,52 +0,0 @@ -#ifdef __has_include - #if __has_include("lvgl.h") - #ifndef LV_LVGL_H_INCLUDE_SIMPLE - #define LV_LVGL_H_INCLUDE_SIMPLE - #endif - #endif -#endif - -#if defined(LV_LVGL_H_INCLUDE_SIMPLE) - #include "lvgl.h" -#else - #include "lvgl/lvgl.h" -#endif - - -#ifndef LV_ATTRIBUTE_MEM_ALIGN -#define LV_ATTRIBUTE_MEM_ALIGN -#endif - -#ifndef LV_ATTRIBUTE_IMG_BATTERY_20 -#define LV_ATTRIBUTE_IMG_BATTERY_20 -#endif - -static const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATTERY_20 uint8_t battery_20_map[] = { - 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ - 0xfd, 0xfe, 0xfd, 0xff, /*Color of index 1*/ - 0x26, 0xc1, 0x38, 0xff, /*Color of index 2*/ - 0x01, 0xbe, 0x37, 0xff, /*Color of index 3*/ - - 0x55, 0x00, 0x55, - 0x54, 0x00, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xff, 0x15, - 0x54, 0x00, 0x15, -}; - -const lv_img_dsc_t kIconBattery20 = { - .header.cf = LV_IMG_CF_INDEXED_2BIT, - .header.always_zero = 0, - .header.reserved = 0, - .header.w = 12, - .header.h = 12, - .data_size = 52, - .data = battery_20_map, -}; diff --git a/src/ui/icons/battery_40.c b/src/ui/icons/battery_40.c deleted file mode 100644 index 4a6ead0c..00000000 --- a/src/ui/icons/battery_40.c +++ /dev/null @@ -1,52 +0,0 @@ -#ifdef __has_include - #if __has_include("lvgl.h") - #ifndef LV_LVGL_H_INCLUDE_SIMPLE - #define LV_LVGL_H_INCLUDE_SIMPLE - #endif - #endif -#endif - -#if defined(LV_LVGL_H_INCLUDE_SIMPLE) - #include "lvgl.h" -#else - #include "lvgl/lvgl.h" -#endif - - -#ifndef LV_ATTRIBUTE_MEM_ALIGN -#define LV_ATTRIBUTE_MEM_ALIGN -#endif - -#ifndef LV_ATTRIBUTE_IMG_BATTERY_40 -#define LV_ATTRIBUTE_IMG_BATTERY_40 -#endif - -static const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATTERY_40 uint8_t battery_40_map[] = { - 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ - 0xfd, 0xfe, 0xfd, 0xff, /*Color of index 1*/ - 0x26, 0xc1, 0x38, 0xff, /*Color of index 2*/ - 0x01, 0xbe, 0x37, 0xff, /*Color of index 3*/ - - 0x55, 0x00, 0x55, - 0x54, 0x00, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xff, 0x15, - 0x54, 0xff, 0x15, - 0x54, 0x00, 0x15, -}; - -const lv_img_dsc_t kIconBattery40 = { - .header.cf = LV_IMG_CF_INDEXED_2BIT, - .header.always_zero = 0, - .header.reserved = 0, - .header.w = 12, - .header.h = 12, - .data_size = 52, - .data = battery_40_map, -}; diff --git a/src/ui/icons/battery_60.c b/src/ui/icons/battery_60.c deleted file mode 100644 index 4695cb73..00000000 --- a/src/ui/icons/battery_60.c +++ /dev/null @@ -1,52 +0,0 @@ -#ifdef __has_include - #if __has_include("lvgl.h") - #ifndef LV_LVGL_H_INCLUDE_SIMPLE - #define LV_LVGL_H_INCLUDE_SIMPLE - #endif - #endif -#endif - -#if defined(LV_LVGL_H_INCLUDE_SIMPLE) - #include "lvgl.h" -#else - #include "lvgl/lvgl.h" -#endif - - -#ifndef LV_ATTRIBUTE_MEM_ALIGN -#define LV_ATTRIBUTE_MEM_ALIGN -#endif - -#ifndef LV_ATTRIBUTE_IMG_BATTERY_60 -#define LV_ATTRIBUTE_IMG_BATTERY_60 -#endif - -static const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATTERY_60 uint8_t battery_60_map[] = { - 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ - 0xfd, 0xfe, 0xfd, 0xff, /*Color of index 1*/ - 0x26, 0xc1, 0x38, 0xff, /*Color of index 2*/ - 0x01, 0xbe, 0x37, 0xff, /*Color of index 3*/ - - 0x55, 0x00, 0x55, - 0x54, 0x00, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xff, 0x15, - 0x54, 0xff, 0x15, - 0x54, 0x00, 0x15, -}; - -const lv_img_dsc_t kIconBattery60 = { - .header.cf = LV_IMG_CF_INDEXED_2BIT, - .header.always_zero = 0, - .header.reserved = 0, - .header.w = 12, - .header.h = 12, - .data_size = 52, - .data = battery_60_map, -}; diff --git a/src/ui/icons/battery_80.c b/src/ui/icons/battery_80.c deleted file mode 100644 index e0b60dfe..00000000 --- a/src/ui/icons/battery_80.c +++ /dev/null @@ -1,52 +0,0 @@ -#ifdef __has_include - #if __has_include("lvgl.h") - #ifndef LV_LVGL_H_INCLUDE_SIMPLE - #define LV_LVGL_H_INCLUDE_SIMPLE - #endif - #endif -#endif - -#if defined(LV_LVGL_H_INCLUDE_SIMPLE) - #include "lvgl.h" -#else - #include "lvgl/lvgl.h" -#endif - - -#ifndef LV_ATTRIBUTE_MEM_ALIGN -#define LV_ATTRIBUTE_MEM_ALIGN -#endif - -#ifndef LV_ATTRIBUTE_IMG_BATTERY_80 -#define LV_ATTRIBUTE_IMG_BATTERY_80 -#endif - -static const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATTERY_80 uint8_t battery_80_map[] = { - 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ - 0xfd, 0xfe, 0xfd, 0xff, /*Color of index 1*/ - 0x26, 0xc1, 0x38, 0xff, /*Color of index 2*/ - 0x01, 0xbe, 0x37, 0xff, /*Color of index 3*/ - - 0x55, 0x00, 0x55, - 0x54, 0x00, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0x55, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xff, 0x15, - 0x54, 0xff, 0x15, - 0x54, 0x00, 0x15, -}; - -const lv_img_dsc_t kIconBattery80 = { - .header.cf = LV_IMG_CF_INDEXED_2BIT, - .header.always_zero = 0, - .header.reserved = 0, - .header.w = 12, - .header.h = 12, - .data_size = 52, - .data = battery_80_map, -}; diff --git a/src/ui/icons/battery_empty.c b/src/ui/icons/battery_empty.c deleted file mode 100644 index 26f84863..00000000 --- a/src/ui/icons/battery_empty.c +++ /dev/null @@ -1,52 +0,0 @@ -#ifdef __has_include - #if __has_include("lvgl.h") - #ifndef LV_LVGL_H_INCLUDE_SIMPLE - #define LV_LVGL_H_INCLUDE_SIMPLE - #endif - #endif -#endif - -#if defined(LV_LVGL_H_INCLUDE_SIMPLE) - #include "lvgl.h" -#else - #include "lvgl/lvgl.h" -#endif - - -#ifndef LV_ATTRIBUTE_MEM_ALIGN -#define LV_ATTRIBUTE_MEM_ALIGN -#endif - -#ifndef LV_ATTRIBUTE_IMG_BATTERY_EMPTY -#define LV_ATTRIBUTE_IMG_BATTERY_EMPTY -#endif - -const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATTERY_EMPTY uint8_t battery_empty_map[] = { - 0xfd, 0xfd, 0xfd, 0xff, /*Color of index 0*/ - 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ - 0x26, 0x2c, 0xfa, 0xff, /*Color of index 2*/ - 0x00, 0x00, 0x00, 0x00, /*Color of index 3*/ - - 0x00, 0x55, 0x00, - 0x01, 0x55, 0x40, - 0x01, 0x00, 0x40, - 0x01, 0x00, 0x40, - 0x01, 0x00, 0x40, - 0x01, 0x00, 0x40, - 0x01, 0x00, 0x40, - 0x01, 0x00, 0x40, - 0x01, 0x00, 0x40, - 0x01, 0xaa, 0x40, - 0x01, 0xaa, 0x40, - 0x01, 0x55, 0x40, -}; - -const lv_img_dsc_t kIconBatteryEmpty = { - .header.cf = LV_IMG_CF_INDEXED_2BIT, - .header.always_zero = 0, - .header.reserved = 0, - .header.w = 12, - .header.h = 12, - .data_size = 52, - .data = battery_empty_map, -}; diff --git a/src/ui/icons/battery_full.c b/src/ui/icons/battery_full.c deleted file mode 100644 index 1e3b17e3..00000000 --- a/src/ui/icons/battery_full.c +++ /dev/null @@ -1,52 +0,0 @@ -#ifdef __has_include - #if __has_include("lvgl.h") - #ifndef LV_LVGL_H_INCLUDE_SIMPLE - #define LV_LVGL_H_INCLUDE_SIMPLE - #endif - #endif -#endif - -#if defined(LV_LVGL_H_INCLUDE_SIMPLE) - #include "lvgl.h" -#else - #include "lvgl/lvgl.h" -#endif - - -#ifndef LV_ATTRIBUTE_MEM_ALIGN -#define LV_ATTRIBUTE_MEM_ALIGN -#endif - -#ifndef LV_ATTRIBUTE_IMG_BATTERY_FULL -#define LV_ATTRIBUTE_IMG_BATTERY_FULL -#endif - -const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATTERY_FULL uint8_t battery_full_map[] = { - 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ - 0xfd, 0xfe, 0xfd, 0xff, /*Color of index 1*/ - 0x26, 0xc1, 0x38, 0xff, /*Color of index 2*/ - 0x01, 0xbe, 0x37, 0xff, /*Color of index 3*/ - - 0x55, 0x00, 0x55, - 0x54, 0x00, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xaa, 0x15, - 0x54, 0xff, 0x15, - 0x54, 0xff, 0x15, - 0x54, 0x00, 0x15, -}; - -const lv_img_dsc_t kIconBatteryFull = { - .header.cf = LV_IMG_CF_INDEXED_2BIT, - .header.always_zero = 0, - .header.reserved = 0, - .header.w = 12, - .header.h = 12, - .data_size = 52, - .data = battery_full_map, -}; diff --git a/src/ui/icons/bluetooth.c b/src/ui/icons/bluetooth.c deleted file mode 100644 index 66322f8f..00000000 --- a/src/ui/icons/bluetooth.c +++ /dev/null @@ -1,54 +0,0 @@ -#ifdef __has_include - #if __has_include("lvgl.h") - #ifndef LV_LVGL_H_INCLUDE_SIMPLE - #define LV_LVGL_H_INCLUDE_SIMPLE - #endif - #endif -#endif - -#if defined(LV_LVGL_H_INCLUDE_SIMPLE) - #include "lvgl.h" -#else - #include "lvgl/lvgl.h" -#endif - - -#ifndef LV_ATTRIBUTE_MEM_ALIGN -#define LV_ATTRIBUTE_MEM_ALIGN -#endif - -#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH -#define LV_ATTRIBUTE_IMG_BLUETOOTH -#endif - -static const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BLUETOOTH uint8_t bluetooth_map[] = { - 0xfe, 0xfe, 0xfe, 0xff, /*Color of index 0*/ - 0xff, 0x75, 0x00, 0xff, /*Color of index 1*/ - 0x00, 0x00, 0x00, 0x00, /*Color of index 2*/ - 0x00, 0x00, 0x00, 0x00, /*Color of index 3*/ - - 0x00, 0x55, 0x40, 0x00, - 0x01, 0x51, 0x50, 0x00, - 0x05, 0x50, 0x54, 0x00, - 0x05, 0x51, 0x14, 0x00, - 0x05, 0x11, 0x04, 0x00, - 0x15, 0x40, 0x15, 0x00, - 0x15, 0x50, 0x55, 0x00, - 0x15, 0x40, 0x15, 0x00, - 0x05, 0x11, 0x04, 0x00, - 0x05, 0x51, 0x14, 0x00, - 0x05, 0x50, 0x54, 0x00, - 0x01, 0x51, 0x50, 0x00, - 0x00, 0x55, 0x40, 0x00, - 0x00, 0x00, 0x00, 0x00, -}; - -const lv_img_dsc_t kIconBluetooth = { - .header.cf = LV_IMG_CF_INDEXED_2BIT, - .header.always_zero = 0, - .header.reserved = 0, - .header.w = 14, - .header.h = 14, - .data_size = 72, - .data = bluetooth_map, -}; diff --git a/src/ui/icons/pause.c b/src/ui/icons/pause.c deleted file mode 100644 index 8201b5bb..00000000 --- a/src/ui/icons/pause.c +++ /dev/null @@ -1,54 +0,0 @@ -#ifdef __has_include - #if __has_include("lvgl.h") - #ifndef LV_LVGL_H_INCLUDE_SIMPLE - #define LV_LVGL_H_INCLUDE_SIMPLE - #endif - #endif -#endif - -#if defined(LV_LVGL_H_INCLUDE_SIMPLE) - #include "lvgl.h" -#else - #include "lvgl/lvgl.h" -#endif - - -#ifndef LV_ATTRIBUTE_MEM_ALIGN -#define LV_ATTRIBUTE_MEM_ALIGN -#endif - -#ifndef LV_ATTRIBUTE_IMG_PAUSE -#define LV_ATTRIBUTE_IMG_PAUSE -#endif - -static const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_PAUSE uint8_t pause_map[] = { - 0xfe, 0xfe, 0xfe, 0xff, /*Color of index 0*/ - 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ - 0x00, 0x00, 0x00, 0x00, /*Color of index 2*/ - 0x00, 0x00, 0x00, 0x00, /*Color of index 3*/ - - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x50, 0x14, 0x00, - 0x00, 0x50, 0x14, 0x00, - 0x00, 0x50, 0x14, 0x00, - 0x00, 0x50, 0x14, 0x00, - 0x00, 0x50, 0x14, 0x00, - 0x00, 0x50, 0x14, 0x00, - 0x00, 0x50, 0x14, 0x00, - 0x00, 0x50, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, -}; - -const lv_img_dsc_t kIconPause = { - .header.cf = LV_IMG_CF_INDEXED_2BIT, - .header.always_zero = 0, - .header.reserved = 0, - .header.w = 14, - .header.h = 14, - .data_size = 72, - .data = pause_map, -}; diff --git a/src/ui/icons/play.c b/src/ui/icons/play.c deleted file mode 100644 index 8984eae4..00000000 --- a/src/ui/icons/play.c +++ /dev/null @@ -1,54 +0,0 @@ -#ifdef __has_include - #if __has_include("lvgl.h") - #ifndef LV_LVGL_H_INCLUDE_SIMPLE - #define LV_LVGL_H_INCLUDE_SIMPLE - #endif - #endif -#endif - -#if defined(LV_LVGL_H_INCLUDE_SIMPLE) - #include "lvgl.h" -#else - #include "lvgl/lvgl.h" -#endif - - -#ifndef LV_ATTRIBUTE_MEM_ALIGN -#define LV_ATTRIBUTE_MEM_ALIGN -#endif - -#ifndef LV_ATTRIBUTE_IMG_PLAY -#define LV_ATTRIBUTE_IMG_PLAY -#endif - -static const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_PLAY uint8_t play_map[] = { - 0xfe, 0xfe, 0xfe, 0xff, /*Color of index 0*/ - 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ - 0x00, 0x00, 0x00, 0x00, /*Color of index 2*/ - 0x00, 0x00, 0x00, 0x00, /*Color of index 3*/ - - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x50, 0x00, 0x00, - 0x00, 0x55, 0x00, 0x00, - 0x00, 0x55, 0x50, 0x00, - 0x00, 0x55, 0x54, 0x00, - 0x00, 0x55, 0x54, 0x00, - 0x00, 0x55, 0x50, 0x00, - 0x00, 0x55, 0x00, 0x00, - 0x00, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, -}; - -const lv_img_dsc_t kIconPlay = { - .header.cf = LV_IMG_CF_INDEXED_2BIT, - .header.always_zero = 0, - .header.reserved = 0, - .header.w = 14, - .header.h = 14, - .data_size = 72, - .data = play_map, -}; diff --git a/src/ui/include/ui_tick.hpp b/src/ui/include/ui_tick.hpp deleted file mode 100644 index 37f8a8bd..00000000 --- a/src/ui/include/ui_tick.hpp +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright 2023 jacqueline <me@jacqueline.id.au> - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include "esp_timer.h" - -#define LV_TICK_CUSTOM_SYS_TIME_EXPR (esp_timer_get_time() / 1000) diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index bb4ce320..49554be8 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -2,4 +2,4 @@ # # SPDX-License-Identifier: GPL-3.0-only -idf_component_register(SRCS INCLUDE_DIRS "include" REQUIRES "database" "span") +idf_component_register(SRCS INCLUDE_DIRS "include" REQUIRES "memory") diff --git a/src/util/include/debug.hpp b/src/util/include/debug.hpp index 620b0974..27fb2999 100644 --- a/src/util/include/debug.hpp +++ b/src/util/include/debug.hpp @@ -8,13 +8,12 @@ #include <iomanip> #include <ostream> - +#include <span> #include <string> -#include "span.hpp" namespace util { -inline std::string format_hex_string(cpp::span<const std::byte> data) { +inline std::string format_hex_string(std::span<const std::byte> data) { std::ostringstream oss; std::ostringstream ascii_values; int count = 0; diff --git a/src/util/random.cpp b/src/util/random.cpp index ae543765..2b2af9c7 100644 --- a/src/util/random.cpp +++ b/src/util/random.cpp @@ -29,8 +29,8 @@ auto Random::Next() -> std::uint64_t { return komirand(&seed1_, &seed2_); } -auto Random::RangeInclusive(std::uint64_t lower, std::uint64_t upper) - -> std::uint64_t { +auto Random::RangeInclusive(std::uint64_t lower, + std::uint64_t upper) -> std::uint64_t { return (Next() % (upper - lower + 1)) + lower; } |
