/* * Usurpation – wearable device main logic * * Copyright (C) 2019 Gediminas Jakutis * 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 */ #include #include #include #include #include #include "SSD1306Wire.h" #include "DejaVu_Sans_Mono_13.h" #include "device_network.h" #include "screen.h" #include "utils.h" #include "tlv.h" #define seconds(a) (((a) * 1000) / (period)) static const unsigned int internal_led = 2; static unsigned int led_state = 0; static char fugg[] = "error :3ccc"; static const char devstr[] = "Device IP:"; static const char daemonstr[] = "Daemon IP:"; static char ipstr[] = " "; static unsigned int period = 1000; SSD1306Wire display(0x3c, 4, 5, GEOMETRY_128_32); 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; struct display_status ds; struct tlv field; struct tlv_packet heartbeat; char buf[MTU]; char hbcounter; IPAddress *daemon_ip; } progstate; void setup(void) { extern const char * const ssid; extern const char * const password; struct tlv field; pinMode(internal_led, OUTPUT); toggle_led(internal_led); init_OLED(); display.fillCircle(32, 16, 12); display.display(); wifi_connect(ssid, password, 1, internal_led); udp_init(com_port); display.fillCircle(64, 16, 12); display.display(); progstate.daemon_ip = discover_client(com_port); display.fillCircle(92, 16, 12); display.display(); tlv_init(&field, HEARTBEAT); field.data = strdup(heartbeat_device); field.head.size = sizeof(heartbeat_device); tlv_packet_init(&progstate.heartbeat); tlv_pack(&progstate.heartbeat, &field); tlv_packet_finalize(&progstate.heartbeat); tlv_destroy(&field); progstate.ip_print_count = 5; } void loop(void) { static int displayed = END_OF_MESSAGE; String current_ip; delay(period); if (!progstate.hbcounter) { udp_init_packet(com_port); udp_push(progstate.heartbeat.data, progstate.heartbeat.cursor); udp_flush(); progstate.hbcounter = seconds(30); } /* Initial display of ips. */ if (!progstate.ip_print_count) { if (udp_get_data(progstate.buf, sizeof(progstate.buf))) { tlv_get(progstate.buf, &progstate.field, NULL); handle_tlv(&progstate.field); } } else if (displayed == END_OF_MESSAGE) { current_ip = (progstate.ip_print_count % 2) ? WiFi.localIP().toString() : progstate.daemon_ip->toString(); memcpy(ipstr, (progstate.ip_print_count % 2) ? devstr : daemonstr, strlen(devstr)); memcpy(ipstr + 16, current_ip.c_str(), strlen(current_ip.c_str())); display_status_init(&display, &progstate.ds, ipstr, strlen(ipstr), seconds(1)); progstate.ip_print_count--; } displayed = display_update_scroll(&progstate.ds); --progstate.hbcounter; } void handle_tlv(const struct tlv *in) { /* Currently just dealing with text. * */ switch (in->head.type) { case TEXT: if (in->head.size) { display_status_init(&display, &progstate.ds, in->data, in->head.size, seconds(3)); } case INVALID: case HEARTBEAT: break; default: display_status_init(&display, &progstate.ds, fugg, sizeof(fugg), seconds(5)); break; } /* clear the tlv after handling it */ progstate.field = tlv_none; } static void init_OLED(void) { display.init(); display.flipScreenVertically(); display.setTextAlignment(TEXT_ALIGN_LEFT); display.setFont((uint8_t *)DejaVu_Sans_Mono_13); } /* toggle the bult-in led and return current state */ unsigned int toggle_led(const int pin) { led_state = !led_state; /* as the cathode of the builtin diode is connected to the MCU's pin, * while the anode is connected to Vcc, to turn it off, we need to set * the pin to HIGH. */ digitalWrite(pin, led_state ? LOW : HIGH); return led_state; } static int wifi_connect(const char * const ssid, const char * const password, const char doblink, const int ledpin) { size_t i = 30; WiFi.forceSleepWake(); yield(); WiFi.persistent(0); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); do { if (doblink) { blink_led(ledpin, 250, 250); } else { delay (500); } } while (WiFi.status() != WL_CONNECTED); return 0; } static void blink_led(const int pin, const int ontime, const int offtime) { toggle_led(pin); delay(ontime); toggle_led(pin); delay(offtime); }