--- /dev/null
+#include <stdio.h>
+#include <stdarg.h>
+
+unsigned char fontdata8x8[64*16] =
+{
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x3C,0x42,0x99,0xBD,0xBD,0x99,0x42,0x3C,0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C,
+ 0xFE,0x82,0x8A,0xD2,0xA2,0x82,0xFE,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00,
+ 0x80,0xC0,0xF0,0xFC,0xF0,0xC0,0x80,0x00,0x01,0x03,0x0F,0x3F,0x0F,0x03,0x01,0x00,
+ 0x18,0x3C,0x7E,0x18,0x7E,0x3C,0x18,0x00,0xEE,0xEE,0xEE,0xCC,0x00,0xCC,0xCC,0x00,
+ 0x00,0x00,0x30,0x68,0x78,0x30,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00,
+ 0x3C,0x66,0x7A,0x7A,0x7E,0x7E,0x3C,0x00,0x0E,0x3E,0x3A,0x22,0x26,0x6E,0xE4,0x40,
+ 0x18,0x3C,0x7E,0x3C,0x3C,0x3C,0x3C,0x00,0x3C,0x3C,0x3C,0x3C,0x7E,0x3C,0x18,0x00,
+ 0x08,0x7C,0x7E,0x7E,0x7C,0x08,0x00,0x00,0x10,0x3E,0x7E,0x7E,0x3E,0x10,0x00,0x00,
+ 0x58,0x2A,0xDC,0xC8,0xDC,0x2A,0x58,0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00,
+ 0x00,0x10,0x10,0x38,0x38,0x7C,0xFE,0x00,0xFE,0x7C,0x38,0x38,0x10,0x10,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x18,0x00,0x18,0x18,0x00,
+ 0x6C,0x6C,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7C,0x28,0x7C,0x28,0x00,0x00,
+ 0x10,0x38,0x60,0x38,0x0C,0x78,0x10,0x00,0x40,0xA4,0x48,0x10,0x24,0x4A,0x04,0x00,
+ 0x18,0x34,0x18,0x3A,0x6C,0x66,0x3A,0x00,0x18,0x18,0x20,0x00,0x00,0x00,0x00,0x00,
+ 0x30,0x60,0x60,0x60,0x60,0x60,0x30,0x00,0x0C,0x06,0x06,0x06,0x06,0x06,0x0C,0x00,
+ 0x10,0x54,0x38,0x7C,0x38,0x54,0x10,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00,
+ 0x38,0x4C,0xC6,0xC6,0xC6,0x64,0x38,0x00,0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00,
+ 0x7C,0xC6,0x0E,0x3C,0x78,0xE0,0xFE,0x00,0x7E,0x0C,0x18,0x3C,0x06,0xC6,0x7C,0x00,
+ 0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x00,0xFC,0xC0,0xFC,0x06,0x06,0xC6,0x7C,0x00,
+ 0x3C,0x60,0xC0,0xFC,0xC6,0xC6,0x7C,0x00,0xFE,0xC6,0x0C,0x18,0x30,0x30,0x30,0x00,
+ 0x78,0xC4,0xE4,0x78,0x86,0x86,0x7C,0x00,0x7C,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00,
+ 0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30,
+ 0x1C,0x38,0x70,0xE0,0x70,0x38,0x1C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00,
+ 0x70,0x38,0x1C,0x0E,0x1C,0x38,0x70,0x00,0x7C,0xC6,0xC6,0x1C,0x18,0x00,0x18,0x00,
+ 0x3C,0x42,0x99,0xA1,0xA5,0x99,0x42,0x3C,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00,
+ 0xFC,0xC6,0xC6,0xFC,0xC6,0xC6,0xFC,0x00,0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00,
+ 0xF8,0xCC,0xC6,0xC6,0xC6,0xCC,0xF8,0x00,0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xFE,0x00,
+ 0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xC0,0x00,0x3E,0x60,0xC0,0xCE,0xC6,0x66,0x3E,0x00,
+ 0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,
+ 0x06,0x06,0x06,0x06,0xC6,0xC6,0x7C,0x00,0xC6,0xCC,0xD8,0xF0,0xF8,0xDC,0xCE,0x00,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00,
+ 0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,
+ 0xFC,0xC6,0xC6,0xC6,0xFC,0xC0,0xC0,0x00,0x7C,0xC6,0xC6,0xC6,0xDE,0xCC,0x7A,0x00,
+ 0xFC,0xC6,0xC6,0xCE,0xF8,0xDC,0xCE,0x00,0x78,0xCC,0xC0,0x7C,0x06,0xC6,0x7C,0x00,
+ 0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,
+ 0xC6,0xC6,0xC6,0xEE,0x7C,0x38,0x10,0x00,0xC6,0xC6,0xD6,0xFE,0xFE,0xEE,0xC6,0x00,
+ 0xC6,0xEE,0x3C,0x38,0x7C,0xEE,0xC6,0x00,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00,
+ 0xFE,0x0E,0x1C,0x38,0x70,0xE0,0xFE,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,
+ 0x60,0x60,0x30,0x18,0x0C,0x06,0x06,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,
+ 0x18,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
+ 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x06,0x3E,0x66,0x66,0x3C,0x00,
+ 0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x00,
+ 0x06,0x3E,0x66,0x66,0x66,0x66,0x3E,0x00,0x00,0x3C,0x66,0x66,0x7E,0x60,0x3C,0x00,
+ 0x1C,0x30,0x78,0x30,0x30,0x30,0x30,0x00,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x3C,
+ 0x60,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x00,
+ 0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x38,0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0x00,
+ 0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0xEC,0xFE,0xFE,0xFE,0xD6,0xC6,0x00,
+ 0x00,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x00,
+ 0x00,0x7C,0x66,0x66,0x66,0x7C,0x60,0x60,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x06,
+ 0x00,0x7E,0x70,0x60,0x60,0x60,0x60,0x00,0x00,0x3C,0x60,0x3C,0x06,0x66,0x3C,0x00,
+ 0x30,0x78,0x30,0x30,0x30,0x30,0x1C,0x00,0x00,0x66,0x66,0x66,0x66,0x6E,0x3E,0x00,
+ 0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0xC6,0xD6,0xFE,0xFE,0x7C,0x6C,0x00,
+ 0x00,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x06,0x3C,
+ 0x00,0x7E,0x0C,0x18,0x30,0x60,0x7E,0x00,0x0E,0x18,0x0C,0x38,0x0C,0x18,0x0E,0x00,
+ 0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x70,0x18,0x30,0x1C,0x30,0x18,0x70,0x00,
+ 0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x10,0x28,0x10,0x54,0xAA,0x44,0x00,0x00,
+};
+
+
+/* The font is generated from Xorg clR5x8.bdf */
+/*
+COMMENT Copyright 1989 Dale Schumacher, dal@syntel.mn.org
+COMMENT 399 Beacon Ave.
+COMMENT St. Paul, MN 55104-3527
+COMMENT
+COMMENT Permission to use, copy, modify, and distribute this software and
+COMMENT its documentation for any purpose and without fee is hereby
+COMMENT granted, provided that the above copyright notice appear in all
+COMMENT copies and that both that copyright notice and this permission
+COMMENT notice appear in supporting documentation, and that the name of
+COMMENT Dale Schumacher not be used in advertising or publicity pertaining to
+COMMENT distribution of the software without specific, written prior
+COMMENT permission. Dale Schumacher makes no representations about the
+COMMENT suitability of this software for any purpose. It is provided "as
+COMMENT is" without express or implied warranty.
+COMMENT
+*/
+unsigned char fontdata6x8[256][8] = {
+{ 0x7c>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0xff>>2, 0x7c>>2, },
+{ 0x00>>2, 0x00>>2, 0x10>>2, 0x28>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x78>>2, 0x44>>2, 0x78>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x40>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x40>>2, 0x78>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x40>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x40>>2, 0x4c>>2, 0x44>>2, 0x3c>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x38>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x1c>>2, 0x04>>2, 0x04>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x48>>2, 0x50>>2, 0x60>>2, 0x50>>2, 0x48>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x6c>>2, 0x54>>2, 0x54>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x64>>2, 0x54>>2, 0x4c>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x0c>>2, },
+{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x78>>2, 0x50>>2, 0x4c>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x40>>2, 0x38>>2, 0x04>>2, 0x78>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x28>>2, 0x28>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x54>>2, 0x54>>2, 0x6c>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x28>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x7c>>2, 0x00>>2, },
+{ 0xe0>>2, 0x80>>2, 0xe0>>2, 0x8c>>2, 0xf0>>2, 0x10>>2, 0x10>>2, 0x0c>>2, },
+{ 0x00>>2, 0x10>>2, 0x38>>2, 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x7c>>2, 0x38>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x18>>2, 0xfc>>2, 0x18>>2, 0x10>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x20>>2, 0x60>>2, 0xfc>>2, 0x60>>2, 0x20>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, 0x10>>2, 0x00>>2, },
+{ 0x28>>2, 0x28>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x28>>2, 0x7c>>2, 0x28>>2, 0x7c>>2, 0x28>>2, 0x00>>2, 0x00>>2, },
+{ 0x10>>2, 0x3c>>2, 0x50>>2, 0x38>>2, 0x14>>2, 0x78>>2, 0x10>>2, 0x00>>2, },
+{ 0x60>>2, 0x64>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x4c>>2, 0x0c>>2, 0x00>>2, },
+{ 0x38>>2, 0x40>>2, 0x40>>2, 0x20>>2, 0x54>>2, 0x48>>2, 0x34>>2, 0x00>>2, },
+{ 0x10>>2, 0x20>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x04>>2, 0x08>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x08>>2, 0x04>>2, 0x00>>2, },
+{ 0x40>>2, 0x20>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x20>>2, 0x40>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x54>>2, 0x38>>2, 0x54>>2, 0x10>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x10>>2, 0x7c>>2, 0x10>>2, 0x10>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x10>>2, 0x10>>2, 0x20>>2, },
+{ 0x00>>2, 0x00>>2, 0x00>>2, 0x7c>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x04>>2, 0x04>>2, 0x08>>2, 0x08>>2, 0x10>>2, 0x10>>2, 0x20>>2, 0x20>>2, },
+{ 0x38>>2, 0x44>>2, 0x4c>>2, 0x54>>2, 0x64>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x10>>2, 0x30>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x04>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x7c>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x04>>2, 0x18>>2, 0x04>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x18>>2, 0x18>>2, 0x28>>2, 0x28>>2, 0x7c>>2, 0x08>>2, 0x1c>>2, 0x00>>2, },
+{ 0x7c>>2, 0x40>>2, 0x78>>2, 0x04>>2, 0x04>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x18>>2, 0x20>>2, 0x40>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x7c>>2, 0x44>>2, 0x04>>2, 0x08>>2, 0x08>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x04>>2, 0x08>>2, 0x30>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x10>>2, 0x00>>2, 0x00>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x10>>2, 0x00>>2, 0x00>>2, 0x10>>2, 0x10>>2, 0x20>>2, },
+{ 0x00>>2, 0x0c>>2, 0x30>>2, 0xc0>>2, 0x30>>2, 0x0c>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x00>>2, 0x7c>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0xc0>>2, 0x30>>2, 0x0c>>2, 0x30>>2, 0xc0>>2, 0x00>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x04>>2, 0x08>>2, 0x10>>2, 0x00>>2, 0x10>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x5c>>2, 0x5c>>2, 0x58>>2, 0x40>>2, 0x38>>2, 0x00>>2, },
+{ 0x10>>2, 0x28>>2, 0x44>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x78>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x70>>2, 0x48>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x48>>2, 0x70>>2, 0x00>>2, },
+{ 0x7c>>2, 0x40>>2, 0x40>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
+{ 0x7c>>2, 0x40>>2, 0x40>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x40>>2, 0x4c>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x00>>2, },
+{ 0x44>>2, 0x44>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x7c>>2, 0x00>>2, },
+{ 0x1c>>2, 0x04>>2, 0x04>>2, 0x04>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x44>>2, 0x48>>2, 0x50>>2, 0x60>>2, 0x50>>2, 0x48>>2, 0x44>>2, 0x00>>2, },
+{ 0x40>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
+{ 0x44>>2, 0x6c>>2, 0x54>>2, 0x54>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x44>>2, 0x64>>2, 0x64>>2, 0x54>>2, 0x4c>>2, 0x4c>>2, 0x44>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x78>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x0c>>2, },
+{ 0x78>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x50>>2, 0x48>>2, 0x44>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x40>>2, 0x38>>2, 0x04>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x44>>2, 0x44>>2, 0x44>>2, 0x28>>2, 0x28>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x44>>2, 0x44>>2, 0x44>>2, 0x54>>2, 0x54>>2, 0x6c>>2, 0x44>>2, 0x00>>2, },
+{ 0x44>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x28>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x44>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x7c>>2, 0x04>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
+{ 0x1c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x1c>>2, 0x00>>2, },
+{ 0x20>>2, 0x20>>2, 0x10>>2, 0x10>>2, 0x08>>2, 0x08>>2, 0x04>>2, 0x04>>2, },
+{ 0x70>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x70>>2, 0x00>>2, },
+{ 0x10>>2, 0x28>>2, 0x44>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0xfc>>2, 0x00>>2, },
+{ 0x10>>2, 0x08>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x44>>2, 0x44>>2, 0x4c>>2, 0x34>>2, 0x00>>2, },
+{ 0x40>>2, 0x40>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x3c>>2, 0x00>>2, },
+{ 0x04>>2, 0x04>>2, 0x3c>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x7c>>2, 0x40>>2, 0x38>>2, 0x00>>2, },
+{ 0x1c>>2, 0x20>>2, 0x78>>2, 0x20>>2, 0x20>>2, 0x20>>2, 0x20>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x04>>2, 0x38>>2, },
+{ 0x40>>2, 0x40>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x10>>2, 0x00>>2, 0x30>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x38>>2, 0x00>>2, },
+{ 0x08>>2, 0x00>>2, 0x38>>2, 0x08>>2, 0x08>>2, 0x08>>2, 0x08>>2, 0x70>>2, },
+{ 0x40>>2, 0x40>>2, 0x48>>2, 0x50>>2, 0x60>>2, 0x50>>2, 0x48>>2, 0x00>>2, },
+{ 0x30>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x68>>2, 0x54>>2, 0x54>>2, 0x54>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x58>>2, 0x64>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x40>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x04>>2, },
+{ 0x00>>2, 0x00>>2, 0x58>>2, 0x60>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x40>>2, 0x38>>2, 0x04>>2, 0x78>>2, 0x00>>2, },
+{ 0x10>>2, 0x10>>2, 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x0c>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x4c>>2, 0x34>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x6c>>2, 0x28>>2, 0x28>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x54>>2, 0x54>>2, 0x54>>2, 0x28>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x28>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x04>>2, 0x38>>2, },
+{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x7c>>2, 0x00>>2, },
+{ 0x04>>2, 0x08>>2, 0x08>>2, 0x10>>2, 0x08>>2, 0x08>>2, 0x04>>2, 0x00>>2, },
+{ 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x40>>2, 0x20>>2, 0x20>>2, 0x10>>2, 0x20>>2, 0x20>>2, 0x40>>2, 0x00>>2, },
+{ 0x20>>2, 0x54>>2, 0x08>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x10>>2, 0x28>>2, 0x28>>2, 0x44>>2, 0x7c>>2, 0x00>>2, },
+};
+
+/* note: may use 1 extra pixel on the right */
+void basic_text_out16_nf(void *fb, int w, int x, int y, const char *text)
+{
+ int i, l;
+ unsigned short *screen;
+ unsigned short val = 0xffff;
+
+ screen = (unsigned short *)fb + x + y * w;
+ for (i = 0; x + i * 8 < w; i++, screen += 8)
+ {
+ char c = text[i];
+ if (c == 0)
+ break;
+ if (c == ' ')
+ continue;
+
+ for (l = 0; l < 8; l++)
+ {
+ unsigned char fd = fontdata8x8[c * 8 + l];
+ unsigned short *s = screen + l * w;
+ unsigned char fd1, fdp = 0;
+
+ if (fd&0x80) s[0] = val;
+ if (fd&0x40) s[1] = val;
+ if (fd&0x20) s[2] = val;
+ if (fd&0x10) s[3] = val;
+ if (fd&0x08) s[4] = val;
+ if (fd&0x04) s[5] = val;
+ if (fd&0x02) s[6] = val;
+ if (fd&0x01) s[7] = val;
+
+ // draw "shadow" (RGB1555 compatible)
+ if (l > 0)
+ fdp = fontdata8x8[c * 8 + l - 1];
+
+ for (fd1 = 0x80; fd1 != 0; fd1 >>= 1, s++)
+ if (!(fd & (fd1 >> 1)) && ((fdp | fd) & fd1))
+ s[1] = (s[1] >> 1) & 0x39ef;
+ }
+ }
+}
+
+void basic_text_out_uyvy_nf(void *fb, int w, int x, int y, const char *text)
+{
+ int i, l;
+ unsigned short *screen;
+
+ screen = (unsigned short *)fb + x + y * w;
+ for (i = 0; x + i * 8 < w; i++, screen += 8)
+ {
+ char c = text[i];
+ if (c == 0)
+ break;
+ if (c == ' ')
+ continue;
+
+ for (l = 0; l < 8; l++)
+ {
+ unsigned char fd = fontdata8x8[c * 8 + l];
+ unsigned char *s = (void *)(screen + l * w);
+ unsigned char fd1, fdp = 0;
+
+ if (fd&0x80) s[0 * 2 + 1] = 235;
+ if (fd&0x40) s[1 * 2 + 1] = 235;
+ if (fd&0x20) s[2 * 2 + 1] = 235;
+ if (fd&0x10) s[3 * 2 + 1] = 235;
+ if (fd&0x08) s[4 * 2 + 1] = 235;
+ if (fd&0x04) s[5 * 2 + 1] = 235;
+ if (fd&0x02) s[6 * 2 + 1] = 235;
+ if (fd&0x01) s[7 * 2 + 1] = 235;
+
+ // draw "shadow"
+ if (l > 0)
+ fdp = fontdata8x8[c * 8 + l - 1];
+
+ for (fd1 = 0x80; fd1 != 0; fd1 >>= 1, s += 2)
+ if (!(fd & (fd1 >> 1)) && ((fdp | fd) & fd1))
+ s[1] /= 2;
+ }
+ }
+}
+
+void basic_text_out16(void *fb, int w, int x, int y, const char *texto, ...)
+{
+ va_list args;
+ char buffer[256];
+
+ va_start(args, texto);
+ vsnprintf(buffer, sizeof(buffer), texto, args);
+ va_end(args);
+
+ basic_text_out16_nf(fb, w, x, y, buffer);
+}
--- /dev/null
+/*
+ * pandora live info
+ * (C) notaz, 2014
+ *
+ * This work is licensed under the terms of 3-clause BSD license.
+ * See COPYING file in the top-level directory.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <signal.h>
+#include <poll.h>
+#include <linux/fb.h>
+#include <linux/omapfb.h>
+#include <stdint.h>
+#include "fonts.h"
+
+#define SCREEN_WIDTH 800
+#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 unsigned int g_old_mem;
+static int g_fd, g_exit;
+
+#define IS_START(buf, str) \
+ !strncmp(buf, str, sizeof(str) - 1)
+
+static int setup_layer(void)
+{
+ 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);
+ if (ret < 0) {
+ perror("ioctl OMAPFB_QUERY_PLANE");
+ return 1;
+ }
+
+ ret = ioctl(g_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);
+ 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);
+ 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);
+ if (ret < 0) {
+ perror("ioctl OMAPFB_SETUP_PLANE (e1)");
+ return 1;
+ }
+
+ ret = ioctl(g_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.bits_per_pixel = 16;
+
+ ret = ioctl(g_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);
+ if (ret < 0) {
+ perror("ioctl OMAPFB_SETUP_PLANE (e2)");
+ return 1;
+ }
+
+ memset(&key, 0, sizeof(key));
+ 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");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int check_layer(void)
+{
+ struct omapfb_plane_info pi;
+ int ret;
+
+ ret = ioctl(g_fd, OMAPFB_QUERY_PLANE, &pi);
+ if (ret < 0) {
+ perror("ioctl OMAPFB_QUERY_PLANE");
+ return 1;
+ }
+
+ if (!pi.enabled) {
+ printf("something disabled the layer (tv-out?), quitting\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static void remove_layer(void)
+{
+ struct omapfb_plane_info pi;
+ struct omapfb_mem_info mi;
+ int ret;
+
+ memset(&pi, 0, sizeof(pi));
+ pi.enabled = 0;
+ ret = ioctl(g_fd, OMAPFB_SETUP_PLANE, &pi);
+ if (ret < 0)
+ perror("ioctl OMAPFB_SETUP_PLANE (c)");
+
+ ret = ioctl(g_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);
+ if (ret < 0) {
+ perror("ioctl SETUP_MEM");
+ goto out;
+ }
+ }
+
+out:
+ close(g_fd);
+ g_fd = -1;
+}
+
+static void handle_signal(int num)
+{
+ g_exit = 1;
+}
+
+static void flip_fb(void)
+{
+ static int id;
+
+ g_vi.yoffset = id * HEIGHT;
+ ioctl(g_fd, FBIOPAN_DISPLAY, &g_vi);
+ id ^= 1;
+ g_screen = g_screen_base + id * WIDTH * HEIGHT;
+}
+
+#define s_printf(x, y, fmt, ...) \
+ basic_text_out16(g_screen, WIDTH, x, y, fmt, ##__VA_ARGS__);
+
+static int read_int_file(const char *fn, int *val)
+{
+ FILE *f;
+ int ret;
+
+ *val = 0;
+ f = fopen(fn, "r");
+ if (f == NULL)
+ return 1;
+ ret = fscanf(f, "%d", val);
+ fclose(f);
+ if (ret != 1)
+ return 1;
+
+ return 0;
+}
+
+static void clear(int h)
+{
+ int *p = (int *)g_screen;
+ int l = WIDTH * h / 2;
+
+ for (; l >= 4; l -= 4, p += 4)
+ p[0] = p[1] = p[2] = p[3] = 0x07e007e0;
+ for (; l > 0; l--, p++)
+ *p = 0x07e007e0;
+}
+
+struct proc_stat {
+ unsigned long idlesum;
+ unsigned long sys;
+ unsigned long irqs;
+ unsigned long ctxt;
+};
+
+static struct {
+ struct proc_stat last_st;
+ int cpu_usage;
+ int cpu_sys;
+ int irqs;
+ int ctxt;
+ int mem_free;
+ int mem_huge;
+ int mem_free_swap;
+} stats;
+
+static void collect_proc_stat(void)
+{
+ static long hz;
+ struct proc_stat st;
+ char buf[256];
+ unsigned long wait;
+ unsigned long iowait;
+ FILE *f;
+
+ if (hz == 0) {
+ hz = sysconf(_SC_CLK_TCK);
+ printf("hz: %ld\n", hz);
+ }
+
+ f = fopen("/proc/stat", "r");
+ if (f == NULL)
+ return;
+
+ if (fscanf(f, "cpu %*s %*s %lu %lu %lu",
+ &st.sys, &wait, &iowait) != 3)
+ goto out;
+ do {
+ if (fgets(buf, sizeof(buf), f) == NULL)
+ goto out;
+ } while (fscanf(f, "intr %lu", &st.irqs) != 1);
+ do {
+ if (fgets(buf, sizeof(buf), f) == NULL)
+ goto out;
+ } while (fscanf(f, "ctxt %lu", &st.ctxt) != 1);
+
+ st.idlesum = wait + iowait;
+
+ stats.cpu_usage = hz - (st.idlesum - stats.last_st.idlesum);
+ stats.cpu_sys = st.sys - stats.last_st.sys;
+ if (hz != 100) {
+ stats.cpu_usage = stats.cpu_usage * 100 / hz;
+ stats.cpu_sys = stats.cpu_sys * 100 / hz;
+ }
+ stats.irqs = st.irqs - stats.last_st.irqs;
+ stats.ctxt = st.ctxt - stats.last_st.ctxt;
+
+out:
+ stats.last_st = st;
+ fclose(f);
+}
+
+static void collect_mem_stat(void)
+{
+ static const char fn[] = "/proc/meminfo";
+ uint32_t total = 0, free = 0, buffers = 0, cached = 0;
+ uint32_t anonhuge = 0, hugetot = 0, hugefree = 0, hugepgsz = 0;
+ uint32_t free_swap = 0;
+ char buf[128];
+ FILE *f;
+
+ f = fopen(fn, "r");
+ if (f == NULL)
+ return;
+
+ while (fgets(buf, sizeof(buf), f)) {
+ if (total == 0 && sscanf(buf, "MemTotal: %u", &total) == 1)
+ continue;
+ if (free == 0 && sscanf(buf, "MemFree: %u", &free) == 1)
+ continue;
+ if (buffers == 0 && sscanf(buf, "Buffers: %u", &buffers) == 1)
+ continue;
+ if (cached == 0 && sscanf(buf, "Cached: %u", &cached) == 1)
+ continue;
+ if (free_swap == 0 && sscanf(buf, "SwapFree: %u", &free_swap) == 1)
+ continue;
+ if (anonhuge == 0 && sscanf(buf, "AnonHugePages: %u", &anonhuge) == 1)
+ continue;
+ if (hugetot == 0 && sscanf(buf, "HugePages_Total: %u", &hugetot) == 1)
+ continue;
+ if (hugefree == 0 && sscanf(buf, "HugePages_Free: %u", &hugefree) == 1)
+ continue;
+ if (hugepgsz == 0 && sscanf(buf, "Hugepagesize: %u", &hugepgsz) == 1)
+ continue;
+ }
+
+ fclose(f);
+
+ hugetot = (hugetot - hugefree) * hugepgsz;
+ free += buffers + cached;
+ stats.mem_free = free >> 10;
+ stats.mem_huge = hugetot >> 10;
+ stats.mem_free_swap = free_swap >> 10;
+}
+
+struct io_stat {
+ unsigned long sec_r;
+ unsigned long sec_w;
+};
+
+static struct {
+ struct io_stat last_st;
+ int read; // kB/s
+ int write;
+} io_stats;
+
+static void collect_io_stat(void)
+{
+ unsigned long sec_r, sec_w;
+ struct io_stat st = { 0, };
+ char buf[128];
+ FILE *f;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ snprintf(buf, sizeof(buf), "/sys/block/mmcblk%d/stat", i);
+ f = fopen(buf, "r");
+ if (f == NULL)
+ continue;
+
+ if (fscanf(f, "%*s %*s %lu %*s %*s %*s %lu",
+ &sec_r, &sec_w) == 2)
+ {
+ st.sec_r += sec_r;
+ st.sec_w += sec_w;
+ }
+ fclose(f);
+ }
+
+ io_stats.read = st.sec_r - io_stats.last_st.sec_r;
+ io_stats.write = st.sec_w - io_stats.last_st.sec_w;
+ // assuming 512 byte sectors..
+ io_stats.read >>= 1;
+ io_stats.write >>= 1;
+
+ io_stats.last_st = st;
+}
+
+struct net_stat {
+ unsigned long rx;
+ unsigned long tx;
+};
+
+static struct {
+ struct net_stat last_st;
+ int down; // kB/s
+ int up;
+ int have_wlan;
+ int link;
+ int level;
+} net_stats;
+
+static void collect_net_stat(void)
+{
+ struct net_stat st = { 0, };
+ unsigned long rx, tx;
+ int found = 0;
+ char buf[256];
+ FILE *f;
+
+ net_stats.down = net_stats.up =
+ net_stats.have_wlan = net_stats.link = net_stats.level = 0;
+
+ f = fopen("/proc/net/dev", "r");
+ if (f == NULL)
+ return;
+
+ while (!feof(f)) {
+ static const char fmt[] =
+ "%255s %lu %*s %*s %*s %*s %*s %*s %lu";
+ if (fscanf(f, fmt, buf, &rx, &tx) != 3)
+ continue;
+ if (IS_START(buf, "lo"))
+ continue;
+ st.rx += rx;
+ st.tx += tx;
+ found = 1;
+ }
+ fclose(f);
+
+ if (found) {
+ net_stats.down = st.rx - net_stats.last_st.rx;
+ net_stats.up = st.tx - net_stats.last_st.tx;
+ }
+ net_stats.last_st = st;
+
+ f = fopen("/proc/net/wireless", "r");
+ if (f == NULL)
+ return;
+
+ while (!feof(f)) {
+ int lnk, lvl;
+ if (fscanf(f, "%255s %*x %d. %d.", buf, &lnk, &lvl) != 3)
+ continue;
+ if (IS_START(buf, "lo"))
+ continue;
+ // first one should be enough
+ net_stats.have_wlan = 1;
+ net_stats.link = lnk;
+ net_stats.level = lvl;
+ break;
+ }
+ fclose(f);
+}
+
+static void collect_stats(void)
+{
+ collect_proc_stat();
+ collect_mem_stat();
+ collect_io_stat();
+ collect_net_stat();
+}
+
+static char cpu_reg_path[64];
+
+static void init_stats(void)
+{
+ char buf[64];
+ int found;
+ FILE *f;
+ int i;
+
+ // find the CPU regulator
+ for (i = found = 0; ; i++) {
+ snprintf(buf, sizeof(buf),
+ "/sys/class/regulator/regulator.%d/name", i);
+ f = fopen(buf, "r");
+ if (f == NULL)
+ break;
+ fgets(buf, sizeof(buf), f);
+ fclose(f);
+ if (IS_START(buf, "vdd_mpu")) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found)
+ snprintf(cpu_reg_path, sizeof(cpu_reg_path),
+ "/sys/class/regulator/regulator.%d/microvolts", i);
+
+ // do collect so differential stats get sane values
+ collect_stats();
+}
+
+static void get_time(int x, int y)
+{
+ struct timeval tv;
+ struct tm *t;
+ char buf[16];
+
+ gettimeofday(&tv, NULL);
+ t = localtime(&tv.tv_sec);
+ strftime(buf, sizeof(buf), "%T", t);
+ s_printf(x, y, " %s", buf);
+}
+
+static void get_cpu(int x, int y)
+{
+ s_printf(x, y, "CPU:%5d%%", stats.cpu_usage);
+}
+
+static void get_sys(int x, int y)
+{
+ s_printf(x, y, "SYS:%5d%%", stats.cpu_sys);
+}
+
+static void get_irq(int x, int y)
+{
+ s_printf(x, y, "IRQ:%5u", stats.irqs);
+}
+
+static void get_cs(int x, int y)
+{
+ s_printf(x, y, "CS:%6u", stats.ctxt);
+}
+
+static void get_cpuf(int x, int y)
+{
+ static const char fn[] =
+ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq";
+ int f;
+
+ if (read_int_file(fn, &f))
+ return;
+ s_printf(x, y, "f:%7dM", f / 1000);
+}
+
+static void get_cpuv(int x, int y)
+{
+ int v = 0;
+
+ if (!cpu_reg_path[0] || read_int_file(cpu_reg_path, &v))
+ return;
+ s_printf(x, y, "V:%7.3fV", (float)v / 1000000.0f);
+}
+
+static void get_memfree(int x, int y)
+{
+ s_printf(x, y, "M:%7dM", stats.mem_free);
+}
+
+static void get_memhuge(int x, int y)
+{
+ s_printf(x, y, "H:%7dM", stats.mem_huge);
+}
+
+static void get_memswap(int x, int y)
+{
+ s_printf(x, y, "S:%7dM", stats.mem_free_swap);
+}
+
+#define PS_BASE "/sys/class/power_supply/bq27500-0/"
+
+static void get_bcap(int x, int y)
+{
+ static const char fnc[] = PS_BASE "capacity";
+ int c;
+
+ if (read_int_file(fnc, &c))
+ return;
+ s_printf(x, y, "C:%7d%%", c);
+}
+
+static void get_btime(int x, int y)
+{
+ static const char fne[] = PS_BASE "time_to_empty_now";
+ static const char fnf[] = PS_BASE "time_to_full_now";
+ int t = 0;
+
+ if (read_int_file(fne, &t) || t == 0) {
+ if (read_int_file(fnf, &t))
+ return;
+ }
+ s_printf(x, y, "t:%4d:%02d", t / 3600, t / 60 % 60);
+}
+
+static void get_bvolts(int x, int y)
+{
+ static const char fnv[] = PS_BASE "voltage_now";
+ int volt = 0;
+
+ if (read_int_file(fnv, &volt))
+ return;
+
+ s_printf(x, y, "V:%7.3fV", (float)volt / 1000000.0f);
+}
+
+static void get_bwatts(int x, int y)
+{
+ static const char fnc[] = PS_BASE "current_now";
+ static const char fnv[] = PS_BASE "voltage_now";
+ int w, cur = 0, volt = 0;
+
+ if (read_int_file(fnc, &cur))
+ return;
+ if (read_int_file(fnv, &volt))
+ return;
+
+ w = (cur / 1000) * (volt / 1000);
+ s_printf(x, y, "P:%7.3fW", (float)w / 1000000.0f);
+}
+
+static void get_btemp(int x, int y)
+{
+ static const char fnt[] = PS_BASE "temp";
+ int t;
+
+ if (read_int_file(fnt, &t))
+ return;
+ s_printf(x, y, "T:%7.1fC", (float)t / 10.0f);
+}
+
+static void get_ioread(int x, int y)
+{
+ s_printf(x, y, "R:%5.1fM/s", (float)io_stats.read / 1000.0f);
+}
+
+static void get_iowrite(int x, int y)
+{
+ s_printf(x, y, "W:%5.1fM/s", (float)io_stats.write / 1000.0f);
+}
+
+static void get_netdown(int x, int y)
+{
+ s_printf(x, y, "D:%5uK/s", net_stats.down / 1000);
+}
+
+static void get_netup(int x, int y)
+{
+ s_printf(x, y, "U:%5uK/s", net_stats.up / 1000);
+}
+
+static void get_netsgnl(int x, int y)
+{
+ s_printf(x, y, "S:%5ddBm", net_stats.level);
+}
+
+int main(int argc, char *argv[])
+{
+ static const char socket_name[] = "\0livestats";
+ 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;
+ int y = 0, y_max = 0;
+ int sock;
+ int ret;
+
+ // look for other instance
+ sock = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (sock == -1) {
+ perror("socket PF_UNIX");
+ return 1;
+ }
+
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+ memcpy(sun.sun_path, socket_name, sizeof(socket_name));
+
+ 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);
+ if (ret != 4)
+ perror("send");
+ close(sock);
+ return 0;
+ }
+
+ // bind/listen for quit command
+ ret = bind(sock, (struct sockaddr *)&sun, sizeof(sun));
+ if (ret != 0) {
+ perror("bind");
+ close(sock);
+ return 1;
+ }
+
+ ret = listen(sock, 1);
+ if (ret != 0) {
+ perror("listen");
+ close(sock);
+ return 1;
+ }
+
+ 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);
+ pthread_condattr_destroy(&condattr);
+ if (ret != 0) {
+ fprintf(stderr, "cond init failed\n");
+ return 1;
+ }
+
+ ret = setup_layer();
+ 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);
+
+ pthread_mutex_lock(&mutex);
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (ret != 0) {
+ perror("clock_gettime CLOCK_MONOTONIC");
+ return 1;
+ }
+
+ nice(-1);
+ init_stats();
+
+ while (!g_exit) {
+ collect_stats();
+
+ y += Y_STEP;
+ if (y > y_max)
+ y_max = y;
+ clear(y_max);
+
+ y = 0;
+ get_time (0, y += Y_STEP);
+ y += Y_STEP / 2;
+ get_cpu (0, y += Y_STEP);
+ get_sys (0, y += Y_STEP);
+ get_irq (0, y += Y_STEP);
+ get_cs (0, y += Y_STEP);
+ get_cpuf (0, y += Y_STEP);
+ get_cpuv (0, y += Y_STEP);
+ y += Y_STEP / 2;
+ s_printf(0, y += Y_STEP, "mem");
+ get_memfree(0, y += Y_STEP);
+ get_memswap(0, y += Y_STEP);
+ if (stats.mem_huge)
+ get_memhuge(0, y += Y_STEP);
+ y += Y_STEP / 2;
+ s_printf(0, y += Y_STEP, "i/o");
+ get_ioread (0, y += Y_STEP);
+ get_iowrite(0, y += Y_STEP);
+ y += Y_STEP / 2;
+ s_printf(0, y += Y_STEP, "net");
+ get_netdown(0, y += Y_STEP);
+ get_netup (0, y += Y_STEP);
+ if (net_stats.have_wlan)
+ get_netsgnl(0, y += Y_STEP);
+ y += Y_STEP / 2;
+ s_printf(0, y += Y_STEP, "batt");
+ get_bcap (0, y += Y_STEP);
+ get_btime (0, y += Y_STEP);
+ get_bvolts (0, 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;
+ }
+
+ ts.tv_sec++;
+ pthread_cond_timedwait(&cond, &mutex, &ts);
+ }
+
+ munmap(g_screen_base, MEM_SIZE);
+ remove_layer();
+ close(sock);
+
+ return 0;
+}
+
+// vim:expandtab:sw=2:ts=2