diff --git a/.vscode/launch.json b/.vscode/launch.json index ee607c3..234b247 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -60,6 +60,60 @@ "miDebuggerPath": "C:\\MinGw\\bin\\gdb.exe" } }, + { + "name": "Debug meteofrance with gdb", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/components/meteofrance/testHost/build/my_custom_app.elf", + "args": [], + "cwd": "${workspaceFolder}", + "stopAtEntry": false, + /* + "setupCommands": [ + { + "description": "Load LVGL GDB helpers", + "text": "source /home/marc/domotic/components/domotic_display/test_host/managed_components/lvgl__lvgl/scripts/gdb/gdbinit.py" + } + ],*/ + "linux": { + "MIMode": "gdb", + "miDebuggerPath": "/usr/bin/gdb" + }, + "osx": { + "MIMode": "lldb" + }, + "windows": { + "MIMode": "gdb", + "miDebuggerPath": "C:\\MinGw\\bin\\gdb.exe" + } + }, + { + "name": "Debug main with gdb", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/rgb_lcd.elf", + "args": [], + "cwd": "${workspaceFolder}", + "stopAtEntry": false, + /* + "setupCommands": [ + { + "description": "Load LVGL GDB helpers", + "text": "source /home/marc/domotic/components/domotic_display/test_host/managed_components/lvgl__lvgl/scripts/gdb/gdbinit.py" + } + ],*/ + "linux": { + "MIMode": "gdb", + "miDebuggerPath": "/usr/bin/gdb" + }, + "osx": { + "MIMode": "lldb" + }, + "windows": { + "MIMode": "gdb", + "miDebuggerPath": "C:\\MinGw\\bin\\gdb.exe" + } + }, { "name": "Debug remindme with gdb", "type": "cppdbg", diff --git a/.vscode/settings.json b/.vscode/settings.json index ecd82d1..e327d38 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,7 @@ { "C_Cpp.intelliSenseEngine": "default", "idf.espIdfPath": "/home/marc/esp/esp-idf", - "idf.pythonBinPath": "/home/marc/.espressif/python_env/idf5.5_py3.10_env/bin/python", + "idf.pythonBinPath": "/home/marc/.espressif/tools/python/v5.5.2/venv/bin/python3", "idf.toolsPath": "/home/marc/.espressif", "idf.customExtraPaths": "/home/marc/.espressif/tools/xtensa-esp-elf-gdb/14.2_20240403/xtensa-esp-elf-gdb/bin:/home/marc/.espressif/tools/riscv32-esp-elf-gdb/14.2_20240403/riscv32-esp-elf-gdb/bin:/home/marc/.espressif/tools/xtensa-esp-elf/esp-13.2.0_20240530/xtensa-esp-elf/bin:/home/marc/.espressif/tools/riscv32-esp-elf/esp-13.2.0_20240530/riscv32-esp-elf/bin:/home/marc/.espressif/tools/esp32ulp-elf/2.38_20240113/esp32ulp-elf/bin:/home/marc/.espressif/tools/cmake/3.24.0/bin:/home/marc/.espressif/tools/openocd-esp32/v0.12.0-esp32-20240318/openocd-esp32/bin:/home/marc/.espressif/tools/ninja/1.11.1:/home/marc/.espressif/tools/esp-rom-elfs/20240305", "idf.customExtraVars": { diff --git a/CMakeLists.txt b/CMakeLists.txt index e8f42be..0272a4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,8 @@ message(STATUS "ROOT:: SIMULATION_QEMU = ${SIMULATION_QEMU}") # CONFIGURATION AVANT project() : uniquement CMake pur # ------------------------------------------------- + + if(SIMULATION_QEMU) message(STATUS "SIMULATION_QEMU = ON") option(SIMULATION_QEMU "Build for QEMU simulation" ON) @@ -19,12 +21,20 @@ if(SIMULATION_QEMU) else() message(STATUS "SIMULATION_QEMU = OFF") option(SIMULATION_QEMU "Build for QEMU simulation" OFF) +# set(COMPONENTS +# components/meteofrance +# components/domotic_display +# managed_components/lvgl_lvgl +# main +# $ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs +# ) endif() +list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/esp_timer") -# 🚹 Rien d'autre avant ces deux lignes ! include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(rgb_lcd) + # ------------------------------------------------- # APRÈS project() : maintenant CONFIG_SIMULATION_QEMU existe # ------------------------------------------------- @@ -40,5 +50,5 @@ if(CONFIG_SIMULATION_QEMU) #) else() message(STATUS "Compilation standard") - add_link_options("-Wl,--disable-non-contiguous-regions") + add_link_options("-Wl,--disable-non-contiguous-regions -lSDL2") endif() diff --git a/components/domotic_display/CMakeLists.txt b/components/domotic_display/CMakeLists.txt index eb277dc..a76d902 100644 --- a/components/domotic_display/CMakeLists.txt +++ b/components/domotic_display/CMakeLists.txt @@ -19,12 +19,12 @@ make_font(Super_Malibu super_malibu 80) #execute_process(COMMAND podman run -v /home/marc/rgb_lcd/components/domotic_display/fonts:/app -w /app lvfontconv lv_font_conv --bpp 4 --size 72 --no-compress --font Roboto-Medium.ttf --symbols "0123456789.°àéÚûCABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz %,'():ĂȘ/-" --format lvgl -o roboto_medium_72.c --font fa-solid-900.ttf --range 61461,0xf0c2,0xf575) - +SET(comps meteofrance eventsManager lvgl RemindMe) if(${IDF_TARGET} STREQUAL "esp32p4" OR ${IDF_TARGET} STREQUAL "esp32s3") #esp32_p4_function_ev_board idf_component_register(SRC_DIRS . fonts INCLUDE_DIRS "include" - REQUIRES meteofrance eventsManager lvgl esp_lvgl_port) + REQUIRES ${comps} esp_lvgl_port) target_compile_options(${COMPONENT_LIB} PUBLIC -DLV_LVGL_H_INCLUDE_SIMPLE) lvgl_port_create_c_image("images/wifi_ok.png" "images/" "ARGB8888" "NONE") @@ -33,5 +33,10 @@ if(${IDF_TARGET} STREQUAL "esp32p4" OR ${IDF_TARGET} STREQUAL "esp32s3") lvgl_port_create_c_image("images/mqtt_ko.png" "images/" "ARGB8888" "NONE") lvgl_port_add_images(${COMPONENT_LIB} "images/") #littlefs_create_partition_image(littlefs images_meteo FLASH_IN_PROJECT) +elseif(${IDF_TARGET} STREQUAL "linux") + idf_component_register(SRC_DIRS . fonts images + INCLUDE_DIRS "include" + REQUIRES ${comps}) + target_compile_options(${COMPONENT_LIB} PUBLIC -DLV_LVGL_H_INCLUDE_SIMPLE) endif() diff --git a/components/domotic_display/idf_component.yml b/components/domotic_display/idf_component.yml index 8e2e917..8387618 100644 --- a/components/domotic_display/idf_component.yml +++ b/components/domotic_display/idf_component.yml @@ -18,5 +18,11 @@ dependencies: rules: - if: target in ["esp32p4","esp32, "esp32s3"] version: ^2.7.0 + lvgl/lvgl: + rules: + - if: target in ["linux"] + version: 9.4.0 espressif/esp_lcd_qemu_rgb: + rules: + - if: target in ["esp32p4","esp32, "esp32s3"] version: ^1 \ No newline at end of file diff --git a/components/domotic_display/ihm.c b/components/domotic_display/ihm.c index 72dc3d1..1db9884 100644 --- a/components/domotic_display/ihm.c +++ b/components/domotic_display/ihm.c @@ -539,7 +539,7 @@ void showMeteoIcon(const char *icon, lv_obj_t *desc_icon, int childNr) char *result = malloc(sizeOfStr); snprintf(result,sizeOfStr, "%s%s.png", str1, icon); ESP_LOGV(TAG,"On affiche l'image %s", result); - lv_image_set_src(img, "A:/home/marc/domotic/components/domotic_display/images_meteo/p4j.png"); + lv_image_set_src(img, "A:/home/marc/esp/domotic/domotic/components/domotic_display/images_meteo/p4j.png"); free(result); } diff --git a/components/domotic_display/include/ihm.h b/components/domotic_display/include/ihm.h index 2c88e1c..cb040e4 100644 --- a/components/domotic_display/include/ihm.h +++ b/components/domotic_display/include/ihm.h @@ -38,6 +38,4 @@ void draw_tabCuve(lv_obj_t * parent); void draw_tabHome(lv_obj_t * parent); void draw_tabSettings(lv_obj_t * parent); - - void drawIhm(void *pvParameter); diff --git a/components/domotic_display/test_host/CMakeLists.txt b/components/domotic_display/test_host/CMakeLists.txt index 1294df1..a561131 100644 --- a/components/domotic_display/test_host/CMakeLists.txt +++ b/components/domotic_display/test_host/CMakeLists.txt @@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) set(COMPONENTS main) -# This test app doesn't require FreeRTOS, using mock instead list(APPEND EXTRA_COMPONENT_DIRS # "$ENV{IDF_PATH}/tools/mocks/freertos/" "$ENV{IDF_PATH}/tools/mocks/esp_timer" @@ -14,18 +13,18 @@ list(APPEND EXTRA_COMPONENT_DIRS ) idf_build_set_property(COMPILE_DEFINITIONS "NO_DEBUG_STORAGE" APPEND) -project(nvs_host_test) +project(host_test) -add_custom_command( - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/coverage_report/index.html" - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - COMMAND gcovr --root $ENV{IDF_PATH}/components/nvs_flash --html-details - --exclude ${CMAKE_CURRENT_SOURCE_DIR}/managed_components/* - -o ${CMAKE_CURRENT_BINARY_DIR}/coverage_report/index.html ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generate coverage report" - ) +#add_custom_command( +# OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/coverage_report/index.html" +# WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +# COMMAND gcovr --root $ENV{IDF_PATH}/components/nvs_flash --html-details +# --exclude ${CMAKE_CURRENT_SOURCE_DIR}/managed_components/* +# -o ${CMAKE_CURRENT_BINARY_DIR}/coverage_report/index.html ${CMAKE_CURRENT_BINARY_DIR} +# COMMENT "Generate coverage report" +# ) -add_custom_target(coverage - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - DEPENDS "coverage_report/index.html" - ) \ No newline at end of file +#add_custom_target(coverage +# WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +# DEPENDS "coverage_report/index.html" +# ) \ No newline at end of file diff --git a/components/image_downloader/CMakeLists.txt b/components/image_downloader/CMakeLists.txt index 910bff1..2596e40 100644 --- a/components/image_downloader/CMakeLists.txt +++ b/components/image_downloader/CMakeLists.txt @@ -1,3 +1,11 @@ +set(requires json esp_http_client esp-tls esp_timer) +idf_build_get_property(target IDF_TARGET) + +if(${target} STREQUAL "linux") + list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/esp_timer" ) +else() + list(APPEND requires esp_timer) +endif() idf_component_register(SRCS "image_downloader.c" INCLUDE_DIRS "include" - REQUIRES json esp_http_client esp-tls esp_timer ) + REQUIRES ${requires} ) diff --git a/components/image_downloader/image_downloader.c b/components/image_downloader/image_downloader.c index a5ab3ef..8b2af87 100644 --- a/components/image_downloader/image_downloader.c +++ b/components/image_downloader/image_downloader.c @@ -199,12 +199,12 @@ void imgdwn(void *domotic_event_group) { if (source_buf == NULL) { ESP_LOGE(TAG, "Initial alloc source_buf failed!"); } - printf("Free heap after buffers allocation: %"PRIu16"\n", xPortGetFreeHeapSize()); + printf("Free heap after buffers allocation: %zu\n", xPortGetFreeHeapSize()); download(); heap_caps_free(source_buf); - printf("Free heap after buffers allocation: %"PRIu16"\n", xPortGetFreeHeapSize()); + printf("Free heap after buffers allocation: %zu\n", xPortGetFreeHeapSize()); vTaskDelay(3600000 / portTICK_PERIOD_MS); }else{ diff --git a/components/meteofrance/meteofrance.c b/components/meteofrance/meteofrance.c index 64214e3..5b8005c 100644 --- a/components/meteofrance/meteofrance.c +++ b/components/meteofrance/meteofrance.c @@ -412,7 +412,7 @@ void initialise_weather_data_retrieval(unsigned long retreival_period, void* dom // http_client_on_process_chunk(&http_client, process_chunk); // http_client_on_disconnected(&http_client, disconnected); TaskHandle_t xHandle = NULL; - BaseType_t ret1 = xTaskCreatePinnedToCore(&http_request_task, "http_meteof", 5 * 1024, domotic_event_group, 5, &xHandle, 1); + BaseType_t ret1 = xTaskCreatePinnedToCore(&http_request_task, "http_meteof", 5 * 1024, domotic_event_group, 5, &xHandle, 0); if(ret1!=pdPASS ){ ESP_LOGE(TAG, "Impossible de creer la tache %"PRIi16, ret1); } diff --git a/components/meteofrance/testHost/CMakeLists.txt b/components/meteofrance/testHost/CMakeLists.txt new file mode 100644 index 0000000..7e66d04 --- /dev/null +++ b/components/meteofrance/testHost/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.16) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +set(COMPONENTS main) +# This test app doesn't require FreeRTOS, using mock instead +list(APPEND EXTRA_COMPONENT_DIRS + # "$ENV{IDF_PATH}/tools/mocks/freertos/" + "$ENV{IDF_PATH}/tools/mocks/esp_timer" + ../../meteofrance + ../../stateManagement + ../../eventsManager + ../../RemindMe + ) + +project(my_custom_app C) \ No newline at end of file diff --git a/components/meteofrance/testHost/dependencies.lock b/components/meteofrance/testHost/dependencies.lock new file mode 100644 index 0000000..01a59aa --- /dev/null +++ b/components/meteofrance/testHost/dependencies.lock @@ -0,0 +1,10 @@ +dependencies: + idf: + source: + type: idf + version: 5.5.2 +direct_dependencies: +- idf +manifest_hash: 2fc18f414627b3fc737adcef5ecbfa3a4f7cff55fd5f96a20734c8d5302b79ed +target: linux +version: 2.0.0 diff --git a/components/meteofrance/testHost/main/CMakeLists.txt b/components/meteofrance/testHost/main/CMakeLists.txt new file mode 100644 index 0000000..f02c3cc --- /dev/null +++ b/components/meteofrance/testHost/main/CMakeLists.txt @@ -0,0 +1,13 @@ +set(LV_BUILD_USE_KCONFIG ON) +idf_component_register(SRCS main.c ../../meteofrance.c + INCLUDE_DIRS + "../../include" + WHOLE_ARCHIVE + REQUIRES stateManagement freertos json esp_http_client esp-tls + EMBED_TXTFILES ../../../../main/ca_cert.pem +) + + +# Currently 'main' for IDF_TARGET=linux is defined in freertos component. +# Since we are using a freertos mock here, need to let Catch2 provide 'main'. +#target_link_libraries(${COMPONENT_LIB} PRIVATE Catch2WithMain) diff --git a/components/meteofrance/testHost/main/main.c b/components/meteofrance/testHost/main/main.c new file mode 100644 index 0000000..b340f10 --- /dev/null +++ b/components/meteofrance/testHost/main/main.c @@ -0,0 +1,45 @@ +#include +#include "meteofrance.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_event.h" + +#define BIT0 0x00000001 +#define WIFI_CONNECTED_BIT BIT0 + + +int main1(int argc, char const *argv[]) +{ + /* code */ + return 0; +} + +void weather_data_retreived_start() +{ + //if (display_lock("weather_data_retreived_start")) + //{ + //ESP_LOGE(TAG,"Mutex obtenu dans weather_data_retreived_start"); + //lv_subject_set_int(&meteoStatus, 1); + ESP_LOGE("","Subject setted weather_data_retreived_start"); + //display_unlock("weather_data_retreived_start"); + //}else{ + // ESP_LOGE(TAG,"Impossible d'obtenir le mutex dans weather_data_retreived_start"); + //} +} + +void weather_data_retreived(struct meteodailyforecast_data dailyDatas[3], struct meteoforecast_data datas[3]) +{ +} + +EventGroupHandle_t domotic_event_group; +int app_main(int argc, char *argv[]) { + ESP_ERROR_CHECK(esp_event_loop_create_default()); + domotic_event_group = xEventGroupCreate(); + on_weather_data_retrieval_start(weather_data_retreived_start); + on_weather_data_retrieval(weather_data_retreived); + initialise_weather_data_retrieval(30000, domotic_event_group); + xEventGroupSetBits(domotic_event_group, WIFI_CONNECTED_BIT); + + return 0; +} \ No newline at end of file diff --git a/components/test_host/.vscode/settings.json b/components/test_host/.vscode/settings.json new file mode 100644 index 0000000..1ad1dee --- /dev/null +++ b/components/test_host/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "idf.pythonInstallPath": "/usr/bin/python3" +} \ No newline at end of file diff --git a/components/test_host/CMakeLists.txt b/components/test_host/CMakeLists.txt new file mode 100644 index 0000000..93955d4 --- /dev/null +++ b/components/test_host/CMakeLists.txt @@ -0,0 +1 @@ +idf_component_register(SRC_DIRS main REQUIRES domotic_display) diff --git a/components/test_host/data.json b/components/test_host/data.json new file mode 100644 index 0000000..a827a15 --- /dev/null +++ b/components/test_host/data.json @@ -0,0 +1,14 @@ +[ +{ + "evenement": "FĂȘte", + "affichage": "Noel est dans %d jour(s)", + "date": "2025-12-25", + "type": "remaining_days" +}, +{ + "evenement": "Ecole", + "affichage": "La rentrĂ©e est dans %d jour(s)", + "date": "2026-01-05", + "type": "remaining_days" +} +] \ No newline at end of file diff --git a/components/test_host/idf_component.yml b/components/test_host/idf_component.yml new file mode 100644 index 0000000..572695f --- /dev/null +++ b/components/test_host/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + lvgl/lvgl: + version: 9.4.0 + #espressif/esp32_p4_function_ev_board: + # version: "4.1.*" \ No newline at end of file diff --git a/components/test_host/main/CMakeLists.txt b/components/test_host/main/CMakeLists.txt new file mode 100644 index 0000000..43023c5 --- /dev/null +++ b/components/test_host/main/CMakeLists.txt @@ -0,0 +1,45 @@ +set(LV_BUILD_USE_KCONFIG ON) +idf_component_register(SRCS + "test_ihm.c" + "../../ihm.c" + "../../ihm_gateway.c" + "../../lv_theme_domotic.c" + "../../model.c" + "driver_backends.c" + "sdl.c" + "../../fonts/montserrat_medium_12.c" + "../../fonts/montserrat_medium_18.c" + "../../fonts/montserrat_medium_24.c" + "../../fonts/roboto_medium_36.c" + "../../fonts/roboto_medium_72.c" + "../../fonts/vlump_96.c" + "../../fonts/super_malibu_80.c" + "../../images/wifi_ko.c" + "../../images/wifi_ok.c" + INCLUDE_DIRS + "../../include" + "../mock" + WHOLE_ARCHIVE + REQUIRES lvgl meteofrance RemindMe) + + message("Including SDL2 support") + find_package(PkgConfig REQUIRED) + pkg_check_modules(SDL2 REQUIRED sdl2) + pkg_check_modules(SDL2_IMAGE REQUIRED SDL2_image) + + list(APPEND PKG_CONFIG_LIB ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) + list(APPEND PKG_CONFIG_INC ${SDL2_INCLUDE_DIRS} ${SDL2_IMAGE_INCLUDE_DIRS}) + + target_compile_options(${COMPONENT_LIB} PUBLIC --coverage -DLV_LVGL_H_INCLUDE_SIMPLE ) + target_link_libraries(${COMPONENT_LIB} PUBLIC ${PKG_CONFIG_LIB} --coverage) + target_include_directories(${COMPONENT_LIB} PRIVATE ${CMAKE_SOURCE_DIR}/mock ${PKG_CONFIG_INC}) + target_link_libraries(${COMPONENT_LIB} PRIVATE bsd) + +if(CMAKE_C_COMPILER_ID MATCHES "Clang") + target_compile_options(${COMPONENT_LIB} PRIVATE -std=gnu++20) +endif() + + +# Currently 'main' for IDF_TARGET=linux is defined in freertos component. +# Since we are using a freertos mock here, need to let Catch2 provide 'main'. +#target_link_libraries(${COMPONENT_LIB} PRIVATE Catch2WithMain) diff --git a/components/test_host/main/backends.h b/components/test_host/main/backends.h new file mode 100644 index 0000000..4121d50 --- /dev/null +++ b/components/test_host/main/backends.h @@ -0,0 +1,97 @@ +/** + * @file backends.h + * + * Interface for abstration layer of a device backend + * + * Copyright (c) 2025 EDGEMTech Ltd. + * + * Author: EDGEMTech Ltd, Erik Tagirov (erik.tagirov@edgemtech.ch) + * + */ +#ifndef BACKENDS_H +#define BACKENDS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/* Prototype of the display initialization functions */ +typedef lv_display_t *(*display_init_t)(void); + +/* Prototype of the run loop */ +typedef void (*run_loop_t)(void); + +/* Represents a display driver handle */ +typedef struct { + display_init_t init_display; /* The display creation/initialization function */ + run_loop_t run_loop; /* The run loop of the driver handle */ + lv_display_t *display; /* The LVGL display that was created */ +} display_backend_t; + +/* Prototype for the initialization of an indev driver backend */ +typedef lv_indev_t *(*indev_init_t)(lv_display_t *display); + +/* Represents an indev driver backend */ +typedef struct { + indev_init_t init_indev; +} indev_backend_t; + +/* Regroup all different types of driver backend */ +typedef union { + display_backend_t *display; + indev_backend_t *indev; +} backend_handle_t; + +/* Define each type of driver backend */ +typedef enum { + BACKEND_DISPLAY, + BACKEND_INDEV +} backend_type_t; + +/* Driver backend descriptor */ +typedef struct { + backend_handle_t *handle; + char *name; + backend_type_t type; +} backend_t; + +/* Prototype used to register a backend */ +typedef int (*backend_init_t)(backend_t *); + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/* Graphics backends */ +int backend_init_fbdev(backend_t *backend); +int backend_init_drm(backend_t *backend); +int backend_init_sdl(backend_t *backend); +int backend_init_glfw3(backend_t *backend); +int backend_init_wayland(backend_t *backend); +int backend_init_x11(backend_t *backend); + +/* Input device driver backends */ +int backend_init_evdev(backend_t *backend); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*BACKEND_H*/ + + diff --git a/components/test_host/main/driver_backends.c b/components/test_host/main/driver_backends.c new file mode 100644 index 0000000..4c835b7 --- /dev/null +++ b/components/test_host/main/driver_backends.c @@ -0,0 +1,281 @@ +/** + * @file driver_backends.c + * + * Copyright (c) 2025 EDGEMTech Ltd. + * + * Author: EDGEMTech Ltd, Erik Tagirov (erik.tagirov@edgemtech.ch) + */ + +/********************* + * INCLUDES + *********************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lvgl.h" + +#include "simulator_util.h" +#include "simulator_settings.h" +#include "driver_backends.h" + +#include "backends.h" + +/********************* + * DEFINES + *********************/ + +/* Catch configuration errors at compile time - checks if no backend was selected */ +#if LV_USE_SDL == 0 && \ + LV_USE_WAYLAND == 0 && \ + LV_USE_LINUX_DRM == 0 && \ + LV_USE_GLFW == 0 && \ + LV_USE_X11 == 0 && \ + LV_USE_LINUX_FBDEV == 0 + +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/* The default backend is the one that will end up at index 0 + * To add support for a new driver backend add the declaration + * and append an entry to the available_backends array + */ +backend_init_t available_backends[] = { + +#if LV_USE_LINUX_FBDEV + backend_init_fbdev, +#endif + +#if LV_USE_LINUX_DRM + backend_init_drm, +#endif + + backend_init_sdl, + +#if LV_USE_WAYLAND + backend_init_wayland, +#endif + +#if LV_USE_X11 + backend_init_x11, +#endif + +#if LV_USE_GLFW + backend_init_glfw3, +#endif + +#if LV_USE_EVDEV + backend_init_evdev, +#endif + NULL /* Sentinel */ +}; + +/* Contains the backend descriptors */ +static backend_t *backends[sizeof(available_backends) / sizeof(available_backends[0])]; + +/* Set once the user selects a backend - or it is set to the default backend */ +static backend_t *sel_display_backend = NULL; + +/********************** + * GLOBAL VARIABLES + **********************/ +/* Contains global simulator settings common to each backend */ +simulator_settings_t settings; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void driver_backends_register(void) +{ + int i; + backend_init_t init_backend; + backend_t *b; + + i = 0; + if (backends[i] != NULL) { + /* backends are already registered - leave */ + return; + } + + while ((init_backend = available_backends[i]) != NULL) { + + b = malloc(sizeof(backend_t)); + LV_ASSERT_NULL(b); + + b->handle = malloc(sizeof(backend_handle_t)); + + init_backend = available_backends[i]; + LV_ASSERT_NULL(init_backend); + + init_backend(b); + backends[i] = b; + i++; + } +} + +int driver_backends_init_backend(char *backend_name) +{ + backend_t *b; + int i; + display_backend_t *dispb; + indev_backend_t *indevb; + + if (backends[0] == NULL) { + LV_LOG_ERROR("Please call driver_backends_register first"); + return -1; + } + + if (backend_name == NULL) { + + /* + * Set default display backend - which is the first defined + * item in available_backends array + */ + LV_ASSERT_NULL(backends[0]); + b = backends[0]; + + if (b->type != BACKEND_DISPLAY) { + LV_LOG_ERROR("The default backend: %s is not a display driver backend", b->name); + return -1; + } + + backend_name = backends[0]->name; + } + + i = 0; + while ((b = backends[i]) != NULL) { + + /* Check if such a backend exists */ + if (strcmp(b->name, backend_name) == 0) { + + if (b->type == BACKEND_DISPLAY) { + /* Initialize the display */ + + dispb = b->handle->display; + LV_ASSERT_NULL(dispb->init_display); + dispb->display = dispb->init_display(); + + if (dispb->display == NULL) { + LV_LOG_ERROR("Failed to init display with %s backend", b->name); + return -1; + } + + sel_display_backend = b; + LV_LOG_INFO("Initialized %s display backend", b->name); + break; + + } else if (b->type == BACKEND_INDEV) { + /* Initialize input device */ + + indevb = b->handle->indev; + LV_ASSERT_NULL(indevb->init_indev); + + /* The display driver backend - has to be initialized first */ + if (sel_display_backend == NULL) { + LV_LOG_ERROR( + "Failed to init indev backend: %s - display needs to be initialized", + b->name); + return -1; + } + + LV_LOG_INFO("Initialized %s indev backend", b->name); + + dispb = sel_display_backend->handle->display; + + LV_ASSERT_NULL(dispb->display); + indevb->init_indev(dispb->display); + break; + } + } + i++; + } + + return 0; +} + +int driver_backends_print_supported(void) +{ + int i; + backend_t *b; + + i = 0; + if (backends[i] == NULL) { + LV_LOG_ERROR("Please call driver_backends_register first"); + return -1; + } + + b = backends[i]; + + fprintf(stdout, "Default backend: %s\n", b->name); + fprintf(stdout, "Supported backends: "); + + while ((b = backends[i++]) != NULL) { + fprintf(stdout, "%s ", b->name); + } + + fprintf(stdout, "\n"); + return 0; + +} + +int driver_backends_is_supported(char *backend_name) +{ + char c; + backend_t *b; + char *name = backend_name; + int i = 0; + + while ((c = *backend_name) != '\0') { + *backend_name = toupper(c); + backend_name++; + } + + while ((b = backends[i++]) != NULL) { + if (strcmp(b->name, name) == 0) { + return 1; + } + } + + return 0; +} + +void driver_backends_run_loop(void) +{ + display_backend_t *dispb; + + if (sel_display_backend != NULL && sel_display_backend->handle->display != NULL) { + + dispb = sel_display_backend->handle->display; + dispb->run_loop(); + + } else { + LV_LOG_ERROR("No backend has been selected - initialize the backend first"); + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + diff --git a/components/test_host/main/driver_backends.h b/components/test_host/main/driver_backends.h new file mode 100644 index 0000000..dde1cd9 --- /dev/null +++ b/components/test_host/main/driver_backends.h @@ -0,0 +1,93 @@ +/** + * @file driver_backends.h + * + * provides an abstration to support multiple graphical + * driver backends at the same time whitout recompiling everything + * each time + * + * E.g: this means LVGL can be compiled with both SDL or X11 + * + * - see backend.h for the details on the interface. + * - see the files in display_backends directory for examples + * on how to use each driver + * + * Copyright (c) 2025 EDGEMTech Ltd. + * + * Author: EDGEMTech Ltd, Erik Tagirov (erik.tagirov@edgemtech.ch) + */ + +#ifndef DRIVER_BACKENDS_H +#define DRIVER_BACKENDS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/* + * Register all available backends + * This function must be called first before any other + * function + */ +void driver_backends_register(void); + +/** + * Initialize the specified backend + * @description in case of a display driver backend + * - create the lv_display, in case of a indev driver backend + * create an input device + * + * @param backend_name the name of the backend to initialize FBDEV,DRM etc + * @return 0 on success, -1 on error + */ +int driver_backends_init_backend(char *backend_name); + +/** + * @brief Checks if a backend exists and is supported + * @param backend_name the backend name to check + * @return 1 is supported, 0 not supported or invalid name + */ +int driver_backends_is_supported(char *backend_name); + +/** + * @brief Print supported backends + * @description Prints a list of supported backends + * + * @return -1 if an error occurred, 0 on success + */ +int driver_backends_print_supported(void); + +/** + * @brief Enter the run loop + * @description enter the run loop of the selected backend + */ +void driver_backends_run_loop(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*DRIVER_BACKENDS_H*/ + + + + diff --git a/components/test_host/main/idf_component.yml b/components/test_host/main/idf_component.yml new file mode 100644 index 0000000..572695f --- /dev/null +++ b/components/test_host/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + lvgl/lvgl: + version: 9.4.0 + #espressif/esp32_p4_function_ev_board: + # version: "4.1.*" \ No newline at end of file diff --git a/components/test_host/main/sdl.c b/components/test_host/main/sdl.c new file mode 100644 index 0000000..6738682 --- /dev/null +++ b/components/test_host/main/sdl.c @@ -0,0 +1,115 @@ +/** + * @file sdl.c + * + * The backend for the SDL simulator + * + * Based on the original file from the repository + * + * - Move to a separate file + * 2025 EDGEMTech Ltd. + * + * Author: EDGEMTech Ltd, Erik Tagirov (erik.tagirov@edgemtech.ch) + * + */ + +/********************* + * INCLUDES + *********************/ +#include +#include +#include + +#include "lvgl.h" +#include "simulator_util.h" +#include "simulator_settings.h" +#include "backends.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * EXTERNAL VARIABLES + **********************/ +extern simulator_settings_t settings; + +/********************** + * STATIC PROTOTYPES + **********************/ +static void run_loop_sdl(void); +static lv_display_t *init_sdl(void); + +/********************** + * STATIC VARIABLES + **********************/ + +static char *backend_name = "SDL"; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Register the backend + * @param backend the backend descriptor + * @description configures the descriptor + */ +int backend_init_sdl(backend_t *backend) +{ + LV_ASSERT_NULL(backend); + + backend->handle->display = malloc(sizeof(display_backend_t)); + LV_ASSERT_NULL(backend->handle->display); + + backend->handle->display->init_display = init_sdl; + backend->handle->display->run_loop = run_loop_sdl; + backend->name = backend_name; + backend->type = BACKEND_DISPLAY; + + return 0; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Initialize the SDL display driver + * + * @return the LVGL display + */ +static lv_display_t *init_sdl(void) +{ + lv_display_t *disp; + + disp = lv_sdl_window_create(settings.window_width, settings.window_height); + + if (disp == NULL) { + return NULL; + } + + return disp; +} + +/** + * The run loop of the SDL driver + */ +static void run_loop_sdl(void) +{ + uint32_t idle_time; + + /* Handle LVGL tasks */ + while (true) { + /* Returns the time to the next timer execution */ + idle_time = lv_timer_handler(); + usleep(idle_time * 1000); + } +} \ No newline at end of file diff --git a/components/test_host/main/simulator_settings.h b/components/test_host/main/simulator_settings.h new file mode 100644 index 0000000..07c0597 --- /dev/null +++ b/components/test_host/main/simulator_settings.h @@ -0,0 +1,53 @@ +/** + * @file simulator_settings.h + * + * global simulator settings + * + * The simulator settings is a global variable defined in + * simulator_settings.c + * + * Copyright (c) 2025 EDGEMTech Ltd. + * + * Author: EDGEMTech Ltd, Erik Tagirov (erik.tagirov@edgemtech.ch) + * + */ + +#ifndef SIMULATOR_SETTINGS_H +#define SIMULATOR_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + uint32_t window_width; + uint32_t window_height; + bool maximize; + bool fullscreen; +} simulator_settings_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*SIMULATOR_SETTINGS_H*/ diff --git a/components/test_host/main/simulator_util.c b/components/test_host/main/simulator_util.c new file mode 100644 index 0000000..68bf75c --- /dev/null +++ b/components/test_host/main/simulator_util.c @@ -0,0 +1,66 @@ +/** + * @file simulator_util.c + * + * Utility functions + * Copyright (c) 2025 EDGEMTech Ltd. + * + * Based on the original file from the repo + * + * Author: EDGEMTech Ltd, Erik Tagirov (erik.tagirov@edgemtech.ch) + * + */ + +/********************* + * INCLUDES + *********************/ + +#include +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +const char *getenv_default(const char *name, const char *default_val) +{ + const char* value = getenv(name); + return value ? value : default_val; +} + + +void die(const char *msg, ...) +{ + va_list args; + + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + + exit(EXIT_FAILURE); + +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/components/test_host/main/simulator_util.h b/components/test_host/main/simulator_util.h new file mode 100644 index 0000000..1430f21 --- /dev/null +++ b/components/test_host/main/simulator_util.h @@ -0,0 +1,62 @@ +/** + * @file simulator_util.h + * + * simulator_util.h - Header file for the utility functions + * used by the simulator + * + * Copyright (c) 2025 EDGEMTech Ltd. + * + * Author: EDGEMTech Ltd, Erik Tagirov (erik.tagirov@edgemtech.ch) + */ + +#ifndef SIMULATOR_UTIL_H +#define SIMULATOR_UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * @description Wrapper around getenv(3), allowing to set a default value + * @param name The name of the environment variable + * @param dflt The default value to set if the variable is not present. + * @return default value or value of environment variable. + */ +const char *getenv_default(const char *name, const char *default_val); + + +/** + * @description Centralized exit point, called due to an error + * @param msg The message to display on stderr before killing the program + * @param ... Values for the format string. + */ +void die(const char *msg, ...); + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*SIMULATOR_UTIL_H*/ diff --git a/components/test_host/main/test_ihm.c b/components/test_host/main/test_ihm.c new file mode 100644 index 0000000..1fa2710 --- /dev/null +++ b/components/test_host/main/test_ihm.c @@ -0,0 +1,229 @@ + +#define LV_USE_SDL 1 +#define LV_FONT_DEFAULT &roboto_medium_36 + +#include +#include "ihm.h" +#include "mqtt_client.h" +#include "backends.h" +#include +#include "driver_backends.h" +#include "simulator_util.h" +#include "simulator_settings.h" +#include "esp_log.h" +#include "eventsManager.h" +#include "RemindMe.h" +#include "ihm_gateway.h" +#include "platform_detect.h" + +esp_mqtt_client_handle_t client; +SemaphoreHandle_t lvgl_mux; + +/* contains the name of the selected backend if user + * has specified one on the command line */ +static char *selected_backend; + +/* Global simulator settings, defined in lv_linux_backend.c */ +extern simulator_settings_t settings; + +void die(const char *msg, ...) +{ + va_list args; + + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + + exit(EXIT_FAILURE); + +} + +/** + * @brief Print LVGL version + */ +static void print_lvgl_version(void) +{ + fprintf(stdout, "%d.%d.%d-%s\n", + LVGL_VERSION_MAJOR, + LVGL_VERSION_MINOR, + LVGL_VERSION_PATCH, + LVGL_VERSION_INFO); +} + +/** + * @brief Print usage information + */ +static void print_usage(void) +{ + fprintf(stdout, "\nlvglsim [-V] [-B] [-b backend_name] [-W window_width] [-H window_height]\n\n"); + fprintf(stdout, "-V print LVGL version\n"); + fprintf(stdout, "-B list supported backends\n"); +} + +/** + * @brief Configure simulator + * @description process arguments recieved by the program to select + * appropriate options + * @param argc the count of arguments in argv + * @param argv The arguments + */ +static void configure_simulator(int argc, char **argv) +{ + int opt = 0; + + selected_backend = NULL; + driver_backends_register(); + + const char *env_w = getenv("LV_SIM_WINDOW_WIDTH"); + const char *env_h = getenv("LV_SIM_WINDOW_HEIGHT"); + /* Default values */ + settings.window_width = atoi(env_w ? env_w : "1024"); + settings.window_height = atoi(env_h ? env_h : "600"); + + /* Parse the command-line options. */ + while ((opt = getopt (argc, argv, "b:fmW:H:BVh")) != -1) { + switch (opt) { + case 'h': + print_usage(); + exit(EXIT_SUCCESS); + break; + case 'V': + print_lvgl_version(); + exit(EXIT_SUCCESS); + break; + case 'B': + driver_backends_print_supported(); + exit(EXIT_SUCCESS); + break; + case 'b': + if (driver_backends_is_supported(optarg) == 0) { + die("error no such backend: %s\n", optarg); + } + selected_backend = strdup(optarg); + break; + case 'W': + settings.window_width = atoi(optarg); + break; + case 'H': + settings.window_height = atoi(optarg); + break; + case ':': + print_usage(); + die("Option -%c requires an argument.\n", optopt); + break; + case '?': + print_usage(); + die("Unknown option -%c.\n", optopt); + } + } +} + +int app_main1(int argc, char *argv[]) { + // DĂ©tecte la plateforme + bool isPC = platform_is_pc(); + + // Init gateway + ihm_gateway_init(); + startEvtManager(); + + if (isPC) { + // PC / SDL : loop dans le thread principal + /* Initialize LVGL. */ + lv_init(); + configure_simulator(argc, argv); + /* Initialize the configured backend */ + if (driver_backends_init_backend(selected_backend) == -1) { + die("Failed to initialize display backend"); + } + lv_sdl_mouse_create(); + lv_sdl_keyboard_create(); + lv_sdl_mousewheel_create(); + lv_sdl_mousewheel_create(); + + time_t now; + struct tm timeinfo; + time(&now); + localtime_r(&now, &timeinfo); + + lv_subject_init_pointer(&timeSubj, &timeinfo); + + drawIhm(NULL); + } else { + // ESP32 : crĂ©er task FreeRTOS + xTaskCreate(drawIhm, "LVGL", 256*1024, NULL, 3, NULL); + } + + // Exemple : poster un Ă©vĂ©nement + xIHMEvent_t *evt = malloc(sizeof(*evt)); + evt->eEventType = 1; + evt->pvData = strdup("Hello LVGL"); + evt->bNeedToFreeData = true; + ihm_gateway_post_event(evt); + + return 0; +} + + +int app_main2(int argc, char *argv[]) +{ + /* code */ + printf("hello\n"); + lvgl_mux = xSemaphoreCreateRecursiveMutex(); + assert(lvgl_mux); + + init_display_ihm(); + + + //size_t watermark = uxTaskGetStackHighWaterMark(NULL); + //ESP_LOGI("STACK", "Remaining stack: %d bytes", watermark); + + + /*lv_timer_t *clock_timer = lv_timer_create(clock_timer_cb, 1000, NULL);*/ + + //draw_ihm(); + startEvtManager(); + + int count=0; + events=get_events(&count); + if (!events) + { + ESP_LOGE("test", "Aucun Ă©vĂ©nement chargĂ©"); + //return 0; + } // Parcourir tous les Ă©vĂ©nements + for (int i = 0; i < count; i++) + { + ESP_LOGI("test", "%s", events[i].affichage); + } + + xTaskCreate(drawIhm, "LVGL", 14 * 1024, getIHMQueueHandle(), 3, NULL); + //drawIhm(getIHMQueueHandle()); + send_event(EVT_WIFI_CONNECTED,NULL); + meteodailyforecast_data dts = { + .datetime= time(NULL), + .isValid= true, + .previsions = { + .desc = "EnsoleillĂ©", + .icon = "p4j", + .max = 12.40f, + .min = 3.30f + } + }; + /* + extern lv_subject_t forecastD1Subj; + extern lv_subject_t forecastD2Subj; + extern lv_subject_t forecastD3Subj; + ESP_LOGI("test_ihm", "Setting forecastD1Subj"); + + lv_subject_set_pointer(&forecastD1Subj, &dts); + lv_subject_set_pointer(&forecastD2Subj, &dts); + lv_subject_set_pointer(&forecastD3Subj, &dts); + */ + + /* Enter the run loop of the selected backend */ + driver_backends_run_loop(); + + //drawIhm(getIHMQueueHandle()); + + return 0; +} + diff --git a/components/test_host/mock/bsp/esp-bsp.h b/components/test_host/mock/bsp/esp-bsp.h new file mode 100644 index 0000000..9fd455d --- /dev/null +++ b/components/test_host/mock/bsp/esp-bsp.h @@ -0,0 +1,6 @@ +int bsp_display_lock(int arg){ + return 1; +} +void bsp_display_unlock(){ + +} \ No newline at end of file diff --git a/components/test_host/mock/esp_netif_sntp.h b/components/test_host/mock/esp_netif_sntp.h new file mode 100644 index 0000000..e69de29 diff --git a/components/test_host/mock/esp_wifi.h b/components/test_host/mock/esp_wifi.h new file mode 100644 index 0000000..177e7b3 --- /dev/null +++ b/components/test_host/mock/esp_wifi.h @@ -0,0 +1,29 @@ +#define BIT0 0x00000001 +#define WIFI_CONNECTED_BIT BIT0 + +typedef enum { + WIFI_EVENT_WIFI_READY = 0, /**< WiFi ready */ + WIFI_EVENT_SCAN_DONE, /**< finish scanning AP */ + WIFI_EVENT_STA_START, /**< station start */ + WIFI_EVENT_STA_STOP, /**< station stop */ + WIFI_EVENT_STA_CONNECTED, /**< station connected to AP */ + WIFI_EVENT_STA_DISCONNECTED, /**< station disconnected from AP */ + WIFI_EVENT_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by station changed */ + WIFI_EVENT_STA_GOT_IP, /**< station got IP from connected AP */ + WIFI_EVENT_STA_WPS_ER_SUCCESS, /**< station wps succeeds in enrollee mode */ + WIFI_EVENT_STA_WPS_ER_FAILED, /**< station wps fails in enrollee mode */ + WIFI_EVENT_STA_WPS_ER_TIMEOUT, /**< station wps timeout in enrollee mode */ + WIFI_EVENT_STA_WPS_ER_PIN, /**< station wps pin code in enrollee mode */ + WIFI_EVENT_AP_START, /**< soft-AP start */ + WIFI_EVENT_AP_STOP, /**< soft-AP stop */ + WIFI_EVENT_AP_STACONNECTED, /**< a station connected to soft-AP */ + WIFI_EVENT_AP_STADISCONNECTED, /**< a station disconnected from soft-AP */ + WIFI_EVENT_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */ + WIFI_EVENT_AP_STA_GOT_IP6, /**< station or ap interface v6IP addr is preferred */ + WIFI_EVENT_ETH_START, /**< ethernet start */ + WIFI_EVENT_ETH_STOP, /**< ethernet stop */ + WIFI_EVENT_ETH_CONNECTED, /**< ethernet phy link up */ + WIFI_EVENT_ETH_DISCONNECTED, /**< ethernet phy link down */ + WIFI_EVENT_ETH_GOT_IP, /**< ethernet got IP from connected AP */ + WIFI_EVENT_MAX +} wifi_event_id_t; diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 820098f..fc4d3af 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,7 +1,7 @@ idf_build_get_property(python SIMULATION_QEMU) message(STATUS "The Python interpreter is: ${python}") -set(comps heap nvs_flash esp_netif image_downloader fatfs protocol_examples_common mqtt) +set(comps heap nvs_flash esp_netif image_downloader fatfs protocol_examples_common mqtt meteofrance domotic_display RemindMe) if(${IDF_TARGET} STREQUAL "esp32p4") message(STATUS "SIMULATION_QEMU = OOF --> main standard") @@ -11,9 +11,28 @@ if(${IDF_TARGET} STREQUAL "esp32p4") REQUIRES ${comps} EMBED_TXTFILES ${PROJECT_DIR}/main/ca_cert.pem EMBED_FILES "index.html") +elseif(${IDF_TARGET} STREQUAL "linux") + message(STATUS "Linux Mode --> main standard") + list(APPEND comps vfs esp_http_server) + idf_component_register(SRCS main.c + INCLUDE_DIRS "./include" + REQUIRES ${comps} + EMBED_TXTFILES ${PROJECT_DIR}/main/ca_cert.pem + EMBED_FILES "index.html") + + message("Including SDL2 support") + find_package(SDL2 REQUIRED) + target_link_libraries(${COMPONENT_LIB} PUBLIC + -Wl,--no-as-needed + SDL2 + -Wl,--as-needed + ) + + target_compile_options(${COMPONENT_LIB} PUBLIC --coverage -DLV_LVGL_H_INCLUDE_SIMPLE ) + else() message(STATUS "SIMULATION_QEMU = On vide le main") - idf_component_register(SRCS test_main.c) + idf_component_register(SRCS test_main.c PRIV_REQUIRES meteofrance) return() endif() diff --git a/main/idf_component.yml b/main/idf_component.yml index 7430317..9f9c9f7 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -25,4 +25,8 @@ dependencies: version: 9.4.0 #espressif/esp32_p4_function_ev_board: # version: "4.1.*" - espressif/esp32_p4_function_ev_board: '*' + espressif/esp32_p4_function_ev_board: + version: '*' + rules: + - if: target in ["esp32p4"] + diff --git a/main/main.c b/main/main.c index 05909a8..a602e88 100644 --- a/main/main.c +++ b/main/main.c @@ -8,33 +8,30 @@ #include "esp_event.h" #include "nvs_flash.h" #include -#include "esp_vfs_fat.h" -#include "sdmmc_cmd.h" #include -#include "bh1750.h" #include #include "esp_http_server.h" -#include "bsp/esp-bsp.h" #include "main.h" #include "ihm.h" +#include "ihm_gateway.h" // OTA -#include "esp_ota_ops.h" +/*#include "esp_ota_ops.h" #include "esp_http_client.h" #include "esp_https_ota.h" - +*/ // Includes personnels -#include "wifi_logger.h" +//#include "wifi_logger.h" #include "obtain_time.h" #include "image_downloader.h" #include "include/communication.h" #include "stateManagement.h" -#include "driver/gpio.h" -#include "am2302_rmt.h" +//#include "driver/gpio.h" +//#include "am2302_rmt.h" #include "eventsManager.h" #include "esp_timer.h" @@ -44,7 +41,7 @@ // GPIO assignment #define AM2302_GPIO 4 -#include "esp_littlefs.h" +//#include "esp_littlefs.h" #define MOUNT_POINT "/sdcard" // Pin assignments can be set in menuconfig, see "SD SPI Example Configuration" menu. @@ -59,7 +56,7 @@ #define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */ #define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */ -static bh1750_handle_t bh1750 = NULL; +//static bh1750_handle_t bh1750 = NULL; static const char *TAG = "domoTic"; @@ -76,7 +73,7 @@ static void wifiStatus_obs_cb(lv_observer_t * observer, lv_subject_t * subject); lv_subject_t mqttStatus; -lv_subject_t wifiStatus; +//lv_subject_t wifiStatus; extern lv_subject_t tempIntSubj; extern lv_subject_t tempExtSubj; @@ -84,7 +81,7 @@ extern lv_subject_t hauteurCuveSubj; extern lv_subject_t hauteurCuveEvolSubj; void init_display(){ - lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG(); +/* lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG(); lvgl_cfg.task_priority=15; bsp_display_cfg_t cfg = { .lvgl_port_cfg = lvgl_cfg, @@ -104,28 +101,31 @@ void init_display(){ bsp_display_brightness_set(50); mainState.display_init=true; + */ } /** * @brief i2c master initialization */ -static void i2c_bus_init(i2c_master_bus_handle_t *bus_handle) +/* static void i2c_bus_init(i2c_master_bus_handle_t *bus_handle) { - i2c_master_bus_config_t conf; - conf.sda_io_num = (gpio_num_t)I2C_MASTER_SDA_IO; - conf.flags.enable_internal_pullup=true; - conf.scl_io_num = (gpio_num_t)I2C_MASTER_SCL_IO; - conf.i2c_port=I2C_NUM_0; - conf.clk_source = I2C_CLK_SRC_DEFAULT; - conf.glitch_ignore_cnt = 7; - ESP_ERROR_CHECK(i2c_new_master_bus(&conf, bus_handle)); + // i2c_master_bus_config_t conf; + // conf.sda_io_num = (gpio_num_t)I2C_MASTER_SDA_IO; + // conf.flags.enable_internal_pullup=true; + // conf.scl_io_num = (gpio_num_t)I2C_MASTER_SCL_IO; + // conf.i2c_port=I2C_NUM_0; + // conf.clk_source = I2C_CLK_SRC_DEFAULT; + // conf.glitch_ignore_cnt = 7; + // ESP_ERROR_CHECK(i2c_new_master_bus(&conf, bus_handle)); } - + */ void bh1750_init(void) { + /* i2c_master_bus_handle_t bus_handle; i2c_bus_init(&bus_handle); bh1750 = bh1750_create(I2C_MASTER_NUM, BH1750_I2C_ADDRESS_DEFAULT, bus_handle); + */ } @@ -133,47 +133,47 @@ void mqtt_cb(mqtt_evt evt, esp_mqtt_event_handle_t event){ switch (evt) { case MQTT_CONNECTED: - if(lvgl_port_lock(50)){ + //if(lvgl_port_lock(50)){ ESP_LOGV(TAG,"Statut mqttStatus 1"); - lv_subject_set_int(&mqttStatus,1); - lvgl_port_unlock(); - } + //lv_subject_set_int(&mqttStatus,1); + //lvgl_port_unlock(); + //} break; case MQTT_DISCONNECTED: - if(lvgl_port_lock(50)){ + //if(lvgl_port_lock(50)){ ESP_LOGE(TAG,"Statut mqttStatus 0"); - lv_subject_set_int(&mqttStatus,0); - lvgl_port_unlock(); - } + //lv_subject_set_int(&mqttStatus,0); + //lvgl_port_unlock(); + //} esp_mqtt_client_reconnect(event->client); break; case MQTT_DATA_RECEIVED: - lv_subject_set_int(&mqttStatus,2); + //lv_subject_set_int(&mqttStatus,2); ESP_LOGD(TAG, "\nMQTT_EVENT_DATA"); ESP_LOGD(TAG, "TOPIC=%.*s\n", event->topic_len, event->topic); ESP_LOGD(TAG, "DATA=%.*s\n", event->data_len, event->data); char *topic = strndup(event->topic, event->topic_len); if (strcmp(topic, topicTempExt) == 0) { - if(lvgl_port_lock(50)){ + //if(lvgl_port_lock(50)){ float temp = strtof(event->data, NULL); char buff[5]; sprintf(buff,"%.1f",temp); - lv_subject_copy_string(&tempExtSubj, buff); + //lv_subject_copy_string(&tempExtSubj, buff); - lvgl_port_unlock(); - } + //lvgl_port_unlock(); + //} } else if (strcmp(topic, topicTempInt) == 0) { - if(lvgl_port_lock(0)){ + //if(lvgl_port_lock(0)){ // on retransforme en float pour ne garder que la partie entiere de la tempĂ©rature float temp = strtof(event->data, NULL); char buff[5]; sprintf(buff,"%.1f",temp); - lv_subject_copy_string(&tempIntSubj, buff); - lvgl_port_unlock(); - } + //lv_subject_copy_string(&tempIntSubj, buff); + //lvgl_port_unlock(); + //} } /*else if (strncmp(event->topic, topicHauteurCuveEvol, event->topic_len) == 0) { @@ -227,7 +227,7 @@ void mqtt_cb(mqtt_evt evt, esp_mqtt_event_handle_t event){ char *datas = strndup(event->data, event->data_len); if(strcmp(datas,"restart")==0){ ESP_LOGI(TAG," Commande 'restart' recue"); - esp_restart(); + //esp_restart(); } } else @@ -235,10 +235,10 @@ void mqtt_cb(mqtt_evt evt, esp_mqtt_event_handle_t event){ ESP_LOGE(TAG, "None match :-( %s", topic); } free(topic); - if (lvgl_port_lock(50)){ - lv_subject_set_int(&mqttStatus,3); - lvgl_port_unlock(); - } + //if (lvgl_port_lock(50)){ + //lv_subject_set_int(&mqttStatus,3); + //lvgl_port_unlock(); + //} break; default: @@ -255,7 +255,7 @@ struct state mainState={ void mount_sd_card() { - // Options for mounting the filesystem. +/* // Options for mounting the filesystem. // If format_if_mount_failed is set to true, SD card will be partitioned and // formatted in case when mounting fails. esp_vfs_fat_sdmmc_mount_config_t mount_config = { @@ -311,13 +311,13 @@ void mount_sd_card() // Card has been initialized, print its properties sdmmc_card_print_info(stdout, card); -} + */} extern char *days[7]; extern char *months[12]; -esp_err_t _ota_http_event_handler(esp_http_client_event_t *evt) +/* esp_err_t _ota_http_event_handler(esp_http_client_event_t *evt) { switch (evt->event_id) { case HTTP_EVENT_ERROR: @@ -347,11 +347,11 @@ esp_err_t _ota_http_event_handler(esp_http_client_event_t *evt) } return ESP_OK; } - + */ extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start"); extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end"); -static esp_err_t validate_image_header(esp_app_desc_t *new_app_info) +/* static esp_err_t validate_image_header(esp_app_desc_t *new_app_info) { if (new_app_info == NULL) { return ESP_ERR_INVALID_ARG; @@ -372,12 +372,12 @@ static esp_err_t validate_image_header(esp_app_desc_t *new_app_info) return ESP_OK; } - + */ void simple_ota_example_task(void *pvParameter) { - ESP_LOGE(TAG,"En attente connexion wifi"); +/* ESP_LOGE(TAG,"En attente connexion wifi"); // Waiting until either the connection is established (WIFI_CONNECTED_BIT). EventBits_t bits = xEventGroupWaitBits(domotic_event_group, BIT0, @@ -503,13 +503,13 @@ ota_end: ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed"); vTaskDelete(NULL); } -} + */} -am2302_handle_t sensor = NULL; +//am2302_handle_t sensor = NULL; void readTempHumid(void *pvParameter) { - float temperature = 0; +/* float temperature = 0; float humidity = 0; while (1) { @@ -524,7 +524,7 @@ void readTempHumid(void *pvParameter) //xQueueSendToFront(ihm_queue,&m,5); vTaskDelay(60000 / portTICK_PERIOD_MS); } - + */ } void alloc_fail(size_t size, uint32_t caps, const char * function_name){ @@ -538,16 +538,16 @@ bool ecranEteint=true; // Ce timer permet d'eteindre l'ecran "arretAuto" apres la derniere prĂ©sence dĂ©tectĂ©e esp_timer_handle_t presence_timer; -static void IRAM_ATTR gpio_isr_handler(void* arg) +/* static void IRAM_ATTR gpio_isr_handler(void* arg) { uint32_t gpio_num = (uint32_t) arg; xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); } - + */ float maxBrightness = 100; -static void gpio_task_example(void* arg) +/* static void gpio_task_example(void* arg) { uint32_t io_num; int delay=50; @@ -574,10 +574,10 @@ static void gpio_task_example(void* arg) } } } -#define GPIO_INPUT_IO_0 CONFIG_GPIO_INPUT_CAPTEUR_PIR + */#define GPIO_INPUT_IO_0 CONFIG_GPIO_INPUT_CAPTEUR_PIR void initPirSensor(){ - //create a queue to handle gpio event from isr +/* //create a queue to handle gpio event from isr gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); //start gpio task xTaskCreate(gpio_task_example, "gpio_task_example", 5000, NULL, 10, NULL); @@ -591,11 +591,11 @@ void initPirSensor(){ ESP_ERROR_CHECK(gpio_config(&gpioconf)); gpio_install_isr_service(0); gpio_isr_handler_add(GPIO_INPUT_IO_0,gpio_isr_handler,(void*)(GPIO_INPUT_IO_0)); - + */ } /* Ce timer permet d'eteindre l'ecran apres @arretAuto de prĂ©sence*/ -static void presence_timer_callback(void* arg) +/* static void presence_timer_callback(void* arg) { int64_t time_since_boot = esp_timer_get_time(); for (int i = maxBrightness; i >= 0; i-=2) @@ -608,7 +608,7 @@ static void presence_timer_callback(void* arg) } ecranEteint=true; } - + */ static esp_err_t download_get_handler(httpd_req_t *req) { httpd_resp_set_type(req, "application/octet-stream"); httpd_resp_set_hdr(req, "Content-Disposition", @@ -749,27 +749,27 @@ void weather_data_retreived(struct meteodailyforecast_data dailyDatas[3], struct printf("%f\n", datas[2].previsions.value); ESP_LOGE(TAG, "fin debug"); */ - if (display_lock("weather_data_retreived")) - { + //if (display_lock("weather_data_retreived")) + //{ ESP_LOGV("MeteoFrance", "------------------------------------- Set des subjects J --------------------------------"); // PrĂ©visions des 3 prochains jours - lv_subject_set_pointer(&forecastD1Subj, &dailyDatas[0]); - lv_subject_set_pointer(&forecastD2Subj, &dailyDatas[1]); - lv_subject_set_pointer(&forecastD3Subj, &dailyDatas[2]); + //lv_subject_set_pointer(&forecastD1Subj, &dailyDatas[0]); + //lv_subject_set_pointer(&forecastD2Subj, &dailyDatas[1]); + //lv_subject_set_pointer(&forecastD3Subj, &dailyDatas[2]); ESP_LOGV("MeteoFrance", "------------------------------------- Set des subjects H--------------------------------"); // PrĂ©visions des 3 prochains jours ESP_LOGV("MeteoFrance", "Pointeur %lli", datas[0].datetime); - lv_subject_set_pointer(&forecastH1Subj, &datas[0]); - lv_subject_set_pointer(&forecastH2Subj, &datas[1]); - lv_subject_set_pointer(&forecastH3Subj, &datas[2]); + //lv_subject_set_pointer(&forecastH1Subj, &datas[0]); + //lv_subject_set_pointer(&forecastH2Subj, &datas[1]); + // lv_subject_set_pointer(&forecastH3Subj, &datas[2]); - lv_subject_set_int(&meteoStatus, 0); - display_unlock("weather_data_retreived"); + //lv_subject_set_int(&meteoStatus, 0); + //display_unlock("weather_data_retreived"); ESP_LOGV(TAG, "------------------------------------- Fin Set des subjects --------------------------------"); - }else{ + //}else{ ESP_LOGE(TAG, "Impossible d'obtenir le mutex dans weather_data_retreived"); - } + //} } void weather_data_retreived_start() @@ -777,7 +777,7 @@ void weather_data_retreived_start() //if (display_lock("weather_data_retreived_start")) //{ //ESP_LOGE(TAG,"Mutex obtenu dans weather_data_retreived_start"); - lv_subject_set_int(&meteoStatus, 1); + //lv_subject_set_int(&meteoStatus, 1); ESP_LOGE(TAG,"Subject setted weather_data_retreived_start"); //display_unlock("weather_data_retreived_start"); //}else{ @@ -788,7 +788,7 @@ void weather_data_retreived_start() LV_IMAGE_DECLARE(mqtt_ok); LV_IMAGE_DECLARE(mqtt_ko); -static void mqttStatus_obs_cb(lv_observer_t * observer, lv_subject_t * subject) +/* static void mqttStatus_obs_cb(lv_observer_t * observer, lv_subject_t * subject) { ESP_LOGV(TAG, "On passe dans le callback de chgt de statut; %li", lv_subject_get_int(subject)); if(lvgl_port_lock(0)){ @@ -825,7 +825,7 @@ static void mqttStatus_obs_cb(lv_observer_t * observer, lv_subject_t * subject) //lv_obj_t * btn = lv_observer_get_target(observer); } - + */ typedef struct { float Lmin; // lux min (ex. 1) @@ -878,7 +878,7 @@ int32_t map_value(int32_t x, int32_t in_min, int32_t in_max, int32_t out_min, in } void lightSensorTask(void *pvParameter){ - float bh1750_data; +/* float bh1750_data; while(1){ ESP_ERROR_CHECK(bh1750_get_data(bh1750, &bh1750_data)); //maxBrightness = map_value(bh1750_data, 0,300,0, 100); @@ -893,43 +893,59 @@ void lightSensorTask(void *pvParameter){ bsp_display_brightness_set(maxBrightness); vTaskDelay(pdMS_TO_TICKS(100)); } - + */ } + static lv_display_t *display; + static lv_indev_t *mouse; + static lv_indev_t *mouse_wheel; + static lv_indev_t *keyboard; void app_main(void) { - esp_task_wdt_deinit(); // dĂ©sactive le task watchdog + printf("Hello from sim\n"); + + lv_init(); + display = lv_sdl_window_create(1024, 600); + mouse = lv_sdl_mouse_create(); + mouse_wheel = lv_sdl_mousewheel_create(); + keyboard = lv_sdl_keyboard_create(); + + ihm_gateway_init(); + startEvtManager(); + drawIhm(NULL); + + /* Create widgets on the screen */ + //lv_demo_widgets(); + +} + +void app_main1(void) +{ + //esp_task_wdt_deinit(); // dĂ©sactive le task watchdog vTaskDelay(pdMS_TO_TICKS(10000)); // laisse le temps d'attacher GDB - bh1750_measure_mode_t cmd_measure; + //bh1750_measure_mode_t cmd_measure; startEvtManager(); init_display(); - const esp_timer_create_args_t periodic_timer_args = { +/* const esp_timer_create_args_t periodic_timer_args = { .callback = &presence_timer_callback, - /* name is optional, but may help identify the timer when debugging */ + // name is optional, but may help identify the timer when debugging .name = "presence" }; ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &presence_timer)); - /* Start the timers */ + // Start the timers ESP_ERROR_CHECK(esp_timer_start_once(presence_timer, 30*1000*1000)); - + */ initPirSensor(); - printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size()); - printf("Free heap size: %" PRIu32 " bytes\n", esp_get_free_heap_size()); - heap_caps_print_heap_info(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - heap_caps_register_failed_alloc_callback(alloc_fail); - - printf("1- Free heap after buffers allocation: %d\n", xPortGetFreeHeapSize()); - esp_log_level_set("wifi", ESP_LOG_ERROR); esp_log_level_set(TAG, ESP_LOG_VERBOSE); //mount_sd_card(); - bsp_sdcard_mount(); +/* bsp_sdcard_mount(); ESP_LOGI(TAG, "Initializing LittleFS"); @@ -965,7 +981,7 @@ void app_main(void) ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); } - // On affiche au plus tot l'ecran de dĂ©marrage + */ // On affiche au plus tot l'ecran de dĂ©marrage // ESP_ERROR_CHECK(esp_lcd_panel_mirror(lcd_panel,true,true)); xTaskCreatePinnedToCore(&drawIhm,"ihm_task",10000,getIHMQueueHandle(),10,NULL,0); @@ -981,19 +997,19 @@ void app_main(void) ESP_ERROR_CHECK(ret); ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); - wifi_init_sta(wifi_cb); + //wifi_init_sta(wifi_cb); //start_wifi_logger(); //wifi_log_e("test", "%s %d %f", "hello world wifi logger", 43, 45.341223242); // write log over wifi with log level -> ERROR esp_log_level_set("tcp_handler", ESP_LOG_NONE); - printf("8b - Free heap after buffers allocation: %d\n", xPortGetFreeHeapSize()); + printf("8b - Free heap after buffers allocation: %zu\n", xPortGetFreeHeapSize()); - printf("9 - Free heap after buffers allocation: %d\n", xPortGetFreeHeapSize()); + printf("9 - Free heap after buffers allocation: %zu\n", xPortGetFreeHeapSize()); /* Ensure to disable any WiFi power save mode, this allows best throughput * and hence timings for overall OTA operation. */ - esp_wifi_set_ps(WIFI_PS_NONE); - xTaskCreatePinnedToCore(&simple_ota_example_task, "ota__task", 8192, NULL, 6, NULL,0); + //esp_wifi_set_ps(WIFI_PS_NONE); + //xTaskCreatePinnedToCore(&simple_ota_example_task, "ota__task", 8192, NULL, 6, NULL,0); on_weather_data_retrieval(weather_data_retreived); on_weather_data_retrieval_start(weather_data_retreived_start); @@ -1008,20 +1024,21 @@ void app_main(void) } - mqtt_app_start(mqtt_cb, domotic_event_group); + //mqtt_app_start(mqtt_cb, domotic_event_group); //start_wifi_logger(); //wifi_log_e("test", "%s %d %f", "hello world wifi logger", 43, 45.341223242); // write log over wifi with log level -> ERROR } - lv_subject_init_int(&mqttStatus,-1); - lv_subject_add_observer_obj(&mqttStatus, mqttStatus_obs_cb, NULL, NULL); + //lv_subject_init_int(&mqttStatus,-1); + //lv_subject_add_observer_obj(&mqttStatus, mqttStatus_obs_cb, NULL, NULL); while(!mainState.wifi_init){ vTaskDelay(pdTICKS_TO_MS(10)); } start_webserver(); - // Configuration de la sonde Temp/Humid. + +/* // Configuration de la sonde Temp/Humid. am2302_config_t am2302_config = { .gpio_num = AM2302_GPIO, }; @@ -1030,5 +1047,5 @@ void app_main(void) }; ESP_ERROR_CHECK(am2302_new_sensor_rmt(&am2302_config, &rmt_config, &sensor)); xTaskCreate(&readTempHumid, "read_temp_task", 8192, NULL, 5, NULL); - + */ } diff --git a/main/test_main.c b/main/test_main.c index cae06d0..79c2146 100644 --- a/main/test_main.c +++ b/main/test_main.c @@ -1,12 +1,9 @@ #include #include "meteofrance.h" #include "eventsManager.h" -#include "esp_lcd_panel_ops.h" -#include "esp_lcd_qemu_rgb.h" #include "lvgl.h" #include "esp_log.h" -#include "ihm.h" #include "esp_heap_caps.h" extern EventGroupHandle_t domotic_event_group;