summaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
authorGravatar Gediminas Jakutis <gediminas@varciai.lt> 2018-05-06 19:01:13 +0300
committerGravatar Gediminas Jakutis <gediminas@varciai.lt> 2018-05-06 19:01:13 +0300
commitdb88777a2f63d7dcd31e5e0442839213784eeb82 (patch)
tree6622d876ba737e3d73cd4d5fa81ba927d050d7f2 /src/server
parent3736b2e92b63d69f2278de2ad72901413a70012d (diff)
downloadcoffeetemp-db88777a2f63d7dcd31e5e0442839213784eeb82.tar.gz
coffeetemp-db88777a2f63d7dcd31e5e0442839213784eeb82.tar.bz2
coffeetemp-db88777a2f63d7dcd31e5e0442839213784eeb82.zip
server: major refactor with preparations for switchable UIs.
Diffstat (limited to 'src/server')
-rw-r--r--src/server/curses.c114
-rw-r--r--src/server/curses.h29
-rw-r--r--src/server/main.c122
-rw-r--r--src/server/net.c31
-rw-r--r--src/server/net.h7
-rw-r--r--src/server/ui.c77
-rw-r--r--src/server/ui.h39
-rw-r--r--src/server/util.c59
-rw-r--r--src/server/util.h53
9 files changed, 411 insertions, 120 deletions
diff --git a/src/server/curses.c b/src/server/curses.c
new file mode 100644
index 0000000..cdd2aea
--- /dev/null
+++ b/src/server/curses.c
@@ -0,0 +1,114 @@
+/*
+ * Hot Beverage Companion – desktop application curses ui
+ *
+ * Copyright (C) 2018 Gediminas Jakutis
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <ncurses.h>
+#include "util.h"
+#include "curses.h"
+
+struct settings {
+ int nd;
+ struct timespec period;
+};
+
+struct settings settings;
+
+static void curses_idle(void);
+static void curses_update(const struct tempmodule_state * const state);
+
+int curses_init(int nd, struct timespec period)
+{
+ settings.nd = nd;
+ settings.period = period;
+
+ initscr();
+ nodelay(stdscr, 1);
+ noecho();
+
+ return A_OK;
+}
+
+int curses_loop(void)
+{
+ static int statechange = 1;
+ static struct tempmodule_state state;
+ int status;
+
+ do {
+ if (getch() == 'q') {
+ status = A_OK;
+ break;
+ }
+
+ status = refresh_data(settings.nd, &state);
+ if (status == A_OK) {
+ curses_update(&state);
+ statechange = 1;
+ } else if (status == DEAD && statechange) {
+ curses_idle();
+ statechange = 0;
+ }
+ nanosleep(&settings.period, NULL);
+ } while (status != ERROR);
+
+ endwin();
+
+ return status;
+}
+
+static void curses_idle(void)
+{
+ move(0, 0);
+ clrtoeol();
+ printw("sequence: [waiting for ESP8266...]");
+ move(1, 0);
+ clrtoeol();
+ mvprintw(1, 0, "thermistor temp: [waiting for ESP8266...]");
+ move(2, 0);
+ clrtoeol();
+ mvprintw(2, 0, "thermistor resistance: [waiting for ESP8266...]");
+ move(3, 0);
+ clrtoeol();
+ mvprintw(3, 0, "tap voltage: [waiting for ESP8266...]");
+ move(4, 0);
+ clrtoeol();
+ mvprintw(4, 0, "press 'q' to exit");
+ refresh();
+}
+
+static void curses_update(const struct tempmodule_state * const state)
+{
+
+ move(0, 0);
+ clrtoeol();
+ printw("sequence: %u", state->sequence);
+ move(1, 0);
+ clrtoeol();
+ mvprintw(1, 0, "thermistor temp: %.1fC", state->temperature);
+ move(2, 0);
+ clrtoeol();
+ mvprintw(2, 0, "thermistor resistance: %hd Ohm", state->resistance);
+ move(3, 0);
+ clrtoeol();
+ mvprintw(3, 0, "tap voltage: %.3fV (%hd)", state->voltage, state->voltage_raw);
+ move(4, 0);
+ clrtoeol();
+ mvprintw(4, 0, "press 'q' to exit");
+ refresh();
+}
diff --git a/src/server/curses.h b/src/server/curses.h
new file mode 100644
index 0000000..7c63ea5
--- /dev/null
+++ b/src/server/curses.h
@@ -0,0 +1,29 @@
+/*
+ * Hot Beverage Companion – desktop application curses ui
+ *
+ * Copyright (C) 2018 Gediminas Jakutis
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef CURSES_H_INCLUDED
+#define CURSES_H_INCLUDED
+
+#include <time.h>
+
+int curses_init(int nd, struct timespec period);
+int curses_loop(void);
+
+#endif /* CURSES_H_INCLUDED */
diff --git a/src/server/main.c b/src/server/main.c
index 7237643..8406d11 100644
--- a/src/server/main.c
+++ b/src/server/main.c
@@ -27,126 +27,50 @@
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
-#include <ncurses.h>
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
+#include "util.h"
#include "net.h"
+#include "ui.h"
-int init(const unsigned short int port);
-static void draw_idle(void);
-static void draw_busy(const char * const data);
-static float digest_temp(const short int rawdata);
+static int init(int argc, char ***argv, const unsigned short int port, enum uitype ui);
-int main(void)
+int main(int argc, char **argv)
{
- static const struct timespec wait = {0, 200 * 1000 * 1000}; /* 200 ms */
- char data[dgsize] = {0};
- int status;
+ int ret;
int nd;
- nd = init(2191);
+ nd = init(argc, &argv, 2191, UI_DEFAULT);
- if (nd == NET_ERROR) {
+ if (nd == ERROR) {
+ ret = nd;
goto fail;
}
- do {
- status = net_getlastdata(nd, data);
- switch (status) {
- case NET_OK:
- /*fall-through */
- case NET_NONEWDATA:
- draw_busy(data);
- break;
- case NET_ERROR:
- goto fail;
- default:
- draw_idle();
- ; /* noop */
- }
- nanosleep(&wait, NULL);
- } while (getch() != 'q');
-
+ ret = ui_startloop();
fail:
net_close(nd);
- endwin();
-
- return 0;
-}
-
-int init(const unsigned short int port)
-{
- int ret;
- ret = net_init(port);
-
- initscr();
- nodelay(stdscr, 1);
- noecho();
-
return ret;
}
-static void draw_idle(void)
-{
- move(0, 0);
- clrtoeol();
- printw("sequence: [waiting for ESP8266...]");
- move(1, 0);
- clrtoeol();
- mvprintw(1, 0, "thermistor temp: [waiting for ESP8266...]");
- move(2, 0);
- clrtoeol();
- mvprintw(2, 0, "thermistor resistance: [waiting for ESP8266...]");
- move(3, 0);
- clrtoeol();
- mvprintw(3, 0, "tap voltage: [waiting for ESP8266...]");
- move(4, 0);
- clrtoeol();
- mvprintw(4, 0, "press 'q' to exit");
- refresh();
-}
-
-static void draw_busy(const char * const data)
+static int init(int argc, char ***argv, const unsigned short int port, enum uitype ui)
{
- unsigned int sequence;
- short int thermistor_data;
- short int voltage;
- float temp;
-
- memcpy(&sequence, data + 2, sizeof(sequence));
- memcpy(&thermistor_data, data + 6, sizeof(thermistor_data));
- temp = digest_temp(thermistor_data);
- memcpy(&thermistor_data, data + 8, sizeof(thermistor_data));
- memcpy(&voltage, data + 10, sizeof(voltage));
-
- move(0, 0);
- clrtoeol();
- printw("sequence: %u", sequence);
- move(1, 0);
- clrtoeol();
- mvprintw(1, 0, "thermistor temp: %.1fC", temp);
- move(2, 0);
- clrtoeol();
- mvprintw(2, 0, "thermistor resistance: %hd", thermistor_data);
- move(3, 0);
- clrtoeol();
- mvprintw(3, 0, "tap voltage: %hd", voltage);
- move(4, 0);
- clrtoeol();
- mvprintw(4, 0, "press 'q' to exit");
- refresh();
-}
+ int ret = A_OK;
+ int nd;
-/*
- * raw data is in 0.1°K per 1. Subtract 2730 to get Celsius.
- * Multiply by 0.1f (divide by 10) to get the correct scale.
- */
-static float digest_temp(const short int rawdata)
-{
- float ret;
+ nd = net_init(port);
+ if (nd == ERROR) {
+ ret = nd;
+ goto fail;
+ }
- ret = (rawdata - 2730) * 0.1f;
+ ret = ui_init(argc, argv, ui, nd, DEFAULT_PERIOD);
+ if (ret == ERROR) {
+ net_close(nd);
+ goto fail;
+ }
+fail:
return ret;
}
diff --git a/src/server/net.c b/src/server/net.c
index f858907..eaab32d 100644
--- a/src/server/net.c
+++ b/src/server/net.c
@@ -29,6 +29,7 @@
#include <string.h>
#include <stdlib.h>
#include <limits.h>
+#include "util.h"
#include "net.h"
struct netstate {
@@ -63,13 +64,13 @@ int net_init(const unsigned short int port)
if (available_count) {
for (i = 0; !state[i].available; ++i) {
if (i == count) {
- ret = NET_ERROR;
+ ret = ERROR;
goto out;
}
}
} else {
if (++count == INT_MAX) {
- ret = NET_ERROR;
+ ret = ERROR;
goto out;
}
@@ -82,7 +83,7 @@ int net_init(const unsigned short int port)
bindaddress.sin_port = htons(port);
state[i].sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (bind(state[i].sock, (struct sockaddr*) &bindaddress, sizeof(bindaddress))) {
- ret = NET_ERROR;
+ ret = ERROR;
goto out;
}
@@ -93,17 +94,17 @@ int net_init(const unsigned short int port)
state[i].data = malloc(dgsize);
memset(state[i].data, 0, dgsize);
state[i].bufsize = dgsize;
- state[i].status = NET_NONEWDATA;
+ state[i].status = NONEWDATA;
pthread_mutex_init(&state[i].datamutex, NULL);
if (pthread_create(&state[i].listner, NULL, dolisten, state + i)) {
- ret = NET_ERROR;
+ ret = ERROR;
goto out;
}
ret = count;
out:
- if (ret == NET_ERROR && sizechanged) {
+ if (ret == ERROR && sizechanged) {
state = realloc(state, sizeof(struct netstate) * --count);
}
@@ -117,7 +118,7 @@ int net_close(int nd)
pthread_mutex_lock(&initmutex);
if (nd > count || nd < 1 || state[nd - 1].available) {
- ret = NET_ERROR;
+ ret = ERROR;
} else {
--nd;
pthread_cancel(state[nd].listner);
@@ -125,7 +126,7 @@ int net_close(int nd)
close(state[nd].sock);
free(state[nd].data);
state[nd].available = 1;
- ret = NET_OK;
+ ret = A_OK;
}
pthread_mutex_unlock(&initmutex);
@@ -137,7 +138,7 @@ int net_getlastdata(int nd, char * const data)
int ret;
if (nd > count || nd < 1 || state[--nd].available) {
- ret = NET_ERROR;
+ ret = ERROR;
} else if (!(ret = state[nd].status)) {
memcpy(data, state[nd].data, dgsize);
}
@@ -169,13 +170,13 @@ static void *dolisten(void * state)
if (st->data[0] == 'I' && !(strcmp(st->data, servermagic))) {
sendto(st->sock, clientmagic, sizeof(clientmagic),
MSG_DONTWAIT, (struct sockaddr *) &clientaddr, sizeof(clientaddr));
- st->status = NET_NONEWDATA; /* consume packet and lie about it */
+ st->status = NONEWDATA; /* consume packet and lie about it */
}
}
/* no packets in five seconds */
if ((now.tv_sec - st->lastreply.tv_sec) >= 5) {
- st->status = NET_DEAD;
+ st->status = DEAD;
} else if (st->data[0] != 'I') {
/* we don't actually want to have NONEWDATA set from this loop,
* barring the one exeption that is after arrival of the beacon
@@ -183,7 +184,7 @@ static void *dolisten(void * state)
* due to polling being generally much more frequent than the
* actual packet rate.
*/
- st->status = NET_OK;
+ st->status = A_OK;
}
pthread_mutex_unlock(&st->datamutex);
@@ -213,12 +214,12 @@ static int getpacket(char *data, size_t buffsize, ssize_t *recvbufsize, int sock
if (ret < 0) {
/* NOOP */
} else if (!ret) {
- ret = NET_NONEWDATA;
+ ret = NONEWDATA;
} else if (pfd.revents & POLLIN) {
*recvbufsize = recvfrom(sock, data, buffsize, MSG_DONTWAIT, (struct sockaddr *) sender, &sender_len);
- ret = NET_OK;
+ ret = A_OK;
} else {
- ret = NET_NONEWDATA;
+ ret = NONEWDATA;
}
return ret;
diff --git a/src/server/net.h b/src/server/net.h
index 0358db7..061c722 100644
--- a/src/server/net.h
+++ b/src/server/net.h
@@ -21,12 +21,7 @@
#ifndef NET_H_INCLUDED
#define NET_H_INCLUDED
-#define NET_ERROR -1
-#define NET_OK 0
-#define NET_NONEWDATA 1
-#define NET_DEAD 2
-
-#define dgsize 512
+#define dgsize 512
int net_init(const unsigned short int port);
int net_close(int nd);
diff --git a/src/server/ui.c b/src/server/ui.c
new file mode 100644
index 0000000..7412a91
--- /dev/null
+++ b/src/server/ui.c
@@ -0,0 +1,77 @@
+/*
+ * Hot Beverage Companion – desktop application ui wrapper
+ *
+ * Copyright (C) 2018 Gediminas Jakutis
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "util.h"
+#include "ui.h"
+#include "curses.h"
+
+static enum uitype chosen = ui_none;
+
+int ui_init(int argc, char ***argv, enum uitype ui, int nd, struct timespec period)
+{
+ int ret = A_OK;
+
+ chosen = ui;
+
+ switch (ui) {
+ case ui_none:
+ /* noop */
+ break;
+ case ui_file:
+ /* TODO: stub */
+ break;
+ case ui_curses:
+ ret = curses_init(nd, period);
+ break;
+ case ui_gtk:
+ /* ret = gtkui_init(nd, period); */
+ break;
+ default:
+ /* noop */
+ break;
+ }
+
+ return ret;
+}
+
+int ui_startloop(void)
+{
+ int ret = A_OK;
+
+ switch (chosen) {
+ case ui_none:
+ /* noop */
+ break;
+ case ui_file:
+ /* TODO: stub */
+ break;
+ case ui_curses:
+ ret = curses_loop();
+ break;
+ case ui_gtk:
+ /* ret = gtkui_loop(); */
+ break;
+ default:
+ /* noop */
+ break;
+ }
+
+ return ret;
+}
diff --git a/src/server/ui.h b/src/server/ui.h
new file mode 100644
index 0000000..8070be3
--- /dev/null
+++ b/src/server/ui.h
@@ -0,0 +1,39 @@
+/*
+ * Hot Beverage Companion – desktop application ui wrapper
+ *
+ * Copyright (C) 2018 Gediminas Jakutis
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef UI_H_INCLUDED
+#define UI_H_INCLUDED
+
+#include <time.h>
+
+enum uitype {
+ ui_none,
+ ui_file,
+ ui_curses,
+ ui_gtk
+};
+
+static const enum uitype UI_DEFAULT = ui_curses;
+static const struct timespec DEFAULT_PERIOD = {0, 200 * 1000 * 1000}; /* 200 ms */
+
+int ui_init(int argc, char ***argv, enum uitype ui, int nd, struct timespec period);
+int ui_startloop(void);
+
+#endif /* UI_H_INCLUDED */
diff --git a/src/server/util.c b/src/server/util.c
new file mode 100644
index 0000000..bb494c8
--- /dev/null
+++ b/src/server/util.c
@@ -0,0 +1,59 @@
+/*
+ * Hot Beverage Companion – desktop application utilities
+ *
+ * Copyright (C) 2018 Gediminas Jakutis
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <string.h>
+#include "util.h"
+#include "net.h"
+
+static float digest_temp(const short int rawtemp);
+static float digest_volt(const short int rawvolt);
+
+/*
+ * raw data is in 0.1°K per 1. Subtract 2730 to get Celsius.
+ * Multiply by 0.1f (divide by 10) to get the correct scale.
+ */
+static float digest_temp(const short int rawtemp)
+{
+ return (rawtemp - 2730) * 0.1f;
+}
+
+/*
+ * raw data is in 1/1024 parts of the max A0 input voltage
+ * on the D1 mini board, which is 3.2V
+ */
+static float digest_volt(const short int rawvolt)
+{
+ return 3.2f / 1024.0f * rawvolt;
+}
+
+int refresh_data(int nd, struct tempmodule_state *state)
+{
+ int ret;
+ char buf[dgsize];
+
+ ret = net_getlastdata(nd, buf);
+ if (ret == A_OK) {
+ memcpy(&state->sequence, buf + 2, sizeof(state->size));
+ state->temperature = digest_temp(state->temperature_raw);
+ state->voltage = digest_volt(state->voltage_raw);
+ }
+
+ return ret;
+}
diff --git a/src/server/util.h b/src/server/util.h
new file mode 100644
index 0000000..80e81cf
--- /dev/null
+++ b/src/server/util.h
@@ -0,0 +1,53 @@
+/*
+ * Hot Beverage Companion – desktop application utilities
+ *
+ * Copyright (C) 2018 Gediminas Jakutis
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef UTIL_H_INCLUDED
+#define UTIL_H_INCLUDED
+
+enum response {
+ ERROR = -1,
+ A_OK = 0,
+ NONEWDATA = 1,
+ DEAD = 2
+};
+
+struct tempmodule_state {
+ union {
+ struct {
+ unsigned int sequence;
+ short int temperature_raw;
+ short int resistance;
+ short int voltage_raw;
+ };
+
+ struct size {
+ unsigned int ui;
+ short int si[3];
+ } size;
+
+ char rawdata[sizeof(struct size)];
+ };
+ float temperature;
+ float voltage;
+};
+
+int refresh_data(int nd, struct tempmodule_state *state);
+
+#endif /* UTIL_H_INCLUDED */