summaryrefslogtreecommitdiff
path: root/fw/src
diff options
context:
space:
mode:
Diffstat (limited to 'fw/src')
-rw-r--r--fw/src/heart.c52
-rw-r--r--fw/src/heart.h20
-rw-r--r--fw/src/http.c112
-rw-r--r--fw/src/index.html21
-rw-r--r--fw/src/iot-contact.js48
-rw-r--r--fw/src/network.c75
-rw-r--r--fw/src/syslog.c75
-rw-r--r--fw/src/ws.c251
-rw-r--r--fw/src/ws.h17
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, &params, 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