diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 6c98f4bd3..000000000 --- a/.gitmodules +++ /dev/null @@ -1,9 +0,0 @@ -[submodule "lv_drivers"] - path = lv_drivers - url = https://github.com/lvgl/lv_drivers.git -[submodule "lvgl"] - path = lvgl - url = https://github.com/lvgl/lvgl.git -[submodule "FreeRTOS"] - path = FreeRTOS - url = https://github.com/FreeRTOS/FreeRTOS-Kernel.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 61e594740..c72617d9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,12 @@ -cmake_minimum_required(VERSION 3.12.4) +cmake_minimum_required(VERSION 3.10) +set(CMAKE_C_COMPILER "gcc" CACHE STRING "C compiler" FORCE) project(lvgl C CXX) +set(CMAKE_BUILD_TYPE Debug) # Set the correct FreeRTOS port for your system (e.g., Posix for WSL) set(FREERTOS_PORT GCC_POSIX CACHE STRING "Port for FreeRTOS on Posix environment") -set(LVGL_PRO_PROJECT_DIR - "" - CACHE PATH "Path to LVGL Pro Project folder") +unset(USE_FREERTOS CACHE) option(USE_FREERTOS "Enable FreeRTOS" OFF) # Turn this on to enable FreeRTOS @@ -38,14 +38,18 @@ else() endif() # Main include files of the project -include_directories(${PROJECT_SOURCE_DIR}/main/inc) +include_directories(${PROJECT_SOURCE_DIR}) +include_directories(${PROJECT_SOURCE_DIR}/src) +include_directories(${PROJECT_SOURCE_DIR}/i18n) +include_directories(${PROJECT_SOURCE_DIR}/ioc) + # Define options for LVGL with default values (OFF) option(LV_USE_DRAW_SDL "Use SDL draw unit" OFF) option(LV_USE_LIBPNG "Use libpng to decode PNG" OFF) option(LV_USE_LIBJPEG_TURBO "Use libjpeg turbo to decode JPEG" OFF) option(LV_USE_FFMPEG "Use libffmpeg to display video using lv_ffmpeg" OFF) -option(LV_USE_FREETYPE "Use freetype library" OFF) +option(LV_USE_FREETYPE "Use freetype library" ON) # Set C and C++ standards set(CMAKE_C_STANDARD 99) @@ -73,6 +77,20 @@ set(MAIN_SOURCES src/mouse_cursor_icon.c src/hal/hal.c) set(MAIN_LIBS lvgl lvgl::examples lvgl::demos lvgl::thorvg ${SDL2_LIBRARIES}) # Create the main executable, depending on the FreeRTOS option +file(GLOB_RECURSE SOURCES + "${PROJECT_SOURCE_DIR}/ioc/*.c" + "${PROJECT_SOURCE_DIR}/i18n/*.c" + "${PROJECT_SOURCE_DIR}/pages/*.c" + "${PROJECT_SOURCE_DIR}/pages_mngr.c" +) + +# 排除 zlog 文件夹里的文件 +foreach(file ${SOURCES}) + if(file MATCHES ".*/ioc/zlog/.*\\.c$") + list(REMOVE_ITEM SOURCES ${file}) + endif() +endforeach() + if(USE_FREERTOS) list(APPEND MAIN_SOURCES src/freertos_main.c src/freertos/freertos_posix_port.c ${FREERTOS_SOURCES}) list(APPEND MAIN_LIBS freertos_config freertos_kernel) @@ -141,7 +159,7 @@ if(LVGL_PRO_PROJECT_DIR) endif() endif() -add_executable(main ${MAIN_SOURCES}) +add_executable(main ${MAIN_SOURCES} ${SOURCES}) target_compile_definitions(main PRIVATE LV_CONF_INCLUDE_SIMPLE) target_link_libraries(main ${MAIN_LIBS}) @@ -153,6 +171,7 @@ if (WIN32) else() target_link_options(main PRIVATE "-mconsole") endif() + target_link_libraries(main ws2_32) endif() # Apply additional compile options if the build type is Debug diff --git a/Charger_PreDefine.h b/Charger_PreDefine.h new file mode 100644 index 000000000..2b0b4e2e9 --- /dev/null +++ b/Charger_PreDefine.h @@ -0,0 +1,18 @@ + +#ifndef __CHARGER_PRE_DEFINE_H__ +#define __CHARGER_PRE_DEFINE_H__ + +// 统一编译选项, 把AC/DC, MT7628/AM3354/SSD202合并到一个项目中, 集中处理各种编译选项 +#define COMPILE_FOR_AC_X86 0 +#define COMPILE_FOR_AC_MT7628 1 // MT7628主板, 目前用于家用塑壳和商用铁壳/落地 +#define COMPILE_FOR_DC_AM3354 2 // AM3354主板, 目前用于嘉盛直流桩 +#define COMPILE_FOR_AC_SSD202 3 // SSD202主板, 目前替代MT7628主板, 后续可能替换直流桩, 待定 +#define COMPILE_FOR_CABINET_AM3354 4 // AM3354主板, 目前用于分体式直流桩 +#define COMPILE_FOR_CABINET_SSD202 5 // SSD202控制盒主板, 分体式直流桩的终端控制盒用于小直流和移动桩时使用 +#define COMPILE_FOR_SSD202_43 6 //4.3寸屏幕 + +#define CHARGER_TYPE_AC_ONLY 1 // 全交流枪充电桩 +#define CHARGER_TYPE_DC 2 // 直流枪充电桩, 可包含交流(交直流一体) +#define CHARGER_TYPE_DC_CABINET 3 // 直流分体充电桩(可包含交流终端) 和采用分体架构的小直流等 + +#endif diff --git a/assets/fonts/D-DIN-PRO-600-SemiBold.otf b/assets/fonts/D-DIN-PRO-600-SemiBold.otf new file mode 100644 index 000000000..5f94c2351 Binary files /dev/null and b/assets/fonts/D-DIN-PRO-600-SemiBold.otf differ diff --git a/assets/fonts/calibri.ttf b/assets/fonts/calibri.ttf new file mode 100644 index 000000000..aac472615 Binary files /dev/null and b/assets/fonts/calibri.ttf differ diff --git a/assets/fonts/calibrib.ttf b/assets/fonts/calibrib.ttf new file mode 100644 index 000000000..72ad9cf98 Binary files /dev/null and b/assets/fonts/calibrib.ttf differ diff --git a/assets/fragment/fragment_00001_btn_text.json b/assets/fragment/fragment_00001_btn_text.json new file mode 100644 index 000000000..e2c349f5c --- /dev/null +++ b/assets/fragment/fragment_00001_btn_text.json @@ -0,0 +1,21 @@ +{ + "name": "fragment_btn_text", + "desc": "帮助按钮类似的130*40按钮, 内置一个文本", + "type": "button", + "properties": { + "style":"style-button-help-language" + }, + "children": [ + { + "name": "text", + "desc": "按钮上的文本", + "type": "label", + "properties": { + "text": "Help", + "align": "LV_ALIGN_CENTER", + "style": "style-text-primary", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00002_btn_language.json b/assets/fragment/fragment_00002_btn_language.json new file mode 100644 index 000000000..59d4183f3 --- /dev/null +++ b/assets/fragment/fragment_00002_btn_language.json @@ -0,0 +1,35 @@ +{ + "name": "fragment_btn_language", + "desc": "语言按钮, 包含一个图标和一个文字", + "type": "button", + "properties": { + "style": "style-button-help-language" + }, + "children": [ + { + "name": "icon", + "desc": "图标", + "type": "image", + "properties": { + "x_ofs":22, + "width": 32, + "height": 32, + "align": "LV_ALIGN_LEFT_MID", + "src": "english", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "label", + "desc": "文字", + "type": "label", + "properties": { + "text": "English", + "x_ofs":56, + "align": "LV_ALIGN_LEFT_MID", + "style": "style-text-primary", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00003_btn_primary.json b/assets/fragment/fragment_00003_btn_primary.json new file mode 100644 index 000000000..24d04dbdb --- /dev/null +++ b/assets/fragment/fragment_00003_btn_primary.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_btn_primary", + "desc": "close按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "btn_label", + "type": "label", + "properties": { + "text": "", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00004_connector_quad_card.json b/assets/fragment/fragment_00004_connector_quad_card.json new file mode 100644 index 000000000..5babdbe15 --- /dev/null +++ b/assets/fragment/fragment_00004_connector_quad_card.json @@ -0,0 +1,153 @@ +{ + "name": "fragment_connector_card_quad", + "desc": "四枪的单个卡片, 有 Idle/Starting/Charging/Suspend/Finished/Reserved/Fault/Unavailable", + "type": "button", + "properties": { + "style": "style-connector-quad-default", + "width": 184, + "height": 123, + "style_checked": "style-connector-quad-checked" + }, + "children": [ + { + "name": "conn_card_id", + "desc": "枪号带背景", + "type": "fragment", + "fragment_name" : "fragment_conn_card_id", + + "properties": { + "x": 14, + "y": 14 + } + }, + { + "name": "conn_card_state", + "desc" : "当前状态, 右对齐, 注意不同语言越界", + "type": "label", + "properties": { + "text": "Idle", + "x_ofs": -14, + "y_ofs": 19, + "align": "LV_ALIGN_TOP_RIGHT", + "style": "style-connector-quad-default-state-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_type", + "desc": "充电枪类型, 左对齐, Idle/Suspend/Fault/Starting/Stopping/Error/Fault/Unavailable", + "type": "label", + "properties": { + "text": "CCS2(DC)", + "x": 14, + "y": 65, + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_power_rated", + "desc": "额定功率, 左对齐, Idle/Suspend/Fault/Starting/Stopping/Error/Fault/Unavailable", + "type": "label", + "properties": { + "text": "120.0kW", + "x": 14, + "y": 89, + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_type_icon", + "desc" : "充电枪类型图标, Idle/Suspend/Fault/Starting/Stopping/Error/Fault/Unavailable", + "type": "image", + "properties": { + "src": "ccs2-dc", + "width": 47, + "height": 47, + "x_ofs": -14, + "y_ofs": -14, + "align": "LV_ALIGN_BOTTOM_RIGHT" + } + }, + { + "name": "conn_card_time_title", + "desc": "计时时间提示信息, Reserved为剩余时间, Finished为占位时间", + "type": "label", + "properties": { + "text": "Idle time", + "x": 14, + "y": 65, + "hidden": true, + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_time", + "desc": "计时时间值, Reserved为剩余时间, Finished为占位时间", + "type": "label", + "properties": { + "text": "04:24", + "x": 14, + "y": 89, + "hidden": true, + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_soc_bar", + "desc": "充电中SoC进度条", + "type": "bar", + "properties": { + "x_ofs": 14, + "y_ofs": 65, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-charging_bar_bg_size", + "style_indic": "style-charging_bar_indic" + } + }, + { + "name": "conn_card_soc", + "desc": "充电中SoC值", + "type": "label", + "properties": { + "text": "12%", + "x_ofs": 14, + "y_ofs": 89, + "width": 50, + "height": 20, + "align": "LV_ALIGN_TOP_LEFT", + "hidden": true, + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_power_real", + "desc": "充电中实时功率, 右对齐", + "type": "label", + "properties": { + "text": "102.5kW", + "x_ofs": -14, + "y_ofs": 89, + "align": "LV_ALIGN_TOP_RIGHT", + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_plug_gun_icon", + "desc" : "插枪提示的绿色图标", + "type": "image", + "properties": { + "src": "icon_connected", + "width": 20, + "height": 20, + "x": 148, + "y": 91 + } + } + ] +} diff --git a/assets/fragment/fragment_00005_connector_no.json b/assets/fragment/fragment_00005_connector_no.json new file mode 100644 index 000000000..99b28c01d --- /dev/null +++ b/assets/fragment/fragment_00005_connector_no.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_conn_card_id", + "desc": "枪id, 内置一个文本", + "type": "flex", + "properties": { + "style": "style-connector-quad-default-num-border" + }, + "children": [ + { + "name": "NoText", + "type": "label", + "properties": { + "text": "1", + "align" : "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-num-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00006_charging_processing.json b/assets/fragment/fragment_00006_charging_processing.json new file mode 100644 index 000000000..c0b8f6028 --- /dev/null +++ b/assets/fragment/fragment_00006_charging_processing.json @@ -0,0 +1,50 @@ +{ + "name": "fragment_charging_process", + "desc": "充电开始前处理阶段", + "type": "flex", + "properties": { + "style": "style-checkbox" + }, + "children": [ + { + "name": "charging_process_gif", + "type": "gif", + "properties": { + "x_ofs": 318, + "y_ofs": 102, + "align": "LV_ALIGN_TOP_LEFT", + "src": "processing" + } + }, + { + "name": "charging_process_title", + "desc": "", + "type": "label", + "properties": { + "text": "", + "x_ofs": 0, + "y_ofs": 260, + "width": 400, + "height": 40, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_label", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "charging_process_subtitle", + "desc": "", + "type": "label", + "properties": { + "text": "it may takes few minutes.", + "x_ofs": 0, + "y_ofs": 296, + "width": 400, + "height": 40, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00007_charging_error.json b/assets/fragment/fragment_00007_charging_error.json new file mode 100644 index 000000000..f92d18926 --- /dev/null +++ b/assets/fragment/fragment_00007_charging_error.json @@ -0,0 +1,71 @@ +{ + "name": "fragment_charging_error", + "desc": "充电失败界面", + "type": "flex", + "properties": { + "width": 760, + "height": 370, + "style": "style-checkbox" + }, + "children": [ + { + "name": "charging_error_draw_icon", + "desc": "充电错误图标", + "type": "fragment", + "fragment_name":"fragment_charging_error_draw_icon", + "properties": { + "x": 351, + "y": 84 + } + }, + { + "name": "charging_error_title", + "type": "label", + "properties": { + "text": "Charging start error", + "x_ofs": 0, + "y_ofs": 168, + "width": 400, + "height": 30, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_label", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "charging_error_code", + "desc": "错误码文本和值", + "type": "fragment", + "fragment_name": "fragment_start_error_code", + "properties": { + "x_ofs": 0, + "y_ofs": 190, + "align": "LV_ALIGN_TOP_MID" + } + }, + { + "name": "charging_error_subtitle", + "desc": "错误提示", + "type": "label", + "properties": { + "text": "Your credit has not been charged. To start a new charging session,please reconnect.", + "x_ofs": 0, + "y_ofs": 220, + "width": 416, + "height": 60, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "charging_error_continue_btn", + "type": "fragment", + "fragment_name" : "fragment_continue_btn", + "properties": { + "x": 281, + "y": 290 + } + } + ] +} diff --git a/assets/fragment/fragment_00008_home_info_card.json b/assets/fragment/fragment_00008_home_info_card.json new file mode 100644 index 000000000..a09d692d4 --- /dev/null +++ b/assets/fragment/fragment_00008_home_info_card.json @@ -0,0 +1,141 @@ +{ + "name": "fragment_home_info_card", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 300, + "style":"style-info_card" + }, + "children": [ + { + "name": "qr_code_home", + "type": "qr", + "properties": { + "x_ofs": 85, + "y_ofs": 20, + "size": 94, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "qr_code_prompt_home", + "desc": "二维码提示文本", + "type": "label", + "properties": { + "text": "Download Ioc APP for a faster experience.", + "width": 227, + "x_ofs": 18, + "y_ofs": 127, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "charger_station_img_home", + "desc": "充电桩状态图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 184, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_charging-station" + } + }, + { + "name": "charger_station_label_home", + "desc": "充电桩状态文本", + "type": "label", + "properties": { + "text": "Charger id:", + "x_ofs": 65, + "y_ofs": 185, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "contact_img_home", + "desc": "联系图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 208, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_contact" + } + }, + { + "name": "contact_label_home", + "desc": "联系文本", + "type": "label", + "properties": { + "text": "0878-1058-4499", + "x_ofs": 65, + "y_ofs": 209, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "telephone_img_home", + "desc": "移动电话图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 232, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_telephone" + } + }, + { + "name": "telephone_label_home", + "desc": "移动电话文本", + "type": "label", + "properties": { + "text": "(021)5088-6428", + "x_ofs": 65, + "y_ofs": 233, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "url_img_home", + "desc": "网址图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 256, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_url" + } + }, + { + "name": "url_label_home", + "desc": "网址文本", + "type": "label", + "properties": { + "text": "Ioc.id", + "x_ofs": 65, + "y_ofs": 257, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00011_idle_info_card.json b/assets/fragment/fragment_00011_idle_info_card.json new file mode 100644 index 000000000..8e49b9911 --- /dev/null +++ b/assets/fragment/fragment_00011_idle_info_card.json @@ -0,0 +1,219 @@ +{ + "name": "fragment_idle_info_card", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "current_time_img_idle", + "desc": "当前时间段图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 38, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_current-time" + } + }, + { + "name": "current_time_label_idle", + "desc": "当前时间段文本", + "type": "label", + "properties": { + "text": "Current Period", + "x_ofs": 30, + "y_ofs": 64, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_idle", + "desc": "当前时间段", + "type": "label", + "properties": { + "text": "13:00-14:00", + "x_ofs": 30, + "y_ofs": 92, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_kwh_idle", + "desc": "当前时间段kwh计费", + "type": "label", + "properties": { + "text": "34.3$/Kwh", + "x_ofs": 150, + "y_ofs": 38, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_hr_idle", + "desc": "当前时间段hr计费", + "type": "label", + "properties": { + "text": "34.3$/hr", + "x_ofs": 150, + "y_ofs": 65, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_times_idle", + "desc": "当前时间段times计费", + "type": "label", + "properties": { + "text": "34.3$/times", + "x_ofs": 150, + "y_ofs": 92, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_circle_idle", + "desc": "当前时间段小圆点", + "type": "flex", + "properties": { + "width": 6, + "height": 6, + "x_ofs": 19, + "y_ofs": 73, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-idle-curtime-circle" + } + }, + { + "name": "split_line_idle", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 203, + "height": 1, + "x_ofs": 0, + "y_ofs": 0, + "align": "LV_ALIGN_CENTER", + "style": "style-split" + } + }, + { + "name": "next_period_img_idle", + "desc": "下一时间段图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 178, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_next-period" + } + }, + { + "name": "next_period_label_idle", + "desc": "下一时间段文本", + "type": "label", + "properties": { + "text": "Next Period", + "x_ofs": 30, + "y_ofs": 204, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_idle", + "desc": "下一时间段", + "type": "label", + "properties": { + "text": "14:00-15:00", + "x_ofs": 30, + "y_ofs": 232, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_kwh_idle", + "desc": "下一时间段kwh计费", + "type": "label", + "properties": { + "text": "34.3$/Kwh", + "x_ofs": 150, + "y_ofs": 178, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_hr_idle", + "desc": "下一时间段hr计费", + "type": "label", + "properties": { + "text": "34.3$/hr", + "x_ofs": 150, + "y_ofs": 205, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_times_idle", + "desc": "下一时间段times计费", + "type": "label", + "properties": { + "text": "34.3$/times", + "x_ofs": 150, + "y_ofs": 232, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_circle_idle", + "desc": "下一时间段小圆点", + "type": "flex", + "properties": { + "width": 6, + "height": 6, + "x_ofs": 19, + "y_ofs": 213, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-idle-netper-circle" + } + }, + { + "name": "ocpp_price", + "desc": "ocpp价格", + "type": "label", + "properties": { + "text": "0.15 $/kWh, idle fee after charging: 1 $/hr", + "width": 243, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00014_starting1_info_card.json b/assets/fragment/fragment_00014_starting1_info_card.json new file mode 100644 index 000000000..1dd544051 --- /dev/null +++ b/assets/fragment/fragment_00014_starting1_info_card.json @@ -0,0 +1,219 @@ +{ + "name": "fragment_starting1_info_card", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "current_time_img_starting1", + "desc": "当前时间段图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 38, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_current-time" + } + }, + { + "name": "current_time_label_starting1", + "desc": "当前时间段文本", + "type": "label", + "properties": { + "text": "Current Period", + "x_ofs": 30, + "y_ofs": 64, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_starting1", + "desc": "当前时间段", + "type": "label", + "properties": { + "text": "13:00-14:00", + "x_ofs": 30, + "y_ofs": 92, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_kwh_starting1", + "desc": "当前时间段kwh计费", + "type": "label", + "properties": { + "text": "34.3$/Kwh", + "x_ofs": 150, + "y_ofs": 38, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_hr_starting1", + "desc": "当前时间段hr计费", + "type": "label", + "properties": { + "text": "34.3$/hr", + "x_ofs": 150, + "y_ofs": 65, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_times_starting1", + "desc": "当前时间段times计费", + "type": "label", + "properties": { + "text": "34.3$/times", + "x_ofs": 150, + "y_ofs": 92, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_circle_starting1", + "desc": "当前时间段小圆点", + "type": "flex", + "properties": { + "width": 6, + "height": 6, + "x_ofs": 19, + "y_ofs": 73, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-idle-curtime-circle" + } + }, + { + "name": "split_line_starting1", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 203, + "height": 1, + "x_ofs": 0, + "y_ofs": 0, + "align": "LV_ALIGN_CENTER", + "style": "style-split" + } + }, + { + "name": "next_period_img_starting1", + "desc": "下一时间段图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 178, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_next-period" + } + }, + { + "name": "next_period_label_starting1", + "desc": "下一时间段文本", + "type": "label", + "properties": { + "text": "Next Period", + "x_ofs": 30, + "y_ofs": 204, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_starting1", + "desc": "下一时间段", + "type": "label", + "properties": { + "text": "14:00-15:00", + "x_ofs": 30, + "y_ofs": 232, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_kwh_starting1", + "desc": "下一时间段kwh计费", + "type": "label", + "properties": { + "text": "34.3$/Kwh", + "x_ofs": 150, + "y_ofs": 178, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_hr_starting1", + "desc": "下一时间段hr计费", + "type": "label", + "properties": { + "text": "34.3$/hr", + "x_ofs": 150, + "y_ofs": 205, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_times_starting1", + "desc": "下一时间段times计费", + "type": "label", + "properties": { + "text": "34.3$/times", + "x_ofs": 150, + "y_ofs": 232, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_circle_starting1", + "desc": "下一时间段小圆点", + "type": "flex", + "properties": { + "width": 6, + "height": 6, + "x_ofs": 19, + "y_ofs": 213, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-idle-netper-circle" + } + }, + { + "name": "ocpp_price", + "desc": "ocpp价格", + "type": "label", + "properties": { + "text": "0.15 $/kWh, idle fee after charging: 1 $/hr", + "width": 243, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00017_starting2_info_card.json b/assets/fragment/fragment_00017_starting2_info_card.json new file mode 100644 index 000000000..9a49f73cb --- /dev/null +++ b/assets/fragment/fragment_00017_starting2_info_card.json @@ -0,0 +1,219 @@ +{ + "name": "fragment_starting2_info_card", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "current_time_img_starting2", + "desc": "当前时间段图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 38, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_current-time" + } + }, + { + "name": "current_time_label_starting2", + "desc": "当前时间段文本", + "type": "label", + "properties": { + "text": "Current Period", + "x_ofs": 30, + "y_ofs": 64, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_starting2", + "desc": "当前时间段", + "type": "label", + "properties": { + "text": "13:00-14:00", + "x_ofs": 30, + "y_ofs": 92, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_kwh_starting2", + "desc": "当前时间段kwh计费", + "type": "label", + "properties": { + "text": "34.3$/Kwh", + "x_ofs": 150, + "y_ofs": 38, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_hr_starting2", + "desc": "当前时间段hr计费", + "type": "label", + "properties": { + "text": "34.3$/hr", + "x_ofs": 150, + "y_ofs": 65, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_times_starting2", + "desc": "当前时间段times计费", + "type": "label", + "properties": { + "text": "34.3$/times", + "x_ofs": 150, + "y_ofs": 92, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_circle_starting2", + "desc": "当前时间段小圆点", + "type": "flex", + "properties": { + "width": 6, + "height": 6, + "x_ofs": 19, + "y_ofs": 73, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-idle-curtime-circle" + } + }, + { + "name": "split_line_starting2", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 203, + "height": 1, + "x_ofs": 0, + "y_ofs": 0, + "align": "LV_ALIGN_CENTER", + "style": "style-split" + } + }, + { + "name": "next_period_img_starting2", + "desc": "下一时间段图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 178, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_next-period" + } + }, + { + "name": "next_period_label_starting2", + "desc": "下一时间段文本", + "type": "label", + "properties": { + "text": "Next Period", + "x_ofs": 30, + "y_ofs": 204, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_starting2", + "desc": "下一时间段", + "type": "label", + "properties": { + "text": "14:00-15:00", + "x_ofs": 30, + "y_ofs": 232, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_kwh_starting2", + "desc": "下一时间段kwh计费", + "type": "label", + "properties": { + "text": "34.3$/Kwh", + "x_ofs": 150, + "y_ofs": 178, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_hr_starting2", + "desc": "下一时间段hr计费", + "type": "label", + "properties": { + "text": "34.3$/hr", + "x_ofs": 150, + "y_ofs": 205, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_times_starting2", + "desc": "下一时间段times计费", + "type": "label", + "properties": { + "text": "34.3$/times", + "x_ofs": 150, + "y_ofs": 232, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "next_period_circle_starting2", + "desc": "下一时间段小圆点", + "type": "flex", + "properties": { + "width": 6, + "height": 6, + "x_ofs": 19, + "y_ofs": 213, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-idle-netper-circle" + } + }, + { + "name": "ocpp_price", + "desc": "ocpp价格", + "type": "label", + "properties": { + "text": "0.15 $/kWh, idle fee after charging: 1 $/hr", + "width": 243, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00020_charging_info_card.json b/assets/fragment/fragment_00020_charging_info_card.json new file mode 100644 index 000000000..5fda37b42 --- /dev/null +++ b/assets/fragment/fragment_00020_charging_info_card.json @@ -0,0 +1,100 @@ +{ + "name": "fragment_charging_info_card", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "current_time_kwh_charging", + "desc": "当前时间段kwh计费", + "type": "label", + "properties": { + "text": "34.3$/Kwh", + "x_ofs": 30, + "y_ofs": 30, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_hr_charging", + "desc": "当前时间段hr计费", + "type": "label", + "properties": { + "text": "34.3$/hr", + "x_ofs": 30, + "y_ofs": 57, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_times_charging", + "desc": "当前时间段times计费", + "type": "label", + "properties": { + "text": "34.3$/times", + "x_ofs": 30, + "y_ofs": 84, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "split_line_charging", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 203, + "height": 1, + "x_ofs": 30, + "y_ofs": 118, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-split" + } + }, + { + "name": "estimated_cost_prompt_charging", + "desc": "预估金额提示", + "type": "label", + "properties": { + "text": "Estimated Cost", + "x_ofs": 30, + "y_ofs": 133, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "estimated_cost_charging", + "desc": "预估金额", + "type": "label", + "properties": { + "text": "34.3$", + "x_ofs": 30, + "y_ofs": 166, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "btn", + "desc": "充电详细数据", + "type": "fragment", + "fragment_name": "fragment_detailed_data_charging", + "properties": { + "x" : 32, + "y" : 210 + } + } + ] +} diff --git a/assets/fragment/fragment_00022_charging_detailed_data.json b/assets/fragment/fragment_00022_charging_detailed_data.json new file mode 100644 index 000000000..245815d2a --- /dev/null +++ b/assets/fragment/fragment_00022_charging_detailed_data.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_detailed_data_charging", + "desc": "充电详细信息", + "type": "button", + "properties": { + "style": "style-detailed_data_charging" + }, + "children": [ + { + "name": "label", + "type": "label", + "properties": { + "text": "Detailed Data", + "align" : "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00024_finished_info_card.json b/assets/fragment/fragment_00024_finished_info_card.json new file mode 100644 index 000000000..992644d93 --- /dev/null +++ b/assets/fragment/fragment_00024_finished_info_card.json @@ -0,0 +1,148 @@ +{ + "name": "fragment_finished_info_card", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "idle_time_label_finished", + "desc": "停充后的idele time 文本", + "type": "label", + "properties": { + "text": "Idle time", + "x_ofs": 0, + "y_ofs": -100, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "idle_time_value_finished", + "desc": "停充后的占位时间", + "type": "label", + "properties": { + "text": "04:24", + "x_ofs": 0, + "y_ofs": -60, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "idle_time_prompt_finished", + "desc": "拔枪剩余时间提醒", + "type": "label", + "properties": { + "text": "Please move your vehicle.10mins grace period exceeded.", + "x_ofs": 14, + "y_ofs": 102, + "width": 235, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "split_line_finished", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 225, + "height": 2, + "x_ofs": 19, + "y_ofs": 162, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-split" + } + }, + { + "name": "charging_cost_label_finished", + "desc": "充电花费金额文本", + "type": "label", + "properties": { + "text": "Charging cost", + "x_ofs": 20, + "y_ofs": 172, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "charging_cost_value_finished", + "desc": "充电花费金额", + "type": "label", + "properties": { + "text": "34.3$", + "x_ofs": 203, + "y_ofs": 172, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "idle_fee_label_finished", + "desc": "闲置费文本", + "type": "label", + "properties": { + "text": "Idle fee", + "x_ofs": 20, + "y_ofs": 200, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "idle_fee_value_finished", + "desc": "闲置费", + "type": "label", + "properties": { + "text": "34.3$", + "x_ofs": 203, + "y_ofs": 200, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "total_amount_label_finished", + "desc": "总金额文本", + "type": "label", + "properties": { + "text": "Total Amount", + "x_ofs": 20, + "y_ofs": 240, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "total_amount_value_finished", + "desc": "总金额", + "type": "label", + "properties": { + "text": "134.3$", + "x_ofs": 171, + "y_ofs": 240, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00027_reserved_info_card.json b/assets/fragment/fragment_00027_reserved_info_card.json new file mode 100644 index 000000000..b96379d36 --- /dev/null +++ b/assets/fragment/fragment_00027_reserved_info_card.json @@ -0,0 +1,172 @@ +{ + "name": "fragment_reserved_info_card", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "Left_label_reserved", + "desc": "预约剩余时间文本", + "type": "label", + "properties": { + "text": "Left", + "x_ofs": 0, + "y_ofs": -100, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "idle_time_value_reserved", + "desc": "拔枪剩余时间", + "type": "label", + "properties": { + "text": "04:24", + "x_ofs": 0, + "y_ofs": -60, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "plug", + "desc": "闲置费文本", + "type": "label", + "properties": { + "text": "Plug in first", + "x_ofs": 0, + "y_ofs": -15, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "split_line_reserved", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 203, + "height": 1, + "x_ofs": 30, + "y_ofs": 139, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-split" + } + }, + { + "name": "current_time_img_reserved", + "desc": "当前时间段图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 168, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_current-time" + } + }, + { + "name": "current_time_circle_reserved", + "desc": "当前时间段小圆点", + "type": "flex", + "properties": { + "width": 6, + "height": 6, + "x_ofs": 20, + "y_ofs": 203, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-idle-curtime-circle" + } + }, + { + "name": "current_time_label_reserved", + "desc": "当前时间段文本", + "type": "label", + "properties": { + "text": "Current Period", + "x_ofs": 30, + "y_ofs": 194, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_value_reserved", + "desc": "当前时间段值", + "type": "label", + "properties": { + "text": "13:00-14:00", + "x_ofs": 30, + "y_ofs": 222, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_kwh_reserved", + "desc": "当前时间段kwh计费", + "type": "label", + "properties": { + "text": "34.3$/Kwh", + "x_ofs": 150, + "y_ofs": 168, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_hr_reserved", + "desc": "当前时间段hr计费", + "type": "label", + "properties": { + "text": "34.3$/hr", + "x_ofs": 150, + "y_ofs": 195, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "current_time_times_reserved", + "desc": "当前时间段times计费", + "type": "label", + "properties": { + "text": "34.3$/times", + "x_ofs": 150, + "y_ofs": 222, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "ocpp_price", + "desc": "ocpp 价格体系文本框", + "type": "fragment", + "fragment_name": "fragment_ocpp_price", + "properties": { + "x_ofs": 0, + "y_ofs": 140, + "align": "LV_ALIGN_TOP_LEFT" + } + } + ] +} diff --git a/assets/fragment/fragment_00030_session_error_info_card.json b/assets/fragment/fragment_00030_session_error_info_card.json new file mode 100644 index 000000000..14807ccbe --- /dev/null +++ b/assets/fragment/fragment_00030_session_error_info_card.json @@ -0,0 +1,141 @@ +{ + "name": "fragment_session_error_info_card", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "qr_code_session_error", + "type": "qr", + "properties": { + "x_ofs": 85, + "y_ofs": 20, + "size": 94, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "qr_code_prompt_session_error", + "desc": "二维码提示文本", + "type": "label", + "properties": { + "text": "Download Ioc APP for a faster experience.", + "width": 227, + "x_ofs": 18, + "y_ofs": 127, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "charger_station_img_session_error", + "desc": "充电桩状态图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 174, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_charging-station" + } + }, + { + "name": "charger_station_label_session_error", + "desc": "充电桩状态文本", + "type": "label", + "properties": { + "text": "Charger id:", + "x_ofs": 65, + "y_ofs": 175, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "contact_img_session_error", + "desc": "联系图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 198, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_contact" + } + }, + { + "name": "contact_label_session_error", + "desc": "联系文本", + "type": "label", + "properties": { + "text": "0878-1058-4499", + "x_ofs": 65, + "y_ofs": 199, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "telephone_img_session_error", + "desc": "移动电话图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 222, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_telephone" + } + }, + { + "name": "telephone_label_session_error", + "desc": "移动电话文本", + "type": "label", + "properties": { + "text": "(021)5088-6428", + "x_ofs": 65, + "y_ofs": 223, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "url_img_session_error", + "desc": "网址图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 246, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_url" + } + }, + { + "name": "url_label_session_error", + "desc": "网址文本", + "type": "label", + "properties": { + "text": "Ioc.id", + "x_ofs": 65, + "y_ofs": 247, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00032_session_error_circle.json b/assets/fragment/fragment_00032_session_error_circle.json new file mode 100644 index 000000000..e0f40fc55 --- /dev/null +++ b/assets/fragment/fragment_00032_session_error_circle.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_session_error_circle", + "desc": "感叹号", + "type": "flex", + "properties": { + "style": "style-session_error-circle" + }, + "children": [ + { + "name": "!_session_error", + "type": "label", + "properties": { + "text": "!", + "align" : "LV_ALIGN_CENTER", + "style": "style-draw_icon_symbol", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00033_session_error_continue.json b/assets/fragment/fragment_00033_session_error_continue.json new file mode 100644 index 000000000..dfdcceee1 --- /dev/null +++ b/assets/fragment/fragment_00033_session_error_continue.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_session_error_continue", + "desc": "continue按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "continue_label_session_error", + "type": "label", + "properties": { + "text": "Continue", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00035_start_error_info_card.json b/assets/fragment/fragment_00035_start_error_info_card.json new file mode 100644 index 000000000..d864893dc --- /dev/null +++ b/assets/fragment/fragment_00035_start_error_info_card.json @@ -0,0 +1,141 @@ +{ + "name": "fragment_start_error_info_card", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "qr_code_start_error", + "type": "qr", + "properties": { + "x_ofs": 85, + "y_ofs": 20, + "size": 94, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "qr_code_prompt_start_error", + "desc": "二维码提示文本", + "type": "label", + "properties": { + "text": "Download Ioc APP for a faster experience.", + "width": 227, + "x_ofs": 18, + "y_ofs": 127, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "charger_station_img_start_error", + "desc": "充电桩状态图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 174, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_charging-station" + } + }, + { + "name": "charger_station_label_start_error", + "desc": "充电桩状态文本", + "type": "label", + "properties": { + "text": "Charger id:", + "x_ofs": 65, + "y_ofs": 175, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "contact_img_start_error", + "desc": "联系图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 198, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_contact" + } + }, + { + "name": "contact_label_start_error", + "desc": "联系文本", + "type": "label", + "properties": { + "text": "0878-1058-4499", + "x_ofs": 65, + "y_ofs": 199, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "telephone_img_start_error", + "desc": "移动电话图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 222, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_telephone" + } + }, + { + "name": "telephone_label_start_error", + "desc": "移动电话文本", + "type": "label", + "properties": { + "text": "(021)5088-6428", + "x_ofs": 65, + "y_ofs": 223, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "url_img_start_error", + "desc": "网址图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 246, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_url" + } + }, + { + "name": "url_label_start_error", + "desc": "网址文本", + "type": "label", + "properties": { + "text": "Ioc.id", + "x_ofs": 65, + "y_ofs": 247, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00037_start_error_circle.json b/assets/fragment/fragment_00037_start_error_circle.json new file mode 100644 index 000000000..aa9002275 --- /dev/null +++ b/assets/fragment/fragment_00037_start_error_circle.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_charging_error_draw_icon", + "desc": "感叹号", + "type": "flex", + "properties": { + "style": "style-session_error-circle" + }, + "children": [ + { + "name": "error_symbol", + "type": "label", + "properties": { + "text": "!", + "align" : "LV_ALIGN_CENTER", + "style": "style-draw_icon_symbol", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00038_start_error_continue.json b/assets/fragment/fragment_00038_start_error_continue.json new file mode 100644 index 000000000..408bcaf64 --- /dev/null +++ b/assets/fragment/fragment_00038_start_error_continue.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_continue_btn", + "desc": "continue按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "continue_label", + "type": "label", + "properties": { + "text": "Continue", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00040_fault_info_card.json b/assets/fragment/fragment_00040_fault_info_card.json new file mode 100644 index 000000000..0437f4de4 --- /dev/null +++ b/assets/fragment/fragment_00040_fault_info_card.json @@ -0,0 +1,141 @@ +{ + "name": "fragment_fault_info_card", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "qr_code_fault", + "type": "qr", + "properties": { + "x_ofs": 85, + "y_ofs": 20, + "size": 94, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "qr_code_prompt_fault", + "desc": "二维码提示文本", + "type": "label", + "properties": { + "text": "Download Ioc APP for a faster experience.", + "width": 227, + "x_ofs": 18, + "y_ofs": 127, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "charger_station_img_fault", + "desc": "充电桩状态图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 174, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_charging-station" + } + }, + { + "name": "charger_station_label_fault", + "desc": "充电桩状态文本", + "type": "label", + "properties": { + "text": "Charger id:", + "x_ofs": 65, + "y_ofs": 175, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "contact_img_fault", + "desc": "联系图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 198, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_contact" + } + }, + { + "name": "contact_label_fault", + "desc": "联系文本", + "type": "label", + "properties": { + "text": "0878-1058-4499", + "x_ofs": 65, + "y_ofs": 199, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "telephone_img_fault", + "desc": "移动电话图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 222, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_telephone" + } + }, + { + "name": "telephone_label_fault", + "desc": "移动电话文本", + "type": "label", + "properties": { + "text": "(021)5088-6428", + "x_ofs": 65, + "y_ofs": 223, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "url_img_fault", + "desc": "网址图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 246, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_url" + } + }, + { + "name": "url_label_fault", + "desc": "网址文本", + "type": "label", + "properties": { + "text": "Ioc.id", + "x_ofs": 65, + "y_ofs": 247, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00043_unavailable_info_card.json b/assets/fragment/fragment_00043_unavailable_info_card.json new file mode 100644 index 000000000..aa98f2b1c --- /dev/null +++ b/assets/fragment/fragment_00043_unavailable_info_card.json @@ -0,0 +1,141 @@ +{ + "name": "fragment_unavailable_info_card", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "qr_code_unavailable", + "type": "qr", + "properties": { + "x_ofs": 85, + "y_ofs": 20, + "size": 94, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "qr_code_prompt_unavailable", + "desc": "二维码提示文本", + "type": "label", + "properties": { + "text": "Download Ioc APP for a faster experience.", + "width": 227, + "x_ofs": 18, + "y_ofs": 127, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "charger_station_img_unavailable", + "desc": "充电桩状态图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 174, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_charging-station" + } + }, + { + "name": "charger_station_label_unavailable", + "desc": "充电桩状态文本", + "type": "label", + "properties": { + "text": "Charger id:", + "x_ofs": 65, + "y_ofs": 175, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "contact_img_unavailable", + "desc": "联系图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 198, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_contact" + } + }, + { + "name": "contact_label_unavailable", + "desc": "联系文本", + "type": "label", + "properties": { + "text": "0878-1058-4499", + "x_ofs": 65, + "y_ofs": 199, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "telephone_img_unavailable", + "desc": "移动电话图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 222, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_telephone" + } + }, + { + "name": "telephone_label_unavailable", + "desc": "移动电话文本", + "type": "label", + "properties": { + "text": "(021)5088-6428", + "x_ofs": 65, + "y_ofs": 223, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "url_img_unavailable", + "desc": "网址图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 246, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_url" + } + }, + { + "name": "url_label_unavailable", + "desc": "网址文本", + "type": "label", + "properties": { + "text": "Ioc.id", + "x_ofs": 65, + "y_ofs": 247, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00053_help1_status.json b/assets/fragment/fragment_00053_help1_status.json new file mode 100644 index 000000000..1de36500a --- /dev/null +++ b/assets/fragment/fragment_00053_help1_status.json @@ -0,0 +1,104 @@ +{ + "name": "fragment_popup_help1_status", + "desc": "中间部分", + "type": "flex", + "properties": { + "width": 190, + "height": 290, + "style":"style-help1_status_bar" + }, + "children": [ + { + "name": "info_RF_img", + "desc": "RF状态图片", + "type": "image", + "properties": { + "x_ofs": 49, + "y_ofs": 41, + "width": 35, + "height": 35, + "align": "LV_ALIGN_TOP_LEFT", + "src": "rf_err" + } + }, + { + "name": "info_4G_img", + "desc": "4G状态图片", + "type": "image", + "properties": { + "x_ofs": 109, + "y_ofs": 41, + "width": 35, + "height": 35, + "align": "LV_ALIGN_TOP_LEFT", + "src": "4g_off" + } + }, + { + "name": "info_sever_img", + "desc": "sever状态图片", + "type": "image", + "properties": { + "x_ofs": 49, + "y_ofs": 96, + "width": 35, + "height": 35, + "align": "LV_ALIGN_TOP_LEFT", + "src": "sever_err" + } + }, + { + "name": "info_net_img", + "desc": "net状态图片", + "type": "image", + "properties": { + "x_ofs": 109, + "y_ofs": 96, + "width": 35, + "height": 35, + "align": "LV_ALIGN_TOP_LEFT", + "src": "net_off" + } + }, + { + "name": "info_wifi_img", + "desc": "wifi状态图片", + "type": "image", + "properties": { + "x_ofs": 49, + "y_ofs": 151, + "width": 35, + "height": 35, + "align": "LV_ALIGN_TOP_LEFT", + "src": "wifi_off" + } + }, + { + "name": "info_meter_img", + "desc": "meter状态图片", + "type": "image", + "properties": { + "x_ofs": 109, + "y_ofs": 151, + "width": 35, + "height": 35, + "align": "LV_ALIGN_TOP_LEFT", + "src": "meter_err" + } + }, + { + "name": "IP_lable", + "desc": "ip文本", + "type": "label", + "properties": { + "text": "IP:", + "width": 190, + "x_ofs": 0, + "y_ofs": 212, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-finished~", + "text_align": "LV_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00055_help2_close_button.json b/assets/fragment/fragment_00055_help2_close_button.json new file mode 100644 index 000000000..e8c96134e --- /dev/null +++ b/assets/fragment/fragment_00055_help2_close_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_help2_close", + "desc": "close按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "close_label_help2", + "type": "label", + "properties": { + "text": "Close", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00056_help2_back_button.json b/assets/fragment/fragment_00056_help2_back_button.json new file mode 100644 index 000000000..495a93d5c --- /dev/null +++ b/assets/fragment/fragment_00056_help2_back_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_help2_back", + "desc": "back按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "back_label_help2", + "type": "label", + "properties": { + "text": "Back", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00057_connection_failed_circle.json b/assets/fragment/fragment_00057_connection_failed_circle.json new file mode 100644 index 000000000..2c6616ac5 --- /dev/null +++ b/assets/fragment/fragment_00057_connection_failed_circle.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_connection_failed_circle", + "desc": "感叹号", + "type": "flex", + "properties": { + "style": "style-connection_failed-circle" + }, + "children": [ + { + "name": "!_session_error", + "type": "label", + "properties": { + "text": "!", + "align" : "LV_ALIGN_CENTER", + "style": "style-draw_icon_symbol", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00058_connection_failed_status_bar.json b/assets/fragment/fragment_00058_connection_failed_status_bar.json new file mode 100644 index 000000000..70f3dc672 --- /dev/null +++ b/assets/fragment/fragment_00058_connection_failed_status_bar.json @@ -0,0 +1,142 @@ +{ + "name": "fragment_popup_common_failed", + "desc": "中间部分", + "type": "flex", + "properties": { + "width": 580, + "height": 120, + "style":"style-help1_status_bar" + }, + "children": [ + { + "name": "qr_code_connection_failed", + "type": "qr", + "properties": { + "x_ofs": 20, + "y_ofs": 13, + "size": 94, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "charger_station_img_connection_failed", + "desc": "充电桩状态图片", + "type": "image", + "properties": { + "x_ofs": 144, + "y_ofs": 13, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_charging-station" + } + }, + { + "name": "charger_station_label_connection_failed", + "desc": "充电桩状态文本", + "type": "label", + "properties": { + "text": "Charger id:", + "x_ofs": 179, + "y_ofs": 14, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "contact_img_connection_failed", + "desc": "联系图片", + "type": "image", + "properties": { + "x_ofs": 377, + "y_ofs": 13, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_contact" + } + }, + { + "name": "contact_label_connection_failed", + "desc": "联系文本", + "type": "label", + "properties": { + "text": "0878-1058-4499", + "x_ofs": 412, + "y_ofs": 14, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "telephone_img_connection_failed", + "desc": "移动电话图片", + "type": "image", + "properties": { + "x_ofs": 144, + "y_ofs": 41, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_telephone" + } + }, + { + "name": "telephone_label_connection_failed", + "desc": "移动电话文本", + "type": "label", + "properties": { + "text": "(021)5088-6428", + "x_ofs": 180, + "y_ofs": 42, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "url_img_connection_failed", + "desc": "网址图片", + "type": "image", + "properties": { + "x_ofs": 377, + "y_ofs": 41, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_url" + } + }, + { + "name": "url_label_connection_failed", + "desc": "网址文本", + "type": "label", + "properties": { + "text": "Ioc.id", + "x_ofs": 415, + "y_ofs": 42, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "prompt_connection_failed", + "desc": "提示文本", + "type": "label", + "properties": { + "text": "Download IoC APP for a faster experience.", + "x_ofs": 145, + "y_ofs": 69, + "width": 376, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00059_connection_failed_close_button.json b/assets/fragment/fragment_00059_connection_failed_close_button.json new file mode 100644 index 000000000..19fb5e2be --- /dev/null +++ b/assets/fragment/fragment_00059_connection_failed_close_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_connection_failed_close", + "desc": "close按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "close_label_connection_failed", + "type": "label", + "properties": { + "text": "Close", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00060_bill_status_bar.json b/assets/fragment/fragment_00060_bill_status_bar.json new file mode 100644 index 000000000..1bbdc4728 --- /dev/null +++ b/assets/fragment/fragment_00060_bill_status_bar.json @@ -0,0 +1,27 @@ +{ + "name": "fragment_popup_bill", + "desc": "中间部分", + "type": "flex", + "properties": { + "width": 320, + "height": 340, + "style":"style-help1_status_bar" + }, + "children": [ + { + "name": "content", + "desc": "充电桩状态文本", + "type": "label", + "properties": { + "text": "Faelliger Betrag:EUR1,01 Reservierungsgebuehr:0,00\nPreis pro kW: 0.01\nServicegebuehr:1,00\nNutzungsgebuehr:0,00\nEnergie: 0.017kWh\nDauer:00:01:04\nMwSt.19%:0,16\nNetto: 0,85\nBesuch: http://gitlab.iocharger.com\n22602/tourist/invoices/53sh", + "x_ofs": 20, + "y_ofs": 20, + "width": 280, + "height": 300, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_LEFT" + } + } + ] +} diff --git a/assets/fragment/fragment_00061_bill_close_button.json b/assets/fragment/fragment_00061_bill_close_button.json new file mode 100644 index 000000000..6286001b3 --- /dev/null +++ b/assets/fragment/fragment_00061_bill_close_button.json @@ -0,0 +1,31 @@ +{ + "name": "fragment_bill_close", + "desc": "close按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "Close", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "seconds", + "type": "label", + "properties": { + "text": "", + "x_ofs": 40, + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00062_pre_authorization_shortcut1_button.json b/assets/fragment/fragment_00062_pre_authorization_shortcut1_button.json new file mode 100644 index 000000000..f89929cc8 --- /dev/null +++ b/assets/fragment/fragment_00062_pre_authorization_shortcut1_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_shortcut1", + "desc": "预授权快捷按钮1", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "10.00", + "align" : "LV_ALIGN_CENTER", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00063_pre_authorization_shortcut2_button.json b/assets/fragment/fragment_00063_pre_authorization_shortcut2_button.json new file mode 100644 index 000000000..caeef7ef6 --- /dev/null +++ b/assets/fragment/fragment_00063_pre_authorization_shortcut2_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_shortcut2", + "desc": "预授权快捷按钮2", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "50.00", + "align" : "LV_ALIGN_CENTER", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00064_pre_authorization_shortcut3_button.json b/assets/fragment/fragment_00064_pre_authorization_shortcut3_button.json new file mode 100644 index 000000000..d8c3d2366 --- /dev/null +++ b/assets/fragment/fragment_00064_pre_authorization_shortcut3_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_shortcut3", + "desc": "预授权快捷按钮3", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "100.00", + "align" : "LV_ALIGN_CENTER", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00065_pre_authorization_close_button.json b/assets/fragment/fragment_00065_pre_authorization_close_button.json new file mode 100644 index 000000000..4fc446a55 --- /dev/null +++ b/assets/fragment/fragment_00065_pre_authorization_close_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_close", + "desc": "close按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "Close", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00066_pre_authorization_num_button.json b/assets/fragment/fragment_00066_pre_authorization_num_button.json new file mode 100644 index 000000000..23b47f419 --- /dev/null +++ b/assets/fragment/fragment_00066_pre_authorization_num_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_keypad", + "desc": "预授权软键盘的按钮", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "", + "align" : "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00067_pre_authorization_num2_button.json b/assets/fragment/fragment_00067_pre_authorization_num2_button.json new file mode 100644 index 000000000..d08e009a9 --- /dev/null +++ b/assets/fragment/fragment_00067_pre_authorization_num2_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_num2", + "desc": "num2按钮", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "2", + "align" : "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00067_pre_authorization_num_button_delete.json b/assets/fragment/fragment_00067_pre_authorization_num_button_delete.json new file mode 100644 index 000000000..7f2e40f65 --- /dev/null +++ b/assets/fragment/fragment_00067_pre_authorization_num_button_delete.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_keypad_delete", + "desc": "预授权软键盘的回撤按钮,因为回撤按钮的←字库不支持,所以单独成一个fragment", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "←", + "align" : "LV_ALIGN_CENTER", + "style": "style-pre_authorization_delete_btn", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00068_pre_authorization_num3_button.json b/assets/fragment/fragment_00068_pre_authorization_num3_button.json new file mode 100644 index 000000000..a6262d79f --- /dev/null +++ b/assets/fragment/fragment_00068_pre_authorization_num3_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_num3", + "desc": "num3按钮", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "3", + "align" : "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00069_pre_authorization_num4_button.json b/assets/fragment/fragment_00069_pre_authorization_num4_button.json new file mode 100644 index 000000000..1d5efac9d --- /dev/null +++ b/assets/fragment/fragment_00069_pre_authorization_num4_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_num4", + "desc": "num4按钮", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "4", + "align" : "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00070_pre_authorization_num5_button.json b/assets/fragment/fragment_00070_pre_authorization_num5_button.json new file mode 100644 index 000000000..7444010d6 --- /dev/null +++ b/assets/fragment/fragment_00070_pre_authorization_num5_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_num5", + "desc": "num5按钮", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "5", + "align" : "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00071_pre_authorization_num6_button.json b/assets/fragment/fragment_00071_pre_authorization_num6_button.json new file mode 100644 index 000000000..7c79a0e43 --- /dev/null +++ b/assets/fragment/fragment_00071_pre_authorization_num6_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_num6", + "desc": "num6按钮", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "6", + "align" : "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00072_pre_authorization_num7_button.json b/assets/fragment/fragment_00072_pre_authorization_num7_button.json new file mode 100644 index 000000000..44e4cca06 --- /dev/null +++ b/assets/fragment/fragment_00072_pre_authorization_num7_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_num7", + "desc": "num7按钮", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "7", + "align" : "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00073_pre_authorization_num8_button.json b/assets/fragment/fragment_00073_pre_authorization_num8_button.json new file mode 100644 index 000000000..8479cbbfc --- /dev/null +++ b/assets/fragment/fragment_00073_pre_authorization_num8_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_num8", + "desc": "num8按钮", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "8", + "align" : "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00074_pre_authorization_num9_button.json b/assets/fragment/fragment_00074_pre_authorization_num9_button.json new file mode 100644 index 000000000..0f6eb2bcd --- /dev/null +++ b/assets/fragment/fragment_00074_pre_authorization_num9_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_num9", + "desc": "num9按钮", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "9", + "align" : "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00075_pre_authorization_character_drop_button.json b/assets/fragment/fragment_00075_pre_authorization_character_drop_button.json new file mode 100644 index 000000000..0f0e65700 --- /dev/null +++ b/assets/fragment/fragment_00075_pre_authorization_character_drop_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_character.", + "desc": "小数点按钮", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": ".", + "align" : "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00076_pre_authorization_num0_button.json b/assets/fragment/fragment_00076_pre_authorization_num0_button.json new file mode 100644 index 000000000..a3ba38618 --- /dev/null +++ b/assets/fragment/fragment_00076_pre_authorization_num0_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_num0", + "desc": "num0按钮", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "0", + "align" : "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00077_pre_authorization_character_delete_button.json b/assets/fragment/fragment_00077_pre_authorization_character_delete_button.json new file mode 100644 index 000000000..2f2e70518 --- /dev/null +++ b/assets/fragment/fragment_00077_pre_authorization_character_delete_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_character<", + "desc": "删除按钮", + "type": "button", + "properties": { + "style": "style-num_button_pre_authorization" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "←", + "align" : "LV_ALIGN_CENTER", + "style": "style-pre_authorization_delete_btn", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00078_pre_authorization_confirm_button.json b/assets/fragment/fragment_00078_pre_authorization_confirm_button.json new file mode 100644 index 000000000..05c979969 --- /dev/null +++ b/assets/fragment/fragment_00078_pre_authorization_confirm_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_pre_authorization_confirm", + "desc": "confirm按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "Confirm", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00079_language_albania_button.json b/assets/fragment/fragment_00079_language_albania_button.json new file mode 100644 index 000000000..93ba1b03f --- /dev/null +++ b/assets/fragment/fragment_00079_language_albania_button.json @@ -0,0 +1,33 @@ +{ + "name": "fragment_language_albania_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 43, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "lang_albania" + } + }, + { + "name": "albania_label_language", + "type": "label", + "properties": { + "text": "Albania", + "x_ofs": 79, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text" + } + } + ] +} diff --git a/assets/fragment/fragment_00080_language_arab_button.json b/assets/fragment/fragment_00080_language_arab_button.json new file mode 100644 index 000000000..2c40353f6 --- /dev/null +++ b/assets/fragment/fragment_00080_language_arab_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_arab_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 53, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "lang_arab" + } + }, + { + "name": "arab_label_language", + "type": "label", + "properties": { + "text": "Arab", + "x_ofs": 89, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00081_language_china_button.json b/assets/fragment/fragment_00081_language_china_button.json new file mode 100644 index 000000000..4404006f2 --- /dev/null +++ b/assets/fragment/fragment_00081_language_china_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_china_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 49, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "lang_china" + } + }, + { + "name": "china_label_language", + "type": "label", + "properties": { + "text": "China", + "x_ofs": 85, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00082_language_czech_republic_button.json b/assets/fragment/fragment_00082_language_czech_republic_button.json new file mode 100644 index 000000000..ada3df62a --- /dev/null +++ b/assets/fragment/fragment_00082_language_czech_republic_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_czech_republic_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 15, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "czech-republic" + } + }, + { + "name": "czech_republic_label_language", + "type": "label", + "properties": { + "text": "Czech Republic", + "x_ofs": 51, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00083_language_english_button.json b/assets/fragment/fragment_00083_language_english_button.json new file mode 100644 index 000000000..ad0a49b90 --- /dev/null +++ b/assets/fragment/fragment_00083_language_english_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_english_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 44, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "english" + } + }, + { + "name": "english_label_language", + "type": "label", + "properties": { + "text": "English", + "x_ofs": 80, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00084_language_finland_button.json b/assets/fragment/fragment_00084_language_finland_button.json new file mode 100644 index 000000000..dc3b68365 --- /dev/null +++ b/assets/fragment/fragment_00084_language_finland_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_finland_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 43, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "finland" + } + }, + { + "name": "finland_label_language", + "type": "label", + "properties": { + "text": "Finland", + "x_ofs": 79, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00085_language_france_button.json b/assets/fragment/fragment_00085_language_france_button.json new file mode 100644 index 000000000..79bfc7f34 --- /dev/null +++ b/assets/fragment/fragment_00085_language_france_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_france_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 46, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "france" + } + }, + { + "name": "france_label_language", + "type": "label", + "properties": { + "text": "France", + "x_ofs": 82, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00086_language_germany_button.json b/assets/fragment/fragment_00086_language_germany_button.json new file mode 100644 index 000000000..323ac77a3 --- /dev/null +++ b/assets/fragment/fragment_00086_language_germany_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_germany_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 36, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "germany" + } + }, + { + "name": "germany_label_language", + "type": "label", + "properties": { + "text": "Germany", + "x_ofs": 72, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00087_language_hong_kong_button.json b/assets/fragment/fragment_00087_language_hong_kong_button.json new file mode 100644 index 000000000..468c06f48 --- /dev/null +++ b/assets/fragment/fragment_00087_language_hong_kong_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_hong_kong_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 5, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "hong-kong" + } + }, + { + "name": "hong_kong_label_language", + "type": "label", + "properties": { + "text": "Hong Kong,China", + "x_ofs": 41, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00088_language_italy_button.json b/assets/fragment/fragment_00088_language_italy_button.json new file mode 100644 index 000000000..17c900b17 --- /dev/null +++ b/assets/fragment/fragment_00088_language_italy_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_italy_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 54, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "italy" + } + }, + { + "name": "italy_label_language", + "type": "label", + "properties": { + "text": "Italy", + "x_ofs": 90, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00089_language_netherlands_button.json b/assets/fragment/fragment_00089_language_netherlands_button.json new file mode 100644 index 000000000..e24184536 --- /dev/null +++ b/assets/fragment/fragment_00089_language_netherlands_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_netherlands_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 24, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "netherlands" + } + }, + { + "name": "netherlands_label_language", + "type": "label", + "properties": { + "text": "Netherlands", + "x_ofs": 60, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00090_language_portugal_button.json b/assets/fragment/fragment_00090_language_portugal_button.json new file mode 100644 index 000000000..7e7e3a1d7 --- /dev/null +++ b/assets/fragment/fragment_00090_language_portugal_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_portugal_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 39, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "portugal" + } + }, + { + "name": "portugal_label_language", + "type": "label", + "properties": { + "text": "Portugal", + "x_ofs": 75, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00091_language_poland_button.json b/assets/fragment/fragment_00091_language_poland_button.json new file mode 100644 index 000000000..daee18b24 --- /dev/null +++ b/assets/fragment/fragment_00091_language_poland_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_poland_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 45, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "poland" + } + }, + { + "name": "poland_label_language", + "type": "label", + "properties": { + "text": "Poland", + "x_ofs": 81, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00092_language_russia_button.json b/assets/fragment/fragment_00092_language_russia_button.json new file mode 100644 index 000000000..16b35be73 --- /dev/null +++ b/assets/fragment/fragment_00092_language_russia_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_russia_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 47, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "russia" + } + }, + { + "name": "russia_label_language", + "type": "label", + "properties": { + "text": "Russia", + "x_ofs": 83, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00093_language_romania_button.json b/assets/fragment/fragment_00093_language_romania_button.json new file mode 100644 index 000000000..bfce2f585 --- /dev/null +++ b/assets/fragment/fragment_00093_language_romania_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_romania_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 37, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "romania" + } + }, + { + "name": "romania_label_language", + "type": "label", + "properties": { + "text": "Romania", + "x_ofs": 73, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00094_language_spain_button.json b/assets/fragment/fragment_00094_language_spain_button.json new file mode 100644 index 000000000..81731f730 --- /dev/null +++ b/assets/fragment/fragment_00094_language_spain_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_spain_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 50, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "spain" + } + }, + { + "name": "spain_label_language", + "type": "label", + "properties": { + "text": "Spain", + "x_ofs": 86, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00095_language_turkey_button.json b/assets/fragment/fragment_00095_language_turkey_button.json new file mode 100644 index 000000000..cf8c4051a --- /dev/null +++ b/assets/fragment/fragment_00095_language_turkey_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_turkey_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 45, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "turkey" + } + }, + { + "name": "turkey_label_language", + "type": "label", + "properties": { + "text": "Turkey", + "x_ofs": 81, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00096_language_thailand_button.json b/assets/fragment/fragment_00096_language_thailand_button.json new file mode 100644 index 000000000..d1748c348 --- /dev/null +++ b/assets/fragment/fragment_00096_language_thailand_button.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_language_thailand_button", + "desc": "语言选择按钮", + "type": "button", + "properties": { + "style": "style-shortcut_button_pre_authorization" + }, + "children": [ + { + "name": "plug_idle", + "type": "image", + "properties": { + "x_ofs": 38, + "y_ofs": 4, + "width": 32, + "height": 32, + "align": "LV_ALIGN_TOP_LEFT", + "src": "thailand" + } + }, + { + "name": "thailand_label_language", + "type": "label", + "properties": { + "text": "Thailand", + "x_ofs": 74, + "y_ofs": 11, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00097_language_close_button.json b/assets/fragment/fragment_00097_language_close_button.json new file mode 100644 index 000000000..8727adf0b --- /dev/null +++ b/assets/fragment/fragment_00097_language_close_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_language_close", + "desc": "close按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "Close", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00098_language_confirm_button.json b/assets/fragment/fragment_00098_language_confirm_button.json new file mode 100644 index 000000000..b5c04970c --- /dev/null +++ b/assets/fragment/fragment_00098_language_confirm_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_language_confirm", + "desc": "confirm按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "Confirm", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00100_charging_car_icon.json b/assets/fragment/fragment_00100_charging_car_icon.json new file mode 100644 index 000000000..4c9a2237a --- /dev/null +++ b/assets/fragment/fragment_00100_charging_car_icon.json @@ -0,0 +1,38 @@ +{ + "name": "fragment_charging_car_icon", + "desc": "充电中的汽车图标,由汽车背景图和中间电池动图组成", + "type": "flex", + "properties": { + "width": 437, + "height": 260, + "style":"style-primary_bg" + }, + "children": [ + { + "name": "charging_car_bg", + "desc": "车背景图", + "type": "image", + "properties": { + "x_ofs": 0, + "y_ofs": 0, + "width": 437, + "height": 260, + "align": "LV_ALIGN_TOP_LEFT", + "src": "bg_data-display_charging" + } + }, + { + "name": "charging_car_gif", + "desc": "充电动态图", + "type": "gif", + "properties": { + "x_ofs": 183, + "y_ofs": 123, + "width": 68, + "height": 71, + "align": "LV_ALIGN_TOP_LEFT", + "src": "charging" + } + } + ] +} diff --git a/assets/fragment/fragment_00101_label_combine_three.json b/assets/fragment/fragment_00101_label_combine_three.json new file mode 100644 index 000000000..1a5646796 --- /dev/null +++ b/assets/fragment/fragment_00101_label_combine_three.json @@ -0,0 +1,51 @@ +{ + "name": "fragment_label_combine_three", + "desc": "由三个label组合的组件,包含一个标题,一个数值和一个单位", + "type": "flex", + "properties": { + "width": 147, + "height": 109, + "style": "style-label_combine_bg" + }, + "children": [ + { + "name": "title", + "type": "label", + "properties": { + "text": "", + "width": 147, + "height": 18, + "x_ofs": 0, + "y_ofs": 18, + "align" : "LV_ALIGN_TOP_MID", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "val", + "type": "label", + "properties": { + "width": 84, + "height": 29, + "x_ofs": 0, + "y_ofs": 58, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_label", + "text_align": "LV_TEXT_ALIGN_RIGHT" + } + }, + { + "name": "unit", + "type": "label", + "properties": { + "text": "", + "x_ofs": 86, + "y_ofs": 69, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-charging_info_unit", + "text_align": "LV_TEXT_ALIGN_LEFT" + } + } + ] +} diff --git a/assets/fragment/fragment_00102_label_comnime_two.json b/assets/fragment/fragment_00102_label_comnime_two.json new file mode 100644 index 000000000..43f192e46 --- /dev/null +++ b/assets/fragment/fragment_00102_label_comnime_two.json @@ -0,0 +1,39 @@ +{ + "name": "fragment_label_combine_two", + "desc": "由两个label组合的组件,包含一个标题,一个数值", + "type": "flex", + "properties": { + "width": 147, + "height": 109, + "style": "style-label_combine_bg" + }, + "children": [ + { + "name": "title", + "type": "label", + "properties": { + "text": "", + "width": 147, + "height": 18, + "x_ofs": 0, + "y_ofs": 18, + "align" : "LV_ALIGN_TOP_MID", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "val", + "type": "label", + "properties": { + "width": 147, + "height": 29, + "x_ofs": 0, + "y_ofs": 58, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_label", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00103_label_comnime_six.json b/assets/fragment/fragment_00103_label_comnime_six.json new file mode 100644 index 000000000..6aa748115 --- /dev/null +++ b/assets/fragment/fragment_00103_label_comnime_six.json @@ -0,0 +1,95 @@ +{ + "name": "fragment_label_combine_six", + "desc": "由六个label组合的组件,结束界面soc", + "type": "flex", + "properties": { + "width": 147, + "height": 109, + "style": "style-label_combine_bg" + }, + "children": [ + { + "name": "title", + "type": "label", + "properties": { + "text": "", + "width": 147, + "height": 18, + "x_ofs": 0, + "y_ofs": 18, + "align" : "LV_ALIGN_TOP_MID", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "val_1", + "type": "label", + "properties": { + "text": "", + "width": 35, + "height": 29, + "x_ofs": 20, + "y_ofs": 58, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_label", + "text_align": "LV_TEXT_ALIGN_RIGHT" + } + }, + { + "name": "unit_1", + "type": "label", + "properties": { + "text": "%", + "width": 10, + "height": 16, + "x_ofs": 58, + "y_ofs": 69, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-charging_info_unit", + "text_align": "LV_TEXT_ALIGN_LEFT" + } + }, + { + "name": "separator", + "type": "label", + "properties": { + "text": "~", + "width": 8, + "height": 20, + "x_ofs": 75, + "y_ofs": 65, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-charging_settle_unit", + "text_align": "LV_TEXT_ALIGN_LEFT" + } + }, + { + "name": "val_2", + "type": "label", + "properties": { + "text": "", + "width": 35, + "height": 29, + "x_ofs": 85, + "y_ofs": 58, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_label", + "text_align": "LV_TEXT_ALIGN_RIGHT" + } + }, + { + "name": "unit_2", + "type": "label", + "properties": { + "text": "%", + "x_ofs": 123, + "y_ofs": 69, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-charging_info_unit", + "text_align": "LV_TEXT_ALIGN_LEFT" + } + } + + ] +} diff --git a/assets/fragment/fragment_00104_connector_trip_card.json b/assets/fragment/fragment_00104_connector_trip_card.json new file mode 100644 index 000000000..f4ffdfd4d --- /dev/null +++ b/assets/fragment/fragment_00104_connector_trip_card.json @@ -0,0 +1,143 @@ +{ + "name": "fragment_conn_card_trip_card", + "desc": "四枪的单个卡片", + "type": "button", + "properties": { + "style": "style-connector-trip-default", + "style_checked": "style-connector-trip-checked" + }, + "children": [ + { + "name": "No", + "type": "fragment", + "fragment_name" : "fragment_connector_no_trip", + "properties": { + "x": 14, + "y": 14 + } + }, + { + "name": "state", + "type": "label", + "properties": { + "text": "Idle", + "x_ofs": -14, + "y_ofs": 19, + "align": "LV_ALIGN_TOP_RIGHT", + "style": "style-connector-quad-default-state-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "type", + "type": "label", + "properties": { + "text": "CCS2(DC)", + "x": 14, + "y": 65, + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "power_rated", + "type": "label", + "properties": { + "text": "120.0kW", + "x": 14, + "y": 89, + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "type_icon", + "type": "image", + "properties": { + "src": "ccs2-dc", + "width": 47, + "height": 47, + "x_ofs": -14, + "y_ofs": -14, + "align": "LV_ALIGN_BOTTOM_RIGHT" + } + }, + { + "name": "time_label", + "type": "label", + "properties": { + "text": "Idle time", + "x": 14, + "y": 65, + "hidden": true, + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "time", + "type": "label", + "properties": { + "text": "04:24", + "x": 14, + "y": 89, + "hidden": true, + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "soc_bar", + "desc": "充电中SoC进度条", + "type": "bar", + "properties": { + "x_ofs": 14, + "y_ofs": 65, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-charging_bar_bg_size", + "style_indic": "style-charging_bar_indic" + } + }, + { + "name": "soc_label", + "desc": "充电中SoC值", + "type": "label", + "properties": { + "text": "12%", + "x_ofs": 14, + "y_ofs": 89, + "width": 50, + "height": 20, + "align": "LV_ALIGN_TOP_LEFT", + "hidden": true, + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "power_real", + "desc": "充电中实时功率, 右对齐", + "type": "label", + "properties": { + "text": "102.5kW", + "x_ofs": -14, + "y_ofs": 89, + "align": "LV_ALIGN_TOP_RIGHT", + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "plug_gun_icon", + "desc" : "插枪提示的绿色图标", + "type": "image", + "properties": { + "src": "icon_connected", + "width": 20, + "height": 20, + "x": 212, + "y": 91 + } + } + ] +} diff --git a/assets/fragment/fragment_00105_connector_no_trip.json b/assets/fragment/fragment_00105_connector_no_trip.json new file mode 100644 index 000000000..6f1f7eb94 --- /dev/null +++ b/assets/fragment/fragment_00105_connector_no_trip.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_connector_no_trip", + "desc": "帮助按钮类似的130*40按钮, 内置一个文本", + "type": "flex", + "properties": { + "style": "style-connector-quad-default-num-border" + }, + "children": [ + { + "name": "NoText", + "type": "label", + "properties": { + "text": "1", + "align" : "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-num-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00106_suspend_draw_icon.json b/assets/fragment/fragment_00106_suspend_draw_icon.json new file mode 100644 index 000000000..282a9fb32 --- /dev/null +++ b/assets/fragment/fragment_00106_suspend_draw_icon.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_suspend_draw_icon", + "desc": "感叹号", + "type": "flex", + "properties": { + "style": "style-suspend-circle" + }, + "children": [ + { + "name": "symbol", + "type": "label", + "properties": { + "text": "!", + "align" : "LV_ALIGN_CENTER", + "style": "style-draw_icon_symbol", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00107_connector_dual_left_card.json b/assets/fragment/fragment_00107_connector_dual_left_card.json new file mode 100644 index 000000000..c01d97c2b --- /dev/null +++ b/assets/fragment/fragment_00107_connector_dual_left_card.json @@ -0,0 +1,143 @@ +{ + "name": "fragment_conn_card_dual_left_card", + "desc": "双枪的单个卡片", + "type": "button", + "properties": { + "style": "style-connector-dual-default", + "style_checked": "style-connector-dual-checked" + }, + "children": [ + { + "name": "conn_card_id", + "type": "fragment", + "fragment_name" : "fragment_conn_id_dual_left", + "properties": { + "x": 0, + "y": 0 + } + }, + { + "name": "conn_card_state", + "type": "label", + "properties": { + "text": "Idle", + "x_ofs": 143, + "y_ofs": 20, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-state-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_type", + "type": "label", + "properties": { + "text": "CCS2(DC)", + "x_ofs": 143, + "y_ofs": 59, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_power_rated", + "type": "label", + "properties": { + "text": "120.0kW", + "x_ofs": 143, + "y_ofs": 83, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_type_icon", + "type": "image", + "properties": { + "src": "ccs2-dc_2connect", + "x_ofs": -20, + "y_ofs": 26, + "align": "LV_ALIGN_TOP_RIGHT" + } + }, + { + "name": "conn_card_time_title", + "type": "label", + "properties": { + "text": "Idle time", + "x": 142, + "y": 58, + "hidden": true, + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_time", + "type": "label", + "properties": { + "text": "04:24", + "x": 142, + "y": 85, + "hidden": true, + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_soc_bar", + "desc": "充电中SoC进度条", + "type": "bar", + "properties": { + "x_ofs": 143, + "y_ofs": 60, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-charging_bar_bg_size2", + "style_indic": "style-charging_bar_indic" + } + }, + { + "name": "conn_card_soc", + "desc": "充电中SoC值", + "type": "label", + "properties": { + "text": "12%", + "x_ofs": 135, + "y_ofs": 89, + "width": 50, + "height": 20, + "align": "LV_ALIGN_TOP_LEFT", + "hidden": true, + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_power_real", + "desc": "充电中实时功率, 右对齐", + "type": "label", + "properties": { + "text": "102.5kW", + "x_ofs": -14, + "y_ofs": 89, + "align": "LV_ALIGN_TOP_RIGHT", + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_plug_gun_icon", + "desc" : "插枪提示的绿色图标", + "type": "image", + "properties": { + "src": "icon_connected", + "width": 20, + "height": 20, + "x": 330, + "y": 80 + } + } + ] +} diff --git a/assets/fragment/fragment_00108_connector_no_dual_left.json b/assets/fragment/fragment_00108_connector_no_dual_left.json new file mode 100644 index 000000000..c17f0138c --- /dev/null +++ b/assets/fragment/fragment_00108_connector_no_dual_left.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_conn_id_dual_left", + "desc": "帮助按钮类似的130*40按钮, 内置一个文本", + "type": "flex", + "properties": { + "style": "style-connector-dual-default-num-border" + }, + "children": [ + { + "name": "NoText", + "type": "label", + "properties": { + "text": "1", + "x_ofs": 55, + "y_ofs": 21, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-dual-default-num-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "←_dual_left", + "type": "label", + "properties": { + "text": "←", + "x_ofs": 50, + "y_ofs": 67, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-dual-default-character", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00109_connector_dual_right_card.json b/assets/fragment/fragment_00109_connector_dual_right_card.json new file mode 100644 index 000000000..5d99a04c7 --- /dev/null +++ b/assets/fragment/fragment_00109_connector_dual_right_card.json @@ -0,0 +1,145 @@ +{ + "name": "fragment_conn_card_dual_right_card", + "desc": "双枪的单个卡片", + "type": "button", + "properties": { + "style": "style-connector-dual-default", + "style_checked": "style-connector-dual-checked" + }, + "children": [ + { + "name": "conn_card_id", + "type": "fragment", + "fragment_name" : "fragment_conn_id_dual_right", + "properties": { + "x": 252, + "y": 0 + } + }, + { + "name": "conn_card_state", + "type": "label", + "properties": { + "text": "Idle", + "x_ofs": -144, + "y_ofs": 20, + "align": "LV_ALIGN_TOP_RIGHT", + "style": "style-connector-quad-default-state-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_type", + "type": "label", + "properties": { + "text": "CCS2(DC)", + "x_ofs": -144, + "y_ofs": 61, + "align": "LV_ALIGN_TOP_RIGHT", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_power_rated", + "type": "label", + "properties": { + "text": "120.0kW", + "x_ofs": -144, + "y_ofs": 83, + "align": "LV_ALIGN_TOP_RIGHT", + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_type_icon", + "type": "image", + "properties": { + "src": "ccs2-dc_2connect", + "x_ofs": 20, + "y_ofs": 26, + "align": "LV_ALIGN_TOP_LEFT" + } + }, + { + "name": "conn_card_time_title", + "type": "label", + "properties": { + "text": "Idle time", + "x_ofs": -146, + "y_ofs": 61, + "align": "LV_ALIGN_TOP_RIGHT", + "hidden": true, + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_time", + "type": "label", + "properties": { + "text": "04:24", + "x_ofs": -146, + "y_ofs": 85, + "align": "LV_ALIGN_TOP_RIGHT", + "hidden": true, + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_soc_bar", + "desc": "充电中SoC进度条", + "type": "bar", + "properties": { + "x_ofs": 20, + "y_ofs": 59, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-charging_bar_bg_size2", + "style_indic": "style-charging_bar_indic" + } + }, + { + "name": "conn_card_soc", + "desc": "充电中SoC值", + "type": "label", + "properties": { + "text": "12%", + "x_ofs": 15, + "y_ofs": 89, + "width": 50, + "height": 20, + "align": "LV_ALIGN_TOP_LEFT", + "hidden": true, + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_power_real", + "desc": "充电中实时功率, 右对齐", + "type": "label", + "properties": { + "text": "102.5kW", + "x_ofs": -144, + "y_ofs": 89, + "align": "LV_ALIGN_TOP_RIGHT", + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_card_plug_gun_icon", + "desc" : "插枪提示的绿色图标", + "type": "image", + "properties": { + "src": "icon_connected", + "width": 20, + "height": 20, + "x": 23, + "y": 80 + } + } + ] +} diff --git a/assets/fragment/fragment_00110_connector_no_dual_right.json b/assets/fragment/fragment_00110_connector_no_dual_right.json new file mode 100644 index 000000000..5c6f0b452 --- /dev/null +++ b/assets/fragment/fragment_00110_connector_no_dual_right.json @@ -0,0 +1,34 @@ +{ + "name": "fragment_conn_id_dual_right", + "desc": "帮助按钮类似的130*40按钮, 内置一个文本", + "type": "flex", + "properties": { + "style": "style-connector-dual-default-num-border" + }, + "children": [ + { + "name": "NoText", + "type": "label", + "properties": { + "text": "2", + "x_ofs": 55, + "y_ofs": 21, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-dual-default-num-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "→_dual_right", + "type": "label", + "properties": { + "text": "→", + "x_ofs": 53, + "y_ofs": 67, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-dual-default-character", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00111_detailed_data_card_left.json b/assets/fragment/fragment_00111_detailed_data_card_left.json new file mode 100644 index 000000000..02595df00 --- /dev/null +++ b/assets/fragment/fragment_00111_detailed_data_card_left.json @@ -0,0 +1,220 @@ +{ + "name": "fragment_card_left_detailed_data", + "desc": "中间部分", + "type": "flex", + "properties": { + "width": 280, + "height": 356, + "style":"style-help1_status_bar" + }, + "children": [ + { + "name": "run_state", + "desc": "运行状态文本", + "type": "label", + "properties": { + "text": "Run State", + "x_ofs": 12, + "y_ofs": 10, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "run_state_value", + "desc": "运行状态值", + "type": "label", + "properties": { + "text": "CCS_CHARGING", + "x_ofs": 157, + "y_ofs": 10, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "sub_state", + "desc": "次级状态文本", + "type": "label", + "properties": { + "text": "Sub State", + "x_ofs": 12, + "y_ofs": 54, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "sub_state_value", + "desc": "次级状态值", + "type": "label", + "properties": { + "text": "1", + "x_ofs": 157, + "y_ofs": 54, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "error_code", + "desc": "错误码文本", + "type": "label", + "properties": { + "text": "Error Code", + "x_ofs": 12, + "y_ofs": 98, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "error_code_value", + "desc": "错误码值", + "type": "label", + "properties": { + "text": "1", + "x_ofs": 157, + "y_ofs": 98, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_status", + "desc": "枪状态文本", + "type": "label", + "properties": { + "text": "Conn Status", + "x_ofs": 12, + "y_ofs": 142, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_status_value", + "desc": "枪状态值", + "type": "label", + "properties": { + "text": "Charging", + "x_ofs": 157, + "y_ofs": 142, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "start_soc", + "desc": "起始电量文本", + "type": "label", + "properties": { + "text": "Start SoC", + "x_ofs": 12, + "y_ofs": 186, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "start_soc_value", + "desc": "起始电量值", + "type": "label", + "properties": { + "text": "5", + "x_ofs": 157, + "y_ofs": 186, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "request_voltage", + "desc": "需求电压文本", + "type": "label", + "properties": { + "text": "Request Voltage", + "x_ofs": 12, + "y_ofs": 230, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "request_voltage_value", + "desc": "需求电压值", + "type": "label", + "properties": { + "text": "400.0V", + "x_ofs": 157, + "y_ofs": 230, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "request_current", + "desc": "需求电流文本", + "type": "label", + "properties": { + "text": "Request Current", + "x_ofs": 12, + "y_ofs": 274, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "request_current_value", + "desc": "需求电流值", + "type": "label", + "properties": { + "text": "120.0A", + "x_ofs": 157, + "y_ofs": 274, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "offer_voltage", + "desc": "提供电压文本", + "type": "label", + "properties": { + "text": "Offer Voltage", + "x_ofs": 12, + "y_ofs": 318, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "offer_voltage_value", + "desc": "提供电压值", + "type": "label", + "properties": { + "text": "750.0V", + "x_ofs": 157, + "y_ofs": 318, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00112_detailed_data_card_right.json b/assets/fragment/fragment_00112_detailed_data_card_right.json new file mode 100644 index 000000000..d5c99dbb1 --- /dev/null +++ b/assets/fragment/fragment_00112_detailed_data_card_right.json @@ -0,0 +1,168 @@ +{ + "name": "fragment_card_right_detailed_data", + "desc": "中间部分", + "type": "flex", + "properties": { + "width": 280, + "height": 356, + "style":"style-help1_status_bar" + }, + "children": [ + { + "name": "offer_current", + "desc": "提供电流文本", + "type": "label", + "properties": { + "text": "Offer Current", + "x_ofs": 12, + "y_ofs": 10, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "offer_current_value", + "desc": "提供电流值", + "type": "label", + "properties": { + "text": "300.0A", + "x_ofs": 157, + "y_ofs": 10, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "output_limit", + "desc": "输出限制文本", + "type": "label", + "properties": { + "text": "Output Limit", + "x_ofs": 12, + "y_ofs": 54, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "output_limit_value", + "desc": "输出限制值", + "type": "label", + "properties": { + "text": "300.0A", + "x_ofs": 157, + "y_ofs": 54, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "comp_group", + "desc": "模块组文本", + "type": "label", + "properties": { + "text": "Comp Group", + "x_ofs": 12, + "y_ofs": 98, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "comp_group_value", + "desc": "模块组值", + "type": "label", + "properties": { + "text": "A+B", + "x_ofs": 157, + "y_ofs": 98, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_temperature", + "desc": "枪温度文本", + "type": "label", + "properties": { + "text": "Conn Temperature", + "x_ofs": 12, + "y_ofs": 142, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_temperature_value", + "desc": "枪温度值", + "type": "label", + "properties": { + "text": "34.0°", + "x_ofs": 157, + "y_ofs": 142, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "output_voltage", + "desc": "输出电压文本", + "type": "label", + "properties": { + "text": "Output Voltage", + "x_ofs": 12, + "y_ofs": 186, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "output_voltage_value", + "desc": "输出电压值", + "type": "label", + "properties": { + "text": "399.7V", + "x_ofs": 157, + "y_ofs": 186, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "output_current", + "desc": "输出电流文本", + "type": "label", + "properties": { + "text": "Output Current", + "x_ofs": 12, + "y_ofs": 230, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "output_current_value", + "desc": "输出电流值", + "type": "label", + "properties": { + "text": "119.6A", + "x_ofs": 157, + "y_ofs": 230, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00113_detailed_data_close_button.json b/assets/fragment/fragment_00113_detailed_data_close_button.json new file mode 100644 index 000000000..a76c59397 --- /dev/null +++ b/assets/fragment/fragment_00113_detailed_data_close_button.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_detailed_data_close", + "desc": "close按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "Close", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00114_help1_charging_time_cost.json b/assets/fragment/fragment_00114_help1_charging_time_cost.json new file mode 100644 index 000000000..c44ac08dc --- /dev/null +++ b/assets/fragment/fragment_00114_help1_charging_time_cost.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_charging_time_cost_help1", + "desc": "充电详细信息", + "type": "button", + "properties": { + "style": "style-charging_time_cost" + }, + "children": [ + { + "name": "NoText_help1", + "type": "label", + "properties": { + "text": "Charging time and cost", + "align" : "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-power-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00115_conn_top_id.json b/assets/fragment/fragment_00115_conn_top_id.json new file mode 100644 index 000000000..19aaa9bee --- /dev/null +++ b/assets/fragment/fragment_00115_conn_top_id.json @@ -0,0 +1,33 @@ +{ + "name": "fragment_conn_top_id", + "desc": "中间卡片左上角枪号", + "type": "flex", + "properties": { + "style": "style-idle-num-border" + }, + "children": [ + { + "name": "conn_id_text", + "type": "label", + "properties": { + "text": "1", + "align" : "LV_ALIGN_CENTER", + "style": "style-idle-num-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_type_icon", + "type": "image", + "properties": { + "src": "ccs2-dc_1connect", + "width": 56, + "height": 56, + "x_ofs": 7, + "y_ofs": 7, + "align": "LV_ALIGN_TOP_LEFT", + "hidden": true + } + } + ] +} diff --git a/assets/fragment/fragment_00116_common_circle.json b/assets/fragment/fragment_00116_common_circle.json new file mode 100644 index 000000000..45533f543 --- /dev/null +++ b/assets/fragment/fragment_00116_common_circle.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_common_circle", + "desc": "感叹号", + "type": "flex", + "properties": { + "style": "style-connection_failed-circle" + }, + "children": [ + { + "name": "!_session_error", + "type": "label", + "properties": { + "text": "!", + "align" : "LV_ALIGN_CENTER", + "style": "style-draw_icon_symbol", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00117_common_close_button.json b/assets/fragment/fragment_00117_common_close_button.json new file mode 100644 index 000000000..ee9fc9200 --- /dev/null +++ b/assets/fragment/fragment_00117_common_close_button.json @@ -0,0 +1,30 @@ +{ + "name": "fragment_common_close", + "desc": "close按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "text", + "type": "label", + "properties": { + "text": "Close", + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "seconds", + "type": "label", + "properties": { + "text": "", + "x_ofs": 40, + "align" : "LV_ALIGN_CENTER", + "style": "style-continue_label_session_error" + } + } + ] +} diff --git a/assets/fragment/fragment_00118_idle_info_card_no_price.json b/assets/fragment/fragment_00118_idle_info_card_no_price.json new file mode 100644 index 000000000..a86c23761 --- /dev/null +++ b/assets/fragment/fragment_00118_idle_info_card_no_price.json @@ -0,0 +1,141 @@ +{ + "name": "fragment_idle_info_card_no_price", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "qr_code", + "type": "qr", + "properties": { + "x_ofs": 85, + "y_ofs": 10, + "size": 94, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "qr_code_prompt", + "desc": "二维码提示文本", + "type": "label", + "properties": { + "text": "Download Ioc APP for a faster experience.", + "width": 227, + "x_ofs": 18, + "y_ofs": 117, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "charger_station_img", + "desc": "充电桩状态图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 174, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_charging-station" + } + }, + { + "name": "charger_station_label", + "desc": "充电桩状态文本", + "type": "label", + "properties": { + "text": "Charger id:", + "x_ofs": 65, + "y_ofs": 175, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "contact_img", + "desc": "联系图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 198, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_contact" + } + }, + { + "name": "contact_label", + "desc": "联系文本", + "type": "label", + "properties": { + "text": "0878-1058-4499", + "x_ofs": 65, + "y_ofs": 199, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "telephone_img", + "desc": "移动电话图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 222, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_telephone" + } + }, + { + "name": "telephone_label", + "desc": "移动电话文本", + "type": "label", + "properties": { + "text": "(021)5088-6428", + "x_ofs": 65, + "y_ofs": 223, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "url_img", + "desc": "网址图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 246, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_url" + } + }, + { + "name": "url_label", + "desc": "网址文本", + "type": "label", + "properties": { + "text": "Ioc.id", + "x_ofs": 65, + "y_ofs": 247, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00119_starting1_info_card_no_price.json b/assets/fragment/fragment_00119_starting1_info_card_no_price.json new file mode 100644 index 000000000..ba26cfe88 --- /dev/null +++ b/assets/fragment/fragment_00119_starting1_info_card_no_price.json @@ -0,0 +1,141 @@ +{ + "name": "fragment_starting1_info_card_no_price", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "qr_code", + "type": "qr", + "properties": { + "x_ofs": 85, + "y_ofs": 10, + "size": 94, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "qr_code_prompt", + "desc": "二维码提示文本", + "type": "label", + "properties": { + "text": "Download Ioc APP for a faster experience.", + "width": 227, + "x_ofs": 18, + "y_ofs": 117, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "charger_station_img", + "desc": "充电桩状态图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 174, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_charging-station" + } + }, + { + "name": "charger_station_label", + "desc": "充电桩状态文本", + "type": "label", + "properties": { + "text": "Charger id:", + "x_ofs": 65, + "y_ofs": 175, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "contact_img", + "desc": "联系图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 198, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_contact" + } + }, + { + "name": "contact_label", + "desc": "联系文本", + "type": "label", + "properties": { + "text": "0878-1058-4499", + "x_ofs": 65, + "y_ofs": 199, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "telephone_img", + "desc": "移动电话图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 222, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_telephone" + } + }, + { + "name": "telephone_label", + "desc": "移动电话文本", + "type": "label", + "properties": { + "text": "(021)5088-6428", + "x_ofs": 65, + "y_ofs": 223, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "url_img", + "desc": "网址图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 246, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_url" + } + }, + { + "name": "url_label", + "desc": "网址文本", + "type": "label", + "properties": { + "text": "Ioc.id", + "x_ofs": 65, + "y_ofs": 247, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00120_starting2_info_card_no_price.json b/assets/fragment/fragment_00120_starting2_info_card_no_price.json new file mode 100644 index 000000000..7bb1a02db --- /dev/null +++ b/assets/fragment/fragment_00120_starting2_info_card_no_price.json @@ -0,0 +1,141 @@ +{ + "name": "fragment_starting2_info_card_no_price", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "qr_code", + "type": "qr", + "properties": { + "x_ofs": 85, + "y_ofs": 10, + "size": 94, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "qr_code_prompt", + "desc": "二维码提示文本", + "type": "label", + "properties": { + "text": "Download Ioc APP for a faster experience.", + "width": 227, + "x_ofs": 18, + "y_ofs": 117, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "charger_station_img", + "desc": "充电桩状态图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 174, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_charging-station" + } + }, + { + "name": "charger_station_label", + "desc": "充电桩状态文本", + "type": "label", + "properties": { + "text": "Charger id:", + "x_ofs": 65, + "y_ofs": 175, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "contact_img", + "desc": "联系图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 198, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_contact" + } + }, + { + "name": "contact_label", + "desc": "联系文本", + "type": "label", + "properties": { + "text": "0878-1058-4499", + "x_ofs": 65, + "y_ofs": 199, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "telephone_img", + "desc": "移动电话图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 222, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_telephone" + } + }, + { + "name": "telephone_label", + "desc": "移动电话文本", + "type": "label", + "properties": { + "text": "(021)5088-6428", + "x_ofs": 65, + "y_ofs": 223, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "url_img", + "desc": "网址图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 246, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_url" + } + }, + { + "name": "url_label", + "desc": "网址文本", + "type": "label", + "properties": { + "text": "Ioc.id", + "x_ofs": 65, + "y_ofs": 247, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00121_charging_info_card_no_price.json b/assets/fragment/fragment_00121_charging_info_card_no_price.json new file mode 100644 index 000000000..e66121443 --- /dev/null +++ b/assets/fragment/fragment_00121_charging_info_card_no_price.json @@ -0,0 +1,61 @@ +{ + "name": "fragment_charging_info_card_no_price", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "qr_code", + "type": "qr", + "properties": { + "x_ofs": 85, + "y_ofs": 10, + "size": 94, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "qr_code_prompt", + "desc": "二维码提示文本", + "type": "label", + "properties": { + "text": "Download Ioc APP for a faster experience.", + "width": 227, + "x_ofs": 18, + "y_ofs": 117, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "split_line_charging", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 203, + "height": 1, + "x_ofs": 30, + "y_ofs": 189, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-split" + } + }, + { + "name": "btn", + "desc": "充电详细数据", + "type": "fragment", + "fragment_name": "fragment_detailed_data_charging_noprice", + "properties": { + "x_ofs" : 0, + "y_ofs" : 110, + "align": "LV_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00122_charging_detailed_data_noprice.json b/assets/fragment/fragment_00122_charging_detailed_data_noprice.json new file mode 100644 index 000000000..07006edcb --- /dev/null +++ b/assets/fragment/fragment_00122_charging_detailed_data_noprice.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_detailed_data_charging_noprice", + "desc": "充电详细信息", + "type": "button", + "properties": { + "style": "style-detailed_data_charging" + }, + "children": [ + { + "name": "label", + "type": "label", + "properties": { + "text": "Detailed Data", + "align" : "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00123_finished_info_card_no_price.json b/assets/fragment/fragment_00123_finished_info_card_no_price.json new file mode 100644 index 000000000..cc0194f26 --- /dev/null +++ b/assets/fragment/fragment_00123_finished_info_card_no_price.json @@ -0,0 +1,57 @@ +{ + "name": "fragment_finished_info_card_no_price", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "idle_time_label_finished", + "desc": "停充后的idele time 文本", + "type": "label", + "properties": { + "text": "Idle time", + "x_ofs": 0, + "y_ofs": -65, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "idle_time_value_finished", + "desc": "停充后的占位时间", + "type": "label", + "properties": { + "text": "04:24", + "x_ofs": 0, + "y_ofs": -20, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "prompt", + "desc": "拔枪剩余时间提醒", + "type": "label", + "properties": { + "text": "Please move your vehicle.10mins grace period exceeded.", + "x_ofs": 0, + "y_ofs": 35, + "width": 235, + "height": 40, + "align": "LV_ALIGN_CENTER", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00124_reserved_info_card_no_price.json b/assets/fragment/fragment_00124_reserved_info_card_no_price.json new file mode 100644 index 000000000..908527940 --- /dev/null +++ b/assets/fragment/fragment_00124_reserved_info_card_no_price.json @@ -0,0 +1,57 @@ +{ + "name": "fragment_reserved_info_card_no_price", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "style":"style-info_card" + }, + "children": [ + { + "name": "left_time_label", + "desc": "预约剩余时间文本", + "type": "label", + "properties": { + "text": "Left", + "x_ofs": 0, + "y_ofs": -65, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "idle_time_value_reserved", + "desc": "拔枪剩余时间", + "type": "label", + "properties": { + "text": "04:24", + "x_ofs": 0, + "y_ofs": -20, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "plug_noprice", + "desc": "先插枪", + "type": "label", + "properties": { + "text": "Plug in first", + "x_ofs": 0, + "y_ofs": 35, + "width": 235, + "height": 40, + "align": "LV_ALIGN_CENTER", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00125_reserved_ocpp_price.json b/assets/fragment/fragment_00125_reserved_ocpp_price.json new file mode 100644 index 000000000..dfdd1cc41 --- /dev/null +++ b/assets/fragment/fragment_00125_reserved_ocpp_price.json @@ -0,0 +1,25 @@ +{ + "name": "fragment_ocpp_price", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 263, + "height": 140, + "style":"style-info_card_half" + }, + "children": [ + { + "name": "label", + "desc": "ocpp价格", + "type": "label", + "properties": { + "text": "0.15 $/kWh, idle fee after charging: 1 $/hr", + "width": 243, + "y_ofs": 0, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00126_starting2_POS_btn.json b/assets/fragment/fragment_00126_starting2_POS_btn.json new file mode 100644 index 000000000..0d802eeef --- /dev/null +++ b/assets/fragment/fragment_00126_starting2_POS_btn.json @@ -0,0 +1,20 @@ +{ + "name": "fragment_starting2_pos_btn", + "desc": "POS机按钮", + "type": "button", + "properties": { + "style": "style-continue_button_session_error" + }, + "children": [ + { + "name": "img", + "type": "image", + "properties": { + "width": 130, + "height": 130, + "align": "LV_ALIGN_CENTER", + "src": "pic_pos" + } + } + ] +} diff --git a/assets/fragment/fragment_00127_popup_common_prompt.json b/assets/fragment/fragment_00127_popup_common_prompt.json new file mode 100644 index 000000000..3255bfd36 --- /dev/null +++ b/assets/fragment/fragment_00127_popup_common_prompt.json @@ -0,0 +1,25 @@ +{ + "name": "fragment_popup_common_prompt", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 450, + "height": 120, + "style":"style-mid_container_top" + }, + "children": [ + { + "name": "text", + "desc": "通用提示文本", + "type": "label", + "properties": { + "text": "downloading", + "width": 430, + "y_ofs": 0, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_label", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00128_session_error_code.json b/assets/fragment/fragment_00128_session_error_code.json new file mode 100644 index 000000000..1a3988c61 --- /dev/null +++ b/assets/fragment/fragment_00128_session_error_code.json @@ -0,0 +1,32 @@ +{ + "name": "fragment_session_error_code", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 200, + "height": 40, + "style":"style-mid_container_top" + }, + "children": [ + { + "name": "label", + "desc": "错误码", + "type": "label", + "properties": { + "text": "Error code:", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "value", + "desc": "错误码", + "type": "label", + "properties": { + "text": "", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/fragment/fragment_00129_start_error_code.json b/assets/fragment/fragment_00129_start_error_code.json new file mode 100644 index 000000000..07ec20a7d --- /dev/null +++ b/assets/fragment/fragment_00129_start_error_code.json @@ -0,0 +1,36 @@ +{ + "name": "fragment_start_error_code", + "desc": "中间卡片部分", + "type": "flex", + "properties": { + "width": 200, + "height": 40, + "style":"style-mid_container_top" + }, + "children": [ + { + "name": "label", + "desc": "错误码", + "type": "label", + "properties": { + "text": "Error code:", + "x":0, + "width": 130, + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_RIGHT" + } + }, + { + "name": "value", + "desc": "错误码", + "type": "label", + "properties": { + "text": "", + "x":130, + "width": 70, + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_LEFT" + } + } + ] +} diff --git a/assets/fragment/fragment_00130_price_rate.json b/assets/fragment/fragment_00130_price_rate.json new file mode 100644 index 000000000..415612dd4 --- /dev/null +++ b/assets/fragment/fragment_00130_price_rate.json @@ -0,0 +1,51 @@ +{ + "name": "fragment_price_rate", + "desc": "当前时间段价格信息", + "type": "flex", + "properties": { + "width": 113, + "height": 102, + "style":"style-info_card" + }, + "children": [ + { + "name": "price_kwh", + "desc": "当前时间段kwh计费", + "type": "label", + "properties": { + "text": "34.3$/Kwh", + "x_ofs": 0, + "y_ofs": 0, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_LEFT" + } + }, + { + "name": "price_hr", + "desc": "当前时间段hr计费", + "type": "label", + "properties": { + "text": "34.3$/hr", + "x_ofs": 0, + "y_ofs": 27, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_LEFT" + } + }, + { + "name": "price_times", + "desc": "当前时间段times计费", + "type": "label", + "properties": { + "text": "34.3$/times", + "x_ofs": 0, + "y_ofs": 54, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_LEFT" + } + } + ] +} diff --git a/assets/fragment/fragment_00131_price_current.json b/assets/fragment/fragment_00131_price_current.json new file mode 100644 index 000000000..a275c2a3e --- /dev/null +++ b/assets/fragment/fragment_00131_price_current.json @@ -0,0 +1,73 @@ +{ + "name": "fragment_price_current", + "desc": "当前时间段价格信息", + "type": "flex", + "properties": { + "width": 244, + "height": 102, + "style":"style-info_card" + }, + "children": [ + { + "name": "price_current_period_icon", + "desc": "当前时间段图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 38, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_current-time" + } + }, + { + "name": "price_current_dot", + "desc": "当前时间段小圆点", + "type": "flex", + "properties": { + "width": 6, + "height": 6, + "x_ofs": 0, + "y_ofs": 37, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-idle-curtime-circle" + } + }, + { + "name": "price_current_title", + "desc": "当前时间段文本", + "type": "label", + "properties": { + "text": "Current Period", + "x_ofs": 30, + "y_ofs": 64, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_current_time", + "desc": "当前时间段", + "type": "label", + "properties": { + "text": "13:00-14:00", + "x_ofs": 30, + "y_ofs": 92, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_current_rate", + "type": "fragment", + "fragment_name" : "fragment_price_rate", + "properties": { + "x":131, + "y":0 + } + } + ] +} diff --git a/assets/fragment/fragment_00132_price_next.json b/assets/fragment/fragment_00132_price_next.json new file mode 100644 index 000000000..87bfb016c --- /dev/null +++ b/assets/fragment/fragment_00132_price_next.json @@ -0,0 +1,73 @@ +{ + "name": "fragment_price_next", + "desc": "下一时间段价格信息", + "type": "flex", + "properties": { + "width": 244, + "height": 102, + "style":"style-info_card" + }, + "children": [ + { + "name": "price_next_period_img", + "desc": "下一时间段图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 38, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_next-time" + } + }, + { + "name": "price_next_dot", + "desc": "下一时间段小圆点", + "type": "flex", + "properties": { + "width": 6, + "height": 6, + "x_ofs": 0, + "y_ofs": 37, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-idle-netper-circle" + } + }, + { + "name": "price_next_title", + "desc": "下一时间段文本", + "type": "label", + "properties": { + "text": "Next Period", + "x_ofs": 30, + "y_ofs": 64, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_next_time", + "desc": "下一时间段", + "type": "label", + "properties": { + "text": "13:00-14:00", + "x_ofs": 30, + "y_ofs": 92, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_next_rate", + "type": "fragment", + "fragment_name" : "fragment_price_rate", + "properties": { + "x":131, + "y":0 + } + } + ] +} diff --git a/assets/help.json b/assets/help.json new file mode 100644 index 000000000..634d9b113 --- /dev/null +++ b/assets/help.json @@ -0,0 +1,46 @@ +[ + { + "title": "How to use the app", + "content": "This app allows you to create and manage your tasks efficiently. You can add, edit, and delete tasks as needed. To get started, click on the 'Add Task' button and fill in the details." + }, + { + "title": "Task Management", + "content": "The app provides a task management system where you can add, edit, and delete tasks. You can also mark tasks as completed or pending." + }, + { + "title": "Task Prioritization", + "content": "The app allows you to prioritize tasks based on their importance. You can set the priority level for each task and sort them accordingly." + }, + { + "title": "Task Reminders", + "content": "The app provides task reminders to help you stay on track. You can set reminders for specific tasks and receive notifications when they are due." + }, + { + "title": "User Settings", + "content": "You can customize your user settings in the app. This includes changing your password, updating your profile information, and managing notification preferences." + }, + { + "title": "Feedback and Support", + "content": "If you have any feedback or need support, please reach out to us through the 'Contact Us' section in the app. We value your input and are here to help." + }, + { + "title": "Privacy Policy", + "content": "We take your privacy seriously. Our app complies with all relevant data protection regulations and ensures the confidentiality of your personal information." + }, + { + "title": "Terms of Service", + "content": "By using this app, you agree to our terms of service. Please read them carefully to understand your rights and responsibilities." + }, + { + "title": "Frequently Asked Questions", + "content": "For common questions and answers, please refer to the FAQ section in the app. If you have further questions, feel free to contact us." + }, + { + "title": "App Updates", + "content": "We regularly update the app to improve performance and add new features. Make sure to keep your app updated to enjoy the latest enhancements." + }, + { + "title": "Contact Us", + "content": "If you need assistance, please contact our support team through the 'Contact Us' section in the app. We are here to help you with any issues you may encounter." + } +] diff --git a/assets/i18n/de-DE.json b/assets/i18n/de-DE.json new file mode 100644 index 000000000..0f318fa34 --- /dev/null +++ b/assets/i18n/de-DE.json @@ -0,0 +1,527 @@ +{ + "name": "de-DE", + "label": "Deutsch", + "icon": "A:./assets/images/Germany.png", + "content": [ + { + "name": "Plug_in_frist", + "value": "Zuerst einstecken" + }, + { + "name": "home_prompt", + "value": "Bitte schließen Sie den Stecker zuerst an Ihr Fahrzeug an, bevor Sie eine neue Ladesitzung starten." + }, + { + "name": "qr_code_prompt", + "value": "Für schnelles Laden jederzeit griffbereit laden Sie bitte die Ioc-App herunter." + }, + { + "name": "charger_station", + "value": "Ladegerät-ID: " + }, + { + "name": "Idle", + "value": "Leerlauf" + }, + { + "name": "Help", + "value": "Hilfe" + }, + { + "name": "conid", + "value": "Anschluss-ID: " + }, + { + "name": "Current_Period", + "value": "Aktueller Zeitraum" + }, + { + "name": "Next_Period", + "value": "Nächster Zeitraum" + }, + { + "name": "Starting", + "value": "Beginnend" + }, + { + "name": "Scan_here_to_start_charging", + "value": "Hier scannen, um den Ladevorgang zu starten" + }, + { + "name": "starting_prompt", + "value": "Greifen Sie landesweit auf Tausende von Ladestationen zu. Mit nur einer App erhalten Sie Zugriff auf Dutzende von Ladenetzwerken." + }, + { + "name": "Charging", + "value": "Aufladen" + }, + { + "name": "Power", + "value": "Leistung" + }, + { + "name": "SoC", + "value": "Ladezustand" + }, + { + "name": "Energy", + "value": "Energie" + }, + { + "name": "Duration", + "value": "Dauer" + }, + { + "name": "Estimated_Cost", + "value": "Geschätzte Kosten" + }, + { + "name": "Detailed_data", + "value": "Detaillierte Daten" + }, + { + "name": "State of charge", + "value": "Ladezustand" + }, + { + "name": "Finished", + "value": "Fertig" + }, + { + "name": "Start_time", + "value": "Startzeit" + }, + { + "name": "Idle_time", + "value": "Leerlaufzeit" + }, + { + "name": "Idle_time_prompt", + "value": "Bitte bewegen Sie Ihr Fahrzeug. Die 10-minütige Karenzzeit wurde überschritten." + }, + { + "name": "Charging_cost", + "value": "Ladekosten" + }, + { + "name": "Idle_fee", + "value": "Leerlaufgebühr" + }, + { + "name": "Total_Amount", + "value": "Gesamtbetrag" + }, + { + "name": "Reserved", + "value": "Reserviert" + }, + { + "name": "Left", + "value": "Links" + }, + { + "name": "left", + "value": "links" + }, + { + "name": "Stopping", + "value": "Anhalten" + }, + { + "name": "Charging_session_error", + "value": "Fehler bei der Ladesitzung" + }, + { + "name": "Error_code_session_error", + "value": "Fehlercode: " + }, + { + "name": "session_error_prompt", + "value": "Die Ladung wurde unterbrochen, bitte ziehen Sie den Stecker. Um eine neue Ladesitzung zu starten, verbinden Sie sich erneut und drücken Sie Weiter." + }, + { + "name": "Continue", + "value": "Weiter" + }, + { + "name": "Error", + "value": "Error" + }, + { + "name": "Charging_start_error", + "value": "Fehler beim Start der Ladeeinheit" + }, + { + "name": "start_error_prompt", + "value": "Ihr Guthaben wurde nicht belastet. Um eine neue Ladesitzung zu starten, bitte verbinden Sie sich erneut." + }, + { + "name": "Fault", + "value": "Fehler" + }, + { + "name": "Equipment_failure", + "value": "Ausrüstungsfehler" + }, + { + "name": "Other_error", + "value": "Andere Fehler: 07" + }, + { + "name": "Lock Failure", + "value": "Sperrfehler" + }, + { + "name": "EV Communication Error", + "value": "EV-Kommunikationsfehler" + }, + { + "name": "Ground Failure", + "value": "Erdschluss" + }, + { + "name": "High Temperature", + "value": "Hohe Temperatur" + }, + { + "name": "Internal Error", + "value": "Interner Fehler" + }, + { + "name": "Over Current", + "value": "Überstrom" + }, + { + "name": "Over Voltage", + "value": "Überspannung" + }, + { + "name": "Meter Failure", + "value": "Zählerfehler" + }, + { + "name": "Power Switch Failure", + "value": "Netzschalterfehler" + }, + { + "name": "Reader Failure", + "value": "Leserfehler" + }, + { + "name": "Reset Failure", + "value": "Fehler zurücksetzen" + }, + { + "name": "Under Voltage", + "value": "Unterspannung" + }, + { + "name": "Weak Signal", + "value": "Schwaches Signal" + }, + { + "name": "Emergency Pushed", + "value": "Notfall gedrückt" + }, + { + "name": "PhaseSwap Failure", + "value": "PhaseSwap-Fehler" + }, + { + "name": "Other Error", + "value": "Anderer Fehler" + }, + { + "name": "Door Opened", + "value": "Tür ist offen" + }, + { + "name": "MCCB Opened", + "value": "MCCB geöffnet" + }, + { + "name": "fault_prompt", + "value": "Bitte kontaktieren Sie das Wartungspersonal." + }, + { + "name": "Unavailable", + "value": "Nicht verfügbar" + }, + { + "name": "Out_of_service", + "value": "Außer Betrieb" + }, + { + "name": "unavailable_prompt", + "value": "Leider ist dieser Ladepunkt nicht verfügbar. Bitte überprüfen Sie die Ioc-App, um einen anderen Ladepunkt in Ihrer Nähe zu finden oder kontaktieren Sie den Kundensupport." + }, + { + "name": "Plug & Charge", + "value": "Stecken & Laden" + }, + { + "name": "connecting_prompt", + "value": "oder AutoCharge startet…" + }, + { + "name": "Authorized", + "value": "Autorisierter" + }, + { + "name": "Charging_is_stopping", + "value": "Laden wird gestoppt" + }, + { + "name": "Waiting", + "value": "Warten" + }, + { + "name": "Wait_in_line", + "value": "Warten Sie in der Warteschlange" + }, + { + "name": "Wait_in_line_prompt", + "value": "Warten auf einen anderen Anschluss, um Strom zu teilen. Das Laden beginnt automatisch, wenn der Anschluss im Leerlauf ist." + }, + { + "name": "Charging_time_and_cost", + "value": "Ladezeit und Kosten" + }, + { + "name": "Energy_delivered_and_charging_rate", + "value": "Gelieferte Energie und Ladeleistung" + }, + { + "name": "State_of_charge", + "value": "Ladezustand" + }, + { + "name": "Balanced_chargers", + "value": "Ausgeglichene Ladegeräte" + }, + { + "name": "Terms_of_use", + "value": "Nutzungsbedingungen" + }, + { + "name": "prompt_help1", + "value": "Für schnelles Laden auf Ihrem Smartphone, laden Sie bitte die Ioc-App herunter." + }, + { + "name": "content_help2", + "value": "Das Laden konnte nicht gestartet werden. Bitte stellen Sie sicher, dass Ihr Fahrzeug korrekt angeschlossen ist. Ihr Guthaben wurde nicht belastet. Um eine neue Ladesitzung zu starten, verbinden Sie sich bitte erneut." + }, + { + "name": "Close", + "value": "Schließen" + }, + { + "name": "Back", + "value": "Zurück" + }, + { + "name": "Authorization_failed", + "value": "Autorisierung fehlgeschlagen" + }, + { + "name": "Reason_for_failure", + "value": "Grund für den Fehler" + }, + { + "name": "Scan_for_bill", + "value": "Scanner pour la facture" + }, + { + "name": "Scan_for_receipt", + "value": "Scan für den Beleg" + }, + { + "name": "Please_enter_the_amount", + "value": "Bitte geben Sie den Betrag ein" + }, + { + "name": "Confirm", + "value": "Bestätigen" + }, + { + "name": "Suspend", + "value": "Suspendieren" + }, + { + "name": "Charging_suspend", + "value": "Ladevorgang pausiert" + }, + { + "name": "Detailed_data", + "value": "Detaillierte Daten" + }, + { + "name": "Run_State", + "value": "Status Ausführen" + }, + { + "name": "Sub_State", + "value": "Unterstaat" + }, + { + "name": "Error_Code", + "value": "Fehlercode" + }, + { + "name": "Conn_Status", + "value": "Verbindungsstatus" + }, + { + "name": "Start_SoC", + "value": "Starten Sie SoC" + }, + { + "name": "Request_Voltage", + "value": "Spannung Anfordern" + }, + { + "name": "Request_Current", + "value": "Strom Anfordern" + }, + { + "name": "Offer_Voltage", + "value": "Spannung Angeboten" + }, + { + "name": "Offer_Current", + "value": "Strom Angeboten" + }, + { + "name": "Output_Limit", + "value": "Ausgang Sgrenze" + }, + { + "name": "Comp_Group", + "value": "Modul Gruppe" + }, + { + "name": "Conn_Temperature", + "value": "Stecker Temperatur" + }, + { + "name": "Output_Voltage", + "value": "Ausgangs Spannung" + }, + { + "name": "Output_Current", + "value": "Ausgangs Strom" + }, + { + "name": "Processing", + "value": "Verarbeitung" + }, + { + "name": "Processing_prompt", + "value": "Dies kann einige Minuten dauern" + }, + { + "name": "Downloading", + "value": "Wird Heruntergeladen" + }, + { + "name": "Installing", + "value": "Installieren" + }, + { + "name": "No connector selected", + "value": "Kein Anschluss ausgewählt" + }, + { + "name": "Failed to start charging", + "value": "Ladevorgang fehlgeschlagen" + }, + { + "name": "Fault found, Stop Charging", + "value": "Fehler gefunden. Laden Sie nicht mehr auf" + }, + { + "name": "Please start charging within 1 minutes for connector 1th", + "value": "Bitte beginnen Sie das Laden innerhalb von 1 Minute für Anschluss 1." + }, + { + "name": "Please start charging within 1 minutes for connector 2th", + "value": "Bitte beginnen Sie das Laden innerhalb von 1 Minute für Anschluss 2." + }, + { + "name": "Please start charging within 1 minutes for connector 3th", + "value": "Bitte beginnen Sie das Laden innerhalb von 1 Minute für Anschluss 3." + }, + { + "name": "Please start charging within 1 minutes for connector 4th", + "value": "Bitte beginnen Sie das Laden innerhalb von 1 Minute für Anschluss 4." + }, + { + "name": "Please start charging within 1 minutes", + "value": "Bitte beginnen Sie das Laden innerhalb von 1 Minute" + }, + { + "name": "Not Permit", + "value": "Nicht erlauben" + }, + { + "name": "Swipe, insert or tap your card on the POS", + "value": "Ziehen, stecken oder tippen Sie Ihre Karte am POS" + }, + { + "name": "pre-authorization failed", + "value": "Vorautorisierung fehlgeschlagen" + }, + { + "name": "Pre-Authorization Settled", + "value": "Vorautorisierung abgeschlossen" + }, + { + "name": "Payment failed", + "value": "Bezahlung fehlgeschlagen" + }, + { + "name": "Payment Settled", + "value": "Zahlung erledigt" + }, + { + "name": "POS is processing the request, please wait", + "value": "POS verarbeitet die Anfrage, bitte warten" + }, + { + "name": "POS busy, please try again later", + "value": "POS beschäftigt, bitte versuchen Sie es später erneut" + }, + { + "name": "POS error, please contact the service", + "value": "POS -Maschinenfehler, bitte wenden Sie sich an das Personal" + }, + { + "name": "ERROR", + "value": "ERROR" + }, + { + "name": "Authorization Failed: Blocked", + "value": "Autorisierung fehlgeschlagen: Blockiert" + }, + { + "name": "Authorization Failed: Expired", + "value": "Chyba autorizace: Opravneni ukonceno" + }, + { + "name": "Authorization Failed: Invalid", + "value": "Autorisierung fehlgeschlagen: Abgelaufen" + }, + { + "name": "Authorization Failed: Concurrent TX", + "value": "Autorisierung fehlgeschlagen: Gleichzeitige Übertragung" + }, + { + "name": "Authorization Failed: Other Reason", + "value": "Autorisierung fehlgeschlagen: Anderer Grund" + }, + { + "name": "Language", + "value": "Sprache" + } + ] +} diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json new file mode 100644 index 000000000..f42d9dc48 --- /dev/null +++ b/assets/i18n/en-US.json @@ -0,0 +1,527 @@ +{ + "name": "en-US", + "label": "English", + "icon": "A:./assets/images/English.png", + "content": [ + { + "name": "Plug_in_frist", + "value": "Plug in first" + }, + { + "name": "home_prompt", + "value": "Please plug in the connector to you vehicle first before start a new session." + }, + { + "name": "qr_code_prompt", + "value": "Download IoC APP for a faster experience." + }, + { + "name": "charger_station", + "value": "charger id:" + }, + { + "name": "Idle", + "value": "Idle" + }, + { + "name": "Help", + "value": "Help" + }, + { + "name": "conid", + "value": "Connector id:" + }, + { + "name": "Current_Period", + "value": "Current Period" + }, + { + "name": "Next_Period", + "value": "Next Period" + }, + { + "name": "Starting", + "value": "Starting" + }, + { + "name": "Scan_here_to_start_charging", + "value": "Scan here to start charging" + }, + { + "name": "starting_prompt", + "value": "Access thousands of chargers across multiple networks with one app." + }, + { + "name": "Charging", + "value": "Charging" + }, + { + "name": "Power", + "value": "Power" + }, + { + "name": "SoC", + "value": "SoC" + }, + { + "name": "Energy", + "value": "Energy" + }, + { + "name": "Duration", + "value": "Duration" + }, + { + "name": "Estimated_Cost", + "value": "Estimated Cost" + }, + { + "name": "Detailed_data", + "value": "Detailed data" + }, + { + "name": "State of charge", + "value": "State of charge" + }, + { + "name": "Finished", + "value": "Finished" + }, + { + "name": "Start_time", + "value": "Start time" + }, + { + "name": "Idle_time", + "value": "Idle time" + }, + { + "name": "Idle_time_prompt", + "value": "Please move your vehicle.10mins grace period exceeded." + }, + { + "name": "Charging_cost", + "value": "Charging cost" + }, + { + "name": "Idle_fee", + "value": "Idle fee" + }, + { + "name": "Total_Amount", + "value": "Total Amount" + }, + { + "name": "Reserved", + "value": "Reserved" + }, + { + "name": "Left", + "value": "Left" + }, + { + "name": "left", + "value": "left" + }, + { + "name": "Stopping", + "value": "Stopping" + }, + { + "name": "Charging_session_error", + "value": "Charging session error" + }, + { + "name": "Error_code_session_error", + "value": "Error code:" + }, + { + "name": "session_error_prompt", + "value": "Charging has been interrupted, please unplug. To start a new charging session, reconnect and press Continue." + }, + { + "name": "Continue", + "value": "Continue" + }, + { + "name": "Error", + "value": "Error" + }, + { + "name": "Charging_start_error", + "value": "Charging start error" + }, + { + "name": "start_error_prompt", + "value": "Your credit has not been charged. To start a new charging session,please reconnect." + }, + { + "name": "Fault", + "value": "Fault" + }, + { + "name": "Equipment_failure", + "value": "Equipment failure" + }, + { + "name": "Other_error", + "value": "Other error:07" + }, + { + "name": "Lock Failure", + "value": "Lock Failure" + }, + { + "name": "EV Communication Error", + "value": "EV Communication Error" + }, + { + "name": "Ground Failure", + "value": "Ground Failure" + }, + { + "name": "High Temperature", + "value": "High Temperature" + }, + { + "name": "Internal Error", + "value": "Internal Error" + }, + { + "name": "Over Current", + "value": "Over Current" + }, + { + "name": "Over Voltage", + "value": "Over Voltage" + }, + { + "name": "Meter Failure", + "value": "Meter Failure" + }, + { + "name": "Power Switch Failure", + "value": "Power Switch Failure" + }, + { + "name": "Reader Failure", + "value": "Reader Failure" + }, + { + "name": "Reset Failure", + "value": "Reset Failure" + }, + { + "name": "Under Voltage", + "value": "Under Voltage" + }, + { + "name": "Weak Signal", + "value": "Weak Signal" + }, + { + "name": "Emergency Pushed", + "value": "Emergency Pushed" + }, + { + "name": "PhaseSwap Failure", + "value": "PhaseSwap Failure" + }, + { + "name": "Other Error", + "value": "Other Error" + }, + { + "name": "Door Opened", + "value": "Door Opened" + }, + { + "name": "MCCB Opened", + "value": "MCCB Opened" + }, + { + "name": "fault_prompt", + "value": "Please contact the maintenance staff." + }, + { + "name": "Unavailable", + "value": "Unavailable" + }, + { + "name": "Out_of_service", + "value": "Out of service" + }, + { + "name": "unavailable_prompt", + "value": "Unfortunately, this charger is unavailable.Please check the Ioc app to find another charger near you or contact customer support." + }, + { + "name": "Plug & Charge", + "value": "Plug & Charge" + }, + { + "name": "connecting_prompt", + "value": "or AutoCharge starting…" + }, + { + "name": "Authorized", + "value": "Authorized" + }, + { + "name": "Charging_is_stopping", + "value": "Charging is stopping" + }, + { + "name": "Waiting", + "value": "Waiting" + }, + { + "name": "Wait_in_line", + "value": "Wait in line" + }, + { + "name": "Wait_in_line_prompt", + "value": "Waiting for another connector to share power,Charging will automatically start when idle." + }, + { + "name": "Charging_time_and_cost", + "value": "Charging time and cost" + }, + { + "name": "Energy_delivered_and_charging_rate", + "value": "Energy delivered and charging rate" + }, + { + "name": "State_of_charge", + "value": "State of charge" + }, + { + "name": "Balanced_chargers", + "value": "Balanced chargers" + }, + { + "name": "Terms_of_use", + "value": "Terms of use" + }, + { + "name": "prompt_help1", + "value": "Download IoC APP for a faster experience." + }, + { + "name": "content_help2", + "value": "Charging could not be initiated. Please ensure your vehicle is plugged in correctly. Your credit has not been charged. To start a new charging session, please reconnect." + }, + { + "name": "Close", + "value": "Close" + }, + { + "name": "Back", + "value": "Back" + }, + { + "name": "Authorization_failed", + "value": "Authorization failed" + }, + { + "name": "Reason_for_failure", + "value": "Reason for failure" + }, + { + "name": "Scan_for_bill", + "value": "Scan for bill" + }, + { + "name": "Scan_for_receipt", + "value": "Scan for receipt" + }, + { + "name": "Please_enter_the_amount", + "value": "Please enter the amount" + }, + { + "name": "Confirm", + "value": "Confirm" + }, + { + "name": "Suspend", + "value": "Suspend" + }, + { + "name": "Charging_suspend", + "value": "Charging suspend" + }, + { + "name": "Detailed_data", + "value": "Detailed data" + }, + { + "name": "Run_State", + "value": "Run State" + }, + { + "name": "Sub_State", + "value": "Sub State" + }, + { + "name": "Error_Code", + "value": "Error Code" + }, + { + "name": "Conn_Status", + "value": "Conn Status" + }, + { + "name": "Start_SoC", + "value": "Start SoC" + }, + { + "name": "Request_Voltage", + "value": "Request Voltage" + }, + { + "name": "Request_Current", + "value": "Request Current" + }, + { + "name": "Offer_Voltage", + "value": "Offer Voltage" + }, + { + "name": "Offer_Current", + "value": "Offer Current" + }, + { + "name": "Output_Limit", + "value": "Output Limit" + }, + { + "name": "Comp_Group", + "value": "Comp Group" + }, + { + "name": "Conn_Temperature", + "value": "Conn Temperature" + }, + { + "name": "Output_Voltage", + "value": "Output Voltage" + }, + { + "name": "Output_Current", + "value": "Output Current" + }, + { + "name": "Processing", + "value": "Processing" + }, + { + "name": "Processing_prompt", + "value": "it may takes few minutes" + }, + { + "name": "Downloading", + "value": "Downloading" + }, + { + "name": "Installing", + "value": "Installing" + }, + { + "name": "No connector selected", + "value": "No connector selected" + }, + { + "name": "Failed to start charging", + "value": "Failed to start charging" + }, + { + "name": "Fault found, Stop Charging", + "value": "Fault found, Stop Charging" + }, + { + "name": "Please start charging within 1 minutes for connector 1th", + "value": "Please start charging within 1 minutes for connector 1th" + }, + { + "name": "Please start charging within 1 minutes for connector 2th", + "value": "Please start charging within 1 minutes for connector 2th" + }, + { + "name": "Please start charging within 1 minutes for connector 3th", + "value": "Please start charging within 1 minutes for connector 3th" + }, + { + "name": "Please start charging within 1 minutes for connector 4th", + "value": "Please start charging within 1 minutes for connector 4th" + }, + { + "name": "Please start charging within 1 minutes", + "value": "Please start charging within 1 minutes" + }, + { + "name": "Not Permit", + "value": "Not Permit" + }, + { + "name": "Swipe, insert or tap your card on the POS", + "value": "Swipe, insert or tap your card on the POS" + }, + { + "name": "pre-authorization failed", + "value": "pre-authorization failed" + }, + { + "name": "Pre-Authorization Settled", + "value": "Pre-Authorization Settled" + }, + { + "name": "Payment failed", + "value": "Payment failed" + }, + { + "name": "Payment Settled", + "value": "Payment Settled" + }, + { + "name": "POS is processing the request, please wait", + "value": "POS is processing the request, please wait" + }, + { + "name": "POS busy, please try again later", + "value": "POS busy, please try again later" + }, + { + "name": "POS error, please contact the service", + "value": "POS error, please contact the service" + }, + { + "name": "ERROR", + "value": "ERROR" + }, + { + "name": "Authorization Failed: Blocked", + "value": "Authorization Failed: Blocked" + }, + { + "name": "Authorization Failed: Expired", + "value": "Authorization Failed: Expired" + }, + { + "name": "Authorization Failed: Invalid", + "value": "Authorization Failed: Invalid" + }, + { + "name": "Authorization Failed: Concurrent TX", + "value": "Authorization Failed: Concurrent TX" + }, + { + "name": "Authorization Failed: Other Reason", + "value": "Authorization Failed: Other Reason" + }, + { + "name": "Language", + "value": "Language" + } + ] +} \ No newline at end of file diff --git a/assets/i18n/es-ES.json b/assets/i18n/es-ES.json new file mode 100644 index 000000000..236686455 --- /dev/null +++ b/assets/i18n/es-ES.json @@ -0,0 +1,527 @@ +{ + "name": "es-ES", + "label": "Español", + "icon": "A:./assets/images/Spain.png", + "content": [ + { + "name": "Plug_in_frist", + "value": "Conecte primero" + }, + { + "name": "home_prompt", + "value": "Conecte el conector a su vehículo antes de iniciar una nueva sesión." + }, + { + "name": "qr_code_prompt", + "value": "Para una carga rápida al alcance de tu mano, descarga la aplicación Ioc." + }, + { + "name": "charger_station", + "value": "ID del cargador: " + }, + { + "name": "Idle", + "value": "lnactivo" + }, + { + "name": "Help", + "value": "Ayuda" + }, + { + "name": "conid", + "value": "ID del conector: " + }, + { + "name": "Current_Period", + "value": "Periodo actual" + }, + { + "name": "Next_Period", + "value": "Próximo periodo" + }, + { + "name": "Starting", + "value": "Comenzando" + }, + { + "name": "Scan_here_to_start_charging", + "value": "Escanee aquí para comenzar a cargar" + }, + { + "name": "starting_prompt", + "value": "Acceda a miles de cargadores en todo el país. Use una sola aplicación para conectarse a docenas de redes de carga." + }, + { + "name": "Charging", + "value": "Cargando" + }, + { + "name": "Power", + "value": "Poder" + }, + { + "name": "SoC", + "value": "Estado de carga" + }, + { + "name": "Energy", + "value": "Energía" + }, + { + "name": "Duration", + "value": "Duración" + }, + { + "name": "Estimated_Cost", + "value": "Costo estimado" + }, + { + "name": "Detailed_data", + "value": "Datos detallados" + }, + { + "name": "State of charge", + "value": "Estado de carga" + }, + { + "name": "Finished", + "value": "Terminado" + }, + { + "name": "Start_time", + "value": "Heure de début" + }, + { + "name": "Idle_time", + "value": "Temps d'inactivité" + }, + { + "name": "Idle_time_prompt", + "value": "Veuillez déplacer votre véhicule. La période de grâce de 10 minutes est dépassée." + }, + { + "name": "Charging_cost", + "value": "Coût de la recharge" + }, + { + "name": "Idle_fee", + "value": "Frais d'inactivité" + }, + { + "name": "Total_Amount", + "value": "Montant total" + }, + { + "name": "Reserved", + "value": "Reservado" + }, + { + "name": "Left", + "value": "Izquierda" + }, + { + "name": "left", + "value": "restante" + }, + { + "name": "Stopping", + "value": "Parada" + }, + { + "name": "Charging_session_error", + "value": "Erreur de session de recharge" + }, + { + "name": "Error_code_session_error", + "value": "Code d'erreur : " + }, + { + "name": "session_error_prompt", + "value": "La recharge a été interrompue, veuillez débrancher. Pour démarrer une nouvelle session de recharge, reconnectez et appuyez sur Continuer." + }, + { + "name": "Continue", + "value": "Continuer" + }, + { + "name": "Error", + "value": "Erreur" + }, + { + "name": "Charging_start_error", + "value": "Error al iniciar la carga" + }, + { + "name": "start_error_prompt", + "value": "No se ha cargado su crédito. Para iniciar una nueva sesión de carga, por favor reconecte." + }, + { + "name": "Fault", + "value": "Culpa" + }, + { + "name": "Equipment_failure", + "value": "Fallo del equipo" + }, + { + "name": "Other_error", + "value": "Otro error: 07" + }, + { + "name": "Lock Failure", + "value": "La falta de bloqueo" + }, + { + "name": "EV Communication Error", + "value": "Error de comunicación EV" + }, + { + "name": "Ground Failure", + "value": "Falla a tierra" + }, + { + "name": "High Temperature", + "value": "Temperatura alta" + }, + { + "name": "Internal Error", + "value": "Error interno" + }, + { + "name": "Over Current", + "value": "Sobre corriente" + }, + { + "name": "Over Voltage", + "value": "Sobre voltaje" + }, + { + "name": "Meter Failure", + "value": "Falla del medidor" + }, + { + "name": "Power Switch Failure", + "value": "Fallo del interruptor de alimentación" + }, + { + "name": "Reader Failure", + "value": "Fallo del lector" + }, + { + "name": "Reset Failure", + "value": "La falta de reposición" + }, + { + "name": "Under Voltage", + "value": "Bajo voltaje" + }, + { + "name": "Weak Signal", + "value": "Señal débil" + }, + { + "name": "Emergency Pushed", + "value": "Paro de Emergencia" + }, + { + "name": "PhaseSwap Failure", + "value": "Error de cambio de fase" + }, + { + "name": "Other Error", + "value": "Otro error" + }, + { + "name": "Door Opened", + "value": "La puerta está abierta" + }, + { + "name": "MCCB Opened", + "value": "Interruptor MCCB abierto" + }, + { + "name": "fault_prompt", + "value": "Por favor, contacte con el personal de mantenimiento" + }, + { + "name": "Unavailable", + "value": "Indisponible" + }, + { + "name": "Out_of_service", + "value": "Fuera de servicio" + }, + { + "name": "unavailable_prompt", + "value": "Desafortunadamente, este cargador no está disponible. Por favor, consulte la aplicación Ioc para encontrar otro cargador cercano o contacte con el soporte al cliente." + }, + { + "name": "Plug & Charge", + "value": "Conectar y cargar" + }, + { + "name": "connecting_prompt", + "value": "o AutoCarga iniciando…" + }, + { + "name": "Authorized", + "value": "Autorizado" + }, + { + "name": "Charging_is_stopping", + "value": "La carga se está deteniendo" + }, + { + "name": "Waiting", + "value": "Esperando" + }, + { + "name": "Wait_in_line", + "value": "Espere en la fila" + }, + { + "name": "Wait_in_line_prompt", + "value": "Esperando a que otro conector comparta energía, la carga comenzará automáticamente cuando esté inactivo." + }, + { + "name": "Charging_time_and_cost", + "value": "Tiempo de carga y costo" + }, + { + "name": "Energy_delivered_and_charging_rate", + "value": "Energía entregada y tarifa de carga" + }, + { + "name": "State_of_charge", + "value": "Estado de carga" + }, + { + "name": "Balanced_chargers", + "value": "Cargadores equilibrados" + }, + { + "name": "Terms_of_use", + "value": "Términos de uso" + }, + { + "name": "prompt_help1", + "value": "Para carga rápida al alcance de su mano, por favor descargue la aplicación Ioc." + }, + { + "name": "content_help2", + "value": "No se pudo iniciar la carga. Por favor, asegúrese de que su vehículo esté conectado correctamente. No se ha cargado su crédito. Para iniciar una nueva sesión de carga, por favor reconecte." + }, + { + "name": "Close", + "value": "Cerrar" + }, + { + "name": "Back", + "value": "Volver" + }, + { + "name": "Authorization_failed", + "value": "Autorización fallida" + }, + { + "name": "Reason_for_failure", + "value": "Razón de la falla" + }, + { + "name": "Scan_for_bill", + "value": "Escanear para factura" + }, + { + "name": "Scan_for_receipt", + "value": "Escanear para recibo" + }, + { + "name": "Please_enter_the_amount", + "value": "Por favor ingrese el monto" + }, + { + "name": "Confirm", + "value": "Confirmar" + }, + { + "name": "Suspend", + "value": "Suspender" + }, + { + "name": "Charging_suspend", + "value": "Carga suspendida" + }, + { + "name": "Detailed_data", + "value": "Données détaillées" + }, + { + "name": "Run_State", + "value": "Estado de ejecución" + }, + { + "name": "Sub_State", + "value": "Estado secundario" + }, + { + "name": "Error_Code", + "value": "Código de error" + }, + { + "name": "Conn_Status", + "value": "Estado del conector" + }, + { + "name": "Start_SoC", + "value": "Iniciar SoC" + }, + { + "name": "Request_Voltage", + "value": "Solicitar voltaje" + }, + { + "name": "Request_Current", + "value": "Solicitar corriente" + }, + { + "name": "Offer_Voltage", + "value": "Oferta voltaje" + }, + { + "name": "Offer_Current", + "value": "Oferta corriente" + }, + { + "name": "Output_Limit", + "value": "Límite de salida" + }, + { + "name": "Comp_Group", + "value": "Grupo de módulos" + }, + { + "name": "Conn_Temperature", + "value": "Temperatura del conector" + }, + { + "name": "Output_Voltage", + "value": "Voltaje de salida" + }, + { + "name": "Output_Current", + "value": "Corriente de salida" + }, + { + "name": "Processing", + "value": "Procesando" + }, + { + "name": "Processing_prompt", + "value": "Puede tardar unos minutos" + }, + { + "name": "Downloading", + "value": "Descargando" + }, + { + "name": "Installing", + "value": "Instalando" + }, + { + "name": "No connector selected", + "value": "Ningún conector seleccionado" + }, + { + "name": "Failed to start charging", + "value": "No se pudo iniciar la carga" + }, + { + "name": "Fault found, Stop Charging", + "value": "Fallo encontrado. Dejar de cargar" + }, + { + "name": "Please start charging within 1 minutes for connector 1th", + "value": "Por favor, comience a cargar en 1 minuto para el conector 1" + }, + { + "name": "Please start charging within 1 minutes for connector 2th", + "value": "Por favor, comience a cargar en 1 minuto para el conector 2." + }, + { + "name": "Please start charging within 1 minutes for connector 3th", + "value": "Por favor, comience a cargar en 1 minuto para el conector 3." + }, + { + "name": "Please start charging within 1 minutes for connector 4th", + "value": "Por favor, comience a cargar en 1 minuto para el conector 4." + }, + { + "name": "Please start charging within 1 minutes", + "value": "Por favor, comience a cargar en 1 minuto" + }, + { + "name": "Not Permit", + "value": "No permitido" + }, + { + "name": "Swipe, insert or tap your card on the POS", + "value": "Pase, inserte o toque su tarjeta en el POS" + }, + { + "name": "pre-authorization failed", + "value": "preautorización fallida" + }, + { + "name": "Pre-Authorization Settled", + "value": "Preautorización resuelta" + }, + { + "name": "Payment failed", + "value": "Pago fallido" + }, + { + "name": "Payment Settled", + "value": "Pago liquidado" + }, + { + "name": "POS is processing the request, please wait", + "value": "POS está procesando la solicitud, espere" + }, + { + "name": "POS busy, please try again later", + "value": "Pos ocupado, inténtelo de nuevo más tarde" + }, + { + "name": "POS error, please contact the service", + "value": "Error de POS, comuníquese con el servicio" + }, + { + "name": "ERROR", + "value": "ERROR" + }, + { + "name": "Authorization Failed: Blocked", + "value": "Autorización fallida: bloqueado" + }, + { + "name": "Authorization Failed: Expired", + "value": "Autorización fallida: caducado" + }, + { + "name": "Authorization Failed: Invalid", + "value": "Autorización fallida: inválido" + }, + { + "name": "Authorization Failed: Concurrent TX", + "value": "Autorización fallida: transmisión simultánea" + }, + { + "name": "Authorization Failed: Other Reason", + "value": "Autorización fallida: otro motivo" + }, + { + "name": "Language", + "value": "Idioma" + } + ] +} diff --git a/assets/i18n/fi-FI.json b/assets/i18n/fi-FI.json new file mode 100644 index 000000000..a9ae2cf14 --- /dev/null +++ b/assets/i18n/fi-FI.json @@ -0,0 +1,527 @@ +{ + "name": "fi-FI", + "label": "Suomi", + "icon": "A:./assets/images/Finland.png", + "content": [ + { + "name": "Plug_in_frist", + "value": "Liitä ensin" + }, + { + "name": "home_prompt", + "value": "Liitä ensin latausnippu ajoneeleesi ennen uuden latauskauden aloittamista." + }, + { + "name": "qr_code_prompt", + "value": "Nopea lataus on helposti käsistäsi, lataa Ioc -sovellus." + }, + { + "name": "charger_station", + "value": "Latausaseman tunniste: " + }, + { + "name": "Idle", + "value": "Vapaa" + }, + { + "name": "Help", + "value": "Apua" + }, + { + "name": "conid", + "value": "Yhteyden tunniste: " + }, + { + "name": "Current_Period", + "value": "Nykyinen jakso" + }, + { + "name": "Next_Period", + "value": "Seuraava jakso" + }, + { + "name": "Starting", + "value": "Aloittaa" + }, + { + "name": "Scan_here_to_start_charging", + "value": "Skannaa tästä aloittaaksesi latauksen." + }, + { + "name": "starting_prompt", + "value": "Pääset käyttämään tuhansia latausasemia koko maassa. Käytä yhtä sovellusta päästäksesi kymmeniin latausverkkoihin." + }, + { + "name": "Charging", + "value": "Lataa" + }, + { + "name": "Power", + "value": "Teho" + }, + { + "name": "SoC", + "value": "Lataustila" + }, + { + "name": "Energy", + "value": "Energia" + }, + { + "name": "Duration", + "value": "Kesto" + }, + { + "name": "Estimated_Cost", + "value": "Arvioitu kustannus" + }, + { + "name": "Detailed_data", + "value": "Yksityiskohtainen tiedot" + }, + { + "name": "State of charge", + "value": "Lataustila" + }, + { + "name": "Finished", + "value": "Päättynyt" + }, + { + "name": "Start_time", + "value": "Aloitusaika" + }, + { + "name": "Idle_time", + "value": "Keskitysaika" + }, + { + "name": "Idle_time_prompt", + "value": "Siirry autosi paikalta. 10 minuuttia kestänyt anteeksiantoperiodi on päättynyt." + }, + { + "name": "Charging_cost", + "value": "Latauskustannus" + }, + { + "name": "Idle_fee", + "value": "Keskitymismaksu" + }, + { + "name": "Total_Amount", + "value": "Kokonaismäärä" + }, + { + "name": "Reserved", + "value": "Varattu" + }, + { + "name": "Left", + "value": "Jäljellä" + }, + { + "name": "left", + "value": "jäljellä" + }, + { + "name": "Stopping", + "value": "Pysähtyy" + }, + { + "name": "Charging_session_error", + "value": "Latauskausi virhe" + }, + { + "name": "Error_code_session_error", + "value": "Virhekoodi:" + }, + { + "name": "session_error_prompt", + "value": "Lataus keskeytyi, irrota latausnippu. Aloittaaksesi uuden latauskauden, yhdistä uudelleen ja paina Jatka." + }, + { + "name": "Continue", + "value": "Jatka" + }, + { + "name": "Error", + "value": "Virhe" + }, + { + "name": "Charging_start_error", + "value": "Latauksen aloituskirjautuminen" + }, + { + "name": "start_error_prompt", + "value": "Krediittisi ei ole veloitettu. Aloittaaksesi uuden latauskauden, yhdistä uudelleen." + }, + { + "name": "Fault", + "value": "Vika" + }, + { + "name": "Equipment_failure", + "value": "Laitevika" + }, + { + "name": "Other_error", + "value": "Muu virhe: 07" + }, + { + "name": "Lock Failure", + "value": "Lukitusvirhe" + }, + { + "name": "EV Communication Error", + "value": "Auton kommunikointivirhe" + }, + { + "name": "Ground Failure", + "value": "Maavika" + }, + { + "name": "High Temperature", + "value": "Korkea lämpötila" + }, + { + "name": "Internal Error", + "value": "Sisäinen virhe" + }, + { + "name": "Over Current", + "value": "Ylivirta" + }, + { + "name": "Over Voltage", + "value": "Ylijännite" + }, + { + "name": "Meter Failure", + "value": "Mittarivika" + }, + { + "name": "Power Switch Failure", + "value": "Virtakytkimen vika" + }, + { + "name": "Reader Failure", + "value": "Lukijan vika" + }, + { + "name": "Reset Failure", + "value": "Vian kuittaus" + }, + { + "name": "Under Voltage", + "value": "Alijännite" + }, + { + "name": "Weak Signal", + "value": "Heikko signaali" + }, + { + "name": "Emergency Pushed", + "value": "Hätäseis painettu" + }, + { + "name": "PhaseSwap Failure", + "value": "Vaihejärjestysvika" + }, + { + "name": "Other Error", + "value": "Muu virhe" + }, + { + "name": "Door Opened", + "value": "ovi on auki" + }, + { + "name": "MCCB Opened", + "value": "MCCB-kytkin avattu" + }, + { + "name": "fault_prompt", + "value": "Ole hyvä ja ota yhteyttä huoltotyöntekijöihin." + }, + { + "name": "Unavailable", + "value": "Ei saatavilla" + }, + { + "name": "Out_of_service", + "value": "Palvelu ei käytettävissä" + }, + { + "name": "unavailable_prompt", + "value": "Valitettavasti tämä latausasema ei ole käytettävissä. Tarkista Ioc -sovellus löytääksesi lähellä olevan latausaseman tai ota yhteyttä asiakaspalveluun." + }, + { + "name": "Plug & Charge", + "value": "Plug & Charge" + }, + { + "name": "connecting_prompt", + "value": "tai AutoCharge käynnistyy..." + }, + { + "name": "Authorized", + "value": "Valtuutettu" + }, + { + "name": "Charging_is_stopping", + "value": "Lataus keskeytyy" + }, + { + "name": "Waiting", + "value": "Odotetaan" + }, + { + "name": "Wait_in_line", + "value": "Odotusjonossa" + }, + { + "name": "Wait_in_line_prompt", + "value": "Odotetaan toista latausnippua jaettavan vahvistuksen, lataus käynnistyy automaattisesti vapaana oleva." + }, + { + "name": "Charging_time_and_cost", + "value": "Latausaika ja kustannukset" + }, + { + "name": "Energy_delivered_and_charging_rate", + "value": "Toimitettu energia ja latausnopeus" + }, + { + "name": "State_of_charge", + "value": "Lataustila" + }, + { + "name": "Balanced_chargers", + "value": "Tasapainotetut latajat" + }, + { + "name": "Terms_of_use", + "value": "Käyttöehdot" + }, + { + "name": "prompt_help1", + "value": "Nopea lataus on helposti käsistäsi, lataa Ioc -sovellus." + }, + { + "name": "content_help2", + "value": "Latausta ei voitu aloittaa. Varmista, että ajoneelasi on kytketty oikein. Krediittisi ei ole veloitettu. Aloittaaksesi uuden latauskauden, yhdistä uudelleen." + }, + { + "name": "Close", + "value": "Sulje" + }, + { + "name": "Back", + "value": "Takaisin" + }, + { + "name": "Authorization_failed", + "value": "Valtuutus epäonnistui" + }, + { + "name": "Reason_for_failure", + "value": "Epäonnistumisen syy" + }, + { + "name": "Scan_for_bill", + "value": "Skannaa laskulle" + }, + { + "name": "Scan_for_receipt", + "value": "Skannaa kuitille" + }, + { + "name": "Please_enter_the_amount", + "value": "Anna määrä" + }, + { + "name": "Confirm", + "value": "Vahvista" + }, + { + "name": "Suspend", + "value": "Keskeytetään" + }, + { + "name": "Charging_suspend", + "value": "Latauksen keskeyttäminen" + }, + { + "name": "Detailed_data", + "value": "Yksityiskohtainen tiedot" + }, + { + "name": "Run_State", + "value": "Nykyinen tila" + }, + { + "name": "Sub_State", + "value": "Aliprosessi" + }, + { + "name": "Error_Code", + "value": "Virhekoodi" + }, + { + "name": "Conn_Status", + "value": "Kaapeleiden tila" + }, + { + "name": "Start_SoC", + "value": "Aloita SoC lataus" + }, + { + "name": "Request_Voltage", + "value": "Pyydetty jännite" + }, + { + "name": "Request_Current", + "value": "Pyydetty virta" + }, + { + "name": "Offer_Voltage", + "value": "Syöttö jännite" + }, + { + "name": "Offer_Current", + "value": "Syöttö virta" + }, + { + "name": "Output_Limit", + "value": "Lähdön raja" + }, + { + "name": "Comp_Group", + "value": "Moduuliryhmä" + }, + { + "name": "Conn_Temperature", + "value": "Pistokkeen lämpötila" + }, + { + "name": "Output_Voltage", + "value": "Lähtöjännite" + }, + { + "name": "Output_Current", + "value": "Lähtövirta" + }, + { + "name": "Processing", + "value": "Käsitellään" + }, + { + "name": "Processing_prompt", + "value": "Tämä saattaa kestää muutaman minuutin" + }, + { + "name": "Downloading", + "value": "Lataa" + }, + { + "name": "Installing", + "value": "Asentaa" + }, + { + "name": "No connector selected", + "value": "Kaapelia ei ole valittu" + }, + { + "name": "Failed to start charging", + "value": "Latauksen aloittaminen epäonnistui" + }, + { + "name": "Fault found, Stop Charging", + "value": "Havaittu vika. Lataus lopetetaan" + }, + { + "name": "Please start charging within 1 minutes for connector 1th", + "value": "Aloita lataus 1 minuutin sisällä liittimelle 1" + }, + { + "name": "Please start charging within 1 minutes for connector 2th", + "value": "Aloita lataus 1 minuutin sisällä liittimelle 2." + }, + { + "name": "Please start charging within 1 minutes for connector 3th", + "value": "Aloita lataus 1 minuutin sisällä liittimelle 3." + }, + { + "name": "Please start charging within 1 minutes for connector 4th", + "value": "Aloita lataus 1 minuutin sisällä liittimelle 4." + }, + { + "name": "Please start charging within 1 minutes", + "value": "Aloita lataus 1 minuutin sisällä." + }, + { + "name": "Not Permit", + "value": "Ei lupaa" + }, + { + "name": "Swipe, insert or tap your card on the POS", + "value": "Pyyhkäise, aseta tai napauta korttiasi myyntipisteessä" + }, + { + "name": "pre-authorization failed", + "value": "ennakkolupa epäonnistui" + }, + { + "name": "Pre-Authorization Settled", + "value": "Ennakkoluulotus" + }, + { + "name": "Payment failed", + "value": "Maksu epäonnistui" + }, + { + "name": "Payment Settled", + "value": "Maksu suoritettu" + }, + { + "name": "POS is processing the request, please wait", + "value": "POS käsittelee pyyntöä, odota" + }, + { + "name": "POS busy, please try again later", + "value": "POS-kone on varattu, yritä myöhemmin uudelleen" + }, + { + "name": "POS error, please contact the service", + "value": "POS -koneen epäonnistuminen, ota yhteyttä henkilökuntaan" + }, + { + "name": "ERROR", + "value": "VIRHE" + }, + { + "name": "Authorization Failed: Blocked", + "value": "Valtuutus epäonnistui: Ei käytössä" + }, + { + "name": "Authorization Failed: Expired", + "value": "Valtuutus epäonnistui: Vanhentunut" + }, + { + "name": "Authorization Failed: Invalid", + "value": "Valtuutus epäonnistui: Virheellinen" + }, + { + "name": "Authorization Failed: Concurrent TX", + "value": "Valtuutus epäonnistui: Päällekkäinen veloitus" + }, + { + "name": "Authorization Failed: Other Reason", + "value": "Valtuutus epäonnistui: Muu syy" + }, + { + "name": "Language", + "value": "Kieli" + } + ] +} diff --git a/assets/i18n/fr-FR.json b/assets/i18n/fr-FR.json new file mode 100644 index 000000000..012c97d63 --- /dev/null +++ b/assets/i18n/fr-FR.json @@ -0,0 +1,527 @@ +{ + "name": "fr-FR", + "label": "Français", + "icon": "A:./assets/images/France.png", + "content": [ + { + "name": "Plug_in_frist", + "value": "Branchez d'abord" + }, + { + "name": "home_prompt", + "value": "Veuillez d'abord brancher le connecteur à votre véhicule avant de commencer une nouvelle session." + }, + { + "name": "qr_code_prompt", + "value": "Pour une recharge rapide à portée de main, téléchargez l’application Ioc." + }, + { + "name": "charger_station", + "value": "ID du chargeur : " + }, + { + "name": "Idle", + "value": "Ralenti" + }, + { + "name": "Help", + "value": "Aide" + }, + { + "name": "conid", + "value": "Identifiant du connecteur : " + }, + { + "name": "Current_Period", + "value": "période actuelle" + }, + { + "name": "Next_Period", + "value": "période suivante" + }, + { + "name": "Starting", + "value": "Départ" + }, + { + "name": "Scan_here_to_start_charging", + "value": "Scannez ici pour commencer la recharge" + }, + { + "name": "starting_prompt", + "value": "Accédez à des milliers de bornes de recharge à travers le pays.Utilisez une seule application pour accéder à des dizaines de réseaux de recharge." + }, + { + "name": "Charging", + "value": "Mise en charge" + }, + { + "name": "Power", + "value": "Puissance" + }, + { + "name": "SoC", + "value": "État de charge" + }, + { + "name": "Energy", + "value": "Énergie" + }, + { + "name": "Duration", + "value": "Durée" + }, + { + "name": "Estimated_Cost", + "value": "Coût estimé" + }, + { + "name": "Detailed_data", + "value": "Données détaillées" + }, + { + "name": "State of charge", + "value": "État de charge" + }, + { + "name": "Finished", + "value": "Ukonceno" + }, + { + "name": "Start_time", + "value": "Heure de début" + }, + { + "name": "Idle_time", + "value": "Temps d'inactivité" + }, + { + "name": "Idle_time_prompt", + "value": "Veuillez déplacer votre véhicule. La période de grâce de 10 minutes est dépassée." + }, + { + "name": "Charging_cost", + "value": "Coût de la recharge" + }, + { + "name": "Idle_fee", + "value": "Frais d'inactivité" + }, + { + "name": "Total_Amount", + "value": "Montant total" + }, + { + "name": "Reserved", + "value": "Réservé" + }, + { + "name": "Left", + "value": "Gauche" + }, + { + "name": "left", + "value": "rauche" + }, + { + "name": "Stopping", + "value": "Arrêt" + }, + { + "name": "Charging_session_error", + "value": "Erreur de session de recharge" + }, + { + "name": "Error_code_session_error", + "value": "Code d'erreur : " + }, + { + "name": "session_error_prompt", + "value": "La recharge a été interrompue, veuillez débrancher. Pour démarrer une nouvelle session de recharge, reconnectez et appuyez sur Continuer." + }, + { + "name": "Continue", + "value": "Continuer" + }, + { + "name": "Error", + "value": "Erreur" + }, + { + "name": "Charging_start_error", + "value": "Erreur de démarrage de la recharge" + }, + { + "name": "start_error_prompt", + "value": "Votre crédit n'a pas été débité. Pour démarrer une nouvelle session de recharge, veuillez reconnecter." + }, + { + "name": "Fault", + "value": "Faute" + }, + { + "name": "Equipment_failure", + "value": "Panne de l'équipement" + }, + { + "name": "Other_error", + "value": "Autre erreur : 07" + }, + { + "name": "Lock Failure", + "value": "Échec de verrouillage" + }, + { + "name": "EV Communication Error", + "value": "Erreur de communication EV" + }, + { + "name": "Ground Failure", + "value": "Défaillance à la terre" + }, + { + "name": "High Temperature", + "value": "Haute température" + }, + { + "name": "Internal Error", + "value": "Erreur interne" + }, + { + "name": "Over Current", + "value": "Plus de courant" + }, + { + "name": "Over Voltage", + "value": "Plus de Tension" + }, + { + "name": "Meter Failure", + "value": "Panne du compteur" + }, + { + "name": "Power Switch Failure", + "value": "Panne de l'interrupteur d'alimentation" + }, + { + "name": "Reader Failure", + "value": "Échec du lecteur" + }, + { + "name": "Reset Failure", + "value": "Échec de réinitialisation" + }, + { + "name": "Under Voltage", + "value": "Sous tension" + }, + { + "name": "Weak Signal", + "value": "Signal faible" + }, + { + "name": "Emergency Pushed", + "value": "Urgence poussée" + }, + { + "name": "PhaseSwap Failure", + "value": "Échec de PhaseSwap" + }, + { + "name": "Other Error", + "value": "Autre erreur" + }, + { + "name": "Door Opened", + "value": "la porte est ouverte" + }, + { + "name": "MCCB Opened", + "value": "Interrupteur MCCB ouvert" + }, + { + "name": "fault_prompt", + "value": "Veuillez contacter le personnel de maintenance." + }, + { + "name": "Unavailable", + "value": "Indisponible" + }, + { + "name": "Out_of_service", + "value": "Hors service" + }, + { + "name": "unavailable_prompt", + "value": "Malheureusement, ce chargeur est indisponible. Veuillez consulter l'application Ioc pour trouver un autre chargeur près de chez vous ou contacter le support client." + }, + { + "name": "Plug & Charge", + "value": "Brancher et charger" + }, + { + "name": "connecting_prompt", + "value": "ou démarrage de l'AutoCharge…" + }, + { + "name": "Authorized", + "value": "Autorisé" + }, + { + "name": "Charging_is_stopping", + "value": "La recharge est en cours d'arrêt" + }, + { + "name": "Waiting", + "value": "En attente" + }, + { + "name": "Wait_in_line", + "value": "Attendez votre tour" + }, + { + "name": "Wait_in_line_prompt", + "value": "En attente qu'un autre connecteur partage l'énergie, la recharge commencera automatiquement lorsqu'il sera inactif." + }, + { + "name": "Charging_time_and_cost", + "value": "Temps de recharge et coût" + }, + { + "name": "Energy_delivered_and_charging_rate", + "value": "Énergie délivrée et taux de recharge" + }, + { + "name": "State_of_charge", + "value": "État de charge" + }, + { + "name": "Balanced_chargers", + "value": "Chargeurs équilibrés" + }, + { + "name": "Terms_of_use", + "value": "Conditions d'utilisation" + }, + { + "name": "prompt_help1", + "value": "Pour une recharge rapide à portée de main, veuillez télécharger l'application Ioc." + }, + { + "name": "content_help2", + "value": "La recharge n'a pas pu être lancée. Veuillez vous assurer que votre véhicule est correctement branché. Votre crédit n'a pas été débité. Pour démarrer une nouvelle session de recharge, veuillez reconnecter." + }, + { + "name": "Close", + "value": "Fermer" + }, + { + "name": "Back", + "value": "Retour" + }, + { + "name": "Authorization_failed", + "value": "Échec de l'autorisation" + }, + { + "name": "Reason_for_failure", + "value": "Raison de l'échec" + }, + { + "name": "Scan_for_bill", + "value": "Scanner pour la facture" + }, + { + "name": "Scan_for_receipt", + "value": "Scanner pour le reçu" + }, + { + "name": "Please_enter_the_amount", + "value": "Veuillez saisir le montant" + }, + { + "name": "Confirm", + "value": "Confirmer" + }, + { + "name": "Suspend", + "value": "Suspendre" + }, + { + "name": "Charging_suspend", + "value": "Recharge suspendue" + }, + { + "name": "Detailed_data", + "value": "Données détaillées" + }, + { + "name": "Run_State", + "value": "État d'exécution" + }, + { + "name": "Sub_State", + "value": "Sous-état" + }, + { + "name": "Error_Code", + "value": "Code d'erreur" + }, + { + "name": "Conn_Status", + "value": "État du connecteur" + }, + { + "name": "Start_SoC", + "value": "Démarrez SoC" + }, + { + "name": "Request_Voltage", + "value": "Demande de tension" + }, + { + "name": "Request_Current", + "value": "Demande de courant" + }, + { + "name": "Offer_Voltage", + "value": "Tension d'offre" + }, + { + "name": "Offer_Current", + "value": "Courant d'offre" + }, + { + "name": "Output_Limit", + "value": "Limite de sortie" + }, + { + "name": "Comp_Group", + "value": "Groupe de modules" + }, + { + "name": "Conn_Temperature", + "value": "Température du connecteur" + }, + { + "name": "Output_Voltage", + "value": "Tension de sortie" + }, + { + "name": "Output_Current", + "value": "Courant de sortie" + }, + { + "name": "Processing", + "value": "Traitement en cours" + }, + { + "name": "Processing_prompt", + "value": "Cela peut prendre quelques minutes" + }, + { + "name": "Downloading", + "value": "Téléchargement" + }, + { + "name": "Installing", + "value": "Installation" + }, + { + "name": "No connector selected", + "value": "Aucun connecteur sélectionné" + }, + { + "name": "Failed to start charging", + "value": "Échec du démarrage de la charge" + }, + { + "name": "Fault found, Stop Charging", + "value": "Erreur détectée. Arrêter de charger" + }, + { + "name": "Please start charging within 1 minutes for connector 1th", + "value": "Veuillez commencer la charge dans 1 minute pour le connecteur 1." + }, + { + "name": "Please start charging within 1 minutes for connector 2th", + "value": "Veuillez commencer la charge dans 1 minute pour le connecteur 2." + }, + { + "name": "Please start charging within 1 minutes for connector 3th", + "value": "Veuillez commencer la charge dans 1 minute pour le connecteur 3." + }, + { + "name": "Please start charging within 1 minutes for connector 4th", + "value": "Veuillez commencer la charge dans 1 minute pour le connecteur 4." + }, + { + "name": "Please start charging within 1 minutes", + "value": "Veuillez commencer la charge dans 1 minute." + }, + { + "name": "Not Permit", + "value": "Pas permis" + }, + { + "name": "Swipe, insert or tap your card on the POS", + "value": "Glissez, insérez ou tapez votre carte sur le point de ven" + }, + { + "name": "pre-authorization failed", + "value": "la pré-autorisation a échoué" + }, + { + "name": "Pre-Authorization Settled", + "value": "Pré-autorisation réglée" + }, + { + "name": "Payment failed", + "value": "Paiement échoué" + }, + { + "name": "Payment Settled", + "value": "Paiement réglé" + }, + { + "name": "POS is processing the request, please wait", + "value": "Le point de vente traite la demande, veuillez patienter" + }, + { + "name": "POS busy, please try again later", + "value": "La machine POS est occupée, veuillez réessayer plus tard" + }, + { + "name": "POS error, please contact the service", + "value": "Échec de la machine POS, veuillez contacter le personnel" + }, + { + "name": "ERROR", + "value": "ERREUR" + }, + { + "name": "Authorization Failed: Blocked", + "value": "Échec de l'autorisation: bloqué" + }, + { + "name": "Authorization Failed: Expired", + "value": "Échec de l'autorisation: expiré" + }, + { + "name": "Authorization Failed: Invalid", + "value": "Échec de l'autorisation: non valide" + }, + { + "name": "Authorization Failed: Concurrent TX", + "value": "Échec de l'autorisation: émission simultanée" + }, + { + "name": "Authorization Failed: Other Reason", + "value": "Échec de l'autorisation: autre raison" + }, + { + "name": "Language", + "value": "Langue" + } + ] +} diff --git a/assets/i18n/it-IT.json b/assets/i18n/it-IT.json new file mode 100644 index 000000000..46c1950b3 --- /dev/null +++ b/assets/i18n/it-IT.json @@ -0,0 +1,527 @@ +{ + "name": "it-IT", + "label": "Italiano", + "icon": "A:./assets/images/Italy.png", + "content": [ + { + "name": "Plug_in_frist", + "value": "Collega prima" + }, + { + "name": "home_prompt", + "value": "Collega prima il connettore al veicolo prima di avviare una nuova sessione." + }, + { + "name": "qr_code_prompt", + "value": "Per una ricarica rapida a portata di mano, scarica l'app Ioc." + }, + { + "name": "charger_station", + "value": "ID del caricatore: " + }, + { + "name": "Idle", + "value": "Inattivo" + }, + { + "name": "Help", + "value": "Aiuto" + }, + { + "name": "conid", + "value": "ID del connettore: " + }, + { + "name": "Current_Period", + "value": "Periodo corrente" + }, + { + "name": "Next_Period", + "value": "Prossimo periodo" + }, + { + "name": "Starting", + "value": "Di partenza" + }, + { + "name": "Scan_here_to_start_charging", + "value": "Scansiona qui per iniziare la ricarica" + }, + { + "name": "starting_prompt", + "value": "Accedi a migliaia di stazioni di ricarica in tutto il paese. Usa un’unica app per accedere a decine di reti di ricarica." + }, + { + "name": "Charging", + "value": "Ricarica" + }, + { + "name": "Power", + "value": "Potere" + }, + { + "name": "SoC", + "value": "Stato di carica" + }, + { + "name": "Energy", + "value": "Energia" + }, + { + "name": "Duration", + "value": "Durata" + }, + { + "name": "Estimated_Cost", + "value": "Costo stimato" + }, + { + "name": "Detailed_data", + "value": "Dati dettagliati" + }, + { + "name": "State of charge", + "value": "Stato di carica" + }, + { + "name": "Finished", + "value": "Finito" + }, + { + "name": "Start_time", + "value": "Ora di inizio" + }, + { + "name": "Idle_time", + "value": "Tempo di inattività" + }, + { + "name": "Idle_time_prompt", + "value": "Si prega di spostare il veicolo. Il periodo di grazia di 10 minuti è scaduto." + }, + { + "name": "Charging_cost", + "value": "Costo di ricarica" + }, + { + "name": "Idle_fee", + "value": "Tariffa per inattività" + }, + { + "name": "Total_Amount", + "value": "Importo totale" + }, + { + "name": "Reserved", + "value": "Riservato" + }, + { + "name": "Left", + "value": "Sinistra" + }, + { + "name": "left", + "value": "restante" + }, + { + "name": "Stopping", + "value": "Fermarsi" + }, + { + "name": "Charging_session_error", + "value": "Errore nella sessione di ricarica" + }, + { + "name": "Error_code_session_error", + "value": "Codice errore: " + }, + { + "name": "session_error_prompt", + "value": "La ricarica è stata interrotta, si prega di scollegare. Per iniziare una nuova sessione di ricarica, ricollegare e premere Continua." + }, + { + "name": "Continue", + "value": "Continua" + }, + { + "name": "Error", + "value": "Errore" + }, + { + "name": "Charging_start_error", + "value": "Errore nell’avvio della ricarica" + }, + { + "name": "start_error_prompt", + "value": "Il tuo credito non è stato addebitato. Per avviare una nuova sessione di ricarica, riconnetti il dispositivo." + }, + { + "name": "Fault", + "value": "Colpa" + }, + { + "name": "Equipment_failure", + "value": "Guasto all’apparecchiatura" + }, + { + "name": "Other_error", + "value": "Altro errore: 07" + }, + { + "name": "Lock Failure", + "value": "Blocco fallito" + }, + { + "name": "EV Communication Error", + "value": "Errore di comunicazione EV" + }, + { + "name": "Ground Failure", + "value": "Mancanza di terra" + }, + { + "name": "High Temperature", + "value": "Alta temperatura" + }, + { + "name": "Internal Error", + "value": "Errore interno" + }, + { + "name": "Over Current", + "value": "Sopra la corrente" + }, + { + "name": "Over Voltage", + "value": "Sopra la Voltaggio" + }, + { + "name": "Meter Failure", + "value": "Guasto del misuratore" + }, + { + "name": "Power Switch Failure", + "value": "Guasto dell'interruttore di alimentazione" + }, + { + "name": "Reader Failure", + "value": "Errore del lettore" + }, + { + "name": "Reset Failure", + "value": "Ripristina errore" + }, + { + "name": "Under Voltage", + "value": "Sotto Voltaggio" + }, + { + "name": "Weak Signal", + "value": "Segnale debole" + }, + { + "name": "Emergency Pushed", + "value": "Emergenza spinta" + }, + { + "name": "PhaseSwap Failure", + "value": "Errore di PhaseSwap" + }, + { + "name": "Other Error", + "value": "Altro errore" + }, + { + "name": "Door Opened", + "value": "la porta è aperta" + }, + { + "name": "MCCB Opened", + "value": "Interruttore MCCB aperto" + }, + { + "name": "fault_prompt", + "value": "Si prega di contattare il personale di manutenzione." + }, + { + "name": "Unavailable", + "value": "Non disponibile" + }, + { + "name": "Out_of_service", + "value": "Fuori servizio" + }, + { + "name": "unavailable_prompt", + "value": "Sfortunatamente, questo caricatore non è disponibile. Controlla l’app Ioc per trovare un altro caricatore vicino a te o contatta il servizio clienti." + }, + { + "name": "Plug & Charge", + "value": "Collega e ricarica" + }, + { + "name": "connecting_prompt", + "value": "oppure Avvio AutoCarica…" + }, + { + "name": "Authorized", + "value": "Autorizzato" + }, + { + "name": "Charging_is_stopping", + "value": "La ricarica si sta interrompendo" + }, + { + "name": "Waiting", + "value": "In attesa" + }, + { + "name": "Wait_in_line", + "value": "Attendere in fila" + }, + { + "name": "Wait_in_line_prompt", + "value": "In attesa che un altro connettore condivida energia, la ricarica inizierà automaticamente quando inattivo." + }, + { + "name": "Charging_time_and_cost", + "value": "Tempo di ricarica e costo" + }, + { + "name": "Energy_delivered_and_charging_rate", + "value": "Energia erogata e tariffa di ricarica" + }, + { + "name": "State_of_charge", + "value": "Stato di carica" + }, + { + "name": "Balanced_chargers", + "value": "Caricatori bilanciati" + }, + { + "name": "Terms_of_use", + "value": "Termini di utilizzo" + }, + { + "name": "prompt_help1", + "value": "Per una ricarica rapida a portata di mano, scarica l’app Ioc." + }, + { + "name": "content_help2", + "value": "Impossibile avviare la ricarica. Assicurati che il veicolo sia correttamente collegato. Il tuo credito non è stato addebitato. Per avviare una nuova sessione di ricarica, riconnetti il dispositivo." + }, + { + "name": "Close", + "value": "Chiudi" + }, + { + "name": "Back", + "value": "Indietro" + }, + { + "name": "Authorization_failed", + "value": "Autorizzazione non riuscita" + }, + { + "name": "Reason_for_failure", + "value": "Motivo del guasto" + }, + { + "name": "Scan_for_bill", + "value": "Scansiona per la fattura" + }, + { + "name": "Scan_for_receipt", + "value": "Scansiona per la ricevuta" + }, + { + "name": "Please_enter_the_amount", + "value": "Inserisci l’importo" + }, + { + "name": "Confirm", + "value": "Conferma" + }, + { + "name": "Suspend", + "value": "Sospendere" + }, + { + "name": "Charging_suspend", + "value": "Ricarica sospesa" + }, + { + "name": "Detailed_data", + "value": "Dati dettagliati" + }, + { + "name": "Run_State", + "value": "Stato di esecuzione" + }, + { + "name": "Sub_State", + "value": "Stato secondario" + }, + { + "name": "Error_Code", + "value": "Codice di errore" + }, + { + "name": "Conn_Status", + "value": "Stato connettore" + }, + { + "name": "Start_SoC", + "value": "Stato connettore" + }, + { + "name": "Request_Voltage", + "value": "Richiedi Voltaggio" + }, + { + "name": "Request_Current", + "value": "Richiedi Corrente" + }, + { + "name": "Offer_Voltage", + "value": "Voltaggio offerta" + }, + { + "name": "Offer_Current", + "value": "Corrente offerta" + }, + { + "name": "Output_Limit", + "value": "Limite di uscita" + }, + { + "name": "Comp_Group", + "value": "Gruppo di moduli" + }, + { + "name": "Conn_Temperature", + "value": "Temperatura del connettore" + }, + { + "name": "Output_Voltage", + "value": "Voltaggio di uscita" + }, + { + "name": "Output_Current", + "value": "Corrente di uscita" + }, + { + "name": "Processing", + "value": "Elaborazione in corso" + }, + { + "name": "Processing_prompt", + "value": "Potrebbe richiedere alcuni minuti" + }, + { + "name": "Downloading", + "value": "Download in corso" + }, + { + "name": "Installing", + "value": "Installazione" + }, + { + "name": "No connector selected", + "value": "Nessun connettore selezionato" + }, + { + "name": "Failed to start charging", + "value": "Impossibile avviare la ricarica" + }, + { + "name": "Fault found, Stop Charging", + "value": "Difetto riscontrato. Interrompi la ricarica" + }, + { + "name": "Please start charging within 1 minutes for connector 1th", + "value": "Per favore, inizia a caricare entro 1 minuto per il connettore 1" + }, + { + "name": "Please start charging within 1 minutes for connector 2th", + "value": "Per favore, inizia a caricare entro 1 minuto per il connettore 2." + }, + { + "name": "Please start charging within 1 minutes for connector 3th", + "value": "Per favore, inizia a caricare entro 1 minuto per il connettore 3." + }, + { + "name": "Please start charging within 1 minutes for connector 4th", + "value": "Per favore, inizia a caricare entro 1 minuto per il connettore 4." + }, + { + "name": "Please start charging within 1 minutes", + "value": "Per favore, inizia a caricare entro 1 minuto." + }, + { + "name": "Not Permit", + "value": "Non permesso" + }, + { + "name": "Swipe, insert or tap your card on the POS", + "value": "Scorri, inserisci o tocca la tua carta sul POS" + }, + { + "name": "pre-authorization failed", + "value": "pre-autorizzazione fallita" + }, + { + "name": "Pre-Authorization Settled", + "value": "Pre-autorizzazione regolata" + }, + { + "name": "Payment failed", + "value": "Pagamento fallito" + }, + { + "name": "Payment Settled", + "value": "Pagamento saldato" + }, + { + "name": "POS is processing the request, please wait", + "value": "Il POS sta elaborando la richiesta, attendere" + }, + { + "name": "POS busy, please try again later", + "value": "Pos occupato, riprova più tardi" + }, + { + "name": "POS error, please contact the service", + "value": "Errore POS, si prega di contattare il servizio" + }, + { + "name": "ERROR", + "value": "ERRORE" + }, + { + "name": "Authorization Failed: Blocked", + "value": "Autorizzazione non riuscita: bloccata" + }, + { + "name": "Authorization Failed: Expired", + "value": "Autorizzazione non riuscita: scaduta" + }, + { + "name": "Authorization Failed: Invalid", + "value": "Autorizzazione non riuscita: non valida" + }, + { + "name": "Authorization Failed: Concurrent TX", + "value": "Autorizzazione non riuscita: TX simultanea" + }, + { + "name": "Authorization Failed: Other Reason", + "value": "Autorizzazione non riuscita: altro motivo" + }, + { + "name": "Language", + "value": "Lingua" + } + ] +} diff --git a/assets/i18n/nl-NL.json b/assets/i18n/nl-NL.json new file mode 100644 index 000000000..32f815226 --- /dev/null +++ b/assets/i18n/nl-NL.json @@ -0,0 +1,527 @@ +{ + "name": "nl-NL", + "label": "Nederlands", + "icon": "A:./assets/images/Netherlands.png", + "content": [ + { + "name": "Plug_in_frist", + "value": "Steek eerst in" + }, + { + "name": "home_prompt", + "value": "Steek eerst de stekker in uw voertuig voordat u een nieuwe sessie start." + }, + { + "name": "qr_code_prompt", + "value": "Voor snelle oplading binnen handbereik, download dan de Ioc APP." + }, + { + "name": "charger_station", + "value": "Lader-id: " + }, + { + "name": "Idle", + "value": "Inactief" + }, + { + "name": "Help", + "value": "Help" + }, + { + "name": "conid", + "value": "Connector-id: " + }, + { + "name": "Current_Period", + "value": "Huidige periode" + }, + { + "name": "Next_Period", + "value": "Volgende periode" + }, + { + "name": "Starting", + "value": "Start" + }, + { + "name": "Scan_here_to_start_charging", + "value": "Scan hier om te beginnen met laden." + }, + { + "name": "starting_prompt", + "value": "Toegang tot duizenden oplaadstations over het hele land. Gebruik één app om toegang te krijgen tot tientallen oplade-netwerken." + }, + { + "name": "Charging", + "value": "Opladen" + }, + { + "name": "Power", + "value": "Stroom" + }, + { + "name": "SoC", + "value": "Ladevervang" + }, + { + "name": "Energy", + "value": "Energie" + }, + { + "name": "Duration", + "value": "Looptijd" + }, + { + "name": "Estimated_Cost", + "value": "Geschatte kosten" + }, + { + "name": "Detailed_data", + "value": "Uitgebreide gegevens" + }, + { + "name": "State of charge", + "value": "Ladevervang" + }, + { + "name": "Finished", + "value": "Voltooid" + }, + { + "name": "Start_time", + "value": "Starttijd" + }, + { + "name": "Idle_time", + "value": "Wachttijd" + }, + { + "name": "Idle_time_prompt", + "value": "Verplaats alstublieft uw voertuig. De 10-minuten gratieperiode is verstreken." + }, + { + "name": "Charging_cost", + "value": "Opladekosten" + }, + { + "name": "Idle_fee", + "value": "Wachtvergoeding" + }, + { + "name": "Total_Amount", + "value": "Totaalbedrag" + }, + { + "name": "Reserved", + "value": "Gereserveerd" + }, + { + "name": "Left", + "value": "Overgebleven" + }, + { + "name": "left", + "value": "overgebleven" + }, + { + "name": "Stopping", + "value": "Stoppen" + }, + { + "name": "Charging_session_error", + "value": "Oplade-sessie fout" + }, + { + "name": "Error_code_session_error", + "value": "Foutcode: " + }, + { + "name": "session_error_prompt", + "value": "De oplading is onderbroken, haal alstublieft de stekker eruit. Om een nieuwe oplade-sessie te starten, herverbind en druk op Verdergaan." + }, + { + "name": "Continue", + "value": "Verdergaan" + }, + { + "name": "Error", + "value": "Fout" + }, + { + "name": "Charging_start_error", + "value": "Oplade start fout" + }, + { + "name": "start_error_prompt", + "value": "Uw krediet is niet in rekening gebracht. Om een nieuwe oplade-sessie te starten, herverbind alstublieft." + }, + { + "name": "Fault", + "value": "Storing" + }, + { + "name": "Equipment_failure", + "value": "Apparaatstoring" + }, + { + "name": "Other_error", + "value": "Andere fout: 07" + }, + { + "name": "Lock Failure", + "value": "Fout bij vergrendelen" + }, + { + "name": "EV Communication Error", + "value": "EV-communicatiefout" + }, + { + "name": "Ground Failure", + "value": "Fout bij Aarden" + }, + { + "name": "High Temperature", + "value": "Hoge temperatuur" + }, + { + "name": "Internal Error", + "value": "Interne fout" + }, + { + "name": "Over Current", + "value": "Over Stroom" + }, + { + "name": "Over Voltage", + "value": "Over Spanning" + }, + { + "name": "Meter Failure", + "value": "Meter Defect" + }, + { + "name": "Power Switch Failure", + "value": "Defect stroomschakelaar" + }, + { + "name": "Reader Failure", + "value": "Fout bij Inlezen" + }, + { + "name": "Reset Failure", + "value": "Reset fout" + }, + { + "name": "Under Voltage", + "value": "Onderspanning" + }, + { + "name": "Weak Signal", + "value": "Zwak signaal" + }, + { + "name": "Emergency Pushed", + "value": "Status: Noodsituatie Ingedrukt" + }, + { + "name": "PhaseSwap Failure", + "value": "Verwisseling fout instellen Fase" + }, + { + "name": "Other Error", + "value": "Andere fou." + }, + { + "name": "Door Opened", + "value": "Deur geopend" + }, + { + "name": "MCCB Opened", + "value": "MCCB geopend" + }, + { + "name": "fault_prompt", + "value": "Neem alstublieft contact op met het onderhoudspersoneel." + }, + { + "name": "Unavailable", + "value": "Niet beschikb." + }, + { + "name": "Out_of_service", + "value": "Uit dienst" + }, + { + "name": "unavailable_prompt", + "value": "Helaas is deze oplader niet beschikbaar. Controleer de Ioc-app om een andere oplader in de buurt te vinden of neem contact op met de klantenservice." + }, + { + "name": "Plug & Charge", + "value": "Plug & Charge" + }, + { + "name": "connecting_prompt", + "value": "of Automatische oplading wordt gestart..." + }, + { + "name": "Authorized", + "value": "Geautoriseerd" + }, + { + "name": "Charging_is_stopping", + "value": "De oplading wordt gestopt" + }, + { + "name": "Waiting", + "value": "Wachten" + }, + { + "name": "Wait_in_line", + "value": "Wachten in de rij" + }, + { + "name": "Wait_in_line_prompt", + "value": "Wachten op een andere aansluiting om stroom te delen, de oplading zal automatisch starten als er geen gebruik wordt gemaakt." + }, + { + "name": "Charging_time_and_cost", + "value": "Opladetijd en kosten" + }, + { + "name": "Energy_delivered_and_charging_rate", + "value": "Geleverde energie en oplaadsnelheid" + }, + { + "name": "State_of_charge", + "value": "Ladevervang" + }, + { + "name": "Balanced_chargers", + "value": "Gebalanceerde opladers" + }, + { + "name": "Terms_of_use", + "value": "Gebruiksvoorwaarden" + }, + { + "name": "prompt_help1", + "value": "Voor snelle oplading binnen handbereik, download dan de Ioc APP." + }, + { + "name": "content_help2", + "value": "De oplading kon niet worden gestart. Controleer of uw voertuig correct is aangesloten. Uw krediet is niet in rekening gebracht. Om een nieuwe oplade-sessie te starten, herverbind alstublieft." + }, + { + "name": "Close", + "value": "Sluiten" + }, + { + "name": "Back", + "value": "Terug" + }, + { + "name": "Authorization_failed", + "value": "Autorisatie mislukt" + }, + { + "name": "Reason_for_failure", + "value": "Reden voor mislukking" + }, + { + "name": "Scan_for_bill", + "value": "Scannen voor factuur" + }, + { + "name": "Scan_for_receipt", + "value": "Scannen voor ontvangstbewijs" + }, + { + "name": "Please_enter_the_amount", + "value": "Voer alstublieft het bedrag in" + }, + { + "name": "Confirm", + "value": "Bevestigen" + }, + { + "name": "Suspend", + "value": "Opschorten" + }, + { + "name": "Charging_suspend", + "value": "Oplading onderbroken" + }, + { + "name": "Detailed_data", + "value": "Uitgebreide gegevens" + }, + { + "name": "Run_State", + "value": "Uitvoeringsstatus" + }, + { + "name": "Sub_State", + "value": "Sub-status" + }, + { + "name": "Error_Code", + "value": "Foutcode" + }, + { + "name": "Conn_Status", + "value": "Verbindgsstatus" + }, + { + "name": "Start_SoC", + "value": "SoC starten" + }, + { + "name": "Request_Voltage", + "value": "Aanvragen Voltage" + }, + { + "name": "Request_Current", + "value": "Aanvragen Stroom" + }, + { + "name": "Offer_Voltage", + "value": "Aanbod Voltage" + }, + { + "name": "Offer_Current", + "value": "Aanbod Stroom" + }, + { + "name": "Output_Limit", + "value": "Uitgangslimiet" + }, + { + "name": "Comp_Group", + "value": "Comp Groep" + }, + { + "name": "Conn_Temperature", + "value": "Verbindings Temp." + }, + { + "name": "Output_Voltage", + "value": "Uitgangs Voltage" + }, + { + "name": "Output_Current", + "value": "Uitgangsstroom" + }, + { + "name": "Processing", + "value": "Bezig met verwerken" + }, + { + "name": "Processing_prompt", + "value": "Het kan enkele minuten duren" + }, + { + "name": "Downloading", + "value": "Downloaden" + }, + { + "name": "Installing", + "value": "Installeren" + }, + { + "name": "No connector selected", + "value": "Geen connector geselecteerd" + }, + { + "name": "Failed to start charging", + "value": "Opladen niet gestart" + }, + { + "name": "Fault found, Stop Charging", + "value": "Fout gevonden, stop opladen" + }, + { + "name": "Please start charging within 1 minutes for connector 1th", + "value": "Begin alstublieft binnen 1 minuut met opladen voor connector 1." + }, + { + "name": "Please start charging within 1 minutes for connector 2th", + "value": "Begin alstublieft binnen 1 minuut met opladen voor connector 2." + }, + { + "name": "Please start charging within 1 minutes for connector 3th", + "value": "Begin alstublieft binnen 1 minuut met opladen voor connector 3." + }, + { + "name": "Please start charging within 1 minutes for connector 4th", + "value": "Begin alstublieft binnen 1 minuut met opladen voor connector 4." + }, + { + "name": "Please start charging within 1 minutes", + "value": "Begin alstublieft met opladen binnen 1 minuut." + }, + { + "name": "Not Permit", + "value": "Geen toestemming" + }, + { + "name": "Swipe, insert or tap your card on the POS", + "value": "Veeg, steek of tik met uw kaart op de POS" + }, + { + "name": "pre-authorization failed", + "value": "pre-autorisatie mislukt" + }, + { + "name": "Pre-Authorization Settled", + "value": "Pre-autorisatie afgehandeld" + }, + { + "name": "Payment failed", + "value": "Betaling mislukt" + }, + { + "name": "Payment Settled", + "value": "Betaling afgehandeld" + }, + { + "name": "POS is processing the request, please wait", + "value": "POS verwerkt de aanvraag, een ogenblik geduld a.u.b." + }, + { + "name": "POS busy, please try again later", + "value": "POS is bezet, probeer het later nog eens" + }, + { + "name": "POS error, please contact the service", + "value": "POS-fout, neem contact op met de service afdeling" + }, + { + "name": "ERROR", + "value": "FOUT" + }, + { + "name": "Authorization Failed: Blocked", + "value": "Autorisatie mislukt: Geblokkeerd" + }, + { + "name": "Authorization Failed: Expired", + "value": "Autorisatie mislukt: Verlopen" + }, + { + "name": "Authorization Failed: Invalid", + "value": "Autorisatie mislukt: Ongeldig" + }, + { + "name": "Authorization Failed: Concurrent TX", + "value": "Autorisatie mislukt: Niet Gelijktijdig" + }, + { + "name": "Authorization Failed: Other Reason", + "value": "Autorisatie mislukt: Andere reden" + }, + { + "name": "Language", + "value": "Taal" + } + ] +} diff --git a/assets/i18n/pt-PT.json b/assets/i18n/pt-PT.json new file mode 100644 index 000000000..186f75d00 --- /dev/null +++ b/assets/i18n/pt-PT.json @@ -0,0 +1,527 @@ +{ + "name": "pt-PT", + "label": "Português", + "icon": "A:./assets/images/Portugal.png", + "content": [ + { + "name": "Plug_in_frist", + "value": "Conecte primeiro" + }, + { + "name": "home_prompt", + "value": "Por favor, conecte o conector ao seu veículo antes de iniciar uma nova sessão." + }, + { + "name": "qr_code_prompt", + "value": "Para carregamento rápido ao seu alcance, baixe o aplicativo Ioc." + }, + { + "name": "charger_station", + "value": "ID do carregador: " + }, + { + "name": "Idle", + "value": "Ocioso" + }, + { + "name": "Help", + "value": "Ajuda" + }, + { + "name": "conid", + "value": "ID do conector: " + }, + { + "name": "Current_Period", + "value": "Período atual" + }, + { + "name": "Next_Period", + "value": "Próximo período" + }, + { + "name": "Starting", + "value": "Iniciando" + }, + { + "name": "Scan_here_to_start_charging", + "value": "Escaneie aqui para iniciar o carregamento" + }, + { + "name": "starting_prompt", + "value": "Acesse milhares de carregadores em todo o país. Use um único aplicativo para acessar dezenas de redes de carregamento." + }, + { + "name": "Charging", + "value": "Carregando" + }, + { + "name": "Power", + "value": "Poder" + }, + { + "name": "SoC", + "value": "Estado de carga" + }, + { + "name": "Energy", + "value": "Energia" + }, + { + "name": "Duration", + "value": "Duração" + }, + { + "name": "Estimated_Cost", + "value": "Custo estimado" + }, + { + "name": "Detailed_data", + "value": "Dados detalhados" + }, + { + "name": "State of charge", + "value": "Estado de carga" + }, + { + "name": "Finished", + "value": "Acabado" + }, + { + "name": "Start_time", + "value": "Hora de início" + }, + { + "name": "Idle_time", + "value": "Tempo de inatividade" + }, + { + "name": "Idle_time_prompt", + "value": "Por favor, mova seu veículo. O período de cortesia de 10 minutos foi excedido." + }, + { + "name": "Charging_cost", + "value": "Custo de carregamento" + }, + { + "name": "Idle_fee", + "value": "Taxa de inatividade" + }, + { + "name": "Total_Amount", + "value": "Valor total" + }, + { + "name": "Reserved", + "value": "Reservado" + }, + { + "name": "Left", + "value": "Esquerda" + }, + { + "name": "left", + "value": "esquerda" + }, + { + "name": "Stopping", + "value": "Parando" + }, + { + "name": "Charging_session_error", + "value": "Erro na sessão de carregamento" + }, + { + "name": "Error_code_session_error", + "value": "Código de erro: " + }, + { + "name": "session_error_prompt", + "value": "O carregamento foi interrompido, por favor desconecte. Para iniciar uma nova sessão de carregamento, reconecte e pressione Continuar." + }, + { + "name": "Continue", + "value": "Continuar" + }, + { + "name": "Error", + "value": "erro" + }, + { + "name": "Charging_start_error", + "value": "Erro ao iniciar o carregamento" + }, + { + "name": "start_error_prompt", + "value": "Seu crédito não foi cobrado. Para iniciar uma nova sessão de carregamento, reconecte por favor." + }, + { + "name": "Fault", + "value": "Culpa" + }, + { + "name": "Equipment_failure", + "value": "Falha no equipamento" + }, + { + "name": "Other_error", + "value": "Outro erro: 07" + }, + { + "name": "Lock Failure", + "value": "Falha de bloqueio" + }, + { + "name": "EV Communication Error", + "value": "Erro de comunicação EV" + }, + { + "name": "Ground Failure", + "value": "Falha de aterramento" + }, + { + "name": "High Temperature", + "value": "Temperatura alta" + }, + { + "name": "Internal Error", + "value": "Erro interno" + }, + { + "name": "Over Current", + "value": "Sobre corrente" + }, + { + "name": "Over Voltage", + "value": "Sobre Voltagem" + }, + { + "name": "Meter Failure", + "value": "Falha do medidor" + }, + { + "name": "Power Switch Failure", + "value": "Falha do interruptor de alimentação" + }, + { + "name": "Reader Failure", + "value": "Falha do leitor" + }, + { + "name": "Reset Failure", + "value": "Falha de reinicialização" + }, + { + "name": "Under Voltage", + "value": "Sob Voltagem" + }, + { + "name": "Weak Signal", + "value": "Sinal fraco" + }, + { + "name": "Emergency Pushed", + "value": "Empurrado de emergência" + }, + { + "name": "PhaseSwap Failure", + "value": "Falha de troca de fase" + }, + { + "name": "Other Error", + "value": "Outro Erro" + }, + { + "name": "Door Opened", + "value": "porta está aberta" + }, + { + "name": "MCCB Opened", + "value": "Disjuntor MCCB aberto" + }, + { + "name": "fault_prompt", + "value": "Por favor, entre em contato com a equipe de manutenção." + }, + { + "name": "Unavailable", + "value": "Indisponível" + }, + { + "name": "Out_of_service", + "value": "Fora de serviço" + }, + { + "name": "unavailable_prompt", + "value": "Infelizmente, este carregador não está disponível. Por favor, verifique o aplicativo Ioc para encontrar outro carregador próximo ou entre em contato com o suporte ao cliente." + }, + { + "name": "Plug & Charge", + "value": "Conectar e Carregar" + }, + { + "name": "connecting_prompt", + "value": "ou AutoCarga iniciando…" + }, + { + "name": "Authorized", + "value": "Autorizado" + }, + { + "name": "Charging_is_stopping", + "value": "O carregamento está sendo interrompido" + }, + { + "name": "Waiting", + "value": "Aguardando" + }, + { + "name": "Wait_in_line", + "value": "Aguarde na fila" + }, + { + "name": "Wait_in_line_prompt", + "value": "Aguardando outro conector compartilhar energia. O carregamento começará automaticamente quando o carregador estiver ocioso." + }, + { + "name": "Charging_time_and_cost", + "value": "Tempo de carregamento e custo" + }, + { + "name": "Energy_delivered_and_charging_rate", + "value": "Energia fornecida e taxa de carregamento" + }, + { + "name": "State_of_charge", + "value": "Estado de carga" + }, + { + "name": "Balanced_chargers", + "value": "Carregadores balanceados" + }, + { + "name": "Terms_of_use", + "value": "Termos de uso" + }, + { + "name": "prompt_help1", + "value": "Para carregamento rápido ao seu alcance, baixe o aplicativo Ioc." + }, + { + "name": "content_help2", + "value": "O carregamento não pôde ser iniciado. Por favor, certifique-se de que seu veículo está corretamente conectado. Seu crédito não foi cobrado. Para iniciar uma nova sessão de carregamento, reconecte." + }, + { + "name": "Close", + "value": "Fechar" + }, + { + "name": "Back", + "value": "Voltar" + }, + { + "name": "Authorization_failed", + "value": "Falha na autorização" + }, + { + "name": "Reason_for_failure", + "value": "Motivo da falha" + }, + { + "name": "Scan_for_bill", + "value": "Escanear para fatura" + }, + { + "name": "Scan_for_receipt", + "value": "Escanear para recibo" + }, + { + "name": "Please_enter_the_amount", + "value": "Por favor, insira o valor" + }, + { + "name": "Confirm", + "value": "Confirmar" + }, + { + "name": "Suspend", + "value": "Suspender" + }, + { + "name": "Charging_suspend", + "value": "Carregamento suspenso" + }, + { + "name": "Detailed_data", + "value": "Dados detalhados" + }, + { + "name": "Run_State", + "value": "Estado de execução" + }, + { + "name": "Sub_State", + "value": "Subestado" + }, + { + "name": "Error_Code", + "value": "Erro de código" + }, + { + "name": "Conn_Status", + "value": "Status do conector" + }, + { + "name": "Start_SoC", + "value": "Iniciar SoC" + }, + { + "name": "Request_Voltage", + "value": "Solicitar Voltagem" + }, + { + "name": "Request_Current", + "value": "Solicitar Corrente" + }, + { + "name": "Offer_Voltage", + "value": "Voltagem oferecida" + }, + { + "name": "Offer_Current", + "value": "Corrente oferecida" + }, + { + "name": "Output_Limit", + "value": "Limite de saída" + }, + { + "name": "Comp_Group", + "value": "Grupo de módulos" + }, + { + "name": "Conn_Temperature", + "value": "Temperatura do conector" + }, + { + "name": "Output_Voltage", + "value": "Voltagem de saída" + }, + { + "name": "Output_Current", + "value": "Corrente de saída" + }, + { + "name": "Processing", + "value": "Processando" + }, + { + "name": "Processing_prompt", + "value": "Isso pode levar alguns minutos" + }, + { + "name": "Downloading", + "value": "Baixando" + }, + { + "name": "Installing", + "value": "Instalando" + }, + { + "name": "No connector selected", + "value": "Nenhum conector selecionado" + }, + { + "name": "Failed to start charging", + "value": "Falha ao iniciar o carregamento" + }, + { + "name": "Fault found, Stop Charging", + "value": "Falha encontrada. Parar de carregar" + }, + { + "name": "Please start charging within 1 minutes for connector 1th", + "value": "Por favor, comece a carregar em 1 minuto para o conector 1." + }, + { + "name": "Please start charging within 1 minutes for connector 2th", + "value": "Por favor, comece a carregar em 1 minuto para o conector 2." + }, + { + "name": "Please start charging within 1 minutes for connector 3th", + "value": "Por favor, comece a carregar em 1 minuto para o conector 3." + }, + { + "name": "Please start charging within 1 minutes for connector 4th", + "value": "Por favor, comece a carregar em 1 minuto para o conector 4." + }, + { + "name": "Please start charging within 1 minutes", + "value": "Por favor, comece a carregar em 1 minuto." + }, + { + "name": "Not Permit", + "value": "Não Permitir" + }, + { + "name": "Swipe, insert or tap your card on the POS", + "value": "Deslize, insira ou toque seu cartão no PDV" + }, + { + "name": "pre-authorization failed", + "value": "falha na pré-autorização" + }, + { + "name": "Pre-Authorization Settled", + "value": "Pré autorização" + }, + { + "name": "Payment failed", + "value": "Pagamento falhou" + }, + { + "name": "Payment Settled", + "value": "Pagamento liquidado" + }, + { + "name": "POS is processing the request, please wait", + "value": "O PDV está processando a solicitação, aguarde" + }, + { + "name": "POS busy, please try again later", + "value": "POS está ocupado, tente novamente mais tarde" + }, + { + "name": "POS error, please contact the service", + "value": "Falha na máquina POS, entre em contato com a equipe" + }, + { + "name": "ERROR", + "value": "ERRO" + }, + { + "name": "Authorization Failed: Blocked", + "value": "Falha na autorização: bloqueada" + }, + { + "name": "Authorization Failed: Expired", + "value": "A autorização falhou: expirou" + }, + { + "name": "Authorization Failed: Invalid", + "value": "Falha na autorização: inválida" + }, + { + "name": "Authorization Failed: Concurrent TX", + "value": "Falha na autorização: TX simultânea" + }, + { + "name": "Authorization Failed: Other Reason", + "value": "A autorização falhou: outro motivo" + }, + { + "name": "Language", + "value": "Idioma" + } + ] +} diff --git a/assets/i18n/ru-RU.json b/assets/i18n/ru-RU.json new file mode 100644 index 000000000..a86b9c575 --- /dev/null +++ b/assets/i18n/ru-RU.json @@ -0,0 +1,527 @@ +{ + "name": "ru-RU", + "label": "Pусский", + "icon": "A:./assets/images/Russia.png", + "content": [ + { + "name": "Plug_in_frist", + "value": "Подключитесь сначала" + }, + { + "name": "home_prompt", + "value": "Пожалуйста, сначала подключите разъем к вашему транспортному средству перед началом новой сессии." + }, + { + "name": "qr_code_prompt", + "value": "Для быстрой зарядки у вас под рукой, пожалуйста, скачайте приложение Ioc." + }, + { + "name": "charger_station", + "value": "ID зарядного устройства: " + }, + { + "name": "Idle", + "value": "Свободно" + }, + { + "name": "Help", + "value": "Помощь" + }, + { + "name": "conid", + "value": "Идентификатор разъема: " + }, + { + "name": "Current_Period", + "value": "Текущий период" + }, + { + "name": "Next_Period", + "value": "Следующий период" + }, + { + "name": "Starting", + "value": "Запускается" + }, + { + "name": "Scan_here_to_start_charging", + "value": "Отсканируйте здесь, чтобы начать зарядку." + }, + { + "name": "starting_prompt", + "value": "Получите доступ к тысячам зарядных станций по всей стране.Используйте одно приложение для доступа к десяткам сетей зарядки." + }, + { + "name": "Charging", + "value": "Заряжается" + }, + { + "name": "Power", + "value": "Мощность" + }, + { + "name": "SoC", + "value": "Состояние заряда батареи" + }, + { + "name": "Energy", + "value": "Эл.энергия" + }, + { + "name": "Duration", + "value": "Время" + }, + { + "name": "Estimated_Cost", + "value": "Предполагаемая стоимость" + }, + { + "name": "Detailed_data", + "value": "Подробные данные" + }, + { + "name": "State of charge", + "value": "Уровень заряда (аккумулятора)" + }, + { + "name": "Finished", + "value": "Завершено" + }, + { + "name": "Start_time", + "value": "Время начала" + }, + { + "name": "Idle_time", + "value": "Время простоя" + }, + { + "name": "Idle_time_prompt", + "value": "Пожалуйста, уберите ваш автомобиль. Превышен льготный период в 10 минут." + }, + { + "name": "Charging_cost", + "value": "Стоимость зарядки" + }, + { + "name": "Idle_fee", + "value": "Плата за простой" + }, + { + "name": "Total_Amount", + "value": "Общая сумма" + }, + { + "name": "Reserved", + "value": "Зарезервировано" + }, + { + "name": "Left", + "value": "Осталось" + }, + { + "name": "left", + "value": "осталось" + }, + { + "name": "Stopping", + "value": "Останавливается" + }, + { + "name": "Charging_session_error", + "value": "Ошибка сессии зарядки" + }, + { + "name": "Error_code_session_error", + "value": "Код ошибки: " + }, + { + "name": "session_error_prompt", + "value": "Зарядка была прервана, пожалуйста, отключите разъем. Для начала новой сессии зарядки подключитесь заново и нажмите «Продолжить»." + }, + { + "name": "Continue", + "value": "Продолжить" + }, + { + "name": "Error", + "value": "Ошибка" + }, + { + "name": "Charging_start_error", + "value": "Ошибка запуска зарядки" + }, + { + "name": "start_error_prompt", + "value": "Ваши средства не были списаны. Чтобы начать новую сессию зарядки, пожалуйста, подключитесь снова.\n\n" + }, + { + "name": "Fault", + "value": "Ошибка" + }, + { + "name": "Equipment_failure", + "value": "Неисправность оборудования" + }, + { + "name": "Other_error", + "value": "Другая ошибка: 07" + }, + { + "name": "Lock Failure", + "value": "Ошибка блокировки" + }, + { + "name": "EV Communication Error", + "value": "Ошибка связи с авто" + }, + { + "name": "Ground Failure", + "value": "Ошибка соединения с землёй" + }, + { + "name": "High Temperature", + "value": "Защита от высокой температуры" + }, + { + "name": "Internal Error", + "value": "Внутренняя ошибка" + }, + { + "name": "Over Current", + "value": "Защита от высокого тока" + }, + { + "name": "Over Voltage", + "value": "Защита от перенапряжения" + }, + { + "name": "Meter Failure", + "value": "Ошибка измерителя" + }, + { + "name": "Power Switch Failure", + "value": "Ошибка переключателя питания" + }, + { + "name": "Reader Failure", + "value": "Ошибка считывателя" + }, + { + "name": "Reset Failure", + "value": "Ошибка сброса" + }, + { + "name": "Under Voltage", + "value": "Недостаточное напряжение" + }, + { + "name": "Weak Signal", + "value": "Слабый сигнал" + }, + { + "name": "Emergency Pushed", + "value": "Аварийный останов" + }, + { + "name": "PhaseSwap Failure", + "value": "Нарушение чередования фаз" + }, + { + "name": "Other Error", + "value": "Другая ошибка" + }, + { + "name": "Door Opened", + "value": "дверь открыта" + }, + { + "name": "MCCB Opened", + "value": "MCCB открыт" + }, + { + "name": "fault_prompt", + "value": "Пожалуйста, свяжитесь с обслуживающим персоналом." + }, + { + "name": "Unavailable", + "value": "Недоступно" + }, + { + "name": "Out_of_service", + "value": "Вне службы" + }, + { + "name": "unavailable_prompt", + "value": "К сожалению, это зарядное устройство недоступно. Пожалуйста, проверьте приложение Ioc, чтобы найти другое зарядное устройство рядом с вами, или свяжитесь со службой поддержки клиентов." + }, + { + "name": "Plug & Charge", + "value": "Подключи и заряжай" + }, + { + "name": "connecting_prompt", + "value": "или начинается автоматическая зарядка…" + }, + { + "name": "Authorized", + "value": "Авторизован" + }, + { + "name": "Charging_is_stopping", + "value": "Зарядка останавливается" + }, + { + "name": "Waiting", + "value": "Ожидание" + }, + { + "name": "Wait_in_line", + "value": "Ждите в очереди" + }, + { + "name": "Wait_in_line_prompt", + "value": "Ожидание другого разъема для совместного использования питания. Зарядка автоматически начнется, когда он освободится." + }, + { + "name": "Charging_time_and_cost", + "value": "Время зарядки и стоимость" + }, + { + "name": "Energy_delivered_and_charging_rate", + "value": "Переданная энергия и скорость зарядки" + }, + { + "name": "State_of_charge", + "value": "Уровень заряда" + }, + { + "name": "Balanced_chargers", + "value": "Балансировка зарядных устройств" + }, + { + "name": "Terms_of_use", + "value": "Условия использования" + }, + { + "name": "prompt_help1", + "value": "Для быстрой зарядки у вас под рукой, пожалуйста, скачайте приложение Ioc." + }, + { + "name": "content_help2", + "value": "Запуск зарядки невозможен. Пожалуйста, убедитесь, что ваш автомобиль правильно подключен. С вашего счета средства не списаны. Для начала новой сессии зарядки, пожалуйста, подключитесь заново.\n\n" + }, + { + "name": "Close", + "value": "Закрыть" + }, + { + "name": "Back", + "value": "Назад" + }, + { + "name": "Authorization_failed", + "value": "Ошибка авторизации" + }, + { + "name": "Reason_for_failure", + "value": "Причина ошибки" + }, + { + "name": "Scan_for_bill", + "value": "Сканируйте счет" + }, + { + "name": "Scan_for_receipt", + "value": "Сканируйте квитанцию" + }, + { + "name": "Please_enter_the_amount", + "value": "Пожалуйста, введите сумму" + }, + { + "name": "Confirm", + "value": "Подтвердить" + }, + { + "name": "Suspend", + "value": "Приостановить" + }, + { + "name": "Charging_suspend", + "value": "Зарядка приостановлена" + }, + { + "name": "Detailed_data", + "value": "Подробные данные" + }, + { + "name": "Run_State", + "value": "Состояние" + }, + { + "name": "Sub_State", + "value": "Подпроцесс" + }, + { + "name": "Error_Code", + "value": "Код ошибки" + }, + { + "name": "Conn_Status", + "value": "Статус коннектора" + }, + { + "name": "Start_SoC", + "value": "Уровень заряда" + }, + { + "name": "Request_Voltage", + "value": "Запрашиваемое напряжение" + }, + { + "name": "Request_Current", + "value": "Запрашиваемый ток" + }, + { + "name": "Offer_Voltage", + "value": "Предлагаемое напряжение" + }, + { + "name": "Offer_Current", + "value": "Предлагаемый ток" + }, + { + "name": "Output_Limit", + "value": "Выходное ограничение" + }, + { + "name": "Comp_Group", + "value": "Модуль" + }, + { + "name": "Conn_Temperature", + "value": "Температура разъема" + }, + { + "name": "Output_Voltage", + "value": "Выходное напряжение" + }, + { + "name": "Output_Current", + "value": "Выходной ток" + }, + { + "name": "Processing", + "value": "Обработка..." + }, + { + "name": "Processing_prompt", + "value": "Это может занять несколько минут." + }, + { + "name": "Downloading", + "value": "Загружается" + }, + { + "name": "Installing", + "value": "Устанавливается" + }, + { + "name": "No connector selected", + "value": "Не выбран кабель зарядки" + }, + { + "name": "Failed to start charging", + "value": "Не удалость начать зарядку" + }, + { + "name": "Fault found, Stop Charging", + "value": "Обнаружена ошибка. Остановите зарядку" + }, + { + "name": "Please start charging within 1 minutes for connector 1th", + "value": "Пожалуйста, начните зарядку в течение 1 минуты для разъема 1." + }, + { + "name": "Please start charging within 1 minutes for connector 2th", + "value": "Пожалуйста, начните зарядку в течение 1 минуты для разъема 2." + }, + { + "name": "Please start charging within 1 minutes for connector 3th", + "value": "Пожалуйста, начните зарядку в течение 1 минуты для разъема 3." + }, + { + "name": "Please start charging within 1 minutes for connector 4th", + "value": "Пожалуйста, начните зарядку в течение 1 минуты для разъема 4." + }, + { + "name": "Please start charging within 1 minutes", + "value": "Пожалуйста, начните зарядку в течение 1 минуты." + }, + { + "name": "Not Permit", + "value": "Не разрешено" + }, + { + "name": "Swipe, insert or tap your card on the POS", + "value": "Проведите, вставьте или коснитесь карты на POS" + }, + { + "name": "pre-authorization failed", + "value": "предварительная авторизация не удалась" + }, + { + "name": "Pre-Authorization Settled", + "value": "Предварительная ауаутризация" + }, + { + "name": "Payment failed", + "value": "Платеж не прошел" + }, + { + "name": "Payment Settled", + "value": "Оплата урегулирована" + }, + { + "name": "POS is processing the request, please wait", + "value": "POS обрабатывает запрос, пожалуйста, подождите" + }, + { + "name": "POS busy, please try again later", + "value": "POS занят, попробуйте еще раз позже" + }, + { + "name": "POS error, please contact the service", + "value": "FOS -affect, пожалуйста, свяжитесь с персоналом" + }, + { + "name": "ERROR", + "value": "ОШИБКА" + }, + { + "name": "Authorization Failed: Blocked", + "value": "Ошибка авторизации: заблокировано" + }, + { + "name": "Authorization Failed: Expired", + "value": "Ошибка авторизации: срок действия истек" + }, + { + "name": "Authorization Failed: Invalid", + "value": "Ошибка авторизации: неверные данные" + }, + { + "name": "Authorization Failed: Concurrent TX", + "value": "Ошибка авторизации: одновременная передача" + }, + { + "name": "Authorization Failed: Other Reason", + "value": "Ошибка авторизации: другая причина" + }, + { + "name": "Language", + "value": "Язык" + } + ] +} diff --git a/assets/images/0mk.py b/assets/images/0mk.py new file mode 100644 index 000000000..5131f8b6f --- /dev/null +++ b/assets/images/0mk.py @@ -0,0 +1,27 @@ +import os +import json +import glob + +def generate_json(): + images = [] + # 遍历当前目录下的所有PNG文件 + for png_file in glob.glob("*.png"): + # 获取文件名(不包括扩展名) + name = os.path.splitext(png_file)[0].lower().replace(" ", "-") + # 构建路径 + path = f"A:./assets/images/{png_file}" + # 添加到列表 + images.append({"name": name, "path": path}) + + # 构建最终的JSON结构 + json_data = {"images": images} + + # 打印JSON + print(json.dumps(json_data, indent=4)) + + # 可选:将JSON保存到文件 + with open("output.json", "w") as f: + json.dump(json_data, f, indent=4) + +if __name__ == "__main__": + generate_json() diff --git a/assets/images/4g_err.png b/assets/images/4g_err.png new file mode 100644 index 000000000..60768e60e Binary files /dev/null and b/assets/images/4g_err.png differ diff --git a/assets/images/4g_off.png b/assets/images/4g_off.png new file mode 100644 index 000000000..0fe98e0eb Binary files /dev/null and b/assets/images/4g_off.png differ diff --git a/assets/images/4g_on.png b/assets/images/4g_on.png new file mode 100644 index 000000000..b4325454f Binary files /dev/null and b/assets/images/4g_on.png differ diff --git a/assets/images/CCS2-DC.png b/assets/images/CCS2-DC.png new file mode 100644 index 000000000..d85034354 Binary files /dev/null and b/assets/images/CCS2-DC.png differ diff --git a/assets/images/CCS2-DC_1connect.png b/assets/images/CCS2-DC_1connect.png new file mode 100644 index 000000000..dbcb04689 Binary files /dev/null and b/assets/images/CCS2-DC_1connect.png differ diff --git a/assets/images/CCS2-DC_2connect.png b/assets/images/CCS2-DC_2connect.png new file mode 100644 index 000000000..2b145ee29 Binary files /dev/null and b/assets/images/CCS2-DC_2connect.png differ diff --git a/assets/images/CHADEMO.png b/assets/images/CHADEMO.png new file mode 100644 index 000000000..48ef86d95 Binary files /dev/null and b/assets/images/CHADEMO.png differ diff --git a/assets/images/CHADEMO_1connect.png b/assets/images/CHADEMO_1connect.png new file mode 100644 index 000000000..4b07c18aa Binary files /dev/null and b/assets/images/CHADEMO_1connect.png differ diff --git a/assets/images/CHADEMO_2connect.png b/assets/images/CHADEMO_2connect.png new file mode 100644 index 000000000..e7fc4e650 Binary files /dev/null and b/assets/images/CHADEMO_2connect.png differ diff --git a/assets/images/Czech Republic.png b/assets/images/Czech Republic.png new file mode 100644 index 000000000..78dc9e0f1 Binary files /dev/null and b/assets/images/Czech Republic.png differ diff --git a/assets/images/English.png b/assets/images/English.png new file mode 100644 index 000000000..bd655822a Binary files /dev/null and b/assets/images/English.png differ diff --git a/assets/images/Europe.png b/assets/images/Europe.png new file mode 100644 index 000000000..01e3d1ef9 Binary files /dev/null and b/assets/images/Europe.png differ diff --git a/assets/images/Europe_1connect.png b/assets/images/Europe_1connect.png new file mode 100644 index 000000000..ad12842c0 Binary files /dev/null and b/assets/images/Europe_1connect.png differ diff --git a/assets/images/Europe_2connect.png b/assets/images/Europe_2connect.png new file mode 100644 index 000000000..196574d5b Binary files /dev/null and b/assets/images/Europe_2connect.png differ diff --git a/assets/images/Finland.png b/assets/images/Finland.png new file mode 100644 index 000000000..187a1f4e3 Binary files /dev/null and b/assets/images/Finland.png differ diff --git a/assets/images/France.png b/assets/images/France.png new file mode 100644 index 000000000..a0017435d Binary files /dev/null and b/assets/images/France.png differ diff --git a/assets/images/GB-AC.png b/assets/images/GB-AC.png new file mode 100644 index 000000000..114e5f18d Binary files /dev/null and b/assets/images/GB-AC.png differ diff --git a/assets/images/GB-AC_1connect.png b/assets/images/GB-AC_1connect.png new file mode 100644 index 000000000..2c391f2a7 Binary files /dev/null and b/assets/images/GB-AC_1connect.png differ diff --git a/assets/images/GB-AC_2connect.png b/assets/images/GB-AC_2connect.png new file mode 100644 index 000000000..922eebe13 Binary files /dev/null and b/assets/images/GB-AC_2connect.png differ diff --git a/assets/images/GB-DC.png b/assets/images/GB-DC.png new file mode 100644 index 000000000..5c5ceb0f1 Binary files /dev/null and b/assets/images/GB-DC.png differ diff --git a/assets/images/GB-DC_1connect.png b/assets/images/GB-DC_1connect.png new file mode 100644 index 000000000..bc5d7cca1 Binary files /dev/null and b/assets/images/GB-DC_1connect.png differ diff --git a/assets/images/GB-DC_2connect.png b/assets/images/GB-DC_2connect.png new file mode 100644 index 000000000..e53b36b98 Binary files /dev/null and b/assets/images/GB-DC_2connect.png differ diff --git a/assets/images/GB-T-AC.png b/assets/images/GB-T-AC.png new file mode 100644 index 000000000..03c672be2 Binary files /dev/null and b/assets/images/GB-T-AC.png differ diff --git a/assets/images/GB-T-AC_1connect.png b/assets/images/GB-T-AC_1connect.png new file mode 100644 index 000000000..76b30ed3a Binary files /dev/null and b/assets/images/GB-T-AC_1connect.png differ diff --git a/assets/images/GB-T-AC_2connect.png b/assets/images/GB-T-AC_2connect.png new file mode 100644 index 000000000..7a5542991 Binary files /dev/null and b/assets/images/GB-T-AC_2connect.png differ diff --git a/assets/images/Germany.png b/assets/images/Germany.png new file mode 100644 index 000000000..0ec4daa2e Binary files /dev/null and b/assets/images/Germany.png differ diff --git a/assets/images/Hong Kong.png b/assets/images/Hong Kong.png new file mode 100644 index 000000000..ddbea693c Binary files /dev/null and b/assets/images/Hong Kong.png differ diff --git a/assets/images/Italy.png b/assets/images/Italy.png new file mode 100644 index 000000000..13d092afa Binary files /dev/null and b/assets/images/Italy.png differ diff --git a/assets/images/J1772.png b/assets/images/J1772.png new file mode 100644 index 000000000..b2b5477b9 Binary files /dev/null and b/assets/images/J1772.png differ diff --git a/assets/images/J1772_1connect.png b/assets/images/J1772_1connect.png new file mode 100644 index 000000000..ae59b6611 Binary files /dev/null and b/assets/images/J1772_1connect.png differ diff --git a/assets/images/J1772_2connect.png b/assets/images/J1772_2connect.png new file mode 100644 index 000000000..348288867 Binary files /dev/null and b/assets/images/J1772_2connect.png differ diff --git a/assets/images/LOGO.png b/assets/images/LOGO.png new file mode 100644 index 000000000..de8426837 Binary files /dev/null and b/assets/images/LOGO.png differ diff --git a/assets/images/LOGO_plug&charge_2.png b/assets/images/LOGO_plug&charge_2.png new file mode 100644 index 000000000..126d59643 Binary files /dev/null and b/assets/images/LOGO_plug&charge_2.png differ diff --git a/assets/images/Netherlands.png b/assets/images/Netherlands.png new file mode 100644 index 000000000..5982e8e57 Binary files /dev/null and b/assets/images/Netherlands.png differ diff --git a/assets/images/Parking diagram.png b/assets/images/Parking diagram.png new file mode 100644 index 000000000..4aa1a1d39 Binary files /dev/null and b/assets/images/Parking diagram.png differ diff --git a/assets/images/Poland.png b/assets/images/Poland.png new file mode 100644 index 000000000..d971b0a0f Binary files /dev/null and b/assets/images/Poland.png differ diff --git a/assets/images/Portugal.png b/assets/images/Portugal.png new file mode 100644 index 000000000..945269a47 Binary files /dev/null and b/assets/images/Portugal.png differ diff --git a/assets/images/Romania.png b/assets/images/Romania.png new file mode 100644 index 000000000..3c236d1ac Binary files /dev/null and b/assets/images/Romania.png differ diff --git a/assets/images/Russia.png b/assets/images/Russia.png new file mode 100644 index 000000000..e5bafa7fd Binary files /dev/null and b/assets/images/Russia.png differ diff --git a/assets/images/Spain.png b/assets/images/Spain.png new file mode 100644 index 000000000..f703134db Binary files /dev/null and b/assets/images/Spain.png differ diff --git a/assets/images/Thailand.png b/assets/images/Thailand.png new file mode 100644 index 000000000..fab34942f Binary files /dev/null and b/assets/images/Thailand.png differ diff --git a/assets/images/Turkey.png b/assets/images/Turkey.png new file mode 100644 index 000000000..e8dd275ec Binary files /dev/null and b/assets/images/Turkey.png differ diff --git a/assets/images/battery1.png b/assets/images/battery1.png new file mode 100644 index 000000000..ca3c42aca Binary files /dev/null and b/assets/images/battery1.png differ diff --git a/assets/images/battery2.png b/assets/images/battery2.png new file mode 100644 index 000000000..0f3a10c29 Binary files /dev/null and b/assets/images/battery2.png differ diff --git a/assets/images/battery3.png b/assets/images/battery3.png new file mode 100644 index 000000000..0905038b9 Binary files /dev/null and b/assets/images/battery3.png differ diff --git a/assets/images/battery4.png b/assets/images/battery4.png new file mode 100644 index 000000000..e2cfd4430 Binary files /dev/null and b/assets/images/battery4.png differ diff --git a/assets/images/bg_data display_Charging.png b/assets/images/bg_data display_Charging.png new file mode 100644 index 000000000..0c697ee82 Binary files /dev/null and b/assets/images/bg_data display_Charging.png differ diff --git a/assets/images/bg_data display_finished.png b/assets/images/bg_data display_finished.png new file mode 100644 index 000000000..321b797c3 Binary files /dev/null and b/assets/images/bg_data display_finished.png differ diff --git a/assets/images/btn_Virtual keyboard_delete.png b/assets/images/btn_Virtual keyboard_delete.png new file mode 100644 index 000000000..2ae1fe25f Binary files /dev/null and b/assets/images/btn_Virtual keyboard_delete.png differ diff --git a/assets/images/car.png b/assets/images/car.png new file mode 100644 index 000000000..a49dbcc0e Binary files /dev/null and b/assets/images/car.png differ diff --git a/assets/images/car1.png b/assets/images/car1.png new file mode 100644 index 000000000..ef0a34670 Binary files /dev/null and b/assets/images/car1.png differ diff --git a/assets/images/car2.png b/assets/images/car2.png new file mode 100644 index 000000000..ef0a34670 Binary files /dev/null and b/assets/images/car2.png differ diff --git a/assets/images/charging.gif b/assets/images/charging.gif new file mode 100644 index 000000000..9784e33b2 Binary files /dev/null and b/assets/images/charging.gif differ diff --git a/assets/images/hint map.png b/assets/images/hint map.png new file mode 100644 index 000000000..8d94f32ed Binary files /dev/null and b/assets/images/hint map.png differ diff --git a/assets/images/icon_Authorized.png b/assets/images/icon_Authorized.png new file mode 100644 index 000000000..f7f78550a Binary files /dev/null and b/assets/images/icon_Authorized.png differ diff --git a/assets/images/icon_Charging pile.png b/assets/images/icon_Charging pile.png new file mode 100644 index 000000000..b0499bdda Binary files /dev/null and b/assets/images/icon_Charging pile.png differ diff --git a/assets/images/icon_Charging station.png b/assets/images/icon_Charging station.png new file mode 100644 index 000000000..4ccdc3eaf Binary files /dev/null and b/assets/images/icon_Charging station.png differ diff --git a/assets/images/icon_Connected.png b/assets/images/icon_Connected.png new file mode 100644 index 000000000..1551b398d Binary files /dev/null and b/assets/images/icon_Connected.png differ diff --git a/assets/images/icon_Current time.png b/assets/images/icon_Current time.png new file mode 100644 index 000000000..3bbd909a9 Binary files /dev/null and b/assets/images/icon_Current time.png differ diff --git a/assets/images/icon_Loading.png b/assets/images/icon_Loading.png new file mode 100644 index 000000000..4ee71840d Binary files /dev/null and b/assets/images/icon_Loading.png differ diff --git a/assets/images/icon_Next period.png b/assets/images/icon_Next period.png new file mode 100644 index 000000000..1be902934 Binary files /dev/null and b/assets/images/icon_Next period.png differ diff --git a/assets/images/icon_Telephone.png b/assets/images/icon_Telephone.png new file mode 100644 index 000000000..a89d5d2ae Binary files /dev/null and b/assets/images/icon_Telephone.png differ diff --git a/assets/images/icon_URL.png b/assets/images/icon_URL.png new file mode 100644 index 000000000..dec54c417 Binary files /dev/null and b/assets/images/icon_URL.png differ diff --git a/assets/images/icon_contact.png b/assets/images/icon_contact.png new file mode 100644 index 000000000..05dbd204e Binary files /dev/null and b/assets/images/icon_contact.png differ diff --git a/assets/images/icon_error.png b/assets/images/icon_error.png new file mode 100644 index 000000000..375bec399 Binary files /dev/null and b/assets/images/icon_error.png differ diff --git a/assets/images/icon_inmation.png b/assets/images/icon_inmation.png new file mode 100644 index 000000000..567152032 Binary files /dev/null and b/assets/images/icon_inmation.png differ diff --git a/assets/images/icon_left connector.png b/assets/images/icon_left connector.png new file mode 100644 index 000000000..b9e9a4b23 Binary files /dev/null and b/assets/images/icon_left connector.png differ diff --git a/assets/images/icon_right connector.png b/assets/images/icon_right connector.png new file mode 100644 index 000000000..3199ddbb6 Binary files /dev/null and b/assets/images/icon_right connector.png differ diff --git a/assets/images/icon_stopping.png b/assets/images/icon_stopping.png new file mode 100644 index 000000000..767fe6f16 Binary files /dev/null and b/assets/images/icon_stopping.png differ diff --git a/assets/images/icon_warning_1.png b/assets/images/icon_warning_1.png new file mode 100644 index 000000000..da273dad2 Binary files /dev/null and b/assets/images/icon_warning_1.png differ diff --git a/assets/images/icon_warning_2.png b/assets/images/icon_warning_2.png new file mode 100644 index 000000000..4021e5120 Binary files /dev/null and b/assets/images/icon_warning_2.png differ diff --git a/assets/images/lang_Albania.png b/assets/images/lang_Albania.png new file mode 100644 index 000000000..19c44807f Binary files /dev/null and b/assets/images/lang_Albania.png differ diff --git a/assets/images/lang_Arab.png b/assets/images/lang_Arab.png new file mode 100644 index 000000000..4cdeba9c0 Binary files /dev/null and b/assets/images/lang_Arab.png differ diff --git a/assets/images/lang_China.png b/assets/images/lang_China.png new file mode 100644 index 000000000..2f4331fa5 Binary files /dev/null and b/assets/images/lang_China.png differ diff --git a/assets/images/meter_err.png b/assets/images/meter_err.png new file mode 100644 index 000000000..1538bc134 Binary files /dev/null and b/assets/images/meter_err.png differ diff --git a/assets/images/meter_off.png b/assets/images/meter_off.png new file mode 100644 index 000000000..c18a43e1e Binary files /dev/null and b/assets/images/meter_off.png differ diff --git a/assets/images/meter_on.png b/assets/images/meter_on.png new file mode 100644 index 000000000..8f5544026 Binary files /dev/null and b/assets/images/meter_on.png differ diff --git a/assets/images/net_err.png b/assets/images/net_err.png new file mode 100644 index 000000000..4c3925837 Binary files /dev/null and b/assets/images/net_err.png differ diff --git a/assets/images/net_off.png b/assets/images/net_off.png new file mode 100644 index 000000000..b44a873fb Binary files /dev/null and b/assets/images/net_off.png differ diff --git a/assets/images/net_on.png b/assets/images/net_on.png new file mode 100644 index 000000000..6a5d70c42 Binary files /dev/null and b/assets/images/net_on.png differ diff --git a/assets/images/output.json b/assets/images/output.json new file mode 100644 index 000000000..9d26593f4 --- /dev/null +++ b/assets/images/output.json @@ -0,0 +1,360 @@ +{ + "images": [ + { + "name": "sever_on", + "path": "A:./assets/images/sever_on.png" + }, + { + "name": "portugal", + "path": "A:./assets/images/Portugal.png" + }, + { + "name": "europe_2connect", + "path": "A:./assets/images/Europe_2connect.png" + }, + { + "name": "bg_data-display_finished", + "path": "A:./assets/images/bg_data display_finished.png" + }, + { + "name": "ccs2-dc_2connect", + "path": "A:./assets/images/CCS2-DC_2connect.png" + }, + { + "name": "icon_authorized", + "path": "A:./assets/images/icon_Authorized.png" + }, + { + "name": "turkey", + "path": "A:./assets/images/Turkey.png" + }, + { + "name": "france", + "path": "A:./assets/images/France.png" + }, + { + "name": "icon_error", + "path": "A:./assets/images/icon_error.png" + }, + { + "name": "italy", + "path": "A:./assets/images/Italy.png" + }, + { + "name": "j1772_2connect", + "path": "A:./assets/images/J1772_2connect.png" + }, + { + "name": "battery4", + "path": "A:./assets/images/battery4.png" + }, + { + "name": "icon_stopping", + "path": "A:./assets/images/icon_stopping.png" + }, + { + "name": "poland", + "path": "A:./assets/images/Poland.png" + }, + { + "name": "wifi_err", + "path": "A:./assets/images/wifi_err.png" + }, + { + "name": "icon_inmation", + "path": "A:./assets/images/icon_inmation.png" + }, + { + "name": "logo_plug&charge_2", + "path": "A:./assets/images/LOGO_plug&charge_2.png" + }, + { + "name": "english", + "path": "A:./assets/images/English.png" + }, + { + "name": "rf_err", + "path": "A:./assets/images/rf_err.png" + }, + { + "name": "sever_off", + "path": "A:./assets/images/sever_off.png" + }, + { + "name": "rf_on", + "path": "A:./assets/images/rf_on.png" + }, + { + "name": "btn_virtual-keyboard_delete", + "path": "A:./assets/images/btn_Virtual keyboard_delete.png" + }, + { + "name": "gb-ac_2connect", + "path": "A:./assets/images/GB-AC_2connect.png" + }, + { + "name": "icon_telephone", + "path": "A:./assets/images/icon_Telephone.png" + }, + { + "name": "gb-t-ac_1connect", + "path": "A:./assets/images/GB-T-AC_1connect.png" + }, + { + "name": "ccs2-dc", + "path": "A:./assets/images/CCS2-DC.png" + }, + { + "name": "germany", + "path": "A:./assets/images/Germany.png" + }, + { + "name": "icon_right-connector", + "path": "A:./assets/images/icon_right connector.png" + }, + { + "name": "icon_url", + "path": "A:./assets/images/icon_URL.png" + }, + { + "name": "gb-dc_1connect", + "path": "A:./assets/images/GB-DC_1connect.png" + }, + { + "name": "hong-kong", + "path": "A:./assets/images/Hong Kong.png" + }, + { + "name": "chademo", + "path": "A:./assets/images/CHADEMO.png" + }, + { + "name": "thailand", + "path": "A:./assets/images/Thailand.png" + }, + { + "name": "logo", + "path": "A:./assets/images/LOGO.png" + }, + { + "name": "romania", + "path": "A:./assets/images/Romania.png" + }, + { + "name": "bg_data-display_charging", + "path": "A:./assets/images/bg_data display_Charging.png" + }, + { + "name": "parking-diagram", + "path": "A:./assets/images/Parking diagram.png" + }, + { + "name": "meter_off", + "path": "A:./assets/images/meter_off.png" + }, + { + "name": "car2", + "path": "A:./assets/images/car2.png" + }, + { + "name": "europe", + "path": "A:./assets/images/Europe.png" + }, + { + "name": "battery1", + "path": "A:./assets/images/battery1.png" + }, + { + "name": "lang_china", + "path": "A:./assets/images/lang_China.png" + }, + { + "name": "4g_err", + "path": "A:./assets/images/4g_err.png" + }, + { + "name": "chademo_2connect", + "path": "A:./assets/images/CHADEMO_2connect.png" + }, + { + "name": "icon_current-time", + "path": "A:./assets/images/icon_Current time.png" + }, + { + "name": "icon_charging-station", + "path": "A:./assets/images/icon_Charging station.png" + }, + { + "name": "car", + "path": "A:./assets/images/car.png" + }, + { + "name": "icon_loading", + "path": "A:./assets/images/icon_Loading.png" + }, + { + "name": "gb-t-ac", + "path": "A:./assets/images/GB-T-AC.png" + }, + { + "name": "battery2", + "path": "A:./assets/images/battery2.png" + }, + { + "name": "gb-t-ac_2connect", + "path": "A:./assets/images/GB-T-AC_2connect.png" + }, + { + "name": "rf_off", + "path": "A:./assets/images/rf_off.png" + }, + { + "name": "icon_left-connector", + "path": "A:./assets/images/icon_left connector.png" + }, + { + "name": "wifi_off", + "path": "A:./assets/images/wifi_off.png" + }, + { + "name": "wifi_on", + "path": "A:./assets/images/wifi_on.png" + }, + { + "name": "pic_pos", + "path": "A:./assets/images/pic_pos.png" + }, + { + "name": "j1772", + "path": "A:./assets/images/J1772.png" + }, + { + "name": "net_err", + "path": "A:./assets/images/net_err.png" + }, + { + "name": "gb-ac_1connect", + "path": "A:./assets/images/GB-AC_1connect.png" + }, + { + "name": "hint-map", + "path": "A:./assets/images/hint map.png" + }, + { + "name": "j1772_1connect", + "path": "A:./assets/images/J1772_1connect.png" + }, + { + "name": "gb-ac", + "path": "A:./assets/images/GB-AC.png" + }, + { + "name": "icon_connected", + "path": "A:./assets/images/icon_Connected.png" + }, + { + "name": "meter_err", + "path": "A:./assets/images/meter_err.png" + }, + { + "name": "meter_on", + "path": "A:./assets/images/meter_on.png" + }, + { + "name": "ccs2-dc_1connect", + "path": "A:./assets/images/CCS2-DC_1connect.png" + }, + { + "name": "4g_on", + "path": "A:./assets/images/4g_on.png" + }, + { + "name": "battery3", + "path": "A:./assets/images/battery3.png" + }, + { + "name": "net_off", + "path": "A:./assets/images/net_off.png" + }, + { + "name": "icon_warning_1", + "path": "A:./assets/images/icon_warning_1.png" + }, + { + "name": "sever_err", + "path": "A:./assets/images/sever_err.png" + }, + { + "name": "netherlands", + "path": "A:./assets/images/Netherlands.png" + }, + { + "name": "lang_arab", + "path": "A:./assets/images/lang_Arab.png" + }, + { + "name": "finland", + "path": "A:./assets/images/Finland.png" + }, + { + "name": "icon_next-period", + "path": "A:./assets/images/icon_Next period.png" + }, + { + "name": "gb-dc_2connect", + "path": "A:./assets/images/GB-DC_2connect.png" + }, + { + "name": "chademo_1connect", + "path": "A:./assets/images/CHADEMO_1connect.png" + }, + { + "name": "net_on", + "path": "A:./assets/images/net_on.png" + }, + { + "name": "icon_contact", + "path": "A:./assets/images/icon_contact.png" + }, + { + "name": "lang_albania", + "path": "A:./assets/images/lang_Albania.png" + }, + { + "name": "spain", + "path": "A:./assets/images/Spain.png" + }, + { + "name": "icon_charging-pile", + "path": "A:./assets/images/icon_Charging pile.png" + }, + { + "name": "russia", + "path": "A:./assets/images/Russia.png" + }, + { + "name": "czech-republic", + "path": "A:./assets/images/Czech Republic.png" + }, + { + "name": "europe_1connect", + "path": "A:./assets/images/Europe_1connect.png" + }, + { + "name": "car1", + "path": "A:./assets/images/car1.png" + }, + { + "name": "icon_warning_2", + "path": "A:./assets/images/icon_warning_2.png" + }, + { + "name": "gb-dc", + "path": "A:./assets/images/GB-DC.png" + }, + { + "name": "4g_off", + "path": "A:./assets/images/4g_off.png" + } + ] +} \ No newline at end of file diff --git a/assets/images/pic_pos.png b/assets/images/pic_pos.png new file mode 100644 index 000000000..e64d6bbdd Binary files /dev/null and b/assets/images/pic_pos.png differ diff --git a/assets/images/processing.gif b/assets/images/processing.gif new file mode 100644 index 000000000..bbcedb90c Binary files /dev/null and b/assets/images/processing.gif differ diff --git a/assets/images/rf_err.png b/assets/images/rf_err.png new file mode 100644 index 000000000..21d99c5b7 Binary files /dev/null and b/assets/images/rf_err.png differ diff --git a/assets/images/rf_off.png b/assets/images/rf_off.png new file mode 100644 index 000000000..b83ed9c85 Binary files /dev/null and b/assets/images/rf_off.png differ diff --git a/assets/images/rf_on.png b/assets/images/rf_on.png new file mode 100644 index 000000000..fb7b7ffa0 Binary files /dev/null and b/assets/images/rf_on.png differ diff --git a/assets/images/sever_err.png b/assets/images/sever_err.png new file mode 100644 index 000000000..f25f12609 Binary files /dev/null and b/assets/images/sever_err.png differ diff --git a/assets/images/sever_off.png b/assets/images/sever_off.png new file mode 100644 index 000000000..c5ea9146f Binary files /dev/null and b/assets/images/sever_off.png differ diff --git a/assets/images/sever_on.png b/assets/images/sever_on.png new file mode 100644 index 000000000..86a5111e3 Binary files /dev/null and b/assets/images/sever_on.png differ diff --git a/assets/images/wifi_err.png b/assets/images/wifi_err.png new file mode 100644 index 000000000..02d1250a5 Binary files /dev/null and b/assets/images/wifi_err.png differ diff --git a/assets/images/wifi_off.png b/assets/images/wifi_off.png new file mode 100644 index 000000000..014b00ab1 Binary files /dev/null and b/assets/images/wifi_off.png differ diff --git a/assets/images/wifi_on.png b/assets/images/wifi_on.png new file mode 100644 index 000000000..ba31b590e Binary files /dev/null and b/assets/images/wifi_on.png differ diff --git a/assets/lanugage.json b/assets/lanugage.json new file mode 100644 index 000000000..34c9c3a77 --- /dev/null +++ b/assets/lanugage.json @@ -0,0 +1,12 @@ +[ + { + "namae" : "English", + "icon" : "A://assets/flag/english.png", + "text" : "English" + }, + { + "namae" : "Chinise", + "icon" : "A://assets/flag/chinise.png", + "text" : "简体中文" + } +] diff --git a/assets/layout/layout_000_welcome.json b/assets/layout/layout_000_welcome.json new file mode 100644 index 000000000..5abc68e45 --- /dev/null +++ b/assets/layout/layout_000_welcome.json @@ -0,0 +1,12 @@ +{ + "name": "welcome", + "desc": "欢迎界面, 加载JSON成功前显示", + "type": "flex", + "properties": { + "width": 800, + "height": 600, + "style": "bg-white" + }, + "children": [ + ] +} diff --git a/assets/layout/layout_001_popup_help1.json b/assets/layout/layout_001_popup_help1.json new file mode 100644 index 000000000..f6a992011 --- /dev/null +++ b/assets/layout/layout_001_popup_help1.json @@ -0,0 +1,68 @@ +{ + "name": "help1", + "desc": "help1弹窗", + "type": "flex", + "properties": { + "width": 660, + "height": 434, + "x": 70, + "y": 40, + "style": "style-help1-background" + }, + "children": [ + { + "name": "help1_title", + "desc": "帮助文本", + "type": "label", + "properties": { + "text": "Help", + "x_ofs": 0, + "y_ofs": 30, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_label" + } + }, + { + "name": "help1_split_line", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 582, + "height": 1, + "x": 40, + "y": 64, + "style": "style-split" + } + }, + { + "name": "help1_list", + "desc": "帮助信息列表", + "type": "list", + "properties": { + "x" : 44, + "y" : 89, + "width" : 372, + "height" : 260 + } + }, + { + "name": "help1_status_info", + "desc": "充电桩桩信息", + "type": "fragment", + "fragment_name": "fragment_popup_help1_status", + "properties": { + "x": 430, + "y": 74 + } + }, + { + "name": "help1_close_button", + "type": "fragment", + "fragment_name" : "fragment_btn_primary", + "properties": { + "x": 230, + "y": 364 + } + } + ] +} diff --git a/assets/layout/layout_002_popup_help2.json b/assets/layout/layout_002_popup_help2.json new file mode 100644 index 000000000..41fe23ec9 --- /dev/null +++ b/assets/layout/layout_002_popup_help2.json @@ -0,0 +1,70 @@ +{ + "name": "help2", + "desc": "help2弹窗", + "type": "flex", + "properties": { + "width": 660, + "height": 434, + "x": 70, + "y": 40, + "style": "style-help1-background" + }, + "children": [ + { + "name": "help2_title", + "desc": "帮助主题", + "type": "label", + "properties": { + "text": "Charging time and cost", + "x_ofs": 40, + "y_ofs": 30, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_label" + } + }, + { + "name": "help2_split_line", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 580, + "height": 1, + "x": 40, + "y": 64, + "style": "style-split" + } + }, + { + "name": "help2_content", + "desc": "帮助内容", + "type": "label", + "properties": { + "text": "Charging could not be initiated. Please ensure your vehicle is plugged in correctly. Your credit has not been charged. To start a new charging session, please reconnect.", + "x_ofs": 40, + "y_ofs": 74, + "width": 580, + "height": 356, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt" + } + }, + { + "name": "help2_close_button", + "type": "fragment", + "fragment_name" : "fragment_btn_primary", + "properties": { + "x": 80, + "y": 364 + } + }, + { + "name": "help2_back_button", + "type": "fragment", + "fragment_name" : "fragment_btn_primary", + "properties": { + "x": 380, + "y": 364 + } + } + ] +} diff --git a/assets/layout/layout_004_popup_bill.json b/assets/layout/layout_004_popup_bill.json new file mode 100644 index 000000000..5c52d6d12 --- /dev/null +++ b/assets/layout/layout_004_popup_bill.json @@ -0,0 +1,79 @@ +{ + "name": "bill", + "desc": "bill弹窗", + "type": "flex", + "properties": { + "width": 660, + "height": 460, + "x": 70, + "y": 70, + "style": "style-help1-background" + }, + "children": [ + { + "name": "bill_qr_code_bill", + "type": "qr", + "properties": { + "x_ofs": 80, + "y_ofs": 30, + "size": 140, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "bill_scan_for_bill_title", + "desc": "扫描账单文本", + "type": "label", + "properties": { + "text": "Scan for bill", + "x_ofs": 108, + "y_ofs": 174, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text" + } + }, + { + "name": "bill_qr_code_receipt", + "type": "qr", + "properties": { + "x_ofs": 80, + "y_ofs": 202, + "size": 140, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "bill_scan_for_receipt_title", + "desc": "扫描收据文本", + "type": "label", + "properties": { + "text": "Scan for receipt", + "x_ofs": 92, + "y_ofs": 346, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-type-text" + } + }, + { + "name": "bill_content", + "desc": "账单内容", + "type": "fragment", + "fragment_name": "fragment_popup_bill", + "properties": { + "x": 300, + "y": 30 + } + }, + { + "name": "bill_close_button", + "type": "fragment", + "fragment_name" : "fragment_btn_primary", + "properties": { + "x": 230, + "y": 390 + } + } + ] +} diff --git a/assets/layout/layout_005_popup_pre_authorization.json b/assets/layout/layout_005_popup_pre_authorization.json new file mode 100644 index 000000000..3bdfa912c --- /dev/null +++ b/assets/layout/layout_005_popup_pre_authorization.json @@ -0,0 +1,229 @@ +{ + "name": "pre_authorization", + "desc": "预授权弹窗", + "type": "flex", + "properties": { + "width": 660, + "height": 520, + "x": 70, + "y": 40, + "style": "style-help1-background" + }, + "children": [ + { + "name": "pre_auth_title", + "desc": "提示输入金额文本", + "type": "label", + "properties": { + "text": "Please enter the amount", + "x_ofs": 0, + "y_ofs": 30, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_label" + } + }, + { + "name": "pre_auth_split_line", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 580, + "height": 1, + "x": 40, + "y": 64, + "style": "style-split" + } + }, + { + "name": "pre_auth_input_box", + "desc": "预授权输入框", + "type": "flex", + "properties": { + "x": 50, + "y": 117, + "width": 260, + "height": 60, + "style": "style-amount" + } + }, + { + "name": "pre_amounut_currency", + "desc": "货币单位", + "type": "label", + "properties": { + "text": "CNY", + "x_ofs": 79, + "y_ofs": 137, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-connector-quad-default-power-text" + } + }, + { + "name": "pre_auth_val", + "desc": "预授权金额", + "type": "label", + "properties": { + "text": "0", + "x_ofs": 117, + "y_ofs": 134, + "align" : "LV_ALIGN_TOP_LEFT", + "style": "style-estimated_cost" + } + }, + { + "name": "pre_auth_shortcut1", + "desc": "预授权金额快捷按钮", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_shortcut1", + "properties": { + "x": 90, + "y": 227 + } + }, + { + "name": "pre_auth_shortcut2", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_shortcut2", + "properties": { + "x": 90, + "y": 287 + } + }, + { + "name": "pre_auth_shortcut3", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_shortcut3", + "properties": { + "x": 90, + "y": 347 + } + }, + { + "name": "num1", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_keypad", + "properties": { + "text": "1", + "x": 380, + "y": 117 + } + }, + { + "name": "num2", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_keypad", + "properties": { + "x": 450, + "y": 117 + } + }, + { + "name": "num3", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_keypad", + "properties": { + "x": 520, + "y": 117 + } + }, + { + "name": "num4", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_keypad", + "properties": { + "x": 380, + "y": 187 + } + }, + { + "name": "num5", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_keypad", + "properties": { + "x": 450, + "y": 187 + } + }, + { + "name": "num6", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_keypad", + "properties": { + "x": 520, + "y": 187 + } + }, + { + "name": "num7", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_keypad", + "properties": { + "x": 380, + "y": 257 + } + }, + { + "name": "num8", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_keypad", + "properties": { + "x": 450, + "y": 257 + } + }, + { + "name": "num9", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_keypad", + "properties": { + "x": 520, + "y": 257 + } + }, + { + "name": "char_drop", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_keypad", + "properties": { + "x": 380, + "y": 327 + } + }, + { + "name": "num0", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_keypad", + "properties": { + "x": 450, + "y": 327 + } + }, + { + "name": "char_delete", + "type": "fragment", + "fragment_name" : "fragment_pre_authorization_keypad_delete", + "properties": { + "x": 520, + "y": 327 + } + }, + { + "name": "pre_auth_close_button", + "type": "fragment", + "fragment_name" : "fragment_btn_primary", + "properties": { + "x": 80, + "y": 450 + } + }, + { + "name": "pre_auth_confirm_button", + "type": "fragment", + "fragment_name" : "fragment_btn_primary", + "properties": { + "x": 380, + "y": 450 + } + } + ] +} diff --git a/assets/layout/layout_006_popup_language.json b/assets/layout/layout_006_popup_language.json new file mode 100644 index 000000000..b276aed6d --- /dev/null +++ b/assets/layout/layout_006_popup_language.json @@ -0,0 +1,57 @@ +{ + "name": "language", + "desc": "language弹窗", + "type": "flex", + "properties": { + "width": 660, + "height": 520, + "x": 70, + "y": 40, + "style": "style-help1-background" + }, + "children": [ + { + "name": "language_title", + "desc": "标题", + "type": "label", + "properties": { + "text": "Language", + "x_ofs": 282, + "y_ofs": 30, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_label" + } + }, + { + "name": "language_split_line", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 580, + "height": 1, + "x": 40, + "y": 64, + "style": "style-split" + } + }, + + { + "name": "language_close_btn", + "type": "fragment", + "fragment_name" : "fragment_btn_primary", + "properties": { + "x": 80, + "y": 450 + } + }, + { + "name": "language_confirm_btn", + "type": "fragment", + "fragment_name" : "fragment_btn_primary", + "properties": { + "x": 380, + "y": 450 + } + } + ] +} diff --git a/assets/layout/layout_007_popup_detailed_data.json b/assets/layout/layout_007_popup_detailed_data.json new file mode 100644 index 000000000..3b706154a --- /dev/null +++ b/assets/layout/layout_007_popup_detailed_data.json @@ -0,0 +1,65 @@ +{ + "name": "detailed_data", + "desc": "detailed_data弹窗", + "type": "flex", + "properties": { + "width": 660, + "height": 520, + "x": 70, + "y": 40, + "style": "style-help1-background" + }, + "children": [ + { + "name": "detailed_data", + "desc": "详细数据", + "type": "label", + "properties": { + "text": "Detailed data", + "x_ofs": 40, + "y_ofs": 30, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_label" + } + }, + { + "name": "split_line_detailed_data", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 580, + "height": 1, + "x": 40, + "y": 64, + "style": "style-split" + } + }, + { + "name": "card_left", + "type": "fragment", + "fragment_name" : "fragment_card_left_detailed_data", + "properties": { + "x": 40, + "y": 74 + } + }, + { + "name": "card_right", + "type": "fragment", + "fragment_name" : "fragment_card_right_detailed_data", + "properties": { + "x": 341, + "y": 74 + } + }, + { + "name": "close_button", + "type": "fragment", + "fragment_name" : "fragment_detailed_data_close", + "properties": { + "x": 230, + "y": 450 + } + } + ] +} diff --git a/assets/layout/layout_010_main.json b/assets/layout/layout_010_main.json new file mode 100644 index 000000000..c84f6683d --- /dev/null +++ b/assets/layout/layout_010_main.json @@ -0,0 +1,12 @@ +{ + "name": "main", + "desc": "主界面(2/3/4枪)", + "type": "flex", + "properties": { + "width": 800, + "height": 600, + "style": "style-background-primary" + }, + "children": [ + ] +} diff --git a/assets/layout/layout_011_main_single.json b/assets/layout/layout_011_main_single.json new file mode 100644 index 000000000..5740a2d4b --- /dev/null +++ b/assets/layout/layout_011_main_single.json @@ -0,0 +1,12 @@ +{ + "name": "main", + "desc": "主界面单枪", + "type": "flex", + "properties": { + "width": 800, + "height": 600, + "style": "style-background-primary" + }, + "children": [ + ] +} diff --git a/assets/layout/layout_020_status_bar.json b/assets/layout/layout_020_status_bar.json new file mode 100644 index 000000000..169fd86d9 --- /dev/null +++ b/assets/layout/layout_020_status_bar.json @@ -0,0 +1,44 @@ +{ + "name": "status_bar", + "desc": "顶部状态栏", + "type": "flex", + "properties": { + "x": 0, + "y": 0, + "width": 800, + "height": 70, + "style":"style-background-primary" + }, + "children": [ + { + "name": "time", + "desc": "当前时间,小数位数由配置决定", + "type": "label", + "properties": { + "text": "12:00", + "align": "LV_ALIGN_CENTER", + "style": "style-text-primary" + } + }, + { + "name": "help", + "desc": "帮助按钮", + "type": "fragment", + "fragment_name": "fragment_btn_text", + "properties": { + "x_ofs": 500, + "align": "LV_ALIGN_LEFT_MID" + } + }, + { + "name": "language", + "desc": "语言按钮", + "type": "fragment", + "fragment_name": "fragment_btn_language", + "properties": { + "x_ofs": 650, + "align": "LV_ALIGN_LEFT_MID" + } + } + ] +} diff --git a/assets/layout/layout_021_connector_quad.json b/assets/layout/layout_021_connector_quad.json new file mode 100644 index 000000000..1af224b5f --- /dev/null +++ b/assets/layout/layout_021_connector_quad.json @@ -0,0 +1,50 @@ +{ + "name": "conn_card_quad", + "desc": "四枪的四个卡片组合默认状态", + "type": "flex", + "properties": { + "x": 0, + "y": 440, + "width": 800, + "height": 160, + "style": "style-background-primary" + }, + "children": [ + { + "name": "connector1", + "type": "fragment", + "fragment_name": "fragment_connector_card_quad", + "properties": { + "x_ofs": 20, + "align": "LV_ALIGN_LEFT_MID" + } + }, + { + "name": "connector2", + "type": "fragment", + "fragment_name": "fragment_connector_card_quad", + "properties": { + "x_ofs": 212, + "align": "LV_ALIGN_LEFT_MID" + } + }, + { + "name": "connector3", + "type": "fragment", + "fragment_name": "fragment_connector_card_quad", + "properties": { + "x_ofs": 404, + "align": "LV_ALIGN_LEFT_MID" + } + }, + { + "name": "connector4", + "type": "fragment", + "fragment_name": "fragment_connector_card_quad", + "properties": { + "x_ofs": 596, + "align": "LV_ALIGN_LEFT_MID" + } + } + ] +} diff --git a/assets/layout/layout_022_connector_dual.json b/assets/layout/layout_022_connector_dual.json new file mode 100644 index 000000000..1739ebe9a --- /dev/null +++ b/assets/layout/layout_022_connector_dual.json @@ -0,0 +1,32 @@ +{ + "name": "conn_card_dual", + "desc": "双枪的三个卡片组合默认状态", + "type": "flex", + "properties": { + "x": 0, + "y": 440, + "width": 800, + "height": 160, + "style": "style-background-primary" + }, + "children": [ + { + "name": "connector1", + "type": "fragment", + "fragment_name": "fragment_conn_card_dual_left_card", + "properties": { + "x_ofs": 20, + "align": "LV_ALIGN_LEFT_MID" + } + }, + { + "name": "connector2", + "type": "fragment", + "fragment_name": "fragment_conn_card_dual_right_card", + "properties": { + "x_ofs": 404, + "align": "LV_ALIGN_LEFT_MID" + } + } + ] +} diff --git a/assets/layout/layout_023_connector_trip.json b/assets/layout/layout_023_connector_trip.json new file mode 100644 index 000000000..3149863b7 --- /dev/null +++ b/assets/layout/layout_023_connector_trip.json @@ -0,0 +1,41 @@ +{ + "name": "conn_card_trip", + "desc": "三枪的三个卡片组合默认状态", + "type": "flex", + "properties": { + "x": 0, + "y": 440, + "width": 800, + "height": 160, + "style": "style-background-primary" + }, + "children": [ + { + "name": "connector1", + "type": "fragment", + "fragment_name": "fragment_conn_card_trip_card", + "properties": { + "x_ofs": 20, + "align": "LV_ALIGN_LEFT_MID" + } + }, + { + "name": "connector2", + "type": "fragment", + "fragment_name": "fragment_conn_card_trip_card", + "properties": { + "x_ofs": 276, + "align": "LV_ALIGN_LEFT_MID" + } + }, + { + "name": "connector3", + "type": "fragment", + "fragment_name": "fragment_conn_card_trip_card", + "properties": { + "x_ofs": 532, + "align": "LV_ALIGN_LEFT_MID" + } + } + ] +} diff --git a/assets/layout/layout_031_page_home.json b/assets/layout/layout_031_page_home.json new file mode 100644 index 000000000..a616b444b --- /dev/null +++ b/assets/layout/layout_031_page_home.json @@ -0,0 +1,59 @@ +{ + "name": "home", + "desc": "未选枪时显示得界面", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "home_plug_icon", + "type": "image", + "properties": { + "x_ofs": 164, + "y_ofs": 48, + "width": 150, + "height": 150, + "align": "LV_ALIGN_TOP_LEFT", + + "src": "hint-map" + } + }, + + { + "name": "home_plug_title", + "desc": "插枪文本", + "type": "label", + "properties": { + "text": "Plug in first", + "x_ofs": 0, + "y_ofs": 130, + "width": 300, + "height": 40, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_label", + "to_obj": "main.home.home_plug_icon", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "home_plug_subtitle", + "desc": "插枪提示", + "type": "label", + "properties": { + "text": "Please plug in the connector to you vehicle first before start a new session.", + "x_ofs": 31, + "y_ofs": 269, + "width": 416, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_032_page_idle.json b/assets/layout/layout_032_page_idle.json new file mode 100644 index 000000000..40459661a --- /dev/null +++ b/assets/layout/layout_032_page_idle.json @@ -0,0 +1,57 @@ +{ + "name": "idle", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "idle_plug_icon", + "type": "image", + "properties": { + "x_ofs": 164, + "y_ofs": 86, + "width": 150, + "height": 150, + "align": "LV_ALIGN_TOP_LEFT", + "src": "hint-map" + } + }, + { + "name": "idle_plug_title", + "desc": "插枪文本", + "type": "label", + "properties": { + "text": "Plug in first", + "x_ofs": 0, + "y_ofs": 120, + "width": 300, + "height": 40, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_label", + "to_obj": "main.idle.idle_plug_icon", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "idle_plug_subtitle", + "desc": "插枪提示", + "type": "label", + "properties": { + "text": "Please plug in the connector to you vehicle first before start a new session.", + "x_ofs": 31, + "y_ofs": 294, + "width": 416, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_033_page_starting1.json b/assets/layout/layout_033_page_starting1.json new file mode 100644 index 000000000..ff976745e --- /dev/null +++ b/assets/layout/layout_033_page_starting1.json @@ -0,0 +1,56 @@ +{ + "name": "starting1", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "starting1_qr", + "type": "qr", + "properties": { + "x_ofs": 174, + "y_ofs": 92, + "size": 130, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "starting1_title", + "desc": "二维码下方提示文本", + "type": "label", + "properties": { + "text": "Scan here to start charging", + "x_ofs": 10, + "y_ofs": 110, + "width": 500, + "height": 40, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_label", + "to_obj": "main.starting1.starting1_qr", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "starting1_subtitle", + "desc": "插枪提示", + "type": "label", + "properties": { + "text": "Access thousands of chargers across multiple networks with one app. ", + "x_ofs": 31, + "y_ofs": 278, + "width": 416, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_034_page_starting2.json b/assets/layout/layout_034_page_starting2.json new file mode 100644 index 000000000..2e5e72fad --- /dev/null +++ b/assets/layout/layout_034_page_starting2.json @@ -0,0 +1,68 @@ +{ + "name": "starting2", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "starting2_qr", + "type": "qr", + "properties": { + "x_ofs": 79, + "y_ofs": 92, + "size": 130, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "starting2_pos_btn", + "type": "fragment", + "fragment_name" : "fragment_starting2_pos_btn", + "properties": { + "x": 269, + "y": 92, + "width": 130, + "height": 130, + "style": "style-info_card_half" + } + }, + { + "name": "starting2_subtitle", + "desc": "插枪提示", + "type": "label", + "properties": { + "text": "Access thousands of chargers across multiple networks with one app. ", + "x_ofs": 31, + "y_ofs": 278, + "width": 416, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "starting2_title", + "desc": "二维码文本", + "type": "label", + "properties": { + "text": "Scan the code or swipe the card to start charging.", + "x_ofs": 10, + "y_ofs": -30, + "width": 500, + "height": 40, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_label", + "to_obj": "main.starting2.starting2_subtitle", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_035_page_charging.json b/assets/layout/layout_035_page_charging.json new file mode 100644 index 000000000..c82095cac --- /dev/null +++ b/assets/layout/layout_035_page_charging.json @@ -0,0 +1,69 @@ +{ + "name": "charging", + "desc": "充电状态", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "charging_car_icon", + "desc": "充电动态图", + "type": "fragment", + "fragment_name" : "fragment_charging_car_icon", + "properties": { + "x_ofs": 20, + "y_ofs": 80, + "align": "LV_ALIGN_TOP_LEFT" + } + }, + { + "name": "charging_power", + "desc": "", + "type": "fragment", + "fragment_name": "fragment_label_combine_three", + "properties": { + "x_ofs": 20, + "y_ofs": 111, + "align": "LV_ALIGN_TOP_LEFT" + } + }, + { + "name": "charging_energy", + "desc": "", + "type": "fragment", + "fragment_name": "fragment_label_combine_three", + "properties": { + "x_ofs": 20, + "y_ofs": 220, + "align": "LV_ALIGN_TOP_LEFT" + } + }, + { + "name": "charging_soc", + "desc": "", + "type": "fragment", + "fragment_name": "fragment_label_combine_three", + "properties": { + "x_ofs": 310, + "y_ofs": 111, + "align": "LV_ALIGN_TOP_LEFT" + } + }, + { + "name": "charging_duration", + "desc": "", + "type": "fragment", + "fragment_name": "fragment_label_combine_two", + "properties": { + "x_ofs": 310, + "y_ofs": 220, + "align": "LV_ALIGN_TOP_LEFT" + } + } + ] +} diff --git a/assets/layout/layout_036_page_finished.json b/assets/layout/layout_036_page_finished.json new file mode 100644 index 000000000..2967ba8dd --- /dev/null +++ b/assets/layout/layout_036_page_finished.json @@ -0,0 +1,71 @@ +{ + "name": "finished", + "desc": "充电完成界面", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "finished_car_icon", + "desc": "", + "type": "image", + "properties": { + "x_ofs": 20, + "y_ofs": 80, + "width": 437, + "height": 260, + "align": "LV_ALIGN_TOP_LEFT", + "src": "bg_data-display_finished" + } + }, + { + "name": "finished_start_time", + "desc": "", + "type": "fragment", + "fragment_name": "fragment_label_combine_two", + "properties": { + "x_ofs": 20, + "y_ofs": 111, + "align": "LV_ALIGN_TOP_LEFT" + } + }, + { + "name": "finished_energy", + "desc": "", + "type": "fragment", + "fragment_name": "fragment_label_combine_three", + "properties": { + "x_ofs": 20, + "y_ofs": 220, + "align": "LV_ALIGN_TOP_LEFT" + } + }, + { + "name": "finished_duration", + "desc": "", + "type": "fragment", + "fragment_name": "fragment_label_combine_two", + "properties": { + "x_ofs": 310, + "y_ofs": 111, + "align": "LV_ALIGN_TOP_LEFT" + } + }, + { + "name": "finished_soc", + "desc": "", + "type": "fragment", + "fragment_name": "fragment_label_combine_six", + "properties": { + "x_ofs": 310, + "y_ofs": 220, + "align": "LV_ALIGN_TOP_LEFT" + } + } + ] +} diff --git a/assets/layout/layout_037_page_reserved.json b/assets/layout/layout_037_page_reserved.json new file mode 100644 index 000000000..3c5df6367 --- /dev/null +++ b/assets/layout/layout_037_page_reserved.json @@ -0,0 +1,27 @@ +{ + "name": "reserved", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "reserved_car_icon", + "desc": "充电预约图", + "type": "image", + "properties": { + "x_ofs": 20, + "y_ofs": 77, + "width": 437, + "height": 283, + "align": "LV_ALIGN_TOP_LEFT", + "src": "parking-diagram" + } + } + ] +} diff --git a/assets/layout/layout_038_page_session_error_full.json b/assets/layout/layout_038_page_session_error_full.json new file mode 100644 index 000000000..bb5530735 --- /dev/null +++ b/assets/layout/layout_038_page_session_error_full.json @@ -0,0 +1,23 @@ +{ + "name": "session_error", + "desc": "充电过程错误界面", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "session_error", + "type": "fragment", + "fragment_name" : "fragment_charging_error", + "properties": { + "x":0, + "y":0 + } + } + ] +} diff --git a/assets/layout/layout_039_page_start_error_full.json b/assets/layout/layout_039_page_start_error_full.json new file mode 100644 index 000000000..a4bf2a594 --- /dev/null +++ b/assets/layout/layout_039_page_start_error_full.json @@ -0,0 +1,23 @@ +{ + "name": "start_error", + "desc": "起充失败界面", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "start_error", + "type": "fragment", + "fragment_name" : "fragment_charging_error", + "properties": { + "x":0, + "y":0 + } + } + ] +} diff --git a/assets/layout/layout_040_page_fault_full.json b/assets/layout/layout_040_page_fault_full.json new file mode 100644 index 000000000..4ca67367f --- /dev/null +++ b/assets/layout/layout_040_page_fault_full.json @@ -0,0 +1,82 @@ +{ + "name": "fault", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "fault_icon", + "type": "image", + "properties": { + "x_ofs": 316, + "y_ofs": 67, + "width": 130, + "height": 130, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_charging-pile" + } + }, + { + "name": "fault_symbol", + "type": "label", + "properties": { + "text": "X", + "x_ofs": 372, + "y_ofs": 130, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-X_start", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "fault_title", + "type": "label", + "properties": { + "text": "Equipment failure", + "x_ofs": 0, + "y_ofs": 200, + "width": 300, + "height": 30, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_label", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "fault_code", + "desc": "错误码", + "type": "label", + "properties": { + "text": "Other error:07", + "x_ofs": 0, + "y_ofs": 237, + "width": 400, + "height": 40, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "fault_subtitle", + "desc": "错误提示", + "type": "label", + "properties": { + "text": "Please contact the maintenance staff.", + "x_ofs": 0, + "y_ofs": 260, + "width": 400, + "height": 40, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_041_page_unavailable_full.json b/assets/layout/layout_041_page_unavailable_full.json new file mode 100644 index 000000000..5412bf04d --- /dev/null +++ b/assets/layout/layout_041_page_unavailable_full.json @@ -0,0 +1,67 @@ +{ + "name": "unavailable", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "unavailable_icon", + "type": "image", + "properties": { + "x_ofs": 316, + "y_ofs": 67, + "width": 130, + "height": 130, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_charging-pile" + } + }, + { + "name": "unavailable_symbol", + "desc": "X文本", + "type": "label", + "properties": { + "text": "X", + "x_ofs": 372, + "y_ofs": 130, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-X_unavailable", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "unavailable_title", + "type": "label", + "properties": { + "text": "Out of service", + "x_ofs": 0, + "y_ofs": 200, + "width": 300, + "height": 30, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_label", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "unavailable_subtitle", + "type": "label", + "properties": { + "text": "Unfortunately, this charger is unavailable.Please check the Ioc app to find another charger near you or contact customer support.", + "x_ofs": 0, + "y_ofs": 240, + "width": 400, + "height": 80, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_042_page_connecting_full.json b/assets/layout/layout_042_page_connecting_full.json new file mode 100644 index 000000000..0204c8a1b --- /dev/null +++ b/assets/layout/layout_042_page_connecting_full.json @@ -0,0 +1,55 @@ +{ + "name": "connecting", + "desc": "链接授权状态", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "connecting_icon", + "type": "image", + "properties": { + "x_ofs": 280, + "y_ofs": 148, + "width": 200, + "height": 82, + "align": "LV_ALIGN_TOP_LEFT", + "src": "logo_plug&charge_2" + } + }, + { + "name": "connecting_title", + "type": "label", + "properties": { + "text": "Plug & Charge", + "x_ofs": 0, + "y_ofs": 268, + "width": 400, + "height": 40, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_label", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "connecting_subtitle", + "desc": "连接车提示", + "type": "label", + "properties": { + "text": "or AutoCharge starting…", + "x_ofs": 0, + "y_ofs": 296, + "width": 400, + "height": 40, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_044_page_stopping_full.json b/assets/layout/layout_044_page_stopping_full.json new file mode 100644 index 000000000..ea1db369d --- /dev/null +++ b/assets/layout/layout_044_page_stopping_full.json @@ -0,0 +1,54 @@ +{ + "name": "stopping", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "stopping_icon", + "type": "image", + "properties": { + "x_ofs": 316, + "y_ofs": 102, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_stopping" + } + }, + { + "name": "stopping_title", + "desc": "暂停文本", + "type": "label", + "properties": { + "text": "Charging is stopping", + "x_ofs": 0, + "y_ofs": 268, + "width": 400, + "height": 40, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_label", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "stopping_reson", + "desc": "暂停原因", + "type": "label", + "properties": { + "text": "", + "x_ofs": 0, + "y_ofs": 316, + "width": 400, + "height": 40, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_045_page_wait_in_line_full.json b/assets/layout/layout_045_page_wait_in_line_full.json new file mode 100644 index 000000000..78d41677b --- /dev/null +++ b/assets/layout/layout_045_page_wait_in_line_full.json @@ -0,0 +1,23 @@ +{ + "name": "wait_in_line", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "wait_in_line", + "type": "fragment", + "fragment_name" : "fragment_charging_process", + "properties": { + "width": 760, + "height": 370 + } + } + ] +} diff --git a/assets/layout/layout_046_page_suspend_full.json b/assets/layout/layout_046_page_suspend_full.json new file mode 100644 index 000000000..288dc16be --- /dev/null +++ b/assets/layout/layout_046_page_suspend_full.json @@ -0,0 +1,54 @@ +{ + "name": "suspend", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "suspend_draw_icon", + "desc": "绘制的圆,中间感叹号", + "type": "fragment", + "fragment_name":"fragment_suspend_draw_icon", + "properties": { + "x": 341, + "y": 120 + } + }, + { + "name": "suspend_label", + "desc": "充电暂停", + "type": "label", + "properties": { + "text": "Charging suspend", + "x_ofs": 0, + "y_ofs": 234, + "width": 400, + "height": 40, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_label", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "suspend_reason", + "desc": "充电暂停原因", + "type": "label", + "properties": { + "text": "", + "x_ofs": 0, + "y_ofs": 260, + "width": 400, + "height": 40, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_047_conn_top_info.json b/assets/layout/layout_047_conn_top_info.json new file mode 100644 index 000000000..13235d95b --- /dev/null +++ b/assets/layout/layout_047_conn_top_info.json @@ -0,0 +1,61 @@ +{ + "name": "conn_top_info", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 70, + "style":"style-mid_container_top" + }, + "children": [ + { + "name": "conn_id", + "type": "fragment", + "fragment_name" : "fragment_conn_top_id", + "properties": { + "x": 0, + "y": 0 + } + }, + { + "name": "station_id", + "type": "label", + "properties": { + "text": "10012", + "x_ofs": 90, + "y_ofs": 42, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_LEFT" + } + }, + { + "name": "conn_state", + "desc": "状态", + "type": "label", + "properties": { + "text": "Idle", + "x_ofs": 90, + "y_ofs": 13, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-idle-status", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "conn_type_power", + "desc": "插枪类型和功率", + "type": "label", + "properties": { + "text": "CCS2(DC)-120.0kW", + "x_ofs": 554, + "y_ofs": 13, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-type_power", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_048_page_processing_full.json b/assets/layout/layout_048_page_processing_full.json new file mode 100644 index 000000000..8c0ca698c --- /dev/null +++ b/assets/layout/layout_048_page_processing_full.json @@ -0,0 +1,22 @@ +{ + "name": "processing", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "processing", + "type": "fragment", + "fragment_name" : "fragment_charging_process", + "properties": { + "width": 760, + "height": 370 + } + } + ] +} diff --git a/assets/layout/layout_049_popup_common.json b/assets/layout/layout_049_popup_common.json new file mode 100644 index 000000000..533eaac1f --- /dev/null +++ b/assets/layout/layout_049_popup_common.json @@ -0,0 +1,46 @@ +{ + "name": "popup_common", + "desc": "通用弹窗", + "type": "flex", + "properties": { + "width": 480, + "height": 300, + "x": 160, + "y": 150, + "style": "style-help1-background" + }, + "children": [ + { + "name": "circle_img", + "type": "image", + "properties": { + "x_ofs": 0, + "y_ofs": -70, + "width": 80, + "height": 80, + "align": "LV_ALIGN_CENTER", + "src": "icon_warning_2" + } + }, + { + "name": "prompt", + "desc": "通用提示文本fragment", + "type": "fragment", + "fragment_name": "fragment_popup_common_prompt", + "properties": { + "x_ofs": 0, + "y_ofs": 20, + "align": "LV_ALIGN_CENTER" + } + }, + { + "name": "close_button", + "type": "fragment", + "fragment_name" : "fragment_common_close", + "properties": { + "x": 140, + "y": 230 + } + } + ] +} diff --git a/assets/layout/layout_050_page_home_full.json b/assets/layout/layout_050_page_home_full.json new file mode 100644 index 000000000..d1f2f1b03 --- /dev/null +++ b/assets/layout/layout_050_page_home_full.json @@ -0,0 +1,59 @@ +{ + "name": "home_full", + "desc": "未选枪时显示得界面", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "home_plug_icon", + "type": "image", + "properties": { + "x_ofs": 309, + "y_ofs": 48, + "width": 150, + "height": 150, + "align": "LV_ALIGN_TOP_LEFT", + + "src": "hint-map" + } + }, + + { + "name": "home_plug_title", + "desc": "插枪文本", + "type": "label", + "properties": { + "text": "Plug in first", + "x_ofs": 0, + "y_ofs": 130, + "width": 300, + "height": 40, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_label", + "to_obj": "main.home.plug_home", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "home_plug_subtitle", + "desc": "插枪提示", + "type": "label", + "properties": { + "text": "Please plug in the connector to you vehicle first before start a new session.", + "x_ofs": 31, + "y_ofs": 269, + "width": 416, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_051_page_idel_full.json b/assets/layout/layout_051_page_idel_full.json new file mode 100644 index 000000000..37a561225 --- /dev/null +++ b/assets/layout/layout_051_page_idel_full.json @@ -0,0 +1,57 @@ +{ + "name": "idle_full", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "idle_plug_icon", + "type": "image", + "properties": { + "x_ofs": 306, + "y_ofs": 86, + "width": 150, + "height": 150, + "align": "LV_ALIGN_TOP_LEFT", + "src": "hint-map" + } + }, + { + "name": "idle_plug_title", + "desc": "插枪文本", + "type": "label", + "properties": { + "text": "Plug in first", + "x_ofs": 0, + "y_ofs": 120, + "width": 300, + "height": 40, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_label", + "to_obj": "main.idle.plug_idle", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "idle_plug_subtitle", + "desc": "插枪提示", + "type": "label", + "properties": { + "text": "Please plug in the connector to you vehicle first before start a new session.", + "x_ofs": 0, + "y_ofs": 294, + "width": 416, + "height": 40, + "align": "LV_ALIGN_TOP_MID", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_052_page_starting1_full.json b/assets/layout/layout_052_page_starting1_full.json new file mode 100644 index 000000000..63b886a21 --- /dev/null +++ b/assets/layout/layout_052_page_starting1_full.json @@ -0,0 +1,56 @@ +{ + "name": "starting1_full", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "starting1_qr", + "type": "qr", + "properties": { + "x_ofs": 174, + "y_ofs": 92, + "size": 130, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "starting1_title", + "desc": "二维码下方提示文本", + "type": "label", + "properties": { + "text": "Scan here to start charging", + "x_ofs": 10, + "y_ofs": 110, + "width": 500, + "height": 40, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_label", + "to_obj": "main.starting1.qr_code_starting1", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "starting1_subtitle", + "desc": "插枪提示", + "type": "label", + "properties": { + "text": "Access thousands of chargers across multiple networks with one app. ", + "x_ofs": 31, + "y_ofs": 278, + "width": 416, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_053_page_starting2_full.json b/assets/layout/layout_053_page_starting2_full.json new file mode 100644 index 000000000..6422d584c --- /dev/null +++ b/assets/layout/layout_053_page_starting2_full.json @@ -0,0 +1,68 @@ +{ + "name": "starting2_full", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "starting2_qr", + "type": "qr", + "properties": { + "x_ofs": 79, + "y_ofs": 92, + "size": 130, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "starting2_pos_btn", + "type": "fragment", + "fragment_name" : "fragment_starting2_pos_btn", + "properties": { + "x": 269, + "y": 92, + "width": 130, + "height": 130, + "style": "style-info_card_half" + } + }, + { + "name": "starting2_title", + "desc": "插枪提示", + "type": "label", + "properties": { + "text": "Access thousands of chargers across multiple networks with one app. ", + "x_ofs": 31, + "y_ofs": 278, + "width": 416, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "starting2_subtitle", + "desc": "二维码文本", + "type": "label", + "properties": { + "text": "Scan here to start charging", + "x_ofs": 10, + "y_ofs": -30, + "width": 500, + "height": 40, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_label", + "to_obj": "main.starting2.qr_code_prompt_starting2", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_054_page_charging_full.json b/assets/layout/layout_054_page_charging_full.json new file mode 100644 index 000000000..a852a7666 --- /dev/null +++ b/assets/layout/layout_054_page_charging_full.json @@ -0,0 +1,71 @@ +{ + "name": "charging_full", + "desc": "中间部分", + "type": "flex", + "properties": { + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "style":"style-checkbox" + }, + "children": [ + { + "name": "charging_car_icon", + "desc": "充电动态图", + "type": "fragment", + "fragment_name" : "fragment_charging_car_icon", + "properties": { + "x_ofs": 162, + "y_ofs": 80, + "width": 437, + "height": 260, + "align": "LV_ALIGN_TOP_LEFT" + } + }, + { + "name": "charging_power", + "desc": "", + "type": "fragment", + "fragment_name": "fragment_label_combine_three", + "properties": { + "x_ofs": 162, + "y_ofs": 31, + "align": "LV_ALIGN_TOP_LEFT" + } + }, + { + "name": "charging_energy", + "desc": "", + "type": "fragment", + "fragment_name": "fragment_label_combine_three", + "properties": { + "x_ofs": 452, + "y_ofs": 140, + "align": "LV_ALIGN_TOP_LEFT" + } + }, + { + "name": "charging_soc", + "desc": "", + "type": "fragment", + "fragment_name": "fragment_label_combine_three", + "properties": { + "x_ofs": 452, + "y_ofs": 31, + "align": "LV_ALIGN_TOP_LEFT" + } + }, + { + "name": "charging_duration", + "desc": "", + "type": "fragment", + "fragment_name": "fragment_label_combine_two", + "properties": { + "x_ofs": 290, + "y_ofs": 140, + "align": "LV_ALIGN_TOP_LEFT" + } + } + ] +} diff --git a/assets/layout/layout_060_customer_info.json b/assets/layout/layout_060_customer_info.json new file mode 100644 index 000000000..c2f0dadf1 --- /dev/null +++ b/assets/layout/layout_060_customer_info.json @@ -0,0 +1,143 @@ +{ + "name": "cuestomer_info", + "desc": "客户信息卡片", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "x": 497, + "y": 140, + "style": "style-info_card" + }, + "children": [ + { + "name": "cuestomer_qrcode", + "type": "qr", + "properties": { + "x_ofs": 85, + "y_ofs": 10, + "size": 94, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "customer_hint", + "desc": "二维码提示文本", + "type": "label", + "properties": { + "text": "Download Ioc APP for a faster experience.", + "width": 227, + "x_ofs": 18, + "y_ofs": 117, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "customer_charger_icon", + "desc": "充电桩状态图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 174, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_charging-station" + } + }, + { + "name": "customer_charger_id", + "desc": "充电桩状态文本", + "type": "label", + "properties": { + "text": "Charger id:", + "x_ofs": 65, + "y_ofs": 175, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "customer_mobile_icon", + "desc": "联系图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 198, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_contact" + } + }, + { + "name": "customer_mobile", + "desc": "联系文本", + "type": "label", + "properties": { + "text": "", + "x_ofs": 65, + "y_ofs": 199, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "customer_tel_icon", + "desc": "移动电话图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 222, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_telephone" + } + }, + { + "name": "customer_tel", + "desc": "移动电话文本", + "type": "label", + "properties": { + "text": "", + "x_ofs": 65, + "y_ofs": 223, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "customer_web_icon", + "desc": "网址图片", + "type": "image", + "properties": { + "x_ofs": 30, + "y_ofs": 246, + "width": 24, + "height": 24, + "align": "LV_ALIGN_TOP_LEFT", + "src": "icon_url" + } + }, + { + "name": "customer_web", + "desc": "网址文本", + "type": "label", + "properties": { + "text": "Ioc.id", + "x_ofs": 65, + "y_ofs": 247, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_061_customer_info_charging.json b/assets/layout/layout_061_customer_info_charging.json new file mode 100644 index 000000000..24261b9d3 --- /dev/null +++ b/assets/layout/layout_061_customer_info_charging.json @@ -0,0 +1,63 @@ +{ + "name": "cuestomer_info_charging", + "desc": "充电中客户信息卡片", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "x": 497, + "y": 140, + "style": "style-info_card" + }, + "children": [ + { + "name": "cuestomer_qrcode", + "type": "qr", + "properties": { + "x_ofs": 85, + "y_ofs": 10, + "size": 94, + "align": "LV_ALIGN_TOP_LEFT", + "qr_code_data":"https://www.iocharger.com/" + } + }, + { + "name": "customer_hint", + "desc": "二维码提示文本", + "type": "label", + "properties": { + "text": "Download Ioc APP for a faster experience.", + "width": 227, + "x_ofs": 18, + "y_ofs": 117, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "customer_charging_divider", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 203, + "height": 1, + "x_ofs": 30, + "y_ofs": 189, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-split" + } + }, + { + "name": "detailed_data", + "desc": "充电详细数据", + "type": "fragment", + "fragment_name": "fragment_detailed_data_charging_noprice", + "properties": { + "x_ofs" : 0, + "y_ofs" : 110, + "align": "LV_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_062_price_charging.json b/assets/layout/layout_062_price_charging.json new file mode 100644 index 000000000..8802d4dbd --- /dev/null +++ b/assets/layout/layout_062_price_charging.json @@ -0,0 +1,72 @@ +{ + "name": "price_charging", + "desc": "充电界面价格信息,包含当前时间段价格,预估费用和详情按钮,以及ocpp价格", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "x": 497, + "y": 140, + "style": "style-info_card" + }, + "children": [ + { + "name": "price_charging_current_rate", + "type": "fragment", + "fragment_name" : "fragment_price_rate", + "properties": { + "x":19, + "y":30 + } + }, + { + "name": "price_charging_divider", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 203, + "height": 1, + "x_ofs": 30, + "y_ofs": 118, + "align": "LV_ALIGN_CENTER", + "style": "style-split" + } + }, + { + "name": "cost_charging_title", + "desc": "预估金额提示", + "type": "label", + "properties": { + "text": "Estimated Cost", + "x_ofs": 30, + "y_ofs": 133, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "cost_charging_val", + "desc": "预估金额", + "type": "label", + "properties": { + "text": "34.3$", + "x_ofs": 30, + "y_ofs": 166, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "detaile_btn", + "desc": "充电详细数据", + "type": "fragment", + "fragment_name": "fragment_detailed_data_charging", + "properties": { + "x" : 32, + "y" : 210 + } + } + ] +} diff --git a/assets/layout/layout_063_price_idle.json b/assets/layout/layout_063_price_idle.json new file mode 100644 index 000000000..c5cec779a --- /dev/null +++ b/assets/layout/layout_063_price_idle.json @@ -0,0 +1,57 @@ +{ + "name": "price_idle", + "desc": "空闲界面价格信息,包含当前时间段和下一时间段的价格,以及ocpp价格", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "x": 497, + "y": 140, + "style": "style-info_card" + }, + "children": [ + { + "name": "price_idle_current", + "type": "fragment", + "fragment_name" : "fragment_price_current", + "properties": { + "x":19, + "y":38 + } + }, + { + "name": "price_idle_divider", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 203, + "height": 1, + "x_ofs": 30, + "y_ofs": 140, + "align": "LV_ALIGN_CENTER", + "style": "style-split" + } + }, + { + "name": "price_idle_next", + "type": "fragment", + "fragment_name" : "fragment_price_next", + "properties": { + "x":19, + "y":168 + } + }, + { + "name": "ocpp_price", + "desc": "ocpp价格", + "type": "label", + "properties": { + "text": "0.15 $/kWh, idle fee after charging: 1 $/hr", + "width": 243, + "align": "LV_ALIGN_CENTER", + "style": "style-plug_prompt", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_064_price_finished.json b/assets/layout/layout_064_price_finished.json new file mode 100644 index 000000000..2a2d90fe8 --- /dev/null +++ b/assets/layout/layout_064_price_finished.json @@ -0,0 +1,150 @@ +{ + "name": "price_finished", + "desc": "充电结束界面价格信息,包含占位时间和费用信息", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "x": 497, + "y": 140, + "style": "style-info_card" + }, + "children": [ + { + "name": "price_finished_title", + "desc": "停充后的idele time 文本", + "type": "label", + "properties": { + "text": "Idle time", + "x_ofs": 0, + "y_ofs": -100, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_finished_time", + "desc": "停充后的占位时间", + "type": "label", + "properties": { + "text": "04:24", + "x_ofs": 0, + "y_ofs": -60, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_finished_tip", + "desc": "拔枪剩余时间提醒", + "type": "label", + "properties": { + "text": "Please move your vehicle.10mins grace period exceeded.", + "x_ofs": 14, + "y_ofs": 102, + "width": 235, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_finished_divider", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 225, + "height": 2, + "x_ofs": 19, + "y_ofs": 162, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-split" + } + }, + { + "name": "price_finished_charging_title", + "desc": "充电花费金额文本", + "type": "label", + "properties": { + "text": "Charging cost", + "x_ofs": 20, + "y_ofs": 172, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_finished_charging_val", + "desc": "充电花费金额", + "type": "label", + "properties": { + "text": "34.3$", + "x_ofs": 203, + "y_ofs": 172, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_finished_idle_title", + "desc": "闲置费文本", + "type": "label", + "properties": { + "text": "Idle fee", + "x_ofs": 20, + "y_ofs": 200, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_finished_idle_val", + "desc": "闲置费", + "type": "label", + "properties": { + "text": "34.3$", + "x_ofs": 203, + "y_ofs": 200, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-current_time", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_finished_total_title", + "desc": "总金额文本", + "type": "label", + "properties": { + "text": "Total Amount", + "x_ofs": 20, + "y_ofs": 240, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_finished_total_val", + "desc": "总金额", + "type": "label", + "properties": { + "text": "134.3$", + "x_ofs": 171, + "y_ofs": 240, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_065_price_finished_no_price.json b/assets/layout/layout_065_price_finished_no_price.json new file mode 100644 index 000000000..43db88037 --- /dev/null +++ b/assets/layout/layout_065_price_finished_no_price.json @@ -0,0 +1,59 @@ +{ + "name": "price_finished_no_price", + "desc": "充电结束界面面板,没有价格信息,仅展示停充时间和提示文本", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "x": 497, + "y": 140, + "style": "style-info_card" + }, + "children": [ + { + "name": "price_finished_title", + "desc": "停充后的idele time 文本", + "type": "label", + "properties": { + "text": "Idle time", + "x_ofs": 0, + "y_ofs": -65, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_finished_time", + "desc": "停充后的占位时间", + "type": "label", + "properties": { + "text": "04:24", + "x_ofs": 0, + "y_ofs": -20, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_finished_tip", + "desc": "拔枪剩余时间提醒", + "type": "label", + "properties": { + "text": "Please move your vehicle.10mins grace period exceeded.", + "x_ofs": 14, + "y_ofs": 35, + "width": 235, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/layout/layout_066_price_reserved.json b/assets/layout/layout_066_price_reserved.json new file mode 100644 index 000000000..2f120ddfb --- /dev/null +++ b/assets/layout/layout_066_price_reserved.json @@ -0,0 +1,91 @@ +{ + "name": "price_reserved", + "desc": "预约界面价格信息,包含预约时间和当前时间段价格,以及ocpp价格", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "x": 497, + "y": 140, + "style": "style-info_card" + }, + "children": [ + { + "name": "price_reserved_title", + "desc": "预约剩余时间文本", + "type": "label", + "properties": { + "text": "Left", + "x_ofs": 0, + "y_ofs": -100, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_reserved_time", + "desc": "拔枪剩余时间", + "type": "label", + "properties": { + "text": "04:24", + "x_ofs": 0, + "y_ofs": -60, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_reserved_tip", + "desc": "", + "type": "label", + "properties": { + "text": "Plug in first", + "x_ofs": 0, + "y_ofs": -15, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_reserved_divider", + "desc": "分割线", + "type": "flex", + "properties": { + "width": 203, + "height": 1, + "x_ofs": 30, + "y_ofs": 139, + "align": "LV_ALIGN_TOP_LEFT", + "style": "style-split" + } + }, + { + "name": "price_reserved_current", + "type": "fragment", + "fragment_name" : "fragment_price_current", + "properties": { + "x":20, + "y":168 + } + }, + { + "name": "ocpp_price", + "desc": "ocpp价格", + "type": "fragment", + "fragment_name": "fragment_ocpp_price", + "properties": { + "x": 0, + "y": 140 + } + } + ] +} diff --git a/assets/layout/layout_067_price_reserved_no_price.json b/assets/layout/layout_067_price_reserved_no_price.json new file mode 100644 index 000000000..82a84b019 --- /dev/null +++ b/assets/layout/layout_067_price_reserved_no_price.json @@ -0,0 +1,59 @@ +{ + "name": "price_reserved_no_price", + "desc": "预约界面信息", + "type": "flex", + "properties": { + "width": 263, + "height": 280, + "x": 497, + "y": 140, + "style": "style-info_card" + }, + "children": [ + { + "name": "price_reserved_title", + "desc": "预约剩余时间文本", + "type": "label", + "properties": { + "text": "Left", + "x_ofs": 0, + "y_ofs": -65, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-connector-quad-default-type-text", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_reserved_time", + "desc": "拔枪剩余时间", + "type": "label", + "properties": { + "text": "04:24", + "x_ofs": 0, + "y_ofs": -20, + "width": 200, + "height": 30, + "align": "LV_ALIGN_CENTER", + "style": "style-estimated_cost", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + }, + { + "name": "price_reserved_tip", + "desc": "", + "type": "label", + "properties": { + "text": "Plug in first", + "x_ofs": 0, + "y_ofs": 35, + "width": 235, + "height": 40, + "align": "LV_ALIGN_CENTER", + "style": "style-finished~", + "text_align": "LV_TEXT_ALIGN_CENTER" + } + } + ] +} diff --git a/assets/style/style-000-default.json b/assets/style/style-000-default.json new file mode 100644 index 000000000..c35dc0a82 --- /dev/null +++ b/assets/style/style-000-default.json @@ -0,0 +1,557 @@ +{ + "name": "default", + "description": "Default style", + "version": "1.0.0", + "styles": [ + { + "name": "style-background-primary", + "bg_color_name": "background_primary", + "border_radius": 0, + "border_width": 0, + "padding": 0 + }, + { + "name": "style-background-test" , + "bg_color_name": "primary", + "border_radius": 0, + "border_width": 0, + "padding": 0 + }, + { + "name": "style-connector-quad-default", + "bg_color_name": "background_primary", + "border_color_name": "split", + "border_width": 1, + "border_radius": 6 + }, + { + "name": "style-connector-dual-checked", + "bg_color_name": "state_idle_success", + "opacity": 16, + "border_color_name": "state_idle_success", + "border_width": 1, + "border_radius": 6 + }, + { + "name": "style-connector-quad-default-num-border", + "bg_color_name": "state_idle_success", + "width": 34, + "height": 34, + "border_width": 0, + "border_radius": 6 + }, + { + "name": "style-connector-quad-default-num-text", + "font_name": "num_notice", + "text_color_name": "background_primary" + }, + { + "name": "style-connector-quad-default-state-text", + "font_name": "title", + "text_color_name": "state_idle_success" + }, + { + "name": "style-connector-quad-default-type-text", + "font_name": "button", + "text_color_name": "text_primary" + }, + { + "name": "style-connector-quad-default-power-text", + "font_name": "primary", + "text_color_name": "text_primary" + }, + { + "name": "style-button-big-normal", + "bg_color_name": "primary", + "width": 200, + "height": 40, + "border_radius": 20 + }, + { + "name": "style-button-big-diable", + "bg_color_name": "primary", + "width": 200, + "height": 40, + "border_radius": 20, + "opacity": 30 + }, + { + "name": "style-button-small-normal", + "bg_color_name": "background_primary", + "width": 180, + "height": 40, + "border_color_name": "split", + "border_width": 1, + "border_radius": 30 + }, + { + "name": "style-button-small-select", + "bg_color_name": "background_secondary", + "width": 180, + "height": 40, + "border_color_name": "split", + "border_width": 1, + "border_radius": 30 + }, + { + "name": "style-button-small-disable", + "bg_color_name": "background_secondary", + "width": 180, + "height": 40, + "border_color_name": "split", + "border_width": 1, + "border_radius": 30 + }, + { + "name": "style-text-primary", + "font_name": "button", + "text_color_name": "text_primary" + }, + { + "name": "style-button-help-language", + "bg_color_name": "background_primary", + "width": 130, + "height": 40, + "border_color_name": "split", + "border_width": 1, + "border_radius": 20, + "padding": 0, + "opacity": 0 + }, + { + "name": "style-checkbox", + "bg_color_name": "background_primary", + "border_color_name": "split", + "border_width": 1, + "border_radius": 6, + "padding": 0, + "opacity": 0 + }, + { + "name": "style-plug_label", + "font_name": "title", + "text_color_name": "text_primary" + }, + { + "name": "style-plug_prompt", + "font_name": "primary", + "text_color_name": "text_primary" + }, + { + "name": "style-info_card", + "bg_color_name": "background_secondary", + "border_radius": 6, + "padding": 0 + }, + { + "name": "style-current_time", + "font_name": "num_primary", + "text_color_name": "text_primary" + }, + { + "name": "style-split", + "bg_color_name": "split" + }, + { + "name": "style-type_power", + "font_name": "primary24", + "text_color_name": "text_primary" + }, + { + "name": "style-idle-num-border", + "bg_color_name": "state_idle_success", + "width": 70, + "height": 70, + "border_width": 0, + "border_radius": 6 + }, + { + "name": "style-idle-num-text", + "font_name": "num_primary_40", + "text_color_name": "background_primary" + }, + { + "name": "style-idle-status", + "font_name": "title", + "text_color_name": "state_idle_success" + }, + { + "name": "style-idle-curtime-circle", + "bg_color_name": "state_idle_success", + "border_width": 0, + "border_radius": 100 + }, + { + "name": "style-idle-netper-circle", + "bg_color_name": "state_warn_suspend", + "border_width": 0, + "border_radius": 100 + }, + { + "name": "style-starting1-status", + "font_name": "title", + "text_color_name": "state_charging" + }, + { + "name": "style-reserved-status", + "font_name": "title", + "text_color_name": "state_reserve" + }, + { + "name": "style-unavaliable-status", + "font_name": "title", + "text_color_name": "state_unavaliable" + }, + { + "name": "style-starting1-num-border", + "bg_color_name": "state_charging", + "width": 70, + "height": 70, + "border_width": 0, + "border_radius": 6 + }, + { + "name": "style-estimated_cost", + "font_name": "num_notice", + "text_color_name": "text_primary" + }, + { + "name": "style-charging_settle_unit", + "font_name": "text_secondary", + "text_color_name": "text_primary" + }, + { + "name": "style-charging_info_unit", + "font_name": "primary12", + "text_color_name": "text_primary" + }, + { + "name": "style-detailed_data_charging", + "bg_color_name": "background_primary", + "width": 200, + "height": 40, + "border_width": 0, + "border_radius": 20 + }, + { + "name": "style-finished~", + "font_name": "primary", + "text_color_name": "text_primary" + }, + { + "name": "style-session_error_circle", + "bg_color_name": "error", + "border_width": 0, + "border_radius": 100 + }, + { + "name": "style-session_error-num-border", + "bg_color_name": "error", + "width": 70, + "height": 70, + "border_width": 0, + "border_radius": 6 + }, + { + "name": "style-session_error-status", + "font_name": "title", + "text_color_name": "error" + }, + { + "name": "style-session_error-circle", + "bg_color_name": "error", + "width": 60, + "height": 60, + "border_radius": 100, + "border_width": 0 + }, + { + "name": "style-draw_icon_symbol", + "font_name": "primary50", + "text_color_name": "background_primary" + }, + { + "name": "style-continue_button_session_error", + "bg_color_name": "text_primary", + "width": 200, + "height": 40, + "border_width": 0, + "border_radius": 20 + }, + { + "name": "style-continue_label_session_error", + "font_name": "button", + "text_color_name": "background_primary" + }, + { + "name": "style-X_start", + "font_name": "primary30", + "text_color_name": "error" + }, + { + "name": "style-fault-status", + "font_name": "title", + "text_color_name": "state_unavaliable" + }, + { + "name": "style-unavailable-num-border", + "bg_color_name": "state_unavaliable", + "width": 70, + "height": 70, + "border_width": 0, + "border_radius": 6 + }, + { + "name": "style-X_unavailable", + "font_name": "primary30", + "text_color_name": "state_unavaliable" + }, + { + "name": "style-help1-background", + "bg_color_name": "background_primary", + "border_radius": 6, + "border_width": 0, + "padding": 0 + }, + { + "name": "style-help1_status_bar", + "bg_color_name": "background_secondary", + "border_radius": 6, + "padding": 0, + "border_width":0 + }, + { + "name": "style-connection_failed-circle", + "bg_color_name": "state_warn_suspend", + "width": 80, + "height": 80, + "border_radius": 100, + "border_width": 0 + }, + { + "name": "style-amount", + "bg_color_name": "state_charging", + "border_radius": 30, + "padding": 0, + "opacity": 16, + "border_width": 1, + "border_color_name":"state_charging" + }, + { + "name": "style-shortcut_button_pre_authorization", + "bg_color_name": "background_primary", + "width": 180, + "height": 40, + "border_width": 1, + "border_color_name": "split", + "border_radius": 30 + }, + { + "name": "style-num_button_pre_authorization", + "bg_color_name": "background_secondary", + "width": 60, + "height": 60, + "border_radius": 4 + }, + { + "name": "style-suspend-num-border", + "bg_color_name": "state_warn_suspend", + "width": 70, + "height": 70, + "border_width": 0, + "border_radius": 6 + }, + { + "name": "style-suspend-circle", + "bg_color_name": "state_warn_suspend", + "width": 80, + "height": 80, + "border_radius": 100, + "border_width": 0 + }, + { + "name": "style-suspend-status", + "font_name": "title", + "text_color_name": "state_warn_suspend" + }, + { + "name": "style-connector-trip-default", + "bg_color_name": "background_primary", + "width": 248, + "height": 123, + "border_color_name": "split", + "border_width": 1, + "border_radius": 6 + }, + { + "name": "style-connector-trip-checked", + "bg_color_name": "state_idle_success", + "opacity": 16, + "width": 248, + "height": 123, + "border_color_name": "state_idle_success", + "border_width": 1, + "border_radius": 6 + }, + { + "name": "style-connector-dual-default-num-border", + "bg_color_name": "state_idle_success", + "width": 123, + "height": 123, + "border_width": 0, + "border_radius": 0 + }, + { + "name": "style-connector-dual-default-num-text", + "font_name": "num_primary_40", + "text_color_name": "background_primary" + }, + { + "name": "style-connector-dual-default-character", + "font_name": "primary35", + "text_color_name": "background_primary" + }, + { + "name": "style-connector-dual-default", + "bg_color_name": "background_primary", + "width": 376, + "height": 123, + "border_color_name": "split", + "border_width": 1, + "border_radius": 6 + }, + { + "name": "style-connector-dual-checked", + "bg_color_name": "state_idle_success", + "opacity": 16, + "width": 376, + "height": 123, + "border_color_name": "state_idle_success", + "border_width": 1, + "border_radius": 6 + }, + { + "name": "style-connector-dual-checked-charging", + "bg_color_name": "state_charging", + "opacity": 16, + "border_color_name": "state_charging", + "border_width": 1, + "border_radius": 6 + }, + { + "name": "style-connector-dual-checked-state_reserve", + "bg_color_name": "state_reserve", + "opacity": 16, + "border_color_name": "state_reserve", + "border_width": 1, + "border_radius": 6 + }, + { + "name": "style-connector-dual-checked-state_fault", + "bg_color_name": "state_fault", + "opacity": 16, + "border_color_name": "state_fault", + "border_width": 1, + "border_radius": 6 + }, + { + "name": "style-connector-dual-checked-state_unavaliable", + "bg_color_name": "state_unavaliable", + "opacity": 16, + "border_color_name": "state_unavaliable", + "border_width": 1, + "border_radius": 6 + }, + { + "name": "style-connector-dual-checked-state_warn_suspend", + "bg_color_name": "state_warn_suspend", + "opacity": 16, + "border_color_name": "state_warn_suspend", + "border_width": 1, + "border_radius": 6 + }, + { + "name": "style-reserved-num-border", + "bg_color_name": "state_reserve", + "width": 70, + "height": 70, + "border_width": 0, + "border_radius": 6 + }, + { + "name": "style-charging_bar_bg_size", + "bg_color_name": "background_secondary", + "width": 156, + "height": 20, + "border_width": 0, + "border_radius": 13 + }, + { + "name": "style-charging_bar_bg_size2", + "bg_color_name": "background_secondary", + "width": 212, + "height": 20, + "border_width": 0, + "border_radius": 13 + }, + { + "name": "style-charging_bar_bg_size3", + "bg_color_name": "background_secondary", + "width": 206, + "height": 20, + "border_width": 0, + "border_radius": 13 + }, + { + "name": "style-charging_bar_indic", + "bg_color_name": "state_charging" + }, + { + "name": "style-charging_time_cost", + "bg_color_name": "background_primary", + "width": 168, + "height": 20, + "border_radius": 20, + "border_color_name": "background_primary" + }, + { + "name": "style-pre_authorization_delete_btn", + "font_name": "primary30", + "text_color_name": "text_primary" + }, + { + "name": "style-mid_container_top", + "bg_color_name": "background_primary", + "border_width": 0, + "border_radius": 0, + "padding": 0, + "opacity": 0 + }, + { + "name": "language_checked", + "bg_color_name": "split" + }, + { + "name": "language_unchecked", + "bg_color_name": "background_primary" + }, + { + "name": "style-info_card_half", + "bg_color_name": "background_secondary", + "border_radius": 0, + "padding": 0, + "border_width": 0 + }, + { + "name": "style-primary_bg", + "bg_color_name": "background_primary", + "border_width": 0 + }, + { + "name": "style-label_combine_bg", + "padding": 0, + "border_width": 0, + "opacity": 0 + } + ] +} diff --git a/assets/theme/theme-000-main-light.json b/assets/theme/theme-000-main-light.json new file mode 100644 index 000000000..5333d5cff --- /dev/null +++ b/assets/theme/theme-000-main-light.json @@ -0,0 +1,401 @@ +{ + "name": "main-light", + "version": "0.0.1", + "description": "main-light theme", + "colors" :[ + {"name": "primary", "value": "#005350"}, + {"name": "state_idle_success", "value": "#52C41A"}, + {"name": "state_charging", "value": "#32D9D1"}, + {"name": "state_reserve", "value": "#1677ff"}, + {"name": "state_warn_suspend", "value": "#FAAD14"}, + {"name": "state_fault", "value": "#FA4D4F"}, + {"name": "state_unavaliable", "value": "#8C9AA4"}, + {"name": "text_primary", "value": "#333333"}, + {"name": "text_secondary", "value": "#999999"}, + {"name": "split", "value": "#E7E7E7"}, + {"name": "background_primary", "value": "#FFFFFF"}, + {"name": "background_secondary", "value": "#F3F3F3"}, + {"name": "background_prompt", "value": "#000000"}, + {"name": "error", "value": "#FF4D4F"} + ], + "fonts": [ + {"name": "title", "family": "./assets/fonts/calibrib.ttf", "size": 24, "bold": true}, + {"name": "button", "family": "./assets/fonts/calibrib.ttf", "size": 18, "bold": true}, + {"name": "primary", "family": "./assets/fonts/calibri.ttf", "size": 18, "bold": false}, + {"name": "primary12", "family": "./assets/fonts/calibri.ttf", "size": 12, "bold": false}, + {"name": "primary24", "family": "./assets/fonts/calibri.ttf", "size": 24, "bold": false}, + {"name": "primary30", "family": "./assets/fonts/calibrib.ttf", "size": 30, "bold": true}, + {"name": "primary40", "family": "./assets/fonts/calibrib.ttf", "size": 40, "bold": true}, + {"name": "primary50", "family": "./assets/fonts/calibrib.ttf", "size": 50, "bold": true}, + {"name": "text_secondary", "family": "./assets/fonts/calibri.ttf", "size": 18, "bold": false}, + {"name": "num_notice", "family": "./assets/fonts/D-DIN-PRO-600-SemiBold.otf", "size": 28, "bold": true}, + {"name": "num_primary", "family": "./assets/fonts/D-DIN-PRO-600-SemiBold.otf", "size": 18, "bold": true}, + {"name": "num_primary_40", "family": "./assets/fonts/D-DIN-PRO-600-SemiBold.otf", "size": 40, "bold": true} + ], + "images": [ + { + "name": "sever_on", + "path": "A:./assets/images/sever_on.png" + }, + { + "name": "portugal", + "path": "A:./assets/images/Portugal.png" + }, + { + "name": "europe_2connect", + "path": "A:./assets/images/Europe_2connect.png" + }, + { + "name": "bg_data-display_finished", + "path": "A:./assets/images/bg_data display_finished.png" + }, + { + "name": "ccs2-dc_2connect", + "path": "A:./assets/images/CCS2-DC_2connect.png" + }, + { + "name": "icon_authorized", + "path": "A:./assets/images/icon_Authorized.png" + }, + { + "name": "turkey", + "path": "A:./assets/images/Turkey.png" + }, + { + "name": "france", + "path": "A:./assets/images/France.png" + }, + { + "name": "icon_error", + "path": "A:./assets/images/icon_error.png" + }, + { + "name": "italy", + "path": "A:./assets/images/Italy.png" + }, + { + "name": "j1772_2connect", + "path": "A:./assets/images/J1772_2connect.png" + }, + { + "name": "battery4", + "path": "A:./assets/images/battery4.png" + }, + { + "name": "icon_stopping", + "path": "A:./assets/images/icon_stopping.png" + }, + { + "name": "poland", + "path": "A:./assets/images/Poland.png" + }, + { + "name": "wifi_err", + "path": "A:./assets/images/wifi_err.png" + }, + { + "name": "icon_inmation", + "path": "A:./assets/images/icon_inmation.png" + }, + { + "name": "logo_plug&charge_2", + "path": "A:./assets/images/LOGO_plug&charge_2.png" + }, + { + "name": "english", + "path": "A:./assets/images/English.png" + }, + { + "name": "rf_err", + "path": "A:./assets/images/rf_err.png" + }, + { + "name": "sever_off", + "path": "A:./assets/images/sever_off.png" + }, + { + "name": "rf_on", + "path": "A:./assets/images/rf_on.png" + }, + { + "name": "btn_virtual-keyboard_delete", + "path": "A:./assets/images/btn_Virtual keyboard_delete.png" + }, + { + "name": "gb-ac_2connect", + "path": "A:./assets/images/GB-AC_2connect.png" + }, + { + "name": "icon_telephone", + "path": "A:./assets/images/icon_Telephone.png" + }, + { + "name": "gb-t-ac_1connect", + "path": "A:./assets/images/GB-T-AC_1connect.png" + }, + { + "name": "ccs2-dc", + "path": "A:./assets/images/CCS2-DC.png" + }, + { + "name": "germany", + "path": "A:./assets/images/Germany.png" + }, + { + "name": "icon_right-connector", + "path": "A:./assets/images/icon_right connector.png" + }, + { + "name": "icon_url", + "path": "A:./assets/images/icon_URL.png" + }, + { + "name": "gb-dc_1connect", + "path": "A:./assets/images/GB-DC_1connect.png" + }, + { + "name": "hong-kong", + "path": "A:./assets/images/Hong Kong.png" + }, + { + "name": "chademo", + "path": "A:./assets/images/CHADEMO.png" + }, + { + "name": "thailand", + "path": "A:./assets/images/Thailand.png" + }, + { + "name": "logo", + "path": "A:./assets/images/LOGO.png" + }, + { + "name": "romania", + "path": "A:./assets/images/Romania.png" + }, + { + "name": "bg_data-display_charging", + "path": "A:./assets/images/bg_data display_Charging.png" + }, + { + "name": "parking-diagram", + "path": "A:./assets/images/Parking diagram.png" + }, + { + "name": "meter_off", + "path": "A:./assets/images/meter_off.png" + }, + { + "name": "car2", + "path": "A:./assets/images/car2.png" + }, + { + "name": "europe", + "path": "A:./assets/images/Europe.png" + }, + { + "name": "battery1", + "path": "A:./assets/images/battery1.png" + }, + { + "name": "lang_china", + "path": "A:./assets/images/lang_China.png" + }, + { + "name": "4g_err", + "path": "A:./assets/images/4g_err.png" + }, + { + "name": "chademo_2connect", + "path": "A:./assets/images/CHADEMO_2connect.png" + }, + { + "name": "icon_current-time", + "path": "A:./assets/images/icon_Current time.png" + }, + { + "name": "icon_charging-station", + "path": "A:./assets/images/icon_Charging station.png" + }, + { + "name": "car", + "path": "A:./assets/images/car.png" + }, + { + "name": "icon_loading", + "path": "A:./assets/images/icon_Loading.png" + }, + { + "name": "gb-t-ac", + "path": "A:./assets/images/GB-T-AC.png" + }, + { + "name": "battery2", + "path": "A:./assets/images/battery2.png" + }, + { + "name": "gb-t-ac_2connect", + "path": "A:./assets/images/GB-T-AC_2connect.png" + }, + { + "name": "rf_off", + "path": "A:./assets/images/rf_off.png" + }, + { + "name": "icon_left-connector", + "path": "A:./assets/images/icon_left connector.png" + }, + { + "name": "wifi_off", + "path": "A:./assets/images/wifi_off.png" + }, + { + "name": "wifi_on", + "path": "A:./assets/images/wifi_on.png" + }, + { + "name": "pic_pos", + "path": "A:./assets/images/pic_pos.png" + }, + { + "name": "j1772", + "path": "A:./assets/images/J1772.png" + }, + { + "name": "net_err", + "path": "A:./assets/images/net_err.png" + }, + { + "name": "gb-ac_1connect", + "path": "A:./assets/images/GB-AC_1connect.png" + }, + { + "name": "hint-map", + "path": "A:./assets/images/hint map.png" + }, + { + "name": "j1772_1connect", + "path": "A:./assets/images/J1772_1connect.png" + }, + { + "name": "gb-ac", + "path": "A:./assets/images/GB-AC.png" + }, + { + "name": "icon_connected", + "path": "A:./assets/images/icon_Connected.png" + }, + { + "name": "meter_err", + "path": "A:./assets/images/meter_err.png" + }, + { + "name": "meter_on", + "path": "A:./assets/images/meter_on.png" + }, + { + "name": "ccs2-dc_1connect", + "path": "A:./assets/images/CCS2-DC_1connect.png" + }, + { + "name": "4g_on", + "path": "A:./assets/images/4g_on.png" + }, + { + "name": "battery3", + "path": "A:./assets/images/battery3.png" + }, + { + "name": "net_off", + "path": "A:./assets/images/net_off.png" + }, + { + "name": "icon_warning_1", + "path": "A:./assets/images/icon_warning_1.png" + }, + { + "name": "sever_err", + "path": "A:./assets/images/sever_err.png" + }, + { + "name": "netherlands", + "path": "A:./assets/images/Netherlands.png" + }, + { + "name": "lang_arab", + "path": "A:./assets/images/lang_Arab.png" + }, + { + "name": "finland", + "path": "A:./assets/images/Finland.png" + }, + { + "name": "icon_next-period", + "path": "A:./assets/images/icon_Next period.png" + }, + { + "name": "gb-dc_2connect", + "path": "A:./assets/images/GB-DC_2connect.png" + }, + { + "name": "chademo_1connect", + "path": "A:./assets/images/CHADEMO_1connect.png" + }, + { + "name": "net_on", + "path": "A:./assets/images/net_on.png" + }, + { + "name": "icon_contact", + "path": "A:./assets/images/icon_contact.png" + }, + { + "name": "lang_albania", + "path": "A:./assets/images/lang_Albania.png" + }, + { + "name": "spain", + "path": "A:./assets/images/Spain.png" + }, + { + "name": "icon_charging-pile", + "path": "A:./assets/images/icon_Charging pile.png" + }, + { + "name": "russia", + "path": "A:./assets/images/Russia.png" + }, + { + "name": "czech-republic", + "path": "A:./assets/images/Czech Republic.png" + }, + { + "name": "europe_1connect", + "path": "A:./assets/images/Europe_1connect.png" + }, + { + "name": "car1", + "path": "A:./assets/images/car1.png" + }, + { + "name": "icon_warning_2", + "path": "A:./assets/images/icon_warning_2.png" + }, + { + "name": "gb-dc", + "path": "A:./assets/images/GB-DC.png" + }, + { + "name": "4g_off", + "path": "A:./assets/images/4g_off.png" + }, + { + "name": "charging", + "path": "A:./assets/images/charging.gif" + }, + { + "name": "processing", + "path": "A:./assets/images/processing.gif" + } + ] +} diff --git a/assets/theme/theme-001-main-dark.json b/assets/theme/theme-001-main-dark.json new file mode 100644 index 000000000..78ec6b1b6 --- /dev/null +++ b/assets/theme/theme-001-main-dark.json @@ -0,0 +1,32 @@ +{ + "name": "main-dark", + "version": "0.0.1", + "description": "main-dark theme", + "colors" :[ + {"name": "primary", "value": "#005350"}, + {"name": "state_idle_success", "value": "#F2C41A"}, + {"name": "state_charging", "value": "#32D9D1"}, + {"name": "state_reserve", "value": "#1677ff"}, + {"name": "state_warn_suspend", "value": "#FAAD14"}, + {"name": "state_fault", "value": "#FA4D4F"}, + {"name": "state_unavaliable", "value": "#8C9AA4"}, + {"name": "text_primary", "value": "#333333"}, + {"name": "text_secondary", "value": "#999999"}, + {"name": "split", "value": "#E7E7E7"}, + {"name": "background_primary", "value": "#FFFFFF"}, + {"name": "background_secondary", "value": "#F3F3F3"}, + {"name": "background_prompt", "value": "#000000"} + ], + "fonts": [ + {"name": "title", "family": "./assets/fonts/calibrib.ttf", "size": 24, "bold": true}, + {"name": "button", "family": "./assets/fonts/calibrib.ttf", "size": 18, "bold": true}, + {"name": "primary", "family": "./assets/fonts/calibri.ttf", "size": 16, "bold": false}, + {"name": "num_notice", "family": "./assets/fonts/D-DIN-PRO-600-SemiBold.otf", "size": 28, "bold": true}, + {"name": "num_primary", "family": "./assets/fonts/D-DIN-PRO-600-SemiBold.otf", "size": 18, "bold": true} + ], + "images": [ + {"name": "logo", "path": "A:./assets/images/LOGO.png"}, + {"name": "english", "path": "A:./assets/images/english.png"}, + {"name": "ccs2-dc", "path": "A:./assets/images/CCS2-DC.png"} + ] +} diff --git a/assets/theme/theme-100-main-light-abacus.json b/assets/theme/theme-100-main-light-abacus.json new file mode 100644 index 000000000..6e5bba05d --- /dev/null +++ b/assets/theme/theme-100-main-light-abacus.json @@ -0,0 +1,11 @@ +{ + "name": "main-light-abacus", + "version": "0.0.1", + "description": "main-light abacus patch", + "colors" :[ + ], + "fonts": [ + ], + "images": [ + ] +} diff --git a/i18n/lv_i18n.c b/i18n/lv_i18n.c new file mode 100644 index 000000000..b5baaf1aa --- /dev/null +++ b/i18n/lv_i18n.c @@ -0,0 +1,415 @@ +#include "./lv_i18n.h" +#include "../pages/ui_popup_language.h" + +//////////////////////////////////////////////////////////////////////////////// +// Define plural operands +// http://unicode.org/reports/tr35/tr35-numbers.html#Operands + +// Integer version, simplified + +#define UNUSED(x) (void)(x) + +static inline uint32_t op_n(int32_t val) { return (uint32_t)(val < 0 ? -val : val); } +static inline uint32_t op_i(uint32_t val) { return val; } +// always zero, when decimal part not exists. +static inline uint32_t op_v(uint32_t val) { UNUSED(val); return 0;} +static inline uint32_t op_w(uint32_t val) { UNUSED(val); return 0; } +static inline uint32_t op_f(uint32_t val) { UNUSED(val); return 0; } +static inline uint32_t op_t(uint32_t val) { UNUSED(val); return 0; } + +// 英语 +static lv_i18n_phrase_t en_us_singulars[] = { +}; + + +static uint8_t en_us_plural_fn(int32_t num) +{ + uint32_t n = op_n(num); UNUSED(n); + uint32_t i = op_i(n); UNUSED(i); + uint32_t v = op_v(n); UNUSED(v); + + if ((i == 1 && v == 0)) return LV_I18N_PLURAL_TYPE_ONE; + return LV_I18N_PLURAL_TYPE_OTHER; +} + +static lv_i18n_lang_t en_us_lang = { + .locale_name = "en-US", + .singulars = NULL, + + .locale_plural_fn = en_us_plural_fn +}; + +// 德语 +static lv_i18n_phrase_t de_de_singulars[] = { + {NULL, NULL}, // End mark +}; + + +static uint8_t de_de_plural_fn(int32_t num) +{ + uint32_t n = op_n(num); UNUSED(n); + uint32_t i = op_i(n); UNUSED(i); + uint32_t v = op_v(n); UNUSED(v); + + if ((i == 1 && v == 0)) return LV_I18N_PLURAL_TYPE_ONE; + return LV_I18N_PLURAL_TYPE_OTHER; +} + +static lv_i18n_lang_t de_de_lang = { + .locale_name = "de-DE", + .singulars = NULL, + + .locale_plural_fn = de_de_plural_fn +}; + +// 希腊语 +static lv_i18n_phrase_t el_gr_singulars[] = { + +}; + + +static uint8_t el_gr_plural_fn(int32_t num) +{ + uint32_t n = op_n(num); UNUSED(n); + + + if ((n == 1)) return LV_I18N_PLURAL_TYPE_ONE; + return LV_I18N_PLURAL_TYPE_OTHER; +} + +static lv_i18n_lang_t el_gr_lang = { + .locale_name = "el-GR", + .singulars = NULL, + + .locale_plural_fn = el_gr_plural_fn +}; + +// 西班牙语 +static lv_i18n_phrase_t es_es_singulars[] = { + {NULL, NULL}, // End mark +}; + + + +static uint8_t es_es_plural_fn(int32_t num) +{ + uint32_t n = op_n(num); UNUSED(n); + + + if ((n == 1)) return LV_I18N_PLURAL_TYPE_ONE; + return LV_I18N_PLURAL_TYPE_OTHER; +} + +static lv_i18n_lang_t es_es_lang = { + .locale_name = "es-ES", + .singulars = NULL, + + .locale_plural_fn = es_es_plural_fn +}; + +// 芬兰语 +static lv_i18n_phrase_t fi_fi_singulars[] = { + {NULL, NULL}, // End mark +}; + + + +static uint8_t fi_fi_plural_fn(int32_t num) +{ + uint32_t n = op_n(num); UNUSED(n); + uint32_t i = op_i(n); UNUSED(i); + uint32_t v = op_v(n); UNUSED(v); + + if ((i == 1 && v == 0)) return LV_I18N_PLURAL_TYPE_ONE; + return LV_I18N_PLURAL_TYPE_OTHER; +} + +static lv_i18n_lang_t fi_fi_lang = { + .locale_name = "fi-FI", + .singulars = NULL, + + .locale_plural_fn = fi_fi_plural_fn +}; + +// 法语 +static lv_i18n_phrase_t fr_fr_singulars[] = { + {NULL,NULL} +} ; + + + +static uint8_t fr_fr_plural_fn(int32_t num) +{ + uint32_t n = op_n(num); UNUSED(n); + uint32_t i = op_i(n); UNUSED(i); + + if ((((i == 0) || (i == 1)))) return LV_I18N_PLURAL_TYPE_ONE; + return LV_I18N_PLURAL_TYPE_OTHER; +} + +static lv_i18n_lang_t fr_fr_lang = { + .locale_name = "fr-FR", + .singulars = NULL, + + .locale_plural_fn = fr_fr_plural_fn +}; + +// 意大利语 +static lv_i18n_phrase_t it_it_singulars[] = { + {NULL,NULL} +} ; + +static uint8_t it_it_plural_fn(int32_t num) +{ + uint32_t n = op_n(num); UNUSED(n); + uint32_t i = op_i(n); UNUSED(i); + uint32_t v = op_v(n); UNUSED(v); + + if ((i == 1 && v == 0)) return LV_I18N_PLURAL_TYPE_ONE; + return LV_I18N_PLURAL_TYPE_OTHER; +} + +static lv_i18n_lang_t it_it_lang = { + .locale_name = "it-IT", + .singulars = NULL, + + .locale_plural_fn = it_it_plural_fn +}; + + +// 葡萄牙语 +static lv_i18n_phrase_t pt_pt_singulars[] = { + {NULL,NULL} +} ; + +static uint8_t pt_pt_plural_fn(int32_t num) +{ + uint32_t n = op_n(num); UNUSED(n); + uint32_t i = op_i(n); UNUSED(i); + uint32_t v = op_v(n); UNUSED(v); + + if ((i == 1 && v == 0)) return LV_I18N_PLURAL_TYPE_ONE; + return LV_I18N_PLURAL_TYPE_OTHER; +} + +static lv_i18n_lang_t pt_pt_lang = { + .locale_name = "pt-PT", + .singulars = NULL, + .locale_plural_fn = pt_pt_plural_fn +}; + +// 荷兰语 +static lv_i18n_phrase_t nl_nl_singulars[] = { + {NULL, NULL}, // End mark +}; + + + +static uint8_t nl_nl_plural_fn(int32_t num) +{ + uint32_t n = op_n(num); UNUSED(n); + uint32_t i = op_i(n); UNUSED(i); + uint32_t v = op_v(n); UNUSED(v); + + if ((i == 1 && v == 0)) return LV_I18N_PLURAL_TYPE_ONE; + return LV_I18N_PLURAL_TYPE_OTHER; +} + +static lv_i18n_lang_t nl_nl_lang = { + .locale_name = "nl-NL", + .singulars = NULL, + + .locale_plural_fn = nl_nl_plural_fn +}; + +// 俄语 +static lv_i18n_phrase_t ru_ru_singulars[] = { + {NULL,NULL} +} ; + +static uint8_t ru_ru_plural_fn(int32_t num) +{ + uint32_t n = op_n(num); UNUSED(n); + uint32_t v = op_v(n); UNUSED(v); + uint32_t i = op_i(n); UNUSED(i); + uint32_t i10 = i % 10; + uint32_t i100 = i % 100; + if ((v == 0 && i10 == 1 && i100 != 11)) return LV_I18N_PLURAL_TYPE_ONE; + if ((v == 0 && (2 <= i10 && i10 <= 4) && (!(12 <= i100 && i100 <= 14)))) return LV_I18N_PLURAL_TYPE_FEW; + if ((v == 0 && i10 == 0) || (v == 0 && (5 <= i10 && i10 <= 9)) || (v == 0 && (11 <= i100 && i100 <= 14))) return LV_I18N_PLURAL_TYPE_MANY; + return LV_I18N_PLURAL_TYPE_OTHER; +} + +static lv_i18n_lang_t ru_ru_lang = { + .locale_name = "ru-RU", + .singulars = NULL, + + .locale_plural_fn = ru_ru_plural_fn +}; + +lv_i18n_language_pack_t lv_i18n_language_pack[] = { + &en_us_lang, + &de_de_lang, + &el_gr_lang, + &es_es_lang, + &fi_fi_lang, + &fr_fr_lang, + &it_it_lang, + &pt_pt_lang, + &nl_nl_lang, + &ru_ru_lang, + NULL // End mark +}; + +//////////////////////////////////////////////////////////////////////////////// + + +// Internal state +static lv_i18n_language_pack_t * current_lang_pack; +static lv_i18n_lang_t * current_lang; + + +lv_i18n_lang_t * current_lang_point; +/** + * Reset internal state. For testing. + */ +void __lv_i18n_reset(void) +{ + current_lang_pack = NULL; + current_lang = NULL; +} + +/** + * Set the languages for internationalization + * @param langs pointer to the array of languages. (Last element has to be `NULL`) + */ +int lv_i18n_init(lv_i18n_language_pack_t * langs) +{ + if(langs == NULL) return -1; + if(langs[0] == NULL) return -1; + + current_lang_pack = langs; + current_lang = langs[0]; /*Automatically select the first language*/ + parse_all_lang_jsons(); + + return 0; +} + +/** + * Change the localization (language) + * @param l_name name of the translation locale to use. E.g. "en-GB" + */ +int lv_i18n_set_locale(const char * l_name) +{ + if(current_lang_pack == NULL) return -1; + + uint16_t i; + + for(i = 0; current_lang_pack[i] != NULL; i++) { + // Found -> finish + if(strcmp(current_lang_pack[i]->locale_name, l_name) == 0) { + current_lang = current_lang_pack[i]; + current_lang_point = current_lang; + return 0; + } + } + + return -1; +} + + +static const char * __lv_i18n_get_text_core(lv_i18n_phrase_t * trans, const char * msg_id) +{ + uint16_t i; + for(i = 0; trans[i].msg_id != NULL; i++) { + if(strcmp(trans[i].msg_id, msg_id) == 0) { + /*The msg_id has found. Check the translation*/ + if(trans[i].translation) return trans[i].translation; + } + } + + return NULL; +} + + +/** + * Get the translation from a message ID + * @param msg_id message ID + * @return the translation of `msg_id` on the set local + */ +const char * lv_i18n_get_text(const char * msg_id) +{ + if(current_lang == NULL) return msg_id; + + const lv_i18n_lang_t * lang = current_lang; + const void * txt; + + // Search in current locale + if(lang->singulars != NULL) { + txt = __lv_i18n_get_text_core(lang->singulars, msg_id); + if (txt != NULL) return txt; + } + + // Try to fallback + if(lang == current_lang_pack[0]) return msg_id; + lang = current_lang_pack[0]; + + // Repeat search for default locale + if(lang->singulars != NULL) { + txt = __lv_i18n_get_text_core(lang->singulars, msg_id); + if (txt != NULL) return txt; + } + + return msg_id; +} + +/** + * Get the translation from a message ID and apply the language's plural rule to get correct form + * @param msg_id message ID + * @param num an integer to select the correct plural form + * @return the translation of `msg_id` on the set local + */ +const char * lv_i18n_get_text_plural(const char * msg_id, int32_t num) +{ + if(current_lang == NULL) return msg_id; + + const lv_i18n_lang_t * lang = current_lang; + const void * txt; + lv_i18n_plural_type_t ptype; + + // Search in current locale + if(lang->locale_plural_fn != NULL) { + ptype = lang->locale_plural_fn(num); + + if(lang->plurals[ptype] != NULL) { + txt = __lv_i18n_get_text_core(lang->plurals[ptype], msg_id); + if (txt != NULL) return txt; + } + } + + // Try to fallback + if(lang == current_lang_pack[0]) return msg_id; + lang = current_lang_pack[0]; + + // Repeat search for default locale + if(lang->locale_plural_fn != NULL) { + ptype = lang->locale_plural_fn(num); + + if(lang->plurals[ptype] != NULL) { + txt = __lv_i18n_get_text_core(lang->plurals[ptype], msg_id); + if (txt != NULL) return txt; + } + } + + return msg_id; +} + +/** + * Get the name of the currently used locale. + * @return name of the currently used locale. E.g. "en-GB" + */ +const char * lv_i18n_get_current_locale(void) +{ + if(!current_lang) return NULL; + return current_lang->locale_name; +} diff --git a/i18n/lv_i18n.h b/i18n/lv_i18n.h new file mode 100644 index 000000000..ecec677fa --- /dev/null +++ b/i18n/lv_i18n.h @@ -0,0 +1,85 @@ +#ifndef LV_I18N_H +#define LV_I18N_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef enum { + LV_I18N_PLURAL_TYPE_ZERO, + LV_I18N_PLURAL_TYPE_ONE, + LV_I18N_PLURAL_TYPE_TWO, + LV_I18N_PLURAL_TYPE_FEW, + LV_I18N_PLURAL_TYPE_MANY, + LV_I18N_PLURAL_TYPE_OTHER, + _LV_I18N_PLURAL_TYPE_NUM, +} lv_i18n_plural_type_t; + +typedef struct { + const char * msg_id; + const char * translation; +} lv_i18n_phrase_t; + +typedef struct { + const char * locale_name; + lv_i18n_phrase_t * singulars; + lv_i18n_phrase_t * plurals[_LV_I18N_PLURAL_TYPE_NUM]; + uint8_t (*locale_plural_fn)(int32_t num); +} lv_i18n_lang_t; + +// Null-terminated list of languages. First one used as default. +typedef lv_i18n_lang_t * lv_i18n_language_pack_t; + + +extern lv_i18n_language_pack_t lv_i18n_language_pack[]; +extern lv_i18n_lang_t * current_lang_point; + +/** + * Set the languages for internationalization + * @param langs pointer to the array of languages. (Last element has to be `NULL`) + */ +int lv_i18n_init(lv_i18n_language_pack_t * langs); + +/** + * Change the localization (language) + * @param l_name name of the translation locale to use. E.g. "en_GB" + */ +int lv_i18n_set_locale(const char * l_name); + +/** + * Get the translation from a message ID + * @param msg_id message ID + * @return the translation of `msg_id` on the set local + */ +const char * lv_i18n_get_text(const char * msg_id); + +/** + * Get the translation from a message ID and apply the language's plural rule to get correct form + * @param msg_id message ID + * @param num an integer to select the correct plural form + * @return the translation of `msg_id` on the set local + */ +const char * lv_i18n_get_text_plural(const char * msg_id, int32_t num); + +/** + * Get the name of the currently used localization. + * @return name of the currently used localization. E.g. "en_GB" + */ +const char * lv_i18n_get_current_locale(void); + + +void __lv_i18n_reset(void); + + +#define _(text) lv_i18n_get_text(text) +#define _p(text, num) lv_i18n_get_text_plural(text, num) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LANG_H*/ diff --git a/ioc/autoGroup.c b/ioc/autoGroup.c new file mode 100644 index 000000000..d707ea02a --- /dev/null +++ b/ioc/autoGroup.c @@ -0,0 +1,198 @@ +// #include "ioc_app.h" + +// // extern int get_local_ip(char *ip); + +// #define SERVICE_DISPLAY "UI_DISPLAY" +// #define SERVICE_DESC "LVGL" + +// #define INVALID_SOCKET_FD (-1) + +// const char* s_default_iface_name = "eth0"; + +// static int s_fd_masterBroadCast = -1; +// static uint32_t s_UdpSentTick = 0; +// static char s_devMasterIp[INET_ADDRSTRLEN] = {0}; +// static char s_sendIP[INET_ADDRSTRLEN] = {0}; +// static uint8_t s_mac_address[6] = {0}; +// static char s_mac_string[18] = {0}; + +// struct ifreq ifr; + +// uint32_t Charger_TimeNowMs(void) +// { +// // return custom_tick_get(); +// } + + +// static bool iface_get_ip() +// { +// int tmp_sock = socket(AF_INET, SOCK_DGRAM, 0); +// if (tmp_sock < 0) +// { +// LV_LOG_WARN("socket - create socket failed while get ip"); +// return false; +// } + +// if(ioctl(tmp_sock, SIOCGIFADDR, &ifr) != 0) +// { +// LV_LOG_WARN("ioctl - get ip failed"); +// close(tmp_sock); +// return false; +// } + +// struct sockaddr_in *ipaddr = (struct sockaddr_in *)&ifr.ifr_addr; +// inet_ntop(AF_INET, &ipaddr->sin_addr, s_devMasterIp, sizeof(s_devMasterIp)); +// close(tmp_sock); +// return true; +// } + + +// // 创建一个UDP服务器,成功返回 fd,失败返回 -1 +// static int MasterDevCreateUdp() +// { +// int fd = INVALID_SOCKET_FD; + +// // 创建UdpSocket +// fd = socket(AF_INET, SOCK_DGRAM, 0); +// if (fd < 0) +// { +// LV_LOG_WARN("socket err:%d, %s\n", errno, strerror(errno)); +// return INVALID_SOCKET_FD; +// } + +// // 设置超时 +// struct timeval timeOutVal; +// timeOutVal.tv_sec = 0; +// timeOutVal.tv_usec = 10; +// if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeOutVal, sizeof(timeOutVal)) < 0) +// { +// LV_LOG_WARN("SO_RCVTIMEO err:%d, %s\n", errno, strerror(errno)); +// close(fd); +// return INVALID_SOCKET_FD; +// } + +// // 支持广播 +// int opt = 1; +// if(-1 == setsockopt(fd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt))) +// { +// LV_LOG_WARN("SO_BROADCAST err:%d, %s\n", errno, strerror(errno)); +// close(fd); +// return INVALID_SOCKET_FD; +// } + +// // 绑定接口 +// if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, s_default_iface_name, strlen(s_default_iface_name)) < 0) +// { +// LV_LOG_WARN("setsockopt - bind iface failed"); +// close(fd); +// fd = -1; +// return INVALID_SOCKET_FD; +// } + +// // 获取MAC地址 +// strncpy(ifr.ifr_name, s_default_iface_name, IFNAMSIZ - 1); +// if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) +// { +// LV_LOG_WARN("ioctl failed"); +// close(fd); +// return INVALID_SOCKET_FD; +// } + +// memcpy(s_mac_address, ifr.ifr_hwaddr.sa_data, 6); + +// // 将MAC地址转成字符串格式 +// snprintf(s_mac_string, sizeof(s_mac_string), +// "%02x:%02x:%02x:%02x:%02x:%02x", +// s_mac_address[0], s_mac_address[1], s_mac_address[2], +// s_mac_address[3], s_mac_address[4], s_mac_address[5]); + +// return fd; +// } + +// // 广播发送dev master的信息 +// static void autoGroup_send(int fd) +// { +// cJSON *serviceArry = cJSON_CreateArray(); +// if(serviceArry == NULL) return; + +// cJSON *servicePos = cJSON_CreateObject(); +// cJSON_AddItemToArray(serviceArry, servicePos); + +// if (cJSON_AddStringToObject(servicePos, "service", SERVICE_DISPLAY) == NULL ) goto FAIL_JSON; +// if (cJSON_AddStringToObject(servicePos, "ip", s_devMasterIp) == NULL ) goto FAIL_JSON; +// if (cJSON_AddNumberToObject(servicePos, "port", SENDUI_LCD3354_DST_PORT) == NULL) goto FAIL_JSON; +// if (cJSON_AddStringToObject(servicePos, "mac", s_mac_string) == NULL) goto FAIL_JSON; +// if (cJSON_AddStringToObject(servicePos, "desc", SERVICE_DESC) == NULL) goto FAIL_JSON; + + +// char * pp = cJSON_PrintUnformatted(serviceArry); +// if (NULL == pp) goto FAIL_JSON; + +// struct sockaddr_in servaddr; + +// bzero(&servaddr, sizeof(servaddr)); +// servaddr.sin_family = AF_INET; +// servaddr.sin_addr.s_addr = inet_addr(s_sendIP);//htonl(INADDR_ANY); +// servaddr.sin_port = htons(DEV_AUTO_GROUP_PORT); + +// // LV_LOG_WARN("Boardbase ip[%s] : Port[%d]", s_sendIP, (int)(DEV_AUTO_GROUP_PORT)); + +// sendto(fd, pp, strlen(pp), 0, (struct sockaddr*)&servaddr, sizeof(struct sockaddr)); + +// // DEBUG_BUFF(pp, strlen(pp)); + +// cJSON_free(pp); + +// FAIL_JSON: + +// cJSON_Delete(serviceArry); + +// } + + +// void autoGroup_init(void) +// { +// #if (COMPILER_FOR == COMPILE_FOR_AC_SSD202) +// s_UdpSentTick = Charger_TimeNowMs(); + +// s_fd_masterBroadCast = MasterDevCreateUdp(); + +// if (s_fd_masterBroadCast > 0) +// { +// LV_LOG_USER("Create Udp(send) fd = %d", s_fd_masterBroadCast); +// } + +// memset(s_devMasterIp, 0x00, sizeof(s_devMasterIp)); +// snprintf(s_sendIP, sizeof(s_sendIP), "%d.%d.%d.%d", 255, 255, 255, 255); +// #endif +// } + +// void autoGroup_step(void) +// { +// #if (COMPILER_FOR == COMPILE_FOR_AC_SSD202) + +// if (s_UdpSentTick + 1000 > Charger_TimeNowMs()) +// { +// return; +// } + +// s_UdpSentTick = Charger_TimeNowMs(); + +// if (strlen(s_devMasterIp) == 0) +// { +// if (!iface_get_ip()) +// { +// LV_LOG_WARN("get device ip failed"); +// return; +// } + +// LV_LOG_WARN("Device IP [%s]", s_devMasterIp); +// } + +// if (s_fd_masterBroadCast >= 0) +// { +// autoGroup_send(s_fd_masterBroadCast); +// } + +// #endif +// } diff --git a/ioc/ioc_app.c b/ioc/ioc_app.c new file mode 100644 index 000000000..f763cedef --- /dev/null +++ b/ioc/ioc_app.c @@ -0,0 +1,675 @@ +#include "ioc_app.h" + +#ifdef _WIN32 +#include +#endif + +static lv_obj_t * s_ui_welcome = NULL; +static const char * s_ui_visible_tree_json_name = "ui_visible_tree.json"; +static const char * s_ui_visible_obj_info_json_name = "ui_visible_obj_info.json"; + +static bool ioc_app_get_executable_dir(char *dir_path, size_t dir_path_size) +{ + if ((dir_path == NULL) || (dir_path_size == 0)) + { + return false; + } + +#ifdef _WIN32 + DWORD path_len = GetModuleFileNameA(NULL, dir_path, (DWORD)dir_path_size); + if ((path_len == 0) || (path_len >= dir_path_size)) + { + LV_LOG_ERROR("Failed to get executable path"); + return false; + } + + for (int i = (int)path_len - 1; i >= 0; i--) + { + if ((dir_path[i] == '\\') || (dir_path[i] == '/')) + { + dir_path[i] = '\0'; + return true; + } + } +#else + ssize_t path_len = readlink("/proc/self/exe", dir_path, dir_path_size - 1); + if ((path_len <= 0) || (path_len >= (ssize_t)dir_path_size)) + { + LV_LOG_ERROR("Failed to get executable path: %s", strerror(errno)); + return false; + } + + dir_path[path_len] = '\0'; + for (ssize_t i = path_len - 1; i >= 0; i--) + { + if (dir_path[i] == '/') + { + dir_path[i] = '\0'; + return true; + } + } +#endif + + LV_LOG_ERROR("Failed to parse executable directory"); + return false; +} + +static const char *ioc_app_align_to_string(lv_align_t align) +{ + switch (align) + { + case LV_ALIGN_DEFAULT: return "LV_ALIGN_DEFAULT"; + case LV_ALIGN_TOP_LEFT: return "LV_ALIGN_TOP_LEFT"; + case LV_ALIGN_TOP_MID: return "LV_ALIGN_TOP_MID"; + case LV_ALIGN_TOP_RIGHT: return "LV_ALIGN_TOP_RIGHT"; + case LV_ALIGN_LEFT_MID: return "LV_ALIGN_LEFT_MID"; + case LV_ALIGN_CENTER: return "LV_ALIGN_CENTER"; + case LV_ALIGN_RIGHT_MID: return "LV_ALIGN_RIGHT_MID"; + case LV_ALIGN_BOTTOM_LEFT: return "LV_ALIGN_BOTTOM_LEFT"; + case LV_ALIGN_BOTTOM_MID: return "LV_ALIGN_BOTTOM_MID"; + case LV_ALIGN_BOTTOM_RIGHT: return "LV_ALIGN_BOTTOM_RIGHT"; + case LV_ALIGN_OUT_TOP_LEFT: return "LV_ALIGN_OUT_TOP_LEFT"; + case LV_ALIGN_OUT_TOP_MID: return "LV_ALIGN_OUT_TOP_MID"; + case LV_ALIGN_OUT_TOP_RIGHT: return "LV_ALIGN_OUT_TOP_RIGHT"; + case LV_ALIGN_OUT_BOTTOM_LEFT: return "LV_ALIGN_OUT_BOTTOM_LEFT"; + case LV_ALIGN_OUT_BOTTOM_MID: return "LV_ALIGN_OUT_BOTTOM_MID"; + case LV_ALIGN_OUT_BOTTOM_RIGHT: return "LV_ALIGN_OUT_BOTTOM_RIGHT"; + case LV_ALIGN_OUT_LEFT_TOP: return "LV_ALIGN_OUT_LEFT_TOP"; + case LV_ALIGN_OUT_LEFT_MID: return "LV_ALIGN_OUT_LEFT_MID"; + case LV_ALIGN_OUT_LEFT_BOTTOM: return "LV_ALIGN_OUT_LEFT_BOTTOM"; + case LV_ALIGN_OUT_RIGHT_TOP: return "LV_ALIGN_OUT_RIGHT_TOP"; + case LV_ALIGN_OUT_RIGHT_MID: return "LV_ALIGN_OUT_RIGHT_MID"; + case LV_ALIGN_OUT_RIGHT_BOTTOM: return "LV_ALIGN_OUT_RIGHT_BOTTOM"; + default: return "LV_ALIGN_UNKNOWN"; + } +} + +static const char *ioc_app_text_align_to_string(lv_text_align_t align) +{ + switch (align) + { + case LV_TEXT_ALIGN_AUTO: return "LV_TEXT_ALIGN_AUTO"; + case LV_TEXT_ALIGN_LEFT: return "LV_TEXT_ALIGN_LEFT"; + case LV_TEXT_ALIGN_CENTER: return "LV_TEXT_ALIGN_CENTER"; + case LV_TEXT_ALIGN_RIGHT: return "LV_TEXT_ALIGN_RIGHT"; + default: return "LV_TEXT_ALIGN_UNKNOWN"; + } +} + +static cJSON *ioc_app_build_visible_obj_tree(lv_obj_t *obj) +{ + if ((obj == NULL) || lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) + { + return NULL; + } + + cJSON *node = cJSON_CreateObject(); + if (node == NULL) + { + return NULL; + } + + const char *name = "lv_scr_act"; + ioc_obj_user_data_t *user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + if ((user_data != NULL) && (user_data->name != NULL)) + { + name = user_data->name; + } + + cJSON_AddStringToObject(node, "name", name); + + cJSON *children = cJSON_CreateArray(); + if (children == NULL) + { + cJSON_Delete(node); + return NULL; + } + cJSON_AddItemToObject(node, "children", children); + + int cnt = lv_obj_get_child_cnt(obj); + for (int i = 0; i < cnt; i++) + { + lv_obj_t *child = lv_obj_get_child(obj, i); + cJSON *child_node = ioc_app_build_visible_obj_tree(child); + if (child_node != NULL) + { + cJSON_AddItemToArray(children, child_node); + } + } + + return node; +} + +static void ioc_app_dump_visible_obj_tree_to_json_file(lv_obj_t *root, const char *file_name) +{ + cJSON *tree = ioc_app_build_visible_obj_tree(root); + if (tree == NULL) + { + LV_LOG_ERROR("Failed to build visible object tree"); + return; + } + + char *json_str = cJSON_Print(tree); + if (json_str == NULL) + { + LV_LOG_ERROR("Failed to serialize visible object tree"); + cJSON_Delete(tree); + return; + } + + char file_path[1024] = {0}; + if (!ioc_app_get_executable_dir(file_path, sizeof(file_path))) + { + cJSON_free(json_str); + cJSON_Delete(tree); + return; + } + + size_t path_len = strlen(file_path); + if ((path_len + 1 + strlen(file_name) + 1) >= sizeof(file_path)) + { + LV_LOG_ERROR("Visible object tree path is too long"); + cJSON_free(json_str); + cJSON_Delete(tree); + return; + } + +#ifdef _WIN32 + snprintf(file_path + path_len, sizeof(file_path) - path_len, "\\%s", file_name); +#else + snprintf(file_path + path_len, sizeof(file_path) - path_len, "/%s", file_name); +#endif + + FILE *fp = fopen(file_path, "w"); + if (fp == NULL) + { + LV_LOG_ERROR("Failed to open %s: %s", file_path, strerror(errno)); + cJSON_free(json_str); + cJSON_Delete(tree); + return; + } + + fputs(json_str, fp); + fclose(fp); + + LV_LOG_WARN("Visible object tree exported to %s", file_path); + + cJSON_free(json_str); + cJSON_Delete(tree); +} + +static cJSON *ioc_app_create_visible_obj_info_item(lv_obj_t *obj) +{ + if ((obj == NULL) || lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) + { + return NULL; + } + + cJSON *item = cJSON_CreateObject(); + if (item == NULL) + { + return NULL; + } + + const char *name = "lv_scr_act"; + ioc_obj_user_data_t *user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + if (user_data != NULL) + { + if (user_data->name != NULL) + { + name = user_data->name; + } + } + + cJSON_AddStringToObject(item, "name", name); + cJSON_AddNumberToObject(item, "x", lv_obj_get_x(obj)); + cJSON_AddNumberToObject(item, "y", lv_obj_get_y(obj)); + cJSON_AddNumberToObject(item, "width", lv_obj_get_width(obj)); + cJSON_AddNumberToObject(item, "height", lv_obj_get_height(obj)); + cJSON_AddStringToObject(item, "align", ioc_app_align_to_string(lv_obj_get_style_align(obj, LV_PART_MAIN))); + cJSON_AddNumberToObject(item, "x_ofs", lv_obj_get_style_x(obj, LV_PART_MAIN)); + cJSON_AddNumberToObject(item, "y_ofs", lv_obj_get_style_y(obj, LV_PART_MAIN)); + cJSON_AddStringToObject(item, "text_align", ioc_app_text_align_to_string(lv_obj_get_style_text_align(obj, LV_PART_MAIN))); + + return item; +} + +static void ioc_app_collect_visible_obj_info(lv_obj_t *obj, cJSON *array) +{ + if ((obj == NULL) || (array == NULL) || lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) + { + return; + } + + cJSON *item = ioc_app_create_visible_obj_info_item(obj); + if (item != NULL) + { + cJSON_AddItemToArray(array, item); + } + + int cnt = lv_obj_get_child_cnt(obj); + for (int i = 0; i < cnt; i++) + { + ioc_app_collect_visible_obj_info(lv_obj_get_child(obj, i), array); + } +} + +static void ioc_app_dump_visible_obj_info_to_json_file(lv_obj_t *root, const char *file_name) +{ + cJSON *array = cJSON_CreateArray(); + if (array == NULL) + { + LV_LOG_ERROR("Failed to create visible object info array"); + return; + } + + ioc_app_collect_visible_obj_info(root, array); + + char *json_str = cJSON_Print(array); + if (json_str == NULL) + { + LV_LOG_ERROR("Failed to serialize visible object info"); + cJSON_Delete(array); + return; + } + + char file_path[1024] = {0}; + if (!ioc_app_get_executable_dir(file_path, sizeof(file_path))) + { + cJSON_free(json_str); + cJSON_Delete(array); + return; + } + + size_t path_len = strlen(file_path); + if ((path_len + 1 + strlen(file_name) + 1) >= sizeof(file_path)) + { + LV_LOG_ERROR("Visible object info path is too long"); + cJSON_free(json_str); + cJSON_Delete(array); + return; + } + +#ifdef _WIN32 + snprintf(file_path + path_len, sizeof(file_path) - path_len, "\\%s", file_name); +#else + snprintf(file_path + path_len, sizeof(file_path) - path_len, "/%s", file_name); +#endif + + FILE *fp = fopen(file_path, "w"); + if (fp == NULL) + { + LV_LOG_ERROR("Failed to open %s: %s", file_path, strerror(errno)); + cJSON_free(json_str); + cJSON_Delete(array); + return; + } + + fputs(json_str, fp); + fclose(fp); + + LV_LOG_WARN("Visible object info exported to %s", file_path); + + cJSON_free(json_str); + cJSON_Delete(array); +} + +void ioc_app_ui_json_updated_widgets(lv_obj_t* parent) +{ + if ((parent == NULL) || (lv_obj_has_flag(parent, LV_OBJ_FLAG_HIDDEN))) + { + return; + } + + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t*)lv_obj_get_user_data(parent); + if (user_data != NULL) + { + // LV_LOG_WARN("in user_data_name: %s", user_data->name); + + if (user_data->ui_json_update_cb != NULL) + { + user_data->ui_json_update_cb(user_data); + } + // LV_LOG_WARN("out user_data_name: %s", user_data->name); + } + + int cnt = lv_obj_get_child_cnt(parent); + if (cnt > 0) + { + // if (cnt > 20) DEBUG_WARN("CNT %d >20", cnt); + lv_obj_t** childs = (lv_obj_t**)malloc(sizeof(lv_obj_t*)*cnt); + int i; + for (i = 0; i < cnt; i++) + { + childs[i] = lv_obj_get_child(parent, i); + } + + for (i = 0; i < cnt; i++) + { + // 递归遍历子控件 + ioc_app_ui_json_updated_widgets(childs[i]); + } + free(childs); + } + + return; +} + +// welcome 界面 +/* ===== 动画配置 ===== */ +#define DOT_SIZE 30 +#define DOT_GAP 20 +#define DOT_RADIUS 8 + +#define ANIM_TIME 600 // 动画速度放慢(原来 350) +#define ANIM_DELAY_STEP 200 // 依次亮起的间隔也放慢 + +/* 亮色 & 暗色 */ +static lv_color_t color_on = LV_COLOR_MAKE(0x1A, 0xE9, 0xD9); // 高亮色 +static lv_color_t color_off = LV_COLOR_MAKE(0xD6, 0xF8, 0xF8); // 浅色 + +/* 动画回调:改变背景色 */ +static void anim_set_color(void * obj, int32_t v) +{ + lv_obj_set_style_bg_color(obj, lv_color_mix(color_on, color_off, v), 0); +} + +/* 单个点动画 */ +static void create_dot_anim(lv_obj_t * dot, uint32_t delay) +{ + lv_anim_t a; + lv_anim_init(&a); + lv_anim_set_var(&a, dot); + lv_anim_set_exec_cb(&a, anim_set_color); + + lv_anim_set_values(&a, 255, 0); // 从浅 → 深(亮起) + lv_anim_set_time(&a, ANIM_TIME); + lv_anim_set_delay(&a, delay); + + lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE); + lv_anim_set_repeat_delay(&a, 200); + lv_anim_start(&a); +} + +/* ===== 创建加载动画组件 ===== */ +void ui_create_loading_anim(lv_obj_t * parent) +{ + /* --- 确保父对象也不是可滚动的(非常关键)--- */ + if(parent) { + lv_obj_clear_flag(parent, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_set_scrollbar_mode(parent, LV_SCROLLBAR_MODE_OFF); + lv_obj_set_scroll_dir(parent, LV_DIR_NONE); + } + + /* 创建透明容器(无外框、无背景) */ + lv_obj_t * cont = lv_obj_create(parent); + lv_obj_set_size(cont, LV_SIZE_CONTENT, LV_SIZE_CONTENT); + lv_obj_set_style_bg_opa(cont, LV_OPA_TRANSP, 0); + lv_obj_set_style_border_width(cont, 0, 0); + lv_obj_set_style_pad_gap(cont, DOT_GAP, 0); + lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW); + + /* 彻底关闭容器的滚动相关设置 */ + lv_obj_clear_flag(cont, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_OFF); + lv_obj_set_scroll_dir(cont, LV_DIR_NONE); + + /* 居中 */ + lv_obj_center(cont); + + for(int i = 0; i < 4; i++) + { + lv_obj_t * dot = lv_obj_create(cont); + lv_obj_set_size(dot, DOT_SIZE, DOT_SIZE); + lv_obj_set_style_radius(dot, DOT_RADIUS, 0); + lv_obj_set_style_bg_color(dot, color_off, 0); + lv_obj_set_style_border_width(dot, 0, 0); + + /* 也把点的滚动属性都清掉(保险) */ + lv_obj_clear_flag(dot, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_set_scrollbar_mode(dot, LV_SCROLLBAR_MODE_OFF); + lv_obj_set_scroll_dir(dot, LV_DIR_NONE); + + create_dot_anim(dot, i * ANIM_DELAY_STEP); + } +} + + +void ioc_app_main(void) +{ + ioc_ui_json_init(); + lv_i18n_init(lv_i18n_language_pack); + // 初始化加载语言列表 + // 初始化加载翻译列表 + ioc_theme_mngr_load("main-light"); + ioc_style_mngr_load(NULL); + ioc_fragment_mngr_load(); + ioc_layout_mngr_load(); + s_preset_handler_init(); + s_ui_welcome = ioc_layout_mngr_load_layout("welcome", lv_scr_act()); + + ui_create_loading_anim(s_ui_welcome); + + // // 自组网 + // autoGroup_init(); + + // // 测试用 + // ioc_ui_json_set_con_num(1); + // g_ui_json.dispenserConfig.connIdx[0] = 0; + // g_ui_json.dispenserConfig.connIdx[1] = 1; +} + +// 触摸测试 +int g_touch_x = -1; +int g_touch_y = -1; + +void draw_black_dot_simple(void) +{ + lv_obj_t * dot = lv_obj_create(lv_layer_top()); + lv_obj_set_size(dot, 10, 10); + lv_obj_set_style_radius(dot, LV_RADIUS_CIRCLE, 0); + lv_obj_set_style_bg_color(dot, lv_color_black(), 0); + lv_obj_clear_flag(dot, LV_OBJ_FLAG_SCROLLABLE); + + lv_obj_set_pos(dot, g_touch_x - 5, g_touch_y - 5); + + lv_obj_move_foreground(dot); +} + +void bright_step() +{ + // static int last_brightness = -1; // 避免重复设亮度 + + // time_t now = time(NULL); + + // if(g_ui_json.biright.activeTime == 0) + // { + // g_ui_json.biright.activeTime = now; + // } + + // int brightness_to_set = g_ui_json.biright.brightIdle; + + // // DEBUG_WARN("brightIdle[%d]",g_ui_json.biright.brightIdle); + // // DEBUG_WARN("brightActive[%d]",g_ui_json.biright.brightActive); + // // DEBUG_WARN("brightCharging[%d]",g_ui_json.biright.brightCharging); + // // DEBUG_WARN("timeoutActive[%d]",g_ui_json.biright.timeoutActive); + // // DEBUG_WARN("activeTime[%d]",g_ui_json.biright.activeTime); + + + // // 判断是否处于激活状态 + // bool isActive = false; + // if (g_ui_json.biright.activeTime > 0 && + // now - g_ui_json.biright.activeTime < (g_ui_json.biright.timeoutActive * 60)) + // { + // isActive = true; + // } + + // // DEBUG_WARN("isActive[%d]",isActive); + + // // 根据状态决定亮度 + // if (isActive) + // { + // brightness_to_set = g_ui_json.biright.brightActive; + // } + // else + // { + // for(int i = 0; i < UI_MAX_CONNECTOR_NUM; i++) + // { + // // 充电状态显示brightCharging亮度 + // if(g_ui_json.connectors[i].state == UI_CONNECTOR_STATE_CHARGING) + // { + // brightness_to_set = g_ui_json.biright.brightCharging; + // break; + // } + // } + // } + + // // 避免重复设亮度 + // if (brightness_to_set != last_brightness) + // { + // LV_LOG_USER("Setting brightness to %d\n", brightness_to_set); + // set_brightness(brightness_to_set); + // last_brightness = brightness_to_set; + // } +} + +static bool language_load = false; +void ioc_app_step(void) +{ + // 自组网 + // autoGroup_step(); + + // 设置屏幕亮度 + // bright_step(); + + // 先等到第一个UI.json到达, 用于确定初始信息 + if (UI_FIRST_JSON) + { + if (ioc_ui_json_step()) + { + LV_LOG_WARN("FIRST==========================================="); + + // 等待UI.json获取homeOcpp设置的当前语言 + s_preset_handler_init(); + if (s_ui_welcome != NULL) + { + lv_obj_del(s_ui_welcome); + s_ui_welcome = NULL; + } + + ui_page_main_create(lv_scr_act()); + if ( language_load == false ) + { + language_page_init(); + ui_language_update_selected(current_lang_point->locale_name); + LV_LOG_WARN("current_lang_point->locale_name:%s",current_lang_point->locale_name); + language_load = true; + } + + // 强制刷新第一次内容 + ioc_app_ui_json_updated_widgets(lv_scr_act()); + ioc_ui_json_handle_over(); + + ioc_app_dump_visible_obj_tree_to_json_file(lv_scr_act(), s_ui_visible_tree_json_name); + ioc_app_dump_visible_obj_info_to_json_file(lv_scr_act(), s_ui_visible_obj_info_json_name); + + g_ui_json.isFirstUIjson = false; + } + return; + } + + // if (access("/tmp/theme-main-dark", F_OK) == 0) + // { + // ioc_theme_mngr_switch("main-dark"); + // ioc_style_mngr_theme_changed(); + // lv_obj_invalidate(lv_scr_act()); + // remove("/tmp/theme-main-dark"); + // } + // if (access("/tmp/theme-main-light", F_OK) == 0) + // { + // ioc_theme_mngr_switch("main-light"); + // ioc_style_mngr_theme_changed(); + // lv_obj_invalidate(lv_scr_act()); + // remove("/tmp/theme-main-light"); + // } + + if (ioc_ui_json_step()) + { + ioc_app_ui_json_updated_widgets(lv_scr_act()); + ioc_app_ui_json_updated_widgets(lv_layer_top()); + + ioc_ui_json_handle_over(); + ioc_app_dump_visible_obj_tree_to_json_file(lv_scr_act(), s_ui_visible_tree_json_name); + ioc_app_dump_visible_obj_info_to_json_file(lv_scr_act(), s_ui_visible_obj_info_json_name); + } + + + // 触摸测试 + // 如果有触摸,画一个直径为6的圆 + if(g_touch_x > 0 && g_touch_y > 0) + { + draw_black_dot_simple(); + g_touch_x = -1; + g_touch_y = -1; + } +} + + +bool ioc_obj_handler_match_preset_name(const char * preset_name, const char *name) +{ + // 先比较基本符合类型 + int preset_name_len = strlen(preset_name); + if (memcmp(preset_name, name, preset_name_len) == 0) + { + return true; + } + + // 再比较Prefix类型 + int prefix_len; + if (ioc_obj_name_is_prefix(preset_name, &prefix_len)) + { + int idx; + const char * name_after_prefix; + int name_after_prefix_len; + return ioc_obj_name_match_prefix(name, preset_name, prefix_len, &idx, &name_after_prefix, &name_after_prefix_len); + } + + return false; +} + +bool ioc_obj_handler_before_create(const char *name) +{ + int size = ioc_get_preset_handler_count(); + + for (int i = 0; i < size; i++) + { + if (ioc_obj_handler_match_preset_name(s_preset_handler[i].name, name)) + { + if (s_preset_handler[i].before_create) + { + return s_preset_handler[i].before_create(name); + } + + return true; + } + } + + return true; +} +void ioc_obj_handler_after_create(const char *name, lv_obj_t *obj) +{ + int size = ioc_get_preset_handler_count(); + + for (int i = 0; i < size; i++) + { + if (ioc_obj_handler_match_preset_name(s_preset_handler[i].name, name)) + { + if (s_preset_handler[i].after_create) + { + s_preset_handler[i].after_create(name, obj); + } + + return; + } + } +} diff --git a/ioc/ioc_app.h b/ioc/ioc_app.h new file mode 100644 index 000000000..37c96d0c9 --- /dev/null +++ b/ioc/ioc_app.h @@ -0,0 +1,74 @@ +#ifndef __IOC_APP_H__ +#define __IOC_APP_H__ + +#define _POSIX_C_SOURCE 200809L +#define _GNU_SOURCE +#include +#include +#include +#include +#include +// #include +#include +#include +#include +// #include +// #include +// #include +// #include +// #include +// #include +#include +#include +// #include + + +#include "lvgl.h" + +#include "../Charger_PreDefine.h" + +#define COMPILER_FOR COMPILE_FOR_DC_AM3354 + +#include "./mngr/cJSON.h" +#include "./mngr/ioc_cjson.h" +#include "./mngr/ioc_string_2_enum.h" +#include "./mngr/ioc_obj.h" +#include "./mngr/ioc_theme_mngr.h" +#include "./mngr/ioc_style_mngr.h" +#include "./mngr/ioc_fragment_mngr.h" +#include "./mngr/ioc_layout_mngr.h" + +#include "./uijson/ui_json.h" + +// #include "./mqtt/ioc_mqtt.h" + +#include "./zlog/zlog.h" +#include "./zlog/Charger_ErrCode.h" + +#include "../i18n/lv_i18n.h" + +// #include "./core/screen_init.h" + +void ioc_app_main(void); +void ioc_app_step(void); +void ioc_app_ui_json_updated_widgets(lv_obj_t* parent); +void s_preset_handler_init(void); +int Charger_zlog_init(); + +// 自组网 +// void autoGroup_init(void); +// void autoGroup_step(void); + +extern ioc_obj_handler_t s_preset_handler[]; +extern lv_obj_t * ui_page_main_create(lv_obj_t *parent); +extern void language_page_init(void); +extern void ui_language_update_selected(const char *str); +extern int ioc_get_preset_handler_count(void); +extern void ui_popup_hide_bill(); +extern void ui_trigger_panel_hide(); +extern void ui_trigger_panel_show(uint8_t color_idx); +extern void ui_popup_show_bill(); +extern void ui_popup_common_handle(const char *str); +extern bool ioc_ui_json_set_language(int language); + +#endif diff --git a/ioc/mngr/cJSON.c b/ioc/mngr/cJSON.c new file mode 100644 index 000000000..6634133b7 --- /dev/null +++ b/ioc/mngr/cJSON.c @@ -0,0 +1,3045 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + 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. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_LOCALES +#include +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#ifdef true +#undef true +#endif +#define true ((cJSON_bool)1) + +#ifdef false +#undef false +#endif +#define false ((cJSON_bool)0) + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { + if (!cJSON_IsString(item)) { + return NULL; + } + + return item->valuestring; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 12) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks +{ + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dillimport '...' is not static */ +static void * CJSON_CDECL internal_malloc(size_t size) +{ + return malloc(size); +} +static void CJSON_CDECL internal_free(void *pointer) +{ + free(pointer); +} +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +/* strlen of character literals resolved at compile time */ +#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + copy = (unsigned char*)hooks->allocate(length); + if (copy == NULL) + { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) + { + memcpy(newbuffer, p->buffer, p->offset + 1); + } + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test; + + if (output_buffer == NULL) + { + return false; + } + + /* This checks for NaN and Infinity */ + if ((d * 0) != 0) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occurred */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = strlen((const char*)value) + sizeof(""); + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +#define cjson_min(a, b) ((a < b) ? a : b) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((len < 0) || (buf == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buf; + p.length = (size_t)len; + p.offset = 0; + p.noalloc = true; + p.format = fmt; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* failed to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output: */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + if ((current_element == NULL) || (current_element->string == NULL)) { + return NULL; + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL)) + { + return false; + } + + child = array->child; + + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + } + else + { + /* append to the end */ + while (child->next) + { + child = child->next; + } + suffix_object(child, item); + } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL)) + { + return false; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return; + } + + add_item_to_array(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return; + } + + add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item->prev != NULL) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + add_item_to_array(array, newitem); + return; + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (parent->child == item) + { + parent->child = replacement; + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return; + } + + cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = b ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0;a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +static void skip_oneline_comment(char **input) +{ + *input += static_strlen("//"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if ((*input)[0] == '\n') { + *input += static_strlen("\n"); + return; + } + } +} + +static void skip_multiline_comment(char **input) +{ + *input += static_strlen("/*"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if (((*input)[0] == '*') && ((*input)[1] == '/')) + { + *input += static_strlen("*/"); + return; + } + } +} + +static void minify_string(char **input, char **output) { + (*output)[0] = (*input)[0]; + *input += static_strlen("\""); + *output += static_strlen("\""); + + + for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { + (*output)[0] = (*input)[0]; + + if ((*input)[0] == '\"') { + (*output)[0] = '\"'; + *input += static_strlen("\""); + *output += static_strlen("\""); + return; + } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { + (*output)[1] = (*input)[1]; + *input += static_strlen("\""); + *output += static_strlen("\""); + } + } +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + char *into = json; + + if (json == NULL) + { + return; + } + + while (json[0] != '\0') + { + switch (json[0]) + { + case ' ': + case '\t': + case '\r': + case '\n': + json++; + break; + + case '/': + if (json[1] == '/') + { + skip_oneline_comment(&json); + } + else if (json[1] == '*') + { + skip_multiline_comment(&json); + } else { + json++; + } + break; + + case '\"': + minify_string(&json, (char**)&into); + break; + + default: + into[0] = json[0]; + json++; + into++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (a->valuedouble == b->valuedouble) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} + +// 读取一个记录文件到cJSON对象 +cJSON * JSON_FromFile(const char * filePath) +{ + FILE * fp = NULL; + char * data = NULL; + cJSON * root = NULL; + + fp = fopen(filePath, "rb"); + if (fp == NULL) + { + goto FAIL; + } + + fseek(fp, 0, SEEK_END); + long size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + data = (char *)malloc(size+1); + if (data == NULL) + { + // printf("NO MEM %s\n", filePath); + goto FAIL; + } + + long rd = fread(data, 1, size, fp); + if (rd != size) + { + // printf("READ FAIL %s %lu<>%lu\n", filePath, rd, size); + goto FAIL; + } + data[size]='\0'; + + root = cJSON_Parse(data); + if (root == NULL) + { + // printf("PARSE FAIL %s\n", filePath); + goto FAIL; + } + + fclose(fp); + free(data); + + return root; +FAIL: + if (fp != NULL) fclose(fp); + if (data != NULL) free(data); + if (root != NULL) cJSON_Delete(root); + return NULL; +} + +// 把一个JSON对象保存到文件中 +int JSON_SaveToFile(cJSON * root, const char * filePath) +{ + FILE * fp = fopen(filePath, "w+"); + if (fp == NULL) return -1; + + char * pstr = cJSON_Print(root); + if (pstr == NULL) + { + fclose(fp); + return -1; + } + + fwrite(pstr, 1, strlen(pstr), fp); + + fclose(fp); system("sync"); + + cJSON_free(pstr); + + return 0; +} diff --git a/ioc/mngr/cJSON.h b/ioc/mngr/cJSON.h new file mode 100644 index 000000000..0fa42f26b --- /dev/null +++ b/ioc/mngr/cJSON.h @@ -0,0 +1,291 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + 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. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 12 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +#define PADDING_LEN 0 // WEBSOCKET头部最大字节数 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* Check if the item is a string and return its valuestring */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/arrray that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detatch items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will +need to be released. With recurse!=0, it will duplicate any children connected to the item. +The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + + +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +/* JSON文件 */ +cJSON * JSON_FromFile(const char * filePath); +int JSON_SaveToFile(cJSON * root, const char * filePath); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ioc/mngr/ioc_cjson.c b/ioc/mngr/ioc_cjson.c new file mode 100644 index 000000000..65f2cb2de --- /dev/null +++ b/ioc/mngr/ioc_cjson.c @@ -0,0 +1,132 @@ +#include "ioc_app.h" + +// 辅助函数:递归合并两个 cJSON 对象 +void cJSON_MergeObject(cJSON *dst, const cJSON *src) +{ + cJSON *current = NULL; + cJSON_ArrayForEach(current, src) + { + const char *name = current->string; + // LV_LOG_WARN("Merging %s", name); + + cJSON *dst_item = cJSON_GetObjectItem(dst, name); + if (cJSON_IsObject(current)) + { + if (dst_item) + { + if (cJSON_IsObject(dst_item)) + { + cJSON_MergeObject(dst_item, current); // 递归合并 + } + else + { + cJSON_ReplaceItemInObject(dst, name, cJSON_Duplicate(current, true)); + } + } + else + { + cJSON_AddItemToObject(dst, name, cJSON_Duplicate(current, true)); + } + } + else if (cJSON_IsArray(current)) + { + if (dst_item) + { + if (cJSON_IsArray(dst_item)) + { + cJSON * sub_item = NULL; + cJSON_ArrayForEach(sub_item, current) + { + cJSON_Merge(dst_item, sub_item); + } + } + else + { + cJSON_ReplaceItemInObject(dst, name, cJSON_Duplicate(current, true)); + } + } + else + { + cJSON_AddItemToObject(dst, name, cJSON_Duplicate(current, true)); + } + } + else + { + if (dst_item) + { + if (!cJSON_Compare(dst_item, current, true)) + { + LV_LOG_WARN("replace: %s", name); + cJSON_ReplaceItemInObject(dst, name, cJSON_Duplicate(current, true)); // 添加新的字段 + } + } + else + { + LV_LOG_WARN("Add: %s", name); + cJSON_AddItemToObject(dst, name, cJSON_Duplicate(current, true)); // 添加新字段 + } + } + } +} + +// 主函数:合并 src 到 dst 数组 +cJSON *cJSON_Merge(cJSON *const dst_array, const cJSON *const src) +{ + if (!dst_array || !src) + { + return NULL; // 如果任一参数为空,返回 NULL + } + + const char *src_name = cJSON_GetStringValue(cJSON_GetObjectItem(src, "name")); + if (!src_name) + { + return dst_array; // 如果 src 没有 name 属性,直接返回 dst + } + + bool deleted = false; + cJSON * src_deleted = cJSON_GetObjectItem(src, "deleted"); + if (src_deleted != NULL && cJSON_IsTrue(src_deleted)) + { + LV_LOG_WARN("Deleted: %s", src_name); + deleted = true; + } + + int idx = 0; + cJSON *current = NULL; + cJSON_ArrayForEach(current, dst_array) + { + const char *current_name = cJSON_GetStringValue(cJSON_GetObjectItem(current, "name")); + // LV_LOG_WARN("current_name: %s", current_name); + if (current_name && strcmp(current_name, src_name) == 0) + { + if (deleted) + { + LV_LOG_WARN("Delete: %s", src_name); + cJSON_DeleteItemFromArray(dst_array, idx); + return dst_array; + } + // 找到相同 name 的对象,递归合并 + cJSON_MergeObject(current, src); + return dst_array; + } + idx++; + } + + // 如果没有找到相同 name 的对象,将 src 添加到 dst 数组中 + if (!deleted) + { + cJSON * idx = cJSON_GetObjectItem(src, "idx"); + if (idx != NULL) + { + // LV_LOG_WARN("Add: %s at %d", src_name, idx->valueint); + cJSON_InsertItemInArray(dst_array, idx->valueint, cJSON_Duplicate(src, true)); + } + else + { + // LV_LOG_WARN("Add: %s", src_name); + cJSON_AddItemToArray(dst_array, cJSON_Duplicate(src, true)); + } + } + + return dst_array; +} diff --git a/ioc/mngr/ioc_cjson.h b/ioc/mngr/ioc_cjson.h new file mode 100644 index 000000000..ec7effd19 --- /dev/null +++ b/ioc/mngr/ioc_cjson.h @@ -0,0 +1,9 @@ +#ifndef __IOC_CJSON_H__ +#define __IOC_CJSON_H__ + +#include "cJSON.h" + +/* 合并两个cJson对象, 用于进行补丁包扩展 */ +cJSON * cJSON_Merge(cJSON * const dst_array, const cJSON * const src); + +#endif diff --git a/ioc/mngr/ioc_fragment_mngr.c b/ioc/mngr/ioc_fragment_mngr.c new file mode 100644 index 000000000..d2f735117 --- /dev/null +++ b/ioc/mngr/ioc_fragment_mngr.c @@ -0,0 +1,102 @@ + +#include "ioc_app.h" + +static cJSON *s_fragments_json = NULL; + +static bool ioc_fragment_mngr_load_dir(const char *fragment_path) +{ + DIR *dir = opendir(fragment_path); + if (dir == NULL) + { + LV_LOG_ERROR("failed %s", fragment_path); + return false; + } + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) + { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + char file_path[512]; + snprintf(file_path, sizeof(file_path), "%s/%s", fragment_path, entry->d_name); + cJSON *fragment_json = JSON_FromFile(file_path); + if (fragment_json == NULL) + { + LV_LOG_ERROR("cant't open %s", file_path); + closedir(dir); + return false; + } + cJSON_Merge(s_fragments_json, fragment_json); + cJSON_Delete(fragment_json); + } + closedir(dir); + return true; +} + +bool ioc_fragment_mngr_load(void) +{ + // 初始化一个空的片段包 + ioc_fragment_mngr_unload(); + s_fragments_json = cJSON_CreateArray(); + + if (!ioc_fragment_mngr_load_dir(FRAGMENT_ROOT_PATH)) + { + LV_LOG_ERROR("Can't load fragment root path %s", FRAGMENT_ROOT_PATH); + return false; + } + if (access(FRAGMENT_PATCH_PATH, F_OK) == 0) + { + if (!ioc_fragment_mngr_load_dir(FRAGMENT_PATCH_PATH)) + { + LV_LOG_ERROR("Can't load fragment patch path %s", FRAGMENT_PATCH_PATH); + return false; + } + } + else + { + LV_LOG_INFO("Skip fragment patch path %s", FRAGMENT_PATCH_PATH); + } + + // char * p = cJSON_Print(s_fragments_json); + // printf("%s\n", p); + // cJSON_free(p); + + return true; +} + +void ioc_fragment_mngr_unload(void) +{ + if (s_fragments_json != NULL) + { + cJSON_Delete(s_fragments_json); + s_fragments_json = NULL; + } +} + + +lv_obj_t * ioc_obj_create_fragment(const char * name, cJSON * fragment_json, lv_obj_t * parent) +{ + const char * fragment_name = cJSON_GetStringValue(cJSON_GetObjectItem(fragment_json, "fragment_name")); + + cJSON * curr_fragment_json; + cJSON_ArrayForEach(curr_fragment_json, s_fragments_json) + { + const char * curr_fragment_name = cJSON_GetStringValue(cJSON_GetObjectItem(curr_fragment_json, "name")); + if (curr_fragment_name != NULL && strcmp(curr_fragment_name, fragment_name) == 0) + { + lv_obj_t * fragment = ioc_obj_create_obj(name, curr_fragment_json, parent); + + cJSON *properties_json = cJSON_GetObjectItem(fragment_json, "properties"); + if (properties_json != NULL) + { + ioc_obj_set_properties_position(fragment, properties_json); + ioc_obj_set_properties_size(fragment, properties_json); + ioc_obj_set_properties_align(fragment, properties_json); + ioc_obj_set_properties_style(fragment, properties_json); + } + + return fragment; + } + } + + LV_LOG_ERROR("Can't find fragment %s", fragment_name); + return NULL; +} diff --git a/ioc/mngr/ioc_fragment_mngr.h b/ioc/mngr/ioc_fragment_mngr.h new file mode 100644 index 000000000..434cfd920 --- /dev/null +++ b/ioc/mngr/ioc_fragment_mngr.h @@ -0,0 +1,15 @@ +#ifndef __IOC_FRAGMENT_MNGR_H__ +#define __IOC_FRAGMENT_MNGR_H__ + +#include "lvgl.h" + +#define FRAGMENT_ROOT_PATH "./assets/fragment/" +#define FRAGMENT_PATCH_PATH "./patch/fragment/" + +bool ioc_fragment_mngr_load(void); +void ioc_fragment_mngr_unload(void); + +lv_obj_t * ioc_obj_create_fragment(const char * name, cJSON * fragment_json, lv_obj_t * parent); + + +#endif diff --git a/ioc/mngr/ioc_layout_mngr.c b/ioc/mngr/ioc_layout_mngr.c new file mode 100644 index 000000000..d343881e6 --- /dev/null +++ b/ioc/mngr/ioc_layout_mngr.c @@ -0,0 +1,94 @@ + +#include "ioc_app.h" + +static cJSON * s_layouts_json = NULL; + +static bool ioc_layout_mngr_load_dir(const char * layout_path) +{ + DIR *dir = opendir(layout_path); + if (dir == NULL) + { + LV_LOG_ERROR("failed %s", layout_path); + return false; + } + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) + { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + char file_path[512]; + snprintf(file_path, sizeof(file_path), "%s/%s", layout_path, entry->d_name); + cJSON *layout_json = JSON_FromFile(file_path); + if (layout_json == NULL) + { + LV_LOG_ERROR("cant't open %s", file_path); + closedir(dir); + return false; + } + cJSON_Merge(s_layouts_json, layout_json); + cJSON_Delete(layout_json); + } + closedir(dir); + return true; +} + +bool ioc_layout_mngr_load(void) +{ + // 初始化一个空的片段包 + ioc_layout_mngr_unload(); + s_layouts_json = cJSON_CreateArray(); + + if (!ioc_layout_mngr_load_dir(LAYOUT_ROOT_PATH)) + { + LV_LOG_ERROR("Can't load layout root path %s", FRAGMENT_ROOT_PATH); + return false; + } + if (access(LAYOUT_PATCH_PATH, F_OK) == 0) + { + if (!ioc_layout_mngr_load_dir(LAYOUT_PATCH_PATH)) + { + LV_LOG_ERROR("Can't load layout patch path %s", FRAGMENT_PATCH_PATH); + return false; + } + } + else + { + LV_LOG_INFO("Skip layout patch path %s", FRAGMENT_PATCH_PATH); + } + + // char * p = cJSON_Print(s_layouts_json); + // printf("%s\n", p); + // cJSON_free(p); + + return true; +} + +void ioc_layout_mngr_unload(void) +{ + if (s_layouts_json != NULL) + { + cJSON_Delete(s_layouts_json); + s_layouts_json = NULL; + } +} + +lv_obj_t * ioc_layout_mngr_load_layout(const char *layout_name, lv_obj_t * screen) +{ + if (s_layouts_json == NULL) + { + return NULL; + } + + cJSON *layout_json; + cJSON_ArrayForEach(layout_json, s_layouts_json) + { + const char *current_name = cJSON_GetStringValue(cJSON_GetObjectItem(layout_json, "name")); + if (current_name != NULL && strcmp(current_name, layout_name) == 0) + { + // LV_LOG_ERROR("load layout %s", layout_name); + return ioc_obj_create_obj(NULL, layout_json, screen); + } + } + + LV_LOG_ERROR("can't find %s", layout_name); + return NULL; +} diff --git a/ioc/mngr/ioc_layout_mngr.h b/ioc/mngr/ioc_layout_mngr.h new file mode 100644 index 000000000..17542abbf --- /dev/null +++ b/ioc/mngr/ioc_layout_mngr.h @@ -0,0 +1,14 @@ +#ifndef __IOC_LAYOUT_MNGR_H__ +#define __IOC_LAYOUT_MNGR_H__ + +#include "lvgl.h" + +#define LAYOUT_ROOT_PATH "./assets/layout/" +#define LAYOUT_PATCH_PATH "./patch/layout/" + +bool ioc_layout_mngr_load(void); +void ioc_layout_mngr_unload(void); + +lv_obj_t * ioc_layout_mngr_load_layout(const char *layout_name, lv_obj_t * screen); + +#endif diff --git a/ioc/mngr/ioc_obj.c b/ioc/mngr/ioc_obj.c new file mode 100644 index 000000000..c99f186d9 --- /dev/null +++ b/ioc/mngr/ioc_obj.c @@ -0,0 +1,617 @@ + +#include "ioc_app.h" + +void ioc_obj_set_properties_position(lv_obj_t *obj, cJSON *properties_json) +{ + cJSON *x_json = cJSON_GetObjectItem(properties_json, "x"); + if (x_json != NULL) + { + lv_obj_set_x(obj, x_json->valueint); + LV_LOG_INFO("%s:x:%d", ioc_obj_get_name(obj), x_json->valueint); + } + + cJSON *y_json = cJSON_GetObjectItem(properties_json, "y"); + if (y_json != NULL) + { + lv_obj_set_y(obj, y_json->valueint); + LV_LOG_INFO("%s:y:%d", ioc_obj_get_name(obj), y_json->valueint); + } + + return; +} + +void ioc_obj_set_properties_size(lv_obj_t *obj, cJSON *properties_json) +{ + cJSON *width_json = cJSON_GetObjectItem(properties_json, "width"); + if (width_json != NULL) + { + lv_obj_set_width(obj, width_json->valueint); + LV_LOG_INFO("%s:w:%d", ioc_obj_get_name(obj), width_json->valueint); + } + + cJSON *height_json = cJSON_GetObjectItem(properties_json, "height"); + if (height_json != NULL) + { + lv_obj_set_height(obj, height_json->valueint); + LV_LOG_INFO("%s:h:%d", ioc_obj_get_name(obj), height_json->valueint); + } + + return; +} + +void ioc_obj_set_properties_align(lv_obj_t * obj, cJSON *properties_json) +{ + const char *align_name = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "align")); + if (align_name != NULL) + { + lv_align_t align = ioc_string_2_align(align_name); + + int32_t x_ofs = 0; + cJSON * x_ofs_json = cJSON_GetObjectItem(properties_json, "x_ofs"); + if (x_ofs_json != NULL) x_ofs = x_ofs_json->valueint; + + int32_t y_ofs = 0; + cJSON * y_ofs_json = cJSON_GetObjectItem(properties_json, "y_ofs"); + if (y_ofs_json != NULL) y_ofs = y_ofs_json->valueint; + + cJSON * to_obj = cJSON_GetObjectItem(properties_json, "to_obj"); + if ( to_obj != NULL ){ + lv_obj_t* parent = lv_obj_get_parent(obj); + #if (LVGL_VERSION_MAJOR == 9) + int cnt = lv_obj_get_child_count(parent); + #else + int cnt = lv_obj_get_child_cnt(parent); + #endif + lv_obj_t* child_obj; + ioc_obj_user_data_t * user_data; + for ( int i = 0; i < cnt; i++ ){ + child_obj = lv_obj_get_child(parent, i); + user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(child_obj); + if ( strcmp(to_obj->valuestring, user_data->name) == 0 ){ + lv_obj_align_to(obj, child_obj, align, x_ofs, y_ofs); + break; + } + } + } + else{ + lv_obj_align(obj, align, x_ofs, y_ofs); + } + } + + return; +} + +void ioc_obj_set_properties_text_align(lv_obj_t * obj, cJSON *properties_json) +{ + const char *text_align = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "text_align")); + if ( text_align != NULL ) + { + char*str = cJSON_Print(properties_json); + lv_text_align_t align = ioc_string_2_text_align(text_align); + lv_obj_set_style_text_align(obj, align, 0); + cJSON_free(str); + } +} + +void ioc_obj_set_properties_style(lv_obj_t *obj, cJSON *properties_json) +{ + const char *style_name = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "style")); + if (style_name != NULL) + { + lv_style_t * style = ioc_style_mngr_get_style(style_name); + if (style != NULL) + { + lv_obj_add_style(obj, style, LV_STATE_DEFAULT); + } + } + + const char *style_checked_name = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "style_checked")); + if (style_checked_name != NULL) + { + lv_style_t * style_checked = ioc_style_mngr_get_style(style_checked_name); + if (style_checked != NULL) + { + lv_obj_add_style(obj, style_checked, LV_STATE_CHECKED); + } + } + + const char *style_indic_name = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "style_indic")); + if (style_indic_name != NULL) + { + lv_style_t * style_indic = ioc_style_mngr_get_style(style_indic_name); + if (style_indic != NULL) + { + lv_obj_add_style(obj, style_indic, LV_PART_INDICATOR); + } + } + + return; +} + +void ioc_obj_set_properties_flex_flow(lv_obj_t *flex, cJSON *properties_json) +{ + const char *flow_name = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "flow")); + if (flow_name != NULL) lv_obj_set_flex_flow(flex, ioc_string_2_flex_flow(flow_name)); + + return; +} + +void ioc_obj_set_properties_flex_align(lv_obj_t *flex, cJSON *properties_json) +{ + const char *main_place = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "main_place")); + const char *cross_place = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "cross_place")); + const char *track_cross_place = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "track_cross_place")); + + const char *flow_name = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "flow")); + if (flow_name != NULL) + { + lv_obj_set_flex_align(flex, ioc_string_2_flex_align(main_place), ioc_string_2_flex_align(cross_place), ioc_string_2_flex_align(track_cross_place)); + } +} + +void ioc_obj_set_properties_image_path(lv_obj_t *img, cJSON *properties_json) +{ + const char *src = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "src")); + if (src != NULL) + { + // char *json_str = cJSON_Print(properties_json); + // if (json_str != NULL) { + // LV_LOG_WARN("%s\n", json_str); + // free(json_str); + // } + + // LV_LOG_WARN("================================================="); + lv_img_set_src(img, ioc_theme_getimgpath(src)); + return; + } + + return; +} + +void ioc_obj_set_properties_gif_path(lv_obj_t *gif, cJSON *properties_json) +{ + const char *src = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "src")); + if (src != NULL) + { + lv_gif_set_src(gif, ioc_theme_getimgpath(src)); + return; + } + + return; +} + +#if (LVGL_VERSION_MAJOR == 9) +void ioc_obj_set_properties_qr_code_size(lv_obj_t *qr, cJSON *properties_json) +{ + cJSON *size = cJSON_GetObjectItem(properties_json, "size"); + if (size != NULL) + { + lv_qrcode_set_size(qr, size->valueint); + return; + } + + return; +} +#endif + +void ioc_obj_set_properties_qr_code_data(lv_obj_t *qr, cJSON *properties_json) +{ + const char *qr_code_data = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "qr_code_data")); + if (qr_code_data != NULL) + { + lv_qrcode_update(qr, qr_code_data, strlen(qr_code_data)); + return; + } + + return; +} + +bool ioc_label_set_text(lv_obj_t *label, const char * text_id) +{ + const char * text = lv_i18n_get_text(text_id); + + // if(strcmp(text_id, "Close") == 0) + // { + // LV_LOG_WARN("text_id [%s] is NULL", text_id); + // } + + if(label == NULL) + { + LV_LOG_WARN("text_id [%s] is NULL", text_id); + return false; + } + + // 如果传入的值一样又会画一遍,浪费CPU, + // 因为lv_label_set_text函数没有判断,所以在这里判断 + if (strcmp(text, lv_label_get_text(label)) == 0) + { + return false; + } + + lv_label_set_text(label, text); + return true; +} + + +void ioc_obj_set_properties_label_text(lv_obj_t *label, cJSON *properties_json) +{ + const char *text = cJSON_GetStringValue(cJSON_GetObjectItem(properties_json, "text")); + if (text == NULL) + { + // 如果text为空则随便传入一个找不到的值,如果没有则返回本身 + ioc_label_set_text(label, "ioc_test"); + return; + } + + ioc_label_set_text(label, text); + return; +} + +void ioc_obj_set_properties_hidden(lv_obj_t *obj, cJSON *properties_json) +{ + cJSON *hidden = cJSON_GetObjectItem(properties_json, "hidden"); + if (hidden != NULL) + { + if (cJSON_IsTrue(hidden)) + { + lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); + } + LV_LOG_INFO("%s set hiden", ioc_obj_get_name(obj)); + } + + return; +} + +static void ioc_obj_make_full_name(char full_name[1024], const char * obj_name, lv_obj_t *parent) +{ + ioc_obj_user_data_t * parent_user_data = lv_obj_get_user_data(parent); + + if (parent_user_data != NULL) + { + const char *parent_name = parent_user_data->name; + snprintf(full_name, 1024, "%s.%s", parent_name, obj_name); + } + else + { + strncpy(full_name, obj_name, 1024); + } +} + +bool ioc_obj_create_user_data(lv_obj_t * obj, const char * obj_name, ioc_obj_type_t type, cJSON *obj_json, lv_obj_t *parent) +{ + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)calloc(1, sizeof(ioc_obj_user_data_t)); + if (user_data == NULL) + { + LV_LOG_ERROR("can't malloc user_data"); + return false; + } + + char full_name[1024]; + ioc_obj_make_full_name(full_name, (obj_name != NULL) ? obj_name : cJSON_GetStringValue(cJSON_GetObjectItem(obj_json, "name")), parent); + user_data->name = strdup(full_name); + if (user_data->name == NULL) + { + LV_LOG_ERROR("can't malloc name"); + free(user_data); + return false; + } + + user_data->type = type; + user_data->ref_json = obj_json; + user_data->obj = obj; + user_data->parent_user_data = lv_obj_get_user_data(parent); + + lv_obj_set_user_data(obj, user_data); + // LV_LOG_WARN("obj: %s", user_data->name); + + lv_obj_add_event_cb(obj, ioc_obj_deleted_event_cb, LV_EVENT_DELETE, NULL); + + return true; +} + +lv_obj_t *ioc_obj_create_basic_obj(const char * name, ioc_obj_type_t type, cJSON *obj_json, lv_obj_t *parent) +{ + lv_obj_t *obj = NULL; + if (type == IOC_OBJ_TYPE_LABEL) + { + obj = lv_label_create(parent); + } + else if (type == IOC_OBJ_TYPE_IMAGE) + { + obj = lv_img_create(parent); + } + else if (type == IOC_OBJ_TYPE_GIF) + { + obj = lv_gif_create(parent); + } + else if (type == IOC_OBJ_TYPE_BUTTON) + { + obj = lv_btn_create(parent); + lv_obj_set_style_shadow_width(obj, 0, 0); + } + else if (type == IOC_OBJ_TYPE_QR) + { + #if (LVGL_VERSION_MAJOR == 9) + obj = lv_qrcode_create(parent); + #else + cJSON *properties_json = cJSON_GetObjectItem(obj_json, "properties"); + if (properties_json != NULL) + { + cJSON *size_json = cJSON_GetObjectItem(properties_json, "size"); + if (size_json != NULL) + { + obj = lv_qrcode_create(parent, size_json->valueint, lv_color_make(0,0,0), lv_color_make(255,255,255)); + } + } + #endif + } + else if (type == IOC_OBJ_TYPE_BAR) + { + obj = lv_bar_create(parent); + } + else if (type == IOC_OBJ_TYPE_LIST) + { + obj = lv_list_create(parent); + } + else + { + obj = lv_obj_create(parent); + lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE); + } + if (obj == NULL) + { + return NULL; + } + lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE); // 全局性的取消所有控件的Scrollable属性, 我们的布局用不到, 如后续有需求再调整代码 + + if (!ioc_obj_create_user_data(obj, (name != NULL) ? name : cJSON_GetStringValue(cJSON_GetObjectItem(obj_json, "name")), type, obj_json, parent)) + { + lv_obj_del(obj); + return NULL; + } + + cJSON *properties_json = cJSON_GetObjectItem(obj_json, "properties"); + if (properties_json != NULL) + { + ioc_obj_set_properties_position(obj, properties_json); + ioc_obj_set_properties_size(obj, properties_json); + ioc_obj_set_properties_align(obj, properties_json); + ioc_obj_set_properties_text_align(obj, properties_json); + ioc_obj_set_properties_hidden(obj, properties_json); + if (type == IOC_OBJ_TYPE_FLEX) + { + ioc_obj_set_properties_flex_flow(obj, properties_json); + ioc_obj_set_properties_flex_align(obj, properties_json); + } + else if (type == IOC_OBJ_TYPE_LABEL) + { + ioc_obj_set_properties_label_text(obj, properties_json); + } + else if (type == IOC_OBJ_TYPE_IMAGE) + { + ioc_obj_set_properties_image_path(obj, properties_json); + } + else if (type == IOC_OBJ_TYPE_GIF) + { + ioc_obj_set_properties_gif_path(obj, properties_json); + } + else if (type == IOC_OBJ_TYPE_QR) + { + #if (LVGL_VERSION_MAJOR == 9) + ioc_obj_set_properties_qr_code_size(obj, properties_json); + #endif + ioc_obj_set_properties_qr_code_data(obj, properties_json); + } + else if (type == IOC_OBJ_TYPE_BAR) + { + + } + else if (type == IOC_OBJ_TYPE_LIST) + { + + } + ioc_obj_set_properties_style(obj, properties_json); + } + + cJSON * children_json = cJSON_GetObjectItem(obj_json, "children"); + + // char *json_str = cJSON_Print(children_json); + // if (json_str != NULL) { + // LV_LOG_WARN("%s\n", json_str); + // free(json_str); + // } + + if (children_json != NULL) + { + cJSON * child_json; + cJSON_ArrayForEach(child_json, children_json) + { + lv_obj_t *child = ioc_obj_create_obj(cJSON_GetStringValue(cJSON_GetObjectItem(child_json, "name")), child_json, obj); + if (child != NULL) + { + ioc_obj_set_properties_position(child, child_json); + ioc_obj_set_properties_size(child, child_json); + ioc_obj_set_properties_hidden(child, child_json); + ioc_obj_set_properties_align(child, properties_json); + ioc_obj_set_properties_text_align(child, properties_json); + ioc_obj_set_properties_style(child, child_json); + } + } + } + + return obj; +} + +lv_obj_t * ioc_obj_create_obj(const char * name, cJSON * obj_json, lv_obj_t * parent) +{ + const char * obj_name = (name != NULL) ? name : cJSON_GetStringValue(cJSON_GetObjectItem(obj_json, "name")); + + char full_name[1024]; + ioc_obj_make_full_name(full_name, obj_name, parent); + + if (!ioc_obj_handler_before_create(full_name)) + { + LV_LOG_ERROR("Not permit to create obj %s", full_name); + return NULL; + } + + const char * type_name = cJSON_GetStringValue(cJSON_GetObjectItem(obj_json, "type")); + if (type_name == NULL) + { + // char *json_str = cJSON_Print(obj_json); + // if (json_str != NULL) { + // LV_LOG_WARN("%s\n", json_str); + // free(json_str); + // } + + LV_LOG_ERROR("crteat[%s] no type", full_name); + return NULL; + } + + lv_obj_t * obj = NULL; + bool is_fragment = false; + if ((strcmp(type_name, "fragment") == 0) + || (strcmp(type_name, "fragment_checkbox") == 0)) + { + is_fragment = true; + obj = ioc_obj_create_fragment(obj_name, obj_json, parent); + } + else if (strcmp(type_name, "flex") == 0) + { + obj = ioc_obj_create_basic_obj(obj_name, IOC_OBJ_TYPE_FLEX, obj_json, parent); + } + else if (strcmp(type_name, "image") == 0) + { + obj = ioc_obj_create_basic_obj(obj_name, IOC_OBJ_TYPE_IMAGE, obj_json, parent); + } + else if (strcmp(type_name, "gif") == 0) + { + obj = ioc_obj_create_basic_obj(obj_name, IOC_OBJ_TYPE_GIF, obj_json, parent); + } + else if (strcmp(type_name, "label") == 0) + { + obj = ioc_obj_create_basic_obj(obj_name, IOC_OBJ_TYPE_LABEL, obj_json, parent); + } + else if (strcmp(type_name, "button") == 0) + { + obj = ioc_obj_create_basic_obj(obj_name, IOC_OBJ_TYPE_BUTTON, obj_json, parent); + } + else if (strcmp(type_name, "qr") == 0) + { + obj = ioc_obj_create_basic_obj(obj_name, IOC_OBJ_TYPE_QR, obj_json, parent); + } + else if (strcmp(type_name, "bar") == 0) + { + obj = ioc_obj_create_basic_obj(obj_name, IOC_OBJ_TYPE_BAR, obj_json, parent); + } + else if (strcmp(type_name, "list") == 0) + { + obj = ioc_obj_create_basic_obj(obj_name, IOC_OBJ_TYPE_LIST, obj_json, parent); + } + else + { + LV_LOG_ERROR("unknow type %s", type_name); + return false; + } + if (obj == NULL) + { + LV_LOG_ERROR("can't create obj %s", full_name); + return false; + } + if (!is_fragment) + { + // LV_LOG_WARN("==============>[%s] %s", type_name, full_name); + ioc_obj_handler_after_create(full_name, obj); + } + + return obj; +} + +void ioc_obj_deleted_event_cb(lv_event_t * e) +{ + lv_obj_t * obj = lv_event_get_target(e); + ioc_obj_user_data_t * user_data = lv_obj_get_user_data(obj); + if (user_data != NULL) + { + free(user_data->name); + free(user_data); + } +} + +const char * ioc_obj_get_name(lv_obj_t * obj) +{ + ioc_obj_user_data_t * user_data = lv_obj_get_user_data(obj); + if (user_data != NULL) + { + return user_data->name; + } + return "UnknownName"; +} + +bool ioc_obj_name_is_prefix(const char *name, int *prefix_len) +{ + int len = strlen(name); + if (len < 2) + { + return false; + } + + if (name[len - 1] != '*') + { + return false; + } + + *prefix_len = len - 1; + return true; +} + +bool ioc_obj_name_match_prefix(const char * name // 待匹配的name + , const char * prefix , int prefix_len // 预设前缀 + , int * idx // 匹配到的idx + , const char ** name_after_prefix, int * name_after_prefix_len // name去掉prefix和idx后的结果 +) +{ + // LV_LOG_WARN("==name[%s] prerix[%s] prefix_len[%d]", name, prefix, prefix_len); + // 检查输入字符串是否以输入前缀开始 + if (strncmp(name, prefix, prefix_len) != 0) + { + return false; // 不符合前缀 + } + + // 跳过前缀部分,定位到数字的起始位置 + const char *num_start = name + prefix_len; + + // 找到数字结束的位置(即点号的位置) + const char *dot_pos = strchr(num_start, '.'); + if (dot_pos == NULL) + { + // 如果没有点号,说明后面没有额外的名称 + *name_after_prefix = NULL; // 后续名称为空 + *name_after_prefix_len = 0; + } + else + { + // 如果有点号,后续名称从点号后开始 + *name_after_prefix = dot_pos + 1; // 跳过点号 + *name_after_prefix_len = strlen(*name_after_prefix); // 计算后续名称的长度 + } + + // 提取数字部分 + char num_str[32] = {0}; // 假设数字不会超过31位 + int num_len = (dot_pos == NULL) ? strlen(num_start) : (dot_pos - num_start); + if (num_len >= sizeof(num_str)) + { + return false; // 数字过长 + } + strncpy(num_str, num_start, num_len); + + // 将数字字符串转换为整数 + char *endptr; + *idx = strtol(num_str, &endptr, 10); + if (*endptr != '\0') + { + return false; // 数字格式不正确 + } + + return true; +} diff --git a/ioc/mngr/ioc_obj.h b/ioc/mngr/ioc_obj.h new file mode 100644 index 000000000..603d82c1a --- /dev/null +++ b/ioc/mngr/ioc_obj.h @@ -0,0 +1,125 @@ +#ifndef __IOC_OBJ_H__ +#define __IOC_OBJ_H__ + +#include "lvgl.h" +#include "cJSON.h" + +typedef enum { + IOC_OBJ_TYPE_FRAGMENT = 0, + + IOC_OBJ_TYPE_FLEX, + + IOC_OBJ_TYPE_LABEL, + IOC_OBJ_TYPE_IMAGE, + IOC_OBJ_TYPE_GIF, + IOC_OBJ_TYPE_BUTTON, + IOC_OBJ_TYPE_QR, + IOC_OBJ_TYPE_BAR, + IOC_OBJ_TYPE_LIST, + + IOC_OBJ_TYPE_NUM, +} ioc_obj_type_t; + +typedef struct ioc_obj_user_data_s +{ + char * name; + ioc_obj_type_t type; + + cJSON * ref_json; + lv_obj_t *obj; + struct ioc_obj_user_data_s * parent_user_data; + + union + { + void * data_ptr; + uint32_t data_uint32; + uint16_t data_uint16; + uint8_t data_uint8; + int32_t data_int32; + int16_t data_int16; + int8_t data_int8; + int data_int; + } extra_data; // 额外数据, 默认创建的控件为NULL, 用户可以在after_create中设置值 + // 如果是动态申请出来的, 请注意用户释放. 建议尽量不要动态申请, 以免增加复杂度 + + void (*ui_json_update_cb)(struct ioc_obj_user_data_s * user_data); // ui_json更新回调, 在ui_json更新的时候调用 + +} ioc_obj_user_data_t; + + +typedef struct { + + const char * name; + + bool (*before_create)(const char *name); + + void (*after_create)(const char * name, lv_obj_t * obj); +} ioc_obj_handler_t; + + +/** + * @note 递归创建对象 + * @param name 对象名称, 如果为null, 则使用json中的name字段 + */ +lv_obj_t * ioc_obj_create_obj(const char * name, cJSON * obj_json, lv_obj_t * parent); + +/** + * @note 对象删除的时候默认调用的回调, 需要删除自动创建的user_data + * 如果用户自己注册了删除回调, 最后需要调用这个回调, 防止内存泄漏 + */ +void ioc_obj_deleted_event_cb(lv_event_t * e); + +/** + * @note 获取对象名称, 对象名称为a.b.c格式 + */ +const char * ioc_obj_get_name(lv_obj_t * obj); + +/** + * @note 判断name是否是prefix的前缀 + * 前缀一定是"main_quad.connector_quad_group.connector*"格式, 即 prefix+星号结束 + * + */ +bool ioc_obj_name_is_prefix(const char * name, int * prefix_len); + +/** + * @note 判断name是否符合prefix格式 + * 前缀一定是"main_quad.connector_quad_group.connector*"格式, 即 prefix+星号结束 + * 我们系统的复杂度目前只考虑一级前缀, 不考虑多级 + * name可能有两个格式 + * 1. "main_quad.connector_quad_group.connector1" + * 2. "main_quad.connector_quad_group.connector1.label" + * 分别对应解析结果为 + * 1. prefix = "main_quad.connector_quad_group.connector", idx = 1, name = NULL + * 2. prefix = "main_quad.connector_quad_group.connector", idx = 1, name = "label" + * 注意, name_after_prefix是name去掉prefix后的结果, 直接指向name的内存, 不需要用户释放 + */ +bool ioc_obj_name_match_prefix(const char * name // 待匹配的name + , const char * prefix , int prefix_len // 预设前缀 + , int * idx // 匹配到的idx + , const char ** name_after_prefix, int * name_after_prefix_len // name去掉prefix和idx后的结果 +); +#define IOC_OBJ_NAME_MATCH_AFTER_PREFIX(preset_const, name_after_prefix, name_after_prefix_len) \ + ((name_after_prefix_len == strlen(preset_const)) && strncmp(name_after_prefix, preset_const, name_after_prefix_len) == 0) + +/** + * @note 在创建对象之前调用, 可以根据name决定是否创建对象 + */ +bool ioc_obj_handler_before_create(const char * name); +/** + * @note 在创建对象之后调用, 可以根据name进行后续的处理 + */ +void ioc_obj_handler_after_create(const char * name, lv_obj_t * obj); + +void ioc_obj_set_properties_position(lv_obj_t *obj, cJSON *properties_json); +void ioc_obj_set_properties_size(lv_obj_t *obj, cJSON *properties_json); +void ioc_obj_set_properties_align(lv_obj_t * obj, cJSON *properties_json); +void ioc_obj_set_properties_flex_flow(lv_obj_t *flex, cJSON *properties_json); +void ioc_obj_set_properties_flex_align(lv_obj_t *flex, cJSON *properties_json); +void ioc_obj_set_properties_style(lv_obj_t *obj, cJSON *properties_json); +void ioc_obj_set_properties_image_path(lv_obj_t *img, cJSON *properties_json); +void ioc_obj_set_properties_label_text(lv_obj_t *label, cJSON *properties_json); +bool ioc_label_set_text(lv_obj_t *label, const char * text_id); + + + +#endif diff --git a/ioc/mngr/ioc_string_2_enum.c b/ioc/mngr/ioc_string_2_enum.c new file mode 100644 index 000000000..2c6ccd72d --- /dev/null +++ b/ioc/mngr/ioc_string_2_enum.c @@ -0,0 +1,137 @@ +#include "ioc_app.h" + +lv_align_t ioc_string_2_align(const char *align_name) +{ + if (strcmp(align_name, "LV_ALIGN_TOP_LEFT") == 0) + return LV_ALIGN_TOP_LEFT; + if (strcmp(align_name, "LV_ALIGN_TOP_MID") == 0) + return LV_ALIGN_TOP_MID; + if (strcmp(align_name, "LV_ALIGN_TOP_RIGHT") == 0) + return LV_ALIGN_TOP_RIGHT; + if (strcmp(align_name, "LV_ALIGN_BOTTOM_LEFT") == 0) + return LV_ALIGN_BOTTOM_LEFT; + if (strcmp(align_name, "LV_ALIGN_BOTTOM_MID") == 0) + return LV_ALIGN_BOTTOM_MID; + if (strcmp(align_name, "LV_ALIGN_BOTTOM_RIGHT") == 0) + return LV_ALIGN_BOTTOM_RIGHT; + if (strcmp(align_name, "LV_ALIGN_LEFT_MID") == 0) + return LV_ALIGN_LEFT_MID; + if (strcmp(align_name, "LV_ALIGN_RIGHT_MID") == 0) + return LV_ALIGN_RIGHT_MID; + if (strcmp(align_name, "LV_ALIGN_CENTER") == 0) + return LV_ALIGN_CENTER; + if (strcmp(align_name, "LV_ALIGN_OUT_TOP_LEFT") == 0) + return LV_ALIGN_OUT_TOP_LEFT; + if (strcmp(align_name, "LV_ALIGN_OUT_TOP_MID") == 0) + return LV_ALIGN_OUT_TOP_MID; + if (strcmp(align_name, "LV_ALIGN_OUT_TOP_RIGHT") == 0) + return LV_ALIGN_OUT_TOP_RIGHT; + if (strcmp(align_name, "LV_ALIGN_OUT_BOTTOM_LEFT") == 0) + return LV_ALIGN_OUT_BOTTOM_LEFT; + if (strcmp(align_name, "LV_ALIGN_OUT_BOTTOM_MID") == 0) + return LV_ALIGN_OUT_BOTTOM_MID; + if (strcmp(align_name, "LV_ALIGN_OUT_BOTTOM_RIGHT") == 0) + return LV_ALIGN_OUT_BOTTOM_RIGHT; + if (strcmp(align_name, "LV_ALIGN_OUT_LEFT_TOP") == 0) + return LV_ALIGN_OUT_LEFT_TOP; + if (strcmp(align_name, "LV_ALIGN_OUT_LEFT_MID") == 0) + return LV_ALIGN_OUT_LEFT_MID; + if (strcmp(align_name, "LV_ALIGN_OUT_LEFT_BOTTOM") == 0) + return LV_ALIGN_OUT_LEFT_BOTTOM; + if (strcmp(align_name, "LV_ALIGN_OUT_RIGHT_TOP") == 0) + return LV_ALIGN_OUT_RIGHT_TOP; + if (strcmp(align_name, "LV_ALIGN_OUT_RIGHT_MID") == 0) + return LV_ALIGN_OUT_RIGHT_MID; + if (strcmp(align_name, "LV_ALIGN_OUT_RIGHT_BOTTOM") == 0) + return LV_ALIGN_OUT_RIGHT_BOTTOM; + + return LV_ALIGN_DEFAULT; +} + + +lv_text_align_t ioc_string_2_text_align(const char *align_name) +{ + if (strcmp(align_name, "LV_TEXT_ALIGN_AUTO") == 0) + return LV_TEXT_ALIGN_AUTO; + if (strcmp(align_name, "LV_TEXT_ALIGN_LEFT") == 0) + return LV_TEXT_ALIGN_LEFT; + if (strcmp(align_name, "LV_TEXT_ALIGN_RIGHT") == 0) + return LV_TEXT_ALIGN_RIGHT; + + return LV_TEXT_ALIGN_CENTER; +} + +lv_flex_flow_t ioc_string_2_flex_flow(const char *flow_name) +{ + if (flow_name != NULL) + { + if (strcmp(flow_name, "LV_FLEX_FLOW_ROW") == 0) + { + return LV_FLEX_FLOW_ROW; + } + else if (strcmp(flow_name, "LV_FLEX_FLOW_COLUMN") == 0) + { + return LV_FLEX_FLOW_COLUMN; + } + else if (strcmp(flow_name, "LV_FLEX_FLOW_ROW_WRAP") == 0) + { + return LV_FLEX_FLOW_ROW_WRAP; + } + else if (strcmp(flow_name, "LV_FLEX_FLOW_ROW_REVERSE") == 0) + { + return LV_FLEX_FLOW_ROW_REVERSE; + } + else if (strcmp(flow_name, "LV_FLEX_FLOW_ROW_WRAP_REVERSE") == 0) + { + return LV_FLEX_FLOW_ROW_WRAP_REVERSE; + } + else if (strcmp(flow_name, "LV_FLEX_FLOW_COLUMN_WRAP") == 0) + { + return LV_FLEX_FLOW_COLUMN_WRAP; + } + else if (strcmp(flow_name, "LV_FLEX_FLOW_COLUMN_REVERSE") == 0) + { + return LV_FLEX_FLOW_COLUMN_REVERSE; + } + else if (strcmp(flow_name, "LV_FLEX_FLOW_COLUMN_WRAP_REVERSE") == 0) + { + return LV_FLEX_FLOW_COLUMN_WRAP_REVERSE; + } + } + + return LV_FLEX_FLOW_ROW; +} + + +lv_flex_align_t ioc_string_2_flex_align(const char *align_name) +{ + if (align_name != NULL) + { + if (strcmp(align_name, "LV_FLEX_ALIGN_START") == 0) + { + return LV_FLEX_ALIGN_START; + } + else if (strcmp(align_name, "LV_FLEX_ALIGN_CENTER") == 0) + { + return LV_FLEX_ALIGN_CENTER; + } + else if (strcmp(align_name, "LV_FLEX_ALIGN_END") == 0) + { + return LV_FLEX_ALIGN_END; + } + else if (strcmp(align_name, "LV_FLEX_ALIGN_SPACE_AROUND") == 0) + { + return LV_FLEX_ALIGN_SPACE_AROUND; + } + else if (strcmp(align_name, "LV_FLEX_ALIGN_SPACE_BETWEEN") == 0) + { + return LV_FLEX_ALIGN_SPACE_BETWEEN; + } + else if (strcmp(align_name, "LV_FLEX_ALIGN_SPACE_EVENLY") == 0) + { + return LV_FLEX_ALIGN_SPACE_EVENLY; + } + } + + return LV_FLEX_ALIGN_START; +} diff --git a/ioc/mngr/ioc_string_2_enum.h b/ioc/mngr/ioc_string_2_enum.h new file mode 100644 index 000000000..e8ff5cdc0 --- /dev/null +++ b/ioc/mngr/ioc_string_2_enum.h @@ -0,0 +1,11 @@ +#ifndef __IOC_STRING_2_ENUM_H__ +#define __IOC_STRING_2_ENUM_H__ + +#include "lvgl.h" + +lv_align_t ioc_string_2_align(const char *align_name); +lv_flex_flow_t ioc_string_2_flex_flow(const char *flow_name); +lv_flex_align_t ioc_string_2_flex_align(const char *align_name); +lv_text_align_t ioc_string_2_text_align(const char *align_name); + +#endif diff --git a/ioc/mngr/ioc_style_mngr.c b/ioc/mngr/ioc_style_mngr.c new file mode 100644 index 000000000..dc7f60974 --- /dev/null +++ b/ioc/mngr/ioc_style_mngr.c @@ -0,0 +1,264 @@ +#include "ioc_app.h" + +static cJSON *s_styles_json = NULL; + +static ioc_style_t **s_styles = NULL; +static int s_styles_cnt = 0; +static int s_style_idx = 0; + + +static void ioc_style_mngr_update_style(ioc_style_t * ioc_style, cJSON *style_json, bool init) +{ + cJSON * styles = cJSON_GetObjectItem(style_json, "styles"); + if (styles == NULL) + { + return; + } + + for (int i = 0; i < ioc_style->style_count; i++) + { + cJSON * style = cJSON_GetArrayItem(styles, i); + if (style == NULL) + { + break; + } + + if (init) + { + ioc_style->styles[i].name = cJSON_GetObjectItem(style, "name")->valuestring; + + lv_style_init(&ioc_style->styles[i].style); + } + + const char *bg_color_name = cJSON_GetStringValue(cJSON_GetObjectItem(style, "bg_color_name")); + if (bg_color_name != NULL) + { + lv_style_set_bg_color(&ioc_style->styles[i].style, ioc_theme_getcolor(bg_color_name)); + // LV_LOG_WARN("bg_color_name[%s] [%x]", bg_color_name, ioc_theme_getcolor(bg_color_name)); + + } + cJSON * border_radius = cJSON_GetObjectItem(style, "border_radius"); + if (border_radius != NULL) + { + lv_style_set_radius(&ioc_style->styles[i].style, border_radius->valueint); + } + cJSON * border_width = cJSON_GetObjectItem(style, "border_width"); + if (border_width != NULL) + { + lv_style_set_border_width(&ioc_style->styles[i].style, border_width->valueint); + } + + lv_style_set_pad_all(&ioc_style->styles[i].style, 0); + cJSON * padding = cJSON_GetObjectItem(style, "padding"); + if (padding != NULL) + { + lv_style_set_pad_all(&ioc_style->styles[i].style, padding->valueint); + } + + cJSON * width = cJSON_GetObjectItem(style, "width"); + if (width != NULL) + { + lv_style_set_width(&ioc_style->styles[i].style, width->valueint); + } + cJSON * height = cJSON_GetObjectItem(style, "height"); + if (height != NULL) + { + lv_style_set_height(&ioc_style->styles[i].style, height->valueint); + } + const char *border_color_name = cJSON_GetStringValue(cJSON_GetObjectItem(style, "border_color_name")); + if (border_color_name != NULL) + { + lv_style_set_border_color(&ioc_style->styles[i].style, ioc_theme_getcolor(border_color_name)); + } + const char *font_name = cJSON_GetStringValue(cJSON_GetObjectItem(style, "font_name")); + if (font_name != NULL) + { + lv_style_set_text_font(&ioc_style->styles[i].style, ioc_theme_getfont(font_name)); + } + const char *text_color_name = cJSON_GetStringValue(cJSON_GetObjectItem(style, "text_color_name")); + if (text_color_name != NULL) + { + lv_style_set_text_color(&ioc_style->styles[i].style, ioc_theme_getcolor(text_color_name)); + } + cJSON * opacity = cJSON_GetObjectItem(style, "opacity"); + if (opacity != NULL) + { + lv_style_set_bg_opa(&ioc_style->styles[i].style, opacity->valueint); + } + } +} + +static ioc_style_t *ioc_style_mngr_load_style(cJSON *style_json) +{ + ioc_style_t * ioc_style = (ioc_style_t *)malloc(sizeof(ioc_style_t)); + if (ioc_style == NULL) + { + LV_LOG_ERROR("malloc failed"); + return NULL; + } + + ioc_style->name = strdup(cJSON_GetObjectItem(style_json, "name")->valuestring); + + ioc_style->style_count = 0; + cJSON * styles = cJSON_GetObjectItem(style_json, "styles"); + if (styles != NULL) + { + ioc_style->style_count = cJSON_GetArraySize(styles); + ioc_style->styles = (ioc_style_one_t *)calloc(ioc_style->style_count, sizeof(ioc_style_one_t)); + if (ioc_style->styles == NULL) + { + LV_LOG_ERROR("malloc failed"); + free(ioc_style); + return NULL; + } + + ioc_style_mngr_update_style(ioc_style, style_json, true); + } + + return ioc_style; +} + +static bool ioc_style_mngr_load_dir(const char *style_path) +{ + DIR *dir = opendir(style_path); + if (dir == NULL) + { + LV_LOG_ERROR("failed %s", style_path); + return false; + } + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) + { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + char file_path[512]; + snprintf(file_path, sizeof(file_path), "%s/%s", style_path, entry->d_name); + cJSON *style_json = JSON_FromFile(file_path); + if (style_json == NULL) + { + LV_LOG_ERROR("cant't open %s", file_path); + closedir(dir); + return false; + } + cJSON_Merge(s_styles_json, style_json); + cJSON_Delete(style_json); + } + closedir(dir); + return true; +} + +bool ioc_style_mngr_load(const char *using_style_name) +{ + // 初始化一个空的片段包 + ioc_style_mngr_unload(); + s_styles_json = cJSON_CreateArray(); + + if (!ioc_style_mngr_load_dir(STYLE_ROOT_PATH)) + { + LV_LOG_ERROR("Can't load style root path %s", STYLE_ROOT_PATH); + return false; + } + if (access(STYLE_PATCH_PATH, F_OK) == 0) + { + if (!ioc_style_mngr_load_dir(STYLE_PATCH_PATH)) + { + LV_LOG_ERROR("Can't load style patch path %s", STYLE_PATCH_PATH); + return false; + } + } + else + { + LV_LOG_INFO("Skip style patch path %s", STYLE_PATCH_PATH); + } + + // char * p = cJSON_Print(s_styles_json); + // printf("%s\n", p); + // cJSON_free(p); + + s_style_idx = 0; + s_styles_cnt = cJSON_GetArraySize(s_styles_json); + s_styles = (ioc_style_t **)calloc(s_styles_cnt, sizeof(ioc_style_t *)); + for (int i = 0; i < s_styles_cnt; i++) + { + s_styles[i] = ioc_style_mngr_load_style(cJSON_GetArrayItem(s_styles_json, i)); + if (s_styles[i] == NULL) + { + LV_LOG_ERROR("load style failed"); + ioc_style_mngr_unload(); + return false; + } + + if (using_style_name != NULL && strcmp(s_styles[i]->name, using_style_name) == 0) + { + s_style_idx = i; + LV_LOG_WARN("Using %s at %d", s_styles[i]->name, s_style_idx); + } + } + + return true; +} + +static void ioc_style_release(ioc_style_t *style) +{ + if (style != NULL) + { + if (style->name != NULL) + { + free(style->name); + style->name = NULL; + } + + if (style->styles) + { + free(style->styles); + style->styles = NULL; + } + + free(style); + } +} + +void ioc_style_mngr_unload(void) +{ + if (s_styles != NULL) + { + for (int i = 0; i < s_styles_cnt; i++) + { + ioc_style_release(s_styles[i]); + } + } + free(s_styles); + s_styles = NULL; + s_styles_cnt = 0; + + if (s_styles_json != NULL) + { + cJSON_Delete(s_styles_json); + s_styles_json = NULL; + } +} + +void ioc_style_mngr_theme_changed(void) +{ + ioc_style_mngr_update_style(s_styles[s_style_idx], cJSON_GetArrayItem(s_styles_json, s_style_idx), false); +} + +lv_style_t *ioc_style_mngr_get_style(const char *style_name) +{ + + if (s_styles == NULL) + { + return NULL; + } + if (s_style_idx < s_styles_cnt) + { + for (int i = 0; i < s_styles[s_style_idx]->style_count; i++) + { + if (strcmp(s_styles[s_style_idx]->styles[i].name, style_name) == 0) + { + return &s_styles[s_style_idx]->styles[i].style; + } + } + } + + return NULL; +} diff --git a/ioc/mngr/ioc_style_mngr.h b/ioc/mngr/ioc_style_mngr.h new file mode 100644 index 000000000..290654985 --- /dev/null +++ b/ioc/mngr/ioc_style_mngr.h @@ -0,0 +1,30 @@ +#ifndef __IOC_STYLE_MNGR_H__ +#define __IOC_STYLE_MNGR_H__ + +#include "lvgl.h" + +#define STYLE_ROOT_PATH "./assets/style/" +#define STYLE_PATCH_PATH "./patch/style/" + +typedef struct +{ + const char * name; + lv_style_t style; +} ioc_style_one_t; + +typedef struct { + char *name; + + ioc_style_one_t * styles; + int style_count; + +} ioc_style_t; + +bool ioc_style_mngr_load(const char * using_style_name); +void ioc_style_mngr_unload(void); +bool ioc_style_mngr_switch(const char * using_style_name); +void ioc_style_mngr_theme_changed(void); + +lv_style_t * ioc_style_mngr_get_style(const char *style_name); + +#endif diff --git a/ioc/mngr/ioc_theme_mngr.c b/ioc/mngr/ioc_theme_mngr.c new file mode 100644 index 000000000..09dea286c --- /dev/null +++ b/ioc/mngr/ioc_theme_mngr.c @@ -0,0 +1,345 @@ +#include "ioc_app.h" + +static cJSON * s_themes_json = NULL; + +static ioc_theme_t ** s_themes = NULL; +static int s_themes_count = 0; +static int s_themes_idx = 0; + +static void ioc_theme_release(ioc_theme_t *theme) +{ + if (theme != NULL) + { + if (theme->colors != NULL) + { + free(theme->colors); + } + if (theme->fonts != NULL) + { + free(theme->fonts); + } + if (theme->imgs != NULL) + { + free(theme->imgs); + } + free(theme); + } +} + +void ioc_theme_mngr_unload(void) +{ + if (s_themes != NULL) + { + for (int i = 0; i < s_themes_count; i++) + { + ioc_theme_release(s_themes[i]); + } + free(s_themes); + s_themes = NULL; + } + s_themes_count = 0; + + if (s_themes_json != NULL) + { + cJSON_Delete(s_themes_json); + s_themes_json = NULL; + } +} + +// 主函数:解析 JSON 数据 +ioc_theme_t *ioc_theme_parse(cJSON *theme_json) +{ + ioc_theme_t *theme = (ioc_theme_t *)malloc(sizeof(ioc_theme_t)); + if (!theme) + { + LV_LOG_ERROR("malloc failed"); + return NULL; + } + + // 解析主题名称 + cJSON *name = cJSON_GetObjectItem(theme_json, "name"); + if ((name == NULL) || !cJSON_IsString(name)) + { + LV_LOG_ERROR("miss name"); + free(theme); + return NULL; + } + theme->name = name->valuestring; + + // 解析颜色 + cJSON *colors = cJSON_GetObjectItem(theme_json, "colors"); + if (colors == NULL || !cJSON_IsArray(colors)) + { + LV_LOG_ERROR("miss colors"); + free(theme); + return NULL; + } + int color_count = cJSON_GetArraySize(colors); + theme->colors = (ioc_theme_color_t *)calloc(color_count, sizeof(ioc_theme_color_t)); + theme->color_count = color_count; + for (int i = 0; i < color_count; i++) { + cJSON *color_item = cJSON_GetArrayItem(colors, i); + cJSON *color_name = cJSON_GetObjectItem(color_item, "name"); + cJSON *color_value = cJSON_GetObjectItem(color_item, "value"); + if (color_name != NULL && color_value != NULL && cJSON_IsString(color_name) && cJSON_IsString(color_value)) + { + theme->colors[i].name = color_name->valuestring; + theme->colors[i].value = color_value->valuestring; + LV_LOG_INFO("color: %s", color_name->valuestring); + } + else + { + LV_LOG_ERROR("miss color name or value"); + free(theme); + return NULL; + } + } + + // 解析字体 + cJSON *fonts = cJSON_GetObjectItem(theme_json, "fonts"); + if (fonts == NULL || !cJSON_IsArray(fonts)) + { + LV_LOG_ERROR("miss fonts"); + free(theme); + return NULL; + } + int font_count = cJSON_GetArraySize(fonts); + theme->fonts = (ioc_theme_font_t *)calloc(font_count, sizeof(ioc_theme_font_t)); + theme->font_count = font_count; + for (int i = 0; i < font_count; i++) { + cJSON *font_item = cJSON_GetArrayItem(fonts, i); + cJSON *font_name = cJSON_GetObjectItem(font_item, "name"); + cJSON *font_family = cJSON_GetObjectItem(font_item, "family"); + cJSON *font_size = cJSON_GetObjectItem(font_item, "size"); + cJSON *font_bold = cJSON_GetObjectItem(font_item, "bold"); + if (font_name != NULL && font_family != NULL && font_size != NULL && cJSON_IsString(font_name) && cJSON_IsString(font_family) && cJSON_IsNumber(font_size)) + { + theme->fonts[i].name = font_name->valuestring; + #if (LVGL_VERSION_MAJOR == 9) + #if LV_USE_FREETYPE + theme->fonts[i].font = lv_freetype_font_create(font_family->valuestring, + (font_size->valueint > 16) ? LV_FREETYPE_FONT_RENDER_MODE_BITMAP : LV_FREETYPE_FONT_RENDER_MODE_OUTLINE, + font_size->valueint, + (font_bold != NULL && cJSON_IsBool(font_bold)) ? LV_FREETYPE_FONT_STYLE_BOLD : LV_FREETYPE_FONT_STYLE_NORMAL); + #else + theme->fonts[i].font = LV_FONT_DEFAULT; + #endif + #else + theme->fonts[i].font_info.name = font_family->valuestring; + theme->fonts[i].font_info.weight = font_size->valueint; + if (font_bold != NULL && cJSON_IsBool(font_bold)) + { + theme->fonts[i].font_info.style = FT_FONT_STYLE_BOLD; + } + else + { + theme->fonts[i].font_info.style = FT_FONT_STYLE_NORMAL; + } + lv_ft_font_init(&theme->fonts[i].font_info); + #endif + LV_LOG_INFO("font: %s", font_name->valuestring); + } + else + { + LV_LOG_ERROR("miss font name or family or size"); + free(theme); + return NULL; + } + + } + + // 解析图片 + cJSON *imgs = cJSON_GetObjectItem(theme_json, "images"); + if (imgs == NULL || !cJSON_IsArray(imgs)) + { + LV_LOG_ERROR("miss images"); + free(theme); + return NULL; + } + int img_count = cJSON_GetArraySize(imgs); + theme->imgs = (ioc_theme_img_t *)calloc(img_count, sizeof(ioc_theme_img_t)); + theme->img_count = img_count; + for (int i = 0; i < img_count; i++) { + cJSON *img_item = cJSON_GetArrayItem(imgs, i); + cJSON *img_name = cJSON_GetObjectItem(img_item, "name"); + cJSON *img_path = cJSON_GetObjectItem(img_item, "path"); + if (img_name != NULL && img_path != NULL && cJSON_IsString(img_name) && cJSON_IsString(img_path)) + { + theme->imgs[i].name = img_name->valuestring; + theme->imgs[i].path = img_path->valuestring; + // printf("img: %s->%s\n", img_name->valuestring, img_path->valuestring); + } + else + { + LV_LOG_ERROR("miss img name or path"); + free(theme); + return NULL; + } + } + + return theme; +} + +static bool ioc_theme_mngr_load_dir(const char * theme_path) +{ + DIR *dir = opendir(theme_path); + if (dir == NULL) + { + LV_LOG_ERROR("failed %s", theme_path); + return false; + } + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) + { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + char file_path[512]; + snprintf(file_path, sizeof(file_path), "%s/%s", theme_path, entry->d_name); + cJSON *theme_json = JSON_FromFile(file_path); + if (theme_json == NULL) + { + LV_LOG_ERROR("cant't open %s", file_path); + closedir(dir); + return false; + } + cJSON_Merge(s_themes_json, theme_json); + cJSON_Delete(theme_json); + } + closedir(dir); + return true; +} + +bool ioc_theme_mngr_load(const char * using_theme_name) +{ + // 初始化一个空的主题包 + ioc_theme_mngr_unload(); + s_themes_json = cJSON_CreateArray(); + + if (!ioc_theme_mngr_load_dir(THEME_ROOT_PATH)) + { + LV_LOG_ERROR("Can't load theme root path %s", THEME_ROOT_PATH); + return false; + } + if (access(THEME_PATCH_PATH, F_OK) == 0) + { + if (!ioc_theme_mngr_load_dir(THEME_PATCH_PATH)) + { + LV_LOG_ERROR("Can't load theme patch path %s", THEME_PATCH_PATH); + return false; + } + } + else + { + LV_LOG_INFO("Skip theme patch path %s", THEME_PATCH_PATH); + } + + + // char * p = cJSON_Print(s_themes_json); + // printf("%s\n", p); + // cJSON_free(p); + + s_themes_idx = 0; + s_themes_count = cJSON_GetArraySize(s_themes_json); + s_themes = (ioc_theme_t **)calloc(s_themes_count, sizeof(ioc_theme_t*)); + for (int i = 0; i < s_themes_count; i++) + { + s_themes[i] = ioc_theme_parse(cJSON_GetArrayItem(s_themes_json, i)); + if (s_themes[i] == NULL) + { + LV_LOG_ERROR("can't parse theme"); + ioc_theme_mngr_unload(); + return false; + } + + if (using_theme_name != NULL && strcmp(s_themes[i]->name, using_theme_name) == 0) + { + s_themes_idx = i; + LV_LOG_WARN("Using %s at %d", s_themes[i]->name, s_themes_idx); + } + } + + return true; +} + +bool ioc_theme_mngr_switch(const char * using_theme_name) +{ + for (int i = 0; i < s_themes_count; i++) + { + if (strcmp(s_themes[i]->name, using_theme_name) == 0) + { + if (s_themes_idx != i) + { + s_themes_idx = i; + LV_LOG_WARN("Using %s at %d", s_themes[i]->name, s_themes_idx); + return true; + } + else + { + LV_LOG_WARN("Already using %s at %d", s_themes[i]->name, s_themes_idx); + return false; + } + } + } + + LV_LOG_ERROR("Theme %s not found", using_theme_name); + return false; +} + +lv_color_t ioc_theme_getcolor(const char * name) +{ + if (s_themes_idx < s_themes_count) + { + for (int i = 0; i < s_themes[s_themes_idx]->color_count; i++) + { + if (strcmp(s_themes[s_themes_idx]->colors[i].name, name) == 0) + { + int r, g, b; + sscanf(s_themes[s_themes_idx]->colors[i].value, "#%2x%2x%2x", &r, &g, &b); + return lv_color_make(r & 0xFF, g & 0xFF, b & 0xFF); + } + } + } + + return lv_color_black(); +} + +const lv_font_t * ioc_theme_getfont(const char * name) +{ + if (s_themes_idx < s_themes_count) + { + for (int i = 0; i < s_themes[s_themes_idx]->font_count; i++) + { + if (strcmp(s_themes[s_themes_idx]->fonts[i].name, name) == 0) + { + #if (LVGL_VERSION_MAJOR == 9) + return s_themes[s_themes_idx]->fonts[i].font; + #else + return s_themes[s_themes_idx]->fonts[i].font_info.font; + #endif + } + } + } +#if (LVGL_VERSION_MAJOR == 9) + return s_themes[0]->fonts[0].font; +#else + return s_themes[0]->fonts[0].font_info.font; +#endif +} + +const char * ioc_theme_getimgpath(const char * name) +{ + if (s_themes_idx < s_themes_count) + { + for (int i = 0; i < s_themes[s_themes_idx]->img_count; i++) + { + if (strcmp(s_themes[s_themes_idx]->imgs[i].name, name) == 0) + { + return s_themes[s_themes_idx]->imgs[i].path; + // LV_LOG_WARN("path[%s]", s_themes[s_themes_idx]->imgs[i].path); + } + } + } + + LV_LOG_WARN("name[%s] path NULL", name); + + return NULL; +} diff --git a/ioc/mngr/ioc_theme_mngr.h b/ioc/mngr/ioc_theme_mngr.h new file mode 100644 index 000000000..d2d97d4e3 --- /dev/null +++ b/ioc/mngr/ioc_theme_mngr.h @@ -0,0 +1,53 @@ +#ifndef __IOC_THEME_MNGR_H__ +#define __IOC_THEME_MNGR_H__ + +#include "lvgl.h" + +#define THEME_ROOT_PATH "./assets/theme/" +#define THEME_PATCH_PATH "./patch/theme/" + +typedef struct +{ + const char * name; + const char * value; +} ioc_theme_color_t; + +typedef struct +{ + const char * name; +#if (LVGL_VERSION_MAJOR == 9) + lv_font_t * font; +#else + lv_ft_info_t font_info; +#endif +} ioc_theme_font_t; + +typedef struct { + const char * name; + const char * path; +} ioc_theme_img_t; + +typedef struct { + const char * name; + + ioc_theme_color_t * colors; + int color_count; + + ioc_theme_font_t * fonts; + int font_count; + + ioc_theme_img_t * imgs; + int img_count; + +} ioc_theme_t; + + +bool ioc_theme_mngr_load(const char * using_theme_name); +void ioc_theme_mngr_unload(void); +bool ioc_theme_mngr_switch(const char * using_theme_name); + +lv_color_t ioc_theme_getcolor(const char * name); +const lv_font_t * ioc_theme_getfont(const char * name); +const char * ioc_theme_getimgpath(const char * name); + +#endif diff --git a/ioc/mqtt/ioc_mqtt.c b/ioc/mqtt/ioc_mqtt.c new file mode 100644 index 000000000..658a82310 --- /dev/null +++ b/ioc/mqtt/ioc_mqtt.c @@ -0,0 +1,964 @@ +#include "ioc_app.h" +#include +// #include +// #include +#include +// #include +#include +#include "mosquitto.h" + +// 测试用 +// #define MQTT_TEST + +#if (COMPILER_FOR == COMPILE_FOR_CABINET_SSD202) + +static struct mosquitto *s_mosq; +static Mqtt_Connetc_Status s_Connect_Satus; +static bool IsMsg = false; + +static int last_connNum = 0; +static int last_connIdx[UI_MAX_CONNECTOR_NUM] = {-1, -1}; // 记录上一次的枪号,初始化为-1 +static int last_autGroup = -1; // 记录上一次的授权组 + +static bool TestMode = false; +// 定义最大主题长度 +#define MAX_TOPIC_LENGTH 128 + +// 订阅的主题名称 +const char * c_mqttSubscribeNames[SUBSCRIBE_NUM] = +{ + "/global-sysconfig", + "/homeOcpp/UI/global-data", + "/homeOcpp/UI/conn-%d", + "/authGroup/display-%d/trigger", + "/TestRGB" +}; + +// 发布的主题名称 +const char * c_mqttPublishNames[PUBLISH_NUM] = +{ + "/homeOcpp/UI", + "/TestRGB_RESP" +}; + +typedef struct +{ + char address[64]; // MQTT 代理地址 + int port; // 端口号 + char clientID[64]; // 客户端 ID +} MqttConfig; + +MqttConfig s_mqttConfig; // mqtt 配置address 和 port 从UDP 获取 + +#define BUFFER_SIZE 1024 +#define QOS 1 // 服务质量 (0, 1, 2) + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// 发布 +int ioc_mqtt_publish(uint8_t connId, Publish_List_t list, char * pData) +{ + char pPublish[128] = {0}; + bool retain = true; + + if (s_Connect_Satus != MQTT_CONNECTED) + { + LV_LOG_WARN("MQTT not connected"); + return -1; + } + + if(pData == NULL) + { + LV_LOG_WARN("pData is NULL"); + return -1; + } + + snprintf(pPublish, sizeof(pPublish), "%s", c_mqttPublishNames[list]); + + return mosquitto_publish(s_mosq, NULL, pPublish, strlen(pData), pData, 2, retain); +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static bool get_json_u8(cJSON *root, const char *fmt, int idx, int *out_val) +{ + char key[32] = {0}; + snprintf(key, sizeof(key), fmt, idx); + cJSON *item = cJSON_GetObjectItem(root, key); + if (item && cJSON_IsString(item)) + { + *out_val = atoi(item->valuestring); + return true; + } + return false; +} +static void TestRGB_subscribe(void) +{ + if (s_Connect_Satus == MQTT_CONNECTED) + { + int rc = mosquitto_subscribe(s_mosq, NULL, c_mqttSubscribeNames[SUBSCRIBE_TestRGB], QOS); + // DEBUG_INFO("subscribe[%s]", new_topic); + if (rc != MOSQ_ERR_SUCCESS) + { + LV_LOG_WARN("Error subscribing new conn topic: %s (%s)\n", c_mqttSubscribeNames[SUBSCRIBE_TestRGB], mosquitto_strerror(rc)); + mosquitto_disconnect(s_mosq); + } + else + { + LV_LOG_WARN("new_topic[%s]", c_mqttSubscribeNames[SUBSCRIBE_TestRGB]); + } + } +} +static void conns_subscribe(void) +{ + int new_connNum = UI_NUMOFCONNECTOR; + + // DEBUG_INFO("last_connNum[%d] new_connNum[%d]", last_connNum, new_connNum); + + // 先取消多余的订阅(如果枪数量减少了) + for (int i = new_connNum; i < last_connNum; i++) + { + LV_LOG_WARN("i[%d] last_connIdx[%d]", i, last_connIdx[i]); + if (last_connIdx[i] >= 0) + { + char old_topic[MAX_TOPIC_LENGTH] = {0}; + snprintf(old_topic, MAX_TOPIC_LENGTH, c_mqttSubscribeNames[SUBSCRIBE_UI_CONNS], last_connIdx[i]); + + if (s_Connect_Satus == MQTT_CONNECTED) + { + int rc = mosquitto_unsubscribe(s_mosq, NULL, old_topic); + // DEBUG_INFO("unsubscribe[%s]", old_topic); + if (rc != MOSQ_ERR_SUCCESS) + { + LV_LOG_WARN("Error unsubscribing old conn topic: %s (%s)\n", old_topic, mosquitto_strerror(rc)); + } + } + last_connIdx[i] = -1; + } + } + + // 遍历新枪数量,检查是否需要重新订阅 + for (int i = 0; i < new_connNum && i < UI_MAX_CONNECTOR_NUM; i++) + { + int new_idx = g_ui_json.dispenserConfig.connIdx[i]; + + LV_LOG_WARN("i[%d] new_idx[%d] last_connIdx[%d]", i, new_idx, last_connIdx[i]); + + if (new_idx != last_connIdx[i]) // 如果枪号变了 + { + LV_LOG_WARN("i[%d] new_idx[%d] last_connIdx[%d]", i, new_idx, last_connIdx[i]); + + // 取消旧的订阅 + if (last_connIdx[i] >= 0) + { + char old_topic[MAX_TOPIC_LENGTH] = {0}; + snprintf(old_topic, MAX_TOPIC_LENGTH, c_mqttSubscribeNames[SUBSCRIBE_UI_CONNS], last_connIdx[i]); + + LV_LOG_WARN("===old_topic[%s]", old_topic); + + + if (s_Connect_Satus == MQTT_CONNECTED) + { + int rc = mosquitto_unsubscribe(s_mosq, NULL, old_topic); + if (rc != MOSQ_ERR_SUCCESS) + { + LV_LOG_WARN("Error unsubscribing old conn topic: %s (%s)\n", old_topic, mosquitto_strerror(rc)); + } + } + } + + // 订阅新的 + char new_topic[MAX_TOPIC_LENGTH] = {0}; + snprintf(new_topic, MAX_TOPIC_LENGTH, c_mqttSubscribeNames[SUBSCRIBE_UI_CONNS], new_idx); + + // LV_LOG_WARN("new_topic[%s]", new_topic); + + if (s_Connect_Satus == MQTT_CONNECTED) + { + int rc = mosquitto_subscribe(s_mosq, NULL, new_topic, QOS); + // DEBUG_INFO("subscribe[%s]", new_topic); + if (rc != MOSQ_ERR_SUCCESS) + { + LV_LOG_WARN("Error subscribing new conn topic: %s (%s)\n", new_topic, mosquitto_strerror(rc)); + mosquitto_disconnect(s_mosq); + } + else + { + LV_LOG_WARN("new_topic[%s]", new_topic); + } + } + + last_connIdx[i] = new_idx; + } + } + + // 更新记录的枪数量 + last_connNum = new_connNum; +} + + +static void authGroup_subscribe() +{ + // 如果授权组变化了,重新订阅 + if (g_ui_json.dispenserConfig.autGroup != last_autGroup) + { + // 如果已经有旧的订阅,先取消 + if (last_autGroup >= 0) + { + char old_topic[MAX_TOPIC_LENGTH] = {0}; + snprintf(old_topic, MAX_TOPIC_LENGTH, c_mqttSubscribeNames[SUBSCRIBE_TRIGGER], last_autGroup); + + if (s_Connect_Satus == MQTT_CONNECTED) + { + int rc = mosquitto_unsubscribe(s_mosq, NULL, old_topic); + if (rc != MOSQ_ERR_SUCCESS) + { + LV_LOG_WARN("Error unsubscribing old topic: %s\n", mosquitto_strerror(rc)); + } + else + { + LV_LOG_WARN("Unsubscribed old topic: %s", old_topic); + } + } + } + + // 拼接新的订阅主题 + char new_topic[MAX_TOPIC_LENGTH] = {0}; + snprintf(new_topic, MAX_TOPIC_LENGTH, c_mqttSubscribeNames[SUBSCRIBE_TRIGGER], g_ui_json.dispenserConfig.autGroup); + + if (s_Connect_Satus == MQTT_CONNECTED) + { + int rc = mosquitto_subscribe(s_mosq, NULL, new_topic, QOS); + if (rc != MOSQ_ERR_SUCCESS) + { + LV_LOG_WARN("Error subscribing new topic: %s\n", mosquitto_strerror(rc)); + mosquitto_disconnect(s_mosq); + } + else + { + LV_LOG_WARN("Subscribed new topic: %s", new_topic); + } + } + + // 更新记录的授权组 + last_autGroup = g_ui_json.dispenserConfig.autGroup; + } +} + + +static void handle_sysconfig_subscribe(const char *value) +{ + // LV_LOG_WARN("===%s", value); + // LV_LOG_WARN("RECEIVE SYSCONFIG========"); + + if (value == NULL || *value == '\0') + { + LV_LOG_WARN("handle_sysconfig_subscribe: empty input"); + return; + } + + cJSON *root = cJSON_Parse(value); + if (root == NULL) + { + LV_LOG_WARN("Failed to parse JSON"); + return; + } + + cJSON * rfNum = cJSON_GetObjectItem(root, "rfNum"); + if (rfNum == NULL) + { + LV_LOG_WARN("No rfNum"); + cJSON_Delete(root); + return; + } + + cJSON * connectorNum = cJSON_GetObjectItem(root, "connectorNum"); + if (connectorNum == NULL) + { + LV_LOG_WARN("No connectorNum"); + cJSON_Delete(root); + return; + } + + int uiScreenNum = atoi(rfNum->valuestring); + int uiConnNum = atoi(connectorNum->valuestring); + + // 屏幕处于哪个终端上 + uint8_t loc = g_ui_json.dispenserConfig.location; + + // 保存旧值,用于变化检测 + uint8_t oldConnNum = g_ui_json.dispenserConfig.connNum; + uint8_t oldAutGroup = g_ui_json.dispenserConfig.autGroup; + uint8_t oldConnIdx[UI_MAX_CONNECTOR_NUM]; + memcpy(oldConnIdx, g_ui_json.dispenserConfig.connIdx, sizeof(oldConnIdx)); + static bool first_call = true; + + g_ui_json.dispenserConfig.connNum = 0; + + for (uint8_t screenIdx = 0; screenIdx < uiScreenNum; screenIdx++) + { + int temp_loc = -1; + get_json_u8(root, "rfDispenser%d", screenIdx, &temp_loc); + // 先根据终端号找到屏幕idx + if (temp_loc == loc) + { + g_ui_json.dispenserConfig.autGroup = screenIdx; + int tmp_connIdx = -1; + // 轮询哪根枪是属于这个屏幕 + for(int connIdx = 0; connIdx < uiConnNum; connIdx++) + { + get_json_u8(root, "connMap2Rf%d", connIdx, &tmp_connIdx); + if(tmp_connIdx == screenIdx) + { + // LV_LOG_WARN("=======tmp[%d]=====screenIdx[%d]", tmp, screenIdx); + if(g_ui_json.dispenserConfig.connNum < UI_MAX_CONNECTOR_NUM) + { + g_ui_json.dispenserConfig.connIdx[g_ui_json.dispenserConfig.connNum] = connIdx; + g_ui_json.dispenserConfig.connNum ++; + } + else + { + LV_LOG_WARN("Exceeded maximum number of display connectors"); + break; + } + } + } + break; // 找到对应项后退出 + } + } + + // 比较前后配置是否变化 + bool changed = false; + if (g_ui_json.dispenserConfig.connNum != oldConnNum || + g_ui_json.dispenserConfig.autGroup != oldAutGroup || + memcmp(g_ui_json.dispenserConfig.connIdx, oldConnIdx, sizeof(oldConnIdx)) != 0) + { + changed = true; + } + + if (!first_call && !changed) + { + LV_LOG_WARN("handle_sysconfig_subscribe: configuration unchanged, skipping"); + cJSON_Delete(root); + return; + } + + LV_LOG_WARN("======rfNum[%d]", uiScreenNum); + LV_LOG_WARN("======================loc[%d]", loc); + LV_LOG_WARN("g_ui_json.dispenserConfig.connNum[%d]", g_ui_json.dispenserConfig.connNum); + LV_LOG_WARN("g_ui_json.dispenserConfig.autGroup[%d]", g_ui_json.dispenserConfig.autGroup); + for (int i = 0; i < g_ui_json.dispenserConfig.connNum; i++) + { + LV_LOG_WARN("g_ui_json.dispenserConfig.connIdx[%d]", g_ui_json.dispenserConfig.connIdx[i]); + } + + ioc_ui_json_set_con_num(g_ui_json.dispenserConfig.connNum); + + // 此处屏幕已经知道自己在哪个授权组上,订阅Triger相关主题 + authGroup_subscribe(); + + // 根据枪数量和枪id订阅要显示枪的主题 + conns_subscribe(); + // 订阅测试主题 + TestRGB_subscribe(); + cJSON_Delete(root); +} +bool ioc_ui_mqtt_trigger_parse(cJSON *trigger) +{ + const char *trigger_str = cJSON_GetStringValue(cJSON_GetObjectItem(trigger, "Trigger")); + // 以下字段不一定有,需要根据Trigger类型进行判断 + cJSON *Msg = cJSON_GetObjectItem(trigger, "Msg"); + if (strcmp(trigger_str, "Test") == 0) + { + if (Msg != NULL) + { + uint8_t color_idx = (uint8_t)Msg->valueint; + ui_trigger_panel_show(color_idx); + } + return true; + } + else if (strcmp(trigger_str, "Cancel") == 0) + { + ui_trigger_panel_hide(); + return false; + } + return false; +} +static void handle_TestRGB_subscribe(const char *value) +{ + // LV_LOG_WARN("RECEIVE UI JSON========"); + if (!value) + { + LV_LOG_WARN("value is NULL"); + return; + } + + if(strlen(value) > UI_JSON_BUFFER_SIZE) + { + LV_LOG_WARN("value too long"); + } + + cJSON *root = cJSON_Parse(value); + if (cJSON_GetObjectItem(root, "Trigger")) + { + TestMode = ioc_ui_mqtt_trigger_parse(root); + } + // + if (TestMode) + { + mosquitto_publish(s_mosq, NULL, c_mqttPublishNames[1], strlen("OK"), "OK", 2, false); + } + + + uint64_t notify = 1; + if (write(g_ui_json_eventfd, ¬ify, sizeof(notify)) < 0) + { + LV_LOG_WARN("write to g_ui_json_eventfd failed"); + return; + } + + memset(g_ui_json_buffer, 0x00, UI_JSON_BUFFER_SIZE); + strncpy(g_ui_json_buffer, value, UI_JSON_BUFFER_SIZE - 1); + g_ui_json_buffer[UI_JSON_BUFFER_SIZE - 1] = '\0'; +} + +static void handle_trigger_subscribe(const char *value) +{ + // LV_LOG_WARN("RECEIVE UI JSON========"); + if (!value) + { + LV_LOG_WARN("value is NULL"); + return; + } + + if(strlen(value) > UI_JSON_BUFFER_SIZE) + { + LV_LOG_WARN("value too long"); + } + + if (g_ui_json_eventfd <= 0) + { + LV_LOG_WARN("Invalid g_ui_json_eventfd: %d", g_ui_json_eventfd); + return; + } + + uint64_t notify = 1; + if (write(g_ui_json_eventfd, ¬ify, sizeof(notify)) < 0) + { + LV_LOG_WARN("write to g_ui_json_eventfd failed"); + return; + } + + memset(g_ui_json_buffer, 0x00, UI_JSON_BUFFER_SIZE); + strncpy(g_ui_json_buffer, value, UI_JSON_BUFFER_SIZE - 1); + g_ui_json_buffer[UI_JSON_BUFFER_SIZE - 1] = '\0'; +} + + +#define UI_JSON_PART_SIZE (2048 * 4) // 每个片段最大字节数 +static char ui_json_global[UI_JSON_PART_SIZE]; +static char ui_json_conns[UI_MAX_CONNECTOR_NUM][UI_JSON_PART_SIZE]; + +// 保存 global-data 或 conn-%d JSON 片段 +static void store_ui_json(const char *topic, const char *payload) +{ + // DEBUG_WARN("store_ui_json topic [%s], payload [%s]", topic, payload); + + if (strcmp(topic, c_mqttSubscribeNames[SUBSCRIBE_UI_GLOBAL]) == 0) + { + strncpy(ui_json_global, payload, UI_JSON_PART_SIZE - 1); + ui_json_global[UI_JSON_PART_SIZE - 1] = '\0'; + } + else + { + int connIdx = -1; + if (sscanf(topic, "/homeOcpp/UI/conn-%d", &connIdx) == 1) + { + for (int i = 0; i < UI_NUMOFCONNECTOR; i++) + { + if (g_ui_json.dispenserConfig.connIdx[i] == connIdx) + { + strncpy(ui_json_conns[i], payload, UI_JSON_PART_SIZE - 1); + ui_json_conns[i][UI_JSON_PART_SIZE - 1] = '\0'; + break; + } + } + } + } +} + + +// 组装最终 JSON: {"global":{...}, "conns":[...]} +static void assemble_ui_json(void) +{ + cJSON *root = cJSON_CreateObject(); + + // global 部分 + if (strlen(ui_json_global) > 0) + { + cJSON *global_json = cJSON_Parse(ui_json_global); + if (global_json) + { + cJSON_AddItemToObject(root, "global", global_json); + } + } + + // LV_LOG_WARN("===================================="); + + // conns 部分 + cJSON *conns_arr = cJSON_CreateArray(); + for (int i = 0; i < UI_NUMOFCONNECTOR; i++) + { + // DEBUG_WARN("ui_json_conns [%s]", ui_json_conns[i]); + if (strlen(ui_json_conns[i]) > 0) + { + cJSON *conn_json = cJSON_Parse(ui_json_conns[i]); + if (conn_json) + { + cJSON_AddItemToArray(conns_arr, conn_json); + } + } + } + cJSON_AddItemToObject(root, "conns", conns_arr); + + // 输出到全局 buffer + char *out = cJSON_PrintUnformatted(root); + if (out) + { + // DEBUG_WARN("out [%s]", out); + + memset(g_ui_json_buffer, 0, UI_JSON_BUFFER_SIZE); + strncpy(g_ui_json_buffer, out, UI_JSON_BUFFER_SIZE - 1); + + uint64_t notify = 1; + if (g_ui_json_eventfd >= 0) + { + write(g_ui_json_eventfd, ¬ify, sizeof(notify)); + } + + free(out); + } + + cJSON_Delete(root); +} + + +// 处理 global-data / conn-%d 订阅 +static void handle_ui_subscribe(const char *topic, const char *value) +{ + if (!topic || !value) + { + LV_LOG_WARN("topic or value is NULL"); + return; + } + + if(strlen(value) > UI_JSON_BUFFER_SIZE) + { + LV_LOG_WARN("value too long"); + } + + if (g_ui_json_eventfd <= 0) + { + LV_LOG_WARN("Invalid g_ui_json_eventfd: %d", g_ui_json_eventfd); + return; + } + + store_ui_json(topic, value); + assemble_ui_json(); +} + +static void mqtt_subscribe_handle(void *pData) +{ + if (pData == NULL) return; + + const struct mosquitto_message *msg = (const struct mosquitto_message *)pData; + + if (msg->topic == NULL || msg->payload == NULL) + { + LV_LOG_WARN("Invalid MQTT message received"); + return; + } + + // LV_LOG_WARN("========msg->topic[%s]", msg->topic); + + if(strcmp(msg->topic, c_mqttSubscribeNames[SUBSCRIBE_SYSCONFIG]) == 0) + { + // 处理 /global-sysconfig 主题的消息 + // DEBUG_WARN("UI conn message received for global-sysconfig[%s]", (char *)msg->payload); + handle_sysconfig_subscribe((char *)msg->payload); + } + else if(strcmp(msg->topic, c_mqttSubscribeNames[SUBSCRIBE_UI_GLOBAL]) == 0) + { + // 处理 /homeOcpp/UI/global-data 主题的消息 + // LV_LOG_WARN("UI conn message received for global-data"); + handle_ui_subscribe(msg->topic, (char *)msg->payload); + + } + else if (strncmp(msg->topic, "/homeOcpp/UI/conn-", strlen("/homeOcpp/UI/conn-")) == 0) + { + // DEBUG_WARN("1111111============================="); + + int connIdx = -1; + if (sscanf(msg->topic, "/homeOcpp/UI/conn-%d", &connIdx) == 1) + { + // LV_LOG_WARN("UI conn message received for conn=%d", connIdx); + handle_ui_subscribe(msg->topic, (char *)msg->payload); + } + else + { + LV_LOG_WARN("Invalid conn topic format: %s", msg->topic); + } + } + else if (strncmp(msg->topic, "/authGroup/display-", strlen("/authGroup/display-")) == 0) + { + int autGroupId = -1; + if (sscanf(msg->topic, "/authGroup/display-%d/trigger", &autGroupId) == 1) + { + LV_LOG_INFO("Trigger received for authGroup=%d", autGroupId); + handle_trigger_subscribe((char *)msg->payload); + } + else + { + LV_LOG_WARN("Invalid trigger topic format: %s", msg->topic); + } + } + else if (strncmp(msg->topic, "/TestRGB", strlen("/TestRGB")) == 0) + { + handle_TestRGB_subscribe((char *)msg->payload); + } + else + { + LV_LOG_WARN("Unknown topic: %s", msg->topic); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* Callback called when the client receives a CONNACK message from the broker. */ +static void on_connect(struct mosquitto *mosq, void *obj, int reason_code) +{ + /* Print out the connection result. mosquitto_connack_string() produces an + * appropriate string for MQTT v3.x clients, the equivalent for MQTT v5.0 + * clients is mosquitto_reason_string(). + */ + + LV_LOG_WARN("on_connect: %s\n", mosquitto_connack_string(reason_code)); + if (reason_code != 0) + { + /* If the connection fails for any reason, we don't want to keep on + * retrying in this example, so disconnect. Without this, the client + * will attempt to reconnect. */ + mosquitto_disconnect(mosq); + } + + /* Making subscriptions in the on_connect() callback means that if the + * connection drops and is automatically resumed by the client, then the + * subscriptions will be recreated when the client reconnects. */ + for (uint8_t i = 0; i < MQTT_SUBSCRIBE_MAX_NUM; i++) + { + if (strlen(c_mqttSubscribeNames[i]) == 0) + { + continue; // 跳过未注册的订阅 + } + + int rc = mosquitto_subscribe(mosq, NULL, c_mqttSubscribeNames[i], QOS); + if (rc != MOSQ_ERR_SUCCESS) + { + LV_LOG_WARN("Error subscribing: %s\n", mosquitto_strerror(rc)); + /* We might as well disconnect if we were unable to subscribe */ + mosquitto_disconnect(mosq); + } + } + + s_Connect_Satus = MQTT_CONNECTED; +} + +static void on_disconnect(struct mosquitto *mosq, void *obj, int reason_code) +{ + LV_LOG_WARN("Lost link, Reason:%d", reason_code); + + // 断连时重置枪组信息 + last_connNum = 0; + for (int i = 0; i < UI_MAX_CONNECTOR_NUM; i++) + { + last_connIdx[i] = -1; + } + + last_autGroup = -1; + + s_Connect_Satus = MQTT_CONNECT_NOT; +} + + +/* Callback called when the broker sends a SUBACK in response to a SUBSCRIBE. */ +static void on_subscribe(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) +{ + int i; + bool have_subscription = false; + + /* In this example we only subscribe to a single topic at once, but a + * SUBSCRIBE can contain many topics at once, so this is one way to check + * them all. */ + for(i=0; itopic, (char *)msg->payload); + IsMsg = true; + mqtt_subscribe_handle((void*)msg); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static void mqtt_lineOff_check(void) +{ + if (s_Connect_Satus != MQTT_CONNECT_NOT) + { + return; + } + + if (s_mqttConfig.port == 0) + { + return; + } + + int rc; + +#ifndef MQTT_TEST + // 测试用,测试时隐藏 + // TLS 配置 + if (access("/tmp/mqtt/cert/client.mqtt.crt", F_OK) == 0) + { + rc = mosquitto_tls_set(s_mosq, NULL, "/etc/ssl/certs/", "/tmp/mqtt/cert/client.mqtt.crt", "/tmp/mqtt/cert/client.mqtt.key", NULL); + } + else + { + rc = mosquitto_tls_set(s_mosq, NULL, "/etc/ssl/certs/", NULL, NULL, NULL); + } + + if (rc != MOSQ_ERR_SUCCESS) + { + // 文件不存在可能导致此错误 + LV_LOG_WARN("Error: %s\n", mosquitto_strerror(rc)); + s_Connect_Satus = MQTT_CONNECT_NOT; + return; + } +#endif + LV_LOG_WARN("address[%s] port[%d]", s_mqttConfig.address, s_mqttConfig.port); + + rc = mosquitto_connect(s_mosq, s_mqttConfig.address, s_mqttConfig.port, 60); + if (rc != MOSQ_ERR_SUCCESS) + { + LV_LOG_WARN("Error %s", mosquitto_strerror(rc)); + s_Connect_Satus = MQTT_CONNECT_NOT; + return; + } + + // 测试用,使用IP时需要 + // mosquitto_tls_insecure_set(s_mosq, true); + + s_Connect_Satus = MQTT_CONNECTING; + +} + + +// 通过UDP获取mqttd的地址和端口 +static bool mqtt_config_init() +{ + int sockfd; + struct sockaddr_in serverAddr, clientAddr; + socklen_t addrLen = sizeof(clientAddr); + char buffer[BUFFER_SIZE]; + + // 创建 UDP socket + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + LV_LOG_WARN("socket error"); + return false; + } + + // 设置非阻塞模式 + fcntl(sockfd, F_SETFL, O_NONBLOCK); + + // 绑定端口 + memset(&serverAddr, 0, sizeof(serverAddr)); + serverAddr.sin_family = AF_INET; + serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); + serverAddr.sin_port = htons(DEV_AUTO_GROUP_PORT); + + // 允许多个进程绑定同一端口 + int reuse = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)); + + int rtn = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)); + if (rtn < 0) + { + LV_LOG_WARN("socket error [%s]", strerror(errno)); + close(sockfd); + return false; + } + + // 记录开始时间 + time_t startTime = time(NULL); + + while (1) + { + ssize_t recvLen = recvfrom(sockfd, buffer, BUFFER_SIZE - 1, 0, + (struct sockaddr*)&clientAddr, &addrLen); + if (recvLen > 0) + { + buffer[recvLen] = '\0'; // 确保字符串终止 + + // 解析 JSON 数据 + cJSON *root = cJSON_Parse(buffer); + if (!root) + { + // writeLog(__LINE__, "1111111111", 0); + close(sockfd); + return false; + } + + // 遍历 JSON 数组 + cJSON *item; + cJSON_ArrayForEach(item, root) + { + cJSON *service = cJSON_GetObjectItem(item, "service"); + cJSON *desc = cJSON_GetObjectItem(item, "desc"); + cJSON *port = cJSON_GetObjectItem(item, "port"); + + if (service && desc && port && cJSON_IsString(service) && cJSON_IsString(desc) && cJSON_IsNumber(port)) + { + if (strcmp(service->valuestring, "MQTT_BROKER") == 0) + { + strncpy(s_mqttConfig.address, desc->valuestring, sizeof(s_mqttConfig.address) - 1); + s_mqttConfig.address[sizeof(s_mqttConfig.address) - 1] = '\0'; + s_mqttConfig.port = port->valueint; + + LV_LOG_WARN("address[%s] port[%d]", s_mqttConfig.address, s_mqttConfig.port); + + // 其他参数填充默认值 + // 生成随机的 clientID + memset(s_mqttConfig.clientID, 0x00, sizeof(s_mqttConfig.clientID)); + + float uptime; + float temp; + FILE *fp = fopen("/proc/uptime", "r"); + if (fp != NULL) { + fscanf(fp, "%f %f", &uptime, &temp); + fclose(fp); + srand((unsigned int)(uptime * 1000)); // 转换为毫秒做种子 + } + + int randomNumber = rand(); // 生成 0 到 9999 之间的随机数 + snprintf(s_mqttConfig.clientID, + sizeof(s_mqttConfig.clientID), + "dispenserScreen%d_%d", + randomNumber, + g_ui_json.dispenserConfig.location); + + LV_LOG_INFO("clientID[%s]", s_mqttConfig.clientID); + + cJSON_Delete(root); + close(sockfd); + return true; // 找到匹配项,成功返回 + } + } + } + cJSON_Delete(root); + } + usleep(100000); // 100ms 轮询 + } +} + + +int ioc_mqtt_init() +{ + LV_LOG_WARN("MQTT init start"); + +#ifndef MQTT_TEST + // 测试用,测试时隐藏 + if(!mqtt_config_init()) + { + return false; + } +#endif + + LV_LOG_WARN("MQTT init success"); + +#ifdef MQTT_TEST + // 测试用 + strcpy(s_mqttConfig.address, "192.168.2.36"); + s_mqttConfig.port = 1883; + int randomNumber = rand(); // 生成 0 到 9999 之间的随机数 + snprintf(s_mqttConfig.clientID, sizeof(s_mqttConfig.clientID), "dispenserSreen%d", randomNumber); + + + // 远程 + // strcpy(s_mqttConfig.address, "60.205.110.94"); + // s_mqttConfig.port = 2223; + // int randomNumber = rand(); // 生成 0 到 9999 之间的随机数 + // snprintf(s_mqttConfig.clientID, sizeof(s_mqttConfig.clientID), "dispenserSreen%d", randomNumber); + +#endif + + // 初始化 MQTT 库 + mosquitto_lib_init(); + + // 创建 MQTT 客户端实例 + s_mosq = mosquitto_new(s_mqttConfig.clientID, true, NULL); + if (s_mosq == NULL) + { + return -1; + } + + // 设置已连接回调 + mosquitto_connect_callback_set(s_mosq, on_connect); + // 设置发布回调 + mosquitto_subscribe_callback_set(s_mosq, on_subscribe); + // 设置订阅回调 + mosquitto_message_callback_set(s_mosq, on_message); + // 设置连接断开的回调 + mosquitto_disconnect_callback_set(s_mosq, on_disconnect); + + // // 订阅主题 + // if (s_Connect_Satus == MQTT_CONNECTED) + // { + // for (int i = 0; i < SUBSCRIBE_NUM; i++) + // { + // int rc = mosquitto_subscribe(s_mosq, NULL, c_mqttSubscribeNames[i], QOS); + // if (rc != MOSQ_ERR_SUCCESS) + // { + // LV_LOG_WARN("Error subscribing: %s\n", mosquitto_strerror(rc)); + // return -1; + // } + // } + // } + + return 1; +} + +void ioc_mqtt_step() +{ + mqtt_lineOff_check(); + + do + { + IsMsg = false; + mosquitto_loop(s_mosq, 0, 1); + } while (IsMsg); +} + +#endif diff --git a/ioc/mqtt/ioc_mqtt.h b/ioc/mqtt/ioc_mqtt.h new file mode 100644 index 000000000..b75a99d30 --- /dev/null +++ b/ioc/mqtt/ioc_mqtt.h @@ -0,0 +1,54 @@ +#ifndef __IOC_MQTT_H__ +#define __IOC_MQTT_H__ + +#define CERTSPATH "/etc/ssl/certs/" + +// 订阅的主题 Topics +typedef enum +{ + SUBSCRIBE_SYSCONFIG = 0, // SysConfig.json + SUBSCRIBE_UI_GLOBAL, // UI.json global部分 + SUBSCRIBE_UI_CONNS, // UI.json conns部分 + SUBSCRIBE_TRIGGER, // Trigger + SUBSCRIBE_TestRGB, // 测试主题 + + SUBSCRIBE_NUM +}Subscribe_List_t; + +typedef enum +{ + PUBLISH_UI = 0, // UI.json + PUBLISH_TestResp, // UI.json + PUBLISH_NUM +}Publish_List_t; + +#define MQTT_SUBSCRIBE_MAX_NUM SUBSCRIBE_NUM + +// MQTT连接状态 +typedef enum +{ + MQTT_CONNECT_NOT = 0, // 未连接 + MQTT_CONNECTING, // 正在连接中 + MQTT_CONNECTED // 已连接 +}Mqtt_Connetc_Status; + +// 订阅 +typedef struct +{ + char * pSubscribeName; // 订阅主题名称 +}Mqtt_Subscribe_t; + +typedef struct +{ + Mqtt_Subscribe_t List[MQTT_SUBSCRIBE_MAX_NUM]; // 订阅列表 + int subId; +}Subscribe_t; + +Subscribe_t s_subscribe; + + +int ioc_mqtt_init(); +void ioc_mqtt_step(); +int ioc_mqtt_publish(uint8_t connId, Publish_List_t list, char * pData); + +#endif \ No newline at end of file diff --git a/ioc/mqtt/mosquitto.h b/ioc/mqtt/mosquitto.h new file mode 100644 index 000000000..09ee7dcfc --- /dev/null +++ b/ioc/mqtt/mosquitto.h @@ -0,0 +1,3274 @@ +/* +Copyright (c) 2010-2020 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License 2.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. + +SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#ifndef MOSQUITTO_H +#define MOSQUITTO_H + +/* + * File: mosquitto.h + * + * This header contains functions and definitions for use with libmosquitto, the Mosquitto client library. + * + * The definitions are also used in Mosquitto broker plugins, and some functions are available to plugins. + */ +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef WIN32 +# ifdef mosquitto_EXPORTS +# define libmosq_EXPORT __declspec(dllexport) +# else +# ifndef LIBMOSQUITTO_STATIC +# ifdef libmosquitto_EXPORTS +# define libmosq_EXPORT __declspec(dllexport) +# else +# define libmosq_EXPORT __declspec(dllimport) +# endif +# else +# define libmosq_EXPORT +# endif +# endif +#else +# define libmosq_EXPORT +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 && !defined(bool) +# ifndef __cplusplus +# define bool char +# define true 1 +# define false 0 +# endif +#else +# ifndef __cplusplus +# include +# endif +#endif + +#include +#include + +#define LIBMOSQUITTO_MAJOR 2 +#define LIBMOSQUITTO_MINOR 0 +#define LIBMOSQUITTO_REVISION 18 +/* LIBMOSQUITTO_VERSION_NUMBER looks like 1002001 for e.g. version 1.2.1. */ +#define LIBMOSQUITTO_VERSION_NUMBER (LIBMOSQUITTO_MAJOR*1000000+LIBMOSQUITTO_MINOR*1000+LIBMOSQUITTO_REVISION) + +/* Log types */ +#define MOSQ_LOG_NONE 0 +#define MOSQ_LOG_INFO (1<<0) +#define MOSQ_LOG_NOTICE (1<<1) +#define MOSQ_LOG_WARNING (1<<2) +#define MOSQ_LOG_ERR (1<<3) +#define MOSQ_LOG_DEBUG (1<<4) +#define MOSQ_LOG_SUBSCRIBE (1<<5) +#define MOSQ_LOG_UNSUBSCRIBE (1<<6) +#define MOSQ_LOG_WEBSOCKETS (1<<7) +#define MOSQ_LOG_INTERNAL 0x80000000U +#define MOSQ_LOG_ALL 0xFFFFFFFFU + +/* Enum: mosq_err_t + * Integer values returned from many libmosquitto functions. */ +enum mosq_err_t { + MOSQ_ERR_AUTH_CONTINUE = -4, + MOSQ_ERR_NO_SUBSCRIBERS = -3, + MOSQ_ERR_SUB_EXISTS = -2, + MOSQ_ERR_CONN_PENDING = -1, + MOSQ_ERR_SUCCESS = 0, + MOSQ_ERR_NOMEM = 1, + MOSQ_ERR_PROTOCOL = 2, + MOSQ_ERR_INVAL = 3, + MOSQ_ERR_NO_CONN = 4, + MOSQ_ERR_CONN_REFUSED = 5, + MOSQ_ERR_NOT_FOUND = 6, + MOSQ_ERR_CONN_LOST = 7, + MOSQ_ERR_TLS = 8, + MOSQ_ERR_PAYLOAD_SIZE = 9, + MOSQ_ERR_NOT_SUPPORTED = 10, + MOSQ_ERR_AUTH = 11, + MOSQ_ERR_ACL_DENIED = 12, + MOSQ_ERR_UNKNOWN = 13, + MOSQ_ERR_ERRNO = 14, + MOSQ_ERR_EAI = 15, + MOSQ_ERR_PROXY = 16, + MOSQ_ERR_PLUGIN_DEFER = 17, + MOSQ_ERR_MALFORMED_UTF8 = 18, + MOSQ_ERR_KEEPALIVE = 19, + MOSQ_ERR_LOOKUP = 20, + MOSQ_ERR_MALFORMED_PACKET = 21, + MOSQ_ERR_DUPLICATE_PROPERTY = 22, + MOSQ_ERR_TLS_HANDSHAKE = 23, + MOSQ_ERR_QOS_NOT_SUPPORTED = 24, + MOSQ_ERR_OVERSIZE_PACKET = 25, + MOSQ_ERR_OCSP = 26, + MOSQ_ERR_TIMEOUT = 27, + MOSQ_ERR_RETAIN_NOT_SUPPORTED = 28, + MOSQ_ERR_TOPIC_ALIAS_INVALID = 29, + MOSQ_ERR_ADMINISTRATIVE_ACTION = 30, + MOSQ_ERR_ALREADY_EXISTS = 31, +}; + +/* Enum: mosq_opt_t + * + * Client options. + * + * See , , and . + */ +enum mosq_opt_t { + MOSQ_OPT_PROTOCOL_VERSION = 1, + MOSQ_OPT_SSL_CTX = 2, + MOSQ_OPT_SSL_CTX_WITH_DEFAULTS = 3, + MOSQ_OPT_RECEIVE_MAXIMUM = 4, + MOSQ_OPT_SEND_MAXIMUM = 5, + MOSQ_OPT_TLS_KEYFORM = 6, + MOSQ_OPT_TLS_ENGINE = 7, + MOSQ_OPT_TLS_ENGINE_KPASS_SHA1 = 8, + MOSQ_OPT_TLS_OCSP_REQUIRED = 9, + MOSQ_OPT_TLS_ALPN = 10, + MOSQ_OPT_TCP_NODELAY = 11, + MOSQ_OPT_BIND_ADDRESS = 12, + MOSQ_OPT_TLS_USE_OS_CERTS = 13, +}; + + +/* MQTT specification restricts client ids to a maximum of 23 characters */ +#define MOSQ_MQTT_ID_MAX_LENGTH 23 + +#define MQTT_PROTOCOL_V31 3 +#define MQTT_PROTOCOL_V311 4 +#define MQTT_PROTOCOL_V5 5 + +/* Struct: mosquitto_message + * + * Contains details of a PUBLISH message. + * + * int mid - the message/packet ID of the PUBLISH message, assuming this is a + * QoS 1 or 2 message. Will be set to 0 for QoS 0 messages. + * + * char *topic - the topic the message was delivered on. + * + * void *payload - the message payload. This will be payloadlen bytes long, and + * may be NULL if a zero length payload was sent. + * + * int payloadlen - the length of the payload, in bytes. + * + * int qos - the quality of service of the message, 0, 1, or 2. + * + * bool retain - set to true for stale retained messages. + */ +struct mosquitto_message{ + int mid; + char *topic; + void *payload; + int payloadlen; + int qos; + bool retain; +}; + +#ifndef MOSQUITTO_PROPERTY +#define MOSQUITTO_PROPERTY +struct mosquitto; +typedef struct mqtt5__property mosquitto_property; +#endif + +/* + * Topic: Threads + * libmosquitto provides thread safe operation, with the exception of + * which is not thread safe. + * + * If the library has been compiled without thread support it is *not* + * guaranteed to be thread safe. + * + * If your application uses threads you must use to + * tell the library this is the case, otherwise it makes some optimisations + * for the single threaded case that may result in unexpected behaviour for + * the multi threaded case. + */ +/*************************************************** + * Important note + * + * The following functions that deal with network operations will return + * MOSQ_ERR_SUCCESS on success, but this does not mean that the operation has + * taken place. An attempt will be made to write the network data, but if the + * socket is not available for writing at that time then the packet will not be + * sent. To ensure the packet is sent, call mosquitto_loop() (which must also + * be called to process incoming network data). + * This is especially important when disconnecting a client that has a will. If + * the broker does not receive the DISCONNECT command, it will assume that the + * client has disconnected unexpectedly and send the will. + * + * mosquitto_connect() + * mosquitto_disconnect() + * mosquitto_subscribe() + * mosquitto_unsubscribe() + * mosquitto_publish() + ***************************************************/ + + +/* ====================================================================== + * + * Section: Library version, init, and cleanup + * + * ====================================================================== */ +/* + * Function: mosquitto_lib_version + * + * Can be used to obtain version information for the mosquitto library. + * This allows the application to compare the library version against the + * version it was compiled against by using the LIBMOSQUITTO_MAJOR, + * LIBMOSQUITTO_MINOR and LIBMOSQUITTO_REVISION defines. + * + * Parameters: + * major - an integer pointer. If not NULL, the major version of the + * library will be returned in this variable. + * minor - an integer pointer. If not NULL, the minor version of the + * library will be returned in this variable. + * revision - an integer pointer. If not NULL, the revision of the library will + * be returned in this variable. + * + * Returns: + * LIBMOSQUITTO_VERSION_NUMBER - which is a unique number based on the major, + * minor and revision values. + * See Also: + * , + */ +libmosq_EXPORT int mosquitto_lib_version(int *major, int *minor, int *revision); + +/* + * Function: mosquitto_lib_init + * + * Must be called before any other mosquitto functions. + * + * This function is *not* thread safe. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_UNKNOWN - on Windows, if sockets couldn't be initialized. + * + * See Also: + * , + */ +libmosq_EXPORT int mosquitto_lib_init(void); + +/* + * Function: mosquitto_lib_cleanup + * + * Call to free resources associated with the library. + * + * Returns: + * MOSQ_ERR_SUCCESS - always + * + * See Also: + * , + */ +libmosq_EXPORT int mosquitto_lib_cleanup(void); + + +/* ====================================================================== + * + * Section: Client creation, destruction, and reinitialisation + * + * ====================================================================== */ +/* + * Function: mosquitto_new + * + * Create a new mosquitto client instance. + * + * Parameters: + * id - String to use as the client id. If NULL, a random client id + * will be generated. If id is NULL, clean_session must be true. + * clean_session - set to true to instruct the broker to clean all messages + * and subscriptions on disconnect, false to instruct it to + * keep them. See the man page mqtt(7) for more details. + * Note that a client will never discard its own outgoing + * messages on disconnect. Calling or + * will cause the messages to be resent. + * Use to reset a client to its + * original state. + * Must be set to true if the id parameter is NULL. + * obj - A user pointer that will be passed as an argument to any + * callbacks that are specified. + * + * Returns: + * Pointer to a struct mosquitto on success. + * NULL on failure. Interrogate errno to determine the cause for the failure: + * - ENOMEM on out of memory. + * - EINVAL on invalid input parameters. + * + * See Also: + * , , + */ +libmosq_EXPORT struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *obj); + +/* + * Function: mosquitto_destroy + * + * Use to free memory associated with a mosquitto client instance. + * + * Parameters: + * mosq - a struct mosquitto pointer to free. + * + * See Also: + * , + */ +libmosq_EXPORT void mosquitto_destroy(struct mosquitto *mosq); + +/* + * Function: mosquitto_reinitialise + * + * This function allows an existing mosquitto client to be reused. Call on a + * mosquitto instance to close any open network connections, free memory + * and reinitialise the client with the new parameters. The end result is the + * same as the output of . + * + * Parameters: + * mosq - a valid mosquitto instance. + * id - string to use as the client id. If NULL, a random client id + * will be generated. If id is NULL, clean_session must be true. + * clean_session - set to true to instruct the broker to clean all messages + * and subscriptions on disconnect, false to instruct it to + * keep them. See the man page mqtt(7) for more details. + * Must be set to true if the id parameter is NULL. + * obj - A user pointer that will be passed as an argument to any + * callbacks that are specified. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_MALFORMED_UTF8 - if the client id is not valid UTF-8. + * + * See Also: + * , + */ +libmosq_EXPORT int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_session, void *obj); + + +/* ====================================================================== + * + * Section: Will + * + * ====================================================================== */ +/* + * Function: mosquitto_will_set + * + * Configure will information for a mosquitto instance. By default, clients do + * not have a will. This must be called before calling . + * + * It is valid to use this function for clients using all MQTT protocol versions. + * If you need to set MQTT v5 Will properties, use instead. + * + * Parameters: + * mosq - a valid mosquitto instance. + * topic - the topic on which to publish the will. + * payloadlen - the size of the payload (bytes). Valid values are between 0 and + * 268,435,455. + * payload - pointer to the data to send. If payloadlen > 0 this must be a + * valid memory location. + * qos - integer value 0, 1 or 2 indicating the Quality of Service to be + * used for the will. + * retain - set to true to make the will a retained message. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. + * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8. + */ +libmosq_EXPORT int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain); + +/* + * Function: mosquitto_will_set_v5 + * + * Configure will information for a mosquitto instance, with attached + * properties. By default, clients do not have a will. This must be called + * before calling . + * + * If the mosquitto instance `mosq` is using MQTT v5, the `properties` argument + * will be applied to the Will. For MQTT v3.1.1 and below, the `properties` + * argument will be ignored. + * + * Set your client to use MQTT v5 immediately after it is created: + * + * mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + * + * Parameters: + * mosq - a valid mosquitto instance. + * topic - the topic on which to publish the will. + * payloadlen - the size of the payload (bytes). Valid values are between 0 and + * 268,435,455. + * payload - pointer to the data to send. If payloadlen > 0 this must be a + * valid memory location. + * qos - integer value 0, 1 or 2 indicating the Quality of Service to be + * used for the will. + * retain - set to true to make the will a retained message. + * properties - list of MQTT 5 properties. Can be NULL. On success only, the + * property list becomes the property of libmosquitto once this + * function is called and will be freed by the library. The + * property list must be freed by the application on error. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. + * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8. + * MOSQ_ERR_NOT_SUPPORTED - if properties is not NULL and the client is not + * using MQTT v5 + * MOSQ_ERR_PROTOCOL - if a property is invalid for use with wills. + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + */ +libmosq_EXPORT int mosquitto_will_set_v5(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties); + +/* + * Function: mosquitto_will_clear + * + * Remove a previously configured will. This must be called before calling + * . + * + * Parameters: + * mosq - a valid mosquitto instance. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + */ +libmosq_EXPORT int mosquitto_will_clear(struct mosquitto *mosq); + + +/* ====================================================================== + * + * Section: Username and password + * + * ====================================================================== */ +/* + * Function: mosquitto_username_pw_set + * + * Configure username and password for a mosquitto instance. By default, no + * username or password will be sent. For v3.1 and v3.1.1 clients, if username + * is NULL, the password argument is ignored. + * + * This is must be called before calling . + * + * Parameters: + * mosq - a valid mosquitto instance. + * username - the username to send as a string, or NULL to disable + * authentication. + * password - the password to send as a string. Set to NULL when username is + * valid in order to send just a username. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + */ +libmosq_EXPORT int mosquitto_username_pw_set(struct mosquitto *mosq, const char *username, const char *password); + + +/* ====================================================================== + * + * Section: Connecting, reconnecting, disconnecting + * + * ====================================================================== */ +/* + * Function: mosquitto_connect + * + * Connect to an MQTT broker. + * + * It is valid to use this function for clients using all MQTT protocol versions. + * If you need to set MQTT v5 CONNECT properties, use + * instead. + * + * Parameters: + * mosq - a valid mosquitto instance. + * host - the hostname or ip address of the broker to connect to. + * port - the network port to connect to. Usually 1883. + * keepalive - the number of seconds after which the client should send a PING + * message to the broker if no other messages have been exchanged + * in that time. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid, which could be any of: + * * mosq == NULL + * * host == NULL + * * port < 0 + * * keepalive < 5 + * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno + * contains the error code, even on Windows. + * Use strerror_r() where available or FormatMessage() on + * Windows. + * + * See Also: + * , , , , + */ +libmosq_EXPORT int mosquitto_connect(struct mosquitto *mosq, const char *host, int port, int keepalive); + +/* + * Function: mosquitto_connect_bind + * + * Connect to an MQTT broker. This extends the functionality of + * by adding the bind_address parameter. Use this function + * if you need to restrict network communication over a particular interface. + * + * Parameters: + * mosq - a valid mosquitto instance. + * host - the hostname or ip address of the broker to connect to. + * port - the network port to connect to. Usually 1883. + * keepalive - the number of seconds after which the client should send a PING + * message to the broker if no other messages have been exchanged + * in that time. + * bind_address - the hostname or ip address of the local network interface to + * bind to. If you do not want to bind to a specific interface, + * set this to NULL. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno + * contains the error code, even on Windows. + * Use strerror_r() where available or FormatMessage() on + * Windows. + * + * See Also: + * , , + */ +libmosq_EXPORT int mosquitto_connect_bind(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address); + +/* + * Function: mosquitto_connect_bind_v5 + * + * Connect to an MQTT broker. This extends the functionality of + * by adding the bind_address parameter and MQTT v5 + * properties. Use this function if you need to restrict network communication + * over a particular interface. + * + * Use e.g. and similar to create a list of + * properties, then attach them to this publish. Properties need freeing with + * . + * + * If the mosquitto instance `mosq` is using MQTT v5, the `properties` argument + * will be applied to the CONNECT message. For MQTT v3.1.1 and below, the + * `properties` argument will be ignored. + * + * Set your client to use MQTT v5 immediately after it is created: + * + * mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + * + * Parameters: + * mosq - a valid mosquitto instance. + * host - the hostname or ip address of the broker to connect to. + * port - the network port to connect to. Usually 1883. + * keepalive - the number of seconds after which the client should send a PING + * message to the broker if no other messages have been exchanged + * in that time. + * bind_address - the hostname or ip address of the local network interface to + * bind to. If you do not want to bind to a specific interface, + * set this to NULL. + * properties - the MQTT 5 properties for the connect (not for the Will). + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid, which could be any of: + * * mosq == NULL + * * host == NULL + * * port < 0 + * * keepalive < 5 + * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno + * contains the error code, even on Windows. + * Use strerror_r() where available or FormatMessage() on + * Windows. + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + * MOSQ_ERR_PROTOCOL - if any property is invalid for use with CONNECT. + * + * See Also: + * , , + */ +libmosq_EXPORT int mosquitto_connect_bind_v5(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address, const mosquitto_property *properties); + +/* + * Function: mosquitto_connect_async + * + * Connect to an MQTT broker. This is a non-blocking call. If you use + * your client must use the threaded interface + * . If you need to use , you must use + * to connect the client. + * + * May be called before or after . + * + * Parameters: + * mosq - a valid mosquitto instance. + * host - the hostname or ip address of the broker to connect to. + * port - the network port to connect to. Usually 1883. + * keepalive - the number of seconds after which the client should send a PING + * message to the broker if no other messages have been exchanged + * in that time. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno + * contains the error code, even on Windows. + * Use strerror_r() where available or FormatMessage() on + * Windows. + * + * See Also: + * , , , , + */ +libmosq_EXPORT int mosquitto_connect_async(struct mosquitto *mosq, const char *host, int port, int keepalive); + +/* + * Function: mosquitto_connect_bind_async + * + * Connect to an MQTT broker. This is a non-blocking call. If you use + * your client must use the threaded interface + * . If you need to use , you must use + * to connect the client. + * + * This extends the functionality of by adding the + * bind_address parameter. Use this function if you need to restrict network + * communication over a particular interface. + * + * May be called before or after . + * + * Parameters: + * mosq - a valid mosquitto instance. + * host - the hostname or ip address of the broker to connect to. + * port - the network port to connect to. Usually 1883. + * keepalive - the number of seconds after which the client should send a PING + * message to the broker if no other messages have been exchanged + * in that time. + * bind_address - the hostname or ip address of the local network interface to + * bind to. If you do not want to bind to a specific interface, + * set this to NULL. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid, which could be any of: + * * mosq == NULL + * * host == NULL + * * port < 0 + * * keepalive < 5 + * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno + * contains the error code, even on Windows. + * Use strerror_r() where available or FormatMessage() on + * Windows. + * + * See Also: + * , , + */ +libmosq_EXPORT int mosquitto_connect_bind_async(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address); + +/* + * Function: mosquitto_connect_srv + * + * Connect to an MQTT broker. + * + * If you set `host` to `example.com`, then this call will attempt to retrieve + * the DNS SRV record for `_secure-mqtt._tcp.example.com` or + * `_mqtt._tcp.example.com` to discover which actual host to connect to. + * + * DNS SRV support is not usually compiled in to libmosquitto, use of this call + * is not recommended. + * + * Parameters: + * mosq - a valid mosquitto instance. + * host - the hostname to search for an SRV record. + * keepalive - the number of seconds after which the client should send a PING + * message to the broker if no other messages have been exchanged + * in that time. + * bind_address - the hostname or ip address of the local network interface to + * bind to. If you do not want to bind to a specific interface, + * set this to NULL. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid, which could be any of: + * * mosq == NULL + * * host == NULL + * * port < 0 + * * keepalive < 5 + * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno + * contains the error code, even on Windows. + * Use strerror_r() where available or FormatMessage() on + * Windows. + * + * See Also: + * , , + */ +libmosq_EXPORT int mosquitto_connect_srv(struct mosquitto *mosq, const char *host, int keepalive, const char *bind_address); + +/* + * Function: mosquitto_reconnect + * + * Reconnect to a broker. + * + * This function provides an easy way of reconnecting to a broker after a + * connection has been lost. It uses the values that were provided in the + * call. It must not be called before + * . + * + * Parameters: + * mosq - a valid mosquitto instance. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno + * contains the error code, even on Windows. + * Use strerror_r() where available or FormatMessage() on + * Windows. + * + * See Also: + * , , + */ +libmosq_EXPORT int mosquitto_reconnect(struct mosquitto *mosq); + +/* + * Function: mosquitto_reconnect_async + * + * Reconnect to a broker. Non blocking version of . + * + * This function provides an easy way of reconnecting to a broker after a + * connection has been lost. It uses the values that were provided in the + * or calls. It must not be + * called before . + * + * Parameters: + * mosq - a valid mosquitto instance. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno + * contains the error code, even on Windows. + * Use strerror_r() where available or FormatMessage() on + * Windows. + * + * See Also: + * , + */ +libmosq_EXPORT int mosquitto_reconnect_async(struct mosquitto *mosq); + +/* + * Function: mosquitto_disconnect + * + * Disconnect from the broker. + * + * It is valid to use this function for clients using all MQTT protocol versions. + * If you need to set MQTT v5 DISCONNECT properties, use + * instead. + * + * Parameters: + * mosq - a valid mosquitto instance. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + */ +libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq); + +/* + * Function: mosquitto_disconnect_v5 + * + * Disconnect from the broker, with attached MQTT properties. + * + * Use e.g. and similar to create a list of + * properties, then attach them to this publish. Properties need freeing with + * . + * + * If the mosquitto instance `mosq` is using MQTT v5, the `properties` argument + * will be applied to the DISCONNECT message. For MQTT v3.1.1 and below, the + * `properties` argument will be ignored. + * + * Set your client to use MQTT v5 immediately after it is created: + * + * mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + * + * Parameters: + * mosq - a valid mosquitto instance. + * reason_code - the disconnect reason code. + * properties - a valid mosquitto_property list, or NULL. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + * MOSQ_ERR_PROTOCOL - if any property is invalid for use with DISCONNECT. + */ +libmosq_EXPORT int mosquitto_disconnect_v5(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties); + + +/* ====================================================================== + * + * Section: Publishing, subscribing, unsubscribing + * + * ====================================================================== */ +/* + * Function: mosquitto_publish + * + * Publish a message on a given topic. + * + * It is valid to use this function for clients using all MQTT protocol versions. + * If you need to set MQTT v5 PUBLISH properties, use + * instead. + * + * Parameters: + * mosq - a valid mosquitto instance. + * mid - pointer to an int. If not NULL, the function will set this + * to the message id of this particular message. This can be then + * used with the publish callback to determine when the message + * has been sent. + * Note that although the MQTT protocol doesn't use message ids + * for messages with QoS=0, libmosquitto assigns them message ids + * so they can be tracked with this parameter. + * topic - null terminated string of the topic to publish to. + * payloadlen - the size of the payload (bytes). Valid values are between 0 and + * 268,435,455. + * payload - pointer to the data to send. If payloadlen > 0 this must be a + * valid memory location. + * qos - integer value 0, 1 or 2 indicating the Quality of Service to be + * used for the message. + * retain - set to true to make the message retained. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the + * broker. + * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. + * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * MOSQ_ERR_QOS_NOT_SUPPORTED - if the QoS is greater than that supported by + * the broker. + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. + * + * See Also: + * + */ +libmosq_EXPORT int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain); + + +/* + * Function: mosquitto_publish_v5 + * + * Publish a message on a given topic, with attached MQTT properties. + * + * Use e.g. and similar to create a list of + * properties, then attach them to this publish. Properties need freeing with + * . + * + * If the mosquitto instance `mosq` is using MQTT v5, the `properties` argument + * will be applied to the PUBLISH message. For MQTT v3.1.1 and below, the + * `properties` argument will be ignored. + * + * Set your client to use MQTT v5 immediately after it is created: + * + * mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + * + * Parameters: + * mosq - a valid mosquitto instance. + * mid - pointer to an int. If not NULL, the function will set this + * to the message id of this particular message. This can be then + * used with the publish callback to determine when the message + * has been sent. + * Note that although the MQTT protocol doesn't use message ids + * for messages with QoS=0, libmosquitto assigns them message ids + * so they can be tracked with this parameter. + * topic - null terminated string of the topic to publish to. + * payloadlen - the size of the payload (bytes). Valid values are between 0 and + * 268,435,455. + * payload - pointer to the data to send. If payloadlen > 0 this must be a + * valid memory location. + * qos - integer value 0, 1 or 2 indicating the Quality of Service to be + * used for the message. + * retain - set to true to make the message retained. + * properties - a valid mosquitto_property list, or NULL. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the + * broker. + * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. + * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + * MOSQ_ERR_PROTOCOL - if any property is invalid for use with PUBLISH. + * MOSQ_ERR_QOS_NOT_SUPPORTED - if the QoS is greater than that supported by + * the broker. + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. + */ +libmosq_EXPORT int mosquitto_publish_v5( + struct mosquitto *mosq, + int *mid, + const char *topic, + int payloadlen, + const void *payload, + int qos, + bool retain, + const mosquitto_property *properties); + + +/* + * Function: mosquitto_subscribe + * + * Subscribe to a topic. + * + * It is valid to use this function for clients using all MQTT protocol versions. + * If you need to set MQTT v5 SUBSCRIBE properties, use + * instead. + * + * Parameters: + * mosq - a valid mosquitto instance. + * mid - a pointer to an int. If not NULL, the function will set this to + * the message id of this particular message. This can be then used + * with the subscribe callback to determine when the message has been + * sent. + * sub - the subscription pattern. + * qos - the requested Quality of Service for this subscription. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. + */ +libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos); + +/* + * Function: mosquitto_subscribe_v5 + * + * Subscribe to a topic, with attached MQTT properties. + * + * Use e.g. and similar to create a list of + * properties, then attach them to this publish. Properties need freeing with + * . + * + * If the mosquitto instance `mosq` is using MQTT v5, the `properties` argument + * will be applied to the PUBLISH message. For MQTT v3.1.1 and below, the + * `properties` argument will be ignored. + * + * Set your client to use MQTT v5 immediately after it is created: + * + * mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + * + * Parameters: + * mosq - a valid mosquitto instance. + * mid - a pointer to an int. If not NULL, the function will set this to + * the message id of this particular message. This can be then used + * with the subscribe callback to determine when the message has been + * sent. + * sub - the subscription pattern. + * qos - the requested Quality of Service for this subscription. + * options - options to apply to this subscription, OR'd together. Set to 0 to + * use the default options, otherwise choose from list of + * properties - a valid mosquitto_property list, or NULL. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + * MOSQ_ERR_PROTOCOL - if any property is invalid for use with SUBSCRIBE. + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. + */ +libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, int options, const mosquitto_property *properties); + +/* + * Function: mosquitto_subscribe_multiple + * + * Subscribe to multiple topics. + * + * Parameters: + * mosq - a valid mosquitto instance. + * mid - a pointer to an int. If not NULL, the function will set this to + * the message id of this particular message. This can be then used + * with the subscribe callback to determine when the message has been + * sent. + * sub_count - the count of subscriptions to be made + * sub - array of sub_count pointers, each pointing to a subscription string. + * The "char *const *const" datatype ensures that neither the array of + * pointers nor the strings that they point to are mutable. If you aren't + * familiar with this, just think of it as a safer "char **", + * equivalent to "const char *" for a simple string pointer. + * qos - the requested Quality of Service for each subscription. + * options - options to apply to this subscription, OR'd together. This + * argument is not used for MQTT v3 susbcriptions. Set to 0 to use + * the default options, otherwise choose from list of + * properties - a valid mosquitto_property list, or NULL. Only used with MQTT + * v5 clients. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_MALFORMED_UTF8 - if a topic is not valid UTF-8 + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. + */ +libmosq_EXPORT int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, int options, const mosquitto_property *properties); + +/* + * Function: mosquitto_unsubscribe + * + * Unsubscribe from a topic. + * + * Parameters: + * mosq - a valid mosquitto instance. + * mid - a pointer to an int. If not NULL, the function will set this to + * the message id of this particular message. This can be then used + * with the unsubscribe callback to determine when the message has been + * sent. + * sub - the unsubscription pattern. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. + */ +libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub); + +/* + * Function: mosquitto_unsubscribe_v5 + * + * Unsubscribe from a topic, with attached MQTT properties. + * + * It is valid to use this function for clients using all MQTT protocol versions. + * If you need to set MQTT v5 UNSUBSCRIBE properties, use + * instead. + * + * Use e.g. and similar to create a list of + * properties, then attach them to this publish. Properties need freeing with + * . + * + * If the mosquitto instance `mosq` is using MQTT v5, the `properties` argument + * will be applied to the PUBLISH message. For MQTT v3.1.1 and below, the + * `properties` argument will be ignored. + * + * Set your client to use MQTT v5 immediately after it is created: + * + * mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + * + * Parameters: + * mosq - a valid mosquitto instance. + * mid - a pointer to an int. If not NULL, the function will set this to + * the message id of this particular message. This can be then used + * with the unsubscribe callback to determine when the message has been + * sent. + * sub - the unsubscription pattern. + * properties - a valid mosquitto_property list, or NULL. Only used with MQTT + * v5 clients. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + * MOSQ_ERR_PROTOCOL - if any property is invalid for use with UNSUBSCRIBE. + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. + */ +libmosq_EXPORT int mosquitto_unsubscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties); + +/* + * Function: mosquitto_unsubscribe_multiple + * + * Unsubscribe from multiple topics. + * + * Parameters: + * mosq - a valid mosquitto instance. + * mid - a pointer to an int. If not NULL, the function will set this to + * the message id of this particular message. This can be then used + * with the subscribe callback to determine when the message has been + * sent. + * sub_count - the count of unsubscriptions to be made + * sub - array of sub_count pointers, each pointing to an unsubscription string. + * The "char *const *const" datatype ensures that neither the array of + * pointers nor the strings that they point to are mutable. If you aren't + * familiar with this, just think of it as a safer "char **", + * equivalent to "const char *" for a simple string pointer. + * properties - a valid mosquitto_property list, or NULL. Only used with MQTT + * v5 clients. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_MALFORMED_UTF8 - if a topic is not valid UTF-8 + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. + */ +libmosq_EXPORT int mosquitto_unsubscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, const mosquitto_property *properties); + + +/* ====================================================================== + * + * Section: Struct mosquitto_message helper functions + * + * ====================================================================== */ +/* + * Function: mosquitto_message_copy + * + * Copy the contents of a mosquitto message to another message. + * Useful for preserving a message received in the on_message() callback. + * + * Parameters: + * dst - a pointer to a valid mosquitto_message struct to copy to. + * src - a pointer to a valid mosquitto_message struct to copy from. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * + * See Also: + * + */ +libmosq_EXPORT int mosquitto_message_copy(struct mosquitto_message *dst, const struct mosquitto_message *src); + +/* + * Function: mosquitto_message_free + * + * Completely free a mosquitto_message struct. + * + * Parameters: + * message - pointer to a mosquitto_message pointer to free. + * + * See Also: + * , + */ +libmosq_EXPORT void mosquitto_message_free(struct mosquitto_message **message); + +/* + * Function: mosquitto_message_free_contents + * + * Free a mosquitto_message struct contents, leaving the struct unaffected. + * + * Parameters: + * message - pointer to a mosquitto_message struct to free its contents. + * + * See Also: + * , + */ +libmosq_EXPORT void mosquitto_message_free_contents(struct mosquitto_message *message); + + +/* ====================================================================== + * + * Section: Network loop (managed by libmosquitto) + * + * The internal network loop must be called at a regular interval. The two + * recommended approaches are to use either or + * . is a blocking call and is + * suitable for the situation where you only want to handle incoming messages + * in callbacks. is a non-blocking call, it creates a + * separate thread to run the loop for you. Use this function when you have + * other tasks you need to run at the same time as the MQTT client, e.g. + * reading data from a sensor. + * + * ====================================================================== */ + +/* + * Function: mosquitto_loop_forever + * + * This function call loop() for you in an infinite blocking loop. It is useful + * for the case where you only want to run the MQTT client loop in your + * program. + * + * It handles reconnecting in case server connection is lost. If you call + * mosquitto_disconnect() in a callback it will return. + * + * Parameters: + * mosq - a valid mosquitto instance. + * timeout - Maximum number of milliseconds to wait for network activity + * in the select() call before timing out. Set to 0 for instant + * return. Set negative to use the default of 1000ms. + * max_packets - this parameter is currently unused and should be set to 1 for + * future compatibility. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost. + * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the + * broker. + * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno + * contains the error code, even on Windows. + * Use strerror_r() where available or FormatMessage() on + * Windows. + * + * See Also: + * , + */ +libmosq_EXPORT int mosquitto_loop_forever(struct mosquitto *mosq, int timeout, int max_packets); + +/* + * Function: mosquitto_loop_start + * + * This is part of the threaded client interface. Call this once to start a new + * thread to process network traffic. This provides an alternative to + * repeatedly calling yourself. + * + * Parameters: + * mosq - a valid mosquitto instance. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOT_SUPPORTED - if thread support is not available. + * + * See Also: + * , , , + */ +libmosq_EXPORT int mosquitto_loop_start(struct mosquitto *mosq); + +/* + * Function: mosquitto_loop_stop + * + * This is part of the threaded client interface. Call this once to stop the + * network thread previously created with . This call + * will block until the network thread finishes. For the network thread to end, + * you must have previously called or have set the force + * parameter to true. + * + * Parameters: + * mosq - a valid mosquitto instance. + * force - set to true to force thread cancellation. If false, + * must have already been called. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOT_SUPPORTED - if thread support is not available. + * + * See Also: + * , + */ +libmosq_EXPORT int mosquitto_loop_stop(struct mosquitto *mosq, bool force); + +/* + * Function: mosquitto_loop + * + * The main network loop for the client. This must be called frequently + * to keep communications between the client and broker working. This is + * carried out by and , which + * are the recommended ways of handling the network loop. You may also use this + * function if you wish. It must not be called inside a callback. + * + * If incoming data is present it will then be processed. Outgoing commands, + * from e.g. , are normally sent immediately that their + * function is called, but this is not always possible. will + * also attempt to send any remaining outgoing messages, which also includes + * commands that are part of the flow for messages with QoS>0. + * + * This calls select() to monitor the client network socket. If you want to + * integrate mosquitto client operation with your own select() call, use + * , , and + * . + * + * Threads: + * + * Parameters: + * mosq - a valid mosquitto instance. + * timeout - Maximum number of milliseconds to wait for network activity + * in the select() call before timing out. Set to 0 for instant + * return. Set negative to use the default of 1000ms. + * max_packets - this parameter is currently unused and should be set to 1 for + * future compatibility. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost. + * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the + * broker. + * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno + * contains the error code, even on Windows. + * Use strerror_r() where available or FormatMessage() on + * Windows. + * See Also: + * , , + */ +libmosq_EXPORT int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets); + +/* ====================================================================== + * + * Section: Network loop (for use in other event loops) + * + * ====================================================================== */ +/* + * Function: mosquitto_loop_read + * + * Carry out network read operations. + * This should only be used if you are not using mosquitto_loop() and are + * monitoring the client network socket for activity yourself. + * + * Parameters: + * mosq - a valid mosquitto instance. + * max_packets - this parameter is currently unused and should be set to 1 for + * future compatibility. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost. + * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the + * broker. + * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno + * contains the error code, even on Windows. + * Use strerror_r() where available or FormatMessage() on + * Windows. + * + * See Also: + * , , + */ +libmosq_EXPORT int mosquitto_loop_read(struct mosquitto *mosq, int max_packets); + +/* + * Function: mosquitto_loop_write + * + * Carry out network write operations. + * This should only be used if you are not using mosquitto_loop() and are + * monitoring the client network socket for activity yourself. + * + * Parameters: + * mosq - a valid mosquitto instance. + * max_packets - this parameter is currently unused and should be set to 1 for + * future compatibility. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost. + * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the + * broker. + * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno + * contains the error code, even on Windows. + * Use strerror_r() where available or FormatMessage() on + * Windows. + * + * See Also: + * , , , + */ +libmosq_EXPORT int mosquitto_loop_write(struct mosquitto *mosq, int max_packets); + +/* + * Function: mosquitto_loop_misc + * + * Carry out miscellaneous operations required as part of the network loop. + * This should only be used if you are not using mosquitto_loop() and are + * monitoring the client network socket for activity yourself. + * + * This function deals with handling PINGs and checking whether messages need + * to be retried, so should be called fairly frequently, around once per second + * is sufficient. + * + * Parameters: + * mosq - a valid mosquitto instance. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * + * See Also: + * , , + */ +libmosq_EXPORT int mosquitto_loop_misc(struct mosquitto *mosq); + + +/* ====================================================================== + * + * Section: Network loop (helper functions) + * + * ====================================================================== */ +/* + * Function: mosquitto_socket + * + * Return the socket handle for a mosquitto instance. Useful if you want to + * include a mosquitto client in your own select() calls. + * + * Parameters: + * mosq - a valid mosquitto instance. + * + * Returns: + * The socket for the mosquitto client or -1 on failure. + */ +libmosq_EXPORT int mosquitto_socket(struct mosquitto *mosq); + +/* + * Function: mosquitto_want_write + * + * Returns true if there is data ready to be written on the socket. + * + * Parameters: + * mosq - a valid mosquitto instance. + * + * See Also: + * , , + */ +libmosq_EXPORT bool mosquitto_want_write(struct mosquitto *mosq); + +/* + * Function: mosquitto_threaded_set + * + * Used to tell the library that your application is using threads, but not + * using . The library operates slightly differently when + * not in threaded mode in order to simplify its operation. If you are managing + * your own threads and do not use this function you will experience crashes + * due to race conditions. + * + * When using , this is set automatically. + * + * Parameters: + * mosq - a valid mosquitto instance. + * threaded - true if your application is using threads, false otherwise. + */ +libmosq_EXPORT int mosquitto_threaded_set(struct mosquitto *mosq, bool threaded); + + +/* ====================================================================== + * + * Section: Client options + * + * ====================================================================== */ +/* + * Function: mosquitto_opts_set + * + * Used to set options for the client. + * + * This function is deprecated, the replacement , + * and functions should + * be used instead. + * + * Parameters: + * mosq - a valid mosquitto instance. + * option - the option to set. + * value - the option specific value. + * + * Options: + * MOSQ_OPT_PROTOCOL_VERSION - Value must be an int, set to either + * MQTT_PROTOCOL_V31 or MQTT_PROTOCOL_V311. Must be set + * before the client connects. + * Defaults to MQTT_PROTOCOL_V31. + * + * MOSQ_OPT_SSL_CTX - Pass an openssl SSL_CTX to be used when creating + * TLS connections rather than libmosquitto creating its own. + * This must be called before connecting to have any effect. + * If you use this option, the onus is on you to ensure that + * you are using secure settings. + * Setting to NULL means that libmosquitto will use its own SSL_CTX + * if TLS is to be used. + * This option is only available for openssl 1.1.0 and higher. + * + * MOSQ_OPT_SSL_CTX_WITH_DEFAULTS - Value must be an int set to 1 or 0. + * If set to 1, then the user specified SSL_CTX passed in using + * MOSQ_OPT_SSL_CTX will have the default options applied to it. + * This means that you only need to change the values that are + * relevant to you. If you use this option then you must configure + * the TLS options as normal, i.e. you should use + * to configure the cafile/capath as a minimum. + * This option is only available for openssl 1.1.0 and higher. + */ +libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *value); + +/* + * Function: mosquitto_int_option + * + * Used to set integer options for the client. + * + * Parameters: + * mosq - a valid mosquitto instance. + * option - the option to set. + * value - the option specific value. + * + * Options: + * MOSQ_OPT_TCP_NODELAY - Set to 1 to disable Nagle's algorithm on client + * sockets. This has the effect of reducing latency of individual + * messages at the potential cost of increasing the number of + * packets being sent. + * Defaults to 0, which means Nagle remains enabled. + * + * MOSQ_OPT_PROTOCOL_VERSION - Value must be set to either MQTT_PROTOCOL_V31, + * MQTT_PROTOCOL_V311, or MQTT_PROTOCOL_V5. Must be set before the + * client connects. Defaults to MQTT_PROTOCOL_V311. + * + * MOSQ_OPT_RECEIVE_MAXIMUM - Value can be set between 1 and 65535 inclusive, + * and represents the maximum number of incoming QoS 1 and QoS 2 + * messages that this client wants to process at once. Defaults to + * 20. This option is not valid for MQTT v3.1 or v3.1.1 clients. + * Note that if the MQTT_PROP_RECEIVE_MAXIMUM property is in the + * proplist passed to mosquitto_connect_v5(), then that property + * will override this option. Using this option is the recommended + * method however. + * + * MOSQ_OPT_SEND_MAXIMUM - Value can be set between 1 and 65535 inclusive, + * and represents the maximum number of outgoing QoS 1 and QoS 2 + * messages that this client will attempt to have "in flight" at + * once. Defaults to 20. + * This option is not valid for MQTT v3.1 or v3.1.1 clients. + * Note that if the broker being connected to sends a + * MQTT_PROP_RECEIVE_MAXIMUM property that has a lower value than + * this option, then the broker provided value will be used. + * + * MOSQ_OPT_SSL_CTX_WITH_DEFAULTS - If value is set to a non zero value, + * then the user specified SSL_CTX passed in using MOSQ_OPT_SSL_CTX + * will have the default options applied to it. This means that + * you only need to change the values that are relevant to you. + * If you use this option then you must configure the TLS options + * as normal, i.e. you should use to + * configure the cafile/capath as a minimum. + * This option is only available for openssl 1.1.0 and higher. + * + * MOSQ_OPT_TLS_OCSP_REQUIRED - Set whether OCSP checking on TLS + * connections is required. Set to 1 to enable checking, + * or 0 (the default) for no checking. + * + * MOSQ_OPT_TLS_USE_OS_CERTS - Set to 1 to instruct the client to load and + * trust OS provided CA certificates for use with TLS connections. + * Set to 0 (the default) to only use manually specified CA certs. + */ +libmosq_EXPORT int mosquitto_int_option(struct mosquitto *mosq, enum mosq_opt_t option, int value); + + +/* + * Function: mosquitto_string_option + * + * Used to set const char* options for the client. + * + * Parameters: + * mosq - a valid mosquitto instance. + * option - the option to set. + * value - the option specific value. + * + * Options: + * MOSQ_OPT_TLS_ENGINE - Configure the client for TLS Engine support. + * Pass a TLS Engine ID to be used when creating TLS + * connections. Must be set before . + * Must be a valid engine, and note that the string will not be used + * until a connection attempt is made so this function will return + * success even if an invalid engine string is passed. + * + * MOSQ_OPT_TLS_KEYFORM - Configure the client to treat the keyfile + * differently depending on its type. Must be set + * before . + * Set as either "pem" or "engine", to determine from where the + * private key for a TLS connection will be obtained. Defaults to + * "pem", a normal private key file. + * + * MOSQ_OPT_TLS_KPASS_SHA1 - Where the TLS Engine requires the use of + * a password to be accessed, this option allows a hex encoded + * SHA1 hash of the private key password to be passed to the + * engine directly. Must be set before . + * + * MOSQ_OPT_TLS_ALPN - If the broker being connected to has multiple + * services available on a single TLS port, such as both MQTT + * and WebSockets, use this option to configure the ALPN + * option for the connection. + * + * MOSQ_OPT_BIND_ADDRESS - Set the hostname or ip address of the local network + * interface to bind to when connecting. + */ +libmosq_EXPORT int mosquitto_string_option(struct mosquitto *mosq, enum mosq_opt_t option, const char *value); + + +/* + * Function: mosquitto_void_option + * + * Used to set void* options for the client. + * + * Parameters: + * mosq - a valid mosquitto instance. + * option - the option to set. + * value - the option specific value. + * + * Options: + * MOSQ_OPT_SSL_CTX - Pass an openssl SSL_CTX to be used when creating TLS + * connections rather than libmosquitto creating its own. This must + * be called before connecting to have any effect. If you use this + * option, the onus is on you to ensure that you are using secure + * settings. + * Setting to NULL means that libmosquitto will use its own SSL_CTX + * if TLS is to be used. + * This option is only available for openssl 1.1.0 and higher. + */ +libmosq_EXPORT int mosquitto_void_option(struct mosquitto *mosq, enum mosq_opt_t option, void *value); + +/* + * Function: mosquitto_reconnect_delay_set + * + * Control the behaviour of the client when it has unexpectedly disconnected in + * or after . The default + * behaviour if this function is not used is to repeatedly attempt to reconnect + * with a delay of 1 second until the connection succeeds. + * + * Use reconnect_delay parameter to change the delay between successive + * reconnection attempts. You may also enable exponential backoff of the time + * between reconnections by setting reconnect_exponential_backoff to true and + * set an upper bound on the delay with reconnect_delay_max. + * + * Example 1: + * delay=2, delay_max=10, exponential_backoff=False + * Delays would be: 2, 4, 6, 8, 10, 10, ... + * + * Example 2: + * delay=3, delay_max=30, exponential_backoff=True + * Delays would be: 3, 6, 12, 24, 30, 30, ... + * + * Parameters: + * mosq - a valid mosquitto instance. + * reconnect_delay - the number of seconds to wait between + * reconnects. + * reconnect_delay_max - the maximum number of seconds to wait + * between reconnects. + * reconnect_exponential_backoff - use exponential backoff between + * reconnect attempts. Set to true to enable + * exponential backoff. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + */ +libmosq_EXPORT int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff); + +/* + * Function: mosquitto_max_inflight_messages_set + * + * This function is deprected. Use the function with the + * MOSQ_OPT_SEND_MAXIMUM option instead. + * + * Set the number of QoS 1 and 2 messages that can be "in flight" at one time. + * An in flight message is part way through its delivery flow. Attempts to send + * further messages with will result in the messages being + * queued until the number of in flight messages reduces. + * + * A higher number here results in greater message throughput, but if set + * higher than the maximum in flight messages on the broker may lead to + * delays in the messages being acknowledged. + * + * Set to 0 for no maximum. + * + * Parameters: + * mosq - a valid mosquitto instance. + * max_inflight_messages - the maximum number of inflight messages. Defaults + * to 20. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + */ +libmosq_EXPORT int mosquitto_max_inflight_messages_set(struct mosquitto *mosq, unsigned int max_inflight_messages); + +/* + * Function: mosquitto_message_retry_set + * + * This function now has no effect. + */ +libmosq_EXPORT void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_retry); + +/* + * Function: mosquitto_user_data_set + * + * When is called, the pointer given as the "obj" parameter + * will be passed to the callbacks as user data. The + * function allows this obj parameter to be updated at any time. This function + * will not modify the memory pointed to by the current user data pointer. If + * it is dynamically allocated memory you must free it yourself. + * + * Parameters: + * mosq - a valid mosquitto instance. + * obj - A user pointer that will be passed as an argument to any callbacks + * that are specified. + */ +libmosq_EXPORT void mosquitto_user_data_set(struct mosquitto *mosq, void *obj); + +/* Function: mosquitto_userdata + * + * Retrieve the "userdata" variable for a mosquitto client. + * + * Parameters: + * mosq - a valid mosquitto instance. + * + * Returns: + * A pointer to the userdata member variable. + */ +libmosq_EXPORT void *mosquitto_userdata(struct mosquitto *mosq); + + +/* ====================================================================== + * + * Section: TLS support + * + * ====================================================================== */ +/* + * Function: mosquitto_tls_set + * + * Configure the client for certificate based SSL/TLS support. Must be called + * before . + * + * Cannot be used in conjunction with . + * + * Define the Certificate Authority certificates to be trusted (ie. the server + * certificate must be signed with one of these certificates) using cafile. + * + * If the server you are connecting to requires clients to provide a + * certificate, define certfile and keyfile with your client certificate and + * private key. If your private key is encrypted, provide a password callback + * function or you will have to enter the password at the command line. + * + * Parameters: + * mosq - a valid mosquitto instance. + * cafile - path to a file containing the PEM encoded trusted CA + * certificate files. Either cafile or capath must not be NULL. + * capath - path to a directory containing the PEM encoded trusted CA + * certificate files. See mosquitto.conf for more details on + * configuring this directory. Either cafile or capath must not + * be NULL. + * certfile - path to a file containing the PEM encoded certificate file + * for this client. If NULL, keyfile must also be NULL and no + * client certificate will be used. + * keyfile - path to a file containing the PEM encoded private key for + * this client. If NULL, certfile must also be NULL and no + * client certificate will be used. + * pw_callback - if keyfile is encrypted, set pw_callback to allow your client + * to pass the correct password for decryption. If set to NULL, + * the password must be entered on the command line. + * Your callback must write the password into "buf", which is + * "size" bytes long. The return value must be the length of the + * password. "userdata" will be set to the calling mosquitto + * instance. The mosquitto userdata member variable can be + * retrieved using . + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * + * See Also: + * , , + * , + */ +libmosq_EXPORT int mosquitto_tls_set(struct mosquitto *mosq, + const char *cafile, const char *capath, + const char *certfile, const char *keyfile, + int (*pw_callback)(char *buf, int size, int rwflag, void *userdata)); + +/* + * Function: mosquitto_tls_insecure_set + * + * Configure verification of the server hostname in the server certificate. If + * value is set to true, it is impossible to guarantee that the host you are + * connecting to is not impersonating your server. This can be useful in + * initial server testing, but makes it possible for a malicious third party to + * impersonate your server through DNS spoofing, for example. + * Do not use this function in a real system. Setting value to true makes the + * connection encryption pointless. + * Must be called before . + * + * Parameters: + * mosq - a valid mosquitto instance. + * value - if set to false, the default, certificate hostname checking is + * performed. If set to true, no hostname checking is performed and + * the connection is insecure. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * + * See Also: + * + */ +libmosq_EXPORT int mosquitto_tls_insecure_set(struct mosquitto *mosq, bool value); + +/* + * Function: mosquitto_tls_opts_set + * + * Set advanced SSL/TLS options. Must be called before . + * + * Parameters: + * mosq - a valid mosquitto instance. + * cert_reqs - an integer defining the verification requirements the client + * will impose on the server. This can be one of: + * * SSL_VERIFY_NONE (0): the server will not be verified in any way. + * * SSL_VERIFY_PEER (1): the server certificate will be verified + * and the connection aborted if the verification fails. + * The default and recommended value is SSL_VERIFY_PEER. Using + * SSL_VERIFY_NONE provides no security. + * tls_version - the version of the SSL/TLS protocol to use as a string. If NULL, + * the default value is used. The default value and the + * available values depend on the version of openssl that the + * library was compiled against. For openssl >= 1.0.1, the + * available options are tlsv1.2, tlsv1.1 and tlsv1, with tlv1.2 + * as the default. For openssl < 1.0.1, only tlsv1 is available. + * ciphers - a string describing the ciphers available for use. See the + * "openssl ciphers" tool for more information. If NULL, the + * default ciphers will be used. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * + * See Also: + * + */ +libmosq_EXPORT int mosquitto_tls_opts_set(struct mosquitto *mosq, int cert_reqs, const char *tls_version, const char *ciphers); + +/* + * Function: mosquitto_tls_psk_set + * + * Configure the client for pre-shared-key based TLS support. Must be called + * before . + * + * Cannot be used in conjunction with . + * + * Parameters: + * mosq - a valid mosquitto instance. + * psk - the pre-shared-key in hex format with no leading "0x". + * identity - the identity of this client. May be used as the username + * depending on the server settings. + * ciphers - a string describing the PSK ciphers available for use. See the + * "openssl ciphers" tool for more information. If NULL, the + * default ciphers will be used. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * + * See Also: + * + */ +libmosq_EXPORT int mosquitto_tls_psk_set(struct mosquitto *mosq, const char *psk, const char *identity, const char *ciphers); + + +/* + * Function: mosquitto_ssl_get + * + * Retrieve a pointer to the SSL structure used for TLS connections in this + * client. This can be used in e.g. the connect callback to carry out + * additional verification steps. + * + * Parameters: + * mosq - a valid mosquitto instance + * + * Returns: + * A valid pointer to an openssl SSL structure - if the client is using TLS. + * NULL - if the client is not using TLS, or TLS support is not compiled in. + */ +libmosq_EXPORT void *mosquitto_ssl_get(struct mosquitto *mosq); + + +/* ====================================================================== + * + * Section: Callbacks + * + * ====================================================================== */ +/* + * Function: mosquitto_connect_callback_set + * + * Set the connect callback. This is called when the library receives a CONNACK + * message in response to a connection. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_connect - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int rc) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * rc - the return code of the connection response. The values are defined by + * the MQTT protocol version in use. + * For MQTT v5.0, look at section 3.2.2.2 Connect Reason code: https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html + * For MQTT v3.1.1, look at section 3.2.2.3 Connect Return code: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html + */ +libmosq_EXPORT void mosquitto_connect_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int)); + +/* + * Function: mosquitto_connect_with_flags_callback_set + * + * Set the connect callback. This is called when the library receives a CONNACK + * message in response to a connection. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_connect - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int rc) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * rc - the return code of the connection response. The values are defined by + * the MQTT protocol version in use. + * For MQTT v5.0, look at section 3.2.2.2 Connect Reason code: https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html + * For MQTT v3.1.1, look at section 3.2.2.3 Connect Return code: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html + * flags - the connect flags. + */ +libmosq_EXPORT void mosquitto_connect_with_flags_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int)); + +/* + * Function: mosquitto_connect_v5_callback_set + * + * Set the connect callback. This is called when the library receives a CONNACK + * message in response to a connection. + * + * It is valid to set this callback for all MQTT protocol versions. If it is + * used with MQTT clients that use MQTT v3.1.1 or earlier, then the `props` + * argument will always be NULL. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_connect - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int rc) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * rc - the return code of the connection response. The values are defined by + * the MQTT protocol version in use. + * For MQTT v5.0, look at section 3.2.2.2 Connect Reason code: https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html + * For MQTT v3.1.1, look at section 3.2.2.3 Connect Return code: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html + * flags - the connect flags. + * props - list of MQTT 5 properties, or NULL + * + */ +libmosq_EXPORT void mosquitto_connect_v5_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int, const mosquitto_property *props)); + +/* + * Function: mosquitto_disconnect_callback_set + * + * Set the disconnect callback. This is called when the broker has received the + * DISCONNECT command and has disconnected the client. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_disconnect - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * rc - integer value indicating the reason for the disconnect. A value of 0 + * means the client has called . Any other value + * indicates that the disconnect is unexpected. + */ +libmosq_EXPORT void mosquitto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int)); + +/* + * Function: mosquitto_disconnect_v5_callback_set + * + * Set the disconnect callback. This is called when the broker has received the + * DISCONNECT command and has disconnected the client. + * + * It is valid to set this callback for all MQTT protocol versions. If it is + * used with MQTT clients that use MQTT v3.1.1 or earlier, then the `props` + * argument will always be NULL. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_disconnect - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * rc - integer value indicating the reason for the disconnect. A value of 0 + * means the client has called . Any other value + * indicates that the disconnect is unexpected. + * props - list of MQTT 5 properties, or NULL + */ +libmosq_EXPORT void mosquitto_disconnect_v5_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int, const mosquitto_property *props)); + +/* + * Function: mosquitto_publish_callback_set + * + * Set the publish callback. This is called when a message initiated with + * has been sent to the broker. "Sent" means different + * things depending on the QoS of the message: + * + * QoS 0: The PUBLISH was passed to the local operating system for delivery, + * there is no guarantee that it was delivered to the remote broker. + * QoS 1: The PUBLISH was sent to the remote broker and the corresponding + * PUBACK was received by the library. + * QoS 2: The PUBLISH was sent to the remote broker and the corresponding + * PUBCOMP was received by the library. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_publish - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int mid) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * mid - the message id of the sent message. + */ +libmosq_EXPORT void mosquitto_publish_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int)); + +/* + * Function: mosquitto_publish_v5_callback_set + * + * Set the publish callback. This is called when a message initiated with + * has been sent to the broker. This callback will be + * called both if the message is sent successfully, or if the broker responded + * with an error, which will be reflected in the reason_code parameter. + * "Sent" means different things depending on the QoS of the message: + * + * QoS 0: The PUBLISH was passed to the local operating system for delivery, + * there is no guarantee that it was delivered to the remote broker. + * QoS 1: The PUBLISH was sent to the remote broker and the corresponding + * PUBACK was received by the library. + * QoS 2: The PUBLISH was sent to the remote broker and the corresponding + * PUBCOMP was received by the library. + * + * + * It is valid to set this callback for all MQTT protocol versions. If it is + * used with MQTT clients that use MQTT v3.1.1 or earlier, then the `props` + * argument will always be NULL. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_publish - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int mid) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * mid - the message id of the sent message. + * reason_code - the MQTT 5 reason code + * props - list of MQTT 5 properties, or NULL + */ +libmosq_EXPORT void mosquitto_publish_v5_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int, int, const mosquitto_property *props)); + +/* + * Function: mosquitto_message_callback_set + * + * Set the message callback. This is called when a message is received from the + * broker and the required QoS flow has completed. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_message - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * message - the message data. This variable and associated memory will be + * freed by the library after the callback completes. The client + * should make copies of any of the data it requires. + * + * See Also: + * + */ +libmosq_EXPORT void mosquitto_message_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *)); + +/* + * Function: mosquitto_message_v5_callback_set + * + * Set the message callback. This is called when a message is received from the + * broker and the required QoS flow has completed. + * + * It is valid to set this callback for all MQTT protocol versions. If it is + * used with MQTT clients that use MQTT v3.1.1 or earlier, then the `props` + * argument will always be NULL. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_message - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * message - the message data. This variable and associated memory will be + * freed by the library after the callback completes. The client + * should make copies of any of the data it requires. + * props - list of MQTT 5 properties, or NULL + * + * See Also: + * + */ +libmosq_EXPORT void mosquitto_message_v5_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *, const mosquitto_property *props)); + +/* + * Function: mosquitto_subscribe_callback_set + * + * Set the subscribe callback. This is called when the library receives a + * SUBACK message in response to a SUBSCRIBE. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_subscribe - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * mid - the message id of the subscribe message. + * qos_count - the number of granted subscriptions (size of granted_qos). + * granted_qos - an array of integers indicating the granted QoS for each of + * the subscriptions. + */ +libmosq_EXPORT void mosquitto_subscribe_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *)); + +/* + * Function: mosquitto_subscribe_v5_callback_set + * + * Set the subscribe callback. This is called when the library receives a + * SUBACK message in response to a SUBSCRIBE. + * + * It is valid to set this callback for all MQTT protocol versions. If it is + * used with MQTT clients that use MQTT v3.1.1 or earlier, then the `props` + * argument will always be NULL. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_subscribe - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * mid - the message id of the subscribe message. + * qos_count - the number of granted subscriptions (size of granted_qos). + * granted_qos - an array of integers indicating the granted QoS for each of + * the subscriptions. + * props - list of MQTT 5 properties, or NULL + */ +libmosq_EXPORT void mosquitto_subscribe_v5_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *, const mosquitto_property *props)); + +/* + * Function: mosquitto_unsubscribe_callback_set + * + * Set the unsubscribe callback. This is called when the library receives a + * UNSUBACK message in response to an UNSUBSCRIBE. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_unsubscribe - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int mid) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * mid - the message id of the unsubscribe message. + */ +libmosq_EXPORT void mosquitto_unsubscribe_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int)); + +/* + * Function: mosquitto_unsubscribe_v5_callback_set + * + * Set the unsubscribe callback. This is called when the library receives a + * UNSUBACK message in response to an UNSUBSCRIBE. + * + * It is valid to set this callback for all MQTT protocol versions. If it is + * used with MQTT clients that use MQTT v3.1.1 or earlier, then the `props` + * argument will always be NULL. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_unsubscribe - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int mid) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * mid - the message id of the unsubscribe message. + * props - list of MQTT 5 properties, or NULL + */ +libmosq_EXPORT void mosquitto_unsubscribe_v5_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int, const mosquitto_property *props)); + +/* + * Function: mosquitto_log_callback_set + * + * Set the logging callback. This should be used if you want event logging + * information from the client library. + * + * mosq - a valid mosquitto instance. + * on_log - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int level, const char *str) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * level - the log message level from the values: + * MOSQ_LOG_INFO + * MOSQ_LOG_NOTICE + * MOSQ_LOG_WARNING + * MOSQ_LOG_ERR + * MOSQ_LOG_DEBUG + * str - the message string. + */ +libmosq_EXPORT void mosquitto_log_callback_set(struct mosquitto *mosq, void (*on_log)(struct mosquitto *, void *, int, const char *)); + + +/* ============================================================================= + * + * Section: SOCKS5 proxy functions + * + * ============================================================================= + */ + +/* + * Function: mosquitto_socks5_set + * + * Configure the client to use a SOCKS5 proxy when connecting. Must be called + * before connecting. "None" and "username/password" authentication is + * supported. + * + * Parameters: + * mosq - a valid mosquitto instance. + * host - the SOCKS5 proxy host to connect to. + * port - the SOCKS5 proxy port to use. + * username - if not NULL, use this username when authenticating with the proxy. + * password - if not NULL and username is not NULL, use this password when + * authenticating with the proxy. + */ +libmosq_EXPORT int mosquitto_socks5_set(struct mosquitto *mosq, const char *host, int port, const char *username, const char *password); + + +/* ============================================================================= + * + * Section: Utility functions + * + * ============================================================================= + */ + +/* + * Function: mosquitto_strerror + * + * Call to obtain a const string description of a mosquitto error number. + * + * Parameters: + * mosq_errno - a mosquitto error number. + * + * Returns: + * A constant string describing the error. + */ +libmosq_EXPORT const char *mosquitto_strerror(int mosq_errno); + +/* + * Function: mosquitto_connack_string + * + * Call to obtain a const string description of an MQTT connection result. + * + * Parameters: + * connack_code - an MQTT connection result. + * + * Returns: + * A constant string describing the result. + */ +libmosq_EXPORT const char *mosquitto_connack_string(int connack_code); + +/* + * Function: mosquitto_reason_string + * + * Call to obtain a const string description of an MQTT reason code. + * + * Parameters: + * reason_code - an MQTT reason code. + * + * Returns: + * A constant string describing the reason. + */ +libmosq_EXPORT const char *mosquitto_reason_string(int reason_code); + +/* Function: mosquitto_string_to_command + * + * Take a string input representing an MQTT command and convert it to the + * libmosquitto integer representation. + * + * Parameters: + * str - the string to parse. + * cmd - pointer to an int, for the result. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - on an invalid input. + * + * Example: + * (start code) + * mosquitto_string_to_command("CONNECT", &cmd); + * // cmd == CMD_CONNECT + * (end) + */ +libmosq_EXPORT int mosquitto_string_to_command(const char *str, int *cmd); + +/* + * Function: mosquitto_sub_topic_tokenise + * + * Tokenise a topic or subscription string into an array of strings + * representing the topic hierarchy. + * + * For example: + * + * subtopic: "a/deep/topic/hierarchy" + * + * Would result in: + * + * topics[0] = "a" + * topics[1] = "deep" + * topics[2] = "topic" + * topics[3] = "hierarchy" + * + * and: + * + * subtopic: "/a/deep/topic/hierarchy/" + * + * Would result in: + * + * topics[0] = NULL + * topics[1] = "a" + * topics[2] = "deep" + * topics[3] = "topic" + * topics[4] = "hierarchy" + * + * Parameters: + * subtopic - the subscription/topic to tokenise + * topics - a pointer to store the array of strings + * count - an int pointer to store the number of items in the topics array. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * + * Example: + * + * > char **topics; + * > int topic_count; + * > int i; + * > + * > mosquitto_sub_topic_tokenise("$SYS/broker/uptime", &topics, &topic_count); + * > + * > for(i=0; i printf("%d: %s\n", i, topics[i]); + * > } + * + * See Also: + * + */ +libmosq_EXPORT int mosquitto_sub_topic_tokenise(const char *subtopic, char ***topics, int *count); + +/* + * Function: mosquitto_sub_topic_tokens_free + * + * Free memory that was allocated in . + * + * Parameters: + * topics - pointer to string array. + * count - count of items in string array. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * + * See Also: + * + */ +libmosq_EXPORT int mosquitto_sub_topic_tokens_free(char ***topics, int count); + +/* + * Function: mosquitto_topic_matches_sub + * + * Check whether a topic matches a subscription. + * + * For example: + * + * foo/bar would match the subscription foo/# or +/bar + * non/matching would not match the subscription non/+/+ + * + * Parameters: + * sub - subscription string to check topic against. + * topic - topic to check. + * result - bool pointer to hold result. Will be set to true if the topic + * matches the subscription. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + */ +libmosq_EXPORT int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result); + + +/* + * Function: mosquitto_topic_matches_sub2 + * + * Check whether a topic matches a subscription. + * + * For example: + * + * foo/bar would match the subscription foo/# or +/bar + * non/matching would not match the subscription non/+/+ + * + * Parameters: + * sub - subscription string to check topic against. + * sublen - length in bytes of sub string + * topic - topic to check. + * topiclen - length in bytes of topic string + * result - bool pointer to hold result. Will be set to true if the topic + * matches the subscription. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + */ +libmosq_EXPORT int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *topic, size_t topiclen, bool *result); + +/* + * Function: mosquitto_pub_topic_check + * + * Check whether a topic to be used for publishing is valid. + * + * This searches for + or # in a topic and checks its length. + * + * This check is already carried out in and + * , there is no need to call it directly before them. It + * may be useful if you wish to check the validity of a topic in advance of + * making a connection for example. + * + * Parameters: + * topic - the topic to check + * + * Returns: + * MOSQ_ERR_SUCCESS - for a valid topic + * MOSQ_ERR_INVAL - if the topic contains a + or a #, or if it is too long. + * MOSQ_ERR_MALFORMED_UTF8 - if topic is not valid UTF-8 + * + * See Also: + * + */ +libmosq_EXPORT int mosquitto_pub_topic_check(const char *topic); + +/* + * Function: mosquitto_pub_topic_check2 + * + * Check whether a topic to be used for publishing is valid. + * + * This searches for + or # in a topic and checks its length. + * + * This check is already carried out in and + * , there is no need to call it directly before them. It + * may be useful if you wish to check the validity of a topic in advance of + * making a connection for example. + * + * Parameters: + * topic - the topic to check + * topiclen - length of the topic in bytes + * + * Returns: + * MOSQ_ERR_SUCCESS - for a valid topic + * MOSQ_ERR_INVAL - if the topic contains a + or a #, or if it is too long. + * MOSQ_ERR_MALFORMED_UTF8 - if topic is not valid UTF-8 + * + * See Also: + * + */ +libmosq_EXPORT int mosquitto_pub_topic_check2(const char *topic, size_t topiclen); + +/* + * Function: mosquitto_sub_topic_check + * + * Check whether a topic to be used for subscribing is valid. + * + * This searches for + or # in a topic and checks that they aren't in invalid + * positions, such as with foo/#/bar, foo/+bar or foo/bar#, and checks its + * length. + * + * This check is already carried out in and + * , there is no need to call it directly before them. + * It may be useful if you wish to check the validity of a topic in advance of + * making a connection for example. + * + * Parameters: + * topic - the topic to check + * + * Returns: + * MOSQ_ERR_SUCCESS - for a valid topic + * MOSQ_ERR_INVAL - if the topic contains a + or a # that is in an + * invalid position, or if it is too long. + * MOSQ_ERR_MALFORMED_UTF8 - if topic is not valid UTF-8 + * + * See Also: + * + */ +libmosq_EXPORT int mosquitto_sub_topic_check(const char *topic); + +/* + * Function: mosquitto_sub_topic_check2 + * + * Check whether a topic to be used for subscribing is valid. + * + * This searches for + or # in a topic and checks that they aren't in invalid + * positions, such as with foo/#/bar, foo/+bar or foo/bar#, and checks its + * length. + * + * This check is already carried out in and + * , there is no need to call it directly before them. + * It may be useful if you wish to check the validity of a topic in advance of + * making a connection for example. + * + * Parameters: + * topic - the topic to check + * topiclen - the length in bytes of the topic + * + * Returns: + * MOSQ_ERR_SUCCESS - for a valid topic + * MOSQ_ERR_INVAL - if the topic contains a + or a # that is in an + * invalid position, or if it is too long. + * MOSQ_ERR_MALFORMED_UTF8 - if topic is not valid UTF-8 + * + * See Also: + * + */ +libmosq_EXPORT int mosquitto_sub_topic_check2(const char *topic, size_t topiclen); + + +/* + * Function: mosquitto_validate_utf8 + * + * Helper function to validate whether a UTF-8 string is valid, according to + * the UTF-8 spec and the MQTT additions. + * + * Parameters: + * str - a string to check + * len - the length of the string in bytes + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if str is NULL or len<0 or len>65536 + * MOSQ_ERR_MALFORMED_UTF8 - if str is not valid UTF-8 + */ +libmosq_EXPORT int mosquitto_validate_utf8(const char *str, int len); + + +/* ============================================================================= + * + * Section: One line client helper functions + * + * ============================================================================= + */ + +struct libmosquitto_will { + char *topic; + void *payload; + int payloadlen; + int qos; + bool retain; +}; + +struct libmosquitto_auth { + char *username; + char *password; +}; + +struct libmosquitto_tls { + char *cafile; + char *capath; + char *certfile; + char *keyfile; + char *ciphers; + char *tls_version; + int (*pw_callback)(char *buf, int size, int rwflag, void *userdata); + int cert_reqs; +}; + +/* + * Function: mosquitto_subscribe_simple + * + * Helper function to make subscribing to a topic and retrieving some messages + * very straightforward. + * + * This connects to a broker, subscribes to a topic, waits for msg_count + * messages to be received, then returns after disconnecting cleanly. + * + * Parameters: + * messages - pointer to a "struct mosquitto_message *". The received + * messages will be returned here. On error, this will be set to + * NULL. + * msg_count - the number of messages to retrieve. + * want_retained - if set to true, stale retained messages will be treated as + * normal messages with regards to msg_count. If set to + * false, they will be ignored. + * topic - the subscription topic to use (wildcards are allowed). + * qos - the qos to use for the subscription. + * host - the broker to connect to. + * port - the network port the broker is listening on. + * client_id - the client id to use, or NULL if a random client id should be + * generated. + * keepalive - the MQTT keepalive value. + * clean_session - the MQTT clean session flag. + * username - the username string, or NULL for no username authentication. + * password - the password string, or NULL for an empty password. + * will - a libmosquitto_will struct containing will information, or NULL for + * no will. + * tls - a libmosquitto_tls struct containing TLS related parameters, or NULL + * for no use of TLS. + * + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * Greater than 0 - on error. + */ +libmosq_EXPORT int mosquitto_subscribe_simple( + struct mosquitto_message **messages, + int msg_count, + bool want_retained, + const char *topic, + int qos, + const char *host, + int port, + const char *client_id, + int keepalive, + bool clean_session, + const char *username, + const char *password, + const struct libmosquitto_will *will, + const struct libmosquitto_tls *tls); + + +/* + * Function: mosquitto_subscribe_callback + * + * Helper function to make subscribing to a topic and processing some messages + * very straightforward. + * + * This connects to a broker, subscribes to a topic, then passes received + * messages to a user provided callback. If the callback returns a 1, it then + * disconnects cleanly and returns. + * + * Parameters: + * callback - a callback function in the following form: + * int callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) + * Note that this is the same as the normal on_message callback, + * except that it returns an int. + * userdata - user provided pointer that will be passed to the callback. + * topic - the subscription topic to use (wildcards are allowed). + * qos - the qos to use for the subscription. + * host - the broker to connect to. + * port - the network port the broker is listening on. + * client_id - the client id to use, or NULL if a random client id should be + * generated. + * keepalive - the MQTT keepalive value. + * clean_session - the MQTT clean session flag. + * username - the username string, or NULL for no username authentication. + * password - the password string, or NULL for an empty password. + * will - a libmosquitto_will struct containing will information, or NULL for + * no will. + * tls - a libmosquitto_tls struct containing TLS related parameters, or NULL + * for no use of TLS. + * + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * Greater than 0 - on error. + */ +libmosq_EXPORT int mosquitto_subscribe_callback( + int (*callback)(struct mosquitto *, void *, const struct mosquitto_message *), + void *userdata, + const char *topic, + int qos, + const char *host, + int port, + const char *client_id, + int keepalive, + bool clean_session, + const char *username, + const char *password, + const struct libmosquitto_will *will, + const struct libmosquitto_tls *tls); + + +/* ============================================================================= + * + * Section: Properties + * + * ============================================================================= + */ + + +/* + * Function: mosquitto_property_add_byte + * + * Add a new byte property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - integer value for the new property + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * + * Example: + * > mosquitto_property *proplist = NULL; + * > mosquitto_property_add_byte(&proplist, MQTT_PROP_PAYLOAD_FORMAT_IDENTIFIER, 1); + */ +libmosq_EXPORT int mosquitto_property_add_byte(mosquitto_property **proplist, int identifier, uint8_t value); + +/* + * Function: mosquitto_property_add_int16 + * + * Add a new int16 property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_RECEIVE_MAXIMUM) + * value - integer value for the new property + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * + * Example: + * > mosquitto_property *proplist = NULL; + * > mosquitto_property_add_int16(&proplist, MQTT_PROP_RECEIVE_MAXIMUM, 1000); + */ +libmosq_EXPORT int mosquitto_property_add_int16(mosquitto_property **proplist, int identifier, uint16_t value); + +/* + * Function: mosquitto_property_add_int32 + * + * Add a new int32 property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_MESSAGE_EXPIRY_INTERVAL) + * value - integer value for the new property + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * + * Example: + * > mosquitto_property *proplist = NULL; + * > mosquitto_property_add_int32(&proplist, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, 86400); + */ +libmosq_EXPORT int mosquitto_property_add_int32(mosquitto_property **proplist, int identifier, uint32_t value); + +/* + * Function: mosquitto_property_add_varint + * + * Add a new varint property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_SUBSCRIPTION_IDENTIFIER) + * value - integer value for the new property + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * + * Example: + * > mosquitto_property *proplist = NULL; + * > mosquitto_property_add_varint(&proplist, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 1); + */ +libmosq_EXPORT int mosquitto_property_add_varint(mosquitto_property **proplist, int identifier, uint32_t value); + +/* + * Function: mosquitto_property_add_binary + * + * Add a new binary property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to the property data + * len - length of property data in bytes + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * + * Example: + * > mosquitto_property *proplist = NULL; + * > mosquitto_property_add_binary(&proplist, MQTT_PROP_AUTHENTICATION_DATA, auth_data, auth_data_len); + */ +libmosq_EXPORT int mosquitto_property_add_binary(mosquitto_property **proplist, int identifier, const void *value, uint16_t len); + +/* + * Function: mosquitto_property_add_string + * + * Add a new string property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_CONTENT_TYPE) + * value - string value for the new property, must be UTF-8 and zero terminated + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, if value is NULL, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * MOSQ_ERR_MALFORMED_UTF8 - value is not valid UTF-8. + * + * Example: + * > mosquitto_property *proplist = NULL; + * > mosquitto_property_add_string(&proplist, MQTT_PROP_CONTENT_TYPE, "application/json"); + */ +libmosq_EXPORT int mosquitto_property_add_string(mosquitto_property **proplist, int identifier, const char *value); + +/* + * Function: mosquitto_property_add_string_pair + * + * Add a new string pair property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_USER_PROPERTY) + * name - string name for the new property, must be UTF-8 and zero terminated + * value - string value for the new property, must be UTF-8 and zero terminated + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, if name or value is NULL, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * MOSQ_ERR_MALFORMED_UTF8 - if name or value are not valid UTF-8. + * + * Example: + * > mosquitto_property *proplist = NULL; + * > mosquitto_property_add_string_pair(&proplist, MQTT_PROP_USER_PROPERTY, "client", "mosquitto_pub"); + */ +libmosq_EXPORT int mosquitto_property_add_string_pair(mosquitto_property **proplist, int identifier, const char *name, const char *value); + + +/* + * Function: mosquitto_property_identifier + * + * Return the property identifier for a single property. + * + * Parameters: + * property - pointer to a valid mosquitto_property pointer. + * + * Returns: + * A valid property identifier on success + * 0 - on error + */ +libmosq_EXPORT int mosquitto_property_identifier(const mosquitto_property *property); + + +/* + * Function: mosquitto_property_next + * + * Return the next property in a property list. Use to iterate over a property + * list, e.g.: + * + * (start code) + * for(prop = proplist; prop != NULL; prop = mosquitto_property_next(prop)){ + * if(mosquitto_property_identifier(prop) == MQTT_PROP_CONTENT_TYPE){ + * ... + * } + * } + * (end) + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * + * Returns: + * Pointer to the next item in the list + * NULL, if proplist is NULL, or if there are no more items in the list. + */ +libmosq_EXPORT const mosquitto_property *mosquitto_property_next(const mosquitto_property *proplist); + + +/* + * Function: mosquitto_property_read_byte + * + * Attempt to read a byte property matching an identifier, from a property list + * or single property. This function can search for multiple entries of the + * same identifier by using the returned value and skip_first. Note however + * that it is forbidden for most properties to be duplicated. + * + * If the property is not found, *value will not be modified, so it is safe to + * pass a variable with a default value to be potentially overwritten: + * + * (start code) + * uint16_t keepalive = 60; // default value + * // Get value from property list, or keep default if not found. + * mosquitto_property_read_int16(proplist, MQTT_PROP_SERVER_KEEP_ALIVE, &keepalive, false); + * (end) + * + * Parameters: + * proplist - mosquitto_property pointer, the list of properties or single property + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to store the value, or NULL if the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. + * + * Returns: + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL. + * + * Example: + * (start code) + * // proplist is obtained from a callback + * mosquitto_property *prop; + * prop = mosquitto_property_read_byte(proplist, identifier, &value, false); + * while(prop){ + * printf("value: %s\n", value); + * prop = mosquitto_property_read_byte(prop, identifier, &value); + * } + * (end) + */ +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_byte( + const mosquitto_property *proplist, + int identifier, + uint8_t *value, + bool skip_first); + +/* + * Function: mosquitto_property_read_int16 + * + * Read an int16 property value from a property. + * + * Parameters: + * property - property to read + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to store the value, or NULL if the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. + * + * Returns: + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL. + * + * Example: + * See + */ +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_int16( + const mosquitto_property *proplist, + int identifier, + uint16_t *value, + bool skip_first); + +/* + * Function: mosquitto_property_read_int32 + * + * Read an int32 property value from a property. + * + * Parameters: + * property - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to store the value, or NULL if the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. + * + * Returns: + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL. + * + * Example: + * See + */ +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_int32( + const mosquitto_property *proplist, + int identifier, + uint32_t *value, + bool skip_first); + +/* + * Function: mosquitto_property_read_varint + * + * Read a varint property value from a property. + * + * Parameters: + * property - property to read + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to store the value, or NULL if the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. + * + * Returns: + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL. + * + * Example: + * See + */ +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_varint( + const mosquitto_property *proplist, + int identifier, + uint32_t *value, + bool skip_first); + +/* + * Function: mosquitto_property_read_binary + * + * Read a binary property value from a property. + * + * On success, value must be free()'d by the application. + * + * Parameters: + * property - property to read + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to store the value, or NULL if the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. + * + * Returns: + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL, or if an out of memory condition occurred. + * + * Example: + * See + */ +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_binary( + const mosquitto_property *proplist, + int identifier, + void **value, + uint16_t *len, + bool skip_first); + +/* + * Function: mosquitto_property_read_string + * + * Read a string property value from a property. + * + * On success, value must be free()'d by the application. + * + * Parameters: + * property - property to read + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to char*, for the property data to be stored in, or NULL if + * the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. + * + * Returns: + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL, or if an out of memory condition occurred. + * + * Example: + * See + */ +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_string( + const mosquitto_property *proplist, + int identifier, + char **value, + bool skip_first); + +/* + * Function: mosquitto_property_read_string_pair + * + * Read a string pair property value pair from a property. + * + * On success, name and value must be free()'d by the application. + * + * Parameters: + * property - property to read + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * name - pointer to char* for the name property data to be stored in, or NULL + * if the name is not required. + * value - pointer to char*, for the property data to be stored in, or NULL if + * the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. + * + * Returns: + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL, or if an out of memory condition occurred. + * + * Example: + * See + */ +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_string_pair( + const mosquitto_property *proplist, + int identifier, + char **name, + char **value, + bool skip_first); + +/* + * Function: mosquitto_property_free_all + * + * Free all properties from a list of properties. Frees the list and sets *properties to NULL. + * + * Parameters: + * properties - list of properties to free + * + * Example: + * > mosquitto_properties *properties = NULL; + * > // Add properties + * > mosquitto_property_free_all(&properties); + */ +libmosq_EXPORT void mosquitto_property_free_all(mosquitto_property **properties); + +/* + * Function: mosquitto_property_copy_all + * + * Parameters: + * dest - pointer for new property list + * src - property list + * + * Returns: + * MOSQ_ERR_SUCCESS - on successful copy + * MOSQ_ERR_INVAL - if dest is NULL + * MOSQ_ERR_NOMEM - on out of memory (dest will be set to NULL) + */ +libmosq_EXPORT int mosquitto_property_copy_all(mosquitto_property **dest, const mosquitto_property *src); + +/* + * Function: mosquitto_property_check_command + * + * Check whether a property identifier is valid for the given command. + * + * Parameters: + * command - MQTT command (e.g. CMD_CONNECT) + * identifier - MQTT property (e.g. MQTT_PROP_USER_PROPERTY) + * + * Returns: + * MOSQ_ERR_SUCCESS - if the identifier is valid for command + * MOSQ_ERR_PROTOCOL - if the identifier is not valid for use with command. + */ +libmosq_EXPORT int mosquitto_property_check_command(int command, int identifier); + + +/* + * Function: mosquitto_property_check_all + * + * Check whether a list of properties are valid for a particular command, + * whether there are duplicates, and whether the values are valid where + * possible. + * + * Note that this function is used internally in the library whenever + * properties are passed to it, so in basic use this is not needed, but should + * be helpful to check property lists *before* the point of using them. + * + * Parameters: + * command - MQTT command (e.g. CMD_CONNECT) + * properties - list of MQTT properties to check. + * + * Returns: + * MOSQ_ERR_SUCCESS - if all properties are valid + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + * MOSQ_ERR_PROTOCOL - if any property is invalid + */ +libmosq_EXPORT int mosquitto_property_check_all(int command, const mosquitto_property *properties); + +/* + * Function: mosquitto_property_identifier_to_string + * + * Return the property name as a string for a property identifier. + * The property name is as defined in the MQTT specification, with - as a + * separator, for example: payload-format-indicator. + * + * Parameters: + * identifier - valid MQTT property identifier integer + * + * Returns: + * A const string to the property name on success + * NULL on failure + */ +libmosq_EXPORT const char *mosquitto_property_identifier_to_string(int identifier); + + +/* Function: mosquitto_string_to_property_info + * + * Parse a property name string and convert to a property identifier and data type. + * The property name is as defined in the MQTT specification, with - as a + * separator, for example: payload-format-indicator. + * + * Parameters: + * propname - the string to parse + * identifier - pointer to an int to receive the property identifier + * type - pointer to an int to receive the property type + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if the string does not match a property + * + * Example: + * (start code) + * mosquitto_string_to_property_info("response-topic", &id, &type); + * // id == MQTT_PROP_RESPONSE_TOPIC + * // type == MQTT_PROP_TYPE_STRING + * (end) + */ +libmosq_EXPORT int mosquitto_string_to_property_info(const char *propname, int *identifier, int *type); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ioc/uijson/const_name.c b/ioc/uijson/const_name.c new file mode 100644 index 000000000..375edcdf3 --- /dev/null +++ b/ioc/uijson/const_name.c @@ -0,0 +1,456 @@ +#include "ioc_app.h" + +/** + * 将字符串转换为枚举值 + * @param value 要转换的字符串 + * @param enum_values 枚举字符串数组 + * @param enum_num 枚举值的数量 + * @return 如果找到匹配的字符串,返回对应的枚举值;否则返回 -1 + */ +int ioc_ui_json_string2enum(const char *value, const char **enum_values, int enum_num) +{ + for (int i = 0; i < enum_num; i++) + { + if (strcmp(value, enum_values[i]) == 0) + { + return i; // 找到匹配的字符串,返回对应的枚举值 + } + } + return -1; // 没有找到匹配的字符串 +} + +/** + * 将枚举值转换为字符串 + * @param enum_value 要转换的枚举值 + * @param enum_values 枚举字符串数组 + * @param enum_num 枚举值的数量 + * @return 如果枚举值有效,返回对应的字符串;否则返回 NULL + */ +const char *ioc_ui_json_enum2string(int enum_value, const char **enum_values, int enum_num) +{ + if (enum_value >= 0 && enum_value < enum_num) + { + return enum_values[enum_value]; // 返回对应的字符串 + } + return NULL; // 枚举值无效 +} + +const char * c_connectorName[] = +{ + "CHAdeMO", + "GBT(DC)", + "CCS1(DC)", + "GBT(AC)", + "CCS2(DC)", + "J1772(AC)", + "TYPE2(AC)", + "GBT-S(AC)", + "SAE-S(AC)", + "TYPE2-S(AC)", + "SCHUKO", + "NACS(DC)" +}; +const char * ioc_ui_json_get_conn_type_name(int type) +{ + return ioc_ui_json_enum2string(type, c_connectorName, CONN_TYPE_VALID + 1); +} + +const char *c_names_ioc_ui_state_t[UI_CONNECTOR_STATE_MAX] = { + "Idle", + "Idle", + "Starting", + "Starting", + "Charging", + "Finished", + "Reserved", + "Stopping", + "Error", + "Fault", + "Unavailable", + "Starting", + "Stopping", + "Waiting", + "Suspend", + "Starting", +}; +const char *ioc_ui_json_get_state_name(int state) +{ + return ioc_ui_json_enum2string(state, c_names_ioc_ui_state_t, UI_CONNECTOR_STATE_MAX); +} + + +// TODO 枪图标需要整理一下 +#if (COMPILER_FOR == COMPILE_FOR_DC_AM3354) +const char * ui_conn_type_img(Charger_CONNType_t connType) +{ + switch (connType) + { + case HWCFG_CONN_TYPE_CHADEMO_DC: + { + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) { + return ioc_theme_getimgpath("chademo_1connect"); + } + else if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_DUAL ) { + return ioc_theme_getimgpath("chademo_2connect"); + } + else { + return ioc_theme_getimgpath("chademo"); + } + } + case HWCFG_CONN_TYPE_GBT_DC: + { + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) { + return ioc_theme_getimgpath("gb-dc_1connect"); + } + else if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_DUAL ) { + return ioc_theme_getimgpath("gb-dc_2connect"); + } + else { + return ioc_theme_getimgpath("gb-dc"); + } + } + case HWCFG_CONN_TYPE_SAE_DC: + { + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) { + return ioc_theme_getimgpath("j1772_1connect"); + } + else if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_DUAL ) { + return ioc_theme_getimgpath("j1772_2connect"); + } + else { + return ioc_theme_getimgpath("j1772"); + } + } + case HWCFG_CONN_TYPE_GBT_AC: + { + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) { + return ioc_theme_getimgpath("gb-ac_1connect"); + } + else if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_DUAL ) { + return ioc_theme_getimgpath("gb-ac_2connect"); + } + else { + return ioc_theme_getimgpath("gb-ac"); + } + } + case HWCFG_CONN_TYPE_IEC_DC: + { + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) { + return ioc_theme_getimgpath("ccs2-dc_1connect"); + } + else if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_DUAL ) { + return ioc_theme_getimgpath("ccs2-dc_2connect"); + } + else { + return ioc_theme_getimgpath("ccs2-dc"); + } + } + case HWCFG_CONN_TYPE_SAE_AC: + case HWCFG_CONN_TYPE_IEC_AC: + case HWCFG_CONN_TYPE_GBT_AC_SOCK: + case HWCFG_CONN_TYPE_SAE_AC_SOCK: + case HWCFG_CONN_TYPE_IEC_AC_SOCK: + { + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) { + return ioc_theme_getimgpath("j1772_1connect"); + } + else if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_DUAL ) { + return ioc_theme_getimgpath("j1772_2connect"); + } + else { + return ioc_theme_getimgpath("j1772"); + } + } + case HWCFG_CONN_TYPE_SCHUKO: + { + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) { + return ioc_theme_getimgpath("europe_1connect"); + } + else if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_DUAL ) { + return ioc_theme_getimgpath("europe_2connect"); + } + else { + return ioc_theme_getimgpath("europe"); + } + } + case HWCFG_CONN_TYPE_NACS_DC: + { + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) { + return ioc_theme_getimgpath("gb-t-ac_1connect"); + } + else if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_DUAL ) { + return ioc_theme_getimgpath("gb-t-ac_2connect"); + } + else { + return ioc_theme_getimgpath("gb-t-ac"); + } + } + default: + return NULL; + } +} +#elif(COMPILER_FOR == COMPILE_FOR_AC_SSD202) +const char * ui_conn_type_img(Charger_CONNType_t connType, bool is_gun) +{ + switch (connType) + { + case HWCFG_CONN_TYPE_CHADEMO_DC: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("chademo_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("chademo_2connect"); + } + } + case HWCFG_CONN_TYPE_GBT_DC: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("gb-dc_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("gb-dc_2connect"); + } + } + case HWCFG_CONN_TYPE_SAE_DC: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("ccs1_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("ccs1_2connect"); + } + } + case HWCFG_CONN_TYPE_GBT_AC: + case HWCFG_CONN_TYPE_GBT_AC_SOCK: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("gb-ac_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("gb-ac_2connect"); + } + } + case HWCFG_CONN_TYPE_IEC_DC: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("ccs2-dc_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("ccs2-dc_2connect"); + } + } + case HWCFG_CONN_TYPE_SAE_AC: + case HWCFG_CONN_TYPE_SAE_AC_SOCK: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("j1772_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("j1772_2connect"); + } + } + case HWCFG_CONN_TYPE_IEC_AC: + case HWCFG_CONN_TYPE_IEC_AC_SOCK: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("gb-ac_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("gb-ac_2connect"); + } + } + case HWCFG_CONN_TYPE_SCHUKO: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("europe_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("europe_2connect"); + } + } + case HWCFG_CONN_TYPE_NACS_DC: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("nacs_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("nacs_2connect"); + } + } + default: + return NULL; + } +} +#else +const char * ui_conn_type_img(Charger_CONNType_t connType, bool is_gun) +{ + switch (connType) + { + case HWCFG_CONN_TYPE_CHADEMO_DC: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("chademo_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("chademo_2connect"); + } + } + case HWCFG_CONN_TYPE_GBT_DC: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("gb-dc_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("gb-dc_2connect"); + } + } + case HWCFG_CONN_TYPE_SAE_DC: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("j1772_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("j1772_2connect"); + } + } + case HWCFG_CONN_TYPE_GBT_AC: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("gb-ac_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("gb-ac_2connect"); + } + } + case HWCFG_CONN_TYPE_IEC_DC: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("ccs2-dc_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("ccs2-dc_2connect"); + } + } + case HWCFG_CONN_TYPE_SAE_AC: + case HWCFG_CONN_TYPE_IEC_AC: + case HWCFG_CONN_TYPE_GBT_AC_SOCK: + case HWCFG_CONN_TYPE_SAE_AC_SOCK: + case HWCFG_CONN_TYPE_IEC_AC_SOCK: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("j1772_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("j1772_2connect"); + } + } + case HWCFG_CONN_TYPE_SCHUKO: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("europe_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("europe_2connect"); + } + } + case HWCFG_CONN_TYPE_NACS_DC: + { + if ( is_gun == false ) { + return ioc_theme_getimgpath("gb-t-ac_1connect"); + } + else if ( is_gun == true ) { + return ioc_theme_getimgpath("gb-t-ac_2connect"); + } + } + default: + return NULL; + } +} +#endif + + +const char * c_LanguageName[] = +{ + "en-US", // 英语 + "fr-FR", // 法语 + "de-DE", // 德语 + "es-ES", // 西班牙语 + "it-IT", // 意大利语 + "pt-PT", // 葡萄牙语 + "ru-RU", // 俄语 + "", // 捷克语 + "fi-FI", // 芬兰语 + "", // 简体中文 + "zh-TW", // 繁体中文(台湾) + "", // 罗马尼亚语 + "", // 泰国语 + "", // 阿拉伯语 + "", // 土耳其语 + "pl-PL", // 波兰语 + "nl-NL", // 荷兰语 + "", // 阿尔巴尼亚语 + "", // 希伯来语 + "el-GR", // 希腊语 + "nb-NO", // 挪威语 +}; + + +const char * c_stateName_CHAdeMO[M1768_STATE_CHADEMO_NUM] ={ + "CHADEMO_IDLE", + "CHADEMO_START", + "CHADEMO_INFORMATION_EXCHANGE", + "CHADEMO_LOCK", + "CHADEMO_PREPARING", + "CHADEMO_CHARGING", + "CHADEMO_BEGIN_TERM", + "CHADEMO_TERMING", + "CHADEMO_UNLOCK", + "CHADEMO_END", + "CHADEMO_FAULT", +}; +const char * c_stateName_GBT[M1768_STATE_GBT_NUM] ={ + "GBT_IDLE", + "GBT_START", + "GBT_SELFCHECK", + "GBT_HANDSHAKE", + "GBT_PRRAMETER", + "GBT_CHARGING", + "GBT_STARTTERMING", + "GBT_TERMING", + "GBT_END", + "GBT_FAULT", +}; +const char * c_stateName_CCS[M1768_STATE_GBT_NUM] ={ + "CCS_IDLE", + "CCS_START", + "CCS_SELFCHECK", + "CCS_HANDSHAKE", + "CCS_PRRAMETER", + "CCS_CHARGING", + "CCS_STARTTERMING", + "CCS_TERMING", + "CCS_END", + "CCS_FAULT", +}; + + + +const char * const ioc_ui_connector_state_str[UI_CONNECTOR_STATE_MAX] = { + [UI_CONNECTOR_STATE_HOME] = "HOME", + [UI_CONNECTOR_STATE_IDLE] = "IDLE", + [UI_CONNECTOR_STATE_STARTING1] = "STARTING1", + [UI_CONNECTOR_STATE_STARTING2] = "STARTING2", + [UI_CONNECTOR_STATE_CHARGING] = "CHARGING", + [UI_CONNECTOR_STATE_FINISHED] = "FINISHED", + [UI_CONNECTOR_STATE_RESERVED] = "RESERVED", + [UI_CONNECTOR_STATE_SESSION_ERROR] = "SESSION_ERROR", + [UI_CONNECTOR_STATE_START_ERROR] = "START_ERROR", + [UI_CONNECTOR_STATE_FAULT] = "FAULT", + [UI_CONNECTOR_STATE_UNAVAILABLE] = "UNAVAILABLE", + [UI_CONNECTOR_STATE_CONNECTING] = "CONNECTING", + [UI_CONNECTOR_STATE_STOPPING] = "STOPPING", + [UI_CONNECTOR_STATE_WAIT_IN_LINE] = "WAIT_IN_LINE", + [UI_CONNECTOR_STATE_SUSPEND] = "SUSPEND", + [UI_CONNECTOR_STATE_PROCESSING] = "PROCESSING", +}; diff --git a/ioc/uijson/const_name.h b/ioc/uijson/const_name.h new file mode 100644 index 000000000..c68e93759 --- /dev/null +++ b/ioc/uijson/const_name.h @@ -0,0 +1,83 @@ +#ifndef __CONST_NAME_H__ +#define __CONST_NAME_H__ + + +typedef enum Charger_CONNType_e +{ + HWCFG_CONN_TYPE_CHADEMO_DC = 0, + HWCFG_CONN_TYPE_GBT_DC = 1, + HWCFG_CONN_TYPE_SAE_DC = 2, + HWCFG_CONN_TYPE_GBT_AC = 3, + HWCFG_CONN_TYPE_IEC_DC = 4, + HWCFG_CONN_TYPE_SAE_AC = 5, + HWCFG_CONN_TYPE_IEC_AC = 6, + HWCFG_CONN_TYPE_GBT_AC_SOCK = 7, + HWCFG_CONN_TYPE_SAE_AC_SOCK = 8, + HWCFG_CONN_TYPE_IEC_AC_SOCK = 9, + HWCFG_CONN_TYPE_SCHUKO = 10, // 欧标单相插座, 由于控制逻辑完全相同, 如果使用英式或美式不再另行使用枚举, 借用本枚举 + HWCFG_CONN_TYPE_NACS_DC = 11, // 特斯拉直流充电接口,控制逻辑与CCS2相同 + HWCFG_CONN_TYPE_INVALID = 0xF +} Charger_CONNType_t; + +#define CONN_TYPE_VALID (HWCFG_CONN_TYPE_NACS_DC) + +typedef enum +{ + LANG_EN = 0, // 英语 + LANG_FR, // 法语 + LANG_DE, // 德语 + LANG_ES, // 西班牙语 + LANG_IT, // 意大利语 + LANG_PT, // 葡萄牙语 + LANG_RU, // 俄语 + LANG_CZ, // 捷克语 + LANG_FI, // 芬兰语 + LANG_ZH_CN, // 简体中文 + LANG_ZH_TW, // 繁体中文(台湾) + LANG_RO, // 罗马尼亚语 + LANG_TH, // 泰国语 + LANG_AR, // 阿拉伯语 + LANG_TU, // 土耳其语 + LANG_PL, // 波兰语 + LANG_NL, // 荷兰语 + LANG_SQ, // 阿尔巴尼亚语 + LANG_HE, // 希伯来语 + LANG_GR, // 希腊语 (DC暂时未使用) + LANG_LT, // 立陶宛语 + LANG_HBC, // HBC客户定制葡萄牙语 + LANG_BG, // 保加利亚语 + + LANG_NUM, +} Language_t; + +/** + * 将字符串转换为枚举值 + * @param value 要转换的字符串 + * @param enum_values 枚举字符串数组 + * @param enum_num 枚举值的数量 + * @return 如果找到匹配的字符串,返回对应的枚举值;否则返回 -1 + */ +int ioc_ui_json_string2enum(const char* value, const char** enum_values, int enum_num); + +/** + * 将枚举值转换为字符串 + * @param enum_value 要转换的枚举值 + * @param enum_values 枚举字符串数组 + * @param enum_num 枚举值的数量 + * @return 如果枚举值有效,返回对应的字符串;否则返回 NULL + */ +const char* ioc_ui_json_enum2string(int enum_value, const char** enum_values, int enum_num); + +const char * ioc_ui_json_get_conn_type_name(int type); +const char * ioc_ui_json_get_state_name(int state); + +#if (COMPILER_FOR == COMPILE_FOR_DC_AM3354) +const char * ui_conn_type_img(Charger_CONNType_t connType); +#else +const char * ui_conn_type_img(Charger_CONNType_t connType, bool is_gun); +#endif + +extern const char *c_LanguageName[]; +extern const char * const ioc_ui_connector_state_str[]; + +#endif diff --git a/ioc/uijson/ui_json.c b/ioc/uijson/ui_json.c new file mode 100644 index 000000000..1a06deacc --- /dev/null +++ b/ioc/uijson/ui_json.c @@ -0,0 +1,2143 @@ +#include "ioc_app.h" +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#include +#else +#include +#endif +#include +#ifndef _WIN32 +#include +#endif +#include +#ifndef _WIN32 +#include +#endif +#include + +ioc_ui_json_t g_ui_json; +static bool s_ui_json_changed = false; +static int s_point_temp = -50; // 环境温度最大值 + +static int s_ui_json_sockfd = -1; +char g_ui_json_buffer[UI_JSON_BUFFER_SIZE]; +static char s_devMasterIp[INET_ADDRSTRLEN] = {0}; + +int g_ui_json_eventfd = -1; + +void ioc_send_udp(char * pt, int length) +{ + if (s_ui_json_sockfd > 0) + { + struct sockaddr_in ser_addr; // + memset(&ser_addr, 0, sizeof(ser_addr)); + ser_addr.sin_family = AF_INET; + +#if (COMPILER_FOR == COMPILE_FOR_CABINET_SSD202) + ser_addr.sin_addr.s_addr = inet_addr("192.168.10.1"); // 注意网络序转换 +#elif (COMPILER_FOR == COMPILE_FOR_AC_SSD202) + if (strlen(s_devMasterIp) == 0) + { + LV_LOG_WARN("No valid target IP, cannot send UDP packet"); + return; + } + ser_addr.sin_addr.s_addr = inet_addr(s_devMasterIp); +#else + ser_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 注意网络序转换 +#endif + + ser_addr.sin_port = htons(SENDUI_AM3354_SRC_PORT); // 发往3354的端口号, 注意网络序转换 + + socklen_t len = sizeof(struct sockaddr); + size_t sent = sendto(s_ui_json_sockfd, pt, length, 0, (struct sockaddr *)&ser_addr, len); + if (sent != length) + { + LV_LOG_ERROR("sendto failed: sent=%ld expected=%d, errno=%d (%s)", sent, length, errno, strerror(errno)); + } + } + else + { + LV_LOG_ERROR("Socket Error"); + } + + return; +} + +void ioc_send_ConnSelected(int idx) +{ + char buf[128] = {0}; + +#if ((COMPILER_FOR == COMPILE_FOR_CABINET_AM3354) || (COMPILER_FOR == COMPILE_FOR_CABINET_SSD202)) + snprintf(buf, sizeof(buf), "{\""UIMSG_ACTIVE_IDX"\":%d}", g_ui_json.dispenserConfig.connIdx[idx]); +#else + snprintf(buf, sizeof(buf), "{\""UIMSG_ACTIVE_IDX"\":%d}", idx); +#endif + + LV_LOG_WARN("activeIdx SEND BUFF[%s]", buf); + + // ioc_mqtt_publish(idx, PUBLISH_UI, buf); + ioc_send_udp(buf, strlen(buf)); +} + +void ioc_send_UseCreditCard(int idx, int PerAuth) +{ + char buf[128] = {0}; + +#if ((COMPILER_FOR == COMPILE_FOR_CABINET_AM3354) || (COMPILER_FOR == COMPILE_FOR_CABINET_SSD202)) + // sprintf(connSelect, "{\""UIMSG_USE_CREDITCARD"\":%d}", idx); + snprintf(buf, sizeof(buf), "{\""UIMSG_USE_CREDITCARD"\":%d,\""PREAUTH_AMOUNT"\":%d}", g_ui_json.dispenserConfig.connIdx[idx], PerAuth); + // ioc_mqtt_publish(idx, PUBLISH_UI, buf); +#else + snprintf(buf, sizeof(buf), "{\""UIMSG_USE_CREDITCARD"\":%d,\""PREAUTH_AMOUNT"\":%d}", idx, PerAuth); +#endif + + LV_LOG_WARN("UseCreditCard SEND BUFF[%s]", buf); + ioc_send_udp(buf, strlen(buf)); +} + +void ioc_send_StopPlugCharging(int idx) +{ + char buf[128] = {0}; + +#if ((COMPILER_FOR == COMPILE_FOR_CABINET_AM3354) || (COMPILER_FOR == COMPILE_FOR_CABINET_SSD202)) + snprintf(buf, sizeof(buf), "{\""STOP_PLUG_CHARGING"\":%d}", g_ui_json.dispenserConfig.connIdx[idx]); +#else + snprintf(buf, sizeof(buf), "{\""STOP_PLUG_CHARGING"\":%d}", idx); +#endif + + LV_LOG_WARN("StopPlugCharging SEND BUFF[%s]", buf); + ioc_send_udp(buf, strlen(buf)); +} + +void ioc_send_StartCharging(int idx) +{ + char buf[128] = {0}; + +#if ((COMPILER_FOR == COMPILE_FOR_CABINET_AM3354) || (COMPILER_FOR == COMPILE_FOR_CABINET_SSD202)) + snprintf(buf, sizeof(buf), "{\""START_CHARGING"\":%d}", g_ui_json.dispenserConfig.connIdx[idx]); +#else + snprintf(buf, sizeof(buf), "{\""START_CHARGING"\":%d}", idx); +#endif + + LV_LOG_WARN("StartPlugCharging SEND BUFF[%s]", buf); + + ioc_send_udp(buf, strlen(buf)); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +const UI_CurrencyMap_t c_CurrencyMaps[] = +{ + {CURRENCY_USD, "USD", "$"}, + {CURRENCY_GBP, "GBP", "£"}, + {CURRENCY_EUR, "EUR", "€"}, + {CURRENCY_RUB, "RUB", "₽"}, + {CURRENCY_CNY, "CNY", "¥"}, + {CURRENCY_SEK, "SEK", "Kr"}, + {CURRENCY_PLN, "PLN", "zł"}, +}; + +// 软件开关功能 +typedef struct +{ + bool lcdIdleOnRF; + bool lcdIdleShowWelcome; + +}SwFunc_t; + +static SwFunc_t sw_Func = {0}; + +#define FUNC_LCD_IDLE_ONRF sw_Func.lcdIdleOnRF // 空闲状态下是否显示刷卡 0显示请插枪 +#define FUNC_LCD_IDLE_SHOW_WELCOME sw_Func.lcdIdleShowWelcome // 未激活返回welcome界面 + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static void SwFuncCheck(uint32_t func) +{ + if(func & (1 << 0)) + { + FUNC_LCD_IDLE_ONRF = true; + } + + if(func & (1 << 13)) + { + FUNC_LCD_IDLE_SHOW_WELCOME = true; + } +} + +void Check_1768(uint8_t idx) +{ + Starting_SubStep_t sub; + uint8_t StateMaxNum, state, type; + char **pCharSta = NULL; + + Charger_CONNType_t ConnType = g_ui_json.connectors[idx].conn_type; + const char *state1768 = g_ui_json.connectors[idx].m1768Info_runState; + uint8_t sub1768 = g_ui_json.connectors[idx].subState; + + switch (ConnType) + { + case HWCFG_CONN_TYPE_CHADEMO_DC: + StateMaxNum = M1768_STATE_CHADEMO_NUM; + pCharSta = (char**)&c_stateName_CHAdeMO; + type = 0; + break; + case HWCFG_CONN_TYPE_GBT_DC: + StateMaxNum = M1768_STATE_GBT_NUM; + pCharSta = (char**)&c_stateName_GBT; + type = 1; + break; + case HWCFG_CONN_TYPE_SAE_DC: + case HWCFG_CONN_TYPE_IEC_DC: + case HWCFG_CONN_TYPE_NACS_DC: + StateMaxNum = M1768_STATE_GBT_NUM; + pCharSta = (char**)&c_stateName_CCS; + type = 2; + break; + default: + LV_LOG_WARN("Invalid connection type[%d]", ConnType); + return; + break; + } + + for (state = 0; state < StateMaxNum; state++) + { + if (strcmp(pCharSta[state], state1768) == 0) + { + break; + } + } + + if (type == 0) // chademo + { + if (state == M1768_STATE_CHADEMO_START) + { + + sub = STARTING_HANDSHAKE; + } + else if (state == M1768_STATE_CHADEMO_INFORMATION_EXCHANGE) + { + if (sub1768 <= 2) + { + sub = STARTING_HANDSHAKE; + } + else + { + sub = STARTING_PARAMTETER; + } + } + else if (state == M1768_STATE_CHADEMO_LOCK) + { + sub = STARTING_INSULATION; + } + else if (state == M1768_STATE_CHADEMO_PREPARING) + { + sub = STARTING_PRECHARGE; + } + } + else if (type == 1) // GBT + { + if (state == M1768_STATE_GBT_START) + { + sub = STARTING_HANDSHAKE; + } + else if (state == M1768_STATE_GBT_SELF_CHECK) + { + sub = STARTING_HANDSHAKE; + } + else if (state == M1768_STATE_GBT_HANDSHAKE) + { + switch (sub1768) + { + case GBT_SHAKEHANDS_INSU: sub = STARTING_INSULATION; break; + + case GBT_SHAKEHANDS_WAIT_BRM: + case GBT_SHAKEHANDS_WAIT_BCP: sub = STARTING_PARAMTETER; break; + + case GBT_SHAKEHANDS_WAIT_BHM: + default: sub = STARTING_HANDSHAKE; break; + } + } + else if (state == M1768_STATE_GBT_PRRAMETER) + { + switch (sub1768) + { + case GBT_PRECHARGE_CHKBAT: + case GBT_PRECHARGE_WAIT_BCS: + case GBT_PRECHARGE_WAIT_K1K2: sub = STARTING_PRECHARGE; break; + + case GBT_PRECHARGE_WAIT_BRO: + default: sub = STARTING_PARAMTETER; break; + } + } + } + else if (type == 2) // RNL + { + if (state == M1768_STATE_GBT_START) + { + sub = STARTING_HANDSHAKE; + } + else if (state == M1768_STATE_GBT_SELF_CHECK) + { + sub = STARTING_HANDSHAKE; + } + else if (state == M1768_STATE_GBT_HANDSHAKE) + { + switch (sub1768) + { + case RNL_SHAKEHANDS_INSU: sub = STARTING_INSULATION; break; + + case RNL_SHAKEHANDS_WAIT_BRM: + case RNL_SHAKEHANDS_WAIT_BCP: sub = STARTING_PARAMTETER; break; + + case RNL_SHAKEHANDS_WAIT_BHM: + default: sub = STARTING_HANDSHAKE; break; + } + } + else if (state == M1768_STATE_GBT_PRRAMETER) + { + switch (sub1768) + { + case RNL_PRECHARGE_WAIT_BRO: sub = STARTING_PARAMTETER; break; + + case RNL_PRECHARGE_INSU: sub = STARTING_INSULATION; break; + + case RNL_PRECHARGE_WAIT_BCL: + case RNL_PRECHARGE_WAIT_K1K2: + case RNL_PRECHARGE_WAIT_BCS: + default: sub = STARTING_PRECHARGE; break; + } + } + else // AC + { + sub = STARTING_AC; + } + } + + g_ui_json.connectors[idx].startingSubStep = sub; +} + + +ioc_ui_connector_state_t ui_page_status_judgment(uint8_t gun_idx) +{ + // LV_LOG_WARN("idx[%d] _status_real[%s]", gun_idx, g_ui_json.connectors[gun_idx]._status_real); + + // 测试用 + return UI_CONNECTOR_STATE_STARTING2; + + // start error + if(g_ui_json.connectors[gun_idx].conn_type == HWCFG_CONN_TYPE_SAE_DC) + { + uint16_t m1768errCode = g_ui_json.connectors[gun_idx].m1768errCode; + if((m1768errCode >= 12 && m1768errCode <= 16) || + (m1768errCode >= 151 && m1768errCode <= 155)) + { + return UI_CONNECTOR_STATE_START_ERROR; + } + } + + const char *status = g_ui_json.connectors[gun_idx]._status_real; + const char *conn = g_ui_json.connectors[gun_idx].connStatus; + + // 先判断 _status_real + if ( strcmp(g_ui_json.connectors[gun_idx]._status_real, "Available") == 0 || + strcmp(g_ui_json.connectors[gun_idx]._status_real, "Preparing") == 0 ) + { + +#if (COMPILER_FOR == COMPILE_FOR_AC_SSD202 || COMPILER_FOR == COMPILE_FOR_SSD202_43) // 交流桩有空闲时显示刷卡界面功能按钮 + if(strcmp(g_ui_json.connectors[gun_idx]._status_real,"Available") == 0) + { + if(FUNC_LCD_IDLE_ONRF) + { + // 判断是否启用POS机 + if(UI_ENABLEPOS) + { + return UI_CONNECTOR_STATE_STARTING2; + } + + return UI_CONNECTOR_STATE_STARTING1; + } + + return UI_CONNECTOR_STATE_IDLE; + } +#endif + // 判断是否插枪 + if ( strcmp(g_ui_json.connectors[gun_idx].connStatus, "Unplug") == 0) + { + return UI_CONNECTOR_STATE_IDLE; + } + else + { + // TODO 未授权跳转到刷卡界面,12Connecting授权失败也可能跳到这个界面,要添加字段 + // if(strcmp(g_ui_json.connectors[gun_idx].idTag, "") == 0) + + // 判断是否启用POS机 + if(UI_ENABLEPOS) + { + return UI_CONNECTOR_STATE_STARTING2; + } + + return UI_CONNECTOR_STATE_STARTING1; + } + } + else if(strcmp(g_ui_json.connectors[gun_idx]._status_real, "SuspendedEVSE") == 0 || + strcmp(g_ui_json.connectors[gun_idx]._status_real, "SuspendedEV") == 0) + { + return UI_CONNECTOR_STATE_SUSPEND; + + } + else if(strcmp(g_ui_json.connectors[gun_idx]._status_real, "Reserved") == 0) + { + return UI_CONNECTOR_STATE_RESERVED; + } + else if(strcmp(g_ui_json.connectors[gun_idx]._status_real, "Unavailable") == 0) + { + return UI_CONNECTOR_STATE_UNAVAILABLE; + } + else if(strcmp(g_ui_json.connectors[gun_idx]._status_real, "Faulted") == 0) + { + return UI_CONNECTOR_STATE_FAULT; + } + else if(strcmp(g_ui_json.connectors[gun_idx]._status_real, "Finishing") == 0) + { + return UI_CONNECTOR_STATE_FINISHED; + } + else if(strcmp(g_ui_json.connectors[gun_idx]._status_real, "Charging") == 0) + { + // PnC/Auto + if( strcmp(g_ui_json.connectors[gun_idx].idTag, "CCSPLUGCHARGE") == 0 ) + { + return UI_CONNECTOR_STATE_CONNECTING; + } + + // Idle + if((strcmp(g_ui_json.connectors[gun_idx].stateMngrInfo_runState, "Idle") == 0) + || (strcmp(g_ui_json.connectors[gun_idx].stateMngrInfo_runState, "Carbin") == 0)) + { + return UI_CONNECTOR_STATE_IDLE; + } + + // 判断是否等待轮充 + if( strcmp(g_ui_json.connectors[gun_idx].stateMngrInfo_runState, "ReqRes") == 0) + { +#if ( COMPILER_FOR == COMPILE_FOR_SSD202_43) // 交流桩跳过WAIT_IN_LINE界面 + return UI_CONNECTOR_STATE_CHARGING; +#else + return UI_CONNECTOR_STATE_WAIT_IN_LINE; +#endif + } + + // Suspend + if((strcmp(g_ui_json.connectors[gun_idx].stateMngrInfo_runState, "SuspendEVSE") == 0) + || (strcmp(g_ui_json.connectors[gun_idx].stateMngrInfo_runState, "SuspendEV") == 0)) + { + return UI_CONNECTOR_STATE_SUSPEND; + } + + // Finishd + if( strcmp(g_ui_json.connectors[gun_idx].stateMngrInfo_runState, "Finished") == 0) + { + return UI_CONNECTOR_STATE_FINISHED; + } + + // Fault + if( strcmp(g_ui_json.connectors[gun_idx].stateMngrInfo_runState, "Fault") == 0) + { + return UI_CONNECTOR_STATE_FAULT; + } + + // Stop + if( strcmp(g_ui_json.connectors[gun_idx].stateMngrInfo_runState, "Finishing") == 0) + { + // Stop + uint8_t stop_code = g_ui_json.connectors[gun_idx].stopCode; + uint8_t conn_type = g_ui_json.connectors[gun_idx].conn_type; + uint8_t threshold = 0; + + switch (conn_type) + { + case HWCFG_CONN_TYPE_CHADEMO_DC: + case HWCFG_CONN_TYPE_GBT_DC: + case HWCFG_CONN_TYPE_SAE_DC: + case HWCFG_CONN_TYPE_IEC_DC: + case HWCFG_CONN_TYPE_NACS_DC: + threshold = 9; + break; + case HWCFG_CONN_TYPE_GBT_AC: + case HWCFG_CONN_TYPE_SAE_AC: + case HWCFG_CONN_TYPE_IEC_AC: + case HWCFG_CONN_TYPE_GBT_AC_SOCK: + case HWCFG_CONN_TYPE_SAE_AC_SOCK: + case HWCFG_CONN_TYPE_IEC_AC_SOCK: + case HWCFG_CONN_TYPE_SCHUKO: + threshold = 2; + break; + default: + threshold = 0; + break; + } + + if(stop_code > threshold) + { + return UI_CONNECTOR_STATE_SESSION_ERROR; + } + + return UI_CONNECTOR_STATE_STOPPING; + } + + if((strcmp(g_ui_json.connectors[gun_idx].stateMngrInfo_runState, "Starting") == 0) + || (strcmp(g_ui_json.connectors[gun_idx].stateMngrInfo_runState, "Charging") == 0)) + { + +#if (COMPILER_FOR == COMPILE_FOR_AC_SSD202 || COMPILER_FOR == COMPILE_FOR_SSD202_43) // 交流桩跳过processing界面 + return UI_CONNECTOR_STATE_CHARGING; +#endif + // Processing + const char *processStates[] = { + "CHADEMO_START", + "CHADEMO_INFORMATION_EXCHANGE", + "CHADEMO_LOCK", + "CHADEMO_PREPARING", + "GBT_START", + "GBT_SELFCHECK", + "GBT_HANDSHAKE", + "GBT_PRRAMETER", + "GBT_HANDSHAKE", + "CCS_START", + "CCS_SELFCHECK", + "CCS_HANDSHAKE", + "CCS_PRRAMETER", + "AC_Idle", + "AC_Lock", + "AC_WaitS2", + "AC_K1K2ON", + "AC_UserStop", + }; + const int numStates = sizeof(processStates) / sizeof(processStates[0]); + for (int i = 0; i < numStates; i++) + { + if (strcmp(g_ui_json.connectors[gun_idx].m1768Info_runState, processStates[i]) == 0) + { + // 判断子状态 + Check_1768(gun_idx); + return UI_CONNECTOR_STATE_PROCESSING; + } + } + + // Charging + if((strstr(g_ui_json.connectors[gun_idx].m1768Info_runState, "_CHARGING") != NULL) || + (strcmp(g_ui_json.connectors[gun_idx].m1768Info_runState, "AC_Charging") == 0)) + { + return UI_CONNECTOR_STATE_CHARGING; + } + } + } + else + { + return UI_CONNECTOR_STATE_HOME; + } + + return UI_CONNECTOR_STATE_HOME; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static bool ioc_ui_json_set_sign_currency(const char *currency) +{ + // 参数保护 + if (currency == NULL) + return false; + + // 如果 code 相同,不更新 + if (strcmp(g_ui_json.currencyCode, currency) == 0) + return false; + + // 遍历已知币种映射表 + for (int i = 0; i < CURRENCY_NUM; i++) + { + if (strcmp(c_CurrencyMaps[i].code, currency) == 0) + { + const char *newIcon = c_CurrencyMaps[i].icon; + + // 更新 code + strncpy(g_ui_json.currencyCode, currency, 3); + g_ui_json.currencyCode[3] = '\0'; + + // 更新 icon + strncpy(g_ui_json.currencyIcon, newIcon, sizeof(g_ui_json.currencyIcon) - 1); + g_ui_json.currencyIcon[sizeof(g_ui_json.currencyIcon) - 1] = '\0'; + + return true; + } + } + + // 币种未知:清空 code + icon + bool changed = false; + + if (g_ui_json.currencyCode[0] != '\0') + { + g_ui_json.currencyCode[0] = '\0'; + changed = true; + } + + if (g_ui_json.currencyIcon[0] != '\0') + { + g_ui_json.currencyIcon[0] = '\0'; + changed = true; + } + + return changed; +} + +static bool ioc_ui_json_set_sign_costPriceDecimalPlaces(uint8_t decimalPlaces) +{ + if(g_ui_json.costPriceDecimalPlaces != decimalPlaces) + { + g_ui_json.costPriceDecimalPlaces = decimalPlaces; + return true; + } + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool ioc_ui_json_set_con_num(int num) +{ + // num = 1; // TODO: remove this line + if ((g_ui_json.connector_num == 0) && g_ui_json.connector_num != num) // 枪号只允许修改1次 + { + LV_LOG_WARN("connector_num %d->%d", g_ui_json.connector_num, num); + g_ui_json.connector_num = num; + return true; + } + + return false; +} + +static bool ioc_ui_json_set_con_type(int idx, const char *type_str) +{ + if (type_str == NULL) return false; + if (idx >= UI_NUMOFCONNECTOR) return false; + + const char * c_connectorName[] = + { + "CHAdeMO", + "GBT(DC)", + "CCS1(DC)", + "GBT(AC)", + "CCS2(DC)", + "J1772(AC)", + "TYPE2(AC)", + "GBT-S(AC)", + "SAE-S(AC)", + "TYPE2-S(AC)", + "SCHUKO", + "NACS(DC)" + }; + for (int i = 0; i < sizeof(c_connectorName) / sizeof(c_connectorName[0]); i++) + { + if (strcmp(type_str, c_connectorName[i]) == 0) + { + if (g_ui_json.connectors[idx].conn_type != i) + { + // LV_LOG_WARN("[%d]type %d->%d", idx, g_ui_json.connectors[idx].conn_type, i); + g_ui_json.connectors[idx].conn_type = i; + return true; + } + } + } + + return false; +} + + +static inline const char * ioc_ui_connector_state_to_str(ioc_ui_connector_state_t state) +{ + if (state >= 0 && state < UI_CONNECTOR_STATE_MAX && + ioc_ui_connector_state_str[state] != NULL) { + return ioc_ui_connector_state_str[state]; + } + return "UNKNOWN"; +} + +bool ioc_ui_json_set_conn_state(int idx, ioc_ui_connector_state_t state) +{ + // #if(COMPILER_FOR==COMPILE_FOR_SSD202_43) + // g_ui_json.connectors[idx].state = state; + // #endif + if (idx >= UI_NUMOFCONNECTOR) return false; + + +// TODO 本功能是印尼客户定制,后续在印尼客户补丁处体现 +// #if((COMPILER_FOR!=COMPILE_FOR_AC_SSD202) && (COMPILER_FOR!=COMPILE_FOR_SSD202_43)) + +// if ( UI_CONNECTOR_STATE(idx) == UI_CONNECTOR_STATE_SESSION_ERROR || +// UI_CONNECTOR_STATE(idx) == UI_CONNECTOR_STATE_START_ERROR ) +// { +// if ( g_ui_json.isUiJsonControlLocked[idx] == true ) return false; +// g_ui_json.isUiJsonControlLocked[idx] = true; +// } +// #endif + // if (idx == 0) state = 14; // TODO: remove this line + + if (g_ui_json.connectors[idx].state != state) + { + LV_LOG_WARN("[UI] connector[%d] state: %d(%s) -> %d(%s)\n", idx, g_ui_json.connectors[idx].state, + ioc_ui_connector_state_to_str(g_ui_json.connectors[idx].state), state, ioc_ui_connector_state_to_str(state)); + g_ui_json.connectors[idx].state = state; + return true; + } + + // LV_LOG_WARN("[%d].state:%d", idx, g_ui_json.connectors[idx].state); + return false; +} + +static bool ioc_ui_json_set_con_rated_power(int idx, int rated_power) +{ + if (idx >= UI_NUMOFCONNECTOR) return false; + + if (g_ui_json.connectors[idx].rated_power != rated_power) + { + // LV_LOG_WARN("[%d]rated_power %d->%d", idx, g_ui_json.connectors[idx].rated_power, rated_power); + g_ui_json.connectors[idx].rated_power = rated_power; + return true; + } + + return false; +} + + +static bool ioc_ui_json_set_con_stop_code(int idx, int code) +{ + if (idx >= UI_NUMOFCONNECTOR) return false; + + if (g_ui_json.connectors[idx].stopCode != code) + { + LV_LOG_WARN("[%d]stopCode %d->%d", idx, g_ui_json.connectors[idx].stopCode, code); + g_ui_json.connectors[idx].stopCode = code; + return true; + } + + return false; +} + +static bool ioc_ui_json_set_m1768_err_code(int idx, int code) +{ + if (idx >= UI_NUMOFCONNECTOR) return false; + + if (g_ui_json.connectors[idx].m1768errCode != code) + { + // LV_LOG_WARN("[%d]m1768errCode %d->%d", idx, g_ui_json.connectors[idx].m1768errCode, code); + g_ui_json.connectors[idx].m1768errCode = code; + return true; + } + + return false; +} + + + + +static bool ioc_ui_json_set_string(int idx, const char *str, char *dest_field, size_t dest_size, const char *field_name) +{ + if (str == NULL) return false; + if (idx >= UI_NUMOFCONNECTOR) return false; + + if (strcmp(str, dest_field) != 0) + { + // DEBUG_INFO("[%d]%s %s->%s", idx, field_name, dest_field, str); + snprintf(dest_field, dest_size, "%s", str); + return true; + } + + return false; +} + +static bool ioc_ui_json_set_con_m1768_runstate(int idx, const char *state_str) +{ + return ioc_ui_json_set_string(idx, state_str, + g_ui_json.connectors[idx].m1768Info_runState, + sizeof(g_ui_json.connectors[idx].m1768Info_runState), + "m1768_runstate"); +} + +static bool ioc_ui_json_set_con_m1768_connstatus(int idx, const char *state_str) +{ + return ioc_ui_json_set_string(idx, state_str, + g_ui_json.connectors[idx].connStatus, + sizeof(g_ui_json.connectors[idx].connStatus), + "m1768_connstatus"); +} + +static bool ioc_ui_json_set_con_statemng_runstate(int idx, const char *state_str) +{ + return ioc_ui_json_set_string(idx, state_str, + g_ui_json.connectors[idx].stateMngrInfo_runState, + sizeof(g_ui_json.connectors[idx].stateMngrInfo_runState), + "statemng_runstate"); +} + +static bool ioc_ui_json_set_con_status_real(int idx, const char *state_str) +{ + bool Breturn=ioc_ui_json_set_string(idx, state_str, + g_ui_json.connectors[idx]._status_real, + sizeof(g_ui_json.connectors[idx]._status_real), + "status_real"); + return Breturn; +} + +static bool ioc_ui_json_set_con_errcode(int idx, const char *errcode) +{ + // LV_LOG_WARN("idx[%d]===errcode %s", idx, errcode); + return ioc_ui_json_set_string(idx, errcode, + g_ui_json.connectors[idx]._errCode, + sizeof(g_ui_json.connectors[idx]._errCode), + "errcode"); +} + +static bool ioc_ui_json_set_con_qrcode(int idx, const char *qrcode) +{ + return ioc_ui_json_set_string(idx, qrcode, + g_ui_json.connectors[idx].state_data.starting.connQR, + sizeof(g_ui_json.connectors[idx].state_data.starting.connQR), + "qrcode"); +} + +static bool ioc_ui_json_set_idTag(int idx, const char *idTag) +{ + return ioc_ui_json_set_string(idx, idTag, + g_ui_json.connectors[idx].idTag, + sizeof(g_ui_json.connectors[idx].idTag), + "idTag"); +} + +static bool ioc_ui_json_set_httpAddr(int idx, const char *httpAddr_str) +{ + return ioc_ui_json_set_string(idx, httpAddr_str, + g_ui_json.drvPointInfo.httpAddr, + sizeof(g_ui_json.drvPointInfo.httpAddr), + "httpAddr"); +} + +static bool ioc_ui_json_set_idType(int idx, IdTagType_t idType) +{ + if (idx >= UI_NUMOFCONNECTOR) return false; + + if (g_ui_json.connectors[idx].idType != idType) + { + // LV_LOG_WARN("[%d]m1768errCode %d->%d", idx, g_ui_json.connectors[idx].m1768errCode, code); + g_ui_json.connectors[idx].idType = idType; + return true; + } + + return false; +} + +static bool ioc_ui_json_set_con_code(int idx, const char *idTag) +{ + return ioc_ui_json_set_string(idx, idTag, + g_ui_json.connectors[idx].connCode, + sizeof(g_ui_json.connectors[idx].connCode), + "connCode"); +} + +static bool ioc_ui_json_set_timeZone(uint8_t timeZone) +{ + if (g_ui_json.timeZone != timeZone) + { + LV_LOG_WARN("timeZone %d->%d", g_ui_json.timeZone, timeZone); + g_ui_json.timeZone = timeZone; + return true; + } + + return false; +} + +// 更新激活时间,如果大于当前激活时间,则更新,另外在触摸处理时也会跟新这时间戳 +static void ioc_ui_json_set_activeTime(time_t activeTime) +{ + if(activeTime > g_ui_json.biright.activeTime) + { + g_ui_json.biright.activeTime = activeTime; + } + + return; +} + +static bool ioc_ui_json_set_price(UI_PriceInfo_t* old, UI_PriceInfo_t* new) +{ + if (memcmp(old, new, sizeof(UI_PriceInfo_t)) != 0) + { + // 不相同则整体赋值 + *old = *new; + return true; + } + return false; +} + +static bool ioc_ui_json_set_meterdata(UI_MeterData_t* old, UI_MeterData_t* new) +{ + if (memcmp(old, new, sizeof(UI_MeterData_t)) != 0) + { + // 不相同则整体赋值 + *old = *new; + return true; + } + return false; +} +static bool ioc_ui_json_set_u8(uint8_t* old, uint8_t* new) +{ + if (* old != * new) + { + *old = *new; + return true; + } + return false; +} + +static bool ioc_ui_json_set_int(int* old, int* new) +{ + if (* old != * new) + { + *old = *new; + return true; + } + return false; +} + + +static bool ioc_ui_json_set_con_m1768_subState(int idx, uint8_t subState) +{ + if (idx >= UI_NUMOFCONNECTOR) return false; + + if (g_ui_json.connectors[idx].subState != subState) + { + g_ui_json.connectors[idx].subState = subState; + return true; + } + + return false; +} + +static bool ioc_ui_json_set_sever_time(time_t new) +{ + time_t local_now = time(NULL); + double diff = difftime(new, local_now); + + // 若服务器时间与本地时间差超过2秒,则同步本地时间 + if (diff > 2 || diff < -2) + { +#ifdef _WIN32 + LV_LOG_WARN("[TIME SYNC] settimeofday is not supported on Windows build"); +#else + struct timeval tv; + tv.tv_sec = new; + tv.tv_usec = 0; + + if (settimeofday(&tv, NULL) == 0) + { + LV_LOG_USER("[TIME SYNC] Local time adjusted to server time (%ld)\n", new); + } + else + { + LV_LOG_WARN("[TIME SYNC] settimeofday failed"); + } +#endif + } + + return false; +} + +static bool ioc_ui_json_set_time(time_t* old, time_t* new) +{ + if (* old != * new) + { + *old = *new; + return true; + } + + return false; +} + +static bool ioc_ui_json_set_double(double* old, double* new) +{ + if (* old != * new) + { + *old = *new; + return true; + } + return false; +} + + +static bool ioc_ui_json_set_cost(UI_CostInfo_t* old, UI_CostInfo_t* new) +{ + if (memcmp(old, new, sizeof(UI_CostInfo_t)) != 0) + { + // 不相同则整体赋值 + *old = *new; + return true; + } + return false; +} + +static bool ioc_ui_json_set_swFunc(uint32_t swFunc) +{ + if (g_ui_json.swFunc != swFunc) + { + g_ui_json.swFunc = swFunc; + // 软件功能开关更新 + SwFuncCheck(swFunc); + return true; + } + + return false; +} + + +static bool ioc_ui_json_set_keyFunc(int idx, uint32_t keyFunc) +{ + if (idx < 0 || idx >= KEY_FUNC_COUNT) + { + LV_LOG_WARN("Invalid keyFunc index: %d", idx); + return false; + } + + if (g_ui_json.keyFunc[idx] != keyFunc) + { + // LV_LOG_WARN("[%d]m1768errCode %d->%d", idx, g_ui_json.connectors[idx].m1768errCode, code); + g_ui_json.keyFunc[idx] = keyFunc; + return true; + } + + return false; +} + +static bool ioc_ui_json_set_isAutoCCS(int idx, int isAutoCCS) +{ + if (idx >= UI_NUMOFCONNECTOR) return false; + + bool ret = (isAutoCCS == cJSON_True); + + if (g_ui_json.isAutoCCS != ret) + { + // LV_LOG_WARN("[%d]m1768errCode %d->%d", idx, g_ui_json.connectors[idx].m1768errCode, code); + g_ui_json.isAutoCCS = ret; + return true; + } + + return false; +} + +static bool ioc_ui_json_set_bool(bool *field, int jsonValue) +{ + bool ret = (jsonValue == cJSON_True); + + if (*field != ret) + { + // LV_LOG_WARN("======================"); + *field = ret; + return true; + } + + return false; +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool ioc_ui_trigger_parse(cJSON * trigger) +{ + const char * trigger_str = cJSON_GetStringValue(cJSON_GetObjectItem(trigger, "Trigger")); + // 以下字段不一定有,需要根据Trigger类型进行判断 + cJSON* seconds = cJSON_GetObjectItem(trigger, "seconds"); + cJSON* percent = cJSON_GetObjectItem(trigger, "percent"); + cJSON* Msg = cJSON_GetObjectItem(trigger, "Msg"); + cJSON* Content = cJSON_GetObjectItem(trigger, "Content"); + cJSON* qrCodeText = cJSON_GetObjectItem(trigger, "qrCodeText"); + cJSON* qrCodeReceiptText = cJSON_GetObjectItem(trigger, "qrCodeReceiptText"); + cJSON* idx = cJSON_GetObjectItem(trigger, "idx"); + cJSON* action = cJSON_GetObjectItem(trigger, "Action"); // 外设命令PeripheralOperation时使用,目前只支持重启 + + if(seconds != NULL) + { + g_ui_json.trigger.seconds = seconds->valueint; + } + if(percent != NULL) + { + g_ui_json.trigger.percent = (unsigned short)percent->valueint; + } + if(Msg != NULL) + { + g_ui_json.trigger.msg = (uint8_t)Msg->valueint; + } + if(Content != NULL) + { + snprintf(g_ui_json.trigger.content, sizeof(g_ui_json.trigger.content), "%s", Content->valuestring); + } + if(qrCodeText != NULL) + { + snprintf(g_ui_json.trigger.billUrlStr, sizeof(g_ui_json.trigger.billUrlStr), "%s", qrCodeText->valuestring); + } + if(qrCodeReceiptText != NULL) + { + snprintf(g_ui_json.trigger.receiptUrlStr, sizeof(g_ui_json.trigger.receiptUrlStr), "%s", qrCodeReceiptText->valuestring); + } + if(idx != NULL) + { + g_ui_json.trigger.idx = -1; + + +#if ((COMPILER_FOR == COMPILE_FOR_CABINET_AM3354) || (COMPILER_FOR == COMPILE_FOR_CABINET_SSD202)) + for ( int i = 0; i < UI_NUMOFCONNECTOR; i++) + { + if(idx->valueint == g_ui_json.dispenserConfig.connIdx[i]) + { + g_ui_json.trigger.idx = i; + } + } +#else + g_ui_json.trigger.idx = idx->valueint; +#endif + + } + if (action != NULL) + { + snprintf(g_ui_json.trigger.action, sizeof(g_ui_json.trigger.action), "%s", action->valuestring); + } + + #ifdef COLOR_TEST + if(strcmp(trigger_str, "Test") == 0) + { + if(Msg != NULL) + { + uint8_t color_idx = (uint8_t)Msg->valueint; + ui_trigger_panel_show(color_idx); + } + + } + #endif + if(strcmp(trigger_str, "Bill") == 0) + { + ui_popup_show_bill(); + } + else if (strcmp(trigger_str, "Cancel") == 0) + { + ui_popup_hide_bill(); + #ifdef COLOR_TEST + ui_trigger_panel_hide(); + #endif + ui_popup_common_handle(trigger_str); + } + else if(strcmp(trigger_str, "ActiveIdx") == 0) + { + ioc_ui_json_set_active_idx(g_ui_json.trigger.idx); + } + else + { + ui_popup_common_handle(trigger_str); + } + + // 更新激活时间 + g_ui_json.biright.activeTime = time(NULL); + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// static bool parseMeterInfo(const cJSON *meterInfo, UI_MeterData_t *meterData) +// { +// const char *keys[3] = {"voltage", "current", "Q"}; +// double *dest[3] = { meterData->voltage, +// meterData->current, +// meterData->Q }; +// const double unit[3]= { UI_JSON_V_UNIT, +// UI_JSON_I_UNIT, +// UI_JSON_Q_UNIT }; + +// int count = sizeof(keys) / sizeof(keys[0]); + +// for (int k = 0; k < count; k++) +// { +// const cJSON *arr = cJSON_GetObjectItem(meterInfo, keys[k]); +// if (!cJSON_IsArray(arr)) +// { +// LV_LOG_WARN("'%s' is not an array or not found", keys[k]); +// return false; +// } + +// int cnt = cJSON_GetArraySize(arr); +// if (cnt != (PHASE_NUM + 1)) +// { +// LV_LOG_WARN("Warning: '%s' length %d != %d", keys[k], cnt, PHASE_NUM + 1); +// return false; +// } + +// for (int i = 0; i < (PHASE_NUM + 1); ++i) +// { +// const cJSON *item = cJSON_GetArrayItem(arr, i); +// if (cJSON_IsNumber(item)) +// { +// dest[k][i] = item->valuedouble * unit[k]; +// } +// else +// { +// LV_LOG_WARN("'%s'[%d] is not a number, defaulting to 0.0", keys[k], i); +// dest[k][i] = 0.0; +// } +// } +// } + +// return true; +// } + +// 拼接四位小数 +static void ioc_merge_fourth_decimal(double *q3, uint8_t fourthQ) +{ + int int_part = (int)(*q3); + int dec3_part = (int)(*q3 * 1000) % 1000; + int full4 = dec3_part * 10 + fourthQ; + *q3 = int_part + full4 / 10000.0; +} + + +// 根据枪的状态解析更新 +static bool ioc_ui_json_parse_state_data(uint8_t idx, cJSON * conn) +{ + // char *formatted = cJSON_Print(conn); + // printf("Formatted JSON:\n%s\n", formatted); + // free(formatted); + + // 解析 + bool changed = false; + // bool is_Q4dot = false; // 电量显示四位小数 + + UI_MeterData_t meterData; + memset(&meterData, 0x00, sizeof(UI_MeterData_t)); + UI_PriceInfo_t currPrice; + memset(&currPrice, 0x00, sizeof(UI_PriceInfo_t)); + UI_PriceInfo_t nextPrice; + memset(&nextPrice, 0x00, sizeof(UI_PriceInfo_t)); + UI_CostInfo_t cost; + memset(&cost, 0x00, sizeof(UI_CostInfo_t)); + + time_t startTime = 0; // 起充时间 + time_t stopTime = 0; // 停充时间 + int duration = 0; // 充电时长 + int Soc = 0; // 实时Soc + int startSoc = 0; // 起充Soc + int stopSoc = 0; // 停止Soc + time_t reverseTime = 0; // 预约开始时间 + double actualMeterVal = 0; // 实际充电电量 + double actualMeter4dot = 0; // 实际充电电量第四位小数 + + cJSON* sessionConnInfo = cJSON_GetObjectItem(conn, "sessionConnInfo"); if(sessionConnInfo == NULL) return false; + cJSON* saveData = cJSON_GetObjectItem(sessionConnInfo, "saveData"); if(saveData == NULL) return false; + cJSON* _startTime = cJSON_GetObjectItem(saveData, "_startTime"); if (_startTime == NULL) return false; + cJSON* _meterStart = cJSON_GetObjectItem(saveData, "_meterStart"); if (_meterStart == NULL) return false; + + cJSON* ramData = cJSON_GetObjectItem(sessionConnInfo, "ramData"); if(ramData == NULL) return false; + cJSON* actualStopTime = cJSON_GetObjectItem(ramData, "actualStopTime"); if(actualStopTime == NULL) return false; + cJSON* actualDuration = cJSON_GetObjectItem(ramData, "actualDuration"); if(actualDuration == NULL) return false; + cJSON* actualMeter = cJSON_GetObjectItem(ramData, "actualMeter"); if(actualMeter == NULL) return false; + + duration = actualDuration->valueint; + stopTime = (time_t)(actualStopTime->valueint); + + // 因为在Finish时actualStopTime会被清空,所以用结束时间减去充电时长来计算起充时间 + if(g_ui_json.connectors[idx].state == UI_CONNECTOR_STATE_FINISHED) + { + startTime = (time_t)(actualStopTime->valueint - actualDuration->valueint); + } + else + { + startTime = (time_t)(_startTime->valueint); + } + + // Soc相关字段只有直流桩有,所以有可能是空 + cJSON* m1768Info = cJSON_GetObjectItem(conn, "m1768Info"); if(m1768Info == NULL) return false; + cJSON* SocItem = cJSON_GetObjectItem(m1768Info, "SoC"); + if(SocItem != NULL) + { + Soc = SocItem->valueint; + } + cJSON* startSoCItem = cJSON_GetObjectItem(m1768Info, "startSoC"); + if(startSoCItem != NULL) + { + startSoc = startSoCItem->valueint; + } + + cJSON* stateMngrInfo = cJSON_GetObjectItem(conn, "stateMngrInfo"); if(stateMngrInfo == NULL) return false; + cJSON* stopSocItem = cJSON_GetObjectItem(stateMngrInfo, "stopSoc"); + if(stopSocItem != NULL) + { + stopSoc = stopSocItem->valueint; + } + + cJSON* reserveConnInfo = cJSON_GetObjectItem(conn, "reserveConnInfo"); if(reserveConnInfo == NULL) return false; + cJSON* expireDate = cJSON_GetObjectItem(reserveConnInfo, "expireDate"); if(expireDate == NULL) return false; + reverseTime = (time_t)expireDate->valueint; + + + // 解析电表数据 + cJSON * meterInfo = cJSON_GetObjectItem(conn, "meterInfo"); if(meterInfo == NULL) return false; + cJSON * qArray = cJSON_GetObjectItem(meterInfo, "Q"); + cJSON * q3 = cJSON_GetArrayItem(qArray, 3); + meterData.Q[3] = q3->valueint; + +#if ((COMPILER_FOR != COMPILE_FOR_AC_SSD202) && (COMPILER_FOR != COMPILE_FOR_SSD202_43)) + cJSON * outputCurArray = cJSON_GetObjectItem(m1768Info, "outputCur"); // Array + cJSON * outputVolArray = cJSON_GetObjectItem(m1768Info, "outputVol"); // Array + int sizeOut = cJSON_GetArraySize(outputCurArray); + for (int j=0; jvaluedouble * UI_JSON_I_UNIT; + + cJSON * outputVol = cJSON_GetArrayItem(outputVolArray, j); // double + meterData.voltage[j] = outputVol->valuedouble * UI_JSON_V_UNIT; + } + #else + cJSON * Varray = cJSON_GetObjectItem(meterInfo, "voltage"); + cJSON * Carray = cJSON_GetObjectItem(meterInfo, "current"); + + int sizeOut = cJSON_GetArraySize(Varray); + for (int j = 0; j < sizeOut; j++) + { + cJSON * outputCur = cJSON_GetArrayItem(Carray, j); // double + meterData.current[j] = outputCur ? (outputCur->valuedouble * UI_JSON_I_UNIT) : 0.0; + + cJSON * outputVol = cJSON_GetArrayItem(Varray, j); // double + meterData.voltage[j] = outputVol ? (outputVol->valuedouble * UI_JSON_V_UNIT) : 0.0; + } + + // 计算电流平均值 + if (meterData.current[3] == 0) + { + double sum = 0.0; + int count = 0; + + for (int k = 0; k < PHASE_NUM; k++) + { + if (meterData.current[k] > 0) // 0 不计入平均 + { + sum += meterData.current[k]; + count++; + } + } + if (count > 0) + { + meterData.current[3] = sum / count; + } + } + + +#endif + + // if(!parseMeterInfo(meteinfo, &meterData)) return false; + + // 本地计算功率 + meterData.power = ((meterData.voltage[0] * meterData.current[0]) + + (meterData.voltage[1] * meterData.current[1]) + + (meterData.voltage[2] * meterData.current[2])) * UI_JSON_P_UNIT; + + + int meterStart = _meterStart->valueint; + + double realQ = 0; // 实际使用功率 当前电表值 - 电表初始值 显示四位小数时单位:0.0001kWh 否则单位:0.001kWh + + cJSON * dotQ4 = cJSON_GetObjectItem(meterInfo, "dotQ4"); + cJSON* startQ4dot = cJSON_GetObjectItem(saveData, "_startQ4dot"); + if ((dotQ4 != NULL) && (startQ4dot != NULL)) // 电量显示四位小数 + { + g_ui_json.connectors[idx].isQ4dot = true; + meterData.fourthQ = (uint8_t)(cJSON_GetArrayItem(dotQ4, 3)->valueint); + meterData.startQ4dot = (uint8_t)startQ4dot->valueint; + + realQ = (meterData.Q[3] * 10 + meterData.fourthQ) - (meterStart * 10 + meterData.startQ4dot); + realQ = realQ * 0.1f; + } + else + { + realQ = meterData.Q[3] - meterStart; + } + + meterData.Q[3] = realQ * UI_JSON_Q_UNIT; + + actualMeterVal = actualMeter->valuedouble * UI_JSON_Q_UNIT; + + + cJSON* actualQ4 = cJSON_GetObjectItem(ramData, "actualQ4"); + if (actualQ4 != NULL) + { + // 有这个字段表示需要显示四位小数 + g_ui_json.connectors[idx].isQ4dot = true; + actualMeter4dot = (uint8_t)(actualQ4->valueint); + ioc_merge_fourth_decimal(&actualMeterVal, actualMeter4dot); + } + + // 测试用 + // g_ui_json.connectors[idx].isQ4dot = true; + + // 解析价格费用信息 + cJSON * priceInfo = cJSON_GetObjectItem(conn, "priceInfo"); + if(priceInfo != NULL) + { + // 有这个字段表示要显示价格和费用信息 + g_ui_json.connectors[idx].showPrice = true; + + cJSON* costItem = cJSON_GetObjectItem(sessionConnInfo, "cost"); if(costItem == NULL) return false; + cost.totalCost = cJSON_GetObjectItem(costItem, "totalCost")->valuedouble; + cost.reserveIdleCost = cJSON_GetObjectItem(costItem, "reserveIdleCost")->valuedouble; + cost.suspendIdleCost = cJSON_GetObjectItem(costItem, "suspendIdleCost")->valuedouble; + cost.stopIdleCost = cJSON_GetObjectItem(costItem, "stopIdleCost")->valuedouble; + + cJSON* currPriceItem = cJSON_GetObjectItem(priceInfo, "currPrice"); if(currPriceItem == NULL) return false; + cJSON* nextPriceItem = cJSON_GetObjectItem(priceInfo, "nextPrice"); if(nextPriceItem == NULL) return false; + + currPrice.startMin = cJSON_GetObjectItem(currPriceItem, "startMin")->valueint; + currPrice.kWhPrice = cJSON_GetObjectItem(currPriceItem, "kWhPrice")->valuedouble; + currPrice.hourPrice = cJSON_GetObjectItem(currPriceItem, "hourPrice")->valuedouble; + currPrice.flatFee = cJSON_GetObjectItem(currPriceItem, "flatFee")->valuedouble; + + nextPrice.startMin = cJSON_GetObjectItem(nextPriceItem, "startMin")->valueint; + nextPrice.endMin = cJSON_GetObjectItem(nextPriceItem, "endMin")->valueint; + nextPrice.kWhPrice = cJSON_GetObjectItem(nextPriceItem, "kWhPrice")->valuedouble; + nextPrice.hourPrice = cJSON_GetObjectItem(nextPriceItem, "hourPrice")->valuedouble; + nextPrice.flatFee = cJSON_GetObjectItem(nextPriceItem, "flatFee")->valuedouble; + + cJSON* priceText = cJSON_GetObjectItem(priceInfo, "priceText"); + if(priceText != NULL) + { + g_ui_json.connectors[idx].isOcppPrice = true; + + snprintf(currPrice.priceText, sizeof(currPrice.priceText), "%s", priceText->valuestring); + } + else + { + g_ui_json.connectors[idx].isOcppPrice = false; + } + } + else + { + g_ui_json.connectors[idx].showPrice = false; + } + +#if ((COMPILER_FOR != COMPILE_FOR_AC_SSD202) && (COMPILER_FOR != COMPILE_FOR_SSD202_43)) + // charging界面detailed里的数据在此更新 + if(g_ui_json.connectors[idx].state == UI_CONNECTOR_STATE_CHARGING) + { + // 在其他地方已经解析过的数据在此不重复解析,直接调用 + // m1768Info_runState + double tempVal = cJSON_GetObjectItem(m1768Info, "reqVol")->valuedouble / 10; + changed |= ioc_ui_json_set_double(&g_ui_json.connectors[idx].reqVol, &tempVal); + tempVal = cJSON_GetObjectItem(m1768Info, "reqCur")->valuedouble / 10; + changed |= ioc_ui_json_set_double(&g_ui_json.connectors[idx].reqCur, &tempVal); + tempVal = cJSON_GetObjectItem(m1768Info, "offerVol")->valuedouble / 10; + changed |= ioc_ui_json_set_double(&g_ui_json.connectors[idx].offerVol, &tempVal); + tempVal = cJSON_GetObjectItem(m1768Info, "offerCur")->valuedouble / 10; + changed |= ioc_ui_json_set_double(&g_ui_json.connectors[idx].offerCur, &tempVal); + tempVal = cJSON_GetObjectItem(m1768Info, "outLimit")->valuedouble / 10; + changed |= ioc_ui_json_set_double(&g_ui_json.connectors[idx].outLimit, &tempVal); + changed |= ioc_ui_json_set_int(&g_ui_json.connectors[idx].compGroup, &cJSON_GetObjectItem(m1768Info, "compGroup")->valueint); + changed |= ioc_ui_json_set_int(&g_ui_json.connectors[idx].startSoc, &startSoc); + + // 温度比较特殊,需要根据环境的温度和枪的温度进行判断 + cJSON * tempConnArray = cJSON_GetObjectItem(m1768Info, "tempConn"); // Array + int sizeOut = cJSON_GetArraySize(tempConnArray); + double temp[3] = {0}; + int conn_temp = -60; + for (int j=0; j < sizeOut; j++) + { + cJSON * tempConn = cJSON_GetArrayItem(tempConnArray, j); // double + temp[j] = tempConn->valuedouble; + if (temp[j] > conn_temp) + { + conn_temp = temp[j]; + } + } + int maxTemp = (conn_temp > s_point_temp) ? conn_temp : s_point_temp; + + changed |= ioc_ui_json_set_int(&g_ui_json.connectors[idx].temp, &maxTemp); + + changed |= ioc_ui_json_set_string(idx, cJSON_GetObjectItem(m1768Info, "unit")->valuestring, + g_ui_json.connectors[idx].outLimitUnit, + sizeof(g_ui_json.connectors[idx].outLimitUnit), + "outLimitUnit"); + } +#endif + + // 数据更新 + switch (g_ui_json.connectors[idx].state) + { + case UI_CONNECTOR_STATE_IDLE: + changed |= ioc_ui_json_set_price(&g_ui_json.connectors[idx].state_data.idle.currPrice, &currPrice); + changed |= ioc_ui_json_set_price(&g_ui_json.connectors[idx].state_data.idle.nextPrice, &nextPrice); + break; + case UI_CONNECTOR_STATE_STARTING1: + case UI_CONNECTOR_STATE_STARTING2: + changed |= ioc_ui_json_set_price(&g_ui_json.connectors[idx].state_data.starting.currPrice, &currPrice); + changed |= ioc_ui_json_set_price(&g_ui_json.connectors[idx].state_data.starting.nextPrice, &nextPrice); + break; + case UI_CONNECTOR_STATE_CHARGING: + changed |= ioc_ui_json_set_price(&g_ui_json.connectors[idx].state_data.charging.currPrice, &currPrice); + changed |= ioc_ui_json_set_cost(&g_ui_json.connectors[idx].state_data.charging.cost, &cost); + changed |= ioc_ui_json_set_meterdata(&g_ui_json.connectors[idx].state_data.charging.meterData, &meterData); + changed |= ioc_ui_json_set_int(&g_ui_json.connectors[idx].state_data.charging.soc, &Soc); + changed |= ioc_ui_json_set_time(&g_ui_json.connectors[idx].state_data.charging.startTime, &startTime); + + break; + case UI_CONNECTOR_STATE_FINISHED: + changed |= ioc_ui_json_set_price(&g_ui_json.connectors[idx].state_data.charging.currPrice, &currPrice); + changed |= ioc_ui_json_set_cost(&g_ui_json.connectors[idx].state_data.finished.cost, &cost); + changed |= ioc_ui_json_set_double(&g_ui_json.connectors[idx].state_data.finished.actualMeter, &actualMeterVal); + changed |= ioc_ui_json_set_int(&g_ui_json.connectors[idx].state_data.finished.startSoc, &startSoc); + changed |= ioc_ui_json_set_int(&g_ui_json.connectors[idx].state_data.finished.stopSoc, &stopSoc); + changed |= ioc_ui_json_set_time(&g_ui_json.connectors[idx].state_data.finished.startTime, &startTime); + changed |= ioc_ui_json_set_time(&g_ui_json.connectors[idx].state_data.finished.stopTime, &stopTime); + changed |= ioc_ui_json_set_int(&g_ui_json.connectors[idx].state_data.finished.duration, &duration); + break; + case UI_CONNECTOR_STATE_RESERVED: + changed |= ioc_ui_json_set_price(&g_ui_json.connectors[idx].state_data.reserved.currPrice, &currPrice); + changed |= ioc_ui_json_set_price(&g_ui_json.connectors[idx].state_data.reserved.nextPrice, &nextPrice); + changed |= ioc_ui_json_set_time(&g_ui_json.connectors[idx].state_data.reserved.reverseTime, &reverseTime); + break; + default: + break; + } + + return changed; +} + +bool ioc_ui_json_parse(const char *json_str) +{ + bool changed = false; + bool rtn = false; + uint8_t tempValue_U8 = 0; + cJSON *root = cJSON_Parse(json_str); + if (root == NULL) + { + LV_LOG_ERROR("parse json failed"); + return false; + } + + // LV_LOG_WARN("recv=========================="); + + // DEBUG_WARN("[%s]", json_str); + + // 收到Trigger做特殊处理 + if(cJSON_GetObjectItem(root, "Trigger")) + { + LV_LOG_WARN("[%s]", json_str); + changed = ioc_ui_trigger_parse(root); + } + else + { + cJSON * global = cJSON_GetObjectItem(root, "global"); + if ((global == NULL) || (!cJSON_IsObject(global))) goto FAILED_JSON; + + cJSON * activeInfo = cJSON_GetObjectItem(global, "activeInfo"); + if (activeInfo != NULL) + { + cJSON * activeTime = cJSON_GetObjectItem(global, "activeTime"); + if (activeTime != NULL) + { + ioc_ui_json_set_activeTime((time_t)activeTime->valueint); + } + } + + cJSON * userConfigInfo = cJSON_GetObjectItem(global, "userConfigInfo"); + if (userConfigInfo != NULL) + { + cJSON * language = cJSON_GetObjectItem(userConfigInfo, "language"); + if (language != NULL) + { + changed |= ioc_ui_json_set_language(language->valueint); + } + cJSON *signCurrency = cJSON_GetObjectItem(userConfigInfo, "signCurrency"); + if (signCurrency != NULL) + { + changed |= ioc_ui_json_set_sign_currency(signCurrency->valuestring); + } + + // 价格和费用的小数位长度,没有的话默认为2 + cJSON *costPriceDecimalPlaces = cJSON_GetObjectItem(userConfigInfo, "costPriceDecimalPlaces"); + if (costPriceDecimalPlaces != NULL) + { + changed |= ioc_ui_json_set_sign_costPriceDecimalPlaces((uint8_t)costPriceDecimalPlaces->valueint); + } +#if (COMPILER_FOR == COMPILE_FOR_AC_SSD202) + // 时间 + cJSON *time = cJSON_GetObjectItem(userConfigInfo, "time"); + if (time != NULL) + { + time_t new_time = (time_t)time->valueint; + changed |= ioc_ui_json_set_sever_time(new_time); + } +#endif + // 设置亮度相关配置 + cJSON *brightIdle = cJSON_GetObjectItem(userConfigInfo, "brightIdle"); + if (brightIdle != NULL) + { + tempValue_U8 = (uint8_t)brightIdle->valueint; + changed |= ioc_ui_json_set_u8(&g_ui_json.biright.brightIdle, &tempValue_U8); + } + cJSON *brightActive = cJSON_GetObjectItem(userConfigInfo, "brightActive"); + if (brightActive != NULL) + { + tempValue_U8 = (uint8_t)brightActive->valueint; + changed |= ioc_ui_json_set_u8(&g_ui_json.biright.brightActive, &tempValue_U8); + } + cJSON *brightCharging = cJSON_GetObjectItem(userConfigInfo, "brightCharging"); + if (brightCharging != NULL) + { + tempValue_U8 = (uint8_t)brightCharging->valueint; + changed |= ioc_ui_json_set_u8(&g_ui_json.biright.brightCharging, &tempValue_U8); + } + cJSON *timeoutActive = cJSON_GetObjectItem(userConfigInfo, "timeoutActive"); + if (timeoutActive != NULL) + { + tempValue_U8 = (uint8_t)timeoutActive->valueint; + changed |= ioc_ui_json_set_u8(&g_ui_json.biright.timeoutActive, &tempValue_U8); + } + + // 功能开关 + cJSON * swFunc = cJSON_GetObjectItem(userConfigInfo, "swFunc"); + if (swFunc != NULL) + { + changed |= ioc_ui_json_set_swFunc((uint32_t)swFunc->valueint); + } + + // 按钮功能 + cJSON * keyFuncArry = cJSON_GetObjectItem(userConfigInfo, "keyFunc"); + if (keyFuncArry != NULL) + { + int size = cJSON_GetArraySize(keyFuncArry); + for (int j = 0; j < size; j++) + { + cJSON * keyFunc = cJSON_GetArrayItem(keyFuncArry, j); // double + changed |= ioc_ui_json_set_keyFunc(j, (uint32_t)keyFunc->valueint); + } + } + } + + cJSON * sysconfigInfo = cJSON_GetObjectItem(global, "sysconfigInfo"); + if (sysconfigInfo != NULL) + { + cJSON * timeZone = cJSON_GetObjectItem(sysconfigInfo, "timeZone"); + if (timeZone != NULL) + { + changed |= ioc_ui_json_set_timeZone((uint8_t)timeZone->valueint); + } + } + + cJSON * m1768Peris = cJSON_GetObjectItem(global, "m1768Peri"); + if (m1768Peris != NULL) + { + cJSON * m1768Peri = cJSON_GetArrayItem(m1768Peris, 0); + if (m1768Peri != NULL) + { + s_point_temp = -20; + + cJSON * temp1 = cJSON_GetObjectItem(m1768Peri, "temp1"); + if (temp1 != NULL) + { + if (temp1->valueint > s_point_temp) + { + s_point_temp = temp1->valueint; + } + } +#if ((COMPILER_FOR != COMPILE_FOR_AC_SSD202)||(COMPILER_FOR != COMPILE_FOR_SSD202_43)) + cJSON * temp2 = cJSON_GetObjectItem(m1768Peri, "temp2"); + if (temp2 != NULL) + { + if (temp2->valueint > s_point_temp) + { + s_point_temp = temp2->valueint; + } + } +#endif + } + + } + + cJSON * drvPointInfo = cJSON_GetObjectItem(global, "drvPointInfo"); + if (drvPointInfo != NULL) + { + cJSON * meterFault = cJSON_GetObjectItem(drvPointInfo, "meterFault"); + if(meterFault != NULL) + { + // LV_LOG_WARN("======================"); + changed |= ioc_ui_json_set_bool(&g_ui_json.drvPointInfo.meterFault, meterFault->type); + } + + cJSON * rfFault = cJSON_GetObjectItem(drvPointInfo, "rfFault"); + if(rfFault != NULL) + { + changed |= ioc_ui_json_set_bool(&g_ui_json.drvPointInfo.rfFault, rfFault->type); + } + + cJSON * online = cJSON_GetObjectItem(drvPointInfo, "online"); + if(online != NULL) + { + changed |= ioc_ui_json_set_bool(&g_ui_json.drvPointInfo.online, online->type); + } + + cJSON * ethStatus = cJSON_GetObjectItem(drvPointInfo, "ethStatus"); + if(ethStatus != NULL) + { + tempValue_U8 = (uint8_t)ethStatus->valueint; + changed |= ioc_ui_json_set_u8(&g_ui_json.drvPointInfo.ethStatus, &tempValue_U8); + } + + cJSON * wifiStatus = cJSON_GetObjectItem(drvPointInfo, "wifiStatus"); + if(wifiStatus != NULL) + { + tempValue_U8 = (uint8_t)wifiStatus->valueint; + changed |= ioc_ui_json_set_u8(&g_ui_json.drvPointInfo.wifiStatus, &tempValue_U8); + } + + cJSON * m4gStatus = cJSON_GetObjectItem(drvPointInfo, "m4gStatus"); + if(m4gStatus != NULL) + { + tempValue_U8 = (uint8_t)m4gStatus->valueint; + changed |= ioc_ui_json_set_u8(&g_ui_json.drvPointInfo.m4gStatus, &tempValue_U8); + } + + cJSON * httpAddr = cJSON_GetObjectItem(drvPointInfo, "httpAddr"); + if(httpAddr != NULL) + { + changed |= ioc_ui_json_set_httpAddr(0, cJSON_GetStringValue(httpAddr)); + } + } + + cJSON * conns = cJSON_GetObjectItem(root, "conns"); + if ((conns == NULL) || (!cJSON_IsArray(conns))) goto FAILED_JSON; + + int conns_len = cJSON_GetArraySize(conns); +#if ((COMPILER_FOR == COMPILE_FOR_DC_AM3354) || (COMPILER_FOR == COMPILE_FOR_AC_SSD202)||(COMPILER_FOR == COMPILE_FOR_SSD202_43)) + if (conns_len > UI_MAX_CONNECTOR_NUM) goto FAILED_JSON; + changed |= ioc_ui_json_set_con_num(conns_len); // 分体桩在MQTT处设置 +#else + if(conns_len != UI_NUMOFCONNECTOR) goto FAILED_JSON; // 等MQTT将所有枪数据收集齐再处理 +#endif + + // LV_LOG_WARN("conns_len[%d]", conns_len); + cJSON * creditCardInfo = cJSON_GetObjectItem(global, "creditCardInfo"); + if (creditCardInfo != NULL) + { + // 有这个字段表示启用了POS机 + g_ui_json.enPOS = true; + + cJSON *enSoftKey = cJSON_GetObjectItem(creditCardInfo, "enSoftKey"); + + if (enSoftKey != NULL && cJSON_IsBool(enSoftKey)) + { + g_ui_json.enSoftKey = cJSON_IsTrue(enSoftKey); + // LV_LOG_WARN("enSoftKey: %d", g_ui_json.enSoftKey); + } + } + else + { + g_ui_json.enPOS = false; + } + + + // 测试用 + g_ui_json.enPOS = true; + + // 解析枪数据 + for (int i = 0; (i < conns_len && i < UI_NUMOFCONNECTOR); i++) + { + int idx = i; + cJSON * conn = cJSON_GetArrayItem(conns, idx); + if ((conn == NULL) || (!cJSON_IsObject(conn))) goto FAILED_JSON; + + cJSON * meterInfo = cJSON_GetObjectItem(conn, "meterInfo"); + cJSON * connConfig = cJSON_GetObjectItem(conn, "connConfig"); + if (connConfig != NULL) + { + cJSON * ratePower = cJSON_GetObjectItem(connConfig, "ratePower"); + if (ratePower != NULL) + { + changed |= ioc_ui_json_set_con_rated_power(i, ratePower->valueint); + } + cJSON * connQR = cJSON_GetObjectItem(connConfig, "connQR"); + if (connQR != NULL) + { + changed |= ioc_ui_json_set_con_qrcode(i, connQR->valuestring); + } + cJSON * connCode = cJSON_GetObjectItem(connConfig, "connCode"); + if (connCode != NULL) + { + changed |= ioc_ui_json_set_con_code(i, connCode->valuestring); + } + + } + cJSON * m1768Info = cJSON_GetObjectItem(conn, "m1768Info"); + if (m1768Info != NULL) + { + changed |= ioc_ui_json_set_con_type(i, cJSON_GetStringValue(cJSON_GetObjectItem(m1768Info, "connType"))); + changed |= ioc_ui_json_set_con_m1768_runstate(i, cJSON_GetStringValue(cJSON_GetObjectItem(m1768Info, "runState"))); + cJSON * subState = cJSON_GetObjectItem(m1768Info, "subState"); + if (subState != NULL) + { + changed |= ioc_ui_json_set_con_m1768_subState(i, (uint8_t)subState->valueint); + } + + changed |= ioc_ui_json_set_con_m1768_connstatus(i, cJSON_GetStringValue(cJSON_GetObjectItem(m1768Info, "connStatus"))); + + +// TODO 从未插枪到插枪表示激活哪根枪, 分体用ActiveIdx控制,现在homeOCpp授权组还没合并到主分支,后续合并后此处考虑修改 +#if ((COMPILER_FOR == COMPILE_FOR_DC_AM3354) || (COMPILER_FOR == COMPILE_FOR_AC_SSD202)) + + // LV_LOG_WARN("==idx[%d].connStatus[%s] plug[%d] ", i, g_ui_json.connectors[i].connStatus, g_ui_json.connectors[i].plug); + if (strcmp(g_ui_json.connectors[i].connStatus, "Unplug") != 0) + { + if(!g_ui_json.connectors[i].plug) + { + ioc_ui_json_set_active_idx(i); + g_ui_json.connectors[i].plug = true; + } + } + else + { + g_ui_json.connectors[i].plug = false; + } +#else + if (strcmp(g_ui_json.connectors[i].connStatus, "Unplug") != 0) + { + if(!g_ui_json.connectors[i].plug) + { + // 更新激活时间 + g_ui_json.biright.activeTime = time(NULL); // TODO此处插枪后点亮屏幕,未进行激活枪,激活枪还是由homeOCPP下发,此处逻辑待优化 + g_ui_json.connectors[i].plug = true; + } + } + else + { + g_ui_json.connectors[i].plug = false; + } +#endif + + + cJSON * errCode = cJSON_GetObjectItem(m1768Info, "errCode"); + if ( errCode != NULL ) + { + changed |= ioc_ui_json_set_m1768_err_code(i, errCode->valueint); + } + } + cJSON * plcInfo = cJSON_GetObjectItem(conn, "plcInfo"); + cJSON * stateMngrInfo = cJSON_GetObjectItem(conn, "stateMngrInfo"); + if (stateMngrInfo != NULL) + { + changed |= ioc_ui_json_set_con_statemng_runstate(i, cJSON_GetStringValue(cJSON_GetObjectItem(stateMngrInfo, "runState"))); + cJSON * stopCode = cJSON_GetObjectItem(stateMngrInfo, "stopCode"); + if ( stopCode != NULL ) + { + changed |= ioc_ui_json_set_con_stop_code(i, stopCode->valueint); + } + } + cJSON * reserveConnInfo = cJSON_GetObjectItem(conn, "reserveConnInfo"); + cJSON * sessionConnInfo = cJSON_GetObjectItem(conn, "sessionConnInfo"); + if (sessionConnInfo != NULL) + { + cJSON * saveData = cJSON_GetObjectItem(sessionConnInfo, "saveData"); + if(saveData != NULL) + { + cJSON * _idAuth = cJSON_GetObjectItem(saveData , "_idAuth"); + changed |= ioc_ui_json_set_idTag(i, cJSON_GetStringValue(cJSON_GetObjectItem(_idAuth, "idTag"))); + cJSON * idType = cJSON_GetObjectItem(_idAuth, "idType"); + if(idType != NULL) + { + changed |= ioc_ui_json_set_idType(i, (IdTagType_t)idType->valueint); + } + + cJSON * isAutoCCS = cJSON_GetObjectItem(saveData, "isAutoCCS"); + if(isAutoCCS != NULL) + { + changed |= ioc_ui_json_set_isAutoCCS(i, isAutoCCS->type); + } + } + + cJSON * ramData = cJSON_GetObjectItem(sessionConnInfo, "ramData"); + if ( ramData != NULL ) + { + changed |= ioc_ui_json_set_con_status_real(i, cJSON_GetStringValue(cJSON_GetObjectItem(ramData, "_status_real"))); + changed |= ioc_ui_json_set_con_errcode(i, cJSON_GetStringValue(cJSON_GetObjectItem(ramData, "_errCode"))); + } + } + + ioc_ui_connector_state_t conn_state = ui_page_status_judgment(i); + // LV_LOG_WARN("[%d] ========= conn_state: %d", i, conn_state); + changed |= ioc_ui_json_set_conn_state(i, conn_state); + + // 解析各个状态的数据 + changed |= ioc_ui_json_parse_state_data(i, conn); + } + } + + // 测试用 + // changed = true; + + rtn = changed; + + // LV_LOG_WARN("changed[%d]==========================", rtn); + +FAILED_JSON: + cJSON_Delete(root); + return rtn; +} + +bool ioc_ui_json_create_udp_socket() +{ + struct sockaddr_in serv_addr; + +#ifdef _WIN32 + static bool wsa_initialized = false; + if (!wsa_initialized) + { + WSADATA wsa_data; + if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) + { + LV_LOG_ERROR("WSAStartup failed"); + return false; + } + wsa_initialized = true; + } +#endif + + // 创建UDP套接字 + s_ui_json_sockfd = socket(AF_INET, SOCK_DGRAM, 0); + + if (s_ui_json_sockfd < 0) + { + LV_LOG_ERROR("create socket failed: %s", strerror(errno)); + return false; + } +#if (COMPILER_FOR == COMPILE_FOR_CABINET_SSD202) + // 打开广播选项 + int opt = 1; + if (setsockopt(s_ui_json_sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) < 0) + { + LV_LOG_ERROR("setsockopt SO_BROADCAST failed: %s", strerror(errno)); +#ifdef _WIN32 + closesocket(s_ui_json_sockfd); +#else + close(s_ui_json_sockfd); +#endif + return false; + } +#endif + + // 设置套接字为非阻塞模式 +#ifdef _WIN32 + u_long non_blocking = 1; + if (ioctlsocket(s_ui_json_sockfd, FIONBIO, &non_blocking) != 0) + { + LV_LOG_ERROR("FIONBIO failed"); + closesocket(s_ui_json_sockfd); + return false; + } +#else + int flags = fcntl(s_ui_json_sockfd, F_GETFL, 0); + if (fcntl(s_ui_json_sockfd, F_SETFL, flags | O_NONBLOCK) < 0) + { + LV_LOG_ERROR("O_NONBLOCK failed: %s", strerror(errno)); + close(s_ui_json_sockfd); + return false; + } +#endif + + // 初始化服务器地址结构 + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; // 绑定到所有可用的网络接口 + serv_addr.sin_port = htons(SENDUI_LCD3354_DST_PORT); // 绑定到端口20001 + + // 绑定套接字到指定端口 + if (bind(s_ui_json_sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + { + LV_LOG_WARN("bind failed: %s", strerror(errno)); +#ifdef _WIN32 + closesocket(s_ui_json_sockfd); +#else + close(s_ui_json_sockfd); +#endif + return false; + } + + LV_LOG_WARN("Socket OK"); + return true; +} + +// 在 dir_path 目录下查找形如 "AddrDispenser" 的文件, 并返回数字部分;失败返回 0。 +uint8_t static ioc_extract_dispenser_index_in_dir(const char *dir_path) +{ + DIR *dp = opendir(dir_path); + if (!dp) + { + LV_LOG_WARN("Open dir %s failed", dir_path); + return 0; + } + + struct dirent *entry; + while ((entry = readdir(dp)) != NULL) + { + int idx; + // 只匹配文件名,不区分文件/目录,用 %n 检查是否全匹配 + int n; + if (sscanf(entry->d_name, "AddrDispenser%d%n", &idx, &n) == 1 + && entry->d_name[n] == '\0') { + closedir(dp); + return idx; + } + } + + closedir(dp); + + // 没找到 + LV_LOG_WARN("No AddrDispenser found in %s", dir_path); + return 0; +} + +bool ioc_ui_json_init(void) +{ + memset(&g_ui_json, 0, sizeof(g_ui_json)); + g_ui_json.active_connector_idx = -1; // 初始化设置为未选中枪 + g_ui_json.costPriceDecimalPlaces = 2; // 价格和费用小数位默认为2 + g_ui_json.language = -1; + g_ui_json.isFirstUIjson = true; + // 亮度配置 + g_ui_json.biright.brightActive = 5; + g_ui_json.biright.brightIdle = 2; + g_ui_json.biright.brightCharging = 3; + g_ui_json.biright.timeoutActive = 1; + + // 电表和读卡器状态信息 + g_ui_json.drvPointInfo.meterFault = true; + g_ui_json.drvPointInfo.rfFault = true; + + +#if ((COMPILER_FOR == COMPILE_FOR_CABINET_AM3354) || (COMPILER_FOR == COMPILE_FOR_CABINET_SSD202)) + g_ui_json.dispenserConfig.location = ioc_extract_dispenser_index_in_dir(IOC_PATH); // 从本地获取屏幕位置信息 + g_ui_json.dispenserConfig.connNum = 1; // 默认一根枪 + for (int i = 0; i < UI_MAX_CONNECTOR_NUM; i++) + { + g_ui_json.dispenserConfig.connIdx[i] = 0; + } + + LV_LOG_WARN("location[%d]", g_ui_json.dispenserConfig.location); + + g_ui_json_eventfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); +#endif + + // 测试用 + // ioc_ui_json_set_con_num(2); + + return ioc_ui_json_create_udp_socket(); +} + +bool ioc_ui_json_step(void) +{ + fd_set readfds; + struct timeval timeout; + int n; + + // 初始化fd集合 + FD_ZERO(&readfds); + int max_fd = -1; + + if (s_ui_json_sockfd >= 0) + { + FD_SET(s_ui_json_sockfd, &readfds); + max_fd = s_ui_json_sockfd; + } + + if (g_ui_json_eventfd >= 0) + { + FD_SET(g_ui_json_eventfd, &readfds); + if (g_ui_json_eventfd > max_fd) + { + max_fd = g_ui_json_eventfd; + } + } + + // 设置超时时间为0,实现非阻塞检查 + timeout.tv_sec = 0; // 超时时间为0秒 + timeout.tv_usec = 0; // 超时时间为0微秒 + + // 使用select检查套接字是否有数据可读 + n = select(max_fd + 1, &readfds, NULL, NULL, &timeout); + if (n > 0) + { +#if ((COMPILER_FOR == COMPILE_FOR_DC_AM3354) || (COMPILER_FOR == COMPILE_FOR_AC_SSD202) ||(COMPILER_FOR == COMPILE_FOR_SSD202_43)) + if(FD_ISSET(s_ui_json_sockfd, &readfds)) + { + // 有数据可读, 暂时不考虑分包问题 + struct sockaddr_in cliaddr; + socklen_t cliaddrlen = sizeof(cliaddr); + memset(g_ui_json_buffer, 0x00, UI_JSON_BUFFER_SIZE); + int bytes_received = recvfrom(s_ui_json_sockfd, g_ui_json_buffer, UI_JSON_BUFFER_SIZE, 0, + (struct sockaddr *)&cliaddr, &cliaddrlen); + if (bytes_received < 0) + { + LV_LOG_ERROR("recvfrom failed: %s", strerror(errno)); + return false; + } + else + { + inet_ntop(AF_INET, &cliaddr.sin_addr, s_devMasterIp, sizeof(s_devMasterIp)); + uint16_t sender_port = ntohs(cliaddr.sin_port); + + LV_LOG_INFO("Received %ld bytes from %s:%d", bytes_received, s_devMasterIp, sender_port); + } + // printf("%s\n", g_ui_json_buffer); + + return ioc_ui_json_parse(g_ui_json_buffer); + } +#else + if(FD_ISSET(g_ui_json_eventfd, &readfds)) + { + uint64_t notify; + read(g_ui_json_eventfd, ¬ify, sizeof(notify)); + return ioc_ui_json_parse(g_ui_json_buffer); + } +#endif + } + + return s_ui_json_changed; +} + + +void ioc_ui_json_set_active_idx(int idx) +{ + // g_ui_json.active_connector_idx = 0; + // return; + // LV_LOG_WARN("====idx[%d] active_idx[%d]", idx, g_ui_json.active_connector_idx); + + if (idx != g_ui_json.active_connector_idx) + { + LV_LOG_WARN("active_idx %d->%d", g_ui_json.active_connector_idx, idx); + g_ui_json.active_connector_idx = idx; + + s_ui_json_changed = true; + } +} + +void ioc_ui_json_handle_over(void) +{ + s_ui_json_changed = false; +} + +void ioc_ui_overtime_changed_page(void) +{ + s_ui_json_changed = true; +} + +bool ioc_conntype_isAC(int idx) +{ + return ((UI_CONNECTOR_CONN_TYPE(idx) == HWCFG_CONN_TYPE_GBT_AC) || ((UI_CONNECTOR_CONN_TYPE(idx) >= HWCFG_CONN_TYPE_SAE_AC) && (UI_CONNECTOR_CONN_TYPE(idx) <= HWCFG_CONN_TYPE_SCHUKO))); +} diff --git a/ioc/uijson/ui_json.h b/ioc/uijson/ui_json.h new file mode 100644 index 000000000..abcb31fb4 --- /dev/null +++ b/ioc/uijson/ui_json.h @@ -0,0 +1,563 @@ +#ifndef __UI_JSON_H__ +#define __UI_JSON_H__ + +#include "const_name.h" + +#define BOARD_MAX_CONNECTOR_NUM 24 // 分体桩最多可能支持24个枪 + +#if (COMPILER_FOR == COMPILE_FOR_DC_AM3354) +#define UI_MAX_CONNECTOR_NUM 4 +#else +#define UI_MAX_CONNECTOR_NUM 2 +#endif + +#define UIMSG_ACTIVE_IDX "activeConnIdx" // 界面切换枪号 +#define UIMSG_USE_CREDITCARD "useCreditCard" // 用户选择信用卡 +#define PREAUTH_AMOUNT "PreAuth" // 预授权额度 +#define STOP_PLUG_CHARGING "stopPlugCharging" // 停止插枪即充启动的充电进程 +#define START_CHARGING "startCharging" // 开始一个无卡充电 + +#define UI_JSON_I_UNIT (0.1) +#define UI_JSON_V_UNIT (0.1) +#define UI_JSON_Q_UNIT (0.001) +#define UI_JSON_P_UNIT (0.001) +#define UI_JSON_Q_4_DOT_UNIT (0.0001) + +#define IOC_PATH "/tmp/Ioc/" + +#define UI_JSON_BUFFER_SIZE (1024 * 16 * 6) +extern char g_ui_json_buffer[UI_JSON_BUFFER_SIZE]; +extern int g_ui_json_eventfd ; +typedef enum +{ + TEST_READ, + TEST_GREEN, + TEST_BULE, + + TEST_COLOR_NUM +}trigger_test_color_type; +// -------------------- M1768相关 -------------------- + +typedef enum +{ + M1768_STATE_AC_1_Idle = 0, // 1. 插枪 12V->9V (这一步不在1768监控范围内), 1768接收到启动命令后跳转到状态2 + M1768_STATE_AC_2_SelfCheckLock, // 2. 桩自检并锁枪,成功则输出PWM 9V->9V PWM,进入状态3 + M1768_STATE_AC_3_Wait_S2_Close, // 3. 桩进入等待S2状态, 车检测PWM后闭合S2,9V PWM-> 6V PWM, 此过程无超时检测,车可以在任意上时刻进入S2闭合,检测到之后进入状态4 SUSPENDEV状态开始 + M1768_STATE_AC_4_K1K2_ON, // 4. 桩闭合K1K2(3秒内), 6V PWM + K1K2闭合,等待实际电流输出,成功则进入状态5 离开SUSPENDEV状态 + M1768_STATE_AC_5_Charging, // 5. 车启动充电,桩进入充电监控状态, 6V PWM + K1K2闭合 + 实际电流输出 + M1768_STATE_AC_V3_EV_STOP, // V3. 桩检测到S2断开需要在100ms内打开K1K2,并保持PWM输出,9V PWM + K1K2闭合 + 小或无电流输出 -> 9V PWM + K1K2打开, 然后不等待,进入状态3 + M1768_STATE_AC_U1_EVSE_STOP, // U1. 桩切换PWM到+12V 状态(关PWM,实际因为枪连接着,输出不是12V), 等待车响应并打开S2, 6V PWM + K1K2闭合 + 实际电流输出 -> 6V + K1K2闭合 + 实际电流输出 + M1768_STATE_AC_U2_K1K2_OFF, // U2. 桩打开K1K2(S2断开后的100ms内), 9V(6V) + K1K2闭合 + 小或无电流输出 -> 9V(6V) + K1K2打开 + M1768_STATE_AC_U3_Unlock, // U3. 桩在100ms内开始解锁,5秒内完成解锁,9V ,解锁成功进入U4,即1状态 + M1768_STATE_AC_END, + M1768_STATE_AC_E_FAULT, // 桩故障状态 + + M1768_STATE_AC_NUM +} M1768_ConnState_AC_t; + +// ======= 子阶段, 用于lcd显示 +// 握手阶段 +typedef enum { + RNL_SHAKEHANDS_WAIT_BHM = 1, + RNL_SHAKEHANDS_INSU, + RNL_SHAKEHANDS_WAIT_BRM, + RNL_SHAKEHANDS_WAIT_BCP +} Charger_RNL_Shakehands_t; + +// 参数配置阶段 +typedef enum { + RNL_PRECHARGE_WAIT_BRO = 1, + RNL_PRECHARGE_INSU, + RNL_PRECHARGE_WAIT_BCL, + RNL_PRECHARGE_WAIT_K1K2, + RNL_PRECHARGE_WAIT_BCS, +} Charge_RNL_PreCharge_t; + +// 握手阶段 +typedef enum { + GBT_SHAKEHANDS_WAIT_BHM = 1, + GBT_SHAKEHANDS_INSU, + GBT_SHAKEHANDS_WAIT_BRM, + GBT_SHAKEHANDS_WAIT_BCP +} Charge_Shakehands_t; + +// 参数配置阶段 +typedef enum { + GBT_PRECHARGE_WAIT_BRO = 1, + GBT_PRECHARGE_CHKBAT, + GBT_PRECHARGE_WAIT_BCS, + GBT_PRECHARGE_WAIT_K1K2 +} Charge_PreCharge_t; +typedef enum +{ + M1768_STATE_GBT_IDLE = 0, + M1768_STATE_GBT_START, + M1768_STATE_GBT_SELF_CHECK, + M1768_STATE_GBT_HANDSHAKE, + M1768_STATE_GBT_PRRAMETER, + M1768_STATE_GBT_CHARGING, + M1768_STATE_GBT_START_TERMING, + M1768_STATE_GBT_TERMING, + M1768_STATE_GBT_END, + M1768_STATE_GBT_FAULT, + + M1768_STATE_GBT_NUM +} M1768_ConnState_GBT_t; + +typedef enum +{ + M1768_STATE_CHADEMO_IDLE = 0, + M1768_STATE_CHADEMO_START, + M1768_STATE_CHADEMO_INFORMATION_EXCHANGE, + M1768_STATE_CHADEMO_LOCK, + M1768_STATE_CHADEMO_PREPARING, + M1768_STATE_CHADEMO_CHARGING, + M1768_STATE_CHADEMO_BEGIN_TERM, + M1768_STATE_CHADEMO_TERMING, + M1768_STATE_CHADEMO_UNLOCK, + M1768_STATE_CHADEMO_END, + M1768_STATE_CHADEMO_FAULT, + + M1768_STATE_CHADEMO_NUM +} M1768_ConnState_CHAdeMO_t; + +// ---------------------------------------------------------------- + + +// 定义功能按键的功能 +#define KEY_FUNC_SWITCH_OUTPUT ((uint32_t)1 << 0) // 调节输出电流 +#define KEY_FUNC_SWTICH_DELAYTIMER ((uint32_t)1 << 1) // 调节延时Timer +#define KEY_FUNC_SELECT_CONN ((uint32_t)1 << 2) // 在A/B枪之间切换 +#define KEY_FUNC_SELECT_CONN_A ((uint32_t)1 << 3) // 切换到A枪 +#define KEY_FUNC_SELECT_CONN_B ((uint32_t)1 << 4) // 切换到B枪 +#define KEY_FUNC_RFID_START ((uint32_t)1 << 5) // 无卡启动充电 +#define KEY_FUNC_RFID_STOP ((uint32_t)1 << 6) // 无卡强行停止充电 (直流桩虚拟按钮强制停止各种类型启动的充电) +#define KEY_FUNC_SWITCH_LANGUAGE ((uint32_t)1 << 7) // 切换lcd语言 +#define KEY_FUNC_SWITCH_ECOMODE ((uint32_t)1 << 8) // 切换负载均衡的 master.chargerMode + + +// -------------------- 软件功能开关 -------------------- +#define SW_FUNC_LCD_IDLE_ONRF ((uint32_t)1 << 0) // 空闲状态下是否显示刷卡 0显示请插枪 +#define SW_FUNC_HIDE_TEMP_DISPLAY ((uint32_t)1 << 1) // 20220316 废弃原功能, 替换为隐藏温度功能 香港客户提出的特殊需求, Smart Charging的Duration当成充电持续时间 +#define SW_FUNC_CHARGE_ON_PLUG ((uint32_t)1 << 2) // 插枪即充 +#define SW_FUNC_ICCARD_FORMAT_BIG_ENDIAN ((uint32_t)1 << 3) // IC卡号是否大端模式 +#define SW_FUNC_TOUCH_LCD ((uint32_t)1 << 4) // 是否是迪文的触摸串口屏 (由于显示相同逻辑, 只是增加了触摸功能, 顾不用RO设置, 改为软件设置) +#define SW_FUNC_ENABLE_ENGINEERING_MODE ((uint32_t)1 << 5) // 是否允许工程师模式 +#define SW_FUNC_NOT_PERMIT_CONCURRENT_TX ((uint32_t)1 << 6) // 是否允许Auth返回ConnCurrentTx继续充电, 默认允许 +#define SW_FUNC_OFFLINE_ADD_RFID ((uint32_t)1 << 7) // 是否允许离线增/删RFID +#define SW_FUNC_ENABLE_STATION_CODE ((uint32_t)1 << 8) // 是否启用StationCode追加在二维码中 +#define SW_FUNC_ENABLE_CHECK_LOCK ((uint32_t)1 << 9) // 是否启用锁枪检测 +#define SW_FUNC_KEEP_LOCK_FINISH ((uint32_t)1 << 10) // 停充的时候是否保持锁定,默认否, 如果是, 需要远程下发Unlock命令解锁 +#define SW_FUNC_PREVENT_START_PE_RCD ((uint32_t)1 << 11) // 当因为PE/RCD故障停止充电时, 是否阻止再次启动, 默认否10秒后可以再次启动, 选为是则必须断电重启 +#define SW_FUNC_QR_WIFI ((uint32_t)1 << 12) // 二维码显示WiFi-AP+SN信息 +#define SW_FUNC_LCD_IDLE_SHOW_WELCOME ((uint32_t)1 << 13) // 空闲时返回welcome界面 +#define SW_FUNC_DISABLE_RECOVERY_SESSION ((uint32_t)1 << 14) // 异常断电是否自动恢复充电, 默认自动恢复 +#define SW_FUNC_CURRLMT_REPORT ((uint32_t)1 << 15) // 是否上报StateMngr判断电流限制变化给后台, 默认关闭, 防止某些后台无法处理 +#define SW_FUNC_METERVALUES_WITH_DEFAULT ((uint32_t)1 << 16) // MeterValues上报时是否上传完整内容, 默认关闭以节省流量, 打开以适应部分运营商 +#define SW_FUNC_ENABLE_CCS_PLUG_CHARGE ((uint32_t)1 << 17) // CCS充电枪是否支持Plug & Charge功能, 当未授权且插枪时, 启动充电, 使用evccid来Authorization +#define SW_FUNC_METERVALUES_OF_CREDIT ((uint32_t)1 << 18) // 信用卡启动的充电不上报MeterValues, 默认不上报, 打开上报,以适应部分运营商 +#define SW_FUNC_EXCLUDE_VIN_MARK_IN_IDTAG ((uint32_t)1 << 19) // VIN前缀不上报后台只报值部分, 默认需要上报(主流后台), 打开则不上报,以适应部分运营商 +#define SW_FUNC_SUSPEND_BY_EV_STOP ((uint32_t)1 << 20) // 与车数字通讯(包括PLC)的情况下, EV正常停充(SoC到达)时, 进入SuspendEv状态, 默认false 进入Finished状态 +#define SW_FUNC_DISABLE_STOPBTN_OF_CREDIT ((uint32_t)1 << 21) // 禁止按键停充信用卡启动的充电 + +// --------------------------------------------------------- +typedef enum +{ + IdTagType_Normal = 0, // 普通idTag (RFID/RemoteId) + + IdTagType_LocalStart, // 本地自动启动充电的卡号(按钮/即插充), 默认 FFFFFFFF + + IdTagType_PlugChargeDefault, // CCS EIM(EVCCID) GBT(VIN) CCS PnC 方式启动充电时的初始默认卡号 + IdTagType_CCS_EVCCID, // CCS EIM(EVCCID) + IdTagType_GBT_VIN, // GBT EIM(VIN) + IdTagType_CCS_PnC, // CCS PnC + + IdTagType_CreditCard, // 信用卡启动的 + + IdTagType_NUM +} IdTagType_t; +typedef enum +{ + CURRENCY_USD, + CURRENCY_GBP, + CURRENCY_EUR, + CURRENCY_RUB, + CURRENCY_CNY, + CURRENCY_SEK, + CURRENCY_PLN, + + CURRENCY_NUM +}CurrencyType_t; + +typedef struct +{ + CurrencyType_t idx; + char * code; + char * icon; + +}UI_CurrencyMap_t; + +typedef struct +{ + uint16_t startMin; // 开始时间,距离00:00的分钟数 + uint16_t endMin; // 结束时间 + + double kWhPrice; // 按电量的价格 + double hourPrice; // 按时间的价格 + double flatFee; // 固定费用 + + char priceText[255 + 1]; // OcppPrice需要显示的默认价格文本 + +} UI_PriceInfo_t; + +typedef struct +{ + double totalCost; // 总费用 + double reserveIdleCost; // 预约费用 + double suspendIdleCost; // 充电中占位费 + double stopIdleCost; // 充电完成后的占位费 + +} UI_CostInfo_t; + +typedef enum +{ + PHASE_L1 = 0, + PHASE_L2 = 1, + PHASE_L3 = 2, + + PHASE_NUM +} PhaseNum_t; + +typedef struct +{ + double voltage[PHASE_NUM+1]; // 3相电压, 最后一个表示三相平均电压(无效相不参与计算) + + double current[PHASE_NUM+1]; // 3相电流, 最后一个表示三相平均电流(无效相不参与计算) + double Q[PHASE_NUM+1]; // kWh, 最后一个表示总电能 + uint8_t fourthQ; // Q 的第4位小数 + uint8_t startQ4dot; // Q 起始的第4位小数 + + double power; // kW功率 + +}UI_MeterData_t; + +typedef enum +{ + CHARGER_SCREEN_MSG_NO_CONN_SELECTED, // Please select a connector firstly + CHARGER_SCREEN_MSG_FAILED_TO_START_CHARGING, //Failed to start charging + CHARGER_SCREEN_MSG_FAULT_FOUND_STOP_CHARGING, //Fault found, Stop Charging + CHARGER_SCREEN_MSG_NOT_PERMIT, //Not Permit + CHARGER_SCREEN_MSG_ADDRFID, + CHARGER_SCREEN_MSG_CLEARRFID, + + CHARGER_SCREEN_MSG_CCS_AUTOCHARGE_BIND, // 提醒用户刷卡或远程启动完成自动充电 + + // CHARGER_SCREEN_MSG_GROUND_FAULT, + + CHARGER_SCREEN_MSG_NONE +} Charger_Screen_Display_Msg_t; + +typedef enum +{ + CHARGER_SCREEN_AUTH_FAIL_OTHER, + CHARGER_SCREEN_AUTH_FAIL_BLOCKED, + CHARGER_SCREEN_AUTH_FAIL_EXPIRED, + CHARGER_SCREEN_AUTH_FAIL_INVALID, + CHARGER_SCREEN_AUTH_FAIL_CONCURRENTTX, + CHARGER_SCREEN_AUTH_SUCCESS, +}Charger_Screen_Auth_Reason_t; + +typedef enum +{ + CHARGER_SCREEN_CREDIT_POINT, + CHARGER_SCREEN_CREDIT_NO_CONN_SELECTED, + CHARGER_SCREEN_CREDIT_PREAUTH_FAILED, // 预授权失败 + CHARGER_SCREEN_CREDIT_PREAUTH_SUCCESS, // 预授权成功 + CHARGER_SCREEN_CREDIT_SETTLEMENT_FAILED, // 结算失败 + CHARGER_SCREEN_CREDIT_SETTLEMENT_SUCCESS, // 结算成功 + CHARGER_SCREEN_CREDIT_WATTING, // "POS机正在处理请求,请等待" + CHARGER_SCREEN_CREDIT_VPOS_BUSY, // "POS机正在处理其他请求,请稍后再试" + CHARGER_SCREEN_CREDIT_VPOS_FAULT, // "POS机出现故障,请联系工作人员" +}Charger_Screen_CreditCard_t; + +/* + *********************************************************************** + 以下属于触发性命令 + { + "Trigger" : "Downloading", // "Cancel", "Downloading", "Installing", "Debug", "Prompt", "Auth", "Test", + "Message","Notify","MessageCancel","NotifyCancel", "CreditCard" + "percent" : 35, // "Downloading" "Installing" 才支持 + "enter" : true, // "Debug" 才支持 + "Msg" : 0, // Prompt => Charger_Screen_Display_Msg_t, Auth => Charger_Screen_Auth_Reason_t + // Test: 0:显示红色 1:显示绿色 2:显示蓝色, CreditCard => Charger_Screen_CreditCard_t + "seconds" : 1, // 提示框显示秒数 + "Content":"1234567" // 弹窗显示的文本内容 + + } + + "Cancel": 立即清除所有提示框 + "Downloading",: 显示下载中提示框, 不调用Cancel就永远显示 + "Installing",: 显示升级中提示框, 不调用Cancel就永远显示, + "Debug": 显示调试信息, 需要显示"homeOcpp.%04d-%02d-%02d.log"文件的内容, 实现tail -f功能 + "Prompt": 显示提示框, 对应于 Charger_Screen_Msg_Display 函数 + "Auth":显示提示框, 对应于 Charger_Screen_Auth_Reason_Set 函数 + "Test": 显示测试界面,根据Msg内容显示 0:显示红色 1:显示绿色 2:显示蓝色 + "Message": 显示中部弹窗 + "Notify": 显示底部弹窗 + "MessageCancel": 清除中部弹窗 + "NotifyCancel": 清除底部弹窗 + "CreditCard": 信用卡提示界面 + + *********************************************************************** + */ +typedef struct +{ + char trigger[16]; + unsigned short percent; + uint8_t msg; + int seconds; + char content[512 + 1]; + char billUrlStr[256 + 1]; + char receiptUrlStr[256 + 1]; + int idx; + char action[64 + 1]; + +}ioc_ui_trigger_t; + + +typedef enum { + UI_CONNECTOR_STATE_HOME = 0, + UI_CONNECTOR_STATE_IDLE, + UI_CONNECTOR_STATE_STARTING1, + UI_CONNECTOR_STATE_STARTING2, + UI_CONNECTOR_STATE_CHARGING, + UI_CONNECTOR_STATE_FINISHED, + UI_CONNECTOR_STATE_RESERVED, + UI_CONNECTOR_STATE_SESSION_ERROR, + UI_CONNECTOR_STATE_START_ERROR, + UI_CONNECTOR_STATE_FAULT, + UI_CONNECTOR_STATE_UNAVAILABLE, + UI_CONNECTOR_STATE_CONNECTING, + UI_CONNECTOR_STATE_STOPPING, + UI_CONNECTOR_STATE_WAIT_IN_LINE, + UI_CONNECTOR_STATE_SUSPEND, + UI_CONNECTOR_STATE_PROCESSING, + + UI_CONNECTOR_STATE_MAX, +} ioc_ui_connector_state_t; + +typedef enum +{ + STARTING_HANDSHAKE = 0, + STARTING_INSULATION, + STARTING_PARAMTETER, + STARTING_PRECHARGE, + + STARTING_AC, // AC充电无子状态 + + STARTING_NUM, + +} Starting_SubStep_t; + +typedef struct +{ + Charger_CONNType_t conn_type; + int rated_power; + + ioc_ui_connector_state_t state; // 根据UI.json计算出当前枪应该显示哪个状态 + bool showPrice; // 是否显示价格 + bool isOcppPrice; // 是否是OcppPrice体系,如果是的话默认价格显示文本 + bool isQ4dot; // 电量显示四位小数 + struct + { + struct { + UI_PriceInfo_t currPrice; // 当前价格 + UI_PriceInfo_t nextPrice; // 下一时段价格 + + } idle; + + struct { + UI_PriceInfo_t currPrice; + UI_PriceInfo_t nextPrice; + char connQR[255+1]; + + } starting; + + struct { + UI_PriceInfo_t currPrice; // 当前价格 + UI_CostInfo_t cost; // 费用信息 + UI_MeterData_t meterData; // 电表数据 + int soc; + time_t startTime; // 起充时间 + + } charging; + + struct { + UI_CostInfo_t cost; // 费用信息 + double actualMeter; // 充电电量 + uint8_t fourthQ; // actualMeter 的第4位小数 + int duration; // 充电时长 + int startSoc; // 起充Soc + int stopSoc; // 停止Soc + time_t startTime; // 开始启动充电的时间 + time_t stopTime; // 结束充电的时间 + + }finished; + + struct { + UI_PriceInfo_t currPrice; + UI_PriceInfo_t nextPrice; + time_t reverseTime; // 预约结束的时间点 + + }reserved; + + } state_data; + + char _status_real[20+1]; + char stateMngrInfo_runState[20+1]; + char m1768Info_runState[50+1]; + uint16_t m1768errCode; + uint8_t stopCode; + char connStatus[20+1]; + char idTag[20+1]; + char _errCode[50+1]; + char connCode[20+1]; + IdTagType_t idType; + bool plug; // 是否插枪,用于保存插枪状态 + + // charging detail data + uint8_t subState; + int startSoc; + double reqVol; + double reqCur; + int temp; + double offerVol; + double offerCur; + double outLimit; + char outLimitUnit[5+1]; + int compGroup; + + Starting_SubStep_t startingSubStep; + +} ioc_ui_json_connector_t; + +typedef enum { + CHARGER_GUN_TYPE_SINGLE = 1, // 单枪 + CHARGER_GUN_TYPE_DUAL = 2, // 双枪 + CHARGER_GUN_TYPE_TRIPLE = 3, // 三枪 + CHARGER_GUN_TYPE_QUAD = 4 // 四枪 +} ChargerGunType_t; + + +typedef struct +{ + uint8_t location; // 屏幕在哪个终端上 + uint8_t connNum; // 屏幕显示多少根枪 + uint8_t connIdx[UI_MAX_CONNECTOR_NUM]; // 屏幕显示哪几根枪 + uint8_t autGroup; // 屏幕属于哪个授权组 + +}ioc_ui_dispenser_config_t; + +typedef struct +{ + time_t activeTime; // 桩下发激活的时间戳 + + uint8_t brightIdle; // 待机状态亮度, 0-5, 0全黑, 5最亮 + uint8_t brightActive; // 激活状态亮度, 1-5, 1最暗, 5最亮 + uint8_t brightCharging; // 充电状态亮度, 1-5, 1最暗, 5最亮 + uint8_t timeoutActive; // 激活->待机状态超时时间, 1-5分钟, 充电中常亮 + +} ioc_ui_biright_t; + +typedef struct +{ + bool meterFault; + bool rfFault; + bool online; + uint8_t ethStatus; + uint8_t wifiStatus; + uint8_t m4gStatus; + + char httpAddr[100 + 1]; + +}ioc_ui_drvPointInfo_t; + + +# define KEY_FUNC_COUNT 3 +typedef struct +{ + ioc_ui_trigger_t trigger; + + Language_t language; + + ioc_ui_json_connector_t connectors[UI_MAX_CONNECTOR_NUM]; + int connector_num; + + int active_connector_idx; + bool enPOS; // 是否启用了POS机 + bool enSoftKey; // 是否启用了软键盘 + uint8_t timeZone; // 配置的时区 + + char currencyIcon[3 + 1]; // 货币单位图标 + char currencyCode[3 + 1]; // 货币代码 + uint8_t costPriceDecimalPlaces; // 费用价格小数位数 + bool isUiJsonControlLocked[CHARGER_GUN_TYPE_QUAD]; + + bool getMqttDataFlag; // 从MQTT获取UI数据标志 + ioc_ui_dispenser_config_t dispenserConfig; + + bool isFirstUIjson; // 是否是第一次获取UIjson数据 + + ioc_ui_biright_t biright; // 设置屏幕亮度相关配置 + + uint32_t swFunc; // 功能开关 + uint32_t keyFunc[KEY_FUNC_COUNT]; // 三个功能按钮的功能 + bool isAutoCCS; // 是否CCS 自动充电时 + + ioc_ui_drvPointInfo_t drvPointInfo; // rf meter net等状态信息 + +} ioc_ui_json_t; + + +bool ioc_ui_json_init(void); +bool ioc_ui_json_step(void); +void ioc_ui_json_handle_over(void); + +extern ioc_ui_json_t g_ui_json; +extern const UI_CurrencyMap_t c_CurrencyMaps[]; + +#define UI_NUMOFCONNECTOR (g_ui_json.connector_num) +#define UI_ENABLEPOS (g_ui_json.enPOS) +#define UI_ENABLESOFTKEY (g_ui_json.enSoftKey) +#define UI_CONNECTOR_ACTIVE_IDX (g_ui_json.active_connector_idx) +// #define UI_CONNECTOR_STARID (g_ui_json.dispenserConfig.connStarId) +#define UI_FIRST_JSON (g_ui_json.isFirstUIjson) +#define UI_SWFUNC (g_ui_json.swFunc) +#define UI_KEYFUNC(indx) (g_ui_json.keyFunc[indx]) + + +#define UI_CONNECTOR_CONN_TYPE(idx) (g_ui_json.connectors[idx].conn_type) +#define UI_CONNECTOR_CONN_TYPE_NAME(idx) (ioc_ui_json_get_conn_type_name(g_ui_json.connectors[idx].conn_type)) +#define UI_CONNECTOR_RATED_POWER(idx) (g_ui_json.connectors[idx].rated_power) +#define UI_CONNECTOR_STATE(idx) (g_ui_json.connectors[idx].state) +#define UI_CONNECTOR_STATE_NAME(idx) (ioc_ui_json_get_state_name(g_ui_json.connectors[idx].state)) +#define UI_CONNECTOR_SHOWPRICE(idx) (g_ui_json.connectors[idx].showPrice) +#define UI_CONNECTOR_ISOCPPRICE(idx) (g_ui_json.connectors[idx].isOcppPrice) +#define UI_CONNECTOR_ISQ4DOT(idx) (g_ui_json.connectors[idx].isQ4dot) +#define UI_CONNECTOR_ERRCODE (g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX]._errCode) +#define UI_CONNECTOR_IDTAG(idx) (g_ui_json.connectors[idx].idTag) +#define UI_CONNECTOR_IDTYPE(idx) (g_ui_json.connectors[idx].idType) + + +void ioc_ui_json_set_active_idx(int idx); +void ioc_ui_overtime_changed_page(void); +void ioc_send_UseCreditCard(int idx, int PerAuth); +void ioc_send_ConnSelected(int idx); +void ioc_send_StopPlugCharging(int idx); +void ioc_send_StartCharging(int idx); +bool ioc_ui_json_set_conn_state(int idx, ioc_ui_connector_state_t state); +bool ioc_conntype_isAC(int idx); +bool ioc_ui_json_parse(const char *json_str); +bool ioc_ui_json_set_con_num(int num); + +#endif diff --git a/ioc/zlog/Charger_DrvPoint_DEBUG.c b/ioc/zlog/Charger_DrvPoint_DEBUG.c new file mode 100644 index 000000000..543033b8e --- /dev/null +++ b/ioc/zlog/Charger_DrvPoint_DEBUG.c @@ -0,0 +1,163 @@ + +#include "ioc_app.h" +#include "zlog.h" + +#include +#include + +typedef time_t dateTime; + +#define LOG_FILE_SELF_PREFIX "lvgl" + +#define LOG_FILE_SIZE_LIMIT "256KB * 1" + +#ifndef MODBUS_MASTER +#define ZLOG_CONF_FILE "/tmp/zlog_config_dispenser_lvgl.conf" +#define ZLOG_LOCK_FILE "/tmp/zlog_config_dispenser_lvgl.lock" +#else +#define ZLOG_CONF_FILE "/tmp/zlog_config_modbus.conf" +#define ZLOG_LOCK_FILE "/tmp/zlog_config_modbus.lock" +#endif + +static char ZLOG_EXT_PATH[32] = ""; +static dateTime s_zlogLoadTime = 0; + +zlog_category_t *c_charger = NULL; +zlog_category_t *c_hex = NULL; + + +char RUNDIR[512]; + +void Zlog_GenerateConf() +{ + char confBuffer[8192] = ""; + + strcat(confBuffer, "[global]\n"); + strcat(confBuffer, "strict init = true\n"); + strcat(confBuffer, "buffer min = 1024\n"); + strcat(confBuffer, "buffer max = 2MB\n"); + strcat(confBuffer, "rotate lock file = "ZLOG_LOCK_FILE"\n"); + strcat(confBuffer, "default format = \"[%d(%T).%ms|%f|%L]%m%n%n\"\n"); + strcat(confBuffer, "file perms = 600\n"); + strcat(confBuffer, "\n"); + strcat(confBuffer, "[levels]\n"); + strcat(confBuffer, "TRACE = 10\n"); + strcat(confBuffer, "CRIT = 130, LOG_CRIT\n"); + strcat(confBuffer, "\n"); + strcat(confBuffer, "[formats]\n"); + strcat(confBuffer, "fileFormat = \"[%d(%T).%ms]%m%n%n\"\n"); + strcat(confBuffer, "hexFileFormat = \"[%d(%T).%ms]%m%n%n\"\n"); + strcat(confBuffer, "\n"); + strcat(confBuffer, "[rules]\n"); +#ifdef x86 + strcat(confBuffer, "charger.DEBUG >stdout; fileFormat\n"); +#else + // 网跑状态直接输出日志 + const char * DftPath = "/mnt/"; + if (memcmp(RUNDIR, DftPath, strlen(DftPath)) == 0) + { + strcat(confBuffer, "charger.DEBUG >stdout; fileFormat\n"); + } +#endif +#ifndef MODBUS_MASTER + strcat(confBuffer, "charger.DEBUG \""IOC_PATH"" LOG_FILE_SELF_PREFIX ".%d(%F).log\", "LOG_FILE_SIZE_LIMIT";fileFormat\n"); +#else + strcat(confBuffer, "charger.DEBUG \""IOC_PATH"master.%d(%F).log\", "LOG_FILE_SIZE_LIMIT";fileFormat\n"); +#endif + strcat(confBuffer, "\n"); +#ifdef x86 + strcat(confBuffer, "hex.DEBUG >stdout; hexFileFormat\n"); +#endif +#ifndef MODBUS_MASTER + strcat(confBuffer, "hex.DEBUG \""IOC_PATH""LOG_FILE_SELF_PREFIX".%d(%F).log\", "LOG_FILE_SIZE_LIMIT";fileFormat\n"); +#else + strcat(confBuffer, "hex.DEBUG \""IOC_PATH"master.%d(%F).log\", "LOG_FILE_SIZE_LIMIT";fileFormat\n"); +#endif + strcat(confBuffer, "\n"); + + if (ZLOG_EXT_PATH[0] != '\0') + { + strcat(confBuffer, "charger.DEBUG \""); + strcat(confBuffer, ZLOG_EXT_PATH); +#ifndef MODBUS_MASTER + strcat(confBuffer, LOG_FILE_SELF_PREFIX ".%d(%F).log\", 100MB;fileFormat\n"); +#else + strcat(confBuffer, "master.%d(%F).log\", 100MB;fileFormat\n"); +#endif + strcat(confBuffer, "hex.DEBUG \""); + strcat(confBuffer, ZLOG_EXT_PATH); +#ifndef MODBUS_MASTER + strcat(confBuffer, LOG_FILE_SELF_PREFIX ".%d(%F).log\", 100MB;hexFileFormat\n"); +#else + strcat(confBuffer, "master.%d(%F).log\", 100MB;hexFileFormat\n"); +#endif + strcat(confBuffer, "\n"); + } + + FILE * fp = fopen(ZLOG_CONF_FILE, "w+"); + if (fp == NULL) + { + printf("can't open "ZLOG_CONF_FILE); + return; + } + + fputs(confBuffer, fp); + + fclose(fp); +} + +int Zlog_Load(bool init) +{ + int rc; + + // 根据当前外置存储生成配置文件 + Zlog_GenerateConf(); + + if (init) + { + rc = zlog_init(ZLOG_CONF_FILE); + } + else + { + rc = zlog_reload(ZLOG_CONF_FILE); + } + if (rc) + { + printf("init %d failed\n", init); + return -1; + } + + c_charger = zlog_get_category("charger"); + if (!c_charger) + { + printf("get c_charger fail\n"); + zlog_fini(); + return -2; + } + + c_hex = zlog_get_category("hex"); + if (!c_hex) + { + printf("get c_hex fail\n"); + zlog_fini(); + return -2; + } + + time_t now = time(NULL); + s_zlogLoadTime = now; + + zlog_notice(c_charger, "ZlogInit(%d) for "ZLOG_CONF_FILE" EXT %s\n", init, ZLOG_EXT_PATH); + return 0; +} + +int Charger_zlog_init() +{ + printf("zlog_init!\n"); + return Zlog_Load(true); +} + +void Charger_zlog_release() +{ + zlog_fini(); +} + diff --git a/ioc/zlog/Charger_ErrCode.h b/ioc/zlog/Charger_ErrCode.h new file mode 100644 index 000000000..e659b027b --- /dev/null +++ b/ioc/zlog/Charger_ErrCode.h @@ -0,0 +1,385 @@ +#ifndef __CHARGER_ERROR_CODE_H__ +#define __CHARGER_ERROR_CODE_H__ + +#ifdef __cplusplus +extern "C" { +#endif +// 返回值标准定义 U32 +// 最高位1表示错误,0表示无错误 +// 31 30-24 23-16 15-0 +// Err Module Main Module Sub ErrorCode + +// 所有模块的错误码在本文件定义,不允许私自定义 +// ErrorCode总共16位,其中0-255保留给通用,各模块自定义errorCode从256开始编号 +// Debug模块为每个类型的枚举设定一个标准的字符串数组用于描述故障 + +#define GENMOD_ERROR_SUCCESS_BASE 0 +#define GENMOD_ERROR_FAIL_BASE 16 +#define SUBMOD_ERROR_CODE_BASE 256 + +// SUCCESS CODE 只能在Charger_Errcode_GeneralSuc_t 中间选择,最多16个 +#define RTN_SUC(SUCCODE) (((Charger_U32)0 << 31) | ((Charger_U32)MOD << 24) | ((Charger_U32)SUBMOD << 16) | ((Charger_U32)SUCCODE << 0)) + +// ERROR CODE 可以在Charger_Errcode_GeneralFail_t 和各个子模块类似Charger_Errcode_1768Fail_t 中选取 +#define RTN_ERR(ERRCODE) (((Charger_U32)1 << 31) | ((Charger_U32)MOD << 24) | ((Charger_U32)SUBMOD << 16) | ((Charger_U32)ERRCODE << 0)) + +#define IS_RTNSUC(CODE) (((Charger_U32)(CODE)&0x80000000) == 0x00000000) +//#define IS_RTNERR(CODE) (((Charger_U32)(CODE)&0x80000000) == 0x80000000) +#define ERRCOEE(CODE) ((Charger_U32)(CODE)&0xFF) + +typedef enum +{ + DEBUG_LEVEL_NONE = 0, + DEBUG_LEVEL_ERROR, + DEBUG_LEVEL_WARN, + DEBUG_LEVEL_KEYI, + DEBUG_LEVEL_INFO, + + DEBUG_LEVEL_NUM +} Debug_Level_t; + +#include "zlog.h" + +extern zlog_category_t *c_charger; +extern zlog_category_t *c_hex; +#if 1 +#define ESC_START "\033[" +#define ESC_END "\033[0m" +// #define COLOR_FATAL "31;40;5m" +// #define COLOR_ALERT "31;40;1m" +// #define COLOR_CRIT "31;40;1m" +#define COLOR_ERROR "0;33m" +#define COLOR_WARN "0;36m" +#define COLOR_NOTICE "0m" +#define COLOR_INFO "0m" +// #define COLOR_DEBUG "36;40;1m" +// #define COLOR_TRACE "37;40;1m" +#else +#define ESC_START +#define ESC_END +// #define COLOR_FATAL +// #define COLOR_ALERT +// #define COLOR_CRIT +#define COLOR_ERROR +#define COLOR_WARN +#define COLOR_NOTICE +#define COLOR_INFO +// #define COLOR_DEBUG "36;40;1m" +// #define COLOR_TRACE "37;40;1m" +#endif + +int Charger_zlog_init(); +void Charger_zlog_release(); + +#define C_ZLOG_FATAL(format, args...) zlog_fatal(c_charger, ESC_START COLOR_ERROR format ESC_END, ##args) +#define C_ZLOG_ERR(format, args...) zlog_error(c_charger, ESC_START COLOR_ERROR format ESC_END, ##args) +#define C_ZLOG_WARN(format, args...) zlog_warn(c_charger, ESC_START COLOR_WARN format ESC_END, ##args) +#define C_ZLOG_NOTICE(format, args...) zlog_notice(c_charger, ESC_START COLOR_NOTICE format ESC_END, ##args) +#define C_ZLOG_INFO(format, args...) zlog_info(c_charger, ESC_START COLOR_INFO format ESC_END, ##args) +#define C_ZLOG_DEBUG(format, args...) zlog_debug(c_charger, ESC_START COLOR_INFO format ESC_END, ##args) + +#define CHARGER_DEBUG_FATAL(_X_) C_ZLOG_FATAL _X_ +#define CHARGER_DEBUG_ERROR(_X_) C_ZLOG_ERR _X_ +#define CHARGER_DEBUG_WARN(_X_) C_ZLOG_WARN _X_ +#define CHARGER_DEBUG_KEYI(_X_) C_ZLOG_NOTICE _X_ +#define CHARGER_DEBUG_INFO(_X_) C_ZLOG_INFO _X_ +#define CHARGER_DEBUG_DEBUG(_X_) C_ZLOG_DEBUG _X_ +#define CHARGER_DEBUG_DUMPDATA(_X_,_L_) hzlog_notice(c_hex, _X_,_L_) + + +#define DEBUG_ERR(ERRCODE,FMT,ARG...) CHARGER_DEBUG_ERROR((#ERRCODE " " FMT"", ##ARG)) +#define DEBUG_WARN(FMT,ARG...) CHARGER_DEBUG_WARN((FMT"", ##ARG)) +#define DEBUG_KEYI(FMT,ARG...) CHARGER_DEBUG_KEYI((FMT"", ##ARG)) +#define DEBUG_INFO(FMT,ARG...) CHARGER_DEBUG_INFO((FMT"", ##ARG)) +#define DEBUG_BUFF(BUFF,LEN) CHARGER_DEBUG_DUMPDATA(BUFF,LEN) + +#define UDP_BLUETOOTH_PORT 23460 // 蓝牙通讯端口, 蓝牙Python模块固定向此端口发送指令 +#define UDP_SELFCHECK_HOST_PORT 23459 // selfCheck默认发送的PC工具端口 +#define UDP_SELFCHECK_PORT 23458 // selfCheck程序绑定端口, 接收PC工具指令 +#define UDP_COMM7628_PORT 23457 // 7628-103 UDP通信, 7628端固定绑定端口 +#define UDP_RO_PORT 23456 // RO端口, 接收激活工具应答 +#define UDP_CONFIG_PORT 23455 // UdpConfig端口 +#define UDP_PRINT_PORT 23454 // 103主板UDP打印端口 +#define UDP_HUB_CT_PORT 22405 // hub上报 + +#define MODBUS_TCP_DEFAULT_LISTEN_PORT 22401 +#define MODBUS_GROUP_DEFAULT_LISTEN_PORT 10000 // master组广播基本端口 实际端口+组号 + +#define SENDUI_AM3354_SRC_PORT 20000 // 7628-LCD通讯端口, 7628/3354模块固定绑定此端口 +#define SENDUI_LCD3354_DST_PORT 20001 // 7628-LCD通讯端口, LCD模块固定绑定此端口 +#define UDP_CLIENT_PORT 13202 // 7628-103 UDP通信, 103端固定绑定端口 + +#define VPOS_TCP_PORT 33401 // POS机 TCP通讯端口 + +#define OPEN_DOOR_CHECK_PROT 11000 // 接收wifi模块上报的的开门检测信息 + +#define DEV_AUTO_GROUP_PORT 12000 // 外设自组网端口 + +typedef enum +{ + MOD_GENERAL = 0, + MOD_SYSCONFIG, + MOD_HAL, + MOD_DRVBOARD, + MOD_DRVPOINT, + MOD_1768, + MOD_CTRL, + + MOD_NUM +} Charger_ModuleLevel_t; + +typedef enum +{ + MOD_GENERAL_MAIN = 0, + + MOD_GENERAL_NUM +} Charger_ModGeneral_SubMod_t; + +typedef enum +{ + MOD_SYSCONFIG_MAIN = 0, + + MOD_SYSCONFIG_NUM +} Charger_ModSysConfig_SubMod_t; + +typedef enum +{ + MOD_HAL_MAIN = 0, + + MOD_HAL_NUM +} Charger_ModHAL_SubMod_t; + +typedef enum +{ + MOD_DRVBOARD_MAIN = 0, + MOD_DRVBOARD_BASE, + MOD_DRVBOARD_GPIO, + MOD_DRVBOARD_ADC, + MOD_DRVBOARD_RTC, + MOD_DRVBOARD_PWM, + MOD_DRVBOARD_TIM, + MOD_DRVBOARD_SPI, + MOD_DRVBOARD_UART, + MOD_DRVBOARD_WDG, + MOD_DRVBOARD_JDQ, + MOD_DRVBOARD_RCD, + MOD_DRVBOARD_UDP, + + MOD_BOARD_NUM +} Charger_ModDrvBoard_SubMod_t; + +typedef enum +{ + MOD_DRVPOINT_MAIN = 0, + MOD_DRVPOINT_BUTTON, + MOD_DRVPOINT_BEEP, + MOD_DRVPOINT_EMERGENCY, + MOD_DRVPOINT_FLASHEX, + MOD_DRVPOINT_METER, + MOD_DRVPOINT_RF, + MOD_DRVPOINT_CONNECTOR, + MOD_DRVPOINT_ETHERNET, + MOD_DRVPOINT_4G, + MOD_DRVPOINT_WIFI, + MOD_DRVPOINT_LED, + MOD_DRVPOINT_LCD, + MOD_DRVPOINT_DEBUG, + MOD_DRVPOINT_TF, + MOD_DRVPOINT_WEBSOCKET, + MOD_DRVPOINT_HTTPFTP, + MOD_DRVPOINT_IPCOM, + MOD_DEVPOINT_MQTT, + + MOD_DRVPOINT_NUM +} Charger_ModDrvPoint_SubMod_t; + +typedef enum +{ + MOD_1768_MNGR = 0, + MOD_1768_UPG, + + MOD_1768_NUM +} Charger_Mod1768_SubMod_t; + +enum +{ + MOD_CTRL_A_SECURITY = 0, + MOD_CTRL_B_PROVISIONING, + MOD_CTRL_C_AUTHORIZATION, + MOD_CTRL_D_LOCALAUTH, + MOD_CTRL_E_TRANSACTION, + MOD_CTRL_F_REMOTECONTROL, + MOD_CTRL_G_AVAILABLITY, + MOD_CTRL_H_RESERVATION, + MOD_CTRL_I_TARIFFCOST, + MOD_CTRL_J_METERVALUES, + MOD_CTRL_K_SMARTCHARING, + MOD_CTRL_L_FIRMWAREMNGR, + MOD_CTRL_M_ISO15118, + MOD_CTRL_N_DIAGNOSTICS, + MOD_CTRL_O_DISPLAYMESSAGE, + MOD_CTRL_P_DATATRANSFER, + + MOD_CTRL_0_CTRL = 0x30, + MOD_CTRL_0_CTRLMAIN, + MOD_CTRL_1_STATEMNGR, + MOD_CTRL_2_RESMNGR, + MOD_CTRL_3_LCD, + MOD_CTRL_3_UI, + MOD_CTRL_4_OCPP, + MOD_CTRL_5_MODBUSTCP, + + MOD_CTRL_STORAGE_OCPP20, + + MOD_CTRL_NUM_OCPP20 +}; + +enum +{ + MOD_CTRL_MAIN = 0, + MOD_CTRL_CTRL, + MOD_CTRL_STORAGE, + MOD_CTRL_AUTH, + MOD_CTRL_RECORDS, + MOD_CTRL_SESSION, + MOD_CTRL_RESERVATION, + MOD_CTRL_STATEMNGR, + MOD_CTRL_SMARTCHARGING, + MOD_CTRL_OCPP, + MOD_CTRL_UPGRADE, + MOD_CTRL_STATUSNOTIFY, + MOD_CTRL_DIAGNOSTICS, + MOD_CTRL_DATATRANSFER, + MOD_CTRL_RESMNGR, + MOD_CTRL_SETPLAN, + MOD_CTRL_MODBUS, + MOD_CTRL_VPOS, + MOD_CTRL_MQTT, + + MOD_CTRL_NUM_OCPP16 +}; + +typedef enum +{ + S_OK = GENMOD_ERROR_SUCCESS_BASE, + S_WAITING, + + GENERAL_S_NUM +} Charger_Errcode_GeneralSuc_t; + +typedef enum +{ + E_FAILED = GENMOD_ERROR_FAIL_BASE, + E_BAD_PARAM, + E_NOT_FOUND, + E_TIMEOUT, + E_OVERFLOW, + E_OUT_OF_RANGE, + E_NO_ENOUGH_MEMORY, + E_NO_AUTH, + + GENERAL_F_NUM +} Charger_Errcode_GeneralFail_t; + +typedef enum +{ + E_SYSCONFIG_UNMATCH = SUBMOD_ERROR_CODE_BASE, + E_SYSCONFIG_CHECKSUM, + + E_SYSCONFIG_NUM +} Charger_Errcode_SysconfigFail_t; + + + +typedef enum +{ + E_DRVBOARD_HAL_ERROR = SUBMOD_ERROR_CODE_BASE, + + E_DRVBOARD_NUM +} Charger_Errcode_DrvBoardFail_t; + +typedef enum +{ + E_CP_UNPLUGGED = SUBMOD_ERROR_CODE_BASE, + E_CP_UNKNOWN, + E_CC_UNPLUGGED, + E_CC_UNKNOWN, + E_K1K2_FAULT, + + E_1768_NUM +} Charger_Errcode_1768Fail_t; + + +typedef enum +{ + E_NORMAL_FAIL = SUBMOD_ERROR_CODE_BASE, + + E_LOCAL_LIST_CONFLICT_REPORT, //LocalListConflict + + E_1768_REJECT, + E_STATE_CONFLICT, + + E_RECORDS_CONFLICT, + + E_AUTH_NUM +} Charger_Errcode_CtrlFail_t; + + +#ifndef OCPP20_IMPL +extern const char * c_ChargePointStatusName[]; +extern const char * c_ChargePointErrorCodeName[]; + +extern const char * c_1768_stateName[]; + +extern const char * c_ocppStateNames[]; +extern const char * c_csCmdNames[]; +extern const char * c_scCmdNames[]; +extern const char * c_callErrorNames[]; + +extern const char * s_stateMngr_stateName[]; +#endif + +extern const char* c_cpStateName[]; +extern const char* c_ccStateName[]; + +extern const char * c_connectorName[]; +extern const char * c_lockName[]; +extern const char * c_meterName[]; +extern const char * c_relayName[]; + +extern const char ** M1768_GetStateNameArray(int connIdx); +extern const char * c_connStatusName[]; + +#ifndef OCPP20_IMPL +extern const char * c_c2s_notifyStatusName[]; + +extern const char * c_ChargingProfilePurposeTypeName[]; +extern const char * c_ChargingProfileKindTypeName[]; +extern const char * c_ChargingRateUnitTypeName[]; +extern const char * c_RecurrencyKindTypeName[]; +#endif + +extern const char * c_stateName_CHAdeMO[]; +extern const char * c_stateName_GBT[]; +extern const char * c_stateName_CCS[]; +extern const char * c_stateName_AC[]; +extern const char * c_connStatusName[]; + +extern const char * c_1768_stopReasonName[]; +extern const char * c_1768_commonErrorName[]; + +extern const char *c_EcoModeName[]; + +extern const char * c_CCNAME[]; +extern const char * c_CPNAME[]; + +extern const char * c_CurrLimitSourceName[]; +extern const char * c_CurrLimitTargetName[]; + +extern const char * c_modbus_protocolName[]; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/ioc/zlog/zlog.h b/ioc/zlog/zlog.h new file mode 100644 index 000000000..9642e0898 --- /dev/null +++ b/ioc/zlog/zlog.h @@ -0,0 +1,279 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_h +#define __zlog_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include /* for va_list */ +#include /* for size_t */ + +# if defined __GNUC__ +# define ZLOG_CHECK_PRINTF(m,n) __attribute__((format(printf,m,n))) +# else +# define ZLOG_CHECK_PRINTF(m,n) +# endif + +typedef struct zlog_category_s zlog_category_t; + +int zlog_init(const char *config); +int zlog_reload(const char *config); +void zlog_fini(void); + +void zlog_profile(void); + +zlog_category_t *zlog_get_category(const char *cname); +int zlog_level_enabled(zlog_category_t *category, const int level); + +int zlog_put_mdc(const char *key, const char *value); +char *zlog_get_mdc(const char *key); +void zlog_remove_mdc(const char *key); +void zlog_clean_mdc(void); + +int zlog_level_switch(zlog_category_t * category, int level); +int zlog_level_enabled(zlog_category_t * category, int level); + +void zlog(zlog_category_t * category, + const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const char *format, ...) ZLOG_CHECK_PRINTF(8,9); +void vzlog(zlog_category_t * category, + const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const char *format, va_list args); +void hzlog(zlog_category_t * category, + const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const void *buf, size_t buflen); + +int dzlog_init(const char *confpath, const char *cname); +int dzlog_set_category(const char *cname); + +void dzlog(const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const char *format, ...) ZLOG_CHECK_PRINTF(7,8); +void vdzlog(const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const char *format, va_list args); +void hdzlog(const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const void *buf, size_t buflen); + +typedef struct zlog_msg_s { + char *buf; + size_t len; + char *path; +} zlog_msg_t; + +typedef int (*zlog_record_fn)(zlog_msg_t *msg); +int zlog_set_record(const char *rname, zlog_record_fn record); + +const char *zlog_version(void); + +/******* useful macros, can be redefined at user's h file **********/ + +typedef enum { + ZLOG_LEVEL_DEBUG = 20, + ZLOG_LEVEL_INFO = 40, + ZLOG_LEVEL_NOTICE = 60, + ZLOG_LEVEL_WARN = 80, + ZLOG_LEVEL_ERROR = 100, + ZLOG_LEVEL_FATAL = 120 +} zlog_level; + +#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L +# if defined __GNUC__ && __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ "" +# endif +#endif + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +/* zlog macros */ +#define zlog_fatal(cat, ...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, __VA_ARGS__) +#define zlog_error(cat, ...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, __VA_ARGS__) +#define zlog_warn(cat, ...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, __VA_ARGS__) +#define zlog_notice(cat, ...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, __VA_ARGS__) +#define zlog_info(cat, ...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, __VA_ARGS__) +#define zlog_debug(cat, ...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, __VA_ARGS__) +/* dzlog macros */ +#define dzlog_fatal(...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, __VA_ARGS__) +#define dzlog_error(...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, __VA_ARGS__) +#define dzlog_warn(...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, __VA_ARGS__) +#define dzlog_notice(...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, __VA_ARGS__) +#define dzlog_info(...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, __VA_ARGS__) +#define dzlog_debug(...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, __VA_ARGS__) +#elif defined __GNUC__ +/* zlog macros */ +#define zlog_fatal(cat, format, args...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, format, ##args) +#define zlog_error(cat, format, args...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, format, ##args) +#define zlog_warn(cat, format, args...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, format, ##args) +#define zlog_notice(cat, format, args...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, format, ##args) +#define zlog_info(cat, format, args...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, format, ##args) +#define zlog_debug(cat, format, args...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, format, ##args) +/* dzlog macros */ +#define dzlog_fatal(format, args...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, format, ##args) +#define dzlog_error(format, args...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, format, ##args) +#define dzlog_warn(format, args...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, format, ##args) +#define dzlog_notice(format, args...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, format, ##args) +#define dzlog_info(format, args...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, format, ##args) +#define dzlog_debug(format, args...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, format, ##args) +#endif + +/* vzlog macros */ +#define vzlog_fatal(cat, format, args) \ + vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, format, args) +#define vzlog_error(cat, format, args) \ + vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, format, args) +#define vzlog_warn(cat, format, args) \ + vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, format, args) +#define vzlog_notice(cat, format, args) \ + vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, format, args) +#define vzlog_info(cat, format, args) \ + vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, format, args) +#define vzlog_debug(cat, format, args) \ + vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, format, args) + +/* hzlog macros */ +#define hzlog_fatal(cat, buf, buf_len) \ + hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, buf, buf_len) +#define hzlog_error(cat, buf, buf_len) \ + hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, buf, buf_len) +#define hzlog_warn(cat, buf, buf_len) \ + hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, buf, buf_len) +#define hzlog_notice(cat, buf, buf_len) \ + hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, buf, buf_len) +#define hzlog_info(cat, buf, buf_len) \ + hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, buf, buf_len) +#define hzlog_debug(cat, buf, buf_len) \ + hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, buf, buf_len) + + +/* vdzlog macros */ +#define vdzlog_fatal(format, args) \ + vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, format, args) +#define vdzlog_error(format, args) \ + vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, format, args) +#define vdzlog_warn(format, args) \ + vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, format, args) +#define vdzlog_notice(format, args) \ + vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, format, args) +#define vdzlog_info(format, args) \ + vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, format, args) +#define vdzlog_debug(format, args) \ + vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, format, args) + +/* hdzlog macros */ +#define hdzlog_fatal(buf, buf_len) \ + hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, buf, buf_len) +#define hdzlog_error(buf, buf_len) \ + hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, buf, buf_len) +#define hdzlog_warn(buf, buf_len) \ + hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, buf, buf_len) +#define hdzlog_notice(buf, buf_len) \ + hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, buf, buf_len) +#define hdzlog_info(buf, buf_len) \ + hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, buf, buf_len) +#define hdzlog_debug(buf, buf_len) \ + hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, buf, buf_len) + +/* enabled macros */ +#define zlog_fatal_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_FATAL) +#define zlog_error_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_ERROR) +#define zlog_warn_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_WARN) +#define zlog_notice_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_NOTICE) +#define zlog_info_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_INFO) +#define zlog_debug_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_DEBUG) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lv_conf.h b/lv_conf.h index 20dd3da54..c8acd4977 100644 --- a/lv_conf.h +++ b/lv_conf.h @@ -504,9 +504,9 @@ * If LV_USE_LOG is enabled, an error message will be printed on failure. */ #define LV_USE_ASSERT_NULL 1 /**< Check if the parameter is NULL. (Very fast, recommended) */ #define LV_USE_ASSERT_MALLOC 1 /**< Checks is the memory is successfully allocated or no. (Very fast, recommended) */ -#define LV_USE_ASSERT_STYLE 1 -#define LV_USE_ASSERT_MEM_INTEGRITY 1 -#define LV_USE_ASSERT_OBJ 1 +#define LV_USE_ASSERT_STYLE 0 +#define LV_USE_ASSERT_MEM_INTEGRITY 0 +#define LV_USE_ASSERT_OBJ 0 /** Add a custom handler when assert happens e.g. to restart MCU. */ #define LV_ASSERT_HANDLER_INCLUDE @@ -1001,7 +1001,7 @@ #define LV_USE_LIBWEBP 0 /** GIF decoder library */ -#define LV_USE_GIF 0 +#define LV_USE_GIF 1 #if LV_USE_GIF /** GIF decoder accelerate */ #define LV_GIF_CACHE_DECODE_DATA 0 @@ -1023,7 +1023,7 @@ #define LV_USE_BARCODE 1 /** FreeType library */ -#define LV_USE_FREETYPE 0 +#define LV_USE_FREETYPE 1 #if LV_USE_FREETYPE /** Let FreeType use LVGL memory and file porting */ #define LV_FREETYPE_USE_LVGL_PORT 0 @@ -1056,7 +1056,7 @@ /** Enable ThorVG (vector graphics library) from the src/libs folder. * Requires LV_USE_VECTOR_GRAPHIC */ -#define LV_USE_THORVG_INTERNAL 1 +#define LV_USE_THORVG_INTERNAL 1 /** Enable ThorVG by assuming that its installed and linked to the project * Requires LV_USE_VECTOR_GRAPHIC */ diff --git a/pages/ui_customer_info.c b/pages/ui_customer_info.c new file mode 100644 index 000000000..94908ba98 --- /dev/null +++ b/pages/ui_customer_info.c @@ -0,0 +1,78 @@ +#include "../pages_mngr.h" + +#define UI_NAME_CUSTOMER_INFO_QR_CODE_PROMPT "customer_hint" +#define UI_NAME_CUSTOMER_INFO_CHARGER_STATION "customer_charger_id" + +typedef struct { + lv_obj_t * page; + + lv_obj_t * qr_code_prompt; + lv_obj_t * charger_station; + +} ui_page_customer_info_t; + +static ui_page_customer_info_t ui_page_customer_info = {NULL}; + +static void ui_page_customer_info_updatejson(struct ioc_obj_user_data_s * user_data) +{ + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + + char buf[64] = {0}; + uint8_t startH = 0, startM = 0, endH = 0, endM = 0; +} + +lv_obj_t * ui_page_create_customer_info(lv_obj_t *parent) +{ + + ui_page_customer_info.page = ioc_layout_mngr_load_layout("cuestomer_info", parent); + if (ui_page_customer_info.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(ui_page_customer_info.page); + user_data->ui_json_update_cb = ui_page_customer_info_updatejson; + } + + return ui_page_customer_info.page; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_idle_update_qr_code_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_customer_info.qr_code_prompt, "qr_code_prompt"); +} + +void ui_after_create_customer_info_qr_code_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_customer_info.qr_code_prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_idle_update_qr_code_prompt; +} + +void ui_idle_update_charger_station(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_customer_info.charger_station, "charger_station"); +} + +void ui_after_create_customer_info_charger_station(const char * name, lv_obj_t * obj) +{ + ui_page_customer_info.charger_station = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_idle_update_charger_station; +} + +void ui_after_create_customer_info(const char * name, lv_obj_t * obj) +{ + const char * idle_name = name + strlen(UI_NAME_CUSTOMER_INFO); + if (strcmp(idle_name, UI_NAME_CUSTOMER_INFO_QR_CODE_PROMPT) == 0) + { + ui_after_create_customer_info_qr_code_prompt(name, obj); + return; + } + else if (strcmp(idle_name, UI_NAME_CUSTOMER_INFO_CHARGER_STATION) == 0) + { + ui_after_create_customer_info_charger_station(name, obj); + return; + } +} diff --git a/pages/ui_customer_info.h b/pages/ui_customer_info.h new file mode 100644 index 000000000..c0fabf47d --- /dev/null +++ b/pages/ui_customer_info.h @@ -0,0 +1,11 @@ +#ifndef __UI_PAGE_CUSTOMER_INFO_H__ +#define __UI_PAGE_CUSTOMER_INFO_H__ + +#include "lvgl.h" + +#define UI_NAME_CUSTOMER_INFO "main.customer_info" + +lv_obj_t * ui_page_create_customer_info(lv_obj_t *parent); +void ui_after_create_customer_info(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_customer_info_charging.c b/pages/ui_customer_info_charging.c new file mode 100644 index 000000000..f6635071d --- /dev/null +++ b/pages/ui_customer_info_charging.c @@ -0,0 +1,102 @@ +#include "../pages_mngr.h" + +#define UI_NAME_CUSTOMER_INFO_CHARGING_QR_CODE_PROMPT "qr_code_prompt" +#define UI_NAME_CUSTOMER_INFO_CHARGING_BTN_NOPRICE "btn" +#define UI_NAME_CUSTOMER_INFO_CHARGING_BTN_LABEL_NOPRICE "btn.label" + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * qr_code_prompt; + lv_obj_t * btn_noprice; + lv_obj_t * btn_label_noprice; +} ui_page_customer_info_charging_t; + +static ui_page_customer_info_charging_t s_ui_page_customer_info_charging = {NULL}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static void ui_page_customer_info_charging_updatejson(struct ioc_obj_user_data_s * user_data) +{ + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +lv_obj_t * ui_page_create_customer_info_charging(lv_obj_t *parent) +{ + + s_ui_page_customer_info_charging.page = ioc_layout_mngr_load_layout("cuestomer_info_charging", parent); + if (s_ui_page_customer_info_charging.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(s_ui_page_customer_info_charging.page); + user_data->ui_json_update_cb = ui_page_customer_info_charging_updatejson; + } + + return s_ui_page_customer_info_charging.page; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// + +static void charging_detailed_data_noprice_event_cb(lv_event_t *e) +{ + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + ui_popup_show_charging_detail(0,0); + } +} + +void ui_charging_update_qr_code_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(s_ui_page_customer_info_charging.qr_code_prompt, "qr_code_prompt"); +} + +void ui_after_create_customer_info_charging_qr_code_prompt(const char * name, lv_obj_t * obj) +{ + s_ui_page_customer_info_charging.qr_code_prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_charging_update_qr_code_prompt; +} + +void ui_after_create_customer_info_charging_btn_noprice(const char * name, lv_obj_t * obj) +{ + s_ui_page_customer_info_charging.btn_noprice = obj; + lv_obj_add_event_cb(obj, charging_detailed_data_noprice_event_cb, LV_EVENT_CLICKED, NULL); +} + +void ui_charging_update_btn_label_noprice_noprice(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(s_ui_page_customer_info_charging.btn_label_noprice, "Detailed_data"); +} + +void ui_after_create_customer_info_charging_btn_label_noprice(const char * name, lv_obj_t * obj) +{ + s_ui_page_customer_info_charging.btn_label_noprice = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_charging_update_btn_label_noprice_noprice; +} + +void ui_after_create_customer_info_charging(const char * name, lv_obj_t * obj) +{ + const char * charging_name = name + strlen(UI_NAME_CUSTOMER_INFO_CHARGING); + if (strcmp(charging_name, UI_NAME_CUSTOMER_INFO_CHARGING_QR_CODE_PROMPT) == 0) + { + ui_after_create_customer_info_charging_qr_code_prompt(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_CUSTOMER_INFO_CHARGING_BTN_NOPRICE) == 0) + { + ui_after_create_customer_info_charging_btn_noprice(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_CUSTOMER_INFO_CHARGING_BTN_LABEL_NOPRICE) == 0) + { + ui_after_create_customer_info_charging_btn_label_noprice(name, obj); + return; + } + + return; +} diff --git a/pages/ui_customer_info_charging.h b/pages/ui_customer_info_charging.h new file mode 100644 index 000000000..e4a3f3105 --- /dev/null +++ b/pages/ui_customer_info_charging.h @@ -0,0 +1,11 @@ +#ifndef __UI_PAGE_CUSTOMER_INFO_CHARGING_H__ +#define __UI_PAGE_CUSTOMER_INFO_CHARGING_H__ + +#include "lvgl.h" + +#define UI_NAME_CUSTOMER_INFO_CHARGING "main.cuestomer_info_charging" + +lv_obj_t * ui_page_create_customer_info_charging(lv_obj_t *parent); +void ui_after_create_customer_info_charging(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_01_home.c b/pages/ui_page_01_home.c new file mode 100644 index 000000000..773563e92 --- /dev/null +++ b/pages/ui_page_01_home.c @@ -0,0 +1,62 @@ +#include "../pages_mngr.h" + + +#define UI_NAME_01_HOME_PLUG_LABEL ".home_plug_title" +#define UI_NAME_01_HOME_PLUG_PROMPT ".home_plug_subtitle" + + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * plug_label; + lv_obj_t * plug_prompt; + +} ui_page_01_home_t; + +static ui_page_01_home_t ui_page_01_home = {NULL}; + +lv_obj_t * ui_page_create_01_home(lv_obj_t *parent) +{ + return ioc_layout_mngr_load_layout("home", parent); +} + +void ui_home_update_plug_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_01_home.plug_label, "Plug_in_frist"); +} + +void ui_after_create_01_home_plug_label(const char * name, lv_obj_t * obj) +{ + ui_page_01_home.plug_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_home_update_plug_label; +} + +void ui_home_update_plug_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_01_home.plug_prompt, "home_prompt"); +} + +void ui_after_create_01_home_plug_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_01_home.plug_prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_home_update_plug_prompt; +} + + +void ui_after_create_state_home(const char * name, lv_obj_t * obj) +{ + const char * home_name = name + strlen(UI_NAME_STATE_HOME); + if (strcmp(home_name, UI_NAME_01_HOME_PLUG_LABEL) == 0) + { + ui_after_create_01_home_plug_label(name, obj); + return; + } + else if (strcmp(home_name, UI_NAME_01_HOME_PLUG_PROMPT) == 0) + { + ui_after_create_01_home_plug_prompt(name, obj); + return; + } +} diff --git a/pages/ui_page_01_home.h b/pages/ui_page_01_home.h new file mode 100644 index 000000000..562c2fd90 --- /dev/null +++ b/pages/ui_page_01_home.h @@ -0,0 +1,11 @@ +#ifndef __UI_PAGE_01_HOME_H__ +#define __UI_PAGE_01_HOME_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_01_home(lv_obj_t *parent); + +#define UI_NAME_STATE_HOME "main.home" +void ui_after_create_state_home(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_02_idle.c b/pages/ui_page_02_idle.c new file mode 100644 index 000000000..981f5e276 --- /dev/null +++ b/pages/ui_page_02_idle.c @@ -0,0 +1,69 @@ +#include "../pages_mngr.h" + + +#define UI_NAME_02_IDLE_PLUG_LABEL ".plug_label_idle" +#define UI_NAME_02_IDLE_PLUG_PROMPT ".plug_prompt_idle" + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * plug_label; + lv_obj_t * plug_prompt; + +} ui_page_02_idle_t; + +static ui_page_02_idle_t ui_page_02_idle = {NULL}; + + +lv_obj_t * ui_page_create_02_idle(lv_obj_t *parent) +{ + memset(&ui_page_02_idle, 0, sizeof(ui_page_02_idle)); + + ui_page_02_idle.page = ioc_layout_mngr_load_layout("idle", parent); + if (ui_page_02_idle.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(ui_page_02_idle.page); + } + + return ui_page_02_idle.page; +} + +void ui_idle_update_plug_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_02_idle.plug_label, "Plug_in_frist"); +} + +void ui_after_create_02_idle_plug_label(const char * name, lv_obj_t * obj) +{ + ui_page_02_idle.plug_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_idle_update_plug_label; +} + +void ui_idle_update_plug_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_02_idle.plug_prompt, "home_prompt"); +} + +void ui_after_create_02_idle_plug_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_02_idle.plug_prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_idle_update_plug_prompt; +} + +void ui_after_create_02_idle(const char * name, lv_obj_t * obj) +{ + const char * idle_name = name + strlen(UI_NAME_02_IDLE); + if (strcmp(idle_name, UI_NAME_02_IDLE_PLUG_LABEL) == 0) + { + ui_after_create_02_idle_plug_label(name, obj); + return; + } + else if (strcmp(idle_name, UI_NAME_02_IDLE_PLUG_PROMPT) == 0) + { + ui_after_create_02_idle_plug_prompt(name, obj); + return; + } +} diff --git a/pages/ui_page_02_idle.h b/pages/ui_page_02_idle.h new file mode 100644 index 000000000..67c7a8760 --- /dev/null +++ b/pages/ui_page_02_idle.h @@ -0,0 +1,11 @@ +#ifndef __UI_PAGE_02_IDLE_H__ +#define __UI_PAGE_02_IDLE_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_02_idle(lv_obj_t *parent); + +#define UI_NAME_02_IDLE "main.idle" +void ui_after_create_02_idle(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_03_starting1.c b/pages/ui_page_03_starting1.c new file mode 100644 index 000000000..d4cba8de6 --- /dev/null +++ b/pages/ui_page_03_starting1.c @@ -0,0 +1,103 @@ +#include "../pages_mngr.h" + +#define UI_STARTING1_DATA g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.starting + + +#define UI_NAME_03_STARTING1_QR_CODE ".starting1_qr" +#define UI_NAME_03_STARTING1_QR_CODE_LABEL ".starting1_title" +#define UI_NAME_03_STARTING1_QR_CODE_PROMPT ".starting1_subtitle" + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * qr_code; + lv_obj_t * qr_code_label; + lv_obj_t * qr_code_prompt; + +} ui_page_03_starting1_t; + +static ui_page_03_starting1_t ui_page_03_starting1 = {NULL}; +static char s_starting1_qr_text[256] = {0}; + + + +static void ui_page_03_starting1_updatejson(struct ioc_obj_user_data_s * user_data) +{ + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + + // 二维码文本有变化时更新二维码 + if(strcmp(s_starting1_qr_text, UI_STARTING1_DATA.connQR) != 0) + { + strcpy(s_starting1_qr_text, UI_STARTING1_DATA.connQR); + lv_qrcode_update(ui_page_03_starting1.qr_code, UI_STARTING1_DATA.connQR, strlen(UI_STARTING1_DATA.connQR)); + LV_LOG_USER("QR Text [%s]", s_starting1_qr_text); + } +} + +lv_obj_t * ui_page_create_03_starting1(lv_obj_t *parent) +{ + memset(&ui_page_03_starting1, 0, sizeof(ui_page_03_starting1)); + + ui_page_03_starting1.page = ioc_layout_mngr_load_layout("starting1", parent); + if (ui_page_03_starting1.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(ui_page_03_starting1.page); + user_data->ui_json_update_cb = ui_page_03_starting1_updatejson; + } + + return ui_page_03_starting1.page; +} + +void ui_starting1_update_qr_code_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_03_starting1.qr_code_label, "Scan_here_to_start_charging"); +} + +void ui_after_create_03_starting1_qr_code_label(const char * name, lv_obj_t * obj) +{ + ui_page_03_starting1.qr_code_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_starting1_update_qr_code_label; +} + +void ui_starting1_update_qr_code_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_03_starting1.qr_code_prompt, "starting_prompt"); +} + +void ui_after_create_03_starting1_qr_code_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_03_starting1.qr_code_prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_starting1_update_qr_code_prompt; +} + +void ui_after_create_03_starting1_qr_code(const char * name, lv_obj_t * obj) +{ + ui_page_03_starting1.qr_code = obj; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_after_create_03_starting1(const char * name, lv_obj_t * obj) +{ + const char * starting1_name = name + strlen(UI_NAME_03_STARTING1); + if (strcmp(starting1_name, UI_NAME_03_STARTING1_QR_CODE_LABEL) == 0) + { + ui_after_create_03_starting1_qr_code_label(name, obj); + return; + } + else if (strcmp(starting1_name, UI_NAME_03_STARTING1_QR_CODE_PROMPT) == 0) + { + ui_after_create_03_starting1_qr_code_prompt(name, obj); + return; + } + else if (strcmp(starting1_name, UI_NAME_03_STARTING1_QR_CODE) == 0) + { + ui_after_create_03_starting1_qr_code(name, obj); + return; + } +} diff --git a/pages/ui_page_03_starting1.h b/pages/ui_page_03_starting1.h new file mode 100644 index 000000000..893a9a500 --- /dev/null +++ b/pages/ui_page_03_starting1.h @@ -0,0 +1,11 @@ +#ifndef __UI_PAGE_03_STARTING1_H__ +#define __UI_PAGE_03_STARTING1_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_03_starting1(lv_obj_t *parent); + +#define UI_NAME_03_STARTING1 "main.starting1" +void ui_after_create_03_starting1(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_04_starting2.c b/pages/ui_page_04_starting2.c new file mode 100644 index 000000000..315b5c53b --- /dev/null +++ b/pages/ui_page_04_starting2.c @@ -0,0 +1,144 @@ +#include "../pages_mngr.h" + +#define UI_STARTING2_DATA g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.starting + +#define UI_NAME_04_STARTING2_QR_CODE ".starting2_qr" +#define UI_NAME_04_STARTING2_QR_CODE_LABEL ".starting2_title" +#define UI_NAME_04_STARTING2_QR_CODE_PROMPT ".starting2_subtitle" +#define UI_NAME_04_STARTING2_POS_BTN ".starting2_pos_btn" + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * qr_code; + lv_obj_t * qr_code_label; + lv_obj_t * qr_code_prompt; + lv_obj_t * pos_btn; + uint8_t auth_conidx; + +} ui_page_04_starting2_t; + +static ui_page_04_starting2_t ui_page_04_starting2 = {NULL}; + +static char s_starting2_qr_text[256] = {0}; + + + +static void ui_page_04_starting2_updatejson(struct ioc_obj_user_data_s * user_data) +{ + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + + char buf[64] = {0}; + uint8_t startH = 0, startM = 0, endH = 0, endM = 0; + + // 二维码文本有变化时更新二维码 + if(strcmp(s_starting2_qr_text, UI_STARTING2_DATA.connQR) != 0) + { + strcpy(s_starting2_qr_text, UI_STARTING2_DATA.connQR); + lv_qrcode_update(ui_page_04_starting2.qr_code, UI_STARTING2_DATA.connQR, strlen(UI_STARTING2_DATA.connQR)); + LV_LOG_USER("QR Text [%s]", s_starting2_qr_text); + } +} + +lv_obj_t * ui_page_create_04_starting2(lv_obj_t *parent) +{ + memset(&ui_page_04_starting2, 0, sizeof(ui_page_04_starting2)); + + ui_page_04_starting2.page = ioc_layout_mngr_load_layout("starting2", parent); + if (ui_page_04_starting2.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(ui_page_04_starting2.page); + user_data->ui_json_update_cb = ui_page_04_starting2_updatejson; + } + + return ui_page_04_starting2.page; +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_starting2_update_qr_code_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_04_starting2.qr_code_label, "Scan_here_to_start_charging"); +} + +void ui_after_create_04_starting2_qr_code_label(const char * name, lv_obj_t * obj) +{ + ui_page_04_starting2.qr_code_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_starting2_update_qr_code_label; +} + +void ui_starting2_update_qr_code_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_04_starting2.qr_code_prompt, "starting_prompt"); +} + +void ui_after_create_04_starting2_qr_code_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_04_starting2.qr_code_prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_starting2_update_qr_code_prompt; +} + +void ui_after_create_04_starting2_qr_code(const char * name, lv_obj_t * obj) +{ + ui_page_04_starting2.qr_code = obj; +} + +static void pos_btn_event_cb(lv_event_t *e) +{ + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + ui_page_04_starting2.auth_conidx = UI_CONNECTOR_ACTIVE_IDX; + lv_obj_t *btn = lv_event_get_target(e); + lang_info_t *info = (lang_info_t *)lv_event_get_user_data(e); + if ( g_ui_json.enSoftKey == false ) + { + ioc_send_UseCreditCard(UI_CONNECTOR_ACTIVE_IDX,0); + } + else + { + ui_popup_show_preauthorization(UI_CONNECTOR_ACTIVE_IDX); + } + } +} + +uint8_t ui_page_04_starting2_get_autu_conidx(void) +{ + return ui_page_04_starting2.auth_conidx; +} + +void ui_after_create_04_starting2_pos_btn(const char * name, lv_obj_t * obj) +{ + ui_page_04_starting2.pos_btn = obj; + lv_obj_add_event_cb(obj, pos_btn_event_cb, LV_EVENT_CLICKED, NULL); +} +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_after_create_04_starting2(const char * name, lv_obj_t * obj) +{ + const char * starting2_name = name + strlen(UI_NAME_04_STARTING2); + if (strcmp(starting2_name, UI_NAME_04_STARTING2_QR_CODE_LABEL) == 0) + { + ui_after_create_04_starting2_qr_code_label(name, obj); + return; + } + else if (strcmp(starting2_name, UI_NAME_04_STARTING2_QR_CODE_PROMPT) == 0) + { + ui_after_create_04_starting2_qr_code_prompt(name, obj); + return; + } + else if (strcmp(starting2_name, UI_NAME_04_STARTING2_QR_CODE) == 0) + { + ui_after_create_04_starting2_qr_code(name, obj); + return; + } + else if (strcmp(starting2_name, UI_NAME_04_STARTING2_POS_BTN) == 0) + { + ui_after_create_04_starting2_pos_btn(name, obj); + return; + } +} diff --git a/pages/ui_page_04_starting2.h b/pages/ui_page_04_starting2.h new file mode 100644 index 000000000..8859ea6fa --- /dev/null +++ b/pages/ui_page_04_starting2.h @@ -0,0 +1,12 @@ +#ifndef __UI_PAGE_04_STARTING2_H__ +#define __UI_PAGE_04_STARTING2_H__ + + +#include "lvgl.h" + +lv_obj_t * ui_page_create_04_starting2(lv_obj_t *parent); + +#define UI_NAME_04_STARTING2 "main.starting2" +void ui_after_create_04_starting2(const char * name, lv_obj_t * obj); +uint8_t ui_page_04_starting2_get_autu_conidx(void); +#endif diff --git a/pages/ui_page_05_charging.c b/pages/ui_page_05_charging.c new file mode 100644 index 000000000..54bd0552d --- /dev/null +++ b/pages/ui_page_05_charging.c @@ -0,0 +1,358 @@ +#include "../pages_mngr.h" + +#define UI_CHARGING_DATA g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.charging + +#define UI_NAME_05_CHARGING_POWER ".charging_power.val" +#define UI_NAME_05_CHARGING_ENERGY ".charging_energy.val" +#define UI_NAME_05_CHARGING_SOC ".charging_soc.val" +#define UI_NAME_05_CHARGING_DURATION ".charging_duration.val" +#define UI_NAME_05_CHARGING_CAR_GIF ".charging_car_icon.charging_car_gif" + +#define UI_NAME_05_CHARGING_POWER_LABEL ".charging_power.title" +#define UI_NAME_05_CHARGING_ENERGY_LABEL ".charging_energy.title" +#define UI_NAME_05_CHARGING_SOC_LABEL ".charging_soc.title" +#define UI_NAME_05_CHARGING_DURATION_LABEL ".charging_duration.title" + +#define UI_NAME_05_CHARGING_POWER_UNIT ".charging_power.unit" +#define UI_NAME_05_CHARGING_ENERGY_UNIT ".charging_energy.unit" +#define UI_NAME_05_CHARGING_SOC_UNIT ".charging_soc.unit" + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * car_gif; + + lv_obj_t * power; + lv_obj_t * energy; + lv_obj_t * soc; + lv_obj_t * duration; + + lv_obj_t * power_label; + lv_obj_t * energy_label; + lv_obj_t * soc_label; + lv_obj_t * duration_label; + + lv_obj_t * power_unit; + lv_obj_t * energy_unit; + lv_obj_t * soc_unit; + +} ui_page_05_charging_t; + +static ui_page_05_charging_t s_ui_page_05_charging = {NULL}; +static lv_timer_t * charging_timer = NULL; + +static void ui_page_05_charging_time(lv_timer_t * temp) +{ + LV_UNUSED(temp); + + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + + time_t current_time = time(NULL); + time_t diftimer = difftime(current_time, UI_CHARGING_DATA.startTime); + + if (diftimer < 0) { + diftimer = 0; + } + + char buf[64] = {0}; + struct tm * tm = gmtime(&diftimer); + if(current_time < UI_CHARGING_DATA.startTime) { + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", 0,0,0); + ioc_label_set_text(s_ui_page_05_charging.duration, buf); + }else{ + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); + ioc_label_set_text(s_ui_page_05_charging.duration, buf); + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static void ui_page_05_charging_updatejson(struct ioc_obj_user_data_s * user_data) +{ + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + + char buf[64] = {0}; + + if (s_ui_page_05_charging.power != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%.2f", UI_CHARGING_DATA.meterData.power); + ioc_label_set_text(s_ui_page_05_charging.power, buf); + } + + if (s_ui_page_05_charging.energy != NULL) + { + memset(buf, 0x00, sizeof(buf)); + // 判断是否显示四位小时,默认显示两位小数 + if (UI_CONNECTOR_ISQ4DOT(UI_CONNECTOR_ACTIVE_IDX)) + { + // 已经在解析时拼接了第四位,在这直接显示 + snprintf(buf, sizeof(buf), "%.4f", UI_CHARGING_DATA.meterData.Q[3]); + } + else + { + snprintf(buf, sizeof(buf), "%.2f", UI_CHARGING_DATA.meterData.Q[3]); + } + ioc_label_set_text(s_ui_page_05_charging.energy, buf); + } + + if (s_ui_page_05_charging.soc != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%d", UI_CHARGING_DATA.soc); + ioc_label_set_text(s_ui_page_05_charging.soc, buf); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +lv_obj_t * ui_page_create_05_charging(lv_obj_t *parent) +{ + memset(&s_ui_page_05_charging, 0, sizeof(s_ui_page_05_charging)); + + s_ui_page_05_charging.page = ioc_layout_mngr_load_layout("charging", parent); + if (s_ui_page_05_charging.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(s_ui_page_05_charging.page); + user_data->ui_json_update_cb = ui_page_05_charging_updatejson; + } + + return s_ui_page_05_charging.page; +} + +void ui_page_show_05_charging(void) +{ + if (s_ui_page_05_charging.car_gif != NULL) + { + lv_gif_restart(s_ui_page_05_charging.car_gif); + } + + // 为了时间显示的流畅,充电时间由本地计算 + if(charging_timer == NULL) + { + charging_timer = lv_timer_create(ui_page_05_charging_time, 500, NULL); + } +} + +void ui_page_hide_05_charging(void) +{ + if (s_ui_page_05_charging.car_gif != NULL) + { + lv_gif_pause(s_ui_page_05_charging.car_gif); + } + + if (charging_timer!= NULL) + { + lv_timer_del(charging_timer); + charging_timer = NULL; + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", 0, 0, 0); + ioc_label_set_text(s_ui_page_05_charging.duration, buf); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_after_create_05_charging_power(const char * name, lv_obj_t * obj) +{ + s_ui_page_05_charging.power = obj; +} + +void ui_after_create_05_charging_energy(const char * name, lv_obj_t * obj) +{ + s_ui_page_05_charging.energy = obj; +} + +void ui_after_create_05_charging_soc(const char * name, lv_obj_t * obj) +{ + s_ui_page_05_charging.soc = obj; +} + +void ui_after_create_05_charging_duration(const char * name, lv_obj_t * obj) +{ + s_ui_page_05_charging.duration = obj; +} + +void ui_after_create_05_charging_power_unit(const char * name, lv_obj_t * obj) +{ + s_ui_page_05_charging.power_unit = obj; + ioc_label_set_text(s_ui_page_05_charging.power_unit, "kW"); +} + +void ui_after_create_05_charging_energy_unit(const char * name, lv_obj_t * obj) +{ + s_ui_page_05_charging.energy_unit = obj; + ioc_label_set_text(s_ui_page_05_charging.energy_unit, "kWh"); +} + +void ui_after_create_05_charging_soc_unit(const char * name, lv_obj_t * obj) +{ + s_ui_page_05_charging.soc_unit = obj; + ioc_label_set_text(s_ui_page_05_charging.soc_unit, "%"); +} + +void ui_charging_update_power_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(s_ui_page_05_charging.power_label, "Power"); +} + +void ui_after_create_05_charging_power_label(const char * name, lv_obj_t * obj) +{ + s_ui_page_05_charging.power_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_charging_update_power_label; +} + +void ui_charging_update_energy_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(s_ui_page_05_charging.energy_label, "Energy"); +} + +void ui_after_create_05_charging_energy_label(const char * name, lv_obj_t * obj) +{ + s_ui_page_05_charging.energy_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_charging_update_energy_label; +} + +void ui_charging_update_soc_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(s_ui_page_05_charging.soc_label, "SoC"); +} + +void ui_after_create_05_charging_soc_label(const char * name, lv_obj_t * obj) +{ + s_ui_page_05_charging.soc_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_charging_update_soc_label; +} + +void ui_charging_update_duration_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(s_ui_page_05_charging.duration_label, "Duration"); +} + +void ui_after_create_05_charging_duration_label(const char * name, lv_obj_t * obj) +{ + s_ui_page_05_charging.duration_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_charging_update_duration_label; +} + + +static void charging_detailed_data_event_cb(lv_event_t *e) +{ + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + ui_popup_show_charging_detail(0,0); + } +} + +void ui_after_create_05_charging_car_gif(const char * name, lv_obj_t * obj) +{ + s_ui_page_05_charging.car_gif = obj; +} + + +void ui_after_create_05_charging(const char * name, lv_obj_t * obj) +{ + const char * charging_name = name + strlen(UI_NAME_05_CHARGING); + if (strcmp(charging_name, UI_NAME_05_CHARGING_POWER_LABEL) == 0) + { + ui_after_create_05_charging_power_label(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_05_CHARGING_ENERGY_LABEL) == 0) + { + ui_after_create_05_charging_energy_label(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_05_CHARGING_SOC_LABEL) == 0) + { + ui_after_create_05_charging_soc_label(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_05_CHARGING_DURATION_LABEL) == 0) + { + ui_after_create_05_charging_duration_label(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_05_CHARGING_POWER) == 0) + { + ui_after_create_05_charging_power(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_05_CHARGING_ENERGY) == 0) + { + ui_after_create_05_charging_energy(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_05_CHARGING_SOC) == 0) + { + ui_after_create_05_charging_soc(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_05_CHARGING_DURATION) == 0) + { + ui_after_create_05_charging_duration(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_05_CHARGING_CAR_GIF) == 0) + { + ui_after_create_05_charging_car_gif(name, obj); + return; + } + if (strcmp(charging_name, UI_NAME_05_CHARGING_POWER_UNIT) == 0) + { + ui_after_create_05_charging_power_unit(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_05_CHARGING_ENERGY_UNIT) == 0) + { + ui_after_create_05_charging_energy_unit(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_05_CHARGING_SOC_UNIT) == 0) + { + ui_after_create_05_charging_soc_unit(name, obj); + return; + } + + return; +} + +// static void ui_status_charging_btn_event_cb(lv_event_t *e) +// { +// lv_obj_t *obj = lv_event_get_target(e); +// lv_event_code_t code = lv_event_get_code(e); + +// if(code == LV_EVENT_CLICKED) { +// ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); +// // lv_obj_clear_flag(ui_status_bar.mask, LV_OBJ_FLAG_HIDDEN); +// // ui_create_status_popup(UI_NAME_DETAILED_DATA); +// // lv_obj_clear_flag(ui_status_popup.detailed_data_page.obj, LV_OBJ_FLAG_HIDDEN); +// } +// } + + +// void ui_state_charging_detailed_data(struct ioc_obj_user_data_s *user_data, const char *name) +// { +// lv_obj_t *child = NULL; +// struct ioc_obj_user_data_s *user_data_tmp; + +// // 遍历当前对象的子对象 +// for (int i = 0; i < lv_obj_get_child_cnt(user_data->obj); i++) { +// child = lv_obj_get_child(user_data->obj, i); +// user_data_tmp = lv_obj_get_user_data(child); +// if (strcmp(get_last_field(user_data_tmp->name), name) == 0) { +// lv_obj_add_event_cb(child, ui_status_charging_btn_event_cb, LV_EVENT_CLICKED, NULL); +// break; +// } +// ui_state_charging_detailed_data(user_data_tmp, name); +// } +// } diff --git a/pages/ui_page_05_charging.h b/pages/ui_page_05_charging.h new file mode 100644 index 000000000..204e19412 --- /dev/null +++ b/pages/ui_page_05_charging.h @@ -0,0 +1,14 @@ +#ifndef __UI_PAGE_05_CHARGING_H__ +#define __UI_PAGE_05_CHARGING_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_05_charging(lv_obj_t *parent); +void ui_page_show_05_charging(void); +void ui_page_hide_05_charging(void); + + +#define UI_NAME_05_CHARGING "main.charging" +void ui_after_create_05_charging(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_06_finished.c b/pages/ui_page_06_finished.c new file mode 100644 index 000000000..fb3feb567 --- /dev/null +++ b/pages/ui_page_06_finished.c @@ -0,0 +1,265 @@ +#include "../pages_mngr.h" + +#define UI_NAME_06_FINISHED_START_TIME ".finished_start_time.val" +#define UI_NAME_06_FINISHED_ENERGY ".finished_energy.val" +#define UI_NAME_06_FINISHED_START_SOC ".finished_soc.val_1" +#define UI_NAME_06_FINISHED_END_SOC ".finished_soc.val_2" +#define UI_NAME_06_FINISHED_DURATION ".finished_duration.val" +#define UI_NAME_06_FINISHED_START_TIME_LABEL ".finished_start_time.title" +#define UI_NAME_06_FINISHED_ENERGY_LABEL ".finished_energy.title" +#define UI_NAME_06_FINISHED_SOC_LABEL ".finished_soc.title" +#define UI_NAME_06_FINISHED_DURATION_LABEL ".finished_duration.title" + +#define UI_NAME_06_FINISHED_ENERGY_UNIT ".finished_energy.unit" + + + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * start_time; + lv_obj_t * energy; + lv_obj_t * start_soc; + lv_obj_t * end_soc; + lv_obj_t * duration; + + lv_obj_t * start_time_label; + lv_obj_t * energy_label; + lv_obj_t * soc_label; + lv_obj_t * duration_label; + + lv_obj_t * energy_unit; + +} ui_page_06_finished_t; + +static ui_page_06_finished_t ui_page_06_finished = {NULL}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////// +static void ui_page_06_finished_updatejson(struct ioc_obj_user_data_s * user_data) +{ + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + + char buf[64] = {0}; + + if (ui_page_06_finished.energy != NULL) + { + memset(buf, 0x00, sizeof(buf)); + // 判断是否显示四位小时,默认显示两位小数 + if (UI_CONNECTOR_ISQ4DOT(UI_CONNECTOR_ACTIVE_IDX)) + { + // 已经在解析时拼接了第四位,在这直接显示 + snprintf(buf, sizeof(buf), "%.4f", UI_FINISHED_DATA.actualMeter); + } + else + { + snprintf(buf, sizeof(buf), "%.2f", UI_FINISHED_DATA.actualMeter); + } + ioc_label_set_text(ui_page_06_finished.energy, buf); + } + + if (ui_page_06_finished.duration != NULL) + { + memset(buf, 0x00, sizeof(buf)); + sprintf((char*)buf, "%02d:%02d", + (UI_FINISHED_DATA.duration / 3600), + ((UI_FINISHED_DATA.duration / 60) % 60) + ); + ioc_label_set_text(ui_page_06_finished.duration, buf); + } + + if (ui_page_06_finished.start_time != NULL) + { + memset(buf, 0x00, sizeof(buf)); + time_t n = 0; + n = UI_FINISHED_DATA.startTime; + + struct tm local; + struct tm * pTt = localtime_r(&n, &local); + + sprintf((char*)buf, "%02d:%02d", (pTt->tm_hour), (pTt->tm_min)); + ioc_label_set_text(ui_page_06_finished.start_time, buf); + } + + if (ui_page_06_finished.start_soc != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%d", UI_FINISHED_DATA.startSoc); + ioc_label_set_text(ui_page_06_finished.start_soc, buf); + } + + if (ui_page_06_finished.end_soc != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%d", UI_FINISHED_DATA.stopSoc); + ioc_label_set_text(ui_page_06_finished.end_soc, buf); + } + + if (ui_page_06_finished.end_soc != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%d", UI_FINISHED_DATA.stopSoc); + ioc_label_set_text(ui_page_06_finished.end_soc, buf); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +lv_obj_t * ui_page_create_06_finished(lv_obj_t *parent) +{ + memset(&ui_page_06_finished, 0, sizeof(ui_page_06_finished)); + + ui_page_06_finished.page = ioc_layout_mngr_load_layout("finished", parent); + if (ui_page_06_finished.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(ui_page_06_finished.page); + user_data->ui_json_update_cb = ui_page_06_finished_updatejson; + } + + return ui_page_06_finished.page; +} + +void ui_page_show_06_finished(void) +{ + +} + +void ui_page_hide_06_finished(void) +{ + +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_finished_update_start_time_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_06_finished.start_time_label, "Start_time"); +} + +void ui_after_create_06_finished_start_time_label(const char * name, lv_obj_t * obj) +{ + ui_page_06_finished.start_time_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_finished_update_start_time_label; +} + +void ui_finished_update_energy_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_06_finished.energy_label, "Energy"); +} + +void ui_after_create_06_finished_energy_label(const char * name, lv_obj_t * obj) +{ + ui_page_06_finished.energy_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_finished_update_energy_label; +} + +void ui_finished_update_soc_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_06_finished.soc_label, "SoC"); +} + +void ui_after_create_06_finished_soc_label(const char * name, lv_obj_t * obj) +{ + ui_page_06_finished.soc_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_finished_update_soc_label; +} + +void ui_finished_update_duration_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_06_finished.duration_label, "Duration"); +} + +void ui_after_create_06_finished_duration_label(const char * name, lv_obj_t * obj) +{ + ui_page_06_finished.duration_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_finished_update_duration_label; +} + + +void ui_after_create_06_finished_start_time(const char * name, lv_obj_t * obj) +{ + ui_page_06_finished.start_time = obj; +} +void ui_after_create_06_finished_energy(const char * name, lv_obj_t * obj) +{ + ui_page_06_finished.energy = obj; +} +void ui_after_create_06_finished_start_soc(const char * name, lv_obj_t * obj) +{ + ui_page_06_finished.start_soc = obj; +} +void ui_after_create_06_finished_end_soc(const char * name, lv_obj_t * obj) +{ + ui_page_06_finished.end_soc = obj; +} +void ui_after_create_06_finished_duration(const char * name, lv_obj_t * obj) +{ + ui_page_06_finished.duration = obj; +} +void ui_after_create_06_finished_energy_unit(const char * name, lv_obj_t * obj) +{ + ui_page_06_finished.energy_unit= obj; + ioc_label_set_text(ui_page_06_finished.energy_unit, "kWh"); +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_after_create_06_finished(const char * name, lv_obj_t * obj) +{ + const char * finished_name = name + strlen(UI_NAME_06_FINISHED); + if (strcmp(finished_name, UI_NAME_06_FINISHED_START_TIME_LABEL) == 0) + { + ui_after_create_06_finished_start_time_label(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_06_FINISHED_ENERGY_LABEL) == 0) + { + ui_after_create_06_finished_energy_label(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_06_FINISHED_SOC_LABEL) == 0) + { + ui_after_create_06_finished_soc_label(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_06_FINISHED_DURATION_LABEL) == 0) + { + ui_after_create_06_finished_duration_label(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_06_FINISHED_START_TIME) == 0) + { + ui_after_create_06_finished_start_time(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_06_FINISHED_ENERGY) == 0) + { + ui_after_create_06_finished_energy(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_06_FINISHED_START_SOC) == 0) + { + ui_after_create_06_finished_start_soc(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_06_FINISHED_END_SOC) == 0) + { + ui_after_create_06_finished_end_soc(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_06_FINISHED_DURATION) == 0) + { + ui_after_create_06_finished_duration(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_06_FINISHED_ENERGY_UNIT) == 0) + { + ui_after_create_06_finished_energy_unit(name, obj); + return; + } +} diff --git a/pages/ui_page_06_finished.h b/pages/ui_page_06_finished.h new file mode 100644 index 000000000..1d62706a2 --- /dev/null +++ b/pages/ui_page_06_finished.h @@ -0,0 +1,16 @@ +#ifndef __UI_PAGE_06_FINISHED_H__ +#define __UI_PAGE_06_FINISHED_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_06_finished(lv_obj_t *parent); + +#define UI_NAME_06_FINISHED "main.finished" +void ui_after_create_06_finished(const char * name, lv_obj_t * obj); +void ui_page_show_06_finished(void); +void ui_page_hide_06_finished(void); + +#define UI_FINISHED_DATA g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.finished +#define UI_FINISHED_SHOWE_PRICE g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].showPrice + +#endif diff --git a/pages/ui_page_07_reserved.c b/pages/ui_page_07_reserved.c new file mode 100644 index 000000000..9bb48a45c --- /dev/null +++ b/pages/ui_page_07_reserved.c @@ -0,0 +1,47 @@ +#include "../pages_mngr.h" + + +typedef struct { + + lv_obj_t * page; + +} ui_page_07_reserved_t; + +static ui_page_07_reserved_t ui_page_07_reserved = {NULL}; + + +static void ui_page_07_reserved_updatejson(struct ioc_obj_user_data_s * user_data) +{ + +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +lv_obj_t * ui_page_create_07_reserved(lv_obj_t *parent) +{ + memset(&ui_page_07_reserved, 0, sizeof(ui_page_07_reserved)); + + ui_page_07_reserved.page = ioc_layout_mngr_load_layout("reserved", parent); + if (ui_page_07_reserved.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(ui_page_07_reserved.page); + user_data->ui_json_update_cb = ui_page_07_reserved_updatejson; + } + + return ui_page_07_reserved.page; +} + +void ui_page_show_07_reserved(void) +{ + +} +void ui_page_hide_07_reserved(void) +{ + +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_after_create_07_reserved(const char * name, lv_obj_t * obj) +{ + +} diff --git a/pages/ui_page_07_reserved.h b/pages/ui_page_07_reserved.h new file mode 100644 index 000000000..852c578e0 --- /dev/null +++ b/pages/ui_page_07_reserved.h @@ -0,0 +1,18 @@ +#ifndef __UI_PAGE_07_RESERVED_H__ +#define __UI_PAGE_07_RESERVED_H__ + + +#include "lvgl.h" + +lv_obj_t * ui_page_create_07_reserved(lv_obj_t *parent); + +#define UI_NAME_07_RESERVED "main.reserved" +#define UI_RESERVED_DATA g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.reserved +#define UI_RESERVED_SHOWE_PRICE g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].showPrice +#define UI_RESERVED_SHOWE_OCCPP_PRICE g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].isOcppPrice +void ui_after_create_07_reserved(const char * name, lv_obj_t * obj); +void ui_page_show_07_reserved(void); +void ui_page_hide_07_reserved(void); + + +#endif diff --git a/pages/ui_page_08_session_error.c b/pages/ui_page_08_session_error.c new file mode 100644 index 000000000..d160d9ac7 --- /dev/null +++ b/pages/ui_page_08_session_error.c @@ -0,0 +1,158 @@ +#include "../pages_mngr.h" + +#define UI_NAME_08_SESSION_ERROR_ERROR_LABEL ".session_error.charging_error_title" +#define UI_NAME_08_SESSION_ERROR_ERROR_CODE ".session_error.charging_error_code" +#define UI_NAME_08_SESSION_ERROR_ERROR_CODE_LABEL ".session_error.charging_error_code.label" +#define UI_NAME_08_SESSION_ERROR_ERROR_CODE_VALUE ".session_error.charging_error_code.value" +#define UI_NAME_08_SESSION_ERROR_ERROR_PROMPT ".session_error.charging_error_subtitle" +#define UI_NAME_08_SESSION_ERROR_CONTINUE_BTN ".session_error.charging_error_continue_btn" +#define UI_NAME_08_SESSION_ERROR_CONTINUE_LABEL ".session_error.charging_error_continue_btn.continue_label" + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * error_label; + lv_obj_t * error_code; + lv_obj_t * error_code_label; + lv_obj_t * error_code_value; + lv_obj_t * error_prompt; + lv_obj_t * continue_btn; + lv_obj_t * continue_label; + +} ui_page_08_session_error_t; + +static ui_page_08_session_error_t ui_page_08_session_error = {NULL}; + +lv_obj_t * ui_page_create_08_session_error(lv_obj_t *parent) +{ + return ioc_layout_mngr_load_layout("session_error", parent); +} + +void ui_session_error_update_error_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_08_session_error.error_label, "Charging_session_error"); +} + +void ui_after_create_08_session_error_error_label(const char * name, lv_obj_t * obj) +{ + ui_page_08_session_error.error_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_session_error_update_error_label; +} + +void ui_after_create_08_session_error_error_code(const char * name, lv_obj_t * obj) +{ + ui_page_08_session_error.error_code = obj; + lv_obj_set_layout(obj, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW); + lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + lv_obj_set_style_pad_column(obj, 0, 0); +} + +void ui_session_error_update_error_code_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_08_session_error.error_code_label, "Error_code_session_error"); +} + +void ui_session_error_update_error_code_value(struct ioc_obj_user_data_s * user_data) +{ + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%d", g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].stopCode); + ioc_label_set_text(ui_page_08_session_error.error_code_value, buf); +} + +void ui_after_create_08_session_error_error_code_label(const char * name, lv_obj_t * obj) +{ + ui_page_08_session_error.error_code_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_session_error_update_error_code_label; +} + +void ui_after_create_08_session_error_error_code_value(const char * name, lv_obj_t * obj) +{ + ui_page_08_session_error.error_code_value = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_session_error_update_error_code_value; +} + +void ui_session_error_update_error_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_08_session_error.error_prompt, "session_error_prompt"); +} + +void ui_after_create_08_session_error_error_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_08_session_error.error_prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_session_error_update_error_prompt; +} + +static void continue_btn_event_cb(lv_event_t *e) +{ + + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + g_ui_json.isUiJsonControlLocked[ UI_CONNECTOR_ACTIVE_IDX ] = false; + ioc_ui_json_set_conn_state(UI_CONNECTOR_ACTIVE_IDX, UI_PAGE_FINISHED); + ioc_ui_overtime_changed_page(); + } +} + +void ui_after_create_08_session_error_continue_btn(const char * name, lv_obj_t * obj) +{ + ui_page_08_session_error.continue_btn = obj; + lv_obj_add_event_cb(obj, continue_btn_event_cb, LV_EVENT_CLICKED, NULL); +} + +void ui_session_error_update_continue_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_08_session_error.continue_label, "Continue"); +} + +void ui_after_create_08_session_error_continue_label(const char * name, lv_obj_t * obj) +{ + ui_page_08_session_error.continue_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_session_error_update_continue_label; +} + +void ui_after_create_08_session_error(const char * name, lv_obj_t * obj) +{ + const char * session_error_name = name + strlen(UI_NAME_08_SESSION_ERROR); + if (strcmp(session_error_name, UI_NAME_08_SESSION_ERROR_ERROR_LABEL) == 0) + { + ui_after_create_08_session_error_error_label(name, obj); + return; + } + else if (strcmp(session_error_name, UI_NAME_08_SESSION_ERROR_ERROR_CODE) == 0) + { + ui_after_create_08_session_error_error_code(name, obj); + return; + } + else if (strcmp(session_error_name, UI_NAME_08_SESSION_ERROR_ERROR_CODE_LABEL) == 0) + { + ui_after_create_08_session_error_error_code_label(name, obj); + return; + } + else if (strcmp(session_error_name, UI_NAME_08_SESSION_ERROR_ERROR_CODE_VALUE) == 0) + { + ui_after_create_08_session_error_error_code_value(name, obj); + return; + } + else if (strcmp(session_error_name, UI_NAME_08_SESSION_ERROR_ERROR_PROMPT) == 0) + { + ui_after_create_08_session_error_error_prompt(name, obj); + return; + } + else if (strcmp(session_error_name, UI_NAME_08_SESSION_ERROR_CONTINUE_BTN) == 0) + { + ui_after_create_08_session_error_continue_btn(name, obj); + return; + } + else if (strcmp(session_error_name, UI_NAME_08_SESSION_ERROR_CONTINUE_LABEL) == 0) + { + ui_after_create_08_session_error_continue_label(name, obj); + return; + } +} diff --git a/pages/ui_page_08_session_error.h b/pages/ui_page_08_session_error.h new file mode 100644 index 000000000..95b02fd5e --- /dev/null +++ b/pages/ui_page_08_session_error.h @@ -0,0 +1,11 @@ +#ifndef __UI_PAGE_08_SESSION_ERROR_H__ +#define __UI_PAGE_08_SESSION_ERROR_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_08_session_error(lv_obj_t *parent); + +#define UI_NAME_08_SESSION_ERROR "main.session_error" +void ui_after_create_08_session_error(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_09_start_error.c b/pages/ui_page_09_start_error.c new file mode 100644 index 000000000..f8c8d0eb1 --- /dev/null +++ b/pages/ui_page_09_start_error.c @@ -0,0 +1,163 @@ +#include "../pages_mngr.h" + + +#define UI_NAME_09_START_ERROR_ERROR_LABEL ".start_error.charging_error_title" +#define UI_NAME_09_START_ERROR_ERROR_CODE ".start_error.charging_error_code" +#define UI_NAME_09_START_ERROR_ERROR_CODE_LABEL ".start_error.charging_error_code.label" +#define UI_NAME_09_START_ERROR_ERROR_CODE_VALUE ".start_error.charging_error_code.value" +#define UI_NAME_09_START_ERROR_ERROR_PROMPT ".start_error.charging_error_subtitle" +#define UI_NAME_09_START_ERROR_CONTINUE_BTN ".start_error.charging_error_continue_btn" +#define UI_NAME_09_START_ERROR_CONTINUE_LABEL ".start_error.charging_error_continue_btn.continue_label" + + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * error_label; + lv_obj_t * error_code; + lv_obj_t * error_code_label; + lv_obj_t * error_code_value; + lv_obj_t * error_prompt; + lv_obj_t * continue_btn; + lv_obj_t * continue_label; + +} ui_page_09_start_error_t; + +static ui_page_09_start_error_t ui_page_09_start_error = {NULL}; + + +lv_obj_t * ui_page_create_09_start_error(lv_obj_t *parent) +{ + return ioc_layout_mngr_load_layout("start_error", parent); +} + +void ui_start_error_update_error_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_09_start_error.error_label, "Charging_start_error"); +} + +void ui_after_create_09_start_error_error_label(const char * name, lv_obj_t * obj) +{ + ui_page_09_start_error.error_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_start_error_update_error_label; +} + + + +void ui_after_create_09_start_error_error_code(const char * name, lv_obj_t * obj) +{ + ui_page_09_start_error.error_code = obj; + lv_obj_set_layout(obj, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW); + lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + lv_obj_set_style_pad_column(obj, 0, 0); +} + +void ui_start_error_update_error_code_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_09_start_error.error_code_label, "Error_code_session_error"); +} + +void ui_start_error_update_error_code_value(struct ioc_obj_user_data_s * user_data) +{ + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%d", g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].m1768errCode); + ioc_label_set_text(ui_page_09_start_error.error_code_value, buf); +} + +void ui_after_create_09_start_error_error_code_label(const char * name, lv_obj_t * obj) +{ + ui_page_09_start_error.error_code_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_start_error_update_error_code_label; +} + +void ui_after_create_09_start_error_error_code_value(const char * name, lv_obj_t * obj) +{ + ui_page_09_start_error.error_code_value = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_start_error_update_error_code_value; +} + +void ui_start_error_update_error_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_09_start_error.error_prompt, "start_error_prompt"); +} + +void ui_after_create_09_start_error_error_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_09_start_error.error_prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_start_error_update_error_prompt; +} + +static void continue_btn_event_cb(lv_event_t *e) +{ + + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + g_ui_json.isUiJsonControlLocked[ UI_CONNECTOR_ACTIVE_IDX ] = false; + ioc_ui_json_set_conn_state(UI_CONNECTOR_ACTIVE_IDX, UI_PAGE_FINISHED); + ioc_ui_overtime_changed_page(); + } +} + +void ui_after_create_09_start_error_continue_btn(const char * name, lv_obj_t * obj) +{ + ui_page_09_start_error.continue_btn = obj; + lv_obj_add_event_cb(obj, continue_btn_event_cb, LV_EVENT_CLICKED, NULL); +} + +void ui_start_error_update_continue_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_09_start_error.continue_label, "Continue"); +} + +void ui_after_create_09_start_error_continue_label(const char * name, lv_obj_t * obj) +{ + ui_page_09_start_error.continue_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_start_error_update_continue_label; +} + +void ui_after_create_09_start_error(const char * name, lv_obj_t * obj) +{ + const char * start_error_name = name + strlen(UI_NAME_09_START_ERROR); + if (strcmp(start_error_name, UI_NAME_09_START_ERROR_ERROR_LABEL) == 0) + { + ui_after_create_09_start_error_error_label(name, obj); + return; + } + else if (strcmp(start_error_name, UI_NAME_09_START_ERROR_ERROR_CODE) == 0) + { + ui_after_create_09_start_error_error_code(name, obj); + return; + } + else if (strcmp(start_error_name, UI_NAME_09_START_ERROR_ERROR_CODE_LABEL) == 0) + { + ui_after_create_09_start_error_error_code_label(name, obj); + return; + } + else if (strcmp(start_error_name, UI_NAME_09_START_ERROR_ERROR_CODE_VALUE) == 0) + { + ui_after_create_09_start_error_error_code_value(name, obj); + return; + } + else if (strcmp(start_error_name, UI_NAME_09_START_ERROR_ERROR_PROMPT) == 0) + { + ui_after_create_09_start_error_error_prompt(name, obj); + return; + } + else if (strcmp(start_error_name, UI_NAME_09_START_ERROR_CONTINUE_BTN) == 0) + { + ui_after_create_09_start_error_continue_btn(name, obj); + return; + } + else if (strcmp(start_error_name, UI_NAME_09_START_ERROR_CONTINUE_LABEL) == 0) + { + ui_after_create_09_start_error_continue_label(name, obj); + return; + } +} diff --git a/pages/ui_page_09_start_error.h b/pages/ui_page_09_start_error.h new file mode 100644 index 000000000..1c5f1d7ff --- /dev/null +++ b/pages/ui_page_09_start_error.h @@ -0,0 +1,11 @@ +#ifndef __UI_PAGE_09_START_ERROR_H__ +#define __UI_PAGE_09_START_ERROR_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_09_start_error(lv_obj_t *parent); + +#define UI_NAME_09_START_ERROR "main.start_error" +void ui_after_create_09_start_error(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_10_fault.c b/pages/ui_page_10_fault.c new file mode 100644 index 000000000..454bee786 --- /dev/null +++ b/pages/ui_page_10_fault.c @@ -0,0 +1,222 @@ +#include "../pages_mngr.h" + +#define UI_NAME_10_FAULT_EQUIPMENT_FAILURE ".fault_title" +#define UI_NAME_10_FAULT_ERROR_CODE ".fault_code" +#define UI_NAME_10_FAULT_ERROR_PROMPT ".fault_subtitle" + + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * equipment_failure; + lv_obj_t * error_code; + lv_obj_t * error_prompt; + +} ui_page_10_fault_t; + +typedef enum +{ + NoError = 0, + ConnectorLockFailure, + EVCommunicationError, + GroundFailure, + HighTemperature, + InternalError, + LocalListConflict, + OtherError, + OverCurrentFailure, + OverVoltage, + PowerMeterFailure, + PowerSwitchFailure, + ReaderFailure, + ResetFailure, + UnderVoltage, + WeakSignal, + + ChargePointErrorCode_Basic_NUM +} ChargePointErrorCodeBasic; +typedef enum +{ + InternalError_Emergency = ChargePointErrorCode_Basic_NUM, + InternalError_PhaseSwap, + + InternalError_RCD_FAULT, + InternalError_PE_LEAK, + InternalError_PME_FAULT, + InternalError_Power_Temp_Over, + + InternalError_CPStatusE, + + InternalError_OpenDoor, + InternalError_PEWiring, + InternalError_RCD_OPENED, // 3354支持本地检测RCD是否脱扣 + InternalError_PowerDown, // 功率板掉电 + InternalError_CoolFault, // 液冷故障 + + ChargePointErrorCode_NUM +} ChargePointErrorCode; + +const char * c_ChargePointErrorCodeName[ChargePointErrorCode_NUM] = +{ + "NoError", + "ConnectorLockFailure", + "EVCommunicationError", + "GroundFailure", + "HighTemperature", + "InternalError", + "LocalListConflict", + "OtherError", + "OverCurrentFailure", + "OverVoltage", + "PowerMeterFailure", + "PowerSwitchFailure", + "ReaderFailure", + "ResetFailure", + "UnderVoltage", + "WeakSignal", + + "EmergencyStop", + "PhaseSwap", + "RCD_6mA", // RCD 6mA漏电 + "PE_LEAK", // PE漏电 + "PME_FAULT", + "PowerTempOver", + "CP Status E", + "Open Door", + "PE Wiring", + "MCCB Opened", + "PowerDown", + "CoolFault", +}; + +static ui_page_10_fault_t ui_page_10_fault = {NULL}; + + +lv_obj_t * ui_page_create_10_fault(lv_obj_t *parent) +{ + return ioc_layout_mngr_load_layout("fault", parent); +} + + +void ui_fault_update_equipment_failure(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_10_fault.equipment_failure, "Equipment_failure"); +} + +void ui_after_create_10_fault_equipment_failure(const char * name, lv_obj_t * obj) +{ + ui_page_10_fault.equipment_failure = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_fault_update_equipment_failure; +} + +void ui_fault_update_error_code(struct ioc_obj_user_data_s * user_data) +{ + char str[255]; + const char *err = UI_CONNECTOR_ERRCODE; + if ( strcmp(err, c_ChargePointErrorCodeName[ConnectorLockFailure]) == 0 ){ + snprintf(str, sizeof(str), "Lock Failure"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[EVCommunicationError]) == 0 ){ + snprintf(str, sizeof(str), "EV Communication Error"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[GroundFailure]) == 0 ){ + snprintf(str, sizeof(str), "Ground Failure"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[HighTemperature]) == 0 ){ + snprintf(str, sizeof(str), "High Temperature"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[InternalError]) == 0 ){ + snprintf(str, sizeof(str), "Internal Error"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[OverCurrentFailure]) == 0 ){ + snprintf(str, sizeof(str), "Over Current"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[OverVoltage]) == 0 ){ + snprintf(str, sizeof(str), "Over Voltage"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[PowerMeterFailure]) == 0 ){ + snprintf(str, sizeof(str), "Meter Failure"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[PowerSwitchFailure]) == 0 ){ + snprintf(str, sizeof(str), "Power Switch Failure"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[ReaderFailure]) == 0 ){ + snprintf(str, sizeof(str), "Reader Failure"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[ResetFailure]) == 0 ){ + snprintf(str, sizeof(str), "Reset Failure"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[UnderVoltage]) == 0 ){ + snprintf(str, sizeof(str), "Under Voltage"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[WeakSignal]) == 0 ){ + snprintf(str, sizeof(str), "Weak Signal"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[InternalError_Emergency]) == 0 ){ + snprintf(str, sizeof(str), "Emergency Pushed"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[InternalError_PhaseSwap]) == 0 ){ + snprintf(str, sizeof(str), "PhaseSwap Failure"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[OtherError]) == 0 ){ + snprintf(str, sizeof(str), "Other Error"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[InternalError_OpenDoor]) == 0 ){ + snprintf(str, sizeof(str), "Door Opened"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[InternalError_RCD_OPENED]) == 0 ){ + snprintf(str, sizeof(str), "MCCB Opened"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[InternalError_PowerDown]) == 0 ){ + snprintf(str, sizeof(str), "PowerDown"); + } + else if ( strcmp(err, c_ChargePointErrorCodeName[InternalError_CoolFault]) == 0 ){ + snprintf(str, sizeof(str), "CoolFault"); + } + else { + snprintf(str, sizeof(str), "Unknown Error"); + } + + ioc_label_set_text(ui_page_10_fault.error_code, str); +} + +void ui_after_create_10_fault_error_code(const char * name, lv_obj_t * obj) +{ + ui_page_10_fault.error_code = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_fault_update_error_code; +} + +void ui_fault_update_error_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_10_fault.error_prompt, "fault_prompt"); +} + +void ui_after_create_10_fault_error_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_10_fault.error_prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_fault_update_error_prompt; +} + +void ui_after_create_10_fault(const char * name, lv_obj_t * obj) +{ + const char * fault_name = name + strlen(UI_NAME_10_FAULT); + if (strcmp(fault_name, UI_NAME_10_FAULT_EQUIPMENT_FAILURE) == 0) + { + ui_after_create_10_fault_equipment_failure(name, obj); + return; + } + else if (strcmp(fault_name, UI_NAME_10_FAULT_ERROR_CODE) == 0) + { + ui_after_create_10_fault_error_code(name, obj); + return; + } + else if (strcmp(fault_name, UI_NAME_10_FAULT_ERROR_PROMPT) == 0) + { + ui_after_create_10_fault_error_prompt(name, obj); + return; + } +} diff --git a/pages/ui_page_10_fault.h b/pages/ui_page_10_fault.h new file mode 100644 index 000000000..b64bd627b --- /dev/null +++ b/pages/ui_page_10_fault.h @@ -0,0 +1,11 @@ +#ifndef __UI_PAGE_10_FAULT_H__ +#define __UI_PAGE_10_FAULT_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_10_fault(lv_obj_t *parent); + +#define UI_NAME_10_FAULT "main.fault" +void ui_after_create_10_fault(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_11_unavailable.c b/pages/ui_page_11_unavailable.c new file mode 100644 index 000000000..95a560518 --- /dev/null +++ b/pages/ui_page_11_unavailable.c @@ -0,0 +1,62 @@ +#include "../pages_mngr.h" + +#define UI_NAME_11_UNAVAILABLE_OUT_SERVICE ".unavailable_title" +#define UI_NAME_11_UNAVAILABLE_PROMPT ".unavailable_subtitle" + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * out_of_service; + lv_obj_t * prompt; + +} ui_page_11_unavailable_t; + +static ui_page_11_unavailable_t ui_page_11_unavailable = {NULL}; + + +lv_obj_t * ui_page_create_11_unavailable(lv_obj_t *parent) +{ + return ioc_layout_mngr_load_layout("unavailable", parent); +} + + +void ui_unavailable_update_out_of_service(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_11_unavailable.out_of_service, "Out_of_service"); +} + +void ui_after_create_11_unavailable_out_of_service(const char * name, lv_obj_t * obj) +{ + ui_page_11_unavailable.out_of_service = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_unavailable_update_out_of_service; +} + +void ui_unavailable_update_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_11_unavailable.prompt, "unavailable_prompt"); +} + +void ui_after_create_11_unavailable_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_11_unavailable.prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_unavailable_update_prompt; +} + + +void ui_after_create_11_unavailable(const char * name, lv_obj_t * obj) +{ + const char * unavailable_name = name + strlen(UI_NAME_11_UNAVAILABLE); + if (strcmp(unavailable_name, UI_NAME_11_UNAVAILABLE_OUT_SERVICE) == 0) + { + ui_after_create_11_unavailable_out_of_service(name, obj); + return; + } + else if (strcmp(unavailable_name, UI_NAME_11_UNAVAILABLE_PROMPT) == 0) + { + ui_after_create_11_unavailable_prompt(name, obj); + return; + } +} diff --git a/pages/ui_page_11_unavailable.h b/pages/ui_page_11_unavailable.h new file mode 100644 index 000000000..15707206b --- /dev/null +++ b/pages/ui_page_11_unavailable.h @@ -0,0 +1,11 @@ +#ifndef __UI_PAGE_11_UNAVAILABLE_H__ +#define __UI_PAGE_11_UNAVAILABLE_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_11_unavailable(lv_obj_t *parent); + +#define UI_NAME_11_UNAVAILABLE "main.unavailable" +void ui_after_create_11_unavailable(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_12_connecting.c b/pages/ui_page_12_connecting.c new file mode 100644 index 000000000..03878fbc2 --- /dev/null +++ b/pages/ui_page_12_connecting.c @@ -0,0 +1,61 @@ +#include "../pages_mngr.h" + +#define UI_NAME_12_CONNECTING_PLUG_CHARGE_LABEL ".connecting_title" +#define UI_NAME_12_CONNECTING_PLUG_CHARGE_PROMPT ".connecting_subtitle" + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * plug_charge_label; + lv_obj_t * plug_charge_prompt; + +} ui_page_12_connecting_t; + +static ui_page_12_connecting_t ui_page_12_connecting = {NULL}; + + +lv_obj_t * ui_page_create_12_connecting(lv_obj_t *parent) +{ + return ioc_layout_mngr_load_layout("connecting", parent); +} + +void ui_connecting_update_plug_charge_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_12_connecting.plug_charge_label, "Plug & Charge"); +} + +void ui_after_create_12_connecting_plug_charge_label(const char * name, lv_obj_t * obj) +{ + ui_page_12_connecting.plug_charge_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_connecting_update_plug_charge_label; +} + + +void ui_connecting_update_plug_charge_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_12_connecting.plug_charge_prompt, "connecting_prompt"); +} + +void ui_after_create_12_connecting_plug_charge_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_12_connecting.plug_charge_prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_connecting_update_plug_charge_prompt; +} + +void ui_after_create_12_connecting(const char * name, lv_obj_t * obj) +{ + const char * connecting_name = name + strlen(UI_NAME_12_CONNECTING); + if (strcmp(connecting_name, UI_NAME_12_CONNECTING_PLUG_CHARGE_LABEL) == 0) + { + ui_after_create_12_connecting_plug_charge_label(name, obj); + return; + } + else if (strcmp(connecting_name, UI_NAME_12_CONNECTING_PLUG_CHARGE_PROMPT) == 0) + { + ui_after_create_12_connecting_plug_charge_prompt(name, obj); + return; + } +} diff --git a/pages/ui_page_12_connecting.h b/pages/ui_page_12_connecting.h new file mode 100644 index 000000000..1d5381107 --- /dev/null +++ b/pages/ui_page_12_connecting.h @@ -0,0 +1,12 @@ +#ifndef __UI_PAGE_12_CONNECTING_H__ +#define __UI_PAGE_12_CONNECTING_H__ + + +#include "lvgl.h" + +lv_obj_t * ui_page_create_12_connecting(lv_obj_t *parent); + +#define UI_NAME_12_CONNECTING "main.connecting" +void ui_after_create_12_connecting(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_14_stopping.c b/pages/ui_page_14_stopping.c new file mode 100644 index 000000000..192ff455d --- /dev/null +++ b/pages/ui_page_14_stopping.c @@ -0,0 +1,41 @@ +#include "../pages_mngr.h" + +#define UI_NAME_14_STOPPING_LABEL ".stopping_title" + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * stopping_label; + +} ui_page_14_stopping_t; + +static ui_page_14_stopping_t ui_page_14_stopping = {NULL}; + + +lv_obj_t * ui_page_create_14_stopping(lv_obj_t *parent) +{ + return ioc_layout_mngr_load_layout("stopping", parent); +} + +void ui_stopping_update_stopping_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_14_stopping.stopping_label, "Charging_is_stopping"); +} + +void ui_after_create_14_stopping_stopping_label(const char * name, lv_obj_t * obj) +{ + ui_page_14_stopping.stopping_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_stopping_update_stopping_label; +} + +void ui_after_create_14_stopping(const char * name, lv_obj_t * obj) +{ + const char * stopping_name = name + strlen(UI_NAME_14_STOPPING); + if (strcmp(stopping_name, UI_NAME_14_STOPPING_LABEL) == 0) + { + ui_after_create_14_stopping_stopping_label(name, obj); + return; + } +} diff --git a/pages/ui_page_14_stopping.h b/pages/ui_page_14_stopping.h new file mode 100644 index 000000000..1a7e677a6 --- /dev/null +++ b/pages/ui_page_14_stopping.h @@ -0,0 +1,12 @@ +#ifndef __UI_PAGE_14_STOPPING_H__ +#define __UI_PAGE_14_STOPPING_H__ + + +#include "lvgl.h" + +lv_obj_t * ui_page_create_14_stopping(lv_obj_t *parent); + +#define UI_NAME_14_STOPPING "main.stopping" +void ui_after_create_14_stopping(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_15_wait_in_line.c b/pages/ui_page_15_wait_in_line.c new file mode 100644 index 000000000..dfcc7b354 --- /dev/null +++ b/pages/ui_page_15_wait_in_line.c @@ -0,0 +1,100 @@ +#include "../pages_mngr.h" + +#define UI_NAME_15_WAIT_IN_LINE_LABEL ".wait_in_line.charging_process_title" +#define UI_NAME_15_WAIT_IN_LINE_PROMPT ".wait_in_line.charging_process_subtitle" +#define UI_NAME_15_WAIT_IN_LINE_PROMPT_GIF ".wait_in_line.charging_process_gif" + + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * label; + lv_obj_t * prompt; + lv_obj_t * gif; + +} ui_page_15_wait_in_line_t; + +static ui_page_15_wait_in_line_t ui_page_15_wait_in_line = {NULL}; + +static bool gif_playing = false; + +void ui_page_show_15_wait_in_line(void) +{ + if (ui_page_15_wait_in_line.gif != NULL) + { + if(!gif_playing) + { + // LV_LOG_WARN("666======================================="); + lv_gif_set_src(ui_page_15_wait_in_line.gif, "A:./assets/images/processing.gif"); // 因为LVGL版本原因,restart不能重启gif定时器,所以需要重置 + gif_playing = true; + } + } +} + +void ui_page_hide_15_wait_in_line(void) +{ + if (ui_page_15_wait_in_line.gif != NULL) + { + // LV_LOG_WARN("888======================================="); + if(gif_playing) + { + lv_gif_pause(ui_page_15_wait_in_line.gif); + } + } +} + + +lv_obj_t * ui_page_create_15_wait_in_line(lv_obj_t *parent) +{ + return ioc_layout_mngr_load_layout("wait_in_line", parent); +} + +void ui_wait_in_line_update_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_15_wait_in_line.label, "Wait_in_line"); +} + +void ui_after_create_15_wait_in_line_label(const char * name, lv_obj_t * obj) +{ + ui_page_15_wait_in_line.label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_wait_in_line_update_label; +} + +void ui_wait_in_line_update_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_15_wait_in_line.prompt, "Wait_in_line_prompt"); +} + +void ui_after_create_15_wait_in_line_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_15_wait_in_line.prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_wait_in_line_update_prompt; +} + +void ui_after_create_15_wait_in_line_gif(const char * name, lv_obj_t * obj) +{ + ui_page_15_wait_in_line.gif = obj; +} + +void ui_after_create_15_wait_in_line(const char * name, lv_obj_t * obj) +{ + const char * wait_in_line_label_name = name + strlen(UI_NAME_15_WAIT_IN_LINE); + if (strcmp(wait_in_line_label_name, UI_NAME_15_WAIT_IN_LINE_LABEL) == 0) + { + ui_after_create_15_wait_in_line_label(name, obj); + return; + } + else if (strcmp(wait_in_line_label_name, UI_NAME_15_WAIT_IN_LINE_PROMPT) == 0) + { + ui_after_create_15_wait_in_line_prompt(name, obj); + return; + } + else if (strcmp(wait_in_line_label_name, UI_NAME_15_WAIT_IN_LINE_PROMPT_GIF) == 0) + { + ui_after_create_15_wait_in_line_gif(name, obj); + return; + } +} diff --git a/pages/ui_page_15_wait_in_line.h b/pages/ui_page_15_wait_in_line.h new file mode 100644 index 000000000..326139c8f --- /dev/null +++ b/pages/ui_page_15_wait_in_line.h @@ -0,0 +1,14 @@ +#ifndef __UI_PAGE_15_WAIT_IN_LINE_H__ +#define __UI_PAGE_15_WAIT_IN_LINE_H__ + + +#include "lvgl.h" + +lv_obj_t * ui_page_create_15_wait_in_line(lv_obj_t *parent); +void ui_page_show_15_wait_in_line(void); +void ui_page_hide_15_wait_in_line(void); + +#define UI_NAME_15_WAIT_IN_LINE "main.wait_in_line" +void ui_after_create_15_wait_in_line(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_16_suspend.c b/pages/ui_page_16_suspend.c new file mode 100644 index 000000000..57839dad7 --- /dev/null +++ b/pages/ui_page_16_suspend.c @@ -0,0 +1,62 @@ +#include "../pages_mngr.h" + +#define UI_NAME_16_SUSPEND_LABEL ".suspend_label" +#define UI_NAME_16_SUSPEND_REASON ".suspend_reason" + + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * suspend_label; + lv_obj_t * suspend_reason; + + +} ui_page_16_suspend_t; + +static ui_page_16_suspend_t ui_page_16_suspend = {NULL}; + +lv_obj_t * ui_page_create_16_suspend(lv_obj_t *parent) +{ + return ioc_layout_mngr_load_layout("suspend", parent); +} + + +void ui_suspend_update_suspend_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_16_suspend.suspend_label, "Charging_suspend"); +} + +void ui_after_create_16_suspend_suspend_label(const char * name, lv_obj_t * obj) +{ + ui_page_16_suspend.suspend_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_suspend_update_suspend_label; +} + +void ui_suspend_update_suspend_reason(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_16_suspend.suspend_reason, ""); +} + +void ui_after_create_16_suspend_suspend_reason(const char * name, lv_obj_t * obj) +{ + ui_page_16_suspend.suspend_reason = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_suspend_update_suspend_reason; +} + +void ui_after_create_16_suspend(const char * name, lv_obj_t * obj) +{ + const char * suspend_label_name = name + strlen(UI_NAME_16_SUSPEND); + if (strcmp(suspend_label_name, UI_NAME_16_SUSPEND_LABEL) == 0) + { + ui_after_create_16_suspend_suspend_label(name, obj); + return; + } + else if (strcmp(suspend_label_name, UI_NAME_16_SUSPEND_REASON) == 0) + { + ui_after_create_16_suspend_suspend_reason(name, obj); + return; + } +} diff --git a/pages/ui_page_16_suspend.h b/pages/ui_page_16_suspend.h new file mode 100644 index 000000000..2589befd2 --- /dev/null +++ b/pages/ui_page_16_suspend.h @@ -0,0 +1,11 @@ +#ifndef __UI_PAGE_16_SUSPEND_H__ +#define __UI_PAGE_16_SUSPEND_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_16_suspend(lv_obj_t *parent); + +#define UI_NAME_16_SUSPEND "main.suspend" +void ui_after_create_16_suspend(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_17_processing.c b/pages/ui_page_17_processing.c new file mode 100644 index 000000000..a01d9b753 --- /dev/null +++ b/pages/ui_page_17_processing.c @@ -0,0 +1,121 @@ +#include "../pages_mngr.h" + +#define UI_NAME_17_PROCESSING_LABEL ".processing.charging_process_title" +#define UI_NAME_17_PROCESSING_PROMPT ".processing.charging_process_subtitle" +#define UI_NAME_17_PROCESSING_GIF ".processing.charging_process_gif" + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * label; + lv_obj_t * prompt; + lv_obj_t * gif; + +} ui_page_17_processing_t; + +static ui_page_17_processing_t ui_page_17_processing = {NULL}; + +static bool gif_playing = false; + + +void ui_page_show_17_processing(void) +{ + + if (ui_page_17_processing.gif != NULL) + { + if(!gif_playing) + { + // LV_LOG_WARN("222======================================="); + lv_gif_set_src(ui_page_17_processing.gif, "A:./assets/images/processing.gif"); // 因为LVGL版本原因,restart不能重启gif定时器,所以需要重置 + gif_playing = true; + } + } +} + +void ui_page_hide_17_processing(void) +{ + if (ui_page_17_processing.gif != NULL) + { + if(gif_playing) + { + // LV_LOG_WARN("444======================================="); + lv_gif_pause(ui_page_17_processing.gif); + gif_playing = false; + } + } +} + +lv_obj_t * ui_page_create_17_processing(lv_obj_t *parent) +{ + return ioc_layout_mngr_load_layout("processing", parent); +} + + +void ui_processing_update_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_17_processing.label, "Processing"); +} + +void ui_after_create_17_processing_label(const char * name, lv_obj_t * obj) +{ + ui_page_17_processing.label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_processing_update_label; +} + + +void ui_processing_update_prompt(struct ioc_obj_user_data_s * user_data) +{ + switch (g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX_SINGLE].startingSubStep) + { + case STARTING_HANDSHAKE: + ioc_label_set_text(ui_page_17_processing.prompt, "Handshake"); // TODO 国际化 + break; + case STARTING_INSULATION: + ioc_label_set_text(ui_page_17_processing.prompt, "Insulation"); // TODO 国际化 + break; + case STARTING_PARAMTETER: + ioc_label_set_text(ui_page_17_processing.prompt, "Parameter"); // TODO 国际化 + break; + case STARTING_PRECHARGE: + ioc_label_set_text(ui_page_17_processing.prompt, "PreCharge"); // TODO 国际化 + break; + case STARTING_AC: + default: + ioc_label_set_text(ui_page_17_processing.prompt, "... ..."); + break; + } +} + +void ui_after_create_17_processing_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_17_processing.prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_processing_update_prompt; +} + +void ui_after_create_17_processing_gif(const char * name, lv_obj_t * obj) +{ + ui_page_17_processing.gif = obj; +} + +void ui_after_create_17_processing(const char * name, lv_obj_t * obj) +{ + const char * processing_name = name + strlen(UI_NAME_17_PROCESSING); + if (strcmp(processing_name, UI_NAME_17_PROCESSING_LABEL) == 0) + { + ui_after_create_17_processing_label(name, obj); + return; + } + else if (strcmp(processing_name, UI_NAME_17_PROCESSING_PROMPT) == 0) + { + ui_after_create_17_processing_prompt(name, obj); + return; + } + else if (strcmp(processing_name, UI_NAME_17_PROCESSING_GIF) == 0) + { + ui_after_create_17_processing_gif(name, obj); + return; + } +} diff --git a/pages/ui_page_17_processing.h b/pages/ui_page_17_processing.h new file mode 100644 index 000000000..e849d4195 --- /dev/null +++ b/pages/ui_page_17_processing.h @@ -0,0 +1,14 @@ +#ifndef __UI_PAGE_17_PROCESSING_H__ +#define __UI_PAGE_17_PROCESSING_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_17_processing(lv_obj_t *parent); + +void ui_page_show_17_processing(void); +void ui_page_hide_17_processing(void); + +#define UI_NAME_17_PROCESSING "main.processing" +void ui_after_create_17_processing(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_connector_group.c b/pages/ui_page_connector_group.c new file mode 100644 index 000000000..981a35535 --- /dev/null +++ b/pages/ui_page_connector_group.c @@ -0,0 +1,626 @@ + +#include "../pages_mngr.h" + +#define UI_NAME_CONNECTOR_CARD_NO "conn_card_id" +#define UI_NAME_CONNECTOR_CARD_NO_TEXT "conn_card_id.NoText" +#define UI_NAME_CONNECTOR_CARD_STATE "conn_card_state" +#define UI_NAME_CONNECTOR_CARD_TYPE "conn_card_type" +#define UI_NAME_CONNECTOR_CARD_POWER "conn_card_power_rated" +#define UI_NAME_CONNECTOR_CARD_TYPE_ICON "conn_card_type_icon" +#define UI_NAME_CONNECTOR_CARD_PLUG_GUN_ICON "conn_card_plug_gun_icon" +#define UI_NAME_CONNECTOR_CARD_TIME_LABEL "conn_card_time_title" +#define UI_NAME_CONNECTOR_CARD_TIME "conn_card_time" +#define UI_NAME_CONNECTOR_CARD_SOC_BAR "conn_card_soc_bar" +#define UI_NAME_CONNECTOR_CARD_SOC_LABEL "conn_card_soc" +#define UI_NAME_CONNECTOR_CARD_POWER_REAL "conn_card_power_real" +// 60秒无操作后返回home页面 +#define CANCEL_ACTIVE_GUN_TIMER_COUNT 60 + +typedef enum { + CARD_VISUAL_IDLE = 0, + CARD_VISUAL_CHARGING, + CARD_VISUAL_FAULT, + CARD_VISUAL_RESERVED, + CARD_VISUAL_UNAVAILABLE, + CARD_VISUAL_SUSPEND, + + CARD_VISUAL_NUM +} card_visual_state_t; + +typedef struct +{ + uint8_t idx; + + ioc_ui_connector_state_t state; // 记录state, 跟UI.json对比, 不一致需要更新Style + lv_obj_t * card; // 卡片本身, 需要按照不同的State来切换Style + lv_style_t * visual_style[CARD_VISUAL_NUM]; // 预置的卡片选中状态的style + lv_color_t style_color[CARD_VISUAL_NUM]; // 不同style对应的颜色 + card_visual_state_t current_visual_state; // 卡片当前选中状态的state + bool card_actived; // 卡片是否被激活 + lv_timer_t * cancel_active_gun_timer; // 60秒无操作后取消激活枪的定时器 + + lv_obj_t * text_state; // 当前状态, 需要根据State来改变 + + lv_obj_t * no; // 枪编号, 一次性, 不需要改变 + lv_obj_t * text_no; // 枪编号文本, 一次性, 不需要改变 + lv_obj_t * text_type; // 枪类型, 一次性, 不需要改变 + lv_obj_t * text_power_rated; // 枪额定功率, 一次性, 不需要改变 + lv_obj_t * type_icon; // 枪类型图标, 一次性, 不需要改变 + lv_obj_t * plug_gun_icon; // 枪类型图标, 一次性, 不需要改变 + + lv_obj_t * text_time_label; // 计时时间提示信息, Reserved为剩余时间, Finished为占位时间 + lv_obj_t * text_time_value; // 计时时间值, Reserved为剩余时间, Finished为占位时间 + + lv_obj_t * bar_soc; // 充电中SoC进度条, 仅Charging状态 + lv_obj_t * text_soc; // 充电中SoC文本, 仅Charging状态 + lv_obj_t * text_power_real; // 充电中实时功率, 仅Charging状态 + +} ui_connector_card_t; +lv_timer_t *update_time_value; +static ui_connector_card_t s_connector_card[UI_MAX_CONNECTOR_NUM] = {0}; + +lv_obj_t * ui_page_create_connector_group(lv_obj_t *parent) +{ + if (UI_NUMOFCONNECTOR == 4) + { + return ioc_layout_mngr_load_layout("conn_card_quad", parent); + } + else if (UI_NUMOFCONNECTOR == 3) + { + return ioc_layout_mngr_load_layout("conn_card_trip", parent); + } + else if (UI_NUMOFCONNECTOR == 2) + { + return ioc_layout_mngr_load_layout("conn_card_dual", parent); + } + else if (UI_NUMOFCONNECTOR == 1) + { + ioc_ui_json_set_active_idx(0); // 单枪不需要home + } + + return NULL; +} + + +static void card_set_visual_state(ui_connector_card_t * connector_card) +{ + // DEBUG_WARN("card %d state %d active=%d", connector_card->idx, connector_card->current_visual_state, connector_card->card_actived); + + // 先清掉所有“视觉相关”的 state + for (int i = 0; i < CARD_VISUAL_NUM; i++) + { + lv_obj_remove_style(connector_card->card, connector_card->visual_style[i], LV_PART_MAIN); + } + + if (!connector_card->card_actived) + { + // DEBUG_WARN("card %d exit state %04X", connector_card->idx, connector_card->current_visual_state); + return; + } + + if (connector_card->current_visual_state < CARD_VISUAL_NUM) + { + lv_obj_add_style(connector_card->card, connector_card->visual_style[connector_card->current_visual_state], LV_PART_MAIN); + } + + // DEBUG_WARN("card %d set state %04X", connector_card->idx, connector_card->current_visual_state); +} + +// 点击卡片切换active idx +static void ui_connector_card_btn_event_cb(lv_event_t *e) +{ + // DEBUG_WARN("1111custom_tick_get[%ld]",custom_tick_get()); + lv_obj_t *obj = lv_event_get_target(e); + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + int idx = user_data->extra_data.data_int; + + if (s_connector_card[idx].card_actived) + { + s_connector_card[idx].card_actived = false; + card_set_visual_state(&s_connector_card[idx]); + + lv_timer_pause(s_connector_card[idx].cancel_active_gun_timer); + + ioc_ui_json_set_active_idx(-1); + } + else + { + for (int i = 0; i < UI_NUMOFCONNECTOR; i++) + { + if (i != idx) + { + s_connector_card[i].card_actived = false; + card_set_visual_state(&s_connector_card[i]); + + lv_timer_pause(s_connector_card[i].cancel_active_gun_timer); + } + } + + // DEBUG_WARN("2222custom_tick_get[%ld]",custom_tick_get()); + s_connector_card[idx].card_actived = true; + card_set_visual_state(&s_connector_card[idx]); + ioc_ui_json_set_active_idx(idx); + + lv_timer_reset(s_connector_card[idx].cancel_active_gun_timer); + lv_timer_resume(s_connector_card[idx].cancel_active_gun_timer); + + // 向homeOcpp发送激活的枪号 + ioc_send_ConnSelected(idx); + } +} + +static void update_time_value_cb(lv_timer_t * temp) +{ + + for ( int idx = 0; idx < CHARGER_GUN_TYPE_QUAD; idx++ ) + { + if ( s_connector_card[idx].text_state == NULL ) + { + return; + } + if ( strcmp(lv_label_get_text(s_connector_card[idx].text_state), lv_i18n_get_text("Finished")) == 0 ) + { + time_t current_time = time(NULL); + time_t diftimer = difftime(current_time, g_ui_json.connectors[idx].state_data.finished.stopTime); + + if (diftimer < 0) { + diftimer = 0; + } + + struct tm *tm = gmtime(&diftimer); + int show_hour = 0; + int show_min = 0; + int show_sec = 0; + + if (current_time >= g_ui_json.connectors[idx].state_data.finished.stopTime) { + show_hour = tm->tm_hour; + show_min = tm->tm_min; + show_sec = tm->tm_sec; + } + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", show_hour, show_min, show_sec); + ioc_label_set_text(s_connector_card[idx].text_time_value, buf); + } + else if ( strcmp(lv_label_get_text(s_connector_card[idx].text_state), lv_i18n_get_text("Reserved")) == 0 ) + { + time_t current_time = time(NULL); + time_t diftimer = difftime(g_ui_json.connectors[idx].state_data.reserved.reverseTime, current_time); + + if (diftimer < 0) { + diftimer = 0; + } + + struct tm *tm = gmtime(&diftimer); + int show_hour = 0; + int show_min = 0; + int show_sec = 0; + + if (current_time < g_ui_json.connectors[idx].state_data.reserved.reverseTime) { + show_hour = tm->tm_hour; + show_min = tm->tm_min; + show_sec = tm->tm_sec; + } + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", show_hour, show_min, show_sec); + ioc_label_set_text(s_connector_card[idx].text_time_value, buf); + } + } +} + +char * ui_connector_get_text_time_value(int idx) +{ + return lv_label_get_text(s_connector_card[idx].text_time_value); +} + +// 卡片本身需要根据不同的State来切换Style和显示隐藏部分控件 +static void ui_connector_card_update(struct ioc_obj_user_data_s * user_data) +{ + int idx = user_data->extra_data.data_int; + if (idx > UI_NUMOFCONNECTOR) + { + return; + } + + // 判断是否显示插枪图标 + if ( s_connector_card[idx].plug_gun_icon != NULL ) + { + if(strcmp(g_ui_json.connectors[idx].connStatus, "Unplug") != 0) + { + if ( UI_CONNECTOR_STATE(idx) == UI_CONNECTOR_STATE_CHARGING ) + { + lv_obj_add_flag(s_connector_card[idx].plug_gun_icon, LV_OBJ_FLAG_HIDDEN); + } + else + { + lv_obj_clear_flag(s_connector_card[idx].plug_gun_icon, LV_OBJ_FLAG_HIDDEN); + } + } + else + { + lv_obj_add_flag(s_connector_card[idx].plug_gun_icon, LV_OBJ_FLAG_HIDDEN); + } + } + + // 更新状态 + s_connector_card[idx].state = UI_CONNECTOR_STATE(idx); + + // 切换激活状态 + bool need_update_style = false; + // DEBUG_WARN("idx %d, card_actived %d", idx, s_connector_card[idx].card_actived); + if (idx == UI_CONNECTOR_ACTIVE_IDX) + { + if (!s_connector_card[idx].card_actived) + { + s_connector_card[idx].card_actived = true; + // DEBUG_WARN("idx %d, card_actived", idx); + + need_update_style = true; + + lv_timer_reset(s_connector_card[idx].cancel_active_gun_timer); + lv_timer_resume(s_connector_card[idx].cancel_active_gun_timer); + } + } + else + { + if (s_connector_card[idx].card_actived) + { + s_connector_card[idx].card_actived = false; + // DEBUG_WARN("idx %d, card_deactived", idx); + + need_update_style = true; + + lv_timer_pause(s_connector_card[idx].cancel_active_gun_timer); + } + } + + // 切换Style + card_visual_state_t visual_state; + switch (UI_CONNECTOR_STATE(idx)) + { + case UI_CONNECTOR_STATE_CONNECTING: + case UI_CONNECTOR_STATE_STARTING1: + case UI_CONNECTOR_STATE_STARTING2: + case UI_CONNECTOR_STATE_CHARGING: + case UI_CONNECTOR_STATE_FINISHED: + case UI_CONNECTOR_STATE_WAIT_IN_LINE: + case UI_CONNECTOR_STATE_STOPPING: + case UI_CONNECTOR_STATE_PROCESSING: + visual_state = CARD_VISUAL_CHARGING; + break; + + case UI_CONNECTOR_STATE_RESERVED: + visual_state = CARD_VISUAL_RESERVED; + break; + + case UI_CONNECTOR_STATE_SESSION_ERROR: + case UI_CONNECTOR_STATE_START_ERROR: + case UI_CONNECTOR_STATE_FAULT: + visual_state = CARD_VISUAL_FAULT; + break; + + case UI_CONNECTOR_STATE_UNAVAILABLE: + visual_state = CARD_VISUAL_UNAVAILABLE; + break; + + case UI_CONNECTOR_STATE_SUSPEND: + visual_state = CARD_VISUAL_SUSPEND; + break; + + case UI_CONNECTOR_STATE_HOME: + case UI_CONNECTOR_STATE_IDLE: + default: + visual_state = CARD_VISUAL_IDLE; + break; + } + if (visual_state != s_connector_card[idx].current_visual_state) + { + s_connector_card[idx].current_visual_state = visual_state; + need_update_style = true; + lv_obj_set_style_bg_color(s_connector_card[idx].no, s_connector_card[idx].style_color[visual_state] , 0); + lv_obj_set_style_text_color(s_connector_card[idx].text_state, s_connector_card[idx].style_color[visual_state],0); + } + + if (need_update_style) + { + card_set_visual_state(&s_connector_card[idx]); + } + + + // if (UI_CONNECTOR_STATE(idx) == s_connector_card[idx].state) + // { + // return; + // } + + // 切换部分控件的显示状态 + if (UI_CONNECTOR_STATE(idx) == UI_CONNECTOR_STATE_CHARGING) + { + lv_obj_add_flag(s_connector_card[idx].text_type, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(s_connector_card[idx].text_power_rated, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(s_connector_card[idx].type_icon, LV_OBJ_FLAG_HIDDEN); + + lv_obj_add_flag(s_connector_card[idx].text_time_label, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(s_connector_card[idx].text_time_value, LV_OBJ_FLAG_HIDDEN); + + lv_obj_clear_flag(s_connector_card[idx].bar_soc, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(s_connector_card[idx].text_soc, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(s_connector_card[idx].text_power_real, LV_OBJ_FLAG_HIDDEN); + } + else if ((UI_CONNECTOR_STATE(idx) == UI_CONNECTOR_STATE_FINISHED) || (UI_CONNECTOR_STATE(idx) == UI_CONNECTOR_STATE_RESERVED)) + { + lv_obj_add_flag(s_connector_card[idx].text_type, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(s_connector_card[idx].text_power_rated, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(s_connector_card[idx].type_icon, LV_OBJ_FLAG_HIDDEN); + + lv_obj_clear_flag(s_connector_card[idx].text_time_label, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(s_connector_card[idx].text_time_value, LV_OBJ_FLAG_HIDDEN); + + lv_obj_add_flag(s_connector_card[idx].bar_soc, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(s_connector_card[idx].text_soc, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(s_connector_card[idx].text_power_real, LV_OBJ_FLAG_HIDDEN); + + if (UI_CONNECTOR_STATE(idx) == UI_CONNECTOR_STATE_FINISHED) + { + ioc_label_set_text(s_connector_card[idx].text_time_label, "Idle time"); + } + else { + ioc_label_set_text(s_connector_card[idx].text_time_label, "left"); + } + } + else + { + lv_obj_clear_flag(s_connector_card[idx].text_type, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(s_connector_card[idx].text_power_rated, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(s_connector_card[idx].type_icon, LV_OBJ_FLAG_HIDDEN); + + lv_obj_add_flag(s_connector_card[idx].text_time_label, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(s_connector_card[idx].text_time_value, LV_OBJ_FLAG_HIDDEN); + + lv_obj_add_flag(s_connector_card[idx].bar_soc, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(s_connector_card[idx].text_soc, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(s_connector_card[idx].text_power_real, LV_OBJ_FLAG_HIDDEN); + } +} + +// 当前状态, 需要根据State来改变值 +static void ui_connector_card_update_state(struct ioc_obj_user_data_s * user_data) +{ + int idx = user_data->extra_data.data_int; + if (idx > UI_NUMOFCONNECTOR) + { + return; + } + ioc_label_set_text(s_connector_card[idx].text_state, UI_CONNECTOR_STATE_NAME(idx)); +} + +static void ui_connector_card_update_time_value(struct ioc_obj_user_data_s * user_data) +{ + int idx = user_data->extra_data.data_int; + if (idx > UI_NUMOFCONNECTOR) + { + return; + } + + if (UI_CONNECTOR_STATE(idx) == UI_CONNECTOR_STATE_FINISHED) + { + ioc_label_set_text(s_connector_card[idx].text_time_value, "04:24"); + } + else + { + ioc_label_set_text(s_connector_card[idx].text_time_value, "12:34:24"); + } + +} + +static void ui_connector_card_update_soc_bar(struct ioc_obj_user_data_s * user_data) +{ + int idx = user_data->extra_data.data_int; + lv_bar_set_value(s_connector_card[idx].bar_soc, g_ui_json.connectors[idx].state_data.charging.soc, LV_ANIM_OFF); + char soc[10]; + snprintf(soc, sizeof(soc), "%d%%", g_ui_json.connectors[idx].state_data.charging.soc); + ioc_label_set_text(s_connector_card[idx].text_soc, soc); +} + +static void ui_connector_card_update_time_label(struct ioc_obj_user_data_s * user_data) +{ + int idx = user_data->extra_data.data_int; + if (idx > UI_NUMOFCONNECTOR) + { + return; + } + if (UI_CONNECTOR_STATE(idx) == UI_CONNECTOR_STATE_FINISHED) + { + ioc_label_set_text(s_connector_card[idx].text_time_label, "Idle_time"); + } + else if ( UI_CONNECTOR_STATE(idx) == UI_CONNECTOR_STATE_RESERVED ) { + ioc_label_set_text(s_connector_card[idx].text_time_label, "left"); + } +} + +// 定时回调:选中枪显示对应页面后,一定时间无操作后返回home页面 +static void active_timer_cb(lv_timer_t * t) +{ + ui_connector_card_t *connector_card = (ui_connector_card_t *)lv_timer_get_user_data(t); + if (connector_card == NULL) + { + return; + } + + // DEBUG_WARN("active_timer_cb, idx %d card_actived %d", connector_card->idx, connector_card->card_actived); + lv_timer_pause(connector_card->cancel_active_gun_timer); + + if (connector_card->card_actived) + { + connector_card->card_actived = false; + card_set_visual_state(connector_card); + + UI_CONNECTOR_ACTIVE_IDX = -1; + LV_LOG_USER("active_idx -> -1"); + ioc_ui_overtime_changed_page(); + } +} + +static void ui_connector_card_register_obj(int idx, const char * name_after_prefix, int name_after_prefix_len, lv_obj_t *obj) +{ + if (idx > UI_NUMOFCONNECTOR) + { + return; + } + + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->extra_data.data_int = idx; // 先记录枪号, 便于后续使用 + + // 需要记录各对象, 用于后续更新 + ui_connector_card_t * connector_card = &s_connector_card[idx]; + connector_card->idx = idx; + if ( update_time_value == NULL ) + { + update_time_value = lv_timer_create(update_time_value_cb, 500, NULL); + } + if (name_after_prefix == NULL) + { + connector_card->card = obj; + lv_obj_add_event_cb(obj, ui_connector_card_btn_event_cb, LV_EVENT_CLICKED, NULL); // 按钮用于切换枪 + user_data->ui_json_update_cb = ui_connector_card_update; // 卡片本身, 需要按照不同的State来切换Style + + lv_style_t * style_find = NULL; + + connector_card->visual_style[CARD_VISUAL_IDLE] = ioc_style_mngr_get_style("style-connector-dual-checked"); + connector_card->style_color[CARD_VISUAL_IDLE] = ioc_theme_getcolor("state_idle_success"); + connector_card->visual_style[CARD_VISUAL_CHARGING] = ioc_style_mngr_get_style("style-connector-dual-checked-charging"); + connector_card->style_color[CARD_VISUAL_CHARGING] = ioc_theme_getcolor("state_charging"); + connector_card->visual_style[CARD_VISUAL_FAULT] = ioc_style_mngr_get_style("style-connector-dual-checked-state_fault"); + connector_card->style_color[CARD_VISUAL_FAULT] = ioc_theme_getcolor("state_fault"); + connector_card->visual_style[CARD_VISUAL_RESERVED] = ioc_style_mngr_get_style("style-connector-dual-checked-state_reserve"); + connector_card->style_color[CARD_VISUAL_RESERVED] = ioc_theme_getcolor("state_reserve"); + connector_card->visual_style[CARD_VISUAL_UNAVAILABLE] = ioc_style_mngr_get_style("style-connector-dual-checked-state_unavaliable"); + connector_card->style_color[CARD_VISUAL_UNAVAILABLE] = ioc_theme_getcolor("state_unavaliable"); + connector_card->visual_style[CARD_VISUAL_SUSPEND] = ioc_style_mngr_get_style("style-connector-dual-checked-state_warn_suspend"); + connector_card->style_color[CARD_VISUAL_SUSPEND] = ioc_theme_getcolor("state_warn_suspend"); + connector_card->current_visual_state = CARD_VISUAL_IDLE; + connector_card->card_actived = false; + + connector_card->cancel_active_gun_timer = lv_timer_create(active_timer_cb, CANCEL_ACTIVE_GUN_TIMER_COUNT * 1000, connector_card); + lv_timer_pause(connector_card->cancel_active_gun_timer); + + connector_card->state = UI_CONNECTOR_STATE_MAX; // 强制触发第一次更新 + return; + } + else if (IOC_OBJ_NAME_MATCH_AFTER_PREFIX(UI_NAME_CONNECTOR_CARD_STATE, name_after_prefix, name_after_prefix_len)) + { + connector_card->text_state = obj; + user_data->ui_json_update_cb = ui_connector_card_update_state; // 当前状态, 需要根据State来改变值 + return; + } + else if (IOC_OBJ_NAME_MATCH_AFTER_PREFIX(UI_NAME_CONNECTOR_CARD_NO, name_after_prefix, name_after_prefix_len)) + { + connector_card->no = obj; // 枪编号, 一次性, 不需要改变 + return; + } + else if (IOC_OBJ_NAME_MATCH_AFTER_PREFIX(UI_NAME_CONNECTOR_CARD_NO_TEXT, name_after_prefix, name_after_prefix_len)) + { + connector_card->text_no = obj; + + char no[10]; + sprintf(no, "%d", idx + 1); + ioc_label_set_text(connector_card->text_no, no); // 枪编号文本, 一次性, 不需要改变 + return; + } + else if (IOC_OBJ_NAME_MATCH_AFTER_PREFIX(UI_NAME_CONNECTOR_CARD_TYPE, name_after_prefix, name_after_prefix_len)) + { + connector_card->text_type = obj; + ioc_label_set_text(connector_card->text_type, UI_CONNECTOR_CONN_TYPE_NAME(idx)); // 枪类型, 一次性, 不需要改变 + return; + } + else if (IOC_OBJ_NAME_MATCH_AFTER_PREFIX(UI_NAME_CONNECTOR_CARD_POWER, name_after_prefix, name_after_prefix_len)) + { + connector_card->text_power_rated = obj; + + char power[40]; + snprintf(power, 20, "%.1fkW", (double)UI_CONNECTOR_RATED_POWER(idx) / 10.0); + ioc_label_set_text(connector_card->text_power_rated, power); // 枪额定功率, 一次性, 不需要改变 + return; + } + else if (IOC_OBJ_NAME_MATCH_AFTER_PREFIX(UI_NAME_CONNECTOR_CARD_TYPE_ICON, name_after_prefix, name_after_prefix_len)) + { + connector_card->type_icon = obj; + lv_img_set_src(connector_card->type_icon, ui_conn_type_img(UI_CONNECTOR_CONN_TYPE(idx))); // 枪类型图标, 一次性, 不需要改变 + return; + } + else if (IOC_OBJ_NAME_MATCH_AFTER_PREFIX(UI_NAME_CONNECTOR_CARD_PLUG_GUN_ICON, name_after_prefix, name_after_prefix_len)) + { + connector_card->plug_gun_icon = obj; + lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); + return; + } + else if (IOC_OBJ_NAME_MATCH_AFTER_PREFIX(UI_NAME_CONNECTOR_CARD_TIME_LABEL, name_after_prefix, name_after_prefix_len)) + { + connector_card->text_time_label = obj; + user_data->ui_json_update_cb = ui_connector_card_update_time_label; // 当前状态, 需要根据State来改变值 + return; + } + else if (IOC_OBJ_NAME_MATCH_AFTER_PREFIX(UI_NAME_CONNECTOR_CARD_TIME, name_after_prefix, name_after_prefix_len)) + { + connector_card->text_time_value = obj; + // user_data->ui_json_update_cb = ui_connector_card_update_time_value; + return; + } + else if (IOC_OBJ_NAME_MATCH_AFTER_PREFIX(UI_NAME_CONNECTOR_CARD_SOC_BAR, name_after_prefix, name_after_prefix_len)) + { + connector_card->bar_soc = obj; + + lv_bar_set_range(connector_card->bar_soc, 0, 100); + // lv_bar_set_value(card->bar_soc, 10, LV_ANIM_OFF); + user_data->ui_json_update_cb = ui_connector_card_update_soc_bar; + return; + } + else if (IOC_OBJ_NAME_MATCH_AFTER_PREFIX(UI_NAME_CONNECTOR_CARD_SOC_LABEL, name_after_prefix, name_after_prefix_len)) + { + connector_card->text_soc = obj; + // user_data->ui_json_update_cb = ui_connector_card_update_soc_label; + return; + } + else if (IOC_OBJ_NAME_MATCH_AFTER_PREFIX(UI_NAME_CONNECTOR_CARD_POWER_REAL, name_after_prefix, name_after_prefix_len)) + { + connector_card->text_power_real = obj; + // user_data->ui_json_update_cb = ui_connector_card_update_power_real; + return; + } + + return; +} + +void ui_after_create_connector_card(const char *name, lv_obj_t *obj) +{ + int id; + const char * name_after_prefix; + int name_after_prefix_len; + + if (ioc_obj_name_match_prefix(name + , UI_NAME_CONNECTOR_CARD_DUAL_PREFIX, strlen(UI_NAME_CONNECTOR_CARD_DUAL_PREFIX) - 1 + , &id, &name_after_prefix, &name_after_prefix_len)) + { + ui_connector_card_register_obj(id-1, name_after_prefix, name_after_prefix_len, obj); + return; + } + // if (ioc_obj_name_match_prefix(name + // , UI_NAME_CONNECTOR_CARD_SINGLE_PREFIX, strlen(UI_NAME_CONNECTOR_CARD_SINGLE_PREFIX) - 1 + // , &id, &name_after_prefix, &name_after_prefix_len)) + // { + // ui_connector_card_register_obj(id-1, name_after_prefix, name_after_prefix_len, obj); + // return; + // } + if (ioc_obj_name_match_prefix(name + , UI_NAME_CONNECTOR_CARD_QUAD_PREFIX, strlen(UI_NAME_CONNECTOR_CARD_QUAD_PREFIX) - 1 + , &id, &name_after_prefix, &name_after_prefix_len)) + { + ui_connector_card_register_obj(id-1, name_after_prefix, name_after_prefix_len, obj); + return; + } + if (ioc_obj_name_match_prefix(name + , UI_NAME_CONNECTOR_CARD_TRIP_PREFIX, strlen(UI_NAME_CONNECTOR_CARD_TRIP_PREFIX) - 1 + , &id, &name_after_prefix, &name_after_prefix_len)) + { + ui_connector_card_register_obj(id-1, name_after_prefix, name_after_prefix_len, obj); + return; + } +} diff --git a/pages/ui_page_connector_group.h b/pages/ui_page_connector_group.h new file mode 100644 index 000000000..fce04fd97 --- /dev/null +++ b/pages/ui_page_connector_group.h @@ -0,0 +1,15 @@ +#ifndef __UI_PAGE_CONNECTOR_GROUP_H__ +#define __UI_PAGE_CONNECTOR_GROUP_H__ + +#include "lvgl.h" + +// 分别对应设置四种枪的对象(目前设计单枪不需要卡片) +// #define UI_NAME_CONNECTOR_CARD_SINGLE_PREFIX "main.connector_single.connector*" +#define UI_NAME_CONNECTOR_CARD_DUAL_PREFIX "main.conn_card_dual.connector*" +#define UI_NAME_CONNECTOR_CARD_TRIP_PREFIX "main.conn_card_trip.connector*" +#define UI_NAME_CONNECTOR_CARD_QUAD_PREFIX "main.conn_card_quad.connector*" +void ui_after_create_connector_card(const char * name, lv_obj_t * obj); + +lv_obj_t * ui_page_create_connector_group(lv_obj_t *parent); +char * ui_connector_get_text_time_value(int idx); +#endif diff --git a/pages/ui_page_main.c b/pages/ui_page_main.c new file mode 100644 index 000000000..8d7a26a18 --- /dev/null +++ b/pages/ui_page_main.c @@ -0,0 +1,153 @@ +#include "../pages_mngr.h" + +static lv_obj_t * s_ui_main = NULL; +static lv_obj_t * s_ui_status_bar = NULL; +static lv_obj_t * s_ui_mid_container_top = NULL; +static lv_obj_t * s_ui_connector_group = NULL; + +static lv_obj_t * s_ui_state_pages[UI_PAGE_MAX]; + +typedef lv_obj_t * (*ui_page_create_func)(lv_obj_t *parent); +typedef void (*ui_page_show_func)(void); +typedef void (*ui_page_hide_func)(void); + +typedef struct { + ui_page_create_func create_func; + ui_page_show_func show_func; + ui_page_hide_func hide_func; +} ui_page_func_t; + +const ui_page_func_t c_ui_page_create_funcs[UI_PAGE_MAX] = { + {ui_page_create_01_home, NULL, NULL}, + {ui_page_create_02_idle, NULL, NULL}, + {ui_page_create_03_starting1, NULL, NULL}, + {ui_page_create_04_starting2, NULL, NULL}, + {ui_page_create_05_charging, ui_page_show_05_charging, ui_page_hide_05_charging}, + {ui_page_create_06_finished, ui_page_show_06_finished, ui_page_hide_06_finished}, + {ui_page_create_07_reserved, ui_page_show_07_reserved, ui_page_hide_07_reserved}, + {ui_page_create_08_session_error, NULL, NULL}, + {ui_page_create_09_start_error, NULL, NULL}, + {ui_page_create_10_fault, NULL, NULL}, + {ui_page_create_11_unavailable, NULL, NULL}, + {ui_page_create_12_connecting, NULL, NULL}, + {ui_page_create_14_stopping, NULL, NULL}, + {ui_page_create_15_wait_in_line, ui_page_show_15_wait_in_line, ui_page_hide_15_wait_in_line}, + {ui_page_create_16_suspend, NULL, NULL}, + {ui_page_create_17_processing, ui_page_show_17_processing, ui_page_hide_17_processing}, +}; + + +static void ui_page_main_show_state_page(ioc_ui_page_e page_idx) +{ + for (int i = 0; i < UI_PAGE_MAX; i++) + { + if (i == page_idx) + { + if (s_ui_state_pages[i] == NULL) + { + s_ui_state_pages[i] = c_ui_page_create_funcs[i].create_func(s_ui_main); + lv_obj_move_foreground(s_ui_mid_container_top); + } + if (s_ui_state_pages[i] != NULL) + { + lv_obj_clear_flag(s_ui_state_pages[i], LV_OBJ_FLAG_HIDDEN); + if (c_ui_page_create_funcs[i].show_func != NULL) + { + c_ui_page_create_funcs[i].show_func(); + } + ioc_app_ui_json_updated_widgets(s_ui_state_pages[i]); + } + if ( s_ui_mid_container_top != NULL ) { + if ( i == UI_PAGE_HOME ) { + lv_obj_add_flag(s_ui_mid_container_top, LV_OBJ_FLAG_HIDDEN); + } + else { + lv_obj_clear_flag(s_ui_mid_container_top, LV_OBJ_FLAG_HIDDEN); + } + } + } + else + { + if (s_ui_state_pages[i] != NULL) + { + lv_obj_add_flag(s_ui_state_pages[i], LV_OBJ_FLAG_HIDDEN); + if (c_ui_page_create_funcs[i].hide_func != NULL) + { + c_ui_page_create_funcs[i].hide_func(); + } + } + } + } +} + +// 根据当前选中的枪的状态, 来切换状态组页面 +static void ui_page_main_updatejson(struct ioc_obj_user_data_s * user_data) +{ + // 未选中枪则显示HOME + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + ui_page_main_show_state_page(UI_PAGE_HOME); + return; + } + + // 否则按照选中枪的状态来显示 + ioc_ui_connector_state_t ui_state = UI_CONNECTOR_STATE(UI_CONNECTOR_ACTIVE_IDX); + switch (ui_state) + { + case UI_CONNECTOR_STATE_HOME: ui_page_main_show_state_page(UI_PAGE_HOME); break; + case UI_CONNECTOR_STATE_IDLE: ui_page_main_show_state_page(UI_PAGE_IDLE); break; + case UI_CONNECTOR_STATE_STARTING1: ui_page_main_show_state_page(UI_PAGE_STARTING1); break; + case UI_CONNECTOR_STATE_STARTING2: ui_page_main_show_state_page(UI_PAGE_STARTING2); break; + case UI_CONNECTOR_STATE_CHARGING: ui_page_main_show_state_page(UI_PAGE_CHARTGING); break; + case UI_CONNECTOR_STATE_FINISHED: ui_page_main_show_state_page(UI_PAGE_FINISHED); break; + case UI_CONNECTOR_STATE_RESERVED: ui_page_main_show_state_page(UI_PAGE_RESERVED); break; + case UI_CONNECTOR_STATE_SESSION_ERROR: ui_page_main_show_state_page(UI_PAGE_SESSION_ERROR); break; + case UI_CONNECTOR_STATE_START_ERROR: ui_page_main_show_state_page(UI_PAGE_START_ERROR); break; + case UI_CONNECTOR_STATE_FAULT: ui_page_main_show_state_page(UI_PAGE_FAULT); break; + case UI_CONNECTOR_STATE_UNAVAILABLE: ui_page_main_show_state_page(UI_PAGE_UNAVAILABLE); break; + case UI_CONNECTOR_STATE_CONNECTING: ui_page_main_show_state_page(UI_PAGE_CONNECTING); break; + case UI_CONNECTOR_STATE_STOPPING: ui_page_main_show_state_page(UI_PAGE_STOPPING); break; + case UI_CONNECTOR_STATE_WAIT_IN_LINE: ui_page_main_show_state_page(UI_PAGE_WAIT_IN_LINE); break; + case UI_CONNECTOR_STATE_SUSPEND: ui_page_main_show_state_page(UI_PAGE_SUSPEND); break; + case UI_CONNECTOR_STATE_PROCESSING: ui_page_main_show_state_page(UI_PAGE_PROCESSING); break; + + default: ui_page_main_show_state_page(UI_PAGE_HOME); break; + } + + return; + + +} + +lv_obj_t * ui_page_main_create(lv_obj_t *parent) +{ + if (s_ui_main != NULL) + { + lv_obj_del(s_ui_main); + s_ui_main = NULL; + } + + s_ui_main = ioc_layout_mngr_load_layout("main", parent); + if (s_ui_main == NULL) + { + return NULL; + } + + // 测试用 + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(s_ui_main); + user_data->ui_json_update_cb = ui_page_main_updatejson; + + // 创建状态栏 + s_ui_status_bar = ui_page_create_status_bar(s_ui_main); + + // 创建中间顶层容器(包含左上角枪号 枪状态 功率类型 等) + s_ui_mid_container_top = ui_page_create_mid_container_top(s_ui_main); + + // 创建枪组 + s_ui_connector_group = ui_page_create_connector_group(s_ui_main); + + // 创建状态组, 初始为空 等待第一次UI.json更新 + memset(s_ui_state_pages, 0x00, sizeof(s_ui_state_pages)); + + return s_ui_main; +} diff --git a/pages/ui_page_main.h b/pages/ui_page_main.h new file mode 100644 index 000000000..bdf567fdf --- /dev/null +++ b/pages/ui_page_main.h @@ -0,0 +1,29 @@ +#ifndef __UI_PAGE_MAIN_H__ +#define __UI_PAGE_MAIN_H__ + +#include "lvgl.h" + +typedef enum { + UI_PAGE_HOME = 0, + UI_PAGE_IDLE, + UI_PAGE_STARTING1, + UI_PAGE_STARTING2, + UI_PAGE_CHARTGING, + UI_PAGE_FINISHED, + UI_PAGE_RESERVED, + UI_PAGE_SESSION_ERROR, + UI_PAGE_START_ERROR, + UI_PAGE_FAULT, + UI_PAGE_UNAVAILABLE, + UI_PAGE_CONNECTING, + UI_PAGE_STOPPING, + UI_PAGE_WAIT_IN_LINE, + UI_PAGE_SUSPEND, + UI_PAGE_PROCESSING, + + UI_PAGE_MAX, +} ioc_ui_page_e; + +lv_obj_t * ui_page_main_create(lv_obj_t *parent); + +#endif diff --git a/pages/ui_page_mid_container_top.c b/pages/ui_page_mid_container_top.c new file mode 100644 index 000000000..55ca1cd66 --- /dev/null +++ b/pages/ui_page_mid_container_top.c @@ -0,0 +1,228 @@ +#include "../pages_mngr.h" + + +#define UI_NAME_MID_CONTAINER_TOP_TYPE_POWER ".conn_type_power" +#define UI_NAME_MID_CONTAINER_TOP_STATUS ".conn_state" +#define UI_NAME_MID_CONTAINER_TOP_CONNID_NO ".station_id" +#define UI_NAME_MID_CONTAINER_TOP_NO ".conn_id" +#define UI_NAME_MID_CONTAINER_TOP_NO_TEXT ".conn_id.conn_id_text" +#define UI_NAME_MID_CONTAINER_TOP_NO_TYPE_ICON ".conn_id.conn_type_icon" + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * type_power; + lv_obj_t * no; + lv_obj_t * no_text; + lv_obj_t * no_type_icon; + lv_obj_t * status; + lv_obj_t * connid_no; + +} ui_page_mid_container_top_t; + +static ui_page_mid_container_top_t ui_page_mid_container_top = {NULL}; + +lv_obj_t * ui_page_create_mid_container_top(lv_obj_t *parent) +{ + return ioc_layout_mngr_load_layout("conn_top_info", parent); +} + +void ui_mid_container_top_update_type_power(struct ioc_obj_user_data_s * user_data) +{ + + float power_kw = UI_CONNECTOR_RATED_POWER(UI_CONNECTOR_ACTIVE_IDX) / 10.0f; + + char result[32] = {0}; + snprintf(result, sizeof(result), "%s-%.1fkW", UI_CONNECTOR_CONN_TYPE_NAME(UI_CONNECTOR_ACTIVE_IDX), power_kw); + + ioc_label_set_text(ui_page_mid_container_top.type_power, result); +} + +void ui_mid_container_top_update_status(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_mid_container_top.status,UI_CONNECTOR_STATE_NAME(UI_CONNECTOR_ACTIVE_IDX)); + + lv_style_t * style = NULL; + switch (UI_CONNECTOR_STATE(UI_CONNECTOR_ACTIVE_IDX)) + { + case UI_CONNECTOR_STATE_CONNECTING: + case UI_CONNECTOR_STATE_STARTING1: + case UI_CONNECTOR_STATE_STARTING2: + case UI_CONNECTOR_STATE_CHARGING: + case UI_CONNECTOR_STATE_FINISHED: + case UI_CONNECTOR_STATE_WAIT_IN_LINE: + case UI_CONNECTOR_STATE_STOPPING: + case UI_CONNECTOR_STATE_PROCESSING: + style = ioc_style_mngr_get_style("style-starting1-status"); + break; + + case UI_CONNECTOR_STATE_RESERVED: + style = ioc_style_mngr_get_style("style-reserved-status"); + break; + + case UI_CONNECTOR_STATE_SESSION_ERROR: + case UI_CONNECTOR_STATE_START_ERROR: + case UI_CONNECTOR_STATE_FAULT: + style = ioc_style_mngr_get_style("style-session_error-status"); + break; + + case UI_CONNECTOR_STATE_UNAVAILABLE: + style = ioc_style_mngr_get_style("style-unavaliable-status"); + break; + + case UI_CONNECTOR_STATE_SUSPEND: + style = ioc_style_mngr_get_style("style-suspend-status"); + break; + + case UI_CONNECTOR_STATE_HOME: + case UI_CONNECTOR_STATE_IDLE: + default: + style = ioc_style_mngr_get_style("style-idle-status"); + break; + } + lv_obj_remove_style(ui_page_mid_container_top.status, style, 0); + lv_obj_add_style(ui_page_mid_container_top.status, style, LV_STATE_DEFAULT); +}void ui_mid_container_top_update_connid_no(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_mid_container_top.connid_no, g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].connCode); +} + +void ui_mid_container_top_update_no(struct ioc_obj_user_data_s * user_data) +{ + lv_color_t bg_color; + switch (UI_CONNECTOR_STATE(UI_CONNECTOR_ACTIVE_IDX)) + { + case UI_CONNECTOR_STATE_CONNECTING: + case UI_CONNECTOR_STATE_STARTING1: + case UI_CONNECTOR_STATE_STARTING2: + case UI_CONNECTOR_STATE_CHARGING: + case UI_CONNECTOR_STATE_FINISHED: + case UI_CONNECTOR_STATE_WAIT_IN_LINE: + case UI_CONNECTOR_STATE_STOPPING: + case UI_CONNECTOR_STATE_PROCESSING: + bg_color = ioc_theme_getcolor("state_charging"); + break; + + case UI_CONNECTOR_STATE_RESERVED: + bg_color = ioc_theme_getcolor("state_reserve"); + break; + + case UI_CONNECTOR_STATE_SESSION_ERROR: + case UI_CONNECTOR_STATE_START_ERROR: + case UI_CONNECTOR_STATE_FAULT: + bg_color = ioc_theme_getcolor("state_fault"); + break; + + case UI_CONNECTOR_STATE_UNAVAILABLE: + bg_color = ioc_theme_getcolor("state_unavaliable"); + break; + + case UI_CONNECTOR_STATE_SUSPEND: + bg_color = ioc_theme_getcolor("state_warn_suspend"); + break; + + case UI_CONNECTOR_STATE_HOME: + case UI_CONNECTOR_STATE_IDLE: + default: + bg_color = ioc_theme_getcolor("state_idle_success"); + break; + } + lv_obj_set_style_bg_color(ui_page_mid_container_top.no, bg_color, LV_STATE_DEFAULT); +} + +void ui_mid_container_top_update_no_text(struct ioc_obj_user_data_s * user_data) +{ + char str[5]; + sprintf(str, "%d", UI_CONNECTOR_ACTIVE_IDX+1); + ioc_label_set_text(ui_page_mid_container_top.no_text, str); +} + +void ui_mid_container_top_update_no_type_icon(struct ioc_obj_user_data_s * user_data) +{ + lv_img_set_src(ui_page_mid_container_top.no_type_icon, ui_conn_type_img(UI_CONNECTOR_CONN_TYPE(UI_CONNECTOR_ACTIVE_IDX))); +} + + +void ui_after_create_mid_container_top_type_power(const char * name, lv_obj_t * obj) +{ + ui_page_mid_container_top.type_power = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_mid_container_top_update_type_power; +} + +void ui_after_create_mid_container_top_status(const char * name, lv_obj_t * obj) +{ + ui_page_mid_container_top.status = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_mid_container_top_update_status; +} +void ui_after_create_mid_container_top_connid_no(const char * name, lv_obj_t * obj) +{ + ui_page_mid_container_top.connid_no = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_mid_container_top_update_connid_no; +} + +void ui_after_create_mid_container_top_no(const char * name, lv_obj_t * obj) +{ + ui_page_mid_container_top.no = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_mid_container_top_update_no; +} + +void ui_after_create_mid_container_top_no_text(const char * name, lv_obj_t * obj) +{ + ui_page_mid_container_top.no_text = obj; + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) { + lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); + } + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_mid_container_top_update_no_text; +} + +void ui_after_create_mid_container_top_no_type_icon(const char * name, lv_obj_t * obj) +{ + ui_page_mid_container_top.no_type_icon = obj; + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) { + lv_obj_clear_flag(obj, LV_OBJ_FLAG_HIDDEN); + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_mid_container_top_update_no_type_icon; + } +} + +void ui_after_create_state_mid_container_top(const char * name, lv_obj_t * obj) +{ + const char * mid_container_top_name = name + strlen(UI_NAME_STATE_MID_CONTAINER_TOP); + if (strcmp(mid_container_top_name, UI_NAME_MID_CONTAINER_TOP_TYPE_POWER) == 0) + { + ui_after_create_mid_container_top_type_power(name, obj); + return; + } + else if (strcmp(mid_container_top_name, UI_NAME_MID_CONTAINER_TOP_STATUS) == 0) + { + ui_after_create_mid_container_top_status(name, obj); + return; + } + else if (strcmp(mid_container_top_name, UI_NAME_MID_CONTAINER_TOP_CONNID_NO) == 0) + { + ui_after_create_mid_container_top_connid_no(name, obj); + return; + } + else if (strcmp(mid_container_top_name, UI_NAME_MID_CONTAINER_TOP_NO) == 0) + { + ui_after_create_mid_container_top_no(name, obj); + return; + } + else if (strcmp(mid_container_top_name, UI_NAME_MID_CONTAINER_TOP_NO_TEXT) == 0) + { + ui_after_create_mid_container_top_no_text(name, obj); + return; + } + else if (strcmp(mid_container_top_name, UI_NAME_MID_CONTAINER_TOP_NO_TYPE_ICON) == 0) + { + ui_after_create_mid_container_top_no_type_icon(name, obj); + return; + } + +} diff --git a/pages/ui_page_mid_container_top.h b/pages/ui_page_mid_container_top.h new file mode 100644 index 000000000..73d7f69bb --- /dev/null +++ b/pages/ui_page_mid_container_top.h @@ -0,0 +1,11 @@ +#ifndef __UI_PAGE_MID_CONTAINER_TOP_H__ +#define __UI_PAGE_MID_CONTAINER_TOP_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_mid_container_top(lv_obj_t *parent); + +#define UI_NAME_STATE_MID_CONTAINER_TOP "main.conn_top_info" +void ui_after_create_state_mid_container_top(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_page_status_bar.c b/pages/ui_page_status_bar.c new file mode 100644 index 000000000..0a69ca564 --- /dev/null +++ b/pages/ui_page_status_bar.c @@ -0,0 +1,118 @@ +#include "../pages_mngr.h" + +#define UI_NAME_STATUS_BAR_TIME ".time" +#define UI_NAME_STATUS_BAR_HELP ".help" +#define UI_NAME_STATUS_BAR_HELP_TEXT ".help.text" +#define UI_NAME_STATUS_BAR_LANGUAGE ".language" +#define UI_NAME_STATUS_BAR_LANGUAGE_ICON ".language.icon" +#define UI_NAME_STATUS_BAR_LANGUAGE_LABEL ".language.label" + + + +ui_status_bar_t ui_status_bar; + +lv_obj_t * ui_page_create_status_bar(lv_obj_t *parent) +{ + return ioc_layout_mngr_load_layout("status_bar", parent); +} + +static void ui_status_bar_help_btn_event_cb(lv_event_t *e) +{ + ui_popup_show_help(); // 点击弹出帮助页面, 关闭由help自己控制 +} +void ui_after_create_status_bar_help(const char * name, lv_obj_t * obj) +{ + ui_status_bar.help_btn = obj; + lv_obj_add_event_cb(obj, ui_status_bar_help_btn_event_cb, LV_EVENT_CLICKED, NULL); +} + + +void ui_status_bar_update_help_text(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_status_bar.help_text, "Help"); +} + +void ui_status_bar_update_time(struct ioc_obj_user_data_s * user_data) +{ + uint8_t tz_val = g_ui_json.timeZone; + time_t UTC = time(NULL); + time_t shift_UTC = UTC + ((tz_val - 48) * 15 * 60); + + struct tm* tp = gmtime(&shift_UTC); + + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%02d : %02d", tp->tm_hour, tp->tm_min); + ioc_label_set_text(ui_status_bar.time, buf); + +} + +void ui_after_create_status_bar_help_text(const char * name, lv_obj_t * obj) +{ + ui_status_bar.help_text = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_status_bar_update_help_text; +} + +static void ui_status_bar_language_btn_event_cb(lv_event_t *e) +{ + ui_popup_show_language(); // 点击弹出语言选择页面, 关闭由language自己控制 +} +void ui_after_create_status_bar_language(const char * name, lv_obj_t * obj) +{ + ui_status_bar.lang_btn = obj; + lv_obj_add_event_cb(obj, ui_status_bar_language_btn_event_cb, LV_EVENT_CLICKED, NULL); +} + +void ui_after_create_status_bar_language_icon(const char * name, lv_obj_t * obj) +{ + ui_status_bar.lang_icon = obj; +} + +void ui_after_create_status_bar_language_label(const char * name, lv_obj_t * obj) +{ + ui_status_bar.lang_label = obj; +} + +void ui_after_create_status_bar_time(const char * name, lv_obj_t * obj) +{ + ui_status_bar.time = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_status_bar_update_time; +} + + + +void ui_after_create_status_bar(const char * name, lv_obj_t * obj) +{ + const char * status_bar_name = name + strlen(UI_NAME_STATUS_BAR); + if (strcmp(status_bar_name, UI_NAME_STATUS_BAR_HELP) == 0) + { + ui_after_create_status_bar_help(name, obj); + return; + } + else if (strcmp(status_bar_name, UI_NAME_STATUS_BAR_HELP_TEXT) == 0) + { + ui_after_create_status_bar_help_text(name, obj); + return; + } + else if (strcmp(status_bar_name, UI_NAME_STATUS_BAR_LANGUAGE) == 0) + { + ui_after_create_status_bar_language(name, obj); + return; + } + else if (strcmp(status_bar_name, UI_NAME_STATUS_BAR_LANGUAGE_ICON) == 0) + { + ui_after_create_status_bar_language_icon(name, obj); + return; + } + else if (strcmp(status_bar_name, UI_NAME_STATUS_BAR_LANGUAGE_LABEL) == 0) + { + ui_after_create_status_bar_language_label(name, obj); + return; + } + else if (strcmp(status_bar_name, UI_NAME_STATUS_BAR_TIME) == 0) + { + ui_after_create_status_bar_time(name, obj); + return; + } +} diff --git a/pages/ui_page_status_bar.h b/pages/ui_page_status_bar.h new file mode 100644 index 000000000..c07f83e91 --- /dev/null +++ b/pages/ui_page_status_bar.h @@ -0,0 +1,23 @@ +#ifndef __UI_PAGE_STATUS_BAR_H__ +#define __UI_PAGE_STATUS_BRA_H__ + +#include "lvgl.h" + +typedef struct +{ + lv_obj_t *help_btn; + lv_obj_t *help_text; + lv_obj_t *lang_btn; + lv_obj_t *lang_icon; + lv_obj_t *lang_label; + lv_obj_t *time; + +} ui_status_bar_t; + +#define UI_NAME_STATUS_BAR "main.status_bar" +void ui_after_create_status_bar(const char * name, lv_obj_t * obj); + +lv_obj_t * ui_page_create_status_bar(lv_obj_t *parent); +extern ui_status_bar_t ui_status_bar; + +#endif diff --git a/pages/ui_popup_bill.c b/pages/ui_popup_bill.c new file mode 100644 index 000000000..1e3b430f2 --- /dev/null +++ b/pages/ui_popup_bill.c @@ -0,0 +1,216 @@ +#include "../pages_mngr.h" + +#define UI_NAME_BILL_QR_CODE_BILL ".bill_qr_code_bill" +#define UI_NAME_BILL_QR_CODE_RECEIPT ".bill_qr_code_receipt" +#define UI_NAME_BILL_CONTENT ".bill_content.content" + +#define UI_NAME_BILL_SCAN_FOR_BILL ".bill_scan_for_bill_title" +#define UI_NAME_BILL_SCAN_FOR_RECEIPT ".bill_qr_code_receipt" +#define UI_NAME_BILL_CLOSE_TEXT ".bill_close_button.text" +#define UI_NAME_BILL_CLOSE_BTN ".bill_close_button" +#define UI_NAME_BILL_CLOSE_SECONDS ".bill_close_button.seconds" + +#define BILL_CLOSE_TIMER_COUNT 60 +typedef struct { + + lv_obj_t * obj; + + lv_obj_t * bill_content; + lv_obj_t * qr_code_bill; + lv_obj_t * qr_code_receipt; + lv_obj_t * scan_for_bill; + lv_obj_t * scan_for_receipt; + lv_obj_t * close_text; + lv_obj_t * close_btn; + lv_obj_t * close_seconds; + + lv_timer_t * close_timer; + uint16_t close_time_counter; +}bill_page_t; + +bill_page_t bill_page; + +static void ui_bill_clear(void) +{ + memset(g_ui_json.trigger.billUrlStr, 0x00, sizeof(g_ui_json.trigger.billUrlStr)); + memset(g_ui_json.trigger.receiptUrlStr, 0x00, sizeof(g_ui_json.trigger.receiptUrlStr)); + memset(g_ui_json.trigger.content, 0x00, sizeof(g_ui_json.trigger.content)); +} + + +static void ui_bill_show_receipt(bool is_show) +{ + if(is_show) { + lv_obj_clear_flag(bill_page.scan_for_receipt, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(bill_page.qr_code_receipt, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_add_flag(bill_page.scan_for_receipt, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(bill_page.qr_code_receipt, LV_OBJ_FLAG_HIDDEN); + } +} + +// 显示某枪的账单弹出信息, 内容由ui_json提供 +void ui_popup_show_bill() { + + ui_popup_show_mask(true); // 显示遮罩层 + + if ( bill_page.obj == NULL ) { + bill_page.obj = ioc_layout_mngr_load_layout("bill", lv_layer_top()); + } + + if ( bill_page.obj != NULL ) { + lv_obj_clear_flag(bill_page.obj, LV_OBJ_FLAG_HIDDEN); + } + + ioc_label_set_text(bill_page.scan_for_bill, "Scan_for_bill"); + ioc_label_set_text(bill_page.scan_for_receipt, "Scan_for_receipt"); + ioc_label_set_text(bill_page.close_text, "Close"); + + bill_page.close_time_counter = g_ui_json.trigger.seconds; + + lv_qrcode_update(bill_page.qr_code_bill, g_ui_json.trigger.billUrlStr, strlen(g_ui_json.trigger.billUrlStr)); + + if(strlen(g_ui_json.trigger.receiptUrlStr) != 0) + { + lv_qrcode_update(bill_page.qr_code_receipt, g_ui_json.trigger.receiptUrlStr, strlen(g_ui_json.trigger.receiptUrlStr)); + } + + ioc_label_set_text(bill_page.bill_content, g_ui_json.trigger.content); + + // 打开定时器 + if (bill_page.close_timer != NULL) { + lv_timer_resume(bill_page.close_timer); + } +} + +void ui_popup_hide_bill() +{ + bill_page.close_time_counter = 0; +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_after_create_bill_scan_for_bill(const char * name, lv_obj_t * obj) +{ + bill_page.scan_for_bill = obj; +} + +void ui_after_create_bill_scan_for_receipt(const char * name, lv_obj_t * obj) +{ + bill_page.scan_for_receipt = obj; +} + +void ui_after_create_bill_close_text(const char * name, lv_obj_t * obj) +{ + bill_page.close_text = obj; +} + +static void bill_close_timer_cb(lv_timer_t * t) { + + if (bill_page.close_time_counter == 0) { + lv_obj_add_flag(bill_page.obj, LV_OBJ_FLAG_HIDDEN); + ui_popup_show_mask(false); + lv_timer_pause(bill_page.close_timer); + bill_page.close_time_counter = BILL_CLOSE_TIMER_COUNT; + ui_bill_clear(); + return; + } + + bill_page.close_time_counter--; + char buf[8]; + snprintf(buf, sizeof(buf), "(%ds)", bill_page.close_time_counter); + ioc_label_set_text(bill_page.close_seconds, buf); +} + + +static void bill_close_event_cb(lv_event_t *e) +{ + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + lv_obj_add_flag(bill_page.obj, LV_OBJ_FLAG_HIDDEN); + ui_popup_show_mask(false); + ui_bill_clear(); + } +} + +void ui_after_create_bill_close_btn(const char * name, lv_obj_t * obj) +{ + bill_page.close_btn = obj; + lv_obj_set_layout(obj, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW); + lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + lv_obj_set_style_pad_column(obj, 5, 0); + lv_obj_add_event_cb(obj, bill_close_event_cb, LV_EVENT_CLICKED, NULL); +} + +void ui_after_create_bill_close_seconds(const char * name, lv_obj_t * obj) +{ + bill_page.close_seconds = obj; +} + +void ui_after_create_bill_qr_code_bill(const char * name, lv_obj_t * obj) +{ + bill_page.qr_code_bill = obj; +} +void ui_after_create_bill_qr_code_receipt(const char * name, lv_obj_t * obj) +{ + bill_page.qr_code_receipt = obj; +} + +void ui_after_create_bill_content(const char * name, lv_obj_t * obj) +{ + bill_page.bill_content = obj; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +void ui_after_create_bill(const char * name, lv_obj_t * obj) +{ + const char * bill_name = name + strlen(UI_NAME_BILL); + if (strcmp(bill_name, UI_NAME_BILL_SCAN_FOR_BILL) == 0) + { + ui_after_create_bill_scan_for_bill(name, obj); + return; + } + else if (strcmp(bill_name, UI_NAME_BILL_SCAN_FOR_RECEIPT) == 0) + { + ui_after_create_bill_scan_for_receipt(name, obj); + return; + } + else if (strcmp(bill_name, UI_NAME_BILL_CLOSE_TEXT) == 0) + { + ui_after_create_bill_close_text(name, obj); + return; + } + else if (strcmp(bill_name, UI_NAME_BILL_CLOSE_BTN) == 0) + { + ui_after_create_bill_close_btn(name, obj); + return; + } + else if (strcmp(bill_name, UI_NAME_BILL_CLOSE_SECONDS) == 0) + { + ui_after_create_bill_close_seconds(name, obj); + return; + } + else if (strcmp(bill_name, UI_NAME_BILL_QR_CODE_BILL) == 0) + { + ui_after_create_bill_qr_code_bill(name, obj); + return; + } + else if (strcmp(bill_name, UI_NAME_BILL_QR_CODE_RECEIPT) == 0) + { + ui_after_create_bill_qr_code_receipt(name, obj); + return; + } + else if (strcmp(bill_name, UI_NAME_BILL_CONTENT) == 0) + { + ui_after_create_bill_content(name, obj); + return; + } + + if ( bill_page.close_timer == NULL ) + { + bill_page.close_time_counter = BILL_CLOSE_TIMER_COUNT; + bill_page.close_timer = lv_timer_create(bill_close_timer_cb, 1000, NULL); + lv_timer_pause(bill_page.close_timer); + } +} diff --git a/pages/ui_popup_bill.h b/pages/ui_popup_bill.h new file mode 100644 index 000000000..76666b5d7 --- /dev/null +++ b/pages/ui_popup_bill.h @@ -0,0 +1,15 @@ +#ifndef __UI_POPUP_BILL_H__ +#define __UI_POPUP_BILL_H__ + +#include "lvgl.h" + +#define UI_NAME_BILL "bill" + +// 显示某枪的账单弹出信息, 内容由ui_json提供 +void ui_popup_show_bill(); + +void ui_popup_hide_bill(); + +void ui_after_create_bill(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_popup_charging_detail.c b/pages/ui_popup_charging_detail.c new file mode 100644 index 000000000..419828227 --- /dev/null +++ b/pages/ui_popup_charging_detail.c @@ -0,0 +1,294 @@ +#include "../pages_mngr.h" + +#define UI_NAME_DETAIL_CLOSE_BTN ".close_button" + +#define UI_NAME_DETAIL_CLOSE_TEXT ".close_button.text" +#define UI_NAME_DETAIL_DETAIL_DATA ".detailed_data" + +#define UI_NAME_DETAIL_RUN_STATE ".card_left.run_state" +#define UI_NAME_DETAIL_SUB_STATE ".card_left.sub_state" +#define UI_NAME_DETAIL_ERROR_CODE ".card_left.error_code" +#define UI_NAME_DETAIL_CONN_STATUS ".card_left.conn_status" +#define UI_NAME_DETAIL_START_SOC ".card_left.start_soc" +#define UI_NAME_DETAIL_REQUEST_VOLTAGE ".card_left.request_voltage" +#define UI_NAME_DETAIL_REQUEST_CURRENT ".card_left.request_current" +#define UI_NAME_DETAIL_OFFER_VOLTAGE ".card_left.offer_voltage" +#define UI_NAME_DETAIL_RUN_STATE_VALUE ".card_left.run_state_value" +#define UI_NAME_DETAIL_SUB_STATE_VALUE ".card_left.sub_state_value" +#define UI_NAME_DETAIL_ERROR_CODE_VALUE ".card_left.error_code_value" +#define UI_NAME_DETAIL_CONN_STATUS_VALUE ".card_left.conn_status_value" +#define UI_NAME_DETAIL_START_SOC_VALUE ".card_left.start_soc_value" +#define UI_NAME_DETAIL_REQUEST_VOLTAGE_VALUE ".card_left.request_voltage_value" +#define UI_NAME_DETAIL_REQUEST_CURRENT_VALUE ".card_left.request_current_value" +#define UI_NAME_DETAIL_OFFER_VOLTAGE_VALUE ".card_left.offer_voltage_value" + +#define UI_NAME_DETAIL_OFFER_CURRENT ".card_right.offer_current" +#define UI_NAME_DETAIL_OUTPUT_LIMIT ".card_right.output_limit" +#define UI_NAME_DETAIL_COMP_GROUP ".card_right.comp_group" +#define UI_NAME_DETAIL_CONN_TEMPERATURE ".card_right.conn_temperature" +#define UI_NAME_DETAIL_OUTPUT_VOLTAGE ".card_right.output_voltage" +#define UI_NAME_DETAIL_OUTPUT_CURRENT ".card_right.output_current" +#define UI_NAME_DETAIL_OFFER_CURRENT_VALUE ".card_right.offer_current_value" +#define UI_NAME_DETAIL_OUTPUT_LIMIT_VALUE ".card_right.output_limit_value" +#define UI_NAME_DETAIL_COMP_GROUP_VALUE ".card_right.comp_group_value" +#define UI_NAME_DETAIL_CONN_TEMPERATURE_VALUE ".card_right.conn_temperature_value" +#define UI_NAME_DETAIL_OUTPUT_VOLTAGE_VALUE ".card_right.output_voltage_value" +#define UI_NAME_DETAIL_OUTPUT_CURRENT_VALUE ".card_right.output_current_value" + + +typedef enum { + CLOSE_TEXT, + DETAIL_DATA, + + RUN_STATE, + SUB_STATE, + ERROR_CODE, + CONN_STATUS, + START_SOC, + REQUEST_VOLTAGE, + REQUEST_CURRENT, + OFFER_VOLTAGE, + OFFER_CURRENT, + OUTPUT_LIMIT, + COMP_GROUP, + CONN_TEMPERATURE, + OUTPUT_VOLTAGE, + OUTPUT_CURRENT, + RUN_STATE_VALUE, + SUB_STATE_VALUE, + ERROR_CODE_VALUE, + CONN_STATUS_VALUE, + START_SOC_VALUE, + REQUEST_VOLTAGE_VALUE, + REQUEST_CURRENT_VALUE, + OFFER_VOLTAGE_VALUE, + OFFER_CURRENT_VALUE, + OUTPUT_LIMIT_VALUE, + COMP_GROUP_VALUE, + CONN_TEMPERATURE_VALUE, + OUTPUT_VOLTAGE_VALUE, + OUTPUT_CURRENT_VALUE, + + CARD_NUMBER + +}detail_card_e; + +typedef struct { + + lv_obj_t * obj; + lv_obj_t * close_btn; + lv_obj_t * card_label[CARD_NUMBER]; +}detailed_data_t; + +detailed_data_t detailed_data; + +// 显示充电详情弹出信息, 内容由ui_json提供 +void ui_popup_show_charging_detail(int idx, int type) +{ + ui_popup_show_mask(true); // 显示遮罩层 + if ( detailed_data.obj == NULL ) { + detailed_data.obj = ioc_layout_mngr_load_layout("detailed_data", lv_layer_top()); + } + if ( detailed_data.obj != NULL ) { + lv_obj_clear_flag(detailed_data.obj, LV_OBJ_FLAG_HIDDEN); + } + ioc_label_set_text(detailed_data.card_label[CLOSE_TEXT], "Close"); + ioc_label_set_text(detailed_data.card_label[DETAIL_DATA], "Detailed_data"); + ioc_label_set_text(detailed_data.card_label[RUN_STATE], "Run_State"); + ioc_label_set_text(detailed_data.card_label[SUB_STATE], "Sub_State"); + ioc_label_set_text(detailed_data.card_label[ERROR_CODE], "Error_Code"); + ioc_label_set_text(detailed_data.card_label[CONN_STATUS], "Conn_Status"); + ioc_label_set_text(detailed_data.card_label[START_SOC], "Start_SoC"); + ioc_label_set_text(detailed_data.card_label[REQUEST_VOLTAGE], "Request_Voltage"); + ioc_label_set_text(detailed_data.card_label[REQUEST_CURRENT], "Request_Current"); + ioc_label_set_text(detailed_data.card_label[OFFER_VOLTAGE], "Offer_Voltage"); + ioc_label_set_text(detailed_data.card_label[OFFER_CURRENT], "Offer_Current"); + ioc_label_set_text(detailed_data.card_label[OUTPUT_LIMIT], "Output_Limit"); + ioc_label_set_text(detailed_data.card_label[COMP_GROUP], "Comp_Group"); + ioc_label_set_text(detailed_data.card_label[CONN_TEMPERATURE], "Conn_Temperature"); + ioc_label_set_text(detailed_data.card_label[OUTPUT_VOLTAGE], "Output_Voltage"); + ioc_label_set_text(detailed_data.card_label[OUTPUT_CURRENT], "Output_Current"); + + // 设置详细数据 + char buf[128] = {0}; + ioc_label_set_text(detailed_data.card_label[RUN_STATE_VALUE], g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].m1768Info_runState); + snprintf(buf, sizeof(buf), "%d", g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].subState); + ioc_label_set_text(detailed_data.card_label[SUB_STATE_VALUE], buf); + + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%d", g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].m1768errCode); + ioc_label_set_text(detailed_data.card_label[ERROR_CODE_VALUE], buf); + + memset(buf, 0x00, sizeof(buf)); + //TODO 国际化 + if(strcmp(g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].connStatus, "Unplug") == 0) + { + ioc_label_set_text(detailed_data.card_label[CONN_STATUS_VALUE], "Unplug"); + } + else if(strcmp(g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].connStatus, "Plug") == 0) + { + ioc_label_set_text(detailed_data.card_label[CONN_STATUS_VALUE], "Plugged"); + } + else if(strcmp(g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].connStatus, "Charging") == 0) + { + ioc_label_set_text(detailed_data.card_label[CONN_STATUS_VALUE], "Charging"); + } + else if(strcmp(g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].connStatus, "Finished") == 0) + { + ioc_label_set_text(detailed_data.card_label[CONN_STATUS_VALUE], "Finished"); + } + else + { + ioc_label_set_text(detailed_data.card_label[CONN_STATUS_VALUE], "Fault"); + } + + // 交流没有以下参数 + if(ioc_conntype_isAC(UI_CONNECTOR_ACTIVE_IDX)) + { + ioc_label_set_text(detailed_data.card_label[START_SOC_VALUE], "N/A"); + ioc_label_set_text(detailed_data.card_label[REQUEST_VOLTAGE_VALUE], "N/A"); + ioc_label_set_text(detailed_data.card_label[REQUEST_CURRENT_VALUE], "N/A"); + ioc_label_set_text(detailed_data.card_label[CONN_TEMPERATURE_VALUE], "N/A"); + } + else + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%d", g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].startSoc); + ioc_label_set_text(detailed_data.card_label[START_SOC_VALUE], buf); + + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%.1f", g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].reqVol); + strncat(buf, "V", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(detailed_data.card_label[REQUEST_VOLTAGE_VALUE], buf); + + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%.1f", g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].reqCur); + strncat(buf, "A", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(detailed_data.card_label[REQUEST_CURRENT_VALUE], buf); + + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%d", g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].temp); + strncat(buf, "°", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(detailed_data.card_label[CONN_TEMPERATURE_VALUE], buf); + } + + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%.1f", g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].offerVol); + strncat(buf, "V", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(detailed_data.card_label[OFFER_VOLTAGE_VALUE], buf); + + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%.1f", g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].offerCur); + strncat(buf, "A", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(detailed_data.card_label[OFFER_CURRENT_VALUE], buf); + + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%.1f", g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].outLimit); + strncat(buf, g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].outLimitUnit, sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(detailed_data.card_label[OUTPUT_LIMIT_VALUE], buf); + + if(g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].compGroup == 1) + { + ioc_label_set_text(detailed_data.card_label[COMP_GROUP_VALUE], "A"); + } + else if(g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].compGroup == 2) + { + ioc_label_set_text(detailed_data.card_label[COMP_GROUP_VALUE], "B"); + } + else if(g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].compGroup == 3) + { + ioc_label_set_text(detailed_data.card_label[COMP_GROUP_VALUE], "A + B"); + } + else + { + ioc_label_set_text(detailed_data.card_label[COMP_GROUP_VALUE], "N/A"); + } + + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%.1f", g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.charging.meterData.voltage[0]); + strncat(buf, "V", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(detailed_data.card_label[OUTPUT_VOLTAGE_VALUE], buf); + + + double Curr[3]; + Curr[0] = g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.charging.meterData.current[0]; + Curr[1] = g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.charging.meterData.current[1]; + Curr[2] = g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.charging.meterData.current[2]; + + double maxCurr = (Curr[0] > Curr[1])? Curr[0] : Curr[1]; + maxCurr = (maxCurr > Curr[2])? maxCurr : Curr[2]; + + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), "%.1f", maxCurr); + strncat(buf, "V", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(detailed_data.card_label[OUTPUT_CURRENT_VALUE], buf); + +} + +typedef struct { + const char *suffix; + lv_obj_t **obj; +} ui_detail_obj_map_entry_t; + +static ui_detail_obj_map_entry_t obj_map[] = { + { UI_NAME_DETAIL_CLOSE_BTN, &detailed_data.close_btn }, + + { UI_NAME_DETAIL_CLOSE_TEXT, &detailed_data.card_label[CLOSE_TEXT] }, + { UI_NAME_DETAIL_DETAIL_DATA, &detailed_data.card_label[DETAIL_DATA] }, + + { UI_NAME_DETAIL_RUN_STATE, &detailed_data.card_label[RUN_STATE] }, + { UI_NAME_DETAIL_SUB_STATE, &detailed_data.card_label[SUB_STATE] }, + { UI_NAME_DETAIL_ERROR_CODE, &detailed_data.card_label[ERROR_CODE] }, + { UI_NAME_DETAIL_CONN_STATUS, &detailed_data.card_label[CONN_STATUS] }, + { UI_NAME_DETAIL_START_SOC, &detailed_data.card_label[START_SOC] }, + { UI_NAME_DETAIL_REQUEST_VOLTAGE, &detailed_data.card_label[REQUEST_VOLTAGE] }, + { UI_NAME_DETAIL_REQUEST_CURRENT, &detailed_data.card_label[REQUEST_CURRENT] }, + { UI_NAME_DETAIL_OFFER_VOLTAGE, &detailed_data.card_label[OFFER_VOLTAGE] }, + { UI_NAME_DETAIL_OFFER_CURRENT, &detailed_data.card_label[OFFER_CURRENT] }, + { UI_NAME_DETAIL_OUTPUT_LIMIT, &detailed_data.card_label[OUTPUT_LIMIT] }, + { UI_NAME_DETAIL_COMP_GROUP, &detailed_data.card_label[COMP_GROUP] }, + { UI_NAME_DETAIL_CONN_TEMPERATURE, &detailed_data.card_label[CONN_TEMPERATURE] }, + { UI_NAME_DETAIL_OUTPUT_VOLTAGE, &detailed_data.card_label[OUTPUT_VOLTAGE] }, + { UI_NAME_DETAIL_OUTPUT_CURRENT, &detailed_data.card_label[OUTPUT_CURRENT] }, + + { UI_NAME_DETAIL_RUN_STATE_VALUE, &detailed_data.card_label[RUN_STATE_VALUE] }, + { UI_NAME_DETAIL_SUB_STATE_VALUE, &detailed_data.card_label[SUB_STATE_VALUE] }, + { UI_NAME_DETAIL_ERROR_CODE_VALUE, &detailed_data.card_label[ERROR_CODE_VALUE] }, + { UI_NAME_DETAIL_CONN_STATUS_VALUE, &detailed_data.card_label[CONN_STATUS_VALUE] }, + { UI_NAME_DETAIL_START_SOC_VALUE, &detailed_data.card_label[START_SOC_VALUE] }, + { UI_NAME_DETAIL_REQUEST_VOLTAGE_VALUE, &detailed_data.card_label[REQUEST_VOLTAGE_VALUE] }, + { UI_NAME_DETAIL_REQUEST_CURRENT_VALUE, &detailed_data.card_label[REQUEST_CURRENT_VALUE] }, + { UI_NAME_DETAIL_OFFER_VOLTAGE_VALUE, &detailed_data.card_label[OFFER_VOLTAGE_VALUE] }, + { UI_NAME_DETAIL_OFFER_CURRENT_VALUE, &detailed_data.card_label[OFFER_CURRENT_VALUE] }, + { UI_NAME_DETAIL_OUTPUT_LIMIT_VALUE, &detailed_data.card_label[OUTPUT_LIMIT_VALUE] }, + { UI_NAME_DETAIL_COMP_GROUP_VALUE, &detailed_data.card_label[COMP_GROUP_VALUE] }, + { UI_NAME_DETAIL_CONN_TEMPERATURE_VALUE, &detailed_data.card_label[CONN_TEMPERATURE_VALUE] }, + { UI_NAME_DETAIL_OUTPUT_VOLTAGE_VALUE, &detailed_data.card_label[OUTPUT_VOLTAGE_VALUE] }, + { UI_NAME_DETAIL_OUTPUT_CURRENT_VALUE, &detailed_data.card_label[OUTPUT_CURRENT_VALUE] } +}; + +static void detail_close_event_cb(lv_event_t *e); + +void ui_after_create_detaile_data(const char * name, lv_obj_t * obj) +{ + const char * dataile_name = name + strlen(UI_NAME_DETAILED_DATA); + + for (size_t i = 0; i < sizeof(obj_map) / sizeof(obj_map[0]); ++i) { + if (strcmp(dataile_name, obj_map[i].suffix) == 0) { + *(obj_map[i].obj) = obj; + if ( strcmp(dataile_name, UI_NAME_DETAIL_CLOSE_BTN) == 0 ) { + lv_obj_add_event_cb(obj, detail_close_event_cb, LV_EVENT_CLICKED, (void*)obj_map[i].suffix); + } + return; + } + } +} + +static void detail_close_event_cb(lv_event_t *e) +{ + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + lv_obj_add_flag(detailed_data.obj, LV_OBJ_FLAG_HIDDEN); + ui_popup_show_mask(false); + } +} diff --git a/pages/ui_popup_charging_detail.h b/pages/ui_popup_charging_detail.h new file mode 100644 index 000000000..657b334ed --- /dev/null +++ b/pages/ui_popup_charging_detail.h @@ -0,0 +1,13 @@ +#ifndef __UI_POPUP_CHARGING_DETAIL_H__ +#define __UI_POPUP_CHARGING_DETAIL_H__ + +#include "lvgl.h" + + +#define UI_NAME_DETAILED_DATA "detailed_data" + +// 显示充电详情弹出信息, 内容由ui_json提供 +void ui_popup_show_charging_detail(int idx, int type); + +void ui_after_create_detaile_data(const char * name, lv_obj_t * obj); +#endif diff --git a/pages/ui_popup_common.c b/pages/ui_popup_common.c new file mode 100644 index 000000000..2eb469e32 --- /dev/null +++ b/pages/ui_popup_common.c @@ -0,0 +1,371 @@ +#include "../pages_mngr.h" + +static lv_obj_t * s_ui_popup_mask = NULL; + +void ui_popup_show_mask(bool show) +{ + if (s_ui_popup_mask == NULL) + { + s_ui_popup_mask = lv_obj_create(lv_layer_top()); + lv_obj_set_size(s_ui_popup_mask,800,600); + lv_obj_set_style_bg_color(s_ui_popup_mask,lv_color_make(0,0,0),0); + lv_obj_set_style_bg_opa(s_ui_popup_mask,100,0); + lv_obj_set_style_radius(s_ui_popup_mask,0,0); + } + if (show) + { + lv_obj_clear_flag(s_ui_popup_mask, LV_OBJ_FLAG_HIDDEN); + } + else + { + lv_obj_add_flag(s_ui_popup_mask, LV_OBJ_FLAG_HIDDEN); + } +} + +#define UI_NAME_COMMON_PROMPT_TEXT ".prompt.text" +#define UI_NAME_COMMON_CLOSE_BTN ".close_button" +#define UI_NAME_COMMON_CLOSE_TEXT ".close_button.text" +#define UI_NAME_COMMON_CLOSE_SECONDS ".close_button.seconds" +#define UI_NAME_COMMON_CIRCLE_IMG ".circle_img" + +#define COMMOM_CLOSE_TIMER_COUNT 60 +typedef struct { + + lv_obj_t * obj; + lv_obj_t * prompt_text; + lv_obj_t * close_btn; + lv_obj_t * close_text; + lv_obj_t * close_seconds; + lv_obj_t * circle_img; + + lv_timer_t * close_timer; + uint16_t close_time_counter; +}popup_common_t; + + +popup_common_t popup_common; + +void ui_popup_show_common(char *str, bool needi18n, circle_e circle_img) +{ + ui_popup_show_mask(true); // 显示遮罩层 + if ( popup_common.obj == NULL ) { + popup_common.obj = ioc_layout_mngr_load_layout("popup_common", lv_layer_top()); + } + if ( popup_common.obj != NULL ) { + lv_obj_clear_flag(popup_common.obj, LV_OBJ_FLAG_HIDDEN); + } + + popup_set_circle_img(circle_img); + + if(needi18n) + { + ioc_label_set_text(popup_common.prompt_text, str); + } + else + { + ioc_label_set_text(popup_common.prompt_text, str); + } + + // "Downloading" 和 “Installing"特殊处理,不显示倒计时 + if (strcmp(str, "Downloading") == 0 || strcmp(str, "Installing") == 0) + { + lv_obj_add_state(popup_common.close_btn, LV_STATE_DISABLED); + char buf[16] = {0}; + sprintf(buf, "%d%%", g_ui_json.trigger.percent); + LV_LOG_WARN("buf[%s] percent[%d]", buf, g_ui_json.trigger.percent); + ioc_label_set_text(popup_common.close_text, buf); + lv_timer_resume(popup_common.close_timer); + return; + } + + // 如果按钮是禁用状态,则恢复 + if (lv_obj_has_state(popup_common.close_btn, LV_STATE_DISABLED)) + { + lv_obj_clear_state(popup_common.close_btn, LV_STATE_DISABLED); + } + + ioc_label_set_text(popup_common.close_text, "Close"); + lv_timer_resume(popup_common.close_timer); + + return; +} + +static void common_close_timer_cb(lv_timer_t * t) { + + if (popup_common.close_time_counter == 0) { + lv_obj_add_flag(popup_common.obj, LV_OBJ_FLAG_HIDDEN); + ui_popup_show_mask(false); + lv_timer_pause(popup_common.close_timer); + popup_common.close_time_counter = 0; + return; + } + + popup_common.close_time_counter--; + + + char buf[8] = {0}; + // "Downloading" 和 “Installing"特殊处理,按钮文本显示百分比 + if((strcmp(g_ui_json.trigger.trigger, "Downloading") != 0) && (strcmp(g_ui_json.trigger.trigger, "Installing") != 0)) + { + char buf[8]; + snprintf(buf, sizeof(buf), "(%ds)", popup_common.close_time_counter); + ioc_label_set_text(popup_common.close_seconds, buf); + } + else + { + ioc_label_set_text(popup_common.close_seconds, buf); + } +} + +typedef struct { + const char *suffix; + lv_obj_t **obj; +} ui_detail_obj_map_entry_t; + +static ui_detail_obj_map_entry_t obj_map[] = { + { UI_NAME_COMMON_PROMPT_TEXT, &popup_common.prompt_text }, + + { UI_NAME_COMMON_CLOSE_BTN, &popup_common.close_btn }, + { UI_NAME_COMMON_CLOSE_TEXT, &popup_common.close_text }, + { UI_NAME_COMMON_CLOSE_SECONDS, &popup_common.close_seconds }, + { UI_NAME_COMMON_CIRCLE_IMG, &popup_common.circle_img } + +}; + +static void popup_common_close_event_cb(lv_event_t *e); + +void ui_after_create_popup_common(const char * name, lv_obj_t * obj) +{ + const char * popup_common_name = name + strlen(UI_NAME_POPUP_COMMON); + + for (size_t i = 0; i < sizeof(obj_map) / sizeof(obj_map[0]); ++i) { + if (strcmp(popup_common_name, obj_map[i].suffix) == 0) { + *(obj_map[i].obj) = obj; + if ( strcmp(popup_common_name, UI_NAME_COMMON_CLOSE_BTN) == 0 ) { + lv_obj_set_layout(obj, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW); + lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + lv_obj_set_style_pad_column(obj, 5, 0); + lv_obj_add_event_cb(obj, popup_common_close_event_cb, LV_EVENT_CLICKED, (void*)obj_map[i].suffix); + } + return; + } + } + if ( popup_common.close_timer == NULL ) + { + popup_common.close_timer = lv_timer_create(common_close_timer_cb, 1000, NULL); + lv_timer_pause(popup_common.close_timer); + } +} + +static void popup_common_close_event_cb(lv_event_t *e) +{ + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + lv_obj_add_flag(popup_common.obj, LV_OBJ_FLAG_HIDDEN); + ui_popup_show_mask(false); + } +} + +void popup_set_circle_img(int idx) +{ + static int last_index = -1; + if ( last_index == idx ) + return; + switch (idx) + { + case POP_PROMPTS : + lv_img_set_src(popup_common.circle_img, "A:./assets/images/icon_inmation.png"); + break; + case POP_WARNRING : + lv_img_set_src(popup_common.circle_img, "A:./assets/images/icon_warning_2.png"); + break; + case POP_ERROR : + lv_img_set_src(popup_common.circle_img, "A:./assets/images/icon_error.png"); + break; + default: + break; + } + last_index = idx; +} + + +void ui_popup_common_handle(const char *trigger_str) +{ + if(g_ui_json.trigger.seconds != 0) + { + popup_common.close_time_counter = g_ui_json.trigger.seconds; + } + + memset(g_ui_json.trigger.trigger, 0x00, sizeof(g_ui_json.trigger.trigger)); + strncpy(g_ui_json.trigger.trigger, trigger_str, sizeof(g_ui_json.trigger.trigger) - 1); + + circle_e circle_img; + char* str = NULL; + if ( strcmp(trigger_str, "Downloading") == 0 ) + { + str = "Downloading"; + circle_img = POP_PROMPTS; + popup_common.close_time_counter = 6000; // 设置一个大的数卡在这个界面 + } + else if ( strcmp(trigger_str, "Installing") == 0 ) + { + str = "Installing"; + circle_img = POP_PROMPTS; + popup_common.close_time_counter = 6000; // 设置一个大的数卡在这个界面 + } + else if ( strcmp(trigger_str, "Prompt") == 0 ) + { + switch (g_ui_json.trigger.msg) + { + case CHARGER_SCREEN_MSG_NO_CONN_SELECTED: + str = "No connector selected"; + break; + case CHARGER_SCREEN_MSG_FAILED_TO_START_CHARGING: + str = "Failed to start charging"; + break; + case CHARGER_SCREEN_MSG_FAULT_FOUND_STOP_CHARGING: + str = "Fault found, Stop Charging"; + break; + case CHARGER_SCREEN_MSG_ADDRFID: + str = "Add RFID succeed"; //TODO 国际化 + break; + case CHARGER_SCREEN_MSG_CLEARRFID: + str = "Remove RFID succeed"; //TODO 国际化 + break; + case CHARGER_SCREEN_MSG_CCS_AUTOCHARGE_BIND: + { + int conidx = ui_page_04_starting2_get_autu_conidx(); + switch (conidx) + { + case 0: + str = "Please start charging within 1 minutes for connector 1th"; + break; + case 1: + str = "Please start charging within 1 minutes for connector 2th"; + break; + case 2: + str = "Please start charging within 1 minutes for connector 3th"; + break; + case 3: + str = "Please start charging within 1 minutes for connector 4th"; + break; + default: + str = "Please start charging within 1 minutes"; + break; + } + } + break; + case CHARGER_SCREEN_MSG_NOT_PERMIT: + default: + str = "Not Permit"; + break; + } + circle_img = POP_WARNRING; + } + else if ( strcmp(trigger_str, "CreditCard") == 0 ) + { + switch (g_ui_json.trigger.msg) + { + case CHARGER_SCREEN_CREDIT_POINT: + str = "Swipe, insert or tap your card on the POS"; + circle_img = POP_PROMPTS; + break; + case CHARGER_SCREEN_CREDIT_NO_CONN_SELECTED: + str = "No connector selected"; + circle_img = POP_ERROR; + break; + case CHARGER_SCREEN_CREDIT_PREAUTH_FAILED: + str = "pre-authorization failed"; + circle_img = POP_ERROR; + break; + case CHARGER_SCREEN_CREDIT_PREAUTH_SUCCESS: + str = "Pre-Authorization Settled"; + circle_img = POP_PROMPTS; + break; + case CHARGER_SCREEN_CREDIT_SETTLEMENT_FAILED: + str = "Payment failed"; + circle_img = POP_ERROR; + break; + case CHARGER_SCREEN_CREDIT_SETTLEMENT_SUCCESS: + str = "Payment Settled"; + circle_img = POP_PROMPTS; + break; + case CHARGER_SCREEN_CREDIT_WATTING: + str = "POS is processing the request, please wait"; + circle_img = POP_PROMPTS; + break; + case CHARGER_SCREEN_CREDIT_VPOS_BUSY: + str = "POS busy, please try again later"; + circle_img = POP_WARNRING; + break; + case CHARGER_SCREEN_CREDIT_VPOS_FAULT: + str = "POS error, please contact the service"; + circle_img = POP_ERROR; + break; + default: + str = "ERROR"; + circle_img = POP_ERROR; + break; + } + } + else if (strcmp(trigger_str, "Auth") == 0) + { + switch (g_ui_json.trigger.msg) + { + case CHARGER_SCREEN_AUTH_FAIL_BLOCKED: + str = "Authorization Failed: Blocked"; + break; + case CHARGER_SCREEN_AUTH_FAIL_EXPIRED: + str = "Authorization Failed: Expired"; + break; + case CHARGER_SCREEN_AUTH_FAIL_INVALID: + str = "Authorization Failed: Invalid"; + break; + case CHARGER_SCREEN_AUTH_FAIL_CONCURRENTTX: + str = "Authorization Failed: Concurrent TX"; + break; + case CHARGER_SCREEN_AUTH_SUCCESS: + str = "Authorized"; + break; + case CHARGER_SCREEN_AUTH_FAIL_OTHER: + default: + str = "Authorization Failed: Other Reason"; + break; + } + if(g_ui_json.trigger.msg == CHARGER_SCREEN_AUTH_SUCCESS) + { + circle_img = POP_PROMPTS; + } + else + { + circle_img = POP_ERROR; + } + } + else if (strcmp(trigger_str, "Message") == 0) + { + // message里的内容是由调用者填写,内容不确定,所以不用国际化 + str = g_ui_json.trigger.content; + circle_img = POP_PROMPTS; + ui_popup_show_common(str, false, circle_img); + return; + } + else if (strcmp(trigger_str, "Cancel") == 0) + { + popup_common.close_time_counter = 0; + return; + } + else if (strcmp(trigger_str, "MessageCancel") == 0) + { + return; + } + else + { + LV_LOG_WARN("Unknow Trigger[%s]", trigger_str); + return; + } + + ui_popup_show_common(str, true, circle_img); + + return; +} diff --git a/pages/ui_popup_common.h b/pages/ui_popup_common.h new file mode 100644 index 000000000..0427c0e0b --- /dev/null +++ b/pages/ui_popup_common.h @@ -0,0 +1,26 @@ +#ifndef __UI_POPUP_COMMON_H__ +#define __UI_POPUP_COMMON_H__ + +#include "lvgl.h" + +#define UI_NAME_POPUP_COMMON "popup_common" + +typedef enum +{ + POP_PROMPTS, + POP_WARNRING, + POP_ERROR, + +}circle_e; + +void ui_popup_show_mask(bool show); + +// 显示ui_json传递过来的homeOcpp发起的弹出信息, 例如授权错误等 +void ui_popup_show_common(char *str, bool needi18n, circle_e circle_img); + +void ui_after_create_popup_common(const char * name, lv_obj_t * obj); + +void popup_set_circle_img(int idx); + +void ui_popup_common_handle(const char *str); +#endif diff --git a/pages/ui_popup_help.c b/pages/ui_popup_help.c new file mode 100644 index 000000000..d3c9890c6 --- /dev/null +++ b/pages/ui_popup_help.c @@ -0,0 +1,556 @@ +#include "../pages_mngr.h" + +#define UI_NAME_HELP1_CLOSE_BTN ".help1_close_button" +#define UI_NAME_HELP1_HELP_LIST ".help1_list" +#define UI_NAME_HELP1_LABEL ".help1_title" +#define UI_NAME_HELP1_CLOSE_LABEL ".help1_close_button.btn_label" +#define UI_NAME_HELP1_INFO_RF ".help1_status_info.info_RF_img" +#define UI_NAME_HELP1_INFO_4G ".help1_status_info.info_4G_img" +#define UI_NAME_HELP1_INFO_SEVER ".help1_status_info.info_sever_img" +#define UI_NAME_HELP1_INFO_NET ".help1_status_info.info_net_img" +#define UI_NAME_HELP1_INFO_WIFI ".help1_status_info.info_wifi_img" +#define UI_NAME_HELP1_INFO_METER ".help1_status_info.info_meter_img" +#define UI_NAME_HELP1_INFO_IP ".help1_status_info.IP_lable" + + +#define UI_NAME_HELP2_CLOSE_BTN ".help2_close_button" +#define UI_NAME_HELP2_BACK_BTN ".help2_back_button" +#define UI_NAME_HELP2_TITLE ".help2_title" +#define UI_NAME_HELP2_CONTENT ".help2_content" +#define UI_NAME_HELP2_CLOSE_LABEL ".help2_close_button.btn_label" +#define UI_NAME_HELP2_BACK_LABEL ".help2_back_button.btn_label" + +typedef struct +{ + lv_obj_t * help1; // 第一层帮助页面 + lv_obj_t * help1_label; // 第一层帮助页面的帮助文本 + lv_obj_t * help1_close_label; // 第一层帮助页面的按钮文本 + lv_obj_t * help1_info_rf; // 第一层帮助页面的RF信息 + lv_obj_t * help1_info_4g; // 第一层帮助页面的RF信息 + lv_obj_t * help1_info_sever; // 第一层帮助页面的server信息 + lv_obj_t * help1_info_net; // 第一层帮助页面的net信息 + lv_obj_t * help1_info_wifi; // 第一层帮助页面的wifi信息 + lv_obj_t * help1_info_meter; // 第一层帮助页面的meter信息 + lv_obj_t * help1_info_IP; // 第一层帮助页面的IP信息 + + lv_obj_t * help2; // 第二层帮助页面 + + lv_obj_t * close_btn_help1; // 第一层页面的关闭按钮, 关闭帮助页面 + lv_obj_t * help_list; // 第一层页面的帮助列表, 点击后打开第二层帮助页面 + + lv_obj_t * close_btn_help2; // 第二层页面的关闭按钮, 直接关闭两层帮助页面 + lv_obj_t * back_btn; // 第二层页面的返回按钮, 返回第一层页面 + lv_obj_t * title; // 第二层页面的标题 + lv_obj_t * content; // 第二层页面的内容 + lv_obj_t * help2_close_label; // 第二层帮助页面的关闭按钮文本 + lv_obj_t * help2_back_label; // 第二层帮助页面的返回按钮文本 + + cJSON * help_json; // 帮助的json数据, 从文件中读取 +} ui_help_t; + +static ui_help_t s_ui_help = {0}; + + +static void update_img_if_changed(lv_obj_t **img_obj, int *last_state, int new_state, const char *on, const char *err, const char *off) +{ + if (new_state != *last_state) + { + const char *src = NULL; + + // 三态判断(1=on, 2=err, 其他=off) + if (new_state == 1) + src = on; + else if (new_state == 2) + src = err; + else + src = off; + + lv_img_set_src(*img_obj, src); + *last_state = new_state; + } +} + +static void update_img_bool_if_changed(lv_obj_t **img_obj, bool *last_state, bool new_state, const char *on, const char *err) +{ + if (new_state != *last_state) + { + const char *src = new_state ? err : on; // true = 错误 + // LV_LOG_WARN("src[%s]", src); + lv_img_set_src(*img_obj, src); + *last_state = new_state; + } +} + +static void ui_page_pop_help_status_update() +{ + // LV_LOG_WARN("2222222=============================="); + + // LV_LOG_WARN("m4gStatus[%d] ethStatus[%d] wifiStatus[%d] meterFault[%d] rfFault[%d] online[%d]", g_ui_json.drvPointInfo.m4gStatus, + // g_ui_json.drvPointInfo.ethStatus, g_ui_json.drvPointInfo.wifiStatus, g_ui_json.drvPointInfo.meterFault, + // g_ui_json.drvPointInfo.rfFault, g_ui_json.drvPointInfo.online); + + + static int last_4g = -1; + static int last_eth = -1; + static int last_wifi = -1; + static bool last_meterFault = true; + static bool last_rfFault = true; + static bool last_online = false; + + // 4G 状态 (1=on, 2=err, else=off) + update_img_if_changed(&s_ui_help.help1_info_4g, &last_4g, + g_ui_json.drvPointInfo.m4gStatus, + "A:./assets/images/4g_on.png", + "A:./assets/images/4g_err.png", + "A:./assets/images/4g_off.png"); + + // 网线状态 + update_img_if_changed(&s_ui_help.help1_info_net, &last_eth, + g_ui_json.drvPointInfo.ethStatus, + "A:./assets/images/net_on.png", + "A:./assets/images/net_err.png", + "A:./assets/images/net_off.png"); + + // Wi-Fi 状态 + update_img_if_changed(&s_ui_help.help1_info_wifi, &last_wifi, + g_ui_json.drvPointInfo.wifiStatus, + "A:./assets/images/wifi_on.png", + "A:./assets/images/wifi_err.png", + "A:./assets/images/wifi_off.png"); + + // 电表故障(true=err, false=on) + update_img_bool_if_changed(&s_ui_help.help1_info_meter, &last_meterFault, + g_ui_json.drvPointInfo.meterFault, + "A:./assets/images/meter_on.png", + "A:./assets/images/meter_err.png"); + + // RF 故障(true=err, false=on) + update_img_bool_if_changed(&s_ui_help.help1_info_rf, &last_rfFault, + g_ui_json.drvPointInfo.rfFault, + "A:./assets/images/rf_on.png", + "A:./assets/images/rf_err.png"); + + // 服务器在线状态(true=on, false=err) + update_img_bool_if_changed(&s_ui_help.help1_info_sever, &last_online, + g_ui_json.drvPointInfo.online, + "A:./assets/images/sever_err.png", + "A:./assets/images/sever_on.png"); +} + +static void ui_page_pop_help_updatejson(struct ioc_obj_user_data_s *user_data) +{ + // LV_LOG_WARN("11111=============================="); + ui_page_pop_help_status_update(); + if (s_ui_help.help1_info_IP != NULL) + { + char buf[128] = {0}; + if (g_ui_json.drvPointInfo.httpAddr[0] != '\0') + { + snprintf(buf, sizeof(buf), "IP: %s", g_ui_json.drvPointInfo.httpAddr); + } + ioc_label_set_text(s_ui_help.help1_info_IP, buf); + } +} + + +// 显示帮助页面 +void ui_popup_show_help(void) +{ + if (s_ui_help.help_json == NULL) + { + s_ui_help.help_json = JSON_FromFile(HELP_PATCH_FILE); + if (s_ui_help.help_json == NULL) + { + s_ui_help.help_json = JSON_FromFile(HELP_JSON_FILE); + } + } + + ui_popup_show_mask(true); // 显示遮罩层 + + if (s_ui_help.help1 == NULL) + { + s_ui_help.help1 = ioc_layout_mngr_load_layout("help1", lv_layer_top()); + + // 第一次刷新一下状态 + ui_page_pop_help_status_update(); + + // 设置回调,用于更新rf,meter等状态 + if (s_ui_help.help1 != NULL) + { + // LV_LOG_WARN("000====================================="); + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(s_ui_help.help1); + user_data->ui_json_update_cb = ui_page_pop_help_updatejson; + } + } + + if (s_ui_help.help1 != NULL) + { + lv_obj_clear_flag(s_ui_help.help1, LV_OBJ_FLAG_HIDDEN); + } + + // 文本随语言的改变而改变 + ioc_label_set_text(s_ui_help.help1_label, "Help"); + ioc_label_set_text(s_ui_help.help1_close_label, "Close"); + ioc_label_set_text(s_ui_help.help2_close_label, "Close"); + ioc_label_set_text(s_ui_help.help2_back_label, "Back"); +} + +static void ui_help1_close_btn_event_cb(lv_event_t * e) +{ + if (s_ui_help.help2 != NULL) + { + lv_obj_add_flag(s_ui_help.help2, LV_OBJ_FLAG_HIDDEN); + } + lv_obj_add_flag(s_ui_help.help1, LV_OBJ_FLAG_HIDDEN); + ui_popup_show_mask(false); // 关闭遮罩层 +} + +static void ui_help2_back_btn_event_cb(lv_event_t * e) +{ + if (s_ui_help.help2 != NULL) + { + lv_obj_add_flag(s_ui_help.help2, LV_OBJ_FLAG_HIDDEN); + } +} + +static void ui_help1_show_help2_btn_event_cb(lv_event_t * e) +{ + if (s_ui_help.help2 == NULL) + { + s_ui_help.help2 = ioc_layout_mngr_load_layout("help2", lv_layer_top()); + } + + if (s_ui_help.help2 != NULL) + { + cJSON * item = (cJSON *)lv_event_get_user_data(e); + cJSON * title = cJSON_GetObjectItem(item, "title"); + cJSON * content = cJSON_GetObjectItem(item, "content"); + ioc_label_set_text(s_ui_help.title, title->valuestring); + ioc_label_set_text(s_ui_help.content, content->valuestring); + + lv_obj_clear_flag(s_ui_help.help2, LV_OBJ_FLAG_HIDDEN); + } +} + +void ui_after_create_help1_close_btn(const char * name, lv_obj_t * obj) +{ + s_ui_help.close_btn_help1 = obj; + lv_obj_add_event_cb(obj, ui_help1_close_btn_event_cb, LV_EVENT_CLICKED, NULL); +} + +void ui_after_create_help1_help_list(const char * name, lv_obj_t * obj) +{ + s_ui_help.help_list = obj; + lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLLABLE); + + if ((s_ui_help.help_json != NULL) && cJSON_IsArray(s_ui_help.help_json)) + { + int size = cJSON_GetArraySize(s_ui_help.help_json); + for (int i = 0; i < size; i++) + { + cJSON * item = cJSON_GetArrayItem(s_ui_help.help_json, i); + if (item == NULL) + { + continue; + } + + cJSON * title = cJSON_GetObjectItem(item, "title"); + cJSON * content = cJSON_GetObjectItem(item, "content"); + if ((title != NULL) && (content != NULL)) + { + lv_obj_t * btn = lv_list_add_btn(obj, NULL, title->valuestring); + lv_obj_add_event_cb(btn, ui_help1_show_help2_btn_event_cb, LV_EVENT_CLICKED, item); + } + } + } +} + +void ui_after_create_help1_label(const char * name, lv_obj_t * obj) +{ + s_ui_help.help1_label = obj; +} + +void ui_after_create_help1_close_label(const char * name, lv_obj_t * obj) +{ + s_ui_help.help1_close_label = obj; +} + +void ui_after_create_help2_close_label(const char * name, lv_obj_t * obj) +{ + s_ui_help.help2_close_label = obj; +} + +void ui_after_create_help2_back_label(const char * name, lv_obj_t * obj) +{ + s_ui_help.help2_back_label = obj; +} + +void ui_after_create_help1_info_rf(const char * name, lv_obj_t * obj) +{ + s_ui_help.help1_info_rf = obj; +} + +void ui_after_create_help1_info_4g(const char * name, lv_obj_t * obj) +{ + s_ui_help.help1_info_4g = obj; +} + +void ui_after_create_help1_info_sever(const char * name, lv_obj_t * obj) +{ + s_ui_help.help1_info_sever = obj; +} + +void ui_after_create_help1_info_net(const char * name, lv_obj_t * obj) +{ + s_ui_help.help1_info_net = obj; +} + +void ui_after_create_help1_info_wifi(const char * name, lv_obj_t * obj) +{ + s_ui_help.help1_info_wifi = obj; +} + +void ui_after_create_help1_info_meter(const char * name, lv_obj_t * obj) +{ + s_ui_help.help1_info_meter = obj; +} + +#if 0 +static bool get_default_iface(char *iface, size_t len) +{ + FILE *fp; + char buf[128] = {0}; + char *p; + + fp = popen("ip route | grep default | head -n 1 | awk -F'dev' '{print $2}'", "r"); + if (fp == NULL) + { + return false; + } + + if (fgets(buf, sizeof(buf), fp) == NULL) + { + pclose(fp); + return false; + } + + pclose(fp); + + // 去掉换行 + if ((p = strchr(buf, '\n')) != NULL) + { + *p = '\0'; + } + + // 跳过前导空格 + p = buf; + while (*p == ' ') + { + p++; + } + + // 截断到第一个空格(防止后面还有参数) + char *space = strchr(p, ' '); + if (space) + { + *space = '\0'; + } + + if (*p == '\0') + { + return false; + } + + strncpy(iface, p, len - 1); + iface[len - 1] = '\0'; + + return true; +} +#endif + +#if 0 +void ui_after_create_help1_info_ip(const char *name, lv_obj_t *obj) +{ + s_ui_help.help1_info_IP = obj; + + char ip_addr[INET_ADDRSTRLEN] = {0}; + char buf[64] = {0}; + char iface[IFNAMSIZ] = {0}; + + int fd = -1; + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + + // 1. 获取默认出口网卡 + if (!get_default_iface(iface, sizeof(iface))) + { + LV_LOG_WARN("Failed to get default network interface"); + ioc_label_set_text(s_ui_help.help1_info_IP, ""); + return; + } + + // 2. 创建 socket + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) + { + LV_LOG_WARN("Failed to create socket"); + ioc_label_set_text(s_ui_help.help1_info_IP, ""); + return; + } + + // 3. 获取该网卡 IP + strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1); + ifr.ifr_name[IFNAMSIZ - 1] = '\0'; + + if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) + { + struct sockaddr_in *ipaddr = (struct sockaddr_in *)&ifr.ifr_addr; + + if (inet_ntop(AF_INET, + &ipaddr->sin_addr, + ip_addr, + sizeof(ip_addr)) != NULL) + { + snprintf(buf, sizeof(buf), "IP: %s", ip_addr); + } + } + + close(fd); + + ioc_label_set_text(s_ui_help.help1_info_IP, buf); +} +#endif + +void ui_after_create_help1_info_ip(const char *name, lv_obj_t *obj) +{ + char buf[128] = {0}; + + s_ui_help.help1_info_IP = obj; + + if (g_ui_json.drvPointInfo.httpAddr[0] != '\0') + { + snprintf(buf, sizeof(buf), "IP: %s", g_ui_json.drvPointInfo.httpAddr); + } + + ioc_label_set_text(s_ui_help.help1_info_IP, buf); +} + + +void ui_after_create_help1(const char * name, lv_obj_t * obj) +{ + const char * help_name = name + strlen(UI_NAME_HELP1); + if (strcmp(help_name, UI_NAME_HELP1_CLOSE_BTN) == 0) + { + ui_after_create_help1_close_btn(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP1_HELP_LIST) == 0) + { + ui_after_create_help1_help_list(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP1_LABEL) == 0) + { + ui_after_create_help1_label(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP1_CLOSE_LABEL) == 0) + { + ui_after_create_help1_close_label(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP1_INFO_RF) == 0) + { + ui_after_create_help1_info_rf(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP1_INFO_4G) == 0) + { + ui_after_create_help1_info_4g(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP1_INFO_SEVER) == 0) + { + ui_after_create_help1_info_sever(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP1_INFO_NET) == 0) + { + ui_after_create_help1_info_net(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP1_INFO_WIFI) == 0) + { + ui_after_create_help1_info_wifi(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP1_INFO_METER) == 0) + { + ui_after_create_help1_info_meter(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP1_INFO_IP) == 0) + { + // LV_LOG_WARN("222========================================="); + ui_after_create_help1_info_ip(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP2_CLOSE_LABEL) == 0) + { + ui_after_create_help2_close_label(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP2_BACK_LABEL) == 0) + { + ui_after_create_help2_back_label(name, obj); + return; + } +} + +void ui_after_create_help2_close_btn(const char * name, lv_obj_t * obj) +{ + s_ui_help.close_btn_help2 = obj; + lv_obj_add_event_cb(obj, ui_help1_close_btn_event_cb, LV_EVENT_CLICKED, NULL); +} + +void ui_after_create_help2_back_btn(const char * name, lv_obj_t * obj) +{ + s_ui_help.back_btn = obj; + lv_obj_add_event_cb(obj, ui_help2_back_btn_event_cb, LV_EVENT_CLICKED, NULL); +} + +void ui_after_create_help2_title(const char * name, lv_obj_t * obj) +{ + s_ui_help.title = obj; +} + +void ui_after_create_help2_content(const char * name, lv_obj_t * obj) +{ + s_ui_help.content = obj; +} + +void ui_after_create_help2(const char * name, lv_obj_t * obj) +{ + const char * help_name = name + strlen(UI_NAME_HELP2); + if (strcmp(help_name, UI_NAME_HELP2_CLOSE_BTN) == 0) + { + ui_after_create_help2_close_btn(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP2_BACK_BTN) == 0) + { + ui_after_create_help2_back_btn(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP2_TITLE) == 0) + { + ui_after_create_help2_title(name, obj); + return; + } + else if (strcmp(help_name, UI_NAME_HELP2_CONTENT) == 0) + { + ui_after_create_help2_content(name, obj); + return; + } +} diff --git a/pages/ui_popup_help.h b/pages/ui_popup_help.h new file mode 100644 index 000000000..aa2e895a2 --- /dev/null +++ b/pages/ui_popup_help.h @@ -0,0 +1,19 @@ +#ifndef __UI_POPUP_HELP_H__ +#define __UI_POPUP_HELP_H__ + +#include "lvgl.h" + +#define HELP_JSON_FILE "./assets/help.json" +#define HELP_PATCH_FILE "./patch/help.json" + +#define UI_NAME_HELP1 "help1" +void ui_after_create_help1(const char * name, lv_obj_t * obj); + +#define UI_NAME_HELP2 "help2" +void ui_after_create_help2(const char * name, lv_obj_t * obj); + +// 显示帮助页面 +void ui_popup_show_help(void); + + +#endif diff --git a/pages/ui_popup_language.c b/pages/ui_popup_language.c new file mode 100644 index 000000000..e7e74786a --- /dev/null +++ b/pages/ui_popup_language.c @@ -0,0 +1,459 @@ +#include "../pages_mngr.h" +#include + +#define UI_NAME_LANGUAGE_CLOSE_BTN ".language_close_btn" +#define UI_NAME_LANGUAGE_CONFIRM_BTN ".language_confirm_btn" +#define UI_NAME_LANGUAGE_CLOSE_TEXT ".language_close_btn.btn_label" +#define UI_NAME_LANGUAGE_CONFIRM_TEXT ".language_confirm_btn.btn_label" +#define UI_NAME_LANGUAGE_LABEL ".language_title" + +#define LANGUAGE_IMG_PATH "./assets/i18n" +#define MAX_LANGUAGES 18 + +ui_language_t s_ui_language = {NULL, NULL, NULL}; + +int compare_lang_label(const void *a, const void *b) { + const lang_info_t *la = (const lang_info_t *)a; + const lang_info_t *lb = (const lang_info_t *)b; + return la->label[0] - lb->label[0]; +} + +// 用户手动设置语言 +bool set_current_language_by_locale(const char *locale) +{ + if (!locale || strlen(locale) == 0) return false; + + for (int i = 0; i < LANG_NUM; ++i) { + if (strcmp(c_LanguageName[i], locale) == 0) { + lv_i18n_set_locale(c_LanguageName[i]); + lv_refr_now(NULL); + return true; + } + } + + LV_LOG_WARN("Unsupported locale: %s", locale); + return false; +} +void language_set_style(lv_obj_t *btn) +{ + lv_style_t *btn_style_checked = ioc_style_mngr_get_style("language_checked"); + lv_style_t *btn_style_unchecked = ioc_style_mngr_get_style("language_unchecked"); + + // 如果点击的是当前已经选中的按钮,则不处理 + if (btn != s_ui_language.selected_btn) { + // 移除上一个按钮的选中样式 + if (s_ui_language.selected_btn) { + lv_obj_add_style(s_ui_language.selected_btn, btn_style_unchecked, 0); + } + if ( s_ui_language.selected_btn && s_ui_language.selected_btn != s_ui_language.selected_btn ) + { + lv_obj_add_style(s_ui_language.selected_btn, btn_style_unchecked, 0); + } + // 设置当前按钮样式为选中 + lv_obj_remove_style(btn, btn_style_checked, 0); + lv_obj_add_style(btn, btn_style_checked, 0); + s_ui_language.selected_btn = btn; + + } +} + +// 重置语言选择状态 +void reset_language_selection(void) +{ + lv_style_t *btn_style_checked = ioc_style_mngr_get_style("language_checked"); + lv_style_t *btn_style_unchecked = ioc_style_mngr_get_style("language_unchecked"); + + // 重置所有按钮样式为未选中 + for (int i = 0; i < s_ui_language.lang_count; i++) { + lv_obj_add_style(s_ui_language.lang_buttons[i].btn_obj, btn_style_unchecked, 0); + } + + // 重新设置当前语言的选中状态 + const char *cur_locale = current_lang_point->locale_name; + for (int i = 0; i < s_ui_language.lang_count; i++) { + if (strcmp(s_ui_language.lang_buttons[i].info.locale, cur_locale) == 0) { + lv_obj_remove_style(s_ui_language.lang_buttons[i].btn_obj, btn_style_checked, 0); + lv_obj_add_style(s_ui_language.lang_buttons[i].btn_obj, btn_style_checked, 0); + s_ui_language.selected_locale = s_ui_language.lang_buttons[i].info.locale; + s_ui_language.selected_btn = s_ui_language.lang_buttons[i].btn_obj; + break; + } + } +} + +void ui_language_update_selected(const char *str); +static void languages_btn_event_cb(lv_event_t *e) +{ + + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + lv_obj_t *btn = lv_event_get_target(e); + lang_info_t *info = (lang_info_t *)lv_event_get_user_data(e); + language_set_style(btn); + if (info) { + s_ui_language.selected_locale = info->locale; + s_ui_language.check_language = true; + LV_LOG_WARN("Language selection: locale=%s, label=%s, filename=%s\n", + info->locale, info->label, info->filename); + } + } +} + + +lv_obj_t *create_language_button(lv_obj_t *parent, const lang_info_t *info, lv_coord_t x, lv_coord_t y) { + lv_style_t *btn_style = ioc_style_mngr_get_style("style-shortcut_button_pre_authorization"); + + // 创建按钮 + lv_obj_t *btn = lv_btn_create(parent); + lv_obj_set_pos(btn, x, y); + lv_obj_set_size(btn, 180, 40); + lv_obj_add_style(btn, btn_style, 0); + lv_obj_add_event_cb(btn, languages_btn_event_cb, LV_EVENT_CLICKED, (void *)info); + + // 创建内部容器(用于水平排列图标和文字) + lv_obj_t *container = lv_obj_create(btn); + lv_obj_remove_style_all(container); + lv_obj_clear_flag(container, LV_OBJ_FLAG_CLICKABLE); // 防止拦截按钮点击事件 + lv_obj_set_size(container, LV_SIZE_CONTENT, LV_SIZE_CONTENT); + lv_obj_center(container); + + lv_obj_set_layout(container, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(container, LV_FLEX_FLOW_ROW); + lv_obj_set_flex_align(container, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + lv_obj_set_style_pad_column(container, 10, 0); + + // 图标 + if (info->icon[0]) { + lv_obj_t *img = lv_img_create(container); + lv_img_set_src(img, info->icon); + lv_obj_align(img, LV_ALIGN_CENTER, 0, 0); + } + + // 标签文字 + lv_obj_t *label_obj = lv_label_create(container); + ioc_label_set_text(label_obj, info->label); + lv_style_t *label_style = ioc_style_mngr_get_style("style-connector-quad-default-type-text"); + lv_obj_add_style(label_obj, label_style, 0); + + return btn; +} + +int parse_language_json(const char *json_path, char *out_label, size_t label_size, char *out_icon, size_t icon_size) { + FILE *f = fopen(json_path, "r"); + if (!f) return -1; + + fseek(f, 0, SEEK_END); + long len = ftell(f); + rewind(f); + + char *data = malloc(len + 1); + fread(data, 1, len, f); + data[len] = '\0'; + fclose(f); + + cJSON *root = cJSON_Parse(data); + free(data); + if (!root) return -1; + + const cJSON *label = cJSON_GetObjectItemCaseSensitive(root, "label"); + const cJSON *icon = cJSON_GetObjectItemCaseSensitive(root, "icon"); + + if (cJSON_IsString(label) && label->valuestring) + strncpy(out_label, label->valuestring, label_size); + + if (cJSON_IsString(icon) && icon->valuestring) + strncpy(out_icon, icon->valuestring, icon_size); + + cJSON_Delete(root); + return 0; +} + +void load_language_buttons(lv_obj_t *parent) { + const char *folder = LANGUAGE_IMG_PATH; + DIR *d = opendir(folder); + if (!d) { + perror("opendir"); + return; + } + static lang_button_t lang_buttons[MAX_LANGUAGES]; // 存放语言按钮及信息 + struct dirent *entry; + s_ui_language.lang_count = 0; + + // 读取 JSON 信息到 lang_buttons[i].info + while ((entry = readdir(d)) != NULL && s_ui_language.lang_count < MAX_LANGUAGES) { + if (!strstr(entry->d_name, ".json")) continue; + + char path[512]; + snprintf(path, sizeof(path), "%s/%s", folder, entry->d_name); + + lang_button_t *btn = &lang_buttons[s_ui_language.lang_count]; + + if (parse_language_json(path, + btn->info.label, sizeof(btn->info.label), + btn->info.icon, sizeof(btn->info.icon)) == 0) { + strncpy(btn->info.filename, entry->d_name, sizeof(btn->info.filename)); + // 可选:从 filename 中提取 locale,如 "en.json" -> "en" + strncpy(btn->info.locale, entry->d_name, sizeof(btn->info.locale)); + char *dot = strrchr(btn->info.locale, '.'); + if (dot) *dot = '\0'; // 去掉 .json + + s_ui_language.lang_count++; + } + } + closedir(d); + + // 按 label 排序 + qsort(lang_buttons, s_ui_language.lang_count, sizeof(lang_button_t), compare_lang_label); + + // 生成按钮并保存 lv_obj_t* + const lv_coord_t base_x[3] = {40, 240, 440}; + const lv_coord_t base_y = 85; + const lv_coord_t row_spacing = 60; + + for (int i = 0; i < s_ui_language.lang_count; i++) { + int row = i / 3; + int col = i % 3; + + lv_coord_t x = base_x[col]; + lv_coord_t y = base_y + row * row_spacing; + lang_buttons[i].btn_obj = create_language_button(parent, &lang_buttons[i].info, x, y); + } + + // 保存到 UI 状态 + s_ui_language.lang_buttons = lang_buttons; +} + +// 显示语言选择页面 +void ui_popup_show_language(void) +{ + ui_popup_show_mask(true); // 显示遮罩层 + static int execute = 0; + if (s_ui_language.language == NULL) + { + s_ui_language.language = ioc_layout_mngr_load_layout("language", lv_layer_top()); + } + + if (s_ui_language.language != NULL) + { + lv_obj_clear_flag(s_ui_language.language, LV_OBJ_FLAG_HIDDEN); + } + if ( execute == 0 ) { + load_language_buttons(s_ui_language.language); + execute = 1; + } + ioc_label_set_text(s_ui_language.close_text, "Close"); + ioc_label_set_text(s_ui_language.confirm_text, "Confirm"); + ioc_label_set_text(s_ui_language.language_label, "Language"); +} + +static void ui_language_close_btn_event_cb(lv_event_t * e) +{ + s_ui_language.confirm_language = false; + + // 重置语言选择状态 + reset_language_selection(); + + lv_obj_add_flag(s_ui_language.language, LV_OBJ_FLAG_HIDDEN); + ui_popup_show_mask(false); // 关闭遮罩层 +} + +static void ui_language_confirm_btn_event_cb(lv_event_t * e) +{ + // 如果用户确实选了语言,则应用它 + if (s_ui_language.check_language && s_ui_language.selected_locale) { + if (set_current_language_by_locale(s_ui_language.selected_locale)) { + printf("Language confirmation: Switch to %s\n", s_ui_language.selected_locale); + ui_language_update_selected(s_ui_language.selected_locale); + } + } + + // 关闭语言选择界面 + lv_obj_add_flag(s_ui_language.language, LV_OBJ_FLAG_HIDDEN); + ui_popup_show_mask(false); +} + +void language_page_init(void) +{ + s_ui_language.confirm_language = true; + ui_popup_show_language(); + lv_obj_add_flag(s_ui_language.language, LV_OBJ_FLAG_HIDDEN); + ui_popup_show_mask(false); +} + +void ui_after_create_language_close_btn(const char * name, lv_obj_t * obj) +{ + s_ui_language.close_btn = obj; + lv_obj_add_event_cb(s_ui_language.close_btn, ui_language_close_btn_event_cb, LV_EVENT_CLICKED, NULL); +} + +void ui_after_create_language_confirm_btn(const char * name, lv_obj_t * obj) +{ + s_ui_language.confirm_btn = obj; + lv_obj_add_event_cb(s_ui_language.confirm_btn, ui_language_confirm_btn_event_cb, LV_EVENT_CLICKED, NULL); +} + +void ui_after_create_language_close_text(const char * name, lv_obj_t * obj) +{ + s_ui_language.close_text = obj; +} + +void ui_after_create_language_confirm_text(const char * name, lv_obj_t * obj) +{ + s_ui_language.confirm_text = obj; +} + +void ui_after_create_language_label(const char * name, lv_obj_t * obj) +{ + s_ui_language.language_label = obj; +} + +void ui_after_create_language(const char * name, lv_obj_t * obj) +{ + const char * language_name = name + strlen(UI_NAME_LANGUAGE); + if (strcmp(language_name, UI_NAME_LANGUAGE_CLOSE_BTN) == 0) + { + ui_after_create_language_close_btn(name, obj); + } + else if (strcmp(language_name, UI_NAME_LANGUAGE_CONFIRM_BTN) == 0) + { + ui_after_create_language_confirm_btn(name, obj); + } + else if (strcmp(language_name, UI_NAME_LANGUAGE_CLOSE_TEXT) == 0) + { + ui_after_create_language_close_text(name, obj); + } + else if (strcmp(language_name, UI_NAME_LANGUAGE_CONFIRM_TEXT) == 0) + { + ui_after_create_language_confirm_text(name, obj); + } + else if (strcmp(language_name, UI_NAME_LANGUAGE_LABEL) == 0) + { + ui_after_create_language_label(name, obj); + } +} + +// 用于国际化(i18n),将 JSON 文件中定义的语言内容读取进 lv_i18n_lang_t 结构体中,用于 LVGL 界面多语言切换。 +void parse_all_lang_jsons(void) { + const char *dir_path = LANGUAGE_IMG_PATH; + DIR *dir = opendir(dir_path); + if (!dir) { + perror("Failed to open i18n directory"); + return; + } + + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + // 跳过不是 .json 文件 + if (!strstr(entry->d_name, ".json")) continue; + + // 构建完整文件路径 + char filepath[512]; + snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, entry->d_name); + + // 打开并读取文件内容 + FILE *fp = fopen(filepath, "r"); + if (!fp) { + perror("File open failed"); + continue; + } + + fseek(fp, 0, SEEK_END); + long size = ftell(fp); + rewind(fp); + + char *json_buf = (char *)malloc(size + 1); + if (!json_buf) { + fclose(fp); + LV_LOG_WARN("Memory allocation failed\n"); + continue; + } + + fread(json_buf, 1, size, fp); + json_buf[size] = '\0'; + fclose(fp); + + cJSON *root = cJSON_Parse(json_buf); + if (!root) { + LV_LOG_WARN("JSON Parse Error in %s: %s\n", filepath, cJSON_GetErrorPtr()); + free(json_buf); + continue; + } + + cJSON *name = cJSON_GetObjectItem(root, "name"); + + if (!cJSON_IsString(name)) { + LV_LOG_WARN("Invalid name field in %s\n", filepath); + cJSON_Delete(root); + free(json_buf); + continue; + } + + const char *lang_prefix = name->valuestring; + // LV_LOG_WARN("lang_prefix:%s\n",lang_prefix); + lv_i18n_lang_t *target_lang = NULL; + + for (int i = 0; lv_i18n_language_pack[i] != NULL; i++) { + // LV_LOG_WARN("lv_i18n_language_pack[%d]->locale_name:%s\n",i,lv_i18n_language_pack[i]->locale_name); + if (strncmp(lv_i18n_language_pack[i]->locale_name, lang_prefix, 2) == 0) { + target_lang = (lv_i18n_lang_t *)lv_i18n_language_pack[i]; + // LV_LOG_WARN("target_lang->locale_name:%s\n",target_lang->locale_name); + break; + } + } + + if (!target_lang) { + LV_LOG_WARN("No matching language or singulars array is NULL for: %s\n", lang_prefix); + cJSON_Delete(root); + free(json_buf); + continue; + } + + cJSON *content = cJSON_GetObjectItem(root, "content"); + if (!cJSON_IsArray(content)) { + LV_LOG_WARN("Invalid content field in %s\n", filepath); + cJSON_Delete(root); + free(json_buf); + continue; + } + + int count = cJSON_GetArraySize(content); + if (target_lang->singulars == NULL) + { + target_lang->singulars = calloc(count + 1, sizeof(lv_i18n_phrase_t)); + } + for (int i = 0; i < count; i++) { + cJSON *item = cJSON_GetArrayItem(content, i); + if (!cJSON_IsObject(item)) continue; + + cJSON *msg_id = cJSON_GetObjectItem(item, "name"); + cJSON *translation = cJSON_GetObjectItem(item, "value"); + + if (cJSON_IsString(msg_id) && cJSON_IsString(translation)) { + target_lang->singulars[i].msg_id = strdup(msg_id->valuestring); + target_lang->singulars[i].translation = strdup(translation->valuestring); + } + } + + target_lang->singulars[count].msg_id = NULL; + target_lang->singulars[count].translation = NULL; + + cJSON_Delete(root); + free(json_buf); + } + + closedir(dir); +} + + +void ui_language_update_selected(const char *str) +{ + if ( !s_ui_language.lang_buttons || !str ) return; + for (int i = 0; i < s_ui_language.lang_count; i++) { + if ( strcmp(s_ui_language.lang_buttons[i].info.locale, str) == 0 ) + { + language_set_style(s_ui_language.lang_buttons[i].btn_obj); + lv_img_set_src(ui_status_bar.lang_icon, s_ui_language.lang_buttons[i].info.icon); + ioc_label_set_text(ui_status_bar.lang_label, s_ui_language.lang_buttons[i].info.label); + } + } +} diff --git a/pages/ui_popup_language.h b/pages/ui_popup_language.h new file mode 100644 index 000000000..a4af1d20b --- /dev/null +++ b/pages/ui_popup_language.h @@ -0,0 +1,48 @@ +#ifndef __UI_POPUP_LANGUAGE_H__ +#define __UI_POPUP_LANGUAGE_H__ + +#include "lvgl.h" + +#define UI_NAME_LANGUAGE "language" +void ui_after_create_language(const char * name, lv_obj_t * obj); + +// 显示语言选择页面 +void ui_popup_show_language(void); + +void parse_all_lang_jsons(void); +void print_translations(const lv_i18n_lang_t *lang); + +#define LANGUAGE_SIZE 255 + +typedef struct { + char locale[32]; // 语言代码,如 "en-US" + char label[64]; // 展示标签,如 "English" + char icon[128]; // 图标路径 + char filename[128]; // 原始 JSON 文件名,便于定位 +} lang_info_t; + +typedef struct { + lang_info_t info; + lv_obj_t *btn_obj; // 按钮对象 +} lang_button_t; +typedef struct +{ + lv_obj_t * language; // 语言选择页面 + + lv_obj_t * close_btn; // 关闭按钮 + lv_obj_t * confirm_btn; // 确认按钮 + lv_obj_t * close_text; // 关闭按钮文本 + lv_obj_t * confirm_text; // 确认按钮文本 + lv_obj_t * language_label; // 语言文本 + int lang_count; // 语言按钮个数 + lang_button_t *lang_buttons; // 指向语言按钮数组 + bool check_language; // 选择语言 + bool confirm_language; // 选择语言 + char *selected_locale; + lv_obj_t * selected_btn; +} ui_language_t; + +extern ui_language_t s_ui_language; +void ui_language_update_selected(const char *str); +void language_page_init(void); +#endif diff --git a/pages/ui_popup_preauthorization.c b/pages/ui_popup_preauthorization.c new file mode 100644 index 000000000..0c8b497b3 --- /dev/null +++ b/pages/ui_popup_preauthorization.c @@ -0,0 +1,333 @@ +#include "../pages_mngr.h" + +#define UI_NAME_PREAUTH_TOTAL_AMOUNT ".pre_auth_val" +#define UI_NAME_PREAUTH_ENTER_AMOUNT ".pre_auth_title" +#define UI_NAME_PREAUTH_CLOSE_TEXT ".pre_auth_close_button.btn_label" +#define UI_NAME_PREAUTH_CONFIM_TEXT ".pre_auth_confirm_button.btn_label" +#define UI_NAME_PREAUTH_CURRRENCY ".pre_amounut_currency" + + +#define UI_NAME_PREAUTH_CLOSE_BTN ".pre_auth_close_button" +#define UI_NAME_PREAUTH_CONFIM_BTN ".pre_auth_confirm_button" +#define UI_NAME_PREAUTH_NUM0 ".num0" +#define UI_NAME_PREAUTH_NUM1 ".num1" +#define UI_NAME_PREAUTH_NUM2 ".num2" +#define UI_NAME_PREAUTH_NUM3 ".num3" +#define UI_NAME_PREAUTH_NUM4 ".num4" +#define UI_NAME_PREAUTH_NUM5 ".num5" +#define UI_NAME_PREAUTH_NUM6 ".num6" +#define UI_NAME_PREAUTH_NUM7 ".num7" +#define UI_NAME_PREAUTH_NUM8 ".num8" +#define UI_NAME_PREAUTH_NUM9 ".num9" +#define UI_NAME_PREAUTH_NUM10 ".num10" +#define UI_NAME_PREAUTH_NUM50 ".num50" +#define UI_NAME_PREAUTH_NUM100 ".num100" +#define UI_NAME_PREAUTH_CHAR_DROP ".char_drop" +#define UI_NAME_PREAUTH_CHAR_DELETE ".char_delete" + +#define UI_NAME_PREAUTH_NUM0_TEXT ".num0.text" +#define UI_NAME_PREAUTH_NUM1_TEXT ".num1.text" +#define UI_NAME_PREAUTH_NUM2_TEXT ".num2.text" +#define UI_NAME_PREAUTH_NUM3_TEXT ".num3.text" +#define UI_NAME_PREAUTH_NUM4_TEXT ".num4.text" +#define UI_NAME_PREAUTH_NUM5_TEXT ".num5.text" +#define UI_NAME_PREAUTH_NUM6_TEXT ".num6.text" +#define UI_NAME_PREAUTH_NUM7_TEXT ".num7.text" +#define UI_NAME_PREAUTH_NUM8_TEXT ".num8.text" +#define UI_NAME_PREAUTH_NUM9_TEXT ".num9.text" +#define UI_NAME_PREAUTH_CHAR_DROP_TEXT ".char_drop.text" + +typedef enum { + NUM0, + NUM1, + NUM2, + NUM3, + NUM4, + NUM5, + NUM6, + NUM7, + NUM8, + NUM9, + CHAR_DROP, + CHAR_DELETE, + + NUM10, + NUM50, + NUM100, + CLOSE_BTN, + CONFIRM_BTN, + + NUMBER +}preauth_key_e; + +typedef struct { + + lv_obj_t * obj; + lv_obj_t * amount; + + lv_obj_t * enter_amount_label; + lv_obj_t * close_text; + lv_obj_t * confirm_text; + lv_obj_t * currency; + + lv_obj_t * key[NUMBER]; + lv_obj_t * key_text[NUMBER]; + +}pre_authorization_t; + +pre_authorization_t pre_authorization; + +// 弹出预授权提示框, 用户输入完毕确认后直接发送预授权请求给ui_json, 调用界面不需要处理预授权金额 +void ui_popup_show_preauthorization(int idx) +{ + ui_popup_show_mask(true); // 显示遮罩层 + + if ( pre_authorization.obj == NULL ) { + pre_authorization.obj = ioc_layout_mngr_load_layout("pre_authorization", lv_layer_top()); + } + + if ( pre_authorization.obj != NULL ) { + lv_obj_clear_flag(pre_authorization.obj, LV_OBJ_FLAG_HIDDEN); + } + + ioc_label_set_text(pre_authorization.enter_amount_label, "Please_enter_the_amount"); + ioc_label_set_text(pre_authorization.close_text, "Close"); + ioc_label_set_text(pre_authorization.confirm_text, "Confirm"); + ioc_label_set_text(pre_authorization.currency, g_ui_json.currencyCode); +} + + +typedef struct { + const char *suffix; + lv_obj_t **obj; +} ui_preauth_obj_map_entry_t; + +static ui_preauth_obj_map_entry_t obj_map[] = { + { UI_NAME_PREAUTH_TOTAL_AMOUNT, &pre_authorization.amount }, + { UI_NAME_PREAUTH_ENTER_AMOUNT, &pre_authorization.enter_amount_label }, + { UI_NAME_PREAUTH_CLOSE_TEXT, &pre_authorization.close_text }, + { UI_NAME_PREAUTH_CONFIM_TEXT, &pre_authorization.confirm_text }, + { UI_NAME_PREAUTH_CURRRENCY, &pre_authorization.currency }, + + { UI_NAME_PREAUTH_CLOSE_BTN, &pre_authorization.key[CLOSE_BTN] }, + { UI_NAME_PREAUTH_CONFIM_BTN, &pre_authorization.key[CONFIRM_BTN] }, + { UI_NAME_PREAUTH_NUM0, &pre_authorization.key[NUM0] }, + { UI_NAME_PREAUTH_NUM1, &pre_authorization.key[NUM1] }, + { UI_NAME_PREAUTH_NUM2, &pre_authorization.key[NUM2] }, + { UI_NAME_PREAUTH_NUM3, &pre_authorization.key[NUM3] }, + { UI_NAME_PREAUTH_NUM4, &pre_authorization.key[NUM4] }, + { UI_NAME_PREAUTH_NUM5, &pre_authorization.key[NUM5] }, + { UI_NAME_PREAUTH_NUM6, &pre_authorization.key[NUM6] }, + { UI_NAME_PREAUTH_NUM7, &pre_authorization.key[NUM7] }, + { UI_NAME_PREAUTH_NUM8, &pre_authorization.key[NUM8] }, + { UI_NAME_PREAUTH_NUM9, &pre_authorization.key[NUM9] }, + { UI_NAME_PREAUTH_NUM10, &pre_authorization.key[NUM10] }, + { UI_NAME_PREAUTH_NUM50, &pre_authorization.key[NUM50] }, + { UI_NAME_PREAUTH_NUM100, &pre_authorization.key[NUM100] }, + { UI_NAME_PREAUTH_CHAR_DROP, &pre_authorization.key[CHAR_DROP] }, + { UI_NAME_PREAUTH_CHAR_DELETE, &pre_authorization.key[CHAR_DELETE] }, + { UI_NAME_PREAUTH_NUM0_TEXT, &pre_authorization.key_text[NUM0] }, + { UI_NAME_PREAUTH_NUM1_TEXT, &pre_authorization.key_text[NUM1] }, + { UI_NAME_PREAUTH_NUM2_TEXT, &pre_authorization.key_text[NUM2] }, + { UI_NAME_PREAUTH_NUM3_TEXT, &pre_authorization.key_text[NUM3] }, + { UI_NAME_PREAUTH_NUM4_TEXT, &pre_authorization.key_text[NUM4] }, + { UI_NAME_PREAUTH_NUM5_TEXT, &pre_authorization.key_text[NUM5] }, + { UI_NAME_PREAUTH_NUM6_TEXT, &pre_authorization.key_text[NUM6] }, + { UI_NAME_PREAUTH_NUM7_TEXT, &pre_authorization.key_text[NUM7] }, + { UI_NAME_PREAUTH_NUM8_TEXT, &pre_authorization.key_text[NUM8] }, + { UI_NAME_PREAUTH_NUM9_TEXT, &pre_authorization.key_text[NUM9] }, + { UI_NAME_PREAUTH_CHAR_DROP_TEXT, &pre_authorization.key_text[CHAR_DROP] }, +}; + +typedef struct { + const char *name; + const char *text; +} keypad_text_map_t; + +static const keypad_text_map_t keypad_map[] = { + { UI_NAME_PREAUTH_NUM0_TEXT, "0" }, + { UI_NAME_PREAUTH_NUM1_TEXT, "1" }, + { UI_NAME_PREAUTH_NUM2_TEXT, "2" }, + { UI_NAME_PREAUTH_NUM3_TEXT, "3" }, + { UI_NAME_PREAUTH_NUM4_TEXT, "4" }, + { UI_NAME_PREAUTH_NUM5_TEXT, "5" }, + { UI_NAME_PREAUTH_NUM6_TEXT, "6" }, + { UI_NAME_PREAUTH_NUM7_TEXT, "7" }, + { UI_NAME_PREAUTH_NUM8_TEXT, "8" }, + { UI_NAME_PREAUTH_NUM9_TEXT, "9" }, + { UI_NAME_PREAUTH_CHAR_DROP_TEXT, "." }, +}; + +static void preauth_keypad_event_cb(lv_event_t *e); +void ui_after_create_preauthorization(const char * name, lv_obj_t * obj) +{ + size_t prefix_len = strlen(UI_NAME_PRE_AUTHORIZATION); + + if (strncmp(name, UI_NAME_PRE_AUTHORIZATION, prefix_len) != 0) + { + LV_LOG_WARN("name[%s] does not start with prefix[%s], ignore.", name, UI_NAME_PRE_AUTHORIZATION); + return; + } + + const char * preauth_name = name + strlen(UI_NAME_PRE_AUTHORIZATION); + + LV_LOG_WARN("name[%s], preauth_name[%s]", name, preauth_name); + + for (size_t i = 0; i < sizeof(obj_map) / sizeof(obj_map[0]); ++i) { + if (strcmp(preauth_name, obj_map[i].suffix) == 0) { + *(obj_map[i].obj) = obj; + + if ( + strcmp(preauth_name, UI_NAME_PREAUTH_ENTER_AMOUNT) != 0 && + strcmp(preauth_name, UI_NAME_PREAUTH_CLOSE_TEXT) != 0 && + strcmp(preauth_name, UI_NAME_PREAUTH_CONFIM_TEXT) != 0 && + strcmp(preauth_name, UI_NAME_PREAUTH_TOTAL_AMOUNT) != 0 && + strcmp(preauth_name, UI_NAME_PREAUTH_CURRRENCY) != 0 + ) { + lv_obj_add_event_cb(obj, preauth_keypad_event_cb, LV_EVENT_CLICKED, (void*)obj_map[i].suffix); + } + + // 键盘数组用统一的fragment,不好在json里设置文本,所以在此处用 + for (size_t j = 0; j < sizeof(keypad_map) / sizeof(keypad_map[0]); j++) + { + if (strcmp(preauth_name, keypad_map[j].name) == 0) + { + ioc_label_set_text(obj, keypad_map[j].text); + break; + } + } + + return; + } + } +} + +static void preauth_keypad_event_cb(lv_event_t *e) +{ + lv_event_code_t code = lv_event_get_code(e); + lv_obj_t *amount_label = pre_authorization.amount; + const char *current_text = lv_label_get_text(amount_label); + char new_text[14]; + snprintf(new_text, sizeof(new_text), "%s", current_text); + + const char * suffix = (const char *)lv_event_get_user_data(e); + if (code == LV_EVENT_CLICKED) { + + // 处理不同按钮的点击事件 + if (strcmp(suffix, UI_NAME_PREAUTH_NUM10) == 0) { + snprintf(new_text, sizeof(new_text), "%s", "10"); + } + else if (strcmp(suffix, UI_NAME_PREAUTH_NUM50) == 0) { + snprintf(new_text, sizeof(new_text), "%s", "50"); + } + else if (strcmp(suffix, UI_NAME_PREAUTH_NUM100) == 0) { + snprintf(new_text, sizeof(new_text), "%s", "100"); + } + else if (strcmp(suffix, UI_NAME_PREAUTH_NUM1) == 0) { + if (strcmp(current_text, "0") == 0) { + snprintf(new_text, sizeof(new_text), "%s", "1"); + } + else { + snprintf(new_text, sizeof(new_text), "%s%s", current_text, "1"); + } + } + else if (strcmp(suffix, UI_NAME_PREAUTH_NUM2) == 0) { + if (strcmp(current_text, "0") == 0) { + snprintf(new_text, sizeof(new_text), "%s", "2"); + } + else { + snprintf(new_text, sizeof(new_text), "%s%s", current_text, "2"); + } + } + else if (strcmp(suffix, UI_NAME_PREAUTH_NUM3) == 0) { + if (strcmp(current_text, "0") == 0) { + snprintf(new_text, sizeof(new_text), "%s", "3"); + } + else { + snprintf(new_text, sizeof(new_text), "%s%s", current_text, "3"); + } + } + else if (strcmp(suffix, UI_NAME_PREAUTH_NUM4) == 0) { + if (strcmp(current_text, "0") == 0) { + snprintf(new_text, sizeof(new_text), "%s", "4"); + } + else { + snprintf(new_text, sizeof(new_text), "%s%s", current_text, "4"); + } + } + else if (strcmp(suffix, UI_NAME_PREAUTH_NUM5) == 0) { + if (strcmp(current_text, "0") == 0) { + snprintf(new_text, sizeof(new_text), "%s", "5"); + } + else { + snprintf(new_text, sizeof(new_text), "%s%s", current_text, "5"); + } + } + else if (strcmp(suffix, UI_NAME_PREAUTH_NUM6) == 0) { + if (strcmp(current_text, "0") == 0) { + snprintf(new_text, sizeof(new_text), "%s", "6"); + } + else { + snprintf(new_text, sizeof(new_text), "%s%s", current_text, "6"); + } + } + else if (strcmp(suffix, UI_NAME_PREAUTH_NUM7) == 0) { + if (strcmp(current_text, "0") == 0) { + snprintf(new_text, sizeof(new_text), "%s", "7"); + } + else { + snprintf(new_text, sizeof(new_text), "%s%s", current_text, "7"); + } + } + else if (strcmp(suffix, UI_NAME_PREAUTH_NUM8) == 0) { + if (strcmp(current_text, "0") == 0) { + snprintf(new_text, sizeof(new_text), "%s", "8"); + } + else { + snprintf(new_text, sizeof(new_text), "%s%s", current_text, "8"); + } + } + else if (strcmp(suffix, UI_NAME_PREAUTH_NUM9) == 0) { + if (strcmp(current_text, "0") == 0) { + snprintf(new_text, sizeof(new_text), "%s", "9"); + } + else { + snprintf(new_text, sizeof(new_text), "%s%s", current_text, "9"); + } + } + else if (strcmp(suffix, UI_NAME_PREAUTH_CHAR_DROP) == 0) { + snprintf(new_text, sizeof(new_text), "%s%s", current_text, "."); + } + else if (strcmp(suffix, UI_NAME_PREAUTH_NUM0) == 0) { + if (strcmp(current_text, "0") == 0) { + snprintf(new_text, sizeof(new_text), "%s", "0"); + } + else { + snprintf(new_text, sizeof(new_text), "%s%s", current_text, "0"); + } + } + else if (strcmp(suffix, UI_NAME_PREAUTH_CHAR_DELETE) == 0) { + if (strlen(new_text) > 1) { + new_text[strlen(new_text) - 1] = '\0'; + } else { + new_text[0] = '\0'; + snprintf(new_text, sizeof(new_text), "0"); + } + } + else if (strcmp(suffix, UI_NAME_PREAUTH_CLOSE_BTN) == 0) { + lv_obj_add_flag(pre_authorization.obj, LV_OBJ_FLAG_HIDDEN); + ui_popup_show_mask(false); + } + else if (strcmp(suffix, UI_NAME_PREAUTH_CONFIM_BTN) == 0) { + // TODO UI 发送金额 + lv_obj_add_flag(pre_authorization.obj, LV_OBJ_FLAG_HIDDEN); + ui_popup_show_mask(false); + if ( g_ui_json.enSoftKey == true ) + { + int amount = atoi(lv_label_get_text(pre_authorization.amount)) * 100; + ioc_send_UseCreditCard(UI_CONNECTOR_ACTIVE_IDX, amount); + } + } + ioc_label_set_text(amount_label, new_text); + } +} diff --git a/pages/ui_popup_preauthorization.h b/pages/ui_popup_preauthorization.h new file mode 100644 index 000000000..0bd5e96a6 --- /dev/null +++ b/pages/ui_popup_preauthorization.h @@ -0,0 +1,14 @@ +#ifndef __UI_POPUP_PREAUTHORIZATION_H__ +#define __UI_POPUP_PREAUTHORIZATION_H__ + + +#include "lvgl.h" + +#define UI_NAME_PRE_AUTHORIZATION "pre_authorization" + +// 弹出预授权提示框, 用户输入完毕确认后直接发送预授权请求给ui_json, 调用界面不需要处理预授权金额 +void ui_popup_show_preauthorization(int idx); + +void ui_after_create_preauthorization(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_price_charging.c b/pages/ui_price_charging.c new file mode 100644 index 000000000..44d65d2b2 --- /dev/null +++ b/pages/ui_price_charging.c @@ -0,0 +1,256 @@ +#include "../pages_mngr.h" + +#define UI_CHARGING_DATA g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.charging +#define UI_CHARGING_SHOWE_PRICE g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].showPrice + +#define UI_NAME_PRICE_CHARGING_PRICE_KWH ".price_charging_current_rate.price_kwh" +#define UI_NAME_PRICE_CHARGING_PRICE_HR ".price_charging_current_rate.price_hr" +#define UI_NAME_PRICE_CHARGING_PRICE_TIMES ".price_charging_current_rate.price_times" + +#define UI_NAME_PRICE_CHARGING_COST_LABEL ".cost_charging_title" +#define UI_NAME_PRICE_CHARGING_COST ".cost_charging_val" + +#define UI_NAME_PRICE_CHARGING_BTN ".detaile_btn" +#define UI_NAME_PRICE_CHARGING_BTN_LABEL ".detaile_btn.label" + + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * price_kwh; + lv_obj_t * price_hr; + lv_obj_t * price_times; + lv_obj_t * cost; + lv_obj_t * estimated_cost; + + lv_obj_t * btn; + lv_obj_t * btn_label; + +} ui_page_price_charging_t; + +static ui_page_price_charging_t s_ui_page_price_charging = {NULL}; +static lv_timer_t * charging_timer = NULL; +static void ui_page_price_charging_show_price(bool is_show) +{ + lv_obj_t * objs[] = { + s_ui_page_price_charging.price_kwh, + s_ui_page_price_charging.price_hr, + s_ui_page_price_charging.price_times, + s_ui_page_price_charging.cost, + s_ui_page_price_charging.estimated_cost, + s_ui_page_price_charging.btn, + s_ui_page_price_charging.btn_label, + }; + + for (uint32_t i = 0; i < sizeof(objs) / sizeof(objs[0]); i++) + { + if (objs[i] == NULL) continue; + if (is_show) lv_obj_clear_flag(objs[i], LV_OBJ_FLAG_HIDDEN); + else lv_obj_add_flag(objs[i], LV_OBJ_FLAG_HIDDEN); + } +} +static int s_charging_show_price_flag = -1; // -1:未收到UI.jison时的初始值 0:不显示价格 1:显示价格 + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static void ui_page_price_charging_updatejson(struct ioc_obj_user_data_s * user_data) +{ + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + + char buf[64] = {0}; + + // 价格相关 + if(UI_CHARGING_SHOWE_PRICE) + { + if(s_charging_show_price_flag != 1) + { + ui_page_price_charging_show_price(true); + s_charging_show_price_flag = 1; + } + + // 根据costPriceDecimalPlaces判断保留几位小数 + char fmt[16]; + snprintf(fmt, sizeof(fmt), "%%.%df", g_ui_json.costPriceDecimalPlaces); + + if (s_ui_page_price_charging.price_kwh != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_CHARGING_DATA.currPrice.kWhPrice); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + strncat(buf, "/kWh", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(s_ui_page_price_charging.price_kwh, buf); + } + if (s_ui_page_price_charging.price_hr != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_CHARGING_DATA.currPrice.hourPrice); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + strncat(buf, "/hr", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(s_ui_page_price_charging.price_hr, buf); + } + if (s_ui_page_price_charging.price_times != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_CHARGING_DATA.currPrice.flatFee); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + strncat(buf, "/times", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(s_ui_page_price_charging.price_times, buf); + } + if (s_ui_page_price_charging.cost != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_CHARGING_DATA.cost.totalCost); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(s_ui_page_price_charging.cost, buf); + } + } + else + { + if(s_charging_show_price_flag != 0) + { + ui_page_price_charging_show_price(false); + s_charging_show_price_flag = 0; + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +lv_obj_t * ui_page_create_price_charging(lv_obj_t *parent) +{ + memset(&s_ui_page_price_charging, 0, sizeof(s_ui_page_price_charging)); + + s_ui_page_price_charging.page = ioc_layout_mngr_load_layout("price_charging", parent); + if (s_ui_page_price_charging.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(s_ui_page_price_charging.page); + user_data->ui_json_update_cb = ui_page_price_charging_updatejson; + } + + return s_ui_page_price_charging.page; +} + +void ui_page_show_price_charging(void) +{ + +} + +void ui_page_hide_price_charging(void) +{ + +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_after_create_price_charging_price_kwh(const char * name, lv_obj_t * obj) +{ + s_ui_page_price_charging.price_kwh = obj; +} +void ui_after_create_price_charging_price_hr(const char * name, lv_obj_t * obj) +{ + s_ui_page_price_charging.price_hr = obj; +} +void ui_after_create_price_charging_price_times(const char * name, lv_obj_t * obj) +{ + s_ui_page_price_charging.price_times = obj; +} +void ui_after_create_price_charging_cost(const char * name, lv_obj_t * obj) +{ + s_ui_page_price_charging.cost = obj; +} + +void ui_charging_update_estimated_cost(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(s_ui_page_price_charging.estimated_cost, "Estimated_Cost"); +} + +void ui_after_create_price_charging_estimated_cost(const char * name, lv_obj_t * obj) +{ + s_ui_page_price_charging.estimated_cost = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_charging_update_estimated_cost; +} + + +static void charging_detailed_data_event_cb(lv_event_t *e) +{ + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + ui_popup_show_charging_detail(0,0); + } +} + +void ui_after_create_price_charging_btn(const char * name, lv_obj_t * obj) +{ + s_ui_page_price_charging.btn = obj; + lv_obj_add_event_cb(obj, charging_detailed_data_event_cb, LV_EVENT_CLICKED, NULL); +} + +void ui_charging_update_btn_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(s_ui_page_price_charging.btn_label, "Detailed_data"); +} + +void ui_after_create_price_charging_btn_label(const char * name, lv_obj_t * obj) +{ + s_ui_page_price_charging.btn_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_charging_update_btn_label; +} + + + +static void charging_detailed_data_noprice_event_cb(lv_event_t *e) +{ + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + ui_popup_show_charging_detail(0,0); + } +} + +void ui_after_create_price_charging(const char * name, lv_obj_t * obj) +{ + const char * charging_name = name + strlen(UI_NAME_PRICE_CHARGING); + if (strcmp(charging_name, UI_NAME_PRICE_CHARGING_COST_LABEL) == 0) + { + ui_after_create_price_charging_estimated_cost(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_PRICE_CHARGING_BTN) == 0) + { + ui_after_create_price_charging_btn(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_PRICE_CHARGING_BTN_LABEL) == 0) + { + ui_after_create_price_charging_btn_label(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_PRICE_CHARGING_PRICE_KWH) == 0) + { + ui_after_create_price_charging_price_kwh(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_PRICE_CHARGING_PRICE_HR) == 0) + { + ui_after_create_price_charging_price_hr(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_PRICE_CHARGING_PRICE_TIMES) == 0) + { + ui_after_create_price_charging_price_times(name, obj); + return; + } + else if (strcmp(charging_name, UI_NAME_PRICE_CHARGING_COST) == 0) + { + ui_after_create_price_charging_cost(name, obj); + return; + } + + + return; +} diff --git a/pages/ui_price_charging.h b/pages/ui_price_charging.h new file mode 100644 index 000000000..3d27f0005 --- /dev/null +++ b/pages/ui_price_charging.h @@ -0,0 +1,15 @@ +#ifndef __UI_PAGE_PRICE_CHARGING_H__ +#define __UI_PAGE_PRICE_CHARGING_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_price_charging(lv_obj_t *parent); + +// void ui_page_show_price_charging(void); +// void ui_page_hide_price_charging(void); + + +#define UI_NAME_PRICE_CHARGING "main.price_charging" +void ui_after_create_price_charging(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_price_finished.c b/pages/ui_price_finished.c new file mode 100644 index 000000000..f9b4c8cbd --- /dev/null +++ b/pages/ui_price_finished.c @@ -0,0 +1,317 @@ +#include "../pages_mngr.h" + +#define UI_NAME_PRICE_FINISHED_IDLE_TIME "price_finished_time" +#define UI_NAME_PRICE_FINISHED_IDLE_TIME_LABEL "price_finished_title" +#define UI_NAME_PRICE_FINISHED_IDLE_TIME_PROMPT "price_finished_tip" +#define UI_NAME_PRICE_FINISHED_CHARGING_COST_LABEL "price_finished_charging_title" +#define UI_NAME_PRICE_FINISHED_IDLE_FEE_LABEL "price_finished_idle_title" +#define UI_NAME_PRICE_FINISHED_TOTAL_AMOUNT_LABEL "price_finished_total_title" +#define UI_NAME_PRICE_FINISHED_CHARGING_COST "price_finished_charging_val" +#define UI_NAME_PRICE_FINISHED_IDLE_FEE "price_finished_idle_val" +#define UI_NAME_PRICE_FINISHED_TOTAL_AMOUNT "price_finished_total_val" + + +#define UI_FINISHED_DATA g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.finished +#define UI_FINISHED_SHOWE_PRICE g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].showPrice + + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * idle_time; + lv_obj_t * charging_cost; + lv_obj_t * idle_fee; + lv_obj_t * total_amount; + + lv_obj_t * idle_time_label; + lv_obj_t * idle_time_prompt; + lv_obj_t * charging_cost_label; + lv_obj_t * idle_fee_label; + lv_obj_t * total_amount_label; + + +} ui_page_price_finished_t; + +static ui_page_price_finished_t ui_page_price_finished = {NULL}; +static lv_timer_t * s_finished_timer = NULL; +static int s_finished_show_price_flag = -1; // -1:未收到UI.jison时的初始值 0:不显示价格 1:显示价格 + + +static void ui_page_price_finished_time(lv_timer_t * temp) +{ + LV_UNUSED(temp); + + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + int show_hour = 0; + int show_min = 0; + int show_sec = 0; + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) + { + time_t current_time = time(NULL); + time_t diftimer = difftime(current_time, UI_FINISHED_DATA.stopTime); + + if (diftimer < 0) { + diftimer = 0; + } + + struct tm *tm = gmtime(&diftimer); + + + if (current_time >= UI_FINISHED_DATA.stopTime) { + show_hour = tm->tm_hour; + show_min = tm->tm_min; + show_sec = tm->tm_sec; + } + } + + if ( UI_CONNECTOR_STATE(UI_CONNECTOR_ACTIVE_IDX) == UI_CONNECTOR_STATE_FINISHED ) + { + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) + { + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", show_hour, show_min, show_sec); + ioc_label_set_text(ui_page_price_finished.idle_time, buf); + } + else + { + ioc_label_set_text(ui_page_price_finished.idle_time, ui_connector_get_text_time_value(UI_CONNECTOR_ACTIVE_IDX)); + } + } +} + +static void ui_page_06_finised_show_price(bool is_show) +{ + +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////// +static void ui_page_price_finished_updatejson(struct ioc_obj_user_data_s * user_data) +{ + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + + char buf[64] = {0}; + + + // 价格相关 + if(UI_FINISHED_SHOWE_PRICE) + { + if(s_finished_show_price_flag != 1) + { + ui_page_06_finised_show_price(true); + s_finished_show_price_flag = 1; + } + + + // 根据costPriceDecimalPlaces判断保留几位小数 + char fmt[16]; + snprintf(fmt, sizeof(fmt), "%%.%df", g_ui_json.costPriceDecimalPlaces); + + if (ui_page_price_finished.charging_cost != NULL) + { + memset(buf, 0x00, sizeof(buf)); + double chargingCost = 0; + if(UI_FINISHED_DATA.cost.totalCost > UI_FINISHED_DATA.cost.stopIdleCost) + { + chargingCost = UI_FINISHED_DATA.cost.totalCost - UI_FINISHED_DATA.cost.stopIdleCost; + } + snprintf(buf, sizeof(buf), fmt, chargingCost); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(ui_page_price_finished.charging_cost, buf); + } + if (ui_page_price_finished.idle_fee != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_FINISHED_DATA.cost.stopIdleCost); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(ui_page_price_finished.idle_fee, buf); + } + if (ui_page_price_finished.total_amount != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_FINISHED_DATA.cost.totalCost); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(ui_page_price_finished.total_amount, buf); + } + } + else + { + if(s_finished_show_price_flag != 0) + { + ui_page_06_finised_show_price(false); + s_finished_show_price_flag = 0; + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +lv_obj_t * ui_page_create_price_finished(lv_obj_t *parent) +{ + memset(&ui_page_price_finished, 0, sizeof(ui_page_price_finished)); + + ui_page_price_finished.page = ioc_layout_mngr_load_layout("finished", parent); + if (ui_page_price_finished.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(ui_page_price_finished.page); + user_data->ui_json_update_cb = ui_page_price_finished_updatejson; + } + + return ui_page_price_finished.page; +} + +void ui_page_show_price_finished(void) +{ + // 为了时间显示的流畅,占位时间由本地计算 + if(s_finished_timer == NULL) + { + s_finished_timer = lv_timer_create(ui_page_price_finished_time, 500, NULL); + } +} + +void ui_page_hide_price_finished(void) +{ + if (s_finished_timer!= NULL) + { + lv_timer_del(s_finished_timer); + s_finished_timer = NULL; + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", 0, 0, 0); + ioc_label_set_text(ui_page_price_finished.idle_time, buf); + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_finished_update_idle_time_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_price_finished.idle_time_label, "Idle_time"); +} + +void ui_after_create_price_finished_idle_time_label(const char * name, lv_obj_t * obj) +{ + ui_page_price_finished.idle_time_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_finished_update_idle_time_label; +} + +void ui_finished_update_idle_time_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_price_finished.idle_time_prompt, "Idle_time_prompt"); +} + +void ui_after_create_price_finished_idle_time_prompt(const char * name, lv_obj_t * obj) +{ + ui_page_price_finished.idle_time_prompt = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_finished_update_idle_time_prompt; +} + +void ui_finished_update_charging_cost_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_price_finished.charging_cost_label, "Charging_cost"); +} + +void ui_after_create_price_finished_charging_cost_label(const char * name, lv_obj_t * obj) +{ + ui_page_price_finished.charging_cost_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_finished_update_charging_cost_label; +} + +void ui_finished_update_idle_fee_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_price_finished.idle_fee_label, "Idle_fee"); +} + +void ui_after_create_price_finished_idle_fee_label(const char * name, lv_obj_t * obj) +{ + ui_page_price_finished.idle_fee_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_finished_update_idle_fee_label; +} + +void ui_finished_update_total_amount_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_price_finished.total_amount_label, "Total_Amount"); +} + +void ui_after_create_price_finished_total_amount_label(const char * name, lv_obj_t * obj) +{ + ui_page_price_finished.total_amount_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_finished_update_total_amount_label; +} + + +void ui_after_create_price_finished_idle_time(const char * name, lv_obj_t * obj) +{ + ui_page_price_finished.idle_time = obj; +} +void ui_after_create_price_finished_charging_cost(const char * name, lv_obj_t * obj) +{ + ui_page_price_finished.charging_cost = obj; +} +void ui_after_create_price_finished_idle_fee(const char * name, lv_obj_t * obj) +{ + ui_page_price_finished.idle_fee = obj; +} +void ui_after_create_price_finished_total_amount(const char * name, lv_obj_t * obj) +{ + ui_page_price_finished.total_amount = obj; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_after_create_price_finished(const char * name, lv_obj_t * obj) +{ + const char * finished_name = name + strlen(UI_NAME_PRICE_FINISHED); + if (strcmp(finished_name, UI_NAME_PRICE_FINISHED_IDLE_TIME) == 0) + { + ui_after_create_price_finished_idle_time(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_PRICE_FINISHED_IDLE_TIME_LABEL) == 0) + { + ui_after_create_price_finished_idle_time_label(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_PRICE_FINISHED_IDLE_TIME_PROMPT) == 0) + { + ui_after_create_price_finished_idle_time_prompt(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_PRICE_FINISHED_CHARGING_COST_LABEL) == 0) + { + ui_after_create_price_finished_charging_cost_label(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_PRICE_FINISHED_IDLE_FEE_LABEL) == 0) + { + ui_after_create_price_finished_idle_fee_label(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_PRICE_FINISHED_TOTAL_AMOUNT_LABEL) == 0) + { + ui_after_create_price_finished_total_amount_label(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_PRICE_FINISHED_CHARGING_COST) == 0) + { + ui_after_create_price_finished_charging_cost(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_PRICE_FINISHED_IDLE_FEE) == 0) + { + ui_after_create_price_finished_idle_fee(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_PRICE_FINISHED_TOTAL_AMOUNT) == 0) + { + ui_after_create_price_finished_total_amount(name, obj); + return; + } +} diff --git a/pages/ui_price_finished.h b/pages/ui_price_finished.h new file mode 100644 index 000000000..70af10a76 --- /dev/null +++ b/pages/ui_price_finished.h @@ -0,0 +1,15 @@ +#ifndef __UI_PAGE_PRICE_FINISHED_H__ +#define __UI_PAGE_PRICE_FINISHED_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_price_finished(lv_obj_t *parent); + +#define UI_NAME_PRICE_FINISHED "main.price_finished" +void ui_after_create_price_finished(const char * name, lv_obj_t * obj); + +// void ui_page_show_price_finished(void); +// void ui_page_hide_price_finished(void); + + +#endif diff --git a/pages/ui_price_finished_no_price.c b/pages/ui_price_finished_no_price.c new file mode 100644 index 000000000..8a9c425c8 --- /dev/null +++ b/pages/ui_price_finished_no_price.c @@ -0,0 +1,197 @@ +#include "../pages_mngr.h" + + +// 无价格体系信息框 +#define UI_NAME_PRICE_FINISHED_IDLE_TIME_NOPRICE "price_finished_time" +#define UI_NAME_PRICE_FINISHED_IDLE_TIME_LABEL_NOPRICE "price_finished_title" +#define UI_NAME_PRICE_FINISHED_PROMPT_NOPRICE "price_finished_tip" + + +#define UI_FINISHED_DATA g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.finished +#define UI_FINISHED_SHOWE_PRICE g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].showPrice + + +typedef struct { + + lv_obj_t * page; + + // 无价格体系信息框 + lv_obj_t * idle_time_noprice_label; + lv_obj_t * idle_time_noprice; + lv_obj_t * prompt_noprice; + +} ui_page_price_finished_no_price_t; + +static ui_page_price_finished_no_price_t ui_page_price_finished = {NULL}; +static lv_timer_t * s_finished_timer = NULL; +static int s_finished_show_price_flag = -1; // -1:未收到UI.jison时的初始值 0:不显示价格 1:显示价格 + + +static void ui_page_price_finished_no_price_time(lv_timer_t * temp) +{ + LV_UNUSED(temp); + + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + int show_hour = 0; + int show_min = 0; + int show_sec = 0; + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) + { + time_t current_time = time(NULL); + time_t diftimer = difftime(current_time, UI_FINISHED_DATA.stopTime); + + if (diftimer < 0) { + diftimer = 0; + } + + struct tm *tm = gmtime(&diftimer); + + + if (current_time >= UI_FINISHED_DATA.stopTime) { + show_hour = tm->tm_hour; + show_min = tm->tm_min; + show_sec = tm->tm_sec; + } + } + + if ( UI_CONNECTOR_STATE(UI_CONNECTOR_ACTIVE_IDX) == UI_CONNECTOR_STATE_FINISHED ) + { + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) + { + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", show_hour, show_min, show_sec); + ioc_label_set_text(ui_page_price_finished.idle_time_noprice, buf); + } + else + { + ioc_label_set_text(ui_page_price_finished.idle_time_noprice, ui_connector_get_text_time_value(UI_CONNECTOR_ACTIVE_IDX)); + } + } +} + +static void ui_page_06_finised_show_price(bool is_show) +{ + +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////// +static void ui_page_price_finished_no_price_updatejson(struct ioc_obj_user_data_s * user_data) +{ + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + + char buf[64] = {0}; + + + // 价格相关 + if(UI_FINISHED_SHOWE_PRICE) + { + if(s_finished_show_price_flag != 1) + { + ui_page_06_finised_show_price(true); + s_finished_show_price_flag = 1; + } + } + else + { + if(s_finished_show_price_flag != 0) + { + ui_page_06_finised_show_price(false); + s_finished_show_price_flag = 0; + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +lv_obj_t * ui_page_create_price_finished_no_price(lv_obj_t *parent) +{ + memset(&ui_page_price_finished, 0, sizeof(ui_page_price_finished)); + + ui_page_price_finished.page = ioc_layout_mngr_load_layout("finished", parent); + if (ui_page_price_finished.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(ui_page_price_finished.page); + user_data->ui_json_update_cb = ui_page_price_finished_no_price_updatejson; + } + + return ui_page_price_finished.page; +} + +static void ui_page_show_price_finished_no_price(void) +{ + // 为了时间显示的流畅,占位时间由本地计算 + if(s_finished_timer == NULL) + { + s_finished_timer = lv_timer_create(ui_page_price_finished_no_price_time, 500, NULL); + } +} + +static void ui_page_hide_price_finished_no_price(void) +{ + if (s_finished_timer!= NULL) + { + lv_timer_del(s_finished_timer); + s_finished_timer = NULL; + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", 0, 0, 0); + ioc_label_set_text(ui_page_price_finished.idle_time_noprice, buf); + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void ui_finished_update_prompt(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_price_finished.prompt_noprice, "Idle_time_prompt"); +} + +void ui_after_create_price_finished_no_price_prompt_noprice(const char * name, lv_obj_t * obj) +{ + ui_page_price_finished.prompt_noprice = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_finished_update_prompt; +} + +void ui_finished_update_idle_time_label_noprice(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_price_finished.idle_time_noprice_label, "Idle_time"); +} + +void ui_after_create_price_finished_no_price_idle_time_label_noprice(const char * name, lv_obj_t * obj) +{ + ui_page_price_finished.idle_time_noprice_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_finished_update_idle_time_label_noprice; +} + +void ui_after_create_price_finished_no_price_idle_time_noprice(const char * name, lv_obj_t * obj) +{ + ui_page_price_finished.idle_time_noprice = obj; +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_after_create_price_finished_no_price(const char * name, lv_obj_t * obj) +{ + const char * finished_name = name + strlen(UI_NAME_PRICE_FINISHED); + if (strcmp(finished_name, UI_NAME_PRICE_FINISHED_IDLE_TIME_NOPRICE) == 0) + { + ui_after_create_price_finished_no_price_idle_time_noprice(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_PRICE_FINISHED_PROMPT_NOPRICE) == 0) + { + ui_after_create_price_finished_no_price_prompt_noprice(name, obj); + return; + } + else if (strcmp(finished_name, UI_NAME_PRICE_FINISHED_IDLE_TIME_LABEL_NOPRICE) == 0) + { + ui_after_create_price_finished_no_price_idle_time_label_noprice(name, obj); + return; + } +} diff --git a/pages/ui_price_finished_no_price.h b/pages/ui_price_finished_no_price.h new file mode 100644 index 000000000..9dff854d7 --- /dev/null +++ b/pages/ui_price_finished_no_price.h @@ -0,0 +1,15 @@ +#ifndef __UI_PAGE_PRICE_FINISHED_NO_PRICE_H__ +#define __UI_PAGE_PRICE_FINISHED_NO_PRICE_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_price_finished_no_price(lv_obj_t *parent); + +#define UI_NAME_PRICE_FINISHED_NO_PRICE "main.price_finished_no_price" +void ui_after_create_price_finished_no_price(const char * name, lv_obj_t * obj); + +// void ui_page_show_price_finished(void); +// void ui_page_hide_price_finished(void); + + +#endif diff --git a/pages/ui_price_idle.c b/pages/ui_price_idle.c new file mode 100644 index 000000000..35e15aa7f --- /dev/null +++ b/pages/ui_price_idle.c @@ -0,0 +1,423 @@ +#include "../pages_mngr.h" + +#define UI_IDLE_DATA g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.idle +#define UI_IDLE_SHOWE_PRICE g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].showPrice +#define UI_IDLE_SHOWE_OCCPP_PRICE g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].isOcppPrice + +#define UI_NAME_PRICE_IDLE_CURRENT_PERIOD_LABEL ".price_idle_current.price_current_title" +#define UI_NAME_PRICE_IDLE_CURRENT_PERIOD ".price_idle_current.price_current_time" +#define UI_NAME_PRICE_IDLE_CURRENT_IMG ".price_idle_current.price_current_period_icon" +#define UI_NAME_PRICE_IDLE_CURRENT_CIRCLE ".price_idle_current.price_current_dot" +#define UI_NAME_PRICE_IDLE_CURRNET_PRICE_KWH ".price_idle_current.price_current_rate.price_kwh" +#define UI_NAME_PRICE_IDLE_CURRNET_PRICE_HR ".price_idle_current.price_current_rate.price_hr" +#define UI_NAME_PRICE_IDLE_CURRNET_PRICE_TIMES ".price_idle_current.price_current_rate.price_times" + +#define UI_NAME_PRICE_IDLE_SPLIT_LINE ".price_idle_divider" + +#define UI_NAME_PRICE_IDLE_NEXT_PERIOD_LABEL ".price_idle_next.price_next_title" +#define UI_NAME_PRICE_IDLE_NEXT_PERIOD ".price_idle_next.price_next_time" +#define UI_NAME_PRICE_IDLE_NEXT_IMG ".price_idle_next.price_next_period_img" +#define UI_NAME_PRICE_IDLE_NEXT_CIRCLE ".price_idle_next.price_next_dot" +#define UI_NAME_PRICE_IDLE_NEXT_PRICE_KWH ".price_idle_next.price_next_rate.price_kwh" +#define UI_NAME_PRICE_IDLE_NEXT_PRICE_HR ".price_idle_next.price_next_rate.price_hr" +#define UI_NAME_PRICE_IDLE_NEXT_PRICE_TIMES ".price_idle_next.price_next_rate.price_times" + + +#define UI_NAME_PRICE_IDLE_DEFAULT_PRICE_TEXT ".ocpp_price" + + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * curr_period; + lv_obj_t * curr_price_kwh; + lv_obj_t * curr_price_hr; + lv_obj_t * curr_price_times; + lv_obj_t * next_period; + lv_obj_t * next_price_kwh; + lv_obj_t * next_price_hr; + lv_obj_t * next_price_times; + lv_obj_t * default_price_text; + lv_obj_t * curr_img; + lv_obj_t * next_img; + lv_obj_t * curr_circle; + lv_obj_t * next_circle; + lv_obj_t * split_line; + + lv_obj_t * curr_period_label; + lv_obj_t * next_period_label; + +} ui_page_PRICE_IDLE_t; + +static ui_page_PRICE_IDLE_t ui_page_idle_price = {NULL}; +static int s_idle_show_price_flag = -1; // -1:未收到UI.jison时的初始值 0:不显示价格 1:显示价格 +static int s_idle_show_OCPPprice_flag = -1; // -1:未收到UI.jison时的初始值 0:显示正常价格 1:显示OCPP默认价格文本 +static char s_idle_price_text[256] = {0}; + + +// OCPPprice 价格体系在空闲时显示默认价格文本 +static void ui_page_price_idle_show_OCPPprie(bool is_show) +{ + if(is_show){ + lv_obj_clear_flag(ui_page_idle_price.default_price_text, LV_OBJ_FLAG_HIDDEN); + + lv_obj_add_flag(ui_page_idle_price.curr_period, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.curr_price_kwh, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.curr_price_hr, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.curr_price_times, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.next_period, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.next_price_kwh, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.next_price_hr, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.next_price_times, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.curr_img, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.next_img, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.curr_circle, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.next_circle, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.split_line, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.curr_period_label, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_idle_price.next_period_label, LV_OBJ_FLAG_HIDDEN); + + } else { + lv_obj_add_flag(ui_page_idle_price.default_price_text, LV_OBJ_FLAG_HIDDEN); + + lv_obj_clear_flag(ui_page_idle_price.curr_period, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.curr_price_kwh, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.curr_price_hr, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.curr_price_times, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.next_period, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.next_price_kwh, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.next_price_hr, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.next_price_times, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.curr_img, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.next_img, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.curr_circle, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.next_circle, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.split_line, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.curr_period_label, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_idle_price.next_period_label, LV_OBJ_FLAG_HIDDEN); + } +} + + +static void ui_page_PRICE_IDLE_updatejson(struct ioc_obj_user_data_s * user_data) +{ + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + + char buf[64] = {0}; + uint8_t startH = 0, startM = 0, endH = 0, endM = 0; + + // 价格相关 + if(UI_IDLE_SHOWE_PRICE) + { + // 判断是都要隐藏noprice + // if(s_idle_show_price_flag != 1) + // { + // ui_page_PRICE_IDLE_show_price(true); + // s_idle_show_price_flag = 1; + // } + + // 判断是否显示OCPPprice的默认价格文本 + if(UI_IDLE_SHOWE_OCCPP_PRICE) + { + if(s_idle_show_OCPPprice_flag != 1) + { + ui_page_price_idle_show_OCPPprie(true); + s_idle_show_OCPPprice_flag = 1; + } + + // 价格文本有变化时再更新 + if(strcmp(s_idle_price_text, UI_IDLE_DATA.currPrice.priceText) != 0) + { + strcpy(s_idle_price_text, UI_IDLE_DATA.currPrice.priceText); + ioc_label_set_text(ui_page_idle_price.default_price_text, s_idle_price_text); + LV_LOG_USER("Default Price Text [%s]", s_idle_price_text); + } + + return; + } + else + { + if(s_idle_show_OCPPprice_flag != 0) + { + ui_page_price_idle_show_OCPPprie(false); + s_idle_show_OCPPprice_flag = 0; + } + } + + // 设置时间段 + startH = (uint8_t)(UI_IDLE_DATA.currPrice.startMin / 60); + startM = (uint8_t)(UI_IDLE_DATA.currPrice.startMin % 60); + endH = (uint8_t)(UI_IDLE_DATA.nextPrice.startMin/ 60); + endM = (uint8_t)(UI_IDLE_DATA.nextPrice.startMin % 60); + + if (ui_page_idle_price.curr_period != NULL) + { + memset(buf, 0x00, sizeof(buf)); + sprintf((char*)buf, "%02d:%02d - %02d:%02d", + startH, startM, endH, endM); + ioc_label_set_text(ui_page_idle_price.curr_period , buf); + } + + startH = (uint8_t)(UI_IDLE_DATA.nextPrice.startMin / 60); + startM = (uint8_t)(UI_IDLE_DATA.nextPrice.startMin % 60); + endH = (uint8_t)(UI_IDLE_DATA.nextPrice.endMin/ 60); + endM = (uint8_t)(UI_IDLE_DATA.nextPrice.endMin % 60); + if (ui_page_idle_price.next_period != NULL) + { + memset(buf, 0x00, sizeof(buf)); + sprintf((char*)buf, "%02d:%02d - %02d:%02d", + startH, startM, endH, endM); + ioc_label_set_text(ui_page_idle_price.next_period , buf); + } + + // 根据costPriceDecimalPlaces判断保留几位小数 + char fmt[16]; + snprintf(fmt, sizeof(fmt), "%%.%df", g_ui_json.costPriceDecimalPlaces); + + if (ui_page_idle_price.curr_price_kwh != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_IDLE_DATA.currPrice.kWhPrice); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + strncat(buf, "/kWh", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(ui_page_idle_price.curr_price_kwh, buf); + } + + if (ui_page_idle_price.curr_price_hr != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_IDLE_DATA.currPrice.hourPrice); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + strncat(buf, "/hr", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(ui_page_idle_price.curr_price_hr, buf); + } + if (ui_page_idle_price.curr_price_times != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_IDLE_DATA.currPrice.flatFee); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + strncat(buf, "/times", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(ui_page_idle_price.curr_price_times, buf); + } + if (ui_page_idle_price.next_price_kwh != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_IDLE_DATA.nextPrice.kWhPrice); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + strncat(buf, "/kWh", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(ui_page_idle_price.next_price_kwh, buf); + } + if (ui_page_idle_price.next_price_hr != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_IDLE_DATA.nextPrice.hourPrice); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + strncat(buf, "/hr", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(ui_page_idle_price.next_price_hr, buf); + } + if (ui_page_idle_price.next_price_times != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_IDLE_DATA.nextPrice.flatFee); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + strncat(buf, "/times", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(ui_page_idle_price.next_price_times, buf); + } + } + else + { + // // 判断是否要隐藏info_card + // if(s_idle_show_price_flag != 0) + // { + // ui_page_PRICE_IDLE_show_price(false); + // s_idle_show_price_flag = 0; + // } + } +} + +lv_obj_t * ui_page_create_price_idle(lv_obj_t *parent) +{ + memset(&ui_page_idle_price, 0, sizeof(ui_page_idle_price)); + + ui_page_idle_price.page = ioc_layout_mngr_load_layout("idle", parent); + if (ui_page_idle_price.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(ui_page_idle_price.page); + user_data->ui_json_update_cb = ui_page_PRICE_IDLE_updatejson; + } + + return ui_page_idle_price.page; +} + + +void ui_idle_update_current_period_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_idle_price.curr_period_label, "Current_Period"); +} + +void ui_after_create_PRICE_IDLE_current_period_label(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.curr_period_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_idle_update_current_period_label; +} + +void ui_idle_update_next_period_lable(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_idle_price.next_period_label, "Next_Period"); +} + +void ui_after_create_PRICE_IDLE_next_period_lable(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.next_period_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_idle_update_next_period_lable; +} + +void ui_after_create_PRICE_IDLE_current_period(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.curr_period = obj; +} +void ui_after_create_PRICE_IDLE_current_price_kwh(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.curr_price_kwh = obj; +} +void ui_after_create_PRICE_IDLE_current_price_hr(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.curr_price_hr = obj; +} +void ui_after_create_PRICE_IDLE_current_price_times(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.curr_price_times = obj; +} +void ui_after_create_PRICE_IDLE_next_period(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.next_period = obj; +} +void ui_after_create_PRICE_IDLE_next_price_kwh(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.next_price_kwh = obj; +} +void ui_after_create_PRICE_IDLE_next_price_hr(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.next_price_hr = obj; +} +void ui_after_create_PRICE_IDLE_next_price_times(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.next_price_times = obj; +} +void ui_after_create_PRICE_IDLE_default_price_text(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.default_price_text = obj; +} +void ui_after_create_PRICE_IDLE_current_img(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.curr_img = obj; +} +void ui_after_create_PRICE_IDLE_current_circle(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.curr_circle = obj; +} +void ui_after_create_PRICE_IDLE_next_img(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.next_img = obj; +} +void ui_after_create_PRICE_IDLE_next_circle(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.next_circle = obj; +} +void ui_after_create_PRICE_IDLE_split_line(const char * name, lv_obj_t * obj) +{ + ui_page_idle_price.split_line = obj; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////// + +void ui_after_create_price_idle(const char * name, lv_obj_t * obj) +{ + const char * price_idle_name = name + strlen(UI_NAME_PRICE_IDLE); + if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_CURRENT_PERIOD_LABEL) == 0) + { + ui_after_create_PRICE_IDLE_current_period_label(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_NEXT_PERIOD_LABEL) == 0) + { + ui_after_create_PRICE_IDLE_next_period_lable(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_CURRENT_PERIOD) == 0) + { + ui_after_create_PRICE_IDLE_current_period(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_CURRNET_PRICE_KWH) == 0) + { + ui_after_create_PRICE_IDLE_current_price_kwh(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_CURRNET_PRICE_HR) == 0) + { + ui_after_create_PRICE_IDLE_current_price_hr(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_CURRNET_PRICE_TIMES) == 0) + { + ui_after_create_PRICE_IDLE_current_price_times(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_NEXT_PERIOD) == 0) + { + ui_after_create_PRICE_IDLE_next_period(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_NEXT_PRICE_KWH) == 0) + { + ui_after_create_PRICE_IDLE_next_price_kwh(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_NEXT_PRICE_HR) == 0) + { + ui_after_create_PRICE_IDLE_next_price_hr(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_NEXT_PRICE_TIMES) == 0) + { + ui_after_create_PRICE_IDLE_next_price_times(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_DEFAULT_PRICE_TEXT) == 0) + { + ui_after_create_PRICE_IDLE_default_price_text(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_CURRENT_IMG) == 0) + { + ui_after_create_PRICE_IDLE_current_img(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_CURRENT_CIRCLE) == 0) + { + ui_after_create_PRICE_IDLE_current_circle(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_NEXT_IMG) == 0) + { + ui_after_create_PRICE_IDLE_next_img(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_NEXT_CIRCLE) == 0) + { + ui_after_create_PRICE_IDLE_next_circle(name, obj); + return; + } + else if (strcmp(price_idle_name, UI_NAME_PRICE_IDLE_SPLIT_LINE) == 0) + { + ui_after_create_PRICE_IDLE_split_line(name, obj); + return; + } +} diff --git a/pages/ui_price_idle.h b/pages/ui_price_idle.h new file mode 100644 index 000000000..bf776a4f0 --- /dev/null +++ b/pages/ui_price_idle.h @@ -0,0 +1,11 @@ +#ifndef __UI_PRICE_IDLE_H__ +#define __UI_PRICE_IDLE_H__ + +#include "lvgl.h" + +lv_obj_t * ui_page_create_price_idle(lv_obj_t *parent); + +#define UI_NAME_PRICE_IDLE "main.price_idle" +void ui_after_create_price_idle(const char * name, lv_obj_t * obj); + +#endif diff --git a/pages/ui_price_reserved.c b/pages/ui_price_reserved.c new file mode 100644 index 000000000..3f0cd2ace --- /dev/null +++ b/pages/ui_price_reserved.c @@ -0,0 +1,402 @@ +#include "../pages_mngr.h" + + +#define UI_NAME_PRICE_RESERVED_LEFT_LABEL "price_reserved_title" +#define UI_NAME_PRICE_RESERVED_PLUG "price_reserved_tip" +#define UI_NAME_PRICE_RESERVED_IDLE_TIME "idle_time_value_reserved" + +#define UI_NAME_PRICE_RESERVED_SPLIT_LINE "price_reserved_divider" + +#define UI_NAME_PRICE_RESERVED_CURRENT_IMG "price_reserved_current.price_current_period_icon" +#define UI_NAME_PRICE_RESERVED_CURRENT_CIRCLE "price_reserved_current.price_current_dot" +#define UI_NAME_PRICE_RESERVED_CURRENT_TIME_LABEL "price_reserved_current.price_current_title" +#define UI_NAME_PRICE_RESERVED_CURRENT_PERIOD "price_reserved_current.price_current_time" +#define UI_NAME_PRICE_RESERVED_CURRNET_PRICE_KWH "price_reserved_current.price_current_rate.price_kwh" +#define UI_NAME_PRICE_RESERVED_CURRNET_PRICE_HR "price_reserved_current.price_current_rate.price_hr" +#define UI_NAME_PRICE_RESERVED_CURRNET_PRICE_TIMES "price_reserved_current.price_current_rate.price_times" +#define UI_NAME_PRICE_RESERVED_DEFAULT_PRICE_TEXT "ocpp_price.label" + + +#define UI_RESERVED_DATA g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].state_data.reserved +#define UI_RESERVED_SHOWE_PRICE g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].showPrice +#define UI_RESERVED_SHOWE_OCCPP_PRICE g_ui_json.connectors[UI_CONNECTOR_ACTIVE_IDX].isOcppPrice + +typedef struct { + + lv_obj_t * page; + lv_obj_t * idle_time; + lv_obj_t * curr_period; + lv_obj_t * curr_price_kwh; + lv_obj_t * curr_price_hr; + lv_obj_t * curr_price_times; + lv_obj_t * default_price_text; + lv_obj_t * curr_img; + lv_obj_t * curr_circle; + lv_obj_t * split_line; + + lv_obj_t * left_label; + lv_obj_t * plug; + lv_obj_t * current_time_label; + +} ui_page_price_reserved_t; + +static ui_page_price_reserved_t ui_page_price_reserved = {NULL}; +static int s_reserved_show_price_flag = -1; // -1:未收到UI.jison时的初始值 0:不显示价格 1:显示价格 +static int s_reserved_show_OCPPprice_flag = -1; // -1:未收到UI.jison时的初始值 0:显示正常价格 1:显示OCPP默认价格文本 +static char s_reserved_price_text[256] = {0}; +lv_timer_t * s_reserved_timer = NULL; + +static void ui_page_price_reserved_time(lv_timer_t * temp) +{ + LV_UNUSED(temp); + + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + int show_hour = 0; + int show_min = 0; + int show_sec = 0; + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) + { + time_t current_time = time(NULL); + time_t diftimer = difftime(UI_RESERVED_DATA.reverseTime, current_time); + + if (diftimer < 0) { + diftimer = 0; + } + + struct tm *tm = gmtime(&diftimer); + + if (current_time < UI_RESERVED_DATA.reverseTime) { + show_hour = tm->tm_hour; + show_min = tm->tm_min; + show_sec = tm->tm_sec; + } + } + + if (UI_FINISHED_SHOWE_PRICE) + { + if ( UI_CONNECTOR_STATE(UI_CONNECTOR_ACTIVE_IDX) == UI_CONNECTOR_STATE_RESERVED ) + { + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) + { + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", show_hour, show_min, show_sec); + ioc_label_set_text(ui_page_price_reserved.idle_time, buf); + } + else + { + ioc_label_set_text(ui_page_price_reserved.idle_time, ui_connector_get_text_time_value(UI_CONNECTOR_ACTIVE_IDX)); + } + } + } +} + +// OCPPprice 价格体系在空闲时显示默认价格文本 +static void ui_page_price_reserved_show_OCPPprie(bool is_show) +{ + if(is_show){ + lv_obj_clear_flag(ui_page_price_reserved.default_price_text, LV_OBJ_FLAG_HIDDEN); + + lv_obj_add_flag(ui_page_price_reserved.curr_period, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_price_reserved.curr_price_kwh, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_price_reserved.curr_price_hr, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_price_reserved.curr_price_times, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_price_reserved.curr_img, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_price_reserved.curr_circle, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(ui_page_price_reserved.split_line, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_add_flag(ui_page_price_reserved.default_price_text, LV_OBJ_FLAG_HIDDEN); + + lv_obj_clear_flag(ui_page_price_reserved.curr_period, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_price_reserved.curr_price_kwh, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_price_reserved.curr_price_hr, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_price_reserved.curr_price_times, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_price_reserved.curr_img, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_price_reserved.curr_circle, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(ui_page_price_reserved.split_line, LV_OBJ_FLAG_HIDDEN); + } +} + +static void ui_page_price_reserved_show_price(bool is_show) +{ + +} + +static void ui_page_price_reserved_updatejson(struct ioc_obj_user_data_s * user_data) +{ + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + + char buf[64] = {0}; + uint8_t startH = 0, startM = 0, endH = 0, endM = 0; + + // 价格相关 + if(UI_RESERVED_SHOWE_PRICE) + { + // 判断是都要隐藏noprice + if(s_reserved_show_price_flag != 1) + { + ui_page_price_reserved_show_price(true); + s_reserved_show_price_flag = 1; + } + + // 判断是否显示OCPPprice的默认价格文本 + if(UI_RESERVED_SHOWE_OCCPP_PRICE) + { + if(s_reserved_show_OCPPprice_flag != 1) + { + ui_page_price_reserved_show_OCPPprie(true); + s_reserved_show_OCPPprice_flag = 1; + } + + // 价格文本有变化时再更新 + if(strcmp(s_reserved_price_text, UI_RESERVED_DATA.currPrice.priceText) != 0) + { + strcpy(s_reserved_price_text, UI_RESERVED_DATA.currPrice.priceText); + ioc_label_set_text(ui_page_price_reserved.default_price_text, s_reserved_price_text); + LV_LOG_USER("Default Price Text [%s]", s_reserved_price_text); + } + + return; + } + else + { + if(s_reserved_show_OCPPprice_flag != 0) + { + ui_page_price_reserved_show_OCPPprie(false); + s_reserved_show_OCPPprice_flag = 0; + } + } + + // 设置时间段 + startH = (uint8_t)(UI_RESERVED_DATA.currPrice.startMin / 60); + startM = (uint8_t)(UI_RESERVED_DATA.currPrice.startMin % 60); + endH = (uint8_t)(UI_RESERVED_DATA.nextPrice.startMin/ 60); + endM = (uint8_t)(UI_RESERVED_DATA.nextPrice.startMin % 60); + + if (ui_page_price_reserved.curr_period != NULL) + { + memset(buf, 0x00, sizeof(buf)); + sprintf((char*)buf, "%02d:%02d - %02d:%02d", + startH, startM, endH, endM); + ioc_label_set_text(ui_page_price_reserved.curr_period , buf); + } + + // 根据costPriceDecimalPlaces判断保留几位小数 + char fmt[16]; + snprintf(fmt, sizeof(fmt), "%%.%df", g_ui_json.costPriceDecimalPlaces); + + if (ui_page_price_reserved.curr_price_kwh != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_RESERVED_DATA.currPrice.kWhPrice); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + strncat(buf, "/kWh", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(ui_page_price_reserved.curr_price_kwh, buf); + } + + if (ui_page_price_reserved.curr_price_hr != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_RESERVED_DATA.currPrice.hourPrice); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + strncat(buf, "/hr", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(ui_page_price_reserved.curr_price_hr, buf); + } + if (ui_page_price_reserved.curr_price_times != NULL) + { + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, sizeof(buf), fmt, UI_RESERVED_DATA.currPrice.flatFee); + strncat(buf, g_ui_json.currencyIcon, sizeof(buf) - strlen(buf) - 1); + strncat(buf, "/times", sizeof(buf) - strlen(buf) - 1); + ioc_label_set_text(ui_page_price_reserved.curr_price_times, buf); + } + } + else + { + // 判断是否要隐藏info_card + if(s_reserved_show_price_flag != 0) + { + ui_page_price_reserved_show_price(false); + s_reserved_show_price_flag = 0; + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +lv_obj_t * ui_page_create_price_reserved(lv_obj_t *parent) +{ + memset(&ui_page_price_reserved, 0, sizeof(ui_page_price_reserved)); + + ui_page_price_reserved.page = ioc_layout_mngr_load_layout("reserved", parent); + if (ui_page_price_reserved.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(ui_page_price_reserved.page); + user_data->ui_json_update_cb = ui_page_price_reserved_updatejson; + } + + return ui_page_price_reserved.page; +} + +void ui_page_show_price_reserved(void) +{ + // 为了时间显示的流畅,占位时间由本地计算 + if(s_reserved_timer == NULL) + { + s_reserved_timer = lv_timer_create(ui_page_price_reserved_time, 500, NULL); + } +} +void ui_page_hide_price_reserved(void) +{ + if (s_reserved_timer!= NULL) + { + lv_timer_del(s_reserved_timer); + s_reserved_timer = NULL; + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", 0, 0, 0); + ioc_label_set_text(ui_page_price_reserved.idle_time, buf); + } +} +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void ui_reserved_update_left_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_price_reserved.left_label, "Left"); +} + +void ui_after_create_price_reserved_left_label(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved.left_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_reserved_update_left_label; +} + +void ui_reserved_update_plug(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_price_reserved.plug, "Plug_in_frist"); +} + +void ui_after_create_price_reserved_plug(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved.plug = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_reserved_update_plug; +} + +void ui_reserved_update_current_time_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_price_reserved.current_time_label, "Current_Period"); +} + +void ui_after_create_price_reserved_current_time_label(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved.current_time_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_reserved_update_current_time_label; +} + +void ui_after_create_price_reserved_idle_time(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved.idle_time = obj; +} +void ui_after_create_price_reserved_current_period(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved.curr_period = obj; +} +void ui_after_create_price_reserved_current_price_kWh(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved.curr_price_kwh = obj; +} +void ui_after_create_price_reserved_current_price_hr(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved.curr_price_hr = obj; +} +void ui_after_create_price_reserved_current_price_times(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved.curr_price_times = obj; +} +void ui_after_create_price_reserved_default_price_text(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved.default_price_text = obj; +} +void ui_after_create_price_reserved_current_img(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved.curr_img = obj; +} +void ui_after_create_price_reserved_current_circle(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved.curr_circle = obj; +} +void ui_after_create_price_reserved_split_line(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved.split_line = obj; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_after_create_price_reserved(const char * name, lv_obj_t * obj) +{ + const char * reserved_name = name + strlen(UI_NAME_PRICE_RESERVED); + if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_LEFT_LABEL) == 0) + { + ui_after_create_price_reserved_left_label(name, obj); + return; + } + else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_PLUG) == 0) + { + ui_after_create_price_reserved_plug(name, obj); + return; + } + else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_CURRENT_TIME_LABEL) == 0) + { + ui_after_create_price_reserved_current_time_label(name, obj); + return; + } + else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_IDLE_TIME) == 0) + { + ui_after_create_price_reserved_idle_time(name, obj); + return; + } + else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_CURRENT_PERIOD) == 0) + { + ui_after_create_price_reserved_current_period(name, obj); + return; + } + else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_CURRNET_PRICE_KWH) == 0) + { + ui_after_create_price_reserved_current_price_kWh(name, obj); + return; + } else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_CURRNET_PRICE_HR) == 0) + { + ui_after_create_price_reserved_current_price_hr(name, obj); + return; + } + else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_CURRNET_PRICE_TIMES) == 0) + { + ui_after_create_price_reserved_current_price_times(name, obj); + return; + } + else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_DEFAULT_PRICE_TEXT) == 0) + { + ui_after_create_price_reserved_default_price_text(name, obj); + return; + } + else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_CURRENT_IMG) == 0) + { + ui_after_create_price_reserved_current_img(name, obj); + return; + } + else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_CURRENT_CIRCLE) == 0) + { + ui_after_create_price_reserved_current_circle(name, obj); + return; + } + else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_SPLIT_LINE) == 0) + { + ui_after_create_price_reserved_split_line(name, obj); + return; + } +} diff --git a/pages/ui_price_reserved.h b/pages/ui_price_reserved.h new file mode 100644 index 000000000..fcd2375d7 --- /dev/null +++ b/pages/ui_price_reserved.h @@ -0,0 +1,17 @@ +#ifndef __UI_PAGE_PRICE_RESERVED_H__ +#define __UI_PAGE_PRICE_RESERVED_H__ + + +#include "lvgl.h" + +lv_obj_t * ui_page_create_price_reserved(lv_obj_t *parent); +void ui_after_create_price_reserved(const char * name, lv_obj_t * obj); + + +#define UI_NAME_PRICE_RESERVED "main.price_reserved" + +// void ui_page_show_price_reserved(void); +// void ui_page_hide_price_reserved(void); + + +#endif diff --git a/pages/ui_price_reserved_no_price.c b/pages/ui_price_reserved_no_price.c new file mode 100644 index 000000000..1387d5680 --- /dev/null +++ b/pages/ui_price_reserved_no_price.c @@ -0,0 +1,162 @@ +#include "../pages_mngr.h" + +// 无价格体系信息框 +#define UI_NAME_PRICE_RESERVED_PRICE_LEFT_TIME_LABEL "price_reserved_title" +#define UI_NAME_PRICE_RESERVED_PRICE_PLUG_NOPRICE "price_reserved_tip" +#define UI_NAME_PRICE_RESERVED_PRICE_IDLE_TIME_NOPRICE "price_reserved_time" + +typedef struct { + + lv_obj_t * page; + + lv_obj_t * left_time_label; + lv_obj_t * plug_noprice; + lv_obj_t * info_card_idle_time_noprice; + +} ui_page_price_reserved_no_price_t; + +static ui_page_price_reserved_no_price_t ui_page_price_reserved_no_price = {NULL}; + +lv_timer_t * s_reserved_no_price_timer = NULL; + +static void ui_page_price_reserved_no_price_time(lv_timer_t * temp) +{ + LV_UNUSED(temp); + + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } + int show_hour = 0; + int show_min = 0; + int show_sec = 0; + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) + { + time_t current_time = time(NULL); + time_t diftimer = difftime(UI_RESERVED_DATA.reverseTime, current_time); + + if (diftimer < 0) { + diftimer = 0; + } + + struct tm *tm = gmtime(&diftimer); + + if (current_time < UI_RESERVED_DATA.reverseTime) { + show_hour = tm->tm_hour; + show_min = tm->tm_min; + show_sec = tm->tm_sec; + } + } + + if ( UI_CONNECTOR_STATE(UI_CONNECTOR_ACTIVE_IDX) == UI_CONNECTOR_STATE_RESERVED ) + { + if ( UI_NUMOFCONNECTOR == CHARGER_GUN_TYPE_SINGLE ) + { + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", show_hour, show_min, show_sec); + ioc_label_set_text(ui_page_price_reserved_no_price.info_card_idle_time_noprice, buf); + } + else + { + ioc_label_set_text(ui_page_price_reserved_no_price.info_card_idle_time_noprice, ui_connector_get_text_time_value(UI_CONNECTOR_ACTIVE_IDX)); + } + } +} + +static void ui_page_price_reserved_no_price_show_price(bool is_show) +{ + +} + +static void ui_page_price_reserved_no_price_updatejson(struct ioc_obj_user_data_s * user_data) +{ + if (UI_CONNECTOR_ACTIVE_IDX < 0 || UI_CONNECTOR_ACTIVE_IDX >= UI_NUMOFCONNECTOR) + { + return; + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +lv_obj_t * ui_page_create_price_reserved_no_price(lv_obj_t *parent) +{ + memset(&ui_page_price_reserved_no_price, 0, sizeof(ui_page_price_reserved_no_price)); + + ui_page_price_reserved_no_price.page = ioc_layout_mngr_load_layout("reserved", parent); + if (ui_page_price_reserved_no_price.page != NULL) + { + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(ui_page_price_reserved_no_price.page); + user_data->ui_json_update_cb = ui_page_price_reserved_no_price_updatejson; + } + + return ui_page_price_reserved_no_price.page; +} + +void ui_page_show_price_reserved_no_price(void) +{ + // 为了时间显示的流畅,占位时间由本地计算 + if(s_reserved_no_price_timer == NULL) + { + s_reserved_no_price_timer = lv_timer_create(ui_page_price_reserved_no_price_time, 500, NULL); + } +} +void ui_page_hide_price_reserved_no_price(void) +{ + if (s_reserved_no_price_timer!= NULL) + { + lv_timer_del(s_reserved_no_price_timer); + s_reserved_no_price_timer = NULL; + char buf[64] = {0}; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", 0, 0, 0); + ioc_label_set_text(ui_page_price_reserved_no_price.info_card_idle_time_noprice, buf); + } +} +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_reserved_update_left_time_label(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_price_reserved_no_price.left_time_label, "Left"); +} + +void ui_after_create_price_reserved_no_price_left_time_label(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved_no_price.left_time_label = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_reserved_update_left_time_label; +} + +void ui_reserved_update_plug_noprice(struct ioc_obj_user_data_s * user_data) +{ + ioc_label_set_text(ui_page_price_reserved_no_price.plug_noprice, "Plug_in_frist"); +} + +void ui_after_create_price_reserved_no_price_plug_noprice(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved_no_price.plug_noprice = obj; + ioc_obj_user_data_t * user_data = (ioc_obj_user_data_t *)lv_obj_get_user_data(obj); + user_data->ui_json_update_cb = ui_reserved_update_plug_noprice; +} + +void ui_after_create_price_reserved_no_price_idle_time_noprice(const char * name, lv_obj_t * obj) +{ + ui_page_price_reserved_no_price.info_card_idle_time_noprice = obj; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ui_after_create_price_reserved_no_price(const char * name, lv_obj_t * obj) +{ + const char * reserved_name = name + strlen(UI_NAME_PRICE_RESERVED_NO_PRICE); + if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_PRICE_LEFT_TIME_LABEL) == 0) + { + ui_after_create_price_reserved_no_price_left_time_label(name, obj); + return; + } + else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_PRICE_PLUG_NOPRICE) == 0) + { + ui_after_create_price_reserved_no_price_plug_noprice(name, obj); + return; + } + else if (strcmp(reserved_name, UI_NAME_PRICE_RESERVED_PRICE_IDLE_TIME_NOPRICE) == 0) + { + ui_after_create_price_reserved_no_price_idle_time_noprice(name, obj); + return; + } +} diff --git a/pages/ui_price_reserved_no_price.h b/pages/ui_price_reserved_no_price.h new file mode 100644 index 000000000..c97a5a080 --- /dev/null +++ b/pages/ui_price_reserved_no_price.h @@ -0,0 +1,16 @@ +#ifndef __UI_PAGE_PRICE_RESERVED_NO_PRICE_H__ +#define __UI_PAGE_PRICE_RESERVED_NO_PRICE_H__ + + +#include "lvgl.h" + +lv_obj_t * ui_page_create_price_reserved_no_price(lv_obj_t *parent); +void ui_after_create_price_reserved_no_price(const char * name, lv_obj_t * obj); + + +#define UI_NAME_PRICE_RESERVED_NO_PRICE "main.price_reserved_no_price" + +// void ui_page_show_price_reserved_no_price(void); +// void ui_page_hide_price_reserved_no_price(void); + +#endif diff --git a/pages_mngr.c b/pages_mngr.c new file mode 100644 index 000000000..3592ec929 --- /dev/null +++ b/pages_mngr.c @@ -0,0 +1,238 @@ +#include "pages_mngr.h" + + +typedef enum +{ + // CHARGING_CONNECTOR_LEFT, + // CHARGING_CONNECTOR_RIGHT, + CONNECTOR_CARD_DUAL, + CONNECTOR_CARD_QUAD, + CONNECTOR_CARD_TRIP, + STATE_MID_CONTAINER_TOP, + STATE_HOME, + STATE_IDLE, + STATE_STARTING1, + STATE_STARTING2, + STATE_CHARGING, + STATE_FINISHED, + STATE_RESERVED, + STATE_SESSION_ERROR, + STATE_START_ERROR, + STATE_FAULT, + STATE_UNAVAILABLE, + STATE_CONNECTING, + STATE_STOPPING, + STATE_WAIT_IN_LINE, + STATE_SUSPEND, + STATE_PROCESSING, + STATU_BAR, + STATU_HELP1, + STATU_HELP2, + STATU_LANGUAGE, + STATU_BILL, + STATU_PRE_AUTHORIZATION, + STATU_DETAILED_DATA, + STATU_POPUP_COMMON, + + + STATU_ENUM +}app_register_e; + +/** + * !!!!!! 注意, 父亲和孩子同时存在的时候, 必须先写孩子后写父亲, 否则会导致孩子无法执行 + * 例如: "main.connector_group.group*" 必须在"main.connector_group.group1.connector*"后面 + */ +ioc_obj_handler_t s_preset_handler[STATU_ENUM]; + +void s_preset_handler_init(void) +{ static int times = 0; + if ( times <= 1) + { + // charging_connector_left 页面 + // s_preset_handler[CHARGING_CONNECTOR_LEFT].name = UI_NAME_05_CHARGING_CONNECTOR_LEFT; + // s_preset_handler[CHARGING_CONNECTOR_LEFT].after_create = ui_after_create_05_charging_connector_left; + // s_preset_handler[CHARGING_CONNECTOR_LEFT].before_create = NULL; + + // // charging_connector_right 页面 + + // s_preset_handler[CHARGING_CONNECTOR_RIGHT].name = UI_NAME_05_CHARGING_CONNECTOR_RIGHT; + // s_preset_handler[CHARGING_CONNECTOR_RIGHT].after_create = ui_after_create_05_charging_connector_right; + // s_preset_handler[CHARGING_CONNECTOR_RIGHT].before_create = NULL; + + // 四种卡片和卡片组的注册 + s_preset_handler[CONNECTOR_CARD_DUAL].name = UI_NAME_CONNECTOR_CARD_DUAL_PREFIX; + s_preset_handler[CONNECTOR_CARD_DUAL].after_create = ui_after_create_connector_card; + s_preset_handler[CONNECTOR_CARD_DUAL].before_create = NULL; + + + s_preset_handler[CONNECTOR_CARD_QUAD].name = UI_NAME_CONNECTOR_CARD_QUAD_PREFIX; + s_preset_handler[CONNECTOR_CARD_QUAD].after_create = ui_after_create_connector_card; + s_preset_handler[CONNECTOR_CARD_QUAD].before_create = NULL; + + + s_preset_handler[CONNECTOR_CARD_TRIP].name = UI_NAME_CONNECTOR_CARD_TRIP_PREFIX; + s_preset_handler[CONNECTOR_CARD_TRIP].after_create = ui_after_create_connector_card; + s_preset_handler[CONNECTOR_CARD_TRIP].before_create = NULL; + + + // 中间顶层状态栏的注册 + s_preset_handler[STATE_MID_CONTAINER_TOP].name = UI_NAME_STATE_MID_CONTAINER_TOP; + s_preset_handler[STATE_MID_CONTAINER_TOP].after_create = ui_after_create_state_mid_container_top; + s_preset_handler[STATE_MID_CONTAINER_TOP].before_create = NULL; + + // home 页面 + s_preset_handler[STATE_HOME].name = UI_NAME_STATE_HOME; + s_preset_handler[STATE_HOME].after_create = ui_after_create_state_home; + s_preset_handler[STATE_HOME].before_create = NULL; + + // idle 页面 + s_preset_handler[STATE_IDLE].name = UI_NAME_02_IDLE; + s_preset_handler[STATE_IDLE].after_create = ui_after_create_02_idle; + s_preset_handler[STATE_IDLE].before_create = NULL; + + // starting1 页面 + s_preset_handler[STATE_STARTING1].name = UI_NAME_03_STARTING1; + s_preset_handler[STATE_STARTING1].after_create = ui_after_create_03_starting1; + s_preset_handler[STATE_STARTING1].before_create = NULL; + + // starting2 页面 + s_preset_handler[STATE_STARTING2].name = UI_NAME_04_STARTING2; + s_preset_handler[STATE_STARTING2].after_create = ui_after_create_04_starting2; + s_preset_handler[STATE_STARTING2].before_create = NULL; + + // charging 页面 + s_preset_handler[STATE_CHARGING].name = UI_NAME_05_CHARGING; + s_preset_handler[STATE_CHARGING].after_create = ui_after_create_05_charging; + s_preset_handler[STATE_CHARGING].before_create = NULL; + + // finished 页面 + s_preset_handler[STATE_FINISHED].name = UI_NAME_06_FINISHED; + s_preset_handler[STATE_FINISHED].after_create = ui_after_create_06_finished; + s_preset_handler[STATE_FINISHED].before_create = NULL; + + // reserved 页面 + s_preset_handler[STATE_RESERVED].name = UI_NAME_07_RESERVED; + s_preset_handler[STATE_RESERVED].after_create = ui_after_create_07_reserved; + s_preset_handler[STATE_RESERVED].before_create = NULL; + + // session_error 页面 + s_preset_handler[STATE_SESSION_ERROR].name = UI_NAME_08_SESSION_ERROR; + s_preset_handler[STATE_SESSION_ERROR].after_create = ui_after_create_08_session_error; + s_preset_handler[STATE_SESSION_ERROR].before_create = NULL; + + // start_error 页面 + s_preset_handler[STATE_START_ERROR].name = UI_NAME_09_START_ERROR; + s_preset_handler[STATE_START_ERROR].after_create = ui_after_create_09_start_error; + s_preset_handler[STATE_START_ERROR].before_create = NULL; + + // falut 页面 + s_preset_handler[STATE_FAULT].name = UI_NAME_10_FAULT; + s_preset_handler[STATE_FAULT].after_create = ui_after_create_10_fault; + s_preset_handler[STATE_FAULT].before_create = NULL; + + // unavailable 页面 + s_preset_handler[STATE_UNAVAILABLE].name = UI_NAME_11_UNAVAILABLE; + s_preset_handler[STATE_UNAVAILABLE].after_create = ui_after_create_11_unavailable; + s_preset_handler[STATE_UNAVAILABLE].before_create = NULL; + + // connecting 页面 + s_preset_handler[STATE_CONNECTING].name = UI_NAME_12_CONNECTING; + s_preset_handler[STATE_CONNECTING].after_create = ui_after_create_12_connecting; + s_preset_handler[STATE_CONNECTING].before_create = NULL; + + // stopping 页面 + s_preset_handler[STATE_STOPPING].name = UI_NAME_14_STOPPING; + s_preset_handler[STATE_STOPPING].after_create = ui_after_create_14_stopping; + s_preset_handler[STATE_STOPPING].before_create = NULL; + + // wait_in_line 页面 + s_preset_handler[STATE_WAIT_IN_LINE].name = UI_NAME_15_WAIT_IN_LINE; + s_preset_handler[STATE_WAIT_IN_LINE].after_create = ui_after_create_15_wait_in_line; + s_preset_handler[STATE_WAIT_IN_LINE].before_create = NULL; + + // suspend 页面 + s_preset_handler[STATE_SUSPEND].name = UI_NAME_16_SUSPEND; + s_preset_handler[STATE_SUSPEND].after_create = ui_after_create_16_suspend; + s_preset_handler[STATE_SUSPEND].before_create = NULL; + + // processing 页面 + s_preset_handler[STATE_PROCESSING].name = UI_NAME_17_PROCESSING; + s_preset_handler[STATE_PROCESSING].after_create = ui_after_create_17_processing; + s_preset_handler[STATE_PROCESSING].before_create = NULL; + + // 状态栏的注册 + s_preset_handler[STATU_BAR].name = UI_NAME_STATUS_BAR; + s_preset_handler[STATU_BAR].after_create = ui_after_create_status_bar; + s_preset_handler[STATU_BAR].before_create = NULL; + + + // 帮助界面 + s_preset_handler[STATU_HELP1].name = UI_NAME_HELP1; + s_preset_handler[STATU_HELP1].after_create = ui_after_create_help1; + s_preset_handler[STATU_HELP1].before_create = NULL; + + + s_preset_handler[STATU_HELP2].name = UI_NAME_HELP2; + s_preset_handler[STATU_HELP2].after_create = ui_after_create_help2; + s_preset_handler[STATU_HELP2].before_create = NULL; + + + // 语言界面 + s_preset_handler[STATU_LANGUAGE].name = UI_NAME_LANGUAGE; + s_preset_handler[STATU_LANGUAGE].after_create = ui_after_create_language; + s_preset_handler[STATU_LANGUAGE].before_create = NULL; + + + // 账单界面 + s_preset_handler[STATU_BILL].name = UI_NAME_BILL; + s_preset_handler[STATU_BILL].after_create = ui_after_create_bill; + s_preset_handler[STATU_BILL].before_create = NULL; + + + // 软键盘界面 + s_preset_handler[STATU_PRE_AUTHORIZATION].name = UI_NAME_PRE_AUTHORIZATION; + s_preset_handler[STATU_PRE_AUTHORIZATION].after_create = ui_after_create_preauthorization; + s_preset_handler[STATU_PRE_AUTHORIZATION].before_create = NULL; + + // 充电详细信息界面 + s_preset_handler[STATU_DETAILED_DATA].name = UI_NAME_DETAILED_DATA; + s_preset_handler[STATU_DETAILED_DATA].after_create = ui_after_create_detaile_data; + s_preset_handler[STATU_DETAILED_DATA].before_create = NULL; + + // 通用弹窗界面 + s_preset_handler[STATU_POPUP_COMMON].name = UI_NAME_POPUP_COMMON; + s_preset_handler[STATU_POPUP_COMMON].after_create = ui_after_create_popup_common; + s_preset_handler[STATU_POPUP_COMMON].before_create = NULL; + times ++; + } + else + { + return; + } +} + +int ioc_get_preset_handler_count(void) +{ + return sizeof(s_preset_handler) / sizeof(s_preset_handler[0]); +} + +// 如果用户没有主动选择语言,那么一直由ui.json决定 +bool ioc_ui_json_set_language(int language) +{ + if ( s_ui_language.check_language == false ) + { + if (language < 0 || language >= LANG_NUM) return false; + + if (g_ui_json.language != language) + { + LV_LOG_WARN("language %d->%d", g_ui_json.language, language); + g_ui_json.language = language; + lv_i18n_set_locale(c_LanguageName[language]); + ui_language_update_selected(c_LanguageName[language]); + return true; + } + + return false; + } + return true; +} diff --git a/pages_mngr.h b/pages_mngr.h new file mode 100644 index 000000000..7bf628c84 --- /dev/null +++ b/pages_mngr.h @@ -0,0 +1,49 @@ +#ifndef __PAGES_MNGR_H__ +#define __PAGES_MNGR_H__ + +#include "ioc_app.h" + +#include "./pages/ui_page_main.h" +#include "./pages/ui_page_connector_group.h" +#include "./pages/ui_page_status_bar.h" +#include "./pages/ui_page_mid_container_top.h" + +#include "./pages/ui_page_01_home.h" +#include "./pages/ui_page_02_idle.h" +#include "./pages/ui_page_03_starting1.h" +#include "./pages/ui_page_04_starting2.h" +#include "./pages/ui_page_05_charging.h" +#include "./pages/ui_page_06_finished.h" +#include "./pages/ui_page_07_reserved.h" +#include "./pages/ui_page_08_session_error.h" +#include "./pages/ui_page_09_start_error.h" +#include "./pages/ui_page_10_fault.h" +#include "./pages/ui_page_11_unavailable.h" +#include "./pages/ui_page_12_connecting.h" +#include "./pages/ui_page_14_stopping.h" +#include "./pages/ui_page_15_wait_in_line.h" +#include "./pages/ui_page_16_suspend.h" +#include "./pages/ui_page_17_processing.h" + +#include "./pages/ui_popup_help.h" +#include "./pages/ui_popup_language.h" +#include "./pages/ui_popup_charging_detail.h" +#include "./pages/ui_popup_bill.h" +#include "./pages/ui_popup_preauthorization.h" +#include "./pages/ui_popup_common.h" +#include "./pages/ui_price_idle.h" +#include "./pages/ui_price_charging.h" +#include "./pages/ui_price_finished.h" +#include "./pages/ui_price_finished_no_price.h" +#include "./pages/ui_price_reserved.h" +#include "./pages/ui_price_reserved_no_price.h" +#include "./pages/ui_customer_info.h" +#include "./pages/ui_customer_info_charging.h" + + +#include "./i18n/lv_i18n.h" + +#define UI_NUMOFCONNECTOR_SINGLE 1 +#define UI_CONNECTOR_ACTIVE_IDX_SINGLE 0 + +#endif diff --git a/patch/images/ocular_title.png b/patch/images/ocular_title.png new file mode 100644 index 000000000..10f0de788 Binary files /dev/null and b/patch/images/ocular_title.png differ diff --git a/patch/layout/layout_100_status_bar.json b/patch/layout/layout_100_status_bar.json new file mode 100644 index 000000000..709066134 --- /dev/null +++ b/patch/layout/layout_100_status_bar.json @@ -0,0 +1,20 @@ +{ + "name": "status_bar", + "desc": "顶部状态栏", + "children": [ + { + "name": "logo", + "type": "image", + "properties": { + "x_ofs": 20, + "y_ofs": 20, + "align": "LV_ALIGN_TOP_LEFT", + "src": "logo" + } + }, + { + "name": "help", + "deleted": true + } + ] +} diff --git a/patch/theme/theme-100-main-light-ocular.json b/patch/theme/theme-100-main-light-ocular.json new file mode 100644 index 000000000..b4f7209cc --- /dev/null +++ b/patch/theme/theme-100-main-light-ocular.json @@ -0,0 +1,10 @@ +{ + "name": "main-light", + "description": "main-light theme ocular", + "images": [ + { + "name": "logo", + "path": "A:./patch/images/ocular_title.png" + } + ] +} diff --git a/simulator.code-workspace b/simulator.code-workspace index 9226f9d87..c98520953 100644 --- a/simulator.code-workspace +++ b/simulator.code-workspace @@ -1,109 +1,134 @@ { - // https://code.visualstudio.com/docs/editor/workspaces - // https://code.visualstudio.com/docs/editor/multi-root-workspaces - // https://code.visualstudio.com/docs/editor/variables-reference - - "folders": [ - { - "path": "." - }, - ], - // extensions.json section - "extensions": { - "recommendations": [ - "ms-vscode.cpptools", // common C/C++ support - "ms-vscode.cpptools-themes", // general C/C++ theme - "ms-vscode.cmake-tools" // cmake support - ], - "unwantedRecommendations": [ - ] - }, - // settings.json section - "settings": { - "files.trimTrailingWhitespace": true, - "files.insertFinalNewline": true, - "files.trimFinalNewlines": true, - "cmake.configureOnOpen": true, - "files.associations": { - "glob.h": "c", - "lvgl.h": "c" - }, - }, - // tasks.json section - "tasks": { - "version": "2.0.0", - "tasks": [ - { - "label": "Build", - "command": "cmake", - "args": [ - "--build", "${command:cmake.buildDirectory}" - ], - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": { - "owner": "cpp", - "fileLocation": ["relative", "${workspaceFolder}"], - "pattern": { - "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", - "file": 1, - "line": 2, - "column": 3, - "severity": 4, - "message": 5 - } - } - }, - { - "label": "Build and Run", - "type": "shell", - "command": "${workspaceFolder}/bin/main", - "group": { - "kind": "test", - "isDefault": true - }, - "dependsOn": "Build" - } - ], - }, - // launch.json section - "launch": { - "version": "0.2.0", - "configurations": [ - { - "name": "Debug LVGL demo with gdb", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/bin/main", - "args": [], - "cwd": "${workspaceFolder}", - "preLaunchTask": "Build", - "stopAtEntry": false, - "linux": { - "MIMode": "gdb", - "miDebuggerPath": "/usr/bin/gdb" - }, - "osx": { - "MIMode": "lldb" - }, - "windows": { - "MIMode": "gdb", - "miDebuggerPath": "C:\\MinGw\\bin\\gdb.exe" - } - }, - { - "name": "Debug LVGL demo with LLVM", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/bin/main", - "args": [], - "cwd": "${workspaceFolder}", - "preLaunchTask": "Build", - "stopAtEntry": false, - "MIMode": "lldb" - }, - ], - }, + "folders": [ + { + "path": "." + } + ], + "extensions": { + "recommendations": [ + "ms-vscode.cpptools", + "ms-vscode.cpptools-themes", + "ms-vscode.cmake-tools" + ], + "unwantedRecommendations": [] + }, + "settings": { + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "cmake.configureOnOpen": true, + "cmake.buildDirectory": "${workspaceFolder}/build", + "files.associations": { + "glob.h": "c", + "lvgl.h": "c" + } + }, + "tasks": { + "version": "2.0.0", + "windows": { + "options": { + "shell": { + "executable": "C:\\msys64\\usr\\bin\\bash.exe", + "args": [ + "-lc" + ] + }, + "env": { + "MSYSTEM": "UCRT64", + "CHERE_INVOKING": "1", + "PATH": "C:\\msys64\\ucrt64\\bin;C:\\msys64\\usr\\bin;${env:PATH}" + } + } + }, + "tasks": [ + { + "label": "CMake: Configure (Ninja UCRT64)", + "type": "shell", + "command": "cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DLV_USE_FREETYPE=ON", + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": "build" + }, + { + "label": "CMake: Build (Ninja UCRT64)", + "type": "shell", + "command": "cmake --build build -j4", + "options": { + "cwd": "${workspaceFolder}" + }, + "dependsOn": "CMake: Configure (Ninja UCRT64)", + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "CMake: Rebuild (Ninja UCRT64)", + "type": "shell", + "command": "cmake --fresh -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DLV_USE_FREETYPE=ON && cmake --build build -j4", + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [ + "$gcc" + ] + }, + { + "label": "Run: main.exe", + "type": "shell", + "command": "./bin/main.exe", + "options": { + "cwd": "${workspaceFolder}" + }, + "dependsOn": "CMake: Build (Ninja UCRT64)", + "problemMatcher": [] + } + ] + }, + "launch": { + "version": "0.2.0", + "configurations": [ + { + "name": "Debug LVGL demo with gdb", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/bin/main.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [ + { + "name": "PATH", + "value": "C:\\msys64\\ucrt64\\bin;C:\\msys64\\usr\\bin;${env:PATH}" + }, + { + "name": "MSYSTEM", + "value": "UCRT64" + }, + { + "name": "CHERE_INVOKING", + "value": "1" + } + ], + "externalConsole": false, + "MIMode": "gdb", + "miDebuggerPath": "C:\\msys64\\ucrt64\\bin\\gdb.exe", + "setupCommands": [ + { + "description": "Enable pretty printing", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "CMake: Build (Ninja UCRT64)" + } + ] + } } diff --git a/src/main.c b/src/main.c index c8932202b..aec2d20d4 100644 --- a/src/main.c +++ b/src/main.c @@ -26,6 +26,8 @@ #include "hal/hal.h" +#include "../ioc/ioc_app.h" + /********************* * DEFINES *********************/ @@ -61,7 +63,9 @@ int main(int argc, char **argv) lv_init(); /*Initialize the HAL (display, input devices, tick) for LVGL*/ - sdl_hal_init(320, 480); + sdl_hal_init(800, 600); + + ioc_app_main(); /* Run the default demo */ /* To try a different demo or example, replace this with one of: */ @@ -69,7 +73,7 @@ int main(int argc, char **argv) /* - lv_demo_stress(); */ /* - lv_example_label_1(); */ /* - etc. */ - lv_demo_widgets(); + // lv_demo_widgets(); while(1) { /* Periodically call the lv_task handler. @@ -82,6 +86,7 @@ int main(int argc, char **argv) Sleep(sleep_time_ms); #else usleep(sleep_time_ms * 1000); + ioc_app_step(); #endif } @@ -94,4 +99,3 @@ int main(int argc, char **argv) /********************** * STATIC FUNCTIONS **********************/ - diff --git a/ui_visible_obj_info.json b/ui_visible_obj_info.json new file mode 100644 index 000000000..718cf2694 --- /dev/null +++ b/ui_visible_obj_info.json @@ -0,0 +1,501 @@ +[{ + "name": "lv_scr_act", + "x": 0, + "y": 0, + "width": 800, + "height": 600, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 0, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main", + "x": 0, + "y": 0, + "width": 800, + "height": 600, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 0, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.status_bar", + "x": 0, + "y": 0, + "width": 800, + "height": 70, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 0, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.status_bar.time", + "x": 380, + "y": 24, + "width": 41, + "height": 22, + "align": "LV_ALIGN_CENTER", + "x_ofs": 0, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.status_bar.language", + "x": 650, + "y": 15, + "width": 130, + "height": 40, + "align": "LV_ALIGN_LEFT_MID", + "x_ofs": 650, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.status_bar.language.icon", + "x": 22, + "y": 3, + "width": 32, + "height": 32, + "align": "LV_ALIGN_LEFT_MID", + "x_ofs": 22, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.status_bar.language.label", + "x": 56, + "y": 8, + "width": 53, + "height": 22, + "align": "LV_ALIGN_LEFT_MID", + "x_ofs": 56, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.status_bar.logo", + "x": 20, + "y": 20, + "width": 260, + "height": 50, + "align": "LV_ALIGN_TOP_LEFT", + "x_ofs": 20, + "y_ofs": 20, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad", + "x": 0, + "y": 440, + "width": 800, + "height": 160, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 0, + "y_ofs": 440, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector1", + "x": 20, + "y": 19, + "width": 184, + "height": 123, + "align": "LV_ALIGN_LEFT_MID", + "x_ofs": 20, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector1.conn_card_id", + "x": 14, + "y": 14, + "width": 34, + "height": 34, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 14, + "y_ofs": 14, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector1.conn_card_id.NoText", + "x": 13, + "y": 3, + "width": 9, + "height": 28, + "align": "LV_ALIGN_CENTER", + "x_ofs": 0, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector1.conn_card_state", + "x": 131, + "y": 19, + "width": 37, + "height": 29, + "align": "LV_ALIGN_TOP_RIGHT", + "x_ofs": -14, + "y_ofs": 19, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector1.conn_card_type", + "x": 14, + "y": 65, + "width": 71, + "height": 22, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 14, + "y_ofs": 65, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector1.conn_card_power_rated", + "x": 14, + "y": 89, + "width": 65, + "height": 22, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 14, + "y_ofs": 89, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector1.conn_card_type_icon", + "x": 121, + "y": 60, + "width": 47, + "height": 47, + "align": "LV_ALIGN_BOTTOM_RIGHT", + "x_ofs": -14, + "y_ofs": -14, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector1.conn_card_plug_gun_icon", + "x": 148, + "y": 91, + "width": 20, + "height": 20, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 148, + "y_ofs": 91, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector2", + "x": 212, + "y": 19, + "width": 184, + "height": 123, + "align": "LV_ALIGN_LEFT_MID", + "x_ofs": 212, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector2.conn_card_id", + "x": 14, + "y": 14, + "width": 34, + "height": 34, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 14, + "y_ofs": 14, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector2.conn_card_id.NoText", + "x": 11, + "y": 3, + "width": 13, + "height": 28, + "align": "LV_ALIGN_CENTER", + "x_ofs": 0, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector2.conn_card_state", + "x": 131, + "y": 19, + "width": 37, + "height": 29, + "align": "LV_ALIGN_TOP_RIGHT", + "x_ofs": -14, + "y_ofs": 19, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector2.conn_card_type", + "x": 14, + "y": 65, + "width": 71, + "height": 22, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 14, + "y_ofs": 65, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector2.conn_card_power_rated", + "x": 14, + "y": 89, + "width": 65, + "height": 22, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 14, + "y_ofs": 89, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector2.conn_card_type_icon", + "x": 121, + "y": 60, + "width": 47, + "height": 47, + "align": "LV_ALIGN_BOTTOM_RIGHT", + "x_ofs": -14, + "y_ofs": -14, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector3", + "x": 404, + "y": 19, + "width": 184, + "height": 123, + "align": "LV_ALIGN_LEFT_MID", + "x_ofs": 404, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector3.conn_card_id", + "x": 14, + "y": 14, + "width": 34, + "height": 34, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 14, + "y_ofs": 14, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector3.conn_card_id.NoText", + "x": 10, + "y": 3, + "width": 14, + "height": 28, + "align": "LV_ALIGN_CENTER", + "x_ofs": 0, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector3.conn_card_state", + "x": 131, + "y": 19, + "width": 37, + "height": 29, + "align": "LV_ALIGN_TOP_RIGHT", + "x_ofs": -14, + "y_ofs": 19, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector3.conn_card_type", + "x": 14, + "y": 65, + "width": 79, + "height": 22, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 14, + "y_ofs": 65, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector3.conn_card_power_rated", + "x": 14, + "y": 89, + "width": 56, + "height": 22, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 14, + "y_ofs": 89, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector3.conn_card_type_icon", + "x": 121, + "y": 60, + "width": 47, + "height": 47, + "align": "LV_ALIGN_BOTTOM_RIGHT", + "x_ofs": -14, + "y_ofs": -14, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector4", + "x": 596, + "y": 19, + "width": 184, + "height": 123, + "align": "LV_ALIGN_LEFT_MID", + "x_ofs": 596, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector4.conn_card_id", + "x": 14, + "y": 14, + "width": 34, + "height": 34, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 14, + "y_ofs": 14, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_card_quad.connector4.conn_card_id.NoText", + "x": 10, + "y": 3, + "width": 14, + "height": 28, + "align": "LV_ALIGN_CENTER", + "x_ofs": 0, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector4.conn_card_state", + "x": 131, + "y": 19, + "width": 37, + "height": 29, + "align": "LV_ALIGN_TOP_RIGHT", + "x_ofs": -14, + "y_ofs": 19, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector4.conn_card_type", + "x": 14, + "y": 65, + "width": 64, + "height": 22, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 14, + "y_ofs": 65, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector4.conn_card_power_rated", + "x": 14, + "y": 89, + "width": 56, + "height": 22, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 14, + "y_ofs": 89, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_card_quad.connector4.conn_card_type_icon", + "x": 121, + "y": 60, + "width": 47, + "height": 47, + "align": "LV_ALIGN_BOTTOM_RIGHT", + "x_ofs": -14, + "y_ofs": -14, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.starting2", + "x": 20, + "y": 70, + "width": 760, + "height": 370, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 20, + "y_ofs": 70, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.starting2.starting2_qr", + "x": 79, + "y": 92, + "width": 130, + "height": 130, + "align": "LV_ALIGN_TOP_LEFT", + "x_ofs": 79, + "y_ofs": 92, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.starting2.starting2_pos_btn", + "x": 269, + "y": 92, + "width": 130, + "height": 130, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 269, + "y_ofs": 92, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.starting2.starting2_pos_btn.img", + "x": 0, + "y": 0, + "width": 130, + "height": 130, + "align": "LV_ALIGN_CENTER", + "x_ofs": 0, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.starting2.starting2_subtitle", + "x": 31, + "y": 278, + "width": 416, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "x_ofs": 31, + "y_ofs": 278, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.starting2.starting2_title", + "x": 0, + "y": 0, + "width": 500, + "height": 40, + "align": "LV_ALIGN_TOP_LEFT", + "x_ofs": -1, + "y_ofs": 248, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_top_info", + "x": 20, + "y": 70, + "width": 760, + "height": 70, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 20, + "y_ofs": 70, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_top_info.conn_id", + "x": 0, + "y": 0, + "width": 70, + "height": 70, + "align": "LV_ALIGN_DEFAULT", + "x_ofs": 0, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_AUTO" + }, { + "name": "main.conn_top_info.conn_id.conn_id_text", + "x": 29, + "y": 15, + "width": 13, + "height": 40, + "align": "LV_ALIGN_CENTER", + "x_ofs": 0, + "y_ofs": 0, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_top_info.station_id", + "x": 90, + "y": 42, + "width": 45, + "height": 22, + "align": "LV_ALIGN_TOP_LEFT", + "x_ofs": 90, + "y_ofs": 42, + "text_align": "LV_TEXT_ALIGN_LEFT" + }, { + "name": "main.conn_top_info.conn_state", + "x": 90, + "y": 13, + "width": 37, + "height": 29, + "align": "LV_ALIGN_TOP_LEFT", + "x_ofs": 90, + "y_ofs": 13, + "text_align": "LV_TEXT_ALIGN_CENTER" + }, { + "name": "main.conn_top_info.conn_type_power", + "x": 554, + "y": 13, + "width": 184, + "height": 29, + "align": "LV_ALIGN_TOP_LEFT", + "x_ofs": 554, + "y_ofs": 13, + "text_align": "LV_TEXT_ALIGN_CENTER" + }] \ No newline at end of file diff --git a/ui_visible_tree.json b/ui_visible_tree.json new file mode 100644 index 000000000..354c708d3 --- /dev/null +++ b/ui_visible_tree.json @@ -0,0 +1,151 @@ +{ + "name": "lv_scr_act", + "children": [{ + "name": "main", + "children": [{ + "name": "main.status_bar", + "children": [{ + "name": "main.status_bar.time", + "children": [] + }, { + "name": "main.status_bar.language", + "children": [{ + "name": "main.status_bar.language.icon", + "children": [] + }, { + "name": "main.status_bar.language.label", + "children": [] + }] + }, { + "name": "main.status_bar.logo", + "children": [] + }] + }, { + "name": "main.conn_card_quad", + "children": [{ + "name": "main.conn_card_quad.connector1", + "children": [{ + "name": "main.conn_card_quad.connector1.conn_card_id", + "children": [{ + "name": "main.conn_card_quad.connector1.conn_card_id.NoText", + "children": [] + }] + }, { + "name": "main.conn_card_quad.connector1.conn_card_state", + "children": [] + }, { + "name": "main.conn_card_quad.connector1.conn_card_type", + "children": [] + }, { + "name": "main.conn_card_quad.connector1.conn_card_power_rated", + "children": [] + }, { + "name": "main.conn_card_quad.connector1.conn_card_type_icon", + "children": [] + }, { + "name": "main.conn_card_quad.connector1.conn_card_plug_gun_icon", + "children": [] + }] + }, { + "name": "main.conn_card_quad.connector2", + "children": [{ + "name": "main.conn_card_quad.connector2.conn_card_id", + "children": [{ + "name": "main.conn_card_quad.connector2.conn_card_id.NoText", + "children": [] + }] + }, { + "name": "main.conn_card_quad.connector2.conn_card_state", + "children": [] + }, { + "name": "main.conn_card_quad.connector2.conn_card_type", + "children": [] + }, { + "name": "main.conn_card_quad.connector2.conn_card_power_rated", + "children": [] + }, { + "name": "main.conn_card_quad.connector2.conn_card_type_icon", + "children": [] + }] + }, { + "name": "main.conn_card_quad.connector3", + "children": [{ + "name": "main.conn_card_quad.connector3.conn_card_id", + "children": [{ + "name": "main.conn_card_quad.connector3.conn_card_id.NoText", + "children": [] + }] + }, { + "name": "main.conn_card_quad.connector3.conn_card_state", + "children": [] + }, { + "name": "main.conn_card_quad.connector3.conn_card_type", + "children": [] + }, { + "name": "main.conn_card_quad.connector3.conn_card_power_rated", + "children": [] + }, { + "name": "main.conn_card_quad.connector3.conn_card_type_icon", + "children": [] + }] + }, { + "name": "main.conn_card_quad.connector4", + "children": [{ + "name": "main.conn_card_quad.connector4.conn_card_id", + "children": [{ + "name": "main.conn_card_quad.connector4.conn_card_id.NoText", + "children": [] + }] + }, { + "name": "main.conn_card_quad.connector4.conn_card_state", + "children": [] + }, { + "name": "main.conn_card_quad.connector4.conn_card_type", + "children": [] + }, { + "name": "main.conn_card_quad.connector4.conn_card_power_rated", + "children": [] + }, { + "name": "main.conn_card_quad.connector4.conn_card_type_icon", + "children": [] + }] + }] + }, { + "name": "main.starting2", + "children": [{ + "name": "main.starting2.starting2_qr", + "children": [] + }, { + "name": "main.starting2.starting2_pos_btn", + "children": [{ + "name": "main.starting2.starting2_pos_btn.img", + "children": [] + }] + }, { + "name": "main.starting2.starting2_subtitle", + "children": [] + }, { + "name": "main.starting2.starting2_title", + "children": [] + }] + }, { + "name": "main.conn_top_info", + "children": [{ + "name": "main.conn_top_info.conn_id", + "children": [{ + "name": "main.conn_top_info.conn_id.conn_id_text", + "children": [] + }] + }, { + "name": "main.conn_top_info.station_id", + "children": [] + }, { + "name": "main.conn_top_info.conn_state", + "children": [] + }, { + "name": "main.conn_top_info.conn_type_power", + "children": [] + }] + }] + }] +} \ No newline at end of file