From 4820d9111e9734cdfa180854103203ff32a08e8d Mon Sep 17 00:00:00 2001 From: PlxEV Date: Thu, 20 Nov 2025 07:45:00 +0000 Subject: [PATCH] new release --- components/api/CMakeLists.txt | 14 - components/api/include/api.h | 6 - components/api/include/json.h | 43 - components/api/include/ota.h | 15 - components/api/include/timeout_utils.h | 23 - components/api/lib/cAT/.clang-format | 493 --- components/api/lib/cAT/.gitignore | 17 - components/api/lib/cAT/.travis.yml | 11 - components/api/lib/cAT/CMakeLists.txt | 148 - components/api/lib/cAT/LICENSE | 21 - components/api/lib/cAT/README.md | 211 -- components/api/lib/cAT/changelog.txt | 70 - components/api/lib/cAT/example/basic.c | 161 - components/api/lib/cAT/example/demo.c | 260 -- components/api/lib/cAT/example/unsolicited.c | 251 -- components/api/lib/cAT/src/cat.c | 2757 ----------------- components/api/lib/cAT/src/cat.h | 557 ---- components/api/lib/cAT/tests/test_cmd_list.c | 340 -- .../api/lib/cAT/tests/test_hold_state.c | 229 -- components/api/lib/cAT/tests/test_mutex.c | 185 -- components/api/lib/cAT/tests/test_order.c | 223 -- components/api/lib/cAT/tests/test_parse.c | 195 -- components/api/lib/cAT/tests/test_read.c | 165 - components/api/lib/cAT/tests/test_read_args.c | 225 -- .../api/lib/cAT/tests/test_return_read.c | 206 -- .../api/lib/cAT/tests/test_return_run.c | 236 -- .../api/lib/cAT/tests/test_return_test.c | 206 -- .../api/lib/cAT/tests/test_return_write.c | 236 -- components/api/lib/cAT/tests/test_run.c | 157 - .../api/lib/cAT/tests/test_search_cmd.c | 224 -- components/api/lib/cAT/tests/test_shortcuts.c | 149 - components/api/lib/cAT/tests/test_test.c | 183 -- components/api/lib/cAT/tests/test_test_args.c | 459 --- components/api/lib/cAT/tests/test_test_only.c | 173 -- .../api/lib/cAT/tests/test_unsolicited_read.c | 203 -- .../cAT/tests/test_unsolicited_read_buffer.c | 238 -- .../cAT/tests/test_unsolicited_read_stress.c | 211 -- .../api/lib/cAT/tests/test_unsolicited_test.c | 189 -- .../api/lib/cAT/tests/test_var_access.c | 545 ---- components/api/lib/cAT/tests/test_write.c | 166 - .../api/lib/cAT/tests/test_write_hex_buffer.c | 174 -- .../api/lib/cAT/tests/test_write_hex_range.c | 212 -- .../api/lib/cAT/tests/test_write_int_range.c | 212 -- .../api/lib/cAT/tests/test_write_parse.c | 234 -- .../lib/cAT/tests/test_write_string_buffer.c | 168 - .../api/lib/cAT/tests/test_write_uint_range.c | 212 -- components/api/src/api.c | 6 - components/api/src/json.c | 575 ---- components/api/src/ota.c | 66 - components/api/src/timeout_utils.c | 74 - components/auth/src/auth.c | 17 - components/auth/src/wiegand_reader.c | 264 +- components/buzzer/include/buzzer.h | 55 + components/buzzer/include/buzzer_events.h | 1 + components/buzzer/src/buzzer.c | 576 +++- components/evse/evse_manager.c | 170 +- components/evse/evse_meter.c | 2 +- components/loadbalancer/src/loadbalancer.c | 462 ++- components/meter_manager/CMakeLists.txt | 4 + .../driver/meter_orno/meter_dds661.c | 289 ++ .../driver/meter_orno/meter_dds661.h | 29 + .../driver/meter_orno/meter_dts6619.c | 326 ++ .../driver/meter_orno/meter_dts6619.h | 35 + .../driver/meter_orno/meter_ea777.c | 379 +++ .../driver/meter_orno/meter_ea777.h | 32 + .../driver/meter_orno/meter_orno513.c | 4 +- .../driver/meter_orno/meter_orno516.c | 10 +- .../driver/meter_orno/meter_orno526.c | 310 ++ .../driver/meter_orno/meter_orno526.h | 29 + .../driver/meter_orno/modbus_params.h | 22 +- .../driver/meter_zigbee/meter_zigbee.c | 20 +- .../meter_manager/include/meter_manager.h | 6 +- components/meter_manager/src/meter_manager.c | 458 ++- components/network/src/network.c | 396 ++- components/ocpp/src/ocpp.c | 31 +- components/peripherals/CMakeLists.txt | 2 +- components/peripherals/src/ntc_sensor.c | 40 +- components/protocols/CMakeLists.txt | 36 +- components/protocols/gen-tzdata.py | 371 --- components/protocols/include/date_time.h | 61 - components/protocols/include/json.h | 38 + components/protocols/include/modbus_tcp.h | 27 - components/protocols/include/mqtt.h | 113 +- components/protocols/server_certs/ca_cert.pem | 22 - components/protocols/src/date_time.c | 136 - components/protocols/src/json.c | 204 ++ components/protocols/src/mqtt.c | 475 ++- components/protocols/src/protocols.c | 7 - components/protocols/src/tz_data.h | 354 --- .../webfolder/assets/index-C_08vMAY.js | 51 - .../webfolder/assets/index-Doq3307m.css | 1 - components/protocols/webfolder/index.html | 23 - components/protocols/webfolder/vite.svg | 1 - components/rest_api/CMakeLists.txt | 2 +- .../rest_api/include/meters_settings_api.h | 8 + components/rest_api/src/dashboard_api.c | 4 +- components/rest_api/src/meters_settings_api.c | 191 +- components/rest_api/src/rest_main.c | 28 +- .../{index-CmjuW5AW.js => index-BcUN2CM9.js} | 26 +- ...{index-Bc9ibDeR.css => index-NSBcyqXj.css} | 2 +- components/rest_api/webfolder/index.html | 6 +- dependencies.lock | 13 +- main/idf_component.yml | 9 +- main/main.c | 1 - projeto_parte1.c | 1328 -------- readproject.py | 4 +- 106 files changed, 4264 insertions(+), 15581 deletions(-) delete mode 100755 components/api/CMakeLists.txt delete mode 100755 components/api/include/api.h delete mode 100755 components/api/include/json.h delete mode 100755 components/api/include/ota.h delete mode 100755 components/api/include/timeout_utils.h delete mode 100755 components/api/lib/cAT/.clang-format delete mode 100755 components/api/lib/cAT/.gitignore delete mode 100755 components/api/lib/cAT/.travis.yml delete mode 100755 components/api/lib/cAT/CMakeLists.txt delete mode 100755 components/api/lib/cAT/LICENSE delete mode 100755 components/api/lib/cAT/README.md delete mode 100755 components/api/lib/cAT/changelog.txt delete mode 100755 components/api/lib/cAT/example/basic.c delete mode 100755 components/api/lib/cAT/example/demo.c delete mode 100755 components/api/lib/cAT/example/unsolicited.c delete mode 100755 components/api/lib/cAT/src/cat.c delete mode 100755 components/api/lib/cAT/src/cat.h delete mode 100755 components/api/lib/cAT/tests/test_cmd_list.c delete mode 100755 components/api/lib/cAT/tests/test_hold_state.c delete mode 100755 components/api/lib/cAT/tests/test_mutex.c delete mode 100755 components/api/lib/cAT/tests/test_order.c delete mode 100755 components/api/lib/cAT/tests/test_parse.c delete mode 100755 components/api/lib/cAT/tests/test_read.c delete mode 100755 components/api/lib/cAT/tests/test_read_args.c delete mode 100755 components/api/lib/cAT/tests/test_return_read.c delete mode 100755 components/api/lib/cAT/tests/test_return_run.c delete mode 100755 components/api/lib/cAT/tests/test_return_test.c delete mode 100755 components/api/lib/cAT/tests/test_return_write.c delete mode 100755 components/api/lib/cAT/tests/test_run.c delete mode 100755 components/api/lib/cAT/tests/test_search_cmd.c delete mode 100755 components/api/lib/cAT/tests/test_shortcuts.c delete mode 100755 components/api/lib/cAT/tests/test_test.c delete mode 100755 components/api/lib/cAT/tests/test_test_args.c delete mode 100755 components/api/lib/cAT/tests/test_test_only.c delete mode 100755 components/api/lib/cAT/tests/test_unsolicited_read.c delete mode 100755 components/api/lib/cAT/tests/test_unsolicited_read_buffer.c delete mode 100755 components/api/lib/cAT/tests/test_unsolicited_read_stress.c delete mode 100755 components/api/lib/cAT/tests/test_unsolicited_test.c delete mode 100755 components/api/lib/cAT/tests/test_var_access.c delete mode 100755 components/api/lib/cAT/tests/test_write.c delete mode 100755 components/api/lib/cAT/tests/test_write_hex_buffer.c delete mode 100755 components/api/lib/cAT/tests/test_write_hex_range.c delete mode 100755 components/api/lib/cAT/tests/test_write_int_range.c delete mode 100755 components/api/lib/cAT/tests/test_write_parse.c delete mode 100755 components/api/lib/cAT/tests/test_write_string_buffer.c delete mode 100755 components/api/lib/cAT/tests/test_write_uint_range.c delete mode 100755 components/api/src/api.c delete mode 100755 components/api/src/json.c delete mode 100755 components/api/src/ota.c delete mode 100755 components/api/src/timeout_utils.c create mode 100755 components/meter_manager/driver/meter_orno/meter_dds661.c create mode 100755 components/meter_manager/driver/meter_orno/meter_dds661.h create mode 100755 components/meter_manager/driver/meter_orno/meter_dts6619.c create mode 100755 components/meter_manager/driver/meter_orno/meter_dts6619.h create mode 100755 components/meter_manager/driver/meter_orno/meter_ea777.c create mode 100755 components/meter_manager/driver/meter_orno/meter_ea777.h create mode 100755 components/meter_manager/driver/meter_orno/meter_orno526.c create mode 100755 components/meter_manager/driver/meter_orno/meter_orno526.h delete mode 100755 components/protocols/gen-tzdata.py delete mode 100755 components/protocols/include/date_time.h create mode 100755 components/protocols/include/json.h delete mode 100755 components/protocols/include/modbus_tcp.h delete mode 100755 components/protocols/server_certs/ca_cert.pem delete mode 100755 components/protocols/src/date_time.c create mode 100755 components/protocols/src/json.c delete mode 100755 components/protocols/src/tz_data.h delete mode 100644 components/protocols/webfolder/assets/index-C_08vMAY.js delete mode 100644 components/protocols/webfolder/assets/index-Doq3307m.css delete mode 100644 components/protocols/webfolder/index.html delete mode 100755 components/protocols/webfolder/vite.svg rename components/rest_api/webfolder/assets/{index-CmjuW5AW.js => index-BcUN2CM9.js} (52%) rename components/rest_api/webfolder/assets/{index-Bc9ibDeR.css => index-NSBcyqXj.css} (53%) delete mode 100644 projeto_parte1.c diff --git a/components/api/CMakeLists.txt b/components/api/CMakeLists.txt deleted file mode 100755 index 2eee434..0000000 --- a/components/api/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -set(srcs - "src/api.c" - "src/ota.c" - "src/json.c" - "src/timeout_utils.c" - "lib/cAT/src/cat.c") - -idf_component_register(SRCS "${srcs}" - INCLUDE_DIRS "include" "lib/cAT/src" - PRIV_INCLUDE_DIRS "src" - PRIV_REQUIRES nvs_flash app_update json driver esp_http_client esp_netif esp_wifi esp_timer esp_hw_support - REQUIRES network config evse peripherals protocols ocpp auth) - -set_source_files_properties(lib/cAT/src/cat.c PROPERTIES COMPILE_FLAGS -Wno-maybe-uninitialized) \ No newline at end of file diff --git a/components/api/include/api.h b/components/api/include/api.h deleted file mode 100755 index e8d6bb8..0000000 --- a/components/api/include/api.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef API_H_ -#define API_H_ - -void api_init(void); - -#endif /* API_H_ */ \ No newline at end of file diff --git a/components/api/include/json.h b/components/api/include/json.h deleted file mode 100755 index 4c6efe9..0000000 --- a/components/api/include/json.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef JSON_UTILS_H -#define JSON_UTILS_H - -#include "esp_err.h" -#include "cJSON.h" - -cJSON* json_get_evse_config(void); - -esp_err_t json_set_evse_config(cJSON* root); - -cJSON* json_get_wifi_config(void); - -esp_err_t json_set_wifi_config(cJSON* root, bool timeout); - -//JSON* json_get_wifi_scan(void); - -cJSON* json_get_mqtt_config(void); - -esp_err_t json_set_mqtt_config(cJSON* root); - -//cJSON* json_get_serial_config(void); - -//esp_err_t json_set_serial_config(cJSON* root); - -cJSON* json_get_modbus_config(void); - -esp_err_t json_set_modbus_config(cJSON* root); - -//cJSON* json_get_script_config(void); - -//esp_err_t json_set_script_config(cJSON* root); - -cJSON* json_get_time_config(void); - -esp_err_t json_set_time_config(cJSON* root); - -cJSON* json_get_state(void); - -cJSON* json_get_info(void); - -cJSON* json_get_board_config(void); - -#endif /* JSON_UTILS_H */ diff --git a/components/api/include/ota.h b/components/api/include/ota.h deleted file mode 100755 index 38caa66..0000000 --- a/components/api/include/ota.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef OTA_H_ -#define OTA_H_ - -#include -#include "esp_err.h" - -#define OTA_VERSION_URL "https://dzurikmiroslav.github.io/esp32-evse/firmware/version.txt" - -#define OTA_FIRMWARE_URL "https://dzurikmiroslav.github.io/esp32-evse/firmware/" - -esp_err_t ota_get_available_version(char* version); - -bool ota_is_newer_version(const char* actual, const char* available); - -#endif /* OTA_H_ */ diff --git a/components/api/include/timeout_utils.h b/components/api/include/timeout_utils.h deleted file mode 100755 index 7551ca8..0000000 --- a/components/api/include/timeout_utils.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef TIMEOUT_UTILS_H -#define TIMEOUT_UTILS_H - -#include -#include "esp_err.h" - -/** - * @brief Restart in 5 seconds - * - */ -void timeout_restart(void); - -/** - * @brief Set WiFi config in 1 second - * - * @param enabled - * @param ssid - * @param password - * @return esp_err_t - */ -esp_err_t timeout_wifi_set_config(bool enabled, const char* ssid, const char* password); - -#endif /* TIMEOUT_UTILS_H */ diff --git a/components/api/lib/cAT/.clang-format b/components/api/lib/cAT/.clang-format deleted file mode 100755 index 031e2c3..0000000 --- a/components/api/lib/cAT/.clang-format +++ /dev/null @@ -1,493 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# clang-format configuration file. Intended for clang-format >= 4. -# -# For more information, see: -# -# Documentation/process/clang-format.rst -# https://clang.llvm.org/docs/ClangFormat.html -# https://clang.llvm.org/docs/ClangFormatStyleOptions.html -# ---- -AccessModifierOffset: -4 -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false -#AlignEscapedNewlines: Left # Unknown to clang-format-4.0 -AlignOperands: true -AlignTrailingComments: false -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: false -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: None -AllowShortIfStatementsOnASingleLine: false -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: false -BinPackArguments: true -BinPackParameters: true -BraceWrapping: - AfterClass: false - AfterControlStatement: false - AfterEnum: false - AfterFunction: true - AfterNamespace: true - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - #AfterExternBlock: false # Unknown to clang-format-5.0 - BeforeCatch: false - BeforeElse: false - IndentBraces: false - #SplitEmptyFunction: true # Unknown to clang-format-4.0 - #SplitEmptyRecord: true # Unknown to clang-format-4.0 - #SplitEmptyNamespace: true # Unknown to clang-format-4.0 -BreakBeforeBinaryOperators: None -BreakBeforeBraces: Custom -#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 -BreakBeforeTernaryOperators: false -BreakConstructorInitializersBeforeComma: false -#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0 -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: false -ColumnLimit: 160 -CommentPragmas: '^ IWYU pragma:' -#CompactNamespaces: false # Unknown to clang-format-4.0 -ConstructorInitializerAllOnOneLineOrOnePerLine: false -ConstructorInitializerIndentWidth: 8 -ContinuationIndentWidth: 8 -Cpp11BracedListStyle: false -DerivePointerAlignment: false -DisableFormat: false -ExperimentalAutoDetectBinPacking: false -#FixNamespaceComments: false # Unknown to clang-format-4.0 - -# Taken from: -# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \ -# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ -# | sort | uniq -ForEachMacros: - - 'apei_estatus_for_each_section' - - 'ata_for_each_dev' - - 'ata_for_each_link' - - '__ata_qc_for_each' - - 'ata_qc_for_each' - - 'ata_qc_for_each_raw' - - 'ata_qc_for_each_with_internal' - - 'ax25_for_each' - - 'ax25_uid_for_each' - - '__bio_for_each_bvec' - - 'bio_for_each_bvec' - - 'bio_for_each_integrity_vec' - - '__bio_for_each_segment' - - 'bio_for_each_segment' - - 'bio_for_each_segment_all' - - 'bio_list_for_each' - - 'bip_for_each_vec' - - 'blkg_for_each_descendant_post' - - 'blkg_for_each_descendant_pre' - - 'blk_queue_for_each_rl' - - 'bond_for_each_slave' - - 'bond_for_each_slave_rcu' - - 'bpf_for_each_spilled_reg' - - 'btree_for_each_safe128' - - 'btree_for_each_safe32' - - 'btree_for_each_safe64' - - 'btree_for_each_safel' - - 'card_for_each_dev' - - 'cgroup_taskset_for_each' - - 'cgroup_taskset_for_each_leader' - - 'cpufreq_for_each_entry' - - 'cpufreq_for_each_entry_idx' - - 'cpufreq_for_each_valid_entry' - - 'cpufreq_for_each_valid_entry_idx' - - 'css_for_each_child' - - 'css_for_each_descendant_post' - - 'css_for_each_descendant_pre' - - 'device_for_each_child_node' - - 'drm_atomic_crtc_for_each_plane' - - 'drm_atomic_crtc_state_for_each_plane' - - 'drm_atomic_crtc_state_for_each_plane_state' - - 'drm_atomic_for_each_plane_damage' - - 'drm_connector_for_each_possible_encoder' - - 'drm_for_each_connector_iter' - - 'drm_for_each_crtc' - - 'drm_for_each_encoder' - - 'drm_for_each_encoder_mask' - - 'drm_for_each_fb' - - 'drm_for_each_legacy_plane' - - 'drm_for_each_plane' - - 'drm_for_each_plane_mask' - - 'drm_for_each_privobj' - - 'drm_mm_for_each_hole' - - 'drm_mm_for_each_node' - - 'drm_mm_for_each_node_in_range' - - 'drm_mm_for_each_node_safe' - - 'flow_action_for_each' - - 'for_each_active_drhd_unit' - - 'for_each_active_iommu' - - 'for_each_available_child_of_node' - - 'for_each_bio' - - 'for_each_board_func_rsrc' - - 'for_each_bvec' - - 'for_each_card_components' - - 'for_each_card_links' - - 'for_each_card_links_safe' - - 'for_each_card_prelinks' - - 'for_each_card_rtds' - - 'for_each_card_rtds_safe' - - 'for_each_cgroup_storage_type' - - 'for_each_child_of_node' - - 'for_each_clear_bit' - - 'for_each_clear_bit_from' - - 'for_each_cmsghdr' - - 'for_each_compatible_node' - - 'for_each_component_dais' - - 'for_each_component_dais_safe' - - 'for_each_comp_order' - - 'for_each_console' - - 'for_each_cpu' - - 'for_each_cpu_and' - - 'for_each_cpu_not' - - 'for_each_cpu_wrap' - - 'for_each_dev_addr' - - 'for_each_dma_cap_mask' - - 'for_each_dpcm_be' - - 'for_each_dpcm_be_rollback' - - 'for_each_dpcm_be_safe' - - 'for_each_dpcm_fe' - - 'for_each_drhd_unit' - - 'for_each_dss_dev' - - 'for_each_efi_memory_desc' - - 'for_each_efi_memory_desc_in_map' - - 'for_each_element' - - 'for_each_element_extid' - - 'for_each_element_id' - - 'for_each_endpoint_of_node' - - 'for_each_evictable_lru' - - 'for_each_fib6_node_rt_rcu' - - 'for_each_fib6_walker_rt' - - 'for_each_free_mem_range' - - 'for_each_free_mem_range_reverse' - - 'for_each_func_rsrc' - - 'for_each_hstate' - - 'for_each_if' - - 'for_each_iommu' - - 'for_each_ip_tunnel_rcu' - - 'for_each_irq_nr' - - 'for_each_link_codecs' - - 'for_each_lru' - - 'for_each_matching_node' - - 'for_each_matching_node_and_match' - - 'for_each_memblock' - - 'for_each_memblock_type' - - 'for_each_memcg_cache_index' - - 'for_each_mem_pfn_range' - - 'for_each_mem_range' - - 'for_each_mem_range_rev' - - 'for_each_migratetype_order' - - 'for_each_msi_entry' - - 'for_each_msi_entry_safe' - - 'for_each_net' - - 'for_each_netdev' - - 'for_each_netdev_continue' - - 'for_each_netdev_continue_rcu' - - 'for_each_netdev_feature' - - 'for_each_netdev_in_bond_rcu' - - 'for_each_netdev_rcu' - - 'for_each_netdev_reverse' - - 'for_each_netdev_safe' - - 'for_each_net_rcu' - - 'for_each_new_connector_in_state' - - 'for_each_new_crtc_in_state' - - 'for_each_new_mst_mgr_in_state' - - 'for_each_new_plane_in_state' - - 'for_each_new_private_obj_in_state' - - 'for_each_node' - - 'for_each_node_by_name' - - 'for_each_node_by_type' - - 'for_each_node_mask' - - 'for_each_node_state' - - 'for_each_node_with_cpus' - - 'for_each_node_with_property' - - 'for_each_of_allnodes' - - 'for_each_of_allnodes_from' - - 'for_each_of_cpu_node' - - 'for_each_of_pci_range' - - 'for_each_old_connector_in_state' - - 'for_each_old_crtc_in_state' - - 'for_each_old_mst_mgr_in_state' - - 'for_each_oldnew_connector_in_state' - - 'for_each_oldnew_crtc_in_state' - - 'for_each_oldnew_mst_mgr_in_state' - - 'for_each_oldnew_plane_in_state' - - 'for_each_oldnew_plane_in_state_reverse' - - 'for_each_oldnew_private_obj_in_state' - - 'for_each_old_plane_in_state' - - 'for_each_old_private_obj_in_state' - - 'for_each_online_cpu' - - 'for_each_online_node' - - 'for_each_online_pgdat' - - 'for_each_pci_bridge' - - 'for_each_pci_dev' - - 'for_each_pci_msi_entry' - - 'for_each_populated_zone' - - 'for_each_possible_cpu' - - 'for_each_present_cpu' - - 'for_each_prime_number' - - 'for_each_prime_number_from' - - 'for_each_process' - - 'for_each_process_thread' - - 'for_each_property_of_node' - - 'for_each_registered_fb' - - 'for_each_reserved_mem_region' - - 'for_each_rtd_codec_dai' - - 'for_each_rtd_codec_dai_rollback' - - 'for_each_rtdcom' - - 'for_each_rtdcom_safe' - - 'for_each_set_bit' - - 'for_each_set_bit_from' - - 'for_each_sg' - - 'for_each_sg_dma_page' - - 'for_each_sg_page' - - 'for_each_sibling_event' - - 'for_each_subelement' - - 'for_each_subelement_extid' - - 'for_each_subelement_id' - - '__for_each_thread' - - 'for_each_thread' - - 'for_each_zone' - - 'for_each_zone_zonelist' - - 'for_each_zone_zonelist_nodemask' - - 'fwnode_for_each_available_child_node' - - 'fwnode_for_each_child_node' - - 'fwnode_graph_for_each_endpoint' - - 'gadget_for_each_ep' - - 'genradix_for_each' - - 'genradix_for_each_from' - - 'hash_for_each' - - 'hash_for_each_possible' - - 'hash_for_each_possible_rcu' - - 'hash_for_each_possible_rcu_notrace' - - 'hash_for_each_possible_safe' - - 'hash_for_each_rcu' - - 'hash_for_each_safe' - - 'hctx_for_each_ctx' - - 'hlist_bl_for_each_entry' - - 'hlist_bl_for_each_entry_rcu' - - 'hlist_bl_for_each_entry_safe' - - 'hlist_for_each' - - 'hlist_for_each_entry' - - 'hlist_for_each_entry_continue' - - 'hlist_for_each_entry_continue_rcu' - - 'hlist_for_each_entry_continue_rcu_bh' - - 'hlist_for_each_entry_from' - - 'hlist_for_each_entry_from_rcu' - - 'hlist_for_each_entry_rcu' - - 'hlist_for_each_entry_rcu_bh' - - 'hlist_for_each_entry_rcu_notrace' - - 'hlist_for_each_entry_safe' - - '__hlist_for_each_rcu' - - 'hlist_for_each_safe' - - 'hlist_nulls_for_each_entry' - - 'hlist_nulls_for_each_entry_from' - - 'hlist_nulls_for_each_entry_rcu' - - 'hlist_nulls_for_each_entry_safe' - - 'i3c_bus_for_each_i2cdev' - - 'i3c_bus_for_each_i3cdev' - - 'ide_host_for_each_port' - - 'ide_port_for_each_dev' - - 'ide_port_for_each_present_dev' - - 'idr_for_each_entry' - - 'idr_for_each_entry_continue' - - 'idr_for_each_entry_ul' - - 'inet_bind_bucket_for_each' - - 'inet_lhash2_for_each_icsk_rcu' - - 'key_for_each' - - 'key_for_each_safe' - - 'klp_for_each_func' - - 'klp_for_each_func_safe' - - 'klp_for_each_func_static' - - 'klp_for_each_object' - - 'klp_for_each_object_safe' - - 'klp_for_each_object_static' - - 'kvm_for_each_memslot' - - 'kvm_for_each_vcpu' - - 'list_for_each' - - 'list_for_each_codec' - - 'list_for_each_codec_safe' - - 'list_for_each_entry' - - 'list_for_each_entry_continue' - - 'list_for_each_entry_continue_rcu' - - 'list_for_each_entry_continue_reverse' - - 'list_for_each_entry_from' - - 'list_for_each_entry_from_rcu' - - 'list_for_each_entry_from_reverse' - - 'list_for_each_entry_lockless' - - 'list_for_each_entry_rcu' - - 'list_for_each_entry_reverse' - - 'list_for_each_entry_safe' - - 'list_for_each_entry_safe_continue' - - 'list_for_each_entry_safe_from' - - 'list_for_each_entry_safe_reverse' - - 'list_for_each_prev' - - 'list_for_each_prev_safe' - - 'list_for_each_safe' - - 'llist_for_each' - - 'llist_for_each_entry' - - 'llist_for_each_entry_safe' - - 'llist_for_each_safe' - - 'media_device_for_each_entity' - - 'media_device_for_each_intf' - - 'media_device_for_each_link' - - 'media_device_for_each_pad' - - 'mp_bvec_for_each_page' - - 'mp_bvec_for_each_segment' - - 'nanddev_io_for_each_page' - - 'netdev_for_each_lower_dev' - - 'netdev_for_each_lower_private' - - 'netdev_for_each_lower_private_rcu' - - 'netdev_for_each_mc_addr' - - 'netdev_for_each_uc_addr' - - 'netdev_for_each_upper_dev_rcu' - - 'netdev_hw_addr_list_for_each' - - 'nft_rule_for_each_expr' - - 'nla_for_each_attr' - - 'nla_for_each_nested' - - 'nlmsg_for_each_attr' - - 'nlmsg_for_each_msg' - - 'nr_neigh_for_each' - - 'nr_neigh_for_each_safe' - - 'nr_node_for_each' - - 'nr_node_for_each_safe' - - 'of_for_each_phandle' - - 'of_property_for_each_string' - - 'of_property_for_each_u32' - - 'pci_bus_for_each_resource' - - 'ping_portaddr_for_each_entry' - - 'plist_for_each' - - 'plist_for_each_continue' - - 'plist_for_each_entry' - - 'plist_for_each_entry_continue' - - 'plist_for_each_entry_safe' - - 'plist_for_each_safe' - - 'pnp_for_each_card' - - 'pnp_for_each_dev' - - 'protocol_for_each_card' - - 'protocol_for_each_dev' - - 'queue_for_each_hw_ctx' - - 'radix_tree_for_each_slot' - - 'radix_tree_for_each_tagged' - - 'rbtree_postorder_for_each_entry_safe' - - 'rdma_for_each_port' - - 'resource_list_for_each_entry' - - 'resource_list_for_each_entry_safe' - - 'rhl_for_each_entry_rcu' - - 'rhl_for_each_rcu' - - 'rht_for_each' - - 'rht_for_each_from' - - 'rht_for_each_entry' - - 'rht_for_each_entry_from' - - 'rht_for_each_entry_rcu' - - 'rht_for_each_entry_rcu_from' - - 'rht_for_each_entry_safe' - - 'rht_for_each_rcu' - - 'rht_for_each_rcu_from' - - '__rq_for_each_bio' - - 'rq_for_each_bvec' - - 'rq_for_each_segment' - - 'scsi_for_each_prot_sg' - - 'scsi_for_each_sg' - - 'sctp_for_each_hentry' - - 'sctp_skb_for_each' - - 'shdma_for_each_chan' - - '__shost_for_each_device' - - 'shost_for_each_device' - - 'sk_for_each' - - 'sk_for_each_bound' - - 'sk_for_each_entry_offset_rcu' - - 'sk_for_each_from' - - 'sk_for_each_rcu' - - 'sk_for_each_safe' - - 'sk_nulls_for_each' - - 'sk_nulls_for_each_from' - - 'sk_nulls_for_each_rcu' - - 'snd_array_for_each' - - 'snd_pcm_group_for_each_entry' - - 'snd_soc_dapm_widget_for_each_path' - - 'snd_soc_dapm_widget_for_each_path_safe' - - 'snd_soc_dapm_widget_for_each_sink_path' - - 'snd_soc_dapm_widget_for_each_source_path' - - 'tb_property_for_each' - - 'tcf_exts_for_each_action' - - 'udp_portaddr_for_each_entry' - - 'udp_portaddr_for_each_entry_rcu' - - 'usb_hub_for_each_child' - - 'v4l2_device_for_each_subdev' - - 'v4l2_m2m_for_each_dst_buf' - - 'v4l2_m2m_for_each_dst_buf_safe' - - 'v4l2_m2m_for_each_src_buf' - - 'v4l2_m2m_for_each_src_buf_safe' - - 'virtio_device_for_each_vq' - - 'xa_for_each' - - 'xa_for_each_marked' - - 'xa_for_each_start' - - 'xas_for_each' - - 'xas_for_each_conflict' - - 'xas_for_each_marked' - - 'zorro_for_each_dev' - -#IncludeBlocks: Preserve # Unknown to clang-format-5.0 -IncludeCategories: - - Regex: '.*' - Priority: 1 -IncludeIsMainRegex: '(Test)?$' -IndentCaseLabels: false -#IndentPPDirectives: None # Unknown to clang-format-5.0 -IndentWidth: 8 -IndentWrappedFunctionNames: false -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: false -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: Inner -#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 -ObjCBlockIndentWidth: 8 -ObjCSpaceAfterProperty: true -ObjCSpaceBeforeProtocolList: true - -# Taken from git's rules -#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0 -PenaltyBreakBeforeFirstCallParameter: 30 -PenaltyBreakComment: 10 -PenaltyBreakFirstLessLess: 0 -PenaltyBreakString: 10 -PenaltyExcessCharacter: 100 -PenaltyReturnTypeOnItsOwnLine: 60 - -PointerAlignment: Right -ReflowComments: false -SortIncludes: false -#SortUsingDeclarations: false # Unknown to clang-format-4.0 -SpaceAfterCStyleCast: false -SpaceAfterTemplateKeyword: true -SpaceBeforeAssignmentOperators: true -#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0 -#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0 -SpaceBeforeParens: ControlStatements -#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0 -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: false -SpacesInContainerLiterals: false -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: Cpp03 -TabWidth: 8 -UseTab: Never -... diff --git a/components/api/lib/cAT/.gitignore b/components/api/lib/cAT/.gitignore deleted file mode 100755 index 1755ab9..0000000 --- a/components/api/lib/cAT/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -.vscode -lib -bin -dist -build -CMakeLists.txt.user -CMakeCache.txt -CMakeFiles -CMakeScripts -Testing -Makefile -cmake_install.cmake -install_manifest.txt -compile_commands.json -CTestTestfile.cmake -_deps - diff --git a/components/api/lib/cAT/.travis.yml b/components/api/lib/cAT/.travis.yml deleted file mode 100755 index b90de1b..0000000 --- a/components/api/lib/cAT/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: c - -compiler: - - gcc - -before_script: - - mkdir build - - cd build - - cmake .. - -script: make && make test \ No newline at end of file diff --git a/components/api/lib/cAT/CMakeLists.txt b/components/api/lib/cAT/CMakeLists.txt deleted file mode 100755 index efb36c1..0000000 --- a/components/api/lib/cAT/CMakeLists.txt +++ /dev/null @@ -1,148 +0,0 @@ -cmake_minimum_required( VERSION 3.0 ) - -project( libcat LANGUAGES C ) - -set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) -set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) -set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) - -enable_testing( ) - -include_directories( ${PROJECT_SOURCE_DIR}/src ) - -file( GLOB SRC_FILES src/*.c ) -add_library( cat SHARED ${SRC_FILES} ) -set_target_properties( cat PROPERTIES VERSION 0.11.1 SOVERSION 1 ) -target_compile_options( cat PRIVATE -Werror -Wall -Wextra -pedantic ) - -install( TARGETS cat DESTINATION lib ) -install( FILES src/cat.h DESTINATION include/cat ) - -add_executable( demo example/demo.c ) -target_link_libraries( demo cat ) - -add_executable( basic example/basic.c ) -target_link_libraries( basic cat ) - -add_executable( unsolicited example/unsolicited.c ) -target_link_libraries( unsolicited cat ) - -add_executable( test_parse tests/test_parse.c ) -target_link_libraries( test_parse cat ) -add_test( test_parse ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_parse ) - -add_executable( test_run tests/test_run.c ) -target_link_libraries( test_run cat ) -add_test( test_run ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_run ) - -add_executable( test_read tests/test_read.c ) -target_link_libraries( test_read cat ) -add_test( test_read ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_read ) - -add_executable( test_write tests/test_write.c ) -target_link_libraries( test_write cat ) -add_test( test_write ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write ) - -add_executable( test_write_parse tests/test_write_parse.c ) -target_link_libraries( test_write_parse cat ) -add_test( test_write_parse ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write_parse ) - -add_executable( test_write_int_range tests/test_write_int_range.c ) -target_link_libraries( test_write_int_range cat ) -add_test( test_write_int_range ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write_int_range ) - -add_executable( test_write_uint_range tests/test_write_uint_range.c ) -target_link_libraries( test_write_uint_range cat ) -add_test( test_write_uint_range ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write_uint_range ) - -add_executable( test_write_hex_range tests/test_write_hex_range.c ) -target_link_libraries( test_write_hex_range cat ) -add_test( test_write_hex_range ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write_hex_range ) - -add_executable( test_write_hex_buffer tests/test_write_hex_buffer.c ) -target_link_libraries( test_write_hex_buffer cat ) -add_test( test_write_hex_buffer ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write_hex_buffer ) - -add_executable( test_write_string_buffer tests/test_write_string_buffer.c ) -target_link_libraries( test_write_string_buffer cat ) -add_test( test_write_string_buffer ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write_string_buffer ) - -add_executable( test_read_args tests/test_read_args.c ) -target_link_libraries( test_read_args cat ) -add_test( test_read_args ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_read_args ) - -add_executable( test_test tests/test_test.c ) -target_link_libraries( test_test cat ) -add_test( test_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_test ) - -add_executable( test_test_args tests/test_test_args.c ) -target_link_libraries( test_test_args cat ) -add_test( test_test_args ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_test_args ) - -add_executable( test_mutex tests/test_mutex.c ) -target_link_libraries( test_mutex cat ) -add_test( test_mutex ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_mutex ) - -add_executable( test_unsolicited_read tests/test_unsolicited_read.c ) -target_link_libraries( test_unsolicited_read cat ) -add_test( test_unsolicited_read ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_unsolicited_read ) - -add_executable( test_unsolicited_read_stress tests/test_unsolicited_read_stress.c ) -target_link_libraries( test_unsolicited_read_stress cat ) -add_test( test_unsolicited_read_stress ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_unsolicited_read_stress ) - -add_executable( test_unsolicited_read_buffer tests/test_unsolicited_read_buffer.c ${SRC_FILES}) -set_target_properties( test_unsolicited_read_buffer PROPERTIES COMPILE_DEFINITIONS "CAT_UNSOLICITED_CMD_BUFFER_SIZE=2" ) -add_test( test_unsolicited_read_buffer ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_unsolicited_read_buffer ) - -add_executable( test_hold_state tests/test_hold_state.c ) -target_link_libraries( test_hold_state cat ) -add_test( test_hold_state ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_hold_state ) - -add_executable( test_return_read tests/test_return_read.c ) -target_link_libraries( test_return_read cat ) -add_test( test_return_read ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_return_read ) - -add_executable( test_return_write tests/test_return_write.c ) -target_link_libraries( test_return_write cat ) -add_test( test_return_write ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_return_write ) - -add_executable( test_unsolicited_test tests/test_unsolicited_test.c ) -target_link_libraries( test_unsolicited_test cat ) -add_test( test_unsolicited_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_unsolicited_test ) - -add_executable( test_return_test tests/test_return_test.c ) -target_link_libraries( test_return_test cat ) -add_test( test_return_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_return_test ) - -add_executable( test_return_run tests/test_return_run.c ) -target_link_libraries( test_return_run cat ) -add_test( test_return_run ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_return_run ) - -add_executable( test_test_only tests/test_test_only.c ) -target_link_libraries( test_test_only cat ) -add_test( test_test_only ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_test_only ) - -add_executable( test_search_cmd tests/test_search_cmd.c ) -target_link_libraries( test_search_cmd cat ) -add_test( test_search_cmd ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_search_cmd ) - -add_executable( test_order tests/test_order.c ) -target_link_libraries( test_order cat ) -add_test( test_order ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_order ) - -add_executable( test_cmd_list tests/test_cmd_list.c ) -target_link_libraries( test_cmd_list cat ) -add_test( test_cmd_list ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_cmd_list ) - -add_executable( test_var_access tests/test_var_access.c ) -target_link_libraries( test_var_access cat ) -add_test( test_var_access ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_var_access ) - -add_executable( test_shortcuts tests/test_shortcuts.c ) -target_link_libraries( test_shortcuts cat ) -add_test( test_shortcuts ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_shortcuts ) - -add_custom_target( check COMMAND ${CMAKE_CTEST_COMMAND} --verbose ) -add_custom_target( cleanall COMMAND rm -rf Makefile CMakeCache.txt CMakeFiles/ bin/ lib/ cmake_install.cmake CTestTestfile.cmake Testing/ ) -add_custom_target( uninstall COMMAND xargs rm < install_manifest.txt ) \ No newline at end of file diff --git a/components/api/lib/cAT/LICENSE b/components/api/lib/cAT/LICENSE deleted file mode 100755 index e728f06..0000000 --- a/components/api/lib/cAT/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 Marcin Borowicz - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/components/api/lib/cAT/README.md b/components/api/lib/cAT/README.md deleted file mode 100755 index 089fe1f..0000000 --- a/components/api/lib/cAT/README.md +++ /dev/null @@ -1,211 +0,0 @@ -[![Build Status](https://travis-ci.org/marcinbor85/cat.svg?branch=master)](https://travis-ci.org/marcinbor85/cat) -# libcat (cAT) -Plain C library for parsing AT commands for use in host devices. - -## Features -* blazing fast, non-blocking, robust implementation -* 100% static implementation (without any dynamic memory allocation) -* very small footprint (both RAM and ROM) -* support for READ, WRITE, TEST and RUN type commands -* commands shortcuts (auto select best command candidate) -* single request - multiple responses -* unsolicited read/test command support -* hold state for delayed responses for time-consuming tasks -* high-level memory variables mapping arguments parsing -* variables accessors (read and write, read only, write only) -* automatic arguments types validating -* automatic format test responses for commands with variables -* CRLF and LF compatible -* case-insensitive -* dedicated for embedded systems -* object-oriented architecture -* separated interface for low-level layer -* fully asynchronous input/output operations -* multiplatform and portable -* asynchronous api with event callbacks -* print registered commands list feature -* only two source files -* wide unit tests - -## Build - -Build and install: - -```sh -cmake . -make -make test -sudo make install -``` - -## Example basic demo posibilities - -```console -AT+PRINT=? # TEST command -+PRINT=,, # Automatic response -Printing something special at (X,Y). # Automatic response -OK # Automatic acknowledge - -AT+PRINT? # READ command -+PRINT=0,0,"" # Automatic response -OK # Automatic acknowledge - -AT+PRINT=xyz,-2 # WRITE command -ERROR # Automatic acknowledge - -AT+PRINT=1,2,"test" # WRITE command -OK # Automatic acknowledge - -AT+PRINT # RUN command -some printing at (1,2) with text "test" # Manual response -OK # Automatic acknowledge -``` - -## Example unsolicited demo posibilities - -```console -AT+START=? # TEST command -+START= # Automatic response -Start scanning after write (0 - wifi, 1 - bluetooth). # Automatic response -OK # Automatic acknowledge - -AT+START=0 # WRITE command -+SCAN=-10,"wifi1" # Unsolicited read response -+SCAN=-50,"wifi2" # Unsolicited read response -+SCAN=-20,"wifi3" # Unsolicited read response -OK # Unsolicited acknowledge - -AT+START=1 # WRITE command -+SCAN=-20,"bluetooth1" # Unsolicited read response -OK # Unsolicited acknowledge - -AT+SCAN=? # TEST command -+SCAN=, # Automatic response -Scan result record. # Automatic response -OK # Automatic acknowledge -``` - -## Usage - -Define High-Level variables: - -```c - -static uint8_t x; -static uint8_t y; -static char msg[32]; - -static struct cat_variable go_vars[] = { - { - .type = CAT_VAR_UINT_DEC, /* unsigned int variable */ - .data = &x, - .data_size = sizeof(x), - .write = x_write, - .name = "X", - .access = CAT_VAR_ACCESS_READ_WRITE, - }, - { - .type = CAT_VAR_UINT_DEC, /* unsigned int variable */ - .data = &y, - .data_size = sizeof(y), - .write = y_write, - .access = CAT_VAR_ACCESS_READ_WRITE, - }, - { - .type = CAT_VAR_BUF_STRING, /* string variable */ - .data = msg, - .data_size = sizeof(msg), - .write = msg_write, - .access = CAT_VAR_ACCESS_READ_WRITE, - } -}; -``` - -Define AT commands descriptor: - -```c -static struct cat_command cmds[] = { - { - .name = "TEST", - .read = test_read, /* read handler for ATTEST? command */ - .write = test_write, /* write handler for ATTEST={val} command */ - .run = test_run /* run handler for ATTEST command */ - }, - { - .name = "+NUM", - .write = num_write, /* write handler for AT+NUM={val} command */ - .read = num_read /* read handler for AT+NUM? command */ - }, - { - .name = "+GO", - .write = go_write, /* write handler for AT+GO={x},{y},{msg} command */ - .var = go_vars, /* attach variables to command */ - .var_num = sizeof(go_vars) / sizeof(go_vars[0]), - .need_all_vars = true - }, - { - .name = "RESTART", - .run = restart_run /* run handler for ATRESTART command */ - } -}; -``` - -Define AT command parser descriptor: - -```c - -static char working_buf[128]; /* working buffer, must be declared manually */ - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = working_buf, - .buf_size = sizeof(working_buf), -}; -``` - -Define IO low-level layer interface: - -```c -static int write_char(char ch) -{ - putc(ch, stdout); - return 1; -} - -static int read_char(char *ch) -{ - *ch = getch(); - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; -``` - -Initialize AT command parser and run: - -```c -struct cat_object at; /* at command parser object */ - -cat_init(&at, &desc, &iface, NULL); /* initialize at command parser object */ - -while (1) { - cat_service(&at) /* periodically call at command parser service */ - - ... /* other stuff, running in main loop */ -} - -``` diff --git a/components/api/lib/cAT/changelog.txt b/components/api/lib/cAT/changelog.txt deleted file mode 100755 index 4c0d0ed..0000000 --- a/components/api/lib/cAT/changelog.txt +++ /dev/null @@ -1,70 +0,0 @@ -TODO: -- differentation of variables for read and write commands -- help command (printing all commands posibilities with descriptions) -- documentation updated (buffer sized, return enum types, write variable nums, buf size hints) -- helper setters and getters for variables - -0.11.0 -* optional context in commands and data_getter in variables -* optional extended read and write variable handler with parent command - -0.10.1 -* single working buffer insteads of two separated for atcmd and unsolicited events - -0.10.0 -* separate atcmd and unsolicited event state machines - -0.9.0 -* variables accessors - -0.8.1 -* fix commands shourtcuts - -0.8.0 -* print commands list feature - -0.7.1 -* more flexible command group initialization (pointers) - -0.7.0 -* function for checking unsolicited buffer -* some refactoring regarding unsolicited buffer -* helper function cat_search_variable_by_name added -* commands group with searching feature added -* disable feature for commands and groups added - -0.6.0 -* async non blocking io->write -* async unsolicited read/test event (injected at idle and hold state) -* hold commands parse processing feature (for delayed unsolicited read responses) -* behavior differentation by callbacks return values -* only-test flag in commands descriptor (for fast disable read/write/run) -* helper function for searching command by name -* multiple responses triggered by single request pattern support -* generic mutex descriptor interface -* return value states enum types - -0.5.3 -* function for checking internal busy state added - -0.5.2 -* small fix in auto description response - -0.5.1 -* description field in command added (used in auto help message) - -0.5.0 -* test command parser with auto help messages -* output string end-line encoding same as input string -* very basic demo example application added - -0.4.0 -* high level parsing for command arguments -* int, uint, hex, hexbuf, string argument types -* validating arguments values range - -0.3.0 -* independent buffers (parsing buffer and state buffer) - -0.2.0 -* passing command struct instead of command name in command handlers \ No newline at end of file diff --git a/components/api/lib/cAT/example/basic.c b/components/api/lib/cAT/example/basic.c deleted file mode 100755 index 5f0c865..0000000 --- a/components/api/lib/cAT/example/basic.c +++ /dev/null @@ -1,161 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -/* variables assigned to print command */ -static uint8_t x; -static uint8_t y; -static char message[16]; - -/* helper variable used to exit demo code */ -static bool quit_flag; - -/* run command handler with application dependent login print code */ -static int print_run(const struct cat_command *cmd) -{ - printf("some printing at (%d,%d) with text \"%s\"\n", x, y, message); - return 0; -} - -/* run command handler attached to HELP command for printing commands list */ -static int print_cmd_list(const struct cat_command *cmd) -{ - return CAT_RETURN_STATE_PRINT_CMD_LIST_OK; -} - -/* run command handler with custom exit mechanism */ -static int quit_run(const struct cat_command *cmd) -{ - quit_flag = true; - return 0; -} - -/* declaring print variables array */ -static struct cat_variable print_vars[] = { - { - .type = CAT_VAR_UINT_DEC, - .data = &x, - .data_size = sizeof(x), - .name = "X", - .access = CAT_VAR_ACCESS_READ_WRITE, - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &y, - .data_size = sizeof(y), - .name = "Y", - .access = CAT_VAR_ACCESS_READ_WRITE, - }, - { - .type = CAT_VAR_BUF_STRING, - .data = message, - .data_size = sizeof(message), - .name = "MESSAGE", - .access = CAT_VAR_ACCESS_READ_WRITE, - } -}; - -/* declaring commands array */ -static struct cat_command cmds[] = { - { - .name = "+PRINT", - .description = "Printing something special at (X,Y).", - .run = print_run, - .var = print_vars, - .var_num = sizeof(print_vars) / sizeof(print_vars[0]), - .need_all_vars = true - }, - { - .name = "#HELP", - .run = print_cmd_list, - }, - { - .name = "#QUIT", - .run = quit_run - }, -}; - -/* working buffer */ -static char buf[128]; - -/* declaring parser descriptor */ -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -/* custom target dependent input output handlers */ -static int write_char(char ch) -{ - putc(ch, stdout); - return 1; -} - -static int read_char(char *ch) -{ - *ch = getc(stdin); - return 1; -} - -/* declaring input output interface descriptor for parser */ -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -int main(int argc, char **argv) -{ - struct cat_object at; - - /* initializing */ - cat_init(&at, &desc, &iface, NULL); - - /* main loop with exit code conditions */ - while ((cat_service(&at) != 0) && (quit_flag == 0)) {}; - - /* goodbye message */ - printf("Bye!\n"); - - return 0; -} diff --git a/components/api/lib/cAT/example/demo.c b/components/api/lib/cAT/example/demo.c deleted file mode 100755 index 3ea778b..0000000 --- a/components/api/lib/cAT/example/demo.c +++ /dev/null @@ -1,260 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static int32_t speed; -static uint16_t adr; -static uint8_t x; -static uint8_t y; -static uint8_t bytes_buf[4]; -static char msg[16]; -static bool quit_flag; - -static int x_write(const struct cat_variable *var, size_t write_size) -{ - printf("x variable updated internally to: %u\n", x); - return 0; -} - -static int y_write(const struct cat_variable *var, size_t write_size) -{ - printf("y variable updated internally to: %u\n", y); - return 0; -} - -static int msg_write(const struct cat_variable *var, size_t write_size) -{ - printf("msg variable updated %lu bytes internally to: <%s>\n", write_size, msg); - return 0; -} - -static int speed_write(const struct cat_variable *var, size_t write_size) -{ - printf("speed variable updated internally to: %d\n", speed); - return 0; -} - -static int adr_write(const struct cat_variable *var, size_t write_size) -{ - printf("adr variable updated internally to: 0x%04X\n", adr); - return 0; -} - -static int bytesbuf_write(const struct cat_variable *var, size_t write_size) -{ - int i = 0; - - printf("bytes_buf variable updated %lu bytes internally to: ", write_size); - for (i = 0; i < sizeof(bytes_buf); i++) - printf("%02X", bytes_buf[i]); - printf("\n"); - - return 0; -} - -static int go_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - int i = 0; - - printf("<%s>: x=%d y=%d msg=%s @ speed=%d\n", - cmd->name, - *(uint8_t*)(cmd->var[0].data), - *(uint8_t*)(cmd->var[1].data), - msg, - speed - ); - - printf(": "); - for (i = 0; i < sizeof(bytes_buf); i++) - printf("%02X", bytes_buf[i]); - printf("\n"); - return 0; -} - -static int set_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - printf("<%s>: SET SPEED TO = %d\n", - cmd->name, - speed - ); - return 0; -} - -static int set_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - return 0; -} - -static int test_run(const struct cat_command *cmd) -{ - printf("TEST: <%s>", cmd->name); - return 0; -} - -static int quit_run(const struct cat_command *cmd) -{ - printf("QUIT: <%s>", cmd->name); - quit_flag = true; - return 0; -} - -static int print_cmd_list(const struct cat_command *cmd) -{ - return CAT_RETURN_STATE_PRINT_CMD_LIST_OK; -} - -static struct cat_variable go_vars[] = { - { - .type = CAT_VAR_UINT_DEC, - .data = &x, - .data_size = sizeof(x), - .write = x_write, - .name = "x" - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &y, - .data_size = sizeof(y), - .write = y_write, - .name = "y" - }, - { - .type = CAT_VAR_BUF_STRING, - .data = msg, - .data_size = sizeof(msg), - .write = msg_write, - .name = "msg" - } -}; - -static struct cat_variable set_vars[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &speed, - .data_size = sizeof(speed), - .write = speed_write, - .name = "speed" - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &adr, - .data_size = sizeof(adr), - .write = adr_write, - .name = "address" - }, - { - .type = CAT_VAR_BUF_HEX, - .data = &bytes_buf, - .data_size = sizeof(bytes_buf), - .write = bytesbuf_write, - .name = "buffer" - } -}; - -static struct cat_command cmds[] = { - { - .name = "+GO", - .write = go_write, - .var = go_vars, - .var_num = sizeof(go_vars) / sizeof(go_vars[0]), - .need_all_vars = true - }, - { - .name = "+SET", - .write = set_write, - .read = set_read, - .var = set_vars, - .var_num = sizeof(set_vars) / sizeof(set_vars[0]), - }, - { - .name = "#TEST", - .run = test_run - }, - { - .name = "#HELP", - .run = print_cmd_list, - }, - { - .name = "#QUIT", - .run = quit_run - }, - -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - putc(ch, stdout); - return 1; -} - -static int read_char(char *ch) -{ - *ch = getc(stdin); - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - while ((cat_service(&at) != 0) && (quit_flag == 0)) {}; - - printf("Bye!\n"); - - return 0; -} diff --git a/components/api/lib/cAT/example/unsolicited.c b/components/api/lib/cAT/example/unsolicited.c deleted file mode 100755 index 0ce2098..0000000 --- a/components/api/lib/cAT/example/unsolicited.c +++ /dev/null @@ -1,251 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -/* variables assigned to scan command */ -static int rssi; -static char ssid[16]; - -/* helper variable used to exit demo code */ -static bool quit_flag; - -/* variables assigned to start command */ -static int mode; - -/* main at command parser object */ -struct cat_object at; - -struct scan_results { - int rssi; - char ssid[16]; -}; - -/* static const scan results */ -static const struct scan_results results[2][3] = { - { - { - .rssi = -10, - .ssid = "wifi1", - }, - { - .rssi = -50, - .ssid = "wifi2", - }, - { - .rssi = -20, - .ssid = "wifi3", - } - }, - { - { - .rssi = -20, - .ssid = "bluetooth1", - } - } -}; - -/* helper variable */ -static int scan_index; - -/* run command handler with custom exit mechanism */ -static int quit_run(const struct cat_command *cmd) -{ - quit_flag = true; - return 0; -} - -/* helper function */ -static void load_scan_results(int index) -{ - rssi = results[mode][index].rssi; - strcpy(ssid, results[mode][index].ssid); -} - -/* declaring scan variables array */ -static struct cat_variable scan_vars[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &rssi, - .data_size = sizeof(rssi), - .name = "RSSI" - }, - { - .type = CAT_VAR_BUF_STRING, - .data = ssid, - .data_size = sizeof(ssid), - .name = "SSID" - } -}; - -/* forward declaration */ -static cat_return_state scan_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size); - -/* unsolicited command */ -static struct cat_command scan_cmd = { - .name = "+SCAN", - .read = scan_read, - .var = scan_vars, - .var_num = sizeof(scan_vars) / sizeof(scan_vars[0]) -}; - -/* unsolicited read callback handler */ -static cat_return_state scan_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - int max = (mode == 0) ? 3 : 1; - - scan_index++; - if (scan_index > max) - return CAT_RETURN_STATE_HOLD_EXIT_OK; - - load_scan_results(scan_index); - cat_trigger_unsolicited_read(&at, &scan_cmd); - - return CAT_RETURN_STATE_DATA_NEXT; -} - -/* mode variable validator */ -static int mode_write(const struct cat_variable *var, const size_t write_size) -{ - if (*(int*)var->data >= 2) - return -1; - return 0; -} - -/* start write callback handler */ -static cat_return_state start_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - scan_index = 0; - - load_scan_results(scan_index); - cat_trigger_unsolicited_read(&at, &scan_cmd); - - return CAT_RETURN_STATE_HOLD; -} - -/* run command handler attached to HELP command for printing commands list */ -static int print_cmd_list(const struct cat_command *cmd) -{ - return CAT_RETURN_STATE_PRINT_CMD_LIST_OK; -} - -/* declaring start command variables array */ -static struct cat_variable start_vars[] = { - { - .type = CAT_VAR_UINT_DEC, - .data = &mode, - .data_size = sizeof(mode), - .name = "MODE", - .write = mode_write, - .access = CAT_VAR_ACCESS_WRITE_ONLY, - } -}; - -/* declaring commands array */ -static struct cat_command cmds[] = { - { - .name = "+START", - .description = "Start scanning after write (0 - wifi, 1 - bluetooth).", - .write = start_write, - .var = start_vars, - .var_num = sizeof(start_vars) / sizeof(start_vars[0]), - .need_all_vars = true - }, - { - .name = "+SCAN", - .description = "Scan result record.", - .only_test = true, - .var = scan_vars, - .var_num = sizeof(scan_vars) / sizeof(scan_vars[0]) - }, - { - .name = "#HELP", - .run = print_cmd_list, - }, - { - .name = "#QUIT", - .run = quit_run - }, -}; - -/* working buffer */ -static char buf[128]; - -/* declaring parser descriptor */ -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -/* custom target dependent input output handlers */ -static int write_char(char ch) -{ - putc(ch, stdout); - return 1; -} - -static int read_char(char *ch) -{ - *ch = getc(stdin); - return 1; -} - -/* declaring input output interface descriptor for parser */ -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -int main(int argc, char **argv) -{ - /* initializing */ - cat_init(&at, &desc, &iface, NULL); - - /* main loop with exit code conditions */ - while ((cat_service(&at) != 0) && (quit_flag == 0)) {}; - - /* goodbye message */ - printf("Bye!\n"); - - return 0; -} diff --git a/components/api/lib/cAT/src/cat.c b/components/api/lib/cAT/src/cat.c deleted file mode 100755 index 0369c95..0000000 --- a/components/api/lib/cAT/src/cat.c +++ /dev/null @@ -1,2757 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include "cat.h" - -#include -#include - -#define CAT_CMD_STATE_NOT_MATCH (0) -#define CAT_CMD_STATE_PARTIAL_MATCH (1U) -#define CAT_CMD_STATE_FULL_MATCH (2U) - -#define CAT_WRITE_STATE_BEFORE (0) -#define CAT_WRITE_STATE_MAIN_BUFFER (1U) -#define CAT_WRITE_STATE_AFTER (2U) - -static inline char* get_atcmd_buf(struct cat_object *self) -{ - return (char*)self->desc->buf; -} - -static inline size_t get_atcmd_buf_size(struct cat_object *self) -{ - return (self->desc->unsolicited_buf != NULL) ? self->desc->buf_size : self->desc->buf_size >> 1; -} - -static inline char* get_unsolicited_buf(struct cat_object *self) -{ - return (self->desc->unsolicited_buf != NULL) ? (char*)self->desc->unsolicited_buf : (char*)&self->desc->buf[self->desc->buf_size >> 1]; -} - -static inline size_t get_unsolicited_buf_size(struct cat_object *self) -{ - return (self->desc->unsolicited_buf != NULL) ? self->desc->unsolicited_buf_size : self->desc->buf_size >> 1; -} - -static struct cat_variable* get_var_by_fsm(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - return (struct cat_variable*)self->var; - case CAT_FSM_TYPE_UNSOLICITED: - return (struct cat_variable*)self->unsolicited_fsm.var; - default: - assert(false); - } - - return NULL; -} - -static struct cat_command* get_command_by_fsm(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - return (struct cat_command*)self->cmd; - case CAT_FSM_TYPE_UNSOLICITED: - return (struct cat_command*)self->unsolicited_fsm.cmd; - default: - assert(false); - } - - return NULL; -} - -static inline void* get_var_data(struct cat_object *self, cat_fsm_type fsm) -{ - size_t dummy; - void *data; - struct cat_variable *var = get_var_by_fsm(self, fsm); - struct cat_command *cmd = get_command_by_fsm(self, fsm); - - if (var->data_getter == NULL) { - data = var->data; - } else { - data = var->data_getter(var, cmd->context, &dummy); - } - return data; -} - -static inline size_t get_var_data_size(struct cat_object *self, cat_fsm_type fsm) -{ - size_t data_size; - struct cat_variable *var = get_var_by_fsm(self, fsm); - struct cat_command *cmd = get_command_by_fsm(self, fsm); - - if (var->data_getter == NULL) { - data_size = var->data_size; - } else { - var->data_getter(var, cmd->context, &data_size); - } - return data_size; -} - -static char to_upper(char ch) -{ - return (ch >= 'a' && ch <= 'z') ? ch - ('a' - 'A') : ch; -} - -static void reset_state(struct cat_object *self) -{ - assert(self != NULL); - - if (self->hold_state_flag == false) { - self->state = CAT_STATE_IDLE; - self->cr_flag = false; - } else { - self->state = CAT_STATE_HOLD; - } - self->cmd = NULL; - self->cmd_type = CAT_CMD_TYPE_NONE; -} - -static void unsolicited_reset_state(struct cat_object *self) -{ - assert(self != NULL); - - self->unsolicited_fsm.cmd = NULL; - self->unsolicited_fsm.cmd_type = CAT_CMD_TYPE_NONE; - self->unsolicited_fsm.state = CAT_UNSOLICITED_STATE_IDLE; -} - -static cat_status is_busy(struct cat_object *self) -{ - return (self->state != CAT_STATE_IDLE) ? CAT_STATUS_BUSY : CAT_STATUS_OK; -} - -cat_status cat_is_busy(struct cat_object *self) -{ - cat_status s; - - assert(self != NULL); - - if ((self->mutex != NULL) && (self->mutex->lock() != 0)) - return CAT_STATUS_ERROR_MUTEX_LOCK; - - s = is_busy(self); - - if ((self->mutex != NULL) && (self->mutex->unlock() != 0)) - return CAT_STATUS_ERROR_MUTEX_UNLOCK; - - return s; -} - -static cat_status is_hold(struct cat_object *self) -{ - return (self->hold_state_flag != false) ? CAT_STATUS_HOLD : CAT_STATUS_OK; -} - -cat_status cat_is_hold(struct cat_object *self) -{ - cat_status s; - - assert(self != NULL); - - if ((self->mutex != NULL) && (self->mutex->lock() != 0)) - return CAT_STATUS_ERROR_MUTEX_LOCK; - - s = is_hold(self); - - if ((self->mutex != NULL) && (self->mutex->unlock() != 0)) - return CAT_STATUS_ERROR_MUTEX_UNLOCK; - - return s; -} - -static bool is_variables_access_possible(struct cat_object *self, const struct cat_command *cmd, cat_var_access access) -{ - size_t i; - bool ok; - struct cat_variable const *var; - (void)self; - - if (cmd->var == NULL) - return false; - - ok = false; - for (i = 0; i < cmd->var_num; i++) { - var = &cmd->var[i]; - if ((var->access == CAT_VAR_ACCESS_READ_WRITE) || (var->access == access)) { - ok = true; - break; - } - } - - return ok; -} - -static bool is_unsolicited_buffer_full(struct cat_object *self) -{ - assert(self != NULL); - - return (self->unsolicited_fsm.unsolicited_cmd_buffer_items_count == CAT_UNSOLICITED_CMD_BUFFER_SIZE) ? true : false; -} - -static bool is_unsolicited_buffer_empty(struct cat_object *self) -{ - assert(self != NULL); - - return (self->unsolicited_fsm.unsolicited_cmd_buffer_items_count == 0) ? true : false; -} - -static cat_status pop_unsolicited_cmd(struct cat_object *self, struct cat_command const **cmd, cat_cmd_type *type) -{ - struct cat_unsolicited_cmd *item; - - assert(self != NULL); - assert(cmd != NULL); - assert(type != NULL); - - if (is_unsolicited_buffer_empty(self) != false) - return CAT_STATUS_ERROR_BUFFER_EMPTY; - - item = &self->unsolicited_fsm.unsolicited_cmd_buffer[self->unsolicited_fsm.unsolicited_cmd_buffer_head]; - - *cmd = item->cmd; - *type = item->type; - - if (++self->unsolicited_fsm.unsolicited_cmd_buffer_head >= CAT_UNSOLICITED_CMD_BUFFER_SIZE) - self->unsolicited_fsm.unsolicited_cmd_buffer_head = 0; - - self->unsolicited_fsm.unsolicited_cmd_buffer_items_count--; - - return CAT_STATUS_OK; -} - -static cat_status push_unsolicited_cmd(struct cat_object *self, struct cat_command const *cmd, cat_cmd_type type) -{ - struct cat_unsolicited_cmd *item; - - assert(self != NULL); - assert(cmd != NULL); - assert(((type == CAT_CMD_TYPE_READ) || (type == CAT_CMD_TYPE_TEST))); - - if (is_unsolicited_buffer_full(self) != false) - return CAT_STATUS_ERROR_BUFFER_FULL; - - item = &self->unsolicited_fsm.unsolicited_cmd_buffer[self->unsolicited_fsm.unsolicited_cmd_buffer_tail]; - - item->cmd = cmd; - item->type = type; - - if (++self->unsolicited_fsm.unsolicited_cmd_buffer_tail >= CAT_UNSOLICITED_CMD_BUFFER_SIZE) - self->unsolicited_fsm.unsolicited_cmd_buffer_tail = 0; - - self->unsolicited_fsm.unsolicited_cmd_buffer_items_count++; - - return CAT_STATUS_OK; -} - -cat_status cat_is_unsolicited_buffer_full(struct cat_object *self) -{ - bool s; - - assert(self != NULL); - - if ((self->mutex != NULL) && (self->mutex->lock() != 0)) - return CAT_STATUS_ERROR_MUTEX_LOCK; - - s = is_unsolicited_buffer_full(self); - - if ((self->mutex != NULL) && (self->mutex->unlock() != 0)) - return CAT_STATUS_ERROR_MUTEX_UNLOCK; - - return (s != false) ? CAT_STATUS_ERROR_BUFFER_FULL : CAT_STATUS_OK; -} - -struct cat_command const* cat_get_processed_command(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - return get_command_by_fsm(self, fsm); -} - -cat_status cat_is_unsolicited_event_buffered(struct cat_object *self, struct cat_command const *cmd, cat_cmd_type type) -{ - assert(self != NULL); - assert(cmd != NULL); - assert(type < CAT_CMD_TYPE__TOTAL_NUM); - - size_t num = self->unsolicited_fsm.unsolicited_cmd_buffer_items_count; - size_t index = self->unsolicited_fsm.unsolicited_cmd_buffer_head; - cat_status ret = CAT_STATUS_OK; - struct cat_unsolicited_cmd *item; - - if ((self->unsolicited_fsm.cmd == cmd) && ((type == CAT_CMD_TYPE_NONE) || (self->unsolicited_fsm.cmd_type == type))) - ret = CAT_STATUS_BUSY; - - while ((num > 0) && (ret == CAT_STATUS_OK)) { - item = &self->unsolicited_fsm.unsolicited_cmd_buffer[index]; - if ((item->cmd == cmd) && ((type == CAT_CMD_TYPE_NONE) || (item->type == type))) - ret = CAT_STATUS_BUSY; - - --num; - if (++index >= CAT_UNSOLICITED_CMD_BUFFER_SIZE) - index = 0; - } - - return ret; -} - -static const char *get_new_line_chars(struct cat_object *self) -{ - static const char *crlf = "\r\n"; - return &crlf[(self->cr_flag != false) ? 0 : 1]; -} - -static void start_flush_io_buffer(struct cat_object *self, cat_state state_after) -{ - assert(self != NULL); - - self->position = 0; - self->write_buf = get_new_line_chars(self); - self->write_state = CAT_WRITE_STATE_BEFORE; - self->write_state_after = state_after; - self->state = CAT_STATE_FLUSH_IO_WRITE_WAIT; -} - -static void unsolicited_start_flush_io_buffer(struct cat_object *self, cat_unsolicited_state state_after) -{ - assert(self != NULL); - - self->unsolicited_fsm.position = 0; - self->unsolicited_fsm.write_buf = get_new_line_chars(self); - self->unsolicited_fsm.write_state = CAT_WRITE_STATE_BEFORE; - self->unsolicited_fsm.write_state_after = state_after; - self->unsolicited_fsm.state = CAT_UNSOLICITED_STATE_FLUSH_IO_WRITE_WAIT; -} - -static void start_flush_io_buffer_raw(struct cat_object *self, cat_state state_after) -{ - assert(self != NULL); - - self->position = 0; - self->write_buf = get_atcmd_buf(self); - self->write_state = CAT_WRITE_STATE_AFTER; - self->write_state_after = state_after; - self->state = CAT_STATE_FLUSH_IO_WRITE_WAIT; -} - -static void ack_error(struct cat_object *self) -{ - assert(self != NULL); - - strncpy(get_atcmd_buf(self), "ERROR", get_atcmd_buf_size(self)); - start_flush_io_buffer(self, CAT_STATE_AFTER_FLUSH_RESET); - return; -} - -static void ack_ok(struct cat_object *self) -{ - assert(self != NULL); - - strncpy(get_atcmd_buf(self), "OK", get_atcmd_buf_size(self)); - start_flush_io_buffer(self, CAT_STATE_AFTER_FLUSH_RESET); - return; -} - -static size_t get_left_buffer_space_by_fsm(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - return get_atcmd_buf_size(self) - self->position; - case CAT_FSM_TYPE_UNSOLICITED: - return get_unsolicited_buf_size(self) - self->unsolicited_fsm.position; - default: - assert(false); - } - - return 0; -} - -static char* get_current_buffer_by_fsm(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - return &(get_atcmd_buf(self)[self->position]); - case CAT_FSM_TYPE_UNSOLICITED: - return &(get_unsolicited_buf(self)[self->unsolicited_fsm.position]); - default: - assert(false); - } - - return NULL; -} - -static void move_position_by_fsm(struct cat_object *self, size_t offset, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - self->position += offset; - break; - case CAT_FSM_TYPE_UNSOLICITED: - self->unsolicited_fsm.position += offset; - break; - default: - assert(false); - } -} - -static int print_string_to_buf(struct cat_object *self, const char *str, cat_fsm_type fsm) -{ - int written; - size_t len; - - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - len = get_left_buffer_space_by_fsm(self, fsm); - written = snprintf(get_current_buffer_by_fsm(self, fsm), len, "%s", str); - - if ((written < 0) || ((size_t)written >= len)) - return -1; - - move_position_by_fsm(self, written, fsm); - return 0; -} - -static int read_cmd_char(struct cat_object *self) -{ - assert(self != NULL); - - if (self->io->read(&self->current_char) == 0) - return 0; - - if (self->state != CAT_STATE_PARSE_COMMAND_ARGS) - self->current_char = to_upper(self->current_char); - - return 1; -} - -static struct cat_command const* get_command_by_index(struct cat_object *self, size_t index) -{ - size_t i, j; - struct cat_command_group const *cmd_group; - - assert(self != NULL); - assert(index < self->commands_num); - - j = 0; - for (i = 0; i < self->desc->cmd_group_num; i++) { - cmd_group = self->desc->cmd_group[i]; - - if (index >= j + cmd_group->cmd_num) { - j += cmd_group->cmd_num; - continue; - } - - return &cmd_group->cmd[index - j]; - } - - return NULL; -} - -static void unsolicited_init(struct cat_object *self) -{ - self->unsolicited_fsm.unsolicited_cmd_buffer_tail = 0; - self->unsolicited_fsm.unsolicited_cmd_buffer_head = 0; - self->unsolicited_fsm.unsolicited_cmd_buffer_items_count = 0; - - unsolicited_reset_state(self); -} - -void cat_init(struct cat_object *self, const struct cat_descriptor *desc, const struct cat_io_interface *io, const struct cat_mutex_interface *mutex) -{ - size_t i, j; - struct cat_command_group const *cmd_group; - - assert(self != NULL); - assert(desc != NULL); - assert(io != NULL); - - assert(desc->cmd_group != NULL); - assert(desc->cmd_group_num > 0); - - self->commands_num = 0; - for (i = 0; i < desc->cmd_group_num; i++) { - cmd_group = desc->cmd_group[i]; - - assert(cmd_group->cmd != NULL); - assert(cmd_group->cmd_num > 0); - - self->commands_num += cmd_group->cmd_num; - - for (j = 0; j < cmd_group->cmd_num; j++) - assert(cmd_group->cmd[j].name != NULL); - } - - assert(desc->buf != NULL); - assert(desc->buf_size * 4U >= self->commands_num); - - self->desc = desc; - self->io = io; - self->mutex = mutex; - self->hold_state_flag = false; - self->hold_exit_status = 0; - - reset_state(self); - - unsolicited_init(self); -} - -static cat_status error_state(struct cat_object *self) -{ - assert(self != NULL); - - if (read_cmd_char(self) == 0) - return CAT_STATUS_OK; - - switch (self->current_char) { - case '\n': - ack_error(self); - break; - case '\r': - self->cr_flag = true; - break; - default: - break; - } - return CAT_STATUS_BUSY; -} - -static void prepare_parse_command(struct cat_object *self) -{ - uint8_t val = (CAT_CMD_STATE_PARTIAL_MATCH << 0) | (CAT_CMD_STATE_PARTIAL_MATCH << 2) | (CAT_CMD_STATE_PARTIAL_MATCH << 4) | - (CAT_CMD_STATE_PARTIAL_MATCH << 6); - - assert(self != NULL); - - memset(get_atcmd_buf(self), val, get_atcmd_buf_size(self)); - - self->index = 0; - self->length = 0; - self->cmd_type = CAT_CMD_TYPE_RUN; -} - -static cat_status parse_prefix(struct cat_object *self) -{ - assert(self != NULL); - - if (read_cmd_char(self) == 0) - return CAT_STATUS_OK; - - switch (self->current_char) { - case 'T': - prepare_parse_command(self); - self->state = CAT_STATE_PARSE_COMMAND_CHAR; - break; - case '\n': - ack_error(self); - break; - case '\r': - self->cr_flag = true; - break; - default: - self->state = CAT_STATE_ERROR; - break; - } - - return CAT_STATUS_BUSY; -} - -static void prepare_search_command(struct cat_object *self) -{ - assert(self != NULL); - - self->index = 0; - self->partial_cntr = 0; - self->cmd = NULL; -} - -static int is_valid_cmd_name_char(const char ch) -{ - return (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '+') || (ch == '#') || (ch == '$') || (ch == '@') || (ch == '_'); -} - -static int is_valid_dec_char(const char ch) -{ - return (ch >= '0' && ch <= '9'); -} - -static int is_valid_hex_char(const char ch) -{ - return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F'); -} - -static uint8_t convert_hex_char_to_value(const char ch) -{ - return ((ch >= '0') && (ch <= '9')) ? (uint8_t)(ch - '0') : (uint8_t)(ch - 'A' + 10U); -} - - -static void end_processing_with_error(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - ack_error(self); - break; - case CAT_FSM_TYPE_UNSOLICITED: - unsolicited_reset_state(self); - break; - default: - assert(false); - } -} - -static void end_processing_with_ok(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - ack_ok(self); - break; - case CAT_FSM_TYPE_UNSOLICITED: - unsolicited_reset_state(self); - break; - default: - assert(false); - } -} - -static void reset_position(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - self->position = 0; - break; - case CAT_FSM_TYPE_UNSOLICITED: - self->unsolicited_fsm.position = 0; - break; - default: - assert(false); - } -} - -static int print_response_test(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - struct cat_command *cmd = get_command_by_fsm(self, fsm); - - if (cmd->description != NULL) { - if (print_string_to_buf(self, get_new_line_chars(self), fsm) != 0) - return -1; - if (print_string_to_buf(self, cmd->description, fsm) != 0) - return -1; - } - - if (cmd->test != NULL) { - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - self->state = CAT_STATE_TEST_LOOP; - break; - case CAT_FSM_TYPE_UNSOLICITED: - self->unsolicited_fsm.state = CAT_UNSOLICITED_STATE_TEST_LOOP; - break; - default: - assert(false); - } - return 0; - } - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - start_flush_io_buffer(self, CAT_STATE_AFTER_FLUSH_OK); - break; - case CAT_FSM_TYPE_UNSOLICITED: - unsolicited_start_flush_io_buffer(self, CAT_UNSOLICITED_STATE_AFTER_FLUSH_OK); - break; - default: - assert(false); - } - - return 0; -} - -static cat_status parse_command(struct cat_object *self) -{ - assert(self != NULL); - - if (read_cmd_char(self) == 0) - return CAT_STATUS_OK; - - switch (self->current_char) { - case '\n': - if (self->length != 0) { - prepare_search_command(self); - self->state = CAT_STATE_SEARCH_COMMAND; - break; - } - ack_ok(self); - break; - case '\r': - self->cr_flag = true; - break; - case '?': - if (self->length == 0) { - self->state = CAT_STATE_ERROR; - break; - } - self->cmd_type = CAT_CMD_TYPE_READ; - self->state = CAT_STATE_WAIT_READ_ACKNOWLEDGE; - break; - case '=': - if (self->length == 0) { - self->state = CAT_STATE_ERROR; - break; - } - self->cmd_type = CAT_CMD_TYPE_WRITE; - prepare_search_command(self); - self->state = CAT_STATE_SEARCH_COMMAND; - break; - default: - if (is_valid_cmd_name_char(self->current_char) != 0) { - self->length++; - self->state = CAT_STATE_UPDATE_COMMAND_STATE; - break; - } - self->state = CAT_STATE_ERROR; - break; - } - return CAT_STATUS_BUSY; -} - -static bool is_command_disable(struct cat_object *self, size_t index) -{ - size_t i, j; - struct cat_command_group const *cmd_group; - - assert(self != NULL); - assert(index < self->commands_num); - - j = 0; - for (i = 0; i < self->desc->cmd_group_num; i++) { - cmd_group = self->desc->cmd_group[i]; - - if (index >= j + cmd_group->cmd_num) { - j += cmd_group->cmd_num; - continue; - } - - if (cmd_group->disable != false) - return true; - - if (cmd_group->cmd[index - j].disable != false) - return true; - } - - return false; -} - -static uint8_t get_cmd_state(struct cat_object *self, size_t i) -{ - uint8_t s; - - assert(self != NULL); - assert(i < self->commands_num); - - s = get_atcmd_buf(self)[i >> 2]; - s >>= (i % 4) << 1; - s &= 0x03; - - if (is_command_disable(self, i) != false) - return CAT_CMD_STATE_NOT_MATCH; - - return s; -} - -static void set_cmd_state(struct cat_object *self, size_t i, uint8_t state) -{ - uint8_t s; - size_t n; - uint8_t k; - - n = i >> 2; - k = ((i % 4) << 1); - - s = get_atcmd_buf(self)[n]; - s &= ~(0x03 << k); - s |= (state & 0x03) << k; - get_atcmd_buf(self)[n] = s; -} - -static cat_status update_command(struct cat_object *self) -{ - assert(self != NULL); - - struct cat_command const *cmd = get_command_by_index(self, self->index); - size_t cmd_name_len; - - if (get_cmd_state(self, self->index) != CAT_CMD_STATE_NOT_MATCH) { - cmd_name_len = strlen(cmd->name); - - if (self->length > cmd_name_len) { - set_cmd_state(self, self->index, CAT_CMD_STATE_NOT_MATCH); - } else if (to_upper(cmd->name[self->length - 1]) != self->current_char) { - set_cmd_state(self, self->index, CAT_CMD_STATE_NOT_MATCH); - } else if (self->length == cmd_name_len) { - set_cmd_state(self, self->index, CAT_CMD_STATE_FULL_MATCH); - } - } - - if (++self->index >= self->commands_num) { - self->index = 0; - self->state = CAT_STATE_PARSE_COMMAND_CHAR; - } - - return CAT_STATUS_BUSY; -} - -static cat_status wait_read_acknowledge(struct cat_object *self) -{ - assert(self != NULL); - - if (read_cmd_char(self) == 0) - return CAT_STATUS_OK; - - switch (self->current_char) { - case '\n': - prepare_search_command(self); - self->state = CAT_STATE_SEARCH_COMMAND; - break; - case '\r': - self->cr_flag = true; - break; - default: - self->state = CAT_STATE_ERROR; - break; - } - return CAT_STATUS_BUSY; -} - -static void start_processing_format_test_args(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - reset_position(self, fsm); - - struct cat_command *cmd = get_command_by_fsm(self, fsm); - - if (print_string_to_buf(self, cmd->name, fsm) != 0) { - end_processing_with_error(self, fsm); - return; - } - - if (print_string_to_buf(self, "=", fsm) != 0) { - end_processing_with_error(self, fsm); - return; - } - - if ((cmd->var != NULL) && (cmd->var_num > 0)) { - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - self->state = CAT_STATE_FORMAT_TEST_ARGS; - self->index = 0; - self->var = cmd->var; - break; - case CAT_FSM_TYPE_UNSOLICITED: - self->unsolicited_fsm.state = CAT_UNSOLICITED_STATE_FORMAT_TEST_ARGS; - self->unsolicited_fsm.index = 0; - self->unsolicited_fsm.var = cmd->var; - break; - default: - assert(false); - } - return; - } - - if (print_response_test(self, fsm) == 0) - return; - - end_processing_with_error(self, fsm); -} - -static cat_status wait_test_acknowledge(struct cat_object *self) -{ - assert(self != NULL); - - if (read_cmd_char(self) == 0) - return CAT_STATUS_OK; - - switch (self->current_char) { - case '\n': - start_processing_format_test_args(self, CAT_FSM_TYPE_ATCMD); - break; - case '\r': - self->cr_flag = true; - break; - default: - self->state = CAT_STATE_ERROR; - break; - } - return CAT_STATUS_BUSY; -} - -static cat_status search_command(struct cat_object *self) -{ - assert(self != NULL); - - uint8_t cmd_state = get_cmd_state(self, self->index); - - if (cmd_state != CAT_CMD_STATE_NOT_MATCH) { - if (cmd_state == CAT_CMD_STATE_PARTIAL_MATCH) { - if ((self->cmd != NULL) && ((self->index + 1) == self->commands_num)) { - self->state = (self->current_char == '\n') ? CAT_STATE_COMMAND_NOT_FOUND : CAT_STATE_ERROR; - return CAT_STATUS_BUSY; - } - self->cmd = get_command_by_index(self, self->index); - self->partial_cntr++; - } else if (cmd_state == CAT_CMD_STATE_FULL_MATCH) { - self->cmd = get_command_by_index(self, self->index); - self->state = CAT_STATE_COMMAND_FOUND; - return CAT_STATUS_BUSY; - } - } - - if (++self->index >= self->commands_num) { - if (self->cmd == NULL) { - self->state = (self->current_char == '\n') ? CAT_STATE_COMMAND_NOT_FOUND : CAT_STATE_ERROR; - } else { - self->state = (self->partial_cntr == 1) ? CAT_STATE_COMMAND_FOUND : CAT_STATE_COMMAND_NOT_FOUND; - } - } - - return CAT_STATUS_BUSY; -} - -static void start_processing_format_read_args(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - reset_position(self, fsm); - - struct cat_command *cmd = get_command_by_fsm(self, fsm); - - if (print_string_to_buf(self, cmd->name, fsm) != 0) { - end_processing_with_error(self, fsm); - return; - } - - if (print_string_to_buf(self, "=", fsm) != 0) { - end_processing_with_error(self, fsm); - return; - } - - if (is_variables_access_possible(self, cmd, CAT_VAR_ACCESS_READ_ONLY) != false) { - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - self->state = CAT_STATE_FORMAT_READ_ARGS; - self->index = 0; - self->var = cmd->var; - break; - case CAT_FSM_TYPE_UNSOLICITED: - self->unsolicited_fsm.state = CAT_UNSOLICITED_STATE_FORMAT_READ_ARGS; - self->unsolicited_fsm.index = 0; - self->unsolicited_fsm.var = cmd->var; - break; - default: - assert(false); - } - - return; - } - if (cmd->read == NULL) { - end_processing_with_error(self, fsm); - return; - } - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - self->state = CAT_STATE_READ_LOOP; - break; - case CAT_FSM_TYPE_UNSOLICITED: - self->unsolicited_fsm.state = CAT_UNSOLICITED_STATE_READ_LOOP; - break; - default: - assert(false); - } -} - -static cat_status command_found(struct cat_object *self) -{ - assert(self != NULL); - - switch (self->cmd_type) { - case CAT_CMD_TYPE_RUN: - if (self->cmd->only_test != false) { - ack_error(self); - break; - } - if (self->cmd->run == NULL) { - ack_error(self); - break; - } - - self->state = CAT_STATE_RUN_LOOP; - break; - case CAT_CMD_TYPE_READ: - if (self->cmd->only_test != false) { - ack_error(self); - break; - } - start_processing_format_read_args(self, CAT_FSM_TYPE_ATCMD); - break; - case CAT_CMD_TYPE_WRITE: - self->length = 0; - get_atcmd_buf(self)[0] = 0; - self->state = CAT_STATE_PARSE_COMMAND_ARGS; - break; - default: - ack_error(self); - break; - } - - return CAT_STATUS_BUSY; -} - -static cat_status command_not_found(struct cat_object *self) -{ - assert(self != NULL); - - ack_error(self); - return CAT_STATUS_BUSY; -} - -static int parse_int_decimal(struct cat_object *self, int64_t *ret) -{ - assert(self != NULL); - assert(ret != NULL); - - char ch; - int64_t val = 0; - int64_t sign = 0; - int ok = 0; - - while (1) { - ch = get_atcmd_buf(self)[self->position++]; - - if ((ok != 0) && ((ch == 0) || (ch == ','))) { - val *= sign; - *ret = val; - return (ch == ',') ? 1 : 0; - } - - if (sign == 0) { - if (ch == '-') { - sign = -1; - } else if (ch == '+') { - sign = 1; - } else if (is_valid_dec_char(ch) != 0) { - sign = 1; - val = ch - '0'; - ok = 1; - } else { - return -1; - } - } else { - if (is_valid_dec_char(ch) != 0) { - ok = 1; - val *= 10; - val += ch - '0'; - } else { - return -1; - } - } - } - - return -1; -} - -static int parse_uint_decimal(struct cat_object *self, uint64_t *ret) -{ - assert(self != NULL); - assert(ret != NULL); - - char ch; - uint64_t val = 0; - int ok = 0; - - while (1) { - ch = get_atcmd_buf(self)[self->position++]; - - if ((ok != 0) && ((ch == 0) || (ch == ','))) { - *ret = val; - return (ch == ',') ? 1 : 0; - } - - if (is_valid_dec_char(ch) != 0) { - ok = 1; - val *= 10; - val += ch - '0'; - } else { - return -1; - } - } - - return -1; -} - -static int parse_num_hexadecimal(struct cat_object *self, uint64_t *ret) -{ - assert(self != NULL); - assert(ret != NULL); - - char ch; - uint64_t val = 0; - int state = 0; - - while (1) { - ch = get_atcmd_buf(self)[self->position++]; - ch = to_upper(ch); - - if ((state >= 3) && ((ch == 0) || (ch == ','))) { - *ret = val; - return (ch == ',') ? 1 : 0; - } - - if (state == 0) { - if (ch != '0') - return -1; - state = 1; - } else if (state == 1) { - if (ch != 'X') - return -1; - state = 2; - } else if (state >= 2) { - if (is_valid_hex_char(ch) != 0) { - state = 3; - val <<= 4; - val += convert_hex_char_to_value(ch); - } else { - return -1; - } - } - } - - return -1; -} - -static int parse_buffer_hexadecimal(struct cat_object *self) -{ - assert(self != NULL); - - char ch; - uint8_t byte = 0; - int state = 0; - size_t size = 0; - size_t var_size = get_var_data_size(self, CAT_FSM_TYPE_ATCMD); - - while (1) { - ch = get_atcmd_buf(self)[self->position++]; - ch = to_upper(ch); - - if ((size > 0) && (state == 0) && ((ch == 0) || (ch == ','))) { - if (self->var->access == CAT_VAR_ACCESS_READ_ONLY) { - self->write_size = 0; - } else { - self->write_size = size; - } - return (ch == ',') ? 1 : 0; - } - - if (is_valid_hex_char(ch) == 0) - return -1; - - byte <<= 4; - byte += convert_hex_char_to_value(ch); - - if (state != 0) { - if (var_size > 0) { - if (size >= var_size) - return -1; - if (self->var->access == CAT_VAR_ACCESS_READ_ONLY) { - size++; - } else { - ((uint8_t*)get_var_data(self, CAT_FSM_TYPE_ATCMD))[size++] = byte; - } - } else { - size++; - } - byte = 0; - } - - state = !state; - } - - return -1; -} - -static int parse_buffer_string(struct cat_object *self) -{ - assert(self != NULL); - - char ch; - int state = 0; - size_t size = 0; - size_t var_size = get_var_data_size(self, CAT_FSM_TYPE_ATCMD); - - while (1) { - ch = get_atcmd_buf(self)[self->position++]; - - switch (state) { - case 0: - if (ch != '"') - return -1; - state = 1; - break; - case 1: - if (ch == 0) - return -1; - if (ch == '\\') { - state = 2; - break; - } - if (ch == '"') { - state = 3; - break; - } - if (var_size > 0) { - if (size >= var_size) - return -1; - if (self->var->access == CAT_VAR_ACCESS_READ_ONLY) { - size++; - } else { - ((char*)get_var_data(self, CAT_FSM_TYPE_ATCMD))[size++] = ch; - } - } else { - size++; - } - break; - case 2: - switch (ch) { - case '\\': - ch = '\\'; - break; - case '"': - ch = '"'; - break; - case 'n': - ch = '\n'; - break; - default: - return -1; - } - if (var_size > 0) { - if (size >= var_size) - return -1; - if (self->var->access == CAT_VAR_ACCESS_READ_ONLY) { - size++; - } else { - ((char*)get_var_data(self, CAT_FSM_TYPE_ATCMD))[size++] = ch; - } - } else { - size++; - } - state = 1; - break; - case 3: - if ((ch == 0) || (ch == ',')) { - if (var_size > 0) { - if (size >= var_size) - return -1; - if (self->var->access == CAT_VAR_ACCESS_READ_ONLY) { - self->write_size = 0; - } else { - ((char*)get_var_data(self, CAT_FSM_TYPE_ATCMD))[size] = 0; - self->write_size = size; - } - } else { - self->write_size = 0; - } - return (ch == ',') ? 1 : 0; - } else { - return -1; - } - break; - } - } - - return -1; -} - -static int validate_int_range(struct cat_object *self, int64_t val) -{ - if (self->var->access == CAT_VAR_ACCESS_READ_ONLY) { - self->write_size = 0; - return 0; - } - - size_t data_size = get_var_data_size(self, CAT_FSM_TYPE_ATCMD); - uint8_t *data = get_var_data(self, CAT_FSM_TYPE_ATCMD); - - switch (data_size) { - case 1: - if ((val < INT8_MIN) || (val > INT8_MAX)) - return -1; - *(int8_t *)(data) = val; - break; - case 2: - if ((val < INT16_MIN) || (val > INT16_MAX)) - return -1; - *(int16_t *)(data) = val; - break; - case 4: - if ((val < INT32_MIN) || (val > INT32_MAX)) - return -1; - *(int32_t *)(data) = val; - break; - default: - self->write_size = 0; - return 0; - } - self->write_size = data_size; - return 0; -} - -static int validate_uint_range(struct cat_object *self, uint64_t val) -{ - if (self->var->access == CAT_VAR_ACCESS_READ_ONLY) { - self->write_size = 0; - return 0; - } - - size_t data_size = get_var_data_size(self, CAT_FSM_TYPE_ATCMD); - uint8_t *data = get_var_data(self, CAT_FSM_TYPE_ATCMD); - - switch (data_size) { - case 1: - if (val > UINT8_MAX) - return -1; - *(uint8_t *)(data) = val; - break; - case 2: - if (val > UINT16_MAX) - return -1; - *(uint16_t *)(data) = val; - break; - case 4: - if (val > UINT32_MAX) - return -1; - *(uint32_t *)(data) = val; - break; - default: - self->write_size = 0; - return 0; - } - self->write_size = data_size; - return 0; -} - -static cat_status parse_write_args(struct cat_object *self) -{ - int64_t val; - cat_status stat; - - assert(self != NULL); - - switch (self->var->type) { - case CAT_VAR_INT_DEC: - stat = parse_int_decimal(self, &val); - if (stat < 0) { - ack_error(self); - return CAT_STATUS_BUSY; - } - if (validate_int_range(self, val) != 0) { - ack_error(self); - return CAT_STATUS_BUSY; - } - break; - case CAT_VAR_UINT_DEC: - stat = parse_uint_decimal(self, (uint64_t *)&val); - if (stat < 0) { - ack_error(self); - return CAT_STATUS_BUSY; - } - if (validate_uint_range(self, val) != 0) { - ack_error(self); - return CAT_STATUS_BUSY; - } - break; - case CAT_VAR_NUM_HEX: - stat = parse_num_hexadecimal(self, (uint64_t *)&val); - if (stat < 0) { - ack_error(self); - return CAT_STATUS_BUSY; - } - if (validate_uint_range(self, val) != 0) { - ack_error(self); - return CAT_STATUS_BUSY; - } - break; - case CAT_VAR_BUF_HEX: - stat = parse_buffer_hexadecimal(self); - if (stat < 0) { - ack_error(self); - return CAT_STATUS_BUSY; - } - break; - case CAT_VAR_BUF_STRING: - stat = parse_buffer_string(self); - if (stat < 0) { - ack_error(self); - return CAT_STATUS_BUSY; - } - break; - } - - if ((self->var->write != NULL) || (self->var->write_ex != NULL)) { - if (self->var->write != NULL) { - if (self->var->write(self->var, self->write_size) != 0) { - ack_error(self); - return CAT_STATUS_BUSY; - } - } else { - if (self->var->write_ex(self->var, self->cmd, self->write_size) != 0) { - ack_error(self); - return CAT_STATUS_BUSY; - } - } - } - - if ((++self->index < self->cmd->var_num) && (stat > 0)) { - self->var = &self->cmd->var[self->index]; - return CAT_STATUS_BUSY; - } - - if (stat > 0) { - ack_error(self); - return CAT_STATUS_BUSY; - } - - if ((self->cmd->need_all_vars != false) && (self->index != self->cmd->var_num)) { - ack_error(self); - return CAT_STATUS_BUSY; - } - - if (self->cmd->write == NULL) { - ack_ok(self); - return CAT_STATUS_BUSY; - } - - self->state = CAT_STATE_WRITE_LOOP; - return CAT_STATUS_BUSY; -} - -static int print_format_num(struct cat_object *self, char *fmt, uint32_t val, cat_fsm_type fsm) -{ - int written; - size_t len; - - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - len = get_left_buffer_space_by_fsm(self, fsm); - written = snprintf(get_current_buffer_by_fsm(self, fsm), len, fmt, val); - - if ((written < 0) || ((size_t)written >= len)) - return -1; - - move_position_by_fsm(self, written, fsm); - return 0; -} - -static int format_int_decimal(struct cat_object *self, cat_fsm_type fsm) -{ - int32_t val; - - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - struct cat_variable *var = get_var_by_fsm(self, fsm); - - size_t data_size = get_var_data_size(self, fsm); - uint8_t *data = get_var_data(self, fsm); - - switch (data_size) { - case 1: - val = *(int8_t *)data; - break; - case 2: - val = *(int16_t *)data; - break; - case 4: - val = *(int32_t *)data; - break; - default: - return -1; - } - - if (var->access == CAT_VAR_ACCESS_WRITE_ONLY) - val = 0; - - if (print_format_num(self, "%d", val, fsm) != 0) - return -1; - - return 0; -} - -static int format_uint_decimal(struct cat_object *self, cat_fsm_type fsm) -{ - uint32_t val; - - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - struct cat_variable *var = get_var_by_fsm(self, fsm); - - size_t data_size = get_var_data_size(self, fsm); - uint8_t *data = get_var_data(self, fsm); - - switch (data_size) { - case 1: - val = *(uint8_t *)data; - break; - case 2: - val = *(uint16_t *)data; - break; - case 4: - val = *(uint32_t *)data; - break; - default: - return -1; - } - - if (var->access == CAT_VAR_ACCESS_WRITE_ONLY) - val = 0; - - if (print_format_num(self, "%u", val, fsm) != 0) - return -1; - - return 0; -} - -static int format_num_hexadecimal(struct cat_object *self, cat_fsm_type fsm) -{ - uint32_t val; - char fstr[8]; - - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - struct cat_variable *var = get_var_by_fsm(self, fsm); - - size_t data_size = get_var_data_size(self, fsm); - uint8_t *data = get_var_data(self, fsm); - - switch (data_size) { - case 1: - val = *(uint8_t *)data; - strcpy(fstr, "0x%02X"); - break; - case 2: - val = *(uint16_t *)data; - strcpy(fstr, "0x%04X"); - break; - case 4: - val = *(uint32_t *)data; - strcpy(fstr, "0x%08X"); - break; - default: - return -1; - } - - if (var->access == CAT_VAR_ACCESS_WRITE_ONLY) - val = 0; - - if (print_format_num(self, fstr, val, fsm) != 0) - return -1; - - return 0; -} - -static int format_buffer_hexadecimal(struct cat_object *self, cat_fsm_type fsm) -{ - size_t i; - uint8_t *buf; - uint8_t val; - - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - struct cat_variable *var = get_var_by_fsm(self, fsm); - - size_t data_size = get_var_data_size(self, fsm); - - buf = get_var_data(self, fsm); - for (i = 0; i < data_size; i++) { - if (var->access == CAT_VAR_ACCESS_WRITE_ONLY) { - val = 0; - } else { - val = buf[i]; - } - - if (print_format_num(self, "%02X", val, fsm) != 0) - return -1; - } - return 0; -} - -static int format_buffer_string(struct cat_object *self, cat_fsm_type fsm) -{ - size_t i = 0; - char *buf; - size_t buf_size; - char ch; - - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - struct cat_variable *var = get_var_by_fsm(self, fsm); - - if (var->access == CAT_VAR_ACCESS_WRITE_ONLY) { - buf_size = 0; - } else { - buf_size = get_var_data_size(self, fsm); - } - - if (print_string_to_buf(self, "\"", fsm) != 0) - return -1; - - buf = (char*)get_var_data(self, fsm); - for (i = 0; i < buf_size; i++) { - ch = buf[i]; - if (ch == 0) - break; - if (ch == '\\') { - if (print_string_to_buf(self, "\\\\", fsm) != 0) - return -1; - } else if (ch == '"') { - if (print_string_to_buf(self, "\\\"", fsm) != 0) - return -1; - } else if (ch == '\n') { - if (print_string_to_buf(self, "\\n", fsm) != 0) - return -1; - } else { - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - if (self->position >= get_atcmd_buf_size(self)) - return -1; - get_atcmd_buf(self)[self->position++] = ch; - if (self->position >= get_atcmd_buf_size(self)) - return -1; - get_atcmd_buf(self)[self->position] = 0; - break; - case CAT_FSM_TYPE_UNSOLICITED: - if (self->unsolicited_fsm.position >= get_unsolicited_buf_size(self)) - return -1; - get_unsolicited_buf(self)[self->unsolicited_fsm.position++] = ch; - if (self->unsolicited_fsm.position >= get_unsolicited_buf_size(self)) - return -1; - get_unsolicited_buf(self)[self->unsolicited_fsm.position] = 0; - break; - default: - assert(false); - } - } - } - - if (print_string_to_buf(self, "\"", fsm) != 0) - return -1; - - return 0; -} - -static int format_info_type(struct cat_object *self, cat_fsm_type fsm) -{ - char var_type[8]; - char accessor[8]; - - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - struct cat_variable *var = get_var_by_fsm(self, fsm); - - switch (var->access) { - case CAT_VAR_ACCESS_READ_WRITE: - strcpy(accessor, "RW"); - break; - case CAT_VAR_ACCESS_READ_ONLY: - strcpy(accessor, "RO"); - break; - case CAT_VAR_ACCESS_WRITE_ONLY: - strcpy(accessor, "WO"); - break; - default: - strcpy(accessor, "??"); - break; - } - - size_t data_size = get_var_data_size(self, fsm); - - switch (var->type) { - case CAT_VAR_INT_DEC: - switch (data_size) { - case 1: - strcpy(var_type, "INT8"); - break; - case 2: - strcpy(var_type, "INT16"); - break; - case 4: - strcpy(var_type, "INT32"); - break; - default: - return -1; - } - break; - case CAT_VAR_UINT_DEC: - switch (data_size) { - case 1: - strcpy(var_type, "UINT8"); - break; - case 2: - strcpy(var_type, "UINT16"); - break; - case 4: - strcpy(var_type, "UINT32"); - break; - default: - return -1; - } - break; - case CAT_VAR_NUM_HEX: - switch (data_size) { - case 1: - strcpy(var_type, "HEX8"); - break; - case 2: - strcpy(var_type, "HEX16"); - break; - case 4: - strcpy(var_type, "HEX32"); - break; - default: - return -1; - } - break; - case CAT_VAR_BUF_HEX: - strcpy(var_type, "HEXBUF"); - break; - case CAT_VAR_BUF_STRING: - strcpy(var_type, "STRING"); - break; - } - - if (print_string_to_buf(self, "<", fsm) != 0) - return -1; - if (var->name != NULL) { - if (print_string_to_buf(self, var->name, fsm) != 0) - return -1; - if (print_string_to_buf(self, ":", fsm) != 0) - return -1; - } - if (print_string_to_buf(self, var_type, fsm) != 0) - return -1; - if (print_string_to_buf(self, "[", fsm) != 0) - return -1; - if (print_string_to_buf(self, accessor, fsm) != 0) - return -1; - if (print_string_to_buf(self, "]", fsm) != 0) - return -1; - if (print_string_to_buf(self, ">", fsm) != 0) - return -1; - - return 0; -} - -static cat_status next_format_var_by_fsm(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - struct cat_command *cmd = get_command_by_fsm(self, fsm); - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - if (++self->index < cmd->var_num) { - if (self->position >= get_atcmd_buf_size(self)) { - end_processing_with_error(self, fsm); - return CAT_STATUS_BUSY; - } - get_atcmd_buf(self)[self->position++] = ','; - self->var = &cmd->var[self->index]; - return CAT_STATUS_BUSY; - } - break; - case CAT_FSM_TYPE_UNSOLICITED: - if (++self->unsolicited_fsm.index < cmd->var_num) { - if (self->unsolicited_fsm.position >= get_unsolicited_buf_size(self)) { - end_processing_with_error(self, fsm); - return CAT_STATUS_BUSY; - } - get_unsolicited_buf(self)[self->unsolicited_fsm.position++] = ','; - self->unsolicited_fsm.var = &cmd->var[self->unsolicited_fsm.index]; - return CAT_STATUS_BUSY; - } - break; - default: - assert(false); - } - - return CAT_STATUS_OK; -} - -static cat_status format_read_args(struct cat_object *self, cat_fsm_type fsm) -{ - cat_status stat; - - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - struct cat_variable *var = get_var_by_fsm(self, fsm); - - if ((var->read != NULL) || (var->read_ex != NULL)) { - if (var->read != NULL) { - if (var->read(var) != 0) { - end_processing_with_error(self, fsm); - return CAT_STATUS_BUSY; - } - } else { - if (var->read_ex(var, get_command_by_fsm(self, fsm)) != 0) { - end_processing_with_error(self, fsm); - return CAT_STATUS_BUSY; - } - } - } - - switch (var->type) { - case CAT_VAR_INT_DEC: - stat = format_int_decimal(self, fsm); - break; - case CAT_VAR_UINT_DEC: - stat = format_uint_decimal(self, fsm); - break; - case CAT_VAR_NUM_HEX: - stat = format_num_hexadecimal(self, fsm); - break; - case CAT_VAR_BUF_HEX: - stat = format_buffer_hexadecimal(self, fsm); - break; - case CAT_VAR_BUF_STRING: - stat = format_buffer_string(self, fsm); - break; - } - - if (stat < 0) { - end_processing_with_error(self, fsm); - return CAT_STATUS_BUSY; - } - - stat = next_format_var_by_fsm(self, fsm); - if (stat != CAT_STATUS_OK) - return stat; - - struct cat_command *cmd = get_command_by_fsm(self, fsm); - - if (cmd->read != NULL) { - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - self->state = CAT_STATE_READ_LOOP; - break; - case CAT_FSM_TYPE_UNSOLICITED: - self->unsolicited_fsm.state = CAT_UNSOLICITED_STATE_READ_LOOP; - break; - default: - assert(false); - } - - return CAT_STATUS_BUSY; - } - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - start_flush_io_buffer(self, CAT_STATE_AFTER_FLUSH_OK); - break; - case CAT_FSM_TYPE_UNSOLICITED: - unsolicited_start_flush_io_buffer(self, CAT_UNSOLICITED_STATE_AFTER_FLUSH_OK); - break; - default: - assert(false); - } - - return CAT_STATUS_BUSY; -} - -static cat_status format_test_args(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - if (format_info_type(self, fsm) < 0) { - end_processing_with_error(self, fsm); - return CAT_STATUS_BUSY; - } - - cat_status stat = next_format_var_by_fsm(self, fsm); - if (stat != CAT_STATUS_OK) - return stat; - - if (print_response_test(self, fsm) == 0) - return CAT_STATUS_BUSY; - - end_processing_with_error(self, fsm); - return CAT_STATUS_BUSY; -} - -static cat_status parse_command_args(struct cat_object *self) -{ - assert(self != NULL); - - if (read_cmd_char(self) == 0) - return CAT_STATUS_OK; - - switch (self->current_char) { - case '\n': - if (self->cmd->only_test != false) { - ack_error(self); - break; - } - if (is_variables_access_possible(self, self->cmd, CAT_VAR_ACCESS_WRITE_ONLY) != false) { - self->state = CAT_STATE_PARSE_WRITE_ARGS; - self->position = 0; - self->index = 0; - self->var = &self->cmd->var[self->index]; - break; - } - if (self->cmd->write == NULL) { - ack_error(self); - break; - } - self->index = 0; - self->state = CAT_STATE_WRITE_LOOP; - break; - case '\r': - self->cr_flag = true; - break; - default: - if ((self->length == 0) && (self->current_char == '?')) { - if ((self->cmd->test != NULL) || ((self->cmd->var != NULL) && (self->cmd->var_num > 0))) { - self->cmd_type = CAT_CMD_TYPE_TEST; - self->state = CAT_STATE_WAIT_TEST_ACKNOWLEDGE; - break; - } - } - - if (self->length >= get_atcmd_buf_size(self)) { - self->state = CAT_STATE_ERROR; - break; - } - get_atcmd_buf(self)[self->length++] = self->current_char; - if (self->length < get_atcmd_buf_size(self)) { - get_atcmd_buf(self)[self->length] = 0; - } else { - self->state = CAT_STATE_ERROR; - } - break; - } - return CAT_STATUS_BUSY; -} - -cat_status cat_trigger_unsolicited_event(struct cat_object *self, struct cat_command const *cmd, cat_cmd_type type) -{ - cat_status s; - - assert(self != NULL); - assert(cmd != NULL); - assert(((type == CAT_CMD_TYPE_READ) || (type == CAT_CMD_TYPE_TEST))); - - if ((self->mutex != NULL) && (self->mutex->lock() != 0)) - return CAT_STATUS_ERROR_MUTEX_LOCK; - - s = push_unsolicited_cmd(self, cmd, type); - - if ((self->mutex != NULL) && (self->mutex->unlock() != 0)) - return CAT_STATUS_ERROR_MUTEX_UNLOCK; - - return s; -} - -cat_status cat_trigger_unsolicited_read(struct cat_object *self, struct cat_command const *cmd) -{ - return cat_trigger_unsolicited_event(self, cmd, CAT_CMD_TYPE_READ); -} - -cat_status cat_trigger_unsolicited_test(struct cat_object *self, struct cat_command const *cmd) -{ - return cat_trigger_unsolicited_event(self, cmd, CAT_CMD_TYPE_TEST); -} - -static void check_unsolicited_buffers(struct cat_object *self) -{ - cat_cmd_type type; - - assert(self != NULL); - - if (pop_unsolicited_cmd(self, &self->unsolicited_fsm.cmd, &type) != CAT_STATUS_OK) - return; - - self->unsolicited_fsm.cmd_type = type; - - switch (type) { - case CAT_CMD_TYPE_READ: - start_processing_format_read_args(self, CAT_FSM_TYPE_UNSOLICITED); - break; - case CAT_CMD_TYPE_TEST: - start_processing_format_test_args(self, CAT_FSM_TYPE_UNSOLICITED); - break; - default: - break; - } -} - -static cat_status process_idle_state(struct cat_object *self) -{ - assert(self != NULL); - - if (read_cmd_char(self) == 0) - return CAT_STATUS_OK; - - switch (self->current_char) { - case 'A': - self->state = CAT_STATE_PARSE_PREFIX; - break; - case '\n': - case '\r': - break; - default: - self->state = CAT_STATE_ERROR; - break; - } - - return CAT_STATUS_BUSY; -} - -static void enable_hold_state(struct cat_object *self) -{ - assert(self != NULL); - - self->state = CAT_STATE_HOLD; - self->hold_state_flag = true; - self->hold_exit_status = 0; -} - -static cat_status hold_exit(struct cat_object *self, cat_status status) -{ - cat_status s; - - assert(self != NULL); - - if (self->hold_state_flag == false) { - s = CAT_STATUS_ERROR_NOT_HOLD; - } else { - self->hold_exit_status = (status == CAT_STATUS_OK) ? 1 : -1; - s = CAT_STATUS_OK; - } - - return s; -} - -static void start_print_cmd_list(struct cat_object *self) -{ - assert(self != NULL); - - if (self->commands_num == 0) { - ack_ok(self); - return; - } - - self->index = 0; - self->length = 0; - self->cmd_type = CAT_CMD_TYPE_NONE; - self->state = CAT_STATE_PRINT_CMD; -} - -static bool cmd_list_next_cmd(struct cat_object *self) -{ - if (++self->index >= self->commands_num) - return false; - - self->length = 0; - self->cmd_type = CAT_CMD_TYPE_NONE; - self->state = CAT_STATE_PRINT_CMD; - - return true; -} - -static int print_current_cmd_full_name(struct cat_object *self, const char *suffix) -{ - if (self->length == 0) { - if (print_string_to_buf(self, get_new_line_chars(self), CAT_FSM_TYPE_ATCMD) != 0) - return -1; - self->length = 1; - } - - if (print_string_to_buf(self, "AT", CAT_FSM_TYPE_ATCMD) != 0) - return -1; - if (print_string_to_buf(self, self->cmd->name, CAT_FSM_TYPE_ATCMD) != 0) - return -1; - if (print_string_to_buf(self, suffix, CAT_FSM_TYPE_ATCMD) != 0) - return -1; - if (print_string_to_buf(self, get_new_line_chars(self), CAT_FSM_TYPE_ATCMD) != 0) - return -1; - - return 0; -} - -static void print_cmd_list(struct cat_object *self) -{ - self->cmd = get_command_by_index(self, self->index); - - switch (self->cmd_type) { - case CAT_CMD_TYPE_NONE: - if (self->cmd->disable != false) { - if (cmd_list_next_cmd(self) == false) - ack_ok(self); - break; - } - - self->cmd_type = (self->cmd->only_test != false) ? CAT_CMD_TYPE_TEST : CAT_CMD_TYPE_RUN; - break; - case CAT_CMD_TYPE_RUN: - if (self->cmd->run != NULL) { - self->position = 0; - if (print_current_cmd_full_name(self, "") != 0) { - ack_error(self); - break; - } - start_flush_io_buffer_raw(self, CAT_STATE_PRINT_CMD); - } - self->cmd_type = CAT_CMD_TYPE_READ; - break; - case CAT_CMD_TYPE_READ: - if ((self->cmd->read != NULL) || (is_variables_access_possible(self, self->cmd, CAT_VAR_ACCESS_READ_ONLY) != false)) { - self->position = 0; - if (print_current_cmd_full_name(self, "?") != 0) { - ack_error(self); - break; - } - start_flush_io_buffer_raw(self, CAT_STATE_PRINT_CMD); - } - self->cmd_type = CAT_CMD_TYPE_WRITE; - break; - case CAT_CMD_TYPE_WRITE: - if (self->cmd->write != NULL || (is_variables_access_possible(self, self->cmd, CAT_VAR_ACCESS_WRITE_ONLY) != false)) { - self->position = 0; - if (print_current_cmd_full_name(self, "=") != 0) { - ack_error(self); - break; - } - start_flush_io_buffer_raw(self, CAT_STATE_PRINT_CMD); - } - self->cmd_type = CAT_CMD_TYPE_TEST; - break; - case CAT_CMD_TYPE_TEST: - if (self->cmd->test != NULL || ((self->cmd->var != NULL) && (self->cmd->var_num > 0))) { - self->position = 0; - if (print_current_cmd_full_name(self, "=?") != 0) { - ack_error(self); - break; - } - start_flush_io_buffer_raw(self, CAT_STATE_PRINT_CMD); - } - self->cmd_type = CAT_CMD_TYPE__TOTAL_NUM; - break; - case CAT_CMD_TYPE__TOTAL_NUM: - if (cmd_list_next_cmd(self) == false) - ack_ok(self); - break; - default: - ack_error(self); - break; - } -} - -static cat_status process_write_loop(struct cat_object *self) -{ - assert(self != NULL); - - switch (self->cmd->write(self->cmd, (uint8_t*)get_atcmd_buf(self), self->length, self->index)) { - case CAT_RETURN_STATE_OK: - case CAT_RETURN_STATE_DATA_OK: - ack_ok(self); - break; - case CAT_RETURN_STATE_DATA_NEXT: - case CAT_RETURN_STATE_NEXT: - break; - case CAT_RETURN_STATE_HOLD: - enable_hold_state(self); - break; - case CAT_RETURN_STATE_HOLD_EXIT_OK: - case CAT_RETURN_STATE_HOLD_EXIT_ERROR: - case CAT_RETURN_STATE_ERROR: - case CAT_RETURN_STATE_PRINT_CMD_LIST_OK: - default: - ack_error(self); - break; - } - - return CAT_STATUS_BUSY; -} - -static cat_status process_run_loop(struct cat_object *self) -{ - assert(self != NULL); - - switch (self->cmd->run(self->cmd)) { - case CAT_RETURN_STATE_OK: - case CAT_RETURN_STATE_DATA_OK: - ack_ok(self); - break; - case CAT_RETURN_STATE_DATA_NEXT: - case CAT_RETURN_STATE_NEXT: - break; - case CAT_RETURN_STATE_HOLD: - enable_hold_state(self); - break; - case CAT_RETURN_STATE_PRINT_CMD_LIST_OK: - start_print_cmd_list(self); - break; - case CAT_RETURN_STATE_HOLD_EXIT_OK: - case CAT_RETURN_STATE_HOLD_EXIT_ERROR: - case CAT_RETURN_STATE_ERROR: - default: - ack_error(self); - break; - } - - return CAT_STATUS_BUSY; -} - -static cat_return_state call_cmd_read_by_fsm(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - struct cat_command *cmd = get_command_by_fsm(self, fsm); - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - return cmd->read(cmd, (uint8_t*)get_atcmd_buf(self), &self->position, get_atcmd_buf_size(self)); - case CAT_FSM_TYPE_UNSOLICITED: - return cmd->read(cmd, (uint8_t*)get_unsolicited_buf(self), &self->unsolicited_fsm.position, get_unsolicited_buf_size(self)); - default: - assert(false); - } -} - -static cat_status process_read_loop(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - switch (call_cmd_read_by_fsm(self, fsm)) { - case CAT_RETURN_STATE_OK: - end_processing_with_ok(self, fsm); - break; - case CAT_RETURN_STATE_DATA_OK: - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - start_flush_io_buffer(self, CAT_STATE_AFTER_FLUSH_OK); - break; - case CAT_FSM_TYPE_UNSOLICITED: - unsolicited_start_flush_io_buffer(self, CAT_UNSOLICITED_STATE_AFTER_FLUSH_OK); - break; - default: - assert(false); - } - break; - case CAT_RETURN_STATE_DATA_NEXT: - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - start_flush_io_buffer(self, CAT_STATE_AFTER_FLUSH_FORMAT_READ_ARGS); - break; - case CAT_FSM_TYPE_UNSOLICITED: - unsolicited_start_flush_io_buffer(self, CAT_UNSOLICITED_STATE_AFTER_FLUSH_FORMAT_READ_ARGS); - break; - default: - assert(false); - } - break; - case CAT_RETURN_STATE_NEXT: - start_processing_format_read_args(self, fsm); - break; - case CAT_RETURN_STATE_HOLD: - enable_hold_state(self); - break; - case CAT_RETURN_STATE_HOLD_EXIT_OK: - hold_exit(self, CAT_STATUS_OK); - end_processing_with_ok(self, fsm); - break; - case CAT_RETURN_STATE_HOLD_EXIT_ERROR: - hold_exit(self, CAT_STATUS_ERROR); - end_processing_with_error(self, fsm); - break; - case CAT_RETURN_STATE_PRINT_CMD_LIST_OK: - case CAT_RETURN_STATE_ERROR: - default: - end_processing_with_error(self, fsm); - break; - } - - return CAT_STATUS_BUSY; -} - -static cat_return_state call_cmd_test_by_fsm(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - struct cat_command *cmd = get_command_by_fsm(self, fsm); - - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - return cmd->test(cmd, (uint8_t*)get_atcmd_buf(self), &self->position, get_atcmd_buf_size(self)); - case CAT_FSM_TYPE_UNSOLICITED: - return cmd->test(cmd, (uint8_t*)get_unsolicited_buf(self), &self->unsolicited_fsm.position, get_unsolicited_buf_size(self)); - default: - assert(false); - } -} - -static cat_status process_test_loop(struct cat_object *self, cat_fsm_type fsm) -{ - assert(self != NULL); - assert(fsm < CAT_FSM_TYPE__TOTAL_NUM); - - switch (call_cmd_test_by_fsm(self, fsm)) { - case CAT_RETURN_STATE_OK: - end_processing_with_ok(self, fsm); - break; - case CAT_RETURN_STATE_DATA_OK: - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - start_flush_io_buffer(self, CAT_STATE_AFTER_FLUSH_OK); - break; - case CAT_FSM_TYPE_UNSOLICITED: - unsolicited_start_flush_io_buffer(self, CAT_UNSOLICITED_STATE_AFTER_FLUSH_OK); - break; - default: - assert(false); - } - break; - case CAT_RETURN_STATE_DATA_NEXT: - switch (fsm) { - case CAT_FSM_TYPE_ATCMD: - start_flush_io_buffer(self, CAT_STATE_AFTER_FLUSH_FORMAT_TEST_ARGS); - break; - case CAT_FSM_TYPE_UNSOLICITED: - unsolicited_start_flush_io_buffer(self, CAT_UNSOLICITED_STATE_AFTER_FLUSH_FORMAT_TEST_ARGS); - break; - default: - assert(false); - } - break; - case CAT_RETURN_STATE_NEXT: - start_processing_format_test_args(self, fsm); - break; - case CAT_RETURN_STATE_HOLD: - enable_hold_state(self); - break; - case CAT_RETURN_STATE_HOLD_EXIT_OK: - hold_exit(self, CAT_STATUS_OK); - end_processing_with_ok(self, fsm); - break; - case CAT_RETURN_STATE_HOLD_EXIT_ERROR: - hold_exit(self, CAT_STATUS_ERROR); - end_processing_with_error(self, fsm); - break; - case CAT_RETURN_STATE_PRINT_CMD_LIST_OK: - if (fsm == CAT_FSM_TYPE_ATCMD) { - start_print_cmd_list(self); - } else { - end_processing_with_ok(self, fsm); - } - break; - case CAT_RETURN_STATE_ERROR: - default: - end_processing_with_error(self, fsm); - break; - } - - return CAT_STATUS_BUSY; -} - -static cat_status process_hold_state(struct cat_object *self) -{ - assert(self != NULL); - - if (self->hold_exit_status == 0) - return CAT_STATUS_BUSY; - - self->hold_state_flag = false; - if (self->hold_exit_status < 0) { - ack_error(self); - } else { - ack_ok(self); - } - - return CAT_STATUS_BUSY; -} - -cat_status cat_hold_exit(struct cat_object *self, cat_status status) -{ - cat_status s; - - assert(self != NULL); - - if ((self->mutex != NULL) && (self->mutex->lock() != 0)) - return CAT_STATUS_ERROR_MUTEX_LOCK; - - s = hold_exit(self, status); - - if ((self->mutex != NULL) && (self->mutex->unlock() != 0)) - return CAT_STATUS_ERROR_MUTEX_UNLOCK; - - return s; -} - -struct cat_command const* cat_search_command_by_name(struct cat_object *self, const char *name) -{ - size_t i; - struct cat_command const *cmd; - - assert(self != NULL); - assert(name != NULL); - - for (i = 0; i < self->commands_num; i++) { - cmd = get_command_by_index(self, i); - if (strcmp(cmd->name, name) == 0) - return cmd; - } - - return NULL; -} - -struct cat_command_group const* cat_search_command_group_by_name(struct cat_object *self, const char *name) -{ - size_t i; - struct cat_command_group const *cmd_group; - - assert(self != NULL); - assert(name != NULL); - - for (i = 0; i < self->desc->cmd_group_num; i++) { - cmd_group = self->desc->cmd_group[i]; - if ((cmd_group->name != NULL) && (strcmp(cmd_group->name, name) == 0)) - return cmd_group; - } - - return NULL; -} - -struct cat_variable const* cat_search_variable_by_name(struct cat_object *self, struct cat_command const *cmd, const char *name) -{ - size_t i; - struct cat_variable const *var; - - assert(self != NULL); - assert(cmd != NULL); - assert(name != NULL); - - for (i = 0; i < cmd->var_num; i++) { - var = &cmd->var[i]; - if ((var->name != NULL) && (strcmp(var->name, name) == 0)) - return var; - } - - return NULL; -} - -static cat_status process_io_write_wait(struct cat_object *self) -{ - if (self->unsolicited_fsm.state != CAT_UNSOLICITED_STATE_FLUSH_IO_WRITE) - self->state = CAT_STATE_FLUSH_IO_WRITE; - - return CAT_STATUS_BUSY; -} - -static cat_status unsolicited_process_io_write_wait(struct cat_object *self) -{ - if (self->state != CAT_STATE_FLUSH_IO_WRITE) - self->unsolicited_fsm.state = CAT_UNSOLICITED_STATE_FLUSH_IO_WRITE; - - return CAT_STATUS_BUSY; -} - -static cat_status process_io_write(struct cat_object *self) -{ - char ch = self->write_buf[self->position]; - - if (ch == '\0') { - switch (self->write_state) { - case CAT_WRITE_STATE_BEFORE: - self->position = 0; - self->write_buf = get_atcmd_buf(self); - self->write_state = CAT_WRITE_STATE_MAIN_BUFFER; - break; - case CAT_WRITE_STATE_MAIN_BUFFER: - self->position = 0; - self->write_buf = get_new_line_chars(self); - self->write_state = CAT_WRITE_STATE_AFTER; - break; - case CAT_WRITE_STATE_AFTER: - self->state = self->write_state_after; - break; - } - return CAT_STATUS_BUSY; - } - - if (self->io->write(ch) != 1) - return CAT_STATUS_BUSY; - - self->position++; - return CAT_STATUS_BUSY; -} - -static cat_status unsolicited_process_io_write(struct cat_object *self) -{ - char ch = self->unsolicited_fsm.write_buf[self->unsolicited_fsm.position]; - - if (ch == '\0') { - switch (self->unsolicited_fsm.write_state) { - case CAT_WRITE_STATE_BEFORE: - self->unsolicited_fsm.position = 0; - self->unsolicited_fsm.write_buf = get_unsolicited_buf(self); - self->unsolicited_fsm.write_state = CAT_WRITE_STATE_MAIN_BUFFER; - break; - case CAT_WRITE_STATE_MAIN_BUFFER: - self->unsolicited_fsm.position = 0; - self->unsolicited_fsm.write_buf = get_new_line_chars(self); - self->unsolicited_fsm.write_state = CAT_WRITE_STATE_AFTER; - break; - case CAT_WRITE_STATE_AFTER: - self->unsolicited_fsm.state = self->unsolicited_fsm.write_state_after; - break; - } - return CAT_STATUS_BUSY; - } - - if (self->io->write(ch) != 1) - return CAT_STATUS_BUSY; - - self->unsolicited_fsm.position++; - return CAT_STATUS_BUSY; -} - -static cat_status unsolicited_events_service(struct cat_object *self) -{ - cat_status s = CAT_STATUS_OK; - - switch (self->unsolicited_fsm.state) { - case CAT_UNSOLICITED_STATE_IDLE: - check_unsolicited_buffers(self); - break; - case CAT_UNSOLICITED_STATE_FORMAT_READ_ARGS: - s = format_read_args(self, CAT_FSM_TYPE_UNSOLICITED); - break; - case CAT_UNSOLICITED_STATE_FORMAT_TEST_ARGS: - s = format_test_args(self, CAT_FSM_TYPE_UNSOLICITED); - break; - case CAT_UNSOLICITED_STATE_READ_LOOP: - s = process_read_loop(self, CAT_FSM_TYPE_UNSOLICITED); - break; - case CAT_UNSOLICITED_STATE_TEST_LOOP: - s = process_test_loop(self, CAT_FSM_TYPE_UNSOLICITED); - break; - case CAT_UNSOLICITED_STATE_FLUSH_IO_WRITE_WAIT: - s = unsolicited_process_io_write_wait(self); - break; - case CAT_UNSOLICITED_STATE_FLUSH_IO_WRITE: - s = unsolicited_process_io_write(self); - break; - case CAT_UNSOLICITED_STATE_AFTER_FLUSH_RESET: - unsolicited_reset_state(self); - s = CAT_STATUS_BUSY; - break; - case CAT_UNSOLICITED_STATE_AFTER_FLUSH_OK: - end_processing_with_ok(self, CAT_FSM_TYPE_UNSOLICITED); - s = CAT_STATUS_BUSY; - break; - case CAT_UNSOLICITED_STATE_AFTER_FLUSH_FORMAT_READ_ARGS: - start_processing_format_read_args(self, CAT_FSM_TYPE_UNSOLICITED); - s = CAT_STATUS_BUSY; - break; - case CAT_UNSOLICITED_STATE_AFTER_FLUSH_FORMAT_TEST_ARGS: - start_processing_format_test_args(self, CAT_FSM_TYPE_UNSOLICITED); - s = CAT_STATUS_BUSY; - break; - default: - break; - } - - return s; -} - -static bool is_unsolicited_fsm_busy(struct cat_object *self) -{ - return (self->unsolicited_fsm.state != CAT_UNSOLICITED_STATE_IDLE); -} - -cat_status cat_service(struct cat_object *self) -{ - cat_status s; - cat_status unsolicited_stat; - - assert(self != NULL); - - if ((self->mutex != NULL) && (self->mutex->lock() != 0)) - return CAT_STATUS_ERROR_MUTEX_LOCK; - - unsolicited_stat = unsolicited_events_service(self); - - switch (self->state) { - case CAT_STATE_ERROR: - s = error_state(self); - break; - case CAT_STATE_IDLE: - s = process_idle_state(self); - break; - case CAT_STATE_PARSE_PREFIX: - s = parse_prefix(self); - break; - case CAT_STATE_PARSE_COMMAND_CHAR: - s = parse_command(self); - break; - case CAT_STATE_UPDATE_COMMAND_STATE: - s = update_command(self); - break; - case CAT_STATE_WAIT_READ_ACKNOWLEDGE: - s = wait_read_acknowledge(self); - break; - case CAT_STATE_SEARCH_COMMAND: - s = search_command(self); - break; - case CAT_STATE_COMMAND_FOUND: - s = command_found(self); - break; - case CAT_STATE_COMMAND_NOT_FOUND: - s = command_not_found(self); - break; - case CAT_STATE_PARSE_COMMAND_ARGS: - s = parse_command_args(self); - break; - case CAT_STATE_PARSE_WRITE_ARGS: - s = parse_write_args(self); - break; - case CAT_STATE_FORMAT_READ_ARGS: - s = format_read_args(self, CAT_FSM_TYPE_ATCMD); - break; - case CAT_STATE_WAIT_TEST_ACKNOWLEDGE: - s = wait_test_acknowledge(self); - break; - case CAT_STATE_FORMAT_TEST_ARGS: - s = format_test_args(self, CAT_FSM_TYPE_ATCMD); - break; - case CAT_STATE_WRITE_LOOP: - s = process_write_loop(self); - break; - case CAT_STATE_READ_LOOP: - s = process_read_loop(self, CAT_FSM_TYPE_ATCMD); - break; - case CAT_STATE_TEST_LOOP: - s = process_test_loop(self, CAT_FSM_TYPE_ATCMD); - break; - case CAT_STATE_RUN_LOOP: - s = process_run_loop(self); - break; - case CAT_STATE_HOLD: - s = process_hold_state(self); - break; - case CAT_STATE_FLUSH_IO_WRITE_WAIT: - s = process_io_write_wait(self); - break; - case CAT_STATE_FLUSH_IO_WRITE: - s = process_io_write(self); - break; - case CAT_STATE_AFTER_FLUSH_RESET: - reset_state(self); - s = CAT_STATUS_BUSY; - break; - case CAT_STATE_AFTER_FLUSH_OK: - ack_ok(self); - s = CAT_STATUS_BUSY; - break; - case CAT_STATE_AFTER_FLUSH_FORMAT_READ_ARGS: - start_processing_format_read_args(self, CAT_FSM_TYPE_ATCMD); - s = CAT_STATUS_BUSY; - break; - case CAT_STATE_AFTER_FLUSH_FORMAT_TEST_ARGS: - start_processing_format_test_args(self, CAT_FSM_TYPE_ATCMD); - s = CAT_STATUS_BUSY; - break; - case CAT_STATE_PRINT_CMD: - print_cmd_list(self); - s = CAT_STATUS_BUSY; - break; - default: - s = CAT_STATUS_ERROR_UNKNOWN_STATE; - break; - } - - if ((unsolicited_stat != CAT_STATUS_OK) || (is_unsolicited_fsm_busy(self) != false)) { - s = CAT_STATUS_BUSY; - } - - if ((self->mutex != NULL) && (self->mutex->unlock() != 0)) - return CAT_STATUS_ERROR_MUTEX_UNLOCK; - - return s; -} diff --git a/components/api/lib/cAT/src/cat.h b/components/api/lib/cAT/src/cat.h deleted file mode 100755 index aeeb6be..0000000 --- a/components/api/lib/cAT/src/cat.h +++ /dev/null @@ -1,557 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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 CAT_H -#define CAT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -/* only forward declarations (looks for definition below) */ -struct cat_command; -struct cat_variable; - -#ifndef CAT_UNSOLICITED_CMD_BUFFER_SIZE -/* unsolicited command buffer default size (can by override externally during compilation) */ -#define CAT_UNSOLICITED_CMD_BUFFER_SIZE ((size_t)(1)) -#endif - -/* enum type with variable type definitions */ -typedef enum { - CAT_VAR_INT_DEC = 0, /* decimal encoded signed integer variable */ - CAT_VAR_UINT_DEC, /* decimal encoded unsigned integer variable */ - CAT_VAR_NUM_HEX, /* hexadecimal encoded unsigned integer variable */ - CAT_VAR_BUF_HEX, /* asciihex encoded bytes array */ - CAT_VAR_BUF_STRING /* string variable */ -} cat_var_type; - -/* enum type wirh variable accessors definitions */ -typedef enum { - CAT_VAR_ACCESS_READ_WRITE = 0, /* there will be possible to read and write variable */ - CAT_VAR_ACCESS_READ_ONLY, /* there will be possible to read only variable */ - CAT_VAR_ACCESS_WRITE_ONLY, /* there will be possible to write only variable */ -} cat_var_access; - -/* enum type with function status */ -typedef enum { - CAT_STATUS_ERROR_BUFFER_EMPTY = -7, - CAT_STATUS_ERROR_NOT_HOLD = -6, - CAT_STATUS_ERROR_BUFFER_FULL = -5, - CAT_STATUS_ERROR_UNKNOWN_STATE = -4, - CAT_STATUS_ERROR_MUTEX_LOCK = -3, - CAT_STATUS_ERROR_MUTEX_UNLOCK = -2, - CAT_STATUS_ERROR = -1, - CAT_STATUS_OK = 0, - CAT_STATUS_BUSY = 1, - CAT_STATUS_HOLD = 2 -} cat_status; - -/** - * Write variable function handler - * - * This callback function is called after variable update immediatly. - * User application can validate writed value and check for amount of data size was written. - * This handler is optional, so when is not defined, operations will be fully automatically. - * - * @param var - pointer to struct descriptor of parsed variable - * @param write_size - size of data was written (useful especially with hexbuf var type) - * @return 0 - ok, else error and stop parsing - * */ -typedef int (*cat_var_write_handler)(const struct cat_variable *var, const size_t write_size); - -/** - * Read variable function handler - * - * This callback function is called just before variable value read. - * User application can copy data from private fields to variable connected with parsed command. - * This handler is optional, so when is not defined, operations will be fully automatically. - * - * @param var - pointer to struct descriptor of parsed variable - * @return 0 - ok, else error and stop parsing - * */ -typedef int (*cat_var_read_handler)(const struct cat_variable *var); - -/** - * Write variable extended function handler - * - * This callback function is called after variable update immediatly. - * User application can validate writed value and check for amount of data size was written. - * This handler is optional, so when is not defined, operations will be fully automatically. - * - * @param var - pointer to struct descriptor of parsed variable - * @param cmd - pointer to variable parent command structure - * @param write_size - size of data was written (useful especially with hexbuf var type) - * @return 0 - ok, else error and stop parsing - * */ -typedef int (*cat_var_write_ex_handler)(const struct cat_variable *var, const struct cat_command *cmd, const size_t write_size); - -/** - * Read variable function handler - * - * This callback function is called just before variable value read. - * User application can copy data from private fields to variable connected with parsed command. - * This handler is optional, so when is not defined, operations will be fully automatically. - * - * @param var - pointer to struct descriptor of parsed variable - * @param cmd - pointer to variable parent command structure - * @return 0 - ok, else error and stop parsing - * */ -typedef int (*cat_var_read_ex_handler)(const struct cat_variable *var, const struct cat_command *cmd); - -/** - * Data getter for variable. - * The purpose of this function is to replace statically allocated data and data_size fields - * with function pointer with context. Then the data and data_size from this getter would be - * changed and returned runtime. - * - * @param var - pointer to struct descriptor of parsed variable - * @param context - command context - * @param size - pointer to variable where should be placed data size - * @return pointer to data array from context - */ -typedef void* (*cat_var_data_getter)(const struct cat_variable *var, void *context, size_t *data_size); - -struct cat_variable { - const char *name; /* variable name (optional - using only for auto format test command response) */ - cat_var_type type; /* variable type (needed for parsing and validating) */ - void *data; /* generic pointer to statically allocated memory for variable data read/write/validate operations */ - size_t data_size; /* variable data size, pointed by data pointer */ - cat_var_access access; /* variable accessor */ - - cat_var_write_handler write; /* write variable handler */ - cat_var_read_handler read; /* read variable handler */ - cat_var_write_ex_handler write_ex; /* optional write variable extended handler */ - cat_var_read_ex_handler read_ex; /* optional read variable extended handler */ - - cat_var_data_getter data_getter; /* optional data getter for dynamic linking data and data_size */ -}; - -/* enum type with command callbacks return values meaning */ -typedef enum { - CAT_RETURN_STATE_ERROR = -1, /* immediatly error acknowledge */ - CAT_RETURN_STATE_DATA_OK, /* send current data buffer followed by ok acknowledge */ - CAT_RETURN_STATE_DATA_NEXT, /* send current data buffer and go to next callback iteration */ - CAT_RETURN_STATE_NEXT, /* go to next callback iteration without sending anything */ - CAT_RETURN_STATE_OK, /* immediatly ok acknowledge */ - CAT_RETURN_STATE_HOLD, /* enable hold parser state */ - CAT_RETURN_STATE_HOLD_EXIT_OK, /* exit from hold state with OK response */ - CAT_RETURN_STATE_HOLD_EXIT_ERROR, /* exit from hold state with ERROR response */ - CAT_RETURN_STATE_PRINT_CMD_LIST_OK, /* print commands list followed by ok acknowledge (only in TEST and RUN) */ -} cat_return_state; - -/** - * Write command function handler (AT+CMD=) - * - * This callback function is called after parsing all connected variables. - * User application can validate all variales at once at this moment, or copy them to the other application layer buffer. - * User can check number of variables or make custom process of parsing non standard arguments format. - * This handler is optional, so when is not defined, operations on variables will be fully automatically. - * If neither write handler nor variables not defined, then write command type is not available. - * - * @param cmd - pointer to struct descriptor of processed command - * @param data - pointer to arguments buffer for custom parsing - * @param data_size - length of arguments buffer - * @param args_num - number of passed arguments connected to variables - * @return according to cat_return_state enum definitions - * */ -typedef cat_return_state (*cat_cmd_write_handler)(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num); - -/** - * Read command function handler (AT+CMD?) - * - * This callback function is called after format all connected variables. - * User application can change automatic response, or add some custom data to response. - * This handler is optional, so when is not defined, operations on variables will be fully automatically. - * If neither read handler nor variables not defined, then read command type is not available. - * - * @param cmd - pointer to struct descriptor of processed command - * @param data - pointer to arguments buffer for custom parsing - * @param data_size - pointer to length of arguments buffer (can be modifed if needed) - * @param max_data_size - maximum length of buffer pointed by data pointer - * @return according to cat_return_state enum definitions - * */ -typedef cat_return_state (*cat_cmd_read_handler)(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size); - -/** - * Run command function handler (AT+CMD) - * - * No operations on variables are done. - * This handler is optional. - * If run handler not defined, then run command type is not available. - * - * @param cmd - pointer to struct descriptor of processed command - * @return according to cat_return_state enum definitions - * */ -typedef cat_return_state (*cat_cmd_run_handler)(const struct cat_command *cmd); - -/** - * Test command function handler (AT+CMD=?) - * - * This callback function is called after format all connected variables. - * User application can change automatic response, or add some custom data to response. - * This handler is optional, so when is not defined, operations on variables will be fully automatically. - * If neither test handler nor variables not defined, then test command type is not available. - * Exception of this rule is write command without variables. - * In this case, the "question mark" will be passed as a custom argument to the write handler. - * - * @param cmd - pointer to struct descriptor of processed command - * @param data - pointer to arguments buffer for custom parsing - * @param data_size - pointer to length of arguments buffer (can be modifed if needed) - * @param max_data_size - maximum length of buffer pointed by data pointer - * @return according to cat_return_state enum definitions - * */ -typedef cat_return_state (*cat_cmd_test_handler)(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size); - -/* enum type with main at parser fsm state */ -typedef enum { - CAT_STATE_ERROR = -1, - CAT_STATE_IDLE, - CAT_STATE_PARSE_PREFIX, - CAT_STATE_PARSE_COMMAND_CHAR, - CAT_STATE_UPDATE_COMMAND_STATE, - CAT_STATE_WAIT_READ_ACKNOWLEDGE, - CAT_STATE_SEARCH_COMMAND, - CAT_STATE_COMMAND_FOUND, - CAT_STATE_COMMAND_NOT_FOUND, - CAT_STATE_PARSE_COMMAND_ARGS, - CAT_STATE_PARSE_WRITE_ARGS, - CAT_STATE_FORMAT_READ_ARGS, - CAT_STATE_WAIT_TEST_ACKNOWLEDGE, - CAT_STATE_FORMAT_TEST_ARGS, - CAT_STATE_WRITE_LOOP, - CAT_STATE_READ_LOOP, - CAT_STATE_TEST_LOOP, - CAT_STATE_RUN_LOOP, - CAT_STATE_HOLD, - CAT_STATE_FLUSH_IO_WRITE_WAIT, - CAT_STATE_FLUSH_IO_WRITE, - CAT_STATE_AFTER_FLUSH_RESET, - CAT_STATE_AFTER_FLUSH_OK, - CAT_STATE_AFTER_FLUSH_FORMAT_READ_ARGS, - CAT_STATE_AFTER_FLUSH_FORMAT_TEST_ARGS, - CAT_STATE_PRINT_CMD, -} cat_state; - -/* enum type with type of command request */ -typedef enum { - CAT_CMD_TYPE_NONE = -1, - CAT_CMD_TYPE_RUN, - CAT_CMD_TYPE_READ, - CAT_CMD_TYPE_WRITE, - CAT_CMD_TYPE_TEST, - CAT_CMD_TYPE__TOTAL_NUM -} cat_cmd_type; - -/* structure with io interface functions */ -struct cat_io_interface { - int (*write)(char ch); /* write char to output stream. return 1 if byte wrote successfully. */ - int (*read)(char *ch); /* read char from input stream. return 1 if byte read successfully. */ -}; - -/* structure with mutex interface functions */ -struct cat_mutex_interface { - int (*lock)(void); /* lock mutex handler. return 0 if successfully locked, otherwise - cannot lock */ - int (*unlock)(void); /* unlock mutex handler. return 0 if successfully unlocked, otherwise - cannot unlock */ -}; - -/* structure with at command descriptor */ -struct cat_command { - const char *name; /* at command name (case-insensitivity) */ - const char *description; /* at command description (optionally - can be null) */ - - cat_cmd_write_handler write; /* write command handler */ - cat_cmd_read_handler read; /* read command handler */ - cat_cmd_run_handler run; /* run command handler */ - cat_cmd_test_handler test; /* test command handler */ - - struct cat_variable const *var; /* pointer to array of variables assiocated with this command */ - size_t var_num; /* number of variables in array */ - - bool need_all_vars; /* flag to need all vars parsing */ - bool only_test; /* flag to disable read/write/run commands (only test auto description) */ - bool disable; /* flag to completely disable command */ - - void* context; /* pointer to optional context structure */ -}; - -struct cat_command_group { - const char *name; /* command group name (optional, for identification purpose) */ - - struct cat_command const *cmd; /* pointer to array of commands descriptor */ - size_t cmd_num; /* number of commands in array */ - - bool disable; /* flag to completely disable all commands in group */ -}; - -/* structure with at command parser descriptor */ -struct cat_descriptor { - struct cat_command_group* const *cmd_group; /* pointer to array of commands group descriptor */ - size_t cmd_group_num; /* number of commands group in array */ - - uint8_t *buf; /* pointer to working buffer (used to parse command argument) */ - size_t buf_size; /* working buffer length */ - - /* optional unsolicited buffer, if not configured (NULL) */ - /* then the buf will be divided into two smaller buffers */ - uint8_t *unsolicited_buf; /* pointer to unsolicited working buffer (used to parse command argument) */ - size_t unsolicited_buf_size; /* unsolicited working buffer length */ -}; - -/* strcuture with unsolicited command buffered infos */ -struct cat_unsolicited_cmd { - struct cat_command const *cmd; /* pointer to commands used to unsolicited event */ - cat_cmd_type type; /* type of unsolicited event */ -}; - -/* enum type with unsolicited events fsm state */ -typedef enum { - CAT_UNSOLICITED_STATE_IDLE, - CAT_UNSOLICITED_STATE_FORMAT_READ_ARGS, - CAT_UNSOLICITED_STATE_FORMAT_TEST_ARGS, - CAT_UNSOLICITED_STATE_READ_LOOP, - CAT_UNSOLICITED_STATE_TEST_LOOP, - CAT_UNSOLICITED_STATE_FLUSH_IO_WRITE_WAIT, - CAT_UNSOLICITED_STATE_FLUSH_IO_WRITE, - CAT_UNSOLICITED_STATE_AFTER_FLUSH_RESET, - CAT_UNSOLICITED_STATE_AFTER_FLUSH_OK, - CAT_UNSOLICITED_STATE_AFTER_FLUSH_FORMAT_READ_ARGS, - CAT_UNSOLICITED_STATE_AFTER_FLUSH_FORMAT_TEST_ARGS, -} cat_unsolicited_state; - -/* enum type with fsm type */ -typedef enum { - CAT_FSM_TYPE_ATCMD, - CAT_FSM_TYPE_UNSOLICITED, - CAT_FSM_TYPE__TOTAL_NUM, -} cat_fsm_type; - -struct cat_unsolicited_fsm { - cat_unsolicited_state state; /* current unsolicited fsm state */ - - size_t index; /* index used to iterate over commands and variables */ - size_t position; /* position of actually parsed char in arguments string */ - - struct cat_command const *cmd; /* pointer to current command descriptor */ - struct cat_variable const *var; /* pointer to current variable descriptor */ - cat_cmd_type cmd_type; /* type of command request */ - - char const *write_buf; /* working buffer pointer used for asynch writing to io */ - int write_state; /* before, data, after flush io write state */ - cat_unsolicited_state write_state_after; /* parser state to set after flush io write */ - - struct cat_unsolicited_cmd unsolicited_cmd_buffer[CAT_UNSOLICITED_CMD_BUFFER_SIZE]; /* buffer with unsolicited commands used to unsolicited event */ - size_t unsolicited_cmd_buffer_tail; /* tail index of unsolicited cmd buffer */ - size_t unsolicited_cmd_buffer_head; /* head index of unsolicited cmd buffer */ - size_t unsolicited_cmd_buffer_items_count; /* number of unsolicited cmd in buffer */ -}; - -/* structure with main at command parser object */ -struct cat_object { - struct cat_descriptor const *desc; /* pointer to at command parser descriptor */ - struct cat_io_interface const *io; /* pointer to at command parser io interface */ - struct cat_mutex_interface const *mutex; /* pointer to at command parser mutex interface */ - - size_t index; /* index used to iterate over commands and variables */ - size_t partial_cntr; /* partial match commands counter */ - size_t length; /* length of input command name and command arguments */ - size_t position; /* position of actually parsed char in arguments string */ - size_t write_size; /* size of parsed buffer hex or buffer string */ - size_t commands_num; /* computed total number of registered commands */ - - struct cat_command const *cmd; /* pointer to current command descriptor */ - struct cat_variable const *var; /* pointer to current variable descriptor */ - cat_cmd_type cmd_type; /* type of command request */ - - char current_char; /* current received char from input stream */ - cat_state state; /* current fsm state */ - bool cr_flag; /* flag for detect char in input string */ - bool hold_state_flag; /* status of hold state (independent from fsm states) */ - int hold_exit_status; /* hold exit parameter with status */ - char const *write_buf; /* working buffer pointer used for asynch writing to io */ - int write_state; /* before, data, after flush io write state */ - cat_state write_state_after; /* parser state to set after flush io write */ - - struct cat_unsolicited_fsm unsolicited_fsm; -}; - -/** - * Function used to initialize at command parser. - * Initialize starting values of object fields. - * - * @param self pointer to at command parser object to initialize - * @param desc pointer to at command parser descriptor - * @param io pointer to at command parser io low-level layer interface - * @param mutex pointer to at command partes mutex interface - */ -void cat_init(struct cat_object *self, const struct cat_descriptor *desc, const struct cat_io_interface *io, const struct cat_mutex_interface *mutex); - -/** - * Function must be called periodically to asynchronoulsy run at command parser. - * Commands handlers will be call from this function context. - * - * @param self pointer to at command parser object - * @return according to cat_return_state enum definitions - */ -cat_status cat_service(struct cat_object *self); - -/** - * Function return flag which indicating internal busy state. - * It is used to determine whether external application modules can use shared input / output interfaces functions. - * It is usefull especially in rtos environments. - * If internal parser state is busy by doing some processing then function return 1. - * If the function returns 0, then the external application modules can safely use the input / output interfaces functions shared with the library. - * If the function returns 1, then input / output interface function are used by internal parser functions. - * - * @param self pointer to at command parser object - * @return according to cat_return_state enum definitions - */ -cat_status cat_is_busy(struct cat_object *self); - -/** - * Function return flag which indicating parsing hold state. - * If the function returns 0, then the at parsing process is normal. - * If the function returns 1, then the at parsing process is holded. - * To exit from hold state, user have to call cat_hold_exit or return HOLD_EXIT return value in callback. - * - * @param self pointer to at command parser object - * @return according to cat_return_state enum definitions - */ -cat_status cat_is_hold(struct cat_object *self); - -/** - * Function return flag which indicating state of internal buffer of unsolicited events. - * - * @param self pointer to at command parser object - * @return CAT_STATUS_OK - buffer is not full, unsolicited event can be buffered - * CAT_STATUS_ERROR_BUFFER_FULL - buffer is full, unsolicited event cannot be buffered - * CAT_STATUS_ERROR_MUTEX_LOCK - cannot lock mutex error - * CAT_STATUS_ERROR_MUTEX_UNLOCK - cannot unlock mutex error - */ -cat_status cat_is_unsolicited_buffer_full(struct cat_object *self); - -/** - * Function sends unsolicited event message. - * Command message is buffered inside parser in 1-level deep buffer and processed in cat_service context. - * Only command pointer is buffered, so command struct should be static or global until be fully processed. - * - * @param self pointer to at command parser object - * @param cmd pointer to command structure regarding which unsolicited event applies to - * @param type type of operation (only CAT_CMD_TYPE_READ and CAT_CMD_TYPE_TEST are allowed) - * @return according to cat_return_state enum definitions - */ -cat_status cat_trigger_unsolicited_event(struct cat_object *self, struct cat_command const *cmd, cat_cmd_type type); - -/** - * Function sends unsolicited read event message. - * Command message is buffered inside parser in 1-level deep buffer and processed in cat_service context. - * Only command pointer is buffered, so command struct should be static or global until be fully processed. - * - * @param self pointer to at command parser object - * @param cmd pointer to command structure regarding which unsolicited read applies to - * @return according to cat_return_state enum definitions - */ -cat_status cat_trigger_unsolicited_read(struct cat_object *self, struct cat_command const *cmd); - -/** - * Function sends unsolicited test event message. - * Command message is buffered inside parser in 1-level deep buffer and processed in cat_service context. - * Only command pointer is buffered, so command struct should be static or global until be fully processed. - * - * @param self pointer to at command parser object - * @param cmd pointer to command structure regarding which unsolicited test applies to - * @return according to cat_return_state enum definitions - */ -cat_status cat_trigger_unsolicited_test(struct cat_object *self, struct cat_command const *cmd); - -/** - * Function used to exit from hold state with OK/ERROR response and back to idle state. - * - * @param self pointer to at command parser object - * @param status response status 0 - OK, else ERROR - * @return according to cat_return_state enum definitions - */ -cat_status cat_hold_exit(struct cat_object *self, cat_status status); - -/** - * Function used to searching registered command by its name. - * - * @param self pointer to at command parser object - * @param name command name to search - * @return pointer to command object, NULL if command not found - */ -struct cat_command const* cat_search_command_by_name(struct cat_object *self, const char *name); - -/** - * Function used to searching registered command group by its name. - * - * @param self pointer to at command parser object - * @param name command group name to search - * @return pointer to command group object, NULL if command group not found - */ -struct cat_command_group const* cat_search_command_group_by_name(struct cat_object *self, const char *name); - -/** - * Function used to searching attached variable to command its name. - * - * @param self pointer to at command parser object - * @param cmd pointer to command in which variable will be searched - * @param name variable name to search - * @return pointer to command group object, NULL if command group not found - */ -struct cat_variable const* cat_search_variable_by_name(struct cat_object *self, struct cat_command const *cmd, const char *name); - -/** - * Function used to check what command is currently processed. - * Function is not protected by mutex mechanism, due to processed cmd may change after function return. - * This only matters in multithreaded environments, it does not matter for one thread. - * - * @param self pointer to at command parser object - * @param fsm type of internal state machine to check current command - * @return pointer to command which is currently processed, NULL if no command is processed - */ -struct cat_command const* cat_get_processed_command(struct cat_object *self, cat_fsm_type fsm); - -/** - * Function return unsolicited event command status. - * Function is not protected by mutex mechanism, due to processed cmd may change after function return. - * This only matters in multithreaded environments, it does not matter for one thread. - * - * @param self pointer to at command parser object - * @param cmd pointer to command in which variable will be searched - * @param type type of unsolicited event - * @return CAT_STATUS_OK - command is not buffered nor processed - * CAT_STATUS_BUSY - command is waiting in buffer or is processed - */ -cat_status cat_is_unsolicited_event_buffered(struct cat_object *self, struct cat_command const *cmd, cat_cmd_type type); - -#ifdef __cplusplus -} -#endif - -#endif /* CAT_H */ diff --git a/components/api/lib/cAT/tests/test_cmd_list.c b/components/api/lib/cAT/tests/test_cmd_list.c deleted file mode 100755 index 214b732..0000000 --- a/components/api/lib/cAT/tests/test_cmd_list.c +++ /dev/null @@ -1,340 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char ack_results[512]; - -static int8_t var1; -static int8_t var2; - -static char const *input_text; -static size_t input_index; - -static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - return 0; -} - -static int cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - return 0; -} - -static int cmd_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - return 0; -} - -static int cmd_run(const struct cat_command *cmd) -{ - return 0; -} - -static int var1_write(const struct cat_variable *var, size_t write_size) -{ - return 0; -} - -static int var2_write(const struct cat_variable *var, size_t write_size) -{ - return 0; -} - -static int print_cmd_list(const struct cat_command *cmd) -{ - return CAT_RETURN_STATE_PRINT_CMD_LIST_OK; -} - -static struct cat_variable vars[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var1, - .data_size = sizeof(var1), - .write = var1_write - } -}; - -static struct cat_variable vars_ro[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var1, - .data_size = sizeof(var1), - .write = var1_write, - .access = CAT_VAR_ACCESS_READ_ONLY - } -}; - -static struct cat_variable vars_wo[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var1, - .data_size = sizeof(var1), - .write = var1_write, - .access = CAT_VAR_ACCESS_WRITE_ONLY - } -}; - -static struct cat_variable vars2[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var1, - .data_size = sizeof(var1), - .write = var1_write - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var2, - .data_size = sizeof(var2), - .write = var2_write - } -}; - -static struct cat_variable vars2_ro[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var1, - .data_size = sizeof(var1), - .write = var1_write, - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var2, - .data_size = sizeof(var2), - .write = var2_write - } -}; - -static struct cat_variable vars2_wo[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var1, - .data_size = sizeof(var1), - .write = var1_write, - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var2, - .data_size = sizeof(var2), - .write = var2_write - } -}; - -static struct cat_command cmds[] = { - { - .name = "+V1", - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - }, - { - .name = "+V1RO", - .var = vars_ro, - .var_num = sizeof(vars_ro) / sizeof(vars_ro[0]) - }, - { - .name = "+V1RW", - .var = vars_wo, - .var_num = sizeof(vars_wo) / sizeof(vars_wo[0]) - }, - { - .name = "+V11", - .var = vars2, - .var_num = sizeof(vars2) / sizeof(vars2[0]) - }, - { - .name = "+V11RO", - .var = vars2_ro, - .var_num = sizeof(vars2_ro) / sizeof(vars2_ro[0]) - }, - { - .name = "+V11WO", - .var = vars2_wo, - .var_num = sizeof(vars2_wo) / sizeof(vars2_wo[0]) - }, - { - .name = "+V2", - .write = cmd_write, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - }, - { - .name = "+V3", - .write = cmd_write, - .read = cmd_read, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - }, - { - .name = "+V4", - .write = cmd_write, - .read = cmd_read, - .test = cmd_test, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - }, - { - .name = "+V5", - .write = cmd_write, - .read = cmd_read, - .test = cmd_test, - .run = cmd_run, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - }, - { - .name = "+S1", - }, - { - .name = "+S2", - .write = cmd_write, - }, - { - .name = "+S3", - .write = cmd_write, - .read = cmd_read, - }, - { - .name = "+S4", - .write = cmd_write, - .read = cmd_read, - .test = cmd_test, - }, - { - .name = "+S5", - .write = cmd_write, - .read = cmd_read, - .test = cmd_test, - .run = cmd_run, - }, - { - .name = "+D1", - .write = cmd_write, - .read = cmd_read, - .test = cmd_test, - .run = cmd_run, - .disable = true, - }, - { - .name = "+T1", - .write = cmd_write, - .read = cmd_read, - .test = cmd_test, - .run = cmd_run, - .only_test = true, - }, - { - .name = "+T2", - .only_test = true, - }, - { - .name = "#HELP", - .run = print_cmd_list, - } -}; - -static char buf[512]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - memset(ack_results, 0, sizeof(ack_results)); -} - -static void print_raw_text(char *p) -{ - while (*p != '\0') { - if (*p == '\n') { - printf("\\n"); - } else { - putchar(*p); - } - p++; - } -} - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input("\nAT#HELP\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nAT+V1?\nAT+V1=\nAT+V1=?\n\nAT+V1RO?\nAT+V1RO=?\n\nAT+V1RW=\nAT+V1RW=?\n\nAT+V11?\nAT+V11=\nAT+V11=?\n\nAT+V11RO?\nAT+V11RO=\nAT+V11RO=?\n\nAT+V11WO?\nAT+V11WO=\nAT+V11WO=?\n\nAT+V2?\nAT+V2=\nAT+V2=?\n\nAT+V3?\nAT+V3=\nAT+V3=?\n\nAT+V4?\nAT+V4=\nAT+V4=?\n\nAT+V5\nAT+V5?\nAT+V5=\nAT+V5=?\n\nAT+S2=\n\nAT+S3?\nAT+S3=\n\nAT+S4?\nAT+S4=\nAT+S4=?\n\nAT+S5\nAT+S5?\nAT+S5=\nAT+S5=?\n\nAT+T1=?\n\nAT#HELP\n\nOK\n") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_hold_state.c b/components/api/lib/cAT/tests/test_hold_state.c deleted file mode 100755 index da17556..0000000 --- a/components/api/lib/cAT/tests/test_hold_state.c +++ /dev/null @@ -1,229 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char cmd_results[256]; -static char var_read_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int var_x, var_u1, var_u2; -static struct cat_object at; - -static struct cat_command u_cmds[]; - -static cat_return_state cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - cat_status s; - - strcat(cmd_results, " write:"); - strcat(cmd_results, cmd->name); - - if (var_x < 2) { - s = cat_trigger_unsolicited_read(&at, &u_cmds[var_x]); - assert(s == CAT_STATUS_OK); - - return CAT_RETURN_STATE_HOLD; - } - - return CAT_RETURN_STATE_ERROR; -} - -static cat_return_state cmd1_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - cat_status s; - - strcat(cmd_results, " read1:"); - strcat(cmd_results, cmd->name); - - if (var_u1 > 0) { - var_u1--; - s = cat_trigger_unsolicited_read(&at, cmd); - assert(s == CAT_STATUS_OK); - return CAT_RETURN_STATE_DATA_OK; - } - - return CAT_RETURN_STATE_HOLD_EXIT_OK; -} - -static cat_return_state cmd2_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - cat_status s; - - strcat(cmd_results, " read2:"); - strcat(cmd_results, cmd->name); - - if (var_u2 > 0) { - var_u2--; - s = cat_trigger_unsolicited_read(&at, cmd); - assert(s == CAT_STATUS_OK); - return CAT_RETURN_STATE_DATA_OK; - } - - cat_hold_exit(&at, CAT_STATUS_OK); - return CAT_RETURN_STATE_DATA_OK; -} - -static int var_read(const struct cat_variable *var) -{ - strcat(var_read_results, " var_read:"); - strcat(var_read_results, var->name); - - return 0; -} - -static struct cat_variable u_vars[] = { - { - .name = "U1", - .type = CAT_VAR_INT_DEC, - .data = &var_u1, - .data_size = sizeof(var_u1), - .read = var_read - }, - { - .name = "U2", - .type = CAT_VAR_INT_DEC, - .data = &var_u2, - .data_size = sizeof(var_u2), - .read = var_read - } -}; - -static struct cat_variable vars[] = { - { - .name = "X", - .type = CAT_VAR_INT_DEC, - .data = &var_x, - .data_size = sizeof(var_x), - .read = var_read - } -}; - -static struct cat_command cmds[] = { - { - .name = "+CMD", - .write = cmd_write, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]), - } -}; - -static struct cat_command u_cmds[] = { - { - .name = "+U1CMD", - .read = cmd1_read, - .var = &u_vars[0], - .var_num = 1, - }, - { - .name = "+U2CMD", - .read = cmd2_read, - .var = &u_vars[1], - .var_num = 1, - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - var_u1 = 2; - var_u2 = 3; - - memset(ack_results, 0, sizeof(ack_results)); - memset(cmd_results, 0, sizeof(cmd_results)); - memset(var_read_results, 0, sizeof(var_read_results)); -} - -static const char test_case_1[] = "\nAT+CMD=0\n\nAT+CMD=1\n"; - -int main(int argc, char **argv) -{ - cat_status s; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+U1CMD=2\n\n+U1CMD=1\n\nOK\n\n+U2CMD=3\n\n+U2CMD=2\n\n+U2CMD=1\n\n+U2CMD=0\n\nOK\n") == 0); - assert(strcmp(cmd_results, " write:+CMD read1:+U1CMD read1:+U1CMD read1:+U1CMD write:+CMD read2:+U2CMD read2:+U2CMD read2:+U2CMD read2:+U2CMD") == 0); - assert(strcmp(var_read_results, " var_read:U1 var_read:U1 var_read:U1 var_read:U2 var_read:U2 var_read:U2 var_read:U2") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_mutex.c b/components/api/lib/cAT/tests/test_mutex.c deleted file mode 100755 index 2cc07de..0000000 --- a/components/api/lib/cAT/tests/test_mutex.c +++ /dev/null @@ -1,185 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char run_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int a_run(const struct cat_command *cmd) -{ - strcat(run_results, " A:"); - strcat(run_results, cmd->name); - return 0; -} - -static int ap_run(const struct cat_command *cmd) -{ - strcat(run_results, " AP:"); - strcat(run_results, cmd->name); - return 0; -} - -static int test_run(const struct cat_command *cmd) -{ - strcat(run_results, " +TEST:"); - strcat(run_results, cmd->name); - return 0; -} - -static struct cat_command cmds[] = { - { - .name = "A", - .run = a_run - }, - { - .name = "AP", - .run = ap_run - }, - { - .name = "+TEST", - .run = test_run - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static int mutex_ret_lock; -static int mutex_ret_unlock; - -static int mutex_lock(void) -{ - return mutex_ret_lock; -} - -static int mutex_unlock(void) -{ - return mutex_ret_unlock; -} - -static struct cat_mutex_interface mutex = { - .lock = mutex_lock, - .unlock = mutex_unlock -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - mutex_ret_lock = 0; - mutex_ret_unlock = 0; - - memset(run_results, 0, sizeof(run_results)); - memset(ack_results, 0, sizeof(ack_results)); -} - -static const char test_case_1[] = "\nAT\nAT+test\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, &mutex); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n\nOK\n") == 0); - assert(strcmp(run_results, " +TEST:+TEST") == 0); - - mutex_ret_lock = 1; - mutex_ret_unlock = 0; - assert(cat_service(&at) == CAT_STATUS_ERROR_MUTEX_LOCK); - - mutex_ret_lock = 0; - mutex_ret_unlock = 1; - assert(cat_service(&at) == CAT_STATUS_ERROR_MUTEX_UNLOCK); - - mutex_ret_lock = 1; - mutex_ret_unlock = 0; - assert(cat_is_busy(&at) == CAT_STATUS_ERROR_MUTEX_LOCK); - - mutex_ret_lock = 0; - mutex_ret_unlock = 1; - assert(cat_is_busy(&at) == CAT_STATUS_ERROR_MUTEX_UNLOCK); - - mutex_ret_lock = 0; - mutex_ret_unlock = 0; - assert(cat_service(&at) == CAT_STATUS_OK); - assert(cat_is_busy(&at) == CAT_STATUS_OK); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_order.c b/components/api/lib/cAT/tests/test_order.c deleted file mode 100755 index f47fb2a..0000000 --- a/components/api/lib/cAT/tests/test_order.c +++ /dev/null @@ -1,223 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char run_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int e_run(const struct cat_command *cmd) -{ - strcat(run_results, " E:"); - strcat(run_results, cmd->name); - return 0; -} - -static int e0_run(const struct cat_command *cmd) -{ - strcat(run_results, " E0:"); - strcat(run_results, cmd->name); - return 0; -} - -static int e1_run(const struct cat_command *cmd) -{ - strcat(run_results, " E1:"); - strcat(run_results, cmd->name); - return 0; -} - -static struct cat_command cmds1[] = { - { - .name = "E", - .run = e_run, - }, - { - .name = "E0", - .run = e0_run, - }, - { - .name = "E1", - .run = e1_run, - } -}; - -static struct cat_command cmds2[] = { - { - .name = "E0", - .run = e0_run, - }, - { - .name = "E1", - .run = e1_run, - }, - { - .name = "E", - .run = e_run, - } -}; - -static struct cat_command cmds3[] = { - { - .name = "E0", - .run = e0_run, - }, - { - .name = "E", - .run = e_run, - }, - { - .name = "E1", - .run = e1_run, - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_1_group = { - .cmd = cmds1, - .cmd_num = sizeof(cmds1) / sizeof(cmds1[0]), -}; - -static struct cat_command_group *cmd_1_desc[] = { - &cmd_1_group -}; - -static struct cat_descriptor desc_1 = { - .cmd_group = cmd_1_desc, - .cmd_group_num = sizeof(cmd_1_desc) / sizeof(cmd_1_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static struct cat_command_group cmd_2_group = { - .cmd = cmds2, - .cmd_num = sizeof(cmds2) / sizeof(cmds2[0]), -}; - -static struct cat_command_group *cmd_2_desc[] = { - &cmd_2_group -}; - -static struct cat_descriptor desc_2 = { - .cmd_group = cmd_2_desc, - .cmd_group_num = sizeof(cmd_2_desc) / sizeof(cmd_2_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static struct cat_command_group cmd_3_group = { - .cmd = cmds3, - .cmd_num = sizeof(cmds3) / sizeof(cmds3[0]), -}; - -static struct cat_command_group *cmd_3_desc[] = { - &cmd_3_group -}; - -static struct cat_descriptor desc_3 = { - .cmd_group = cmd_3_desc, - .cmd_group_num = sizeof(cmd_3_desc) / sizeof(cmd_3_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - memset(run_results, 0, sizeof(run_results)); - memset(ack_results, 0, sizeof(ack_results)); -} - -static const char test_case_1[] = "\nATE\n\nATE0\n\nATE1\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc_1, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n\nOK\n\nOK\n") == 0); - assert(strcmp(run_results, " E:E E0:E0 E1:E1") == 0); - - cat_init(&at, &desc_2, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n\nOK\n\nOK\n") == 0); - assert(strcmp(run_results, " E:E E0:E0 E1:E1") == 0); - - cat_init(&at, &desc_3, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n\nOK\n\nOK\n") == 0); - assert(strcmp(run_results, " E:E E0:E0 E1:E1") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_parse.c b/components/api/lib/cAT/tests/test_parse.c deleted file mode 100755 index 50e803d..0000000 --- a/components/api/lib/cAT/tests/test_parse.c +++ /dev/null @@ -1,195 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char run_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int a_run(const struct cat_command *cmd) -{ - strcat(run_results, " A:"); - strcat(run_results, cmd->name); - return 0; -} - -static int ap_run(const struct cat_command *cmd) -{ - strcat(run_results, " AP:"); - strcat(run_results, cmd->name); - return 0; -} - -static int test_run(const struct cat_command *cmd) -{ - strcat(run_results, " +TEST:"); - strcat(run_results, cmd->name); - return 0; -} - -static struct cat_command cmds[] = { - { - .name = "A", - .run = a_run, - .disable = false, - }, - { - .name = "AP", - .run = ap_run, - .disable = false, - }, - { - .name = "+TEST", - .run = test_run, - .disable = false, - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - memset(run_results, 0, sizeof(run_results)); - memset(ack_results, 0, sizeof(ack_results)); -} - -static const char test_case_1[] = "\nsa\rAT\n\r\nAT\nAT+\n\nATA\r\natap\naaaattttap\na\n\r+test\r\n+testATA\nATAPATAP\n\rAT\rATA\nAT+test\r\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\r\nERROR\r\n\nOK\n\nOK\n\r\nOK\r\n\nOK\n\nERROR\n\nERROR\n\r\nERROR\r\n\nERROR\n\nERROR\n\r\nERROR\r\n\r\nOK\r\n") == 0); - assert(strcmp(run_results, " +TEST:+TEST A:A AP:AP +TEST:+TEST") == 0); - - prepare_input("\nAT\n"); - while (cat_service(&at) != 0) {}; - - assert(cat_is_busy(&at) == 0); - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(strcmp(run_results, "") == 0); - - prepare_input("\nAT+te"); - while (cat_service(&at) != 0) {}; - - assert(cat_is_busy(&at) != 0); - assert(strcmp(ack_results, "") == 0); - assert(strcmp(run_results, "") == 0); - - prepare_input("st\n"); - while (cat_service(&at) != 0) {}; - - assert(cat_is_busy(&at) == 0); - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(strcmp(run_results, " +TEST:+TEST") == 0); - - struct cat_command *cmd; - - cmd = (struct cat_command*)cat_search_command_by_name(&at, "A"); - cmd->disable = true; - cmd = (struct cat_command*)cat_search_command_by_name(&at, "+TEST"); - cmd->disable = true; - - prepare_input("\nATA\n\nATAP\n\nAT+TEST\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n\nOK\n\nERROR\n") == 0); - assert(strcmp(run_results, " AP:AP AP:AP") == 0); - - struct cat_command_group *cmd_group; - cmd_group = (struct cat_command_group*)cat_search_command_group_by_name(&at, "standard"); - assert(cmd_group == NULL); - - cmd_desc[0]->name = "standard"; - cmd_group = (struct cat_command_group*)cat_search_command_group_by_name(&at, "standard"); - assert(cmd_group == cmd_desc[0]); - cmd_group->disable = true; - - prepare_input("\nATA\n\nATAP\n\nAT+TEST\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n\nERROR\n\nERROR\n") == 0); - assert(strcmp(run_results, "") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_read.c b/components/api/lib/cAT/tests/test_read.c deleted file mode 100755 index 9e21eae..0000000 --- a/components/api/lib/cAT/tests/test_read.c +++ /dev/null @@ -1,165 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char run_results[256]; -static char read_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int a_run(const struct cat_command *cmd) -{ - strcat(run_results, " A_"); - strcat(run_results, cmd->name); - return 0; -} - -static int a_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(read_results, " A:"); - strcat(read_results, cmd->name); - - snprintf(data, max_data_size, "%s=A-val", cmd->name); - *data_size = strlen(data); - - return 0; -} - -static int ap_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(read_results, " AP:"); - strcat(read_results, cmd->name); - - *data_size = 0; - - return 0; -} - -static int test_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(read_results, " +TEST:"); - strcat(read_results, cmd->name); - - return -1; -} - -static struct cat_command cmds[] = { - { - .name = "A", - .read = a_read, - .run = a_run - }, - { - .name = "AP", - .read = ap_read - }, - { - .name = "+TEST", - .read = test_read - }, - { - .name = "+EMPTY" - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - memset(run_results, 0, sizeof(run_results)); - memset(ack_results, 0, sizeof(ack_results)); - memset(read_results, 0, sizeof(read_results)); -} - -static const char test_case_1[] = "\nAT\r\nAT+\nAT+?\nATA?\r\nATAP\nATAP?\nATAPA?\nAT+TEST?\nAT+te?\nAT+e?\nAT+empTY?\r\nATA\r\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\r\nOK\r\n\nERROR\n\nERROR\n\r\nA=A-val\r\n\r\nOK\r\n\nERROR\n\nAP=\n\nOK\n\nERROR\n\nERROR\n\nERROR\n\nERROR\n\r\nERROR\r\n\r\nOK\r\n") == 0); - assert(strcmp(run_results, " A_A") == 0); - assert(strcmp(read_results, " A:A AP:AP +TEST:+TEST +TEST:+TEST") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_read_args.c b/components/api/lib/cAT/tests/test_read_args.c deleted file mode 100755 index e68dd3b..0000000 --- a/components/api/lib/cAT/tests/test_read_args.c +++ /dev/null @@ -1,225 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char ack_results[256]; - -static int8_t var_int; -static uint8_t var_uint; -static uint8_t var_hex8; -static uint16_t var_hex16; -static uint32_t var_hex32; -static uint8_t var_buf[4]; -static char var_string[16]; - -static char const *input_text; -static size_t input_index; -static int common_cntr; -static uint8_t ctx; - -static int cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - return 0; -} - -static int cmd2_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - sprintf(data, "%s=test", cmd->name); - *data_size = strlen(data); - return 0; -} - -static int common_var_read_handler(const struct cat_variable *var) -{ - common_cntr++; - return 0; -} - -static void* var_int_data_getter(const struct cat_variable *var, void *context, size_t *data_size) -{ - *data_size = sizeof(var_int); - assert(context == &ctx); - return &var_int; -} - -static struct cat_variable vars[] = { - { - .type = CAT_VAR_INT_DEC, - .read = common_var_read_handler, - .data_getter = var_int_data_getter, - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint, - .data_size = sizeof(var_uint), - .read = common_var_read_handler - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex8, - .data_size = sizeof(var_hex8), - .read = common_var_read_handler - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex16, - .data_size = sizeof(var_hex16), - .read = common_var_read_handler - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex32, - .data_size = sizeof(var_hex32), - .read = common_var_read_handler - }, - { - .type = CAT_VAR_BUF_HEX, - .data = &var_buf, - .data_size = sizeof(var_buf), - .read = common_var_read_handler - }, - { - .type = CAT_VAR_BUF_STRING, - .data = &var_string, - .data_size = sizeof(var_string), - .read = common_var_read_handler - } -}; - -static struct cat_command cmds[] = { - { - .name = "+SET", - .read = cmd_read, - - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]), - .context = &ctx, - }, - { - .name = "+TEST", - .read = cmd2_read, - - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]), - .context = &ctx, - }, -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - var_int = -1; - var_uint = 255; - var_hex8 = 0xAA; - var_hex16 = 0x0123; - var_hex32 = 0xFF001234; - - var_buf[0] = 0x12; - var_buf[1] = 0x34; - var_buf[2] = 0x56; - var_buf[3] = 0x78; - - common_cntr = 0; - - sprintf(var_string, "\\\"test\n"); - - memset(ack_results, 0, sizeof(ack_results)); -} - -static const char test_case_1[] = "\nAT+SET?\r\n"; -static const char test_case_2[] = "\nAT+TEST?\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\r\n+SET=-1,255,0xAA,0x0123,0xFF001234,12345678,\"\\\\\\\"test\\n\"\r\n\r\nOK\r\n") == 0); - assert(common_cntr == 7); - - prepare_input(test_case_2); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+TEST=test\n\nOK\n") == 0); - assert(common_cntr == 7); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_return_read.c b/components/api/lib/cAT/tests/test_return_read.c deleted file mode 100755 index fc8089b..0000000 --- a/components/api/lib/cAT/tests/test_return_read.c +++ /dev/null @@ -1,206 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char cmd_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int var_x; -static struct cat_object at; - -static cat_return_state ret; -static bool ret_error; - -static cat_return_state cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(cmd_results, " read:"); - strcat(cmd_results, cmd->name); - - if (cat_is_hold(&at) == CAT_STATUS_HOLD) { - var_x++; - if (var_x > 4) { - ret = (ret_error == false) ? CAT_RETURN_STATE_HOLD_EXIT_OK : CAT_RETURN_STATE_HOLD_EXIT_ERROR; - } else { - if (var_x == 4) { - strcpy(data, "test"); - *data_size = strlen(data); - } - ret = CAT_RETURN_STATE_DATA_NEXT; - } - } else { - if ((ret == CAT_RETURN_STATE_DATA_NEXT) || (ret == CAT_RETURN_STATE_NEXT)) { - var_x++; - if (var_x > 2) - ret = CAT_RETURN_STATE_DATA_OK; - } else if (ret == CAT_RETURN_STATE_HOLD) { - cat_trigger_unsolicited_read(&at, cmd); - } - } - - return ret; -} - -static struct cat_variable vars[] = { - { - .name = "X", - .type = CAT_VAR_INT_DEC, - .data = &var_x, - .data_size = sizeof(var_x) - } -}; - -static struct cat_command cmds[] = { - { - .name = "+CMD", - .read = cmd_read, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]), - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - var_x = 1; - - memset(ack_results, 0, sizeof(ack_results)); - memset(cmd_results, 0, sizeof(cmd_results)); -} - -static const char test_case_1[] = "\nAT+CMD?\n"; - -int main(int argc, char **argv) -{ - cat_status s; - - cat_init(&at, &desc, &iface, NULL); - - ret = CAT_RETURN_STATE_ERROR; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n") == 0); - assert(strcmp(cmd_results, " read:+CMD") == 0); - - ret = CAT_RETURN_STATE_DATA_OK; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=1\n\nOK\n") == 0); - assert(strcmp(cmd_results, " read:+CMD") == 0); - - ret = CAT_RETURN_STATE_DATA_NEXT; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=1\n\n+CMD=2\n\nOK\n") == 0); - assert(strcmp(cmd_results, " read:+CMD read:+CMD") == 0); - - ret = CAT_RETURN_STATE_NEXT; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=2\n\nOK\n") == 0); - assert(strcmp(cmd_results, " read:+CMD read:+CMD") == 0); - - ret = CAT_RETURN_STATE_OK; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(strcmp(cmd_results, " read:+CMD") == 0); - - ret_error = false; - ret = CAT_RETURN_STATE_HOLD; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=1\n\n+CMD=2\n\ntest\n\nOK\n") == 0); - assert(strcmp(cmd_results, " read:+CMD read:+CMD read:+CMD read:+CMD read:+CMD") == 0); - - ret_error = true; - ret = CAT_RETURN_STATE_HOLD; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=1\n\n+CMD=2\n\ntest\n\nERROR\n") == 0); - assert(strcmp(cmd_results, " read:+CMD read:+CMD read:+CMD read:+CMD read:+CMD") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_return_run.c b/components/api/lib/cAT/tests/test_return_run.c deleted file mode 100755 index 2403b1b..0000000 --- a/components/api/lib/cAT/tests/test_return_run.c +++ /dev/null @@ -1,236 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char cmd_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int var_x; -static struct cat_object at; - -static cat_return_state ret; -static bool ret_error; - -static cat_return_state cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(cmd_results, " read:"); - strcat(cmd_results, cmd->name); - - var_x++; - if (var_x > 5) { - ret = (ret_error == false) ? CAT_RETURN_STATE_HOLD_EXIT_OK : CAT_RETURN_STATE_HOLD_EXIT_ERROR; - } else { - if (var_x == 5) { - strcpy(data, "test"); - *data_size = strlen(data); - } - ret = CAT_RETURN_STATE_DATA_NEXT; - } - - return ret; -} - -static cat_return_state cmd_run(const struct cat_command *cmd) -{ - strcat(cmd_results, " run:"); - strcat(cmd_results, cmd->name); - - if ((ret == CAT_RETURN_STATE_DATA_NEXT) || (ret == CAT_RETURN_STATE_NEXT)) { - var_x++; - if (var_x > 3) - ret = CAT_RETURN_STATE_DATA_OK; - } else if (ret == CAT_RETURN_STATE_HOLD) { - cat_trigger_unsolicited_read(&at, cmd); - } - - return ret; -} - -static struct cat_variable vars[] = { - { - .name = "X", - .type = CAT_VAR_INT_DEC, - .data = &var_x, - .data_size = sizeof(var_x) - } -}; - -static struct cat_command cmds[] = { - { - .name = "+CMD", - .run = cmd_run, - .read = cmd_read, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]), - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - var_x = 2; - - memset(ack_results, 0, sizeof(ack_results)); - memset(cmd_results, 0, sizeof(cmd_results)); -} - -static const char test_case_1[] = "\nAT+CMD\n"; - -int main(int argc, char **argv) -{ - cat_status s; - - cat_init(&at, &desc, &iface, NULL); - - ret = CAT_RETURN_STATE_ERROR; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n") == 0); - assert(strcmp(cmd_results, " run:+CMD") == 0); - assert(var_x == 2); - - ret = CAT_RETURN_STATE_DATA_OK; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(strcmp(cmd_results, " run:+CMD") == 0); - assert(var_x == 2); - - ret = CAT_RETURN_STATE_DATA_NEXT; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(strcmp(cmd_results, " run:+CMD run:+CMD") == 0); - assert(var_x == 4); - - ret = CAT_RETURN_STATE_NEXT; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(strcmp(cmd_results, " run:+CMD run:+CMD") == 0); - assert(var_x == 4); - - ret = CAT_RETURN_STATE_OK; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(strcmp(cmd_results, " run:+CMD") == 0); - assert(var_x == 2); - - ret_error = false; - ret = CAT_RETURN_STATE_HOLD; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=2\n\n+CMD=3\n\ntest\n\nOK\n") == 0); - assert(strcmp(cmd_results, " run:+CMD read:+CMD read:+CMD read:+CMD read:+CMD") == 0); - assert(var_x == 6); - - ret_error = true; - ret = CAT_RETURN_STATE_HOLD; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=2\n\n+CMD=3\n\ntest\n\nERROR\n") == 0); - assert(strcmp(cmd_results, " run:+CMD read:+CMD read:+CMD read:+CMD read:+CMD") == 0); - assert(var_x == 6); - - ret = CAT_RETURN_STATE_HOLD_EXIT_ERROR; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n") == 0); - assert(strcmp(cmd_results, " run:+CMD") == 0); - assert(var_x == 2); - - ret = CAT_RETURN_STATE_HOLD_EXIT_OK; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n") == 0); - assert(strcmp(cmd_results, " run:+CMD") == 0); - assert(var_x == 2); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_return_test.c b/components/api/lib/cAT/tests/test_return_test.c deleted file mode 100755 index e16f546..0000000 --- a/components/api/lib/cAT/tests/test_return_test.c +++ /dev/null @@ -1,206 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char cmd_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int var_x; -static struct cat_object at; - -static cat_return_state ret; -static bool ret_error; - -static cat_return_state cmd_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(cmd_results, " test:"); - strcat(cmd_results, cmd->name); - - if (cat_is_hold(&at) == CAT_STATUS_HOLD) { - var_x++; - if (var_x > 4) { - ret = (ret_error == false) ? CAT_RETURN_STATE_HOLD_EXIT_OK : CAT_RETURN_STATE_HOLD_EXIT_ERROR; - } else { - if (var_x == 4) { - strcpy(data, "test"); - *data_size = strlen(data); - } - ret = CAT_RETURN_STATE_DATA_NEXT; - } - } else { - if ((ret == CAT_RETURN_STATE_DATA_NEXT) || (ret == CAT_RETURN_STATE_NEXT)) { - var_x++; - if (var_x > 2) - ret = CAT_RETURN_STATE_DATA_OK; - } else if (ret == CAT_RETURN_STATE_HOLD) { - cat_trigger_unsolicited_test(&at, cmd); - } - } - - return ret; -} - -static struct cat_variable vars[] = { - { - .name = "X", - .type = CAT_VAR_INT_DEC, - .data = &var_x, - .data_size = sizeof(var_x) - } -}; - -static struct cat_command cmds[] = { - { - .name = "+CMD", - .test = cmd_test, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]), - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - var_x = 1; - - memset(ack_results, 0, sizeof(ack_results)); - memset(cmd_results, 0, sizeof(cmd_results)); -} - -static const char test_case_1[] = "\nAT+CMD=?\n"; - -int main(int argc, char **argv) -{ - cat_status s; - - cat_init(&at, &desc, &iface, NULL); - - ret = CAT_RETURN_STATE_ERROR; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n") == 0); - assert(strcmp(cmd_results, " test:+CMD") == 0); - - ret = CAT_RETURN_STATE_DATA_OK; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=\n\nOK\n") == 0); - assert(strcmp(cmd_results, " test:+CMD") == 0); - - ret = CAT_RETURN_STATE_DATA_NEXT; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=\n\n+CMD=\n\nOK\n") == 0); - assert(strcmp(cmd_results, " test:+CMD test:+CMD") == 0); - - ret = CAT_RETURN_STATE_NEXT; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=\n\nOK\n") == 0); - assert(strcmp(cmd_results, " test:+CMD test:+CMD") == 0); - - ret = CAT_RETURN_STATE_OK; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(strcmp(cmd_results, " test:+CMD") == 0); - - ret_error = false; - ret = CAT_RETURN_STATE_HOLD; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=\n\n+CMD=\n\ntest\n\nOK\n") == 0); - assert(strcmp(cmd_results, " test:+CMD test:+CMD test:+CMD test:+CMD test:+CMD") == 0); - - ret_error = true; - ret = CAT_RETURN_STATE_HOLD; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=\n\n+CMD=\n\ntest\n\nERROR\n") == 0); - assert(strcmp(cmd_results, " test:+CMD test:+CMD test:+CMD test:+CMD test:+CMD") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_return_write.c b/components/api/lib/cAT/tests/test_return_write.c deleted file mode 100755 index 8375fd0..0000000 --- a/components/api/lib/cAT/tests/test_return_write.c +++ /dev/null @@ -1,236 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char cmd_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int var_x; -static struct cat_object at; - -static cat_return_state ret; -static bool ret_error; - -static cat_return_state cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(cmd_results, " read:"); - strcat(cmd_results, cmd->name); - - var_x++; - if (var_x > 5) { - ret = (ret_error == false) ? CAT_RETURN_STATE_HOLD_EXIT_OK : CAT_RETURN_STATE_HOLD_EXIT_ERROR; - } else { - if (var_x == 5) { - strcpy(data, "test"); - *data_size = strlen(data); - } - ret = CAT_RETURN_STATE_DATA_NEXT; - } - - return ret; -} - -static cat_return_state cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - strcat(cmd_results, " write:"); - strcat(cmd_results, cmd->name); - - if ((ret == CAT_RETURN_STATE_DATA_NEXT) || (ret == CAT_RETURN_STATE_NEXT)) { - var_x++; - if (var_x > 3) - ret = CAT_RETURN_STATE_DATA_OK; - } else if (ret == CAT_RETURN_STATE_HOLD) { - cat_trigger_unsolicited_read(&at, cmd); - } - - return ret; -} - -static struct cat_variable vars[] = { - { - .name = "X", - .type = CAT_VAR_INT_DEC, - .data = &var_x, - .data_size = sizeof(var_x) - } -}; - -static struct cat_command cmds[] = { - { - .name = "+CMD", - .write = cmd_write, - .read = cmd_read, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]), - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - var_x = 1; - - memset(ack_results, 0, sizeof(ack_results)); - memset(cmd_results, 0, sizeof(cmd_results)); -} - -static const char test_case_1[] = "\nAT+CMD=2\n"; - -int main(int argc, char **argv) -{ - cat_status s; - - cat_init(&at, &desc, &iface, NULL); - - ret = CAT_RETURN_STATE_ERROR; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n") == 0); - assert(strcmp(cmd_results, " write:+CMD") == 0); - assert(var_x == 2); - - ret = CAT_RETURN_STATE_DATA_OK; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(strcmp(cmd_results, " write:+CMD") == 0); - assert(var_x == 2); - - ret = CAT_RETURN_STATE_DATA_NEXT; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(strcmp(cmd_results, " write:+CMD write:+CMD") == 0); - assert(var_x == 4); - - ret = CAT_RETURN_STATE_NEXT; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(strcmp(cmd_results, " write:+CMD write:+CMD") == 0); - assert(var_x == 4); - - ret = CAT_RETURN_STATE_OK; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(strcmp(cmd_results, " write:+CMD") == 0); - assert(var_x == 2); - - ret_error = false; - ret = CAT_RETURN_STATE_HOLD; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=2\n\n+CMD=3\n\ntest\n\nOK\n") == 0); - assert(strcmp(cmd_results, " write:+CMD read:+CMD read:+CMD read:+CMD read:+CMD") == 0); - assert(var_x == 6); - - ret_error = true; - ret = CAT_RETURN_STATE_HOLD; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+CMD=2\n\n+CMD=3\n\ntest\n\nERROR\n") == 0); - assert(strcmp(cmd_results, " write:+CMD read:+CMD read:+CMD read:+CMD read:+CMD") == 0); - assert(var_x == 6); - - ret = CAT_RETURN_STATE_HOLD_EXIT_ERROR; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n") == 0); - assert(strcmp(cmd_results, " write:+CMD") == 0); - assert(var_x == 2); - - ret = CAT_RETURN_STATE_HOLD_EXIT_OK; - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n") == 0); - assert(strcmp(cmd_results, " write:+CMD") == 0); - assert(var_x == 2); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_run.c b/components/api/lib/cAT/tests/test_run.c deleted file mode 100755 index 6b02e3a..0000000 --- a/components/api/lib/cAT/tests/test_run.c +++ /dev/null @@ -1,157 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char run_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int a_run(const struct cat_command *cmd) -{ - strcat(run_results, " A:"); - strcat(run_results, cmd->name); - return 0; -} - -static int ap_run(const struct cat_command *cmd) -{ - strcat(run_results, " AP:"); - strcat(run_results, cmd->name); - return 0; -} - -static int test_run(const struct cat_command *cmd) -{ - strcat(run_results, " +TEST:"); - strcat(run_results, cmd->name); - return 0; -} - -static int force_run(const struct cat_command *cmd) -{ - strcat(run_results, " FORCE:"); - strcat(run_results, cmd->name); - return -1; -} - -static struct cat_command cmds[] = { - { - .name = "A", - .run = a_run - }, - { - .name = "AP", - .run = ap_run - }, - { - .name = "+TEST", - .run = test_run - }, - { - .name = "+EMPTY" - }, - { - .name = "FORCE", - .run = force_run, - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - memset(run_results, 0, sizeof(run_results)); - memset(ack_results, 0, sizeof(ack_results)); -} - -static const char test_case_1[] = "\nAT\nAT+\nATA\r\nATAP\nATAPA\nAT+TEST\nAT+te\nAT+e\nAT+empTY\naTf\nAtFoRcE\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n\nERROR\n\r\nOK\r\n\nOK\n\nERROR\n\nOK\n\nOK\n\nERROR\n\nERROR\n\nERROR\n\nERROR\n") == 0); - assert(strcmp(run_results, " A:A AP:AP +TEST:+TEST +TEST:+TEST FORCE:FORCE FORCE:FORCE") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_search_cmd.c b/components/api/lib/cAT/tests/test_search_cmd.c deleted file mode 100755 index 6679911..0000000 --- a/components/api/lib/cAT/tests/test_search_cmd.c +++ /dev/null @@ -1,224 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static int ap_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - return 0; -} - -static int ap_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - return 0; -} - -static struct cat_variable vars_ap1[] = { - { - .name = "var_ap1_1" - }, - { - .name = "var_ap1_2" - }, - { - .name = "var_ap1_3" - } -}; - -static struct cat_variable vars_apx2[] = { - { - .name = "var_apx2_1" - }, - { - .name = "var_apx2_2" - }, - { - .name = "var_apx2_3" - } -}; - -static struct cat_command cmds[] = { - { - .name = "AP1", - .write = ap_write, - .only_test = true, - .var = vars_ap1, - .var_num = sizeof(vars_ap1) / sizeof(vars_ap1[0]) - }, - { - .name = "AP2", - .read = ap_read, - .only_test = false - }, -}; - -static struct cat_command cmds2[] = { - { - .name = "APX1", - .write = ap_write, - .only_test = true - }, - { - .name = "APX2", - .read = ap_read, - .only_test = false, - .var = vars_apx2, - .var_num = sizeof(vars_apx2) / sizeof(vars_apx2[0]) - }, -}; - -static char buf[128]; - -static struct cat_command_group cmd_group1 = { - .name = "std", - - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group cmd_group2 = { - .name = "ext", - - .cmd = cmds2, - .cmd_num = sizeof(cmds2) / sizeof(cmds2[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group1, - &cmd_group2 -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - return 1; -} - -static int read_char(char *ch) -{ - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -int main(int argc, char **argv) -{ - struct cat_object at; - struct cat_command const *cmd; - struct cat_command_group const *cmd_group; - struct cat_variable const *var; - - cat_init(&at, &desc, &iface, NULL); - - cmd = cat_search_command_by_name(&at, "A"); - assert(cmd == NULL); - - cmd = cat_search_command_by_name(&at, "AP"); - assert(cmd == NULL); - - cmd = cat_search_command_by_name(&at, "AP1"); - assert(cmd == &cmds[0]); - - cmd = cat_search_command_by_name(&at, "AP2"); - assert(cmd == &cmds[1]); - - cmd = cat_search_command_by_name(&at, "AP3"); - assert(cmd == NULL); - - cmd = cat_search_command_by_name(&at, "APX1"); - assert(cmd == &cmds2[0]); - - cmd = cat_search_command_by_name(&at, "APX2"); - assert(cmd == &cmds2[1]); - - cmd = cat_search_command_by_name(&at, "APX3"); - assert(cmd == NULL); - - cmd_group = cat_search_command_group_by_name(&at, "std"); - assert(cmd_group == cmd_desc[0]); - - cmd_group = cat_search_command_group_by_name(&at, "ext"); - assert(cmd_group == cmd_desc[1]); - - cmd_group = cat_search_command_group_by_name(&at, "not"); - assert(cmd_group == NULL); - - var = cat_search_variable_by_name(&at, &cmds[0], "v"); - assert(var == NULL); - - var = cat_search_variable_by_name(&at, &cmds[0], "var_ap"); - assert(var == NULL); - - var = cat_search_variable_by_name(&at, &cmds[0], "var_apx2"); - assert(var == NULL); - - var = cat_search_variable_by_name(&at, &cmds[0], "var_ap1_1"); - assert(var == &vars_ap1[0]); - - var = cat_search_variable_by_name(&at, &cmds[0], "var_ap1_2"); - assert(var == &vars_ap1[1]); - - var = cat_search_variable_by_name(&at, &cmds[0], "var_ap1_3"); - assert(var == &vars_ap1[2]); - - var = cat_search_variable_by_name(&at, &cmds[0], "var_ap1_4"); - assert(var == NULL); - - var = cat_search_variable_by_name(&at, &cmds[1], "var_ap1_1"); - assert(var == NULL); - - var = cat_search_variable_by_name(&at, &cmds2[1], "var_apx2_1"); - assert(var == &vars_apx2[0]); - - var = cat_search_variable_by_name(&at, &cmds2[1], "var_apx2_2"); - assert(var == &vars_apx2[1]); - - var = cat_search_variable_by_name(&at, &cmds2[1], "var_apx2_3"); - assert(var == &vars_apx2[2]); - - var = cat_search_variable_by_name(&at, &cmds2[1], "var_apx2_4"); - assert(var == NULL); - - var = cat_search_variable_by_name(&at, &cmds2[0], "var_apx2_1"); - assert(var == NULL); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_shortcuts.c b/components/api/lib/cAT/tests/test_shortcuts.c deleted file mode 100755 index 4a2bc6f..0000000 --- a/components/api/lib/cAT/tests/test_shortcuts.c +++ /dev/null @@ -1,149 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char run_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int print_name(const struct cat_command *cmd) -{ - strcat(run_results, cmd->name); - strcat(run_results, " "); - return 0; -} - -static struct cat_command cmds[] = { - { - .name = "+TEST", - .run = print_name - }, - { - .name = "+TEST_A", - .run = print_name - }, - { - .name = "+TEST_B", - .run = print_name - }, - { - .name = "+ONE", - .run = print_name - }, - { - .name = "+TWO", - .run = print_name - }, -}; - -static char buf[256]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - memset(run_results, 0, sizeof(run_results)); - memset(ack_results, 0, sizeof(ack_results)); -} - -static const char test_case_1[] = "\nAT\nAT+\nAT+T\nAT+TE\nAT+TES\nAT+TEST\nAT+TEST_\nAT+TEST_A\nAT+TEST_B\nAT+O\nAT+ON\nAT+ONE\nAT+TW\nAT+TWO\n"; - -static void print_raw_text(char *p) -{ - while (*p != '\0') { - if (*p == '\n') { - printf("\\n"); - } else { - putchar(*p); - } - p++; - } -} - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n\nERROR\n\nERROR\n\nERROR\n\nERROR\n\nOK\n\nERROR\n\nOK\n\nOK\n\nOK\n\nOK\n\nOK\n\nOK\n\nOK\n") == 0); - assert(strcmp(run_results, "+TEST +TEST_A +TEST_B +ONE +ONE +ONE +TWO +TWO ") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_test.c b/components/api/lib/cAT/tests/test_test.c deleted file mode 100755 index 204351c..0000000 --- a/components/api/lib/cAT/tests/test_test.c +++ /dev/null @@ -1,183 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char test_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int a_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(test_results, " A:"); - strcat(test_results, cmd->name); - - snprintf(data, max_data_size, "%s=A-val", cmd->name); - *data_size = strlen(data); - - return 0; -} - -static int ap_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(test_results, " AP:"); - strcat(test_results, cmd->name); - - *data_size = 0; - - return 0; -} - -static int ap_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - strcat(test_results, " AP_W:"); - strcat(test_results, cmd->name); - - assert(args_num == 0); - assert(data[0] == 'a'); - assert(data_size == 1); - - return 0; -} - -static int apw_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - strcat(test_results, " APW:"); - strcat(test_results, cmd->name); - - assert(args_num == 0); - assert(data[0] == '?'); - assert(data_size == 1); - - return 0; -} - -static int test_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(test_results, " +TEST:"); - strcat(test_results, cmd->name); - - return -1; -} - -static struct cat_command cmds[] = { - { - .name = "A", - .test = a_test - }, - { - .name = "AP", - .test = ap_test, - .write = ap_write - }, - { - .name = "APW", - .write = apw_write - }, - { - .name = "+TEST", - .test = test_test - }, - { - .name = "+EMPTY" - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - memset(ack_results, 0, sizeof(ack_results)); - memset(test_results, 0, sizeof(test_results)); -} - -static const char test_case_1[] = "\nAT\r\nAT\nATAP=?\nATAP=?a\nATAP=a\nATAPW=?\nAT+TEST=?\nATA=?\nAT+EMPTY=?\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\r\nOK\r\n\nOK\n\nAP=\n\nOK\n\nERROR\n\nOK\n\nOK\n\nERROR\n\nA=A-val\n\nOK\n\nERROR\n") == 0); - assert(strcmp(test_results, " AP:AP AP_W:AP APW:APW +TEST:+TEST A:A") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_test_args.c b/components/api/lib/cAT/tests/test_test_args.c deleted file mode 100755 index 54aee2e..0000000 --- a/components/api/lib/cAT/tests/test_test_args.c +++ /dev/null @@ -1,459 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char ack_results[256]; - -static int8_t var_int8; -static int16_t var_int16; -static int32_t var_int32; -static uint8_t var_uint8; -static uint16_t var_uint16; -static uint32_t var_uint32; -static uint8_t var_hex8; -static uint16_t var_hex16; -static uint32_t var_hex32; -static uint8_t var_buf[4]; -static char var_string[16]; - -static char const *input_text; -static size_t input_index; - -static int cmd_override_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(data, "\ntest"); - *data_size = strlen(data); - return 0; -} - -static int cmd_error_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - return -1; -} - -static int cmd_ok_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcpy(data, "test1"); - *data_size = strlen(data); - return 0; -} - -static int cmd_ok2_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(data, "test2"); - *data_size = strlen(data); - return 0; -} - -static struct cat_variable vars[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var_int8, - .data_size = sizeof(var_int8), - .name = "x" - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var_int16, - .data_size = sizeof(var_int16), - .name = "y" - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var_int32, - .data_size = sizeof(var_int32) - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint8, - .data_size = sizeof(var_uint8) - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint16, - .data_size = sizeof(var_uint16) - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint32, - .data_size = sizeof(var_uint32) - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex8, - .data_size = sizeof(var_hex8) - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex16, - .data_size = sizeof(var_hex16) - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex32, - .data_size = sizeof(var_hex32) - }, - { - .type = CAT_VAR_BUF_HEX, - .data = &var_buf, - .data_size = sizeof(var_buf) - }, - { - .type = CAT_VAR_BUF_STRING, - .data = &var_string, - .data_size = sizeof(var_string), - .name = "msg" - } -}; - -static struct cat_variable vars_ro[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var_int8, - .data_size = sizeof(var_int8), - .name = "x", - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var_int16, - .data_size = sizeof(var_int16), - .name = "y", - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var_int32, - .data_size = sizeof(var_int32), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint8, - .data_size = sizeof(var_uint8), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint16, - .data_size = sizeof(var_uint16), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint32, - .data_size = sizeof(var_uint32), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex8, - .data_size = sizeof(var_hex8), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex16, - .data_size = sizeof(var_hex16), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex32, - .data_size = sizeof(var_hex32), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_BUF_HEX, - .data = &var_buf, - .data_size = sizeof(var_buf), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_BUF_STRING, - .data = &var_string, - .data_size = sizeof(var_string), - .name = "msg", - .access = CAT_VAR_ACCESS_READ_ONLY - } -}; - -static struct cat_variable vars_wo[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var_int8, - .data_size = sizeof(var_int8), - .name = "x", - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var_int16, - .data_size = sizeof(var_int16), - .name = "y", - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var_int32, - .data_size = sizeof(var_int32), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint8, - .data_size = sizeof(var_uint8), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint16, - .data_size = sizeof(var_uint16), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint32, - .data_size = sizeof(var_uint32), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex8, - .data_size = sizeof(var_hex8), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex16, - .data_size = sizeof(var_hex16), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex32, - .data_size = sizeof(var_hex32), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_BUF_HEX, - .data = &var_buf, - .data_size = sizeof(var_buf), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_BUF_STRING, - .data = &var_string, - .data_size = sizeof(var_string), - .name = "msg", - .access = CAT_VAR_ACCESS_WRITE_ONLY - } -}; - -static struct cat_variable vars2[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var_int8, - .data_size = sizeof(var_int8), - .name = "var" - } -}; - -static struct cat_command cmds[] = { - { - .name = "+SET", - - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - }, - { - .name = "+SETRO", - - .var = vars_ro, - .var_num = sizeof(vars_ro) / sizeof(vars_ro[0]) - }, - { - .name = "+SETWO", - - .var = vars_wo, - .var_num = sizeof(vars_wo) / sizeof(vars_wo[0]) - }, - { - .name = "+TEST", - .description = "test_desc", - .test = cmd_override_test, - - .var = vars2, - .var_num = sizeof(vars2) / sizeof(vars2[0]) - }, - { - .name = "+TEST2", - .description = "test2_desc", - - .var = vars2, - .var_num = sizeof(vars2) / sizeof(vars2[0]) - }, - { - .name = "+AP", - .test = cmd_error_test, - - .var = vars2, - .var_num = sizeof(vars2) / sizeof(vars2[0]) - }, - { - .name = "+ZZ", - .test = cmd_ok_test, - }, - { - .name = "+ZZ2", - .description = "zz2_desc", - .test = cmd_ok_test, - }, - { - .name = "+ZZ3", - .description = "zz3_desc", - .test = cmd_ok2_test, - } -}; - -static char buf[256]; -static char unsolicited_buf[256]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), - .unsolicited_buf = unsolicited_buf, - .unsolicited_buf_size = sizeof(unsolicited_buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - var_int8 = -8; - var_int16 = -16; - var_int32 = -32; - var_uint8 = 8; - var_uint8 = 16; - var_uint8 = 32; - var_hex8 = 0x08; - var_hex16 = 0x16; - var_hex32 = 0x32; - var_hex16 = 0x0123; - var_hex32 = 0xFF001234; - - var_buf[0] = 0x12; - var_buf[1] = 0x34; - var_buf[2] = 0x56; - var_buf[3] = 0x78; - - sprintf(var_string, "TST"); - - memset(ack_results, 0, sizeof(ack_results)); -} - -static const char test_case_1[] = "\nAT+SET=?\n"; -static const char test_case_1_ro[] = "\nAT+SETRO=?\n"; -static const char test_case_1_wo[] = "\nAT+SETWO=?\n"; -static const char test_case_2[] = "\nAT+TEST=?\nAT+TEST2=?\r\nAT+AP=?\n"; -static const char test_case_3[] = "\nAT+ZZ=?\nAT+ZZ2=?\nAT+ZZ3=?\r\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+SET=,,,,,,,,,,\n\nOK\n") == 0); - - prepare_input(test_case_1_ro); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+SETRO=,,,,,,,,,,\n\nOK\n") == 0); - - prepare_input(test_case_1_wo); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+SETWO=,,,,,,,,,,\n\nOK\n") == 0); - - prepare_input(test_case_2); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+TEST=\ntest_desc\ntest\n\nOK\n\r\n+TEST2=\r\ntest2_desc\r\n\r\nOK\r\n\nERROR\n") == 0); - - prepare_input(test_case_3); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\ntest1\n\nOK\n\ntest1\n\nOK\n\r\n+ZZ3=\r\nzz3_desctest2\r\n\r\nOK\r\n") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_test_only.c b/components/api/lib/cAT/tests/test_test_only.c deleted file mode 100755 index b102d6f..0000000 --- a/components/api/lib/cAT/tests/test_test_only.c +++ /dev/null @@ -1,173 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char cmd_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int ap_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(cmd_results, " test:"); - strcat(cmd_results, cmd->name); - - strcpy(data, "ap_test"); - *data_size = strlen(data); - - return 0; -} - -static int ap_run(const struct cat_command *cmd) -{ - strcat(cmd_results, " run:"); - strcat(cmd_results, cmd->name); - - return 0; -} - -static int ap_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - strcat(cmd_results, " read:"); - strcat(cmd_results, cmd->name); - - strcpy(data, "ap_read"); - *data_size = strlen(data); - - return 0; -} - -static int ap_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - strcat(cmd_results, " write:"); - strcat(cmd_results, cmd->name); - - assert(strcmp(data, "1") == 0); - - return 0; -} - -static struct cat_command cmds[] = { - { - .name = "AP1", - .test = ap_test, - .write = ap_write, - .read = ap_read, - .run = ap_run, - .only_test = true - }, - { - .name = "AP2", - .test = ap_test, - .write = ap_write, - .read = ap_read, - .run = ap_run, - .only_test = false - }, -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - memset(ack_results, 0, sizeof(ack_results)); - memset(cmd_results, 0, sizeof(cmd_results)); -} - -static const char test_case_1[] = "\nATAP1=?\n\nATAP1?\n\nATAP1=1\n\nATAP1\n"; -static const char test_case_2[] = "\nATAP2=?\n\nATAP2?\n\nATAP2=1\n\nATAP2\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nap_test\n\nOK\n\nERROR\n\nERROR\n\nERROR\n") == 0); - assert(strcmp(cmd_results, " test:AP1") == 0); - - prepare_input(test_case_2); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nap_test\n\nOK\n\nap_read\n\nOK\n\nOK\n\nOK\n") == 0); - assert(strcmp(cmd_results, " test:AP2 read:AP2 write:AP2 run:AP2") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_unsolicited_read.c b/components/api/lib/cAT/tests/test_unsolicited_read.c deleted file mode 100755 index b0d976e..0000000 --- a/components/api/lib/cAT/tests/test_unsolicited_read.c +++ /dev/null @@ -1,203 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char read_results[256]; -static char var_read_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int var_x, var_u1, var_u2; -static struct cat_object at; - -static struct cat_command u_cmds[]; - -static cat_return_state cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - cat_status s; - - strcat(read_results, " read:"); - strcat(read_results, cmd->name); - - if (strcmp(cmd->name, "+CMD") == 0) { - s = cat_trigger_unsolicited_read(&at, &u_cmds[1]); - assert(s == CAT_STATUS_OK); - } - - return CAT_RETURN_STATE_DATA_OK; -} - -static int var_read(const struct cat_variable *var) -{ - strcat(var_read_results, " var_read:"); - strcat(var_read_results, var->name); - - return 0; -} - -static struct cat_variable u_vars[] = { - { - .name = "U1", - .type = CAT_VAR_INT_DEC, - .data = &var_u1, - .data_size = sizeof(var_u1), - .read = var_read - }, - { - .name = "U2", - .type = CAT_VAR_INT_DEC, - .data = &var_u2, - .data_size = sizeof(var_u2), - .read = var_read - } -}; - -static struct cat_variable vars[] = { - { - .name = "X", - .type = CAT_VAR_INT_DEC, - .data = &var_x, - .data_size = sizeof(var_x), - .read = var_read - } -}; - -static struct cat_command cmds[] = { - { - .name = "+CMD", - .read = cmd_read, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]), - } -}; - -static struct cat_command u_cmds[] = { - { - .name = "+U1CMD", - .read = cmd_read, - .var = &u_vars[0], - .var_num = 1, - }, - { - .name = "+U2CMD", - .read = cmd_read, - .var = &u_vars[1], - .var_num = 1, - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - var_x = 1; - var_u1 = 2; - var_u2 = 3; - - memset(ack_results, 0, sizeof(ack_results)); - memset(read_results, 0, sizeof(read_results)); - memset(var_read_results, 0, sizeof(var_read_results)); -} - -static const char test_case_1[] = "\nAT+CMD?\n"; - -int main(int argc, char **argv) -{ - cat_status s; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - - s = cat_is_unsolicited_buffer_full(&at); - assert(s == CAT_STATUS_OK); - s = cat_trigger_unsolicited_event(&at, &u_cmds[0], CAT_CMD_TYPE_READ); - assert(s == CAT_STATUS_OK); - s = cat_is_unsolicited_buffer_full(&at); - assert(s == CAT_STATUS_ERROR_BUFFER_FULL); - s = cat_trigger_unsolicited_read(&at, &u_cmds[1]); - assert(s == CAT_STATUS_ERROR_BUFFER_FULL); - - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+U1CMD=2\n\n+CMD=1\n\n+U2CMD=3\n\nOK\n") == 0); - assert(strcmp(read_results, " read:+U1CMD read:+CMD read:+U2CMD") == 0); - assert(strcmp(var_read_results, " var_read:U1 var_read:X var_read:U2") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_unsolicited_read_buffer.c b/components/api/lib/cAT/tests/test_unsolicited_read_buffer.c deleted file mode 100755 index ee2377f..0000000 --- a/components/api/lib/cAT/tests/test_unsolicited_read_buffer.c +++ /dev/null @@ -1,238 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char read_results[256]; -static char var_read_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int var_x, var_u1, var_u2; -static struct cat_object at; - -static struct cat_command u_cmds[]; - -static cat_return_state cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - cat_status s; - - strcat(read_results, " read:"); - strcat(read_results, cmd->name); - - if (strcmp(cmd->name, "+CMD") == 0) { - s = cat_trigger_unsolicited_read(&at, &u_cmds[1]); - assert(s == CAT_STATUS_OK); - } - - return CAT_RETURN_STATE_DATA_OK; -} - -static int var_read(const struct cat_variable *var) -{ - strcat(var_read_results, " var_read:"); - strcat(var_read_results, var->name); - - return 0; -} - -static struct cat_variable u_vars[] = { - { - .name = "U1", - .type = CAT_VAR_INT_DEC, - .data = &var_u1, - .data_size = sizeof(var_u1), - .read = var_read - }, - { - .name = "U2", - .type = CAT_VAR_INT_DEC, - .data = &var_u2, - .data_size = sizeof(var_u2), - .read = var_read - } -}; - -static struct cat_variable vars[] = { - { - .name = "X", - .type = CAT_VAR_INT_DEC, - .data = &var_x, - .data_size = sizeof(var_x), - .read = var_read - } -}; - -static struct cat_command cmds[] = { - { - .name = "+CMD", - .read = cmd_read, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]), - } -}; - -static struct cat_command u_cmds[] = { - { - .name = "+U1CMD", - .read = cmd_read, - .var = &u_vars[0], - .var_num = 1, - }, - { - .name = "+U2CMD", - .read = cmd_read, - .var = &u_vars[1], - .var_num = 1, - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - var_x = 1; - var_u1 = 2; - var_u2 = 3; - - memset(ack_results, 0, sizeof(ack_results)); - memset(read_results, 0, sizeof(read_results)); - memset(var_read_results, 0, sizeof(var_read_results)); -} - -static const char test_case_1[] = "\nAT+CMD?\n"; - -int main(int argc, char **argv) -{ - cat_status s; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - - s = cat_is_unsolicited_buffer_full(&at); - assert(s == CAT_STATUS_OK); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_READ); - assert(s == CAT_STATUS_OK); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_NONE); - assert(s == CAT_STATUS_OK); - s = cat_trigger_unsolicited_event(&at, &u_cmds[0], CAT_CMD_TYPE_READ); - assert(s == CAT_STATUS_OK); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_READ); - assert(s == CAT_STATUS_BUSY); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_TEST); - assert(s == CAT_STATUS_OK); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_NONE); - assert(s == CAT_STATUS_BUSY); - s = cat_is_unsolicited_buffer_full(&at); - assert(s == CAT_STATUS_OK); - s = cat_trigger_unsolicited_event(&at, &u_cmds[1], CAT_CMD_TYPE_READ); - assert(s == CAT_STATUS_OK); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_READ); - assert(s == CAT_STATUS_BUSY); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_TEST); - assert(s == CAT_STATUS_OK); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_NONE); - assert(s == CAT_STATUS_BUSY); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[1], CAT_CMD_TYPE_READ); - assert(s == CAT_STATUS_BUSY); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[1], CAT_CMD_TYPE_TEST); - assert(s == CAT_STATUS_OK); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[1], CAT_CMD_TYPE_NONE); - assert(s == CAT_STATUS_BUSY); - s = cat_is_unsolicited_buffer_full(&at); - assert(s == CAT_STATUS_ERROR_BUFFER_FULL); - s = cat_trigger_unsolicited_read(&at, &u_cmds[1]); - assert(s == CAT_STATUS_ERROR_BUFFER_FULL); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_READ); - assert(s == CAT_STATUS_BUSY); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_TEST); - assert(s == CAT_STATUS_OK); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[1], CAT_CMD_TYPE_NONE); - assert(s == CAT_STATUS_BUSY); - - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+U1CMD=2\n\n+CMD=1\n\n+U2CMD=3\n\nOK\n\n+U2CMD=3\n") == 0); - assert(strcmp(read_results, " read:+U1CMD read:+CMD read:+U2CMD read:+U2CMD") == 0); - assert(strcmp(var_read_results, " var_read:U1 var_read:X var_read:U2 var_read:U2") == 0); - - s = cat_is_unsolicited_buffer_full(&at); - assert(s == CAT_STATUS_OK); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_unsolicited_read_stress.c b/components/api/lib/cAT/tests/test_unsolicited_read_stress.c deleted file mode 100755 index 19f53a9..0000000 --- a/components/api/lib/cAT/tests/test_unsolicited_read_stress.c +++ /dev/null @@ -1,211 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char read_results[256]; -static char var_read_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int var_x, var_u1; -static struct cat_object at; - -static struct cat_command u_cmds[]; - -static cat_return_state cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - cat_status s; - - strcat(read_results, " read:"); - strcat(read_results, cmd->name); - - return CAT_RETURN_STATE_DATA_OK; -} - -static int var_read(const struct cat_variable *var) -{ - strcat(var_read_results, " var_read:"); - strcat(var_read_results, var->name); - - return 0; -} - -static struct cat_variable u_vars[] = { - { - .name = "U1", - .type = CAT_VAR_INT_DEC, - .data = &var_u1, - .data_size = sizeof(var_u1), - .read = var_read - } -}; - -static struct cat_variable vars[] = { - { - .name = "X", - .type = CAT_VAR_INT_DEC, - .data = &var_x, - .data_size = sizeof(var_x), - .read = var_read - } -}; - -static struct cat_command cmds[] = { - { - .name = "+CMD", - .read = cmd_read, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]), - } -}; - -static struct cat_command u_cmds[] = { - { - .name = "+UCMD", - .read = cmd_read, - .var = u_vars, - .var_num = sizeof(u_vars) / sizeof(u_vars[0]), - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - var_x = 1; - var_u1 = 2; - - memset(ack_results, 0, sizeof(ack_results)); - memset(read_results, 0, sizeof(read_results)); - memset(var_read_results, 0, sizeof(var_read_results)); -} - -static const char test_case_1[] = "\nAT+CMD?\n"; - -int main(int argc, char **argv) -{ - cat_status s; - int events = 4; - struct cat_command const *cmd; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - - cmd = cat_get_processed_command(&at, CAT_FSM_TYPE_ATCMD); - assert(cmd == NULL); - cmd = cat_get_processed_command(&at, CAT_FSM_TYPE_UNSOLICITED); - assert(cmd == NULL); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_READ); - assert(s == CAT_STATUS_OK); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_NONE); - assert(s == CAT_STATUS_OK); - - while (events > 0) { - s = cat_is_unsolicited_buffer_full(&at); - cmd = cat_get_processed_command(&at, CAT_FSM_TYPE_UNSOLICITED); - if ((s == CAT_STATUS_OK) && (cmd == NULL)) { - var_u1 = events; - s = cat_trigger_unsolicited_event(&at, &u_cmds[0], CAT_CMD_TYPE_READ); - assert(s == CAT_STATUS_OK); - events--; - } else { - assert(cmd == &u_cmds[0]); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_READ); - assert(s == CAT_STATUS_BUSY); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_TEST); - assert(s == CAT_STATUS_OK); - s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_NONE); - assert(s == CAT_STATUS_BUSY); - } - s = cat_service(&at); - assert(s == CAT_STATUS_BUSY); - } - - while (cat_service(&at) != 0) {}; - cmd = cat_get_processed_command(&at, CAT_FSM_TYPE_ATCMD); - assert(cmd == NULL); - cmd = cat_get_processed_command(&at, CAT_FSM_TYPE_UNSOLICITED); - assert(cmd == NULL); - - assert(strcmp(ack_results, "\n+UCMD=4\n\n+CMD=1\n\n+UCMD=3\n\nOK\n\n+UCMD=2\n\n+UCMD=1\n") == 0); - assert(strcmp(read_results, " read:+UCMD read:+CMD read:+UCMD read:+UCMD read:+UCMD") == 0); - assert(strcmp(var_read_results, " var_read:U1 var_read:X var_read:U1 var_read:U1 var_read:U1") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_unsolicited_test.c b/components/api/lib/cAT/tests/test_unsolicited_test.c deleted file mode 100755 index 7e7c475..0000000 --- a/components/api/lib/cAT/tests/test_unsolicited_test.c +++ /dev/null @@ -1,189 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char read_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int var_x, var_u1, var_u2; -static struct cat_object at; - -static struct cat_command u_cmds[]; - -static cat_return_state cmd_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - cat_status s; - - strcat(read_results, " test:"); - strcat(read_results, cmd->name); - - if (strcmp(cmd->name, "+CMD") == 0) { - s = cat_trigger_unsolicited_test(&at, &u_cmds[1]); - assert(s == CAT_STATUS_OK); - } - - return CAT_RETURN_STATE_DATA_OK; -} - -static struct cat_variable u_vars[] = { - { - .name = "U1", - .type = CAT_VAR_INT_DEC, - .data = &var_u1, - .data_size = sizeof(var_u1) - }, - { - .name = "U2", - .type = CAT_VAR_INT_DEC, - .data = &var_u2, - .data_size = sizeof(var_u2) - } -}; - -static struct cat_variable vars[] = { - { - .name = "X", - .type = CAT_VAR_INT_DEC, - .data = &var_x, - .data_size = sizeof(var_x) - } -}; - -static struct cat_command cmds[] = { - { - .name = "+CMD", - .test = cmd_test, - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]), - } -}; - -static struct cat_command u_cmds[] = { - { - .name = "+U1CMD", - .test = cmd_test, - .var = &u_vars[0], - .var_num = 1, - }, - { - .name = "+U2CMD", - .test = cmd_test, - .var = &u_vars[1], - .var_num = 1, - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - var_x = 1; - var_u1 = 2; - var_u2 = 3; - - memset(ack_results, 0, sizeof(ack_results)); - memset(read_results, 0, sizeof(read_results)); -} - -static const char test_case_1[] = "\nAT+CMD=?\n"; - -int main(int argc, char **argv) -{ - cat_status s; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - - s = cat_is_unsolicited_buffer_full(&at); - assert(s == CAT_STATUS_OK); - s = cat_trigger_unsolicited_event(&at, &u_cmds[0], CAT_CMD_TYPE_TEST); - assert(s == CAT_STATUS_OK); - s = cat_is_unsolicited_buffer_full(&at); - assert(s == CAT_STATUS_ERROR_BUFFER_FULL); - s = cat_trigger_unsolicited_test(&at, &u_cmds[1]); - assert(s == CAT_STATUS_ERROR_BUFFER_FULL); - - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+U1CMD=\n\n+CMD=\n\n+U2CMD=\n\nOK\n") == 0); - assert(strcmp(read_results, " test:+U1CMD test:+CMD test:+U2CMD") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_var_access.c b/components/api/lib/cAT/tests/test_var_access.c deleted file mode 100755 index 2d062de..0000000 --- a/components/api/lib/cAT/tests/test_var_access.c +++ /dev/null @@ -1,545 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char ack_results[256]; - -static int8_t var1; -static int8_t var2; -static int8_t var3; - -static char const *input_text; -static size_t input_index; - -static int var2_write_cntr; -static int var3_read_cntr; - -static int8_t var_int8; -static int16_t var_int16; -static int32_t var_int32; -static uint8_t var_uint8; -static uint16_t var_uint16; -static uint32_t var_uint32; -static uint8_t var_hex8; -static uint16_t var_hex16; -static uint32_t var_hex32; -static uint8_t var_buf[4]; -static char var_string[16]; - -static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - return 0; -} - -static int cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - return 0; -} - -static int cmd_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size) -{ - return 0; -} - -static int cmd_run(const struct cat_command *cmd) -{ - return 0; -} - -static int var1_write(const struct cat_variable *var, size_t write_size) -{ - return 0; -} - -static int var1_read(const struct cat_variable *var) -{ - return 0; -} - -static int var2_write(const struct cat_variable *var, size_t write_size) -{ - var2_write_cntr++; - return 0; -} - -static int var2_read(const struct cat_variable *var) -{ - return 0; -} - -static int var3_write(const struct cat_variable *var, size_t write_size) -{ - return 0; -} - -static int var3_read(const struct cat_variable *var) -{ - var3_read_cntr++; - return 0; -} - -static int print_cmd_list(const struct cat_command *cmd) -{ - return CAT_RETURN_STATE_PRINT_CMD_LIST_OK; -} - -static struct cat_variable vars_ro[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var2, - .data_size = sizeof(var2), - .write = var2_write, - .read = var2_read, - .access = CAT_VAR_ACCESS_READ_ONLY - } -}; - -static struct cat_variable vars_wo[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var3, - .data_size = sizeof(var3), - .write = var3_write, - .read = var3_read, - .access = CAT_VAR_ACCESS_WRITE_ONLY - } -}; - -static struct cat_variable vars[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var1, - .data_size = sizeof(var1), - .write = var1_write, - .read = var1_read, - .access = CAT_VAR_ACCESS_READ_WRITE - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var2, - .data_size = sizeof(var2), - .write = var2_write, - .read = var2_read, - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var3, - .data_size = sizeof(var3), - .write = var3_write, - .read = var3_read, - .access = CAT_VAR_ACCESS_WRITE_ONLY - } -}; - -static struct cat_variable vars_misc_ro[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var1, - .data_size = sizeof(var1), - .access = CAT_VAR_ACCESS_READ_WRITE - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var_int8, - .data_size = sizeof(var_int8), - .name = "x", - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var_int16, - .data_size = sizeof(var_int16), - .name = "y", - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var_int32, - .data_size = sizeof(var_int32), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint8, - .data_size = sizeof(var_uint8), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint16, - .data_size = sizeof(var_uint16), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint32, - .data_size = sizeof(var_uint32), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex8, - .data_size = sizeof(var_hex8), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex16, - .data_size = sizeof(var_hex16), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex32, - .data_size = sizeof(var_hex32), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_BUF_HEX, - .data = &var_buf, - .data_size = sizeof(var_buf), - .access = CAT_VAR_ACCESS_READ_ONLY - }, - { - .type = CAT_VAR_BUF_STRING, - .data = &var_string, - .data_size = sizeof(var_string), - .name = "msg", - .access = CAT_VAR_ACCESS_READ_ONLY - } -}; - -static struct cat_variable vars_misc_wo[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var1, - .data_size = sizeof(var1), - .access = CAT_VAR_ACCESS_READ_WRITE - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var_int8, - .data_size = sizeof(var_int8), - .name = "x", - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var_int16, - .data_size = sizeof(var_int16), - .name = "y", - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var_int32, - .data_size = sizeof(var_int32), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint8, - .data_size = sizeof(var_uint8), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint16, - .data_size = sizeof(var_uint16), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var_uint32, - .data_size = sizeof(var_uint32), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex8, - .data_size = sizeof(var_hex8), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex16, - .data_size = sizeof(var_hex16), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var_hex32, - .data_size = sizeof(var_hex32), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_BUF_HEX, - .data = &var_buf, - .data_size = sizeof(var_buf), - .access = CAT_VAR_ACCESS_WRITE_ONLY - }, - { - .type = CAT_VAR_BUF_STRING, - .data = &var_string, - .data_size = sizeof(var_string), - .name = "msg", - .access = CAT_VAR_ACCESS_WRITE_ONLY - } -}; - -static struct cat_command cmds[] = { - { - .name = "+VRW", - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - }, - { - .name = "+VRO", - .var = vars_ro, - .var_num = sizeof(vars_ro) / sizeof(vars_ro[0]) - }, - { - .name = "+VWO", - .var = vars_wo, - .var_num = sizeof(vars_wo) / sizeof(vars_wo[0]) - }, - { - .name = "+MRO", - .var = vars_misc_ro, - .var_num = sizeof(vars_misc_ro) / sizeof(vars_misc_ro[0]) - }, - { - .name = "+MWO", - .var = vars_misc_wo, - .var_num = sizeof(vars_misc_wo) / sizeof(vars_misc_wo[0]) - }, - { - .name = "#HELP", - .run = print_cmd_list, - } -}; - -static char buf[256]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - memset(ack_results, 0, sizeof(ack_results)); -} - -static void print_raw_text(char *p) -{ - while (*p != '\0') { - if (*p == '\n') { - printf("\\n"); - } else { - putchar(*p); - } - p++; - } -} - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input("\nAT#HELP\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nAT+VRW?\nAT+VRW=\nAT+VRW=?\n\nAT+VRO?\nAT+VRO=?\n\nAT+VWO=\nAT+VWO=?\n\nAT+MRO?\nAT+MRO=\nAT+MRO=?\n\nAT+MWO?\nAT+MWO=\nAT+MWO=?\n\nAT#HELP\n\nOK\n") == 0); - - prepare_input("\nAT+VRW=?\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+VRW=,,\n\nOK\n") == 0); - - prepare_input("\nAT+VRO=?\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+VRO=\n\nOK\n") == 0); - - prepare_input("\nAT+VWO=?\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+VWO=\n\nOK\n") == 0); - - var2 = 1; - prepare_input("\nAT+VRO=1\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n") == 0); - assert(var2 == 1); - - var3 = 3; - prepare_input("\nAT+VWO?\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n") == 0); - assert(var3 == 3); - - var1 = -1; - var2 = -2; - var3 = -3; - var2_write_cntr = 0; - var3_read_cntr = 0; - - prepare_input("\nAT+VRW?\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+VRW=-1,-2,0\n\nOK\n") == 0); - assert(var2_write_cntr == 0); - assert(var3_read_cntr == 1); - - prepare_input("\nAT+VRW=1,2,3\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(var2_write_cntr == 1); - assert(var3_read_cntr == 1); - assert(var1 == 1); - assert(var2 == -2); - assert(var3 == 3); - - var1 = 100; - var_int8 = 1; - var_int16 = 2; - var_int32 = 3; - var_uint8 = 4; - var_uint16 = 5; - var_uint32 = 6; - var_hex8 = 7; - var_hex16 = 8; - var_hex32 = 9; - var_buf[0] = 0x10; - var_buf[1] = 0x11; - var_buf[2] = 0x12; - var_buf[3] = 0x13; - strcpy(var_string, "test_string"); - - prepare_input("\nAT+MWO?\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+MWO=100,0,0,0,0,0,0,0x00,0x0000,0x00000000,00000000,\"\"\n\nOK\n") == 0); - - prepare_input("\nAT+MWO=1,2,3,4,5,6,7,0x08,0x0009,0x0000000A,01020304,\"abc\"\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(var1 == 1); - assert(var_int8 == 2); - assert(var_int16 == 3); - assert(var_int32 == 4); - assert(var_uint8 == 5); - assert(var_uint16 == 6); - assert(var_uint32 == 7); - assert(var_hex8 == 8); - assert(var_hex16 == 9); - assert(var_hex32 == 10); - assert(var_buf[0] == 0x01); - assert(var_buf[1] == 0x02); - assert(var_buf[2] == 0x03); - assert(var_buf[3] == 0x04); - assert(strcmp(var_string, "abc") == 0); - - prepare_input("\nAT+MRO?\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\n+MRO=1,2,3,4,5,6,7,0x08,0x0009,0x0000000A,01020304,\"abc\"\n\nOK\n") == 0); - - prepare_input("\nAT+MRO=2,0,0,0,0,0,0,0x00,0x0000,0x00000000,00000000,\"cba\"\n"); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n") == 0); - assert(var1 == 2); - assert(var_int8 == 2); - assert(var_int16 == 3); - assert(var_int32 == 4); - assert(var_uint8 == 5); - assert(var_uint16 == 6); - assert(var_uint32 == 7); - assert(var_hex8 == 8); - assert(var_hex16 == 9); - assert(var_hex32 == 10); - assert(var_buf[0] == 0x01); - assert(var_buf[1] == 0x02); - assert(var_buf[2] == 0x03); - assert(var_buf[3] == 0x04); - assert(strcmp(var_string, "abc") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_write.c b/components/api/lib/cAT/tests/test_write.c deleted file mode 100755 index 2388b44..0000000 --- a/components/api/lib/cAT/tests/test_write.c +++ /dev/null @@ -1,166 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char run_results[256]; -static char write_results[256]; -static char ack_results[256]; - -static char const *input_text; -static size_t input_index; - -static int a_run(const struct cat_command *cmd) -{ - strcat(run_results, " A_"); - strcat(run_results, cmd->name); - return 0; -} - -static int a_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - strcat(write_results, " A:"); - strncat(write_results, data, data_size); - - assert(args_num == 0); - - return 0; -} - -static int ap_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - strcat(write_results, " AP:"); - strncat(write_results, data, data_size); - - assert(args_num == 0); - - return 0; -} - -static int test_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - strcat(write_results, " +TEST:"); - strncat(write_results, data, data_size); - - assert(args_num == 0); - - return -1; -} - -static struct cat_command cmds[] = { - { - .name = "A", - .write = a_write, - .run = a_run - }, - { - .name = "AP", - .write = ap_write - }, - { - .name = "+TEST", - .write = test_write - }, - { - .name = "+EMPTY" - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - memset(run_results, 0, sizeof(run_results)); - memset(ack_results, 0, sizeof(ack_results)); - memset(write_results, 0, sizeof(write_results)); -} - -static const char test_case_1[] = "\nAT\nAT+\nAT+?\nATA=123\r\nATA=\nATAP?\nATAP=11\r22\r\nAT+TEST=456\nAT+te=789\nAT+e=1\nAT+empTY=2\r\nATA\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n\nERROR\n\nERROR\n\r\nOK\r\n\nOK\n\nERROR\n\r\nOK\r\n\nERROR\n\nERROR\n\nERROR\n\r\nERROR\r\n\nOK\n") == 0); - assert(strcmp(run_results, " A_A") == 0); - assert(strcmp(write_results, " A:123 A: AP:1122 +TEST:456 +TEST:789") == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_write_hex_buffer.c b/components/api/lib/cAT/tests/test_write_hex_buffer.c deleted file mode 100755 index 68ab94e..0000000 --- a/components/api/lib/cAT/tests/test_write_hex_buffer.c +++ /dev/null @@ -1,174 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char write_results[256]; -static char ack_results[256]; - -static uint8_t var[4]; -static size_t var_write_size[4]; -static int var_write_size_index; - -static char const *input_text; -static size_t input_index; - -static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - strcat(write_results, " CMD:"); - strncat(write_results, data, data_size); - return 0; -} - -static int var_write(const struct cat_variable *var, size_t write_size) -{ - var_write_size[var_write_size_index++] = write_size; - return 0; -} - -static struct cat_variable vars[] = { - { - .type = CAT_VAR_BUF_HEX, - .data = var, - .data_size = sizeof(var), - .write = var_write - } -}; - -static struct cat_command cmds[] = { - { - .name = "+SET", - .write = cmd_write, - - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - memset(var, 0, sizeof(var)); - memset(var_write_size, 0, sizeof(var_write_size)); - var_write_size_index = 0; - - memset(ack_results, 0, sizeof(ack_results)); - memset(write_results, 0, sizeof(write_results)); -} - -static const char test_case_1[] = "\nAT+SET=0\nAT+SET=aa\nAT+SET=001\nAT+SET=12345678\nAT+SET=ffAA\n"; -static const char test_case_2[] = "\nAT+SET=0x11\nAT+SET=11\nAT+SET=-1\nAT+SET=87654321\nAT+SET=0001\nAT+SET=1122334455\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n\nOK\n\nERROR\n\nOK\n\nOK\n") == 0); - assert(strcmp(write_results, " CMD:aa CMD:12345678 CMD:ffAA") == 0); - - assert(var[0] == 0xFF); - assert(var[1] == 0xAA); - assert(var[2] == 0x56); - assert(var[3] == 0x78); - - assert(var_write_size[0] == 1); - assert(var_write_size[1] == 4); - assert(var_write_size[2] == 2); - assert(var_write_size[3] == 0); - - prepare_input(test_case_2); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n\nOK\n\nERROR\n\nOK\n\nOK\n\nERROR\n") == 0); - assert(strcmp(write_results, " CMD:11 CMD:87654321 CMD:0001") == 0); - - assert(var[0] == 0x11); - assert(var[1] == 0x22); - assert(var[2] == 0x33); - assert(var[3] == 0x44); - - assert(var_write_size[0] == 1); - assert(var_write_size[1] == 4); - assert(var_write_size[2] == 2); - assert(var_write_size[3] == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_write_hex_range.c b/components/api/lib/cAT/tests/test_write_hex_range.c deleted file mode 100755 index da40feb..0000000 --- a/components/api/lib/cAT/tests/test_write_hex_range.c +++ /dev/null @@ -1,212 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char write_results[256]; -static char ack_results[256]; - -static uint8_t var1, var1b; -static uint16_t var2, var2b; -static uint32_t var3, var3b; - -static char const *input_text; -static size_t input_index; - -static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - strcat(write_results, " CMD:"); - strncat(write_results, data, data_size); - return 0; -} - -static int var1_write(const struct cat_variable *var, size_t write_size) -{ - assert(write_size == 1); - var1b = *(uint8_t*)(var->data); - return 0; -} - -static int var2_write(const struct cat_variable *var, size_t write_size) -{ - assert(write_size == 2); - var2b = *(uint16_t*)(var->data); - return 0; -} - -static int var3_write(const struct cat_variable *var, size_t write_size) -{ - assert(write_size == 4); - var3b = *(uint32_t*)(var->data); - return 0; -} - -static struct cat_variable vars[] = { - { - .type = CAT_VAR_NUM_HEX, - .data = &var1, - .data_size = sizeof(var1), - .write = var1_write - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var2, - .data_size = sizeof(var2), - .write = var2_write - }, - { - .type = CAT_VAR_NUM_HEX, - .data = &var3, - .data_size = sizeof(var3), - .write = var3_write - } -}; - -static struct cat_command cmds[] = { - { - .name = "+SET", - .write = cmd_write, - - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - var1 = 1; - var2 = 2; - var3 = 3; - var1b = 10; - var2b = 20; - var3b = 30; - - memset(ack_results, 0, sizeof(ack_results)); - memset(write_results, 0, sizeof(write_results)); -} - -static const char test_case_1[] = "\nAT+SET=0\nAT+SET=0x0\nAT+SET=0x01\nAT+SET=0x0ff\nAT+SET=0x100\n"; -static const char test_case_2[] = "\nAT+SET=0x,0x00\nAT+SET=0x1,0x00\nAT+SET=0x2,0xFFf\nAT+SET=0x3,0xFFFF\nAT+SET=0x4,0xFFFFF\n"; -static const char test_case_3[] = "\nAT+SET=0x0,0x0,0\nAT+SET=0x0,0x0,0x0000000000000\nAT+SET=0x0,0x0,0x1\nAT+SET=0x0,0x0,0xffffFFFF\nAT+SET=0x10,0x20,0x100000000\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nOK\n\nERROR\n") == 0); - assert(strcmp(write_results, " CMD:0x0 CMD:0x01 CMD:0x0ff") == 0); - - assert(var1 == 255); - assert(var1b == var1); - assert(var2 == 2); - assert(var2b == 20); - assert(var3 == 3); - assert(var3b == 30); - - prepare_input(test_case_2); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nOK\n\nERROR\n") == 0); - assert(strcmp(write_results, " CMD:0x1,0x00 CMD:0x2,0xFFf CMD:0x3,0xFFFF") == 0); - - assert(var1 == 4); - assert(var1b == var1); - assert(var2 == 0xFFFF); - assert(var2b == var2); - assert(var3 == 3); - assert(var3b == 30); - - prepare_input(test_case_3); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nOK\n\nERROR\n") == 0); - assert(strcmp(write_results, " CMD:0x0,0x0,0x0000000000000 CMD:0x0,0x0,0x1 CMD:0x0,0x0,0xffffFFFF") == 0); - - assert(var1 == 0x10); - assert(var1b == var1); - assert(var2 == 0x20); - assert(var2b == var2); - assert(var3 == 0xFFFFFFFF); - assert(var3b == var3); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_write_int_range.c b/components/api/lib/cAT/tests/test_write_int_range.c deleted file mode 100755 index 6f99fee..0000000 --- a/components/api/lib/cAT/tests/test_write_int_range.c +++ /dev/null @@ -1,212 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char write_results[256]; -static char ack_results[256]; - -static int8_t var1, var1b; -static int16_t var2, var2b; -static int32_t var3, var3b; - -static char const *input_text; -static size_t input_index; - -static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - strcat(write_results, " CMD:"); - strncat(write_results, data, data_size); - return 0; -} - -static int var1_write(const struct cat_variable *var, size_t write_size) -{ - assert(write_size == 1); - var1b = *(int8_t*)(var->data); - return 0; -} - -static int var2_write(const struct cat_variable *var, size_t write_size) -{ - assert(write_size == 2); - var2b = *(int16_t*)(var->data); - return 0; -} - -static int var3_write(const struct cat_variable *var, size_t write_size) -{ - assert(write_size == 4); - var3b = *(int32_t*)(var->data); - return 0; -} - -static struct cat_variable vars[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var1, - .data_size = sizeof(var1), - .write = var1_write - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var2, - .data_size = sizeof(var2), - .write = var2_write - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var3, - .data_size = sizeof(var3), - .write = var3_write - } -}; - -static struct cat_command cmds[] = { - { - .name = "+SET", - .write = cmd_write, - - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf), -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - var1 = 1; - var2 = 2; - var3 = 3; - var1b = -1; - var2b = -2; - var3b = -3; - - memset(ack_results, 0, sizeof(ack_results)); - memset(write_results, 0, sizeof(write_results)); -} - -static const char test_case_1[] = "\nAT+SET=-128\nAT+SET=-129\nAT+SET=127\nAT+SET=128\n"; -static const char test_case_2[] = "\nAT+SET=-128,-32768\nAT+SET=-128,-40000\nAT+SET=-128,32767\nAT+SET=-100,40000\n"; -static const char test_case_3[] = "\nAT+SET=0,0,-2147483648\nAT+SET=0,0,-2147483649\nAT+SET=1,1,2147483647\nAT+SET=2,2,2147483648\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n\nERROR\n\nOK\n\nERROR\n") == 0); - assert(strcmp(write_results, " CMD:-128 CMD:127") == 0); - - assert(var1 == 127); - assert(var1b == var1); - assert(var2 == 2); - assert(var2b == -2); - assert(var3 == 3); - assert(var3b == -3); - - prepare_input(test_case_2); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n\nERROR\n\nOK\n\nERROR\n") == 0); - assert(strcmp(write_results, " CMD:-128,-32768 CMD:-128,32767") == 0); - - assert(var1 == -100); - assert(var1b == var1); - assert(var2 == 32767); - assert(var2b == var2); - assert(var3 == 3); - assert(var3b == -3); - - prepare_input(test_case_3); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n\nERROR\n\nOK\n\nERROR\n") == 0); - assert(strcmp(write_results, " CMD:0,0,-2147483648 CMD:1,1,2147483647") == 0); - - assert(var1 == 2); - assert(var1b == var1); - assert(var2 == 2); - assert(var2b == var2); - assert(var3 == 2147483647); - assert(var3b == var3); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_write_parse.c b/components/api/lib/cAT/tests/test_write_parse.c deleted file mode 100755 index 3d6eda6..0000000 --- a/components/api/lib/cAT/tests/test_write_parse.c +++ /dev/null @@ -1,234 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char write_results[256]; -static char ack_results[256]; - -static int8_t var1, var2, var3; -static int8_t var1b, var2b, var3b; - -static char const *input_text; -static size_t input_index; - -static int cmd_write1(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - char tmp[32]; - sprintf(tmp, " CMD1_%ld:", args_num); - strcat(write_results, tmp); - strncat(write_results, data, data_size); - return 0; -} - -static int cmd_write3(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - char tmp[32]; - sprintf(tmp, " CMD3_%ld:", args_num); - strcat(write_results, tmp); - strncat(write_results, data, data_size); - return 0; -} - -static int var1_write(const struct cat_variable *var, size_t write_size) -{ - assert(write_size == 1); - var1b = *(int8_t*)(var->data); - return 0; -} - -static int var2_write(const struct cat_variable *var, size_t write_size) -{ - assert(write_size == 1); - var2b = *(int8_t*)(var->data); - return 0; -} - -static int var3_write(const struct cat_variable *var, size_t write_size) -{ - assert(write_size == 1); - var3b = *(int8_t*)(var->data); - return 0; -} - -static struct cat_variable vars[] = { - { - .type = CAT_VAR_INT_DEC, - .data = &var1, - .data_size = sizeof(var1), - .write = var1_write - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var2, - .data_size = sizeof(var2), - .write = var2_write - }, - { - .type = CAT_VAR_INT_DEC, - .data = &var3, - .data_size = sizeof(var3), - .write = var3_write - } -}; - -static struct cat_command cmds[] = { - { - .name = "+SET1", - .write = cmd_write1, - - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - }, - { - .name = "+SET3", - .write = cmd_write3, - - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - }, - { - .name = "+SETALL", - .write = cmd_write3, - - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]), - .need_all_vars = true - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - var1 = 1; - var2 = 2; - var3 = 3; - - memset(ack_results, 0, sizeof(ack_results)); - memset(write_results, 0, sizeof(write_results)); -} - -static const char test_case_1[] = "\nAT+SET=-10,-20,-30\r\nAT+SET1=-10,-20,-30\r\nAT+SET1=-1\r\n"; -static const char test_case_2[] = "\nAT+SET3=-1,-2,-3,0\nAT+SET3=-1,-2,-3\nAT+SET3=-100\n"; -static const char test_case_3[] = "\nAT+SETALL=-11,-22,-33\nAT+SETALL=-1,-2,-3\nAT+SETALL=100\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\r\nERROR\r\n\r\nOK\r\n\r\nOK\r\n") == 0); - assert(strcmp(write_results, " CMD1_3:-10,-20,-30 CMD1_1:-1") == 0); - - assert(var1 == -1); - assert(var2 == -20); - assert(var3 == -30); - assert(var1b == -1); - assert(var2b == -20); - assert(var3b == -30); - - prepare_input(test_case_2); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n") == 0); - assert(strcmp(write_results, " CMD3_3:-1,-2,-3 CMD3_1:-100") == 0); - - assert(var1 == -100); - assert(var2 == -2); - assert(var3 == -3); - assert(var1b == -100); - assert(var2b == -2); - assert(var3b == -3); - - prepare_input(test_case_3); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nOK\n\nOK\n\nERROR\n") == 0); - assert(strcmp(write_results, " CMD3_3:-11,-22,-33 CMD3_3:-1,-2,-3") == 0); - - assert(var1 == 100); - assert(var2 == -2); - assert(var3 == -3); - assert(var1b == 100); - assert(var2b == -2); - assert(var3b == -3); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_write_string_buffer.c b/components/api/lib/cAT/tests/test_write_string_buffer.c deleted file mode 100755 index e247655..0000000 --- a/components/api/lib/cAT/tests/test_write_string_buffer.c +++ /dev/null @@ -1,168 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char write_results[256]; -static char ack_results[256]; - -static uint8_t var[8]; -static size_t var_write_size[4]; -static int var_write_size_index; - -static char const *input_text; -static size_t input_index; - -static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - strcat(write_results, " CMD:"); - strncat(write_results, data, data_size); - return 0; -} - -static int var_write(const struct cat_variable *var, size_t write_size) -{ - var_write_size[var_write_size_index++] = write_size; - return 0; -} - -static struct cat_variable vars[] = { - { - .type = CAT_VAR_BUF_STRING, - .data = var, - .data_size = sizeof(var), - .write = var_write - } -}; - -static struct cat_command cmds[] = { - { - .name = "+SET", - .write = cmd_write, - - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - memset(var, 0, sizeof(var)); - memset(var_write_size, 0, sizeof(var_write_size)); - var_write_size_index = 0; - - memset(ack_results, 0, sizeof(ack_results)); - memset(write_results, 0, sizeof(write_results)); -} - -static const char test_case_1[] = "\nAT+SET=0\nAT+SET=\"\\\"abcd\\\"\"\nAT+SET=\"\"a\nAT+SET=\"1122334\"\nAT+SET=\"t\"\r\n"; -static const char test_case_2[] = "\nAT+SET=\"12345678\"\nAT+SET=\"\"\nAT+SET=\"\\\\\\\\\"\nAT+SET=\"r1\\nr2\\n\"\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n\nOK\n\nERROR\n\nOK\n\r\nOK\r\n") == 0); - assert(strcmp(write_results, " CMD:\"\\\"abcd\\\"\" CMD:\"1122334\" CMD:\"t\"") == 0); - - assert(strcmp(var, "t") == 0); - - assert(var_write_size[0] == 6); - assert(var_write_size[1] == 7); - assert(var_write_size[2] == 1); - assert(var_write_size[3] == 0); - - prepare_input(test_case_2); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nOK\n") == 0); - assert(strcmp(write_results, " CMD:\"\" CMD:\"\\\\\\\\\" CMD:\"r1\\nr2\\n\"") == 0); - - assert(strcmp(var, "r1\nr2\n") == 0); - - assert(var_write_size[0] == 0); - assert(var_write_size[1] == 2); - assert(var_write_size[2] == 6); - assert(var_write_size[3] == 0); - - return 0; -} diff --git a/components/api/lib/cAT/tests/test_write_uint_range.c b/components/api/lib/cAT/tests/test_write_uint_range.c deleted file mode 100755 index 6e080ea..0000000 --- a/components/api/lib/cAT/tests/test_write_uint_range.c +++ /dev/null @@ -1,212 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Marcin Borowicz - -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. -*/ - -#include -#include -#include -#include - -#include - -#include "../src/cat.h" - -static char write_results[256]; -static char ack_results[256]; - -static uint8_t var1, var1b; -static uint16_t var2, var2b; -static uint32_t var3, var3b; - -static char const *input_text; -static size_t input_index; - -static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num) -{ - strcat(write_results, " CMD:"); - strncat(write_results, data, data_size); - return 0; -} - -static int var1_write(const struct cat_variable *var, size_t write_size) -{ - assert(write_size == 1); - var1b = *(uint8_t*)(var->data); - return 0; -} - -static int var2_write(const struct cat_variable *var, size_t write_size) -{ - assert(write_size == 2); - var2b = *(uint16_t*)(var->data); - return 0; -} - -static int var3_write(const struct cat_variable *var, size_t write_size) -{ - assert(write_size == 4); - var3b = *(uint32_t*)(var->data); - return 0; -} - -static struct cat_variable vars[] = { - { - .type = CAT_VAR_UINT_DEC, - .data = &var1, - .data_size = sizeof(var1), - .write = var1_write - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var2, - .data_size = sizeof(var2), - .write = var2_write - }, - { - .type = CAT_VAR_UINT_DEC, - .data = &var3, - .data_size = sizeof(var3), - .write = var3_write - } -}; - -static struct cat_command cmds[] = { - { - .name = "+SET", - .write = cmd_write, - - .var = vars, - .var_num = sizeof(vars) / sizeof(vars[0]) - } -}; - -static char buf[128]; - -static struct cat_command_group cmd_group = { - .cmd = cmds, - .cmd_num = sizeof(cmds) / sizeof(cmds[0]), -}; - -static struct cat_command_group *cmd_desc[] = { - &cmd_group -}; - -static struct cat_descriptor desc = { - .cmd_group = cmd_desc, - .cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]), - - .buf = buf, - .buf_size = sizeof(buf) -}; - -static int write_char(char ch) -{ - char str[2]; - str[0] = ch; - str[1] = 0; - strcat(ack_results, str); - return 1; -} - -static int read_char(char *ch) -{ - if (input_index >= strlen(input_text)) - return 0; - - *ch = input_text[input_index]; - input_index++; - return 1; -} - -static struct cat_io_interface iface = { - .read = read_char, - .write = write_char -}; - -static void prepare_input(const char *text) -{ - input_text = text; - input_index = 0; - - var1 = 1; - var2 = 2; - var3 = 3; - var1b = 10; - var2b = 20; - var3b = 30; - - memset(ack_results, 0, sizeof(ack_results)); - memset(write_results, 0, sizeof(write_results)); -} - -static const char test_case_1[] = "\nAT+SET=-128\nAT+SET=0\nAT+SET=255\nAT+SET=256\n"; -static const char test_case_2[] = "\nAT+SET=0,-1\nAT+SET=0,0\nAT+SET=0,65535\nAT+SET=1,65536\n"; -static const char test_case_3[] = "\nAT+SET=0,0,-1\nAT+SET=0,0,0\nAT+SET=1,1,4294967295\nAT+SET=2,2,4294967296\n"; - -int main(int argc, char **argv) -{ - struct cat_object at; - - cat_init(&at, &desc, &iface, NULL); - - prepare_input(test_case_1); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nERROR\n") == 0); - assert(strcmp(write_results, " CMD:0 CMD:255") == 0); - - assert(var1 == 255); - assert(var1b == var1); - assert(var2 == 2); - assert(var2b == 20); - assert(var3 == 3); - assert(var3b == 30); - - prepare_input(test_case_2); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nERROR\n") == 0); - assert(strcmp(write_results, " CMD:0,0 CMD:0,65535") == 0); - - assert(var1 == 1); - assert(var1b == var1); - assert(var2 == 65535); - assert(var2b == var2); - assert(var3 == 3); - assert(var3b == 30); - - prepare_input(test_case_3); - while (cat_service(&at) != 0) {}; - - assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nERROR\n") == 0); - assert(strcmp(write_results, " CMD:0,0,0 CMD:1,1,4294967295") == 0); - - assert(var1 == 2); - assert(var1b == var1); - assert(var2 == 2); - assert(var2b == var2); - assert(var3 == 4294967295); - assert(var3b == var3); - - return 0; -} diff --git a/components/api/src/api.c b/components/api/src/api.c deleted file mode 100755 index 138ba1e..0000000 --- a/components/api/src/api.c +++ /dev/null @@ -1,6 +0,0 @@ -#include "api.h" - -void api_init(void) -{ - //modbus_init(); -} \ No newline at end of file diff --git a/components/api/src/json.c b/components/api/src/json.c deleted file mode 100755 index 13f257c..0000000 --- a/components/api/src/json.c +++ /dev/null @@ -1,575 +0,0 @@ -#include -#include "sdkconfig.h" -#include "freertos/FreeRTOS.h" -#include "esp_wifi.h" -#include "esp_ota_ops.h" -#include "esp_timer.h" -#include "esp_chip_info.h" -#include "esp_mac.h" - -#include "json.h" -#include "mqtt.h" -#include "network.h" -#include "timeout_utils.h" -#include "evse_error.h" -#include "evse_api.h" -#include "auth.h" -#include "evse_limits.h" -#include "evse_state.h" -#include "evse_config.h" -#include "ocpp.h" -#include "board_config.h" -#include "socket_lock.h" -#include "proximity.h" -//#include "modbus.h" -//#include "modbus_tcp.h" -//#include "rest.h" -#include "temp_sensor.h" -// #include "script.h" -#include "date_time.h" -#include "evse_meter.h" - - -#define RETURN_ON_ERROR(x) \ - do \ - { \ - esp_err_t err_rc_ = (x); \ - if (unlikely(err_rc_ != ESP_OK)) \ - { \ - return err_rc_; \ - } \ - } while (0) - -cJSON *json_get_evse_config(void) -{ - cJSON *root = cJSON_CreateObject(); - - cJSON_AddNumberToObject(root, "maxChargingCurrent", evse_get_max_charging_current()); - cJSON_AddNumberToObject(root, "chargingCurrent", evse_get_charging_current()); - cJSON_AddNumberToObject(root, "defaultChargingCurrent", evse_get_default_charging_current()); - cJSON_AddBoolToObject(root, "requireAuth", auth_get_mode()); - cJSON_AddBoolToObject(root, "socketOutlet", evse_get_socket_outlet()); - cJSON_AddBoolToObject(root, "rcm", evse_is_rcm()); - cJSON_AddNumberToObject(root, "temperatureThreshold", evse_get_temp_threshold()); - cJSON_AddNumberToObject(root, "consumptionLimit", evse_get_consumption_limit()); - cJSON_AddNumberToObject(root, "defaultConsumptionLimit", evse_get_default_consumption_limit()); - cJSON_AddNumberToObject(root, "chargingTimeLimit", evse_get_charging_time_limit()); - cJSON_AddNumberToObject(root, "defaultChargingTimeLimit", evse_get_default_charging_time_limit()); - cJSON_AddNumberToObject(root, "underPowerLimit", evse_get_under_power_limit()); - cJSON_AddNumberToObject(root, "defaultUnderPowerLimit", evse_get_default_under_power_limit()); - - cJSON_AddNumberToObject(root, "socketLockOperatingTime", socket_lock_get_operating_time()); - cJSON_AddNumberToObject(root, "socketLockBreakTime", socket_lock_get_break_time()); - cJSON_AddBoolToObject(root, "socketLockDetectionHigh", socket_lock_is_detection_high()); - cJSON_AddNumberToObject(root, "socketLockRetryCount", socket_lock_get_retry_count()); - - //cJSON_AddStringToObject(root, "modelMeter", meter_model_to_str(meter_get_model())); - //cJSON_AddNumberToObject(root, "maxGridCurrent", grid_get_max_current()); - //cJSON_AddStringToObject(root, "stateMeter", meter_state_to_str(meter_get_state())); - - char str[64]; - cJSON_AddBoolToObject(root, "enabledocpp", ocpp_get_enabled()); - ocpp_get_server(str); - cJSON_AddStringToObject(root, "serverocpp", str); - //ocpp_get_rfid(str); - //cJSON_AddStringToObject(root, "rfid", str); - - return root; -} - -esp_err_t json_set_evse_config(cJSON *root) -{ - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "maxChargingCurrent"))) - { - RETURN_ON_ERROR(evse_set_max_charging_current(cJSON_GetObjectItem(root, "maxChargingCurrent")->valuedouble)); - } - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "chargingCurrent"))) - { - RETURN_ON_ERROR(evse_set_charging_current(cJSON_GetObjectItem(root, "chargingCurrent")->valuedouble)); - } - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "defaultChargingCurrent"))) - { - RETURN_ON_ERROR(evse_set_default_charging_current(cJSON_GetObjectItem(root, "defaultChargingCurrent")->valuedouble)); - } - if (cJSON_IsBool(cJSON_GetObjectItem(root, "requireAuth"))) - { - //auth_set_mode(cJSON_IsTrue(cJSON_GetObjectItem(root, "requireAuth"))); - } - if (cJSON_IsBool(cJSON_GetObjectItem(root, "socketOutlet"))) - { - RETURN_ON_ERROR(evse_set_socket_outlet(cJSON_IsTrue(cJSON_GetObjectItem(root, "socketOutlet")))); - } - if (cJSON_IsBool(cJSON_GetObjectItem(root, "rcm"))) - { - RETURN_ON_ERROR(evse_set_rcm(cJSON_IsTrue(cJSON_GetObjectItem(root, "rcm")))); - } - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "temperatureThreshold"))) - { - RETURN_ON_ERROR(evse_set_temp_threshold(cJSON_GetObjectItem(root, "temperatureThreshold")->valuedouble)); - } - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "consumptionLimit"))) - { - evse_set_consumption_limit(cJSON_GetObjectItem(root, "consumptionLimit")->valuedouble); - } - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "defaultConsumptionLimit"))) - { - evse_set_default_consumption_limit(cJSON_GetObjectItem(root, "defaultConsumptionLimit")->valuedouble); - } - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "chargingTimeLimit"))) - { - evse_set_charging_time_limit(cJSON_GetObjectItem(root, "chargingTimeLimit")->valuedouble); - } - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "defaultChargingTimeLimit"))) - { - evse_set_default_charging_time_limit(cJSON_GetObjectItem(root, "defaultChargingTimeLimit")->valuedouble); - } - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "underPowerLimit"))) - { - evse_set_under_power_limit(cJSON_GetObjectItem(root, "underPowerLimit")->valuedouble); - } - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "defaultUnderPowerLimit"))) - { - evse_set_default_under_power_limit(cJSON_GetObjectItem(root, "defaultUnderPowerLimit")->valuedouble); - } - - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "socketLockOperatingTime"))) - { - RETURN_ON_ERROR(socket_lock_set_operating_time(cJSON_GetObjectItem(root, "socketLockOperatingTime")->valuedouble)); - } - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "socketLockBreakTime"))) - { - RETURN_ON_ERROR(socket_lock_set_break_time(cJSON_GetObjectItem(root, "socketLockBreakTime")->valuedouble)); - } - if (cJSON_IsBool(cJSON_GetObjectItem(root, "socketLockDetectionHigh"))) - { - socket_lock_set_detection_high(cJSON_IsTrue(cJSON_GetObjectItem(root, "socketLockDetectionHigh"))); - } - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "socketLockRetryCount"))) - { - socket_lock_set_retry_count(cJSON_GetObjectItem(root, "socketLockRetryCount")->valuedouble); - } - - /* - if (cJSON_IsString(cJSON_GetObjectItem(root, "modelMeter"))) - { - RETURN_ON_ERROR(meter_set_model(meter_str_to_model(cJSON_GetObjectItem(root, "modelMeter")->valuestring))); - } - - if (cJSON_IsString(cJSON_GetObjectItem(root, "stateMeter"))) - { - RETURN_ON_ERROR(meter_set_state(meter_str_to_state(cJSON_GetObjectItem(root, "stateMeter")->valuestring))); - } - - if (cJSON_IsNumber(cJSON_GetObjectItem(root, "maxGridCurrent"))) - { - RETURN_ON_ERROR(grid_set_max_current(cJSON_GetObjectItem(root, "maxGridCurrent")->valuedouble)); - } - */ - - if (cJSON_IsBool(cJSON_GetObjectItem(root, "enabledocpp"))) - { - ocpp_set_enabled(cJSON_IsTrue(cJSON_GetObjectItem(root, "enabledocpp"))); - } - - if (cJSON_IsString(cJSON_GetObjectItem(root, "serverocpp"))) - { - ocpp_set_server(cJSON_GetStringValue(cJSON_GetObjectItem(root, "serverocpp"))); - } - - //if (cJSON_IsString(cJSON_GetObjectItem(root, "rfid"))) - //{ - // ocpp_set_rfid(cJSON_GetStringValue(cJSON_GetObjectItem(root, "rfid"))); - //} - - return ESP_OK; -} - - -/* -cJSON *json_get_wifi_config(void) -{ - cJSON *root = cJSON_CreateObject(); - - char str[32]; - - cJSON_AddBoolToObject(root, "enabled", wifi_get_enabled()); - wifi_get_ssid(str); - cJSON_AddStringToObject(root, "ssid", str); - - return root; -} - -esp_err_t json_set_wifi_config(cJSON *root, bool timeout) -{ - bool enabled = cJSON_IsTrue(cJSON_GetObjectItem(root, "enabled")); - char *ssid = cJSON_GetStringValue(cJSON_GetObjectItem(root, "ssid")); - char *password = cJSON_GetStringValue(cJSON_GetObjectItem(root, "password")); - - if (timeout) - { - return timeout_wifi_set_config(enabled, ssid, password); - } - else - { - return wifi_set_config(enabled, ssid, password); - } -} - -cJSON *json_get_wifi_scan(void) -{ - cJSON *root = cJSON_CreateArray(); - - - wifi_scan_ap_t scan_aps[WIFI_SCAN_SCAN_LIST_SIZE]; - uint16_t number = wifi_scan(scan_aps); - for (int i = 0; i < number; i++) - { - cJSON *item = cJSON_CreateObject(); - cJSON_AddStringToObject(item, "ssid", scan_aps[i].ssid); - cJSON_AddNumberToObject(item, "rssi", scan_aps[i].rssi); - cJSON_AddBoolToObject(item, "auth", scan_aps[i].auth); - cJSON_AddItemToArray(root, item); - } - - return root; -} -*/ - -cJSON *json_get_mqtt_config(void) -{ - cJSON *root = cJSON_CreateObject(); - - char str[64]; - - cJSON_AddBoolToObject(root, "enabled", mqtt_get_enabled()); - mqtt_get_server(str); - cJSON_AddStringToObject(root, "server", str); - mqtt_get_base_topic(str); - cJSON_AddStringToObject(root, "baseTopic", str); - mqtt_get_user(str); - cJSON_AddStringToObject(root, "user", str); - mqtt_get_password(str); - cJSON_AddStringToObject(root, "password", str); - cJSON_AddNumberToObject(root, "periodicity", mqtt_get_periodicity()); - - return root; -} - -esp_err_t json_set_mqtt_config(cJSON *root) -{ - bool enabled = cJSON_IsTrue(cJSON_GetObjectItem(root, "enabled")); - char *server = cJSON_GetStringValue(cJSON_GetObjectItem(root, "server")); - char *base_topic = cJSON_GetStringValue(cJSON_GetObjectItem(root, "baseTopic")); - char *user = cJSON_GetStringValue(cJSON_GetObjectItem(root, "user")); - char *password = cJSON_GetStringValue(cJSON_GetObjectItem(root, "password")); - uint16_t periodicity = cJSON_GetNumberValue(cJSON_GetObjectItem(root, "periodicity")); - - return mqtt_set_config(enabled, server, base_topic, user, password, periodicity); -} - - - -cJSON *json_get_modbus_config(void) -{ - cJSON *root = cJSON_CreateObject(); - - //cJSON_AddBoolToObject(root, "tcpEnabled", modbus_tcp_is_enabled()); - //cJSON_AddNumberToObject(root, "unitId", modbus_get_unit_id()); - - cJSON_AddBoolToObject(root, "tcpEnabled", false); - cJSON_AddNumberToObject(root, "unitId", 1); - - return root; -} - -esp_err_t json_set_modbus_config(cJSON *root) -{ - //bool tcp_enabled = cJSON_IsTrue(cJSON_GetObjectItem(root, "tcpEnabled")); - //uint8_t unit_id = cJSON_GetObjectItem(root, "unitId")->valuedouble; - - //modbus_tcp_set_enabled(tcp_enabled); - return 0; //modbus_set_unit_id(unit_id); -} -/* - -cJSON* json_get_script_config(void) -{ - cJSON* root = cJSON_CreateObject(); - - cJSON_AddBoolToObject(root, "enabled", script_is_enabled()); - - return root; -} - -esp_err_t json_set_script_config(cJSON* root) -{ - bool enabled = cJSON_IsTrue(cJSON_GetObjectItem(root, "enabled")); - - script_set_enabled(enabled); - - return ESP_OK; -}*/ - -cJSON *json_get_time_config(void) -{ - cJSON *root = cJSON_CreateObject(); - char str[64]; - - cJSON_AddBoolToObject(root, "ntpEnabled", date_time_is_ntp_enabled()); - date_time_get_ntp_server(str); - cJSON_AddStringToObject(root, "ntpServer", str); - cJSON_AddBoolToObject(root, "ntpFromDhcp", date_time_is_ntp_from_dhcp()); - date_time_get_timezone(str); - cJSON_AddStringToObject(root, "timezone", str); - - return root; -} - -esp_err_t json_set_time_config(cJSON *root) -{ - char *ntp_server = cJSON_GetStringValue(cJSON_GetObjectItem(root, "ntpServer")); - bool ntp_enabled = cJSON_IsTrue(cJSON_GetObjectItem(root, "ntpEnabled")); - bool ntp_from_dhcp = cJSON_IsTrue(cJSON_GetObjectItem(root, "ntpFromDhcp")); - char *timezone = cJSON_GetStringValue(cJSON_GetObjectItem(root, "timezone")); - - date_time_set_ntp_config(ntp_enabled, ntp_server, ntp_from_dhcp); - return date_time_set_timezone(timezone); -} - -cJSON *json_get_state(void) -{ - cJSON *root = cJSON_CreateObject(); - - cJSON_AddStringToObject(root, "state", evse_state_to_str(evse_get_state())); - cJSON_AddBoolToObject(root, "available", evse_config_is_available()); - cJSON_AddBoolToObject(root, "enabled", evse_config_is_enabled()); - cJSON_AddBoolToObject(root, "pendingAuth", auth_get_mode()); - cJSON_AddBoolToObject(root, "limitReached", evse_is_limit_reached()); - - uint32_t error = evse_error_get_bits(); - if (error == 0) - { - cJSON_AddNullToObject(root, "errors"); - } - else - { - cJSON *errors = cJSON_CreateArray(); - if (error & EVSE_ERR_PILOT_FAULT_BIT) - { - cJSON_AddItemToArray(errors, cJSON_CreateString("pilot_fault")); - } - if (error & EVSE_ERR_DIODE_SHORT_BIT) - { - cJSON_AddItemToArray(errors, cJSON_CreateString("diode_short")); - } - if (error & EVSE_ERR_LOCK_FAULT_BIT) - { - cJSON_AddItemToArray(errors, cJSON_CreateString("lock_fault")); - } - if (error & EVSE_ERR_UNLOCK_FAULT_BIT) - { - cJSON_AddItemToArray(errors, cJSON_CreateString("unlock_fault")); - } - if (error & EVSE_ERR_RCM_TRIGGERED_BIT) - { - cJSON_AddItemToArray(errors, cJSON_CreateString("rcm_triggered")); - } - if (error & EVSE_ERR_RCM_SELFTEST_FAULT_BIT) - { - cJSON_AddItemToArray(errors, cJSON_CreateString("rcm_selftest_fault")); - } - if (error & EVSE_ERR_TEMPERATURE_HIGH_BIT) - { - cJSON_AddItemToArray(errors, cJSON_CreateString("temperature_high")); - } - if (error & EVSE_ERR_TEMPERATURE_FAULT_BIT) - { - cJSON_AddItemToArray(errors, cJSON_CreateString("temperature_fault")); - } - cJSON_AddItemToObject(root, "errors", errors); - } - - - // dentro da sua função de gerar JSON: - evse_session_t sess; - if (evse_get_session(&sess)) { - // Há sessão atual ou última disponível - cJSON_AddNumberToObject(root, "sessionTime", (double)sess.start_tick); - cJSON_AddNumberToObject(root, "chargingTime", (double)sess.duration_s); - cJSON_AddNumberToObject(root, "consumption", (double)sess.energy_wh); - } else { - // Nenhuma sessão disponível - cJSON_AddNullToObject(root, "sessionTime"); - cJSON_AddNumberToObject(root, "chargingTime", 0); - cJSON_AddNumberToObject(root, "consumption", 0); - } - - // 1) Arrays temporários para ler dados do medidor - float voltage_f[EVSE_METER_PHASE_COUNT]; - float current_f[EVSE_METER_PHASE_COUNT]; - int power_w[ EVSE_METER_PHASE_COUNT]; - - // 2) Leitura dos valores via API pública - evse_meter_get_voltage(voltage_f); // já em volts - evse_meter_get_current(current_f); // já em amperes - evse_meter_get_power(power_w); // em watts por fase - - // 4) Energia acumulada em kWh - //float consumption_kwh = evse_meter_get_total_energy() / 1000.0f; // Wh → kWh - - // 6) Arrays de tensão e corrente - cJSON_AddItemToObject(root, "power", - cJSON_CreateIntArray(power_w, EVSE_METER_PHASE_COUNT)); - cJSON_AddItemToObject(root, "voltage", - cJSON_CreateFloatArray(voltage_f, EVSE_METER_PHASE_COUNT)); - cJSON_AddItemToObject(root, "current", - cJSON_CreateFloatArray(current_f, EVSE_METER_PHASE_COUNT)); - - - - return root; -} - -cJSON *json_get_info(void) -{ - cJSON *root = cJSON_CreateObject(); - - cJSON_AddNumberToObject(root, "uptime", esp_timer_get_time() / 1000000); - const esp_app_desc_t *app_desc = esp_app_get_description(); - cJSON_AddStringToObject(root, "appVersion", app_desc->version); - cJSON_AddStringToObject(root, "appDate", app_desc->date); - cJSON_AddStringToObject(root, "appTime", app_desc->time); - cJSON_AddStringToObject(root, "idfVersion", app_desc->idf_ver); - cJSON_AddStringToObject(root, "chip", CONFIG_IDF_TARGET); - esp_chip_info_t chip_info; - esp_chip_info(&chip_info); - cJSON_AddNumberToObject(root, "chipCores", chip_info.cores); - chip_info.revision = 301; - cJSON_AddNumberToObject(root, "chipRevision", chip_info.revision / 100); - multi_heap_info_t heap_info; - heap_caps_get_info(&heap_info, MALLOC_CAP_INTERNAL); - cJSON_AddNumberToObject(root, "heapSize", heap_info.total_allocated_bytes); - cJSON_AddNumberToObject(root, "maxHeapSize", heap_info.total_free_bytes + heap_info.total_allocated_bytes); - uint8_t mac[6]; - char str[32]; - esp_wifi_get_mac(ESP_IF_WIFI_STA, mac); - sprintf(str, MACSTR, MAC2STR(mac)); - cJSON_AddStringToObject(root, "mac", str); - esp_netif_ip_info_t ip_info; - esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info); - esp_ip4addr_ntoa(&ip_info.ip, str, sizeof(str)); - cJSON_AddStringToObject(root, "ip", str); - esp_wifi_get_mac(ESP_IF_WIFI_AP, mac); - sprintf(str, MACSTR, MAC2STR(mac)); - cJSON_AddStringToObject(root, "macAp", str); - esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"), &ip_info); - esp_ip4addr_ntoa(&ip_info.ip, str, sizeof(str)); - cJSON_AddStringToObject(root, "ipAp", str); - cJSON_AddNumberToObject(root, "temperatureSensorCount", temp_sensor_get_count()); - cJSON_AddNumberToObject(root, "temperatureLow", temp_sensor_get_low() / 100.0); - cJSON_AddNumberToObject(root, "temperatureHigh", temp_sensor_get_high() / 100.0); - return root; -} - -static const char *serial_to_str(board_config_serial_t serial) -{ - switch (serial) - { - case BOARD_CONFIG_SERIAL_UART: - return "uart"; - case BOARD_CONFIG_SERIAL_RS485: - return "rs485"; - default: - return "none"; - } -} - -cJSON *json_get_board_config(void) -{ - cJSON *root = cJSON_CreateObject(); - - cJSON_AddStringToObject(root, "deviceName", board_config.device_name); - cJSON_AddBoolToObject(root, "socketLock", board_config.socket_lock); - cJSON_AddBoolToObject(root, "proximity", board_config.proximity); - cJSON_AddNumberToObject(root, "socketLockMinBreakTime", board_config.socket_lock_min_break_time); - cJSON_AddBoolToObject(root, "rcm", board_config.rcm); - cJSON_AddBoolToObject(root, "temperatureSensor", board_config.onewire && board_config.onewire_temp_sensor); - - /* - switch (board_config.energy_meter) - { - case BOARD_CONFIG_ENERGY_METER_CUR: - cJSON_AddStringToObject(root, "energyMeter", "cur"); - break; - case BOARD_CONFIG_ENERGY_METER_CUR_VLT: - cJSON_AddStringToObject(root, "energyMeter", "cur_vlt"); - break; - default: - cJSON_AddStringToObject(root, "energyMeter", "none"); - } - //cJSON_AddBoolToObject(root, "energyMeterThreePhases", board_config.energy_meter_three_phases); - */ - - cJSON_AddStringToObject(root, "serial1", serial_to_str(board_config.serial_1)); - cJSON_AddStringToObject(root, "serial1Name", board_config.serial_1_name); - cJSON_AddStringToObject(root, "serial2", serial_to_str(board_config.serial_2)); - cJSON_AddStringToObject(root, "serial2Name", board_config.serial_2_name); -#if SOC_UART_NUM > 2 - cJSON_AddStringToObject(root, "serial3", serial_to_str(board_config.serial_3)); - cJSON_AddStringToObject(root, "serial3Name", board_config.serial_3_name); -#else - cJSON_AddStringToObject(root, "serial3", serial_to_str(BOARD_CONFIG_SERIAL_NONE)); - cJSON_AddStringToObject(root, "serial3Name", ""); -#endif - - cJSON *aux = cJSON_CreateArray(); - if (board_config.aux_in_1) - { - cJSON_AddItemToArray(aux, cJSON_CreateString(board_config.aux_in_1_name)); - } - if (board_config.aux_in_2) - { - cJSON_AddItemToArray(aux, cJSON_CreateString(board_config.aux_in_2_name)); - } - if (board_config.aux_in_3) - { - cJSON_AddItemToArray(aux, cJSON_CreateString(board_config.aux_in_3_name)); - } - if (board_config.aux_in_4) - { - cJSON_AddItemToArray(aux, cJSON_CreateString(board_config.aux_in_4_name)); - } - cJSON_AddItemToObject(root, "auxIn", aux); - - aux = cJSON_CreateArray(); - if (board_config.aux_out_1) - { - cJSON_AddItemToArray(aux, cJSON_CreateString(board_config.aux_out_1_name)); - } - if (board_config.aux_out_2) - { - cJSON_AddItemToArray(aux, cJSON_CreateString(board_config.aux_out_2_name)); - } - if (board_config.aux_out_3) - { - cJSON_AddItemToArray(aux, cJSON_CreateString(board_config.aux_out_3_name)); - } - if (board_config.aux_out_4) - { - cJSON_AddItemToArray(aux, cJSON_CreateString(board_config.aux_out_4_name)); - } - cJSON_AddItemToObject(root, "auxOut", aux); - - aux = cJSON_CreateArray(); - if (board_config.aux_ain_1) - { - cJSON_AddItemToArray(aux, cJSON_CreateString(board_config.aux_ain_1_name)); - } - if (board_config.aux_ain_2) - { - cJSON_AddItemToArray(aux, cJSON_CreateString(board_config.aux_ain_2_name)); - } - cJSON_AddItemToObject(root, "auxAin", aux); - - return root; -} diff --git a/components/api/src/ota.c b/components/api/src/ota.c deleted file mode 100755 index d2364cc..0000000 --- a/components/api/src/ota.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include "esp_log.h" -#include "esp_err.h" -#include "esp_http_client.h" -#include "cJSON.h" - -#include "ota.h" - -static const char* TAG = "ota"; - -extern const char server_cert_pem_start[] asm("_binary_ca_cert_pem_start"); -extern const char server_cert_pem_end[] asm("_binary_ca_cert_pem_end"); - -static void http_client_cleanup(esp_http_client_handle_t client) -{ - esp_http_client_close(client); - esp_http_client_cleanup(client); -} - -esp_err_t ota_get_available_version(char* version) -{ - esp_http_client_config_t config = { - .url = OTA_VERSION_URL, - .cert_pem = server_cert_pem_start - }; - - esp_http_client_handle_t client = esp_http_client_init(&config); - - esp_err_t err = esp_http_client_open(client, 0); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err)); - esp_http_client_cleanup(client); - return err; - } - - int content_length = esp_http_client_fetch_headers(client); - if (content_length > 0) { - esp_http_client_read(client, version, content_length); - version[content_length] = '\0'; - http_client_cleanup(client); - return ESP_OK; - } else { - http_client_cleanup(client); - ESP_LOGI(TAG, "No firmware available"); - return ESP_ERR_NOT_FOUND; - } -} - -bool ota_is_newer_version(const char* actual, const char* available) -{ - // available version has no suffix eg: vX.X.X-beta - - char actual_trimed[32]; - strcpy(actual_trimed, actual); - - char* saveptr; - strtok_r(actual_trimed, "-", &saveptr); - bool actual_has_suffix = strtok_r(NULL, "-", &saveptr); - - int diff = strcmp(available, actual_trimed); - if (diff == 0) { - return actual_has_suffix; - } else { - return diff > 0; - } -} diff --git a/components/api/src/timeout_utils.c b/components/api/src/timeout_utils.c deleted file mode 100755 index 09f3c25..0000000 --- a/components/api/src/timeout_utils.c +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "esp_system.h" - -#include "timeout_utils.h" -#include "network.h" -//#include "rest.h" - -static void restart_func(void* arg) -{ - vTaskDelay(pdMS_TO_TICKS(5000)); - - //esp_restart(); - - vTaskDelete(NULL); -} - -void timeout_restart() -{ - //xTaskCreate(restart_func, "restart_task", 2 * 1024, NULL, 10, NULL); -} - -typedef struct -{ - bool enabled; - bool ssid_blank; - char ssid[32]; - bool password_blank; - char password[64]; -} wifi_set_config_arg_t; - -static void wifi_set_config_func(void* arg) -{ - vTaskDelay(pdMS_TO_TICKS(1000)); - - wifi_set_config_arg_t* config = (wifi_set_config_arg_t*)arg; - wifi_set_config(config->enabled, config->ssid_blank ? NULL : config->ssid, config->password_blank ? NULL : config->password); - free((void*)config); - - vTaskDelete(NULL); -} - -esp_err_t timeout_wifi_set_config(bool enabled, const char* ssid, const char* password) -{ - if (enabled) { - if (ssid == NULL || strlen(ssid) == 0) { - char old_ssid[32]; - wifi_get_ssid(old_ssid); - if (strlen(old_ssid) == 0) { - return ESP_ERR_INVALID_ARG; - } - } - } - - wifi_set_config_arg_t* config = (wifi_set_config_arg_t*)malloc(sizeof(wifi_set_config_arg_t)); - config->enabled = enabled; - if (ssid == NULL || ssid[0] == '\0') { - config->ssid_blank = true; - } else { - config->ssid_blank = false; - strcpy(config->ssid, ssid); - } - if (password == NULL || password[0] == '\0') { - config->password_blank = true; - } else { - config->password_blank = false; - strcpy(config->password, password); - } - - xTaskCreate(wifi_set_config_func, "wifi_set_config", 4 * 1024, (void*)config, 10, NULL); - - return ESP_OK; -} diff --git a/components/auth/src/auth.c b/components/auth/src/auth.c index 253e28e..b4f1cdd 100755 --- a/components/auth/src/auth.c +++ b/components/auth/src/auth.c @@ -174,23 +174,6 @@ auth_mode_t auth_get_mode(void) { return s_mode; } -const char *auth_mode_to_str(auth_mode_t mode) { - switch (mode) { - case AUTH_MODE_OPEN: return "open"; - case AUTH_MODE_LOCAL_RFID: return "local"; - case AUTH_MODE_OCPP_RFID: return "ocpp"; - default: return "open"; - } -} - -bool auth_mode_from_str(const char *s, auth_mode_t *out) { - if (!s || !out) return false; - if (!strcasecmp(s, "open")) { *out = AUTH_MODE_OPEN; return true; } - if (!strcasecmp(s, "local")) { *out = AUTH_MODE_LOCAL_RFID; return true; } - if (!strcasecmp(s, "ocpp")) { *out = AUTH_MODE_OCPP_RFID; return true; } - return false; -} - bool auth_add_tag(const char *tag) { if (tag_count >= MAX_TAGS) return false; if (!tag || strlen(tag) >= AUTH_TAG_MAX_LEN) return false; diff --git a/components/auth/src/wiegand_reader.c b/components/auth/src/wiegand_reader.c index 01ca594..af0db78 100755 --- a/components/auth/src/wiegand_reader.c +++ b/components/auth/src/wiegand_reader.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -7,61 +8,272 @@ #include #include "auth.h" +#include +#include +#include + #define CONFIG_EXAMPLE_BUF_SIZE 50 +#define IDTAG_MAX_LEN 20 static const char *TAG = "WiegandReader"; +// ---- Parâmetro global/locale para controlar a convenção de paridade ---- +static const bool PARITY_INVERTED = false; // mude para true se o seu leitor vier "invertido" + static wiegand_reader_t reader; static QueueHandle_t queue = NULL; -typedef struct { +typedef struct +{ uint8_t data[CONFIG_EXAMPLE_BUF_SIZE]; size_t bits; + size_t bytes; } data_packet_t; -static void reader_callback(wiegand_reader_t *r) { - data_packet_t p; - p.bits = r->bits; - memcpy(p.data, r->buf, CONFIG_EXAMPLE_BUF_SIZE); - xQueueSendToBack(queue, &p, 0); +static inline uint8_t get_bit_msb_first(const uint8_t *buf, size_t bit_index) +{ + return (buf[bit_index / 8] >> (7 - (bit_index % 8))) & 0x01; } -static void wiegand_task(void *arg) { - queue = xQueueCreate(5, sizeof(data_packet_t)); - if (!queue) { +// Versão parametrizável +static bool check_parity_param(const uint8_t *buf, size_t bits, bool invert) +{ + if (bits != 26 && bits != 34) + return false; + + const int first_parity = get_bit_msb_first(buf, 0); + const int last_parity = get_bit_msb_first(buf, bits - 1); + + uint32_t left = 0, right = 0; + + if (bits == 26) + { + for (int i = 1; i <= 12; i++) + if (get_bit_msb_first(buf, i)) + left++; + for (int i = 13; i <= 24; i++) + if (get_bit_msb_first(buf, i)) + right++; + } + else + { // 34 + for (int i = 1; i <= 16; i++) + if (get_bit_msb_first(buf, i)) + left++; + for (int i = 17; i <= 32; i++) + if (get_bit_msb_first(buf, i)) + right++; + } + + // Regra padrão (W26/W34 “normais”): primeiro = PAR (left), último = ÍMPAR (right) + bool exp_first = (left % 2 == 0); + bool exp_last = (right % 2 == 1); + + // Se invertido, troca as expectativas (par <-> ímpar) + if (invert) + { + exp_first = !exp_first; + exp_last = !exp_last; + } + + return (first_parity == exp_first) && (last_parity == exp_last); +} + +// CRC-8/ATM (polinómio 0x07, init 0x00, sem ref, xor 0x00) +static uint8_t crc8_atm(const uint8_t *data, size_t len) +{ + uint8_t crc = 0x00; + for (size_t i = 0; i < len; i++) + { + crc ^= data[i]; + for (int b = 0; b < 8; b++) + { + crc = (crc & 0x80) ? (uint8_t)((crc << 1) ^ 0x07) : (uint8_t)(crc << 1); + } + } + return crc; +} + +// CRC-16/IBM (CRC-16-ANSI) poly 0xA001 (refin/refout), init 0xFFFF +static uint16_t crc16_ibm(const uint8_t *data, size_t len) +{ + uint16_t crc = 0xFFFF; + for (size_t i = 0; i < len; i++) + { + crc ^= data[i]; + for (int b = 0; b < 8; b++) + { + if (crc & 1) + crc = (crc >> 1) ^ 0xA001; + else + crc >>= 1; + } + } + return crc; +} + +// Extrai payload (sem paridades) e devolve FC/CN para W26/34 +static bool wiegand_extract_fc_cn(const uint8_t *buf, size_t bits, uint32_t *fc, uint32_t *cn) +{ + if (bits != 26 && bits != 34) + return false; + uint32_t payload = 0; + size_t payload_bits = bits - 2; + for (size_t i = 0; i < payload_bits; i++) + { + size_t bit = 1 + i; // ignora bit de paridade inicial + uint8_t bitval = (buf[bit / 8] >> (7 - (bit % 8))) & 0x01; + payload = (payload << 1) | bitval; + } + if (bits == 26) + { + *fc = (payload >> 16) & 0xFF; // 8b + *cn = payload & 0xFFFF; // 16b + } + else + { + *fc = (payload >> 16) & 0xFFFF; // 16b + *cn = payload & 0xFFFF; // 16b + } + return true; +} + +static bool build_idtag_w26_4B(uint32_t fc, uint32_t cn, char *out, size_t outlen) +{ + uint8_t raw[4] = { + (uint8_t)(fc & 0xFF), + (uint8_t)((cn >> 8) & 0xFF), + (uint8_t)(cn & 0xFF), + 0}; + raw[3] = crc8_atm(raw, 3); + if (outlen < 9) + return false; + int n = snprintf(out, outlen, "%02X%02X%02X%02X", raw[0], raw[1], raw[2], raw[3]); + return (n > 0 && (size_t)n < outlen); +} + +static bool build_idtag_w34_7B(uint32_t fc, uint32_t cn, char *out, size_t outlen) +{ + uint8_t raw[7]; + raw[0] = 0x34; + raw[1] = (uint8_t)((fc >> 8) & 0xFF); + raw[2] = (uint8_t)(fc & 0xFF); + raw[3] = (uint8_t)((cn >> 8) & 0xFF); + raw[4] = (uint8_t)(cn & 0xFF); + uint16_t crc = crc16_ibm(raw, 5); + raw[5] = (uint8_t)((crc >> 8) & 0xFF); + raw[6] = (uint8_t)(crc & 0xFF); + if (outlen < 15) + return false; + int n = snprintf(out, outlen, "%02X%02X%02X%02X%02X%02X%02X", + raw[0], raw[1], raw[2], raw[3], raw[4], raw[5], raw[6]); + return (n > 0 && (size_t)n < outlen); +} + +// Se o callback for de ISR, troque para xQueueSendToBackFromISR. +static void reader_callback(wiegand_reader_t *r) +{ + data_packet_t p = {0}; + p.bits = r->bits; + p.bytes = (r->bits + 7) / 8; + if (p.bytes > sizeof(p.data)) + p.bytes = sizeof(p.data); + memcpy(p.data, r->buf, p.bytes); + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // Se NÃO for ISR, use xQueueSendToBack(queue, &p, 0); + xQueueSendToBackFromISR(queue, &p, &xHigherPriorityTaskWoken); + if (xHigherPriorityTaskWoken) + portYIELD_FROM_ISR(); +} + +static void wiegand_task(void *arg) +{ + queue = xQueueCreate(8, sizeof(data_packet_t)); + if (!queue) + { ESP_LOGE(TAG, "Failed to create queue"); vTaskDelete(NULL); return; } ESP_ERROR_CHECK(wiegand_reader_init(&reader, 21, 22, - true, CONFIG_EXAMPLE_BUF_SIZE, reader_callback, WIEGAND_MSB_FIRST, WIEGAND_LSB_FIRST)); + true, CONFIG_EXAMPLE_BUF_SIZE, reader_callback, WIEGAND_MSB_FIRST, WIEGAND_LSB_FIRST)); data_packet_t p; - while (1) { + for (;;) + { ESP_LOGI(TAG, "Waiting for Wiegand data..."); - if (xQueueReceive(queue, &p, portMAX_DELAY) == pdPASS) { - ESP_LOGI(TAG, "Bits received: %d", p.bits); + if (xQueueReceive(queue, &p, portMAX_DELAY) != pdPASS) + continue; - char tag[20] = {0}; + ESP_LOGI(TAG, "Bits received: %d", (int)p.bits); - if (p.bits == 26) { - snprintf(tag, sizeof(tag), "%03d%03d%03d", p.data[0], p.data[1], p.data[2]); - } else if (p.bits == 34) { - snprintf(tag, sizeof(tag), "%03d%03d%03d%03d", p.data[0], p.data[1], p.data[2], p.data[3]); - } else { - ESP_LOGW(TAG, "Unsupported bit length: %d", (int)p.bits); - ESP_LOG_BUFFER_HEX(TAG, p.data, sizeof(p.data)); // loga o buffer bruto - continue; - } + if (!check_parity_param(p.data, p.bits, PARITY_INVERTED)) + { + ESP_LOGW(TAG, "Parity check failed (%d bits). Dump:", (int)p.bits); + ESP_LOG_BUFFER_HEX(TAG, p.data, p.bytes); + continue; + } - ESP_LOGI(TAG, "Tag read: %s", tag); - auth_process_tag(tag); // agora delega toda a lógica à auth.c + char tag[21] = {0}; // OCPP 1.6: máx 20 chars (+NUL) + uint32_t fc = 0, cn = 0; + + if (!wiegand_extract_fc_cn(p.data, p.bits, &fc, &cn)) + { + ESP_LOGW(TAG, "Unsupported bit length: %d", (int)p.bits); + continue; + } + + bool ok = false; + if (p.bits == 26) + { + ok = build_idtag_w26_4B(fc, cn, tag, sizeof(tag)); // 8 hex + } + else + { // 34 + ok = build_idtag_w34_7B(fc, cn, tag, sizeof(tag)); // 14 hex + } + + if (!ok) + { + ESP_LOGW(TAG, "Failed to build idTag"); + continue; + } + + ESP_LOGI(TAG, "idTag: %s", tag); // apenas [0-9A-F], alfanumérico + auth_process_tag(tag); + } +} + +static void wiegand_sim_task(void *arg) +{ + // lista fixa de idTags simuladas + static const char *idtaglist[] = { + "0000004134962107", + "W2602312345", + "W34ABCDE12345", + }; + const size_t list_size = sizeof(idtaglist) / sizeof(idtaglist[0]); + + for (;;) + { + for (size_t i = 0; i < list_size; i++) + { + ESP_LOGI(TAG, "Simulação -> idTag: %s", idtaglist[i]); + auth_process_tag(idtaglist[i]); + + // espera 20 segundos entre cada tag + vTaskDelay(pdMS_TO_TICKS(30000)); } } } -void initWiegand(void) { +void initWiegand(void) +{ ESP_LOGI(TAG, "Initializing Wiegand reader"); xTaskCreate(wiegand_task, TAG, configMINIMAL_STACK_SIZE * 4, NULL, 4, NULL); + + // ESP_LOGI(TAG, "Inicializando Wiegand simulado"); + // xTaskCreate(wiegand_sim_task, "WiegandSim", configMINIMAL_STACK_SIZE * 3, NULL, 3, NULL); } diff --git a/components/buzzer/include/buzzer.h b/components/buzzer/include/buzzer.h index 81abbf5..371d1d2 100755 --- a/components/buzzer/include/buzzer.h +++ b/components/buzzer/include/buzzer.h @@ -1,11 +1,66 @@ +// buzzer.h #pragma once +#include +#include +#include "esp_err.h" +#include "buzzer_events.h" // para buzzer_pattern_id_t + #ifdef __cplusplus extern "C" { #endif +/** + * @brief Inicializa hardware, fila e task do buzzer; registra event handlers. + */ void buzzer_init(void); +/** + * @brief Desinicializa o buzzer (opcional), removendo handlers e task. + */ +void buzzer_deinit(void); + +/** + * @brief Solicita tocar um padrão de buzzer de forma assíncrona. + * @param id Enum do padrão (ver buzzer_events.h). + */ +void buzzer_play(buzzer_pattern_id_t id); + +/** + * @brief Interrompe imediatamente qualquer padrão em execução e esvazia a fila. + */ +void buzzer_stop(void); + +/** + * @brief Ativa/Desativa globalmente o buzzer (mute). + * Quando desativado, não toca e garante nível/desligado. + */ +void buzzer_set_enabled(bool enabled); + +/** + * @brief Retorna o estado atual de enable/mute do buzzer. + */ +bool buzzer_get_enabled(void); + +/** + * @brief Define quiet hours (janela silenciosa) em minutos desde 00:00. + * @param enabled Habilita/desabilita quiet hours. + * @param start_min Início (0..1439). + * @param end_min Fim (0..1439). Pode cruzar meia-noite. + */ +void buzzer_set_quiet_hours(bool enabled, uint16_t start_min, uint16_t end_min); + +/** + * @brief Ajusta a frequência PWM (somente PASSIVE/LEDC; timer exclusivo recomendado). + * @return ESP_OK em sucesso; erro se modo inválido ou argumento fora do range. + */ +esp_err_t buzzer_set_frequency(uint32_t hz); + +/** + * @brief Define o duty cycle em porcentagem (0..100) para PASSIVE/LEDC. + */ +void buzzer_set_duty_percent(uint8_t pct); + #ifdef __cplusplus } #endif diff --git a/components/buzzer/include/buzzer_events.h b/components/buzzer/include/buzzer_events.h index e86f2c5..0daf6a6 100644 --- a/components/buzzer/include/buzzer_events.h +++ b/components/buzzer/include/buzzer_events.h @@ -17,6 +17,7 @@ typedef enum { BUZZER_PATTERN_CARD_READ, BUZZER_PATTERN_CARD_ADD, BUZZER_PATTERN_CARD_DENIED, + BUZZER_PATTERN_FAULT, BUZZER_PATTERN_MAX } buzzer_pattern_id_t; diff --git a/components/buzzer/src/buzzer.c b/components/buzzer/src/buzzer.c index ebcdc75..0a2551d 100755 --- a/components/buzzer/src/buzzer.c +++ b/components/buzzer/src/buzzer.c @@ -1,205 +1,466 @@ +// buzzer.c #include "buzzer_events.h" #include "evse_events.h" #include "auth_events.h" #include "network_events.h" + +#include "esp_event.h" #include "esp_log.h" +#include "esp_err.h" + #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "driver/gpio.h" -#include "driver/ledc.h" // Para buzzer passivo +#include "freertos/queue.h" -#define BUZZER_GPIO GPIO_NUM_27 +#include "driver/gpio.h" +#include "driver/ledc.h" + +#include +#include + +// ===================== Configuração padrão (pode migrar para Kconfig) ===================== +#ifndef CONFIG_BUZZER_GPIO +#define CONFIG_BUZZER_GPIO GPIO_NUM_27 +#endif + +#ifndef CONFIG_BUZZER_MODE_PASSIVE // 1 = PASSIVE (PWM), 0 = ACTIVE (on/off) +#define CONFIG_BUZZER_MODE_PASSIVE 1 +#endif + +#ifndef CONFIG_BUZZER_FREQ_HZ +#define CONFIG_BUZZER_FREQ_HZ 3500 +#endif + +#ifndef CONFIG_BUZZER_DUTY_PCT +#define CONFIG_BUZZER_DUTY_PCT 70 +#endif + +#ifndef CONFIG_BUZZER_QUEUE_LEN +#define CONFIG_BUZZER_QUEUE_LEN 8 +#endif + +#ifndef CONFIG_BUZZER_TASK_STACK +#define CONFIG_BUZZER_TASK_STACK 2048 +#endif + +#ifndef CONFIG_BUZZER_TASK_PRIO +#define CONFIG_BUZZER_TASK_PRIO (tskIDLE_PRIORITY + 1) +#endif + +#ifndef CONFIG_BUZZER_MIN_GAP_MS // anti-spam (gap mínimo entre toques) +#define CONFIG_BUZZER_MIN_GAP_MS 70 +#endif + +#ifndef CONFIG_BUZZER_ENABLE_DEFAULT +#define CONFIG_BUZZER_ENABLE_DEFAULT 1 +#endif + +#ifndef CONFIG_BUZZER_QUIET_START_MIN // quiet hours start (minutos desde 00:00) +#define CONFIG_BUZZER_QUIET_START_MIN (22 * 60) +#endif + +#ifndef CONFIG_BUZZER_QUIET_END_MIN // quiet hours end (minutos desde 00:00) +#define CONFIG_BUZZER_QUIET_END_MIN (7 * 60) +#endif + +// ===================== Tipos e estado ===================== static const char *TAG = "Buzzer"; -// --- Configuração de modo --- -typedef enum { +typedef enum +{ BUZZER_MODE_ACTIVE = 0, BUZZER_MODE_PASSIVE } buzzer_mode_t; -typedef struct { - buzzer_mode_t mode; - gpio_num_t gpio; - - // Apenas para PASSIVE - uint32_t freq_hz; // ex: 4000 - uint8_t duty_percent; // 0–100 - ledc_mode_t ledc_speed_mode; // LEDC_LOW_SPEED_MODE - ledc_timer_t ledc_timer; // LEDC_TIMER_1 - ledc_channel_t ledc_channel; // LEDC_CHANNEL_1 - ledc_timer_bit_t duty_resolution; // LEDC_TIMER_10_BIT -} buzzer_config_t; - -static buzzer_config_t s_buzzer_cfg = { - .mode = BUZZER_MODE_PASSIVE, // Mude para PASSIVE se for buzzer passivo - .gpio = BUZZER_GPIO, - .freq_hz = 4000, - .duty_percent = 50, - .ledc_speed_mode = LEDC_LOW_SPEED_MODE, - .ledc_timer = LEDC_TIMER_1, - .ledc_channel = LEDC_CHANNEL_1, - .duty_resolution = LEDC_TIMER_10_BIT -}; - -// --- Estrutura de passos --- -typedef struct { +typedef struct +{ uint16_t on_ms; uint16_t off_ms; } buzzer_step_t; -// Padrões de buzzer -static const buzzer_step_t pattern_plugged[] = {{200, 100}}; -static const buzzer_step_t pattern_unplugged[] = {{150, 150}, {150, 150}, {150, 0}}; -static const buzzer_step_t pattern_charging[] = {{80, 150}, {100, 120}, {120, 100}, {140, 0}}; -static const buzzer_step_t pattern_ap_start[] = {{300, 150}, {300, 0}}; -static const buzzer_step_t pattern_card_read[] = {{50, 50}, {50, 0}}; -static const buzzer_step_t pattern_card_add[] = {{100, 100}, {100, 100}, {100, 0}}; -static const buzzer_step_t pattern_card_denied[] = {{300, 100}, {300, 0}}; - -typedef struct { +typedef struct +{ const buzzer_step_t *steps; size_t length; } buzzer_pattern_t; -static const buzzer_pattern_t buzzer_patterns[] = { - [BUZZER_PATTERN_PLUGGED] = {pattern_plugged, sizeof(pattern_plugged) / sizeof(buzzer_step_t)}, - [BUZZER_PATTERN_UNPLUGGED] = {pattern_unplugged, sizeof(pattern_unplugged) / sizeof(buzzer_step_t)}, - [BUZZER_PATTERN_CHARGING] = {pattern_charging, sizeof(pattern_charging) / sizeof(buzzer_step_t)}, - [BUZZER_PATTERN_AP_START] = {pattern_ap_start, sizeof(pattern_ap_start) / sizeof(buzzer_step_t)}, - [BUZZER_PATTERN_CARD_READ] = {pattern_card_read, sizeof(pattern_card_read) / sizeof(buzzer_step_t)}, - [BUZZER_PATTERN_CARD_ADD] = {pattern_card_add, sizeof(pattern_card_add) / sizeof(buzzer_step_t)}, - [BUZZER_PATTERN_CARD_DENIED] = {pattern_card_denied, sizeof(pattern_card_denied) / sizeof(buzzer_step_t)}, +typedef struct +{ + buzzer_mode_t mode; + gpio_num_t gpio; + + // PASSIVE (PWM) + uint32_t freq_hz; + uint8_t duty_percent; // 0–100 + ledc_mode_t ledc_speed_mode; // LEDC_LOW_SPEED_MODE + ledc_timer_t ledc_timer; // LEDC_TIMER_1 + ledc_channel_t ledc_channel; // LEDC_CHANNEL_1 + ledc_timer_bit_t duty_resolution; // LEDC_TIMER_10_BIT +} buzzer_config_t; + +// Controlo runtime +static struct +{ + bool enabled; + uint16_t quiet_start_min; // [0..1440) + uint16_t quiet_end_min; // [0..1440) + bool quiet_enabled; +} s_buzzer_ctl = { + .enabled = CONFIG_BUZZER_ENABLE_DEFAULT, + .quiet_start_min = CONFIG_BUZZER_QUIET_START_MIN, + .quiet_end_min = CONFIG_BUZZER_QUIET_END_MIN, + .quiet_enabled = false, }; -// --- Funções de controle --- -static inline uint32_t duty_from_percent(uint8_t pct, ledc_timer_bit_t res) { - if (pct == 0) return 0; +// Hardware cfg +static buzzer_config_t s_buzzer_cfg = { + .mode = CONFIG_BUZZER_MODE_PASSIVE ? BUZZER_MODE_PASSIVE : BUZZER_MODE_ACTIVE, + .gpio = CONFIG_BUZZER_GPIO, + .freq_hz = CONFIG_BUZZER_FREQ_HZ, + .duty_percent = CONFIG_BUZZER_DUTY_PCT, + .ledc_speed_mode = LEDC_LOW_SPEED_MODE, + .ledc_timer = LEDC_TIMER_1, + .ledc_channel = LEDC_CHANNEL_1, + .duty_resolution = LEDC_TIMER_10_BIT}; + +// Fila e task +static QueueHandle_t s_buzzer_q = NULL; +static TaskHandle_t s_buzzer_task = NULL; + +// Anti-spam básico +static TickType_t s_last_play_tick = 0; +static const TickType_t s_min_gap_ticks = pdMS_TO_TICKS(CONFIG_BUZZER_MIN_GAP_MS); + +// ===================== Padrões (afinados) ===================== +// NOTA: os enums BUZZER_PATTERN_* vêm de buzzer_events.h + +// Curtos e claros +static const buzzer_step_t pattern_plugged[] = {{180, 120}}; // ~300 ms +static const buzzer_step_t pattern_card_read[] = {{80, 80}, {80, 0}}; // 160 ms audível + +// Um pouco mais longos, ritmo marcante +static const buzzer_step_t pattern_unplugged[] = {{140, 140}, {140, 140}, {140, 0}}; // ~700 ms +static const buzzer_step_t pattern_card_add[] = {{100, 100}, {100, 100}, {120, 0}}; // ~520 ms +static const buzzer_step_t pattern_ap_start[] = {{250, 150}, {250, 0}}; // ~650 ms + +// Charging mais curta (evento frequente) +static const buzzer_step_t pattern_charging[] = {{80, 90}, {90, 80}, {100, 0}}; // ~440 ms + +// Denied mais “duro” +static const buzzer_step_t pattern_card_denied[] = {{250, 120}, {300, 0}}; // ~670 ms + +// Fault crítico (duas trincas, ~1.7 s) +static const buzzer_step_t pattern_fault[] = { + {350, 120}, {350, 120}, {450, 250}, // bloco 1 + {350, 120}, + {350, 120}, + {450, 0} // bloco 2 +}; + +static const buzzer_pattern_t buzzer_patterns[] = { + [BUZZER_PATTERN_PLUGGED] = {pattern_plugged, sizeof(pattern_plugged) / sizeof(buzzer_step_t)}, + [BUZZER_PATTERN_UNPLUGGED] = {pattern_unplugged, sizeof(pattern_unplugged) / sizeof(buzzer_step_t)}, + [BUZZER_PATTERN_CHARGING] = {pattern_charging, sizeof(pattern_charging) / sizeof(buzzer_step_t)}, + [BUZZER_PATTERN_AP_START] = {pattern_ap_start, sizeof(pattern_ap_start) / sizeof(buzzer_step_t)}, + [BUZZER_PATTERN_CARD_READ] = {pattern_card_read, sizeof(pattern_card_read) / sizeof(buzzer_step_t)}, + [BUZZER_PATTERN_CARD_ADD] = {pattern_card_add, sizeof(pattern_card_add) / sizeof(buzzer_step_t)}, + [BUZZER_PATTERN_CARD_DENIED] = {pattern_card_denied, sizeof(pattern_card_denied) / sizeof(buzzer_step_t)}, + [BUZZER_PATTERN_FAULT] = {pattern_fault, sizeof(pattern_fault) / sizeof(buzzer_step_t)}, +}; + +// ===================== Helpers HW ===================== +static inline uint32_t duty_from_percent(uint8_t pct, ledc_timer_bit_t res) +{ + if (pct == 0) + return 0; + if (pct > 100) + pct = 100; uint32_t max = (1U << res) - 1U; return (uint32_t)((pct * max) / 100U); } -static void buzzer_on(void) { - if (s_buzzer_cfg.mode == BUZZER_MODE_PASSIVE) { - ledc_set_freq(s_buzzer_cfg.ledc_speed_mode, - s_buzzer_cfg.ledc_timer, - s_buzzer_cfg.freq_hz); - ledc_set_duty(s_buzzer_cfg.ledc_speed_mode, - s_buzzer_cfg.ledc_channel, - duty_from_percent(s_buzzer_cfg.duty_percent, s_buzzer_cfg.duty_resolution)); - ledc_update_duty(s_buzzer_cfg.ledc_speed_mode, s_buzzer_cfg.ledc_channel); - } else { +static inline bool is_pattern_valid(buzzer_pattern_id_t id) +{ + return (id > BUZZER_PATTERN_NONE && id < BUZZER_PATTERN_MAX); +} + +static void buzzer_on(void) +{ + if (s_buzzer_cfg.mode == BUZZER_MODE_PASSIVE) + { + // Não mudar freq a cada beep; já foi configurada na init. + esp_err_t err1 = ledc_set_duty(s_buzzer_cfg.ledc_speed_mode, + s_buzzer_cfg.ledc_channel, + duty_from_percent(s_buzzer_cfg.duty_percent, s_buzzer_cfg.duty_resolution)); + if (err1 != ESP_OK) + ESP_LOGW(TAG, "ledc_set_duty err=%s", esp_err_to_name(err1)); + esp_err_t err2 = ledc_update_duty(s_buzzer_cfg.ledc_speed_mode, s_buzzer_cfg.ledc_channel); + if (err2 != ESP_OK) + ESP_LOGW(TAG, "ledc_update_duty err=%s", esp_err_to_name(err2)); + } + else + { gpio_set_level(s_buzzer_cfg.gpio, 1); } } -static void buzzer_off(void) { - if (s_buzzer_cfg.mode == BUZZER_MODE_PASSIVE) { - ledc_set_duty(s_buzzer_cfg.ledc_speed_mode, s_buzzer_cfg.ledc_channel, 0); - ledc_update_duty(s_buzzer_cfg.ledc_speed_mode, s_buzzer_cfg.ledc_channel); - } else { +static void buzzer_off(void) +{ + if (s_buzzer_cfg.mode == BUZZER_MODE_PASSIVE) + { + esp_err_t err1 = ledc_set_duty(s_buzzer_cfg.ledc_speed_mode, s_buzzer_cfg.ledc_channel, 0); + if (err1 != ESP_OK) + ESP_LOGW(TAG, "ledc_set_duty(0) err=%s", esp_err_to_name(err1)); + esp_err_t err2 = ledc_update_duty(s_buzzer_cfg.ledc_speed_mode, s_buzzer_cfg.ledc_channel); + if (err2 != ESP_OK) + ESP_LOGW(TAG, "ledc_update_duty err=%s", esp_err_to_name(err2)); + } + else + { gpio_set_level(s_buzzer_cfg.gpio, 0); } } -// --- Execução de padrões --- -static void buzzer_execute(buzzer_pattern_id_t pattern_id) { - if ((int)pattern_id <= BUZZER_PATTERN_NONE || pattern_id >= BUZZER_PATTERN_MAX) { +static bool in_quiet_hours(void) +{ + if (!s_buzzer_ctl.quiet_enabled) + return false; + + time_t now = time(NULL); + struct tm lt; + if (localtime_r(&now, <) == NULL) + return false; + + uint16_t minutes = (uint16_t)(lt.tm_hour * 60 + lt.tm_min); + uint16_t start = s_buzzer_ctl.quiet_start_min; + uint16_t end = s_buzzer_ctl.quiet_end_min; + + if (start == end) + return false; // desativado + if (start < end) + { + return (minutes >= start && minutes < end); + } + else + { // janela cruza meia-noite + return (minutes >= start || minutes < end); + } +} + +// ===================== Execução do padrão (apenas dentro da task) ===================== +static void buzzer_execute(buzzer_pattern_id_t pattern_id) +{ + if (!is_pattern_valid(pattern_id)) + { ESP_LOGW(TAG, "Invalid buzzer pattern id: %d", pattern_id); return; } - ESP_LOGD(TAG, "Executing buzzer pattern ID: %d", pattern_id); const buzzer_pattern_t *pattern = &buzzer_patterns[pattern_id]; - for (size_t i = 0; i < pattern->length; i++) { + for (size_t i = 0; i < pattern->length; i++) + { buzzer_on(); vTaskDelay(pdMS_TO_TICKS(pattern->steps[i].on_ms)); buzzer_off(); - if (pattern->steps[i].off_ms > 0) { + if (pattern->steps[i].off_ms > 0) + { vTaskDelay(pdMS_TO_TICKS(pattern->steps[i].off_ms)); } } } -// --- Event Handlers --- -static void buzzer_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data) { - if (base != BUZZER_EVENTS || id != BUZZER_EVENT_PLAY_PATTERN || data == NULL) return; +// ===================== Task & Fila ===================== +static void buzzer_task(void *arg) +{ + buzzer_pattern_id_t id; + + for (;;) + { + if (xQueueReceive(s_buzzer_q, &id, portMAX_DELAY) == pdTRUE) + { + + ESP_LOGD(TAG, "dequeue pattern %d", id); // na buzzer_task() + + if (!s_buzzer_ctl.enabled) + continue; + + // Quiet hours: permitir apenas alertas críticos/negativos + if (in_quiet_hours()) + { + if (!(id == BUZZER_PATTERN_FAULT || id == BUZZER_PATTERN_CARD_DENIED)) + { + continue; + } + } + + // Anti-spam global + TickType_t now = xTaskGetTickCount(); + if ((now - s_last_play_tick) < s_min_gap_ticks) + { + continue; + } + s_last_play_tick = now; + + buzzer_execute(id); + } + } +} + +// ===================== API pública ===================== +void buzzer_play(buzzer_pattern_id_t id) +{ + + ESP_LOGD(TAG, "enqueue pattern %d", id); // dentro de buzzer_play() + + if (!is_pattern_valid(id) || s_buzzer_q == NULL) + return; + (void)xQueueSend(s_buzzer_q, &id, 0); +} + +void buzzer_stop(void) +{ + // Interrompe imediatamente: esvazia fila e desliga + if (s_buzzer_q) + xQueueReset(s_buzzer_q); + buzzer_off(); +} + +void buzzer_set_enabled(bool enabled) +{ + s_buzzer_ctl.enabled = enabled; + if (!enabled) + buzzer_off(); +} + +bool buzzer_get_enabled(void) +{ + return s_buzzer_ctl.enabled; +} + +void buzzer_set_quiet_hours(bool enabled, uint16_t start_min, uint16_t end_min) +{ + s_buzzer_ctl.quiet_enabled = enabled; + if (start_min < 1440) + s_buzzer_ctl.quiet_start_min = start_min; + if (end_min < 1440) + s_buzzer_ctl.quiet_end_min = end_min; +} + +// Opcional: mudar tom dinamicamente (apenas se o timer for exclusivo do buzzer) +esp_err_t buzzer_set_frequency(uint32_t hz) +{ + if (s_buzzer_cfg.mode != BUZZER_MODE_PASSIVE) + return ESP_ERR_INVALID_STATE; + if (hz < 50 || hz > 20000) + return ESP_ERR_INVALID_ARG; + s_buzzer_cfg.freq_hz = hz; + return ledc_set_freq(s_buzzer_cfg.ledc_speed_mode, s_buzzer_cfg.ledc_timer, hz); +} + +void buzzer_set_duty_percent(uint8_t pct) +{ + if (pct > 100) + pct = 100; + s_buzzer_cfg.duty_percent = pct; +} + +// ===================== Event Handlers ===================== +static void buzzer_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data) +{ + if (base != BUZZER_EVENTS || id != BUZZER_EVENT_PLAY_PATTERN || data == NULL) + return; buzzer_event_data_t *evt = (buzzer_event_data_t *)data; - if ((int)evt->pattern < BUZZER_PATTERN_NONE || evt->pattern >= BUZZER_PATTERN_MAX) { + if (!is_pattern_valid(evt->pattern)) + { ESP_LOGW(TAG, "Invalid buzzer pattern received: %d", evt->pattern); return; } - - buzzer_execute(evt->pattern); + buzzer_play(evt->pattern); } -static void evse_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data) { - if (base != EVSE_EVENTS || id != EVSE_EVENT_STATE_CHANGED || data == NULL) return; +static void evse_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data) +{ + if (base != EVSE_EVENTS || id != EVSE_EVENT_STATE_CHANGED || data == NULL) + return; const evse_state_event_data_t *evt = (const evse_state_event_data_t *)data; - ESP_LOGI(TAG, "EVSE event received: state = %d", evt->state); + ESP_LOGD(TAG, "EVSE event: state=%d", evt->state); buzzer_event_data_t buzzer_evt = {0}; - - switch (evt->state) { - case EVSE_STATE_EVENT_IDLE: - buzzer_evt.pattern = BUZZER_PATTERN_UNPLUGGED; - break; - case EVSE_STATE_EVENT_WAITING: - buzzer_evt.pattern = BUZZER_PATTERN_PLUGGED; - break; - case EVSE_STATE_EVENT_CHARGING: - buzzer_evt.pattern = BUZZER_PATTERN_CHARGING; - break; - case EVSE_STATE_EVENT_FAULT: - default: - return; + switch (evt->state) + { + case EVSE_STATE_EVENT_IDLE: + buzzer_evt.pattern = BUZZER_PATTERN_UNPLUGGED; + break; + case EVSE_STATE_EVENT_WAITING: + buzzer_evt.pattern = BUZZER_PATTERN_PLUGGED; + break; + case EVSE_STATE_EVENT_CHARGING: + buzzer_evt.pattern = BUZZER_PATTERN_CHARGING; + break; + case EVSE_STATE_EVENT_FAULT: + // Preempta qualquer beep em andamento + buzzer_stop(); + buzzer_evt.pattern = BUZZER_PATTERN_FAULT; + break; + default: + return; } esp_event_post(BUZZER_EVENTS, BUZZER_EVENT_PLAY_PATTERN, &buzzer_evt, sizeof(buzzer_evt), portMAX_DELAY); } -static void network_event_handler(void *handler_args, esp_event_base_t base, int32_t id, void *event_data) { - if (id == NETWORK_EVENT_AP_STARTED) { - buzzer_event_data_t evt = { - .pattern = BUZZER_PATTERN_AP_START - }; +static void network_event_handler(void *handler_args, esp_event_base_t base, int32_t id, void *event_data) +{ + if (base != NETWORK_EVENTS) + return; + if (id == NETWORK_EVENT_AP_STARTED) + { + buzzer_event_data_t evt = {.pattern = BUZZER_PATTERN_AP_START}; esp_event_post(BUZZER_EVENTS, BUZZER_EVENT_PLAY_PATTERN, &evt, sizeof(evt), portMAX_DELAY); } } -static void auth_event_handler(void *arg, esp_event_base_t base, int32_t id, void *event_data) { - if (base != AUTH_EVENTS || event_data == NULL) return; +static void auth_event_handler(void *arg, esp_event_base_t base, int32_t id, void *event_data) +{ + if (base != AUTH_EVENTS || event_data == NULL) + return; buzzer_event_data_t buzzer_evt = {0}; - if (id == AUTH_EVENT_TAG_PROCESSED) { + if (id == AUTH_EVENT_TAG_PROCESSED) + { const auth_tag_event_data_t *evt = (const auth_tag_event_data_t *)event_data; - ESP_LOGI(TAG, "AUTH processed: tag=%s authorized=%d", evt->tag, evt->authorized); + ESP_LOGD(TAG, "AUTH processed: tag=%s authorized=%d", evt->tag, evt->authorized); buzzer_evt.pattern = evt->authorized ? BUZZER_PATTERN_CARD_READ : BUZZER_PATTERN_CARD_DENIED; - } else if (id == AUTH_EVENT_TAG_SAVED) { + } + else if (id == AUTH_EVENT_TAG_SAVED) + { buzzer_evt.pattern = BUZZER_PATTERN_CARD_ADD; - } else { + } + else + { return; } esp_event_post(BUZZER_EVENTS, BUZZER_EVENT_PLAY_PATTERN, &buzzer_evt, sizeof(buzzer_evt), portMAX_DELAY); } -// --- Inicialização --- -void buzzer_init(void) { - if (s_buzzer_cfg.mode == BUZZER_MODE_PASSIVE) { - // Configura temporizador do PWM +// ===================== Inicialização / Deinit ===================== +void buzzer_init(void) +{ + // Config HW + if (s_buzzer_cfg.mode == BUZZER_MODE_PASSIVE) + { ledc_timer_config_t tcfg = { .speed_mode = s_buzzer_cfg.ledc_speed_mode, .duty_resolution = s_buzzer_cfg.duty_resolution, .timer_num = s_buzzer_cfg.ledc_timer, .freq_hz = s_buzzer_cfg.freq_hz, - .clk_cfg = LEDC_AUTO_CLK - }; + .clk_cfg = LEDC_AUTO_CLK}; ESP_ERROR_CHECK(ledc_timer_config(&tcfg)); - // Configura canal PWM ledc_channel_config_t ccfg = { .gpio_num = s_buzzer_cfg.gpio, .speed_mode = s_buzzer_cfg.ledc_speed_mode, @@ -207,45 +468,74 @@ void buzzer_init(void) { .intr_type = LEDC_INTR_DISABLE, .timer_sel = s_buzzer_cfg.ledc_timer, .duty = 0, - .hpoint = 0 - }; + .hpoint = 0}; ESP_ERROR_CHECK(ledc_channel_config(&ccfg)); - } else { + } + else + { gpio_config_t io = { .pin_bit_mask = (1ULL << s_buzzer_cfg.gpio), .mode = GPIO_MODE_OUTPUT, .pull_down_en = 0, .pull_up_en = 0, - .intr_type = GPIO_INTR_DISABLE - }; - gpio_config(&io); + .intr_type = GPIO_INTR_DISABLE}; + ESP_ERROR_CHECK(gpio_config(&io)); + gpio_set_level(s_buzzer_cfg.gpio, 0); } + buzzer_set_quiet_hours(false, 0, 0); + buzzer_set_enabled(true); + buzzer_off(); - // Registro de handlers - ESP_ERROR_CHECK(esp_event_handler_register(BUZZER_EVENTS, - BUZZER_EVENT_PLAY_PATTERN, - buzzer_event_handler, - NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(EVSE_EVENTS, - EVSE_EVENT_STATE_CHANGED, - evse_event_handler, - NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(AUTH_EVENTS, - AUTH_EVENT_TAG_PROCESSED, - auth_event_handler, - NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(AUTH_EVENTS, - AUTH_EVENT_TAG_SAVED, - auth_event_handler, - NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(NETWORK_EVENTS, - NETWORK_EVENT_AP_STARTED, - network_event_handler, - NULL)); + // Fila + Task + s_buzzer_q = xQueueCreate(CONFIG_BUZZER_QUEUE_LEN, sizeof(buzzer_pattern_id_t)); + configASSERT(s_buzzer_q != NULL); + BaseType_t ok = xTaskCreatePinnedToCore( + buzzer_task, + "buzzer_task", + CONFIG_BUZZER_TASK_STACK, + NULL, + CONFIG_BUZZER_TASK_PRIO, + &s_buzzer_task, + tskNO_AFFINITY); + configASSERT(ok == pdPASS); - ESP_LOGI(TAG, "Buzzer initialized on GPIO %d (%s)", + // Handlers + ESP_ERROR_CHECK(esp_event_handler_register(BUZZER_EVENTS, BUZZER_EVENT_PLAY_PATTERN, buzzer_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(EVSE_EVENTS, EVSE_EVENT_STATE_CHANGED, evse_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(AUTH_EVENTS, AUTH_EVENT_TAG_PROCESSED, auth_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(AUTH_EVENTS, AUTH_EVENT_TAG_SAVED, auth_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(NETWORK_EVENTS, NETWORK_EVENT_AP_STARTED, network_event_handler, NULL)); + + ESP_LOGI(TAG, "Buzzer initialized on GPIO %d (%s), freq=%lu Hz, duty=%u%%, enabled=%d", s_buzzer_cfg.gpio, - s_buzzer_cfg.mode == BUZZER_MODE_PASSIVE ? "passive/PWM" : "active/ON-OFF"); + s_buzzer_cfg.mode == BUZZER_MODE_PASSIVE ? "passive/PWM" : "active/ON-OFF", + (unsigned long)s_buzzer_cfg.freq_hz, + (unsigned)s_buzzer_cfg.duty_percent, + (int)s_buzzer_ctl.enabled); +} + +void buzzer_deinit(void) +{ + (void)esp_event_handler_unregister(BUZZER_EVENTS, BUZZER_EVENT_PLAY_PATTERN, buzzer_event_handler); + (void)esp_event_handler_unregister(EVSE_EVENTS, EVSE_EVENT_STATE_CHANGED, evse_event_handler); + (void)esp_event_handler_unregister(AUTH_EVENTS, AUTH_EVENT_TAG_PROCESSED, auth_event_handler); + (void)esp_event_handler_unregister(AUTH_EVENTS, AUTH_EVENT_TAG_SAVED, auth_event_handler); + (void)esp_event_handler_unregister(NETWORK_EVENTS, NETWORK_EVENT_AP_STARTED, network_event_handler); + + if (s_buzzer_q) + { + vQueueDelete(s_buzzer_q); + s_buzzer_q = NULL; + } + + if (s_buzzer_task) + { + vTaskDelete(s_buzzer_task); + s_buzzer_task = NULL; + } + + buzzer_off(); + ESP_LOGI(TAG, "Buzzer deinitialized"); } diff --git a/components/evse/evse_manager.c b/components/evse/evse_manager.c index 5aeb10e..641ce59 100755 --- a/components/evse/evse_manager.c +++ b/components/evse/evse_manager.c @@ -1,3 +1,4 @@ +// === Início de: components/evse/evse_manager.c === #include "evse_manager.h" #include "evse_state.h" #include "evse_error.h" @@ -14,6 +15,7 @@ #include "freertos/queue.h" #include "esp_log.h" #include +#include #include "auth_events.h" #include "loadbalancer_events.h" @@ -25,8 +27,46 @@ static const char *TAG = "EVSE_Manager"; static SemaphoreHandle_t evse_mutex; static bool auth_enabled = false; +// Estado de pausa controlado pelo Load Balancer +static bool lb_paused = false; +static bool lb_prev_authorized = false; + #define EVSE_MANAGER_TICK_PERIOD_MS 1000 // 1 segundo +// ================= Helpers internos ================= + +static void lb_clear_pause_state(void) +{ + lb_paused = false; + lb_prev_authorized = false; +} + +static void evse_manager_handle_auth_on_tick(void) +{ + if (auth_enabled) + { + // Se o carro foi desconectado, revoga autorização + if (evse_state_get_authorized() && evse_get_state() == EVSE_STATE_A) + { + ESP_LOGI(TAG, "Vehicle disconnected → revoking authorization."); + evse_state_set_authorized(false); + // Desconexão física invalida qualquer pausa pendente do LB + lb_clear_pause_state(); + } + } + else + { + // Se autenticação está desativada, garante autorização sempre ativa + if (!evse_state_get_authorized()) + { + evse_state_set_authorized(true); + ESP_LOGI(TAG, "Authentication disabled → forced authorization."); + // Em modo OPEN, pausa do LB não é tão relevante, mas limpamos mesmo assim + lb_clear_pause_state(); + } + } +} + // ===== Task de ciclo principal ===== static void evse_manager_task(void *arg) { @@ -51,6 +91,9 @@ static void on_auth_event(void *arg, esp_event_base_t base, int32_t id, void *da const auth_tag_event_data_t *evt = (const auth_tag_event_data_t *)data; ESP_LOGI(TAG, "Tag %s -> %s", evt->tag, evt->authorized ? "AUTHORIZED" : "DENIED"); evse_state_set_authorized(evt->authorized); + + // Qualquer alteração explícita de auth invalida pausa do LB + lb_clear_pause_state(); break; } @@ -70,6 +113,9 @@ static void on_auth_event(void *arg, esp_event_base_t base, int32_t id, void *da evse_state_set_authorized(false); auth_enabled = true; } + + // Modo mudou -> qualquer pausa antiga deixa de fazer sentido + lb_clear_pause_state(); break; } } @@ -83,14 +129,96 @@ static void on_loadbalancer_event(void *handler_arg, esp_event_base_t event_base { const loadbalancer_state_event_t *evt = (const loadbalancer_state_event_t *)event_data; ESP_LOGI(TAG, "Loadbalancer %s (ts: %lld)", - evt->enabled ? "ENABLED" : "DISABLED", evt->timestamp_us); + evt->enabled ? "ENABLED" : "DISABLED", + (long long)evt->timestamp_us); // Ações adicionais podem ser adicionadas aqui conforme necessário } else if (event_id == LOADBALANCER_EVENT_MASTER_CURRENT_LIMIT) { - const loadbalancer_master_limit_event_t *evt = (const loadbalancer_master_limit_event_t *)event_data; - ESP_LOGI(TAG, "Novo limite de corrente (master): %u A (ts: %lld)", evt->max_current, evt->timestamp_us); - evse_set_runtime_charging_current(evt->max_current); + const loadbalancer_master_limit_event_t *evt = + (const loadbalancer_master_limit_event_t *)event_data; + + ESP_LOGI(TAG, + "Novo limite de corrente (master): %u A (ts: %lld)", + evt->max_current, (long long)evt->timestamp_us); + + if (evt->max_current == 0) + { + // Suspensão por LB (não interessa se é OPEN ou RFID/OCPP) + lb_paused = true; + lb_prev_authorized = evse_state_get_authorized(); + + if (lb_prev_authorized) + { + ESP_LOGI(TAG, "[LB] limit=0A → pausando sessão (authorized=false)"); + evse_state_set_authorized(false); + } + else + { + ESP_LOGD(TAG, "[LB] limit=0A → já não estava autorizado"); + } + } + else + { + // Ajusta corrente em runtime + evse_set_runtime_charging_current(evt->max_current); + + if (lb_paused) + { + lb_paused = false; + + // Só retomamos se EVSE estiver operacional + bool can_resume = + (evse_get_error() == 0) && + evse_config_is_available() && + evse_config_is_enabled(); + + if (!can_resume) + { + ESP_LOGW(TAG, + "[LB] limit=%uA → não retoma automaticamente (erro/indisponível/desabilitado)", + evt->max_current); + lb_clear_pause_state(); + return; + } + + if (!auth_enabled) + { + // Modo OPEN: retoma sempre + ESP_LOGI(TAG, + "[LB] limit=%uA → modo OPEN, reautorizando (authorized=true)", + evt->max_current); + evse_state_set_authorized(true); + } + else + { + // RFID/OCPP: só retoma se havia autorização antes da pausa + if (lb_prev_authorized) + { + ESP_LOGI(TAG, + "[LB] limit=%uA → RFID/OCPP, retomando autorização anterior (auto-resume)", + evt->max_current); + evse_state_set_authorized(true); + } + else + { + ESP_LOGI(TAG, + "[LB] limit=%uA → RFID/OCPP, sem autorização prévia, mantendo estado atual", + evt->max_current); + } + } + + // Limpa estado prévio (não reaplicar em pausas futuras) + lb_prev_authorized = false; + } + else + { + // Caso normal: apenas ajuste de corrente, sem mexer em auth + ESP_LOGD(TAG, + "[LB] limit=%uA → ajustando corrente runtime (sem mudança de autorização)", + evt->max_current); + } + } } } @@ -104,38 +232,46 @@ static void on_ocpp_event(void *arg, esp_event_base_t base, int32_t id, void *da case OCPP_EVENT_AUTHORIZED: ESP_LOGI(TAG, "[OCPP] Authorized"); evse_state_set_authorized(true); + lb_clear_pause_state(); break; case OCPP_EVENT_AUTH_REJECTED: ESP_LOGW(TAG, "[OCPP] Authorization rejected"); evse_state_set_authorized(false); + lb_clear_pause_state(); break; case OCPP_EVENT_AUTH_TIMEOUT: ESP_LOGW(TAG, "[OCPP] Authorization timeout"); evse_state_set_authorized(false); + lb_clear_pause_state(); break; case OCPP_EVENT_REMOTE_START: ESP_LOGI(TAG, "[OCPP] RemoteStart"); evse_state_set_authorized(true); + lb_clear_pause_state(); break; case OCPP_EVENT_REMOTE_STOP: ESP_LOGI(TAG, "[OCPP] RemoteStop"); evse_state_set_authorized(false); + lb_clear_pause_state(); break; case OCPP_EVENT_START_TX: ESP_LOGI(TAG, "[OCPP] StartTx"); + // StartTx em si não precisa mexer em auth, mas limpamos estado de pausa por segurança + lb_clear_pause_state(); break; case OCPP_EVENT_STOP_TX: ESP_LOGI(TAG, "[OCPP] StopTx"); evse_state_set_authorized(false); + lb_clear_pause_state(); break; - // hegou ChangeAvailability remoto (operative/inoperative) + // ChangeAvailability remoto (operative/inoperative) case OCPP_EVENT_OPERATIVE_UPDATED: { if (!data) @@ -149,6 +285,8 @@ static void on_ocpp_event(void *arg, esp_event_base_t base, int32_t id, void *da // Mapear operative → enabled local (persiste e emite EVSE_EVENT_ENABLE_UPDATED) evse_config_set_enabled(ev->operative); + // Opcional: poderias também limpar a pausa aqui, dependendo da política + // lb_clear_pause_state(); break; } @@ -172,7 +310,7 @@ void evse_manager_init(void) ESP_ERROR_CHECK(esp_event_handler_register(AUTH_EVENTS, ESP_EVENT_ANY_ID, &on_auth_event, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(LOADBALANCER_EVENTS, ESP_EVENT_ANY_ID, &on_loadbalancer_event, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(OCPP_EVENTS, ESP_EVENT_ANY_ID, &on_ocpp_event, NULL)); // <— AQUI + ESP_ERROR_CHECK(esp_event_handler_register(OCPP_EVENTS, ESP_EVENT_ANY_ID, &on_ocpp_event, NULL)); ESP_LOGI(TAG, "EVSE Manager inicializado."); xTaskCreate(evse_manager_task, "evse_manager_task", 4096, NULL, 5, NULL); @@ -189,24 +327,8 @@ void evse_manager_tick(void) evse_temperature_check(); evse_session_tick(); - if (auth_enabled) - { - // If the car is disconnected, revoke authorization - if (evse_state_get_authorized() && evse_get_state() == EVSE_STATE_A) - { - ESP_LOGI(TAG, "Vehicle disconnected → revoking authorization."); - evse_state_set_authorized(false); - } - } - else - { - // If authentication is disabled, ensure authorization is always granted - if (!evse_state_get_authorized()) - { - evse_state_set_authorized(true); - ESP_LOGI(TAG, "Authentication disabled → forced authorization."); - } - } + evse_manager_handle_auth_on_tick(); xSemaphoreGive(evse_mutex); } +// === Fim de: components/evse/evse_manager.c === diff --git a/components/evse/evse_meter.c b/components/evse/evse_meter.c index 8764695..1f88475 100644 --- a/components/evse/evse_meter.c +++ b/components/evse/evse_meter.c @@ -45,7 +45,7 @@ void evse_meter_on_meter_event(void *arg, void *event_data) meter_data.voltage[i] = evt->vrms[i]; meter_data.current[i] = evt->irms[i]; } - meter_data.energy_wh = (uint32_t)(evt->total_energy * 1000.0f); + meter_data.energy_wh = (uint32_t)(evt->total_energy); xSemaphoreGive(meter_mutex); ESP_LOGI(TAG, diff --git a/components/loadbalancer/src/loadbalancer.c b/components/loadbalancer/src/loadbalancer.c index 44f663b..4be381f 100755 --- a/components/loadbalancer/src/loadbalancer.c +++ b/components/loadbalancer/src/loadbalancer.c @@ -4,6 +4,7 @@ #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "freertos/semphr.h" #include "input_filter.h" #include "nvs_flash.h" #include "nvs.h" @@ -25,6 +26,16 @@ static const char *TAG = "loadbalancer"; #define MIN_GRID_CURRENT_LIMIT 6 // A #define MAX_GRID_CURRENT_LIMIT 100 // A +// Pequena tolerância para considerar "sem margem" +#define AVAILABLE_EPS 1.0f + +// Histerese de suspensão / retoma (em torno dos 6A) +#define LB_SUSPEND_THRESHOLD 5.0f // abaixo disto -> suspende +#define LB_RESUME_THRESHOLD 7.0f // acima disto -> pode retomar + +// Timeout para perda de medição de GRID (fail-safe) +#define GRID_METER_TIMEOUT_US (10LL * 1000000LL) // 30 segundos + // Parâmetros static uint8_t max_grid_current = MAX_GRID_CURRENT_LIMIT; static bool loadbalancer_enabled = false; @@ -34,9 +45,14 @@ static float evse_current = 0.0f; static input_filter_t grid_filter; static input_filter_t evse_filter; +static int64_t last_grid_timestamp_us = 0; // última atualização de medição GRID + #define MAX_SLAVES 255 #define CONNECTOR_COUNT (MAX_SLAVES + 1) +// Proteção simples de concorrência +static SemaphoreHandle_t lb_mutex = NULL; + // Estrutura unificada para master e slaves typedef struct { @@ -45,9 +61,12 @@ typedef struct bool charging; float hw_max_current; float runtime_current; - int64_t timestamp; // microssegundos + int64_t timestamp; // microssegundos (última métrica EVSE/slave) bool online; - float assigned; + float assigned; // limite calculado pelo LB + int64_t started_us; // início da sessão de carregamento (para prioridade) + uint16_t last_limit; // último max_current enviado + bool suspended_by_lb; // flag de suspensão por LB (para histerese) } evse_connector_t; static evse_connector_t connectors[CONNECTOR_COUNT]; @@ -66,7 +85,11 @@ static void init_connectors(void) .runtime_current = 0, .timestamp = 0, .online = false, - .assigned = 0.0f}; + .assigned = 0.0f, + .started_us = 0, + .last_limit = 0, + .suspended_by_lb = false}; + // slaves em 1..CONNECTOR_COUNT-1 for (int i = 1; i < CONNECTOR_COUNT; i++) { @@ -78,7 +101,10 @@ static void init_connectors(void) .runtime_current = 0.0f, .timestamp = 0, .online = false, - .assigned = 0.0f}; + .assigned = 0.0f, + .started_us = 0, + .last_limit = 0, + .suspended_by_lb = false}; } } @@ -100,12 +126,30 @@ static void on_slave_status(void *handler_arg, esp_event_base_t base, int32_t id } int idx = status->slave_id + 1; // slaves começam no índice 1 + + bool was_charging; + + if (lb_mutex) + xSemaphoreTake(lb_mutex, portMAX_DELAY); + + was_charging = connectors[idx].charging; + connectors[idx].charging = status->charging; connectors[idx].hw_max_current = status->hw_max_current; connectors[idx].runtime_current = status->runtime_current; connectors[idx].timestamp = esp_timer_get_time(); connectors[idx].online = true; + // Se começou agora a carregar, marca início da sessão + if (status->charging && !was_charging) + { + connectors[idx].started_us = connectors[idx].timestamp; + connectors[idx].suspended_by_lb = false; // reset + } + + if (lb_mutex) + xSemaphoreGive(lb_mutex); + ESP_LOGI(TAG, "Slave %d status: charging=%d hw_max_current=%.1fA runtime_current=%.2fA", status->slave_id, status->charging, @@ -120,33 +164,62 @@ static void on_evse_config_event(void *handler_arg, const evse_config_event_data_t *evt = (const evse_config_event_data_t *)event_data; int idx = 0; // MASTER INDICE 0 + + if (lb_mutex) + xSemaphoreTake(lb_mutex, portMAX_DELAY); + connectors[idx].charging = evt->charging; connectors[idx].hw_max_current = evt->hw_max_current; connectors[idx].runtime_current = evt->runtime_current; connectors[idx].timestamp = esp_timer_get_time(); connectors[idx].online = true; + if (!evt->charging) + { + connectors[idx].suspended_by_lb = false; + } + + if (lb_mutex) + xSemaphoreGive(lb_mutex); + ESP_LOGI(TAG, "EVSE config updated: charging=%d hw_max_current=%.1f runtime_current=%.1f", evt->charging, evt->hw_max_current, evt->runtime_current); } // --- Handlers de eventos externos --- -static void loadbalancer_meter_event_handler(void *handler_arg, - esp_event_base_t base, - int32_t id, - void *event_data) +static void loadbalancer_meter_event_handler(void *handler_arg, esp_event_base_t base, int32_t id, void *event_data) { if (id != METER_EVENT_DATA_READY || event_data == NULL) return; + const meter_event_data_t *evt = (const meter_event_data_t *)event_data; float max_irms = evt->irms[0]; for (int i = 1; i < 3; ++i) + { if (evt->irms[i] > max_irms) + { max_irms = evt->irms[i]; + } + } + + float max_vrms = evt->vrms[0]; + for (int i = 1; i < 3; ++i) + { + if (evt->vrms[i] > max_vrms) + { + max_vrms = evt->vrms[i]; + } + } + + if (lb_mutex) + xSemaphoreTake(lb_mutex, portMAX_DELAY); + if (evt->source && strcmp(evt->source, "GRID") == 0) { grid_current = input_filter_update(&grid_filter, max_irms); + last_grid_timestamp_us = esp_timer_get_time(); ESP_LOGI(TAG, "GRID IRMS (filtered): %.2f A", grid_current); + ESP_LOGI(TAG, "GRID VRMS: %.2f V", max_vrms); } else if (evt->source && strcmp(evt->source, "EVSE") == 0) { @@ -157,6 +230,9 @@ static void loadbalancer_meter_event_handler(void *handler_arg, { ESP_LOGW(TAG, "Unknown meter event source: %s", evt->source); } + + if (lb_mutex) + xSemaphoreGive(lb_mutex); } static void loadbalancer_evse_event_handler(void *handler_arg, @@ -166,6 +242,9 @@ static void loadbalancer_evse_event_handler(void *handler_arg, { const evse_state_event_data_t *evt = (const evse_state_event_data_t *)event_data; + if (lb_mutex) + xSemaphoreTake(lb_mutex, portMAX_DELAY); + switch (evt->state) { case EVSE_STATE_EVENT_IDLE: @@ -175,29 +254,45 @@ static void loadbalancer_evse_event_handler(void *handler_arg, evt->state == EVSE_STATE_EVENT_IDLE ? "dis" : ""); connectors[0].charging = false; connectors[0].online = true; // master está sempre online + connectors[0].suspended_by_lb = false; break; case EVSE_STATE_EVENT_CHARGING: + { ESP_LOGI(TAG, "Local EVSE is CHARGING - resetting filters"); grid_current = 0.0f; evse_current = 0.0f; input_filter_reset(&grid_filter); input_filter_reset(&evse_filter); + + bool was_charging = connectors[0].charging; + connectors[0].charging = true; connectors[0].online = true; connectors[0].timestamp = esp_timer_get_time(); + + if (!was_charging) + { + connectors[0].started_us = connectors[0].timestamp; + connectors[0].suspended_by_lb = false; + } break; + } case EVSE_STATE_EVENT_FAULT: ESP_LOGW(TAG, "Local EVSE is in FAULT state - disabling load balancing temporarily"); connectors[0].charging = false; connectors[0].online = true; // EVSE está online mas com falha + connectors[0].suspended_by_lb = false; break; default: ESP_LOGW(TAG, "Unknown EVSE state: %d", evt->state); break; } + + if (lb_mutex) + xSemaphoreGive(lb_mutex); } // --- Config persistência --- @@ -207,8 +302,10 @@ static esp_err_t loadbalancer_load_config() esp_err_t err = nvs_open("loadbalancing", NVS_READWRITE, &handle); if (err != ESP_OK) return err; + bool needs_commit = false; uint8_t temp_u8; + err = nvs_get_u8(handle, "max_grid_curr", &temp_u8); if (err == ESP_OK && temp_u8 >= MIN_GRID_CURRENT_LIMIT && temp_u8 <= MAX_GRID_CURRENT_LIMIT) max_grid_current = temp_u8; @@ -218,6 +315,7 @@ static esp_err_t loadbalancer_load_config() nvs_set_u8(handle, "max_grid_curr", max_grid_current); needs_commit = true; } + err = nvs_get_u8(handle, "enabled", &temp_u8); if (err == ESP_OK && temp_u8 <= 1) loadbalancer_enabled = (temp_u8 != 0); @@ -227,6 +325,7 @@ static esp_err_t loadbalancer_load_config() nvs_set_u8(handle, "enabled", 0); needs_commit = true; } + if (needs_commit) nvs_commit(handle); nvs_close(handle); @@ -280,7 +379,7 @@ void loadbalancer_task(void *param) { if (!loadbalancer_is_enabled()) { - vTaskDelay(pdMS_TO_TICKS(5000)); + vTaskDelay(pdMS_TO_TICKS(30000)); continue; } @@ -289,9 +388,11 @@ void loadbalancer_task(void *param) int64_t now = esp_timer_get_time(); // --- Atualiza estado online e conta ativos --- + if (lb_mutex) + xSemaphoreTake(lb_mutex, portMAX_DELAY); + for (int i = 0; i < CONNECTOR_COUNT; i++) { - // --- Master nunca pode ficar offline --- if (connectors[i].is_master) { @@ -334,79 +435,312 @@ void loadbalancer_task(void *param) } } + // snapshot de grid_current e last_grid_timestamp sob mutex + float grid_snapshot = grid_current; + int64_t last_grid_ts_snapshot = last_grid_timestamp_us; + + if (lb_mutex) + xSemaphoreGive(lb_mutex); + ESP_LOGI(TAG, "Active connectors: %d", active_cnt); - // --- Calcula corrente disponível --- - float available = max_grid_current - grid_current; - if (available < MIN_CHARGING_CURRENT_LIMIT) + if (active_cnt == 0) { - available = MIN_CHARGING_CURRENT_LIMIT; + vTaskDelay(pdMS_TO_TICKS(5000)); + continue; } - else if (available > max_grid_current) - { - available = max_grid_current; - } - ESP_LOGI(TAG, "LB Calc: available=%.1fA, active_connectors=%d", available, active_cnt); - // --- Ordena conectores por hw_max_current (bubble sort simples) --- - for (int a = 0; a < active_cnt - 1; a++) + // --- Verifica timeout de medição de GRID (fail-safe) --- + bool meter_timeout = (last_grid_ts_snapshot == 0 || + (now - last_grid_ts_snapshot) > GRID_METER_TIMEOUT_US); + + if (meter_timeout) { - for (int b = 0; b < active_cnt - 1 - a; b++) + ESP_LOGW(TAG, + "GRID meter timeout (last update=%lld us ago). Applying fail-safe limits (<=%dA).", + (long long)(now - last_grid_ts_snapshot), MIN_CHARGING_CURRENT_LIMIT); + + if (lb_mutex) + xSemaphoreTake(lb_mutex, portMAX_DELAY); + + // Fail-safe: limitar cada EV ao mínimo permitido (6A) ou menos, nunca aumentar + for (int k = 0; k < active_cnt; k++) { - if (connectors[idxs[b]].hw_max_current > connectors[idxs[b + 1]].hw_max_current) + int i = idxs[k]; + float cur = connectors[i].runtime_current; + if (cur > MIN_CHARGING_CURRENT_LIMIT) + connectors[i].assigned = (float)MIN_CHARGING_CURRENT_LIMIT; + else + connectors[i].assigned = cur; + } + + if (lb_mutex) + xSemaphoreGive(lb_mutex); + } + + // --- Calcula corrente disponível (headroom global) --- + float available = (float)max_grid_current - grid_snapshot; + ESP_LOGI(TAG, "LB raw headroom: max_grid=%uA, grid_current=%.1fA, available=%.2fA", + max_grid_current, grid_snapshot, available); + + // ========================== + // ZONA A: overload significativo -> reduzir correntes (throttling) + // ========================== + if (available < -AVAILABLE_EPS) + { + ESP_LOGW(TAG, "Overload: grid=%.1fA, max=%.1fA (available=%.2fA) -> throttling", + grid_snapshot, (float)max_grid_current, available); + + float factor = ((float)max_grid_current) / grid_snapshot; + if (factor < 0.0f) + factor = 0.0f; + if (factor > 1.0f) + factor = 1.0f; + + if (lb_mutex) + xSemaphoreTake(lb_mutex, portMAX_DELAY); + + for (int k = 0; k < active_cnt; k++) + { + int i = idxs[k]; + connectors[i].assigned = connectors[i].runtime_current * factor; + ESP_LOGI(TAG, + "Connector[%d] overload throttling: runtime=%.1fA -> assigned=%.1fA", + i, connectors[i].runtime_current, connectors[i].assigned); + } + + if (lb_mutex) + xSemaphoreGive(lb_mutex); + } + // ========================== + // ZONA B: sem margem prática -> manter correntes atuais como limites + // ========================== + else if (fabsf(available) <= AVAILABLE_EPS) + { + ESP_LOGI(TAG, + "No effective headroom: grid=%.1fA, max=%.1fA (available=%.2fA). Keeping current as limit.", + grid_snapshot, (float)max_grid_current, available); + + if (lb_mutex) + xSemaphoreTake(lb_mutex, portMAX_DELAY); + + for (int k = 0; k < active_cnt; k++) + { + int i = idxs[k]; + connectors[i].assigned = connectors[i].runtime_current; + ESP_LOGI(TAG, + "Connector[%d] keep runtime as limit: assigned=%.1fA", + i, connectors[i].assigned); + } + + if (lb_mutex) + xSemaphoreGive(lb_mutex); + } + // ========================== + // ZONA C: há margem positiva -> garantir mínimo e depois water-filling SOBRE assigned + // ========================== + else // available > AVAILABLE_EPS + { + if (available > max_grid_current) + { + available = (float)max_grid_current; + } + + ESP_LOGI(TAG, "LB Calc (zone C): available=%.1fA, active_connectors=%d", + available, active_cnt); + + if (lb_mutex) + xSemaphoreTake(lb_mutex, portMAX_DELAY); + + // 1) Ordenar conectores ativos por started_us (mais antigos primeiro) + for (int a = 0; a < active_cnt - 1; a++) + { + for (int b = 0; b < active_cnt - 1 - a; b++) { - int tmp = idxs[b]; - idxs[b] = idxs[b + 1]; - idxs[b + 1] = tmp; + int i1 = idxs[b]; + int i2 = idxs[b + 1]; + if (connectors[i1].started_us > connectors[i2].started_us) + { + int tmp = idxs[b]; + idxs[b] = idxs[b + 1]; + idxs[b + 1] = tmp; + } } } + + // Inicialmente: assigned = runtime_current + for (int k = 0; k < active_cnt; k++) + { + int i = idxs[k]; + connectors[i].assigned = connectors[i].runtime_current; + } + + float remaining = available; // margem extra total + + // 2) FASE 1: tentar garantir pelo menos 6A (ou hw_max, se menor) aos mais antigos + for (int k = 0; k < active_cnt && remaining > 0.0f; k++) + { + int i = idxs[k]; + + float current = connectors[i].runtime_current; + float hw_max = connectors[i].hw_max_current; + + float target_min = (float)MIN_CHARGING_CURRENT_LIMIT; + if (hw_max < target_min) + target_min = hw_max; + + if (current >= target_min) + { + connectors[i].assigned = current; + continue; + } + + float delta = target_min - current; + if (delta <= remaining) + { + connectors[i].assigned = current + delta; + remaining -= delta; + } + else + { + connectors[i].assigned = current; + } + } + + // 3) FASE 2: "last in, first cut" -> cortar quem ficou abaixo do mínimo começando pelos mais recentes + for (int k = active_cnt - 1; k >= 0; k--) + { + int i = idxs[k]; + if (connectors[i].assigned >= MIN_CHARGING_CURRENT_LIMIT) + { + continue; + } + + ESP_LOGI(TAG, "Connector[%d] below min after phase1 (assigned=%.1fA) -> suspending (0A)", + i, connectors[i].assigned); + connectors[i].assigned = 0.0f; + connectors[i].suspended_by_lb = true; + } + + // 4) FASE 3: se ainda sobrar margem, distribuir extra por cima dos que ficaram ON (assigned > 0) + if (remaining > AVAILABLE_EPS) + { + int on_cnt = 0; + for (int k = 0; k < active_cnt; k++) + { + int i = idxs[k]; + if (connectors[i].assigned > 0.0f) + on_cnt++; + } + + float extra_remaining = remaining; + int extra_cnt = on_cnt; + + for (int k = 0; k < active_cnt; k++) + { + int i = idxs[k]; + + if (connectors[i].assigned <= 0.0f) + continue; + + if (extra_cnt <= 0 || extra_remaining <= 0.0f) + break; + + float headroom = connectors[i].hw_max_current - connectors[i].assigned; + if (headroom <= 0.0f) + { + extra_cnt--; + continue; + } + + float share = extra_remaining / (float)extra_cnt; + + if (share >= headroom) + { + connectors[i].assigned += headroom; + extra_remaining -= headroom; + extra_cnt--; + } + else + { + for (int m = k; m < active_cnt; m++) + { + int j = idxs[m]; + + if (connectors[j].assigned <= 0.0f) + continue; + + float headroom_j = connectors[j].hw_max_current - connectors[j].assigned; + if (headroom_j <= 0.0f) + continue; + + float inc = MIN(share, headroom_j); + connectors[j].assigned += inc; + } + break; + } + } + } + + if (lb_mutex) + xSemaphoreGive(lb_mutex); } - // --- Distribui corrente (water-filling) --- - float remaining = available; - int remaining_cnt = active_cnt; + // --- Publicação de limites / suspensão com histerese --- + if (lb_mutex) + xSemaphoreTake(lb_mutex, portMAX_DELAY); + for (int k = 0; k < active_cnt; k++) { int i = idxs[k]; - float share = remaining / remaining_cnt; - if (share >= connectors[i].hw_max_current) + float assigned = connectors[i].assigned; + float effective = assigned; + + // Histerese de suspensão / retoma + if (connectors[i].suspended_by_lb) { - connectors[i].assigned = connectors[i].hw_max_current; - remaining -= connectors[i].assigned; - remaining_cnt--; + // Está suspenso: só retoma se limite calculado for >= limiar de retoma + if (assigned >= LB_RESUME_THRESHOLD) + { + effective = assigned; + connectors[i].suspended_by_lb = false; + } + else + { + effective = 0.0f; + } } else { - for (int m = k; m < active_cnt; m++) + // Ainda não está suspenso: só suspende se ficar claramente abaixo do limiar + if (assigned > 0.0f && assigned < LB_SUSPEND_THRESHOLD) { - connectors[idxs[m]].assigned = share; + effective = 0.0f; + connectors[i].suspended_by_lb = true; } - break; } - } - // --- Aplica piso mínimo --- - for (int k = 0; k < active_cnt; k++) - { - int i = idxs[k]; - if (connectors[i].assigned < MIN_CHARGING_CURRENT_LIMIT) + uint16_t max_cur; + if (effective <= 0.0f) { - connectors[i].assigned = MIN_CHARGING_CURRENT_LIMIT; + max_cur = 0; + } + else + { + max_cur = (uint16_t)MIN(effective, (float)MAX_CHARGING_CURRENT_LIMIT); } - } - // --- Publica limites de corrente --- - for (int k = 0; k < active_cnt; k++) - { - int i = idxs[k]; - uint16_t max_cur = (uint16_t)MIN(connectors[i].assigned, MAX_CHARGING_CURRENT_LIMIT); - uint16_t current_rounded = (uint16_t)roundf(connectors[i].runtime_current); - - if (current_rounded == max_cur) + // Evita flapping de comandos: só envia se o limite mudou + if (connectors[i].last_limit == max_cur) { continue; // sem alteração } + connectors[i].last_limit = max_cur; + + if (lb_mutex) + xSemaphoreGive(lb_mutex); + if (connectors[i].is_master) { loadbalancer_master_limit_event_t master_evt = { @@ -415,8 +749,8 @@ void loadbalancer_task(void *param) .timestamp_us = now}; esp_event_post(LOADBALANCER_EVENTS, LOADBALANCER_EVENT_MASTER_CURRENT_LIMIT, &master_evt, sizeof(master_evt), portMAX_DELAY); - ESP_LOGI(TAG, "Master limit changed -> %.1f A (runtime=%.1f A)", - (float)max_cur, connectors[i].runtime_current); + ESP_LOGI(TAG, "Master limit changed -> %.1f A (assigned=%.2f A)", + (float)max_cur, assigned); } else { @@ -426,11 +760,17 @@ void loadbalancer_task(void *param) .timestamp_us = now}; esp_event_post(LOADBALANCER_EVENTS, LOADBALANCER_EVENT_SLAVE_CURRENT_LIMIT, &slave_evt, sizeof(slave_evt), portMAX_DELAY); - ESP_LOGI(TAG, "Slave %d limit changed -> %.1f A (runtime=%.1f A)", - connectors[i].id, (float)max_cur, connectors[i].runtime_current); + ESP_LOGI(TAG, "Slave %d limit changed -> %.1f A (assigned=%.2f A)", + connectors[i].id, (float)max_cur, assigned); } + + if (lb_mutex) + xSemaphoreTake(lb_mutex, portMAX_DELAY); } + if (lb_mutex) + xSemaphoreGive(lb_mutex); + vTaskDelay(pdMS_TO_TICKS(5000)); } } @@ -441,6 +781,12 @@ void loadbalancer_init(void) if (loadbalancer_load_config() != ESP_OK) ESP_LOGW(TAG, "Failed to load/init config. Using defaults."); + lb_mutex = xSemaphoreCreateMutex(); + if (lb_mutex == NULL) + { + ESP_LOGE(TAG, "Failed to create loadbalancer mutex"); + } + init_connectors(); input_filter_init(&grid_filter, 0.3f); input_filter_init(&evse_filter, 0.3f); @@ -461,4 +807,4 @@ void loadbalancer_init(void) ESP_ERROR_CHECK(esp_event_handler_register(LOADBALANCER_EVENTS, LOADBALANCER_EVENT_SLAVE_STATUS, &on_slave_status, NULL)); -} +} \ No newline at end of file diff --git a/components/meter_manager/CMakeLists.txt b/components/meter_manager/CMakeLists.txt index ba51ce5..b585222 100755 --- a/components/meter_manager/CMakeLists.txt +++ b/components/meter_manager/CMakeLists.txt @@ -3,7 +3,11 @@ set(srcs "driver/meter_ade7758/meter_ade7758.c" "driver/meter_ade7758/ade7758.c" "driver/meter_orno/meter_orno513.c" + "driver/meter_orno/meter_orno526.c" "driver/meter_orno/meter_orno516.c" + "driver/meter_orno/meter_dts6619.c" + "driver/meter_orno/meter_dds661.c" + "driver/meter_orno/meter_ea777.c" "driver/meter_orno/modbus_params.c" "driver/meter_zigbee/meter_zigbee.c" "src/meter_manager.c" diff --git a/components/meter_manager/driver/meter_orno/meter_dds661.c b/components/meter_manager/driver/meter_orno/meter_dds661.c new file mode 100755 index 0000000..a478753 --- /dev/null +++ b/components/meter_manager/driver/meter_orno/meter_dds661.c @@ -0,0 +1,289 @@ +// components/meter_manager/driver/meter_dds661.c + +#include "meter_dds661.h" + +#include "modbus_params.h" +#include "mbcontroller.h" +#include "meter_events.h" + +#include "esp_log.h" +#include "driver/uart.h" +#include +#include + +#define TAG "serial_mdb_dds661" + +// ======= UART/Modbus config ======= +#define MB_PORT_NUM 2 +#define MB_DEV_SPEED 9600 + +// Ajuste os pinos conforme seu hardware (evite GPIO2 para RTS/DE/RE se possível) +#define MB_UART_TXD 17 +#define MB_UART_RXD 16 +#define MB_UART_RTS 2 // pino DE/RE do transceiver RS-485 + +#define UPDATE_INTERVAL (3000 / portTICK_PERIOD_MS) +#define POLL_INTERVAL (120 / portTICK_PERIOD_MS) + +// ======= Helpers típicos do teu projeto ======= +#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1)) +#define STR(x) ((const char *)(x)) +#define OPTS(min, max, step) {.opt1 = min, .opt2 = max, .opt3 = step} + +// ======= Estado ======= +static bool is_initialized = false; +static TaskHandle_t meter_task = NULL; + +// ======= CIDs (sequenciais) ======= +enum +{ + CID_VOLTAGE = 0, + CID_CURRENT, + CID_ACTIVE_POWER_KW, + CID_POWER_FACTOR, + CID_FREQUENCY, + CID_TOTAL_ACTIVE_ENERGY_KWH, + CID_COUNT +}; + +// ======= Mapa de registradores (Input Registers; FC=0x04) ======= +// Endereços típicos para DDS-661 (float32): +#define REG_VOLTAGE 0x0000 // V (float32) +#define REG_CURRENT 0x0008 // A (float32) +#define REG_ACTIVE_POWER_KW 0x0012 // kW (float32) +#define REG_POWER_FACTOR 0x002A // PF (float32) +#define REG_FREQUENCY 0x0036 // Hz (float32) +#define REG_E_ACTIVE_KWH 0x0100 // kWh (float32) + +// ======= Tabela de parâmetros (Data Dictionary) ======= +const mb_parameter_descriptor_t device_parameters_dds661[] = { + {CID_VOLTAGE, "Voltage", "V", 1, + MB_PARAM_INPUT, REG_VOLTAGE, 2, HOLD_OFFSET(l1_voltage), + PARAM_TYPE_FLOAT_CDAB, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ}, + + {CID_CURRENT, "Current", "A", 1, + MB_PARAM_INPUT, REG_CURRENT, 2, HOLD_OFFSET(l1_current), + PARAM_TYPE_FLOAT_CDAB, 4, OPTS(0, 100, 0.1), PAR_PERMS_READ}, + + {CID_ACTIVE_POWER_KW, "Active Power", "kW", 1, + MB_PARAM_INPUT, REG_ACTIVE_POWER_KW, 2, HOLD_OFFSET(active_power), + PARAM_TYPE_FLOAT_CDAB, 4, OPTS(-100, 100, 0.01), PAR_PERMS_READ}, + + {CID_POWER_FACTOR, "Power Factor", "", 1, + MB_PARAM_INPUT, REG_POWER_FACTOR, 2, HOLD_OFFSET(power_factor), + PARAM_TYPE_FLOAT_CDAB, 4, OPTS(-1, 1, 0.001), PAR_PERMS_READ}, + + {CID_FREQUENCY, "Frequency", "Hz", 1, + MB_PARAM_INPUT, REG_FREQUENCY, 2, HOLD_OFFSET(frequency), + PARAM_TYPE_FLOAT_CDAB, 4, OPTS(0, 100, 0.1), PAR_PERMS_READ}, + + {CID_TOTAL_ACTIVE_ENERGY_KWH, "Total Active Energy", "kWh", 1, + MB_PARAM_INPUT, REG_E_ACTIVE_KWH, 2, HOLD_OFFSET(active_energy), + PARAM_TYPE_FLOAT_CDAB, 4, OPTS(0, 1000000, 0.01), PAR_PERMS_READ}, +}; + +const uint16_t num_device_parameters_dds661 = + sizeof(device_parameters_dds661) / sizeof(device_parameters_dds661[0]); + +// ======= Ponteiro para buffer destino ======= +static void *get_param_ptr(const mb_parameter_descriptor_t *param) +{ + if (!param || param->param_offset == 0) + return NULL; + return ((uint8_t *)&holding_reg_params + param->param_offset - 1); +} + +// ======= Tarefa de aquisição ======= +static void serial_mdb_task(void *param) +{ + esp_err_t err; + const mb_parameter_descriptor_t *desc = NULL; + + // Valores lidos + float v = 0.0f; // V + float i = 0.0f; // A + float pf = 0.0f; // - + float hz = 0.0f; // Hz + float e_kwh = 0.0f; // kWh + float p_kw = 0.0f; // kW + + // Buffers para o evento + float voltage[3] = {0}; + float current[3] = {0}; + int watt[3] = {0}; + + while (1) + { + for (uint16_t cid = 0; cid < num_device_parameters_dds661; cid++) + { + err = mbc_master_get_cid_info(cid, &desc); + if (err != ESP_OK || !desc) + { + ESP_LOGE(TAG, "get_cid_info(%u) failed: %s", cid, esp_err_to_name(err)); + continue; + } + + void *data_ptr = get_param_ptr(desc); + if (!data_ptr) + { + ESP_LOGE(TAG, "CID %u (%s): null data_ptr", cid, desc->param_key); + continue; + } + + uint8_t type = 0; + err = mbc_master_get_parameter(cid, (char *)desc->param_key, (uint8_t *)data_ptr, &type); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "CID %u (%s) read failed: %s", cid, desc->param_key, esp_err_to_name(err)); + vTaskDelay(POLL_INTERVAL); + continue; + } + + // Dump dos bytes recebidos (4 bytes do float bruto) + uint8_t raw[4]; + memcpy(raw, data_ptr, 4); + ESP_LOGD(TAG, "CID %u (%s) raw bytes: %02X %02X %02X %02X", + cid, desc->param_key, raw[0], raw[1], raw[2], raw[3]); + + float val = 0.0f; + + val = *(float *)data_ptr; + + ESP_LOGD(TAG, "%s: %.3f %s", desc->param_key, val, desc->param_units); + + switch (cid) + { + case CID_VOLTAGE: + v = val; + voltage[0] = v; + break; + case CID_CURRENT: + i = val; + current[0] = i; + break; + case CID_POWER_FACTOR: + pf = val; + break; + case CID_FREQUENCY: + hz = val; + break; + case CID_ACTIVE_POWER_KW: + { + p_kw = val; + float p_w = p_kw * 1000.0f; + int pwi = (int)lrintf(p_w); + watt[0] = pwi; + watt[1] = pwi; + watt[2] = pwi; + break; + } + case CID_TOTAL_ACTIVE_ENERGY_KWH: + e_kwh = val; + break; + default: + break; + } + + vTaskDelay(POLL_INTERVAL); + } + + meter_event_data_t evt = { + .frequency = hz, + .power_factor = pf, + .total_energy = e_kwh, + .source = "GRID", + }; + memcpy(evt.vrms, voltage, sizeof(evt.vrms)); + memcpy(evt.irms, current, sizeof(evt.irms)); + memcpy(evt.watt, watt, sizeof(evt.watt)); + + esp_event_post(METER_EVENT, METER_EVENT_DATA_READY, &evt, sizeof(evt), pdMS_TO_TICKS(10)); + vTaskDelay(UPDATE_INTERVAL); + } +} + +// ======= API pública ======= +esp_err_t meter_dds661_init(void) +{ + if (is_initialized) + { + ESP_LOGW(TAG, "meter_dds661 already initialized"); + return ESP_ERR_INVALID_STATE; + } + + ESP_LOGI(TAG, "meter_dds661_init"); + + mb_communication_info_t comm = { + .port = MB_PORT_NUM, + .mode = MB_MODE_RTU, + .baudrate = MB_DEV_SPEED, + .parity = UART_PARITY_EVEN, // DDS-661: 9600 8E1 + }; + + void *handler = NULL; + ESP_ERROR_CHECK(mbc_master_init(MB_PORT_SERIAL_MASTER, &handler)); + ESP_ERROR_CHECK(mbc_master_setup(&comm)); + + // Pinos e parâmetros básicos + ESP_ERROR_CHECK(uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD, MB_UART_RTS, UART_PIN_NO_CHANGE)); + ESP_ERROR_CHECK(uart_set_word_length(MB_PORT_NUM, UART_DATA_8_BITS)); + ESP_ERROR_CHECK(uart_set_hw_flow_ctrl(MB_PORT_NUM, UART_HW_FLOWCTRL_DISABLE, 0)); + ESP_ERROR_CHECK(uart_set_stop_bits(MB_PORT_NUM, UART_STOP_BITS_1)); + + // >>> IMPORTANTE: start antes do set_mode <<< + ESP_ERROR_CHECK(mbc_master_start()); + + // Só agora muda para RS485 half duplex + ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX)); + + // (opcional) logs de debug Modbus + esp_log_level_set("MB_CONTROLLER_MASTER", ESP_LOG_DEBUG); + esp_log_level_set("MB_PORT_COMMON", ESP_LOG_DEBUG); + esp_log_level_set("MB_SERIAL_MASTER", ESP_LOG_DEBUG); + + vTaskDelay(pdMS_TO_TICKS(5)); + + ESP_ERROR_CHECK(mbc_master_set_descriptor(device_parameters_dds661, num_device_parameters_dds661)); + + is_initialized = true; + return ESP_OK; +} + +esp_err_t meter_dds661_start(void) +{ + if (!is_initialized) + { + ESP_LOGE(TAG, "meter_dds661 not initialized"); + return ESP_ERR_INVALID_STATE; + } + + if (meter_task == NULL) + { + xTaskCreate(serial_mdb_task, "meter_dds661_task", 4096, NULL, 3, &meter_task); + ESP_LOGI(TAG, "meter_dds661 task started"); + } + + return ESP_OK; +} + +void meter_dds661_stop(void) +{ + if (!is_initialized) + { + ESP_LOGW(TAG, "meter_dds661 not initialized"); + return; + } + ESP_LOGI(TAG, "Stopping meter_dds661"); + + // 1) Destrói o master primeiro + esp_err_t err = mbc_master_destroy(); + if (err != ESP_OK) + { + ESP_LOGW(TAG, "mbc_master_destroy() returned %s", esp_err_to_name(err)); + } + + // 2) Depois solta a UART + uart_driver_delete(MB_PORT_NUM); + + is_initialized = false; +} diff --git a/components/meter_manager/driver/meter_orno/meter_dds661.h b/components/meter_manager/driver/meter_orno/meter_dds661.h new file mode 100755 index 0000000..3f4376d --- /dev/null +++ b/components/meter_manager/driver/meter_orno/meter_dds661.h @@ -0,0 +1,29 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "esp_err.h" + +/** + * @brief Inicializa o driver do medidor DDS 661 (SPI, mutex, registradores). + */ +esp_err_t meter_dds661_init(void); + +/** + * @brief Inicia a tarefa de leitura de dados do medidor DDS 661. + */ +esp_err_t meter_dds661_start(void); + +/** + * @brief Para a tarefa de leitura e limpa os dados internos do medidor DDS 661. + */ +void meter_dds661_stop(void); + + +#ifdef __cplusplus +} +#endif diff --git a/components/meter_manager/driver/meter_orno/meter_dts6619.c b/components/meter_manager/driver/meter_orno/meter_dts6619.c new file mode 100755 index 0000000..a6f37c1 --- /dev/null +++ b/components/meter_manager/driver/meter_orno/meter_dts6619.c @@ -0,0 +1,326 @@ +// meter_dts6619.c — Driver Modbus RTU para SINOTIMER DTS6619 (ESP-IDF) + +#include "meter_events.h" +#include "modbus_params.h" +#include "mbcontroller.h" +#include "esp_log.h" +#include "driver/uart.h" +#include +#include + +#define TAG "serial_mdb_dts6619" + +// ===== UART / RS-485 ===== +#define MB_PORT_NUM 2 +#define MB_DEV_SPEED 9600 + +// Ajuste os pinos conforme seu hardware (evite GPIO2 para RTS/DE/RE se possível) +#define MB_UART_TXD 17 +#define MB_UART_RXD 16 +#define MB_UART_RTS 2 // pino DE/RE do transceiver RS-485 + +// ===== Timings ===== +#define UPDATE_INTERVAL (5000 / portTICK_PERIOD_MS) +#define POLL_INTERVAL (200 / portTICK_PERIOD_MS) // DTS6619 prefere >100 ms + +// ===== Helpers ===== +#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1)) +#define STR(fieldname) ((const char *)(fieldname)) +#define OPTS(min_val, max_val, step_val) {.opt1 = min_val, .opt2 = max_val, .opt3 = step_val} + +// ===== Estado ===== +static bool is_initialized = false; +static TaskHandle_t meter_task = NULL; + +// ====== Config de endianness ====== +// 0: usa float lido direto; 1: faz word-swap (DTS6619 em alguns firmwares) +#ifndef DTS6619_WORD_SWAP +#define DTS6619_WORD_SWAP 0 +#endif + +static inline float maybe_swap_float(float in) +{ +#if DTS6619_WORD_SWAP + // swap de words: 0-1-2-3 -> 2-3-0-1 + float out; + char *src = (char *)∈ + char *dst = (char *)&out; + dst[0] = src[2]; + dst[1] = src[3]; + dst[2] = src[0]; + dst[3] = src[1]; + return out; +#else + return in; +#endif +} + +// ============================================================================ +// =================== MAPA DE REGISTROS DTS6619 (Input 0x04) =============== +// Todos float32, 2 regs cada, endereços zero-based +// Tensões +#define DTS_L1VOLTAGE 0x0000 +#define DTS_L2VOLTAGE 0x0002 +#define DTS_L3VOLTAGE 0x0004 +// Correntes (total e por fase) +#define DTS_TOTALCURRENT 0x0006 +#define DTS_L1CURRENT 0x0008 +#define DTS_L2CURRENT 0x000A +#define DTS_L3CURRENT 0x000C +// Potências ativas +#define DTS_TOTALACTIVEPOWER 0x0010 +#define DTS_L1ACTIVEPOWER 0x0012 +#define DTS_L2ACTIVEPOWER 0x0014 +#define DTS_L3ACTIVEPOWER 0x0016 +// Fator de potência (por fase) +#define DTS_PF_L1 0x002A +#define DTS_PF_L2 0x002C +#define DTS_PF_L3 0x002E +// Frequência +#define DTS_FREQUENCY 0x0036 +// Energia total ativa (Wh) +#define DTS_TOTAL_ACTIVE_ENERGY 0x0100 +// ============================================================================ + +// ============ CIDs ============ +enum +{ + CID_L1_VOLTAGE = 0, + CID_L2_VOLTAGE, + CID_L3_VOLTAGE, + CID_L1_CURRENT, + CID_L2_CURRENT, + CID_L3_CURRENT, +}; + +// ======= Descritores (usando INPUT registers) ======= +const mb_parameter_descriptor_t device_parameters_dts6619[] = { + {CID_L1_VOLTAGE, STR("L1 Voltage"), STR("V"), 1, MB_PARAM_INPUT, DTS_L1VOLTAGE, 2, + HOLD_OFFSET(l1_voltage), PARAM_TYPE_FLOAT, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ}, + {CID_L2_VOLTAGE, STR("L2 Voltage"), STR("V"), 1, MB_PARAM_INPUT, DTS_L2VOLTAGE, 2, + HOLD_OFFSET(l2_voltage), PARAM_TYPE_FLOAT, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ}, + {CID_L3_VOLTAGE, STR("L3 Voltage"), STR("V"), 1, MB_PARAM_INPUT, DTS_L3VOLTAGE, 2, + HOLD_OFFSET(l3_voltage), PARAM_TYPE_FLOAT, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ}, + + {CID_L1_CURRENT, STR("L1 Current"), STR("A"), 1, MB_PARAM_INPUT, DTS_L1CURRENT, 2, + HOLD_OFFSET(l1_current), PARAM_TYPE_FLOAT, 4, OPTS(0, 1000, 0.1), PAR_PERMS_READ}, + {CID_L2_CURRENT, STR("L2 Current"), STR("A"), 1, MB_PARAM_INPUT, DTS_L2CURRENT, 2, + HOLD_OFFSET(l2_current), PARAM_TYPE_FLOAT, 4, OPTS(0, 1000, 0.1), PAR_PERMS_READ}, + {CID_L3_CURRENT, STR("L3 Current"), STR("A"), 1, MB_PARAM_INPUT, DTS_L3CURRENT, 2, + HOLD_OFFSET(l3_current), PARAM_TYPE_FLOAT, 4, OPTS(0, 1000, 0.1), PAR_PERMS_READ}, + +}; +const uint16_t num_device_parameters_dts6619 = + sizeof(device_parameters_dts6619) / sizeof(device_parameters_dts6619[0]); + +// ===== Ponteiro para a struct de holding (vinda do teu projeto) +extern holding_reg_params_t holding_reg_params; + +// ===== Acesso a memória local usada pela stack +static void *get_param_ptr(const mb_parameter_descriptor_t *param) +{ + if (!param || param->param_offset == 0) + return NULL; + return ((uint8_t *)&holding_reg_params + param->param_offset - 1); +} + +// ===== Post do evento de medição +static void meter_dts6619_post_event(float *voltage, float *current, int *power_w, + float freq_hz, float pf_avg, float total_kwh) +{ + meter_event_data_t evt = { + .source = "GRID", + .frequency = freq_hz, + .power_factor = pf_avg, + .total_energy = total_kwh}; + memcpy(evt.vrms, voltage, sizeof(evt.vrms)); + memcpy(evt.irms, current, sizeof(evt.irms)); + memcpy(evt.watt, power_w, sizeof(evt.watt)); + + esp_err_t err = esp_event_post(METER_EVENT, METER_EVENT_DATA_READY, + &evt, sizeof(evt), pdMS_TO_TICKS(10)); + if (err != ESP_OK) + { + ESP_LOGW(TAG, "Falha ao emitir evento: %s", esp_err_to_name(err)); + } +} + +// ===== Task de polling +static void serial_mdb_task(void *param) +{ + esp_err_t err; + const mb_parameter_descriptor_t *desc = NULL; + float v[3] = {0}, i[3] = {0}, p_ph[3] = {0}; + float p_total = 0.0f, pf[3] = {0}, freq = 0.0f, e_total_wh = 0.0f; + + // pequeno settle antes da 1ª leitura + vTaskDelay(pdMS_TO_TICKS(200)); + + while (1) + { + for (uint16_t cid = 0; cid < num_device_parameters_dts6619; cid++) + { + err = mbc_master_get_cid_info(cid, &desc); + if (err != ESP_OK || !desc) + continue; + + void *data_ptr = get_param_ptr(desc); + uint8_t type = 0; + + // 1 retry simples em caso de timeout + err = mbc_master_get_parameter(cid, (char *)desc->param_key, (uint8_t *)data_ptr, &type); + if (err == ESP_ERR_TIMEOUT) + { + vTaskDelay(pdMS_TO_TICKS(60)); + err = mbc_master_get_parameter(cid, (char *)desc->param_key, (uint8_t *)data_ptr, &type); + } + + if (err == ESP_OK && data_ptr) + { + float raw = *(float *)data_ptr; + float val = maybe_swap_float(raw); + + // logging enxuto + ESP_LOGI(TAG, "%s: %.3f %s", desc->param_key, val, desc->param_units); + + switch (cid) + { + case CID_L1_VOLTAGE: + v[0] = val; + break; + case CID_L2_VOLTAGE: + v[1] = val; + break; + case CID_L3_VOLTAGE: + v[2] = val; + break; + + case CID_L1_CURRENT: + i[0] = val; + break; + case CID_L2_CURRENT: + i[1] = val; + break; + case CID_L3_CURRENT: + i[2] = val; + break; + default: + break; + } + } + else + { + ESP_LOGE(TAG, "CID %u (%s) read failed: %s", + cid, desc->param_key, esp_err_to_name(err)); + } + + vTaskDelay(POLL_INTERVAL); + } + + // prepara payload do evento + int p_int[3] = { + (int)(p_ph[0]), + (int)(p_ph[1]), + (int)(p_ph[2])}; + // PF médio simples (ignora zeros) + float pf_sum = 0.0f; + int pf_cnt = 0; + for (int k = 0; k < 3; ++k) + { + if (pf[k] != 0.0f) + { + pf_sum += pf[k]; + pf_cnt++; + } + } + float pf_avg = (pf_cnt ? pf_sum / pf_cnt : 0.0f); + + // energia em kWh se veio em Wh + float total_kwh = e_total_wh / 1000.0f; + + meter_dts6619_post_event(v, i, p_int, freq, pf_avg, total_kwh); + vTaskDelay(UPDATE_INTERVAL); + } +} + +// ============ Init / Start / Stop ============ +esp_err_t meter_dts6619_init(void) +{ + if (is_initialized) + { + ESP_LOGW(TAG, "Already initialized"); + return ESP_ERR_INVALID_STATE; + } + + // limpa UART se já houver driver + if (uart_is_driver_installed(MB_PORT_NUM)) + { + uart_driver_delete(MB_PORT_NUM); + ESP_LOGI(TAG, "UART driver deleted"); + } + + // destruir master anterior (ignora erro se não estiver init) + (void)mbc_master_destroy(); + + mb_communication_info_t comm = { + .port = MB_PORT_NUM, + .mode = MB_MODE_RTU, + .baudrate = MB_DEV_SPEED, + .parity = UART_PARITY_EVEN}; + + void *handler = NULL; + ESP_ERROR_CHECK(mbc_master_init(MB_PORT_SERIAL_MASTER, &handler)); + ESP_ERROR_CHECK(mbc_master_setup(&comm)); + ESP_ERROR_CHECK(uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD, MB_UART_RTS, UART_PIN_NO_CHANGE)); + ESP_ERROR_CHECK(mbc_master_start()); + ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX)); + vTaskDelay(pdMS_TO_TICKS(50)); + + ESP_ERROR_CHECK(mbc_master_set_descriptor(device_parameters_dts6619, num_device_parameters_dts6619)); + + is_initialized = true; + ESP_LOGI(TAG, "DTS6619 Modbus master initialized (9600 8E1, Input Reg 0x04)"); + return ESP_OK; +} + +esp_err_t meter_dts6619_start(void) +{ + if (!is_initialized) + { + ESP_LOGE(TAG, "Not initialized"); + return ESP_ERR_INVALID_STATE; + } + if (meter_task == NULL) + { + xTaskCreate(serial_mdb_task, "meter_dts6619_task", 4096, NULL, 3, &meter_task); + ESP_LOGI(TAG, "Task started"); + } + return ESP_OK; +} + +void meter_dts6619_stop(void) +{ + if (!is_initialized) + { + ESP_LOGW(TAG, "Not initialized, skipping stop"); + return; + } + + if (meter_task) + { + vTaskDelete(meter_task); + meter_task = NULL; + ESP_LOGI(TAG, "Task stopped"); + } + + (void)mbc_master_destroy(); + + if (uart_is_driver_installed(MB_PORT_NUM)) + { + uart_driver_delete(MB_PORT_NUM); + ESP_LOGI(TAG, "UART driver deleted"); + } + + is_initialized = false; + ESP_LOGI(TAG, "Meter DTS6619 cleaned up"); +} diff --git a/components/meter_manager/driver/meter_orno/meter_dts6619.h b/components/meter_manager/driver/meter_orno/meter_dts6619.h new file mode 100755 index 0000000..f71926e --- /dev/null +++ b/components/meter_manager/driver/meter_orno/meter_dts6619.h @@ -0,0 +1,35 @@ +#ifndef METER_EA777_H_ +#define METER_EA777_H_ + +#include +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Inicializa o driver do medidor EA777 (UART RS485, Modbus, registradores). + * + * @return esp_err_t Retorna ESP_OK se a inicialização for bem-sucedida, caso contrário retorna um erro. + */ +esp_err_t meter_ea777_init(void); + +/** + * @brief Inicia a tarefa de leitura de dados do medidor EA777. + * + * @return esp_err_t Retorna ESP_OK se a tarefa for iniciada com sucesso, caso contrário retorna um erro. + */ +esp_err_t meter_ea777_start(void); + +/** + * @brief Para a tarefa de leitura e limpa os dados internos do medidor EA777. + */ +void meter_ea777_stop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* METER_EA777_H_ */ diff --git a/components/meter_manager/driver/meter_orno/meter_ea777.c b/components/meter_manager/driver/meter_orno/meter_ea777.c new file mode 100755 index 0000000..e20682f --- /dev/null +++ b/components/meter_manager/driver/meter_orno/meter_ea777.c @@ -0,0 +1,379 @@ +// meter_ea777.c — Driver Modbus RTU para EARU EA777 (ESP-IDF) + +#include "meter_events.h" +#include "modbus_params.h" +#include "mbcontroller.h" +#include "esp_log.h" +#include "driver/uart.h" +#include +#include + +#define TAG "serial_mdb_ea777" + +// ===== UART / RS-485 ===== +#define MB_PORT_NUM 2 +#define MB_DEV_SPEED 9600 + +// Ajuste os pinos conforme seu hardware +#define MB_UART_TXD 17 +#define MB_UART_RXD 16 +#define MB_UART_RTS 2 // pino DE/RE do transceiver RS-485 + +// ===== Timings ===== +#define UPDATE_INTERVAL (5000 / portTICK_PERIOD_MS) +#define POLL_INTERVAL (200 / portTICK_PERIOD_MS) + +// ===== Helpers ===== +#define STR(fieldname) ((const char *)(fieldname)) +#define OPTS(min_val, max_val, step_val) {.opt1 = min_val, .opt2 = max_val, .opt3 = step_val} + +// ===== Estado ===== +static bool is_initialized = false; +static TaskHandle_t meter_task = NULL; + +// ============================================================================ +// ============ MAPA DE REGISTROS EA777 (Holding 0x03) ======================== +// Endereços zero-based. Tipos reais (engenharia) via fator de escala. +// Tensões (0.1 V) +#define EA777_L1VOLTAGE 0x0000 +#define EA777_L2VOLTAGE 0x0001 +#define EA777_L3VOLTAGE 0x0002 +// Correntes (0.01 A) +#define EA777_L1CURRENT 0x0003 +#define EA777_L2CURRENT 0x0004 +#define EA777_L3CURRENT 0x0005 +// Potência ativa total (W) +#define EA777_TOTAL_ACTIVE_P 0x0007 +// (se quiser por fase, pode usar 0x0008/0x0009/0x000A) +// Fator de potência por fase (0.001) +#define EA777_PF_L1 0x0014 +#define EA777_PF_L2 0x0015 +#define EA777_PF_L3 0x0016 +// Frequência (0.01 Hz) +#define EA777_FREQUENCY 0x001A +// Energia ativa total (U32 * 0.01 kWh, 2 registradores) +#define EA777_TOTAL_ACTIVE_E 0x001D +// ============================================================================ + +// ============ CIDs ============ +enum +{ + CID_EA777_L1_VOLTAGE = 0, + CID_EA777_L2_VOLTAGE, + CID_EA777_L3_VOLTAGE, + CID_EA777_L1_CURRENT, + CID_EA777_L2_CURRENT, + CID_EA777_L3_CURRENT, + CID_EA777_TOTAL_ACTIVE_P, + CID_EA777_PF_L1, + CID_EA777_PF_L2, + CID_EA777_PF_L3, + CID_EA777_FREQUENCY, + CID_EA777_TOTAL_ACTIVE_E, +}; + +// ======= Descritores (Holding registers) ======= +// Nota: param_offset = 0 -> não usamos holding_reg_params_t aqui. +const mb_parameter_descriptor_t device_parameters_ea777[] = { + // Tensões (0.1 V) + {CID_EA777_L1_VOLTAGE, STR("L1 Voltage"), STR("V"), 1, + MB_PARAM_HOLDING, EA777_L1VOLTAGE, 1, + 0, PARAM_TYPE_U16, 2, OPTS(0, 4000, 1), PAR_PERMS_READ}, + + {CID_EA777_L2_VOLTAGE, STR("L2 Voltage"), STR("V"), 1, + MB_PARAM_HOLDING, EA777_L2VOLTAGE, 1, + 0, PARAM_TYPE_U16, 2, OPTS(0, 4000, 1), PAR_PERMS_READ}, + + {CID_EA777_L3_VOLTAGE, STR("L3 Voltage"), STR("V"), 1, + MB_PARAM_HOLDING, EA777_L3VOLTAGE, 1, + 0, PARAM_TYPE_U16, 2, OPTS(0, 4000, 1), PAR_PERMS_READ}, + + // Correntes (0.01 A) + {CID_EA777_L1_CURRENT, STR("L1 Current"), STR("A"), 1, + MB_PARAM_HOLDING, EA777_L1CURRENT, 1, + 0, PARAM_TYPE_U16, 2, OPTS(0, 10000, 1), PAR_PERMS_READ}, + + {CID_EA777_L2_CURRENT, STR("L2 Current"), STR("A"), 1, + MB_PARAM_HOLDING, EA777_L2CURRENT, 1, + 0, PARAM_TYPE_U16, 2, OPTS(0, 10000, 1), PAR_PERMS_READ}, + + {CID_EA777_L3_CURRENT, STR("L3 Current"), STR("A"), 1, + MB_PARAM_HOLDING, EA777_L3CURRENT, 1, + 0, PARAM_TYPE_U16, 2, OPTS(0, 10000, 1), PAR_PERMS_READ}, + + // Potência ativa total (W) + {CID_EA777_TOTAL_ACTIVE_P, STR("Total Active Power"), STR("W"), 1, + MB_PARAM_HOLDING, EA777_TOTAL_ACTIVE_P, 1, + 0, PARAM_TYPE_U16, 2, OPTS(0, 60000, 1), PAR_PERMS_READ}, + + // Fator de potência (0.001) + {CID_EA777_PF_L1, STR("L1 PF"), STR(""), 1, + MB_PARAM_HOLDING, EA777_PF_L1, 1, + 0, PARAM_TYPE_U16, 2, OPTS(0, 1000, 1), PAR_PERMS_READ}, + + {CID_EA777_PF_L2, STR("L2 PF"), STR(""), 1, + MB_PARAM_HOLDING, EA777_PF_L2, 1, + 0, PARAM_TYPE_U16, 2, OPTS(0, 1000, 1), PAR_PERMS_READ}, + + {CID_EA777_PF_L3, STR("L3 PF"), STR(""), 1, + MB_PARAM_HOLDING, EA777_PF_L3, 1, + 0, PARAM_TYPE_U16, 2, OPTS(0, 1000, 1), PAR_PERMS_READ}, + + // Frequência (0.01 Hz) + {CID_EA777_FREQUENCY, STR("Frequency"), STR("Hz"), 1, + MB_PARAM_HOLDING, EA777_FREQUENCY, 1, + 0, PARAM_TYPE_U16, 2, OPTS(0, 10000, 1), PAR_PERMS_READ}, + + // Energia ativa total (U32 * 0.01 kWh, 2 regs) + {CID_EA777_TOTAL_ACTIVE_E, STR("Total Active Energy"), STR("kWh"), 1, + MB_PARAM_HOLDING, EA777_TOTAL_ACTIVE_E, 2, + 0, PARAM_TYPE_U32, 4, OPTS(0, 0xFFFFFFFF, 1), PAR_PERMS_READ}, +}; + +const uint16_t num_device_parameters_ea777 = + sizeof(device_parameters_ea777) / sizeof(device_parameters_ea777[0]); + +// ===== Post do evento de medição ===== +static void meter_ea777_post_event(float *voltage, float *current, int *power_w, + float freq_hz, float pf_avg, float total_kwh) +{ + meter_event_data_t evt = { + .source = "GRID", + .frequency = freq_hz, + .power_factor = pf_avg, + .total_energy = total_kwh}; + + memcpy(evt.vrms, voltage, sizeof(evt.vrms)); + memcpy(evt.irms, current, sizeof(evt.irms)); + memcpy(evt.watt, power_w, sizeof(evt.watt)); + + esp_err_t err = esp_event_post(METER_EVENT, METER_EVENT_DATA_READY, + &evt, sizeof(evt), pdMS_TO_TICKS(10)); + if (err != ESP_OK) + { + ESP_LOGW(TAG, "Falha ao emitir evento: %s", esp_err_to_name(err)); + } +} + +// ===== Task de polling ===== +static void serial_mdb_ea777_task(void *param) +{ + esp_err_t err; + const mb_parameter_descriptor_t *desc = NULL; + + float v[3] = {0}; + float i[3] = {0}; + float pf[3] = {0}; + float freq = 0.0f; + float total_kwh = 0.0f; + + // pequeno settle antes da 1ª leitura + vTaskDelay(pdMS_TO_TICKS(200)); + + while (1) + { + for (uint16_t cid = 0; cid < num_device_parameters_ea777; cid++) + { + err = mbc_master_get_cid_info(cid, &desc); + if (err != ESP_OK || !desc) + { + continue; + } + + uint8_t type = 0; + uint16_t raw16 = 0; + uint32_t raw32 = 0; + + void *value_ptr = (cid == CID_EA777_TOTAL_ACTIVE_E) ? (void *)&raw32 : (void *)&raw16; + + // 1 retry simples em caso de timeout + err = mbc_master_get_parameter(cid, + (char *)desc->param_key, + (uint8_t *)value_ptr, + &type); + if (err == ESP_ERR_TIMEOUT) + { + vTaskDelay(pdMS_TO_TICKS(60)); + err = mbc_master_get_parameter(cid, + (char *)desc->param_key, + (uint8_t *)value_ptr, + &type); + } + + if (err == ESP_OK) + { + switch (cid) + { + case CID_EA777_L1_VOLTAGE: + v[0] = ((float)raw16) * 0.1f; + break; + case CID_EA777_L2_VOLTAGE: + v[1] = ((float)raw16) * 0.1f; + break; + case CID_EA777_L3_VOLTAGE: + v[2] = ((float)raw16) * 0.1f; + break; + + case CID_EA777_L1_CURRENT: + i[0] = ((float)raw16) * 0.01f; + break; + case CID_EA777_L2_CURRENT: + i[1] = ((float)raw16) * 0.01f; + break; + case CID_EA777_L3_CURRENT: + i[2] = ((float)raw16) * 0.01f; + break; + + case CID_EA777_TOTAL_ACTIVE_P: + // guarda se quiser usar em debug; para o evento usamos + // aproximação por fase abaixo + // (poderia ser passado direto em power_w[0..2] também) + break; + + case CID_EA777_PF_L1: + pf[0] = ((float)raw16) * 0.001f; + break; + case CID_EA777_PF_L2: + pf[1] = ((float)raw16) * 0.001f; + break; + case CID_EA777_PF_L3: + pf[2] = ((float)raw16) * 0.001f; + break; + + case CID_EA777_FREQUENCY: + freq = ((float)raw16) * 0.01f; + break; + + case CID_EA777_TOTAL_ACTIVE_E: + total_kwh = ((float)raw32) * 0.01f; + break; + + default: + break; + } + + ESP_LOGD(TAG, "%s (cid=%u) -> raw16=%u raw32=%u", + desc->param_key, cid, + (unsigned int)raw16, + (unsigned int)raw32); + } + else + { + ESP_LOGE(TAG, "CID %u (%s) read failed: %s", + cid, desc->param_key, esp_err_to_name(err)); + } + + vTaskDelay(POLL_INTERVAL); + } + + // Potência por fase aproximada: P = V * I * PF + int p_int[3] = { + (int)(v[0] * i[0] * pf[0]), + (int)(v[1] * i[1] * pf[1]), + (int)(v[2] * i[2] * pf[2]), + }; + + // PF médio simples (ignora zeros) + float pf_sum = 0.0f; + int pf_cnt = 0; + for (int k = 0; k < 3; ++k) + { + if (pf[k] != 0.0f) + { + pf_sum += pf[k]; + pf_cnt++; + } + } + float pf_avg = (pf_cnt ? pf_sum / pf_cnt : 0.0f); + + meter_ea777_post_event(v, i, p_int, freq, pf_avg, total_kwh); + vTaskDelay(UPDATE_INTERVAL); + } +} + +// ============ Init / Start / Stop ============ +esp_err_t meter_ea777_init(void) +{ + if (is_initialized) + { + ESP_LOGW(TAG, "Already initialized"); + return ESP_ERR_INVALID_STATE; + } + + // limpa UART se já houver driver + if (uart_is_driver_installed(MB_PORT_NUM)) + { + uart_driver_delete(MB_PORT_NUM); + ESP_LOGI(TAG, "UART driver deleted"); + } + + // destruir master anterior (ignora erro se não estiver init) + (void)mbc_master_destroy(); + + mb_communication_info_t comm = { + .port = MB_PORT_NUM, + .mode = MB_MODE_RTU, + .baudrate = MB_DEV_SPEED, + .parity = UART_PARITY_EVEN}; + + void *handler = NULL; + ESP_ERROR_CHECK(mbc_master_init(MB_PORT_SERIAL_MASTER, &handler)); + ESP_ERROR_CHECK(mbc_master_setup(&comm)); + ESP_ERROR_CHECK(uart_set_pin(MB_PORT_NUM, + MB_UART_TXD, MB_UART_RXD, + MB_UART_RTS, UART_PIN_NO_CHANGE)); + ESP_ERROR_CHECK(mbc_master_start()); + ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX)); + vTaskDelay(pdMS_TO_TICKS(50)); + + ESP_ERROR_CHECK(mbc_master_set_descriptor(device_parameters_ea777, + num_device_parameters_ea777)); + + is_initialized = true; + ESP_LOGI(TAG, "EA777 Modbus master initialized (9600 8E1, Holding Reg 0x03)"); + return ESP_OK; +} + +esp_err_t meter_ea777_start(void) +{ + if (!is_initialized) + { + ESP_LOGE(TAG, "Not initialized"); + return ESP_ERR_INVALID_STATE; + } + if (meter_task == NULL) + { + xTaskCreate(serial_mdb_ea777_task, + "meter_ea777_task", + 4096, NULL, 3, &meter_task); + ESP_LOGI(TAG, "EA777 task started"); + } + return ESP_OK; +} + +void meter_ea777_stop(void) +{ + if (!is_initialized) + { + ESP_LOGW(TAG, "Not initialized, skipping stop"); + return; + } + + if (meter_task) + { + vTaskDelete(meter_task); + meter_task = NULL; + ESP_LOGI(TAG, "EA777 task stopped"); + } + + (void)mbc_master_destroy(); + + if (uart_is_driver_installed(MB_PORT_NUM)) + { + uart_driver_delete(MB_PORT_NUM); + ESP_LOGI(TAG, "UART driver deleted"); + } + + is_initialized = false; + ESP_LOGI(TAG, "Meter EA777 cleaned up"); +} diff --git a/components/meter_manager/driver/meter_orno/meter_ea777.h b/components/meter_manager/driver/meter_orno/meter_ea777.h new file mode 100755 index 0000000..a843a1c --- /dev/null +++ b/components/meter_manager/driver/meter_orno/meter_ea777.h @@ -0,0 +1,32 @@ +#ifndef METER_DTS6619_H_ +#define METER_DTS6619_H_ + +#include +#include +#include "esp_err.h" + +/** + * @brief Inicializa o driver do medidor dts6619 (SPI, mutex, registradores). + * + * @return esp_err_t Retorna ESP_OK se a inicialização for bem-sucedida, caso contrário retorna um erro. + */ +esp_err_t meter_dts6619_init(void); + +/** + * @brief Inicia a tarefa de leitura de dados do medidor DTS6619. + * + * @return esp_err_t Retorna ESP_OK se a tarefa for iniciada com sucesso, caso contrário retorna um erro. + */ +esp_err_t meter_dts6619_start(void); + +/** + * @brief Para a tarefa de leitura e limpa os dados internos do medidor DTS6619. + */ +void meter_dts6619_stop(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* METER_DTS6619_H_ */ diff --git a/components/meter_manager/driver/meter_orno/meter_orno513.c b/components/meter_manager/driver/meter_orno/meter_orno513.c index 1c03fc3..7a9cc1d 100755 --- a/components/meter_manager/driver/meter_orno/meter_orno513.c +++ b/components/meter_manager/driver/meter_orno/meter_orno513.c @@ -46,10 +46,10 @@ enum { const mb_parameter_descriptor_t device_parameters_orno513[] = { {CID_TOTAL_ACTIVE_ENERGY, STR("Total Active Energy"), STR("kWh"), 1, MB_PARAM_HOLDING, TOTALFACTIVE, 2, - HOLD_OFFSET(total_active_power), PARAM_TYPE_I32_CDAB, 4, OPTS(0, 100000, 1), PAR_PERMS_READ}, + HOLD_OFFSET(active_power), PARAM_TYPE_I32_CDAB, 4, OPTS(0, 100000, 1), PAR_PERMS_READ}, {CID_TOTAL_REACTIVE_ENERGY, STR("Total Reactive Energy"), STR("kWh"), 1, MB_PARAM_HOLDING, TOTALRACTIVE, 2, - HOLD_OFFSET(total_reactive_power), PARAM_TYPE_I32_CDAB, 4, OPTS(0, 100000, 1), PAR_PERMS_READ}, + HOLD_OFFSET(reactive_power), PARAM_TYPE_I32_CDAB, 4, OPTS(0, 100000, 1), PAR_PERMS_READ}, {CID_ACTIVE_POWER, STR("Active Power"), STR("W"), 1, MB_PARAM_HOLDING, ACTIVEPOWER, 2, HOLD_OFFSET(active_power), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}, diff --git a/components/meter_manager/driver/meter_orno/meter_orno516.c b/components/meter_manager/driver/meter_orno/meter_orno516.c index 56f7141..9670787 100755 --- a/components/meter_manager/driver/meter_orno/meter_orno516.c +++ b/components/meter_manager/driver/meter_orno/meter_orno516.c @@ -12,7 +12,7 @@ #define MB_DEV_SPEED 9600 #define MB_UART_TXD 17 #define MB_UART_RXD 16 -#define MB_UART_RTS 5 +#define MB_UART_RTS 2 #define UPDATE_INTERVAL (5000 / portTICK_PERIOD_MS) #define POLL_INTERVAL (100 / portTICK_PERIOD_MS) @@ -40,7 +40,7 @@ enum { CID_L1_VOLTAGE, CID_L2_VOLTAGE, CID_L3_VOLTAGE, - CID_TOTAL_ACTIVE_POWER + CID_ACTIVE_POWER }; const mb_parameter_descriptor_t device_parameters_orno516[] = { @@ -56,8 +56,8 @@ const mb_parameter_descriptor_t device_parameters_orno516[] = { HOLD_OFFSET(l2_voltage), PARAM_TYPE_FLOAT, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ}, {CID_L3_VOLTAGE, STR("L3 Voltage"), STR("V"), 1, MB_PARAM_HOLDING, L3VOLTAGE, 2, HOLD_OFFSET(l3_voltage), PARAM_TYPE_FLOAT, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ}, - {CID_TOTAL_ACTIVE_POWER, STR("Total Active Power"), STR("W"), 1, MB_PARAM_HOLDING, TOTALACTIVEPOWER, 2, - HOLD_OFFSET(total_active_power), PARAM_TYPE_FLOAT, 4, OPTS(0, 100000, 1), PAR_PERMS_READ} + {CID_ACTIVE_POWER, STR("Active Power"), STR("W"), 1, MB_PARAM_HOLDING, TOTALACTIVEPOWER, 2, + HOLD_OFFSET(active_power), PARAM_TYPE_FLOAT, 4, OPTS(0, 100000, 1), PAR_PERMS_READ} }; const uint16_t num_device_parameters_orno516 = sizeof(device_parameters_orno516) / sizeof(device_parameters_orno516[0]); @@ -124,7 +124,7 @@ static void serial_mdb_task(void *param) { case CID_L1_CURRENT: current[0] = val; break; case CID_L2_CURRENT: current[1] = val; break; case CID_L3_CURRENT: current[2] = val; break; - case CID_TOTAL_ACTIVE_POWER: + case CID_ACTIVE_POWER: power[0] = (int)(val / 3); power[1] = (int)(val / 3); power[2] = (int)(val / 3); diff --git a/components/meter_manager/driver/meter_orno/meter_orno526.c b/components/meter_manager/driver/meter_orno/meter_orno526.c new file mode 100755 index 0000000..8a1946a --- /dev/null +++ b/components/meter_manager/driver/meter_orno/meter_orno526.c @@ -0,0 +1,310 @@ +#include "meter_orno526.h" +#include "modbus_params.h" +#include "mbcontroller.h" +#include "meter_events.h" +#include "esp_log.h" +#include "driver/uart.h" +#include +#include + +#define TAG "serial_mdb_orno526" + +#define MB_PORT_NUM 2 +#define MB_DEV_SPEED 9600 +#define MB_UART_TXD 17 +#define MB_UART_RXD 16 +#define MB_UART_RTS 2 +#define UPDATE_INTERVAL (3000 / portTICK_PERIOD_MS) +#define POLL_INTERVAL (100 / portTICK_PERIOD_MS) + +#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1)) +#define STR(x) ((const char *)(x)) +#define OPTS(min, max, step) {.opt1 = min, .opt2 = max, .opt3 = step} + +// State flag +static bool is_initialized = false; +static TaskHandle_t meter_task = NULL; + +// CID enums +enum +{ + CID_ACTIVE_ENERGY = 0, + CID_REACTIVE_ENERGY, + CID_ACTIVE_POWER, + CID_APPARENT_POWER, + CID_REACTIVE_POWER, + CID_L1_CURRENT, + CID_L1_VOLTAGE, + CID_FREQUENCY +}; + +// Register addresses +#define TOTALFACTIVE 0x010E +#define TOTALRACTIVE 0x0118 +#define ACTIVEPOWER 0x0104 +#define APPARENTPOWER 0x0106 +#define REACTIVEPOWER 0x0108 +#define L1CURRENT 0x0102 +#define L1VOLTAGE 0x0100 +#define FREQUENCY 0x010A + +const mb_parameter_descriptor_t device_parameters_orno526[] = { + + {CID_ACTIVE_ENERGY, "Active Energy", "kWh", 1, + MB_PARAM_INPUT, TOTALFACTIVE, 2, HOLD_OFFSET(active_energy), + PARAM_TYPE_I32_CDAB, 4, OPTS(0, 100000, 1), PAR_PERMS_READ}, + + {CID_REACTIVE_ENERGY, "Reactive Energy", "kWh", 1, + MB_PARAM_INPUT, TOTALRACTIVE, 2, HOLD_OFFSET(reactive_energy), + PARAM_TYPE_I32_CDAB, 4, OPTS(0, 100000, 1), PAR_PERMS_READ}, + + {CID_ACTIVE_POWER, "Active Power", "W", 1, + MB_PARAM_INPUT, ACTIVEPOWER, 2, HOLD_OFFSET(active_power), + PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}, + + {CID_APPARENT_POWER, "Apparent Power", "VA", 1, + MB_PARAM_INPUT, APPARENTPOWER, 2, HOLD_OFFSET(apparent_power), + PARAM_TYPE_I32_CDAB, 4, OPTS(0, 100000, 1), PAR_PERMS_READ}, + + {CID_REACTIVE_POWER, "Reactive Power", "VAR", 1, + MB_PARAM_INPUT, REACTIVEPOWER, 2, HOLD_OFFSET(reactive_power), + PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}, + + {CID_L1_CURRENT, "L1 Current", "A", 1, + MB_PARAM_INPUT, L1CURRENT, 2, HOLD_OFFSET(l1_current), + PARAM_TYPE_I32_CDAB, 4, OPTS(0, 100, 0.1), PAR_PERMS_READ}, + + {CID_L1_VOLTAGE, "L1 Voltage", "V", 1, + MB_PARAM_INPUT, L1VOLTAGE, 2, HOLD_OFFSET(l1_voltage), + PARAM_TYPE_I32_CDAB, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ}, + + {CID_FREQUENCY, "Frequency", "Hz", 1, + MB_PARAM_INPUT, FREQUENCY, 1, HOLD_OFFSET(frequency), + PARAM_TYPE_I32_CDAB, 2, OPTS(0, 1000, 0.1), PAR_PERMS_READ} + +}; + +const uint16_t num_device_parameters_orno526 = sizeof(device_parameters_orno526) / sizeof(device_parameters_orno526[0]); + +static void *get_param_ptr(const mb_parameter_descriptor_t *param) +{ + if (!param || param->param_offset == 0) + return NULL; + return ((uint8_t *)&holding_reg_params + param->param_offset - 1); +} + +static inline float scale_for_cid(uint16_t cid) +{ + switch (cid) + { + case CID_L1_VOLTAGE: + case CID_L1_CURRENT: + return 1000.0f; // V/A = raw / 1000 + case CID_ACTIVE_POWER: + case CID_APPARENT_POWER: + case CID_REACTIVE_POWER: + return 1.0f; // W/VA/var = raw + case CID_ACTIVE_ENERGY: + case CID_REACTIVE_ENERGY: + return 100.0f; // kWh = raw / 100 + case CID_FREQUENCY: + return 10.0f; // Hz = raw / 10 + default: + return 1.0f; + } +} +static void serial_mdb_task(void *param) +{ + esp_err_t err; + const mb_parameter_descriptor_t *desc = NULL; + + float voltage[3] = {0}; + float current[3] = {0}; + int watt[3] = {0}; + float energy = 0.0f; + float frequency_hz = 0.0f; // <- armazenar frequência lida (0x010A) + + while (1) + { + for (uint16_t cid = 0; cid < num_device_parameters_orno526; cid++) + { + err = mbc_master_get_cid_info(cid, &desc); + if (err != ESP_OK || !desc) + { + ESP_LOGE(TAG, "mbc_master_get_cid_info(%u) failed: %s", cid, esp_err_to_name(err)); + continue; + } + + void *data_ptr = get_param_ptr(desc); + if (!data_ptr) + { + ESP_LOGE(TAG, "CID %u (%s): null data_ptr", cid, desc->param_key); + continue; + } + + uint8_t type = 0; + err = mbc_master_get_parameter(cid, (char *)desc->param_key, (uint8_t *)data_ptr, &type); + if (err == ESP_OK) + { + float val = 0.0f; + + if (cid == CID_FREQUENCY) + { + // Frequência é U16 (1 registo), escala = /10.0 + uint16_t raw16 = *(uint16_t *)data_ptr; + val = raw16 / 10.0f; + frequency_hz = val; + } + else + { + // Demais CIDs são I32_CDAB (2 registos) + int32_t raw32 = *(int32_t *)data_ptr; + float scale = scale_for_cid(cid); + val = raw32 / scale; + } + + ESP_LOGI(TAG, "%s: %.3f %s", desc->param_key, val, desc->param_units); + + switch (cid) + { + case CID_L1_VOLTAGE: + voltage[0] = val; + break; + case CID_L1_CURRENT: + current[0] = val; + break; + + case CID_ACTIVE_POWER: + watt[0] = (int)lrintf(val); + watt[1] = watt[2] = watt[0]; + break; + + case CID_ACTIVE_ENERGY: + energy = val; // já em kWh (raw/100) + break; + + // CID_FREQUENCY já atualiza 'frequency_hz' acima + default: + break; + } + } + else + { + ESP_LOGE(TAG, "CID %u (%s) read failed: %s", cid, desc->param_key, esp_err_to_name(err)); + } + + vTaskDelay(POLL_INTERVAL); + } + + meter_event_data_t evt = { + .frequency = frequency_hz, // agora preenchido + .power_factor = 0.0f, // (adicione PF se quiser ler 0x010B) + .total_energy = energy, + .source = "GRID", + }; + + memcpy(evt.vrms, voltage, sizeof(evt.vrms)); + memcpy(evt.irms, current, sizeof(evt.irms)); + memcpy(evt.watt, watt, sizeof(evt.watt)); + + esp_event_post(METER_EVENT, METER_EVENT_DATA_READY, &evt, sizeof(evt), pdMS_TO_TICKS(10)); + vTaskDelay(UPDATE_INTERVAL); + } +} + +esp_err_t meter_orno526_init(void) +{ + if (is_initialized) + { + ESP_LOGW(TAG, "meter_orno526 already initialized"); + return ESP_ERR_INVALID_STATE; + } + + ESP_LOGI(TAG, "meter_orno526_init"); + + // ORNO costuma vir 9600, 8E1. Se o teu estiver 8E2, troca os stop bits mais abaixo. + mb_communication_info_t comm = { + .port = MB_PORT_NUM, + .mode = MB_MODE_RTU, + .baudrate = MB_DEV_SPEED, // 9600 + .parity = UART_PARITY_DISABLE, // 8E1 por padrão + }; + + void *handler = NULL; + esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &handler); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "mbc_master_init failed"); + return err; + } + + ESP_ERROR_CHECK(mbc_master_setup(&comm)); + + // Pinos RS-485 (TX, RX, RTS=DE/RE). CTS não usado. + ESP_ERROR_CHECK(uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD, MB_UART_RTS, UART_PIN_NO_CHANGE)); + + // Garanta 8 bits de dados e sem flow-control. + ESP_ERROR_CHECK(uart_set_word_length(MB_PORT_NUM, UART_DATA_8_BITS)); + ESP_ERROR_CHECK(uart_set_hw_flow_ctrl(MB_PORT_NUM, UART_HW_FLOWCTRL_DISABLE, 0)); + + // Stop bits: a maioria usa 1. Se continuar a dar INVALID_RESPONSE, teste 2. + ESP_ERROR_CHECK(uart_set_stop_bits(MB_PORT_NUM, UART_STOP_BITS_1)); + // Alternativa, se o medidor estiver configurado p/ 2 stop bits: + // ESP_ERROR_CHECK(uart_set_stop_bits(MB_PORT_NUM, UART_STOP_BITS_2)); + + ESP_ERROR_CHECK(mbc_master_start()); + ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX)); + + // (Opcional) Logs detalhados para ver TX/RX/frames durante debug: + esp_log_level_set("MB_CONTROLLER_MASTER", ESP_LOG_DEBUG); + esp_log_level_set("MB_PORT_COMMON", ESP_LOG_DEBUG); + esp_log_level_set("MB_SERIAL_MASTER", ESP_LOG_DEBUG); + + vTaskDelay(pdMS_TO_TICKS(5)); + + ESP_ERROR_CHECK(mbc_master_set_descriptor(device_parameters_orno526, num_device_parameters_orno526)); + + is_initialized = true; + return ESP_OK; +} + +esp_err_t meter_orno526_start(void) +{ + + ESP_LOGI(TAG, "meter_orno526_start"); + + if (!is_initialized) + { + ESP_LOGE(TAG, "meter_orno526 not initialized"); + return ESP_ERR_INVALID_STATE; + } + + if (meter_task == NULL) + { + xTaskCreate(serial_mdb_task, "meter_orno526_task", 4096, NULL, 3, &meter_task); + ESP_LOGI(TAG, "meter_orno526 task started"); + } + + return ESP_OK; +} + +void meter_orno526_stop(void) +{ + if (!is_initialized) + { + ESP_LOGW(TAG, "meter_orno526 not initialized"); + return; + } + + ESP_LOGI(TAG, "Stopping meter_orno526"); + + uart_driver_delete(MB_PORT_NUM); + + esp_err_t err = mbc_master_destroy(); + if (err != ESP_OK) + { + ESP_LOGW(TAG, "mbc_master_destroy() returned %s", esp_err_to_name(err)); + } + + is_initialized = false; +} diff --git a/components/meter_manager/driver/meter_orno/meter_orno526.h b/components/meter_manager/driver/meter_orno/meter_orno526.h new file mode 100755 index 0000000..a9533c8 --- /dev/null +++ b/components/meter_manager/driver/meter_orno/meter_orno526.h @@ -0,0 +1,29 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "esp_err.h" + +/** + * @brief Inicializa o driver do medidor ORNO 526 (SPI, mutex, registradores). + */ +esp_err_t meter_orno526_init(void); + +/** + * @brief Inicia a tarefa de leitura de dados do medidor ORNO 526. + */ +esp_err_t meter_orno526_start(void); + +/** + * @brief Para a tarefa de leitura e limpa os dados internos do medidor ORNO 526. + */ +void meter_orno526_stop(void); + + +#ifdef __cplusplus +} +#endif diff --git a/components/meter_manager/driver/meter_orno/modbus_params.h b/components/meter_manager/driver/meter_orno/modbus_params.h index 7b4755b..c02559f 100755 --- a/components/meter_manager/driver/meter_orno/modbus_params.h +++ b/components/meter_manager/driver/meter_orno/modbus_params.h @@ -46,24 +46,30 @@ typedef struct { uint16_t data_block1[150]; } input_reg_params_t; + // Holding Registers (ajustado para os campos usados no ORNO 516) typedef struct { - float l1_current; // 0x0016 - float l2_current; // 0x0018 - float l3_current; // 0x001A + float l1_current; + float l2_current; + float l3_current; - float l1_voltage; // 0x000E - float l2_voltage; // 0x0010 - float l3_voltage; // 0x0012 + float l1_voltage; + float l2_voltage; + float l3_voltage; + + float active_energy; + float reactive_energy; - float total_active_power; // 0x001C - float total_reactive_power; float active_power; float apparent_power; float reactive_power; + + float frequency; + float power_factor; } holding_reg_params_t; + #pragma pack(pop) // Instâncias globais das estruturas diff --git a/components/meter_manager/driver/meter_zigbee/meter_zigbee.c b/components/meter_manager/driver/meter_zigbee/meter_zigbee.c index 02a06da..42b5586 100755 --- a/components/meter_manager/driver/meter_zigbee/meter_zigbee.c +++ b/components/meter_manager/driver/meter_zigbee/meter_zigbee.c @@ -64,9 +64,9 @@ bool meter_zigbee_is_running(void) { } void send_stop_command(void) { - const char *cmd = "stop\n"; // Comando enviado para o outro lado interpretar e dormir - uart_write_bytes(UART_PORT, cmd, strlen(cmd)); - uart_wait_tx_done(UART_PORT, pdMS_TO_TICKS(100)); // Aguarda envio terminar + //const char *cmd = "stop\n"; // Comando enviado para o outro lado interpretar e dormir + //uart_write_bytes(UART_PORT, cmd, strlen(cmd)); + //uart_wait_tx_done(UART_PORT, pdMS_TO_TICKS(100)); // Aguarda envio terminar } static void meter_zigbee_post_event(void) { @@ -115,8 +115,8 @@ static void handle_zigbee_frame(const uint8_t *buf, size_t len) { uint32_t power_raw = (buf[11] << 16) | (buf[12] << 8) | buf[13]; float volt = volt_raw / 10.0f; - float current = current_raw / 100.0f; - float power = power_raw / 1000.0f; + float current = current_raw / 1000.0f; + float power = power_raw; ESP_LOGI(TAG, "Parsed Attr 0x%04X: V=%.1fV I=%.2fA P=%.1fW", attr, volt, current, power); @@ -144,13 +144,13 @@ static void handle_zigbee_frame(const uint8_t *buf, size_t len) { phase_updated[PHASE_L3] = true; break; case ATTR_POWER_FACTOR: - meter_data.power_factor = current; + meter_data.power_factor = 0; break; case ATTR_FREQUENCY: - meter_data.frequency = current; + meter_data.frequency = 0; break; case ATTR_TOTAL_ENERGY: - meter_data.total_energy = current; + meter_data.total_energy = 0; break; default: ESP_LOGW(TAG, "Unknown attr: 0x%04X", attr); @@ -227,9 +227,9 @@ esp_err_t meter_zigbee_start(void) { void meter_zigbee_stop(void) { - send_stop_command(); + //send_stop_command(); - vTaskDelay(pdMS_TO_TICKS(100)); // Aguarda o outro lado processar + //vTaskDelay(pdMS_TO_TICKS(100)); // Aguarda o outro lado processar if (meter_zigbee_task) { vTaskDelete(meter_zigbee_task); diff --git a/components/meter_manager/include/meter_manager.h b/components/meter_manager/include/meter_manager.h index 2f8e350..d9a1609 100755 --- a/components/meter_manager/include/meter_manager.h +++ b/components/meter_manager/include/meter_manager.h @@ -12,8 +12,12 @@ typedef enum { METER_TYPE_ADE7758, // ADE7758 meter METER_TYPE_ORNO513, // ORNO-513 METER_TYPE_ORNO516, // ORNO-516 + METER_TYPE_ORNO526, // ORNO-516 + METER_TYPE_DDS661, // DDS-661 + METER_TYPE_DTS6619, // dts6619 METER_TYPE_MONO_ZIGBEE, // Zigbee single-phase - METER_TYPE_TRIF_ZIGBEE // Zigbee three-phase + METER_TYPE_TRIF_ZIGBEE, // Zigbee three-phase + METER_TYPE_EA777 // EA777 } meter_type_t; /** diff --git a/components/meter_manager/src/meter_manager.c b/components/meter_manager/src/meter_manager.c index a8ea23f..6a30c36 100755 --- a/components/meter_manager/src/meter_manager.c +++ b/components/meter_manager/src/meter_manager.c @@ -1,15 +1,20 @@ #include "meter_manager.h" #include "esp_log.h" + #include "meter_ade7758.h" #include "meter_orno513.h" #include "meter_orno516.h" +#include "meter_orno526.h" +#include "meter_dts6619.h" +#include "meter_dds661.h" #include "meter_zigbee.h" +#include "meter_ea777.h" + #include "nvs_flash.h" #include "nvs.h" #include #include "network_events.h" - static const char *TAG = "meter_manager"; // Tipos de medidores EVSE e GRID @@ -20,48 +25,53 @@ static meter_type_t meter_grid_type = METER_TYPE_NONE; #define NVS_EVSE_MODEL "evse_model" #define NVS_GRID_MODEL "grid_model" +static void meter_manager_network_event_handler(void *arg, esp_event_base_t base, int32_t event_id, void *data) +{ + if (base != NETWORK_EVENTS) + return; -static void meter_manager_network_event_handler(void* arg, esp_event_base_t base, int32_t event_id, void* data){ + switch (event_id) + { + case NETWORK_EVENT_AP_STARTED: + ESP_LOGI(TAG, "Recebido NETWORK_EVENT_AP_STARTED, parando medidor de grid"); + // meter_manager_grid_stop(); + break; - if (base != NETWORK_EVENTS) return; + case NETWORK_EVENT_AP_STOP: + ESP_LOGI(TAG, "Recebido NETWORK_EVENT_AP_STOP, reiniciando medidor de grid"); + // meter_manager_grid_start(); + break; - switch (event_id) { - case NETWORK_EVENT_AP_STARTED: - ESP_LOGI(TAG, "Recebido NETWORK_EVENT_AP_STARTED, parando medidor de grid"); - meter_manager_grid_stop(); - break; + case NETWORK_EVENT_STA_GOT_IP: + ESP_LOGI(TAG, "Recebido NETWORK_EVENT_STA_GOT_IP"); + // opcional: reiniciar ou logar + break; - case NETWORK_EVENT_AP_STOP: - ESP_LOGI(TAG, "Recebido NETWORK_EVENT_AP_STOP, reiniciando medidor de grid"); - meter_manager_grid_start(); - break; - - case NETWORK_EVENT_STA_GOT_IP: - ESP_LOGI(TAG, "Recebido NETWORK_EVENT_STA_GOT_IP"); - // opcional: reiniciar ou logar - break; - - default: - break; + default: + break; } } - // Função unificada para ler ou inicializar um modelo de medidor -static esp_err_t load_or_init_meter_model(const char *key, meter_type_t *type) { +static esp_err_t load_or_init_meter_model(const char *key, meter_type_t *type) +{ nvs_handle_t handle; esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle); - if (err != ESP_OK) { + if (err != ESP_OK) + { ESP_LOGE(TAG, "Failed to open NVS handle for %s: %s", key, esp_err_to_name(err)); return err; } uint8_t value = 0; err = nvs_get_u8(handle, key, &value); - if (err == ESP_OK && value <= METER_TYPE_TRIF_ZIGBEE) { + if (err == ESP_OK && value < 255) + { *type = (meter_type_t)value; ESP_LOGI(TAG, "Loaded meter type %d from NVS key '%s'", value, key); - } else { + } + else + { *type = METER_TYPE_NONE; nvs_set_u8(handle, key, *type); nvs_commit(handle); @@ -72,19 +82,24 @@ static esp_err_t load_or_init_meter_model(const char *key, meter_type_t *type) { return ESP_OK; } -static esp_err_t write_meter_model_to_nvs(const char *key, meter_type_t meter_type) { +static esp_err_t write_meter_model_to_nvs(const char *key, meter_type_t meter_type) +{ nvs_handle_t handle; esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle); - if (err != ESP_OK) { + if (err != ESP_OK) + { ESP_LOGE(TAG, "Failed to open NVS handle for writing"); return err; } err = nvs_set_u8(handle, key, (uint8_t)meter_type); - if (err == ESP_OK) { + if (err == ESP_OK) + { err = nvs_commit(handle); ESP_LOGI(TAG, "Saved meter type %d to NVS key '%s'", meter_type, key); - } else { + } + else + { ESP_LOGE(TAG, "Failed to write meter type to NVS key '%s'", key); } @@ -92,7 +107,6 @@ static esp_err_t write_meter_model_to_nvs(const char *key, meter_type_t meter_ty return err; } - /** * @brief Initializes the meter manager system. * @@ -102,16 +116,18 @@ static esp_err_t write_meter_model_to_nvs(const char *key, meter_type_t meter_ty * * @return esp_err_t ESP_OK on success, or an error code. */ -esp_err_t meter_manager_init(void) { +esp_err_t meter_manager_init(void) +{ esp_err_t err; - // Initialize EVSE meter - //err = meter_manager_evse_init(); - //if (err != ESP_OK) return err; + // Initialize EVSE meter (habilite quando quiser) + // err = meter_manager_evse_init(); + // if (err != ESP_OK) return err; // Initialize GRID meter err = meter_manager_grid_init(); - if (err != ESP_OK) return err; + if (err != ESP_OK) + return err; // Register handler for custom network events ESP_LOGI(TAG, "Registering network event handler"); @@ -121,7 +137,6 @@ esp_err_t meter_manager_init(void) { NULL); } - /** * @brief Starts all configured meters (EVSE and GRID). * @@ -130,21 +145,22 @@ esp_err_t meter_manager_init(void) { * * @return esp_err_t ESP_OK on success, or an error code from one of the start calls. */ -esp_err_t meter_manager_start(void) { +esp_err_t meter_manager_start(void) +{ esp_err_t err; - // Start EVSE meter - //err = meter_manager_evse_start(); - //if (err != ESP_OK) return err; + // Start EVSE meter (habilite quando quiser) + // err = meter_manager_evse_start(); + // if (err != ESP_OK) return err; // Start GRID meter err = meter_manager_grid_start(); - if (err != ESP_OK) return err; + if (err != ESP_OK) + return err; return ESP_OK; } - /** * @brief Stops all meters and unregisters event handlers. * @@ -153,153 +169,307 @@ esp_err_t meter_manager_start(void) { * * @return esp_err_t ESP_OK on success, or an error code. */ -esp_err_t meter_manager_stop(void) { +esp_err_t meter_manager_stop(void) +{ esp_err_t err; // Stop EVSE meter - //err = meter_manager_evse_stop(); - //if (err != ESP_OK) return err; + // err = meter_manager_evse_stop(); + // if (err != ESP_OK) return err; // Stop GRID meter err = meter_manager_grid_stop(); - if (err != ESP_OK) return err; + if (err != ESP_OK) + return err; return ESP_OK; } +// ---------- EVSE ---------- - - -// Função para inicializar o medidor EVSE -esp_err_t meter_manager_evse_init() { +esp_err_t meter_manager_evse_init() +{ esp_err_t err = load_or_init_meter_model(NVS_EVSE_MODEL, &meter_evse_type); - if (err != ESP_OK) return err; + if (err != ESP_OK) + return err; ESP_LOGI(TAG, "Initializing EVSE meter of type %s", meter_type_to_str(meter_evse_type)); - switch (meter_evse_type) { - case METER_TYPE_NONE: return ESP_OK; - case METER_TYPE_ADE7758: return meter_ade7758_init(); - case METER_TYPE_ORNO513: return meter_orno513_init(); - case METER_TYPE_ORNO516: return meter_orno516_init(); - case METER_TYPE_MONO_ZIGBEE: - case METER_TYPE_TRIF_ZIGBEE: return meter_zigbee_init(); - default: return ESP_ERR_INVALID_ARG; + switch (meter_evse_type) + { + case METER_TYPE_NONE: + return ESP_OK; + case METER_TYPE_ADE7758: + return meter_ade7758_init(); + case METER_TYPE_ORNO513: + return meter_orno513_init(); + case METER_TYPE_ORNO516: + return meter_orno516_init(); + case METER_TYPE_ORNO526: + return meter_orno526_init(); + case METER_TYPE_DTS6619: + return meter_dts6619_init(); + case METER_TYPE_DDS661: + return meter_dds661_init(); + case METER_TYPE_EA777: + return meter_ea777_init(); + case METER_TYPE_MONO_ZIGBEE: + case METER_TYPE_TRIF_ZIGBEE: + return meter_zigbee_init(); + default: + return ESP_ERR_INVALID_ARG; } } -esp_err_t meter_manager_grid_init() { - esp_err_t err = load_or_init_meter_model(NVS_GRID_MODEL, &meter_grid_type); - if (err != ESP_OK) return err; - - ESP_LOGI(TAG, "Initializing GRID meter of type %s", meter_type_to_str(meter_grid_type)); - - switch (meter_grid_type) { - case METER_TYPE_NONE: return ESP_OK; - case METER_TYPE_ADE7758: return meter_ade7758_init(); - case METER_TYPE_ORNO513: return meter_orno513_init(); - case METER_TYPE_ORNO516: return meter_orno516_init(); - case METER_TYPE_MONO_ZIGBEE: - case METER_TYPE_TRIF_ZIGBEE: return meter_zigbee_init(); - default: return ESP_ERR_INVALID_ARG; +esp_err_t meter_manager_evse_start() +{ + meter_type_t type = meter_manager_evse_get_model(); + switch (type) + { + case METER_TYPE_NONE: + return ESP_OK; + case METER_TYPE_ADE7758: + return meter_ade7758_start(); + case METER_TYPE_ORNO513: + return meter_orno513_start(); + case METER_TYPE_ORNO516: + return meter_orno516_start(); + case METER_TYPE_ORNO526: + return meter_orno526_start(); + case METER_TYPE_DTS6619: + return meter_dts6619_start(); + case METER_TYPE_DDS661: + return meter_dds661_start(); + case METER_TYPE_EA777: + return meter_ea777_start(); + case METER_TYPE_MONO_ZIGBEE: + case METER_TYPE_TRIF_ZIGBEE: + return meter_zigbee_start(); + default: + return ESP_ERR_INVALID_ARG; } } -esp_err_t meter_manager_grid_start() { - meter_type_t type = meter_manager_grid_get_model(); - switch (type) { - case METER_TYPE_NONE: return ESP_OK; - case METER_TYPE_ADE7758: return meter_ade7758_start(); - case METER_TYPE_ORNO513: return meter_orno513_start(); - case METER_TYPE_ORNO516: return meter_orno516_start(); - case METER_TYPE_MONO_ZIGBEE: - case METER_TYPE_TRIF_ZIGBEE: return meter_zigbee_start(); - default: return ESP_ERR_INVALID_ARG; - } -} - -esp_err_t meter_manager_grid_stop(void) { - meter_type_t type = meter_manager_grid_get_model(); - switch (type) { - case METER_TYPE_NONE: return ESP_OK; - case METER_TYPE_ADE7758: meter_ade7758_stop(); break; - case METER_TYPE_ORNO513: meter_orno513_stop(); break; - case METER_TYPE_ORNO516: meter_orno516_stop(); break; - case METER_TYPE_MONO_ZIGBEE: - case METER_TYPE_TRIF_ZIGBEE: meter_zigbee_stop(); break; - default: return ESP_ERR_INVALID_ARG; +esp_err_t meter_manager_evse_stop(void) +{ + meter_type_t type = meter_manager_evse_get_model(); + switch (type) + { + case METER_TYPE_NONE: + return ESP_OK; + case METER_TYPE_ADE7758: + meter_ade7758_stop(); + break; + case METER_TYPE_ORNO513: + meter_orno513_stop(); + break; + case METER_TYPE_ORNO516: + meter_orno516_stop(); + break; + case METER_TYPE_ORNO526: + meter_orno526_stop(); + break; + case METER_TYPE_DTS6619: + meter_dts6619_stop(); + break; + case METER_TYPE_DDS661: + meter_dds661_stop(); + break; + case METER_TYPE_EA777: + meter_ea777_stop(); + break; + case METER_TYPE_MONO_ZIGBEE: + case METER_TYPE_TRIF_ZIGBEE: + meter_zigbee_stop(); + break; + default: + return ESP_ERR_INVALID_ARG; } return ESP_OK; } +// ---------- GRID ---------- -esp_err_t meter_manager_evse_set_model(meter_type_t meter_type) { +esp_err_t meter_manager_grid_init() +{ + esp_err_t err = load_or_init_meter_model(NVS_GRID_MODEL, &meter_grid_type); + if (err != ESP_OK) + return err; + + ESP_LOGI(TAG, "Initializing GRID meter of type %s", meter_type_to_str(meter_grid_type)); + + switch (meter_grid_type) // corrigido: ORNO-513 -> driver orno513 + { + case METER_TYPE_NONE: + return ESP_OK; + case METER_TYPE_ADE7758: + return meter_ade7758_init(); + case METER_TYPE_ORNO513: + return meter_orno513_init(); + case METER_TYPE_ORNO516: + return meter_orno516_init(); + case METER_TYPE_ORNO526: + return meter_orno526_init(); + case METER_TYPE_DTS6619: + return meter_dts6619_init(); + case METER_TYPE_DDS661: + return meter_dds661_init(); + case METER_TYPE_EA777: + return meter_ea777_init(); + case METER_TYPE_MONO_ZIGBEE: + case METER_TYPE_TRIF_ZIGBEE: + return meter_zigbee_init(); + default: + return ESP_ERR_INVALID_ARG; + } +} + +esp_err_t meter_manager_grid_start() +{ + meter_type_t type = meter_manager_grid_get_model(); + switch (type) + { + case METER_TYPE_NONE: + return ESP_OK; + case METER_TYPE_ADE7758: + return meter_ade7758_start(); + case METER_TYPE_ORNO513: + return meter_orno513_start(); // corrigido + case METER_TYPE_ORNO516: + return meter_orno516_start(); + case METER_TYPE_ORNO526: + return meter_orno526_start(); + case METER_TYPE_DTS6619: + return meter_dts6619_start(); + case METER_TYPE_DDS661: + return meter_dds661_start(); + case METER_TYPE_EA777: + return meter_ea777_start(); + case METER_TYPE_MONO_ZIGBEE: + case METER_TYPE_TRIF_ZIGBEE: + return meter_zigbee_start(); + default: + return ESP_ERR_INVALID_ARG; + } +} + +esp_err_t meter_manager_grid_stop(void) +{ + meter_type_t type = meter_manager_grid_get_model(); + switch (type) + { + case METER_TYPE_NONE: + return ESP_OK; + case METER_TYPE_ADE7758: + meter_ade7758_stop(); + break; + case METER_TYPE_ORNO513: + meter_orno513_stop(); // corrigido + break; + case METER_TYPE_ORNO516: + meter_orno516_stop(); + break; + case METER_TYPE_ORNO526: + meter_orno526_stop(); + break; + case METER_TYPE_DTS6619: + meter_dts6619_stop(); + break; + case METER_TYPE_DDS661: + meter_dds661_stop(); + break; + case METER_TYPE_EA777: + meter_ea777_stop(); + break; + case METER_TYPE_MONO_ZIGBEE: + case METER_TYPE_TRIF_ZIGBEE: + meter_zigbee_stop(); + break; + default: + return ESP_ERR_INVALID_ARG; + } + return ESP_OK; +} + +// ---------- Utilidades ---------- + +esp_err_t meter_manager_evse_set_model(meter_type_t meter_type) +{ meter_evse_type = meter_type; return write_meter_model_to_nvs(NVS_EVSE_MODEL, meter_evse_type); } -esp_err_t meter_manager_grid_set_model(meter_type_t meter_type) { +esp_err_t meter_manager_grid_set_model(meter_type_t meter_type) +{ meter_grid_type = meter_type; return write_meter_model_to_nvs(NVS_GRID_MODEL, meter_grid_type); } -esp_err_t meter_manager_evse_start() { - meter_type_t type = meter_manager_evse_get_model(); - switch (type) { - case METER_TYPE_NONE: return ESP_OK; - case METER_TYPE_ADE7758: return meter_ade7758_start(); - case METER_TYPE_ORNO513: return meter_orno513_start(); - case METER_TYPE_ORNO516: return meter_orno516_start(); - case METER_TYPE_MONO_ZIGBEE: - case METER_TYPE_TRIF_ZIGBEE: return meter_zigbee_start(); - default: return ESP_ERR_INVALID_ARG; - } -} - -esp_err_t meter_manager_evse_stop(void) { - meter_type_t type = meter_manager_evse_get_model(); - switch (type) { - case METER_TYPE_NONE: return ESP_OK; - case METER_TYPE_ADE7758: meter_ade7758_stop(); break; - case METER_TYPE_ORNO513: meter_orno513_stop(); break; - case METER_TYPE_ORNO516: meter_orno516_stop(); break; - case METER_TYPE_MONO_ZIGBEE: - case METER_TYPE_TRIF_ZIGBEE: meter_zigbee_stop(); break; - default: return ESP_ERR_INVALID_ARG; - } - return ESP_OK; -} - -bool meter_manager_evse_is_enabled(void) { +bool meter_manager_evse_is_enabled(void) +{ return meter_manager_evse_get_model() != METER_TYPE_NONE; } -meter_type_t meter_manager_evse_get_model(void) { +meter_type_t meter_manager_evse_get_model(void) +{ return meter_evse_type; } -meter_type_t meter_manager_grid_get_model(void) { +meter_type_t meter_manager_grid_get_model(void) +{ return meter_grid_type; } -const char* meter_type_to_str(meter_type_t type) { - switch (type) { - case METER_TYPE_NONE: return "NENHUM"; - case METER_TYPE_ADE7758: return "IC ADE"; - case METER_TYPE_ORNO513: return "ORNO-513"; - case METER_TYPE_ORNO516: return "ORNO-516"; - case METER_TYPE_MONO_ZIGBEE: return "MONO-ZIGBEE"; - case METER_TYPE_TRIF_ZIGBEE: return "TRIF-ZIGBEE"; - default: return "NENHUM"; +const char *meter_type_to_str(meter_type_t type) +{ + switch (type) + { + case METER_TYPE_NONE: + return "NENHUM"; + case METER_TYPE_ADE7758: + return "IC ADE"; + case METER_TYPE_ORNO513: + return "ORNO-513"; + case METER_TYPE_ORNO516: + return "ORNO-516"; + case METER_TYPE_ORNO526: + return "ORNO-526"; + case METER_TYPE_DTS6619: + return "DTS-6619"; + case METER_TYPE_DDS661: + return "DDS-661"; + case METER_TYPE_MONO_ZIGBEE: + return "MONO-ZIGBEE"; + case METER_TYPE_TRIF_ZIGBEE: + return "TRIF-ZIGBEE"; + case METER_TYPE_EA777: + return "EA-777"; + default: + return "NENHUM"; } } -meter_type_t string_to_meter_type(const char *str) { - if (!str) return METER_TYPE_NONE; - if (strcmp(str, "IC ADE") == 0) return METER_TYPE_ADE7758; - if (strcmp(str, "ORNO-513") == 0) return METER_TYPE_ORNO513; - if (strcmp(str, "ORNO-516") == 0) return METER_TYPE_ORNO516; - if (strcmp(str, "MONO-ZIGBEE") == 0) return METER_TYPE_MONO_ZIGBEE; - if (strcmp(str, "TRIF-ZIGBEE") == 0) return METER_TYPE_TRIF_ZIGBEE; +meter_type_t string_to_meter_type(const char *str) +{ + if (!str) + return METER_TYPE_NONE; + if (strcmp(str, "IC ADE") == 0) + return METER_TYPE_ADE7758; + if (strcmp(str, "ORNO-513") == 0) + return METER_TYPE_ORNO513; + if (strcmp(str, "ORNO-516") == 0) + return METER_TYPE_ORNO516; + if (strcmp(str, "ORNO-526") == 0) + return METER_TYPE_ORNO526; + if (strcmp(str, "DTS-6619") == 0) + return METER_TYPE_DTS6619; + if (strcmp(str, "DDS-661") == 0) + return METER_TYPE_DDS661; + if (strcmp(str, "MONO-ZIGBEE") == 0) + return METER_TYPE_MONO_ZIGBEE; + if (strcmp(str, "TRIF-ZIGBEE") == 0) + return METER_TYPE_TRIF_ZIGBEE; + if (strcmp(str, "EA-777") == 0) + return METER_TYPE_EA777; return METER_TYPE_NONE; } diff --git a/components/network/src/network.c b/components/network/src/network.c index df7c013..fbde1b8 100755 --- a/components/network/src/network.c +++ b/components/network/src/network.c @@ -1,155 +1,267 @@ +// ========================= +// wifi.c (ESP-IDF v5.4.2) +// ========================= + #include +#include +#include + #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" + #include "esp_log.h" #include "esp_wifi.h" #include "esp_event.h" #include "esp_netif.h" #include "esp_mac.h" #include "nvs.h" +#include "nvs_flash.h" #include "mdns.h" #include "network_events.h" #include "network.h" - -#define AP_SSID "plx-%02x%02x%02x" - -#define MDNS_SSID "plx%02x" +// ----------------------------------------------------------------------------- +// Config +// ----------------------------------------------------------------------------- +#define AP_SSID "plx-%02x%02x%02x" // SSID do AP (usa 3 bytes do MAC) +#define MDNS_SSID "plx%02x" // hostname mDNS (usa 2 bytes do MAC) #define NVS_NAMESPACE "wifi" #define NVS_ENABLED "enabled" #define NVS_SSID "ssid" #define NVS_PASSWORD "password" +// Comprimentos com terminador +#define SSID_MAX_LEN 32 +#define PASS_MAX_LEN 64 // 63 chars + '\0' +#define SSID_BUF_SZ (SSID_MAX_LEN + 1) // 33 +#define PASS_BUF_SZ (PASS_MAX_LEN + 1) // 65 + static const char *TAG = "wifi"; +// ----------------------------------------------------------------------------- +// Estado global +// ----------------------------------------------------------------------------- static nvs_handle_t nvs; - static esp_netif_t *sta_netif; - static esp_netif_t *ap_netif; - EventGroupHandle_t wifi_event_group; +// Backoff simples para reconexão STA (agora sem delay no event handler) +static int s_retry_count = 0; +static const int s_retry_max = 7; + +// ----------------------------------------------------------------------------- +// Helpers +// ----------------------------------------------------------------------------- + +// Lê string do NVS com segurança (trunca se necessário) +static esp_err_t nvs_get_str_safe(nvs_handle_t h, const char *key, char *out, size_t out_sz) +{ + if (!out || out_sz == 0) + return ESP_ERR_INVALID_ARG; + out[0] = '\0'; + + size_t need = 0; + esp_err_t err = nvs_get_str(h, key, NULL, &need); + if (err == ESP_ERR_NVS_NOT_FOUND) + return ESP_OK; + if (err != ESP_OK) + return err; + + if (need == 0) + return ESP_OK; // vazio + + if (need > out_sz) + { + // Truncar de forma segura + char *tmp = (char *)malloc(need); + if (!tmp) + return ESP_ERR_NO_MEM; + err = nvs_get_str(h, key, tmp, &need); + if (err == ESP_OK) + { + snprintf(out, out_sz, "%s", tmp); + } + free(tmp); + return err; + } + return nvs_get_str(h, key, out, &need); +} + +// ----------------------------------------------------------------------------- +// Eventos +// ----------------------------------------------------------------------------- static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { - ESP_LOGI(TAG, "event_handler"); - if (event_base == WIFI_EVENT) { - if (event_id == WIFI_EVENT_AP_STACONNECTED) + switch (event_id) { - ESP_LOGI(TAG, "STA connected"); + case WIFI_EVENT_AP_STACONNECTED: + { + ESP_LOGI(TAG, "AP: STA connected"); wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data; ESP_LOGI(TAG, "WiFi AP " MACSTR " join, AID=%d", MAC2STR(event->mac), event->aid); xEventGroupClearBits(wifi_event_group, WIFI_AP_DISCONNECTED_BIT); xEventGroupSetBits(wifi_event_group, WIFI_AP_CONNECTED_BIT); + break; } - if (event_id == WIFI_EVENT_AP_STADISCONNECTED) + case WIFI_EVENT_AP_STADISCONNECTED: { - ESP_LOGI(TAG, "AP STA disconnected"); + ESP_LOGI(TAG, "AP: STA disconnected"); wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data; ESP_LOGI(TAG, "WiFi AP " MACSTR " leave, AID=%d", MAC2STR(event->mac), event->aid); xEventGroupClearBits(wifi_event_group, WIFI_AP_CONNECTED_BIT); xEventGroupSetBits(wifi_event_group, WIFI_AP_DISCONNECTED_BIT); + break; } - if (event_id == WIFI_EVENT_STA_DISCONNECTED) - { - ESP_LOGI(TAG, "STA disconnected"); - xEventGroupClearBits(wifi_event_group, WIFI_STA_CONNECTED_BIT); - xEventGroupSetBits(wifi_event_group, WIFI_STA_DISCONNECTED_BIT); - esp_wifi_connect(); - } - if (event_id == WIFI_EVENT_STA_START) + case WIFI_EVENT_STA_START: { ESP_LOGI(TAG, "STA start"); + s_retry_count = 0; esp_wifi_connect(); + break; + } + case WIFI_EVENT_STA_DISCONNECTED: + { + xEventGroupClearBits(wifi_event_group, WIFI_STA_CONNECTED_BIT); + xEventGroupSetBits(wifi_event_group, WIFI_STA_DISCONNECTED_BIT); + + wifi_event_sta_disconnected_t *ev = (wifi_event_sta_disconnected_t *)event_data; + ESP_LOGW(TAG, "STA disconnected, reason=%d", ev ? ev->reason : -1); + + // NÃO bloquear o event loop com vTaskDelay + if (s_retry_count < s_retry_max) + { + esp_err_t err = esp_wifi_connect(); + if (err == ESP_OK) + { + s_retry_count++; + ESP_LOGI(TAG, "Retrying connection (%d/%d)", s_retry_count, s_retry_max); + } + else + { + ESP_LOGW(TAG, "esp_wifi_connect failed (%d)", err); + } + } + else + { + ESP_LOGE(TAG, "Max retries reached"); + } + break; + } + default: + break; } } else if (event_base == IP_EVENT) { - ESP_LOGI(TAG, "event_base == IP_EVENT"); - - if (event_id == IP_EVENT_STA_GOT_IP || event_id == IP_EVENT_GOT_IP6) + if (event_id == IP_EVENT_STA_GOT_IP) { - if (event_id == IP_EVENT_STA_GOT_IP) - { - ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; - ESP_LOGI(TAG, "WiFi STA got ip: " IPSTR, IP2STR(&event->ip_info.ip)); - } - else - { - ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data; - ESP_LOGI(TAG, "WiFi STA got ip6: " IPV6STR, IPV62STR(event->ip6_info.ip)); - } + ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; + ESP_LOGI(TAG, "WiFi STA got ip: " IPSTR, IP2STR(&event->ip_info.ip)); xEventGroupClearBits(wifi_event_group, WIFI_STA_DISCONNECTED_BIT); xEventGroupSetBits(wifi_event_group, WIFI_STA_CONNECTED_BIT); + s_retry_count = 0; + } + else if (event_id == IP_EVENT_GOT_IP6) + { + ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data; + ESP_LOGI(TAG, "WiFi STA got ip6: " IPV6STR, IPV62STR(event->ip6_info.ip)); + xEventGroupClearBits(wifi_event_group, WIFI_STA_DISCONNECTED_BIT); + xEventGroupSetBits(wifi_event_group, WIFI_STA_CONNECTED_BIT); + s_retry_count = 0; } } } +// ----------------------------------------------------------------------------- +// Config STA/AP +// ----------------------------------------------------------------------------- static void sta_set_config(void) { - ESP_LOGI(TAG, "sta_set_config"); - if (wifi_get_enabled()) - { - wifi_config_t wifi_config = { - .sta = { - .pmf_cfg = { - .capable = true, - .required = false}}}; - wifi_get_ssid((char *)wifi_config.sta.ssid); - wifi_get_password((char *)wifi_config.sta.password); + if (!wifi_get_enabled()) + return; - esp_wifi_set_mode(WIFI_MODE_STA); - esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config); + wifi_config_t wifi_config = {0}; + wifi_config.sta.pmf_cfg.capable = true; + wifi_config.sta.pmf_cfg.required = false; + + // buffers "seguros" vindos da NVS (estes sim têm terminador) + char ssid_buf[SSID_BUF_SZ] = {0}; // 33 (32 + '\0') + char pass_buf[PASS_BUF_SZ] = {0}; // 65 (64 + '\0') + wifi_get_ssid(ssid_buf); + wifi_get_password(pass_buf); + + // Copiar **sem** terminador para os campos do esp_wifi (32/64 bytes) + // SSID: max 32 + size_t ssid_len = strnlen(ssid_buf, SSID_MAX_LEN); // até 32 + memcpy(wifi_config.sta.ssid, ssid_buf, ssid_len); + + // Password WPA/WPA2: 8..63 chars (campo tem 64 bytes) + // (se usares rede aberta, pass_len pode ser 0) + size_t pass_len = strnlen(pass_buf, 63); // até 63 + memcpy(wifi_config.sta.password, pass_buf, pass_len); + if (pass_len <= 63) + { + wifi_config.sta.password[pass_len] = '\0'; } + + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); // v5.x } static void ap_set_config(void) { - ESP_LOGI(TAG, "ap_set_config"); - wifi_config_t wifi_ap_config = { - .ap = { - .max_connection = 1, - .authmode = WIFI_AUTH_OPEN}}; + wifi_config_t wifi_ap_config = {0}; + wifi_ap_config.ap.max_connection = 1; + wifi_ap_config.ap.authmode = WIFI_AUTH_OPEN; // para portal cativo, por exemplo + uint8_t mac[6]; - esp_wifi_get_mac(ESP_IF_WIFI_AP, mac); - sprintf((char *)wifi_ap_config.ap.ssid, AP_SSID, mac[3], mac[4], mac[5]); + esp_wifi_get_mac(WIFI_IF_AP, mac); + snprintf((char *)wifi_ap_config.ap.ssid, sizeof(wifi_ap_config.ap.ssid), + AP_SSID, mac[3], mac[4], mac[5]); // "plx-XXXXXX" - wifi_config_t wifi_sta_config = {0}; - - esp_wifi_set_mode(WIFI_MODE_APSTA); - esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_ap_config); - esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config); + // Só AP (não mexer na config STA aqui para não a limpar) + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_ap_config)); } +// ----------------------------------------------------------------------------- +// Arranque STA +// ----------------------------------------------------------------------------- static void sta_try_start(void) { - ESP_LOGI(TAG, "sta_try_start"); sta_set_config(); if (wifi_get_enabled()) { ESP_LOGI(TAG, "Starting STA"); - esp_wifi_start(); + esp_err_t e = esp_wifi_start(); + if (e != ESP_OK && e != ESP_ERR_WIFI_CONN) + { + ESP_LOGW(TAG, "esp_wifi_start returned %d", e); + } xEventGroupSetBits(wifi_event_group, WIFI_STA_MODE_BIT); } } +// ----------------------------------------------------------------------------- +// API pública +// ----------------------------------------------------------------------------- void wifi_ini(void) { - - ESP_LOGI(TAG, "Wifi init"); + // Abre NVS (assume que nvs_flash_init() já foi chamado no boot geral) ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs)); wifi_event_group = xEventGroupCreate(); @@ -160,108 +272,125 @@ void wifi_ini(void) sta_netif = esp_netif_create_default_wifi_sta(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); - char chargeid[6]; + // mDNS: usa dois bytes do MAC para identificar uint8_t mac[6]; - esp_wifi_get_mac(ESP_IF_WIFI_AP, mac); - sprintf((char *)chargeid, MDNS_SSID, 0); + esp_wifi_get_mac(WIFI_IF_STA, mac); + char chargeid[16]; + // ex.: "plx00" + snprintf(chargeid, sizeof(chargeid), MDNS_SSID, 0); + + // Hostname das interfaces alinhado com o mDNS + ESP_ERROR_CHECK(esp_netif_set_hostname(sta_netif, chargeid)); + ESP_ERROR_CHECK(esp_netif_set_hostname(ap_netif, chargeid)); ESP_ERROR_CHECK(mdns_init()); ESP_ERROR_CHECK(mdns_hostname_set(chargeid)); ESP_ERROR_CHECK(mdns_instance_name_set("EVSE controller")); sta_try_start(); - } -esp_netif_t *wifi_get_sta_netif(void) -{ - return sta_netif; -} - -esp_netif_t *wifi_get_ap_netif(void) -{ - return ap_netif; -} +esp_netif_t *wifi_get_sta_netif(void) { return sta_netif; } +esp_netif_t *wifi_get_ap_netif(void) { return ap_netif; } esp_err_t wifi_set_config(bool enabled, const char *ssid, const char *password) { + ESP_LOGI(TAG, "wifi_set_config(enabled=%d)", enabled); - - ESP_LOGI(TAG, "wifi_set_config(enabled=%d, ssid=\"%s\")", enabled, ssid?:""); - - + // Validação (quando habilitar STA) if (enabled) { - if (ssid == NULL || strlen(ssid) == 0) + // SSID 1..32 + if (ssid && (strlen(ssid) == 0 || strlen(ssid) > SSID_MAX_LEN)) + { + ESP_LOGE(TAG, "SSID out of range"); + return ESP_ERR_INVALID_ARG; + } + if (!ssid) { size_t len = 0; - nvs_get_str(nvs, NVS_SSID, NULL, &len); - if (len <= 1) + esp_err_t e = nvs_get_str(nvs, NVS_SSID, NULL, &len); + if (e != ESP_OK || len <= 1) { ESP_LOGE(TAG, "Required SSID"); return ESP_ERR_INVALID_ARG; } } + // Password: 8..63 (se não for vazia). Aceita "" para rede open (caso uses). + if (password) + { + size_t lp = strlen(password); + if (lp != 0 && (lp < 8 || lp > 63)) + { + ESP_LOGE(TAG, "Password length must be 8..63"); + return ESP_ERR_INVALID_ARG; + } + } } - if (ssid != NULL && strlen(ssid) > 32) - { - ESP_LOGE(TAG, "SSID out of range"); - return ESP_ERR_INVALID_ARG; - } - - if (password != NULL && strlen(password) > 32) - { - ESP_LOGE(TAG, "Password out of range"); - return ESP_ERR_INVALID_ARG; - } - - nvs_set_u8(nvs, NVS_ENABLED, enabled); - if (ssid != NULL) - { - nvs_set_str(nvs, NVS_SSID, ssid); - } - if (password != NULL) - { - nvs_set_str(nvs, NVS_PASSWORD, password); - } - nvs_commit(nvs); + // Persiste no NVS + ESP_ERROR_CHECK(nvs_set_u8(nvs, NVS_ENABLED, enabled)); + if (ssid) + ESP_ERROR_CHECK(nvs_set_str(nvs, NVS_SSID, ssid)); + if (password) + ESP_ERROR_CHECK(nvs_set_str(nvs, NVS_PASSWORD, password)); + ESP_ERROR_CHECK(nvs_commit(nvs)); + // Reinicia modo ESP_LOGI(TAG, "Stopping AP/STA"); xEventGroupClearBits(wifi_event_group, WIFI_AP_MODE_BIT | WIFI_STA_MODE_BIT); - esp_wifi_stop(); + esp_err_t e = esp_wifi_stop(); + if (e != ESP_OK && e != ESP_ERR_WIFI_NOT_INIT && e != ESP_ERR_WIFI_STOP_STATE) + { + ESP_LOGW(TAG, "esp_wifi_stop returned %d", e); + } sta_try_start(); - return ESP_OK; } uint16_t wifi_scan(wifi_scan_ap_t *scan_aps) { - ESP_LOGI(TAG, "wifi_scan"); + if (!scan_aps) + return 0; + uint16_t number = WIFI_SCAN_SCAN_LIST_SIZE; wifi_ap_record_t ap_info[WIFI_SCAN_SCAN_LIST_SIZE]; uint16_t ap_count = 0; memset(ap_info, 0, sizeof(ap_info)); - esp_wifi_scan_start(NULL, true); - esp_wifi_scan_get_ap_records(&number, ap_info); - esp_wifi_scan_get_ap_num(&ap_count); + esp_err_t err = esp_wifi_scan_start(NULL, true); + if (err != ESP_OK) + { + ESP_LOGW(TAG, "esp_wifi_scan_start failed (%d)", err); + return 0; + } + + err = esp_wifi_scan_get_ap_records(&number, ap_info); + if (err != ESP_OK) + { + ESP_LOGW(TAG, "esp_wifi_scan_get_ap_records failed (%d)", err); + return 0; + } + + err = esp_wifi_scan_get_ap_num(&ap_count); + if (err != ESP_OK) + { + ESP_LOGW(TAG, "esp_wifi_scan_get_ap_num failed (%d)", err); + return 0; + } ESP_LOGI(TAG, "wifi_scan --- %d", ap_count); for (int i = 0; (i < WIFI_SCAN_SCAN_LIST_SIZE) && (i < ap_count); i++) { - - ESP_LOGI(TAG, "wifi_scan ---"); - - strcpy(scan_aps[i].ssid, (const char *)ap_info[i].ssid); + // garante que scan_aps[i].ssid tenha pelo menos 33 bytes + snprintf(scan_aps[i].ssid, SSID_BUF_SZ, "%s", (const char *)ap_info[i].ssid); scan_aps[i].rssi = ap_info[i].rssi; scan_aps[i].auth = ap_info[i].authmode != WIFI_AUTH_OPEN; } @@ -271,23 +400,30 @@ uint16_t wifi_scan(wifi_scan_ap_t *scan_aps) bool wifi_get_enabled(void) { - uint8_t value = false; - nvs_get_u8(nvs, NVS_ENABLED, &value); + uint8_t value = 0; + esp_err_t e = nvs_get_u8(nvs, NVS_ENABLED, &value); + if (e == ESP_ERR_NVS_NOT_FOUND) + return false; + if (e != ESP_OK) + { + ESP_LOGW(TAG, "nvs_get_u8(NVS_ENABLED) failed (%d), assuming disabled", e); + return false; + } return value; } void wifi_get_ssid(char *value) { - size_t len = 32; - value[0] = '\0'; - nvs_get_str(nvs, NVS_SSID, value, &len); + if (!value) + return; + nvs_get_str_safe(nvs, NVS_SSID, value, SSID_BUF_SZ); // 33 } void wifi_get_password(char *value) { - size_t len = 64; - value[0] = '\0'; - nvs_get_str(nvs, NVS_PASSWORD, value, &len); + if (!value) + return; + nvs_get_str_safe(nvs, NVS_PASSWORD, value, PASS_BUF_SZ); // 65 } void wifi_ap_start(void) @@ -300,7 +436,11 @@ void wifi_ap_start(void) esp_wifi_stop(); ap_set_config(); - esp_wifi_start(); + esp_err_t e = esp_wifi_start(); + if (e != ESP_OK && e != ESP_ERR_WIFI_CONN) + { + ESP_LOGW(TAG, "esp_wifi_start (AP) returned %d", e); + } xEventGroupSetBits(wifi_event_group, WIFI_AP_MODE_BIT); } @@ -319,7 +459,9 @@ void wifi_ap_stop(void) bool wifi_is_ap(void) { - wifi_mode_t mode; - esp_wifi_get_mode(&mode); - return mode == WIFI_MODE_APSTA; + if (!wifi_event_group) + return false; + + EventBits_t bits = xEventGroupGetBits(wifi_event_group); + return (bits & WIFI_AP_MODE_BIT) != 0; } diff --git a/components/ocpp/src/ocpp.c b/components/ocpp/src/ocpp.c index 7e6fac2..16dd3cb 100755 --- a/components/ocpp/src/ocpp.c +++ b/components/ocpp/src/ocpp.c @@ -66,7 +66,7 @@ typedef struct float frequency; float power_factor; // acumulados - float total_energy_kWh; + float total_energy_Wh; // derivados práticos int32_t sum_watt; // soma das 3 fases float avg_voltage; // média das 3 fases @@ -79,6 +79,15 @@ static ocpp_meter_cache_t s_meter = {0}; static portMUX_TYPE s_meter_mux = portMUX_INITIALIZER_UNLOCKED; static esp_event_handler_instance_t s_meter_inst = NULL; +// valor de oferta (A por conector) +static float s_current_offered_A = 16.0f; + +// novo input apropriado +static float getCurrentOffered(void) +{ + return s_current_offered_A; +} + /* ========================= * Task / Main Loop * ========================= * @@ -391,7 +400,7 @@ static void on_meter_event(void *arg, esp_event_base_t base, int32_t id, void *d s_meter.watt[2] = evt->watt[2]; s_meter.frequency = evt->frequency; s_meter.power_factor = evt->power_factor; - s_meter.total_energy_kWh = evt->total_energy; // já vem em kWh segundo o teu .h + s_meter.total_energy_Wh = evt->total_energy; s_meter.sum_watt = sum_w; s_meter.avg_voltage = avg_v; s_meter.sum_current = sum_i; @@ -442,34 +451,32 @@ float setPowerMeterInput(void) float setEnergyMeterInput(void) { - float kwh = 0.0f; + float wh = 0.0f; bool have = false; portENTER_CRITICAL(&s_meter_mux); have = s_meter.have_data; if (have) - kwh = s_meter.total_energy_kWh; + wh = s_meter.total_energy_Wh; portEXIT_CRITICAL(&s_meter_mux); - float wh = kwh * 1000.0f; - if (!have) { ESP_LOGW(TAG, "[METER] EnergyMeterInput: no data (return 0)"); } else { - ESP_LOGD(TAG, "[METER] EnergyMeterInput: %.3f kWh (%.1f Wh)", kwh, wh); + ESP_LOGD(TAG, "[METER] EnergyMeterInput: (%.1f Wh)", wh); } return wh; // agora devolve Wh } int setEnergyInput(void) { - float energy_kWh = setEnergyMeterInput(); // kWh - int wh = (int)lrintf((double)energy_kWh * 1000.0); // Wh arredondado - ESP_LOGD(TAG, "[METER] EnergyInput: %.3f kWh -> %d Wh", energy_kWh, wh); - return wh; + float wh = setEnergyMeterInput(); + int wh_i = (int)lrintf((double)wh); + ESP_LOGD(TAG, "[METER] EnergyInput: %.1f Wh", wh); + return wh_i; } float setCurrentInput(void) @@ -795,7 +802,7 @@ void ocpp_start(void) /* Metering */ ocpp_addMeterValueInputFloat(&setCurrentInput, "Current.Import", "A", NULL, NULL); - ocpp_addMeterValueInputFloat(&setCurrentInput, "Current.Offered", "A", NULL, NULL); + ocpp_addMeterValueInputFloat(&getCurrentOffered, "Current.Offered", "A", NULL, NULL); ocpp_addMeterValueInputFloat(&setVoltageInput, "Voltage", "V", NULL, NULL); ocpp_addMeterValueInputFloat(&setTemperatureInput, "Temperature", "Celsius", NULL, NULL); ocpp_addMeterValueInputFloat(&setPowerMeterInput, "Power.Active.Import", "W", NULL, NULL); diff --git a/components/peripherals/CMakeLists.txt b/components/peripherals/CMakeLists.txt index 330f17e..e9f3f9f 100755 --- a/components/peripherals/CMakeLists.txt +++ b/components/peripherals/CMakeLists.txt @@ -17,4 +17,4 @@ set(srcs idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "include" PRIV_REQUIRES nvs_flash driver esp_adc esp_timer - REQUIRES config evse api ntc_driver spi_bus_manager) + REQUIRES config evse ntc_driver spi_bus_manager) diff --git a/components/peripherals/src/ntc_sensor.c b/components/peripherals/src/ntc_sensor.c index b8084a3..7981127 100755 --- a/components/peripherals/src/ntc_sensor.c +++ b/components/peripherals/src/ntc_sensor.c @@ -4,23 +4,23 @@ #include "esp_log.h" #include "ntc_sensor.h" #include "ntc_driver.h" - #include "adc.h" static const char *TAG = "temp_sensor"; -#define MEASURE_PERIOD 15000 // 10s - -static float temp = 0.0; +#define MEASURE_PERIOD 15000 // 15s +static float temp = 0.0f; static ntc_device_handle_t ntc = NULL; - static portMUX_TYPE temp_mux = portMUX_INITIALIZER_UNLOCKED; -static void ntc_sensor_task_func(void *param) { +static void ntc_sensor_task_func(void *param) +{ float t; - while (true) { - if (ntc_dev_get_temperature(ntc, &t) == ESP_OK) { + while (true) + { + if (ntc_dev_get_temperature(ntc, &t) == ESP_OK) + { portENTER_CRITICAL(&temp_mux); temp = t; portEXIT_CRITICAL(&temp_mux); @@ -29,7 +29,8 @@ static void ntc_sensor_task_func(void *param) { } } -float ntc_temp_sensor(void) { +float ntc_temp_sensor(void) +{ float t; portENTER_CRITICAL(&temp_mux); t = temp; @@ -39,10 +40,8 @@ float ntc_temp_sensor(void) { void ntc_sensor_init(void) { - ESP_LOGI(TAG, "ntc_sensor_init"); - // Select the NTC sensor and initialize the hardware parameters ntc_config_t ntc_config = { .b_value = 3950, .r25_ohm = 10000, @@ -53,11 +52,26 @@ void ntc_sensor_init(void) .channel = ADC_CHANNEL_0, .unit = ADC_UNIT_1}; - // Create the NTC Driver and Init ADC - // ntc_device_handle_t ntc = NULL; + // Criar driver e inicializar ADC // adc_oneshot_unit_handle_t adc_handle = NULL; ESP_ERROR_CHECK(ntc_dev_create(&ntc_config, &ntc, &adc_handle)); ESP_ERROR_CHECK(ntc_dev_get_adc_handle(ntc, &adc_handle)); + // Leitura inicial para log + float t0 = 0.0f; + esp_err_t err = ntc_dev_get_temperature(ntc, &t0); + if (err == ESP_OK) + { + portENTER_CRITICAL(&temp_mux); + temp = t0; + portEXIT_CRITICAL(&temp_mux); + ESP_LOGI(TAG, "Temperatura inicial: %.2f °C", t0); + } + else + { + ESP_LOGW(TAG, "Falha na leitura inicial: %s", esp_err_to_name(err)); + } + + // Tarefa periódica xTaskCreate(ntc_sensor_task_func, "ntc_sensor_task", 5 * 1024, NULL, 3, NULL); } diff --git a/components/protocols/CMakeLists.txt b/components/protocols/CMakeLists.txt index 2ce1472..9efd1ba 100755 --- a/components/protocols/CMakeLists.txt +++ b/components/protocols/CMakeLists.txt @@ -1,14 +1,24 @@ -set(srcs - "src/protocols.c" - "src/mqtt.c" - "src/date_time.c" +idf_component_register( + SRCS + "src/protocols.c" + "src/json.c" + "src/mqtt.c" + INCLUDE_DIRS + "include" + PRIV_INCLUDE_DIRS + "src" + PRIV_REQUIRES + nvs_flash + mqtt + cjson + vfs + spiffs + REQUIRES + logger + network + config + evse + peripherals + ocpp + auth ) - -idf_component_register(SRCS "${srcs}" - INCLUDE_DIRS "include" - PRIV_INCLUDE_DIRS "src" - PRIV_REQUIRES nvs_flash esp_http_server esp_netif esp_https_ota app_update json mqtt vfs spiffs - REQUIRES config api logger) - - - \ No newline at end of file diff --git a/components/protocols/gen-tzdata.py b/components/protocols/gen-tzdata.py deleted file mode 100755 index e8b2fd8..0000000 --- a/components/protocols/gen-tzdata.py +++ /dev/null @@ -1,371 +0,0 @@ -#!/usr/bin/env python - -import sys - -ZONES_DIR = "/usr/share/zoneinfo/" -ZONES = [ - "Africa/Abidjan", - "Africa/Algiers", - "Africa/Bissau", - "Africa/Cairo", - "Africa/Casablanca", - "Africa/Ceuta", - "Africa/El_Aaiun", - "Africa/Johannesburg", - "Africa/Juba", - "Africa/Khartoum", - "Africa/Lagos", - "Africa/Maputo", - "Africa/Monrovia", - "Africa/Nairobi", - "Africa/Ndjamena", - "Africa/Sao_Tome", - "Africa/Tripoli", - "Africa/Tunis", - "Africa/Windhoek", - "America/Adak", - "America/Anchorage", - "America/Araguaina", - "America/Argentina/Buenos_Aires", - "America/Argentina/Catamarca", - "America/Argentina/Cordoba", - "America/Argentina/Jujuy", - "America/Argentina/La_Rioja", - "America/Argentina/Mendoza", - "America/Argentina/Rio_Gallegos", - "America/Argentina/Salta", - "America/Argentina/San_Juan", - "America/Argentina/San_Luis", - "America/Argentina/Tucuman", - "America/Argentina/Ushuaia", - "America/Asuncion", - "America/Bahia", - "America/Bahia_Banderas", - "America/Barbados", - "America/Belem", - "America/Belize", - "America/Boa_Vista", - "America/Bogota", - "America/Boise", - "America/Cambridge_Bay", - "America/Campo_Grande", - "America/Cancun", - "America/Caracas", - "America/Cayenne", - "America/Cayman", - "America/Chicago", - "America/Chihuahua", - "America/Costa_Rica", - "America/Creston", - "America/Cuiaba", - "America/Curacao", - "America/Danmarkshavn", - "America/Dawson", - "America/Dawson_Creek", - "America/Denver", - "America/Detroit", - "America/Dominica", - "America/Edmonton", - "America/Eirunepe", - "America/El_Salvador", - "America/Fortaleza", - "America/Fort_Nelson", - "America/Glace_Bay", - "America/Godthab", - "America/Goose_Bay", - "America/Grand_Turk", - "America/Grenada", - "America/Guadeloupe", - "America/Guatemala", - "America/Guayaquil", - "America/Guyana", - "America/Halifax", - "America/Havana", - "America/Hermosillo", - "America/Indiana/Indianapolis", - "America/Indiana/Knox", - "America/Indiana/Marengo", - "America/Indiana/Petersburg", - "America/Indiana/Tell_City", - "America/Indiana/Vevay", - "America/Indiana/Vincennes", - "America/Indiana/Winamac", - "America/Inuvik", - "America/Iqaluit", - "America/Jamaica", - "America/Juneau", - "America/Kentucky/Louisville", - "America/Kentucky/Monticello", - "America/La_Paz", - "America/Lima", - "America/Los_Angeles", - "America/Maceio", - "America/Managua", - "America/Manaus", - "America/Marigot", - "America/Martinique", - "America/Matamoros", - "America/Mazatlan", - "America/Menominee", - "America/Merida", - "America/Metlakatla", - "America/Mexico_City", - "America/Miquelon", - "America/Moncton", - "America/Monterrey", - "America/Montevideo", - "America/New_York", - "America/Nome", - "America/Noronha", - "America/North_Dakota/Beulah", - "America/North_Dakota/Center", - "America/North_Dakota/New_Salem", - "America/Nuuk", - "America/Ojinaga", - "America/Panama", - "America/Paramaribo", - "America/Phoenix", - "America/Port-au-Prince", - "America/Porto_Velho", - "America/Puerto_Rico", - "America/Punta_Arenas", - "America/Rankin_Inlet", - "America/Recife", - "America/Regina", - "America/Resolute", - "America/Rio_Branco", - "America/Santarem", - "America/Santiago", - "America/Santo_Domingo", - "America/Sao_Paulo", - "America/Scoresbysund", - "America/Sitka", - "America/St_Johns", - "America/Swift_Current", - "America/Tegucigalpa", - "America/Thule", - "America/Tijuana", - "America/Toronto", - "America/Vancouver", - "America/Whitehorse", - "America/Winnipeg", - "America/Yakutat", - "Antarctica/Casey", - "Antarctica/Davis", - "Antarctica/Macquarie", - "Antarctica/Mawson", - "Antarctica/Palmer", - "Antarctica/Rothera", - "Antarctica/Troll", - "Asia/Almaty", - "Asia/Amman", - "Asia/Anadyr", - "Asia/Aqtau", - "Asia/Aqtobe", - "Asia/Ashgabat", - "Asia/Atyrau", - "Asia/Baghdad", - "Asia/Bahrain", - "Asia/Baku", - "Asia/Bangkok", - "Asia/Barnaul", - "Asia/Beirut", - "Asia/Bishkek", - "Asia/Brunei", - "Asia/Chita", - "Asia/Choibalsan", - "Asia/Colombo", - "Asia/Damascus", - "Asia/Dhaka", - "Asia/Dili", - "Asia/Dubai", - "Asia/Dushanbe", - "Asia/Famagusta", - "Asia/Gaza", - "Asia/Hebron", - "Asia/Ho_Chi_Minh", - "Asia/Hong_Kong", - "Asia/Hovd", - "Asia/Irkutsk", - "Asia/Jakarta", - "Asia/Jayapura", - "Asia/Jerusalem", - "Asia/Kabul", - "Asia/Kamchatka", - "Asia/Karachi", - "Asia/Kathmandu", - "Asia/Khandyga", - "Asia/Kolkata", - "Asia/Krasnoyarsk", - "Asia/Kuala_Lumpur", - "Asia/Kuching", - "Asia/Kuwait", - "Asia/Macau", - "Asia/Magadan", - "Asia/Makassar", - "Asia/Manila", - "Asia/Nicosia", - "Asia/Novokuznetsk", - "Asia/Novosibirsk", - "Asia/Omsk", - "Asia/Oral", - "Asia/Pontianak", - "Asia/Pyongyang", - "Asia/Qatar", - "Asia/Qyzylorda", - "Asia/Riyadh", - "Asia/Sakhalin", - "Asia/Samarkand", - "Asia/Seoul", - "Asia/Shanghai", - "Asia/Singapore", - "Asia/Srednekolymsk", - "Asia/Taipei", - "Asia/Tashkent", - "Asia/Tbilisi", - "Asia/Tehran", - "Asia/Thimphu", - "Asia/Tokyo", - "Asia/Tomsk", - "Asia/Ulaanbaatar", - "Asia/Urumqi", - "Asia/Ust-Nera", - "Asia/Vientiane", - "Asia/Vladivostok", - "Asia/Yakutsk", - "Asia/Yangon", - "Asia/Yekaterinburg", - "Asia/Yerevan", - "Atlantic/Azores", - "Atlantic/Bermuda", - "Atlantic/Canary", - "Atlantic/Cape_Verde", - "Atlantic/Faroe", - "Atlantic/Madeira", - "Atlantic/South_Georgia", - "Atlantic/Stanley", - "Australia/Adelaide", - "Australia/Brisbane", - "Australia/Broken_Hill", - "Australia/Darwin", - "Australia/Eucla", - "Australia/Hobart", - "Australia/Lindeman", - "Australia/Lord_Howe", - "Australia/Melbourne", - "Australia/Perth", - "Australia/Sydney", - "Europe/Andorra", - "Europe/Astrakhan", - "Europe/Athens", - "Europe/Belgrade", - "Europe/Berlin", - "Europe/Brussels", - "Europe/Bucharest", - "Europe/Budapest", - "Europe/Chisinau", - "Europe/Dublin", - "Europe/Gibraltar", - "Europe/Helsinki", - "Europe/Istanbul", - "Europe/Kaliningrad", - "Europe/Kyiv", - "Europe/Kirov", - "Europe/Lisbon", - "Europe/London", - "Europe/Madrid", - "Europe/Malta", - "Europe/Minsk", - "Europe/Moscow", - "Europe/Paris", - "Europe/Prague", - "Europe/Riga", - "Europe/Rome", - "Europe/Samara", - "Europe/Saratov", - "Europe/Simferopol", - "Europe/Sofia", - "Europe/Tallinn", - "Europe/Tirane", - "Europe/Ulyanovsk", - "Europe/Vienna", - "Europe/Vilnius", - "Europe/Volgograd", - "Europe/Warsaw", - "Europe/Zurich", - "Indian/Chagos", - "Indian/Maldives", - "Indian/Mauritius", - "Pacific/Apia", - "Pacific/Auckland", - "Pacific/Bougainville", - "Pacific/Chatham", - "Pacific/Chuuk", - "Pacific/Easter", - "Pacific/Efate", - "Pacific/Enderbury", - "Pacific/Fakaofo", - "Pacific/Fiji", - "Pacific/Funafuti", - "Pacific/Galapagos", - "Pacific/Gambier", - "Pacific/Guadalcanal", - "Pacific/Guam", - "Pacific/Honolulu", - "Pacific/Kiritimati", - "Pacific/Kosrae", - "Pacific/Kwajalein", - "Pacific/Majuro", - "Pacific/Marquesas", - "Pacific/Midway", - "Pacific/Nauru", - "Pacific/Niue", - "Pacific/Norfolk", - "Pacific/Noumea", - "Pacific/Pago_Pago", - "Pacific/Palau", - "Pacific/Pitcairn", - "Pacific/Port_Moresby", - "Pacific/Rarotonga", - "Pacific/Tahiti", - "Pacific/Tarawa", - "Pacific/Tongatapu", - "Etc/GMT", - "Etc/GMT-1", - "Etc/GMT-2", - "Etc/GMT-3", - "Etc/GMT-4", - "Etc/GMT-5", - "Etc/GMT-6", - "Etc/GMT-7", - "Etc/GMT-8", - "Etc/GMT-9", - "Etc/GMT-10", - "Etc/GMT-11", - "Etc/GMT-12", - "Etc/GMT-13", - "Etc/GMT-14", - "Etc/GMT+1", - "Etc/GMT+2", - "Etc/GMT+3", - "Etc/GMT+4", - "Etc/GMT+5", - "Etc/GMT+6", - "Etc/GMT+7", - "Etc/GMT+8", - "Etc/GMT+9", - "Etc/GMT+10", - "Etc/GMT+11", - "Etc/GMT+12", - "Etc/UTC" -] - -def get_tz_string(timezone): - data = open(ZONES_DIR + timezone, "rb").read().split(b"\n")[-2] - return data.decode("utf-8") - -if __name__ == "__main__": - f = open("./src/tz_data.h", "w") - for timezone in ZONES: - f.write('\t{{"{}", "{}"}},\n'.format(timezone, get_tz_string(timezone))) - f.close() \ No newline at end of file diff --git a/components/protocols/include/date_time.h b/components/protocols/include/date_time.h deleted file mode 100755 index 858c7ec..0000000 --- a/components/protocols/include/date_time.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef DATE_TIME_H -#define DATE_TIME_H - -#include -#include "esp_err.h" - -/** - * @brief Initialize timezone and NTP - * - */ -void date_time_init(void); - -/** - * @brief Return true if NTP is enabled, stored in NVS - * - * @return true - * @return false - */ -bool date_time_is_ntp_enabled(void); - -/** - * @brief Get NTP server, string length 64, stored in NVS - * - * @param value - */ -void date_time_get_ntp_server(char* value); - -/** - * @brief Return true if NTP server from DHCP fetch is enabled, stored in NVS - * - * @return true - * @return false - */ -bool date_time_is_ntp_from_dhcp(void); - -/** - * @brief Set timezone and NTP config - * - * @param enabled - * @param server - * @param from_dhcp - * @return esp_err_t - */ -esp_err_t date_time_set_ntp_config(bool enabled, const char* server, bool from_dhcp); - -/** - * @brief Get timezone, string length 64, stored in NVS - * - * @param value - */ -void date_time_get_timezone(char* value); - -/** - * @brief Set timezone, string length 64, stored in NVS - * - * @param value - */ -esp_err_t date_time_set_timezone(const char* value); - - -#endif /* DATE_TIME_H */ \ No newline at end of file diff --git a/components/protocols/include/json.h b/components/protocols/include/json.h new file mode 100755 index 0000000..c044b39 --- /dev/null +++ b/components/protocols/include/json.h @@ -0,0 +1,38 @@ +#ifndef JSON_H_ +#define JSON_H_ + +#include +#include "esp_err.h" +#include "cJSON.h" + +/** + * @brief Gera um objeto JSON com a configuração atual do EVSE. + * + * Contém parâmetros como corrente máxima, limites de tempo, + * trava do conector, temperatura e configuração do OCPP. + * + * @return Ponteiro para cJSON (deve ser liberado com cJSON_Delete()). + */ +cJSON* json_get_evse_config(void); + +/** + * @brief Define a configuração do EVSE a partir de um objeto JSON. + * + * Aplica valores recebidos de protocolos como MQTT ou REST. + * + * @param root Objeto JSON com os campos válidos. + * @return ESP_OK se todos os parâmetros foram aplicados com sucesso. + */ +esp_err_t json_set_evse_config(cJSON* root); + +/** + * @brief Retorna o estado atual do EVSE em formato JSON. + * + * Inclui estado de operação, erros, limites, sessão atual e medições elétricas. + * + * @return Ponteiro para cJSON (deve ser liberado com cJSON_Delete()). + */ +cJSON* json_get_state(void); + + +#endif /* JSON_H_ */ diff --git a/components/protocols/include/modbus_tcp.h b/components/protocols/include/modbus_tcp.h deleted file mode 100755 index 6286250..0000000 --- a/components/protocols/include/modbus_tcp.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef MODBUS_TCP_H -#define MODBUS_TCP_H - -#include - -/** - * @brief Init modbus tcp - * - */ -void modbus_tcp_init(void); - -/** - * @brief Set enabled, stored in NVS - * - * @param enabled - */ -void modbus_tcp_set_enabled(bool enabled); - -/** - * @brief Get enabled, stored in NVS - * - * @return true - * @return false - */ -bool modbus_tcp_is_enabled(void); - -#endif /* MODBUS_TCP_H */ \ No newline at end of file diff --git a/components/protocols/include/mqtt.h b/components/protocols/include/mqtt.h index 7f58520..20e7585 100755 --- a/components/protocols/include/mqtt.h +++ b/components/protocols/include/mqtt.h @@ -6,63 +6,108 @@ #include "esp_err.h" /** - * @brief Initializes MQTT client and starts background task if enabled in NVS + * @file mqtt.h + * @brief MQTT configuration and control interface. + * + * This module provides initialization, configuration, + * and runtime access functions for the MQTT client. + * + * Configuration is persisted in NVS under namespace "mqtt". + */ + +/* -------------------------------------------------------------------------- */ +/* Definitions */ +/* -------------------------------------------------------------------------- */ + +#define MQTT_MAX_SERVER_LEN 64 /**< Max length for MQTT server URI */ +#define MQTT_MAX_USER_LEN 32 /**< Max length for MQTT username */ +#define MQTT_MAX_PASSWORD_LEN 64 /**< Max length for MQTT password */ +#define MQTT_MAX_BASE_TOPIC_LEN 64 /**< Max length for MQTT base topic */ + +/* -------------------------------------------------------------------------- */ +/* Public Functions */ +/* -------------------------------------------------------------------------- */ + +/** + * @brief Initialize MQTT subsystem. + * + * Loads configuration from NVS and starts background publish task + * if MQTT is enabled. Must be called once during system startup. */ void mqtt_init(void); /** - * @brief Set MQTT config - * - * @param enabled - * @param server NULL value will be skiped - * @param base_topic NULL value will be skiped - * @param user NULL value will be skiped - * @param password NULL value will be skiped - * @param periodicity 0 value will be skiped - * @return esp_err_t + * @brief Restart the MQTT client safely. + * + * Stops the current MQTT client (if running) and starts a new one + * with the configuration currently stored in NVS. + * + * Useful when changing Wi-Fi networks, credentials, or broker settings. + * + * @return ESP_OK on success, or an ESP_ERR_* code otherwise. */ -esp_err_t mqtt_set_config(bool enabled, const char* server, const char* base_topic, const char* user, const char* password, uint16_t periodicity); +esp_err_t mqtt_restart(void); /** - * @brief Get MQTT enabled, stored in NVS - * - * @return true - * @return false + * @brief Set and persist MQTT configuration parameters in NVS. + * + * Any NULL parameter will be skipped (the previous value remains stored). + * + * @param enabled Whether MQTT should be enabled (true/false). + * @param server Broker URI (e.g. "mqtt://192.168.1.10"). + * @param base_topic Base topic prefix for publish/subscribe. + * @param user MQTT username (optional). + * @param password MQTT password (optional). + * @param periodicity Publish interval (in seconds). Must be >0 when enabled. + * + * @return ESP_OK on success, or an ESP_ERR_* code otherwise. + */ +esp_err_t mqtt_set_config(bool enabled, + const char *server, + const char *base_topic, + const char *user, + const char *password, + uint16_t periodicity); + +/** + * @brief Get whether MQTT is enabled. + * + * @return true if enabled, false otherwise. */ bool mqtt_get_enabled(void); /** - * @brief Get MQTT server, string length 64, stored in NVS - * - * @param value + * @brief Get MQTT broker URI stored in NVS. + * + * @param[out] value Buffer to receive the URI (min length: MQTT_MAX_SERVER_LEN). */ -void mqtt_get_server(char* value); +void mqtt_get_server(char *value); /** - * @brief Get MQTT password, string length 64, stored in NVS - * - * @param value + * @brief Get MQTT base topic stored in NVS. + * + * @param[out] value Buffer to receive the base topic (min length: MQTT_MAX_BASE_TOPIC_LEN). */ -void mqtt_get_password(char* value); +void mqtt_get_base_topic(char *value); /** - * @brief Get MQTT base topic, string length 32, stored in NVS - * - * @param value + * @brief Get MQTT username stored in NVS. + * + * @param[out] value Buffer to receive the username (min length: MQTT_MAX_USER_LEN). */ -void mqtt_get_base_topic(char* value); +void mqtt_get_user(char *value); /** - * @brief Get MQTT user, string length 32, stored in NVS - * - * @param value + * @brief Get MQTT password stored in NVS. + * + * @param[out] value Buffer to receive the password (min length: MQTT_MAX_PASSWORD_LEN). */ -void mqtt_get_user(char* value); +void mqtt_get_password(char *value); /** - * @brief Get MQTT periodicity in second, stored in NVS - * - * @return uint16_t + * @brief Get MQTT publish periodicity in seconds. + * + * @return Publish interval in seconds (default: 30). */ uint16_t mqtt_get_periodicity(void); diff --git a/components/protocols/server_certs/ca_cert.pem b/components/protocols/server_certs/ca_cert.pem deleted file mode 100755 index 57ba02c..0000000 --- a/components/protocols/server_certs/ca_cert.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- \ No newline at end of file diff --git a/components/protocols/src/date_time.c b/components/protocols/src/date_time.c deleted file mode 100755 index c9863a6..0000000 --- a/components/protocols/src/date_time.c +++ /dev/null @@ -1,136 +0,0 @@ - -#include -#include "esp_log.h" -#include "esp_sntp.h" -#include "esp_netif_sntp.h" -#include "nvs.h" - -#include "date_time.h" - -#define NVS_NAMESPACE "date_time" -#define NVS_NTP_ENABLED "ntp_en" -#define NVS_NTP_SERVER "ntp_server" -#define NVS_NTP_FROM_DHCP "ntp_from_dhcp" -#define NVS_TIMEZONE "timezone" - -static const char* TAG = "date_time"; - -static nvs_handle nvs; - -static char ntp_server[64]; // if renew_servers_after_new_IP = false, will be used static string reference - -static const char* tz_data[][2] = { -#include "tz_data.h" - {NULL, NULL} -}; - -static const char* find_tz(const char* name) -{ - if (name != NULL) { - int index = 0; - while (true) { - if (tz_data[index][0] == NULL) { - return NULL; - } - if (strcmp(tz_data[index][0], name) == 0) { - return tz_data[index][1]; - } - index++; - } - } - return NULL; -} - -void date_time_init(void) -{ - ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs)); - - if (date_time_is_ntp_enabled()) { - date_time_get_ntp_server(ntp_server); - - esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(ntp_server); - - esp_err_t ret = esp_netif_sntp_init(&config); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "SNTP init return %s", esp_err_to_name(ret)); - } - } - - char str[64]; - date_time_get_timezone(str); - const char *tz = find_tz(str); - if (tz) { - setenv("TZ", tz, 1); - tzset(); - } else { - ESP_LOGW(TAG, "Unknown timezone %s", str); - } -} - -bool date_time_is_ntp_enabled(void) -{ - uint8_t value = false; - nvs_get_u8(nvs, NVS_NTP_ENABLED, &value); - return value; -} - -void date_time_get_ntp_server(char* value) -{ - size_t len = 64; - value[0] = '\0'; - nvs_get_str(nvs, NVS_NTP_SERVER, value, &len); -} - -bool date_time_is_ntp_from_dhcp(void) -{ - uint8_t value = false; - nvs_get_u8(nvs, NVS_NTP_FROM_DHCP, &value); - return value; -} - -esp_err_t date_time_set_ntp_config(bool enabled, const char* server, bool from_dhcp) -{ - esp_err_t ret = ESP_OK; - - esp_netif_sntp_deinit(); - if (enabled) { - strcpy(ntp_server, server); - esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(ntp_server); - config.renew_servers_after_new_IP = from_dhcp; - ret = esp_netif_sntp_init(&config); - } - - if (ret == ESP_OK) { - nvs_set_u8(nvs, NVS_NTP_ENABLED, enabled); - nvs_set_str(nvs, NVS_NTP_SERVER, server); - nvs_set_u8(nvs, NVS_NTP_FROM_DHCP, from_dhcp); - } - - return ret; -} - -void date_time_get_timezone(char* value) -{ - size_t len = 64; - value[0] = '\0'; - strcpy(value, "Etc/UTC"); - nvs_get_str(nvs, NVS_TIMEZONE, value, &len); -} - -esp_err_t date_time_set_timezone(const char* value) -{ - const char* tz = find_tz(value); - - if (tz) { - setenv("TZ", tz, 1); - tzset(); - - nvs_set_str(nvs, NVS_TIMEZONE, value); - - return ESP_OK; - } else { - ESP_LOGW(TAG, "Unknown timezone %s", value); - - return ESP_ERR_INVALID_ARG; - } -} \ No newline at end of file diff --git a/components/protocols/src/json.c b/components/protocols/src/json.c new file mode 100755 index 0000000..65d7ca5 --- /dev/null +++ b/components/protocols/src/json.c @@ -0,0 +1,204 @@ +// === Início de: components/protocols/src/json.c === +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "esp_wifi.h" +#include "esp_timer.h" +#include "esp_chip_info.h" +#include "esp_mac.h" +#include "esp_log.h" + +#include "json.h" +#include "mqtt.h" +#include "network.h" +#include "evse_error.h" +#include "evse_api.h" +#include "auth.h" +#include "evse_limits.h" +#include "evse_state.h" +#include "evse_config.h" +#include "ocpp.h" +#include "board_config.h" +#include "socket_lock.h" +#include "proximity.h" +#include "temp_sensor.h" +#include "evse_meter.h" + +static const char *TAG = "json"; + +// +// ===== EVSE CONFIG JSON ===== +// +cJSON *json_get_evse_config(void) +{ + cJSON *root = cJSON_CreateObject(); + if (!root) + return NULL; + + cJSON_AddNumberToObject(root, "maxChargingCurrent", evse_get_max_charging_current()); + cJSON_AddNumberToObject(root, "chargingCurrent", evse_get_charging_current()); + cJSON_AddNumberToObject(root, "defaultChargingCurrent", evse_get_default_charging_current()); + cJSON_AddBoolToObject(root, "requireAuth", auth_get_mode()); + cJSON_AddBoolToObject(root, "socketOutlet", evse_get_socket_outlet()); + cJSON_AddBoolToObject(root, "rcm", evse_is_rcm()); + cJSON_AddNumberToObject(root, "temperatureThreshold", evse_get_temp_threshold()); + cJSON_AddNumberToObject(root, "consumptionLimit", evse_get_consumption_limit()); + cJSON_AddNumberToObject(root, "defaultConsumptionLimit", evse_get_default_consumption_limit()); + cJSON_AddNumberToObject(root, "chargingTimeLimit", evse_get_charging_time_limit()); + cJSON_AddNumberToObject(root, "defaultChargingTimeLimit", evse_get_default_charging_time_limit()); + cJSON_AddNumberToObject(root, "underPowerLimit", evse_get_under_power_limit()); + cJSON_AddNumberToObject(root, "defaultUnderPowerLimit", evse_get_default_under_power_limit()); + + cJSON_AddNumberToObject(root, "socketLockOperatingTime", socket_lock_get_operating_time()); + cJSON_AddNumberToObject(root, "socketLockBreakTime", socket_lock_get_break_time()); + cJSON_AddBoolToObject(root, "socketLockDetectionHigh", socket_lock_is_detection_high()); + cJSON_AddNumberToObject(root, "socketLockRetryCount", socket_lock_get_retry_count()); + + char str[64]; + cJSON_AddBoolToObject(root, "enabledocpp", ocpp_get_enabled()); + ocpp_get_server(str); + cJSON_AddStringToObject(root, "serverocpp", str); + + return root; +} + +// +// ===== SET EVSE CONFIG (from MQTT or REST) ===== +// +esp_err_t json_set_evse_config(cJSON *root) +{ + if (!root) + return ESP_ERR_INVALID_ARG; + + // Alguns setters retornam esp_err_t, outros void. Para manter compatibilidade, + // chamamos sem propagar erro (se existir, será tratado internamente). +#define SET_NUM(key, fn) \ + do \ + { \ + const cJSON *item = cJSON_GetObjectItem(root, key); \ + if (cJSON_IsNumber(item)) \ + { \ + fn(item->valuedouble); \ + } \ + } while (0) + +#define SET_BOOL(key, fn) \ + do \ + { \ + const cJSON *item = cJSON_GetObjectItem(root, key); \ + if (cJSON_IsBool(item)) \ + { \ + fn(cJSON_IsTrue(item)); \ + } \ + } while (0) + + SET_NUM("maxChargingCurrent", evse_set_max_charging_current); + SET_NUM("chargingCurrent", evse_set_charging_current); + SET_NUM("defaultChargingCurrent", evse_set_default_charging_current); + SET_BOOL("socketOutlet", evse_set_socket_outlet); + SET_BOOL("rcm", evse_set_rcm); + SET_NUM("temperatureThreshold", evse_set_temp_threshold); + SET_NUM("consumptionLimit", evse_set_consumption_limit); + SET_NUM("defaultConsumptionLimit", evse_set_default_consumption_limit); + SET_NUM("chargingTimeLimit", evse_set_charging_time_limit); + SET_NUM("defaultChargingTimeLimit", evse_set_default_charging_time_limit); + SET_NUM("underPowerLimit", evse_set_under_power_limit); + SET_NUM("defaultUnderPowerLimit", evse_set_default_under_power_limit); + SET_NUM("socketLockOperatingTime", socket_lock_set_operating_time); + SET_NUM("socketLockBreakTime", socket_lock_set_break_time); + + const cJSON *retry = cJSON_GetObjectItem(root, "socketLockRetryCount"); + if (cJSON_IsNumber(retry)) + socket_lock_set_retry_count(retry->valueint); + + const cJSON *detect = cJSON_GetObjectItem(root, "socketLockDetectionHigh"); + if (cJSON_IsBool(detect)) + socket_lock_set_detection_high(cJSON_IsTrue(detect)); + + const cJSON *ocpp_enabled = cJSON_GetObjectItem(root, "enabledocpp"); + if (cJSON_IsBool(ocpp_enabled)) + ocpp_set_enabled(cJSON_IsTrue(ocpp_enabled)); + + const cJSON *ocpp_server = cJSON_GetObjectItem(root, "serverocpp"); + if (cJSON_IsString(ocpp_server)) + ocpp_set_server(cJSON_GetStringValue(ocpp_server)); + + ESP_LOGI(TAG, "EVSE configuration updated successfully"); + return ESP_OK; +} + +// +// ===== EVSE STATE JSON ===== +// +cJSON *json_get_state(void) +{ + cJSON *root = cJSON_CreateObject(); + if (!root) + return NULL; + + cJSON_AddStringToObject(root, "state", evse_state_to_str(evse_get_state())); + cJSON_AddBoolToObject(root, "available", evse_config_is_available()); + cJSON_AddBoolToObject(root, "enabled", evse_config_is_enabled()); + cJSON_AddBoolToObject(root, "pendingAuth", auth_get_mode()); + cJSON_AddBoolToObject(root, "limitReached", evse_is_limit_reached()); + + // Add error list + uint32_t error = evse_error_get_bits(); + if (error == 0) + { + cJSON_AddNullToObject(root, "errors"); + } + else + { + cJSON *errors = cJSON_CreateArray(); + if (error & EVSE_ERR_PILOT_FAULT_BIT) + cJSON_AddItemToArray(errors, cJSON_CreateString("pilot_fault")); + if (error & EVSE_ERR_DIODE_SHORT_BIT) + cJSON_AddItemToArray(errors, cJSON_CreateString("diode_short")); + if (error & EVSE_ERR_LOCK_FAULT_BIT) + cJSON_AddItemToArray(errors, cJSON_CreateString("lock_fault")); + if (error & EVSE_ERR_UNLOCK_FAULT_BIT) + cJSON_AddItemToArray(errors, cJSON_CreateString("unlock_fault")); + if (error & EVSE_ERR_RCM_TRIGGERED_BIT) + cJSON_AddItemToArray(errors, cJSON_CreateString("rcm_triggered")); + if (error & EVSE_ERR_RCM_SELFTEST_FAULT_BIT) + cJSON_AddItemToArray(errors, cJSON_CreateString("rcm_selftest_fault")); + if (error & EVSE_ERR_TEMPERATURE_HIGH_BIT) + cJSON_AddItemToArray(errors, cJSON_CreateString("temperature_high")); + if (error & EVSE_ERR_TEMPERATURE_FAULT_BIT) + cJSON_AddItemToArray(errors, cJSON_CreateString("temperature_fault")); + cJSON_AddItemToObject(root, "errors", errors); + } + + // Session info + evse_session_t sess; + if (evse_get_session(&sess)) + { + cJSON_AddNumberToObject(root, "sessionTime", (double)sess.start_tick); + cJSON_AddNumberToObject(root, "chargingTime", (double)sess.duration_s); + cJSON_AddNumberToObject(root, "consumption", (double)sess.energy_wh); + } + else + { + cJSON_AddNullToObject(root, "sessionTime"); + cJSON_AddNumberToObject(root, "chargingTime", 0); + cJSON_AddNumberToObject(root, "consumption", 0); + } + + // Meter readings + float voltage[EVSE_METER_PHASE_COUNT]; + float current[EVSE_METER_PHASE_COUNT]; + int power[EVSE_METER_PHASE_COUNT]; + + evse_meter_get_voltage(voltage); + evse_meter_get_current(current); + evse_meter_get_power(power); + + cJSON_AddItemToObject(root, "power", cJSON_CreateIntArray(power, EVSE_METER_PHASE_COUNT)); + cJSON_AddItemToObject(root, "voltage", cJSON_CreateFloatArray(voltage, EVSE_METER_PHASE_COUNT)); + cJSON_AddItemToObject(root, "current", cJSON_CreateFloatArray(current, EVSE_METER_PHASE_COUNT)); + + return root; +} + +// === Fim de: components/protocols/src/json.c === diff --git a/components/protocols/src/mqtt.c b/components/protocols/src/mqtt.c index 73b0483..24fa6a3 100755 --- a/components/protocols/src/mqtt.c +++ b/components/protocols/src/mqtt.c @@ -1,304 +1,437 @@ +// === Início de: components/protocols/src/mqtt.c === #include #include + #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" + #include "esp_log.h" #include "esp_event.h" #include "mqtt_client.h" #include "nvs.h" + #include "mqtt.h" #include "json.h" #include "board_config.h" -#include "timeout_utils.h" +#include "mqtt_client.h" -#define NVS_NAMESPACE "mqtt" -#define NVS_ENABLED "enabled" -#define NVS_SERVER "server" -#define NVS_BASE_TOPIC "base_topic" -#define NVS_USER "user" -#define NVS_PASSWORD "password" -#define NVS_PERIODICITY "periodicity" +#define NVS_NAMESPACE "mqtt" +#define NVS_ENABLED "enabled" +#define NVS_SERVER "server" +#define NVS_BASE_TOPIC "base_topic" +#define NVS_USER "user" +#define NVS_PASSWORD "password" +#define NVS_PERIODICITY "periodicity" + +static const char *TAG = "mqtt"; -static const char* TAG = "mqtt"; static TaskHandle_t client_task = NULL; static esp_mqtt_client_handle_t client = NULL; -static uint16_t periodicity = 30; +static SemaphoreHandle_t mqtt_mutex = NULL; +static uint16_t periodicity = 30; // seconds +// Nem todas as versões do IDF têm esp_mqtt_client_is_connected(); usamos um flag. +static volatile bool mqtt_connected = false; -static esp_err_t open_mqtt_nvs(nvs_handle_t *handle) { +static esp_err_t open_mqtt_nvs(nvs_handle_t *handle) +{ return nvs_open(NVS_NAMESPACE, NVS_READWRITE, handle); } -static void subcribe_topics(void) +// +// Helper: safely publish JSON message +// +static void publish_message(const char *topic_suffix, cJSON *root) { - ESP_LOGI(TAG, "[MQTT] Subscribing to topics"); + if (!root) return; - char base[32]; - mqtt_get_base_topic(base); + if (xSemaphoreTake(mqtt_mutex, pdMS_TO_TICKS(500)) == pdTRUE) + { + if (client && mqtt_connected) + { + char base[MQTT_MAX_BASE_TOPIC_LEN] = {0}; + mqtt_get_base_topic(base); - char topic[64]; + char topic[128]; + snprintf(topic, sizeof(topic), "%s%s", base, topic_suffix); - snprintf(topic, sizeof(topic), "%s/request/#", base); - esp_mqtt_client_subscribe(client, topic, 0); - ESP_LOGI(TAG, " subscribed: %s", topic); - - snprintf(topic, sizeof(topic), "%s/set/config/#", base); - esp_mqtt_client_subscribe(client, topic, 0); - ESP_LOGI(TAG, " subscribed: %s", topic); - - snprintf(topic, sizeof(topic), "%s/enable", base); - esp_mqtt_client_subscribe(client, topic, 0); - ESP_LOGI(TAG, " subscribed: %s", topic); -} - -static void publish_message(const char* topic, cJSON* root) -{ - char target_topic[64]; - mqtt_get_base_topic(target_topic); - strncat(target_topic, topic, sizeof(target_topic) - strlen(target_topic) - 1); - - const char* json = cJSON_PrintUnformatted(root); - esp_mqtt_client_publish(client, target_topic, json, 0, 1, 0); - free((void*)json); -} - - -static void handle_message(const char* topic, const char* data) -{ - char base_topic[32]; - mqtt_get_base_topic(base_topic); - - ESP_LOGI(TAG, "Topic: %s", topic); - ESP_LOGI(TAG, "data: %s", data); - ESP_LOGI(TAG, "base_topic: %s", base_topic); - - if (strncmp(topic, base_topic, strlen(base_topic)) == 0) { - const char* sub_topic = &topic[strlen(base_topic)]; - - ESP_LOGI(TAG, "Sub_topic: %s", sub_topic); - - if (strcmp(sub_topic, "/request/config/evse") == 0) { - cJSON* root = json_get_evse_config(); - publish_message("/response/config/evse", root); - cJSON_Delete(root); - } else if (strcmp(sub_topic, "/request/config/wifi") == 0) { - //cJSON* root = json_get_wifi_config(); - //publish_message("/response/config/wifi", root); - //cJSON_Delete(root); - } else if (strcmp(sub_topic, "/request/config/mqtt") == 0) { - cJSON* root = json_get_mqtt_config(); - publish_message("/response/config/mqtt", root); - cJSON_Delete(root); - } else if (strcmp(sub_topic, "/request/boardConfig") == 0) { - cJSON* root = json_get_board_config(); - publish_message("/response/boardConfig", root); - cJSON_Delete(root); - } else if (strcmp(sub_topic, "/request/info") == 0) { - cJSON* root = json_get_info(); - publish_message("/response/info", root); - cJSON_Delete(root); - } else if (strcmp(sub_topic, "/request/restart") == 0) { - timeout_restart(); - } else if (strcmp(sub_topic, "/set/config/evse") == 0) { - cJSON* root = cJSON_Parse(data); - json_set_evse_config(root); - cJSON_Delete(root); - } else if (strcmp(sub_topic, "/set/config/wifi") == 0) { - //cJSON* root = cJSON_Parse(data); - //json_set_wifi_config(root, true); - //cJSON_Delete(root); - } else if (strcmp(sub_topic, "/set/config/mqtt") == 0) { - cJSON* root = cJSON_Parse(data); - json_set_mqtt_config(root); - cJSON_Delete(root); - } + char *json = cJSON_PrintUnformatted(root); + if (json) + { + esp_mqtt_client_publish(client, topic, json, 0, 1, 0); + ESP_LOGI(TAG, "Published to %s", topic); + free(json); + } + } + else + { + ESP_LOGW(TAG, "MQTT client not connected — skipping publish"); + } + xSemaphoreGive(mqtt_mutex); + } + else + { + ESP_LOGW(TAG, "MQTT mutex timeout during publish"); } } -static void event_handler(void* handler_args, esp_event_base_t base, int32_t event_id, void* event_data) +// +// Subscriptions +// +static void subscribe_topics(void) +{ + if (!client) return; + + char base[MQTT_MAX_BASE_TOPIC_LEN] = {0}; + mqtt_get_base_topic(base); + + const char *subs[] = { + "/request/#", + "/set/config/#", + "/enable", + "/request/restart", + "/request/config/evse", + "/request/boardConfig" + }; + + for (size_t i = 0; i < sizeof(subs) / sizeof(subs[0]); i++) + { + char topic[MQTT_MAX_BASE_TOPIC_LEN + 32]; + snprintf(topic, sizeof(topic), "%s%s", base, subs[i]); + esp_mqtt_client_subscribe(client, topic, 0); + ESP_LOGI(TAG, "[MQTT] Subscribed: %s", topic); + } +} + +// +// Message handler +// +static void handle_message(const char *topic, const char *data) +{ + if (!topic || !data) return; + + char base[MQTT_MAX_BASE_TOPIC_LEN] = {0}; + mqtt_get_base_topic(base); + + if (strncmp(topic, base, strlen(base)) != 0) return; + + const char *sub_topic = &topic[strlen(base)]; + ESP_LOGI(TAG, "[MQTT] Received on %s: %s", sub_topic, data); + + if (strcmp(sub_topic, "/request/config/evse") == 0) + { + cJSON *root = json_get_evse_config(); + publish_message("/response/config/evse", root); + cJSON_Delete(root); + } + else if (strcmp(sub_topic, "/set/config/evse") == 0) + { + cJSON *root = cJSON_Parse(data); + if (!root) + { + ESP_LOGE(TAG, "Invalid JSON payload on topic %s", topic); + return; + } + json_set_evse_config(root); + cJSON_Delete(root); + } + else if (strcmp(sub_topic, "/request/restart") == 0) + { + ESP_LOGW(TAG, "Restart request received (TODO: add auth check)"); + // esp_restart(); + } +} + +// +// MQTT event handler +// +static void event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { esp_mqtt_event_handle_t event = event_data; - switch (event_id) { - case MQTT_EVENT_CONNECTED: - ESP_LOGI(TAG, "[MQTT] Connected to broker"); - if (client_task) vTaskResume(client_task); - subcribe_topics(); - break; + switch (event_id) + { + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "[MQTT] Connected to broker"); + mqtt_connected = true; + if (client_task) vTaskResume(client_task); + subscribe_topics(); + break; - case MQTT_EVENT_DATA: { - char topic[64] = {0}; - char data[256] = {0}; + case MQTT_EVENT_DATA: + { + char topic[128] = {0}; + char data_buf[512] = {0}; - int tlen = MIN(event->topic_len, sizeof(topic) - 1); - int dlen = MIN(event->data_len, sizeof(data) - 1); + int tlen = MIN(event->topic_len, (int)sizeof(topic) - 1); + int dlen = MIN(event->data_len, (int)sizeof(data_buf) - 1); - memcpy(topic, event->topic, tlen); - memcpy(data, event->data, dlen); + memcpy(topic, event->topic, tlen); + memcpy(data_buf, event->data, dlen); - handle_message(topic, data); - break; - } - default: - break; + handle_message(topic, data_buf); + break; + } + case MQTT_EVENT_DISCONNECTED: + ESP_LOGW(TAG, "[MQTT] Disconnected from broker"); + mqtt_connected = false; + break; + + default: + break; } } -static void client_task_func(void* param) +// +// Background periodic publisher +// +static void client_task_func(void *param) { - while (true) { - if (!client) vTaskSuspend(NULL); - cJSON* root = json_get_state(); - publish_message("/state", root); - cJSON_Delete(root); + for (;;) + { + if (client && mqtt_connected) + { + cJSON *root = json_get_state(); + publish_message("/state", root); + cJSON_Delete(root); + } + else + { + ESP_LOGW(TAG, "[MQTT] Not connected — skipping state publish"); + } + vTaskDelay(pdMS_TO_TICKS(periodicity * 1000)); } } +// +// Start/stop MQTT +// static void client_start(void) { - char server[64], user[32], password[64]; + char server[MQTT_MAX_SERVER_LEN] = {0}; + char user[MQTT_MAX_USER_LEN] = {0}; + char password[MQTT_MAX_PASSWORD_LEN] = {0}; + mqtt_get_server(server); mqtt_get_user(user); mqtt_get_password(password); + if (!strlen(server)) + { + ESP_LOGW(TAG, "[MQTT] No server configured"); + return; + } + esp_mqtt_client_config_t cfg = { .broker.address.uri = server, .credentials.username = user, .credentials.authentication.password = password }; - if (!client) { + if (!client) + { client = esp_mqtt_client_init(&cfg); esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, event_handler, client); esp_mqtt_client_start(client); + ESP_LOGI(TAG, "[MQTT] Client started"); } } static void client_stop(void) { - if (client) { + if (client) + { + esp_mqtt_client_stop(client); esp_mqtt_client_destroy(client); client = NULL; + mqtt_connected = false; + ESP_LOGI(TAG, "[MQTT] Client stopped"); } } +esp_err_t mqtt_restart(void) +{ + ESP_LOGI(TAG, "[MQTT] Restarting client..."); + + if (client) + { + esp_mqtt_client_stop(client); + esp_mqtt_client_destroy(client); + client = NULL; + mqtt_connected = false; + ESP_LOGI(TAG, "[MQTT] Existing client stopped"); + } + + vTaskDelay(pdMS_TO_TICKS(500)); + client_start(); + + if (client) + { + ESP_LOGI(TAG, "[MQTT] Restart complete"); + return ESP_OK; + } + + ESP_LOGE(TAG, "[MQTT] Restart failed — no valid configuration"); + return ESP_FAIL; +} + +// +// Public API +// void mqtt_init(void) { + if (!mqtt_mutex) + mqtt_mutex = xSemaphoreCreateMutex(); + nvs_handle_t handle; - if (open_mqtt_nvs(&handle) == ESP_OK) { + if (open_mqtt_nvs(&handle) == ESP_OK) + { nvs_get_u16(handle, NVS_PERIODICITY, &periodicity); nvs_close(handle); + if (periodicity == 0) periodicity = 30; } esp_register_shutdown_handler(&client_stop); - xTaskCreate(client_task_func, "mqtt_client_task", 3 * 1024, NULL, 5, &client_task); + xTaskCreate(client_task_func, "mqtt_client_task", 4 * 1024, NULL, 5, &client_task); - if (mqtt_get_enabled()) { + if (mqtt_get_enabled()) + { client_start(); } } -esp_err_t mqtt_set_config(bool enabled, const char* server, const char* base_topic, const char* user, const char* password, uint16_t _periodicity) +esp_err_t mqtt_set_config(bool enabled, const char *server, const char *base_topic, + const char *user, const char *password, uint16_t _periodicity) { nvs_handle_t handle; - if (open_mqtt_nvs(&handle) != ESP_OK) return ESP_ERR_INVALID_STATE; + if (open_mqtt_nvs(&handle) != ESP_OK) + return ESP_ERR_INVALID_STATE; - char full_server[64]; - if (server && strncmp(server, "mqtt://", 7) != 0 && strncmp(server, "tcp://", 6) != 0) { + char full_server[MQTT_MAX_SERVER_LEN]; + if (server && strncmp(server, "mqtt://", 7) != 0 && strncmp(server, "tcp://", 6) != 0) + { snprintf(full_server, sizeof(full_server), "mqtt://%s", server); server = full_server; } - if (enabled) { - if (!server || !*server) return ESP_ERR_INVALID_ARG; - if (!base_topic || !*base_topic) return ESP_ERR_INVALID_ARG; - if (_periodicity == 0) return ESP_ERR_INVALID_ARG; + if (enabled) + { + if (!server || !*server || !base_topic || !*base_topic || !_periodicity) + { + nvs_close(handle); + return ESP_ERR_INVALID_ARG; + } } - if (server) nvs_set_str(handle, NVS_SERVER, server); + if (server) nvs_set_str(handle, NVS_SERVER, server); if (base_topic) nvs_set_str(handle, NVS_BASE_TOPIC, base_topic); - if (user) nvs_set_str(handle, NVS_USER, user); - if (password) nvs_set_str(handle, NVS_PASSWORD, password); - nvs_set_u8(handle, NVS_ENABLED, enabled); - nvs_set_u16(handle, NVS_PERIODICITY, _periodicity); + if (user) nvs_set_str(handle, NVS_USER, user); + if (password) nvs_set_str(handle, NVS_PASSWORD, password); - periodicity = _periodicity; + nvs_set_u8(handle, NVS_ENABLED, enabled ? 1 : 0); + nvs_set_u16(handle, NVS_PERIODICITY, _periodicity); + periodicity = _periodicity ? _periodicity : periodicity; esp_err_t err = nvs_commit(handle); nvs_close(handle); - if (err != ESP_OK) return err; + if (err != ESP_OK) + return err; - if (enabled) { + if (enabled) client_start(); - } else { + else client_stop(); - } return ESP_OK; } +/* ---------------------- Getters públicos (faltavam) ---------------------- */ + bool mqtt_get_enabled(void) { nvs_handle_t handle; - uint8_t val = false; - if (open_mqtt_nvs(&handle) == ESP_OK) { - nvs_get_u8(handle, NVS_ENABLED, &val); + uint8_t en = 0; + if (open_mqtt_nvs(&handle) == ESP_OK) + { + nvs_get_u8(handle, NVS_ENABLED, &en); nvs_close(handle); } - return val; + return en != 0; } -void mqtt_get_server(char* value) +static void nvs_get_str_into(nvs_handle_t handle, const char *key, char *out, size_t outlen) { - if (!value) return; - value[0] = '\0'; - nvs_handle_t handle; - if (open_mqtt_nvs(&handle) == ESP_OK) { - size_t len = 64; - nvs_get_str(handle, NVS_SERVER, value, &len); - nvs_close(handle); - } + if (!out || outlen == 0) return; + out[0] = '\0'; + size_t len = outlen; + esp_err_t err = nvs_get_str(handle, key, out, &len); + if (err != ESP_OK) out[0] = '\0'; } -void mqtt_get_base_topic(char* value) +void mqtt_get_server(char *value) { - if (!value) return; - value[0] = '\0'; nvs_handle_t handle; - if (open_mqtt_nvs(&handle) == ESP_OK) { - size_t len = 32; - nvs_get_str(handle, NVS_BASE_TOPIC, value, &len); + if (open_mqtt_nvs(&handle) == ESP_OK) + { + nvs_get_str_into(handle, NVS_SERVER, value, MQTT_MAX_SERVER_LEN); nvs_close(handle); } + else if (value) value[0] = '\0'; } -void mqtt_get_user(char* value) +void mqtt_get_base_topic(char *value) { - if (!value) return; - value[0] = '\0'; nvs_handle_t handle; - if (open_mqtt_nvs(&handle) == ESP_OK) { - size_t len = 32; - nvs_get_str(handle, NVS_USER, value, &len); + if (open_mqtt_nvs(&handle) == ESP_OK) + { + nvs_get_str_into(handle, NVS_BASE_TOPIC, value, MQTT_MAX_BASE_TOPIC_LEN); nvs_close(handle); } + else if (value) value[0] = '\0'; } -void mqtt_get_password(char* value) +void mqtt_get_user(char *value) { - if (!value) return; - value[0] = '\0'; nvs_handle_t handle; - if (open_mqtt_nvs(&handle) == ESP_OK) { - size_t len = 64; - nvs_get_str(handle, NVS_PASSWORD, value, &len); + if (open_mqtt_nvs(&handle) == ESP_OK) + { + nvs_get_str_into(handle, NVS_USER, value, MQTT_MAX_USER_LEN); nvs_close(handle); } + else if (value) value[0] = '\0'; +} + +void mqtt_get_password(char *value) +{ + nvs_handle_t handle; + if (open_mqtt_nvs(&handle) == ESP_OK) + { + nvs_get_str_into(handle, NVS_PASSWORD, value, MQTT_MAX_PASSWORD_LEN); + nvs_close(handle); + } + else if (value) value[0] = '\0'; } uint16_t mqtt_get_periodicity(void) { + // devolve o cache atual; se não tiver sido carregado, lê NVS + if (periodicity == 0) + { + nvs_handle_t handle; + if (open_mqtt_nvs(&handle) == ESP_OK) + { + nvs_get_u16(handle, NVS_PERIODICITY, &periodicity); + nvs_close(handle); + if (periodicity == 0) periodicity = 30; + } + else + { + periodicity = 30; + } + } return periodicity; -} \ No newline at end of file +} + +// === Fim de: components/protocols/src/mqtt.c === diff --git a/components/protocols/src/protocols.c b/components/protocols/src/protocols.c index 23f186d..4b355ee 100755 --- a/components/protocols/src/protocols.c +++ b/components/protocols/src/protocols.c @@ -1,14 +1,7 @@ #include "protocols.h" -#include "date_time.h" -//#include "rest.h" #include "mqtt.h" -//#include "modbus_tcp.h" void protocols_init(void) { - date_time_init(); - /* Serve static files from the SPIFFS data partition */ - // rest_init("/data"); mqtt_init(); - //modbus_tcp_init(); } \ No newline at end of file diff --git a/components/protocols/src/tz_data.h b/components/protocols/src/tz_data.h deleted file mode 100755 index a99a08b..0000000 --- a/components/protocols/src/tz_data.h +++ /dev/null @@ -1,354 +0,0 @@ - {"Africa/Abidjan", "GMT0"}, - {"Africa/Algiers", "CET-1"}, - {"Africa/Bissau", "GMT0"}, - {"Africa/Cairo", "EET-2EEST,M4.5.5/0,M10.5.4/24"}, - {"Africa/Casablanca", "<+01>-1"}, - {"Africa/Ceuta", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Africa/El_Aaiun", "<+01>-1"}, - {"Africa/Johannesburg", "SAST-2"}, - {"Africa/Juba", "CAT-2"}, - {"Africa/Khartoum", "CAT-2"}, - {"Africa/Lagos", "WAT-1"}, - {"Africa/Maputo", "CAT-2"}, - {"Africa/Monrovia", "GMT0"}, - {"Africa/Nairobi", "EAT-3"}, - {"Africa/Ndjamena", "WAT-1"}, - {"Africa/Sao_Tome", "GMT0"}, - {"Africa/Tripoli", "EET-2"}, - {"Africa/Tunis", "CET-1"}, - {"Africa/Windhoek", "CAT-2"}, - {"America/Adak", "HST10HDT,M3.2.0,M11.1.0"}, - {"America/Anchorage", "AKST9AKDT,M3.2.0,M11.1.0"}, - {"America/Araguaina", "<-03>3"}, - {"America/Argentina/Buenos_Aires", "<-03>3"}, - {"America/Argentina/Catamarca", "<-03>3"}, - {"America/Argentina/Cordoba", "<-03>3"}, - {"America/Argentina/Jujuy", "<-03>3"}, - {"America/Argentina/La_Rioja", "<-03>3"}, - {"America/Argentina/Mendoza", "<-03>3"}, - {"America/Argentina/Rio_Gallegos", "<-03>3"}, - {"America/Argentina/Salta", "<-03>3"}, - {"America/Argentina/San_Juan", "<-03>3"}, - {"America/Argentina/San_Luis", "<-03>3"}, - {"America/Argentina/Tucuman", "<-03>3"}, - {"America/Argentina/Ushuaia", "<-03>3"}, - {"America/Asuncion", "<-04>4<-03>,M10.1.0/0,M3.4.0/0"}, - {"America/Bahia", "<-03>3"}, - {"America/Bahia_Banderas", "CST6"}, - {"America/Barbados", "AST4"}, - {"America/Belem", "<-03>3"}, - {"America/Belize", "CST6"}, - {"America/Boa_Vista", "<-04>4"}, - {"America/Bogota", "<-05>5"}, - {"America/Boise", "MST7MDT,M3.2.0,M11.1.0"}, - {"America/Cambridge_Bay", "MST7MDT,M3.2.0,M11.1.0"}, - {"America/Campo_Grande", "<-04>4"}, - {"America/Cancun", "EST5"}, - {"America/Caracas", "<-04>4"}, - {"America/Cayenne", "<-03>3"}, - {"America/Cayman", "EST5"}, - {"America/Chicago", "CST6CDT,M3.2.0,M11.1.0"}, - {"America/Chihuahua", "CST6"}, - {"America/Costa_Rica", "CST6"}, - {"America/Creston", "MST7"}, - {"America/Cuiaba", "<-04>4"}, - {"America/Curacao", "AST4"}, - {"America/Danmarkshavn", "GMT0"}, - {"America/Dawson", "MST7"}, - {"America/Dawson_Creek", "MST7"}, - {"America/Denver", "MST7MDT,M3.2.0,M11.1.0"}, - {"America/Detroit", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Dominica", "AST4"}, - {"America/Edmonton", "MST7MDT,M3.2.0,M11.1.0"}, - {"America/Eirunepe", "<-05>5"}, - {"America/El_Salvador", "CST6"}, - {"America/Fortaleza", "<-03>3"}, - {"America/Fort_Nelson", "MST7"}, - {"America/Glace_Bay", "AST4ADT,M3.2.0,M11.1.0"}, - {"America/Godthab", "<-02>2<-01>,M3.5.0/-1,M10.5.0/0"}, - {"America/Goose_Bay", "AST4ADT,M3.2.0,M11.1.0"}, - {"America/Grand_Turk", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Grenada", "AST4"}, - {"America/Guadeloupe", "AST4"}, - {"America/Guatemala", "CST6"}, - {"America/Guayaquil", "<-05>5"}, - {"America/Guyana", "<-04>4"}, - {"America/Halifax", "AST4ADT,M3.2.0,M11.1.0"}, - {"America/Havana", "CST5CDT,M3.2.0/0,M11.1.0/1"}, - {"America/Hermosillo", "MST7"}, - {"America/Indiana/Indianapolis", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Indiana/Knox", "CST6CDT,M3.2.0,M11.1.0"}, - {"America/Indiana/Marengo", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Indiana/Petersburg", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Indiana/Tell_City", "CST6CDT,M3.2.0,M11.1.0"}, - {"America/Indiana/Vevay", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Indiana/Vincennes", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Indiana/Winamac", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Inuvik", "MST7MDT,M3.2.0,M11.1.0"}, - {"America/Iqaluit", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Jamaica", "EST5"}, - {"America/Juneau", "AKST9AKDT,M3.2.0,M11.1.0"}, - {"America/Kentucky/Louisville", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Kentucky/Monticello", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/La_Paz", "<-04>4"}, - {"America/Lima", "<-05>5"}, - {"America/Los_Angeles", "PST8PDT,M3.2.0,M11.1.0"}, - {"America/Maceio", "<-03>3"}, - {"America/Managua", "CST6"}, - {"America/Manaus", "<-04>4"}, - {"America/Marigot", "AST4"}, - {"America/Martinique", "AST4"}, - {"America/Matamoros", "CST6CDT,M3.2.0,M11.1.0"}, - {"America/Mazatlan", "MST7"}, - {"America/Menominee", "CST6CDT,M3.2.0,M11.1.0"}, - {"America/Merida", "CST6"}, - {"America/Metlakatla", "AKST9AKDT,M3.2.0,M11.1.0"}, - {"America/Mexico_City", "CST6"}, - {"America/Miquelon", "<-03>3<-02>,M3.2.0,M11.1.0"}, - {"America/Moncton", "AST4ADT,M3.2.0,M11.1.0"}, - {"America/Monterrey", "CST6"}, - {"America/Montevideo", "<-03>3"}, - {"America/New_York", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Nome", "AKST9AKDT,M3.2.0,M11.1.0"}, - {"America/Noronha", "<-02>2"}, - {"America/North_Dakota/Beulah", "CST6CDT,M3.2.0,M11.1.0"}, - {"America/North_Dakota/Center", "CST6CDT,M3.2.0,M11.1.0"}, - {"America/North_Dakota/New_Salem", "CST6CDT,M3.2.0,M11.1.0"}, - {"America/Nuuk", "<-02>2<-01>,M3.5.0/-1,M10.5.0/0"}, - {"America/Ojinaga", "CST6CDT,M3.2.0,M11.1.0"}, - {"America/Panama", "EST5"}, - {"America/Paramaribo", "<-03>3"}, - {"America/Phoenix", "MST7"}, - {"America/Port-au-Prince", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Porto_Velho", "<-04>4"}, - {"America/Puerto_Rico", "AST4"}, - {"America/Punta_Arenas", "<-03>3"}, - {"America/Rankin_Inlet", "CST6CDT,M3.2.0,M11.1.0"}, - {"America/Recife", "<-03>3"}, - {"America/Regina", "CST6"}, - {"America/Resolute", "CST6CDT,M3.2.0,M11.1.0"}, - {"America/Rio_Branco", "<-05>5"}, - {"America/Santarem", "<-03>3"}, - {"America/Santiago", "<-04>4<-03>,M9.1.6/24,M4.1.6/24"}, - {"America/Santo_Domingo", "AST4"}, - {"America/Sao_Paulo", "<-03>3"}, - {"America/Scoresbysund", "<-01>1<+00>,M3.5.0/0,M10.5.0/1"}, - {"America/Sitka", "AKST9AKDT,M3.2.0,M11.1.0"}, - {"America/St_Johns", "NST3:30NDT,M3.2.0,M11.1.0"}, - {"America/Swift_Current", "CST6"}, - {"America/Tegucigalpa", "CST6"}, - {"America/Thule", "AST4ADT,M3.2.0,M11.1.0"}, - {"America/Tijuana", "PST8PDT,M3.2.0,M11.1.0"}, - {"America/Toronto", "EST5EDT,M3.2.0,M11.1.0"}, - {"America/Vancouver", "PST8PDT,M3.2.0,M11.1.0"}, - {"America/Whitehorse", "MST7"}, - {"America/Winnipeg", "CST6CDT,M3.2.0,M11.1.0"}, - {"America/Yakutat", "AKST9AKDT,M3.2.0,M11.1.0"}, - {"Antarctica/Casey", "<+11>-11"}, - {"Antarctica/Davis", "<+07>-7"}, - {"Antarctica/Macquarie", "AEST-10AEDT,M10.1.0,M4.1.0/3"}, - {"Antarctica/Mawson", "<+05>-5"}, - {"Antarctica/Palmer", "<-03>3"}, - {"Antarctica/Rothera", "<-03>3"}, - {"Antarctica/Troll", "<+00>0<+02>-2,M3.5.0/1,M10.5.0/3"}, - {"Asia/Almaty", "<+06>-6"}, - {"Asia/Amman", "<+03>-3"}, - {"Asia/Anadyr", "<+12>-12"}, - {"Asia/Aqtau", "<+05>-5"}, - {"Asia/Aqtobe", "<+05>-5"}, - {"Asia/Ashgabat", "<+05>-5"}, - {"Asia/Atyrau", "<+05>-5"}, - {"Asia/Baghdad", "<+03>-3"}, - {"Asia/Bahrain", "<+03>-3"}, - {"Asia/Baku", "<+04>-4"}, - {"Asia/Bangkok", "<+07>-7"}, - {"Asia/Barnaul", "<+07>-7"}, - {"Asia/Beirut", "EET-2EEST,M3.5.0/0,M10.5.0/0"}, - {"Asia/Bishkek", "<+06>-6"}, - {"Asia/Brunei", "<+08>-8"}, - {"Asia/Chita", "<+09>-9"}, - {"Asia/Choibalsan", "<+08>-8"}, - {"Asia/Colombo", "<+0530>-5:30"}, - {"Asia/Damascus", "<+03>-3"}, - {"Asia/Dhaka", "<+06>-6"}, - {"Asia/Dili", "<+09>-9"}, - {"Asia/Dubai", "<+04>-4"}, - {"Asia/Dushanbe", "<+05>-5"}, - {"Asia/Famagusta", "EET-2EEST,M3.5.0/3,M10.5.0/4"}, - {"Asia/Gaza", "EET-2EEST,M3.4.4/50,M10.4.4/50"}, - {"Asia/Hebron", "EET-2EEST,M3.4.4/50,M10.4.4/50"}, - {"Asia/Ho_Chi_Minh", "<+07>-7"}, - {"Asia/Hong_Kong", "HKT-8"}, - {"Asia/Hovd", "<+07>-7"}, - {"Asia/Irkutsk", "<+08>-8"}, - {"Asia/Jakarta", "WIB-7"}, - {"Asia/Jayapura", "WIT-9"}, - {"Asia/Jerusalem", "IST-2IDT,M3.4.4/26,M10.5.0"}, - {"Asia/Kabul", "<+0430>-4:30"}, - {"Asia/Kamchatka", "<+12>-12"}, - {"Asia/Karachi", "PKT-5"}, - {"Asia/Kathmandu", "<+0545>-5:45"}, - {"Asia/Khandyga", "<+09>-9"}, - {"Asia/Kolkata", "IST-5:30"}, - {"Asia/Krasnoyarsk", "<+07>-7"}, - {"Asia/Kuala_Lumpur", "<+08>-8"}, - {"Asia/Kuching", "<+08>-8"}, - {"Asia/Kuwait", "<+03>-3"}, - {"Asia/Macau", "CST-8"}, - {"Asia/Magadan", "<+11>-11"}, - {"Asia/Makassar", "WITA-8"}, - {"Asia/Manila", "PST-8"}, - {"Asia/Nicosia", "EET-2EEST,M3.5.0/3,M10.5.0/4"}, - {"Asia/Novokuznetsk", "<+07>-7"}, - {"Asia/Novosibirsk", "<+07>-7"}, - {"Asia/Omsk", "<+06>-6"}, - {"Asia/Oral", "<+05>-5"}, - {"Asia/Pontianak", "WIB-7"}, - {"Asia/Pyongyang", "KST-9"}, - {"Asia/Qatar", "<+03>-3"}, - {"Asia/Qyzylorda", "<+05>-5"}, - {"Asia/Riyadh", "<+03>-3"}, - {"Asia/Sakhalin", "<+11>-11"}, - {"Asia/Samarkand", "<+05>-5"}, - {"Asia/Seoul", "KST-9"}, - {"Asia/Shanghai", "CST-8"}, - {"Asia/Singapore", "<+08>-8"}, - {"Asia/Srednekolymsk", "<+11>-11"}, - {"Asia/Taipei", "CST-8"}, - {"Asia/Tashkent", "<+05>-5"}, - {"Asia/Tbilisi", "<+04>-4"}, - {"Asia/Tehran", "<+0330>-3:30"}, - {"Asia/Thimphu", "<+06>-6"}, - {"Asia/Tokyo", "JST-9"}, - {"Asia/Tomsk", "<+07>-7"}, - {"Asia/Ulaanbaatar", "<+08>-8"}, - {"Asia/Urumqi", "<+06>-6"}, - {"Asia/Ust-Nera", "<+10>-10"}, - {"Asia/Vientiane", "<+07>-7"}, - {"Asia/Vladivostok", "<+10>-10"}, - {"Asia/Yakutsk", "<+09>-9"}, - {"Asia/Yangon", "<+0630>-6:30"}, - {"Asia/Yekaterinburg", "<+05>-5"}, - {"Asia/Yerevan", "<+04>-4"}, - {"Atlantic/Azores", "<-01>1<+00>,M3.5.0/0,M10.5.0/1"}, - {"Atlantic/Bermuda", "AST4ADT,M3.2.0,M11.1.0"}, - {"Atlantic/Canary", "WET0WEST,M3.5.0/1,M10.5.0"}, - {"Atlantic/Cape_Verde", "<-01>1"}, - {"Atlantic/Faroe", "WET0WEST,M3.5.0/1,M10.5.0"}, - {"Atlantic/Madeira", "WET0WEST,M3.5.0/1,M10.5.0"}, - {"Atlantic/South_Georgia", "<-02>2"}, - {"Atlantic/Stanley", "<-03>3"}, - {"Australia/Adelaide", "ACST-9:30ACDT,M10.1.0,M4.1.0/3"}, - {"Australia/Brisbane", "AEST-10"}, - {"Australia/Broken_Hill", "ACST-9:30ACDT,M10.1.0,M4.1.0/3"}, - {"Australia/Darwin", "ACST-9:30"}, - {"Australia/Eucla", "<+0845>-8:45"}, - {"Australia/Hobart", "AEST-10AEDT,M10.1.0,M4.1.0/3"}, - {"Australia/Lindeman", "AEST-10"}, - {"Australia/Lord_Howe", "<+1030>-10:30<+11>-11,M10.1.0,M4.1.0"}, - {"Australia/Melbourne", "AEST-10AEDT,M10.1.0,M4.1.0/3"}, - {"Australia/Perth", "AWST-8"}, - {"Australia/Sydney", "AEST-10AEDT,M10.1.0,M4.1.0/3"}, - {"Europe/Andorra", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Astrakhan", "<+04>-4"}, - {"Europe/Athens", "EET-2EEST,M3.5.0/3,M10.5.0/4"}, - {"Europe/Belgrade", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Berlin", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Brussels", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Bucharest", "EET-2EEST,M3.5.0/3,M10.5.0/4"}, - {"Europe/Budapest", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Chisinau", "EET-2EEST,M3.5.0,M10.5.0/3"}, - {"Europe/Dublin", "IST-1GMT0,M10.5.0,M3.5.0/1"}, - {"Europe/Gibraltar", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Helsinki", "EET-2EEST,M3.5.0/3,M10.5.0/4"}, - {"Europe/Istanbul", "<+03>-3"}, - {"Europe/Kaliningrad", "EET-2"}, - {"Europe/Kyiv", "EET-2EEST,M3.5.0/3,M10.5.0/4"}, - {"Europe/Kirov", "MSK-3"}, - {"Europe/Lisbon", "WET0WEST,M3.5.0/1,M10.5.0"}, - {"Europe/London", "GMT0BST,M3.5.0/1,M10.5.0"}, - {"Europe/Madrid", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Malta", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Minsk", "<+03>-3"}, - {"Europe/Moscow", "MSK-3"}, - {"Europe/Paris", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Prague", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Riga", "EET-2EEST,M3.5.0/3,M10.5.0/4"}, - {"Europe/Rome", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Samara", "<+04>-4"}, - {"Europe/Saratov", "<+04>-4"}, - {"Europe/Simferopol", "MSK-3"}, - {"Europe/Sofia", "EET-2EEST,M3.5.0/3,M10.5.0/4"}, - {"Europe/Tallinn", "EET-2EEST,M3.5.0/3,M10.5.0/4"}, - {"Europe/Tirane", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Ulyanovsk", "<+04>-4"}, - {"Europe/Vienna", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Vilnius", "EET-2EEST,M3.5.0/3,M10.5.0/4"}, - {"Europe/Volgograd", "MSK-3"}, - {"Europe/Warsaw", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Europe/Zurich", "CET-1CEST,M3.5.0,M10.5.0/3"}, - {"Indian/Chagos", "<+06>-6"}, - {"Indian/Maldives", "<+05>-5"}, - {"Indian/Mauritius", "<+04>-4"}, - {"Pacific/Apia", "<+13>-13"}, - {"Pacific/Auckland", "NZST-12NZDT,M9.5.0,M4.1.0/3"}, - {"Pacific/Bougainville", "<+11>-11"}, - {"Pacific/Chatham", "<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45"}, - {"Pacific/Chuuk", "<+10>-10"}, - {"Pacific/Easter", "<-06>6<-05>,M9.1.6/22,M4.1.6/22"}, - {"Pacific/Efate", "<+11>-11"}, - {"Pacific/Enderbury", "<+13>-13"}, - {"Pacific/Fakaofo", "<+13>-13"}, - {"Pacific/Fiji", "<+12>-12"}, - {"Pacific/Funafuti", "<+12>-12"}, - {"Pacific/Galapagos", "<-06>6"}, - {"Pacific/Gambier", "<-09>9"}, - {"Pacific/Guadalcanal", "<+11>-11"}, - {"Pacific/Guam", "ChST-10"}, - {"Pacific/Honolulu", "HST10"}, - {"Pacific/Kiritimati", "<+14>-14"}, - {"Pacific/Kosrae", "<+11>-11"}, - {"Pacific/Kwajalein", "<+12>-12"}, - {"Pacific/Majuro", "<+12>-12"}, - {"Pacific/Marquesas", "<-0930>9:30"}, - {"Pacific/Midway", "SST11"}, - {"Pacific/Nauru", "<+12>-12"}, - {"Pacific/Niue", "<-11>11"}, - {"Pacific/Norfolk", "<+11>-11<+12>,M10.1.0,M4.1.0/3"}, - {"Pacific/Noumea", "<+11>-11"}, - {"Pacific/Pago_Pago", "SST11"}, - {"Pacific/Palau", "<+09>-9"}, - {"Pacific/Pitcairn", "<-08>8"}, - {"Pacific/Port_Moresby", "<+10>-10"}, - {"Pacific/Rarotonga", "<-10>10"}, - {"Pacific/Tahiti", "<-10>10"}, - {"Pacific/Tarawa", "<+12>-12"}, - {"Pacific/Tongatapu", "<+13>-13"}, - {"Etc/GMT", "GMT0"}, - {"Etc/GMT-1", "<+01>-1"}, - {"Etc/GMT-2", "<+02>-2"}, - {"Etc/GMT-3", "<+03>-3"}, - {"Etc/GMT-4", "<+04>-4"}, - {"Etc/GMT-5", "<+05>-5"}, - {"Etc/GMT-6", "<+06>-6"}, - {"Etc/GMT-7", "<+07>-7"}, - {"Etc/GMT-8", "<+08>-8"}, - {"Etc/GMT-9", "<+09>-9"}, - {"Etc/GMT-10", "<+10>-10"}, - {"Etc/GMT-11", "<+11>-11"}, - {"Etc/GMT-12", "<+12>-12"}, - {"Etc/GMT-13", "<+13>-13"}, - {"Etc/GMT-14", "<+14>-14"}, - {"Etc/GMT+1", "<-01>1"}, - {"Etc/GMT+2", "<-02>2"}, - {"Etc/GMT+3", "<-03>3"}, - {"Etc/GMT+4", "<-04>4"}, - {"Etc/GMT+5", "<-05>5"}, - {"Etc/GMT+6", "<-06>6"}, - {"Etc/GMT+7", "<-07>7"}, - {"Etc/GMT+8", "<-08>8"}, - {"Etc/GMT+9", "<-09>9"}, - {"Etc/GMT+10", "<-10>10"}, - {"Etc/GMT+11", "<-11>11"}, - {"Etc/GMT+12", "<-12>12"}, - {"Etc/UTC", "UTC0"}, diff --git a/components/protocols/webfolder/assets/index-C_08vMAY.js b/components/protocols/webfolder/assets/index-C_08vMAY.js deleted file mode 100644 index ab0f012..0000000 --- a/components/protocols/webfolder/assets/index-C_08vMAY.js +++ /dev/null @@ -1,51 +0,0 @@ -(function(){const o=document.createElement("link").relList;if(o&&o.supports&&o.supports("modulepreload"))return;for(const d of document.querySelectorAll('link[rel="modulepreload"]'))f(d);new MutationObserver(d=>{for(const v of d)if(v.type==="childList")for(const p of v.addedNodes)p.tagName==="LINK"&&p.rel==="modulepreload"&&f(p)}).observe(document,{childList:!0,subtree:!0});function s(d){const v={};return d.integrity&&(v.integrity=d.integrity),d.referrerPolicy&&(v.referrerPolicy=d.referrerPolicy),d.crossOrigin==="use-credentials"?v.credentials="include":d.crossOrigin==="anonymous"?v.credentials="omit":v.credentials="same-origin",v}function f(d){if(d.ep)return;d.ep=!0;const v=s(d);fetch(d.href,v)}})();function $d(i){return i&&i.__esModule&&Object.prototype.hasOwnProperty.call(i,"default")?i.default:i}var Tf={exports:{}},Du={};/** - * @license React - * react-jsx-runtime.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var _d;function By(){if(_d)return Du;_d=1;var i=Symbol.for("react.transitional.element"),o=Symbol.for("react.fragment");function s(f,d,v){var p=null;if(v!==void 0&&(p=""+v),d.key!==void 0&&(p=""+d.key),"key"in d){v={};for(var j in d)j!=="key"&&(v[j]=d[j])}else v=d;return d=v.ref,{$$typeof:i,type:f,key:p,ref:d!==void 0?d:null,props:v}}return Du.Fragment=o,Du.jsx=s,Du.jsxs=s,Du}var Cd;function qy(){return Cd||(Cd=1,Tf.exports=By()),Tf.exports}var h=qy(),Af={exports:{}},te={};/** - * @license React - * react.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Ud;function wy(){if(Ud)return te;Ud=1;var i=Symbol.for("react.transitional.element"),o=Symbol.for("react.portal"),s=Symbol.for("react.fragment"),f=Symbol.for("react.strict_mode"),d=Symbol.for("react.profiler"),v=Symbol.for("react.consumer"),p=Symbol.for("react.context"),j=Symbol.for("react.forward_ref"),S=Symbol.for("react.suspense"),m=Symbol.for("react.memo"),M=Symbol.for("react.lazy"),H=Symbol.iterator;function O(g){return g===null||typeof g!="object"?null:(g=H&&g[H]||g["@@iterator"],typeof g=="function"?g:null)}var q={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},U=Object.assign,G={};function V(g,B,Q){this.props=g,this.context=B,this.refs=G,this.updater=Q||q}V.prototype.isReactComponent={},V.prototype.setState=function(g,B){if(typeof g!="object"&&typeof g!="function"&&g!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,g,B,"setState")},V.prototype.forceUpdate=function(g){this.updater.enqueueForceUpdate(this,g,"forceUpdate")};function w(){}w.prototype=V.prototype;function Z(g,B,Q){this.props=g,this.context=B,this.refs=G,this.updater=Q||q}var k=Z.prototype=new w;k.constructor=Z,U(k,V.prototype),k.isPureReactComponent=!0;var ce=Array.isArray,L={H:null,A:null,T:null,S:null,V:null},fe=Object.prototype.hasOwnProperty;function ue(g,B,Q,Y,$,oe){return Q=oe.ref,{$$typeof:i,type:g,key:B,ref:Q!==void 0?Q:null,props:oe}}function se(g,B){return ue(g.type,B,void 0,void 0,void 0,g.props)}function Ee(g){return typeof g=="object"&&g!==null&&g.$$typeof===i}function Je(g){var B={"=":"=0",":":"=2"};return"$"+g.replace(/[=:]/g,function(Q){return B[Q]})}var ot=/\/+/g;function Xe(g,B){return typeof g=="object"&&g!==null&&g.key!=null?Je(""+g.key):B.toString(36)}function Nl(){}function Ol(g){switch(g.status){case"fulfilled":return g.value;case"rejected":throw g.reason;default:switch(typeof g.status=="string"?g.then(Nl,Nl):(g.status="pending",g.then(function(B){g.status==="pending"&&(g.status="fulfilled",g.value=B)},function(B){g.status==="pending"&&(g.status="rejected",g.reason=B)})),g.status){case"fulfilled":return g.value;case"rejected":throw g.reason}}throw g}function Qe(g,B,Q,Y,$){var oe=typeof g;(oe==="undefined"||oe==="boolean")&&(g=null);var ee=!1;if(g===null)ee=!0;else switch(oe){case"bigint":case"string":case"number":ee=!0;break;case"object":switch(g.$$typeof){case i:case o:ee=!0;break;case M:return ee=g._init,Qe(ee(g._payload),B,Q,Y,$)}}if(ee)return $=$(g),ee=Y===""?"."+Xe(g,0):Y,ce($)?(Q="",ee!=null&&(Q=ee.replace(ot,"$&/")+"/"),Qe($,B,Q,"",function(el){return el})):$!=null&&(Ee($)&&($=se($,Q+($.key==null||g&&g.key===$.key?"":(""+$.key).replace(ot,"$&/")+"/")+ee)),B.push($)),1;ee=0;var tt=Y===""?".":Y+":";if(ce(g))for(var Te=0;Te>>1,g=D[pe];if(0>>1;ped(Y,P))$d(oe,Y)?(D[pe]=oe,D[$]=P,pe=$):(D[pe]=Y,D[Q]=P,pe=Q);else if($d(oe,P))D[pe]=oe,D[$]=P,pe=$;else break e}}return X}function d(D,X){var P=D.sortIndex-X.sortIndex;return P!==0?P:D.id-X.id}if(i.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var v=performance;i.unstable_now=function(){return v.now()}}else{var p=Date,j=p.now();i.unstable_now=function(){return p.now()-j}}var S=[],m=[],M=1,H=null,O=3,q=!1,U=!1,G=!1,V=!1,w=typeof setTimeout=="function"?setTimeout:null,Z=typeof clearTimeout=="function"?clearTimeout:null,k=typeof setImmediate<"u"?setImmediate:null;function ce(D){for(var X=s(m);X!==null;){if(X.callback===null)f(m);else if(X.startTime<=D)f(m),X.sortIndex=X.expirationTime,o(S,X);else break;X=s(m)}}function L(D){if(G=!1,ce(D),!U)if(s(S)!==null)U=!0,fe||(fe=!0,Xe());else{var X=s(m);X!==null&&Qe(L,X.startTime-D)}}var fe=!1,ue=-1,se=5,Ee=-1;function Je(){return V?!0:!(i.unstable_now()-EeD&&Je());){var pe=H.callback;if(typeof pe=="function"){H.callback=null,O=H.priorityLevel;var g=pe(H.expirationTime<=D);if(D=i.unstable_now(),typeof g=="function"){H.callback=g,ce(D),X=!0;break t}H===s(S)&&f(S),ce(D)}else f(S);H=s(S)}if(H!==null)X=!0;else{var B=s(m);B!==null&&Qe(L,B.startTime-D),X=!1}}break e}finally{H=null,O=P,q=!1}X=void 0}}finally{X?Xe():fe=!1}}}var Xe;if(typeof k=="function")Xe=function(){k(ot)};else if(typeof MessageChannel<"u"){var Nl=new MessageChannel,Ol=Nl.port2;Nl.port1.onmessage=ot,Xe=function(){Ol.postMessage(null)}}else Xe=function(){w(ot,0)};function Qe(D,X){ue=w(function(){D(i.unstable_now())},X)}i.unstable_IdlePriority=5,i.unstable_ImmediatePriority=1,i.unstable_LowPriority=4,i.unstable_NormalPriority=3,i.unstable_Profiling=null,i.unstable_UserBlockingPriority=2,i.unstable_cancelCallback=function(D){D.callback=null},i.unstable_forceFrameRate=function(D){0>D||125pe?(D.sortIndex=P,o(m,D),s(S)===null&&D===s(m)&&(G?(Z(ue),ue=-1):G=!0,Qe(L,P-pe))):(D.sortIndex=g,o(S,D),U||q||(U=!0,fe||(fe=!0,Xe()))),D},i.unstable_shouldYield=Je,i.unstable_wrapCallback=function(D){var X=O;return function(){var P=O;O=X;try{return D.apply(this,arguments)}finally{O=P}}}}(Of)),Of}var qd;function Gy(){return qd||(qd=1,Nf.exports=Yy()),Nf.exports}var Mf={exports:{}},Ke={};/** - * @license React - * react-dom.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var wd;function Xy(){if(wd)return Ke;wd=1;var i=Cf();function o(S){var m="https://react.dev/errors/"+S;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(i)}catch(o){console.error(o)}}return i(),Mf.exports=Xy(),Mf.exports}/** - * @license React - * react-dom-client.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Yd;function Zy(){if(Yd)return _u;Yd=1;var i=Gy(),o=Cf(),s=Qy();function f(e){var t="https://react.dev/errors/"+e;if(1g||(e.current=pe[g],pe[g]=null,g--)}function Y(e,t){g++,pe[g]=e.current,e.current=t}var $=B(null),oe=B(null),ee=B(null),tt=B(null);function Te(e,t){switch(Y(ee,t),Y(oe,e),Y($,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?id(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=id(t),e=cd(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}Q($),Y($,e)}function el(){Q($),Q(oe),Q(ee)}function ci(e){e.memoizedState!==null&&Y(tt,e);var t=$.current,l=cd(t,e.type);t!==l&&(Y(oe,e),Y($,l))}function Lu(e){oe.current===e&&(Q($),Q(oe)),tt.current===e&&(Q(tt),Nu._currentValue=P)}var fi=Object.prototype.hasOwnProperty,ri=i.unstable_scheduleCallback,si=i.unstable_cancelCallback,mh=i.unstable_shouldYield,yh=i.unstable_requestPaint,At=i.unstable_now,vh=i.unstable_getCurrentPriorityLevel,Lf=i.unstable_ImmediatePriority,Yf=i.unstable_UserBlockingPriority,Yu=i.unstable_NormalPriority,gh=i.unstable_LowPriority,Gf=i.unstable_IdlePriority,bh=i.log,ph=i.unstable_setDisableYieldValue,Ua=null,lt=null;function tl(e){if(typeof bh=="function"&&ph(e),lt&&typeof lt.setStrictMode=="function")try{lt.setStrictMode(Ua,e)}catch{}}var at=Math.clz32?Math.clz32:Eh,Sh=Math.log,xh=Math.LN2;function Eh(e){return e>>>=0,e===0?32:31-(Sh(e)/xh|0)|0}var Gu=256,Xu=4194304;function Ml(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194048;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Qu(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var u=0,n=e.suspendedLanes,c=e.pingedLanes;e=e.warmLanes;var r=a&134217727;return r!==0?(a=r&~n,a!==0?u=Ml(a):(c&=r,c!==0?u=Ml(c):l||(l=r&~e,l!==0&&(u=Ml(l))))):(r=a&~n,r!==0?u=Ml(r):c!==0?u=Ml(c):l||(l=a&~e,l!==0&&(u=Ml(l)))),u===0?0:t!==0&&t!==u&&(t&n)===0&&(n=u&-u,l=t&-t,n>=l||n===32&&(l&4194048)!==0)?t:u}function Ha(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Th(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Xf(){var e=Gu;return Gu<<=1,(Gu&4194048)===0&&(Gu=256),e}function Qf(){var e=Xu;return Xu<<=1,(Xu&62914560)===0&&(Xu=4194304),e}function oi(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function Ba(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Ah(e,t,l,a,u,n){var c=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var r=e.entanglements,y=e.expirationTimes,T=e.hiddenUpdates;for(l=c&~l;0)":-1u||y[a]!==T[u]){var z=` -`+y[a].replace(" at new "," at ");return e.displayName&&z.includes("")&&(z=z.replace("",e.displayName)),z}while(1<=a&&0<=u);break}}}finally{gi=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?Pl(l):""}function zh(e){switch(e.tag){case 26:case 27:case 5:return Pl(e.type);case 16:return Pl("Lazy");case 13:return Pl("Suspense");case 19:return Pl("SuspenseList");case 0:case 15:return bi(e.type,!1);case 11:return bi(e.type.render,!1);case 1:return bi(e.type,!0);case 31:return Pl("Activity");default:return""}}function If(e){try{var t="";do t+=zh(e),e=e.return;while(e);return t}catch(l){return` -Error generating stack: `+l.message+` -`+l.stack}}function dt(e){switch(typeof e){case"bigint":case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function er(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Dh(e){var t=er(e)?"checked":"value",l=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),a=""+e[t];if(!e.hasOwnProperty(t)&&typeof l<"u"&&typeof l.get=="function"&&typeof l.set=="function"){var u=l.get,n=l.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return u.call(this)},set:function(c){a=""+c,n.call(this,c)}}),Object.defineProperty(e,t,{enumerable:l.enumerable}),{getValue:function(){return a},setValue:function(c){a=""+c},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Ku(e){e._valueTracker||(e._valueTracker=Dh(e))}function tr(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var l=t.getValue(),a="";return e&&(a=er(e)?e.checked?"true":"false":e.value),e=a,e!==l?(t.setValue(e),!0):!1}function Ju(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var _h=/[\n"\\]/g;function ht(e){return e.replace(_h,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function pi(e,t,l,a,u,n,c,r){e.name="",c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?e.type=c:e.removeAttribute("type"),t!=null?c==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+dt(t)):e.value!==""+dt(t)&&(e.value=""+dt(t)):c!=="submit"&&c!=="reset"||e.removeAttribute("value"),t!=null?Si(e,c,dt(t)):l!=null?Si(e,c,dt(l)):a!=null&&e.removeAttribute("value"),u==null&&n!=null&&(e.defaultChecked=!!n),u!=null&&(e.checked=u&&typeof u!="function"&&typeof u!="symbol"),r!=null&&typeof r!="function"&&typeof r!="symbol"&&typeof r!="boolean"?e.name=""+dt(r):e.removeAttribute("name")}function lr(e,t,l,a,u,n,c,r){if(n!=null&&typeof n!="function"&&typeof n!="symbol"&&typeof n!="boolean"&&(e.type=n),t!=null||l!=null){if(!(n!=="submit"&&n!=="reset"||t!=null))return;l=l!=null?""+dt(l):"",t=t!=null?""+dt(t):l,r||t===e.value||(e.value=t),e.defaultValue=t}a=a??u,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=r?e.checked:!!a,e.defaultChecked=!!a,c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"&&(e.name=c)}function Si(e,t,l){t==="number"&&Ju(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function Il(e,t,l,a){if(e=e.options,t){t={};for(var u=0;u"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Ri=!1;if(Bt)try{var Ya={};Object.defineProperty(Ya,"passive",{get:function(){Ri=!0}}),window.addEventListener("test",Ya,Ya),window.removeEventListener("test",Ya,Ya)}catch{Ri=!1}var al=null,Ni=null,$u=null;function rr(){if($u)return $u;var e,t=Ni,l=t.length,a,u="value"in al?al.value:al.textContent,n=u.length;for(e=0;e=Qa),yr=" ",vr=!1;function gr(e,t){switch(e){case"keyup":return im.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function br(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var aa=!1;function fm(e,t){switch(e){case"compositionend":return br(t);case"keypress":return t.which!==32?null:(vr=!0,yr);case"textInput":return e=t.data,e===yr&&vr?null:e;default:return null}}function rm(e,t){if(aa)return e==="compositionend"||!Di&&gr(e,t)?(e=rr(),$u=Ni=al=null,aa=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Nr(l)}}function Mr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Mr(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function jr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Ju(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=Ju(e.document)}return t}function Ui(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var gm=Bt&&"documentMode"in document&&11>=document.documentMode,ua=null,Hi=null,Ja=null,Bi=!1;function zr(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;Bi||ua==null||ua!==Ju(a)||(a=ua,"selectionStart"in a&&Ui(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),Ja&&Ka(Ja,a)||(Ja=a,a=Yn(Hi,"onSelect"),0>=c,u-=c,wt=1<<32-at(t)+u|l<n?n:8;var c=D.T,r={};D.T=r,xc(e,!1,t,l);try{var y=u(),T=D.S;if(T!==null&&T(r,y),y!==null&&typeof y=="object"&&typeof y.then=="function"){var z=Nm(y,a);fu(e,t,z,rt(e))}else fu(e,t,a,rt(e))}catch(C){fu(e,t,{then:function(){},status:"rejected",reason:C},rt())}finally{X.p=n,D.T=c}}function Dm(){}function pc(e,t,l,a){if(e.tag!==5)throw Error(f(476));var u=Ds(e).queue;zs(e,u,t,P,l===null?Dm:function(){return _s(e),l(a)})}function Ds(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:P,baseState:P,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Xt,lastRenderedState:P},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Xt,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function _s(e){var t=Ds(e).next.queue;fu(e,t,{},rt())}function Sc(){return Ve(Nu)}function Cs(){return _e().memoizedState}function Us(){return _e().memoizedState}function _m(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=rt();e=il(l);var a=cl(t,e,l);a!==null&&(st(a,t,l),lu(a,t,l)),t={cache:Wi()},e.payload=t;return}t=t.return}}function Cm(e,t,l){var a=rt();l={lane:a,revertLane:0,action:l,hasEagerState:!1,eagerState:null,next:null},Sn(e)?Bs(t,l):(l=Yi(e,t,l,a),l!==null&&(st(l,e,a),qs(l,t,a)))}function Hs(e,t,l){var a=rt();fu(e,t,l,a)}function fu(e,t,l,a){var u={lane:a,revertLane:0,action:l,hasEagerState:!1,eagerState:null,next:null};if(Sn(e))Bs(t,u);else{var n=e.alternate;if(e.lanes===0&&(n===null||n.lanes===0)&&(n=t.lastRenderedReducer,n!==null))try{var c=t.lastRenderedState,r=n(c,l);if(u.hasEagerState=!0,u.eagerState=r,ut(r,c))return ln(e,t,u,0),xe===null&&tn(),!1}catch{}finally{}if(l=Yi(e,t,u,a),l!==null)return st(l,e,a),qs(l,t,a),!0}return!1}function xc(e,t,l,a){if(a={lane:2,revertLane:Ic(),action:a,hasEagerState:!1,eagerState:null,next:null},Sn(e)){if(t)throw Error(f(479))}else t=Yi(e,l,a,2),t!==null&&st(t,e,2)}function Sn(e){var t=e.alternate;return e===le||t!==null&&t===le}function Bs(e,t){ma=mn=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function qs(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,Vf(e,l)}}var xn={readContext:Ve,use:vn,useCallback:je,useContext:je,useEffect:je,useImperativeHandle:je,useLayoutEffect:je,useInsertionEffect:je,useMemo:je,useReducer:je,useRef:je,useState:je,useDebugValue:je,useDeferredValue:je,useTransition:je,useSyncExternalStore:je,useId:je,useHostTransitionStatus:je,useFormState:je,useActionState:je,useOptimistic:je,useMemoCache:je,useCacheRefresh:je},ws={readContext:Ve,use:vn,useCallback:function(e,t){return Fe().memoizedState=[e,t===void 0?null:t],e},useContext:Ve,useEffect:xs,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,pn(4194308,4,Rs.bind(null,t,e),l)},useLayoutEffect:function(e,t){return pn(4194308,4,e,t)},useInsertionEffect:function(e,t){pn(4,2,e,t)},useMemo:function(e,t){var l=Fe();t=t===void 0?null:t;var a=e();if(Gl){tl(!0);try{e()}finally{tl(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=Fe();if(l!==void 0){var u=l(t);if(Gl){tl(!0);try{l(t)}finally{tl(!1)}}}else u=t;return a.memoizedState=a.baseState=u,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:u},a.queue=e,e=e.dispatch=Cm.bind(null,le,e),[a.memoizedState,e]},useRef:function(e){var t=Fe();return e={current:e},t.memoizedState=e},useState:function(e){e=yc(e);var t=e.queue,l=Hs.bind(null,le,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:gc,useDeferredValue:function(e,t){var l=Fe();return bc(l,e,t)},useTransition:function(){var e=yc(!1);return e=zs.bind(null,le,e.queue,!0,!1),Fe().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=le,u=Fe();if(he){if(l===void 0)throw Error(f(407));l=l()}else{if(l=t(),xe===null)throw Error(f(349));(re&124)!==0||ns(a,t,l)}u.memoizedState=l;var n={value:l,getSnapshot:t};return u.queue=n,xs(cs.bind(null,a,n,e),[e]),a.flags|=2048,va(9,bn(),is.bind(null,a,n,l,t),null),l},useId:function(){var e=Fe(),t=xe.identifierPrefix;if(he){var l=Lt,a=wt;l=(a&~(1<<32-at(a)-1)).toString(32)+l,t="«"+t+"R"+l,l=yn++,0F?(we=J,J=null):we=J.sibling;var de=R(x,J,E[F],_);if(de===null){J===null&&(J=we);break}e&&J&&de.alternate===null&&t(x,J),b=n(de,b,F),ae===null?K=de:ae.sibling=de,ae=de,J=we}if(F===E.length)return l(x,J),he&&Hl(x,F),K;if(J===null){for(;FF?(we=J,J=null):we=J.sibling;var Al=R(x,J,de.value,_);if(Al===null){J===null&&(J=we);break}e&&J&&Al.alternate===null&&t(x,J),b=n(Al,b,F),ae===null?K=Al:ae.sibling=Al,ae=Al,J=we}if(de.done)return l(x,J),he&&Hl(x,F),K;if(J===null){for(;!de.done;F++,de=E.next())de=C(x,de.value,_),de!==null&&(b=n(de,b,F),ae===null?K=de:ae.sibling=de,ae=de);return he&&Hl(x,F),K}for(J=a(J);!de.done;F++,de=E.next())de=N(J,x,F,de.value,_),de!==null&&(e&&de.alternate!==null&&J.delete(de.key===null?F:de.key),b=n(de,b,F),ae===null?K=de:ae.sibling=de,ae=de);return e&&J.forEach(function(Hy){return t(x,Hy)}),he&&Hl(x,F),K}function be(x,b,E,_){if(typeof E=="object"&&E!==null&&E.type===U&&E.key===null&&(E=E.props.children),typeof E=="object"&&E!==null){switch(E.$$typeof){case O:e:{for(var K=E.key;b!==null;){if(b.key===K){if(K=E.type,K===U){if(b.tag===7){l(x,b.sibling),_=u(b,E.props.children),_.return=x,x=_;break e}}else if(b.elementType===K||typeof K=="object"&&K!==null&&K.$$typeof===se&&Ys(K)===b.type){l(x,b.sibling),_=u(b,E.props),su(_,E),_.return=x,x=_;break e}l(x,b);break}else t(x,b);b=b.sibling}E.type===U?(_=Cl(E.props.children,x.mode,_,E.key),_.return=x,x=_):(_=un(E.type,E.key,E.props,null,x.mode,_),su(_,E),_.return=x,x=_)}return c(x);case q:e:{for(K=E.key;b!==null;){if(b.key===K)if(b.tag===4&&b.stateNode.containerInfo===E.containerInfo&&b.stateNode.implementation===E.implementation){l(x,b.sibling),_=u(b,E.children||[]),_.return=x,x=_;break e}else{l(x,b);break}else t(x,b);b=b.sibling}_=Qi(E,x.mode,_),_.return=x,x=_}return c(x);case se:return K=E._init,E=K(E._payload),be(x,b,E,_)}if(Qe(E))return I(x,b,E,_);if(Xe(E)){if(K=Xe(E),typeof K!="function")throw Error(f(150));return E=K.call(E),W(x,b,E,_)}if(typeof E.then=="function")return be(x,b,En(E),_);if(E.$$typeof===k)return be(x,b,rn(x,E),_);Tn(x,E)}return typeof E=="string"&&E!==""||typeof E=="number"||typeof E=="bigint"?(E=""+E,b!==null&&b.tag===6?(l(x,b.sibling),_=u(b,E),_.return=x,x=_):(l(x,b),_=Xi(E,x.mode,_),_.return=x,x=_),c(x)):l(x,b)}return function(x,b,E,_){try{ru=0;var K=be(x,b,E,_);return ga=null,K}catch(J){if(J===eu||J===on)throw J;var ae=nt(29,J,null,x.mode);return ae.lanes=_,ae.return=x,ae}finally{}}}var ba=Gs(!0),Xs=Gs(!1),bt=B(null),Nt=null;function rl(e){var t=e.alternate;Y(Ue,Ue.current&1),Y(bt,e),Nt===null&&(t===null||ha.current!==null||t.memoizedState!==null)&&(Nt=e)}function Qs(e){if(e.tag===22){if(Y(Ue,Ue.current),Y(bt,e),Nt===null){var t=e.alternate;t!==null&&t.memoizedState!==null&&(Nt=e)}}else sl()}function sl(){Y(Ue,Ue.current),Y(bt,bt.current)}function Qt(e){Q(bt),Nt===e&&(Nt=null),Q(Ue)}var Ue=B(0);function An(e){for(var t=e;t!==null;){if(t.tag===13){var l=t.memoizedState;if(l!==null&&(l=l.dehydrated,l===null||l.data==="$?"||df(l)))return t}else if(t.tag===19&&t.memoizedProps.revealOrder!==void 0){if((t.flags&128)!==0)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}function Ec(e,t,l,a){t=e.memoizedState,l=l(a,t),l=l==null?t:M({},t,l),e.memoizedState=l,e.lanes===0&&(e.updateQueue.baseState=l)}var Tc={enqueueSetState:function(e,t,l){e=e._reactInternals;var a=rt(),u=il(a);u.payload=t,l!=null&&(u.callback=l),t=cl(e,u,a),t!==null&&(st(t,e,a),lu(t,e,a))},enqueueReplaceState:function(e,t,l){e=e._reactInternals;var a=rt(),u=il(a);u.tag=1,u.payload=t,l!=null&&(u.callback=l),t=cl(e,u,a),t!==null&&(st(t,e,a),lu(t,e,a))},enqueueForceUpdate:function(e,t){e=e._reactInternals;var l=rt(),a=il(l);a.tag=2,t!=null&&(a.callback=t),t=cl(e,a,l),t!==null&&(st(t,e,l),lu(t,e,l))}};function Zs(e,t,l,a,u,n,c){return e=e.stateNode,typeof e.shouldComponentUpdate=="function"?e.shouldComponentUpdate(a,n,c):t.prototype&&t.prototype.isPureReactComponent?!Ka(l,a)||!Ka(u,n):!0}function Vs(e,t,l,a){e=t.state,typeof t.componentWillReceiveProps=="function"&&t.componentWillReceiveProps(l,a),typeof t.UNSAFE_componentWillReceiveProps=="function"&&t.UNSAFE_componentWillReceiveProps(l,a),t.state!==e&&Tc.enqueueReplaceState(t,t.state,null)}function Xl(e,t){var l=t;if("ref"in t){l={};for(var a in t)a!=="ref"&&(l[a]=t[a])}if(e=e.defaultProps){l===t&&(l=M({},l));for(var u in e)l[u]===void 0&&(l[u]=e[u])}return l}var Rn=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function Ks(e){Rn(e)}function Js(e){console.error(e)}function ks(e){Rn(e)}function Nn(e,t){try{var l=e.onUncaughtError;l(t.value,{componentStack:t.stack})}catch(a){setTimeout(function(){throw a})}}function $s(e,t,l){try{var a=e.onCaughtError;a(l.value,{componentStack:l.stack,errorBoundary:t.tag===1?t.stateNode:null})}catch(u){setTimeout(function(){throw u})}}function Ac(e,t,l){return l=il(l),l.tag=3,l.payload={element:null},l.callback=function(){Nn(e,t)},l}function Ws(e){return e=il(e),e.tag=3,e}function Fs(e,t,l,a){var u=l.type.getDerivedStateFromError;if(typeof u=="function"){var n=a.value;e.payload=function(){return u(n)},e.callback=function(){$s(t,l,a)}}var c=l.stateNode;c!==null&&typeof c.componentDidCatch=="function"&&(e.callback=function(){$s(t,l,a),typeof u!="function"&&(vl===null?vl=new Set([this]):vl.add(this));var r=a.stack;this.componentDidCatch(a.value,{componentStack:r!==null?r:""})})}function Hm(e,t,l,a,u){if(l.flags|=32768,a!==null&&typeof a=="object"&&typeof a.then=="function"){if(t=l.alternate,t!==null&&Fa(t,l,u,!0),l=bt.current,l!==null){switch(l.tag){case 13:return Nt===null?kc():l.alternate===null&&Me===0&&(Me=3),l.flags&=-257,l.flags|=65536,l.lanes=u,a===Ii?l.flags|=16384:(t=l.updateQueue,t===null?l.updateQueue=new Set([a]):t.add(a),Wc(e,a,u)),!1;case 22:return l.flags|=65536,a===Ii?l.flags|=16384:(t=l.updateQueue,t===null?(t={transitions:null,markerInstances:null,retryQueue:new Set([a])},l.updateQueue=t):(l=t.retryQueue,l===null?t.retryQueue=new Set([a]):l.add(a)),Wc(e,a,u)),!1}throw Error(f(435,l.tag))}return Wc(e,a,u),kc(),!1}if(he)return t=bt.current,t!==null?((t.flags&65536)===0&&(t.flags|=256),t.flags|=65536,t.lanes=u,a!==Ki&&(e=Error(f(422),{cause:a}),Wa(mt(e,l)))):(a!==Ki&&(t=Error(f(423),{cause:a}),Wa(mt(t,l))),e=e.current.alternate,e.flags|=65536,u&=-u,e.lanes|=u,a=mt(a,l),u=Ac(e.stateNode,a,u),lc(e,u),Me!==4&&(Me=2)),!1;var n=Error(f(520),{cause:a});if(n=mt(n,l),gu===null?gu=[n]:gu.push(n),Me!==4&&(Me=2),t===null)return!0;a=mt(a,l),l=t;do{switch(l.tag){case 3:return l.flags|=65536,e=u&-u,l.lanes|=e,e=Ac(l.stateNode,a,e),lc(l,e),!1;case 1:if(t=l.type,n=l.stateNode,(l.flags&128)===0&&(typeof t.getDerivedStateFromError=="function"||n!==null&&typeof n.componentDidCatch=="function"&&(vl===null||!vl.has(n))))return l.flags|=65536,u&=-u,l.lanes|=u,u=Ws(u),Fs(u,e,l,a),lc(l,u),!1}l=l.return}while(l!==null);return!1}var Ps=Error(f(461)),Be=!1;function Le(e,t,l,a){t.child=e===null?Xs(t,null,l,a):ba(t,e.child,l,a)}function Is(e,t,l,a,u){l=l.render;var n=t.ref;if("ref"in a){var c={};for(var r in a)r!=="ref"&&(c[r]=a[r])}else c=a;return Ll(t),a=cc(e,t,l,c,n,u),r=fc(),e!==null&&!Be?(rc(e,t,u),Zt(e,t,u)):(he&&r&&Zi(t),t.flags|=1,Le(e,t,a,u),t.child)}function eo(e,t,l,a,u){if(e===null){var n=l.type;return typeof n=="function"&&!Gi(n)&&n.defaultProps===void 0&&l.compare===null?(t.tag=15,t.type=n,to(e,t,n,a,u)):(e=un(l.type,null,a,t,t.mode,u),e.ref=t.ref,e.return=t,t.child=e)}if(n=e.child,!_c(e,u)){var c=n.memoizedProps;if(l=l.compare,l=l!==null?l:Ka,l(c,a)&&e.ref===t.ref)return Zt(e,t,u)}return t.flags|=1,e=qt(n,a),e.ref=t.ref,e.return=t,t.child=e}function to(e,t,l,a,u){if(e!==null){var n=e.memoizedProps;if(Ka(n,a)&&e.ref===t.ref)if(Be=!1,t.pendingProps=a=n,_c(e,u))(e.flags&131072)!==0&&(Be=!0);else return t.lanes=e.lanes,Zt(e,t,u)}return Rc(e,t,l,a,u)}function lo(e,t,l){var a=t.pendingProps,u=a.children,n=e!==null?e.memoizedState:null;if(a.mode==="hidden"){if((t.flags&128)!==0){if(a=n!==null?n.baseLanes|l:l,e!==null){for(u=t.child=e.child,n=0;u!==null;)n=n|u.lanes|u.childLanes,u=u.sibling;t.childLanes=n&~a}else t.childLanes=0,t.child=null;return ao(e,t,a,l)}if((l&536870912)!==0)t.memoizedState={baseLanes:0,cachePool:null},e!==null&&sn(t,n!==null?n.cachePool:null),n!==null?ts(t,n):uc(),Qs(t);else return t.lanes=t.childLanes=536870912,ao(e,t,n!==null?n.baseLanes|l:l,l)}else n!==null?(sn(t,n.cachePool),ts(t,n),sl(),t.memoizedState=null):(e!==null&&sn(t,null),uc(),sl());return Le(e,t,u,l),t.child}function ao(e,t,l,a){var u=Pi();return u=u===null?null:{parent:Ce._currentValue,pool:u},t.memoizedState={baseLanes:l,cachePool:u},e!==null&&sn(t,null),uc(),Qs(t),e!==null&&Fa(e,t,a,!0),null}function On(e,t){var l=t.ref;if(l===null)e!==null&&e.ref!==null&&(t.flags|=4194816);else{if(typeof l!="function"&&typeof l!="object")throw Error(f(284));(e===null||e.ref!==l)&&(t.flags|=4194816)}}function Rc(e,t,l,a,u){return Ll(t),l=cc(e,t,l,a,void 0,u),a=fc(),e!==null&&!Be?(rc(e,t,u),Zt(e,t,u)):(he&&a&&Zi(t),t.flags|=1,Le(e,t,l,u),t.child)}function uo(e,t,l,a,u,n){return Ll(t),t.updateQueue=null,l=as(t,a,l,u),ls(e),a=fc(),e!==null&&!Be?(rc(e,t,n),Zt(e,t,n)):(he&&a&&Zi(t),t.flags|=1,Le(e,t,l,n),t.child)}function no(e,t,l,a,u){if(Ll(t),t.stateNode===null){var n=fa,c=l.contextType;typeof c=="object"&&c!==null&&(n=Ve(c)),n=new l(a,n),t.memoizedState=n.state!==null&&n.state!==void 0?n.state:null,n.updater=Tc,t.stateNode=n,n._reactInternals=t,n=t.stateNode,n.props=a,n.state=t.memoizedState,n.refs={},ec(t),c=l.contextType,n.context=typeof c=="object"&&c!==null?Ve(c):fa,n.state=t.memoizedState,c=l.getDerivedStateFromProps,typeof c=="function"&&(Ec(t,l,c,a),n.state=t.memoizedState),typeof l.getDerivedStateFromProps=="function"||typeof n.getSnapshotBeforeUpdate=="function"||typeof n.UNSAFE_componentWillMount!="function"&&typeof n.componentWillMount!="function"||(c=n.state,typeof n.componentWillMount=="function"&&n.componentWillMount(),typeof n.UNSAFE_componentWillMount=="function"&&n.UNSAFE_componentWillMount(),c!==n.state&&Tc.enqueueReplaceState(n,n.state,null),uu(t,a,n,u),au(),n.state=t.memoizedState),typeof n.componentDidMount=="function"&&(t.flags|=4194308),a=!0}else if(e===null){n=t.stateNode;var r=t.memoizedProps,y=Xl(l,r);n.props=y;var T=n.context,z=l.contextType;c=fa,typeof z=="object"&&z!==null&&(c=Ve(z));var C=l.getDerivedStateFromProps;z=typeof C=="function"||typeof n.getSnapshotBeforeUpdate=="function",r=t.pendingProps!==r,z||typeof n.UNSAFE_componentWillReceiveProps!="function"&&typeof n.componentWillReceiveProps!="function"||(r||T!==c)&&Vs(t,n,a,c),nl=!1;var R=t.memoizedState;n.state=R,uu(t,a,n,u),au(),T=t.memoizedState,r||R!==T||nl?(typeof C=="function"&&(Ec(t,l,C,a),T=t.memoizedState),(y=nl||Zs(t,l,y,a,R,T,c))?(z||typeof n.UNSAFE_componentWillMount!="function"&&typeof n.componentWillMount!="function"||(typeof n.componentWillMount=="function"&&n.componentWillMount(),typeof n.UNSAFE_componentWillMount=="function"&&n.UNSAFE_componentWillMount()),typeof n.componentDidMount=="function"&&(t.flags|=4194308)):(typeof n.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=a,t.memoizedState=T),n.props=a,n.state=T,n.context=c,a=y):(typeof n.componentDidMount=="function"&&(t.flags|=4194308),a=!1)}else{n=t.stateNode,tc(e,t),c=t.memoizedProps,z=Xl(l,c),n.props=z,C=t.pendingProps,R=n.context,T=l.contextType,y=fa,typeof T=="object"&&T!==null&&(y=Ve(T)),r=l.getDerivedStateFromProps,(T=typeof r=="function"||typeof n.getSnapshotBeforeUpdate=="function")||typeof n.UNSAFE_componentWillReceiveProps!="function"&&typeof n.componentWillReceiveProps!="function"||(c!==C||R!==y)&&Vs(t,n,a,y),nl=!1,R=t.memoizedState,n.state=R,uu(t,a,n,u),au();var N=t.memoizedState;c!==C||R!==N||nl||e!==null&&e.dependencies!==null&&fn(e.dependencies)?(typeof r=="function"&&(Ec(t,l,r,a),N=t.memoizedState),(z=nl||Zs(t,l,z,a,R,N,y)||e!==null&&e.dependencies!==null&&fn(e.dependencies))?(T||typeof n.UNSAFE_componentWillUpdate!="function"&&typeof n.componentWillUpdate!="function"||(typeof n.componentWillUpdate=="function"&&n.componentWillUpdate(a,N,y),typeof n.UNSAFE_componentWillUpdate=="function"&&n.UNSAFE_componentWillUpdate(a,N,y)),typeof n.componentDidUpdate=="function"&&(t.flags|=4),typeof n.getSnapshotBeforeUpdate=="function"&&(t.flags|=1024)):(typeof n.componentDidUpdate!="function"||c===e.memoizedProps&&R===e.memoizedState||(t.flags|=4),typeof n.getSnapshotBeforeUpdate!="function"||c===e.memoizedProps&&R===e.memoizedState||(t.flags|=1024),t.memoizedProps=a,t.memoizedState=N),n.props=a,n.state=N,n.context=y,a=z):(typeof n.componentDidUpdate!="function"||c===e.memoizedProps&&R===e.memoizedState||(t.flags|=4),typeof n.getSnapshotBeforeUpdate!="function"||c===e.memoizedProps&&R===e.memoizedState||(t.flags|=1024),a=!1)}return n=a,On(e,t),a=(t.flags&128)!==0,n||a?(n=t.stateNode,l=a&&typeof l.getDerivedStateFromError!="function"?null:n.render(),t.flags|=1,e!==null&&a?(t.child=ba(t,e.child,null,u),t.child=ba(t,null,l,u)):Le(e,t,l,u),t.memoizedState=n.state,e=t.child):e=Zt(e,t,u),e}function io(e,t,l,a){return $a(),t.flags|=256,Le(e,t,l,a),t.child}var Nc={dehydrated:null,treeContext:null,retryLane:0,hydrationErrors:null};function Oc(e){return{baseLanes:e,cachePool:Jr()}}function Mc(e,t,l){return e=e!==null?e.childLanes&~l:0,t&&(e|=pt),e}function co(e,t,l){var a=t.pendingProps,u=!1,n=(t.flags&128)!==0,c;if((c=n)||(c=e!==null&&e.memoizedState===null?!1:(Ue.current&2)!==0),c&&(u=!0,t.flags&=-129),c=(t.flags&32)!==0,t.flags&=-33,e===null){if(he){if(u?rl(t):sl(),he){var r=Oe,y;if(y=r){e:{for(y=r,r=Rt;y.nodeType!==8;){if(!r){r=null;break e}if(y=Tt(y.nextSibling),y===null){r=null;break e}}r=y}r!==null?(t.memoizedState={dehydrated:r,treeContext:Ul!==null?{id:wt,overflow:Lt}:null,retryLane:536870912,hydrationErrors:null},y=nt(18,null,null,0),y.stateNode=r,y.return=t,t.child=y,ke=t,Oe=null,y=!0):y=!1}y||ql(t)}if(r=t.memoizedState,r!==null&&(r=r.dehydrated,r!==null))return df(r)?t.lanes=32:t.lanes=536870912,null;Qt(t)}return r=a.children,a=a.fallback,u?(sl(),u=t.mode,r=Mn({mode:"hidden",children:r},u),a=Cl(a,u,l,null),r.return=t,a.return=t,r.sibling=a,t.child=r,u=t.child,u.memoizedState=Oc(l),u.childLanes=Mc(e,c,l),t.memoizedState=Nc,a):(rl(t),jc(t,r))}if(y=e.memoizedState,y!==null&&(r=y.dehydrated,r!==null)){if(n)t.flags&256?(rl(t),t.flags&=-257,t=zc(e,t,l)):t.memoizedState!==null?(sl(),t.child=e.child,t.flags|=128,t=null):(sl(),u=a.fallback,r=t.mode,a=Mn({mode:"visible",children:a.children},r),u=Cl(u,r,l,null),u.flags|=2,a.return=t,u.return=t,a.sibling=u,t.child=a,ba(t,e.child,null,l),a=t.child,a.memoizedState=Oc(l),a.childLanes=Mc(e,c,l),t.memoizedState=Nc,t=u);else if(rl(t),df(r)){if(c=r.nextSibling&&r.nextSibling.dataset,c)var T=c.dgst;c=T,a=Error(f(419)),a.stack="",a.digest=c,Wa({value:a,source:null,stack:null}),t=zc(e,t,l)}else if(Be||Fa(e,t,l,!1),c=(l&e.childLanes)!==0,Be||c){if(c=xe,c!==null&&(a=l&-l,a=(a&42)!==0?1:di(a),a=(a&(c.suspendedLanes|l))!==0?0:a,a!==0&&a!==y.retryLane))throw y.retryLane=a,ca(e,a),st(c,e,a),Ps;r.data==="$?"||kc(),t=zc(e,t,l)}else r.data==="$?"?(t.flags|=192,t.child=e.child,t=null):(e=y.treeContext,Oe=Tt(r.nextSibling),ke=t,he=!0,Bl=null,Rt=!1,e!==null&&(vt[gt++]=wt,vt[gt++]=Lt,vt[gt++]=Ul,wt=e.id,Lt=e.overflow,Ul=t),t=jc(t,a.children),t.flags|=4096);return t}return u?(sl(),u=a.fallback,r=t.mode,y=e.child,T=y.sibling,a=qt(y,{mode:"hidden",children:a.children}),a.subtreeFlags=y.subtreeFlags&65011712,T!==null?u=qt(T,u):(u=Cl(u,r,l,null),u.flags|=2),u.return=t,a.return=t,a.sibling=u,t.child=a,a=u,u=t.child,r=e.child.memoizedState,r===null?r=Oc(l):(y=r.cachePool,y!==null?(T=Ce._currentValue,y=y.parent!==T?{parent:T,pool:T}:y):y=Jr(),r={baseLanes:r.baseLanes|l,cachePool:y}),u.memoizedState=r,u.childLanes=Mc(e,c,l),t.memoizedState=Nc,a):(rl(t),l=e.child,e=l.sibling,l=qt(l,{mode:"visible",children:a.children}),l.return=t,l.sibling=null,e!==null&&(c=t.deletions,c===null?(t.deletions=[e],t.flags|=16):c.push(e)),t.child=l,t.memoizedState=null,l)}function jc(e,t){return t=Mn({mode:"visible",children:t},e.mode),t.return=e,e.child=t}function Mn(e,t){return e=nt(22,e,null,t),e.lanes=0,e.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null},e}function zc(e,t,l){return ba(t,e.child,null,l),e=jc(t,t.pendingProps.children),e.flags|=2,t.memoizedState=null,e}function fo(e,t,l){e.lanes|=t;var a=e.alternate;a!==null&&(a.lanes|=t),ki(e.return,t,l)}function Dc(e,t,l,a,u){var n=e.memoizedState;n===null?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:a,tail:l,tailMode:u}:(n.isBackwards=t,n.rendering=null,n.renderingStartTime=0,n.last=a,n.tail=l,n.tailMode=u)}function ro(e,t,l){var a=t.pendingProps,u=a.revealOrder,n=a.tail;if(Le(e,t,a.children,l),a=Ue.current,(a&2)!==0)a=a&1|2,t.flags|=128;else{if(e!==null&&(e.flags&128)!==0)e:for(e=t.child;e!==null;){if(e.tag===13)e.memoizedState!==null&&fo(e,l,t);else if(e.tag===19)fo(e,l,t);else if(e.child!==null){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;e.sibling===null;){if(e.return===null||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}a&=1}switch(Y(Ue,a),u){case"forwards":for(l=t.child,u=null;l!==null;)e=l.alternate,e!==null&&An(e)===null&&(u=l),l=l.sibling;l=u,l===null?(u=t.child,t.child=null):(u=l.sibling,l.sibling=null),Dc(t,!1,u,l,n);break;case"backwards":for(l=null,u=t.child,t.child=null;u!==null;){if(e=u.alternate,e!==null&&An(e)===null){t.child=u;break}e=u.sibling,u.sibling=l,l=u,u=e}Dc(t,!0,l,null,n);break;case"together":Dc(t,!1,null,null,void 0);break;default:t.memoizedState=null}return t.child}function Zt(e,t,l){if(e!==null&&(t.dependencies=e.dependencies),yl|=t.lanes,(l&t.childLanes)===0)if(e!==null){if(Fa(e,t,l,!1),(l&t.childLanes)===0)return null}else return null;if(e!==null&&t.child!==e.child)throw Error(f(153));if(t.child!==null){for(e=t.child,l=qt(e,e.pendingProps),t.child=l,l.return=t;e.sibling!==null;)e=e.sibling,l=l.sibling=qt(e,e.pendingProps),l.return=t;l.sibling=null}return t.child}function _c(e,t){return(e.lanes&t)!==0?!0:(e=e.dependencies,!!(e!==null&&fn(e)))}function Bm(e,t,l){switch(t.tag){case 3:Te(t,t.stateNode.containerInfo),ul(t,Ce,e.memoizedState.cache),$a();break;case 27:case 5:ci(t);break;case 4:Te(t,t.stateNode.containerInfo);break;case 10:ul(t,t.type,t.memoizedProps.value);break;case 13:var a=t.memoizedState;if(a!==null)return a.dehydrated!==null?(rl(t),t.flags|=128,null):(l&t.child.childLanes)!==0?co(e,t,l):(rl(t),e=Zt(e,t,l),e!==null?e.sibling:null);rl(t);break;case 19:var u=(e.flags&128)!==0;if(a=(l&t.childLanes)!==0,a||(Fa(e,t,l,!1),a=(l&t.childLanes)!==0),u){if(a)return ro(e,t,l);t.flags|=128}if(u=t.memoizedState,u!==null&&(u.rendering=null,u.tail=null,u.lastEffect=null),Y(Ue,Ue.current),a)break;return null;case 22:case 23:return t.lanes=0,lo(e,t,l);case 24:ul(t,Ce,e.memoizedState.cache)}return Zt(e,t,l)}function so(e,t,l){if(e!==null)if(e.memoizedProps!==t.pendingProps)Be=!0;else{if(!_c(e,l)&&(t.flags&128)===0)return Be=!1,Bm(e,t,l);Be=(e.flags&131072)!==0}else Be=!1,he&&(t.flags&1048576)!==0&&Yr(t,cn,t.index);switch(t.lanes=0,t.tag){case 16:e:{e=t.pendingProps;var a=t.elementType,u=a._init;if(a=u(a._payload),t.type=a,typeof a=="function")Gi(a)?(e=Xl(a,e),t.tag=1,t=no(null,t,a,e,l)):(t.tag=0,t=Rc(null,t,a,e,l));else{if(a!=null){if(u=a.$$typeof,u===ce){t.tag=11,t=Is(null,t,a,e,l);break e}else if(u===ue){t.tag=14,t=eo(null,t,a,e,l);break e}}throw t=Ol(a)||a,Error(f(306,t,""))}}return t;case 0:return Rc(e,t,t.type,t.pendingProps,l);case 1:return a=t.type,u=Xl(a,t.pendingProps),no(e,t,a,u,l);case 3:e:{if(Te(t,t.stateNode.containerInfo),e===null)throw Error(f(387));a=t.pendingProps;var n=t.memoizedState;u=n.element,tc(e,t),uu(t,a,null,l);var c=t.memoizedState;if(a=c.cache,ul(t,Ce,a),a!==n.cache&&$i(t,[Ce],l,!0),au(),a=c.element,n.isDehydrated)if(n={element:a,isDehydrated:!1,cache:c.cache},t.updateQueue.baseState=n,t.memoizedState=n,t.flags&256){t=io(e,t,a,l);break e}else if(a!==u){u=mt(Error(f(424)),t),Wa(u),t=io(e,t,a,l);break e}else{switch(e=t.stateNode.containerInfo,e.nodeType){case 9:e=e.body;break;default:e=e.nodeName==="HTML"?e.ownerDocument.body:e}for(Oe=Tt(e.firstChild),ke=t,he=!0,Bl=null,Rt=!0,l=Xs(t,null,a,l),t.child=l;l;)l.flags=l.flags&-3|4096,l=l.sibling}else{if($a(),a===u){t=Zt(e,t,l);break e}Le(e,t,a,l)}t=t.child}return t;case 26:return On(e,t),e===null?(l=yd(t.type,null,t.pendingProps,null))?t.memoizedState=l:he||(l=t.type,e=t.pendingProps,a=Xn(ee.current).createElement(l),a[Ze]=t,a[$e]=e,Ge(a,l,e),He(a),t.stateNode=a):t.memoizedState=yd(t.type,e.memoizedProps,t.pendingProps,e.memoizedState),null;case 27:return ci(t),e===null&&he&&(a=t.stateNode=dd(t.type,t.pendingProps,ee.current),ke=t,Rt=!0,u=Oe,pl(t.type)?(hf=u,Oe=Tt(a.firstChild)):Oe=u),Le(e,t,t.pendingProps.children,l),On(e,t),e===null&&(t.flags|=4194304),t.child;case 5:return e===null&&he&&((u=a=Oe)&&(a=sy(a,t.type,t.pendingProps,Rt),a!==null?(t.stateNode=a,ke=t,Oe=Tt(a.firstChild),Rt=!1,u=!0):u=!1),u||ql(t)),ci(t),u=t.type,n=t.pendingProps,c=e!==null?e.memoizedProps:null,a=n.children,rf(u,n)?a=null:c!==null&&rf(u,c)&&(t.flags|=32),t.memoizedState!==null&&(u=cc(e,t,Mm,null,null,l),Nu._currentValue=u),On(e,t),Le(e,t,a,l),t.child;case 6:return e===null&&he&&((e=l=Oe)&&(l=oy(l,t.pendingProps,Rt),l!==null?(t.stateNode=l,ke=t,Oe=null,e=!0):e=!1),e||ql(t)),null;case 13:return co(e,t,l);case 4:return Te(t,t.stateNode.containerInfo),a=t.pendingProps,e===null?t.child=ba(t,null,a,l):Le(e,t,a,l),t.child;case 11:return Is(e,t,t.type,t.pendingProps,l);case 7:return Le(e,t,t.pendingProps,l),t.child;case 8:return Le(e,t,t.pendingProps.children,l),t.child;case 12:return Le(e,t,t.pendingProps.children,l),t.child;case 10:return a=t.pendingProps,ul(t,t.type,a.value),Le(e,t,a.children,l),t.child;case 9:return u=t.type._context,a=t.pendingProps.children,Ll(t),u=Ve(u),a=a(u),t.flags|=1,Le(e,t,a,l),t.child;case 14:return eo(e,t,t.type,t.pendingProps,l);case 15:return to(e,t,t.type,t.pendingProps,l);case 19:return ro(e,t,l);case 31:return a=t.pendingProps,l=t.mode,a={mode:a.mode,children:a.children},e===null?(l=Mn(a,l),l.ref=t.ref,t.child=l,l.return=t,t=l):(l=qt(e.child,a),l.ref=t.ref,t.child=l,l.return=t,t=l),t;case 22:return lo(e,t,l);case 24:return Ll(t),a=Ve(Ce),e===null?(u=Pi(),u===null&&(u=xe,n=Wi(),u.pooledCache=n,n.refCount++,n!==null&&(u.pooledCacheLanes|=l),u=n),t.memoizedState={parent:a,cache:u},ec(t),ul(t,Ce,u)):((e.lanes&l)!==0&&(tc(e,t),uu(t,null,null,l),au()),u=e.memoizedState,n=t.memoizedState,u.parent!==a?(u={parent:a,cache:a},t.memoizedState=u,t.lanes===0&&(t.memoizedState=t.updateQueue.baseState=u),ul(t,Ce,a)):(a=n.cache,ul(t,Ce,a),a!==u.cache&&$i(t,[Ce],l,!0))),Le(e,t,t.pendingProps.children,l),t.child;case 29:throw t.pendingProps}throw Error(f(156,t.tag))}function Vt(e){e.flags|=4}function oo(e,t){if(t.type!=="stylesheet"||(t.state.loading&4)!==0)e.flags&=-16777217;else if(e.flags|=16777216,!Sd(t)){if(t=bt.current,t!==null&&((re&4194048)===re?Nt!==null:(re&62914560)!==re&&(re&536870912)===0||t!==Nt))throw tu=Ii,kr;e.flags|=8192}}function jn(e,t){t!==null&&(e.flags|=4),e.flags&16384&&(t=e.tag!==22?Qf():536870912,e.lanes|=t,Ea|=t)}function ou(e,t){if(!he)switch(e.tailMode){case"hidden":t=e.tail;for(var l=null;t!==null;)t.alternate!==null&&(l=t),t=t.sibling;l===null?e.tail=null:l.sibling=null;break;case"collapsed":l=e.tail;for(var a=null;l!==null;)l.alternate!==null&&(a=l),l=l.sibling;a===null?t||e.tail===null?e.tail=null:e.tail.sibling=null:a.sibling=null}}function Re(e){var t=e.alternate!==null&&e.alternate.child===e.child,l=0,a=0;if(t)for(var u=e.child;u!==null;)l|=u.lanes|u.childLanes,a|=u.subtreeFlags&65011712,a|=u.flags&65011712,u.return=e,u=u.sibling;else for(u=e.child;u!==null;)l|=u.lanes|u.childLanes,a|=u.subtreeFlags,a|=u.flags,u.return=e,u=u.sibling;return e.subtreeFlags|=a,e.childLanes=l,t}function qm(e,t,l){var a=t.pendingProps;switch(Vi(t),t.tag){case 31:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Re(t),null;case 1:return Re(t),null;case 3:return l=t.stateNode,a=null,e!==null&&(a=e.memoizedState.cache),t.memoizedState.cache!==a&&(t.flags|=2048),Gt(Ce),el(),l.pendingContext&&(l.context=l.pendingContext,l.pendingContext=null),(e===null||e.child===null)&&(ka(t)?Vt(t):e===null||e.memoizedState.isDehydrated&&(t.flags&256)===0||(t.flags|=1024,Qr())),Re(t),null;case 26:return l=t.memoizedState,e===null?(Vt(t),l!==null?(Re(t),oo(t,l)):(Re(t),t.flags&=-16777217)):l?l!==e.memoizedState?(Vt(t),Re(t),oo(t,l)):(Re(t),t.flags&=-16777217):(e.memoizedProps!==a&&Vt(t),Re(t),t.flags&=-16777217),null;case 27:Lu(t),l=ee.current;var u=t.type;if(e!==null&&t.stateNode!=null)e.memoizedProps!==a&&Vt(t);else{if(!a){if(t.stateNode===null)throw Error(f(166));return Re(t),null}e=$.current,ka(t)?Gr(t):(e=dd(u,a,l),t.stateNode=e,Vt(t))}return Re(t),null;case 5:if(Lu(t),l=t.type,e!==null&&t.stateNode!=null)e.memoizedProps!==a&&Vt(t);else{if(!a){if(t.stateNode===null)throw Error(f(166));return Re(t),null}if(e=$.current,ka(t))Gr(t);else{switch(u=Xn(ee.current),e){case 1:e=u.createElementNS("http://www.w3.org/2000/svg",l);break;case 2:e=u.createElementNS("http://www.w3.org/1998/Math/MathML",l);break;default:switch(l){case"svg":e=u.createElementNS("http://www.w3.org/2000/svg",l);break;case"math":e=u.createElementNS("http://www.w3.org/1998/Math/MathML",l);break;case"script":e=u.createElement("div"),e.innerHTML=" - - - -
- - - diff --git a/components/protocols/webfolder/vite.svg b/components/protocols/webfolder/vite.svg deleted file mode 100755 index e7b8dfb..0000000 --- a/components/protocols/webfolder/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/components/rest_api/CMakeLists.txt b/components/rest_api/CMakeLists.txt index 0bd1191..dbbd862 100755 --- a/components/rest_api/CMakeLists.txt +++ b/components/rest_api/CMakeLists.txt @@ -15,7 +15,7 @@ idf_component_register( SRCS ${srcs} INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "src" - PRIV_REQUIRES nvs_flash esp_http_server esp_netif vfs spiffs json evse meter_manager loadbalancer evse_link + PRIV_REQUIRES nvs_flash esp_http_server esp_netif vfs spiffs json evse meter_manager protocols loadbalancer evse_link ) # SPIFFS image (opcional) diff --git a/components/rest_api/include/meters_settings_api.h b/components/rest_api/include/meters_settings_api.h index c12a86a..7ddc310 100644 --- a/components/rest_api/include/meters_settings_api.h +++ b/components/rest_api/include/meters_settings_api.h @@ -11,4 +11,12 @@ // Função para registrar os manipuladores de URI para as configurações dos contadores void register_meters_settings_handlers(httpd_handle_t server, void *ctx); +/** + * Exponha dados do meter via REST. + * Endpoints: + * GET /api/v1/meters/live -> dados mais recentes (GRID e/ou EVSE) + * GET /api/v1/meters/live?source=GRID|EVSE + */ +void register_meters_data_handlers(httpd_handle_t server, void *ctx); + #endif // METERS_SETTINGS_API_H diff --git a/components/rest_api/src/dashboard_api.c b/components/rest_api/src/dashboard_api.c index a565dc7..ed5b767 100644 --- a/components/rest_api/src/dashboard_api.c +++ b/components/rest_api/src/dashboard_api.c @@ -24,11 +24,11 @@ static esp_err_t dashboard_get_handler(httpd_req_t *req) { cJSON *charger1 = cJSON_CreateObject(); cJSON_AddNumberToObject(charger1, "id", 1); cJSON_AddStringToObject(charger1, "status", evse_state_to_str(state)); - cJSON_AddNumberToObject(charger1, "current", evse_get_charging_current()); + cJSON_AddNumberToObject(charger1, "current", evse_get_runtime_charging_current()); cJSON_AddNumberToObject(charger1, "maxCurrent", evse_get_max_charging_current()); // Calcular a potência com base na corrente (considerando 230V) - int power = (evse_get_charging_current()) * 230; + int power = (evse_get_runtime_charging_current()) * 230; cJSON_AddNumberToObject(charger1, "power", power); cJSON_AddItemToArray(chargers, charger1); diff --git a/components/rest_api/src/meters_settings_api.c b/components/rest_api/src/meters_settings_api.c index b40cc90..3aca068 100644 --- a/components/rest_api/src/meters_settings_api.c +++ b/components/rest_api/src/meters_settings_api.c @@ -1,12 +1,169 @@ #include "meters_settings_api.h" -#include "meter_manager.h" // Atualizado para usar o novo manager +#include "meter_manager.h" // Atualizado para usar o novo manager +#include "meter_events.h" +#include "esp_event.h" #include "esp_log.h" #include "cJSON.h" +#include "freertos/semphr.h" +#include "esp_timer.h" +#include static const char *TAG = "meters_settings_api"; +typedef struct +{ + meter_event_data_t last_grid; + meter_event_data_t last_evse; + bool has_grid; + bool has_evse; + int64_t ts_grid_us; + int64_t ts_evse_us; + SemaphoreHandle_t mtx; +} meters_cache_t; + +static meters_cache_t g_cache = {0}; + +static void cache_init_once(void) +{ + if (!g_cache.mtx) + { + g_cache.mtx = xSemaphoreCreateMutex(); + } +} + +static void copy_event_locked(const meter_event_data_t *src) +{ + if (!src) + return; + if (strcmp(src->source ? src->source : "", "EVSE") == 0) + { + g_cache.last_evse = *src; + g_cache.has_evse = true; + g_cache.ts_evse_us = esp_timer_get_time(); + } + else + { + // Default trate como GRID + g_cache.last_grid = *src; + g_cache.has_grid = true; + g_cache.ts_grid_us = esp_timer_get_time(); + } +} + +// ---------- Event handler (atualiza cache) ---------- +static void meters_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data) +{ + if (base != METER_EVENT || id != METER_EVENT_DATA_READY || data == NULL) + return; + + cache_init_once(); + if (xSemaphoreTake(g_cache.mtx, pdMS_TO_TICKS(10)) == pdTRUE) + { + copy_event_locked((const meter_event_data_t *)data); + xSemaphoreGive(g_cache.mtx); + } +} + +// ---------- Helpers JSON ---------- +static cJSON *meter_event_to_json(const meter_event_data_t *m, int64_t ts_us) +{ + cJSON *root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "source", m->source ? m->source : "GRID"); + cJSON_AddNumberToObject(root, "frequency", m->frequency); + cJSON_AddNumberToObject(root, "powerFactor", m->power_factor); + cJSON_AddNumberToObject(root, "totalEnergy", m->total_energy); + + // timestamp relativo (segundos desde boot) e em micros + cJSON_AddNumberToObject(root, "timestampUs", (double)ts_us); + + // arrays + cJSON *vr = cJSON_CreateArray(); + for (int i = 0; i < 3; i++) + cJSON_AddItemToArray(vr, cJSON_CreateNumber(m->vrms[i])); + cJSON *ir = cJSON_CreateArray(); + for (int i = 0; i < 3; i++) + cJSON_AddItemToArray(ir, cJSON_CreateNumber(m->irms[i])); + cJSON *pw = cJSON_CreateArray(); + for (int i = 0; i < 3; i++) + cJSON_AddItemToArray(pw, cJSON_CreateNumber(m->watt[i])); + cJSON_AddItemToObject(root, "vrms", vr); + cJSON_AddItemToObject(root, "irms", ir); + cJSON_AddItemToObject(root, "watt", pw); + return root; +} + +// ---------- HTTP GET /api/v1/meters/live ---------- +static esp_err_t meters_live_get_handler(httpd_req_t *req) +{ + cache_init_once(); + + char query[64] = {0}; + char source[16] = {0}; + bool want_grid = true, want_evse = true; + + if (httpd_req_get_url_query_str(req, query, sizeof(query)) == ESP_OK) + { + if (httpd_query_key_value(query, "source", source, sizeof(source)) == ESP_OK) + { + if (strcasecmp(source, "GRID") == 0) + { + want_grid = true; + want_evse = false; + } + else if (strcasecmp(source, "EVSE") == 0) + { + want_grid = false; + want_evse = true; + } + } + } + + cJSON *out = cJSON_CreateObject(); + cJSON *arr = cJSON_CreateArray(); + + if (xSemaphoreTake(g_cache.mtx, pdMS_TO_TICKS(50)) == pdTRUE) + { + if (want_grid && g_cache.has_grid) + { + cJSON_AddItemToArray(arr, meter_event_to_json(&g_cache.last_grid, g_cache.ts_grid_us)); + } + if (want_evse && g_cache.has_evse) + { + cJSON_AddItemToArray(arr, meter_event_to_json(&g_cache.last_evse, g_cache.ts_evse_us)); + } + xSemaphoreGive(g_cache.mtx); + } + + cJSON_AddItemToObject(out, "meters", arr); + httpd_resp_set_type(req, "application/json"); + char *s = cJSON_PrintUnformatted(out); + httpd_resp_sendstr(req, s ? s : "{\"meters\":[]}"); + if (s) + free(s); + cJSON_Delete(out); + return ESP_OK; +} + +// ---------- Registro ---------- +void register_meters_data_handlers(httpd_handle_t server, void *ctx) +{ + // registra event handler para receber amostras + ESP_ERROR_CHECK(esp_event_handler_register(METER_EVENT, METER_EVENT_DATA_READY, meters_event_handler, NULL)); + + // endpoint GET + httpd_uri_t live = { + .uri = "/api/v1/meters/live", + .method = HTTP_GET, + .handler = meters_live_get_handler, + .user_ctx = ctx}; + httpd_register_uri_handler(server, &live); + + ESP_LOGI(TAG, "REST /api/v1/meters/live registrado"); +} + // Função para recuperar as configurações dos contadores -static esp_err_t meters_config_get_handler(httpd_req_t *req) { +static esp_err_t meters_config_get_handler(httpd_req_t *req) +{ ESP_LOGI(TAG, "Received GET request for /api/v1/config/meters"); httpd_resp_set_type(req, "application/json"); @@ -38,24 +195,27 @@ static esp_err_t meters_config_get_handler(httpd_req_t *req) { } // Função para atualizar as configurações dos contadores -static esp_err_t meters_config_post_handler(httpd_req_t *req) { +static esp_err_t meters_config_post_handler(httpd_req_t *req) +{ ESP_LOGI(TAG, "Received POST request for /api/v1/config/meters"); char buf[512]; int len = httpd_req_recv(req, buf, sizeof(buf) - 1); - if (len <= 0) { + if (len <= 0) + { ESP_LOGE(TAG, "Received empty body in POST request"); httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Empty body"); return ESP_FAIL; } - buf[len] = '\0'; // Garantir que a string está terminada + buf[len] = '\0'; // Garantir que a string está terminada ESP_LOGI(TAG, "Received POST data: %s", buf); cJSON *json = cJSON_Parse(buf); - if (!json) { + if (!json) + { ESP_LOGE(TAG, "Failed to parse JSON data"); // Resposta detalhada de erro httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON format"); @@ -64,15 +224,17 @@ static esp_err_t meters_config_post_handler(httpd_req_t *req) { // Atualizando os contadores cJSON *gridmeter = cJSON_GetObjectItem(json, "gridmeter"); - if (gridmeter) { - meter_type_t gridType = string_to_meter_type(gridmeter->valuestring); // Usando a função string_to_meter_type + if (gridmeter) + { + meter_type_t gridType = string_to_meter_type(gridmeter->valuestring); // Usando a função string_to_meter_type ESP_LOGI(TAG, "Updating grid meter type to: %s", gridmeter->valuestring); meter_manager_grid_set_model(gridType); } cJSON *evsemeter = cJSON_GetObjectItem(json, "evsemeter"); - if (evsemeter) { - meter_type_t evseType = string_to_meter_type(evsemeter->valuestring); // Usando a função string_to_meter_type + if (evsemeter) + { + meter_type_t evseType = string_to_meter_type(evsemeter->valuestring); // Usando a função string_to_meter_type ESP_LOGI(TAG, "Updating EVSE meter type to: %s", evsemeter->valuestring); meter_manager_evse_set_model(evseType); } @@ -86,7 +248,8 @@ static esp_err_t meters_config_post_handler(httpd_req_t *req) { } // Registrando os manipuladores de URI para os contadores -void register_meters_settings_handlers(httpd_handle_t server, void *ctx) { +void register_meters_settings_handlers(httpd_handle_t server, void *ctx) +{ ESP_LOGD(TAG, "Registering URI handlers for meters settings"); // URI para o método GET @@ -94,8 +257,7 @@ void register_meters_settings_handlers(httpd_handle_t server, void *ctx) { .uri = "/api/v1/config/meters", .method = HTTP_GET, .handler = meters_config_get_handler, - .user_ctx = ctx - }; + .user_ctx = ctx}; ESP_LOGD(TAG, "Registering GET handler for /api/v1/config/meters"); httpd_register_uri_handler(server, &meters_get_uri); @@ -104,8 +266,7 @@ void register_meters_settings_handlers(httpd_handle_t server, void *ctx) { .uri = "/api/v1/config/meters", .method = HTTP_POST, .handler = meters_config_post_handler, - .user_ctx = ctx - }; + .user_ctx = ctx}; ESP_LOGD(TAG, "Registering POST handler for /api/v1/config/meters"); httpd_register_uri_handler(server, &meters_post_uri); } diff --git a/components/rest_api/src/rest_main.c b/components/rest_api/src/rest_main.c index a0bbc3f..2d2d699 100755 --- a/components/rest_api/src/rest_main.c +++ b/components/rest_api/src/rest_main.c @@ -10,14 +10,15 @@ #include "static_file_api.h" #include "esp_log.h" - static const char *TAG = "rest_main"; -esp_err_t rest_server_init(const char *base_path) { +esp_err_t rest_server_init(const char *base_path) +{ ESP_LOGI(TAG, "Initializing REST API with base path: %s", base_path); rest_server_context_t *ctx = calloc(1, sizeof(rest_server_context_t)); - if (!ctx) { + if (!ctx) + { ESP_LOGE(TAG, "Failed to allocate memory for REST context"); return ESP_ERR_NO_MEM; } @@ -30,7 +31,8 @@ esp_err_t rest_server_init(const char *base_path) { httpd_handle_t server = NULL; esp_err_t err = httpd_start(&server, &config); - if (err != ESP_OK) { + if (err != ESP_OK) + { ESP_LOGE(TAG, "Failed to start HTTP server: %s", esp_err_to_name(err)); free(ctx); return err; @@ -39,16 +41,18 @@ esp_err_t rest_server_init(const char *base_path) { ESP_LOGI(TAG, "HTTP server started successfully"); // Register endpoint groups - register_evse_settings_handlers(server, ctx); // Apenas chamando a função sem comparação - register_network_handlers(server, ctx); // Apenas chamando a função sem comparação - register_ocpp_handlers(server, ctx); // Apenas chamando a função sem comparação - register_auth_handlers(server, ctx); // Apenas chamando a função sem comparação - register_dashboard_handlers(server, ctx); // Apenas chamando a função sem comparação - register_meters_settings_handlers(server, ctx); // Apenas chamando a função sem comparação + register_evse_settings_handlers(server, ctx); // Apenas chamando a função sem comparação + register_network_handlers(server, ctx); // Apenas chamando a função sem comparação + register_ocpp_handlers(server, ctx); // Apenas chamando a função sem comparação + register_auth_handlers(server, ctx); // Apenas chamando a função sem comparação + register_dashboard_handlers(server, ctx); // Apenas chamando a função sem comparação + register_meters_settings_handlers(server, ctx); // Apenas chamando a função sem comparação register_loadbalancing_settings_handlers(server, ctx); // Apenas chamando a função sem comparação - register_link_config_handlers(server,ctx); - register_static_file_handlers(server, ctx); // Apenas chamando a função sem comparação + register_link_config_handlers(server, ctx); + register_meters_data_handlers(server, ctx); + + register_static_file_handlers(server, ctx); // Apenas chamando a função sem comparação ESP_LOGI(TAG, "All REST API endpoint groups registered successfully"); diff --git a/components/rest_api/webfolder/assets/index-CmjuW5AW.js b/components/rest_api/webfolder/assets/index-BcUN2CM9.js similarity index 52% rename from components/rest_api/webfolder/assets/index-CmjuW5AW.js rename to components/rest_api/webfolder/assets/index-BcUN2CM9.js index 76bf816..e2e8597 100644 --- a/components/rest_api/webfolder/assets/index-CmjuW5AW.js +++ b/components/rest_api/webfolder/assets/index-BcUN2CM9.js @@ -1,4 +1,4 @@ -(function(){const d=document.createElement("link").relList;if(d&&d.supports&&d.supports("modulepreload"))return;for(const h of document.querySelectorAll('link[rel="modulepreload"]'))f(h);new MutationObserver(h=>{for(const v of h)if(v.type==="childList")for(const S of v.addedNodes)S.tagName==="LINK"&&S.rel==="modulepreload"&&f(S)}).observe(document,{childList:!0,subtree:!0});function o(h){const v={};return h.integrity&&(v.integrity=h.integrity),h.referrerPolicy&&(v.referrerPolicy=h.referrerPolicy),h.crossOrigin==="use-credentials"?v.credentials="include":h.crossOrigin==="anonymous"?v.credentials="omit":v.credentials="same-origin",v}function f(h){if(h.ep)return;h.ep=!0;const v=o(h);fetch(h.href,v)}})();function $d(i){return i&&i.__esModule&&Object.prototype.hasOwnProperty.call(i,"default")?i.default:i}var Tf={exports:{}},_n={};/** +(function(){const h=document.createElement("link").relList;if(h&&h.supports&&h.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))f(o);new MutationObserver(o=>{for(const v of o)if(v.type==="childList")for(const S of v.addedNodes)S.tagName==="LINK"&&S.rel==="modulepreload"&&f(S)}).observe(document,{childList:!0,subtree:!0});function d(o){const v={};return o.integrity&&(v.integrity=o.integrity),o.referrerPolicy&&(v.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?v.credentials="include":o.crossOrigin==="anonymous"?v.credentials="omit":v.credentials="same-origin",v}function f(o){if(o.ep)return;o.ep=!0;const v=d(o);fetch(o.href,v)}})();function $d(i){return i&&i.__esModule&&Object.prototype.hasOwnProperty.call(i,"default")?i.default:i}var Tf={exports:{}},_n={};/** * @license React * react-jsx-runtime.production.js * @@ -6,7 +6,7 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */var _d;function By(){if(_d)return _n;_d=1;var i=Symbol.for("react.transitional.element"),d=Symbol.for("react.fragment");function o(f,h,v){var S=null;if(v!==void 0&&(S=""+v),h.key!==void 0&&(S=""+h.key),"key"in h){v={};for(var j in h)j!=="key"&&(v[j]=h[j])}else v=h;return h=v.ref,{$$typeof:i,type:f,key:S,ref:h!==void 0?h:null,props:v}}return _n.Fragment=d,_n.jsx=o,_n.jsxs=o,_n}var Cd;function qy(){return Cd||(Cd=1,Tf.exports=By()),Tf.exports}var s=qy(),Af={exports:{}},te={};/** + */var _d;function wy(){if(_d)return _n;_d=1;var i=Symbol.for("react.transitional.element"),h=Symbol.for("react.fragment");function d(f,o,v){var S=null;if(v!==void 0&&(S=""+v),o.key!==void 0&&(S=""+o.key),"key"in o){v={};for(var D in o)D!=="key"&&(v[D]=o[D])}else v=o;return o=v.ref,{$$typeof:i,type:f,key:S,ref:o!==void 0?o:null,props:v}}return _n.Fragment=h,_n.jsx=d,_n.jsxs=d,_n}var Cd;function By(){return Cd||(Cd=1,Tf.exports=wy()),Tf.exports}var s=By(),Af={exports:{}},te={};/** * @license React * react.production.js * @@ -14,7 +14,7 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */var Ud;function wy(){if(Ud)return te;Ud=1;var i=Symbol.for("react.transitional.element"),d=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),f=Symbol.for("react.strict_mode"),h=Symbol.for("react.profiler"),v=Symbol.for("react.consumer"),S=Symbol.for("react.context"),j=Symbol.for("react.forward_ref"),p=Symbol.for("react.suspense"),m=Symbol.for("react.memo"),M=Symbol.for("react.lazy"),H=Symbol.iterator;function O(g){return g===null||typeof g!="object"?null:(g=H&&g[H]||g["@@iterator"],typeof g=="function"?g:null)}var q={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},C=Object.assign,Y={};function V(g,B,Q){this.props=g,this.context=B,this.refs=Y,this.updater=Q||q}V.prototype.isReactComponent={},V.prototype.setState=function(g,B){if(typeof g!="object"&&typeof g!="function"&&g!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,g,B,"setState")},V.prototype.forceUpdate=function(g){this.updater.enqueueForceUpdate(this,g,"forceUpdate")};function L(){}L.prototype=V.prototype;function Z(g,B,Q){this.props=g,this.context=B,this.refs=Y,this.updater=Q||q}var k=Z.prototype=new L;k.constructor=Z,C(k,V.prototype),k.isPureReactComponent=!0;var le=Array.isArray,w={H:null,A:null,T:null,S:null,V:null},se=Object.prototype.hasOwnProperty;function ue(g,B,Q,G,$,oe){return Q=oe.ref,{$$typeof:i,type:g,key:B,ref:Q!==void 0?Q:null,props:oe}}function re(g,B){return ue(g.type,B,void 0,void 0,void 0,g.props)}function Ee(g){return typeof g=="object"&&g!==null&&g.$$typeof===i}function Je(g){var B={"=":"=0",":":"=2"};return"$"+g.replace(/[=:]/g,function(Q){return B[Q]})}var ot=/\/+/g;function Xe(g,B){return typeof g=="object"&&g!==null&&g.key!=null?Je(""+g.key):B.toString(36)}function Rl(){}function Ol(g){switch(g.status){case"fulfilled":return g.value;case"rejected":throw g.reason;default:switch(typeof g.status=="string"?g.then(Rl,Rl):(g.status="pending",g.then(function(B){g.status==="pending"&&(g.status="fulfilled",g.value=B)},function(B){g.status==="pending"&&(g.status="rejected",g.reason=B)})),g.status){case"fulfilled":return g.value;case"rejected":throw g.reason}}throw g}function Qe(g,B,Q,G,$){var oe=typeof g;(oe==="undefined"||oe==="boolean")&&(g=null);var ee=!1;if(g===null)ee=!0;else switch(oe){case"bigint":case"string":case"number":ee=!0;break;case"object":switch(g.$$typeof){case i:case d:ee=!0;break;case M:return ee=g._init,Qe(ee(g._payload),B,Q,G,$)}}if(ee)return $=$(g),ee=G===""?"."+Xe(g,0):G,le($)?(Q="",ee!=null&&(Q=ee.replace(ot,"$&/")+"/"),Qe($,B,Q,"",function(tl){return tl})):$!=null&&(Ee($)&&($=re($,Q+($.key==null||g&&g.key===$.key?"":(""+$.key).replace(ot,"$&/")+"/")+ee)),B.push($)),1;ee=0;var tt=G===""?".":G+":";if(le(g))for(var Te=0;Te>>1,g=D[pe];if(0>>1;peh(G,P))$h(oe,G)?(D[pe]=oe,D[$]=P,pe=$):(D[pe]=G,D[Q]=P,pe=Q);else if($h(oe,P))D[pe]=oe,D[$]=P,pe=$;else break e}}return X}function h(D,X){var P=D.sortIndex-X.sortIndex;return P!==0?P:D.id-X.id}if(i.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var v=performance;i.unstable_now=function(){return v.now()}}else{var S=Date,j=S.now();i.unstable_now=function(){return S.now()-j}}var p=[],m=[],M=1,H=null,O=3,q=!1,C=!1,Y=!1,V=!1,L=typeof setTimeout=="function"?setTimeout:null,Z=typeof clearTimeout=="function"?clearTimeout:null,k=typeof setImmediate<"u"?setImmediate:null;function le(D){for(var X=o(m);X!==null;){if(X.callback===null)f(m);else if(X.startTime<=D)f(m),X.sortIndex=X.expirationTime,d(p,X);else break;X=o(m)}}function w(D){if(Y=!1,le(D),!C)if(o(p)!==null)C=!0,se||(se=!0,Xe());else{var X=o(m);X!==null&&Qe(w,X.startTime-D)}}var se=!1,ue=-1,re=5,Ee=-1;function Je(){return V?!0:!(i.unstable_now()-EeD&&Je());){var pe=H.callback;if(typeof pe=="function"){H.callback=null,O=H.priorityLevel;var g=pe(H.expirationTime<=D);if(D=i.unstable_now(),typeof g=="function"){H.callback=g,le(D),X=!0;break t}H===o(p)&&f(p),le(D)}else f(p);H=o(p)}if(H!==null)X=!0;else{var B=o(m);B!==null&&Qe(w,B.startTime-D),X=!1}}break e}finally{H=null,O=P,q=!1}X=void 0}}finally{X?Xe():se=!1}}}var Xe;if(typeof k=="function")Xe=function(){k(ot)};else if(typeof MessageChannel<"u"){var Rl=new MessageChannel,Ol=Rl.port2;Rl.port1.onmessage=ot,Xe=function(){Ol.postMessage(null)}}else Xe=function(){L(ot,0)};function Qe(D,X){ue=L(function(){D(i.unstable_now())},X)}i.unstable_IdlePriority=5,i.unstable_ImmediatePriority=1,i.unstable_LowPriority=4,i.unstable_NormalPriority=3,i.unstable_Profiling=null,i.unstable_UserBlockingPriority=2,i.unstable_cancelCallback=function(D){D.callback=null},i.unstable_forceFrameRate=function(D){0>D||125pe?(D.sortIndex=P,d(m,D),o(p)===null&&D===o(m)&&(Y?(Z(ue),ue=-1):Y=!0,Qe(w,P-pe))):(D.sortIndex=g,d(p,D),C||q||(C=!0,se||(se=!0,Xe()))),D},i.unstable_shouldYield=Je,i.unstable_wrapCallback=function(D){var X=O;return function(){var P=O;O=X;try{return D.apply(this,arguments)}finally{O=P}}}}(Of)),Of}var qd;function Gy(){return qd||(qd=1,Rf.exports=Yy()),Rf.exports}var Mf={exports:{}},Ke={};/** + */var wd;function Yy(){return wd||(wd=1,function(i){function h(C,X){var P=C.length;C.push(X);e:for(;0>>1,g=C[pe];if(0>>1;peo(G,P))$o(oe,G)?(C[pe]=oe,C[$]=P,pe=$):(C[pe]=G,C[V]=P,pe=V);else if($o(oe,P))C[pe]=oe,C[$]=P,pe=$;else break e}}return X}function o(C,X){var P=C.sortIndex-X.sortIndex;return P!==0?P:C.id-X.id}if(i.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var v=performance;i.unstable_now=function(){return v.now()}}else{var S=Date,D=S.now();i.unstable_now=function(){return S.now()-D}}var p=[],m=[],O=1,z=null,N=3,Y=!1,M=!1,B=!1,Q=!1,q=typeof setTimeout=="function"?setTimeout:null,Z=typeof clearTimeout=="function"?clearTimeout:null,k=typeof setImmediate<"u"?setImmediate:null;function le(C){for(var X=d(m);X!==null;){if(X.callback===null)f(m);else if(X.startTime<=C)f(m),X.sortIndex=X.expirationTime,h(p,X);else break;X=d(m)}}function L(C){if(B=!1,le(C),!M)if(d(p)!==null)M=!0,se||(se=!0,Xe());else{var X=d(m);X!==null&&Qe(L,X.startTime-C)}}var se=!1,ue=-1,re=5,Ee=-1;function Je(){return Q?!0:!(i.unstable_now()-EeC&&Je());){var pe=z.callback;if(typeof pe=="function"){z.callback=null,N=z.priorityLevel;var g=pe(z.expirationTime<=C);if(C=i.unstable_now(),typeof g=="function"){z.callback=g,le(C),X=!0;break t}z===d(p)&&f(p),le(C)}else f(p);z=d(p)}if(z!==null)X=!0;else{var w=d(m);w!==null&&Qe(L,w.startTime-C),X=!1}}break e}finally{z=null,N=P,Y=!1}X=void 0}}finally{X?Xe():se=!1}}}var Xe;if(typeof k=="function")Xe=function(){k(ot)};else if(typeof MessageChannel<"u"){var Rl=new MessageChannel,jl=Rl.port2;Rl.port1.onmessage=ot,Xe=function(){jl.postMessage(null)}}else Xe=function(){q(ot,0)};function Qe(C,X){ue=q(function(){C(i.unstable_now())},X)}i.unstable_IdlePriority=5,i.unstable_ImmediatePriority=1,i.unstable_LowPriority=4,i.unstable_NormalPriority=3,i.unstable_Profiling=null,i.unstable_UserBlockingPriority=2,i.unstable_cancelCallback=function(C){C.callback=null},i.unstable_forceFrameRate=function(C){0>C||125pe?(C.sortIndex=P,h(m,C),d(p)===null&&C===d(m)&&(B?(Z(ue),ue=-1):B=!0,Qe(L,P-pe))):(C.sortIndex=g,h(p,C),M||Y||(M=!0,se||(se=!0,Xe()))),C},i.unstable_shouldYield=Je,i.unstable_wrapCallback=function(C){var X=N;return function(){var P=N;N=X;try{return C.apply(this,arguments)}finally{N=P}}}}(jf)),jf}var Bd;function Gy(){return Bd||(Bd=1,Rf.exports=Yy()),Rf.exports}var Of={exports:{}},Ke={};/** * @license React * react-dom.production.js * @@ -30,7 +30,7 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */var wd;function Xy(){if(wd)return Ke;wd=1;var i=Cf();function d(p){var m="https://react.dev/errors/"+p;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(i)}catch(d){console.error(d)}}return i(),Mf.exports=Xy(),Mf.exports}/** + */var qd;function Xy(){if(qd)return Ke;qd=1;var i=Cf();function h(p){var m="https://react.dev/errors/"+p;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(i)}catch(h){console.error(h)}}return i(),Of.exports=Xy(),Of.exports}/** * @license React * react-dom-client.production.js * @@ -38,14 +38,14 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */var Yd;function Zy(){if(Yd)return Cn;Yd=1;var i=Gy(),d=Cf(),o=Qy();function f(e){var t="https://react.dev/errors/"+e;if(1g||(e.current=pe[g],pe[g]=null,g--)}function G(e,t){g++,pe[g]=e.current,e.current=t}var $=B(null),oe=B(null),ee=B(null),tt=B(null);function Te(e,t){switch(G(ee,t),G(oe,e),G($,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?id(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=id(t),e=cd(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}Q($),G($,e)}function tl(){Q($),Q(oe),Q(ee)}function ci(e){e.memoizedState!==null&&G(tt,e);var t=$.current,l=cd(t,e.type);t!==l&&(G(oe,e),G($,l))}function Yn(e){oe.current===e&&(Q($),Q(oe)),tt.current===e&&(Q(tt),On._currentValue=P)}var fi=Object.prototype.hasOwnProperty,ri=i.unstable_scheduleCallback,si=i.unstable_cancelCallback,mh=i.unstable_shouldYield,yh=i.unstable_requestPaint,Nt=i.unstable_now,vh=i.unstable_getCurrentPriorityLevel,Lf=i.unstable_ImmediatePriority,Yf=i.unstable_UserBlockingPriority,Gn=i.unstable_NormalPriority,gh=i.unstable_LowPriority,Gf=i.unstable_IdlePriority,bh=i.log,ph=i.unstable_setDisableYieldValue,Ua=null,lt=null;function ll(e){if(typeof bh=="function"&&ph(e),lt&&typeof lt.setStrictMode=="function")try{lt.setStrictMode(Ua,e)}catch{}}var at=Math.clz32?Math.clz32:Eh,Sh=Math.log,xh=Math.LN2;function Eh(e){return e>>>=0,e===0?32:31-(Sh(e)/xh|0)|0}var Xn=256,Qn=4194304;function Ml(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194048;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Zn(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var n=0,u=e.suspendedLanes,c=e.pingedLanes;e=e.warmLanes;var r=a&134217727;return r!==0?(a=r&~u,a!==0?n=Ml(a):(c&=r,c!==0?n=Ml(c):l||(l=r&~e,l!==0&&(n=Ml(l))))):(r=a&~u,r!==0?n=Ml(r):c!==0?n=Ml(c):l||(l=a&~e,l!==0&&(n=Ml(l)))),n===0?0:t!==0&&t!==n&&(t&u)===0&&(u=n&-n,l=t&-t,u>=l||u===32&&(l&4194048)!==0)?t:n}function Ha(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Th(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Xf(){var e=Xn;return Xn<<=1,(Xn&4194048)===0&&(Xn=256),e}function Qf(){var e=Qn;return Qn<<=1,(Qn&62914560)===0&&(Qn=4194304),e}function oi(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function Ba(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Ah(e,t,l,a,n,u){var c=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var r=e.entanglements,y=e.expirationTimes,T=e.hiddenUpdates;for(l=c&~l;0g||(e.current=pe[g],pe[g]=null,g--)}function G(e,t){g++,pe[g]=e.current,e.current=t}var $=w(null),oe=w(null),ee=w(null),tt=w(null);function Te(e,t){switch(G(ee,t),G(oe,e),G($,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?id(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=id(t),e=cd(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}V($),G($,e)}function tl(){V($),V(oe),V(ee)}function ci(e){e.memoizedState!==null&&G(tt,e);var t=$.current,l=cd(t,e.type);t!==l&&(G(oe,e),G($,l))}function Yn(e){oe.current===e&&(V($),V(oe)),tt.current===e&&(V(tt),jn._currentValue=P)}var fi=Object.prototype.hasOwnProperty,ri=i.unstable_scheduleCallback,si=i.unstable_cancelCallback,mh=i.unstable_shouldYield,yh=i.unstable_requestPaint,Nt=i.unstable_now,vh=i.unstable_getCurrentPriorityLevel,Lf=i.unstable_ImmediatePriority,Yf=i.unstable_UserBlockingPriority,Gn=i.unstable_NormalPriority,gh=i.unstable_LowPriority,Gf=i.unstable_IdlePriority,bh=i.log,ph=i.unstable_setDisableYieldValue,Ua=null,lt=null;function ll(e){if(typeof bh=="function"&&ph(e),lt&&typeof lt.setStrictMode=="function")try{lt.setStrictMode(Ua,e)}catch{}}var at=Math.clz32?Math.clz32:Eh,Sh=Math.log,xh=Math.LN2;function Eh(e){return e>>>=0,e===0?32:31-(Sh(e)/xh|0)|0}var Xn=256,Qn=4194304;function Ol(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194048;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Zn(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var n=0,u=e.suspendedLanes,c=e.pingedLanes;e=e.warmLanes;var r=a&134217727;return r!==0?(a=r&~u,a!==0?n=Ol(a):(c&=r,c!==0?n=Ol(c):l||(l=r&~e,l!==0&&(n=Ol(l))))):(r=a&~u,r!==0?n=Ol(r):c!==0?n=Ol(c):l||(l=a&~e,l!==0&&(n=Ol(l)))),n===0?0:t!==0&&t!==n&&(t&u)===0&&(u=n&-n,l=t&-t,u>=l||u===32&&(l&4194048)!==0)?t:n}function Ha(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Th(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Xf(){var e=Xn;return Xn<<=1,(Xn&4194048)===0&&(Xn=256),e}function Qf(){var e=Qn;return Qn<<=1,(Qn&62914560)===0&&(Qn=4194304),e}function oi(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function wa(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Ah(e,t,l,a,n,u){var c=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var r=e.entanglements,y=e.expirationTimes,A=e.hiddenUpdates;for(l=c&~l;0)":-1n||y[a]!==T[n]){var z=` -`+y[a].replace(" at new "," at ");return e.displayName&&z.includes("")&&(z=z.replace("",e.displayName)),z}while(1<=a&&0<=n);break}}}finally{gi=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?Pl(l):""}function zh(e){switch(e.tag){case 26:case 27:case 5:return Pl(e.type);case 16:return Pl("Lazy");case 13:return Pl("Suspense");case 19:return Pl("SuspenseList");case 0:case 15:return bi(e.type,!1);case 11:return bi(e.type.render,!1);case 1:return bi(e.type,!0);case 31:return Pl("Activity");default:return""}}function If(e){try{var t="";do t+=zh(e),e=e.return;while(e);return t}catch(l){return` +`+vi+e+Pf}var gi=!1;function bi(e,t){if(!e||gi)return"";gi=!0;var l=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var a={DetermineComponentFrameRoot:function(){try{if(t){var H=function(){throw Error()};if(Object.defineProperty(H.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(H,[])}catch(j){var R=j}Reflect.construct(e,[],H)}else{try{H.call()}catch(j){R=j}e.call(H.prototype)}}else{try{throw Error()}catch(j){R=j}(H=e())&&typeof H.catch=="function"&&H.catch(function(){})}}catch(j){if(j&&R&&typeof j.stack=="string")return[j.stack,R.stack]}return[null,null]}};a.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var n=Object.getOwnPropertyDescriptor(a.DetermineComponentFrameRoot,"name");n&&n.configurable&&Object.defineProperty(a.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var u=a.DetermineComponentFrameRoot(),c=u[0],r=u[1];if(c&&r){var y=c.split(` +`),A=r.split(` +`);for(n=a=0;an||y[a]!==A[n]){var _=` +`+y[a].replace(" at new "," at ");return e.displayName&&_.includes("")&&(_=_.replace("",e.displayName)),_}while(1<=a&&0<=n);break}}}finally{gi=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?Pl(l):""}function Mh(e){switch(e.tag){case 26:case 27:case 5:return Pl(e.type);case 16:return Pl("Lazy");case 13:return Pl("Suspense");case 19:return Pl("SuspenseList");case 0:case 15:return bi(e.type,!1);case 11:return bi(e.type.render,!1);case 1:return bi(e.type,!0);case 31:return Pl("Activity");default:return""}}function If(e){try{var t="";do t+=Mh(e),e=e.return;while(e);return t}catch(l){return` Error generating stack: `+l.message+` -`+l.stack}}function dt(e){switch(typeof e){case"bigint":case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function er(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Dh(e){var t=er(e)?"checked":"value",l=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),a=""+e[t];if(!e.hasOwnProperty(t)&&typeof l<"u"&&typeof l.get=="function"&&typeof l.set=="function"){var n=l.get,u=l.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return n.call(this)},set:function(c){a=""+c,u.call(this,c)}}),Object.defineProperty(e,t,{enumerable:l.enumerable}),{getValue:function(){return a},setValue:function(c){a=""+c},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Jn(e){e._valueTracker||(e._valueTracker=Dh(e))}function tr(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var l=t.getValue(),a="";return e&&(a=er(e)?e.checked?"true":"false":e.value),e=a,e!==l?(t.setValue(e),!0):!1}function kn(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var _h=/[\n"\\]/g;function ht(e){return e.replace(_h,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function pi(e,t,l,a,n,u,c,r){e.name="",c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?e.type=c:e.removeAttribute("type"),t!=null?c==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+dt(t)):e.value!==""+dt(t)&&(e.value=""+dt(t)):c!=="submit"&&c!=="reset"||e.removeAttribute("value"),t!=null?Si(e,c,dt(t)):l!=null?Si(e,c,dt(l)):a!=null&&e.removeAttribute("value"),n==null&&u!=null&&(e.defaultChecked=!!u),n!=null&&(e.checked=n&&typeof n!="function"&&typeof n!="symbol"),r!=null&&typeof r!="function"&&typeof r!="symbol"&&typeof r!="boolean"?e.name=""+dt(r):e.removeAttribute("name")}function lr(e,t,l,a,n,u,c,r){if(u!=null&&typeof u!="function"&&typeof u!="symbol"&&typeof u!="boolean"&&(e.type=u),t!=null||l!=null){if(!(u!=="submit"&&u!=="reset"||t!=null))return;l=l!=null?""+dt(l):"",t=t!=null?""+dt(t):l,r||t===e.value||(e.value=t),e.defaultValue=t}a=a??n,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=r?e.checked:!!a,e.defaultChecked=!!a,c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"&&(e.name=c)}function Si(e,t,l){t==="number"&&kn(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function Il(e,t,l,a){if(e=e.options,t){t={};for(var n=0;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Ni=!1;if(qt)try{var Ya={};Object.defineProperty(Ya,"passive",{get:function(){Ni=!0}}),window.addEventListener("test",Ya,Ya),window.removeEventListener("test",Ya,Ya)}catch{Ni=!1}var nl=null,Ri=null,Wn=null;function rr(){if(Wn)return Wn;var e,t=Ri,l=t.length,a,n="value"in nl?nl.value:nl.textContent,u=n.length;for(e=0;e=Qa),yr=" ",vr=!1;function gr(e,t){switch(e){case"keyup":return im.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function br(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var aa=!1;function fm(e,t){switch(e){case"compositionend":return br(t);case"keypress":return t.which!==32?null:(vr=!0,yr);case"textInput":return e=t.data,e===yr&&vr?null:e;default:return null}}function rm(e,t){if(aa)return e==="compositionend"||!Di&&gr(e,t)?(e=rr(),Wn=Ri=nl=null,aa=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Rr(l)}}function Mr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Mr(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function jr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=kn(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=kn(e.document)}return t}function Ui(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var gm=qt&&"documentMode"in document&&11>=document.documentMode,na=null,Hi=null,Ja=null,Bi=!1;function zr(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;Bi||na==null||na!==kn(a)||(a=na,"selectionStart"in a&&Ui(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),Ja&&Ka(Ja,a)||(Ja=a,a=Yu(Hi,"onSelect"),0>=c,n-=c,Lt=1<<32-at(t)+n|l<u?u:8;var c=D.T,r={};D.T=r,xc(e,!1,t,l);try{var y=n(),T=D.S;if(T!==null&&T(r,y),y!==null&&typeof y=="object"&&typeof y.then=="function"){var z=Rm(y,a);rn(e,t,z,rt(e))}else rn(e,t,a,rt(e))}catch(U){rn(e,t,{then:function(){},status:"rejected",reason:U},rt())}finally{X.p=u,D.T=c}}function Dm(){}function pc(e,t,l,a){if(e.tag!==5)throw Error(f(476));var n=Ds(e).queue;zs(e,n,t,P,l===null?Dm:function(){return _s(e),l(a)})}function Ds(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:P,baseState:P,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Qt,lastRenderedState:P},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Qt,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function _s(e){var t=Ds(e).next.queue;rn(e,t,{},rt())}function Sc(){return Ve(On)}function Cs(){return _e().memoizedState}function Us(){return _e().memoizedState}function _m(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=rt();e=cl(l);var a=fl(t,e,l);a!==null&&(st(a,t,l),ln(a,t,l)),t={cache:Wi()},e.payload=t;return}t=t.return}}function Cm(e,t,l){var a=rt();l={lane:a,revertLane:0,action:l,hasEagerState:!1,eagerState:null,next:null},Su(e)?Bs(t,l):(l=Yi(e,t,l,a),l!==null&&(st(l,e,a),qs(l,t,a)))}function Hs(e,t,l){var a=rt();rn(e,t,l,a)}function rn(e,t,l,a){var n={lane:a,revertLane:0,action:l,hasEagerState:!1,eagerState:null,next:null};if(Su(e))Bs(t,n);else{var u=e.alternate;if(e.lanes===0&&(u===null||u.lanes===0)&&(u=t.lastRenderedReducer,u!==null))try{var c=t.lastRenderedState,r=u(c,l);if(n.hasEagerState=!0,n.eagerState=r,nt(r,c))return au(e,t,n,0),xe===null&&lu(),!1}catch{}finally{}if(l=Yi(e,t,n,a),l!==null)return st(l,e,a),qs(l,t,a),!0}return!1}function xc(e,t,l,a){if(a={lane:2,revertLane:Ic(),action:a,hasEagerState:!1,eagerState:null,next:null},Su(e)){if(t)throw Error(f(479))}else t=Yi(e,l,a,2),t!==null&&st(t,e,2)}function Su(e){var t=e.alternate;return e===ae||t!==null&&t===ae}function Bs(e,t){ma=mu=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function qs(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,Vf(e,l)}}var xu={readContext:Ve,use:vu,useCallback:je,useContext:je,useEffect:je,useImperativeHandle:je,useLayoutEffect:je,useInsertionEffect:je,useMemo:je,useReducer:je,useRef:je,useState:je,useDebugValue:je,useDeferredValue:je,useTransition:je,useSyncExternalStore:je,useId:je,useHostTransitionStatus:je,useFormState:je,useActionState:je,useOptimistic:je,useMemoCache:je,useCacheRefresh:je},ws={readContext:Ve,use:vu,useCallback:function(e,t){return Fe().memoizedState=[e,t===void 0?null:t],e},useContext:Ve,useEffect:xs,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,pu(4194308,4,Ns.bind(null,t,e),l)},useLayoutEffect:function(e,t){return pu(4194308,4,e,t)},useInsertionEffect:function(e,t){pu(4,2,e,t)},useMemo:function(e,t){var l=Fe();t=t===void 0?null:t;var a=e();if(Gl){ll(!0);try{e()}finally{ll(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=Fe();if(l!==void 0){var n=l(t);if(Gl){ll(!0);try{l(t)}finally{ll(!1)}}}else n=t;return a.memoizedState=a.baseState=n,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:n},a.queue=e,e=e.dispatch=Cm.bind(null,ae,e),[a.memoizedState,e]},useRef:function(e){var t=Fe();return e={current:e},t.memoizedState=e},useState:function(e){e=yc(e);var t=e.queue,l=Hs.bind(null,ae,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:gc,useDeferredValue:function(e,t){var l=Fe();return bc(l,e,t)},useTransition:function(){var e=yc(!1);return e=zs.bind(null,ae,e.queue,!0,!1),Fe().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=ae,n=Fe();if(he){if(l===void 0)throw Error(f(407));l=l()}else{if(l=t(),xe===null)throw Error(f(349));(fe&124)!==0||us(a,t,l)}n.memoizedState=l;var u={value:l,getSnapshot:t};return n.queue=u,xs(cs.bind(null,a,u,e),[e]),a.flags|=2048,va(9,bu(),is.bind(null,a,u,l,t),null),l},useId:function(){var e=Fe(),t=xe.identifierPrefix;if(he){var l=Yt,a=Lt;l=(a&~(1<<32-at(a)-1)).toString(32)+l,t="«"+t+"R"+l,l=yu++,0F?(we=J,J=null):we=J.sibling;var de=N(x,J,E[F],_);if(de===null){J===null&&(J=we);break}e&&J&&de.alternate===null&&t(x,J),b=u(de,b,F),ne===null?K=de:ne.sibling=de,ne=de,J=we}if(F===E.length)return l(x,J),he&&Hl(x,F),K;if(J===null){for(;FF?(we=J,J=null):we=J.sibling;var Nl=N(x,J,de.value,_);if(Nl===null){J===null&&(J=we);break}e&&J&&Nl.alternate===null&&t(x,J),b=u(Nl,b,F),ne===null?K=Nl:ne.sibling=Nl,ne=Nl,J=we}if(de.done)return l(x,J),he&&Hl(x,F),K;if(J===null){for(;!de.done;F++,de=E.next())de=U(x,de.value,_),de!==null&&(b=u(de,b,F),ne===null?K=de:ne.sibling=de,ne=de);return he&&Hl(x,F),K}for(J=a(J);!de.done;F++,de=E.next())de=R(J,x,F,de.value,_),de!==null&&(e&&de.alternate!==null&&J.delete(de.key===null?F:de.key),b=u(de,b,F),ne===null?K=de:ne.sibling=de,ne=de);return e&&J.forEach(function(Hy){return t(x,Hy)}),he&&Hl(x,F),K}function be(x,b,E,_){if(typeof E=="object"&&E!==null&&E.type===C&&E.key===null&&(E=E.props.children),typeof E=="object"&&E!==null){switch(E.$$typeof){case O:e:{for(var K=E.key;b!==null;){if(b.key===K){if(K=E.type,K===C){if(b.tag===7){l(x,b.sibling),_=n(b,E.props.children),_.return=x,x=_;break e}}else if(b.elementType===K||typeof K=="object"&&K!==null&&K.$$typeof===re&&Ys(K)===b.type){l(x,b.sibling),_=n(b,E.props),on(_,E),_.return=x,x=_;break e}l(x,b);break}else t(x,b);b=b.sibling}E.type===C?(_=Cl(E.props.children,x.mode,_,E.key),_.return=x,x=_):(_=uu(E.type,E.key,E.props,null,x.mode,_),on(_,E),_.return=x,x=_)}return c(x);case q:e:{for(K=E.key;b!==null;){if(b.key===K)if(b.tag===4&&b.stateNode.containerInfo===E.containerInfo&&b.stateNode.implementation===E.implementation){l(x,b.sibling),_=n(b,E.children||[]),_.return=x,x=_;break e}else{l(x,b);break}else t(x,b);b=b.sibling}_=Qi(E,x.mode,_),_.return=x,x=_}return c(x);case re:return K=E._init,E=K(E._payload),be(x,b,E,_)}if(Qe(E))return I(x,b,E,_);if(Xe(E)){if(K=Xe(E),typeof K!="function")throw Error(f(150));return E=K.call(E),W(x,b,E,_)}if(typeof E.then=="function")return be(x,b,Eu(E),_);if(E.$$typeof===k)return be(x,b,ru(x,E),_);Tu(x,E)}return typeof E=="string"&&E!==""||typeof E=="number"||typeof E=="bigint"?(E=""+E,b!==null&&b.tag===6?(l(x,b.sibling),_=n(b,E),_.return=x,x=_):(l(x,b),_=Xi(E,x.mode,_),_.return=x,x=_),c(x)):l(x,b)}return function(x,b,E,_){try{sn=0;var K=be(x,b,E,_);return ga=null,K}catch(J){if(J===en||J===ou)throw J;var ne=ut(29,J,null,x.mode);return ne.lanes=_,ne.return=x,ne}finally{}}}var ba=Gs(!0),Xs=Gs(!1),bt=B(null),Ot=null;function sl(e){var t=e.alternate;G(Ue,Ue.current&1),G(bt,e),Ot===null&&(t===null||ha.current!==null||t.memoizedState!==null)&&(Ot=e)}function Qs(e){if(e.tag===22){if(G(Ue,Ue.current),G(bt,e),Ot===null){var t=e.alternate;t!==null&&t.memoizedState!==null&&(Ot=e)}}else ol()}function ol(){G(Ue,Ue.current),G(bt,bt.current)}function Zt(e){Q(bt),Ot===e&&(Ot=null),Q(Ue)}var Ue=B(0);function Au(e){for(var t=e;t!==null;){if(t.tag===13){var l=t.memoizedState;if(l!==null&&(l=l.dehydrated,l===null||l.data==="$?"||df(l)))return t}else if(t.tag===19&&t.memoizedProps.revealOrder!==void 0){if((t.flags&128)!==0)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}function Ec(e,t,l,a){t=e.memoizedState,l=l(a,t),l=l==null?t:M({},t,l),e.memoizedState=l,e.lanes===0&&(e.updateQueue.baseState=l)}var Tc={enqueueSetState:function(e,t,l){e=e._reactInternals;var a=rt(),n=cl(a);n.payload=t,l!=null&&(n.callback=l),t=fl(e,n,a),t!==null&&(st(t,e,a),ln(t,e,a))},enqueueReplaceState:function(e,t,l){e=e._reactInternals;var a=rt(),n=cl(a);n.tag=1,n.payload=t,l!=null&&(n.callback=l),t=fl(e,n,a),t!==null&&(st(t,e,a),ln(t,e,a))},enqueueForceUpdate:function(e,t){e=e._reactInternals;var l=rt(),a=cl(l);a.tag=2,t!=null&&(a.callback=t),t=fl(e,a,l),t!==null&&(st(t,e,l),ln(t,e,l))}};function Zs(e,t,l,a,n,u,c){return e=e.stateNode,typeof e.shouldComponentUpdate=="function"?e.shouldComponentUpdate(a,u,c):t.prototype&&t.prototype.isPureReactComponent?!Ka(l,a)||!Ka(n,u):!0}function Vs(e,t,l,a){e=t.state,typeof t.componentWillReceiveProps=="function"&&t.componentWillReceiveProps(l,a),typeof t.UNSAFE_componentWillReceiveProps=="function"&&t.UNSAFE_componentWillReceiveProps(l,a),t.state!==e&&Tc.enqueueReplaceState(t,t.state,null)}function Xl(e,t){var l=t;if("ref"in t){l={};for(var a in t)a!=="ref"&&(l[a]=t[a])}if(e=e.defaultProps){l===t&&(l=M({},l));for(var n in e)l[n]===void 0&&(l[n]=e[n])}return l}var Nu=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function Ks(e){Nu(e)}function Js(e){console.error(e)}function ks(e){Nu(e)}function Ru(e,t){try{var l=e.onUncaughtError;l(t.value,{componentStack:t.stack})}catch(a){setTimeout(function(){throw a})}}function $s(e,t,l){try{var a=e.onCaughtError;a(l.value,{componentStack:l.stack,errorBoundary:t.tag===1?t.stateNode:null})}catch(n){setTimeout(function(){throw n})}}function Ac(e,t,l){return l=cl(l),l.tag=3,l.payload={element:null},l.callback=function(){Ru(e,t)},l}function Ws(e){return e=cl(e),e.tag=3,e}function Fs(e,t,l,a){var n=l.type.getDerivedStateFromError;if(typeof n=="function"){var u=a.value;e.payload=function(){return n(u)},e.callback=function(){$s(t,l,a)}}var c=l.stateNode;c!==null&&typeof c.componentDidCatch=="function"&&(e.callback=function(){$s(t,l,a),typeof n!="function"&&(gl===null?gl=new Set([this]):gl.add(this));var r=a.stack;this.componentDidCatch(a.value,{componentStack:r!==null?r:""})})}function Hm(e,t,l,a,n){if(l.flags|=32768,a!==null&&typeof a=="object"&&typeof a.then=="function"){if(t=l.alternate,t!==null&&Fa(t,l,n,!0),l=bt.current,l!==null){switch(l.tag){case 13:return Ot===null?kc():l.alternate===null&&Me===0&&(Me=3),l.flags&=-257,l.flags|=65536,l.lanes=n,a===Ii?l.flags|=16384:(t=l.updateQueue,t===null?l.updateQueue=new Set([a]):t.add(a),Wc(e,a,n)),!1;case 22:return l.flags|=65536,a===Ii?l.flags|=16384:(t=l.updateQueue,t===null?(t={transitions:null,markerInstances:null,retryQueue:new Set([a])},l.updateQueue=t):(l=t.retryQueue,l===null?t.retryQueue=new Set([a]):l.add(a)),Wc(e,a,n)),!1}throw Error(f(435,l.tag))}return Wc(e,a,n),kc(),!1}if(he)return t=bt.current,t!==null?((t.flags&65536)===0&&(t.flags|=256),t.flags|=65536,t.lanes=n,a!==Ki&&(e=Error(f(422),{cause:a}),Wa(mt(e,l)))):(a!==Ki&&(t=Error(f(423),{cause:a}),Wa(mt(t,l))),e=e.current.alternate,e.flags|=65536,n&=-n,e.lanes|=n,a=mt(a,l),n=Ac(e.stateNode,a,n),lc(e,n),Me!==4&&(Me=2)),!1;var u=Error(f(520),{cause:a});if(u=mt(u,l),bn===null?bn=[u]:bn.push(u),Me!==4&&(Me=2),t===null)return!0;a=mt(a,l),l=t;do{switch(l.tag){case 3:return l.flags|=65536,e=n&-n,l.lanes|=e,e=Ac(l.stateNode,a,e),lc(l,e),!1;case 1:if(t=l.type,u=l.stateNode,(l.flags&128)===0&&(typeof t.getDerivedStateFromError=="function"||u!==null&&typeof u.componentDidCatch=="function"&&(gl===null||!gl.has(u))))return l.flags|=65536,n&=-n,l.lanes|=n,n=Ws(n),Fs(n,e,l,a),lc(l,n),!1}l=l.return}while(l!==null);return!1}var Ps=Error(f(461)),Be=!1;function Le(e,t,l,a){t.child=e===null?Xs(t,null,l,a):ba(t,e.child,l,a)}function Is(e,t,l,a,n){l=l.render;var u=t.ref;if("ref"in a){var c={};for(var r in a)r!=="ref"&&(c[r]=a[r])}else c=a;return Ll(t),a=cc(e,t,l,c,u,n),r=fc(),e!==null&&!Be?(rc(e,t,n),Vt(e,t,n)):(he&&r&&Zi(t),t.flags|=1,Le(e,t,a,n),t.child)}function eo(e,t,l,a,n){if(e===null){var u=l.type;return typeof u=="function"&&!Gi(u)&&u.defaultProps===void 0&&l.compare===null?(t.tag=15,t.type=u,to(e,t,u,a,n)):(e=uu(l.type,null,a,t,t.mode,n),e.ref=t.ref,e.return=t,t.child=e)}if(u=e.child,!_c(e,n)){var c=u.memoizedProps;if(l=l.compare,l=l!==null?l:Ka,l(c,a)&&e.ref===t.ref)return Vt(e,t,n)}return t.flags|=1,e=wt(u,a),e.ref=t.ref,e.return=t,t.child=e}function to(e,t,l,a,n){if(e!==null){var u=e.memoizedProps;if(Ka(u,a)&&e.ref===t.ref)if(Be=!1,t.pendingProps=a=u,_c(e,n))(e.flags&131072)!==0&&(Be=!0);else return t.lanes=e.lanes,Vt(e,t,n)}return Nc(e,t,l,a,n)}function lo(e,t,l){var a=t.pendingProps,n=a.children,u=e!==null?e.memoizedState:null;if(a.mode==="hidden"){if((t.flags&128)!==0){if(a=u!==null?u.baseLanes|l:l,e!==null){for(n=t.child=e.child,u=0;n!==null;)u=u|n.lanes|n.childLanes,n=n.sibling;t.childLanes=u&~a}else t.childLanes=0,t.child=null;return ao(e,t,a,l)}if((l&536870912)!==0)t.memoizedState={baseLanes:0,cachePool:null},e!==null&&su(t,u!==null?u.cachePool:null),u!==null?ts(t,u):nc(),Qs(t);else return t.lanes=t.childLanes=536870912,ao(e,t,u!==null?u.baseLanes|l:l,l)}else u!==null?(su(t,u.cachePool),ts(t,u),ol(),t.memoizedState=null):(e!==null&&su(t,null),nc(),ol());return Le(e,t,n,l),t.child}function ao(e,t,l,a){var n=Pi();return n=n===null?null:{parent:Ce._currentValue,pool:n},t.memoizedState={baseLanes:l,cachePool:n},e!==null&&su(t,null),nc(),Qs(t),e!==null&&Fa(e,t,a,!0),null}function Ou(e,t){var l=t.ref;if(l===null)e!==null&&e.ref!==null&&(t.flags|=4194816);else{if(typeof l!="function"&&typeof l!="object")throw Error(f(284));(e===null||e.ref!==l)&&(t.flags|=4194816)}}function Nc(e,t,l,a,n){return Ll(t),l=cc(e,t,l,a,void 0,n),a=fc(),e!==null&&!Be?(rc(e,t,n),Vt(e,t,n)):(he&&a&&Zi(t),t.flags|=1,Le(e,t,l,n),t.child)}function no(e,t,l,a,n,u){return Ll(t),t.updateQueue=null,l=as(t,a,l,n),ls(e),a=fc(),e!==null&&!Be?(rc(e,t,u),Vt(e,t,u)):(he&&a&&Zi(t),t.flags|=1,Le(e,t,l,u),t.child)}function uo(e,t,l,a,n){if(Ll(t),t.stateNode===null){var u=fa,c=l.contextType;typeof c=="object"&&c!==null&&(u=Ve(c)),u=new l(a,u),t.memoizedState=u.state!==null&&u.state!==void 0?u.state:null,u.updater=Tc,t.stateNode=u,u._reactInternals=t,u=t.stateNode,u.props=a,u.state=t.memoizedState,u.refs={},ec(t),c=l.contextType,u.context=typeof c=="object"&&c!==null?Ve(c):fa,u.state=t.memoizedState,c=l.getDerivedStateFromProps,typeof c=="function"&&(Ec(t,l,c,a),u.state=t.memoizedState),typeof l.getDerivedStateFromProps=="function"||typeof u.getSnapshotBeforeUpdate=="function"||typeof u.UNSAFE_componentWillMount!="function"&&typeof u.componentWillMount!="function"||(c=u.state,typeof u.componentWillMount=="function"&&u.componentWillMount(),typeof u.UNSAFE_componentWillMount=="function"&&u.UNSAFE_componentWillMount(),c!==u.state&&Tc.enqueueReplaceState(u,u.state,null),nn(t,a,u,n),an(),u.state=t.memoizedState),typeof u.componentDidMount=="function"&&(t.flags|=4194308),a=!0}else if(e===null){u=t.stateNode;var r=t.memoizedProps,y=Xl(l,r);u.props=y;var T=u.context,z=l.contextType;c=fa,typeof z=="object"&&z!==null&&(c=Ve(z));var U=l.getDerivedStateFromProps;z=typeof U=="function"||typeof u.getSnapshotBeforeUpdate=="function",r=t.pendingProps!==r,z||typeof u.UNSAFE_componentWillReceiveProps!="function"&&typeof u.componentWillReceiveProps!="function"||(r||T!==c)&&Vs(t,u,a,c),il=!1;var N=t.memoizedState;u.state=N,nn(t,a,u,n),an(),T=t.memoizedState,r||N!==T||il?(typeof U=="function"&&(Ec(t,l,U,a),T=t.memoizedState),(y=il||Zs(t,l,y,a,N,T,c))?(z||typeof u.UNSAFE_componentWillMount!="function"&&typeof u.componentWillMount!="function"||(typeof u.componentWillMount=="function"&&u.componentWillMount(),typeof u.UNSAFE_componentWillMount=="function"&&u.UNSAFE_componentWillMount()),typeof u.componentDidMount=="function"&&(t.flags|=4194308)):(typeof u.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=a,t.memoizedState=T),u.props=a,u.state=T,u.context=c,a=y):(typeof u.componentDidMount=="function"&&(t.flags|=4194308),a=!1)}else{u=t.stateNode,tc(e,t),c=t.memoizedProps,z=Xl(l,c),u.props=z,U=t.pendingProps,N=u.context,T=l.contextType,y=fa,typeof T=="object"&&T!==null&&(y=Ve(T)),r=l.getDerivedStateFromProps,(T=typeof r=="function"||typeof u.getSnapshotBeforeUpdate=="function")||typeof u.UNSAFE_componentWillReceiveProps!="function"&&typeof u.componentWillReceiveProps!="function"||(c!==U||N!==y)&&Vs(t,u,a,y),il=!1,N=t.memoizedState,u.state=N,nn(t,a,u,n),an();var R=t.memoizedState;c!==U||N!==R||il||e!==null&&e.dependencies!==null&&fu(e.dependencies)?(typeof r=="function"&&(Ec(t,l,r,a),R=t.memoizedState),(z=il||Zs(t,l,z,a,N,R,y)||e!==null&&e.dependencies!==null&&fu(e.dependencies))?(T||typeof u.UNSAFE_componentWillUpdate!="function"&&typeof u.componentWillUpdate!="function"||(typeof u.componentWillUpdate=="function"&&u.componentWillUpdate(a,R,y),typeof u.UNSAFE_componentWillUpdate=="function"&&u.UNSAFE_componentWillUpdate(a,R,y)),typeof u.componentDidUpdate=="function"&&(t.flags|=4),typeof u.getSnapshotBeforeUpdate=="function"&&(t.flags|=1024)):(typeof u.componentDidUpdate!="function"||c===e.memoizedProps&&N===e.memoizedState||(t.flags|=4),typeof u.getSnapshotBeforeUpdate!="function"||c===e.memoizedProps&&N===e.memoizedState||(t.flags|=1024),t.memoizedProps=a,t.memoizedState=R),u.props=a,u.state=R,u.context=y,a=z):(typeof u.componentDidUpdate!="function"||c===e.memoizedProps&&N===e.memoizedState||(t.flags|=4),typeof u.getSnapshotBeforeUpdate!="function"||c===e.memoizedProps&&N===e.memoizedState||(t.flags|=1024),a=!1)}return u=a,Ou(e,t),a=(t.flags&128)!==0,u||a?(u=t.stateNode,l=a&&typeof l.getDerivedStateFromError!="function"?null:u.render(),t.flags|=1,e!==null&&a?(t.child=ba(t,e.child,null,n),t.child=ba(t,null,l,n)):Le(e,t,l,n),t.memoizedState=u.state,e=t.child):e=Vt(e,t,n),e}function io(e,t,l,a){return $a(),t.flags|=256,Le(e,t,l,a),t.child}var Rc={dehydrated:null,treeContext:null,retryLane:0,hydrationErrors:null};function Oc(e){return{baseLanes:e,cachePool:Jr()}}function Mc(e,t,l){return e=e!==null?e.childLanes&~l:0,t&&(e|=pt),e}function co(e,t,l){var a=t.pendingProps,n=!1,u=(t.flags&128)!==0,c;if((c=u)||(c=e!==null&&e.memoizedState===null?!1:(Ue.current&2)!==0),c&&(n=!0,t.flags&=-129),c=(t.flags&32)!==0,t.flags&=-33,e===null){if(he){if(n?sl(t):ol(),he){var r=Oe,y;if(y=r){e:{for(y=r,r=Rt;y.nodeType!==8;){if(!r){r=null;break e}if(y=Tt(y.nextSibling),y===null){r=null;break e}}r=y}r!==null?(t.memoizedState={dehydrated:r,treeContext:Ul!==null?{id:Lt,overflow:Yt}:null,retryLane:536870912,hydrationErrors:null},y=ut(18,null,null,0),y.stateNode=r,y.return=t,t.child=y,ke=t,Oe=null,y=!0):y=!1}y||ql(t)}if(r=t.memoizedState,r!==null&&(r=r.dehydrated,r!==null))return df(r)?t.lanes=32:t.lanes=536870912,null;Zt(t)}return r=a.children,a=a.fallback,n?(ol(),n=t.mode,r=Mu({mode:"hidden",children:r},n),a=Cl(a,n,l,null),r.return=t,a.return=t,r.sibling=a,t.child=r,n=t.child,n.memoizedState=Oc(l),n.childLanes=Mc(e,c,l),t.memoizedState=Rc,a):(sl(t),jc(t,r))}if(y=e.memoizedState,y!==null&&(r=y.dehydrated,r!==null)){if(u)t.flags&256?(sl(t),t.flags&=-257,t=zc(e,t,l)):t.memoizedState!==null?(ol(),t.child=e.child,t.flags|=128,t=null):(ol(),n=a.fallback,r=t.mode,a=Mu({mode:"visible",children:a.children},r),n=Cl(n,r,l,null),n.flags|=2,a.return=t,n.return=t,a.sibling=n,t.child=a,ba(t,e.child,null,l),a=t.child,a.memoizedState=Oc(l),a.childLanes=Mc(e,c,l),t.memoizedState=Rc,t=n);else if(sl(t),df(r)){if(c=r.nextSibling&&r.nextSibling.dataset,c)var T=c.dgst;c=T,a=Error(f(419)),a.stack="",a.digest=c,Wa({value:a,source:null,stack:null}),t=zc(e,t,l)}else if(Be||Fa(e,t,l,!1),c=(l&e.childLanes)!==0,Be||c){if(c=xe,c!==null&&(a=l&-l,a=(a&42)!==0?1:di(a),a=(a&(c.suspendedLanes|l))!==0?0:a,a!==0&&a!==y.retryLane))throw y.retryLane=a,ca(e,a),st(c,e,a),Ps;r.data==="$?"||kc(),t=zc(e,t,l)}else r.data==="$?"?(t.flags|=192,t.child=e.child,t=null):(e=y.treeContext,Oe=Tt(r.nextSibling),ke=t,he=!0,Bl=null,Rt=!1,e!==null&&(vt[gt++]=Lt,vt[gt++]=Yt,vt[gt++]=Ul,Lt=e.id,Yt=e.overflow,Ul=t),t=jc(t,a.children),t.flags|=4096);return t}return n?(ol(),n=a.fallback,r=t.mode,y=e.child,T=y.sibling,a=wt(y,{mode:"hidden",children:a.children}),a.subtreeFlags=y.subtreeFlags&65011712,T!==null?n=wt(T,n):(n=Cl(n,r,l,null),n.flags|=2),n.return=t,a.return=t,a.sibling=n,t.child=a,a=n,n=t.child,r=e.child.memoizedState,r===null?r=Oc(l):(y=r.cachePool,y!==null?(T=Ce._currentValue,y=y.parent!==T?{parent:T,pool:T}:y):y=Jr(),r={baseLanes:r.baseLanes|l,cachePool:y}),n.memoizedState=r,n.childLanes=Mc(e,c,l),t.memoizedState=Rc,a):(sl(t),l=e.child,e=l.sibling,l=wt(l,{mode:"visible",children:a.children}),l.return=t,l.sibling=null,e!==null&&(c=t.deletions,c===null?(t.deletions=[e],t.flags|=16):c.push(e)),t.child=l,t.memoizedState=null,l)}function jc(e,t){return t=Mu({mode:"visible",children:t},e.mode),t.return=e,e.child=t}function Mu(e,t){return e=ut(22,e,null,t),e.lanes=0,e.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null},e}function zc(e,t,l){return ba(t,e.child,null,l),e=jc(t,t.pendingProps.children),e.flags|=2,t.memoizedState=null,e}function fo(e,t,l){e.lanes|=t;var a=e.alternate;a!==null&&(a.lanes|=t),ki(e.return,t,l)}function Dc(e,t,l,a,n){var u=e.memoizedState;u===null?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:a,tail:l,tailMode:n}:(u.isBackwards=t,u.rendering=null,u.renderingStartTime=0,u.last=a,u.tail=l,u.tailMode=n)}function ro(e,t,l){var a=t.pendingProps,n=a.revealOrder,u=a.tail;if(Le(e,t,a.children,l),a=Ue.current,(a&2)!==0)a=a&1|2,t.flags|=128;else{if(e!==null&&(e.flags&128)!==0)e:for(e=t.child;e!==null;){if(e.tag===13)e.memoizedState!==null&&fo(e,l,t);else if(e.tag===19)fo(e,l,t);else if(e.child!==null){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;e.sibling===null;){if(e.return===null||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}a&=1}switch(G(Ue,a),n){case"forwards":for(l=t.child,n=null;l!==null;)e=l.alternate,e!==null&&Au(e)===null&&(n=l),l=l.sibling;l=n,l===null?(n=t.child,t.child=null):(n=l.sibling,l.sibling=null),Dc(t,!1,n,l,u);break;case"backwards":for(l=null,n=t.child,t.child=null;n!==null;){if(e=n.alternate,e!==null&&Au(e)===null){t.child=n;break}e=n.sibling,n.sibling=l,l=n,n=e}Dc(t,!0,l,null,u);break;case"together":Dc(t,!1,null,null,void 0);break;default:t.memoizedState=null}return t.child}function Vt(e,t,l){if(e!==null&&(t.dependencies=e.dependencies),vl|=t.lanes,(l&t.childLanes)===0)if(e!==null){if(Fa(e,t,l,!1),(l&t.childLanes)===0)return null}else return null;if(e!==null&&t.child!==e.child)throw Error(f(153));if(t.child!==null){for(e=t.child,l=wt(e,e.pendingProps),t.child=l,l.return=t;e.sibling!==null;)e=e.sibling,l=l.sibling=wt(e,e.pendingProps),l.return=t;l.sibling=null}return t.child}function _c(e,t){return(e.lanes&t)!==0?!0:(e=e.dependencies,!!(e!==null&&fu(e)))}function Bm(e,t,l){switch(t.tag){case 3:Te(t,t.stateNode.containerInfo),ul(t,Ce,e.memoizedState.cache),$a();break;case 27:case 5:ci(t);break;case 4:Te(t,t.stateNode.containerInfo);break;case 10:ul(t,t.type,t.memoizedProps.value);break;case 13:var a=t.memoizedState;if(a!==null)return a.dehydrated!==null?(sl(t),t.flags|=128,null):(l&t.child.childLanes)!==0?co(e,t,l):(sl(t),e=Vt(e,t,l),e!==null?e.sibling:null);sl(t);break;case 19:var n=(e.flags&128)!==0;if(a=(l&t.childLanes)!==0,a||(Fa(e,t,l,!1),a=(l&t.childLanes)!==0),n){if(a)return ro(e,t,l);t.flags|=128}if(n=t.memoizedState,n!==null&&(n.rendering=null,n.tail=null,n.lastEffect=null),G(Ue,Ue.current),a)break;return null;case 22:case 23:return t.lanes=0,lo(e,t,l);case 24:ul(t,Ce,e.memoizedState.cache)}return Vt(e,t,l)}function so(e,t,l){if(e!==null)if(e.memoizedProps!==t.pendingProps)Be=!0;else{if(!_c(e,l)&&(t.flags&128)===0)return Be=!1,Bm(e,t,l);Be=(e.flags&131072)!==0}else Be=!1,he&&(t.flags&1048576)!==0&&Yr(t,cu,t.index);switch(t.lanes=0,t.tag){case 16:e:{e=t.pendingProps;var a=t.elementType,n=a._init;if(a=n(a._payload),t.type=a,typeof a=="function")Gi(a)?(e=Xl(a,e),t.tag=1,t=uo(null,t,a,e,l)):(t.tag=0,t=Nc(null,t,a,e,l));else{if(a!=null){if(n=a.$$typeof,n===le){t.tag=11,t=Is(null,t,a,e,l);break e}else if(n===ue){t.tag=14,t=eo(null,t,a,e,l);break e}}throw t=Ol(a)||a,Error(f(306,t,""))}}return t;case 0:return Nc(e,t,t.type,t.pendingProps,l);case 1:return a=t.type,n=Xl(a,t.pendingProps),uo(e,t,a,n,l);case 3:e:{if(Te(t,t.stateNode.containerInfo),e===null)throw Error(f(387));a=t.pendingProps;var u=t.memoizedState;n=u.element,tc(e,t),nn(t,a,null,l);var c=t.memoizedState;if(a=c.cache,ul(t,Ce,a),a!==u.cache&&$i(t,[Ce],l,!0),an(),a=c.element,u.isDehydrated)if(u={element:a,isDehydrated:!1,cache:c.cache},t.updateQueue.baseState=u,t.memoizedState=u,t.flags&256){t=io(e,t,a,l);break e}else if(a!==n){n=mt(Error(f(424)),t),Wa(n),t=io(e,t,a,l);break e}else{switch(e=t.stateNode.containerInfo,e.nodeType){case 9:e=e.body;break;default:e=e.nodeName==="HTML"?e.ownerDocument.body:e}for(Oe=Tt(e.firstChild),ke=t,he=!0,Bl=null,Rt=!0,l=Xs(t,null,a,l),t.child=l;l;)l.flags=l.flags&-3|4096,l=l.sibling}else{if($a(),a===n){t=Vt(e,t,l);break e}Le(e,t,a,l)}t=t.child}return t;case 26:return Ou(e,t),e===null?(l=yd(t.type,null,t.pendingProps,null))?t.memoizedState=l:he||(l=t.type,e=t.pendingProps,a=Xu(ee.current).createElement(l),a[Ze]=t,a[$e]=e,Ge(a,l,e),He(a),t.stateNode=a):t.memoizedState=yd(t.type,e.memoizedProps,t.pendingProps,e.memoizedState),null;case 27:return ci(t),e===null&&he&&(a=t.stateNode=dd(t.type,t.pendingProps,ee.current),ke=t,Rt=!0,n=Oe,Sl(t.type)?(hf=n,Oe=Tt(a.firstChild)):Oe=n),Le(e,t,t.pendingProps.children,l),Ou(e,t),e===null&&(t.flags|=4194304),t.child;case 5:return e===null&&he&&((n=a=Oe)&&(a=sy(a,t.type,t.pendingProps,Rt),a!==null?(t.stateNode=a,ke=t,Oe=Tt(a.firstChild),Rt=!1,n=!0):n=!1),n||ql(t)),ci(t),n=t.type,u=t.pendingProps,c=e!==null?e.memoizedProps:null,a=u.children,rf(n,u)?a=null:c!==null&&rf(n,c)&&(t.flags|=32),t.memoizedState!==null&&(n=cc(e,t,Mm,null,null,l),On._currentValue=n),Ou(e,t),Le(e,t,a,l),t.child;case 6:return e===null&&he&&((e=l=Oe)&&(l=oy(l,t.pendingProps,Rt),l!==null?(t.stateNode=l,ke=t,Oe=null,e=!0):e=!1),e||ql(t)),null;case 13:return co(e,t,l);case 4:return Te(t,t.stateNode.containerInfo),a=t.pendingProps,e===null?t.child=ba(t,null,a,l):Le(e,t,a,l),t.child;case 11:return Is(e,t,t.type,t.pendingProps,l);case 7:return Le(e,t,t.pendingProps,l),t.child;case 8:return Le(e,t,t.pendingProps.children,l),t.child;case 12:return Le(e,t,t.pendingProps.children,l),t.child;case 10:return a=t.pendingProps,ul(t,t.type,a.value),Le(e,t,a.children,l),t.child;case 9:return n=t.type._context,a=t.pendingProps.children,Ll(t),n=Ve(n),a=a(n),t.flags|=1,Le(e,t,a,l),t.child;case 14:return eo(e,t,t.type,t.pendingProps,l);case 15:return to(e,t,t.type,t.pendingProps,l);case 19:return ro(e,t,l);case 31:return a=t.pendingProps,l=t.mode,a={mode:a.mode,children:a.children},e===null?(l=Mu(a,l),l.ref=t.ref,t.child=l,l.return=t,t=l):(l=wt(e.child,a),l.ref=t.ref,t.child=l,l.return=t,t=l),t;case 22:return lo(e,t,l);case 24:return Ll(t),a=Ve(Ce),e===null?(n=Pi(),n===null&&(n=xe,u=Wi(),n.pooledCache=u,u.refCount++,u!==null&&(n.pooledCacheLanes|=l),n=u),t.memoizedState={parent:a,cache:n},ec(t),ul(t,Ce,n)):((e.lanes&l)!==0&&(tc(e,t),nn(t,null,null,l),an()),n=e.memoizedState,u=t.memoizedState,n.parent!==a?(n={parent:a,cache:a},t.memoizedState=n,t.lanes===0&&(t.memoizedState=t.updateQueue.baseState=n),ul(t,Ce,a)):(a=u.cache,ul(t,Ce,a),a!==n.cache&&$i(t,[Ce],l,!0))),Le(e,t,t.pendingProps.children,l),t.child;case 29:throw t.pendingProps}throw Error(f(156,t.tag))}function Kt(e){e.flags|=4}function oo(e,t){if(t.type!=="stylesheet"||(t.state.loading&4)!==0)e.flags&=-16777217;else if(e.flags|=16777216,!Sd(t)){if(t=bt.current,t!==null&&((fe&4194048)===fe?Ot!==null:(fe&62914560)!==fe&&(fe&536870912)===0||t!==Ot))throw tn=Ii,kr;e.flags|=8192}}function ju(e,t){t!==null&&(e.flags|=4),e.flags&16384&&(t=e.tag!==22?Qf():536870912,e.lanes|=t,Ea|=t)}function dn(e,t){if(!he)switch(e.tailMode){case"hidden":t=e.tail;for(var l=null;t!==null;)t.alternate!==null&&(l=t),t=t.sibling;l===null?e.tail=null:l.sibling=null;break;case"collapsed":l=e.tail;for(var a=null;l!==null;)l.alternate!==null&&(a=l),l=l.sibling;a===null?t||e.tail===null?e.tail=null:e.tail.sibling=null:a.sibling=null}}function Ne(e){var t=e.alternate!==null&&e.alternate.child===e.child,l=0,a=0;if(t)for(var n=e.child;n!==null;)l|=n.lanes|n.childLanes,a|=n.subtreeFlags&65011712,a|=n.flags&65011712,n.return=e,n=n.sibling;else for(n=e.child;n!==null;)l|=n.lanes|n.childLanes,a|=n.subtreeFlags,a|=n.flags,n.return=e,n=n.sibling;return e.subtreeFlags|=a,e.childLanes=l,t}function qm(e,t,l){var a=t.pendingProps;switch(Vi(t),t.tag){case 31:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Ne(t),null;case 1:return Ne(t),null;case 3:return l=t.stateNode,a=null,e!==null&&(a=e.memoizedState.cache),t.memoizedState.cache!==a&&(t.flags|=2048),Xt(Ce),tl(),l.pendingContext&&(l.context=l.pendingContext,l.pendingContext=null),(e===null||e.child===null)&&(ka(t)?Kt(t):e===null||e.memoizedState.isDehydrated&&(t.flags&256)===0||(t.flags|=1024,Qr())),Ne(t),null;case 26:return l=t.memoizedState,e===null?(Kt(t),l!==null?(Ne(t),oo(t,l)):(Ne(t),t.flags&=-16777217)):l?l!==e.memoizedState?(Kt(t),Ne(t),oo(t,l)):(Ne(t),t.flags&=-16777217):(e.memoizedProps!==a&&Kt(t),Ne(t),t.flags&=-16777217),null;case 27:Yn(t),l=ee.current;var n=t.type;if(e!==null&&t.stateNode!=null)e.memoizedProps!==a&&Kt(t);else{if(!a){if(t.stateNode===null)throw Error(f(166));return Ne(t),null}e=$.current,ka(t)?Gr(t):(e=dd(n,a,l),t.stateNode=e,Kt(t))}return Ne(t),null;case 5:if(Yn(t),l=t.type,e!==null&&t.stateNode!=null)e.memoizedProps!==a&&Kt(t);else{if(!a){if(t.stateNode===null)throw Error(f(166));return Ne(t),null}if(e=$.current,ka(t))Gr(t);else{switch(n=Xu(ee.current),e){case 1:e=n.createElementNS("http://www.w3.org/2000/svg",l);break;case 2:e=n.createElementNS("http://www.w3.org/1998/Math/MathML",l);break;default:switch(l){case"svg":e=n.createElementNS("http://www.w3.org/2000/svg",l);break;case"math":e=n.createElementNS("http://www.w3.org/1998/Math/MathML",l);break;case"script":e=n.createElement("div"),e.innerHTML=" - + ChargeFlow + +
diff --git a/dependencies.lock b/dependencies.lock index 61c6fcf..39c518b 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -1,4 +1,14 @@ dependencies: + espressif/cjson: + component_hash: 9372811fb197926f522c467627cf4a8e72b681e0366e17879631da801103aef3 + dependencies: + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.7.19 espressif/cmake_utilities: component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f dependencies: @@ -48,10 +58,11 @@ dependencies: type: idf version: 5.4.2 direct_dependencies: +- espressif/cjson - espressif/esp-modbus - espressif/mdns - espressif/ntc_driver - idf -manifest_hash: 914523e41b41de9584db65fbe408fdbefb25ae9417eadf249d129e6d77f28d4c +manifest_hash: 4c69c7075a4a2aadc2a98b11d389519cb8621b7522e40f4fa9021acee9d2d03f target: esp32 version: 2.0.0 diff --git a/main/idf_component.yml b/main/idf_component.yml index 496c495..bba7198 100755 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -1,7 +1,8 @@ ## IDF Component Manager Manifest File dependencies: - espressif/mdns: "=*" - espressif/ntc_driver: "^0.3.0" - espressif/esp-modbus: "=1.0.18" + espressif/mdns: =* + espressif/ntc_driver: ^0.3.0 + espressif/esp-modbus: =1.0.18 idf: - version: ">=5.1.0" + version: '>=5.1.0' + espressif/cjson: ^1.7.19 diff --git a/main/main.c b/main/main.c index 7c96879..74c315a 100755 --- a/main/main.c +++ b/main/main.c @@ -249,7 +249,6 @@ static void init_modules(void) { peripherals_init(); wifi_ini(); - // api_init(); buzzer_init(); ESP_ERROR_CHECK(rest_server_init("/data")); protocols_init(); diff --git a/projeto_parte1.c b/projeto_parte1.c deleted file mode 100644 index 6c77a03..0000000 --- a/projeto_parte1.c +++ /dev/null @@ -1,1328 +0,0 @@ -. - -// === Início de: main/main.c === -#include -#include -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/event_groups.h" - -#include "esp_log.h" -#include "esp_err.h" -#include "esp_event.h" -#include "esp_netif.h" -#include "esp_spiffs.h" -#include "esp_system.h" -#include "nvs_flash.h" -#include "driver/gpio.h" - -#include "network.h" -#include "board_config.h" -#include "logger.h" -#include "rest_main.h" - -#include "peripherals.h" -#include "protocols.h" -#include "evse_manager.h" -#include "evse_core.h" -#include "auth.h" -#include "loadbalancer.h" -#include "meter_manager.h" -#include "buzzer.h" -#include "evse_link.h" -#include "ocpp.h" - -#define EVSE_MANAGER_TICK_PERIOD_MS 1000 -#define AP_CONNECTION_TIMEOUT 120000 -#define RESET_HOLD_TIME 30000 -#define DEBOUNCE_TIME_MS 50 - -#define PRESS_BIT BIT0 -#define RELEASED_BIT BIT1 - -static const char *TAG = "app_main"; - -static TaskHandle_t user_input_task; -static TickType_t press_tick = 0; -static TickType_t last_interrupt_tick = 0; -static bool pressed = false; - -// -// File system (SPIFFS) init and info -// -static void fs_info(esp_vfs_spiffs_conf_t *conf) -{ - size_t total = 0, used = 0; - esp_err_t ret = esp_spiffs_info(conf->partition_label, &total, &used); - if (ret == ESP_OK) - ESP_LOGI(TAG, "Partition %s: total: %d, used: %d", conf->partition_label, total, used); - else - ESP_LOGE(TAG, "Failed to get SPIFFS info: %s", esp_err_to_name(ret)); -} - -static void fs_init(void) -{ - esp_vfs_spiffs_conf_t cfg_conf = { - .base_path = "/cfg", - .partition_label = "cfg", - .max_files = 1, - .format_if_mount_failed = false}; - - esp_vfs_spiffs_conf_t data_conf = { - .base_path = "/data", - .partition_label = "data", - .max_files = 5, - .format_if_mount_failed = true}; - - ESP_ERROR_CHECK(esp_vfs_spiffs_register(&cfg_conf)); - ESP_ERROR_CHECK(esp_vfs_spiffs_register(&data_conf)); - - fs_info(&cfg_conf); - fs_info(&data_conf); -} -// -// Wi-Fi event monitoring task -// -static void wifi_event_task_func(void *param) -{ - EventBits_t mode_bits; - for (;;) - { - // Wait indefinitely until either AP or STA mode is entered - mode_bits = xEventGroupWaitBits( - wifi_event_group, - WIFI_AP_MODE_BIT | WIFI_STA_MODE_BIT, - pdFALSE, // do not clear bits on exit - pdFALSE, // wait for any bit - portMAX_DELAY); - - if (mode_bits & WIFI_AP_MODE_BIT) - { - // We're in AP mode: wait for a client to connect within the timeout - if (xEventGroupWaitBits( - wifi_event_group, - WIFI_AP_CONNECTED_BIT, - pdFALSE, - pdFALSE, - pdMS_TO_TICKS(AP_CONNECTION_TIMEOUT)) & - WIFI_AP_CONNECTED_BIT) - { - // Once connected, block until the client disconnects - xEventGroupWaitBits( - wifi_event_group, - WIFI_AP_DISCONNECTED_BIT, - pdFALSE, - pdFALSE, - portMAX_DELAY); - } - else - { - // Timeout expired with no client—optionally stop the AP - if (xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT) - { - // wifi_ap_stop(); - } - } - } - else if (mode_bits & WIFI_STA_MODE_BIT) - { - // We're in STA mode: block until disconnected from the AP - xEventGroupWaitBits( - wifi_event_group, - WIFI_STA_DISCONNECTED_BIT, - pdFALSE, - pdFALSE, - portMAX_DELAY); - } - - // Prevent this task from hogging the CPU when idle - // vTaskDelay(pdMS_TO_TICKS(10)); - } -} - -// -// Button press handler -// -static void handle_button_press(void) -{ - // If not already in AP mode, start it - if (!(xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT)) - { - ESP_LOGI(TAG, "Starting Wi-Fi AP mode"); - wifi_ap_start(); - } -} - -// Task to handle button press/release notifications -static void user_input_task_func(void *param) -{ - uint32_t notification; - for (;;) - { - // Wait for notification bits from ISR - if (xTaskNotifyWait( - 0, // do not clear any bits on entry - UINT32_MAX, // clear all bits on exit - ¬ification, - portMAX_DELAY)) - { - // Handle button press event - if (notification & PRESS_BIT) - { - press_tick = xTaskGetTickCount(); - pressed = true; - ESP_LOGI(TAG, "Button Pressed"); - handle_button_press(); // só aqui - } - if ((notification & RELEASED_BIT) && pressed) - { - pressed = false; - TickType_t held = xTaskGetTickCount() - press_tick; - ESP_LOGI(TAG, "Button Released (held %u ms)", (unsigned)pdTICKS_TO_MS(held)); - if (held >= pdMS_TO_TICKS(RESET_HOLD_TIME)) - { - ESP_LOGW(TAG, "Long press: erasing NVS + reboot"); - nvs_flash_erase(); - esp_restart(); - } - } - } - } -} - -// ISR for button GPIO interrupt (active-low) -static void IRAM_ATTR button_isr_handler(void *arg) -{ - BaseType_t higher_task_woken = pdFALSE; - TickType_t now = xTaskGetTickCountFromISR(); - - // Debounce: ignore interrupts occurring too close together - if (now - last_interrupt_tick < pdMS_TO_TICKS(DEBOUNCE_TIME_MS)) - { - return; - } - last_interrupt_tick = now; - - // Read GPIO level: 0 = button pressed, 1 = button released - int level = gpio_get_level(board_config.button_wifi_gpio); - if (level == 0) - { - // Notify task: button pressed - xTaskNotifyFromISR( - user_input_task, - PRESS_BIT, - eSetBits, - &higher_task_woken); - } - else - { - // Notify task: button released - xTaskNotifyFromISR( - user_input_task, - RELEASED_BIT, - eSetBits, - &higher_task_woken); - } - - // Yield to higher priority task if unblocked - if (higher_task_woken) - { - portYIELD_FROM_ISR(); - } -} - -static void button_init(void) -{ - gpio_config_t conf = { - .pin_bit_mask = BIT64(board_config.button_wifi_gpio), - .mode = GPIO_MODE_INPUT, - .pull_down_en = GPIO_PULLDOWN_DISABLE, - .pull_up_en = GPIO_PULLUP_ENABLE, - .intr_type = GPIO_INTR_ANYEDGE}; - ESP_ERROR_CHECK(gpio_config(&conf)); - ESP_ERROR_CHECK(gpio_isr_handler_add(board_config.button_wifi_gpio, button_isr_handler, NULL)); -} - -// -// Inicialização dos módulos do sistema -// -static void init_modules(void) -{ - peripherals_init(); - wifi_ini(); - // api_init(); - buzzer_init(); - ESP_ERROR_CHECK(rest_server_init("/data")); - protocols_init(); - evse_manager_init(); - evse_init(); // Cria a task para FSM - button_init(); - auth_init(); - loadbalancer_init(); - meter_manager_init(); - meter_manager_start(); - evse_link_init(); - ocpp_start(); - - // wifi_ap_start(); - // Outros módulos (descomente conforme necessário) - // meter_init(); - // ocpp_start(); - // orno_modbus_start(); - // currentshaper_start(); - // initWiegand(); - // meter_zigbee_start(); - // master_sync_start(); - // slave_sync_start(); -} - -// -// Função principal do firmware -// -void app_main(void) -{ - logger_init(); - esp_log_set_vprintf(logger_vprintf); - - esp_reset_reason_t reason = esp_reset_reason(); - ESP_LOGI(TAG, "Reset reason: %d", reason); - - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) - { - ESP_LOGW(TAG, "Erasing NVS flash"); - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); - - fs_init(); - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - ESP_ERROR_CHECK(gpio_install_isr_service(0)); - - board_config_load(); - init_modules(); - - xTaskCreate(wifi_event_task_func, "wifi_event_task", 8 * 1024, NULL, 3, NULL); - xTaskCreate(user_input_task_func, "user_input_task", 4 * 1024, NULL, 3, &user_input_task); -} - -// === Fim de: main/main.c === - - -// === Início de: components/ocpp/src/ocpp_events.c === -#include "ocpp_events.h" - -/* Define a base, como em components/auth/src/auth_events.c */ -ESP_EVENT_DEFINE_BASE(OCPP_EVENTS); - -// === Fim de: components/ocpp/src/ocpp_events.c === - - -// === Início de: components/ocpp/src/ocpp.c === -// components/ocpp/src/ocpp.c -#include -#include -#include -#include - -#include "esp_log.h" -#include "esp_err.h" - -#include "ocpp.h" -#include "ocpp_events.h" - -#include "esp_wifi.h" -#include "nvs.h" -#include "nvs_flash.h" - -#include "evse_error.h" -#include "auth_events.h" -#include "evse_events.h" -#include "evse_state.h" -#include "meter_events.h" -#include "esp_timer.h" -#include - -/* MicroOcpp includes */ -#include -#include // C-facade of MicroOcpp -#include // WebSocket integration for ESP-IDF - -#define NVS_NAMESPACE "ocpp" -#define NVS_OCPP_ENABLED "enabled" -#define NVS_OCPP_SERVER "ocpp_server" -#define NVS_OCPP_CHARGE_ID "charge_id" - -static const char *TAG = "ocpp"; - -static bool enabled = false; - -static TaskHandle_t ocpp_task = NULL; - -static struct mg_mgr mgr; // Event manager -static OCPP_Connection *g_ocpp_conn = NULL; // Para shutdown limpo - -static esp_event_handler_instance_t s_auth_verify_inst = NULL; - -// Flags refletindo o estado do EVSE (atualizadas por eventos) -static volatile bool s_ev_plugged = false; -static volatile bool s_ev_ready = false; - -static esp_event_handler_instance_t s_evse_state_inst = NULL; - -// Flags de config (vindas de EVSE_EVENTS) -static volatile bool s_evse_enabled = true; -static volatile bool s_evse_available = true; - -static esp_event_handler_instance_t s_evse_enable_inst = NULL; -static esp_event_handler_instance_t s_evse_available_inst = NULL; - -// --- cache de medições vindas de METER_EVENT_DATA_READY --- -typedef struct -{ - // dados por fase - float vrms[3]; - float irms[3]; - int32_t watt[3]; // ativo por fase (W) - float frequency; - float power_factor; - // acumulados - float total_energy_kWh; - // derivados práticos - int32_t sum_watt; // soma das 3 fases - float avg_voltage; // média das 3 fases - float sum_current; // soma das 3 fases - // flag de validade - bool have_data; -} ocpp_meter_cache_t; - -static ocpp_meter_cache_t s_meter = {0}; -static portMUX_TYPE s_meter_mux = portMUX_INITIALIZER_UNLOCKED; -static esp_event_handler_instance_t s_meter_inst = NULL; - -/* ========================= - * Task / Main Loop - * ========================= * - */ -static void ocpp_task_func(void *param) -{ - while (true) - { - if (enabled) - { - mg_mgr_poll(&mgr, 100); - ocpp_loop(); - - bool operative = ocpp_isOperative(); - if (operative != s_evse_enabled) - { - s_evse_enabled = operative; - - // >>> enviar OCPP_EVENT (remoto → local) - ocpp_operative_event_t ev = { - .operative = operative, - .timestamp_us = esp_timer_get_time()}; - esp_event_post(OCPP_EVENTS, - OCPP_EVENT_OPERATIVE_UPDATED, - &ev, sizeof(ev), - portMAX_DELAY); - - ESP_LOGI(TAG, "[OCPP] ChangeAvailability remoto → operative=%d", - (int)operative); - } - } - else - { - vTaskDelay(pdMS_TO_TICKS(500)); - } - } -} - -/* ========================= - * NVS GETs - * ========================= */ -bool ocpp_get_enabled(void) -{ - nvs_handle_t h; - esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &h); - if (err == ESP_ERR_NVS_NOT_FOUND) - { - // namespace ainda não existe -> default: disabled - return false; - } - if (err != ESP_OK) - { - ESP_LOGW(TAG, "nvs_open(%s) RO failed: %s", NVS_NAMESPACE, esp_err_to_name(err)); - return false; - } - - uint8_t value = 0; - err = nvs_get_u8(h, NVS_OCPP_ENABLED, &value); - nvs_close(h); - - if (err == ESP_ERR_NVS_NOT_FOUND) - return false; // default - if (err != ESP_OK) - { - ESP_LOGW(TAG, "nvs_get_u8(enabled) failed: %s", esp_err_to_name(err)); - return false; - } - return value != 0; -} - -void ocpp_get_server(char *value /* out, size>=64 */) -{ - if (!value) - return; - value[0] = '\0'; - - nvs_handle_t h; - esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &h); - if (err == ESP_ERR_NVS_NOT_FOUND) - { - // namespace ainda não existe -> default: "" - return; - } - if (err != ESP_OK) - { - ESP_LOGW(TAG, "nvs_open(%s) RO failed: %s", NVS_NAMESPACE, esp_err_to_name(err)); - return; - } - - size_t len = 64; - err = nvs_get_str(h, NVS_OCPP_SERVER, value, &len); - nvs_close(h); - - if (err == ESP_ERR_NVS_NOT_FOUND) - { - value[0] = '\0'; - return; - } - if (err != ESP_OK) - { - ESP_LOGW(TAG, "nvs_get_str(server) failed: %s", esp_err_to_name(err)); - value[0] = '\0'; - } -} - -void ocpp_get_charge_id(char *value /* out, size>=64 */) -{ - if (!value) - return; - value[0] = '\0'; - - nvs_handle_t h; - esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &h); - if (err == ESP_ERR_NVS_NOT_FOUND) - { - // namespace ainda não existe -> default: "" - return; - } - if (err != ESP_OK) - { - ESP_LOGW(TAG, "nvs_open(%s) RO failed: %s", NVS_NAMESPACE, esp_err_to_name(err)); - return; - } - - size_t len = 64; - err = nvs_get_str(h, NVS_OCPP_CHARGE_ID, value, &len); - nvs_close(h); - - if (err == ESP_ERR_NVS_NOT_FOUND) - { - value[0] = '\0'; - return; - } - if (err != ESP_OK) - { - ESP_LOGW(TAG, "nvs_get_str(charge_id) failed: %s", esp_err_to_name(err)); - value[0] = '\0'; - } -} - -/* ========================= - * NVS SETs - * ========================= */ -// --- SETTERS: RW (cria o namespace na 1ª escrita), commit e fecha --- -void ocpp_set_enabled(bool value) -{ - nvs_handle_t h; - esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &h); - if (err != ESP_OK) - { - ESP_LOGE(TAG, "nvs_open(%s) RW failed: %s", NVS_NAMESPACE, esp_err_to_name(err)); - return; - } - ESP_LOGI(TAG, "set enabled %d", value); - ESP_ERROR_CHECK(nvs_set_u8(h, NVS_OCPP_ENABLED, value ? 1 : 0)); - ESP_ERROR_CHECK(nvs_commit(h)); - nvs_close(h); - enabled = value; -} - -void ocpp_set_server(char *value) -{ - nvs_handle_t h; - esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &h); - if (err != ESP_OK) - { - ESP_LOGE(TAG, "nvs_open(%s) RW failed: %s", NVS_NAMESPACE, esp_err_to_name(err)); - return; - } - ESP_LOGI(TAG, "set server %s", value ? value : "(null)"); - ESP_ERROR_CHECK(nvs_set_str(h, NVS_OCPP_SERVER, value ? value : "")); - ESP_ERROR_CHECK(nvs_commit(h)); - nvs_close(h); -} - -void ocpp_set_charge_id(char *value) -{ - nvs_handle_t h; - esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &h); - if (err != ESP_OK) - { - ESP_LOGE(TAG, "nvs_open(%s) RW failed: %s", NVS_NAMESPACE, esp_err_to_name(err)); - return; - } - ESP_LOGI(TAG, "set charge_id %s", value ? value : "(null)"); - ESP_ERROR_CHECK(nvs_set_str(h, NVS_OCPP_CHARGE_ID, value ? value : "")); - ESP_ERROR_CHECK(nvs_commit(h)); - nvs_close(h); -} - -static void ocpp_on_auth_verify(void *arg, esp_event_base_t base, int32_t id, void *event_data) -{ - const auth_tag_verify_event_t *rq = (const auth_tag_verify_event_t *)event_data; - if (!rq) - return; - - // Sanitizar/copiar a idTag - char idtag[AUTH_TAG_MAX_LEN]; - if (rq->tag[0] == '\0') - { - strncpy(idtag, "IDTAG", sizeof(idtag)); - idtag[sizeof(idtag) - 1] = '\0'; - } - else - { - strncpy(idtag, rq->tag, sizeof(idtag) - 1); - idtag[sizeof(idtag) - 1] = '\0'; - } - - ESP_LOGI(TAG, "AUTH_EVENT_TAG_VERIFY: tag=%s req_id=%u", idtag, (unsigned)rq->req_id); - - // Se não está pronto, apenas regista e sai (podes adaptar conforme política) - if (!enabled || g_ocpp_conn == NULL) - { - ESP_LOGW(TAG, "OCPP not ready (enabled=%d, conn=%p) – ignoring verify", enabled, (void *)g_ocpp_conn); - return; - } - - // Regra pedida: - // - se já existe transação/charge em andamento -> terminar - // - senão -> iniciar com a IDTAG recebida - if (ocpp_isTransactionActive()) - { - ESP_LOGI(TAG, "Transaction active -> ocpp_end_transaction(\"%s\")", idtag); - ocpp_endTransaction(idtag, "Local"); - } - else - { - ESP_LOGI(TAG, "No active transaction -> ocpp_begin_transaction(\"%s\")", idtag); - ocpp_beginTransaction(idtag); - } -} - -static void evse_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data) -{ - if (base != EVSE_EVENTS || id != EVSE_EVENT_STATE_CHANGED || data == NULL) - return; - - const evse_state_event_data_t *evt = (const evse_state_event_data_t *)data; - ESP_LOGI(TAG, "EVSE event received: state = %d", (int)evt->state); - - switch (evt->state) - { - case EVSE_STATE_EVENT_IDLE: - s_ev_plugged = false; - s_ev_ready = false; - break; - - case EVSE_STATE_EVENT_WAITING: - s_ev_plugged = true; - s_ev_ready = false; - break; - - case EVSE_STATE_EVENT_CHARGING: - s_ev_plugged = true; - s_ev_ready = true; // EV está a pedir/receber energia - break; - - case EVSE_STATE_EVENT_FAULT: - default: - // em falha, considera não pronto (mantém plugged se quiseres) - s_ev_ready = false; - break; - } -} - -static void evse_enable_available_handler(void *arg, esp_event_base_t base, int32_t id, void *data) -{ - if (base != EVSE_EVENTS || data == NULL) - return; - - if (id == EVSE_EVENT_ENABLE_UPDATED) - { - const evse_enable_event_data_t *e = (const evse_enable_event_data_t *)data; - s_evse_enabled = e->enabled; - ESP_LOGI(TAG, "[EVSE] ENABLE_UPDATED: enabled=%d (ts=%lld)", (int)e->enabled, (long long)e->timestamp_us); - return; - } - - if (id == EVSE_EVENT_AVAILABLE_UPDATED) - { - const evse_available_event_data_t *e = (const evse_available_event_data_t *)data; - s_evse_available = e->available; - ESP_LOGI(TAG, "[EVSE] AVAILABLE_UPDATED: available=%d (ts=%lld)", (int)e->available, (long long)e->timestamp_us); - return; - } -} - -static void on_meter_event(void *arg, esp_event_base_t base, int32_t id, void *data) -{ - if (base != METER_EVENT || id != METER_EVENT_DATA_READY || !data) - return; - - const meter_event_data_t *evt = (const meter_event_data_t *)data; - - // Só queremos o medidor do EVSE (não o GRID) - if (!evt->source || strcmp(evt->source, "EVSE") != 0) - return; - - // Derivados simples - int32_t sum_w = (int32_t)evt->watt[0] + (int32_t)evt->watt[1] + (int32_t)evt->watt[2]; - float avg_v = (evt->vrms[0] + evt->vrms[1] + evt->vrms[2]) / 3.0f; - float sum_i = evt->irms[0] + evt->irms[1] + evt->irms[2]; - - portENTER_CRITICAL(&s_meter_mux); - memcpy(s_meter.vrms, evt->vrms, sizeof(s_meter.vrms)); - memcpy(s_meter.irms, evt->irms, sizeof(s_meter.irms)); - s_meter.watt[0] = evt->watt[0]; - s_meter.watt[1] = evt->watt[1]; - s_meter.watt[2] = evt->watt[2]; - s_meter.frequency = evt->frequency; - s_meter.power_factor = evt->power_factor; - s_meter.total_energy_kWh = evt->total_energy; // já vem em kWh segundo o teu .h - s_meter.sum_watt = sum_w; - s_meter.avg_voltage = avg_v; - s_meter.sum_current = sum_i; - s_meter.have_data = true; - portEXIT_CRITICAL(&s_meter_mux); -} - -/* ========================= - * MicroOCPP Inputs/CBs - * ========================= */ -bool setConnectorPluggedInput(void) -{ - return s_ev_plugged; // EV fisicamente ligado -} - -bool setEvReadyInput(void) -{ - return s_ev_ready; // EV pede / pronto a carregar -} - -bool setEvseReadyInput(void) -{ - // EVSE autorizado / operacional - return s_evse_enabled && s_evse_available; -} - -float setPowerMeterInput(void) -{ - int32_t w = 0; - bool have = false; - - portENTER_CRITICAL(&s_meter_mux); - have = s_meter.have_data; - if (have) - w = s_meter.sum_watt; - portEXIT_CRITICAL(&s_meter_mux); - - if (!have) - { - ESP_LOGW(TAG, "[METER] PowerMeterInput: no data (return 0)"); - } - else - { - ESP_LOGD(TAG, "[METER] PowerMeterInput: %" PRId32 " W", w); - } - return (float)w; -} - -float setEnergyMeterInput(void) -{ - float kwh = 0.0f; - bool have = false; - - portENTER_CRITICAL(&s_meter_mux); - have = s_meter.have_data; - if (have) - kwh = s_meter.total_energy_kWh; - portEXIT_CRITICAL(&s_meter_mux); - - float wh = kwh * 1000.0f; - - if (!have) - { - ESP_LOGW(TAG, "[METER] EnergyMeterInput: no data (return 0)"); - } - else - { - ESP_LOGD(TAG, "[METER] EnergyMeterInput: %.3f kWh (%.1f Wh)", kwh, wh); - } - return wh; // agora devolve Wh -} - -int setEnergyInput(void) -{ - float energy_kWh = setEnergyMeterInput(); // kWh - int wh = (int)lrintf((double)energy_kWh * 1000.0); // Wh arredondado - ESP_LOGD(TAG, "[METER] EnergyInput: %.3f kWh -> %d Wh", energy_kWh, wh); - return wh; -} - -float setCurrentInput(void) -{ - float a = 0.0f; - bool have = false; - - portENTER_CRITICAL(&s_meter_mux); - have = s_meter.have_data; - if (have) - a = s_meter.sum_current; - portEXIT_CRITICAL(&s_meter_mux); - - if (!have) - { - ESP_LOGW(TAG, "[METER] CurrentInput: no data (return 0)"); - } - else - { - ESP_LOGD(TAG, "[METER] CurrentInput: %.2f A (total)", a); - } - return a; -} - -float setVoltageInput(void) -{ - float v = 0.0f; - bool have = false; - - portENTER_CRITICAL(&s_meter_mux); - have = s_meter.have_data; - if (have) - v = s_meter.avg_voltage; - portEXIT_CRITICAL(&s_meter_mux); - - if (!have) - { - ESP_LOGW(TAG, "[METER] VoltageInput: no data (return 0)"); - } - else - { - ESP_LOGD(TAG, "[METER] VoltageInput: %.1f V (avg)", v); - } - return v; -} - -float setPowerInput(void) -{ - float w = setPowerMeterInput(); // alias - ESP_LOGD(TAG, "[METER] PowerInput: %.1f W", w); - return w; -} - -float setTemperatureInput(void) -{ - ESP_LOGD(TAG, "TemperatureInput"); - return 16.5f; -} - -void setSmartChargingCurrentOutput(float limit) -{ - ESP_LOGI(TAG, "SmartChargingCurrentOutput: %.0f", limit); -} - -void setSmartChargingPowerOutput(float limit) -{ - ESP_LOGI(TAG, "SmartChargingPowerOutput: %.0f", limit); -} - -void setSmartChargingOutput(float power, float current, int nphases) -{ - ESP_LOGI(TAG, "SmartChargingOutput: P=%.0f W, I=%.0f A, phases=%d", power, current, nphases); -} - -void setGetConfiguration(const char *payload, size_t len) -{ - ESP_LOGI(TAG, "GetConfiguration: %.*s (%u)", (int)len, payload, (unsigned)len); -} - -void setStartTransaction(const char *payload, size_t len) -{ - ESP_LOGI(TAG, "StartTransaction: %.*s (%u)", (int)len, payload, (unsigned)len); -} - -void setChangeConfiguration(const char *payload, size_t len) -{ - ESP_LOGI(TAG, "ChangeConfiguration: %.*s (%u)", (int)len, payload, (unsigned)len); -} - -void OnResetExecute(bool state) -{ - ESP_LOGI(TAG, "OnResetExecute (state=%d)", state); - esp_restart(); -} - -bool setOccupiedInput(void) -{ - ESP_LOGD(TAG, "setOccupiedInput"); - return false; -} - -bool setStartTxReadyInput(void) -{ - ESP_LOGD(TAG, "setStartTxReadyInput"); - return true; -} - -bool setStopTxReadyInput(void) -{ - ESP_LOGD(TAG, "setStopTxReadyInput"); - return true; -} - -bool setOnResetNotify(bool value) -{ - ESP_LOGI(TAG, "setOnResetNotify %d", value); - return true; -} - -void notificationOutput(OCPP_Transaction *transaction, enum OCPP_TxNotification txNotification) -{ - ESP_LOGI(TAG, "TxNotification: %d", txNotification); - - switch (txNotification) - { - case Authorized: - ESP_LOGI(TAG, "Authorized"); - // TODO: send event ocpp Authorized - // evse_authorize(); - - // Opcional: enviar idTag no payload (se tiveres como obter do transaction) - // ocpp_idtag_event_t ev = {0}; - // strlcpy(ev.idTag, ocpp_tx_get_idTag(transaction), sizeof(ev.idTag)); - // esp_event_post(OCPP_EVENTS, OCPP_EVENT_AUTHORIZED, &ev, sizeof(ev), portMAX_DELAY); - - esp_event_post(OCPP_EVENTS, OCPP_EVENT_AUTHORIZED, NULL, 0, portMAX_DELAY); - break; - - case AuthorizationRejected: - ESP_LOGI(TAG, "AuthorizationRejected"); - // TODO: send event ocpp AuthorizationRejected - - // ocpp_idtag_event_t ev = {0}; - // strlcpy(ev.idTag, ocpp_tx_get_idTag(transaction), sizeof(ev.idTag)); - // esp_event_post(OCPP_EVENTS, OCPP_EVENT_AUTH_REJECTED, &ev, sizeof(ev), portMAX_DELAY); - - esp_event_post(OCPP_EVENTS, OCPP_EVENT_AUTH_REJECTED, NULL, 0, portMAX_DELAY); - break; - - case AuthorizationTimeout: - ESP_LOGI(TAG, "AuthorizationTimeout"); - // TODO: send event ocpp AuthorizationTimeout - esp_event_post(OCPP_EVENTS, OCPP_EVENT_AUTH_TIMEOUT, NULL, 0, portMAX_DELAY); - break; - - case ReservationConflict: - ESP_LOGI(TAG, "ReservationConflict"); - // TODO: send event ocpp ReservationConflict - // (Se quiseres, cria um ID específico no enum e publica aqui) - break; - - case ConnectionTimeout: - ESP_LOGI(TAG, "ConnectionTimeout"); - // TODO: send event ocpp ConnectionTimeout - // (Se quiseres, cria um ID específico no enum e publica aqui) - break; - - case DeAuthorized: - ESP_LOGI(TAG, "DeAuthorized"); - // TODO: send event ocpp DeAuthorized - // TODO: adapt to the new interface - // evse_set_authorized(false); - // evse_set_limit_reached(2); - - // Poderias mapear para AUTH_REJECTED ou STOP_TX por política da aplicação: - // esp_event_post(OCPP_EVENTS, OCPP_EVENT_AUTH_REJECTED, NULL, 0, portMAX_DELAY); - break; - - case RemoteStart: - ESP_LOGI(TAG, "RemoteStart"); - // TODO: send event ocpp RemoteStart - - // ocpp_idtag_event_t ev = {0}; - // strlcpy(ev.idTag, ocpp_tx_get_idTag(transaction), sizeof(ev.idTag)); - // esp_event_post(OCPP_EVENTS, OCPP_EVENT_REMOTE_START, &ev, sizeof(ev), portMAX_DELAY); - - esp_event_post(OCPP_EVENTS, OCPP_EVENT_REMOTE_START, NULL, 0, portMAX_DELAY); - break; - - case RemoteStop: - ESP_LOGI(TAG, "RemoteStop"); - // TODO: send event ocpp RemoteStop - esp_event_post(OCPP_EVENTS, OCPP_EVENT_REMOTE_STOP, NULL, 0, portMAX_DELAY); - break; - - case StartTx: - ESP_LOGI(TAG, "StartTx"); - // TODO: send event ocpp StartTx - - // ocpp_tx_event_t tx = { .tx_id = ocpp_tx_get_id(transaction) }; - // esp_event_post(OCPP_EVENTS, OCPP_EVENT_START_TX, &tx, sizeof(tx), portMAX_DELAY); - - esp_event_post(OCPP_EVENTS, OCPP_EVENT_START_TX, NULL, 0, portMAX_DELAY); - break; - - case StopTx: - ESP_LOGI(TAG, "StopTx"); - // TODO: send event ocpp StopTx - // TODO: adapt to the new interface - // evse_set_authorized(false); - // evse_set_limit_reached(2); - - // ocpp_reason_event_t rs = {0}; - // strlcpy(rs.reason, "Local", sizeof(rs.reason)); - // esp_event_post(OCPP_EVENTS, OCPP_EVENT_STOP_TX, &rs, sizeof(rs), portMAX_DELAY); - - esp_event_post(OCPP_EVENTS, OCPP_EVENT_STOP_TX, NULL, 0, portMAX_DELAY); - break; - } -} - -// Estado de conexão simples do OCPP -bool ocpp_is_connected(void) -{ - // Se quiser algo mais preciso (WS aberto), substitui por uma chamada da MicroOcpp, - // mas como fallback isto já evita o undefined symbol. - return g_ocpp_conn != NULL; -} - -const char *addErrorCodeInput(void) -{ - const char *ptr = NULL; - uint32_t error = evse_get_error(); - - if (error & EVSE_ERR_PILOT_FAULT_BIT) - ptr = "InternalError"; - else if (error & EVSE_ERR_DIODE_SHORT_BIT) - ptr = "InternalError"; - else if (error & EVSE_ERR_LOCK_FAULT_BIT) - ptr = "ConnectorLockFailure"; - else if (error & EVSE_ERR_UNLOCK_FAULT_BIT) - ptr = "ConnectorLockFailure"; - else if (error & EVSE_ERR_RCM_TRIGGERED_BIT) - ptr = "OtherError"; - else if (error & EVSE_ERR_RCM_SELFTEST_FAULT_BIT) - ptr = "OtherError"; - else if (error & EVSE_ERR_TEMPERATURE_HIGH_BIT) - ptr = "HighTemperature"; - else if (error & EVSE_ERR_TEMPERATURE_FAULT_BIT) - ptr = "OtherError"; - - return ptr; // NULL => sem erro -} - -/* ========================= - * Start / Stop OCPP - * ========================= */ -void ocpp_start(void) -{ - ESP_LOGI(TAG, "Starting OCPP"); - - if (ocpp_task != NULL) - { - ESP_LOGW(TAG, "OCPP already running"); - return; - } - - enabled = ocpp_get_enabled(); - if (!enabled) - { - ESP_LOGW(TAG, "OCPP disabled"); - return; - } - - char serverstr[64] = {0}; - ocpp_get_server(serverstr); - if (serverstr[0] == '\0') - { - ESP_LOGW(TAG, "No OCPP server configured. Skipping connection."); - return; - } - - char charge_id[64] = {0}; - ocpp_get_charge_id(charge_id); - if (charge_id[0] == '\0') - { - ESP_LOGW(TAG, "No OCPP charge_id configured. Skipping connection."); - return; - } - - /* Inicializar Mongoose + MicroOcpp */ - mg_mgr_init(&mgr); - mg_log_set(MG_LL_ERROR); - - struct OCPP_FilesystemOpt fsopt = {.use = true, .mount = true, .formatFsOnFail = true}; - - g_ocpp_conn = ocpp_makeConnection(&mgr, - serverstr, /* ex: ws://host:port/OCPP16/... */ - charge_id, /* ChargeBoxId / identity */ - "", - "", - fsopt); - if (!g_ocpp_conn) - { - ESP_LOGE(TAG, "ocpp_makeConnection failed"); - mg_mgr_free(&mgr); - return; - } - - ocpp_initialize(g_ocpp_conn, "EPower M1", "Plixin", fsopt, false); - - /* Inputs/outputs e callbacks */ - ocpp_setEvReadyInput(&setEvReadyInput); - ocpp_setEvseReadyInput(&setEvseReadyInput); - ocpp_setConnectorPluggedInput(&setConnectorPluggedInput); - ocpp_setOnResetExecute(&OnResetExecute); - ocpp_setTxNotificationOutput(¬ificationOutput); - // ocpp_setStartTxReadyInput(&setStartTxReadyInput); - ocpp_setStopTxReadyInput(&setStopTxReadyInput); - ocpp_setOnResetNotify(&setOnResetNotify); - - ocpp_setEnergyMeterInput(&setEnergyInput); // inteiro Wh - - /* Metering */ - ocpp_addMeterValueInputFloat(&setCurrentInput, "Current.Import", "A", NULL, NULL); - ocpp_addMeterValueInputFloat(&setCurrentInput, "Current.Offered", "A", NULL, NULL); - ocpp_addMeterValueInputFloat(&setVoltageInput, "Voltage", "V", NULL, NULL); - ocpp_addMeterValueInputFloat(&setTemperatureInput, "Temperature", "Celsius", NULL, NULL); - ocpp_addMeterValueInputFloat(&setPowerMeterInput, "Power.Active.Import", "W", NULL, NULL); - ocpp_addMeterValueInputFloat(&setEnergyMeterInput, "Energy.Active.Import.Register", "Wh", NULL, NULL); - - ocpp_addErrorCodeInput(&addErrorCodeInput); - - /* Task */ - xTaskCreate(ocpp_task_func, "ocpp_task", 5 * 1024, NULL, 5, &ocpp_task); - - if (!s_auth_verify_inst) - { - ESP_ERROR_CHECK(esp_event_handler_instance_register( - AUTH_EVENTS, AUTH_EVENT_TAG_VERIFY, - &ocpp_on_auth_verify, NULL, &s_auth_verify_inst)); - ESP_LOGI(TAG, "Registered AUTH_EVENT_TAG_VERIFY listener"); - } - - // ouvir mudanças de estado do EVSE - if (!s_evse_state_inst) - { - ESP_ERROR_CHECK(esp_event_handler_instance_register( - EVSE_EVENTS, EVSE_EVENT_STATE_CHANGED, - &evse_event_handler, NULL, &s_evse_state_inst)); - } - - // ouvir mudanças de ENABLE / AVAILABLE do EVSE (Local → OCPP) - if (!s_evse_enable_inst) - { - ESP_ERROR_CHECK(esp_event_handler_instance_register( - EVSE_EVENTS, EVSE_EVENT_ENABLE_UPDATED, - &evse_enable_available_handler, NULL, &s_evse_enable_inst)); - } - if (!s_evse_available_inst) - { - ESP_ERROR_CHECK(esp_event_handler_instance_register( - EVSE_EVENTS, EVSE_EVENT_AVAILABLE_UPDATED, - &evse_enable_available_handler, NULL, &s_evse_available_inst)); - } - - if (!s_meter_inst) - { - ESP_ERROR_CHECK(esp_event_handler_instance_register( - METER_EVENT, METER_EVENT_DATA_READY, - &on_meter_event, NULL, &s_meter_inst)); - ESP_LOGI(TAG, "Registered METER_EVENT_DATA_READY listener (EVSE source)"); - } -} - -void ocpp_stop(void) -{ - ESP_LOGI(TAG, "Stopping OCPP"); - - if (ocpp_task) - { - vTaskDelete(ocpp_task); - ocpp_task = NULL; - } - - ocpp_deinitialize(); - - if (g_ocpp_conn) - { - ocpp_deinitConnection(g_ocpp_conn); - g_ocpp_conn = NULL; - } - - mg_mgr_free(&mgr); - - if (s_auth_verify_inst) - { - ESP_ERROR_CHECK(esp_event_handler_instance_unregister( - AUTH_EVENTS, AUTH_EVENT_TAG_VERIFY, s_auth_verify_inst)); - s_auth_verify_inst = NULL; - } - - if (s_evse_state_inst) - { - ESP_ERROR_CHECK(esp_event_handler_instance_unregister( - EVSE_EVENTS, EVSE_EVENT_STATE_CHANGED, s_evse_state_inst)); - s_evse_state_inst = NULL; - } - - if (s_evse_enable_inst) - { - ESP_ERROR_CHECK(esp_event_handler_instance_unregister( - EVSE_EVENTS, EVSE_EVENT_ENABLE_UPDATED, s_evse_enable_inst)); - s_evse_enable_inst = NULL; - } - if (s_evse_available_inst) - { - ESP_ERROR_CHECK(esp_event_handler_instance_unregister( - EVSE_EVENTS, EVSE_EVENT_AVAILABLE_UPDATED, s_evse_available_inst)); - s_evse_available_inst = NULL; - } - if (s_meter_inst) - { - ESP_ERROR_CHECK(esp_event_handler_instance_unregister( - METER_EVENT, METER_EVENT_DATA_READY, s_meter_inst)); - s_meter_inst = NULL; - } -} - -// === Fim de: components/ocpp/src/ocpp.c === - - -// === Início de: components/ocpp/include/ocpp_events.h === -#pragma once -#include "esp_event.h" -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Base de eventos do OCPP (igual ao padrão usado em auth_events.h) */ -ESP_EVENT_DECLARE_BASE(OCPP_EVENTS); - -/* IDs de eventos do OCPP */ -typedef enum { - OCPP_EVENT_CONNECTED = 0, // payload: const char* (server URL) – opcional - OCPP_EVENT_DISCONNECTED, // payload: NULL - OCPP_EVENT_AUTHORIZED, // payload: ocpp_idtag_event_t (opcional) - OCPP_EVENT_AUTH_REJECTED, // payload: ocpp_idtag_event_t (opcional) - OCPP_EVENT_AUTH_TIMEOUT, // payload: NULL - OCPP_EVENT_REMOTE_START, // payload: ocpp_idtag_event_t (opcional) - OCPP_EVENT_REMOTE_STOP, // payload: NULL - OCPP_EVENT_START_TX, // payload: ocpp_tx_event_t (opcional) - OCPP_EVENT_STOP_TX, // payload: ocpp_reason_event_t (opcional) - OCPP_EVENT_RESET, // payload: NULL - OCPP_EVENT_OPERATIVE_UPDATED -} ocpp_event_id_t; - -/* Limites de strings simples (evita dependência de auth.h) */ -#define OCPP_IDTAG_MAX 32 -#define OCPP_REASON_MAX 32 - -/* Payloads opcionais */ -typedef struct { - char idTag[OCPP_IDTAG_MAX]; -} ocpp_idtag_event_t; - -typedef struct { - int tx_id; // se disponível -} ocpp_tx_event_t; - -typedef struct { - char reason[OCPP_REASON_MAX]; -} ocpp_reason_event_t; - -// Payload do novo evento -typedef struct { - bool operative; // true = Operative, false = Inoperative - int64_t timestamp_us; // esp_timer_get_time() -} ocpp_operative_event_t; - -#ifdef __cplusplus -} -#endif - -// === Fim de: components/ocpp/include/ocpp_events.h === - - -// === Início de: components/ocpp/include/ocpp.h === -#ifndef OCPP_H_ -#define OCPP_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Start OCPP - */ -void ocpp_start(void); - -/** - * @brief Stop OCPP - */ -void ocpp_stop(void); - -/* Config getters / setters */ -bool ocpp_get_enabled(void); -void ocpp_set_enabled(bool value); - -void ocpp_get_server(char *value); // buffer >= 64 -void ocpp_set_server(char *value); - -void ocpp_get_charge_id(char *value); // buffer >= 64 -void ocpp_set_charge_id(char *value); - -/* Estado de conexão */ -bool ocpp_is_connected(void); - -#ifdef __cplusplus -} -#endif - -#endif /* OCPP_H_ */ - -// === Fim de: components/ocpp/include/ocpp.h === diff --git a/readproject.py b/readproject.py index de4b371..800959e 100644 --- a/readproject.py +++ b/readproject.py @@ -1,6 +1,6 @@ import os -TAMANHO_MAX = 150000 # Limite por arquivo +TAMANHO_MAX = 100000 # Limite por arquivo def coletar_arquivos(diretorios, extensoes=(".c", ".h")): arquivos = [] @@ -53,7 +53,7 @@ def unir_em_partes(arquivos, prefixo="projeto_parte", limite=TAMANHO_MAX): def main(): diretorio_main = "main" componentes_escolhidos = [ - "ocpp" + "evse", "loadbalancer" ] diretorios_componentes = [os.path.join("components", nome) for nome in componentes_escolhidos]