diff --git a/.clang-format b/.clang-format index f6605270..03091be4 100644 --- a/.clang-format +++ b/.clang-format @@ -1,12 +1,12 @@ --- -Language: Cpp +Language: Cpp # BasedOnStyle: LLVM AccessModifierOffset: -2 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: true AlignConsecutiveDeclarations: false AlignEscapedNewlinesLeft: false -AlignOperands: true +AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false @@ -21,51 +21,51 @@ AlwaysBreakTemplateDeclarations: false BinPackArguments: true BinPackParameters: true BreakBeforeBraces: Custom -BraceWrapping: - AfterClass: false +BraceWrapping: + AfterClass: false AfterControlStatement: false - AfterEnum: false - AfterFunction: true - AfterNamespace: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false AfterObjCDeclaration: false - AfterStruct: true - AfterUnion: true - BeforeCatch: false - BeforeElse: false - IndentBraces: false + AfterStruct: true + AfterUnion: true + BeforeCatch: false + BeforeElse: false + IndentBraces: false SplitEmptyFunction: false BreakBeforeBinaryOperators: None BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true -ColumnLimit: 120 -CommentPragmas: '^ IWYU pragma:' +ColumnLimit: 120 +CommentPragmas: "^ IWYU pragma:" ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false -DisableFormat: false +DisableFormat: false ExperimentalAutoDetectBinPacking: false -ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] -IncludeCategories: - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Priority: 2 - - Regex: '^(<|"(gtest|isl|json)/)' - Priority: 3 - - Regex: '.*' - Priority: 1 -IncludeIsMainRegex: '$' +ForEachMacros: [foreach, Q_FOREACH, BOOST_FOREACH] +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|isl|json)/)' + Priority: 3 + - Regex: ".*" + Priority: 1 +IncludeIsMainRegex: "$" IndentCaseLabels: true -IndentWidth: 4 +IndentWidth: 4 IndentWrappedFunctionNames: false -IndentPPDirectives: BeforeHash +# IndentPPDirectives: BeforeHash JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: true -MacroBlockBegin: '' -MacroBlockEnd: '' +MacroBlockBegin: "" +MacroBlockEnd: "" MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCBlockIndentWidth: 2 @@ -77,21 +77,20 @@ PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 -PointerAlignment: Middle -ReflowComments: true -SortIncludes: false +PointerAlignment: Left +ReflowComments: true +SortIncludes: false SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true SpaceBeforeParens: Never SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 -SpacesInAngles: false +SpacesInAngles: false SpacesInContainerLiterals: false SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false -Standard: Cpp11 -TabWidth: 4 -UseTab: Never -... +Standard: Cpp11 +TabWidth: 4 +UseTab: Never diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 09882fc0..190e2497 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,48 +1,55 @@ -name: Build master branch +name: Build 0.4.0-dev branch -on: [push] +on: [push, workflow_dispatch] jobs: build: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Cache pip - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - name: Cache PlatformIO - uses: actions/cache@v2 - with: - path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - - name: Set up Python - uses: actions/setup-python@v2 - - name: Install PlatformIO - run: | - python -m pip install --upgrade pip - pip install --upgrade platformio - - name: Enable ESP platforms from platformio_override-template.ini - run: | - sed 's/; user_setups\/esp/user_setups\/esp/g' platformio_override-template.ini > platformio_override.ini - - name: List all files in current folder - run: | - ls -la - - name: Cat platformio_override.ini - run: | - cat platformio_override.ini - - name: Run PlatformIO - run: pio run -e d1-mini-esp32_ili9341 -e lanbon_l8 -e wt32-sc01 -e d1-mini-esp8266_ili9341 - - name: Upload output file - uses: actions/upload-artifact@v2 - with: - name: hasp-lvgl firmware.zip - path: build_output/firmware/*.bin + - uses: actions/checkout@v2 + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Cache PlatformIO + uses: actions/cache@v2 + with: + path: ~/.platformio + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + - name: Set up Python + uses: actions/setup-python@v2 + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + - name: Enable ESP platforms from platformio_override-template.ini + run: | + sed 's/; user_setups\/esp/user_setups\/esp/g' platformio_override-template.ini > platformio_override.ini + - name: Enable Linux platform from platformio_override.ini + run: | + sed -i 's/; user_setups\/linux/user_setups\/linux/g' platformio_override.ini + mkdir -p .pio/libdeps/linux_sdl_64bits/paho/src + - name: Install SDL2 library + run: | + sudo apt-get update + sudo apt-get install libsdl2-dev + - name: List all files in current folder + run: | + ls -la + - name: Cat platformio_override.ini + run: | + cat platformio_override.ini + - name: Run PlatformIO + run: pio run -e d1-mini-esp32_ili9341 -e esp32-touchdown -e huzzah32-featherwing-24 -e huzzah32-featherwing-35 -e lanbon_l8 -e m5stack-core2 -e wt32-sc01 -e d1-mini-esp8266_ili9341 -e linux_sdl_64bits + - name: Upload output file + uses: actions/upload-artifact@v2 + with: + name: hasp-lvgl firmware.zip + path: build_output/firmware/*.bin #- name: Create release and upload firmware # run: | # set -x diff --git a/.gitignore b/.gitignore index 24f89b84..43182a35 100644 --- a/.gitignore +++ b/.gitignore @@ -6,18 +6,23 @@ .pio data/* src/user_setups/active/* +include/user_config_override.h src/user_config_override.h +user_config_override.h platformio_override.ini user_setups/active/* build_output/* build_output/firmware/*.bin +build_output/firmware/*.exe ## Test result files *.xml *.bin ## Visual Studio Code specific ###### -.vscode +!.vscode +.vscode/* +!.vscode/extensions.json .vscode/.browse.c_cpp.db* .vscode/c_cpp_properties.json .vscode/launch.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..d304a5ef --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "ms-vscode.cpptools", + "platformio.platformio-ide" + ] +} diff --git a/README.md b/README.md index 49b9dc7c..6b4437fd 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Control your home-automation devices from a customizable touchscreen UI connecte This project is a re-implementation of the popular HASwitchPlate sketch created by aderusha. The [original HASwitchPlate][1] project uses a Wemos D1 mini and requires a Nextion/TJC HMI display. -This rewrite removes the Nextion/TJC requirement by using the [Littlev Graphics Library][2] on the MCU to drive a cheap commodity display. +This rewrite removes the Nextion/TJC requirement by using the [Light and Versatile Graphics Library][2] on the MCU to drive a cheap commodity display. This version also adds ESP32 and STM32F4 support to take advantage of the additional hardware capabilities. @@ -72,7 +72,7 @@ For support using hasp-lvgl, please join the [#hasp-lvgl channel][6] on Discord. [1]: https://github.com/aderusha/HASwitchPlate -[2]: https://github.com/littlevgl/lvgl +[2]: https://github.com/lvgl/lvgl [3]: https://littlevgl.com/themes [4]: https://github.com/fvanroie/HMI-Font-Pack/releases [5]: https://fontawesome.com/cheatsheet/ diff --git a/hal/sdl2/app_hal.c b/hal/sdl2/app_hal.c new file mode 100644 index 00000000..fd062ada --- /dev/null +++ b/hal/sdl2/app_hal.c @@ -0,0 +1,55 @@ +#include +#define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" issue*/ +#include +#include "display/monitor.h" +#include "indev/mouse.h" +#include "indev/mousewheel.h" +#include "indev/keyboard.h" + +/** + * A task to measure the elapsed time for LittlevGL + * @param data unused + * @return never return + */ +static int tick_thread(void* data) +{ + (void)data; + + while(1) { + SDL_Delay(5); /*Sleep for 5 millisecond*/ + lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/ + } + + return 0; +} + +void hal_setup(void) +{ +// Workaround for sdl2 `-m32` crash +// https://bugs.launchpad.net/ubuntu/+source/libsdl2/+bug/1775067/comments/7 +#ifndef WIN32 + setenv("DBUS_FATAL_WARNINGS", "0", 1); +#endif + + /* Add a display + * Use the 'monitor' driver which creates window on PC's monitor to simulate a display*/ + monitor_init(MONITOR_HOR_RES, MONITOR_VER_RES); + + /* Add the mouse as input device + * Use the 'mouse' driver which reads the PC's mouse*/ + mouse_init(); + + /* Tick init. + * You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed + * Create an SDL thread to do this*/ + SDL_CreateThread(tick_thread, "tick", NULL); +} + +void hal_loop(void) +{ + // we don't use thise !! + // while(1) { + // SDL_Delay(5); + // lv_task_handler(); + // } +} diff --git a/hal/sdl2/app_hal.h b/hal/sdl2/app_hal.h new file mode 100644 index 00000000..58a5b9df --- /dev/null +++ b/hal/sdl2/app_hal.h @@ -0,0 +1,17 @@ +#ifndef DRIVER_H +#define DRIVER_H + +#ifdef __cplusplus +extern "C" { +#endif + + +void hal_setup(void); +void hal_loop(void); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*DRIVER_H*/ diff --git a/hal/stm32f407_btt/app_hal.c b/hal/stm32f407_btt/app_hal.c new file mode 100644 index 00000000..639a3b04 --- /dev/null +++ b/hal/stm32f407_btt/app_hal.c @@ -0,0 +1,50 @@ + +#include "Arduino.h" + +#include "stm32f4xx.h" +//#include "stm32f429i_discovery.h" +#include "tft.h" +//#include "touchpad.h" + +#ifdef USE_RTOS_SYSTICK +#include +#endif + +void hal_setup(void) +{ + pinMode(PD12, OUTPUT); + digitalWrite(PD12, HIGH); + + // HAL_Init(); + + // /* Configure the system clock to 180 MHz */ + // SystemClock_Config(); + + // /* Start up indication */ + // BSP_LED_Init(LED3); + // for (uint8_t i = 0; i < 8; i++) { BSP_LED_Toggle(LED3); delay(50); } + + tft_init(); + //touchpad_init(); +} + +// void SysTick_Handler(void) +// { +// HAL_IncTick(); +// HAL_SYSTICK_IRQHandler(); + +// lv_tick_inc(1); + +// #ifdef USE_RTOS_SYSTICK +// osSystickHandler(); +// #endif +// } + +void hal_loop(void) +{ + //while (1) + { + delay(5); + lv_task_handler(); + } +} diff --git a/hal/stm32f407_btt/app_hal.h b/hal/stm32f407_btt/app_hal.h new file mode 100644 index 00000000..58a5b9df --- /dev/null +++ b/hal/stm32f407_btt/app_hal.h @@ -0,0 +1,17 @@ +#ifndef DRIVER_H +#define DRIVER_H + +#ifdef __cplusplus +extern "C" { +#endif + + +void hal_setup(void); +void hal_loop(void); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*DRIVER_H*/ diff --git a/hal/stm32f407_btt/tft.c b/hal/stm32f407_btt/tft.c new file mode 100644 index 00000000..76ab6061 --- /dev/null +++ b/hal/stm32f407_btt/tft.c @@ -0,0 +1,65 @@ +/** + * @file disp.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include + +#include "tft.h" +#include "stm32f4xx.h" +#include "fsmc_ssd1963.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static lv_disp_drv_t disp_drv; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +/** + * Initialize your display here + */ +void tft_init(void) +{ + static lv_color_t disp_buf1[TFT_HOR_RES * 40]; + static lv_disp_buf_t buf; + lv_disp_buf_init(&buf, disp_buf1, NULL, TFT_HOR_RES * 40); + + lv_disp_drv_init(&disp_drv); + fsmc_ssd1963_init(0, false); + + disp_drv.buffer = &buf; + disp_drv.flush_cb = fsmc_ssd1963_flush; + disp_drv.hor_res = TFT_HOR_RES; + disp_drv.ver_res = TFT_VER_RES; +#if TFT_USE_GPU != 0 + DMA2D_Config(); + disp_drv.gpu_blend_cb = gpu_mem_blend; + disp_drv.gpu_fill_cb = gpu_mem_fill; +#endif + lv_disp_drv_register(&disp_drv); +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/hal/stm32f407_btt/tft.h b/hal/stm32f407_btt/tft.h new file mode 100644 index 00000000..fc54bb03 --- /dev/null +++ b/hal/stm32f407_btt/tft.h @@ -0,0 +1,37 @@ +/** + * @file disp.h + * + */ + +#ifndef DISP_H +#define DISP_H + +/********************* + * INCLUDES + *********************/ +#include +#include "lvgl.h" + +/********************* + * DEFINES + *********************/ +#define TFT_HOR_RES TFT_WIDTH +#define TFT_VER_RES TFT_HEIGHT + +#define TFT_EXT_FB 1 /*Frame buffer is located into an external SDRAM*/ +#define TFT_USE_GPU 0 /*Enable hardware accelerator*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void tft_init(void); + +/********************** + * MACROS + **********************/ + +#endif diff --git a/hal/stm32f429_disco/app_hal.c b/hal/stm32f429_disco/app_hal.c new file mode 100644 index 00000000..c7aa120f --- /dev/null +++ b/hal/stm32f429_disco/app_hal.c @@ -0,0 +1,123 @@ + +#include "stm32f4xx.h" +#include "stm32f429i_discovery.h" +#include "tft.h" +#include "touchpad.h" + +#ifdef USE_RTOS_SYSTICK +#include +#endif + + +/** + * @brief System Clock Configuration + * The system Clock is configured as follow : + * System Clock source = PLL (HSE) + * SYSCLK(Hz) = 180000000 + * HCLK(Hz) = 180000000 + * AHB Prescaler = 1 + * APB1 Prescaler = 4 + * APB2 Prescaler = 2 + * HSE Frequency(Hz) = 8000000 + * PLL_M = 8 + * PLL_N = 360 + * PLL_P = 2 + * PLL_Q = 7 + * VDD(V) = 3.3 + * Main regulator output voltage = Scale1 mode + * Flash Latency(WS) = 5 + * The LTDC Clock is configured as follow : + * PLLSAIN = 192 + * PLLSAIR = 4 + * PLLSAIDivR = 8 + * @param None + * @retval None + */ +static void SystemClock_Config(void) +{ + RCC_ClkInitTypeDef RCC_ClkInitStruct; + RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + + /* Enable Power Control clock */ + __HAL_RCC_PWR_CLK_ENABLE(); + + /* The voltage scaling allows optimizing the power consumption when the device is + clocked below the maximum system frequency, to update the voltage scaling value + regarding system frequency refer to product datasheet. */ + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + /*##-1- System Clock Configuration #########################################*/ + /* Enable HSE Oscillator and activate PLL with HSE as source */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = 8; + RCC_OscInitStruct.PLL.PLLN = 360; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; + RCC_OscInitStruct.PLL.PLLQ = 7; + HAL_RCC_OscConfig(&RCC_OscInitStruct); + + /* Activate the Over-Drive mode */ + HAL_PWREx_EnableOverDrive(); + + /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 + clocks dividers */ + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5); + + /*##-2- LTDC Clock Configuration ###########################################*/ + /* LCD clock configuration */ + /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 MHz */ + /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 MHz */ + /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/4 = 48 MHz */ + /* LTDC clock frequency = PLLLCDCLK / RCC_PLLSAIDIVR_8 = 48/8 = 6 MHz */ + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; + PeriphClkInitStruct.PLLSAI.PLLSAIN = 192; + PeriphClkInitStruct.PLLSAI.PLLSAIR = 4; + PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_8; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); +} + + +void hal_setup(void) +{ + HAL_Init(); + + /* Configure the system clock to 180 MHz */ + SystemClock_Config(); + + /* Start up indication */ + BSP_LED_Init(LED3); + for (uint8_t i = 0; i < 8; i++) { BSP_LED_Toggle(LED3); HAL_Delay(50); } + + tft_init(); + touchpad_init(); +} + + +void SysTick_Handler(void) +{ + HAL_IncTick(); + HAL_SYSTICK_IRQHandler(); + + lv_tick_inc(1); + +#ifdef USE_RTOS_SYSTICK + osSystickHandler(); +#endif +} + + +void hal_loop(void) +{ + while(1) { + HAL_Delay(5); + lv_task_handler(); + } +} diff --git a/hal/stm32f429_disco/app_hal.h b/hal/stm32f429_disco/app_hal.h new file mode 100644 index 00000000..58a5b9df --- /dev/null +++ b/hal/stm32f429_disco/app_hal.h @@ -0,0 +1,17 @@ +#ifndef DRIVER_H +#define DRIVER_H + +#ifdef __cplusplus +extern "C" { +#endif + + +void hal_setup(void); +void hal_loop(void); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*DRIVER_H*/ diff --git a/hal/stm32f429_disco/tft.c b/hal/stm32f429_disco/tft.c new file mode 100644 index 00000000..d6a463c2 --- /dev/null +++ b/hal/stm32f429_disco/tft.c @@ -0,0 +1,236 @@ +/** + * @file disp.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include + +#include "tft.h" +#include "stm32f4xx.h" +#include "stm32f429i_discovery_lcd.h" +#include "ili9341.h" + +/********************* + * DEFINES + *********************/ + +#define SDRAM_BANK_ADDR ((uint32_t)0xD0000000) + +#define DMA_STREAM DMA2_Stream0 +#define DMA_CHANNEL DMA_CHANNEL_0 +#define DMA_STREAM_IRQ DMA2_Stream0_IRQn +#define DMA_STREAM_IRQHANDLER DMA2_Stream0_IRQHandler + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static void tft_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p); + +/********************** + * STATIC VARIABLES + **********************/ +extern LTDC_HandleTypeDef LtdcHandler; + +#if TFT_USE_GPU != 0 +static DMA2D_HandleTypeDef Dma2dHandle; +#endif + +#if TFT_EXT_FB != 0 +static __IO uint16_t *my_fb = (__IO uint16_t *)(SDRAM_BANK_ADDR); +#else +static uint16_t my_fb[TFT_HOR_RES * TFT_VER_RES]; +#endif + +/*DMA to flush to frame buffer*/ +static void DMA_Config(void); +static void DMA_TransferComplete(DMA_HandleTypeDef *han); +static void DMA_TransferError(DMA_HandleTypeDef *han); + +DMA_HandleTypeDef DmaHandle; +static lv_disp_drv_t disp_drv; +static int32_t x1_flush; +static int32_t y1_flush; +static int32_t x2_flush; +static int32_t y2_fill; +static int32_t y_fill_act; +static const lv_color_t *buf_to_flush; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +/** + * Initialize your display here + */ +void tft_init(void) +{ + static lv_color_t disp_buf1[TFT_HOR_RES * 40]; + static lv_disp_buf_t buf; + lv_disp_buf_init(&buf, disp_buf1, NULL, TFT_HOR_RES * 40); + + lv_disp_drv_init(&disp_drv); + + BSP_LCD_Init(); + BSP_LCD_LayerDefaultInit(0, (uint32_t)my_fb); + HAL_LTDC_SetPixelFormat(&LtdcHandler, LTDC_PIXEL_FORMAT_RGB565, 0); + DMA_Config(); + disp_drv.buffer = &buf; + disp_drv.flush_cb = tft_flush; + disp_drv.hor_res = TFT_HOR_RES; + disp_drv.ver_res = TFT_VER_RES; +#if TFT_USE_GPU != 0 + DMA2D_Config(); + disp_drv.gpu_blend_cb = gpu_mem_blend; + disp_drv.gpu_fill_cb = gpu_mem_fill; +#endif + lv_disp_drv_register(&disp_drv); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Flush a color buffer + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_p pointer to an array of colors + */ +static void tft_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) +{ + /*Return if the area is out the screen*/ + if (area->x2 < 0) + return; + if (area->y2 < 0) + return; + if (area->x1 > TFT_HOR_RES - 1) + return; + if (area->y1 > TFT_VER_RES - 1) + return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = area->x1 < 0 ? 0 : area->x1; + int32_t act_y1 = area->y1 < 0 ? 0 : area->y1; + int32_t act_x2 = area->x2 > TFT_HOR_RES - 1 ? TFT_HOR_RES - 1 : area->x2; + int32_t act_y2 = area->y2 > TFT_VER_RES - 1 ? TFT_VER_RES - 1 : area->y2; + + x1_flush = act_x1; + y1_flush = act_y1; + x2_flush = act_x2; + y2_fill = act_y2; + y_fill_act = act_y1; + buf_to_flush = color_p; + + /*##-7- Start the DMA transfer using the interrupt mode #*/ + /* Configure the source, destination and buffer size DMA fields and Start DMA Stream transfer */ + /* Enable All the DMA interrupts */ + HAL_StatusTypeDef err; + err = HAL_DMA_Start_IT(&DmaHandle, (uint32_t)buf_to_flush, (uint32_t)&my_fb[y_fill_act * TFT_HOR_RES + x1_flush], + (x2_flush - x1_flush + 1)); + if (err != HAL_OK) + { + while (1) + ; /*Halt on error*/ + } +} + +static void DMA_Config(void) +{ + /*## -1- Enable DMA2 clock #################################################*/ + __HAL_RCC_DMA2_CLK_ENABLE(); + + /*##-2- Select the DMA functional Parameters ###############################*/ + DmaHandle.Init.Channel = DMA_CHANNEL; /* DMA_CHANNEL_0 */ + DmaHandle.Init.Direction = DMA_MEMORY_TO_MEMORY; /* M2M transfer mode */ + DmaHandle.Init.PeriphInc = DMA_PINC_ENABLE; /* Peripheral increment mode Enable */ + DmaHandle.Init.MemInc = DMA_MINC_ENABLE; /* Memory increment mode Enable */ + DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* Peripheral data alignment : 16bit */ + DmaHandle.Init.MemDataAlignment = DMA_PDATAALIGN_HALFWORD; /* memory data alignment : 16bit */ + DmaHandle.Init.Mode = DMA_NORMAL; /* Normal DMA mode */ + DmaHandle.Init.Priority = DMA_PRIORITY_HIGH; /* priority level : high */ + DmaHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; /* FIFO mode enabled */ + DmaHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; /* FIFO threshold: 1/4 full */ + DmaHandle.Init.MemBurst = DMA_MBURST_SINGLE; /* Memory burst */ + DmaHandle.Init.PeriphBurst = DMA_PBURST_SINGLE; /* Peripheral burst */ + + /*##-3- Select the DMA instance to be used for the transfer : DMA2_Stream0 #*/ + DmaHandle.Instance = DMA_STREAM; + + /*##-4- Initialize the DMA stream ##########################################*/ + if (HAL_DMA_Init(&DmaHandle) != HAL_OK) + { + while (1) + ; + } + + /*##-5- Select Callbacks functions called after Transfer complete and Transfer error */ + HAL_DMA_RegisterCallback(&DmaHandle, HAL_DMA_XFER_CPLT_CB_ID, DMA_TransferComplete); + HAL_DMA_RegisterCallback(&DmaHandle, HAL_DMA_XFER_ERROR_CB_ID, DMA_TransferError); + + /*##-6- Configure NVIC for DMA transfer complete/error interrupts ##########*/ + HAL_NVIC_SetPriority(DMA_STREAM_IRQ, 0, 0); + HAL_NVIC_EnableIRQ(DMA_STREAM_IRQ); +} + +/** + * @brief DMA conversion complete callback + * @note This function is executed when the transfer complete interrupt + * is generated + * @retval None + */ +static void DMA_TransferComplete(DMA_HandleTypeDef *han) +{ + y_fill_act++; + + if (y_fill_act > y2_fill) + { + lv_disp_flush_ready(&disp_drv); + } + else + { + buf_to_flush += x2_flush - x1_flush + 1; + /*##-7- Start the DMA transfer using the interrupt mode ####################*/ + /* Configure the source, destination and buffer size DMA fields and Start DMA Stream transfer */ + /* Enable All the DMA interrupts */ + if (HAL_DMA_Start_IT(han, (uint32_t)buf_to_flush, (uint32_t)&my_fb[y_fill_act * TFT_HOR_RES + x1_flush], + (x2_flush - x1_flush + 1)) != HAL_OK) + { + while (1) + ; /*Halt on error*/ + } + } +} + +/** + * @brief DMA conversion error callback + * @note This function is executed when the transfer error interrupt + * is generated during DMA transfer + * @retval None + */ +static void DMA_TransferError(DMA_HandleTypeDef *han) +{ +} + +/** + * @brief This function handles DMA Stream interrupt request. + * @param None + * @retval None + */ +void DMA_STREAM_IRQHANDLER(void) +{ + /* Check the interrupt and clear flag */ + HAL_DMA_IRQHandler(&DmaHandle); +} \ No newline at end of file diff --git a/hal/stm32f429_disco/tft.h b/hal/stm32f429_disco/tft.h new file mode 100644 index 00000000..e9bbdfbb --- /dev/null +++ b/hal/stm32f429_disco/tft.h @@ -0,0 +1,37 @@ +/** + * @file disp.h + * + */ + +#ifndef DISP_H +#define DISP_H + +/********************* + * INCLUDES + *********************/ +#include +#include "lvgl.h" + +/********************* + * DEFINES + *********************/ +#define TFT_HOR_RES 240 +#define TFT_VER_RES 320 + +#define TFT_EXT_FB 1 /*Frame buffer is located into an external SDRAM*/ +#define TFT_USE_GPU 0 /*Enable hardware accelerator*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void tft_init(void); + +/********************** + * MACROS + **********************/ + +#endif diff --git a/hal/stm32f429_disco/touchpad.c b/hal/stm32f429_disco/touchpad.c new file mode 100644 index 00000000..cba8bd77 --- /dev/null +++ b/hal/stm32f429_disco/touchpad.c @@ -0,0 +1,144 @@ +/** + * @file indev.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "tft.h" +#include "lvgl.h" + +#include "stm32f4xx.h" +#include "stm32f429i_discovery.h" +#include "stmpe811.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static bool touchpad_read(lv_indev_drv_t * drv, lv_indev_data_t *data); +static bool touchpad_get_xy(int16_t *x, int16_t *y); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize your input devices here + */ +void touchpad_init(void) +{ + stmpe811_Init(TS_I2C_ADDRESS); + stmpe811_TS_Start(TS_I2C_ADDRESS); + + lv_indev_drv_t indev_drv; + lv_indev_drv_init(&indev_drv); + indev_drv.read_cb = touchpad_read; + indev_drv.type = LV_INDEV_TYPE_POINTER; + lv_indev_drv_register(&indev_drv); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Read an input device + * @param indev_id id of the input device to read + * @param x put the x coordinate here + * @param y put the y coordinate here + * @return true: the device is pressed, false: released + */ +static bool touchpad_read(lv_indev_drv_t * drv, lv_indev_data_t *data) +{ + static int16_t last_x = 0; + static int16_t last_y = 0; + + bool detected; + int16_t x; + int16_t y; + detected = touchpad_get_xy(&x, &y); + if(detected) { + data->point.x = x; + data->point.y = y; + last_x = data->point.x; + last_y = data->point.y; + + data->state = LV_INDEV_STATE_PR; + } else { + data->point.x = last_x; + data->point.y = last_y; + data->state = LV_INDEV_STATE_REL; + } + + return false; +} + + +static bool touchpad_get_xy(int16_t *x, int16_t *y) +{ + static int32_t _x = 0, _y = 0; + int16_t xDiff, yDiff, xr, yr, x_raw, y_raw;; + + bool detected; + detected = stmpe811_TS_DetectTouch(TS_I2C_ADDRESS); + + if(!detected) return false; + + + stmpe811_TS_GetXY(TS_I2C_ADDRESS, &x_raw, &y_raw); + + /* Y value first correction */ + y_raw -= 360; + + /* Y value second correction */ + yr = y_raw / 11; + + /* Return y_raw position value */ + if(yr <= 0) yr = 0; + else if (yr > TFT_VER_RES) yr = TFT_VER_RES - 1; + + y_raw = yr; + + /* X value first correction */ + if(x_raw <= 3000) x_raw = 3870 - x_raw; + else x_raw = 3800 - x_raw; + + /* X value second correction */ + xr = x_raw / 15; + + /* Return X position value */ + if(xr <= 0) xr = 0; + else if (xr > TFT_HOR_RES) xr = TFT_HOR_RES - 1; + + x_raw = xr; + xDiff = x_raw > _x? (x_raw - _x): (_x - x_raw); + yDiff = y_raw > _y? (y_raw - _y): (_y - y_raw); + + if (xDiff + yDiff > 5) { + _x = x_raw; + _y = y_raw; + } + + /* Update the X and Y position */ + *x = _x; + *y = _y; + + return true; +} diff --git a/hal/stm32f429_disco/touchpad.h b/hal/stm32f429_disco/touchpad.h new file mode 100644 index 00000000..bfd61c2d --- /dev/null +++ b/hal/stm32f429_disco/touchpad.h @@ -0,0 +1,32 @@ +/** + * @file indev.h + * + */ + +#ifndef INDEV_H +#define INDEV_H + +/********************* + * INCLUDES + *********************/ +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void touchpad_init(void); + +/********************** + * MACROS + **********************/ + +#endif diff --git a/include/README b/include/README index 194dcd43..794e54d7 100644 --- a/include/README +++ b/include/README @@ -1,39 +1,4 @@ This directory is intended for project header files. -A header file is a file containing C declarations and macro definitions -to be shared between several project source files. You request the use of a -header file in your project source file (C, C++, etc) located in `src` folder -by including it, with the C preprocessing directive `#include'. - -```src/main.c - -#include "header.h" - -int main (void) -{ - ... -} -``` - -Including a header file produces the same results as copying the header file -into each source file that needs it. Such copying would be time-consuming -and error-prone. With a header file, the related declarations appear -in only one place. If they need to be changed, they can be changed in one -place, and programs that include the header file will automatically use the -new version when next recompiled. The header file eliminates the labor of -finding and changing all the copies as well as the risk that a failure to -find one copy will result in inconsistencies within a program. - -In C, the usual convention is to give header files names that end with `.h'. -It is most portable to use only letters, digits, dashes, and underscores in -header file names, and at most one dot. - -Read more about using header files in official GCC documentation: - -* Include Syntax -* Include Operation -* Once-Only Headers -* Computed Includes - -https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html +The header files in this folder configure the different components of HASP, LVGL and paho. \ No newline at end of file diff --git a/include/VersionInfo.h b/include/VersionInfo.h new file mode 100644 index 00000000..5b91bf3a --- /dev/null +++ b/include/VersionInfo.h @@ -0,0 +1,7 @@ +#ifndef VERSIONINFO_H +#define VERSIONINFO_H + +#define BUILD_TIMESTAMP "@BUILD_TIMESTAMP@" +#define CLIENT_VERSION "@CLIENT_VERSION@" + +#endif /* VERSIONINFO_H */ diff --git a/include/hasp_conf.h b/include/hasp_conf.h index 2ac6c842..52d2e081 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -1,89 +1,92 @@ #ifndef HASP_CONF_H #define HASP_CONF_H +// language specific defines +#include "lang/lang.h" + #define HASP_USE_APP 1 #ifndef HASP_USE_DEBUG - #define HASP_USE_DEBUG 1 +#define HASP_USE_DEBUG 1 #endif /* Network Services */ #ifndef HASP_USE_ETHERNET - #define HASP_USE_ETHERNET 0 +#define HASP_USE_ETHERNET 0 #endif #ifndef HASP_USE_WIFI - #define HASP_USE_WIFI (ARDUINO_ARCH_ESP32 > 0 || ARDUINO_ARCH_ESP8266 > 0 || HASP_USE_WIFI > 0) +#define HASP_USE_WIFI (ARDUINO_ARCH_ESP32 > 0 || ARDUINO_ARCH_ESP8266 > 0 || HASP_USE_WIFI > 0) #endif #define HASP_HAS_NETWORK \ (ARDUINO_ARCH_ESP32 > 0 || ARDUINO_ARCH_ESP8266 > 0 || HASP_USE_ETHERNET > 0 || HASP_USE_WIFI > 0) #ifndef HASP_USE_OTA - #define HASP_USE_OTA (HASP_HAS_NETWORK) +#define HASP_USE_OTA (HASP_HAS_NETWORK) #endif #ifndef HASP_USE_MQTT - #define HASP_USE_MQTT (HASP_HAS_NETWORK) +#define HASP_USE_MQTT (HASP_HAS_NETWORK) #endif #ifndef HASP_USE_HTTP - #define HASP_USE_HTTP (HASP_HAS_NETWORK) +#define HASP_USE_HTTP (HASP_HAS_NETWORK) #endif #ifndef HASP_USE_MDNS - #define HASP_USE_MDNS (HASP_HAS_NETWORK) +#define HASP_USE_MDNS (HASP_HAS_NETWORK) #endif #ifndef HASP_USE_SYSLOG - #define HASP_USE_SYSLOG (HASP_HAS_NETWORK) +#define HASP_USE_SYSLOG (HASP_HAS_NETWORK) #endif #ifndef HASP_USE_TELNET - #define HASP_USE_TELNET 0 +#define HASP_USE_TELNET 0 #endif /* Filesystem */ #define HASP_HAS_FILESYSTEM (ARDUINO_ARCH_ESP32 > 0 || ARDUINO_ARCH_ESP8266 > 0) #ifndef HASP_USE_SPIFFS - #ifndef HASP_USE_LITTLEFS - #define HASP_USE_SPIFFS (HASP_HAS_FILESYSTEM) - #else - #define HASP_USE_SPIFFS (HASP_USE_LITTLEFS <= 0) - #endif +#ifndef HASP_USE_LITTLEFS +#define HASP_USE_SPIFFS (HASP_HAS_FILESYSTEM) +#else +#define HASP_USE_SPIFFS (HASP_USE_LITTLEFS <= 0) +#endif #endif #ifndef HASP_USE_LITTLEFS - #define HASP_USE_LITTLEFS (HASP_USE_SPIFFS <= 0) +#define HASP_USE_LITTLEFS (HASP_USE_SPIFFS <= 0) #endif #ifndef HASP_USE_EEPROM - #define HASP_USE_EEPROM 1 +#define HASP_USE_EEPROM 1 #endif #ifndef HASP_USE_SDCARD - #define HASP_USE_SDCARD 0 +#define HASP_USE_SDCARD 0 #endif #ifndef HASP_USE_GPIO - #define HASP_USE_GPIO 1 +#define HASP_USE_GPIO 1 #endif #ifndef HASP_USE_QRCODE - #define HASP_USE_QRCODE 1 +#define HASP_USE_QRCODE 1 #endif #ifndef HASP_USE_PNGDECODE - #define HASP_USE_PNGDECODE 0 +#define HASP_USE_PNGDECODE 0 #endif #ifndef HASP_NUM_GPIO_CONFIG - #define HASP_NUM_GPIO_CONFIG 8 +#define HASP_NUM_GPIO_CONFIG 8 #endif #ifndef HASP_NUM_INPUTS - #define HASP_NUM_INPUTS 4 // Number of ACE Buttons +#define HASP_NUM_INPUTS 4 // Number of ACE Buttons #endif // #ifndef HASP_NUM_OUTPUTS @@ -91,128 +94,191 @@ // #endif #ifndef HASP_NUM_PAGES - #if defined(ARDUINO_ARCH_ESP8266) - #define HASP_NUM_PAGES 4 - #else - #define HASP_NUM_PAGES 12 - #endif +#if defined(ARDUINO_ARCH_ESP8266) +#define HASP_NUM_PAGES 4 +#else +#define HASP_NUM_PAGES 12 +#endif #endif #define HASP_OBJECT_NOTATION "p%ub%u" /* Includes */ -#include +#ifdef WINDOWS +#include "winsock2.h" +#include "Windows.h" +#elif defined(POSIX) +#else +#include "Arduino.h" +#endif #if HASP_USE_SPIFFS > 0 - // #if defined(ARDUINO_ARCH_ESP32) - // #include "SPIFFS.h" - // #endif - // #include // Include the SPIFFS library - #include "hasp_filesystem.h" +// #if defined(ARDUINO_ARCH_ESP32) +// #include "SPIFFS.h" +// #endif +// #include // Include the SPIFFS library +#include "hasp_filesystem.h" #endif #if HASP_USE_LITTLEFS > 0 - // #if defined(ARDUINO_ARCH_ESP32) - // #include "LITTLEFS.h" - // #elif defined(ARDUINO_ARCH_ESP8266) - // #include // Include the FS library - // #include - // #endif - #include "hasp_filesystem.h" +// #if defined(ARDUINO_ARCH_ESP32) +// #include "LITTLEFS.h" +// #elif defined(ARDUINO_ARCH_ESP8266) +// #include // Include the FS library +// #include +// #endif +#include "hasp_filesystem.h" #endif #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 - #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) - #include "lv_zifont.h" - #endif +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) +#include "lv_zifont.h" +#endif #endif #if HASP_USE_EEPROM > 0 - #include "hasp_eeprom.h" +#include "hasp_eeprom.h" #endif #if HASP_USE_WIFI > 0 - #include "net/hasp_wifi.h" +#include "sys/net/hasp_wifi.h" - #if defined(STM32F4xx) - #include "WiFiSpi.h" +#if defined(STM32F4xx) +#include "WiFiSpi.h" static WiFiSpiClass WiFi; - #endif +#endif #endif // HASP_USE_WIFI #if HASP_USE_ETHERNET > 0 - #if defined(ARDUINO_ARCH_ESP32) - #include +#if defined(ARDUINO_ARCH_ESP32) +#include - #define ETH_ADDR 0 - #define ETH_POWER_PIN -1 - #define ETH_MDC_PIN 23 - #define ETH_MDIO_PIN 18 - #define NRST 5 - #define ETH_TYPE ETH_PHY_LAN8720 - #define ETH_CLKMODE ETH_CLOCK_GPIO17_OUT +#define ETH_ADDR 0 +#define ETH_POWER_PIN -1 +#define ETH_MDC_PIN 23 +#define ETH_MDIO_PIN 18 +#define NRST 5 +#define ETH_TYPE ETH_PHY_LAN8720 +#define ETH_CLKMODE ETH_CLOCK_GPIO17_OUT - #include "net/hasp_ethernet_esp32.h" - #warning Using ESP32 Ethernet LAN8720 +#include "sys/net/hasp_ethernet_esp32.h" +#warning Using ESP32 Ethernet LAN8720 - #else - #if USE_BUILTIN_ETHERNET > 0 - #include - #include - #warning Use built-in STM32 Ethernet - #elif USE_UIP_ETHERNET - #include - #include - #warning Use ENC28J60 Ethernet shield - #else - #include "Ethernet.h" - #warning Use W5x00 Ethernet shield - #endif - #include "net/hasp_ethernet_stm32.h" - #endif +#else +#if USE_BUILTIN_ETHERNET > 0 +#include +#include +#warning Use built-in STM32 Ethernet +#elif USE_UIP_ETHERNET +#include +#include +#warning Use ENC28J60 Ethernet shield +#else +#include "Ethernet.h" +#warning Use W5x00 Ethernet shield +#endif +#include "sys/net/hasp_ethernet_stm32.h" +#endif #endif #if HASP_USE_MQTT > 0 - #include "svc/hasp_mqtt.h" +#include "mqtt/hasp_mqtt.h" + +#if defined(WINDOWS) || defined(POSIX) +#define USE_PAHO +#else +#define USE_PUBSUBCLIENT +#endif + #endif #if HASP_USE_GPIO > 0 - #include "hasp_gpio.h" +#include "sys/gpio/hasp_gpio.h" #endif #if HASP_USE_HTTP > 0 - #include "svc/hasp_http.h" +#include "sys/svc/hasp_http.h" #endif #if HASP_USE_TELNET > 0 - #include "svc/hasp_telnet.h" +#include "sys/svc/hasp_telnet.h" #endif #if HASP_USE_MDNS > 0 - #include "svc/hasp_mdns.h" +#include "sys/svc/hasp_mdns.h" #endif #if HASP_USE_OTA > 0 - #include "svc/hasp_ota.h" - #ifndef HASP_OTA_PORT - #if defined(ARDUINO_ARCH_ESP32) - #define HASP_OTA_PORT 3232 - #elif defined(ARDUINO_ARCH_ESP8266) - #define HASP_OTA_PORT 8266 - #endif - #endif +#include "sys/svc/hasp_ota.h" +#ifndef HASP_OTA_PORT +#if defined(ARDUINO_ARCH_ESP32) +#define HASP_OTA_PORT 3232 +#elif defined(ARDUINO_ARCH_ESP8266) +#define HASP_OTA_PORT 8266 +#endif +#endif #endif -#if HASP_USE_TASMOTA_SLAVE > 0 - #include "svc/hasp_slave.h" +#if HASP_USE_TASMOTA_CLIENT > 0 +#include "sys/svc/hasp_slave.h" #endif #ifndef FPSTR - #define FPSTR(pstr_pointer) (reinterpret_cast(pstr_pointer)) +#define FPSTR(pstr_pointer) (reinterpret_cast(pstr_pointer)) #endif #ifndef PGM_P - #define PGM_P const char * +#define PGM_P const char* #endif -#endif // HASP_CONF_H \ No newline at end of file +#if defined(WINDOWS) || defined(POSIX) +#ifndef __FlashStringHelper +#define __FlashStringHelper char +#endif + +#ifndef F +#define F(x) (x) +#endif + +#ifndef PSTR +#define PSTR(x) x +#endif + +#ifndef PROGMEM +#define PROGMEM +#endif +#endif + +#if defined(WINDOWS) +#include +#define delay Sleep +#endif +#if defined(POSIX) +#define delay SDL_Delay +#endif +#if defined(WINDOWS) || defined(POSIX) +#include +#include +#include +#include + +#define snprintf_P snprintf +#define memcpy_P memcpy +#define strcasecmp_P strcasecmp +#define strcmp_P strcmp +#define strstr_P strstr +#define halRestartMcu() +#define millis SDL_GetTicks + +#define DEC 10 +#define HEX 16 +#define BIN 2 + +#define guiGetDim() 255 +#define guiSetDim(x) +#define guiGetBacklight() 1 +#define guiSetBacklight(x) +//#define guiCalibrate() +#endif + +#endif // HASP_CONF_H diff --git a/include/hasp_macro.h b/include/hasp_macro.h index 0e7c636a..d3b6bdcc 100644 --- a/include/hasp_macro.h +++ b/include/hasp_macro.h @@ -1,65 +1,70 @@ #ifndef HASP_MACRO_H #define HASP_MACRO_H -#if HASP_LOG_LEVEL > LOG_LEVEL_FATAL - #define LOG_FATAL(...) \ - Log.fatal(__VA_ARGS__); \ - while(true) { \ - } +#if defined(WINDOWS) || defined(POSIX) +#define LOG_OUTPUT(x, ...) printf(__VA_ARGS__) #else - #define LOG_FATAL(...) \ - do { \ - } while(0) +#define LOG_OUTPUT(...) Log.output(...) + +#if HASP_LOG_LEVEL > LOG_LEVEL_FATAL +#define LOG_FATAL(...) \ + Log.fatal(__VA_ARGS__); \ + while(true) { \ + } +#else +#define LOG_FATAL(...) \ + do { \ + } while(0) #endif #if HASP_LOG_LEVEL > LOG_LEVEL_ALERT - #define LOG_ALERT(...) Log.alert(__VA_ARGS__) +#define LOG_ALERT(...) Log.alert(__VA_ARGS__) #else - #define LOG_ALERT(...) +#define LOG_ALERT(...) #endif #if HASP_LOG_LEVEL > LOG_LEVEL_CRITICAL - #define LOG_CRITICAL(...) Log.critical(__VA_ARGS__) +#define LOG_CRITICAL(...) Log.critical(__VA_ARGS__) #else - #define LOG_CRITICAL(...) +#define LOG_CRITICAL(...) #endif #if HASP_LOG_LEVEL > LOG_LEVEL_ERROR - #define LOG_ERROR(...) Log.error(__VA_ARGS__) +#define LOG_ERROR(...) Log.error(__VA_ARGS__) #else - #define LOG_ERROR(...) +#define LOG_ERROR(...) #endif #if HASP_LOG_LEVEL > LOG_LEVEL_WARNING - #define LOG_WARNING(...) Log.warning(__VA_ARGS__) +#define LOG_WARNING(...) Log.warning(__VA_ARGS__) #else - #define LOG_WARNING(...) +#define LOG_WARNING(...) #endif #if HASP_LOG_LEVEL > LOG_LEVEL_INFO - #define LOG_INFO(...) Log.notice(__VA_ARGS__) +#define LOG_INFO(...) Log.notice(__VA_ARGS__) #else - #define LOG_INFO(...) +#define LOG_INFO(...) #endif #if HASP_LOG_LEVEL > LOG_LEVEL_TRACE - #define LOG_TRACE(...) Log.trace(__VA_ARGS__) +#define LOG_TRACE(...) Log.trace(__VA_ARGS__) #else - #define LOG_TRACE(...) +#define LOG_TRACE(...) #endif #if HASP_LOG_LEVEL > LOG_LEVEL_VERBOSE - #define LOG_VERBOSE(...) Log.verbose(__VA_ARGS__) +#define LOG_VERBOSE(...) Log.verbose(__VA_ARGS__) #else - #define LOG_VERBOSE(...) +#define LOG_VERBOSE(...) #endif #if HASP_LOG_LEVEL > LOG_LEVEL_DEBUG - #define LOG_DEBUG(...) Log.debug(__VA_ARGS__) +#define LOG_DEBUG(...) Log.debug(__VA_ARGS__) #else - #define LOG_DEBUG(...) +#define LOG_DEBUG(...) #endif -#define LOG_OUTPUT(...) Log.output(...) +#endif -#endif \ No newline at end of file +#endif // HASP_MACRO_H diff --git a/include/lv_conf_v7.h b/include/lv_conf_v7.h index abb7c91e..506d5e03 100644 --- a/include/lv_conf_v7.h +++ b/include/lv_conf_v7.h @@ -5,9 +5,9 @@ #if 1 /*Set it to "1" to enable content*/ - #ifndef LV_CONF_H - #define LV_CONF_H - /* clang-format off */ +#ifndef LV_CONF_H +#define LV_CONF_H +/* clang-format off */ #include @@ -26,6 +26,8 @@ /* Maximal horizontal and vertical resolution to support by the library.*/ #define LV_HOR_RES_MAX (TFT_WIDTH) #define LV_VER_RES_MAX (TFT_HEIGHT) +#define LV_HOR_RES (TFT_WIDTH) +#define LV_VER_RES (TFT_HEIGHT) /* Color depth: * - 1: 1 byte per pixel @@ -181,14 +183,15 @@ typedef void* lv_group_user_data_t; typedef void* lv_fs_drv_user_data_t; /*File system interface*/ -#define LV_USE_FS_IF 1 +#define LV_USE_FS_IF 0 #if LV_USE_FS_IF # define LV_FS_IF_FATFS '\0' -#if defined(ARDUINO_ARCH_ESP32) // || defined(ARDUINO_ARCH_ESP8266) -# define LV_FS_IF_PC 'S' +#if defined(STM32F4xx) // || defined(ARDUINO_ARCH_ESP8266) +# define LV_FS_IF_PC '\0' # define LV_FS_IF_SPIFFS '\0' // internal esp Flash #else # define LV_FS_IF_PC '\0' +# define LV_FS_IF_POSIX '\0' # define LV_FS_IF_SPIFFS '\0' // no internal esp Flash #endif #endif /*LV_USE_FS_IF*/ @@ -251,12 +254,18 @@ typedef void* lv_img_decoder_user_data_t; /* 1: use a custom tick source. * It removes the need to manually update the tick with `lv_tick_inc`) */ +#ifdef ARDUINO + #define LV_TICK_CUSTOM 1 #if LV_TICK_CUSTOM == 1 #define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the sys time function*/ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current systime in ms*/ #endif /*LV_TICK_CUSTOM*/ +#else +#define LV_TICK_CUSTOM 0 +#endif + typedef void* lv_disp_drv_user_data_t; /*Type of user data in the display driver*/ typedef void* lv_indev_drv_user_data_t; /*Type of user data in the input device driver*/ @@ -431,7 +440,7 @@ typedef void* lv_font_user_data_t; /*Always enable at least on theme*/ #define LV_USE_THEME_MATERIAL 1 /*A fast and impressive theme*/ -#define LV_THEME_DEFAULT_INIT lv_theme_hasp_init // We init the theme ourselves +#define LV_THEME_DEFAULT_INIT lv_theme_material_init // lv_theme_hasp_init // We init the theme ourselves #define LV_THEME_DEFAULT_COLOR_PRIMARY LV_COLOR_RED #define LV_THEME_DEFAULT_COLOR_SECONDARY LV_COLOR_BLUE #define LV_THEME_DEFAULT_FLAG 0 //LV_THEME_MATERIAL_FLAG_NONE @@ -509,9 +518,11 @@ typedef void* lv_font_user_data_t; /*Declare the type of the user data of object (can be e.g. `void *`, `int`, `struct`)*/ typedef struct { + uint8_t id:8; uint8_t objid:8; - uint8_t groupid:8; - uint8_t id; + uint8_t transitionid:4; + uint8_t actionid:4; + uint8_t groupid:4; } lv_obj_user_data_t; /*1: enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/ @@ -637,7 +648,7 @@ typedef struct { #endif /*Preload (dependencies: lv_arc, lv_anim)*/ -#define LV_USE_SPINNER 0 +#define LV_USE_SPINNER 1 #if LV_USE_SPINNER != 0 # define LV_SPINNER_DEF_ARC_LENGTH 60 /*[deg]*/ # define LV_SPINNER_DEF_SPIN_TIME 1000 /*[ms]*/ diff --git a/include/lv_conf_v8.h b/include/lv_conf_v8.h index 0534d9ff..afaa51ea 100644 --- a/include/lv_conf_v8.h +++ b/include/lv_conf_v8.h @@ -582,9 +582,11 @@ typedef void * lv_font_user_data_t; *==================*/ typedef struct { + uint8_t id:8; uint8_t objid:8; - uint8_t groupid:8; - uint8_t id; + uint8_t transitionid:4; + uint8_t actionid:4; + uint8_t groupid:4; } lv_obj_user_data_t; #if LV_USE_USER_DATA diff --git a/include/lv_drv_conf.h b/include/lv_drv_conf.h index ea6a588c..cb5bd603 100644 --- a/include/lv_drv_conf.h +++ b/include/lv_drv_conf.h @@ -1,6 +1,10 @@ /** * @file lv_drv_conf.h - * + * Configuration file for v7.9.1 + */ + +/* + * COPY THIS FILE AS lv_drv_conf.h */ #if 1 /*Set it to "1" to enable the content*/ @@ -13,9 +17,15 @@ /********************* * DELAY INTERFACE *********************/ +#ifdef ARDUINO #define LV_DRV_DELAY_INCLUDE /*Dummy include by default*/ #define LV_DRV_DELAY_US(us) delayMicroseconds(ud) /*Delay the given number of microseconds*/ #define LV_DRV_DELAY_MS(ms) delay(ms) /*Delay the given number of milliseconds*/ +#else +#define LV_DRV_DELAY_INCLUDE /*Dummy include by default*/ +#define LV_DRV_DELAY_US(us) /*delay_us(us)*/ /*Delay the given number of microseconds*/ +#define LV_DRV_DELAY_MS(ms) /*delay_ms(ms)*/ /*Delay the given number of milliseconds*/ +#endif /********************* * DISPLAY INTERFACE @@ -93,7 +103,9 @@ #define MONITOR_VER_RES LV_VER_RES /* Scale window by this factor (useful when simulating small screens) */ +#ifndef MONITOR_ZOOM #define MONITOR_ZOOM 1 +#endif /* Used to test true double buffering with only address changing. * Set LV_VDB_SIZE = (LV_HOR_RES * LV_VER_RES) and LV_VDB_DOUBLE = 1 and LV_COLOR_DEPTH = 32" */ @@ -102,9 +114,6 @@ /*Eclipse: Visual Studio: */ #define MONITOR_SDL_INCLUDE_PATH -/*Different rendering might be used if running in a Virtual machine*/ -#define MONITOR_VIRTUAL_MACHINE 0 - /*Open two windows to test multi display support*/ #define MONITOR_DUAL 0 #endif @@ -116,12 +125,18 @@ #define USE_WINDOWS 0 #endif -#define USE_WINDOWS 0 #if USE_WINDOWS #define WINDOW_HOR_RES 480 #define WINDOW_VER_RES 320 #endif +/*---------------------------------------- + * GTK drivers (monitor, mouse, keyboard + *---------------------------------------*/ +#ifndef USE_GTK +#define USE_GTK 0 +#endif + /*---------------- * SSD1963 *--------------*/ @@ -181,6 +196,17 @@ /*No settings*/ #endif /*USE_ST7565*/ +/*------------------------------ + * GC9A01 (color, low res.) + *-----------------------------*/ +#ifndef USE_GC9A01 +#define USE_GC9A01 0 +#endif + +#if USE_GC9A01 +/*No settings*/ +#endif /*USE_GC9A01*/ + /*------------------------------------------ * UC1610 (4 gray 160*[104|128]) * (EA DOGXL160 160x104 tested) @@ -218,6 +244,20 @@ b) /*((uint8_t) __REV(__RBIT(b)))*/ /*Architecture / compiler dependent byte bits order reverse*/ #endif /*USE_SHARP_MIP*/ +/*------------------------------------------------- + * ILI9341 240X320 TFT LCD + *------------------------------------------------*/ +#ifndef USE_ILI9341 +#define USE_ILI9341 0 +#endif + +#if USE_ILI9341 +#define ILI9341_HOR_RES LV_HOR_RES +#define ILI9341_VER_RES LV_VER_RES +#define ILI9341_GAMMA 1 +#define ILI9341_TEARING 0 +#endif /*USE_ILI9341*/ + /*----------------------------------------- * Linux frame buffer device (/dev/fbx) *-----------------------------------------*/ @@ -240,6 +280,18 @@ #define FBDEV_PATH "/dev/fb0" #endif +/*----------------------------------------- + * DRM/KMS device (/dev/dri/cardX) + *-----------------------------------------*/ +#ifndef USE_DRM +#define USE_DRM 0 +#endif + +#if USE_DRM +#define DRM_CARD "/dev/dri/card0" +#define DRM_CONNECTOR_ID -1 /* -1 for the first connected one */ +#endif + /********************* * INPUT DEVICES *********************/ @@ -330,25 +382,25 @@ #define USE_EVDEV 0 #endif -#if USE_EVDEV -#define EVDEV_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test \ - them*/ -#define EVDEV_SWAP_AXES 0 /*Swap the x and y axes of the touchscreen*/ +#ifndef USE_BSD_EVDEV +#define USE_BSD_EVDEV 0 +#endif -#define EVDEV_SCALE 0 /* Scale input, e.g. if touchscreen resolution does not match display resolution */ -#if EVDEV_SCALE -#define EVDEV_SCALE_HOR_RES (4096) /* Horizontal resolution of touchscreen */ -#define EVDEV_SCALE_VER_RES (4096) /* Vertical resolution of touchscreen */ -#endif /*EVDEV_SCALE*/ +#if USE_EVDEV || USE_BSD_EVDEV +#define EVDEV_NAME \ + "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test \ + them*/ +#define EVDEV_SWAP_AXES 0 /*Swap the x and y axes of the touchscreen*/ #define EVDEV_CALIBRATE \ 0 /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/ + #if EVDEV_CALIBRATE -#define EVDEV_HOR_MIN 3800 /*If EVDEV_XXX_MIN > EVDEV_XXX_MAX the XXX axis is automatically inverted*/ -#define EVDEV_HOR_MAX 200 -#define EVDEV_VER_MIN 200 -#define EVDEV_VER_MAX 3800 -#endif /*EVDEV_SCALE*/ +#define EVDEV_HOR_MIN 0 /*to invert axis swap EVDEV_XXX_MIN by EVDEV_XXX_MAX*/ +#define EVDEV_HOR_MAX 4096 /*"evtest" Linux tool can help to get the correct calibraion values>*/ +#define EVDEV_VER_MIN 0 +#define EVDEV_VER_MAX 4096 +#endif /*EVDEV_CALIBRATE*/ #endif /*USE_EVDEV*/ /*------------------------------- diff --git a/src/user_config_override-template.h b/include/user_config_override-template.h similarity index 96% rename from src/user_config_override-template.h rename to include/user_config_override-template.h index 31d9b2c9..4d0d8806 100644 --- a/src/user_config_override-template.h +++ b/include/user_config_override-template.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ /*************************************************** diff --git a/lib/AXP192/AXP192.cpp b/lib/AXP192/AXP192.cpp deleted file mode 100644 index 7480a9e7..00000000 --- a/lib/AXP192/AXP192.cpp +++ /dev/null @@ -1,602 +0,0 @@ -#include "AXP192.h" - -AXP192::AXP192() -{ -} - -void AXP192::begin(void) -{ - - Wire1.begin(21, 22); - Wire1.setClock(400000); - - //AXP192 30H - Write1Byte(0x30, (Read8bit(0x30) & 0x04) | 0X02); - Serial.printf("axp: vbus limit off\n"); - - //AXP192 GPIO1:OD OUTPUT - Write1Byte(0x92, Read8bit(0x92) & 0xf8); - Serial.printf("axp: gpio1 init\n"); - - //AXP192 GPIO2:OD OUTPUT - Write1Byte(0x93, Read8bit(0x93) & 0xf8); - Serial.printf("axp: gpio2 init\n"); - - //AXP192 RTC CHG - Write1Byte(0x35, (Read8bit(0x35) & 0x1c) | 0xa2); - Serial.printf("axp: rtc battery charging enabled\n"); - - SetESPVoltage(3350); - Serial.printf("axp: esp32 power voltage was set to 3.35v\n"); - - SetLcdVoltage(2800); - Serial.printf("axp: lcd backlight voltage was set to 2.80v\n"); - - SetLDOVoltage(2, 3300); //Periph power voltage preset (LCD_logic, SD card) - Serial.printf("axp: lcd logic and sdcard voltage preset to 3.3v\n"); - - SetLDOVoltage(3, 2000); //Vibrator power voltage preset - Serial.printf("axp: vibrator voltage preset to 2v\n"); - - SetLDOEnable(2, true); - SetDCDC3(true); // LCD backlight - SetLed(true); - - SetCHGCurrent(kCHG_100mA); - //SetAxpPriphPower(1); - //Serial.printf("axp: lcd_logic and sdcard power enabled\n\n"); - - //pinMode(39, INPUT_PULLUP); - - //AXP192 GPIO4 - Write1Byte(0X95, (Read8bit(0x95) & 0x72) | 0X84); - - Write1Byte(0X36, 0X4C); - - Write1Byte(0x82,0xff); - - SetLCDRSet(0); - delay(100); - SetLCDRSet(1); - delay(100); - // I2C_WriteByteDataAt(0X15,0XFE,0XFF); - - // bus power mode_output - SetBusPowerMode(0); -} - -void AXP192::Write1Byte(uint8_t Addr, uint8_t Data) -{ - Wire1.beginTransmission(0x34); - Wire1.write(Addr); - Wire1.write(Data); - Wire1.endTransmission(); -} - -uint8_t AXP192::Read8bit(uint8_t Addr) -{ - Wire1.beginTransmission(0x34); - Wire1.write(Addr); - Wire1.endTransmission(); - Wire1.requestFrom(0x34, 1); - return Wire1.read(); -} - -uint16_t AXP192::Read12Bit(uint8_t Addr) -{ - uint16_t Data = 0; - uint8_t buf[2]; - ReadBuff(Addr, 2, buf); - Data = ((buf[0] << 4) + buf[1]); // - return Data; -} - -uint16_t AXP192::Read13Bit(uint8_t Addr) -{ - uint16_t Data = 0; - uint8_t buf[2]; - ReadBuff(Addr, 2, buf); - Data = ((buf[0] << 5) + buf[1]); // - return Data; -} - -uint16_t AXP192::Read16bit(uint8_t Addr) -{ - uint16_t ReData = 0; - Wire1.beginTransmission(0x34); - Wire1.write(Addr); - Wire1.endTransmission(); - Wire1.requestFrom(0x34, 2); - for (int i = 0; i < 2; i++) - { - ReData <<= 8; - ReData |= Wire1.read(); - } - return ReData; -} - -uint32_t AXP192::Read24bit(uint8_t Addr) -{ - uint32_t ReData = 0; - Wire1.beginTransmission(0x34); - Wire1.write(Addr); - Wire1.endTransmission(); - Wire1.requestFrom(0x34, 3); - for (int i = 0; i < 3; i++) - { - ReData <<= 8; - ReData |= Wire1.read(); - } - return ReData; -} - -uint32_t AXP192::Read32bit(uint8_t Addr) -{ - uint32_t ReData = 0; - Wire1.beginTransmission(0x34); - Wire1.write(Addr); - Wire1.endTransmission(); - Wire1.requestFrom(0x34, 2); - for (int i = 0; i < 4; i++) - { - ReData <<= 8; - ReData |= Wire1.read(); - } - return ReData; -} - -void AXP192::ReadBuff(uint8_t Addr, uint8_t Size, uint8_t *Buff) -{ - Wire1.beginTransmission(0x34); - Wire1.write(Addr); - Wire1.endTransmission(); - Wire1.requestFrom(0x34, (int)Size); - for (int i = 0; i < Size; i++) - { - *(Buff + i) = Wire1.read(); - } -} - -void AXP192::ScreenBreath(uint8_t brightness) -{ - if (brightness > 12) - { - brightness = 12; - } - uint8_t buf = Read8bit(0x28); - Write1Byte(0x28, ((buf & 0x0f) | (brightness << 4))); -} - -bool AXP192::GetBatState() -{ - if (Read8bit(0x01) | 0x20) - return true; - else - return false; -} -//---------coulombcounter_from_here--------- -//enable: void EnableCoulombcounter(void); -//disable: void DisableCOulombcounter(void); -//stop: void StopCoulombcounter(void); -//clear: void ClearCoulombcounter(void); -//get charge data: uint32_t GetCoulombchargeData(void); -//get discharge data: uint32_t GetCoulombdischargeData(void); -//get coulomb val affter calculation: float GetCoulombData(void); -//------------------------------------------ -void AXP192::EnableCoulombcounter(void) -{ - Write1Byte(0xB8, 0x80); -} - -void AXP192::DisableCoulombcounter(void) -{ - Write1Byte(0xB8, 0x00); -} - -void AXP192::StopCoulombcounter(void) -{ - Write1Byte(0xB8, 0xC0); -} - -void AXP192::ClearCoulombcounter(void) -{ - Write1Byte(0xB8, 0xA0); -} - -uint32_t AXP192::GetCoulombchargeData(void) -{ - return Read32bit(0xB0); -} - -uint32_t AXP192::GetCoulombdischargeData(void) -{ - return Read32bit(0xB4); -} - -float AXP192::GetCoulombData(void) -{ - - uint32_t coin = 0; - uint32_t coout = 0; - - coin = GetCoulombchargeData(); - coout = GetCoulombdischargeData(); - - //c = 65536 * current_LSB * (coin - coout) / 3600 / ADC rate - //Adc rate can be read from 84H ,change this variable if you change the ADC reate - float ccc = 65536 * 0.5 * (coin - coout) / 3600.0 / 25.0; - return ccc; -} - -// Cut all power, except for LDO1 (RTC) -void AXP192::PowerOff(void) -{ - Write1Byte(0x32, Read8bit(0x32) | 0b10000000); -} - -void AXP192::SetAdcState(bool state) -{ - // Enable / Disable all ADCs - Write1Byte(0x82, state ? 0xff : 0x00); -} - -void AXP192::PrepareToSleep(void) -{ - // Disable ADCs - SetAdcState(false); - - // Turn LED off - SetLed(false); - - // Turn LCD backlight off - SetDCDC3(false); -} - -void AXP192::RestoreFromLightSleep(void) -{ - // Turn LCD backlight on - SetDCDC3(true); - - // Turn LED on - SetLed(true); - - // Enable ADCs - SetAdcState(true); -} - -uint8_t AXP192::GetWarningLeve(void) -{ - Wire1.beginTransmission(0x34); - Wire1.write(0x47); - Wire1.endTransmission(); - Wire1.requestFrom(0x34, 1); - uint8_t buf = Wire1.read(); - return (buf & 0x01); -} - -// -- sleep -void AXP192::DeepSleep(uint64_t time_in_us) -{ - PrepareToSleep(); - - if (time_in_us > 0) - { - esp_sleep_enable_timer_wakeup(time_in_us); - } - else - { - esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); - } - (time_in_us == 0) ? esp_deep_sleep_start() : esp_deep_sleep(time_in_us); - - // Never reached - after deep sleep ESP32 restarts -} - -void AXP192::LightSleep(uint64_t time_in_us) -{ - PrepareToSleep(); - - if (time_in_us > 0) - { - esp_sleep_enable_timer_wakeup(time_in_us); - } - else - { - esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); - } - esp_light_sleep_start(); - - RestoreFromLightSleep(); -} - -uint8_t AXP192::GetWarningLevel(void) -{ - return Read8bit(0x47) & 0x01; -} - -float AXP192::GetBatVoltage() -{ - float ADCLSB = 1.1 / 1000.0; - uint16_t ReData = Read12Bit(0x78); - return ReData * ADCLSB; -} - -float AXP192::GetBatCurrent() -{ - float ADCLSB = 0.5; - uint16_t CurrentIn = Read13Bit(0x7A); - uint16_t CurrentOut = Read13Bit(0x7C); - return (CurrentIn - CurrentOut) * ADCLSB; -} - -float AXP192::GetVinVoltage() -{ - float ADCLSB = 1.7 / 1000.0; - uint16_t ReData = Read12Bit(0x56); - return ReData * ADCLSB; -} - -float AXP192::GetVinCurrent() -{ - float ADCLSB = 0.625; - uint16_t ReData = Read12Bit(0x58); - return ReData * ADCLSB; -} - -float AXP192::GetVBusVoltage() -{ - float ADCLSB = 1.7 / 1000.0; - uint16_t ReData = Read12Bit(0x5A); - return ReData * ADCLSB; -} - -float AXP192::GetVBusCurrent() -{ - float ADCLSB = 0.375; - uint16_t ReData = Read12Bit(0x5C); - return ReData * ADCLSB; -} - -float AXP192::GetTempInAXP192() -{ - float ADCLSB = 0.1; - const float OFFSET_DEG_C = -144.7; - uint16_t ReData = Read12Bit(0x5E); - return OFFSET_DEG_C + ReData * ADCLSB; -} - -float AXP192::GetBatPower() -{ - float VoltageLSB = 1.1; - float CurrentLCS = 0.5; - uint32_t ReData = Read24bit(0x70); - return VoltageLSB * CurrentLCS * ReData / 1000.0; -} - -float AXP192::GetBatChargeCurrent() -{ - float ADCLSB = 0.5; - uint16_t ReData = Read12Bit(0x7A); - return ReData * ADCLSB; -} -float AXP192::GetAPSVoltage() -{ - float ADCLSB = 1.4 / 1000.0; - uint16_t ReData = Read12Bit(0x7E); - return ReData * ADCLSB; -} - -float AXP192::GetBatCoulombInput() -{ - uint32_t ReData = Read32bit(0xB0); - return ReData * 65536 * 0.5 / 3600 / 25.0; -} - -float AXP192::GetBatCoulombOut() -{ - uint32_t ReData = Read32bit(0xB4); - return ReData * 65536 * 0.5 / 3600 / 25.0; -} - -void AXP192::SetCoulombClear() -{ - Write1Byte(0xB8, 0x20); -} - -void AXP192::SetLDO2(bool State) -{ - uint8_t buf = Read8bit(0x12); - if (State == true) - buf = (1 << 2) | buf; - else - buf = ~(1 << 2) & buf; - Write1Byte(0x12, buf); -} - -void AXP192::SetDCDC3(bool State) -{ - uint8_t buf = Read8bit(0x12); - if (State == true) - buf = (1 << 1) | buf; - else - buf = ~(1 << 1) & buf; - Write1Byte(0x12, buf); -} - -uint8_t AXP192::AXPInState() -{ - return Read8bit(0x00); -} -bool AXP192::isACIN() -{ - return ( Read8bit(0x00) & 0x80 ) ? true : false; -} -bool AXP192::isCharging() -{ - return ( Read8bit(0x00) & 0x04 ) ? true : false; -} -bool AXP192::isVBUS() -{ - return ( Read8bit(0x00) & 0x20 ) ? true : false; -} - -void AXP192::SetLDOVoltage(uint8_t number, uint16_t voltage) -{ - voltage = (voltage > 3300) ? 15 : (voltage / 100) - 18; - switch (number) - { - //uint8_t reg, data; - case 2: - Write1Byte(0x28, (Read8bit(0x28) & 0X0F) | (voltage << 4)); - break; - case 3: - Write1Byte(0x28, (Read8bit(0x28) & 0XF0) | voltage); - break; - } -} - -void AXP192::SetDCVoltage(uint8_t number, uint16_t voltage) -{ - uint8_t addr; - if (number > 2) - return; - voltage = (voltage < 700) ? 0 : (voltage - 700) / 25; - switch (number) - { - case 0: - addr = 0x26; - break; - case 1: - addr = 0x25; - break; - case 2: - addr = 0x27; - break; - } - Write1Byte(addr, (Read8bit(addr) & 0X80) | (voltage & 0X7F)); -} - -void AXP192::SetESPVoltage(uint16_t voltage) -{ - if (voltage >= 3000 && voltage <= 3400) - { - SetDCVoltage(0, voltage); - } -} -void AXP192::SetLcdVoltage(uint16_t voltage) -{ - if (voltage >= 2500 && voltage <= 3300) - { - SetDCVoltage(2, voltage); - } -} - -void AXP192::SetLDOEnable(uint8_t number, bool state) -{ - uint8_t mark = 0x01; - if ((number < 2) || (number > 3)) - return; - - mark <<= number; - if (state) - { - Write1Byte(0x12, (Read8bit(0x12) | mark)); - } - else - { - Write1Byte(0x12, (Read8bit(0x12) & (~mark))); - } -} - -void AXP192::SetLCDRSet(bool state) -{ - uint8_t reg_addr = 0x96; - uint8_t gpio_bit = 0x02; - uint8_t data; - data = Read8bit(reg_addr); - - if (state) - { - data |= gpio_bit; - } - else - { - data &= ~gpio_bit; - } - - Write1Byte(reg_addr, data); -} - -void AXP192::SetBusPowerMode(uint8_t state) -{ - uint8_t data; - if (state == 0) - { - data = Read8bit(0x91); - Write1Byte(0x91, (data & 0X0F) | 0XF0); - - data = Read8bit(0x90); - Write1Byte(0x90, (data & 0XF8) | 0X02); //set GPIO0 to LDO OUTPUT , pullup N_VBUSEN to disable supply from BUS_5V - - data = Read8bit(0x91); - - data = Read8bit(0x12); //read reg 0x12 - Write1Byte(0x12, data | 0x40); //set EXTEN to enable 5v boost - } - else - { - data = Read8bit(0x12); //read reg 0x10 - Write1Byte(0x12, data & 0XBF); //set EXTEN to disable 5v boost - - //delay(2000); - - data = Read8bit(0x90); - Write1Byte(0x90, (data & 0xF8) | 0X01); //set GPIO0 to float , using enternal pulldown resistor to enable supply from BUS_5VS - } -} - -void AXP192::SetLed(uint8_t state) -{ - uint8_t reg_addr=0x94; - uint8_t data; - data=Read8bit(reg_addr); - - if(state) - { - data=data&0XFD; - } - else - { - data|=0X02; - } - - Write1Byte(reg_addr,data); -} - -//set led state(GPIO high active,set 1 to enable amplifier) -void AXP192::SetSpkEnable(uint8_t state) -{ - uint8_t reg_addr=0x94; - uint8_t gpio_bit=0x04; - uint8_t data; - data=Read8bit(reg_addr); - - if(state) - { - data|=gpio_bit; - } - else - { - data&=~gpio_bit; - } - - Write1Byte(reg_addr,data); -} - -void AXP192::SetCHGCurrent(uint8_t state) -{ - uint8_t data = Read8bit(0x33); - data &= 0xf0; - data = data | ( state & 0x0f ); - Write1Byte(0x33,data); -} diff --git a/lib/AXP192/AXP192.h b/lib/AXP192/AXP192.h deleted file mode 100644 index 662c37e8..00000000 --- a/lib/AXP192/AXP192.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef __AXP192_H__ -#define __AXP192_H__ - -#include -#include - -#define SLEEP_MSEC(us) (((uint64_t)us) * 1000L) -#define SLEEP_SEC(us) (((uint64_t)us) * 1000000L) -#define SLEEP_MIN(us) (((uint64_t)us) * 60L * 1000000L) -#define SLEEP_HR(us) (((uint64_t)us) * 60L * 60L * 1000000L) - -#define AXP_ADDR 0X34 - -#define PowerOff(x) SetSleep(x) - -class AXP192 { -public: - - enum CHGCurrent{ - kCHG_100mA = 0, - kCHG_190mA, - kCHG_280mA, - kCHG_360mA, - kCHG_450mA, - kCHG_550mA, - kCHG_630mA, - kCHG_700mA, - kCHG_780mA, - kCHG_880mA, - kCHG_960mA, - kCHG_1000mA, - kCHG_1080mA, - kCHG_1160mA, - kCHG_1240mA, - kCHG_1320mA, - }; - - AXP192(); - void begin(void); - void ScreenBreath(uint8_t brightness); - bool GetBatState(); - - void EnableCoulombcounter(void); - void DisableCoulombcounter(void); - void StopCoulombcounter(void); - void ClearCoulombcounter(void); - uint32_t GetCoulombchargeData(void); - uint32_t GetCoulombdischargeData(void); - float GetCoulombData(void); - void PowerOff(void); - void SetAdcState(bool state); - // -- sleep - void PrepareToSleep(void); - void RestoreFromLightSleep(void); - void DeepSleep(uint64_t time_in_us = 0); - void LightSleep(uint64_t time_in_us = 0); - uint8_t GetWarningLeve(void); - -public: - // void SetChargeVoltage( uint8_t ); - // void SetChargeCurrent( uint8_t ); - float GetBatVoltage(); - float GetBatCurrent(); - float GetVinVoltage(); - float GetVinCurrent(); - float GetVBusVoltage(); - float GetVBusCurrent(); - float GetTempInAXP192(); - float GetBatPower(); - float GetBatChargeCurrent(); - float GetAPSVoltage(); - float GetBatCoulombInput(); - float GetBatCoulombOut(); - uint8_t GetWarningLevel(void); - void SetCoulombClear(); - void SetLDO2( bool State ); - void SetDCDC3( bool State ); - - uint8_t AXPInState(); - bool isACIN(); - bool isCharging(); - bool isVBUS(); - - void SetLDOVoltage(uint8_t number , uint16_t voltage); - void SetDCVoltage(uint8_t number , uint16_t voltage); - void SetESPVoltage(uint16_t voltage); - void SetLcdVoltage(uint16_t voltage); - void SetLDOEnable( uint8_t number ,bool state ); - void SetLCDRSet( bool state ); - void SetBusPowerMode( uint8_t state ); - void SetLed(uint8_t state); - void SetSpkEnable(uint8_t state); - void SetCHGCurrent(uint8_t state); - -private: - void Write1Byte( uint8_t Addr , uint8_t Data ); - uint8_t Read8bit( uint8_t Addr ); - uint16_t Read12Bit( uint8_t Addr); - uint16_t Read13Bit( uint8_t Addr); - uint16_t Read16bit( uint8_t Addr ); - uint32_t Read24bit( uint8_t Addr ); - uint32_t Read32bit( uint8_t Addr ); - void ReadBuff( uint8_t Addr , uint8_t Size , uint8_t *Buff ); -}; - -#endif diff --git a/lib/AXP192/LICENSE b/lib/AXP192/LICENSE deleted file mode 100644 index 6580a5df..00000000 --- a/lib/AXP192/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 M5Stack - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/lib/ArduinoLog/ArduinoLog.cpp b/lib/ArduinoLog/ArduinoLog.cpp index d3174f52..af50c24f 100644 --- a/lib/ArduinoLog/ArduinoLog.cpp +++ b/lib/ArduinoLog/ArduinoLog.cpp @@ -29,85 +29,87 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "ArduinoLog.h" +#ifdef ARDUINO + + #include "ArduinoLog.h" void Logging::begin(int level, bool showLevel) { -#ifndef DISABLE_LOGGING + #ifndef DISABLE_LOGGING setLevel(0, level); setLevel(1, level); setLevel(2, level); setShowLevel(0, showLevel); -#endif + #endif } void Logging::registerOutput(uint8_t slot, Print * logOutput, int level, bool showLevel) { -#ifndef DISABLE_LOGGING + #ifndef DISABLE_LOGGING if(slot >= 3) return; setLevel(slot, level); setShowLevel(slot, showLevel); _logOutput[slot] = logOutput; -#endif + #endif } void Logging::unregisterOutput(uint8_t slot) { -#ifndef DISABLE_LOGGING + #ifndef DISABLE_LOGGING if(slot >= 3) return; _logOutput[slot] = NULL; -#endif + #endif } void Logging::setLevel(uint8_t slot, int level) { -#ifndef DISABLE_LOGGING + #ifndef DISABLE_LOGGING _level[slot] = constrain(level, LOG_LEVEL_SILENT, LOG_LEVEL_OUTPUT); -#endif + #endif } int Logging::getLevel(uint8_t slot) const { -#ifndef DISABLE_LOGGING + #ifndef DISABLE_LOGGING return _level[slot]; -#else + #else return 0; -#endif + #endif } void Logging::setShowLevel(uint8_t slot, bool showLevel) { -#ifndef DISABLE_LOGGING + #ifndef DISABLE_LOGGING _showLevel[slot] = showLevel; -#endif + #endif } bool Logging::getShowLevel(uint8_t slot) const { -#ifndef DISABLE_LOGGING + #ifndef DISABLE_LOGGING return _showLevel[slot]; -#else + #else return false; -#endif + #endif } void Logging::setPrefix(printfunction f) { -#ifndef DISABLE_LOGGING + #ifndef DISABLE_LOGGING _prefix = f; -#endif + #endif } void Logging::setSuffix(printfunction f) { -#ifndef DISABLE_LOGGING + #ifndef DISABLE_LOGGING _suffix = f; -#endif + #endif } void Logging::print(Print * logOutput, const __FlashStringHelper * format, va_list args) { -#ifndef DISABLE_LOGGING + #ifndef DISABLE_LOGGING PGM_P p = reinterpret_cast(format); char c = pgm_read_byte(p++); for(; c != 0; c = pgm_read_byte(p++)) { @@ -118,12 +120,12 @@ void Logging::print(Print * logOutput, const __FlashStringHelper * format, va_li logOutput->print(c); } } -#endif + #endif } void Logging::print(Print * logOutput, const char * format, va_list args) { -#ifndef DISABLE_LOGGING + #ifndef DISABLE_LOGGING for(; *format != 0; ++format) { if(*format == '%') { ++format; @@ -132,12 +134,12 @@ void Logging::print(Print * logOutput, const char * format, va_list args) logOutput->print(*format); } } -#endif + #endif } void Logging::printFormat(Print * logOutput, const char format, va_list * args) { -#ifndef DISABLE_LOGGING + #ifndef DISABLE_LOGGING if(format == '%') { logOutput->print(format); } else if(format == 's') { @@ -179,7 +181,9 @@ void Logging::printFormat(Print * logOutput, const char format, va_list * args) logOutput->print(F("false")); } } -#endif + #endif } Logging Log = Logging(); + +#endif // ARDUINO \ No newline at end of file diff --git a/lib/ArduinoLog/ArduinoLog.h b/lib/ArduinoLog/ArduinoLog.h index 68060baa..921a92db 100644 --- a/lib/ArduinoLog/ArduinoLog.h +++ b/lib/ArduinoLog/ArduinoLog.h @@ -17,12 +17,12 @@ Licensed under the MIT License . #include #include #if defined(ARDUINO) && ARDUINO >= 100 - #include "Arduino.h" +#include "Arduino.h" #else - #include "WProgram.h" +#include "WProgram.h" #endif //#include "StringStream.h" -typedef void (*printfunction)(uint8_t tag, int level, Print *); +typedef void (*printfunction)(uint8_t tag, int level, Print*); //#include //#include @@ -92,7 +92,7 @@ class Logging { */ Logging() #ifndef DISABLE_LOGGING - // : _level(LOG_LEVEL_SILENT), _showLevel(true) + // : _level(LOG_LEVEL_SILENT), _showLevel(true) #endif {} @@ -116,7 +116,7 @@ class Logging { * \return void * */ - void registerOutput(uint8_t slot, Print * logOutput, int level, bool showLevel); + void registerOutput(uint8_t slot, Print* logOutput, int level, bool showLevel); /** * Unregister the printer in a certain slot @@ -311,11 +311,11 @@ class Logging { } private: - void print(Print * logOutput, const char * format, va_list args); + void print(Print* logOutput, const char* format, va_list args); - void print(Print * logOutput, const __FlashStringHelper * format, va_list args); + void print(Print* logOutput, const __FlashStringHelper* format, va_list args); - void printFormat(Print * logOutput, const char format, va_list * args); + void printFormat(Print* logOutput, const char format, va_list* args); template void printLevel(uint8_t tag, int level, T msg, ...) { @@ -343,7 +343,7 @@ class Logging { #ifndef DISABLE_LOGGING int _level[3]; bool _showLevel[3]; - Print * _logOutput[3]; + Print* _logOutput[3]; printfunction _prefix = NULL; printfunction _suffix = NULL; diff --git a/lib/README b/lib/README index 6debab1e..79cec710 100644 --- a/lib/README +++ b/lib/README @@ -1,5 +1,5 @@ -This directory is intended for project specific (private) libraries. +This directory is intended for project specific (customized) libraries. PlatformIO will compile them to static libraries and link into executable file. The source code of each library should be placed in a an own separate directory diff --git a/lib/lv_drivers/.gitignore b/lib/lv_drivers/.gitignore deleted file mode 100644 index 2372cca0..00000000 --- a/lib/lv_drivers/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.o \ No newline at end of file diff --git a/lib/lv_drivers/LICENSE b/lib/lv_drivers/LICENSE deleted file mode 100644 index cc227abe..00000000 --- a/lib/lv_drivers/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 LittlevGL - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/lib/lv_drivers/README.md b/lib/lv_drivers/README.md deleted file mode 100644 index 160d08ae..00000000 --- a/lib/lv_drivers/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Display and Touch pad drivers - -Display controller and touchpad driver to can be directly used with [LittlevGL](https://littlevgl.com). - -To learn more about using drivers in LittlevGL visit the [Porting guide](https://littlevgl.com/porting). - -If you used a new display or touch pad driver with LittlevGL please share it with other people! diff --git a/lib/lv_drivers/display/R61581.c b/lib/lv_drivers/display/R61581.c deleted file mode 100644 index 4d21bff9..00000000 --- a/lib/lv_drivers/display/R61581.c +++ /dev/null @@ -1,425 +0,0 @@ -/** - * @file R61581.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "R61581.h" -#if USE_R61581 != 0 - -#include -#include "lvgl/lv_core/lv_vdb.h" -#include LV_DRV_DISP_INCLUDE -#include LV_DRV_DELAY_INCLUDE - -/********************* - * DEFINES - *********************/ -#define R61581_CMD_MODE 0 -#define R61581_DATA_MODE 1 - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ -static void r61581_io_init(void); -static void r61581_reset(void); -static void r61581_set_tft_spec(void); -static inline void r61581_cmd_mode(void); -static inline void r61581_data_mode(void); -static inline void r61581_cmd(uint8_t cmd); -static inline void r61581_data(uint8_t data); - -/********************** - * STATIC VARIABLES - **********************/ -static bool cmd_mode = true; - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Initialize the R61581 display controller - * @return HW_RES_OK or any error from hw_res_t enum - */ -void r61581_init(void) -{ - r61581_io_init(); - - /*Slow mode until the PLL is not started in the display controller*/ - LV_DRV_DISP_PAR_SLOW; - - r61581_reset(); - - r61581_set_tft_spec(); - - r61581_cmd(0x13); //SET display on - - r61581_cmd(0x29); //SET display on - LV_DRV_DELAY_MS(30); - - /*Parallel to max speed*/ - LV_DRV_DISP_PAR_FAST; -} - -void r61581_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) -{ - /*Return if the area is out the screen*/ - if(x2 < 0) return; - if(y2 < 0) return; - if(x1 > R61581_HOR_RES - 1) return; - if(y1 > R61581_VER_RES - 1) return; - - /*Truncate the area to the screen*/ - int32_t act_x1 = x1 < 0 ? 0 : x1; - int32_t act_y1 = y1 < 0 ? 0 : y1; - int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2; - int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2; - - - //Set the rectangular area - r61581_cmd(0x002A); - r61581_data(act_x1 >> 8); - r61581_data(0x00FF & act_x1); - r61581_data(act_x2 >> 8); - r61581_data(0x00FF & act_x2); - - r61581_cmd(0x002B); - r61581_data(act_y1 >> 8); - r61581_data(0x00FF & act_y1); - r61581_data(act_y2 >> 8); - r61581_data(0x00FF & act_y2); - - r61581_cmd(0x2c); - - int16_t i; - uint16_t full_w = x2 - x1 + 1; - - r61581_data_mode(); - -#if LV_COLOR_DEPTH == 16 - uint16_t act_w = act_x2 - act_x1 + 1; - for(i = act_y1; i <= act_y2; i++) { - LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w); - color_p += full_w; - } -#else - int16_t j; - for(i = act_y1; i <= act_y2; i++) { - for(j = 0; j <= act_x2 - act_x1 + 1; j++) { - LV_DRV_DISP_PAR_WR_WORD(lv_color_to16(color_p[j])); - color_p += full_w; - } - } -#endif - - lv_flush_ready(); -} - -void r61581_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color) -{ - /*Return if the area is out the screen*/ - if(x2 < 0) return; - if(y2 < 0) return; - if(x1 > R61581_HOR_RES - 1) return; - if(y1 > R61581_VER_RES - 1) return; - - /*Truncate the area to the screen*/ - int32_t act_x1 = x1 < 0 ? 0 : x1; - int32_t act_y1 = y1 < 0 ? 0 : y1; - int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2; - int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2; - - //Set the rectangular area - r61581_cmd(0x002A); - r61581_data(act_x1 >> 8); - r61581_data(0x00FF & act_x1); - r61581_data(act_x2 >> 8); - r61581_data(0x00FF & act_x2); - - r61581_cmd(0x002B); - r61581_data(act_y1 >> 8); - r61581_data(0x00FF & act_y1); - r61581_data(act_y2 >> 8); - r61581_data(0x00FF & act_y2); - - r61581_cmd(0x2c); - - r61581_data_mode(); - - uint16_t color16 = lv_color_to16(color); - uint32_t size = (act_x2 - act_x1 + 1) * (act_y2 - act_y1 + 1); - uint32_t i; - for(i = 0; i < size; i++) { - LV_DRV_DISP_PAR_WR_WORD(color16); - } -} - -void r61581_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) -{ - /*Return if the area is out the screen*/ - if(x2 < 0) return; - if(y2 < 0) return; - if(x1 > R61581_HOR_RES - 1) return; - if(y1 > R61581_VER_RES - 1) return; - - /*Truncate the area to the screen*/ - int32_t act_x1 = x1 < 0 ? 0 : x1; - int32_t act_y1 = y1 < 0 ? 0 : y1; - int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2; - int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2; - - - //Set the rectangular area - r61581_cmd(0x002A); - r61581_data(act_x1 >> 8); - r61581_data(0x00FF & act_x1); - r61581_data(act_x2 >> 8); - r61581_data(0x00FF & act_x2); - - r61581_cmd(0x002B); - r61581_data(act_y1 >> 8); - r61581_data(0x00FF & act_y1); - r61581_data(act_y2 >> 8); - r61581_data(0x00FF & act_y2); - - r61581_cmd(0x2c); - - int16_t i; - uint16_t full_w = x2 - x1 + 1; - - r61581_data_mode(); - -#if LV_COLOR_DEPTH == 16 - uint16_t act_w = act_x2 - act_x1 + 1; - for(i = act_y1; i <= act_y2; i++) { - LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w); - color_p += full_w; - } -#else - int16_t j; - for(i = act_y1; i <= act_y2; i++) { - for(j = 0; j <= act_x2 - act_x1 + 1; j++) { - LV_DRV_DISP_PAR_WR_WORD(lv_color_to16(color_p[j])); - color_p += full_w; - } - } -#endif -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -/** - * Io init - */ -static void r61581_io_init(void) -{ - LV_DRV_DISP_CMD_DATA(R61581_CMD_MODE) - cmd_mode = true; -} - -/** - * Reset - */ -static void r61581_reset(void) -{ - /*Hardware reset*/ - LV_DRV_DISP_RST(1); - LV_DRV_DELAY_MS(50); - LV_DRV_DISP_RST(0); - LV_DRV_DELAY_MS(50); - LV_DRV_DISP_RST(1); - LV_DRV_DELAY_MS(50); - - /*Chip enable*/ - LV_DRV_DISP_PAR_CS(1); - LV_DRV_DELAY_MS(10); - LV_DRV_DISP_PAR_CS(0); - LV_DRV_DELAY_MS(5); - - /*Software reset*/ - r61581_cmd(0x01); - LV_DRV_DELAY_MS(20); - - r61581_cmd(0x01); - LV_DRV_DELAY_MS(20); - - r61581_cmd(0x01); - LV_DRV_DELAY_MS(20); -} - -/** - * TFT specific initialization - */ -static void r61581_set_tft_spec(void) -{ - r61581_cmd(0xB0); - r61581_data(0x00); - - r61581_cmd(0xB3); - r61581_data(0x02); - r61581_data(0x00); - r61581_data(0x00); - r61581_data(0x10); - - r61581_cmd(0xB4); - r61581_data(0x00);//0X10 - - r61581_cmd(0xB9); //PWM - r61581_data(0x01); - r61581_data(0xFF); //FF brightness - r61581_data(0xFF); - r61581_data(0x18); - - /*Panel Driving Setting*/ - r61581_cmd(0xC0); - r61581_data(0x02); - r61581_data(0x3B); - r61581_data(0x00); - r61581_data(0x00); - r61581_data(0x00); - r61581_data(0x01); - r61581_data(0x00);//NW - r61581_data(0x43); - - /*Display Timing Setting for Normal Mode */ - r61581_cmd(0xC1); - r61581_data(0x08); - r61581_data(0x15); //CLOCK - r61581_data(R61581_VFP); - r61581_data(R61581_VBP); - - /*Source/VCOM/Gate Driving Timing Setting*/ - r61581_cmd(0xC4); - r61581_data(0x15); - r61581_data(0x03); - r61581_data(0x03); - r61581_data(0x01); - - /*Interface Setting*/ - r61581_cmd(0xC6); - r61581_data((R61581_DPL << 0) | - (R61581_EPL << 1) | - (R61581_HSPL << 4) | - (R61581_VSPL << 5)); - - /*Gamma Set*/ - r61581_cmd(0xC8); - r61581_data(0x0c); - r61581_data(0x05); - r61581_data(0x0A); - r61581_data(0x6B); - r61581_data(0x04); - r61581_data(0x06); - r61581_data(0x15); - r61581_data(0x10); - r61581_data(0x00); - r61581_data(0x31); - - - r61581_cmd(0x36); - if(R61581_ORI == 0) r61581_data(0xE0); - else r61581_data(0x20); - - r61581_cmd(0x0C); - r61581_data(0x55); - - r61581_cmd(0x3A); - r61581_data(0x55); - - r61581_cmd(0x38); - - r61581_cmd(0xD0); - r61581_data(0x07); - r61581_data(0x07); - r61581_data(0x14); - r61581_data(0xA2); - - r61581_cmd(0xD1); - r61581_data(0x03); - r61581_data(0x5A); - r61581_data(0x10); - - r61581_cmd(0xD2); - r61581_data(0x03); - r61581_data(0x04); - r61581_data(0x04); - - r61581_cmd(0x11); - LV_DRV_DELAY_MS(10); - - r61581_cmd(0x2A); - r61581_data(0x00); - r61581_data(0x00); - r61581_data(((R61581_HOR_RES - 1) >> 8) & 0XFF); - r61581_data((R61581_HOR_RES - 1) & 0XFF); - - r61581_cmd(0x2B); - r61581_data(0x00); - r61581_data(0x00); - r61581_data(((R61581_VER_RES - 1) >> 8) & 0XFF); - r61581_data((R61581_VER_RES - 1) & 0XFF); - - LV_DRV_DELAY_MS(10); - - r61581_cmd(0x29); - LV_DRV_DELAY_MS(5); - - r61581_cmd(0x2C); - LV_DRV_DELAY_MS(5); -} - -/** - * Command mode - */ -static inline void r61581_cmd_mode(void) -{ - if(cmd_mode == false) { - LV_DRV_DISP_CMD_DATA(R61581_CMD_MODE) - cmd_mode = true; - } -} - -/** - * Data mode - */ -static inline void r61581_data_mode(void) -{ - if(cmd_mode != false) { - LV_DRV_DISP_CMD_DATA(R61581_DATA_MODE); - cmd_mode = false; - } -} - -/** - * Write command - * @param cmd the command - */ -static inline void r61581_cmd(uint8_t cmd) -{ - r61581_cmd_mode(); - LV_DRV_DISP_PAR_WR_WORD(cmd); -} - -/** - * Write data - * @param data the data - */ -static inline void r61581_data(uint8_t data) -{ - r61581_data_mode(); - LV_DRV_DISP_PAR_WR_WORD(data); -} -#endif diff --git a/lib/lv_drivers/display/R61581.h b/lib/lv_drivers/display/R61581.h deleted file mode 100644 index 3ba4ff93..00000000 --- a/lib/lv_drivers/display/R61581.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @file R61581.h - * - */ - -#ifndef R61581_H -#define R61581_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_R61581 - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -void r61581_init(void); -void r61581_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); -void r61581_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); -void r61581_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); -/********************** - * MACROS - **********************/ - -#endif /* USE_R61581 */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* R61581_H */ diff --git a/lib/lv_drivers/display/SHARP_MIP.c b/lib/lv_drivers/display/SHARP_MIP.c deleted file mode 100644 index 129ac2f3..00000000 --- a/lib/lv_drivers/display/SHARP_MIP.c +++ /dev/null @@ -1,182 +0,0 @@ -/** - * @file SHARP_MIP.c - * - */ - -/*------------------------------------------------------------------------------------------------- - * SHARP memory in pixel monochrome display series - * LS012B7DD01 (184x38 pixels.) - * LS013B7DH03 (128x128 pixels.) - * LS013B7DH05 (144x168 pixels.) - * LS027B7DH01 (400x240 pixels.) (tested) - * LS032B7DD02 (336x536 pixels.) - * LS044Q7DH01 (320x240 pixels.) - * - * These displays need periodic com inversion, there are two ways : - * - software com inversion : - * define SHARP_MIP_SOFT_COM_INVERSION 1 and set EXTMODE display pin LOW, - * call sharp_mip_com_inversion() periodically - * - hardware com inversion with EXTCOMIN display pin : - * define SHARP_MIP_SOFT_COM_INVERSION 0, - * set EXTMODE display pin HIGH and handle - * EXTCOMIN waveform (for example with mcu pwm output), - * see datasheet pages 8-12 for details - * - * VDB size : (LV_VER_RES / X) * (2 + LV_HOR_RES / 8) + 2 bytes, structure : - * [FRAME_HEADER (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] 1st line - * [DUMMY (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] 2nd line - * ........................................................................................... - * [DUMMY (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] last line - * [DUMMY (2 bytes)] - * - * Since extra bytes (dummy, addresses, header) are stored in VDB, we need to use - * an "oversized" VDB. Buffer declaration in "lv_port_disp.c" becomes for example : - * static lv_disp_buf_t disp_buf; - * static uint8_t buf[(LV_VER_RES_MAX / X) * (2 + (LV_HOR_RES_MAX / 8)) + 2]; - * lv_disp_buf_init(&disp_buf, buf, NULL, LV_VER_RES_MAX * LV_HOR_RES_MAX / X); - *-----------------------------------------------------------------------------------------------*/ - -/********************* - * INCLUDES - *********************/ - -#include "SHARP_MIP.h" - -#if USE_SHARP_MIP - -#include -#include LV_DRV_DISP_INCLUDE -#include LV_DRV_DELAY_INCLUDE - -/********************* - * DEFINES - *********************/ - -#define SHARP_MIP_HEADER 0 -#define SHARP_MIP_UPDATE_RAM_FLAG (1 << 7) /* (M0) Mode flag : H -> update memory, L -> maintain memory */ -#define SHARP_MIP_COM_INVERSION_FLAG (1 << 6) /* (M1) Frame inversion flag : relevant when EXTMODE = L, */ - /* H -> outputs VCOM = H, L -> outputs VCOM = L */ -#define SHARP_MIP_CLEAR_SCREEN_FLAG (1 << 5) /* (M2) All clear flag : H -> clear all pixels */ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ - -#if SHARP_MIP_SOFT_COM_INVERSION -static bool_t com_output_state = false; -#endif - -/********************** - * MACROS - **********************/ - -/* - * Return the VDB byte index corresponding to the pixel - * relatives coordinates (x, y) in the area. - * The area is rounded to a whole screen line. - */ -#define BUFIDX(x, y) (((x) >> 3) + ((y) * (2 + (SHARP_MIP_HOR_RES >> 3))) + 2) - -/* - * Return the byte bitmask of a pixel bit corresponding - * to VDB arrangement (8 pixels per byte on lines). - */ -#define PIXIDX(x) SHARP_MIP_REV_BYTE(1 << ((x) & 7)) - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void sharp_mip_init(void) { - /* These displays have nothing to initialize */ -} - - -void sharp_mip_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { - - /*Return if the area is out the screen*/ - if(area->y2 < 0) return; - if(area->y1 > SHARP_MIP_VER_RES - 1) return; - - /*Truncate the area to the screen*/ - uint16_t act_y1 = area->y1 < 0 ? 0 : area->y1; - uint16_t act_y2 = area->y2 > SHARP_MIP_VER_RES - 1 ? SHARP_MIP_VER_RES - 1 : area->y2; - - uint8_t * buf = (uint8_t *) color_p; /*Get the buffer address*/ - uint16_t buf_h = (act_y2 - act_y1 + 1); /*Number of buffer lines*/ - uint16_t buf_size = buf_h * (2 + SHARP_MIP_HOR_RES / 8) + 2; /*Buffer size in bytes */ - - /* Set lines to flush dummy byte & gate address in VDB*/ - for(uint16_t act_y = 0 ; act_y < buf_h ; act_y++) { - buf[BUFIDX(0, act_y) - 1] = SHARP_MIP_REV_BYTE((act_y1 + act_y + 1)); - buf[BUFIDX(0, act_y) - 2] = 0; - } - - /* Set last dummy two bytes in VDB */ - buf[BUFIDX(0, buf_h) - 1] = 0; - buf[BUFIDX(0, buf_h) - 2] = 0; - - /* Set frame header in VDB */ - buf[0] = SHARP_MIP_HEADER | - SHARP_MIP_UPDATE_RAM_FLAG; - - /* Write the frame on display memory */ - LV_DRV_DISP_SPI_CS(1); - LV_DRV_DISP_SPI_WR_ARRAY(buf, buf_size); - LV_DRV_DISP_SPI_CS(0); - - lv_disp_flush_ready(disp_drv); -} - -void sharp_mip_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) { - (void) disp_drv; - (void) buf_w; - (void) opa; - - if (lv_color_to1(color) != 0) { - buf[BUFIDX(x, y)] |= PIXIDX(x); /*Set VDB pixel bit to 1 for other colors than BLACK*/ - } else { - buf[BUFIDX(x, y)] &= ~PIXIDX(x); /*Set VDB pixel bit to 0 for BLACK color*/ - } -} - -void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area) { - (void) disp_drv; - - /* Round area to a whole line */ - area->x1 = 0; - area->x2 = SHARP_MIP_HOR_RES - 1; -} - -#if SHARP_MIP_SOFT_COM_INVERSION -void sharp_mip_com_inversion(void) { - uint8_t inversion_header[2] = {0}; - - /* Set inversion header */ - if (com_output_state) { - com_output_state = false; - } else { - inversion_header[0] |= SHARP_MIP_COM_INVERSION_FLAG; - com_output_state = true; - } - - /* Write inversion header on display memory */ - LV_DRV_DISP_SPI_CS(1); - LV_DRV_DISP_SPI_WR_ARRAY(inversion_header, 2); - LV_DRV_DISP_SPI_CS(0); -} -#endif - -/********************** - * STATIC FUNCTIONS - **********************/ - -#endif diff --git a/lib/lv_drivers/display/SHARP_MIP.h b/lib/lv_drivers/display/SHARP_MIP.h deleted file mode 100644 index c10d8459..00000000 --- a/lib/lv_drivers/display/SHARP_MIP.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @file SHARP_MIP.h - * - */ - -#ifndef SHARP_MIP_H -#define SHARP_MIP_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ - -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_SHARP_MIP - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -void sharp_mip_init(void); -void sharp_mip_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); -void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area); -void sharp_mip_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); -#if SHARP_MIP_SOFT_COM_INVERSION -void sharp_mip_com_inversion(void); -#endif - -/********************** - * MACROS - **********************/ - -#endif /* USE_SHARP_MIP */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* SHARP_MIP_H */ diff --git a/lib/lv_drivers/display/SSD1963.c b/lib/lv_drivers/display/SSD1963.c deleted file mode 100644 index c961066b..00000000 --- a/lib/lv_drivers/display/SSD1963.c +++ /dev/null @@ -1,292 +0,0 @@ -/** - * @file SSD1963.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "SSD1963.h" -#if USE_SSD1963 - -#include -#include LV_DRV_DISP_INCLUDE -#include LV_DRV_DELAY_INCLUDE - -/********************* - * DEFINES - *********************/ -#define SSD1963_CMD_MODE 0 -#define SSD1963_DATA_MODE 1 - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ -static inline void ssd1963_cmd_mode(void); -static inline void ssd1963_data_mode(void); -static inline void ssd1963_cmd(uint8_t cmd); -static inline void ssd1963_data(uint8_t data); -static void ssd1963_io_init(void); -static void ssd1963_reset(void); -static void ssd1963_set_clk(void); -static void ssd1963_set_tft_spec(void); -static void ssd1963_init_bl(void); - -/********************** - * STATIC VARIABLES - **********************/ -static bool cmd_mode = true; - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void ssd1963_init(void) -{ - - LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE); - cmd_mode = true; - - LV_DRV_DELAY_MS(250); - - - ssd1963_cmd(0x00E2); //PLL multiplier, set PLL clock to 120M - ssd1963_data(0x0023); //N=0x36 for 6.5M, 0x23 for 10M crystal - ssd1963_data(0x0002); - ssd1963_data(0x0004); - ssd1963_cmd(0x00E0); // PLL enable - ssd1963_data(0x0001); - LV_DRV_DELAY_MS(1); - ssd1963_cmd(0x00E0); - ssd1963_data(0x0003); // now, use PLL output as system clock - LV_DRV_DELAY_MS(1); - ssd1963_cmd(0x0001); // software reset - LV_DRV_DELAY_MS(1); - ssd1963_cmd(0x00E6); //PLL setting for PCLK, depends on resolution - - ssd1963_data(0x0001); //HX8257C - ssd1963_data(0x0033); //HX8257C - ssd1963_data(0x0033); //HX8257C - - - ssd1963_cmd(0x00B0); //LCD SPECIFICATION - ssd1963_data(0x0020); - ssd1963_data(0x0000); - ssd1963_data(((SSD1963_HOR_RES - 1) >> 8) & 0X00FF); //Set HDP - ssd1963_data((SSD1963_HOR_RES - 1) & 0X00FF); - ssd1963_data(((SSD1963_VER_RES - 1) >> 8) & 0X00FF); //Set VDP - ssd1963_data((SSD1963_VER_RES - 1) & 0X00FF); - ssd1963_data(0x0000); - LV_DRV_DELAY_MS(1);//Delay10us(5); - ssd1963_cmd(0x00B4); //HSYNC - ssd1963_data((SSD1963_HT >> 8) & 0X00FF); //Set HT - ssd1963_data(SSD1963_HT & 0X00FF); - ssd1963_data((SSD1963_HPS >> 8) & 0X00FF); //Set HPS - ssd1963_data(SSD1963_HPS & 0X00FF); - ssd1963_data(SSD1963_HPW); //Set HPW - ssd1963_data((SSD1963_LPS >> 8) & 0X00FF); //SetLPS - ssd1963_data(SSD1963_LPS & 0X00FF); - ssd1963_data(0x0000); - - ssd1963_cmd(0x00B6); //VSYNC - ssd1963_data((SSD1963_VT >> 8) & 0X00FF); //Set VT - ssd1963_data(SSD1963_VT & 0X00FF); - ssd1963_data((SSD1963_VPS >> 8) & 0X00FF); //Set VPS - ssd1963_data(SSD1963_VPS & 0X00FF); - ssd1963_data(SSD1963_VPW); //Set VPW - ssd1963_data((SSD1963_FPS >> 8) & 0X00FF); //Set FPS - ssd1963_data(SSD1963_FPS & 0X00FF); - - ssd1963_cmd(0x00B8); - ssd1963_data(0x000f); //GPIO is controlled by host GPIO[3:0]=output GPIO[0]=1 LCD ON GPIO[0]=1 LCD OFF - ssd1963_data(0x0001); //GPIO0 normal - - ssd1963_cmd(0x00BA); - ssd1963_data(0x0001); //GPIO[0] out 1 --- LCD display on/off control PIN - - ssd1963_cmd(0x0036); //rotation - ssd1963_data(0x0008); //RGB=BGR - - ssd1963_cmd(0x003A); //Set the current pixel format for RGB image data - ssd1963_data(0x0050); //16-bit/pixel - - ssd1963_cmd(0x00F0); //Pixel Data Interface Format - ssd1963_data(0x0003); //16-bit(565 format) data - - ssd1963_cmd(0x00BC); - ssd1963_data(0x0040); //contrast value - ssd1963_data(0x0080); //brightness value - ssd1963_data(0x0040); //saturation value - ssd1963_data(0x0001); //Post Processor Enable - - LV_DRV_DELAY_MS(1); - - ssd1963_cmd(0x0029); //display on - - ssd1963_cmd(0x00BE); //set PWM for B/L - ssd1963_data(0x0006); - ssd1963_data(0x0080); - ssd1963_data(0x0001); - ssd1963_data(0x00f0); - ssd1963_data(0x0000); - ssd1963_data(0x0000); - - ssd1963_cmd(0x00d0); - ssd1963_data(0x000d); - - //DisplayBacklightOn(); - - LV_DRV_DELAY_MS(30); -} - -void ssd1963_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) -{ - - /*Return if the area is out the screen*/ - if(area->x2 < 0) return; - if(area->y2 < 0) return; - if(area->x1 > SSD1963_HOR_RES - 1) return; - if(area->y1 > SSD1963_VER_RES - 1) return; - - /*Truncate the area to the screen*/ - int32_t act_x1 = area->x1 < 0 ? 0 : area->x1; - int32_t act_y1 = area->y1 < 0 ? 0 : area->y1; - int32_t act_x2 = area->x2 > SSD1963_HOR_RES - 1 ? SSD1963_HOR_RES - 1 : area->x2; - int32_t act_y2 = area->y2 > SSD1963_VER_RES - 1 ? SSD1963_VER_RES - 1 : area->y2; - - //Set the rectangular area - ssd1963_cmd(0x002A); - ssd1963_data(act_x1 >> 8); - ssd1963_data(0x00FF & act_x1); - ssd1963_data(act_x2 >> 8); - ssd1963_data(0x00FF & act_x2); - - ssd1963_cmd(0x002B); - ssd1963_data(act_y1 >> 8); - ssd1963_data(0x00FF & act_y1); - ssd1963_data(act_y2 >> 8); - ssd1963_data(0x00FF & act_y2); - - ssd1963_cmd(0x2c); - int16_t i; - uint16_t full_w = area->x2 - area->x1 + 1; - - ssd1963_data_mode(); - LV_DRV_DISP_PAR_CS(0); -#if LV_COLOR_DEPTH == 16 - uint16_t act_w = act_x2 - act_x1 + 1; - for(i = act_y1; i <= act_y2; i++) { - LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w); - color_p += full_w; - } - LV_DRV_DISP_PAR_CS(1); -#else - int16_t j; - for(i = act_y1; i <= act_y2; i++) { - for(j = 0; j <= act_x2 - act_x1 + 1; j++) { - LV_DRV_DISP_PAR_WR_WORD(color_p[j]); - color_p += full_w; - } - } -#endif - - lv_disp_flush_ready(disp_drv); -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -static void ssd1963_io_init(void) -{ - LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE); - cmd_mode = true; -} - -static void ssd1963_reset(void) -{ - /*Hardware reset*/ - LV_DRV_DISP_RST(1); - LV_DRV_DELAY_MS(50); - LV_DRV_DISP_RST(0); - LV_DRV_DELAY_MS(50); - LV_DRV_DISP_RST(1); - LV_DRV_DELAY_MS(50); - - /*Chip enable*/ - LV_DRV_DISP_PAR_CS(0); - LV_DRV_DELAY_MS(10); - LV_DRV_DISP_PAR_CS(1); - LV_DRV_DELAY_MS(5); - - /*Software reset*/ - ssd1963_cmd(0x01); - LV_DRV_DELAY_MS(20); - - ssd1963_cmd(0x01); - LV_DRV_DELAY_MS(20); - - ssd1963_cmd(0x01); - LV_DRV_DELAY_MS(20); - -} - -/** - * Command mode - */ -static inline void ssd1963_cmd_mode(void) -{ - if(cmd_mode == false) { - LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE); - cmd_mode = true; - } -} - -/** - * Data mode - */ -static inline void ssd1963_data_mode(void) -{ - if(cmd_mode != false) { - LV_DRV_DISP_CMD_DATA(SSD1963_DATA_MODE); - cmd_mode = false; - } -} - -/** - * Write command - * @param cmd the command - */ -static inline void ssd1963_cmd(uint8_t cmd) -{ - - LV_DRV_DISP_PAR_CS(0); - ssd1963_cmd_mode(); - LV_DRV_DISP_PAR_WR_WORD(cmd); - LV_DRV_DISP_PAR_CS(1); - -} - -/** - * Write data - * @param data the data - */ -static inline void ssd1963_data(uint8_t data) -{ - - LV_DRV_DISP_PAR_CS(0); - ssd1963_data_mode(); - LV_DRV_DISP_PAR_WR_WORD(data); - LV_DRV_DISP_PAR_CS(1); - -} - -#endif diff --git a/lib/lv_drivers/display/SSD1963.h b/lib/lv_drivers/display/SSD1963.h deleted file mode 100644 index 49639f59..00000000 --- a/lib/lv_drivers/display/SSD1963.h +++ /dev/null @@ -1,150 +0,0 @@ -/** - * @file SSD1963.h - * - */ - -#ifndef SSD1963_H -#define SSD1963_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_SSD1963 - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -/********************* - * DEFINES - *********************/ -// SSD1963 command table -#define CMD_NOP 0x00 //No operation -#define CMD_SOFT_RESET 0x01 //Software reset -#define CMD_GET_PWR_MODE 0x0A //Get the current power mode -#define CMD_GET_ADDR_MODE 0x0B //Get the frame memory to the display panel read order -#define CMD_GET_PIXEL_FORMAT 0x0C //Get the current pixel format -#define CMD_GET_DISPLAY_MODE 0x0D //Returns the display mode -#define CMD_GET_SIGNAL_MODE 0x0E // -#define CMD_GET_DIAGNOSTIC 0x0F -#define CMD_ENT_SLEEP 0x10 -#define CMD_EXIT_SLEEP 0x11 -#define CMD_ENT_PARTIAL_MODE 0x12 -#define CMD_ENT_NORMAL_MODE 0x13 -#define CMD_EXIT_INVERT_MODE 0x20 -#define CMD_ENT_INVERT_MODE 0x21 -#define CMD_SET_GAMMA 0x26 -#define CMD_BLANK_DISPLAY 0x28 -#define CMD_ON_DISPLAY 0x29 -#define CMD_SET_COLUMN 0x2A -#define CMD_SET_PAGE 0x2B -#define CMD_WR_MEMSTART 0x2C -#define CMD_RD_MEMSTART 0x2E -#define CMD_SET_PARTIAL_AREA 0x30 -#define CMD_SET_SCROLL_AREA 0x33 -#define CMD_SET_TEAR_OFF 0x34 //synchronization information is not sent from the display -#define CMD_SET_TEAR_ON 0x35 //sync. information is sent from the display -#define CMD_SET_ADDR_MODE 0x36 //set fram buffer read order to the display panel -#define CMD_SET_SCROLL_START 0x37 -#define CMD_EXIT_IDLE_MODE 0x38 -#define CMD_ENT_IDLE_MODE 0x39 -#define CMD_SET_PIXEL_FORMAT 0x3A //defines how many bits per pixel is used -#define CMD_WR_MEM_AUTO 0x3C -#define CMD_RD_MEM_AUTO 0x3E -#define CMD_SET_TEAR_SCANLINE 0x44 -#define CMD_GET_SCANLINE 0x45 -#define CMD_RD_DDB_START 0xA1 -#define CMD_RD_DDB_AUTO 0xA8 -#define CMD_SET_PANEL_MODE 0xB0 -#define CMD_GET_PANEL_MODE 0xB1 -#define CMD_SET_HOR_PERIOD 0xB4 -#define CMD_GET_HOR_PERIOD 0xB5 -#define CMD_SET_VER_PERIOD 0xB6 -#define CMD_GET_VER_PERIOD 0xB7 -#define CMD_SET_GPIO_CONF 0xB8 -#define CMD_GET_GPIO_CONF 0xB9 -#define CMD_SET_GPIO_VAL 0xBA -#define CMD_GET_GPIO_STATUS 0xBB -#define CMD_SET_POST_PROC 0xBC -#define CMD_GET_POST_PROC 0xBD -#define CMD_SET_PWM_CONF 0xBE -#define CMD_GET_PWM_CONF 0xBF -#define CMD_SET_LCD_GEN0 0xC0 -#define CMD_GET_LCD_GEN0 0xC1 -#define CMD_SET_LCD_GEN1 0xC2 -#define CMD_GET_LCD_GEN1 0xC3 -#define CMD_SET_LCD_GEN2 0xC4 -#define CMD_GET_LCD_GEN2 0xC5 -#define CMD_SET_LCD_GEN3 0xC6 -#define CMD_GET_LCD_GEN3 0xC7 -#define CMD_SET_GPIO0_ROP 0xC8 -#define CMD_GET_GPIO0_ROP 0xC9 -#define CMD_SET_GPIO1_ROP 0xCA -#define CMD_GET_GPIO1_ROP 0xCB -#define CMD_SET_GPIO2_ROP 0xCC -#define CMD_GET_GPIO2_ROP 0xCD -#define CMD_SET_GPIO3_ROP 0xCE -#define CMD_GET_GPIO3_ROP 0xCF -#define CMD_SET_ABC_DBC_CONF 0xD0 -#define CMD_GET_ABC_DBC_CONF 0xD1 -#define CMD_SET_DBC_HISTO_PTR 0xD2 -#define CMD_GET_DBC_HISTO_PTR 0xD3 -#define CMD_SET_DBC_THRES 0xD4 -#define CMD_GET_DBC_THRES 0xD5 -#define CMD_SET_ABM_TMR 0xD6 -#define CMD_GET_ABM_TMR 0xD7 -#define CMD_SET_AMB_LVL0 0xD8 -#define CMD_GET_AMB_LVL0 0xD9 -#define CMD_SET_AMB_LVL1 0xDA -#define CMD_GET_AMB_LVL1 0xDB -#define CMD_SET_AMB_LVL2 0xDC -#define CMD_GET_AMB_LVL2 0xDD -#define CMD_SET_AMB_LVL3 0xDE -#define CMD_GET_AMB_LVL3 0xDF -#define CMD_PLL_START 0xE0 //start the PLL -#define CMD_PLL_STOP 0xE1 //disable the PLL -#define CMD_SET_PLL_MN 0xE2 -#define CMD_GET_PLL_MN 0xE3 -#define CMD_GET_PLL_STATUS 0xE4 //get the current PLL status -#define CMD_ENT_DEEP_SLEEP 0xE5 -#define CMD_SET_PCLK 0xE6 //set pixel clock (LSHIFT signal) frequency -#define CMD_GET_PCLK 0xE7 //get pixel clock (LSHIFT signal) freq. settings -#define CMD_SET_DATA_INTERFACE 0xF0 -#define CMD_GET_DATA_INTERFACE 0xF1 - - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -void ssd1963_init(void); -void ssd1963_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); - -/********************** - * MACROS - **********************/ - -#endif /* USE_SSD1963 */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* SSD1963_H */ diff --git a/lib/lv_drivers/display/ST7565.c b/lib/lv_drivers/display/ST7565.c deleted file mode 100644 index e4eac4b2..00000000 --- a/lib/lv_drivers/display/ST7565.c +++ /dev/null @@ -1,289 +0,0 @@ -/** - * @file ST7565.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "ST7565.h" -#if USE_ST7565 - -#include -#include -#include -#include "lvgl/lv_core/lv_vdb.h" -#include LV_DRV_DISP_INCLUDE -#include LV_DRV_DELAY_INCLUDE - -/********************* - * DEFINES - *********************/ -#define ST7565_BAUD 2000000 /*< 2,5 MHz (400 ns)*/ - -#define ST7565_CMD_MODE 0 -#define ST7565_DATA_MODE 1 - -#define ST7565_HOR_RES 128 -#define ST7565_VER_RES 64 - -#define CMD_DISPLAY_OFF 0xAE -#define CMD_DISPLAY_ON 0xAF - -#define CMD_SET_DISP_START_LINE 0x40 -#define CMD_SET_PAGE 0xB0 - -#define CMD_SET_COLUMN_UPPER 0x10 -#define CMD_SET_COLUMN_LOWER 0x00 - -#define CMD_SET_ADC_NORMAL 0xA0 -#define CMD_SET_ADC_REVERSE 0xA1 - -#define CMD_SET_DISP_NORMAL 0xA6 -#define CMD_SET_DISP_REVERSE 0xA7 - -#define CMD_SET_ALLPTS_NORMAL 0xA4 -#define CMD_SET_ALLPTS_ON 0xA5 -#define CMD_SET_BIAS_9 0xA2 -#define CMD_SET_BIAS_7 0xA3 - -#define CMD_RMW 0xE0 -#define CMD_RMW_CLEAR 0xEE -#define CMD_INTERNAL_RESET 0xE2 -#define CMD_SET_COM_NORMAL 0xC0 -#define CMD_SET_COM_REVERSE 0xC8 -#define CMD_SET_POWER_CONTROL 0x28 -#define CMD_SET_RESISTOR_RATIO 0x20 -#define CMD_SET_VOLUME_FIRST 0x81 -#define CMD_SET_VOLUME_SECOND 0x00 -#define CMD_SET_STATIC_OFF 0xAC -#define CMD_SET_STATIC_ON 0xAD -#define CMD_SET_STATIC_REG 0x00 -#define CMD_SET_BOOSTER_FIRST 0xF8 -#define CMD_SET_BOOSTER_234 0x00 -#define CMD_SET_BOOSTER_5 0x01 -#define CMD_SET_BOOSTER_6 0x03 -#define CMD_NOP 0xE3 -#define CMD_TEST 0xF0 - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ -static void st7565_sync(int32_t x1, int32_t y1, int32_t x2, int32_t y2); -static void st7565_command(uint8_t cmd); -static void st7565_data(uint8_t data); - -/********************** - * STATIC VARIABLES - **********************/ -static uint8_t lcd_fb[ST7565_HOR_RES * ST7565_VER_RES / 8] = {0xAA, 0xAA}; -static uint8_t pagemap[] = { 7, 6, 5, 4, 3, 2, 1, 0 }; - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Initialize the ST7565 - */ -void st7565_init(void) -{ - LV_DRV_DISP_RST(1); - LV_DRV_DELAY_MS(10); - LV_DRV_DISP_RST(0); - LV_DRV_DELAY_MS(10); - LV_DRV_DISP_RST(1); - LV_DRV_DELAY_MS(10); - - LV_DRV_DISP_SPI_CS(0); - - st7565_command(CMD_SET_BIAS_7); - st7565_command(CMD_SET_ADC_NORMAL); - st7565_command(CMD_SET_COM_NORMAL); - st7565_command(CMD_SET_DISP_START_LINE); - st7565_command(CMD_SET_POWER_CONTROL | 0x4); - LV_DRV_DELAY_MS(50); - - st7565_command(CMD_SET_POWER_CONTROL | 0x6); - LV_DRV_DELAY_MS(50); - - st7565_command(CMD_SET_POWER_CONTROL | 0x7); - LV_DRV_DELAY_MS(10); - - st7565_command(CMD_SET_RESISTOR_RATIO | 0x6); // Defaulted to 0x26 (but could also be between 0x20-0x27 based on display's specs) - - st7565_command(CMD_DISPLAY_ON); - st7565_command(CMD_SET_ALLPTS_NORMAL); - - /*Set brightness*/ - st7565_command(CMD_SET_VOLUME_FIRST); - st7565_command(CMD_SET_VOLUME_SECOND | (0x18 & 0x3f)); - - LV_DRV_DISP_SPI_CS(1); - - memset(lcd_fb, 0x00, sizeof(lcd_fb)); -} - - -void st7565_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) -{ - /*Return if the area is out the screen*/ - if(x2 < 0) return; - if(y2 < 0) return; - if(x1 > ST7565_HOR_RES - 1) return; - if(y1 > ST7565_VER_RES - 1) return; - - /*Truncate the area to the screen*/ - int32_t act_x1 = x1 < 0 ? 0 : x1; - int32_t act_y1 = y1 < 0 ? 0 : y1; - int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2; - int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2; - - int32_t x, y; - - /*Set the first row in */ - - /*Refresh frame buffer*/ - for(y = act_y1; y <= act_y2; y++) { - for(x = act_x1; x <= act_x2; x++) { - if(lv_color_to1(*color_p) != 0) { - lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8))); - } else { - lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8))); - } - color_p ++; - } - - color_p += x2 - act_x2; /*Next row*/ - } - - st7565_sync(act_x1, act_y1, act_x2, act_y2); - lv_flush_ready(); -} - - - -void st7565_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color) -{ - /*Return if the area is out the screen*/ - if(x2 < 0) return; - if(y2 < 0) return; - if(x1 > ST7565_HOR_RES - 1) return; - if(y1 > ST7565_VER_RES - 1) return; - - /*Truncate the area to the screen*/ - int32_t act_x1 = x1 < 0 ? 0 : x1; - int32_t act_y1 = y1 < 0 ? 0 : y1; - int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2; - int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2; - - int32_t x, y; - uint8_t white = lv_color_to1(color); - - /*Refresh frame buffer*/ - for(y = act_y1; y <= act_y2; y++) { - for(x = act_x1; x <= act_x2; x++) { - if(white != 0) { - lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8))); - } else { - lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8))); - } - } - } - - st7565_sync(act_x1, act_y1, act_x2, act_y2); -} - -void st7565_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) -{ - /*Return if the area is out the screen*/ - if(x2 < 0) return; - if(y2 < 0) return; - if(x1 > ST7565_HOR_RES - 1) return; - if(y1 > ST7565_VER_RES - 1) return; - - /*Truncate the area to the screen*/ - int32_t act_x1 = x1 < 0 ? 0 : x1; - int32_t act_y1 = y1 < 0 ? 0 : y1; - int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2; - int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2; - - int32_t x, y; - - /*Set the first row in */ - - /*Refresh frame buffer*/ - for(y = act_y1; y <= act_y2; y++) { - for(x = act_x1; x <= act_x2; x++) { - if(lv_color_to1(*color_p) != 0) { - lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8))); - } else { - lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8))); - } - color_p ++; - } - - color_p += x2 - act_x2; /*Next row*/ - } - - st7565_sync(act_x1, act_y1, act_x2, act_y2); -} -/********************** - * STATIC FUNCTIONS - **********************/ -/** - * Flush a specific part of the buffer to the display - * @param x1 left coordinate of the area to flush - * @param y1 top coordinate of the area to flush - * @param x2 right coordinate of the area to flush - * @param y2 bottom coordinate of the area to flush - */ -static void st7565_sync(int32_t x1, int32_t y1, int32_t x2, int32_t y2) -{ - - LV_DRV_DISP_SPI_CS(0); - - uint8_t c, p; - for(p = y1 / 8; p <= y2 / 8; p++) { - st7565_command(CMD_SET_PAGE | pagemap[p]); - st7565_command(CMD_SET_COLUMN_LOWER | (x1 & 0xf)); - st7565_command(CMD_SET_COLUMN_UPPER | ((x1 >> 4) & 0xf)); - st7565_command(CMD_RMW); - - for(c = x1; c <= x2; c++) { - st7565_data(lcd_fb[(ST7565_HOR_RES * p) + c]); - } - } - - LV_DRV_DISP_SPI_CS(1); -} - -/** - * Write a command to the ST7565 - * @param cmd the command - */ -static void st7565_command(uint8_t cmd) -{ - LV_DRV_DISP_CMD_DATA(ST7565_CMD_MODE); - LV_DRV_DISP_SPI_WR_BYTE(cmd); -} - -/** - * Write data to the ST7565 - * @param data the data - */ -static void st7565_data(uint8_t data) -{ - LV_DRV_DISP_CMD_DATA(ST7565_DATA_MODE); - LV_DRV_DISP_SPI_WR_BYTE(data); -} - -#endif diff --git a/lib/lv_drivers/display/ST7565.h b/lib/lv_drivers/display/ST7565.h deleted file mode 100644 index 1a96df43..00000000 --- a/lib/lv_drivers/display/ST7565.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @file ST7565.h - * - */ - -#ifndef ST7565_H -#define ST7565_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_ST7565 - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -void st7565_init(void); -void st7565_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); -void st7565_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); -void st7565_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); - -/********************** - * MACROS - **********************/ - -#endif /* USE_ST7565 */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ST7565_H */ diff --git a/lib/lv_drivers/display/UC1610.c b/lib/lv_drivers/display/UC1610.c deleted file mode 100644 index b678277c..00000000 --- a/lib/lv_drivers/display/UC1610.c +++ /dev/null @@ -1,206 +0,0 @@ -/** - * @file UC1610.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "UC1610.h" - -#if USE_UC1610 - -#include -#include LV_DRV_DISP_INCLUDE -#include LV_DRV_DELAY_INCLUDE - -/********************* - * DEFINES - *********************/ -#define UC1610_CMD_MODE 0 -#define UC1610_DATA_MODE 1 -#define UC1610_RESET_MODE 0 -#define UC1610_SET_MODE 1 - -/* hardware control commands */ -#define UC1610_SYSTEM_RESET 0xE2 /* software reset */ -#define UC1610_NOP 0xE3 -#define UC1610_SET_TEMP_COMP 0x24 /* set temperature compensation, default -0.05%/°C */ -#define UC1610_SET_PANEL_LOADING 0x29 /* set panel loading, default 16~21 nF */ -#define UC1610_SET_PUMP_CONTROL 0x2F /* default internal Vlcd (8x pump) */ -#define UC1610_SET_LCD_BIAS_RATIO 0xEB /* default 11 */ -#define UC1610_SET_VBIAS_POT 0x81 /* 1 byte (0~255) to follow setting the contrast, default 0x81 */ -#define UC1610_SET_LINE_RATE 0xA0 /* default 12,1 Klps */ -#define UC1610_SET_DISPLAY_ENABLE 0xAE /* + 1 / 0 : exit sleep mode / entering sleep mode */ -#define UC1610_SET_LCD_GRAY_SHADE 0xD0 /* default 24% between the two gray shade levels */ -#define UC1610_SET_COM_END 0xF1 /* set the number of used com electrodes (lines number -1) */ - -/* ram address control */ -#define UC1610_SET_AC 0x88 /* set ram address control */ -#define UC1610_AC_WA_FLAG 1 /* automatic column/page increment wrap around (1 : cycle increment) */ -#define UC1610_AC_AIO_FLAG (1 << 1) /* auto increment order (0/1 : column/page increment first) */ -#define UC1610_AC_PID_FLAG (1 << 2) /* page address auto increment order (0/1 : +1/-1) */ - -/* set cursor ram address */ -#define UC1610_SET_CA_LSB 0x00 /* + 4 LSB bits */ -#define UC1610_SET_CA_MSB 0x10 /* + 4 MSB bits // MSB + LSB values range : 0~159 */ -#define UC1610_SET_PA 0x60 /* + 5 bits // values range : 0~26 */ - -/* display control commands */ -#define UC1610_SET_FIXED_LINES 0x90 /* + 4 bits = 2xFL */ -#define UC1610_SET_SCROLL_LINES_LSB 0x40 /* + 4 LSB bits scroll up display by N (7 bits) lines */ -#define UC1610_SET_SCROLL_LINES_MSB 0x50 /* + 3 MSB bits */ -#define UC1610_SET_ALL_PIXEL_ON 0xA4 /* + 1 / 0 : set all pixel on, reverse */ -#define UC1610_SET_INVERSE_DISPLAY 0xA6 /* + 1 / 0 : inverse all data stored in ram, reverse */ -#define UC1610_SET_MAPPING_CONTROL 0xC0 /* control mirorring */ -#define UC1610_SET_MAPPING_CONTROL_LC_FLAG 1 -#define UC1610_SET_MAPPING_CONTROL_MX_FLAG (1 << 1) -#define UC1610_SET_MAPPING_CONTROL_MY_FLAG (1 << 2) - -/* window program mode */ -#define UC1610_SET_WINDOW_PROGRAM_ENABLE 0xF8 /* + 1 / 0 : enable / disable window programming mode, */ - /* reset before changing boundaries */ -#define UC1610_SET_WP_STARTING_CA 0xF4 /* 1 byte to follow for column address */ -#define UC1610_SET_WP_ENDING_CA 0xF6 /* 1 byte to follow for column address */ -#define UC1610_SET_WP_STARTING_PA 0xF5 /* 1 byte to follow for page address */ -#define UC1610_SET_WP_ENDING_PA 0xF7 /* 1 byte to follow for page address */ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ -static uint8_t cmd_buf[12]; - -/********************** - * MACROS - **********************/ - -/* Return the byte bitmask of a pixel color corresponding to VDB arrangement */ -#define PIXIDX(y, c) ((c) << (((y) & 3) << 1)) - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void uc1610_init(void) { - LV_DRV_DELAY_MS(12); - - /* initialization sequence */ -#if UC1610_INIT_HARD_RST - LV_DRV_DISP_RST(UC1610_RESET_MODE); /* hardware reset */ - LV_DRV_DELAY_MS(1); - LV_DRV_DISP_RST(UC1610_SET_MODE); -#else - cmd_buf[0] = UC1610_SYSTEM_RESET; /* software reset */ - LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE); - LV_DRV_DISP_SPI_CS(0); - LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 1); - LV_DRV_DISP_SPI_CS(1); -#endif - - LV_DRV_DELAY_MS(2); - cmd_buf[0] = UC1610_SET_COM_END; /* set com end value */ - cmd_buf[1] = UC1610_VER_RES - 1; - cmd_buf[2] = UC1610_SET_PANEL_LOADING; - cmd_buf[3] = UC1610_SET_LCD_BIAS_RATIO; - cmd_buf[4] = UC1610_SET_VBIAS_POT; /* set contrast */ - cmd_buf[5] = (UC1610_INIT_CONTRAST * 255) / 100; -#if UC1610_TOP_VIEW - cmd_buf[6] = UC1610_SET_MAPPING_CONTROL | /* top view */ - UC1610_SET_MAPPING_CONTROL_MY_FLAG | - UC1610_SET_MAPPING_CONTROL_MX_FLAG; -#else - cmd_buf[6] = UC1610_SET_MAPPING_CONTROL; /* bottom view */ -#endif - cmd_buf[7] = UC1610_SET_SCROLL_LINES_LSB | 0; /* set scroll line on line 0 */ - cmd_buf[8] = UC1610_SET_SCROLL_LINES_MSB | 0; - cmd_buf[9] = UC1610_SET_AC | UC1610_AC_WA_FLAG; /* set auto increment wrap around */ - cmd_buf[10] = UC1610_SET_INVERSE_DISPLAY | 1; /* invert colors to complies lv color system */ - cmd_buf[11] = UC1610_SET_DISPLAY_ENABLE | 1; /* turn display on */ - - LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE); - LV_DRV_DISP_SPI_CS(0); - LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 12); - LV_DRV_DISP_SPI_CS(1); -} - - -void uc1610_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { - /*Return if the area is out the screen*/ - if(area->x2 < 0) return; - if(area->y2 < 0) return; - if(area->x1 > UC1610_HOR_RES - 1) return; - if(area->y1 > UC1610_VER_RES - 1) return; - - /*Truncate the area to the screen*/ - uint8_t act_x1 = area->x1 < 0 ? 0 : area->x1; - uint8_t act_y1 = area->y1 < 0 ? 0 : area->y1; - uint8_t act_x2 = area->x2 > UC1610_HOR_RES - 1 ? UC1610_HOR_RES - 1 : area->x2; - uint8_t act_y2 = area->y2 > UC1610_VER_RES - 1 ? UC1610_VER_RES - 1 : area->y2; - - uint8_t * buf = (uint8_t *) color_p; - uint16_t buf_size = (act_x2 - act_x1 + 1) * (((act_y2 - act_y1) >> 2) + 1); - - /*Set display window to fill*/ - cmd_buf[0] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 0; /* before changing boundaries */ - cmd_buf[1] = UC1610_SET_WP_STARTING_CA; - cmd_buf[2] = act_x1; - cmd_buf[3] = UC1610_SET_WP_ENDING_CA; - cmd_buf[4] = act_x2; - cmd_buf[5] = UC1610_SET_WP_STARTING_PA; - cmd_buf[6] = act_y1 >> 2; - cmd_buf[7] = UC1610_SET_WP_ENDING_PA; - cmd_buf[8] = act_y2 >> 2; - cmd_buf[9] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 1; /* entering window programming */ - - LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE); - LV_DRV_DISP_SPI_CS(0); - LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 10); - LV_DRV_DISP_SPI_CS(1); - - /*Flush VDB on display memory*/ - LV_DRV_DISP_CMD_DATA(UC1610_DATA_MODE); - LV_DRV_DISP_SPI_CS(0); - LV_DRV_DISP_SPI_WR_ARRAY(buf, buf_size); - LV_DRV_DISP_SPI_CS(1); - - lv_disp_flush_ready(disp_drv); -} - -void uc1610_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) { - (void) disp_drv; - (void) opa; - - uint16_t idx = x + buf_w * (y >> 2); - - /* Convert color to depth 2 */ -#if LV_COLOR_DEPTH == 1 - uint8_t color2 = color.full * 3; -#else - uint8_t color2 = color.full >> (LV_COLOR_DEPTH - 2); -#endif - - buf[idx] &= ~PIXIDX(y, 3); /* reset pixel color */ - buf[idx] |= PIXIDX(y, color2); /* write new color */ -} - -void uc1610_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area) { - (void) disp_drv; - - /* Round y window to display memory page size */ - area->y1 = (area->y1 & (~3)); - area->y2 = (area->y2 & (~3)) + 3; -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -#endif diff --git a/lib/lv_drivers/display/UC1610.h b/lib/lv_drivers/display/UC1610.h deleted file mode 100644 index 38b1fa3c..00000000 --- a/lib/lv_drivers/display/UC1610.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @file UC1610.h - * - */ - -#ifndef UC1610_H -#define UC1610_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_UC1610 - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -void uc1610_init(void); -void uc1610_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); -void uc1610_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area); -void uc1610_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); - -/********************** - * MACROS - **********************/ - -#endif /* USE_UC1610 */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UC1610_H */ diff --git a/lib/lv_drivers/display/display.mk b/lib/lv_drivers/display/display.mk deleted file mode 100644 index d0255920..00000000 --- a/lib/lv_drivers/display/display.mk +++ /dev/null @@ -1,12 +0,0 @@ -CSRCS += fbdev.c -CSRCS += monitor.c -CSRCS += R61581.c -CSRCS += SSD1963.c -CSRCS += ST7565.c -CSRCS += UC1610.c -CSRCS += SHARP_MIP.c - -DEPPATH += --dep-path $(LVGL_DIR)/lv_drivers/display -VPATH += :$(LVGL_DIR)/lv_drivers/display - -CFLAGS += "-I$(LVGL_DIR)/lv_drivers/display" diff --git a/lib/lv_drivers/display/fbdev.c b/lib/lv_drivers/display/fbdev.c deleted file mode 100644 index 14c6cf14..00000000 --- a/lib/lv_drivers/display/fbdev.c +++ /dev/null @@ -1,241 +0,0 @@ -/** - * @file fbdev.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "fbdev.h" -#if USE_FBDEV || USE_BSD_FBDEV - -#include -#include -#include -#include -#include -#include -#include - -#if USE_BSD_FBDEV -#include -#include -#include -#include -#else /* USE_BSD_FBDEV */ -#include -#endif /* USE_BSD_FBDEV */ - -/********************* - * DEFINES - *********************/ -#ifndef FBDEV_PATH -#define FBDEV_PATH "/dev/fb0" -#endif - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STRUCTURES - **********************/ - -struct bsd_fb_var_info{ - uint32_t xoffset; - uint32_t yoffset; - uint32_t xres; - uint32_t yres; - int bits_per_pixel; - }; - -struct bsd_fb_fix_info{ - long int line_length; -}; - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ -#if USE_BSD_FBDEV -static struct bsd_fb_var_info vinfo; -static struct bsd_fb_fix_info finfo; -#else -static struct fb_var_screeninfo vinfo; -static struct fb_fix_screeninfo finfo; -#endif /* USE_BSD_FBDEV */ -static char *fbp = 0; -static long int screensize = 0; -static int fbfd = 0; - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void fbdev_init(void) -{ - // Open the file for reading and writing - fbfd = open(FBDEV_PATH, O_RDWR); - if(fbfd == -1) { - perror("Error: cannot open framebuffer device"); - return; - } - printf("The framebuffer device was opened successfully.\n"); - -#if USE_BSD_FBDEV - struct fbtype fb; - unsigned line_length; - - //Get fb type - if (ioctl(fbfd, FBIOGTYPE, &fb) != 0) { - perror("ioctl(FBIOGTYPE)"); - return; - } - - //Get screen width - if (ioctl(fbfd, FBIO_GETLINEWIDTH, &line_length) != 0) { - perror("ioctl(FBIO_GETLINEWIDTH)"); - return; - } - - vinfo.xres = (unsigned) fb.fb_width; - vinfo.yres = (unsigned) fb.fb_height; - vinfo.bits_per_pixel = fb.fb_depth + 8; - vinfo.xoffset = 0; - vinfo.yoffset = 0; - finfo.line_length = line_length; -#else /* USE_BSD_FBDEV */ - - // Get fixed screen information - if(ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) { - perror("Error reading fixed information"); - return; - } - - // Get variable screen information - if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) { - perror("Error reading variable information"); - return; - } -#endif /* USE_BSD_FBDEV */ - - printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); - - // Figure out the size of the screen in bytes - screensize = finfo.smem_len; //finfo.line_length * vinfo.yres; - - // Map the device to memory - fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); - if((intptr_t)fbp == -1) { - perror("Error: failed to map framebuffer device to memory"); - return; - } - memset(fbp, 0, screensize); - - printf("The framebuffer device was mapped to memory successfully.\n"); - -} - -void fbdev_exit(void) -{ - close(fbfd); -} - -/** - * Flush a buffer to the marked area - * @param drv pointer to driver where this function belongs - * @param area an area where to copy `color_p` - * @param color_p an array of pixel to copy to the `area` part of the screen - */ -void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p) -{ - if(fbp == NULL || - area->x2 < 0 || - area->y2 < 0 || - area->x1 > (int32_t)vinfo.xres - 1 || - area->y1 > (int32_t)vinfo.yres - 1) { - lv_disp_flush_ready(drv); - return; - } - - /*Truncate the area to the screen*/ - int32_t act_x1 = area->x1 < 0 ? 0 : area->x1; - int32_t act_y1 = area->y1 < 0 ? 0 : area->y1; - int32_t act_x2 = area->x2 > (int32_t)vinfo.xres - 1 ? (int32_t)vinfo.xres - 1 : area->x2; - int32_t act_y2 = area->y2 > (int32_t)vinfo.yres - 1 ? (int32_t)vinfo.yres - 1 : area->y2; - - - lv_coord_t w = lv_area_get_width(area); - long int location = 0; - long int byte_location = 0; - unsigned char bit_location = 0; - - /*32 or 24 bit per pixel*/ - if(vinfo.bits_per_pixel == 32 || vinfo.bits_per_pixel == 24) { - uint32_t * fbp32 = (uint32_t *)fbp; - int32_t y; - for(y = act_y1; y <= act_y2; y++) { - location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 4; - memcpy(&fbp32[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 4); - color_p += w; - } - } - /*16 bit per pixel*/ - else if(vinfo.bits_per_pixel == 16) { - uint16_t * fbp16 = (uint16_t *)fbp; - int32_t y; - for(y = act_y1; y <= act_y2; y++) { - location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 2; - memcpy(&fbp16[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 2); - color_p += w; - } - } - /*8 bit per pixel*/ - else if(vinfo.bits_per_pixel == 8) { - uint8_t * fbp8 = (uint8_t *)fbp; - int32_t y; - for(y = act_y1; y <= act_y2; y++) { - location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length; - memcpy(&fbp8[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1)); - color_p += w; - } - } - /*1 bit per pixel*/ - else if(vinfo.bits_per_pixel == 1) { - uint8_t * fbp8 = (uint8_t *)fbp; - int32_t x; - int32_t y; - for(y = act_y1; y <= act_y2; y++) { - for(x = act_x1; x <= act_x2; x++) { - location = (x + vinfo.xoffset) + (y + vinfo.yoffset) * vinfo.xres; - byte_location = location / 8; /* find the byte we need to change */ - bit_location = location % 8; /* inside the byte found, find the bit we need to change */ - fbp8[byte_location] &= ~(((uint8_t)(1)) << bit_location); - fbp8[byte_location] |= ((uint8_t)(color_p->full)) << bit_location; - color_p++; - } - - color_p += area->x2 - act_x2; - } - } else { - /*Not supported bit per pixel*/ - } - - //May be some direct update command is required - //ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect)); - - lv_disp_flush_ready(drv); -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -#endif diff --git a/lib/lv_drivers/display/fbdev.h b/lib/lv_drivers/display/fbdev.h deleted file mode 100644 index 9f0e2d5c..00000000 --- a/lib/lv_drivers/display/fbdev.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @file fbdev.h - * - */ - -#ifndef FBDEV_H -#define FBDEV_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_FBDEV || USE_BSD_FBDEV - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -void fbdev_init(void); -void fbdev_exit(void); -void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p); - - -/********************** - * MACROS - **********************/ - -#endif /*USE_FBDEV*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /*FBDEV_H*/ diff --git a/lib/lv_drivers/display/monitor.c b/lib/lv_drivers/display/monitor.c deleted file mode 100644 index 491646b4..00000000 --- a/lib/lv_drivers/display/monitor.c +++ /dev/null @@ -1,415 +0,0 @@ -/** - * @file monitor.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "monitor.h" -#if USE_MONITOR - -#ifndef MONITOR_SDL_INCLUDE_PATH -# define MONITOR_SDL_INCLUDE_PATH -#endif - -#include -#include -#include -#include MONITOR_SDL_INCLUDE_PATH -#include "../indev/mouse.h" -#include "../indev/keyboard.h" -#include "../indev/mousewheel.h" - -/********************* - * DEFINES - *********************/ -#define SDL_REFR_PERIOD 50 /*ms*/ - -#ifndef MONITOR_ZOOM -#define MONITOR_ZOOM 1 -#endif - -#ifndef MONITOR_HOR_RES -#define MONITOR_HOR_RES LV_HOR_RES -#endif - -#ifndef MONITOR_VER_RES -#define MONITOR_VER_RES LV_VER_RES -#endif - -#if defined(__APPLE__) && defined(TARGET_OS_MAC) -# if __APPLE__ && TARGET_OS_MAC -#define MONITOR_APPLE -# endif -#endif - -#if defined(__EMSCRIPTEN__) -# define MONITOR_EMSCRIPTEN -#endif - -/********************** - * TYPEDEFS - **********************/ -typedef struct { - SDL_Window * window; - SDL_Renderer * renderer; - SDL_Texture * texture; - volatile bool sdl_refr_qry; -#if MONITOR_DOUBLE_BUFFERED - uint32_t * tft_fb_act; -#else - uint32_t tft_fb[LV_HOR_RES_MAX * LV_VER_RES_MAX]; -#endif -}monitor_t; - -/********************** - * STATIC PROTOTYPES - **********************/ -static int monitor_sdl_refr_thread(void * param); -static void window_create(monitor_t * m); -static void window_update(monitor_t * m); - -/*********************** - * GLOBAL PROTOTYPES - ***********************/ - -/********************** - * STATIC VARIABLES - **********************/ -monitor_t monitor; - -#if MONITOR_DUAL -monitor_t monitor2; -#endif - -static volatile bool sdl_inited = false; -static volatile bool sdl_quit_qry = false; - -int quit_filter(void * userdata, SDL_Event * event); -static void monitor_sdl_clean_up(void); -static void monitor_sdl_init(void); -#ifdef MONITOR_EMSCRIPTEN -void monitor_sdl_refr_core(void); /* called from Emscripten loop */ -#else -static void monitor_sdl_refr_core(void); -#endif - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Initialize the monitor - */ -void monitor_init(void) -{ - /*OSX needs to initialize SDL here*/ -#if defined(MONITOR_APPLE) || defined(MONITOR_EMSCRIPTEN) - monitor_sdl_init(); -#endif - -#ifndef MONITOR_EMSCRIPTEN - SDL_CreateThread(monitor_sdl_refr_thread, "sdl_refr", NULL); - while(sdl_inited == false); /*Wait until 'sdl_refr' initializes the SDL*/ -#endif -} - -/** - * Flush a buffer to the marked area - * @param drv pointer to driver where this function belongs - * @param area an area where to copy `color_p` - * @param color_p an array of pixel to copy to the `area` part of the screen - */ -void monitor_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) -{ - lv_coord_t hres = disp_drv->rotated == 0 ? disp_drv->hor_res : disp_drv->ver_res; - lv_coord_t vres = disp_drv->rotated == 0 ? disp_drv->ver_res : disp_drv->hor_res; - -// printf("x1:%d,y1:%d,x2:%d,y2:%d\n", area->x1, area->y1, area->x2, area->y2); - - /*Return if the area is out the screen*/ - if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) { - - lv_disp_flush_ready(disp_drv); - return; - } - -#if MONITOR_DOUBLE_BUFFERED - monitor.tft_fb_act = (uint32_t *)color_p; - - monitor.sdl_refr_qry = true; - - /*IMPORTANT! It must be called to tell the system the flush is ready*/ - lv_disp_flush_ready(disp_drv); -#else - - int32_t y; -#if LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 /*32 is valid but support 24 for backward compatibility too*/ - int32_t x; - for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) { - for(x = area->x1; x <= area->x2; x++) { - monitor.tft_fb[y * disp_drv->hor_res + x] = lv_color_to32(*color_p); - color_p++; - } - - } -#else - uint32_t w = lv_area_get_width(area); - for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) { - memcpy(&monitor.tft_fb[y * MONITOR_HOR_RES + area->x1], color_p, w * sizeof(lv_color_t)); - color_p += w; - } -#endif - - monitor.sdl_refr_qry = true; - - /*IMPORTANT! It must be called to tell the system the flush is ready*/ - lv_disp_flush_ready(disp_drv); -#endif -} - - -#if MONITOR_DUAL - -/** - * Flush a buffer to the marked area - * @param drv pointer to driver where this function belongs - * @param area an area where to copy `color_p` - * @param color_p an array of pixel to copy to the `area` part of the screen - */ -void monitor_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) -{ - lv_coord_t hres = disp_drv->rotated == 0 ? disp_drv->hor_res : disp_drv->ver_res; - lv_coord_t vres = disp_drv->rotated == 0 ? disp_drv->ver_res : disp_drv->hor_res; - - /*Return if the area is out the screen*/ - if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) { - lv_disp_flush_ready(disp_drv); - return; - } - -#if MONITOR_DOUBLE_BUFFERED - monitor2.tft_fb_act = (uint32_t *)color_p; - - monitor2.sdl_refr_qry = true; - - /*IMPORTANT! It must be called to tell the system the flush is ready*/ - lv_disp_flush_ready(disp_drv); -#else - - int32_t y; -#if LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 /*32 is valid but support 24 for backward compatibility too*/ - int32_t x; - for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) { - for(x = area->x1; x <= area->x2; x++) { - monitor2.tft_fb[y * disp_drv->hor_res + x] = lv_color_to32(*color_p); - color_p++; - } - - } -#else - uint32_t w = lv_area_get_width(area); - for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) { - memcpy(&monitor2.tft_fb[y * disp_drv->hor_res + area->x1], color_p, w * sizeof(lv_color_t)); - color_p += w; - } -#endif - - monitor2.sdl_refr_qry = true; - - /*IMPORTANT! It must be called to tell the system the flush is ready*/ - lv_disp_flush_ready(disp_drv); -#endif -} -#endif - -/********************** - * STATIC FUNCTIONS - **********************/ - -/** - * SDL main thread. All SDL related task have to be handled here! - * It initializes SDL, handles drawing and the mouse. - */ - -static int monitor_sdl_refr_thread(void * param) -{ - (void)param; - - /*If not OSX initialize SDL in the Thread*/ -#ifndef MONITOR_APPLE - monitor_sdl_init(); -#endif - /*Run until quit event not arrives*/ - while(sdl_quit_qry == false) { - /*Refresh handling*/ - monitor_sdl_refr_core(); - } - - monitor_sdl_clean_up(); - exit(0); - - return 0; -} - -int quit_filter(void * userdata, SDL_Event * event) -{ - (void)userdata; - - if(event->type == SDL_WINDOWEVENT) { - if(event->window.event == SDL_WINDOWEVENT_CLOSE) { - sdl_quit_qry = true; - } - } - else if(event->type == SDL_QUIT) { - sdl_quit_qry = true; - } - - - - return 1; -} - -static void monitor_sdl_clean_up(void) -{ - SDL_DestroyTexture(monitor.texture); - SDL_DestroyRenderer(monitor.renderer); - SDL_DestroyWindow(monitor.window); - -#if MONITOR_DUAL - SDL_DestroyTexture(monitor2.texture); - SDL_DestroyRenderer(monitor2.renderer); - SDL_DestroyWindow(monitor2.window); - -#endif - - SDL_Quit(); -} - -static void monitor_sdl_init(void) -{ - /*Initialize the SDL*/ - SDL_Init(SDL_INIT_VIDEO); - - SDL_SetEventFilter(quit_filter, NULL); - - window_create(&monitor); -#if MONITOR_DUAL - window_create(&monitor2); - int x, y; - SDL_GetWindowPosition(monitor2.window, &x, &y); - SDL_SetWindowPosition(monitor.window, x + MONITOR_HOR_RES / 2 + 10, y); - SDL_SetWindowPosition(monitor2.window, x - MONITOR_HOR_RES / 2 - 10, y); -#endif - - sdl_inited = true; -} - -#ifdef MONITOR_EMSCRIPTEN -void monitor_sdl_refr_core(void) -#else -static void monitor_sdl_refr_core(void) -#endif -{ - - if(monitor.sdl_refr_qry != false) { - monitor.sdl_refr_qry = false; - window_update(&monitor); - } - -#if MONITOR_DUAL - if(monitor2.sdl_refr_qry != false) { - monitor2.sdl_refr_qry = false; - window_update(&monitor2); - } -#endif - -#if !defined(MONITOR_APPLE) && !defined(MONITOR_EMSCRIPTEN) - SDL_Event event; - while(SDL_PollEvent(&event)) { -#if USE_MOUSE != 0 - mouse_handler(&event); -#endif - -#if USE_MOUSEWHEEL != 0 - mousewheel_handler(&event); -#endif - -#if USE_KEYBOARD - keyboard_handler(&event); -#endif - if((&event)->type == SDL_WINDOWEVENT) { - switch((&event)->window.event) { -#if SDL_VERSION_ATLEAST(2, 0, 5) - case SDL_WINDOWEVENT_TAKE_FOCUS: -#endif - case SDL_WINDOWEVENT_EXPOSED: - window_update(&monitor); -#if MONITOR_DUAL - window_update(&monitor2); -#endif - break; - default: - break; - } - } - } -#endif /*MONITOR_APPLE*/ - - /*Sleep some time*/ - SDL_Delay(SDL_REFR_PERIOD); - -} - -static void window_create(monitor_t * m) -{ - m->window = SDL_CreateWindow("TFT Simulator", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - MONITOR_HOR_RES * MONITOR_ZOOM, MONITOR_VER_RES * MONITOR_ZOOM, 0); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/ - -#if MONITOR_VIRTUAL_MACHINE || defined(MONITOR_EMSCRIPTEN) - m->renderer = SDL_CreateRenderer(m->window, -1, SDL_RENDERER_SOFTWARE); -#else - m->renderer = SDL_CreateRenderer(m->window, -1, 0); -#endif - m->texture = SDL_CreateTexture(m->renderer, - SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, MONITOR_HOR_RES, MONITOR_VER_RES); - SDL_SetTextureBlendMode(m->texture, SDL_BLENDMODE_BLEND); - - /*Initialize the frame buffer to gray (77 is an empirical value) */ -#if MONITOR_DOUBLE_BUFFERED - SDL_UpdateTexture(m->texture, NULL, m->tft_fb_act, MONITOR_HOR_RES * sizeof(uint32_t)); -#else - memset(m->tft_fb, 0x44, MONITOR_HOR_RES * MONITOR_VER_RES * sizeof(uint32_t)); -#endif - - m->sdl_refr_qry = true; - -} - -static void window_update(monitor_t * m) -{ -#if MONITOR_DOUBLE_BUFFERED == 0 - SDL_UpdateTexture(m->texture, NULL, m->tft_fb, MONITOR_HOR_RES * sizeof(uint32_t)); -#else - if(m->tft_fb_act == NULL) return; - SDL_UpdateTexture(m->texture, NULL, m->tft_fb_act, MONITOR_HOR_RES * sizeof(uint32_t)); -#endif - SDL_RenderClear(m->renderer); - /*Test: Draw a background to test transparent screens (LV_COLOR_SCREEN_TRANSP)*/ - // SDL_SetRenderDrawColor(renderer, 0xff, 0, 0, 0xff); - // SDL_Rect r; - // r.x = 0; r.y = 0; r.w = MONITOR_HOR_RES; r.w = MONITOR_VER_RES; - // SDL_RenderDrawRect(renderer, &r); - - /*Update the renderer with the texture containing the rendered image*/ - SDL_RenderCopy(m->renderer, m->texture, NULL, NULL); - SDL_RenderPresent(m->renderer); -} - -#endif /*USE_MONITOR*/ diff --git a/lib/lv_drivers/display/monitor.h b/lib/lv_drivers/display/monitor.h deleted file mode 100644 index 6ef4d6d3..00000000 --- a/lib/lv_drivers/display/monitor.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @file monitor.h - * - */ - -#ifndef MONITOR_H -#define MONITOR_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_MONITOR - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -void monitor_init(void); -void monitor_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); -void monitor_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); - -/********************** - * MACROS - **********************/ - -#endif /* USE_MONITOR */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* MONITOR_H */ diff --git a/lib/lv_drivers/docs/astyle_c b/lib/lv_drivers/docs/astyle_c deleted file mode 100644 index 9b9d7f3c..00000000 --- a/lib/lv_drivers/docs/astyle_c +++ /dev/null @@ -1 +0,0 @@ ---style=kr --convert-tabs --indent=spaces=4 --indent-switches --pad-oper --unpad-paren --align-pointer=middle --suffix=.bak --lineend=linux --min-conditional-indent= diff --git a/lib/lv_drivers/docs/astyle_h b/lib/lv_drivers/docs/astyle_h deleted file mode 100644 index d9c76337..00000000 --- a/lib/lv_drivers/docs/astyle_h +++ /dev/null @@ -1 +0,0 @@ ---convert-tabs --indent=spaces=4 diff --git a/lib/lv_drivers/indev/AD_touch.c b/lib/lv_drivers/indev/AD_touch.c deleted file mode 100644 index c09c3593..00000000 --- a/lib/lv_drivers/indev/AD_touch.c +++ /dev/null @@ -1,383 +0,0 @@ -/** - * @file AD_touch.c - * - */ - -#include "AD_touch.h" - -#if USE_AD_TOUCH - -#include LV_DRV_INDEV_INCLUDE -#include LV_DRV_DELAY_INCLUDE - -#define SAMPLE_POINTS 4 - -#define CALIBRATIONINSET 20 // range 0 <= CALIBRATIONINSET <= 40 - -#define RESISTIVETOUCH_AUTO_SAMPLE_MODE -#define TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD 350 // between 0-0x03ff the lesser this value - - -// Current ADC values for X and Y channels -int16_t adcX = 0; -int16_t adcY = 0; -volatile unsigned int adcTC = 0; - -// coefficient values -volatile long _trA; -volatile long _trB; -volatile long _trC; -volatile long _trD; - -volatile int16_t xRawTouch[SAMPLE_POINTS] = {TOUCHCAL_ULX, TOUCHCAL_URX, TOUCHCAL_LRX, TOUCHCAL_LLX}; -volatile int16_t yRawTouch[SAMPLE_POINTS] = {TOUCHCAL_ULY, TOUCHCAL_URY, TOUCHCAL_LRY, TOUCHCAL_LLY}; - -#define TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR 8 - -// use this scale factor to avoid working in floating point numbers -#define SCALE_FACTOR (1 << TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR) - -typedef enum { - IDLE, //0 - SET_X, //1 - RUN_X, //2 - GET_X, //3 - RUN_CHECK_X, //4 - CHECK_X, //5 - SET_Y, //6 - RUN_Y, //7 - GET_Y, //8 - CHECK_Y, //9 - SET_VALUES, //10 - GET_POT, //11 - RUN_POT //12 -} TOUCH_STATES; - -volatile TOUCH_STATES state = IDLE; - -#define CAL_X_INSET (((GetMaxX() + 1) * (CALIBRATIONINSET >> 1)) / 100) -#define CAL_Y_INSET (((GetMaxY() + 1) * (CALIBRATIONINSET >> 1)) / 100) - -int stat; -int16_t temp_x, temp_y; - - -static int16_t TouchGetX(void); -static int16_t TouchGetRawX(void); -static int16_t TouchGetY(void); -static int16_t TouchGetRawY(void); -static int16_t TouchDetectPosition(void); -static void TouchCalculateCalPoints(void); - - -/********************************************************************/ -void ad_touch_init(void) -{ - // Initialize ADC for auto sampling mode - AD1CON1 = 0; // reset - AD1CON2 = 0; // AVdd, AVss, int every conversion, MUXA only - AD1CON3 = 0x1FFF; // 31 Tad auto-sample, Tad = 256*Tcy - AD1CON1 = 0x80E0; // Turn on A/D module, use auto-convert - - - ADPCFG_XPOS = RESISTIVETOUCH_ANALOG; - ADPCFG_YPOS = RESISTIVETOUCH_ANALOG; - - AD1CSSL = 0; // No scanned inputs - - state = SET_X; // set the state of the state machine to start the sampling - - /*Load calibration data*/ - xRawTouch[0] = TOUCHCAL_ULX; - yRawTouch[0] = TOUCHCAL_ULY; - xRawTouch[1] = TOUCHCAL_URX; - yRawTouch[1] = TOUCHCAL_URY; - xRawTouch[3] = TOUCHCAL_LLX; - yRawTouch[3] = TOUCHCAL_LLY; - xRawTouch[2] = TOUCHCAL_LRX; - yRawTouch[2] = TOUCHCAL_LRY; - - TouchCalculateCalPoints(); -} - -/*Use this in lv_indev_drv*/ -bool ad_touch_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) -{ - static int16_t last_x = 0; - static int16_t last_y = 0; - - int16_t x, y; - - x = TouchGetX(); - y = TouchGetY(); - - if((x > 0) && (y > 0)) { - data->point.x = x; - data->point.y = y; - last_x = data->point.x; - last_y = data->point.y; - data->state = LV_INDEV_STATE_PR; - } else { - data->point.x = last_x; - data->point.y = last_y; - data->state = LV_INDEV_STATE_REL; - } - - return false; -} - -/* Call periodically (e.g. in every 1 ms) to handle reading with ADC*/ -int16_t ad_touch_handler(void) -{ - static int16_t tempX, tempY; - int16_t temp; - - switch(state) { - case IDLE: - adcX = 0; - adcY = 0; - break; - - case SET_VALUES: - if(!TOUCH_ADC_DONE) - break; - if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD < (WORD)ADC1BUF0) { - adcX = 0; - adcY = 0; - } else { - adcX = tempX; - adcY = tempY; - } - state = SET_X; - return 1; // touch screen acquisition is done - - case SET_X: - TOUCH_ADC_INPUT_SEL = ADC_XPOS; - - ResistiveTouchScreen_XPlus_Config_As_Input(); - ResistiveTouchScreen_YPlus_Config_As_Input(); - ResistiveTouchScreen_XMinus_Config_As_Input(); - ResistiveTouchScreen_YMinus_Drive_Low(); - ResistiveTouchScreen_YMinus_Config_As_Output(); - - ADPCFG_YPOS = RESISTIVETOUCH_DIGITAL; // set to digital pin - ADPCFG_XPOS = RESISTIVETOUCH_ANALOG; // set to analog pin - - TOUCH_ADC_START = 1; // run conversion - state = CHECK_X; - break; - - case CHECK_X: - case CHECK_Y: - - if(TOUCH_ADC_DONE == 0) { - break; - } - - if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD > (WORD)ADC1BUF0) { - if(state == CHECK_X) { - ResistiveTouchScreen_YPlus_Drive_High(); - ResistiveTouchScreen_YPlus_Config_As_Output(); - tempX = 0; - state = RUN_X; - } else { - ResistiveTouchScreen_XPlus_Drive_High(); - ResistiveTouchScreen_XPlus_Config_As_Output(); - tempY = 0; - state = RUN_Y; - } - } else { - adcX = 0; - adcY = 0; - state = SET_X; - return 1; // touch screen acquisition is done - break; - } - - case RUN_X: - case RUN_Y: - TOUCH_ADC_START = 1; - state = (state == RUN_X) ? GET_X : GET_Y; - // no break needed here since the next state is either GET_X or GET_Y - break; - - case GET_X: - case GET_Y: - if(!TOUCH_ADC_DONE) - break; - - temp = ADC1BUF0; - if(state == GET_X) { - if(temp != tempX) { - tempX = temp; - state = RUN_X; - break; - } - } else { - if(temp != tempY) { - tempY = temp; - state = RUN_Y; - break; - } - } - - if(state == GET_X) - ResistiveTouchScreen_YPlus_Config_As_Input(); - else - ResistiveTouchScreen_XPlus_Config_As_Input(); - TOUCH_ADC_START = 1; - state = (state == GET_X) ? SET_Y : SET_VALUES; - break; - - case SET_Y: - if(!TOUCH_ADC_DONE) - break; - - if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD < (WORD)ADC1BUF0) { - adcX = 0; - adcY = 0; - state = SET_X; - return 1; // touch screen acquisition is done - break; - } - - TOUCH_ADC_INPUT_SEL = ADC_YPOS; - - ResistiveTouchScreen_XPlus_Config_As_Input(); - ResistiveTouchScreen_YPlus_Config_As_Input(); - ResistiveTouchScreen_XMinus_Drive_Low(); - ResistiveTouchScreen_XMinus_Config_As_Output(); - ResistiveTouchScreen_YMinus_Config_As_Input(); - - ADPCFG_YPOS = RESISTIVETOUCH_ANALOG; // set to analog pin - ADPCFG_XPOS = RESISTIVETOUCH_DIGITAL; // set to digital pin - TOUCH_ADC_START = 1; // run conversion - state = CHECK_Y; - break; - - default: - state = SET_X; - return 1; // touch screen acquisition is done - } - stat = state; - temp_x = adcX; - temp_y = adcY; - - return 0; // touch screen acquisition is not done -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -/********************************************************************/ -static int16_t TouchGetX(void) -{ - long result; - - result = TouchGetRawX(); - - if(result > 0) { - result = (long)((((long)_trC * result) + _trD) >> TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR); - - } - return ((int16_t)result); -} -/********************************************************************/ -static int16_t TouchGetRawX(void) -{ -#ifdef TOUCHSCREEN_RESISTIVE_SWAP_XY - return adcY; -#else - return adcX; -#endif -} - -/********************************************************************/ -static int16_t TouchGetY(void) -{ - - long result; - - result = TouchGetRawY(); - - if(result > 0) { - result = (long)((((long)_trA * result) + (long)_trB) >> TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR); - - } - return ((int16_t)result); -} - -/********************************************************************/ -static int16_t TouchGetRawY(void) -{ -#ifdef TOUCHSCREEN_RESISTIVE_SWAP_XY - return adcX; -#else - return adcY; -#endif -} - - -static void TouchCalculateCalPoints(void) -{ - long trA, trB, trC, trD; // variables for the coefficients - long trAhold, trBhold, trChold, trDhold; - long test1, test2; // temp variables (must be signed type) - - int16_t xPoint[SAMPLE_POINTS], yPoint[SAMPLE_POINTS]; - - yPoint[0] = yPoint[1] = CAL_Y_INSET; - yPoint[2] = yPoint[3] = (GetMaxY() - CAL_Y_INSET); - xPoint[0] = xPoint[3] = CAL_X_INSET; - xPoint[1] = xPoint[2] = (GetMaxX() - CAL_X_INSET); - - // calculate points transfer functiona - // based on two simultaneous equations solve for the - // constants - - // use sample points 1 and 4 - // Dy1 = aTy1 + b; Dy4 = aTy4 + b - // Dx1 = cTx1 + d; Dy4 = aTy4 + b - - test1 = (long)yPoint[0] - (long)yPoint[3]; - test2 = (long)yRawTouch[0] - (long)yRawTouch[3]; - - trA = ((long)((long)test1 * SCALE_FACTOR) / test2); - trB = ((long)((long)yPoint[0] * SCALE_FACTOR) - (trA * (long)yRawTouch[0])); - - test1 = (long)xPoint[0] - (long)xPoint[2]; - test2 = (long)xRawTouch[0] - (long)xRawTouch[2]; - - trC = ((long)((long)test1 * SCALE_FACTOR) / test2); - trD = ((long)((long)xPoint[0] * SCALE_FACTOR) - (trC * (long)xRawTouch[0])); - - trAhold = trA; - trBhold = trB; - trChold = trC; - trDhold = trD; - - // use sample points 2 and 3 - // Dy2 = aTy2 + b; Dy3 = aTy3 + b - // Dx2 = cTx2 + d; Dy3 = aTy3 + b - - test1 = (long)yPoint[1] - (long)yPoint[2]; - test2 = (long)yRawTouch[1] - (long)yRawTouch[2]; - - trA = ((long)(test1 * SCALE_FACTOR) / test2); - trB = ((long)((long)yPoint[1] * SCALE_FACTOR) - (trA * (long)yRawTouch[1])); - - test1 = (long)xPoint[1] - (long)xPoint[3]; - test2 = (long)xRawTouch[1] - (long)xRawTouch[3]; - - trC = ((long)((long)test1 * SCALE_FACTOR) / test2); - trD = ((long)((long)xPoint[1] * SCALE_FACTOR) - (trC * (long)xRawTouch[1])); - - // get the average and use the average - _trA = (trA + trAhold) >> 1; - _trB = (trB + trBhold) >> 1; - _trC = (trC + trChold) >> 1; - _trD = (trD + trDhold) >> 1; -} - -#endif diff --git a/lib/lv_drivers/indev/AD_touch.h b/lib/lv_drivers/indev/AD_touch.h deleted file mode 100644 index 7c07ab37..00000000 --- a/lib/lv_drivers/indev/AD_touch.h +++ /dev/null @@ -1,120 +0,0 @@ -/** - * @file AD_touch.h - * - */ - -#ifndef AD_TOUCH_H -#define AD_TOUCH_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_AD_TOUCH - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#define _SUPPRESS_PLIB_WARNING -#include - -#include "GenericTypeDefs.h" - -#define DISP_ORIENTATION 0 -#define DISP_HOR_RESOLUTION 320 -#define DISP_VER_RESOLUTION 240 - -/*GetMaxX Macro*/ -#if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270) -#define GetMaxX() (DISP_VER_RESOLUTION - 1) -#elif (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180) -#define GetMaxX() (DISP_HOR_RESOLUTION - 1) -#endif - -/*GetMaxY Macro*/ -#if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270) -#define GetMaxY() (DISP_HOR_RESOLUTION - 1) -#elif (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180) -#define GetMaxY() (DISP_VER_RESOLUTION - 1) -#endif - -/********************************************************************* - * HARDWARE PROFILE FOR THE RESISTIVE TOUCHSCREEN - *********************************************************************/ - -#define TOUCH_ADC_INPUT_SEL AD1CHS - -// ADC Sample Start -#define TOUCH_ADC_START AD1CON1bits.SAMP - -// ADC Status -#define TOUCH_ADC_DONE AD1CON1bits.DONE - -#define RESISTIVETOUCH_ANALOG 1 -#define RESISTIVETOUCH_DIGITAL 0 - -// ADC channel constants -#define ADC_XPOS ADC_CH0_POS_SAMPLEA_AN12 -#define ADC_YPOS ADC_CH0_POS_SAMPLEA_AN13 - -// ADC Port Control Bits -#define ADPCFG_XPOS AD1PCFGbits.PCFG12 //XR -#define ADPCFG_YPOS AD1PCFGbits.PCFG13 //YD - -// X port definitions -#define ResistiveTouchScreen_XPlus_Drive_High() LATBbits.LATB12 = 1 -#define ResistiveTouchScreen_XPlus_Drive_Low() LATBbits.LATB12 = 0 //LAT_XPOS -#define ResistiveTouchScreen_XPlus_Config_As_Input() TRISBbits.TRISB12 = 1 //TRIS_XPOS -#define ResistiveTouchScreen_XPlus_Config_As_Output() TRISBbits.TRISB12 = 0 - -#define ResistiveTouchScreen_XMinus_Drive_High() LATFbits.LATF0 = 1 -#define ResistiveTouchScreen_XMinus_Drive_Low() LATFbits.LATF0 = 0 //LAT_XNEG -#define ResistiveTouchScreen_XMinus_Config_As_Input() TRISFbits.TRISF0 = 1 //TRIS_XNEG -#define ResistiveTouchScreen_XMinus_Config_As_Output() TRISFbits.TRISF0 = 0 - -// Y port definitions -#define ResistiveTouchScreen_YPlus_Drive_High() LATBbits.LATB13 = 1 -#define ResistiveTouchScreen_YPlus_Drive_Low() LATBbits.LATB13 = 0 //LAT_YPOS -#define ResistiveTouchScreen_YPlus_Config_As_Input() TRISBbits.TRISB13 = 1 //TRIS_YPOS -#define ResistiveTouchScreen_YPlus_Config_As_Output() TRISBbits.TRISB13 = 0 - -#define ResistiveTouchScreen_YMinus_Drive_High() LATFbits.LATF1 = 1 -#define ResistiveTouchScreen_YMinus_Drive_Low() LATFbits.LATF1 = 0 //LAT_YNEG -#define ResistiveTouchScreen_YMinus_Config_As_Input() TRISFbits.TRISF1 = 1 //TRIS_YNEG -#define ResistiveTouchScreen_YMinus_Config_As_Output() TRISFbits.TRISF1 = 0 - -// Default calibration points -#define TOUCHCAL_ULX 0x0348 -#define TOUCHCAL_ULY 0x00CC -#define TOUCHCAL_URX 0x00D2 -#define TOUCHCAL_URY 0x00CE -#define TOUCHCAL_LLX 0x034D -#define TOUCHCAL_LLY 0x0335 -#define TOUCHCAL_LRX 0x00D6 -#define TOUCHCAL_LRY 0x032D - -void ad_touch_init(void); -bool ad_touch_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); -int16_t ad_touch_handler(void); - -#endif /* USE_AD_TOUCH */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* AD_TOUCH_H */ diff --git a/lib/lv_drivers/indev/FT5406EE8.c b/lib/lv_drivers/indev/FT5406EE8.c deleted file mode 100644 index e753a183..00000000 --- a/lib/lv_drivers/indev/FT5406EE8.c +++ /dev/null @@ -1,179 +0,0 @@ -/** - * @file FT5406EE8.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "FT5406EE8.h" -#if USE_FT5406EE8 - -#include -#include -#include LV_DRV_INDEV_INCLUDE -#include LV_DRV_DELAY_INCLUDE - -/********************* - * DEFINES - *********************/ - -#define I2C_WR_BIT 0x00 -#define I2C_RD_BIT 0x01 - -/*DEVICE MODES*/ -#define OPERAT_MD 0x00 -#define TEST_MD 0x04 -#define SYS_INF_MD 0x01 - -/*OPERATING MODE*/ -#define DEVICE_MODE 0x00 -#define GEST_ID 0x01 -#define TD_STATUS 0x02 - -#define FT5406EE8_FINGER_MAX 10 - -/*Register adresses*/ -#define FT5406EE8_REG_DEVICE_MODE 0x00 -#define FT5406EE8_REG_GEST_ID 0x01 -#define FT5406EE8_REG_TD_STATUS 0x02 -#define FT5406EE8_REG_YH 0x03 -#define FT5406EE8_REG_YL 0x04 -#define FT5406EE8_REG_XH 0x05 -#define FT5406EE8_REG_XL 0x06 - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -static bool ft5406ee8_get_touch_num(void); -static bool ft5406ee8_read_finger1(int16_t * x, int16_t * y); - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * - */ -void ft5406ee8_init(void) -{ - -} - -/** - * Get the current position and state of the touchpad - * @param data store the read data here - * @return false: because no ore data to be read - */ -bool ft5406ee8_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) -{ - static int16_t x_last; - static int16_t y_last; - int16_t x; - int16_t y; - bool valid = true; - - valid = ft5406ee8_get_touch_num(); - if(valid == true) { - valid = ft5406ee8_read_finger1(&x, &y); - } - - if(valid == true) { - x = (uint32_t)((uint32_t)x * 320) / 2048; - y = (uint32_t)((uint32_t)y * 240) / 2048; - - - x_last = x; - y_last = y; - } else { - x = x_last; - y = y_last; - } - - data->point.x = x; - data->point.y = y; - data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR; - return false; -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -static bool ft5406ee8_get_touch_num(void) -{ - bool ok = true; - uint8_t t_num = 0; - - LV_DRV_INDEV_I2C_START; - LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_WR_BIT); - LV_DRV_INDEV_I2C_WR(FT5406EE8_REG_TD_STATUS) - LV_DRV_INDEV_I2C_RESTART; - LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_RD_BIT); - t_num = LV_DRV_INDEV_I2C_READ(0); - - /* Error if not touched or too much finger */ - if(t_num > FT5406EE8_FINGER_MAX || t_num == 0) { - ok = false; - } - - return ok; -} - -/** - * Read the x and y coordinated - * @param x store the x coordinate here - * @param y store the y coordinate here - * @return false: not valid point; true: valid point - */ -static bool ft5406ee8_read_finger1(int16_t * x, int16_t * y) -{ - uint8_t temp_xH = 0; - uint8_t temp_xL = 0; - uint8_t temp_yH = 0; - uint8_t temp_yL = 0; - - /*Read Y High and low byte*/ - LV_DRV_INDEV_I2C_START; - LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_WR_BIT); - LV_DRV_INDEV_I2C_WR(FT5406EE8_REG_YH) - LV_DRV_INDEV_I2C_RESTART; - LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_RD_BIT); - temp_yH = LV_DRV_INDEV_I2C_READ(1); - temp_yL = LV_DRV_INDEV_I2C_READ(1); - - /*The upper two bit must be 2 on valid press*/ - if(((temp_yH >> 6) & 0xFF) != 2) { - (void) LV_DRV_INDEV_I2C_READ(0); /*Dummy read to close read sequence*/ - *x = 0; - *y = 0; - return false; - } - - /*Read X High and low byte*/ - temp_xH = LV_DRV_INDEV_I2C_READ(1); - temp_xL = LV_DRV_INDEV_I2C_READ(0); - - /*Save the result*/ - *x = (temp_xH & 0x0F) << 8; - *x += temp_xL; - *y = (temp_yH & 0x0F) << 8; - *y += temp_yL; - - return true; -} - -#endif diff --git a/lib/lv_drivers/indev/FT5406EE8.h b/lib/lv_drivers/indev/FT5406EE8.h deleted file mode 100644 index 2d1eda7d..00000000 --- a/lib/lv_drivers/indev/FT5406EE8.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file FT5406EE8.h - * - */ - -#ifndef FT5406EE8_H -#define FT5406EE8_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_FT5406EE8 - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -void ft5406ee8_init(void); -bool ft5406ee8_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); - -/********************** - * MACROS - **********************/ - -#endif /* USE_FT5406EE8 */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* FT5406EE8_H */ diff --git a/lib/lv_drivers/indev/XPT2046.cpp b/lib/lv_drivers/indev/XPT2046.cpp deleted file mode 100644 index 3edafa7f..00000000 --- a/lib/lv_drivers/indev/XPT2046.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/** - * @file XPT2046.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "XPT2046.h" -#if USE_XPT2046 - -#include -#include LV_DRV_INDEV_INCLUDE -#include LV_DRV_DELAY_INCLUDE -#include -#include "XPT2046_Touchscreen.h" - -/********************* - * DEFINES - *********************/ -#define CMD_X_READ 0b10010000 -#define CMD_Y_READ 0b11010000 - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ -static void xpt2046_corr(int16_t * x, int16_t * y); -static void xpt2046_avg(int16_t * x, int16_t * y); - -/********************** - * STATIC VARIABLES - **********************/ -int16_t avg_buf_x[XPT2046_AVG]; -int16_t avg_buf_y[XPT2046_AVG]; -uint8_t avg_last; -#if defined(STM32F407ZG) -#include "SoftSPI.h" -SoftSPI xpt2046_spi(PF11, PB2, PB0); -XPT2046_Touchscreen ts(PC13); -#else -SPIClass xpt2046_spi(PB15, PB14, PB13, PB12); -XPT2046_Touchscreen ts(PB12); -#endif -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Initialize the XPT2046 - */ -void xpt2046_init(uint8_t rotation) -{ - ts.begin(); - ts.setRotation(rotation); -} - -/** - * Get the current position and state of the touchpad - * @param data store the read data here - * @return false: because no ore data to be read - */ -bool xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) -{ - static int16_t last_x = 0; - static int16_t last_y = 0; - uint8_t buf; - - int16_t x = 0; - int16_t y = 0; - - // uint8_t irq = LV_DRV_INDEV_IRQ_READ; - data->state = ts.touched(); - - if(data->state) { - TS_Point p = ts.getPoint(); - x = p.x; - y = p.y; - xpt2046_corr(&x, &y); - -#if 0 - // LV_DRV_INDEV_SPI_CS(0); - xpt2046_spi.beginTransaction(SPI_SETTING); - digitalWrite(PB12, LOW); - - xpt2046_spi.transfer(CMD_X_READ); /*Start x read*/ - - buf = xpt2046_spi.transfer(0); /*Read x MSB*/ - x = buf << 8; - buf = xpt2046_spi.transfer(CMD_Y_READ); /*Until x LSB converted y command can be sent*/ - x += buf; - - buf = xpt2046_spi.transfer(0); /*Read y MSB*/ - y = buf << 8; - - buf = xpt2046_spi.transfer(0); /*Read y LSB*/ - y += buf; - - /*Normalize Data*/ - x = x >> 3; - y = y >> 3; - xpt2046_corr(&x, &y); - xpt2046_avg(&x, &y); - - last_x = x; - last_y = y; - data->state = LV_INDEV_STATE_PR; - - if(data->state) { - Serial.print(x); - Serial.print(" - "); - Serial.println(y); - } else { - Serial.print("."); - } - - // LV_DRV_INDEV_SPI_CS(1); - digitalWrite(PB12, HIGH); - xpt2046_spi.endTransaction(); -#endif - } else { - x = last_x; - y = last_y; - avg_last = 0; - data->state = LV_INDEV_STATE_REL; - } - - data->point.x = x; - data->point.y = y; - if(data->state) { - Serial.print(x); - Serial.print(" - "); - Serial.println(y); - } else { - // Serial.print("."); - } - - return false; -} - -/********************** - * STATIC FUNCTIONS - **********************/ -static void xpt2046_corr(int16_t * x, int16_t * y) -{ -#if XPT2046_XY_SWAP != 0 - int16_t swap_tmp; - swap_tmp = *x; - *x = *y; - *y = swap_tmp; -#endif - - if((*x) > XPT2046_X_MIN) - (*x) -= XPT2046_X_MIN; - else - (*x) = 0; - - if((*y) > XPT2046_Y_MIN) - (*y) -= XPT2046_Y_MIN; - else - (*y) = 0; - - (*x) = (uint32_t)((uint32_t)(*x) * XPT2046_HOR_RES) / (XPT2046_X_MAX - XPT2046_X_MIN); - - (*y) = (uint32_t)((uint32_t)(*y) * XPT2046_VER_RES) / (XPT2046_Y_MAX - XPT2046_Y_MIN); - -#if XPT2046_X_INV != 0 - (*x) = XPT2046_HOR_RES - (*x); -#endif - -#if XPT2046_Y_INV != 0 - (*y) = XPT2046_VER_RES - (*y); -#endif -} - -static void xpt2046_avg(int16_t * x, int16_t * y) -{ - /*Shift out the oldest data*/ - uint8_t i; - for(i = XPT2046_AVG - 1; i > 0; i--) { - avg_buf_x[i] = avg_buf_x[i - 1]; - avg_buf_y[i] = avg_buf_y[i - 1]; - } - - /*Insert the new point*/ - avg_buf_x[0] = *x; - avg_buf_y[0] = *y; - if(avg_last < XPT2046_AVG) avg_last++; - - /*Sum the x and y coordinates*/ - int32_t x_sum = 0; - int32_t y_sum = 0; - for(i = 0; i < avg_last; i++) { - x_sum += avg_buf_x[i]; - y_sum += avg_buf_y[i]; - } - - /*Normalize the sums*/ - (*x) = (int32_t)x_sum / avg_last; - (*y) = (int32_t)y_sum / avg_last; -} - -#endif diff --git a/lib/lv_drivers/indev/XPT2046.h b/lib/lv_drivers/indev/XPT2046.h deleted file mode 100644 index 7a8c047f..00000000 --- a/lib/lv_drivers/indev/XPT2046.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file XPT2046.h - * - */ - -#ifndef XPT2046_H -#define XPT2046_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_XPT2046 - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -void xpt2046_init(uint8_t rotation); -bool xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); - -/********************** - * MACROS - **********************/ - -#endif /* USE_XPT2046 */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* XPT2046_H */ diff --git a/lib/lv_drivers/indev/XPT2046_alt_drv.cpp b/lib/lv_drivers/indev/XPT2046_alt_drv.cpp deleted file mode 100644 index fab4ffcf..00000000 --- a/lib/lv_drivers/indev/XPT2046_alt_drv.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file XPT2046.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "XPT2046_alt_drv.h" -#if USE_XPT2046_ALT_DRV - -#include -#include LV_DRV_INDEV_INCLUDE -#include LV_DRV_DELAY_INCLUDE -#include - -/********************* - * DEFINES - *********************/ -#define CS_PIN PB12 - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ -XPT2046_Touchscreen ts(CS_PIN); - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Initialize the XPT2046 - */ -void xpt2046_alt_drv_init(uint8_t rotation) -{ - ts.begin(); - ts.setRotation(rotation); -} - -/** - * Get the current position and state of the touchpad - * @param data store the read data here - * @return false: because no more data to be read - */ -bool xpt2046_alt_drv_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) -{ - data->state = ts.touched(); - if(data->state) { - TS_Point p = ts.getPoint(); - data->point.x = p.x; - data->point.y = p.y; - Serial.print(p.x); - Serial.print(" - "); - Serial.println(p.y); - } - return false; -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -#endif diff --git a/lib/lv_drivers/indev/XPT2046_alt_drv.h b/lib/lv_drivers/indev/XPT2046_alt_drv.h deleted file mode 100644 index 7918ed68..00000000 --- a/lib/lv_drivers/indev/XPT2046_alt_drv.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file XPT2046_alt_drv.h - * - */ - -#ifndef XPT2046_ALT_DRV_H -#define XPT2046_ALT_DRV_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_XPT2046_ALT_DRV - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -void xpt2046_alt_drv_init(uint8_t rotation); -bool xpt2046_alt_drv_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); - -/********************** - * MACROS - **********************/ - -#endif /* USE_XPT2046_ALT_DRV */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* XPT2046_ALT_DRV_H */ diff --git a/lib/lv_drivers/indev/evdev.c b/lib/lv_drivers/indev/evdev.c deleted file mode 100644 index 9912e099..00000000 --- a/lib/lv_drivers/indev/evdev.c +++ /dev/null @@ -1,223 +0,0 @@ -/** - * @file evdev.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "evdev.h" -#if USE_EVDEV != 0 - -#include -#include -#include -#include - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ -int map(int x, int in_min, int in_max, int out_min, int out_max); - -/********************** - * STATIC VARIABLES - **********************/ -int evdev_fd; -int evdev_root_x; -int evdev_root_y; -int evdev_button; - -int evdev_key_val; - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Initialize the evdev interface - */ -void evdev_init(void) -{ - evdev_fd = open(EVDEV_NAME, O_RDWR | O_NOCTTY | O_NDELAY); - if(evdev_fd == -1) { - perror("unable open evdev interface:"); - return; - } - - fcntl(evdev_fd, F_SETFL, O_ASYNC | O_NONBLOCK); - - evdev_root_x = 0; - evdev_root_y = 0; - evdev_key_val = 0; - evdev_button = LV_INDEV_STATE_REL; -} -/** - * reconfigure the device file for evdev - * @param dev_name set the evdev device filename - * @return true: the device file set complete - * false: the device file doesn't exist current system - */ -bool evdev_set_file(char* dev_name) -{ - if(evdev_fd != -1) { - close(evdev_fd); - } - evdev_fd = open(dev_name, O_RDWR | O_NOCTTY | O_NDELAY); - - if(evdev_fd == -1) { - perror("unable open evdev interface:"); - return false; - } - - fcntl(evdev_fd, F_SETFL, O_ASYNC | O_NONBLOCK); - - evdev_root_x = 0; - evdev_root_y = 0; - evdev_key_val = 0; - evdev_button = LV_INDEV_STATE_REL; - - return true; -} -/** - * Get the current position and state of the evdev - * @param data store the evdev data here - * @return false: because the points are not buffered, so no more data to be read - */ -bool evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data) -{ - struct input_event in; - - while(read(evdev_fd, &in, sizeof(struct input_event)) > 0) { - if(in.type == EV_REL) { - if(in.code == REL_X) - #if EVDEV_SWAP_AXES - evdev_root_y += in.value; - #else - evdev_root_x += in.value; - #endif - else if(in.code == REL_Y) - #if EVDEV_SWAP_AXES - evdev_root_x += in.value; - #else - evdev_root_y += in.value; - #endif - } else if(in.type == EV_ABS) { - if(in.code == ABS_X) - #if EVDEV_SWAP_AXES - evdev_root_y = in.value; - #else - evdev_root_x = in.value; - #endif - else if(in.code == ABS_Y) - #if EVDEV_SWAP_AXES - evdev_root_x = in.value; - #else - evdev_root_y = in.value; - #endif - else if(in.code == ABS_MT_POSITION_X) - #if EVDEV_SWAP_AXES - evdev_root_y = in.value; - #else - evdev_root_x = in.value; - #endif - else if(in.code == ABS_MT_POSITION_Y) - #if EVDEV_SWAP_AXES - evdev_root_x = in.value; - #else - evdev_root_y = in.value; - #endif - } else if(in.type == EV_KEY) { - if(in.code == BTN_MOUSE || in.code == BTN_TOUCH) { - if(in.value == 0) - evdev_button = LV_INDEV_STATE_REL; - else if(in.value == 1) - evdev_button = LV_INDEV_STATE_PR; - } else if(drv->type == LV_INDEV_TYPE_KEYPAD) { - data->state = (in.value) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; - switch(in.code) { - case KEY_BACKSPACE: - data->key = LV_KEY_BACKSPACE; - break; - case KEY_ENTER: - data->key = LV_KEY_ENTER; - break; - case KEY_UP: - data->key = LV_KEY_UP; - break; - case KEY_LEFT: - data->key = LV_KEY_PREV; - break; - case KEY_RIGHT: - data->key = LV_KEY_NEXT; - break; - case KEY_DOWN: - data->key = LV_KEY_DOWN; - break; - default: - data->key = 0; - break; - } - evdev_key_val = data->key; - evdev_button = data->state; - return false; - } - } - } - - if(drv->type == LV_INDEV_TYPE_KEYPAD) { - /* No data retrieved */ - data->key = evdev_key_val; - data->state = evdev_button; - return false; - } - if(drv->type != LV_INDEV_TYPE_POINTER) - return false; - /*Store the collected data*/ - -#if EVDEV_SCALE - data->point.x = map(evdev_root_x, 0, EVDEV_SCALE_HOR_RES, 0, lv_disp_get_hor_res(drv->disp)); - data->point.y = map(evdev_root_y, 0, EVDEV_SCALE_VER_RES, 0, lv_disp_get_ver_res(drv->disp)); -#endif -#if EVDEV_CALIBRATE - data->point.x = map(evdev_root_x, EVDEV_HOR_MIN, EVDEV_HOR_MAX, 0, lv_disp_get_hor_res(drv->disp)); - data->point.y = map(evdev_root_y, EVDEV_VER_MIN, EVDEV_VER_MAX, 0, lv_disp_get_ver_res(drv->disp)); -#else - data->point.x = evdev_root_x; - data->point.y = evdev_root_y; -#endif - - data->state = evdev_button; - - if(data->point.x < 0) - data->point.x = 0; - if(data->point.y < 0) - data->point.y = 0; - if(data->point.x >= lv_disp_get_hor_res(drv->disp)) - data->point.x = lv_disp_get_hor_res(drv->disp) - 1; - if(data->point.y >= lv_disp_get_ver_res(drv->disp)) - data->point.y = lv_disp_get_ver_res(drv->disp) - 1; - - return false; -} - -/********************** - * STATIC FUNCTIONS - **********************/ -int map(int x, int in_min, int in_max, int out_min, int out_max) -{ - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; -} - -#endif diff --git a/lib/lv_drivers/indev/evdev.h b/lib/lv_drivers/indev/evdev.h deleted file mode 100644 index 3a598dd4..00000000 --- a/lib/lv_drivers/indev/evdev.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file evdev.h - * - */ - -#ifndef EVDEV_H -#define EVDEV_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_EVDEV - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ - -/** - * Initialize the evdev - */ -void evdev_init(void); -/** - * reconfigure the device file for evdev - * @param dev_name set the evdev device filename - * @return true: the device file set complete - * false: the device file doesn't exist current system - */ -bool evdev_set_file(char* dev_name); -/** - * Get the current position and state of the evdev - * @param data store the evdev data here - * @return false: because the points are not buffered, so no more data to be read - */ -bool evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data); - - -/********************** - * MACROS - **********************/ - -#endif /* USE_EVDEV */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* EVDEV_H */ diff --git a/lib/lv_drivers/indev/indev.mk b/lib/lv_drivers/indev/indev.mk deleted file mode 100644 index 09ff47d0..00000000 --- a/lib/lv_drivers/indev/indev.mk +++ /dev/null @@ -1,12 +0,0 @@ -CSRCS += FT5406EE8.c -CSRCS += keyboard.c -CSRCS += mouse.c -CSRCS += mousewheel.c -CSRCS += evdev.c -CSRCS += libinput.c -CSRCS += XPT2046.c - -DEPPATH += --dep-path $(LVGL_DIR)/lv_drivers/indev -VPATH += :$(LVGL_DIR)/lv_drivers/indev - -CFLAGS += "-I$(LVGL_DIR)/lv_drivers/indev" diff --git a/lib/lv_drivers/indev/keyboard.c b/lib/lv_drivers/indev/keyboard.c deleted file mode 100644 index 2f4549af..00000000 --- a/lib/lv_drivers/indev/keyboard.c +++ /dev/null @@ -1,130 +0,0 @@ -/** - * @file sdl_kb.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "keyboard.h" -#if USE_KEYBOARD - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ -static uint32_t keycode_to_ascii(uint32_t sdl_key); - -/********************** - * STATIC VARIABLES - **********************/ -static uint32_t last_key; -static lv_indev_state_t state; - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Initialize the keyboard - */ -void keyboard_init(void) -{ - /*Nothing to init*/ -} - -/** - * Get the last pressed or released character from the PC's keyboard - * @param indev_drv pointer to the related input device driver - * @param data store the read data here - * @return false: because the points are not buffered, so no more data to be read - */ -bool keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) -{ - (void) indev_drv; /*Unused*/ - data->state = state; - data->key = keycode_to_ascii(last_key); - - return false; -} - -/** - * It is called periodically from the SDL thread to check a key is pressed/released - * @param event describes the event - */ -void keyboard_handler(SDL_Event * event) -{ - /* We only care about SDL_KEYDOWN and SDL_KEYUP events */ - switch(event->type) { - case SDL_KEYDOWN: /*Button press*/ - last_key = event->key.keysym.sym; /*Save the pressed key*/ - state = LV_INDEV_STATE_PR; /*Save the key is pressed now*/ - break; - case SDL_KEYUP: /*Button release*/ - state = LV_INDEV_STATE_REL; /*Save the key is released but keep the last key*/ - break; - default: - break; - - } -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -/** - * Convert the key code LV_KEY_... "codes" or leave them if they are not control characters - * @param sdl_key the key code - * @return - */ -static uint32_t keycode_to_ascii(uint32_t sdl_key) -{ - /*Remap some key to LV_KEY_... to manage groups*/ - switch(sdl_key) { - case SDLK_RIGHT: - case SDLK_KP_PLUS: - return LV_KEY_RIGHT; - - case SDLK_LEFT: - case SDLK_KP_MINUS: - return LV_KEY_LEFT; - - case SDLK_UP: - return LV_KEY_UP; - - case SDLK_DOWN: - return LV_KEY_DOWN; - - case SDLK_ESCAPE: - return LV_KEY_ESC; - -#ifdef LV_KEY_BACKSPACE /*For backward compatibility*/ - case SDLK_BACKSPACE: - return LV_KEY_BACKSPACE; -#endif - -#ifdef LV_KEY_DEL /*For backward compatibility*/ - case SDLK_DELETE: - return LV_KEY_DEL; -#endif - case SDLK_KP_ENTER: - case '\r': - return LV_KEY_ENTER; - - default: - return sdl_key; - } -} -#endif diff --git a/lib/lv_drivers/indev/keyboard.h b/lib/lv_drivers/indev/keyboard.h deleted file mode 100644 index 03ca15b3..00000000 --- a/lib/lv_drivers/indev/keyboard.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @file keyboard.h - * - */ - -#ifndef KEYBOARD_H -#define KEYBOARD_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_KEYBOARD - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MONITOR_SDL_INCLUDE_PATH -#define MONITOR_SDL_INCLUDE_PATH -#endif - -#include MONITOR_SDL_INCLUDE_PATH - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -/** - * Initialize the keyboard - */ -void keyboard_init(void); - -/** - * Get the last pressed or released character from the PC's keyboard - * @param indev_drv pointer to the related input device driver - * @param data store the read data here - * @return false: because the points are not buffered, so no more data to be read - */ -bool keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); - -/** - * It is called periodically from the SDL thread to check a key is pressed/released - * @param event describes the event - */ -void keyboard_handler(SDL_Event *event); - -/********************** - * MACROS - **********************/ - -#endif /*USE_KEYBOARD*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /*KEYBOARD_H*/ diff --git a/lib/lv_drivers/indev/libinput.c b/lib/lv_drivers/indev/libinput.c deleted file mode 100644 index 98dfd7df..00000000 --- a/lib/lv_drivers/indev/libinput.c +++ /dev/null @@ -1,175 +0,0 @@ -/** - * @file libinput.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "libinput_drv.h" -#if USE_LIBINPUT != 0 - -#include -#include -#include -#include -#include -#include -#include -#include - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ -static int open_restricted(const char *path, int flags, void *user_data); -static void close_restricted(int fd, void *user_data); - -/********************** - * STATIC VARIABLES - **********************/ -static int libinput_fd; -static int libinput_button; -static const int timeout = 0; // do not block -static const nfds_t nfds = 1; -static struct pollfd fds[1]; -static lv_point_t most_recent_touch_point = { .x = 0, .y = 0}; - -static struct libinput *libinput_context; -static struct libinput_device *libinput_device; -const static struct libinput_interface interface = { - .open_restricted = open_restricted, - .close_restricted = close_restricted, -}; - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * reconfigure the device file for libinput - * @param dev_name set the libinput device filename - * @return true: the device file set complete - * false: the device file doesn't exist current system - */ -bool libinput_set_file(char* dev_name) -{ - // This check *should* not be necessary, yet applications crashes even on NULL handles. - // citing libinput.h:libinput_path_remove_device: - // > If no matching device exists, this function does nothing. - if (libinput_device) { - libinput_device = libinput_device_unref(libinput_device); - libinput_path_remove_device(libinput_device); - } - - libinput_device = libinput_path_add_device(libinput_context, dev_name); - if(!libinput_device) { - perror("unable to add device to libinput context:"); - return false; - } - libinput_device = libinput_device_ref(libinput_device); - if(!libinput_device) { - perror("unable to reference device within libinput context:"); - return false; - } - - libinput_button = LV_INDEV_STATE_REL; - - return true; -} - -/** - * Initialize the libinput interface - */ -void libinput_init(void) -{ - libinput_device = NULL; - libinput_context = libinput_path_create_context(&interface, NULL); - if(!libinput_set_file(LIBINPUT_NAME)) { - perror("unable to add device \"" LIBINPUT_NAME "\" to libinput context:"); - return; - } - libinput_fd = libinput_get_fd(libinput_context); - - /* prepare poll */ - fds[0].fd = libinput_fd; - fds[0].events = POLLIN; - fds[0].revents = 0; -} - -/** - * Get the current position and state of the libinput - * @param indev_drv driver object itself - * @param data store the libinput data here - * @return false: because the points are not buffered, so no more data to be read - */ -bool libinput_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) -{ - struct libinput_event *event; - struct libinput_event_touch *touch_event = NULL; - int rc = 0; - - rc = poll(fds, nfds, timeout); - switch (rc){ - case -1: - perror(NULL); - case 0: - goto report_most_recent_state; - default: - break; - } - libinput_dispatch(libinput_context); - while((event = libinput_get_event(libinput_context)) != NULL) { - enum libinput_event_type type = libinput_event_get_type(event); - switch (type) { - case LIBINPUT_EVENT_TOUCH_MOTION: - case LIBINPUT_EVENT_TOUCH_DOWN: - touch_event = libinput_event_get_touch_event(event); - most_recent_touch_point.x = libinput_event_touch_get_x_transformed(touch_event, LV_HOR_RES); - most_recent_touch_point.y = libinput_event_touch_get_y_transformed(touch_event, LV_VER_RES); - libinput_button = LV_INDEV_STATE_PR; - break; - case LIBINPUT_EVENT_TOUCH_UP: - libinput_button = LV_INDEV_STATE_REL; - break; - default: - break; - } - libinput_event_destroy(event); - } -report_most_recent_state: - data->point.x = most_recent_touch_point.x; - data->point.y = most_recent_touch_point.y; - data->state = libinput_button; - - return false; -} - - -/********************** - * STATIC FUNCTIONS - **********************/ - -static int open_restricted(const char *path, int flags, void *user_data) -{ - int fd = open(path, flags); - return fd < 0 ? -errno : fd; -} - -static void close_restricted(int fd, void *user_data) -{ - close(fd); -} - -#endif diff --git a/lib/lv_drivers/indev/libinput_drv.h b/lib/lv_drivers/indev/libinput_drv.h deleted file mode 100644 index ae1ee42c..00000000 --- a/lib/lv_drivers/indev/libinput_drv.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file libinput.h - * - */ - -#ifndef LVGL_LIBINPUT_H -#define LVGL_LIBINPUT_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_LIBINPUT - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ - -/** - * Initialize the libinput - */ -void libinput_init(void); -/** - * reconfigure the device file for libinput - * @param dev_name set the libinput device filename - * @return true: the device file set complete - * false: the device file doesn't exist current system - */ -bool libinput_set_file(char* dev_name); -/** - * Get the current position and state of the libinput - * @param indev_drv driver object itself - * @param data store the libinput data here - * @return false: because the points are not buffered, so no more data to be read - */ -bool libinput_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); - - -/********************** - * MACROS - **********************/ - -#endif /* USE_LIBINPUT */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* LVGL_LIBINPUT_H */ diff --git a/lib/lv_drivers/indev/mouse.c b/lib/lv_drivers/indev/mouse.c deleted file mode 100644 index 01d850fa..00000000 --- a/lib/lv_drivers/indev/mouse.c +++ /dev/null @@ -1,98 +0,0 @@ -/** - * @file mouse.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "mouse.h" -#if USE_MOUSE != 0 - -/********************* - * DEFINES - *********************/ -#ifndef MONITOR_ZOOM -#define MONITOR_ZOOM 1 -#endif - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ -static bool left_button_down = false; -static int16_t last_x = 0; -static int16_t last_y = 0; - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Initialize the mouse - */ -void mouse_init(void) -{ - -} - -/** - * Get the current position and state of the mouse - * @param indev_drv pointer to the related input device driver - * @param data store the mouse data here - * @return false: because the points are not buffered, so no more data to be read - */ -bool mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) -{ - (void) indev_drv; /*Unused*/ - - /*Store the collected data*/ - data->point.x = last_x; - data->point.y = last_y; - data->state = left_button_down ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; - - return false; -} - -/** - * It will be called from the main SDL thread - */ -void mouse_handler(SDL_Event * event) -{ - switch(event->type) { - case SDL_MOUSEBUTTONUP: - if(event->button.button == SDL_BUTTON_LEFT) - left_button_down = false; - break; - case SDL_MOUSEBUTTONDOWN: - if(event->button.button == SDL_BUTTON_LEFT) { - left_button_down = true; - last_x = event->motion.x / MONITOR_ZOOM; - last_y = event->motion.y / MONITOR_ZOOM; - } - break; - case SDL_MOUSEMOTION: - last_x = event->motion.x / MONITOR_ZOOM; - last_y = event->motion.y / MONITOR_ZOOM; - - break; - } - -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -#endif diff --git a/lib/lv_drivers/indev/mouse.h b/lib/lv_drivers/indev/mouse.h deleted file mode 100644 index bd04dee1..00000000 --- a/lib/lv_drivers/indev/mouse.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @file mouse.h - * - */ - -#ifndef MOUSE_H -#define MOUSE_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_MOUSE - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MONITOR_SDL_INCLUDE_PATH -#define MONITOR_SDL_INCLUDE_PATH -#endif - -#include MONITOR_SDL_INCLUDE_PATH - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ - -/** - * Initialize the mouse - */ -void mouse_init(void); - -/** - * Get the current position and state of the mouse - * @param indev_drv pointer to the related input device driver - * @param data store the mouse data here - * @return false: because the points are not buffered, so no more data to be read - */ -bool mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); - -/** - * It will be called from the main SDL thread - */ -void mouse_handler(SDL_Event *event); - -/********************** - * MACROS - **********************/ - -#endif /* USE_MOUSE */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* MOUSE_H */ diff --git a/lib/lv_drivers/indev/mousewheel.c b/lib/lv_drivers/indev/mousewheel.c deleted file mode 100644 index 7ada72fd..00000000 --- a/lib/lv_drivers/indev/mousewheel.c +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @file mousewheel.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "mousewheel.h" -#if USE_MOUSEWHEEL - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ -static int16_t enc_diff = 0; -static lv_indev_state_t state = LV_INDEV_STATE_REL; - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Initialize the mousewheel - */ -void mousewheel_init(void) -{ - /*Nothing to init*/ -} - -/** - * Get encoder (i.e. mouse wheel) ticks difference and pressed state - * @param indev_drv pointer to the related input device driver - * @param data store the read data here - * @return false: all ticks and button state are handled - */ -bool mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) -{ - (void) indev_drv; /*Unused*/ - - data->state = state; - data->enc_diff = enc_diff; - enc_diff = 0; - - return false; /*No more data to read so return false*/ -} - -/** - * It is called periodically from the SDL thread to check mouse wheel state - * @param event describes the event - */ -void mousewheel_handler(SDL_Event * event) -{ - switch(event->type) { - case SDL_MOUSEWHEEL: - // Scroll down (y = -1) means positive encoder turn, - // so invert it -#ifdef __EMSCRIPTEN__ - /*Escripten scales it wrong*/ - if(event->wheel.y < 0) enc_diff++; - if(event->wheel.y > 0) enc_diff--; -#else - enc_diff = -event->wheel.y; -#endif - break; - case SDL_MOUSEBUTTONDOWN: - if(event->button.button == SDL_BUTTON_MIDDLE) { - state = LV_INDEV_STATE_PR; - } - break; - case SDL_MOUSEBUTTONUP: - if(event->button.button == SDL_BUTTON_MIDDLE) { - state = LV_INDEV_STATE_REL; - } - break; - default: - break; - } -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -#endif diff --git a/lib/lv_drivers/indev/mousewheel.h b/lib/lv_drivers/indev/mousewheel.h deleted file mode 100644 index cbe1ed45..00000000 --- a/lib/lv_drivers/indev/mousewheel.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file mousewheel.h - * - */ - -#ifndef MOUSEWHEEL_H -#define MOUSEWHEEL_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../../lv_drv_conf.h" -#endif -#endif - -#if USE_MOUSEWHEEL - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MONITOR_SDL_INCLUDE_PATH -#define MONITOR_SDL_INCLUDE_PATH -#endif - -#include MONITOR_SDL_INCLUDE_PATH - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ - -/** - * Initialize the encoder - */ -void mousewheel_init(void); - -/** - * Get encoder (i.e. mouse wheel) ticks difference and pressed state - * @param indev_drv pointer to the related input device driver - * @param data store the read data here - * @return false: all ticks and button state are handled - */ -bool mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); - -/** - * It is called periodically from the SDL thread to check a key is pressed/released - * @param event describes the event - */ -void mousewheel_handler(SDL_Event *event); - -/********************** - * MACROS - **********************/ - -#endif /*USE_MOUSEWHEEL*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /*MOUSEWHEEL_H*/ diff --git a/lib/lv_drivers/library.json b/lib/lv_drivers/library.json deleted file mode 100644 index cdb6e888..00000000 --- a/lib/lv_drivers/library.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "lv_drivers", - "version": "6.0.2", - "keywords": "littlevgl, lvgl, driver, display, touchpad", - "description": "Drivers for LittlevGL graphics library.", - "repository": { - "type": "git", - "url": "https://github.com/littlevgl/lv_drivers.git" - }, - "build": { - "includeDir": "." - } -} diff --git a/lib/lv_drivers/lv_drivers.mk b/lib/lv_drivers/lv_drivers.mk deleted file mode 100644 index 1bb786c1..00000000 --- a/lib/lv_drivers/lv_drivers.mk +++ /dev/null @@ -1,10 +0,0 @@ -include $(LVGL_DIR)/lv_drivers/display/display.mk -include $(LVGL_DIR)/lv_drivers/indev/indev.mk - - -CSRCS += win_drv.c - -DEPPATH += --dep-path $(LVGL_DIR)/lv_drivers -VPATH += :$(LVGL_DIR)/lv_drivers - -CFLAGS += "-I$(LVGL_DIR)/lv_drivers" diff --git a/lib/lv_drivers/lv_drv_conf_templ.h b/lib/lv_drivers/lv_drv_conf_templ.h deleted file mode 100644 index e3367d38..00000000 --- a/lib/lv_drivers/lv_drv_conf_templ.h +++ /dev/null @@ -1,357 +0,0 @@ -/** - * @file lv_drv_conf.h - * - */ - -/* - * COPY THIS FILE AS lv_drv_conf.h - */ - -#if 0 /*Set it to "1" to enable the content*/ - -#ifndef LV_DRV_CONF_H -#define LV_DRV_CONF_H - -#include "lv_conf.h" - -/********************* - * DELAY INTERFACE - *********************/ -#define LV_DRV_DELAY_INCLUDE /*Dummy include by default*/ -#define LV_DRV_DELAY_US(us) /*delay_us(us)*/ /*Delay the given number of microseconds*/ -#define LV_DRV_DELAY_MS(ms) /*delay_ms(ms)*/ /*Delay the given number of milliseconds*/ - -/********************* - * DISPLAY INTERFACE - *********************/ - -/*------------ - * Common - *------------*/ -#define LV_DRV_DISP_INCLUDE /*Dummy include by default*/ -#define LV_DRV_DISP_CMD_DATA(val) /*pin_x_set(val)*/ /*Set the command/data pin to 'val'*/ -#define LV_DRV_DISP_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/ - -/*--------- - * SPI - *---------*/ -#define LV_DRV_DISP_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/ -#define LV_DRV_DISP_SPI_WR_BYTE(data) /*spi_wr(data)*/ /*Write a byte the SPI bus*/ -#define LV_DRV_DISP_SPI_WR_ARRAY(adr, n) /*spi_wr_mem(adr, n)*/ /*Write 'n' bytes to SPI bus from 'adr'*/ - -/*------------------ - * Parallel port - *-----------------*/ -#define LV_DRV_DISP_PAR_CS(val) /*par_cs_set(val)*/ /*Set the Parallel port's Chip select to 'val'*/ -#define LV_DRV_DISP_PAR_SLOW /*par_slow()*/ /*Set low speed on the parallel port*/ -#define LV_DRV_DISP_PAR_FAST /*par_fast()*/ /*Set high speed on the parallel port*/ -#define LV_DRV_DISP_PAR_WR_WORD(data) /*par_wr(data)*/ /*Write a word to the parallel port*/ -#define LV_DRV_DISP_PAR_WR_ARRAY(adr, n) /*par_wr_mem(adr,n)*/ /*Write 'n' bytes to Parallel ports from 'adr'*/ - -/*************************** - * INPUT DEVICE INTERFACE - ***************************/ - -/*---------- - * Common - *----------*/ -#define LV_DRV_INDEV_INCLUDE /*Dummy include by default*/ -#define LV_DRV_INDEV_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/ -#define LV_DRV_INDEV_IRQ_READ 0 /*pn_x_read()*/ /*Read the IRQ pin*/ - -/*--------- - * SPI - *---------*/ -#define LV_DRV_INDEV_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/ -#define LV_DRV_INDEV_SPI_XCHG_BYTE(data) 0 /*spi_xchg(val)*/ /*Write 'val' to SPI and give the read value*/ - -/*--------- - * I2C - *---------*/ -#define LV_DRV_INDEV_I2C_START /*i2c_start()*/ /*Make an I2C start*/ -#define LV_DRV_INDEV_I2C_STOP /*i2c_stop()*/ /*Make an I2C stop*/ -#define LV_DRV_INDEV_I2C_RESTART /*i2c_restart()*/ /*Make an I2C restart*/ -#define LV_DRV_INDEV_I2C_WR(data) /*i2c_wr(data)*/ /*Write a byte to the I1C bus*/ -#define LV_DRV_INDEV_I2C_READ(last_read) 0 /*i2c_rd()*/ /*Read a byte from the I2C bud*/ - - -/********************* - * DISPLAY DRIVERS - *********************/ - -/*------------------- - * Monitor of PC - *-------------------*/ -#ifndef USE_MONITOR -# define USE_MONITOR 0 -#endif - -#if USE_MONITOR -# define MONITOR_HOR_RES LV_HOR_RES -# define MONITOR_VER_RES LV_VER_RES - -/* Scale window by this factor (useful when simulating small screens) */ -# define MONITOR_ZOOM 1 - -/* Used to test true double buffering with only address changing. - * Set LV_VDB_SIZE = (LV_HOR_RES * LV_VER_RES) and LV_VDB_DOUBLE = 1 and LV_COLOR_DEPTH = 32" */ -# define MONITOR_DOUBLE_BUFFERED 0 - -/*Eclipse: Visual Studio: */ -# define MONITOR_SDL_INCLUDE_PATH - -/*Different rendering might be used if running in a Virtual machine*/ -# define MONITOR_VIRTUAL_MACHINE 0 - -/*Open two windows to test multi display support*/ -# define MONITOR_DUAL 0 -#endif - -/*----------------------------------- - * Native Windows (including mouse) - *----------------------------------*/ -#ifndef USE_WINDOWS -# define USE_WINDOWS 0 -#endif - -#define USE_WINDOWS 0 -#if USE_WINDOWS -# define WINDOW_HOR_RES 480 -# define WINDOW_VER_RES 320 -#endif - -/*---------------- - * SSD1963 - *--------------*/ -#ifndef USE_SSD1963 -# define USE_SSD1963 0 -#endif - -#if USE_SSD1963 -# define SSD1963_HOR_RES LV_HOR_RES -# define SSD1963_VER_RES LV_VER_RES -# define SSD1963_HT 531 -# define SSD1963_HPS 43 -# define SSD1963_LPS 8 -# define SSD1963_HPW 10 -# define SSD1963_VT 288 -# define SSD1963_VPS 12 -# define SSD1963_FPS 4 -# define SSD1963_VPW 10 -# define SSD1963_HS_NEG 0 /*Negative hsync*/ -# define SSD1963_VS_NEG 0 /*Negative vsync*/ -# define SSD1963_ORI 0 /*0, 90, 180, 270*/ -# define SSD1963_COLOR_DEPTH 16 -#endif - -/*---------------- - * R61581 - *--------------*/ -#ifndef USE_R61581 -# define USE_R61581 0 -#endif - -#if USE_R61581 -# define R61581_HOR_RES LV_HOR_RES -# define R61581_VER_RES LV_VER_RES -# define R61581_HSPL 0 /*HSYNC signal polarity*/ -# define R61581_HSL 10 /*HSYNC length (Not Implemented)*/ -# define R61581_HFP 10 /*Horitontal Front poarch (Not Implemented)*/ -# define R61581_HBP 10 /*Horitontal Back poarch (Not Implemented */ -# define R61581_VSPL 0 /*VSYNC signal polarity*/ -# define R61581_VSL 10 /*VSYNC length (Not Implemented)*/ -# define R61581_VFP 8 /*Vertical Front poarch*/ -# define R61581_VBP 8 /*Vertical Back poarch */ -# define R61581_DPL 0 /*DCLK signal polarity*/ -# define R61581_EPL 1 /*ENABLE signal polarity*/ -# define R61581_ORI 0 /*0, 180*/ -# define R61581_LV_COLOR_DEPTH 16 /*Fix 16 bit*/ -#endif - -/*------------------------------ - * ST7565 (Monochrome, low res.) - *-----------------------------*/ -#ifndef USE_ST7565 -# define USE_ST7565 0 -#endif - -#if USE_ST7565 -/*No settings*/ -#endif /*USE_ST7565*/ - -/*------------------------------------------ - * UC1610 (4 gray 160*[104|128]) - * (EA DOGXL160 160x104 tested) - *-----------------------------------------*/ -#ifndef USE_UC1610 -# define USE_UC1610 0 -#endif - -#if USE_UC1610 -# define UC1610_HOR_RES LV_HOR_RES -# define UC1610_VER_RES LV_VER_RES -# define UC1610_INIT_CONTRAST 33 /* init contrast, values in [%] */ -# define UC1610_INIT_HARD_RST 0 /* 1 : hardware reset at init, 0 : software reset */ -# define UC1610_TOP_VIEW 0 /* 0 : Bottom View, 1 : Top View */ -#endif /*USE_UC1610*/ - -/*------------------------------------------------- - * SHARP memory in pixel monochrome display series - * LS012B7DD01 (184x38 pixels.) - * LS013B7DH03 (128x128 pixels.) - * LS013B7DH05 (144x168 pixels.) - * LS027B7DH01 (400x240 pixels.) (tested) - * LS032B7DD02 (336x536 pixels.) - * LS044Q7DH01 (320x240 pixels.) - *------------------------------------------------*/ -#ifndef USE_SHARP_MIP -# define USE_SHARP_MIP 0 -#endif - -#if USE_SHARP_MIP -# define SHARP_MIP_HOR_RES LV_HOR_RES -# define SHARP_MIP_VER_RES LV_VER_RES -# define SHARP_MIP_SOFT_COM_INVERSION 0 -# define SHARP_MIP_REV_BYTE(b) /*((uint8_t) __REV(__RBIT(b)))*/ /*Architecture / compiler dependent byte bits order reverse*/ -#endif /*USE_SHARP_MIP*/ - -/*----------------------------------------- - * Linux frame buffer device (/dev/fbx) - *-----------------------------------------*/ -#ifndef USE_FBDEV -# define USE_FBDEV 0 -#endif - -#if USE_FBDEV -# define FBDEV_PATH "/dev/fb0" -#endif - -/*----------------------------------------- - * FreeBSD frame buffer device (/dev/fbx) - *.........................................*/ -#ifndef USE_BSD_FBDEV -# define USE_BSD_FBDEV 0 -#endif - -#if USE_BSD_FBDEV -# define FBDEV_PATH "/dev/fb0" -#endif - -/********************* - * INPUT DEVICES - *********************/ - -/*-------------- - * XPT2046 - *--------------*/ -#ifndef USE_XPT2046 -# define USE_XPT2046 0 -#endif - -#if USE_XPT2046 -# define XPT2046_HOR_RES 480 -# define XPT2046_VER_RES 320 -# define XPT2046_X_MIN 200 -# define XPT2046_Y_MIN 200 -# define XPT2046_X_MAX 3800 -# define XPT2046_Y_MAX 3800 -# define XPT2046_AVG 4 -# define XPT2046_INV 0 -#endif - -/*----------------- - * FT5406EE8 - *-----------------*/ -#ifndef USE_FT5406EE8 -# define USE_FT5406EE8 0 -#endif - -#if USE_FT5406EE8 -# define FT5406EE8_I2C_ADR 0x38 /*7 bit address*/ -#endif - -/*--------------- - * AD TOUCH - *--------------*/ -#ifndef USE_AD_TOUCH -# define USE_AD_TOUCH 0 -#endif - -#if USE_AD_TOUCH -/*No settings*/ -#endif - - -/*--------------------------------------- - * Mouse or touchpad on PC (using SDL) - *-------------------------------------*/ -#ifndef USE_MOUSE -# define USE_MOUSE 0 -#endif - -#if USE_MOUSE -/*No settings*/ -#endif - -/*------------------------------------------- - * Mousewheel as encoder on PC (using SDL) - *------------------------------------------*/ -#ifndef USE_MOUSEWHEEL -# define USE_MOUSEWHEEL 0 -#endif - -#if USE_MOUSEWHEEL -/*No settings*/ -#endif - -/*------------------------------------------------- - * Touchscreen as libinput interface (for Linux based systems) - *------------------------------------------------*/ -#ifndef USE_LIBINPUT -# define USE_LIBINPUT 0 -#endif - -#if USE_LIBINPUT -# define LIBINPUT_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/ -#endif /*USE_LIBINPUT*/ - -/*------------------------------------------------- - * Mouse or touchpad as evdev interface (for Linux based systems) - *------------------------------------------------*/ -#ifndef USE_EVDEV -# define USE_EVDEV 0 -#endif - -#if USE_EVDEV -# define EVDEV_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/ -# define EVDEV_SWAP_AXES 0 /*Swap the x and y axes of the touchscreen*/ - -# define EVDEV_SCALE 0 /* Scale input, e.g. if touchscreen resolution does not match display resolution */ -# if EVDEV_SCALE -# define EVDEV_SCALE_HOR_RES (4096) /* Horizontal resolution of touchscreen */ -# define EVDEV_SCALE_VER_RES (4096) /* Vertical resolution of touchscreen */ -# endif /*EVDEV_SCALE*/ - -# define EVDEV_CALIBRATE 0 /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/ -# if EVDEV_CALIBRATE -# define EVDEV_HOR_MIN 3800 /*If EVDEV_XXX_MIN > EVDEV_XXX_MAX the XXX axis is automatically inverted*/ -# define EVDEV_HOR_MAX 200 -# define EVDEV_VER_MIN 200 -# define EVDEV_VER_MAX 3800 -# endif /*EVDEV_SCALE*/ -#endif /*USE_EVDEV*/ - -/*------------------------------- - * Keyboard of a PC (using SDL) - *------------------------------*/ -#ifndef USE_KEYBOARD -# define USE_KEYBOARD 0 -#endif - -#if USE_KEYBOARD -/*No settings*/ -#endif - -#endif /*LV_DRV_CONF_H*/ - -#endif /*End of "Content enable"*/ diff --git a/lib/lv_drivers/win_drv.c b/lib/lv_drivers/win_drv.c deleted file mode 100644 index 3115f555..00000000 --- a/lib/lv_drivers/win_drv.c +++ /dev/null @@ -1,318 +0,0 @@ -/** - * @file win_drv.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "win_drv.h" -#if USE_WINDOWS - -#include -#include -#include "lvgl/lvgl.h" - -#if LV_COLOR_DEPTH < 16 -#error Windows driver only supports true RGB colors at this time -#endif - -/********************** - * DEFINES - **********************/ - - #define WINDOW_STYLE (WS_OVERLAPPEDWINDOW & ~(WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME)) - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ -static void do_register(void); -static void win_drv_flush(lv_disp_t *drv, lv_area_t *area, const lv_color_t * color_p); -static void win_drv_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); -static void win_drv_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); -static bool win_drv_read(lv_indev_t *drv, lv_indev_data_t * data); -static void msg_handler(void *param); - -static COLORREF lv_color_to_colorref(const lv_color_t color); - -static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - - -/********************** - * GLOBAL VARIABLES - **********************/ - -bool lv_win_exit_flag = false; -lv_disp_t *lv_windows_disp; - -/********************** - * STATIC VARIABLES - **********************/ -static HWND hwnd; -static uint32_t *fbp = NULL; /* Raw framebuffer memory */ -static bool mouse_pressed; -static int mouse_x, mouse_y; - - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ -const char g_szClassName[] = "LittlevGL"; - -HWND windrv_init(void) -{ - WNDCLASSEX wc; - RECT winrect; - HICON lvgl_icon; - - //Step 1: Registering the Window Class - wc.cbSize = sizeof(WNDCLASSEX); - wc.style = 0; - wc.lpfnWndProc = WndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = GetModuleHandle(NULL); - lvgl_icon = (HICON) LoadImage( NULL, "lvgl_icon.bmp", IMAGE_ICON, 0, 0, LR_LOADFROMFILE); - - if(lvgl_icon == NULL) - lvgl_icon = LoadIcon(NULL, IDI_APPLICATION); - - wc.hIcon = lvgl_icon; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); - wc.lpszMenuName = NULL; - wc.lpszClassName = g_szClassName; - wc.hIconSm = lvgl_icon; - - if(!RegisterClassEx(&wc)) - { - return NULL; - } - - winrect.left = 0; - winrect.right = WINDOW_HOR_RES - 1; - winrect.top = 0; - winrect.bottom = WINDOW_VER_RES - 1; - AdjustWindowRectEx(&winrect, WINDOW_STYLE, FALSE, WS_EX_CLIENTEDGE); - OffsetRect(&winrect, -winrect.left, -winrect.top); - // Step 2: Creating the Window - hwnd = CreateWindowEx( - WS_EX_CLIENTEDGE, - g_szClassName, - "LittlevGL Simulator", - WINDOW_STYLE, - CW_USEDEFAULT, CW_USEDEFAULT, winrect.right, winrect.bottom, - NULL, NULL, GetModuleHandle(NULL), NULL); - - if(hwnd == NULL) - { - return NULL; - } - - ShowWindow(hwnd, SW_SHOWDEFAULT); - UpdateWindow(hwnd); - - - lv_task_create(msg_handler, 0, LV_TASK_PRIO_HIGHEST, NULL); - lv_win_exit_flag = false; - do_register(); -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -static void do_register(void) -{ - /*----------------------------- - * Create a buffer for drawing - *----------------------------*/ - - /* LittlevGL requires a buffer where it draw the objects. The buffer's has to be greater than 1 display row - * - * There are three buffering configurations: - * 1. Create ONE buffer some rows: LittlevGL will draw the display's content here and writes it to your display - * 2. Create TWO buffer some rows: LittlevGL will draw the display's content to a buffer and writes it your display. - * You should use DMA to write the buffer's content to the display. - * It will enable LittlevGL to draw the next part of the screen to the other buffer while - * the data is being sent form the first buffer. It makes rendering and flushing parallel. - * 3. Create TWO screen buffer: Similar to 2) but the buffer have to be screen sized. When LittlevGL is ready it will give the - * whole frame to display. This way you only need to change the frame buffer's address instead of - * copying the pixels. - * */ - - /* Example for 1) */ - static lv_disp_buf_t disp_buf_1; - static lv_color_t buf1_1[WINDOW_HOR_RES * WINDOW_VER_RES]; /*A buffer for 10 rows*/ - lv_disp_buf_init(&disp_buf_1, buf1_1, NULL, WINDOW_HOR_RES * WINDOW_VER_RES); /*Initialize the display buffer*/ - - - /*----------------------------------- - * Register the display in LittlevGL - *----------------------------------*/ - - lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ - lv_disp_drv_init(&disp_drv); /*Basic initialization*/ - - /*Set up the functions to access to your display*/ - - /*Set the resolution of the display*/ - disp_drv.hor_res = WINDOW_HOR_RES; - disp_drv.ver_res = WINDOW_VER_RES; - - /*Used to copy the buffer's content to the display*/ - disp_drv.flush_cb = win_drv_flush; - - /*Set a display buffer*/ - disp_drv.buffer = &disp_buf_1; - - /*Finally register the driver*/ - lv_windows_disp = lv_disp_drv_register(&disp_drv); - lv_indev_drv_t indev_drv; - lv_indev_drv_init(&indev_drv); - indev_drv.type = LV_INDEV_TYPE_POINTER; - indev_drv.read_cb = win_drv_read; - lv_indev_drv_register(&indev_drv); -} - -static void msg_handler(void *param) -{ - (void)param; - - MSG msg; - BOOL bRet; - if( (bRet = PeekMessage( &msg, NULL, 0, 0, TRUE )) != 0) - { - if (bRet == -1) - { - return; - } - else - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - if(msg.message == WM_QUIT) - lv_win_exit_flag = true; -} - - static bool win_drv_read(lv_indev_t *drv, lv_indev_data_t * data) -{ - data->state = mouse_pressed ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; - data->point.x = mouse_x; - data->point.y = mouse_y; - return false; -} - - static void on_paint(void) - { - HBITMAP bmp = CreateBitmap(WINDOW_HOR_RES, WINDOW_VER_RES, 1, 32, fbp); - PAINTSTRUCT ps; - - HDC hdc = BeginPaint(hwnd, &ps); - - HDC hdcMem = CreateCompatibleDC(hdc); - HBITMAP hbmOld = SelectObject(hdcMem, bmp); - - BitBlt(hdc, 0, 0, WINDOW_HOR_RES, WINDOW_VER_RES, hdcMem, 0, 0, SRCCOPY); - - SelectObject(hdcMem, hbmOld); - DeleteDC(hdcMem); - - EndPaint(hwnd, &ps); - DeleteObject(bmp); - -} -/** - * Flush a buffer to the marked area - * @param x1 left coordinate - * @param y1 top coordinate - * @param x2 right coordinate - * @param y2 bottom coordinate - * @param color_p an array of colors - */ -static void win_drv_flush(lv_disp_t *drv, lv_area_t *area, const lv_color_t * color_p) -{ - win_drv_map(area->x1, area->y1, area->x2, area->y2, color_p); - lv_disp_flush_ready(drv); -} - -/** - * Put a color map to the marked area - * @param x1 left coordinate - * @param y1 top coordinate - * @param x2 right coordinate - * @param y2 bottom coordinate - * @param color_p an array of colors - */ -static void win_drv_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) -{ - for(int y = y1; y <= y2; y++) - { - for(int x = x1; x <= x2; x++) - { - fbp[y*WINDOW_HOR_RES+x] = lv_color_to32(*color_p); - color_p++; - } - } - InvalidateRect(hwnd, NULL, FALSE); - UpdateWindow(hwnd); -} - -static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - HDC hdc; - PAINTSTRUCT ps; - switch(msg) { - case WM_CREATE: - fbp = malloc(4*WINDOW_HOR_RES*WINDOW_VER_RES); - if(fbp == NULL) - return 1; - - return 0; - case WM_MOUSEMOVE: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - mouse_x = GET_X_LPARAM(lParam); - mouse_y = GET_Y_LPARAM(lParam); - if(msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) { - mouse_pressed = (msg == WM_LBUTTONDOWN); - } - return 0; - case WM_CLOSE: - free(fbp); - fbp = NULL; - DestroyWindow(hwnd); - return 0; - case WM_PAINT: - on_paint(); - return 0; - case WM_DESTROY: - PostQuitMessage(0); - return 0; - default: - break; - } - return DefWindowProc(hwnd, msg, wParam, lParam); -} -static COLORREF lv_color_to_colorref(const lv_color_t color) -{ - uint32_t raw_color = lv_color_to32(color); - lv_color32_t tmp; - tmp.full = raw_color; - uint32_t colorref = RGB(tmp.ch.red, tmp.ch.green, tmp.ch.blue); - return colorref; -} -#endif - - - diff --git a/lib/lv_drivers/win_drv.h b/lib/lv_drivers/win_drv.h deleted file mode 100644 index 7a0f9b25..00000000 --- a/lib/lv_drivers/win_drv.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file fbdev.h - * - */ - -#ifndef WINDRV_H -#define WINDRV_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF -#ifdef LV_CONF_INCLUDE_SIMPLE -#include "lv_drv_conf.h" -#else -#include "../lv_drv_conf.h" -#endif -#endif - -#if USE_WINDOWS - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#include - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -extern bool lv_win_exit_flag; -extern lv_disp_t *lv_windows_disp; - -HWND windrv_init(void); - -/********************** - * MACROS - **********************/ - -#endif /*USE_WINDOWS*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /*WIN_DRV_H*/ diff --git a/lib/lv_drv_tft_espi/tft_espi_drv.h b/lib/lv_drv_tft_espi/tft_espi_drv.h deleted file mode 100644 index 1bb0b4e2..00000000 --- a/lib/lv_drv_tft_espi/tft_espi_drv.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file tft_espi_drv.h - * - */ - -#ifndef TFT_ESPI_DRV_H -#define TFT_ESPI_DRV_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#ifndef LV_DRV_NO_CONF - #ifdef LV_CONF_INCLUDE_SIMPLE - #include "lv_drv_conf.h" - #else - #include "../../lv_drv_conf.h" - #endif -#endif - -#if USE_TFT_ESPI - - #ifdef LV_LVGL_H_INCLUDE_SIMPLE - #include "lvgl.h" - #else - #include "lvgl/lvgl.h" - #endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ -void tft_espi_init(uint8_t rotation, bool invert_display=false); -void tft_espi_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p); -// void tft_espi_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); -void tft_espi_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); -void tft_espi_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); - - #if defined(TOUCH_CS) -void tft_espi_calibrate(uint16_t * calData); -void tft_espi_set_touch(uint16_t * calData); -bool tft_espi_get_touch(int16_t * touchX, int16_t * touchY, uint16_t threshold); - #endif - - /********************** - * MACROS - **********************/ - -#endif /* USE_TFT_ESPI */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* TFT_ESPI_DRV_H */ diff --git a/lib/lv_fs_if/lv_fs_fatfs.c b/lib/lv_fs_if/lv_fs_fatfs.c index 4279b2b7..3448b707 100644 --- a/lib/lv_fs_if/lv_fs_fatfs.c +++ b/lib/lv_fs_if/lv_fs_fatfs.c @@ -21,30 +21,30 @@ **********************/ /* Create a type to store the required data about your file.*/ -typedef FIL file_t; +typedef FIL file_t; /*Similarly to `file_t` create a type for directory reading too */ -typedef DIR dir_t; +typedef DIR dir_t; /********************** * STATIC PROTOTYPES **********************/ static void fs_init(void); -static lv_fs_res_t fs_open (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode); -static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p); -static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br); -static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw); -static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos); -static lv_fs_res_t fs_size (lv_fs_drv_t * drv, void * file_p, uint32_t * size_p); -static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p); -static lv_fs_res_t fs_remove (lv_fs_drv_t * drv, const char *path); -static lv_fs_res_t fs_trunc (lv_fs_drv_t * drv, void * file_p); -static lv_fs_res_t fs_rename (lv_fs_drv_t * drv, const char * oldname, const char * newname); -static lv_fs_res_t fs_free (lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p); -static lv_fs_res_t fs_dir_open (lv_fs_drv_t * drv, void * dir_p, const char *path); -static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn); -static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p); +static lv_fs_res_t fs_open(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode); +static lv_fs_res_t fs_close(lv_fs_drv_t* drv, void* file_p); +static lv_fs_res_t fs_read(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br); +static lv_fs_res_t fs_write(lv_fs_drv_t* drv, void* file_p, const void* buf, uint32_t btw, uint32_t* bw); +static lv_fs_res_t fs_seek(lv_fs_drv_t* drv, void* file_p, uint32_t pos); +static lv_fs_res_t fs_size(lv_fs_drv_t* drv, void* file_p, uint32_t* size_p); +static lv_fs_res_t fs_tell(lv_fs_drv_t* drv, void* file_p, uint32_t* pos_p); +static lv_fs_res_t fs_remove(lv_fs_drv_t* drv, const char* path); +static lv_fs_res_t fs_trunc(lv_fs_drv_t* drv, void* file_p); +static lv_fs_res_t fs_rename(lv_fs_drv_t* drv, const char* oldname, const char* newname); +static lv_fs_res_t fs_free(lv_fs_drv_t* drv, uint32_t* total_p, uint32_t* free_p); +static lv_fs_res_t fs_dir_open(lv_fs_drv_t* drv, void* dir_p, const char* path); +static lv_fs_res_t fs_dir_read(lv_fs_drv_t* drv, void* dir_p, char* fn); +static lv_fs_res_t fs_dir_close(lv_fs_drv_t* drv, void* dir_p); /********************** * STATIC VARIABLES @@ -70,28 +70,28 @@ void lv_fs_if_fatfs_init(void) *--------------------------------------------------*/ /* Add a simple drive to open images */ - lv_fs_drv_t fs_drv; /*A driver descriptor*/ - lv_fs_drv_init(&fs_drv); + static lv_fs_drv_t fs_drv; /*A driver descriptor*/ + lv_fs_drv_init(&fs_drv); /*Set up fields...*/ - fs_drv.file_size = sizeof(file_t); - fs_drv.letter = LV_FS_IF_FATFS; - fs_drv.open_cb = fs_open; - fs_drv.close_cb = fs_close; - fs_drv.read_cb = fs_read; - fs_drv.write_cb = fs_write; - fs_drv.seek_cb = fs_seek; - fs_drv.tell_cb = fs_tell; + fs_drv.file_size = sizeof(file_t); + fs_drv.letter = LV_FS_IF_FATFS; + fs_drv.open_cb = fs_open; + fs_drv.close_cb = fs_close; + fs_drv.read_cb = fs_read; + fs_drv.write_cb = fs_write; + fs_drv.seek_cb = fs_seek; + fs_drv.tell_cb = fs_tell; fs_drv.free_space_cb = fs_free; - fs_drv.size_cb = fs_size; - fs_drv.remove_cb = fs_remove; - fs_drv.rename_cb = fs_rename; - fs_drv.trunc_cb = fs_trunc; + fs_drv.size_cb = fs_size; + fs_drv.remove_cb = fs_remove; + fs_drv.rename_cb = fs_rename; + fs_drv.trunc_cb = fs_trunc; - fs_drv.rddir_size = sizeof(dir_t); + fs_drv.rddir_size = sizeof(dir_t); fs_drv.dir_close_cb = fs_dir_close; - fs_drv.dir_open_cb = fs_dir_open; - fs_drv.dir_read_cb = fs_dir_read; + fs_drv.dir_open_cb = fs_dir_open; + fs_drv.dir_read_cb = fs_dir_read; lv_fs_drv_register(&fs_drv); } @@ -115,25 +115,27 @@ static void fs_init(void) * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_open (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode) +static lv_fs_res_t fs_open(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode) { uint8_t flags = 0; - if(mode == LV_FS_MODE_WR) flags = FA_WRITE | FA_OPEN_ALWAYS; - else if(mode == LV_FS_MODE_RD) flags = FA_READ; - else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS; + if(mode == LV_FS_MODE_WR) + flags = FA_WRITE | FA_OPEN_ALWAYS; + else if(mode == LV_FS_MODE_RD) + flags = FA_READ; + else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) + flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS; FRESULT res = f_open(file_p, path, flags); if(res == FR_OK) { - f_lseek(file_p, 0); - return LV_FS_RES_OK; + f_lseek(file_p, 0); + return LV_FS_RES_OK; } else { - return LV_FS_RES_UNKNOWN; + return LV_FS_RES_UNKNOWN; } } - /** * Close an opened file * @param drv pointer to a driver where this function belongs @@ -141,7 +143,7 @@ static lv_fs_res_t fs_open (lv_fs_drv_t * drv, void * file_p, const char * path, * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p) +static lv_fs_res_t fs_close(lv_fs_drv_t* drv, void* file_p) { f_close(file_p); return LV_FS_RES_OK; @@ -157,11 +159,13 @@ static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p) * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br) +static lv_fs_res_t fs_read(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br) { FRESULT res = f_read(file_p, buf, btr, (UINT*)br); - if(res == FR_OK) return LV_FS_RES_OK; - else return LV_FS_RES_UNKNOWN; + if(res == FR_OK) + return LV_FS_RES_OK; + else + return LV_FS_RES_UNKNOWN; } /** @@ -173,11 +177,13 @@ static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32 * @param br the number of real written bytes (Bytes Written). NULL if unused. * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw) +static lv_fs_res_t fs_write(lv_fs_drv_t* drv, void* file_p, const void* buf, uint32_t btw, uint32_t* bw) { - FRESULT res = f_write(file_p, buf, btw, (UINT*)bw); - if(res == FR_OK) return LV_FS_RES_OK; - else return LV_FS_RES_UNKNOWN; + FRESULT res = f_write(file_p, buf, btw, (UINT*)bw); + if(res == FR_OK) + return LV_FS_RES_OK; + else + return LV_FS_RES_UNKNOWN; } /** @@ -188,7 +194,7 @@ static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos) +static lv_fs_res_t fs_seek(lv_fs_drv_t* drv, void* file_p, uint32_t pos) { f_lseek(file_p, pos); return LV_FS_RES_OK; @@ -201,9 +207,9 @@ static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos) * @param size pointer to a variable to store the size * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_size (lv_fs_drv_t * drv, void * file_p, uint32_t * size_p) +static lv_fs_res_t fs_size(lv_fs_drv_t* drv, void* file_p, uint32_t* size_p) { - (*size_p) = f_size(((file_t *)file_p)); + (*size_p) = f_size(((file_t*)file_p)); return LV_FS_RES_OK; } @@ -215,9 +221,9 @@ static lv_fs_res_t fs_size (lv_fs_drv_t * drv, void * file_p, uint32_t * size_p) * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) +static lv_fs_res_t fs_tell(lv_fs_drv_t* drv, void* file_p, uint32_t* pos_p) { - *pos_p = f_tell(((file_t *)file_p)); + *pos_p = f_tell(((file_t*)file_p)); return LV_FS_RES_OK; } @@ -227,7 +233,7 @@ static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) * @param path path of the file to delete * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_remove (lv_fs_drv_t * drv, const char *path) +static lv_fs_res_t fs_remove(lv_fs_drv_t* drv, const char* path) { lv_fs_res_t res = LV_FS_RES_NOT_IMP; @@ -243,9 +249,9 @@ static lv_fs_res_t fs_remove (lv_fs_drv_t * drv, const char *path) * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_trunc (lv_fs_drv_t * drv, void * file_p) +static lv_fs_res_t fs_trunc(lv_fs_drv_t* drv, void* file_p) { - f_sync(file_p); /*If not syncronized fclose can write the truncated part*/ + f_sync(file_p); /*If not syncronized fclose can write the truncated part*/ f_truncate(file_p); return LV_FS_RES_OK; } @@ -257,13 +263,15 @@ static lv_fs_res_t fs_trunc (lv_fs_drv_t * drv, void * file_p) * @param newname path with the new name * @return LV_FS_RES_OK or any error from 'fs_res_t' */ -static lv_fs_res_t fs_rename (lv_fs_drv_t * drv, const char * oldname, const char * newname) +static lv_fs_res_t fs_rename(lv_fs_drv_t* drv, const char* oldname, const char* newname) { - + FRESULT res = f_rename(oldname, newname); - if(res == FR_OK) return LV_FS_RES_OK; - else return LV_FS_RES_UNKNOWN; + if(res == FR_OK) + return LV_FS_RES_OK; + else + return LV_FS_RES_UNKNOWN; } /** @@ -274,7 +282,7 @@ static lv_fs_res_t fs_rename (lv_fs_drv_t * drv, const char * oldname, const cha * @param free_p pointer to store the free size [kB] * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_free (lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p) +static lv_fs_res_t fs_free(lv_fs_drv_t* drv, uint32_t* total_p, uint32_t* free_p) { lv_fs_res_t res = LV_FS_RES_NOT_IMP; @@ -290,11 +298,13 @@ static lv_fs_res_t fs_free (lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * fr * @param path path to a directory * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_dir_open (lv_fs_drv_t * drv, void * dir_p, const char *path) +static lv_fs_res_t fs_dir_open(lv_fs_drv_t* drv, void* dir_p, const char* path) { FRESULT res = f_opendir(dir_p, path); - if(res == FR_OK) return LV_FS_RES_OK; - else return LV_FS_RES_UNKNOWN; + if(res == FR_OK) + return LV_FS_RES_OK; + else + return LV_FS_RES_UNKNOWN; } /** @@ -305,21 +315,21 @@ static lv_fs_res_t fs_dir_open (lv_fs_drv_t * drv, void * dir_p, const char *pat * @param fn pointer to a buffer to store the filename * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn) +static lv_fs_res_t fs_dir_read(lv_fs_drv_t* drv, void* dir_p, char* fn) { - FRESULT res; - FILINFO fno; - fn[0] = '\0'; + FRESULT res; + FILINFO fno; + fn[0] = '\0'; do { - res = f_readdir(dir_p, &fno); - if(res != FR_OK) return LV_FS_RES_UNKNOWN; + res = f_readdir(dir_p, &fno); + if(res != FR_OK) return LV_FS_RES_UNKNOWN; - if(fno.fattrib & AM_DIR) { - fn[0] = '/'; - strcpy(&fn[1], fno.fname); - } - else strcpy(fn, fno.fname); + if(fno.fattrib & AM_DIR) { + fn[0] = '/'; + strcpy(&fn[1], fno.fname); + } else + strcpy(fn, fno.fname); } while(strcmp(fn, "/.") == 0 || strcmp(fn, "/..") == 0); @@ -332,11 +342,11 @@ static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn) * @param dir_p pointer to an initialized 'fs_read_dir_t' variable * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p) +static lv_fs_res_t fs_dir_close(lv_fs_drv_t* drv, void* dir_p) { - f_closedir(dir_p); + f_closedir(dir_p); return LV_FS_RES_OK; } -#endif /*LV_USE_FS_IF*/ -#endif /*LV_FS_IF_FATFS*/ +#endif /*LV_USE_FS_IF*/ +#endif /*LV_FS_IF_FATFS*/ diff --git a/lib/lv_fs_if/lv_fs_pc.c b/lib/lv_fs_if/lv_fs_pc.c index d76ab87e..6bdca94d 100644 --- a/lib/lv_fs_if/lv_fs_pc.c +++ b/lib/lv_fs_if/lv_fs_pc.c @@ -8,58 +8,62 @@ *********************/ #include "lv_fs_if.h" #if LV_USE_FS_IF - #if LV_FS_IF_PC != '\0' +#if LV_FS_IF_PC != '\0' - #include - #include - #include - #include - #ifdef WIN32 - #include - #endif +#include +#include +#include +#if !defined(ARDUINO_ARCH_ESP8266) && !defined(STM32F4xx) +#include +#endif +#ifdef WIN32 +#include +#endif - /********************* - * DEFINES - *********************/ - #ifndef LV_FS_PC_PATH - #ifndef WIN32 - #define LV_FS_PC_PATH "/fs" /*Projet root*/ - #else - #define LV_FS_PC_PATH ".\\" /*Projet root*/ - #endif - #endif /*LV_FS_PATH*/ +/********************* + * DEFINES + *********************/ +#ifndef LV_FS_PC_PATH +#ifndef WIN32 +#define LV_FS_PC_PATH "/fs" /*Projet root*/ +#else +#define LV_FS_PC_PATH ".\\" /*Projet root*/ +#endif +#endif /*LV_FS_PATH*/ /********************** * TYPEDEFS **********************/ /* Create a type to store the required data about your file. */ -typedef FILE * file_t; +typedef FILE* file_t; - /*Similarly to `file_t` create a type for directory reading too */ - #ifndef WIN32 -typedef DIR * dir_t; - #else +/*Similarly to `file_t` create a type for directory reading too */ +#if defined(WIN32) typedef HANDLE dir_t; - #endif +#elif defined(ARDUINO_ARCH_ESP8266) || defined(STM32F4xx) +typedef FILE* dir_t; +#else +typedef DIR* dir_t; +#endif /********************** * STATIC PROTOTYPES **********************/ -static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode); -static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p); -static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br); -static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw); -static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos); -static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p); -static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p); -static lv_fs_res_t fs_remove(lv_fs_drv_t * drv, const char * path); -static lv_fs_res_t fs_trunc(lv_fs_drv_t * drv, void * file_p); -static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char * newname); -static lv_fs_res_t fs_free(lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p); -static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * path); -static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn); -static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p); +static lv_fs_res_t fs_open(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode); +static lv_fs_res_t fs_close(lv_fs_drv_t* drv, void* file_p); +static lv_fs_res_t fs_read(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br); +static lv_fs_res_t fs_write(lv_fs_drv_t* drv, void* file_p, const void* buf, uint32_t btw, uint32_t* bw); +static lv_fs_res_t fs_seek(lv_fs_drv_t* drv, void* file_p, uint32_t pos); +static lv_fs_res_t fs_size(lv_fs_drv_t* drv, void* file_p, uint32_t* size_p); +static lv_fs_res_t fs_tell(lv_fs_drv_t* drv, void* file_p, uint32_t* pos_p); +static lv_fs_res_t fs_remove(lv_fs_drv_t* drv, const char* path); +static lv_fs_res_t fs_trunc(lv_fs_drv_t* drv, void* file_p); +static lv_fs_res_t fs_rename(lv_fs_drv_t* drv, const char* oldname, const char* newname); +static lv_fs_res_t fs_free(lv_fs_drv_t* drv, uint32_t* total_p, uint32_t* free_p); +static lv_fs_res_t fs_dir_open(lv_fs_drv_t* drv, void* dir_p, const char* path); +static lv_fs_res_t fs_dir_read(lv_fs_drv_t* drv, void* dir_p, char* fn); +static lv_fs_res_t fs_dir_close(lv_fs_drv_t* drv, void* dir_p); /********************** * STATIC VARIABLES @@ -83,7 +87,7 @@ void lv_fs_if_pc_init(void) *--------------------------------------------------*/ /* Add a simple drive to open images */ - lv_fs_drv_t fs_drv; /*A driver descriptor*/ + static lv_fs_drv_t fs_drv; /*A driver descriptor*/ lv_fs_drv_init(&fs_drv); /*Set up fields...*/ @@ -121,12 +125,12 @@ void lv_fs_if_pc_init(void) * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode) +static lv_fs_res_t fs_open(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode) { (void)drv; /*Unused*/ errno = 0; - const char * flags = ""; + const char* flags = ""; if(mode == LV_FS_MODE_WR) flags = "wb"; @@ -135,16 +139,16 @@ static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) flags = "rb+"; - /*Make the path relative to the current directory (the projects root folder)*/ + /*Make the path relative to the current directory (the projects root folder)*/ - #ifndef WIN32 +#ifndef WIN32 char buf[256]; sprintf(buf, LV_FS_PC_PATH "/%s", path); printf("%s\n", buf); - #else +#else char buf[256]; sprintf(buf, LV_FS_PC_PATH "\\%s", path); - #endif +#endif file_t f = fopen(buf, flags); if(f == NULL) { @@ -156,8 +160,8 @@ static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, /* 'file_p' is pointer to a file descriptor and * we need to store our file descriptor here*/ - file_t * fp = file_p; /*Just avoid the confusing casings*/ - *fp = f; + file_t* fp = file_p; /*Just avoid the confusing casings*/ + *fp = f; return LV_FS_RES_OK; } @@ -169,10 +173,10 @@ static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p) +static lv_fs_res_t fs_close(lv_fs_drv_t* drv, void* file_p) { - (void)drv; /*Unused*/ - file_t * fp = file_p; /*Just avoid the confusing casings*/ + (void)drv; /*Unused*/ + file_t* fp = file_p; /*Just avoid the confusing casings*/ fclose(*fp); return LV_FS_RES_OK; } @@ -187,11 +191,11 @@ static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p) * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br) +static lv_fs_res_t fs_read(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br) { - (void)drv; /*Unused*/ - file_t * fp = file_p; /*Just avoid the confusing casings*/ - *br = fread(buf, 1, btr, *fp); + (void)drv; /*Unused*/ + file_t* fp = file_p; /*Just avoid the confusing casings*/ + *br = fread(buf, 1, btr, *fp); return LV_FS_RES_OK; } @@ -204,11 +208,11 @@ static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_ * @param br the number of real written bytes (Bytes Written). NULL if unused. * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw) +static lv_fs_res_t fs_write(lv_fs_drv_t* drv, void* file_p, const void* buf, uint32_t btw, uint32_t* bw) { - (void)drv; /*Unused*/ - file_t * fp = file_p; /*Just avoid the confusing casings*/ - *bw = fwrite(buf, 1, btw, *fp); + (void)drv; /*Unused*/ + file_t* fp = file_p; /*Just avoid the confusing casings*/ + *bw = fwrite(buf, 1, btw, *fp); return LV_FS_RES_OK; } @@ -220,10 +224,10 @@ static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos) +static lv_fs_res_t fs_seek(lv_fs_drv_t* drv, void* file_p, uint32_t pos) { - (void)drv; /*Unused*/ - file_t * fp = file_p; /*Just avoid the confusing casings*/ + (void)drv; /*Unused*/ + file_t* fp = file_p; /*Just avoid the confusing casings*/ fseek(*fp, pos, SEEK_SET); return LV_FS_RES_OK; } @@ -235,10 +239,10 @@ static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos) * @param size pointer to a variable to store the size * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p) +static lv_fs_res_t fs_size(lv_fs_drv_t* drv, void* file_p, uint32_t* size_p) { - (void)drv; /*Unused*/ - file_t * fp = file_p; /*Just avoid the confusing casings*/ + (void)drv; /*Unused*/ + file_t* fp = file_p; /*Just avoid the confusing casings*/ uint32_t cur = ftell(*fp); @@ -258,11 +262,11 @@ static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p) * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) +static lv_fs_res_t fs_tell(lv_fs_drv_t* drv, void* file_p, uint32_t* pos_p) { - (void)drv; /*Unused*/ - file_t * fp = file_p; /*Just avoid the confusing casings*/ - *pos_p = ftell(*fp); + (void)drv; /*Unused*/ + file_t* fp = file_p; /*Just avoid the confusing casings*/ + *pos_p = ftell(*fp); return LV_FS_RES_OK; } @@ -272,7 +276,7 @@ static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) * @param path path of the file to delete * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_remove(lv_fs_drv_t * drv, const char * path) +static lv_fs_res_t fs_remove(lv_fs_drv_t* drv, const char* path) { (void)drv; /*Unused*/ lv_fs_res_t res = LV_FS_RES_NOT_IMP; @@ -289,10 +293,10 @@ static lv_fs_res_t fs_remove(lv_fs_drv_t * drv, const char * path) * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_trunc(lv_fs_drv_t * drv, void * file_p) +static lv_fs_res_t fs_trunc(lv_fs_drv_t* drv, void* file_p) { - (void)drv; /*Unused*/ - file_t * fp = file_p; /*Just avoid the confusing casings*/ + (void)drv; /*Unused*/ + file_t* fp = file_p; /*Just avoid the confusing casings*/ fflush(*fp); /*If not syncronized fclose can write the truncated part*/ uint32_t p = ftell(*fp); @@ -307,7 +311,7 @@ static lv_fs_res_t fs_trunc(lv_fs_drv_t * drv, void * file_p) * @param newname path with the new name * @return LV_FS_RES_OK or any error from 'fs_res_t' */ -static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char * newname) +static lv_fs_res_t fs_rename(lv_fs_drv_t* drv, const char* oldname, const char* newname) { (void)drv; /*Unused*/ static char new[512]; @@ -316,12 +320,14 @@ static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char sprintf(old, LV_FS_PC_PATH "/%s", oldname); sprintf(new, LV_FS_PC_PATH "/%s", newname); - int r = rename(old, new); + return LV_FS_RES_UNKNOWN; - if(r == 0) - return LV_FS_RES_OK; - else - return LV_FS_RES_UNKNOWN; + // int r = rename(old, new); + + // if(r == 0) + // return LV_FS_RES_OK; + // else + // return LV_FS_RES_UNKNOWN; } /** @@ -332,7 +338,7 @@ static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char * @param free_p pointer to store the free size [kB] * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_free(lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p) +static lv_fs_res_t fs_free(lv_fs_drv_t* drv, uint32_t* total_p, uint32_t* free_p) { (void)drv; /*Unused*/ lv_fs_res_t res = LV_FS_RES_NOT_IMP; @@ -342,9 +348,9 @@ static lv_fs_res_t fs_free(lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * fre return res; } - #ifdef WIN32 +#ifdef WIN32 static char next_fn[256]; - #endif +#endif /** * Initialize a 'fs_read_dir_t' variable for directory reading @@ -353,11 +359,14 @@ static char next_fn[256]; * @param path path to a directory * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * path) +static lv_fs_res_t fs_dir_open(lv_fs_drv_t* drv, void* dir_p, const char* path) { (void)drv; /*Unused*/ dir_t d; - #ifndef WIN32 +#if defined(ARDUINO_ARCH_ESP8266) || defined(STM32F4xx) + return LV_FS_RES_UNKNOWN; + +#elif !defined(WIN32) /*Make the path relative to the current directory (the projects root folder)*/ char buf[256]; sprintf(buf, LV_FS_PC_PATH "/%s", path); @@ -366,10 +375,10 @@ static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * pat } else { /* 'dir_p' is pointer to a file descriptor and * we need to store our file descriptor here*/ - dir_t * dp = dir_p; /*Just avoid the confusing casings*/ - *dp = d; + dir_t* dp = dir_p; /*Just avoid the confusing casings*/ + *dp = d; } - #else +#else d = INVALID_HANDLE_VALUE; WIN32_FIND_DATA fdata; @@ -393,10 +402,10 @@ static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * pat } } while(FindNextFileA(d, &fdata)); - dir_t * dp = dir_p; /*Just avoid the confusing casings*/ - *dp = d; + dir_t* dp = dir_p; /*Just avoid the confusing casings*/ + *dp = d; - #endif +#endif return LV_FS_RES_OK; } @@ -409,17 +418,18 @@ static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * pat * @param fn pointer to a buffer to store the filename * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn) +static lv_fs_res_t fs_dir_read(lv_fs_drv_t* drv, void* dir_p, char* fn) { - (void)drv; /*Unused*/ - dir_t * dp = dir_p; /*Just avoid the confusing casings*/ + (void)drv; /*Unused*/ + dir_t* dp = dir_p; /*Just avoid the confusing casings*/ - #ifndef WIN32 - struct dirent * entry; +#ifdef ARDUINO_ARCH_ESP32 + struct dirent* entry; do { entry = readdir(*dp); if(entry) { + if(entry->d_type == DT_DIR) sprintf(fn, "/%s", entry->d_name); else @@ -428,7 +438,9 @@ static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn) strcpy(fn, ""); } } while(strcmp(fn, "/.") == 0 || strcmp(fn, "/..") == 0); - #else +#endif + +#ifdef WIN32 strcpy(fn, next_fn); strcpy(next_fn, ""); @@ -449,7 +461,7 @@ static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn) } } while(FindNextFile(*dp, &fdata)); - #endif +#endif return LV_FS_RES_OK; } @@ -459,18 +471,21 @@ static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn) * @param dir_p pointer to an initialized 'fs_read_dir_t' variable * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p) +static lv_fs_res_t fs_dir_close(lv_fs_drv_t* drv, void* dir_p) { (void)drv; /*Unused*/ - dir_t * dp = dir_p; - #ifndef WIN32 + dir_t* dp = dir_p; +#if defined(ARDUINO_ARCH_ESP8266) || defined(STM32F4xx) + return LV_FS_RES_UNKNOWN; + +#elif !defined(WIN32) closedir(*dp); - #else +#else FindClose(*dp); *dp = INVALID_HANDLE_VALUE; - #endif +#endif return LV_FS_RES_OK; } - #endif /*LV_USE_FS_IF*/ -#endif /*LV_FS_IF_FATFS*/ +#endif /*LV_USE_FS_IF*/ +#endif /*LV_FS_IF_FATFS*/ diff --git a/lib/lv_fs_if/lv_fs_spiffs.cpp b/lib/lv_fs_if/lv_fs_spiffs.cpp index e4fe5e82..c33fb2c1 100644 --- a/lib/lv_fs_if/lv_fs_spiffs.cpp +++ b/lib/lv_fs_if/lv_fs_spiffs.cpp @@ -6,33 +6,35 @@ /********************* * INCLUDES *********************/ +#ifdef ARDUINO + #include #include "lv_fs_if.h" #include "lv_fs_spiffs.h" #include "ArduinoLog.h" #if LV_USE_FS_IF - #if LV_FS_IF_SPIFFS != '\0' +#if LV_FS_IF_SPIFFS != '\0' - #if defined(ARDUINO_ARCH_ESP32) - #if HASP_USE_SPIFFS > 0 - #include "SPIFFS.h" - #define LV_FS_SPIFFS SPIFFS - #elif HASP_USE_LITTLEFS > 0 - #include "LITTLEFS.h" - #define LV_FS_SPIFFS LITTLEFS - #endif - #elif defined(ARDUINO_ARCH_ESP8266) - #include "LittleFS.h" - #define LV_FS_SPIFFS LittleFS - #endif // ARDUINO_ARCH +#if defined(ARDUINO_ARCH_ESP32) +#if HASP_USE_SPIFFS > 0 +#include "SPIFFS.h" +#define LV_FS_SPIFFS SPIFFS +#elif HASP_USE_LITTLEFS > 0 +#include "LITTLEFS.h" +#define LV_FS_SPIFFS LITTLEFS +#endif +#elif defined(ARDUINO_ARCH_ESP8266) +#include "LittleFS.h" +#define LV_FS_SPIFFS LittleFS +#endif // ARDUINO_ARCH - #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - #include - #include - #endif // ARDUINO_ARCH +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +#include +#include +#endif // ARDUINO_ARCH - #define TAG_LVFS 91 +#define TAG_LVFS 91 /********************* * DEFINES @@ -45,34 +47,34 @@ /* Create a type to store the required data about your file.*/ typedef File lv_spiffs_file_t; - /*Similarly to `file_t` create a type for directory reading too */ - #if defined(ARDUINO_ARCH_ESP32) +/*Similarly to `file_t` create a type for directory reading too */ +#if defined(ARDUINO_ARCH_ESP32) typedef File lv_spiffs_dir_t; - #elif defined(ARDUINO_ARCH_ESP8266) +#elif defined(ARDUINO_ARCH_ESP8266) typedef Dir lv_spiffs_dir_t; - #define FILE_READ "r" - #define FILE_WRITE "r+" - #endif +#define FILE_READ "r" +#define FILE_WRITE "r+" +#endif /********************** * STATIC PROTOTYPES **********************/ static void fs_init(void); -static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode); -static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p); -static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br); -static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw); -static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos); -static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p); -static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p); -static lv_fs_res_t fs_remove(lv_fs_drv_t * drv, const char * path); -static lv_fs_res_t fs_trunc(lv_fs_drv_t * drv, void * file_p); -static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char * newname); -static lv_fs_res_t fs_free(lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p); -static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * path); -static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn); -static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p); +static lv_fs_res_t fs_open(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode); +static lv_fs_res_t fs_close(lv_fs_drv_t* drv, void* file_p); +static lv_fs_res_t fs_read(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br); +static lv_fs_res_t fs_write(lv_fs_drv_t* drv, void* file_p, const void* buf, uint32_t btw, uint32_t* bw); +static lv_fs_res_t fs_seek(lv_fs_drv_t* drv, void* file_p, uint32_t pos); +static lv_fs_res_t fs_size(lv_fs_drv_t* drv, void* file_p, uint32_t* size_p); +static lv_fs_res_t fs_tell(lv_fs_drv_t* drv, void* file_p, uint32_t* pos_p); +static lv_fs_res_t fs_remove(lv_fs_drv_t* drv, const char* path); +static lv_fs_res_t fs_trunc(lv_fs_drv_t* drv, void* file_p); +static lv_fs_res_t fs_rename(lv_fs_drv_t* drv, const char* oldname, const char* newname); +static lv_fs_res_t fs_free(lv_fs_drv_t* drv, uint32_t* total_p, uint32_t* free_p); +static lv_fs_res_t fs_dir_open(lv_fs_drv_t* drv, void* dir_p, const char* path); +static lv_fs_res_t fs_dir_read(lv_fs_drv_t* drv, void* dir_p, char* fn); +static lv_fs_res_t fs_dir_close(lv_fs_drv_t* drv, void* dir_p); /********************** * STATIC VARIABLES @@ -98,7 +100,7 @@ void lv_fs_if_spiffs_init(void) *--------------------------------------------------*/ /* Add a simple drive to open images */ - lv_fs_drv_t fs_drv; /*A driver descriptor*/ + static lv_fs_drv_t fs_drv; /*A driver descriptor*/ lv_fs_drv_init(&fs_drv); /*Set up fields...*/ @@ -142,14 +144,14 @@ static void fs_init(void) * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode) +static lv_fs_res_t fs_open(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode) { (void)drv; /*Unused*/ char filename[32]; snprintf_P(filename, sizeof(filename), PSTR("/%s"), path); - lv_spiffs_file_t * fp = (lv_spiffs_file_t *)file_p; + lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p; if(fp == NULL) return LV_FS_RES_INV_PARAM; LOG_VERBOSE(TAG_LVFS, F("Opening %s"), filename); @@ -184,10 +186,10 @@ static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p) +static lv_fs_res_t fs_close(lv_fs_drv_t* drv, void* file_p) { (void)drv; /*Unused*/ - lv_spiffs_file_t * fp = (lv_spiffs_file_t *)file_p; + lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p; if(fp == NULL) return LV_FS_RES_INV_PARAM; lv_spiffs_file_t file = *fp; @@ -215,10 +217,10 @@ static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p) * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br) +static lv_fs_res_t fs_read(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br) { (void)drv; /*Unused*/ - lv_spiffs_file_t * fp = (lv_spiffs_file_t *)file_p; + lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p; if(fp == NULL) return LV_FS_RES_INV_PARAM; lv_spiffs_file_t file = *fp; @@ -230,7 +232,7 @@ static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_ } else { // LOG_VERBOSE(TAG_LVFS, F("Reading %u bytes from %s at position %u"), btr, file.name(), file.position()); uint32_t len = 0; - char * chp = (char *)buf; + char* chp = (char*)buf; if(chp != NULL && btr > 0) len = file.readBytes(chp, btr); else @@ -255,10 +257,10 @@ static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_ * @param br the number of real written bytes (Bytes Written). NULL if unused. * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw) +static lv_fs_res_t fs_write(lv_fs_drv_t* drv, void* file_p, const void* buf, uint32_t btw, uint32_t* bw) { (void)drv; /*Unused*/ - lv_spiffs_file_t file = *(lv_spiffs_file_t *)file_p; + lv_spiffs_file_t file = *(lv_spiffs_file_t*)file_p; // File file = fp; if(!file) { @@ -266,7 +268,7 @@ static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, return LV_FS_RES_NOT_EX; } else { - *bw = (uint32_t)file.write((byte *)buf, btw); + *bw = (uint32_t)file.write((byte*)buf, btw); return LV_FS_RES_OK; } } @@ -279,10 +281,10 @@ static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos) +static lv_fs_res_t fs_seek(lv_fs_drv_t* drv, void* file_p, uint32_t pos) { (void)drv; /*Unused*/ - lv_spiffs_file_t file = *(lv_spiffs_file_t *)file_p; + lv_spiffs_file_t file = *(lv_spiffs_file_t*)file_p; // File file = fp; if(!file) { @@ -302,10 +304,10 @@ static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos) * @param size pointer to a variable to store the size * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p) +static lv_fs_res_t fs_size(lv_fs_drv_t* drv, void* file_p, uint32_t* size_p) { (void)drv; /*Unused*/ - lv_spiffs_file_t file = *(lv_spiffs_file_t *)file_p; + lv_spiffs_file_t file = *(lv_spiffs_file_t*)file_p; // File file = fp; if(!file) { @@ -326,10 +328,10 @@ static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p) * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) +static lv_fs_res_t fs_tell(lv_fs_drv_t* drv, void* file_p, uint32_t* pos_p) { (void)drv; /*Unused*/ - lv_spiffs_file_t file = *(lv_spiffs_file_t *)file_p; + lv_spiffs_file_t file = *(lv_spiffs_file_t*)file_p; // File file = fp; if(!file) { @@ -348,7 +350,7 @@ static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) * @param path path of the file to delete * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_remove(lv_fs_drv_t * drv, const char * path) +static lv_fs_res_t fs_remove(lv_fs_drv_t* drv, const char* path) { (void)drv; /*Unused*/ @@ -373,7 +375,7 @@ static lv_fs_res_t fs_remove(lv_fs_drv_t * drv, const char * path) * @return LV_FS_RES_OK: no error, the file is read * any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_trunc(lv_fs_drv_t * drv, void * file_p) +static lv_fs_res_t fs_trunc(lv_fs_drv_t* drv, void* file_p) { return LV_FS_RES_NOT_IMP; } @@ -385,7 +387,7 @@ static lv_fs_res_t fs_trunc(lv_fs_drv_t * drv, void * file_p) * @param newname path with the new name * @return LV_FS_RES_OK or any error from 'fs_res_t' */ -static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char * newname) +static lv_fs_res_t fs_rename(lv_fs_drv_t* drv, const char* oldname, const char* newname) { (void)drv; /*Unused*/ char fromname[32]; @@ -409,23 +411,23 @@ static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char * @param free_p pointer to store the free size [kB] * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_free(lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p) +static lv_fs_res_t fs_free(lv_fs_drv_t* drv, uint32_t* total_p, uint32_t* free_p) { (void)drv; /*Unused*/ - #if defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) FSInfo fs_info; LV_FS_SPIFFS.info(fs_info); *total_p = (uint32_t)fs_info.totalBytes; *free_p = (uint32_t)fs_info.totalBytes - fs_info.usedBytes; return LV_FS_RES_OK; - #elif defined(ARDUINO_ARCH_ESP32) +#elif defined(ARDUINO_ARCH_ESP32) *total_p = (uint32_t)LV_FS_SPIFFS.totalBytes(); *free_p = (uint32_t)LV_FS_SPIFFS.totalBytes() - LV_FS_SPIFFS.usedBytes(); return LV_FS_RES_OK; - #endif +#endif return LV_FS_RES_NOT_IMP; } @@ -437,23 +439,23 @@ static lv_fs_res_t fs_free(lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * fre * @param path path to a directory * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * path) +static lv_fs_res_t fs_dir_open(lv_fs_drv_t* drv, void* dir_p, const char* path) { lv_spiffs_dir_t dir; - #if defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP32) dir = LV_FS_SPIFFS.open(path); if(!dir) { return LV_FS_RES_UNKNOWN; } - #endif +#endif - #if defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) dir = LV_FS_SPIFFS.openDir(path); - #endif +#endif - lv_spiffs_dir_t * dp = (lv_spiffs_dir_t *)dir_p; /*Just avoid the confusing casings*/ - *dp = dir; + lv_spiffs_dir_t* dp = (lv_spiffs_dir_t*)dir_p; /*Just avoid the confusing casings*/ + *dp = dir; return LV_FS_RES_OK; } @@ -465,11 +467,11 @@ static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * pat * @param fn pointer to a buffer to store the filename * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn) +static lv_fs_res_t fs_dir_read(lv_fs_drv_t* drv, void* dir_p, char* fn) { - lv_spiffs_dir_t dir = *(lv_spiffs_dir_t *)dir_p; /*Convert type*/ + lv_spiffs_dir_t dir = *(lv_spiffs_dir_t*)dir_p; /*Convert type*/ - #if defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP32) File file = dir.openNextFile(); if(file) { strcpy(fn, file.name()); @@ -477,16 +479,16 @@ static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn) } else { return LV_FS_RES_UNKNOWN; } - #endif +#endif - #if defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) if(dir.next()) { strcpy(fn, dir.fileName().c_str()); return LV_FS_RES_OK; } else { return LV_FS_RES_UNKNOWN; } - #endif +#endif return LV_FS_RES_NOT_IMP; } @@ -497,10 +499,12 @@ static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn) * @param dir_p pointer to an initialized 'fs_read_dir_t' variable * @return LV_FS_RES_OK or any error from lv_fs_res_t enum */ -static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p) +static lv_fs_res_t fs_dir_close(lv_fs_drv_t* drv, void* dir_p) { return LV_FS_RES_OK; } - #endif /*LV_USE_FS_IF*/ -#endif /*LV_FS_IF_SPIFFS*/ +#endif /*LV_USE_FS_IF*/ +#endif /*LV_FS_IF_SPIFFS*/ + +#endif /*ARDUINO*/ \ No newline at end of file diff --git a/lib/lv_lib_zifont/README.md b/lib/lv_lib_zifont/README.md index 380987b3..1b374cd1 100644 --- a/lib/lv_lib_zifont/README.md +++ b/lib/lv_lib_zifont/README.md @@ -15,7 +15,7 @@ Obtain or create a font file: lv_zifont_init(); static lv_font_t font1; - lv_zifont_font_init(&font1, "./notosans_32.zi", 0); + lv_zifont_font_init(&font1, "/notosans_32.zi", 0); static lv_style_t ft_style; lv_style_copy(&ft_style, &lv_style_plain); diff --git a/lib/lv_lib_zifont/lv_zifont.cpp b/lib/lv_lib_zifont/lv_zifont.cpp index 90e586b1..176c26a4 100644 --- a/lib/lv_lib_zifont/lv_zifont.cpp +++ b/lib/lv_lib_zifont/lv_zifont.cpp @@ -1,6 +1,9 @@ /********************* * INCLUDES *********************/ + +#if !(defined(WINDOWS) || defined(POSIX)) + #include #include @@ -52,8 +55,8 @@ enum zifont_codepage_t8_t { ASCII = 0x01, ISO_8859_1 = 0x03, UTF_8 = 0x18 }; /********************** * STATIC PROTOTYPES **********************/ -const uint8_t * IRAM_ATTR lv_font_get_bitmap_fmt_zifont(const lv_font_t * font, uint32_t unicode_letter); -bool IRAM_ATTR lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, +const uint8_t* IRAM_ATTR lv_font_get_bitmap_fmt_zifont(const lv_font_t* font, uint32_t unicode_letter); +bool IRAM_ATTR lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t* font, lv_font_glyph_dsc_t* dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next); /********************** @@ -70,7 +73,7 @@ lv_zifont_char_t lastCharInfo; // Holds the last Glyph DSC #define CHAR_CACHE_SIZE 95 // static lv_zifont_char_t charCache[256 - 32]; // glyphID DSC cache #endif -static uint8_t * charBitmap_p; +static uint8_t* charBitmap_p; /********************** * MACROS @@ -80,18 +83,19 @@ static uint8_t * charBitmap_p; * GLOBAL FUNCTIONS **********************/ -static void IRAM_ATTR blackAdd(uint8_t * charBitmap_p, uint16_t pos); -static void IRAM_ATTR colorsAdd(uint8_t * charBitmap_p, uint8_t color1, uint16_t pos); +static void IRAM_ATTR blackAdd(uint8_t* charBitmap_p, uint16_t pos); +static void IRAM_ATTR colorsAdd(uint8_t* charBitmap_p, uint8_t color1, uint16_t pos); // static uint16_t unicode2codepoint(uint32_t unicode, uint8_t codepage); // static void printBuffer(uint8_t * charBitmap_p, uint8_t w, uint8_t h); int lv_zifont_init(void) { + // FS.begin(true); // charBitmap_p = (uint8_t *)lv_mem_alloc(32 * 32); return LV_RES_OK; // OK } -static inline bool openFont(File & file, const char * filename) +static inline bool openFont(File& file, const char* filename) { if(*filename != '/') return false; @@ -100,6 +104,7 @@ static inline bool openFont(File & file, const char * filename) LOG_ERROR(TAG_FONT, F("Opening font: %s"), filename); return false; } + // LOG_TRACE(TAG_FONT, F("Opening font: %s"), filename); return file; } @@ -107,7 +112,7 @@ static inline bool initCharacterFrame(size_t size) { if(size > _lv_mem_get_size(charBitmap_p)) { lv_mem_free(charBitmap_p); - charBitmap_p = (uint8_t *)lv_mem_alloc(size); + charBitmap_p = (uint8_t*)lv_mem_alloc(size); LOG_WARNING(TAG_FONT, F("Pixel buffer is %d bytes"), _lv_mem_get_size(charBitmap_p)); } @@ -120,29 +125,34 @@ static inline bool initCharacterFrame(size_t size) } } -int lv_zifont_font_init(lv_font_t ** font, const char * font_path, uint16_t size) +int lv_zifont_font_init(lv_font_t** font, const char* font_path, uint16_t size) { charInBuffer = 0; // invalidate any previous cache + LOG_TRACE(TAG_FONT, F("File %s - Line %d - lv_zifont_font_init"), __FILE__, __LINE__); if(!*font) { - *font = (lv_font_t *)lv_mem_alloc(sizeof(lv_font_t)); + LOG_TRACE(TAG_FONT, F("File %s - Line %d - init font"), __FILE__, __LINE__); + *font = (lv_font_t*)lv_mem_alloc(sizeof(lv_font_t)); LV_ASSERT_MEM(*font); _lv_memset_00(*font, sizeof(lv_font_t)); // lv_mem_alloc might be dirty } - lv_font_fmt_zifont_dsc_t * dsc; + lv_font_fmt_zifont_dsc_t* dsc; if(!(*font)->dsc) { - dsc = (lv_font_fmt_zifont_dsc_t *)lv_mem_alloc(sizeof(lv_font_fmt_zifont_dsc_t)); + LOG_TRACE(TAG_FONT, F("File %s - Line %d - init font dsc"), __FILE__, __LINE__); + dsc = (lv_font_fmt_zifont_dsc_t*)lv_mem_alloc(sizeof(lv_font_fmt_zifont_dsc_t)); LV_ASSERT_MEM(dsc); _lv_memset_00(dsc, sizeof(lv_font_fmt_zifont_dsc_t)); // lv_mem_alloc might be dirty + dsc->ascii_glyph_dsc = NULL; } else { - dsc = (lv_font_fmt_zifont_dsc_t *)(*font)->dsc; + LOG_TRACE(TAG_FONT, F("File %s - Line %d - reuse font dsc"), __FILE__, __LINE__); + dsc = (lv_font_fmt_zifont_dsc_t*)(*font)->dsc; } LV_ASSERT_MEM(dsc); if(!dsc) return ZIFONT_ERROR_OUT_OF_MEMORY; /* Initialize Last Glyph DSC */ - dsc->last_glyph_dsc = (lv_zifont_char_t *)lv_mem_alloc(sizeof(lv_zifont_char_t)); + dsc->last_glyph_dsc = (lv_zifont_char_t*)lv_mem_alloc(sizeof(lv_zifont_char_t)); _lv_memset_00(dsc->last_glyph_dsc, sizeof(lv_zifont_char_t)); // lv_mem_alloc might be dirty if(dsc->last_glyph_dsc == NULL) return ZIFONT_ERROR_OUT_OF_MEMORY; @@ -155,7 +165,9 @@ int lv_zifont_font_init(lv_font_t ** font, const char * font_path, uint16_t size /* Read file header as dsc */ zi_font_header_t header; - size_t readSize = file.readBytes((char *)&header, sizeof(zi_font_header_t)); + size_t readSize = file.readBytes((char*)&header, sizeof(zi_font_header_t)); + + LOG_TRACE(TAG_FONT, F("File %s - Line %d"), __FILE__, __LINE__); /* Check that we read the correct size */ if(readSize != sizeof(zi_font_header_t)) { @@ -164,6 +176,8 @@ int lv_zifont_font_init(lv_font_t ** font, const char * font_path, uint16_t size return ZIFONT_ERROR_READING_DATA; } + LOG_TRACE(TAG_FONT, F("File %s - Line %d"), __FILE__, __LINE__); + /* Check ziFile Header Format */ if(header.Password != 4 || header.Version != 5) { LOG_ERROR(TAG_FONT, F("Unknown font file format")); @@ -171,6 +185,8 @@ int lv_zifont_font_init(lv_font_t ** font, const char * font_path, uint16_t size return ZIFONT_ERROR_UNKNOWN_HEADER; } + LOG_TRACE(TAG_FONT, F("File %s - Line %d"), __FILE__, __LINE__); + dsc->CharHeight = header.CharHeight; dsc->CharWidth = header.CharWidth; dsc->Maximumnumchars = header.Maximumnumchars; @@ -179,20 +195,33 @@ int lv_zifont_font_init(lv_font_t ** font, const char * font_path, uint16_t size dsc->Startdataaddress = header.Startdataaddress + header.Descriptionlength; dsc->Fontdataadd8byte = header.Fontdataadd8byte; - if(!dsc->ascii_glyph_dsc) { - dsc->ascii_glyph_dsc = (lv_zifont_char_t *)lv_mem_alloc(sizeof(lv_zifont_char_t) * CHAR_CACHE_SIZE); + LOG_TRACE(TAG_FONT, F("File %s - Line %d - %d"), __FILE__, __LINE__, dsc->ascii_glyph_dsc); + + if(dsc->ascii_glyph_dsc == NULL) { + LOG_TRACE(TAG_FONT, F("File %s - Line %d - ascii_glyph_dsc init"), __FILE__, __LINE__); + dsc->ascii_glyph_dsc = (lv_zifont_char_t*)lv_mem_alloc(sizeof(lv_zifont_char_t) * CHAR_CACHE_SIZE); LV_ASSERT_MEM(dsc->ascii_glyph_dsc); _lv_memset_00(dsc->ascii_glyph_dsc, sizeof(lv_zifont_char_t) * CHAR_CACHE_SIZE); // lv_mem_alloc might be dirty } + + LOG_TRACE(TAG_FONT, F("File %s - Line %d"), __FILE__, __LINE__); + if(dsc->ascii_glyph_dsc == NULL) { file.close(); return ZIFONT_ERROR_OUT_OF_MEMORY; } + LOG_TRACE(TAG_FONT, F("File %s - Line %d - Seerkset: %d"), __FILE__, __LINE__, dsc->Startdataaddress); + /* read charmap into cache */ file.seek(0 * sizeof(zi_font_header_t) + dsc->Startdataaddress, SeekSet); + + LOG_TRACE(TAG_FONT, F("File %s - Line %d"), __FILE__, __LINE__); + //* read and fill charmap cache - readSize = file.readBytes((char *)dsc->ascii_glyph_dsc, sizeof(lv_zifont_char_t) * CHAR_CACHE_SIZE); + readSize = file.readBytes((char*)dsc->ascii_glyph_dsc, sizeof(lv_zifont_char_t) * CHAR_CACHE_SIZE); + + LOG_TRACE(TAG_FONT, F("File %s - Line %d"), __FILE__, __LINE__); //* Check that we read the correct size if(readSize != sizeof(lv_zifont_char_t) * CHAR_CACHE_SIZE) { @@ -233,9 +262,11 @@ int lv_zifont_font_init(lv_font_t ** font, const char * font_path, uint16_t size /* header data struct */ /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ (*font)->subpx = 0; - if((*font)->user_data != (char *)font_path) { + LOG_TRACE(TAG_FONT, F("File %s - Line %d"), __FILE__, __LINE__); + + if((*font)->user_data != (char*)font_path) { if((*font)->user_data) free((*font)->user_data); - (*font)->user_data = (char *)font_path; + (*font)->user_data = (char*)font_path; } return ZIFONT_NO_ERROR; @@ -251,7 +282,7 @@ int lv_zifont_font_init(lv_font_t ** font, const char * font_path, uint16_t size * @param unicode_letter an unicode letter which bitmap should be get * @return pointer to the bitmap or NULL if not found */ -const uint8_t * IRAM_ATTR lv_font_get_bitmap_fmt_zifont(const lv_font_t * font, uint32_t unicode_letter) +const uint8_t* IRAM_ATTR lv_font_get_bitmap_fmt_zifont(const lv_font_t* font, uint32_t unicode_letter) { /* Bitmap still in buffer */ if(charInBuffer == unicode_letter && charBitmap_p) { @@ -260,8 +291,8 @@ const uint8_t * IRAM_ATTR lv_font_get_bitmap_fmt_zifont(const lv_font_t * font, return charBitmap_p; } - lv_font_fmt_zifont_dsc_t * fdsc = (lv_font_fmt_zifont_dsc_t *)font->dsc; /* header data struct */ - lv_zifont_char_t * charInfo; + lv_font_fmt_zifont_dsc_t* fdsc = (lv_font_fmt_zifont_dsc_t*)font->dsc; /* header data struct */ + lv_zifont_char_t* charInfo; /* Space */ if(unicode_letter == 0x20) { @@ -286,7 +317,7 @@ const uint8_t * IRAM_ATTR lv_font_get_bitmap_fmt_zifont(const lv_font_t * font, charmap_position = 25 + sizeof(zi_font_header_t); glyphID = unicode_letter - 0xf000; // start of fontawesome } else { - strcpy(filename, (char *)font->user_data); + strcpy(filename, (char*)font->user_data); charmap_position = fdsc->Startdataaddress; glyphID = unicode_letter - 0x20; // simple unicode to ascii - space is charNum=0 } @@ -300,11 +331,11 @@ const uint8_t * IRAM_ATTR lv_font_get_bitmap_fmt_zifont(const lv_font_t * font, } else { Serial.print("%"); /* Read Character Table */ - charInfo = (lv_zifont_char_t *)lv_mem_alloc(sizeof(lv_zifont_char_t)); + charInfo = (lv_zifont_char_t*)lv_mem_alloc(sizeof(lv_zifont_char_t)); // lv_memset(charInfo, 0x00, sizeof(lv_zifont_char_t)); // lv_mem_alloc might be dirty uint32_t char_position = glyphID * sizeof(lv_zifont_char_t) + charmap_position; file.seek(char_position, SeekSet); - size_t readSize = file.readBytes((char *)charInfo, sizeof(lv_zifont_char_t)); + size_t readSize = file.readBytes((char*)charInfo, sizeof(lv_zifont_char_t)); /* Check that we read the correct size */ if(readSize != sizeof(lv_zifont_char_t)) { @@ -438,7 +469,7 @@ const uint8_t * IRAM_ATTR lv_font_get_bitmap_fmt_zifont(const lv_font_t * font, * @return true: descriptor is successfully loaded into `dsc_out`. * false: the letter was not found, no data is loaded to `dsc_out` */ -bool IRAM_ATTR lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, +bool IRAM_ATTR lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t* font, lv_font_glyph_dsc_t* dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next) { /* Only ascii characteres supported for now */ @@ -449,7 +480,7 @@ bool IRAM_ATTR lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t * font, lv_font_ // if(unicode_letter > 0xff) Serial.printf("Char# %u\n", unicode_letter); // ulong startMillis = millis(); - lv_font_fmt_zifont_dsc_t * fdsc = (lv_font_fmt_zifont_dsc_t *)font->dsc; /* header data struct */ + lv_font_fmt_zifont_dsc_t* fdsc = (lv_font_fmt_zifont_dsc_t*)font->dsc; /* header data struct */ uint16_t glyphID; File file; @@ -479,7 +510,7 @@ bool IRAM_ATTR lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t * font, lv_font_ snprintf_P(filename, sizeof(filename), PSTR("/fontawesome%u.zi"), fdsc->CharHeight); if(!openFont(file, filename)) return false; } else { - if(!openFont(file, (char *)font->user_data)) return false; + if(!openFont(file, (char*)font->user_data)) return false; } /* read 10 bytes charmap */ @@ -487,7 +518,7 @@ bool IRAM_ATTR lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t * font, lv_font_ lv_zifont_char_t myCharIndex; uint32_t char_position = glyphID * sizeof(lv_zifont_char_t) + charmap_position; file.seek(char_position, SeekSet); - size_t readSize = file.readBytes((char *)&myCharIndex, sizeof(lv_zifont_char_t)); + size_t readSize = file.readBytes((char*)&myCharIndex, sizeof(lv_zifont_char_t)); file.close(); /* Check that we read the correct size */ @@ -533,7 +564,7 @@ bool IRAM_ATTR lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t * font, lv_font_ return true; } -static void IRAM_ATTR blackAdd(uint8_t * charBitmap_p, uint16_t pos) +static void IRAM_ATTR blackAdd(uint8_t* charBitmap_p, uint16_t pos) { uint8_t col = pos & 0x0001; // remainder uint16_t map_p = pos >> 1; // devide by 2 @@ -545,7 +576,7 @@ static void IRAM_ATTR blackAdd(uint8_t * charBitmap_p, uint16_t pos) } } -static inline void IRAM_ATTR colorsAdd(uint8_t * charBitmap_p, uint8_t color1, uint16_t pos) +static inline void IRAM_ATTR colorsAdd(uint8_t* charBitmap_p, uint8_t color1, uint16_t pos) { uint32_t col = pos & 0x0001; // remainder uint32_t map_p = pos >> 1; // devide by 2 @@ -557,6 +588,8 @@ static inline void IRAM_ATTR colorsAdd(uint8_t * charBitmap_p, uint8_t color1, u } } +#endif + /* void printPixel(uint8_t pixel) { diff --git a/platformio.ini b/platformio.ini index afc289b4..03fc69ac 100644 --- a/platformio.ini +++ b/platformio.ini @@ -34,14 +34,13 @@ extra_default_envs = ; Common environment settings ;*************************************************** [env] -framework = arduino upload_speed = 921600 monitor_speed = 115200 build_flags = -D PIOENV=\"${PIOENV}\" - ;-Os ; Code Size Optimization - -Og ; Code Debug Optimization + -Os ; Code Size Optimization + ;-Og ; Code Debug Optimization ;-w ; Suppress warnings -D CORE_DEBUG_LEVEL=0 ; 0=Silent, 1=Errors, 2=Warnings -I include ; include lv_conf.h and hasp_conf.h @@ -49,11 +48,10 @@ build_flags = -D LV_CONF_INCLUDE_SIMPLE ; for lvgl -D LV_LVGL_H_INCLUDE_SIMPLE ; for lv_drivers -D LV_COMP_CONF_INCLUDE_SIMPLE ; for components - ; -- littlevgl build options ------------------------------ + ; -- ESP build options ------------------------------------ -D SPIFFS_TEMPORAL_FD_CACHE ; speedup opening recent files ; -- ArduinoJson build options ---------------------------- -D ARDUINOJSON_DECODE_UNICODE=1 ; for utf-8 symbols - -D ARDUINOJSON_ENABLE_PROGMEM=1 ; for PROGMEM arguments ; -- StreamUtils build options ---------------------------- -D STREAMUTILS_ENABLE_EEPROM=1 ; for STM32, it also supports EEPROM @@ -63,21 +61,20 @@ build_flags = -D HASP_VER_MIN=4 -D HASP_VER_REV=0 -D HASP_LOG_LEVEL=9 - -D HASP_USE_CONFIG=1 ; Native application, not library ${override.build_flags} ; -- Shared library dependencies in all environments ; Warning : don't put comments after github links => causes infinite download loop lib_deps = bxparks/AceButton@^1.8.2 ; GPIO button library - bblanchon/ArduinoJson@^6.17.2 ; Json(l) parser + bblanchon/ArduinoJson@^6.17.3 ; Json(l) parser bblanchon/StreamUtils@1.6.0 ; for EEPromStream knolleary/PubSubClient@^2.8.0 ; MQTT client git+https://github.com/fvanroie/ConsoleInput.git ;git+https://github.com/andrethomas/TasmotaSlave.git ;git+https://github.com/fvanroie/lv_components.git - git+https://github.com/lvgl/lvgl.git - ;lvgl/lvgl @ ^7.7.2 ; from PIO library + ;git+https://github.com/lvgl/lvgl.git + lvgl/lvgl @^7.11.0 ; from PIO library ;bodmer/TFT_eSPI @ 2.3.4 ; Tft SPI drivers EXACT version 2.3.5 has compile error git+https://github.com/Bodmer/TFT_eSPI.git ; ------ Unused / Test libraries @@ -89,10 +86,25 @@ lib_deps = src_filter = +<*> -<.git/> - - - - - -extra_scripts = tools/copy_fw.py ; tools/pre:extra_script.py ; -- Platform specific build flags [esp32] +framework = arduino +platform = espressif32 + +board_upload.flash_size=4MB +board_upload.maximum_size = 4194304 +board_build.partitions = user_setups/esp32/partition_app1704k_spiffs720k.csv + +; ----- crash reporter +monitor_filters = esp32_exception_decoder + +; ----- debugger +check_tool = cppcheck +check_flags = --enable=all +debug_tool = esp-prog +debug_init_break = tbreak setup + build_flags = ${env.build_flags} -D HTTP_UPLOAD_BUFLEN=1024 ; lower http upload buffer @@ -101,13 +113,16 @@ build_flags = -D NO_GLOBAL_HTTPUPDATE ; dont instantiate httpUpdate ; -- lvgl build options ----------------------------- -D LV_MEM_SIZE=61440U ; 60kB lvgl memory +; -- ArduinoJson build options ---------------------------- + -D ARDUINOJSON_ENABLE_PROGMEM=1 ; for PROGMEM arguments ; -- tft_espi build options ------------------------ ;-D USE_DMA_TO_TFT ; -- hasp-lvgl build options ------------------------ - ;-D HASP_USE_TELNET=1 + -D HASP_USE_TELNET=1 ;-D HASP_USE_SPIFFS=1 -D HASP_USE_LITTLEFS=1 ;-D HASP_USE_EEPROM=1 + -D HASP_USE_CONFIG=1 ; Native application, not library ; -- LittleFS build options ------------------------ -D CONFIG_LITTLEFS_FOR_IDF_3_2 @@ -130,10 +145,10 @@ ps_ram = -mfix-esp32-psram-cache-issue extra_scripts = - ${env.extra_scripts} - tools/copy_partitions.py + tools/esp_merge_bin.py tools/analyze_elf.py - +; ${env.extra_scripts} +; tools/copy_partitions.py ; -- The ESP32 has 2 SPI Hardware Busses available to use: vspi = @@ -146,23 +161,40 @@ hspi = -D TFT_SCLK=14 [esp8266] +framework = arduino +platform = espressif8266 + +board_build.f_flash = 40000000L +board_build.flash_mode = dout +board_build.ldscript = eagle.flash.4m2m.ld ; 2Mb Spiffs +board_build.f_cpu = 160000000L ; set frequency to 160MHz + +; ----- crash reporter +monitor_filters = esp8266_exception_decoder + build_flags= - -D HTTP_UPLOAD_BUFLEN=512 ; lower http upload buffer - -D MQTT_MAX_PACKET_SIZE=1024 ; longer PubSubClient messages - -D HASP_CONSOLE_BUFFER=160 ; maximum length of a console/telnet command - -D ATOMIC_FS_UPDATE ; enabled compressed ota updates - -D NO_GLOBAL_HTTPUPDATE ; dont instantiate httpUpdate + -D HTTP_UPLOAD_BUFLEN=512 ; lower http upload buffer + -D MQTT_MAX_PACKET_SIZE=1024 ; longer PubSubClient messages + -D HASP_CONSOLE_BUFFER=160 ; maximum length of a console/telnet command + -D ATOMIC_FS_UPDATE ; enabled compressed ota updates + -D NO_GLOBAL_HTTPUPDATE ; dont instantiate httpUpdate ; -- lwIP Variant ----------------------------------- ;-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY ; -- lvgl build options ----------------------------- - -D LV_MEM_SIZE=12288U ; 12kB lvgl memory + -D LV_MEM_SIZE=12288U ; 12kB lvgl memory +; -- ArduinoJson build options ---------------------------- + -D ARDUINOJSON_ENABLE_PROGMEM=1 ; for PROGMEM arguments + -D ARDUINOJSON_ENABLE_STD_STRING=1 ; for std::string ; -- hasp-lvgl build options ------------------------ - ;-D HASP_USE_TELNET=1 + -D HASP_USE_TELNET=1 ;-D HASP_USE_SPIFFS=1 -D HASP_USE_LITTLEFS=1 -D HASP_USE_EEPROM=1 -D HASP_USE_ETHERNET=0 + -D HASP_USE_CONFIG=1 ; Native application, not library + +extra_scripts = tools/copy_fw.py ; tools/pre:extra_script.py lib_ignore = ESP32 BLE Arduino @@ -173,49 +205,28 @@ lib_ignore = lib_deps = + [stm32f4] +framework = arduino +platform = ststm32 build_flags= -I include/stm32f4 - -D MQTT_MAX_PACKET_SIZE=2048 ; longer PubSubClient messages - -D HASP_CONSOLE_BUFFER=220 ; maximum length of a console/telnet command - -D IRAM_ATTR= ; No IRAM_ATTR available on STM32 + -D MQTT_MAX_PACKET_SIZE=2048 ; longer PubSubClient messages + -D HASP_CONSOLE_BUFFER=220 ; maximum length of a console/telnet command + -D IRAM_ATTR= ; No IRAM_ATTR available on STM32 -D ICACHE_RAM_ATTR= -D STM32 + -D ARDUINOJSON_DECODE_UNICODE=1 ; for utf-8 symbols + -D ARDUINOJSON_ENABLE_PROGMEM=1 ; for PROGMEM arguments -D STREAMUTILS_USE_EEPROM_UPDATE=1 ; update cell only when changed ; -- lvgl build options ----------------------------- - -D LV_MEM_SIZE=20480U ; 20kB lvgl memory - -D HASP_USE_SYSLOG=0 ; Needs UDP + -D LV_MEM_SIZE=20480U ; 20kB lvgl memory + -D HASP_USE_SYSLOG=0 ; Needs UDP -D HASP_USE_SPIFFS=0 -D HASP_USE_LITTLEFS=0 + -D HASP_USE_CONFIG=1 ; Native application, not library lib_deps = ; sstaub/Ticker @ ^3.2.0 stm32duino/STM32duino LwIP @ ^2.1.2 ;https://github.com/stm32duino/LwIP.git - - -;*************************************************** -; Native build -;*************************************************** -;[env:native] -;platform = native -;build_flags = -; -D LV_CONF_INCLUDE_SIMPLE -; ; -I src Required to find lv_conf.h -; -I src -; -I drivers/sdl2 -; -lSDL2 -; ; SDL drivers options -; -D LV_LVGL_H_INCLUDE_SIMPLE -; -D LV_DRV_NO_CONF -; -D USE_MONITOR -; -D MONITOR_ZOOM=2 -; -D USE_MOUSE -; -D USE_MOUSEWHEEL -; -D USE_KEYBOARD -;lib_deps = -; ;lvgl=https://github.com/littlevgl/lvgl/archive/master.zip -; ;lvgl@^6.1.0 -; ;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/master.zip -; lv_drivers@^6.0.2 -;src_filter = +<*> +<../drivers/sdl2> diff --git a/platformio_override-template.ini b/platformio_override-template.ini index 46731383..7202556b 100644 --- a/platformio_override-template.ini +++ b/platformio_override-template.ini @@ -6,14 +6,17 @@ [platformio] extra_configs = ; Uncomment or edit the lines to show more User Setups in the PIO sidebar + ; user_setups/darwin_sdl/*.ini ; user_setups/esp32/*.ini ; user_setups/esp8266/*.ini + ; user_setups/linux_sdl/*.ini ; user_setups/stm32f4xx/*.ini - + ; user_setups/win32/*.ini + [override] ; -- Hasp config options -------------------------------------- build_flags = -; -- Uncomment the next line to use the file src/user_config_override.h settings +; -- Uncomment the next line to use the file include/user_config_override.h settings ; -DUSE_CONFIG_OVERRIDE ;region -- Default Build Environments : Used when Build All --- @@ -21,15 +24,16 @@ extra_default_envs = ; Comment unneeded environments or create extra ; d1-mini-esp32_ili9341 ; d1-mini-esp8266_ili9341 - ; lolind32pro-lolintft24 - ; esp32dev-mrb3511 - ; esp12e-st7735 ; d132-unoshield - ; nodemcu32s-raspi + ; esp12e-st7735 + ; esp32dev-mrb3511 ; esp32dev-ili9488 ; lanbon_l8 - ; wt32-sc01 + ; lolin-d32-pro_ili9341 ; my_custom_build + ; nodemcu32s-raspi + ; wt32-sc01 + ; ttgo_esp32_poe-ili9341 ;endregion ;region -- Define your local COM ports for each environment --- @@ -52,36 +56,43 @@ upload_port = 192.168.4.4 ; IP of the ESP upload_protocol = espota ; Use ArduinoOTA after flashing over serial upload_flags = --port=3232 ; --auth=haspadmin ; OTA password -[env:ttgo_esp32_poe-lolintft24] +[env:ttgo_esp32_poe-ili9341] monitor_port = COM9 ; Change to the correct port -;upload_port = ${env:ttgo_esp32_poe-lolintft24.monitor_port} +;upload_port = ${env:ttgo_esp32_poe-ili9341.monitor_port} upload_port = 192.168.4.5 ; IP of the ESP upload_protocol = espota ; Use ArduinoOTA after flashing over serial upload_flags = --port=3232 ; --auth=haspadmin ; OTA password -[env:lolind32pro-lolintft24] -monitor_port = COM3 ; Change to the correct port -upload_port = ${env:lolind32pro-lolintft24.monitor_port} +[env:lolin-d32-pro_ili9341] +monitor_port = COM5 ; Change to the correct port +upload_port = ${env:lolin-d32-pro_ili9341.monitor_port} ;endregion ;region -- Custom Environment configuration example ----------------- [env:my_custom_build] -platform = espressif32 +extends = esp32 board = nodemcu-32s -monitor_port = COM3 -upload_port = ${env:my_custom_build.monitor_port} + +upload_port = COM12 ; To change the port, use platform_override.ini +monitor_port = COM12 ; To change the port, use platform_override.ini + +board_build.partitions = user_setups/esp32/partition_app1536k_spiffs1024k.csv ; default.csv + debug_tool = esp-prog debug_init_break = tbreak setup build_flags = + ${env.build_flags} ${esp32.build_flags} ;region -- TFT_eSPI build options ----------------------------------- - ${lcd.raspberrypi} + ${lcd.lolin24} ${esp32.vspi} - -D TFT_CS=5 - -D TFT_DC=4 - -D TFT_RST=32 - -D TFT_BCKL=-1 ; None, configurable via web UI (e.g. 21) - -D TOUCH_CS=22 + -D TFT_DC=5 + -D TFT_CS=26 + -D TFT_RST=-1 ; RST + -D TFT_BCKL=22 ; None, configurable via web UI (e.g. 21) + -D TOUCH_CS=17 ; (can also be 22 or 16) +; -- Options ---------------------------------------- + -D HASP_USE_TELNET=1 ;endregion ;endregion \ No newline at end of file diff --git a/src/dev/device.cpp b/src/dev/device.cpp index 99e49f86..395a6e43 100644 --- a/src/dev/device.cpp +++ b/src/dev/device.cpp @@ -1,9 +1,2 @@ -#include "device.h" - -#if defined(LANBONL8) - #warning Lanbon L8 -#elif defined(M5STACK) - #warning M5 Stack -#else -dev::BaseDevice haspDevice; -#endif \ No newline at end of file +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ diff --git a/src/dev/device.h b/src/dev/device.h index 98250540..4f6ae713 100644 --- a/src/dev/device.h +++ b/src/dev/device.h @@ -1,14 +1,50 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_DEVICE_H #define HASP_DEVICE_H +#ifdef ARDUINO +#include "Arduino.h" +#endif + +#if defined(WINDOWS) || defined(POSIX) +#include +#endif +#if defined(POSIX) +#include +#endif +#ifdef WINDOWS +#include "Windows.h" +#endif + namespace dev { class BaseDevice { public: - virtual void pre_setup() + bool has_battery = false; + bool has_backligth_control = true; + + virtual void reboot() + {} + virtual const char* get_hostname() + { + return ""; + } + virtual void set_hostname(const char*) + {} + virtual const char* get_core_version() + { + return ""; + } + virtual const char* get_chip_model() + { + return ""; + } + + virtual void init() + {} + virtual void show_info() {} virtual void post_setup() {} @@ -16,20 +52,64 @@ class BaseDevice { {} virtual void loop_5s() {} + virtual void set_backlight_pin(uint8_t pin) + {} + virtual void set_backlight_level(uint8_t level) + {} + virtual uint8_t get_backlight_level() + { + return -1; + } + virtual void set_backlight_power(bool power) + {} + virtual bool get_backlight_power() + { + return true; + } + virtual size_t get_free_max_block() + { + return 0; + } + virtual size_t get_free_heap() + { + return 0; + } + virtual uint8_t get_heap_fragmentation() + { + return 0; + } + virtual uint16_t get_cpu_frequency() + { + return 0; + } + virtual bool is_system_pin(uint8_t pin) + { + return false; + } }; } // namespace dev -using dev::BaseDevice; +#if defined(ESP32) +#warning Building for ESP32 Devices +#include "esp32/esp32.h" +#elif defined(ESP8266) +#warning Building for ESP8266 Devices +#include "esp8266/esp8266.h" +#elif defined(STM32F4) +#warning Building for STM32F4xx Devices +#include "stm32f4/stm32f4.h" +#elif defined(WINDOWS) +#warning Building for Win32 Devices +#include "win32/hasp_win32.h" +#elif defined(POSIX) +#warning Building for Posix Devices +#include "posix/hasp_posix.h" -#include "lanbonl8.h" -#include "m5stackcore2.h" - -#if defined(LANBONL8) - #warning Lanbon L8 -#elif defined(M5STACK) - #warning M5 Stack #else +#warning Building for Generic Devices +using dev::BaseDevice; extern dev::BaseDevice haspDevice; #endif -#endif \ No newline at end of file + +#endif diff --git a/src/dev/esp32/esp32.cpp b/src/dev/esp32/esp32.cpp new file mode 100644 index 00000000..837a6bad --- /dev/null +++ b/src/dev/esp32/esp32.cpp @@ -0,0 +1,170 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#if defined(ESP32) + +#include "Arduino.h" +#include +#include "esp_system.h" + +#include "../device.h" +#include "esp32.h" + +#include "driver/adc.h" +#include "esp_adc_cal.h" + +#include "hasp_conf.h" +#include "hasp_debug.h" +#include "hasp/hasp_utilities.h" + +#define BACKLIGHT_CHANNEL 0 + +namespace dev { + +void Esp32Device::reboot() +{ + ESP.restart(); +} + +void Esp32Device::show_info() +{ + LOG_VERBOSE(TAG_DEV, F("Processor : ESP32")); + LOG_VERBOSE(TAG_DEV, F("CPU freq. : %i MHz"), get_cpu_frequency()); + // LOG_VERBOSE(TAG_DEV, F("Voltage : %2.2f V"), ESP.getVcc() / 918.0); // 918 empirically determined +} + +const char* Esp32Device::get_hostname() +{ + return _hostname.c_str(); +} +void Esp32Device::set_hostname(const char* hostname) +{ + _hostname = hostname; +} +const char* Esp32Device::get_core_version() +{ + return esp_get_idf_version(); // == ESP.getSdkVersion(); +} +const char* Esp32Device::get_chip_model() +{ + esp_chip_info_t chip_info; + esp_chip_info(&chip_info); + + // model = chip_info.cores; + // model += F("core "); + switch(chip_info.model) { + case CHIP_ESP32: + return "ESP32"; + +#ifdef CHIP_ESP32S2 + case CHIP_ESP32S2: + return "ESP32-S2"; +#endif + +#ifdef CHIP_ESP32S3 + case CHIP_ESP32S3: + return "ESP32-S3"; +#endif + + default: + return "Unknown ESP32"; + } + // model += F(" rev"); + // model += chip_info.revision; +} + +void Esp32Device::set_backlight_pin(uint8_t pin) +{ + _backlight_pin = pin; + + /* Setup Backlight Control Pin */ + if(pin < GPIO_NUM_MAX) { + LOG_VERBOSE(TAG_GUI, F("Backlight : Pin %d"), pin); + ledcSetup(BACKLIGHT_CHANNEL, 20000, 12); + ledcAttachPin(pin, BACKLIGHT_CHANNEL); + update_backlight(); + } else { + LOG_VERBOSE(TAG_GUI, F("Backlight : Pin not set")); + } +} + +void Esp32Device::set_backlight_level(uint8_t level) +{ + _backlight_level = level >= 0 ? level : 0; + _backlight_level = _backlight_level <= 100 ? _backlight_level : 100; + + update_backlight(); +} + +uint8_t Esp32Device::get_backlight_level() +{ + return _backlight_level; +} + +void Esp32Device::set_backlight_power(bool power) +{ + _backlight_power = power; + update_backlight(); +} + +bool Esp32Device::get_backlight_power() +{ + return _backlight_power != 0; +} + +void Esp32Device::update_backlight() +{ + if(_backlight_pin < GPIO_NUM_MAX) { + uint32_t duty = _backlight_power ? map(_backlight_level, 0, 100, 0, 4095) : 0; + ledcWrite(BACKLIGHT_CHANNEL, duty); // ledChannel and value + } +} + +size_t Esp32Device::get_free_max_block() +{ + return ESP.getMaxAllocHeap(); +} + +size_t Esp32Device::get_free_heap() +{ + return ESP.getFreeHeap(); +} + +uint8_t Esp32Device::get_heap_fragmentation() +{ + uint32_t free = ESP.getFreeHeap(); + if(free) { + return (int8_t)(100.00f - (float)ESP.getMaxAllocHeap() * 100.00f / (float)free); + } else { + return 100; // no free memory + } +} + +uint16_t Esp32Device::get_cpu_frequency() +{ + return ESP.getCpuFreqMHz(); +} + +bool Esp32Device::is_system_pin(uint8_t pin) +{ + if((pin >= 6) && (pin <= 11)) return true; // integrated SPI flash + if((pin == 37) || (pin == 38)) return true; // unavailable + if(psramFound()) { + if((pin == 16) || (pin == 17)) return true; // PSRAM + } + return false; +} + +} // namespace dev + +#if defined(LANBONL8) +#warning Building for Lanbon L8 +#include "dev/esp32/lanbonl8.h" +#elif defined(M5STACK) +#warning Building for M5Stack core2 +#include "dev/esp32/m5stackcore2.h" +#else +dev::Esp32Device haspDevice; +#endif + +#endif // ESP32 \ No newline at end of file diff --git a/src/dev/esp32/esp32.h b/src/dev/esp32/esp32.h new file mode 100644 index 00000000..7c2b6797 --- /dev/null +++ b/src/dev/esp32/esp32.h @@ -0,0 +1,72 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_DEVICE_ESP32_H +#define HASP_DEVICE_ESP32_H + +#include "../device.h" + +#if defined(ESP32) + +namespace dev { + +class Esp32Device : public BaseDevice { + + public: + Esp32Device() + { + _hostname = "plate"; + _backlight_power = 1; + _backlight_level = 100; +#ifdef TFT_BCKL + _backlight_pin = TFT_BCKL; +#else + _backlight_pin = -1; +#endif + } + void reboot() override; + void show_info() override; + + const char* get_hostname(); + void set_hostname(const char*); + const char* get_core_version(); + const char* get_chip_model(); + + void set_backlight_pin(uint8_t pin) override; + void set_backlight_level(uint8_t val) override; + uint8_t get_backlight_level() override; + void set_backlight_power(bool power) override; + bool get_backlight_power() override; + + size_t get_free_max_block() override; + size_t get_free_heap() override; + uint8_t get_heap_fragmentation() override; + uint16_t get_cpu_frequency() override; + + bool is_system_pin(uint8_t pin) override; + + private: + std::string _hostname; + + uint8_t _backlight_pin; + uint8_t _backlight_level; + uint8_t _backlight_power; + + void update_backlight(); +}; + +} // namespace dev + +#if defined(LANBONL8) +#warning Building for Lanbon L8 +#include "lanbonl8.h" +#elif defined(M5STACK) +#warning Building for M5Stack core2 +#include "m5stackcore2.h" +#else +using dev::Esp32Device; +extern dev::Esp32Device haspDevice; +#endif +#endif // ESP32 + +#endif // HASP_DEVICE_ESP32_H \ No newline at end of file diff --git a/src/dev/lanbonl8.cpp b/src/dev/esp32/lanbonl8.cpp similarity index 77% rename from src/dev/lanbonl8.cpp rename to src/dev/esp32/lanbonl8.cpp index 71f92851..f2f50ad9 100644 --- a/src/dev/lanbonl8.cpp +++ b/src/dev/esp32/lanbonl8.cpp @@ -1,13 +1,23 @@ -#include "Arduino.h" +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + #include "lanbonl8.h" #if defined(LANBONL8) - #include "driver/adc.h" - #include "esp_adc_cal.h" +#include "Arduino.h" +#include "dev/esp32/esp32.h" - #define REF_VOLTAGE 1100 -esp_adc_cal_characteristics_t * adc_chars = +#include "driver/adc.h" +#include "esp_adc_cal.h" + +#include "hasp_conf.h" +#include "hasp_debug.h" + +#define BACKLIGHT_CHANNEL 0 + +#define REF_VOLTAGE 1100 +esp_adc_cal_characteristics_t* adc_chars = new esp_adc_cal_characteristics_t; // adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t)); namespace dev { @@ -41,7 +51,7 @@ static void print_char_val_type(esp_adc_cal_value_t val_type) } } -void LanbonL8::pre_setup() +void LanbonL8::init() { // Check if Two Point or Vref are burned into eFuse check_efuse(); @@ -54,20 +64,8 @@ void LanbonL8::pre_setup() print_char_val_type(val_type); } -void LanbonL8::post_setup() -{} - -void LanbonL8::loop() -{} - -void LanbonL8::loop_5s() -{ - double voltage = esp_adc_cal_raw_to_voltage(analogRead(39), adc_chars); - Serial.print(adc1_get_raw(ADC1_CHANNEL_3)); - Serial.print(" - "); - Serial.println(voltage); -} } // namespace dev dev::LanbonL8 haspDevice; + #endif diff --git a/src/dev/lanbonl8.h b/src/dev/esp32/lanbonl8.h similarity index 53% rename from src/dev/lanbonl8.h rename to src/dev/esp32/lanbonl8.h index 445a2204..f32e1fa4 100644 --- a/src/dev/lanbonl8.h +++ b/src/dev/esp32/lanbonl8.h @@ -1,27 +1,23 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_DEVICE_LANBONL8_H #define HASP_DEVICE_LANBONL8_H -#include "device.h" +#include "esp32.h" #if defined(LANBONL8) namespace dev { -class LanbonL8 : public BaseDevice { +class LanbonL8 : public Esp32Device { public: - void pre_setup() override; - - void post_setup() override; - - void loop() override; - - void loop_5s() override; + void init(); }; + } // namespace dev +using dev::LanbonL8; extern dev::LanbonL8 haspDevice; #endif diff --git a/src/dev/m5stackcore2.cpp b/src/dev/esp32/m5stackcore2.cpp similarity index 78% rename from src/dev/m5stackcore2.cpp rename to src/dev/esp32/m5stackcore2.cpp index d208931d..11785afe 100644 --- a/src/dev/m5stackcore2.cpp +++ b/src/dev/esp32/m5stackcore2.cpp @@ -1,13 +1,17 @@ -#include "device.h" +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + #include "m5stackcore2.h" #if defined(M5STACK) - #include "AXP192.h" // Power Mgmt + +#include "AXP192.h" // Power Mgmt +#include "dev/esp32/esp32.h" // AXP192 Axp; namespace dev { -void M5StackCore2::pre_setup(void) +void M5StackCore2::init(void) { AXP192 Axp; Wire.begin(TOUCH_SDA, TOUCH_SCL); @@ -39,15 +43,8 @@ void M5StackCore2::pre_setup(void) Axp.SetLed(1); } -void M5StackCore2::post_setup(void) -{} - -void M5StackCore2::loop(void) -{} - -void M5StackCore2::loop_5s(void) -{} } // namespace dev dev::M5StackCore2 haspDevice; + #endif diff --git a/src/dev/m5stackcore2.h b/src/dev/esp32/m5stackcore2.h similarity index 56% rename from src/dev/m5stackcore2.h rename to src/dev/esp32/m5stackcore2.h index 39539fff..7bc48dd3 100644 --- a/src/dev/m5stackcore2.h +++ b/src/dev/esp32/m5stackcore2.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_DEVICE_M5STACKCORE2_H @@ -6,16 +6,13 @@ #if defined(M5STACK) - #include "device.h" +#include "esp32.h" namespace dev { -class M5StackCore2 : public BaseDevice { +class M5StackCore2 : public Esp32Device { public: - void pre_setup() override; - void post_setup() override; - void loop() override; - void loop_5s() override; + void init() override; }; } // namespace dev diff --git a/src/dev/esp8266/esp8266.cpp b/src/dev/esp8266/esp8266.cpp new file mode 100644 index 00000000..9b8c5ec3 --- /dev/null +++ b/src/dev/esp8266/esp8266.cpp @@ -0,0 +1,123 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#if defined(ESP8266) + +#include "Arduino.h" +#include + +#include "esp8266.h" + +#include "hasp_conf.h" +#include "hasp_debug.h" +#include "hasp/hasp_utilities.h" + +#define BACKLIGHT_CHANNEL 0 + +namespace dev { + +void Esp8266Device::reboot() +{ + ESP.restart(); +} + +void Esp8266Device::show_info() +{ + LOG_VERBOSE(TAG_DEV, F("Processor : ESP8266")); + LOG_VERBOSE(TAG_DEV, F("CPU freq. : %i MHz"), get_cpu_frequency()); + LOG_VERBOSE(TAG_DEV, F("Voltage : %2.2f V"), ESP.getVcc() / 918.0); // 918 empirically determined +} + +const char* Esp8266Device::get_hostname() +{ + return _hostname.c_str(); +} +void Esp8266Device::set_hostname(const char* hostname) +{ + _hostname = hostname; +} + +const char* Esp8266Device::get_core_version() +{ + return _core_version.c_str(); +} + +const char* Esp8266Device::get_chip_model() +{ + return "ESP8266"; +} + +void Esp8266Device::set_backlight_pin(uint8_t pin) +{ + _backlight_pin = pin; + /* Setup Backlight Control Pin */ + if(pin >= 0) { + LOG_VERBOSE(TAG_GUI, F("Backlight : Pin %d"), pin); + pinMode(_backlight_pin, OUTPUT); + update_backlight(); + } +} + +void Esp8266Device::set_backlight_level(uint8_t level) +{ + _backlight_level = level >= 0 ? level : 0; + _backlight_level = _backlight_level <= 100 ? _backlight_level : 100; + + update_backlight(); +} + +uint8_t Esp8266Device::get_backlight_level() +{ + return _backlight_level; +} + +void Esp8266Device::set_backlight_power(bool power) +{ + _backlight_power = power; + update_backlight(); +} + +bool Esp8266Device::get_backlight_power() +{ + return _backlight_power != 0; +} + +void Esp8266Device::update_backlight() +{ + if(_backlight_pin == -1) return; + + analogWrite(_backlight_pin, _backlight_power ? map(_backlight_level, 0, 100, 0, 1023) : 0); +} + +size_t Esp8266Device::get_free_max_block() +{ + return ESP.getMaxFreeBlockSize(); +} + +size_t Esp8266Device::get_free_heap(void) +{ + return ESP.getFreeHeap(); +} + +uint8_t Esp8266Device::get_heap_fragmentation() +{ + return ESP.getHeapFragmentation(); +} + +uint16_t Esp8266Device::get_cpu_frequency() +{ + return ESP.getCpuFreqMHz(); +} + +bool Esp8266Device::is_system_pin(uint8_t pin) +{ + if((pin >= 6) && (pin <= 11)) return true; // integrated SPI flash + if((pin >= 12) && (pin <= 14)) return true; // HSPI + return false; +} + +} // namespace dev + +dev::Esp8266Device haspDevice; + +#endif // ESP8266 \ No newline at end of file diff --git a/src/dev/esp8266/esp8266.h b/src/dev/esp8266/esp8266.h new file mode 100644 index 00000000..4c48d1ae --- /dev/null +++ b/src/dev/esp8266/esp8266.h @@ -0,0 +1,69 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_DEVICE_ESP8266_H +#define HASP_DEVICE_ESP8266_H + +#include "hasp_conf.h" +#include "dev/device.h" + +#if defined(ESP8266) + +namespace dev { + +class Esp8266Device : public BaseDevice { + + public: + Esp8266Device() + { + _hostname = "plate"; + _backlight_power = 1; + _backlight_level = 100; + _core_version = ESP.getCoreVersion().c_str(); +#ifdef TFT_BCKL + _backlight_pin = TFT_BCKL; +#else + _backlight_pin = -1; +#endif + } + + void reboot() override; + void show_info() override; + + const char* get_hostname(); + void set_hostname(const char*); + const char* get_core_version(); + const char* get_chip_model(); + + void set_backlight_pin(uint8_t pin) override; + void set_backlight_level(uint8_t val) override; + uint8_t get_backlight_level() override; + void set_backlight_power(bool power) override; + bool get_backlight_power() override; + + size_t get_free_max_block() override; + size_t get_free_heap() override; + uint8_t get_heap_fragmentation() override; + uint16_t get_cpu_frequency() override; + + bool is_system_pin(uint8_t pin) override; + + private: + std::string _hostname; + std::string _core_version; + + uint8_t _backlight_pin; + uint8_t _backlight_level; + uint8_t _backlight_power; + + void update_backlight(); +}; + +} // namespace dev + +using dev::Esp8266Device; +extern dev::Esp8266Device haspDevice; + +#endif // ESP8266 + +#endif // HASP_DEVICE_ESP8266_H \ No newline at end of file diff --git a/src/dev/posix/hasp_posix.cpp b/src/dev/posix/hasp_posix.cpp new file mode 100644 index 00000000..8884861a --- /dev/null +++ b/src/dev/posix/hasp_posix.cpp @@ -0,0 +1,157 @@ +#if defined(POSIX) + +#include +#include + +#include "hasp_posix.h" + +#include "hasp_conf.h" +#include "hasp/hasp_utilities.h" +#include "hasp_debug.h" + +#include "display/monitor.h" + +// extern monitor_t monitor; + +namespace dev { + +PosixDevice::PosixDevice() +{ + struct utsname uts; + + if(uname(&uts) < 0) { + LOG_ERROR(0, "uname() error"); + _hostname = "localhost"; + _core_version = "unknown"; + _chip_model = "unknown"; + } else { + // LOG_VERBOSE(0,"Sysname: %s", uts.sysname); + // LOG_VERBOSE(0,"Nodename: %s", uts.nodename); + // LOG_VERBOSE(0,"Release: %s", uts.release); + // LOG_VERBOSE(0,"Version: %s", uts.version); + // LOG_VERBOSE(0,"Machine: %s", uts.machine); + + char version[128]; + snprintf(version, sizeof(version), "%s %s", uts.sysname, uts.release); + _core_version = version; + _chip_model = uts.machine; + _hostname = uts.nodename; + } + + _backlight_power = 1; + _backlight_level = 100; +} + +void PosixDevice::reboot() +{} +void PosixDevice::show_info() +{ + struct utsname uts; + + if(uname(&uts) < 0) { + LOG_ERROR(0, "uname() error"); + } else { + LOG_VERBOSE(0, "Sysname: %s", uts.sysname); + LOG_VERBOSE(0, "Nodename: %s", uts.nodename); + LOG_VERBOSE(0, "Release: %s", uts.release); + LOG_VERBOSE(0, "Version: %s", uts.version); + LOG_VERBOSE(0, "Machine: %s", uts.machine); + } + + LOG_VERBOSE(0, "Processor : %s", "unknown"); + LOG_VERBOSE(0, "CPU freq. : %i MHz", 0); +} + +const char* PosixDevice::get_hostname() +{ + return _hostname.c_str(); +} +void PosixDevice::set_hostname(const char* hostname) +{ + _hostname = hostname; + monitor_title(hostname); + // SDL_SetWindowTitle(monitor.window, hostname); +} +const char* PosixDevice::get_core_version() +{ + return _core_version.c_str(); +} +const char* PosixDevice::get_chip_model() +{ + return _chip_model.c_str(); +} + +void PosixDevice::set_backlight_pin(uint8_t pin) +{ + // PosixDevice::backlight_pin = pin; +} + +void PosixDevice::set_backlight_level(uint8_t level) +{ + uint8_t new_level = level >= 0 ? level : 0; + new_level = new_level <= 100 ? new_level : 100; + + if(_backlight_level != new_level) { + _backlight_level = new_level; + update_backlight(); + } +} + +uint8_t PosixDevice::get_backlight_level() +{ + return _backlight_level; +} + +void PosixDevice::set_backlight_power(bool power) +{ + _backlight_power = power; + update_backlight(); +} + +bool PosixDevice::get_backlight_power() +{ + return _backlight_power != 0; +} + +void PosixDevice::update_backlight() +{ + uint8_t level = _backlight_power ? map(_backlight_level, 0, 100, 0, 255) : 0; + monitor_backlight(level); + // SDL_SetTextureColorMod(monitor.texture, level, level, level); + // window_update(&monitor); + // monitor.sdl_refr_qry = true; + // monitor_sdl_refr(NULL); + // const lv_area_t area = {1,1,0,0}; + // monitor_flush(NULL,&area,NULL); +} + +size_t PosixDevice::get_free_max_block() +{ + return 0; +} + +size_t PosixDevice::get_free_heap(void) +{ + return 0; +} + +uint8_t PosixDevice::get_heap_fragmentation() +{ + return 0; +} + +uint16_t PosixDevice::get_cpu_frequency() +{ + return 0; +} + +bool PosixDevice::is_system_pin(uint8_t pin) +{ + return false; +} + +} // namespace dev + +dev::PosixDevice haspDevice; + +#endif // POSIX diff --git a/src/dev/posix/hasp_posix.h b/src/dev/posix/hasp_posix.h new file mode 100644 index 00000000..962bd45d --- /dev/null +++ b/src/dev/posix/hasp_posix.h @@ -0,0 +1,74 @@ +/* MIT License - Copyright (c) 2020 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_DEVICE_POSIX_H +#define HASP_DEVICE_POSIX_H + +#include +#include + +extern "C" { +#include +#include +#include +#include +} + +#include "hasp_conf.h" +#include "../device.h" + +#if defined(POSIX) +static inline void itoa(int i, char* out, int unused_) +{ + (void)unused_; + sprintf(out, "%d", i); +} + +namespace dev { + +class PosixDevice : public BaseDevice { + + public: + PosixDevice(); + + void reboot() override; + void show_info() override; + + const char* get_hostname(); + void set_hostname(const char*); + const char* get_core_version(); + const char* get_chip_model(); + + void set_backlight_pin(uint8_t pin); + void set_backlight_level(uint8_t val); + uint8_t get_backlight_level(); + void set_backlight_power(bool power); + bool get_backlight_power(); + + size_t get_free_max_block(); + size_t get_free_heap(); + uint8_t get_heap_fragmentation(); + uint16_t get_cpu_frequency(); + + bool is_system_pin(uint8_t pin) override; + + private: + std::string _hostname; + std::string _core_version; + std::string _chip_model; + + uint8_t _backlight_pin; + uint8_t _backlight_level; + uint8_t _backlight_power; + + void update_backlight(); +}; + +} // namespace dev + +using dev::PosixDevice; +extern dev::PosixDevice haspDevice; + +#endif // POSIX + +#endif // HASP_DEVICE_POSIX_H diff --git a/src/dev/stm32f4/stm32f4.cpp b/src/dev/stm32f4/stm32f4.cpp new file mode 100644 index 00000000..41df3ad3 --- /dev/null +++ b/src/dev/stm32f4/stm32f4.cpp @@ -0,0 +1,134 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#if defined(STM32F4xx) + +#include "Arduino.h" + +#include "stm32f4.h" + +#include "hasp_conf.h" +#include "hasp_debug.h" +#include "hasp/hasp_utilities.h" + +#define BACKLIGHT_CHANNEL 0 + +namespace dev { + +void Stm32f4Device::reboot() +{ + // ESP.restart(); +} + +void Stm32f4Device::show_info() +{ + LOG_VERBOSE(TAG_DEV, F("Processor : STM32F4xx")); + // LOG_VERBOSE(TAG_DEV, F("CPU freq. : %i MHz"), get_cpu_frequency()); + // LOG_VERBOSE(TAG_DEV, F("Voltage : %2.2f V"), ESP.getVcc() / 918.0); // 918 empirically determined +} + +const char* Stm32f4Device::get_hostname() +{ + return _hostname.c_str(); +} +void Stm32f4Device::set_hostname(const char* hostname) +{ + _hostname = hostname; +} + +const char* Stm32f4Device::get_core_version() +{ + // return ESP.getCoreVersion().c_str(); +} + +void Stm32f4Device::set_backlight_pin(uint8_t pin) +{ + _backlight_pin = pin; + /* Setup Backlight Control Pin */ + if(pin >= 0) { + LOG_VERBOSE(TAG_GUI, F("Backlight : Pin %d"), pin); + pinMode(_backlight_pin, OUTPUT); + update_backlight(); + } +} + +const char* Stm32f4Device::get_chip_model() +{ +#if defined(STM32F407ZG) + return "STM32F407ZG"; +#elif defined(STM32F407ZE) + return "STM32F407ZE"; +#elif defined(STM32F407VE) + return "STM32F407VE"; +#elif defined(STM32F407VG) + return "STM32F407VG"; +#elif defined(STM32F4xx) || defined(ARDUINO_ARCH_STM32F4) + return "STM32F4"; +#else + return "Unknown STM32"; +#endif +} + +void Stm32f4Device::set_backlight_level(uint8_t level) +{ + _backlight_level = level >= 0 ? level : 0; + _backlight_level = _backlight_level <= 100 ? _backlight_level : 100; + + update_backlight(); +} + +uint8_t Stm32f4Device::get_backlight_level() +{ + return _backlight_level; +} + +void Stm32f4Device::set_backlight_power(bool power) +{ + _backlight_power = power; + update_backlight(); +} + +bool Stm32f4Device::get_backlight_power() +{ + return _backlight_power != 0; +} + +void Stm32f4Device::update_backlight() +{ + if(_backlight_pin == -1) return; + + // analogWrite(_backlight_pin, _backlight_power ? map(_backlight_level, 0, 100, 0, 1023) : 0); +} + +size_t Stm32f4Device::get_free_max_block() +{ + // return ESP.getMaxFreeBlockSize(); +} + +size_t Stm32f4Device::get_free_heap(void) +{ + // return ESP.getFreeHeap(); +} + +uint8_t Stm32f4Device::get_heap_fragmentation() +{ + // return ESP.getHeapFragmentation(); +} + +uint16_t Stm32f4Device::get_cpu_frequency() +{ + // return ESP.getCpuFreqMHz(); +} + +bool Stm32f4Device::is_system_pin(uint8_t pin) +{ + // if((pin >= 6) && (pin <= 11)) return true; // integrated SPI flash + // if((pin >= 12) && (pin <= 14)) return true; // HSPI + return false; +} + +} // namespace dev + +dev::Stm32f4Device haspDevice; + +#endif // STM32F4xx \ No newline at end of file diff --git a/src/dev/stm32f4/stm32f4.h b/src/dev/stm32f4/stm32f4.h new file mode 100644 index 00000000..30513dc0 --- /dev/null +++ b/src/dev/stm32f4/stm32f4.h @@ -0,0 +1,67 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_DEVICE_STM32F4_H +#define HASP_DEVICE_STM32F4_H + +#include "hasp_conf.h" +#include "dev/device.h" + +#if defined(STM32F4xx) + +namespace dev { + +class Stm32f4Device : public BaseDevice { + + public: + Stm32f4Device() + { + _hostname = "plate"; + _backlight_power = 1; + _backlight_level = 100; +#ifdef TFT_BCKL + _backlight_pin = TFT_BCKL; +#else + _backlight_pin = -1; +#endif + } + + void reboot() override; + void show_info() override; + + const char* get_hostname(); + void set_hostname(const char*); + const char* get_core_version(); + const char* get_chip_model(); + + void set_backlight_pin(uint8_t pin) override; + void set_backlight_level(uint8_t val) override; + uint8_t get_backlight_level() override; + void set_backlight_power(bool power) override; + bool get_backlight_power() override; + + size_t get_free_max_block() override; + size_t get_free_heap() override; + uint8_t get_heap_fragmentation() override; + uint16_t get_cpu_frequency() override; + + bool is_system_pin(uint8_t pin) override; + + private: + std::string _hostname; + + uint8_t _backlight_pin; + uint8_t _backlight_level; + uint8_t _backlight_power; + + void update_backlight(); +}; + +} // namespace dev + +using dev::Stm32f4Device; +extern dev::Stm32f4Device haspDevice; + +#endif // STM32F4xx + +#endif // HASP_DEVICE_STM32F4_H \ No newline at end of file diff --git a/src/dev/win32/hasp_win32.cpp b/src/dev/win32/hasp_win32.cpp new file mode 100644 index 00000000..be465952 --- /dev/null +++ b/src/dev/win32/hasp_win32.cpp @@ -0,0 +1,134 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#if defined(WINDOWS) + +#include +#include "Windows.h" + +#include "hasp_win32.h" + +#include "hasp_conf.h" +#include "hasp/hasp_utilities.h" +#include "hasp_debug.h" + +#include "display/monitor.h" + +namespace dev { + +static inline void native_cpuid(unsigned int* eax, unsigned int* ebx, unsigned int* ecx, unsigned int* edx) +{ + /* ecx is often an input as well as an output. */ + asm volatile("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "0"(*eax), "2"(*ecx) : "memory"); +} + +void Win32Device::reboot() +{} + +void Win32Device::show_info() +{ + + unsigned int eax, ebx, ecx, edx; + eax = 0; + native_cpuid(&eax, &ebx, &ecx, &edx); + // printf("EAX: %08X EBX: %08X ECX: %08X EDX: %08X\n", eax, ebx, ecx, edx); + char vendor[13]; + memcpy(vendor, &ebx, 4); + memcpy(vendor + 4, &edx, 4); + memcpy(vendor + 8, &ecx, 4); + vendor[12] = '\0'; + + LOG_VERBOSE(0, F("Processor : %s"), vendor); + LOG_VERBOSE(0, F("CPU freq. : %i MHz"), get_cpu_frequency()); +} + +const char* Win32Device::get_hostname() +{ + return _hostname.c_str(); +} +void Win32Device::set_hostname(const char* hostname) +{ + _hostname = hostname; + monitor_title(hostname); + // SDL_SetWindowTitle(monitor.window, hostname); +} +const char* Win32Device::get_core_version() +{ + return _core_version.c_str(); +} +const char* Win32Device::get_chip_model() +{ + return "SDL2"; +} + +void Win32Device::set_backlight_pin(uint8_t pin) +{ + // Win32Device::_backlight_pin = pin; +} + +void Win32Device::set_backlight_level(uint8_t level) +{ + uint8_t new_level = level >= 0 ? level : 0; + new_level = new_level <= 100 ? new_level : 100; + + if(_backlight_level != new_level) { + _backlight_level = new_level; + update_backlight(); + } +} + +uint8_t Win32Device::get_backlight_level() +{ + return _backlight_level; +} + +void Win32Device::set_backlight_power(bool power) +{ + _backlight_power = power; + update_backlight(); +} + +bool Win32Device::get_backlight_power() +{ + return _backlight_power != 0; +} + +void Win32Device::update_backlight() +{ + uint8_t level = _backlight_power ? map(_backlight_level, 0, 100, 0, 255) : 0; + monitor_backlight(level); +} + +size_t Win32Device::get_free_max_block() +{ + return 0; +} + +size_t Win32Device::get_free_heap(void) +{ + MEMORYSTATUSEX status; + status.dwLength = sizeof(status); + GlobalMemoryStatusEx(&status); + return status.ullAvailPhys; +} + +uint8_t Win32Device::get_heap_fragmentation() +{ + return 0; +} + +uint16_t Win32Device::get_cpu_frequency() +{ + return 0; +} + +bool Win32Device::is_system_pin(uint8_t pin) +{ + return false; +} + +} // namespace dev + +dev::Win32Device haspDevice; + +#endif // WINDOWS \ No newline at end of file diff --git a/src/dev/win32/hasp_win32.h b/src/dev/win32/hasp_win32.h new file mode 100644 index 00000000..7aaa9ae3 --- /dev/null +++ b/src/dev/win32/hasp_win32.h @@ -0,0 +1,93 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_DEVICE_WINDOWS_H +#define HASP_DEVICE_WINDOWS_H + +#include +#include +#include "Windows.h" + +#include "hasp_conf.h" +#include "../device.h" + +#if defined(WINDOWS) + +namespace dev { + +class Win32Device : public BaseDevice { + + public: + Win32Device() + { + char buffer[MAX_COMPUTERNAME_LENGTH + 1]; + DWORD length = sizeof(buffer); + + if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNameNetBIOS, buffer, &length)) { + _hostname = buffer; + } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNameDnsHostname, buffer, &length)) { + _hostname = buffer; + } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNamePhysicalDnsHostname, buffer, &length)) { + _hostname = buffer; + } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNamePhysicalDnsDomain, buffer, &length)) { + _hostname = buffer; + } else { + _hostname = "localhost"; + } + + // Get the Windows version. + DWORD dwBuild = 0; + DWORD dwVersion = GetVersion(); + DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); + DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); + if(dwVersion < 0x80000000) dwBuild = (DWORD)(HIWORD(dwVersion)); + + char version[128]; + snprintf(version, sizeof(version), "Windows %d.%d-%d", dwMajorVersion, dwMinorVersion, dwBuild); + _core_version = version; + + // _backlight_pin = -1; + _backlight_power = 1; + _backlight_level = 100; + } + + void reboot() override; + void show_info() override; + + const char* get_hostname(); + void set_hostname(const char*); + const char* get_core_version(); + const char* get_chip_model(); + + void set_backlight_pin(uint8_t pin); + void set_backlight_level(uint8_t val); + uint8_t get_backlight_level(); + void set_backlight_power(bool power); + bool get_backlight_power(); + + size_t get_free_max_block(); + size_t get_free_heap(); + uint8_t get_heap_fragmentation(); + uint16_t get_cpu_frequency(); + + bool is_system_pin(uint8_t pin) override; + + private: + std::string _hostname; + std::string _core_version; + + uint8_t _backlight_pin; + uint8_t _backlight_level; + uint8_t _backlight_power; + + void update_backlight(); +}; + +} // namespace dev + +using dev::Win32Device; +extern dev::Win32Device haspDevice; + +#endif // WINDOWS + +#endif // HASP_DEVICE_WINDOWS_H \ No newline at end of file diff --git a/src/drv/hasp_drv_display.cpp b/src/drv/hasp_drv_display.cpp deleted file mode 100644 index ad80fdf8..00000000 --- a/src/drv/hasp_drv_display.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "hasp_drv_display.h" - -void drv_display_init(lv_disp_drv_t * disp_drv, uint8_t rotation, bool invert_display) -{ - /* TFT init */ -#if defined(USE_FSMC) - fsmc_ili9341_init(rotation, invert_display); - disp_drv->flush_cb = fsmc_ili9341_flush; // Normal callback when flushing - // xpt2046_init(rotation); -#else - tft_espi_init(rotation, invert_display); - disp_drv->flush_cb = tft_espi_flush; // Normal callback when flushing -#endif -} - -/* Callback used for screenshots only: */ - -/* indirect callback to flush screenshot data to the screen */ -void drv_display_flush_cb(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p) -{ -#if defined(USE_FSMC) - fsmc_ili9341_flush(disp, area, color_p); -#else - tft_espi_flush(disp, area, color_p); -#endif -} \ No newline at end of file diff --git a/src/drv/hasp_drv_display.h b/src/drv/hasp_drv_display.h deleted file mode 100644 index 477cb762..00000000 --- a/src/drv/hasp_drv_display.h +++ /dev/null @@ -1,17 +0,0 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie - For full license information read the LICENSE file in the project folder */ - -#ifndef HASP_DRV_DISPLAY_H -#define HASP_DRV_DISPLAY_H - -// Select Display Driver -#if defined(USE_FSMC) - #include "fsmc_ili9341.h" -#else - #include "tft_espi_drv.h" -#endif - -void drv_display_init(lv_disp_drv_t * disp_drv, uint8_t rotation, bool invert_display); -void drv_display_flush_cb(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p); - -#endif \ No newline at end of file diff --git a/src/drv/hasp_drv_ft5206.h b/src/drv/hasp_drv_ft5206.h deleted file mode 100644 index e53c1c07..00000000 --- a/src/drv/hasp_drv_ft5206.h +++ /dev/null @@ -1,17 +0,0 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie - For full license information read the LICENSE file in the project folder */ - -#ifndef HASP_DRV_FT5206_H -#define HASP_DRV_FT5206_H - -#if TOUCH_DRIVER == 5206 - - #define FT5206_address 0x38 - - #include "hasp_debug.h" // for TAG_DRVR - -bool FT5206_getXY(int16_t * touchX, int16_t * touchY, bool debug); -void FT5206_init(); - -#endif -#endif \ No newline at end of file diff --git a/src/drv/hasp_drv_touch.cpp b/src/drv/hasp_drv_touch.cpp index bb311480..77f5f512 100644 --- a/src/drv/hasp_drv_touch.cpp +++ b/src/drv/hasp_drv_touch.cpp @@ -1,25 +1,31 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + #include "hasp_drv_touch.h" #include "hasp/hasp.h" +#include "drv/tft_driver.h" #include "lvgl.h" #if TOUCH_DRIVER == 2046 - #if defined(USE_FSMC) - #else - #include "tft_espi_drv.h" - #endif +#if defined(USE_FSMC) +#else +#include "tft_espi_drv.h" +#endif #elif TOUCH_DRIVER == 2046 - #include "indev/XPT2046.h" +#include "indev/XPT2046.h" #elif TOUCH_DRIVER == 0x2046B - #include "hasp_drv_xpt2046.h" +#include "drv/touch/hasp_drv_xpt2046.h" #elif TOUCH_DRIVER == 911 - #include "hasp_drv_gt911.h" +#include "drv/touch/hasp_drv_gt911.h" #elif TOUCH_DRIVER == 0xADC - #include "hasp_drv_ft6336u.h" +#include "drv/touch/hasp_drv_ft6336u.h" #elif TOUCH_DRIVER == 5206 - #include "hasp_drv_ft5206.h" +#include "drv/touch/hasp_drv_ft5206.h" #elif TOUCH_DRIVER == 6336 - #include "hasp_drv_ft6336u.h" +#include "drv/touch/hasp_drv_ft6336u.h" +#elif TOUCH_DRIVER == 610 +#include "drv/touch/hasp_drv_stmpe610.h" #else //#include "tp_i2c.h" //#include "ft6x36.h" @@ -34,12 +40,12 @@ void drv_touch_init(uint8_t rotation) drv_touch_rotation = rotation; #if TOUCH_DRIVER == 2046 // XPT2046 Resistive touch panel driver - #if defined(USE_FSMC) +#if defined(USE_FSMC) xpt2046_init(rotation); - #else - // The display driver takes care of all initializations - // tft_espi_init(rotation); - #endif +#else + // The display driver takes care of all initializations + // tft_espi_init(rotation); +#endif #elif TOUCH_DRIVER == 911 GT911_init(); @@ -53,6 +59,9 @@ void drv_touch_init(uint8_t rotation) #elif TOUCH_DRIVER == 6336 FT6336U_init(); +#elif TOUCH_DRIVER == 610 + STMPE610_init(); + #else // xpt2046_alt_drv_read(indev_driver, data); // xpt2046_read(indev_driver, data); @@ -60,13 +69,13 @@ void drv_touch_init(uint8_t rotation) #endif } -static inline bool drv_touchpad_getXY(int16_t * touchX, int16_t * touchY) +static inline bool drv_touchpad_getXY(int16_t* touchX, int16_t* touchY) { bool touched; int16_t normal_x; int16_t normal_y; #if TOUCH_DRIVER == 2046 // XPT2046 Resistive touch panel driver - touched = tft_espi_get_touch(&normal_x, &normal_y, 300u); + touched = haspTft.tft.getTouch((uint16_t*)&normal_x, (uint16_t*)&normal_y, 300); #elif TOUCH_DRIVER == 0x2046B touched = XPT2046_getXY(&normal_x, &normal_y, true); @@ -83,6 +92,9 @@ static inline bool drv_touchpad_getXY(int16_t * touchX, int16_t * touchY) #elif TOUCH_DRIVER == 6336 touched = FT6336U_getXY(&normal_x, &normal_y, true); +#elif TOUCH_DRIVER == 610 + touched = STMPE610_getXY(&normal_x, &normal_y, drv_touch_rotation, true); + #else // xpt2046_alt_drv_read(indev_driver, data); // xpt2046_read(indev_driver, data); @@ -151,7 +163,7 @@ bool touch_rotate = false; bool touch_invert_x = false; bool touch_invert_y = false; -bool drv_touch_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data) +bool drv_touch_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data) { #if TOUCH_DRIVER > 0 int16_t touchX = 0; diff --git a/src/drv/hasp_drv_touch.h b/src/drv/hasp_drv_touch.h index 6273ef71..f1b83f10 100644 --- a/src/drv/hasp_drv_touch.h +++ b/src/drv/hasp_drv_touch.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_DRV_TOUCH_H @@ -7,11 +7,11 @@ #include "lvgl.h" #ifndef TOUCH_DRIVER - #define TOUCH_DRIVER -1 // No Touch +#define TOUCH_DRIVER -1 // No Touch #endif void drv_touch_init(uint8_t rotation); -bool drv_touch_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data); +bool drv_touch_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data); void drv_touch_loop(); #endif \ No newline at end of file diff --git a/src/drv/hasp_drv_xpt2046.h b/src/drv/hasp_drv_xpt2046.h deleted file mode 100644 index 188d31f7..00000000 --- a/src/drv/hasp_drv_xpt2046.h +++ /dev/null @@ -1,24 +0,0 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie - For full license information read the LICENSE file in the project folder */ - -#ifndef HASP_DRV_XPT2046B_H -#define HASP_DRV_XPT2046B_H - -#if TOUCH_DRIVER == 0x2046B - - #include "XPT2046_Touchscreen.h" - - #define XPT2046_HOR_RES TFT_WIDTH - #define XPT2046_VER_RES TFT_HEIGHT - #define XPT2046_X_MIN 200 - #define XPT2046_Y_MIN 200 - #define XPT2046_X_MAX 3800 - #define XPT2046_Y_MAX 3800 - #define XPT2046_AVG 4 - #define XPT2046_INV 0 - -bool XPT2046_getXY(int16_t * touchX, int16_t * touchY, bool debug); -void XPT2046_init(); - -#endif -#endif \ No newline at end of file diff --git a/src/drv/tft_driver.h b/src/drv/tft_driver.h new file mode 100644 index 00000000..52a25f5d --- /dev/null +++ b/src/drv/tft_driver.h @@ -0,0 +1,57 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_BASE_TFT_DRIVER_H +#define HASP_BASE_TFT_DRIVER_H + +#ifdef ARDUINO +#include "Arduino.h" +#endif + +#include "lvgl.h" + +namespace dev { + +class BaseTft { + public: + virtual void init(int w, int h) + {} + virtual void show_info() + {} + virtual void set_rotation(uint8_t rotation) + {} + virtual void set_invert(bool invert_display) + {} + static void flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) + {} + virtual bool is_driver_pin(uint8_t) + { + return false; + } + virtual const char* get_tft_model() + { + return ""; + } +}; + +} // namespace dev + +#if defined(ESP32) +#warning Building for ESP32 Tfts +#include "tft_driver_tftespi.h" +#elif defined(ESP8266) +#warning Building for ESP8266 Tfts +#include "tft_driver_tftespi.h" +#elif defined(STM32F4) +#warning Building for STM32F4xx Tfts +#include "tft_driver_tftespi.h" +#elif defined(WINDOWS) || defined(POSIX) +#warning Building for SDL2 +#include "tft_driver_sdl2.h" +#else +#warning Building for Generic Tfts +using dev::BaseTft; +extern dev::BaseTft haspTft; +#endif + +#endif diff --git a/src/drv/tft_driver_sdl2.cpp b/src/drv/tft_driver_sdl2.cpp new file mode 100644 index 00000000..0c8801a1 --- /dev/null +++ b/src/drv/tft_driver_sdl2.cpp @@ -0,0 +1,100 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#if defined(WINDOWS) || defined(POSIX) + +#include "lvgl.h" +#include + +#include "display/monitor.h" +#include "indev/mouse.h" + +#include "drv/tft_driver.h" +#include "tft_driver_sdl2.h" + +#include "dev/device.h" +#include "hasp_debug.h" + +#include "tft_driver_sdl2.h" + +//#include "bootscreen.h" // Sketch tab header for xbm images + +namespace dev { + +/** + * A task to measure the elapsed time for LittlevGL + * @param data unused + * @return never return + */ +static int tick_thread(void* data) +{ + (void)data; + + while(1) { + SDL_Delay(5); /*Sleep for 5 millisecond*/ + lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/ + } + + return 0; +} + +void TftSdl::init(int w, int h) +{ + +// Workaround for sdl2 `-m32` crash +// https://bugs.launchpad.net/ubuntu/+source/libsdl2/+bug/1775067/comments/7 +#ifndef WIN32 + setenv("DBUS_FATAL_WARNINGS", "0", 1); +#endif + + /* Add a display + * Use the 'monitor' driver which creates window on PC's monitor to simulate a display*/ + monitor_init(MONITOR_HOR_RES, MONITOR_VER_RES); + monitor_title(haspDevice.get_hostname()); + + /* Add the mouse as input device + * Use the 'mouse' driver which reads the PC's mouse*/ + mouse_init(); + + /* Tick init. + * You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed + * Create an SDL thread to do this*/ + SDL_CreateThread(tick_thread, "tick", NULL); +} +void TftSdl::show_info() +{ + SDL_version linked; + SDL_GetVersion(&linked); + LOG_VERBOSE(TAG_TFT, F("Driver : SDL2")); + LOG_VERBOSE(TAG_TFT, F("SDL Version: v%d.%d.%d"), linked.major, linked.minor, linked.patch); +} + +void TftSdl::splashscreen() +{ + // tft.fillScreen(TFT_DARKCYAN); + // int x = (tft.width() - logoWidth) / 2; + // int y = (tft.height() - logoHeight) / 2; + // tft.drawXBitmap(x, y, bootscreen, logoWidth, logoHeight, TFT_WHITE); +} +void TftSdl::set_rotation(uint8_t rotation) +{} +void TftSdl::set_invert(bool invert) +{} +void TftSdl::flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) +{ + monitor_flush(disp, area, color_p); +} +bool TftSdl::is_driver_pin(uint8_t pin) +{ + return false; +} +const char* TftSdl::get_tft_model() +{ + return "SDL2"; +} + +} // namespace dev + +dev::TftSdl haspTft; + +#endif // WINDOWS || POSIX \ No newline at end of file diff --git a/src/drv/tft_driver_sdl2.h b/src/drv/tft_driver_sdl2.h new file mode 100644 index 00000000..d4c453eb --- /dev/null +++ b/src/drv/tft_driver_sdl2.h @@ -0,0 +1,38 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_SDL2_DRIVER_H +#define HASP_SDL2_DRIVER_H + +#include "tft_driver.h" + +#if defined(WINDOWS) || defined(POSIX) +#warning Building H driver TFT SDL2 + +#include "lvgl.h" +#include "indev/mouse.h" + +namespace dev { + +class TftSdl : BaseTft { + public: + void init(int w, int h); + void show_info(); + void splashscreen(); + + void set_rotation(uint8_t rotation); + void set_invert(bool invert); + + void flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p); + bool is_driver_pin(uint8_t pin); + + const char* get_tft_model(); +}; + +} // namespace dev + +#endif // defined(WINDOWS) || defined(POSIX) + +#endif // HASP_SDL2_DRIVER_H +using dev::TftSdl; +extern dev::TftSdl haspTft; diff --git a/src/drv/tft_driver_tftespi.cpp b/src/drv/tft_driver_tftespi.cpp new file mode 100644 index 00000000..c0dfcdd1 --- /dev/null +++ b/src/drv/tft_driver_tftespi.cpp @@ -0,0 +1,270 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifdef ARDUINO +#include "tft_driver_tftespi.h" + +namespace dev { + +void TftEspi::init(int w, int h) +{ + tft.begin(); + tft.setSwapBytes(true); /* set endianess */ +} + +void TftEspi::show_info() +{ + + setup_t tftSetup; + tft.getSetup(tftSetup); + + LOG_VERBOSE(TAG_TFT, F("TFT_eSPI : v%s"), tftSetup.version.c_str()); + LOG_VERBOSE(TAG_TFT, F("Transactns : %s"), (tftSetup.trans == 1) ? PSTR("Yes") : PSTR("No")); + LOG_VERBOSE(TAG_TFT, F("Interface : %s"), (tftSetup.serial == 1) ? PSTR("SPI") : PSTR("Parallel")); + +#if defined(ARDUINO_ARCH_ESP8266) + LOG_VERBOSE(TAG_TFT, F("SPI overlap: %s"), (tftSetup.overlap == 1) ? PSTR("Yes") : PSTR("No")); +#endif + + if(tftSetup.tft_driver != 0xE9D) // For ePaper displays the size is defined in the sketch + { + LOG_VERBOSE(TAG_TFT, F("Driver : %s"), haspTft.get_tft_model()); // tftSetup.tft_driver); + LOG_VERBOSE(TAG_TFT, F("Resolution : %ix%i"), tftSetup.tft_width, tftSetup.tft_height); + } else if(tftSetup.tft_driver == 0xE9D) + LOG_VERBOSE(TAG_TFT, F("Driver = ePaper")); + + // Offsets, not all used yet + tftOffsetInfo(0, tftSetup.r0_x_offset, tftSetup.r0_y_offset); + tftOffsetInfo(1, tftSetup.r1_x_offset, tftSetup.r1_y_offset); + tftOffsetInfo(2, tftSetup.r2_x_offset, tftSetup.r2_y_offset); + tftOffsetInfo(3, tftSetup.r3_x_offset, tftSetup.r3_y_offset); + /* replaced by tftOffsetInfo + // if(tftSetup.r1_x_offset != 0) Serial.printf("R1 x offset = %i \n", tftSetup.r1_x_offset); + // if(tftSetup.r1_y_offset != 0) Serial.printf("R1 y offset = %i \n", tftSetup.r1_y_offset); + // if(tftSetup.r2_x_offset != 0) Serial.printf("R2 x offset = %i \n", tftSetup.r2_x_offset); + // if(tftSetup.r2_y_offset != 0) Serial.printf("R2 y offset = %i \n", tftSetup.r2_y_offset); + // if(tftSetup.r3_x_offset != 0) Serial.printf("R3 x offset = %i \n", tftSetup.r3_x_offset); + // if(tftSetup.r3_y_offset != 0) Serial.printf("R3 y offset = %i \n", tftSetup.r3_y_offset); + */ + + tftPinInfo(F("MOSI"), tftSetup.pin_tft_mosi); + tftPinInfo(F("MISO"), tftSetup.pin_tft_miso); + tftPinInfo(F("SCLK"), tftSetup.pin_tft_clk); + +#if defined(ARDUINO_ARCH_ESP8266) + if(tftSetup.overlap == true) { + LOG_VERBOSE(TAG_TFT, F("Overlap selected, following pins MUST be used:")); + + LOG_VERBOSE(TAG_TFT, F("MOSI : SD1 (GPIO 8)")); + LOG_VERBOSE(TAG_TFT, F("MISO : SD0 (GPIO 7)")); + LOG_VERBOSE(TAG_TFT, F("SCK : CLK (GPIO 6)")); + LOG_VERBOSE(TAG_TFT, F("TFT_CS : D3 (GPIO 0)")); + + LOG_VERBOSE(TAG_TFT, F("TFT_DC and TFT_RST pins can be tftSetup defined")); + } +#endif + + tftPinInfo(F("TFT_CS"), tftSetup.pin_tft_cs); + tftPinInfo(F("TFT_DC"), tftSetup.pin_tft_dc); + tftPinInfo(F("TFT_RST"), tftSetup.pin_tft_rst); + + tftPinInfo(F("TOUCH_CS"), tftSetup.pin_tch_cs); + + tftPinInfo(F("TFT_WR"), tftSetup.pin_tft_wr); + tftPinInfo(F("TFT_RD"), tftSetup.pin_tft_rd); + + tftPinInfo(F("TFT_D0"), tftSetup.pin_tft_d0); + tftPinInfo(F("TFT_D1"), tftSetup.pin_tft_d1); + tftPinInfo(F("TFT_D2"), tftSetup.pin_tft_d2); + tftPinInfo(F("TFT_D3"), tftSetup.pin_tft_d3); + tftPinInfo(F("TFT_D4"), tftSetup.pin_tft_d4); + tftPinInfo(F("TFT_D5"), tftSetup.pin_tft_d5); + tftPinInfo(F("TFT_D6"), tftSetup.pin_tft_d6); + tftPinInfo(F("TFT_D7"), tftSetup.pin_tft_d7); + + if(tftSetup.serial == 1) { + LOG_VERBOSE(TAG_TFT, F("Display SPI freq. : %d.%d MHz"), tftSetup.tft_spi_freq / 10, + tftSetup.tft_spi_freq % 10); + } + if(tftSetup.pin_tch_cs != -1) { + LOG_VERBOSE(TAG_TFT, F("Touch SPI freq. : %d.%d MHz"), tftSetup.tch_spi_freq / 10, + tftSetup.tch_spi_freq % 10); + } +} + +void TftEspi::splashscreen() +{ + tft.fillScreen(TFT_DARKCYAN); + int x = (tft.width() - logoWidth) / 2; + int y = (tft.height() - logoHeight) / 2; + tft.drawXBitmap(x, y, bootscreen, logoWidth, logoHeight, TFT_WHITE); +} + +void TftEspi::set_rotation(uint8_t rotation) +{ + LOG_VERBOSE(TAG_TFT, F("Rotation : %d"), rotation); + tft.setRotation(rotation); +} + +void TftEspi::set_invert(bool invert) +{ + char buffer[4]; + memcpy_P(buffer, invert ? PSTR("yes") : PSTR("no"), sizeof(buffer)); + + LOG_VERBOSE(TAG_TFT, F("Invert Disp: %s"), buffer); + tft.invertDisplay(invert); +} + +void TftEspi::flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) +{ + size_t len = lv_area_get_size(area); + + /* Update TFT */ + tft.startWrite(); /* Start new TFT transaction */ + tft.setWindow(area->x1, area->y1, area->x2, area->y2); /* set the working window */ +#ifdef USE_DMA_TO_TFT + tft.pushPixelsDMA((uint16_t*)color_p, len); /* Write words at once */ +#else + tft.pushPixels((uint16_t*)color_p, len); /* Write words at once */ +#endif + tft.endWrite(); /* terminate TFT transaction */ + + /* Tell lvgl that flushing is done */ + lv_disp_flush_ready(disp); +} + +bool TftEspi::is_driver_pin(uint8_t pin) +{ + if(false // start condition is always needed + +// Use individual checks instead of switch statement, as some case labels could be duplicated +#ifdef TOUCH_CS + || (pin == TOUCH_CS) +#endif +#ifdef TFT_MOSI + || (pin == TFT_MOSI) +#endif +#ifdef TFT_MISO + || (pin == TFT_MISO) +#endif +#ifdef TFT_SCLK + || (pin == TFT_SCLK) +#endif +#ifdef TFT_CS + || (pin == TFT_CS) +#endif +#ifdef TFT_DC + || (pin == TFT_DC) +#endif +#ifdef TFT_BL + || (pin == TFT_BL) +#endif +#ifdef TFT_RST + || (pin == TFT_RST) +#endif +#ifdef TFT_WR + || (pin == TFT_WR) +#endif +#ifdef TFT_RD + || (pin == TFT_RD) +#endif +#ifdef TFT_D0 + || (pin == TFT_D0) +#endif +#ifdef TFT_D1 + || (pin == TFT_D1) +#endif +#ifdef TFT_D2 + || (pin == TFT_D2) +#endif +#ifdef TFT_D3 + || (pin == TFT_D3) +#endif +#ifdef TFT_D4 + || (pin == TFT_D4) +#endif +#ifdef TFT_D5 + || (pin == TFT_D5) +#endif +#ifdef TFT_D6 + || (pin == TFT_D6) +#endif +#ifdef TFT_D7 + || (pin == TFT_D7) +#endif +#ifdef TFT_D8 + || (pin == TFT_D8) +#endif +#ifdef TFT_D9 + || (pin == TFT_D9) +#endif +#ifdef TFT_D10 + || (pin == TFT_D10) +#endif +#ifdef TFT_D11 + || (pin == TFT_D11) +#endif +#ifdef TFT_D12 + || (pin == TFT_D12) +#endif +#ifdef TFT_D13 + || (pin == TFT_D13) +#endif +#ifdef TFT_D14 + || (pin == TFT_D14) +#endif +#ifdef TFT_D15 + || (pin == TFT_D15) +#endif + ) { + return true; + } + +#ifdef ARDUINO_ARCH_ESP8266 +#ifndef TFT_SPI_OVERLAP + if((pin >= 12) && (pin <= 14)) return true; // HSPI +#endif +#endif + + return false; +} + +const char* TftEspi::get_tft_model() +{ +#if defined(ILI9341_DRIVER) + return "ILI9341"; +#elif defined(ST7735_DRIVER) + return "ST7735"; +#elif defined(ILI9163_DRIVER) + return "ILI9163"; +#elif defined(S6D02A1_DRIVER) + return "S6D02A1"; +#elif defined(ST7796_DRIVER) + return "ST7796"; +#elif defined(ILI9486_DRIVER) + return "ILI9486"; +#elif defined(ILI9481_DRIVER) + return "ILI9481"; +#elif defined(ILI9488_DRIVER) + return "ILI9488"; +#elif defined(HX8357D_DRIVER) + return "HX8357D"; +#elif defined(EPD_DRIVER) + return "EPD"; +#elif defined(ST7789_DRIVER) + return "ST7789"; +#elif defined(R61581_DRIVER) + return "R61581"; +#elif defined(ST7789_2_DRIVER) + return "ST7789_2"; +#elif defined(RM68140_DRIVER) + return "RM68140"; +#else + return "Other"; +#endif +} + +} // namespace dev + +dev::TftEspi haspTft; +#endif \ No newline at end of file diff --git a/src/drv/tft_driver_tftespi.h b/src/drv/tft_driver_tftespi.h new file mode 100644 index 00000000..05e21792 --- /dev/null +++ b/src/drv/tft_driver_tftespi.h @@ -0,0 +1,68 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_TFTESPI_DRIVER_H +#define HASP_TFTESPI_DRIVER_H + +#ifdef ARDUINO +#include "Arduino.h" + +#include "lvgl.h" +#include "TFT_eSPI.h" + +#include "tft_driver.h" +#include "hal/hasp_hal.h" +#include "dev/device.h" +#include "hasp_debug.h" + +#include "bootscreen.h" // Sketch tab header for xbm images + +namespace dev { + +class TftEspi : BaseTft { + + public: + TFT_eSPI tft; + + void init(int w, int h); + void show_info(); + void splashscreen(); + + void set_rotation(uint8_t rotation); + void set_invert(bool invert); + + void flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p); + bool is_driver_pin(uint8_t pin); + + const char* get_tft_model(); + + private: + void tftOffsetInfo(uint8_t pin, uint8_t x_offset, uint8_t y_offset) + { + if(x_offset != 0) { + LOG_VERBOSE(TAG_TFT, F("R%u x offset = %i"), pin, x_offset); + } + if(y_offset != 0) { + LOG_VERBOSE(TAG_TFT, F("R%u y offset = %i"), pin, y_offset); + } + } + + void tftPinInfo(const __FlashStringHelper* pinfunction, int8_t pin) + { + if(pin != -1) { + char buffer[64]; + snprintf_P(buffer, sizeof(buffer), PSTR("%-11s: %s (GPIO %02d)"), pinfunction, halGpioName(pin).c_str(), + pin); + LOG_VERBOSE(TAG_TFT, buffer); + } + } +}; + +} // namespace dev + +using dev::TftEspi; +extern dev::TftEspi haspTft; + +#endif // ARDUINO + +#endif // HASP_TFTESPI_DRIVER_H \ No newline at end of file diff --git a/lib/lv_drv_tft_espi/tft_espi_drv.cpp b/src/drv/tft_espi_drv.cpp similarity index 69% rename from lib/lv_drv_tft_espi/tft_espi_drv.cpp rename to src/drv/tft_espi_drv.cpp index 2b51d462..5d1bd236 100644 --- a/lib/lv_drv_tft_espi/tft_espi_drv.cpp +++ b/src/drv/tft_espi_drv.cpp @@ -1,29 +1,61 @@ -/** - * @file tft_espi_drv.cpp - * - */ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ /********************* * INCLUDES *********************/ -#include "../../src/hasp_hal.h" // for halGpioName() +#include "hasp_conf.h" + +#if defined(TOUCH_CS) + +#include "hal/hasp_hal.h" // for halGpioName() +#include "dev/device.h" +#include "drv/tft_driver.h" + #include "tft_espi_drv.h" #include "ArduinoLog.h" #include "hasp_macro.h" -#if USE_TFT_ESPI != 0 +void tft_espi_calibrate(uint16_t* calData) +{ + haspTft.tft.fillScreen(TFT_BLACK); + haspTft.tft.setCursor(20, 0); + haspTft.tft.setTextFont(1); + haspTft.tft.setTextSize(1); + haspTft.tft.setTextColor(TFT_WHITE, TFT_BLACK); - #include - #include "TFT_eSPI.h" + // tft.println(PSTR("Touch corners as indicated")); - #include LV_DRV_DISP_INCLUDE - #include LV_DRV_DELAY_INCLUDE - #include "bootscreen.h" // Sketch tab header for xbm images + haspTft.tft.setTextFont(1); + delay(500); + haspTft.tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15); + haspTft.tft.setTouch(calData); +} - /********************* - * DEFINES - *********************/ - #define TAG_TFT 22 +void tft_espi_set_touch(uint16_t* calData) +{ + haspTft.tft.setTouch(calData); +} + +bool tft_espi_get_touch(int16_t* touchX, int16_t* touchY, uint16_t threshold) +{ + return haspTft.tft.getTouch((uint16_t*)touchX, (uint16_t*)touchY, threshold); +} +#endif + +#if 0 // USE_TFT_ESPI != 0 + +#include +#include "TFT_eSPI.h" + +#include LV_DRV_DISP_INCLUDE +#include LV_DRV_DELAY_INCLUDE +#include "bootscreen.h" // Sketch tab header for xbm images + +/********************* + * DEFINES + *********************/ +#define TAG_TFT 22 /********************** * TYPEDEFS @@ -32,8 +64,8 @@ /********************** * STATIC PROTOTYPES **********************/ -static void tftShowConfig(TFT_eSPI & tft); -static inline void tftShowLogo(TFT_eSPI & tft); +static void tftShowConfig(TFT_eSPI& tft); +static inline void tftShowLogo(TFT_eSPI& tft); /********************** * STATIC VARIABLES @@ -54,11 +86,11 @@ static TFT_eSPI tft; */ void tft_espi_init(uint8_t rotation, bool invert_display) { - #ifdef USE_DMA_TO_TFT +#ifdef USE_DMA_TO_TFT // DMA - should work with STM32F2xx/F4xx/F7xx processors // NOTE: >>>>>> DMA IS FOR SPI DISPLAYS ONLY <<<<<< tft.initDMA(); // Initialise the DMA engine (tested with STM32F446 and STM32F767) - #endif +#endif /* TFT init */ tft.begin(); @@ -70,18 +102,18 @@ void tft_espi_init(uint8_t rotation, bool invert_display) tftShowConfig(tft); } -void tft_espi_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p) +void tft_espi_flush(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) { size_t len = lv_area_get_size(area); /* Update TFT */ tft.startWrite(); /* Start new TFT transaction */ tft.setWindow(area->x1, area->y1, area->x2, area->y2); /* set the working window */ - #ifdef USE_DMA_TO_TFT - tft.pushPixelsDMA((uint16_t *)color_p, len); /* Write words at once */ - #else - tft.pushPixels((uint16_t *)color_p, len); /* Write words at once */ - #endif +#ifdef USE_DMA_TO_TFT + tft.pushPixelsDMA((uint16_t*)color_p, len); /* Write words at once */ +#else + tft.pushPixels((uint16_t*)color_p, len); /* Write words at once */ +#endif tft.endWrite(); /* terminate TFT transaction */ /* Tell lvgl that flushing is done */ @@ -98,9 +130,9 @@ void tft_espi_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * c // tft_espi_flush(x1, y1, x2, y2, color_p); // } - #if defined(TOUCH_CS) +#if defined(TOUCH_CS) -void tft_espi_calibrate(uint16_t * calData) +void tft_espi_calibrate(uint16_t* calData) { tft.fillScreen(TFT_BLACK); tft.setCursor(20, 0); @@ -116,24 +148,24 @@ void tft_espi_calibrate(uint16_t * calData) tft.setTouch(calData); } -void tft_espi_set_touch(uint16_t * calData) +void tft_espi_set_touch(uint16_t* calData) { tft.setTouch(calData); } -bool tft_espi_get_touch(int16_t * touchX, int16_t * touchY, uint16_t threshold) +bool tft_espi_get_touch(int16_t* touchX, int16_t* touchY, uint16_t threshold) { - return tft.getTouch((uint16_t *)touchX, (uint16_t *)touchY, threshold); + return tft.getTouch((uint16_t*)touchX, (uint16_t*)touchY, threshold); } - #endif +#endif /********************** * STATIC FUNCTIONS **********************/ - #if defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) ADC_MODE(ADC_VCC); // tftShowConfig measures the voltage on the pin - #endif +#endif static void tftOffsetInfo(uint8_t pin, uint8_t x_offset, uint8_t y_offset) { @@ -145,7 +177,7 @@ static void tftOffsetInfo(uint8_t pin, uint8_t x_offset, uint8_t y_offset) } } -static void tftPinInfo(const __FlashStringHelper * pinfunction, int8_t pin) +static void tftPinInfo(const __FlashStringHelper* pinfunction, int8_t pin) { if(pin != -1) { char buffer[64]; @@ -154,27 +186,28 @@ static void tftPinInfo(const __FlashStringHelper * pinfunction, int8_t pin) } } -static void tftShowConfig(TFT_eSPI & tft) +static void tftShowConfig(TFT_eSPI& tft) { setup_t tftSetup; tft.getSetup(tftSetup); - LOG_VERBOSE(TAG_TFT, F("TFT_eSPI : v%s"), tftSetup.version.c_str()); - #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - LOG_VERBOSE(TAG_TFT, F("Processor : ESP%x"), tftSetup.esp); - #else - LOG_VERBOSE(TAG_TFT, F("Processor : STM%x"), tftSetup.esp); - #endif - LOG_VERBOSE(TAG_TFT, F("CPU freq. : %i MHz"), halGetCpuFreqMHz()); + // LOG_VERBOSE(TAG_TFT, F("TFT_eSPI : v%s"), tftSetup.version.c_str()); + // #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + // LOG_VERBOSE(TAG_TFT, F("Processor : ESP%x"), tftSetup.esp); + // #else + // LOG_VERBOSE(TAG_TFT, F("Processor : STM%x"), tftSetup.esp); + // #endif + // LOG_VERBOSE(TAG_TFT, F("CPU freq. : %i MHz"), haspDevice.get_cpu_frequency()); + + // #if defined(ARDUINO_ARCH_ESP8266) + // LOG_VERBOSE(TAG_TFT, F("Voltage : %2.2f V"), ESP.getVcc() / 918.0); // 918 empirically determined + // #endif - #if defined(ARDUINO_ARCH_ESP8266) - LOG_VERBOSE(TAG_TFT, F("Voltage : %2.2f V"), ESP.getVcc() / 918.0); // 918 empirically determined - #endif LOG_VERBOSE(TAG_TFT, F("Transactns : %s"), (tftSetup.trans == 1) ? PSTR("Yes") : PSTR("No")); LOG_VERBOSE(TAG_TFT, F("Interface : %s"), (tftSetup.serial == 1) ? PSTR("SPI") : PSTR("Parallel")); - #if defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) LOG_VERBOSE(TAG_TFT, F("SPI overlap: %s"), (tftSetup.overlap == 1) ? PSTR("Yes") : PSTR("No")); - #endif +#endif if(tftSetup.tft_driver != 0xE9D) // For ePaper displays the size is defined in the sketch { @@ -201,7 +234,7 @@ static void tftShowConfig(TFT_eSPI & tft) tftPinInfo(F("MISO"), tftSetup.pin_tft_miso); tftPinInfo(F("SCLK"), tftSetup.pin_tft_clk); - #if defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) if(tftSetup.overlap == true) { LOG_VERBOSE(TAG_TFT, F("Overlap selected, following pins MUST be used:")); @@ -212,7 +245,7 @@ static void tftShowConfig(TFT_eSPI & tft) LOG_VERBOSE(TAG_TFT, F("TFT_DC and TFT_RST pins can be tftSetup defined")); } - #endif +#endif tftPinInfo(F("TFT_CS"), tftSetup.pin_tft_cs); tftPinInfo(F("TFT_DC"), tftSetup.pin_tft_dc); @@ -242,7 +275,7 @@ static void tftShowConfig(TFT_eSPI & tft) } } -static inline void tftShowLogo(TFT_eSPI & tft) +static inline void tftShowLogo(TFT_eSPI& tft) { tft.fillScreen(TFT_DARKCYAN); int x = (tft.width() - logoWidth) / 2; diff --git a/src/drv/tft_espi_drv.h b/src/drv/tft_espi_drv.h new file mode 100644 index 00000000..9f55e73f --- /dev/null +++ b/src/drv/tft_espi_drv.h @@ -0,0 +1,63 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef TFT_ESPI_DRV_H +#define TFT_ESPI_DRV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_TFT_ESPI + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void tft_espi_init(uint8_t rotation, bool invert_display = false); +void tft_espi_flush(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p); +// void tft_espi_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); +void tft_espi_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); +void tft_espi_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t* color_p); + +#if defined(TOUCH_CS) +void tft_espi_calibrate(uint16_t* calData); +void tft_espi_set_touch(uint16_t* calData); +bool tft_espi_get_touch(int16_t* touchX, int16_t* touchY, uint16_t threshold); +#endif + +/********************** + * MACROS + **********************/ + +#endif /* USE_TFT_ESPI */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* TFT_ESPI_DRV_H */ diff --git a/src/drv/hasp_drv_ft5206.cpp b/src/drv/touch/hasp_drv_ft5206.cpp similarity index 100% rename from src/drv/hasp_drv_ft5206.cpp rename to src/drv/touch/hasp_drv_ft5206.cpp diff --git a/src/drv/touch/hasp_drv_ft5206.h b/src/drv/touch/hasp_drv_ft5206.h new file mode 100644 index 00000000..1922d7cb --- /dev/null +++ b/src/drv/touch/hasp_drv_ft5206.h @@ -0,0 +1,17 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_DRV_FT5206_H +#define HASP_DRV_FT5206_H + +#if TOUCH_DRIVER == 5206 + +#define FT5206_address 0x38 + +#include "hasp_debug.h" // for TAG_DRVR + +bool FT5206_getXY(int16_t* touchX, int16_t* touchY, bool debug); +void FT5206_init(); + +#endif +#endif \ No newline at end of file diff --git a/src/drv/hasp_drv_ft6336u.cpp b/src/drv/touch/hasp_drv_ft6336u.cpp similarity index 100% rename from src/drv/hasp_drv_ft6336u.cpp rename to src/drv/touch/hasp_drv_ft6336u.cpp diff --git a/src/drv/hasp_drv_ft6336u.h b/src/drv/touch/hasp_drv_ft6336u.h similarity index 54% rename from src/drv/hasp_drv_ft6336u.h rename to src/drv/touch/hasp_drv_ft6336u.h index f8e0e1e3..a52100e1 100644 --- a/src/drv/hasp_drv_ft6336u.h +++ b/src/drv/touch/hasp_drv_ft6336u.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_DRV_FT6336U_H @@ -6,9 +6,9 @@ #if TOUCH_DRIVER == 6336 - #include "hasp_debug.h" // for TAG_DRVR +#include "hasp_debug.h" // for TAG_DRVR -bool FT6336U_getXY(int16_t * touchX, int16_t * touchY, bool debug); +bool FT6336U_getXY(int16_t* touchX, int16_t* touchY, bool debug); void FT6336U_init(); #endif diff --git a/src/drv/hasp_drv_gt911.cpp b/src/drv/touch/hasp_drv_gt911.cpp similarity index 90% rename from src/drv/hasp_drv_gt911.cpp rename to src/drv/touch/hasp_drv_gt911.cpp index 1d2ee59f..eebba5b1 100644 --- a/src/drv/hasp_drv_gt911.cpp +++ b/src/drv/touch/hasp_drv_gt911.cpp @@ -19,11 +19,11 @@ void GT911_setXY(int8_t contacts, GTPoint * points) GT911_num_touches = contacts; GT911_points = points; - LOG_VERBOSE(TAG_GUI, F("Contacts: %d"), contacts); - for(int i = 0; i < contacts; i++) { - LOG_VERBOSE(TAG_GUI, F("C%d: #%d %d,%d s:%d"), i, points[i].trackId, points[i].x, points[i].y, points[i].area); - yield(); - } + // LOG_VERBOSE(TAG_GUI, F("Contacts: %d"), contacts); + // for(int i = 0; i < contacts; i++) { + // LOG_VERBOSE(TAG_GUI, F("C%d: #%d %d,%d s:%d"), i, points[i].trackId, points[i].x, points[i].y, points[i].area); + // yield(); + // } } // Read touch points from global variable diff --git a/src/drv/hasp_drv_gt911.h b/src/drv/touch/hasp_drv_gt911.h similarity index 55% rename from src/drv/hasp_drv_gt911.h rename to src/drv/touch/hasp_drv_gt911.h index d72627a0..727a84e7 100644 --- a/src/drv/hasp_drv_gt911.h +++ b/src/drv/touch/hasp_drv_gt911.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_DRV_911_H @@ -6,9 +6,9 @@ #if TOUCH_DRIVER == 911 - #include "hasp_debug.h" // for TAG_DRVR +#include "hasp_debug.h" // for TAG_DRVR -bool GT911_getXY(int16_t * touchX, int16_t * touchY, bool debug); +bool GT911_getXY(int16_t* touchX, int16_t* touchY, bool debug); void GT911_init(); void GT911_loop(); diff --git a/src/drv/touch/hasp_drv_stmpe610.cpp b/src/drv/touch/hasp_drv_stmpe610.cpp new file mode 100644 index 00000000..f1a6df4a --- /dev/null +++ b/src/drv/touch/hasp_drv_stmpe610.cpp @@ -0,0 +1,69 @@ +#if TOUCH_DRIVER == 610 + + #include + #include "Adafruit_STMPE610.h" + #include "ArduinoLog.h" + + #include "hasp_drv_stmpe610.h" + +// This is calibration data for the raw touch data to the screen coordinates + #define TS_MINX 3800 + #define TS_MAXX 100 + #define TS_MINY 100 + #define TS_MAXY 3750 + +static Adafruit_STMPE610 touch = Adafruit_STMPE610(STMPE_CS); + +// Read touch points from global variable +bool IRAM_ATTR STMPE610_getXY(int16_t * touchX, int16_t * touchY, uint8_t touchRotation, bool debug) +{ + uint16_t x, y; + uint8_t z; + if(! touch.touched()) return false; + + while (! touch.bufferEmpty()) { + touch.readData(&x, &y, &z); + if(debug) Log.trace(TAG_DRVR, F("STMPE610: x=%i y=%i z=%i r=%i"), x, y, z, touchRotation); + } + touch.writeRegister8(STMPE_INT_STA, 0xFF); + if (1 == touchRotation) { + #if HX8357D_DRIVER == 1 + y = map(y, TS_MINX, TS_MAXX, 0, TFT_HEIGHT); + x = map(x, TS_MINY, TS_MAXY, TFT_WIDTH, 0); + #else + x = map(x, TS_MAXX, TS_MINX, 0, TFT_WIDTH); + y = map(y, TS_MAXY, TS_MINY, 0, TFT_HEIGHT); + #endif + } else if (2 == touchRotation) { + #if HX8357D_DRIVER == 1 + x = map(x, TS_MAXX, TS_MINX, TFT_WIDTH, 0); + y = map(y, TS_MAXY, TS_MINY, 0, TFT_HEIGHT); + #else + x = map(x, TS_MAXX, TS_MINX, 0, TFT_WIDTH); + y = map(y, TS_MAXY, TS_MINY, 0, TFT_HEIGHT); + #endif + } else { + #if HX8357D_DRIVER == 1 + x = map(x, TS_MINX, TS_MAXX, TFT_WIDTH, 0); + y = map(y, TS_MINY, TS_MAXY, 0, TFT_HEIGHT); + #else + x = map(x, TS_MINX, TS_MAXX, 0, TFT_WIDTH); + y = map(y, TS_MINY, TS_MAXY, 0, TFT_HEIGHT); + #endif + } + + *touchX = x; + *touchY = y; + return true; + +} + +void STMPE610_init() +{ + if (! touch.begin()) { + Log.trace(TAG_DRVR, F("STMPE610 not found!")); + } else { + Log.trace(TAG_DRVR, F("STMPE610 touch driver started")); + } +} +#endif \ No newline at end of file diff --git a/src/drv/touch/hasp_drv_stmpe610.h b/src/drv/touch/hasp_drv_stmpe610.h new file mode 100644 index 00000000..2eb07f99 --- /dev/null +++ b/src/drv/touch/hasp_drv_stmpe610.h @@ -0,0 +1,15 @@ +/* MIT License - Copyright (c) 2020 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_DRV_STMPE610_H +#define HASP_DRV_STMPE610_H + +#if TOUCH_DRIVER == 610 + + #include "hasp_debug.h" // for TAG_DRVR + +bool IRAM_ATTR STMPE610_getXY(int16_t * touchX, int16_t * touchY, uint8_t touchRotation, bool debug); +void STMPE610_init(); + +#endif +#endif \ No newline at end of file diff --git a/src/drv/hasp_drv_xpt2046.cpp b/src/drv/touch/hasp_drv_xpt2046.cpp similarity index 100% rename from src/drv/hasp_drv_xpt2046.cpp rename to src/drv/touch/hasp_drv_xpt2046.cpp diff --git a/src/drv/touch/hasp_drv_xpt2046.h b/src/drv/touch/hasp_drv_xpt2046.h new file mode 100644 index 00000000..e4217fa9 --- /dev/null +++ b/src/drv/touch/hasp_drv_xpt2046.h @@ -0,0 +1,24 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_DRV_XPT2046B_H +#define HASP_DRV_XPT2046B_H + +#if TOUCH_DRIVER == 0x2046B + +#include "XPT2046_Touchscreen.h" + +#define XPT2046_HOR_RES TFT_WIDTH +#define XPT2046_VER_RES TFT_HEIGHT +#define XPT2046_X_MIN 200 +#define XPT2046_Y_MIN 200 +#define XPT2046_X_MAX 3800 +#define XPT2046_Y_MAX 3800 +#define XPT2046_AVG 4 +#define XPT2046_INV 0 + +bool XPT2046_getXY(int16_t* touchX, int16_t* touchY, bool debug); +void XPT2046_init(); + +#endif +#endif \ No newline at end of file diff --git a/src/hal/README.md b/src/hal/README.md new file mode 100644 index 00000000..25db048a --- /dev/null +++ b/src/hal/README.md @@ -0,0 +1,2 @@ +These files need to be obsoleted. +The functions should be moved to the respective device ot tft objects. \ No newline at end of file diff --git a/src/hasp_hal.cpp b/src/hal/hasp_hal.cpp similarity index 85% rename from src/hasp_hal.cpp rename to src/hal/hasp_hal.cpp index aa0323d0..0b2bc579 100644 --- a/src/hasp_hal.cpp +++ b/src/hal/hasp_hal.cpp @@ -1,22 +1,22 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #include "hasp_hal.h" #include "hasp_conf.h" #if defined(ESP8266) - #include - #include +#include +#include #endif #if defined(ESP32) - #include - #include - #include "esp_system.h" +#include +#include +#include "esp_system.h" #endif #if defined(ARDUINO_ARCH_ESP32) - #include // needed to get the ResetInfo +#include // needed to get the ResetInfo // Compatibility function for ESP8266 getRestInfo String esp32ResetReason(uint8_t cpuid) @@ -26,7 +26,7 @@ String esp32ResetReason(uint8_t cpuid) } RESET_REASON reason = rtc_get_reset_reason(cpuid); - String resetReason((char *)0); + String resetReason((char*)0); resetReason.reserve(128); resetReason += F("CPU"); @@ -102,7 +102,7 @@ void halRestartMcu(void) String halGetResetInfo() { #if defined(ARDUINO_ARCH_ESP32) - String resetReason((char *)0); + String resetReason((char*)0); resetReason.reserve(128); resetReason += String(esp32ResetReason(0)); @@ -116,20 +116,20 @@ String halGetResetInfo() #endif } -String halGetCoreVersion() -{ -#if defined(ARDUINO_ARCH_ESP32) - return String(ESP.getSdkVersion()); -#elif defined(ARDUINO_ARCH_ESP8266) - return String(ESP.getCoreVersion()); -#else - return String(STM32_CORE_VERSION_MAJOR) + "." + STM32_CORE_VERSION_MINOR + "." + STM32_CORE_VERSION_PATCH; -#endif -} +// String halGetCoreVersion() +// { +// #if defined(ARDUINO_ARCH_ESP32) +// return String(ESP.getSdkVersion()); +// #elif defined(ARDUINO_ARCH_ESP8266) +// return String(ESP.getCoreVersion()); +// #else +// return String(STM32_CORE_VERSION_MAJOR) + "." + STM32_CORE_VERSION_MINOR + "." + STM32_CORE_VERSION_PATCH; +// #endif +// } String halGetChipModel() { - String model((char *)0); + String model((char*)0); model.reserve(128); #if defined(STM32F4xx) @@ -152,11 +152,11 @@ String halGetChipModel() case CHIP_ESP32: model += F("ESP32"); break; - #ifdef CHIP_ESP32S2 +#ifdef CHIP_ESP32S2 case CHIP_ESP32S2: model += F("ESP32-S2"); break; - #endif +#endif default: model = F("Unknown ESP32"); } @@ -174,19 +174,19 @@ String halGetChipModel() /* Memory Management Functions */ #if defined(STM32F4xx) - #include // for mallinfo() - #include // for sbrk() +#include // for mallinfo() +#include // for sbrk() int freeHighMemory() { char top; - #ifdef __arm__ - return &top - reinterpret_cast(sbrk(0)); - #elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151) +#ifdef __arm__ + return &top - reinterpret_cast(sbrk(0)); +#elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151) return &top - __brkval; - #else // __arm__ +#else // __arm__ return __brkval ? &top - __brkval : &top - __malloc_heap_start; - #endif // __arm__ +#endif // __arm__ } #endif @@ -254,25 +254,25 @@ uint8_t halGetHeapFragmentation() #endif } -String halGetMacAddress(int start, const char * seperator) +String halGetMacAddress(int start, const char* seperator) { byte mac[6]; #if defined(STM32F4xx) - uint8_t * mac_p = nullptr; - #if HASP_USE_ETHERNET > 0 - #if USE_BUILTIN_ETHERNET > 0 + uint8_t* mac_p = nullptr; +#if HASP_USE_ETHERNET > 0 +#if USE_BUILTIN_ETHERNET > 0 mac_p = Ethernet.MACAddress(); for(int i = 0; i < 6; i++) mac[i] = *(mac_p + i); - #else +#else Ethernet.macAddress(mac); - #endif - #endif +#endif +#endif #else WiFi.macAddress(mac); #endif - String cMac((char *)0); + String cMac((char*)0); cMac.reserve(32); for(int i = start; i < 6; ++i) { @@ -293,8 +293,6 @@ uint16_t halGetCpuFreqMHz() #endif } - - String halDisplayDriverName() { #if defined(ILI9341_DRIVER) @@ -342,56 +340,56 @@ String halGpioName(uint8_t gpio) case PortName::PortB: ioName = F("PB"); break; - #if defined GPIOC_BASE +#if defined GPIOC_BASE case PortName::PortC: ioName = F("PC"); break; - #endif - #if defined GPIOD_BASE +#endif +#if defined GPIOD_BASE case PortName::PortD: ioName = F("PD"); break; - #endif - #if defined GPIOE_BASE +#endif +#if defined GPIOE_BASE case PortName::PortE: ioName = F("PE"); break; - #endif - #if defined GPIOF_BASE +#endif +#if defined GPIOF_BASE case PortName::PortF: ioName = F("PF"); break; - #endif - #if defined GPIOG_BASE +#endif +#if defined GPIOG_BASE case PortName::PortG: ioName = F("PG"); break; - #endif - #if defined GPIOH_BASE +#endif +#if defined GPIOH_BASE case PortName::PortH: ioName = F("PH"); break; - #endif - #if defined GPIOI_BASE +#endif +#if defined GPIOI_BASE case PortName::PortI: ioName = F("PI"); break; - #endif - #if defined GPIOJ_BASE +#endif +#if defined GPIOJ_BASE case PortName::PortJ: ioName = F("PJ"); break; - #endif - #if defined GPIOK_BASE +#endif +#if defined GPIOK_BASE case PortName::PortK: ioName = F("PK"); break; - #endif - #if defined GPIOZ_BASE +#endif +#if defined GPIOZ_BASE case PortName::PortZ: ioName = F("PZ"); break; - #endif +#endif default: ioName = F("P?"); } diff --git a/src/hal/hasp_hal.h b/src/hal/hasp_hal.h new file mode 100644 index 00000000..61cfa2a5 --- /dev/null +++ b/src/hal/hasp_hal.h @@ -0,0 +1,21 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_HAL_H +#define HASP_HAL_H + +#include + +// void halRestartMcu(void); +String halGetResetInfo(void); +// uint8_t halGetHeapFragmentation(void); +// size_t halGetMaxFreeBlock(void); +// size_t halGetFreeHeap(void); +// String halGetCoreVersion(void); +// String halGetChipModel(); +String halGetMacAddress(int start, const char* seperator); +// uint16_t halGetCpuFreqMHz(void); +// String halDisplayDriverName(void); +String halGpioName(uint8_t gpio); + +#endif \ No newline at end of file diff --git a/src/hasp/hasp.cpp b/src/hasp/hasp.cpp index 50008358..d2be0930 100644 --- a/src/hasp/hasp.cpp +++ b/src/hasp/hasp.cpp @@ -1,35 +1,45 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ -#include "hasp_conf.h" +#ifdef ARDUINO +#include "ArduinoLog.h" +#endif + +#if defined(WINDOWS) || defined(POSIX) +#include +#include +#include +#endif #include "ArduinoJson.h" -#include "ArduinoLog.h" #if HASP_USE_EEPROM > 0 - #include "StreamUtils.h" // For EEPromStream +#include "StreamUtils.h" // For EEPromStream #endif #include "lvgl.h" #include "lv_conf.h" -#include "hasp_conf.h" #if HASP_USE_DEBUG > 0 - #include "lv_fs_if.h" - #include "hasp_debug.h" - #include "hasp_config.h" - #include "hasp_gui.h" +#include "../hasp_debug.h" +#endif + +#if HASP_USE_CONFIG > 0 +#include "lv_fs_if.h" +#include "hasp_gui.h" +#include "hasp_config.h" //#include "hasp_filesystem.h" included in hasp_conf.h #endif -#include "hasp_object.h" -#include "hasp_dispatch.h" - -#include "hasp_attribute.h" +#include "hasplib.h" #include "hasp.h" #include "lv_theme_hasp.h" +#include "dev/device.h" + +#if HASP_USE_EEPROM > 0 #include "EEPROM.h" +#endif //#if LV_USE_HASP @@ -65,7 +75,6 @@ LV_IMG_DECLARE(img_bubble_pattern) /********************** * GLOBAL FUNCTIONS **********************/ -void haspLoadPage(const char * pages); //////////////////////////////////////////////////////////////////////////////////////////////////// uint8_t hasp_sleep_state = HASP_SLEEP_OFF; // Used in hasp_drv_touch.cpp @@ -80,18 +89,16 @@ char haspPagesPath[32] = "/pages.jsonl"; char haspZiFontPath[32]; lv_style_t style_mbox_bg; /*Black bg. style with opacity*/ -lv_obj_t * kb; +lv_obj_t* kb; // lv_font_t * defaultFont; -lv_obj_t * pages[HASP_NUM_PAGES]; -static lv_font_t * haspFonts[4] = {nullptr, LV_THEME_DEFAULT_FONT_NORMAL, LV_THEME_DEFAULT_FONT_SUBTITLE, - LV_THEME_DEFAULT_FONT_TITLE}; -uint8_t current_page = 1; +static lv_font_t* haspFonts[4] = {nullptr, nullptr, nullptr, nullptr}; +uint8_t current_page = 1; /** * Get Font ID */ -lv_font_t * hasp_get_font(uint8_t fontid) +lv_font_t* hasp_get_font(uint8_t fontid) { if(fontid >= 4) { return nullptr; @@ -129,15 +136,21 @@ bool hasp_update_sleep_state() void hasp_enable_wakeup_touch() { - LOG_VERBOSE(TAG_HASP,F("Wakeup touch enabled")); + LOG_VERBOSE(TAG_HASP, F("Wakeup touch enabled")); lv_obj_set_click(lv_disp_get_layer_sys(NULL), true); // enable first touch lv_obj_set_event_cb(lv_disp_get_layer_sys(NULL), wakeup_event_handler); } +void hasp_disable_wakeup_touch() +{ + LOG_VERBOSE(TAG_HASP, F("Wakeup touch disabled")); + lv_obj_set_click(lv_disp_get_layer_sys(NULL), false); // disable first touch +} + /** * Return the sleep times */ -void hasp_get_sleep_time(uint16_t & short_time, uint16_t & long_time) +void hasp_get_sleep_time(uint16_t& short_time, uint16_t& long_time) { short_time = sleepTimeShort; long_time = sleepTimeLong; @@ -155,45 +168,10 @@ void hasp_set_sleep_time(uint16_t short_time, uint16_t long_time) /** * Checks if we went to sleep, wake up is handled in the event handlers */ -// void haspEverySecond() -// { -// hasp_update_sleep_state(); -// } - -//////////////////////////////////////////////////////////////////////////////////////////////////// -/** - * Get Page Object by PageID - */ -lv_obj_t * get_page_obj(uint8_t pageid) +void haspEverySecond() { - if(pageid == 0) return lv_layer_top(); // 254 - if(pageid == 255) return lv_layer_sys(); - if(pageid > sizeof pages / sizeof *pages) return NULL; // >=0 - return pages[pageid - PAGE_START_INDEX]; -} - -bool get_page_id(lv_obj_t * obj, uint8_t * pageid) -{ - lv_obj_t * page = lv_obj_get_screen(obj); - - if(!page) return false; - - if(page == lv_layer_top()) { - *pageid = 0; // 254 - return true; - } - if(page == lv_layer_sys()) { - *pageid = 255; - return true; - } - - for(uint8_t i = 0; i < sizeof pages / sizeof *pages; i++) { - if(page == pages[i]) { - *pageid = i + PAGE_START_INDEX; - return true; - } - } - return false; + hasp_update_sleep_state(); + dispatchEverySecond(); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -240,8 +218,8 @@ void haspReconnect() // Shows/hides the the global progress bar and updates the value void haspProgressVal(uint8_t val) { - lv_obj_t * layer = lv_disp_get_layer_sys(NULL); - lv_obj_t * bar = hasp_find_obj_from_parent_id(get_page_obj(255), (uint8_t)10); + lv_obj_t* layer = lv_disp_get_layer_sys(NULL); + lv_obj_t* bar = hasp_find_obj_from_parent_id(haspPages.get_obj(255), (uint8_t)10); if(layer && bar) { if(val == 255) { if(!lv_obj_get_hidden(bar)) { @@ -263,14 +241,14 @@ void haspProgressVal(uint8_t val) } lv_bar_set_value(bar, val, LV_ANIM_OFF); } - lv_task_handler(); /* let the GUI do its work */ + lv_task_handler(); // needed to let the GUI do its work during long updates } } // Sets the value string of the global progress bar -void haspProgressMsg(const char * msg) +void haspProgressMsg(const char* msg) { - lv_obj_t * bar = hasp_find_obj_from_parent_id(get_page_obj(255), (uint8_t)10); + lv_obj_t* bar = hasp_find_obj_from_parent_id(haspPages.get_obj(255), (uint8_t)10); if(bar) { char value_str[10]; @@ -278,27 +256,29 @@ void haspProgressMsg(const char * msg) hasp_process_obj_attribute(bar, value_str, msg, true); } - lv_task_handler(); /* let the GUI do its work */ + lv_task_handler(); // needed to let the GUI do its work during long updates /* if(bar) { progress_str.reserve(64); progress_str = msg; lv_obj_set_style_local_value_str(bar, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, progress_str.c_str()); - lv_task_handler(); // let the GUI do its work + // lv_task_handler(); // let the GUI do its work } */ } +#ifdef ARDUINO // Sets the value string of the global progress bar -void haspProgressMsg(const __FlashStringHelper * msg) +void haspProgressMsg(const __FlashStringHelper* msg) { haspProgressMsg(String(msg).c_str()); } +#endif /*Add a custom apply callback*/ -static void custom_font_apply_cb(lv_theme_t * th, lv_obj_t * obj, lv_theme_style_t name) +static void custom_font_apply_cb(lv_theme_t* th, lv_obj_t* obj, lv_theme_style_t name) { - lv_style_list_t * list; + lv_style_list_t* list; switch(name) { case LV_THEME_BTN: @@ -313,7 +293,7 @@ static void custom_font_apply_cb(lv_theme_t * th, lv_obj_t * obj, lv_theme_style */ void haspSetup(void) { - guiSetDim(haspStartDim); + haspDevice.set_backlight_level(haspStartDim); /******* File System Test ********************************************************************/ // lv_fs_file_t f; @@ -345,18 +325,35 @@ void haspSetup(void) /* ********** Font Initializations ********** */ + LOG_WARNING(TAG_ATTR, "%s %d %x", __FILE__, __LINE__, nullptr); + LOG_WARNING(TAG_ATTR, "%s %d %x", __FILE__, __LINE__, haspFonts[0]); + // LOG_WARNING(TAG_ATTR, "%s %d %x", __FILE__, __LINE__, &robotocondensed_regular_16_nokern); + #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 - #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) + + lv_font_t* hasp_font = nullptr; // required or font init will crash lv_zifont_init(); - if(lv_zifont_font_init(&haspFonts[1], haspZiFontPath, 32) != 0) { + // WARNING: hasp_font needs to be null ! + if(lv_zifont_font_init(&hasp_font, haspZiFontPath, 32) != 0) { LOG_ERROR(TAG_HASP, F("Failed to set font to %s"), haspZiFontPath); - haspFonts[1] = LV_FONT_DEFAULT; + haspFonts[0] = LV_THEME_DEFAULT_FONT_SMALL; } else { // defaultFont = haspFonts[0]; + haspFonts[0] = hasp_font; // save it } - #endif + + // LOG_WARNING(TAG_ATTR, "%s %d %x", __FILE__, __LINE__, robotocondensed_regular_16_nokern); + LOG_WARNING(TAG_ATTR, "%s %d %x", __FILE__, __LINE__, *hasp_font); + #endif +#endif + + if(haspFonts[0] == nullptr) haspFonts[0] = LV_THEME_DEFAULT_FONT_SMALL; + if(haspFonts[1] == nullptr) haspFonts[1] = LV_THEME_DEFAULT_FONT_NORMAL; + if(haspFonts[2] == nullptr) haspFonts[2] = LV_THEME_DEFAULT_FONT_SUBTITLE; + if(haspFonts[3] == nullptr) haspFonts[3] = LV_THEME_DEFAULT_FONT_TITLE; // haspFonts[0] = lv_font_load("E:/font_1.fnt"); // haspFonts[2] = lv_font_load("E:/font_2.fnt"); @@ -367,7 +364,7 @@ void haspSetup(void) if(haspThemeId == 9) haspThemeId = 5; // update old material id if(haspThemeId < 0 || haspThemeId > 5) haspThemeId = 1; // check bounds - lv_theme_t * th = NULL; + lv_theme_t* th = NULL; #if(LV_USE_THEME_HASP == 1) lv_theme_hasp_flag_t hasp_flags = LV_THEME_HASP_FLAG_LIGHT; #endif @@ -448,9 +445,6 @@ void haspSetup(void) } /* Create all screens using the theme */ - for(int i = 0; i < (sizeof pages / sizeof *pages); i++) { - pages[i] = lv_obj_create(NULL, NULL); - } #if HASP_USE_WIFI > 0 if(!wifiShowAP()) { @@ -458,8 +452,9 @@ void haspSetup(void) } #endif - haspLoadPage(haspPagesPath); - haspSetPage(haspStartPage); + haspPages.init(haspStartPage); + haspPages.load_jsonl(haspPagesPath); + haspPages.set(haspStartPage, LV_SCR_LOAD_ANIM_NONE); } /********************** @@ -467,7 +462,9 @@ void haspSetup(void) **********************/ void haspLoop(void) -{} +{ + dispatchLoop(); +} /* void hasp_background(uint16_t pageid, uint16_t imageid) @@ -520,14 +517,14 @@ void hasp_background(uint16_t pageid, uint16_t imageid) /////////////////////////////////////////////////////////////////////////////////////////////////////////// -void haspGetVersion(char * version, size_t len) +void haspGetVersion(char* version, size_t len) { snprintf_P(version, len, PSTR("%u.%u.%u"), HASP_VER_MAJ, HASP_VER_MIN, HASP_VER_REV); } void haspClearPage(uint16_t pageid) { - lv_obj_t * page = get_page_obj(pageid); + lv_obj_t* page = haspPages.get_obj(pageid); if(!page || (pageid > HASP_NUM_PAGES)) { LOG_WARNING(TAG_HASP, F(D_HASP_INVALID_PAGE), pageid); } else if(page == lv_layer_sys() /*|| page == lv_layer_top()*/) { @@ -545,7 +542,7 @@ uint8_t haspGetPage() void haspSetPage(uint8_t pageid) { - lv_obj_t * page = get_page_obj(pageid); + lv_obj_t* page = haspPages.get_obj(pageid); if(!page || pageid == 0 || pageid > HASP_NUM_PAGES) { LOG_WARNING(TAG_HASP, F(D_HASP_INVALID_PAGE), pageid); } else { @@ -556,7 +553,7 @@ void haspSetPage(uint8_t pageid) } } -void haspLoadPage(const char * pagesfile) +void haspLoadPage(const char* pagesfile) { #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 if(pagesfile[0] == '\0') return; @@ -580,19 +577,28 @@ void haspLoadPage(const char * pagesfile) LOG_INFO(TAG_HASP, F("File %s loaded"), pagesfile); #else - #if HASP_USE_EEPROM > 0 +#if HASP_USE_EEPROM > 0 LOG_TRACE(TAG_HASP, F("Loading jsonl from EEPROM...")); EepromStream eepromStream(4096, 1024); dispatch_parse_jsonl(eepromStream); LOG_INFO(TAG_HASP, F("Loaded jsonl from EEPROM")); - #endif +#endif + + std::ifstream ifs("pages.json", std::ifstream::in); + if(ifs) { + LOG_TRACE(TAG_HASP, F("Loading file %s"), pagesfile); + dispatch_parse_jsonl(ifs); + LOG_INFO(TAG_HASP, F("File %s loaded"), pagesfile); + } else { + LOG_ERROR(TAG_HASP, F("Non existing file %s"), pagesfile); + } #endif } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if HASP_USE_CONFIG > 0 -bool haspGetConfig(const JsonObject & settings) +bool haspGetConfig(const JsonObject& settings) { bool changed = false; @@ -626,7 +632,7 @@ bool haspGetConfig(const JsonObject & settings) * * @param[in] settings JsonObject with the config settings. **/ -bool haspSetConfig(const JsonObject & settings) +bool haspSetConfig(const JsonObject& settings) { configOutput(settings, TAG_HASP); bool changed = false; diff --git a/src/hasp/hasp.h b/src/hasp/hasp.h index edc5512b..a84749cb 100644 --- a/src/hasp/hasp.h +++ b/src/hasp/hasp.h @@ -1,17 +1,22 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_H #define HASP_H -#define NORMALIZE(a, b, c) map(a, b, c, 0, 0xFFFFU) +#ifdef ARDUINO +#include "Arduino.h" +#endif -#include #include "lvgl.h" #include "hasp_conf.h" +#include "hasp_conf.h" +#include "hasp_utilities.h" + #if HASP_USE_DEBUG > 0 - #include "../hasp_debug.h" +#include "../hasp_debug.h" +#include "dev/device.h" #endif #ifdef __cplusplus @@ -24,12 +29,12 @@ extern "C" { #if HASP_USE_APP > 0 - /********************* - * DEFINES - *********************/ - #define HASP_SLEEP_OFF 0 - #define HASP_SLEEP_SHORT 1 - #define HASP_SLEEP_LONG 2 +/********************* + * DEFINES + *********************/ +#define HASP_SLEEP_OFF 0 +#define HASP_SLEEP_SHORT 1 +#define HASP_SLEEP_LONG 2 /********************** * TYPEDEFS @@ -44,41 +49,34 @@ extern "C" { */ void haspSetup(void); void haspLoop(void); -// void haspEverySecond(void); // See MACROS +void haspEverySecond(void); void haspReconnect(void); void haspDisconnect(void); -lv_obj_t * get_page_obj(uint8_t pageid); -bool get_page_id(lv_obj_t * obj, uint8_t * pageid); - -void haspSetPage(uint8_t id); -uint8_t haspGetPage(); -void haspClearPage(uint16_t pageid); - -void haspGetVersion(char * version, size_t len); +void haspGetVersion(char* version, size_t len); // void haspBackground(uint16_t pageid, uint16_t imageid); // void haspNewObject(const JsonObject & config, uint8_t & saved_page_id); void haspProgressVal(uint8_t val); - #if HASP_USE_CONFIG > 0 -bool haspGetConfig(const JsonObject & settings); -bool haspSetConfig(const JsonObject & settings); - #endif +#if HASP_USE_CONFIG > 0 +bool haspGetConfig(const JsonObject& settings); +bool haspSetConfig(const JsonObject& settings); +#endif -lv_font_t * hasp_get_font(uint8_t fontid); +lv_font_t* hasp_get_font(uint8_t fontid); bool hasp_update_sleep_state(); -void hasp_get_sleep_time(uint16_t & short_time, uint16_t & long_time); +void hasp_get_sleep_time(uint16_t& short_time, uint16_t& long_time); void hasp_set_sleep_time(uint16_t short_time, uint16_t long_time); void hasp_enable_wakeup_touch(); +void hasp_disable_wakeup_touch(); - /********************** - * MACROS - **********************/ - #define haspEverySecond hasp_update_sleep_state +/********************** + * MACROS + **********************/ #endif /*HASP_USE_APP*/ @@ -86,7 +84,9 @@ void hasp_enable_wakeup_touch(); } /* extern "C" */ #endif -void haspProgressMsg(const char * msg); -void haspProgressMsg(const __FlashStringHelper * msg); +void haspProgressMsg(const char* msg); +#ifdef ARDUINO +void haspProgressMsg(const __FlashStringHelper* msg); +#endif #endif /*HASP_H*/ diff --git a/src/hasp/hasp_attribute.cpp b/src/hasp/hasp_attribute.cpp index 43e6fe6c..391b6de6 100644 --- a/src/hasp/hasp_attribute.cpp +++ b/src/hasp/hasp_attribute.cpp @@ -1,21 +1,19 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ +#ifdef ARDUINO +#include "ArduinoLog.h" +#endif + #include "lvgl.h" #if LVGL_VERSION_MAJOR != 7 - #include "../lv_components.h" +#include "../lv_components.h" #endif -#include "ArduinoLog.h" -#include "hasp.h" -#include "hasp_object.h" -#include "hasp_dispatch.h" -#include "hasp_attribute.h" -#include "hasp_utilities.h" +#include "hasplib.h" LV_FONT_DECLARE(unscii_8_icon); -extern lv_font_t * haspFonts[8]; -extern const char ** btnmatrix_default_map; // memory pointer to lvgl default btnmatrix map +extern const char** btnmatrix_default_map; // memory pointer to lvgl default btnmatrix map #if 0 static bool attribute_lookup_lv_property(uint16_t hash, uint8_t * prop) @@ -107,20 +105,20 @@ static bool attribute_lookup_lv_property(uint16_t hash, uint8_t * prop) {ATTR_TRANSITION_PATH, LV_STYLE_TRANSITION_PATH & LV_STYLE_PROP_ALL}, {ATTR_VALUE_STR, LV_STYLE_VALUE_STR & LV_STYLE_PROP_ALL}, - #if LV_USE_SHADOW +#if LV_USE_SHADOW {ATTR_SHADOW_WIDTH, LV_STYLE_SHADOW_WIDTH & LV_STYLE_PROP_ALL}, {ATTR_SHADOW_OFS_X, LV_STYLE_SHADOW_OFS_X & LV_STYLE_PROP_ALL}, {ATTR_SHADOW_OFS_Y, LV_STYLE_SHADOW_OFS_Y & LV_STYLE_PROP_ALL}, {ATTR_SHADOW_SPREAD, LV_STYLE_SHADOW_SPREAD & LV_STYLE_PROP_ALL}, {ATTR_SHADOW_COLOR, LV_STYLE_SHADOW_COLOR & LV_STYLE_PROP_ALL}, {ATTR_SHADOW_OPA, LV_STYLE_SHADOW_OPA & LV_STYLE_PROP_ALL}, - #endif +#endif - #if LV_USE_BLEND_MODES && LV_USE_SHADOW +#if LV_USE_BLEND_MODES && LV_USE_SHADOW {ATTR_SHADOW_BLEND_MODE, LV_STYLE_SHADOW_BLEND_MODE & LV_STYLE_PROP_ALL}, - #endif +#endif - #if LV_USE_BLEND_MODES +#if LV_USE_BLEND_MODES {ATTR_BG_BLEND_MODE, LV_STYLE_BG_BLEND_MODE & LV_STYLE_PROP_ALL}, {ATTR_PATTERN_BLEND_MODE, LV_STYLE_PATTERN_BLEND_MODE & LV_STYLE_PROP_ALL}, {ATTR_IMAGE_BLEND_MODE, LV_STYLE_IMAGE_BLEND_MODE & LV_STYLE_PROP_ALL}, @@ -129,7 +127,7 @@ static bool attribute_lookup_lv_property(uint16_t hash, uint8_t * prop) {ATTR_OUTLINE_BLEND_MODE, LV_STYLE_OUTLINE_BLEND_MODE & LV_STYLE_PROP_ALL}, {ATTR_VALUE_BLEND_MODE, LV_STYLE_VALUE_BLEND_MODE & LV_STYLE_PROP_ALL}, {ATTR_TEXT_BLEND_MODE, LV_STYLE_TEXT_BLEND_MODE & LV_STYLE_PROP_ALL}, - #endif +#endif }; for(uint32_t i = 0; i < sizeof(props) / sizeof(props[0]); i++) { @@ -181,9 +179,9 @@ static bool attribute_update_lv_property(lv_obj_t * obj, const char * attr_p, ui #endif // OK - this function is missing in lvgl -static uint8_t my_roller_get_visible_row_count(lv_obj_t * roller) +static uint8_t my_roller_get_visible_row_count(lv_obj_t* roller) { - const lv_font_t * font = lv_obj_get_style_text_font(roller, LV_ROLLER_PART_BG); + const lv_font_t* font = lv_obj_get_style_text_font(roller, LV_ROLLER_PART_BG); lv_style_int_t line_space = lv_obj_get_style_text_line_space(roller, LV_ROLLER_PART_BG); lv_coord_t h = lv_obj_get_height(roller); @@ -194,32 +192,32 @@ static uint8_t my_roller_get_visible_row_count(lv_obj_t * roller) } // OK - this function is missing in lvgl -static inline int16_t my_arc_get_rotation(lv_obj_t * arc) +static inline int16_t my_arc_get_rotation(lv_obj_t* arc) { - lv_arc_ext_t * ext = (lv_arc_ext_t *)lv_obj_get_ext_attr(arc); + lv_arc_ext_t* ext = (lv_arc_ext_t*)lv_obj_get_ext_attr(arc); return ext->rotation_angle; } // OK - this function is missing in lvgl -static inline int16_t my_chart_get_min_value(lv_obj_t * chart) +static inline int16_t my_chart_get_min_value(lv_obj_t* chart) { - lv_chart_ext_t * ext = (lv_chart_ext_t *)lv_obj_get_ext_attr(chart); + lv_chart_ext_t* ext = (lv_chart_ext_t*)lv_obj_get_ext_attr(chart); return ext->ymin[LV_CHART_AXIS_PRIMARY_Y]; } // OK - this function is missing in lvgl -static inline int16_t my_chart_get_max_value(lv_obj_t * chart) +static inline int16_t my_chart_get_max_value(lv_obj_t* chart) { - lv_chart_ext_t * ext = (lv_chart_ext_t *)lv_obj_get_ext_attr(chart); + lv_chart_ext_t* ext = (lv_chart_ext_t*)lv_obj_get_ext_attr(chart); return ext->ymax[LV_CHART_AXIS_PRIMARY_Y]; } -lv_chart_series_t * my_chart_get_series(lv_obj_t * chart, uint8_t ser_num) +lv_chart_series_t* my_chart_get_series(lv_obj_t* chart, uint8_t ser_num) { - lv_chart_ext_t * ext = (lv_chart_ext_t *)lv_obj_get_ext_attr(chart); - lv_chart_series_t * ser = (lv_chart_series_t *)_lv_ll_get_tail(&ext->series_ll); + lv_chart_ext_t* ext = (lv_chart_ext_t*)lv_obj_get_ext_attr(chart); + lv_chart_series_t* ser = (lv_chart_series_t*)_lv_ll_get_tail(&ext->series_ll); while(ser_num > 0 && ser) { - ser = (lv_chart_series_t *)_lv_ll_get_prev(&ext->series_ll, ser); + ser = (lv_chart_series_t*)_lv_ll_get_prev(&ext->series_ll, ser); ser_num--; } return ser; @@ -230,11 +228,11 @@ lv_chart_series_t * my_chart_get_series(lv_obj_t * chart, uint8_t ser_num) * @param obj pointer to a object * @param text '\0' terminated character string. NULL to refresh with the current text. */ -void my_obj_set_value_str_txt(lv_obj_t * obj, uint8_t part, lv_state_t state, const char * text) +void my_obj_set_value_str_txt(lv_obj_t* obj, uint8_t part, lv_state_t state, const char* text) { // LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); - const void * value_str_p = lv_obj_get_style_value_str(obj, part); + const void* value_str_p = lv_obj_get_style_value_str(obj, part); lv_obj_invalidate(obj); if(text == NULL || text[0] == 0) { @@ -253,13 +251,13 @@ void my_obj_set_value_str_txt(lv_obj_t * obj, uint8_t part, lv_state_t state, co /*Allocate space for the new text*/ // LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); - value_str_p = (char *)lv_mem_alloc(len); + value_str_p = (char*)lv_mem_alloc(len); LV_ASSERT_MEM(value_str_p); if(value_str_p == NULL) return; // LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); - strncpy((char *)value_str_p, text, len); - lv_obj_set_style_local_value_str(obj, part, state, (char *)value_str_p); + strncpy((char*)value_str_p, text, len); + lv_obj_set_style_local_value_str(obj, part, state, (char*)value_str_p); // LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); return; } @@ -290,17 +288,17 @@ void my_obj_set_value_str_txt(lv_obj_t * obj, uint8_t part, lv_state_t state, co /*Allocate space for the new text*/ value_str_p = lv_mem_alloc(len); LV_ASSERT_MEM(value_str_p); - if(value_str_p != NULL) strcpy((char *)value_str_p, text); - lv_obj_set_style_local_value_str(obj, part, state, (char *)value_str_p); + if(value_str_p != NULL) strcpy((char*)value_str_p, text); + lv_obj_set_style_local_value_str(obj, part, state, (char*)value_str_p); } // LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); } -void my_btnmatrix_map_clear(lv_obj_t * obj) +void my_btnmatrix_map_clear(lv_obj_t* obj) { - lv_btnmatrix_ext_t * ext = (lv_btnmatrix_ext_t *)lv_obj_get_ext_attr(obj); - const char ** map_p_tmp = ext->map_p; // store current pointer + lv_btnmatrix_ext_t* ext = (lv_btnmatrix_ext_t*)lv_obj_get_ext_attr(obj); + const char** map_p_tmp = ext->map_p; // store current pointer LOG_VERBOSE(TAG_ATTR, "%s %d %x btn_cnt: %d", __FILE__, __LINE__, map_p_tmp, ext->btn_cnt); @@ -322,9 +320,9 @@ void my_btnmatrix_map_clear(lv_obj_t * obj) } } -static void my_btnmatrix_map_create(lv_obj_t * obj, const char * payload) +static void my_btnmatrix_map_create(lv_obj_t* obj, const char* payload) { - const char ** map_p = lv_btnmatrix_get_map_array(obj); + const char** map_p = lv_btnmatrix_get_map_array(obj); // Create new map // Reserve memory for JsonDocument @@ -339,25 +337,28 @@ static void my_btnmatrix_map_create(lv_obj_t * obj, const char * payload) JsonArray arr = map_doc.as(); // Parse payload - size_t tot_len = sizeof(char *) * (arr.size() + 1); - const char ** map_data_str = (const char **)lv_mem_alloc(tot_len); + size_t tot_len = sizeof(char*) * (arr.size() + 1); + const char** map_data_str = (const char**)lv_mem_alloc(tot_len); if(map_data_str == NULL) { - return LOG_ERROR(TAG_ATTR, F("Out of memory while creating button map")); + LOG_ERROR(TAG_ATTR, F("Out of memory while creating button map")); + return; } memset(map_data_str, 0, tot_len); // Create buffer tot_len = 0; for(JsonVariant btn : arr) { - tot_len += btn.as().length() + 1; + // tot_len += btn.as().length() + 1; + tot_len += strlen(btn.as()) + 1; } tot_len++; // trailing '\0' LOG_VERBOSE(TAG_ATTR, F("Array Size = %d, Map Length = %d"), arr.size(), tot_len); - char * buffer_addr = (char *)lv_mem_alloc(tot_len); + char* buffer_addr = (char*)lv_mem_alloc(tot_len); if(buffer_addr == NULL) { lv_mem_free(map_data_str); - return LOG_ERROR(TAG_ATTR, F("Out of memory while creating button map")); + LOG_ERROR(TAG_ATTR, F("Out of memory while creating button map")); + return; } memset(buffer_addr, 0, tot_len); // Important, last index needs to be 0 => empty string "" @@ -370,11 +371,15 @@ static void my_btnmatrix_map_create(lv_obj_t * obj, const char * payload) size_t pos = 0; LOG_VERBOSE(TAG_ATTR, F("%s %d lbl addr: %x"), __FILE__, __LINE__, buffer_addr); for(JsonVariant btn : arr) { - size_t len = btn.as().length() + 1; - LOG_VERBOSE(TAG_ATTR, F(D_BULLET "Adding button: %s (%d bytes) %x"), btn.as().c_str(), len, + // size_t len = btn.as().length() + 1; + size_t len = strlen(btn.as()) + 1; + LOG_VERBOSE(TAG_ATTR, F(D_BULLET "Adding button: %s (%d bytes) %x"), btn.as(), len, buffer_addr + pos); - memccpy(buffer_addr + pos, btn.as().c_str(), 0, len); // Copy the label text into the buffer - map_data_str[index++] = buffer_addr + pos; // save pointer to the label in the array + // LOG_VERBOSE(TAG_ATTR, F(D_BULLET "Adding button: %s (%d bytes) %x"), btn.as().c_str(), len, + // buffer_addr + pos); + memccpy(buffer_addr + pos, btn.as(), 0, len); // Copy the label text into the buffer + // memccpy(buffer_addr + pos, btn.as().c_str(), 0, len); // Copy the label text into the buffer + map_data_str[index++] = buffer_addr + pos; // save pointer to the label in the array pos += len; } map_data_str[index] = buffer_addr + pos; // save pointer to the last \0 byte @@ -384,17 +389,17 @@ static void my_btnmatrix_map_create(lv_obj_t * obj, const char * payload) LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__); } -void line_clear_points(lv_obj_t * obj) +void line_clear_points(lv_obj_t* obj) { - lv_line_ext_t * ext = (lv_line_ext_t *)lv_obj_get_ext_attr(obj); + lv_line_ext_t* ext = (lv_line_ext_t*)lv_obj_get_ext_attr(obj); if(ext->point_array && (ext->point_num > 0)) { - const lv_point_t * ptr = ext->point_array; + const lv_point_t* ptr = ext->point_array; lv_line_set_points(obj, NULL, 0); lv_mem_free(ptr); } } -static void line_set_points(lv_obj_t * obj, const char * payload) +static void line_set_points(lv_obj_t* obj, const char* payload) { line_clear_points(obj); // delete pointmap @@ -411,10 +416,11 @@ static void line_set_points(lv_obj_t * obj, const char * payload) JsonArray arr = doc.as(); // Parse payload - size_t tot_len = sizeof(lv_point_t *) * (arr.size()); - lv_point_t * point_arr = (lv_point_t *)lv_mem_alloc(tot_len); + size_t tot_len = sizeof(lv_point_t*) * (arr.size()); + lv_point_t* point_arr = (lv_point_t*)lv_mem_alloc(tot_len); if(point_arr == NULL) { - return LOG_ERROR(TAG_ATTR, F("Out of memory while creating line points")); + LOG_ERROR(TAG_ATTR, F("Out of memory while creating line points")); + return; } memset(point_arr, 0, tot_len); @@ -442,109 +448,42 @@ static inline lv_color_t haspLogColor(lv_color_t color) return color; } -// OK -bool haspPayloadToColor(const char * payload, lv_color32_t & color) -{ - /* HEX format #rrggbb or #rgb */ - if(*payload == '#') { - if(strlen(payload) >= 8) return false; - - char * pEnd; - long color_int = strtol(payload + 1, &pEnd, HEX); - uint8_t R8; - uint8_t G8; - uint8_t B8; - - if(pEnd - payload == 7) { // #rrbbgg - color.ch.red = color_int >> 16 & 0xff; - color.ch.green = color_int >> 8 & 0xff; - color.ch.blue = color_int & 0xff; - - } else if(pEnd - payload == 4) { // #rgb - color.ch.red = color_int >> 8 & 0xf; - color.ch.green = color_int >> 4 & 0xf; - color.ch.blue = color_int & 0xf; - - color.ch.red += color.ch.red * HEX; - color.ch.green += color.ch.green * HEX; - color.ch.blue += color.ch.blue * HEX; - - } else { - return false; /* Invalid hex length */ - } - - return true; /* Color found */ - } - - /* 16-bit RGB565 Color Scheme*/ - if(hasp_util_is_only_digits(payload)) { - uint16_t c = atoi(payload); - - /* Initial colors */ - uint8_t R5 = ((c >> 11) & 0b11111); - uint8_t G6 = ((c >> 5) & 0b111111); - uint8_t B5 = (c & 0b11111); - - /* Remapped colors */ - color.ch.red = (R5 * 527 + 23) >> 6; - color.ch.green = (G6 * 259 + 33) >> 6; - color.ch.blue = (B5 * 527 + 23) >> 6; - - return true; /* Color found */ - } - - /* Named colors */ - size_t numColors = sizeof(haspNamedColors) / sizeof(haspNamedColors[0]); - uint16_t sdbm = hasp_util_get_sdbm(payload); - - for(size_t i = 0; i < numColors; i++) { - if(sdbm == (uint16_t)pgm_read_word_near(&(haspNamedColors[i].hash))) { - color.ch.red = (uint16_t)pgm_read_byte_near(&(haspNamedColors[i].r)); - color.ch.green = (uint16_t)pgm_read_byte_near(&(haspNamedColors[i].g)); - color.ch.blue = (uint16_t)pgm_read_byte_near(&(haspNamedColors[i].b)); - - return true; /* Color found */ - } - } - - return false; /* Color not found */ -} - -static lv_font_t * haspPayloadToFont(const char * payload) +static lv_font_t* haspPayloadToFont(const char* payload) { uint8_t var = atoi(payload); switch(var) { - case 0: - case 1: - case 2: - case 3: + case 0 ... 7: + // LOG_WARNING(TAG_ATTR, "%s %d %x", __FILE__, __LINE__, robotocondensed_regular_12_nokern); return hasp_get_font(var); case 8: return &unscii_8_icon; -#if ESP32 +#ifndef ARDUINO_ARCH_ESP8266 - #ifdef LV_FONT_CUSTOM_12 +#ifdef LV_FONT_CUSTOM_12 case 12: - return LV_THEME_DEFAULT_FONT_SMALL; - #endif + return &robotocondensed_regular_12_nokern; +#endif - #ifdef LV_FONT_CUSTOM_16 +#ifdef LV_FONT_CUSTOM_16 case 16: - return LV_THEME_DEFAULT_FONT_NORMAL; - #endif + LOG_WARNING(TAG_ATTR, "%s %d %x", __FILE__, __LINE__, robotocondensed_regular_16_nokern); + return &robotocondensed_regular_16_nokern; +#endif - #ifdef LV_FONT_CUSTOM_22 +#ifdef LV_FONT_CUSTOM_22 case 22: - return LV_THEME_DEFAULT_FONT_SUBTITLE; - #endif + LOG_WARNING(TAG_ATTR, "%s %d %x", __FILE__, __LINE__, robotocondensed_regular_22_nokern); + return &robotocondensed_regular_22_nokern; +#endif - #ifdef LV_FONT_CUSTOM_28 +#ifdef LV_FONT_CUSTOM_28 case 28: - return LV_THEME_DEFAULT_FONT_TITLE; - #endif + LOG_WARNING(TAG_ATTR, "%s %d %x", __FILE__, __LINE__, robotocondensed_regular_28_nokern); + return &robotocondensed_regular_28_nokern; +#endif #endif @@ -553,27 +492,27 @@ static lv_font_t * haspPayloadToFont(const char * payload) } } -static void gauge_format_10(lv_obj_t * gauge, char * buf, int bufsize, int32_t value) +static void gauge_format_10(lv_obj_t* gauge, char* buf, int bufsize, int32_t value) { snprintf(buf, bufsize, PSTR("%d"), value / 10); } -static void gauge_format_100(lv_obj_t * gauge, char * buf, int bufsize, int32_t value) +static void gauge_format_100(lv_obj_t* gauge, char* buf, int bufsize, int32_t value) { snprintf(buf, bufsize, PSTR("%d"), value / 100); } -static void gauge_format_1k(lv_obj_t * gauge, char * buf, int bufsize, int32_t value) +static void gauge_format_1k(lv_obj_t* gauge, char* buf, int bufsize, int32_t value) { snprintf(buf, bufsize, PSTR("%d"), value / 1000); } -static void gauge_format_10k(lv_obj_t * gauge, char * buf, int bufsize, int32_t value) +static void gauge_format_10k(lv_obj_t* gauge, char* buf, int bufsize, int32_t value) { snprintf(buf, bufsize, PSTR("%d"), value / 10000); } -static void hasp_process_label_long_mode(lv_obj_t * obj, const char * payload, bool update) +static void hasp_process_label_long_mode(lv_obj_t* obj, const char* payload, bool update) { if(update) { lv_label_long_mode_t mode = LV_LABEL_LONG_EXPAND; @@ -590,7 +529,8 @@ static void hasp_process_label_long_mode(lv_obj_t * obj, const char * payload, b } else if(!strcasecmp_P(payload, PSTR("crop"))) { mode = LV_LABEL_LONG_CROP; } else { - return LOG_WARNING(TAG_ATTR, F("Invalid long mode")); + LOG_WARNING(TAG_ATTR, F("Invalid long mode")); + return; } lv_label_set_long_mode(obj, mode); } else { @@ -600,10 +540,10 @@ static void hasp_process_label_long_mode(lv_obj_t * obj, const char * payload, b } // OK -lv_obj_t * FindButtonLabel(lv_obj_t * btn) +lv_obj_t* FindButtonLabel(lv_obj_t* btn) { if(btn) { - lv_obj_t * label = lv_obj_get_child_back(btn, NULL); + lv_obj_t* label = lv_obj_get_child_back(btn, NULL); #if 1 if(label) { if(check_obj_type(label, LV_HASP_LABEL)) { @@ -613,7 +553,7 @@ lv_obj_t * FindButtonLabel(lv_obj_t * btn) if(label) { lv_obj_type_t list; lv_obj_get_type(label, &list); - const char * objtype = list.type[0]; + const char* objtype = list.type[0]; if(check_obj_type(objtype, LV_HASP_LABEL)) { return label; @@ -630,23 +570,23 @@ lv_obj_t * FindButtonLabel(lv_obj_t * btn) } // OK -static inline void haspSetLabelText(lv_obj_t * obj, const char * value) +static inline void haspSetLabelText(lv_obj_t* obj, const char* value) { - lv_obj_t * label = FindButtonLabel(obj); + lv_obj_t* label = FindButtonLabel(obj); if(label) { lv_label_set_text(label, value); } } // OK -static bool haspGetLabelText(lv_obj_t * obj, char ** text) +static bool haspGetLabelText(lv_obj_t* obj, char** text) { if(!obj) { LOG_WARNING(TAG_ATTR, F("Button not defined")); return false; } - lv_obj_t * label = lv_obj_get_child_back(obj, NULL); + lv_obj_t* label = lv_obj_get_child_back(obj, NULL); if(label) { #if 1 if(check_obj_type(label, LV_HASP_LABEL)) { @@ -670,8 +610,8 @@ static bool haspGetLabelText(lv_obj_t * obj, char ** text) return false; } -static void hasp_attribute_get_part_state(lv_obj_t * obj, const char * attr_in, char * attr_out, uint8_t & part, - uint8_t & state) +static void hasp_attribute_get_part_state(lv_obj_t* obj, const char* attr_in, char* attr_out, uint8_t& part, + uint8_t& state) { int len = strlen(attr_in); if(len <= 0 || len >= 32) { @@ -723,7 +663,7 @@ static void hasp_attribute_get_part_state(lv_obj_t * obj, const char * attr_in, (LV_SLIDER_PART_BG != LV_SWITCH_PART_BG) || (LV_SLIDER_PART_INDIC != LV_ARC_PART_INDIC) || \ (LV_SLIDER_PART_KNOB != LV_ARC_PART_KNOB) || (LV_SLIDER_PART_BG != LV_ARC_PART_BG) || \ (LV_SLIDER_PART_INDIC != LV_BAR_PART_INDIC) || (LV_SLIDER_PART_BG != LV_BAR_PART_BG) - #error "LV_SLIDER, LV_BAR, LV_ARC, LV_SWITCH parts should match!" +#error "LV_SLIDER, LV_BAR, LV_ARC, LV_SWITCH parts should match!" #endif if(check_obj_type(obj, LV_HASP_SLIDER) || check_obj_type(obj, LV_HASP_SWITCH) || check_obj_type(obj, LV_HASP_ARC) || @@ -774,7 +714,7 @@ static void hasp_attribute_get_part_state(lv_obj_t * obj, const char * attr_in, * @param update bool: change/set the value if true, dispatch/get value if false * @note setting a value won't return anything, getting will dispatch the value */ -static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t attr_hash, const char * payload, +static void hasp_local_style_attr(lv_obj_t* obj, const char* attr_p, uint16_t attr_hash, const char* payload, bool update) { char attr[32]; @@ -785,7 +725,7 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t // test_prop(attr_hash); hasp_attribute_get_part_state(obj, attr_p, attr, part, state); - attr_hash = hasp_util_get_sdbm(attr); // attribute name without the index number + attr_hash = Utilities::get_sdbm(attr); // attribute name without the index number /* ***** WARNING **************************************************** * when using hasp_out use attr_p for the original attribute name @@ -836,7 +776,7 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t case ATTR_BG_COLOR: { if(update) { lv_color32_t c; - if(haspPayloadToColor(payload, c) && part != 64) + if(Parser::haspPayloadToColor(payload, c) && part != 64) lv_obj_set_style_local_bg_color(obj, part, state, lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); } else { hasp_out_color(obj, attr, lv_obj_get_style_bg_color(obj, part)); @@ -846,7 +786,7 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t case ATTR_BG_GRAD_COLOR: if(update) { lv_color32_t c; - if(haspPayloadToColor(payload, c)) + if(Parser::haspPayloadToColor(payload, c)) lv_obj_set_style_local_bg_grad_color(obj, part, state, lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); } else { @@ -857,6 +797,16 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t case ATTR_BG_OPA: return attribute_bg_opa(obj, part, state, update, attr_p, (lv_opa_t)var); + /* Margin attributes */ + case ATTR_MARGIN_TOP: + return attribute_margin_top(obj, part, state, update, attr_p, (lv_style_int_t)var); + case ATTR_MARGIN_BOTTOM: + return attribute_margin_bottom(obj, part, state, update, attr_p, (lv_style_int_t)var); + case ATTR_MARGIN_LEFT: + return attribute_margin_left(obj, part, state, update, attr_p, (lv_style_int_t)var); + case ATTR_MARGIN_RIGHT: + return attribute_margin_right(obj, part, state, update, attr_p, (lv_style_int_t)var); + /* Padding attributes */ case ATTR_PAD_TOP: return attribute_pad_top(obj, part, state, update, attr_p, (lv_style_int_t)var); @@ -871,6 +821,37 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t return attribute_pad_inner(obj, part, state, update, attr_p, (lv_style_int_t)var); #endif + /* Scale attributes */ + case ATTR_SCALE_GRAD_COLOR: { + if(update) { + lv_color32_t c; + if(Parser::haspPayloadToColor(payload, c) && part != 64) + lv_obj_set_style_local_scale_grad_color(obj, part, state, + lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); + } else { + hasp_out_color(obj, attr, lv_obj_get_style_scale_grad_color(obj, part)); + } + return; + } + case ATTR_SCALE_END_COLOR: + if(update) { + lv_color32_t c; + if(Parser::haspPayloadToColor(payload, c)) + lv_obj_set_style_local_scale_end_color(obj, part, state, + lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); + } else { + hasp_out_color(obj, attr, lv_obj_get_style_scale_end_color(obj, part)); + } + return; + case ATTR_SCALE_END_LINE_WIDTH: + return attribute_scale_end_line_width(obj, part, state, update, attr_p, (lv_style_int_t)var); + case ATTR_SCALE_END_BORDER_WIDTH: + return attribute_scale_end_border_width(obj, part, state, update, attr_p, (lv_style_int_t)var); + case ATTR_SCALE_BORDER_WIDTH: + return attribute_scale_border_width(obj, part, state, update, attr_p, (lv_style_int_t)var); + case ATTR_SCALE_WIDTH: + return attribute_scale_width(obj, part, state, update, attr_p, (lv_style_int_t)var); + /* Text attributes */ case ATTR_TEXT_LETTER_SPACE: return attribute_text_letter_space(obj, part, state, update, attr_p, (lv_style_int_t)var); @@ -883,7 +864,7 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t case ATTR_TEXT_COLOR: { if(update) { lv_color32_t c; - if(haspPayloadToColor(payload, c)) + if(Parser::haspPayloadToColor(payload, c)) lv_obj_set_style_local_text_color(obj, part, state, lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); } else { hasp_out_color(obj, attr, lv_obj_get_style_text_color(obj, part)); @@ -893,7 +874,7 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t case ATTR_TEXT_SEL_COLOR: { if(update) { lv_color32_t c; - if(haspPayloadToColor(payload, c)) + if(Parser::haspPayloadToColor(payload, c)) lv_obj_set_style_local_text_sel_color(obj, part, state, lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); } else { @@ -902,15 +883,16 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t return; } case ATTR_TEXT_FONT: { - lv_font_t * font = haspPayloadToFont(payload); + lv_font_t* font = haspPayloadToFont(payload); if(font) { + LOG_WARNING(TAG_ATTR, "%s %d %x", __FILE__, __LINE__, *font); uint8_t count = 3; if(check_obj_type(obj, LV_HASP_ROLLER)) count = my_roller_get_visible_row_count(obj); lv_obj_set_style_local_text_font(obj, part, state, font); if(check_obj_type(obj, LV_HASP_ROLLER)) lv_roller_set_visible_row_count(obj, count); lv_obj_set_style_local_text_font(obj, part, state, font); // again, for roller - if(check_obj_type(obj, LV_HASP_DDLIST)) { // issue #43 + if(check_obj_type(obj, LV_HASP_DROPDOWN)) { // issue #43 lv_obj_set_style_local_text_font(obj, LV_DROPDOWN_PART_MAIN, state, font); lv_obj_set_style_local_text_font(obj, LV_DROPDOWN_PART_LIST, state, font); lv_obj_set_style_local_text_font(obj, LV_DROPDOWN_PART_SELECTED, state, font); @@ -928,13 +910,13 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t case ATTR_BORDER_SIDE: return attribute_border_side(obj, part, state, update, attr_p, (lv_border_side_t)var); case ATTR_BORDER_POST: - return attribute_border_post(obj, part, state, update, attr_p, hasp_util_is_true(payload)); + return attribute_border_post(obj, part, state, update, attr_p, Utilities::is_true(payload)); case ATTR_BORDER_OPA: return attribute_border_opa(obj, part, state, update, attr_p, (lv_opa_t)var); case ATTR_BORDER_COLOR: { if(update) { lv_color32_t c; - if(haspPayloadToColor(payload, c)) + if(Parser::haspPayloadToColor(payload, c)) lv_obj_set_style_local_border_color(obj, part, state, lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); } else { @@ -953,7 +935,7 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t case ATTR_OUTLINE_COLOR: { if(update) { lv_color32_t c; - if(haspPayloadToColor(payload, c)) + if(Parser::haspPayloadToColor(payload, c)) lv_obj_set_style_local_outline_color(obj, part, state, lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); } else { @@ -977,7 +959,7 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t case ATTR_SHADOW_COLOR: { if(update) { lv_color32_t c; - if(haspPayloadToColor(payload, c)) + if(Parser::haspPayloadToColor(payload, c)) lv_obj_set_style_local_shadow_color(obj, part, state, lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); } else { @@ -995,13 +977,13 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t case ATTR_LINE_DASH_GAP: return attribute_line_dash_gap(obj, part, state, update, attr_p, (lv_style_int_t)var); case ATTR_LINE_ROUNDED: - return attribute_line_rounded(obj, part, state, update, attr_p, hasp_util_is_true(payload)); + return attribute_line_rounded(obj, part, state, update, attr_p, Utilities::is_true(payload)); case ATTR_LINE_OPA: return attribute_line_opa(obj, part, state, update, attr_p, (lv_opa_t)var); case ATTR_LINE_COLOR: { if(update) { lv_color32_t c; - if(haspPayloadToColor(payload, c)) + if(Parser::haspPayloadToColor(payload, c)) lv_obj_set_style_local_line_color(obj, part, state, lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); } else { hasp_out_color(obj, attr, lv_obj_get_style_line_color(obj, part)); @@ -1051,7 +1033,7 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t case ATTR_VALUE_COLOR: { if(update) { lv_color32_t c; - if(haspPayloadToColor(payload, c)) + if(Parser::haspPayloadToColor(payload, c)) lv_obj_set_style_local_value_color(obj, part, state, lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); } else { @@ -1060,17 +1042,18 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t return; } case ATTR_VALUE_FONT: { - lv_font_t * font = haspPayloadToFont(payload); + lv_font_t* font = haspPayloadToFont(payload); if(font) { return lv_obj_set_style_local_value_font(obj, part, state, font); } else { - return LOG_WARNING(TAG_ATTR, F("Unknown Font ID %s"), attr_p); + LOG_WARNING(TAG_ATTR, F("Unknown Font ID %s"), attr_p); + return; } } /* Pattern attributes */ case ATTR_PATTERN_REPEAT: - return attribute_pattern_repeat(obj, part, state, update, attr_p, hasp_util_is_true(payload)); + return attribute_pattern_repeat(obj, part, state, update, attr_p, Utilities::is_true(payload)); case ATTR_PATTERN_OPA: return attribute_pattern_opa(obj, part, state, update, attr_p, (lv_opa_t)var); case ATTR_PATTERN_RECOLOR_OPA: @@ -1081,7 +1064,7 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t case ATTR_PATTERN_RECOLOR: { if(update) { lv_color32_t c; - if(haspPayloadToColor(payload, c)) + if(Parser::haspPayloadToColor(payload, c)) lv_obj_set_style_local_pattern_recolor(obj, part, state, lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); } else { @@ -1099,17 +1082,17 @@ static void hasp_local_style_attr(lv_obj_t * obj, const char * attr_p, uint16_t /* Transition attributes */ // Todo } - LOG_WARNING(TAG_ATTR, F(D_ATTRIBUTE_UNKNOWN), attr_p); + LOG_WARNING(TAG_ATTR, F(D_ATTRIBUTE_UNKNOWN " (%d)"), attr_p, attr_hash); } -static void hasp_process_arc_attribute(lv_obj_t * obj, const char * attr_p, uint16_t attr_hash, const char * payload, +static void hasp_process_arc_attribute(lv_obj_t* obj, const char* attr_p, uint16_t attr_hash, const char* payload, bool update) { // We already know it's a arc object int16_t intval = atoi(payload); uint16_t val = atoi(payload); - char * attr = (char *)attr_p; + char* attr = (char*)attr_p; if(*attr == '.') attr++; // strip leading '.' switch(attr_hash) { @@ -1121,7 +1104,7 @@ static void hasp_process_arc_attribute(lv_obj_t * obj, const char * attr_p, uint case ATTR_ADJUSTABLE: if(update) { - bool toggle = hasp_util_is_true(payload); + bool toggle = Utilities::is_true(payload); lv_arc_set_adjustable(obj, toggle); lv_obj_set_event_cb(obj, toggle ? slider_event_handler : generic_event_handler); } else { @@ -1146,7 +1129,7 @@ static void hasp_process_arc_attribute(lv_obj_t * obj, const char * attr_p, uint LOG_WARNING(TAG_ATTR, F(D_ATTRIBUTE_UNKNOWN), attr_p); } -static void hasp_process_lmeter_attribute(lv_obj_t * obj, const char * attr_p, uint16_t attr_hash, const char * payload, +static void hasp_process_lmeter_attribute(lv_obj_t* obj, const char* attr_p, uint16_t attr_hash, const char* payload, bool update) { // We already know it's a linemeter object @@ -1156,7 +1139,7 @@ static void hasp_process_lmeter_attribute(lv_obj_t * obj, const char * attr_p, u uint16_t line_count = lv_linemeter_get_line_count(obj); uint16_t angle = lv_linemeter_get_scale_angle(obj); - char * attr = (char *)attr_p; + char* attr = (char*)attr_p; if(*attr == '.') attr++; // strip leading '.' switch(attr_hash) { @@ -1178,7 +1161,7 @@ static void hasp_process_lmeter_attribute(lv_obj_t * obj, const char * attr_p, u LOG_WARNING(TAG_ATTR, F(D_ATTRIBUTE_UNKNOWN), attr_p); } -static void hasp_process_gauge_attribute(lv_obj_t * obj, const char * attr_p, uint16_t attr_hash, const char * payload, +static void hasp_process_gauge_attribute(lv_obj_t* obj, const char* attr_p, uint16_t attr_hash, const char* payload, bool update) { // We already know it's a gauge object @@ -1189,7 +1172,7 @@ static void hasp_process_gauge_attribute(lv_obj_t * obj, const char * attr_p, ui uint16_t line_count = lv_gauge_get_line_count(obj); uint16_t angle = lv_gauge_get_scale_angle(obj); - char * attr = (char *)attr_p; + char* attr = (char*)attr_p; if(*attr == '.') attr++; // strip leading '.' switch(attr_hash) { @@ -1237,7 +1220,7 @@ static void hasp_process_gauge_attribute(lv_obj_t * obj, const char * attr_p, ui // ##################### Common Attributes ######################################################## -static void hasp_process_obj_attribute_txt(lv_obj_t * obj, const char * attr, const char * payload, bool update) +static void hasp_process_obj_attribute_txt(lv_obj_t* obj, const char* attr, const char* payload, bool update) { /* Attributes depending on objecttype */ // lv_obj_type_t list; @@ -1248,7 +1231,7 @@ static void hasp_process_obj_attribute_txt(lv_obj_t * obj, const char * attr, co if(update) { haspSetLabelText(obj, payload); } else { - char * text = NULL; + char* text = NULL; if(haspGetLabelText(obj, &text) && text) hasp_out_str(obj, attr, text); } return; @@ -1259,7 +1242,7 @@ static void hasp_process_obj_attribute_txt(lv_obj_t * obj, const char * attr, co if(check_obj_type(obj, LV_HASP_CHECKBOX)) { return update ? lv_checkbox_set_text(obj, payload) : hasp_out_str(obj, attr, lv_checkbox_get_text(obj)); } - if(check_obj_type(obj, LV_HASP_DDLIST)) { + if(check_obj_type(obj, LV_HASP_DROPDOWN)) { char buffer[128]; lv_dropdown_get_selected_str(obj, buffer, sizeof(buffer)); return hasp_out_str(obj, attr, buffer); @@ -1279,9 +1262,9 @@ static void hasp_process_obj_attribute_txt(lv_obj_t * obj, const char * attr, co LOG_WARNING(TAG_ATTR, F(D_ATTRIBUTE_UNKNOWN), attr); } -bool hasp_process_obj_attribute_val(lv_obj_t * obj, const char * attr, const char * payload, bool update) +bool hasp_process_obj_attribute_val(lv_obj_t* obj, const char* attr, int16_t intval, bool boolval, bool update) { - int16_t intval = atoi(payload); + // int16_t intval = atoi(payload); if(check_obj_type(obj, LV_HASP_BUTTON)) { if(lv_btn_get_checkable(obj)) { @@ -1297,14 +1280,13 @@ bool hasp_process_obj_attribute_val(lv_obj_t * obj, const char * attr, const cha return false; // not checkable } } else if(check_obj_type(obj, LV_HASP_CHECKBOX)) { - update ? lv_checkbox_set_checked(obj, hasp_util_is_true(payload)) - : hasp_out_int(obj, attr, lv_checkbox_is_checked(obj)); + update ? lv_checkbox_set_checked(obj, boolval) : hasp_out_int(obj, attr, lv_checkbox_is_checked(obj)); } else if(check_obj_type(obj, LV_HASP_SWITCH)) { if(update) - hasp_util_is_true(payload) ? lv_switch_on(obj, LV_ANIM_ON) : lv_switch_off(obj, LV_ANIM_ON); + boolval ? lv_switch_on(obj, LV_ANIM_ON) : lv_switch_off(obj, LV_ANIM_ON); else hasp_out_int(obj, attr, lv_switch_get_state(obj)); - } else if(check_obj_type(obj, LV_HASP_DDLIST)) { + } else if(check_obj_type(obj, LV_HASP_DROPDOWN)) { lv_dropdown_set_selected(obj, (uint16_t)intval); } else if(check_obj_type(obj, LV_HASP_LMETER)) { update ? lv_linemeter_set_value(obj, intval) : hasp_out_int(obj, attr, lv_linemeter_get_value(obj)); @@ -1327,7 +1309,7 @@ bool hasp_process_obj_attribute_val(lv_obj_t * obj, const char * attr, const cha return true; } -static void hasp_process_obj_attribute_range(lv_obj_t * obj, const char * attr, const char * payload, bool update, +static void hasp_process_obj_attribute_range(lv_obj_t* obj, const char* attr, const char* payload, bool update, bool set_min, bool set_max) { int16_t val = atoi(payload); @@ -1341,7 +1323,7 @@ static void hasp_process_obj_attribute_range(lv_obj_t * obj, const char * attr, if(check_obj_type(obj, LV_HASP_SLIDER)) { int16_t min = lv_slider_get_min_value(obj); int16_t max = lv_slider_get_max_value(obj); - if(update && (set_min ? val : min) >= (set_max ? val : max)) return; // prevent setting min>=max + if(update && (set_min ? val : min) == (set_max ? val : max)) return; // prevent setting min=max return update ? lv_slider_set_range(obj, set_min ? val : min, set_max ? val : max) : hasp_out_int(obj, attr, set_min ? min : max); } @@ -1349,7 +1331,7 @@ static void hasp_process_obj_attribute_range(lv_obj_t * obj, const char * attr, if(check_obj_type(obj, LV_HASP_GAUGE)) { int32_t min = lv_gauge_get_min_value(obj); int32_t max = lv_gauge_get_max_value(obj); - if(update && (set_min ? val32 : min) >= (set_max ? val32 : max)) return; // prevent setting min>=max + if(update && (set_min ? val32 : min) == (set_max ? val32 : max)) return; // prevent setting min=max return update ? lv_gauge_set_range(obj, set_min ? val32 : min, set_max ? val32 : max) : hasp_out_int(obj, attr, set_min ? min : max); } @@ -1357,7 +1339,7 @@ static void hasp_process_obj_attribute_range(lv_obj_t * obj, const char * attr, if(check_obj_type(obj, LV_HASP_ARC)) { int16_t min = lv_arc_get_min_value(obj); int16_t max = lv_arc_get_max_value(obj); - if(update && (set_min ? val : min) >= (set_max ? val : max)) return; // prevent setting min>=max + if(update && (set_min ? val : min) == (set_max ? val : max)) return; // prevent setting min=max return update ? lv_arc_set_range(obj, set_min ? val : min, set_max ? val : max) : hasp_out_int(obj, attr, set_min ? min : max); } @@ -1365,7 +1347,7 @@ static void hasp_process_obj_attribute_range(lv_obj_t * obj, const char * attr, if(check_obj_type(obj, LV_HASP_BAR)) { int16_t min = lv_bar_get_min_value(obj); int16_t max = lv_bar_get_max_value(obj); - if(update && (set_min ? val : min) >= (set_max ? val : max)) return; // prevent setting min>=max + if(update && (set_min ? val : min) == (set_max ? val : max)) return; // prevent setting min=max return update ? lv_bar_set_range(obj, set_min ? val : min, set_max ? val : max) : hasp_out_int(obj, attr, set_min ? min : max); } @@ -1373,7 +1355,7 @@ static void hasp_process_obj_attribute_range(lv_obj_t * obj, const char * attr, if(check_obj_type(obj, LV_HASP_LMETER)) { int32_t min = lv_linemeter_get_min_value(obj); int32_t max = lv_linemeter_get_max_value(obj); - if(update && (set_min ? val32 : min) >= (set_max ? val32 : max)) return; // prevent setting min>=max + if(update && (set_min ? val32 : min) == (set_max ? val32 : max)) return; // prevent setting min=max return update ? lv_linemeter_set_range(obj, set_min ? val32 : min, set_max ? val32 : max) : hasp_out_int(obj, attr, set_min ? min : max); } @@ -1381,7 +1363,7 @@ static void hasp_process_obj_attribute_range(lv_obj_t * obj, const char * attr, if(check_obj_type(obj, LV_HASP_CHART)) { int16_t min = my_chart_get_min_value(obj); int16_t max = my_chart_get_max_value(obj); - if(update && (set_min ? val : min) >= (set_max ? val : max)) return; // prevent setting min>=max + if(update && (set_min ? val : min) == (set_max ? val : max)) return; // prevent setting min=max return update ? lv_chart_set_range(obj, set_min ? val : min, set_max ? val : max) : hasp_out_int(obj, attr, set_min ? min : max); } @@ -1399,16 +1381,19 @@ static void hasp_process_obj_attribute_range(lv_obj_t * obj, const char * attr, * @param update bool: change/set the value if true, dispatch/get value if false * @note setting a value won't return anything, getting will dispatch the value */ -void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char * payload, bool update) +void hasp_process_obj_attribute(lv_obj_t* obj, const char* attr_p, const char* payload, bool update) { // unsigned long start = millis(); - if(!obj) return LOG_WARNING(TAG_ATTR, F(D_OBJECT_UNKNOWN)); + if(!obj) { + LOG_WARNING(TAG_ATTR, F(D_OBJECT_UNKNOWN)); + return; + } int16_t val = atoi(payload); - char * attr = (char *)attr_p; + char* attr = (char*)attr_p; if(*attr == '.') attr++; // strip leading '.' - uint16_t attr_hash = hasp_util_get_sdbm(attr); + uint16_t attr_hash = Utilities::get_sdbm(attr); // LOG_VERBOSE(TAG_ATTR,"%s => %d", attr, attr_hash); /* 16-bit Hash Lookup Table */ @@ -1421,12 +1406,23 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char update ? (void)(obj->user_data.groupid = (uint8_t)val) : hasp_out_int(obj, attr, obj->user_data.groupid); break; // attribute_found + case ATTR_ACTION: + update ? (void)(obj->user_data.actionid = (uint8_t)val) : hasp_out_int(obj, attr, obj->user_data.actionid); + break; // attribute_found + + case ATTR_TRANSITION: + update ? (void)(obj->user_data.transitionid = (uint8_t)val) + : hasp_out_int(obj, attr, obj->user_data.transitionid); + break; // attribute_found + + case ATTR_OBJ: + if(update) LOG_WARNING(TAG_ATTR, F(D_ATTRIBUTE_READ_ONLY), attr_p); + hasp_out_str(obj, attr, get_obj_type_name(obj)); + break; // attribute_found + case ATTR_OBJID: - if(update) { - LOG_WARNING(TAG_ATTR, F(D_ATTRIBUTE_READ_ONLY), attr_p); - } else { - hasp_out_int(obj, attr, obj->user_data.objid); - } + if(update) LOG_WARNING(TAG_ATTR, F(D_ATTRIBUTE_READ_ONLY), attr_p); + hasp_out_int(obj, attr, obj->user_data.objid); break; // attribute_found case ATTR_X: @@ -1466,12 +1462,12 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char break; // attribute_found case ATTR_VIS: - update ? lv_obj_set_hidden(obj, !hasp_util_is_true(payload)) + update ? lv_obj_set_hidden(obj, !Utilities::is_true(payload)) : hasp_out_int(obj, attr, !lv_obj_get_hidden(obj)); break; // attribute_found case ATTR_HIDDEN: - update ? lv_obj_set_hidden(obj, hasp_util_is_true(payload)) + update ? lv_obj_set_hidden(obj, Utilities::is_true(payload)) : hasp_out_int(obj, attr, lv_obj_get_hidden(obj)); break; // attribute_found @@ -1484,7 +1480,7 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char if(check_obj_type(obj, LV_HASP_CPICKER)) { if(update) { lv_color32_t c; - if(haspPayloadToColor(payload, c)) + if(Parser::haspPayloadToColor(payload, c)) lv_cpicker_set_color(obj, lv_color_make(c.ch.red, c.ch.green, c.ch.blue)); } else { hasp_out_color(obj, attr, lv_cpicker_get_color(obj)); @@ -1495,7 +1491,8 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char break; // attribute_found case ATTR_VAL: - if(!hasp_process_obj_attribute_val(obj, attr, payload, update)) goto attribute_not_found; + if(!hasp_process_obj_attribute_val(obj, attr, atoi(payload), Utilities::is_true(payload), update)) + goto attribute_not_found; break; // attribute_found case ATTR_MIN: @@ -1512,7 +1509,8 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char break; // attribute_found case ATTR_ENABLED: - update ? lv_obj_set_click(obj, hasp_util_is_true(payload)) : hasp_out_int(obj, attr, lv_obj_get_click(obj)); + update ? lv_obj_set_click(obj, Utilities::is_true(payload)) + : hasp_out_int(obj, attr, lv_obj_get_click(obj)); break; // attribute_found case ATTR_SRC: @@ -1524,7 +1522,7 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char case LV_IMG_SRC_FILE: return hasp_out_str(obj, attr, lv_img_get_file_name(obj)); case LV_IMG_SRC_SYMBOL: - return hasp_out_str(obj, attr, (char *)lv_img_get_src(obj)); + return hasp_out_str(obj, attr, (char*)lv_img_get_src(obj)); default: return; } @@ -1562,7 +1560,7 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char case ATTR_ALIGN: if(check_obj_type(obj, LV_HASP_BUTTON)) { - lv_obj_t * label = FindButtonLabel(obj); + lv_obj_t* label = FindButtonLabel(obj); if(label == NULL) goto attribute_not_found; else @@ -1581,7 +1579,7 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char case ATTR_MODE: if(check_obj_type(obj, LV_HASP_BUTTON)) { - lv_obj_t * label = FindButtonLabel(obj); + lv_obj_t* label = FindButtonLabel(obj); if(label) { hasp_process_label_long_mode(label, payload, update); lv_obj_set_width(label, lv_obj_get_width(obj)); @@ -1596,7 +1594,7 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char case ATTR_TOGGLE: if(check_obj_type(obj, LV_HASP_BUTTON)) { if(update) { - bool toggle = hasp_util_is_true(payload); + bool toggle = Utilities::is_true(payload); lv_btn_set_checkable(obj, toggle); lv_obj_set_event_cb(obj, toggle ? toggle_event_handler : generic_event_handler); } else { @@ -1608,7 +1606,7 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char break; // attribute_found case ATTR_OPTIONS: - if(check_obj_type(obj, LV_HASP_DDLIST)) { + if(check_obj_type(obj, LV_HASP_DROPDOWN)) { if(update) { lv_dropdown_set_options(obj, payload); } else { @@ -1616,7 +1614,7 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char } } else if(check_obj_type(obj, LV_HASP_ROLLER)) { if(update) { - lv_roller_ext_t * ext = (lv_roller_ext_t *)lv_obj_get_ext_attr(obj); + lv_roller_ext_t* ext = (lv_roller_ext_t*)lv_obj_get_ext_attr(obj); lv_roller_set_options(obj, payload, ext->mode); } else { hasp_out_str(obj, attr, lv_roller_get_options(obj)); @@ -1673,21 +1671,24 @@ void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char case ATTR_DELETE: if(!lv_obj_get_parent(obj)) { - return LOG_ERROR(TAG_ATTR, F(D_ATTRIBUTE_PAGE_METHOD_INVALID), attr_p); + LOG_ERROR(TAG_ATTR, F(D_ATTRIBUTE_PAGE_METHOD_INVALID), attr_p); + return; } lv_obj_del_async(obj); break; // attribute_found case ATTR_TO_FRONT: if(!lv_obj_get_parent(obj)) { - return LOG_ERROR(TAG_ATTR, F(D_ATTRIBUTE_PAGE_METHOD_INVALID), attr_p); + LOG_ERROR(TAG_ATTR, F(D_ATTRIBUTE_PAGE_METHOD_INVALID), attr_p); + return; } lv_obj_move_foreground(obj); break; // attribute_found case ATTR_TO_BACK: if(!lv_obj_get_parent(obj)) { - return LOG_ERROR(TAG_ATTR, F(D_ATTRIBUTE_PAGE_METHOD_INVALID), attr_p); + LOG_ERROR(TAG_ATTR, F(D_ATTRIBUTE_PAGE_METHOD_INVALID), attr_p); + return; } lv_obj_move_background(obj); break; // attribute_found diff --git a/src/hasp/hasp_attribute.h b/src/hasp/hasp_attribute.h index c7381fc4..38b656b7 100644 --- a/src/hasp/hasp_attribute.h +++ b/src/hasp/hasp_attribute.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_ATTR_SET_H @@ -6,7 +6,7 @@ #include "lvgl.h" #if LVGL_VERSION_MAJOR != 7 - #include "../lv_components.h" +#include "../lv_components.h" #endif #include "hasp_conf.h" @@ -18,16 +18,14 @@ extern "C" { #endif // test -lv_chart_series_t * my_chart_get_series(lv_obj_t * chart, uint8_t ser_num); -void my_obj_set_value_str_txt(lv_obj_t * obj, uint8_t part, lv_state_t state, const char * text); +lv_chart_series_t* my_chart_get_series(lv_obj_t* chart, uint8_t ser_num); +void my_obj_set_value_str_txt(lv_obj_t* obj, uint8_t part, lv_state_t state, const char* text); -void my_btnmatrix_map_clear(lv_obj_t * obj); -void line_clear_points(lv_obj_t * obj); +void my_btnmatrix_map_clear(lv_obj_t* obj); +void line_clear_points(lv_obj_t* obj); -void hasp_process_obj_attribute(lv_obj_t * obj, const char * attr_p, const char * payload, bool update); -bool hasp_process_obj_attribute_val(lv_obj_t * obj, const char * attr, const char * payload, bool update); - -bool haspPayloadToColor(const char * payload, lv_color32_t & color); +void hasp_process_obj_attribute(lv_obj_t* obj, const char* attr_p, const char* payload, bool update); +bool hasp_process_obj_attribute_val(lv_obj_t* obj, const char* attr, int16_t intval, bool booval, bool update); #ifdef __cplusplus } /* extern "C" */ @@ -39,8 +37,8 @@ bool haspPayloadToColor(const char * payload, lv_color32_t & color); #define hasp_out_color hasp_send_obj_attribute_color #define _HASP_ATTRIBUTE(prop_name, func_name, value_type) \ - static inline void attribute_##func_name(lv_obj_t * obj, uint8_t part, lv_state_t state, bool update, \ - const char * attr, value_type val) \ + static inline void attribute_##func_name(lv_obj_t* obj, uint8_t part, lv_state_t state, bool update, \ + const char* attr, value_type val) \ { \ if(update) { \ return lv_obj_set_style_local_##func_name(obj, part, state, (value_type)val); \ @@ -57,6 +55,10 @@ _HASP_ATTRIBUTE(SIZE, size, lv_style_int_t) _HASP_ATTRIBUTE(TRANSFORM_WIDTH, transform_width, lv_style_int_t) _HASP_ATTRIBUTE(TRANSFORM_HEIGHT, transform_height, lv_style_int_t) _HASP_ATTRIBUTE(OPA_SCALE, opa_scale, lv_opa_t) +_HASP_ATTRIBUTE(MARGIN_TOP, margin_top, lv_style_int_t) +_HASP_ATTRIBUTE(MARGIN_BOTTOM, margin_bottom, lv_style_int_t) +_HASP_ATTRIBUTE(MARGIN_LEFT, margin_left, lv_style_int_t) +_HASP_ATTRIBUTE(MARGIN_RIGHT, margin_right, lv_style_int_t) _HASP_ATTRIBUTE(PAD_TOP, pad_top, lv_style_int_t) _HASP_ATTRIBUTE(PAD_BOTTOM, pad_bottom, lv_style_int_t) _HASP_ATTRIBUTE(PAD_LEFT, pad_left, lv_style_int_t) @@ -162,6 +164,12 @@ _HASP_ATTRIBUTE(SCALE_END_LINE_WIDTH, scale_end_line_width, lv_style_int_t) #define ATTR_BG_BLEND_MODE 31147 #define ATTR_BG_GRAD_COLOR 44140 +/* Margin Attributes */ +#define ATTR_MARGIN_TOP 7812 +#define ATTR_MARGIN_LEFT 24440 +#define ATTR_MARGIN_BOTTOM 37692 +#define ATTR_MARGIN_RIGHT 2187 + /* Padding Attributes */ #define ATTR_PAD_TOP 59081 #define ATTR_PAD_LEFT 43123 @@ -304,75 +312,10 @@ _HASP_ATTRIBUTE(SCALE_END_LINE_WIDTH, scale_end_line_width, lv_style_int_t) #define ATTR_MAP 45628 /* hasp user data */ +#define ATTR_ACTION 42102 +#define ATTR_TRANSITION 10933 #define ATTR_GROUPID 48986 #define ATTR_OBJID 41010 - -/* Named COLOR attributes */ -#define ATTR_RED 177 -#define ATTR_TAN 7873 -#define ATTR_AQUA 3452 -#define ATTR_BLUE 37050 -#define ATTR_CYAN 9763 -#define ATTR_GOLD 53440 -#define ATTR_GRAY 64675 -#define ATTR_GREY 64927 -#define ATTR_LIME 34741 -#define ATTR_NAVY 44918 -#define ATTR_PERU 36344 -#define ATTR_PINK 51958 -#define ATTR_PLUM 64308 -#define ATTR_SNOW 35587 -#define ATTR_TEAL 52412 -#define ATTR_AZURE 44239 -#define ATTR_BEIGE 12132 -#define ATTR_BLACK 26527 -#define ATTR_BLUSH 41376 -#define ATTR_BROWN 10774 -#define ATTR_CORAL 16369 -#define ATTR_GREEN 26019 -#define ATTR_IVORY 1257 -#define ATTR_KHAKI 32162 -#define ATTR_LINEN 30074 -#define ATTR_OLIVE 47963 -#define ATTR_WHEAT 11591 -#define ATTR_WHITE 28649 -#define ATTR_BISQUE 60533 -#define ATTR_INDIGO 46482 -#define ATTR_MAROON 12528 -#define ATTR_ORANGE 21582 -#define ATTR_ORCHID 39235 -#define ATTR_PURPLE 53116 -#define ATTR_SALMON 29934 -#define ATTR_SIENNA 50930 -#define ATTR_SILVER 62989 -#define ATTR_TOMATO 8234 -#define ATTR_VIOLET 61695 -#define ATTR_YELLOW 10484 -#define ATTR_FUCHSIA 5463 -#define ATTR_MAGENTA 49385 - -struct hasp_color_t -{ - uint16_t hash; - uint8_t r, g, b; -}; - -/* Named COLOR lookup table */ -const hasp_color_t haspNamedColors[] PROGMEM = { - {ATTR_RED, 0xFF, 0x00, 0x00}, {ATTR_TAN, 0xD2, 0xB4, 0x8C}, {ATTR_AQUA, 0x00, 0xFF, 0xFF}, - {ATTR_BLUE, 0x00, 0x00, 0xFF}, {ATTR_CYAN, 0x00, 0xFF, 0xFF}, {ATTR_GOLD, 0xFF, 0xD7, 0x00}, - {ATTR_GRAY, 0x80, 0x80, 0x80}, {ATTR_GREY, 0x80, 0x80, 0x80}, {ATTR_LIME, 0x00, 0xFF, 0x00}, - {ATTR_NAVY, 0x00, 0x00, 0x80}, {ATTR_PERU, 0xCD, 0x85, 0x3F}, {ATTR_PINK, 0xFF, 0xC0, 0xCB}, - {ATTR_PLUM, 0xDD, 0xA0, 0xDD}, {ATTR_SNOW, 0xFF, 0xFA, 0xFA}, {ATTR_TEAL, 0x00, 0x80, 0x80}, - {ATTR_AZURE, 0xF0, 0xFF, 0xFF}, {ATTR_BEIGE, 0xF5, 0xF5, 0xDC}, {ATTR_BLACK, 0x00, 0x00, 0x00}, - {ATTR_BLUSH, 0xB0, 0x00, 0x00}, {ATTR_BROWN, 0xA5, 0x2A, 0x2A}, {ATTR_CORAL, 0xFF, 0x7F, 0x50}, - {ATTR_GREEN, 0x00, 0x80, 0x00}, {ATTR_IVORY, 0xFF, 0xFF, 0xF0}, {ATTR_KHAKI, 0xF0, 0xE6, 0x8C}, - {ATTR_LINEN, 0xFA, 0xF0, 0xE6}, {ATTR_OLIVE, 0x80, 0x80, 0x00}, {ATTR_WHEAT, 0xF5, 0xDE, 0xB3}, - {ATTR_WHITE, 0xFF, 0xFF, 0xFF}, {ATTR_BISQUE, 0xFF, 0xE4, 0xC4}, {ATTR_INDIGO, 0x4B, 0x00, 0x82}, - {ATTR_MAROON, 0x80, 0x00, 0x00}, {ATTR_ORANGE, 0xFF, 0xA5, 0x00}, {ATTR_ORCHID, 0xDA, 0x70, 0xD6}, - {ATTR_PURPLE, 0x80, 0x00, 0x80}, {ATTR_SALMON, 0xFA, 0x80, 0x72}, {ATTR_SIENNA, 0xA0, 0x52, 0x2D}, - {ATTR_SILVER, 0xC0, 0xC0, 0xC0}, {ATTR_TOMATO, 0xFF, 0x63, 0x47}, {ATTR_VIOLET, 0xEE, 0x82, 0xEE}, - {ATTR_YELLOW, 0xFF, 0xFF, 0x00}, {ATTR_FUCHSIA, 0xFF, 0x00, 0xFF}, {ATTR_MAGENTA, 0xFF, 0x00, 0xFF}, -}; +#define ATTR_OBJ 53623 #endif diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index e308d5f6..65913e9e 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -1,71 +1,117 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ -#include "ArduinoLog.h" -#include "hasp_conf.h" +#include -#include "hasp_dispatch.h" -#include "hasp_object.h" -#include "hasp.h" -#include "hasp_utilities.h" -#include "hasp_attribute.h" +//#include "ArduinoLog.h" +#include "hasplib.h" + +#include "dev/device.h" +#include "drv/tft_driver.h" + +//#include "hasp_gui.h" #if HASP_USE_DEBUG > 0 - #include "StringStream.h" - #include "CharStream.h" +#include "../hasp_debug.h" +#include "hasp_gui.h" // for screenshot - #include "hasp_debug.h" - #include "hasp_gui.h" - #include "hasp_oobe.h" - #include "hasp_gpio.h" - #include "hasp_hal.h" - - #include "svc/hasp_ota.h" - #include "svc/hasp_mqtt.h" - #include "net/hasp_network.h" // for network_get_status() +#if defined(WINDOWS) || defined(POSIX) +#include +#include +#include +#include "../mqtt/hasp_mqtt.h" #else - #include - #include +#include "StringStream.h" +#include "CharStream.h" + +#include "hasp_oobe.h" +#include "sys/gpio/hasp_gpio.h" +#include "hal/hasp_hal.h" + +#include "sys/svc/hasp_ota.h" +#include "mqtt/hasp_mqtt.h" +#include "sys/net/hasp_network.h" // for network_get_status() +#endif #endif #if HASP_USE_CONFIG > 0 - #include "hasp_config.h" +#include "hasp_config.h" #endif -extern unsigned long debugLastMillis; // UpdateStatus timer extern uint8_t hasp_sleep_state; +dispatch_conf_t dispatch_setings = {.teleperiod = 10}; + +uint32_t dispatchLastMillis; uint8_t nCommands = 0; -haspCommand_t commands[17]; +haspCommand_t commands[18]; struct moodlight_t { - byte power; - byte r, g, b; + uint8_t power; + uint8_t r, g, b; }; moodlight_t moodlight; -static void dispatch_config(const char * topic, const char * payload); +static void dispatch_config(const char* topic, const char* payload); // void dispatch_group_value(uint8_t groupid, int16_t state, lv_obj_t * obj); -static inline void dispatch_state_msg(const __FlashStringHelper * subtopic, const char * payload); -void dispatch_screenshot(const char *, const char * filename) +/* Sends the payload out on the state/subtopic + */ +void dispatch_state_subtopic(const char* subtopic, const char* payload) { -#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 - - if(strlen(filename) == 0) { // no filename given - char tempfile[32]; - memcpy_P(tempfile, PSTR("/screenshot.bmp"), sizeof(tempfile)); - guiTakeScreenshot(tempfile); - } else if(strlen(filename) > 31 || filename[0] != '/') { // Invalid filename - LOG_WARNING(TAG_MSGR, "Invalid filename %s", filename); - } else { // Valid filename - guiTakeScreenshot(filename); - } - +#if !defined(HASP_USE_MQTT) && !defined(HASP_USE_TASMOTA_CLIENT) + LOG_TRACE(TAG_MSGR, F("%s => %s"), subtopic, payload); #else - LOG_WARNING(TAG_MSGR, "Failed to save %s, no storage", filename); + +#if HASP_USE_MQTT > 0 + switch(mqtt_send_state(subtopic, payload)) { + case MQTT_ERR_OK: + LOG_TRACE(TAG_MQTT_PUB, F("%s => %s"), subtopic, payload); + break; + case MQTT_ERR_PUB_FAIL: + LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " %s => %s"), subtopic, payload); + break; + case MQTT_ERR_NO_CONN: + LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED)); + break; + default: + LOG_ERROR(TAG_MQTT, F(D_ERROR_UNKNOWN)); + } #endif + +#if HASP_USE_TASMOTA_CLIENT > 0 + slave_send_state(subtopic, payload); +#endif + +#endif +} + +/* Sends the data out on the state/pxby topic + */ +void dispatch_state_object(uint8_t pageid, uint8_t btnid, const char* payload) +{ + char topic[16]; + snprintf_P(topic, sizeof(topic), PSTR(HASP_OBJECT_NOTATION), pageid, btnid); + dispatch_state_subtopic(topic, payload); +} + +/* Takes and lv_obj and finds the pageid and objid + Then sends the data out on the state/pxby topic +*/ +void dispatch_obj_data(lv_obj_t* obj, const char* data) +{ + uint8_t pageid; + uint8_t objid; + + if(hasp_find_id_from_obj(obj, &pageid, &objid)) { + if(!data) return; +#if HASP_USE_MQTT > 0 + dispatch_state_object(pageid, objid, data); +#endif + } else { + LOG_ERROR(TAG_MSGR, F(D_OBJECT_UNKNOWN)); + } } // Format filesystem and erase EEPROM @@ -85,16 +131,16 @@ bool dispatch_factory_reset() return formated && erased; } -void dispatch_json_error(uint8_t tag, DeserializationError & jsonError) +void dispatch_json_error(uint8_t tag, DeserializationError& jsonError) { LOG_ERROR(tag, F(D_JSON_FAILED " %s"), jsonError.c_str()); } // p[x].b[y].attr=value -static inline bool dispatch_parse_button_attribute(const char * topic_p, const char * payload) +static inline bool dispatch_parse_button_attribute(const char* topic_p, const char* payload) { long num; - char * pEnd; + char* pEnd; uint8_t pageid, objid; if(*topic_p != 'p' && *topic_p != 'P') return false; // obligated p @@ -188,7 +234,7 @@ static inline bool dispatch_parse_button_attribute(const char * topic_p, const c } // objectattribute=value -void dispatch_command(const char * topic, const char * payload) +void dispatch_command(const char* topic, const char* payload) { /* ================================= Standard payload commands ======================================= */ @@ -204,8 +250,13 @@ void dispatch_command(const char * topic, const char * payload) /* =============================== Not standard payload commands ===================================== */ if(strlen(topic) == 7 && topic == strstr_P(topic, PSTR("output"))) { - int16_t state = atoi(payload); - dispatch_normalized_group_value(atoi(topic + 6), state, NULL); // + 6 => trim 'output' from the topic + + if(strlen(payload) == 0) { + // reply state + } else { + int16_t state = atoi(payload); + dispatch_normalized_group_value(atoi(topic + 6), NULL, state, 0, 1); // + 6 => trim 'output' from the topic + } // } else if(strcasecmp_P(topic, PSTR("screenshot")) == 0) { // guiTakeScreenshot("/screenshot.bmp"); // Literal String @@ -215,16 +266,16 @@ void dispatch_command(const char * topic, const char * payload) #if HASP_USE_CONFIG > 0 - #if HASP_USE_WIFI > 0 +#if HASP_USE_WIFI > 0 } else if(!strcmp_P(topic, FP_CONFIG_SSID) || !strcmp_P(topic, FP_CONFIG_PASS)) { StaticJsonDocument<64> settings; settings[topic] = payload; wifiSetConfig(settings.as()); - #endif // HASP_USE_WIFI +#endif // HASP_USE_WIFI - #if HASP_USE_MQTT > 0 +#if HASP_USE_MQTT > 0 } else if(!strcmp_P(topic, PSTR("mqtthost")) || !strcmp_P(topic, PSTR("mqttport")) || - !strcmp_P(topic, PSTR("mqttport")) || !strcmp_P(topic, PSTR("mqttuser")) || + !strcmp_P(topic, PSTR("mqttuser")) || !strcmp_P(topic, PSTR("mqttpass")) || !strcmp_P(topic, PSTR("hostname"))) { // char item[5]; // memset(item, 0, sizeof(item)); @@ -233,7 +284,7 @@ void dispatch_command(const char * topic, const char * payload) StaticJsonDocument<64> settings; settings[topic + 4] = payload; mqttSetConfig(settings.as()); - #endif // HASP_USE_MQTT +#endif // HASP_USE_MQTT #endif // HASP_USE_CONFIG @@ -246,34 +297,34 @@ void dispatch_command(const char * topic, const char * payload) } // Strip command/config prefix from the topic and process the payload -void dispatch_topic_payload(const char * topic, const char * payload) +void dispatch_topic_payload(const char* topic, const char* payload) { // LOG_VERBOSE(TAG_MSGR,F("TOPIC: short topic: %s"), topic); if(!strcmp_P(topic, PSTR("command"))) { - dispatch_text_line((char *)payload); + dispatch_text_line((char*)payload); return; } if(topic == strstr_P(topic, PSTR("command/"))) { // startsWith command/ topic += 8u; - dispatch_command(topic, (char *)payload); + dispatch_command(topic, (char*)payload); return; } #if HASP_USE_CONFIG > 0 if(topic == strstr_P(topic, PSTR("config/"))) { // startsWith command/ topic += 7u; - dispatch_config(topic, (char *)payload); + dispatch_config(topic, (char*)payload); return; } #endif - dispatch_command(topic, (char *)payload); // dispatch as is + dispatch_command(topic, (char*)payload); // dispatch as is } // Parse one line of text and execute the command -void dispatch_text_line(const char * cmnd) +void dispatch_text_line(const char* cmnd) { size_t pos1 = std::string(cmnd).find("="); size_t pos2 = std::string(cmnd).find(" "); @@ -312,51 +363,55 @@ void dispatch_text_line(const char * cmnd) // send idle state to the client void dispatch_output_idle_state(uint8_t state) { + char topic[6]; char payload[6]; switch(state) { case HASP_SLEEP_LONG: - memcpy_P(payload, PSTR("LONG"), sizeof(payload)); + memcpy_P(payload, PSTR("long"), 5); break; case HASP_SLEEP_SHORT: - memcpy_P(payload, PSTR("SHORT"), sizeof(payload)); + memcpy_P(payload, PSTR("short"), 6); break; default: - memcpy_P(payload, PSTR("OFF"), sizeof(payload)); + memcpy_P(payload, PSTR("off"), 4); } - dispatch_state_msg(F("idle"), payload); + memcpy_P(topic, PSTR("idle"), 5); + dispatch_state_subtopic(topic, payload); } void dispatch_output_group_state(uint8_t groupid, uint16_t state) { char payload[64]; char number[16]; // Return the current state + char topic[8]; itoa(state, number, DEC); snprintf_P(payload, sizeof(payload), PSTR("{\"group\":%d,\"state\":\"%s\"}"), groupid, number); - dispatch_state_msg(F("output"), payload); + memcpy_P(topic, PSTR("output"), 7); + dispatch_state_subtopic(topic, payload); } -void dispatch_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char * attribute, const char * data) +void dispatch_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char* attribute, const char* data) { if(!attribute || !data) return; char payload[32 + strlen(data) + strlen(attribute)]; snprintf_P(payload, sizeof(payload), PSTR("{\"%s\":\"%s\"}"), attribute, data); - mqtt_send_object_state(pageid, btnid, payload); + dispatch_state_object(pageid, btnid, payload); } -void dispatch_send_obj_attribute_int(uint8_t pageid, uint8_t btnid, const char * attribute, int32_t val) +void dispatch_send_obj_attribute_int(uint8_t pageid, uint8_t btnid, const char* attribute, int32_t val) { if(!attribute) return; char payload[64 + strlen(attribute)]; snprintf_P(payload, sizeof(payload), PSTR("{\"%s\":%d}"), attribute, val); - mqtt_send_object_state(pageid, btnid, payload); + dispatch_state_object(pageid, btnid, payload); } -void dispatch_send_obj_attribute_color(uint8_t pageid, uint8_t btnid, const char * attribute, uint8_t r, uint8_t g, +void dispatch_send_obj_attribute_color(uint8_t pageid, uint8_t btnid, const char* attribute, uint8_t r, uint8_t g, uint8_t b) { if(!attribute) return; @@ -365,12 +420,12 @@ void dispatch_send_obj_attribute_color(uint8_t pageid, uint8_t btnid, const char snprintf_P(payload, sizeof(payload), PSTR("{\"%s\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d}"), attribute, r, g, b, r, g, b); - mqtt_send_object_state(pageid, btnid, payload); + dispatch_state_object(pageid, btnid, payload); } #if HASP_USE_CONFIG > 0 // Get or Set a part of the config.json file -static void dispatch_config(const char * topic, const char * payload) +static void dispatch_config(const char* topic, const char* payload) { DynamicJsonDocument doc(128 * 2); char buffer[128 * 2]; @@ -413,48 +468,60 @@ static void dispatch_config(const char * topic, const char * payload) haspGetConfig(settings); } - #if HASP_USE_WIFI > 0 +#if HASP_USE_GPIO > 0 + else if(strcasecmp_P(topic, PSTR("gpio")) == 0) { + if(update) + gpioSetConfig(settings); + else + gpioGetConfig(settings); + } +#endif + +#if HASP_USE_WIFI > 0 else if(strcasecmp_P(topic, PSTR("wifi")) == 0) { if(update) wifiSetConfig(settings); else wifiGetConfig(settings); } - #if HASP_USE_MQTT > 0 +#if HASP_USE_MQTT > 0 else if(strcasecmp_P(topic, PSTR("mqtt")) == 0) { if(update) mqttSetConfig(settings); else mqttGetConfig(settings); } - #endif - #if HASP_USE_TELNET > 0 - // else if(strcasecmp_P(topic, PSTR("telnet")) == 0) - // telnetGetConfig(settings[F("telnet")]); - #endif - #if HASP_USE_MDNS > 0 +#endif +#if HASP_USE_TELNET > 0 + // else if(strcasecmp_P(topic, PSTR("telnet")) == 0) + // telnetGetConfig(settings[F("telnet")]); +#endif +#if HASP_USE_MDNS > 0 else if(strcasecmp_P(topic, PSTR("mdns")) == 0) { if(update) mdnsSetConfig(settings); else mdnsGetConfig(settings); } - #endif - #if HASP_USE_HTTP > 0 +#endif +#if HASP_USE_HTTP > 0 else if(strcasecmp_P(topic, PSTR("http")) == 0) { if(update) httpSetConfig(settings); else httpGetConfig(settings); } - #endif - #endif +#endif +#endif // Send output if(!update) { + char subtopic[8]; settings.remove(F("pass")); // hide password in output + size_t size = serializeJson(doc, buffer, sizeof(buffer)); - dispatch_state_msg(F("config"), buffer); + memcpy_P(subtopic, PSTR("config"), 7); + dispatch_state_subtopic(subtopic, buffer); } } #endif // HASP_USE_CONFIG @@ -480,35 +547,38 @@ bool dispatch_get_event_state(uint8_t eventid) } // Map events to their description string -void dispatch_get_event_name(uint8_t eventid, char * buffer, size_t size) +void dispatch_get_event_name(uint8_t eventid, char* buffer, size_t size) { switch(eventid) { case HASP_EVENT_ON: - memcpy_P(buffer, PSTR("ON"), size); + memcpy_P(buffer, PSTR("on"), size); break; case HASP_EVENT_OFF: - memcpy_P(buffer, PSTR("OFF"), size); + memcpy_P(buffer, PSTR("off"), size); break; case HASP_EVENT_UP: - memcpy_P(buffer, PSTR("UP"), size); + memcpy_P(buffer, PSTR("up"), size); break; case HASP_EVENT_DOWN: - memcpy_P(buffer, PSTR("DOWN"), size); + memcpy_P(buffer, PSTR("down"), size); break; case HASP_EVENT_SHORT: - memcpy_P(buffer, PSTR("SHORT"), size); + memcpy_P(buffer, PSTR("short"), size); break; case HASP_EVENT_LONG: - memcpy_P(buffer, PSTR("LONG"), size); + memcpy_P(buffer, PSTR("long"), size); break; case HASP_EVENT_HOLD: - memcpy_P(buffer, PSTR("HOLD"), size); + memcpy_P(buffer, PSTR("hold"), size); break; case HASP_EVENT_LOST: - memcpy_P(buffer, PSTR("LOST"), size); + memcpy_P(buffer, PSTR("lost"), size); + break; + case HASP_EVENT_CHANGED: + memcpy_P(buffer, PSTR("changed"), size); break; default: - memcpy_P(buffer, PSTR("UNKNOWN"), size); + memcpy_P(buffer, PSTR("unknown"), size); } } @@ -516,58 +586,82 @@ void dispatch_get_event_name(uint8_t eventid, char * buffer, size_t size) void dispatch_gpio_input_event(uint8_t pin, uint8_t group, uint8_t eventid) { char payload[64]; + char topic[8]; char event[8]; dispatch_get_event_name(eventid, event, sizeof(event)); snprintf_P(payload, sizeof(payload), PSTR("{\"pin\":%d,\"group\":%d,\"event\":\"%s\"}"), pin, group, event); - #if HASP_USE_MQTT > 0 - mqtt_send_state(F("input"), payload); - #endif +#if HASP_USE_MQTT > 0 + memcpy_P(topic, PSTR("input"), 6); + dispatch_state_subtopic(topic, payload); +#endif // update outputstates // dispatch_group_onoff(group, dispatch_get_event_state(eventid), NULL); } #endif -void dispatch_object_event(lv_obj_t * obj, uint8_t eventid) +/* ============================== Event Senders ============================ */ + +// Send out the event that occured +void dispatch_object_generic_event(lv_obj_t* obj, uint8_t eventid) { - char topic[8]; - char payload[8]; - uint8_t pageid, objid; + char data[40]; + char eventname[8]; - snprintf_P(topic, sizeof(topic), PSTR("event")); - dispatch_get_event_name(eventid, payload, sizeof(payload)); - - if(hasp_find_id_from_obj(obj, &pageid, &objid)) { - dispatch_send_obj_attribute_str(pageid, objid, topic, payload); - } - - // dispatch_group_onoff(obj->user_data.groupid, dispatch_get_event_state(eventid), obj); + dispatch_get_event_name(eventid, eventname, sizeof(eventname)); + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\"}"), eventname); + dispatch_obj_data(obj, data); } -void dispatch_object_value_changed(lv_obj_t * obj, int16_t state) +// Send out the on/off event, with the val +void dispatch_object_toggle_event(lv_obj_t* obj, bool state) { - char topic[4]; + char data[40]; + char eventname[8]; - hasp_update_sleep_state(); // wakeup? - snprintf_P(topic, sizeof(topic), PSTR("val")); - hasp_send_obj_attribute_int(obj, topic, state); + dispatch_get_event_name(state, eventname, sizeof(eventname)); + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d}"), eventname, state); + dispatch_obj_data(obj, data); +} + +// Send out the changed event, with the val +void dispatch_object_value_changed(lv_obj_t* obj, int16_t state) +{ + char data[48]; + + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"changed\",\"val\":%d}"), state); + dispatch_obj_data(obj, data); +} + +// Send out the changed event, with the val and text +void dispatch_object_selection_changed(lv_obj_t* obj, int16_t val, const char* text) +{ + char data[200]; + + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"changed\",\"val\":%d,\"text\":\"%s\"}"), val, text); + dispatch_obj_data(obj, data); +} + +// Send out the changed event, with the color +void dispatch_object_color_changed(lv_obj_t* obj, lv_color_t color) +{ + char data[80]; + lv_color32_t c32; + c32.full = lv_color_to32(color); + + snprintf_P(data, sizeof(data), + PSTR("{\"event\":\"changed\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d}"), c32.ch.red, + c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue); + dispatch_obj_data(obj, data); } /********************************************** Output States ******************************************/ -static inline void dispatch_state_msg(const __FlashStringHelper * subtopic, const char * payload) +/* +static inline void dispatch_state_msg(const __FlashStringHelper* subtopic, const char* payload) { -#if !defined(HASP_USE_MQTT) && !defined(HASP_USE_TASMOTA_SLAVE) - LOG_TRACE(TAG_MSGR, F("%s => %s"), String(subtopic).c_str(), payload); -#else - #if HASP_USE_MQTT > 0 - mqtt_send_state(subtopic, payload); - #endif - #if HASP_USE_TASMOTA_SLAVE > 0 - slave_send_state(subtopic, payload); - #endif -#endif -} + +}*/ // void dispatch_group_onoff(uint8_t groupid, uint16_t eventid, lv_obj_t * obj) // { @@ -576,7 +670,7 @@ static inline void dispatch_state_msg(const __FlashStringHelper * subtopic, cons // if(groupid >= 0) { // bool state = dispatch_get_event_state(eventid); // gpio_set_group_onoff(groupid, state); -// object_set_group_state(groupid, eventid, obj); +// object_set_normalized_group_value(groupid, eventid, obj); // } // char payload[8]; @@ -588,25 +682,46 @@ static inline void dispatch_state_msg(const __FlashStringHelper * subtopic, cons // { // if(groupid >= 0) { // gpio_set_group_value(groupid, state); -// object_set_group_state(groupid, state, obj); +// object_set_normalized_group_value(groupid, state, obj); // } // char payload[8]; // // dispatch_output_group_state(groupid, payload); // } -void dispatch_normalized_group_value(uint8_t groupid, uint16_t value, lv_obj_t * obj) +void dispatch_normalized_group_value(uint8_t groupid, lv_obj_t* obj, int16_t val, int16_t min, int16_t max) { - if(groupid > 0) { - LOG_VERBOSE(TAG_MSGR, F("GROUP %d value %d"), groupid, value); - gpio_set_normalized_group_value(groupid, value); - // object_set_group_state(groupid, value, obj); - } + if(groupid == 0) return; + + LOG_VERBOSE(TAG_MSGR, F("GROUP %d value %d (%d-%d)"), groupid, val, min, max); +#if HASP_USE_GPIO > 0 + gpio_set_normalized_group_value(groupid, val, min, max); // Update GPIO states +#endif + object_set_normalized_group_value(groupid, obj, val, min, max); // Update onsreen objects } /********************************************** Native Commands ****************************************/ -void dispatch_parse_json(const char *, const char * payload) +void dispatch_screenshot(const char*, const char* filename) +{ +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 + + if(strlen(filename) == 0) { // no filename given + char tempfile[32]; + memcpy_P(tempfile, PSTR("/screenshot.bmp"), sizeof(tempfile)); + guiTakeScreenshot(tempfile); + } else if(strlen(filename) > 31 || filename[0] != '/') { // Invalid filename + LOG_WARNING(TAG_MSGR, "Invalid filename %s", filename); + } else { // Valid filename + guiTakeScreenshot(filename); + } + +#else + LOG_WARNING(TAG_MSGR, "Failed to save %s, no storage", filename); +#endif +} + +void dispatch_parse_json(const char*, const char* payload) { // Parse an incoming JSON array into individual commands /* if(strPayload.endsWith(",]")) { // Trailing null array elements are an artifact of older Home Assistant automations @@ -627,40 +742,48 @@ void dispatch_parse_json(const char *, const char * payload) } else if(json.is()) { // handle json as an array of commands JsonArray arr = json.as(); - guiStop(); + // guiStop(); for(JsonVariant command : arr) { - dispatch_text_line(command.as().c_str()); + dispatch_text_line(command.as()); } - guiStart(); + // guiStart(); } else if(json.is()) { // handle json as a jsonl - uint8_t savedPage = haspGetPage(); + uint8_t savedPage = haspPages.get(); hasp_new_object(json.as(), savedPage); - } else if(json.is()) { // handle json as a single command - dispatch_text_line(json.as()); + // #ifdef ARDUINO + // } else if(json.is()) { // handle json as a single command + // dispatch_text_line(json.as().c_str()); + // #else + } else if(json.is()) { // handle json as a single command + dispatch_text_line(json.as().c_str()); + // #endif - } else if(json.is()) { // handle json as a single command - dispatch_text_line(json.as()); + } else if(json.is()) { // handle json as a single command + dispatch_text_line(json.as()); - } else if(json.is()) { // handle json as a single command - dispatch_text_line(json.as().c_str()); + } else if(json.is()) { // handle json as a single command + dispatch_text_line(json.as()); } else { LOG_WARNING(TAG_MSGR, F(D_DISPATCH_COMMAND_NOT_FOUND), payload); } } -#if HASP_USE_CONFIG > 0 -void dispatch_parse_jsonl(Stream & stream) +#ifdef ARDUINO +void dispatch_parse_jsonl(Stream& stream) #else -void dispatch_parse_jsonl(std::istringstream & stream) +void dispatch_parse_jsonl(std::istream& stream) #endif { - uint8_t savedPage = haspGetPage(); + uint8_t savedPage = haspPages.get(); size_t line = 1; DynamicJsonDocument jsonl(MQTT_MAX_PACKET_SIZE / 2 + 128); // max ~256 characters per line DeserializationError jsonError = deserializeJson(jsonl, stream); + +#ifdef ARDUINO stream.setTimeout(25); +#endif // guiStop(); while(jsonError == DeserializationError::Ok) { @@ -679,92 +802,105 @@ void dispatch_parse_jsonl(std::istringstream & stream) } } -void dispatch_parse_jsonl(const char *, const char * payload) +void dispatch_parse_jsonl(const char*, const char* payload) { #if HASP_USE_CONFIG > 0 - CharStream stream((char *)payload); + CharStream stream((char*)payload); // stream.setTimeout(10); dispatch_parse_jsonl(stream); #else - std::istringstream stream((char *)payload); + std::istringstream stream((char*)payload); dispatch_parse_jsonl(stream); #endif } void dispatch_output_current_page() { - // Log result - char payload[4]; - itoa(haspGetPage(), payload, DEC); - dispatch_state_msg(F("page"), payload); + char topic[8]; + char payload[8]; + + memcpy_P(topic, PSTR("page"), 5); + snprintf_P(payload, sizeof(payload), PSTR("%d"), haspPages.get()); + dispatch_state_subtopic(topic, payload); } -// Get or Set a page -void dispatch_page(const char *, const char * page) +// Dispatch Page Get or Set +void dispatch_page_next(lv_scr_load_anim_t animation) { - if(strlen(page) > 0) { - if(hasp_util_is_only_digits(page)) { - uint8_t pageid = atoi(page); - haspSetPage(pageid); - } else { - - if(!strcasecmp_P(page, PSTR("prev"))) { - dispatch_page_prev(); - } else if(!strcasecmp_P(page, PSTR("next"))) { - dispatch_page_next(); - } else { - LOG_WARNING(TAG_MSGR, PSTR(D_DISPATCH_INVALID_PAGE), page); - } - return; - } - } - + haspPages.next(animation); dispatch_output_current_page(); } -void dispatch_page_next() +void dispatch_page_prev(lv_scr_load_anim_t animation) { - uint8_t page = haspGetPage(); - if(page >= HASP_NUM_PAGES) { - page = 1; + haspPages.prev(animation); + dispatch_output_current_page(); +} + +void dispatch_page_back(lv_scr_load_anim_t animation) +{ + haspPages.back(animation); + dispatch_output_current_page(); +} + +void dispatch_set_page(uint8_t pageid) +{ + dispatch_set_page(pageid, LV_SCR_LOAD_ANIM_NONE); +} + +void dispatch_set_page(uint8_t pageid, lv_scr_load_anim_t animation) +{ + haspPages.set(pageid, animation); + dispatch_output_current_page(); +} + +void dispatch_page(const char*, const char* page) +{ + if(strlen(page) == 0) { + dispatch_output_current_page(); // No payload, send current page + return; + } + + lv_scr_load_anim_t animation = LV_SCR_LOAD_ANIM_NONE; + if(Utilities::is_only_digits(page)) { + uint8_t pageid = atoi(page); + dispatch_set_page(pageid, animation); + } else if(!strcasecmp_P(page, PSTR("prev"))) { + dispatch_page_prev(animation); + } else if(!strcasecmp_P(page, PSTR("next"))) { + dispatch_page_next(animation); + } else if(!strcasecmp_P(page, PSTR("back"))) { + dispatch_page_back(animation); } else { - page++; + LOG_WARNING(TAG_MSGR, PSTR(D_DISPATCH_INVALID_PAGE), page); } - haspSetPage(page); - dispatch_output_current_page(); -} - -void dispatch_page_prev() -{ - uint8_t page = haspGetPage(); - if(page == 1) { - page = HASP_NUM_PAGES; - } else { - page--; - } - haspSetPage(page); - dispatch_output_current_page(); } // Clears a page id or the current page if empty -void dispatch_clear_page(const char *, const char * page) +void dispatch_clear_page(const char*, const char* page) { - uint8_t pageid = haspGetPage(); - if(strlen(page) > 0) pageid = atoi(page); - haspClearPage(pageid); + uint8_t pageid; + if(strlen(page) > 0) + pageid = atoi(page); + else + pageid = haspPages.get(); + haspPages.clear(pageid); } -void dispatch_dim(const char *, const char * level) +void dispatch_dim(const char*, const char* level) { // Set the current state - if(strlen(level) != 0) guiSetDim(atoi(level)); + if(strlen(level) != 0) haspDevice.set_backlight_level(atoi(level)); - char payload[5]; - itoa(guiGetDim(), payload, DEC); - dispatch_state_msg(F("dim"), payload); + char topic[8]; + char payload[8]; + + memcpy_P(topic, PSTR("dim"), 4); + snprintf_P(payload, sizeof(payload), PSTR("%d"), haspDevice.get_backlight_level()); + dispatch_state_subtopic(topic, payload); } -void dispatch_moodlight(const char * topic, const char * payload) +void dispatch_moodlight(const char* topic, const char* payload) { // Set the current state if(strlen(payload) != 0) { @@ -781,48 +917,76 @@ void dispatch_moodlight(const char * topic, const char * payload) dispatch_json_error(TAG_MSGR, jsonError); } else { - if(!json[F("power")].isNull()) moodlight.power = hasp_util_is_true(json[F("power")].as().c_str()); + if(!json[F("state")].isNull()) + moodlight.power = Utilities::is_true(json[F("state")].as().c_str()); if(!json[F("r")].isNull()) moodlight.r = json[F("r")].as(); - if(!json[F("g")].isNull()) moodlight.r = json[F("g")].as(); - if(!json[F("b")].isNull()) moodlight.r = json[F("b")].as(); + if(!json[F("g")].isNull()) moodlight.g = json[F("g")].as(); + if(!json[F("b")].isNull()) moodlight.b = json[F("b")].as(); if(!json[F("color")].isNull()) { - lv_color32_t color; - if(haspPayloadToColor(json[F("color")].as().c_str(), color)) { - moodlight.r = color.ch.red; - moodlight.g = color.ch.green; - moodlight.b = color.ch.blue; + if(!json[F("color")]["r"].isNull()) { + moodlight.r = json[F("color")]["r"].as(); } + if(!json[F("color")]["g"].isNull()) { + moodlight.g = json[F("color")]["g"].as(); + } + if(!json[F("color")]["b"].isNull()) { + moodlight.b = json[F("color")]["b"].as(); + } + // lv_color32_t color; + // if(Parser::haspPayloadToColor(json[F("color")].as(), color)) { + // moodlight.r = color.ch.red; + // moodlight.g = color.ch.green; + // moodlight.b = color.ch.blue; + // } } +#if HASP_USE_GPIO > 0 if(moodlight.power) gpio_set_moodlight(moodlight.r, moodlight.g, moodlight.b); else gpio_set_moodlight(0, 0, 0); +#endif } } // Return the current state char buffer[128]; - snprintf_P(buffer, sizeof(buffer), - PSTR("{\"power\":\"%u\",\"color\":\"#%02x%02x%02x\",\"r\":%u,\"g\":%u,\"b\":%u}"), moodlight.power, - moodlight.r, moodlight.g, moodlight.b, moodlight.r, moodlight.g, moodlight.b); - dispatch_state_msg(F("moodlight"), buffer); + char out_topic[16]; + memcpy_P(out_topic, PSTR("moodlight"), 10); + snprintf_P( + // buffer, sizeof(buffer), + // PSTR("{\"state\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%u,\"g\":%u,\"b\":%u}"), + buffer, sizeof(buffer), PSTR("{\"state\":\"%s\",\"color\":{\"r\":%u,\"g\":%u,\"b\":%u}}"), + moodlight.power ? "ON" : "OFF", moodlight.r, moodlight.g, moodlight.b); + dispatch_state_subtopic(out_topic, buffer); } -void dispatch_backlight(const char *, const char * payload) +void dispatch_backlight(const char*, const char* payload) { // Set the current state - if(strlen(payload) != 0) guiSetBacklight(hasp_util_is_true(payload)); + if(strlen(payload) != 0) { + bool power = Utilities::is_true(payload); + + if(haspDevice.get_backlight_power() != power) { + haspDevice.set_backlight_power(power); + if(power) + hasp_disable_wakeup_touch(); + else + hasp_enable_wakeup_touch(); + } + } // Return the current state + char topic[8]; char buffer[4]; - memcpy_P(buffer, guiGetBacklight() ? PSTR("ON") : PSTR("OFF"), sizeof(buffer)); - dispatch_state_msg(F("light"), buffer); + memcpy_P(topic, PSTR("light"), 6); + memcpy_P(buffer, haspDevice.get_backlight_power() ? PSTR("on") : PSTR("off"), sizeof(buffer)); + dispatch_state_subtopic(topic, buffer); } -void dispatch_web_update(const char *, const char * espOtaUrl) +void dispatch_web_update(const char*, const char* espOtaUrl) { #if HASP_USE_OTA > 0 LOG_TRACE(TAG_MSGR, F(D_OTA_CHECK_UPDATE), espOtaUrl); @@ -834,9 +998,9 @@ void dispatch_web_update(const char *, const char * espOtaUrl) void dispatch_reboot(bool saveConfig) { #if HASP_USE_CONFIG > 0 - if(saveConfig) configWriteConfig(); + if(saveConfig) configWrite(); #endif -#if HASP_USE_MQTT > 0 +#if HASP_USE_MQTT > 0 && defined(ARDUINO) mqttStop(); // Stop the MQTT Client first #endif #if HASP_USE_CONFIG > 0 @@ -847,21 +1011,28 @@ void dispatch_reboot(bool saveConfig) #endif LOG_VERBOSE(TAG_MSGR, F("-------------------------------------")); LOG_TRACE(TAG_MSGR, F(D_DISPATCH_REBOOT)); + +#if defined(WINDOWS) || defined(POSIX) + fflush(stdout); +#else Serial.flush(); - halRestartMcu(); +#endif + + // halRestartMcu(); + haspDevice.reboot(); } void dispatch_current_state() { - dispatch_output_current_page(); dispatch_output_statusupdate(NULL, NULL); dispatch_output_idle_state(hasp_sleep_state); + dispatch_output_current_page(); } /******************************************* Command Wrapper Functions *********************************/ // Periodically publish a JSON string indicating system status -void dispatch_output_statusupdate(const char *, const char *) +void dispatch_output_statusupdate(const char*, const char*) { #if HASP_USE_MQTT > 0 @@ -872,30 +1043,35 @@ void dispatch_output_statusupdate(const char *, const char *) haspGetVersion(buffer, sizeof(buffer)); snprintf_P(data, sizeof(data), PSTR("{\"node\":\"%s\",\"status\":\"available\",\"version\":\"%s\",\"uptime\":%lu,"), - mqttGetNodename().c_str(), buffer, long(millis() / 1000)); + haspDevice.get_hostname(), buffer, long(millis() / 1000)); - #if HASP_USE_WIFI > 0 +#if HASP_USE_WIFI > 0 network_get_statusupdate(buffer, sizeof(buffer)); strcat(data, buffer); - #endif - snprintf_P(buffer, sizeof(buffer), PSTR("\"heapFree\":%u,\"heapFrag\":%u,\"espCore\":\"%s\","), - halGetFreeHeap(), halGetHeapFragmentation(), halGetCoreVersion().c_str()); - strcat(data, buffer); - snprintf_P(buffer, sizeof(buffer), PSTR("\"espCanUpdate\":\"false\",\"page\":%u,\"numPages\":%u,"), - haspGetPage(), (HASP_NUM_PAGES)); +#endif + + snprintf_P(buffer, sizeof(buffer), PSTR("\"heapFree\":%u,\"heapFrag\":%u,\"core\":\"%s\","), + haspDevice.get_free_heap(), haspDevice.get_heap_fragmentation(), haspDevice.get_core_version()); strcat(data, buffer); - #if defined(ARDUINO_ARCH_ESP8266) - snprintf_P(buffer, sizeof(buffer), PSTR("\"espVcc\":%.2f,"), (float)ESP.getVcc() / 1000); + snprintf_P(buffer, sizeof(buffer), PSTR("\"canUpdate\":\"false\",\"page\":%u,\"numPages\":%u,"), + haspPages.get(), haspPages.count()); strcat(data, buffer); - #endif + +// #if defined(ARDUINO_ARCH_ESP8266) +// snprintf_P(buffer, sizeof(buffer), PSTR("\"espVcc\":%.2f,"), (float)ESP.getVcc() / 1000); +// strcat(data, buffer); +// #endif snprintf_P(buffer, sizeof(buffer), PSTR("\"tftDriver\":\"%s\",\"tftWidth\":%u,\"tftHeight\":%u}"), - halDisplayDriverName().c_str(), (TFT_WIDTH), (TFT_HEIGHT)); + haspTft.get_tft_model(), (TFT_WIDTH), (TFT_HEIGHT)); strcat(data, buffer); } - mqtt_send_state(F("statusupdate"), data); - debugLastMillis = millis(); + + char topic[16]; + memcpy_P(topic, PSTR("statusupdate"), 13); + dispatch_state_subtopic(topic, data); + dispatchLastMillis = millis(); /* if(updateEspAvailable) { mqttStatusPayload += F("\"updateEspAvailable\":true,"); @@ -907,22 +1083,28 @@ void dispatch_output_statusupdate(const char *, const char *) #endif } -void dispatch_calibrate(const char * topic = NULL, const char * payload = NULL) +void dispatch_calibrate(const char* topic = NULL, const char* payload = NULL) { guiCalibrate(); } -void dispatch_wakeup(const char *, const char *) +void dispatch_wakeup(const char*, const char*) { lv_disp_trig_activity(NULL); + hasp_disable_wakeup_touch(); } -void dispatch_reboot(const char *, const char *) +void dispatch_sleep(const char*, const char*) +{ + hasp_enable_wakeup_touch(); +} + +void dispatch_reboot(const char*, const char*) { dispatch_reboot(true); } -void dispatch_factory_reset(const char *, const char *) +void dispatch_factory_reset(const char*, const char*) { dispatch_factory_reset(); delay(500); @@ -931,7 +1113,7 @@ void dispatch_factory_reset(const char *, const char *) /******************************************* Commands builder *******************************************/ -static void dispatch_add_command(const char * p_cmdstr, void (*func)(const char *, const char *)) +static void dispatch_add_command(const char* p_cmdstr, void (*func)(const char*, const char*)) { if(nCommands >= sizeof(commands) / sizeof(haspCommand_t)) { LOG_FATAL(TAG_MSGR, F("CMD_OVERFLOW %d"), nCommands); @@ -953,6 +1135,7 @@ void dispatchSetup() dispatch_add_command(PSTR("json"), dispatch_parse_json); dispatch_add_command(PSTR("page"), dispatch_page); dispatch_add_command(PSTR("wakeup"), dispatch_wakeup); + dispatch_add_command(PSTR("sleep"), dispatch_sleep); dispatch_add_command(PSTR("statusupdate"), dispatch_output_statusupdate); dispatch_add_command(PSTR("clearpage"), dispatch_clear_page); dispatch_add_command(PSTR("jsonl"), dispatch_parse_jsonl); @@ -974,5 +1157,30 @@ void dispatchSetup() void dispatchLoop() { - // Not used + lv_task_handler(); // process animations } + +#if 1 || ARDUINO +void dispatchEverySecond() +{ + if(dispatch_setings.teleperiod > 0 && (millis() - dispatchLastMillis) >= dispatch_setings.teleperiod * 1000) { + dispatchLastMillis += dispatch_setings.teleperiod * 1000; + dispatch_output_statusupdate(NULL, NULL); + } +} +#else +#include +std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); +void everySecond() +{ + if(dispatch_setings.teleperiod > 0) { + std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); + std::chrono::seconds elapsed = std::chrono::duration_cast(end - begin); + + if(elapsed.count() >= dispatch_setings.teleperiod) { + std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); + dispatch_output_statusupdate(NULL, NULL); + } + } +} +#endif diff --git a/src/hasp/hasp_dispatch.h b/src/hasp/hasp_dispatch.h index b8a4c1b9..1cae7f74 100644 --- a/src/hasp/hasp_dispatch.h +++ b/src/hasp/hasp_dispatch.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_DISPATCH_H @@ -7,6 +7,11 @@ #include "ArduinoJson.h" #include "lvgl.h" +struct dispatch_conf_t +{ + uint16_t teleperiod; +}; + enum hasp_event_t { // even = released, odd = pressed HASP_EVENT_OFF = 0, HASP_EVENT_ON = 1, @@ -17,7 +22,9 @@ enum hasp_event_t { // even = released, odd = pressed HASP_EVENT_LONG = 5, HASP_EVENT_LOST = 6, HASP_EVENT_HOLD = 7, - HASP_EVENT_DOUBLE = 8 + HASP_EVENT_DOUBLE = 8, + + HASP_EVENT_CHANGED = 32 }; /* ===== Default Event Processors ===== */ @@ -28,39 +35,53 @@ void dispatchStart(void); void dispatchStop(void); /* ===== Special Event Processors ===== */ -void dispatch_topic_payload(const char * topic, const char * payload); -void dispatch_text_line(const char * cmnd); -void dispatch_parse_jsonl(Stream & stream); -void dispatch_clear_page(const char * page); -void dispatch_json_error(uint8_t tag, DeserializationError & jsonError); +void dispatch_topic_payload(const char* topic, const char* payload); +void dispatch_text_line(const char* cmnd); -// void dispatchPage(uint8_t page); -void dispatch_page_next(); -void dispatch_page_prev(); +#ifdef ARDUINO +void dispatch_parse_jsonl(Stream& stream); +#else +void dispatch_parse_jsonl(std::istream& stream); +#endif -void dispatch_dim(const char * level); -void dispatch_backlight(const char * payload); +void dispatch_clear_page(const char* page); +void dispatch_json_error(uint8_t tag, DeserializationError& jsonError); -void dispatch_web_update(const char * espOtaUrl); +// void dispatch_set_page(uint8_t pageid); +void dispatch_set_page(uint8_t pageid, lv_scr_load_anim_t effectid); +void dispatch_page_next(lv_scr_load_anim_t effectid); +void dispatch_page_prev(lv_scr_load_anim_t effectid); +void dispatch_page_back(lv_scr_load_anim_t effectid); + +void dispatch_dim(const char* level); +void dispatch_backlight(const char*, const char* payload); + +void dispatch_web_update(const char*, const char* espOtaUrl); void dispatch_reboot(bool saveConfig); void dispatch_output_idle_state(uint8_t state); -void dispatch_output_statusupdate(const char *, const char *); +void dispatch_output_statusupdate(const char*, const char*); void dispatch_current_state(); +void dispatch_output_current_page(); void dispatch_gpio_input_event(uint8_t pin, uint8_t group, uint8_t eventid); -void dispatch_object_event(lv_obj_t * obj, uint8_t eventid); bool dispatch_get_event_state(uint8_t eventid); -void dispatch_get_event_name(uint8_t eventid, char * buffer, size_t size); -void dispatch_object_value_changed(lv_obj_t * obj, int16_t state); +void dispatch_get_event_name(uint8_t eventid, char* buffer, size_t size); +void dispatch_object_value_changed(lv_obj_t* obj, int16_t state); -void dispatch_normalized_group_value(uint8_t groupid, uint16_t value, lv_obj_t * obj); +void dispatch_normalized_group_value(uint8_t groupid, lv_obj_t* obj, int16_t val, int16_t min, int16_t max); -void dispatch_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char * attribute, const char * data); -void dispatch_send_obj_attribute_int(uint8_t pageid, uint8_t btnid, const char * attribute, int32_t val); -void dispatch_send_obj_attribute_color(uint8_t pageid, uint8_t btnid, const char * attribute, uint8_t r, uint8_t g, +void dispatch_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char* attribute, const char* data); +void dispatch_send_obj_attribute_int(uint8_t pageid, uint8_t btnid, const char* attribute, int32_t val); +void dispatch_send_obj_attribute_color(uint8_t pageid, uint8_t btnid, const char* attribute, uint8_t r, uint8_t g, uint8_t b); +void dispatch_object_generic_event(lv_obj_t* obj, uint8_t eventid); +void dispatch_object_toggle_event(lv_obj_t* obj, bool state); +void dispatch_object_value_changed(lv_obj_t* obj, int16_t state); +void dispatch_object_selection_changed(lv_obj_t* obj, int16_t val, const char* text); +void dispatch_object_color_changed(lv_obj_t* obj, lv_color_t color); + /* ===== Getter and Setter Functions ===== */ /* ===== Read/Write Configuration ===== */ @@ -68,8 +89,8 @@ void dispatch_send_obj_attribute_color(uint8_t pageid, uint8_t btnid, const char /* ===== Structs and Constants ===== */ struct haspCommand_t { - void (*func)(const char *, const char *); - const char * p_cmdstr; + const char* p_cmdstr; + void (*func)(const char*, const char*); }; #endif \ No newline at end of file diff --git a/src/hasp/hasp_lvfs.cpp b/src/hasp/hasp_lvfs.cpp new file mode 100644 index 00000000..996ba567 --- /dev/null +++ b/src/hasp/hasp_lvfs.cpp @@ -0,0 +1,36 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#include "lv_fs_if.h" + +#include "hasp_conf.h" // include first +#include "hasp_debug.h" + +void filesystem_list_path(const char* path) +{ + lv_fs_dir_t dir; + lv_fs_res_t res; + res = lv_fs_dir_open(&dir, path); + if(res != LV_FS_RES_OK) { + LOG_ERROR(TAG_LVFS, "Error opening directory %s", path); + } else { + char fn[256]; + while(1) { + res = lv_fs_dir_read(&dir, fn); + if(res != LV_FS_RES_OK) { + LOG_ERROR(TAG_LVFS, "Directory %s can not be read", path); + break; + } + + /*fn is empty, if not more files to read*/ + if(strlen(fn) == 0) { + LOG_WARNING(TAG_LVFS, "Directory %s listing complete", path); + break; + } + + LOG_VERBOSE(TAG_LVFS, D_BULLET "%s", fn); + } + } + + lv_fs_dir_close(&dir); +} diff --git a/src/hasp/hasp_lvfs.h b/src/hasp/hasp_lvfs.h new file mode 100644 index 00000000..2dde864d --- /dev/null +++ b/src/hasp/hasp_lvfs.h @@ -0,0 +1,9 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_LVFS_H +#define HASP_LVFS_H + +void filesystem_list_path(const char* path); + +#endif \ No newline at end of file diff --git a/src/hasp/hasp_object.cpp b/src/hasp/hasp_object.cpp index 82a25a0d..ddd12286 100644 --- a/src/hasp/hasp_object.cpp +++ b/src/hasp/hasp_object.cpp @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ /* ******************************************************************************************** @@ -13,44 +13,46 @@ * ******************************************************************************************** */ +#ifdef ARDUINO #include "ArduinoLog.h" +#endif #include "lvgl.h" #if LVGL_VERSION_MAJOR != 7 - #include "../lv_components.h" +#include "../lv_components.h" #endif -#include "hasp.h" -#include "hasp_object.h" -#include "hasp_dispatch.h" -#include "hasp_attribute.h" -#include "hasp_utilities.h" +#include "hasplib.h" -const char ** btnmatrix_default_map; // memory pointer to lvgl default btnmatrix map +#define HASP_NUM_PAGE_PREV (HASP_NUM_PAGES + 1) +#define HASP_NUM_PAGE_BACK (HASP_NUM_PAGES + 2) +#define HASP_NUM_PAGE_NEXT (HASP_NUM_PAGES + 3) + +const char** btnmatrix_default_map; // memory pointer to lvgl default btnmatrix map // static unsigned long last_change_event = 0; static bool last_press_was_short = false; // Avoid SHORT + UP double events // ##################### Object Finders ######################################################## -lv_obj_t * hasp_find_obj_from_parent_id(lv_obj_t * parent, uint8_t objid) +lv_obj_t* hasp_find_obj_from_parent_id(lv_obj_t* parent, uint8_t objid) { if(objid == 0 || parent == nullptr) return parent; - lv_obj_t * child; + lv_obj_t* child; child = lv_obj_get_child(parent, NULL); while(child) { /* child found, return it */ if(objid == child->user_data.id) return child; /* check grandchildren */ - lv_obj_t * grandchild = hasp_find_obj_from_parent_id(child, objid); + lv_obj_t* grandchild = hasp_find_obj_from_parent_id(child, objid); if(grandchild) return grandchild; /* grandchild found, return it */ /* check tabs */ if(check_obj_type(child, LV_HASP_TABVIEW)) { uint16_t tabcount = lv_tabview_get_tab_count(child); for(uint16_t i = 0; i < tabcount; i++) { - lv_obj_t * tab = lv_tabview_get_tab(child, i); + lv_obj_t* tab = lv_tabview_get_tab(child, i); LOG_VERBOSE(TAG_HASP, "Found tab %i", i); if(tab->user_data.objid && objid == tab->user_data.objid) return tab; /* tab found, return it */ @@ -71,9 +73,9 @@ lv_obj_t * hasp_find_obj_from_parent_id(lv_obj_t * parent, uint8_t objid) // return hasp_find_obj_from_parent_id(get_page_obj(pageid), objid); // } -bool hasp_find_id_from_obj(lv_obj_t * obj, uint8_t * pageid, uint8_t * objid) +bool hasp_find_id_from_obj(lv_obj_t* obj, uint8_t* pageid, uint8_t* objid) { - if(!get_page_id(obj, pageid)) return false; + if(!haspPages.get_id(obj, pageid)) return false; if(!(obj->user_data.id > 0)) return false; // memcpy(objid, &obj->user_data.id, sizeof(lv_obj_user_data_t)); *objid = obj->user_data.id; @@ -102,11 +104,11 @@ bool hasp_find_id_from_obj(lv_obj_t * obj, uint8_t * pageid, uint8_t * objid) // return (strcmp_P(lvobjtype, PSTR("label")) == 0); // case LV_HASP_CHECKBOX: // return (strcmp_P(lvobjtype, PSTR("checkbox")) == 0); // || (strcmp_P(lvobjtype, PSTR("lv_cb")) == 0); -// case LV_HASP_DDLIST: +// case LV_HASP_DROPDOWN: // return (strcmp_P(lvobjtype, PSTR("dropdown")) == 0); // || (strcmp_P(lvobjtype, PSTR("lv_ddlist")) == 0); // case LV_HASP_CPICKER: // return (strcmp_P(lvobjtype, PSTR("cpicker")) == 0); -// case LV_HASP_PRELOADER: +// case LV_HASP_SPINNER: // return (strcmp_P(lvobjtype, PSTR("spinner")) == 0); // || (strcmp_P(lvobjtype, PSTR("lv_preload")) == 0); // case LV_HASP_SLIDER: // return (strcmp_P(lvobjtype, PSTR("slider")) == 0); @@ -154,6 +156,20 @@ bool hasp_find_id_from_obj(lv_obj_t * obj, uint8_t * pageid, uint8_t * objid) // } // } +/** + * Get the object type name of an object + * @param obj an lv_obj_t* of the object to check its type + * @return name of the object type + * @note + */ +const char* get_obj_type_name(lv_obj_t* obj) +{ + lv_obj_type_t list; + lv_obj_get_type(obj, &list); + const char* objtype = list.type[0]; + return objtype + 3; // skip lv_ +} + /** * Check if an lvgl objecttype name corresponds to a given HASP object ID * @param obj an lv_obj_t* of the object to check its type @@ -161,29 +177,29 @@ bool hasp_find_id_from_obj(lv_obj_t * obj, uint8_t * pageid, uint8_t * objid) * @return true or false wether the types match * @note */ -bool check_obj_type(lv_obj_t * obj, lv_hasp_obj_type_t haspobjtype) +bool check_obj_type(lv_obj_t* obj, lv_hasp_obj_type_t haspobjtype) { #if 1 return obj->user_data.objid == (uint8_t)haspobjtype; #else lv_obj_type_t list; lv_obj_get_type(obj, &list); - const char * objtype = list.type[0]; + const char* objtype = list.type[0]; return check_obj_type(objtype, haspobjtype); #endif } -void hasp_object_tree(lv_obj_t * parent, uint8_t pageid, uint16_t level) +void hasp_object_tree(lv_obj_t* parent, uint8_t pageid, uint16_t level) { if(parent == nullptr) return; /* Output parent info */ lv_obj_type_t list; lv_obj_get_type(parent, &list); - const char * objtype = list.type[0]; + const char* objtype = list.type[0]; LOG_VERBOSE(TAG_HASP, F("[%d] " HASP_OBJECT_NOTATION " %s"), level, pageid, parent->user_data.id, objtype); - lv_obj_t * child; + lv_obj_t* child; child = lv_obj_get_child(parent, NULL); while(child) { /* child found, process it */ @@ -198,7 +214,7 @@ void hasp_object_tree(lv_obj_t * parent, uint8_t pageid, uint16_t level) #if 1 uint16_t tabcount = lv_tabview_get_tab_count(parent); for(uint16_t i = 0; i < tabcount; i++) { - lv_obj_t * tab = lv_tabview_get_tab(parent, i); + lv_obj_t* tab = lv_tabview_get_tab(parent, i); LOG_VERBOSE(TAG_HASP, "Found tab %i", i); if(tab->user_data.objid) hasp_object_tree(tab, pageid, level + 1); } @@ -208,7 +224,7 @@ void hasp_object_tree(lv_obj_t * parent, uint8_t pageid, uint16_t level) // ##################### Value Dispatchers ######################################################## -void hasp_send_obj_attribute_str(lv_obj_t * obj, const char * attribute, const char * data) +void hasp_send_obj_attribute_str(lv_obj_t* obj, const char* attribute, const char* data) { uint8_t pageid; uint8_t objid; @@ -218,7 +234,7 @@ void hasp_send_obj_attribute_str(lv_obj_t * obj, const char * attribute, const c } } -void hasp_send_obj_attribute_int(lv_obj_t * obj, const char * attribute, int32_t val) +void hasp_send_obj_attribute_int(lv_obj_t* obj, const char* attribute, int32_t val) { uint8_t pageid; uint8_t objid; @@ -228,7 +244,7 @@ void hasp_send_obj_attribute_int(lv_obj_t * obj, const char * attribute, int32_t } } -void hasp_send_obj_attribute_color(lv_obj_t * obj, const char * attribute, lv_color_t color) +void hasp_send_obj_attribute_color(lv_obj_t* obj, const char* attribute, lv_color_t color) { uint8_t pageid; uint8_t objid; @@ -271,12 +287,29 @@ void hasp_send_obj_attribute_color(lv_obj_t * obj, const char * attribute, lv_co // ##################### Event Handlers ######################################################## +/** + * Called when a press on the system layer is detected + * @param obj pointer to a button matrix + * @param event type of event that occured + */ +void wakeup_event_handler(lv_obj_t* obj, lv_event_t event) +{ + if(event == LV_EVENT_RELEASED && obj == lv_disp_get_layer_sys(NULL)) { + hasp_update_sleep_state(); // wakeup? + if(!haspDevice.get_backlight_power()) + dispatch_backlight(NULL, "1"); // backlight on and also disable wakeup touch + else { + hasp_disable_wakeup_touch(); // only disable wakeup touch + } + } +} + /** * Called when a button-style object is clicked * @param obj pointer to a button object * @param event type of event that occured */ -void generic_event_handler(lv_obj_t * obj, lv_event_t event) +void generic_event_handler(lv_obj_t* obj, lv_event_t event) { uint8_t eventid; @@ -319,7 +352,7 @@ void generic_event_handler(lv_obj_t * obj, lv_event_t event) return; case LV_EVENT_VALUE_CHANGED: - LOG_WARNING(TAG_HASP, F("Value changed Event %d occured"), event); + LOG_WARNING(TAG_HASP, F("Value changed Event %d occured"), event); // Shouldn't happen in this event handler last_press_was_short = false; return; @@ -335,26 +368,32 @@ void generic_event_handler(lv_obj_t * obj, lv_event_t event) return; } - hasp_update_sleep_state(); // wakeup? - dispatch_object_event(obj, eventid); // send object event - dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(dispatch_get_event_state(eventid), 0, 1), obj); -} + hasp_update_sleep_state(); // wakeup? -/** - * Called when a press on the system layer is detected - * @param obj pointer to a button matrix - * @param event type of event that occured - */ -void wakeup_event_handler(lv_obj_t * obj, lv_event_t event) -{ - if(obj == lv_disp_get_layer_sys(NULL)) { - hasp_update_sleep_state(); // wakeup? - - if(event == LV_EVENT_CLICKED) { - lv_obj_set_click(obj, false); // disable first touch - LOG_VERBOSE(TAG_HASP, F("Wakeup touch disabled")); + /* If an actionid is attached, perform that action on UP event only */ + if(obj->user_data.actionid) { + if(eventid == HASP_EVENT_UP || eventid == HASP_EVENT_SHORT) { + lv_scr_load_anim_t transitionid = (lv_scr_load_anim_t)obj->user_data.transitionid; + switch(obj->user_data.actionid) { + case HASP_NUM_PAGE_PREV: + haspPages.prev(transitionid); + break; + case HASP_NUM_PAGE_BACK: + haspPages.back(transitionid); + break; + case HASP_NUM_PAGE_NEXT: + haspPages.next(transitionid); + break; + default: + haspPages.set(obj->user_data.actionid, transitionid); + } + dispatch_output_current_page(); } + } else { + dispatch_object_generic_event(obj, eventid); // send normal object event } + dispatch_normalized_group_value(obj->user_data.groupid, obj, dispatch_get_event_state(eventid), HASP_EVENT_OFF, + HASP_EVENT_ON); } /** @@ -362,10 +401,10 @@ void wakeup_event_handler(lv_obj_t * obj, lv_event_t event) * @param obj pointer to a switch object * @param event type of event that occured */ -void toggle_event_handler(lv_obj_t * obj, lv_event_t event) +void toggle_event_handler(lv_obj_t* obj, lv_event_t event) { if(event == LV_EVENT_VALUE_CHANGED) { - char property[4]; + char property[36]; // 4 for val only bool val = 0; hasp_update_sleep_state(); // wakeup? @@ -387,9 +426,12 @@ void toggle_event_handler(lv_obj_t * obj, lv_event_t event) return; } - snprintf_P(property, sizeof(property), PSTR("val")); - hasp_send_obj_attribute_int(obj, property, val); - dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(val, 0, 1), obj); + // snprintf_P(property, sizeof(property), PSTR("val")); + // hasp_send_obj_attribute_int(obj, property, val); + + hasp_update_sleep_state(); // wakeup? + dispatch_object_toggle_event(obj, val); + dispatch_normalized_group_value(obj->user_data.groupid, obj, val, HASP_EVENT_OFF, HASP_EVENT_ON); } else if(event == LV_EVENT_DELETE) { LOG_VERBOSE(TAG_HASP, F(D_OBJECT_DELETED)); @@ -402,7 +444,7 @@ void toggle_event_handler(lv_obj_t * obj, lv_event_t event) * @param obj pointer to a dropdown list or roller * @param event type of event that occured */ -static void selector_event_handler(lv_obj_t * obj, lv_event_t event) +static void selector_event_handler(lv_obj_t* obj, lv_event_t event) { if(event == LV_EVENT_VALUE_CHANGED) { char buffer[128]; @@ -412,7 +454,7 @@ static void selector_event_handler(lv_obj_t * obj, lv_event_t event) hasp_update_sleep_state(); // wakeup? switch(obj->user_data.objid) { - case LV_HASP_DDLIST: + case LV_HASP_DROPDOWN: val = lv_dropdown_get_selected(obj); max = lv_dropdown_get_option_cnt(obj) - 1; lv_dropdown_get_selected_str(obj, buffer, sizeof(buffer)); @@ -425,8 +467,8 @@ static void selector_event_handler(lv_obj_t * obj, lv_event_t event) break; case LV_HASP_BTNMATRIX: { - val = lv_btnmatrix_get_active_btn(obj); - const char * txt = lv_btnmatrix_get_btn_text(obj, val); + val = lv_btnmatrix_get_active_btn(obj); + const char* txt = lv_btnmatrix_get_btn_text(obj, val); strncpy(buffer, txt, sizeof(buffer)); break; } @@ -436,10 +478,10 @@ static void selector_event_handler(lv_obj_t * obj, lv_event_t event) uint16_t col; if(lv_table_get_pressed_cell(obj, &row, &col) != LV_RES_OK) return; // outside any cell - const char * txt = lv_table_get_cell_value(obj, row, col); + const char* txt = lv_table_get_cell_value(obj, row, col); strncpy(buffer, txt, sizeof(buffer)); - snprintf_P(property, sizeof(property), PSTR("row\":%d,\"col\":%d,\"txt"), row, col); + snprintf_P(property, sizeof(property), PSTR("row\":%d,\"col\":%d,\"text"), row, col); hasp_send_obj_attribute_str(obj, property, buffer); return; } @@ -449,9 +491,11 @@ static void selector_event_handler(lv_obj_t * obj, lv_event_t event) } // set the property - snprintf_P(property, sizeof(property), PSTR("val\":%d,\"text"), val); - hasp_send_obj_attribute_str(obj, property, buffer); - if(max > 0) dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(val, 0, max), obj); + // snprintf_P(property, sizeof(property), PSTR("val\":%d,\"text"), val); + // hasp_send_obj_attribute_str(obj, property, buffer); + + dispatch_object_selection_changed(obj, val, buffer); + if(max > 0) dispatch_normalized_group_value(obj->user_data.groupid, obj, val, 0, max); } else if(event == LV_EVENT_DELETE) { LOG_VERBOSE(TAG_HASP, F(D_OBJECT_DELETED)); @@ -464,7 +508,7 @@ static void selector_event_handler(lv_obj_t * obj, lv_event_t event) * @param obj pointer to a slider * @param event type of event that occured */ -void slider_event_handler(lv_obj_t * obj, lv_event_t event) +void slider_event_handler(lv_obj_t* obj, lv_event_t event) { if(event == LV_EVENT_VALUE_CHANGED) { /* bool is_dragged; @@ -483,6 +527,7 @@ void slider_event_handler(lv_obj_t * obj, lv_event_t event) int16_t val = 0; int16_t min = 0; int16_t max = 0; + hasp_update_sleep_state(); // wakeup? if(obj->user_data.objid == LV_HASP_SLIDER) { val = lv_slider_get_value(obj); @@ -496,7 +541,7 @@ void slider_event_handler(lv_obj_t * obj, lv_event_t event) return; } dispatch_object_value_changed(obj, val); - dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(val, min, max), obj); + dispatch_normalized_group_value(obj->user_data.groupid, obj, val, min, max); } else if(event == LV_EVENT_DELETE) { LOG_VERBOSE(TAG_HASP, F(D_OBJECT_DELETED)); @@ -509,14 +554,16 @@ void slider_event_handler(lv_obj_t * obj, lv_event_t event) * @param obj pointer to a color picker * @param event type of event that occured */ -static void cpicker_event_handler(lv_obj_t * obj, lv_event_t event) +static void cpicker_event_handler(lv_obj_t* obj, lv_event_t event) { char color[6]; snprintf_P(color, sizeof(color), PSTR("color")); if(event == LV_EVENT_VALUE_CHANGED) { hasp_update_sleep_state(); // wakeup? - hasp_send_obj_attribute_color(obj, color, lv_cpicker_get_color(obj)); + // hasp_send_obj_attribute_color(obj, color, lv_cpicker_get_color(obj)); + dispatch_object_color_changed(obj, lv_cpicker_get_color(obj)); + } else if(event == LV_EVENT_DELETE) { LOG_VERBOSE(TAG_HASP, F(D_OBJECT_DELETED)); hasp_object_delete(obj); @@ -525,48 +572,31 @@ static void cpicker_event_handler(lv_obj_t * obj, lv_event_t event) // ##################### State Changers ######################################################## -// TODO make this a recursive function that goes over all objects only ONCE -void object_set_group_state(uint8_t groupid, uint8_t eventid, lv_obj_t * src_obj) -{ - if(groupid == 0) return; - bool state = dispatch_get_event_state(eventid); - - for(uint8_t page = 0; page < HASP_NUM_PAGES; page++) { - uint8_t startid = 1; - for(uint8_t objid = startid; objid < 20; objid++) { - lv_obj_t * obj = hasp_find_obj_from_parent_id(get_page_obj(page), objid); - if(obj && obj != src_obj && obj->user_data.groupid == groupid) { // skip source object, if set - lv_obj_set_state(obj, state ? LV_STATE_PRESSED | LV_STATE_CHECKED : LV_STATE_DEFAULT); - } - } - } -} - -void object_set_group_value(lv_obj_t * parent, uint8_t groupid, const char * payload) +void object_set_group_value(lv_obj_t* parent, uint8_t groupid, int16_t intval) { if(groupid == 0 || parent == nullptr) return; - lv_obj_t * child; + lv_obj_t* child; child = lv_obj_get_child(parent, NULL); while(child) { /* child found, update it */ - if(groupid == child->user_data.groupid) hasp_process_obj_attribute_val(child, NULL, payload, true); + if(groupid == child->user_data.groupid) hasp_process_obj_attribute_val(child, NULL, intval, intval, true); /* update grandchildren */ - object_set_group_value(child, groupid, payload); + object_set_group_value(child, groupid, intval); /* check tabs */ if(check_obj_type(child, LV_HASP_TABVIEW)) { //#if LVGL_VERSION_MAJOR == 7 uint16_t tabcount = lv_tabview_get_tab_count(child); for(uint16_t i = 0; i < tabcount; i++) { - lv_obj_t * tab = lv_tabview_get_tab(child, i); + lv_obj_t* tab = lv_tabview_get_tab(child, i); LOG_VERBOSE(TAG_HASP, F("Found tab %i"), i); if(tab->user_data.groupid && groupid == tab->user_data.groupid) - hasp_process_obj_attribute_val(tab, NULL, payload, true); /* tab found, update it */ + hasp_process_obj_attribute_val(tab, NULL, intval, intval, true); /* tab found, update it */ /* check grandchildren */ - object_set_group_value(tab, groupid, payload); + object_set_group_value(tab, groupid, intval); } //#endif } @@ -576,18 +606,38 @@ void object_set_group_value(lv_obj_t * parent, uint8_t groupid, const char * pay } } -void object_set_group_value(uint8_t groupid, int16_t state) +// TODO make this a recursive function that goes over all objects only ONCE +void object_set_normalized_group_value(uint8_t groupid, lv_obj_t* src_obj, int16_t val, int16_t min, int16_t max) { - char payload[16]; - itoa(state, payload, DEC); + if(groupid == 0) return; + if(min == max) return; + + for(uint8_t page = 0; page < HASP_NUM_PAGES; page++) { + object_set_group_value(haspPages.get_obj(page), groupid, val); + // uint8_t startid = 1; + // for(uint8_t objid = startid; objid < 20; objid++) { + // lv_obj_t* obj = hasp_find_obj_from_parent_id(get_page_obj(page), objid); + // if(obj && obj != src_obj && obj->user_data.groupid == groupid) { // skip source object, if set + // LOG_VERBOSE(TAG_HASP, F("Found p%db%d in group %d"), page, objid, groupid); + // lv_obj_set_state(obj, val > 0 ? LV_STATE_PRESSED | LV_STATE_CHECKED : LV_STATE_DEFAULT); + // switch(obj->user_data.objid) { + // case HASP_OBJ_ARC: + // case HASP_OBJ_SLIDER: + // case HASP_OBJ_CHECKBOX: + // hasp_process_obj_attribute_val(); + // default: + // } + // } + // } + } } //////////////////////////////////////////////////////////////////////////////////////////////////// // Used in the dispatcher & hasp_new_object -void hasp_process_attribute(uint8_t pageid, uint8_t objid, const char * attr, const char * payload) +void hasp_process_attribute(uint8_t pageid, uint8_t objid, const char* attr, const char* payload) { - if(lv_obj_t * obj = hasp_find_obj_from_parent_id(get_page_obj(pageid), objid)) { + if(lv_obj_t* obj = hasp_find_obj_from_parent_id(haspPages.get_obj(pageid), objid)) { hasp_process_obj_attribute(obj, attr, payload, strlen(payload) > 0); } else { LOG_WARNING(TAG_HASP, F(D_OBJECT_UNKNOWN " " HASP_OBJECT_NOTATION), pageid, objid); @@ -596,41 +646,79 @@ void hasp_process_attribute(uint8_t pageid, uint8_t objid, const char * attr, co // ##################### Object Creator ######################################################## +int hasp_parse_json_attributes(lv_obj_t* obj, const JsonObject& doc) +{ + int i = 0; +#if defined(WINDOWS) || defined(POSIX) + // String v((char *)0); + // v.reserve(64); + std::string v; + + for(JsonPair keyValue : doc) { + LOG_VERBOSE(TAG_HASP, F(D_BULLET "%s=%s"), keyValue.key().c_str(), keyValue.value().as().c_str()); + v = keyValue.value().as(); + hasp_process_obj_attribute(obj, keyValue.key().c_str(), keyValue.value().as().c_str(), true); + i++; + } +#else + String v((char*)0); + v.reserve(64); + + for(JsonPair keyValue : doc) { + LOG_DEBUG(TAG_HASP, F(D_BULLET "%s=%s"), keyValue.key().c_str(), keyValue.value().as().c_str()); + v = keyValue.value().as(); + hasp_process_obj_attribute(obj, keyValue.key().c_str(), keyValue.value().as().c_str(), true); + i++; + } +#endif + LOG_VERBOSE(TAG_HASP, F("%d attributes processed"), i); + return i; +} + /** * Create a new object according to the json config * @param config Json representation for this object * @param saved_page_id the pageid to use when no pageid is specified in the Json, updated when it is specified so * following objects in the file can share the pageid */ -void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) +void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id) { - /* Page selection: page is the default parent_obj */ - uint8_t pageid = config[FPSTR(FP_PAGE)].isNull() ? saved_page_id : config[FPSTR(FP_PAGE)].as(); - lv_obj_t * parent_obj = get_page_obj(pageid); - if(!parent_obj) { - return LOG_WARNING(TAG_HASP, F(D_OBJECT_PAGE_UNKNOWN), pageid); - } else { - saved_page_id = pageid; /* save the current pageid */ + /* Page selection */ + uint8_t pageid = saved_page_id; + if(!config[FPSTR(FP_PAGE)].isNull()) { + pageid = config[FPSTR(FP_PAGE)].as(); + config.remove(FPSTR(FP_PAGE)); } - // lv_obj_t * parent_obj = page; + /* Page with pageid is the default parent_obj */ + lv_obj_t* parent_obj = haspPages.get_obj(pageid); + if(!parent_obj) { + LOG_WARNING(TAG_HASP, F(D_OBJECT_PAGE_UNKNOWN), pageid); + return; + } else { + saved_page_id = pageid; /* save the current pageid for next objects */ + } + + /* A custom parentid was set */ if(!config[FPSTR(FP_PARENTID)].isNull()) { uint8_t parentid = config[FPSTR(FP_PARENTID)].as(); parent_obj = hasp_find_obj_from_parent_id(parent_obj, parentid); if(!parent_obj) { - return LOG_WARNING(TAG_HASP, F("Parent ID " HASP_OBJECT_NOTATION " not found, skipping..."), pageid, - parentid); + LOG_WARNING(TAG_HASP, F("Parent ID " HASP_OBJECT_NOTATION " not found, skipping..."), pageid, parentid); + return; } else { LOG_VERBOSE(TAG_HASP, F("Parent ID " HASP_OBJECT_NOTATION " found"), pageid, parentid); } + config.remove(FPSTR(FP_PARENTID)); } uint16_t sdbm = 0; - uint8_t id = config[FPSTR(FP_ID)].as(); uint8_t groupid = config[FPSTR(FP_GROUPID)].as(); + uint8_t id = config[FPSTR(FP_ID)].as(); + config.remove(FPSTR(FP_ID)); - /* Define Objects*/ - lv_obj_t * obj = hasp_find_obj_from_parent_id(parent_obj, id); + /* Create the object if it does not exist */ + lv_obj_t* obj = hasp_find_obj_from_parent_id(parent_obj, id); if(!obj) { /* Create the object first */ @@ -640,10 +728,12 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) if(config[FPSTR(FP_OBJ)].isNull()) { return; // comments } else { - sdbm = hasp_util_get_sdbm(config[FPSTR(FP_OBJ)].as().c_str()); + sdbm = Utilities::get_sdbm(config[FPSTR(FP_OBJ)].as()); + config.remove(FPSTR(FP_OBJ)); } } else { sdbm = config[FPSTR(FP_OBJID)].as(); + config.remove(FPSTR(FP_OBJID)); } switch(sdbm) { @@ -655,9 +745,9 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) lv_btnmatrix_set_recolor(obj, true); lv_obj_set_event_cb(obj, selector_event_handler); - lv_btnmatrix_ext_t * ext = (lv_btnmatrix_ext_t *)lv_obj_get_ext_attr(obj); - btnmatrix_default_map = ext->map_p; // store the static pointer to the default lvgl btnmap - obj->user_data.objid = LV_HASP_BTNMATRIX; + lv_btnmatrix_ext_t* ext = (lv_btnmatrix_ext_t*)lv_obj_get_ext_attr(obj); + btnmatrix_default_map = ext->map_p; // store the static pointer to the default lvgl btnmap + obj->user_data.objid = LV_HASP_BTNMATRIX; } break; @@ -674,7 +764,7 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) case HASP_OBJ_BTN: obj = lv_btn_create(parent_obj, NULL); if(obj) { - lv_obj_t * lbl = lv_label_create(obj, NULL); + lv_obj_t* lbl = lv_label_create(obj, NULL); if(lbl) { lv_label_set_text(lbl, ""); lv_label_set_recolor(lbl, true); @@ -687,7 +777,7 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) break; case LV_HASP_CHECKBOX: - case HASP_OBJ_CB: + case HASP_OBJ_CHECKBOX: obj = lv_checkbox_create(parent_obj, NULL); if(obj) { lv_obj_set_event_cb(obj, toggle_event_handler); @@ -781,7 +871,7 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) obj = lv_tabview_create(parent_obj, LV_DIR_TOP, 100); // No event handler for tabs if(obj) { - lv_obj_t * tab; + lv_obj_t* tab; tab = lv_tabview_add_tab(obj, "tab 1"); // lv_obj_set_user_data(tab, id + 1); tab = lv_tabview_add_tab(obj, "tab 2"); @@ -816,7 +906,7 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) obj = lv_tabview_create(parent_obj, NULL); // No event handler for tabs if(obj) { - lv_obj_t * tab; + lv_obj_t* tab; tab = lv_tabview_add_tab(obj, "tab 1"); // lv_obj_set_user_data(tab, id + 1); tab = lv_tabview_add_tab(obj, "tab 2"); @@ -839,11 +929,11 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) } break; -#if LV_USE_PRELOAD != 0 - case LV_HASP_PRELOADER: +#if LV_USE_SPINNER != 0 + case LV_HASP_SPINNER: case HASP_OBJ_SPINNER: obj = lv_spinner_create(parent_obj, NULL); - if(obj) obj->user_data.objid = LV_HASP_PRELOADER; + if(obj) obj->user_data.objid = LV_HASP_SPINNER; break; #endif @@ -901,7 +991,7 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) lv_chart_add_series(obj, LV_COLOR_GREEN); lv_chart_add_series(obj, LV_COLOR_BLUE); - lv_chart_series_t * ser = my_chart_get_series(obj, 2); + lv_chart_series_t* ser = my_chart_get_series(obj, 2); lv_chart_set_next(obj, ser, 10); lv_chart_set_next(obj, ser, 20); lv_chart_set_next(obj, ser, 30); @@ -922,7 +1012,7 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) break; /* ----- List Object ------- */ - case LV_HASP_DDLIST: + case LV_HASP_DROPDOWN: case HASP_OBJ_DROPDOWN: obj = lv_dropdown_create(parent_obj, NULL); if(obj) { @@ -931,7 +1021,7 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) lv_obj_set_top(obj, true); // lv_obj_align(obj, NULL, LV_ALIGN_IN_TOP_MID, 0, 20); lv_obj_set_event_cb(obj, selector_event_handler); - obj->user_data.objid = LV_HASP_DDLIST; + obj->user_data.objid = LV_HASP_DROPDOWN; } break; @@ -953,7 +1043,8 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) /* No object was actually created */ if(!obj) { - return LOG_ERROR(TAG_HASP, F(D_OBJECT_CREATE_FAILED), id); + LOG_ERROR(TAG_HASP, F(D_OBJECT_CREATE_FAILED), id); + return; } // Prevent losing press when the press is slid out of the objects. @@ -968,7 +1059,8 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) /** testing start **/ uint8_t temp; if(!hasp_find_id_from_obj(obj, &pageid, &temp)) { - return LOG_ERROR(TAG_HASP, F(D_OBJECT_LOST)); + LOG_ERROR(TAG_HASP, F(D_OBJECT_LOST)); + return; } /** verbose reporting **/ @@ -977,30 +1069,22 @@ void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id) LOG_VERBOSE(TAG_HASP, F(D_BULLET HASP_OBJECT_NOTATION " = %s"), pageid, temp, list.type[0]); /* test double-check */ - lv_obj_t * test = hasp_find_obj_from_parent_id(get_page_obj(pageid), (uint8_t)temp); + lv_obj_t* test = hasp_find_obj_from_parent_id(haspPages.get_obj(pageid), (uint8_t)temp); if(test != obj) { - return LOG_ERROR(TAG_HASP, F(D_OBJECT_MISMATCH)); + LOG_ERROR(TAG_HASP, F(D_OBJECT_MISMATCH)); + return; + } else { + // object created successfully } + + } else { + // object already exists } - /* do not process these attributes */ - config.remove(FPSTR(FP_PAGE)); - config.remove(FPSTR(FP_ID)); - config.remove(FPSTR(FP_OBJ)); - config.remove(FPSTR(FP_OBJID)); // TODO: obsolete objid - config.remove(FPSTR(FP_PARENTID)); - - String v((char *)0); - v.reserve(64); - - for(JsonPair keyValue : config) { - v = keyValue.value().as(); - hasp_process_obj_attribute(obj, keyValue.key().c_str(), v.c_str(), true); - // LOG_VERBOSE(TAG_HASP,F(" * %s => %s"), keyValue.key().c_str(), v.c_str()); - } + hasp_parse_json_attributes(obj, config); } -void hasp_object_delete(lv_obj_t * obj) +void hasp_object_delete(lv_obj_t* obj) { switch(obj->user_data.objid) { case LV_HASP_LINE: @@ -1019,4 +1103,4 @@ void hasp_object_delete(lv_obj_t * obj) // TODO: delete value_str data for ALL parts my_obj_set_value_str_txt(obj, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, NULL); -} \ No newline at end of file +} diff --git a/src/hasp/hasp_object.h b/src/hasp/hasp_object.h index 9ef17688..dd6c594e 100644 --- a/src/hasp/hasp_object.h +++ b/src/hasp/hasp_object.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_OBJECT_H @@ -7,12 +7,12 @@ #include #include "lvgl.h" -const char FP_PAGE[] PROGMEM = "page"; -const char FP_ID[] PROGMEM = "id"; -const char FP_OBJ[] PROGMEM = "obj"; -const char FP_OBJID[] PROGMEM = "objid"; +const char FP_PAGE[] PROGMEM = "page"; +const char FP_ID[] PROGMEM = "id"; +const char FP_OBJ[] PROGMEM = "obj"; +const char FP_OBJID[] PROGMEM = "objid"; const char FP_PARENTID[] PROGMEM = "parentid"; -const char FP_GROUPID[] PROGMEM = "groupid"; +const char FP_GROUPID[] PROGMEM = "groupid"; enum lv_hasp_obj_type_t { /* Controls */ @@ -28,7 +28,7 @@ enum lv_hasp_obj_type_t { LV_HASP_CPICKER = 20, /* Selectors */ - LV_HASP_DDLIST = 50, + LV_HASP_DROPDOWN = 50, LV_HASP_ROLLER = 51, LV_HASP_LIST = 52, // placeholder LV_HASP_TABLE = 53, @@ -44,14 +44,14 @@ enum lv_hasp_obj_type_t { LV_HASP_PAGE = 79, // Obsolete in v8 /* Visualizers */ - LV_HASP_LABEL = 12, // 30 - LV_HASP_GAUGE = 31, - LV_HASP_BAR = 32, - LV_HASP_LMETER = 33, - LV_HASP_LED = 41, // 34 - LV_HASP_ARC = 22, // 35 - LV_HASP_PRELOADER = 21, // 36 - LV_HASP_CHART = 37, + LV_HASP_LABEL = 12, // 30 + LV_HASP_GAUGE = 31, + LV_HASP_BAR = 32, + LV_HASP_LMETER = 33, + LV_HASP_LED = 41, // 34 + LV_HASP_ARC = 22, // 35 + LV_HASP_SPINNER = 21, // 36 + LV_HASP_CHART = 37, /* Graphics */ LV_HASP_LINE = 60, @@ -60,32 +60,33 @@ enum lv_hasp_obj_type_t { LV_HASP_MASK = 63, // placeholder }; -void hasp_new_object(const JsonObject & config, uint8_t & saved_page_id); +void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id); -lv_obj_t * hasp_find_obj_from_parent_id(lv_obj_t * parent, uint8_t objid); +lv_obj_t* hasp_find_obj_from_parent_id(lv_obj_t* parent, uint8_t objid); // lv_obj_t * hasp_find_obj_from_page_id(uint8_t pageid, uint8_t objid); -bool hasp_find_id_from_obj(lv_obj_t * obj, uint8_t * pageid, uint8_t * objid); +bool hasp_find_id_from_obj(lv_obj_t* obj, uint8_t* pageid, uint8_t* objid); // bool check_obj_type_str(const char * lvobjtype, lv_hasp_obj_type_t haspobjtype); -bool check_obj_type(lv_obj_t * obj, lv_hasp_obj_type_t haspobjtype); -void hasp_object_tree(lv_obj_t * parent, uint8_t pageid, uint16_t level); -void hasp_object_delete(lv_obj_t * obj); +const char* get_obj_type_name(lv_obj_t* obj); +bool check_obj_type(lv_obj_t* obj, lv_hasp_obj_type_t haspobjtype); +void hasp_object_tree(lv_obj_t* parent, uint8_t pageid, uint16_t level); +void hasp_object_delete(lv_obj_t* obj); -void hasp_send_obj_attribute_str(lv_obj_t * obj, const char * attribute, const char * data); -void hasp_send_obj_attribute_int(lv_obj_t * obj, const char * attribute, int32_t val); -void hasp_send_obj_attribute_color(lv_obj_t * obj, const char * attribute, lv_color_t color); -void hasp_process_attribute(uint8_t pageid, uint8_t objid, const char * attr, const char * payload); +void hasp_send_obj_attribute_str(lv_obj_t* obj, const char* attribute, const char* data); +void hasp_send_obj_attribute_int(lv_obj_t* obj, const char* attribute, int32_t val); +void hasp_send_obj_attribute_color(lv_obj_t* obj, const char* attribute, lv_color_t color); +void hasp_process_attribute(uint8_t pageid, uint8_t objid, const char* attr, const char* payload); -void object_set_group_state(uint8_t groupid, uint8_t eventid, lv_obj_t * src_obj); +void object_set_normalized_group_value(uint8_t groupid, lv_obj_t* src_obj, int16_t val, int16_t min, int16_t max); -void generic_event_handler(lv_obj_t * obj, lv_event_t event); -void toggle_event_handler(lv_obj_t * obj, lv_event_t event); -void slider_event_handler(lv_obj_t * obj, lv_event_t event); -void wakeup_event_handler(lv_obj_t * obj, lv_event_t event); +void generic_event_handler(lv_obj_t* obj, lv_event_t event); +void toggle_event_handler(lv_obj_t* obj, lv_event_t event); +void slider_event_handler(lv_obj_t* obj, lv_event_t event); +void wakeup_event_handler(lv_obj_t* obj, lv_event_t event); #define HASP_OBJ_BAR 1971 #define HASP_OBJ_BTN 3164 #define HASP_OBJ_CPICKER 3313 -#define HASP_OBJ_CB 6335 +#define HASP_OBJ_CHECKBOX 1923 #define HASP_OBJ_SPINNER 7097 #define HASP_OBJ_MSGBOX 7498 #define HASP_OBJ_TABLE 12078 diff --git a/src/hasp/hasp_page.cpp b/src/hasp/hasp_page.cpp new file mode 100644 index 00000000..72cf2b95 --- /dev/null +++ b/src/hasp/hasp_page.cpp @@ -0,0 +1,152 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#include "hasp_conf.h" +#include "hasplib.h" + +#include "hasp_page.h" + +namespace hasp { + +Page::Page() +{ + // LVGL is not yet initialized at construction time +} + +size_t Page::count() +{ + return sizeof(_pages) / sizeof(*_pages); +} + +void Page::init(uint8_t start_page) +{ + for(int i = 0; i < count(); i++) { + _pages[i] = lv_obj_create(NULL, NULL); + + uint16_t thispage = i + PAGE_START_INDEX; + _meta_data[i].prev = thispage == PAGE_START_INDEX ? HASP_NUM_PAGES : thispage - PAGE_START_INDEX; + _meta_data[i].next = thispage == HASP_NUM_PAGES ? PAGE_START_INDEX : thispage + PAGE_START_INDEX; + _meta_data[i].back = start_page; + } +} + +void Page::clear(uint16_t pageid) +{ + lv_obj_t* page = get_obj(pageid); + if(!page || (pageid > HASP_NUM_PAGES)) { + LOG_WARNING(TAG_HASP, F(D_HASP_INVALID_PAGE), pageid); + } else if(page == lv_layer_sys() /*|| page == lv_layer_top()*/) { + LOG_WARNING(TAG_HASP, F(D_HASP_INVALID_LAYER)); + } else { + LOG_TRACE(TAG_HASP, F(D_HASP_CLEAR_PAGE), pageid); + lv_obj_clean(page); + } +} + +// void Page::set(uint8_t pageid) +// { +// set(pageid, LV_SCR_LOAD_ANIM_NONE); +// } + +void Page::set(uint8_t pageid, lv_scr_load_anim_t animation) +{ + lv_obj_t* page = get_obj(pageid); + if(!page || pageid == 0 || pageid > HASP_NUM_PAGES) { + LOG_WARNING(TAG_HASP, F(D_HASP_INVALID_PAGE), pageid); + } else { + LOG_TRACE(TAG_HASP, F(D_HASP_CHANGE_PAGE), pageid); + _current_page = pageid; + lv_scr_load_anim(page, animation, 500, 0, false); + hasp_object_tree(page, pageid, 0); + } +} + +void Page::next(lv_scr_load_anim_t animation) +{ + set(_meta_data[_current_page - PAGE_START_INDEX].next, animation); +} + +void Page::prev(lv_scr_load_anim_t animation) +{ + set(_meta_data[_current_page - PAGE_START_INDEX].prev, animation); +} + +void Page::back(lv_scr_load_anim_t animation) +{ + set(_meta_data[_current_page - PAGE_START_INDEX].back, animation); +} + +uint8_t Page::get() +{ + return _current_page; +} + +void Page::load_jsonl(const char* pagesfile) +{ +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 + if(pagesfile[0] == '\0') return; + + if(!filesystemSetup()) { + LOG_ERROR(TAG_HASP, F("FS not mounted. Failed to load %s"), pagesfile); + return; + } + + if(!HASP_FS.exists(pagesfile)) { + LOG_ERROR(TAG_HASP, F("Non existing file %s"), pagesfile); + return; + } + + LOG_TRACE(TAG_HASP, F("Loading file %s"), pagesfile); + + File file = HASP_FS.open(pagesfile, "r"); + dispatch_parse_jsonl(file); + file.close(); + + LOG_INFO(TAG_HASP, F("File %s loaded"), pagesfile); +#else + +#if HASP_USE_EEPROM > 0 + LOG_TRACE(TAG_HASP, F("Loading jsonl from EEPROM...")); + EepromStream eepromStream(4096, 1024); + dispatch_parse_jsonl(eepromStream); + LOG_INFO(TAG_HASP, F("Loaded jsonl from EEPROM")); +#endif + +#endif +} + +lv_obj_t* Page::get_obj(uint8_t pageid) +{ + if(pageid == 0) return lv_layer_top(); // 254 + if(pageid == 255) return lv_layer_sys(); + if(pageid > count()) return NULL; // >=0 + return _pages[pageid - PAGE_START_INDEX]; +} + +bool Page::get_id(lv_obj_t* obj, uint8_t* pageid) +{ + lv_obj_t* page = lv_obj_get_screen(obj); + + if(!page) return false; + + if(page == lv_layer_top()) { + *pageid = 0; + return true; + } + if(page == lv_layer_sys()) { + *pageid = 255; + return true; + } + + for(uint8_t i = 0; i < count(); i++) { + if(page == _pages[i]) { + *pageid = i + PAGE_START_INDEX; + return true; + } + } + return false; +} + +} // namespace hasp + +hasp::Page haspPages; diff --git a/src/hasp/hasp_page.h b/src/hasp/hasp_page.h new file mode 100644 index 00000000..1e2bfaa4 --- /dev/null +++ b/src/hasp/hasp_page.h @@ -0,0 +1,55 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_PAGES_H +#define HASP_PAGES_H + +#include "hasp_conf.h" +#include "hasplib.h" + +/********************* + * DEFINES + *********************/ +#define PAGE_START_INDEX 1 // Page number of array index 0 + +/********************** + * TYPEDEFS + **********************/ + +typedef struct hasp_page_meta_data_t +{ + uint8_t prev : 4; + uint8_t next : 4; + uint8_t back : 4; +}; + +namespace hasp { + +class Page { + private: + hasp_page_meta_data_t _meta_data[HASP_NUM_PAGES]; // index 0 = Page 1 etc. + lv_obj_t* _pages[HASP_NUM_PAGES]; // index 0 = Page 1 etc. + uint8_t _current_page; + + public: + Page(); + size_t count(); + void init(uint8_t start_page); + void clear(uint16_t pageid); + // void set(uint8_t pageid); + void set(uint8_t pageid, lv_scr_load_anim_t animation); + void next(lv_scr_load_anim_t animation); + void prev(lv_scr_load_anim_t animation); + void back(lv_scr_load_anim_t animation); + uint8_t get(); + void load_jsonl(const char* pagesfile); + lv_obj_t* get_obj(uint8_t pageid); + bool get_id(lv_obj_t* obj, uint8_t* pageid); +}; + +} // namespace hasp + +using hasp::Page; +extern hasp::Page haspPages; + +#endif // HASP_PAGES_H diff --git a/src/hasp/hasp_parser.cpp b/src/hasp/hasp_parser.cpp new file mode 100644 index 00000000..10336a42 --- /dev/null +++ b/src/hasp/hasp_parser.cpp @@ -0,0 +1,88 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#include + +#ifdef ARDUINO +#include "pgmspace.h" +#endif + +#include "lvgl.h" + +#include "hasplib.h" + +bool Parser::haspPayloadToColor(const char* payload, lv_color32_t& color) +{ + /* HEX format #rrggbb or #rgb */ + if(*payload == '#') { + if(strlen(payload) >= 8) return false; + + char* pEnd; + long color_int = strtol(payload + 1, &pEnd, HEX); + + if(pEnd - payload == 7) { // #rrbbgg + color.ch.red = color_int >> 16 & 0xff; + color.ch.green = color_int >> 8 & 0xff; + color.ch.blue = color_int & 0xff; + + } else if(pEnd - payload == 4) { // #rgb + color.ch.red = color_int >> 8 & 0xf; + color.ch.green = color_int >> 4 & 0xf; + color.ch.blue = color_int & 0xf; + + color.ch.red += color.ch.red * HEX; + color.ch.green += color.ch.green * HEX; + color.ch.blue += color.ch.blue * HEX; + + } else { + return false; /* Invalid hex length */ + } + + return true; /* Color found */ + } + + /* 16-bit RGB565 Color Scheme*/ + if(Utilities::is_only_digits(payload)) { + uint16_t c = atoi(payload); + + /* Initial colors */ + uint8_t R5 = ((c >> 11) & 0b11111); + uint8_t G6 = ((c >> 5) & 0b111111); + uint8_t B5 = (c & 0b11111); + + /* Remapped colors */ + color.ch.red = (R5 * 527 + 23) >> 6; + color.ch.green = (G6 * 259 + 33) >> 6; + color.ch.blue = (B5 * 527 + 23) >> 6; + + return true; /* Color found */ + } + + /* Named colors */ + size_t numColors = sizeof(haspNamedColors) / sizeof(haspNamedColors[0]); + uint16_t sdbm = Utilities::get_sdbm(payload); + +#ifdef ARDUINO + for(size_t i = 0; i < numColors; i++) { + if(sdbm == (uint16_t)pgm_read_word_near(&(haspNamedColors[i].hash))) { + color.ch.red = (uint16_t)pgm_read_byte_near(&(haspNamedColors[i].r)); + color.ch.green = (uint16_t)pgm_read_byte_near(&(haspNamedColors[i].g)); + color.ch.blue = (uint16_t)pgm_read_byte_near(&(haspNamedColors[i].b)); + + return true; /* Color found */ + } + } +#else + for(size_t i = 0; i < numColors; i++) { + if(sdbm == haspNamedColors[i].hash) { + color.ch.red = haspNamedColors[i].r; + color.ch.green = haspNamedColors[i].g; + color.ch.blue = haspNamedColors[i].b; + + return true; /* Color found */ + } + } +#endif + + return false; /* Color not found */ +} \ No newline at end of file diff --git a/src/hasp/hasp_parser.h b/src/hasp/hasp_parser.h new file mode 100644 index 00000000..d0697a17 --- /dev/null +++ b/src/hasp/hasp_parser.h @@ -0,0 +1,84 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_PARSER_H +#define HASP_PARSER_H + +#include "lvgl.h" +#include "hasp_conf.h" + +class Parser { + + public: + static bool haspPayloadToColor(const char* payload, lv_color32_t& color); +}; + +/* Named COLOR attributes */ +#define ATTR_RED 177 +#define ATTR_TAN 7873 +#define ATTR_AQUA 3452 +#define ATTR_BLUE 37050 +#define ATTR_CYAN 9763 +#define ATTR_GOLD 53440 +#define ATTR_GRAY 64675 +#define ATTR_GREY 64927 +#define ATTR_LIME 34741 +#define ATTR_NAVY 44918 +#define ATTR_PERU 36344 +#define ATTR_PINK 51958 +#define ATTR_PLUM 64308 +#define ATTR_SNOW 35587 +#define ATTR_TEAL 52412 +#define ATTR_AZURE 44239 +#define ATTR_BEIGE 12132 +#define ATTR_BLACK 26527 +#define ATTR_BLUSH 41376 +#define ATTR_BROWN 10774 +#define ATTR_CORAL 16369 +#define ATTR_GREEN 26019 +#define ATTR_IVORY 1257 +#define ATTR_KHAKI 32162 +#define ATTR_LINEN 30074 +#define ATTR_OLIVE 47963 +#define ATTR_WHEAT 11591 +#define ATTR_WHITE 28649 +#define ATTR_BISQUE 60533 +#define ATTR_INDIGO 46482 +#define ATTR_MAROON 12528 +#define ATTR_ORANGE 21582 +#define ATTR_ORCHID 39235 +#define ATTR_PURPLE 53116 +#define ATTR_SALMON 29934 +#define ATTR_SIENNA 50930 +#define ATTR_SILVER 62989 +#define ATTR_TOMATO 8234 +#define ATTR_VIOLET 61695 +#define ATTR_YELLOW 10484 +#define ATTR_FUCHSIA 5463 +#define ATTR_MAGENTA 49385 + +struct hasp_color_t +{ + uint16_t hash; + uint8_t r, g, b; +}; + +/* Named COLOR lookup table */ +const hasp_color_t haspNamedColors[] PROGMEM = { + {ATTR_RED, 0xFF, 0x00, 0x00}, {ATTR_TAN, 0xD2, 0xB4, 0x8C}, {ATTR_AQUA, 0x00, 0xFF, 0xFF}, + {ATTR_BLUE, 0x00, 0x00, 0xFF}, {ATTR_CYAN, 0x00, 0xFF, 0xFF}, {ATTR_GOLD, 0xFF, 0xD7, 0x00}, + {ATTR_GRAY, 0x80, 0x80, 0x80}, {ATTR_GREY, 0x80, 0x80, 0x80}, {ATTR_LIME, 0x00, 0xFF, 0x00}, + {ATTR_NAVY, 0x00, 0x00, 0x80}, {ATTR_PERU, 0xCD, 0x85, 0x3F}, {ATTR_PINK, 0xFF, 0xC0, 0xCB}, + {ATTR_PLUM, 0xDD, 0xA0, 0xDD}, {ATTR_SNOW, 0xFF, 0xFA, 0xFA}, {ATTR_TEAL, 0x00, 0x80, 0x80}, + {ATTR_AZURE, 0xF0, 0xFF, 0xFF}, {ATTR_BEIGE, 0xF5, 0xF5, 0xDC}, {ATTR_BLACK, 0x00, 0x00, 0x00}, + {ATTR_BLUSH, 0xB0, 0x00, 0x00}, {ATTR_BROWN, 0xA5, 0x2A, 0x2A}, {ATTR_CORAL, 0xFF, 0x7F, 0x50}, + {ATTR_GREEN, 0x00, 0x80, 0x00}, {ATTR_IVORY, 0xFF, 0xFF, 0xF0}, {ATTR_KHAKI, 0xF0, 0xE6, 0x8C}, + {ATTR_LINEN, 0xFA, 0xF0, 0xE6}, {ATTR_OLIVE, 0x80, 0x80, 0x00}, {ATTR_WHEAT, 0xF5, 0xDE, 0xB3}, + {ATTR_WHITE, 0xFF, 0xFF, 0xFF}, {ATTR_BISQUE, 0xFF, 0xE4, 0xC4}, {ATTR_INDIGO, 0x4B, 0x00, 0x82}, + {ATTR_MAROON, 0x80, 0x00, 0x00}, {ATTR_ORANGE, 0xFF, 0xA5, 0x00}, {ATTR_ORCHID, 0xDA, 0x70, 0xD6}, + {ATTR_PURPLE, 0x80, 0x00, 0x80}, {ATTR_SALMON, 0xFA, 0x80, 0x72}, {ATTR_SIENNA, 0xA0, 0x52, 0x2D}, + {ATTR_SILVER, 0xC0, 0xC0, 0xC0}, {ATTR_TOMATO, 0xFF, 0x63, 0x47}, {ATTR_VIOLET, 0xEE, 0x82, 0xEE}, + {ATTR_YELLOW, 0xFF, 0xFF, 0x00}, {ATTR_FUCHSIA, 0xFF, 0x00, 0xFF}, {ATTR_MAGENTA, 0xFF, 0x00, 0xFF}, +}; + +#endif \ No newline at end of file diff --git a/src/hasp/hasp_utilities.cpp b/src/hasp/hasp_utilities.cpp index 75ab5cd8..1787c2a2 100644 --- a/src/hasp/hasp_utilities.cpp +++ b/src/hasp/hasp_utilities.cpp @@ -1,11 +1,16 @@ #include +#include +#ifdef ARDUINO #include "Arduino.h" +#endif + +#include "hasp_conf.h" #include "hasp_utilities.h" /* 16-bit hashing function http://www.cse.yorku.ca/~oz/hash.html */ /* all possible attributes are hashed and checked if they are unique */ -uint16_t hasp_util_get_sdbm(const char * str) +uint16_t Utilities::get_sdbm(const char* str) { uint16_t hash = 0; char c; @@ -18,13 +23,13 @@ uint16_t hasp_util_get_sdbm(const char * str) return hash; } -bool hasp_util_is_true(const char * s) +bool Utilities::is_true(const char* s) { return (!strcasecmp_P(s, PSTR("true")) || !strcasecmp_P(s, PSTR("on")) || !strcasecmp_P(s, PSTR("yes")) || !strcmp_P(s, PSTR("1"))); } -bool hasp_util_is_only_digits(const char * s) +bool Utilities::is_only_digits(const char* s) { size_t digits = 0; while(*(s + digits) != '\0' && isdigit(*(s + digits))) { @@ -33,7 +38,7 @@ bool hasp_util_is_only_digits(const char * s) return strlen(s) == digits; } -int hasp_util_format_bytes(size_t filesize, char * buf, size_t len) +int Utilities::format_bytes(size_t filesize, char* buf, size_t len) { if(filesize < 1024) return snprintf_P(buf, len, PSTR("%d B"), filesize); @@ -47,4 +52,11 @@ int hasp_util_format_bytes(size_t filesize, char * buf, size_t len) } return snprintf_P(buf, len, PSTR("%d.%d %ciB"), filesize / 10, filesize % 10, labels[unit]); -} \ No newline at end of file +} + +#ifndef ARDUINO +long map(long x, long in_min, long in_max, long out_min, long out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} +#endif \ No newline at end of file diff --git a/src/hasp/hasp_utilities.h b/src/hasp/hasp_utilities.h index eb164cd5..a94a6f80 100644 --- a/src/hasp/hasp_utilities.h +++ b/src/hasp/hasp_utilities.h @@ -1,12 +1,22 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_UTILITIES_H #define HASP_UTILITIES_H -uint16_t hasp_util_get_sdbm(const char * str); -bool hasp_util_is_true(const char * s); -bool hasp_util_is_only_digits(const char * s); -int hasp_util_format_bytes(size_t filesize, char * buf, size_t len); +#include + +class Utilities { + + public: + static uint16_t get_sdbm(const char* str); + static bool is_true(const char* s); + static bool is_only_digits(const char* s); + static int format_bytes(size_t filesize, char* buf, size_t len); +}; + +#ifndef ARDUINO +long map(long x, long in_min, long in_max, long out_min, long out_max); +#endif #endif \ No newline at end of file diff --git a/src/hasp/lv_theme_hasp.c b/src/hasp/lv_theme_hasp.c index 5a736abe..cedb3444 100644 --- a/src/hasp/lv_theme_hasp.c +++ b/src/hasp/lv_theme_hasp.c @@ -15,13 +15,15 @@ #include "src/lv_misc/lv_gc.h" #if defined(LV_GC_INCLUDE) - #include LV_GC_INCLUDE +#include LV_GC_INCLUDE #endif /* LV_ENABLE_GC */ /********************* * DEFINES *********************/ +#define HASP_DPX(n) hasp_dpx(n) + /*SCREEN*/ #define COLOR_SCR (IS_LIGHT ? LV_COLOR_WHITE : lv_color_hex(0x545b6a)) @@ -60,10 +62,10 @@ #define COLOR_BG_BORDER_CHK_PR (IS_LIGHT ? lv_color_hex(0x3b3e42) : lv_color_hex(0x5f656e)) #define COLOR_BG_BORDER_DIS (IS_LIGHT ? lv_color_hex(0xd6dde3) : lv_color_hex(0x5f656e)) -#define COLOR_BG_TEXT (IS_LIGHT ? lv_color_hex(0xeeeeee) : lv_color_hex(0xeeeeee)) -#define COLOR_BG_TEXT_PR (IS_LIGHT ? lv_color_hex(0xffffff) : lv_color_hex(0xffffff)) -#define COLOR_BG_TEXT_CHK (IS_LIGHT ? lv_color_hex(0xffffff) : lv_color_hex(0xffffff)) -#define COLOR_BG_TEXT_CHK_PR (IS_LIGHT ? lv_color_hex(0xffffff) : lv_color_hex(0xffffff)) +#define COLOR_BG_TEXT lv_color_hex(0xeeeeee) +#define COLOR_BG_TEXT_PR LV_COLOR_WHITE +#define COLOR_BG_TEXT_CHK LV_COLOR_WHITE +#define COLOR_BG_TEXT_CHK_PR LV_COLOR_WHITE #define COLOR_BG_TEXT_DIS (IS_LIGHT ? lv_color_hex3(0xaaa) : lv_color_hex3(0x999)) /*SECONDARY BACKGROUND*/ @@ -74,15 +76,15 @@ #define COLOR_BG_SEC_TEXT_DIS (IS_LIGHT ? lv_color_hex(0xaaaaaa) : lv_color_hex(0xa5a8ad)) #define TRANSITION_TIME 0 /*((theme.flags & LV_THEME_HASP_FLAG_NO_TRANSITION) ? 0 : 150)*/ -#define BORDER_WIDTH LV_DPX(2) +#define BORDER_WIDTH HASP_DPX(2) #define BORDER_COLOR ((theme.flags & IS_LIGHT) ? lv_color_make(0x40, 0x40, 0x40) : lv_color_make(0xb0, 0xb0, 0xb0)) -#define OUTLINE_WIDTH ((theme.flags & LV_THEME_HASP_FLAG_NO_FOCUS) ? 0 : LV_DPX(3)) +#define OUTLINE_WIDTH ((theme.flags & LV_THEME_HASP_FLAG_NO_FOCUS) ? 0 : HASP_DPX(3)) #define OUTLINE_COLOR ((theme.flags & LV_THEME_HASP_FLAG_NO_FOCUS) ? BORDER_COLOR : theme.color_secondary) #define IS_LIGHT (theme.flags & LV_THEME_HASP_FLAG_LIGHT) #define NO_FOCUS (theme.flags & LV_THEME_HASP_FLAG_NO_FOCUS) -#define PAD_DEF (lv_disp_get_size_category(NULL) <= LV_DISP_SIZE_MEDIUM ? LV_DPX(15) : (LV_DPX(30))) +#define PAD_DEF (lv_disp_get_size_category(NULL) <= LV_DISP_SIZE_MEDIUM ? HASP_DPX(15) : (HASP_DPX(30))) /*SCROLLBAR*/ #define SCROLLBAR_COLOR \ @@ -162,9 +164,9 @@ typedef struct #if LV_USE_PAGE lv_style_t sb; - #if LV_USE_ANIMATION +#if LV_USE_ANIMATION lv_style_t edge_flash; - #endif +#endif #endif #if LV_USE_SLIDER @@ -196,14 +198,14 @@ typedef struct /********************** * STATIC PROTOTYPES **********************/ -static void theme_apply(lv_theme_t * th, lv_obj_t * obj, lv_theme_style_t name); -static void style_init_reset(lv_style_t * style); +static void theme_apply(lv_theme_t* th, lv_obj_t* obj, lv_theme_style_t name); +static void style_init_reset(lv_style_t* style); /********************** * STATIC VARIABLES **********************/ static lv_theme_t theme; -static theme_styles_t * styles; +static theme_styles_t* styles; static bool inited; @@ -215,18 +217,25 @@ static bool inited; * STATIC FUNCTIONS **********************/ -static void basic_init(void) +static lv_style_int_t hasp_dpx(lv_style_int_t n) { + return (n == 0 ? 0 : LV_MATH_MAX(((LV_DPI * (n) + 80) / 160), 1)); /*+80 for rounding*/ +} + +static void basic_init(lv_style_int_t border_width, lv_style_int_t outline_width, lv_color_t value_color, + lv_color_t color_scr_text) +{ + sizeof(lv_style_t); // Objects with transparent background, like Checkbox, container style_init_reset(&styles->transparent); lv_style_set_bg_opa(&styles->transparent, LV_STATE_DEFAULT, LV_OPA_TRANSP); lv_style_set_border_opa(&styles->transparent, LV_STATE_DEFAULT, LV_OPA_TRANSP); lv_style_set_outline_opa(&styles->transparent, LV_STATE_DEFAULT, LV_OPA_TRANSP); - lv_style_set_value_color(&styles->transparent, LV_STATE_DEFAULT, COLOR_SCR_TEXT); + lv_style_set_value_color(&styles->transparent, LV_STATE_DEFAULT, color_scr_text); lv_style_set_value_font(&styles->transparent, LV_STATE_DEFAULT, theme.font_subtitle); - if(!NO_FOCUS) lv_style_set_outline_width(&styles->transparent, LV_STATE_DEFAULT, OUTLINE_WIDTH); + if(!NO_FOCUS) lv_style_set_outline_width(&styles->transparent, LV_STATE_DEFAULT, outline_width); // Background gradient style_init_reset(&styles->pretty); @@ -244,22 +253,22 @@ static void basic_init(void) lv_style_set_scale_end_line_width(&styles->pretty, LV_STATE_DEFAULT, 1); lv_style_set_scale_end_color(&styles->pretty, LV_STATE_DEFAULT, theme.color_primary); - lv_style_set_text_color(&styles->pretty, LV_STATE_DEFAULT, COLOR_SCR_TEXT); - //lv_style_set_text_font(&styles->pretty, LV_STATE_DEFAULT, theme.font_normal); + lv_style_set_text_color(&styles->pretty, LV_STATE_DEFAULT, color_scr_text); + // lv_style_set_text_font(&styles->pretty, LV_STATE_DEFAULT, theme.font_normal); - lv_style_set_value_color(&styles->pretty, LV_STATE_DEFAULT, COLOR_SCR_TEXT); + lv_style_set_value_color(&styles->pretty, LV_STATE_DEFAULT, color_scr_text); lv_style_set_value_font(&styles->pretty, LV_STATE_DEFAULT, theme.font_subtitle); lv_style_set_border_opa(&styles->pretty, LV_STATE_DEFAULT, LV_OPA_30); - lv_style_set_border_width(&styles->pretty, LV_STATE_DEFAULT, BORDER_WIDTH); + lv_style_set_border_width(&styles->pretty, LV_STATE_DEFAULT, border_width); lv_style_set_border_color(&styles->pretty, LV_STATE_DEFAULT, BORDER_COLOR); lv_style_set_border_color(&styles->pretty, LV_STATE_EDITED, lv_color_darken(theme.color_secondary, LV_OPA_30)); - lv_style_set_outline_width(&styles->pretty, LV_STATE_DEFAULT, OUTLINE_WIDTH); + lv_style_set_outline_width(&styles->pretty, LV_STATE_DEFAULT, outline_width); if(!NO_FOCUS) { lv_style_set_border_color(&styles->pretty, LV_STATE_FOCUSED, theme.color_secondary); - lv_style_set_border_width(&styles->pretty, LV_STATE_FOCUSED, OUTLINE_WIDTH); + lv_style_set_border_width(&styles->pretty, LV_STATE_FOCUSED, outline_width); } // Primary Colored gradient @@ -273,23 +282,23 @@ static void basic_init(void) lv_style_set_line_width(&styles->pretty_color, LV_STATE_DEFAULT, 1); lv_style_set_scale_end_line_width(&styles->pretty_color, LV_STATE_DEFAULT, 1); lv_style_set_scale_end_color(&styles->pretty_color, LV_STATE_DEFAULT, theme.color_primary); - lv_style_set_text_color(&styles->pretty_color, LV_STATE_DEFAULT, COLOR_SCR_TEXT); + lv_style_set_text_color(&styles->pretty_color, LV_STATE_DEFAULT, color_scr_text); lv_style_set_line_color(&styles->pretty_color, LV_STATE_DEFAULT, lv_color_make(0x20, 0x20, 0x20)); - //lv_style_set_text_font(&styles->pretty_color, LV_STATE_DEFAULT, theme.font_normal); + // lv_style_set_text_font(&styles->pretty_color, LV_STATE_DEFAULT, theme.font_normal); lv_style_set_value_font(&styles->pretty_color, LV_STATE_DEFAULT, theme.font_subtitle); - lv_style_set_value_color(&styles->pretty_color, LV_STATE_DEFAULT, COLOR_SCR_TEXT); + lv_style_set_value_color(&styles->pretty_color, LV_STATE_DEFAULT, color_scr_text); lv_style_set_border_opa(&styles->pretty_color, LV_STATE_DEFAULT, LV_OPA_50); - lv_style_set_border_width(&styles->pretty_color, LV_STATE_DEFAULT, BORDER_WIDTH); + lv_style_set_border_width(&styles->pretty_color, LV_STATE_DEFAULT, border_width); lv_style_set_border_color(&styles->pretty_color, LV_STATE_DEFAULT, BORDER_COLOR); lv_style_set_border_color(&styles->pretty_color, LV_STATE_EDITED, lv_color_darken(theme.color_secondary, LV_OPA_30)); - lv_style_set_outline_width(&styles->pretty_color, LV_STATE_DEFAULT, OUTLINE_WIDTH); + lv_style_set_outline_width(&styles->pretty_color, LV_STATE_DEFAULT, outline_width); if(!NO_FOCUS) { lv_style_set_border_color(&styles->pretty_color, LV_STATE_FOCUSED, theme.color_secondary); - lv_style_set_border_width(&styles->pretty_color, LV_STATE_FOCUSED, OUTLINE_WIDTH); + lv_style_set_border_width(&styles->pretty_color, LV_STATE_FOCUSED, outline_width); } /* style_init_reset(&styles->bg_sec); @@ -353,7 +362,7 @@ static void basic_init(void) lv_style_set_border_color(&styles->btn, LV_STATE_DEFAULT, COLOR_BTN_BORDER); lv_style_set_border_color(&styles->btn, LV_STATE_CHECKED, COLOR_BTN_BORDER_CHK); lv_style_set_border_color(&styles->btn, LV_STATE_DISABLED, COLOR_BTN_BORDER_INA); - lv_style_set_border_width(&styles->btn, LV_STATE_DEFAULT, BORDER_WIDTH); + lv_style_set_border_width(&styles->btn, LV_STATE_DEFAULT, border_width); lv_style_set_border_opa(&styles->btn, LV_STATE_DEFAULT, LV_OPA_50); // lv_style_set_border_opa(&styles->btn, LV_STATE_CHECKED, LV_OPA_40); @@ -363,31 +372,25 @@ static void basic_init(void) lv_style_set_text_color(&styles->btn, LV_STATE_CHECKED | LV_STATE_PRESSED, COLOR_BG_TEXT_CHK_PR); lv_style_set_text_color(&styles->btn, LV_STATE_DISABLED, COLOR_BG_TEXT_DIS); - lv_style_set_image_recolor(&styles->btn, LV_STATE_DEFAULT, - IS_LIGHT ? lv_color_hex(0x31404f) : lv_color_hex(0xffffff)); - lv_style_set_image_recolor(&styles->btn, LV_STATE_PRESSED, - IS_LIGHT ? lv_color_hex(0x31404f) : lv_color_hex(0xffffff)); - lv_style_set_image_recolor(&styles->btn, LV_STATE_PRESSED, lv_color_hex(0xffffff)); - lv_style_set_image_recolor(&styles->btn, LV_STATE_CHECKED | LV_STATE_PRESSED, lv_color_hex(0xffffff)); + lv_style_set_image_recolor(&styles->btn, LV_STATE_DEFAULT, value_color); + lv_style_set_image_recolor(&styles->btn, LV_STATE_PRESSED, value_color); + lv_style_set_image_recolor(&styles->btn, LV_STATE_PRESSED, LV_COLOR_WHITE); + lv_style_set_image_recolor(&styles->btn, LV_STATE_CHECKED | LV_STATE_PRESSED, LV_COLOR_WHITE); lv_style_set_image_recolor(&styles->btn, LV_STATE_DISABLED, IS_LIGHT ? lv_color_hex(0x888888) : lv_color_hex(0x888888)); - lv_style_set_value_color(&styles->btn, LV_STATE_DEFAULT, - IS_LIGHT ? lv_color_hex(0x31404f) : lv_color_hex(0xffffff)); - lv_style_set_value_color(&styles->btn, LV_STATE_PRESSED, - IS_LIGHT ? lv_color_hex(0x31404f) : lv_color_hex(0xffffff)); - lv_style_set_value_color(&styles->btn, LV_STATE_CHECKED, lv_color_hex(0xffffff)); - lv_style_set_value_color(&styles->btn, LV_STATE_CHECKED | LV_STATE_PRESSED, lv_color_hex(0xffffff)); + lv_style_set_value_color(&styles->btn, LV_STATE_DEFAULT, value_color); + lv_style_set_value_color(&styles->btn, LV_STATE_PRESSED, value_color); + lv_style_set_value_color(&styles->btn, LV_STATE_CHECKED, LV_COLOR_WHITE); + lv_style_set_value_color(&styles->btn, LV_STATE_CHECKED | LV_STATE_PRESSED, LV_COLOR_WHITE); lv_style_set_value_color(&styles->btn, LV_STATE_DISABLED, IS_LIGHT ? lv_color_hex(0x888888) : lv_color_hex(0x888888)); - lv_style_set_pad_left(&styles->btn, LV_STATE_DEFAULT, LV_DPX(40)); - lv_style_set_pad_right(&styles->btn, LV_STATE_DEFAULT, LV_DPX(40)); - lv_style_set_pad_top(&styles->btn, LV_STATE_DEFAULT, LV_DPX(15)); - lv_style_set_pad_bottom(&styles->btn, LV_STATE_DEFAULT, LV_DPX(15)); - lv_style_set_pad_inner(&styles->btn, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_hor(&styles->btn, LV_STATE_DEFAULT, HASP_DPX(40)); + lv_style_set_pad_ver(&styles->btn, LV_STATE_DEFAULT, HASP_DPX(15)); + lv_style_set_pad_inner(&styles->btn, LV_STATE_DEFAULT, HASP_DPX(20)); - lv_style_set_outline_width(&styles->btn, LV_STATE_DEFAULT, OUTLINE_WIDTH); + lv_style_set_outline_width(&styles->btn, LV_STATE_DEFAULT, outline_width); if(!NO_FOCUS) { lv_style_set_outline_opa(&styles->btn, LV_STATE_DEFAULT, LV_OPA_0); lv_style_set_outline_opa(&styles->btn, LV_STATE_FOCUSED, LV_OPA_50); @@ -404,22 +407,22 @@ static void basic_init(void) style_init_reset(&styles->pad_inner); lv_style_set_pad_inner(&styles->pad_inner, LV_STATE_DEFAULT, - lv_disp_get_size_category(NULL) <= LV_DISP_MEDIUM_LIMIT ? LV_DPX(20) : LV_DPX(40)); + lv_disp_get_size_category(NULL) <= LV_DISP_MEDIUM_LIMIT ? HASP_DPX(20) : HASP_DPX(40)); style_init_reset(&styles->pad_small); - lv_style_int_t pad_small_value = lv_disp_get_size_category(NULL) <= LV_DISP_MEDIUM_LIMIT ? LV_DPX(10) : LV_DPX(20); + lv_style_int_t pad_small_value = + lv_disp_get_size_category(NULL) <= LV_DISP_MEDIUM_LIMIT ? HASP_DPX(10) : HASP_DPX(20); lv_style_set_pad_all(&styles->pad_small, LV_STATE_DEFAULT, pad_small_value); lv_style_set_pad_inner(&styles->pad_small, LV_STATE_DEFAULT, pad_small_value); #if LV_USE_DROPDOWN || LV_USE_ROLLER style_init_reset(&styles->line_space); - lv_style_set_text_line_space(&styles->line_space, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_text_line_space(&styles->line_space, LV_STATE_DEFAULT, HASP_DPX(20)); lv_style_set_clip_corner(&styles->line_space, LV_STATE_DEFAULT, true); style_init_reset(&styles->selected); lv_style_set_radius(&styles->selected, LV_STATE_DEFAULT, 0); - lv_style_set_text_color(&styles->selected, LV_STATE_DEFAULT, - IS_LIGHT ? lv_color_hex3(0xfff) : lv_color_hex3(0xfff)); + lv_style_set_text_color(&styles->selected, LV_STATE_DEFAULT, IS_LIGHT ? LV_COLOR_WHITE : LV_COLOR_WHITE); lv_style_set_bg_color(&styles->selected, LV_STATE_PRESSED, COLOR_BG_PR); lv_style_set_text_color(&styles->selected, LV_STATE_PRESSED, COLOR_BG_TEXT_PR); #endif @@ -453,11 +456,11 @@ static void bar_init(void) lv_style_set_radius(&styles->bar_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); lv_style_set_bg_opa(&styles->bar_bg, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&styles->bar_bg, LV_STATE_DEFAULT, COLOR_BG_SEC); - lv_style_set_value_color(&styles->bar_bg, LV_STATE_DEFAULT, IS_LIGHT ? lv_color_hex(0x31404f) : LV_COLOR_WHITE); + lv_style_set_value_color(&styles->bar_bg, LV_STATE_DEFAULT, value_color); lv_style_set_outline_color(&styles->bar_bg, LV_STATE_DEFAULT, theme.color_primary); lv_style_set_outline_color(&styles->bar_bg, LV_STATE_EDITED, theme.color_secondary); lv_style_set_outline_opa(&styles->bar_bg, LV_STATE_DEFAULT, LV_OPA_TRANSP); - lv_style_set_outline_width(&styles->bar_bg, LV_STATE_DEFAULT, OUTLINE_WIDTH); + lv_style_set_outline_width(&styles->bar_bg, LV_STATE_DEFAULT, outline_width); lv_style_set_transition_time(&styles->bar_bg, LV_STATE_DEFAULT, TRANSITION_TIME); lv_style_set_transition_prop_6(&styles->bar_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA); @@ -495,10 +498,10 @@ static void led_init(void) lv_style_set_border_opa(&styles->led, LV_STATE_DEFAULT, LV_OPA_50); lv_style_set_border_color(&styles->led, LV_STATE_DEFAULT, lv_color_lighten(theme.color_primary, LV_OPA_30)); lv_style_set_radius(&styles->led, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_shadow_width(&styles->led, LV_STATE_DEFAULT, LV_DPX(15)); + lv_style_set_shadow_width(&styles->led, LV_STATE_DEFAULT, HASP_DPX(15)); lv_style_set_shadow_color(&styles->led, LV_STATE_DEFAULT, theme.color_primary); - lv_style_set_shadow_spread(&styles->led, LV_STATE_DEFAULT, LV_DPX(5)); - lv_style_set_margin_all(&styles->led, LV_STATE_DEFAULT, LV_DPX(5)); + lv_style_set_shadow_spread(&styles->led, LV_STATE_DEFAULT, HASP_DPX(5)); + lv_style_set_margin_all(&styles->led, LV_STATE_DEFAULT, HASP_DPX(5)); #endif } @@ -509,18 +512,12 @@ static void slider_init(void) // lv_style_set_bg_opa(&styles->slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER); // lv_style_set_bg_color(&styles->slider_knob, LV_STATE_DEFAULT, IS_LIGHT ? theme.color_primary : LV_COLOR_WHITE); // lv_style_set_value_color(&styles->slider_knob, LV_STATE_DEFAULT, - // IS_LIGHT ? lv_color_hex(0x31404f) : LV_COLOR_WHITE); + // value_color); // lv_style_set_radius(&styles->slider_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_pad_left(&styles->slider_knob, LV_STATE_DEFAULT, LV_DPX(7)); - lv_style_set_pad_right(&styles->slider_knob, LV_STATE_DEFAULT, LV_DPX(7)); - lv_style_set_pad_top(&styles->slider_knob, LV_STATE_DEFAULT, LV_DPX(7)); - lv_style_set_pad_bottom(&styles->slider_knob, LV_STATE_DEFAULT, LV_DPX(7)); + lv_style_set_pad_all(&styles->slider_knob, LV_STATE_DEFAULT, HASP_DPX(7)); style_init_reset(&styles->slider_bg); - lv_style_set_margin_left(&styles->slider_bg, LV_STATE_DEFAULT, LV_DPX(10)); - lv_style_set_margin_right(&styles->slider_bg, LV_STATE_DEFAULT, LV_DPX(10)); - lv_style_set_margin_top(&styles->slider_bg, LV_STATE_DEFAULT, LV_DPX(10)); - lv_style_set_margin_bottom(&styles->slider_bg, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_margin_all(&styles->slider_bg, LV_STATE_DEFAULT, HASP_DPX(10)); #endif } @@ -532,10 +529,7 @@ static void switch_init(void) // lv_style_set_bg_opa(&styles->sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER); // lv_style_set_bg_color(&styles->sw_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE); // lv_style_set_radius(&styles->sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_pad_top(&styles->sw_knob, LV_STATE_DEFAULT, LV_DPX(2)); - lv_style_set_pad_bottom(&styles->sw_knob, LV_STATE_DEFAULT, LV_DPX(2)); - lv_style_set_pad_left(&styles->sw_knob, LV_STATE_DEFAULT, LV_DPX(2)); - lv_style_set_pad_right(&styles->sw_knob, LV_STATE_DEFAULT, LV_DPX(2)); + lv_style_set_pad_all(&styles->sw_knob, LV_STATE_DEFAULT, HASP_DPX(2)); #endif } @@ -544,17 +538,16 @@ static void linemeter_init(void) #if LV_USE_LINEMETER != 0 style_init_reset(&styles->lmeter); lv_style_set_radius(&styles->lmeter, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_pad_left(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_right(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_top(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_inner(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(30)); - lv_style_set_scale_width(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(25)); + lv_style_set_pad_hor(&styles->lmeter, LV_STATE_DEFAULT, HASP_DPX(20)); + lv_style_set_pad_top(&styles->lmeter, LV_STATE_DEFAULT, HASP_DPX(20)); + lv_style_set_pad_inner(&styles->lmeter, LV_STATE_DEFAULT, HASP_DPX(30)); + lv_style_set_scale_width(&styles->lmeter, LV_STATE_DEFAULT, HASP_DPX(25)); lv_style_set_line_color(&styles->lmeter, LV_STATE_DEFAULT, theme.color_primary); lv_style_set_scale_grad_color(&styles->lmeter, LV_STATE_DEFAULT, theme.color_primary); lv_style_set_scale_end_color(&styles->lmeter, LV_STATE_DEFAULT, lv_color_hex3(0x888)); - lv_style_set_line_width(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(10)); - lv_style_set_scale_end_line_width(&styles->lmeter, LV_STATE_DEFAULT, LV_DPX(7)); + lv_style_set_line_width(&styles->lmeter, LV_STATE_DEFAULT, HASP_DPX(10)); + lv_style_set_scale_end_line_width(&styles->lmeter, LV_STATE_DEFAULT, HASP_DPX(7)); #endif } @@ -565,34 +558,33 @@ static void gauge_init(void) lv_style_set_line_color(&styles->gauge_main, LV_STATE_DEFAULT, lv_color_hex3(0x888)); lv_style_set_scale_grad_color(&styles->gauge_main, LV_STATE_DEFAULT, lv_color_hex3(0x888)); lv_style_set_scale_end_color(&styles->gauge_main, LV_STATE_DEFAULT, theme.color_primary); - lv_style_set_line_width(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(2)); // normal scale minor thick width + lv_style_set_line_width(&styles->gauge_main, LV_STATE_DEFAULT, HASP_DPX(2)); // normal scale minor thick width lv_style_set_scale_end_line_width(&styles->gauge_main, LV_STATE_DEFAULT, - LV_DPX(2)); // strong scale minor tick width - lv_style_set_scale_end_border_width(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(3)); - lv_style_set_pad_left(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(20)); // left margin - lv_style_set_pad_right(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(20)); // right margin - lv_style_set_pad_top(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(20)); // top margin - lv_style_set_pad_inner(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(15)); // position of the labels - lv_style_set_scale_width(&styles->gauge_main, LV_STATE_DEFAULT, LV_DPX(10)); // minor thick length + HASP_DPX(2)); // strong scale minor tick width + lv_style_set_scale_end_border_width(&styles->gauge_main, LV_STATE_DEFAULT, HASP_DPX(3)); + lv_style_set_pad_hor(&styles->gauge_main, LV_STATE_DEFAULT, HASP_DPX(20)); // left margin + lv_style_set_pad_top(&styles->gauge_main, LV_STATE_DEFAULT, HASP_DPX(20)); // top margin + lv_style_set_pad_inner(&styles->gauge_main, LV_STATE_DEFAULT, HASP_DPX(15)); // position of the labels + lv_style_set_scale_width(&styles->gauge_main, LV_STATE_DEFAULT, HASP_DPX(10)); // minor thick length lv_style_set_radius(&styles->gauge_main, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); style_init_reset(&styles->gauge_strong); lv_style_set_line_color(&styles->gauge_strong, LV_STATE_DEFAULT, lv_color_hex3(0x888)); lv_style_set_scale_grad_color(&styles->gauge_strong, LV_STATE_DEFAULT, lv_color_hex3(0x888)); lv_style_set_scale_end_color(&styles->gauge_strong, LV_STATE_DEFAULT, theme.color_primary); - lv_style_set_line_width(&styles->gauge_strong, LV_STATE_DEFAULT, LV_DPX(8)); // strong scale arc width - lv_style_set_scale_end_line_width(&styles->gauge_strong, LV_STATE_DEFAULT, LV_DPX(8)); - lv_style_set_scale_width(&styles->gauge_strong, LV_STATE_DEFAULT, LV_DPX(20)); // major thick length + lv_style_set_line_width(&styles->gauge_strong, LV_STATE_DEFAULT, HASP_DPX(8)); // strong scale arc width + lv_style_set_scale_end_line_width(&styles->gauge_strong, LV_STATE_DEFAULT, HASP_DPX(8)); + lv_style_set_scale_width(&styles->gauge_strong, LV_STATE_DEFAULT, HASP_DPX(20)); // major thick length style_init_reset(&styles->gauge_needle); lv_style_set_line_color(&styles->gauge_needle, LV_STATE_DEFAULT, IS_LIGHT ? lv_color_hex(0x464b5b) : LV_COLOR_WHITE); - lv_style_set_line_width(&styles->gauge_needle, LV_STATE_DEFAULT, LV_DPX(8)); + lv_style_set_line_width(&styles->gauge_needle, LV_STATE_DEFAULT, HASP_DPX(8)); lv_style_set_bg_opa(&styles->gauge_needle, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&styles->gauge_needle, LV_STATE_DEFAULT, IS_LIGHT ? lv_color_hex(0x464b5b) : LV_COLOR_WHITE); lv_style_set_radius(&styles->gauge_needle, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_size(&styles->gauge_needle, LV_STATE_DEFAULT, LV_DPX(30)); - lv_style_set_pad_inner(&styles->gauge_needle, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_size(&styles->gauge_needle, LV_STATE_DEFAULT, HASP_DPX(30)); + lv_style_set_pad_inner(&styles->gauge_needle, LV_STATE_DEFAULT, HASP_DPX(10)); #endif } @@ -601,15 +593,15 @@ static void arc_init(void) #if LV_USE_ARC != 0 style_init_reset(&styles->arc_indic); lv_style_set_line_color(&styles->arc_indic, LV_STATE_DEFAULT, theme.color_primary); - lv_style_set_line_width(&styles->arc_indic, LV_STATE_DEFAULT, LV_DPX(25)); + lv_style_set_line_width(&styles->arc_indic, LV_STATE_DEFAULT, HASP_DPX(25)); lv_style_set_line_rounded(&styles->arc_indic, LV_STATE_DEFAULT, true); style_init_reset(&styles->arc_bg); lv_style_set_line_color(&styles->arc_bg, LV_STATE_DEFAULT, lv_color_mix(BORDER_COLOR, COLOR_SCR_GRAD, 128)); - lv_style_set_line_width(&styles->arc_bg, LV_STATE_DEFAULT, LV_DPX(25)); + lv_style_set_line_width(&styles->arc_bg, LV_STATE_DEFAULT, HASP_DPX(25)); lv_style_set_line_rounded(&styles->arc_bg, LV_STATE_DEFAULT, true); lv_style_set_radius(&styles->arc_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_border_width(&styles->arc_bg, LV_STATE_DEFAULT, LV_DPX(25)); + lv_style_set_border_width(&styles->arc_bg, LV_STATE_DEFAULT, HASP_DPX(25)); /* lv_style_set_border_opa(&styles->pretty_color, LV_STATE_DEFAULT, LV_OPA_TRANSP); lv_style_set_border_opa(&styles->pretty_color, LV_STATE_FOCUSED, LV_OPA_30); @@ -619,10 +611,7 @@ static void arc_init(void) */ style_init_reset(&styles->arc_knob); lv_style_set_radius(&styles->arc_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_pad_top(&styles->arc_knob, LV_STATE_DEFAULT, LV_DPX(0)); - lv_style_set_pad_bottom(&styles->arc_knob, LV_STATE_DEFAULT, LV_DPX(0)); - lv_style_set_pad_left(&styles->arc_knob, LV_STATE_DEFAULT, LV_DPX(0)); - lv_style_set_pad_right(&styles->arc_knob, LV_STATE_DEFAULT, LV_DPX(0)); + lv_style_set_pad_all(&styles->arc_knob, LV_STATE_DEFAULT, HASP_DPX(0)); #endif } @@ -640,27 +629,26 @@ static void chart_init(void) lv_style_set_text_color(&styles->chart_bg, LV_STATE_DEFAULT, IS_LIGHT ? COLOR_BG_TEXT_DIS : lv_color_hex(0xa1adbd)); style_init_reset(&styles->chart_series_bg); - lv_style_set_line_width(&styles->chart_series_bg, LV_STATE_DEFAULT, LV_DPX(1)); - lv_style_set_line_dash_width(&styles->chart_series_bg, LV_STATE_DEFAULT, LV_DPX(10)); - lv_style_set_line_dash_gap(&styles->chart_series_bg, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_line_width(&styles->chart_series_bg, LV_STATE_DEFAULT, HASP_DPX(1)); + lv_style_set_line_dash_width(&styles->chart_series_bg, LV_STATE_DEFAULT, HASP_DPX(10)); + lv_style_set_line_dash_gap(&styles->chart_series_bg, LV_STATE_DEFAULT, HASP_DPX(10)); lv_style_set_line_color(&styles->chart_series_bg, LV_STATE_DEFAULT, COLOR_BG_BORDER); style_init_reset(&styles->chart_series); - lv_style_set_line_width(&styles->chart_series, LV_STATE_DEFAULT, LV_DPX(3)); - lv_style_set_size(&styles->chart_series, LV_STATE_DEFAULT, LV_DPX(4)); - lv_style_set_pad_inner(&styles->chart_series, LV_STATE_DEFAULT, LV_DPX(2)); /*Space between columns*/ - lv_style_set_radius(&styles->chart_series, LV_STATE_DEFAULT, LV_DPX(1)); + lv_style_set_line_width(&styles->chart_series, LV_STATE_DEFAULT, HASP_DPX(3)); + lv_style_set_size(&styles->chart_series, LV_STATE_DEFAULT, HASP_DPX(4)); + lv_style_set_pad_inner(&styles->chart_series, LV_STATE_DEFAULT, HASP_DPX(2)); /*Space between columns*/ + lv_style_set_radius(&styles->chart_series, LV_STATE_DEFAULT, HASP_DPX(1)); #endif } -static void calendar_init(void) +static void calendar_init(lv_style_int_t pad_def, lv_color_t value_color) { #if LV_USE_CALENDAR style_init_reset(&styles->calendar_date_nums); - lv_style_set_radius(&styles->calendar_date_nums, LV_STATE_DEFAULT, LV_DPX(4)); - lv_style_set_text_color(&styles->calendar_date_nums, LV_STATE_CHECKED, - IS_LIGHT ? lv_color_hex(0x31404f) : LV_COLOR_WHITE); + lv_style_set_radius(&styles->calendar_date_nums, LV_STATE_DEFAULT, HASP_DPX(4)); + lv_style_set_text_color(&styles->calendar_date_nums, LV_STATE_CHECKED, value_color); lv_style_set_text_color(&styles->calendar_date_nums, LV_STATE_DISABLED, LV_COLOR_GRAY); lv_style_set_bg_opa(&styles->calendar_date_nums, LV_STATE_CHECKED, IS_LIGHT ? LV_OPA_20 : LV_OPA_40); lv_style_set_bg_opa(&styles->calendar_date_nums, LV_STATE_PRESSED, LV_OPA_20); @@ -673,10 +661,9 @@ static void calendar_init(void) lv_style_set_border_width(&styles->calendar_date_nums, LV_STATE_CHECKED, 2); lv_style_set_border_side(&styles->calendar_date_nums, LV_STATE_CHECKED, LV_BORDER_SIDE_LEFT); lv_style_set_border_color(&styles->calendar_date_nums, LV_STATE_CHECKED, theme.color_primary); - lv_style_set_pad_inner(&styles->calendar_date_nums, LV_STATE_DEFAULT, LV_DPX(3)); - lv_style_set_pad_left(&styles->calendar_date_nums, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_right(&styles->calendar_date_nums, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_bottom(&styles->calendar_date_nums, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_inner(&styles->calendar_date_nums, LV_STATE_DEFAULT, HASP_DPX(3)); + lv_style_set_pad_hor(&styles->calendar_date_nums, LV_STATE_DEFAULT, pad_def); + lv_style_set_pad_bottom(&styles->calendar_date_nums, LV_STATE_DEFAULT, pad_def); #endif } @@ -684,10 +671,10 @@ static void cpicker_init(void) { #if LV_USE_CPICKER style_init_reset(&styles->cpicker_bg); - lv_style_set_scale_width(&styles->cpicker_bg, LV_STATE_DEFAULT, LV_DPX(30)); + lv_style_set_scale_width(&styles->cpicker_bg, LV_STATE_DEFAULT, HASP_DPX(30)); lv_style_set_bg_opa(&styles->cpicker_bg, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&styles->cpicker_bg, LV_STATE_DEFAULT, COLOR_SCR); - lv_style_set_pad_inner(&styles->cpicker_bg, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_inner(&styles->cpicker_bg, LV_STATE_DEFAULT, HASP_DPX(20)); lv_style_set_radius(&styles->cpicker_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); style_init_reset(&styles->cpicker_indic); @@ -698,10 +685,7 @@ static void cpicker_init(void) lv_style_set_border_color(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_COLOR_GRAY); lv_style_set_border_color(&styles->cpicker_indic, LV_STATE_FOCUSED, theme.color_primary); lv_style_set_border_color(&styles->cpicker_indic, LV_STATE_EDITED, theme.color_secondary); - lv_style_set_pad_left(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_DPX(13)); - lv_style_set_pad_right(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_DPX(13)); - lv_style_set_pad_top(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_DPX(13)); - lv_style_set_pad_bottom(&styles->cpicker_indic, LV_STATE_DEFAULT, LV_DPX(13)); + lv_style_set_pad_all(&styles->cpicker_indic, LV_STATE_DEFAULT, HASP_DPX(13)); #endif } @@ -709,29 +693,26 @@ static void checkbox_init(void) { #if LV_USE_CHECKBOX != 0 /* style_init_reset(&styles->cb_bg); - lv_style_set_radius(&styles->cb_bg, LV_STATE_DEFAULT, LV_DPX(4)); - lv_style_set_pad_inner(&styles->cb_bg, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_radius(&styles->cb_bg, LV_STATE_DEFAULT, HASP_DPX(4)); + lv_style_set_pad_inner(&styles->cb_bg, LV_STATE_DEFAULT, HASP_DPX(10)); lv_style_set_outline_color(&styles->cb_bg, LV_STATE_DEFAULT, theme.color_primary); lv_style_set_outline_opa(&styles->cb_bg, LV_STATE_DEFAULT, LV_OPA_TRANSP); lv_style_set_outline_opa(&styles->cb_bg, LV_STATE_FOCUSED, LV_OPA_50); - lv_style_set_outline_width(&styles->cb_bg, LV_STATE_DEFAULT, OUTLINE_WIDTH); - lv_style_set_outline_pad(&styles->cb_bg, LV_STATE_DEFAULT, LV_DPX(10)); + lv_style_set_outline_width(&styles->cb_bg, LV_STATE_DEFAULT, outline_width); + lv_style_set_outline_pad(&styles->cb_bg, LV_STATE_DEFAULT, HASP_DPX(10)); lv_style_set_transition_time(&styles->cb_bg, LV_STATE_DEFAULT, TRANSITION_TIME); lv_style_set_transition_prop_6(&styles->cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA); */ style_init_reset(&styles->cb_bullet); lv_style_set_outline_opa(&styles->cb_bullet, LV_STATE_FOCUSED, LV_OPA_TRANSP); - lv_style_set_radius(&styles->cb_bullet, LV_STATE_DEFAULT, LV_DPX(4)); + lv_style_set_radius(&styles->cb_bullet, LV_STATE_DEFAULT, HASP_DPX(4)); lv_style_set_pattern_image(&styles->cb_bullet, LV_STATE_CHECKED, LV_SYMBOL_OK); lv_style_set_pattern_recolor(&styles->cb_bullet, LV_STATE_CHECKED, LV_COLOR_WHITE); lv_style_set_pattern_opa(&styles->cb_bullet, LV_STATE_DEFAULT, LV_OPA_TRANSP); lv_style_set_pattern_opa(&styles->cb_bullet, LV_STATE_CHECKED, LV_OPA_COVER); lv_style_set_transition_prop_3(&styles->cb_bullet, LV_STATE_DEFAULT, LV_STYLE_PATTERN_OPA); lv_style_set_text_font(&styles->cb_bullet, LV_STATE_CHECKED, theme.font_small); - lv_style_set_pad_left(&styles->cb_bullet, LV_STATE_DEFAULT, LV_DPX(3)); - lv_style_set_pad_right(&styles->cb_bullet, LV_STATE_DEFAULT, LV_DPX(3)); - lv_style_set_pad_top(&styles->cb_bullet, LV_STATE_DEFAULT, LV_DPX(3)); - lv_style_set_pad_bottom(&styles->cb_bullet, LV_STATE_DEFAULT, LV_DPX(3)); + lv_style_set_pad_all(&styles->cb_bullet, LV_STATE_DEFAULT, HASP_DPX(3)); lv_style_set_bg_color(&styles->cb_bullet, LV_STATE_PRESSED, COLOR_BTN_PR); lv_style_set_bg_grad_color(&styles->cb_bullet, LV_STATE_PRESSED, COLOR_BTN_CHK_GRAD); @@ -758,15 +739,12 @@ static void keyboard_init(void) #if LV_USE_KEYBOARD style_init_reset(&styles->kb_bg); lv_style_set_radius(&styles->kb_bg, LV_STATE_DEFAULT, 0); - lv_style_set_border_width(&styles->kb_bg, LV_STATE_DEFAULT, LV_DPX(4)); + lv_style_set_border_width(&styles->kb_bg, LV_STATE_DEFAULT, HASP_DPX(4)); lv_style_set_border_side(&styles->kb_bg, LV_STATE_DEFAULT, LV_BORDER_SIDE_TOP); lv_style_set_border_color(&styles->kb_bg, LV_STATE_DEFAULT, IS_LIGHT ? COLOR_BG_TEXT : LV_COLOR_BLACK); lv_style_set_border_color(&styles->kb_bg, LV_STATE_EDITED, theme.color_secondary); - lv_style_set_pad_left(&styles->kb_bg, LV_STATE_DEFAULT, LV_DPX(5)); - lv_style_set_pad_right(&styles->kb_bg, LV_STATE_DEFAULT, LV_DPX(5)); - lv_style_set_pad_top(&styles->kb_bg, LV_STATE_DEFAULT, LV_DPX(5)); - lv_style_set_pad_bottom(&styles->kb_bg, LV_STATE_DEFAULT, LV_DPX(5)); - lv_style_set_pad_inner(&styles->kb_bg, LV_STATE_DEFAULT, LV_DPX(3)); + lv_style_set_pad_all(&styles->kb_bg, LV_STATE_DEFAULT, HASP_DPX(5)); + lv_style_set_pad_inner(&styles->kb_bg, LV_STATE_DEFAULT, HASP_DPX(3)); #endif } @@ -774,38 +752,38 @@ static void msgbox_init(void) { #if LV_USE_MSGBOX style_init_reset(&styles->mbox_bg); - lv_style_set_shadow_width(&styles->mbox_bg, LV_STATE_DEFAULT, LV_DPX(50)); + lv_style_set_shadow_width(&styles->mbox_bg, LV_STATE_DEFAULT, HASP_DPX(50)); lv_style_set_shadow_color(&styles->mbox_bg, LV_STATE_DEFAULT, IS_LIGHT ? LV_COLOR_SILVER : lv_color_hex3(0x777)); #endif } -static void page_init(void) +static void page_init(lv_style_int_t dpx7) { #if LV_USE_PAGE style_init_reset(&styles->sb); lv_style_set_bg_opa(&styles->sb, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&styles->sb, LV_STATE_DEFAULT, SCROLLBAR_COLOR); lv_style_set_radius(&styles->sb, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_size(&styles->sb, LV_STATE_DEFAULT, LV_DPX(7)); - lv_style_set_pad_right(&styles->sb, LV_STATE_DEFAULT, LV_DPX(7)); - lv_style_set_pad_bottom(&styles->sb, LV_STATE_DEFAULT, LV_DPX(7)); + lv_style_set_size(&styles->sb, LV_STATE_DEFAULT, dpx7); + lv_style_set_pad_right(&styles->sb, LV_STATE_DEFAULT, dpx7); + lv_style_set_pad_bottom(&styles->sb, LV_STATE_DEFAULT, dpx7); - #if LV_USE_ANIMATION +#if LV_USE_ANIMATION style_init_reset(&styles->edge_flash); lv_style_set_bg_opa(&styles->edge_flash, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&styles->edge_flash, LV_STATE_DEFAULT, lv_color_hex3(0x888)); - #endif +#endif #endif } -static void textarea_init(void) +static void textarea_init(lv_style_int_t border_width) { #if LV_USE_TEXTAREA style_init_reset(&styles->ta_cursor); lv_style_set_border_color(&styles->ta_cursor, LV_STATE_DEFAULT, COLOR_BG_SEC_TEXT); - lv_style_set_border_width(&styles->ta_cursor, LV_STATE_DEFAULT, BORDER_WIDTH); - lv_style_set_pad_left(&styles->ta_cursor, LV_STATE_DEFAULT, LV_DPX(1)); + lv_style_set_border_width(&styles->ta_cursor, LV_STATE_DEFAULT, border_width); + lv_style_set_pad_left(&styles->ta_cursor, LV_STATE_DEFAULT, HASP_DPX(1)); lv_style_set_border_side(&styles->ta_cursor, LV_STATE_DEFAULT, LV_BORDER_SIDE_LEFT); style_init_reset(&styles->ta_placeholder); @@ -822,13 +800,12 @@ static void spinbox_init(void) lv_style_set_bg_opa(&styles->spinbox_cursor, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&styles->spinbox_cursor, LV_STATE_DEFAULT, theme.color_primary); lv_style_set_text_color(&styles->spinbox_cursor, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_pad_top(&styles->spinbox_cursor, LV_STATE_DEFAULT, LV_DPX(100)); - lv_style_set_pad_bottom(&styles->spinbox_cursor, LV_STATE_DEFAULT, LV_DPX(100)); + lv_style_set_pad_ver(&styles->spinbox_cursor, LV_STATE_DEFAULT, HASP_DPX(100)); #endif } -static void list_init(void) +static void list_init(lv_style_int_t pad_def, lv_style_int_t border_width) { #if LV_USE_LIST != 0 /* style_init_reset(&styles->list_bg); @@ -859,23 +836,20 @@ static void list_init(void) lv_style_set_border_side(&styles->list_btn, LV_STATE_DEFAULT, LV_BORDER_SIDE_BOTTOM); lv_style_set_border_color(&styles->list_btn, LV_STATE_DEFAULT, COLOR_BG_BORDER); lv_style_set_border_color(&styles->list_btn, LV_STATE_FOCUSED, theme.color_primary); - lv_style_set_border_width(&styles->list_btn, LV_STATE_DEFAULT, BORDER_WIDTH); + lv_style_set_border_width(&styles->list_btn, LV_STATE_DEFAULT, border_width); lv_style_set_outline_color(&styles->list_btn, LV_STATE_FOCUSED, theme.color_secondary); - // lv_style_set_outline_width(&styles->list_btn, LV_STATE_FOCUSED, OUTLINE_WIDTH); - lv_style_set_outline_pad(&styles->list_btn, LV_STATE_FOCUSED, -BORDER_WIDTH); + // lv_style_set_outline_width(&styles->list_btn, LV_STATE_FOCUSED, outline_width); + lv_style_set_outline_pad(&styles->list_btn, LV_STATE_FOCUSED, -border_width); - lv_style_set_pad_left(&styles->list_btn, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_right(&styles->list_btn, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_top(&styles->list_btn, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_bottom(&styles->list_btn, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_inner(&styles->list_btn, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_all(&styles->list_btn, LV_STATE_DEFAULT, pad_def); + lv_style_set_pad_inner(&styles->list_btn, LV_STATE_DEFAULT, pad_def); - lv_style_set_transform_width(&styles->list_btn, LV_STATE_DEFAULT, -PAD_DEF); - lv_style_set_transform_width(&styles->list_btn, LV_STATE_PRESSED, -BORDER_WIDTH); - lv_style_set_transform_width(&styles->list_btn, LV_STATE_CHECKED, -BORDER_WIDTH); - lv_style_set_transform_width(&styles->list_btn, LV_STATE_DISABLED, -BORDER_WIDTH); - lv_style_set_transform_width(&styles->list_btn, LV_STATE_FOCUSED, -BORDER_WIDTH); + lv_style_set_transform_width(&styles->list_btn, LV_STATE_DEFAULT, -pad_def); + lv_style_set_transform_width(&styles->list_btn, LV_STATE_PRESSED, -border_width); + lv_style_set_transform_width(&styles->list_btn, LV_STATE_CHECKED, -border_width); + lv_style_set_transform_width(&styles->list_btn, LV_STATE_DISABLED, -border_width); + lv_style_set_transform_width(&styles->list_btn, LV_STATE_FOCUSED, -border_width); lv_style_set_transition_time(&styles->list_btn, LV_STATE_DEFAULT, TRANSITION_TIME); lv_style_set_transition_prop_6(&styles->list_btn, LV_STATE_DEFAULT, LV_STYLE_BG_COLOR); @@ -888,7 +862,7 @@ static void ddlist_init(void) #if LV_USE_DROPDOWN != 0 /* style_init_reset(&styles->ddlist_page); - lv_style_set_text_line_space(&styles->ddlist_page, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_text_line_space(&styles->ddlist_page, LV_STATE_DEFAULT, HASP_DPX(20)); lv_style_set_clip_corner(&styles->ddlist_page, LV_STATE_DEFAULT, true); style_init_reset(&styles->ddlist_sel); @@ -896,7 +870,7 @@ static void ddlist_init(void) // lv_style_set_bg_opa(&styles->ddlist_sel, LV_STATE_DEFAULT, LV_OPA_COVER); // lv_style_set_bg_color(&styles->ddlist_sel, LV_STATE_DEFAULT, theme.color_primary); lv_style_set_text_color(&styles->ddlist_sel, LV_STATE_DEFAULT, - IS_LIGHT ? lv_color_hex3(0xfff) : lv_color_hex3(0xfff)); + IS_LIGHT ?LV_COLOR_WHITE :LV_COLOR_WHITE); lv_style_set_bg_color(&styles->ddlist_sel, LV_STATE_PRESSED, COLOR_BG_PR); lv_style_set_text_color(&styles->ddlist_sel, LV_STATE_PRESSED, COLOR_BG_TEXT_PR); */ @@ -907,7 +881,7 @@ static void roller_init(void) { #if LV_USE_ROLLER != 0 /* style_init_reset(&styles->roller_bg); - lv_style_set_text_line_space(&styles->roller_bg, LV_STATE_DEFAULT, LV_DPX(25)); + lv_style_set_text_line_space(&styles->roller_bg, LV_STATE_DEFAULT, HASP_DPX(25)); style_init_reset(&styles->roller_sel); lv_style_set_bg_opa(&styles->roller_sel, LV_STATE_DEFAULT, LV_OPA_COVER); @@ -928,18 +902,14 @@ static void tileview_init(void) #endif } -static void table_init(void) +static void table_init(lv_style_int_t pad_def) { #if LV_USE_TABLE != 0 style_init_reset(&styles->table_cell); lv_style_set_border_color(&styles->table_cell, LV_STATE_DEFAULT, COLOR_BG_BORDER); lv_style_set_border_width(&styles->table_cell, LV_STATE_DEFAULT, 1); lv_style_set_border_side(&styles->table_cell, LV_STATE_DEFAULT, LV_BORDER_SIDE_TOP | LV_BORDER_SIDE_BOTTOM); - lv_style_set_pad_left(&styles->table_cell, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_right(&styles->table_cell, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_top(&styles->table_cell, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_bottom(&styles->table_cell, LV_STATE_DEFAULT, PAD_DEF); - + lv_style_set_pad_all(&styles->table_cell, LV_STATE_DEFAULT, pad_def); #endif } @@ -949,24 +919,22 @@ static void win_init(void) #endif } -static void tabview_win_shared_init(void) +static void tabview_win_shared_init(lv_style_int_t pad_def, lv_style_int_t dpx7, lv_color_t color_scr_text) { #if LV_USE_TABVIEW || LV_USE_WIN style_init_reset(&styles->tabview_btns_bg); lv_style_set_bg_opa(&styles->tabview_btns_bg, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&styles->tabview_btns_bg, LV_STATE_DEFAULT, COLOR_SCR_GRAD); - lv_style_set_text_color(&styles->tabview_btns_bg, LV_STATE_DEFAULT, COLOR_SCR_TEXT); + lv_style_set_text_color(&styles->tabview_btns_bg, LV_STATE_DEFAULT, color_scr_text); lv_style_set_image_recolor(&styles->tabview_btns_bg, LV_STATE_DEFAULT, lv_color_hex(0x979a9f)); - lv_style_set_pad_top(&styles->tabview_btns_bg, LV_STATE_DEFAULT, LV_DPX(7)); - lv_style_set_pad_left(&styles->tabview_btns_bg, LV_STATE_DEFAULT, LV_DPX(7)); - lv_style_set_pad_right(&styles->tabview_btns_bg, LV_STATE_DEFAULT, LV_DPX(7)); + lv_style_set_pad_top(&styles->tabview_btns_bg, LV_STATE_DEFAULT, dpx7); + lv_style_set_pad_hor(&styles->tabview_btns_bg, LV_STATE_DEFAULT, dpx7); style_init_reset(&styles->tabview_btns); lv_style_set_bg_opa(&styles->tabview_btns, LV_STATE_PRESSED, LV_OPA_50); lv_style_set_bg_color(&styles->tabview_btns, LV_STATE_PRESSED, lv_color_hex3(0x888)); - lv_style_set_text_color(&styles->tabview_btns, LV_STATE_CHECKED, COLOR_SCR_TEXT); - lv_style_set_pad_top(&styles->tabview_btns, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_bottom(&styles->tabview_btns, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_text_color(&styles->tabview_btns, LV_STATE_CHECKED, color_scr_text); + lv_style_set_pad_ver(&styles->tabview_btns, LV_STATE_DEFAULT, HASP_DPX(20)); lv_style_set_text_color(&styles->tabview_btns, LV_STATE_FOCUSED, theme.color_primary); lv_style_set_text_color(&styles->tabview_btns, LV_STATE_EDITED, theme.color_secondary); @@ -974,15 +942,12 @@ static void tabview_win_shared_init(void) lv_style_set_bg_opa(&styles->tabview_indic, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&styles->tabview_indic, LV_STATE_DEFAULT, theme.color_primary); lv_style_set_bg_color(&styles->tabview_indic, LV_STATE_EDITED, theme.color_secondary); - lv_style_set_size(&styles->tabview_indic, LV_STATE_DEFAULT, LV_DPX(5)); + lv_style_set_size(&styles->tabview_indic, LV_STATE_DEFAULT, HASP_DPX(5)); lv_style_set_radius(&styles->tabview_indic, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); style_init_reset(&styles->tabview_page_scrl); - lv_style_set_pad_top(&styles->tabview_page_scrl, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_bottom(&styles->tabview_page_scrl, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_left(&styles->tabview_page_scrl, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_right(&styles->tabview_page_scrl, LV_STATE_DEFAULT, PAD_DEF); - lv_style_set_pad_inner(&styles->tabview_page_scrl, LV_STATE_DEFAULT, PAD_DEF); + lv_style_set_pad_all(&styles->tabview_page_scrl, LV_STATE_DEFAULT, pad_def); + lv_style_set_pad_inner(&styles->tabview_page_scrl, LV_STATE_DEFAULT, pad_def); #endif } @@ -1001,9 +966,9 @@ static void tabview_win_shared_init(void) * @param font_title pointer to a extra large font * @return a pointer to reference this theme later */ -lv_theme_t * lv_theme_hasp_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags, - const lv_font_t * font_small, const lv_font_t * font_normal, - const lv_font_t * font_subtitle, const lv_font_t * font_title) +lv_theme_t* lv_theme_hasp_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags, + const lv_font_t* font_small, const lv_font_t* font_normal, + const lv_font_t* font_subtitle, const lv_font_t* font_title) { /* This trick is required only to avoid the garbage collection of @@ -1011,7 +976,7 @@ lv_theme_t * lv_theme_hasp_init(lv_color_t color_primary, lv_color_t color_secon * In a general case styles could be simple `static lv_style_t my style` variables*/ if(!inited) { LV_GC_ROOT(_lv_theme_material_styles) = lv_mem_alloc(sizeof(theme_styles_t)); - styles = (theme_styles_t *)LV_GC_ROOT(_lv_theme_material_styles); + styles = (theme_styles_t*)LV_GC_ROOT(_lv_theme_material_styles); } theme.color_primary = color_primary; @@ -1022,7 +987,14 @@ lv_theme_t * lv_theme_hasp_init(lv_color_t color_primary, lv_color_t color_secon theme.font_title = font_title; theme.flags = flags; - basic_init(); + lv_style_int_t border_width = BORDER_WIDTH; + lv_style_int_t outline_width = OUTLINE_WIDTH; + lv_style_int_t pad_def = PAD_DEF; + lv_style_int_t dpx7 = HASP_DPX(7); + lv_color_t value_color = IS_LIGHT ? lv_color_hex(0x31404f) : LV_COLOR_WHITE; + lv_color_t color_scr_text = COLOR_SCR_TEXT; + + basic_init(border_width, outline_width, value_color, color_scr_text); cont_init(); btn_init(); label_init(); @@ -1037,23 +1009,23 @@ lv_theme_t * lv_theme_hasp_init(lv_color_t color_primary, lv_color_t color_secon arc_init(); spinner_init(); chart_init(); - calendar_init(); + calendar_init(pad_def, value_color); cpicker_init(); checkbox_init(); btnmatrix_init(); keyboard_init(); msgbox_init(); - page_init(); - textarea_init(); + page_init(dpx7); + textarea_init(border_width); spinbox_init(); - list_init(); + list_init(pad_def, border_width); ddlist_init(); roller_init(); tabview_init(); tileview_init(); - table_init(); + table_init(pad_def); win_init(); - tabview_win_shared_init(); + tabview_win_shared_init(pad_def, dpx7, color_scr_text); theme.apply_xcb = NULL; theme.apply_cb = theme_apply; @@ -1065,11 +1037,11 @@ lv_theme_t * lv_theme_hasp_init(lv_color_t color_primary, lv_color_t color_secon return &theme; } -static void theme_apply(lv_theme_t * th, lv_obj_t * obj, lv_theme_style_t name) +static void theme_apply(lv_theme_t* th, lv_obj_t* obj, lv_theme_style_t name) { LV_UNUSED(th); - lv_style_list_t * list; + lv_style_list_t* list; switch(name) { case LV_THEME_NONE: @@ -1267,10 +1239,10 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj, lv_theme_style_t name) list = lv_obj_get_style_list(obj, LV_PAGE_PART_SCROLLBAR); _lv_style_list_add_style(list, &styles->sb); - #if LV_USE_ANIMATION +#if LV_USE_ANIMATION list = lv_obj_get_style_list(obj, LV_PAGE_PART_EDGE_FLASH); _lv_style_list_add_style(list, &styles->edge_flash); - #endif +#endif break; #endif #if LV_USE_TABVIEW @@ -1303,10 +1275,10 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj, lv_theme_style_t name) list = lv_obj_get_style_list(obj, LV_TILEVIEW_PART_SCROLLBAR); _lv_style_list_add_style(list, &styles->sb); - #if LV_USE_ANIMATION +#if LV_USE_ANIMATION list = lv_obj_get_style_list(obj, LV_TILEVIEW_PART_EDGE_FLASH); _lv_style_list_add_style(list, &styles->edge_flash); - #endif +#endif break; #endif @@ -1518,7 +1490,7 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj, lv_theme_style_t name) * STATIC FUNCTIONS **********************/ -static void style_init_reset(lv_style_t * style) +static void style_init_reset(lv_style_t* style) { if(inited) lv_style_reset(style); diff --git a/src/hasp/lv_theme_hasp.h b/src/hasp/lv_theme_hasp.h index 49425093..f6fe647c 100644 --- a/src/hasp/lv_theme_hasp.h +++ b/src/hasp/lv_theme_hasp.h @@ -22,10 +22,10 @@ extern "C" { * DEFINES *********************/ typedef enum { - LV_THEME_HASP_FLAG_DARK = 0x01, - LV_THEME_HASP_FLAG_LIGHT = 0x02, - LV_THEME_HASP_FLAG_NO_TRANSITION = 0x10, - LV_THEME_HASP_FLAG_NO_FOCUS = 0x20, + LV_THEME_HASP_FLAG_DARK = 0x01, + LV_THEME_HASP_FLAG_LIGHT = 0x02, + LV_THEME_HASP_FLAG_NO_TRANSITION = 0x10, + LV_THEME_HASP_FLAG_NO_FOCUS = 0x20, } lv_theme_hasp_flag_t; /********************** @@ -47,17 +47,15 @@ typedef enum { * @param font_title pointer to a extra large font * @return a pointer to reference this theme later */ -lv_theme_t * lv_theme_hasp_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags, - const lv_font_t * font_small, const lv_font_t * font_normal, - const lv_font_t * font_subtitle, const lv_font_t * font_title); +lv_theme_t* lv_theme_hasp_init(lv_color_t color_primary, lv_color_t color_secondary, uint32_t flags, + const lv_font_t* font_small, const lv_font_t* font_normal, + const lv_font_t* font_subtitle, const lv_font_t* font_title); /********************** * MACROS **********************/ -#endif - #ifdef __cplusplus } /* extern "C" */ #endif -//#endif /*LV_THEME_HASP_H*/ +#endif /*LV_THEME_HASP_H*/ diff --git a/src/hasp_config.cpp b/src/hasp_config.cpp index 0c040cb9..4240ceb6 100644 --- a/src/hasp_config.cpp +++ b/src/hasp_config.cpp @@ -1,30 +1,37 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #if HASP_USE_CONFIG > 0 - #include "ArduinoJson.h" - #include "StreamUtils.h" // For EEPromStream +#include "ArduinoJson.h" +#include "StreamUtils.h" // For EEPromStream - #include "hasp_conf.h" +#include "hasp_conf.h" - #include "hasp_config.h" - #include "hasp_debug.h" - #include "hasp_gui.h" +#include "hasp_config.h" +#include "hasp_debug.h" +#include "hasp_gui.h" - //#include "hasp_ota.h" included in conf - //#include "hasp_filesystem.h" included in conf - //#include "hasp_telnet.h" included in conf - //#include "hasp_gpio.h" included in conf +//#include "hasp_ota.h" included in conf +//#include "hasp_filesystem.h" included in conf +//#include "hasp_telnet.h" included in conf +//#include "hasp_gpio.h" included in conf - //#include "hasp_eeprom.h" - #include "hasp/hasp.h" +//#include "hasp_eeprom.h" +#include "hasp/hasp.h" +#include "hasp/hasp_dispatch.h" - #if HASP_USE_EEPROM > 0 - #include "EEPROM.h" - #endif +#if HASP_USE_EEPROM > 0 +#include "EEPROM.h" +#endif -void confDebugSet(const __FlashStringHelper * fstr_name) +extern uint16_t dispatchTelePeriod; +extern uint32_t dispatchLastMillis; + +extern gui_conf_t gui_settings; +extern dispatch_conf_t dispatch_settings; + +void confDebugSet(const __FlashStringHelper* fstr_name) { /*char buffer[128]; snprintf_P(buffer, sizeof(buffer), PSTR(" * %s set"), name); @@ -32,7 +39,7 @@ void confDebugSet(const __FlashStringHelper * fstr_name) LOG_VERBOSE(TAG_CONF, F(D_BULLET "%S set"), fstr_name); } -bool configSet(int8_t & value, const JsonVariant & setting, const __FlashStringHelper * fstr_name) +bool configSet(int8_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name) { if(!setting.isNull()) { int8_t val = setting.as(); @@ -44,7 +51,7 @@ bool configSet(int8_t & value, const JsonVariant & setting, const __FlashStringH } return false; } -bool configSet(uint8_t & value, const JsonVariant & setting, const __FlashStringHelper * fstr_name) +bool configSet(uint8_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name) { if(!setting.isNull()) { uint8_t val = setting.as(); @@ -56,7 +63,7 @@ bool configSet(uint8_t & value, const JsonVariant & setting, const __FlashString } return false; } -bool configSet(uint16_t & value, const JsonVariant & setting, const __FlashStringHelper * fstr_name) +bool configSet(uint16_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name) { if(!setting.isNull()) { uint16_t val = setting.as(); @@ -69,31 +76,31 @@ bool configSet(uint16_t & value, const JsonVariant & setting, const __FlashStrin return false; } -void configStartDebug(bool setupdebug, String & configFile) +void configStartDebug(bool setupdebug, String& configFile) { if(setupdebug) { debugStart(); // Debug started, now we can use it; HASP header sent - #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 LOG_INFO(TAG_CONF, F("SPI flash FS mounted")); filesystemInfo(); filesystemList(); - #endif +#endif } - #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 LOG_TRACE(TAG_CONF, F(D_FILE_LOADING), configFile.c_str()); - #else +#else LOG_TRACE(TAG_CONF, F(D_FILE_LOADING), "EEPROM"); - #endif +#endif } -void configGetConfig(JsonDocument & settings, bool setupdebug = false) +void configRead(JsonDocument& settings, bool setupdebug = false) { - String configFile((char *)0); + String configFile((char*)0); configFile.reserve(32); configFile = String(FPSTR(FP_HASP_CONFIG_FILE)); DeserializationError error; - #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 File file = HASP_FS.open(configFile, "r"); if(file) { @@ -116,8 +123,8 @@ void configGetConfig(JsonDocument & settings, bool setupdebug = false) // show settings in log String output; serializeJson(settings, output); - String passmask = F(D_PASSWORD_MASK); - const __FlashStringHelper * pass = F("pass"); + String passmask = F(D_PASSWORD_MASK); + const __FlashStringHelper* pass = F("pass"); output.replace(settings[FPSTR(FP_HTTP)][pass].as(), passmask); output.replace(settings[FPSTR(FP_MQTT)][pass].as(), passmask); output.replace(settings[FPSTR(FP_WIFI)][pass].as(), passmask); @@ -128,14 +135,14 @@ void configGetConfig(JsonDocument & settings, bool setupdebug = false) return; } } - #else +#else - #if HASP_USE_EEPROM > 0 +#if HASP_USE_EEPROM > 0 EepromStream eepromStream(0, 1024); error = deserializeJson(settings, eepromStream); - #endif +#endif - #endif +#endif // File does not exist or error reading file if(setupdebug) { @@ -143,9 +150,9 @@ void configGetConfig(JsonDocument & settings, bool setupdebug = false) } configStartDebug(setupdebug, configFile); - #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 LOG_ERROR(TAG_CONF, F(D_FILE_LOAD_FAILED), configFile.c_str()); - #endif +#endif } /* void configBackupToEeprom() @@ -177,20 +184,20 @@ void configBackupToEeprom() #endif } */ -void configWriteConfig() +void configWrite() { - String configFile((char *)0); + String configFile((char*)0); configFile.reserve(32); configFile = String(FPSTR(FP_HASP_CONFIG_FILE)); - String settingsChanged((char *)0); + String settingsChanged((char*)0); settingsChanged.reserve(128); settingsChanged = F(D_CONFIG_CHANGED); /* Read Config File */ DynamicJsonDocument doc(8 * 256); LOG_TRACE(TAG_CONF, F(D_FILE_LOADING), configFile.c_str()); - configGetConfig(doc, false); + configRead(doc, false); LOG_INFO(TAG_CONF, F(D_FILE_LOADED), configFile.c_str()); // Make sure we have a valid JsonObject to start from @@ -203,9 +210,9 @@ void configWriteConfig() bool writefile = false; bool changed = false; - const __FlashStringHelper * module; + const __FlashStringHelper* module; - #if HASP_USE_WIFI > 0 +#if HASP_USE_WIFI > 0 module = FPSTR(FP_WIFI); if(settings[module].as().isNull()) settings.createNestedObject(module); changed = wifiGetConfig(settings[module]); @@ -214,9 +221,9 @@ void configWriteConfig() configOutput(settings[module], TAG_WIFI); writefile = true; } - #endif +#endif - #if HASP_USE_MQTT > 0 +#if HASP_USE_MQTT > 0 module = FPSTR(FP_MQTT); if(settings[module].as().isNull()) settings.createNestedObject(module); changed = mqttGetConfig(settings[module]); @@ -225,9 +232,9 @@ void configWriteConfig() configOutput(settings[module], TAG_MQTT); writefile = true; } - #endif +#endif - #if HASP_USE_TELNET > 0 +#if HASP_USE_TELNET > 0 module = F("telnet"); if(settings[module].as().isNull()) settings.createNestedObject(module); changed = telnetGetConfig(settings[module]); @@ -236,9 +243,9 @@ void configWriteConfig() configOutput(settings[module], TAG_TELN); writefile = true; } - #endif +#endif - #if HASP_USE_MDNS > 0 +#if HASP_USE_MDNS > 0 module = FPSTR(FP_MDNS); if(settings[module].as().isNull()) settings.createNestedObject(module); changed = mdnsGetConfig(settings[module]); @@ -247,9 +254,9 @@ void configWriteConfig() configOutput(settings[module], TAG_MDNS); writefile = true; } - #endif +#endif - #if HASP_USE_HTTP > 0 +#if HASP_USE_HTTP > 0 if(settings[FPSTR(FP_HTTP)].as().isNull()) settings.createNestedObject(F("http")); changed = httpGetConfig(settings[FPSTR(FP_HTTP)]); if(changed) { @@ -257,9 +264,9 @@ void configWriteConfig() configOutput(settings[FPSTR(FP_HTTP)], TAG_HTTP); writefile = true; } - #endif +#endif - #if HASP_USE_GPIO > 0 +#if HASP_USE_GPIO > 0 module = FPSTR(FP_GPIO); if(settings[module].as().isNull()) settings.createNestedObject(module); changed = gpioGetConfig(settings[module]); @@ -268,7 +275,7 @@ void configWriteConfig() configOutput(settings[module], TAG_GPIO); writefile = true; } - #endif +#endif module = FPSTR(FP_DEBUG); if(settings[module].as().isNull()) settings.createNestedObject(module); @@ -298,7 +305,7 @@ void configWriteConfig() // changed |= otaGetConfig(settings[F("ota")].as()); if(writefile) { - #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 File file = HASP_FS.open(configFile, "w"); if(file) { LOG_TRACE(TAG_CONF, F(D_FILE_SAVING), configFile.c_str()); @@ -313,7 +320,7 @@ void configWriteConfig() } else { LOG_ERROR(TAG_CONF, F(D_FILE_SAVE_FAILED), configFile.c_str()); } - #endif +#endif // Method 1 // LOG_INFO(TAG_CONF,F("Writing to EEPROM")); @@ -323,9 +330,9 @@ void configWriteConfig() // bufferedWifiClient.flush(); // <- OPTIONAL // eepromStream.flush(); // (for ESP) - #if defined(STM32F4xx) +#if defined(STM32F4xx) // Method 2 - LOG_INFO(TAG_CONF, F(F_FILE_SAVING), "EEPROM"); + LOG_INFO(TAG_CONF, F(D_FILE_SAVING), "EEPROM"); char buffer[1024 + 128]; size_t size = serializeJson(doc, buffer, sizeof(buffer)); if(size > 0) { @@ -333,11 +340,11 @@ void configWriteConfig() for(i = 0; i < size; i++) eeprom_buffered_write_byte(i, buffer[i]); eeprom_buffered_write_byte(i, 0); eeprom_buffer_flush(); - LOG_INFO(TAG_CONF, F(F_FILE_SAVED), "EEPROM"); + LOG_INFO(TAG_CONF, F(D_FILE_SAVED), "EEPROM"); } else { - LOG_ERROR(TAG_CONF, F(D_FILE_WRITE_FAILED), "EEPROM"); + LOG_ERROR(TAG_CONF, F(D_FILE_SAVE_FAILED), "EEPROM"); } - #endif +#endif } else { LOG_INFO(TAG_CONF, F(D_CONFIG_NOT_CHANGED)); @@ -354,20 +361,20 @@ void configSetup() Serial.println(__LINE__); if(i == 0) { - #if HASP_USE_SPIFFS > 0 +#if HASP_USE_SPIFFS > 0 EepromStream eepromStream(0, 2048); DeserializationError err = deserializeJson(settings, eepromStream); - #else +#else continue; - #endif +#endif } else { - #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 if(!filesystemSetup()) { LOG_ERROR(TAG_CONF, F("FILE: SPI flash init failed. Unable to mount FS: Using default settings...")); return; } - #endif - configGetConfig(settings, true); +#endif + configRead(settings, true); } //#if HASP_USE_SPIFFS > 0 @@ -379,35 +386,35 @@ void configSetup() haspSetConfig(settings[FPSTR(FP_HASP)]); // otaGetConfig(settings[F("ota")]); - #if HASP_USE_WIFI > 0 +#if HASP_USE_WIFI > 0 LOG_INFO(TAG_WIFI, F("Loading WiFi settings")); wifiSetConfig(settings[FPSTR(FP_WIFI)]); - #endif +#endif - #if HASP_USE_MQTT > 0 +#if HASP_USE_MQTT > 0 LOG_INFO(TAG_MQTT, F("Loading MQTT settings")); mqttSetConfig(settings[FPSTR(FP_MQTT)]); - #endif +#endif - #if HASP_USE_TELNET > 0 +#if HASP_USE_TELNET > 0 LOG_INFO(TAG_TELN, F("Loading Telnet settings")); telnetSetConfig(settings[F("telnet")]); - #endif +#endif - #if HASP_USE_MDNS > 0 +#if HASP_USE_MDNS > 0 LOG_INFO(TAG_MDNS, F("Loading MDNS settings")); mdnsSetConfig(settings[FPSTR(FP_MDNS)]); - #endif +#endif - #if HASP_USE_HTTP > 0 +#if HASP_USE_HTTP > 0 LOG_INFO(TAG_HTTP, F("Loading HTTP settings")); httpSetConfig(settings[FPSTR(FP_HTTP)]); - #endif +#endif - #if HASP_USE_GPIO > 0 +#if HASP_USE_GPIO > 0 LOG_INFO(TAG_GPIO, F("Loading GPIO settings")); gpioSetConfig(settings[FPSTR(FP_GPIO)]); - #endif +#endif LOG_INFO(TAG_CONF, F(D_CONFIG_LOADED)); } @@ -417,17 +424,17 @@ void configSetup() void configLoop(void) {} -void configOutput(const JsonObject & settings, uint8_t tag) +void configOutput(const JsonObject& settings, uint8_t tag) { - String output((char *)0); + String output((char*)0); output.reserve(128); serializeJson(settings, output); - String passmask((char *)0); + String passmask((char*)0); passmask.reserve(128); passmask = F("\"pass\":\"" D_PASSWORD_MASK "\""); - String password((char *)0); + String password((char*)0); password.reserve(128); String pass = F("pass"); @@ -464,7 +471,7 @@ void configOutput(const JsonObject & settings, uint8_t tag) bool configClearEeprom() { - #if defined(STM32F4xx) +#if defined(STM32F4xx) LOG_TRACE(TAG_CONF, F("Clearing EEPROM")); char buffer[1024 + 128]; memset(buffer, 1, sizeof(buffer)); @@ -479,11 +486,11 @@ bool configClearEeprom() LOG_ERROR(TAG_CONF, F("Failed to clear to EEPROM")); return false; } - #elif HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 +#elif HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 return HASP_FS.format(); - #else +#else return false; - #endif +#endif } #endif // HAS_USE_CONFIG \ No newline at end of file diff --git a/src/hasp_config.h b/src/hasp_config.h index 31ea0df3..77eb6e01 100644 --- a/src/hasp_config.h +++ b/src/hasp_config.h @@ -1,14 +1,14 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #if HASP_USE_CONFIG > 0 - #ifndef HASP_CONFIG_H - #define HASP_CONFIG_H +#ifndef HASP_CONFIG_H +#define HASP_CONFIG_H - #include "hasp_conf.h" - #include "ArduinoJson.h" - #include "hasp_debug.h" // for TAG_CONF +#include "hasp_conf.h" +#include "ArduinoJson.h" +#include "hasp_debug.h" // for TAG_CONF /* ===== Default Event Processors ===== */ void configSetup(void); @@ -18,18 +18,18 @@ void configStart(void); void configStop(void); /* ===== Special Event Processors ===== */ -void configWriteConfig(void); -void configOutput(const JsonObject & settings, uint8_t tag = TAG_CONF); +void configWrite(void); +void configOutput(const JsonObject& settings, uint8_t tag = TAG_CONF); bool configClearEeprom(void); /* ===== Getter and Setter Functions ===== */ -bool configSet(int8_t & value, const JsonVariant & setting, const __FlashStringHelper * fstr_name); -bool configSet(uint8_t & value, const JsonVariant & setting, const __FlashStringHelper * fstr_name); -bool configSet(uint16_t & value, const JsonVariant & setting, const __FlashStringHelper * fstr_name); +bool configSet(int8_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name); +bool configSet(uint8_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name); +bool configSet(uint16_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name); /* ===== Read/Write Configuration ===== */ -void configSetConfig(JsonObject & settings); -void configGetConfig(JsonDocument & settings); +void configSetConfig(JsonObject& settings); +void configGetConfig(JsonDocument& settings); /* json keys used in the configfile */ const char FP_CONFIG_STARTPAGE[] PROGMEM = "startpage"; @@ -62,16 +62,15 @@ const char FP_GPIO_CONFIG[] PROGMEM = "config"; const char FP_HASP_CONFIG_FILE[] PROGMEM = "/config.json"; -const char FP_WIFI[] PROGMEM = "wifi"; -const char FP_MQTT[] PROGMEM = "mqtt"; -const char FP_HTTP[] PROGMEM = "http"; -const char FP_GPIO[] PROGMEM = "gpio"; -const char FP_MDNS[] PROGMEM = "mdns"; -const char FP_HASP[] PROGMEM = "hasp"; -const char FP_GUI[] PROGMEM = "gui"; +const char FP_WIFI[] PROGMEM = "wifi"; +const char FP_MQTT[] PROGMEM = "mqtt"; +const char FP_HTTP[] PROGMEM = "http"; +const char FP_GPIO[] PROGMEM = "gpio"; +const char FP_MDNS[] PROGMEM = "mdns"; +const char FP_HASP[] PROGMEM = "hasp"; +const char FP_GUI[] PROGMEM = "gui"; const char FP_DEBUG[] PROGMEM = "debug"; - - #endif +#endif #endif // HASP_USE_CONFIG \ No newline at end of file diff --git a/src/hasp_debug.cpp b/src/hasp_debug.cpp index 9b556153..9946f969 100644 --- a/src/hasp_debug.cpp +++ b/src/hasp_debug.cpp @@ -1,377 +1,314 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ -/* =========================================================================== - -- LOG_FATAL() - A fatal exception is caught, the program should halt with while(1){} -- LOG_ERROR() - An important but non-fatal error occured, this error should be checked and not ignored -- LOG_WARNING() - Send at the end of a function to indicate failure of the sub process, can be ignored - -- LOG_TRACE() - Information at the START of an action to notify another function is now running - - LOG_INFO() - Send at the END of a function to indicate successful completion of the sub process - - LOG_VERBOSE() - Send DEBUG information DURING a subprocess - -=========================================================================== */ - -#include "hasp_conf.h" -#include "ConsoleInput.h" +#include "ArduinoJson.h" #include "lvgl.h" -//#include "time.h" - -#if defined(ARDUINO_ARCH_ESP8266) - #include // sntp_servermode_dhcp() - #include - #include -#elif defined(ARDUINO_ARCH_ESP32) - #include - #include -#endif +#include +#include "lang/lang.h" #include "hasp_conf.h" - -#include "hasp_hal.h" #include "hasp_debug.h" -#include "hasp_config.h" - -#include "hasp/hasp_dispatch.h" +#include "hasp_macro.h" #include "hasp/hasp.h" -#ifdef USE_CONFIG_OVERRIDE - #include "user_config_override.h" +#if(!defined(WINDOWS)) && (!defined(POSIX)) +#include "ArduinoLog.h" + +#define debug_print(io, ...) io->printf(__VA_ARGS__) +#define debug_newline(io) io->println() + +bool debugSerialStarted = false; +#else +#include +#include +#include + +#define debug_print(io, ...) fprintf(stdout, __VA_ARGS__) +#define debug_newline(io) fprintf(stdout, "\n") + +bool debugSerialStarted = true; #endif -#ifndef SERIAL_SPEED - #define SERIAL_SPEED 115200 -#endif +bool debugAnsiCodes = true; -#if HASP_USE_SYSLOG > 0 - #include - - #ifndef SYSLOG_SERVER - #define SYSLOG_SERVER "" - #endif - - #ifndef SYSLOG_PORT - #define SYSLOG_PORT 514 - #endif - - #ifndef APP_NAME - #define APP_NAME "HASP" - #endif - -// variables for debug stream writer -// static String debugOutput((char *)0); -// static StringStream debugStream((String &)debugOutput); - -// extern char mqttNodeName[16]; -const char * syslogAppName = APP_NAME; -char debugSyslogHost[32] = SYSLOG_SERVER; -uint16_t debugSyslogPort = SYSLOG_PORT; -uint8_t debugSyslogFacility = 0; -uint8_t debugSyslogProtocol = 0; - -// A UDP instance to let us send and receive packets over UDP -WiFiUDP * syslogClient; - #define SYSLOG_PROTO_IETF 0 - -// Create a new syslog instance with LOG_KERN facility -// Syslog syslog(syslogClient, SYSLOG_SERVER, SYSLOG_PORT, MQTT_CLIENT, APP_NAME, LOG_KERN); -// Create a new empty syslog instance -// Syslog * syslog; - -#endif // USE_SYSLOG - -// Serial Settings -// uint16_t serialInputIndex = 0; // Empty buffer -// char serialInputBuffer[220] = ""; -// uint16_t historyIndex = sizeof(serialInputBuffer) - 1; // Empty buffer -uint16_t debugSerialBaud = SERIAL_SPEED / 10; // Multiplied by 10 -bool debugSerialStarted = false; -bool debugAnsiCodes = true; - -ConsoleInput debugConsole(&Serial, HASP_CONSOLE_BUFFER); - -//#define TERM_COLOR_Black "\u001b[30m" -#define TERM_COLOR_GRAY "\e[37m" -#define TERM_COLOR_RED "\e[91m" -#define TERM_COLOR_GREEN "\e[92m" -#define TERM_COLOR_ORANGE "\e[38;5;214m" -#define TERM_COLOR_YELLOW "\e[93m" -#define TERM_COLOR_BLUE "\e[94m" -#define TERM_COLOR_MAGENTA "\e[35m" -#define TERM_COLOR_CYAN "\e[96m" -#define TERM_COLOR_WHITE "\e[97m" -#define TERM_COLOR_RESET "\e[0m" -#define TERM_CLEAR_LINE "\e[1000D\e[0K" - -unsigned long debugLastMillis = 0; -uint16_t debugTelePeriod = 300; - -// Send the HASP header and version to the output device specified -void debugPrintHaspHeader(Print * output) +inline void debugSendAnsiCode(const __FlashStringHelper* code, Print* _logOutput) { - if(debugAnsiCodes) output->print(TERM_COLOR_YELLOW); - output->println(); - output->print(F("" - " _____ _____ _____ _____\r\n" - " | | | _ | __| _ |\r\n" - " | | |__ | __|\r\n" - " |__|__|__|__|_____|__|\r\n" - " Home Automation Switch Plate\r\n" - " Open Hardware edition v")); - char buffer[32]; - haspGetVersion(buffer, sizeof(buffer)); - output->println(buffer); - output->println(); +#ifdef ARDUINO + if(debugAnsiCodes) _logOutput->print(code); +#else + if(debugAnsiCodes) debug_print(_logOutput, code); +#endif +} + +void debug_timestamp() +{ + timeval curTime; + gettimeofday(&curTime, NULL); + int milli = curTime.tv_usec / 1000; + + char currentTime[80]; + time_t t = curTime.tv_sec; + // strftime(currentTime, 80, "%Y-%m-%d %H:%M.%S", localtime(&t)); + strftime(currentTime, 80, "%H:%M:%S", localtime(&t)); + printf("[%s.%03d] ", currentTime, milli); +} + +static void debugPrintTimestamp(int level, Print* _logOutput) +{ /* Print Current Time */ + + timeval curTime; + int rslt = gettimeofday(&curTime, NULL); + time_t t = curTime.tv_sec; + tm* timeinfo = localtime(&t); + int milli = curTime.tv_usec / 1000; + + debugSendAnsiCode(F(TERM_COLOR_CYAN), _logOutput); + + if(timeinfo->tm_year >= 120) { + char buffer[24]; + strftime(buffer, sizeof(buffer), "[%b %d %H:%M:%S", timeinfo); // Literal String + // strftime(buffer, sizeof(buffer), "[%H:%M:%S.", timeinfo); // Literal String + +#ifdef ARDUINO + _logOutput->printf(PSTR("%s.%03lu]"), buffer, curTime.tv_usec / 1000); +#else + debug_print(_logOutput, PSTR("%s.%03lu]"), buffer, curTime.tv_usec / 1000); +#endif + + } else { + + uint32_t msecs = millis(); +#ifdef ARDUINO + _logOutput->printf(PSTR("[%15d.%03d]"), msecs / 1000, msecs % 1000); +#else + debug_print(_logOutput, PSTR("[%15d.%03d]"), msecs / 1000, msecs % 1000); +#endif + } +} + +/* ===== Default Event Processors ===== */ +// void debugPreSetup(JsonObject settings); +// void debugSetup(); + +static inline void debug_flush() +{ +#if defined(ARDUINO) + Serial.flush(); +#endif + +#if defined(WINDOWS) || defined(POSIX) + fflush(stdout); +#endif +} + +void debugEverySecond() +{ + // if(debugTelePeriod > 0 && (millis() - debugLastMillis) >= debugTelePeriod * 1000) { + // dispatch_output_statusupdate(NULL, NULL); + // debugLastMillis = millis(); + // } + // printLocalTime(); } void debugStart() { + +#if defined(WINDOWS) || defined(POSIX) + debug_newline(); + debugPrintHaspHeader(NULL); + debug_newline(); + + LOG_INFO(TAG_DEBG, F("Console started")); + LOG_INFO(TAG_DEBG, F("Environment: " PIOENV)); +#endif + if(debugSerialStarted) { - Serial.flush(); + debug_flush; + // Serial.println(); // Serial.println(debugHaspHeader()); - // Serial.flush(); + // debug_flush(); } // prepare syslog configuration here (can be anywhere before first call of // log/logf method) } -// #if HASP_USE_SYSLOG > 0 -// void syslogSend(uint8_t priority, const char * debugText) -// { -// if(strlen(debugSyslogHost) != 0 && WiFi.isConnected()) { -// syslog->log(priority, debugText); -// } -// } -// #endif - -void debugSetup() -{ - // memset(serialInputBuffer, 0, sizeof(serialInputBuffer)); - // serialInputIndex = 0; - LOG_TRACE(TAG_DEBG, F(D_SERVICE_STARTING)); // Starting console - debugConsole.setLineCallback(dispatch_text_line); -} - -void debugStartSyslog() -{ - -#if HASP_USE_SYSLOG > 0 - // syslog = new Syslog(syslogClient, debugSyslogProtocol == 0 ? SYSLOG_PROTO_IETF : SYSLOG_PROTO_BSD); - // syslog->server(debugSyslogHost, debugSyslogPort); - // syslog->deviceHostname(mqttNodeName); - // syslog->appName(syslogAppName); - // uint16_t priority = (uint16_t)(debugSyslogFacility + 16) << 3; // localx facility, x = 0-7 - // syslog->defaultPriority(priority); - - if(strlen(debugSyslogHost) > 0) { - if(!syslogClient) syslogClient = new WiFiUDP(); - - if(syslogClient) { - if(syslogClient->beginPacket(debugSyslogHost, debugSyslogPort)) { - Log.registerOutput(2, syslogClient, LOG_LEVEL_VERBOSE, true); - LOG_INFO(TAG_SYSL, F(D_SERVICE_STARTED)); - } - } else { - LOG_ERROR(TAG_SYSL, F(D_SERVICE_START_FAILED)); - } - } -#endif -} - -void debugStopSyslog() -{ -#if HASP_USE_SYSLOG > 0 - if(strlen(debugSyslogHost) > 0) { - LOG_WARNING(TAG_SYSL, F(D_SERVICE_STOPPED)); - Log.unregisterOutput(2); - } -#endif -} - void debugStop() { - if(debugSerialStarted) Serial.flush(); + if(debugSerialStarted) debug_flush(); } -#if HASP_USE_CONFIG > 0 -bool debugGetConfig(const JsonObject & settings) +/* ===== Special Event Processors ===== */ + +void debugLvglLogEvent(lv_log_level_t level, const char* file, uint32_t line, const char* funcname, const char* descr) { - bool changed = false; +#if LV_USE_LOG != 0 + /* used for duplicate detection */ + static uint32_t lastDbgLine; + static uint32_t lastDbgFreeMem; - if(debugSerialBaud != settings[FPSTR(FP_CONFIG_BAUD)].as()) changed = true; - settings[FPSTR(FP_CONFIG_BAUD)] = debugSerialBaud; + lv_mem_monitor_t mem_mon; + lv_mem_monitor(&mem_mon); - if(debugTelePeriod != settings[FPSTR(FP_DEBUG_TELEPERIOD)].as()) changed = true; - settings[FPSTR(FP_DEBUG_TELEPERIOD)] = debugTelePeriod; - - #if HASP_USE_SYSLOG > 0 - if(strcmp(debugSyslogHost, settings[FPSTR(FP_CONFIG_HOST)].as().c_str()) != 0) changed = true; - settings[FPSTR(FP_CONFIG_HOST)] = debugSyslogHost; - - if(debugSyslogPort != settings[FPSTR(FP_CONFIG_PORT)].as()) changed = true; - settings[FPSTR(FP_CONFIG_PORT)] = debugSyslogPort; - - if(debugSyslogProtocol != settings[FPSTR(FP_CONFIG_PROTOCOL)].as()) changed = true; - settings[FPSTR(FP_CONFIG_PROTOCOL)] = debugSyslogProtocol; - - if(debugSyslogFacility != settings[FPSTR(FP_CONFIG_LOG)].as()) changed = true; - settings[FPSTR(FP_CONFIG_LOG)] = debugSyslogFacility; - #endif - - if(changed) configOutput(settings, TAG_DEBG); - return changed; -} - -/** Set DEBUG Configuration. - * - * Read the settings from json and sets the application variables. - * - * @note: data pixel should be formated to uint32_t RGBA. Imagemagick requirements. - * - * @param[in] settings JsonObject with the config settings. - **/ -bool debugSetConfig(const JsonObject & settings) -{ - configOutput(settings, TAG_DEBG); - bool changed = false; - - /* Serial Settings*/ - changed |= configSet(debugSerialBaud, settings[FPSTR(FP_CONFIG_BAUD)], F("debugSerialBaud")); - - /* Teleperiod Settings*/ - changed |= configSet(debugTelePeriod, settings[FPSTR(FP_DEBUG_TELEPERIOD)], F("debugTelePeriod")); - - /* Syslog Settings*/ - #if HASP_USE_SYSLOG > 0 - if(!settings[FPSTR(FP_CONFIG_HOST)].isNull()) { - changed |= strcmp(debugSyslogHost, settings[FPSTR(FP_CONFIG_HOST)]) != 0; - strncpy(debugSyslogHost, settings[FPSTR(FP_CONFIG_HOST)], sizeof(debugSyslogHost)); - } - changed |= configSet(debugSyslogPort, settings[FPSTR(FP_CONFIG_PORT)], F("debugSyslogPort")); - changed |= configSet(debugSyslogProtocol, settings[FPSTR(FP_CONFIG_PROTOCOL)], F("debugSyslogProtocol")); - changed |= configSet(debugSyslogFacility, settings[FPSTR(FP_CONFIG_LOG)], F("debugSyslogFacility")); - #endif - - return changed; -} -#endif // HASP_USE_CONFIG - -inline void debugSendAnsiCode(const __FlashStringHelper * code, Print * _logOutput) -{ - if(debugAnsiCodes) _logOutput->print(code); -} -/* -size_t debugHistorycount() -{ - size_t count = 0; - for(size_t i = 1; i < sizeof(serialInputBuffer); i++) { - if(serialInputBuffer[i] == 0 && serialInputBuffer[i - 1] != 0) count++; - } - return count; -} - -size_t debugHistoryIndex(size_t num) -{ - size_t pos = 0; - while(num > 0 && pos < sizeof(serialInputBuffer) - 2) { - if(serialInputBuffer[pos] == 0) { - num--; - // skip extra \0s - while(serialInputBuffer[pos] == 0) { - pos++; - } - } else { - pos++; + /* Reduce the number of repeated debug message */ + if(line != lastDbgLine || mem_mon.free_biggest_size != lastDbgFreeMem) { + switch(level) { + case LV_LOG_LEVEL_TRACE: + LOG_VERBOSE(TAG_LVGL, descr); + break; + case LV_LOG_LEVEL_WARN: + LOG_WARNING(TAG_LVGL, descr); + break; + case LV_LOG_LEVEL_ERROR: + LOG_ERROR(TAG_LVGL, descr); + break; + default: + LOG_TRACE(TAG_LVGL, descr); } + lastDbgLine = line; + lastDbgFreeMem = mem_mon.free_biggest_size; } - - return pos; +#endif } -void debugShowHistory() +// Send the HASP header and version to the output device specified +void debugPrintHaspHeader(Print* output) { - size_t num = debugHistorycount(); - Serial.println(); - for(int i = 0; i <= num; i++) { - Serial.print("["); - Serial.print(i); - Serial.print("] "); - size_t pos = debugHistoryIndex(i); - if(pos < sizeof(serialInputBuffer)) Serial.println((char *)(serialInputBuffer + pos)); - } + // if(debugAnsiCodes) debug_print(output,TERM_COLOR_YELLOW); + + // debug_newline(output); + // debug_print(output, F("" + // " _____ _____ _____ _____\r\n" + // " | | | _ | __| _ |\r\n" + // " | | |__ | __|\r\n" + // " |__|__|__|__|_____|__|\r\n" + // " Home Automation Switch Plate\r\n" + // " Open Hardware edition v")); + char buffer[32]; + haspGetVersion(buffer, sizeof(buffer)); +#ifdef ARDUINO + output->println(buffer); +#else + debug_print(output, buffer); + debug_newline(output); +#endif } -void debugGetHistoryLine(size_t num) +void debug_get_tag(uint8_t tag, char* buffer) { - size_t pos = debugHistoryIndex(num); - size_t len = strlen(serialInputBuffer); - char * dst = serialInputBuffer; - char * src = serialInputBuffer + pos; - size_t newlen = strlen(src); - if(len < newlen) { - // make room, shift whole buffer right - dst = serialInputBuffer + newlen - len; - src = serialInputBuffer; - memmove(dst, src, sizeof(serialInputBuffer) - newlen + len); + switch(tag) { + case TAG_MAIN: + memcpy_P(buffer, PSTR("MAIN"), 5); + break; - dst = serialInputBuffer; - memset(dst, 0, newlen); - } else { - memset(dst, 0, len); - } - dst = serialInputBuffer; - src = serialInputBuffer + pos + newlen - len; - memmove(dst, src, newlen); -} -*/ + case TAG_HASP: + memcpy_P(buffer, PSTR("HASP"), 5); + break; -static void debugPrintTimestamp(int level, Print * _logOutput) -{ /* Print Current Time */ + case TAG_DRVR: + memcpy_P(buffer, PSTR("DRVR"), 5); + break; - struct timeval tval; - struct tm * timeinfo; - int rslt; + case TAG_ATTR: + memcpy_P(buffer, PSTR("ATTR"), 5); + break; - rslt = gettimeofday(&tval, NULL); - if(rslt) { - // uint32_t msecs = millis(); - // _logOutput->printf(PSTR("[%9d.%03d]"), msecs / 1000, msecs % 1000); - } else { - timeinfo = localtime(&tval.tv_sec); - } + case TAG_MSGR: + memcpy_P(buffer, PSTR("MSGR"), 5); + break; - /* - time_t rawtime; - struct tm * timeinfo; + case TAG_OOBE: + memcpy_P(buffer, PSTR("OOBE"), 5); + break; + case TAG_HAL: + memcpy_P(buffer, PSTR("HAL "), 5); + break; - time(&rawtime); - timeinfo = localtime(&rawtime); + case TAG_DEBG: + memcpy_P(buffer, PSTR("DBUG"), 5); + break; + case TAG_TELN: + memcpy_P(buffer, PSTR("TELN"), 5); + break; + case TAG_SYSL: + memcpy_P(buffer, PSTR("SYSL"), 5); + break; + case TAG_TASM: + memcpy_P(buffer, PSTR("TASM"), 5); + break; - // strftime(buffer, sizeof(buffer), "%b %d %H:%M:%S.", timeinfo); - // Serial.println(buffer); -*/ - debugSendAnsiCode(F(TERM_COLOR_CYAN), _logOutput); + case TAG_CONF: + memcpy_P(buffer, PSTR("CONF"), 5); + break; + case TAG_GUI: + memcpy_P(buffer, PSTR("GUI "), 5); + break; + case TAG_TFT: + memcpy_P(buffer, PSTR("TFT "), 5); + break; - if(timeinfo->tm_year >= 120) { - char buffer[24]; - strftime(buffer, sizeof(buffer), "[%b %d %H:%M:%S.", timeinfo); // Literal String - // strftime(buffer, sizeof(buffer), "[%H:%M:%S.", timeinfo); // Literal String - _logOutput->print(buffer); - _logOutput->printf(PSTR("%03lu]"), tval.tv_usec / 1000); - } else { - uint32_t msecs = millis(); - _logOutput->printf(PSTR("[%15d.%03d]"), msecs / 1000, msecs % 1000); + case TAG_EPRM: + memcpy_P(buffer, PSTR("EPRM"), 5); + break; + case TAG_FILE: + memcpy_P(buffer, PSTR("FILE"), 5); + break; + case TAG_GPIO: + memcpy_P(buffer, PSTR("GPIO"), 5); + break; + + case TAG_ETH: + memcpy_P(buffer, PSTR("ETH "), 5); + break; + case TAG_WIFI: + memcpy_P(buffer, PSTR("WIFI"), 5); + break; + case TAG_HTTP: + memcpy_P(buffer, PSTR("HTTP"), 5); + break; + case TAG_MDNS: + memcpy_P(buffer, PSTR("MDNS"), 5); + break; + case TAG_MQTT: + memcpy_P(buffer, PSTR("MQTT"), 5); + break; + case TAG_MQTT_PUB: + memcpy_P(buffer, PSTR("MQTT PUB"), 9); + break; + case TAG_MQTT_RCV: + memcpy_P(buffer, PSTR("MQTT RCV"), 9); + break; + + case TAG_OTA: + memcpy_P(buffer, PSTR("OTA "), 5); + break; + case TAG_FWUP: + memcpy_P(buffer, PSTR("FWUP"), 5); + break; + + case TAG_LVGL: + memcpy_P(buffer, PSTR("LVGL"), 5); + break; + case TAG_LVFS: + memcpy_P(buffer, PSTR("LVFS"), 5); + break; + case TAG_FONT: + memcpy_P(buffer, PSTR("FONT"), 5); + break; + + default: + memcpy_P(buffer, PSTR("----"), 5); + break; } } -static void debugPrintHaspMemory(int level, Print * _logOutput) +static void debugPrintHaspMemory(int level, Print* _logOutput) { - size_t maxfree = halGetMaxFreeBlock(); - uint32_t totalfree = halGetFreeHeap(); - uint8_t frag = halGetHeapFragmentation(); +#ifdef ARDUINO + size_t maxfree = haspDevice.get_free_max_block(); + size_t totalfree = haspDevice.get_free_heap(); + uint8_t frag = haspDevice.get_heap_fragmentation(); /* Print HASP Memory Info */ if(debugAnsiCodes) { @@ -383,11 +320,12 @@ static void debugPrintHaspMemory(int level, Print * _logOutput) debugSendAnsiCode(F(TERM_COLOR_RED), _logOutput); } _logOutput->printf(PSTR("[%5u/%5u%3u]"), maxfree, totalfree, frag); +#endif } -#if LV_MEM_CUSTOM == 0 -static void debugPrintLvglMemory(int level, Print * _logOutput) +static void debugPrintLvglMemory(int level, Print* _logOutput) { +#if LV_MEM_CUSTOM == 0 lv_mem_monitor_t mem_mon; lv_mem_monitor(&mem_mon); @@ -401,17 +339,23 @@ static void debugPrintLvglMemory(int level, Print * _logOutput) else debugSendAnsiCode(F(TERM_COLOR_RED), _logOutput); } - _logOutput->printf(PSTR("[%5u/%5u%3u]"), mem_mon.free_biggest_size, mem_mon.free_size, mem_mon.frag_pct); -} -#endif -static void debugPrintPriority(int level, Print * _logOutput) +#ifdef ARDUINO + _logOutput->printf(PSTR("[%5u/%5u%3u]"), mem_mon.free_biggest_size, mem_mon.free_size, mem_mon.frag_pct); +#else + debug_print(_logOutput, PSTR("[%5u/%5u%3u]"), mem_mon.free_biggest_size, mem_mon.free_size, mem_mon.frag_pct); +#endif // ARDUINO + +#endif // LV_MEM_CUSTOM +} + +static void debugPrintPriority(int level, Print* _logOutput) { // if(_logOutput == &syslogClient) { // } switch(level) { - case LOG_LEVEL_FATAL...LOG_LEVEL_ERROR: + case LOG_LEVEL_FATAL ... LOG_LEVEL_ERROR: debugSendAnsiCode(F(TERM_COLOR_RED), _logOutput); break; case LOG_LEVEL_WARNING: @@ -435,117 +379,11 @@ static void debugPrintPriority(int level, Print * _logOutput) } } -static void debugPrintTag(uint8_t tag, Print * _logOutput) +void debugPrintPrefix(uint8_t tag, int level, Print* _logOutput) { - switch(tag) { - case TAG_MAIN: - _logOutput->print(F("MAIN")); - break; + char buffer[10]; - case TAG_HASP: - _logOutput->print(F("HASP")); - break; - - case TAG_DRVR: - _logOutput->print(F("DRVR")); - break; - - case TAG_ATTR: - _logOutput->print(F("ATTR")); - break; - - case TAG_MSGR: - _logOutput->print(F("MSGR")); - break; - - case TAG_OOBE: - _logOutput->print(F("OOBE")); - break; - case TAG_HAL: - _logOutput->print(F("HAL ")); - break; - - case TAG_DEBG: - _logOutput->print(F("DEBG")); - break; - case TAG_TELN: - _logOutput->print(F("TELN")); - break; - case TAG_SYSL: - _logOutput->print(F("SYSL")); - break; - case TAG_TASM: - _logOutput->print(F("TASM")); - break; - - case TAG_CONF: - _logOutput->print(F("CONF")); - break; - case TAG_GUI: - _logOutput->print(F("GUI ")); - break; - case TAG_TFT: - _logOutput->print(F("TFT ")); - break; - - case TAG_EPRM: - _logOutput->print(F("EPRM")); - break; - case TAG_FILE: - _logOutput->print(F("FILE")); - break; - case TAG_GPIO: - _logOutput->print(F("GPIO")); - break; - - case TAG_ETH: - _logOutput->print(F("ETH ")); - break; - case TAG_WIFI: - _logOutput->print(F("WIFI")); - break; - case TAG_HTTP: - _logOutput->print(F("HTTP")); - break; - case TAG_MDNS: - _logOutput->print(F("MDNS")); - break; - case TAG_MQTT: - _logOutput->print(F("MQTT")); - break; - case TAG_MQTT_PUB: - _logOutput->print(F("MQTT PUB")); - break; - case TAG_MQTT_RCV: - _logOutput->print(F("MQTT RCV")); - break; - - case TAG_OTA: - _logOutput->print(F("OTA")); - break; - case TAG_FWUP: - _logOutput->print(F("FWUP")); - break; - - case TAG_LVGL: - _logOutput->print(F("LVGL")); - break; - case TAG_LVFS: - _logOutput->print(F("LVFS")); - break; - case TAG_FONT: - _logOutput->print(F("FONT")); - break; - - default: - _logOutput->print(F("----")); - break; - } -} - -void debugPrintPrefix(uint8_t tag, int level, Print * _logOutput) -{ -#if HASP_USE_SYSLOG > 0 +#if 0 && HASP_USE_SYSLOG > 0 if(_logOutput == syslogClient && syslogClient) { if(syslogClient->beginPacket(debugSyslogHost, debugSyslogPort)) { @@ -561,9 +399,8 @@ void debugPrintPrefix(uint8_t tag, int level, Print * _logOutput) syslogClient->print(F("1 - ")); } - syslogClient->print(mqttGetNodename()); - syslogClient->print(F(" ")); - debugPrintTag(tag, _logOutput); + debug_get_tag(tag, buffer); + syslogClient->print(F("%s %s"), haspDevice.get_hostname(), buffer); if(debugSyslogProtocol == SYSLOG_PROTO_IETF) { syslogClient->print(F(" - - - \xEF\xBB\xBF")); // include UTF-8 BOM @@ -572,9 +409,7 @@ void debugPrintPrefix(uint8_t tag, int level, Print * _logOutput) } debugPrintHaspMemory(level, _logOutput); - #if LV_MEM_CUSTOM == 0 debugPrintLvglMemory(level, _logOutput); - #endif } return; } @@ -583,10 +418,7 @@ void debugPrintPrefix(uint8_t tag, int level, Print * _logOutput) debugSendAnsiCode(F(TERM_CLEAR_LINE), _logOutput); debugPrintTimestamp(level, _logOutput); debugPrintHaspMemory(level, _logOutput); - -#if LV_MEM_CUSTOM == 0 debugPrintLvglMemory(level, _logOutput); -#endif if(tag == TAG_MQTT_PUB && level == LOG_LEVEL_NOTICE) { debugSendAnsiCode(F(TERM_COLOR_GREEN), _logOutput); @@ -596,161 +428,10 @@ void debugPrintPrefix(uint8_t tag, int level, Print * _logOutput) debugPrintPriority(level, _logOutput); } - _logOutput->print(F(" ")); - debugPrintTag(tag, _logOutput); - _logOutput->print(F(": ")); -} - -void debugPrintSuffix(uint8_t tag, int level, Print * _logOutput) -{ -#if HASP_USE_SYSLOG > 0 - if(_logOutput == syslogClient && syslogClient) { - syslogClient->endPacket(); - return; - } + debug_get_tag(tag, buffer); +#ifdef ARDUINO + _logOutput->printf(PSTR(" %s: "), buffer); +#else + debug_print(_logOutput, PSTR(" %s: "), buffer); #endif - - if(debugAnsiCodes) - _logOutput->println(F(TERM_COLOR_RESET)); - else - _logOutput->println(); - - if(_logOutput == &Serial) { - debugConsole.update(); - } else { - _logOutput->print("hasp > "); - } -} - -void debugPreSetup(JsonObject settings) -{ - Log.begin(LOG_LEVEL_WARNING, true); - Log.setPrefix(debugPrintPrefix); // Uncomment to get timestamps as prefix - Log.setSuffix(debugPrintSuffix); // Uncomment to get newline as suffix - - uint32_t baudrate = 0; -#if HASP_USE_CONFIG > 0 - baudrate = settings[FPSTR(FP_CONFIG_BAUD)].as() * 10; -#endif - - if(baudrate == 0) baudrate = SERIAL_SPEED; - if(baudrate >= 9600u) { /* the baudrates are stored divided by 10 */ - -#if defined(STM32F4xx) - #ifndef STM32_SERIAL1 // Define what Serial port to use for log output - Serial.setRx(PA3); // User Serial2 - Serial.setTx(PA2); - #endif -#endif - Serial.begin(baudrate); /* prepare for possible serial debug */ - delay(10); - Log.registerOutput(0, &Serial, LOG_LEVEL_VERBOSE, true); // LOG_LEVEL_VERBOSE - debugSerialStarted = true; - - Serial.println(); - debugPrintHaspHeader(&Serial); - Serial.flush(); - - LOG_INFO(TAG_DEBG, F("Serial started at %u baud"), baudrate); - LOG_INFO(TAG_DEBG, F("Environment: " PIOENV)); - } -} - -#if LV_USE_LOG != 0 -void debugLvglLogEvent(lv_log_level_t level, const char * file, uint32_t line, const char * funcname, - const char * descr) -{ - /* used for duplicate detection */ - static uint32_t lastDbgLine; - static uint16_t lastDbgFreeMem; - - lv_mem_monitor_t mem_mon; - lv_mem_monitor(&mem_mon); - - /* Reduce the number of repeated debug message */ - if(line != lastDbgLine || mem_mon.free_biggest_size != lastDbgFreeMem) { - switch(level) { - case LV_LOG_LEVEL_TRACE: - LOG_VERBOSE(TAG_LVGL, descr); - break; - case LV_LOG_LEVEL_WARN: - LOG_WARNING(TAG_LVGL, descr); - break; - case LV_LOG_LEVEL_ERROR: - LOG_ERROR(TAG_LVGL, descr); - break; - default: - LOG_TRACE(TAG_LVGL, descr); - } - lastDbgLine = line; - lastDbgFreeMem = mem_mon.free_biggest_size; - } -} -#endif - -void debugLoop(void) -{ - int16_t keypress; - do { - switch(keypress = debugConsole.readKey()) { - - case ConsoleInput::KEY_PAGE_UP: - dispatch_page_next(); - break; - - case ConsoleInput::KEY_PAGE_DOWN: - dispatch_page_prev(); - break; - - case(ConsoleInput::KEY_FN)...(ConsoleInput::KEY_FN + 12): - haspSetPage(keypress - ConsoleInput::KEY_FN - 1); - break; - } - } while(keypress != 0); -} -void printLocalTime() -{ - char buffer[128]; - time_t rawtime; - struct tm * timeinfo; - - // if(!time(nullptr)) return; - - time(&rawtime); - timeinfo = localtime(&rawtime); - - strftime(buffer, sizeof(buffer), "%b %d %H:%M:%S.", timeinfo); - Serial.println(buffer); - // struct tm timeinfo; - // time_t now = time(nullptr); - - // Serial-.print(ctime(&now)); - // Serial.print(&timeinfo, " %d %B %Y %H:%M:%S "); - -#if LWIP_VERSION_MAJOR > 1 - - // LwIP v2 is able to list more details about the currently configured SNTP servers - for(int i = 0; i < SNTP_MAX_SERVERS; i++) { - IPAddress sntp = *sntp_getserver(i); - const char * name = sntp_getservername(i); - if(sntp.isSet()) { - Serial.printf("sntp%d: ", i); - if(name) { - Serial.printf("%s (%s) ", name, sntp.toString().c_str()); - } else { - Serial.printf("%s ", sntp.toString().c_str()); - } - Serial.printf("IPv6: %s Reachability: %o\n", sntp.isV6() ? "Yes" : "No", sntp_getreachability(i)); - } - } -#endif -} - -void debugEverySecond() -{ - if(debugTelePeriod > 0 && (millis() - debugLastMillis) >= debugTelePeriod * 1000) { - dispatch_output_statusupdate(NULL, NULL); - debugLastMillis = millis(); - } - // printLocalTime(); -} +} \ No newline at end of file diff --git a/src/hasp_debug.h b/src/hasp_debug.h index 0c182a04..006acb6c 100644 --- a/src/hasp_debug.h +++ b/src/hasp_debug.h @@ -1,41 +1,155 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_DEBUG_H #define HASP_DEBUG_H #include "ArduinoJson.h" -#include "ArduinoLog.h" #include "hasp_macro.h" #include "lvgl.h" #include "lang/lang.h" +#if(!defined(WINDOWS)) && (!defined(POSIX)) +#include "ArduinoLog.h" + /* ===== Default Event Processors ===== */ void debugPreSetup(JsonObject settings); void debugSetup(); -void debugLoop(void); -void debugEverySecond(void); -void debugStart(void); -void debugStop(void); /* ===== Special Event Processors ===== */ -void debugLvglLogEvent(lv_log_level_t level, const char * file, uint32_t line, const char * funcname, - const char * descr); -void debugPrintHaspHeader(Print * output); + void debugStartSyslog(void); void debugStopSyslog(void); // void syslogSend(uint8_t log, const char * debugText); -/* ===== Read/Write Configuration ===== */ -#if HASP_USE_CONFIG > 0 -bool debugGetConfig(const JsonObject & settings); -bool debugSetConfig(const JsonObject & settings); +#else + +#define Print void + +#include +#include + +#define LOG_LEVEL_SILENT -1 + +#define LOG_LEVEL_FATAL 0 +#define LOG_LEVEL_ALERT 1 +#define LOG_LEVEL_CRITICAL 2 +#define LOG_LEVEL_ERROR 3 +#define LOG_LEVEL_WARNING 4 +#define LOG_LEVEL_NOTICE 5 +#define LOG_LEVEL_INFO 5 +#define LOG_LEVEL_TRACE 6 +#define LOG_LEVEL_VERBOSE 7 +#define LOG_LEVEL_DEBUG 8 +#define LOG_LEVEL_OUTPUT 9 + +#define LOG_FATAL(x, ...) \ + debugPrintPrefix(x, LOG_LEVEL_FATAL, NULL); \ + printf(__VA_ARGS__); \ + std::cout << std::endl; \ + fflush(stdout) +#define LOG_ERROR(x, ...) \ + debugPrintPrefix(x, LOG_LEVEL_ERROR, NULL); \ + printf(__VA_ARGS__); \ + std::cout << std::endl; \ + fflush(stdout) +#define LOG_WARNING(x, ...) \ + debugPrintPrefix(x, LOG_LEVEL_WARNING, NULL); \ + printf(__VA_ARGS__); \ + std::cout << std::endl; \ + fflush(stdout) +#define LOG_NOTICE(x, ...) \ + debugPrintPrefix(x, LOG_LEVEL_NOTICE, NULL); \ + printf(__VA_ARGS__); \ + std::cout << std::endl; \ + fflush(stdout) +#define LOG_TRACE(x, ...) \ + debugPrintPrefix(x, LOG_LEVEL_TRACE, NULL); \ + printf(__VA_ARGS__); \ + std::cout << std::endl; \ + fflush(stdout) +#define LOG_VERBOSE(x, ...) \ + debugPrintPrefix(x, LOG_LEVEL_VERBOSE, NULL); \ + printf(__VA_ARGS__); \ + std::cout << std::endl; \ + fflush(stdout) +#define LOG_DEBUG(x, ...) \ + debugPrintPrefix(x, LOG_LEVEL_DEBUG, NULL); \ + printf(__VA_ARGS__); \ + std::cout << std::endl; \ + fflush(stdout) +#define LOG_INFO(x, ...) \ + debugPrintPrefix(x, LOG_LEVEL_INFO, NULL); \ + printf(__VA_ARGS__); \ + std::cout << std::endl; \ + fflush(stdout) + +/* json keys used in the configfile */ +// const char FP_CONFIG_STARTPAGE[] PROGMEM = "startpage"; +// const char FP_CONFIG_STARTDIM[] PROGMEM = "startdim"; +// const char FP_CONFIG_THEME[] PROGMEM = "theme"; +// const char FP_CONFIG_HUE[] PROGMEM = "hue"; +// const char FP_CONFIG_ZIFONT[] PROGMEM = "font"; +// const char FP_CONFIG_PAGES[] PROGMEM = "pages"; +// const char FP_CONFIG_ENABLE[] PROGMEM = "enable"; +// const char FP_CONFIG_HOST[] PROGMEM = "host"; +// const char FP_CONFIG_PORT[] PROGMEM = "port"; +// const char FP_CONFIG_NAME[] PROGMEM = "name"; +// const char FP_CONFIG_USER[] PROGMEM = "user"; +// const char FP_CONFIG_PASS[] PROGMEM = "pass"; +// const char FP_CONFIG_SSID[] PROGMEM = "ssid"; +// const char FP_CONFIG_GROUP[] PROGMEM = "group"; +// const char FP_CONFIG_BAUD[] PROGMEM = "baud"; +// const char FP_CONFIG_LOG[] PROGMEM = "log"; +// const char FP_CONFIG_PROTOCOL[] PROGMEM = "proto"; +// const char FP_GUI_ROTATION[] PROGMEM = "rotate"; +// const char FP_GUI_INVERT[] PROGMEM = "invert"; +// const char FP_GUI_TICKPERIOD[] PROGMEM = "tick"; +// const char FP_GUI_IDLEPERIOD1[] PROGMEM = "idle1"; +// const char FP_GUI_IDLEPERIOD2[] PROGMEM = "idle2"; +// const char FP_GUI_CALIBRATION[] PROGMEM = "calibration"; +// const char FP_GUI_BACKLIGHTPIN[] PROGMEM = "bckl"; +// const char FP_GUI_POINTER[] PROGMEM = "cursor"; +// const char FP_DEBUG_TELEPERIOD[] PROGMEM = "tele"; +// const char FP_GPIO_CONFIG[] PROGMEM = "config"; + +// const char FP_HASP_CONFIG_FILE[] PROGMEM = "/config.json"; + +// const char FP_WIFI[] PROGMEM = "wifi"; +// const char FP_MQTT[] PROGMEM = "mqtt"; +// const char FP_HTTP[] PROGMEM = "http"; +// const char FP_GPIO[] PROGMEM = "gpio"; +// const char FP_MDNS[] PROGMEM = "mdns"; +// const char FP_HASP[] PROGMEM = "hasp"; +// const char FP_GUI[] PROGMEM = "gui"; +// const char FP_DEBUG[] PROGMEM = "debug"; + #endif -// void debugPrintPrefix(int level, Print * _logOutput); -// void debugPrintSuffix(int level, Print * _logOutput); -// void debugSendOuput(const char * buffer); +#ifdef __cplusplus +extern "C" { +#endif + +// Functions used by ANDROID, WINDOWS and POSSIX +void debugLvglLogEvent(lv_log_level_t level, const char* file, uint32_t line, const char* funcname, const char* descr); +void debugLoop(void); +void debugEverySecond(void); +void debugStart(void); +void debugStop(void); +void debugPrintHaspHeader(Print* output); +void debugPrintTag(uint8_t tag, Print* _logOutput); +void debugPrintPrefix(uint8_t tag, int level, Print* _logOutput); + +#ifdef __cplusplus +} +#endif + +/* ===== Read/Write Configuration ===== */ +#if HASP_USE_CONFIG > 0 +bool debugGetConfig(const JsonObject& settings); +bool debugSetConfig(const JsonObject& settings); +#endif enum { TAG_MAIN = 0, @@ -45,6 +159,7 @@ enum { TAG_OOBE = 4, TAG_HAL = 5, TAG_DRVR = 6, + TAG_DEV = 7, TAG_DEBG = 10, TAG_TELN = 11, @@ -75,4 +190,17 @@ enum { TAG_FONT = 92 }; +//#define TERM_COLOR_Black "\u001b[30m" +#define TERM_COLOR_GRAY "\e[37m" +#define TERM_COLOR_RED "\e[91m" +#define TERM_COLOR_GREEN "\e[92m" +#define TERM_COLOR_ORANGE "\e[38;5;214m" +#define TERM_COLOR_YELLOW "\e[93m" +#define TERM_COLOR_BLUE "\e[94m" +#define TERM_COLOR_MAGENTA "\e[35m" +#define TERM_COLOR_CYAN "\e[96m" +#define TERM_COLOR_WHITE "\e[97m" +#define TERM_COLOR_RESET "\e[0m" +#define TERM_CLEAR_LINE "\e[1000D\e[0K" + #endif diff --git a/src/hasp_eeprom.cpp b/src/hasp_eeprom.cpp index 7faa5527..fdb02824 100644 --- a/src/hasp_eeprom.cpp +++ b/src/hasp_eeprom.cpp @@ -1,7 +1,14 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ -#include +#include "hasp_conf.h" // load first + +#if HASP_USE_EEPROM > 0 + +#ifdef ARDUINO +#include "Arduino.h" +#endif + #include "EEPROM.h" void eepromSetup() @@ -9,12 +16,13 @@ void eepromSetup() #if defined(STM32Fxx) eeprom_buffer_fill(); - char buffer[] = "{\"objid\":10,\"id\":1,\"page\":0,\"x\":10,\"y\":45,\"w\":220,\"h\":55,\"toggle\":\"TRUE\",\"txt\":\"Toggle Me\"}"; + char buffer[] = "{\"objid\":10,\"id\":1,\"page\":0,\"x\":10,\"y\":45,\"w\":220,\"h\":55,\"toggle\":\"TRUE\"," + "\"txt\":\"Toggle Me\"}"; uint size = strlen(buffer); uint16_t i; - for(i = 0; i < size; i++) eeprom_buffered_write_byte(i+4096, buffer[i]); - eeprom_buffered_write_byte(i+4096, 0); - // eeprom_buffer_flush(); + for(i = 0; i < size; i++) eeprom_buffered_write_byte(i + 4096, buffer[i]); + eeprom_buffered_write_byte(i + 4096, 0); + // eeprom_buffer_flush(); #endif // ESP8266 // Don't start at boot, only at write @@ -23,4 +31,6 @@ void eepromSetup() } void eepromLoop() -{} \ No newline at end of file +{} + +#endif \ No newline at end of file diff --git a/src/hasp_eeprom.h b/src/hasp_eeprom.h index c2d83d22..db8d40bd 100644 --- a/src/hasp_eeprom.h +++ b/src/hasp_eeprom.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_EEPROM_H @@ -8,7 +8,7 @@ void eepromSetup(void); void eepromLoop(void); -void eepromWrite(uint16_t addr, std::string & data); +void eepromWrite(uint16_t addr, std::string& data); std::string eepromRead(uint16_t addr); #endif \ No newline at end of file diff --git a/src/hasp_filesystem.cpp b/src/hasp_filesystem.cpp index a4544532..6a014e7d 100644 --- a/src/hasp_filesystem.cpp +++ b/src/hasp_filesystem.cpp @@ -1,11 +1,14 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ +#include "hasp_conf.h" // include first + +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 + #include #include "ArduinoJson.h" #include "ArduinoLog.h" -#include "hasp_conf.h" #include "hasp_debug.h" #include "hasp_filesystem.h" @@ -15,7 +18,7 @@ void filesystemInfo() FSInfo fs_info; SPIFFS.info(fs_info); - Serial.println("File sistem info."); + Serial.println("File system info."); Serial.print("Total space: "); Serial.print(fs_info.totalBytes); @@ -99,7 +102,7 @@ bool filesystemSetup(void) { // no SPIFFS settings, as settings depend on SPIFFS // no Logging, because it depends on the configuration file - + // Logging is defered until debugging has started // FS success or failure is printed at that time ! @@ -118,4 +121,6 @@ bool filesystemSetup(void) #endif return false; -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/hasp_filesystem.h b/src/hasp_filesystem.h index ed3b773b..bda556ed 100644 --- a/src/hasp_filesystem.h +++ b/src/hasp_filesystem.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_FILESYSTEM_H @@ -12,22 +12,22 @@ void filesystemList(); void filesystemInfo(); #if defined(ARDUINO_ARCH_ESP32) - #if HASP_USE_SPIFFS > 0 - #include "SPIFFS.h" - #define HASP_FS SPIFFS - #elif HASP_USE_LITTLEFS > 0 - #include "LITTLEFS.h" - #define HASP_FS LITTLEFS - #endif +#if HASP_USE_SPIFFS > 0 +#include "SPIFFS.h" +#define HASP_FS SPIFFS +#elif HASP_USE_LITTLEFS > 0 +#include "LITTLEFS.h" +#define HASP_FS LITTLEFS +#endif #elif defined(ARDUINO_ARCH_ESP8266) - // included by default - #include - #define HASP_FS LittleFS +// included by default +#include +#define HASP_FS LittleFS #endif // ARDUINO_ARCH #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - #include - #include +#include +#include #endif // ARDUINO_ARCH #endif // HASP_FILESYSTEM_H \ No newline at end of file diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 6fd4af36..1ae15dd1 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #include "hasp_conf.h" @@ -12,23 +12,26 @@ #include "lv_fs_if.h" // Device Drivers -#include "drv/hasp_drv_display.h" +#include "drv/tft_driver.h" +#include "dev/device.h" + +//#include "drv/hasp_drv_display.h" #include "drv/hasp_drv_touch.h" +#include "drv/tft_espi_drv.h" #include "hasp_debug.h" #include "hasp_config.h" #include "hasp_gui.h" #include "hasp_oobe.h" -#include "hasp/hasp_dispatch.h" -#include "hasp/hasp.h" +#include "hasplib.h" //#include "tpcal.h" //#include "Ticker.h" #if HASP_USE_PNGDECODE > 0 - #include "png_decoder.h" +#include "png_decoder.h" #endif #define BACKLIGHT_CHANNEL 0 // pwm channel 0-15 @@ -40,25 +43,25 @@ File pFileOut; #define LVGL_TICK_PERIOD 20 #ifndef TFT_BCKL - #define TFT_BCKL -1 // No Backlight Control +#define TFT_BCKL -1 // No Backlight Control #endif #ifndef TFT_ROTATION - #define TFT_ROTATION 0 +#define TFT_ROTATION 0 #endif #ifndef INVERT_COLORS - #define INVERT_COLORS 0 +#define INVERT_COLORS 0 #endif // static void IRAM_ATTR lv_tick_handler(void); -static bool guiShowPointer = false; -static bool guiBacklightIsOn = true; -static int8_t guiDimLevel = -1; -static int8_t guiBacklightPin = TFT_BCKL; -static uint8_t guiTickPeriod = 20; -static uint8_t guiRotation = TFT_ROTATION; -static uint8_t guiInvertDisplay = INVERT_COLORS; -static uint16_t calData[5] = {0, 65535, 0, 65535, 0}; +gui_conf_t gui_settings = {.show_pointer = false, + .backlight_pin = TFT_BCKL, + .rotation = TFT_ROTATION, + .invert_display = INVERT_COLORS, + .cal_data = {0, 65535, 0, 65535, 0}}; + +// static int8_t guiDimLevel = 100; +// bool guiBacklightIsOn; // #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) // static Ticker tick; /* timer for interrupt handler */ @@ -73,163 +76,20 @@ static uint16_t calData[5] = {0, 65535, 0, 65535, 0}; // { // lv_tick_inc(LVGL_TICK_PERIOD); // } - -/* Reading input device (simulated encoder here) */ -/*bool read_encoder(lv_indev_drv_t * indev, lv_indev_data_t * data) +void gui_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) { - static int32_t last_diff = 0; - int32_t diff = 0; // Dummy - no movement - int btn_state = LV_INDEV_STATE_REL; // Dummy - no press - - data->enc_diff = diff - last_diff; - data->state = btn_state; - last_diff = diff; - return false; -}*/ - -// #define _RAWERR 20 // Deadband error allowed in successive position samples -// uint8_t validTouch(uint16_t * x, uint16_t * y, uint16_t threshold) -// { -// uint16_t x_tmp, y_tmp, x_tmp2, y_tmp2; - -// // Wait until pressure stops increasing to debounce pressure -// uint16_t z1 = 1; -// uint16_t z2 = 0; -// while(z1 > z2) { -// z2 = z1; -// z1 = tft.getTouchRawZ(); -// delay(1); -// } - -// // Serial.print("Z = ");Serial.println(z1); - -// if(z1 <= threshold) return false; - -// tft.getTouchRaw(&x_tmp, &y_tmp); - -// // Serial.print("Sample 1 x,y = "); Serial.print(x_tmp);Serial.print(",");Serial.print(y_tmp); -// // Serial.print(", Z = ");Serial.println(z1); - -// delay(1); // Small delay to the next sample -// if(tft.getTouchRawZ() <= threshold) return false; - -// delay(2); // Small delay to the next sample -// tft.getTouchRaw(&x_tmp2, &y_tmp2); - -// // Serial.print("Sample 2 x,y = "); Serial.print(x_tmp2);Serial.print(",");Serial.println(y_tmp2); -// // Serial.print("Sample difference = ");Serial.print(abs(x_tmp - -// // x_tmp2));Serial.print(",");Serial.println(abs(y_tmp - y_tmp2)); - -// if(abs(x_tmp - x_tmp2) > _RAWERR) return false; -// if(abs(y_tmp - y_tmp2) > _RAWERR) return false; - -// *x = x_tmp; -// *y = y_tmp; - -// return true; -// } - -// bool gui_touchpad_read_raw(lv_indev_drv_t * indev_driver, lv_indev_data_t * data) -// { -// #ifdef TOUCH_CS -// uint16_t touchX, touchY; - -// bool touched = validTouch(&touchX, &touchY, 600u / 2); -// if(!touched) return false; - -// // if(touchCounter < 255) { -// // touchCounter++; - -// // // Store the raw touches -// // if(touchCounter >= 8) { -// // touchPoints[touchCorner].x /= touchCounter; -// // touchPoints[touchCorner].y /= touchCounter; -// // touchCounter = 255; -// // } else { -// // touchPoints[touchCorner].x += touchX; -// // touchPoints[touchCorner].y += touchY; -// // } -// // } - -// if(sleep_state > 0) hasp_update_sleep_state(); // update Idle - -// /*Save the state and save the pressed coordinate*/ -// // lv_disp_t * disp = lv_disp_get_default(); -// data->state = touched ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; -// data->point.x = touchX; // 20 + (disp->driver.hor_res - 40) * (touchCorner % 2); -// data->point.y = touchY; // 20 + (disp->driver.ver_res - 40) * (touchCorner / 2); - -// LOG_VERBOSE(TAG_GUI,F("Calibrate touch %u / %u"), touchX, touchY); - -// #endif - -// return false; /*Return `false` because we are not buffering and no more data to read*/ -// } - -#if TOUCH_DRIVER == 0xADC // Analog Digital Touch Conroller - #include "Touchscreen.h" // For Uno Shield or ADC based resistive touchscreens - -boolean Touch_getXY(uint16_t * x, uint16_t * y, boolean showTouch) -{ - static const int coords[] = {3800, 500, 300, 3800}; // portrait - left, right, top, bottom - static const int XP = 27, XM = 15, YP = 4, YM = 14; // default ESP32 Uno touchscreen pins - static TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); - TSPoint p = ts.getPoint(); - int z1 = analogRead(aXM); - int z2 = analogRead(aYP); - Serial.print(p.x); - Serial.print(" - "); - Serial.print(p.y); - Serial.print(" - "); - Serial.print(p.z); - Serial.print(" - "); - Serial.print(z1); - Serial.print(" - "); - Serial.println(z2); - - pinMode(aYP, OUTPUT); // restore shared pins - pinMode(aXM, OUTPUT); - digitalWrite(aYP, HIGH); // because TFT control pins - digitalWrite(aXM, HIGH); - // adjust pressure sensitivity - note works 'backwards' - #define MINPRESSURE 200 - #define MAXPRESSURE 1000 - bool pressed = (p.z > MINPRESSURE && p.z < MAXPRESSURE); - if(pressed) { - - switch(guiRotation) { - case 0: // portrait - *x = map(p.x, coords[0], coords[1], 0, tft.width()); - *y = map(p.y, coords[2], coords[3], 0, tft.height()); - break; - case 1: // landscape - *x = map(p.y, coords[1], coords[0], 0, tft.width()); - *y = map(p.x, coords[2], coords[3], 0, tft.height()); - break; - case 2: // portrait inverted - *x = map(p.x, coords[1], coords[0], 0, tft.width()); - *y = map(p.y, coords[3], coords[2], 0, tft.height()); - break; - case 3: // landscape inverted - *x = map(p.y, coords[0], coords[1], 0, tft.width()); - *y = map(p.x, coords[3], coords[2], 0, tft.height()); - break; - } - // if(showTouch) tft.fillCircle(*x, *y, 2, YELLOW); - } - return pressed; + haspTft.flush_pixels(disp, area, color_p); } -#endif -void guiCalibrate() +void guiCalibrate(void) { #if TOUCH_DRIVER == 2046 && USE_TFT_ESPI > 0 - #ifdef TOUCH_CS - tft_espi_calibrate(calData); - #endif +#ifdef TOUCH_CS + tft_espi_calibrate(gui_settings.cal_data); +#endif for(int i = 0; i < 5; i++) { - Serial.print(calData[i]); + Serial.print(gui_settings.cal_data[i]); if(i < 4) Serial.print(", "); } @@ -238,43 +98,59 @@ void guiCalibrate() #endif } -void guiSetup() +void guiSetup(void) { - /* Initialize the Virtual Device Buffers */ -#if defined(ARDUINO_ARCH_ESP32) - /* allocate on iram (or psram ?) */ + // Register logger to capture lvgl_init output + LOG_TRACE(TAG_LVGL, F(D_SERVICE_STARTING)); +#if LV_USE_LOG != 0 + lv_log_register_print_cb(debugLvglLogEvent); +#endif - #ifdef USE_DMA_TO_TFT - static lv_disp_buf_t disp_buf; + // Initialize the TFT + haspTft.init(240, 320); + haspTft.set_rotation(gui_settings.rotation); + haspTft.set_invert(gui_settings.invert_display); + haspTft.show_info(); + + /* Create the Virtual Device Buffers */ +#if defined(ARDUINO_ARCH_ESP32) + +#ifdef USE_DMA_TO_TFT static lv_color_t *guiVdbBuffer1, *guiVdbBuffer2 = NULL; // DMA: len must be less than 32767 - size_t guiVDBsize = 15 * 1024u; // 30 KBytes - guiVdbBuffer1 = (lv_color_t *)heap_caps_calloc(guiVDBsize, sizeof(lv_color_t), MALLOC_CAP_DMA); - // guiVdbBuffer2 = (lv_color_t *)heap_caps_malloc(sizeof(lv_color_t) * guiVDBsize, MALLOC_CAP_DMA); - // lv_disp_buf_init(&disp_buf, guiVdbBuffer1, guiVdbBuffer2, guiVDBsize); - #else - static lv_color_t * guiVdbBuffer1; - size_t guiVDBsize = 16 * 1024u; // 32 KBytes + const size_t guiVDBsize = 15 * 1024u; // 30 KBytes + guiVdbBuffer1 = (lv_color_t*)heap_caps_calloc(guiVDBsize, sizeof(lv_color_t), MALLOC_CAP_DMA); + // guiVdbBuffer2 = (lv_color_t *)heap_caps_malloc(sizeof(lv_color_t) * guiVDBsize, MALLOC_CAP_DMA); + // lv_disp_buf_init(&disp_buf, guiVdbBuffer1, guiVdbBuffer2, guiVDBsize); +#else + static lv_color_t* guiVdbBuffer1; + const size_t guiVDBsize = 16 * 1024u; // 32 KBytes if(0 && psramFound()) { - guiVdbBuffer1 = (lv_color_t *)ps_calloc(guiVDBsize, sizeof(lv_color_t)); // too slow for VDB + guiVdbBuffer1 = (lv_color_t*)ps_calloc(guiVDBsize, sizeof(lv_color_t)); // too slow for VDB } else { - guiVdbBuffer1 = (lv_color_t *)calloc(guiVDBsize, sizeof(lv_color_t)); + guiVdbBuffer1 = (lv_color_t*)calloc(guiVDBsize, sizeof(lv_color_t)); } - #endif +#endif // static lv_color_t * guiVdbBuffer2 = (lv_color_t *)malloc(sizeof(lv_color_t) * guiVDBsize); // lv_disp_buf_init(&disp_buf, guiVdbBuffer1, guiVdbBuffer2, guiVDBsize); + #elif defined(ARDUINO_ARCH_ESP8266) /* allocate on heap */ // static lv_color_t guiVdbBuffer1[2 * 512u]; // 4 KBytes // size_t guiVDBsize = sizeof(guiVdbBuffer1) / sizeof(guiVdbBuffer1[0]); // lv_disp_buf_init(&disp_buf, guiVdbBuffer1, NULL, guiVDBsize); - static lv_color_t * guiVdbBuffer1; - size_t guiVDBsize = 2 * 512u; // 4 KBytes * 2 - guiVdbBuffer1 = (lv_color_t *)malloc(sizeof(lv_color_t) * guiVDBsize); + static lv_color_t* guiVdbBuffer1; + const size_t guiVDBsize = 2 * 512u; // 4 KBytes * 2 + guiVdbBuffer1 = (lv_color_t*)malloc(sizeof(lv_color_t) * guiVDBsize); + +#elif defined(WINDOWS) || defined(POSIX) + const size_t guiVDBsize = LV_HOR_RES_MAX * 10; + static lv_color_t guiVdbBuffer1[guiVDBsize]; /*Declare a buffer for 10 lines*/ + #else static lv_color_t guiVdbBuffer1[16 * 512u]; // 16 KBytes // static lv_color_t guiVdbBuffer2[16 * 512u]; // 16 KBytes @@ -282,18 +158,43 @@ void guiSetup() // lv_disp_buf_init(&disp_buf, guiVdbBuffer1, guiVdbBuffer2, guiVDBsize); #endif - if(!guiVdbBuffer1) { - LOG_ERROR(TAG_GUI, F("Gram out of memory")); + /* Initialize lvgl */ + static lv_disp_buf_t disp_buf; + if(guiVdbBuffer1 && guiVDBsize > 0) { + lv_init(); + lv_disp_buf_init(&disp_buf, guiVdbBuffer1, NULL, guiVDBsize); + } else { + LOG_FATAL(TAG_GUI, F(D_ERROR_OUT_OF_MEMORY)); } - static lv_disp_buf_t disp_buf; - lv_init(); - lv_disp_buf_init(&disp_buf, guiVdbBuffer1, NULL, guiVDBsize); + /* Initialize the display driver */ + static lv_disp_drv_t disp_drv; + lv_disp_drv_init(&disp_drv); + disp_drv.buffer = &disp_buf; + disp_drv.flush_cb = gui_flush_cb; + disp_drv.hor_res = TFT_WIDTH; + disp_drv.ver_res = TFT_HEIGHT; + lv_disp_t* display = lv_disp_drv_register(&disp_drv); - /* Initialize Filesystems */ + switch(gui_settings.rotation) { + case 1: + case 3: + case 5: + case 7: + lv_disp_set_rotation(display, LV_DISP_ROT_90); + break; + default: + lv_disp_set_rotation(display, LV_DISP_ROT_NONE); + } + + /* Initialize Filesystems */ #if LV_USE_FS_IF != 0 - _lv_fs_init(); // lvgl File System + // _lv_fs_init(); // lvgl File System -- not neaded, it done in lv_init() when LV_USE_FILESYSTEM is set + LOG_VERBOSE(TAG_LVGL, F("Filesystem : Enabled")); lv_fs_if_init(); // auxilary file system drivers + filesystem_list_path("S:/fs/"); +#else + LOG_VERBOSE(TAG_LVGL, F("Filesystem : Disabled")); #endif /* Initialize PNG decoder */ @@ -308,17 +209,7 @@ void guiSetup() #endif /* Setup Backlight Control Pin */ - if(guiBacklightPin >= 0) { - LOG_VERBOSE(TAG_GUI, F("Backlight : Pin %d"), guiBacklightPin); - -#if defined(ARDUINO_ARCH_ESP32) - ledcSetup(BACKLIGHT_CHANNEL, 20000, 12); - ledcAttachPin(guiBacklightPin, BACKLIGHT_CHANNEL); -#elif defined(ARDUINO_ARCH_ESP8266) - pinMode(guiBacklightPin, OUTPUT); -#endif - } - LOG_VERBOSE(TAG_GUI, F("Rotation : %d"), guiRotation); + haspDevice.set_backlight_pin(gui_settings.backlight_pin); LOG_VERBOSE(TAG_LVGL, F("Version : %u.%u.%u %s"), LVGL_VERSION_MAJOR, LVGL_VERSION_MINOR, LVGL_VERSION_PATCH, PSTR(LVGL_VERSION_INFO)); @@ -328,62 +219,27 @@ void guiSetup() #endif LOG_VERBOSE(TAG_LVGL, F("VFB size : %d"), (size_t)sizeof(lv_color_t) * guiVDBsize); -#if LV_USE_LOG != 0 - LOG_TRACE(TAG_LVGL, F("Registering lvgl logging handler")); - lv_log_register_print_cb(debugLvglLogEvent); -#endif - - /* Initialize the display driver */ - lv_disp_drv_t disp_drv; - lv_disp_drv_init(&disp_drv); - drv_display_init(&disp_drv, guiRotation, guiInvertDisplay); // Set display driver callback & rotation - disp_drv.buffer = &disp_buf; - - if(guiRotation == 0 || guiRotation == 2 || guiRotation == 4 || guiRotation == 6) { - /* 1/3=Landscape or 0/2=Portrait orientation */ - // Normal width & height - disp_drv.hor_res = TFT_WIDTH; - disp_drv.ver_res = TFT_HEIGHT; - } else { - // Swapped width & height - disp_drv.hor_res = TFT_HEIGHT; - disp_drv.ver_res = TFT_WIDTH; - } - lv_disp_drv_register(&disp_drv); - - /* Initialize Global progress bar*/ - lv_obj_t * bar = lv_bar_create(lv_layer_sys(), NULL); - lv_obj_set_hidden(bar, true); - lv_bar_set_range(bar, 0, 100); - lv_bar_set_value(bar, 10, LV_ANIM_OFF); - lv_obj_set_size(bar, 200, 15); - lv_obj_align(bar, lv_layer_sys(), LV_ALIGN_CENTER, 0, -10); - lv_obj_user_data_t udata = (lv_obj_user_data_t){10, 0, 10}; - lv_obj_set_user_data(bar, udata); - lv_obj_set_style_local_value_color(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_obj_set_style_local_value_align(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_ALIGN_CENTER); - lv_obj_set_style_local_value_ofs_y(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, 20); - lv_obj_set_style_local_value_font(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_FONT_DEFAULT); - lv_obj_set_style_local_bg_color(lv_layer_sys(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - lv_obj_set_style_local_bg_opa(lv_layer_sys(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0); - /* Initialize the touch pad */ - lv_indev_drv_t indev_drv; + static lv_indev_drv_t indev_drv; lv_indev_drv_init(&indev_drv); - indev_drv.type = LV_INDEV_TYPE_POINTER; - indev_drv.read_cb = drv_touch_read; - lv_indev_t * mouse_indev = lv_indev_drv_register(&indev_drv); + indev_drv.type = LV_INDEV_TYPE_POINTER; +#if defined(WINDOWS) || defined(POSIX) + indev_drv.read_cb = mouse_read; +#else + indev_drv.read_cb = drv_touch_read; +#endif + lv_indev_t* mouse_indev = lv_indev_drv_register(&indev_drv); mouse_indev->driver.type = LV_INDEV_TYPE_POINTER; /*Set a cursor for the mouse*/ - if(guiShowPointer) { + if(gui_settings.show_pointer) { // lv_obj_t * label = lv_label_create(lv_layer_sys(), NULL); // lv_label_set_text(label, "<"); // lv_indev_set_cursor(mouse_indev, label); // connect the object to the driver LOG_TRACE(TAG_GUI, F("Initialize Cursor")); - lv_obj_t * cursor; - lv_obj_t * mouse_layer = lv_disp_get_layer_sys(NULL); // default display + lv_obj_t* cursor; + lv_obj_t* mouse_layer = lv_disp_get_layer_sys(NULL); // default display #if defined(ARDUINO_ARCH_ESP32) LV_IMG_DECLARE(mouse_cursor_icon); /*Declare the image file.*/ @@ -398,7 +254,26 @@ void guiSetup() #endif lv_indev_set_cursor(mouse_indev, cursor); /*Connect the image object to the driver*/ } - drv_touch_init(guiRotation); // Touch driver + +#if !(defined(WINDOWS) || defined(POSIX)) + drv_touch_init(gui_settings.rotation); // Touch driver +#endif + + /* Initialize Global progress bar*/ + lv_obj_user_data_t udata = (lv_obj_user_data_t){10, 0, 10}; + lv_obj_t* bar = lv_bar_create(lv_layer_sys(), NULL); + lv_obj_set_user_data(bar, udata); + lv_obj_set_hidden(bar, true); + lv_bar_set_range(bar, 0, 100); + lv_bar_set_value(bar, 10, LV_ANIM_OFF); + lv_obj_set_size(bar, 200, 15); + lv_obj_align(bar, lv_layer_sys(), LV_ALIGN_CENTER, 0, -10); + lv_obj_set_style_local_value_color(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_value_align(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_ALIGN_CENTER); + lv_obj_set_style_local_value_ofs_y(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, 20); + lv_obj_set_style_local_value_font(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_FONT_DEFAULT); + lv_obj_set_style_local_bg_color(lv_layer_sys(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_obj_set_style_local_bg_opa(lv_layer_sys(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0); // guiStart(); // Ticker } @@ -409,8 +284,9 @@ void guiLoop(void) // tick.update(); #endif - lv_task_handler(); // process animations - drv_touch_loop(); // update touch +#if !(defined(WINDOWS) || defined(POSIX)) + drv_touch_loop(); // update touch +#endif } void guiEverySecond(void) @@ -438,66 +314,17 @@ void guiStop() // #endif } -//////////////////////////////////////////////////////////////////////////////////////////////////// -bool guiGetBacklight() -{ - return guiBacklightIsOn; -} - -void guiSetBacklight(bool lighton) -{ - guiBacklightIsOn = lighton; - -if(!lighton) hasp_enable_wakeup_touch(); - - if(guiBacklightPin >= 0) { - -#if defined(ARDUINO_ARCH_ESP32) - ledcWrite(BACKLIGHT_CHANNEL, lighton ? map(guiDimLevel, 0, 100, 0, 4095) : 0); // ledChannel and value -#else - analogWrite(guiBacklightPin, lighton ? map(guiDimLevel, 0, 100, 0, 1023) : 0); -#endif - - } else { - guiBacklightIsOn = true; - } -} - -void guiSetDim(int8_t level) -{ - if(guiBacklightPin >= 0) { - guiDimLevel = level >= 0 ? level : 0; - guiDimLevel = guiDimLevel <= 100 ? guiDimLevel : 100; - - if(guiBacklightIsOn) { // The backlight is ON -#if defined(ARDUINO_ARCH_ESP32) - ledcWrite(BACKLIGHT_CHANNEL, map(guiDimLevel, 0, 100, 0, 4095)); // ledChannel and value -#else - analogWrite(guiBacklightPin, map(guiDimLevel, 0, 100, 0, 1023)); -#endif - } - - } else { - guiDimLevel = -1; - } -} - -int8_t guiGetDim() -{ - return guiDimLevel; -} - //////////////////////////////////////////////////////////////////////////////////////////////////// #if HASP_USE_CONFIG > 0 -bool guiGetConfig(const JsonObject & settings) +bool guiGetConfig(const JsonObject& settings) { bool changed = false; uint16_t guiSleepTime1; uint16_t guiSleepTime2; hasp_get_sleep_time(guiSleepTime1, guiSleepTime2); - if(guiTickPeriod != settings[FPSTR(FP_GUI_TICKPERIOD)].as()) changed = true; - settings[FPSTR(FP_GUI_TICKPERIOD)] = guiTickPeriod; + // if(guiTickPeriod != settings[FPSTR(FP_GUI_TICKPERIOD)].as()) changed = true; + // settings[FPSTR(FP_GUI_TICKPERIOD)] = guiTickPeriod; if(guiSleepTime1 != settings[FPSTR(FP_GUI_IDLEPERIOD1)].as()) changed = true; settings[FPSTR(FP_GUI_IDLEPERIOD1)] = guiSleepTime1; @@ -505,32 +332,32 @@ bool guiGetConfig(const JsonObject & settings) if(guiSleepTime2 != settings[FPSTR(FP_GUI_IDLEPERIOD2)].as()) changed = true; settings[FPSTR(FP_GUI_IDLEPERIOD2)] = guiSleepTime2; - if(guiBacklightPin != settings[FPSTR(FP_GUI_BACKLIGHTPIN)].as()) changed = true; - settings[FPSTR(FP_GUI_BACKLIGHTPIN)] = guiBacklightPin; + if(gui_settings.backlight_pin != settings[FPSTR(FP_GUI_BACKLIGHTPIN)].as()) changed = true; + settings[FPSTR(FP_GUI_BACKLIGHTPIN)] = gui_settings.backlight_pin; - if(guiRotation != settings[FPSTR(FP_GUI_ROTATION)].as()) changed = true; - settings[FPSTR(FP_GUI_ROTATION)] = guiRotation; + if(gui_settings.rotation != settings[FPSTR(FP_GUI_ROTATION)].as()) changed = true; + settings[FPSTR(FP_GUI_ROTATION)] = gui_settings.rotation; - if(guiShowPointer != settings[FPSTR(FP_GUI_POINTER)].as()) changed = true; - settings[FPSTR(FP_GUI_POINTER)] = guiShowPointer; + if(gui_settings.show_pointer != settings[FPSTR(FP_GUI_POINTER)].as()) changed = true; + settings[FPSTR(FP_GUI_POINTER)] = gui_settings.show_pointer; - if(guiInvertDisplay != settings[FPSTR(FP_GUI_INVERT)].as()) changed = true; - settings[FPSTR(FP_GUI_INVERT)] = guiInvertDisplay; + if(gui_settings.invert_display != settings[FPSTR(FP_GUI_INVERT)].as()) changed = true; + settings[FPSTR(FP_GUI_INVERT)] = gui_settings.invert_display; /* Check CalData array has changed */ JsonArray array = settings[FPSTR(FP_GUI_CALIBRATION)].as(); uint8_t i = 0; for(JsonVariant v : array) { - LOG_VERBOSE(TAG_GUI, F("GUI CONF: %d: %d <=> %d"), i, calData[i], v.as()); + LOG_VERBOSE(TAG_GUI, F("GUI CONF: %d: %d <=> %d"), i, gui_settings.cal_data[i], v.as()); if(i < 5) { - if(calData[i] != v.as()) changed = true; - v.set(calData[i]); + if(gui_settings.cal_data[i] != v.as()) changed = true; + v.set(gui_settings.cal_data[i]); } else { changed = true; - #if TOUCH_DRIVER == 2046 && USE_TFT_ESPI > 0 && defined(TOUCH_CS) - tft_espi_set_touch(calData); - #endif +#if TOUCH_DRIVER == 2046 && USE_TFT_ESPI > 0 && defined(TOUCH_CS) + tft_espi_set_touch(gui_settings.cal_data); +#endif } i++; } @@ -539,13 +366,13 @@ bool guiGetConfig(const JsonObject & settings) if(i != 5) { array = settings[FPSTR(FP_GUI_CALIBRATION)].to(); // Clear JsonArray for(int i = 0; i < 5; i++) { - array.add(calData[i]); + array.add(gui_settings.cal_data[i]); } changed = true; - #if TOUCH_DRIVER == 2046 && USE_TFT_ESPI > 0 && defined(TOUCH_CS) - tft_espi_set_touch(calData); - #endif +#if TOUCH_DRIVER == 2046 && USE_TFT_ESPI > 0 && defined(TOUCH_CS) + tft_espi_set_touch(gui_settings.cal_data); +#endif } if(changed) configOutput(settings, TAG_GUI); @@ -560,7 +387,7 @@ bool guiGetConfig(const JsonObject & settings) * * @param[in] settings JsonObject with the config settings. **/ -bool guiSetConfig(const JsonObject & settings) +bool guiSetConfig(const JsonObject& settings) { configOutput(settings, TAG_GUI); bool changed = false; @@ -569,22 +396,22 @@ bool guiSetConfig(const JsonObject & settings) hasp_get_sleep_time(guiSleepTime1, guiSleepTime2); - changed |= configSet(guiTickPeriod, settings[FPSTR(FP_GUI_TICKPERIOD)], F("guiTickPeriod")); - changed |= configSet(guiBacklightPin, settings[FPSTR(FP_GUI_BACKLIGHTPIN)], F("guiBacklightPin")); + // changed |= configSet(guiTickPeriod, settings[FPSTR(FP_GUI_TICKPERIOD)], F("guiTickPeriod")); + changed |= configSet(gui_settings.backlight_pin, settings[FPSTR(FP_GUI_BACKLIGHTPIN)], F("guiBacklightPin")); changed |= configSet(guiSleepTime1, settings[FPSTR(FP_GUI_IDLEPERIOD1)], F("guiSleepTime1")); changed |= configSet(guiSleepTime2, settings[FPSTR(FP_GUI_IDLEPERIOD2)], F("guiSleepTime2")); - changed |= configSet(guiRotation, settings[FPSTR(FP_GUI_ROTATION)], F("guiRotation")); - changed |= configSet(guiInvertDisplay, settings[FPSTR(FP_GUI_INVERT)], F("guiInvertDisplay")); + changed |= configSet(gui_settings.rotation, settings[FPSTR(FP_GUI_ROTATION)], F("gui_settings.rotation")); + changed |= configSet(gui_settings.invert_display, settings[FPSTR(FP_GUI_INVERT)], F("guiInvertDisplay")); hasp_set_sleep_time(guiSleepTime1, guiSleepTime2); if(!settings[FPSTR(FP_GUI_POINTER)].isNull()) { - if(guiShowPointer != settings[FPSTR(FP_GUI_POINTER)].as()) { + if(gui_settings.show_pointer != settings[FPSTR(FP_GUI_POINTER)].as()) { LOG_VERBOSE(TAG_GUI, F("guiShowPointer set")); } - changed |= guiShowPointer != settings[FPSTR(FP_GUI_POINTER)].as(); + changed |= gui_settings.show_pointer != settings[FPSTR(FP_GUI_POINTER)].as(); - guiShowPointer = settings[FPSTR(FP_GUI_POINTER)].as(); + gui_settings.show_pointer = settings[FPSTR(FP_GUI_POINTER)].as(); } if(!settings[FPSTR(FP_GUI_CALIBRATION)].isNull()) { @@ -594,24 +421,26 @@ bool guiSetConfig(const JsonObject & settings) JsonArray array = settings[FPSTR(FP_GUI_CALIBRATION)].as(); for(JsonVariant v : array) { if(i < 5) { - if(calData[i] != v.as()) status = true; - calData[i] = v.as(); + if(gui_settings.cal_data[i] != v.as()) status = true; + gui_settings.cal_data[i] = v.as(); } i++; } - if(calData[0] != 0 || calData[1] != 65535 || calData[2] != 0 || calData[3] != 65535) { - LOG_VERBOSE(TAG_GUI, F("calData set [%u, %u, %u, %u, %u]"), calData[0], calData[1], calData[2], calData[3], - calData[4]); + if(gui_settings.cal_data[0] != 0 || gui_settings.cal_data[1] != 65535 || gui_settings.cal_data[2] != 0 || + gui_settings.cal_data[3] != 65535) { + LOG_VERBOSE(TAG_GUI, F("calData set [%u, %u, %u, %u, %u]"), gui_settings.cal_data[0], + gui_settings.cal_data[1], gui_settings.cal_data[2], gui_settings.cal_data[3], + gui_settings.cal_data[4]); oobeSetAutoCalibrate(false); } else { LOG_TRACE(TAG_GUI, F("First Touch Calibration enabled")); oobeSetAutoCalibrate(true); } - #if TOUCH_DRIVER == 2046 && USE_TFT_ESPI > 0 && defined(TOUCH_CS) - if(status) tft_espi_set_touch(calData); - #endif +#if TOUCH_DRIVER == 2046 && USE_TFT_ESPI > 0 && defined(TOUCH_CS) + if(status) tft_espi_set_touch(gui_settings.cal_data); +#endif changed |= status; } @@ -622,7 +451,7 @@ bool guiSetConfig(const JsonObject & settings) /* **************************** SCREENSHOTS ************************************** */ #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 || HASP_USE_HTTP > 0 -static void guiSetBmpHeader(uint8_t * buffer_p, int32_t data) +static void guiSetBmpHeader(uint8_t* buffer_p, int32_t data) { *buffer_p++ = data & 0xFF; *buffer_p++ = (data >> 8) & 0xFF; @@ -637,13 +466,13 @@ static void guiSetBmpHeader(uint8_t * buffer_p, int32_t data) * @note: send header before refreshing the whole screen * **/ -static void gui_get_bitmap_header(uint8_t * buffer, size_t bufsize) +static void gui_get_bitmap_header(uint8_t* buffer, size_t bufsize) { memset(buffer, 0, bufsize); - lv_disp_t * disp = lv_disp_get_default(); - buffer[0] = 0x42; // B - buffer[1] = 0x4D; // M + lv_disp_t* disp = lv_disp_get_default(); + buffer[0] = 0x42; // B + buffer[1] = 0x4D; // M buffer[10 + 0] = 122; // full header size buffer[14 + 0] = 122 - 14; // dib header size @@ -653,7 +482,7 @@ static void gui_get_bitmap_header(uint8_t * buffer, size_t bufsize) // The refresh draws the active screen only, so we need the dimensions of the active screen // This could in be diferent from the display driver width/height if the screen has been resized - lv_obj_t * scr = lv_disp_get_scr_act(NULL); + lv_obj_t* scr = lv_disp_get_scr_act(NULL); // file size guiSetBmpHeader(&buffer[2], 122 + disp->driver.hor_res * disp->driver.ver_res * buffer[28] / 8); @@ -694,13 +523,16 @@ void gui_flush_not_complete() #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 /* Flush VDB bytes to a file */ -static void gui_screenshot_to_file(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p) +static void gui_screenshot_to_file(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) { size_t len = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1); /* Number of pixels */ len *= sizeof(lv_color_t); /* Number of bytes */ - size_t res = pFileOut.write((uint8_t *)color_p, len); + size_t res = pFileOut.write((uint8_t*)color_p, len); if(res != len) gui_flush_not_complete(); - drv_display_flush_cb(disp, area, color_p); // indirect callback to flush screenshot data to the screen + + // indirect callback to flush screenshot data to the screen + // drv_display_flush_cb(disp, area, color_p); + haspTft.flush_pixels(disp, area, color_p); } /** Take Screenshot. @@ -712,7 +544,7 @@ static void gui_screenshot_to_file(lv_disp_drv_t * disp, const lv_area_t * area, * @param[in] pFileName Output binary file name. * **/ -void guiTakeScreenshot(const char * pFileName) +void guiTakeScreenshot(const char* pFileName) { uint8_t buffer[128]; gui_get_bitmap_header(buffer, sizeof(buffer)); @@ -725,8 +557,8 @@ void guiTakeScreenshot(const char * pFileName) LOG_VERBOSE(TAG_GUI, F("Bitmap header written")); /* Refresh screen to screenshot callback */ - lv_disp_t * disp = lv_disp_get_default(); - void (*flush_cb)(struct _disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); + lv_disp_t* disp = lv_disp_get_default(); + void (*flush_cb)(struct _disp_drv_t * disp_drv, const lv_area_t* area, lv_color_t* color_p); flush_cb = disp->driver.flush_cb; /* store callback */ disp->driver.flush_cb = gui_screenshot_to_file; @@ -749,13 +581,16 @@ void guiTakeScreenshot(const char * pFileName) #if HASP_USE_HTTP > 0 /* Flush VDB bytes to a webclient */ -static void gui_screenshot_to_http(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p) +static void gui_screenshot_to_http(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) { size_t len = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1); /* Number of pixels */ len *= sizeof(lv_color_t); /* Number of bytes */ - size_t res = httpClientWrite((uint8_t *)color_p, len); + size_t res = httpClientWrite((uint8_t*)color_p, len); if(res != len) gui_flush_not_complete(); - drv_display_flush_cb(disp, area, color_p); + + // indirect callback to flush screenshot data to the screen + // drv_display_flush_cb(disp, area, color_p); + haspTft.flush_pixels(disp, area, color_p); } /** Take Screenshot. @@ -774,8 +609,8 @@ void guiTakeScreenshot() LOG_VERBOSE(TAG_GUI, F("Bitmap header sent")); /* Refresh screen to screenshot callback */ - lv_disp_t * disp = lv_disp_get_default(); - void (*flush_cb)(struct _disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); + lv_disp_t* disp = lv_disp_get_default(); + void (*flush_cb)(struct _disp_drv_t * disp_drv, const lv_area_t* area, lv_color_t* color_p); flush_cb = disp->driver.flush_cb; /* store callback */ disp->driver.flush_cb = gui_screenshot_to_http; lv_obj_invalidate(lv_scr_act()); @@ -787,4 +622,4 @@ void guiTakeScreenshot() LOG_ERROR(TAG_GUI, F("Data sent does not match header size")); } } -#endif \ No newline at end of file +#endif diff --git a/src/hasp_gui.h b/src/hasp_gui.h index 8db8e1f7..3e33d068 100644 --- a/src/hasp_gui.h +++ b/src/hasp_gui.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_GUI_H @@ -7,28 +7,31 @@ #include "ArduinoJson.h" #include "lvgl.h" +struct gui_conf_t +{ + bool show_pointer; + int8_t backlight_pin; + uint8_t rotation; + uint8_t invert_display; + uint16_t cal_data[5]; +}; + /* ===== Default Event Processors ===== */ -void guiSetup(); +void guiSetup(void); void guiLoop(void); void guiEverySecond(void); void guiStart(void); void guiStop(void); /* ===== Special Event Processors ===== */ -void guiCalibrate(); -void guiTakeScreenshot(const char * pFileName); // to file -void guiTakeScreenshot(); // webclient - -/* ===== Getter and Setter Functions ===== */ -void guiSetDim(int8_t level); -int8_t guiGetDim(void); -void guiSetBacklight(bool lighton); -bool guiGetBacklight(); +void guiCalibrate(void); +void guiTakeScreenshot(const char* pFileName); // to file +void guiTakeScreenshot(void); // webclient /* ===== Read/Write Configuration ===== */ #if HASP_USE_CONFIG > 0 -bool guiGetConfig(const JsonObject & settings); -bool guiSetConfig(const JsonObject & settings); +bool guiGetConfig(const JsonObject& settings); +bool guiSetConfig(const JsonObject& settings); #endif #endif \ No newline at end of file diff --git a/src/hasp_hal.h b/src/hasp_hal.h deleted file mode 100644 index 5c735bab..00000000 --- a/src/hasp_hal.h +++ /dev/null @@ -1,21 +0,0 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie - For full license information read the LICENSE file in the project folder */ - -#ifndef HASP_HAL_H -#define HASP_HAL_H - -#include - -void halRestartMcu(void); -uint8_t halGetHeapFragmentation(void); -String halGetResetInfo(void); -size_t halGetMaxFreeBlock(void); -size_t halGetFreeHeap(void); -String halGetCoreVersion(void); -String halGetChipModel(); -String halGetMacAddress(int start, const char * seperator); -uint16_t halGetCpuFreqMHz(void); -String halDisplayDriverName(void); -String halGpioName(uint8_t gpio); - -#endif \ No newline at end of file diff --git a/src/hasp_oobe.cpp b/src/hasp_oobe.cpp index 0b14ecb9..562753a0 100644 --- a/src/hasp_oobe.cpp +++ b/src/hasp_oobe.cpp @@ -1,35 +1,34 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #if HASP_USE_CONFIG > 0 - #include "hasp_conf.h" +#include "hasp_conf.h" - #include "lvgl.h" - #if LVGL_VERSION_MAJOR != 7 - #include "../lv_components.h" - #endif +#include "lvgl.h" +#if LVGL_VERSION_MAJOR != 7 +#include "../lv_components.h" +#endif - #include "hasp_gui.h" - #include "hasp_config.h" +#include "hasp_gui.h" +#include "hasp_config.h" - #include "net/hasp_wifi.h" - #include "hasp/hasp_dispatch.h" - #include "hasp/hasp_object.h" +#include "sys/net/hasp_wifi.h" +#include "hasp/hasp_dispatch.h" +#include "hasp/hasp_object.h" +#include "dev/device.h" static bool oobeAutoCalibrate = true; - #if HASP_USE_WIFI > 0 +#if HASP_USE_WIFI > 0 - #if HASP_USE_QRCODE > 0 - #include "lv_qrcode.h" - #endif +#if HASP_USE_QRCODE > 0 +#include "lv_qrcode.h" +#endif -static lv_obj_t * oobepage[2]; -static lv_obj_t * oobekb; -extern lv_font_t * defaultFont; - -lv_obj_t * pwd_ta; +static lv_obj_t* oobepage[2]; +static lv_obj_t* oobekb; +lv_obj_t* pwd_ta; static inline void oobeSetPage(uint8_t pageid) { @@ -37,7 +36,7 @@ static inline void oobeSetPage(uint8_t pageid) lv_obj_invalidate(lv_disp_get_layer_sys(NULL)); } -void gotoPage1_cb(lv_obj_t * event_kb, lv_event_t event) +void gotoPage1_cb(lv_obj_t* event_kb, lv_event_t event) { if(event == LV_EVENT_RELEASED) { lv_obj_set_click(lv_disp_get_layer_sys(NULL), false); @@ -45,7 +44,7 @@ void gotoPage1_cb(lv_obj_t * event_kb, lv_event_t event) } } -static void peek_password_cb(lv_obj_t * obj, lv_event_t event) +static void peek_password_cb(lv_obj_t* obj, lv_event_t event) { if(event == LV_EVENT_VALUE_CHANGED) { lv_obj_set_style_local_value_str(obj, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, @@ -54,13 +53,13 @@ static void peek_password_cb(lv_obj_t * obj, lv_event_t event) } } -static void kb_event_cb(lv_obj_t * event_kb, lv_event_t event) +static void kb_event_cb(lv_obj_t* event_kb, lv_event_t event) { if(event == LV_EVENT_APPLY) { StaticJsonDocument<256> settings; char ssid[32] = ""; char pass[32] = ""; - lv_obj_t * obj; + lv_obj_t* obj; obj = hasp_find_obj_from_parent_id(oobepage[1], (uint8_t)10); if(obj) { @@ -91,7 +90,7 @@ static void kb_event_cb(lv_obj_t * event_kb, lv_event_t event) // lv_kb_def_event_cb(event_kb, event); } } -static void ta_event_cb(lv_obj_t * ta, lv_event_t event) +static void ta_event_cb(lv_obj_t* ta, lv_event_t event) { if(event == LV_EVENT_CLICKED) { /* Focus on the clicked text area */ @@ -99,9 +98,9 @@ static void ta_event_cb(lv_obj_t * ta, lv_event_t event) } else if(event == LV_EVENT_INSERT) { - const char * str = (const char *)lv_event_get_data(); + const char* str = (const char*)lv_event_get_data(); if(str[0] == '\n') { - lv_obj_t * obj; + lv_obj_t* obj; obj = hasp_find_obj_from_parent_id(oobepage[1], (uint8_t)10); if(ta == obj) { // now ssid, goto pass @@ -118,23 +117,23 @@ static void ta_event_cb(lv_obj_t * ta, lv_event_t event) } } -static void oobeSetupQR(const char * ssid, const char * pass) +static void oobeSetupQR(const char* ssid, const char* pass) { - lv_disp_t * disp = lv_disp_get_default(); - oobepage[0] = lv_obj_create(NULL, NULL); + lv_disp_t* disp = lv_disp_get_default(); + oobepage[0] = lv_obj_create(NULL, NULL); char buffer[128]; - lv_obj_t * container = lv_cont_create(oobepage[0], NULL); + lv_obj_t* container = lv_cont_create(oobepage[0], NULL); lv_obj_set_pos(container, 5, 5); - // lv_obj_set_style_local_bg_opa(container, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0); - // lv_obj_set_style_local_border_opa(container, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0); + // lv_obj_set_style_local_bg_opa(container, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0); + // lv_obj_set_style_local_border_opa(container, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0); - #if HASP_USE_QRCODE > 0 +#if HASP_USE_QRCODE > 0 snprintf_P(buffer, sizeof(buffer), PSTR("WIFI:S:%s;T:WPA;P:%s;;"), ssid, pass); - lv_obj_t * qr = lv_qrcode_create(oobepage[0], 120, LV_COLOR_BLACK, LV_COLOR_WHITE); + lv_obj_t* qr = lv_qrcode_create(oobepage[0], 120, LV_COLOR_BLACK, LV_COLOR_WHITE); lv_qrcode_update(qr, buffer, strlen(buffer)); - lv_obj_t * qrlabel = lv_label_create(oobepage[0], NULL); + lv_obj_t* qrlabel = lv_label_create(oobepage[0], NULL); snprintf_P(buffer, sizeof(buffer), PSTR(D_OOBE_SCAN_TO_CONNECT)); lv_label_set_text(qrlabel, buffer); @@ -148,12 +147,12 @@ static void oobeSetupQR(const char * ssid, const char * pass) lv_obj_align(qrlabel, qr, LV_ALIGN_OUT_BOTTOM_MID, 0, 5); } - #else +#else lv_obj_set_size(container, disp->driver.hor_res, disp->driver.ver_res); - #endif +#endif - lv_obj_t * aplabel = lv_label_create(container, NULL); + lv_obj_t* aplabel = lv_label_create(container, NULL); snprintf_P(buffer, sizeof(buffer), PSTR(D_OOBE_MSG)); lv_label_set_text(aplabel, buffer); lv_label_set_long_mode(aplabel, LV_LABEL_LONG_BREAK); @@ -163,28 +162,28 @@ static void oobeSetupQR(const char * ssid, const char * pass) lv_obj_align(aplabel, container, LV_ALIGN_IN_TOP_MID, 0, 0); - lv_obj_t * panel = lv_cont_create(container, NULL); + lv_obj_t* panel = lv_cont_create(container, NULL); lv_obj_align(panel, aplabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 10); lv_cont_set_fit(panel, LV_FIT_TIGHT); lv_cont_set_layout(panel, LV_LAYOUT_COLUMN_MID); - String txt((char *)0); + String txt((char*)0); txt.reserve(64); - txt = String(LV_SYMBOL_WIFI) + " " + String(ssid); - lv_obj_t * network = lv_label_create(panel, NULL); + txt = String(LV_SYMBOL_WIFI) + " " + String(ssid); + lv_obj_t* network = lv_label_create(panel, NULL); lv_label_set_text(network, txt.c_str()); - lv_obj_t * password = lv_label_create(panel, NULL); - txt = String(F("\xef\x80\xA3")) + " " + String(pass); + lv_obj_t* password = lv_label_create(panel, NULL); + txt = String(F("\xef\x80\xA3")) + " " + String(pass); lv_label_set_text(password, txt.c_str()); } static void oobeSetupSsid(void) { - lv_font_t * defaultfont; + lv_font_t* defaultfont; // #if defined(ARDUINO_ARCH_ESP32) // defaultfont = &lv_font_montserrat_12; // #else @@ -195,7 +194,7 @@ static void oobeSetupSsid(void) lv_align_t labelpos; lv_obj_user_data_t udata = {0, 0, 0}; - lv_disp_t * disp = lv_disp_get_default(); + lv_disp_t* disp = lv_disp_get_default(); if(disp->driver.hor_res <= disp->driver.ver_res) { leftmargin = 0; topmargin = -35; @@ -226,7 +225,7 @@ static void oobeSetupSsid(void) lv_obj_set_event_cb(pwd_ta, ta_event_cb); lv_obj_align(pwd_ta, NULL, LV_ALIGN_CENTER, leftmargin / 2 - lv_obj_get_height(pwd_ta) / 2, topmargin - voffset); - lv_obj_t * pwd_icon = lv_btn_create(oobepage[1], NULL); + lv_obj_t* pwd_icon = lv_btn_create(oobepage[1], NULL); lv_obj_set_size(pwd_icon, lv_obj_get_height(pwd_ta), lv_obj_get_height(pwd_ta)); lv_obj_set_pos(pwd_icon, lv_obj_get_x(pwd_ta) + lv_obj_get_width(pwd_ta), lv_obj_get_y(pwd_ta)); lv_obj_set_style_local_value_str(pwd_icon, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_SYMBOL_EYE_CLOSE); @@ -236,7 +235,7 @@ static void oobeSetupSsid(void) lv_btn_set_checkable(pwd_icon, true); /* Create the one-line mode text area */ - lv_obj_t * oneline_ta = lv_textarea_create(oobepage[1], pwd_ta); + lv_obj_t* oneline_ta = lv_textarea_create(oobepage[1], pwd_ta); lv_obj_set_style_local_text_font(oneline_ta, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, defaultfont); @@ -246,23 +245,23 @@ static void oobeSetupSsid(void) lv_obj_align(oneline_ta, pwd_ta, LV_ALIGN_OUT_TOP_MID, 0, topmargin); /* Create a label and position it above the text box */ - lv_obj_t * pwd_label = lv_label_create(oobepage[1], NULL); + lv_obj_t* pwd_label = lv_label_create(oobepage[1], NULL); snprintf_P(buffer, sizeof(buffer), PSTR(D_PASSWORD)); lv_label_set_text(pwd_label, buffer); lv_obj_align(pwd_label, pwd_ta, labelpos, 0, 0); /* Create a label and position it above the text box */ - lv_obj_t * oneline_label = lv_label_create(oobepage[1], NULL); + lv_obj_t* oneline_label = lv_label_create(oobepage[1], NULL); snprintf_P(buffer, sizeof(buffer), PSTR(D_SSID)); lv_label_set_text(oneline_label, buffer); lv_obj_align(oneline_label, oneline_ta, labelpos, 0, 0); - /* Create a keyboard and make it fill the width of the above text areas */ - #if LVGL_VERSION_MAJOR == 8 +/* Create a keyboard and make it fill the width of the above text areas */ +#if LVGL_VERSION_MAJOR == 8 oobekb = lv_keyboard_create(oobepage[1]); - #else +#else oobekb = lv_keyboard_create(oobepage[1], NULL); - #endif +#endif lv_obj_set_style_local_pad_inner(oobekb, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 0); lv_obj_set_style_local_border_width(oobekb, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 0); @@ -285,11 +284,11 @@ static void oobeSetupSsid(void) lv_keyboard_set_cursor_manage(oobekb, true); /* Automatically show/hide cursors on text areas */ } -static void oobe_calibrate_cb(lv_obj_t * ta, lv_event_t event) +static void oobe_calibrate_cb(lv_obj_t* ta, lv_event_t event) { if(event == LV_EVENT_CLICKED) { if(oobeAutoCalibrate) { - guiSetDim(100); + haspDevice.set_backlight_level(100); guiCalibrate(); oobeAutoCalibrate = false; lv_obj_set_click(lv_disp_get_layer_sys(NULL), true); @@ -300,7 +299,7 @@ static void oobe_calibrate_cb(lv_obj_t * ta, lv_event_t event) } } } - #endif // HASP_USE_WIFI +#endif // HASP_USE_WIFI void oobeSetAutoCalibrate(bool cal) { @@ -309,15 +308,15 @@ void oobeSetAutoCalibrate(bool cal) bool oobeSetup() { - #if HASP_USE_ETHERNET > 0 +#if HASP_USE_ETHERNET > 0 if(eth_connected) return false; - #endif - #if HASP_USE_WIFI > 0 +#endif +#if HASP_USE_WIFI > 0 char ssid[32]; char pass[32]; if(wifiShowAP(ssid, pass)) { - guiSetDim(100); + haspDevice.set_backlight_level(100); oobeSetupQR(ssid, pass); oobeSetupSsid(); @@ -334,18 +333,18 @@ bool oobeSetup() } else { return false; } - #endif +#endif return false; } // Thist is used for testing only !! -void oobeFakeSetup(const char *, const char *) +void oobeFakeSetup(const char*, const char*) { - #if HASP_USE_WIFI > 0 +#if HASP_USE_WIFI > 0 char ssid[32] = "HASP-ABCDEF"; char pass[32] = "haspadmin"; - guiSetDim(100); + haspDevice.set_backlight_level(100); oobeSetupQR(ssid, pass); oobeSetupSsid(); oobeSetPage(0); @@ -359,6 +358,6 @@ void oobeFakeSetup(const char *, const char *) } else { LOG_INFO(TAG_OOBE, F(D_OOBE_CALIBRATED)); } - #endif +#endif } #endif // HASP_USE_CONFIG \ No newline at end of file diff --git a/src/hasp_oobe.h b/src/hasp_oobe.h index 8e3e7f4b..a2ed71d4 100644 --- a/src/hasp_oobe.h +++ b/src/hasp_oobe.h @@ -1,10 +1,10 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #if HASP_USE_CONFIG > 0 void oobeSetAutoCalibrate(bool cal); bool oobeSetup(); -void oobeFakeSetup(const char *, const char *); // for testing purposes only +void oobeFakeSetup(const char*, const char*); // for testing purposes only #endif // HASP_USE_CONFIG diff --git a/src/hasplib.h b/src/hasplib.h new file mode 100644 index 00000000..ada7b224 --- /dev/null +++ b/src/hasplib.h @@ -0,0 +1,12 @@ +#include "hasp_conf.h" + +#include "hasp/hasp.h" +#include "hasp/hasp_attribute.h" +#include "hasp/hasp_dispatch.h" +#include "hasp/hasp_object.h" +#include "hasp/hasp_page.h" +#include "hasp/hasp_parser.h" +#include "hasp/hasp_utilities.h" +#include "hasp/hasp_lvfs.h" + +#include "hasp/lv_theme_hasp.h" \ No newline at end of file diff --git a/src/lang/en_US.h b/src/lang/en_US.h index f03b9f45..9b01a3a1 100644 --- a/src/lang/en_US.h +++ b/src/lang/en_US.h @@ -5,6 +5,9 @@ #define D_PASSWORD "Password:" #define D_SSID "Ssid:" +#define D_ERROR_OUT_OF_MEMORY "Out of memory" +#define D_ERROR_UNKNOWN "Unkown error" + #define D_CONFIG_NOT_CHANGED "Settings did not change" #define D_CONFIG_CHANGED "Settings changed" #define D_CONFIG_LOADED "Settings loaded" @@ -89,7 +92,7 @@ #define D_OTA_CHECK_UPDATE "Checking updates URL: %s" #define D_OTA_CHECK_COMPLETE "Update check complete" #define D_OTA_CHECK_FAILED "Update check failed: %s" -#define D_OTA_UPDATE_FIRMWARE "OTA Update firmware" +#define D_OTA_UPDATE_FIRMWARE "OTA Firmware Update" #define D_OTA_UPDATE_COMPLETE "OTA Update complete" #define D_OTA_UPDATE_APPLY "Applying Firmware & Reboot" #define D_OTA_UPDATE_FAILED "OTA Update failed" diff --git a/src/lang/lang.h b/src/lang/lang.h index 81633d7f..4a5428b9 100644 --- a/src/lang/lang.h +++ b/src/lang/lang.h @@ -3,6 +3,7 @@ #include "en_US.h" +// language independent defines #define D_PASSWORD_MASK "********" #define D_BULLET " * " #define D_MANUFACTURER "hasp-lvgl" diff --git a/src/lang/nl_NL.h b/src/lang/nl_NL.h index 84528bc9..e2b26fc7 100644 --- a/src/lang/nl_NL.h +++ b/src/lang/nl_NL.h @@ -5,6 +5,9 @@ #define D_PASSWORD "Wachtwoord:" #define D_SSID "Ssid:" +#define D_ERROR_OUT_OF_MEMORY "Geen geheugen bechikbaar" +#define D_ERROR_UNKNOWN "Unbekende fout" + #define D_CONFIG_NOT_CHANGED "Instellingen ongewijzigd" #define D_CONFIG_CHANGED "Instellingen gewijzigd" #define D_CONFIG_LOADED "Instellingen geladen" @@ -86,13 +89,13 @@ #define D_JSONL_FAILED "JSONL verwerking mislukt op lijn %d" #define D_JSONL_SUCCEEDED "Jsonl volledig verwerkt" -#define D_OTA_CHECK_UPDATE "Checking updates URL: %s" -#define D_OTA_CHECK_COMPLETE "Update check complete" +#define D_OTA_CHECK_UPDATE "Controle update URL: %s" +#define D_OTA_CHECK_COMPLETE "Update controle klaar" #define D_OTA_CHECK_FAILED "Update check failed: %s" -#define D_OTA_UPDATE_FIRMWARE "OTA Update firmware" -#define D_OTA_UPDATE_COMPLETE "OTA Update complete" -#define D_OTA_UPDATE_APPLY "Applying Firmware & Reboot" -#define D_OTA_UPDATE_FAILED "OTA Update failed" +#define D_OTA_UPDATE_FIRMWARE "OTA Firmware bijwerken" +#define D_OTA_UPDATE_COMPLETE "OTA Firmware bijgewerkt" +#define D_OTA_UPDATE_APPLY "Firmware Schrijven & Herstart" +#define D_OTA_UPDATE_FAILED "OTA Update mislukt" #define D_HTTP_HASP_DESIGN "HASP Ontwerp" #define D_HTTP_INFORMATION "Informatie" diff --git a/src/log/hasp_debug.cpp b/src/log/hasp_debug.cpp new file mode 100644 index 00000000..f30989fc --- /dev/null +++ b/src/log/hasp_debug.cpp @@ -0,0 +1,393 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +/* =========================================================================== + +- LOG_FATAL() - A fatal exception is caught, the program should halt with while(1){} +- LOG_ERROR() - An important but non-fatal error occured, this error should be checked and not ignored +- LOG_WARNING() - Send at the end of a function to indicate failure of the sub process, can be ignored + +- LOG_TRACE() - Information at the START of an action to notify another function is now running + - LOG_INFO() - Send at the END of a function to indicate successful completion of the sub process + - LOG_VERBOSE() - Send DEBUG information DURING a subprocess + +=========================================================================== */ + +#include "hasp_conf.h" +#include "ConsoleInput.h" +#include "lvgl.h" +//#include "time.h" + +#if defined(ARDUINO_ARCH_ESP8266) +#include // sntp_servermode_dhcp() +#include +#include +#elif defined(ARDUINO_ARCH_ESP32) +#include +#include +#elif defined(STM32F4xx) +#include +#endif + +#include "hasp_conf.h" +#include "dev/device.h" + +#include "hal/hasp_hal.h" +#include "hasp_debug.h" +#include "hasp_config.h" + +#include "hasp/hasp_dispatch.h" +#include "hasp/hasp.h" + +#ifdef USE_CONFIG_OVERRIDE +#include "user_config_override.h" +#endif + +#ifndef SERIAL_SPEED +#define SERIAL_SPEED 115200 +#endif + +#if HASP_USE_SYSLOG > 0 +#include + +#ifndef SYSLOG_SERVER +#define SYSLOG_SERVER "" +#endif + +#ifndef SYSLOG_PORT +#define SYSLOG_PORT 514 +#endif + +#ifndef APP_NAME +#define APP_NAME "HASP" +#endif + +// variables for debug stream writer +// static String debugOutput((char *)0); +// static StringStream debugStream((String &)debugOutput); + +// extern char mqttNodeName[16]; +const char* syslogAppName = APP_NAME; +char debugSyslogHost[32] = SYSLOG_SERVER; +uint16_t debugSyslogPort = SYSLOG_PORT; +uint8_t debugSyslogFacility = 0; +uint8_t debugSyslogProtocol = 0; + +// A UDP instance to let us send and receive packets over UDP +WiFiUDP* syslogClient; +#define SYSLOG_PROTO_IETF 0 + +// Create a new syslog instance with LOG_KERN facility +// Syslog syslog(syslogClient, SYSLOG_SERVER, SYSLOG_PORT, MQTT_CLIENT, APP_NAME, LOG_KERN); +// Create a new empty syslog instance +// Syslog * syslog; + +#endif // USE_SYSLOG + +// Serial Settings +// uint16_t serialInputIndex = 0; // Empty buffer +// char serialInputBuffer[220] = ""; +// uint16_t historyIndex = sizeof(serialInputBuffer) - 1; // Empty buffer +uint16_t debugSerialBaud = SERIAL_SPEED / 10; // Multiplied by 10 +extern bool debugSerialStarted; +extern bool debugAnsiCodes; + +ConsoleInput debugConsole(&Serial, HASP_CONSOLE_BUFFER); + +unsigned long debugLastMillis = 0; +extern dispatch_conf_t dispatch_setings; + +// #if HASP_USE_SYSLOG > 0 +// void syslogSend(uint8_t priority, const char * debugText) +// { +// if(strlen(debugSyslogHost) != 0 && WiFi.isConnected()) { +// syslog->log(priority, debugText); +// } +// } +// #endif + +void debugSetup() +{ + // memset(serialInputBuffer, 0, sizeof(serialInputBuffer)); + // serialInputIndex = 0; + LOG_TRACE(TAG_DEBG, F(D_SERVICE_STARTING)); // Starting console + debugConsole.setLineCallback(dispatch_text_line); +} + +void debugStartSyslog() +{ + +#if HASP_USE_SYSLOG > 0 + // syslog = new Syslog(syslogClient, debugSyslogProtocol == 0 ? SYSLOG_PROTO_IETF : SYSLOG_PROTO_BSD); + // syslog->server(debugSyslogHost, debugSyslogPort); + // syslog->deviceHostname(mqttNodeName); + // syslog->appName(syslogAppName); + // uint16_t priority = (uint16_t)(debugSyslogFacility + 16) << 3; // localx facility, x = 0-7 + // syslog->defaultPriority(priority); + + if(strlen(debugSyslogHost) > 0) { + if(!syslogClient) syslogClient = new WiFiUDP(); + + if(syslogClient) { + if(syslogClient->beginPacket(debugSyslogHost, debugSyslogPort)) { + Log.registerOutput(2, syslogClient, LOG_LEVEL_VERBOSE, true); + LOG_INFO(TAG_SYSL, F(D_SERVICE_STARTED)); + } + } else { + LOG_ERROR(TAG_SYSL, F(D_SERVICE_START_FAILED)); + } + } +#endif +} + +void debugStopSyslog() +{ +#if HASP_USE_SYSLOG > 0 + if(strlen(debugSyslogHost) > 0) { + LOG_WARNING(TAG_SYSL, F(D_SERVICE_STOPPED)); + Log.unregisterOutput(2); + } +#endif +} + +#if HASP_USE_CONFIG > 0 +bool debugGetConfig(const JsonObject& settings) +{ + bool changed = false; + + if(debugSerialBaud != settings[FPSTR(FP_CONFIG_BAUD)].as()) changed = true; + settings[FPSTR(FP_CONFIG_BAUD)] = debugSerialBaud; + + if(dispatch_setings.teleperiod != settings[FPSTR(FP_DEBUG_TELEPERIOD)].as()) changed = true; + settings[FPSTR(FP_DEBUG_TELEPERIOD)] = dispatch_setings.teleperiod; + +#if HASP_USE_SYSLOG > 0 + if(strcmp(debugSyslogHost, settings[FPSTR(FP_CONFIG_HOST)].as().c_str()) != 0) changed = true; + settings[FPSTR(FP_CONFIG_HOST)] = debugSyslogHost; + + if(debugSyslogPort != settings[FPSTR(FP_CONFIG_PORT)].as()) changed = true; + settings[FPSTR(FP_CONFIG_PORT)] = debugSyslogPort; + + if(debugSyslogProtocol != settings[FPSTR(FP_CONFIG_PROTOCOL)].as()) changed = true; + settings[FPSTR(FP_CONFIG_PROTOCOL)] = debugSyslogProtocol; + + if(debugSyslogFacility != settings[FPSTR(FP_CONFIG_LOG)].as()) changed = true; + settings[FPSTR(FP_CONFIG_LOG)] = debugSyslogFacility; +#endif + + if(changed) configOutput(settings, TAG_DEBG); + return changed; +} + +/** Set DEBUG Configuration. + * + * Read the settings from json and sets the application variables. + * + * @note: data pixel should be formated to uint32_t RGBA. Imagemagick requirements. + * + * @param[in] settings JsonObject with the config settings. + **/ +bool debugSetConfig(const JsonObject& settings) +{ + configOutput(settings, TAG_DEBG); + bool changed = false; + + /* Serial Settings*/ + changed |= configSet(debugSerialBaud, settings[FPSTR(FP_CONFIG_BAUD)], F("debugSerialBaud")); + + /* Teleperiod Settings*/ + changed |= configSet(dispatch_setings.teleperiod, settings[FPSTR(FP_DEBUG_TELEPERIOD)], F("debugTelePeriod")); + +/* Syslog Settings*/ +#if HASP_USE_SYSLOG > 0 + if(!settings[FPSTR(FP_CONFIG_HOST)].isNull()) { + changed |= strcmp(debugSyslogHost, settings[FPSTR(FP_CONFIG_HOST)]) != 0; + strncpy(debugSyslogHost, settings[FPSTR(FP_CONFIG_HOST)], sizeof(debugSyslogHost)); + } + changed |= configSet(debugSyslogPort, settings[FPSTR(FP_CONFIG_PORT)], F("debugSyslogPort")); + changed |= configSet(debugSyslogProtocol, settings[FPSTR(FP_CONFIG_PROTOCOL)], F("debugSyslogProtocol")); + changed |= configSet(debugSyslogFacility, settings[FPSTR(FP_CONFIG_LOG)], F("debugSyslogFacility")); +#endif + + return changed; +} +#endif // HASP_USE_CONFIG + +/* +size_t debugHistorycount() +{ + size_t count = 0; + for(size_t i = 1; i < sizeof(serialInputBuffer); i++) { + if(serialInputBuffer[i] == 0 && serialInputBuffer[i - 1] != 0) count++; + } + return count; +} + +size_t debugHistoryIndex(size_t num) +{ + size_t pos = 0; + while(num > 0 && pos < sizeof(serialInputBuffer) - 2) { + if(serialInputBuffer[pos] == 0) { + num--; + // skip extra \0s + while(serialInputBuffer[pos] == 0) { + pos++; + } + } else { + pos++; + } + } + + return pos; +} + +void debugShowHistory() +{ + size_t num = debugHistorycount(); + Serial.println(); + for(int i = 0; i <= num; i++) { + Serial.print("["); + Serial.print(i); + Serial.print("] "); + size_t pos = debugHistoryIndex(i); + if(pos < sizeof(serialInputBuffer)) Serial.println((char *)(serialInputBuffer + pos)); + } +} + +void debugGetHistoryLine(size_t num) +{ + size_t pos = debugHistoryIndex(num); + size_t len = strlen(serialInputBuffer); + char * dst = serialInputBuffer; + char * src = serialInputBuffer + pos; + size_t newlen = strlen(src); + if(len < newlen) { + // make room, shift whole buffer right + dst = serialInputBuffer + newlen - len; + src = serialInputBuffer; + memmove(dst, src, sizeof(serialInputBuffer) - newlen + len); + + dst = serialInputBuffer; + memset(dst, 0, newlen); + } else { + memset(dst, 0, len); + } + dst = serialInputBuffer; + src = serialInputBuffer + pos + newlen - len; + memmove(dst, src, newlen); +} +*/ + +void debugPrintSuffix(uint8_t tag, int level, Print* _logOutput) +{ +#if HASP_USE_SYSLOG > 0 + if(_logOutput == syslogClient && syslogClient) { + syslogClient->endPacket(); + return; + } +#endif + + if(debugAnsiCodes) + _logOutput->println(F(TERM_COLOR_RESET)); + else + _logOutput->println(); + + if(_logOutput == &Serial) { + debugConsole.update(); + } else { + _logOutput->print("hasp > "); + } +} + +void debugPreSetup(JsonObject settings) +{ + Log.begin(LOG_LEVEL_WARNING, true); + Log.setPrefix(debugPrintPrefix); // Uncomment to get timestamps as prefix + Log.setSuffix(debugPrintSuffix); // Uncomment to get newline as suffix + + uint32_t baudrate = 0; +#if HASP_USE_CONFIG > 0 + baudrate = settings[FPSTR(FP_CONFIG_BAUD)].as() * 10; +#endif + + if(baudrate == 0) baudrate = SERIAL_SPEED; + if(baudrate >= 9600u) { /* the baudrates are stored divided by 10 */ + +#if defined(STM32F4xx) +#ifndef STM32_SERIAL1 // Define what Serial port to use for log output + Serial.setRx(PA3); // User Serial2 + Serial.setTx(PA2); +#endif +#endif + Serial.begin(baudrate); /* prepare for possible serial debug */ + delay(10); + Log.registerOutput(0, &Serial, LOG_LEVEL_VERBOSE, true); // LOG_LEVEL_VERBOSE + debugSerialStarted = true; + + Serial.println(); + debugPrintHaspHeader(&Serial); + Serial.flush(); + + LOG_INFO(TAG_DEBG, F("Serial started at %u baud"), baudrate); + LOG_INFO(TAG_DEBG, F("Environment: " PIOENV)); + } +} + +void debugLoop(void) +{ + int16_t keypress; + do { + switch(keypress = debugConsole.readKey()) { + + case ConsoleInput::KEY_PAGE_UP: + dispatch_page_next(LV_SCR_LOAD_ANIM_NONE); + break; + + case ConsoleInput::KEY_PAGE_DOWN: + dispatch_page_prev(LV_SCR_LOAD_ANIM_NONE); + break; + + case(ConsoleInput::KEY_FN)...(ConsoleInput::KEY_FN + 12): + dispatch_set_page(keypress - ConsoleInput::KEY_FN, LV_SCR_LOAD_ANIM_NONE); + break; + } + } while(keypress != 0); +} + +void printLocalTime() +{ + char buffer[128]; + time_t rawtime; + struct tm* timeinfo; + + // if(!time(nullptr)) return; + + time(&rawtime); + timeinfo = localtime(&rawtime); + + strftime(buffer, sizeof(buffer), "%b %d %H:%M:%S.", timeinfo); + Serial.println(buffer); + // struct tm timeinfo; + // time_t now = time(nullptr); + + // Serial-.print(ctime(&now)); + // Serial.print(&timeinfo, " %d %B %Y %H:%M:%S "); + +#if LWIP_VERSION_MAJOR > 1 + + // LwIP v2 is able to list more details about the currently configured SNTP servers + for(int i = 0; i < SNTP_MAX_SERVERS; i++) { + IPAddress sntp = *sntp_getserver(i); + const char* name = sntp_getservername(i); + if(sntp.isSet()) { + Serial.printf("sntp%d: ", i); + if(name) { + Serial.printf("%s (%s) ", name, sntp.toString().c_str()); + } else { + Serial.printf("%s ", sntp.toString().c_str()); + } + Serial.printf("IPv6: %s Reachability: %o\n", sntp.isV6() ? "Yes" : "No", sntp_getreachability(i)); + } + } +#endif +} diff --git a/src/main.cpp b/src/main_arduino copy.cpp similarity index 89% rename from src/main.cpp rename to src/main_arduino copy.cpp index 818f0919..9f93e141 100644 --- a/src/main.cpp +++ b/src/main_arduino copy.cpp @@ -1,18 +1,27 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ +#if 0 && ARDUINO + #include +#include "lvgl.h" #include "hasp_conf.h" // load first +#if HASP_USE_CONFIG > 0 #include "hasp_debug.h" +#endif + +#if HASP_USE_CONFIG > 0 #include "hasp_config.h" #include "hasp_gui.h" +#endif + #include "hasp_oobe.h" #include "hasp/hasp_dispatch.h" #include "hasp/hasp.h" -#include "net/hasp_network.h" +#include "sys/net/hasp_network.h" #include "dev/device.h" @@ -22,7 +31,9 @@ unsigned long mainLastLoopTime = 0; void setup() { - haspDevice.pre_setup(); + hal_setup(); + + haspDevice.init(); /**************************** * Storage initializations @@ -49,6 +60,7 @@ void setup() dispatchSetup(); guiSetup(); debugSetup(); // Init the console + #if HASP_USE_GPIO > 0 gpioSetup(); #endif @@ -88,7 +100,7 @@ void setup() telnetSetup(); #endif -#if HASP_USE_TASMOTA_SLAVE > 0 +#if HASP_USE_TASMOTA_CLIENT > 0 slaveSetup(); #endif @@ -107,7 +119,7 @@ void loop() mqttLoop(); #endif // MQTT -#if HASP_USE_TASMOTA_SLAVE > 0 +#if HASP_USE_TASMOTA_CLIENT > 0 slaveLoop(); #endif // TASMOTASLAVE @@ -129,7 +141,7 @@ void loop() #if HASP_USE_TELNET > 0 telnetLoop(); // Console -#endif // TELNET +#endif // TELNET debugLoop(); // Console haspDevice.loop(); @@ -137,7 +149,7 @@ void loop() /* Timer Loop */ if(millis() - mainLastLoopTime >= 1000) { /* Runs Every Second */ - haspEverySecond(); + haspEverySecond(); // sleep timer debugEverySecond(); // statusupdate #if HASP_USE_OTA > 0 @@ -177,4 +189,6 @@ void loop() #else delay(6); #endif -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/main_arduino.cpp b/src/main_arduino.cpp new file mode 100644 index 00000000..c863a28a --- /dev/null +++ b/src/main_arduino.cpp @@ -0,0 +1,171 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#if !(defined(WINDOWS) || defined(POSIX)) + +#include +#include "lvgl.h" +#include "hasp_conf.h" // load first + +#if HASP_USE_CONFIG > 0 +#include "hasp_debug.h" +#endif + +#if HASP_USE_CONFIG > 0 +#include "hasp_config.h" +#include "hasp_gui.h" +#endif + +#include "hasp_oobe.h" + +#include "hasp/hasp_dispatch.h" +#include "hasp/hasp.h" + +#include "sys/net/hasp_network.h" + +#include "dev/device.h" + +bool isConnected; +uint8_t mainLoopCounter = 0; +unsigned long mainLastLoopTime = 0; + +void setup() +{ + // hal_setup(); + + haspDevice.init(); + + /**************************** + * Storage initializations + ***************************/ +#if HASP_USE_EEPROM > 0 + eepromSetup(); // Don't start at boot, only at write +#endif + + // #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 + // filesystemSetup(); // FS mount is done in configSetup() + // #endif + + // #if HASP_USE_SDCARD > 0 + // sdcardSetup(); + // #endif + + /**************************** + * Read & Apply User Configuration + ***************************/ +#if HASP_USE_CONFIG > 0 + configSetup(); // also runs debugPreSetup(), debugSetup() and debugStart() +#endif + + guiSetup(); + debugSetup(); // Init the console + dispatchSetup(); // for hasp and oobe + +#if HASP_USE_CONFIG > 0 + if(!oobeSetup()) +#endif + { + haspSetup(); + } + +#if HASP_USE_GPIO > 0 + gpioSetup(); +#endif + + /**************************** + * Apply User Configuration + ***************************/ + +#if HASP_USE_MQTT > 0 + mqttSetup(); // Load Hostname before starting WiFi +#endif + +#if HASP_USE_WIFI > 0 || HASP_USE_ETHERNET > 0 + networkSetup(); +#endif + +#if HASP_USE_MDNS > 0 + mdnsSetup(); +#endif + +#if HASP_USE_OTA > 0 + otaSetup(); +#endif + +#if HASP_USE_HTTP > 0 + httpSetup(); +#endif + +#if HASP_USE_TELNET > 0 + telnetSetup(); +#endif + +#if HASP_USE_TASMOTA_CLIENT > 0 + slaveSetup(); +#endif + + mainLastLoopTime = millis() - 1000; // reset loop counter + delay(250); + // guiStart(); +} + +void loop() +{ + guiLoop(); + haspLoop(); + networkLoop(); + +#if HASP_USE_GPIO > 0 + gpioLoop(); +#endif // GPIO + +#if HASP_USE_MQTT > 0 + mqttLoop(); +#endif // MQTT + + debugLoop(); // Console + haspDevice.loop(); + + /* Timer Loop */ + if(millis() - mainLastLoopTime >= 1000) { + + /* Runs Every Second */ + haspEverySecond(); // sleep timer + debugEverySecond(); // statusupdate + + /* Runs Every 5 Seconds */ + if(mainLoopCounter == 0 || mainLoopCounter == 5) { + isConnected = networkEvery5Seconds(); // Check connection + +#if HASP_USE_HTTP > 0 + // httpEvery5Seconds(); +#endif + +#if HASP_USE_MQTT > 0 + mqttEvery5Seconds(isConnected); +#endif + +#if HASP_USE_GPIO > 0 + // gpioEvery5Seconds(); +#endif + + haspDevice.loop_5s(); + } + + /* Reset loop counter every 10 seconds */ + if(mainLoopCounter >= 9) { + mainLoopCounter = 0; + } else { + mainLoopCounter++; + } + mainLastLoopTime += 1000; + } + +#ifdef ARDUINO_ARCH_ESP8266 + delay(2); +#else + delay(6); +#endif +} + +#endif diff --git a/src/main_sdl2.cpp b/src/main_sdl2.cpp new file mode 100644 index 00000000..cb031b78 --- /dev/null +++ b/src/main_sdl2.cpp @@ -0,0 +1,282 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#if defined(WINDOWS) || defined(POSIX) + +#if defined(WINDOWS) + +#include +#include +// MSDN recommends against using getcwd & chdir names +#define cwd _getcwd +#define cd _chdir +#endif + +#if defined(POSIX) +#include +#include +#define cwd getcwd +#define cd chdir +#endif + +#include +#include + +#include "hasp_conf.h" + +#include "lvgl.h" +#include "app_hal.h" +#include "display/monitor.h" + +#include "hasp_debug.h" +#include "hasp_gui.h" + +#include "hasp/hasp_dispatch.h" +#include "hasp/hasp.h" + +#include "dev/device.h" + +bool isConnected; +bool isRunning = 1; + +uint8_t mainLoopCounter = 0; +unsigned long mainLastLoopTime = 0; + +#if defined(WINDOWS) +// https://gist.github.com/kingseva/a918ec66079a9475f19642ec31276a21 +void BindStdHandlesToConsole() +{ + // TODO: Add Error checking. + + // Redirect the CRT standard input, output, and error handles to the console + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stderr); + freopen("CONOUT$", "w", stdout); + + // Note that there is no CONERR$ file + HANDLE hStdout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE hStdin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + SetStdHandle(STD_OUTPUT_HANDLE, hStdout); + SetStdHandle(STD_ERROR_HANDLE, hStdout); + SetStdHandle(STD_INPUT_HANDLE, hStdin); + + // Clear the error state for each of the C++ standard stream objects. + std::wclog.clear(); + std::clog.clear(); + std::wcout.clear(); + std::cout.clear(); + std::wcerr.clear(); + std::cerr.clear(); + std::wcin.clear(); + std::cin.clear(); +} + +void InitializeConsoleOutput() +{ + bool isConsoleApp; + + // How to check if the program is run from a console? + // https://stackoverflow.com/questions/9009333/how-to-check-if-the-program-is-run-from-a-console + HWND consoleWnd = GetConsoleWindow(); + DWORD dwProcessId; + GetWindowThreadProcessId(consoleWnd, &dwProcessId); + + if(GetCurrentProcessId() == dwProcessId) { + isConsoleApp = true; // Opened in Console + } else { + isConsoleApp = false; // Opened in Windows + } + + // Use normal console that launched the program + AttachConsole(ATTACH_PARENT_PROCESS); + + // Test if the application was started from a Console Window + if(!isConsoleApp) { + // If started from Windows, use detached Log Console Window + AllocConsole(); + } + + // Redirect all standard output streams to the console + BindStdHandlesToConsole(); +} +#endif + +void setup() +{ + // Load Settings + + // Init debug log + // debug_init(); + + // Initialize lvgl environment + lv_init(); + lv_log_register_print_cb(debugLvglLogEvent); + + haspDevice.init(); // hardware setup + haspDevice.show_info(); // debug info + // hal_setup(); + guiSetup(); + + // debugSetup(); // Init the console + + printf("%s %d\n", __FILE__, __LINE__); + dispatchSetup(); // for hasp and oobe + haspSetup(); + +#if HASP_USE_MQTT > 0 + printf("%s %d\n", __FILE__, __LINE__); + mqttSetup(); // Hasp must be running + mqttStart(); +#endif + + mainLastLoopTime = millis() - 1000; // reset loop counter + delay(250); + printf("%s %d\n", __FILE__, __LINE__); +} + +void loop() +{ + haspLoop(); + mqttLoop(); + + // debugLoop(); // Console + haspDevice.loop(); + guiLoop(); + + /* Timer Loop */ + if(millis() - mainLastLoopTime >= 1000) { + /* Runs Every Second */ + haspEverySecond(); // sleep timer + dispatchEverySecond(); // sleep timer + +#if HASP_USE_OTA > 0 + otaEverySecond(); // progressbar +#endif + + /* Runs Every 5 Seconds */ + if(mainLoopCounter == 0 || mainLoopCounter == 5) { + + haspDevice.loop_5s(); + } + + /* Reset loop counter every 10 seconds */ + if(mainLoopCounter >= 9) { + mainLoopCounter = 0; + } else { + mainLoopCounter++; + } + mainLastLoopTime += 1000; + } + // delay(6); +} + +void usage(char* progName) +{ + std::cout << progName << " [options]" << std::endl + << std::endl + << "Options:" << std::endl + << " -h | --help Print this help" << std::endl + << " -n | --name Plate hostname used in the mqtt topic" + << std::endl + // << " -b | --broker Mqtt broker name or ip address" << std::endl + // << " -P | --port Mqtt broker port (default: 1883)" << std::endl + // << " -u | --user Mqtt username (optional)" << std::endl + // << " -p | --pass Mqtt password (optional)" << std::endl + // << " -t | --topic Base topic of the mqtt messages (default: hasp)" << std::endl + // << " -g | --group Group topic of on which to accept incoming messages (default: plates)" + // << std::endl + // << " -f | --fullscreen Open the application fullscreen" << std::endl + // << " -v | --verbose Verbosity level" << std::endl + << std::endl; + fflush(stdout); +#if defined(WINDOWS) + static const char s[] = "\n"; + DWORD slen = lstrlen(s); + WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), s, slen, &slen, NULL); +#endif +} + +int main(int argc, char* argv[]) +{ + bool showhelp = false; + int count; + +#if defined(WINDOWS) + InitializeConsoleOutput(); + SetConsoleCP(65001); // 65001 = UTF-8 + static const char s[] = "tränenüberströmt™\n"; + DWORD slen = lstrlen(s); + WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), s, slen, &slen, NULL); + + HANDLE std_out = GetStdHandle(STD_OUTPUT_HANDLE); + if(std_out == INVALID_HANDLE_VALUE) { + return 66; + } + if(!WriteConsole(std_out, "Hello World!\n", 13, NULL, NULL)) { + return 67; + } +#endif + + SDL_Init(0); // Needs to be initialized for GetPerfPath + char buf[4096]; // never know how much is needed + std::cout << "CWD: " << cwd(buf, sizeof buf) << std::endl; + cd(SDL_GetPrefPath("hasp", "hasp")); + std::cout << "CWD changed to: " << cwd(buf, sizeof buf) << std::endl; + SDL_Quit(); // We'll properly init later + + // Change to preferences dir + std::cout << "\nCommand-line arguments:\n"; + for(count = 0; count < argc; count++) + std::cout << " argv[" << count << "] " << argv[count] << "\n" << std::endl << std::flush; + + for(count = 0; count < argc; count++) { + if(argv[count][0] == '-') { + + if(strncmp(argv[count], "--help", 6) == 0 || strncmp(argv[count], "-h", 2) == 0) { + std::cout << " argv[" << count << "] " << argv[count] << "\n" << std::endl << std::flush; + fflush(stdout); + exit(0); + } + + if(strncmp(argv[count], "--name", 6) == 0) { + std::cout << " argv[" << count << "] " << argv[count] << "\n" << std::endl << std::flush; + fflush(stdout); + if(count + 1 < argc) { + haspDevice.set_hostname(argv[count + 1]); + } else { + showhelp = true; + } + } + } + } + + if(showhelp) { + usage("hasp-lvgl"); + +#if defined(WINDOWS) + WriteConsole(std_out, "bye", 3, NULL, NULL); + + FreeConsole(); +#endif + return 0; + } + + // printf("%s %d\n", __FILE__, __LINE__); + // fflush(stdout); + printf("pre setup\n"); + setup(); + printf("to loop\n"); + + while(isRunning) { + loop(); + // std::cout << "HSetup OK\n"; + } + printf("endrunning\n"); + + return 0; +} + +#endif diff --git a/src/mouse_cursor_icon.c b/src/mouse_cursor_icon.c index 14c089a4..1c3a93a8 100644 --- a/src/mouse_cursor_icon.c +++ b/src/mouse_cursor_icon.c @@ -1,4 +1,3 @@ -#include "Arduino.h" #include "lvgl.h" #if 1 diff --git a/src/mqtt/hasp_mqtt.h b/src/mqtt/hasp_mqtt.h new file mode 100644 index 00000000..d109f038 --- /dev/null +++ b/src/mqtt/hasp_mqtt.h @@ -0,0 +1,48 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_MQTT_H +#define HASP_MQTT_H + +#include +#include "ArduinoJson.h" + +#include "hasp_conf.h" + + +// #if defined(WINDOWS) || defined(POSIX) +// #define __FlashStringHelper char +// #endif + +enum hasp_mqtt_error_t { + MQTT_ERR_OK = 0, + MQTT_ERR_DISABLED = -1, + MQTT_ERR_NO_CONN = -2, + MQTT_ERR_SUB_FAIL = -3, + MQTT_ERR_PUB_FAIL = -4, + MQTT_ERR_UNKNOWN = -128 +}; + + +void mqttSetup(); +void mqttLoop(); +void mqttEvery5Seconds(bool wifiIsConnected); +void mqttStart(); +void mqttStop(); + +int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload); +int mqtt_send_state(const char* subtopic, const char* payload); +int mqttPublish(const char* topic, const char* payload, size_t len, bool retain); + +bool mqttIsConnected(); + +#if HASP_USE_CONFIG > 0 +bool mqttGetConfig(const JsonObject& settings); +bool mqttSetConfig(const JsonObject& settings); +#endif + +// #ifndef WINDOWS +// String mqttGetNodename(void); +// #endif + +#endif diff --git a/src/svc/hasp_mqtt_ha.cpp b/src/mqtt/hasp_mqtt_ha.cpp similarity index 69% rename from src/svc/hasp_mqtt_ha.cpp rename to src/mqtt/hasp_mqtt_ha.cpp index 90069126..fadf490c 100644 --- a/src/svc/hasp_mqtt_ha.cpp +++ b/src/mqtt/hasp_mqtt_ha.cpp @@ -1,24 +1,21 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #include "ArduinoJson.h" #include "hasp_conf.h" + #if HASP_USE_MQTT > 0 - #include "PubSubClient.h" +#include "hasp/hasp.h" +#include "hasp/hasp_dispatch.h" +#include "dev/device.h" - #include "hasp/hasp.h" - #include "hasp/hasp_dispatch.h" - #include "hasp_hal.h" - #include "hasp_mqtt.h" - #include "hasp_mqtt_ha.h" +#include "hasp_mqtt.h" +#include "hasp_mqtt_ha.h" - #define RETAINED true - #define HASP_MAC_ADDRESS halGetMacAddress(0, "").c_str() - #define HASP_MAC_ADDRESS_STR halGetMacAddress(0, "") +#define RETAINED true -extern PubSubClient mqttClient; -extern char mqttNodeName[16]; +// extern char mqttNodeName[16]; extern char mqttNodeTopic[24]; extern char mqttGroupTopic[24]; extern bool mqttEnabled; @@ -26,45 +23,74 @@ extern bool mqttHAautodiscover; char discovery_prefix[] = "homeassistant"; -const char FP_MQTT_HA_DEVICE[] PROGMEM = "device"; -const char FP_MQTT_HA_IDENTIFIERS[] PROGMEM = "ids"; -const char FP_MQTT_HA_NAME[] PROGMEM = "name"; -const char FP_MQTT_HA_MODEL[] PROGMEM = "mdl"; +const char FP_MQTT_HA_DEVICE[] PROGMEM = "device"; +const char FP_MQTT_HA_IDENTIFIERS[] PROGMEM = "ids"; +const char FP_MQTT_HA_NAME[] PROGMEM = "name"; +const char FP_MQTT_HA_MODEL[] PROGMEM = "mdl"; const char FP_MQTT_HA_MANUFACTURER[] PROGMEM = "mf"; -void mqtt_ha_send_json(char * topic, JsonDocument & doc) +#if !(defined(WINDOWS) || defined(POSIX)) + +#include "hal/hasp_hal.h" + +#define HASP_MAC_ADDRESS halGetMacAddress(0, "").c_str() +#define HASP_MAC_ADDRESS_STR halGetMacAddress(0, "") + +// #include "PubSubClient.h" +// extern PubSubClient mqttClient; + +#else + +#define HASP_MAC_ADDRESS "aabbccddeeff" +#define HASP_MAC_ADDRESS_STR "aabbccddeeff" + +#endif + +void mqtt_ha_send_json(char* topic, JsonDocument& doc) { LOG_VERBOSE(TAG_MQTT_PUB, topic); - mqttClient.beginPublish(topic, measureJson(doc), RETAINED); - serializeJson(doc, mqttClient); - mqttClient.endPublish(); + + // size_t n; + // LOG_VERBOSE(TAG_MQTT_PUB, " >>> measureJson & serializeJson start "); + // long start = millis(); + // mqttClient.beginPublish(topic, measureJson(doc), RETAINED); + // n = serializeJson(doc, mqttClient); + // mqttClient.endPublish(); + // LOG_VERBOSE(TAG_MQTT_PUB, " >>> measureJson & serializeJson done, %d bytes in %d millis\n", n, millis() - start); + + // LOG_VERBOSE(TAG_MQTT_PUB, " >>> serializeJson start "); + // start = millis(); + char buffer[800]; + size_t len = serializeJson(doc, buffer, sizeof(buffer)); + mqttPublish(topic, buffer, len, RETAINED); + // LOG_VERBOSE(TAG_MQTT_PUB, " >>> serializeJson done, %d bytes in %d millis\n", n, millis() - start); } // adds the device identifiers to the HA MQTT auto-discovery message -void mqtt_ha_add_device_ids(JsonDocument & doc) +void mqtt_ha_add_device_ids(JsonDocument& doc) { JsonObject device = doc.createNestedObject(FPSTR(FP_MQTT_HA_DEVICE)); JsonArray ids = device.createNestedArray(FPSTR(FP_MQTT_HA_IDENTIFIERS)); - ids.add(mqttNodeName); + ids.add(haspDevice.get_hostname()); ids.add(HASP_MAC_ADDRESS_STR); char buffer[32]; haspGetVersion(buffer, sizeof(buffer)); device[F("sw")] = buffer; - device[FPSTR(FP_MQTT_HA_NAME)] = mqttNodeName; - device[FPSTR(FP_MQTT_HA_MODEL)] = F(PIOENV); - device[FPSTR(FP_MQTT_HA_MANUFACTURER)] = F(D_MANUFACTURER); + device[FPSTR(FP_MQTT_HA_NAME)] = haspDevice.get_hostname(); + device[FPSTR(FP_MQTT_HA_MODEL)] = F(PIOENV); + device[FPSTR(FP_MQTT_HA_MANUFACTURER)] = F(D_MANUFACTURER); doc[F("~")] = mqttNodeTopic; } // adds the name and unique_id to the HA MQTT auto-discovery message -void mqtt_ha_add_unique_id(JsonDocument & doc, char * item) +void mqtt_ha_add_unique_id(JsonDocument& doc, char* item) { char buffer[64]; - snprintf_P(buffer, sizeof(buffer), PSTR("HASP %s %s"), mqttNodeName, item); + snprintf_P(buffer, sizeof(buffer), PSTR("%s %s"), haspDevice.get_hostname(), item); doc[FPSTR(FP_MQTT_HA_NAME)] = buffer; snprintf_P(buffer, sizeof(buffer), PSTR("hasp_%s-%s"), HASP_MAC_ADDRESS, item); @@ -73,7 +99,7 @@ void mqtt_ha_add_unique_id(JsonDocument & doc, char * item) void mqtt_ha_register_button(uint8_t page, uint8_t id) { - StaticJsonDocument<640> doc; + StaticJsonDocument<800> doc; mqtt_ha_add_device_ids(doc); char buffer[128]; @@ -88,34 +114,34 @@ void mqtt_ha_register_button(uint8_t page, uint8_t id) doc[F("pl")] = buffer; doc[F("type")] = "button_short_press"; snprintf_P(buffer, sizeof(buffer), PSTR("%s/device_automation/%s/" HASP_OBJECT_NOTATION "_%s/config"), - discovery_prefix, mqttNodeName, page, id, "short_press"); + discovery_prefix, haspDevice.get_hostname(), page, id, "short_press"); mqtt_ha_send_json(buffer, doc); dispatch_get_event_name(HASP_EVENT_SHORT, buffer, sizeof(buffer)); doc[F("pl")] = buffer; doc[F("type")] = "button_short_release"; snprintf_P(buffer, sizeof(buffer), PSTR("%s/device_automation/%s/" HASP_OBJECT_NOTATION "_%s/config"), - discovery_prefix, mqttNodeName, page, id, "short_release"); + discovery_prefix, haspDevice.get_hostname(), page, id, "short_release"); mqtt_ha_send_json(buffer, doc); dispatch_get_event_name(HASP_EVENT_LONG, buffer, sizeof(buffer)); doc[F("pl")] = buffer; doc[F("type")] = "button_long_press"; snprintf_P(buffer, sizeof(buffer), PSTR("%s/device_automation/%s/" HASP_OBJECT_NOTATION "_%s/config"), - discovery_prefix, mqttNodeName, page, id, "long_press"); + discovery_prefix, haspDevice.get_hostname(), page, id, "long_press"); mqtt_ha_send_json(buffer, doc); dispatch_get_event_name(HASP_EVENT_UP, buffer, sizeof(buffer)); doc[F("pl")] = buffer; doc[F("type")] = "button_long_release"; snprintf_P(buffer, sizeof(buffer), PSTR("%s/device_automation/%s/" HASP_OBJECT_NOTATION "_%s/config"), - discovery_prefix, mqttNodeName, page, id, "long_release"); + discovery_prefix, haspDevice.get_hostname(), page, id, "long_release"); mqtt_ha_send_json(buffer, doc); } void mqtt_ha_register_switch(uint8_t page, uint8_t id) { - StaticJsonDocument<640> doc; + StaticJsonDocument<800> doc; mqtt_ha_add_device_ids(doc); char buffer[128]; @@ -125,18 +151,18 @@ void mqtt_ha_register_switch(uint8_t page, uint8_t id) doc[F("t")] = buffer; // topic doc[F("atype")] = F("binary_sensor"); // automation_type - doc[F("pl")] = F("SHORT"); // payload + doc[F("pl")] = F("short"); // payload doc[F("type")] = F("button_short_release"); snprintf_P(buffer, sizeof(buffer), PSTR("%s/device_automation/%s/" HASP_OBJECT_NOTATION "_%s/config"), - discovery_prefix, mqttNodeName, page, id, "short"); + discovery_prefix, haspDevice.get_hostname(), page, id, "short"); mqtt_ha_send_json(buffer, doc); } void mqtt_ha_register_connectivity() { - StaticJsonDocument<640> doc; + StaticJsonDocument<1024> doc; char item[16]; snprintf_P(item, sizeof(item), PSTR("connectivity")); @@ -147,13 +173,14 @@ void mqtt_ha_register_connectivity() mqtt_ha_add_unique_id(doc, item); char buffer[128]; - snprintf_P(buffer, sizeof(buffer), PSTR("%s/binary_sensor/%s/%s/config"), discovery_prefix, mqttNodeName, item); + snprintf_P(buffer, sizeof(buffer), PSTR("%s/binary_sensor/%s/%s/config"), discovery_prefix, + haspDevice.get_hostname(), item); mqtt_ha_send_json(buffer, doc); } void mqtt_ha_register_backlight() { - StaticJsonDocument<640> doc; + DynamicJsonDocument doc(1024); char item[16]; snprintf_P(item, sizeof(item), PSTR("backlight")); @@ -161,6 +188,8 @@ void mqtt_ha_register_backlight() deserializeJson(doc, F("{" "\"cmd_t\":\"~command/light\"," "\"stat_t\":\"~state/light\"," + "\"pl_on\":\"on\"," + "\"pl_off\":\"off\"," "\"avty_t\":\"~LWT\"," "\"bri_stat_t\":\"~state/dim\"," "\"bri_cmd_t\":\"~command/dim\"," @@ -168,11 +197,12 @@ void mqtt_ha_register_backlight() mqtt_ha_add_device_ids(doc); mqtt_ha_add_unique_id(doc, item); - // doc[F("pl_on")] = F("ON"); - // doc[F("pl_off")] = F("OFF"); + // doc[F("pl_on")] = F("on"); + // doc[F("pl_off")] = F("off"); char buffer[128]; - snprintf_P(buffer, sizeof(buffer), PSTR("%s/light/%s/%s/config"), discovery_prefix, mqttNodeName, item); + snprintf_P(buffer, sizeof(buffer), PSTR("%s/light/%s/%s/config"), discovery_prefix, haspDevice.get_hostname(), + item); mqtt_ha_send_json(buffer, doc); } @@ -186,12 +216,22 @@ void mqtt_ha_register_moodlight() deserializeJson(doc, F("{" "\"cmd_t\":\"~command/moodlight\"," "\"stat_t\":\"~state/moodlight\"," - "\"avty_t\":\"~LWT\"," - "\"bri_stat_t\":\"~state/moodlight/dim\"," - "\"bri_cmd_t\":\"~command/moodlight/dim\"," - "\"bri_scl\":100," - "\"rgb_stat_t\":\"~state/moodlight/rgb\"," - "\"rgb_cmd_t\":\"~command/moodlight/rgb\"}")); + "\"platform\":\"mqtt\"," + "\"schema\":\"json\"," + "\"rgb\":true," + "\"brightness\":true," + "\"avty_t\":\"~LWT\"}")); + + /* deserializeJson(doc, F("{" + "\"cmd_t\":\"~command/moodlight\"," + // "\"stat_t\":\"~state/moodlight\"," + "\"avty_t\":\"~LWT\"," + "\"bri_stat_t\":\"~state/moodlight/dim\"," + "\"bri_cmd_t\":\"~command/moodlight/dim\"," + "\"bri_scl\":100," + "\"rgb_stat_t\":\"~state/moodlight/rgb\"," + "\"rgb_cmd_t\":\"~command/moodlight/rgb\"}")); + */ mqtt_ha_add_device_ids(doc); mqtt_ha_add_unique_id(doc, item); @@ -203,13 +243,14 @@ void mqtt_ha_register_moodlight() // doc[F("rgb_command_template")] = F("{{ '%02x%02x%02x0000'| format(red, green, blue) }}"); char buffer[128]; - snprintf_P(buffer, sizeof(buffer), PSTR("%s/light/%s/%s/config"), discovery_prefix, mqttNodeName, item); + snprintf_P(buffer, sizeof(buffer), PSTR("%s/light/%s/%s/config"), discovery_prefix, haspDevice.get_hostname(), + item); mqtt_ha_send_json(buffer, doc); } void mqtt_ha_register_idle() { - StaticJsonDocument<640> doc; + StaticJsonDocument<800> doc; char item[16]; snprintf_P(item, sizeof(item), PSTR("idle")); @@ -219,13 +260,14 @@ void mqtt_ha_register_idle() mqtt_ha_add_unique_id(doc, item); char buffer[128]; - snprintf_P(buffer, sizeof(buffer), PSTR("%s/sensor/%s/%s/config"), discovery_prefix, mqttNodeName, item); + snprintf_P(buffer, sizeof(buffer), PSTR("%s/sensor/%s/%s/config"), discovery_prefix, haspDevice.get_hostname(), + item); mqtt_ha_send_json(buffer, doc); } void mqtt_ha_register_activepage() { - StaticJsonDocument<640> doc; + StaticJsonDocument<800> doc; char item[16]; snprintf_P(item, sizeof(item), PSTR("page")); @@ -235,7 +277,8 @@ void mqtt_ha_register_activepage() mqtt_ha_add_unique_id(doc, item); char buffer[128]; - snprintf_P(buffer, sizeof(buffer), PSTR("%s/number/%s/%s/config"), discovery_prefix, mqttNodeName, item); + snprintf_P(buffer, sizeof(buffer), PSTR("%s/number/%s/%s/config"), discovery_prefix, haspDevice.get_hostname(), + item); mqtt_ha_send_json(buffer, doc); } @@ -300,8 +343,8 @@ device: "bri_stat_t": "~/state/dim", "bri_cmd_t": "~/command/dim", "bri_scl": 100, - "pl_on": "ON", - "pl_off": "OFF" + "pl_on": "on", + "pl_off": "off" } { diff --git a/src/svc/hasp_mqtt_ha.h b/src/mqtt/hasp_mqtt_ha.h similarity index 75% rename from src/svc/hasp_mqtt_ha.h rename to src/mqtt/hasp_mqtt_ha.h index 5580f79e..9d84db6f 100644 --- a/src/svc/hasp_mqtt_ha.h +++ b/src/mqtt/hasp_mqtt_ha.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_MQTT_HA_H diff --git a/src/mqtt/hasp_mqtt_paho_async.cpp b/src/mqtt/hasp_mqtt_paho_async.cpp new file mode 100644 index 00000000..5c49c141 --- /dev/null +++ b/src/mqtt/hasp_mqtt_paho_async.cpp @@ -0,0 +1,436 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +/* Multi threaded asynchronous paho client */ + +#include + +#include "hasp_conf.h" + +#if HASP_USE_MQTT_ASYNC > 0 +#ifdef USE_PAHO + +/******************************************************************************* + * Copyright (c) 2012, 2020 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * https://www.eclipse.org/legal/epl-2.0/ + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial contribution + *******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "MQTTAsync.h" + +#include "hasp_mqtt.h" // functions to implement here + +#include "hasp/hasp_dispatch.h" // for dispatch_topic_payload +#include "hasp_debug.h" // for logging + +#if !defined(_WIN32) +#include +#else +#include +#endif + +#if defined(_WRS_KERNEL) +#include +#endif + +#define ADDRESS "10.4.0.5:1883" +#define CLIENTID "ExampleClientSub" +#define TOPIC "hasp/plate35/" +#define QOS 1 +#define TIMEOUT 10000L + +const char* mqttNodeTopic = TOPIC; +const char* mqttGroupTopic = TOPIC; +// char mqttNodeTopic[24]; +// char mqttGroupTopic[24]; +bool mqttEnabled = false; +bool mqttHAautodiscover = true; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// These defaults may be overwritten with values saved by the web interface +#ifndef MQTT_HOST +#define MQTT_HOST ""; +#endif + +#ifndef MQTT_PORT +#define MQTT_PORT 1883; +#endif + +#ifndef MQTT_USER +#define MQTT_USER ""; +#endif + +#ifndef MQTT_PASSW +#define MQTT_PASSW ""; +#endif +#ifndef MQTT_NODENAME +#define MQTT_NODENAME ""; +#endif +#ifndef MQTT_GROUPNAME +#define MQTT_GROUPNAME ""; +#endif + +#ifndef MQTT_PREFIX +#define MQTT_PREFIX "hasp" +#endif + +#define LWT_TOPIC "LWT" + +std::recursive_mutex dispatch_mtx; +std::recursive_mutex publish_mtx; + +char mqttServer[16] = MQTT_HOST; +char mqttUser[23] = MQTT_USER; +char mqttPassword[32] = MQTT_PASSW; +// char mqttNodeName[16] = MQTT_NODENAME; +char mqttGroupName[16] = MQTT_GROUPNAME; +uint16_t mqttPort = MQTT_PORT; + +MQTTAsync mqtt_client; + +int disc_finished = 0; +int subscribed = 0; +int connected = 0; + +static bool mqttPublish(const char* topic, const char* payload, size_t len, bool retain = false); + +/* ===== Paho event callbacks ===== */ + +void connlost(void* context, char* cause) +{ + printf("\nConnection lost\n"); + if(cause) printf(" cause: %s\n", cause); + + printf("Reconnecting\n"); + mqttStart(); +} + +// Receive incoming messages +static void mqtt_message_cb(char* topic, char* payload, unsigned int length) +{ // Handle incoming commands from MQTT + if(length + 1 >= MQTT_MAX_PACKET_SIZE) { + LOG_ERROR(TAG_MQTT_RCV, F("Payload too long (%d bytes)"), length); + return; + } else { + payload[length] = '\0'; + } + + LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, (char*)payload); + + if(topic == strstr(topic, mqttNodeTopic)) { // startsWith mqttNodeTopic + + // Node topic + topic += strlen(mqttNodeTopic); // shorten topic + + } else if(topic == strstr(topic, mqttGroupTopic)) { // startsWith mqttGroupTopic + + // Group topic + topic += strlen(mqttGroupTopic); // shorten topic + dispatch_mtx.lock(); + dispatch_topic_payload(topic, (const char*)payload); + dispatch_mtx.unlock(); + return; + + } else if(topic == strstr_P(topic, PSTR("homeassistant/status"))) { // HA discovery topic + if(mqttHAautodiscover && !strcasecmp_P((char*)payload, PSTR("online"))) { + dispatch_current_state(); + mqtt_ha_register_auto_discovery(); + } + return; + + } else { + // Other topic + LOG_ERROR(TAG_MQTT, F(D_MQTT_INVALID_TOPIC)); + return; + } + + // catch a dangling LWT from a previous connection if it appears + if(!strcmp_P(topic, PSTR(LWT_TOPIC))) { // endsWith LWT + if(!strcasecmp_P((char*)payload, PSTR("offline"))) { + { + char msg[8]; + char tmp_topic[strlen(mqttNodeTopic) + 8]; + snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" LWT_TOPIC), mqttNodeTopic); + snprintf_P(msg, sizeof(msg), PSTR("online")); + + // /*bool res =*/mqttClient.publish(tmp_topic, msg, true); + mqttPublish(tmp_topic, msg, true); + } + + } else { + // LOG_TRACE(TAG_MQTT, F("ignoring LWT = online")); + } + } else { + dispatch_mtx.lock(); + dispatch_topic_payload(topic, (const char*)payload); + dispatch_mtx.unlock(); + } +} + +int msgarrvd(void* context, char* topicName, int topicLen, MQTTAsync_message* message) +{ + // printf("MQT RCV >> "); + // printf("%s => %.*s (%d)\n", topicName, message->payloadlen, (char *)message->payload, message->payloadlen); + + char msg[message->payloadlen + 1]; + memcpy(msg, (char*)message->payload, message->payloadlen); + msg[message->payloadlen] = '\0'; + + mqtt_message_cb(topicName, (char*)message->payload, message->payloadlen); + + MQTTAsync_freeMessage(&message); + MQTTAsync_free(topicName); + return 1; +} + +void onDisconnectFailure(void* context, MQTTAsync_failureData* response) +{ + printf("Disconnect failed, rc %d\n", response->code); + disc_finished = 1; +} + +void onDisconnect(void* context, MQTTAsync_successData* response) +{ + printf("Successful disconnection\n"); + disc_finished = 1; + connected = 0; +} + +void onSubscribe(void* context, MQTTAsync_successData* response) +{ + printf("Subscribe succeeded %d\n", response->token); + subscribed = 1; +} + +void onSubscribeFailure(void* context, MQTTAsync_failureData* response) +{ + printf("Subscribe failed, rc %d\n", response->code); +} + +void onConnectFailure(void* context, MQTTAsync_failureData* response) +{ + connected = 0; + printf("Connect failed, rc %d\n", response->code); +} + +void mqtt_subscribe(void* context, const char* topic) +{ + MQTTAsync client = (MQTTAsync)context; + MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; + int rc; + + printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n", topic, CLIENTID, QOS); + opts.onSuccess = onSubscribe; + opts.onFailure = onSubscribeFailure; + opts.context = client; + if((rc = MQTTAsync_subscribe(client, topic, QOS, &opts)) != MQTTASYNC_SUCCESS) { + printf("Failed to start subscribe, return code %d\n", rc); + } +} + +void onConnect(void* context, MQTTAsync_successData* response) +{ + MQTTAsync client = (MQTTAsync)context; + connected = 1; + + printf("Successful connection\n"); + + mqtt_subscribe(context, TOPIC "command/#"); + mqtt_subscribe(context, TOPIC "command"); + mqtt_subscribe(context, TOPIC "light"); + mqtt_subscribe(context, TOPIC "dim"); + + mqttPublish(TOPIC LWT_TOPIC, "online", false); + + mqtt_send_object_state(0, 0, "connected"); + std::cout << std::endl; +} + +void onSendFailure(void* context, MQTTAsync_failureData* response) +{ + MQTTAsync client = (MQTTAsync)context; + MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer; + int rc; + + printf("Message send failed token %d error code %d\n", response->token, response->code); + opts.onSuccess = onDisconnect; + opts.onFailure = onDisconnectFailure; + opts.context = client; + if((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS) { + printf("Failed to start disconnect, return code %d\n", rc); + // exit(EXIT_FAILURE); + } +} + +void onSend(void* context, MQTTAsync_successData* response) +{ + MQTTAsync client = (MQTTAsync)context; + MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer; + int rc; + + // printf("Message with token value %d delivery confirmed\n", response->token); + + // opts.onSuccess = onDisconnect; + // opts.onFailure = onDisconnectFailure; + // opts.context = client; + // if ((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS) + // { + // printf("Failed to start disconnect, return code %d\n", rc); + // exit(EXIT_FAILURE); + // } +} + +/* ===== Local HASP MQTT functions ===== */ + +static bool mqttPublish(const char* topic, const char* payload, size_t len, bool retain) +{ + if(mqttIsConnected()) { + MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; + MQTTAsync_message pubmsg = MQTTAsync_message_initializer; + int rc; + + opts.onSuccess = onSend; + opts.onFailure = onSendFailure; + opts.context = mqtt_client; + pubmsg.payload = (char*)payload; + pubmsg.payloadlen = (int)strlen(payload); + pubmsg.qos = QOS; + pubmsg.retained = 0; + dispatch_mtx.lock(); + if((rc = MQTTAsync_sendMessage(mqtt_client, topic, &pubmsg, &opts)) != MQTTASYNC_SUCCESS) { + dispatch_mtx.unlock(); + LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " %s => %s"), topic, payload); + } else { + dispatch_mtx.unlock(); + LOG_TRACE(TAG_MQTT_PUB, F("%s => %s"), topic, payload); + return true; + } + } else { + LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED)); + } + return false; +} + +/* ===== Public HASP MQTT functions ===== */ + +bool mqttIsConnected() +{ + return connected == 1; +} + +void mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload) +{ + char tmp_topic[strlen(mqttNodeTopic) + 20]; + printf(("%sstate/%s\n"), mqttNodeTopic, subtopic); + snprintf_P(tmp_topic, sizeof(tmp_topic), ("%sstate/%s"), mqttNodeTopic, subtopic); + mqttPublish(tmp_topic, payload, false); +} + +void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload) +{ + char tmp_topic[strlen(mqttNodeTopic) + 20]; + snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/p%ub%u"), mqttNodeTopic, pageid, btnid); + mqttPublish(tmp_topic, payload, false); +} + +void mqttStart() +{ + MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer; + MQTTAsync_willOptions will_opts = MQTTAsync_willOptions_initializer; + int rc; + int ch; + + if((rc = MQTTAsync_create(&mqtt_client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL)) != + MQTTASYNC_SUCCESS) { + printf("Failed to create client, return code %d\n", rc); + rc = EXIT_FAILURE; + return; + } + + if((rc = MQTTAsync_setCallbacks(mqtt_client, mqtt_client, connlost, msgarrvd, NULL)) != MQTTASYNC_SUCCESS) { + printf("Failed to set callbacks, return code %d\n", rc); + rc = EXIT_FAILURE; + return; + } + + conn_opts.will = &will_opts; + conn_opts.will->message = "offline"; + conn_opts.will->qos = 1; + conn_opts.will->retained = 0; + conn_opts.will->topicName = "hasp/plate35/LWT"; + + conn_opts.keepAliveInterval = 20; + conn_opts.cleansession = 1; + conn_opts.onSuccess = onConnect; + conn_opts.onFailure = onConnectFailure; + conn_opts.context = mqtt_client; + + if((rc = MQTTAsync_connect(mqtt_client, &conn_opts)) != MQTTASYNC_SUCCESS) { + printf("Failed to start connect, return code %d\n", rc); + rc = EXIT_FAILURE; + // goto destroy_exit; + } else { + } + + // while (!subscribed && !finished) + // #if defined(_WIN32) + // Sleep(100); + // #else + // usleep(10000L); + // #endif + + // if (finished) + // goto exit; +} + +void mqttStop() +{ + int rc; + MQTTAsync_disconnectOptions disc_opts = MQTTAsync_disconnectOptions_initializer; + disc_opts.onSuccess = onDisconnect; + disc_opts.onFailure = onDisconnectFailure; + if((rc = MQTTAsync_disconnect(mqtt_client, &disc_opts)) != MQTTASYNC_SUCCESS) { + printf("Failed to start disconnect, return code %d\n", rc); + rc = EXIT_FAILURE; + // goto destroy_exit; + } + // while (!disc_finished) + // { + // #if defined(_WIN32) + // Sleep(100); + // #else + // usleep(10000L); + // #endif + // } + + // destroy_exit: + // MQTTAsync_destroy(&client); + // exit: + // return rc; +} + +void mqttSetup(){}; + +void mqttLoop(){}; + +void mqttEvery5Seconds(bool wifiIsConnected){}; + +#endif // USE_PAHO +#endif // USE_MQTT diff --git a/src/mqtt/hasp_mqtt_paho_single.cpp b/src/mqtt/hasp_mqtt_paho_single.cpp new file mode 100644 index 00000000..d65802d1 --- /dev/null +++ b/src/mqtt/hasp_mqtt_paho_single.cpp @@ -0,0 +1,375 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +/* Single threaded synchronous paho client */ + +#include + +#include "hasp_conf.h" + +#if HASP_USE_MQTT > 0 +#ifdef USE_PAHO + +/******************************************************************************* + * Copyright (c) 2012, 2020 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * https://www.eclipse.org/legal/epl-2.0/ + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial contribution + *******************************************************************************/ + +#include +#include +#include +#include +#include + +#include "MQTTClient.h" + +#include "hasp_mqtt.h" // functions to implement here +#include "hasp_mqtt_ha.h" // HA functions + +#include "hasp/hasp_dispatch.h" // for dispatch_topic_payload +#include "hasp_debug.h" // for logging + +#if !defined(_WIN32) +#include +#else +#include +#endif + +#if defined(_WRS_KERNEL) +#include +#endif + +#define ADDRESS "10.1.0.208:1883" +#define CLIENTID "test1123" +#define TOPIC "hasp/plate35/" +#define QOS 1 +#define TIMEOUT 1000L + +char mqttNodeTopic[24] = "hasp/plate35/"; +const char* mqttGroupTopic = "hasp/plates/"; +// char mqttNodeTopic[24]; +// char mqttGroupTopic[24]; +bool mqttEnabled = false; +bool mqttHAautodiscover = true; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// These defaults may be overwritten with values saved by the web interface +#ifndef MQTT_HOST +#define MQTT_HOST ""; +#endif + +#ifndef MQTT_PORT +#define MQTT_PORT 1883; +#endif + +#ifndef MQTT_USER +#define MQTT_USER ""; +#endif + +#ifndef MQTT_PASSW +#define MQTT_PASSW ""; +#endif +#ifndef MQTT_NODENAME +#define MQTT_NODENAME ""; +#endif +#ifndef MQTT_GROUPNAME +#define MQTT_GROUPNAME ""; +#endif + +#ifndef MQTT_PREFIX +#define MQTT_PREFIX "hasp" +#endif + +#define LWT_TOPIC "LWT" + +char mqttServer[16] = MQTT_HOST; +char mqttUser[23] = MQTT_USER; +char mqttPassword[32] = MQTT_PASSW; +// char mqttNodeName[16] = MQTT_NODENAME; +char mqttGroupName[16] = MQTT_GROUPNAME; +uint16_t mqttPort = MQTT_PORT; + +MQTTClient mqtt_client; + +int disc_finished = 0; +int subscribed = 0; +int connected = 0; + +int mqttPublish(const char* topic, const char* payload, size_t len, bool retain); + +/* ===== Paho event callbacks ===== */ + +void connlost(void* context, char* cause) +{ + printf("\nConnection lost\n"); + if(cause) printf(" cause: %s\n", cause); + + printf("Reconnecting\n"); + mqttStart(); +} + +// Receive incoming messages +static void mqtt_message_cb(char* topic, char* payload, unsigned int length) +{ // Handle incoming commands from MQTT + if(length + 1 >= MQTT_MAX_PACKET_SIZE) { + LOG_ERROR(TAG_MQTT_RCV, F("Payload too long (%d bytes)"), length); + return; + } else { + payload[length] = '\0'; + } + + LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, (char*)payload); + + if(topic == strstr(topic, mqttNodeTopic)) { // startsWith mqttNodeTopic + + // Node topic + topic += strlen(mqttNodeTopic); // shorten topic + + } else if(topic == strstr(topic, mqttGroupTopic)) { // startsWith mqttGroupTopic + + // Group topic + topic += strlen(mqttGroupTopic); // shorten topic + dispatch_topic_payload(topic, (const char*)payload); + return; + + } else if(topic == strstr_P(topic, PSTR("homeassistant/status"))) { // HA discovery topic + if(mqttHAautodiscover && !strcasecmp_P((char*)payload, PSTR("online"))) { + dispatch_current_state(); + mqtt_ha_register_auto_discovery(); + } + return; + + } else { + // Other topic + LOG_ERROR(TAG_MQTT, F(D_MQTT_INVALID_TOPIC)); + return; + } + + // catch a dangling LWT from a previous connection if it appears + if(!strcmp_P(topic, PSTR(LWT_TOPIC))) { // endsWith LWT + if(!strcasecmp_P((char*)payload, PSTR("offline"))) { + { + char msg[8]; + char tmp_topic[strlen(mqttNodeTopic) + 8]; + snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" LWT_TOPIC), mqttNodeTopic); + snprintf_P(msg, sizeof(msg), PSTR("online")); + + // /*bool res =*/mqttClient.publish(tmp_topic, msg, true); + mqttPublish(tmp_topic, msg, strlen(msg), true); + } + + } else { + // LOG_TRACE(TAG_MQTT, F("ignoring LWT = online")); + } + } else { + dispatch_topic_payload(topic, (const char*)payload); + } +} + +int msgarrvd(void* context, char* topicName, int topicLen, MQTTClient_message* message) +{ + // printf("MQT RCV >> "); + // printf("%s => %.*s (%d)\n", topicName, message->payloadlen, (char *)message->payload, message->payloadlen); + + char msg[message->payloadlen + 1]; + memcpy(msg, (char*)message->payload, message->payloadlen); + msg[message->payloadlen] = '\0'; + + mqtt_message_cb(topicName, msg, message->payloadlen); + + MQTTClient_freeMessage(&message); + MQTTClient_free(topicName); + return 1; // the message was received properly +} + +void mqtt_subscribe(void* context, const char* topic) +{ + MQTTClient client = (MQTTClient)context; + int rc; + + printf("Subscribing to topic %s\n", topic); + //\nfor client %s using QoS%d\n\n", topic, CLIENTID, QOS); + if((rc = MQTTClient_subscribe(client, topic, QOS)) != MQTTCLIENT_SUCCESS) { + printf("Failed to start subscribe, return code %d\n", rc); + } +} + +/* ===== Local HASP MQTT functions ===== */ + +int mqttPublish(const char* topic, const char* payload, size_t len, bool retain) +{ + if(!mqttIsConnected()) return MQTT_ERR_NO_CONN; + + MQTTClient_message pubmsg = MQTTClient_message_initializer; + MQTTClient_deliveryToken token; + + pubmsg.payload = (char*)payload; + pubmsg.payloadlen = len; // (int)strlen(payload); + pubmsg.qos = QOS; + pubmsg.retained = retain; + + MQTTClient_publishMessage(mqtt_client, topic, &pubmsg, &token); + int rc = MQTTClient_waitForCompletion(mqtt_client, token, TIMEOUT); + + if(rc != MQTTCLIENT_SUCCESS) { + LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " '%s' => %s"), topic, payload); + return MQTT_ERR_PUB_FAIL; + } else { + // LOG_TRACE(TAG_MQTT_PUB, F("'%s' => %s OK"), topic, payload); + return MQTT_ERR_OK; + } +} + +// static bool mqttPublish(const char* topic, const char* payload, bool retain) +// { +// return mqttPublish(topic, payload, strlen(payload), retain); +// } + +/* ===== Public HASP MQTT functions ===== */ + +bool mqttIsConnected() +{ + return connected == 1; +} + +int mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload) +{ + char tmp_topic[strlen(mqttNodeTopic) + 20]; + // printf(("%sstate/%s\n"), mqttNodeTopic, subtopic); + snprintf_P(tmp_topic, sizeof(tmp_topic), ("%sstate/%s"), mqttNodeTopic, subtopic); + return mqttPublish(tmp_topic, payload, strlen(payload), false); +} + +int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload) +{ + char tmp_topic[strlen(mqttNodeTopic) + 20]; + snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/p%ub%u"), mqttNodeTopic, pageid, btnid); + return mqttPublish(tmp_topic, payload, strlen(payload), false); +} + +static void onConnect(void* context) +{ + MQTTClient client = (MQTTClient)context; + connected = 1; + + printf("Successful connection\n"); + + mqtt_subscribe(mqtt_client, TOPIC "command/#"); + // mqtt_subscribe(mqtt_client, TOPIC "command"); + mqtt_subscribe(mqtt_client, TOPIC "light/#"); + mqtt_subscribe(mqtt_client, TOPIC "brightness/#"); + mqtt_subscribe(mqtt_client, "hass/status"); + + /* Home Assistant auto-configuration */ + if(mqttHAautodiscover) mqtt_subscribe(mqtt_client, "homeassistant/status"); + + mqttPublish(TOPIC LWT_TOPIC, "online", 6, false); + + mqtt_send_object_state(0, 0, "connected"); + std::cout << std::endl; +} + +void mqttStart() +{ + MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; + MQTTClient_willOptions will_opts = MQTTClient_willOptions_initializer; + int rc; + int ch; + + if((rc = MQTTClient_create(&mqtt_client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL)) != + MQTTCLIENT_SUCCESS) { + printf("Failed to create client, return code %d\n", rc); + rc = EXIT_FAILURE; + return; + } + + // if((rc = MQTTClient_setCallbacks(mqtt_client, mqtt_client, connlost, msgarrvd, NULL)) != MQTTCLIENT_SUCCESS) { + // printf("Failed to set callbacks, return code %d\n", rc); + // rc = EXIT_FAILURE; + // return; + // } + + conn_opts.will = &will_opts; + conn_opts.will->message = "offline"; + conn_opts.will->qos = 1; + conn_opts.will->retained = 0; + conn_opts.will->topicName = "hasp/plate35/LWT"; + + conn_opts.keepAliveInterval = 20; + conn_opts.cleansession = 1; + + conn_opts.username = "hasp"; + conn_opts.password = "hasp"; + + if((rc = MQTTClient_connect(mqtt_client, &conn_opts)) != MQTTCLIENT_SUCCESS) { + printf("Failed to start connect, return code %d\n", rc); + rc = EXIT_FAILURE; + // goto destroy_exit; + } else { + onConnect(&mqtt_client); + } + + // while (!subscribed && !finished) + // #if defined(_WIN32) + // Sleep(100); + // #else + // usleep(10000L); + // #endif + + // if (finished) + // goto exit; +} + +void mqttStop() +{ + int rc; + // MQTTClient_disconnectOptions disc_opts = MQTTClient_disconnectOptions_initializer; + // disc_opts.onSuccess = onDisconnect; + // disc_opts.onFailure = onDisconnectFailure; + if((rc = MQTTClient_disconnect(mqtt_client, 1000)) != MQTTCLIENT_SUCCESS) { + printf("Failed to start disconnect, return code %d\n", rc); + rc = EXIT_FAILURE; + // goto destroy_exit; + } + // while (!disc_finished) + // { + // #if defined(_WIN32) + // Sleep(100); + // #else + // usleep(10000L); + // #endif + // } + + // destroy_exit: + // MQTTClient_destroy(&client); + // exit: + // return rc; +} + +void mqttSetup(){}; + +char* topicName; +int topicLen; +MQTTClient_message* message; +void mqttLoop() +{ + + int rc = MQTTClient_receive(mqtt_client, &topicName, &topicLen, &message, 4); + if(rc == MQTTCLIENT_SUCCESS && message) msgarrvd(mqtt_client, topicName, topicLen, message); +}; + +void mqttEvery5Seconds(bool wifiIsConnected){}; + +#endif // USE_PAHO +#endif // USE_MQTT \ No newline at end of file diff --git a/src/svc/hasp_mqtt.cpp b/src/mqtt/hasp_mqtt_pubsubclient.cpp similarity index 73% rename from src/svc/hasp_mqtt.cpp rename to src/mqtt/hasp_mqtt_pubsubclient.cpp index 044e68a0..3fe89dff 100644 --- a/src/svc/hasp_mqtt.cpp +++ b/src/mqtt/hasp_mqtt_pubsubclient.cpp @@ -1,111 +1,109 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #include "hasp_conf.h" + #if HASP_USE_MQTT > 0 +#ifdef USE_PUBSUBCLIENT - #include "PubSubClient.h" +#include "PubSubClient.h" - #include "hasp/hasp.h" - #include "hasp_mqtt.h" - #include "hasp_mqtt_ha.h" +#include "hasp/hasp.h" +#include "hasp_mqtt.h" +#include "hasp_mqtt_ha.h" - #if defined(ARDUINO_ARCH_ESP32) - #include +#if defined(ARDUINO_ARCH_ESP32) +#include WiFiClient mqttNetworkClient; - #elif defined(ARDUINO_ARCH_ESP8266) - #include - #include - #include +#elif defined(ARDUINO_ARCH_ESP8266) +#include +#include +#include WiFiClient mqttNetworkClient; - #else - #if defined(STM32F4xx) && HASP_USE_WIFI > 0 +#else +#if defined(STM32F4xx) && HASP_USE_WIFI > 0 // #include WiFiSpiClient mqttNetworkClient; - #else - #if defined(W5500_MOSI) && defined(W5500_MISO) && defined(W5500_SCLK) - #define W5500_LAN - #include - #else - #include - #endif +#else +#if defined(W5500_MOSI) && defined(W5500_MISO) && defined(W5500_SCLK) +#define W5500_LAN +#include +#else +#include +#endif EthernetClient mqttNetworkClient; - #endif - #endif +#endif +#endif - #include "hasp_hal.h" - #include "hasp_debug.h" - #include "hasp_config.h" +#include "hal/hasp_hal.h" +#include "hasp_debug.h" +#include "hasp_config.h" - #include "../hasp/hasp_dispatch.h" +#include "../hasp/hasp_dispatch.h" - #ifdef USE_CONFIG_OVERRIDE - #include "user_config_override.h" - #endif +#ifdef USE_CONFIG_OVERRIDE +#include "user_config_override.h" +#endif char mqttNodeTopic[24]; char mqttGroupTopic[24]; bool mqttEnabled = false; bool mqttHAautodiscover = true; - //////////////////////////////////////////////////////////////////////////////////////////////////// - // These defaults may be overwritten with values saved by the web interface - #ifndef MQTT_HOST - #define MQTT_HOST ""; - #endif +//////////////////////////////////////////////////////////////////////////////////////////////////// +// These defaults may be overwritten with values saved by the web interface +#ifndef MQTT_HOST +#define MQTT_HOST ""; +#endif - #ifndef MQTT_PORT - #define MQTT_PORT 1883; - #endif +#ifndef MQTT_PORT +#define MQTT_PORT 1883; +#endif - #ifndef MQTT_USER - #define MQTT_USER ""; - #endif +#ifndef MQTT_USER +#define MQTT_USER ""; +#endif - #ifndef MQTT_PASSW - #define MQTT_PASSW ""; - #endif - #ifndef MQTT_NODENAME - #define MQTT_NODENAME ""; - #endif - #ifndef MQTT_GROUPNAME - #define MQTT_GROUPNAME ""; - #endif +#ifndef MQTT_PASSW +#define MQTT_PASSW ""; +#endif +#ifndef MQTT_NODENAME +#define MQTT_NODENAME ""; +#endif +#ifndef MQTT_GROUPNAME +#define MQTT_GROUPNAME ""; +#endif - #ifndef MQTT_PREFIX - #define MQTT_PREFIX "hasp" - #endif +#ifndef MQTT_PREFIX +#define MQTT_PREFIX "hasp" +#endif - #define LWT_TOPIC "LWT" +#define LWT_TOPIC "LWT" -char mqttServer[16] = MQTT_HOST; -char mqttUser[23] = MQTT_USER; -char mqttPassword[32] = MQTT_PASSW; -char mqttNodeName[16] = MQTT_NODENAME; +char mqttServer[16] = MQTT_HOST; +char mqttUser[23] = MQTT_USER; +char mqttPassword[32] = MQTT_PASSW; +// char mqttNodeName[16] = MQTT_NODENAME; char mqttGroupName[16] = MQTT_GROUPNAME; uint16_t mqttPort = MQTT_PORT; PubSubClient mqttClient(mqttNetworkClient); -static bool mqttPublish(const char * topic, const char * payload, size_t len, bool retain = false) +int mqttPublish(const char* topic, const char* payload, size_t len, bool retain) { - if(mqttIsConnected()) { - if(mqttClient.beginPublish(topic, len, retain)) { - mqttClient.write((uint8_t *)payload, len); - mqttClient.endPublish(); + if(!mqttEnabled) return MQTT_ERR_DISABLED; + if(!mqttClient.connected()) return MQTT_ERR_NO_CONN; - LOG_TRACE(TAG_MQTT_PUB, F("%s => %s"), topic, payload); - return true; - } else { - LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " %s => %s"), topic, payload); - } - } else { - LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED)); + if(mqttClient.beginPublish(topic, len, retain)) { + mqttClient.write((uint8_t*)payload, len); + mqttClient.endPublish(); + return MQTT_ERR_OK; } - return false; + + return MQTT_ERR_PUB_FAIL; } -static bool mqttPublish(const char * topic, const char * payload, bool retain = false) +int mqttPublish(const char* topic, const char* payload, bool retain) { return mqttPublish(topic, payload, strlen(payload), retain); } @@ -130,23 +128,23 @@ void mqtt_send_lwt(bool online) bool res = mqttPublish(tmp_topic, tmp_payload, len, true); } -void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, char * payload) +int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload) { char tmp_topic[strlen(mqttNodeTopic) + 16]; snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/" HASP_OBJECT_NOTATION), mqttNodeTopic, pageid, btnid); - mqttPublish(tmp_topic, payload); + return mqttPublish(tmp_topic, payload, false); } -void mqtt_send_state(const __FlashStringHelper * subtopic, const char * payload) +int mqtt_send_state(const char* subtopic, const char* payload) { char tmp_topic[strlen(mqttNodeTopic) + 20]; snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/%s"), mqttNodeTopic, subtopic); - mqttPublish(tmp_topic, payload); + return mqttPublish(tmp_topic, payload, false); } //////////////////////////////////////////////////////////////////////////////////////////////////// // Receive incoming messages -static void mqtt_message_cb(char * topic, byte * payload, unsigned int length) +static void mqtt_message_cb(char* topic, byte* payload, unsigned int length) { // Handle incoming commands from MQTT if(length + 1 >= mqttClient.getBufferSize()) { LOG_ERROR(TAG_MQTT_RCV, F("Payload too long (%d bytes)"), length); @@ -155,7 +153,7 @@ static void mqtt_message_cb(char * topic, byte * payload, unsigned int length) payload[length] = '\0'; } - LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, (char *)payload); + LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, (char*)payload); if(topic == strstr(topic, mqttNodeTopic)) { // startsWith mqttNodeTopic @@ -166,13 +164,13 @@ static void mqtt_message_cb(char * topic, byte * payload, unsigned int length) // Group topic topic += strlen(mqttGroupTopic); // shorten topic - dispatch_topic_payload(topic, (const char *)payload); + dispatch_topic_payload(topic, (const char*)payload); return; } else if(topic == strstr_P(topic, PSTR("homeassistant/status"))) { // HA discovery topic - if(mqttHAautodiscover && !strcasecmp_P((char *)payload, PSTR("online"))) { - dispatch_current_state(); - mqtt_ha_register_auto_discovery(); + if(mqttHAautodiscover && !strcasecmp_P((char*)payload, PSTR("online"))) { + mqtt_ha_register_auto_discovery(); // auto-discovery first + dispatch_current_state(); // send the data } return; @@ -184,25 +182,26 @@ static void mqtt_message_cb(char * topic, byte * payload, unsigned int length) // catch a dangling LWT from a previous connection if it appears if(!strcmp_P(topic, PSTR(LWT_TOPIC))) { // endsWith LWT - if(!strcasecmp_P((char *)payload, PSTR("offline"))) { + if(!strcasecmp_P((char*)payload, PSTR("offline"))) { { char msg[8]; char tmp_topic[strlen(mqttNodeTopic) + 8]; snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" LWT_TOPIC), mqttNodeTopic); snprintf_P(msg, sizeof(msg), PSTR("online")); - /*bool res =*/mqttClient.publish(tmp_topic, msg, true); + // /*bool res =*/mqttClient.publish(tmp_topic, msg, true); + mqttPublish(tmp_topic, msg, true); } } else { // LOG_TRACE(TAG_MQTT, F("ignoring LWT = online")); } } else { - dispatch_topic_payload(topic, (const char *)payload); + dispatch_topic_payload(topic, (const char*)payload); } } -static void mqttSubscribeTo(const __FlashStringHelper * format, const char * data) +static void mqttSubscribeTo(const __FlashStringHelper* format, const char* data) { char tmp_topic[strlen_P((PGM_P)format) + 2 + strlen(data)]; snprintf_P(tmp_topic, sizeof(tmp_topic), (PGM_P)format, data); @@ -287,7 +286,7 @@ void mqttStart() LOG_INFO(TAG_MQTT, F(D_MQTT_CONNECTED), mqttServer, mqttClientId); // Subscribe to our incoming topics - const __FlashStringHelper * F_topic; + const __FlashStringHelper* F_topic; F_topic = F("%scommand/#"); mqttSubscribeTo(F_topic, mqttGroupTopic); mqttSubscribeTo(F_topic, mqttNodeTopic); @@ -345,10 +344,10 @@ void mqttEvery5Seconds(bool networkIsConnected) } } -String mqttGetNodename() -{ - return mqttNodeName; -} +// String mqttGetNodename() +// { +// return mqttNodeName; +// } void mqttStop() { @@ -360,13 +359,13 @@ void mqttStop() } } - #if HASP_USE_CONFIG > 0 -bool mqttGetConfig(const JsonObject & settings) +#if HASP_USE_CONFIG > 0 +bool mqttGetConfig(const JsonObject& settings) { bool changed = false; - if(strcmp(mqttNodeName, settings[FPSTR(FP_CONFIG_NAME)].as().c_str()) != 0) changed = true; - settings[FPSTR(FP_CONFIG_NAME)] = mqttNodeName; + if(strcmp(haspDevice.get_hostname(), settings[FPSTR(FP_CONFIG_NAME)].as().c_str()) != 0) changed = true; + settings[FPSTR(FP_CONFIG_NAME)] = haspDevice.get_hostname(); if(strcmp(mqttGroupName, settings[FPSTR(FP_CONFIG_GROUP)].as().c_str()) != 0) changed = true; settings[FPSTR(FP_CONFIG_GROUP)] = mqttGroupName; @@ -395,7 +394,7 @@ bool mqttGetConfig(const JsonObject & settings) * * @param[in] settings JsonObject with the config settings. **/ -bool mqttSetConfig(const JsonObject & settings) +bool mqttSetConfig(const JsonObject& settings) { configOutput(settings, TAG_MQTT); bool changed = false; @@ -403,14 +402,17 @@ bool mqttSetConfig(const JsonObject & settings) changed |= configSet(mqttPort, settings[FPSTR(FP_CONFIG_PORT)], F("mqttPort")); if(!settings[FPSTR(FP_CONFIG_NAME)].isNull()) { - changed |= strcmp(mqttNodeName, settings[FPSTR(FP_CONFIG_NAME)]) != 0; - strncpy(mqttNodeName, settings[FPSTR(FP_CONFIG_NAME)], sizeof(mqttNodeName)); + changed |= strcmp(haspDevice.get_hostname(), settings[FPSTR(FP_CONFIG_NAME)]) != 0; + // strncpy(mqttNodeName, settings[FPSTR(FP_CONFIG_NAME)], sizeof(mqttNodeName)); + haspDevice.set_hostname(settings[FPSTR(FP_CONFIG_NAME)].as()); } // Prefill node name - if(strlen(mqttNodeName) == 0) { + if(strlen(haspDevice.get_hostname()) == 0) { + char mqttNodeName[64]; String mac = halGetMacAddress(3, ""); mac.toLowerCase(); snprintf_P(mqttNodeName, sizeof(mqttNodeName), PSTR(D_MQTT_DEFAULT_NAME), mac.c_str()); + haspDevice.set_hostname(mqttNodeName); changed = true; } @@ -440,11 +442,13 @@ bool mqttSetConfig(const JsonObject & settings) strncpy(mqttPassword, settings[FPSTR(FP_CONFIG_PASS)], sizeof(mqttPassword)); } - snprintf_P(mqttNodeTopic, sizeof(mqttNodeTopic), PSTR(MQTT_PREFIX "/%s/"), mqttNodeName); + snprintf_P(mqttNodeTopic, sizeof(mqttNodeTopic), PSTR(MQTT_PREFIX "/%s/"), haspDevice.get_hostname()); snprintf_P(mqttGroupTopic, sizeof(mqttGroupTopic), PSTR(MQTT_PREFIX "/%s/"), mqttGroupName); return changed; } - #endif // HASP_USE_CONFIG +#endif // HASP_USE_CONFIG + +#endif // PUBSUBCLIENT #endif // HASP_USE_MQTT diff --git a/src/net/hasp_network.cpp b/src/net/hasp_network.cpp deleted file mode 100644 index 31ab26d2..00000000 --- a/src/net/hasp_network.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie - For full license information read the LICENSE file in the project folder */ - -#include -#include -#define MYTZ "EST5EDT,M3.2.0/2,M11.1.0" - -#include -#include "ArduinoLog.h" - -#include "hasp_conf.h" -#include "hasp_hal.h" -#include "hasp_debug.h" -#include "hasp_network.h" - -#include "../hasp/hasp.h" -#include "../svc/hasp_mdns.h" - -#if HASP_USE_ETHERNET > 0 || HASP_USE_WIFI > 0 -void networkStart(void) -{ - haspProgressVal(255); // hide - configTzTime(MYTZ, "pool.ntp.org", "time.nist.gov", NULL); // literal string - - haspReconnect(); - debugStartSyslog(); - // mqttStart(); - httpStart(); - mdnsStart(); -} - -void networkStop(void) -{ - haspProgressMsg(F("Network Disconnected")); - - debugStopSyslog(); - // mqttStop(); - httpStop(); - mdnsStop(); -} - -void networkSetup() -{ - #if HASP_USE_ETHERNET > 0 - ethernetSetup(); - #endif - - #if HASP_USE_WIFI > 0 - wifiSetup(); - #endif -} - -void networkLoop(void) -{ - #if HASP_USE_ETHERNET > 0 - ethernetLoop(); - #endif - - #if HASP_USE_WIFI > 0 - // wifiLoop(); - #endif -} - -bool networkEvery5Seconds(void) -{ - #if HASP_USE_ETHERNET > 0 - return ethernetEvery5Seconds(); - #endif - - #if HASP_USE_WIFI > 0 - return wifiEvery5Seconds(); - #endif - - return false; -} - -bool networkEverySecond(void) -{ - #if HASP_USE_ETHERNET > 0 - // return ethernetEverySecond(); - #endif - - #if HASP_USE_WIFI > 0 - // return wifiEverySecond(); - #endif - return true; -} - -void network_get_statusupdate(char * buffer, size_t len) -{ - #if HASP_USE_ETHERNET > 0 - ethernet_get_statusupdate(buffer, len); - #endif - - #if HASP_USE_WIFI > 0 - wifi_get_statusupdate(buffer, len); - #endif -} - -#endif \ No newline at end of file diff --git a/src/net/hasp_wifi.h b/src/net/hasp_wifi.h deleted file mode 100644 index 5364150f..00000000 --- a/src/net/hasp_wifi.h +++ /dev/null @@ -1,23 +0,0 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie - For full license information read the LICENSE file in the project folder */ - -#ifndef HASP_WIFI_H -#define HASP_WIFI_H - -#include "ArduinoJson.h" - -void wifiSetup(); -bool wifiShowAP(); -bool wifiShowAP(char * ssid, char * pass); -bool wifiEvery5Seconds(void); -void wifiStop(void); - -bool wifiValidateSsid(const char * ssid, const char * pass); -void wifi_get_statusupdate(char * buffer, size_t len); - -#if HASP_USE_CONFIG > 0 -bool wifiGetConfig(const JsonObject & settings); -bool wifiSetConfig(const JsonObject & settings); -#endif - -#endif \ No newline at end of file diff --git a/src/svc/hasp_mqtt.h b/src/svc/hasp_mqtt.h deleted file mode 100644 index c1343a3c..00000000 --- a/src/svc/hasp_mqtt.h +++ /dev/null @@ -1,27 +0,0 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie - For full license information read the LICENSE file in the project folder */ - -#ifndef HASP_MQTT_H -#define HASP_MQTT_H - -#include "ArduinoJson.h" - -void mqttSetup(); -void mqttLoop(); -void mqttEvery5Seconds(bool wifiIsConnected); -void mqttStart(); -void mqttStop(); - -void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, char * payload); -void mqtt_send_state(const __FlashStringHelper * subtopic, const char * payload); - -bool mqttIsConnected(); - -#if HASP_USE_CONFIG > 0 -bool mqttGetConfig(const JsonObject & settings); -bool mqttSetConfig(const JsonObject & settings); -#endif - -String mqttGetNodename(void); - -#endif \ No newline at end of file diff --git a/src/svc/hasp_slave.h b/src/svc/hasp_slave.h deleted file mode 100644 index a97e132d..00000000 --- a/src/svc/hasp_slave.h +++ /dev/null @@ -1,22 +0,0 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie - For full license information read the LICENSE file in the project folder */ - -#ifndef HASP_SLAVE_H -#define HASP_SLAVE_H - -#include "ArduinoJson.h" - -#define HASP_SLAVE_SPEED 57600 - -void TASMO_EVERY_SECOND(void); -void TASMO_DATA_RECEIVE(char *data); -void slave_send_state(const __FlashStringHelper * subtopic, const char * payload); -void slave_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char * attribute, const char * data); -void slave_send_input(uint8_t id, const char * payload); -void slave_send_statusupdate(); - -void slaveSetup(); -void slaveLoop(void); - - -#endif \ No newline at end of file diff --git a/src/sys/README.md b/src/sys/README.md new file mode 100644 index 00000000..33252851 --- /dev/null +++ b/src/sys/README.md @@ -0,0 +1,4 @@ +System Component functions +- net : Control of the user customizable GPIO funcionality +- net : Unified network functions for wifi or ethernet +- svc : Network services diff --git a/src/hasp_gpio.cpp b/src/sys/gpio/hasp_gpio.cpp similarity index 87% rename from src/hasp_gpio.cpp rename to src/sys/gpio/hasp_gpio.cpp index 91f519cd..31762e7c 100644 --- a/src/hasp_gpio.cpp +++ b/src/sys/gpio/hasp_gpio.cpp @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #include "AceButton.h" @@ -12,13 +12,13 @@ #include "hasp/hasp.h" #ifdef ARDUINO_ARCH_ESP8266 - #define INPUT_PULLDOWN INPUT +#define INPUT_PULLDOWN INPUT #endif uint8_t gpioUsedInputCount = 0; using namespace ace_button; -static AceButton * button[HASP_NUM_INPUTS]; +static AceButton* button[HASP_NUM_INPUTS]; // An array of button pins, led pins, and the led states. Cannot be const // because ledState is mutable. @@ -49,7 +49,7 @@ class TouchConfig : public ButtonConfig { TouchConfig touchConfig(); #endif -static void gpio_event_handler(AceButton * button, uint8_t eventType, uint8_t buttonState) +static void gpio_event_handler(AceButton* button, uint8_t eventType, uint8_t buttonState) { uint8_t btnid = button->getId(); uint8_t eventid; @@ -90,12 +90,12 @@ static void gpio_event_handler(AceButton * button, uint8_t eventType, uint8_t bu dispatch_gpio_input_event(gpioConfig[btnid].pin, gpioConfig[btnid].group, eventid); if(eventid != HASP_EVENT_LONG) // do not repeat DOWN + LONG - dispatch_normalized_group_value(gpioConfig[btnid].group, NORMALIZE(state, 0, 1), NULL); + dispatch_normalized_group_value(gpioConfig[btnid].group, NULL, state, HASP_EVENT_OFF, HASP_EVENT_ON); } void aceButtonSetup(void) { - ButtonConfig * buttonConfig = ButtonConfig::getSystemButtonConfig(); + ButtonConfig* buttonConfig = ButtonConfig::getSystemButtonConfig(); buttonConfig->setEventHandler(gpio_event_handler); // Features @@ -128,14 +128,14 @@ void gpioAddButton(uint8_t pin, uint8_t input_mode, uint8_t default_state, uint8 if(!button[i]) { LOG_TRACE(TAG_GPIO, F("Creating Button%d on pin %d (index %d) mode %d default %d"), i, pin, index, - input_mode, default_state); + input_mode, default_state); button[i] = new AceButton(pin, default_state, index); if(button[i]) { // pinMode(pin, input_mode); - ButtonConfig * buttonConfig = button[i]->getButtonConfig(); + ButtonConfig* buttonConfig = button[i]->getButtonConfig(); buttonConfig->setEventHandler(gpio_event_handler); buttonConfig->setFeature(ButtonConfig::kFeatureClick); buttonConfig->clearFeature(ButtonConfig::kFeatureDoubleClick); @@ -146,7 +146,7 @@ void gpioAddButton(uint8_t pin, uint8_t input_mode, uint8_t default_state, uint8 buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterClick); LOG_INFO(TAG_GPIO, F("Button%d created on pin %d (index %d) mode %d default %d"), i, pin, index, - input_mode, default_state); + input_mode, default_state); gpioUsedInputCount = i + 1; return; } @@ -163,19 +163,19 @@ void gpioAddSwitch(uint8_t pin, uint8_t input_mode, uint8_t default_state, uint8 if(!button[i]) { LOG_TRACE(TAG_GPIO, F("Creating Switch%d on pin %d (index %d) mode %d default %d"), i, pin, index, - input_mode, default_state); + input_mode, default_state); button[i] = new AceButton(pin, default_state, index); if(button[i]) { // pinMode(pin, input_mode); - ButtonConfig * buttonConfig = button[i]->getButtonConfig(); + ButtonConfig* buttonConfig = button[i]->getButtonConfig(); buttonConfig->setEventHandler(gpio_event_handler); buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAll); LOG_INFO(TAG_GPIO, F("Button%d switch on pin %d (index %d) mode %d default %d"), i, pin, index, - input_mode, default_state); + input_mode, default_state); gpioUsedInputCount = i + 1; return; } @@ -196,7 +196,7 @@ void gpioAddTouchButton(uint8_t pin, uint8_t input_mode, uint8_t default_state, if(button[i]) { pinMode(pin, input_mode); - ButtonConfig * buttonConfig = button[i]->getButtonConfig(); + ButtonConfig* buttonConfig = button[i]->getButtonConfig(); buttonConfig->setEventHandler(gpio_event_handler); buttonConfig->setFeature(ButtonConfig::kFeatureClick); buttonConfig->clearFeature(ButtonConfig::kFeatureDoubleClick); @@ -206,7 +206,7 @@ void gpioAddTouchButton(uint8_t pin, uint8_t input_mode, uint8_t default_state, ButtonConfig::kFeatureSuppressClickBeforeDoubleClick); // Causes annoying pauses LOG_INFO(TAG_GPIO, F("Button%d created on pin %d (index %d) mode %d default %d"), i, pin, index, - input_mode, default_state); + input_mode, default_state); gpioUsedInputCount = i + 1; return; } @@ -279,27 +279,41 @@ void gpioSetup() } /* ********************************* State Setters *************************************** */ -void gpio_set_normalized_value(hasp_gpio_config_t gpio, uint16_t state) +void gpio_set_normalized_value(hasp_gpio_config_t gpio, int16_t val, int16_t min, int16_t max) { + if(min == max) { + LOG_ERROR(TAG_GPIO, F("Invalid value range")); + return; + } + switch(gpio.type) { case HASP_GPIO_RELAY: - gpio.val = state >= 0x8000U ? HIGH : LOW; + gpio.val = val > min ? HIGH : LOW; digitalWrite(gpio.pin, gpio.val); break; case HASP_GPIO_RELAY_INVERTED: - gpio.val = state >= 0x8000U ? LOW : HIGH; + gpio.val = val > min ? LOW : HIGH; digitalWrite(gpio.pin, gpio.val); break; case HASP_GPIO_LED: case HASP_GPIO_LED_R: case HASP_GPIO_LED_G: case HASP_GPIO_LED_B: - case HASP_GPIO_PWM: #if defined(ARDUINO_ARCH_ESP32) - gpio.val = map(state, 0, 0xFFFFU, 0, 4095); + gpio.val = map(val, min, max, 0, 4095); ledcWrite(gpio.group, gpio.val); // ledChannel and value #else - analogWrite(gpio.pin, map(state, 0, 0xFFFFU, 0, 1023)); + gpio.val = map(val, min, max, 0, 1023); + analogWrite(gpio.pin, gpio.val); +#endif + break; + case HASP_GPIO_PWM: +#if defined(ARDUINO_ARCH_ESP32) + gpio.val = map(val, min, max, 0, 4095); + ledcWrite(gpio.group, gpio.val); // ledChannel and value +#else + gpio.val = map(val, min, max, 0, 1023); + analogWrite(gpio.pin, gpio.val); #endif break; case HASP_GPIO_LED_INVERTED: @@ -308,10 +322,11 @@ void gpio_set_normalized_value(hasp_gpio_config_t gpio, uint16_t state) case HASP_GPIO_LED_B_INVERTED: case HASP_GPIO_PWM_INVERTED: #if defined(ARDUINO_ARCH_ESP32) - gpio.val = map(0xFFFFU - state, 0, 0xFFFFU, 0, 4095); + gpio.val = map(val, min, max, 0, 4095); ledcWrite(gpio.group, gpio.val); // ledChannel and value #else - analogWrite(gpio.pin, map(0xFFFFU - state, 0, 0xFFFFU, 0, 1023)); + gpio.val = map(val, min, max, 0, 1023); + analogWrite(gpio.pin, gpio.val); #endif break; @@ -330,28 +345,39 @@ void gpio_set_normalized_value(hasp_gpio_config_t gpio, uint16_t state) // } // } -void gpio_set_normalized_group_value(uint8_t groupid, uint16_t state) +void gpio_set_normalized_group_value(uint8_t groupid, int16_t val, int16_t min, int16_t max) { + if(min == max) { + LOG_ERROR(TAG_GPIO, F("Invalid value range")); + return; + } + // bool state = dispatch_get_event_state(eventid); for(uint8_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { if(gpioConfig[i].group == groupid) { - gpio_set_normalized_value(gpioConfig[i], state); + gpio_set_normalized_value(gpioConfig[i], val, min, max); } } } void gpio_set_moodlight(uint8_t r, uint8_t g, uint8_t b) { + // uint16_t max_level = power == 0 ? 0 : map(brightness, 0, 0xFF, 0, 0xFFFFU); + uint16_t max_level = 0xFFFFU; + for(uint8_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { - switch(gpioConfig[i].type & 0xfe) { + switch(gpioConfig[i].type) { case HASP_GPIO_LED_R: - gpio_set_normalized_value(gpioConfig[i], map(r, 0, 0xFF, 0, 0xFFFFU)); + case HASP_GPIO_LED_R_INVERTED: + gpio_set_normalized_value(gpioConfig[i], r, 0, 0xFF); break; case HASP_GPIO_LED_G: - gpio_set_normalized_value(gpioConfig[i], map(g, 0, 0xFF, 0, 0xFFFFU)); + case HASP_GPIO_LED_G_INVERTED: + gpio_set_normalized_value(gpioConfig[i], g, 0, 0xFF); break; case HASP_GPIO_LED_B: - gpio_set_normalized_value(gpioConfig[i], map(b, 0, 0xFF, 0, 0xFFFFU)); + case HASP_GPIO_LED_B_INVERTED: + gpio_set_normalized_value(gpioConfig[i], b, 0, 0xFF); break; } } @@ -460,7 +486,7 @@ bool gpioIsSystemPin(uint8_t gpio) // Backlight GPIO // Network GPIOs // Serial GPIOs - // Tasmota Slave GPIOs + // Tasmota Client GPIOs #ifdef ARDUINO_ARCH_ESP32 if((gpio >= 6) && (gpio <= 11)) return true; // integrated SPI flash @@ -472,9 +498,9 @@ bool gpioIsSystemPin(uint8_t gpio) #ifdef ARDUINO_ARCH_ESP8266 if((gpio >= 6) && (gpio <= 11)) return true; // integrated SPI flash - #ifndef TFT_SPI_OVERLAP +#ifndef TFT_SPI_OVERLAP if((gpio >= 12) && (gpio <= 14)) return true; // HSPI - #endif +#endif #endif return false; @@ -505,7 +531,7 @@ bool gpioSavePinConfig(uint8_t config_num, uint8_t pin, uint8_t type, uint8_t gr gpioConfig[config_num].group = group; gpioConfig[config_num].gpio_function = pinfunc; LOG_TRACE(TAG_GPIO, F("Saving Pin config #%d pin %d - type %d - group %d - func %d"), config_num, pin, type, - group, pinfunc); + group, pinfunc); return true; } @@ -535,7 +561,7 @@ hasp_gpio_config_t gpioGetPinConfig(uint8_t num) //////////////////////////////////////////////////////////////////////////////////////////////////// #if HASP_USE_CONFIG > 0 -bool gpioGetConfig(const JsonObject & settings) +bool gpioGetConfig(const JsonObject& settings) { bool changed = false; @@ -579,7 +605,7 @@ bool gpioGetConfig(const JsonObject & settings) * * @param[in] settings JsonObject with the config settings. **/ -bool gpioSetConfig(const JsonObject & settings) +bool gpioSetConfig(const JsonObject& settings) { configOutput(settings); bool changed = false; diff --git a/src/hasp_gpio.h b/src/sys/gpio/hasp_gpio.h similarity index 90% rename from src/hasp_gpio.h rename to src/sys/gpio/hasp_gpio.h index 1ff8507c..a19674e0 100644 --- a/src/hasp_gpio.h +++ b/src/sys/gpio/hasp_gpio.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_GPIO_H @@ -24,7 +24,7 @@ void gpioLoop(void); void gpioEvery5Seconds(void); // void gpio_set_group_onoff(uint8_t groupid, bool ison); -void gpio_set_normalized_group_value(uint8_t groupid, uint16_t state); +void gpio_set_normalized_group_value(uint8_t groupid, int16_t val, int16_t min, int16_t max); // void gpio_set_gpio_state(uint8_t pin, uint16_t state); void gpio_set_moodlight(uint8_t r, uint8_t g, uint8_t b); @@ -36,8 +36,8 @@ int8_t gpioGetFreeConfigId(); hasp_gpio_config_t gpioGetPinConfig(uint8_t num); #if HASP_USE_CONFIG > 0 -bool gpioGetConfig(const JsonObject & settings); -bool gpioSetConfig(const JsonObject & settings); +bool gpioGetConfig(const JsonObject& settings); +bool gpioSetConfig(const JsonObject& settings); #endif #define HASP_GPIO_FREE 0x00 diff --git a/src/net/hasp_ethernet_esp32.cpp b/src/sys/net/hasp_ethernet_esp32.cpp similarity index 84% rename from src/net/hasp_ethernet_esp32.cpp rename to src/sys/net/hasp_ethernet_esp32.cpp index b32ba958..a0415e71 100644 --- a/src/net/hasp_ethernet_esp32.cpp +++ b/src/sys/net/hasp_ethernet_esp32.cpp @@ -1,12 +1,13 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ - #include "hasp_conf.h" -#include "hasp_hal.h" #include "hasp_debug.h" #include "hasp_network.h" +#include "hal/hasp_hal.h" +#include "dev/device.h" + #if HASP_USE_ETHERNET > 0 && defined(ARDUINO_ARCH_ESP32) IPAddress ip; @@ -17,7 +18,7 @@ void EthernetEvent(WiFiEvent_t event) case SYSTEM_EVENT_ETH_START: LOG_TRACE(TAG_ETH, F(D_SERVICE_STARTED)); // set eth hostname here - ETH.setHostname(mqttGetNodename().c_str()); + ETH.setHostname(haspDevice.get_hostname()); break; case SYSTEM_EVENT_ETH_CONNECTED: LOG_TRACE(TAG_ETH, F(D_SERVICE_CONNECTED)); @@ -63,10 +64,10 @@ bool ethernetEvery5Seconds() return eth_connected; } -void ethernet_get_statusupdate(char * buffer, size_t len) +void ethernet_get_statusupdate(char* buffer, size_t len) { - snprintf_P(buffer, len, PSTR("\"eth\":\"%s\",\"link\":\"%d Mbps\",\"ip\":\"%s\","), eth_connected ? F("ON") : F("OFF"), ETH.linkSpeed(), - ETH.localIP().toString().c_str()); + snprintf_P(buffer, len, PSTR("\"eth\":\"%s\",\"link\":\"%d Mbps\",\"ip\":\"%s\","), + eth_connected ? F("on") : F("off"), ETH.linkSpeed(), ETH.localIP().toString().c_str()); } #endif \ No newline at end of file diff --git a/src/net/hasp_ethernet_esp32.h b/src/sys/net/hasp_ethernet_esp32.h similarity index 64% rename from src/net/hasp_ethernet_esp32.h rename to src/sys/net/hasp_ethernet_esp32.h index 5e824a34..8a25a147 100644 --- a/src/net/hasp_ethernet_esp32.h +++ b/src/sys/net/hasp_ethernet_esp32.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_ETHERNET_ESP32_H @@ -9,7 +9,8 @@ static bool eth_connected = false; void ethernetSetup(); void ethernetLoop(void); +bool ethernetEverySecond(); bool ethernetEvery5Seconds(); -void ethernet_get_statusupdate(char * buffer, size_t len); +void ethernet_get_statusupdate(char* buffer, size_t len); #endif \ No newline at end of file diff --git a/src/net/hasp_ethernet_stm32.cpp b/src/sys/net/hasp_ethernet_stm32.cpp similarity index 85% rename from src/net/hasp_ethernet_stm32.cpp rename to src/sys/net/hasp_ethernet_stm32.cpp index 46935132..39787953 100644 --- a/src/net/hasp_ethernet_stm32.cpp +++ b/src/sys/net/hasp_ethernet_stm32.cpp @@ -1,10 +1,10 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #include "hasp_conf.h" #include "hasp_debug.h" -#include "hasp_hal.h" +#include "hal/hasp_hal.h" #if HASP_USE_ETHERNET > 0 && defined(STM32F4xx) @@ -13,9 +13,9 @@ IPAddress ip; void ethernetSetup() { - #if USE_BUILTIN_ETHERNET > 0 +#if USE_BUILTIN_ETHERNET > 0 // start Ethernet and UDP - LOG_TRACE(TAG_ETH, F("LAN8720 "D_SERVICE_STARTING)); + LOG_TRACE(TAG_ETH, F("LAN8720 " D_SERVICE_STARTING)); if(Ethernet.begin() == 0) { LOG_TRACE(TAG_ETH, F("Failed to configure Ethernet using DHCP")); eth_connected = false; @@ -27,7 +27,7 @@ void ethernetSetup() LOG_TRACE(TAG_ETH, F("MAC Address %s"), halGetMacAddress(0, ":")); - #else +#else byte mac[6]; uint32_t baseUID = (uint32_t)UID_BASE; mac[0] = 0x00; @@ -44,14 +44,14 @@ void ethernetSetup() Ethernet.setCsPin(W5500_CS); Ethernet.setRstPin(W5500_RST); Ethernet.setHostname(ethHostname); - LOG_TRACE(TAG_ETH, F("W5500 "D_SERVICE_STARTING)); + LOG_TRACE(TAG_ETH, F("W5500 " D_SERVICE_STARTING)); if(Ethernet.begin(mac) == 0) { LOG_TRACE(TAG_ETH, F("Failed to configure Ethernet using DHCP")); } else { ip = Ethernet.localIP(); LOG_TRACE(TAG_ETH, F("DHCP Success got IP %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); } - #endif +#endif } void ethernetLoop(void) @@ -88,25 +88,25 @@ void ethernetLoop(void) bool ethernetEvery5Seconds() { bool state; - #if USE_BUILTIN_ETHERNET > 0 +#if USE_BUILTIN_ETHERNET > 0 state = Ethernet.linkStatus() == LinkON; - #else +#else state = Ethernet.link() == 1; - #endif +#endif LOG_WARNING(TAG_ETH, state ? F(D_NETWORK_ONLINE) : F(D_NETWORK_OFFLINE)); return state; } -void ethernet_get_statusupdate(char * buffer, size_t len) +void ethernet_get_statusupdate(char* buffer, size_t len) { - #if USE_BUILTIN_ETHERNET > 0 +#if USE_BUILTIN_ETHERNET > 0 bool state = Ethernet.linkStatus() == LinkON; - #else +#else bool state = Ethernet.link() == 1; - #endif +#endif IPAddress ip = Ethernet.localIP(); - snprintf_P(buffer, len, PSTR("\"eth\":\"%s\",\"link\":%d,\"ip\":\"%d.%d.%d.%d\","), state ? F("ON") : F("OFF"), 10, + snprintf_P(buffer, len, PSTR("\"eth\":\"%s\",\"link\":%d,\"ip\":\"%d.%d.%d.%d\","), state ? F("on") : F("off"), 10, ip[0], ip[1], ip[2], ip[3]); } #endif \ No newline at end of file diff --git a/src/net/hasp_ethernet_stm32.h b/src/sys/net/hasp_ethernet_stm32.h similarity index 64% rename from src/net/hasp_ethernet_stm32.h rename to src/sys/net/hasp_ethernet_stm32.h index 04ddec72..f499069f 100644 --- a/src/net/hasp_ethernet_stm32.h +++ b/src/sys/net/hasp_ethernet_stm32.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_ETHERNET_STM32_H @@ -9,7 +9,8 @@ static bool eth_connected = false; void ethernetSetup(); void ethernetLoop(void); +bool ethernetEverySecond(); bool ethernetEvery5Seconds(); -void ethernet_get_statusupdate(char * buffer, size_t len); +void ethernet_get_statusupdate(char* buffer, size_t len); #endif \ No newline at end of file diff --git a/src/sys/net/hasp_network.cpp b/src/sys/net/hasp_network.cpp new file mode 100644 index 00000000..ba6dd8b0 --- /dev/null +++ b/src/sys/net/hasp_network.cpp @@ -0,0 +1,134 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#include +#include +#ifdef USE_CONFIG_OVERRIDE +#include "user_config_override.h" +#endif +#ifndef MYTZ +#define MYTZ "EST5EDT,M3.2.0/2,M11.1.0" +#endif +#include +#include "ArduinoLog.h" + +#include "hasp_conf.h" +#include "hal/hasp_hal.h" +#include "hasp_debug.h" +#include "hasp_network.h" + +#include "hasp/hasp.h" +#include "sys/svc/hasp_mdns.h" + +#if HASP_USE_ETHERNET > 0 || HASP_USE_WIFI > 0 +void networkStart(void) +{ +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) + LOG_WARNING(TAG_MAIN, F("TIMEZONE: %s"), MYTZ); + configTzTime(MYTZ, "pool.ntp.org", "time.nist.gov", NULL); // literal string +#endif + + haspProgressVal(255); // hide + haspReconnect(); + debugStartSyslog(); + // mqttStart(); + httpStart(); + mdnsStart(); +} + +void networkStop(void) +{ + haspProgressMsg(F("Network Disconnected")); + + debugStopSyslog(); + // mqttStop(); + httpStop(); + mdnsStop(); +} + +void networkSetup() +{ +#if HASP_USE_ETHERNET > 0 + ethernetSetup(); +#endif + +#if HASP_USE_WIFI > 0 + wifiSetup(); +#endif +} + +void networkLoop(void) +{ +#if HASP_USE_ETHERNET > 0 + ethernetLoop(); +#endif + +#if HASP_USE_WIFI > 0 + // wifiLoop(); +#endif + +#if HASP_USE_TASMOTA_CLIENT > 0 + tasmotaclientLoop(); +#endif // HASP_USE_TASMOTA_CLIENT + +#if HASP_USE_HTTP > 0 + httpLoop(); +#endif // HTTP + +#if HASP_USE_OTA > 0 + otaLoop(); +#endif // OTA + +#if HASP_USE_MDNS > 0 + mdnsLoop(); +#endif // MDNS + +#if HASP_USE_TELNET > 0 + telnetLoop(); // Console +#endif // TELNET +} + +bool networkEvery5Seconds(void) +{ +#if HASP_USE_ETHERNET > 0 + return ethernetEvery5Seconds(); +#endif + +#if HASP_USE_WIFI > 0 + return wifiEvery5Seconds(); +#endif + + return false; +} + +bool networkEverySecond(void) +{ + bool connected = false; + +#if HASP_USE_ETHERNET > 0 + connected |= ethernetEverySecond(); +#endif + +#if HASP_USE_WIFI > 0 + // connected |= wifiEverySecond(); +#endif + +#if HASP_USE_OTA > 0 + otaEverySecond(); // progressbar +#endif + + return true; +} + +void network_get_statusupdate(char* buffer, size_t len) +{ +#if HASP_USE_ETHERNET > 0 + ethernet_get_statusupdate(buffer, len); +#endif + +#if HASP_USE_WIFI > 0 + wifi_get_statusupdate(buffer, len); +#endif +} + +#endif \ No newline at end of file diff --git a/src/net/hasp_network.h b/src/sys/net/hasp_network.h similarity index 80% rename from src/net/hasp_network.h rename to src/sys/net/hasp_network.h index facd76e7..094d96ad 100644 --- a/src/net/hasp_network.h +++ b/src/sys/net/hasp_network.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_NETWORK_H @@ -15,7 +15,7 @@ void networkStop(void); /* ===== Special Event Processors ===== */ /* ===== Getter and Setter Functions ===== */ -void network_get_statusupdate(char * buffer, size_t len); +void network_get_statusupdate(char* buffer, size_t len); /* ===== Read/Write Configuration ===== */ diff --git a/src/net/hasp_wifi.cpp b/src/sys/net/hasp_wifi.cpp similarity index 88% rename from src/net/hasp_wifi.cpp rename to src/sys/net/hasp_wifi.cpp index 4d92c17d..5746a0a2 100644 --- a/src/net/hasp_wifi.cpp +++ b/src/sys/net/hasp_wifi.cpp @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #include @@ -9,45 +9,45 @@ #if HASP_USE_WIFI > 0 - #include "hasp_debug.h" - #include "hasp_config.h" - #include "hasp_network.h" - #include "hasp_gui.h" +#include "hasp_debug.h" +#include "hasp_config.h" +#include "hasp_network.h" +#include "hasp_gui.h" - #include "hasp/hasp_dispatch.h" - #include "hasp/hasp.h" +#include "hasp/hasp_dispatch.h" +#include "hasp/hasp.h" - #if defined(ARDUINO_ARCH_ESP32) - #include - #elif defined(ARDUINO_ARCH_ESP8266) - #include - #include "user_interface.h" // Wifi Reasons +#if defined(ARDUINO_ARCH_ESP32) +#include +#elif defined(ARDUINO_ARCH_ESP8266) +#include +#include "user_interface.h" // Wifi Reasons static WiFiEventHandler gotIpEventHandler, disconnectedEventHandler; - #elif defined(STM32F4xx) +#elif defined(STM32F4xx) // #include // #include "WiFiSpi.h" // extern WiFiSpiClass WiFi; SPIClass espSPI(ESPSPI_MOSI, ESPSPI_MISO, ESPSPI_SCLK); // SPI port where esp is connected - #endif +#endif //#include "DNSserver.h" - #ifdef USE_CONFIG_OVERRIDE - #include "user_config_override.h" - #endif +#ifdef USE_CONFIG_OVERRIDE +#include "user_config_override.h" +#endif - #ifdef WIFI_SSID +#ifdef WIFI_SSID char wifiSsid[32] = WIFI_SSID; - #else +#else char wifiSsid[32] = ""; - #endif - #ifdef WIFI_PASSW +#endif +#ifdef WIFI_PASSW char wifiPassword[64] = WIFI_PASSW; - #else +#else char wifiPassword[64] = ""; - #endif +#endif uint8_t wifiReconnectCounter = 0; // const byte DNS_PORT = 53; @@ -57,20 +57,20 @@ uint8_t wifiReconnectCounter = 0; static void wifiConnected(IPAddress ipaddress) { - #if defined(STM32F4xx) +#if defined(STM32F4xx) IPAddress ip; ip = WiFi.localIP(); LOG_TRACE(TAG_WIFI, F("Received IP address %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); - #else +#else LOG_TRACE(TAG_WIFI, F(D_NETWORK_IP_ADDRESS_RECEIVED), ipaddress.toString().c_str()); - #endif +#endif LOG_VERBOSE(TAG_WIFI, F("Connected = %s"), WiFi.status() == WL_CONNECTED ? PSTR(D_NETWORK_ONLINE) : PSTR(D_NETWORK_OFFLINE)); networkStart(); } -static void wifiDisconnected(const char * ssid, uint8_t reason) +static void wifiDisconnected(const char* ssid, uint8_t reason) { wifiReconnectCounter++; @@ -85,7 +85,7 @@ static void wifiDisconnected(const char * ssid, uint8_t reason) char buffer[64]; switch(reason) { - #if defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) case REASON_UNSPECIFIED: snprintf_P(buffer, sizeof(buffer), PSTR("unspecified")); break; @@ -171,9 +171,9 @@ static void wifiDisconnected(const char * ssid, uint8_t reason) case REASON_HANDSHAKE_TIMEOUT: snprintf_P(buffer, sizeof(buffer), PSTR("handshake timeout")); break; - #endif +#endif - #if defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP32) case WIFI_REASON_UNSPECIFIED: snprintf_P(buffer, sizeof(buffer), PSTR("unspecified")); break; @@ -262,7 +262,7 @@ static void wifiDisconnected(const char * ssid, uint8_t reason) case WIFI_REASON_CONNECTION_FAIL: snprintf_P(buffer, sizeof(buffer), PSTR(D_NETWORK_CONNECTION_FAILED)); break; - #endif +#endif default: snprintf_P(buffer, sizeof(buffer), PSTR("unknown")); @@ -271,33 +271,33 @@ static void wifiDisconnected(const char * ssid, uint8_t reason) LOG_WARNING(TAG_WIFI, F("Disconnected from %s (Reason: %s [%d])"), ssid, buffer, reason); } -static void wifiSsidConnected(const char * ssid) +static void wifiSsidConnected(const char* ssid) { LOG_TRACE(TAG_WIFI, F("Connected to SSID %s. Requesting IP..."), ssid); wifiReconnectCounter = 0; } - #if defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP32) static void wifi_callback(system_event_id_t event, system_event_info_t info) { switch(event) { case SYSTEM_EVENT_STA_CONNECTED: - wifiSsidConnected((const char *)info.connected.ssid); + wifiSsidConnected((const char*)info.connected.ssid); break; case SYSTEM_EVENT_STA_GOT_IP: wifiConnected(IPAddress(info.got_ip.ip_info.ip.addr)); break; case SYSTEM_EVENT_STA_DISCONNECTED: - wifiDisconnected((const char *)info.disconnected.ssid, info.disconnected.reason); + wifiDisconnected((const char*)info.disconnected.ssid, info.disconnected.reason); // NTP.stop(); // NTP sync can be disabled to avoid sync errors break; default: break; } } - #endif +#endif - #if defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) static void wifiSTAConnected(WiFiEventStationModeConnected info) { wifiSsidConnected(info.ssid.c_str()); @@ -314,7 +314,7 @@ static void wifiSTADisconnected(WiFiEventStationModeDisconnected info) { wifiDisconnected(info.ssid.c_str(), info.reason); } - #endif +#endif /* ================================================================================================ */ @@ -326,7 +326,7 @@ bool wifiShowAP() return true; } -bool wifiShowAP(char * ssid, char * pass) +bool wifiShowAP(char* ssid, char* pass) { if(strlen(wifiSsid) != 0) return false; @@ -334,9 +334,9 @@ bool wifiShowAP(char * ssid, char * pass) WiFi.macAddress(mac); sprintf_P(ssid, PSTR("HASP-%02x%02x%02x"), mac[3], mac[4], mac[5]); sprintf_P(pass, PSTR("haspadmin")); - #if defined(STM32F4xx) +#if defined(STM32F4xx) LOG_WARNING(TAG_WIFI, F("We should setup Temporary Access Point %s password: %s"), ssid, pass); - #else +#else WiFi.softAP(ssid, pass); /* Setup the DNS server redirecting all the domains to the apIP */ @@ -346,28 +346,32 @@ bool wifiShowAP(char * ssid, char * pass) LOG_WARNING(TAG_WIFI, F("Temporary Access Point %s password: %s"), ssid, pass); LOG_WARNING(TAG_WIFI, F("AP IP address : %s"), WiFi.softAPIP().toString().c_str()); networkStart(); - // httpReconnect();} - #endif +// httpReconnect();} +#endif return true; } static void wifiReconnect(void) { +#if defined(ARDUINO_ARCH_ESP8266) WiFi.disconnect(true); - #if defined(ARDUINO_ARCH_ESP8266) - WiFi.hostname(mqttGetNodename().c_str()); - #elif defined(ARDUINO_ARCH_ESP32) - WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); - WiFi.setHostname(mqttGetNodename().c_str()); - #endif WiFi.begin(wifiSsid, wifiPassword); + WiFi.hostname(haspDevice.get_hostname()); + +#elif defined(ARDUINO_ARCH_ESP32) + // https://github.com/espressif/arduino-esp32/issues/3438#issuecomment-721428310 + WiFi.disconnect(true); + WiFi.begin(wifiSsid, wifiPassword); + // WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); // causes 255.255.255.255 IP errors + WiFi.setHostname(haspDevice.get_hostname()); +#endif } /* ============ Setup, Loop, Start, Stop =================================================== */ void wifiSetup() { - #if defined(STM32F4xx) +#if defined(STM32F4xx) // Temp ESP reset function pinMode(ESPSPI_RST, OUTPUT); digitalWrite(ESPSPI_RST, 0); @@ -403,41 +407,41 @@ void wifiSetup() // status = WiFi.begin(wifiSsid, wifiPassword); WiFi.begin(wifiSsid, wifiPassword); } - // } + // } - #else +#else if(wifiShowAP()) { WiFi.mode(WIFI_AP_STA); } else { WiFi.mode(WIFI_STA); - #if defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) // wifiEventHandler[0] = WiFi.onStationModeConnected(wifiSTAConnected); gotIpEventHandler = WiFi.onStationModeGotIP(wifiSTAGotIP); // As soon WiFi is connected, start NTP Client disconnectedEventHandler = WiFi.onStationModeDisconnected(wifiSTADisconnected); WiFi.setSleepMode(WIFI_NONE_SLEEP); - #elif defined(ARDUINO_ARCH_ESP32) +#elif defined(ARDUINO_ARCH_ESP32) WiFi.onEvent(wifi_callback); WiFi.setSleep(false); - #endif +#endif wifiReconnect(); LOG_TRACE(TAG_WIFI, F("Connecting to : %s"), wifiSsid); } - #endif +#endif } bool wifiEvery5Seconds() { - #if defined(STM32F4xx) +#if defined(STM32F4xx) if(wifiShowAP()) { // no ssid is set yet wait for user on-screen input return false; } else if(WiFi.status() == WL_CONNECTED) { - #else +#else if(WiFi.getMode() != WIFI_STA) { return false; } else if(WiFi.status() == WL_CONNECTED) { - #endif +#endif return true; } else { wifiReconnectCounter++; @@ -453,32 +457,32 @@ bool wifiEvery5Seconds() } } -bool wifiValidateSsid(const char * ssid, const char * pass) +bool wifiValidateSsid(const char* ssid, const char* pass) { uint8_t attempt = 0; WiFi.begin(ssid, pass); - #if defined(STM32F4xx) +#if defined(STM32F4xx) IPAddress ip; ip = WiFi.localIP(); char espIp[16]; memset(espIp, 0, sizeof(espIp)); snprintf_P(espIp, sizeof(espIp), PSTR("%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); while(attempt < 15 && (WiFi.status() != WL_CONNECTED || String(espIp) == F("0.0.0.0"))) { - #else +#else while(attempt < 15 && (WiFi.status() != WL_CONNECTED || WiFi.localIP().toString() == F("0.0.0.0"))) { - #endif +#endif attempt++; LOG_INFO(TAG_WIFI, F("Trying to connect to %s... %u"), wifiSsid, attempt); delay(500); } - #if defined(STM32F4xx) +#if defined(STM32F4xx) LOG_INFO(TAG_WIFI, F(D_NETWORK_IP_ADDRESS_RECEIVED), espIp); if((WiFi.status() == WL_CONNECTED && String(espIp) != F("0.0.0.0"))) return true; - #else +#else LOG_INFO(TAG_WIFI, F(D_NETWORK_IP_ADDRESS_RECEIVED), WiFi.localIP().toString().c_str()); if((WiFi.status() == WL_CONNECTED && WiFi.localIP().toString() != F("0.0.0.0"))) return true; - #endif +#endif LOG_WARNING(TAG_WIFI, F(D_NETWORK_IP_ADDRESS_RECEIVED), WiFi.localIP().toString().c_str()); WiFi.disconnect(); @@ -489,30 +493,30 @@ void wifiStop() { wifiReconnectCounter = 0; // Prevent endless loop in wifiDisconnected WiFi.disconnect(); - #if !defined(STM32F4xx) +#if !defined(STM32F4xx) WiFi.mode(WIFI_OFF); - #endif +#endif LOG_WARNING(TAG_WIFI, F(D_SERVICE_STOPPED)); } -void wifi_get_statusupdate(char * buffer, size_t len) +void wifi_get_statusupdate(char* buffer, size_t len) { - #if defined(STM32F4xx) +#if defined(STM32F4xx) IPAddress ip; ip = WiFi.localIP(); char espIp[16]; memset(espIp, 0, sizeof(espIp)); snprintf_P(buffer, len, PSTR("\"ssid\":\"%s\",\"rssi\":%i,\"ip\":\"%d.%d.%d.%d\","), WiFi.SSID(), WiFi.RSSI(), ip[0], ip[1], ip[2], ip[3]); - #else +#else snprintf_P(buffer, len, PSTR("\"ssid\":\"%s\",\"rssi\":%i,\"ip\":\"%s\","), WiFi.SSID().c_str(), WiFi.RSSI(), WiFi.localIP().toString().c_str()); - #endif +#endif } - /* ============ Confiuration =============================================================== */ - #if HASP_USE_CONFIG > 0 -bool wifiGetConfig(const JsonObject & settings) +/* ============ Confiuration =============================================================== */ +#if HASP_USE_CONFIG > 0 +bool wifiGetConfig(const JsonObject& settings) { bool changed = false; @@ -534,7 +538,7 @@ bool wifiGetConfig(const JsonObject & settings) * * @param[in] settings JsonObject with the config settings. **/ -bool wifiSetConfig(const JsonObject & settings) +bool wifiSetConfig(const JsonObject& settings) { configOutput(settings, TAG_WIFI); bool changed = false; @@ -552,6 +556,6 @@ bool wifiSetConfig(const JsonObject & settings) return changed; } - #endif // HASP_USE_CONFIG +#endif // HASP_USE_CONFIG #endif diff --git a/src/sys/net/hasp_wifi.h b/src/sys/net/hasp_wifi.h new file mode 100644 index 00000000..9854d449 --- /dev/null +++ b/src/sys/net/hasp_wifi.h @@ -0,0 +1,23 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_WIFI_H +#define HASP_WIFI_H + +#include "ArduinoJson.h" + +void wifiSetup(); +bool wifiShowAP(); +bool wifiShowAP(char* ssid, char* pass); +bool wifiEvery5Seconds(void); +void wifiStop(void); + +bool wifiValidateSsid(const char* ssid, const char* pass); +void wifi_get_statusupdate(char* buffer, size_t len); + +#if HASP_USE_CONFIG > 0 +bool wifiGetConfig(const JsonObject& settings); +bool wifiSetConfig(const JsonObject& settings); +#endif + +#endif \ No newline at end of file diff --git a/src/svc/hasp_http.cpp b/src/sys/svc/hasp_http.cpp similarity index 86% rename from src/svc/hasp_http.cpp rename to src/sys/svc/hasp_http.cpp index 9b6e4006..8dd4ebcf 100644 --- a/src/svc/hasp_http.cpp +++ b/src/sys/svc/hasp_http.cpp @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ //#include "webServer.h" @@ -7,25 +7,28 @@ #include "lvgl.h" #if defined(ARDUINO_ARCH_ESP32) - #include "Update.h" +#include "Update.h" #endif #include "hasp_conf.h" +#include "dev/device.h" #include "hasp_gui.h" -#include "hasp_hal.h" +#include "hasp/hasp_dispatch.h" #include "hasp_debug.h" #include "hasp_config.h" +#include "hal/hasp_hal.h" #include "hasp/hasp_utilities.h" #include "hasp/hasp_dispatch.h" +#include "hasp/hasp_page.h" #include "hasp/hasp.h" #if HASP_USE_HTTP > 0 - #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) File fsUploadFile; - #endif +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// bool webServerStarted = false; @@ -36,33 +39,33 @@ bool webServerStarted = false; // char httpPassword[32] = ""; hasp_http_config_t http_config; - #define HTTP_PAGE_SIZE (6 * 256) +#define HTTP_PAGE_SIZE (6 * 256) - #if defined(STM32F4xx) && HASP_USE_ETHERNET > 0 - #include +#if defined(STM32F4xx) && HASP_USE_ETHERNET > 0 +#include EthernetWebServer webServer(80); - #endif +#endif - #if defined(STM32F4xx) && HASP_USE_WIFI > 0 - #include +#if defined(STM32F4xx) && HASP_USE_WIFI > 0 +#include // #include EthernetWebServer webServer(80); - #endif +#endif - #if defined(ARDUINO_ARCH_ESP8266) - #include "StringStream.h" - #include - #include +#if defined(ARDUINO_ARCH_ESP8266) +#include "StringStream.h" +#include +#include ESP8266WebServer webServer(80); - #endif +#endif - #if defined(ARDUINO_ARCH_ESP32) - #include - #include +#if defined(ARDUINO_ARCH_ESP32) +#include +#include WebServer webServer(80); - #endif // ESP32 +#endif // ESP32 -HTTPUpload * upload; +HTTPUpload* upload; static const char HTTP_MENU_BUTTON[] PROGMEM = "

"; @@ -71,9 +74,9 @@ const char MAIN_MENU_BUTTON[] PROGMEM = "

"; const char MIT_LICENSE[] PROGMEM = "
MIT License

"; -const char HTTP_DOCTYPE[] PROGMEM = - ""; +const char HTTP_DOCTYPE[] PROGMEM = ""; const char HTTP_META_GO_BACK[] PROGMEM = ""; const char HTTP_HEADER[] PROGMEM = "%s"; const char HTTP_STYLE[] PROGMEM = @@ -112,11 +115,11 @@ const char HTTP_FOOTER[] PROGMEM = " by Francis Van Roie"; // // Default link to compiled Nextion firmware images // String lcdFirmwareUrl = "http://haswitchplate.com/update/HASwitchPlate.tft"; - #if HASP_USE_MQTT > 0 -extern char mqttNodeName[16]; - #else -char mqttNodeName[3] = "na"; - #endif +// #if HASP_USE_MQTT > 0 +// extern char mqttNodeName[16]; +// #else +// char mqttNodeName[3] = "na"; +// #endif //////////////////////////////////////////////////////////////////////////////////////////////////// String getOption(int value, String label, bool selected) @@ -135,14 +138,14 @@ String getOption(String value, String label, bool selected) return buffer; } -static void add_gpio_select_option(String & str, uint8_t gpio, uint8_t bcklpin) +static void add_gpio_select_option(String& str, uint8_t gpio, uint8_t bcklpin) { char buffer[10]; snprintf_P(buffer, sizeof(buffer), PSTR("GPIO %d"), gpio); str += getOption(gpio, buffer, bcklpin == gpio); } -static void add_button(String & str, const __FlashStringHelper * label, const __FlashStringHelper * extra) +static void add_button(String& str, const __FlashStringHelper* label, const __FlashStringHelper* extra) { str += F("

"); - #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 if(HASP_FS.exists(F("/edit.htm.gz"))) { httpMessage += F("

"); } - #endif +#endif httpMessage += F("

"); - webSendPage(httpGetNodename(), httpMessage.length(), false); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), false); webServer.sendContent(httpMessage); } // httpMessage.clear(); @@ -349,14 +352,14 @@ void httpHandleReboot() if(!httpIsAuthenticated(F("reboot"))) return; { - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); httpMessage = F(D_DISPATCH_REBOOT); - webSendPage(httpGetNodename(), httpMessage.length(), true); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), true); webServer.sendContent(httpMessage); } // httpMessage.clear(); @@ -373,14 +376,16 @@ void webHandleScreenshot() if(webServer.hasArg(F("a"))) { if(webServer.arg(F("a")) == F("next")) { - dispatch_page_next(); + dispatch_page_next(LV_SCR_LOAD_ANIM_NONE); } else if(webServer.arg(F("a")) == F("prev")) { - dispatch_page_prev(); + dispatch_page_prev(LV_SCR_LOAD_ANIM_NONE); + } else if(webServer.arg(F("a")) == F("back")) { + dispatch_page_back(LV_SCR_LOAD_ANIM_NONE); } } if(webServer.hasArg(F("q"))) { - lv_disp_t * disp = lv_disp_get_default(); + lv_disp_t* disp = lv_disp_get_default(); webServer.setContentLength(122 + disp->driver.hor_res * disp->driver.ver_res * sizeof(lv_color_t)); webServer.send_P(200, PSTR("image/bmp"), ""); guiTakeScreenshot(); @@ -388,10 +393,10 @@ void webHandleScreenshot() } else { { - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); httpMessage += @@ -412,7 +417,7 @@ void webHandleScreenshot() "

"); httpMessage += FPSTR(MAIN_MENU_BUTTON); - webSendPage(httpGetNodename(), httpMessage.length(), false); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), false); webServer.sendContent(httpMessage); } // httpMessage.clear(); @@ -427,7 +432,7 @@ void webHandleAbout() if(!httpIsAuthenticated(F("about"))) return; { - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

HASP OpenHardware edition

Copyright© 2020 Francis Van Roie "); @@ -454,21 +459,21 @@ void webHandleAbout() F("

ArduinoLog

Copyright© 2017,2018 Thijs Elenbaas, MrRobot62, rahuldeo2047, NOX73, " "dhylands, Josha blemasle, mfalkvidd"); httpMessage += FPSTR(MIT_LICENSE); - #if HASP_USE_SYSLOG > 0 - // Replaced with WiFiUDP client - // httpMessage += F("

Syslog

Copyright© 2016 Martin Sloup"); - // httpMessage += FPSTR(MIT_LICENSE); - #endif - #if HASP_USE_QRCODE > 0 +#if HASP_USE_SYSLOG > 0 + // Replaced with WiFiUDP client + // httpMessage += F("

Syslog

Copyright© 2016 Martin Sloup"); + // httpMessage += FPSTR(MIT_LICENSE); +#endif +#if HASP_USE_QRCODE > 0 httpMessage += F("

QR Code generator

Copyright© Project Nayuki"); httpMessage += FPSTR(MIT_LICENSE); - #endif +#endif httpMessage += F("

AceButton

Copyright© 2018 Brian T. Park"); httpMessage += FPSTR(MIT_LICENSE); httpMessage += FPSTR(MAIN_MENU_BUTTON); - webSendPage(httpGetNodename(), httpMessage.length(), false); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), false); webServer.sendContent(httpMessage); } // httpMessage.clear(); @@ -482,10 +487,10 @@ void webHandleInfo() { char size_buf[32]; - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); /* HASP Stats */ @@ -526,30 +531,30 @@ void webHandleInfo() httpMessage += F("s"); httpMessage += F("
Free Memory: "); - hasp_util_format_bytes(halGetFreeHeap(), size_buf, sizeof(size_buf)); + Utilities::format_bytes(haspDevice.get_free_heap(), size_buf, sizeof(size_buf)); httpMessage += size_buf; httpMessage += F("
Memory Fragmentation: "); - httpMessage += String(halGetHeapFragmentation()); + httpMessage += String(haspDevice.get_heap_fragmentation()); - #if ARDUINO_ARCH_ESP32 +#if ARDUINO_ARCH_ESP32 if(psramFound()) { httpMessage += F("
Free PSRam: "); - hasp_util_format_bytes(ESP.getFreePsram(), size_buf, sizeof(size_buf)); + Utilities::format_bytes(ESP.getFreePsram(), size_buf, sizeof(size_buf)); httpMessage += size_buf; httpMessage += F("
PSRam Size: "); - hasp_util_format_bytes(ESP.getPsramSize(), size_buf, sizeof(size_buf)); + Utilities::format_bytes(ESP.getPsramSize(), size_buf, sizeof(size_buf)); httpMessage += size_buf; } - #endif +#endif /* LVGL Stats */ lv_mem_monitor_t mem_mon; lv_mem_monitor(&mem_mon); httpMessage += F("

LVGL Memory: "); - hasp_util_format_bytes(mem_mon.total_size, size_buf, sizeof(size_buf)); + Utilities::format_bytes(mem_mon.total_size, size_buf, sizeof(size_buf)); httpMessage += size_buf; httpMessage += F("
LVGL Free: "); - hasp_util_format_bytes(mem_mon.free_size, size_buf, sizeof(size_buf)); + Utilities::format_bytes(mem_mon.free_size, size_buf, sizeof(size_buf)); httpMessage += size_buf; httpMessage += F("
LVGL Fragmentation: "); httpMessage += mem_mon.frag_pct; @@ -558,10 +563,10 @@ void webHandleInfo() // String(LV_HASP_VER_RES_MAX); httpMessage += F("
LCD Version: ")) + // String(lcdVersion); httpMessage += F("

LCD Active Page: "); - httpMessage += String(haspGetPage()); + httpMessage += String(haspPages.get()); /* Wifi Stats */ - #if HASP_USE_WIFI > 0 +#if HASP_USE_WIFI > 0 httpMessage += F("

SSID: "); httpMessage += String(WiFi.SSID()); httpMessage += F("
Signal Strength: "); @@ -581,7 +586,7 @@ void webHandleInfo() } else { httpMessage += F("Very Bad)"); } - #if defined(STM32F4xx) +#if defined(STM32F4xx) byte mac[6]; WiFi.macAddress(mac); char macAddress[16]; @@ -593,7 +598,7 @@ void webHandleInfo() httpMessage += String(WiFi.gatewayIP()); httpMessage += F("
MAC Address: "); httpMessage += String(macAddress); - #else +#else httpMessage += F("
IP Address: "); httpMessage += String(WiFi.localIP().toString()); httpMessage += F("
Gateway: "); @@ -602,10 +607,10 @@ void webHandleInfo() httpMessage += String(WiFi.dnsIP().toString()); httpMessage += F("
MAC Address: "); httpMessage += String(WiFi.macAddress()); - #endif - #endif - #if HASP_USE_ETHERNET > 0 - #if defined(ARDUINO_ARCH_ESP32) +#endif +#endif +#if HASP_USE_ETHERNET > 0 +#if defined(ARDUINO_ARCH_ESP32) httpMessage += F("

Ethernet: "); httpMessage += String(ETH.linkSpeed()); httpMessage += F(" Mbps"); @@ -620,10 +625,10 @@ void webHandleInfo() httpMessage += String(ETH.dnsIP().toString()); httpMessage += F("
MAC Address: "); httpMessage += String(ETH.macAddress()); - #endif - #endif - /* Mqtt Stats */ - #if HASP_USE_MQTT > 0 +#endif +#endif +/* Mqtt Stats */ +#if HASP_USE_MQTT > 0 httpMessage += F("

MQTT Status: "); if(mqttIsConnected()) { // Check MQTT connection httpMessage += F("Connected"); @@ -637,46 +642,46 @@ void webHandleInfo() char mqttClientId[64]; String mac = halGetMacAddress(3, ""); mac.toLowerCase(); - snprintf_P(mqttClientId, sizeof(mqttClientId), PSTR("%s-%s"), mqttNodeName, mac.c_str()); + snprintf_P(mqttClientId, sizeof(mqttClientId), PSTR("%s-%s"), haspDevice.get_hostname(), mac.c_str()); httpMessage += mqttClientId; } - #endif // MQTT +#endif // MQTT /* ESP Stats */ httpMessage += F("

MCU Model: "); - httpMessage += halGetChipModel(); + httpMessage += haspDevice.get_chip_model(); httpMessage += F("
CPU Frequency: "); - httpMessage += String(halGetCpuFreqMHz()); + httpMessage += String(haspDevice.get_cpu_frequency()); httpMessage += F("MHz"); - #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) httpMessage += F("
Flash Chip Size: "); - hasp_util_format_bytes(ESP.getFlashChipSize(), size_buf, sizeof(size_buf)); + Utilities::format_bytes(ESP.getFlashChipSize(), size_buf, sizeof(size_buf)); httpMessage += size_buf; httpMessage += F("
Program Size: "); - hasp_util_format_bytes(ESP.getSketchSize(), size_buf, sizeof(size_buf)); + Utilities::format_bytes(ESP.getSketchSize(), size_buf, sizeof(size_buf)); httpMessage += size_buf; httpMessage += F("
Free Program Space: "); - hasp_util_format_bytes(ESP.getFreeSketchSpace(), size_buf, sizeof(size_buf)); + Utilities::format_bytes(ESP.getFreeSketchSpace(), size_buf, sizeof(size_buf)); httpMessage += size_buf; - #endif +#endif //#if defined(ARDUINO_ARCH_ESP32) // httpMessage += F("
ESP SDK version: "); // httpMessage += String(ESP.getSdkVersion()); //#else httpMessage += F("
Core version: "); - httpMessage += String(halGetCoreVersion()); + httpMessage += haspDevice.get_core_version(); //#endif httpMessage += F("
Last Reset: "); httpMessage += halGetResetInfo(); httpMessage += FPSTR(MAIN_MENU_BUTTON); - webSendPage(httpGetNodename(), httpMessage.length(), false); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), false); webServer.sendContent(httpMessage); } // httpMessage.clear(); @@ -713,7 +718,7 @@ void webHandleInfo() // return F("text/plain"); // } -static String getContentType(const String & path) +static String getContentType(const String& path) { char buff[sizeof(mime::mimeTable[0].mimeType)]; // Check all entries but last one for match, return if found @@ -767,20 +772,20 @@ void webUploadProgress() haspProgressVal(t); } - #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) static inline void webUpdatePrintError() { - #if defined(ARDUINO_ARCH_ESP8266) - String output((char *)0); +#if defined(ARDUINO_ARCH_ESP8266) + String output((char*)0); output.reserve(128); - StringStream stream((String &)output); + StringStream stream((String&)output); Update.printError(stream); // ESP8266 only has printError() LOG_ERROR(TAG_HTTP, output.c_str()); haspProgressMsg(output.c_str()); - #elif defined(ARDUINO_ARCH_ESP32) +#elif defined(ARDUINO_ARCH_ESP32) LOG_ERROR(TAG_HTTP, Update.errorString()); // ESP32 has errorString() haspProgressMsg(Update.errorString()); - #endif +#endif } void webUpdateReboot() @@ -788,14 +793,14 @@ void webUpdateReboot() LOG_INFO(TAG_HTTP, F("Update Success: %u bytes received. Rebooting..."), upload->totalSize); { - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); httpMessage += F("Upload complete. Rebooting device, please wait..."); - webSendPage(httpGetNodename(), httpMessage.length(), true); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), true); webServer.sendContent(httpMessage); } // httpMessage.clear(); @@ -838,9 +843,9 @@ void webHandleFirmwareUpload() } } } - #endif +#endif - #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 bool handleFileRead(String path) { if(!httpIsAuthenticated(F("fileread"))) return false; @@ -874,7 +879,7 @@ void handleFileUpload() if(upload->status == UPLOAD_FILE_START) { if(!httpIsAuthenticated(F("fileupload"))) return; LOG_INFO(TAG_HTTP, F("Total size: %s"), webServer.headerName(0).c_str()); - String filename((char *)0); + String filename((char*)0); filename.reserve(128); filename = upload->filename; if(!filename.startsWith("/")) { @@ -972,7 +977,7 @@ void handleFileList() LOG_TRACE(TAG_HTTP, F("handleFileList: %s"), path.c_str()); path.clear(); - #if defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP32) File root = HASP_FS.open("/", FILE_READ); File file = root.openNextFile(); String output = "["; @@ -997,7 +1002,7 @@ void handleFileList() } output += "]"; webServer.send(200, PSTR("text/json"), output); - #elif defined(ARDUINO_ARCH_ESP8266) +#elif defined(ARDUINO_ARCH_ESP8266) Dir dir = HASP_FS.openDir(path); String output = "["; while(dir.next()) { @@ -1019,41 +1024,41 @@ void handleFileList() } output += "]"; webServer.send(200, PSTR("text/json"), output); - #endif +#endif } - #endif +#endif - //////////////////////////////////////////////////////////////////////////////////////////////////// - #if HASP_USE_CONFIG > 0 +//////////////////////////////////////////////////////////////////////////////////////////////////// +#if HASP_USE_CONFIG > 0 void webHandleConfig() { // http://plate01/config if(!httpIsAuthenticated(F("config"))) return; saveConfig(); - // Reboot after saving wifi config in AP mode - #if HASP_USE_WIFI > 0 && !defined(STM32F4xx) +// Reboot after saving wifi config in AP mode +#if HASP_USE_WIFI > 0 && !defined(STM32F4xx) if(WiFi.getMode() != WIFI_STA) { httpHandleReboot(); } - #endif +#endif { - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); - #if HASP_USE_WIFI > 0 +#if HASP_USE_WIFI > 0 httpMessage += F("

"); - #endif +#endif - #if HASP_USE_MQTT > 0 +#if HASP_USE_MQTT > 0 httpMessage += F("

"); - #endif +#endif httpMessage += F("

"); @@ -1061,14 +1066,14 @@ void webHandleConfig() httpMessage += F("

"); - // httpMessage += - // F("

"); + // httpMessage += + // F("

"); - #if HASP_USE_GPIO > 0 +#if HASP_USE_GPIO > 0 httpMessage += F("

"); - #endif +#endif httpMessage += F("

"); @@ -1079,15 +1084,15 @@ void webHandleConfig() httpMessage += FPSTR(MAIN_MENU_BUTTON); - webSendPage(httpGetNodename(), httpMessage.length(), false); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), false); webServer.sendContent(httpMessage); } // httpMessage.clear(); webSendFooter(); } - //////////////////////////////////////////////////////////////////////////////////////////////////// - #if HASP_USE_MQTT > 0 +//////////////////////////////////////////////////////////////////////////////////////////////////// +#if HASP_USE_MQTT > 0 void webHandleMqttConfig() { // http://plate01/config/mqtt if(!httpIsAuthenticated(F("config/mqtt"))) return; @@ -1097,10 +1102,10 @@ void webHandleMqttConfig() { // char buffer[128]; - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); httpMessage += F("
"); @@ -1132,13 +1137,13 @@ void webHandleMqttConfig() // D_HTTP_CONFIGURATION // "

"); - webSendPage(httpGetNodename(), httpMessage.length(), false); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), false); webServer.sendContent(httpMessage); } // httpMessage.clear(); webSendFooter(); } - #endif +#endif //////////////////////////////////////////////////////////////////////////////////////////////////// void webHandleGuiConfig() @@ -1149,10 +1154,10 @@ void webHandleGuiConfig() StaticJsonDocument<256> settings; guiGetConfig(settings.to()); - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); httpMessage += F("
"); @@ -1190,7 +1195,7 @@ void webHandleGuiConfig() int8_t bcklpin = settings[FPSTR(FP_GUI_BACKLIGHTPIN)].as(); httpMessage += F("

Backlight Control

"); add_button(httpMessage, F(D_HTTP_SAVE_SETTINGS), F("name='save' value='gui'")); close_form(httpMessage); - // httpMessage += - // F("

"); + // httpMessage += + // F("

"); - #if TOUCH_DRIVER == 2046 && defined(TOUCH_CS) +#if TOUCH_DRIVER == 2046 && defined(TOUCH_CS) add_form_button(httpMessage, F(D_HTTP_CALIBRATE), F("/config/gui"), F("name='action' value='calibrate'")); - // httpMessage += PSTR("

"); - #endif +// httpMessage += PSTR("

"); +#endif add_form_button(httpMessage, F("↩ " D_HTTP_CONFIGURATION), F("/config"), F("")); @@ -1227,7 +1232,7 @@ void webHandleGuiConfig() // D_HTTP_CONFIGURATION // "

"); - webSendPage(httpGetNodename(), httpMessage.length(), false); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), false); webServer.sendContent(httpMessage); } webSendFooter(); @@ -1235,8 +1240,8 @@ void webHandleGuiConfig() if(webServer.hasArg(F("action"))) dispatch_text_line(webServer.arg(F("action")).c_str()); } - //////////////////////////////////////////////////////////////////////////////////////////////////// - #if HASP_USE_WIFI > 0 +//////////////////////////////////////////////////////////////////////////////////////////////////// +#if HASP_USE_WIFI > 0 void webHandleWifiConfig() { // http://plate01/config/wifi if(!httpIsAuthenticated(F("config/wifi"))) return; @@ -1244,10 +1249,10 @@ void webHandleWifiConfig() StaticJsonDocument<256> settings; wifiGetConfig(settings.to()); - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); httpMessage += F("
"); @@ -1262,28 +1267,28 @@ void webHandleWifiConfig() httpMessage += F("'>

"); - #if HASP_USE_WIFI > 0 && !defined(STM32F4xx) +#if HASP_USE_WIFI > 0 && !defined(STM32F4xx) if(WiFi.getMode() == WIFI_STA) { add_form_button(httpMessage, F("↩ " D_HTTP_CONFIGURATION), F("/config"), F("")); // httpMessage += PSTR("

"); } - #endif +#endif - webSendPage(httpGetNodename(), httpMessage.length(), false); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), false); webServer.sendContent(httpMessage); - #if defined(STM32F4xx) +#if defined(STM32F4xx) httpMessage = ""; - #else +#else httpMessage.clear(); - #endif +#endif webSendFooter(); } - #endif +#endif - //////////////////////////////////////////////////////////////////////////////////////////////////// - #if HASP_USE_HTTP > 0 +//////////////////////////////////////////////////////////////////////////////////////////////////// +#if HASP_USE_HTTP > 0 void webHandleHttpConfig() { // http://plate01/config/http if(!httpIsAuthenticated(F("config/http"))) return; @@ -1295,7 +1300,7 @@ void webHandleHttpConfig() // String httpMessage((char *)0); // httpMessage.reserve(HTTP_PAGE_SIZE); // httpMessage += F("

"); - // httpMessage += httpGetNodename(); + // httpMessage += haspDevice.get_hostname(); // httpMessage += F("


"); // httpMessage += F("
"); @@ -1327,23 +1332,23 @@ void webHandleHttpConfig() "

" "

"), - httpGetNodename(), settings[FPSTR(FP_CONFIG_USER)].as().c_str(), + haspDevice.get_hostname(), settings[FPSTR(FP_CONFIG_USER)].as().c_str(), settings[FPSTR(FP_CONFIG_PASS)].as().c_str()); // if(settings[FPSTR(FP_CONFIG_PASS)].as() != "") { // httpMessage += F(D_PASSWORD_MASK); // } - webSendPage(httpGetNodename(), len, false); + webSendPage(haspDevice.get_hostname(), len, false); webServer.sendContent(httpMessage); } // httpMessage.clear(); webSendFooter(); } - #endif +#endif - //////////////////////////////////////////////////////////////////////////////////////////////////// - #if defined(HASP_USE_GPIO) && (HASP_USE_GPIO > 0) +//////////////////////////////////////////////////////////////////////////////////////////////////// +#if HASP_USE_GPIO > 0 void webHandleGpioConfig() { // http://plate01/config/gpio if(!httpIsAuthenticated(F("config/gpio"))) return; @@ -1367,10 +1372,10 @@ void webHandleGpioConfig() } { - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); httpMessage += F("
"); @@ -1465,7 +1470,7 @@ void webHandleGpioConfig() // D_HTTP_CONFIGURATION // "

"); - webSendPage(httpGetNodename(), httpMessage.length(), false); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), false); webServer.sendContent(httpMessage); } // httpMessage.clear(); @@ -1483,10 +1488,10 @@ void webHandleGpioOptions() uint8_t config_id = webServer.arg(F("id")).toInt(); - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); httpMessage += F("
"); @@ -1541,7 +1546,7 @@ void webHandleGpioOptions() httpMessage += F("

Group

Telemetry Period (Seconds, 0=disable) " - "

"); - #if HASP_USE_SYSLOG > 0 +#if HASP_USE_SYSLOG > 0 httpMessage += F("Syslog Hostame (optional)() == 1) httpMessage += F(" checked"); httpMessage += F(">BSD (RFC 3164)"); - #endif +#endif httpMessage += F("

"); @@ -1633,7 +1638,7 @@ void webHandleDebugConfig() // D_HTTP_CONFIGURATION // "

"); - webSendPage(httpGetNodename(), httpMessage.length(), false); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), false); webServer.sendContent(httpMessage); } // httpMessage.clear(); @@ -1649,10 +1654,10 @@ void webHandleHaspConfig() haspGetConfig(settings.to()); { - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); httpMessage += F("

UI Theme (required)
"); httpMessage += F("Hue

"); httpMessage += F("

Default Font

"); httpMessage += F("

Startup Layout (optional)"D_HTTP_CONFIGURATION"

"); httpMessage += FPSTR(MAIN_MENU_BUTTON); - webSendPage(httpGetNodename(), httpMessage.length(), false); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), false); webServer.sendContent(httpMessage); } // httpMessage.clear(); webSendFooter(); } - #endif // HASP_USE_CONFIG +#endif // HASP_USE_CONFIG //////////////////////////////////////////////////////////////////////////////////////////////////// void httpHandleNotFound() { // webServer 404 - #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 if(handleFileRead(webServer.uri())) return; - #endif +#endif - #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) LOG_TRACE(TAG_HTTP, F("Sending 404 to client connected from: %s"), webServer.client().remoteIP().toString().c_str()); - #else +#else // LOG_TRACE(TAG_HTTP,F("Sending 404 to client connected from: %s"), String(webServer.client().remoteIP()).c_str()); - #endif +#endif - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("File Not Found\n\nURI: "); @@ -1780,10 +1785,10 @@ void webHandleFirmware() if(!httpIsAuthenticated(F("firmware"))) return; { - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); httpMessage += F("

"); // httpMessage += F("

"); + httpMessage += F("
"); + httpMessage += F("
Update ESP from URL"); + httpMessage += F("


"); + httpMessage += FPSTR(MAIN_MENU_BUTTON); - webSendPage(httpGetNodename(), httpMessage.length(), false); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), false); webServer.sendContent(httpMessage); } // httpMessage.clear(); @@ -1806,35 +1817,38 @@ void webHandleFirmware() //////////////////////////////////////////////////////////////////////////////////////////////////// void httpHandleEspFirmware() { // http://plate01/espfirmware + char url[4]; + memcpy_P(url, PSTR("url"), 4); + if(!httpIsAuthenticated(F("espfirmware"))) return; { - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); httpMessage += F("

ESP update

Updating ESP firmware from: "); - httpMessage += webServer.arg("espFirmware"); + httpMessage += webServer.arg(url); - webSendPage(httpGetNodename(), httpMessage.length(), true); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), true); webServer.sendContent(httpMessage); // httpMessage.clear(); } webSendFooter(); - LOG_TRACE(TAG_HTTP, F("Attempting ESP firmware update from: %s"), webServer.arg("espFirmware").c_str()); - // espStartOta(webServer.arg("espFirmware")); + LOG_TRACE(TAG_HTTP, F("Attempting ESP firmware update from: %s"), webServer.arg(url).c_str()); + dispatch_web_update(NULL, webServer.arg(url).c_str()); } - //////////////////////////////////////////////////////////////////////////////////////////////////// - #if HASP_USE_CONFIG > 0 +//////////////////////////////////////////////////////////////////////////////////////////////////// +#if HASP_USE_CONFIG > 0 void webHandleSaveConfig() { if(!httpIsAuthenticated(F("saveConfig"))) return; - configWriteConfig(); + configWrite(); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1845,10 +1859,10 @@ void httpHandleResetConfig() bool resetConfirmed = webServer.arg(F("confirm")) == F("yes"); { - String httpMessage((char *)0); + String httpMessage((char*)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); - httpMessage += httpGetNodename(); + httpMessage += haspDevice.get_hostname(); httpMessage += F("


"); if(resetConfirmed) { // User has confirmed, so reset everything @@ -1876,7 +1890,7 @@ void httpHandleResetConfig() // "

"); } - webSendPage(httpGetNodename(), httpMessage.length(), resetConfirmed); + webSendPage(haspDevice.get_hostname(), httpMessage.length(), resetConfirmed); webServer.sendContent(httpMessage); } // httpMessage.clear(); @@ -1888,30 +1902,30 @@ void httpHandleResetConfig() dispatch_reboot(false); // Do not save the current config } } - #endif // HASP_USE_CONFIG +#endif // HASP_USE_CONFIG void httpStart() { webServer.begin(); webServerStarted = true; - #if HASP_USE_WIFI > 0 - #if defined(STM32F4xx) +#if HASP_USE_WIFI > 0 +#if defined(STM32F4xx) IPAddress ip; ip = WiFi.localIP(); LOG_INFO(TAG_HTTP, F(D_SERVICE_STARTED " @ http://%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); - #else +#else LOG_INFO(TAG_HTTP, F(D_SERVICE_STARTED " @ http://%s"), (WiFi.getMode() != WIFI_STA ? WiFi.softAPIP().toString().c_str() : WiFi.localIP().toString().c_str())); - #endif - #else +#endif +#else IPAddress ip; - #if defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP32) ip = ETH.localIP(); - #else +#else ip = Ethernet.localIP(); - #endif +#endif LOG_INFO(TAG_HTTP, F(D_SERVICE_STARTED " @ http://%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); - #endif +#endif } void httpStop() @@ -1927,36 +1941,40 @@ void httpSetup() // httpSetConfig(settings); // ask server to track these headers - const char * headerkeys[] = {"Content-Length"}; // "Authentication" - size_t headerkeyssize = sizeof(headerkeys) / sizeof(char *); + const char* headerkeys[] = {"Content-Length"}; // "Authentication" + size_t headerkeyssize = sizeof(headerkeys) / sizeof(char*); webServer.collectHeaders(headerkeys, headerkeyssize); // Shared pages webServer.on(F("/about"), webHandleAbout); webServer.onNotFound(httpHandleNotFound); - #if HASP_USE_WIFI > 0 - #if !defined(STM32F4xx) +#if HASP_USE_WIFI > 0 - #if HASP_USE_CONFIG > 0 + // These two endpoints are needed in STA and AP mode + webServer.on(F("/config"), webHandleConfig); + +#if !defined(STM32F4xx) + +#if HASP_USE_CONFIG > 0 if(WiFi.getMode() != WIFI_STA) { - LOG_TRACE(TAG_HTTP, F("Wifi access point")); webServer.on(F("/"), webHandleWifiConfig); - webServer.on(F("/config"), webHandleConfig); + LOG_TRACE(TAG_HTTP, F("Wifi access point")); return; } - #endif - #endif - #endif +#endif // HASP_USE_CONFIG +#endif // !STM32F4xx +#endif // HASP_USE_WIFI + // The following endpoints are only needed in STA mode webServer.on(F("/page/"), []() { String pageid = webServer.arg(F("page")); webServer.send(200, PSTR("text/plain"), "Page: '" + pageid + "'"); - haspSetPage(pageid.toInt()); + dispatch_set_page(pageid.toInt(), LV_SCR_LOAD_ANIM_NONE); }); - #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 webServer.on(F("/list"), HTTP_GET, handleFileList); // load editor webServer.on(F("/edit"), HTTP_GET, []() { @@ -1977,7 +1995,7 @@ void httpSetup() LOG_VERBOSE(TAG_HTTP, F("Headers: %d"), webServer.headers()); }, handleFileUpload); - #endif +#endif webServer.on(F("/"), webHandleRoot); webServer.on(F("/info"), webHandleInfo); @@ -1985,27 +2003,26 @@ void httpSetup() webServer.on(F("/firmware"), webHandleFirmware); webServer.on(F("/reboot"), httpHandleReboot); - #if HASP_USE_CONFIG > 0 +#if HASP_USE_CONFIG > 0 webServer.on(F("/config/hasp"), webHandleHaspConfig); webServer.on(F("/config/http"), webHandleHttpConfig); webServer.on(F("/config/gui"), webHandleGuiConfig); webServer.on(F("/config/debug"), webHandleDebugConfig); - #if HASP_USE_MQTT > 0 +#if HASP_USE_MQTT > 0 webServer.on(F("/config/mqtt"), webHandleMqttConfig); - #endif - #if HASP_USE_WIFI > 0 +#endif +#if HASP_USE_WIFI > 0 webServer.on(F("/config/wifi"), webHandleWifiConfig); - #endif - #if HASP_USE_GPIO > 0 +#endif +#if HASP_USE_GPIO > 0 webServer.on(F("/config/gpio"), webHandleGpioConfig); webServer.on(F("/config/gpio/options"), webHandleGpioOptions); - #endif +#endif webServer.on(F("/saveConfig"), webHandleSaveConfig); webServer.on(F("/resetConfig"), httpHandleResetConfig); - webServer.on(F("/config"), webHandleConfig); - #endif // HASP_USE_CONFIG +#endif // HASP_USE_CONFIG - #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) webServer.on( F("/update"), HTTP_POST, []() { @@ -2014,7 +2031,7 @@ void httpSetup() }, webHandleFirmwareUpload); webServer.on(F("/espfirmware"), httpHandleEspFirmware); - #endif +#endif LOG_INFO(TAG_HTTP, F(D_SERVICE_STARTED)); // webStart(); Wait for network connection @@ -2028,9 +2045,9 @@ void httpReconnect() if(webServerStarted) { httpStop(); } else - #if HASP_USE_WIFI > 0 && !defined(STM32F4xx) +#if HASP_USE_WIFI > 0 && !defined(STM32F4xx) if(WiFi.status() == WL_CONNECTED || WiFi.getMode() != WIFI_STA) - #endif +#endif { httpStart(); } @@ -2049,8 +2066,8 @@ void httpEvery5Seconds() } //////////////////////////////////////////////////////////////////////////////////////////////////// - #if HASP_USE_CONFIG > 0 -bool httpGetConfig(const JsonObject & settings) +#if HASP_USE_CONFIG > 0 +bool httpGetConfig(const JsonObject& settings) { bool changed = false; @@ -2077,7 +2094,7 @@ bool httpGetConfig(const JsonObject & settings) * * @param[in] settings JsonObject with the config settings. **/ -bool httpSetConfig(const JsonObject & settings) +bool httpSetConfig(const JsonObject& settings) { configOutput(settings, TAG_HTTP); bool changed = false; @@ -2096,9 +2113,9 @@ bool httpSetConfig(const JsonObject & settings) return changed; } - #endif // HASP_USE_CONFIG +#endif // HASP_USE_CONFIG -size_t httpClientWrite(const uint8_t * buf, size_t size) +size_t httpClientWrite(const uint8_t* buf, size_t size) { /***** Sending 16Kb at once freezes on STM32 EthernetClient *****/ size_t bytes_sent = 0; diff --git a/src/svc/hasp_http.h b/src/sys/svc/hasp_http.h similarity index 67% rename from src/svc/hasp_http.h rename to src/sys/svc/hasp_http.h index 34e2bd1d..51313c6d 100644 --- a/src/svc/hasp_http.h +++ b/src/sys/svc/hasp_http.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_HTTP_H @@ -22,11 +22,11 @@ void httpEvery5Seconds(void); void httpStart(void); void httpStop(void); -size_t httpClientWrite(const uint8_t * buf, size_t size); // Screenshot Write Data +size_t httpClientWrite(const uint8_t* buf, size_t size); // Screenshot Write Data #if HASP_USE_CONFIG > 0 -bool httpGetConfig(const JsonObject & settings); -bool httpSetConfig(const JsonObject & settings); +bool httpGetConfig(const JsonObject& settings); +bool httpSetConfig(const JsonObject& settings); #endif // HASP_USE_CONFIG #endif \ No newline at end of file diff --git a/src/svc/hasp_mdns.cpp b/src/sys/svc/hasp_mdns.cpp similarity index 77% rename from src/svc/hasp_mdns.cpp rename to src/sys/svc/hasp_mdns.cpp index 8f06c2f4..822c7970 100644 --- a/src/svc/hasp_mdns.cpp +++ b/src/sys/svc/hasp_mdns.cpp @@ -1,19 +1,19 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #include "hasp_conf.h" #if HASP_USE_MDNS > 0 - #if defined(ARDUINO_ARCH_ESP32) - #include - #elif defined(ARDUINO_ARCH_ESP8266) - #include - // MDNSResponder::hMDNSService hMDNSService; - #endif +#if defined(ARDUINO_ARCH_ESP32) +#include +#elif defined(ARDUINO_ARCH_ESP8266) +#include +// MDNSResponder::hMDNSService hMDNSService; +#endif - #include "hasp/hasp.h" - #include "hasp_config.h" - #include "hasp_debug.h" +#include "hasp/hasp.h" +#include "hasp_config.h" +#include "hasp_debug.h" // uint8_t mdnsEnabled = true; hasp_mdns_config_t mdns_config; @@ -33,12 +33,6 @@ void mdnsStart() LOG_TRACE(TAG_MDNS, F(D_SERVICE_STARTING)); - #if HASP_USE_MQTT > 0 - String hasp2Node = mqttGetNodename(); - #else - String hasp2Node = "unknown"; - #endif - // Setup mDNS service discovery if enabled /* uint8_t attempt = 0; @@ -55,7 +49,7 @@ void mdnsStart() LOG_VERBOSE(TAG_MDNS, F("Trying hostname %s"), hasp2Node.c_str()); };*/ - if(MDNS.begin(hasp2Node.c_str())) { + if(MDNS.begin(haspDevice.get_hostname())) { char value[32]; char service[12]; char key[12]; @@ -86,23 +80,23 @@ void mdnsStart() void mdnsLoop(void) { - #if defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) if(mdns_config.enable) { MDNS.update(); } - #endif +#endif } void mdnsStop() { return; - #if HASP_USE_MDNS > 0 +#if HASP_USE_MDNS > 0 MDNS.end(); - #endif +#endif } - #if HASP_USE_CONFIG > 0 -bool mdnsGetConfig(const JsonObject & settings) +#if HASP_USE_CONFIG > 0 +bool mdnsGetConfig(const JsonObject& settings) { bool changed = false; @@ -118,7 +112,7 @@ bool mdnsGetConfig(const JsonObject & settings) * @note: data pixel should be formated to uint32_t RGBA. Imagemagick requirements. * @param[in] settings JsonObject with the config settings. **/ -bool mdnsSetConfig(const JsonObject & settings) +bool mdnsSetConfig(const JsonObject& settings) { configOutput(settings, TAG_MDNS); bool changed = false; @@ -127,6 +121,6 @@ bool mdnsSetConfig(const JsonObject & settings) return changed; } - #endif // HASP_USE_CONFIG +#endif // HASP_USE_CONFIG #endif // HASP_USE_MDNS diff --git a/src/svc/hasp_mdns.h b/src/sys/svc/hasp_mdns.h similarity index 68% rename from src/svc/hasp_mdns.h rename to src/sys/svc/hasp_mdns.h index 9886b823..2700595b 100644 --- a/src/svc/hasp_mdns.h +++ b/src/sys/svc/hasp_mdns.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_MDNS_H @@ -8,7 +8,7 @@ struct hasp_mdns_config_t { - uint8_t enable = true; + uint8_t enable = true; }; /* ===== Default Event Processors ===== */ @@ -19,8 +19,8 @@ void mdnsStop(void); /* ===== Read/Write Configuration ===== */ #if HASP_USE_CONFIG > 0 -bool mdnsGetConfig(const JsonObject & settings); -bool mdnsSetConfig(const JsonObject & settings); +bool mdnsGetConfig(const JsonObject& settings); +bool mdnsSetConfig(const JsonObject& settings); #endif #endif \ No newline at end of file diff --git a/src/svc/hasp_ota.cpp b/src/sys/svc/hasp_ota.cpp similarity index 60% rename from src/svc/hasp_ota.cpp rename to src/sys/svc/hasp_ota.cpp index 6dc60d84..fd113e26 100644 --- a/src/svc/hasp_ota.cpp +++ b/src/sys/svc/hasp_ota.cpp @@ -1,27 +1,61 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - #include "hasp_conf.h" +#include "hasp_conf.h" - #include "hasp_debug.h" - #include "hasp_ota.h" +#include "hasp_debug.h" +#include "hasp_ota.h" - #include "../hasp/hasp_dispatch.h" - #include "../hasp/hasp.h" +#include "../../hasp/hasp_dispatch.h" +#include "../../hasp/hasp.h" - #if defined(ARDUINO_ARCH_ESP8266) - #include - #include - #include - #else - #include - #include - #include - #endif +#if defined(ARDUINO_ARCH_ESP8266) +#include +#include +#include +#include +#endif - #include +#if defined(ARDUINO_ARCH_ESP32) +#include +#include +#include +#include + +/** + * This is lets-encrypt-x3-cross-signed.pem + */ +const char* rootCACertificate = "-----BEGIN CERTIFICATE-----\n" + "MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\n" + "MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" + "DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\n" + "SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\n" + "GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\n" + "AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\n" + "q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\n" + "SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\n" + "Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\n" + "a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\n" + "/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\n" + "AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\n" + "CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\n" + "bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\n" + "c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\n" + "VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\n" + "ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\n" + "MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\n" + "Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\n" + "AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\n" + "uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\n" + "wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\n" + "X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\n" + "PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\n" + "KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n" + "-----END CERTIFICATE-----\n"; + +#endif static WiFiClient otaClient; std::string otaUrl = "http://ota.netwize.be"; @@ -141,27 +175,23 @@ void otaSetup(void) // delay(5000); }); - #if HASP_USE_MQTT > 0 - ArduinoOTA.setHostname(String(mqttGetNodename()).c_str()); - #else - ArduinoOTA.setHostname(String(mqttGetNodename()).c_str()); - #endif - // ArduinoOTA.setPassword(configPassword); + ArduinoOTA.setHostname(haspDevice.get_hostname()); + // ArduinoOTA.setPassword(configPassword); // See OTA_PASSWORD ArduinoOTA.setPort(otaPort); - #if ESP32 - #if HASP_USE_MDNS > 0 +#if ESP32 +#if HASP_USE_MDNS > 0 ArduinoOTA.setMdnsEnabled(true); - #else +#else ArduinoOTA.setMdnsEnabled(false); - #endif - // ArduinoOTA.setTimeout(1000); - #endif +#endif + // ArduinoOTA.setTimeout(1000); +#endif ArduinoOTA.setRebootOnSuccess(false); // We do that ourselves - #ifdef OTA_PASSWORD - ArduinoOTA.setPassword(OTA_PASSWORD); - #endif +#ifdef OTA_PASSWORD + ArduinoOTA.setPassword(OTA_PASSWORD); // TODO +#endif ArduinoOTA.begin(); LOG_INFO(TAG_OTA, F(D_SERVICE_STARTED)); @@ -180,25 +210,33 @@ void otaEverySecond(void) if(otaPrecentageComplete >= 0) otaProgress(); } -void otaHttpUpdate(const char * espOtaUrl) +void otaHttpUpdate(const char* espOtaUrl) { // Update ESP firmware from HTTP - #if HASP_USE_MDNS > 0 +#if HASP_USE_MDNS > 0 mdnsStop(); // Keep mDNS responder from breaking things - #endif +#endif - #if defined(ARDUINO_ARCH_ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) // ESPhttpUpdate.onStart(update_started); // ESPhttpUpdate.onEnd(update_finished); // ESPhttpUpdate.onProgress(update_progress); // ESPhttpUpdate.onError(update_error); ESP8266HTTPUpdate httpUpdate; - #else - HTTPUpdate httpUpdate; - #endif - httpUpdate.rebootOnUpdate(false); // We do that ourselves t_httpUpdate_return returnCode = httpUpdate.update(otaClient, espOtaUrl); +#else + HTTPUpdate httpUpdate; + WiFiClientSecure secClient; + secClient.setCACert(rootCACertificate); + + // Reading data over SSL may be slow, use an adequate timeout + secClient.setTimeout(12000 / 1000); // timeout argument is defined in seconds for setTimeout + httpUpdate.rebootOnUpdate(false); // We do that ourselves + t_httpUpdate_return returnCode = httpUpdate.update(secClient, espOtaUrl); + +#endif + switch(returnCode) { case HTTP_UPDATE_FAILED: LOG_ERROR(TAG_FWUP, F("HTTP_UPDATE_FAILED error %i %s"), httpUpdate.getLastError(), @@ -214,9 +252,9 @@ void otaHttpUpdate(const char * espOtaUrl) dispatch_reboot(true); } - #if HASP_USE_MDNS > 0 +#if HASP_USE_MDNS > 0 mdnsStart(); - #endif // HASP_USE_MDNS +#endif // HASP_USE_MDNS } #endif // ARDUINO_ARCH_ESP8266 || ARDUINO_ARCH_ESP32 \ No newline at end of file diff --git a/src/svc/hasp_ota.h b/src/sys/svc/hasp_ota.h similarity index 79% rename from src/svc/hasp_ota.h rename to src/sys/svc/hasp_ota.h index 9d023c1f..215cd73a 100644 --- a/src/svc/hasp_ota.h +++ b/src/sys/svc/hasp_ota.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) @@ -14,7 +14,7 @@ void otaLoop(void); void otaEverySecond(void); /* ===== Special Event Processors ===== */ -void otaHttpUpdate(const char * espOtaUrl); +void otaHttpUpdate(const char* espOtaUrl); #endif #endif \ No newline at end of file diff --git a/src/svc/hasp_slave.cpp b/src/sys/svc/hasp_slave.cpp similarity index 89% rename from src/svc/hasp_slave.cpp rename to src/sys/svc/hasp_slave.cpp index dc287ae9..a3739845 100644 --- a/src/svc/hasp_slave.cpp +++ b/src/sys/svc/hasp_slave.cpp @@ -1,8 +1,8 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #include "hasp_conf.h" -#if HASP_USE_TASMOTA_SLAVE > 0 +#if HASP_USE_TASMOTA_CLIENT > 0 #include "hasp_slave.h" #include "ArduinoJson.h" @@ -25,7 +25,7 @@ unsigned long updatLedPeriod = 1000; // timer in msec for tele mqtt send bool ledstate = false; -void slave_send_state(const __FlashStringHelper * subtopic, const char * payload) +void slave_send_state(const __FlashStringHelper* subtopic, const char* payload) { // page = 0 // p[0].b[0].attr = abc @@ -37,32 +37,32 @@ void slave_send_state(const __FlashStringHelper * subtopic, const char * payload char cBuffer[strlen(payload) + 64]; memset(cBuffer, 0, sizeof(cBuffer)); snprintf_P(cBuffer, sizeof(cBuffer), PSTR("publish %sstate/%s %s"), slaveNodeTopic, subtopic, payload); - slave.ExecuteCommand((char *)cBuffer); + slave.ExecuteCommand((char*)cBuffer); // Log after char buffers are cleared LOG_TRACE(TAG_TASM, F("TAS PUB: %sstate/%S = %s"), slaveNodeTopic, subtopic, payload); } -void slave_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char * attribute, const char * data) +void slave_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char* attribute, const char* data) { char cBuffer[192]; memset(cBuffer, 0, sizeof(cBuffer)); snprintf_P(cBuffer, sizeof(cBuffer), PSTR("publish %sstate/json {\"p[%u].b[%u].%s\":\"%s\"}"), slaveNodeTopic, pageid, btnid, attribute, data); - slave.ExecuteCommand((char *)cBuffer); + slave.ExecuteCommand((char*)cBuffer); // Log after char buffers are cleared LOG_TRACE(TAG_TASM, F("TAS PUB: %sstate/json = {\"p[%u].b[%u].%s\":\"%s\"}"), slaveNodeTopic, pageid, btnid, - attribute, data); + attribute, data); } -void slave_send_input(uint8_t id, const char * payload) +void slave_send_input(uint8_t id, const char* payload) { // LOG_VERBOSE(TAG_TASM,F("MQTT TST: %sstate/input%u = %s"), mqttNodeTopic, id, payload); // to be removed char cBuffer[strlen(payload) + 64]; memset(cBuffer, 0, sizeof(cBuffer)); snprintf_P(cBuffer, sizeof(cBuffer), PSTR("publish %sstate/input%u %s"), slaveNodeTopic, id, payload); - slave.ExecuteCommand((char *)cBuffer); + slave.ExecuteCommand((char*)cBuffer); // Log after char buffers are cleared LOG_TRACE(TAG_TASM, F("TAS PUB: %sstate/input%u = %s"), slaveNodeTopic, id, payload); @@ -85,12 +85,12 @@ void TASMO_TELE_JSON() halDisplayDriverName().c_str(), (TFT_WIDTH), (TFT_HEIGHT)); strcat(data, buffer); } - slave.sendJSON((char *)data); + slave.sendJSON((char*)data); // slave_send_state(F("statusupdate"), data); // debugLastMillis = millis(); } -void TASMO_DATA_RECEIVE(char * data) +void TASMO_DATA_RECEIVE(char* data) { LOG_INFO(TAG_TASM, F("Slave IN [%s]"), data); @@ -145,7 +145,7 @@ void TASMO_EVERY_SECOND(void) void slaveSetup() { - Serial2.begin(HASP_SLAVE_SPEED); + Serial2.begin(HASP_TASMOTACLIENT_SPEED); // slave.attach_FUNC_EVERY_SECOND(TASMO_EVERY_SECOND); slave.attach_FUNC_JSON(TASMO_TELE_JSON); slave.attach_FUNC_COMMAND_SEND(TASMO_DATA_RECEIVE); diff --git a/src/sys/svc/hasp_slave.h b/src/sys/svc/hasp_slave.h new file mode 100644 index 00000000..0fe530c7 --- /dev/null +++ b/src/sys/svc/hasp_slave.h @@ -0,0 +1,21 @@ +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_TASMOTACLIENT_H +#define HASP_TASMOTACLIENT_H + +#include "ArduinoJson.h" + +#define HASP_TASMOTACLIENT_SPEED 57600 + +void TASMO_EVERY_SECOND(void); +void TASMO_DATA_RECEIVE(char* data); +void slave_send_state(const __FlashStringHelper* subtopic, const char* payload); +void slave_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char* attribute, const char* data); +void slave_send_input(uint8_t id, const char* payload); +void slave_send_statusupdate(); + +void slaveSetup(); +void slaveLoop(void); + +#endif \ No newline at end of file diff --git a/src/svc/hasp_telnet.cpp b/src/sys/svc/hasp_telnet.cpp similarity index 89% rename from src/svc/hasp_telnet.cpp rename to src/sys/svc/hasp_telnet.cpp index 7f10e7e1..52de8836 100644 --- a/src/svc/hasp_telnet.cpp +++ b/src/sys/svc/hasp_telnet.cpp @@ -1,41 +1,43 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #include "hasp_conf.h" + #if HASP_USE_TELNET > 0 - #include "ArduinoJson.h" - #include "ConsoleInput.h" +#include "ArduinoJson.h" +#include "ConsoleInput.h" - #include "hasp_debug.h" - #include "hasp_config.h" - #include "hasp_telnet.h" +#include "hasp_debug.h" +#include "hasp_config.h" +#include "hasp_telnet.h" +#include "hasp_http.h" - #include "../hasp/hasp_dispatch.h" +#include "../../hasp/hasp_dispatch.h" - #if defined(ARDUINO_ARCH_ESP32) - #include +#if defined(ARDUINO_ARCH_ESP32) +#include WiFiClient telnetClient; -static WiFiServer * telnetServer; - #elif defined(ARDUINO_ARCH_ESP8266) - #include +static WiFiServer* telnetServer; +#elif defined(ARDUINO_ARCH_ESP8266) +#include WiFiClient telnetClient; -static WiFiServer * telnetServer; - #else +static WiFiServer* telnetServer; +#else //#include EthernetClient telnetClient; static EthernetServer telnetServer(23); - #endif +#endif - #if HASP_USE_HTTP > 0 +#if HASP_USE_HTTP > 0 extern hasp_http_config_t http_config; - #endif +#endif uint8_t telnetLoginState = TELNET_UNAUTHENTICATED; uint16_t telnetPort = 23; uint8_t telnetEnabled = true; // Enable telnet debug output uint8_t telnetLoginAttempt = 0; // Initial attempt -ConsoleInput * telnetConsole; +ConsoleInput* telnetConsole; void telnetClientDisconnect() { @@ -82,27 +84,27 @@ void telnetAcceptClient() // telnetClient.print((char)0xFD); // telnetClient.print((char)0x1B); - #if HASP_USE_HTTP > 0 +#if HASP_USE_HTTP > 0 if(strlen(http_config.user) != 0 || strlen(http_config.password) != 0) { telnetClient.println(F("\r\n" D_USERNAME " ")); telnetLoginState = TELNET_UNAUTHENTICATED; } else - #endif +#endif { telnetClientLogon(); } telnetLoginAttempt = 0; // Initial attempt } - #if 0 +#if 0 static inline void telnetProcessLine() { telnetInputBuffer[telnetInputIndex] = 0; // null terminate our char array switch(telnetLoginState) { case TELNET_UNAUTHENTICATED: { - telnetClient.printf(PSTR(D_TELNET_PASSWORD" %c%c%c"), 0xFF, 0xFB, 0x01); // Hide characters - #if HASP_USE_HTTP > 0 + telnetClient.printf(PSTR(D_PASSWORD" %c%c%c"), 0xFF, 0xFB, 0x01); // Hide characters +#if HASP_USE_HTTP > 0 telnetLoginState = strcmp(telnetInputBuffer, http_config.user) == 0 ? TELNET_USERNAME_OK : TELNET_USERNAME_NOK; break; } @@ -119,12 +121,12 @@ static inline void telnetProcessLine() if(telnetLoginAttempt >= 3) { telnetClientDisconnect(); } else { - telnetClient.print(F(D_TELNET_USERNAME" ")); + telnetClient.print(F(D_USERNAME" ")); } } - #else +#else telnetClientLogon(); - #endif +#endif break; } default: @@ -178,9 +180,9 @@ static inline void telnetProcessCharacter(char ch) //} } - #endif +#endif -static inline void telnetProcessLine(const char * input) +static inline void telnetProcessLine(const char* input) { switch(telnetLoginState) { case TELNET_UNAUTHENTICATED: { @@ -188,7 +190,7 @@ static inline void telnetProcessLine(const char * input) snprintf_P(buffer, sizeof(buffer), PSTR(D_PASSWORD " %c%c%c\n"), 0xFF, 0xFB, 0x01); // Hide characters telnetClient.print(buffer); - #if HASP_USE_HTTP > 0 +#if HASP_USE_HTTP > 0 telnetLoginState = strcmp(input, http_config.user) == 0 ? TELNET_USERNAME_OK : TELNET_USERNAME_NOK; break; } @@ -208,9 +210,9 @@ static inline void telnetProcessLine(const char * input) telnetClient.print(F(D_USERNAME " ")); } } - #else +#else telnetClientLogon(); - #endif +#endif break; } default: @@ -230,15 +232,15 @@ void telnetSetup() // telnetSetConfig(settings); if(telnetEnabled) { // Setup telnet server for remote debug output - #if defined(STM32F4xx) +#if defined(STM32F4xx) // if(!telnetServer) telnetServer = new EthernetServer(telnetPort); // if(telnetServer) { telnetServer->begin(); LOG_INFO(TAG_TELN, F(D_TELNET_STARTED)); - // } else { - // LOG_ERROR(TAG_TELN,F("Failed to start telnet server")); - //} - #else + // } else { + // LOG_ERROR(TAG_TELN,F("Failed to start telnet server")); + //} +#else if(!telnetServer) telnetServer = new WiFiServer(telnetPort); if(telnetServer) { telnetServer->setNoDelay(true); @@ -253,7 +255,7 @@ void telnetSetup() } LOG_ERROR(TAG_TELN, F(D_TELNET_FAILED)); - #endif +#endif } } @@ -261,7 +263,7 @@ void telnetLoop() { // Basic telnet client handling code from: https://gist.github.com/tablatronix/4793677ca748f5f584c95ec4a2b10303 - #if defined(STM32F4xx) +#if defined(STM32F4xx) Ethernet.schedule(); // if(telnetServer) { // client is connected @@ -288,7 +290,7 @@ void telnetLoop() } } } - #else +#else if(telnetServer && telnetServer->hasClient()) { // a new client has connected if(!telnetClient.connected()) { // nobody is already connected telnetAcceptClient(); // allow the new client @@ -311,11 +313,11 @@ void telnetLoop() } } } - #endif +#endif } - #if HASP_USE_CONFIG > 0 -bool telnetGetConfig(const JsonObject & settings) +#if HASP_USE_CONFIG > 0 +bool telnetGetConfig(const JsonObject& settings) { bool changed = false; @@ -337,7 +339,7 @@ bool telnetGetConfig(const JsonObject & settings) * * @param[in] settings JsonObject with the config settings. **/ -bool telnetSetConfig(const JsonObject & settings) +bool telnetSetConfig(const JsonObject& settings) { configOutput(settings, TAG_TELN); bool changed = false; @@ -347,6 +349,6 @@ bool telnetSetConfig(const JsonObject & settings) return changed; } - #endif // HASP_USE_CONFIG +#endif // HASP_USE_CONFIG #endif \ No newline at end of file diff --git a/src/svc/hasp_telnet.h b/src/sys/svc/hasp_telnet.h similarity index 81% rename from src/svc/hasp_telnet.h rename to src/sys/svc/hasp_telnet.h index 98a958ee..314e678b 100644 --- a/src/svc/hasp_telnet.h +++ b/src/sys/svc/hasp_telnet.h @@ -1,4 +1,4 @@ -/* MIT License - Copyright (c) 2020 Francis Van Roie +/* MIT License - Copyright (c) 2019-2021 Francis Van Roie For full license information read the LICENSE file in the project folder */ #ifndef HASP_TELNET_H @@ -23,8 +23,8 @@ void telnetStop(void); /* ===== Read/Write Configuration ===== */ #if HASP_USE_CONFIG > 0 -bool telnetSetConfig(const JsonObject & settings); -bool telnetGetConfig(const JsonObject & settings); +bool telnetSetConfig(const JsonObject& settings); +bool telnetGetConfig(const JsonObject& settings); #endif #define TELNET_UNAUTHENTICATED 0 diff --git a/test/config.yaml b/test/config.yaml index 123df340..8e75a5fc 100644 --- a/test/config.yaml +++ b/test/config.yaml @@ -1,10 +1,11 @@ # config.yaml --- - name: Common test information description: Connection information for MQTT Client variables: - host: 10.4.0.5 + host: homeassistant.local + username: hasp + password: hasp port: 1883 - plate: plate35 \ No newline at end of file + plate: plate35 diff --git a/test/test_colors.tavern.yaml b/test/test_colors.tavern.yaml index 569dff13..32e07ac0 100644 --- a/test/test_colors.tavern.yaml +++ b/test/test_colors.tavern.yaml @@ -13,6 +13,9 @@ paho-mqtt: host: "{host}" port: !int "{port:d}" timeout: 3 + auth: + username: "{username}" + password: "{password}" marks: - parametrize: @@ -60,17 +63,17 @@ marks: - ["purple", "#830083", 131, 0, 131, 32784] - ["salmon", "#ff8173", 255, 129, 115, 64526] - ["sienna", "#a45029", 164, 80, 41, 41605] - - ["silver", "#c5c2c5", 197, 194, 197, 50712] - ["tomato", "#ff6141", 255, 97, 65, 64264] - ["violet", "#ee81ee", 238, 129, 238, 60445] - ["yellow", "#ffff00", 255, 255, 0, 65504] - ["fuchsia", "#ff00ff", 255, 0, 255, 63519] - ["magenta", "#ff00ff", 255, 0, 255, 63519] + - ["silver", "#c5c2c5", 197, 194, 197, 50712] - parametrize: key: obj vals: - - cb + - checkbox - btn stages: @@ -81,20 +84,20 @@ stages: mqtt_response: topic: hasp/{plate}/state/page payload: "1" - timeout: 5 + timeout: 1 delay_after: 0 - name: Set bg_color mqtt_publish: topic: hasp/{plate}/command payload: "p[1].b[0].bg_color={color}" - delay_after: 0.1 + delay_after: 0.02 - name: Clear page mqtt_publish: topic: hasp/{plate}/command/clearpage payload: "" - delay_after: 0.2 + delay_after: 0.02 - name: Create object mqtt_publish: @@ -103,16 +106,16 @@ stages: obj: "{obj}" id: 1 txt: "{color}" - x: "{r}" - y: "{g}" - w: "{b}" - delay_after: 0.1 + r: !int "{r:d}" + g: !int "{g:d}" + b: !int "{b:d}" + delay_after: 0.02 - name: Set bg_color mqtt_publish: topic: hasp/{plate}/command payload: "p[1].b[0].bg_color={rgb565}" - delay_after: 0.1 + delay_after: 0.02 - name: Test named COLOR mqtt_publish: @@ -122,10 +125,10 @@ stages: topic: hasp/{plate}/state/p1b1 json: text_color: "{hex}" - r: "{r}" - g: "{g}" - b: "{b}" - timeout: 5 + r: !int "{r:d}" + g: !int "{g:d}" + b: !int "{b:d}" + timeout: 1 - name: Reset mqtt_publish: @@ -141,10 +144,10 @@ stages: topic: hasp/{plate}/state/p1b1 json: text_color: "{hex}" - r: "{r}" - g: "{g}" - b: "{b}" - timeout: 5 + r: !int "{r:d}" + g: !int "{g:d}" + b: !int "{b:d}" + timeout: 1 - name: Reset mqtt_publish: @@ -160,7 +163,7 @@ stages: topic: hasp/{plate}/state/p1b1 json: text_color: "{hex}" - r: "{r}" - g: "{g}" - b: "{b}" - timeout: 5 + r: !int "{r:d}" + g: !int "{g:d}" + b: !int "{b:d}" + timeout: 1 diff --git a/test/test_label.tavern.yaml b/test/test_label.tavern.yaml index 48a4ce44..207baafe 100644 --- a/test/test_label.tavern.yaml +++ b/test/test_label.tavern.yaml @@ -12,7 +12,10 @@ paho-mqtt: &mqtt_spec connect: host: "{host}" port: !int "{port:d}" - timeout: 3 + timeout: 1 + auth: + username: "{username}" + password: "{password}" stages: - name: Page 1 @@ -22,14 +25,14 @@ stages: mqtt_response: topic: hasp/{plate}/state/page payload: "1" - timeout: 5 - delay_after: 0.1 + timeout: 1 + delay_after: 0.02 - name: Clear page mqtt_publish: topic: hasp/{plate}/command/clearpage payload: "" - delay_after: 0.1 + delay_after: 0.02 - name: Create object mqtt_publish: @@ -37,310 +40,310 @@ stages: json: objid: 12 id: 1 - delay_after: 0.1 + delay_after: 0.02 - name: Set x mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].x=50" - delay_after: 0.1 + payload: "p1b1.x=50" + delay_after: 0.02 - name: Get x mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].x" + payload: "p1b1.x" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - x: "50" - timeout: 5 + x: 50 + timeout: 1 - name: Set x mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].x=25" + payload: "p1b1.x=25" - name: Get x mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].x" + payload: "p1b1.x" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - x: "25" - timeout: 5 + x: 25 + timeout: 1 - name: Set y mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].y=50" - delay_after: 0.1 + payload: "p1b1.y=50" + delay_after: 0.02 - name: Get y mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].y" + payload: "p1b1.y" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - y: "50" - timeout: 5 + y: 50 + timeout: 1 - name: Set y mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].y=25" - delay_after: 0.1 + payload: "p1b1.y=25" + delay_after: 0.02 - name: Get y mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].y" + payload: "p1b1.y" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - y: "25" - timeout: 5 + y: 25 + timeout: 1 - name: Set w mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].w=50" - delay_after: 0.1 + payload: "p1b1.w=50" + delay_after: 0.02 - name: Get w mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].w" + payload: "p1b1.w" mqtt_response: topic: hasp/{plate}/state/p1b1 json: w: !anything - timeout: 5 + timeout: 1 - name: Set w mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].w=25" + payload: "p1b1.w=25" - name: Get w mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].w" + payload: "p1b1.w" mqtt_response: topic: hasp/{plate}/state/p1b1 json: w: !anything - timeout: 5 + timeout: 1 - name: Set h mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].h=50" - delay_after: 0.1 + payload: "p1b1.h=50" + delay_after: 0.02 - name: Get h mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].h" + payload: "p1b1.h" mqtt_response: topic: hasp/{plate}/state/p1b1 json: h: !anything - timeout: 5 + timeout: 1 - name: Set h mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].h=25" - delay_after: 0.1 + payload: "p1b1.h=25" + delay_after: 0.02 - name: Get h mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].h" + payload: "p1b1.h" mqtt_response: topic: hasp/{plate}/state/p1b1 json: h: !anything - timeout: 5 + timeout: 1 - name: Set mode mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].mode=crop" - delay_after: 0.1 + payload: "p1b1.mode=crop" + delay_after: 0.02 - name: Get mode mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].mode" + payload: "p1b1.mode" - name: Set w mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].w=50" - delay_after: 0.1 + payload: "p1b1.w=50" + delay_after: 0.02 - name: Get w mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].w" + payload: "p1b1.w" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - w: "50" - timeout: 5 + w: 50 + timeout: 1 - name: Set w mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].w=25" + payload: "p1b1.w=25" - name: Get w mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].w" + payload: "p1b1.w" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - w: "25" - timeout: 5 + w: 25 + timeout: 1 - name: Set h mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].h=50" - delay_after: 0.1 + payload: "p1b1.h=50" + delay_after: 0.02 - name: Get h mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].h" + payload: "p1b1.h" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - h: "50" - timeout: 5 + h: 50 + timeout: 1 - name: Set h mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].h=45" - delay_after: 0.1 + payload: "p1b1.h=45" + delay_after: 0.02 - name: Get h mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].h" + payload: "p1b1.h" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - h: "45" - timeout: 5 + h: 45 + timeout: 1 - name: Set enabled mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].enabled=0" - delay_after: 0.1 + payload: "p1b1.enabled=0" + delay_after: 0.02 - name: Get enabled mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].enabled" + payload: "p1b1.enabled" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - enabled: "0" - timeout: 5 + enabled: 0 + timeout: 1 - name: Set enabled mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].enabled=1" - delay_after: 0.1 + payload: "p1b1.enabled=1" + delay_after: 0.02 - name: Get enabled mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].enabled" + payload: "p1b1.enabled" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - enabled: "1" - timeout: 5 + enabled: 1 + timeout: 1 - name: Set hidden mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].hidden=1" - delay_after: 0.1 + payload: "p1b1.hidden=1" + delay_after: 0.02 - name: Get hidden mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].hidden" + payload: "p1b1.hidden" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - hidden: "1" - timeout: 5 + hidden: 1 + timeout: 1 - name: Get vis mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].vis" + payload: "p1b1.vis" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - vis: "0" - timeout: 5 + vis: 0 + timeout: 1 - name: Set hidden mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].hidden=0" - delay_after: 0.1 + payload: "p1b1.hidden=0" + delay_after: 0.02 - name: Get hidden mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].hidden" + payload: "p1b1.hidden" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - hidden: "0" - timeout: 5 + hidden: 0 + timeout: 1 - name: Get vis mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].vis" + payload: "p1b1.vis" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - vis: "1" - timeout: 5 + vis: 1 + timeout: 1 - name: Set vis mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].vis=0" - delay_after: 0.1 + payload: "p1b1.vis=0" + delay_after: 0.02 - name: Get hidden mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].hidden" + payload: "p1b1.hidden" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - hidden: "1" - timeout: 5 + hidden: 1 + timeout: 1 - name: Get vis mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].vis" + payload: "p1b1.vis" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - vis: "0" - timeout: 5 + vis: 0 + timeout: 1 - name: Set vis mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].vis=1" - delay_after: 0.1 + payload: "p1b1.vis=1" + delay_after: 0.02 - name: Get hidden mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].hidden" + payload: "p1b1.hidden" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - hidden: "0" - timeout: 5 + hidden: 0 + timeout: 1 - name: Get vis mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].vis" + payload: "p1b1.vis" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - vis: "1" - timeout: 5 + vis: 1 + timeout: 1 diff --git a/test/test_mqtt.tavern.yaml b/test/test_mqtt.tavern.yaml index 18c220af..c0aa526a 100644 --- a/test/test_mqtt.tavern.yaml +++ b/test/test_mqtt.tavern.yaml @@ -1,6 +1,5 @@ # test_page.tavern.yaml --- - test_name: Page command includes: @@ -14,6 +13,9 @@ paho-mqtt: host: "{host}" port: !int "{port:d}" timeout: 3 + auth: + username: "{username}" + password: "{password}" stages: - name: step 1 - Page test @@ -23,8 +25,8 @@ stages: mqtt_response: topic: hasp/{plate}/state/page payload: "1" - timeout: 5 - delay_after: 1 + timeout: 1 + delay_after: 0 - name: step 2 - Page test mqtt_publish: topic: hasp/{plate}/command @@ -32,8 +34,8 @@ stages: mqtt_response: topic: hasp/{plate}/state/page payload: "2" - timeout: 5 - delay_after: 1 + timeout: 1 + delay_after: 0 - name: step 3 - Page test mqtt_publish: topic: hasp/{plate}/command @@ -41,26 +43,26 @@ stages: mqtt_response: topic: hasp/{plate}/state/page payload: "3" - timeout: 5 - delay_after: 1 + timeout: 1 + delay_after: 0 - name: step 4 - Page test mqtt_publish: topic: hasp/{plate}/command/json - payload: "[\"page=0\"]" + payload: '["page=1"]' mqtt_response: topic: hasp/{plate}/state/page - payload: "0" - timeout: 3 - delay_after: 1 + payload: "1" + timeout: 1 + delay_after: 0 - name: step 5 - Page test mqtt_publish: topic: hasp/{plate}/command/json - payload: "[\"page 300\"]" + payload: '["page 300"]' mqtt_response: topic: hasp/{plate}/state/page - payload: "0" - timeout: 3 - delay_after: 1 + payload: "1" + timeout: 1 + delay_after: 0 --- test_name: Reboot Command @@ -75,7 +77,7 @@ paho-mqtt: connect: host: "{host}" port: !int "{port:d}" - timeout: 3 + timeout: 1 stages: - name: Test reboot command @@ -86,7 +88,7 @@ stages: topic: hasp/{plate}/LWT payload: "offline" timeout: 20 - delay_after: 1 + delay_after: 0 --- test_name: Idle States @@ -110,9 +112,9 @@ stages: payload: "wakeup" mqtt_response: topic: hasp/{plate}/state/idle - payload: "LONG" + payload: "long" timeout: 190 - delay_after: 1 + delay_after: 0 - name: Test idle mqtt_publish: @@ -120,9 +122,9 @@ stages: payload: "wakeup" mqtt_response: topic: hasp/{plate}/state/idle - payload: "SHORT" + payload: "short" timeout: 70 - delay_after: 1 + delay_after: 0 - name: Test idle mqtt_publish: @@ -130,6 +132,6 @@ stages: payload: "wakeup" mqtt_response: topic: hasp/{plate}/state/idle - payload: "OFF" - timeout: 3 - delay_after: 1 + payload: "off" + timeout: 1 + delay_after: 0 diff --git a/test/test_obj.tavern.yaml b/test/test_obj.tavern.yaml index 032621a3..5b0a4dd7 100644 --- a/test/test_obj.tavern.yaml +++ b/test/test_obj.tavern.yaml @@ -13,8 +13,33 @@ paho-mqtt: host: "{host}" port: !int "{port:d}" timeout: 3 + auth: + username: "{username}" + password: "{password}" marks: + - parametrize: + key: obj + vals: + - btnmatrix + - cpicker + - table + - tabview + - chart + - gauge + - btn + - label + - slider + - checkbox + - switch + - bar + - arc + - led + - obj + - lmeter + - dropdown + - spinner + - roller - parametrize: key: - hidden @@ -25,27 +50,35 @@ marks: - h - radius - opacity + - str1 + - str2 vals: - - [1, 0, 120, 121, 122, 123, 0, 255] - - [0, 1, 80, 81, 82, 83, 32535, 192] - - [1, 0, -10, -10, 256, 257, 1, 64] - - [0, 1, 1024, 1025, 1026, 1027, 5, 0] - - parametrize: - key: objid - vals: - - 10 - - 12 - - 20 - - 22 - - 30 - - 31 - - 32 - - 33 - - 40 - - 41 - - 50 - - 51 - - 91 + - [1, 0, 120, 121, 122, 123, 0, 255, "I'm sorry.", "louie"] + - [1, 0, -10, -10, 256, 257, 1, 64, "louie", " The cat stretched."] + - [ + 0, + 1, + 1024, + 1025, + 1026, + 1027, + 5, + 0, + "The pipe began to rust while new.", + "", + ] + - [ + 0, + 1, + 80, + 81, + 82, + 83, + 32535, + 192, + "", + " Oak is strong and also gives shade.", + ] stages: - name: Page 1 @@ -55,140 +88,167 @@ stages: mqtt_response: topic: hasp/{plate}/state/page payload: "1" - timeout: 5 + timeout: 1 delay_after: 0 - name: Clear page mqtt_publish: topic: hasp/{plate}/command/clearpage payload: "" - delay_after: 0 + delay_after: 0.2 - name: Create object mqtt_publish: topic: hasp/{plate}/command/jsonl json: - objid: "{objid}" + obj: "{obj}" id: 1 + x: 128 + y: 128 delay_after: 0 - - name: Test x - mqtt_publish: - topic: hasp/{plate}/command/json - payload: '["p[1].b[1].x={x}","p[1].b[1].x"]' - mqtt_response: - topic: hasp/{plate}/state/p1b1 - json: - x: "{x}" - timeout: 5 - - name: Test y mqtt_publish: topic: hasp/{plate}/command/json - payload: '["p[1].b[1].y={y}","p[1].b[1].y"]' + payload: '["p1b1.y={y}","p1b1.y"]' mqtt_response: topic: hasp/{plate}/state/p1b1 json: - y: "{y}" - timeout: 5 + y: !int "{y:d}" + timeout: 1 + + - name: Test x + mqtt_publish: + topic: hasp/{plate}/command/json + payload: '["p1b1.x={x}","p1b1.x"]' + mqtt_response: + topic: hasp/{plate}/state/p1b1 + json: + x: !int "{x:d}" + timeout: 1 - name: Test w mqtt_publish: topic: hasp/{plate}/command/json - payload: '["p[1].b[1].w={w}","p[1].b[1].w"]' + payload: '["p1b1.w={w}","p1b1.w"]' mqtt_response: topic: hasp/{plate}/state/p1b1 json: - w: "{w}" - timeout: 5 + w: !int "{w:d}" + timeout: 1 - name: Test h mqtt_publish: topic: hasp/{plate}/command/json - payload: '["p[1].b[1].h={h}","p[1].b[1].h"]' + payload: '["p1b1.h={h}","p1b1.h"]' delay_after: 0 mqtt_response: topic: hasp/{plate}/state/p1b1 json: - h: "{h}" - timeout: 5 + h: !int "{h:d}" + timeout: 1 - name: Test enabled mqtt_publish: topic: hasp/{plate}/command/json - payload: '["p[1].b[1].enabled={hidden}","p[1].b[1].enabled"]' + payload: '["p1b1.enabled={hidden}","p1b1.enabled"]' delay_after: 0 mqtt_response: topic: hasp/{plate}/state/p1b1 json: - enabled: "{hidden}" - timeout: 5 + enabled: !int "{hidden:d}" + timeout: 1 - name: Set vis mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].vis={hidden}" + payload: "p1b1.vis={hidden}" delay_after: 0 - name: Get hidden mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].hidden" + payload: "p1b1.hidden" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - hidden: "{hidden_inv}" - timeout: 5 + hidden: !int "{hidden_inv:d}" + timeout: 1 - name: Get vis mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].vis" + payload: "p1b1.vis" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - vis: "{hidden}" - timeout: 5 + vis: !int "{hidden:d}" + timeout: 1 - name: Set hidden mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].hidden={hidden}" + payload: "p1b1.hidden={hidden}" delay_after: 0 - name: Get hidden mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].hidden" + payload: "p1b1.hidden" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - hidden: "{hidden}" - timeout: 5 + hidden: !int "{hidden:d}" + timeout: 1 - name: Get vis mqtt_publish: topic: hasp/{plate}/command - payload: "p[1].b[1].vis" + payload: "p1b1.vis" mqtt_response: topic: hasp/{plate}/state/p1b1 json: - vis: "{hidden_inv}" - timeout: 5 + vis: !int "{hidden_inv:d}" + timeout: 1 - name: Test opacity mqtt_publish: topic: hasp/{plate}/command/json - payload: '["p[1].b[1].opacity={opacity}","p[1].b[1].opacity"]' + payload: '["p1b1.opacity={opacity}","p1b1.opacity"]' mqtt_response: topic: hasp/{plate}/state/p1b1 json: - opacity: "{opacity}" - timeout: 5 + opacity: !int "{opacity:d}" + timeout: 1 - name: Test radius mqtt_publish: topic: hasp/{plate}/command/json - payload: '["p[1].b[1].radius={radius}","p[1].b[1].radius"]' + payload: '["p1b1.radius={radius}","p1b1.radius"]' mqtt_response: topic: hasp/{plate}/state/p1b1 json: - radius: "{radius}" - timeout: 5 + radius: !int "{radius:d}" + timeout: 1 + + - name: Set value_str + mqtt_publish: + topic: "hasp/{plate}/command/p1b1.value_str" + payload: "{str1}{str2}" + delay_after: 0.05 + - name: Get value_str + mqtt_publish: + topic: hasp/{plate}/command + payload: "p1b1.value_str" + mqtt_response: + topic: hasp/{plate}/state/p1b1 + json: + value_str: "{str1}{str2}" + timeout: 1 + + - name: Get obj type + mqtt_publish: + topic: hasp/{plate}/command + payload: "p1b1.obj" + mqtt_response: + topic: hasp/{plate}/state/p1b1 + json: + obj: "{obj}" + timeout: 1 diff --git a/test/test_value_str.tavern.yaml b/test/test_value_str.tavern.yaml index a0cc6a4f..ec85b53d 100644 --- a/test/test_value_str.tavern.yaml +++ b/test/test_value_str.tavern.yaml @@ -1,6 +1,5 @@ # test_value_str.tavern.yaml --- - test_name: Obj Standard Properties includes: @@ -14,29 +13,33 @@ paho-mqtt: host: "{host}" port: !int "{port:d}" timeout: 3 + auth: + username: "{username}" + password: "{password}" marks: - parametrize: - key: objid + key: obj vals: - - 10 - - 12 - - 20 - - 22 - - 30 - - 31 - - 32 -# - 33 -# - 40 - - 41 - - 50 - - 51 - - 91 -# - 90 -# - 1 - - 2 - - 71 - - 80 + - cpicker + - table + - tabview + - chart + - gauge + - btn + - label + - slider + - checkbox + - switch + - bar + - arc + - led + - obj + - lmeter + - dropdown + - spinner + - roller + - btnmatrix - parametrize: key: str1 @@ -49,8 +52,6 @@ marks: - "She opened the door." - "Aaron made a picture." - "I'm sorry." - - Test - - ABC - huey - dewey - "" @@ -59,7 +60,6 @@ marks: key: str2 vals: - louie - - fred - " I danced." - " Oak is strong and also gives shade." - " Cats and dogs each hate the other." @@ -81,14 +81,26 @@ stages: mqtt_response: topic: hasp/{plate}/state/page payload: "1" - timeout: 5 + timeout: 1 + delay_after: 0 + + - name: Create object + mqtt_publish: + topic: hasp/{plate}/command/jsonl + json: + obj: "{obj}" + id: 1 + x: 0 + y: 0 + w: 240 + h: 240 delay_after: 0 - name: Set value_str mqtt_publish: topic: "hasp/{plate}/command/p[1].b[1].value_str" payload: "{str1}{str2}" - delay_after: 0.2 + delay_after: 0 - name: Get value_str mqtt_publish: topic: hasp/{plate}/command @@ -97,4 +109,4 @@ stages: topic: hasp/{plate}/state/p1b1 json: value_str: "{str1}{str2}" - timeout: 5 + timeout: 1 diff --git a/tools/esp_merge_bin.py b/tools/esp_merge_bin.py new file mode 100644 index 00000000..58fa2c46 --- /dev/null +++ b/tools/esp_merge_bin.py @@ -0,0 +1,97 @@ +Import('env') +import os +import sys +import shutil +import subprocess + +buildFlags = env.ParseFlags(env['BUILD_FLAGS']) +OUTPUT_DIR = "build_output{}".format(os.path.sep) + +platform = env.PioPlatform() +FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoespressif32") +FRAMEWORK_DIR = "{}{}".format(FRAMEWORK_DIR, os.path.sep) + + +def get_fw_version(source, target, env): + global HASP_VER_MAJ + global HASP_VER_MIN + global HASP_VER_REV + + for item in buildFlags.get("CPPDEFINES"): + if (type(item) is list): + if (item[0]=="HASP_VER_MAJ"): HASP_VER_MAJ = item[1] + if (item[0]=="HASP_VER_MIN"): HASP_VER_MIN = item[1] + if (item[0]=="HASP_VER_REV"): HASP_VER_REV = item[1] + print(" * %s = %s" % (item[0],item[1])) + else: + print(" * %s" % item) + + +def copy_merge_bins(source, target, env): + version = 'v' + str(HASP_VER_MAJ) + '.' + str(HASP_VER_MIN) + '.' + str(HASP_VER_REV) + name =str(target[0]).split(os.path.sep)[2] + flash_size = env.GetProjectOption("board_upload.flash_size") + + bootloader = "{}tools{}sdk{}bin{}bootloader_dio_40m.bin".format(FRAMEWORK_DIR, os.path.sep, os.path.sep, os.path.sep, os.path.sep) + partitions = "{}{}partitions.bin".format(env.subst("$BUILD_DIR"), os.path.sep) + boot_app0 = "{}tools{}partitions{}boot_app0.bin".format(FRAMEWORK_DIR, os.path.sep, os.path.sep, os.path.sep) + firmware_dst ="{}firmware{}{}_full_{}_{}.bin".format(OUTPUT_DIR, os.path.sep, name, flash_size, version) + firmware_src = str(target[0]) + + # check if output directories exist and create if necessary + if not os.path.isdir(OUTPUT_DIR): + os.mkdir(OUTPUT_DIR) + + for d in ['firmware', 'map']: + if not os.path.isdir("{}{}".format(OUTPUT_DIR, d)): + os.mkdir("{}{}".format(OUTPUT_DIR, d)) + + # check if new target files exist and remove if necessary + for f in [firmware_dst]: + if os.path.isfile(f): + os.remove(f) + + print(bootloader) + print(partitions) + print(boot_app0) + print(firmware_src) + print(firmware_dst) + print(flash_size) + + process = subprocess.Popen(['python', 'tools/esptool_with_merge_bin.py', '--chip', 'esp32', 'merge_bin', '--output', firmware_dst, '--flash_mode', 'dio', '--flash_size', flash_size, '0x1000', bootloader, '0x8000', partitions, '0xe000', boot_app0, '0x10000', firmware_src], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = process.communicate() + stdout, stderr + print(stdout.decode("utf-8") ) + print(stderr.decode("utf-8") ) + +def copy_ota(source, target, env): + version = 'v' + str(HASP_VER_MAJ) + '.' + str(HASP_VER_MIN) + '.' + str(HASP_VER_REV) + name =str(target[0]).split(os.path.sep)[2] + + firmware_src = str(target[0]) + firmware_dst ="{}firmware{}{}_ota_{}.bin".format(OUTPUT_DIR, os.path.sep, name, version) + + # check if output directories exist and create if necessary + if not os.path.isdir(OUTPUT_DIR): + os.mkdir(OUTPUT_DIR) + + for d in ['firmware', 'map']: + if not os.path.isdir("{}{}".format(OUTPUT_DIR, d)): + os.mkdir("{}{}".format(OUTPUT_DIR, d)) + + # check if new target files exist and remove if necessary + for f in [firmware_dst]: + if os.path.isfile(f): + os.remove(f) + + print(firmware_src) + print(firmware_dst) + + # copy firmware.bin to firmware/.bin + shutil.copy(firmware_src, firmware_dst) + +env.AddPreAction("$BUILD_DIR/${PROGNAME}.bin", [get_fw_version]) +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [copy_merge_bins]) +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [copy_ota]) diff --git a/tools/esptool_with_merge_bin.py b/tools/esptool_with_merge_bin.py new file mode 100644 index 00000000..df16da4c --- /dev/null +++ b/tools/esptool_with_merge_bin.py @@ -0,0 +1,4422 @@ +#!/usr/bin/env python +# +# ESP8266 & ESP32 family ROM Bootloader Utility +# Copyright (C) 2014-2016 Fredrik Ahlberg, Angus Gratton, Espressif Systems (Shanghai) PTE LTD, other contributors as noted. +# https://github.com/espressif/esptool +# +# This program 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 2 of the License, or (at your option) any later version. +# +# This program 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, write to the Free Software Foundation, Inc., 51 Franklin +# Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from __future__ import division, print_function + +import argparse +import base64 +import binascii +import copy +import hashlib +import inspect +import io +import itertools +import os +import shlex +import string +import struct +import sys +import time +import zlib + +try: + import serial +except ImportError: + print("Pyserial is not installed for %s. Check the README for installation instructions." % (sys.executable)) + raise + +# check 'serial' is 'pyserial' and not 'serial' https://github.com/espressif/esptool/issues/269 +try: + if "serialization" in serial.__doc__ and "deserialization" in serial.__doc__: + raise ImportError(""" +esptool.py depends on pyserial, but there is a conflict with a currently installed package named 'serial'. + +You may be able to work around this by 'pip uninstall serial; pip install pyserial' \ +but this may break other installed Python software that depends on 'serial'. + +There is no good fix for this right now, apart from configuring virtualenvs. \ +See https://github.com/espressif/esptool/issues/269#issuecomment-385298196 for discussion of the underlying issue(s).""") +except TypeError: + pass # __doc__ returns None for pyserial + +try: + import serial.tools.list_ports as list_ports +except ImportError: + print("The installed version (%s) of pyserial appears to be too old for esptool.py (Python interpreter %s). " + "Check the README for installation instructions." % (sys.VERSION, sys.executable)) + raise +except Exception: + if sys.platform == "darwin": + # swallow the exception, this is a known issue in pyserial+macOS Big Sur preview ref https://github.com/espressif/esptool/issues/540 + list_ports = None + else: + raise + + +__version__ = "3.1-dev" + +MAX_UINT32 = 0xffffffff +MAX_UINT24 = 0xffffff + +DEFAULT_TIMEOUT = 3 # timeout for most flash operations +START_FLASH_TIMEOUT = 20 # timeout for starting flash (may perform erase) +CHIP_ERASE_TIMEOUT = 120 # timeout for full chip erase +MAX_TIMEOUT = CHIP_ERASE_TIMEOUT * 2 # longest any command can run +SYNC_TIMEOUT = 0.1 # timeout for syncing with bootloader +MD5_TIMEOUT_PER_MB = 8 # timeout (per megabyte) for calculating md5sum +ERASE_REGION_TIMEOUT_PER_MB = 30 # timeout (per megabyte) for erasing a region +ERASE_WRITE_TIMEOUT_PER_MB = 40 # timeout (per megabyte) for erasing and writing data +MEM_END_ROM_TIMEOUT = 0.05 # special short timeout for ESP_MEM_END, as it may never respond +DEFAULT_SERIAL_WRITE_TIMEOUT = 10 # timeout for serial port write +DEFAULT_CONNECT_ATTEMPTS = 7 # default number of times to try connection + + +def timeout_per_mb(seconds_per_mb, size_bytes): + """ Scales timeouts which are size-specific """ + result = seconds_per_mb * (size_bytes / 1e6) + if result < DEFAULT_TIMEOUT: + return DEFAULT_TIMEOUT + return result + + +def _chip_to_rom_loader(chip): + return { + 'esp8266': ESP8266ROM, + 'esp32': ESP32ROM, + 'esp32s2': ESP32S2ROM, + 'esp32s3beta2': ESP32S3BETA2ROM, + 'esp32s3beta3': ESP32S3BETA3ROM, + 'esp32c3': ESP32C3ROM, + }[chip] + + +def get_default_connected_device(serial_list, port, connect_attempts, initial_baud, chip='auto', trace=False, + before='default_reset'): + _esp = None + for each_port in reversed(serial_list): + print("Serial port %s" % each_port) + try: + if chip == 'auto': + _esp = ESPLoader.detect_chip(each_port, initial_baud, before, trace, + connect_attempts) + else: + chip_class = _chip_to_rom_loader(chip) + _esp = chip_class(each_port, initial_baud, trace) + _esp.connect(before, connect_attempts) + break + except (FatalError, OSError) as err: + if port is not None: + raise + print("%s failed to connect: %s" % (each_port, err)) + _esp = None + return _esp + + +DETECTED_FLASH_SIZES = {0x12: '256KB', 0x13: '512KB', 0x14: '1MB', + 0x15: '2MB', 0x16: '4MB', 0x17: '8MB', 0x18: '16MB'} + + +def check_supported_function(func, check_func): + """ + Decorator implementation that wraps a check around an ESPLoader + bootloader function to check if it's supported. + + This is used to capture the multidimensional differences in + functionality between the ESP8266 & ESP32/32S2/32S3/32C3 ROM loaders, and the + software stub that runs on both. Not possible to do this cleanly + via inheritance alone. + """ + def inner(*args, **kwargs): + obj = args[0] + if check_func(obj): + return func(*args, **kwargs) + else: + raise NotImplementedInROMError(obj, func) + return inner + + +def stub_function_only(func): + """ Attribute for a function only supported in the software stub loader """ + return check_supported_function(func, lambda o: o.IS_STUB) + + +def stub_and_esp32_function_only(func): + """ Attribute for a function only supported by software stubs or ESP32/32S2/32S3/32C3 ROM """ + return check_supported_function(func, lambda o: o.IS_STUB or isinstance(o, ESP32ROM)) + + +PYTHON2 = sys.version_info[0] < 3 # True if on pre-Python 3 + +# Function to return nth byte of a bitstring +# Different behaviour on Python 2 vs 3 +if PYTHON2: + def byte(bitstr, index): + return ord(bitstr[index]) +else: + def byte(bitstr, index): + return bitstr[index] + +# Provide a 'basestring' class on Python 3 +try: + basestring +except NameError: + basestring = str + + +def print_overwrite(message, last_line=False): + """ Print a message, overwriting the currently printed line. + + If last_line is False, don't append a newline at the end (expecting another subsequent call will overwrite this one.) + + After a sequence of calls with last_line=False, call once with last_line=True. + + If output is not a TTY (for example redirected a pipe), no overwriting happens and this function is the same as print(). + """ + if sys.stdout.isatty(): + print("\r%s" % message, end='\n' if last_line else '') + else: + print(message) + + +def _mask_to_shift(mask): + """ Return the index of the least significant bit in the mask """ + shift = 0 + while mask & 0x1 == 0: + shift += 1 + mask >>= 1 + return shift + + +def esp8266_function_only(func): + """ Attribute for a function only supported on ESP8266 """ + return check_supported_function(func, lambda o: o.CHIP_NAME == "ESP8266") + + +class ESPLoader(object): + """ Base class providing access to ESP ROM & software stub bootloaders. + Subclasses provide ESP8266 & ESP32 specific functionality. + + Don't instantiate this base class directly, either instantiate a subclass or + call ESPLoader.detect_chip() which will interrogate the chip and return the + appropriate subclass instance. + + """ + CHIP_NAME = "Espressif device" + IS_STUB = False + + DEFAULT_PORT = "/dev/ttyUSB0" + + # Commands supported by ESP8266 ROM bootloader + ESP_FLASH_BEGIN = 0x02 + ESP_FLASH_DATA = 0x03 + ESP_FLASH_END = 0x04 + ESP_MEM_BEGIN = 0x05 + ESP_MEM_END = 0x06 + ESP_MEM_DATA = 0x07 + ESP_SYNC = 0x08 + ESP_WRITE_REG = 0x09 + ESP_READ_REG = 0x0a + + # Some comands supported by ESP32 ROM bootloader (or -8266 w/ stub) + ESP_SPI_SET_PARAMS = 0x0B + ESP_SPI_ATTACH = 0x0D + ESP_READ_FLASH_SLOW = 0x0e # ROM only, much slower than the stub flash read + ESP_CHANGE_BAUDRATE = 0x0F + ESP_FLASH_DEFL_BEGIN = 0x10 + ESP_FLASH_DEFL_DATA = 0x11 + ESP_FLASH_DEFL_END = 0x12 + ESP_SPI_FLASH_MD5 = 0x13 + + # Commands supported by ESP32-S2/S3/C3 ROM bootloader only + ESP_GET_SECURITY_INFO = 0x14 + + # Some commands supported by stub only + ESP_ERASE_FLASH = 0xD0 + ESP_ERASE_REGION = 0xD1 + ESP_READ_FLASH = 0xD2 + ESP_RUN_USER_CODE = 0xD3 + + # Flash encryption encrypted data command + ESP_FLASH_ENCRYPT_DATA = 0xD4 + + # Response code(s) sent by ROM + ROM_INVALID_RECV_MSG = 0x05 # response if an invalid message is received + + # Maximum block sized for RAM and Flash writes, respectively. + ESP_RAM_BLOCK = 0x1800 + + FLASH_WRITE_SIZE = 0x400 + + # Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want. + ESP_ROM_BAUD = 115200 + + # First byte of the application image + ESP_IMAGE_MAGIC = 0xe9 + + # Initial state for the checksum routine + ESP_CHECKSUM_MAGIC = 0xef + + # Flash sector size, minimum unit of erase. + FLASH_SECTOR_SIZE = 0x1000 + + UART_DATE_REG_ADDR = 0x60000078 + + CHIP_DETECT_MAGIC_REG_ADDR = 0x40001000 # This ROM address has a different value on each chip model + + UART_CLKDIV_MASK = 0xFFFFF + + # Memory addresses + IROM_MAP_START = 0x40200000 + IROM_MAP_END = 0x40300000 + + # The number of bytes in the UART response that signify command status + STATUS_BYTES_LENGTH = 2 + + def __init__(self, port=DEFAULT_PORT, baud=ESP_ROM_BAUD, trace_enabled=False): + """Base constructor for ESPLoader bootloader interaction + + Don't call this constructor, either instantiate ESP8266ROM + or ESP32ROM, or use ESPLoader.detect_chip(). + + This base class has all of the instance methods for bootloader + functionality supported across various chips & stub + loaders. Subclasses replace the functions they don't support + with ones which throw NotImplementedInROMError(). + + """ + self.secure_download_mode = False # flag is set to True if esptool detects the ROM is in Secure Download Mode + + if isinstance(port, basestring): + self._port = serial.serial_for_url(port) + else: + self._port = port + self._slip_reader = slip_reader(self._port, self.trace) + # setting baud rate in a separate step is a workaround for + # CH341 driver on some Linux versions (this opens at 9600 then + # sets), shouldn't matter for other platforms/drivers. See + # https://github.com/espressif/esptool/issues/44#issuecomment-107094446 + self._set_port_baudrate(baud) + self._trace_enabled = trace_enabled + # set write timeout, to prevent esptool blocked at write forever. + try: + self._port.write_timeout = DEFAULT_SERIAL_WRITE_TIMEOUT + except NotImplementedError: + # no write timeout for RFC2217 ports + # need to set the property back to None or it will continue to fail + self._port.write_timeout = None + + @property + def serial_port(self): + return self._port.port + + def _set_port_baudrate(self, baud): + try: + self._port.baudrate = baud + except IOError: + raise FatalError("Failed to set baud rate %d. The driver may not support this rate." % baud) + + @staticmethod + def detect_chip(port=DEFAULT_PORT, baud=ESP_ROM_BAUD, connect_mode='default_reset', trace_enabled=False, + connect_attempts=DEFAULT_CONNECT_ATTEMPTS): + """ Use serial access to detect the chip type. + + We use the UART's datecode register for this, it's mapped at + the same address on ESP8266 & ESP32 so we can use one + memory read and compare to the datecode register for each chip + type. + + This routine automatically performs ESPLoader.connect() (passing + connect_mode parameter) as part of querying the chip. + """ + detect_port = ESPLoader(port, baud, trace_enabled=trace_enabled) + detect_port.connect(connect_mode, connect_attempts, detecting=True) + try: + print('Detecting chip type...', end='') + sys.stdout.flush() + chip_magic_value = detect_port.read_reg(ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR) + + for cls in [ESP8266ROM, ESP32ROM, ESP32S2ROM, ESP32S3BETA2ROM, ESP32S3BETA3ROM, ESP32C3ROM]: + if chip_magic_value == cls.CHIP_DETECT_MAGIC_VALUE: + # don't connect a second time + inst = cls(detect_port._port, baud, trace_enabled=trace_enabled) + inst._post_connect() + print(' %s' % inst.CHIP_NAME, end='') + return inst + except UnsupportedCommandError: + raise FatalError("Unsupported Command Error received. Probably this means Secure Download Mode is enabled, " + "autodetection will not work. Need to manually specify the chip.") + finally: + print('') # end line + raise FatalError("Unexpected CHIP magic value 0x%08x. Failed to autodetect chip type." % (chip_magic_value)) + + """ Read a SLIP packet from the serial port """ + def read(self): + return next(self._slip_reader) + + """ Write bytes to the serial port while performing SLIP escaping """ + def write(self, packet): + buf = b'\xc0' \ + + (packet.replace(b'\xdb', b'\xdb\xdd').replace(b'\xc0', b'\xdb\xdc')) \ + + b'\xc0' + self.trace("Write %d bytes: %s", len(buf), HexFormatter(buf)) + self._port.write(buf) + + def trace(self, message, *format_args): + if self._trace_enabled: + now = time.time() + try: + + delta = now - self._last_trace + except AttributeError: + delta = 0.0 + self._last_trace = now + prefix = "TRACE +%.3f " % delta + print(prefix + (message % format_args)) + + """ Calculate checksum of a blob, as it is defined by the ROM """ + @staticmethod + def checksum(data, state=ESP_CHECKSUM_MAGIC): + for b in data: + if type(b) is int: # python 2/3 compat + state ^= b + else: + state ^= ord(b) + + return state + + """ Send a request and read the response """ + def command(self, op=None, data=b"", chk=0, wait_response=True, timeout=DEFAULT_TIMEOUT): + saved_timeout = self._port.timeout + new_timeout = min(timeout, MAX_TIMEOUT) + if new_timeout != saved_timeout: + self._port.timeout = new_timeout + + try: + if op is not None: + self.trace("command op=0x%02x data len=%s wait_response=%d timeout=%.3f data=%s", + op, len(data), 1 if wait_response else 0, timeout, HexFormatter(data)) + pkt = struct.pack(b' self.STATUS_BYTES_LENGTH: + return data[:-self.STATUS_BYTES_LENGTH] + else: # otherwise, just return the 'val' field which comes from the reply header (this is used by read_reg) + return val + + def flush_input(self): + self._port.flushInput() + self._slip_reader = slip_reader(self._port, self.trace) + + def sync(self): + self.command(self.ESP_SYNC, b'\x07\x07\x12\x20' + 32 * b'\x55', + timeout=SYNC_TIMEOUT) + for i in range(7): + self.command() + + def _setDTR(self, state): + self._port.setDTR(state) + + def _setRTS(self, state): + self._port.setRTS(state) + # Work-around for adapters on Windows using the usbser.sys driver: + # generate a dummy change to DTR so that the set-control-line-state + # request is sent with the updated RTS state and the same DTR state + self._port.setDTR(self._port.dtr) + + def _connect_attempt(self, mode='default_reset', esp32r0_delay=False): + """ A single connection attempt, with esp32r0 workaround options """ + # esp32r0_delay is a workaround for bugs with the most common auto reset + # circuit and Windows, if the EN pin on the dev board does not have + # enough capacitance. + # + # Newer dev boards shouldn't have this problem (higher value capacitor + # on the EN pin), and ESP32 revision 1 can't use this workaround as it + # relies on a silicon bug. + # + # Details: https://github.com/espressif/esptool/issues/136 + last_error = None + + # If we're doing no_sync, we're likely communicating as a pass through + # with an intermediate device to the ESP32 + if mode == "no_reset_no_sync": + return last_error + + # issue reset-to-bootloader: + # RTS = either CH_PD/EN or nRESET (both active low = chip in reset + # DTR = GPIO0 (active low = boot to flasher) + # + # DTR & RTS are active low signals, + # ie True = pin @ 0V, False = pin @ VCC. + if mode != 'no_reset': + self._setDTR(False) # IO0=HIGH + self._setRTS(True) # EN=LOW, chip in reset + time.sleep(0.1) + if esp32r0_delay: + # Some chips are more likely to trigger the esp32r0 + # watchdog reset silicon bug if they're held with EN=LOW + # for a longer period + time.sleep(1.2) + self._setDTR(True) # IO0=LOW + self._setRTS(False) # EN=HIGH, chip out of reset + if esp32r0_delay: + # Sleep longer after reset. + # This workaround only works on revision 0 ESP32 chips, + # it exploits a silicon bug spurious watchdog reset. + time.sleep(0.4) # allow watchdog reset to occur + time.sleep(0.05) + self._setDTR(False) # IO0=HIGH, done + + for _ in range(5): + try: + self.flush_input() + self._port.flushOutput() + self.sync() + return None + except FatalError as e: + if esp32r0_delay: + print('_', end='') + else: + print('.', end='') + sys.stdout.flush() + time.sleep(0.05) + last_error = e + return last_error + + def get_memory_region(self, name): + """ Returns a tuple of (start, end) for the memory map entry with the given name, or None if it doesn't exist + """ + try: + return [(start, end) for (start, end, n) in self.MEMORY_MAP if n == name][0] + except IndexError: + return None + + def connect(self, mode='default_reset', attempts=DEFAULT_CONNECT_ATTEMPTS, detecting=False): + """ Try connecting repeatedly until successful, or giving up """ + print('Connecting...', end='') + sys.stdout.flush() + last_error = None + + try: + for _ in range(attempts) if attempts > 0 else itertools.count(): + last_error = self._connect_attempt(mode=mode, esp32r0_delay=False) + if last_error is None: + break + last_error = self._connect_attempt(mode=mode, esp32r0_delay=True) + if last_error is None: + break + finally: + print('') # end 'Connecting...' line + + if last_error is not None: + raise FatalError('Failed to connect to %s: %s' % (self.CHIP_NAME, last_error)) + + if not detecting: + try: + # check the date code registers match what we expect to see + chip_magic_value = self.read_reg(ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR) + if chip_magic_value != self.CHIP_DETECT_MAGIC_VALUE: + actually = None + for cls in [ESP8266ROM, ESP32ROM, ESP32S2ROM, ESP32S3BETA2ROM, ESP32S3BETA3ROM, ESP32C3ROM]: + if chip_magic_value == cls.CHIP_DETECT_MAGIC_VALUE: + actually = cls + break + if actually is None: + print(("WARNING: This chip doesn't appear to be a %s (chip magic value 0x%08x). " + "Probably it is unsupported by this version of esptool.") % (self.CHIP_NAME, chip_magic_value)) + else: + raise FatalError("This chip is %s not %s. Wrong --chip argument?" % (actually.CHIP_NAME, self.CHIP_NAME)) + except UnsupportedCommandError: + self.secure_download_mode = True + self._post_connect() + + def _post_connect(self): + """ + Additional initialization hook, may be overridden by the chip-specific class. + Gets called after connect, and after auto-detection. + """ + pass + + def read_reg(self, addr, timeout=DEFAULT_TIMEOUT): + """ Read memory address in target """ + # we don't call check_command here because read_reg() function is called + # when detecting chip type, and the way we check for success (STATUS_BYTES_LENGTH) is different + # for different chip types (!) + val, data = self.command(self.ESP_READ_REG, struct.pack(' 0: + # add a dummy write to a date register as an excuse to have a delay + command += struct.pack(' start: + raise FatalError(("Software loader is resident at 0x%08x-0x%08x. " + "Can't load binary at overlapping address range 0x%08x-0x%08x. " + "Either change binary loading address, or use the --no-stub " + "option to disable the software loader.") % (start, end, load_start, load_end)) + + return self.check_command("enter RAM download mode", self.ESP_MEM_BEGIN, + struct.pack(' length: + raise FatalError('Read more than expected') + + digest_frame = self.read() + if len(digest_frame) != 16: + raise FatalError('Expected digest, got: %s' % hexify(digest_frame)) + expected_digest = hexify(digest_frame).upper() + digest = hashlib.md5(data).hexdigest().upper() + if digest != expected_digest: + raise FatalError('Digest mismatch: expected %s, got %s' % (expected_digest, digest)) + return data + + def flash_spi_attach(self, hspi_arg): + """Send SPI attach command to enable the SPI flash pins + + ESP8266 ROM does this when you send flash_begin, ESP32 ROM + has it as a SPI command. + """ + # last 3 bytes in ESP_SPI_ATTACH argument are reserved values + arg = struct.pack(' 0: + self.write_reg(SPI_MOSI_DLEN_REG, mosi_bits - 1) + if miso_bits > 0: + self.write_reg(SPI_MISO_DLEN_REG, miso_bits - 1) + else: + + def set_data_lengths(mosi_bits, miso_bits): + SPI_DATA_LEN_REG = SPI_USR1_REG + SPI_MOSI_BITLEN_S = 17 + SPI_MISO_BITLEN_S = 8 + mosi_mask = 0 if (mosi_bits == 0) else (mosi_bits - 1) + miso_mask = 0 if (miso_bits == 0) else (miso_bits - 1) + self.write_reg(SPI_DATA_LEN_REG, + (miso_mask << SPI_MISO_BITLEN_S) | ( + mosi_mask << SPI_MOSI_BITLEN_S)) + + # SPI peripheral "command" bitmasks for SPI_CMD_REG + SPI_CMD_USR = (1 << 18) + + # shift values + SPI_USR2_COMMAND_LEN_SHIFT = 28 + + if read_bits > 32: + raise FatalError("Reading more than 32 bits back from a SPI flash operation is unsupported") + if len(data) > 64: + raise FatalError("Writing more than 64 bytes of data with one SPI command is unsupported") + + data_bits = len(data) * 8 + old_spi_usr = self.read_reg(SPI_USR_REG) + old_spi_usr2 = self.read_reg(SPI_USR2_REG) + flags = SPI_USR_COMMAND + if read_bits > 0: + flags |= SPI_USR_MISO + if data_bits > 0: + flags |= SPI_USR_MOSI + set_data_lengths(data_bits, read_bits) + self.write_reg(SPI_USR_REG, flags) + self.write_reg(SPI_USR2_REG, + (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflash_command) + if data_bits == 0: + self.write_reg(SPI_W0_REG, 0) # clear data register before we read it + else: + data = pad_to(data, 4, b'\00') # pad to 32-bit multiple + words = struct.unpack("I" * (len(data) // 4), data) + next_reg = SPI_W0_REG + for word in words: + self.write_reg(next_reg, word) + next_reg += 4 + self.write_reg(SPI_CMD_REG, SPI_CMD_USR) + + def wait_done(): + for _ in range(10): + if (self.read_reg(SPI_CMD_REG) & SPI_CMD_USR) == 0: + return + raise FatalError("SPI command did not complete in time") + wait_done() + + status = self.read_reg(SPI_W0_REG) + # restore some SPI controller registers + self.write_reg(SPI_USR_REG, old_spi_usr) + self.write_reg(SPI_USR2_REG, old_spi_usr2) + return status + + def read_status(self, num_bytes=2): + """Read up to 24 bits (num_bytes) of SPI flash status register contents + via RDSR, RDSR2, RDSR3 commands + + Not all SPI flash supports all three commands. The upper 1 or 2 + bytes may be 0xFF. + """ + SPIFLASH_RDSR = 0x05 + SPIFLASH_RDSR2 = 0x35 + SPIFLASH_RDSR3 = 0x15 + + status = 0 + shift = 0 + for cmd in [SPIFLASH_RDSR, SPIFLASH_RDSR2, SPIFLASH_RDSR3][0:num_bytes]: + status += self.run_spiflash_command(cmd, read_bits=8) << shift + shift += 8 + return status + + def write_status(self, new_status, num_bytes=2, set_non_volatile=False): + """Write up to 24 bits (num_bytes) of new status register + + num_bytes can be 1, 2 or 3. + + Not all flash supports the additional commands to write the + second and third byte of the status register. When writing 2 + bytes, esptool also sends a 16-byte WRSR command (as some + flash types use this instead of WRSR2.) + + If the set_non_volatile flag is set, non-volatile bits will + be set as well as volatile ones (WREN used instead of WEVSR). + + """ + SPIFLASH_WRSR = 0x01 + SPIFLASH_WRSR2 = 0x31 + SPIFLASH_WRSR3 = 0x11 + SPIFLASH_WEVSR = 0x50 + SPIFLASH_WREN = 0x06 + SPIFLASH_WRDI = 0x04 + + enable_cmd = SPIFLASH_WREN if set_non_volatile else SPIFLASH_WEVSR + + # try using a 16-bit WRSR (not supported by all chips) + # this may be redundant, but shouldn't hurt + if num_bytes == 2: + self.run_spiflash_command(enable_cmd) + self.run_spiflash_command(SPIFLASH_WRSR, struct.pack(">= 8 + + self.run_spiflash_command(SPIFLASH_WRDI) + + def get_crystal_freq(self): + # Figure out the crystal frequency from the UART clock divider + # Returns a normalized value in integer MHz (40 or 26 are the only supported values) + # + # The logic here is: + # - We know that our baud rate and the ESP UART baud rate are roughly the same, or we couldn't communicate + # - We can read the UART clock divider register to know how the ESP derives this from the APB bus frequency + # - Multiplying these two together gives us the bus frequency which is either the crystal frequency (ESP32) + # or double the crystal frequency (ESP8266). See the self.XTAL_CLK_DIVIDER parameter for this factor. + uart_div = self.read_reg(self.UART_CLKDIV_REG) & self.UART_CLKDIV_MASK + est_xtal = (self._port.baudrate * uart_div) / 1e6 / self.XTAL_CLK_DIVIDER + norm_xtal = 40 if est_xtal > 33 else 26 + if abs(norm_xtal - est_xtal) > 1: + print("WARNING: Detected crystal freq %.2fMHz is quite different to normalized freq %dMHz. Unsupported crystal in use?" % (est_xtal, norm_xtal)) + return norm_xtal + + def hard_reset(self): + self._setRTS(True) # EN->LOW + time.sleep(0.1) + self._setRTS(False) + + def soft_reset(self, stay_in_bootloader): + if not self.IS_STUB: + if stay_in_bootloader: + return # ROM bootloader is already in bootloader! + else: + # 'run user code' is as close to a soft reset as we can do + self.flash_begin(0, 0) + self.flash_finish(False) + else: + if stay_in_bootloader: + # soft resetting from the stub loader + # will re-load the ROM bootloader + self.flash_begin(0, 0) + self.flash_finish(True) + elif self.CHIP_NAME != "ESP8266": + raise FatalError("Soft resetting is currently only supported on ESP8266") + else: + # running user code from stub loader requires some hacks + # in the stub loader + self.command(self.ESP_RUN_USER_CODE, wait_response=False) + + +class ESP8266ROM(ESPLoader): + """ Access class for ESP8266 ROM bootloader + """ + CHIP_NAME = "ESP8266" + IS_STUB = False + + CHIP_DETECT_MAGIC_VALUE = 0xfff0c101 + + # OTP ROM addresses + ESP_OTP_MAC0 = 0x3ff00050 + ESP_OTP_MAC1 = 0x3ff00054 + ESP_OTP_MAC3 = 0x3ff0005c + + SPI_REG_BASE = 0x60000200 + SPI_USR_OFFS = 0x1c + SPI_USR1_OFFS = 0x20 + SPI_USR2_OFFS = 0x24 + SPI_MOSI_DLEN_OFFS = None + SPI_MISO_DLEN_OFFS = None + SPI_W0_OFFS = 0x40 + + UART_CLKDIV_REG = 0x60000014 + + XTAL_CLK_DIVIDER = 2 + + FLASH_SIZES = { + '512KB': 0x00, + '256KB': 0x10, + '1MB': 0x20, + '2MB': 0x30, + '4MB': 0x40, + '2MB-c1': 0x50, + '4MB-c1': 0x60, + '8MB': 0x80, + '16MB': 0x90, + } + + BOOTLOADER_FLASH_OFFSET = 0 + + MEMORY_MAP = [[0x3FF00000, 0x3FF00010, "DPORT"], + [0x3FFE8000, 0x40000000, "DRAM"], + [0x40100000, 0x40108000, "IRAM"], + [0x40201010, 0x402E1010, "IROM"]] + + def get_efuses(self): + # Return the 128 bits of ESP8266 efuse as a single Python integer + result = self.read_reg(0x3ff0005c) << 96 + result |= self.read_reg(0x3ff00058) << 64 + result |= self.read_reg(0x3ff00054) << 32 + result |= self.read_reg(0x3ff00050) + return result + + def _get_flash_size(self, efuses): + # rX_Y = EFUSE_DATA_OUTX[Y] + r0_4 = (efuses & (1 << 4)) != 0 + r3_25 = (efuses & (1 << 121)) != 0 + r3_26 = (efuses & (1 << 122)) != 0 + r3_27 = (efuses & (1 << 123)) != 0 + + if r0_4 and not r3_25: + if not r3_27 and not r3_26: + return 1 + elif not r3_27 and r3_26: + return 2 + if not r0_4 and r3_25: + if not r3_27 and not r3_26: + return 2 + elif not r3_27 and r3_26: + return 4 + return -1 + + def get_chip_description(self): + efuses = self.get_efuses() + is_8285 = (efuses & ((1 << 4) | 1 << 80)) != 0 # One or the other efuse bit is set for ESP8285 + if is_8285: + flash_size = self._get_flash_size(efuses) + max_temp = (efuses & (1 << 5)) != 0 # This efuse bit identifies the max flash temperature + chip_name = { + 1: "ESP8285H08" if max_temp else "ESP8285N08", + 2: "ESP8285H16" if max_temp else "ESP8285N16" + }.get(flash_size, "ESP8285") + return chip_name + return "ESP8266EX" + + def get_chip_features(self): + features = ["WiFi"] + if "ESP8285" in self.get_chip_description(): + features += ["Embedded Flash"] + return features + + def flash_spi_attach(self, hspi_arg): + if self.IS_STUB: + super(ESP8266ROM, self).flash_spi_attach(hspi_arg) + else: + # ESP8266 ROM has no flash_spi_attach command in serial protocol, + # but flash_begin will do it + self.flash_begin(0, 0) + + def flash_set_parameters(self, size): + # not implemented in ROM, but OK to silently skip for ROM + if self.IS_STUB: + super(ESP8266ROM, self).flash_set_parameters(size) + + def chip_id(self): + """ Read Chip ID from efuse - the equivalent of the SDK system_get_chip_id() function """ + id0 = self.read_reg(self.ESP_OTP_MAC0) + id1 = self.read_reg(self.ESP_OTP_MAC1) + return (id0 >> 24) | ((id1 & MAX_UINT24) << 8) + + def read_mac(self): + """ Read MAC from OTP ROM """ + mac0 = self.read_reg(self.ESP_OTP_MAC0) + mac1 = self.read_reg(self.ESP_OTP_MAC1) + mac3 = self.read_reg(self.ESP_OTP_MAC3) + if (mac3 != 0): + oui = ((mac3 >> 16) & 0xff, (mac3 >> 8) & 0xff, mac3 & 0xff) + elif ((mac1 >> 16) & 0xff) == 0: + oui = (0x18, 0xfe, 0x34) + elif ((mac1 >> 16) & 0xff) == 1: + oui = (0xac, 0xd0, 0x74) + else: + raise FatalError("Unknown OUI") + return oui + ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff) + + def get_erase_size(self, offset, size): + """ Calculate an erase size given a specific size in bytes. + + Provides a workaround for the bootloader erase bug.""" + + sectors_per_block = 16 + sector_size = self.FLASH_SECTOR_SIZE + num_sectors = (size + sector_size - 1) // sector_size + start_sector = offset // sector_size + + head_sectors = sectors_per_block - (start_sector % sectors_per_block) + if num_sectors < head_sectors: + head_sectors = num_sectors + + if num_sectors < 2 * head_sectors: + return (num_sectors + 1) // 2 * sector_size + else: + return (num_sectors - head_sectors) * sector_size + + def override_vddsdio(self, new_voltage): + raise NotImplementedInROMError("Overriding VDDSDIO setting only applies to ESP32") + + +class ESP8266StubLoader(ESP8266ROM): + """ Access class for ESP8266 stub loader, runs on top of ROM. + """ + FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c + IS_STUB = True + + def __init__(self, rom_loader): + self.secure_download_mode = rom_loader.secure_download_mode + self._port = rom_loader._port + self._trace_enabled = rom_loader._trace_enabled + self.flush_input() # resets _slip_reader + + def get_erase_size(self, offset, size): + return size # stub doesn't have same size bug as ROM loader + + +ESP8266ROM.STUB_CLASS = ESP8266StubLoader + + +class ESP32ROM(ESPLoader): + """Access class for ESP32 ROM bootloader + + """ + CHIP_NAME = "ESP32" + IMAGE_CHIP_ID = 0 + IS_STUB = False + + CHIP_DETECT_MAGIC_VALUE = 0x00f01d83 + + IROM_MAP_START = 0x400d0000 + IROM_MAP_END = 0x40400000 + + DROM_MAP_START = 0x3F400000 + DROM_MAP_END = 0x3F800000 + + # ESP32 uses a 4 byte status reply + STATUS_BYTES_LENGTH = 4 + + SPI_REG_BASE = 0x3ff42000 + SPI_USR_OFFS = 0x1c + SPI_USR1_OFFS = 0x20 + SPI_USR2_OFFS = 0x24 + SPI_MOSI_DLEN_OFFS = 0x28 + SPI_MISO_DLEN_OFFS = 0x2c + EFUSE_RD_REG_BASE = 0x3ff5a000 + + EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE + 0x18 + EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = (1 << 7) # EFUSE_RD_DISABLE_DL_ENCRYPT + + DR_REG_SYSCON_BASE = 0x3ff66000 + + SPI_W0_OFFS = 0x80 + + UART_CLKDIV_REG = 0x3ff40014 + + XTAL_CLK_DIVIDER = 1 + + FLASH_SIZES = { + '1MB': 0x00, + '2MB': 0x10, + '4MB': 0x20, + '8MB': 0x30, + '16MB': 0x40 + } + + BOOTLOADER_FLASH_OFFSET = 0x1000 + + OVERRIDE_VDDSDIO_CHOICES = ["1.8V", "1.9V", "OFF"] + + MEMORY_MAP = [[0x00000000, 0x00010000, "PADDING"], + [0x3F400000, 0x3F800000, "DROM"], + [0x3F800000, 0x3FC00000, "EXTRAM_DATA"], + [0x3FF80000, 0x3FF82000, "RTC_DRAM"], + [0x3FF90000, 0x40000000, "BYTE_ACCESSIBLE"], + [0x3FFAE000, 0x40000000, "DRAM"], + [0x3FFE0000, 0x3FFFFFFC, "DIRAM_DRAM"], + [0x40000000, 0x40070000, "IROM"], + [0x40070000, 0x40078000, "CACHE_PRO"], + [0x40078000, 0x40080000, "CACHE_APP"], + [0x40080000, 0x400A0000, "IRAM"], + [0x400A0000, 0x400BFFFC, "DIRAM_IRAM"], + [0x400C0000, 0x400C2000, "RTC_IRAM"], + [0x400D0000, 0x40400000, "IROM"], + [0x50000000, 0x50002000, "RTC_DATA"]] + + FLASH_ENCRYPTED_WRITE_ALIGN = 32 + + """ Try to read the BLOCK1 (encryption key) and check if it is valid """ + + def is_flash_encryption_key_valid(self): + + """ Bit 0 of efuse_rd_disable[3:0] is mapped to BLOCK1 + this bit is at position 16 in EFUSE_BLK0_RDATA0_REG """ + word0 = self.read_efuse(0) + rd_disable = (word0 >> 16) & 0x1 + + # reading of BLOCK1 is NOT ALLOWED so we assume valid key is programmed + if rd_disable: + return True + else: + # reading of BLOCK1 is ALLOWED so we will read and verify for non-zero. + # When ESP32 has not generated AES/encryption key in BLOCK1, the contents will be readable and 0. + # If the flash encryption is enabled it is expected to have a valid non-zero key. We break out on + # first occurance of non-zero value + key_word = [0] * 7 + for i in range(len(key_word)): + key_word[i] = self.read_efuse(14 + i) + # key is non-zero so break & return + if key_word[i] != 0: + return True + return False + + def get_flash_crypt_config(self): + """ For flash encryption related commands we need to make sure + user has programmed all the relevant efuse correctly so before + writing encrypted write_flash_encrypt esptool will verify the values + of flash_crypt_config to be non zero if they are not read + protected. If the values are zero a warning will be printed + + bit 3 in efuse_rd_disable[3:0] is mapped to flash_crypt_config + this bit is at position 19 in EFUSE_BLK0_RDATA0_REG """ + word0 = self.read_efuse(0) + rd_disable = (word0 >> 19) & 0x1 + + if rd_disable == 0: + """ we can read the flash_crypt_config efuse value + so go & read it (EFUSE_BLK0_RDATA5_REG[31:28]) """ + word5 = self.read_efuse(5) + word5 = (word5 >> 28) & 0xF + return word5 + else: + # if read of the efuse is disabled we assume it is set correctly + return 0xF + + def get_encrypted_download_disabled(self): + if self.read_reg(self.EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG) & self.EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT: + return True + else: + return False + + def get_pkg_version(self): + word3 = self.read_efuse(3) + pkg_version = (word3 >> 9) & 0x07 + pkg_version += ((word3 >> 2) & 0x1) << 3 + return pkg_version + + def get_chip_revision(self): + word3 = self.read_efuse(3) + word5 = self.read_efuse(5) + apb_ctl_date = self.read_reg(self.DR_REG_SYSCON_BASE + 0x7C) + + rev_bit0 = (word3 >> 15) & 0x1 + rev_bit1 = (word5 >> 20) & 0x1 + rev_bit2 = (apb_ctl_date >> 31) & 0x1 + if rev_bit0: + if rev_bit1: + if rev_bit2: + return 3 + else: + return 2 + else: + return 1 + return 0 + + def get_chip_description(self): + pkg_version = self.get_pkg_version() + chip_revision = self.get_chip_revision() + rev3 = (chip_revision == 3) + single_core = self.read_efuse(3) & (1 << 0) # CHIP_VER DIS_APP_CPU + + chip_name = { + 0: "ESP32-S0WDQ6" if single_core else "ESP32-D0WDQ6", + 1: "ESP32-S0WD" if single_core else "ESP32-D0WD", + 2: "ESP32-D2WD", + 4: "ESP32-U4WDH", + 5: "ESP32-PICO-V3" if rev3 else "ESP32-PICO-D4", + 6: "ESP32-PICO-V3-02", + }.get(pkg_version, "unknown ESP32") + + # ESP32-D0WD-V3, ESP32-D0WDQ6-V3 + if chip_name.startswith("ESP32-D0WD") and rev3: + chip_name += "-V3" + + return "%s (revision %d)" % (chip_name, chip_revision) + + def get_chip_features(self): + features = ["WiFi"] + word3 = self.read_efuse(3) + + # names of variables in this section are lowercase + # versions of EFUSE names as documented in TRM and + # ESP-IDF efuse_reg.h + + chip_ver_dis_bt = word3 & (1 << 1) + if chip_ver_dis_bt == 0: + features += ["BT"] + + chip_ver_dis_app_cpu = word3 & (1 << 0) + if chip_ver_dis_app_cpu: + features += ["Single Core"] + else: + features += ["Dual Core"] + + chip_cpu_freq_rated = word3 & (1 << 13) + if chip_cpu_freq_rated: + chip_cpu_freq_low = word3 & (1 << 12) + if chip_cpu_freq_low: + features += ["160MHz"] + else: + features += ["240MHz"] + + pkg_version = self.get_pkg_version() + if pkg_version in [2, 4, 5, 6]: + features += ["Embedded Flash"] + + if pkg_version == 6: + features += ["Embedded PSRAM"] + + word4 = self.read_efuse(4) + adc_vref = (word4 >> 8) & 0x1F + if adc_vref: + features += ["VRef calibration in efuse"] + + blk3_part_res = word3 >> 14 & 0x1 + if blk3_part_res: + features += ["BLK3 partially reserved"] + + word6 = self.read_efuse(6) + coding_scheme = word6 & 0x3 + features += ["Coding Scheme %s" % { + 0: "None", + 1: "3/4", + 2: "Repeat (UNSUPPORTED)", + 3: "Invalid"}[coding_scheme]] + + return features + + def read_efuse(self, n): + """ Read the nth word of the ESP3x EFUSE region. """ + return self.read_reg(self.EFUSE_RD_REG_BASE + (4 * n)) + + def chip_id(self): + raise NotSupportedError(self, "chip_id") + + def read_mac(self): + """ Read MAC from EFUSE region """ + words = [self.read_efuse(2), self.read_efuse(1)] + bitstring = struct.pack(">II", *words) + bitstring = bitstring[2:8] # trim the 2 byte CRC + try: + return tuple(ord(b) for b in bitstring) + except TypeError: # Python 3, bitstring elements are already bytes + return tuple(bitstring) + + def get_erase_size(self, offset, size): + return size + + def override_vddsdio(self, new_voltage): + new_voltage = new_voltage.upper() + if new_voltage not in self.OVERRIDE_VDDSDIO_CHOICES: + raise FatalError("The only accepted VDDSDIO overrides are '1.8V', '1.9V' and 'OFF'") + RTC_CNTL_SDIO_CONF_REG = 0x3ff48074 + RTC_CNTL_XPD_SDIO_REG = (1 << 31) + RTC_CNTL_DREFH_SDIO_M = (3 << 29) + RTC_CNTL_DREFM_SDIO_M = (3 << 27) + RTC_CNTL_DREFL_SDIO_M = (3 << 25) + # RTC_CNTL_SDIO_TIEH = (1 << 23) # not used here, setting TIEH=1 would set 3.3V output, not safe for esptool.py to do + RTC_CNTL_SDIO_FORCE = (1 << 22) + RTC_CNTL_SDIO_PD_EN = (1 << 21) + + reg_val = RTC_CNTL_SDIO_FORCE # override efuse setting + reg_val |= RTC_CNTL_SDIO_PD_EN + if new_voltage != "OFF": + reg_val |= RTC_CNTL_XPD_SDIO_REG # enable internal LDO + if new_voltage == "1.9V": + reg_val |= (RTC_CNTL_DREFH_SDIO_M | RTC_CNTL_DREFM_SDIO_M | RTC_CNTL_DREFL_SDIO_M) # boost voltage + self.write_reg(RTC_CNTL_SDIO_CONF_REG, reg_val) + print("VDDSDIO regulator set to %s" % new_voltage) + + def read_flash_slow(self, offset, length, progress_fn): + BLOCK_LEN = 64 # ROM read limit per command (this limit is why it's so slow) + + data = b'' + while len(data) < length: + block_len = min(BLOCK_LEN, length - len(data)) + r = self.check_command("read flash block", self.ESP_READ_FLASH_SLOW, + struct.pack('> 21) & 0x0F + return pkg_version + + def get_chip_description(self): + chip_name = { + 0: "ESP32-S2", + 1: "ESP32-S2FH16", + 2: "ESP32-S2FH32", + }.get(self.get_pkg_version(), "unknown ESP32-S2") + + return "%s" % (chip_name) + + def get_chip_features(self): + features = ["WiFi"] + + if self.secure_download_mode: + features += ["Secure Download Mode Enabled"] + + pkg_version = self.get_pkg_version() + + if pkg_version in [1, 2]: + if pkg_version == 1: + features += ["Embedded 2MB Flash"] + elif pkg_version == 2: + features += ["Embedded 4MB Flash"] + features += ["105C temp rating"] + + num_word = 4 + block2_addr = self.EFUSE_BASE + 0x05C + word4 = self.read_reg(block2_addr + (4 * num_word)) + block2_version = (word4 >> 4) & 0x07 + + if block2_version == 1: + features += ["ADC and temperature sensor calibration in BLK2 of efuse"] + return features + + def get_crystal_freq(self): + # ESP32-S2 XTAL is fixed to 40MHz + return 40 + + def override_vddsdio(self, new_voltage): + raise NotImplementedInROMError("VDD_SDIO overrides are not supported for ESP32-S2") + + def read_mac(self): + mac0 = self.read_reg(self.MAC_EFUSE_REG) + mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC + bitstring = struct.pack(">II", mac1, mac0)[2:] + try: + return tuple(ord(b) for b in bitstring) + except TypeError: # Python 3, bitstring elements are already bytes + return tuple(bitstring) + + def get_flash_crypt_config(self): + return None # doesn't exist on ESP32-S2 + + def get_key_block_purpose(self, key_block): + if key_block < 0 or key_block > 5: + raise FatalError("Valid key block numbers must be in range 0-5") + + reg, shift = [(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT), + (self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT), + (self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT), + (self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT), + (self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT), + (self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT)][key_block] + return (self.read_reg(reg) >> shift) & 0xF + + def is_flash_encryption_key_valid(self): + # Need to see either an AES-128 key or two AES-256 keys + purposes = [self.get_key_block_purpose(b) for b in range(6)] + + if any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes): + return True + + return any(p == self.PURPOSE_VAL_XTS_AES256_KEY_1 for p in purposes) \ + and any(p == self.PURPOSE_VAL_XTS_AES256_KEY_2 for p in purposes) + + def uses_usb(self, _cache=[]): + if self.secure_download_mode: + return False # can't detect native USB in secure download mode + if not _cache: + buf_no = self.read_reg(self.UARTDEV_BUF_NO) & 0xff + _cache.append(buf_no == self.UARTDEV_BUF_NO_USB) + return _cache[0] + + def _post_connect(self): + if self.uses_usb(): + self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK + + def _check_if_can_reset(self): + """ + Check the strapping register to see if we can reset out of download mode. + """ + if os.getenv("ESPTOOL_TESTING") is not None: + print("ESPTOOL_TESTING is set, ignoring strapping mode check") + # Esptool tests over USB CDC run with GPIO0 strapped low, don't complain in this case. + return + strap_reg = self.read_reg(self.GPIO_STRAP_REG) + force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG) + if strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0 and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0: + print("ERROR: {} chip was placed into download mode using GPIO0.\n" + "esptool.py can not exit the download mode over USB. " + "To run the app, reset the chip manually.\n" + "To suppress this error, set --after option to 'no_reset'.".format(self.get_chip_description())) + raise SystemExit(1) + + def hard_reset(self): + if self.uses_usb(): + self._check_if_can_reset() + + self._setRTS(True) # EN->LOW + if self.uses_usb(): + # Give the chip some time to come out of reset, to be able to handle further DTR/RTS transitions + time.sleep(0.2) + self._setRTS(False) + time.sleep(0.2) + else: + self._setRTS(False) + + +class ESP32S3BETA2ROM(ESP32ROM): + CHIP_NAME = "ESP32-S3(beta2)" + IMAGE_CHIP_ID = 4 + + IROM_MAP_START = 0x42000000 + IROM_MAP_END = 0x44000000 + DROM_MAP_START = 0x3c000000 + DROM_MAP_END = 0x3e000000 + + UART_DATE_REG_ADDR = 0x60000080 + + CHIP_DETECT_MAGIC_VALUE = 0xeb004136 + + SPI_REG_BASE = 0x60002000 + SPI_USR_OFFS = 0x18 + SPI_USR1_OFFS = 0x1c + SPI_USR2_OFFS = 0x20 + SPI_MOSI_DLEN_OFFS = 0x24 + SPI_MISO_DLEN_OFFS = 0x28 + SPI_W0_OFFS = 0x58 + + EFUSE_REG_BASE = 0x6001A030 # BLOCK0 read base address + + MAC_EFUSE_REG = 0x6001A000 # ESP32S3 has special block for MAC efuses + + UART_CLKDIV_REG = 0x60000014 + + GPIO_STRAP_REG = 0x60004038 + + MEMORY_MAP = [[0x00000000, 0x00010000, "PADDING"], + [0x3C000000, 0x3D000000, "DROM"], + [0x3D000000, 0x3E000000, "EXTRAM_DATA"], + [0x600FE000, 0x60100000, "RTC_DRAM"], + [0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"], + [0x3FC88000, 0x403E2000, "MEM_INTERNAL"], + [0x3FC88000, 0x3FD00000, "DRAM"], + [0x40000000, 0x4001A100, "IROM_MASK"], + [0x40370000, 0x403E0000, "IRAM"], + [0x600FE000, 0x60100000, "RTC_IRAM"], + [0x42000000, 0x42800000, "IROM"], + [0x50000000, 0x50002000, "RTC_DATA"]] + + def get_chip_description(self): + return "ESP32-S3(beta2)" + + def get_chip_features(self): + return ["WiFi", "BLE"] + + def get_crystal_freq(self): + # ESP32S3 XTAL is fixed to 40MHz + return 40 + + def override_vddsdio(self, new_voltage): + raise NotImplementedInROMError("VDD_SDIO overrides are not supported for ESP32-S3") + + def read_mac(self): + mac0 = self.read_reg(self.MAC_EFUSE_REG) + mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC + bitstring = struct.pack(">II", mac1, mac0)[2:] + try: + return tuple(ord(b) for b in bitstring) + except TypeError: # Python 3, bitstring elements are already bytes + return tuple(bitstring) + + +class ESP32S3BETA3ROM(ESP32ROM): + CHIP_NAME = "ESP32-S3(beta3)" + IMAGE_CHIP_ID = 6 + + IROM_MAP_START = 0x42000000 + IROM_MAP_END = 0x44000000 + DROM_MAP_START = 0x3c000000 + DROM_MAP_END = 0x3e000000 + + UART_DATE_REG_ADDR = 0x60000080 + + CHIP_DETECT_MAGIC_VALUE = 0x9 + + SPI_REG_BASE = 0x60002000 + SPI_USR_OFFS = 0x18 + SPI_USR1_OFFS = 0x1c + SPI_USR2_OFFS = 0x20 + SPI_MOSI_DLEN_OFFS = 0x24 + SPI_MISO_DLEN_OFFS = 0x28 + SPI_W0_OFFS = 0x58 + + EFUSE_BASE = 0x6001A000 # BLOCK0 read base address + + MAC_EFUSE_REG = EFUSE_BASE + 0x044 # ESP32S3 has special block for MAC efuses + + UART_CLKDIV_REG = 0x60000014 + + GPIO_STRAP_REG = 0x60004038 + + MEMORY_MAP = [[0x00000000, 0x00010000, "PADDING"], + [0x3C000000, 0x3D000000, "DROM"], + [0x3D000000, 0x3E000000, "EXTRAM_DATA"], + [0x600FE000, 0x60100000, "RTC_DRAM"], + [0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"], + [0x3FC88000, 0x403E2000, "MEM_INTERNAL"], + [0x3FC88000, 0x3FD00000, "DRAM"], + [0x40000000, 0x4001A100, "IROM_MASK"], + [0x40370000, 0x403E0000, "IRAM"], + [0x600FE000, 0x60100000, "RTC_IRAM"], + [0x42000000, 0x42800000, "IROM"], + [0x50000000, 0x50002000, "RTC_DATA"]] + + def get_chip_description(self): + return "ESP32-S3(beta3)" + + def get_chip_features(self): + return ["WiFi", "BLE"] + + def get_crystal_freq(self): + # ESP32S3 XTAL is fixed to 40MHz + return 40 + + def override_vddsdio(self, new_voltage): + raise NotImplementedInROMError("VDD_SDIO overrides are not supported for ESP32-S3") + + def read_mac(self): + mac0 = self.read_reg(self.MAC_EFUSE_REG) + mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC + bitstring = struct.pack(">II", mac1, mac0)[2:] + try: + return tuple(ord(b) for b in bitstring) + except TypeError: # Python 3, bitstring elements are already bytes + return tuple(bitstring) + + +class ESP32C3ROM(ESP32ROM): + CHIP_NAME = "ESP32-C3" + IMAGE_CHIP_ID = 5 + + IROM_MAP_START = 0x42000000 + IROM_MAP_END = 0x42800000 + DROM_MAP_START = 0x3c000000 + DROM_MAP_END = 0x3c800000 + + SPI_REG_BASE = 0x60002000 + SPI_USR_OFFS = 0x18 + SPI_USR1_OFFS = 0x1C + SPI_USR2_OFFS = 0x20 + SPI_MOSI_DLEN_OFFS = 0x24 + SPI_MISO_DLEN_OFFS = 0x28 + SPI_W0_OFFS = 0x58 + + BOOTLOADER_FLASH_OFFSET = 0x0 + + CHIP_DETECT_MAGIC_VALUE = 0x6921506f + + UART_DATE_REG_ADDR = 0x60000000 + 0x7c + + EFUSE_BASE = 0x60008800 + MAC_EFUSE_REG = EFUSE_BASE + 0x044 + + EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address + + EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34 + EFUSE_PURPOSE_KEY0_SHIFT = 24 + EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34 + EFUSE_PURPOSE_KEY1_SHIFT = 28 + EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38 + EFUSE_PURPOSE_KEY2_SHIFT = 0 + EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38 + EFUSE_PURPOSE_KEY3_SHIFT = 4 + EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38 + EFUSE_PURPOSE_KEY4_SHIFT = 8 + EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38 + EFUSE_PURPOSE_KEY5_SHIFT = 12 + + EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE + EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20 + + PURPOSE_VAL_XTS_AES128_KEY = 4 + + GPIO_STRAP_REG = 0x3f404038 + + FLASH_ENCRYPTED_WRITE_ALIGN = 16 + + MEMORY_MAP = [[0x00000000, 0x00010000, "PADDING"], + [0x3C000000, 0x3C800000, "DROM"], + [0x3FC80000, 0x3FCE0000, "DRAM"], + [0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"], + [0x3FF00000, 0x3FF20000, "DROM_MASK"], + [0x40000000, 0x40060000, "IROM_MASK"], + [0x42000000, 0x42800000, "IROM"], + [0x4037C000, 0x403E0000, "IRAM"], + [0x50000000, 0x50002000, "RTC_IRAM"], + [0x50000000, 0x50002000, "RTC_DRAM"], + [0x600FE000, 0x60100000, "MEM_INTERNAL2"]] + + def get_pkg_version(self): + num_word = 3 + block1_addr = self.EFUSE_BASE + 0x044 + word3 = self.read_reg(block1_addr + (4 * num_word)) + pkg_version = (word3 >> 21) & 0x0F + return pkg_version + + def get_chip_revision(self): + # reads WAFER_VERSION field from EFUSE_RD_MAC_SPI_SYS_3_REG + block1_addr = self.EFUSE_BASE + 0x044 + num_word = 3 + pos = 18 + return (self.read_reg(block1_addr + (4 * num_word)) & (0x7 << pos)) >> pos + + def get_chip_description(self): + chip_name = { + 0: "ESP32-C3", + }.get(self.get_pkg_version(), "unknown ESP32-C3") + chip_revision = self.get_chip_revision() + + return "%s (revision %d)" % (chip_name, chip_revision) + + def get_chip_features(self): + return ["Wi-Fi"] + + def get_crystal_freq(self): + # ESP32C3 XTAL is fixed to 40MHz + return 40 + + def override_vddsdio(self, new_voltage): + raise NotImplementedInROMError("VDD_SDIO overrides are not supported for ESP32-C3") + + def read_mac(self): + mac0 = self.read_reg(self.MAC_EFUSE_REG) + mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC + bitstring = struct.pack(">II", mac1, mac0)[2:] + try: + return tuple(ord(b) for b in bitstring) + except TypeError: # Python 3, bitstring elements are already bytes + return tuple(bitstring) + + def get_flash_crypt_config(self): + return None # doesn't exist on ESP32-C3 + + def get_key_block_purpose(self, key_block): + if key_block < 0 or key_block > 5: + raise FatalError("Valid key block numbers must be in range 0-5") + + reg, shift = [(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT), + (self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT), + (self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT), + (self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT), + (self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT), + (self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT)][key_block] + return (self.read_reg(reg) >> shift) & 0xF + + def is_flash_encryption_key_valid(self): + # Need to see an AES-128 key + purposes = [self.get_key_block_purpose(b) for b in range(6)] + + return any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes) + + +class ESP32StubLoader(ESP32ROM): + """ Access class for ESP32 stub loader, runs on top of ROM. + """ + FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c + STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM + IS_STUB = True + + def __init__(self, rom_loader): + self.secure_download_mode = rom_loader.secure_download_mode + self._port = rom_loader._port + self._trace_enabled = rom_loader._trace_enabled + self.flush_input() # resets _slip_reader + + +ESP32ROM.STUB_CLASS = ESP32StubLoader + + +class ESP32S2StubLoader(ESP32S2ROM): + """ Access class for ESP32-S2 stub loader, runs on top of ROM. + + (Basically the same as ESP32StubLoader, but different base class. + Can possibly be made into a mixin.) + """ + FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c + STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM + IS_STUB = True + + def __init__(self, rom_loader): + self.secure_download_mode = rom_loader.secure_download_mode + self._port = rom_loader._port + self._trace_enabled = rom_loader._trace_enabled + self.flush_input() # resets _slip_reader + + if rom_loader.uses_usb(): + self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK + self.FLASH_WRITE_SIZE = self.USB_RAM_BLOCK + + +ESP32S2ROM.STUB_CLASS = ESP32S2StubLoader + + +class ESP32S3BETA2StubLoader(ESP32S3BETA2ROM): + """ Access class for ESP32S3 stub loader, runs on top of ROM. + + (Basically the same as ESP32StubLoader, but different base class. + Can possibly be made into a mixin.) + """ + FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c + STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM + IS_STUB = True + + def __init__(self, rom_loader): + self.secure_download_mode = rom_loader.secure_download_mode + self._port = rom_loader._port + self._trace_enabled = rom_loader._trace_enabled + self.flush_input() # resets _slip_reader + + +ESP32S3BETA2ROM.STUB_CLASS = ESP32S3BETA2StubLoader + + +class ESP32S3BETA3StubLoader(ESP32S3BETA3ROM): + """ Access class for ESP32S3 stub loader, runs on top of ROM. + + (Basically the same as ESP32StubLoader, but different base class. + Can possibly be made into a mixin.) + """ + FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c + STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM + IS_STUB = True + + def __init__(self, rom_loader): + self.secure_download_mode = rom_loader.secure_download_mode + self._port = rom_loader._port + self._trace_enabled = rom_loader._trace_enabled + self.flush_input() # resets _slip_reader + + +ESP32S3BETA3ROM.STUB_CLASS = ESP32S3BETA3StubLoader + + +class ESP32C3StubLoader(ESP32C3ROM): + """ Access class for ESP32C3 stub loader, runs on top of ROM. + + (Basically the same as ESP32StubLoader, but different base class. + Can possibly be made into a mixin.) + """ + FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c + STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM + IS_STUB = True + + def __init__(self, rom_loader): + self.secure_download_mode = rom_loader.secure_download_mode + self._port = rom_loader._port + self._trace_enabled = rom_loader._trace_enabled + self.flush_input() # resets _slip_reader + + +ESP32C3ROM.STUB_CLASS = ESP32C3StubLoader + + +class ESPBOOTLOADER(object): + """ These are constants related to software ESP8266 bootloader, working with 'v2' image files """ + + # First byte of the "v2" application image + IMAGE_V2_MAGIC = 0xea + + # First 'segment' value in a "v2" application image, appears to be a constant version value? + IMAGE_V2_SEGMENT = 4 + + +def LoadFirmwareImage(chip, filename): + """ Load a firmware image. Can be for any supported SoC. + + ESP8266 images will be examined to determine if they are original ROM firmware images (ESP8266ROMFirmwareImage) + or "v2" OTA bootloader images. + + Returns a BaseFirmwareImage subclass, either ESP8266ROMFirmwareImage (v1) or ESP8266V2FirmwareImage (v2). + """ + chip = chip.lower().replace("-", "") + with open(filename, 'rb') as f: + if chip == 'esp32': + return ESP32FirmwareImage(f) + elif chip == "esp32s2": + return ESP32S2FirmwareImage(f) + elif chip == "esp32s3beta2": + return ESP32S3BETA2FirmwareImage(f) + elif chip == "esp32s3beta3": + return ESP32S3BETA3FirmwareImage(f) + elif chip == 'esp32c3': + return ESP32C3FirmwareImage(f) + else: # Otherwise, ESP8266 so look at magic to determine the image type + magic = ord(f.read(1)) + f.seek(0) + if magic == ESPLoader.ESP_IMAGE_MAGIC: + return ESP8266ROMFirmwareImage(f) + elif magic == ESPBOOTLOADER.IMAGE_V2_MAGIC: + return ESP8266V2FirmwareImage(f) + else: + raise FatalError("Invalid image magic number: %d" % magic) + + +class ImageSegment(object): + """ Wrapper class for a segment in an ESP image + (very similar to a section in an ELFImage also) """ + def __init__(self, addr, data, file_offs=None): + self.addr = addr + self.data = data + self.file_offs = file_offs + self.include_in_checksum = True + if self.addr != 0: + self.pad_to_alignment(4) # pad all "real" ImageSegments 4 byte aligned length + + def copy_with_new_addr(self, new_addr): + """ Return a new ImageSegment with same data, but mapped at + a new address. """ + return ImageSegment(new_addr, self.data, 0) + + def split_image(self, split_len): + """ Return a new ImageSegment which splits "split_len" bytes + from the beginning of the data. Remaining bytes are kept in + this segment object (and the start address is adjusted to match.) """ + result = copy.copy(self) + result.data = self.data[:split_len] + self.data = self.data[split_len:] + self.addr += split_len + self.file_offs = None + result.file_offs = None + return result + + def __repr__(self): + r = "len 0x%05x load 0x%08x" % (len(self.data), self.addr) + if self.file_offs is not None: + r += " file_offs 0x%08x" % (self.file_offs) + return r + + def get_memory_type(self, image): + """ + Return a list describing the memory type(s) that is covered by this + segment's start address. + """ + return [map_range[2] for map_range in image.ROM_LOADER.MEMORY_MAP if map_range[0] <= self.addr < map_range[1]] + + def pad_to_alignment(self, alignment): + self.data = pad_to(self.data, alignment, b'\x00') + + +class ELFSection(ImageSegment): + """ Wrapper class for a section in an ELF image, has a section + name as well as the common properties of an ImageSegment. """ + def __init__(self, name, addr, data): + super(ELFSection, self).__init__(addr, data) + self.name = name.decode("utf-8") + + def __repr__(self): + return "%s %s" % (self.name, super(ELFSection, self).__repr__()) + + +class BaseFirmwareImage(object): + SEG_HEADER_LEN = 8 + SHA256_DIGEST_LEN = 32 + + """ Base class with common firmware image functions """ + def __init__(self): + self.segments = [] + self.entrypoint = 0 + self.elf_sha256 = None + self.elf_sha256_offset = 0 + + def load_common_header(self, load_file, expected_magic): + (magic, segments, self.flash_mode, self.flash_size_freq, self.entrypoint) = struct.unpack(' 16: + raise FatalError('Invalid segment count %d (max 16). Usually this indicates a linker script problem.' % len(self.segments)) + + def load_segment(self, f, is_irom_segment=False): + """ Load the next segment from the image file """ + file_offs = f.tell() + (offset, size) = struct.unpack(' 0x40200000 or offset < 0x3ffe0000 or size > 65536: + print('WARNING: Suspicious segment 0x%x, length %d' % (offset, size)) + + def maybe_patch_segment_data(self, f, segment_data): + """If SHA256 digest of the ELF file needs to be inserted into this segment, do so. Returns segment data.""" + segment_len = len(segment_data) + file_pos = f.tell() # file_pos is position in the .bin file + if self.elf_sha256_offset >= file_pos and self.elf_sha256_offset < file_pos + segment_len: + # SHA256 digest needs to be patched into this binary segment, + # calculate offset of the digest inside the binary segment. + patch_offset = self.elf_sha256_offset - file_pos + # Sanity checks + if patch_offset < self.SEG_HEADER_LEN or patch_offset + self.SHA256_DIGEST_LEN > segment_len: + raise FatalError('Cannot place SHA256 digest on segment boundary' + '(elf_sha256_offset=%d, file_pos=%d, segment_size=%d)' % + (self.elf_sha256_offset, file_pos, segment_len)) + # offset relative to the data part + patch_offset -= self.SEG_HEADER_LEN + if segment_data[patch_offset:patch_offset + self.SHA256_DIGEST_LEN] != b'\x00' * self.SHA256_DIGEST_LEN: + raise FatalError('Contents of segment at SHA256 digest offset 0x%x are not all zero. Refusing to overwrite.' % + self.elf_sha256_offset) + assert(len(self.elf_sha256) == self.SHA256_DIGEST_LEN) + segment_data = segment_data[0:patch_offset] + self.elf_sha256 + \ + segment_data[patch_offset + self.SHA256_DIGEST_LEN:] + return segment_data + + def save_segment(self, f, segment, checksum=None): + """ Save the next segment to the image file, return next checksum value if provided """ + segment_data = self.maybe_patch_segment_data(f, segment.data) + f.write(struct.pack(' 0: + if len(irom_segments) != 1: + raise FatalError('Found %d segments that could be irom0. Bad ELF file?' % len(irom_segments)) + return irom_segments[0] + return None + + def get_non_irom_segments(self): + irom_segment = self.get_irom_segment() + return [s for s in self.segments if s != irom_segment] + + def merge_adjacent_segments(self): + if not self.segments: + return # nothing to merge + + segments = [] + # The easiest way to merge the sections is the browse them backward. + for i in range(len(self.segments) - 1, 0, -1): + # elem is the previous section, the one `next_elem` may need to be + # merged in + elem = self.segments[i - 1] + next_elem = self.segments[i] + if all((elem.get_memory_type(self) == next_elem.get_memory_type(self), + elem.include_in_checksum == next_elem.include_in_checksum, + next_elem.addr == elem.addr + len(elem.data))): + # Merge any segment that ends where the next one starts, without spanning memory types + # + # (don't 'pad' any gaps here as they may be excluded from the image due to 'noinit' + # or other reasons.) + elem.data += next_elem.data + else: + # The section next_elem cannot be merged into the previous one, + # which means it needs to be part of the final segments. + # As we are browsing the list backward, the elements need to be + # inserted at the beginning of the final list. + segments.insert(0, next_elem) + + # The first segment will always be here as it cannot be merged into any + # "previous" section. + segments.insert(0, self.segments[0]) + + # note: we could sort segments here as well, but the ordering of segments is sometimes + # important for other reasons (like embedded ELF SHA-256), so we assume that the linker + # script will have produced any adjacent sections in linear order in the ELF, anyhow. + self.segments = segments + + +class ESP8266ROMFirmwareImage(BaseFirmwareImage): + """ 'Version 1' firmware image, segments loaded directly by the ROM bootloader. """ + + ROM_LOADER = ESP8266ROM + + def __init__(self, load_file=None): + super(ESP8266ROMFirmwareImage, self).__init__() + self.flash_mode = 0 + self.flash_size_freq = 0 + self.version = 1 + + if load_file is not None: + segments = self.load_common_header(load_file, ESPLoader.ESP_IMAGE_MAGIC) + + for _ in range(segments): + self.load_segment(load_file) + self.checksum = self.read_checksum(load_file) + + self.verify() + + def default_output_name(self, input_file): + """ Derive a default output name from the ELF name. """ + return input_file + '-' + + def save(self, basename): + """ Save a set of V1 images for flashing. Parameter is a base filename. """ + # IROM data goes in its own plain binary file + irom_segment = self.get_irom_segment() + if irom_segment is not None: + with open("%s0x%05x.bin" % (basename, irom_segment.addr - ESP8266ROM.IROM_MAP_START), "wb") as f: + f.write(irom_segment.data) + + # everything but IROM goes at 0x00000 in an image file + normal_segments = self.get_non_irom_segments() + with open("%s0x00000.bin" % basename, 'wb') as f: + self.write_common_header(f, normal_segments) + checksum = ESPLoader.ESP_CHECKSUM_MAGIC + for segment in normal_segments: + checksum = self.save_segment(f, segment, checksum) + self.append_checksum(f, checksum) + + +ESP8266ROM.BOOTLOADER_IMAGE = ESP8266ROMFirmwareImage + + +class ESP8266V2FirmwareImage(BaseFirmwareImage): + """ 'Version 2' firmware image, segments loaded by software bootloader stub + (ie Espressif bootloader or rboot) + """ + + ROM_LOADER = ESP8266ROM + + def __init__(self, load_file=None): + super(ESP8266V2FirmwareImage, self).__init__() + self.version = 2 + if load_file is not None: + segments = self.load_common_header(load_file, ESPBOOTLOADER.IMAGE_V2_MAGIC) + if segments != ESPBOOTLOADER.IMAGE_V2_SEGMENT: + # segment count is not really segment count here, but we expect to see '4' + print('Warning: V2 header has unexpected "segment" count %d (usually 4)' % segments) + + # irom segment comes before the second header + # + # the file is saved in the image with a zero load address + # in the header, so we need to calculate a load address + irom_segment = self.load_segment(load_file, True) + irom_segment.addr = 0 # for actual mapped addr, add ESP8266ROM.IROM_MAP_START + flashing_addr + 8 + irom_segment.include_in_checksum = False + + first_flash_mode = self.flash_mode + first_flash_size_freq = self.flash_size_freq + first_entrypoint = self.entrypoint + # load the second header + + segments = self.load_common_header(load_file, ESPLoader.ESP_IMAGE_MAGIC) + + if first_flash_mode != self.flash_mode: + print('WARNING: Flash mode value in first header (0x%02x) disagrees with second (0x%02x). Using second value.' + % (first_flash_mode, self.flash_mode)) + if first_flash_size_freq != self.flash_size_freq: + print('WARNING: Flash size/freq value in first header (0x%02x) disagrees with second (0x%02x). Using second value.' + % (first_flash_size_freq, self.flash_size_freq)) + if first_entrypoint != self.entrypoint: + print('WARNING: Entrypoint address in first header (0x%08x) disagrees with second header (0x%08x). Using second value.' + % (first_entrypoint, self.entrypoint)) + + # load all the usual segments + for _ in range(segments): + self.load_segment(load_file) + self.checksum = self.read_checksum(load_file) + + self.verify() + + def default_output_name(self, input_file): + """ Derive a default output name from the ELF name. """ + irom_segment = self.get_irom_segment() + if irom_segment is not None: + irom_offs = irom_segment.addr - ESP8266ROM.IROM_MAP_START + else: + irom_offs = 0 + return "%s-0x%05x.bin" % (os.path.splitext(input_file)[0], + irom_offs & ~(ESPLoader.FLASH_SECTOR_SIZE - 1)) + + def save(self, filename): + with open(filename, 'wb') as f: + # Save first header for irom0 segment + f.write(struct.pack(b' 0: + last_addr = flash_segments[0].addr + for segment in flash_segments[1:]: + if segment.addr // self.IROM_ALIGN == last_addr // self.IROM_ALIGN: + raise FatalError(("Segment loaded at 0x%08x lands in same 64KB flash mapping as segment loaded at 0x%08x. " + "Can't generate binary. Suggest changing linker script or ELF to merge sections.") % + (segment.addr, last_addr)) + last_addr = segment.addr + + def get_alignment_data_needed(segment): + # Actual alignment (in data bytes) required for a segment header: positioned so that + # after we write the next 8 byte header, file_offs % IROM_ALIGN == segment.addr % IROM_ALIGN + # + # (this is because the segment's vaddr may not be IROM_ALIGNed, more likely is aligned + # IROM_ALIGN+0x18 to account for the binary file header + align_past = (segment.addr % self.IROM_ALIGN) - self.SEG_HEADER_LEN + pad_len = (self.IROM_ALIGN - (f.tell() % self.IROM_ALIGN)) + align_past + if pad_len == 0 or pad_len == self.IROM_ALIGN: + return 0 # already aligned + + # subtract SEG_HEADER_LEN a second time, as the padding block has a header as well + pad_len -= self.SEG_HEADER_LEN + if pad_len < 0: + pad_len += self.IROM_ALIGN + return pad_len + + # try to fit each flash segment on a 64kB aligned boundary + # by padding with parts of the non-flash segments... + while len(flash_segments) > 0: + segment = flash_segments[0] + pad_len = get_alignment_data_needed(segment) + if pad_len > 0: # need to pad + if len(ram_segments) > 0 and pad_len > self.SEG_HEADER_LEN: + pad_segment = ram_segments[0].split_image(pad_len) + if len(ram_segments[0].data) == 0: + ram_segments.pop(0) + else: + pad_segment = ImageSegment(0, b'\x00' * pad_len, f.tell()) + checksum = self.save_segment(f, pad_segment, checksum) + total_segments += 1 + else: + # write the flash segment + assert (f.tell() + 8) % self.IROM_ALIGN == segment.addr % self.IROM_ALIGN + checksum = self.save_flash_segment(f, segment, checksum) + flash_segments.pop(0) + total_segments += 1 + + # flash segments all written, so write any remaining RAM segments + for segment in ram_segments: + checksum = self.save_segment(f, segment, checksum) + total_segments += 1 + + if self.secure_pad: + # pad the image so that after signing it will end on a a 64KB boundary. + # This ensures all mapped flash content will be verified. + if not self.append_digest: + raise FatalError("secure_pad only applies if a SHA-256 digest is also appended to the image") + align_past = (f.tell() + self.SEG_HEADER_LEN) % self.IROM_ALIGN + # 16 byte aligned checksum (force the alignment to simplify calculations) + checksum_space = 16 + if self.secure_pad == '1': + # after checksum: SHA-256 digest + (to be added by signing process) version, signature + 12 trailing bytes due to alignment + space_after_checksum = 32 + 4 + 64 + 12 + elif self.secure_pad == '2': # Secure Boot V2 + # after checksum: SHA-256 digest + signature sector, but we place signature sector after the 64KB boundary + space_after_checksum = 32 + pad_len = (self.IROM_ALIGN - align_past - checksum_space - space_after_checksum) % self.IROM_ALIGN + pad_segment = ImageSegment(0, b'\x00' * pad_len, f.tell()) + + checksum = self.save_segment(f, pad_segment, checksum) + total_segments += 1 + + # done writing segments + self.append_checksum(f, checksum) + image_length = f.tell() + + if self.secure_pad: + assert ((image_length + space_after_checksum) % self.IROM_ALIGN) == 0 + + # kinda hacky: go back to the initial header and write the new segment count + # that includes padding segments. This header is not checksummed + f.seek(1) + try: + f.write(chr(total_segments)) + except TypeError: # Python 3 + f.write(bytes([total_segments])) + + if self.append_digest: + # calculate the SHA256 of the whole file and append it + f.seek(0) + digest = hashlib.sha256() + digest.update(f.read(image_length)) + f.write(digest.digest()) + + with open(filename, 'wb') as real_file: + real_file.write(f.getvalue()) + + def save_flash_segment(self, f, segment, checksum=None): + """ Save the next segment to the image file, return next checksum value if provided """ + segment_end_pos = f.tell() + len(segment.data) + self.SEG_HEADER_LEN + segment_len_remainder = segment_end_pos % self.IROM_ALIGN + if segment_len_remainder < 0x24: + # Work around a bug in ESP-IDF 2nd stage bootloader, that it didn't map the + # last MMU page, if an IROM/DROM segment was < 0x24 bytes over the page boundary. + segment.data += b'\x00' * (0x24 - segment_len_remainder) + return self.save_segment(f, segment, checksum) + + def load_extended_header(self, load_file): + def split_byte(n): + return (n & 0x0F, (n >> 4) & 0x0F) + + fields = list(struct.unpack(self.EXTENDED_HEADER_STRUCT_FMT, load_file.read(16))) + + self.wp_pin = fields[0] + + # SPI pin drive stengths are two per byte + self.clk_drv, self.q_drv = split_byte(fields[1]) + self.d_drv, self.cs_drv = split_byte(fields[2]) + self.hd_drv, self.wp_drv = split_byte(fields[3]) + + chip_id = fields[4] + if chip_id != self.ROM_LOADER.IMAGE_CHIP_ID: + print(("Unexpected chip id in image. Expected %d but value was %d. " + "Is this image for a different chip model?") % (self.ROM_LOADER.IMAGE_CHIP_ID, chip_id)) + + # reserved fields in the middle should all be zero + if any(f for f in fields[6:-1] if f != 0): + print("Warning: some reserved header fields have non-zero values. This image may be from a newer esptool.py?") + + append_digest = fields[-1] # last byte is append_digest + if append_digest in [0, 1]: + self.append_digest = (append_digest == 1) + else: + raise RuntimeError("Invalid value for append_digest field (0x%02x). Should be 0 or 1.", append_digest) + + def save_extended_header(self, save_file): + def join_byte(ln, hn): + return (ln & 0x0F) + ((hn & 0x0F) << 4) + + append_digest = 1 if self.append_digest else 0 + + fields = [self.wp_pin, + join_byte(self.clk_drv, self.q_drv), + join_byte(self.d_drv, self.cs_drv), + join_byte(self.hd_drv, self.wp_drv), + self.ROM_LOADER.IMAGE_CHIP_ID, + self.min_rev] + fields += [0] * 8 # padding + fields += [append_digest] + + packed = struct.pack(self.EXTENDED_HEADER_STRUCT_FMT, *fields) + save_file.write(packed) + + +ESP32ROM.BOOTLOADER_IMAGE = ESP32FirmwareImage + + +class ESP32S2FirmwareImage(ESP32FirmwareImage): + """ ESP32S2 Firmware Image almost exactly the same as ESP32FirmwareImage """ + ROM_LOADER = ESP32S2ROM + + +ESP32S2ROM.BOOTLOADER_IMAGE = ESP32S2FirmwareImage + + +class ESP32S3BETA2FirmwareImage(ESP32FirmwareImage): + """ ESP32S3 Firmware Image almost exactly the same as ESP32FirmwareImage """ + ROM_LOADER = ESP32S3BETA2ROM + + +ESP32S3BETA2ROM.BOOTLOADER_IMAGE = ESP32S3BETA2FirmwareImage + + +class ESP32S3BETA3FirmwareImage(ESP32FirmwareImage): + """ ESP32S3 Firmware Image almost exactly the same as ESP32FirmwareImage """ + ROM_LOADER = ESP32S3BETA3ROM + + +ESP32S3BETA3ROM.BOOTLOADER_IMAGE = ESP32S3BETA3FirmwareImage + + +class ESP32C3FirmwareImage(ESP32FirmwareImage): + """ ESP32C3 Firmware Image almost exactly the same as ESP32FirmwareImage """ + ROM_LOADER = ESP32C3ROM + + +ESP32C3ROM.BOOTLOADER_IMAGE = ESP32C3FirmwareImage + + +class ELFFile(object): + SEC_TYPE_PROGBITS = 0x01 + SEC_TYPE_STRTAB = 0x03 + + LEN_SEC_HEADER = 0x28 + + SEG_TYPE_LOAD = 0x01 + LEN_SEG_HEADER = 0x20 + + def __init__(self, name): + # Load sections from the ELF file + self.name = name + with open(self.name, 'rb') as f: + self._read_elf_file(f) + + def get_section(self, section_name): + for s in self.sections: + if s.name == section_name: + return s + raise ValueError("No section %s in ELF file" % section_name) + + def _read_elf_file(self, f): + # read the ELF file header + LEN_FILE_HEADER = 0x34 + try: + (ident, _type, machine, _version, + self.entrypoint, _phoff, shoff, _flags, + _ehsize, _phentsize, _phnum, shentsize, + shnum, shstrndx) = struct.unpack("<16sHHLLLLLHHHHHH", f.read(LEN_FILE_HEADER)) + except struct.error as e: + raise FatalError("Failed to read a valid ELF header from %s: %s" % (self.name, e)) + + if byte(ident, 0) != 0x7f or ident[1:4] != b'ELF': + raise FatalError("%s has invalid ELF magic header" % self.name) + if machine not in [0x5e, 0xf3]: + raise FatalError("%s does not appear to be an Xtensa or an RISCV ELF file. e_machine=%04x" % (self.name, machine)) + if shentsize != self.LEN_SEC_HEADER: + raise FatalError("%s has unexpected section header entry size 0x%x (not 0x%x)" % (self.name, shentsize, self.LEN_SEC_HEADER)) + if shnum == 0: + raise FatalError("%s has 0 section headers" % (self.name)) + self._read_sections(f, shoff, shnum, shstrndx) + self._read_segments(f, _phoff, _phnum, shstrndx) + + def _read_sections(self, f, section_header_offs, section_header_count, shstrndx): + f.seek(section_header_offs) + len_bytes = section_header_count * self.LEN_SEC_HEADER + section_header = f.read(len_bytes) + if len(section_header) == 0: + raise FatalError("No section header found at offset %04x in ELF file." % section_header_offs) + if len(section_header) != (len_bytes): + raise FatalError("Only read 0x%x bytes from section header (expected 0x%x.) Truncated ELF file?" % (len(section_header), len_bytes)) + + # walk through the section header and extract all sections + section_header_offsets = range(0, len(section_header), self.LEN_SEC_HEADER) + + def read_section_header(offs): + name_offs, sec_type, _flags, lma, sec_offs, size = struct.unpack_from(" 0] + self.sections = prog_sections + + def _read_segments(self, f, segment_header_offs, segment_header_count, shstrndx): + f.seek(segment_header_offs) + len_bytes = segment_header_count * self.LEN_SEG_HEADER + segment_header = f.read(len_bytes) + if len(segment_header) == 0: + raise FatalError("No segment header found at offset %04x in ELF file." % segment_header_offs) + if len(segment_header) != (len_bytes): + raise FatalError("Only read 0x%x bytes from segment header (expected 0x%x.) Truncated ELF file?" % (len(segment_header), len_bytes)) + + # walk through the segment header and extract all segments + segment_header_offsets = range(0, len(segment_header), self.LEN_SEG_HEADER) + + def read_segment_header(offs): + seg_type, seg_offs, _vaddr, lma, size, _memsize, _flags, _align = struct.unpack_from(" 0] + self.segments = prog_segments + + def sha256(self): + # return SHA256 hash of the input ELF file + sha256 = hashlib.sha256() + with open(self.name, 'rb') as f: + sha256.update(f.read()) + return sha256.digest() + + +def slip_reader(port, trace_function): + """Generator to read SLIP packets from a serial port. + Yields one full SLIP packet at a time, raises exception on timeout or invalid data. + + Designed to avoid too many calls to serial.read(1), which can bog + down on slow systems. + """ + partial_packet = None + in_escape = False + while True: + waiting = port.inWaiting() + read_bytes = port.read(1 if waiting == 0 else waiting) + if read_bytes == b'': + waiting_for = "header" if partial_packet is None else "content" + trace_function("Timed out waiting for packet %s", waiting_for) + raise FatalError("Timed out waiting for packet %s" % waiting_for) + trace_function("Read %d bytes: %s", len(read_bytes), HexFormatter(read_bytes)) + for b in read_bytes: + if type(b) is int: + b = bytes([b]) # python 2/3 compat + + if partial_packet is None: # waiting for packet header + if b == b'\xc0': + partial_packet = b"" + else: + trace_function("Read invalid data: %s", HexFormatter(read_bytes)) + trace_function("Remaining data in serial buffer: %s", HexFormatter(port.read(port.inWaiting()))) + raise FatalError('Invalid head of packet (0x%s)' % hexify(b)) + elif in_escape: # part-way through escape sequence + in_escape = False + if b == b'\xdc': + partial_packet += b'\xc0' + elif b == b'\xdd': + partial_packet += b'\xdb' + else: + trace_function("Read invalid data: %s", HexFormatter(read_bytes)) + trace_function("Remaining data in serial buffer: %s", HexFormatter(port.read(port.inWaiting()))) + raise FatalError('Invalid SLIP escape (0xdb, 0x%s)' % (hexify(b))) + elif b == b'\xdb': # start of escape sequence + in_escape = True + elif b == b'\xc0': # end of packet + trace_function("Received full packet: %s", HexFormatter(partial_packet)) + yield partial_packet + partial_packet = None + else: # normal byte in packet + partial_packet += b + + +def arg_auto_int(x): + return int(x, 0) + + +def div_roundup(a, b): + """ Return a/b rounded up to nearest integer, + equivalent result to int(math.ceil(float(int(a)) / float(int(b))), only + without possible floating point accuracy errors. + """ + return (int(a) + int(b) - 1) // int(b) + + +def align_file_position(f, size): + """ Align the position in the file to the next block of specified size """ + align = (size - 1) - (f.tell() % size) + f.seek(align, 1) + + +def flash_size_bytes(size): + """ Given a flash size of the type passed in args.flash_size + (ie 512KB or 1MB) then return the size in bytes. + """ + if "MB" in size: + return int(size[:size.index("MB")]) * 1024 * 1024 + elif "KB" in size: + return int(size[:size.index("KB")]) * 1024 + else: + raise FatalError("Unknown size %s" % size) + + +def hexify(s, uppercase=True): + format_str = '%02X' if uppercase else '%02x' + if not PYTHON2: + return ''.join(format_str % c for c in s) + else: + return ''.join(format_str % ord(c) for c in s) + + +class HexFormatter(object): + """ + Wrapper class which takes binary data in its constructor + and returns a hex string as it's __str__ method. + + This is intended for "lazy formatting" of trace() output + in hex format. Avoids overhead (significant on slow computers) + of generating long hex strings even if tracing is disabled. + + Note that this doesn't save any overhead if passed as an + argument to "%", only when passed to trace() + + If auto_split is set (default), any long line (> 16 bytes) will be + printed as separately indented lines, with ASCII decoding at the end + of each line. + """ + def __init__(self, binary_string, auto_split=True): + self._s = binary_string + self._auto_split = auto_split + + def __str__(self): + if self._auto_split and len(self._s) > 16: + result = "" + s = self._s + while len(s) > 0: + line = s[:16] + ascii_line = "".join(c if (c == ' ' or (c in string.printable and c not in string.whitespace)) + else '.' for c in line.decode('ascii', 'replace')) + s = s[16:] + result += "\n %-16s %-16s | %s" % (hexify(line[:8], False), hexify(line[8:], False), ascii_line) + return result + else: + return hexify(self._s, False) + + +def pad_to(data, alignment, pad_character=b'\xFF'): + """ Pad to the next alignment boundary """ + pad_mod = len(data) % alignment + if pad_mod != 0: + data += pad_character * (alignment - pad_mod) + return data + + +class FatalError(RuntimeError): + """ + Wrapper class for runtime errors that aren't caused by internal bugs, but by + ESP8266 responses or input content. + """ + def __init__(self, message): + RuntimeError.__init__(self, message) + + @staticmethod + def WithResult(message, result): + """ + Return a fatal error object that appends the hex values of + 'result' as a string formatted argument. + """ + message += " (result was %s)" % hexify(result) + return FatalError(message) + + +class NotImplementedInROMError(FatalError): + """ + Wrapper class for the error thrown when a particular ESP bootloader function + is not implemented in the ROM bootloader. + """ + def __init__(self, bootloader, func): + FatalError.__init__(self, "%s ROM does not support function %s." % (bootloader.CHIP_NAME, func.__name__)) + + +class NotSupportedError(FatalError): + def __init__(self, esp, function_name): + FatalError.__init__(self, "Function %s is not supported for %s." % (function_name, esp.CHIP_NAME)) + +# "Operation" commands, executable at command line. One function each +# +# Each function takes either two args (, ) or a single +# argument. + + +class UnsupportedCommandError(RuntimeError): + """ + Wrapper class for when ROM loader returns an invalid command response. + + Usually this indicates the loader is running in Secure Download Mode. + """ + def __init__(self, esp, op): + if esp.secure_download_mode: + msg = "This command (0x%x) is not supported in Secure Download Mode" % op + else: + msg = "Invalid (unsupported) command 0x%x" % op + RuntimeError.__init__(self, msg) + + +def load_ram(esp, args): + image = LoadFirmwareImage(esp.CHIP_NAME, args.filename) + + print('RAM boot...') + for seg in image.segments: + size = len(seg.data) + print('Downloading %d bytes at %08x...' % (size, seg.addr), end=' ') + sys.stdout.flush() + esp.mem_begin(size, div_roundup(size, esp.ESP_RAM_BLOCK), esp.ESP_RAM_BLOCK, seg.addr) + + seq = 0 + while len(seg.data) > 0: + esp.mem_block(seg.data[0:esp.ESP_RAM_BLOCK], seq) + seg.data = seg.data[esp.ESP_RAM_BLOCK:] + seq += 1 + print('done!') + + print('All segments done, executing at %08x' % image.entrypoint) + esp.mem_finish(image.entrypoint) + + +def read_mem(esp, args): + print('0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address))) + + +def write_mem(esp, args): + esp.write_reg(args.address, args.value, args.mask, 0) + print('Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address)) + + +def dump_mem(esp, args): + with open(args.filename, 'wb') as f: + for i in range(args.size // 4): + d = esp.read_reg(args.address + (i * 4)) + f.write(struct.pack(b'> 16 + args.flash_size = DETECTED_FLASH_SIZES.get(size_id) + if args.flash_size is None: + print('Warning: Could not auto-detect Flash size (FlashID=0x%x, SizeID=0x%x), defaulting to 4MB' % (flash_id, size_id)) + args.flash_size = '4MB' + else: + print('Auto-detected Flash size:', args.flash_size) + + +def _update_image_flash_params(esp, address, args, image): + """ Modify the flash mode & size bytes if this looks like an executable bootloader image """ + if len(image) < 8: + return image # not long enough to be a bootloader image + + # unpack the (potential) image header + magic, _, flash_mode, flash_size_freq = struct.unpack("BBBB", image[:4]) + if address != esp.BOOTLOADER_FLASH_OFFSET: + return image # not flashing bootloader offset, so don't modify this + + if (args.flash_mode, args.flash_freq, args.flash_size) == ('keep',) * 3: + return image # all settings are 'keep', not modifying anything + + # easy check if this is an image: does it start with a magic byte? + if magic != esp.ESP_IMAGE_MAGIC: + print("Warning: Image file at 0x%x doesn't look like an image file, so not changing any flash settings." % address) + return image + + # make sure this really is an image, and not just data that + # starts with esp.ESP_IMAGE_MAGIC (mostly a problem for encrypted + # images that happen to start with a magic byte + try: + test_image = esp.BOOTLOADER_IMAGE(io.BytesIO(image)) + test_image.verify() + except Exception: + print("Warning: Image file at 0x%x is not a valid %s image, so not changing any flash settings." % (address, esp.CHIP_NAME)) + return image + + if args.flash_mode != 'keep': + flash_mode = {'qio': 0, 'qout': 1, 'dio': 2, 'dout': 3}[args.flash_mode] + + flash_freq = flash_size_freq & 0x0F + if args.flash_freq != 'keep': + flash_freq = {'40m': 0, '26m': 1, '20m': 2, '80m': 0xf}[args.flash_freq] + + flash_size = flash_size_freq & 0xF0 + if args.flash_size != 'keep': + flash_size = esp.parse_flash_size_arg(args.flash_size) + + flash_params = struct.pack(b'BB', flash_mode, flash_size + flash_freq) + if flash_params != image[2:4]: + print('Flash params set to 0x%04x' % struct.unpack(">H", flash_params)) + image = image[0:2] + flash_params + image[4:] + return image + + +def write_flash(esp, args): + # set args.compress based on default behaviour: + # -> if either --compress or --no-compress is set, honour that + # -> otherwise, set --compress unless --no-stub is set + if args.compress is None and not args.no_compress: + args.compress = not args.no_stub + + # In case we have encrypted files to write, we first do few sanity checks before actual flash + if args.encrypt or args.encrypt_files is not None: + do_write = True + + if not esp.secure_download_mode: + if esp.get_encrypted_download_disabled(): + raise FatalError("This chip has encrypt functionality in UART download mode disabled. " + "This is the Flash Encryption configuration for Production mode instead of Development mode.") + + crypt_cfg_efuse = esp.get_flash_crypt_config() + + if crypt_cfg_efuse is not None and crypt_cfg_efuse != 0xF: + print('Unexpected FLASH_CRYPT_CONFIG value: 0x%x' % (crypt_cfg_efuse)) + do_write = False + + enc_key_valid = esp.is_flash_encryption_key_valid() + + if not enc_key_valid: + print('Flash encryption key is not programmed') + do_write = False + + # Determine which files list contain the ones to encrypt + files_to_encrypt = args.addr_filename if args.encrypt else args.encrypt_files + + for address, argfile in files_to_encrypt: + if address % esp.FLASH_ENCRYPTED_WRITE_ALIGN: + print("File %s address 0x%x is not %d byte aligned, can't flash encrypted" % + (argfile.name, address, esp.FLASH_ENCRYPTED_WRITE_ALIGN)) + do_write = False + + if not do_write and not args.ignore_flash_encryption_efuse_setting: + raise FatalError("Can't perform encrypted flash write, consult Flash Encryption documentation for more information") + + # verify file sizes fit in flash + if args.flash_size != 'keep': # TODO: check this even with 'keep' + flash_end = flash_size_bytes(args.flash_size) + for address, argfile in args.addr_filename: + argfile.seek(0, 2) # seek to end + if address + argfile.tell() > flash_end: + raise FatalError(("File %s (length %d) at offset %d will not fit in %d bytes of flash. " + "Use --flash-size argument, or change flashing address.") + % (argfile.name, argfile.tell(), address, flash_end)) + argfile.seek(0) + + if args.erase_all: + erase_flash(esp, args) + + """ Create a list describing all the files we have to flash. Each entry holds an "encrypt" flag + marking whether the file needs encryption or not. This list needs to be sorted. + + First, append to each entry of our addr_filename list the flag args.encrypt + For example, if addr_filename is [(0x1000, "partition.bin"), (0x8000, "bootloader")], + all_files will be [(0x1000, "partition.bin", args.encrypt), (0x8000, "bootloader", args.encrypt)], + where, of course, args.encrypt is either True or False + """ + all_files = [(offs, filename, args.encrypt) for (offs, filename) in args.addr_filename] + + """Now do the same with encrypt_files list, if defined. + In this case, the flag is True + """ + if args.encrypt_files is not None: + encrypted_files_flag = [(offs, filename, True) for (offs, filename) in args.encrypt_files] + + # Concatenate both lists and sort them. + # As both list are already sorted, we could simply do a merge instead, + # but for the sake of simplicity and because the lists are very small, + # let's use sorted. + all_files = sorted(all_files + encrypted_files_flag, key=lambda x: x[0]) + + for address, argfile, encrypted in all_files: + compress = args.compress + + # Check whether we can compress the current file before flashing + if compress and encrypted: + print('\nWARNING: - compress and encrypt options are mutually exclusive ') + print('Will flash %s uncompressed' % argfile.name) + compress = False + + if args.no_stub: + print('Erasing flash...') + image = pad_to(argfile.read(), esp.FLASH_ENCRYPTED_WRITE_ALIGN if encrypted else 4) + if len(image) == 0: + print('WARNING: File %s is empty' % argfile.name) + continue + image = _update_image_flash_params(esp, address, args, image) + calcmd5 = hashlib.md5(image).hexdigest() + uncsize = len(image) + if compress: + uncimage = image + image = zlib.compress(uncimage, 9) + # Decompress the compressed binary a block at a time, to dynamically calculate the + # timeout based on the real write size + decompress = zlib.decompressobj() + blocks = esp.flash_defl_begin(uncsize, len(image), address) + else: + blocks = esp.flash_begin(uncsize, address, begin_rom_encrypted=encrypted) + argfile.seek(0) # in case we need it again + seq = 0 + bytes_sent = 0 # bytes sent on wire + bytes_written = 0 # bytes written to flash + t = time.time() + + timeout = DEFAULT_TIMEOUT + + while len(image) > 0: + print_overwrite('Writing at 0x%08x... (%d %%)' % (address + bytes_written, 100 * (seq + 1) // blocks)) + sys.stdout.flush() + block = image[0:esp.FLASH_WRITE_SIZE] + if compress: + # feeding each compressed block into the decompressor lets us see block-by-block how much will be written + block_uncompressed = len(decompress.decompress(block)) + bytes_written += block_uncompressed + block_timeout = max(DEFAULT_TIMEOUT, timeout_per_mb(ERASE_WRITE_TIMEOUT_PER_MB, block_uncompressed)) + if not esp.IS_STUB: + timeout = block_timeout # ROM code writes block to flash before ACKing + esp.flash_defl_block(block, seq, timeout=timeout) + if esp.IS_STUB: + timeout = block_timeout # Stub ACKs when block is received, then writes to flash while receiving the block after it + else: + # Pad the last block + block = block + b'\xff' * (esp.FLASH_WRITE_SIZE - len(block)) + if encrypted: + esp.flash_encrypt_block(block, seq) + else: + esp.flash_block(block, seq) + bytes_written += len(block) + bytes_sent += len(block) + image = image[esp.FLASH_WRITE_SIZE:] + seq += 1 + + if esp.IS_STUB: + # Stub only writes each block to flash after 'ack'ing the receive, so do a final dummy operation which will + # not be 'ack'ed until the last block has actually been written out to flash + esp.read_reg(ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR, timeout=timeout) + + t = time.time() - t + speed_msg = "" + if compress: + if t > 0.0: + speed_msg = " (effective %.1f kbit/s)" % (uncsize / t * 8 / 1000) + print_overwrite('Wrote %d bytes (%d compressed) at 0x%08x in %.1f seconds%s...' % (uncsize, + bytes_sent, + address, t, speed_msg), last_line=True) + else: + if t > 0.0: + speed_msg = " (%.1f kbit/s)" % (bytes_written / t * 8 / 1000) + print_overwrite('Wrote %d bytes at 0x%08x in %.1f seconds%s...' % (bytes_written, address, t, speed_msg), last_line=True) + + if not encrypted and not esp.secure_download_mode: + try: + res = esp.flash_md5sum(address, uncsize) + if res != calcmd5: + print('File md5: %s' % calcmd5) + print('Flash md5: %s' % res) + print('MD5 of 0xFF is %s' % (hashlib.md5(b'\xFF' * uncsize).hexdigest())) + raise FatalError("MD5 of file does not match data in flash!") + else: + print('Hash of data verified.') + except NotImplementedInROMError: + pass + + print('\nLeaving...') + + if esp.IS_STUB: + # skip sending flash_finish to ROM loader here, + # as it causes the loader to exit and run user code + esp.flash_begin(0, 0) + + # Get the "encrypted" flag for the last file flashed + # Note: all_files list contains triplets like: + # (address: Integer, filename: String, encrypted: Boolean) + last_file_encrypted = all_files[-1][2] + + # Check whether the last file flashed was compressed or not + if args.compress and not last_file_encrypted: + esp.flash_defl_finish(False) + else: + esp.flash_finish(False) + + if args.verify: + print('Verifying just-written flash...') + print('(This option is deprecated, flash contents are now always read back after flashing.)') + # If some encrypted files have been flashed print a warning saying that we won't check them + if args.encrypt or args.encrypt_files is not None: + print('WARNING: - cannot verify encrypted files, they will be ignored') + # Call verify_flash function only if there at least one non-encrypted file flashed + if not args.encrypt: + verify_flash(esp, args) + + +def image_info(args): + image = LoadFirmwareImage(args.chip, args.filename) + print('Image version: %d' % image.version) + print('Entry point: %08x' % image.entrypoint if image.entrypoint != 0 else 'Entry point not set') + print('%d segments' % len(image.segments)) + print() + idx = 0 + for seg in image.segments: + idx += 1 + segs = seg.get_memory_type(image) + seg_name = ",".join(segs) + print('Segment %d: %r [%s]' % (idx, seg, seg_name)) + calc_checksum = image.calculate_checksum() + print('Checksum: %02x (%s)' % (image.checksum, + 'valid' if image.checksum == calc_checksum else 'invalid - calculated %02x' % calc_checksum)) + try: + digest_msg = 'Not appended' + if image.append_digest: + is_valid = image.stored_digest == image.calc_digest + digest_msg = "%s (%s)" % (hexify(image.calc_digest).lower(), + "valid" if is_valid else "invalid") + print('Validation Hash: %s' % digest_msg) + except AttributeError: + pass # ESP8266 image has no append_digest field + + +def make_image(args): + image = ESP8266ROMFirmwareImage() + if len(args.segfile) == 0: + raise FatalError('No segments specified') + if len(args.segfile) != len(args.segaddr): + raise FatalError('Number of specified files does not match number of specified addresses') + for (seg, addr) in zip(args.segfile, args.segaddr): + with open(seg, 'rb') as f: + data = f.read() + image.segments.append(ImageSegment(addr, data)) + image.entrypoint = args.entrypoint + image.save(args.output) + + +def elf2image(args): + e = ELFFile(args.input) + if args.chip == 'auto': # Default to ESP8266 for backwards compatibility + print("Creating image for ESP8266...") + args.chip = 'esp8266' + + if args.chip == 'esp32': + image = ESP32FirmwareImage() + if args.secure_pad: + image.secure_pad = '1' + elif args.secure_pad_v2: + image.secure_pad = '2' + elif args.chip == 'esp32s2': + image = ESP32S2FirmwareImage() + if args.secure_pad_v2: + image.secure_pad = '2' + elif args.chip == 'esp32s3beta2': + image = ESP32S3BETA2FirmwareImage() + if args.secure_pad_v2: + image.secure_pad = '2' + elif args.chip == 'esp32s3beta3': + image = ESP32S3BETA3FirmwareImage() + if args.secure_pad_v2: + image.secure_pad = '2' + elif args.chip == 'esp32c3': + image = ESP32C3FirmwareImage() + if args.secure_pad_v2: + image.secure_pad = '2' + elif args.version == '1': # ESP8266 + image = ESP8266ROMFirmwareImage() + else: + image = ESP8266V2FirmwareImage() + image.entrypoint = e.entrypoint + image.flash_mode = {'qio': 0, 'qout': 1, 'dio': 2, 'dout': 3}[args.flash_mode] + + if args.chip != 'esp8266': + image.min_rev = int(args.min_rev) + + # ELFSection is a subclass of ImageSegment, so can use interchangeably + image.segments = e.segments if args.use_segments else e.sections + + image.flash_size_freq = image.ROM_LOADER.FLASH_SIZES[args.flash_size] + image.flash_size_freq += {'40m': 0, '26m': 1, '20m': 2, '80m': 0xf}[args.flash_freq] + + if args.elf_sha256_offset: + image.elf_sha256 = e.sha256() + image.elf_sha256_offset = args.elf_sha256_offset + + before = len(image.segments) + image.merge_adjacent_segments() + if len(image.segments) != before: + delta = before - len(image.segments) + print("Merged %d ELF section%s" % (delta, "s" if delta > 1 else "")) + + image.verify() + + if args.output is None: + args.output = image.default_output_name(args.input) + image.save(args.output) + + +def read_mac(esp, args): + mac = esp.read_mac() + + def print_mac(label, mac): + print('%s: %s' % (label, ':'.join(map(lambda x: '%02x' % x, mac)))) + print_mac("MAC", mac) + + +def chip_id(esp, args): + try: + chipid = esp.chip_id() + print('Chip ID: 0x%08x' % chipid) + except NotSupportedError: + print('Warning: %s has no Chip ID. Reading MAC instead.' % esp.CHIP_NAME) + read_mac(esp, args) + + +def erase_flash(esp, args): + print('Erasing flash (this may take a while)...') + t = time.time() + esp.erase_flash() + print('Chip erase completed successfully in %.1fs' % (time.time() - t)) + + +def erase_region(esp, args): + print('Erasing region (may be slow depending on size)...') + t = time.time() + esp.erase_region(args.address, args.size) + print('Erase completed successfully in %.1f seconds.' % (time.time() - t)) + + +def run(esp, args): + esp.run() + + +def flash_id(esp, args): + flash_id = esp.flash_id() + print('Manufacturer: %02x' % (flash_id & 0xff)) + flid_lowbyte = (flash_id >> 16) & 0xFF + print('Device: %02x%02x' % ((flash_id >> 8) & 0xff, flid_lowbyte)) + print('Detected flash size: %s' % (DETECTED_FLASH_SIZES.get(flid_lowbyte, "Unknown"))) + + +def read_flash(esp, args): + if args.no_progress: + flash_progress = None + else: + def flash_progress(progress, length): + msg = '%d (%d %%)' % (progress, progress * 100.0 / length) + padding = '\b' * len(msg) + if progress == length: + padding = '\n' + sys.stdout.write(msg + padding) + sys.stdout.flush() + t = time.time() + data = esp.read_flash(args.address, args.size, flash_progress) + t = time.time() - t + print_overwrite('Read %d bytes at 0x%x in %.1f seconds (%.1f kbit/s)...' + % (len(data), args.address, t, len(data) / t * 8 / 1000), last_line=True) + with open(args.filename, 'wb') as f: + f.write(data) + + +def verify_flash(esp, args): + differences = False + + for address, argfile in args.addr_filename: + image = pad_to(argfile.read(), 4) + argfile.seek(0) # rewind in case we need it again + + image = _update_image_flash_params(esp, address, args, image) + + image_size = len(image) + print('Verifying 0x%x (%d) bytes @ 0x%08x in flash against %s...' % (image_size, image_size, address, argfile.name)) + # Try digest first, only read if there are differences. + digest = esp.flash_md5sum(address, image_size) + expected_digest = hashlib.md5(image).hexdigest() + if digest == expected_digest: + print('-- verify OK (digest matched)') + continue + else: + differences = True + if getattr(args, 'diff', 'no') != 'yes': + print('-- verify FAILED (digest mismatch)') + continue + + flash = esp.read_flash(address, image_size) + assert flash != image + diff = [i for i in range(image_size) if flash[i] != image[i]] + print('-- verify FAILED: %d differences, first @ 0x%08x' % (len(diff), address + diff[0])) + for d in diff: + flash_byte = flash[d] + image_byte = image[d] + if PYTHON2: + flash_byte = ord(flash_byte) + image_byte = ord(image_byte) + print(' %08x %02x %02x' % (address + d, flash_byte, image_byte)) + if differences: + raise FatalError("Verify failed.") + + +def read_flash_status(esp, args): + print('Status value: 0x%04x' % esp.read_status(args.bytes)) + + +def write_flash_status(esp, args): + fmt = "0x%%0%dx" % (args.bytes * 2) + args.value = args.value & ((1 << (args.bytes * 8)) - 1) + print(('Initial flash status: ' + fmt) % esp.read_status(args.bytes)) + print(('Setting flash status: ' + fmt) % args.value) + esp.write_status(args.value, args.bytes, args.non_volatile) + print(('After flash status: ' + fmt) % esp.read_status(args.bytes)) + + +def get_security_info(esp, args): + (flags, flash_crypt_cnt, key_purposes) = esp.get_security_info() + # TODO: better display + print('Flags: 0x%08x (%s)' % (flags, bin(flags))) + print('Flash_Crypt_Cnt: 0x%x' % flash_crypt_cnt) + print('Key_Purposes: %s' % (key_purposes,)) + + +def merge_bin(args): + chip_class = _chip_to_rom_loader(args.chip) + + # sort the files by offset. The AddrFilenamePairAction has already checked for overlap + input_files = sorted(args.addr_filename, key=lambda x: x[0]) + if not input_files: + raise FatalError("No input files specified") + first_addr = input_files[0][0] + if first_addr < args.target_offset: + raise FatalError("Output file target offset is 0x%x. Input file offset 0x%x is before this." % (args.target_offset, first_addr)) + + if args.format != 'raw': + raise FatalError("This version of esptool only supports the 'raw' output format") + + with open(args.output, 'wb') as of: + def pad_to(flash_offs): + # account for output file offset if there is any + of.write(b'\xFF' * (flash_offs - args.target_offset - of.tell())) + for addr, argfile in input_files: + pad_to(addr) + image = argfile.read() + image = _update_image_flash_params(chip_class, addr, args, image) + of.write(image) + if args.fill_flash_size: + pad_to(flash_size_bytes(args.fill_flash_size)) + print("Wrote 0x%x bytes to file %s, ready to flash to offset 0x%x" % (of.tell(), args.output, args.target_offset)) + + +def version(args): + print(__version__) + +# +# End of operations functions +# + + +def main(argv=None, esp=None): + """ + Main function for esptool + + argv - Optional override for default arguments parsing (that uses sys.argv), can be a list of custom arguments + as strings. Arguments and their values need to be added as individual items to the list e.g. "-b 115200" thus + becomes ['-b', '115200']. + + esp - Optional override of the connected device previously returned by get_default_connected_device() + """ + + external_esp = esp is not None + + parser = argparse.ArgumentParser(description='esptool.py v%s - ESP8266 ROM Bootloader Utility' % __version__, prog='esptool') + + parser.add_argument('--chip', '-c', + help='Target chip type', + type=lambda c: c.lower().replace('-', ''), # support ESP32-S2, etc. + choices=['auto', 'esp8266', 'esp32', 'esp32s2', 'esp32s3beta2', 'esp32s3beta3', 'esp32c3'], + default=os.environ.get('ESPTOOL_CHIP', 'auto')) + + parser.add_argument( + '--port', '-p', + help='Serial port device', + default=os.environ.get('ESPTOOL_PORT', None)) + + parser.add_argument( + '--baud', '-b', + help='Serial port baud rate used when flashing/reading', + type=arg_auto_int, + default=os.environ.get('ESPTOOL_BAUD', ESPLoader.ESP_ROM_BAUD)) + + parser.add_argument( + '--before', + help='What to do before connecting to the chip', + choices=['default_reset', 'no_reset', 'no_reset_no_sync'], + default=os.environ.get('ESPTOOL_BEFORE', 'default_reset')) + + parser.add_argument( + '--after', '-a', + help='What to do after esptool.py is finished', + choices=['hard_reset', 'soft_reset', 'no_reset'], + default=os.environ.get('ESPTOOL_AFTER', 'hard_reset')) + + parser.add_argument( + '--no-stub', + help="Disable launching the flasher stub, only talk to ROM bootloader. Some features will not be available.", + action='store_true') + + parser.add_argument( + '--trace', '-t', + help="Enable trace-level output of esptool.py interactions.", + action='store_true') + + parser.add_argument( + '--override-vddsdio', + help="Override ESP32 VDDSDIO internal voltage regulator (use with care)", + choices=ESP32ROM.OVERRIDE_VDDSDIO_CHOICES, + nargs='?') + + parser.add_argument( + '--connect-attempts', + help=('Number of attempts to connect, negative or 0 for infinite. ' + 'Default: %d.' % DEFAULT_CONNECT_ATTEMPTS), + type=int, + default=os.environ.get('ESPTOOL_CONNECT_ATTEMPTS', DEFAULT_CONNECT_ATTEMPTS)) + + subparsers = parser.add_subparsers( + dest='operation', + help='Run esptool {command} -h for additional help') + + def add_spi_connection_arg(parent): + parent.add_argument('--spi-connection', '-sc', help='ESP32-only argument. Override default SPI Flash connection. ' + 'Value can be SPI, HSPI or a comma-separated list of 5 I/O numbers to use for SPI flash (CLK,Q,D,HD,CS).', + action=SpiConnectionAction) + + parser_load_ram = subparsers.add_parser( + 'load_ram', + help='Download an image to RAM and execute') + parser_load_ram.add_argument('filename', help='Firmware image') + + parser_dump_mem = subparsers.add_parser( + 'dump_mem', + help='Dump arbitrary memory to disk') + parser_dump_mem.add_argument('address', help='Base address', type=arg_auto_int) + parser_dump_mem.add_argument('size', help='Size of region to dump', type=arg_auto_int) + parser_dump_mem.add_argument('filename', help='Name of binary dump') + + parser_read_mem = subparsers.add_parser( + 'read_mem', + help='Read arbitrary memory location') + parser_read_mem.add_argument('address', help='Address to read', type=arg_auto_int) + + parser_write_mem = subparsers.add_parser( + 'write_mem', + help='Read-modify-write to arbitrary memory location') + parser_write_mem.add_argument('address', help='Address to write', type=arg_auto_int) + parser_write_mem.add_argument('value', help='Value', type=arg_auto_int) + parser_write_mem.add_argument('mask', help='Mask of bits to write', type=arg_auto_int, nargs='?', default='0xFFFFFFFF') + + def add_spi_flash_subparsers(parent, allow_keep, auto_detect): + """ Add common parser arguments for SPI flash properties """ + extra_keep_args = ['keep'] if allow_keep else [] + + if auto_detect and allow_keep: + extra_fs_message = ", detect, or keep" + elif auto_detect: + extra_fs_message = ", or detect" + elif allow_keep: + extra_fs_message = ", or keep" + else: + extra_fs_message = "" + + parent.add_argument('--flash_freq', '-ff', help='SPI Flash frequency', + choices=extra_keep_args + ['40m', '26m', '20m', '80m'], + default=os.environ.get('ESPTOOL_FF', 'keep' if allow_keep else '40m')) + parent.add_argument('--flash_mode', '-fm', help='SPI Flash mode', + choices=extra_keep_args + ['qio', 'qout', 'dio', 'dout'], + default=os.environ.get('ESPTOOL_FM', 'keep' if allow_keep else 'qio')) + parent.add_argument('--flash_size', '-fs', help='SPI Flash size in MegaBytes (1MB, 2MB, 4MB, 8MB, 16M)' + ' plus ESP8266-only (256KB, 512KB, 2MB-c1, 4MB-c1)' + extra_fs_message, + action=FlashSizeAction, auto_detect=auto_detect, + default=os.environ.get('ESPTOOL_FS', 'keep' if allow_keep else '1MB')) + add_spi_connection_arg(parent) + + parser_write_flash = subparsers.add_parser( + 'write_flash', + help='Write a binary blob to flash') + + parser_write_flash.add_argument('addr_filename', metavar='
', help='Address followed by binary filename, separated by space', + action=AddrFilenamePairAction) + parser_write_flash.add_argument('--erase-all', '-e', + help='Erase all regions of flash (not just write areas) before programming', + action="store_true") + + add_spi_flash_subparsers(parser_write_flash, allow_keep=True, auto_detect=True) + parser_write_flash.add_argument('--no-progress', '-p', help='Suppress progress output', action="store_true") + parser_write_flash.add_argument('--verify', help='Verify just-written data on flash ' + '(mostly superfluous, data is read back during flashing)', action='store_true') + parser_write_flash.add_argument('--encrypt', help='Apply flash encryption when writing data (required correct efuse settings)', + action='store_true') + # In order to not break backward compatibility, our list of encrypted files to flash is a new parameter + parser_write_flash.add_argument('--encrypt-files', metavar='
', + help='Files to be encrypted on the flash. Address followed by binary filename, separated by space.', + action=AddrFilenamePairAction) + parser_write_flash.add_argument('--ignore-flash-encryption-efuse-setting', help='Ignore flash encryption efuse settings ', + action='store_true') + + compress_args = parser_write_flash.add_mutually_exclusive_group(required=False) + compress_args.add_argument('--compress', '-z', help='Compress data in transfer (default unless --no-stub is specified)', + action="store_true", default=None) + compress_args.add_argument('--no-compress', '-u', help='Disable data compression during transfer (default if --no-stub is specified)', + action="store_true") + + subparsers.add_parser( + 'run', + help='Run application code in flash') + + parser_image_info = subparsers.add_parser( + 'image_info', + help='Dump headers from an application image') + parser_image_info.add_argument('filename', help='Image file to parse') + + parser_make_image = subparsers.add_parser( + 'make_image', + help='Create an application image from binary files') + parser_make_image.add_argument('output', help='Output image file') + parser_make_image.add_argument('--segfile', '-f', action='append', help='Segment input file') + parser_make_image.add_argument('--segaddr', '-a', action='append', help='Segment base address', type=arg_auto_int) + parser_make_image.add_argument('--entrypoint', '-e', help='Address of entry point', type=arg_auto_int, default=0) + + parser_elf2image = subparsers.add_parser( + 'elf2image', + help='Create an application image from ELF file') + parser_elf2image.add_argument('input', help='Input ELF file') + parser_elf2image.add_argument('--output', '-o', help='Output filename prefix (for version 1 image), or filename (for version 2 single image)', type=str) + parser_elf2image.add_argument('--version', '-e', help='Output image version', choices=['1', '2'], default='1') + parser_elf2image.add_argument('--min-rev', '-r', help='Minimum chip revision', choices=['0', '1', '2', '3'], default='0') + parser_elf2image.add_argument('--secure-pad', action='store_true', + help='Pad image so once signed it will end on a 64KB boundary. For Secure Boot v1 images only.') + parser_elf2image.add_argument('--secure-pad-v2', action='store_true', + help='Pad image to 64KB, so once signed its signature sector will start at the next 64K block. ' + 'For Secure Boot v2 images only.') + parser_elf2image.add_argument('--elf-sha256-offset', help='If set, insert SHA256 hash (32 bytes) of the input ELF file at specified offset in the binary.', + type=arg_auto_int, default=None) + parser_elf2image.add_argument('--use_segments', help='If set, ELF segments will be used instead of ELF sections to genereate the image.', + action='store_true') + + add_spi_flash_subparsers(parser_elf2image, allow_keep=False, auto_detect=False) + + subparsers.add_parser( + 'read_mac', + help='Read MAC address from OTP ROM') + + subparsers.add_parser( + 'chip_id', + help='Read Chip ID from OTP ROM') + + parser_flash_id = subparsers.add_parser( + 'flash_id', + help='Read SPI flash manufacturer and device ID') + add_spi_connection_arg(parser_flash_id) + + parser_read_status = subparsers.add_parser( + 'read_flash_status', + help='Read SPI flash status register') + + add_spi_connection_arg(parser_read_status) + parser_read_status.add_argument('--bytes', help='Number of bytes to read (1-3)', type=int, choices=[1, 2, 3], default=2) + + parser_write_status = subparsers.add_parser( + 'write_flash_status', + help='Write SPI flash status register') + + add_spi_connection_arg(parser_write_status) + parser_write_status.add_argument('--non-volatile', help='Write non-volatile bits (use with caution)', action='store_true') + parser_write_status.add_argument('--bytes', help='Number of status bytes to write (1-3)', type=int, choices=[1, 2, 3], default=2) + parser_write_status.add_argument('value', help='New value', type=arg_auto_int) + + parser_read_flash = subparsers.add_parser( + 'read_flash', + help='Read SPI flash content') + add_spi_connection_arg(parser_read_flash) + parser_read_flash.add_argument('address', help='Start address', type=arg_auto_int) + parser_read_flash.add_argument('size', help='Size of region to dump', type=arg_auto_int) + parser_read_flash.add_argument('filename', help='Name of binary dump') + parser_read_flash.add_argument('--no-progress', '-p', help='Suppress progress output', action="store_true") + + parser_verify_flash = subparsers.add_parser( + 'verify_flash', + help='Verify a binary blob against flash') + parser_verify_flash.add_argument('addr_filename', help='Address and binary file to verify there, separated by space', + action=AddrFilenamePairAction) + parser_verify_flash.add_argument('--diff', '-d', help='Show differences', + choices=['no', 'yes'], default='no') + add_spi_flash_subparsers(parser_verify_flash, allow_keep=True, auto_detect=True) + + parser_erase_flash = subparsers.add_parser( + 'erase_flash', + help='Perform Chip Erase on SPI flash') + add_spi_connection_arg(parser_erase_flash) + + parser_erase_region = subparsers.add_parser( + 'erase_region', + help='Erase a region of the flash') + add_spi_connection_arg(parser_erase_region) + parser_erase_region.add_argument('address', help='Start address (must be multiple of 4096)', type=arg_auto_int) + parser_erase_region.add_argument('size', help='Size of region to erase (must be multiple of 4096)', type=arg_auto_int) + + parser_merge_bin = subparsers.add_parser( + 'merge_bin', + help='Merge multiple raw binary files into a single file for later flashing') + + parser_merge_bin.add_argument('--output', '-o', help='Output filename', type=str, required=True) + parser_merge_bin.add_argument('--format', '-f', help='Format of the output file', choices='raw', default='raw') # for future expansion + add_spi_flash_subparsers(parser_merge_bin, allow_keep=True, auto_detect=False) + + parser_merge_bin.add_argument('--target-offset', '-t', help='Target offset where the output file will be flashed', + type=arg_auto_int, default=0) + parser_merge_bin.add_argument('--fill-flash-size', help='If set, the final binary file will be padded with FF ' + 'bytes up to this flash size.', action=FlashSizeAction) + parser_merge_bin.add_argument('addr_filename', metavar='
', + help='Address followed by binary filename, separated by space', + action=AddrFilenamePairAction) + + subparsers.add_parser( + 'version', help='Print esptool version') + + subparsers.add_parser('get_security_info', help='Get some security-related data') + + # internal sanity check - every operation matches a module function of the same name + for operation in subparsers.choices.keys(): + assert operation in globals(), "%s should be a module function" % operation + + argv = expand_file_arguments(argv or sys.argv[1:]) + + args = parser.parse_args(argv) + print('esptool.py v%s' % __version__) + + # operation function can take 1 arg (args), 2 args (esp, arg) + # or be a member function of the ESPLoader class. + + if args.operation is None: + parser.print_help() + sys.exit(1) + + # Forbid the usage of both --encrypt, which means encrypt all the given files, + # and --encrypt-files, which represents the list of files to encrypt. + # The reason is that allowing both at the same time increases the chances of + # having contradictory lists (e.g. one file not available in one of list). + if args.operation == "write_flash" and args.encrypt and args.encrypt_files is not None: + raise FatalError("Options --encrypt and --encrypt-files must not be specified at the same time.") + + operation_func = globals()[args.operation] + + if PYTHON2: + # This function is depreciated in Python3 + operation_args = inspect.getargspec(operation_func).args + else: + operation_args = inspect.getfullargspec(operation_func).args + + if operation_args[0] == 'esp': # operation function takes an ESPLoader connection object + if args.before != "no_reset_no_sync": + initial_baud = min(ESPLoader.ESP_ROM_BAUD, args.baud) # don't sync faster than the default baud rate + else: + initial_baud = args.baud + + if args.port is None: + ser_list = get_port_list() + print("Found %d serial ports" % len(ser_list)) + else: + ser_list = [args.port] + esp = esp or get_default_connected_device(ser_list, port=args.port, connect_attempts=args.connect_attempts, + initial_baud=initial_baud, chip=args.chip, trace=args.trace, + before=args.before) + if esp is None: + raise FatalError("Could not connect to an Espressif device on any of the %d available serial ports." % len(ser_list)) + + if esp.secure_download_mode: + print("Chip is %s in Secure Download Mode" % esp.CHIP_NAME) + else: + print("Chip is %s" % (esp.get_chip_description())) + print("Features: %s" % ", ".join(esp.get_chip_features())) + print("Crystal is %dMHz" % esp.get_crystal_freq()) + read_mac(esp, args) + + if not args.no_stub: + if esp.secure_download_mode: + print("WARNING: Stub loader is not supported in Secure Download Mode, setting --no-stub") + args.no_stub = True + else: + esp = esp.run_stub() + + if args.override_vddsdio: + esp.override_vddsdio(args.override_vddsdio) + + if args.baud > initial_baud: + try: + esp.change_baud(args.baud) + except NotImplementedInROMError: + print("WARNING: ROM doesn't support changing baud rate. Keeping initial baud rate %d" % initial_baud) + + # override common SPI flash parameter stuff if configured to do so + if hasattr(args, "spi_connection") and args.spi_connection is not None: + if esp.CHIP_NAME != "ESP32": + raise FatalError("Chip %s does not support --spi-connection option." % esp.CHIP_NAME) + print("Configuring SPI flash mode...") + esp.flash_spi_attach(args.spi_connection) + elif args.no_stub: + print("Enabling default SPI flash mode...") + # ROM loader doesn't enable flash unless we explicitly do it + esp.flash_spi_attach(0) + + if hasattr(args, "flash_size"): + print("Configuring flash size...") + detect_flash_size(esp, args) + if args.flash_size != 'keep': # TODO: should set this even with 'keep' + esp.flash_set_parameters(flash_size_bytes(args.flash_size)) + + try: + operation_func(esp, args) + finally: + try: # Clean up AddrFilenamePairAction files + for address, argfile in args.addr_filename: + argfile.close() + except AttributeError: + pass + + # Handle post-operation behaviour (reset or other) + if operation_func == load_ram: + # the ESP is now running the loaded image, so let it run + print('Exiting immediately.') + elif args.after == 'hard_reset': + print('Hard resetting via RTS pin...') + esp.hard_reset() + elif args.after == 'soft_reset': + print('Soft resetting...') + # flash_finish will trigger a soft reset + esp.soft_reset(False) + else: + print('Staying in bootloader.') + if esp.IS_STUB: + esp.soft_reset(True) # exit stub back to ROM loader + + if not external_esp: + esp._port.close() + + else: + operation_func(args) + + +def get_port_list(): + if list_ports is None: + raise FatalError("Listing all serial ports is currently not available. Please try to specify the port when " + "running esptool.py or update the pyserial package to the latest version") + return sorted(ports.device for ports in list_ports.comports()) + + +def expand_file_arguments(argv): + """ Any argument starting with "@" gets replaced with all values read from a text file. + Text file arguments can be split by newline or by space. + Values are added "as-is", as if they were specified in this order on the command line. + """ + new_args = [] + expanded = False + for arg in argv: + if arg.startswith("@"): + expanded = True + with open(arg[1:], "r") as f: + for line in f.readlines(): + new_args += shlex.split(line) + else: + new_args.append(arg) + if expanded: + print("esptool.py %s" % (" ".join(new_args[1:]))) + return new_args + return argv + + +class FlashSizeAction(argparse.Action): + """ Custom flash size parser class to support backwards compatibility with megabit size arguments. + + (At next major relase, remove deprecated sizes and this can become a 'normal' choices= argument again.) + """ + def __init__(self, option_strings, dest, nargs=1, auto_detect=False, **kwargs): + super(FlashSizeAction, self).__init__(option_strings, dest, nargs, **kwargs) + self._auto_detect = auto_detect + + def __call__(self, parser, namespace, values, option_string=None): + try: + value = { + '2m': '256KB', + '4m': '512KB', + '8m': '1MB', + '16m': '2MB', + '32m': '4MB', + '16m-c1': '2MB-c1', + '32m-c1': '4MB-c1', + }[values[0]] + print("WARNING: Flash size arguments in megabits like '%s' are deprecated." % (values[0])) + print("Please use the equivalent size '%s'." % (value)) + print("Megabit arguments may be removed in a future release.") + except KeyError: + value = values[0] + + known_sizes = dict(ESP8266ROM.FLASH_SIZES) + known_sizes.update(ESP32ROM.FLASH_SIZES) + if self._auto_detect: + known_sizes['detect'] = 'detect' + known_sizes['keep'] = 'keep' + if value not in known_sizes: + raise argparse.ArgumentError(self, '%s is not a known flash size. Known sizes: %s' % (value, ", ".join(known_sizes.keys()))) + setattr(namespace, self.dest, value) + + +class SpiConnectionAction(argparse.Action): + """ Custom action to parse 'spi connection' override. Values are SPI, HSPI, or a sequence of 5 pin numbers separated by commas. + """ + def __call__(self, parser, namespace, value, option_string=None): + if value.upper() == "SPI": + value = 0 + elif value.upper() == "HSPI": + value = 1 + elif "," in value: + values = value.split(",") + if len(values) != 5: + raise argparse.ArgumentError(self, '%s is not a valid list of comma-separate pin numbers. Must be 5 numbers - CLK,Q,D,HD,CS.' % value) + try: + values = tuple(int(v, 0) for v in values) + except ValueError: + raise argparse.ArgumentError(self, '%s is not a valid argument. All pins must be numeric values' % values) + if any([v for v in values if v > 33 or v < 0]): + raise argparse.ArgumentError(self, 'Pin numbers must be in the range 0-33.') + # encode the pin numbers as a 32-bit integer with packed 6-bit values, the same way ESP32 ROM takes them + # TODO: make this less ESP32 ROM specific somehow... + clk, q, d, hd, cs = values + value = (hd << 24) | (cs << 18) | (d << 12) | (q << 6) | clk + else: + raise argparse.ArgumentError(self, '%s is not a valid spi-connection value. ' + 'Values are SPI, HSPI, or a sequence of 5 pin numbers CLK,Q,D,HD,CS).' % value) + setattr(namespace, self.dest, value) + + +class AddrFilenamePairAction(argparse.Action): + """ Custom parser class for the address/filename pairs passed as arguments """ + def __init__(self, option_strings, dest, nargs='+', **kwargs): + super(AddrFilenamePairAction, self).__init__(option_strings, dest, nargs, **kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + # validate pair arguments + pairs = [] + for i in range(0, len(values), 2): + try: + address = int(values[i], 0) + except ValueError: + raise argparse.ArgumentError(self, 'Address "%s" must be a number' % values[i]) + try: + argfile = open(values[i + 1], 'rb') + except IOError as e: + raise argparse.ArgumentError(self, e) + except IndexError: + raise argparse.ArgumentError(self, 'Must be pairs of an address and the binary filename to write there') + pairs.append((address, argfile)) + + # Sort the addresses and check for overlapping + end = 0 + for address, argfile in sorted(pairs, key=lambda x: x[0]): + argfile.seek(0, 2) # seek to end + size = argfile.tell() + argfile.seek(0) + sector_start = address & ~(ESPLoader.FLASH_SECTOR_SIZE - 1) + sector_end = ((address + size + ESPLoader.FLASH_SECTOR_SIZE - 1) & ~(ESPLoader.FLASH_SECTOR_SIZE - 1)) - 1 + if sector_start < end: + message = 'Detected overlap at address: 0x%x for file: %s' % (address, argfile.name) + raise argparse.ArgumentError(self, message) + end = sector_end + setattr(namespace, self.dest, pairs) + + +# Binary stub code (see flasher_stub dir for source & details) +ESP8266ROM.STUB_CODE = eval(zlib.decompress(base64.b64decode(b""" +eNq9PGtj1Da2f8V2QpIZJkWyPR6bR5lMkikUKJAuge6md+MnvdwCYcg22W7Y3359XpLsmSTQ14fAyJalo3OOzlv6z+ZpfX66edsrNo/O8/ToXKujc6Wm7T/66Lxp4G9+Co/sX9b+pfj2fvsgla5tI1X0Jz3T2G1P\ +p/LrwQ5/kMVmKPg3oyl1eHReQlt5Hswd5u0/0f7ReQ0/4G0OgNXt98kCXj1vWzF8C+Mm8EPLk3YENQYovn3RDqo8mP4n+GbWzjNGsBT11cUuQAg/ud/sBfx7OzEPgl38V75sJ6kLmgS+m7TwhPf99qGAQD9aoGpc\ +2e2wC8Jz6XG0CUuhhadJF9vyxx8O2n8shD/AMHNAUafTD51O8EnUQlMhrLdb8FUJj0yH8ICnAVII8ltGWAAJ6FWOLcMBqcsBwg71/acPdh4SG+Ulv81j09hql6tg4BbLuu3T5NxAcHDoY+G57tr1CnwA9lc9S8su\ +D9IMvY52kt5LXgjhzzTa+TedEeNV4DLIncWr1Bmk6Lzp7JR00NtdjTtAxA3AgmnASGa0rOQt0dyHESrZjql5TDTTRQ8VqV2J2eTP2n9qp6FDadx1wCyUM38RO40KGjk27jgfNB2pUbqQwVC1I0JU0SW9eYk9ZXUr\ +GUB1IaR9ygDoLmNlLj2wkctySqHnlJBoGrltvEIqTvfm+N/oMf53/sDw1Lf8q4gf8q+y/Ip/VWmGv9relQwNa6txSdPHGzI3f+sTTAB9BtKPtid+ojVs4yBfC3CT0urCvBVUZZi3Mq4Kc5A/YQ6iLcwZbzVL2tLg\ +C6YIWWwVEWOqpH2gEhfbAFL4KJhAb2DPMaFaaYYANqAqd4ftiCB584j35ZhIrrR/wZPrX3nCHCXTcGQkUvsDMBT6hHILDD7V7tMDGr5aWhH0QukaEMaUNsMDlSJv3euKSITf4+Gi/nD8PPzc5x9kI7ZSPqtZD9AP\ +LT8Khkzx8kKGslpBnQwZQBOm1gzkKX2mk4/yDSOw4jc9WZ/ZpzoMdoDHAhTtAEe5jk/Gs+e7YR5sILe1ckGX0QS6e6ydUnej0ddRiP+B/kL9qFXgNaBi9da2mXsLegR50OUoXQbB811mkMhlJFDKOaurFPR/xp81\ +NFsU2EnbScBy0KCJS6/F14QFczMhztYRD4tYbefKtDNXXRMAGdOzHPN20u3+rkpXcjjoAj6Z0J5EpCb8u1UX0XdAXXhagv3AMrRJFl4TyvNGHs4AqcCn9PwRPJ+TGlYK0EijX2DzgJfcDpvzsPC7qCwjZX2o0glD\ +hRMtLGBZ44yAdG3sl/Awm9hhCzvs/FeGsYiFiu6caZLxhFsNoZ+e7kpn5MkWnHc0cuOMvM0TJiSepb/ujv9Y3qzZLyuGKUeYQ6JgpZF3RzDbqTxTE9JrYIaUDiLtV2FnthvuKwfW9h0sdDynzS6IAnhL+L+Bj/9J\ +/Ibckck8G6TlDR0SoYP01v9aljRgMcG4WRnwZ6G7Fb3RDny46H94COtZw22D+qZBdTyiLmV5C6b9iadVHprDh4BwsrFrQGDT8N6PsA/sMgTyzYq5MhDbtbJvzFzN5Gsy4p2hCOZyxTgocFbAfCj2//wHAZrFXE07\ +jXa5g2GV/LfXC4hVzy8cahQN2f4q+YeL04beEJ1mQknHI5IJld6wXRX6JSoAXo5BxsDi6tCqaANmCJYlKFya4QRl+o9b2/unLIiS284i1UwmQ7hUiBO06NbZVXNM7B4sk9coiu+B8munTUOYbZajhv4AI2siTdPM\ +fLQUYJgqugkqec37jkxQxB9YyISsFoCmIm4hDIeOSyJQtCSvYedEsqn+jmsF9ZAeEKFLQ2hUWEZg8zAZiHCYWqf3YJCCZXdDo5NCmQlngbkbTVsfcleYbx2MQFId4wP8j3UfSEj4CNdO+uvZrjcNPXo9sYyD2k2B\ +dvM2YFhZnGZ0ZtF831HadfyFWCkTNB7T0OmSUhcdCW99TWPU4YwHA/yp5K4VlmloQWaBtEniiEbIrNTH1SF/NU9Jpi2Ey0VpKS9etcEYLJKEobXyyxgszorJDAZLdUF+OVKpdLfX1v0iH1t12pUB6a0tAPoV2Nze\ +Gti8hT/eQPouOrbcWCVqCvRridc16sbk9IB6FwYDy7kEQVTmVos2Da2e9Y52bM7OmltBr6sl2TBncci2skb985yMWEv+B4zXkmWrYfhtmqVRa8AI06/hX+TCVYwSfpcTq6FsRiyf07SmK8w6mUAsxLirK4gHuoM2\ +k8NfNdtmSKTbA7TYHkUYdHi0J2ajIoOCNlVEUOgkAI58SGtErcgET9EIb6w0hgfo6cRWWxoAk2XHbpVMY1P3dP/oiD0ahaGiMbX3f4Z/D8kZKcOOydaQMavRGtJjMa/QDECxJoYb2kTAEfFGaPsosfQTkrrGUXUs\ +ER4N2CB2DQodfuMYM1psiKZEbSbj+ew5AH1B0FUo5cU3YJbq+gaFPLQ+ATwGh7amnQMYCkgwVAqF/5jNQo2ydJtpoAnH3SkCssxrjvUVTb8D82fJ7I7PDmDI8Qw1FA4fgSuQjl8zKRIasKmXjXkUxV7khczpKrCs\ +moKxZQZAUA/k7UG+frk7EvDKWmd5yIyHRs1HVqHgQzT1B7KJYRlFCLJe5XeomQobtpBu0uCtpTOEFzkqccZCi5XNzOHuHCQM9QjBIU3HgsbQTz78ggvw1wt/ePKILbJ8780LioKk8UF+A2e4ydSKhb/AAI7P2lGQ\ +W+eP6B3EMWA75oBxjTTQ4623AGq+hYBsHOSDu9+D0vgE+NsmAQGefKvCHVsEd2mFoUOQTTVp4y16iXhAka8fuSJOJARFGECpwf8pCJAK/kEuamEgewH61wgX22MsfNTCRwzjRjmBmG98AWrleBfGfItxgOJHwNDC\ +X59zDIV1fhr660iYG/5djhFPyLWpcG+mYhqcZ0RS1IFsfechT7ym3gD6LmibICDx8T6sxJ2dPoZQgYpaSA7aOTHY97KdcALx1gNWr4pDJeEPJCFSdYuMDbR7o78Hrf11AJFS4hDQWBWq5V+s2NJRa48d+DHxzSGL\ +D/JfPe8FgHtIPqzobGH41Btz4BBN+x1Wyo0QC+SUbFvdoP1xADrwZWLDmqrB2Lhit7kknDWIg6jVzuCTzO2uUivEeNVSxqeQXFOPdg0O0S9CfcMPiuRuwHTpxIGBK4AizBIC/vGa0AWNnoh1cOKMWCFTlCsi68iG\ +CbLNDdph4EdDMAmJAG+L7cDabSTppyIUNeGyLD2wMTyEHaw+gKb5wFPUqJ3WB8AVnr8zAPODHKQ62iEagVPXVIck0DTptvWjzbtbczFKya2i9UOY4ioUfO9z9qPKik9i4KKFGbmrd5AzX8ZIjhjJBSP6t2KEV0Iq\ +Hxsco5wyDpCnAvbpUo89Z0UGkuh9LUzCBkXXivw8zuDPa3ZnYd2yjTvUxyTFZ61V1kgrBuqTxVGDPqliQqahL6Y80DdGmxiCeMaER0ykO6sWx5S3hiMTn0RiLEsE0pYfictx6u4SgZw+cR4AZehatXNWIOCrUDI8\ +TR58GwhgggjNIqNJnlr9QIExn6xfY+UD3TC4AlEK/FF5jTqGZEn8mkNOEzagKisbENARruB+L5LPaAVFhPipP4/odyM24hD2q9m9JwCK3y4AhAXekvxC/lanooENoTtsgUCYPN7dXUYvG5MGO/5Ho6XH5Pe2ZAWV\ +XLyHn/tCshe0Yci9O2Q6pfRAl26ckE0WjApfhSD/fzsz567evJ4Qo5LDVVk3BXPpFgSOzPT/0OwVZEtL9QwEp3rNNrnGgV+zB4at5glBBPbtsxteq1DRtySdioat7EjDW60/aVTqGyD3mxfH7zHGBKyeQQy2ZpMf\ +0bDBJgSqktguAqy/f3ic14r8MyN755yDcgUvZpc2jP3vWXESvAZxPxKDFMz3agbPQhGFY1rVAgwpuzBMkHUWtvAjWhWtEEz8CYdTMhNESme74FsXAYZKDg8kWaJOhD3AX0Grn/qcUR9ioixeANCvgFI/MoLK87m7\ +VX4NwAlBtwPFyTZhQhcwLjBfo32IVlYYs6w40t/JOM2MHArYvYKAfpocYybpPQee8sBuUdA1upr3rQe27liB5lcqULaCk7/1xKhfmfkK/8brVbLiXtilNssKmBKdsNpzokAkOiaoHH3wXJtWHB+ZOZyeYlbjkJEV\ +P9OnTEsgUE1BA0WCxTBD1NG0DzAkifJ6uK4gk6yCkq1RI+PvOzIeM1X+U+RFVnqUU3IsVqVP+hxIhgfyutli825Glu11Q5T0GqLUbNtRLHNhZEeGsgPt/Imo7zN8tflFyhtNN/8OkQEdtyXmakdX68M9P+3p9haX\ +HVUOhh2h0+doTwXeZOv33yePQZcRxC/hFTLOBCXYnOUzsv5jJ3yAMJd6zxVqC8qWPVq59yHVrpDKuNhjLs6BvRPuoP813MK1CTXZW0AXO8R8iN7tj4zkCn1feAHLey4fB0ML/REgcwthLxgJPIghcmBAHIgiD9Va\ +vh3kXz1h7mmFmBFoLHwjxomC8KAwriYnNQyEnwnHOvS/mt4CMCBpXYuFFQ7g3YBFaOUkRsFLVbs0CIbJ9N63VJ6UYQHAtzvDAYcleJ4BudEQccnBkAX5UY81Rx5LKLpJeQs3yfCmz/uqnFGSulLTb9gdhenSVxBW\ +SFlgF+VwHYkyQvBOwcyKZnkWUFxwd8nR6ZcQke4aRf0cFIrEEc75TsgLhiHaDinZWRpc/lydc5q5IPnbZI5WTG32mlES5OnMT088jLDntwi2ppkG3smHncN/2ogBzJZOJndOzhnZ6gzV4Rk0T070zFcL/B4DKa1D\ +VdQULsPNnHLxDhRu5BpQFp8Q5BmHorHECJRLHjk5LCMQZv4t+DqYvbL5tfbzTRIkmKhNPNpSmUc7CCvWctpJOW/OQrW7vdAEWY5jTAWOBfMMZgRfhzBR+YkiVBzF9QY7ZEhiFUTJfk9sAkpIGp5dxXYfly342QXr\ +Q3ymGLSYq21SepGrlcCcETDqowmzYZDLn7BBRoJgMvM5/VGkrfNKUwMSytRD+npnAMoFygA/O/lV/boIBP7hmU+pzaaEbhn6Mi9huBnwHXBThq723iwfLfyvSIhj+JxjqAWXQrRwbW9sOWn2zIYdU6eEAvznspPu\ +sj7UDdhnA5JGeSIyPdngIKqgv8buGCYB+VkO16Zgxih2Zsg5CzGo6GleHnKUGoAswKzJGK2Q1rhbt4kWHXZtQGBJBDXao6gKxrXLCzLVHc19DK/BfWqRvaWGG2hTGZgyEVpF6xxUCed+kpsl2nyvqXIIVMxSoOsz\ +TCEtxSPJL25o1zGJHDuoDsSD1MW96/WtkAvVH+LCiZ1XrAjUJfUm6Hfd7dhDWBjFINzkYfsgrHkmLBFKoMH/1KF7/pKIfowIDl2iRx2ip0T0TMOYsOdKB9YU0/e8yjzmbaqlWkLFSFko+9JYFht7R5sKxXweHHdJ\ ++4TQkwHHGhJ0bTpj8QXgYlKS42gT4v6xD0q8XPhbFHx4TVBJGdFiJsUWsdHvWLGREu3BcczI3jcerBvbcxw4SmugYYQ8nEBSokx2XL7RaNy2yLWxeBHHQb5BljtFVRdfyqdrAFhCk61gzstiOgt/4zqf/oxjVy1q\ +NvRDwl9GbncpcUajjBr6PkPTrGhMAgMg2MAMZs8ZTDuEHDYgYhsuYSWaDm8ZGxAokx0tNEdRgc5gpqRkaJW3Y+N8oCvc94AP6Ju++8s1HGygd93UD0B3MFMgfdwiEP4L31Sv3VKHf9tCKyxjmTg+YIdBvuekIEcB\ +GlDZTenfhH/voam3bN1+3Ye5NQR9zllQ8YTWBF14G4sbs/4Hrh+scWecN8UWEaZ1mwZMIs1/xTnZpxUUShTpHADTBSgPI7BUIkoEbK96h82S4lksz9cEN49F/n/Fss3oJqlzcjqjsoDcORC3wKgxSKSO+ilWqJ/a\ +VT8ssEQDwdxrtqJKh6sU0C4rncyxPH6rAipWaZ+5VT2fF63VEMrEYE7CQaDLo7V/kNqxAU0W5ZM/TeXs4D6+hsaBlDMqUTgYz/AGWopkltUOkRW1TWFJqYu1Dj1JZ7A5iUNN2PhtIhQGU6415iA8RmyRotBIbjki\ +vRvF94wesln6hg1lp7qlb4ZzzQr7J1XUEx0Y9SzcqGdDoU6OsOrixZyC6l0rENgoo6i2NjwiyeU17zJWYUJaamkyeB1qodOglq1CIpnSSCPgXFOzUxI1dLF+mQGgMnUbjU5mjDSPphGbIJi7QUMgZIMz4thE5aiT\ +S2hxBqi94FoprLGYAGT5bAkzewj+unf5Jqq4ZkSFHXb+dRk7xNAzFzs4/NTT04eCndDBDuY9Rf8kS3Jn0Mqd/L2gpm8jveXsN9viTRXuO5os7iBm6iBGcTwXQ+aIzHDe5cwWATCUvvkCjkEhQwNcadxQssMUikhA\ +gg4rDCHug2lWxAuWJr8JuAB6wxcyt+bHm4INfk5aYsHt+OwuJ0cS9zTGl4XMNEf4VfLjkgx1QmZXZrxaA2zj+qRHTiHMAvu6kcrE/caNUR73YpRJ1wyy6emuQzdnBYKuHEiEji/Hdbo791aLVkynNH+yGwdZruIv\ +8eG+hA0QyGSbeXw5+9Jlhz/Ik5vLkbO/xI3LOWlsCX/cJfxvd+XYHPtrXTl9UxaDWmUYpRg1yjcgYtlQRndjuMYiZQuFxztO3cN21FhOU3++wUUyDFbeZDbIdn2qrrpMdmSfJTuyCftXLGpc8ZHbzwrKc1oJMqTs\ +zrsO9ri6ERFY5FsfWFPm5Nie/EsqH/2b2gYIUyNJSJ2r28EiH9yj/U9GBxfJ7VDEEi2lHDGHp0sw1WtEg0/VEk0++j5DYxgDeHehKAOSiU3+6WiBL8qN+c/X1WHIwZ/cmD+EqUGLj4V/83iIrMLxkvyEMLPmEAFI\ +06rjfRHn+YC1nSreH1KtiaTAbdmBSTwVzBCsT+W5xqZR3+GdAB+Ed0CLghcOmRotssr0UzQK5D7VWGDUpF/fvHBLTySuekHMmBq/ZCEnpubsdNU+HwmELYBKYsIOkUQKU3EIsQ7FcxKDnydBR2xiJazby8+rn+mJ\ +1OzPrZ+5gNWY2hlKPHcKsCAh5pYctDy0DtWDOQfuuWyh0T6fvQZI6McTPGaXxybpvO8cPIEdCf5165a3/rVHCQ9t4gfABo8vK9v5AgpkTAEi3R+f+pOiDXSPTruocmtz3n1JXGqExQCQGc2zYnVFWydONZEixYns\ +3bOdN5zEQEW6JTk3qWkd0AMqyuGamgpD5jK0j9JjtJYVtmwvNRE86YUBuw0OH8SP4GhDicZ4dAn7pMw+aZ99QF/+AFOKjYscnfHZpexcmEmKGCjXSBGqkusUJdEocTbWDMBqEPevMVLhD5gyIR8SDn+CH5gnBOY2\ +SefCH7NKA1piL3AV8Aef8qu4mh0zLmOubJd9DLWWqta/sNyHStJUqqXHF/bYA554ip9IIoz/xp+4a3mOgGCU7Ua/vss1uEWoUpkN1tGGtv4bngESINOIucWcKwylT0Tv5A/9+JwOnJo+8RXvxle8S654N+m+A9hq\ +bqdFcBtW8U0GqJ2uQfgDWLhglGfquON1ha76gk/tYMOMTzqG30CGtYHykybHAxSz1khYYqr9jxh3PiBE0XGJbdqG5XhBOUBtcsvTM6I9MN8O5NVzYh45ywJRisk2V6liHZBUvifLlxZgQhrEKSZ9cyZnQyStQsth\ +VXkoMpk5qeaUWs31Y5jii5Y8UydQy/6BkvQhqnUMnuYH/nBrrYC8cIVFBHj+8QX/gI5Y24n2w2AtRcO7uHWQDz/YWxrK/Hvvllfk6z8cLTxIx45PxnJ6EMCeUdQmxbphPJ42vUFbWTuHFPE4ayP0KnGrbZrT3gtE\ ++5CNJ7ZCUaakW/dooMIcMrql5VQALAL9P0kGsrFemYCZnCKbDEDUJRPnhGHbYQGDo9YM5//gQgY5dWXz6PIwgzHK5CXaG9s2p69ASKDMw3I+SE7qG4y7zknxreWHafKcH6YCCpbLPRVonJMXaK71vi+Vo1dB2TZ4\ +S4rf7+lx3YWUAVTcExcLriFM36iRB04QeDeMFWOBtjBhgJwOcwR8KCUda+dwrD0BK+cLIwh0N8X5p5/evvrxwZP03ta25VnUQunymmq3GiOkTVBKICxhBwg/DldgWQaHwDd2RJsctcCDH9Pth3w8Bs/4Z5mVbShL\ +4bx+xZfR0J0DKUlFex5PUSlhCokIPKuf3bOz6hLPQOEkpqM9FwbwdDKdDQe4y0RCesLueLgFe60zqULI5rk3QJShj3c8+HjHg493PPj3SQJr7V7g0r/uw9aBQsPKk2P3tpVjn7NMnUt5SII51ykwf4ZHp3hAyWdz\ +V8t2cK8lKNliQOGBZbElHRwCnKNzBVWXKnZhMpf5dG4SaB3iBd4PhLQ3hgrwrcSOuEyVPvY5dtzwRTcWeGaBMvXp2gSoRDE7buV1OEbGyyULBm+hi9FwCb0wt4NU98CWUuuHu1JPncltRnmno1x/0Uw6jx92rnjA\ +2y0OT5cQZqqbqHBDBUtLSpeuUZnaG26MfovdNTtcUYbsTJT6k5QI4c1NwYi+0ngqerJvl2XSVRNCHyY8yrFzFVQiRXR11LnXqX+hhYvJQ7wLI33M+lBO8IQ7/4GBIR8Bj4p09CzibVRCvZ6YK7gzwnSUc/apmX4v\ +96yYORJDLXPNE541hVOfmL7rAggyslKfR7P0sYfPs8fpaLg2GAm7pv5qbnwsN83ISxSWIAFK/ZIxCZGRJgUnMts5Ov0AG/S5lbIYxOBrWiSjoMVZiXlPlBRkgLNWsJKq3Fl9zAeph7TaesxhfTQ5t0ag7NFVD0lN\ +o/naWBsB/Rs8EaWegoemvubLWKRjR2vCqU6Sx/Hg6Ai/fHCXVWYDuYYSan1aaQzhxfQDIBDAT5+zM9fYy648QaZ7kZNSz+8R9hweP5XDWPEMQxnq8c7DG2abQt/xYIwp5/jbYLjmjXYG+1IdF9Rys8N7Grejs1It\ +6mXsrZGiu0r0qDs9oiNw5nQvl0prud6kYnXZFH1MSodySeq6V14UcrRVbntLLhun4g7xinty0mvlaUecWEVCigW59Taou44lHFjzRzxUucFFxAz4dxlVxZDqx52HP0Ir8i8D7ZWrEk+6t5GBhYwldUiLEm9umcbO\ +M/TvMrnjySHB0m6FrYk71exPe7+T7NWArXXF6JBNO15xVwip/wwtC76vQlwEzFc0fHNRRUcnFljowEfRlbYbojNoGT6BYbXSngMLbtJquXvFjmBlgrKHYJ9WvgjJ0I5BN/2w5l26/agOHdkcYe99Wfe2jWx0hRHy\ +ZElor2rrm+KJus8UCV2utFcInfKNUkXxGxj9Z5eJfnIbp27j3G1cdBkv7V2Ll/Xb7rVlaXlnhY7ItDVESENUvD1KMS8AW8CKwJLIny5LtjQw9giSZ8SphDxC5bZjeajqEHrPuTVFHVSyd9+SG7qa93LRz3KyDjZt\ +3sC1Nclrt97zAR004exSMVl10Vksihv5Z7hjYZ7fc+mUU3wC+1ZsAsmk+A3biRHfNyN3YhA0oMNCL5eI3D02KPMGrq1JnsilD7dYy+WrbjCrUpk1ekUTpSUHidA3mb1lX8FcyNLLUEKtiVxOZgycfA9viNyXS/EA\ +tHqbt8+Yry1p2JlGBCC0vIJKbTPIWbmCTGVuZ0MXMscbPDCVMRYAKBWOSQ2IvwJvYBVW82wkzEUJL5v6tXsYj6bjLHKSSc2e/OxTNNucA0jlKi+14m4husUhl0+CowXuSRic7Lt95+g2ZxQ0Kr7vpOQrNMgEaOJg\ +1yZcar7JgrBr7iudyGmCje8GWHXayGUMHYDTJYD3RSr650tikDSd1MuiXTVxNqPBQNqPOsi1Lzlay3hTQN7dU+D0pi/vWgfZXLKXOL6UJN70bxGwEJIJZyJV0a37hvgEK1VKJwbg5r7N+Q0FxU50g0Sj5EzdeIMP\ +ZmAat3DuTaoKvJQCp4Cvy2BgszvkHhuDCC9lHdvzDZrmw/ssrEiXgfHwayiwF51PrBFmPruQS+yazjnXNaxpCp8Bo+GB+wjOhRTjwbM9Sz4d2yNlgooJHkhUzDW6CMxZDKXBUC/2Dvn8Yz1hPQmdHABSqhbBJ5PE\ +iWeEqww1+tt7eGivLuRe7SK2AP7QhR9iH5ctgYIhFMxrgZ0xnM0h16c1bgeZpcRi0isB6YOLc4Kr1g5/6skRKU66LX0Tuti1rzdHHt6Y/M+Pp/kC7k3WahKn8WQSx+2b+t3p4t/uw7R9WOWnOV+w3LkPFnff2LG6\ +pXhXIpRyYJ8L2zLe2nihbVk4DTDyTANvAMGLnKc7XKqAfWrz+G8U8sDHuTIN27sg8YodqtppYO+i19v+SimS05sZol51I8NVTgPDy+rS4YhxljpwShetiek9Pm6uphdk3re/7vB9znK1cDO+dIpVv26Te9N5psyv\ +93zdkZr+n0Hof80clFK0yCtXYJf5OxEIi8+E68t/2SxS27jvwIXFTgLx0j26/RxD1Gv3vcTeiU5bN4t/3cvDF7092ZvbvVAJTbVOELBj1HSstP4Vzp2AhF5xcbTu9de992GvHfXaca+d9Nppr11227oHj+7099xG\ +p6d7W7U+vvr+4z/0T1/TDr+Qh67jqet4rN9OrmlPrmmnV7ZPr2i9u6LVucl6Zbu8sr24au9c+/el+zb5IhydfsG6+5A310iBHuS6B0n/GnPdGW/Nbdx0G51h77iNXbfRsSw6BPnYkzQ9OPNeu+y162jFLtF/4S7+\ +s6XA75USv1eK/F4p83ul0HXtL/zTygYmzQ6c4M6jSiRxNWJzzTffeicxPLPTVum4S1e6yVara+RGk1DFafrp/wG5amLt\ +"""))) +ESP32ROM.STUB_CODE = eval(zlib.decompress(base64.b64decode(b""" +eNqNWntz3LYR/yoUrXfkDMDjkaDHre8uyunhtJGcRJYyN01JkIwzcTWyfKnOqtzPXuyLAHmXpH9QAkE8dhe7v33g/rO3bFbLvRdRtbdYKeMetVi16avFStvgBRrdS5kuVk3lXmoY5r9kU2huuXbpnnaxsiqCHlg1\ +cd/aote97/6kUbRcrAq3VZO418w9Y7+bUjBrTLOMdv+z3gqOFFjbkWMMUV9Cn3JLNsqzo6q4BRJcb+6GwhoprAOU6t6CBQ3TtetVAdcmYtZbE7LqKIf59YAoR4yjAEYatX11Sl9xZPn/jBzuDo9WUXcS0eBM8DFC\ +UQPissJeRUsqS9LwGzOnSFUVCLgYUFgk76jhe1DUV5/WWXErPrneBLiJVRTR0WxiR6kJ0dsIsW6cO5ei9KQ0dSA4OySrGDDUp2rznvxo3zbKz7aKNRoWkAcHptFAvZGaJGb+sq9Aa4ET4zlpSvpajkXAZkbnAKPg\ +v04vRRFzVuTKxEDTiKzK2tEliRMXtaLp8cSN1XrH9Y+Ck1PcBrZwhaCzf+4j96VOel/e2N4pX8Ooq9+I7MkI+ouZic+/Oov7wi1UIDhlJtwygWxx2zR8n0ykdUrdOKdIu6VElystQo3QrB3L1Yg3FhmP+8hQBO0O\ +DAo+YhPqcZUcBDbMkixYk3sjC4AE4xkuFB2cdudqC6Lacl83ySbXPMNRWVQhZiVnQ5MKNkDVLz01spmIFNs5WMCcB6ee84axsoQ2ayPuH5qKRdCpgqm4HqgkrAmwoNQTLQBftFug0XOYFNpRqFO3oVyLxbJbpt9/\ +25+1JKLrgFBDxrHsCYcF2Tfqi+fgLxhGpqQYbXudXowsWyBoyugaDO3H7y4WiylBP812mtQwphhz7ASW8QmghW0T42i7Cf0XUYUoBTarU+BxBGBXJRHrIttW6IOMfRGTRtr04Pt9mPgiPoB/+ymIyhnYECtNH+jR\ +aO7IUbblq9Nt5B/GxySJktXLUVszdpY14Z0JMNRT9Rc4EISihMTRyAlo0sky8UoP/VoQRDdMh1hc4vVOTGng5EpsRWF/8otY4haTDjrZrmNaKMhSPWOAGzppgGuBbCUQAsvAWSKlCZFB7J3CAGDOTsXNJaGbxh59\ +YJDCFE49Phypl1P2psnBdXHKOoIK/BykaUCapZz0eEjlERHRuT8QAo9VfFoJmyMMa+gI4HtdsUiqDSKRMZZVfNRfG+fKmobXyf9gnZrHpOtj1j0rcfJCwrfEf0P14XddxQxPFXs8oKZNfy/ckfZ1+OJAqUbMnwBq\ +fMkGAMjVdYObBH7dS7a1RTTUmlU3CMF6tpl5bLv07qNC47n4yq1oa/bmckKBlwlXau2hH1yx8a2RMBpOPI/Jx15ZiibRDthcq2A2IHFZMuw3Gw4Q+osgXqhkzo7XUlKPrB8IKYU6a3//gL16WObD2j9Tj/fh4b0L\ +X+7Cl2X4sgpfQKI/M/jVqjMe2O8dm9FW6aPWMILVZXtGfGpEtcqLEe03PVrc3sBCs5aHbDzTS58jIM+1rP4DeKXxW3dAhrU8y1lONe2L4zeYqw9uPwTHhUQ+XiJJ851gJB7b5CPJXTNCS75DOna3Eh3NIVASP2Q3\ ++iE3qfxAnV1qMH6Dru3xAwOIDXIJDCnceVW4di3oj4e/49Mz2l4o+ie4VCajMkMyHuPH45xQtWY2a5T8xXIzmyYHd5yTXMUrKDrKW+B4/p6X0aE44cu+F6V89IRccazVUDxUMqUIXNl7Wqaq3Nec9wPgwrAT2M++\ +Xix/BMHAjNeCcz9wijny9lu2vEdOwYM17ddAwptd2AIkAUlv8pZEAlSAJReoI06SFUgSFBdtn5kp2g32P/ZpE65gNmEBnWsjKDSWwzxCB6bpCP/IsDHWta++PZ2eEbVcDICYETClAhxOeT68KF9KwBQhfTXIsDak\ +Z6CopucSJr38cRiMIkkEvN2Lk9lesEIa1DBEiYSEgA3JLHmRyqc4T+9464ZR6Vpiysn7Q/RGJmGnpB2+UMtaan1D/yDAHPMygKAFsbMib6YoAHLe67pDu2/IkwPauSmak9C66ez3Ni4RyDi6Ub/nIGAWwo0mh4nT\ +O0cwA6+pXsc5oEa+Q2dJO7wmk7A64vASg4dGQAQ2A41vtqQxlQTz8NmwtlJ1huhGAyrDOqgg+Px45j1svabiU0HgN6TgQHlYTXIqfBH7GPOAA3r9380oXJsNIrLZWpUqoaOqSjIlm04gDQaXiRDbJfQR1cYgOlVs\ +cptxh5xKxfzV+py3DDoRjyyJB0LtUoeIt9n/OuorG8L64QhCIDhz0O06+aLHFgTR2f0atyNhp+sFpzSaTYHnGTs7jYP2sFPfXy6WN5e7lMODE9A2f6AVwFegjiGBMnt0zw2sFR3DGnfHUYuN07jbF0L09Oxy3o9V\ +tN2eXULEBtAldQygGLSJ9BQobSg5b9s/3vQDWY1zcXcADSeE0joJ4x1YKvWuATqbZkc6d8iLte3cq6xS9z1BoeEVOT1IQEYQrtRD8ff2ZwkhSCdRQbKHqOXBNvsgnScgyhZhLZm/ZaFku9BoT7BT8KV96xetEPrm\ +cadCWEAL6QGtx7ajB7d48P3ondScnICCHItmzUm3ZMmqt+RcUIuDsEIOb7Cxyma062FLoqddv5XhiyUSxAAB0R14OCj79MXJqT3QqztFoX37273ttOgk7P5Xlwug3UpZBvOhZCirRASlw2GKhuh8O+jU0qmJOJX2\ +PVc3cDTk6CxIxGFAOhxwylEayuNe9HhOMYecis6vto8AMJabcukloRVwjaFdR9guFe2QWlyFjrFE0cxAkZJ7+Du6A6uPfK2qSq9IFQC4wFmUGALfHZM7xzJTyYGcCfwvPJCJG/1uLUp7Ad73nv0O5A4le3kHgXs+\ +2O7yzq5UdkVVnbaZe8GX/LRYOVxLB68OKUc1+rUUVB8k5znnUJi2fzBUFrJByj1g5XojK8U6K1cU3oLMbHbH+EHgIyfBoGFseOpsGTlRYUo+OrB34M9mNlhLaf7UrZVJASYmFkpsJAStle5ChC493rRSKP5Co/dE\ +BUkvYJ1IGElOSC9oymfe2YAnh7I3aRnrDFVvfyPltNkqUGcAzSo9OoVoRx+xfEMLoI1K2QhJXyV+q7slIRMgYMM10xK9yJRwHw4BIudG39QzsLsvPm3T0gWozOgziiP7tase37OX5hNxiy3DE8ywangLer+6gaXj\ +GbsOiAELLiCH2XWhHt2fkTh7QQCIDM2wxlKSuaPJV6TuUJfGfrwoUSeHXMaUcsxYPCKXlWGs1hNoRDN/pp2Gka9kxU67ITm7UaxxqOOoY4YDUXDDBZbfEWG+C+/z6gDGE7HNvsCWFEAUJpV+c0XlRw1QmRzjwX4P\ +tH4TBgc0JjQPzaipU8FvQU6MPw2YIyiHhRC6wqoZXsRostoharqlbzv1nM9CqN09lh1eSVoRc0o89kYyXBD9YxtkNiXIo6/UgBBo3s0E9H9K0U6R/G1x+0S1XdSMJtAMEIMoORgenAd431oHpcSmTwrpPeXsVq8O\ +uMhdYFzCVVwAKryfSrYW97ukCBgiSWG3SZ5jjecJ2oCeGoGuDIu/LnC4B009JgWw7EurPKWgWnV19vY4iJjMJoNX82e9Q/DQZLOIta7OxbDfrGK+PwQpYt2h+QRvn1ljMn/3XclNWeM1CQO0qjNhytOx9ojeeQSB\ +wG/QuKNt9NBF2+zqxisERvGNfCrwesYdx8nL8wn16TTUAfSdjlSp3LfdVcsjSbIwv7x+wJ1vmbT2EZz7HaX5Vp3kRI/ODihexRiuolIUZr7Zo4+pNVQ+wP/ofMqVgWbF0IGfO+O8CaKFcioxwB0BuhnddHSTMO7k\ +oj4pQRMAhQ3XwhpQLNJLN6SRDw0BcNteSaWpS0bELbWYdUxO0NhJceafMGatfThLtZzdwA82nGeZwBCdCuw9cEaDwz5CP6yMMIu8B99V9oKDZMqAAzyrE6TqW3lN8fXjnK9Qmn48SPgjBZ4GlFWMF9SlXDPaLQqq\ +UDxSNWqG6SvZc3QMMQHkrRqxGbPYaDsiVwEuBDeX86kqskXDRewhWKDLGvFFYUfxOrZh/huwWWOUAaTIHboPQEwM59BwIGutn1mJ+xrNwjyOyET3VVURDcOqKxNo+W61Gd/6igfm+M2fJIa/gp8K7RzvUNSx3C+m\ +VNgDTNJc2ANtKOROKbwOKZKSQLIZ38hl1FZ3w7PHtwuZ2DfC7h5BLZgnZO/N+HLDFSRNBu5tKtwzx3j1teHYdHbeFfzxOvItXEfm53gdme/nE+BZnXFMWQo+kajYX3fSehBdeoC4gLZ2g23O5ULLYJrJbS6G983W\ +rxwE0CX8fUkm3WBNRWE9K9vfFTQBHjE1xGT6hXdrJVtGg26teePvZa3e+olzkIImgpaCJpb6H1yN5XsaKyUDS3EStg1dg1Ep6ud1IVoMAiqzC9t98I6zZIW0eOMNXyV9qMiBlnDbbLgQCyMBTkDIlDZEdIHOr1gK\ +jPyKWDAsySfhrZ6IuKH0s2z4blR+HRHcKorMKATY+YnVkOm2KJ0D/DmS/hIOZ98QxIMOYlDaam5wxFpnB1xDB62Dq5Oa9YXqawdsP6hl+dn1PPg9iH1JqEWY/ETy1WwwRTvdhrmioebge0BxAQKjt8KvxcH1/N/y\ +dT++SggDyy7oOt6AXOCUEfH1X9e/Gj0dds5vux1AxaEAAL/p8Ju8/DN4zNYHYLurkbCS9W/Qut+ZiS52WQJX6uinIHTzbTFw4vt8DAdzHxcptLTRE3kdHyzu0nCV78Z0AmaQzq7dJKuDZ7IvWmgsC7dQ9KE94+5G\ +es//WItIw9HP+V5n0211LT8iE9ay3tTYk9KX1d5RhD9m/OnjsryHnzRqlafjxAkxdV+a2+X9p65Tp0XmOutyWQa/feSa/x5/CRcaZWo8TtPP/wO9arcm\ +"""))) +ESP32S2ROM.STUB_CODE = eval(zlib.decompress(base64.b64decode(b""" +eNqNW3t31LYS/yobQ5INgVvJ67Vl2p5soN0ToA+S0jTl5JzGku2EHm5usg2wodDPfjUvS951uPcPE68sjUajefxmJP7evmmWN9uPR3b7dKmMfxQ8Z6dL7aIf9MI/Krd7umybPd8nNOf78GfDf6j8054unRpBC5BM\ +/be27DWP/T/ZyL+WmX/8VE3qW3L/TOPZYOCUBhrt/+Y9Ip4VIO8pGEPcV9Cmbjw5FS3HJi1w4VsL3xVoZEAHmNU9giV107Vv7Xh4NZrtvVKzPVqh5xbG1CuMeAb8rAbe1P3jA/qKPav/p2d/Rnge+lnhL/+JHiOM\ +NCAZJyuxREk5WniYjxeFzNhIluUKY2V6QS+hBaV6fLu+Ak/xk29NYRGJgn2EXVhfBTwz4rcRZn0/vwVlFVhp6khebpWtcmVBfa6G5+RHh3ejotGK9RcIyIMds5Hs84awkia8uPwpaCcsw4RlNBV9raYiXfOENgF6\ +wV+dHYrCFayw1iTA0IQMyLnJIckSiTrR6GTm+2q96dsn0bYpfoc1IYWosb/pE/+lTntfjlxvi0+g1/E7Yns2gfbyiUmeP32W9CVbqkhqsBswfVvviSJHcs7i37OZvB0AcR4DNs/URJetFrmO2IJBojWzW4qkp30/\ +UEbvnemXvMsmVmWb7kTWy/IsWZl7PUtwACYsGx7YPu1315W0Csdt3SCXnvAIz2VpYw+VPlu1qmgC1P4qcCOTiVTxvQAjmHPnLKy8Yc9YwTvrJM4fW4tDd2OjoUgPFBNogmdQ6hMRgC/aE2j0HAbFphRr1mUs1/L0\ +piPTb7/sj7ohpuuIUUMmctMTDgty1a5ROdAgQekymE/PeCfQzP0Pm0U/SkV9SMMiT1y6hO1w0veEccyoUnpkk8Tme3ElJ1Md7J8P0IznnK5/j5fcKomxtnszTkcr2gi+MtYiZ2g3Ko6INlq5iUJAbyEcM8xK/NOZ\ +RLq92W40NVNir21SodSOMbTpEFclLhtHOl9NA9d+1su7N4B4GPenrWpgcEMsOBHFaxMOcBDged4bMNnxjuhdk0fxEeJWRaGls09YBggPhYzmASa4A152BG+gpQ79sh/Uzh74fyvyOiA2cMWwSFBvtEtmBHUkXQ9N\ +uGXNl3WAnk7kKc3mOjmwKaenC9Y//6W2TdjvrtHNSfN6HHQjOjoc3sqV0TUvyQxFXGLvcbq+VDQH/q1t0sV/nqvNhkmFiXGl02BLce/KiFVUmbwpJV6hYUvBNXv1qdjJwf72ZDd55DtWbBJuBX6KvaI2+MfWBClQ\ +ZYv1vTM6CZIT7CEWcKcjmKwTAl0FPwyS90xdxhsHOjXZYj2GiM1MKbebVl/WLYQ+zD/FC4wsqD7IZUvTKhPZSxTInvYBmWyHc9eRke4joj3JXk4cIySQ4OQEvMnrX16enu4TBKfVeC7rzlV85yfJOTYiArpPu4Q6\ +kJISunIdQgLzOgNOJoBEbTpi0aYDe+QeJ6xd2c6rMQx8nOzAn3EGWuEBUE8vrygzaSvEPREYnwncsaxzFb/lVUDnDjmIPJxGqDMCcU6Ey2qVyx9xx0F8sGhQPImVmkxHAo3gFy2ID8CiKyJslAaE0KaDiQg6MDNa\ +i9WW50NzYV1t2oGgpu4zEF0N2KCp7ZoX04SkkEO2c1rWAXSARbl9yUXSOIXCFr1jEF1A0lglDybqm31x6Tsn5UEHzh9haAERVrLd0+FcIaSwJ/GPt0e8ycYteIONkzblfqHEZmODNgN0WKu79hMVvsNTh8GhkUN5\ ++dSxGWeRd7oDQ7TuQegsDmmNhTWf8jwhdH/sKG4jZOQ4bKPRYP4Q1u5yITiujDIVG8aAwjeKpE9+M++nYErhXrihjXgbC/8i/nEV/7iJfyzjHwyZ0A9tVCuprhXrw8TpCWrl/g/BJCkJsEEOgE0Wgu5+59pCiv6x\ +PYVKSb5JcGA9xj8kVPNwVXiHYj/eWzoWra5+Bbg7/c3vQkFEXP51hHVyWoDM1I82/rdlguKtNXqKj4dsFBmyPt+MRmASMPuLoqtmxyJBihTqaikKWfQV0k2GHCr4p2sKVh3Amh6hj/54zc7eibNH53QFyx0xbQ3N\ +kslAzieBhxkgnqDslLPHtGtw8WPy8buC3ELNC62R15c3wws1heTiecieGQpfwlbP3/KSm1iw8GUchOnqVUaOGYg3BLyrCEqp/C2RsXYTkAcrbYEjFmDt359eviZFqNIXgpt+5YrVJPAIBlu1PEtBcdAV7ffAxNEW\ +TAKyACCT/kZCgQYw3bKJHE/eN/dKrS4GVLwNAUTCbWf3igdLsEMlbURmGlweYfQJYXTaT7T/ytO2A+ZD0G8UaXfzv/Axy7He+/lg/xnASoKDn4iGSmcH36BbqClM+YYo8TFnlOVgxQK/hKqnmc32VspDA7UlL4Vt\ +aR3DnKv1OsNGYnpBZ9arkA2uJySX+ENnUQlWVFY4awMINtEYG5VtTgkC4Gx1nDVXcdZcc2Z9IlAa1KLJhMvsipuVeidh0VDWQ9FSPRMIbqYdGP9aunayw2ai9fZaSDp5M9kOvi3fS1/1gd/K7H3HAcnuoqOZc/IG\ +qbGgSrDnBDHtEwYb4gjXguuGqHBk2SGEPQF0p14kBcCoAtS3kRlekN46Peq0uiEb87Q+g/Q38N99QiFt++Bev+K8cQ8+P+PcFtaABLr8qd21ADQm1O6k4NewC0vZqKYR7G3WM/zSfUOGGxJvkVLc1UYe1qVBaJyV\ +3fT94pdqJmW1zghSzwJu70JLdUe9hL8DKl+l1Ru/lo/ts5NcOXN4mQSsu8Mm1kuxbJQRojfA5zWHnnpoGoScR+QlQVvi+TwcGJgSaJmBJeEcZkAzK722lJT0FZIDcMkum0HRFjAWph1d+XlEJm44kwUNwGkG9r6N\ +3DxCId5lF7VbPWa+U16xilWqcgPc09j9LRj4YHIEbmZ3TkncUGHEsuPnxVqhdHYG+C9/z1A5UjfumRwIkT8H1AVkHqHCsh0GVevt1+Tl2pbrpDzbBSMkTWkqVeUZUXKXN9QFyZZ3TLe23bBhksOWA3WGSAcmLMSU\ +8o7+F9xtibh59/UWvtp94NOy98D6wRjbYDHp4enN7eEW1d2BgnbFB6Kha66TFLIzMH6y4JdURKCv2lELW6wukp7A8jeH/cxAuy3r52vYwbHVwUaRUwUaTTAAI15xYuM5OREGnOiz2eocOp+dhQK6zSmdjmtLAFpK\ +1y92QdJTxe3TgIyA67oLuj3ZAbL9wPJKCbFVWEk6L37C7qmXRd2wleXvR23X8500zrEEsyVpwIkUmbcwBMyZCOb5qj3m2XNyAErNk8jTx7zAbpU18YIzvA/tFoPanLYVa0s0ak6+U+jZQG9O4pTyty5lE+MpFR6V\ ++fl2W5I8zXcofUF9zovgXlt5b3sy5HmAUcnzYKzur+5192W7x8J1l3pT0EMKCy5ppr2JJp10WumgUN/vyU+NPzMml62Sm/TIvQKtkE9ZEN0PUbVdJmphY20ZvugCcgjzCDQdNrYBP7A/4DqgpoiwfQm+Hah0Bd4t\ +TnQyIcmKghZnsWq+QFx+BeyOwnGTzY45/oAdkCO84sNGPDKqOGMyAXriuRvUbIxeO9M4fgxAdMF5H6TyVc4naI7S6LgYyMUohLPHVAdsm3l0xsJPi0DnX2uTPaBMH2F/I/74A83nGxecehILHwzhWnRmkz4LvJzN\ +weWU68s5pgwLQxbZ80K8jGwFO4UyjXXgM1XI0EJl41D6kE3lF7FS8BcxXMNpisUqvklswGlN5LEq9Z4CP44xEWdKRxRNtA1GzuAbywffbQcCZVXp+crYVLg5Qm4k5DQh6kksQo5K5OhzOA4ljsBZGCXTdsdIzZdZ\ +mC+xFpSG6a/eE0swdw0QpkSsX72j2pecdkHgBZBjStCaOt+93SLieHg8+Yznknmv+F79JyLBFUyMZR1fOXmzshTp/IncHUMUlBOmVnGUdNHynTq7BcnwTkKpyKwcqECEh+7+uSHz6CqpCmkWX5GoSomR0yhecpYL\ +nGGQx/dR1CEP61JdPJXj9LhjEQKu0lKFHkVr6o6q9NmSdtvkxyi/Y/YHIivTCZAFaxiqGM7Lu+qROEwUYMGnBGgNP8t51pxEPf8xxAoTLwoN6Twe+lzOlhfgc0ELQIUc5IpiWVEBbgVPen4vBfm26qMY2tMVTEvm\ +eyBTziR3Sfpw3E0GsjaIfG2/lFCJVw8S4TISOud0/lj61vsEo0AbjOf1E7lHL/aF8FASnmi0GAvFIseHRHYggeusBuPPcoePX0q5aYD+s+CTDjxO3UKVWUQnDFgucFd/d4EWXWkVH0JA5QxFZ2kqWASc/Wh1DkQp\ +a1uWGHHag8jBRhgyktD8/p3OdAMVk3E4RFtztEwYZ8FZDiLw5jYyEA6nhJk4OeLdE11rTEA3EH6D6f+bOhh1TqNAtgWY8OQKU4dVR5L/ToHbQObZyNeShYhnt9/+xOaMR/YrWlGW3zMbAx6lrOxF+wI6vTm9ZM4g\ +V6vAaarPbM1FSVe0wDABt0Kll/bnlrEVpGS9Ihkum8//dVX9A7wvWWw5Fcwie+aiK0n8lisbZZC4zjnUlt4rX4qUr/i+T4s4yQHiPuOqGJRREFjSnaBNbN/E3P0YkgEbgXdxVoqvxuj86Tl6n3YuavUPgmOB8Qbh\ +yJbAYTwaB73J7w0iUZcvO3hpBxHsfrD2msu6faSq8z/W4SSMHDF8rysZFifScMBRd8mzZBagA1hjR13HHP4X+EURqoOc7arpb/xGLaU+6WXnXIogfwDHrxmgFyhDUPTAosRoF+MDB0Gs+xdnVOJyWMGpB/L1lFJC\ +vJmkX693ABtx0/7Ka7yuh0evjCNsyiVo73Kb25DJSZlNKuqDSSUoCiaV1o6YXctqxaxrs3kWrg/YtY34cooMKztaXdk1V3CcZT+AARajbsupPCaYju2roNssiMSw2LzfL6p3u1pNv5IkeoNavFvd5mqKZHMZusJt\ +cnzg26EM75V8+46Dd9hH1ETbSQRW9XSguOWed2fvyTlsE5y/F3/i+XsxLs7w3twbrJd8OxwN8QBD7IPkGgGTlAE/4ZsPIysMLbhAqMLVHkWOPzqVRo2X+iveSMajnkVFLr/ByprCYnI+3uwobfPZHdYBBgJqwwE1\ +iJBC6AY71IZrSppqHNImRzSIJLmqi8UQQw5YsbSxzeEStgeiNWIUazZhs67jrJF02+FVPfgqiZKVm9QVbjAfEKHDtOSVMcIDcrRldOkarGo6ClQBMeHBVMpXjET2dbjCZLh8hchFd2UvUdfSvyyan8NNskaL8KCM\ +asYZJUIANxCEtjrciYA56nzMh3Kgmy07PqqgMM52xZtX/RyUNPUZn2wiPr0MRq3zJ3DBMwnBK4yVxnIHSb6BUePkmApPZSV30yo5hq2j22/1emFQZUM24FYdzDgVrvB+3TSqZ3XOkzOplUnwPe3KJKfrMWT4flYp\ +R8Jd6sIFRyOZD3hDl4ZLLKarGHa3NWDEJyoi49eG81+NGcZWEvzcFy+uqZ17Mi9eikqEcIvpQBHtS40lB7m9RKxh70d8JhzN1c1RyzV3WVreG5oEVvqy2n44wv9Z8cdfN9UC/n+FVsWkVNM8z/yX5vJmcds1FlOd\ ++8a6uqlW/iNGW+9t85ceoTxNlco+/xcolYoO\ +"""))) +ESP32S3BETA2ROM.STUB_CODE = eval(zlib.decompress(base64.b64decode(b""" +eNqNWntz2zYS/yqKYtmRm84QfIKezkVSHVlOrlc7TRQnVadHguT1pjmP7Ki17HO++2FfBEip7f1BmwTBxWIfv31A/z3a1NvN0cmgPFptA22vAK5/rrbKeA90ww9F/NVqa8oXdo4bTqfw78lq2xT2auyEYAAjQDK0\ +75q8M/zM/okH9jaP7WWXqkM7ktor8VeDDxP6UCv7P+0QsawAeUtBa+K+gLFgY8kF3nbKYQNc2NHMTgUaMdABZlWHYE7TVGVHWx7e4qt/vvX3aXmGL6seO5YNu7aGu+BguaC3OLP4f2Z214Xr+aBVwGBHFbBDYacG\ +KRnZVUn0AkNCcKvyBpGl0pNr3mMvD3+hGzeCEl7e7+7DUny0oyFsZRiATkEju3uBa0L81sKsnWfVkReOlbrypGb6bOW9DXW52r8mX8rd68D7OmBbBgJy4cR40DNs5CYc8v7Sb8FYYSfa7aQu6G2RiID1jPQAs+C/\ +ii/F/jK231IPgaeI/MmY6JLEiUSNGPhwYucqNbLjkae5gO9hW0jBG+zqPbJvqrDz5o3paPkKZi1/I7YnEYznMz189e35sCvcPPAEBwqB5U3xQizaE3XsP08mcrcA4vwNQABTE3Mulch1wA4NEi15Yi6STrqwkHv3\ +LRLkrGjtW3MZjj03ZnnmbM+dmTnggXbbhgvUp6x2Tc674LH2IxNe8ReWy7z0ASs87zuWtwA6QOG4kcVEqnifgR/MeXLsdl4zUBZwzzaJ6/sOYxB3Su9TpAeGCTQBHILgkQjAG2UJ1GoOH/ne5FvWtS/XfLVpyXTH\ +r7tfbYjpymNUk4tsOsJhQfZdu5aQETOk2D8l6vEqvogMe2MEBn0FTvfxh4vVakroTzRGRARFoE+t2FLWA3rbAW0f/Tik/yIwH7HAf1UMO40A+MpwwBbJfuaHIW1OhmSXJh6/fQYfngzH8O9ZDAKzztbBzTXtsCnQ\ +x7rwP2F3rUgE2/YuLdjOLMMVQqkH7wo9awCvI2G06DP6HWgKkSokCZWiGkXGWoTOG2BcCcCwDdbK88bQ2WQT7o2BBd4Ndqyj5CWLCpTI5t7sirUIDhj6eiaCQC5gHgiyABkteBHS8rSzBUyAfZmpBMDQj944osYa\ +7RmylmJ4HAXfTDnOhuOrfNGGg69BihqkWIjSkz6LA45AYsL2A2YIAAX3HbJ/gshrEj28r0rWXrlHHjLHsLVHXdr4rdDUTCf7EzoVz4l35+wGXNrJiSRzoXuHZsPPqhwyXpUcCIGb5g/SBpdlXvkPwN7vsL8JBE32\ +9hgeeHhyh//SJ09o9Uqxse61e5RWC3OXLpKUoAh18a1dwlQc3kU3XsDxKTXm2E2m7/ewEPU/fDWkoLs0lFsikjNGld7XAMpFwS5R71EdjOdeAlHKNyNnn2QYaTczCgK0VvPHqnWGYXgfxvyVYXzy1faL/7D2Hzb+\ +w9Z/WCxYtQDQmATGk7cLdp0nhUM4P5lVRXNOO1SIYKUTIDps/Hx1/QFYnjU8Za82L12VgLuthPo7CE3Je0YqtPiMJVTRujh/j4u6PPfGUxQy+XCJLM1H3kxU2OQzSVwxGkvFQ9a13op1ZpAwSRgye8MQQPoNDbZV\ +QvIGI9vDDYOG8coKzCuspkqkjevVYpgjV6DR8sIR1Ikps1HqPhsPw4fTjGC04m1WKPmLzf5t6gyicUZylfw2IFVew47nn5iM8sUJb545UcpLx8iSE66akqKCOUWwSj8RmbKkeCp5LOAVpp8ggfTlavMRZAMfvRZ4\ +e8dBJnLOWzS8TEbpg9HNS+DizSGsAsKAyjd8T1IBRsCNczQTK8wShAm2i47P+8n3xcPEFVFIQe8DAg7VAkGJ6PM5xi1FWvwruLfZ+/eL6TlwSx2BR/g2Az/FpBXuAtdG0BPOYTpl1p4aDUxUdwLApFNE7n6JdUQQ\ +ew9WVEcehdjrX4j5CAvCvdsoUij9IqfR3yHcaEKdTycMSOgkCh8gX0t5GHJFHt62iSpxyA8LemvRME/4Lei9oYRgtaIQhePgITz+/C2GtIs2cwC9/UhAaDlVXKpWpnXt62GBGMeZjmDKDmbDVxnni5KUu+gwK+Hv\ +62EWkvmjkbX48ZocxqjBSKiQTVUNU0RDq5/IzZQ31Rw/7fdewAtNw40McGDwGTQivD6eu8hb7ZjoVPD2Ddk+MO83nKx1XwxdqjnmbF897sfoKt0jJRPvNLJCCoKQKIOXmXgC9TKEUgTgtvIH+IwpWQ3YG3W73V4G\ +4blgpbg/ZLxBRKucxAMmVSgfD5FssYf7EgenhKVNfRxBVIR+HuWw7bYWlB+odNPZ7RWnDYZcypNjNJvCnmfcwVM46QgH1e3lajO+PORKH6pKk90RBYgkaGbIoHwd3fINNpVOgcb6dNDgzWLUYTI+v5x3cxhlDmZ2\ +wdp1O4BdCP9kpASjYJ4G7fzPF7UBMccUa72GDPWMAFyF3TwIqUUudsA4ZGaFP56IqufiGcDwbUdi28rqNM/oQk5SgvkguMv/0fxLMg1yUrSU9G7Q8GST3sjgGci0QQwM5+9ZOukh3DRnOGhpY6+1ee+IUodlPmxt\ +CbMtnx+T8r3lB5e4c+MYwYI5BYoAai/6ak6mKiTLDsk5lSbEH7QhRIu9hYN0RqseN6QDWvV7mb7aIEOMFJAE1pyld8XJDQDgV7UWQ+t2l3vfmtOZP/yftlhAB5YWDpZKYV9WoQhK+dMCmqKyA29QyaAi5oK4G+La\ +iVF/R3/3anOYEPcnLDhOoTxuaRZaYRk6rahsefAckON2X429IdiCXWMG2DJ2SD0+5BapkBoLFM1shCvC32gN7j9wfa0yXpIpIIIllJRYNzul2I8tqYLzPe0Fa7igQtdqBzaXJ1A33XIMguKiiLlDZ9ATOCd39aO0\ +1ZZUWjT13Am+4KvBLuPPO4sdU/mq1bm0YO9osZzwul0e9A8JgfGq8d5Wlnu3ku9uZSnIDeTWjB+EQqIJBg1tfK2zZ2TEhS5YdZhyAC6lxqMVKH7V0kqlbTqiLRR4E3LWzLlCWzzvI+PLPlcYQ9E6wCTqcCC7CM/I\ +KOiTL7ysfgdZ2siZGNpLLJ3eWzJOk249cwbQLOPni5cQG49Zvr4H0FqFrIXcbxO32npDyAQIWCvuvmDsDDiVhxysVuNqhjH0/oDogh/q6AuKI/21bTNfs6WzOiyxja++FBuL12D02w9AejTjXAPy3Zw7zX7MyYMH\ ++yeSkC/uDz0y3e+9FATO6O8l2To0sHEcz1WCs2PudIYcjxKJi9x/hrlKTeBmIK9Sz7woYrJVx+2UjIMpdkCC00G7Gc5IIR7n2KdHePlBTv1CaoG0GB6KY3YFtqE0ItexjOsltSMV4GR4ilqFrBlh0gN8nXd9QzFk\ +qljAW2BTY1fvNwi572CBl2AjCVsk2vSeFpAlfd3a5nzm4+zhqazwQgqQEZfN0lOq2Vj8U0zYcOPVQAVWEx2LBnhA366xnJhS2pMn362uH+kACy2j9iwDxEAWTo4H+oDQC/Go7ab0WCG7p7reqO2Y++A5JiXc0gWU\ +wuOs8Mnq9pAMARZuu7x1+DV2gB7hHqBTIcoVfifYZg23YKmnZACGA2mZxZRaB20rvjn10iW9z9uD+dOOEhw0mXTAVlcl4tjvtiPpNE0ppDb1PTx9cXAmJ+QAgVjO1M6SMDsrWxemQj4IJxyaI/jiFm7WtIzqx2eT\ +Lj+4Ey7M5Wt5lVPqGuizb15NaEzFvg1g4LSsSie/ac9kHqjezPW/X9/hytfMWvMAkX1NpaEJzjLiR6VjSlYxgSupXYVHsOmDS65V1lDwUdmU+iVNvWXowNetc469VKGYUiLX1GvCHR2NW75JGGs5zg+x31KT26Jy\ +rV0hmbo98k+4YOTiM8f4sJSmVFuZSHRqsASZnKHPk/3MHzFvrVxKS6npoRcLsXSu6V780VrC0R2XNzgNGtAoQ0RbFEHn/TecKEPDAM1GYK0Kkavv5THGx89zPguqezkhwpC0ieqrkfNl7deHfoGcc7sL+0clpxJe\ +PSXuPdlAXiCoTgVRMDnDDO6UjxNQUBfkSYaxqwh2AQPDVsSnii27u/hWqe4eK0wzgA+8if0MBDATVV5xMmuM+7iUKBbN/KKObBOjWFkOaBo2DJhHPKPRo2vX/jCooD8vEflQqenv6QZGKh8D8NwlOOXjSXAY6AqC\ +vBV3BfHnMHIIpb3uvOi1SK748IpB2PJ9xKcSqXg+AvIRgXDBca5OLvacX9LHIBATi0ASShBwU3uUqdJXvdMqcPP8PZ8GZq+4c5vTrrTOJnjafw4P6qFPcM6Zf83OtitnJqzWeFA48zgMuYYXVAdzSAe77cFcoaHf\ +QFitrvCXN/nNBabr98X2UPDozp06BuaEtoB1mcge4+Po0p39GnXzI/Fe8AlooT5yn5ePfxDI+BgZmw+aOleYi8sYRGa1E/R/AiAs9SGsdUNSqJSnebZngwfsh3KUygMUiQs42dbc8oXJATezMUYnAzqy50ew+WTt\ +iIJHgaVAXYvHhiLnmgJeUfPJq/weQ84+sj2yS37q2i3t5p5+CPAMFLPNKVwUGvqbjbpweW+VjrlbbzI6pIHeXIH9hsun7GZoi9n5u7n38xMwlbytfO5Jwgq6IzljIIq9/VyfX81/dzgCp79oO+2E/PzD/LNMWIyW\ +G6LvTgSne+BPfSWYuyeb0upvOz7xa7tCwk040INbJP8rjFW7E/BemgopI3C3pd/+uE0WasuNZ3wIn3FWBC1BE7ofCiBUZS7BCvAHNtEjxS2XdR7S9CA7HDII9orinaPqYPxU1kVHHQrhBlpHtOawPfI+cj8SI9Zw\ +9td8iLTvOLySH6/J1tLOp0PHSldWR88H+NvJnz9vilv4BaUKsizK8iAL7Zv6enN7L4M6SFRqB6tiU/R+ammKF0f8xicUhFme5OGX/wGbX9rc\ +"""))) +ESP32S3BETA3ROM.STUB_CODE = eval(zlib.decompress(base64.b64decode(b""" +eNqNWntz2zYS/yqKYtmWm84QfDPTuUiqI9tJe7XTRHFy7rQgSLY37XlkR61ln/PdD/siQIpt7w9KJAgsFovd3z7A/x5s6u3m4PmoPLjaBrm9Arh+utoq4z3QDT/o+IurrSlf2D6uOZ3D35OrbaPt1dgOwQhagGRo\ +3zVFp/nQ/sQje1vE9rJT1aFtSe2V+LPBwIQG5sr+px0ilhUgbynkOXGvoS3YWHKBt5xy3AAXtjWzXYFGDHSAWdUhWFA3VdnWloe3+Oqnt/46Lc8wsuqxY9mwc+dwF+ytTukt9tT/T8/uvHA9G7UbMNrZClihsFOD\ +lIysqiR6gSEhuFl5gchS6cm16LFXhL/QjWtBCa/ud9dhKT7a1hCWMg5gT2FHdtcC14z4rYVZ289uR6EdK3XlSc302Sp6C+pyNTwnX8rd54E3OmBdBgJyYcd41FNs5CYc8/rSr0FZYSW5W0mt6a1ORMD5gvYBesG/\ +ii9E/zLW3zIfA08R2ZMx0QWJE4kaUfDxzPZVamLbI2/nAr6HZSEFr7G775F9U4WdN29MZ5cvodfqd2J7FkF7scjHr74+G3eFWwSe4GBDYHqjX4hGe6KO/efZTO5OgTiPAQhgaqLOpRK5jtigQaIldyxE0kkXFgrv\ +vkWCgjc697W5DKeeGbM8C9bnTs8C8CB3y4YLtk/Z3TUFr4Lb2kEmvOQRlsui9AErPOsbljcBGoB23MhkIlW8z8AOltw5diuvGSg13LNO4vy+wRjEndIbivRAMYEmgEMQPBIBeKMsgVotYZBvTb5mXftyLa42LZlu\ ++3V31IaYrjxGczKRTUc4LMi+aVc5scSAYn9K3MXL+DwybIsRqPMlmNzH78+vruaE/UTBmlHN6JLnx1ZoKe8C2toeLR6tOKR/EZePV2C9KoZ1RgB7ZThifWQr851Qbp6PSStNPH17CAOfj6fwdxiDuKypdVBzTS6x\ +0WhhXfBHK/oFJGrvN/yfatYwy2yFIOoBu0KbGsHrSJjUfSa/RUogvZCkU8qmKFJTHTo7gHYl0MLaVyvPDkOnjU046P003o129KLkKXUFG8iK3uyKVAd7DHo95UAIFxgPBFOATC5IEdL0tLJT6ADrMnNxfaHvt7FF\ +TXPUZIhX9PgoCr6as4cNp5fFaesIvgQp5iBFLRue9Fk85VhH1NcOYIYASnDdIVsmiLwm0cP7quTdKwfkIX0Ma3rUpY1jhWbOdLK/oFNxn3i3z66rpZU8lzAudO9QbfhZlWNGqpJdIHDT/EnA4OLLS/8BbIigCW3B\ +muaGb6vAa69M+5A+eUJ8VIrVdtACUG4t1F04b1LClqjzry1FU7GLl13ynI5PqTFHrjONH2Ah6g98NSbHuzIUXyKaM1KV3mhYmNZsHPXAJkJ74QURpYyZOE0lFUm70VEQoN6aP99kpyKG12HM36nIb/4G/uI/rP2H\ +jf+w7W56jV4K9/On1oBoMdyczp9oB3p+ZKt0c0ZjFIJa6SSJNhw/u7r+ALwvGu4yuK0XLmXAZVdC/R34qeQ9gxcaQcaiqmhe7D9gtS7ovfF2DJl8uECWlhOvJ+7c7BOJXjFAS/pDarbeippmED2JVzKDXglQ/oYa\ +25QheYOO7uGGccR4OQYGGXbLSqSN89WioROXrdH0whEkjSmzUeZ9Nh7GD8cZIWvFy6xQ8ueb4WXmGTjnjOQqwW5AW3kNK17+xmSUL054c+hEKS8dIyuOvmqKkDRziviV/kZkypJcrAS1AGEYi4IE0pdXm48gGxj0\ +WhDvHfudyFmxbniajKIJkzcvgYs3+zALCAPS4PA9SQUYAXsuUE2sMEsQJuguIgCvpxhykYnLqJBCPoQI7L0FixLZz2foyhTt4t95ABvKf3c6PwNuqTzwCGOzGYQ4wCTcBa6mkM84pOnkXAMJG6ho3vEJs05GuTsS\ +k4og9h6sqA48CrFXzBD1ERaEe7dQpFD6GQ+yk4n3CVr4YZdT8YOOOTTDWcRFlc5bGeNuXQdkTcANE0R5KFz/3FHREgofCs8zztBkXOWI2F+jOKGtTGvz12ON4MdRkYDNDqrDqIxjSwndnf9YlPD7epyFZBeofS2w\ +vCZLMmo0ESqkbFXDFFED6ydyMyc8aJqjp/0KDZinabjcAZYNxoTahdfHM+ebqx3dnQsQvyGjAOb9spRV+/OxC0unnBWox2HwrtIBKZl4p9wVkpuEoBrMz8QzyKrB2SIyt/WBEWoOBrYBm2neLrcXY3i2WSmuIhmv\ +EWGsIPFAOqGVD5RIVg9wX2LjnEC2qY8icJdQ9aN4t13WKUUQKt10VnvJgYUhW/PkGC3msOYF1/kUdjrARnV7cbWZXuxzPQByT5PdEQVwMahmyKCMjm75BktPx0BjfTxq8OZ00mEyPrtYdqMcZfYWdsLa1USAXYgL\ +SEkJX0E9Der5X09qPWWBQdh6DdHsCSG7CruRElKLnFOBdojdtN+eyFYvxTKA4duOxLaV3dMiows5SQn/g+Cu+Gfzs4QgbPqgKendqOHOJr2RxhOQaYPgGC7fC/bsw01zgo2WNlZkm/eOKNVhluNWl7Aw5/NjUr63\ +/OAUd64dXVuwFKBsZNSSVFVIlh2SS0pjBBtVIbvYmzhIFzTrUUN7QLN+J92vNsgQIwVEhzXH8V1xcqEA+FWtxtC83enet+p04jf/p00n0ICl0INpVdiXVSiCUn63gLqobM9rVNKoiLkg7vq+tmPUX9E3Xh4PHeJ+\ +h1OO8lAet9QLtbAM3a6obLX3DJDjdigf3xBswaoxNGwZ26dKIHKLVGgbNYpmMcEZ4Tdag/mPXPWrjFekCohgCUUr1syOyQsXkuKlrg5LrNgLsvlc7cDm6jlkVrfsgyD90DHX8QxaAgfrbfraFt9WVCNq6qUTvOar\ +wVrkjzuTHVGqm6szKdTe0WQF4XU7Pew/FJmMl7n3lrIaXEqxu5SVIDeQWzN+EArJTjBo5MbfdbaMjLjINW8d2Dusz6TGoxUoftXSSqW4OqElaLwJOZzmWKFNr4fI+LIvFPpQ1A5QiTocySrCE1IKGvKZp83fQTA0\ +cSqG+hJLPfiWlNOkW0+dATTL+NnpS/CNRyxf3wJoLi1zIffbxM223hAyAQLWiis16DsDjvEh5q7VtFqgD73fI7pgh3n0GcWR/toWo69Z03k7LLGNv30pFiCvQem3H4D0ZMGxBgZ9XI/2fU4RPNifSFy+mD/U0/J+\ +nUYTOKO9l6TrUObGdjx9CU6OuCIasj9KxC9ylRr6KgVRqR7Jq9RTL/KYrNVx2yVjZ4o1kuB41C6GI1LwxwVW8xFevpezwZCKJC2Gh2KYXYFtKIwo8lja8xWVLhXgZHiMu/oWeP3GDxGoj28biiFTxQLeAps5VgB/\ +B5f7DiZ4CTqSsEaiTg8UiSzp61Y3lwsfZ/ePZYYXkplMOJ+WqlPNyuKfdcKCGy850iCPrkYDPKBt15iOzCnsKZJvr64f6ZgLNaP2NAPEQBpOhgf7Aa4X/FFbZumxQnpPCb9R2ynXywsp3qMKZHzoFT65ut3nrKr2\ +KsJ1+CXWiB7hHqBTIcppv2pso4Zb0NRjUgDDjrTMYgqtg7Zk3xx74VI+ZO3B8mlnExw0mXTEWlclYtjvthM+lAQpgktt6nt4+uzgTM7RAQIxnamdJmF0VrYmTBl+EM7YNUcw4hZu1jSN6vtnk64+uHMwjOVreVVQ\ +6BrkJ1+9mlGbin0dQMdpWZWqf9Oe3ABkJLDAf7++w5mvmbXmATz7mlJDE5xkxI9KpxSsYgBXUh0LD2rTBxdcq6wh56OyORVSmnrL0IGvW+OceqGCnlMg19Rrwp08mrZ8kzDWcugfYiGmJrPFzbV6hWTq9sOAhBNG\ +Tj4L9A8rqVa1mYl4pwZTkNkJ2jzpz/IR49bKhbQUmu57vhBT55ruxR6tJhzccXqD3f6AdqCMaIsi6Lz/igPlOmW1EVirQuTqO3mM8fHTks+M6l5MiDAk9aP6cuJsOffzQz9BLrgOhoWlkkMJL58S855tIC4QVKeE\ +KJidYAR3zEcPKKhzsiTD2KWDXcBAtxXx2WPL7i6+Vaq7xgrDDOADb2I/AgHMxC2vOJg1xg0uxYtFCz+pI91EL1aWI+qGBQPmEc9z8sm1K38Y3KC/ThH5AKrpr+kGWiofA/CMJjjmY0wwGCgXgrwVlwvxoxk5sMq9\ ++r3sq04u+aCLQdjyfcDnFqlYPgLyAYGwZj9XJ+cD55w0GARiYhFIQgECLmpgM1X6qneyBWZevOeTw+wVl3QLWlWeZzP8JuAMHtRDn+CSI/+ajW1XzkxYrfFQceFxGHIOL6gO6pCOduuGhUJFvwG3Wl3i9znFzTmG\ +6/d6uy94dOdOKAPznJaAeZnIHv3j5MKdERt18y/iXfNpqVYfuQDMB0QIZHzcjMWHnCpXGItLG3hmteP0fwAgLPN9mOuGpFApb+dZnw0ew+/LsSs3kCfWcAKecy0YOgdc5UYfnYzoYJ8fQeeTtSMKFgWaAnktHjGK\ +nGtyeLrmU1r5akMORbIB2SU/dPWWVnNPnwscwsZsC3IXOj+Hmoc6d3FvlU65jG8yOr2B2pzGesPFUzYz1MXs7N3S+0gFVKVoM597krCC6kjBGIhib4fnZ5fLPxyOwEkx6k7boTj7sPwkHU4nqw3Rd2eG8wH4U18I\ +5g5EU7n6x45N/NrOkHARDvbBTVL8Hcaq3Q54L0WFlBG4W+tvP4GTidp045AP7DOOiqAkaEL3UQFCVeYCrAA/w4keyW+5qHOfugfZ/phBsJcU7xxrB9OnMi8a6lgIN1A6ojnH7fH4gfuUjFjD3l/y6dLQ0Xkln7jJ\ +0tLO0LFjpSurg2cj/MLyx08bfQvfWaogy6KsCLLQvqmvN7f30pgHiUptY6U3uvdBptEvDviNTygIsyIpws//Ay4v6A0=\ +"""))) +ESP32C3ROM.STUB_CODE = eval(zlib.decompress(base64.b64decode(b""" +eNrFWmt328YR/SuypEix29PugngqtUw6lChKlmvnpFGcA6UGdgHVSatTyVQtt+V/7955ECAl0vnWD3wBi93ZmTt3Hsv/7M+a+9n+wVa9X94bW97b8Kqz8B0v8/60vHd5+DYo76uivM/p6l64WL0Ob+l34S0Ol9Lw\ +2WyHNydPx/R0ed/6dxnN8SK8mVdh/sEsXMXttrwt7xsTfkXDerwTFsh3WYY6mpb3Phq/nG6HZ01ShYWj8Apj83wY3gblfnmNFTDfXZghofloVJHNw9WwQBNktkX40oY7Lghft1m5T3L99yyM82F8zc+2bZatuaFL\ +j1g1tNPw8j6jnfJ8ED4VnUUL5YVXUF0RXm6Az2/nIkt+gT0OIfxRt44Jn3kxYhU8vmjxYi5L8wrDngy6Uvfbum9hAJ49rLc0tVqbjJaNoaFgomLAUwejBjMV7kxtSyYnQ75mWerwtMvOsyfhIwjubYbtsOX5aZuf\ +hGF+EiDhw4hGYGHdGJdZx8BUMxhNaR8zkcvIIAgD+znRZpWwzu/bTDRmus020F5bllDBzlYm2+trwDrIMyAQ70OzjrEd1joMCxU7uwI/wqMAUMC4hEGTLOQ1okcnXmMHPeM7aHAU3m3N8uFqblkVeTLBbTz6BNAH\ +hAyDAMPa4uIQg/qrQpNwwEYWyItjXAnb83Kl9Re8X8gC9cEqNKXtZKsNHA8S02QDxhjkaxtMOlFv6cEhPIJ9pOJqRsBmuyG649Z2qwM6nlYjwWipiNHQuodTQLB/8MJ1dkSIFAfAiDw5Io2TL7x94aayM2Axm/Tw\ +i10pZPJBzzOFxzxG40ePOl5iyIjHW5GcdGdwJ8WdKFioiGTqPAXR7Agudfv9yQt71YlDy8fdItBlwzgmvsCcRJFqowXkMUtdYTEh4d5miGhT2fl6HdBvYRATY+mg4AY/jPAWb0kQ6PUHNstLPeE7AZNsRCM4gBFX\ +eUWm9P0pGxHYCzK/xDxENvg6UfrpM0+fZQA4sISAsgKAY6YVRxZ5OpY78N9iD36OGd4xxplqTtxfwjQd87hL7BWmKWfPiXBPhnuiw4adshDdgj/ALeTRhsNZ44QTEt3VkFyjpOHlkBUUZihJyHIsrBTj4nDMEfUL\ +HHSb3LGjaMjuReC7b4RpXfPi7xok8fiYZV0nOxTW1MJMNmFKqKMJ74Kwmm0dsg0a+00/zkwUjMNH1vPMzMy3cPPoaJ0Q4HFQTwhizIaaHQgX9lQw0lRFYW8SRUsaYJc3Hex6DjFj2YBO1ycyosmrOTs9khhEbCd3\ +gIXcHzDMACR8Iv6By3MMrnf4BhPhCIGgYG5jTbxhblz1lZXwvhw84KhG4kakEyl7b7KhH3SjHY3u1rVCI/zclUwCjUSrAYLYOu8Cw8YlbbckEz60W2cj9fMYLh3pVp8x2mtx5Jos4Vi6IuZlgszbyAGi8WragpzJ\ +yCiKAPER4hhxy90NmMLOP+LWB6yc7IkxwxZ8wxv1SElAUpVIlM0BDFi2C0czVkYu5KusA8Hb6pAFZVbZZnAq+axTVIW8eXlyk/zSrUAkUE3CduuCmSRAshdg6QVBC9E0i7JGxEJEXH68txpMmmx/ic52ZISzR/gC\ +P8M3k7hOYXU1fAZTVePyOvBUm75rf4KCf5ouvBX0WbiPGKSG+3DKlApD5MnrL/MqQAYgNH7pyY1beM/RDtGkKJRnd0efe9laAmnShulUQazZzFp/cdHNzfzjD/D9n0BAPwNFtbAKxb9tMN8e3PEUsiN4tSiXPOQZ\ +/ML00AgqKzGjqnRJjugPnCzXUGWdMueAE1y0ad9greTKwYM/8Yx54hU/uRZpmyG+UblbIIj5v9dPSNhzB8ygBDj3cHBY9ZYfIZ7VXMdOD6UUS1YTqWzFZyhNsJLseUQdrNNGIZc0tbthfzKDG6TZUkVwHAcqk7fw\ +pCR7zZiqvowpflnhlAKFcFG42QdGSq0kWiDzR1aRZ/07vxuxxXOScfBJKl66siTDD1/AtYsuOaP6rQpCjHKs9zZH8JoirJ2HqxhT6J32Cyav47mkR9BAEvOPpuLHvE/dnzvsIog00XMppNcLShfJ7N9xYn3NaTUJ\ +moAuta5YJKEo8TUJtXbCF/OcMwhqMPx/2XNYzpqkz54+VPvJqmtvpjwwyQrVvnn2PUD3fXn9DvJPfwG7VKenZ7h59uwVbr4qr8/Bw5fnvaq1zi5G03c3nQWQ0WGzgdAPxSOEVCvEyFgS+Yjp0xse4ySGOomhdK9i\ +8YFryg4jTmJRZICjAA5nrnnApjyicprR5S+yTyv1jKZGmqbgWo0nGqmJbZTAGvbob5z3VRhpk4SBs6ixluujJ1eHhLgtSXG1rkryoTbC8I0fmnBKZOyx1qRqy0WTyyZHNJfEubVu1LquyVaWk4e4qGlKVQDtL6OU\ +sGTRN+GmrTYQh6lFydw0cn+VvVRsTFHx9aLBJs0ByAd/I7mBR0sXE/7CrY2jTdkPyBmucJWdycbQqbArXRPkvHnSjlq1Q9dkocwjiDpD1KVukf81e6VWXadocD4Rda0BicG7aA9ksu+c94f4TNfj7nooibiuvZaq\ +lqjSsqEwGEqxnJPOMJTKJ7lfDZbH4+XTp9TNcdoXO6efqfxMBbyVPfqaVVIkVhg3izvZXbYrMLPtNnR4yaXWwmXAH6i72rrXgPsNlcR7LnKWy4hNpi16ExNzNZsRSs2pAjG5zrT1pf0Ky9+J8RPdaNz1WBa7rqRD\ +4QupMDUMoHWB1cgPqJXovj2E1j9wmucKNRIbZcqXly2ZUHcNXpF9DSC0KW/LctsNG8uixY28vKXLtU7hfpU7cTmjO+Q725TadNGG2g6t9qKoLf4h1Z8Isu3b9HMhsppVEZ8TamizQ4c2ZxaRFhbQeg1xJ9IlbLI3\ +5a1qSDhlMWfyGKyscByHCVF4ImmHlwoXpQ+12T3bq7C03ZjK7GsA6VjWlL4QrOJgKpMcSXeUqNeJsXx+srOrFIoCpKm0G8aZcsWmQQTKtpxQXirh1B93O/SaQgy+OqXKHHzjNAfYddIUpO12VnkvsiSMiortnUtS\ +Xy0WiGQB6odAyWSkjDsd3iEU568QSU/CN3MC2hljovFmV8pb1McFmJV7IFIuU/zPzlUYQVmtKBsdC4PQjXQBP4T+BzoBLbHIUF22J/s3diydX8cqbqSTF08VN1kfNxNlYjTTfN0j1EJK+oL0u73DroPQo23YKqYF\ +vxL+oLbiFrWZc+lCWkwAFl3YVnqPhtvRyFm9sJzesoveRSF9cbTjeK9GgUZZ1dEzxfVU+vdep5HpAfTspV4cLiYWpVDK26kA4ETrJUB41BWOsktxiKafwsRdmZnbSbcFogRI7bw80Sjvfd/30bFGxmmf+vmeF3hF\ +D+7IoUWzQp2UPIsbNXknoRUJq4QVZJLxufRc12S94W0QK3TfSpdywME/lz07Q03PK2YR1UhBSYkdyfz2AO7kR2jjFH7OFW3r55q/+yFfanJJDWrK9KQvVwhIXbYU1+Y0xzUHrEZSw3rw6Ss5+iEPHn3o1nDXUhyZ\ ++efu6mew1MaVwEqhNLZg5eKU12u1Kbbpscp8lsfYBrsjgWcrrKlxUSh0LOWQl3Mx0+cZXxyI7doHDyTdA4U7cewpGuQcDstoCpNEbCZOx/Rp8aWmWTwd9Z6GfXUK6W1TPoLwVERcic70BCKW9oacjtWZHFi0i5h/\ +zBeoyE+kvrbS5PUCTOKv5EjmgC9LiBGB5byFvBb7WmSrj9vu7rkegX0S1jByjlkDrZeTXoSMO2STGK2/xKJ3cr6ZnIzXr5SDlawb/wg0x8M53FHO+fSopDBCQq539gkU5K3me7n4eiiVR+y4Xo/w7OSJnLfi1JwS\ +GmLmJumSzbBJPXBSzhl8rWOl3iGOqtU0lJaLP7T50HHZrfzWSJ5NnbAGIdxzMN+VPrkRZxismNqa110CWCiDUQIh+6mWrSonE0Rng91OZCsnQIuqnngsrH8tSQV9IsbykbP4VC8L2OItIP5Q/6ifteXCiu6xm4Xp\ +PWlXbpr+k3Y6kRSTyjvnNEDFRyuJLPWH1ubBSyC0D/NiKge8ZNWtHGA/CNXBs24lA4fyBm6MBp91P/JhvpZp/yRFsh2borM3R3o5rRx0FjRIkavF8YKEeK1HnF4f9uM2bVnyBBc/zEwR8OJLTgEfd6ytn7s/rfAO\ +R5QufaRUb5s5nWBKwRtd1S5cG+JrKw7KeppRGP+hOyhU/XFwcG8IxAFVTdtl9d7ccbJMcyc6d5527QO12fpw8I4SrOXDRNF/W/RlmUpwreRsGkpfHqG64Ibf/oiK2qebBWjMxVMC4KzpNSmSm55+1UBmA885M136\ +YxEC6Fl3ht3/I4Ul9VxIV9cSmO8Yyfq/EUW2/p2DheEsYCBHjlnXX3tcsafdfnJzuDZlOJb+dfx4Kq/2Llo2Jnl23F2v5Pwht/rXhn/piaUiKGWv2dClYp/M20Nuvi2wR2ETf3gKE15zk4776SF31E5/3K1gkhM5\ +MW8577o9eYmW3YH060jkP1KdOolO5D8YDKSA1VJaEZKnahPF6msgxIyItk7rjP/ogna/L4kFsOOGYk3kMZTaedkw9WGjC8QOCvZUD+mBQiInsKb3DwKRiw4PPM729SiZ/k1BHFNw/GlS6XYvOW2x0/U0yDMSDg6S\ +Rsy4sdmIbrFkFXXLS6TpOygsr8UtLe/kMaNNrcc57PlDn3t85LDY5Hh/YoeoK0nMiPZyCVbNRhEg48FvchMQhZZpMR/WEabTN3toWKcoXVK0rNNpi5Z1enoM90/P9lAnp69wG5VFdNksmtb7v9+ivyf+9eOsusWf\ +FK3JstjaPDbhTnM9u/28uDgYRLjoq1ml/2YEpIIv7cvl/izGpnFh4vn/AOixonk=\ +"""))) + + +def _main(): + try: + main() + except FatalError as e: + print('\nA fatal error occurred: %s' % e) + sys.exit(2) + + +if __name__ == '__main__': + _main() diff --git a/tools/linux_build_extra.py b/tools/linux_build_extra.py new file mode 100644 index 00000000..c849af5c --- /dev/null +++ b/tools/linux_build_extra.py @@ -0,0 +1,19 @@ +Import("env", "projenv") + +# Override unused "upload" to execute compiled binary +from SCons.Script import AlwaysBuild +AlwaysBuild(env.Alias("build", "$BUILD_DIR/${PROGNAME}", "$BUILD_DIR/${PROGNAME}")) + +# Add custom target to explorer +env.AddTarget( + name = "execute", + dependencies = "$BUILD_DIR/${PROGNAME}", + actions = "$BUILD_DIR/${PROGNAME}", +# actions = 'cmd.exe /C "start cmd.exe /C $BUILD_DIR\${PROGNAME}.exe"', + title = "Execute", + description = "Build and execute", + group="General" +) + +#print('=====================================') +#print(env.Dump()) diff --git a/tools/osx_build_extra.py b/tools/osx_build_extra.py new file mode 100644 index 00000000..3f445946 --- /dev/null +++ b/tools/osx_build_extra.py @@ -0,0 +1,8 @@ +Import("env") + +env.Replace(CC="gcc-10", CXX="g++-10") + +env.Replace(BUILD_SCRIPT="tools/osx_build_script.py") + +#print('=====================================') +#print(env.Dump()) diff --git a/tools/osx_build_script.py b/tools/osx_build_script.py new file mode 100644 index 00000000..b1fbe229 --- /dev/null +++ b/tools/osx_build_script.py @@ -0,0 +1,38 @@ +""" + Builder for native platform +""" + +from SCons.Script import AlwaysBuild, Default, DefaultEnvironment + +env = DefaultEnvironment() + +# Preserve C and C++ build flags +backup_cflags = env.get("CFLAGS", []) +backup_cxxflags = env.get("CXXFLAGS", []) + +# Scan for GCC compiler +env.Tool("gcc") +env.Tool("g++") + +# Restore C/C++ build flags as they were overridden by env.Tool +env.Append(CFLAGS=backup_cflags, CXXFLAGS=backup_cxxflags) + +# +# Target: Build executable program +# + +target_bin = env.BuildProgram() + +# +# Target: Print binary size +# + +target_size = env.Alias("size", target_bin, env.VerboseAction( + "$SIZEPRINTCMD", "Calculating size $SOURCE")) +AlwaysBuild(target_size) + +# +# Default targets +# + +Default([target_bin]) diff --git a/tools/sdl2_build_extra.py b/tools/sdl2_build_extra.py new file mode 100644 index 00000000..358540f5 --- /dev/null +++ b/tools/sdl2_build_extra.py @@ -0,0 +1,9 @@ +Import("env", "projenv") + +for e in [ env, projenv ]: + # If compiler uses `-m32`, propagate it to linker. + # Add via script, because `-Wl,-m32` does not work. + if "-m32" in e['CCFLAGS']: + e.Append(LINKFLAGS = ["-m32"]) + + diff --git a/tools/windows_build_extra.py b/tools/windows_build_extra.py new file mode 100644 index 00000000..9d7c5810 --- /dev/null +++ b/tools/windows_build_extra.py @@ -0,0 +1,27 @@ +Import("env") + +env.Append( + LINKFLAGS=[ + "-static", + "-static-libgcc", + "-static-libstdc++" + ] +) + +# Override unused "upload" to execute compiled binary +from SCons.Script import AlwaysBuild +AlwaysBuild(env.Alias("build", "$BUILD_DIR/${PROGNAME}", "$BUILD_DIR/${PROGNAME}")) + +# Add custom target to explorer +env.AddTarget( + name = "execute", + dependencies = "$BUILD_DIR\${PROGNAME}.exe", + actions = "$BUILD_DIR\${PROGNAME}.exe", +# actions = 'cmd.exe /C "start cmd.exe /C $BUILD_DIR\${PROGNAME}.exe"', + title = "Execute", + description = "Build and execute", + group="General" +) + +#print('=====================================') +#print(env.Dump()) diff --git a/user_setups/darwin_sdl/darwin_sdl_64bits.ini b/user_setups/darwin_sdl/darwin_sdl_64bits.ini new file mode 100644 index 00000000..65b99594 --- /dev/null +++ b/user_setups/darwin_sdl/darwin_sdl_64bits.ini @@ -0,0 +1,100 @@ +[env:darwin_sdl_64bits] +lib_archive = false +platform = native@^1.1.3 +extra_scripts = + pre:tools/osx_build_extra.py + tools/linux_build_extra.py +build_flags = + ${env.build_flags} + ; ----- Monitor + -D TFT_WIDTH=240 + -D TFT_HEIGHT=320 + ; SDL drivers options + ;-D LV_LVGL_H_INCLUDE_SIMPLE + ;-D LV_DRV_NO_CONF + -D LV_MEM_SIZE=262144U ; 256kB lvgl memory + -D USE_MONITOR + -D MONITOR_ZOOM=1 ; can be fractional like 1.5 or 2 + -D USE_MOUSE + -D USE_MOUSEWHEEL + -D USE_KEYBOARD + ; ----- ArduinoJson + -D ARDUINOJSON_DECODE_UNICODE=1 + -D HASP_NUM_PAGES=12 + -D HASP_USE_SPIFFS=0 + -D HASP_USE_LITTLEFS=0 + -D HASP_USE_EEPROM=0 + -D HASP_USE_GPIO=0 + -D HASP_USE_CONFIG=0 ; Standalone application, as library + -D HASP_USE_DEBUG=1 + -D HASP_USE_MQTT=1 + -D MQTT_MAX_PACKET_SIZE=2048 + ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_INFO + ;-D LV_LOG_PRINTF=1 + ; Add recursive dirs for hal headers search + -D POSIX + -D PAHO_MQTT_STATIC + -DPAHO_WITH_SSL=TRUE + -DPAHO_BUILD_DOCUMENTATION=FALSE + -DPAHO_BUILD_SAMPLES=FALSE + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_VERBOSE_MAKEFILE=TRUE + ;-D NO_PERSISTENCE + -I.pio/libdeps/darwin_sdl_64bits/paho/src + -I.pio/libdeps/darwin_sdl_64bits/ArduinoJson/src + -I lib/ArduinoJson/src + -I lib/lv_fs_if + !python -c "import os; print(' '.join(['-I {}'.format(i[0].replace('\x5C','/')) for i in os.walk('hal/sdl2')]))" + ; ----- Statically linked libraries -------------------- + -lSDL2 + -lm + -lpthread + ; MacOS with Homebrew + -I/usr/local/include + -L/usr/local/lib + -DTARGET_OS_MAC=1 + +lib_deps = + ${env.lib_deps} + ; lv_drivers@~7.9.1 + ;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/7d71907c1d6b02797d066f50984b866e080ebeed.zip + https://github.com/eclipse/paho.mqtt.c.git + bblanchon/ArduinoJson@^6.17.2 ; Json(l) parser + https://github.com/fvanroie/lv_drivers + +lib_ignore = + paho + AXP192 + ArduinoLog + lv_fs_if + +src_filter = + +<*> + -<*.h> + +<../hal/sdl2> + +<../.pio/libdeps/darwin_sdl_64bits/paho/src/*.c> + +<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTClient.c> + -<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTAsync.c> + -<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTVersion.c> + -<../.pio/libdeps/darwin_sdl_64bits/paho/src/SSLSocket.c> + + + - + - + - + - + - + - + + + - + - + + + - + - + - + + + + + + + - + + + +<../.pio/libdeps/darwin_sdl_64bits/ArduinoJson/src/ArduinoJson.h> diff --git a/user_setups/esp32/d1-mini-esp32_ili9341.ini b/user_setups/esp32/d1-mini-esp32_ili9341.ini index 68ed7003..8746bd98 100644 --- a/user_setups/esp32/d1-mini-esp32_ili9341.ini +++ b/user_setups/esp32/d1-mini-esp32_ili9341.ini @@ -6,14 +6,8 @@ ;***************************************************; [env:d1-mini-esp32_ili9341] -platform = espressif32 -platform_packages = framework-arduinoespressif32 -framework = arduino +extends = esp32 board = wemos_d1_mini32 -;upload_port = COM5 ; To change the port, use platform_override.ini -;monitor_port = COM5 ; To change the port, use platform_override.ini -monitor_filters = esp32_exception_decoder -board_build.partitions = user_setups/esp32_partition_app1300k_spiffs1216k.csv build_flags = ${env.build_flags} @@ -38,7 +32,3 @@ lib_ignore = ${env.lib_ignore} ${esp32.lib_ignore} ;endregion - -extra_scripts = - ${env.extra_scripts} - ${esp32.extra_scripts} \ No newline at end of file diff --git a/user_setups/esp32/d132-unoshield_ili9486_parallel.ini b/user_setups/esp32/d132-unoshield_ili9486_parallel.ini index 8c188f00..b1c84d76 100644 --- a/user_setups/esp32/d132-unoshield_ili9486_parallel.ini +++ b/user_setups/esp32/d132-unoshield_ili9486_parallel.ini @@ -5,12 +5,8 @@ ;***************************************************; [env:d132-unoshield] -platform = espressif32 +extends = esp32 board = esp32dev -upload_port = COM4 ; To change the port, use platform_override.ini -monitor_port = COM4 ; To change the port, use platform_override.ini -monitor_filters = esp32_exception_decoder -board_build.partitions = user_setups/esp32_partition_app1300k_spiffs1216k.csv build_flags = ${env.build_flags} diff --git a/user_setups/esp32/esp32-dev_ili9488.ini b/user_setups/esp32/esp32-dev_ili9488.ini index 2b529cc8..6fbcbba4 100644 --- a/user_setups/esp32/esp32-dev_ili9488.ini +++ b/user_setups/esp32/esp32-dev_ili9488.ini @@ -5,19 +5,8 @@ ;***************************************************; [env:esp32dev-ili9488] -platform = espressif32 @ ^2.0.0 +extends = esp32 board = esp32dev -upload_port = COM2 ; To change the port, use platform_override.ini -monitor_port = COM2 ; To change the port, use platform_override.ini -; upload_protocol = espota ; Use ArduinoOTA after flashing over serial -; upload_port = 10.4.0.171 ; IP of the ESP -; upload_flags = -; --port=3232 -monitor_filters = esp32_exception_decoder -board_build.partitions = user_setups/esp32_partition_app1300k_spiffs1216k.csv - -debug_tool = esp-prog -debug_init_break = tbreak setup build_flags = ${env.build_flags} @@ -41,7 +30,7 @@ build_flags = -D TOUCH_DRIVER=2046 ; XPT2606 Resistive touch panel driver -D SPI_FREQUENCY=27000000 -D SPI_TOUCH_FREQUENCY=2500000 - -D SPI_READ_FREQUENCY=16000000 + -D SPI_READ_FREQUENCY=20000000 ;endregion ; -- Debugging options ----------------------------- diff --git a/user_setups/esp32/esp32-dev_ili9488_parallel.ini b/user_setups/esp32/esp32-dev_ili9488_parallel.ini index d6f73632..0cfde697 100644 --- a/user_setups/esp32/esp32-dev_ili9488_parallel.ini +++ b/user_setups/esp32/esp32-dev_ili9488_parallel.ini @@ -6,16 +6,8 @@ ;***************************************************; [env:esp32dev-mrb3511] -platform = espressif32 @ ^2.0.0 +extends = esp32 board = esp32dev -upload_port = COM1 ; To change the port, use platform_override.ini -monitor_port = COM1 ; To change the port, use platform_override.ini -monitor_filters = esp32_exception_decoder -board_build.partitions = user_setups/esp32_partition_app1300k_spiffs1216k.csv -check_tool = cppcheck -check_flags = --enable=all -debug_tool = esp-prog -debug_init_break = tbreak setup build_flags = ${env.build_flags} @@ -59,5 +51,4 @@ lib_ignore = ${env.lib_ignore} ; ${esp32.lib_ignore} lv_drv_fsmc_ili9341 - ;endregion diff --git a/user_setups/esp32/esp32-touchdown.ini b/user_setups/esp32/esp32-touchdown.ini new file mode 100644 index 00000000..61ae1322 --- /dev/null +++ b/user_setups/esp32/esp32-touchdown.ini @@ -0,0 +1,49 @@ +;***************************************************; +; ESP32-Touchdown custom PCB with 3.5" TFT ; +; - ili9488 TFT SPI 4-WIRE ; +; - ft6336 touch controller ; +;***************************************************; + +[env:esp32-touchdown] +extends = esp32 +board = esp32dev + +build_flags = + ${env.build_flags} + ${esp32.build_flags} + ${esp32.vspi} ; Use VSPI hardware SPI bus + +;region -- TFT_eSPI build options ------------------------ + -D USER_SETUP_LOADED=1 + -D ILI9488_DRIVER=1 + -D TFT_ROTATION=0 ; 0=0, 1=90, 2=180 or 3=270 degree + -D TFT_WIDTH=320 + -D TFT_HEIGHT=480 + -D TFT_CS=15 ;// Chip select control pin + -D TFT_DC=2 ;// Data Command control pin + -D TFT_RST=4 ;// Reset pin (could connect to RST pin) + -D TFT_BCKL=32 ;None, configurable via web UI (e.g. 2 for D4) + -D SUPPORT_TRANSACTIONS + -D TOUCH_DRIVER=6336 ; FT6336 Capacitive touch panel driver + -D TOUCH_SDA=21 + -D TOUCH_SCL=22 + -D TOUCH_IRQ=27 + -D TOUCH_RST=-1 ; not used + -D TOUCH_FREQUENCY=400000 + -D SPI_FREQUENCY=27000000 + -D SPI_READ_FREQUENCY=16000000 +;endregion + +; -- Debugging options ----------------------------- +; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG + +;region -- Library options ------------------------------- +lib_deps = + ${env.lib_deps} + ${esp32.lib_deps} + git+https://github.com/aselectroworks/Arduino-FT6336U.git + +lib_ignore = + ${env.lib_ignore} + ${esp32.lib_ignore} +;endregion \ No newline at end of file diff --git a/user_setups/esp32/esp32cam_st7796.ini b/user_setups/esp32/esp32cam_st7796.ini index 88d4e79d..d85b7810 100644 --- a/user_setups/esp32/esp32cam_st7796.ini +++ b/user_setups/esp32/esp32cam_st7796.ini @@ -6,27 +6,14 @@ ;***************************************************; [env:esp32cam-st7796] -platform = espressif32 @ ^2.0.0 +extends = esp32 board = esp32cam -; upload_port = COM18 ; To change the port, use platform_override.ini -; monitor_port = COM18 ; To change the port, use platform_override.ini -; upload_protocol = espota ; Use ArduinoOTA after flashing over serial -; upload_port = x.x.x.x; IP of the ESP -; upload_flags = -; --port=3232 - -debug_tool = esp-prog -debug_init_break = tbreak setup -;board_build.partitions = min_spiffs.csv -monitor_filters = esp32_exception_decoder -board_build.partitions = user_setups/esp32_partition_app1300k_spiffs1216k.csv ;ESP32 CAM PINS build_flags = ${env.build_flags} ${esp32.build_flags} - -DBOARD_HAS_PSRAM - -mfix-esp32-psram-cache-issue + ${esp32.ps_ram} ;region -- TFT_eSPI build options ------------------------ ${lcd.raspberrypi} diff --git a/user_setups/esp32/huzzah32-featherwing-24.ini b/user_setups/esp32/huzzah32-featherwing-24.ini new file mode 100644 index 00000000..2c1d23fc --- /dev/null +++ b/user_setups/esp32/huzzah32-featherwing-24.ini @@ -0,0 +1,34 @@ +;***************************************************; +; HUZZAH32 ESP32 with Featherwing TFT 2.4" ; +; - HUZZAH32 esp32 board ; +; - ili9341 TFT Featherwing 2.4" ; +; - STMPE610 touch controller ; +;***************************************************; + +[env:huzzah32-featherwing-24] +extends = esp32 +board = featheresp32 + +build_flags = + ${env.build_flags} + ${esp32.build_flags} +;region -- TFT_eSPI build options ------------------------ + ${lcd.featherwing-24} + -D TFT_MISO=19 + -D TFT_MOSI=18 + -D TFT_SCLK=5 + -D TFT_DC=33 + -D TFT_CS=15 + -D TFT_RST=-1 ; RST + -D TFT_BCKL=-1 ; Solder the LITE pad to a PWM enabled pin of the ESP. + -D STMPE_CS=32 +;endregion + +lib_deps = + ${env.lib_deps} + ${esp32.lib_deps} + adafruit/Adafruit STMPE610@^1.1.3 ;STMPE610 touch controller + +lib_ignore = + ${env.lib_ignore} + ${esp32.lib_ignore} \ No newline at end of file diff --git a/user_setups/esp32/huzzah32-featherwing-35.ini b/user_setups/esp32/huzzah32-featherwing-35.ini new file mode 100644 index 00000000..0555d4b4 --- /dev/null +++ b/user_setups/esp32/huzzah32-featherwing-35.ini @@ -0,0 +1,34 @@ +;***************************************************; +; HUZZAH32 ESP32 with Featherwing TFT 3.5" ; +; - HUZZAH32 esp32 board ; +; - HX8357D TFT Featherwing 3.5" ; +; - STMPE610 touch controller ; +;***************************************************; + +[env:huzzah32-featherwing-35] +extends = esp32 +board = featheresp32 + +build_flags = + ${env.build_flags} + ${esp32.build_flags} +;region -- TFT_eSPI build options ------------------------ + ${lcd.featherwing-35} + -D TFT_MISO=19 + -D TFT_MOSI=18 + -D TFT_SCLK=5 + -D TFT_DC=33 + -D TFT_CS=15 + -D TFT_RST=-1 ; RST + -D TFT_BCKL=-1 ; Solder the LITE pad to a PWM enabled pin of the ESP. + -D STMPE_CS=32 +;endregion + +lib_deps = + ${env.lib_deps} + ${esp32.lib_deps} + adafruit/Adafruit STMPE610@^1.1.3 ;STMPE610 touch controller + +lib_ignore = + ${env.lib_ignore} + ${esp32.lib_ignore} \ No newline at end of file diff --git a/user_setups/esp32/lanbon_l8.ini b/user_setups/esp32/lanbon_l8.ini index fbfcecd0..780fb0ab 100644 --- a/user_setups/esp32/lanbon_l8.ini +++ b/user_setups/esp32/lanbon_l8.ini @@ -6,14 +6,12 @@ ;***************************************************; [env:lanbon_l8] -platform = espressif32@3.0.0 -platform_packages = framework-arduinoespressif32 -framework = arduino +extends = esp32 board = esp32dev -;upload_port = COM5 ; To change the port, use platform_override.ini -;monitor_port = COM5 ; To change the port, use platform_override.ini -monitor_filters = esp32_exception_decoder -board_build.partitions = user_setups/esp32_partition_app1300k_spiffs1216k.csv + +board_upload.flash_size=8MB +board_upload.maximum_size = 8388608 +board_build.partitions = user_setups/esp32/partition_app2000k_spiffs4000k.csv build_flags = ${env.build_flags} @@ -54,8 +52,5 @@ lib_deps = lib_ignore = ${env.lib_ignore} ${esp32.lib_ignore} + ESP32 BLE Arduino ;endregion - -extra_scripts = - ${env.extra_scripts} - ${esp32.extra_scripts} diff --git a/user_setups/esp32/lolin-d32-pro_ili9341.ini b/user_setups/esp32/lolin-d32-pro_ili9341.ini index c2d22b36..a3fb65ce 100644 --- a/user_setups/esp32/lolin-d32-pro_ili9341.ini +++ b/user_setups/esp32/lolin-d32-pro_ili9341.ini @@ -7,15 +7,13 @@ ; !! This board already defines TFT_CS, TFT_DC and TFT_RST !! -[env:lolind32pro-lolintft24] -platform = espressif32 +[env:lolin-d32-pro_ili9341] +extends = esp32 board = lolin_d32_pro -;upload_port = COM6 ; To change the port, use platform_override.ini -;monitor_port = COM6 ; To change the port, use platform_override.ini -monitor_filters = esp32_exception_decoder -board_build.partitions = user_setups/esp32_partition_app1300k_spiffs1216k.csv -check_tool = cppcheck -check_flags = --enable=all + +board_upload.flash_size=16MB +board_upload.maximum_size = 16777216 +board_build.partitions = user_setups/esp32/partition_app2000k_spiffs4000k.csv build_flags = ${env.build_flags} @@ -25,6 +23,7 @@ build_flags = ;region -- TFT_eSPI build options ------------------------ ${lcd.lolin24} ${esp32.vspi} ; Use VSPI hardware SPI bus + -D USE_TFT_ESPI ; The board already defines the macros for the TFT connector: ;-D TFT_DC=27 ; Defined by board, don't redefine !! ;-D TFT_CS=14 ; Defined by board, don't redefine !! @@ -42,7 +41,3 @@ lib_ignore = ${env.lib_ignore} ${esp32.lib_ignore} ;endregion - -extra_scripts = - ${env.extra_scripts} - ${esp32.extra_scripts} \ No newline at end of file diff --git a/user_setups/esp32/m5stack_core2.ini b/user_setups/esp32/m5stack_core2.ini index 6ea889e0..7eaa0427 100644 --- a/user_setups/esp32/m5stack_core2.ini +++ b/user_setups/esp32/m5stack_core2.ini @@ -6,14 +6,12 @@ ;***************************************************; [env:m5stack-core2] -platform = espressif32 -platform_packages = framework-arduinoespressif32 -framework = arduino +extends = esp32 board = esp32dev -;upload_port = COM5 ; To change the port, use platform_override.ini -;monitor_port = COM5 ; To change the port, use platform_override.ini -monitor_filters = esp32_exception_decoder -board_build.partitions = user_setups/esp32_partition_app1300k_spiffs1216k.csv + +board_upload.flash_size=16MB +board_upload.maximum_size = 16777216 +board_build.partitions = user_setups/esp32/partition_app2000k_spiffs4000k.csv build_flags = ${env.build_flags} @@ -42,6 +40,7 @@ lib_deps = ${env.lib_deps} ${esp32.lib_deps} git+https://github.com/aselectroworks/Arduino-FT6336U.git + https://github.com/fvanroie/M5Core2.git#AXP192 lib_ignore = ${env.lib_ignore} @@ -53,9 +52,4 @@ lib_ignore = sstaub/Ticker lv_drv_fsmc_ili9341 lv_drivers - ; AXP192 -- needed for M5Stack core2 ;endregion - -extra_scripts = - ${env.extra_scripts} - ${esp32.extra_scripts} \ No newline at end of file diff --git a/user_setups/esp32/nodemcu-32s_st7796.ini b/user_setups/esp32/nodemcu-32s_st7796.ini index 919b9ee4..5fd72ab2 100644 --- a/user_setups/esp32/nodemcu-32s_st7796.ini +++ b/user_setups/esp32/nodemcu-32s_st7796.ini @@ -6,14 +6,8 @@ ;***************************************************; [env:nodemcu32s-raspi] -platform = espressif32 @ ^2.0.0 +extends = esp32 board = nodemcu-32s -;upload_port = COM9 ; To change the port, use platform_override.ini -;monitor_port = COM9 ; To change the port, use platform_override.ini -monitor_filters = esp32_exception_decoder -board_build.partitions = user_setups/esp32_partition_app1300k_spiffs1216k.csv -debug_tool = esp-prog -debug_init_break = tbreak setup build_flags = ${env.build_flags} diff --git a/user_setups/esp32_partition_app1280k_spiffs1472k.csv b/user_setups/esp32/partition_app1280k_spiffs1472k.csv similarity index 100% rename from user_setups/esp32_partition_app1280k_spiffs1472k.csv rename to user_setups/esp32/partition_app1280k_spiffs1472k.csv diff --git a/user_setups/esp32_partition_app1300k_spiffs1216k.csv b/user_setups/esp32/partition_app1300k_spiffs1216k.csv similarity index 100% rename from user_setups/esp32_partition_app1300k_spiffs1216k.csv rename to user_setups/esp32/partition_app1300k_spiffs1216k.csv diff --git a/user_setups/esp32/partition_app1536k_spiffs1024k.csv b/user_setups/esp32/partition_app1536k_spiffs1024k.csv new file mode 100644 index 00000000..414702e0 --- /dev/null +++ b/user_setups/esp32/partition_app1536k_spiffs1024k.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x180000, +app1, app, ota_1, 0x190000, 0x180000, +spiffs, data, spiffs, 0x310000, 0x0F0000, diff --git a/user_setups/esp32/partition_app1704k_spiffs720k.csv b/user_setups/esp32/partition_app1704k_spiffs720k.csv new file mode 100644 index 00000000..cd96d227 --- /dev/null +++ b/user_setups/esp32/partition_app1704k_spiffs720k.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x1A0000, +app1, app, ota_1, 0x1B0000, 0x1A0000, +spiffs, data, spiffs, 0x350000, 0x0B0000, diff --git a/user_setups/esp32/partition_app2000k_spiffs4000k.csv b/user_setups/esp32/partition_app2000k_spiffs4000k.csv new file mode 100644 index 00000000..0ada1ac6 --- /dev/null +++ b/user_setups/esp32/partition_app2000k_spiffs4000k.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x1F0000, +app1, app, ota_1, 0x200000, 0x1F0000, +spiffs, data, spiffs, 0x3F0000, 0x410000, diff --git a/user_setups/esp32/ttgo-esp32-lilygo-pi.ini b/user_setups/esp32/ttgo-esp32-lilygo-pi.ini index 215a51ee..d6bffca3 100644 --- a/user_setups/esp32/ttgo-esp32-lilygo-pi.ini +++ b/user_setups/esp32/ttgo-esp32-lilygo-pi.ini @@ -6,17 +6,12 @@ ;***************************************************; [env:ttgo-esp32-lilygo-pi] -platform = espressif32 +extends = esp32 board = esp32dev -;upload_protocol = espota ; Use ArduinoOTA after flashing over serial -;upload_port = 10.4.70.37 ; 10.4.0.198 ; IP of the ESP -;upload_flags = -; --port=3232 -;upload_port = COM9 ; To change the port, use platform_override.ini -;monitor_port = COM9 ; To change the port, use platform_override.ini -monitor_filters = esp32_exception_decoder -board_build.partitions = user_setups/esp32_partition_app1300k_spiffs1216k.csv +board_upload.flash_size=16MB +board_upload.maximum_size = 16777216 +board_build.partitions = user_setups/esp32/partition_app2000k_spiffs4000k.csv build_flags = ${env.build_flags} @@ -40,7 +35,7 @@ build_flags = -D TFT_RST=-1 ; RST -D TFT_BCKL=12 ; None, configurable via web UI (e.g. 21) -D TOUCH_DRIVER=911 ; GT911 Capacitive I2C touch panel driver - -D TOUCH_IRQ=39 + -D TOUCH_IRQ=34 -D TOUCH_RST=-1 -D TOUCH_SDA=21 -D TOUCH_SCL=22 diff --git a/user_setups/esp32/ttgo-esp32-poe_ili9341.ini b/user_setups/esp32/ttgo-esp32-poe_ili9341.ini index cab11a22..30b0f53e 100644 --- a/user_setups/esp32/ttgo-esp32-poe_ili9341.ini +++ b/user_setups/esp32/ttgo-esp32-poe_ili9341.ini @@ -6,18 +6,9 @@ ; - xpt2046 touch controller ; ;***************************************************; -[env:ttgo_esp32_poe-lolintft24] -platform = espressif32 @ ^2.0.0 +[env:ttgo_esp32_poe-ili9341] +extends = esp32 board = esp32dev -;upload_protocol = espota ; Use ArduinoOTA after flashing over serial -;upload_port = 10.4.70.37 ; 10.4.0.198 ; IP of the ESP -;upload_flags = -; --port=3232 - -;upload_port = COM9 ; To change the port, use platform_override.ini -;monitor_port = COM9 ; To change the port, use platform_override.ini -monitor_filters = esp32_exception_decoder -board_build.partitions = user_setups/esp32_partition_app1300k_spiffs1216k.csv build_flags = ${env.build_flags} diff --git a/user_setups/esp32/wt32-sc01.ini b/user_setups/esp32/wt32-sc01.ini index 5076645f..7b489c3f 100644 --- a/user_setups/esp32/wt32-sc01.ini +++ b/user_setups/esp32/wt32-sc01.ini @@ -6,14 +6,8 @@ ;***************************************************; [env:wt32-sc01] -platform = espressif32 -platform_packages = framework-arduinoespressif32 -framework = arduino +extends = esp32 board = esp32dev -;upload_port = COM5 ; To change the port, use platform_override.ini -;monitor_port = COM5 ; To change the port, use platform_override.ini -monitor_filters = esp32_exception_decoder -board_build.partitions = user_setups/esp32_partition_app1300k_spiffs1216k.csv build_flags = ${env.build_flags} @@ -48,7 +42,3 @@ lib_ignore = ${env.lib_ignore} ${esp32.lib_ignore} ;endregion - -extra_scripts = - ${env.extra_scripts} - ${esp32.extra_scripts} \ No newline at end of file diff --git a/user_setups/esp8266/d1-mini-esp8266_ili9341.ini b/user_setups/esp8266/d1-mini-esp8266_ili9341.ini index c9998782..6eb7ac8a 100644 --- a/user_setups/esp8266/d1-mini-esp8266_ili9341.ini +++ b/user_setups/esp8266/d1-mini-esp8266_ili9341.ini @@ -6,15 +6,9 @@ ;***************************************************; [env:d1-mini-esp8266_ili9341] -platform = espressif8266@^2.6.2 +extends = esp8266 board = d1_mini -;upload_port = COM7 ; To change the port, use platform_override.ini -;monitor_port = COM7 ; To change the port, use platform_override.ini -monitor_filters = esp8266_exception_decoder -board_build.f_flash = 40000000L -board_build.flash_mode = dout -board_build.ldscript = eagle.flash.4m2m.ld ; 2Mb Spiffs -board_build.f_cpu = 160000000L ; set frequency to 160MHz + build_flags = ${env.build_flags} ${esp8266.build_flags} diff --git a/user_setups/esp8266/esp8266_st7735.ini b/user_setups/esp8266/esp8266_st7735.ini index d1637bcc..374292b6 100644 --- a/user_setups/esp8266/esp8266_st7735.ini +++ b/user_setups/esp8266/esp8266_st7735.ini @@ -5,14 +5,9 @@ ;***************************************************; [env:esp12e-st7735] -platform = espressif8266@^2.6.2 +extends = esp8266 board = esp12e -upload_port = COM8 ; To change the port, use platform_override.ini -monitor_port = COM8 ; To change the port, use platform_override.ini -board_build.f_flash = 40000000L -board_build.flash_mode = dout -board_build.ldscript = eagle.flash.4m2m.ld ; 2Mb Spiffs -board_build.f_cpu = 160000000L ; set frequency to 160MHz + build_flags = ${env.build_flags} ${esp8266.build_flags} diff --git a/user_setups/lcd_config.ini b/user_setups/lcd_config.ini index 366fd709..ee240560 100644 --- a/user_setups/lcd_config.ini +++ b/user_setups/lcd_config.ini @@ -75,7 +75,6 @@ st7789v = -D SPI_FREQUENCY=80000000 -D SPI_READ_FREQUENCY=6000000 -D USER_SETUP_LOADED=1 - ;-D TOUCH_DRIVER=6336 ; FT6336U Capacitive I2C touch panel driver -D SUPPORT_TRANSACTIONS wt32-sc01 = @@ -86,3 +85,27 @@ wt32-sc01 = -D SPI_FREQUENCY=40000000 -D USER_SETUP_LOADED=1 ;-D SUPPORT_TRANSACTIONS ; Default on ESP32 + +featherwing-35 = + -D HX8357D_DRIVER=1 + -D TFT_WIDTH=320 + -D TFT_HEIGHT=480 + -D TFT_ROTATION=0 ; Use default, see TFT_ROTATION values + -D SPI_FREQUENCY=27000000 + -D SPI_TOUCH_FREQUENCY=2500000 + -D SPI_READ_FREQUENCY=20000000 + -D USER_SETUP_LOADED=1 + -D TOUCH_DRIVER=610 ;STMPE610 + ;-D SUPPORT_TRANSACTIONS ; Default on ESP32 + +featherwing-24 = + -D ILI9341_DRIVER=1 + -D TFT_WIDTH=240 + -D TFT_HEIGHT=320 + -D TFT_ROTATION=0 ; Use default, see TFT_ROTATION values + -D SPI_FREQUENCY=27000000 + -D SPI_TOUCH_FREQUENCY=2500000 + -D SPI_READ_FREQUENCY=20000000 + -D USER_SETUP_LOADED=1 + -D TOUCH_DRIVER=610 ;STMPE610 + ;-D SUPPORT_TRANSACTIONS ; Default on ESP32 \ No newline at end of file diff --git a/user_setups/linux_sdl/linux_sdl_64bits.ini b/user_setups/linux_sdl/linux_sdl_64bits.ini new file mode 100644 index 00000000..33fb9537 --- /dev/null +++ b/user_setups/linux_sdl/linux_sdl_64bits.ini @@ -0,0 +1,95 @@ +[env:linux_sdl_64bits] +platform = native@^1.1.3 +extra_scripts = + tools/sdl2_build_extra.py + tools/linux_build_extra.py +build_flags = + ${env.build_flags} + ; ----- Monitor + -D TFT_WIDTH=240 + -D TFT_HEIGHT=320 + ; SDL drivers options + ;-D LV_LVGL_H_INCLUDE_SIMPLE + ;-D LV_DRV_NO_CONF + -D LV_MEM_SIZE=262144U ; 256kB lvgl memory + -D USE_MONITOR + -D MONITOR_ZOOM=1 ; can be fractional like 1.5 or 2 + -D USE_MOUSE + -D USE_MOUSEWHEEL + -D USE_KEYBOARD + ; ----- ArduinoJson + -D ARDUINOJSON_DECODE_UNICODE=1 + -D HASP_NUM_PAGES=12 + -D HASP_USE_SPIFFS=0 + -D HASP_USE_LITTLEFS=0 + -D HASP_USE_EEPROM=0 + -D HASP_USE_GPIO=0 + -D HASP_USE_CONFIG=0 ; Standalone application, as library + -D HASP_USE_DEBUG=1 + -D HASP_USE_MQTT=1 + -D MQTT_MAX_PACKET_SIZE=2048 + ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_INFO + ;-D LV_LOG_PRINTF=1 + ; Add recursive dirs for hal headers search + -D POSIX + -D PAHO_MQTT_STATIC + -DPAHO_WITH_SSL=TRUE + -DPAHO_BUILD_DOCUMENTATION=FALSE + -DPAHO_BUILD_SAMPLES=FALSE + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_VERBOSE_MAKEFILE=TRUE + ;-D NO_PERSISTENCE + -I.pio/libdeps/linux_sdl_64bits/paho/src + -I.pio/libdeps/linux_sdl_64bits/ArduinoJson/src + -I lib/ArduinoJson/src + -I lib/lv_fs_if + !python -c "import os; print(' '.join(['-I {}'.format(i[0].replace('\x5C','/')) for i in os.walk('hal/sdl2')]))" + ; ----- Statically linked libraries -------------------- + -lSDL2 + -lm + -lpthread + +lib_deps = + ${env.lib_deps} + ;lv_drivers@~7.9.0 + ;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/7d71907c1d6b02797d066f50984b866e080ebeed.zip + https://github.com/eclipse/paho.mqtt.c.git + bblanchon/ArduinoJson@^6.17.2 ; Json(l) parser + https://github.com/fvanroie/lv_drivers + +lib_ignore = + paho + AXP192 + ArduinoLog + lv_fs_if + +src_filter = + +<*> + -<*.h> + +<../hal/sdl2> + +<../.pio/libdeps/linux_sdl_64bits/paho/src/*.c> + +<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTClient.c> + -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTAsync.c> + -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTVersion.c> + -<../.pio/libdeps/linux_sdl_64bits/paho/src/SSLSocket.c> + + + - + - + - + - + - + - + + + - + - + + + - + - + - + + + + + + + - + + + +<../.pio/libdeps/linux_sdl_64bits/ArduinoJson/src/ArduinoJson.h> diff --git a/user_setups/stm32f4xx/STM32F407VET6_black_fsmc.ini b/user_setups/stm32f4xx/STM32F407VET6_black_fsmc.ini index eb720d23..7af5c6d8 100644 --- a/user_setups/stm32f4xx/STM32F407VET6_black_fsmc.ini +++ b/user_setups/stm32f4xx/STM32F407VET6_black_fsmc.ini @@ -22,7 +22,7 @@ ; Documentation: https://github.com/mcauser/BLACK_F407ZG [env:STM32F407VET6_black_fsmc] -platform = ststm32 +extends = stm32f4 board = black_f407ve ; upload_protocol = dfu upload_protocol = dfu @@ -50,7 +50,7 @@ build_flags = -D STM32_SERIAL1 ; Set this option to use Serial1 as default sersial port, leave out if using Serial2 ;region -- Hasp build options ---------------------------- - -D HASP_USE_TASMOTA_SLAVE=0 + -D HASP_USE_TASMOTA_CLIENT=0 -D HASP_OUTPUT_PIN=PA1 ; User LED D2 on DevEBox board -D HASP_INPUT_PIN=PA0 ; User Button K1 on DevEBox board -D HASP_USE_WIFI=0 diff --git a/user_setups/stm32f4xx/stm32f407-black_ili9341.ini b/user_setups/stm32f4xx/stm32f407-black_ili9341.ini index 57ed09f7..a6e4e8d4 100644 --- a/user_setups/stm32f4xx/stm32f407-black_ili9341.ini +++ b/user_setups/stm32f4xx/stm32f407-black_ili9341.ini @@ -6,7 +6,7 @@ ;***************************************************; [env:black_f407vg] -platform = ststm32 +extends = stm32f4 board = diymore_f407vgt board_build.mcu = stm32f407vgt6 upload_protocol = dfu @@ -32,7 +32,7 @@ build_flags = ;region -- Hasp build options ---------------------------- -D HASP_OUTPUT_PIN=PE0 ; User LED D2 on DevEBox board -D HASP_INPUT_PIN=PD15 ; User Button K1 on DevEBox board - -D HASP_USE_TASMOTA_SLAVE=1 + -D HASP_USE_TASMOTA_CLIENT=1 -D HASP_USE_OTA=0 -D HASP_USE_ETHERNET=1 ;endregion diff --git a/user_setups/stm32f4xx/stm32f407-black_ili9341_parallel.ini b/user_setups/stm32f4xx/stm32f407-black_ili9341_parallel.ini index 54221de1..930292b9 100644 --- a/user_setups/stm32f4xx/stm32f407-black_ili9341_parallel.ini +++ b/user_setups/stm32f4xx/stm32f407-black_ili9341_parallel.ini @@ -6,7 +6,7 @@ ;***************************************************; [env:stm32f4xx-parallel] -platform = ststm32 +extends = stm32f4 board = diymore_f407vgt board_build.mcu = stm32f407vet6 upload_protocol = dfu diff --git a/user_setups/stm32f4xx/stm32f407-black_ili9341_wifi.ini b/user_setups/stm32f4xx/stm32f407-black_ili9341_wifi.ini index c855aebb..a87b5fe9 100644 --- a/user_setups/stm32f4xx/stm32f407-black_ili9341_wifi.ini +++ b/user_setups/stm32f4xx/stm32f407-black_ili9341_wifi.ini @@ -6,7 +6,7 @@ ;***************************************************; [env:black_f407vg_wifi] -platform = ststm32 +extends = stm32f4 board = diymore_f407vgt board_build.mcu = stm32f407vgt6 upload_protocol = dfu @@ -44,7 +44,7 @@ build_flags = -D HASP_USE_SPIFFS=0 -D HASP_USE_EEPROM=1 -D HASP_USE_GPIO=0 - -D HASP_USE_TASMOTA_SLAVE=0 + -D HASP_USE_TASMOTA_CLIENT=0 -D HASP_USE_OTA=0 -D HASP_USE_ETHERNET=0 ;endregion diff --git a/user_setups/stm32f4xx/stm32f407-devebox_ili9341.ini b/user_setups/stm32f4xx/stm32f407-devebox_ili9341.ini index 2a5e7950..a28ab857 100644 --- a/user_setups/stm32f4xx/stm32f407-devebox_ili9341.ini +++ b/user_setups/stm32f4xx/stm32f407-devebox_ili9341.ini @@ -14,8 +14,9 @@ ; - STM32F407VET6 has 512 KB flash ; - STM32F407VGT6 has 1 MB flash -[env:DevEBox_STM32F4xx] -platform = ststm32 +;[env:DevEBox_STM32F4xx] +[env:stm32f407-devebox_ili9341] +extends = stm32f4 board = black_f407vg board_upload.maximum_size = 1048576 ; Flash size is wrong in variant ; upload_protocol = dfu @@ -52,7 +53,7 @@ build_flags = -D HASP_USE_SPIFFS=0 -D HASP_USE_EEPROM=1 -D HASP_USE_GPIO=1 - -D HASP_USE_TASMOTA_SLAVE=0 + -D HASP_USE_TASMOTA_CLIENT=0 -D HASP_USE_OTA=0 -D HASP_OUTPUT_PIN=PA1 ; User LED D2 on DevEBox board -D HASP_INPUT_PIN=PA0 ; User Button K1 on DevEBox board diff --git a/user_setups/win32/windows_sdl_64bits.ini b/user_setups/win32/windows_sdl_64bits.ini new file mode 100644 index 00000000..a679a63d --- /dev/null +++ b/user_setups/win32/windows_sdl_64bits.ini @@ -0,0 +1,116 @@ +[env:windows_sdl_64bits] +platform = native@^1.1.3 +extra_scripts = + tools/sdl2_build_extra.py + tools/windows_build_extra.py +build_flags = + ${env.build_flags} + ; ----- Monitor + -D TFT_WIDTH=240 + -D TFT_HEIGHT=320 + ; SDL drivers options + ;-D LV_LVGL_H_INCLUDE_SIMPLE + ;-D LV_DRV_NO_CONF + -D LV_MEM_SIZE=262144U ; 256kB lvgl memory + -D USE_MONITOR + -D MONITOR_ZOOM=1 ; can be fractional like 1.5 or 2 + -D USE_MOUSE + -D USE_MOUSEWHEEL + -D USE_KEYBOARD + ; ----- ArduinoJson + -D ARDUINOJSON_DECODE_UNICODE=1 + -D HASP_NUM_PAGES=12 + -D HASP_USE_SPIFFS=0 + -D HASP_USE_LITTLEFS=0 + -D HASP_USE_EEPROM=0 + -D HASP_USE_GPIO=0 + -D HASP_USE_CONFIG=0 ; Standalone application, as library + -D HASP_USE_DEBUG=1 + -D HASP_USE_MQTT=1 + -D MQTT_MAX_PACKET_SIZE=2048 + ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_INFO + ;-D LV_LOG_PRINTF=1 + ; Add recursive dirs for hal headers search + -D _WIN64 + -D WINDOWS ; We add this ourselves for code branching in hasp + -D WIN32_LEAN_AND_MEAN ; exclude a bunch of Windows header files from windows.h + -D PAHO_MQTT_STATIC + -DPAHO_WITH_SSL=TRUE + -DPAHO_BUILD_DOCUMENTATION=FALSE + -DPAHO_BUILD_SAMPLES=FALSE + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_VERBOSE_MAKEFILE=TRUE + ;-D NO_PERSISTENCE + -I.pio/libdeps/windows_sdl_64bits/paho/src + -I.pio/libdeps/windows_sdl_64bits/ArduinoJson/src + -I lib/ArduinoJson/src + -I lib/lv_fs_if + !python -c "import os; print(' '.join(['-I {}'.format(i[0].replace('\x5C','/')) for i in os.walk('hal/sdl2')]))" + -mconsole + ; ----- Statically linked libraries -------------------- + -l"ws2_32" ;windsock2 + -lrpcrt4 + -lcrypt32 + -lmingw32 + -lSDL2main + -lSDL2 + -mwindows + -lm + -ldinput8 + ;-ldxguid + ;-ldxerr8 + ;-luser32 + ;-lgdi32 + -lwinmm + -limm32 + -lole32 + -loleaut32 + ;-lshell32 + -lversion + ;-luuid + -lsetupapi + ;-lhid + +lib_deps = + ${env.lib_deps} + ;lv_drivers@~7.9.0 + ;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/7d71907c1d6b02797d066f50984b866e080ebeed.zip + https://github.com/eclipse/paho.mqtt.c.git + bblanchon/ArduinoJson@^6.17.2 ; Json(l) parser + https://github.com/fvanroie/lv_drivers + +lib_ignore = + paho + AXP192 + ArduinoLog + +src_filter = + +<*> + -<*.h> + +<../hal/sdl2> + +<../.pio/libdeps/windows_sdl_64bits/paho/src/*.c> + +<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTClient.c> + -<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTAsync.c> + -<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTVersion.c> + -<../.pio/libdeps/windows_sdl_64bits/paho/src/SSLSocket.c> + + + - + - + - + - + - + - + + + - + - + + + - + - + - + + + + + + + - + + + +<../.pio/libdeps/windows_sdl_64bits/ArduinoJson/src/ArduinoJson.h>