commit 9b69e9da6d77e4b0b2589bf010f5cc8f2dc47f47
parent ee56cfa4320489244a526b60607950cbaa607f05
Author: Martin Kloeckner <mjkloeckner@gmail.com>
Date: Fri, 10 Apr 2026 23:46:03 -0300
Implement UART TX/RX data share between main MCU
Diffstat:
| M | data/index.html | | | 89 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
| M | data/main.js | | | 57 | +++++++++++++++++++++++++++++++-------------------------- |
| M | data/style.css | | | 243 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- |
| A | include/queue.h | | | 31 | +++++++++++++++++++++++++++++++ |
| M | platformio.ini | | | 1 | + |
| M | src/main.cpp | | | 260 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
| A | src/queue.c | | | 45 | +++++++++++++++++++++++++++++++++++++++++++++ |
7 files changed, 664 insertions(+), 62 deletions(-)
diff --git a/data/index.html b/data/index.html
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
- <title>ESP8266 Remote Panel</title>
+ <title>ESP8266 Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="data:,">
<link rel="stylesheet" type="text/css" href="style.css">
@@ -10,6 +10,85 @@
<body>
<div id="main-div">
<h1 id="title">ESP8266 Remote Panel</h1>
+ <div id="buttons-div">
+ <div id="main-toggle-div" onclick="handle_click('main-toggle')">
+ <table>
+ <tr style="vertical-align: bottom;">
+ <td>
+ Main output enabled
+ </td>
+ <td id="main-checkbox-td">
+ <div id="main-checkbox" checked="">
+ <svg id="checkmark-svg"
+ version="1.0"
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 64.000000 64.000000"
+ preserveAspectRatio="xMidYMid meet">
+ <g transform="translate(0.000000,64.000000) scale(0.100000,-0.100000)"
+ fill="currentColor" stroke="currentColor">
+ <path d="M380 419 l-142 -211 -67 66 c-38 38 -75 66 -87 66 -25 0 -84 -60 -84
+ -86 0 -11 45 -65 113 -132 121 -121 145 -132 184 -89 49 54 343 502 343 523 0
+ 27 -62 74 -96 74 -16 0 -53 -48 -164 -211z"/>
+ </g>
+ </svg>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div id="timer">
+ <div id="timer-enable" onclick="handle_click('timer-toggle')">
+ <table>
+ <tr>
+ <td>
+ Timer enabled
+ </td>
+ <td id="timer-checkbox-td">
+ <div id="timer-checkbox" checked="">
+ <svg id="checkmark-svg"
+ version="1.0"
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 64.000000 64.000000"
+ preserveAspectRatio="xMidYMid meet">
+ <g transform="translate(0.000000,64.000000) scale(0.100000,-0.100000)"
+ fill="currentColor" stroke="currentColor">
+ <path d="M380 419 l-142 -211 -67 66 c-38 38 -75 66 -87 66 -25 0 -84 -60 -84
+ -86 0 -11 45 -65 113 -132 121 -121 145 -132 184 -89 49 54 343 502 343 523 0
+ 27 -62 74 -96 74 -16 0 -53 -48 -164 -211z"/>
+ </g>
+ </svg>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div id="timer-sep"></div>
+ <div id="timer-picker">
+ <table>
+ <tr>
+ <td>
+ From
+ </td>
+ <td>
+ <input id="from-time" type="time" value="18:00"/>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Until
+ </td>
+ <td>
+ <input id="to-time" type="time" value="00:00"/>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div id="timer-save-div">
+ <input type="button" value="Save" id="timer-save">
+ </div>
+ </div>
+ </div>
+
<div id="info-div">
<table style="width: 100%; padding: 1em;">
<tr>
@@ -36,6 +115,14 @@
<a id="system-ip-addr"></a>
</td>
</tr>
+ <tr>
+ <td>
+ System time
+ </td>
+ <td>
+ <div id="system-time"></div>
+ </td>
+ </tr>
</table>
</div>
</div>
diff --git a/data/main.js b/data/main.js
@@ -1,6 +1,8 @@
var received_data;
-var time_div;
-var system_time, ip_addr, wifi_ssid, wifi_rssi;
+var main_checkbox, timer_checkbox;
+var time_div, system_ip_addr, wifi_ssid, wifi_rssi;
+var system_time, system_time_elem;
+var to_time, from_time, timer_save_button;
const time_formatter = new Intl.DateTimeFormat('en-GB', {
timeZone: 'America/Argentina/Buenos_Aires',
@@ -13,7 +15,10 @@ const time_formatter = new Intl.DateTimeFormat('en-GB', {
});
const query_types = {
- "QUERY_STATUS": 0,
+ "QUERY_STATUS": 0,
+ "QUERY_MAIN_OUTPUT_TOGGLE": 1,
+ "QUERY_TIMER_TOGGLE": 2,
+ "QUERY_TIMER_SET_VALUES": 3
}
function rssi_to_percentage(rssi) {
@@ -29,7 +34,6 @@ function rssi_to_percentage(rssi) {
return quality;
}
-/*
function update_checkbox() {
main_checkbox.setAttribute("checked", received_data["main-output-enabled"]);
timer_checkbox.setAttribute("checked", received_data["timer"]["enabled"]);
@@ -48,28 +52,15 @@ function update_timer() {
to_time.value = received_data["timer"]["to"]["hour"] + ":"
+ received_data["timer"]["to"]["minute"];
}
-*/
function update_all() {
- /*
update_checkbox();
update_time();
update_timer();
- system_local_domain.href = "http://" + received_data["system-local-domain"] + ".local";
- system_local_domain.innerHTML = "http://" + received_data["system-local-domain"] + ".local";
- */
-
- system_ip_addr.href = "/"
+ system_ip_addr.href = received_data["system-ip-addr"];
system_ip_addr.innerHTML = received_data["system-ip-addr"];
- /*
- last_ntp_sync = received_data["last-ntp-sync"];
- last_ntp_sync_elem.innerHTML = time_formatter.format(new Date(last_ntp_sync*1000))
- .replaceAll("/", "-")
- .replaceAll(",", "") + " GMT-3";
- */
-
wifi_ssid.innerHTML = received_data["wifi-ssid"];
const rssi = received_data["wifi-rssi"];
wifi_rssi.innerHTML = rssi + "dBm (" + rssi_to_percentage(rssi) + "%)";
@@ -77,11 +68,21 @@ function update_all() {
function socket_onmessage_handler(event) {
received_data = JSON.parse(event.data);
+ console.log(received_data);
switch(received_data["type"]) {
case "all":
update_all();
break;
+ case "time":
+ update_time();
+ break;
+ case "cb":
+ update_checkbox();
+ break;
+ case "timer":
+ update_timer();
+ break;
default:
console.log("[SOCKET] received_data: type not known, updating all...");
update_all();
@@ -93,21 +94,18 @@ function socket_onopen_handler(event) {
socket.send(query_types["QUERY_STATUS"]);
}
-/*
function handle_click(cb) {
if(cb == 'main-toggle') {
- socket.send(query_types["MAIN_OUTPUT_TOGGLE"]);
+ socket.send(query_types["QUERY_MAIN_OUTPUT_TOGGLE"]);
} else if(cb == 'timer-toggle') {
- socket.send(query_types["TIMER_TOGGLE"]);
+ socket.send(query_types["QUERY_TIMER_TOGGLE"]);
} else {
console.log("handle_click: wrong target");
}
}
-*/
-/*
function update_system_time() {
- socket.send(query_types["MAIN_OUTPUT_STATUS"]);
+ socket.send(query_types["QUERY_STATUS"]);
}
function timer_set_time() {
@@ -121,16 +119,23 @@ function timer_set_time() {
query_json.to.hour = to_time.value.slice(0, 2);
query_json.to.minute = to_time.value.slice(3, 5);
- socket.send(query_types["TIMER_SET_VALUES"] + JSON.stringify(query_json));
+ socket.send(query_types["QUERY_TIMER_SET_VALUES"] + JSON.stringify(query_json));
}
-*/
function query_data() {
+ main_checkbox = document.getElementById("main-checkbox");
+ timer_checkbox = document.getElementById("timer-checkbox");
system_time_elem = document.getElementById("system-time");
system_ip_addr = document.getElementById("system-ip-addr");
wifi_ssid = document.getElementById("wifi-ssid");
wifi_rssi = document.getElementById("wifi-rssi");
+ from_time = document.getElementById("from-time");
+ to_time = document.getElementById("to-time");
+
+ timer_save_button = document.getElementById("timer-save");
+ timer_save_button.addEventListener( "click", timer_set_time, false);
+
// setInterval(update_system_time, 30*1000); // update time every 30 secs
}
diff --git a/data/style.css b/data/style.css
@@ -1,22 +1,134 @@
body {
margin: 3em auto 3em auto;
- /* font-family: "Nimbus Sans", "Nimbus Sans L", "Helvetica", Inter; */
- font-family: monospace;
- font-size: 18px;
+ text-align: center;
+ font-family: "Nimbus Sans", "Nimbus Sans L", "Helvetica", Inter;
+ font-size: 20px;
+}
+
+#title {
+ padding: 0em 0.5em 0em 0.5em;
}
#main-div {
- max-width: 640px;
+ max-width: 23em;
+ margin: auto auto;
+ padding: 0 10px;
+}
+
+table {
+ border-collapse: collapse;
+}
+
+tr {
+ vertical-align: bottom;
+ border-color: #3E3E42;
+}
+
+td {
+ width: 100%;
+}
+
+a, a:visited {
+ color: #00E;
+}
+
+h1 {
+ font-size: 36px;
+}
+
+#main-toggle-div {
+ margin-bottom: 0.5em;
+ cursor: pointer;
+ padding: 1.25em 28px 1.00em 28px;
+ border-radius: 8px;
+ border: 1px solid #E3E3E3;
+}
+
+#timer {
+ border-radius: 8px;
+ border: 1px solid #E3E3E3;
+}
+
+#timer-enable {
+ cursor: pointer;
+ padding: 27.5px 28px 16px 28px;
+}
+
+#timer-picker {
+ padding: 18px 28px 0.00em 28px;
+ font-size: 20px;
+}
+
+#timer-sep {
+ border-bottom: 1px solid #E3E3E3;
+ margin: 0 30px 0 30px;
+}
+
+#from-time, #to-time {
+ font-size: 18px;
+ padding: 2px;
+ margin: 0px;
+ border: 1px solid #E3E3E3;
+ border-radius: 5px;
+ cursor: pointer;
+ background-color: white;
+}
+
+#timer-save-div {
+ padding: 18px 30px 30px 30px;
text-align: center;
+}
+
+#timer-save {
+ margin-right: 0px;
+ box-shadow: none;
+ border: 1px solid #E3E3E3;
+ color: black;
+ background-color: white;
+ border-radius: 5px;
+ cursor: pointer;
+ height: 32px;
+ font-size: 14px;
+ width: 100%;
+ font-weight: bold;
+}
+
+#timer-save:active {
+ background-color: #E3E3E3;
+ border: none;
+}
+
+@media (hover: hover) and (pointer: fine) {
+ #main-toggle-div:hover #main-checkbox,
+ #timer-enable:hover #timer-checkbox,
+ #from-time:hover, #to-time:hover,
+ #main-checkbox:hover, #timer-checkbox:hover,
+ #timer-save:hover {
+ border: 1px solid #999999;
+ }
+}
+
+#from-time:focus-visible,
+#to-time:focus-visible {
+ border: 1px solid #999999;
+ outline: none;
+}
+
+#buttons-div {
+ text-align: left;
margin-left: auto;
margin-right: auto;
- padding: 12px;
+ font-size: 22px;
+ user-select: none;
}
#info-div {
- border: 1px solid black;
- border-radius: 12px;
-
+ padding: 1.75em 1em 1em 1em;
+ font-size: 16px;
+ td {
+ padding: .20em;
+ text-wrap: nowrap;
+ }
td:nth-child(1) {
text-align: left;
user-select: none;
@@ -27,15 +139,122 @@ body {
}
}
+#save-button {
+ padding: 0.25em 0 0 0;
+ text-align: right;
+}
+
+#save-timer-button {
+ border: 1px solid grey;
+ border-radius: 2px;
+ text-align: center;
+ margin-top: 0.35em;
+ font-size: 16px;
+ color: black;
+ background-color: white;
+ vertical-align: bottom;
+}
+
+#main-checkbox, #timer-checkbox {
+ width: 20px;
+ height: 20px;
+ border: 1px solid #E3E3E3;
+ border-radius: 5px;
+ color: black;
+ text-align: center;
+ vertical-align: center;
+ cursor: pointer;
+ color: white;
+ svg {
+ display: none;
+ }
+}
+
+#main-checkbox[checked="1"], #timer-checkbox[checked="1"] {
+ background-color: #3584e4;
+ svg {
+ display: revert;
+ }
+}
+
+#checkmark-svg {
+ width: 14px;
+ height: 20px;
+}
+
+#main-checkbox-td, #timer-checkbox-td {
+ display: block;
+ padding: 0;
+ margin: 0;
+}
+
@media (prefers-color-scheme: dark) {
body {
color: white;
background-color: #17171A;
}
- a {
- color: skyblue;
+
+ a, a:visited {
+ color: #56C8FF;
}
- #info-div {
- border-color: grey;
+
+ input {
+ color-scheme: dark;
+ }
+
+ #buttons-div {
+ border: none;
+ }
+
+ #main-toggle-div, #timer {
+ background-color: #232326;
+ border: none;
+ }
+
+ #timer-sep {
+ border-bottom-color: #3E3E42;
+ }
+
+ #timer-save {
+ border-color: #999999;
+ color: white;
+ background-color: #303033;
+ border-color: #3E3E42;
+ }
+
+ #timer-save:active {
+ background-color: #3E3E42;
+ border: none;
+ }
+
+ #from-time, #to-time {
+ background-color: #303033;
+ color: white;
+ border-color: #3E3E42;
+ }
+
+ #main-checkbox, #timer-checkbox {
+ border-color: #3E3E42;
+ background-color: #303033;
+ }
+
+ #main-checkbox[checked="1"], #timer-checkbox[checked="1"] {
+ background-color: #56C8FF;
+ color: #004263;
+ }
+
+ @media (hover: hover) and (pointer: fine) {
+ #main-toggle-div:hover #main-checkbox,
+ #timer-enable:hover #timer-checkbox,
+ #from-time:hover, #to-time:hover,
+ #main-checkbox:hover, #timer-checkbox:hover,
+ #timer-save:hover {
+ border: 1px solid #828282;
+ }
+ }
+
+ #from-time:focus-visible,
+ #to-time:focus-visible {
+ border: 1px solid #828282;
}
}
diff --git a/include/queue.h b/include/queue.h
@@ -0,0 +1,31 @@
+
+#ifndef QUEUE_H
+#define QUEUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#define QUEUE_LEN 255
+
+typedef struct {
+ uint8_t head;
+ uint8_t tail;
+ uint8_t count;
+ uint8_t data[QUEUE_LEN];
+} queue_t;
+
+void queue_init(queue_t *queue);
+void queue_enqueue(queue_t *queue, uint8_t value);
+uint8_t queue_dequeue(queue_t *queue);
+uint8_t queue_peek(queue_t *queue);
+uint8_t queue_count(queue_t *queue);
+uint8_t queue_is_empty(queue_t *queue);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // QUEUE_H
diff --git a/platformio.ini b/platformio.ini
@@ -3,6 +3,7 @@ platform = espressif8266
framework = arduino
board = esp01
upload_protocol = esptool
+upload_speed = 921600
lib_deps =
links2004/WebSockets
arduino-libraries/Arduino_JSON
diff --git a/src/main.cpp b/src/main.cpp
@@ -1,10 +1,11 @@
-#include <Arduino.h>
#include <Arduino_JSON.h>
#include <ESP8266WiFi.h>
#include <WebSocketsServer.h>
#include <ESP8266WebServer.h>
#include <LittleFS.h>
+#include "queue.h"
+
#ifndef LED_BUILTIN
#define LED_BUILTIN 2
#endif
@@ -12,7 +13,7 @@
#define REMOTE_LED_PIN 2
#define WIFI_SSID "abcdefgh"
#define WIFI_PASSWD "12345678"
-#define LOG_ENABLE true
+#define LOG_ENABLE false
#if true == LOG_ENABLE
#define LOG(fmt, ...) do { \
@@ -27,13 +28,42 @@
#define LOG_ERROR(fmt, ...) LOG("[ERROR] " fmt, ##__VA_ARGS__)
typedef enum {
- QUERY_STATUS
-} query_t;
+ TX_DATA_STATUS = 'A',
+ TX_DATA_MAIN_OUTPUT_TOGGLE = 'B',
+ TX_DATA_TIMER_TOGGLE = 'C',
+ TX_DATA_TIMER_SET_VALUES = 'D',
+} uart_tx_data_e;
-ESP8266WebServer server(80);
-WebSocketsServer web_socket = WebSocketsServer(81);
-static uint8_t remote_devices;
-JSONVar data;
+typedef enum {
+ RX_DATA_STATUS_OK = 'A',
+ RX_DATA_MAIN_OUTPUT_TOGGLE_OK = 'B',
+ RX_DATA_TIMER_TOGGLE_OK = 'C',
+ RX_DATA_TIMER_SET_VALUES_OK = 'D'
+} uart_rx_data_e;
+
+typedef enum {
+ QUERY_STATUS = 0,
+ QUERY_MAIN_OUTPUT_TOGGLE,
+ QUERY_TIMER_TOGGLE,
+ QUERY_TIMER_SET_VALUES
+} query_type_e;
+
+typedef struct {
+ uint8_t enabled;
+ uint8_t from_hour;
+ uint8_t from_minute;
+ uint8_t to_hour;
+ uint8_t to_minute;
+} timer_param_t;
+
+static ESP8266WebServer server(80);
+static WebSocketsServer web_socket = WebSocketsServer(81);
+static uint8_t remote_devices, main_output_enabled;
+uint32_t t, system_time_dt;
+static time_t system_time;
+static timer_param_t timer, new_timer;
+static JSONVar data, timer_data;
+static queue_t uart_queue_tx, uart_queue_rx;
void setup_wifi();
void setup_websocket();
@@ -41,12 +71,13 @@ void setup_webserver();
void setup_fs();
void websocket_event_handler(uint8_t num, WStype_t type, uint8_t *payload, size_t len);
-int webserver_get_file(String path, String &return_page);
+uint16_t webserver_get_file(String path, String &return_page);
String webserver_file_content_type(String path);
void webserver_file_handler();
void webserver_handle_root();
void update_data();
+void update_timer_data();
void setup_wifi()
{
@@ -95,11 +126,37 @@ void setup_fs()
LOG_INFO("LittleFS started %d bytes used\n", fs_info.usedBytes);
}
+void webserver_update_all_clients_checkbox()
+{
+ JSONVar output_data;
+ String output_data_as_json;
+
+ output_data["type"] = "cb";
+ output_data["main-output-enabled"] = String(main_output_enabled);
+ output_data["timer"]["enabled"] = String(timer.enabled);
+
+ output_data_as_json = JSON.stringify(output_data);
+ web_socket.broadcastTXT(output_data_as_json);
+}
+
+void webserver_update_all_clients_timer_values()
+{
+ JSONVar output_data;
+ String output_data_as_json;
+
+ update_timer_data();
+ output_data["type"] = "timer";
+ output_data["timer"] = timer_data;
+
+ // web_socket.broadcastTXT(JSON.stringify(output_data).c_str());
+ output_data_as_json = JSON.stringify(output_data);
+ web_socket.broadcastTXT(output_data_as_json);
+}
+
void websocket_event_handler(uint8_t num, WStype_t type, uint8_t *payload, size_t len)
{
- String data_as_json;
IPAddress ip;
- uint8_t query_type;
+ query_type_e query_type;
switch(type)
{
@@ -123,18 +180,47 @@ void websocket_event_handler(uint8_t num, WStype_t type, uint8_t *payload, size_
case WStype_TEXT:
- query_type = *payload - '0';
+ query_type = (query_type_e)(*payload - '0');
+ LOG_INFO("Received query_type '%s'\n", payload);
+
switch(query_type)
{
case QUERY_STATUS:
- update_data();
- data["type"] = "all";
- data_as_json = JSON.stringify(data);
- web_socket.sendTXT(num, data_as_json);
+ queue_enqueue(&uart_queue_tx, TX_DATA_STATUS);
+ break;
+
+ case QUERY_MAIN_OUTPUT_TOGGLE:
+ queue_enqueue(&uart_queue_tx, TX_DATA_MAIN_OUTPUT_TOGGLE);
+ break;
+
+ case QUERY_TIMER_TOGGLE:
+ queue_enqueue(&uart_queue_tx, TX_DATA_TIMER_TOGGLE);
+ break;
+
+ case QUERY_TIMER_SET_VALUES:
+ payload++; // skip query type
+ timer_data = JSON.parse((char *)payload);
+
+ if(JSON.typeof(timer_data) == "undefined")
+ {
+ LOG_ERROR("QUERY_TIMER_SET_VALUES: Parsing payload failed!");
+ break;
+ }
+
+ new_timer.from_hour = (uint8_t)String(timer_data["from"]["hour"]).toInt();
+ new_timer.from_minute = (uint8_t)String(timer_data["from"]["minute"]).toInt();
+ new_timer.to_hour = (uint8_t)String(timer_data["to"]["hour"]).toInt();
+ new_timer.to_minute = (uint8_t)String(timer_data["to"]["minute"]).toInt();
+
+ queue_enqueue(&uart_queue_tx, TX_DATA_TIMER_SET_VALUES);
+ queue_enqueue(&uart_queue_tx, new_timer.from_hour);
+ queue_enqueue(&uart_queue_tx, new_timer.from_minute);
+ queue_enqueue(&uart_queue_tx, new_timer.to_hour);
+ queue_enqueue(&uart_queue_tx, new_timer.to_minute);
+
break;
default:
- LOG_INFO(" %s\n", payload);
break;
}
@@ -152,7 +238,8 @@ void websocket_event_handler(uint8_t num, WStype_t type, uint8_t *payload, size_
}
}
-int webserver_get_file(String path, String &return_page)
+// TODO: This should return server response codes, i.e. 200, 404, etc
+uint16_t webserver_get_file(String path, String &return_page)
{
if (LittleFS.exists(path))
{
@@ -197,7 +284,7 @@ void webserver_file_handler()
{
String path = server.uri();
String requested_page;
- int response_code;
+ uint16_t response_code;
response_code = webserver_get_file(path, requested_page) ? 404 : 200;
server.send(response_code, webserver_file_content_type(path), requested_page);
}
@@ -205,17 +292,113 @@ void webserver_file_handler()
void webserver_handle_root()
{
String index_page;
- int response_code = 200;
+ uint16_t response_code = 200;
if (webserver_get_file("index.html", index_page)) {
response_code = 404;
}
server.send(response_code, "text/html", index_page.c_str());
}
+String left_pad(uint8_t n) {
+ return n < 10 ? "0" + String(n) : String(n);
+}
+
+void update_timer_data() {
+ timer_data["enabled"] = String(timer.enabled);
+ timer_data["from"]["hour"] = left_pad(timer.from_hour);
+ timer_data["from"]["minute"] = left_pad(timer.from_minute);
+ timer_data["to"]["hour"] = left_pad(timer.to_hour);
+ timer_data["to"]["minute"] = left_pad(timer.to_minute);
+}
+
void update_data() {
- data["system-ip-addr"] = WiFi.localIP().toString();
- data["wifi-ssid"] = WIFI_SSID;
- data["wifi-rssi"] = WiFi.RSSI();
+ data["main-output-enabled"] = String(main_output_enabled);
+ data["system-ip-addr"] = WiFi.localIP().toString();
+ data["system-time"] = (uint32_t)system_time;
+ data["wifi-ssid"] = WIFI_SSID;
+ data["wifi-rssi"] = WiFi.RSSI();
+ update_timer_data();
+ data["timer"] = timer_data;
+}
+
+void uart_rx_handler(void)
+{
+ String data_as_json;
+ uint8_t buffer_aux[4];
+ uart_rx_data_e rx_data_type = (uart_rx_data_e)queue_peek(&uart_queue_rx);
+ /*
+ uart_rx_data_e rx_data_type = (uart_rx_data_e)queue_dequeue(&uart_queue_rx);
+ */
+
+ // Wait for additional data to arrive
+ if ((rx_data_type == RX_DATA_STATUS_OK) && (8 >= queue_count(&uart_queue_rx)))
+ {
+ return;
+ }
+ else
+ {
+ queue_dequeue(&uart_queue_tx);
+ }
+
+ switch(rx_data_type)
+ {
+ case RX_DATA_STATUS_OK:
+
+ main_output_enabled = queue_dequeue(&uart_queue_rx);
+
+ // LSB first
+ buffer_aux[0] = queue_dequeue(&uart_queue_rx);
+ buffer_aux[1] = queue_dequeue(&uart_queue_rx);
+ buffer_aux[2] = queue_dequeue(&uart_queue_rx);
+ buffer_aux[3] = queue_dequeue(&uart_queue_rx);
+
+ system_time = ((uint32_t)buffer_aux[3] << 24) |
+ ((uint32_t)buffer_aux[2] << 16) |
+ ((uint32_t)buffer_aux[1] << 8) |
+ ((uint32_t)buffer_aux[0]);
+
+ timer.enabled = queue_dequeue(&uart_queue_rx);
+ timer.from_hour = queue_dequeue(&uart_queue_rx);
+ timer.from_minute = queue_dequeue(&uart_queue_rx);
+ timer.to_hour = queue_dequeue(&uart_queue_rx);
+ timer.to_minute = queue_dequeue(&uart_queue_rx);
+
+ update_data();
+ data["type"] = "all";
+
+ // TODO: Use sendTXT instead of braodcastTXT; resolve socket numb
+ // web_socket.sendTXT(num, data_as_json);
+ data_as_json = JSON.stringify(data);
+ web_socket.broadcastTXT(data_as_json);
+
+ break;
+ case RX_DATA_MAIN_OUTPUT_TOGGLE_OK:
+
+ main_output_enabled = !main_output_enabled;
+ webserver_update_all_clients_checkbox();
+
+ break;
+
+ case RX_DATA_TIMER_TOGGLE_OK:
+
+ timer.enabled = !timer.enabled;
+ webserver_update_all_clients_checkbox();
+
+ break;
+
+ case RX_DATA_TIMER_SET_VALUES_OK:
+
+ timer.from_hour = new_timer.from_hour;
+ timer.from_minute = new_timer.from_minute;
+ timer.to_hour = new_timer.to_hour;
+ timer.to_minute = new_timer.to_minute;
+ webserver_update_all_clients_timer_values();
+
+ break;
+
+ default:
+ break;
+ }
}
void setup()
@@ -223,6 +406,7 @@ void setup()
pinMode(REMOTE_LED_PIN, OUTPUT);
digitalWrite(REMOTE_LED_PIN, LOW);
Serial.begin(115200);
+ Serial.write("\n\r\n\r\n\r");
delay(2000);
LOG_INFO("Booting");
@@ -234,6 +418,18 @@ void setup()
remote_devices = 0;
+ timer.enabled = 0;
+ timer.from_hour = 12;
+ timer.from_minute = 0;
+ timer.to_hour = 0;
+ timer.to_minute = 0;
+
+ main_output_enabled = 0;
+ t = 0;
+ system_time_dt = 0;
+
+ time(&system_time); // read the current time
+
setup_wifi();
setup_fs();
setup_websocket();
@@ -241,10 +437,28 @@ void setup()
LOG_INFO("Setup done\n");
digitalWrite(REMOTE_LED_PIN, HIGH);
+
+ queue_init(&uart_queue_tx);
+ queue_init(&uart_queue_rx);
}
void loop()
{
+ while (Serial.available() > 0)
+ {
+ queue_enqueue(&uart_queue_rx, Serial.read());
+ }
+
+ if (!queue_is_empty(&uart_queue_rx))
+ {
+ uart_rx_handler();
+ }
+
+ while (!queue_is_empty(&uart_queue_tx) && (Serial.availableForWrite() > 0))
+ {
+ Serial.write(queue_dequeue(&uart_queue_tx));
+ }
+
web_socket.loop();
server.handleClient();
}
diff --git a/src/queue.c b/src/queue.c
@@ -0,0 +1,45 @@
+#include "queue.h"
+
+void queue_init(queue_t *queue)
+{
+ queue->head = 0;
+ queue->tail = 0;
+ queue->count = 0;
+
+ for (uint8_t i = 0; i < QUEUE_LEN; ++i)
+ {
+ queue->data[i] = 0;
+ }
+}
+
+void queue_enqueue(queue_t *queue, uint8_t value)
+{
+ queue->count++;
+ queue->data[queue->head++] = value;
+}
+
+uint8_t queue_dequeue(queue_t *queue)
+{
+ if (queue_is_empty(queue))
+ {
+ return queue_peek(queue);
+ }
+
+ queue->count--;
+ return queue->data[queue->tail++];
+}
+
+uint8_t queue_peek(queue_t *queue)
+{
+ return queue->data[queue->tail];
+}
+
+uint8_t queue_count(queue_t *queue)
+{
+ return queue->count;
+}
+
+uint8_t queue_is_empty(queue_t *queue)
+{
+ return (queue->count == 0);
+}