diff --git a/g13.cc b/g13.cc
index d428bce..6c187d5 100644
--- a/g13.cc
+++ b/g13.cc
@@ -643,6 +643,8 @@ void g13_keypad::image(unsigned char *data, int size) {
   g13_write_lcd(ctx, this->handle, data, size);
 }
 
+extern unsigned char font8x8_basic[128][8];
+
 g13_keypad::g13_keypad(libusb_device_handle *handle, int id) {
     this->handle = handle;
     this->id = id;
@@ -668,12 +670,22 @@ g13_keypad::g13_keypad(libusb_device_handle *handle, int id) {
     //         KEY_A, KEY_S, KEY_LEFTCTRL, 0, 0,
     //         KEY_F1, KEY_N, KEY_R, KEY_P, KEY_K, KEY_D, KEY_X, KEY_Y,
     // 	    KEY_Z, KEY_TAB, KEY_W, KEY_BACKSPACE, 0, 0, 0, 0};
-    }
 
-    void g13_keypad::command(char const *str) {
-    int red, green, blue, mod;
+    image_clear();
+    cursor_col = 0;
+    cursor_row = 0;
+    text_mode = 0;
+
+    #define CONTROL_DIR std::string("/tmp/")
+    this->_fifo_name = CONTROL_DIR + "g13-" + boost::lexical_cast<std::string>(id);
+    _init_fonts();
+}
+
+void g13_keypad::command(char const *str) {
+    int red, green, blue, mod, row, col;;
     char keyname[256];
     char binding[256];
+    char c;
     if(sscanf(str, "rgb %i %i %i", &red, &green, &blue) == 3) {
       g13_set_key_color(handle, red, green, blue);
     } else if(sscanf(str, "mod %i", &mod) == 1) {
@@ -699,8 +711,286 @@ g13_keypad::g13_keypad(libusb_device_handle *handle, int id) {
       } else {
         cerr << "unknown key: " << binding << endl;
       }
-
+    } else if(sscanf(str, "image %i %i", &red, &green) == 2) {
+    	image_test(red,green);
+    } else if(sscanf(str, "write_char %c %i %i", &c, &row, &col) == 3) {
+       	write_char( c, row, col );
+    } else if(sscanf(str, "pos %i %i", &row, &col) == 2) {
+       	write_pos( row, col );
+    } else if(sscanf(str, "write_char %c", &c ) == 1) {
+       	write_char( c );
+    } else if( !strncmp( str, "out ", 4 ) ) {
+    	write_string( str+4 );
+    } else if( !strncmp( str, "clear", 5 ) ) {
+    	image_clear();
+    	image_send();
+    } else if(sscanf(str, "mode %i", &mod ) == 1) {
+    	text_mode = mod;
+    } else if( !strncmp( str, "refresh", 6 ) ) {
+    	image_send();
     } else {
       cerr << "unknown command: <" << str << ">" <<  endl;
     }
-  }
+}
+
+
+void g13_keypad::write_pos(int row, int col ) {
+	cursor_row = row;
+	cursor_col = col;
+	if( cursor_col >= G13_LCD_TEXT_COLUMNS ) {
+		cursor_col = 0;
+	}
+	if( cursor_row >= G13_LCD_TEXT_ROWS ) {
+		cursor_row = 0;
+	}
+}
+void g13_keypad::write_char( char c, int row, int col ) {
+	if( row == -1 ) {
+		row = cursor_row;
+		col = cursor_col;
+		if( ++cursor_col >= G13_LCD_TEXT_COLUMNS ) {
+			cursor_col = 0;
+			if( ++cursor_row >= G13_LCD_TEXT_ROWS ) {
+				cursor_row = 0;
+			}
+		}
+	}
+	unsigned offset = image_byte_offset( row*G13_LCD_TEXT_CHEIGHT, col*G13_LCD_TEXT_CWIDTH );
+	if( text_mode ) {
+		memcpy( & image_buf[offset], &font_inverted[c], G13_LCD_TEXT_CWIDTH );
+	} else {
+		memcpy( & image_buf[offset], &font_basic[c], G13_LCD_TEXT_CWIDTH );
+	}
+}
+
+void g13_keypad::write_string( const char *str ) {
+	std::cout << "writing \"" << str << "\"" << std::endl;
+	while( *str ) {
+		if( *str == '\n' ) {
+			cursor_col = 0;
+			if( ++cursor_row >= G13_LCD_TEXT_ROWS ) {
+				cursor_row = 0;
+			}
+		} else if( *str == '\t' ) {
+			cursor_col += 4 - (cursor_col % 4) ;
+			if( ++cursor_col >= G13_LCD_TEXT_COLUMNS ) {
+				cursor_col = 0;
+				if( ++cursor_row >= G13_LCD_TEXT_ROWS ) {
+					cursor_row = 0;
+				}
+			}
+		} else {
+			write_char(*str);
+		}
+		++str;
+	}
+	image_send();
+}
+
+void g13_keypad::image_test( int x, int y ) {
+
+
+
+
+	int row = 0, col = 0;
+	if( y >= 0 ) {
+		image_setpixel( x, y );
+	} else {
+		image_clear();
+		switch( x ) {
+		case 1:
+			for( row = 0; row < G13_LCD_ROWS; ++row ) {
+				col = row;
+				image_setpixel( row, col );
+				image_setpixel( row, G13_LCD_COLUMNS-col );
+			}
+			break;
+
+		case 2:
+		default:
+			for( row = 0; row < G13_LCD_ROWS; ++row ) {
+				col = row;
+				image_setpixel( row, 8 );
+				image_setpixel( row, G13_LCD_COLUMNS - 8 );
+				image_setpixel( row, G13_LCD_COLUMNS / 2 );
+				image_setpixel( row, col );
+				image_setpixel( row, G13_LCD_COLUMNS-col );
+			}
+			break;
+
+		}
+	}
+	image_send();
+}
+
+
+// font data from https://github.com/dhepper/font8x8
+    // Constant: font8x8_basic
+    // Contains an 8x8 font map for unicode points U+0000 - U+007F (basic latin)
+    unsigned char font8x8_basic[128][8] = {
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0000 (nul)
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0001
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0002
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0003
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0004
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0005
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0006
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0007
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0008
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0009
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000A
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000B
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000C
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000D
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000E
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000F
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0010
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0011
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0012
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0013
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0014
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0015
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0016
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0017
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0018
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0019
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001A
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001B
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001C
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001D
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001E
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001F
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0020 (space)
+        { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00},   // U+0021 (!)
+        { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0022 (")
+        { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00},   // U+0023 (#)
+        { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00},   // U+0024 ($)
+        { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00},   // U+0025 (%)
+        { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00},   // U+0026 (&)
+        { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0027 (')
+        { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00},   // U+0028 (()
+        { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00},   // U+0029 ())
+        { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00},   // U+002A (*)
+        { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00},   // U+002B (+)
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06},   // U+002C (,)
+        { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00},   // U+002D (-)
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00},   // U+002E (.)
+        { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00},   // U+002F (/)
+        { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00},   // U+0030 (0)
+        { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00},   // U+0031 (1)
+        { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00},   // U+0032 (2)
+        { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00},   // U+0033 (3)
+        { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00},   // U+0034 (4)
+        { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00},   // U+0035 (5)
+        { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00},   // U+0036 (6)
+        { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00},   // U+0037 (7)
+        { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00},   // U+0038 (8)
+        { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00},   // U+0039 (9)
+        { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00},   // U+003A (:)
+        { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06},   // U+003B (//)
+        { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00},   // U+003C (<)
+        { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00},   // U+003D (=)
+        { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00},   // U+003E (>)
+        { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00},   // U+003F (?)
+        { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00},   // U+0040 (@)
+        { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00},   // U+0041 (A)
+        { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00},   // U+0042 (B)
+        { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00},   // U+0043 (C)
+        { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00},   // U+0044 (D)
+        { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00},   // U+0045 (E)
+        { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00},   // U+0046 (F)
+        { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00},   // U+0047 (G)
+        { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00},   // U+0048 (H)
+        { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+0049 (I)
+        { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00},   // U+004A (J)
+        { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00},   // U+004B (K)
+        { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00},   // U+004C (L)
+        { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00},   // U+004D (M)
+        { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00},   // U+004E (N)
+        { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00},   // U+004F (O)
+        { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00},   // U+0050 (P)
+        { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00},   // U+0051 (Q)
+        { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00},   // U+0052 (R)
+        { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00},   // U+0053 (S)
+        { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+0054 (T)
+        { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00},   // U+0055 (U)
+        { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00},   // U+0056 (V)
+        { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00},   // U+0057 (W)
+        { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00},   // U+0058 (X)
+        { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00},   // U+0059 (Y)
+        { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00},   // U+005A (Z)
+        { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00},   // U+005B ([)
+        { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00},   // U+005C (\)
+        { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00},   // U+005D (])
+        { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00},   // U+005E (^)
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF},   // U+005F (_)
+        { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0060 (`)
+        { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00},   // U+0061 (a)
+        { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00},   // U+0062 (b)
+        { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00},   // U+0063 (c)
+        { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00},   // U+0064 (d)
+        { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00},   // U+0065 (e)
+        { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00},   // U+0066 (f)
+        { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F},   // U+0067 (g)
+        { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00},   // U+0068 (h)
+        { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+0069 (i)
+        { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E},   // U+006A (j)
+        { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00},   // U+006B (k)
+        { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+006C (l)
+        { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00},   // U+006D (m)
+        { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00},   // U+006E (n)
+        { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00},   // U+006F (o)
+        { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F},   // U+0070 (p)
+        { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78},   // U+0071 (q)
+        { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00},   // U+0072 (r)
+        { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00},   // U+0073 (s)
+        { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00},   // U+0074 (t)
+        { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00},   // U+0075 (u)
+        { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00},   // U+0076 (v)
+        { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00},   // U+0077 (w)
+        { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00},   // U+0078 (x)
+        { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F},   // U+0079 (y)
+        { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00},   // U+007A (z)
+        { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00},   // U+007B ({)
+        { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00},   // U+007C (|)
+        { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00},   // U+007D (})
+        { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+007E (~)
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}    // U+007F
+    };
+
+void g13_keypad::_init_fonts() {
+    for( int i = 0; i < 128; i++ ) {
+    	memset( &font_basic[i], 0, 8 );
+    	for( int x = 0; x < 8; x++ ) {
+    		unsigned char x_mask = 1 << x;
+    		for( int y = 0;  y < 8; y++ ) {
+    			unsigned char y_mask = 1 << y;
+    			if( font8x8_basic[i][y] & x_mask ) {
+    				font_basic[i][x] |= 1 << y;
+    			}
+    		}
+    	}
+    	if( G13_LCD_TEXT_CWIDTH == 5 ) {
+    		if( font_basic[i][0] ) {
+    			font_basic[i][0] = font_basic[i][0] | font_basic[i][1];
+				font_basic[i][1] = font_basic[i][2] | font_basic[i][3];
+				font_basic[i][2] = font_basic[i][4]; // font_basic[i][4];
+				font_basic[i][3] = font_basic[i][5] | font_basic[i][6];
+				font_basic[i][4] = font_basic[i][7]; // | font_basic[i][7];
+    		} else {
+    			// font_basic[i][0] = font_basic[i][0] | font_basic[i][1];
+				font_basic[i][1] = font_basic[i][1] | font_basic[i][2];
+				font_basic[i][2] = font_basic[i][3]; // font_basic[i][4];
+				font_basic[i][3] = font_basic[i][4] | font_basic[i][5];
+				font_basic[i][4] = font_basic[i][6] | font_basic[i][7];
+
+    		}
+    	}
+
+    	for( int x = 0; x < 8; x++ ) {
+    		font_inverted[i][x] = ~font_basic[i][x];
+    	}
+    }
+
+}
+
diff --git a/g13.h b/g13.h
index 4eb7b5a..15c1f39 100644
--- a/g13.h
+++ b/g13.h
@@ -15,6 +15,18 @@
 
 enum stick_mode_t { STICK_ABSOLUTE, /*STICK_RELATIVE,*/ STICK_KEYS };
 enum stick_key_t { STICK_LEFT, STICK_UP, STICK_DOWN, STICK_RIGHT };
+
+const size_t G13_LCD_COLUMNS = 160;
+const size_t G13_LCD_ROWS = 48;
+const size_t G13_LCD_BYTES_PER_ROW = G13_LCD_COLUMNS/8;
+const size_t G13_LCD_BUF_SIZE = G13_LCD_ROWS * G13_LCD_BYTES_PER_ROW;
+
+//const size_t TEXT_CWIDTH = 5;
+const size_t G13_LCD_TEXT_CWIDTH = 8;
+const size_t G13_LCD_TEXT_CHEIGHT = 8;
+const size_t G13_LCD_TEXT_COLUMNS = 160 / G13_LCD_TEXT_CWIDTH;
+const size_t G13_LCD_TEXT_ROWS = 160 / G13_LCD_TEXT_CHEIGHT;
+
 struct g13_keypad {
   libusb_device_handle *handle;
   int uinput_file;
@@ -22,6 +34,16 @@ struct g13_keypad {
   int fifo;
   stick_mode_t stick_mode;
   int stick_keys[4];
+
+  std::string _fifo_name;
+  unsigned cursor_row;
+  unsigned cursor_col;
+  int text_mode;
+  unsigned char font_basic[128][8];
+  unsigned char font_inverted[128][8];
+
+  unsigned char image_buf[G13_LCD_BUF_SIZE+8];
+
   g13_keypad(libusb_device_handle *handle, int id);
   int map[G13_NUM_KEYS];
 
@@ -44,10 +66,71 @@ struct g13_keypad {
   }
   void command(char const *str);
   void image(unsigned char *data, int size);
-#define CONTROL_DIR std::string("/tmp/")
+
   const char *fifo_name() {
-    return (CONTROL_DIR + "g13-" + boost::lexical_cast<std::string>(id)).c_str();
+    return _fifo_name.c_str();
   }
+
+  void image_test( int x, int y );
+  void image_clear() {
+	  memset( image_buf, 0, G13_LCD_BUF_SIZE );
+  }
+  void image_send() {
+	  image( image_buf, G13_LCD_BUF_SIZE );
+  }
+
+	// pixels are mapped rather strangely for G13 buffer...
+	//
+	//  byte 0 contains column 0 / row 0 - 7
+	//  byte 1 contains column 1 / row 0 - 7
+	//
+	// so the masks for each pixel are laid out as below (ByteOffset.PixelMask)
+	//
+	// 00.01 01.01 02.01 ...
+	// 00.02 01.02 02.02 ...
+	// 00.04 01.04 02.04 ...
+	// 00.08 01.08 02.08 ...
+	// 00.10 01.10 02.10 ...
+	// 00.20 01.20 02.20 ...
+	// 00.40 01.40 02.40 ...
+	// 00.80 01.80 02.80 ...
+	// A0.01 A1.01 A2.01 ...
+
+  unsigned image_byte_offset( unsigned row, unsigned col ) {
+  	  return col + (row /8 ) * G13_LCD_BYTES_PER_ROW * 8;
+    }
+
+  void image_setpixel( unsigned row, unsigned col ) {
+	unsigned offset = image_byte_offset( row, col ); // col + (row /8 ) * BYTES_PER_ROW * 8;
+	unsigned char mask = 1 << ((row)&7);
+
+	if( offset >= G13_LCD_BUF_SIZE ) {
+		std::cerr << "bad offset " << offset << " for "
+				<< (row) << " x " << (col) << std::endl;
+		return;
+	}
+
+	image_buf[ offset ] |= mask;
+  }
+
+
+  void image_clearpixel( unsigned row, unsigned col ) {
+
+	unsigned offset = image_byte_offset( row, col ); // col + (row /8 ) * BYTES_PER_ROW * 8;
+	unsigned char mask = 1 << ((row)&7);
+
+	if( offset >= G13_LCD_BUF_SIZE ) {
+		std::cerr << "bad offset " << offset << " for "
+				<< (row) << " x " << (col) << std::endl;
+		return;
+	}
+	image_buf[ offset ] &= ~mask;
+  }
+
+  void write_char( char c, int row = -1, int col = -1);
+  void write_string( const char *str );
+  void write_pos(int row, int col );
+  void _init_fonts();
 };
 
 enum G13_KEYS {
diff --git a/g13_test.py b/g13_test.py
new file mode 100755
index 0000000..5b9b402
--- /dev/null
+++ b/g13_test.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python2.7
+import subprocess, re, os, time
+
+# simple test script to update G13 LCD with temperature values from lm-sensors
+
+def doCmd( *cmd ):
+    #print( "cmd = %r" % (cmd,) )
+    p = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
+    out, err = p.communicate()
+    return out #, err
+
+def get_sensors():
+    sensor_lines = doCmd( 'sensors' ).split('\n')
+    print( "sensor_lines = %r" % (sensor_lines,) )
+    temp_re = re.compile( r'''([a-zA-Z])[a-zA-Z s]+([0-9])\:\s*\+([0-9.]+)[\xc2\xb0C]*C.*''' )
+     
+    temps = []
+    for line in sensor_lines:
+        m = temp_re.match(line)
+        if m:
+            tag, index, value = m.groups()
+            print( "%s%s = %s" % (tag, index, value))
+            #temps.append( "%s%s:%s" % (tag, index, value) )
+            temps.append( "%s" % (value,) )
+        # else:
+        #   print( "failed to match %r" % (line,))
+            
+        
+    with open( '/tmp/g13-0', 'w') as p:
+        p.write( 'pos 0 0 \n' )
+        p.write( 'out %s\n' % (' '.join(temps)) )
+    
+    
+def main():
+    while 1:
+        get_sensors()
+        time.sleep(1.0)
+    
+main()
+
+