+static float fatof(const char *filename) {
+ FILE *f = fopen(filename, "r");
+ if (f == NULL) {
+ return NAN;
+ }
+
+ const int bufsize = 1024;
+ char buf[bufsize];
+ const int read = fread(buf, sizeof(char), bufsize, f);
+ if (read == 0 || read == bufsize || ferror(f)) {
+ fclose(f);
+ return NAN;
+ }
+ fclose(f);
+
+ char *end;
+ errno = 0;
+ float val = strtof(buf, &end);
+ int parsed = end - buf;
+ gboolean parsed_all = parsed == read;
+ gboolean parsed_all_but_space = parsed == read - 1 && isspace(*end);
+ gboolean parse_ok = parsed_all || parsed_all_but_space;
+ if (errno != 0 || parsed == 0 || !parse_ok) {
+ return NAN;
+ }
+ return val;
+}
+
+static gboolean collect_data(struct State *state) {
+ float now = g_get_monotonic_time() / 1e6;
+ float voltage = fatof(state->voltage_filename);
+ float current = fatof(state->current_filename);
+ if (!isnan(voltage)) {
+ bv_chart_add_point(state->voltage, now, voltage);
+ gtk_widget_queue_draw(GTK_WIDGET(state->voltage));
+ }
+ if (!isnan(current)) {
+ bv_chart_add_point(state->current, now, current);
+ gtk_widget_queue_draw(GTK_WIDGET(state->current));
+ }
+ return TRUE;
+}
+
+static void activate(GtkApplication *app, gpointer user_data) {