diff options
Diffstat (limited to 'fw/src')
-rw-r--r-- | fw/src/heart.c | 52 | ||||
-rw-r--r-- | fw/src/heart.h | 20 | ||||
-rw-r--r-- | fw/src/http.c | 112 | ||||
-rw-r--r-- | fw/src/index.html | 21 | ||||
-rw-r--r-- | fw/src/iot-contact.js | 48 | ||||
-rw-r--r-- | fw/src/network.c | 75 | ||||
-rw-r--r-- | fw/src/syslog.c | 75 | ||||
-rw-r--r-- | fw/src/ws.c | 251 | ||||
-rw-r--r-- | fw/src/ws.h | 17 |
9 files changed, 0 insertions, 671 deletions
diff --git a/fw/src/heart.c b/fw/src/heart.c deleted file mode 100644 index 6bcced6..0000000 --- a/fw/src/heart.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 <stdbool.h> - -#include <zephyr/kernel.h> -#include <zephyr/logging/log.h> - -#include "heart.h" - - -LOG_MODULE_REGISTER(heart); - - -#define HEART_PERIOD K_MSEC(1000) -#define HEART_STACK_SIZE 500 -#define HEART_PRIO K_PRIO_PREEMPT(8) - - -ZBUS_CHAN_DEFINE( - heartbeat_channel, - struct heartbeat, - NULL, - NULL, - ZBUS_OBSERVERS_EMPTY, - ZBUS_MSG_INIT(.ttl_ms = 0) -); - - -static void heart_thread_function(void *ptr1, void *ptr2, void *ptr3) { - LOG_INF("Starting to beat"); - - struct heartbeat heartbeat = {.ttl_ms = 1100}; - - while (true) { - LOG_DBG("Heart beat"); - int ret = zbus_chan_pub(&heartbeat_channel, &heartbeat, K_FOREVER); - if (ret < 0) { - LOG_ERR("Could not publish heartbeat"); - } - k_sleep(HEART_PERIOD); - } -} - - -K_THREAD_DEFINE(heart_thread, HEART_STACK_SIZE, - heart_thread_function, NULL, NULL, NULL, - HEART_PRIO, 0, 0); diff --git a/fw/src/heart.h b/fw/src/heart.h deleted file mode 100644 index cd32c15..0000000 --- a/fw/src/heart.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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_HEART_H -#define SRC_HEART_H - - -#include <zephyr/zbus/zbus.h> - - -struct heartbeat { - uint32_t ttl_ms; -}; - -ZBUS_CHAN_DECLARE(heartbeat_channel); - -#endif // !SRC_HEART_H diff --git a/fw/src/http.c b/fw/src/http.c deleted file mode 100644 index e206f86..0000000 --- a/fw/src/http.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 <stdint.h> - -#include <zephyr/init.h> -#include <zephyr/logging/log.h> -#include <zephyr/net/http/server.h> -#include <zephyr/net/http/service.h> -#include <zephyr/net/http/status.h> - -#include "ws.h" - - -LOG_MODULE_REGISTER(http); - - -static const uint8_t index_html_gz[] = { - #include "index.html.gz.inc" -}; - -struct http_resource_detail_static index_resource_detail = { - .common = { - .type = HTTP_RESOURCE_TYPE_STATIC, - .bitmask_of_supported_http_methods = BIT(HTTP_GET), - .content_encoding = "gzip", - .content_type = "text/html", - }, - .static_data = index_html_gz, - .static_data_len = sizeof(index_html_gz), -}; - -static const uint8_t js_html_gz[] = { - #include "iot-contact.js.gz.inc" -}; - -struct http_resource_detail_static js_resource_detail = { - .common = { - .type = HTTP_RESOURCE_TYPE_STATIC, - .bitmask_of_supported_http_methods = BIT(HTTP_GET), - .content_encoding = "gzip", - .content_type = "text/javascript", - }, - .static_data = js_html_gz, - .static_data_len = sizeof(js_html_gz), -}; - -static int favicon_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 -) { - LOG_DBG("Handling favicon request"); - - response_ctx->body = NULL; - response_ctx->body_len = 0; - response_ctx->final_chunk = true; - response_ctx->status = HTTP_204_NO_CONTENT; - - LOG_DBG("Favicon request handled"); - return 0; -} - -static struct http_resource_detail_dynamic favicon_resource_detail = { - .common = { - .type = HTTP_RESOURCE_TYPE_DYNAMIC, - .bitmask_of_supported_http_methods = BIT(HTTP_GET), - }, - .cb = favicon_handler, - .user_data = NULL, -}; - -static uint8_t websocket_read_buffer[1024]; - -struct http_resource_detail_websocket websocket_resource_detail = { - .common = { - .type = HTTP_RESOURCE_TYPE_WEBSOCKET, - .bitmask_of_supported_http_methods = BIT(HTTP_GET), - }, - .cb = ws_upgrade_handler, - .data_buffer = websocket_read_buffer, - .data_buffer_len = sizeof(websocket_read_buffer), -}; - -static uint16_t http_port = 80; - -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(js_resource, http_service, "/iot-contact.js", &js_resource_detail); - -int init_http_server(void) { - LOG_DBG("Starting HTTP server"); - - int ret = http_server_start(); - if (ret < 0) { - LOG_ERR("Failed to start HTTP server (%d)", ret); - return ret; - } - - LOG_INF("HTTP server was started"); - return 0; -} -SYS_INIT(init_http_server, APPLICATION, 99); diff --git a/fw/src/index.html b/fw/src/index.html deleted file mode 100644 index 5817818..0000000 --- a/fw/src/index.html +++ /dev/null @@ -1,21 +0,0 @@ -<!DOCTYPE html> - -<!-- 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/. --> - -<html lang="en"> - <head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>iot-contact</title> - <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> - </body> -</html> diff --git a/fw/src/iot-contact.js b/fw/src/iot-contact.js deleted file mode 100644 index e8e966f..0000000 --- a/fw/src/iot-contact.js +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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/. - */ - -function blinkHeartbeat() { - const heartbeat = document.getElementById("heartbeat"); - heartbeat.value = 1; - setTimeout(() => heartbeat.value = 0, 300); -} - -window.addEventListener("DOMContentLoaded", (ev) => { - const ws = new WebSocket("/"); - console.log("WebSocket object created"); - - ws.onopen = (event) => { - console.log("WebSocket connection opened"); - }; - - ws.onmessage = (event) => { - try { - const data = JSON.parse(event.data); - console.log("Message received: ", data); - if (data.type === 0 && data.ttl_ms) { - blinkHeartbeat(); - } - } catch (error) { - console.error("Invalid message received:", event.data); - } - }; - - ws.onclose = (event) => { - console.log("WebSocket connection closed"); - }; - - ws.onerror = (event) => { - console.log("WebSocket error: ", event); - }; - - setInterval(() => { - if (ws.readyState === WebSocket.OPEN) { - const data = "{\"type\":0,\"ttl_ms\":1100}\n"; - ws.send(data); - console.log("Heartbeat sent: '", data, "'"); - } - }, 1000); -}) diff --git a/fw/src/network.c b/fw/src/network.c deleted file mode 100644 index 6e6eb17..0000000 --- a/fw/src/network.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 <stdint.h> -#include <string.h> - -#include <zephyr/init.h> -#include <zephyr/logging/log.h> -#include <zephyr/net/hostname.h> -#include <zephyr/net/net_if.h> -#include <zephyr/net/net_linkaddr.h> -#include <zephyr/net/net_mgmt.h> -#include <zephyr/net/ethernet.h> -#include <zephyr/net/ethernet_mgmt.h> -#include <zephyr/sys/util.h> - - -LOG_MODULE_REGISTER(network); - - -#define HOSTNAME "iot-contact" - - -/* will be read from an EEPROM chip in the future */ -static const uint8_t mac_address[NET_ETH_ADDR_LEN] = {0x00, 0x00, 0x5e, 0x00, 0x53, 0x01}; - -int init_mac_address(void) -{ - LOG_DBG("Setting custom MAC address"); - - struct net_if *interface = net_if_get_default(); - - int ret = net_if_down(interface); - if (ret < 0) { - LOG_ERR("Failed to set interface down to set MAC address (%d)", ret); - return ret; - } - - struct ethernet_req_params params = {0}; - memcpy(params.mac_address.addr, mac_address, 6); - ret = net_mgmt(NET_REQUEST_ETHERNET_SET_MAC_ADDRESS, interface, ¶ms, sizeof(params)); - if (ret < 0) { - LOG_ERR("Failed to set MAC address (%d)", ret); - return ret; - } - - ret = net_if_up(interface); - if (ret < 0) { - LOG_ERR("Failed to set interface up after setting MAC address (%d)", ret); - return ret; - } - - LOG_INF("Successfully set MAC address"); - return 0; -} -SYS_INIT(init_mac_address, APPLICATION, 0); - -int init_hostname(void) -{ - LOG_DBG("Setting hostname"); - - int ret = net_hostname_set(HOSTNAME, sizeof(HOSTNAME)); - if (ret < 0) { - LOG_ERR("Failed to set hostname to '%s' (%d)", HOSTNAME, ret); - return ret; - } - - LOG_INF("Successfully set hostname to '%s'", HOSTNAME); - return 0; -} -SYS_INIT(init_hostname, APPLICATION, 1); diff --git a/fw/src/syslog.c b/fw/src/syslog.c deleted file mode 100644 index b1a1077..0000000 --- a/fw/src/syslog.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 <stdbool.h> - -#include <zephyr/init.h> -#include <zephyr/kernel.h> -#include <zephyr/logging/log.h> -#include <zephyr/logging/log_backend.h> -#include <zephyr/logging/log_backend_net.h> -#include <zephyr/logging/log_ctrl.h> -#include <zephyr/logging/log_core.h> -#include <zephyr/net/conn_mgr_connectivity.h> - -LOG_MODULE_REGISTER(syslog); - -#define L4_EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED) - -struct net_mgmt_event_callback l4_cb; -static K_SEM_DEFINE(network_connected, 0, 1); - -void l4_event_handler( - struct net_mgmt_event_callback *cb, - uint32_t event, - struct net_if *iface) -{ - LOG_DBG("Executing L4 event handler"); - - switch (event) { - case NET_EVENT_L4_CONNECTED: - k_sem_give(&network_connected); - LOG_INF("Network connected"); - break; - case NET_EVENT_L4_DISCONNECTED: - LOG_INF("Network disconnected"); - break; - default: - break; - } -} - -int init_network_monitoring(void) -{ - net_mgmt_init_event_callback(&l4_cb, l4_event_handler, L4_EVENT_MASK); - net_mgmt_add_event_callback(&l4_cb); - - return 0; -} -SYS_INIT(init_network_monitoring, APPLICATION, 0); - -int init_syslog(void) -{ - LOG_DBG("Initializing syslog logging backend"); - - LOG_DBG("Waiting for network ..."); - k_sem_take(&network_connected, K_FOREVER); - - LOG_DBG("Enabling syslog backend"); - const struct log_backend *backend = log_backend_net_get(); - if (log_backend_is_active(backend) == false) { - /* flush log messages to ensure first syslog message is reproducible */ - while (log_process()); - log_backend_init(backend); - log_backend_enable(backend, backend->cb->ctx, CONFIG_LOG_MAX_LEVEL); - LOG_INF("Syslog backend enabled"); - } else { - LOG_INF("Syslog backend was already enabled"); - } - - return 0; -} -SYS_INIT(init_syslog, APPLICATION, 50); diff --git a/fw/src/ws.c b/fw/src/ws.c deleted file mode 100644 index 6f68538..0000000 --- a/fw/src/ws.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * 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 <errno.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <zephyr/kernel.h> -#include <zephyr/logging/log.h> -#include <zephyr/net/http/server.h> -#include <zephyr/net/websocket.h> -#include <zephyr/sys_clock.h> -#include <zephyr/zbus/zbus.h> - -#include "heart.h" - - -LOG_MODULE_REGISTER(ws); - - -#define WS_NUM_HANDLERS 1 -#define WS_HANDLER_STACK_SIZE 2048 -#define WS_HANDLER_PRIO K_PRIO_PREEMPT(8) -#define WS_CONNECTION_BACKLOG_LEN 5 -#define WS_TX_BUFFER_LEN 150 -#define WS_CLIENT_HEARTBEAT_GRACE_TIME_MS 10000 - -K_MSGQ_DEFINE(ws_connection_backlog, sizeof(int), WS_CONNECTION_BACKLOG_LEN, 1); -ZBUS_MSG_SUBSCRIBER_DEFINE(ws_tx_messages); -ZBUS_CHAN_ADD_OBS(heartbeat_channel, ws_tx_messages, 3); - -static void ws_tx_thread_function(void *ptr1, void *ptr2, void *ptr3) { - int fd = -1; - struct k_msgq *tx_fds = ptr1; - uint8_t buffer[WS_TX_BUFFER_LEN]; - const struct zbus_channel *chan; - struct heartbeat heartbeat; - - while (true) { - int ret = zbus_obs_set_enable(&ws_tx_messages, false); - if (ret < 0) { - LOG_ERR("Could not disable zbus observer (%d)", ret); - continue; - } - - ret = k_msgq_get(tx_fds, &fd, K_FOREVER); - if (ret < 0) { - LOG_ERR("Error getting new file descriptor (%d)", ret); - continue; - } - LOG_INF("Handling TX of connection with file descriptor %d", fd); - - ret = zbus_obs_set_enable(&ws_tx_messages, true); - if (ret < 0) { - LOG_ERR("Could not enable zbus observer (%d)", ret); - continue; - } - - while (true) { - ret = zbus_sub_wait_msg(&ws_tx_messages, &chan, &heartbeat, K_FOREVER); - if (ret < 0) { - LOG_ERR("Could not wait for zbus messages (%d)", ret); - break; - } - if (chan != &heartbeat_channel) { - LOG_ERR("Unsupported channel"); - continue; - } - - ret = snprintf((char *)buffer, sizeof(buffer), - "{\"type\":0,\"ttl_ms\":%d}\n", heartbeat.ttl_ms); - if (ret < 0) { - LOG_ERR("Could not serialize heartbeat message"); - continue; - } - size_t len = ret; - - int ret = websocket_send_msg( - fd, (const uint8_t *)buffer, len, - WEBSOCKET_OPCODE_DATA_TEXT, false, true, 100 - ); - if (ret < 0) { - if (ret == -EBADF) { - LOG_DBG("Connection closed, waiting for new one"); - } else { - LOG_ERR("Error on websocket_send_msg (%d)", ret); - } - break; - } - } - } -} - -static int ws_recv_full_message(int fd, void *buf, const size_t len, - uint32_t *message_type, int64_t deadline) { - uint64_t remaining = 0; - size_t read = 0; - int ret; - - while (true) { - int64_t timeout = MIN(50, deadline - k_uptime_get()); - if (timeout <= 0) { - ret = -ETIMEDOUT; - LOG_ERR("No time left to read message from %d (%d)", fd, ret); - return ret; - } - - if (read >= len) { - ret = -ENOSPC; - LOG_ERR("No buffer space left to store message from %d (%d)", fd, ret); - return ret; - } - - ret = websocket_recv_msg(fd, (unsigned char *)buf+read, len-read, - message_type, &remaining, timeout); - if (ret < 0) { - if (ret == -EAGAIN || ret == -EINTR) { - LOG_DBG("Trying again to read full message"); - continue; - } else { - LOG_ERR("Unhandled error on message reading (%d)", ret); - return ret; - } - } - - read += ret; - - if (remaining <= 0) { - return read; - } - } -} - -static int ws_handle_data_text(const uint8_t *buf, size_t len, int64_t *deadline) { - LOG_DBG("Got text message"); - - static const char heartbeat[] = "{\"type\":0,\"ttl_ms\":1100}\n"; - - if (len + 1 == sizeof(heartbeat)) { - if (memcmp((const void *)buf, heartbeat, len) == 0) { - LOG_DBG("Received heartbeat from client"); - *deadline = k_uptime_get() + WS_CLIENT_HEARTBEAT_GRACE_TIME_MS; - return 0; - } - } - - LOG_HEXDUMP_DBG(buf, len, "Could not handle message"); - return -EIO; -} - -static int ws_rx_handle_connection(int fd) { - LOG_INF("Handling RX of connection with file descriptor %d", fd); - - uint8_t rx_buf[100]; - uint32_t message_type = 0; - int64_t rx_heartbeat_deadline = k_uptime_get() + WS_CLIENT_HEARTBEAT_GRACE_TIME_MS; - - while (true) { - memset(rx_buf, 0, sizeof(rx_buf)); - - int ret = ws_recv_full_message(fd, rx_buf, sizeof(rx_buf), - &message_type, rx_heartbeat_deadline); - if (ret < 0) { - LOG_ERR("Could not receive full message from %d (%d)", fd, ret); - return ret; - } - size_t len = ret; - LOG_DBG("Received message with opcode %d of length %d", message_type, len); - - if (message_type == WEBSOCKET_OPCODE_DATA_TEXT || - message_type == 3) { // FIXME for some reason opcode 1 parses to 3 - ret = ws_handle_data_text(rx_buf, len, &rx_heartbeat_deadline); - if (ret < 0) { - LOG_ERR("Failed to handle text data (%d)", ret); - } - } else if (message_type == WEBSOCKET_OPCODE_CLOSE) { - LOG_INF("Client closed connection"); - return 0; - } else { - LOG_WRN("Received unhandled message opcode %d", message_type); - LOG_HEXDUMP_WRN(rx_buf, len, "Message content:"); - } - - if (k_uptime_get() > rx_heartbeat_deadline) { - LOG_INF("Client heartbeat timeout expired on %d - closing", fd); - return -ETIMEDOUT; - } - } -} - -static void ws_rx_thread_function(void *ptr1, void *ptr2, void *ptr3) { - struct k_msgq *tx_fds = ptr1; - - while (true) { - int fd; - int ret = k_msgq_get(&ws_connection_backlog, &fd, K_FOREVER); - if (ret < 0) { - LOG_ERR("Error getting new file descriptor (%d)", ret); - continue; - } - - ret = k_msgq_put(tx_fds, (const void *)&fd, K_FOREVER); - if (ret < 0) { - LOG_ERR("Could not pass file descriptor %d to TX thread (%d)", fd, ret); - goto unregister; - } - - ret = ws_rx_handle_connection(fd); - if (ret < 0) { - LOG_ERR("Failed to handle connection %d (%d)", fd, ret); - goto unregister; - } - -unregister: - ret = websocket_unregister(fd); - if (ret < 0) { - LOG_ERR("Failed to unregister connection %d (%d)", fd, ret); - } - } -} - -K_MSGQ_DEFINE(ws_tx_fd_1, sizeof(int), 1, 1); -K_THREAD_DEFINE(ws_rx_thread_1, WS_HANDLER_STACK_SIZE, - ws_rx_thread_function, &ws_tx_fd_1, NULL, NULL, - WS_HANDLER_PRIO, 0, 0); -K_THREAD_DEFINE(ws_tx_thread_1, WS_HANDLER_STACK_SIZE, - ws_tx_thread_function, &ws_tx_fd_1, NULL, NULL, - WS_HANDLER_PRIO, 0, 0); - -int ws_upgrade_handler( - int ws_socket, - struct http_request_ctx *request_ctx, - void *user_data -) { - LOG_DBG("Handling WebSocket upgrade for file descriptor %d", ws_socket); - - int ret = k_msgq_put(&ws_connection_backlog, (const void *)&ws_socket, - K_NO_WAIT); - if (ret < 0) { - LOG_ERR("Connection backlog full, dropping file descriptor %d", ws_socket); - return -ENOENT; - } - - LOG_INF("Added file descriptor %d to connection backlog", ws_socket); - return 0; -} diff --git a/fw/src/ws.h b/fw/src/ws.h deleted file mode 100644 index 0c13039..0000000 --- a/fw/src/ws.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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_WS_H -#define SRC_WS_H - - -#include <zephyr/net/http/server.h> - - -int ws_upgrade_handler(int ws_socket, struct http_request_ctx *request_ctx, - void *user_data); - -#endif // !SRC_WS_H |