*/
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
+#include <ctype.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#define SCREEN_HEIGHT 480
#define WIDTH 80
#define HEIGHT 480
-#define MEM_SIZE (((WIDTH * HEIGHT * 2 * 2) + 0xfff) & ~0xfff)
#define Y_STEP 9
static struct fb_var_screeninfo g_vi;
static uint16_t *g_screen_base, *g_screen;
+static struct {
+ int x, y, w, h;
+} g_layer;
+static unsigned int g_mem_size;
static unsigned int g_old_mem;
-static int g_fd, g_exit;
+static int g_flip_id;
+static int g_exit, g_hide;
+static pthread_cond_t g_cond;
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#define PAGE_ALIGN(x) (((x) + 0xfff) & ~0xfff)
#define IS_START(buf, str) \
!strncmp(buf, str, sizeof(str) - 1)
-static int setup_layer(void)
+static void clear_bytes(void *mem, int bytes);
+
+static int setup_layer(int fd)
{
- static const char fbname[] = "/dev/fb2";
struct omapfb_plane_info pi;
struct omapfb_mem_info mi;
struct omapfb_color_key key;
int ret;
- g_fd = open(fbname, O_RDWR);
- if (g_fd == -1) {
- fprintf(stderr, "open %s: ", fbname);
- perror(NULL);
- return 1;
- }
-
- ret = ioctl(g_fd, OMAPFB_QUERY_PLANE, &pi);
+ ret = ioctl(fd, OMAPFB_QUERY_PLANE, &pi);
if (ret < 0) {
perror("ioctl OMAPFB_QUERY_PLANE");
return 1;
}
- ret = ioctl(g_fd, OMAPFB_QUERY_MEM, &mi);
+ ret = ioctl(fd, OMAPFB_QUERY_MEM, &mi);
if (ret < 0) {
perror("ioctl OMAPFB_QUERY_MEM");
return 1;
/* must disable when changing stuff */
if (pi.enabled) {
pi.enabled = 0;
- ret = ioctl(g_fd, OMAPFB_SETUP_PLANE, &pi);
+ ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
if (ret < 0) {
perror("ioctl OMAPFB_SETUP_PLANE (d)");
return 1;
}
g_old_mem = mi.size;
- if (mi.size < MEM_SIZE) {
- mi.size = MEM_SIZE;
- ret = ioctl(g_fd, OMAPFB_SETUP_MEM, &mi);
+ g_mem_size = PAGE_ALIGN(g_layer.w * g_layer.h * 2 * 2);
+ if (mi.size < g_mem_size) {
+ mi.size = g_mem_size;
+ ret = ioctl(fd, OMAPFB_SETUP_MEM, &mi);
if (ret < 0) {
perror("ioctl SETUP_MEM");
return 1;
}
}
- pi.pos_x = SCREEN_WIDTH - WIDTH;
- pi.pos_y = 0;
- pi.out_width = WIDTH;
- pi.out_height = HEIGHT;
- ret = ioctl(g_fd, OMAPFB_SETUP_PLANE, &pi);
+ printf("layer: %d %d %d %d\n",
+ g_layer.x, g_layer.y, g_layer.w, g_layer.h);
+
+ pi.pos_x = g_layer.x;
+ pi.pos_y = g_layer.y;
+ pi.out_width = g_layer.w;
+ pi.out_height = g_layer.h;
+ ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
if (ret < 0) {
perror("ioctl OMAPFB_SETUP_PLANE (e1)");
return 1;
}
- ret = ioctl(g_fd, FBIOGET_VSCREENINFO, &g_vi);
+ ret = ioctl(fd, FBIOGET_VSCREENINFO, &g_vi);
if (ret < 0) {
perror("ioctl FBIOGET_VSCREENINFO");
return 1;
}
- g_vi.xres = g_vi.xres_virtual = WIDTH;
- g_vi.yres = HEIGHT;
- g_vi.yres_virtual = HEIGHT * 2;
+ g_vi.xres = g_vi.xres_virtual = g_layer.w;
+ g_vi.yres = g_layer.h;
+ g_vi.yres_virtual = g_layer.h * 2;
g_vi.bits_per_pixel = 16;
- ret = ioctl(g_fd, FBIOPUT_VSCREENINFO, &g_vi);
+ ret = ioctl(fd, FBIOPUT_VSCREENINFO, &g_vi);
if (ret < 0) {
perror("ioctl FBIOPUT_VSCREENINFO");
return 1;
}
pi.enabled = 1;
- ret = ioctl(g_fd, OMAPFB_SETUP_PLANE, &pi);
+ ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
if (ret < 0) {
perror("ioctl OMAPFB_SETUP_PLANE (e2)");
return 1;
key.key_type = OMAPFB_COLOR_KEY_VID_SRC;
key.trans_key = 0x07e0;
- ret = ioctl(g_fd, OMAPFB_SET_COLOR_KEY, &key);
- if (ret < 0) {
- perror("ioctl OMAPFB_SET_COLOR_KEY");
+ ret = ioctl(fd, OMAPFB_SET_COLOR_KEY, &key);
+ if (ret < 0) {
+ perror("ioctl OMAPFB_SET_COLOR_KEY");
return 1;
- }
+ }
+
+ g_screen_base = mmap(NULL, g_mem_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (g_screen_base == MAP_FAILED) {
+ perror("mmap");
+ g_screen = g_screen_base = NULL;
+ return 1;
+ }
+ clear_bytes(g_screen_base, g_mem_size);
+ g_screen = g_screen_base;
+ g_flip_id = 0;
return 0;
}
-static int check_layer(void)
+static int check_layer(int fd)
{
struct omapfb_plane_info pi;
int ret;
- ret = ioctl(g_fd, OMAPFB_QUERY_PLANE, &pi);
+ ret = ioctl(fd, OMAPFB_QUERY_PLANE, &pi);
if (ret < 0) {
perror("ioctl OMAPFB_QUERY_PLANE");
return 1;
return 0;
}
-static void remove_layer(void)
+static void remove_layer(int fd)
{
struct omapfb_plane_info pi;
struct omapfb_mem_info mi;
int ret;
+ if (g_screen_base != NULL) {
+ munmap(g_screen_base, g_mem_size);
+ g_screen = g_screen_base = NULL;
+ }
+
memset(&pi, 0, sizeof(pi));
pi.enabled = 0;
- ret = ioctl(g_fd, OMAPFB_SETUP_PLANE, &pi);
+ ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
if (ret < 0)
perror("ioctl OMAPFB_SETUP_PLANE (c)");
- ret = ioctl(g_fd, OMAPFB_QUERY_MEM, &mi);
+ ret = ioctl(fd, OMAPFB_QUERY_MEM, &mi);
if (ret < 0) {
perror("ioctl OMAPFB_QUERY_MEM");
goto out;
if (mi.size != g_old_mem) {
mi.size = g_old_mem;
- ret = ioctl(g_fd, OMAPFB_SETUP_MEM, &mi);
+ ret = ioctl(fd, OMAPFB_SETUP_MEM, &mi);
if (ret < 0) {
perror("ioctl SETUP_MEM");
goto out;
}
}
-out:
- close(g_fd);
- g_fd = -1;
+out:;
}
-static void handle_signal(int num)
+static void flip_fb(int fd)
+{
+ g_vi.yoffset = g_flip_id * g_layer.h;
+ ioctl(fd, FBIOPAN_DISPLAY, &g_vi);
+ g_flip_id ^= 1;
+ g_screen = g_screen_base + g_flip_id * g_layer.w * g_layer.h;
+}
+
+static void handle_term(int num)
{
g_exit = 1;
+ pthread_cond_signal(&g_cond);
}
-static void flip_fb(void)
+static void handle_usr1(int num)
{
- static int id;
+ g_hide = !g_hide;
+ pthread_cond_signal(&g_cond);
+}
+
+static struct {
+ char text[16];
+ int idle;
+} user_msgs[16];
+
+static int handle_socket(int sock)
+{
+ char buf[256], *p;
+ int i, ret;
+
+ ret = recv(sock, buf, sizeof(buf) - 1, 0);
+ if (ret < 0) {
+ perror("recv");
+ return ret;
+ }
+ if (ret == 0)
+ return 0;
+
+ buf[ret] = 0;
+ p = strchr(buf, ':');
+ if (p != NULL) {
+ for (i = 0; i < ARRAY_SIZE(user_msgs); i++) {
+ if (user_msgs[i].text[0] == 0)
+ break;
+ if (!strncmp(user_msgs[i].text, buf, p - buf + 1))
+ break;
+ }
+ if (i == ARRAY_SIZE(user_msgs)) {
+ printf("out of user_msg slots\n");
+ return 0;
+ }
+ memcpy(user_msgs[i].text, buf, sizeof(user_msgs[i].text) - 1);
+ user_msgs[i].text[sizeof(user_msgs[i].text) - 1] = 0;
+ user_msgs[i].idle = 0;
+ }
+ else if (!strcmp(buf, "poke")) {
+ // if hidden, show up
+ // if visible, exit
+ if (g_hide) {
+ g_hide = 0;
+ return 1;
+ }
+ g_exit = 1;
+ return 1;
+ }
+ else if (!strcmp(buf, "hide")) {
+ g_hide = 1;
+ return 1;
+ }
+ else if (!strcmp(buf, "show")) {
+ g_hide = 0;
+ return 1;
+ }
+ else if (!strcmp(buf, "quit")) {
+ g_exit = 1;
+ return 1;
+ }
+ else {
+ printf("unknown command: '%s'\n", buf);
+ }
+
+ return 0;
+}
+
+static void default_config(void)
+{
+ g_layer.x = SCREEN_WIDTH - WIDTH;
+ g_layer.y = 0;
+ g_layer.w = WIDTH;
+ g_layer.h = HEIGHT;
+}
+
+static void handle_config(void)
+{
+ char buf[256], *p;
+ int x, y, v;
+ FILE *f;
+
+ default_config();
+
+ f = fopen("config.cfg", "r");
+ if (f == NULL)
+ return;
- g_vi.yoffset = id * HEIGHT;
- ioctl(g_fd, FBIOPAN_DISPLAY, &g_vi);
- id ^= 1;
- g_screen = g_screen_base + id * WIDTH * HEIGHT;
+ while ((p = fgets(buf, sizeof(buf), f))) {
+ while (isspace(*p))
+ p++;
+ if (*p == '#' || *p == ';' || *p == 0)
+ continue;
+
+ if (sscanf(p, "position = %d %d", &x, &y) == 2) {
+ g_layer.x = x;
+ g_layer.y = y;
+ }
+ else {
+ printf("unhandled config entry: '%s'\n", p);
+ }
+ }
+ fclose(f);
+
+ v = SCREEN_WIDTH - g_layer.x;
+ if (v <= 0) {
+ printf("bad x position in config: %d\n", g_layer.x);
+ default_config();
+ return;
+ }
+ if (v < WIDTH)
+ g_layer.w = v;
+
+ v = SCREEN_HEIGHT - g_layer.y;
+ if (v <= 0) {
+ printf("bad y position in config: %d\n", g_layer.y);
+ default_config();
+ return;
+ }
+ if (v < HEIGHT)
+ g_layer.h = v;
}
-#define s_printf(x, y, fmt, ...) \
- basic_text_out16(g_screen, WIDTH, x, y, fmt, ##__VA_ARGS__);
+#define s_printf(x, y, fmt, ...) do { \
+ if ((y) <= g_layer.h - 8) \
+ basic_text_out16(g_screen, g_layer.w, x, y, fmt, ##__VA_ARGS__); \
+} while (0)
static int read_int_file(const char *fn, int *val)
{
return 0;
}
-static void clear(int h)
+static void clear_bytes(void *mem, int bytes)
{
- int *p = (int *)g_screen;
- int l = WIDTH * h / 2;
+ int *p = mem;
+ int l = bytes / 4;
for (; l >= 4; l -= 4, p += 4)
p[0] = p[1] = p[2] = p[3] = 0x07e007e0;
*p = 0x07e007e0;
}
+static void clear(int h)
+{
+ if (h > g_layer.h)
+ h = g_layer.h;
+
+ clear_bytes(g_screen, g_layer.w * h * 2);
+}
+
struct proc_stat {
unsigned long idlesum;
unsigned long sys;
int main(int argc, char *argv[])
{
- static const char socket_name[] = "\0livestats";
+ static const char socket_name[] = "\0liveinfo";
+ static const char fbname[] = "/dev/fb2";
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- pthread_cond_t cond;
pthread_condattr_t condattr;
struct sockaddr_un sun;
struct timespec ts;
struct pollfd pfd;
+ const char *p;
+ int is_hidden = 0;
int y = 0, y_max = 0;
+ int fd = -1;
int sock;
- int ret;
+ int i, ret;
// look for other instance
- sock = socket(PF_UNIX, SOCK_STREAM, 0);
+ sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if (sock == -1) {
perror("socket PF_UNIX");
return 1;
ret = connect(sock, (struct sockaddr *)&sun, sizeof(sun));
if (ret == 0) {
- printf("other instance detected, sending quit command\n");
- ret = send(sock, "quit", 4, 0);
+ printf("other instance detected, sending poke command\n");
+ ret = send(sock, "poke", 4, 0);
if (ret != 4)
perror("send");
close(sock);
- return 0;
+ return ret == 4 ? 0 : 1;
}
- // bind/listen for quit command
+ // load the config
+ handle_config();
+
+ fd = open(fbname, O_RDWR);
+ if (fd == -1) {
+ fprintf(stderr, "open %s: ", fbname);
+ perror(NULL);
+ return 1;
+ }
+
+ nice(-1);
+
+ // no need for privileges any more
+ p = getenv("SUDO_UID");
+ if (p != NULL) {
+ ret = atoi(p);
+ if (ret != 0) {
+ ret = setuid(ret);
+ if (ret)
+ perror("setuid");
+ }
+ }
+
+ // bind/listen for commands
ret = bind(sock, (struct sockaddr *)&sun, sizeof(sun));
if (ret != 0) {
perror("bind");
return 1;
}
+#if 0
ret = listen(sock, 1);
if (ret != 0) {
perror("listen");
close(sock);
return 1;
}
+#endif
pfd.fd = sock;
pfd.events = POLLIN | POLLPRI;
pfd.revents = 0;
- // clean up on kill too
- signal(SIGTERM, handle_signal);
-
ret = pthread_condattr_init(&condattr);
ret |= pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
- ret |= pthread_cond_init(&cond, &condattr);
+ ret |= pthread_cond_init(&g_cond, &condattr);
pthread_condattr_destroy(&condattr);
if (ret != 0) {
fprintf(stderr, "cond init failed\n");
return 1;
}
- ret = setup_layer();
+ ret = setup_layer(fd);
if (ret)
return ret;
- g_screen_base = mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE,
- MAP_SHARED, g_fd, 0);
- if (g_screen_base == MAP_FAILED) {
- perror("mmap");
- return 1;
- }
- g_screen = g_screen_base;
- clear(HEIGHT);
- flip_fb();
- clear(HEIGHT);
+ // clean up on kill too
+ signal(SIGTERM, handle_term);
+ signal(SIGUSR1, handle_usr1);
pthread_mutex_lock(&mutex);
ret = clock_gettime(CLOCK_MONOTONIC, &ts);
return 1;
}
- nice(-1);
init_stats();
- while (!g_exit) {
+ while (!g_exit)
+ {
+ // anything on unix socket?
+ ret = poll(&pfd, 1, 0);
+ if (ret < 0) {
+ perror("poll");
+ break;
+ }
+ if (ret > 0) {
+ ret = handle_socket(sock);
+ if (ret < 0)
+ break;
+ continue;
+ }
+
+ // handle hiding
+ if (g_hide) {
+ if (!is_hidden) {
+ remove_layer(fd);
+ is_hidden = 1;
+ }
+ goto do_sleep;
+ }
+ else if (is_hidden) {
+ ret = setup_layer(fd);
+ if (ret)
+ break;
+ is_hidden = 0;
+ }
+
+ if (check_layer(fd) != 0)
+ break;
+
collect_stats();
y += Y_STEP;
get_bwatts (0, y += Y_STEP);
get_btemp (0, y += Y_STEP);
- flip_fb();
-
- if (check_layer() != 0)
- break;
- ret = poll(&pfd, 1, 0);
- if (ret != 0) {
- printf("poll returned %d\n", ret);
- break;
+ // print user messages
+ y += Y_STEP;
+ for (i = 0; i < ARRAY_SIZE(user_msgs); i++) {
+ if (user_msgs[i].text[0] == 0)
+ break;
+ user_msgs[i].idle++;
+ if (user_msgs[i].idle > 6) {
+ // drop old entry, shift others up
+ memmove(&user_msgs[i], &user_msgs[i + 1],
+ (ARRAY_SIZE(user_msgs) - i - 1) * sizeof(user_msgs[0]));
+ user_msgs[ARRAY_SIZE(user_msgs) - 1].text[0] = 0;
+ // reprocess
+ i--;
+ continue;
+ }
+
+ s_printf(0, y += Y_STEP, user_msgs[i].text);
}
+ flip_fb(fd);
+
+do_sleep:
ts.tv_sec++;
- pthread_cond_timedwait(&cond, &mutex, &ts);
+ pthread_cond_timedwait(&g_cond, &mutex, &ts);
}
- munmap(g_screen_base, MEM_SIZE);
- remove_layer();
+ remove_layer(fd);
+ close(fd);
close(sock);
return 0;