diff options
Diffstat (limited to 'fw')
-rw-r--r-- | fw/app/CMakeLists.txt | 1 | ||||
-rw-r--r-- | fw/app/prj.conf | 15 | ||||
-rw-r--r-- | fw/app/src/http.c | 45 | ||||
-rw-r--r-- | fw/app/src/settings.c | 79 | ||||
-rw-r--r-- | fw/app/src/settings.h | 31 | ||||
-rw-r--r-- | fw/app/src/syslog.c | 79 |
6 files changed, 248 insertions, 2 deletions
diff --git a/fw/app/CMakeLists.txt b/fw/app/CMakeLists.txt index 1a63b77..de1c418 100644 --- a/fw/app/CMakeLists.txt +++ b/fw/app/CMakeLists.txt @@ -19,6 +19,7 @@ target_sources(app "${CMAKE_CURRENT_SOURCE_DIR}/src/http.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/ws.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/heart.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/settings.c" ) target_sources_ifdef( diff --git a/fw/app/prj.conf b/fw/app/prj.conf index eeb97a8..6589ec0 100644 --- a/fw/app/prj.conf +++ b/fw/app/prj.conf @@ -21,7 +21,6 @@ CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=4 CONFIG_LOG=y CONFIG_LOG_BACKEND_NET=y -CONFIG_LOG_BACKEND_NET_SERVER="[2001:db8::2]:514" CONFIG_LOG_BACKEND_NET_AUTOSTART=n CONFIG_LOG_MODE_DEFERRED=y @@ -44,5 +43,19 @@ CONFIG_ZBUS=y CONFIG_ZBUS_MSG_SUBSCRIBER=y CONFIG_HEAP_MEM_POOL_SIZE=2048 +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y + +CONFIG_NVS=y +CONFIG_NVS_DATA_CRC=y + CONFIG_SETTINGS=y +CONFIG_SETTINGS_RUNTIME=y +CONFIG_SETTINGS_NVS=y CONFIG_SETTINGS_SHELL=y + +CONFIG_GNU_C_EXTENSIONS=y + +CONFIG_JSON_LIBRARY=y diff --git a/fw/app/src/http.c b/fw/app/src/http.c index 08b59c1..1c24490 100644 --- a/fw/app/src/http.c +++ b/fw/app/src/http.c @@ -5,6 +5,7 @@ */ +#include <errno.h> #include <stdint.h> #include <zephyr/init.h> @@ -13,6 +14,7 @@ #include <zephyr/net/http/service.h> #include <zephyr/net/http/status.h> +#include "settings.h" #include "ws.h" @@ -91,6 +93,48 @@ static struct http_resource_detail_dynamic favicon_resource_detail = { .user_data = NULL, }; +static int settings_handler( + struct http_client_ctx *client, + enum http_data_status status, + const struct http_request_ctx *request_ctx, + struct http_response_ctx *response_ctx, + void *user_data +) { + static char buffer[100]; + + int ret = settings_to_json(buffer, sizeof(buffer) - 1); + if (ret < 0) { + LOG_ERR("Could not serialize payload for settings request"); + return ret; + } + + size_t len = strnlen(buffer, sizeof(buffer)); + if (len + 2 > sizeof(buffer)) { + LOG_ERR("Settings JSON requires %d octets but buffer has only %d", + len + 2, sizeof(buffer)); + return -ENOMEM; + } + + buffer[len] = '\n'; + buffer[len + 1] = '\0'; + + response_ctx->body = (const uint8_t *)buffer; + response_ctx->body_len = len + 1; + response_ctx->final_chunk = true; + response_ctx->status = HTTP_200_OK; + + return 0; +} + +static struct http_resource_detail_dynamic settings_resource_detail = { + .common = { + .type = HTTP_RESOURCE_TYPE_DYNAMIC, + .bitmask_of_supported_http_methods = BIT(HTTP_GET), + }, + .cb = settings_handler, + .user_data = NULL, +}; + static uint8_t websocket_read_buffer[1024]; struct http_resource_detail_websocket websocket_resource_detail = { @@ -112,6 +156,7 @@ HTTP_RESOURCE_DEFINE(websocket_resource, http_service, "/", &websocket_resource_ HTTP_RESOURCE_DEFINE(favicon_resource, http_service, "/favicon.ico", &favicon_resource_detail); HTTP_RESOURCE_DEFINE(css_resource, http_service, "/simple.css", &css_resource_detail); HTTP_RESOURCE_DEFINE(js_resource, http_service, "/iot-contact.js", &js_resource_detail); +HTTP_RESOURCE_DEFINE(settings_resource, http_service, "/settings.json", &settings_resource_detail); int init_http_server(void) { LOG_DBG("Starting HTTP server"); diff --git a/fw/app/src/settings.c b/fw/app/src/settings.c new file mode 100644 index 0000000..04d309e --- /dev/null +++ b/fw/app/src/settings.c @@ -0,0 +1,79 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <string.h> + +#include <zephyr/data/json.h> +#include <zephyr/init.h> +#include <zephyr/logging/log.h> +#include <zephyr/settings/settings.h> + +#include "settings.h" + + +LOG_MODULE_DECLARE(settings); + + +int init_settings(void) { + int ret = settings_subsys_init(); + if (ret < 0) { + LOG_ERR("Subsystem init failed (%d)", ret); + return ret; + } + LOG_INF("Subsystem initialized"); + + ret = settings_load(); + if (ret < 0) { + LOG_ERR("Failed to load settings (%d)", ret); + return ret; + } + LOG_INF("Loaded settings"); + + return 0; +} +SYS_INIT(init_settings, APPLICATION, 50); + +static const struct json_obj_descr settings_syslog_target_descr[] = { + JSON_OBJ_DESCR_PRIM(struct settings_syslog_target, ip, JSON_TOK_STRING), +}; + +static const struct json_obj_descr settings_syslog_descr[] = { + JSON_OBJ_DESCR_OBJECT(struct settings_syslog, target, settings_syslog_target_descr), +}; + +static const struct json_obj_descr settings_descr[] = { + JSON_OBJ_DESCR_OBJECT(struct settings, syslog, settings_syslog_descr), +}; + +int settings_to_json(void *buffer, size_t len) +{ + struct settings settings = {0,}; + + static char ip[IPV6_STRLEN_MAX]; + int ret = settings_runtime_get("syslog/target/ip", + ip, + sizeof(ip)); + if (ret < 0) { + LOG_ERR("Failed to get runtime setting syslog/target/ip (%d)", ret); + return ret; + } + + settings.syslog.target.ip = ip; + + ret = json_obj_encode_buf( + settings_descr, + ARRAY_SIZE(settings_descr), + &settings, + buffer, + len + ); + if (ret < 0) { + LOG_ERR("Failed to serialize settings as JSON"); + return ret; + } + + return 0; +} diff --git a/fw/app/src/settings.h b/fw/app/src/settings.h new file mode 100644 index 0000000..d86477e --- /dev/null +++ b/fw/app/src/settings.h @@ -0,0 +1,31 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef SRC_SETTINGS_H +#define SRC_SETTINGS_H + +#include <stddef.h> + +#include <zephyr/data/json.h> + +#define IPV6_STRLEN_MAX 39 // excluding '\0' + + +struct settings_syslog_target { + const char *ip; +}; + +struct settings_syslog { + struct settings_syslog_target target; +}; + +struct settings { + struct settings_syslog syslog; +}; + +int settings_to_json(void *buffer, size_t data); + +#endif // !SRC_SETTINGS_H diff --git a/fw/app/src/syslog.c b/fw/app/src/syslog.c index e19a196..22aa034 100644 --- a/fw/app/src/syslog.c +++ b/fw/app/src/syslog.c @@ -4,8 +4,12 @@ * obtain one at https://mozilla.org/MPL/2.0/. */ +#include <errno.h> #include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <string.h> #include <zephyr/init.h> #include <zephyr/kernel.h> #include <zephyr/logging/log.h> @@ -14,18 +18,24 @@ #include <zephyr/logging/log_ctrl.h> #include <zephyr/logging/log_core.h> #include <zephyr/net/conn_mgr_connectivity.h> +#include <zephyr/settings/settings.h> +#include <zephyr/sys/util.h> #ifdef CONFIG_IOT_CONTACT_NETWORK_HACK #include <zephyr/sys/reboot.h> #endif // CONFIG_IOT_CONTACT_NETWORK_HACK +#include "settings.h" + LOG_MODULE_REGISTER(syslog); #define NETWORK_BUG_DELAY K_MSEC(4000) #define L4_EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED) +#define SYSLOG_TARGET_PORT 514 struct net_mgmt_event_callback l4_cb; static K_SEM_DEFINE(network_connected, 0, 1); +static char target_ip[IPV6_STRLEN_MAX + 1] = "2001:db8::2"; void l4_event_handler( struct net_mgmt_event_callback *cb, @@ -87,4 +97,71 @@ int init_syslog(void) return 0; } -SYS_INIT(init_syslog, APPLICATION, 50); +SYS_INIT(init_syslog, APPLICATION, 40); + +int syslog_handle_set(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg) +{ + const char* next = NULL; + + if (settings_name_steq(name, "target/ip", &next) && !next) { + memset(target_ip, '\0', sizeof(target_ip)); + ssize_t ret = read_cb(cb_arg, target_ip, MIN(sizeof(target_ip) - 1, len)); + if (ret < 0) { + LOG_ERR("Failed to set target IP (%d)", ret); + return (int)ret; + } + LOG_INF("Set target IP to '%s'", target_ip); + return 0; + } + + return 0; +} + +int syslog_handle_commit(void) +{ + char target[IPV6_STRLEN_MAX + 9]; // 9 for brackets, colon, port and \0 + + int ret = snprintf(target, sizeof(target), "[%s]:%d", target_ip, + SYSLOG_TARGET_PORT); + if (ret < 0) { + LOG_ERR("Failed to format target based on ip and port (%d)", ret); + return ret; + } + + if (log_backend_net_set_addr(target) == false) { + LOG_ERR("Could not commit settings"); + return -EINVAL; + } + LOG_INF("Committed settings"); + + return 0; +} + +int syslog_handle_export(int (*cb)(const char *name, const void *value, + size_t val_len)) +{ + LOG_WRN("Settings export not implemented"); + return 0; +} + +int syslog_handle_get(const char *name, char *val, int val_len_max) +{ + const char* next = NULL; + + if (settings_name_steq(name, "target/ip", &next) && !next) { + size_t len = strnlen(target_ip, sizeof(target_ip)); + memcpy(val, target_ip, MIN(len, val_len_max)); + } + + return 0; +} + +SETTINGS_STATIC_HANDLER_DEFINE( + syslog_settings_handler, + "syslog", + syslog_handle_get, + syslog_handle_set, + syslog_handle_commit, + syslog_handle_export +); |