Add date set/view and power screen
This commit is contained in:
parent
317b3ee5b7
commit
d05f4c39ec
18
Makefile
18
Makefile
@ -8,7 +8,8 @@ LDFLAGS=-lgpio -lfigpar -lpthread ${SQLITE3_LDFLAGS}
|
|||||||
SRCS=src/main.c src/util.c src/lcd.c src/ths.c src/button.c src/ui/screen.c\
|
SRCS=src/main.c src/util.c src/lcd.c src/ths.c src/button.c src/ui/screen.c\
|
||||||
src/ui/datesel.c src/ui/statsby.c src/ui/datapoints.c src/ui/timesel.c\
|
src/ui/datesel.c src/ui/statsby.c src/ui/datapoints.c src/ui/timesel.c\
|
||||||
src/ui/statrange.c src/config.c src/ui/blankscreen.c src/drive.c\
|
src/ui/statrange.c src/config.c src/ui/blankscreen.c src/drive.c\
|
||||||
src/ui/exportscreen.c
|
src/ui/exportscreen.c src/ui/setdatescreen.c src/ui/viewdatescreen.c\
|
||||||
|
src/ui/powerscreen.c
|
||||||
PROG=rpi4b-temp-humidity
|
PROG=rpi4b-temp-humidity
|
||||||
|
|
||||||
all: config.conf bin/${PROG}
|
all: config.conf bin/${PROG}
|
||||||
@ -22,20 +23,24 @@ bin/main.o bin/config.o: config.mk
|
|||||||
bin/main.o bin/util.o bin/lcd.o bin/ths.o bin/button.o: src/util.h
|
bin/main.o bin/util.o bin/lcd.o bin/ths.o bin/button.o: src/util.h
|
||||||
bin/ui/screen.o bin/ui/statsby.o bin/ui/datesel.o: src/util.h
|
bin/ui/screen.o bin/ui/statsby.o bin/ui/datesel.o: src/util.h
|
||||||
bin/ui/datapoints.o bin/ui/timesel.o bin/ui/statrange.o: src/util.h
|
bin/ui/datapoints.o bin/ui/timesel.o bin/ui/statrange.o: src/util.h
|
||||||
|
bin/ui/viewdatescreen.o bin/ui/setdatescreen.o bin/ui/powerscreen.o: src/util.h
|
||||||
|
|
||||||
bin/main.o bin/lcd.o bin/screen.o bin/ui/datesel.o: src/lcd.h
|
bin/main.o bin/lcd.o bin/screen.o bin/ui/datesel.o: src/lcd.h
|
||||||
bin/ui/statsby.o bin/ui/timesel.o bin/ui/statrange.o: src/lcd.h
|
bin/ui/statsby.o bin/ui/timesel.o bin/ui/statrange.o: src/lcd.h
|
||||||
bin/ui/datapoints.o: src/lcd.h
|
bin/ui/datapoints.o bin/ui/viewdatescreen.o: src/lcd.h
|
||||||
|
bin/ui/setdatescreen.o bin/ui/powerscreen.o: src/lcd.h
|
||||||
|
|
||||||
bin/main.o bin/ui/screen.o bin/ui/statsby.o: src/ui/screen.h
|
bin/main.o bin/ui/screen.o bin/ui/statsby.o: src/ui/screen.h
|
||||||
bin/ui/datesel.o bin/ui/datapoints.o bin/ui/timesel.o: src/ui/screen.h
|
bin/ui/datesel.o bin/ui/datapoints.o bin/ui/timesel.o: src/ui/screen.h
|
||||||
bin/ui/statrange.o: src/ui/screen.h
|
bin/ui/statrange.o bin/ui/setdatescreen.o: src/ui/screen.h
|
||||||
|
bin/ui/viewdatescreen.o bin/ui/powerscreen.o: src/ui/screen.h
|
||||||
|
|
||||||
bin/main.o bin/ui/datesel.o bin/ui/statsby.o: src/ui/datesel.h
|
bin/main.o bin/ui/datesel.o bin/ui/statsby.o: src/ui/datesel.h
|
||||||
bin/ui/datapoints.o bin/ui/timesel.o bin/ui/statrange.o: src/ui/datesel.h
|
bin/ui/datapoints.o bin/ui/timesel.o bin/ui/statrange.o: src/ui/datesel.h
|
||||||
|
bin/ui/setdatescreen.o: src/ui/datesel.h
|
||||||
|
|
||||||
bin/main.o bin/ui/timesel.o bin/ui/datapoints.o: src/ui/timesel.h
|
bin/main.o bin/ui/timesel.o bin/ui/datapoints.o: src/ui/timesel.h
|
||||||
bin/ui/statrange.o: src/ui/timesel.h
|
bin/ui/statrange.o bin/ui/setdatescreen.o: src/ui/timesel.h
|
||||||
|
|
||||||
bin/main.o bin/ths.o: src/ths.h
|
bin/main.o bin/ths.o: src/ths.h
|
||||||
bin/main.o bin/config.o: src/config.h
|
bin/main.o bin/config.o: src/config.h
|
||||||
@ -44,7 +49,10 @@ bin/main.o bin/ui/statsby.o: src/ui/statsby.h
|
|||||||
bin/main.o bin/ui/datapoints.o: src/ui/datapoints.h
|
bin/main.o bin/ui/datapoints.o: src/ui/datapoints.h
|
||||||
bin/main.o bin/ui/blankscreen.o: src/ui/blankscreen.h
|
bin/main.o bin/ui/blankscreen.o: src/ui/blankscreen.h
|
||||||
bin/main.o bin/ui/statrange.o: src/ui/statrange.h
|
bin/main.o bin/ui/statrange.o: src/ui/statrange.h
|
||||||
vin/main.o bin/ui/exportscreen.o: src/ui/exportscreen.h
|
bin/main.o bin/ui/exportscreen.o: src/ui/exportscreen.h
|
||||||
|
bin/main.o bin/ui/setdatescreen.o: src/ui/setdatescreen.h
|
||||||
|
bin/main.o bin/ui/viewdatescreen.o: src/ui/viewdatescreen.h
|
||||||
|
bin/main.o bin/ui/powerscreen.o: src/ui/powerscreen.h
|
||||||
bin/main.o bin/drive.o bin/ui/exportscreen.o: src/drive.h
|
bin/main.o bin/drive.o bin/ui/exportscreen.o: src/drive.h
|
||||||
|
|
||||||
.if "${DEFAULT_TEMP_UNIT}" != "F" && "${DEFAULT_TEMP_UNIT}" != "C" &&\
|
.if "${DEFAULT_TEMP_UNIT}" != "F" && "${DEFAULT_TEMP_UNIT}" != "C" &&\
|
||||||
|
@ -19,6 +19,9 @@
|
|||||||
#include "ui/statrange.h"
|
#include "ui/statrange.h"
|
||||||
#include "ui/blankscreen.h"
|
#include "ui/blankscreen.h"
|
||||||
#include "ui/exportscreen.h"
|
#include "ui/exportscreen.h"
|
||||||
|
#include "ui/viewdatescreen.h"
|
||||||
|
#include "ui/setdatescreen.h"
|
||||||
|
#include "ui/powerscreen.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
@ -118,6 +121,9 @@ int main(int argc, char *const *argv) {
|
|||||||
if (GLOBAL_OPTS.bl_pin >= 0) {
|
if (GLOBAL_OPTS.bl_pin >= 0) {
|
||||||
screen_manager_add(screen_manager, blank_screen_new());
|
screen_manager_add(screen_manager, blank_screen_new());
|
||||||
}
|
}
|
||||||
|
screen_manager_add(screen_manager, (Screen *) view_date_screen_new());
|
||||||
|
screen_manager_add(screen_manager, (Screen *) set_date_screen_new());
|
||||||
|
screen_manager_add(screen_manager, (Screen *) power_screen_new());
|
||||||
while (RUNNING) {
|
while (RUNNING) {
|
||||||
lock_stat_globals();
|
lock_stat_globals();
|
||||||
uint32_t temp = LAST_TEMP;
|
uint32_t temp = LAST_TEMP;
|
||||||
@ -127,6 +133,8 @@ int main(int argc, char *const *argv) {
|
|||||||
// 10ms is probably faster than anyone will press a button
|
// 10ms is probably faster than anyone will press a button
|
||||||
usleep(10 * 1000);
|
usleep(10 * 1000);
|
||||||
}
|
}
|
||||||
|
// this is mostly about LCD and DB cleanup, not freeing memory, this leaks a
|
||||||
|
// lot when caused from something other than the main screen
|
||||||
screen_manager_delete(screen_manager);
|
screen_manager_delete(screen_manager);
|
||||||
lcd_close(lcd);
|
lcd_close(lcd);
|
||||||
if (pthread_join(bg_update, NULL) != 0) {
|
if (pthread_join(bg_update, NULL) != 0) {
|
||||||
|
@ -13,8 +13,7 @@
|
|||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
|
||||||
void date_sel_init(DateSelection *ds, UtilPeriod limit_period) {
|
void date_sel_init(DateSelection *ds, UtilPeriod limit_period) {
|
||||||
memset(&ds->start_time, 0, sizeof(UtilDate)); // min date
|
ds->clamp_time = true;
|
||||||
memset(&ds->end_time, 0xff, sizeof(UtilDate)); // max date
|
|
||||||
date_sel_set_period(ds, limit_period);
|
date_sel_set_period(ds, limit_period);
|
||||||
date_sel_reset(ds);
|
date_sel_reset(ds);
|
||||||
}
|
}
|
||||||
@ -42,36 +41,38 @@ void date_sel_set_period(DateSelection *ds, UtilPeriod limit_period) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void date_sel_clamp_time(DateSelection *ds) {
|
static void date_sel_clamp_time(DateSelection *ds) {
|
||||||
if (ds->year > ds->end_time.local_year) {
|
if (ds->clamp_time) {
|
||||||
ds->year = ds->end_time.local_year;
|
if (ds->year > ds->end_time.local_year) {
|
||||||
}
|
ds->year = ds->end_time.local_year;
|
||||||
if (ds->year == ds->end_time.local_year &&
|
|
||||||
ds->month > ds->end_time.local_month) {
|
|
||||||
ds->month = ds->end_time.local_month;
|
|
||||||
if (ds->stage == DATE_SEL_DAY) {
|
|
||||||
// last days of previous month
|
|
||||||
ds->day = days_in_month(ds->month, ds->year);
|
|
||||||
}
|
}
|
||||||
}
|
if (ds->year == ds->end_time.local_year &&
|
||||||
if (ds->year == ds->end_time.local_year &&
|
ds->month > ds->end_time.local_month) {
|
||||||
ds->month == ds->end_time.local_month &&
|
ds->month = ds->end_time.local_month;
|
||||||
ds->day > ds->end_time.local_day) {
|
if (ds->stage == DATE_SEL_DAY) {
|
||||||
ds->day = ds->end_time.local_day;
|
// last days of previous month
|
||||||
}
|
ds->day = days_in_month(ds->month, ds->year);
|
||||||
if (ds->year < ds->start_time.local_year) {
|
}
|
||||||
ds->year = ds->start_time.local_year;
|
}
|
||||||
}
|
if (ds->year == ds->end_time.local_year &&
|
||||||
if (ds->year == ds->start_time.local_year &&
|
ds->month == ds->end_time.local_month &&
|
||||||
ds->month < ds->start_time.local_month) {
|
ds->day > ds->end_time.local_day) {
|
||||||
ds->month = ds->start_time.local_month;
|
ds->day = ds->end_time.local_day;
|
||||||
if (ds->stage == DATE_SEL_DAY) {
|
}
|
||||||
ds->day = 1; // first day of the next month
|
if (ds->year < ds->start_time.local_year) {
|
||||||
|
ds->year = ds->start_time.local_year;
|
||||||
|
}
|
||||||
|
if (ds->year == ds->start_time.local_year &&
|
||||||
|
ds->month < ds->start_time.local_month) {
|
||||||
|
ds->month = ds->start_time.local_month;
|
||||||
|
if (ds->stage == DATE_SEL_DAY) {
|
||||||
|
ds->day = 1; // first day of the next month
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ds->year == ds->start_time.local_year &&
|
||||||
|
ds->month == ds->start_time.local_month &&
|
||||||
|
ds->day < ds->start_time.local_day) {
|
||||||
|
ds->day = ds->start_time.local_day;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (ds->year == ds->start_time.local_year &&
|
|
||||||
ds->month == ds->start_time.local_month &&
|
|
||||||
ds->day < ds->start_time.local_day) {
|
|
||||||
ds->day = ds->start_time.local_day;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +97,6 @@ static void date_sel_cleanup(DateSelection *ds) {
|
|||||||
++ds->month;
|
++ds->month;
|
||||||
date_sel_cleanup(ds);
|
date_sel_cleanup(ds);
|
||||||
}
|
}
|
||||||
date_sel_clamp_time(ds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void date_sel_add_units(DateSelection *ds, int n) {
|
static void date_sel_add_units(DateSelection *ds, int n) {
|
||||||
@ -117,15 +117,17 @@ static void date_sel_add_units(DateSelection *ds, int n) {
|
|||||||
DateSelectionState date_sel_dispatch(DateSelection *ds,
|
DateSelectionState date_sel_dispatch(DateSelection *ds,
|
||||||
SensorState *state,
|
SensorState *state,
|
||||||
const char *label) {
|
const char *label) {
|
||||||
UtilDate start, end;
|
if (ds->clamp_time) {
|
||||||
if (!get_database_limits(state->db, ds->limit_period, &start, &end)) {
|
UtilDate start, end;
|
||||||
warnx("failed to query database limits");
|
if (!get_database_limits(state->db, ds->limit_period, &start, &end)) {
|
||||||
lcd_display_control(state->lcd, LCD_CURSOR_NO_BLINK, LCD_CURSOR_OFF,
|
warnx("failed to query database limits");
|
||||||
LCD_DISPLAY_ON);
|
lcd_display_control(state->lcd, LCD_CURSOR_NO_BLINK, LCD_CURSOR_OFF,
|
||||||
return DATE_SEL_ERROR;
|
LCD_DISPLAY_ON);
|
||||||
|
return DATE_SEL_ERROR;
|
||||||
|
}
|
||||||
|
ds->start_time = start;
|
||||||
|
ds->end_time = end;
|
||||||
}
|
}
|
||||||
ds->start_time = start;
|
|
||||||
ds->end_time = end;
|
|
||||||
lcd_clear(state->lcd);
|
lcd_clear(state->lcd);
|
||||||
lcd_move_to(state->lcd, 0, 0);
|
lcd_move_to(state->lcd, 0, 0);
|
||||||
lcd_write_string(state->lcd, label);
|
lcd_write_string(state->lcd, label);
|
||||||
@ -199,3 +201,7 @@ DateSelectionState date_sel_dispatch(DateSelection *ds,
|
|||||||
lcd_move_to(state->lcd, 1, cursor_pos);
|
lcd_move_to(state->lcd, 1, cursor_pos);
|
||||||
return DATE_SEL_CONTINUE;
|
return DATE_SEL_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void date_sel_set_clamp_time(DateSelection *ds, bool clamp_time) {
|
||||||
|
ds->clamp_time = clamp_time;
|
||||||
|
}
|
||||||
|
@ -28,6 +28,7 @@ typedef struct {
|
|||||||
UtilPeriod limit_period;
|
UtilPeriod limit_period;
|
||||||
UtilDate start_time;
|
UtilDate start_time;
|
||||||
UtilDate end_time;
|
UtilDate end_time;
|
||||||
|
bool clamp_time;
|
||||||
} DateSelection;
|
} DateSelection;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -61,4 +62,9 @@ DateSelectionState date_sel_dispatch(DateSelection *ds,
|
|||||||
SensorState *state,
|
SensorState *state,
|
||||||
const char *label);
|
const char *label);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set weather or not DS clamps time according to CLAMP_TIME.
|
||||||
|
*/
|
||||||
|
void date_sel_set_clamp_time(DateSelection *ds, bool clamp_time);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
75
src/ui/powerscreen.c
Normal file
75
src/ui/powerscreen.c
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* powerscreen.h - Screen for rebooting or halting
|
||||||
|
* Copyright (C) 2024 Alexander Rosenberg
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version. See the LICENSE file for more information.
|
||||||
|
*/
|
||||||
|
#include "powerscreen.h"
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/reboot.h>
|
||||||
|
|
||||||
|
static bool power_screen_dispatch(PowerScreen *screen,
|
||||||
|
SensorState *state) {
|
||||||
|
if (state->back_down) {
|
||||||
|
lcd_display_control(state->lcd, LCD_CURSOR_NO_BLINK, LCD_CURSOR_OFF,
|
||||||
|
LCD_DISPLAY_ON);
|
||||||
|
screen->choice = POWER_SCREEN_REBOOT;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (state->sel_down) {
|
||||||
|
switch (screen->choice) {
|
||||||
|
case POWER_SCREEN_REBOOT:
|
||||||
|
LOG_VERBOSE("Rebooting...");
|
||||||
|
reboot(RB_AUTOBOOT);
|
||||||
|
abort();
|
||||||
|
// how did we even get here???
|
||||||
|
break;
|
||||||
|
case POWER_SCREEN_POWEROFF:
|
||||||
|
LOG_VERBOSE("Powering off...");
|
||||||
|
reboot(RB_POWEROFF);
|
||||||
|
abort();
|
||||||
|
// how did we even get here???
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warnx("invalid power screen choice");
|
||||||
|
lcd_display_control(state->lcd, LCD_CURSOR_NO_BLINK, LCD_CURSOR_OFF,
|
||||||
|
LCD_DISPLAY_ON);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
screen->choice = abs((screen->choice + state->up_down - state->down_down) %
|
||||||
|
POWER_SCREEN_NCHOICE);
|
||||||
|
if (state->force_draw || state->up_down || state->down_down) {
|
||||||
|
lcd_clear(state->lcd);
|
||||||
|
lcd_move_to(state->lcd, 0, 0);
|
||||||
|
lcd_write_string(state->lcd, "Type:");
|
||||||
|
lcd_move_to(state->lcd, 1, 0);
|
||||||
|
lcd_write_char(state->lcd, '>');
|
||||||
|
switch (screen->choice) {
|
||||||
|
case POWER_SCREEN_REBOOT:
|
||||||
|
lcd_write_string(state->lcd, "REBOOT");
|
||||||
|
break;
|
||||||
|
case POWER_SCREEN_POWEROFF:
|
||||||
|
lcd_write_string(state->lcd, "POWEROFF");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lcd_display_control(state->lcd, LCD_CURSOR_BLINK, LCD_CURSOR_ON,
|
||||||
|
LCD_DISPLAY_ON);
|
||||||
|
lcd_move_to(state->lcd, 1, 0);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PowerScreen *power_screen_new(void) {
|
||||||
|
PowerScreen *s = malloc_checked(sizeof(PowerScreen));
|
||||||
|
screen_init(&s->parent, "Power options",
|
||||||
|
(ScreenDispatchFunc) power_screen_dispatch,
|
||||||
|
(ScreenCleanupFunc) free);
|
||||||
|
s->choice = POWER_SCREEN_REBOOT;
|
||||||
|
return s;
|
||||||
|
}
|
31
src/ui/powerscreen.h
Normal file
31
src/ui/powerscreen.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* powerscreen.h - Screen for rebooting or halting
|
||||||
|
* Copyright (C) 2024 Alexander Rosenberg
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version. See the LICENSE file for more information.
|
||||||
|
*/
|
||||||
|
#ifndef INCLUDED_POWERSCREEN_H
|
||||||
|
#define INCLUDED_POWERSCREEN_H
|
||||||
|
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Screen parent;
|
||||||
|
enum {
|
||||||
|
POWER_SCREEN_REBOOT = 0,
|
||||||
|
POWER_SCREEN_POWEROFF,
|
||||||
|
POWER_SCREEN_NCHOICE,
|
||||||
|
};
|
||||||
|
int choice;
|
||||||
|
} PowerScreen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new power screen that can be used to reboot or halt the device.
|
||||||
|
*/
|
||||||
|
PowerScreen *power_screen_new(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
157
src/ui/setdatescreen.c
Normal file
157
src/ui/setdatescreen.c
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* setdatescreen.c - Screen for setting the date and time
|
||||||
|
* Copyright (C) 2024 Alexander Rosenberg
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version. See the LICENSE file for more information.
|
||||||
|
*/
|
||||||
|
#include "setdatescreen.h"
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
static void set_date_reset(SetDateScreen *screen,
|
||||||
|
SensorState *state) {
|
||||||
|
date_sel_reset(&screen->ds);
|
||||||
|
time_sel_reset(&screen->ts);
|
||||||
|
screen->need_redraw = true;
|
||||||
|
screen->stage = SET_DATE_SELECT_DATE;
|
||||||
|
lcd_display_control(state->lcd, LCD_CURSOR_NO_BLINK, LCD_CURSOR_OFF,
|
||||||
|
LCD_DISPLAY_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool set_date_screen_select_date(SetDateScreen *screen,
|
||||||
|
SensorState *state) {
|
||||||
|
if (state->sel_down || state->back_down || state->up_down ||
|
||||||
|
state->down_down) {
|
||||||
|
screen->need_redraw = true;
|
||||||
|
}
|
||||||
|
if (screen->need_redraw) {
|
||||||
|
screen->need_redraw = false;
|
||||||
|
DateSelectionState dss = date_sel_dispatch(&screen->ds, state, "New Date:");
|
||||||
|
switch (dss) {
|
||||||
|
case DATE_SEL_CONTINUE:
|
||||||
|
return false; // ignore
|
||||||
|
case DATE_SEL_BACK:
|
||||||
|
return true;
|
||||||
|
case DATE_SEL_DONE:
|
||||||
|
screen->stage = SET_DATE_SELECT_TIME;
|
||||||
|
break;
|
||||||
|
case DATE_SEL_ERROR:
|
||||||
|
screen->stage = SET_DATE_FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
screen->need_redraw = true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool set_date_and_time(DateSelection *ds, TimeSelection *ts) {
|
||||||
|
int64_t utc_time = timedate_sel_to_uts_timestamp(ds, ts);
|
||||||
|
struct timeval new_time = {
|
||||||
|
.tv_sec = utc_time,
|
||||||
|
.tv_usec = 0, // can't set, user not fast enough (lol)
|
||||||
|
};
|
||||||
|
if (settimeofday(&new_time, NULL) < 0) {
|
||||||
|
warn("settimeofday(2) failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LOG_VERBOSE("Set system date and time to %04d/%02d/%02d %02d:%02d:%02d\n",
|
||||||
|
ds->year, ds->month, ds->day, ts->hour, ts->minute, ts->second);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_date_screen_select_time(SetDateScreen *screen,
|
||||||
|
SensorState *state) {
|
||||||
|
if (state->sel_down || state->back_down || state->up_down ||
|
||||||
|
state->down_down) {
|
||||||
|
screen->need_redraw = true;
|
||||||
|
}
|
||||||
|
if (screen->need_redraw) {
|
||||||
|
screen->need_redraw = false;
|
||||||
|
TimeSelState tss = time_sel_dispatch(&screen->ts, state, "New Time");
|
||||||
|
switch (tss) {
|
||||||
|
case TIME_SEL_CONTINUE:
|
||||||
|
return; // ignore
|
||||||
|
case TIME_SEL_BACK:
|
||||||
|
--screen->stage;
|
||||||
|
break;
|
||||||
|
case TIME_SEL_DONE:
|
||||||
|
if (set_date_and_time(&screen->ds, &screen->ts)) {
|
||||||
|
screen->stage = SET_DATE_SUCCESS;
|
||||||
|
} else {
|
||||||
|
screen->stage = SET_DATE_FAIL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TIME_SEL_ERROR:
|
||||||
|
screen->stage = SET_DATE_FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
screen->need_redraw = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool set_date_screen_message(SetDateScreen *screen,
|
||||||
|
SensorState *state,
|
||||||
|
const char *msg) {
|
||||||
|
if (state->up_down || state->down_down || state->sel_down ||
|
||||||
|
state->back_down) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (screen->need_redraw) {
|
||||||
|
screen->need_redraw = false;
|
||||||
|
lcd_clear(state->lcd);
|
||||||
|
lcd_move_to(state->lcd, 0, 0);
|
||||||
|
lcd_write_string(state->lcd, msg);
|
||||||
|
lcd_display_control(state->lcd, LCD_CURSOR_NO_BLINK, LCD_CURSOR_OFF,
|
||||||
|
LCD_DISPLAY_ON);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool set_date_screen_dispatch(SetDateScreen *screen,
|
||||||
|
SensorState *state) {
|
||||||
|
if (state->force_draw) {
|
||||||
|
screen->need_redraw = true;
|
||||||
|
}
|
||||||
|
switch (screen->stage) {
|
||||||
|
case SET_DATE_SELECT_DATE:
|
||||||
|
if (set_date_screen_select_date(screen, state)) {
|
||||||
|
set_date_reset(screen, state);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SET_DATE_SELECT_TIME:
|
||||||
|
set_date_screen_select_time(screen, state);
|
||||||
|
break;
|
||||||
|
case SET_DATE_FAIL:
|
||||||
|
if (set_date_screen_message(screen, state, "Fail!")) {
|
||||||
|
set_date_reset(screen, state);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SET_DATE_SUCCESS:
|
||||||
|
if (set_date_screen_message(screen, state, "Success!")) {
|
||||||
|
set_date_reset(screen, state);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDateScreen *set_date_screen_new() {
|
||||||
|
SetDateScreen *s = malloc_checked(sizeof(SetDateScreen));
|
||||||
|
screen_init(&s->parent, "Set date/time",
|
||||||
|
(ScreenDispatchFunc) set_date_screen_dispatch,
|
||||||
|
(ScreenCleanupFunc) free);
|
||||||
|
date_sel_init(&s->ds, PERIOD_DAY);
|
||||||
|
date_sel_set_clamp_time(&s->ds, false);
|
||||||
|
time_sel_init(&s->ts, NULL, true);
|
||||||
|
s->need_redraw = true;
|
||||||
|
s->stage = SET_DATE_SELECT_DATE;
|
||||||
|
return s;
|
||||||
|
}
|
35
src/ui/setdatescreen.h
Normal file
35
src/ui/setdatescreen.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* setdatescreen.h - Screen for setting the date and time
|
||||||
|
* Copyright (C) 2024 Alexander Rosenberg
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version. See the LICENSE file for more information.
|
||||||
|
*/
|
||||||
|
#ifndef INCLUDED_SETDATESCREEN_H
|
||||||
|
#define INCLUDED_SETDATESCREEN_H
|
||||||
|
|
||||||
|
#include "screen.h"
|
||||||
|
#include "timesel.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Screen parent;
|
||||||
|
enum {
|
||||||
|
SET_DATE_SELECT_DATE,
|
||||||
|
SET_DATE_SELECT_TIME,
|
||||||
|
SET_DATE_FAIL,
|
||||||
|
SET_DATE_SUCCESS
|
||||||
|
} stage;
|
||||||
|
bool need_redraw;
|
||||||
|
DateSelection ds;
|
||||||
|
TimeSelection ts;
|
||||||
|
} SetDateScreen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new SetDateScreen. This screen will allow the user to configure the
|
||||||
|
* date and time.
|
||||||
|
*/
|
||||||
|
SetDateScreen *set_date_screen_new(void);
|
||||||
|
|
||||||
|
#endif
|
@ -65,24 +65,6 @@ static void stat_range_handle_time(StatRangeScreen *screen, TimeSelection *ts,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t to_uts_timestamp(DateSelection *ds, TimeSelection *ts) {
|
|
||||||
struct tm broken_time = {
|
|
||||||
.tm_sec = ts->second,
|
|
||||||
.tm_min = ts->minute,
|
|
||||||
.tm_hour = ts->hour,
|
|
||||||
.tm_mday = ds->day,
|
|
||||||
.tm_mon = ds->month - 1,
|
|
||||||
.tm_year = ds->year - 1900,
|
|
||||||
.tm_isdst = -1,
|
|
||||||
};
|
|
||||||
time_t it = mktime(&broken_time);
|
|
||||||
if (it < 0) {
|
|
||||||
warnx("failed to convert to UTC timestamp");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stat_range_show_data(StatRangeScreen *screen, SensorState *state) {
|
static void stat_range_show_data(StatRangeScreen *screen, SensorState *state) {
|
||||||
if (state->back_down) {
|
if (state->back_down) {
|
||||||
screen->need_redraw = true;
|
screen->need_redraw = true;
|
||||||
@ -99,10 +81,10 @@ static void stat_range_show_data(StatRangeScreen *screen, SensorState *state) {
|
|||||||
}
|
}
|
||||||
if (screen->need_redraw) {
|
if (screen->need_redraw) {
|
||||||
screen->need_redraw = false;
|
screen->need_redraw = false;
|
||||||
uint64_t start = to_uts_timestamp(&screen->sds, &screen->sts);
|
int64_t start = timedate_sel_to_uts_timestamp(&screen->sds, &screen->sts);
|
||||||
uint64_t end = to_uts_timestamp(&screen->eds, &screen->ets);
|
int64_t end = timedate_sel_to_uts_timestamp(&screen->eds, &screen->ets);
|
||||||
if (start > end) {
|
if (start > end) {
|
||||||
uint64_t t = end;
|
int64_t t = end;
|
||||||
end = start;
|
end = start;
|
||||||
start = t;
|
start = t;
|
||||||
}
|
}
|
||||||
|
@ -173,3 +173,21 @@ void time_sel_reset(TimeSelection *ts) {
|
|||||||
ts->minute = 0;
|
ts->minute = 0;
|
||||||
ts->stage = TS_STAGE_HOUR;
|
ts->stage = TS_STAGE_HOUR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t timedate_sel_to_uts_timestamp(DateSelection *ds, TimeSelection *ts) {
|
||||||
|
struct tm broken_time = {
|
||||||
|
.tm_sec = ts->second,
|
||||||
|
.tm_min = ts->minute,
|
||||||
|
.tm_hour = ts->hour,
|
||||||
|
.tm_mday = ds->day,
|
||||||
|
.tm_mon = ds->month - 1,
|
||||||
|
.tm_year = ds->year - 1900,
|
||||||
|
.tm_isdst = -1,
|
||||||
|
};
|
||||||
|
time_t it = mktime(&broken_time);
|
||||||
|
if (it < 0) {
|
||||||
|
warnx("failed to convert to UTC timestamp");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
@ -52,4 +52,9 @@ TimeSelState time_sel_dispatch(TimeSelection *ts, SensorState *state,
|
|||||||
*/
|
*/
|
||||||
void time_sel_reset(TimeSelection *ts);
|
void time_sel_reset(TimeSelection *ts);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert DS and TS to a UTC timestamp;
|
||||||
|
*/
|
||||||
|
int64_t timedate_sel_to_uts_timestamp(DateSelection *ds, TimeSelection *ts);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
45
src/ui/viewdatescreen.c
Normal file
45
src/ui/viewdatescreen.c
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* viewdatescreen.c - Screen for viewing the date and time
|
||||||
|
* Copyright (C) 2024 Alexander Rosenberg
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version. See the LICENSE file for more information.
|
||||||
|
*/
|
||||||
|
#include "viewdatescreen.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
static bool view_date_screen_dispatch(ViewDateScreen *screen,
|
||||||
|
SensorState *state) {
|
||||||
|
time_t now = time(NULL);
|
||||||
|
if (state->back_down || state->sel_down || state->up_down ||
|
||||||
|
state->down_down) {
|
||||||
|
return true;
|
||||||
|
} else if (state->force_draw || now != screen->last_time) {
|
||||||
|
screen->last_time = now;
|
||||||
|
lcd_clear(state->lcd);
|
||||||
|
struct tm broken_time;
|
||||||
|
localtime_r(&now, &broken_time);
|
||||||
|
char buf[17];
|
||||||
|
snprintf(buf, 17, "%04d/%02d/%02d", broken_time.tm_year + 1900,
|
||||||
|
broken_time.tm_mon + 1, broken_time.tm_mday);
|
||||||
|
lcd_move_to(state->lcd, 0, 0);
|
||||||
|
lcd_write_string(state->lcd, buf);
|
||||||
|
snprintf(buf, 17, "%02d:%02d:%02d", broken_time.tm_hour,
|
||||||
|
broken_time.tm_min, broken_time.tm_sec);
|
||||||
|
lcd_move_to(state->lcd, 1, 0);
|
||||||
|
lcd_write_string(state->lcd, buf);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewDateScreen *view_date_screen_new() {
|
||||||
|
ViewDateScreen *s = malloc_checked(sizeof(ViewDateScreen));
|
||||||
|
screen_init(&s->parent, "View date/time",
|
||||||
|
(ScreenDispatchFunc) view_date_screen_dispatch,
|
||||||
|
(ScreenCleanupFunc) free);
|
||||||
|
s->last_time = INT64_MIN;
|
||||||
|
return s;
|
||||||
|
}
|
25
src/ui/viewdatescreen.h
Normal file
25
src/ui/viewdatescreen.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* viewdatescreen.h - Screen for viewing the date and time
|
||||||
|
* Copyright (C) 2024 Alexander Rosenberg
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version. See the LICENSE file for more information.
|
||||||
|
*/
|
||||||
|
#ifndef INCLUDED_VIEWDATESCREEN_H
|
||||||
|
#define INCLUDED_VIEWDATESCREEN_H
|
||||||
|
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Screen parent;
|
||||||
|
int64_t last_time;
|
||||||
|
} ViewDateScreen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new view date screen that shows the user the current date and time.
|
||||||
|
*/
|
||||||
|
ViewDateScreen *view_date_screen_new(void);
|
||||||
|
|
||||||
|
#endif
|
@ -357,7 +357,7 @@ bool get_data_point_info(sqlite3 *db, int64_t time, UtilDataPointInfo *info) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get_average_for_range(sqlite3 *db, uint64_t start, uint64_t end,
|
bool get_average_for_range(sqlite3 *db, int64_t start, int64_t end,
|
||||||
UtilAverageRange *data) {
|
UtilAverageRange *data) {
|
||||||
bool success = true;
|
bool success = true;
|
||||||
sqlite3_bind_int64(AVG_FOR_RANGE_QUERY, 1, start);
|
sqlite3_bind_int64(AVG_FOR_RANGE_QUERY, 1, start);
|
||||||
|
@ -203,7 +203,7 @@ typedef struct {
|
|||||||
* Get the average DATA for the range of UTC times START to END (inclusive).
|
* Get the average DATA for the range of UTC times START to END (inclusive).
|
||||||
* Return: false if an error occurred, true otherwise.
|
* Return: false if an error occurred, true otherwise.
|
||||||
*/
|
*/
|
||||||
bool get_average_for_range(sqlite3 *db, uint64_t start, uint64_t end,
|
bool get_average_for_range(sqlite3 *db, int64_t start, int64_t end,
|
||||||
UtilAverageRange *data);
|
UtilAverageRange *data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user