summaryrefslogtreecommitdiff
path: root/fw/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'fw/app/src')
-rw-r--r--fw/app/src/http.c67
-rw-r--r--fw/app/src/index.html17
-rw-r--r--fw/app/src/settings.c77
-rw-r--r--fw/app/src/settings.h33
l---------fw/app/src/simple.css1
-rw-r--r--fw/app/src/syslog.c79
6 files changed, 267 insertions, 7 deletions
diff --git a/fw/app/src/http.c b/fw/app/src/http.c
index e206f86..f9016c1 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"
@@ -34,6 +36,21 @@ struct http_resource_detail_static index_resource_detail = {
.static_data_len = sizeof(index_html_gz),
};
+static const uint8_t css_gz[] = {
+ #include "simple.css.gz.inc"
+};
+
+struct http_resource_detail_static css_resource_detail = {
+ .common = {
+ .type = HTTP_RESOURCE_TYPE_STATIC,
+ .bitmask_of_supported_http_methods = BIT(HTTP_GET),
+ .content_encoding = "gzip",
+ .content_type = "text/css",
+ },
+ .static_data = css_gz,
+ .static_data_len = sizeof(css_gz),
+};
+
static const uint8_t js_html_gz[] = {
#include "iot-contact.js.gz.inc"
};
@@ -76,6 +93,54 @@ 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[SETTINGS_JSON_MAX_LEN];
+
+ int ret = settings_to_json(buffer, sizeof(buffer));
+ if (ret < 0) {
+ LOG_ERR("Could not serialize payload for settings request");
+ return ret;
+ }
+
+ size_t len = strnlen(buffer, sizeof(buffer));
+ if (len >= sizeof(buffer)) {
+ LOG_ERR("End of settings JSON string not found (strnlen returned %d)",
+ sizeof(buffer));
+ return -ENOMEM;
+ }
+
+ if (sizeof(buffer) < len + 2) {
+ LOG_ERR("Settings JSON buffer too small to hold \\n and \\0");
+ return -ENOMEM;
+ }
+ buffer[len + 0] = '\n';
+ buffer[len + 1] = '\0';
+ len += 1;
+
+ response_ctx->body = (const uint8_t *)buffer;
+ response_ctx->body_len = len;
+ 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),
+ .content_type = "text/json",
+ },
+ .cb = settings_handler,
+ .user_data = NULL,
+};
+
static uint8_t websocket_read_buffer[1024];
struct http_resource_detail_websocket websocket_resource_detail = {
@@ -95,7 +160,9 @@ HTTP_SERVICE_DEFINE(http_service, NULL, &http_port, 1, 10, NULL, NULL);
HTTP_RESOURCE_DEFINE(index_resource, http_service, "/", &index_resource_detail);
HTTP_RESOURCE_DEFINE(websocket_resource, http_service, "/", &websocket_resource_detail);
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/index.html b/fw/app/src/index.html
index 5817818..d4ccd45 100644
--- a/fw/app/src/index.html
+++ b/fw/app/src/index.html
@@ -8,14 +8,19 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
- <title>iot-contact</title>
+ <title>IoT contact</title>
+ <link rel="stylesheet" type="text/css" href="simple.css">
<script type="text/javascript" src="/iot-contact.js"></script>
</head>
<body>
- <h4>iot-contact</h4>
- <p>
- <label for="heartbeat">Heartbeat</label>
- <meter id="heartbeat" min="0" max="1" value="0"></meter>
- </p>
+ <header>
+ <h1>IoT contact</h1>
+ </header>
+ <main>
+ <p class="notice">
+ <label for="heartbeat">Heartbeat</label>
+ <meter id="heartbeat" min="0" max="1" value="0"></meter>
+ </p>
+ </main>
</body>
</html>
diff --git a/fw/app/src/settings.c b/fw/app/src/settings.c
new file mode 100644
index 0000000..4b2c248
--- /dev/null
+++ b/fw/app/src/settings.c
@@ -0,0 +1,77 @@
+/*
+ * 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,};
+ settings.syslog.target.ip = (char *)settings.syslog.target.ip_array;
+
+ int ret = settings_runtime_get("syslog/target/ip",
+ settings.syslog.target.ip_array,
+ sizeof(settings.syslog.target.ip_array));
+ if (ret < 0) {
+ LOG_ERR("Failed to get runtime setting syslog/target/ip (%d)", ret);
+ return ret;
+ }
+
+ 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..8c7b4e3
--- /dev/null
+++ b/fw/app/src/settings.h
@@ -0,0 +1,33 @@
+/*
+ * 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'
+#define SETTINGS_JSON_MAX_LEN (IPV6_STRLEN_MAX + 50)
+
+
+struct settings_syslog_target {
+ char ip_array[IPV6_STRLEN_MAX];
+ char *ip; /* Zephyr's JSON lib does not work with arrays directly */
+};
+
+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/simple.css b/fw/app/src/simple.css
new file mode 120000
index 0000000..5483eb1
--- /dev/null
+++ b/fw/app/src/simple.css
@@ -0,0 +1 @@
+../../../simple.css/simple.css \ No newline at end of file
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
+);