summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Gediminas Jakutis <gediminas@varciai.lt> 2019-06-01 15:27:19 +0300
committerGravatar Gediminas Jakutis <gediminas@varciai.lt> 2019-06-01 15:27:19 +0300
commitfb220a85890b1de874061cc6b1b2102ba33ad43f (patch)
tree6ec02e665d35d114c2212a5243dd1cb0f6afff37
parent96d7d31534921889c219a5c9e00a46c3e94d0124 (diff)
parent227a0e12ee262dbabdd8d988fec194273cf90029 (diff)
downloadusurpation-fb220a85890b1de874061cc6b1b2102ba33ad43f.tar.gz
usurpation-fb220a85890b1de874061cc6b1b2102ba33ad43f.tar.bz2
usurpation-fb220a85890b1de874061cc6b1b2102ba33ad43f.zip
Merge branch '35-Message-Output'
Signed-off-by: Gediminas Jakutis <gediminas@varciai.lt>
-rw-r--r--include/meson.build2
-rw-r--r--include/protocol.h137
-rw-r--r--include/tlv.h197
-rw-r--r--src/common/meson.build1
-rw-r--r--src/common/protocol_private.h48
-rw-r--r--src/common/tlv.c (renamed from src/common/protocol.c)145
-rw-r--r--src/device/device_network.cpp14
-rw-r--r--[-rwxr-xr-x]src/device/device_network.h1
-rw-r--r--src/device/main.ino69
-rw-r--r--src/device/meson.build8
-rw-r--r--src/device/screen.cpp83
-rw-r--r--src/device/screen.h50
-rw-r--r--src/meson.build4
13 files changed, 480 insertions, 279 deletions
diff --git a/include/meson.build b/include/meson.build
index 33e9426..77a8d53 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -1,7 +1,7 @@
header_filenames = [
'utils.h',
'net.h',
- 'protocol.h'
+ 'tlv.h'
]
fw_headers = files(header_filenames)
diff --git a/include/protocol.h b/include/protocol.h
deleted file mode 100644
index 34ad4a3..0000000
--- a/include/protocol.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Usurpataion --- client-server protocol interface.
- *
- * Copyright (C) 2019 Ramūnas Mažeikis
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; version 2.1
- * of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#ifndef USURPATION_PROTOCOL_H_INCLUDED
-#define USURPATION_PROTOCOL_H_INCLUDED
-
-#include <errno.h>
-
-#define E_TLV_OVERFLOW (1 << 0)
-#define E_UNKNOWN_TYPE (1 << 1)
-#define E_IVALID_DESCRIPTOR (1 << 2)
-#define END_OF_PACKET (1 << 3)
-
-/**
- * Regular packets contain tlv's defined by tlv_type.
- *
- * Hearbeat packet tell daemon that device is still alive and listening.
- *
- * Discovery packets are used for what they say.
- */
-enum packet_type {
- REGURAL,
- HEARTBEAT,
- DISCOVERY
-};
-
-/**
- * Message sequence number since beggining of sesssion.
- *
- * Mainly used for identifying lost messages.
- */
-typedef unsigned int msg_idx_t;
-
-enum tlv_type {
- /**
- * NULL-terminated string. To be put in a queue to display on the
- * screen.
- */
- TEXT,
-
- /** Fixed point. 1 decimal digit of precision. */
- FPI1,
-
- /** Literally time_t */
- TIMESTAMP,
-
- /** Represents a request for lost message. Data is unsigned integer
- * that uniquely identifies the message.
- */
- REQUEST,
-
- /**
- * Response to request. Begins with unsigned integer that represents
- * which message is being repeated and the actual null-terminated
- * message after that.
- */
- REPLY,
-
- /**
- * UUID that represents a particular device.
- */
- UUID
-};
-
-/**
- * Packet data itself is a special type of tlv. A packet is either regular,
- * hearbeat or discovery.
- *
- * May be used to send data.
- */
-struct tlv_packet {
- enum packet_type type;
- size_t size;
- size_t offset;
- char *data; /* Bytes representing tlv's */
-};
-
-/**
- * Literally type-length-value
- * */
-struct tlv {
- enum tlv_type type;
- size_t length;
- void *data;
-};
-
-struct tlv_parser {
- char *data;
- size_t offset;
- size_t size;
-};
-
-int get_tlv(struct tlv_parser *parser, struct tlv *ret);
-
-/**
- * Appends data to the next packet to be sent. Type of data is determined by
- * enum tlv_type.
- *
- * In case of overflow return E_TLV_OVERFLOW.
- *
- * On next call after retreiving last packet returns END_OF_PACKET.
- *
- * Overflow can be detected after forming tlv header. This means that the
- * packet may have changes.
- * */
-int push_data(struct tlv_packet *packet, enum tlv_type type, char *data);
-
-
-/**
- * Resets offset to 0 and set entire buffer to 0.
- */
-void clear_data(struct tlv_packet *packet);
-
-
-/**
- * Tells what size of buffer is needed for next tlv.
- */
-size_t tlv_data_size(struct tlv_parser *parser);
-
-#endif /* USURPATION_PROTOCOL_H_INCLUDED */
diff --git a/include/tlv.h b/include/tlv.h
new file mode 100644
index 0000000..b52763a
--- /dev/null
+++ b/include/tlv.h
@@ -0,0 +1,197 @@
+/*
+ * Usurpataion --- client-server protocol interface.
+ *
+ * Copyright (C) 2019 Ramūnas Mažeikis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; version 2.1
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef USURPATION_PROTOCOL_H_INCLUDED
+#define USURPATION_PROTOCOL_H_INCLUDED
+
+#if 0
+
+How do we use this API(?), I hear you say. Well, here is a self-contained
+example complete with tedious comments, allocation of buffers and cleanup:
+
+-------------------------------------------------------------------------------
+ 1 | void functy_the_function(void)
+ 2 | {
+ 3 | struct tlv tlv_packet; /* A packet made of tlv's */
+ 4 | struct tlv text; /* Actually useful data */
+ 5 | char *packet; /* Raw bytes to be pushed via UDP */
+ 6 | size_t packet_size; /* Raw packet size */
+ 7 | char message[] = "Get jacked!"; /* Duh! */
+ 9 |
+ 10 | tlv_init(&tlv_packet, REGURAL); /* Initialise tlv_packet to regular */
+ 11 | tlv_init(&text, TEXT); /* Initialise text packet */
+ 12 | tlv_push_data(&text, message, sizeof(message)); /* Push text to appropriate tlv */
+ 13 | tlv_push_tlv(&tlv_packet, &text); /* Push the tlv into tlv packet */
+ 14 |
+ 15 | packet_size = tlv_raw_size(&tlv_packet); /* Get raw size required to push entire tlv_packet as bytes */
+ 16 | packet = (char *)malloc(packet_size); /* Allocate buffer for outgoing packet */
+ 17 | tlv_get_raw(&tlv_packet, packet); /* Flash tlv_packet to buffer */
+ 19 | udp_push(packet, packet_size); /* Push packet via UDP */
+ 20 | udp_flush(); /* Flush to the other side*/
+ 21 |
+ 22 | tlv_destroy(&tlv_packet); /* Free tlv_packet */
+ 23 | free(packet); /* Free packet itself */
+ 24 | return; /* GTFO and save stack space */
+ 25 | }
+-------------------------------------------------------------------------------
+
+A few things to note:
+ * Calling tlv_destroy() on a tlv of type REGURAL or HEARTBEAT destorys
+ all sub-tlv's too.
+ * Tlv's get copies of data, which means the original buffer can be
+ freed immediately.
+
+#endif
+
+
+#include <errno.h>
+
+#define E_TLV_OVERFLOW (1 << 0)
+#define E_UNKNOWN_TYPE (1 << 1)
+#define END_OF_PACKET (1 << 2)
+
+#define TLV_SZ_MAX_RAW (MTU - 64)
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+/**
+ * Message sequence number since beggining of sesssion.
+ *
+ * Mainly used for identifying lost messages.
+ */
+typedef unsigned int msg_idx_t;
+
+enum tlv_type {
+ /**
+ * NULL-terminated string. To be put in a queue to display on the
+ * screen.
+ */
+ TEXT,
+
+ /** Fixed point. 1 decimal digit of precision. */
+ FPI1,
+
+ /** Literally time_t */
+ TIMESTAMP,
+
+ /** Represents a request for lost message. Data is unsigned integer
+ * that uniquely identifies the message.
+ */
+ REQUEST,
+
+ /**
+ * Response to request. Begins with unsigned integer that represents
+ * which message is being repeated and the actual null-terminated
+ * message after that.
+ */
+ REPLY,
+
+ /**
+ * UUID that represents a particular device.
+ */
+ UUID,
+
+/* Data of the following types are other tlv's! */
+
+ /**
+ * Just a TLV container.
+ */
+ REGURAL,
+
+ /**
+ * Says "I'm not dead yet.".
+ */
+ HEARTBEAT,
+
+ /**
+ * Says "Bring out yer dead!".
+ */
+ DISCOVERY
+};
+
+/**
+ * Literally type-length-value
+ * */
+struct tlv {
+ enum tlv_type type;
+ size_t length;
+ void *data;
+};
+
+/**
+ * Keeps state of the parsing process.
+ *
+ * Related functions return one tlv at a time.
+ */
+struct tlv_parser {
+ char *data;
+ size_t offset;
+ size_t size;
+};
+
+/**
+ * Fills tlv structure to represent the next tlv in the packet.
+ *
+ * Returns END_OF_PACKET if all tlv's were read of E_TLV_OVERFLOW, if the last
+ * tlv, according to its declared size should not fit in a packet.
+ */
+int tlv_get(struct tlv_parser *parser, struct tlv *ret);
+
+/**
+ * Initialises tlv to sane values.
+ */
+void tlv_init(struct tlv *t, enum tlv_type type);
+
+/**
+ * Frees data held in the tlv structure. The structure itself shall be freed as
+ * needed by calling code.
+ */
+void tlv_destroy(struct tlv *t);
+
+/**
+ * Tells amount of bytes needed to push tlv to a buffer
+ */
+size_t tlv_raw_size(const struct tlv *t);
+
+/**
+ * Pushes tlv to buffer as contiguous data. Check tlv size with tlv_raw_size
+ * beforehand. If you don't do that and overflow --- tough tiddy.
+ */
+int tlv_get_raw(struct tlv *t, char *buf);
+
+/**
+ * Pushes data to tlv. Returns E_TLV_OVERFLOW if pushing data would cause the
+ * final size to be greater than TLV_SZ_MAX_RAW. In case of such error the data is left
+ * untouched.
+ */
+int tlv_push_data(struct tlv *t, const char *data, size_t size);
+
+/**
+ * Pushes a sub-tlv into the packet. 't' can only be REGURAL, HEARTBEAT or
+ * DISCOVERY.
+ */
+int tlv_push_tlv(struct tlv *t, const struct tlv *other);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* USURPATION_PROTOCOL_H_INCLUDED */
diff --git a/src/common/meson.build b/src/common/meson.build
index b0f0c82..da8b656 100644
--- a/src/common/meson.build
+++ b/src/common/meson.build
@@ -1,4 +1,5 @@
common_filenames = [
+ 'tlv.c'
]
common_sources = files(common_filenames)
diff --git a/src/common/protocol_private.h b/src/common/protocol_private.h
deleted file mode 100644
index 51d5431..0000000
--- a/src/common/protocol_private.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Usurpataion --- clinet-server protocol implementation.
- *
- * Copyright (C) 2019 Ramūnas Mažeikis
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; version 2.1
- * of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/**
- * Common parts of protocol implementation. Handling of anything that actually
- * deals with connection descriptor has to be implemented by device and daemon
- * separately.
- */
-
-#ifndef PROTOCOL_PRIVATE_H
-#define PROTOCOL_PRIVATE_H
-
-#include "protocol_private.h"
-
-/**
- * Convenience function that pushes bytes to the end of a packet and reports
- * potential overflow.
- *
- * In case of detected overflow nothing is done to the packet.
- */
-int push_bytes(struct tlv_packet *packet, char *data, size_t size);
-
-/**
- * Convenience function that forms a tlv header at the end of a packet. Reports
- * potential overflow.
- *
- * In case of detected overflow nothing is done to the packet.
- */
-int push_tlv_header(struct tlv_packet *packet, enum tlv_type type, size_t size);
-
-#endif /* PROTOCOL_PRIVATE_H */
diff --git a/src/common/protocol.c b/src/common/tlv.c
index b2e0d40..c25f008 100644
--- a/src/common/protocol.c
+++ b/src/common/tlv.c
@@ -27,107 +27,106 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include "protocol.h"
-#include "protocol_private.h"
+#include "tlv.h"
#include "net.h"
#include "utils.h"
-int push_tlv(struct tlv_packet *packet, enum tlv_type type, char *data)
+int tlv_get(struct tlv_parser *parser, struct tlv *ret)
{
- int ret = 0;
- size_t size;
+ int retval = 0;
- switch (type) {
- case TEXT:
- size = strlen(data) + 1;
- break;
- case FPI1:
- size = sizeof(fpi1_t);
- break;
- case TIMESTAMP:
- size = sizeof(time_t);
- break;
- case REQUEST:
- size = sizeof(msg_idx_t);
- break;
- case REPLY:
- size = sizeof(msg_idx_t) + strlen(data + sizeof(msg_idx_t));
- break;
- case UUID:
- size = sizeof(uuid_t);
- break;
- default:
- ret = E_UNKNOWN_TYPE;
+ if (parser->offset + sizeof(ret->type) + sizeof(ret->length) >= parser->size) {
+ retval = E_TLV_OVERFLOW;
+ } else if (parser -> offset == parser->size) {
+ retval = END_OF_PACKET;
+ } else {
+ memcpy(&ret->type, parser->data + parser->offset, sizeof(ret->type));
+ parser->size += sizeof(ret->type);
+ ret->length = memcpy(&ret->length, parser->data + parser->offset, sizeof(ret->length));
+ parser->offset += sizeof(ret->length);
+ if (parser->offset + ret->length >= parser->size) {
+ retval = E_TLV_OVERFLOW;
+ } else {
+ memcpy(ret->data, parser->data, ret->length);
+ }
}
- ret |= push_tlv_header(packet, type, size);
- ret |= push_bytes(packet, data, size);
- return ret;
-}
-
-void clear_data(struct tlv_packet *packet)
-{
- packet->offset = 0;
- packet->type = 0;
- memset(packet->data, 0, packet->size);
+ return retval;
}
-static int push_bytes(struct tlv_packet *packet, char *data, size_t size)
+size_t tlv_data_size(struct tlv_parser *parser)
{
- int ret = 0;
+ size_t size;
- if (packet->offset + size >= packet->size) {
- ret = E_TLV_OVERFLOW;
+ if (parser->offset + sizeof(enum tlv_type) + sizeof(size_t) >= parser->size) {
+ size = 0;
} else {
- memcpy(packet->data + packet->offset, data, size);
- packet->offset += size;
+ memcpy(&size, parser->data + parser->offset + sizeof(enum tlv_type), sizeof(size_t));
}
+ return size;
}
-static int push_tlv_header(struct tlv_packet *packet, enum tlv_type type, size_t size)
+void tlv_destroy(struct tlv *t)
{
- int ret = 0;
-
- if (packet->offset + sizeof(type) + sizeof(size) >= packet->size) {
- ret = E_TLV_OVERFLOW;
- } else {
- memcpy(packet->data + packet->size, type, sizeof(type));
- packet->offset += sizeof(type);
- memcpy(packet->data + packet->offset, size, sizeof(size));
- packet->offset += sizeof(size);
+ size_t i = 0;
+ size_t tlv_count;
+ struct tlv *arr;
+ switch (t->type)
+ {
+ case REGURAL:
+ case HEARTBEAT:
+ case DISCOVERY:
+ tlv_count = t->length / sizeof(struct tlv);
+ arr = t->data;
+ for (i = 0; i < tlv_count; i++) {
+ tlv_destroy(&arr[i]);
+ }
+ default:
+ free(t->data);
+ t->length = 0;
+ break;
}
- return ret;
}
-int get_tlv(struct tlv_parser *parser, struct tlv *ret)
+size_t tlv_raw_size(const struct tlv *t)
{
- int ret = 0;
+ return sizeof(*t) + t->length;
+}
- if (parser->offset + sizeof(ret->type) + sizeof(ret->length) >= parser->size) {
+int tlv_push_data(struct tlv *t, const char *data, size_t size)
+{
+ int ret = 0;
+ size_t final_size = tlv_raw_size(t) + size;
+ if (final_size > TLV_SZ_MAX_RAW) {
ret = E_TLV_OVERFLOW;
- } else if (parser -> offset == parser->size) {
- ret = END_OF_PACKET;
} else {
- ret->type = memcpy(&ret->type, parser->data + parser->offset, sizeof(ret->type));
- parser->size += sizeof(ret->type);
- ret->length = memcpy(&ret->length, parser->data + parser->offset, sizeof(ret->length));
- parser->offset += sizeof(ret->length);
- if (parser->offset + ret->length >= parser->size) {
- ret = E_TLV_OVERFLOW;
- } else {
- memcpy(ret->data, parser->data, ret->length);
- }
+ t->data = realloc(t->data, final_size);
+ memcpy(t->data + t->length, data, size);
+ t->length = final_size;
}
return ret;
}
-size_t tlv_data_size(struct tlv_parser *parser)
+void tlv_init(struct tlv *t, enum tlv_type type)
{
- size_t size;
+ t->type = type;
+ t->length = 0;
+ t->data = NULL;
+}
- if (parser->offset + sizeof(enum tlv_type) + sizeof(size_t) >= parser->size) {
- size = 0;
+int tlv_push_tlv(struct tlv *t, const struct tlv *other)
+{
+ int ret = 0;
+ size_t other_size;
+ size_t final_size;
+
+ other_size = tlv_raw_size(other);
+ final_size = tlv_raw_size(t) + other_size;
+ if (final_size > TLV_SZ_MAX_RAW) {
+ ret = E_TLV_OVERFLOW;
} else {
- memcpy(&size, parser->data + parser->offset + sizeof(enum tlv_type), sizeof(size_t));
+ tlv_get_raw(other, t->data + t->length);
+ t->length = final_size;
}
- return size;
+
+ return ret;
}
diff --git a/src/device/device_network.cpp b/src/device/device_network.cpp
index d7781a0..f2456d9 100644
--- a/src/device/device_network.cpp
+++ b/src/device/device_network.cpp
@@ -26,7 +26,7 @@
static struct netstate {
WiFiUDP udp;
- char udppacketbuffer[1500];
+ char udppacketbuffer[MTU];
char *udppacketcursor;
IPAddress daemon_ip;
bool acquired;
@@ -59,6 +59,17 @@ int udp_flush(void)
return state.udp.endPacket();
}
+size_t udp_get_data(char *buf, size_t size)
+{
+ size_t ret;
+ if (state.udp.available() != 0) {
+ ret = state.udp.read(buf, size);
+ } else {
+ ret = 0;
+ }
+ return ret;
+}
+
void discover_client(const int port)
{
IPAddress bcastip(255, 255, 255, 255);
@@ -100,4 +111,3 @@ static void udp_init_packet_expaddr(IPAddress ip, const int port)
memset(state.udppacketbuffer, 0, sizeof(state.udppacketbuffer));
state.udppacketcursor = state.udppacketbuffer;
}
-
diff --git a/src/device/device_network.h b/src/device/device_network.h
index d8f41a1..92af429 100755..100644
--- a/src/device/device_network.h
+++ b/src/device/device_network.h
@@ -31,6 +31,7 @@ void udp_init(const int port);
void udp_init_packet(const int port);
void udp_push(const void * const data, const size_t size);
int udp_flush(void);
+size_t udp_get_data(char *buf, size_t size);
void discover_client(const int port);
IPAddress *get_daemon_address(void);
diff --git a/src/device/main.ino b/src/device/main.ino
index 66e52e8..24cfb9c 100644
--- a/src/device/main.ino
+++ b/src/device/main.ino
@@ -27,6 +27,9 @@
#include "SSD1306Wire.h"
#include "DejaVu_Sans_Mono_13.h"
#include "device_network.h"
+#include "screen.h"
+#include "net.h"
+#include "tlv.h"
static const unsigned int internal_led = 2;
static unsigned int led_state = 0;
@@ -36,6 +39,16 @@ static void init_OLED(void);
unsigned int toggle_led(const int pin);
static int wifi_connect(const char * const ssid, const char * const password, const char doblink, const int ledpin);
static void blink_led(const int pin, const int ontime, const int offtime);
+void handle_tlv(const struct tlv *data);
+
+static struct progstate_t {
+ int ip_print_count = 5;
+ struct display_status ds = {0};
+ struct tlv_parser parser = {0};
+ struct tlv crr_data;
+ size_t bytes_read = 0;
+ char in_packet_buf[MTU];
+} progstate;
void setup(void)
{
@@ -64,27 +77,55 @@ void loop(void)
static String prefix;
static IPAddress ip_to_print;
static IPAddress *daemon_ip = NULL;
- static int print_dev_ip = 0;
static unsigned int delta = 2000; /* sleep length to use (ms) */
- /* static int dot_idx = 0; */
delay(delta);
- udp_init_packet(com_port);
- udp_push(clientmagic, sizeof(clientmagic));
- udp_flush();
+ /* Initial display of ip's. */
+ if (progstate.ip_print_count > 0) {
+ udp_init_packet(com_port);
+ udp_push(clientmagic, sizeof(clientmagic));
+ udp_flush();
+
+ if (!daemon_ip) {
+ daemon_ip = get_daemon_address();
+ }
- if (!daemon_ip) {
- daemon_ip = get_daemon_address();
+ prefix = (progstate.ip_print_count % 2) ? devstr : daemonstr;
+ ip_to_print = (progstate.ip_print_count) ? WiFi.localIP() : *daemon_ip;
+ display.clear();
+ display.drawString(0, 0, prefix);
+ display.drawString(0, 16, ip_to_print.toString());
+ display.display();
+ progstate.ip_print_count--;
+ } else { /* Dealing with tlv's one at a time. */
+ progstate.bytes_read = udp_get_data(progstate.in_packet_buf, sizeof(progstate.in_packet_buf));
+ if (progstate.bytes_read > 0) {
+ progstate.parser.data = progstate.in_packet_buf;
+ progstate.parser.offset = 0;
+ progstate.parser.size = progstate.bytes_read;
+ /* Ignore errors for now. */
+ while (tlv_get(&progstate.parser, &progstate.crr_data) == 0) {
+ handle_tlv(&progstate.crr_data);
+ }
+ }
+ display_update_scroll(&progstate.ds);
}
+}
- prefix = (print_dev_ip) ? devstr : daemonstr;
- ip_to_print = (print_dev_ip) ? WiFi.localIP() : *daemon_ip;
- display.clear();
- display.drawString(0, 0, prefix);
- display.drawString(0, 16, ip_to_print.toString());
- display.display();
- print_dev_ip = !print_dev_ip;
+void handle_tlv(const struct tlv *t)
+{
+ /* Currently just dealing with text.
+ * */
+ switch (t->type) {
+ case TEXT:
+ display_status_init(&display, &progstate.ds, (char *)t->data);
+ break;
+ default:
+ display.clear();
+ display.drawString(0, 0, "Fugg :DDD");
+ break;
+ }
}
static void init_OLED(void)
diff --git a/src/device/meson.build b/src/device/meson.build
index 625bd2d..7a0665c 100644
--- a/src/device/meson.build
+++ b/src/device/meson.build
@@ -35,10 +35,14 @@ if get_option('fwbuild')
cpus = '2'
endif
- fw_filenames = ['main.ino',
+ fw_filenames = [
+ 'main.ino',
'DejaVu_Sans_Mono_13.h',
'device_network.cpp',
- 'device_network.h']
+ 'device_network.h',
+ 'screen.cpp',
+ 'screen.h'
+ ]
fw_true_sources += files(fw_filenames)
fw_filenames += oledlibnames
fw_true_sources += oledlib
diff --git a/src/device/screen.cpp b/src/device/screen.cpp
new file mode 100644
index 0000000..2857161
--- /dev/null
+++ b/src/device/screen.cpp
@@ -0,0 +1,83 @@
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <OLEDDisplay.h>
+#include <Wire.h>
+#include "screen.h"
+
+void draw_lines(OLEDDisplay *screen, struct display_status *status);
+void update_lines(struct display_status *status);
+void init_msg(char *msg, size_t size);
+
+/* Effectively const. For type safety reasons. */
+static char NOTHING[] = {'\0'};
+
+void display_status_init(OLEDDisplay *screen, struct display_status *status, char *msg)
+{
+ status->delta = 2; /* Currently default */
+ status->screen = screen;
+ init_msg(msg, strlen(msg));
+ status->message = msg;
+ status->line_cursor = 0;
+ status->last_scroll_time = time(NULL);
+ update_lines(status);
+}
+
+/**
+ * Turns all whitespace into literal spaces to save screen real-estate and
+ * possible misinterpretation.
+ */
+void init_msg(char *msg, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ switch (msg[i]) {
+ case '\n':
+ case '\t':
+ case '\r':
+ msg[i] = ' ';
+ break;
+ case '\0':
+ goto end;
+ default:
+ break;
+ }
+ }
+end:
+ return;
+}
+
+int display_update_scroll(struct display_status *status)
+{
+ time_t crr_time = time(NULL);
+ /* Only scroll lines once a delta, because --- duh! */
+ if (status->last_scroll_time - crr_time > status->delta) {
+ status->last_scroll_time += status->delta;
+ status->line_cursor++;
+ update_lines(status);
+ draw_lines(status->screen, status);
+ }
+ if (status->first_line == NOTHING && status->second_line == NOTHING) {
+ return END_OF_MESSAGE;
+ } else {
+ return 0;
+ }
+}
+
+void draw_lines(OLEDDisplay *screen, struct display_status *status)
+{
+ screen->clear();
+ screen->drawString(0, 0, status->first_line);
+ screen->drawString(0, SCREEN_HEIGHT / 2, status->second_line);
+}
+
+void update_lines(struct display_status *status)
+{
+ status->first_line = (status->line_cursor * SCREEN_MAX_CHARS < status->message_len)
+ ? status->message + status->line_cursor * SCREEN_MAX_CHARS
+ : NOTHING;
+ status->second_line = (status->line_cursor * SCREEN_MAX_CHARS < status->message_len)
+ ? status->message + (status->line_cursor + 1) * SCREEN_MAX_CHARS
+ : NOTHING;
+}
diff --git a/src/device/screen.h b/src/device/screen.h
new file mode 100644
index 0000000..5d0e3b3
--- /dev/null
+++ b/src/device/screen.h
@@ -0,0 +1,50 @@
+/**
+ * Simple API for scrolling lines. Keeps things simple by not even assuming
+ * which screen is being drawn on.
+ */
+
+#ifndef DEVICE_SCREEN_H
+#define DEVICE_SCREEN_H
+
+#include <time.h>
+#include <OLEDDisplay.h>
+#include <Wire.h>
+
+#define SCREEN_WIDTH (128)
+#define SCREEN_HEIGHT (32)
+#define FONT_WIDTH (8)
+#define SCREEN_MAX_CHARS (SCREEN_WIDTH / FONT_WIDTH)
+
+/**
+ * Struct that keeps track of the lines on the screen.
+ */
+struct display_status {
+ OLEDDisplay *screen; /* Screen to draw on. */
+ time_t delta; /* Seconds/Line */
+ time_t last_scroll_time; /* Last second the line was scrolled */
+ char *message; /* Entire message to be shown */
+ char *first_line; /* First line on display */
+ char *second_line; /* Second line on display */
+ size_t message_len; /* Length of the message */
+ size_t line_cursor; /* Index of the first line being displayed. */
+};
+
+/**
+ * Displays scrolling text on the screen.
+ */
+int display_update_scroll(struct display_status *status);
+
+#define END_OF_MESSAGE (1 << 0)
+/**
+ * Initialises display_status structure so it can be used for
+ * display_update_scroll.
+ *
+ * screen - screen to draw on
+ *
+ * status - structure to Initialise
+ *
+ * msg - message to scroll on the screen
+ */
+void display_status_init(OLEDDisplay *screen, struct display_status *status, char *msg);
+
+#endif /* DEVICE_SCREEN_H */ \ No newline at end of file
diff --git a/src/meson.build b/src/meson.build
index 12b583a..38a1f57 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,6 +1,6 @@
-#subdir('common')
+subdir('common')
-fw_true_sources = [fw_headers]
+fw_true_sources = [fw_headers, common_sources]
subdir('daemon')
subdir('device')