]> git.scottworley.com Git - batteryviewer/blame - batteryviewer.c
Grab the current time
[batteryviewer] / batteryviewer.c
CommitLineData
ef0963b8
SW
1// For vasprintf
2#define _GNU_SOURCE
3
5a945372 4#include "chart.h"
0f9e308a
SW
5#include <ctype.h>
6#include <errno.h>
eda1f8c1 7#include <glob.h>
79ac753b 8#include <gtk/gtk.h>
0f9e308a 9#include <math.h>
ef0963b8 10#include <stdarg.h>
0f9e308a
SW
11#include <stdio.h>
12#include <stdlib.h>
eda1f8c1 13#include <string.h>
0f9e308a 14
ef0963b8
SW
15char *sasprintf(const char *fmt, ...) {
16 char *result;
17 va_list args;
18 va_start(args, fmt);
19 if (vasprintf(&result, fmt, args) == -1) {
20 fprintf(stderr, "Can't allocate memory!?\n");
21 abort();
22 }
23 va_end(args);
24 return result;
25}
26
fc1a2773 27struct State {
7281755a
SW
28 char *voltage_filename;
29 char *current_filename;
fc1a2773
SW
30 BVChart *voltage;
31 BVChart *current;
32};
33
0f9e308a
SW
34static float fatof(const char *filename) {
35 FILE *f = fopen(filename, "r");
36 if (f == NULL) {
37 return NAN;
38 }
39
40 const int bufsize = 1024;
41 char buf[bufsize];
42 const int read = fread(buf, sizeof(char), bufsize, f);
43 if (read == 0 || read == bufsize || ferror(f)) {
44 fclose(f);
45 return NAN;
46 }
47 fclose(f);
48
49 char *end;
50 errno = 0;
51 float val = strtof(buf, &end);
52 int parsed = end - buf;
53 gboolean parsed_all = parsed == read;
54 gboolean parsed_all_but_space = parsed == read - 1 && isspace(*end);
55 gboolean parse_ok = parsed_all || parsed_all_but_space;
56 if (errno != 0 || parsed == 0 || !parse_ok) {
57 return NAN;
58 }
59 return val;
60}
61
7281755a 62static gboolean collect_data(struct State *state) {
51a39b46
SW
63 float now = g_get_monotonic_time() / 1e6;
64 fprintf(stderr, "%f: Voltage: %f, current: %f\n", now,
65 fatof(state->voltage_filename), fatof(state->current_filename));
6f50819e
SW
66 return TRUE;
67}
68
fc1a2773 69static void activate(GtkApplication *app, gpointer user_data) {
79ac753b 70
cecfa926 71 GtkWidget *window = gtk_application_window_new(app);
a8d35c4c 72 gtk_window_set_title(GTK_WINDOW(window), "BatteryViewer");
79ac753b
SW
73 gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
74
1bd5b327
SW
75 GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 1);
76 gtk_container_add(GTK_CONTAINER(window), box);
77
fc1a2773
SW
78 struct State *state = (struct State *)user_data;
79 state->voltage = BV_CHART(bv_chart_new());
80 bv_chart_add_point(state->voltage, 0.0, 0.0);
81 bv_chart_add_point(state->voltage, 1.0, 1.0);
82 bv_chart_add_point(state->voltage, 3.0, 2.0);
1bd5b327
SW
83 gboolean expand = TRUE;
84 gboolean fill = TRUE;
85 guint padding = 0;
fc1a2773
SW
86 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(state->voltage), expand, fill,
87 padding);
1bd5b327 88
fc1a2773
SW
89 state->current = BV_CHART(bv_chart_new());
90 bv_chart_add_point(state->current, 0.0, 1.0);
91 bv_chart_add_point(state->current, 1.0, 0.0);
92 gtk_box_pack_end(GTK_BOX(box), GTK_WIDGET(state->current), expand, fill,
93 padding);
79ac753b 94
a9a80e4e 95 gtk_widget_show_all(window);
6f50819e
SW
96
97 g_timeout_add_seconds(1, (GSourceFunc)collect_data, user_data);
79ac753b
SW
98}
99
eda1f8c1
SW
100char *find_battery_dir() {
101 glob_t globbuf = {.gl_offs = 0};
102 char pattern[] = "/sys/class/power_supply/*[Bb][Aa][Tt]*";
103 if (glob(pattern, GLOB_ERR, NULL, &globbuf) != 0 || globbuf.gl_pathc == 0) {
104 fprintf(stderr, "Could not find battery dir %s\n", pattern);
105 exit(1);
106 }
107 if (globbuf.gl_pathc != 1) {
108 // TODO: Filter for directories that have {voltage,current}_now files.
109 // TODO: Support multiple batteries
110 fprintf(stderr, "Multiple batteries found. Arbitrarily choosing %s\n",
111 globbuf.gl_pathv[0]);
112 }
113 char *dir = strdup(globbuf.gl_pathv[0]);
114 globfree(&globbuf);
115 return dir;
116}
117
79ac753b 118int main(int argc, char **argv) {
eda1f8c1 119 char *battery_dir = find_battery_dir();
7281755a 120 struct State state = {
ef0963b8
SW
121 .voltage_filename = sasprintf("%s/voltage_now", battery_dir),
122 .current_filename = sasprintf("%s/current_now", battery_dir),
7281755a 123 };
79ac753b 124
a8d35c4c
SW
125 GtkApplication *app = gtk_application_new("com.scottworley.batteryviewer",
126 G_APPLICATION_DEFAULT_FLAGS);
fc1a2773 127 g_signal_connect(app, "activate", G_CALLBACK(activate), &state);
cecfa926 128 int status = g_application_run(G_APPLICATION(app), argc, argv);
79ac753b
SW
129 g_object_unref(app);
130
131 return status;
132}