Compare commits
22 Commits
emscripten
...
rei/develo
Author | SHA1 | Date |
---|---|---|
Olivier 'reivilibre' | 1acd5e568c | |
Olivier 'reivilibre' | 5911e3093a | |
Olivier 'reivilibre' | f2ce51c173 | |
Reinhold Gschweicher | 04c923bd82 | |
Reinhold Gschweicher | 53d765bbd8 | |
NeroBurner | ce22ba29c9 | |
NeroBurner | f64e1aab80 | |
NeroBurner | 6313a7498b | |
Reinhold Gschweicher | 068c5a823e | |
Reinhold Gschweicher | 5f1dc192ac | |
Reinhold Gschweicher | 9427d4ddb1 | |
JF | 644431cbc4 | |
Riku Isokoski | b1fbae36f9 | |
Reinhold Gschweicher | f0c6ef9cd6 | |
Reinhold Gschweicher | d9d729d40f | |
NeroBurner | de8d0d6b6f | |
Reinhold Gschweicher | 7194e3e38e | |
Reinhold Gschweicher | 7110fa0034 | |
Reinhold Gschweicher | 9f36b7886d | |
Reinhold Gschweicher | d4e81ca177 | |
Wivik | 8507c601fb | |
Reinhold Gschweicher | 80ef18cce0 |
|
@ -34,6 +34,10 @@ jobs:
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get -y install libsdl2-dev
|
sudo apt-get -y install libsdl2-dev
|
||||||
|
|
||||||
|
- name: Install lv_font_conv
|
||||||
|
run:
|
||||||
|
npm i -g lv_font_conv@1.5.2
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
# Checkout
|
# Checkout
|
||||||
|
|
||||||
|
|
|
@ -49,3 +49,8 @@ Testing/Temporary/
|
||||||
src/nRF5_SDK_15.3.0_59ac345
|
src/nRF5_SDK_15.3.0_59ac345
|
||||||
src/arm-none-eabi
|
src/arm-none-eabi
|
||||||
|
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
package.json
|
||||||
|
package-lock.json
|
||||||
|
spiNorFlash.raw
|
|
@ -1,9 +1,9 @@
|
||||||
[submodule "InfiniTime"]
|
[submodule "InfiniTime"]
|
||||||
path = InfiniTime
|
path = InfiniTime
|
||||||
url = ../../InfiniTimeOrg/InfiniTime.git
|
url = gitea@bics.ga:rei-forks/InfiniTime.git
|
||||||
[submodule "lv_drivers"]
|
[submodule "lv_drivers"]
|
||||||
path = lv_drivers
|
path = lv_drivers
|
||||||
url = ../../lvgl/lv_drivers.git
|
url = https://github.com/lvgl/lv_drivers.git
|
||||||
[submodule "libpng"]
|
[submodule "libpng"]
|
||||||
path = libpng
|
path = libpng
|
||||||
url = ../../glennrp/libpng.git
|
url = https://github.com/glennrp/libpng.git
|
||||||
|
|
|
@ -80,6 +80,8 @@ target_sources(infinisim PUBLIC
|
||||||
sim/components/ble/MusicService.cpp
|
sim/components/ble/MusicService.cpp
|
||||||
sim/components/ble/NavigationService.h
|
sim/components/ble/NavigationService.h
|
||||||
sim/components/ble/NavigationService.cpp
|
sim/components/ble/NavigationService.cpp
|
||||||
|
sim/components/ble/AgendaService.h
|
||||||
|
sim/components/ble/AgendaService.cpp
|
||||||
sim/components/ble/NimbleController.h
|
sim/components/ble/NimbleController.h
|
||||||
sim/components/ble/NimbleController.cpp
|
sim/components/ble/NimbleController.cpp
|
||||||
sim/components/ble/weather/WeatherService.h
|
sim/components/ble/weather/WeatherService.h
|
||||||
|
@ -88,14 +90,10 @@ target_sources(infinisim PUBLIC
|
||||||
sim/components/brightness/BrightnessController.cpp
|
sim/components/brightness/BrightnessController.cpp
|
||||||
sim/components/firmwarevalidator/FirmwareValidator.h
|
sim/components/firmwarevalidator/FirmwareValidator.h
|
||||||
sim/components/firmwarevalidator/FirmwareValidator.cpp
|
sim/components/firmwarevalidator/FirmwareValidator.cpp
|
||||||
sim/components/fs/FS.h
|
|
||||||
sim/components/fs/FS.cpp
|
|
||||||
sim/components/heartrate/HeartRateController.h
|
sim/components/heartrate/HeartRateController.h
|
||||||
sim/components/heartrate/HeartRateController.cpp
|
sim/components/heartrate/HeartRateController.cpp
|
||||||
sim/components/motion/MotionController.h
|
sim/components/motion/MotionController.h
|
||||||
sim/components/motion/MotionController.cpp
|
sim/components/motion/MotionController.cpp
|
||||||
sim/components/motor/MotorController.h
|
|
||||||
sim/components/motor/MotorController.cpp
|
|
||||||
sim/drivers/Watchdog.h
|
sim/drivers/Watchdog.h
|
||||||
sim/drivers/Watchdog.cpp
|
sim/drivers/Watchdog.cpp
|
||||||
sim/drivers/Bma421.h
|
sim/drivers/Bma421.h
|
||||||
|
@ -169,12 +167,25 @@ file(GLOB InfiniTime_FONTS
|
||||||
file(GLOB InfiniTime_ICONS
|
file(GLOB InfiniTime_ICONS
|
||||||
"${InfiniTime_DIR}/src/displayapp/icons/*.c"
|
"${InfiniTime_DIR}/src/displayapp/icons/*.c"
|
||||||
)
|
)
|
||||||
|
file(GLOB InfiniTime_WIDGETS
|
||||||
|
"${InfiniTime_DIR}/src/displayapp/widgets/*.cpp"
|
||||||
|
"${InfiniTime_DIR}/src/displayapp/widgets/*.h"
|
||||||
|
)
|
||||||
|
set(LITTLEFS_SRC
|
||||||
|
${InfiniTime_DIR}/src/libs/littlefs/lfs_util.h
|
||||||
|
${InfiniTime_DIR}/src/libs/littlefs/lfs.h
|
||||||
|
${InfiniTime_DIR}/src/libs/littlefs/lfs_util.c
|
||||||
|
${InfiniTime_DIR}/src/libs/littlefs/lfs.c
|
||||||
|
)
|
||||||
target_sources(infinisim PUBLIC ${InfiniTime_SCREENS})
|
target_sources(infinisim PUBLIC ${InfiniTime_SCREENS})
|
||||||
target_sources(infinisim PUBLIC ${InfiniTime_FONTS})
|
target_sources(infinisim PUBLIC ${InfiniTime_FONTS})
|
||||||
target_sources(infinisim PUBLIC ${InfiniTime_ICONS})
|
target_sources(infinisim PUBLIC ${InfiniTime_ICONS})
|
||||||
|
target_sources(infinisim PUBLIC ${InfiniTime_WIDGETS})
|
||||||
|
target_sources(infinisim PUBLIC ${LITTLEFS_SRC})
|
||||||
|
|
||||||
# add files directly from InfiniTime sources
|
# add files directly from InfiniTime sources
|
||||||
target_include_directories(infinisim PRIVATE "${InfiniTime_DIR}/src")
|
target_include_directories(infinisim PRIVATE "${InfiniTime_DIR}/src")
|
||||||
|
target_include_directories(infinisim PRIVATE "${InfiniTime_DIR}/src/libs/littlefs")
|
||||||
target_sources(infinisim PUBLIC
|
target_sources(infinisim PUBLIC
|
||||||
${InfiniTime_DIR}/src/BootloaderVersion.h
|
${InfiniTime_DIR}/src/BootloaderVersion.h
|
||||||
${InfiniTime_DIR}/src/BootloaderVersion.cpp
|
${InfiniTime_DIR}/src/BootloaderVersion.cpp
|
||||||
|
@ -197,6 +208,10 @@ target_sources(infinisim PUBLIC
|
||||||
${InfiniTime_DIR}/src/components/settings/Settings.cpp
|
${InfiniTime_DIR}/src/components/settings/Settings.cpp
|
||||||
${InfiniTime_DIR}/src/components/ble/NotificationManager.h
|
${InfiniTime_DIR}/src/components/ble/NotificationManager.h
|
||||||
${InfiniTime_DIR}/src/components/ble/NotificationManager.cpp
|
${InfiniTime_DIR}/src/components/ble/NotificationManager.cpp
|
||||||
|
${InfiniTime_DIR}/src/components/fs/FS.h
|
||||||
|
${InfiniTime_DIR}/src/components/fs/FS.cpp
|
||||||
|
${InfiniTime_DIR}/src/components/motor/MotorController.h
|
||||||
|
${InfiniTime_DIR}/src/components/motor/MotorController.cpp
|
||||||
${InfiniTime_DIR}/src/components/timer/TimerController.h
|
${InfiniTime_DIR}/src/components/timer/TimerController.h
|
||||||
${InfiniTime_DIR}/src/components/timer/TimerController.cpp
|
${InfiniTime_DIR}/src/components/timer/TimerController.cpp
|
||||||
${InfiniTime_DIR}/src/drivers/PinMap.h
|
${InfiniTime_DIR}/src/drivers/PinMap.h
|
||||||
|
@ -213,6 +228,38 @@ target_sources(infinisim PUBLIC
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# QCBOR
|
||||||
|
add_library(QCBOR STATIC
|
||||||
|
${InfiniTime_DIR}/src/libs/QCBOR/src/ieee754.c
|
||||||
|
${InfiniTime_DIR}/src/libs/QCBOR/src/qcbor_decode.c
|
||||||
|
${InfiniTime_DIR}/src/libs/QCBOR/src/qcbor_encode.c
|
||||||
|
${InfiniTime_DIR}/src/libs/QCBOR/src/qcbor_err_to_str.c
|
||||||
|
${InfiniTime_DIR}/src/libs/QCBOR/src/UsefulBuf.c)
|
||||||
|
target_include_directories(QCBOR SYSTEM PUBLIC ${InfiniTime_DIR}/src/libs/QCBOR/inc)
|
||||||
|
# This is required with the current configuration
|
||||||
|
target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_FLOAT_HW_USE)
|
||||||
|
# These are for space-saving
|
||||||
|
target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_PREFERRED_FLOAT)
|
||||||
|
target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_EXP_AND_MANTISSA)
|
||||||
|
target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS)
|
||||||
|
#target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS)
|
||||||
|
target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_UNCOMMON_TAGS)
|
||||||
|
target_compile_definitions(QCBOR PUBLIC USEFULBUF_CONFIG_LITTLE_ENDIAN)
|
||||||
|
set_target_properties(QCBOR PROPERTIES LINKER_LANGUAGE C)
|
||||||
|
#target_compile_options(QCBOR PRIVATE
|
||||||
|
# $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||||
|
# $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||||
|
# $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||||
|
# )
|
||||||
|
target_link_libraries(infinisim PRIVATE QCBOR)
|
||||||
|
|
||||||
|
if(EXISTS ${InfiniTime_DIR}/src/displayapp/fonts/CMakeLists.txt)
|
||||||
|
# available since https://github.com/InfiniTimeOrg/InfiniTime/pull/1097
|
||||||
|
message(STATUS "add subdirectory ${InfiniTime_DIR}/src/displayapp/fonts for 'infinitime_fonts' target")
|
||||||
|
add_subdirectory(${InfiniTime_DIR}/src/displayapp/fonts fonts)
|
||||||
|
target_link_libraries(infinisim PRIVATE infinitime_fonts)
|
||||||
|
endif()
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
# Special case for SDL2 dependency, goal is to find a config that exports SDL2::SDL2 target
|
# Special case for SDL2 dependency, goal is to find a config that exports SDL2::SDL2 target
|
||||||
# libsdl2-dev has a `sdl2-config.cmake` that doesn't export this, but vcpkg does..
|
# libsdl2-dev has a `sdl2-config.cmake` that doesn't export this, but vcpkg does..
|
||||||
|
@ -236,6 +283,8 @@ option(WITH_PNG "Compile with libpng support to dump current screen as png" ON)
|
||||||
if(WITH_PNG)
|
if(WITH_PNG)
|
||||||
target_compile_definitions(infinisim PRIVATE WITH_PNG)
|
target_compile_definitions(infinisim PRIVATE WITH_PNG)
|
||||||
add_subdirectory(libpng EXCLUDE_FROM_ALL)
|
add_subdirectory(libpng EXCLUDE_FROM_ALL)
|
||||||
|
target_include_directories(infinisim PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
target_include_directories(infinisim PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/libpng")
|
||||||
target_link_libraries(infinisim PRIVATE png_static)
|
target_link_libraries(infinisim PRIVATE png_static)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 8f436e1d74ffdd497c68dc2f34f6a67e430a1932
|
Subproject commit e54d78a04b42264770cf25dc2bb2952c7618b764
|
19
README.md
19
README.md
|
@ -14,17 +14,30 @@ For a history on how this simulator started and the challenges on its way visit
|
||||||
- CMake
|
- CMake
|
||||||
- SDL2 (provides the simulator window, handles mouse and keyboard input)
|
- SDL2 (provides the simulator window, handles mouse and keyboard input)
|
||||||
- Compiler (g++ or clang++)
|
- Compiler (g++ or clang++)
|
||||||
|
- [lv_font_conv](https://github.com/lvgl/lv_font_conv#install-the-script) (for `font.c` generation since [InfiniTime#1097](https://github.com/InfiniTimeOrg/InfiniTime/pull/1097))
|
||||||
|
|
||||||
On Ubuntu/Debian install the following packages:
|
On Ubuntu/Debian install the following packages:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo apt install -y cmake libsdl2-dev g++
|
sudo apt install -y cmake libsdl2-dev g++ npm
|
||||||
```
|
```
|
||||||
|
|
||||||
On Arch Linux the following packages are needed:
|
On Arch Linux the following packages are needed:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo pacman -S cmake sdl2 gcc
|
sudo pacman -S cmake sdl2 gcc npm
|
||||||
|
```
|
||||||
|
|
||||||
|
On Fedora the following packages are needed:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo dnf install cmake SDL2-devel gcc
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install the `lv_font_conv` executable to the source directory (will be installed at `node_modules/.bin/lv_font_conv`)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install lv_font_conv@1.5.2
|
||||||
```
|
```
|
||||||
|
|
||||||
## Get the Sources
|
## Get the Sources
|
||||||
|
@ -83,7 +96,7 @@ Using the keyboard the following events can be triggered:
|
||||||
- `m` ... let motor run for 100 ms
|
- `m` ... let motor run for 100 ms
|
||||||
- `M` ... let motor run for 255 ms
|
- `M` ... let motor run for 255 ms
|
||||||
- `n` ... send notification
|
- `n` ... send notification
|
||||||
- `N` ... clear all notifications
|
- `N` ... clear new notification flag
|
||||||
- `b` ... connect Bluetooth
|
- `b` ... connect Bluetooth
|
||||||
- `B` ... disconnect Bluetooth
|
- `B` ... disconnect Bluetooth
|
||||||
- `v` ... increase battery voltage and percentage
|
- `v` ... increase battery voltage and percentage
|
||||||
|
|
51
main.cpp
51
main.cpp
|
@ -51,6 +51,7 @@
|
||||||
#include "displayapp/LittleVgl.h"
|
#include "displayapp/LittleVgl.h"
|
||||||
|
|
||||||
#include <nrfx_gpiote.h>
|
#include <nrfx_gpiote.h>
|
||||||
|
#include <hal/nrf_gpio.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
@ -61,7 +62,7 @@
|
||||||
#include <date/date.h>
|
#include <date/date.h>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#if defined(WITH_PNG)
|
#if defined(WITH_PNG)
|
||||||
#include <libpng16/png.h>
|
#include <libpng/png.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
|
@ -224,7 +225,7 @@ Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn};
|
||||||
Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand};
|
Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand};
|
||||||
|
|
||||||
Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn};
|
Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn};
|
||||||
Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi};
|
Pinetime::Drivers::SpiNorFlash spiNorFlash {"spiNorFlash.raw"};
|
||||||
|
|
||||||
// The TWI device should work @ up to 400Khz but there is a HW bug which prevent it from
|
// The TWI device should work @ up to 400Khz but there is a HW bug which prevent it from
|
||||||
// respecting correct timings. According to erratas heet, this magic value makes it run
|
// respecting correct timings. According to erratas heet, this magic value makes it run
|
||||||
|
@ -252,7 +253,7 @@ Pinetime::Controllers::Ble bleController;
|
||||||
Pinetime::Controllers::HeartRateController heartRateController;
|
Pinetime::Controllers::HeartRateController heartRateController;
|
||||||
Pinetime::Applications::HeartRateTask heartRateApp(heartRateSensor, heartRateController);
|
Pinetime::Applications::HeartRateTask heartRateApp(heartRateSensor, heartRateController);
|
||||||
|
|
||||||
Pinetime::Controllers::FS fs; // {spiNorFlash};
|
Pinetime::Controllers::FS fs {spiNorFlash};
|
||||||
Pinetime::Controllers::Settings settingsController {fs};
|
Pinetime::Controllers::Settings settingsController {fs};
|
||||||
Pinetime::Controllers::MotorController motorController {};
|
Pinetime::Controllers::MotorController motorController {};
|
||||||
|
|
||||||
|
@ -402,19 +403,11 @@ public:
|
||||||
}
|
}
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
{ // motorController.is_ringing
|
|
||||||
constexpr const int center_x = 15;
|
|
||||||
constexpr const int center_y = 15;
|
|
||||||
if (motorController.is_ringing) {
|
|
||||||
draw_circle_red(center_x, center_y, 15);
|
|
||||||
} else {
|
|
||||||
draw_circle_grey(center_x, center_y, 15);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{ // motorController.motor_is_running
|
{ // motorController.motor_is_running
|
||||||
constexpr const int center_x = 45;
|
constexpr const int center_x = 45;
|
||||||
constexpr const int center_y = 15;
|
constexpr const int center_y = 15;
|
||||||
if (motorController.motor_is_running) {
|
bool motor_is_running = nrf_gpio_pin_read(Pinetime::PinMap::Motor);
|
||||||
|
if (motor_is_running) {
|
||||||
draw_circle_red(center_x, center_y, 15);
|
draw_circle_red(center_x, center_y, 15);
|
||||||
} else {
|
} else {
|
||||||
draw_circle_grey(center_x, center_y, 15);
|
draw_circle_grey(center_x, center_y, 15);
|
||||||
|
@ -515,7 +508,7 @@ public:
|
||||||
notificationManager.Push(std::move(notif));
|
notificationManager.Push(std::move(notif));
|
||||||
// send next message the next time
|
// send next message the next time
|
||||||
notification_idx++;
|
notification_idx++;
|
||||||
if (notification_idx >= notification_messages.size()) {
|
if (notification_idx >= notification_messages.size()/2) {
|
||||||
notification_idx = 0;
|
notification_idx = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -773,7 +766,7 @@ public:
|
||||||
private:
|
private:
|
||||||
bool key_handled_r = false; // r ... enable ringing, R ... disable ringing
|
bool key_handled_r = false; // r ... enable ringing, R ... disable ringing
|
||||||
bool key_handled_m = false; // m ... let motor run, M ... stop motor
|
bool key_handled_m = false; // m ... let motor run, M ... stop motor
|
||||||
bool key_handled_n = false; // n ... send notification, N ... clear all notifications
|
bool key_handled_n = false; // n ... send notification, N ... clear new notification flag
|
||||||
bool key_handled_b = false; // b ... connect Bluetooth, B ... disconnect Bluetooth
|
bool key_handled_b = false; // b ... connect Bluetooth, B ... disconnect Bluetooth
|
||||||
bool key_handled_v = false; // battery Voltage and percentage, v ... increase, V ... decrease
|
bool key_handled_v = false; // battery Voltage and percentage, v ... increase, V ... decrease
|
||||||
bool key_handled_c = false; // c ... charging, C ... not charging
|
bool key_handled_c = false; // c ... charging, C ... not charging
|
||||||
|
@ -837,6 +830,8 @@ int main(int argc, char **argv)
|
||||||
/*Initialize the HAL (display, input devices, tick) for LVGL*/
|
/*Initialize the HAL (display, input devices, tick) for LVGL*/
|
||||||
hal_init();
|
hal_init();
|
||||||
|
|
||||||
|
fs.Init();
|
||||||
|
|
||||||
// initialize the core of our Simulator
|
// initialize the core of our Simulator
|
||||||
Framework fw(fw_status_window_visible, 240,240);
|
Framework fw(fw_status_window_visible, 240,240);
|
||||||
|
|
||||||
|
@ -868,21 +863,21 @@ static void hal_init(void)
|
||||||
SDL_CreateThread(tick_thread, "tick", NULL);
|
SDL_CreateThread(tick_thread, "tick", NULL);
|
||||||
|
|
||||||
// use pinetime_theme
|
// use pinetime_theme
|
||||||
lv_theme_t* th = lv_pinetime_theme_init(
|
//lv_theme_t* th = lv_pinetime_theme_init(
|
||||||
LV_COLOR_WHITE, LV_COLOR_SILVER, 0, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20);
|
// LV_COLOR_WHITE, LV_COLOR_SILVER, 0, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20, &jetbrains_mono_bold_20);
|
||||||
lv_theme_set_act(th);
|
//lv_theme_set_act(th);
|
||||||
|
|
||||||
/*Create a display buffer*/
|
///*Create a display buffer*/
|
||||||
static lv_disp_buf_t disp_buf1;
|
//static lv_disp_buf_t disp_buf1;
|
||||||
static lv_color_t buf1_1[LV_HOR_RES_MAX * 120];
|
//static lv_color_t buf1_1[LV_HOR_RES_MAX * 120];
|
||||||
lv_disp_buf_init(&disp_buf1, buf1_1, NULL, LV_HOR_RES_MAX * 120);
|
//lv_disp_buf_init(&disp_buf1, buf1_1, NULL, LV_HOR_RES_MAX * 120);
|
||||||
|
|
||||||
/*Create a display*/
|
///*Create a display*/
|
||||||
lv_disp_drv_t disp_drv;
|
//lv_disp_drv_t disp_drv;
|
||||||
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
//lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
||||||
disp_drv.buffer = &disp_buf1;
|
//disp_drv.buffer = &disp_buf1;
|
||||||
disp_drv.flush_cb = monitor_flush;
|
//disp_drv.flush_cb = monitor_flush;
|
||||||
lv_disp_drv_register(&disp_drv);
|
//lv_disp_drv_register(&disp_drv);
|
||||||
|
|
||||||
/* Add the mouse as input device
|
/* Add the mouse as input device
|
||||||
* Use the 'mouse' driver which reads the PC's mouse*/
|
* Use the 'mouse' driver which reads the PC's mouse*/
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/* Copyright (C) 2021 Adam Pigg
|
||||||
|
|
||||||
|
This file is part of InfiniTime.
|
||||||
|
|
||||||
|
InfiniTime is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
InfiniTime is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "components/ble/AgendaService.h"
|
||||||
|
|
||||||
|
#include "systemtask/SystemTask.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/*
|
||||||
|
// 3fdaYYXX-e246-472e-b7e0-d2b0f3d9c17a
|
||||||
|
constexpr ble_uuid128_t CharUuid(uint8_t x, uint8_t y) {
|
||||||
|
return ble_uuid128_t {.u = {.type = BLE_UUID_TYPE_128},
|
||||||
|
.value = {0x7a, 0xc1, 0xd9, 0xf3, 0xb0, 0xd2, 0xe0, 0xb7, 0x2e, 0x47, 0x46, 0xe2, x, y, 0xda, 0x3f}};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 00010000-78fc-48fe-8e23-433b3a1942d0
|
||||||
|
constexpr ble_uuid128_t BaseUuid() {
|
||||||
|
return CharUuid(0x00, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ble_uuid128_t agendaUuid {BaseUuid()};
|
||||||
|
|
||||||
|
constexpr ble_uuid128_t agendaItemCharUuid {CharUuid(0x01, 0x00)};
|
||||||
|
|
||||||
|
int AgendaCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||||
|
auto agendaService = static_cast<Pinetime::Controllers::AgendaService*>(arg);
|
||||||
|
return agendaService->OnCommand(conn_handle, attr_handle, ctxt);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
Pinetime::Controllers::AgendaService::AgendaService(Pinetime::System::SystemTask& system) : m_system(system) {
|
||||||
|
/*
|
||||||
|
characteristicDefinition[0] = {.uuid = &agendaItemCharUuid.u,
|
||||||
|
.access_cb = AgendaCallback,
|
||||||
|
.arg = this,
|
||||||
|
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||||
|
|
||||||
|
characteristicDefinition[1] = {0};
|
||||||
|
|
||||||
|
serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &agendaUuid.u, .characteristics = characteristicDefinition};
|
||||||
|
serviceDefinition[1] = {0};
|
||||||
|
*/
|
||||||
|
m_agenda_times[0] = 1655327841;
|
||||||
|
m_agenda_pieces[0] = "Write AgendaService";
|
||||||
|
|
||||||
|
m_agenda_times[1] = 1655369999;
|
||||||
|
m_agenda_pieces[1] = "WTF C++ dates";
|
||||||
|
|
||||||
|
m_agenda_times[2] = 1655370699;
|
||||||
|
m_agenda_pieces[2] = "??? work ???";
|
||||||
|
|
||||||
|
m_agenda_times[3] = 1655380699;
|
||||||
|
m_agenda_pieces[3] = "??? stuff ???";
|
||||||
|
|
||||||
|
m_agenda_times[4] = 1655381699;
|
||||||
|
m_agenda_pieces[4] = "WTF C++ dates";
|
||||||
|
|
||||||
|
m_agenda_times[5] = 1655382699;
|
||||||
|
m_agenda_pieces[5] = "??? work ???";
|
||||||
|
|
||||||
|
m_agenda_times[6] = 1655493699;
|
||||||
|
m_agenda_pieces[6] = "??? stuff ???";
|
||||||
|
|
||||||
|
m_agenda_times[7] = 1655497999;
|
||||||
|
m_agenda_pieces[7] = "??? stuff ???";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pinetime::Controllers::AgendaService::Init() {
|
||||||
|
/*
|
||||||
|
int res = 0;
|
||||||
|
res = ble_gatts_count_cfg(serviceDefinition);
|
||||||
|
ASSERT(res == 0);
|
||||||
|
|
||||||
|
res = ble_gatts_add_svcs(serviceDefinition);
|
||||||
|
ASSERT(res == 0);
|
||||||
|
|
||||||
|
m_agenda_times[0] = 1655327841;
|
||||||
|
m_agenda_pieces[0] = "Write AgendaService";
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int Pinetime::Controllers::AgendaService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||||
|
|
||||||
|
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||||
|
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
|
||||||
|
uint8_t data[notifSize + 1];
|
||||||
|
data[notifSize] = '\0';
|
||||||
|
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
|
||||||
|
char* s = (char*) &data[0];
|
||||||
|
if (ble_uuid_cmp(ctxt->chr->uuid, &agendaItemCharUuid.u) == 0) {
|
||||||
|
if (notifSize >= 5) {
|
||||||
|
uint8_t itemIndex = (uint8_t) data[0];
|
||||||
|
uint32_t itemTime = ((uint32_t) data[1]) << 24 | ((uint32_t) data[2]) << 16 | ((uint32_t) data[3]) << 8 | ((uint32_t) data[4]);
|
||||||
|
char* sAgendaItem = (char*) &data[5];
|
||||||
|
if (itemIndex <= 15) { // don't allow a buffer overflow
|
||||||
|
m_agenda_times = itemTime;
|
||||||
|
// implicit std::string copy/conversion here:
|
||||||
|
m_agenda_pieces = sAgendaItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
uint32_t Pinetime::Controllers::AgendaService::getAgendaTime(uint8_t index) {
|
||||||
|
if (index <= AGENDA_CAPACITY) {
|
||||||
|
return m_agenda_times[index];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Pinetime::Controllers::AgendaService::getAgendaPiece(uint8_t index) {
|
||||||
|
if (index <= AGENDA_CAPACITY) {
|
||||||
|
return m_agenda_pieces[index];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/* Copyright (C) 2021 Adam Pigg
|
||||||
|
|
||||||
|
This file is part of InfiniTime.
|
||||||
|
|
||||||
|
InfiniTime is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
InfiniTime is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
// #define min // workaround: nimble's min/max macros conflict with libstdc++
|
||||||
|
// #define max
|
||||||
|
// #include <host/ble_gap.h>
|
||||||
|
// #include <host/ble_uuid.h>
|
||||||
|
// #undef max
|
||||||
|
// #undef min
|
||||||
|
|
||||||
|
namespace Pinetime {
|
||||||
|
namespace System {
|
||||||
|
class SystemTask;
|
||||||
|
}
|
||||||
|
namespace Controllers {
|
||||||
|
|
||||||
|
class AgendaService {
|
||||||
|
public:
|
||||||
|
static const uint8_t AGENDA_CAPACITY = 30;
|
||||||
|
|
||||||
|
explicit AgendaService(Pinetime::System::SystemTask& system);
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
// int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||||
|
|
||||||
|
uint32_t getAgendaTime(uint8_t index);
|
||||||
|
|
||||||
|
std::string getAgendaPiece(uint8_t index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// struct ble_gatt_chr_def characteristicDefinition[2];
|
||||||
|
// struct ble_gatt_svc_def serviceDefinition[2];
|
||||||
|
|
||||||
|
uint32_t m_agenda_times[AGENDA_CAPACITY];
|
||||||
|
std::string m_agenda_pieces[AGENDA_CAPACITY];
|
||||||
|
|
||||||
|
Pinetime::System::SystemTask& m_system;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,6 +45,7 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
|
||||||
// currentTimeService {dateTimeController},
|
// currentTimeService {dateTimeController},
|
||||||
musicService {systemTask},
|
musicService {systemTask},
|
||||||
weatherService {systemTask, dateTimeController},
|
weatherService {systemTask, dateTimeController},
|
||||||
|
agendaService {systemTask},
|
||||||
navService {systemTask} {
|
navService {systemTask} {
|
||||||
// batteryInformationService {batteryController},
|
// batteryInformationService {batteryController},
|
||||||
// immediateAlertService {systemTask, notificationManager},
|
// immediateAlertService {systemTask, notificationManager},
|
||||||
|
@ -92,6 +93,7 @@ void NimbleController::Init() {
|
||||||
musicService.Init();
|
musicService.Init();
|
||||||
weatherService.Init();
|
weatherService.Init();
|
||||||
navService.Init();
|
navService.Init();
|
||||||
|
agendaService.Init();
|
||||||
// anService.Init();
|
// anService.Init();
|
||||||
// dfuService.Init();
|
// dfuService.Init();
|
||||||
// batteryInformationService.Init();
|
// batteryInformationService.Init();
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
//#include "components/ble/ImmediateAlertService.h"
|
//#include "components/ble/ImmediateAlertService.h"
|
||||||
#include "components/ble/MusicService.h"
|
#include "components/ble/MusicService.h"
|
||||||
#include "components/ble/NavigationService.h"
|
#include "components/ble/NavigationService.h"
|
||||||
|
#include "components/ble/AgendaService.h"
|
||||||
//#include "components/ble/ServiceDiscovery.h"
|
//#include "components/ble/ServiceDiscovery.h"
|
||||||
//#include "components/ble/MotionService.h"
|
//#include "components/ble/MotionService.h"
|
||||||
#include "components/ble/weather/WeatherService.h"
|
#include "components/ble/weather/WeatherService.h"
|
||||||
|
@ -75,6 +76,9 @@ namespace Pinetime {
|
||||||
Pinetime::Controllers::NavigationService& navigation() {
|
Pinetime::Controllers::NavigationService& navigation() {
|
||||||
return navService;
|
return navService;
|
||||||
};
|
};
|
||||||
|
Pinetime::Controllers::AgendaService& agenda() {
|
||||||
|
return agendaService;
|
||||||
|
};
|
||||||
Pinetime::Controllers::AlertNotificationService& alertService() {
|
Pinetime::Controllers::AlertNotificationService& alertService() {
|
||||||
return anService;
|
return anService;
|
||||||
};
|
};
|
||||||
|
@ -113,6 +117,7 @@ namespace Pinetime {
|
||||||
MusicService musicService;
|
MusicService musicService;
|
||||||
WeatherService weatherService;
|
WeatherService weatherService;
|
||||||
NavigationService navService;
|
NavigationService navService;
|
||||||
|
AgendaService agendaService;
|
||||||
// BatteryInformationService batteryInformationService;
|
// BatteryInformationService batteryInformationService;
|
||||||
// ImmediateAlertService immediateAlertService;
|
// ImmediateAlertService immediateAlertService;
|
||||||
// HeartRateService heartRateService;
|
// HeartRateService heartRateService;
|
||||||
|
|
|
@ -1,250 +0,0 @@
|
||||||
#include "FS.h"
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstring>
|
|
||||||
#include <filesystem>
|
|
||||||
//#include <littlefs/lfs.h>
|
|
||||||
#include <lvgl/lvgl.h>
|
|
||||||
|
|
||||||
using namespace Pinetime::Controllers;
|
|
||||||
|
|
||||||
//FS::FS(Pinetime::Drivers::SpiNorFlash& driver)
|
|
||||||
// : flashDriver {driver},
|
|
||||||
// lfsConfig {
|
|
||||||
// .context = this,
|
|
||||||
// .read = SectorRead,
|
|
||||||
// .prog = SectorProg,
|
|
||||||
// .erase = SectorErase,
|
|
||||||
// .sync = SectorSync,
|
|
||||||
//
|
|
||||||
// .read_size = 16,
|
|
||||||
// .prog_size = 8,
|
|
||||||
// .block_size = blockSize,
|
|
||||||
// .block_count = size / blockSize,
|
|
||||||
// .block_cycles = 1000u,
|
|
||||||
//
|
|
||||||
// .cache_size = 16,
|
|
||||||
// .lookahead_size = 16,
|
|
||||||
//
|
|
||||||
// .name_max = 50,
|
|
||||||
// .attr_max = 50,
|
|
||||||
// } {
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
void FS::Init() {
|
|
||||||
|
|
||||||
// // try mount
|
|
||||||
// int err = lfs_mount(&lfs, &lfsConfig);
|
|
||||||
//
|
|
||||||
// // reformat if we can't mount the filesystem
|
|
||||||
// // this should only happen on the first boot
|
|
||||||
// if (err != LFS_ERR_OK) {
|
|
||||||
// lfs_format(&lfs, &lfsConfig);
|
|
||||||
// err = lfs_mount(&lfs, &lfsConfig);
|
|
||||||
// if (err != LFS_ERR_OK) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//#ifndef PINETIME_IS_RECOVERY
|
|
||||||
// VerifyResource();
|
|
||||||
// LVGLFileSystemInit();
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void FS::VerifyResource() {
|
|
||||||
// validate the resource metadata
|
|
||||||
resourcesValid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FS::FileOpen(lfs_file_t* file_p, const char* fileName, const int flags) {
|
|
||||||
// create the file in the current directory
|
|
||||||
const char *local_filename = fileName[0]=='/' ? &fileName[1] : fileName;
|
|
||||||
const char *mode;
|
|
||||||
bool flag_read = flags & LFS_O_RDONLY;
|
|
||||||
bool flag_write = flags & LFS_O_WRONLY;
|
|
||||||
bool flag_create = flags & LFS_O_CREAT;
|
|
||||||
if (flag_create) {
|
|
||||||
if (std::filesystem::exists(local_filename)) {
|
|
||||||
if (flag_read && flag_write) {
|
|
||||||
mode = "rb+";
|
|
||||||
} else if (flag_read) {
|
|
||||||
mode = "rb";
|
|
||||||
} else if (flag_write) {
|
|
||||||
mode = "wb";
|
|
||||||
} else {
|
|
||||||
assert(false); // not implemented
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (flag_read && flag_write) {
|
|
||||||
mode = "wb+";
|
|
||||||
} else if (flag_read) {
|
|
||||||
assert(false); // read only file not existing
|
|
||||||
mode = "rb";
|
|
||||||
} else if (flag_write) {
|
|
||||||
mode = "wb";
|
|
||||||
} else {
|
|
||||||
assert(false); // not implemented
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (std::filesystem::exists(local_filename)) {
|
|
||||||
if (flag_read && flag_write) {
|
|
||||||
mode = "rb+";
|
|
||||||
} else if (flag_read) {
|
|
||||||
mode = "rb";
|
|
||||||
} else if (flag_write) {
|
|
||||||
mode = "wb";
|
|
||||||
} else {
|
|
||||||
assert(false); // not implemented
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return LFS_ERR_IO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FILE *fptr = fopen(local_filename, mode);
|
|
||||||
if (fptr == nullptr) {
|
|
||||||
return LFS_ERR_BADF;
|
|
||||||
} else {
|
|
||||||
*file_p = fptr;
|
|
||||||
return LFS_ERR_OK;
|
|
||||||
}
|
|
||||||
//return lfs_file_open(&lfs, file_p, fileName, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
int FS::FileClose(lfs_file_t* file_p) {
|
|
||||||
return fclose(*file_p);
|
|
||||||
//return lfs_file_close(&lfs, file_p);
|
|
||||||
}
|
|
||||||
|
|
||||||
int FS::FileRead(lfs_file_t* file_p, uint8_t* buff, uint32_t size) {
|
|
||||||
return fread(buff, sizeof(uint8_t), size, *file_p);
|
|
||||||
//return lfs_file_read(&lfs, file_p, buff, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int FS::FileWrite(lfs_file_t* file_p, const uint8_t* buff, uint32_t size) {
|
|
||||||
return fwrite((void*)buff, sizeof(uint8_t), size, *file_p);
|
|
||||||
//return lfs_file_write(&lfs, file_p, buff, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int FS::FileSeek(lfs_file_t* file_p, uint32_t pos) {
|
|
||||||
return fseek(*file_p, pos, SEEK_SET);
|
|
||||||
//return lfs_file_seek(&lfs, file_p, pos, whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
int FS::FileDelete(const char* fileName) {
|
|
||||||
return std::filesystem::remove(fileName);
|
|
||||||
//return lfs_remove(&lfs, fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int FS::DirCreate(const char* path) {
|
|
||||||
return std::filesystem::create_directory(path);
|
|
||||||
//return lfs_mkdir(&lfs, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete directory and all files inside
|
|
||||||
int FS::DirDelete(const char* path) {
|
|
||||||
return std::filesystem::remove_all(path);
|
|
||||||
|
|
||||||
//lfs_dir_t lfs_dir;
|
|
||||||
//lfs_info entryInfo;
|
|
||||||
|
|
||||||
//int err;
|
|
||||||
//err = lfs_dir_open(&lfs, &lfs_dir, path);
|
|
||||||
//if (err) {
|
|
||||||
// return err;
|
|
||||||
//}
|
|
||||||
//while (lfs_dir_read(&lfs, &lfs_dir, &entryInfo)) {
|
|
||||||
// lfs_remove(&lfs, entryInfo.name);
|
|
||||||
//}
|
|
||||||
//lfs_dir_close(&lfs, &lfs_dir);
|
|
||||||
//return LFS_ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
----------- Interface between littlefs and SpiNorFlash -----------
|
|
||||||
|
|
||||||
*/
|
|
||||||
//int FS::SectorSync(const struct lfs_config* c) {
|
|
||||||
// return 0;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//int FS::SectorErase(const struct lfs_config* c, lfs_block_t block) {
|
|
||||||
// Pinetime::Controllers::FS& lfs = *(static_cast<Pinetime::Controllers::FS*>(c->context));
|
|
||||||
// const size_t address = startAddress + (block * blockSize);
|
|
||||||
// lfs.flashDriver.SectorErase(address);
|
|
||||||
// return lfs.flashDriver.EraseFailed() ? -1 : 0;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//int FS::SectorProg(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size) {
|
|
||||||
// Pinetime::Controllers::FS& lfs = *(static_cast<Pinetime::Controllers::FS*>(c->context));
|
|
||||||
// const size_t address = startAddress + (block * blockSize) + off;
|
|
||||||
// lfs.flashDriver.Write(address, (uint8_t*) buffer, size);
|
|
||||||
// return lfs.flashDriver.ProgramFailed() ? -1 : 0;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//int FS::SectorRead(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, void* buffer, lfs_size_t size) {
|
|
||||||
// Pinetime::Controllers::FS& lfs = *(static_cast<Pinetime::Controllers::FS*>(c->context));
|
|
||||||
// const size_t address = startAddress + (block * blockSize) + off;
|
|
||||||
// lfs.flashDriver.Read(address, static_cast<uint8_t*>(buffer), size);
|
|
||||||
// return 0;
|
|
||||||
//}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
----------- LVGL filesystem integration -----------
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
lv_fs_res_t lvglOpen(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode) {
|
|
||||||
|
|
||||||
lfs_file_t* file = static_cast<lfs_file_t*>(file_p);
|
|
||||||
FS* filesys = static_cast<FS*>(drv->user_data);
|
|
||||||
int ret = filesys->FileOpen(file, path, LFS_O_RDONLY);
|
|
||||||
if (ret != LFS_ERR_OK) {
|
|
||||||
return LV_FS_RES_FS_ERR;
|
|
||||||
}
|
|
||||||
return LV_FS_RES_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
lv_fs_res_t lvglClose(lv_fs_drv_t* drv, void* file_p) {
|
|
||||||
FS* filesys = static_cast<FS*>(drv->user_data);
|
|
||||||
lfs_file_t* file = static_cast<lfs_file_t*>(file_p);
|
|
||||||
filesys->FileClose(file);
|
|
||||||
|
|
||||||
return LV_FS_RES_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
lv_fs_res_t lvglRead(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br) {
|
|
||||||
FS* filesys = static_cast<FS*>(drv->user_data);
|
|
||||||
lfs_file_t* file = static_cast<lfs_file_t*>(file_p);
|
|
||||||
filesys->FileRead(file, static_cast<uint8_t*>(buf), btr);
|
|
||||||
*br = btr;
|
|
||||||
return LV_FS_RES_OK;
|
|
||||||
}
|
|
||||||
lv_fs_res_t lvglSeek(lv_fs_drv_t* drv, void* file_p, uint32_t pos) {
|
|
||||||
FS* filesys = static_cast<FS*>(drv->user_data);
|
|
||||||
lfs_file_t* file = static_cast<lfs_file_t*>(file_p);
|
|
||||||
filesys->FileSeek(file, pos);
|
|
||||||
return LV_FS_RES_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FS::LVGLFileSystemInit() {
|
|
||||||
lv_fs_drv_init(&fs_drv);
|
|
||||||
|
|
||||||
fs_drv.file_size = sizeof(lfs_file_t);
|
|
||||||
fs_drv.letter = 'F';
|
|
||||||
fs_drv.open_cb = lvglOpen;
|
|
||||||
fs_drv.close_cb = lvglClose;
|
|
||||||
fs_drv.read_cb = lvglRead;
|
|
||||||
fs_drv.seek_cb = lvglSeek;
|
|
||||||
|
|
||||||
fs_drv.user_data = this;
|
|
||||||
|
|
||||||
lv_fs_drv_register(&fs_drv);
|
|
||||||
}
|
|
|
@ -1,134 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdint>
|
|
||||||
//#include "drivers/SpiNorFlash.h"
|
|
||||||
//#include <littlefs/lfs.h>
|
|
||||||
#include <lvgl/lvgl.h>
|
|
||||||
|
|
||||||
using lfs_file_t = FILE*;
|
|
||||||
|
|
||||||
// copied from src/libs/littlefs/lfs.h
|
|
||||||
// Possible error codes, these are negative to allow
|
|
||||||
// valid positive return values
|
|
||||||
enum lfs_error {
|
|
||||||
LFS_ERR_OK = 0, // No error
|
|
||||||
LFS_ERR_IO = -5, // Error during device operation
|
|
||||||
LFS_ERR_CORRUPT = -84, // Corrupted
|
|
||||||
LFS_ERR_NOENT = -2, // No directory entry
|
|
||||||
LFS_ERR_EXIST = -17, // Entry already exists
|
|
||||||
LFS_ERR_NOTDIR = -20, // Entry is not a dir
|
|
||||||
LFS_ERR_ISDIR = -21, // Entry is a dir
|
|
||||||
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
|
|
||||||
LFS_ERR_BADF = -9, // Bad file number
|
|
||||||
LFS_ERR_FBIG = -27, // File too large
|
|
||||||
LFS_ERR_INVAL = -22, // Invalid parameter
|
|
||||||
LFS_ERR_NOSPC = -28, // No space left on device
|
|
||||||
LFS_ERR_NOMEM = -12, // No more memory available
|
|
||||||
LFS_ERR_NOATTR = -61, // No data/attr available
|
|
||||||
LFS_ERR_NAMETOOLONG = -36, // File name too long
|
|
||||||
};
|
|
||||||
|
|
||||||
enum lfs_open_flags {
|
|
||||||
// open flags
|
|
||||||
LFS_O_RDONLY = 1, // Open a file as read only
|
|
||||||
#ifndef LFS_READONLY
|
|
||||||
LFS_O_WRONLY = 2, // Open a file as write only
|
|
||||||
LFS_O_RDWR = 3, // Open a file as read and write
|
|
||||||
LFS_O_CREAT = 0x0100, // Create a file if it does not exist
|
|
||||||
LFS_O_EXCL = 0x0200, // Fail if a file already exists
|
|
||||||
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
|
|
||||||
LFS_O_APPEND = 0x0800, // Move to end of file on every write
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
// File seek flags
|
|
||||||
enum lfs_whence_flags {
|
|
||||||
LFS_SEEK_SET = 0, // Seek relative to an absolute position
|
|
||||||
LFS_SEEK_CUR = 1, // Seek relative to the current file position
|
|
||||||
LFS_SEEK_END = 2, // Seek relative to the end of the file
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef int32_t lfs_ssize_t;
|
|
||||||
|
|
||||||
namespace Pinetime {
|
|
||||||
namespace Controllers {
|
|
||||||
class FS {
|
|
||||||
public:
|
|
||||||
//FS(Pinetime::Drivers::SpiNorFlash&);
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
void LVGLFileSystemInit();
|
|
||||||
|
|
||||||
int FileOpen(lfs_file_t* file_p, const char* fileName, const int flags);
|
|
||||||
int FileClose(lfs_file_t* file_p);
|
|
||||||
int FileRead(lfs_file_t* file_p, uint8_t* buff, uint32_t size);
|
|
||||||
int FileWrite(lfs_file_t* file_p, const uint8_t* buff, uint32_t size);
|
|
||||||
int FileSeek(lfs_file_t* file_p, uint32_t pos);
|
|
||||||
|
|
||||||
int FileDelete(const char* fileName);
|
|
||||||
|
|
||||||
//int DirOpen(const char* path, lfs_dir_t* lfs_dir);
|
|
||||||
//int DirClose(lfs_dir_t* lfs_dir);
|
|
||||||
//int DirRead(lfs_dir_t* dir, lfs_info* info);
|
|
||||||
//int DirRewind(lfs_dir_t* dir);
|
|
||||||
int DirCreate(const char* path);
|
|
||||||
int DirDelete(const char* path);
|
|
||||||
|
|
||||||
lfs_ssize_t GetFSSize();
|
|
||||||
int Rename(const char* oldPath, const char* newPath);
|
|
||||||
//int Stat(const char* path, lfs_info* info);
|
|
||||||
void VerifyResource();
|
|
||||||
|
|
||||||
static size_t getSize() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
static size_t getBlockSize() {
|
|
||||||
return blockSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
//Pinetime::Drivers::SpiNorFlash& flashDriver;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* External Flash MAP (4 MBytes)
|
|
||||||
*
|
|
||||||
* 0x000000 +---------------------------------------+
|
|
||||||
* | Bootloader Assets |
|
|
||||||
* | 256 KBytes |
|
|
||||||
* | |
|
|
||||||
* 0x040000 +---------------------------------------+
|
|
||||||
* | OTA |
|
|
||||||
* | 464 KBytes |
|
|
||||||
* | |
|
|
||||||
* | |
|
|
||||||
* | |
|
|
||||||
* 0x0B4000 +---------------------------------------+
|
|
||||||
* | File System |
|
|
||||||
* | |
|
|
||||||
* | |
|
|
||||||
* | |
|
|
||||||
* | |
|
|
||||||
* 0x400000 +---------------------------------------+
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static constexpr size_t startAddress = 0x0B4000;
|
|
||||||
static constexpr size_t size = 0x34C000;
|
|
||||||
static constexpr size_t blockSize = 4096;
|
|
||||||
|
|
||||||
lv_fs_drv_t fs_drv;
|
|
||||||
|
|
||||||
bool resourcesValid = false;
|
|
||||||
//const struct lfs_config lfsConfig;
|
|
||||||
|
|
||||||
//lfs_t lfs;
|
|
||||||
|
|
||||||
//static int SectorSync(const struct lfs_config* c);
|
|
||||||
//static int SectorErase(const struct lfs_config* c, lfs_block_t block);
|
|
||||||
//static int SectorProg(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size);
|
|
||||||
//static int SectorRead(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, void* buffer, lfs_size_t size);
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
#include "components/motor/MotorController.h"
|
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
using namespace Pinetime::Controllers;
|
|
||||||
|
|
||||||
void MotorController::Init() {
|
|
||||||
//nrf_gpio_cfg_output(PinMap::Motor);
|
|
||||||
//nrf_gpio_pin_set(PinMap::Motor);
|
|
||||||
//app_timer_init();
|
|
||||||
|
|
||||||
//app_timer_create(&shortVibTimer, APP_TIMER_MODE_SINGLE_SHOT, StopMotor);
|
|
||||||
//app_timer_create(&longVibTimer, APP_TIMER_MODE_REPEATED, Ring);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MotorController::Ring(void* p_context) {
|
|
||||||
auto* motorController = static_cast<MotorController*>(p_context);
|
|
||||||
motorController->RunForDuration(50);
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint32 StopMotor_callback(Uint32 interval, void *param)
|
|
||||||
{
|
|
||||||
auto* motorController = static_cast<MotorController*>(param);
|
|
||||||
motorController->motor_is_running = false;
|
|
||||||
return 0; // cancel timer
|
|
||||||
}
|
|
||||||
Uint32 Ring_callback(Uint32 interval, void *param)
|
|
||||||
{
|
|
||||||
auto* motorController = static_cast<MotorController*>(param);
|
|
||||||
motorController->RunForDuration(50);
|
|
||||||
if (motorController->is_ringing) {
|
|
||||||
return interval;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
void MotorController::RunForDuration(uint8_t motorDuration) {
|
|
||||||
this->motor_is_running = true;
|
|
||||||
SDL_AddTimer(motorDuration, StopMotor_callback, this);
|
|
||||||
//nrf_gpio_pin_clear(PinMap::Motor);
|
|
||||||
//app_timer_start(shortVibTimer, APP_TIMER_TICKS(motorDuration), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MotorController::StartRinging() {
|
|
||||||
Ring(this);
|
|
||||||
is_ringing = true;
|
|
||||||
SDL_AddTimer(1000, Ring_callback, this);
|
|
||||||
//app_timer_start(longVibTimer, APP_TIMER_TICKS(1000), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MotorController::StopRinging() {
|
|
||||||
is_ringing = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MotorController::StopMotor(void* p_context) {
|
|
||||||
//nrf_gpio_pin_set(PinMap::Motor);
|
|
||||||
auto* motorController = static_cast<MotorController*>(p_context);
|
|
||||||
motorController->motor_is_running = false;
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace Pinetime {
|
|
||||||
namespace Controllers {
|
|
||||||
|
|
||||||
class MotorController {
|
|
||||||
public:
|
|
||||||
MotorController() = default;
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
void RunForDuration(uint8_t motorDuration);
|
|
||||||
void StartRinging();
|
|
||||||
void StopRinging();
|
|
||||||
|
|
||||||
bool motor_is_running = false;
|
|
||||||
bool is_ringing = false;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void Ring(void* p_context);
|
|
||||||
static void StopMotor(void* p_context);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +1,73 @@
|
||||||
#include "displayapp/LittleVgl.h"
|
#include "displayapp/LittleVgl.h"
|
||||||
#include "displayapp/lv_pinetime_theme.h"
|
#include "displayapp/lv_pinetime_theme.h"
|
||||||
|
|
||||||
//#include <FreeRTOS.h>
|
#include <FreeRTOS.h>
|
||||||
//#include <task.h>
|
#include <task.h>
|
||||||
|
#include <timers.h>
|
||||||
////#include <projdefs.h>
|
////#include <projdefs.h>
|
||||||
#include "drivers/Cst816s.h"
|
#include "drivers/Cst816s.h"
|
||||||
#include "drivers/St7789.h"
|
#include "drivers/St7789.h"
|
||||||
|
|
||||||
|
// lv-sim monitor display driver for monitor_flush() function
|
||||||
|
#include "lv_drivers/display/monitor.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
using namespace Pinetime::Components;
|
using namespace Pinetime::Components;
|
||||||
|
|
||||||
//lv_style_t* LabelBigStyle = nullptr;
|
lv_style_t* LabelBigStyle = nullptr;
|
||||||
//
|
|
||||||
//static void disp_flush(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p) {
|
static void disp_flush(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p) {
|
||||||
// auto* lvgl = static_cast<LittleVgl*>(disp_drv->user_data);
|
auto* lvgl = static_cast<LittleVgl*>(disp_drv->user_data);
|
||||||
// lvgl->FlushDisplay(area, color_p);
|
lvgl->FlushDisplay(area, color_p);
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
|
static void rounder(lv_disp_drv_t* disp_drv, lv_area_t* area) {
|
||||||
|
auto* lvgl = static_cast<LittleVgl*>(disp_drv->user_data);
|
||||||
|
if (lvgl->GetFullRefresh()) {
|
||||||
|
area->x1 = 0;
|
||||||
|
area->x2 = LV_HOR_RES - 1;
|
||||||
|
area->y1 = 0;
|
||||||
|
area->y2 = LV_VER_RES - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool touchpad_read(lv_indev_drv_t* indev_drv, lv_indev_data_t* data) {
|
bool touchpad_read(lv_indev_drv_t* indev_drv, lv_indev_data_t* data) {
|
||||||
auto* lvgl = static_cast<LittleVgl*>(indev_drv->user_data);
|
auto* lvgl = static_cast<LittleVgl*>(indev_drv->user_data);
|
||||||
return lvgl->GetTouchPadInfo(data);
|
return lvgl->GetTouchPadInfo(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel)
|
LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel)
|
||||||
: lcd {lcd}, touchPanel {touchPanel}, previousClick {0, 0} {
|
: lcd {lcd}, touchPanel {touchPanel} {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LittleVgl::Init() {
|
void LittleVgl::Init() {
|
||||||
// lv_init();
|
// lv_init();
|
||||||
// InitDisplay();
|
InitTheme();
|
||||||
// InitTheme();
|
InitDisplay();
|
||||||
InitTouchpad();
|
InitTouchpad();
|
||||||
}
|
}
|
||||||
|
|
||||||
//void LittleVgl::InitDisplay() {
|
void LittleVgl::InitDisplay() {
|
||||||
// lv_disp_draw_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 4); /*Initialize the display buffer*/
|
lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 4); /*Initialize the display buffer*/
|
||||||
// lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
||||||
//
|
|
||||||
// /*Set up the functions to access to your display*/
|
/*Set up the functions to access to your display*/
|
||||||
//
|
|
||||||
// /*Set the resolution of the display*/
|
/*Set the resolution of the display*/
|
||||||
// disp_drv.hor_res = 240;
|
disp_drv.hor_res = 240;
|
||||||
// disp_drv.ver_res = 240;
|
disp_drv.ver_res = 240;
|
||||||
//
|
|
||||||
// /*Used to copy the buffer's content to the display*/
|
/*Used to copy the buffer's content to the display*/
|
||||||
// disp_drv.flush_cb = disp_flush;
|
disp_drv.flush_cb = disp_flush;
|
||||||
// /*Set a display buffer*/
|
/*Set a display buffer*/
|
||||||
// disp_drv.draw_buf = &disp_buf_2;
|
disp_drv.buffer = &disp_buf_2;
|
||||||
// disp_drv.user_data = this;
|
disp_drv.user_data = this;
|
||||||
//
|
disp_drv.rounder_cb = rounder;
|
||||||
// /*Finally register the driver*/
|
|
||||||
// lv_disp_drv_register(&disp_drv);
|
/*Finally register the driver*/
|
||||||
//}
|
lv_disp_drv_register(&disp_drv);
|
||||||
|
}
|
||||||
|
|
||||||
void LittleVgl::InitTouchpad() {
|
void LittleVgl::InitTouchpad() {
|
||||||
lv_indev_drv_t indev_drv;
|
lv_indev_drv_t indev_drv;
|
||||||
|
@ -67,239 +83,185 @@ void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
|
||||||
if (scrollDirection == FullRefreshDirections::None) {
|
if (scrollDirection == FullRefreshDirections::None) {
|
||||||
scrollDirection = direction;
|
scrollDirection = direction;
|
||||||
if (scrollDirection == FullRefreshDirections::Down) {
|
if (scrollDirection == FullRefreshDirections::Down) {
|
||||||
lv_disp_set_rotation(lv_disp_get_default(), LV_DISP_ROT_NONE);
|
lv_disp_set_direction(lv_disp_get_default(), 1);
|
||||||
} else if (scrollDirection == FullRefreshDirections::Right) {
|
} else if (scrollDirection == FullRefreshDirections::Right) {
|
||||||
lv_disp_set_rotation(lv_disp_get_default(), LV_DISP_ROT_NONE);
|
lv_disp_set_direction(lv_disp_get_default(), 2);
|
||||||
} else if (scrollDirection == FullRefreshDirections::Left) {
|
} else if (scrollDirection == FullRefreshDirections::Left) {
|
||||||
lv_disp_set_rotation(lv_disp_get_default(), LV_DISP_ROT_NONE);
|
lv_disp_set_direction(lv_disp_get_default(), 3);
|
||||||
} else if (scrollDirection == FullRefreshDirections::RightAnim) {
|
} else if (scrollDirection == FullRefreshDirections::RightAnim) {
|
||||||
lv_disp_set_rotation(lv_disp_get_default(), LV_DISP_ROT_NONE);
|
lv_disp_set_direction(lv_disp_get_default(), 5);
|
||||||
} else if (scrollDirection == FullRefreshDirections::LeftAnim) {
|
} else if (scrollDirection == FullRefreshDirections::LeftAnim) {
|
||||||
lv_disp_set_rotation(lv_disp_get_default(), LV_DISP_ROT_NONE);
|
lv_disp_set_direction(lv_disp_get_default(), 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fullRefresh = true;
|
||||||
}
|
}
|
||||||
//
|
|
||||||
//
|
// glue the lvgl code to the lv-sim monitor driver
|
||||||
//void LittleVgl::DisplayDownScroll(){
|
void DrawBuffer(lv_disp_drv_t *disp_drv, uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t* data, size_t size) {
|
||||||
// // We are controlling the drawing process, disable lvgl timers
|
lv_area_t area;
|
||||||
// lv_timer_enable(false);
|
area.x1 = x;
|
||||||
//
|
area.x2 = x+width-1;
|
||||||
// // For each segment, draw the full width, 4 lines at a time starting from the bottom
|
area.y1 = y;
|
||||||
// // TODO: Should probably calculate this from the size of the draw buffer
|
area.y2 = y+height-1;
|
||||||
// int16_t height = 4;
|
lv_color_t* color_p = reinterpret_cast<lv_color_t*>(data);
|
||||||
// int16_t width = 240;
|
monitor_flush(disp_drv, &area, color_p);
|
||||||
// int16_t y2 = 240;
|
}
|
||||||
// int16_t y1 = 240 - height;
|
|
||||||
//
|
// copied from lv_drivers/display/monitor.c to get the SDL_Window for the InfiniTime screen
|
||||||
// lv_area_t area;
|
extern "C"
|
||||||
// area.x1 = 0;
|
{
|
||||||
// area.x2 = width;
|
typedef struct {
|
||||||
//
|
SDL_Window * window;
|
||||||
// // Start from the bottom and create a 4 line high box
|
SDL_Renderer * renderer;
|
||||||
// for (y1 = 240 - height; y1 >= 0; y1 -= height) {
|
SDL_Texture * texture;
|
||||||
// y2 = y1 + height - 1;
|
volatile bool sdl_refr_qry;
|
||||||
//
|
#if MONITOR_DOUBLE_BUFFERED
|
||||||
// // If the box has reached the end of the visible line on the lcd controller...
|
uint32_t * tft_fb_act;
|
||||||
// if (y2 == visibleNbLines - 1) {
|
#else
|
||||||
// // move past the non visible lines
|
uint32_t tft_fb[LV_HOR_RES_MAX * LV_VER_RES_MAX];
|
||||||
// writeOffset += (totalNbLines - visibleNbLines);
|
#endif
|
||||||
// // and wrap around to the start of address space
|
}monitor_t;
|
||||||
// writeOffset %= totalNbLines;
|
extern monitor_t monitor;
|
||||||
// }
|
}
|
||||||
// // Set new box
|
|
||||||
// area.y1 = y1;
|
// positive height moves screen down (draw y=0 to y=height)
|
||||||
// area.y2 = y2;
|
// negative height moves screen up (draw y=height to y=0)
|
||||||
//
|
void MoveScreen(lv_disp_drv_t *disp_drv, int16_t height) {
|
||||||
// // Scroll as we draw
|
if (height == 0)
|
||||||
// uint16_t toScroll = height;
|
return; // nothing to do
|
||||||
// if (scrollOffset >= toScroll)
|
|
||||||
// scrollOffset -= toScroll;
|
const int sdl_width = 240;
|
||||||
// else { // now we need to wrap the scroll address
|
const int sdl_height = 240;
|
||||||
// toScroll -= scrollOffset;
|
auto renderer = monitor.renderer;
|
||||||
// scrollOffset = totalNbLines - toScroll;
|
|
||||||
// }
|
const Uint32 format = SDL_PIXELFORMAT_RGBA8888;
|
||||||
// lcd.VerticalScrollStartAddress(scrollOffset);
|
SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, sdl_width, sdl_height, 32, format);
|
||||||
//
|
SDL_RenderReadPixels(renderer, NULL, format, surface->pixels, surface->pitch);
|
||||||
// lv_disp_t* disp = lv_disp_get_default();
|
uint8_t *pixels = (uint8_t*) surface->pixels;
|
||||||
// // Clear invalid area list / tells lvgl that nothing on the screen needs to be updated
|
|
||||||
// _lv_inv_area(disp, nullptr);
|
std::array<lv_color16_t, 240*240> color_p;
|
||||||
// // invalidate only the segment we want to update in this portion of the animation
|
for (int hi = 0; hi < sdl_height; hi++) {
|
||||||
// _lv_inv_area(disp, &area);
|
for (int wi = 0; wi < sdl_width; wi++) {
|
||||||
// // cancel any current flushes in the display driver
|
auto red = pixels[hi*surface->pitch + wi*4 + 3]; // red
|
||||||
// // Since we've stopped timers, it will be waiting forever if there is currently a flush
|
auto green = pixels[hi*surface->pitch + wi*4 + 2]; // greeen
|
||||||
// lv_disp_flush_ready(disp->driver);
|
auto blue = pixels[hi*surface->pitch + wi*4 + 1]; // blue
|
||||||
// lv_refr_now(disp);
|
color_p.at(hi * sdl_width + wi) = LV_COLOR_MAKE(red, green, blue);
|
||||||
// }
|
}
|
||||||
// // Done! clear flags and enable timers
|
}
|
||||||
// scrollDirection = FullRefreshDirections::None;
|
int16_t buffer_height = sdl_height - abs(height);
|
||||||
// animating = false;
|
if (height >= 0) {
|
||||||
// lv_timer_enable(true);
|
DrawBuffer(disp_drv, 0, height, sdl_width, sdl_height, (uint8_t*)color_p.data(), sdl_width*buffer_height *2);
|
||||||
//}
|
} else {
|
||||||
//
|
DrawBuffer(disp_drv, 0, 0, sdl_width, sdl_height, (uint8_t*)(&color_p.at(sdl_width*abs(height))), sdl_width*buffer_height *2);
|
||||||
//void LittleVgl::DisplayHorizAnim() {
|
}
|
||||||
// lv_timer_enable(false);
|
}
|
||||||
//
|
|
||||||
// int16_t height, width, x1, x2;
|
|
||||||
// lv_area_t area;
|
|
||||||
//
|
|
||||||
// height = 240;
|
|
||||||
// width = 4;
|
|
||||||
// int16_t (*NextStep)(int16_t, int16_t){};
|
|
||||||
// bool (*CheckEnd)(int16_t){};
|
|
||||||
//
|
|
||||||
// area.y1=0;
|
|
||||||
// area.y2=height;
|
|
||||||
//
|
|
||||||
// if (scrollDirection == FullRefreshDirections::RightAnim) {
|
|
||||||
// x1 = 0;
|
|
||||||
//
|
|
||||||
// CheckEnd = [](int16_t x) -> bool {
|
|
||||||
// return (x < LV_HOR_RES_MAX);
|
|
||||||
// };
|
|
||||||
// NextStep = [](int16_t x, int16_t width) -> int16_t {
|
|
||||||
// auto newx = x + width * 2;
|
|
||||||
// if (newx < 240) {return newx;};
|
|
||||||
// return (newx < 240 + width) ? (newx - 240 + width) : newx;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// } else if (scrollDirection == FullRefreshDirections::LeftAnim) {
|
|
||||||
// x1 = 240 - width;
|
|
||||||
//
|
|
||||||
// CheckEnd = [](int16_t x) -> bool {
|
|
||||||
// return (x >= 0);
|
|
||||||
// };
|
|
||||||
// NextStep = [](int16_t x, int16_t width) -> int16_t {
|
|
||||||
// auto newx = x - width * 2;
|
|
||||||
// if (newx >= 0) {return newx;}
|
|
||||||
// return (newx >= 0 - width) ? (newx + 240 - width) : newx;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// } else {
|
|
||||||
// // Not set for a horizontal animation!
|
|
||||||
// lv_timer_enable(true);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for (; CheckEnd(x1); x1 = NextStep(x1, width)) {
|
|
||||||
// x2 = x1 + width-1;
|
|
||||||
//
|
|
||||||
// if (area.y2 == visibleNbLines - 1) {
|
|
||||||
// writeOffset += (totalNbLines - visibleNbLines);
|
|
||||||
// writeOffset %= totalNbLines;
|
|
||||||
// }
|
|
||||||
// area.x1 = x1;
|
|
||||||
// area.x2 = x2;
|
|
||||||
//
|
|
||||||
// lv_disp_t* disp = lv_disp_get_default();
|
|
||||||
// _lv_inv_area(disp, nullptr);
|
|
||||||
// _lv_inv_area(disp, &area);
|
|
||||||
// lv_disp_flush_ready(disp->driver);
|
|
||||||
// lv_refr_now(disp);
|
|
||||||
// }
|
|
||||||
// scrollDirection = FullRefreshDirections::None;
|
|
||||||
// animating = false;
|
|
||||||
// lv_timer_enable(true);
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//void LittleVgl::FlushDisplayManually() {
|
|
||||||
// switch(scrollDirection){
|
|
||||||
// case FullRefreshDirections::Down:
|
|
||||||
// DisplayDownScroll();
|
|
||||||
// break;
|
|
||||||
// case FullRefreshDirections::RightAnim:
|
|
||||||
// case FullRefreshDirections::LeftAnim:
|
|
||||||
// DisplayHorizAnim();
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
|
void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
|
||||||
// uint16_t y1, y2, width, height = 0;
|
uint16_t y1, y2, width, height = 0;
|
||||||
//
|
|
||||||
//ulTaskNotifyTake(pdTRUE, 200);
|
//ulTaskNotifyTake(pdTRUE, 200);
|
||||||
// // NOtification is still needed (even if there is a mutex on SPI) because of the DataCommand pin
|
// Notification is still needed (even if there is a mutex on SPI) because of the DataCommand pin
|
||||||
// // which cannot be set/clear during a transfert.
|
// which cannot be set/clear during a transfer.
|
||||||
//
|
|
||||||
// if (!animating && (scrollDirection == FullRefreshDirections::Down ||
|
//if ((scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) {
|
||||||
// scrollDirection == FullRefreshDirections::RightAnim ||
|
// writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines;
|
||||||
// scrollDirection == FullRefreshDirections::LeftAnim)){
|
//} else if ((scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0)) {
|
||||||
// animating = true;
|
|
||||||
// FlushDisplayManually();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if ((scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0)) {
|
|
||||||
// writeOffset = (writeOffset + visibleNbLines) % totalNbLines;
|
// writeOffset = (writeOffset + visibleNbLines) % totalNbLines;
|
||||||
//}
|
//}
|
||||||
//
|
|
||||||
// y1 = (area->y1 + writeOffset) % totalNbLines;
|
y1 = (area->y1 + writeOffset) % totalNbLines;
|
||||||
// y2 = (area->y2 + writeOffset) % totalNbLines;
|
y2 = (area->y2 + writeOffset) % totalNbLines;
|
||||||
//
|
|
||||||
// width = (area->x2 - area->x1) + 1;
|
width = (area->x2 - area->x1) + 1;
|
||||||
// height = (area->y2 - area->y1) + 1;
|
height = (area->y2 - area->y1) + 1;
|
||||||
//
|
|
||||||
// if (scrollDirection == FullRefreshDirections::Up) {
|
if (scrollDirection == LittleVgl::FullRefreshDirections::Down) {
|
||||||
//
|
|
||||||
// if (area->y1 > 0) {
|
if (area->y2 < visibleNbLines - 1) {
|
||||||
// if (area->y2 == visibleNbLines - 1) {
|
uint16_t toScroll = 0;
|
||||||
// scrollOffset += (height * 2);
|
if (area->y1 == 0) {
|
||||||
// scrollDirection = FullRefreshDirections::None;
|
toScroll = height * 2;
|
||||||
//// lv_disp_set_rotation(lv_disp_get_default(), LV_DISP_ROT_NONE);
|
scrollDirection = FullRefreshDirections::None;
|
||||||
// } else {
|
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||||
// scrollOffset += height;
|
} else {
|
||||||
// }
|
toScroll = height;
|
||||||
// scrollOffset = scrollOffset % totalNbLines;
|
}
|
||||||
// lcd.VerticalScrollStartAddress(scrollOffset);
|
|
||||||
// }
|
if (scrollOffset >= toScroll)
|
||||||
// } else if (scrollDirection == FullRefreshDirections::Left or scrollDirection == FullRefreshDirections::LeftAnim) {
|
scrollOffset -= toScroll;
|
||||||
// if (area->x2 == visibleNbLines - 1) {
|
else {
|
||||||
// scrollDirection = FullRefreshDirections::None;
|
toScroll -= scrollOffset;
|
||||||
//// lv_disp_set_rotation(lv_disp_get_default(), LV_DISP_ROT_NONE);
|
scrollOffset = (totalNbLines) -toScroll;
|
||||||
// }
|
}
|
||||||
// } else if (scrollDirection == FullRefreshDirections::Right or scrollDirection == FullRefreshDirections::RightAnim) {
|
lcd.VerticalScrollStartAddress(scrollOffset);
|
||||||
// if (area->x1 == 0) {
|
|
||||||
// scrollDirection = FullRefreshDirections::None;
|
}
|
||||||
//// lv_disp_set_rotation(lv_disp_get_default(), LV_DISP_ROT_NONE);
|
// move the whole screen down and draw the new screen at the top of the display
|
||||||
// }
|
MoveScreen(&disp_drv, static_cast<int16_t>(height));
|
||||||
// }
|
y1 = 0;
|
||||||
//
|
y2 = height;
|
||||||
// if (y2 < y1) {
|
|
||||||
// height = totalNbLines - y1;
|
} else if (scrollDirection == FullRefreshDirections::Up) {
|
||||||
//
|
|
||||||
// if (height > 0) {
|
if (area->y1 > 0) {
|
||||||
|
if (area->y2 == visibleNbLines - 1) {
|
||||||
|
scrollOffset += (height * 2);
|
||||||
|
scrollDirection = FullRefreshDirections::None;
|
||||||
|
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||||
|
} else {
|
||||||
|
scrollOffset += height;
|
||||||
|
}
|
||||||
|
scrollOffset = scrollOffset % totalNbLines;
|
||||||
|
lcd.VerticalScrollStartAddress(scrollOffset);
|
||||||
|
}
|
||||||
|
// move the whole screen up and draw the new screen at the bottom the display
|
||||||
|
MoveScreen(&disp_drv, -static_cast<int16_t>(height));
|
||||||
|
y1 = LV_VER_RES - height;
|
||||||
|
y2 = LV_VER_RES;
|
||||||
|
} else if (scrollDirection == FullRefreshDirections::Left or scrollDirection == FullRefreshDirections::LeftAnim) {
|
||||||
|
if (area->x2 == visibleNbLines - 1) {
|
||||||
|
scrollDirection = FullRefreshDirections::None;
|
||||||
|
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||||
|
}
|
||||||
|
} else if (scrollDirection == FullRefreshDirections::Right or scrollDirection == FullRefreshDirections::RightAnim) {
|
||||||
|
if (area->x1 == 0) {
|
||||||
|
scrollDirection = FullRefreshDirections::None;
|
||||||
|
lv_disp_set_direction(lv_disp_get_default(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y2 < y1) {
|
||||||
|
height = totalNbLines - y1;
|
||||||
|
|
||||||
|
if (height > 0) {
|
||||||
//lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
|
//lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
|
||||||
|
DrawBuffer(&disp_drv, area->x1, y1, width, height, reinterpret_cast<uint8_t*>(color_p), width * height * 2);
|
||||||
//ulTaskNotifyTake(pdTRUE, 100);
|
//ulTaskNotifyTake(pdTRUE, 100);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// uint16_t pixOffset = width * height;
|
uint16_t pixOffset = width * height;
|
||||||
// height = y2 + 1;
|
height = y2 + 1;
|
||||||
//lcd.DrawBuffer(area->x1, 0, width, height, reinterpret_cast<const uint8_t*>(color_p + pixOffset), width * height * 2);
|
//lcd.DrawBuffer(area->x1, 0, width, height, reinterpret_cast<const uint8_t*>(color_p + pixOffset), width * height * 2);
|
||||||
//
|
DrawBuffer(&disp_drv, area->x1, 0, width, height, reinterpret_cast<uint8_t*>(color_p + pixOffset), width * height * 2);
|
||||||
// } else {
|
|
||||||
|
} else {
|
||||||
//lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
|
//lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
|
||||||
// }
|
DrawBuffer(&disp_drv, area->x1, y1, width, height, reinterpret_cast<uint8_t*>(color_p), width * height * 2);
|
||||||
//
|
}
|
||||||
// // IMPORTANT!!!
|
|
||||||
// // Inform the graphics library that you are ready with the flushing
|
// IMPORTANT!!!
|
||||||
|
// Inform the graphics library that you are ready with the flushing
|
||||||
//lv_disp_flush_ready(&disp_drv);
|
//lv_disp_flush_ready(&disp_drv);
|
||||||
|
|
||||||
|
// call flush with flushing_last set
|
||||||
|
// workaround because lv_disp_flush_ready() doesn't seem to trigger monitor_flush
|
||||||
lv_disp_t *disp = lv_disp_get_default();
|
lv_disp_t *disp = lv_disp_get_default();
|
||||||
lv_disp_drv_t *disp_drv = &disp->driver;
|
|
||||||
lv_area_t area_trimmed = *area;
|
|
||||||
if (area->x1 < 0)
|
|
||||||
area_trimmed.x1 = 0;
|
|
||||||
if (area->x2 >= LV_HOR_RES)
|
|
||||||
area_trimmed.x2 = LV_HOR_RES-1;
|
|
||||||
if (area->y1 < 0)
|
|
||||||
area_trimmed.y1 = 0;
|
|
||||||
if (area->y2 >= LV_VER_RES)
|
|
||||||
area_trimmed.y2 = LV_VER_RES-1;
|
|
||||||
// tell flush_cb this is the last thing to flush to get the monitor refreshed
|
|
||||||
lv_disp_get_buf(disp)->flushing_last = true;
|
lv_disp_get_buf(disp)->flushing_last = true;
|
||||||
disp_drv->flush_cb(disp_drv, &area_trimmed, color_p);
|
lv_area_t area_zero {0,0,0,0};
|
||||||
|
monitor_flush(&disp_drv, &area_zero, color_p);
|
||||||
|
// delay drawing to mimic PineTime display rendering speed
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LittleVgl::SetNewTouchPoint(uint16_t x, uint16_t y, bool contact) {
|
void LittleVgl::SetNewTouchPoint(uint16_t x, uint16_t y, bool contact) {
|
||||||
|
@ -319,9 +281,15 @@ bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//void LittleVgl::InitTheme() {
|
void LittleVgl::InitTheme() {
|
||||||
// if (!lv_pinetime_theme_is_inited()) {
|
|
||||||
// lv_theme_t* th = lv_pinetime_theme_init(lv_disp_get_default(), lv_color_white(), lv_color_hex(0xC0C0C0), &jetbrains_mono_bold_20);
|
lv_theme_t* th = lv_pinetime_theme_init(LV_COLOR_WHITE,
|
||||||
// lv_disp_set_theme(lv_disp_get_default(), th);
|
LV_COLOR_SILVER,
|
||||||
// }
|
0,
|
||||||
//}
|
&jetbrains_mono_bold_20,
|
||||||
|
&jetbrains_mono_bold_20,
|
||||||
|
&jetbrains_mono_bold_20,
|
||||||
|
&jetbrains_mono_bold_20);
|
||||||
|
|
||||||
|
lv_theme_set_act(th);
|
||||||
|
}
|
||||||
|
|
|
@ -25,27 +25,30 @@ namespace Pinetime {
|
||||||
bool GetTouchPadInfo(lv_indev_data_t* ptr);
|
bool GetTouchPadInfo(lv_indev_data_t* ptr);
|
||||||
void SetFullRefresh(FullRefreshDirections direction);
|
void SetFullRefresh(FullRefreshDirections direction);
|
||||||
void SetNewTouchPoint(uint16_t x, uint16_t y, bool contact);
|
void SetNewTouchPoint(uint16_t x, uint16_t y, bool contact);
|
||||||
//
|
|
||||||
// private:
|
bool GetFullRefresh() {
|
||||||
// void InitDisplay();
|
bool returnValue = fullRefresh;
|
||||||
|
if (fullRefresh) {
|
||||||
|
fullRefresh = false;
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitDisplay();
|
||||||
void InitTouchpad();
|
void InitTouchpad();
|
||||||
// void InitTheme();
|
void InitTheme();
|
||||||
//
|
|
||||||
// void FlushDisplayManually();
|
|
||||||
// void DisplayDownScroll();
|
|
||||||
// void DisplayHorizAnim();
|
|
||||||
|
|
||||||
Pinetime::Drivers::St7789& lcd;
|
Pinetime::Drivers::St7789& lcd;
|
||||||
Pinetime::Drivers::Cst816S& touchPanel;
|
Pinetime::Drivers::Cst816S& touchPanel;
|
||||||
|
|
||||||
// lv_disp_draw_buf_t disp_buf_2;
|
lv_disp_buf_t disp_buf_2;
|
||||||
// lv_color_t buf2_1[LV_HOR_RES_MAX * 4];
|
lv_color_t buf2_1[LV_HOR_RES_MAX * 4];
|
||||||
// lv_color_t buf2_2[LV_HOR_RES_MAX * 4];
|
lv_color_t buf2_2[LV_HOR_RES_MAX * 4];
|
||||||
//
|
|
||||||
lv_disp_drv_t disp_drv;
|
|
||||||
lv_point_t previousClick;
|
|
||||||
|
|
||||||
bool firstTouch = true;
|
lv_disp_drv_t disp_drv;
|
||||||
|
|
||||||
|
bool fullRefresh = false;
|
||||||
static constexpr uint8_t nbWriteLines = 4;
|
static constexpr uint8_t nbWriteLines = 4;
|
||||||
static constexpr uint16_t totalNbLines = 320;
|
static constexpr uint16_t totalNbLines = 320;
|
||||||
static constexpr uint16_t visibleNbLines = 240;
|
static constexpr uint16_t visibleNbLines = 240;
|
||||||
|
|
|
@ -1,12 +1,28 @@
|
||||||
#include "drivers/SpiNorFlash.h"
|
#include "drivers/SpiNorFlash.h"
|
||||||
#include <hal/nrf_gpio.h>
|
#include <hal/nrf_gpio.h>
|
||||||
#include <libraries/delay/nrf_delay.h>
|
|
||||||
#include <libraries/log/nrf_log.h>
|
#include <libraries/log/nrf_log.h>
|
||||||
#include "drivers/Spi.h"
|
#include "drivers/Spi.h"
|
||||||
|
#include <filesystem>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
using namespace Pinetime::Drivers;
|
using namespace Pinetime::Drivers;
|
||||||
|
|
||||||
SpiNorFlash::SpiNorFlash(Spi& spi) : spi {spi} {
|
SpiNorFlash::SpiNorFlash(const std::string& memoryFilePath) : memoryFilePath{memoryFilePath} {
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
fs::path f{ memoryFilePath };
|
||||||
|
if (fs::exists(f)) {
|
||||||
|
memoryFile = std::fstream(memoryFilePath, std::ios::binary | std::fstream::in | std::fstream::out);
|
||||||
|
} else {
|
||||||
|
memoryFile = std::fstream(memoryFilePath, std::ios::trunc | std::ios::binary | std::fstream::in | std::fstream::out);
|
||||||
|
memoryFile.seekp(memorySize - 1);
|
||||||
|
memoryFile.write("", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SpiNorFlash::~SpiNorFlash() {
|
||||||
|
if (memoryFile.is_open()) {
|
||||||
|
memoryFile.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpiNorFlash::Init() {
|
void SpiNorFlash::Init() {
|
||||||
|
@ -19,126 +35,67 @@ void SpiNorFlash::Uninit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpiNorFlash::Sleep() {
|
void SpiNorFlash::Sleep() {
|
||||||
auto cmd = static_cast<uint8_t>(Commands::DeepPowerDown);
|
|
||||||
spi.Write(&cmd, sizeof(uint8_t));
|
|
||||||
NRF_LOG_INFO("[SpiNorFlash] Sleep")
|
NRF_LOG_INFO("[SpiNorFlash] Sleep")
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpiNorFlash::Wakeup() {
|
void SpiNorFlash::Wakeup() {
|
||||||
// send Commands::ReleaseFromDeepPowerDown then 3 dummy bytes before reading Device ID
|
|
||||||
// static constexpr uint8_t cmdSize = 4;
|
|
||||||
// uint8_t cmd[cmdSize] = {static_cast<uint8_t>(Commands::ReleaseFromDeepPowerDown), 0x01, 0x02, 0x03};
|
|
||||||
// uint8_t id = 0;
|
|
||||||
// spi.Read(reinterpret_cast<uint8_t*>(&cmd), cmdSize, &id, 1);
|
|
||||||
// auto devId = device_id = ReadIdentificaion();
|
|
||||||
// if (devId.type != device_id.type) {
|
|
||||||
// NRF_LOG_INFO("[SpiNorFlash] ID on Wakeup: Failed");
|
|
||||||
// } else {
|
|
||||||
// NRF_LOG_INFO("[SpiNorFlash] ID on Wakeup: %d", id);
|
|
||||||
// }
|
|
||||||
NRF_LOG_INFO("[SpiNorFlash] Wakeup")
|
NRF_LOG_INFO("[SpiNorFlash] Wakeup")
|
||||||
}
|
}
|
||||||
|
|
||||||
SpiNorFlash::Identification SpiNorFlash::ReadIdentificaion() {
|
SpiNorFlash::Identification SpiNorFlash::ReadIdentificaion() {
|
||||||
// auto cmd = static_cast<uint8_t>(Commands::ReadIdentification);
|
|
||||||
// Identification identification;
|
|
||||||
// spi.Read(&cmd, 1, reinterpret_cast<uint8_t*>(&identification), sizeof(Identification));
|
|
||||||
// return identification;
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SpiNorFlash::ReadStatusRegister() {
|
uint8_t SpiNorFlash::ReadStatusRegister() {
|
||||||
auto cmd = static_cast<uint8_t>(Commands::ReadStatusRegister);
|
return 0;
|
||||||
uint8_t status;
|
|
||||||
spi.Read(&cmd, sizeof(cmd), &status, sizeof(uint8_t));
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpiNorFlash::WriteInProgress() {
|
bool SpiNorFlash::WriteInProgress() {
|
||||||
// return (ReadStatusRegister() & 0x01u) == 0x01u;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpiNorFlash::WriteEnabled() {
|
bool SpiNorFlash::WriteEnabled() {
|
||||||
// return (ReadStatusRegister() & 0x02u) == 0x02u;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SpiNorFlash::ReadConfigurationRegister() {
|
uint8_t SpiNorFlash::ReadConfigurationRegister() {
|
||||||
auto cmd = static_cast<uint8_t>(Commands::ReadConfigurationRegister);
|
return 0;
|
||||||
uint8_t status;
|
|
||||||
spi.Read(&cmd, sizeof(cmd), &status, sizeof(uint8_t));
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpiNorFlash::Read(uint32_t address, uint8_t* buffer, size_t size) {
|
void SpiNorFlash::Read(uint32_t address, uint8_t* buffer, size_t size) {
|
||||||
static constexpr uint8_t cmdSize = 4;
|
static_assert(sizeof(uint8_t) == sizeof(char));
|
||||||
uint8_t cmd[cmdSize] = {static_cast<uint8_t>(Commands::Read), (uint8_t) (address >> 16U), (uint8_t) (address >> 8U), (uint8_t) address};
|
if (address + size * sizeof(uint8_t) > memorySize) {
|
||||||
spi.Read(reinterpret_cast<uint8_t*>(&cmd), cmdSize, buffer, size);
|
throw std::runtime_error("SpiNorFlash::Read out of bounds");
|
||||||
|
}
|
||||||
|
memoryFile.seekp(address);
|
||||||
|
memoryFile.read(reinterpret_cast<char *>(buffer), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpiNorFlash::WriteEnable() {
|
void SpiNorFlash::WriteEnable() {
|
||||||
auto cmd = static_cast<uint8_t>(Commands::WriteEnable);
|
|
||||||
spi.Read(&cmd, sizeof(cmd), nullptr, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpiNorFlash::SectorErase(uint32_t sectorAddress) {
|
void SpiNorFlash::SectorErase(uint32_t sectorAddress) {
|
||||||
// static constexpr uint8_t cmdSize = 4;
|
|
||||||
// uint8_t cmd[cmdSize] = {static_cast<uint8_t>(Commands::SectorErase),
|
|
||||||
// (uint8_t) (sectorAddress >> 16U),
|
|
||||||
// (uint8_t) (sectorAddress >> 8U),
|
|
||||||
// (uint8_t) sectorAddress};
|
|
||||||
//
|
|
||||||
// WriteEnable();
|
|
||||||
// while (!WriteEnabled())
|
|
||||||
// vTaskDelay(1);
|
|
||||||
//
|
|
||||||
// spi.Read(reinterpret_cast<uint8_t*>(&cmd), cmdSize, nullptr, 0);
|
|
||||||
//
|
|
||||||
// while (WriteInProgress())
|
|
||||||
// vTaskDelay(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SpiNorFlash::ReadSecurityRegister() {
|
uint8_t SpiNorFlash::ReadSecurityRegister() {
|
||||||
auto cmd = static_cast<uint8_t>(Commands::ReadSecurityRegister);
|
return 0;
|
||||||
uint8_t status;
|
|
||||||
spi.Read(&cmd, sizeof(cmd), &status, sizeof(uint8_t));
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpiNorFlash::ProgramFailed() {
|
bool SpiNorFlash::ProgramFailed() {
|
||||||
// return (ReadSecurityRegister() & 0x20u) == 0x20u;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpiNorFlash::EraseFailed() {
|
bool SpiNorFlash::EraseFailed() {
|
||||||
// return (ReadSecurityRegister() & 0x40u) == 0x40u;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpiNorFlash::Write(uint32_t address, const uint8_t* buffer, size_t size) {
|
void SpiNorFlash::Write(uint32_t address, const uint8_t* buffer, size_t size) {
|
||||||
// static constexpr uint8_t cmdSize = 4;
|
if (address + size * sizeof(uint8_t) > memorySize) {
|
||||||
//
|
throw std::runtime_error("SpiNorFlash::Write out of bounds");
|
||||||
// size_t len = size;
|
}
|
||||||
// uint32_t addr = address;
|
memoryFile.seekp(address);
|
||||||
// const uint8_t* b = buffer;
|
memoryFile.write(reinterpret_cast<const char *>(buffer), size);
|
||||||
// while (len > 0) {
|
memoryFile.flush();
|
||||||
// uint32_t pageLimit = (addr & ~(pageSize - 1u)) + pageSize;
|
|
||||||
// uint32_t toWrite = pageLimit - addr > len ? len : pageLimit - addr;
|
|
||||||
//
|
|
||||||
// uint8_t cmd[cmdSize] = {static_cast<uint8_t>(Commands::PageProgram), (uint8_t) (addr >> 16U), (uint8_t) (addr >> 8U), (uint8_t) addr};
|
|
||||||
//
|
|
||||||
// WriteEnable();
|
|
||||||
// while (!WriteEnabled())
|
|
||||||
// vTaskDelay(1);
|
|
||||||
//
|
|
||||||
// spi.WriteCmdAndBuffer(cmd, cmdSize, b, toWrite);
|
|
||||||
//
|
|
||||||
// while (WriteInProgress())
|
|
||||||
// vTaskDelay(1);
|
|
||||||
//
|
|
||||||
// addr += toWrite;
|
|
||||||
// b += toWrite;
|
|
||||||
// len -= toWrite;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
namespace Drivers {
|
namespace Drivers {
|
||||||
class Spi;
|
class Spi;
|
||||||
class SpiNorFlash {
|
class SpiNorFlash {
|
||||||
public:
|
public:
|
||||||
explicit SpiNorFlash(Spi& spi);
|
explicit SpiNorFlash(const std::string& memoryFilePath);
|
||||||
|
~SpiNorFlash();
|
||||||
SpiNorFlash(const SpiNorFlash&) = delete;
|
SpiNorFlash(const SpiNorFlash&) = delete;
|
||||||
SpiNorFlash& operator=(const SpiNorFlash&) = delete;
|
SpiNorFlash& operator=(const SpiNorFlash&) = delete;
|
||||||
SpiNorFlash(SpiNorFlash&&) = delete;
|
SpiNorFlash(SpiNorFlash&&) = delete;
|
||||||
SpiNorFlash& operator=(SpiNorFlash&&) = delete;
|
SpiNorFlash& operator=(SpiNorFlash&&) = delete;
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
struct __attribute__((packed)) Identification {
|
||||||
uint8_t manufacturer = 0;
|
uint8_t manufacturer = 0;
|
||||||
uint8_t type = 0;
|
uint8_t type = 0;
|
||||||
uint8_t density = 0;
|
uint8_t density = 0;
|
||||||
} Identification;
|
};
|
||||||
|
|
||||||
Identification ReadIdentificaion();
|
Identification ReadIdentificaion();
|
||||||
uint8_t ReadStatusRegister();
|
uint8_t ReadStatusRegister();
|
||||||
|
@ -53,8 +55,12 @@ namespace Pinetime {
|
||||||
};
|
};
|
||||||
static constexpr uint16_t pageSize = 256;
|
static constexpr uint16_t pageSize = 256;
|
||||||
|
|
||||||
Spi& spi;
|
static constexpr size_t memorySize {0x400000};
|
||||||
|
const std::string& memoryFilePath;
|
||||||
|
|
||||||
|
|
||||||
Identification device_id;
|
Identification device_id;
|
||||||
|
std::fstream memoryFile;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,8 +57,12 @@ ret_code_t app_timer_init(void) {
|
||||||
ret_code_t app_timer_create(app_timer_t *p_timer_id,
|
ret_code_t app_timer_create(app_timer_t *p_timer_id,
|
||||||
app_timer_mode_t mode,
|
app_timer_mode_t mode,
|
||||||
app_timer_timeout_handler_t timeout_handler) {
|
app_timer_timeout_handler_t timeout_handler) {
|
||||||
if (mode != APP_TIMER_MODE_SINGLE_SHOT) {
|
if (mode == APP_TIMER_MODE_SINGLE_SHOT) {
|
||||||
throw std::runtime_error("only mode 'APP_TIMER_MODE_SINGLE_SHOT' implemented");
|
p_timer_id->repeating = false;
|
||||||
|
} else if (mode == APP_TIMER_MODE_REPEATED) {
|
||||||
|
p_timer_id->repeating = true;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("only mode 'APP_TIMER_MODE_SINGLE_SHOT' or 'APP_TIMER_MODE_REPEATED' implemented");
|
||||||
}
|
}
|
||||||
p_timer_id->handler = timeout_handler;
|
p_timer_id->handler = timeout_handler;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -67,10 +71,15 @@ Uint32 timeout_callback_wrapper(Uint32 interval, void *param)
|
||||||
{
|
{
|
||||||
auto* timer_id = static_cast<app_timer_t*>(param);
|
auto* timer_id = static_cast<app_timer_t*>(param);
|
||||||
timer_id->handler(timer_id->p_context);
|
timer_id->handler(timer_id->p_context);
|
||||||
|
if (timer_id->repeating) {
|
||||||
|
return timer_id->repeat_period;
|
||||||
|
} else {
|
||||||
return 0; // cancel timer
|
return 0; // cancel timer
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ret_code_t app_timer_start(app_timer_t &timer_id, uint32_t timeout_ticks, void * p_context) {
|
ret_code_t app_timer_start(app_timer_t &timer_id, uint32_t timeout_ticks, void * p_context) {
|
||||||
timer_id.p_context = p_context;
|
timer_id.p_context = p_context;
|
||||||
|
timer_id.repeat_period = timeout_ticks;
|
||||||
timer_id.sdl_timer_id = SDL_AddTimer(timeout_ticks, timeout_callback_wrapper, (void*)(&timer_id));
|
timer_id.sdl_timer_id = SDL_AddTimer(timeout_ticks, timeout_callback_wrapper, (void*)(&timer_id));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,13 @@ typedef uint32_t ret_code_t;
|
||||||
/**@brief Application time-out handler type. */
|
/**@brief Application time-out handler type. */
|
||||||
typedef void (*app_timer_timeout_handler_t)(void * p_context);
|
typedef void (*app_timer_timeout_handler_t)(void * p_context);
|
||||||
|
|
||||||
|
/**@brief Timer modes. */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
APP_TIMER_MODE_SINGLE_SHOT, /**< The timer will expire only once. */
|
||||||
|
APP_TIMER_MODE_REPEATED /**< The timer will restart each time it expires. */
|
||||||
|
} app_timer_mode_t;
|
||||||
|
|
||||||
struct app_timer_t
|
struct app_timer_t
|
||||||
{
|
{
|
||||||
//nrf_sortlist_item_t list_item; /**< Token used by sortlist. */
|
//nrf_sortlist_item_t list_item; /**< Token used by sortlist. */
|
||||||
|
@ -96,6 +103,7 @@ struct app_timer_t
|
||||||
uint32_t repeat_period; /**< Repeat period (0 if single shot mode). */
|
uint32_t repeat_period; /**< Repeat period (0 if single shot mode). */
|
||||||
app_timer_timeout_handler_t handler; /**< User handler. */
|
app_timer_timeout_handler_t handler; /**< User handler. */
|
||||||
void * p_context; /**< User context. */
|
void * p_context; /**< User context. */
|
||||||
|
bool repeating;
|
||||||
//NRF_LOG_INSTANCE_PTR_DECLARE(p_log) /**< Pointer to instance of the logger object (Conditionally compiled). */
|
//NRF_LOG_INSTANCE_PTR_DECLARE(p_log) /**< Pointer to instance of the logger object (Conditionally compiled). */
|
||||||
//volatile bool active; /**< Flag indicating that timer is active. */
|
//volatile bool active; /**< Flag indicating that timer is active. */
|
||||||
};
|
};
|
||||||
|
@ -127,13 +135,6 @@ uint32_t constexpr APP_TIMER_TICKS(uint32_t ms) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**@brief Timer modes. */
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
APP_TIMER_MODE_SINGLE_SHOT, /**< The timer will expire only once. */
|
|
||||||
APP_TIMER_MODE_REPEATED /**< The timer will restart each time it expires. */
|
|
||||||
} app_timer_mode_t;
|
|
||||||
|
|
||||||
/**@brief Function for initializing the timer module.
|
/**@brief Function for initializing the timer module.
|
||||||
*
|
*
|
||||||
* @retval NRF_SUCCESS If the module was initialized successfully.
|
* @retval NRF_SUCCESS If the module was initialized successfully.
|
||||||
|
|
|
@ -6,8 +6,20 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string> // std::to_string
|
#include <string> // std::to_string
|
||||||
|
|
||||||
void nrf_gpio_cfg_default(uint32_t pin_number) {}
|
bool motor_running = false;
|
||||||
void nrf_gpio_pin_set(uint32_t pin_number) {}
|
|
||||||
|
void nrf_gpio_cfg_default(uint32_t pin_number) {
|
||||||
|
if (pin_number == Pinetime::PinMap::Motor)
|
||||||
|
{
|
||||||
|
motor_running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void nrf_gpio_pin_set(uint32_t pin_number) {
|
||||||
|
if (pin_number == Pinetime::PinMap::Motor)
|
||||||
|
{
|
||||||
|
motor_running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
uint32_t nrf_gpio_pin_read(uint32_t pin_number)
|
uint32_t nrf_gpio_pin_read(uint32_t pin_number)
|
||||||
{
|
{
|
||||||
if (pin_number == Pinetime::PinMap::Button) {
|
if (pin_number == Pinetime::PinMap::Button) {
|
||||||
|
@ -16,12 +28,21 @@ uint32_t nrf_gpio_pin_read(uint32_t pin_number)
|
||||||
bool right_click = (buttons & SDL_BUTTON_RMASK) != 0;
|
bool right_click = (buttons & SDL_BUTTON_RMASK) != 0;
|
||||||
return right_click;
|
return right_click;
|
||||||
}
|
}
|
||||||
|
else if (pin_number == Pinetime::PinMap::Motor)
|
||||||
|
{
|
||||||
|
return motor_running;
|
||||||
|
}
|
||||||
throw std::runtime_error("nrf_gpio_pin_read: unhandled pin_number: " + std::to_string(pin_number));
|
throw std::runtime_error("nrf_gpio_pin_read: unhandled pin_number: " + std::to_string(pin_number));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nrf_gpio_cfg_output(uint32_t pin_number) {}
|
void nrf_gpio_cfg_output(uint32_t pin_number) {}
|
||||||
void nrf_gpio_pin_clear(uint32_t pin_number) {}
|
void nrf_gpio_pin_clear(uint32_t pin_number) {
|
||||||
|
if (pin_number == Pinetime::PinMap::Motor)
|
||||||
|
{
|
||||||
|
motor_running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
void nrf_gpio_range_cfg_input(uint32_t pin_range_start,
|
void nrf_gpio_range_cfg_input(uint32_t pin_range_start,
|
||||||
uint32_t pin_range_end,
|
uint32_t pin_range_end,
|
||||||
nrf_gpio_pin_pull_t pull_config) {}
|
nrf_gpio_pin_pull_t pull_config) {}
|
||||||
|
|
Loading…
Reference in New Issue