32x64 3-color message board http://elektorembedded.blogspot.com/

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
Clemo
Date:
Wed May 05 12:04:34 2010 +0000
Commit message:

Changed in this revision

arial_8pt.c Show annotated file Show diff for this revision Revisions of this file
arial_8pt.h Show annotated file Show diff for this revision Revisions of this file
font.h Show annotated file Show diff for this revision Revisions of this file
ini.c Show annotated file Show diff for this revision Revisions of this file
ini.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arial_8pt.c	Wed May 05 12:04:34 2010 +0000
@@ -0,0 +1,405 @@
+/* 
+**  Font data for Arial 8pt
+*/
+
+#include "font.h"
+#include "arial_8pt.h"
+
+/* Character bitmaps for Arial 8pt */
+const uint8_t arial_8pt_char_bitmaps[] = 
+{
+    /* @0 ' ' (2 pixels wide) */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+    /* @10 '!' (1 pixels wide) */
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 
+
+    /* @20 '"' (3 pixels wide) */
+    0xA0, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+    /* @30 '#' (5 pixels wide) */
+    0x28, 0x28, 0xF8, 0x50, 0x50, 0xF8, 0xA0, 0xA0, 0x00, 0x00, 
+
+    /* @40 '$' (5 pixels wide) */
+    0x70, 0xA8, 0xA0, 0x70, 0x28, 0x28, 0xA8, 0x70, 0x20, 0x00, 
+
+    /* @50 '%' (9 pixels wide) */
+    0x62, 0x00, 0x94, 0x00, 0x94, 0x00, 0x68, 0x00, 0x0B, 0x00, 0x14, 0x80, 0x14, 0x80, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+    /* @70 '&' (6 pixels wide) */
+    0x30, 0x48, 0x48, 0x30, 0x50, 0x8C, 0x88, 0x74, 0x00, 0x00, 
+
+    /* @80 ''' (1 pixels wide) */
+    0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+    /* @90 '(' (3 pixels wide) */
+    0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40, 0x20, 
+
+    /* @100 ')' (3 pixels wide) */
+    0x80, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x80, 
+
+    /* @110 '*' (3 pixels wide) */
+    0x40, 0xE0, 0x40, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+    /* @120 '+' (5 pixels wide) */
+    0x00, 0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00, 0x00, 
+
+    /* @130 ',' (1 pixels wide) */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 
+
+    /* @140 '-' (3 pixels wide) */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 
+
+    /* @150 '.' (1 pixels wide) */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 
+
+    /* @160 '/' (3 pixels wide) */
+    0x20, 0x20, 0x40, 0x40, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 
+
+    /* @170 '0' (5 pixels wide) */
+    0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 
+
+    /* @180 '1' (3 pixels wide) */
+    0x20, 0x60, 0xA0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 
+
+    /* @190 '2' (5 pixels wide) */
+    0x70, 0x88, 0x08, 0x08, 0x10, 0x20, 0x40, 0xF8, 0x00, 0x00, 
+
+    /* @200 '3' (5 pixels wide) */
+    0x70, 0x88, 0x08, 0x30, 0x08, 0x08, 0x88, 0x70, 0x00, 0x00, 
+
+    /* @210 '4' (5 pixels wide) */
+    0x10, 0x30, 0x50, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00, 0x00, 
+
+    /* @220 '5' (5 pixels wide) */
+    0x78, 0x40, 0x80, 0xF0, 0x08, 0x08, 0x88, 0x70, 0x00, 0x00, 
+
+    /* @230 '6' (5 pixels wide) */
+    0x70, 0x88, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 
+
+    /* @240 '7' (5 pixels wide) */
+    0xF8, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x40, 0x00, 0x00, 
+
+    /* @250 '8' (5 pixels wide) */
+    0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 
+
+    /* @260 '9' (5 pixels wide) */
+    0x70, 0x88, 0x88, 0x88, 0x78, 0x08, 0x88, 0x70, 0x00, 0x00, 
+
+    /* @270 ':' (1 pixels wide) */
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 
+
+    /* @280 ';' (1 pixels wide) */
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 
+
+    /* @290 '<' (5 pixels wide) */
+    0x00, 0x00, 0x08, 0x70, 0x80, 0x70, 0x08, 0x00, 0x00, 0x00, 
+
+    /* @300 '=' (5 pixels wide) */
+    0x00, 0x00, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 
+
+    /* @310 '>' (5 pixels wide) */
+    0x00, 0x00, 0x80, 0x70, 0x08, 0x70, 0x80, 0x00, 0x00, 0x00, 
+
+    /* @320 '?' (5 pixels wide) */
+    0x70, 0x88, 0x08, 0x10, 0x20, 0x20, 0x00, 0x20, 0x00, 0x00, 
+
+    /* @330 '@' (10 pixels wide) */
+    0x1F, 0x00, 0x60, 0x80, 0x4D, 0x40, 0x93, 0x40, 0xA2, 0x40, 0xA2, 0x40, 0xA6, 0x80, 0x9B, 0x00, 0x40, 0x40, 0x3F, 0x80, 
+
+    /* @350 'A' (7 pixels wide) */
+    0x10, 0x28, 0x28, 0x28, 0x44, 0x7C, 0x82, 0x82, 0x00, 0x00, 
+
+    /* @360 'B' (6 pixels wide) */
+    0xF8, 0x84, 0x84, 0xFC, 0x84, 0x84, 0x84, 0xF8, 0x00, 0x00, 
+
+    /* @370 'C' (6 pixels wide) */
+    0x38, 0x44, 0x80, 0x80, 0x80, 0x80, 0x44, 0x38, 0x00, 0x00, 
+
+    /* @380 'D' (6 pixels wide) */
+    0xF0, 0x88, 0x84, 0x84, 0x84, 0x84, 0x88, 0xF0, 0x00, 0x00, 
+
+    /* @390 'E' (5 pixels wide) */
+    0xF8, 0x80, 0x80, 0xF8, 0x80, 0x80, 0x80, 0xF8, 0x00, 0x00, 
+
+    /* @400 'F' (5 pixels wide) */
+    0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 
+
+    /* @410 'G' (7 pixels wide) */
+    0x38, 0x44, 0x82, 0x80, 0x8E, 0x82, 0x44, 0x38, 0x00, 0x00, 
+
+    /* @420 'H' (6 pixels wide) */
+    0x84, 0x84, 0x84, 0xFC, 0x84, 0x84, 0x84, 0x84, 0x00, 0x00, 
+
+    /* @430 'I' (1 pixels wide) */
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 
+
+    /* @440 'J' (4 pixels wide) */
+    0x10, 0x10, 0x10, 0x10, 0x10, 0x90, 0x90, 0x60, 0x00, 0x00, 
+
+    /* @450 'K' (6 pixels wide) */
+    0x84, 0x88, 0x90, 0xB0, 0xD0, 0x88, 0x88, 0x84, 0x00, 0x00, 
+
+    /* @460 'L' (5 pixels wide) */
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8, 0x00, 0x00, 
+
+    /* @470 'M' (7 pixels wide) */
+    0x82, 0xC6, 0xC6, 0xAA, 0xAA, 0xAA, 0x92, 0x92, 0x00, 0x00, 
+
+    /* @480 'N' (6 pixels wide) */
+    0x84, 0xC4, 0xA4, 0xA4, 0x94, 0x94, 0x8C, 0x84, 0x00, 0x00, 
+
+    /* @490 'O' (7 pixels wide) */
+    0x38, 0x44, 0x82, 0x82, 0x82, 0x82, 0x44, 0x38, 0x00, 0x00, 
+
+    /* @500 'P' (5 pixels wide) */
+    0xF0, 0x88, 0x88, 0x88, 0xF0, 0x80, 0x80, 0x80, 0x00, 0x00, 
+
+    /* @510 'Q' (7 pixels wide) */
+    0x38, 0x44, 0x82, 0x82, 0x82, 0x9A, 0x44, 0x3A, 0x00, 0x00, 
+
+    /* @520 'R' (6 pixels wide) */
+    0xF8, 0x84, 0x84, 0xF8, 0x90, 0x88, 0x88, 0x84, 0x00, 0x00, 
+
+    /* @530 'S' (6 pixels wide) */
+    0x78, 0x84, 0x80, 0x60, 0x18, 0x04, 0x84, 0x78, 0x00, 0x00, 
+
+    /* @540 'T' (5 pixels wide) */
+    0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 
+
+    /* @550 'U' (6 pixels wide) */
+    0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x78, 0x00, 0x00, 
+
+    /* @560 'V' (7 pixels wide) */
+    0x82, 0x82, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 
+
+    /* @570 'W' (11 pixels wide) */
+    0x84, 0x20, 0x8A, 0x20, 0x4A, 0x40, 0x4A, 0x40, 0x51, 0x40, 0x51, 0x40, 0x20, 0x80, 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 
+
+    /* @590 'X' (6 pixels wide) */
+    0x84, 0x48, 0x48, 0x30, 0x30, 0x48, 0x48, 0x84, 0x00, 0x00, 
+
+    /* @600 'Y' (7 pixels wide) */
+    0x82, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 
+
+    /* @610 'Z' (6 pixels wide) */
+    0x7C, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0xFC, 0x00, 0x00, 
+
+    /* @620 '[' (2 pixels wide) */
+    0xC0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0, 
+
+    /* @630 '\' (3 pixels wide) */
+    0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 
+
+    /* @640 ']' (2 pixels wide) */
+    0xC0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xC0, 
+
+    /* @650 '^' (5 pixels wide) */
+    0x20, 0x50, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+    /* @660 '_' (6 pixels wide) */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 
+
+    /* @670 '`' (2 pixels wide) */
+    0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+    /* @680 'a' (5 pixels wide) */
+    0x00, 0x00, 0x70, 0x88, 0x78, 0x88, 0x98, 0x68, 0x00, 0x00, 
+
+    /* @690 'b' (5 pixels wide) */
+    0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0xC8, 0xB0, 0x00, 0x00, 
+
+    /* @700 'c' (5 pixels wide) */
+    0x00, 0x00, 0x70, 0x88, 0x80, 0x80, 0x88, 0x70, 0x00, 0x00, 
+
+    /* @710 'd' (5 pixels wide) */
+    0x08, 0x08, 0x68, 0x98, 0x88, 0x88, 0x98, 0x68, 0x00, 0x00, 
+
+    /* @720 'e' (5 pixels wide) */
+    0x00, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x88, 0x70, 0x00, 0x00, 
+
+    /* @730 'f' (3 pixels wide) */
+    0x20, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 
+
+    /* @740 'g' (5 pixels wide) */
+    0x00, 0x00, 0x68, 0x98, 0x88, 0x88, 0x98, 0x68, 0x08, 0xF0, 
+
+    /* @750 'h' (5 pixels wide) */
+    0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 
+
+    /* @760 'i' (1 pixels wide) */
+    0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 
+
+    /* @770 'j' (2 pixels wide) */
+    0x40, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x80, 
+
+    /* @780 'k' (4 pixels wide) */
+    0x80, 0x80, 0x90, 0xA0, 0xC0, 0xA0, 0xA0, 0x90, 0x00, 0x00, 
+
+    /* @790 'l' (1 pixels wide) */
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 
+
+    /* @800 'm' (7 pixels wide) */
+    0x00, 0x00, 0xBC, 0xD2, 0x92, 0x92, 0x92, 0x92, 0x00, 0x00, 
+
+    /* @810 'n' (5 pixels wide) */
+    0x00, 0x00, 0xF0, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 
+
+    /* @820 'o' (5 pixels wide) */
+    0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 
+
+    /* @830 'p' (5 pixels wide) */
+    0x00, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0xC8, 0xB0, 0x80, 0x80, 
+
+    /* @840 'q' (5 pixels wide) */
+    0x00, 0x00, 0x68, 0x98, 0x88, 0x88, 0x98, 0x68, 0x08, 0x08, 
+
+    /* @850 'r' (3 pixels wide) */
+    0x00, 0x00, 0xA0, 0xC0, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 
+
+    /* @860 's' (5 pixels wide) */
+    0x00, 0x00, 0x70, 0x88, 0x60, 0x10, 0x88, 0x70, 0x00, 0x00, 
+
+    /* @870 't' (3 pixels wide) */
+    0x40, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x60, 0x00, 0x00, 
+
+    /* @880 'u' (5 pixels wide) */
+    0x00, 0x00, 0x88, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00, 0x00, 
+
+    /* @890 'v' (5 pixels wide) */
+    0x00, 0x00, 0x88, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00, 0x00, 
+
+    /* @900 'w' (9 pixels wide) */
+    0x00, 0x00, 0x00, 0x00, 0x88, 0x80, 0x94, 0x80, 0x55, 0x00, 0x55, 0x00, 0x22, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+    /* @920 'x' (5 pixels wide) */
+    0x00, 0x00, 0x88, 0x50, 0x20, 0x20, 0x50, 0x88, 0x00, 0x00, 
+
+    /* @930 'y' (5 pixels wide) */
+    0x00, 0x00, 0x88, 0x88, 0x50, 0x50, 0x20, 0x20, 0x20, 0x40, 
+
+    /* @940 'z' (5 pixels wide) */
+    0x00, 0x00, 0xF8, 0x10, 0x20, 0x20, 0x40, 0xF8, 0x00, 0x00, 
+
+    /* @950 '{' (3 pixels wide) */
+    0x20, 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 
+
+    /* @960 '|' (1 pixels wide) */
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 
+
+    /* @970 '}' (3 pixels wide) */
+    0x80, 0x40, 0x40, 0x40, 0x20, 0x40, 0x40, 0x40, 0x40, 0x80, 
+
+    /* @980 '~' (5 pixels wide) */
+    0x00, 0x00, 0x00, 0xE8, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 
+};
+
+/* Character descriptors for Arial 8pt */
+/* { [Char width in bits], [Offset into arial8ptCharBitmaps in bytes] } */
+const FONT_CHAR_INFO arial_8pt_char_descriptors[] =
+{
+    {2, 0},         /*   */
+    {1, 10},         /* ! */
+    {3, 20},         /* " */
+    {5, 30},         /* # */
+    {5, 40},         /* $ */
+    {9, 50},         /* % */
+    {6, 70},         /* & */
+    {1, 80},         /* ' */
+    {3, 90},         /* ( */
+    {3, 100},         /* ) */
+    {3, 110},         /* * */
+    {5, 120},         /* + */
+    {1, 130},         /* , */
+    {3, 140},         /* - */
+    {1, 150},         /* . */
+    {3, 160},         /* / */
+    {5, 170},         /* 0 */
+    {3, 180},         /* 1 */
+    {5, 190},         /* 2 */
+    {5, 200},         /* 3 */
+    {5, 210},         /* 4 */
+    {5, 220},         /* 5 */
+    {5, 230},         /* 6 */
+    {5, 240},         /* 7 */
+    {5, 250},         /* 8 */
+    {5, 260},         /* 9 */
+    {1, 270},         /* : */
+    {1, 280},         /* ; */
+    {5, 290},         /* < */
+    {5, 300},         /* = */
+    {5, 310},         /* > */
+    {5, 320},         /* ? */
+    {10, 330},         /* @ */
+    {7, 350},         /* A */
+    {6, 360},         /* B */
+    {6, 370},         /* C */
+    {6, 380},         /* D */
+    {5, 390},         /* E */
+    {5, 400},         /* F */
+    {7, 410},         /* G */
+    {6, 420},         /* H */
+    {1, 430},         /* I */
+    {4, 440},         /* J */
+    {6, 450},         /* K */
+    {5, 460},         /* L */
+    {7, 470},         /* M */
+    {6, 480},         /* N */
+    {7, 490},         /* O */
+    {5, 500},         /* P */
+    {7, 510},         /* Q */
+    {6, 520},         /* R */
+    {6, 530},         /* S */
+    {5, 540},         /* T */
+    {6, 550},         /* U */
+    {7, 560},         /* V */
+    {11, 570},         /* W */
+    {6, 590},         /* X */
+    {7, 600},         /* Y */
+    {6, 610},         /* Z */
+    {2, 620},         /* [ */
+    {3, 630},         /* \ */
+    {2, 640},         /* ] */
+    {5, 650},         /* ^ */
+    {6, 660},         /* _ */
+    {2, 670},         /* ` */
+    {5, 680},         /* a */
+    {5, 690},         /* b */
+    {5, 700},         /* c */
+    {5, 710},         /* d */
+    {5, 720},         /* e */
+    {3, 730},         /* f */
+    {5, 740},         /* g */
+    {5, 750},         /* h */
+    {1, 760},         /* i */
+    {2, 770},         /* j */
+    {4, 780},         /* k */
+    {1, 790},         /* l */
+    {7, 800},         /* m */
+    {5, 810},         /* n */
+    {5, 820},         /* o */
+    {5, 830},         /* p */
+    {5, 840},         /* q */
+    {3, 850},         /* r */
+    {5, 860},         /* s */
+    {3, 870},         /* t */
+    {5, 880},         /* u */
+    {5, 890},         /* v */
+    {9, 900},         /* w */
+    {5, 920},         /* x */
+    {5, 930},         /* y */
+    {5, 940},         /* z */
+    {3, 950},         /* { */
+    {1, 960},         /* | */
+    {3, 970},         /* } */
+    {5, 980},         /* ~ */
+};
+
+/* Font information for Arial 8pt */
+const FONT_INFO arial_8pt_font_info =
+{
+    10, /*  Character height in bits */
+    ' ', /*  Start character */
+    arial_8pt_char_descriptors, /*  Character decriptor array */
+    arial_8pt_char_bitmaps, /*  Character bitmap array */
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arial_8pt.h	Wed May 05 12:04:34 2010 +0000
@@ -0,0 +1,11 @@
+#ifndef __ARIAL_8PT_H__
+#define __ARIAL_8PT_H__
+
+
+/* Font data for Arial 8pt */
+extern const uint8_t arial_8pt_char_bitmaps[];
+extern const FONT_CHAR_INFO arial_8pt_char_descriptors[];
+extern const FONT_INFO arial_8pt_font_info;
+
+
+#endif // __ARIAL_8PT_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/font.h	Wed May 05 12:04:34 2010 +0000
@@ -0,0 +1,26 @@
+#ifndef __FONT_H__
+#define __FONT_H__
+
+
+typedef unsigned char uint8_t;
+
+
+typedef struct
+{
+  int width; // Character width in bits.
+  int offset; // Offset in bytes into font bitmap.
+}
+FONT_CHAR_INFO;
+
+
+typedef struct
+{
+  int height; // Character height in bits.
+  char start_char; // Start character.
+  const FONT_CHAR_INFO *p_character_descriptor; // Character decriptor array.
+  const uint8_t *p_character_bitmaps; // Character bitmap array.
+}
+FONT_INFO;
+
+
+#endif // __FONT_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ini.c	Wed May 05 12:04:34 2010 +0000
@@ -0,0 +1,130 @@
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+http://code.google.com/p/inih/
+
+*/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "ini.h"
+
+#define MAX_LINE 200
+#define MAX_SECTION 50
+#define MAX_NAME 50
+
+/* Strip whitespace chars off end of given string, in place. Return s. */
+static char* rstrip(char* s)
+{
+    char* p = s + strlen(s);
+    while (p > s && isspace(*--p))
+        *p = '\0';
+    return s;
+}
+
+/* Return pointer to first non-whitespace char in given string. */
+static char* lskip(const char* s)
+{
+    while (*s && isspace(*s))
+        s++;
+    return (char*)s;
+}
+
+/* Return pointer to first char c or ';' in given string, or pointer to
+   null at end of string if neither found. */
+static char* find_char_or_comment(const char* s, char c)
+{
+    while (*s && *s != c && *s != ';')
+        s++;
+    return (char*)s;
+}
+
+/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
+static char* strncpy0(char* dest, const char* src, size_t size)
+{
+    strncpy(dest, src, size);
+    dest[size - 1] = '\0';
+    return dest;
+}
+
+/* See documentation in header file. */
+int ini_parse(const char* filename,
+              int (*handler)(void*, const char*, const char*, const char*),
+              void* user)
+{
+    /* Uses a fair bit of stack (use heap instead if you need to) */
+    char line[MAX_LINE];
+    char section[MAX_SECTION] = "";
+    char prev_name[MAX_NAME] = "";
+
+    FILE* file;
+    char* start;
+    char* end;
+    char* name;
+    char* value;
+    int lineno = 0;
+    int error = 0;
+
+    file = fopen(filename, "r");
+    if (!file)
+        return -1;
+
+    /* Scan through file line by line */
+    while (fgets(line, sizeof(line), file) != NULL) {
+        lineno++;
+        start = lskip(rstrip(line));
+
+#if INI_ALLOW_MULTILINE
+        if (*prev_name && *start && start > line) {
+            /* Non-black line with leading whitespace, treat as continuation
+               of previous name's value (as per Python ConfigParser). */
+            if (!handler(user, section, prev_name, start) && !error)
+                error = lineno;
+        }
+        else
+#endif
+        if (*start == '[') {
+            /* A "[section]" line */
+            end = find_char_or_comment(start + 1, ']');
+            if (*end == ']') {
+                *end = '\0';
+                strncpy0(section, start + 1, sizeof(section));
+                *prev_name = '\0';
+            }
+            else if (!error) {
+                /* No ']' found on section line */
+                error = lineno;
+            }
+        }
+        else if (*start && *start != ';') {
+            /* Not a comment, must be a name=value pair */
+            end = find_char_or_comment(start, '=');
+            if (*end == '=') {
+                *end = '\0';
+                name = rstrip(start);
+                value = lskip(end + 1);
+                end = find_char_or_comment(value, ';');
+                if (*end == ';')
+                    *end = '\0';
+                rstrip(value);
+
+                /* Valid name=value pair found, call handler */
+                strncpy0(prev_name, name, sizeof(prev_name));
+                if (!handler(user, section, name, value) && !error)
+                    error = lineno;
+            }
+            else if (!error) {
+                /* No '=' found on name=value line */
+                error = lineno;
+            }
+        }
+    }
+
+    fclose(file);
+
+    return error;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ini.h	Wed May 05 12:04:34 2010 +0000
@@ -0,0 +1,45 @@
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+http://code.google.com/p/inih/
+
+*/
+
+#ifndef __INI_H__
+#define __INI_H__
+
+/* Make this header file easier to include in C++ code */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Parse given INI-style file. May have [section]s, name=value pairs
+   (whitespace stripped), and comments starting with ';' (semicolon). Section
+   is "" if name=value pair parsed before any section heading.
+
+   For each name=value pair parsed, call handler function with given user
+   pointer as well as section, name, and value (data only valid for duration
+   of handler call). Handler should return nonzero on success, zero on error.
+
+   Returns 0 on success, line number of first error on parse error, or -1 on
+   file open error.
+*/
+int ini_parse(const char* filename,
+              int (*handler)(void* user, const char* section,
+                             const char* name, const char* value),
+              void* user);
+
+/* Nonzero to allow multi-line value parsing, in the style of Python's
+   ConfigParser. If allowed, ini_parse() will call the handler with the same
+   name for each subsequent line parsed. */
+#ifndef INI_ALLOW_MULTILINE
+#define INI_ALLOW_MULTILINE 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INI_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed May 05 12:04:34 2010 +0000
@@ -0,0 +1,543 @@
+#include "mbed.h"
+#include "font.h"
+#include "arial_8pt.h"
+#include "ini.h"
+#include <ctype.h>
+
+
+#define ROWS  16 /* Two rows are drawn "in parallel". */
+#define COLUMNS  64
+
+typedef enum
+{
+  kOrange = 0,
+  kGreen = 1,
+  kRed = 2,
+  kBlack = 3
+}
+color_t;
+
+typedef struct
+{
+  unsigned char pixel[COLUMNS]; // Contains data for 2 rows!
+}
+row_t;
+
+typedef struct
+{
+  int rows;
+  int columns;
+  row_t row[ROWS];
+}
+matrix_t;
+
+matrix_t Panel;
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+
+DigitalOut Enable(p5); // enable
+DigitalOut Clock(p15); // clock per bit
+DigitalOut Latch(p14); // latch per line
+DigitalOut R1(p6); // Red upper half
+DigitalOut R2(p7); // Red lower half
+DigitalOut G1(p12); // Green upper half
+DigitalOut G2(p13); // Green lower half
+BusOut Row(p8,p9,p10,p11);
+
+DigitalIn Switch(p20); // Day selection switch.
+
+#define PANEL_ON  Enable = 0
+#define PANEL_OFF  Enable = 1
+#define CLOCK_DATA  Clock=0; Clock=1
+#define LATCH_DATA  Latch=0; Latch=1
+
+Serial PC(USBTX,USBRX); // USB serial port.
+LocalFileSystem local("local"); // File system.
+const char *ini_file = "/local/pages.ini";
+
+#define MAX_LINES  (4)
+#define MAX_LINE_LENGTH  (128) /* Use very long lines for easy scrolling, we have plenty of memory. */
+#define MAX_PAGES  (7)
+#define SCROLL_GAP  (24)  /* in pixels */
+
+
+typedef struct
+{
+  char str[MAX_LINE_LENGTH];
+  color_t color;
+  int x;
+  int y;
+  int scroll;  // <0=left, 0=no scroll, >0=right
+  int strlen_pixels; // String length in pixels.
+}
+line_t;
+
+typedef struct
+{
+  line_t line[MAX_LINES];
+  int hide;
+}
+page_entry_t;
+
+page_entry_t pages[MAX_PAGES];
+
+
+struct
+{
+  float scroll_speed;
+  float brightness;
+}
+app_data;
+
+
+void led_sweep();
+void panel_load(unsigned char *p_pixel, int nr_of_pixels);
+void panel_refresh_row(int nr, row_t *p_pixel_data, int nr_of_pixels);
+void panel_refresh(matrix_t *p_panel);
+void panel_init(matrix_t& panel, int rows, int columns);
+void panel_fill_row(row_t *p_row, unsigned char value, int count);
+void panel_fill_matrix(matrix_t& panel, unsigned char value);
+void put_pixel(matrix_t& panel, unsigned int x, unsigned int y, color_t color);
+int put_char_xy(matrix_t& panel, char ch, unsigned int x, unsigned int y, const FONT_INFO *p_font, color_t color);
+int put_string_xy(matrix_t& panel, char *p_str, unsigned int x, unsigned int y, const FONT_INFO *p_font, color_t color);
+int measure_string(char *p_str, const FONT_INFO *p_font);
+void clear_display(void);
+int is_valid_char(char ch);
+color_t str_to_color(const char *p_str);
+int ini_file_handler(void* user, const char* section, const char* name, const char* value);
+void page_pre_init(void);
+void page_post_init(const FONT_INFO *p_font);
+int page_next(int page);
+int page_show(matrix_t& panel, int p);
+
+
+void led_sweep()
+{
+  led1 = 0;
+  led2 = 0;
+  led3 = 0;
+  led4 = 0;
+  led1 = 1;
+  wait(0.05);
+  led1 = 0;
+  led2 = 1;
+  wait(0.05);
+  led2 = 0;
+  led3 = 1;
+  wait(0.05);
+  led3 = 0;
+  led4 = 1;
+  wait(0.05);
+  led4 = 0;
+}
+
+
+// Clock the data into the display.
+// This is where the bit-banging happens.
+void panel_load(unsigned char *p_pixel, int nr_of_pixels)
+{
+  int i;
+  for (i=0; i<nr_of_pixels; i++)
+  {
+    unsigned char pixel = p_pixel[i];
+    R1 = pixel & 0x01;
+    pixel >>= 1;
+    G1 = pixel & 0x01;
+    pixel >>= 1;
+    R2 = pixel & 0x01;
+    pixel >>= 1;
+    G2 = pixel & 0x01;
+    CLOCK_DATA;
+  }
+  LATCH_DATA;
+}
+
+
+void panel_refresh_row(int nr, row_t *p_pixel_data, int nr_of_pixels)
+{
+  Row = nr;
+  panel_load(p_pixel_data->pixel,nr_of_pixels);
+  PANEL_ON;
+  wait(app_data.brightness);
+  PANEL_OFF;
+}
+
+
+void panel_refresh(matrix_t *p_panel)
+{
+  int i;
+  for (i=0; i<p_panel->rows; i++)
+  {
+    panel_refresh_row(i,&p_panel->row[i],p_panel->columns);
+  }
+}
+
+
+void panel_init(matrix_t& panel, int rows, int columns)
+{
+  CLOCK_DATA; // Init the clock line
+  LATCH_DATA; // Reset the shift registers
+  panel.rows = rows;
+  panel.columns = columns;
+  panel_fill_matrix(panel,kBlack); // Clear display.
+}
+
+
+void panel_fill_row(row_t *p_row, unsigned char value, int count)
+{
+  int i;
+  for (i=0; i<count; i++)
+  {
+    p_row->pixel[i] = value;
+  }
+}
+
+
+void panel_fill_matrix(matrix_t& panel, unsigned char value)
+{
+  int i;
+  for (i=0; i<panel.rows; i++)
+  {
+    // Two rows are stored in one row...
+    panel_fill_row(&panel.row[i],(value<<2)+value,panel.columns);
+  }
+}
+
+
+void put_pixel(matrix_t& panel, unsigned int x, unsigned int y, color_t color)
+{
+  unsigned char mask;
+  unsigned char c;
+
+  if (x<panel.columns && y<2*panel.rows)
+  {
+    mask = 0x03;
+    c = color;
+    if (y>=panel.rows)
+    {
+      // Remember: two rows are stored in one.
+      y -= panel.rows;
+      c <<= 2;
+      mask <<= 2;
+    }
+    c |= ~mask; // Do not overwrite the other pixel.
+    panel.row[y].pixel[x] |= mask; // Clear pixel (pixels are active low!).
+    panel.row[y].pixel[x] &= c; // Add in the zeroes.
+  }
+}
+
+
+int put_char_xy(matrix_t& panel, char ch, unsigned int x, unsigned int y, const FONT_INFO *p_font, color_t color)
+{
+  int i, h, w;
+  if (p_font!=NULL)
+  {
+    i = ch - p_font->start_char;
+    int width = p_font->p_character_descriptor[i].width;
+    int second_byte = 0;
+    if (width>8)
+    {
+      // Some wide characters are coded in two bytes.
+      second_byte = width - 8;
+      width = 8;
+    }
+    int offset = p_font->p_character_descriptor[i].offset;
+    const uint8_t *p_char = p_font->p_character_bitmaps + offset;
+    uint8_t mask;
+    for (h=0; h<p_font->height; h++)
+    {
+      // Plot pixels for first byte.
+      mask = 0x80;
+      for (w=0; w<width; w++)
+      {
+        if ((*p_char&mask)!=0) put_pixel(panel,x+w,y+h,color);
+        mask >>= 1;
+      }
+      if (second_byte>0)
+      {
+        // Handle 2nd byte of extra wide characters.
+        p_char += 1;
+        mask = 0x80;
+        for (w=0; w<second_byte; w++)
+        {
+          if ((*p_char&mask)!=0) put_pixel(panel,x+w+8,y+h,color);
+          mask >>= 1;
+        }
+      }
+      p_char += 1;
+    }
+    return p_font->p_character_descriptor[i].width;
+  }
+  return 0;
+}
+
+
+int put_string_xy(matrix_t& panel, char *p_str, unsigned int x, unsigned int y, const FONT_INFO *p_font, color_t color)
+{
+  int _x = 0;
+  while (*p_str!=0)
+  {
+    _x += put_char_xy(panel,*p_str,x+_x,y,p_font,color);
+    _x += 1;
+    p_str += 1;
+  }
+  return _x>0? _x-1 : 0;
+}
+
+
+// Return the length of a string in pixels when printed using the provided font.
+int measure_string(char *p_str, const FONT_INFO *p_font)
+{
+  int i;
+  int strlen_pixels = 0;
+  if (p_font!=NULL)
+  {
+    while (*p_str!=0)
+    {
+      i = *p_str - p_font->start_char;
+      strlen_pixels += p_font->p_character_descriptor[i].width;
+      strlen_pixels += 1;
+      p_str += 1;
+    }
+  }
+  return strlen_pixels;
+}
+
+
+void clear_display(void)
+{
+  panel_fill_matrix(Panel,kBlack);
+}
+
+
+int is_valid_char(char ch)
+{
+  return (ch>=' ' && ch<='~');
+}
+
+#define IS_SECTION(a)  if (strcmp(p_section,(a))==0)
+#define IS_NAME(a)  if (strcmp(p_name,(a))==0)
+#define IS_VALUE(a)  if (strcmp(p_value,(a))==0)
+
+color_t str_to_color(const char *p_str)
+{
+  color_t color = kGreen;
+  if (strcmp(p_str,"green")==0) color = kGreen;
+  else if (strcmp(p_str,"orange")==0) color = kOrange;
+  else if (strcmp(p_str,"red")==0) color = kRed;
+  else if (strcmp(p_str,"black")==0) color = kBlack;
+  return color;
+}
+
+
+int ini_file_handler(void *p_user, const char *p_section, const char *p_name, const char *p_value)
+{
+  // Called from ini.c
+  
+  int p = 0;
+  
+  IS_SECTION("global")
+  {
+    IS_NAME("brightness") app_data.brightness = atof(p_value)/10000.0;
+    else IS_NAME("speed") app_data.scroll_speed = atof(p_value)/1000.0;
+  }
+  else IS_SECTION("page1") p = 0;
+  else IS_SECTION("page2") p = 1;
+  else IS_SECTION("page3") p = 2;
+  else IS_SECTION("page4") p = 3;
+  else IS_SECTION("page5") p = 4;
+  else IS_SECTION("page6") p = 5;
+  else IS_SECTION("page7") p = 6;
+
+       IS_NAME("hide") pages[p].hide = atoi(p_value);
+  else IS_NAME("text1") strcpy(pages[p].line[0].str,p_value);
+  else IS_NAME("text2") strcpy(pages[p].line[1].str,p_value);
+  else IS_NAME("text3") strcpy(pages[p].line[2].str,p_value);
+  else IS_NAME("text4") strcpy(pages[p].line[3].str,p_value);
+  else IS_NAME("color1") pages[p].line[0].color = str_to_color(p_value);
+  else IS_NAME("color2") pages[p].line[1].color = str_to_color(p_value);
+  else IS_NAME("color3") pages[p].line[2].color = str_to_color(p_value);
+  else IS_NAME("color4") pages[p].line[3].color = str_to_color(p_value);
+  else IS_NAME("x1") pages[p].line[0].x = atoi(p_value);
+  else IS_NAME("x2") pages[p].line[1].x = atoi(p_value);
+  else IS_NAME("x3") pages[p].line[2].x = atoi(p_value);
+  else IS_NAME("x4") pages[p].line[3].x = atoi(p_value);
+  else IS_NAME("y1") pages[p].line[0].y = atoi(p_value);
+  else IS_NAME("y2") pages[p].line[1].y = atoi(p_value);
+  else IS_NAME("y3") pages[p].line[2].y = atoi(p_value);
+  else IS_NAME("y4") pages[p].line[3].y = atoi(p_value);
+  else IS_NAME("scroll1") pages[p].line[0].scroll = atoi(p_value);
+  else IS_NAME("scroll2") pages[p].line[1].scroll = atoi(p_value);
+  else IS_NAME("scroll3") pages[p].line[2].scroll = atoi(p_value);
+  else IS_NAME("scroll4") pages[p].line[3].scroll = atoi(p_value);
+
+  // Return 0 on error.
+  return 1;
+}
+
+
+void page_pre_init(void)
+{
+  int i, j;
+  int y;
+  // Set zero default values.
+  memset(&pages,0,sizeof(pages));
+  for (j=0; j<MAX_PAGES; j++)
+  {
+    y = 0;
+    for (i=0; i<MAX_LINES; i++)
+    {
+      // Set non-zero default values.
+      pages[j].line[i].color = kBlack;
+      pages[j].line[i].y = y;
+      y += 8;
+    }
+  }
+}
+
+
+void page_post_init(const FONT_INFO *p_font)
+{
+  int i, j;
+  for (j=0; j<MAX_PAGES; j++)
+  {
+    for (i=0; i<MAX_LINES; i++)
+    {
+      // We need to know the length in pixels of each string.
+      pages[j].line[i].strlen_pixels = measure_string(pages[j].line[i].str,p_font);
+    }
+  }
+}
+
+
+int page_next(int page)
+{
+  page += 1;
+  if (page<0) page = MAX_PAGES - 1;
+  else if (page>=MAX_PAGES) page = 0;
+  return page;
+}
+
+
+int page_show(matrix_t& panel, int p)
+{
+  int i;
+  clear_display();
+  // Show page if not hidden.
+  if (pages[p].hide==0)
+  {
+    for (i=0; i<MAX_LINES; i++)
+    {
+      int x = pages[p].line[i].x;
+      // Print the string.
+      put_string_xy(panel,pages[p].line[i].str,x,pages[p].line[i].y,&arial_8pt_font_info,pages[p].line[i].color);
+      // Handle scrolling.
+      if (pages[p].line[i].scroll!=0)
+      {
+        // Simply print the string a second time, display clipping will prevent 
+        // artifacts when a string is partly printed off-screen.
+        if (pages[p].line[i].scroll<0)
+        {
+          // Scroll to the left.
+          x += (pages[p].line[i].strlen_pixels + SCROLL_GAP);
+          // Reset the starting point when the string is completely off screen.
+          if (pages[p].line[i].x+pages[p].line[i].strlen_pixels<0) pages[p].line[i].x = x;
+        }
+        else if (pages[p].line[i].scroll>0)
+        {
+          // Scroll to the right.
+          x -= (pages[p].line[i].strlen_pixels + SCROLL_GAP);
+          // Reset the starting point when the string is completely off screen.
+          if (pages[p].line[i].x>=COLUMNS) pages[p].line[i].x = x;
+        }
+        put_string_xy(panel,pages[p].line[i].str,x,pages[p].line[i].y,&arial_8pt_font_info,pages[p].line[i].color);
+        
+        // Update x position.
+        pages[p].line[i].x += pages[p].line[i].scroll;
+      }
+    }
+  }
+  else p = page_next(p); // Page is hidden, move on to the next page.
+
+  return p;
+}
+
+
+int main() 
+{
+  int page = 0;
+  int debounce = 0;
+  const FONT_INFO *p_font = &arial_8pt_font_info;
+
+  PC.printf("\nmbed LED panel experiments\n");
+  led_sweep();
+
+  led1 = 0;
+  led2 = 0;
+  led3 = 0;
+  led4 = 0;
+  
+  // Set some default values.
+  app_data.brightness = 0.0005;
+  app_data.scroll_speed = 0.001;
+
+  // Setup display.
+  PANEL_OFF;
+  panel_init(Panel,ROWS,COLUMNS);
+
+  // Read page data.
+  page_pre_init();
+  int error = false;
+  error = ini_parse(ini_file,ini_file_handler,0);
+  page_post_init(p_font);
+  
+  //sprintf(pages[0].line[0].str,"%0.3f",app_data.scroll_speed);
+  
+  while (1)
+  {
+    if (error==true)
+    {
+      put_string_xy(Panel,"file not found",0,0,p_font,kRed);
+    }
+    else
+    {
+      page = page_show(Panel,page);
+    }
+
+    // Handle next-page switch.
+    if (Switch==1)
+    {
+      if (debounce<10) debounce += 1;
+      else if (debounce==10)
+      {
+        debounce += 1;
+        page = page_next(page);
+        clear_display();
+      }
+    }
+    else debounce = 0;
+            
+    /*if (PC.readable()) 
+    {
+      int ch;
+      ch = PC.getc();
+      PC.putc(ch);
+      if (ch=='B') color = kBlack;
+      else if (ch=='R') color = kRed;
+      else if (ch=='O') color = kOrange;
+      else if (ch=='G') color = kGreen;
+      else if (ch=='x') x -= 1;
+      else if (ch=='X') x += 1;
+      else if (ch=='y') y -= 1;
+      else if (ch=='Y') y += 1;
+      PC.printf("\tx=%d, y=%d, color=%d\n",x,y,color);
+      clear_display();
+    }*/
+    
+    panel_refresh(&Panel); // Call regularly!
+    wait(app_data.scroll_speed); // Slow down, but not too much.
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed May 05 12:04:34 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0