diff options
-rw-r--r-- | src/server/curses.c | 114 | ||||
-rw-r--r-- | src/server/curses.h | 29 | ||||
-rw-r--r-- | src/server/main.c | 122 | ||||
-rw-r--r-- | src/server/net.c | 31 | ||||
-rw-r--r-- | src/server/net.h | 7 | ||||
-rw-r--r-- | src/server/ui.c | 77 | ||||
-rw-r--r-- | src/server/ui.h | 39 | ||||
-rw-r--r-- | src/server/util.c | 59 | ||||
-rw-r--r-- | src/server/util.h | 53 |
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 */ |