diff --git a/CREDITS b/CREDITS
index 0da27dc..f65a991 100644
--- a/CREDITS
+++ b/CREDITS
@@ -211,6 +211,7 @@ Eric Pooch:
- Mac OS X / Darwin support
- serialPOS driver
- uss720 connection type for hd44780 driver
+ - driver for SoundGraph iMON OEM LCD Modules
Benjamin Wiedmann
- Added functionality for HITACHI SP14Q002 gLCD (320x240)
@@ -259,6 +260,11 @@ Phant0m / Aron Parsons
Malte Poeggel
- support for ST7036 controller in hd44780
+Dean Harding,
+Christian Leuschen,
+Jonathan Kyler:
+ - driver for SoundGraph iMON OEM LCD Modules
+
Further developers in the sourceforge lcdproc team:
Mindaugas Idzelis aim4min
diff --git a/ChangeLog b/ChangeLog
index 2631592..1b5a12f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -69,7 +69,8 @@ v.0.5dev (ongoing development)
* Change drivers to start in background by default: bayrad, CFontz, ea65, glk
* imon driver: Change hbars to make last char in-/decrease vertically
+ hd44780 driver: port usblcd connection type from 0.4.5 to 0.5 (M. Dolze)
- * server: Fix interpretation of named screen priorities
+ * server: Fix interpretation of named screen priorities
+ + new driver imonlcd for SoundGraph iMON LCD (Dean Harding, Jonathan Kyler)
v.0.5.2
* fix switching on/off the Load screen in lcdproc client using the menu
diff --git a/LCDd.conf b/LCDd.conf
index 6f43c2d..a59d2ec 100644
--- a/LCDd.conf
+++ b/LCDd.conf
@@ -45,7 +45,7 @@ DriverPath=server/drivers/
#
# The following drivers are supported:
# bayrad, CFontz, CFontz633, CFontzPacket, curses, CwLnx, ea65,
-# EyeboxOne, g15, glcdlib, glk, hd44780, icp_a106, imon, IOWarrior,
+# EyeboxOne, g15, glcdlib, glk, hd44780, icp_a106, imon, imonlcd, IOWarrior,
# irman, joy, lb216, lcdm001, lcterm, lirc, lis, MD8800, ms6931, mtc_s16209x,
# MtxOrb, mx5000, NoritakeVFD, picolcd, pyramid, sed1330, sed1520, serialPOS,
# serialVFD, shuttleVFD, sli, stv5730, svga, t6963, text, tyan, ula200,
@@ -550,6 +550,34 @@ Size=16x2
+## Soundgraph iMON LCD ##
+[imonlcd]
+# Specify which iMon protocol should be used [legal: 0=15c2:ffdc device,
+# 1=15c2:0038 device; default: 0]
+Protocol=0
+
+# Set the exit behavior [legal: 0=leave shutdown message, 1=show the big clock,
+# 2=blank device; default: 1]
+#OnExit=2
+
+# Select the output device to use [default: /dev/lcd0]
+Device=/dev/lcd0
+
+# Select the displays contrast [default: 200; legal: 0-1000]
+Contrast=200
+
+# Specify the size of the display in pixels [default: 96x16]
+#Size=96x16
+
+# Set the backlight state [default: on; legal: on, off]
+#Backlight=on
+
+# Set the disc mode [legal: 0=spin the "slim" disc - two disc segments,
+# 1=their complement spinning; default: 0]
+#DiscMode=0
+
+
+
## IrMan driver ##
[IrMan]
# in case of trouble with IrMan, try the Lirc emulator for IrMan
@@ -1063,5 +1091,4 @@ Offset=200x200
# X font to use, in XLFD format, as given by "xfontsel"
Font=-*-terminus-*-r-*-*-*-320-*-*-*-*-*
-
# EOF
diff --git a/acinclude.m4 b/acinclude.m4
index 0145e3c..f75c915 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -9,7 +9,7 @@ AC_ARG_ENABLE(drivers,
[ which is a comma-separated list of drivers.]
[ Possible drivers are:]
[ bayrad,CFontz,CFontz633,CFontzPacket,curses,CwLnx,ea65,]
- [ EyeboxOne,g15,glcdlib,glk,hd44780,i2500vfd,icp_a106,imon,]
+ [ EyeboxOne,g15,glcdlib,glk,hd44780,i2500vfd,icp_a106,imon,imonlcd,]
[ IOWarrior,irman,irtrans,joy,lb216,lcdm001,lcterm,lirc,lis,]
[ MD8800,ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,picolcd,]
[ pyramid,sed1330,sed1520,serialPOS,serialVFD,shuttleVFD,sli,]
@@ -19,7 +19,7 @@ AC_ARG_ENABLE(drivers,
drivers="$enableval",
drivers=[bayrad,CFontz,CFontz633,curses,CwLnx,glk,lb216,lcdm001,MtxOrb,pyramid,text])
-allDrivers=[bayrad,CFontz,CFontz633,CFontzPacket,curses,CwLnx,ea65,EyeboxOne,g15,glcdlib,glk,hd44780,i2500vfd,icp_a106,imon,IOWarrior,irman,irtrans,joy,lb216,lcdm001,lcterm,lirc,lis,MD8800,ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,picolcd,pyramid,sed1330,sed1520,serialPOS,serialVFD,shuttleVFD,sli,stv5730,svga,t6963,text,tyan,ula200,xosd]
+allDrivers=[bayrad,CFontz,CFontz633,CFontzPacket,curses,CwLnx,ea65,EyeboxOne,g15,glcdlib,glk,hd44780,i2500vfd,icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,joy,lb216,lcdm001,lcterm,lirc,lis,MD8800,ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,picolcd,pyramid,sed1330,sed1520,serialPOS,serialVFD,shuttleVFD,sli,stv5730,svga,t6963,text,tyan,ula200,xosd]
drivers=`echo $drivers | sed -e 's/,/ /g'`
@@ -224,6 +224,10 @@ dnl else
DRIVERS="$DRIVERS imon${SO}"
actdrivers=["$actdrivers imon"]
;;
+ imonlcd)
+ DRIVERS="$DRIVERS imonlcd${SO}"
+ actdrivers=["$actdrivers imonlcd"]
+ ;;
IOWarrior)
if test "$enable_libusb" = yes ; then
DRIVERS="$DRIVERS IOWarrior${SO}"
diff --git a/clients/lcdproc/mode.c b/clients/lcdproc/mode.c
index 97af5b5..10c4cfa 100644
--- a/clients/lcdproc/mode.c
+++ b/clients/lcdproc/mode.c
@@ -150,6 +150,9 @@ credit_screen(int rep, int display, int *flags_ptr)
"Jack Cleaver",
"Aron Parsons",
"Malte Poeggel",
+ "Dean Harding",
+ "Christian Leuschen",
+ "Jonathan Kyler",
NULL
};
int contr_num = 0;
diff --git a/docs/LCDd.8.in b/docs/LCDd.8.in
index 5b1e985..4a18f65 100644
--- a/docs/LCDd.8.in
+++ b/docs/LCDd.8.in
@@ -186,6 +186,9 @@ ICP A106 alarm/LCD board in 19" rack cases by ICP
.B imon
iMON IR/VFD modules in cases by Soundgraph/Ahanix/Silverstone/Uneed/Accent
.TP
+.B imonlcd
+iMON IR/LCD modules in cases by Soundgraph/Ahanix/Silverstone/Uneed/Accent/Antec
+.TP
.B irtrans
IRTrans IR/VFD modules in cases by Ahanix (e.g. MCE303) and possibly others
May require irserver (http://www.irtrans.de/en/download/linux.php) to be running for connectivity.
diff --git a/docs/lcdproc-user/drivers.docbook b/docs/lcdproc-user/drivers.docbook
index 0f7e599..4a00505 100644
--- a/docs/lcdproc-user/drivers.docbook
+++ b/docs/lcdproc-user/drivers.docbook
@@ -21,6 +21,7 @@ well as the configuration of LCDd.
&hd44780;
&icp_a106;
&imon;
+&imonlcd;
&IOWarrior;
&irman;
&irtrans;
diff --git a/docs/lcdproc-user/drivers/imonlcd.docbook b/docs/lcdproc-user/drivers/imonlcd.docbook
new file mode 100644
index 0000000..500600d
--- /dev/null
+++ b/docs/lcdproc-user/drivers/imonlcd.docbook
@@ -0,0 +1,134 @@
+
+The imonlcd Driver
+
+
+General
+
+
+This section talks about using LCDproc with LCD devices manufactured by SoundGraph.
+For example, the iMON OEM LCD.
+
+
+
+This driver currently supports versions 15c2:ffdc and 15c2:0038 of the device.
+(You can find the version of your lcd via the lsusb command).
+
+
+
+In many systems, the LCD backlight will remain on after the system is shutdown.
+This behavior remains a mystery - somehow the lcd recieves a reset command (or
+similar) AFTER LCDd is stopped.
+
+
+
+This driver requires the iMON module included with LIRC v0.8.4a or newer,
+available from the LIRC project.
+The 15c2:0038 device may require LIRC v0.8.5 or newer.
+
+
+
+
+
+
+Configuration in LCDd.conf
+
+
+[imonlcd]
+
+
+
+
+ Protocol =
+
+ PROTOCOL
+
+
+
+ Specify which version of iMON LCD is installed.
+ The default, 0 specifies the :ffdc device.
+ 1 should be used for the :0038 device.
+
+
+
+
+
+ OnExit =
+ ONEXIT
+
+
+ Specify the exit behavior.
+ The default is 1, which turns on the big ugly clock upon
+ shutdown. 0 leaves the shutdown message on the screen.
+ 2 turns the LCD off.
+
+
+
+
+
+ Device =
+ DEVICE
+
+
+ Select the output device to use. Change this from the default
+ /dev/lcd0 to the device file that gets created
+ when the kernel module (see above)
+ is loaded.
+
+
+
+
+
+ Contrast =
+ CONTRAST
+
+
+ Select the display's contrast 200 is the default.
+ Permissible values are in the range of 0-1000.
+
+
+
+
+
+ Size =
+
+ WIDTH
+ x
+ HEIGHT
+
+
+
+ Set the display size in pixels. The default 96x16 should
+ be safe for most if not all users, since the device seeems to be made only
+ with this one size.
+
+
+
+
+
+ Backlight =
+ BACKLIGHT
+
+
+ Set the backlight state. The default is 1, which turns
+ the backlight on. 0 turns the backlight off.
+
+
+
+
+
+ DiscMode =
+ DISCMODE
+
+
+ Sets the disc mode. The default is 0 which spins the
+ "slim" disc. 1 spins their complement.
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/lcdproc-user/lcdproc-user.docbook b/docs/lcdproc-user/lcdproc-user.docbook
index cfdccac..d4e9784 100644
--- a/docs/lcdproc-user/lcdproc-user.docbook
+++ b/docs/lcdproc-user/lcdproc-user.docbook
@@ -28,6 +28,7 @@
+
diff --git a/server/drivers/Makefile.am b/server/drivers/Makefile.am
index 423981f..ac7bb71 100644
--- a/server/drivers/Makefile.am
+++ b/server/drivers/Makefile.am
@@ -19,7 +19,7 @@ AM_LDFLAGS = @LDSHARED@
#LIBS =
pkglib_PROGRAMS = @DRIVERS@
-EXTRA_PROGRAMS = bayrad CFontz CFontz633 CFontzPacket curses CwLnx ea65 EyeboxOne g15 glcdlib glk hd44780 icp_a106 imon IOWarrior irman joy lb216 lcdm001 lcterm lirc lis MD8800 ms6931 mtc_s16209x MtxOrb mx5000 NoritakeVFD picolcd pyramid sed1330 sed1520 serialPOS serialVFD shuttleVFD stv5730 svga t6963 text tyan sli ula200 xosd i2500vfd irtrans
+EXTRA_PROGRAMS = bayrad CFontz CFontz633 CFontzPacket curses CwLnx ea65 EyeboxOne g15 glcdlib glk hd44780 icp_a106 imon imonlcd IOWarrior irman joy lb216 lcdm001 lcterm lirc lis MD8800 ms6931 mtc_s16209x MtxOrb mx5000 NoritakeVFD picolcd pyramid sed1330 sed1520 serialPOS serialVFD shuttleVFD stv5730 svga t6963 text tyan sli ula200 xosd i2500vfd irtrans
noinst_LIBRARIES = libLCD.a libbignum.a
IOWarrior_CFLAGS = @LIBUSB_CFLAGS@ $(AM_CFLAGS)
@@ -42,6 +42,7 @@ hd44780_LDADD = libLCD.a @HD44780_DRIVERS@ @LIBUSB_LIBS@ @LIBFTDI_LIBS@ lib
hd44780_DEPENDENCIES = @HD44780_DRIVERS@
icp_a106_LDADD = libLCD.a
imon_LDADD = libLCD.a
+imonlcd_LDADD = libLCD.a
IOWarrior_LDADD = @LIBUSB_LIBS@ libLCD.a libbignum.a
irman_LDADD = @LIBIRMAN@
lcterm_LDADD = libLCD.a
@@ -84,6 +85,7 @@ EXTRA_hd44780_SOURCES = hd44780-4bit.c hd44780-4bit.h hd44780-ext8bit.c hd44780-
icp_a106_SOURCES = lcd.h lcd_lib.h icp_a106.c icp_a106.h report.h
imon_SOURCES = lcd.h lcd_lib.h imon.h imon.c report.h
+imonlcd_SOURCES = lcd.h lcd_lib.h imonlcd.h imonlcd_font.h imonlcd.c report.h
IOWarrior_SOURCES = lcd.h lcd_lib.h hd44780-charmap.h IOWarrior.c IOWarrior.h report.h adv_bignum.h
irman_SOURCES = lcd.h irmanin.c irmanin.h report.h
joy_SOURCES = lcd.h joy.c joy.h port.h report.h
diff --git a/server/drivers/imonlcd.c b/server/drivers/imonlcd.c
new file mode 100644
index 0000000..b4dee7a
--- /dev/null
+++ b/server/drivers/imonlcd.c
@@ -0,0 +1,1393 @@
+/** \file server/drivers/imonlcd.c
+ * Driver for SoundGraph iMON OEM LCD Modules
+ *
+ * Requires the lirc_imon module included with lirc >= 0.8.4a
+ */
+
+/*-
+ * Modified March 2009 by Jonathan Kyler for inclusion in lcdproc
+ * Added 0038 support
+ * Added Protocol configuration parameter
+ * Converted and upgraded t6963 font for use with iMon Soundgraph LCD
+ *
+ * Modified March 2009 by Eric Pooch - lots of cleanup and streamlining
+ * Removed fixed "96" width listed everywhere
+ * Streamlined config file parsing
+ * Sped up font access
+ * Implemented backing store to avoid unnecessary refreshes
+ * Adjusted p->width and p->height to use character width and height properly
+ * Fixed long long defines
+ * Replaced send_data() and send_byte_data() with send_packet()
+ * Improved send_command_data()
+ * Reduced functions for basic character drawing - removed draw_char() and draw_string()
+ *
+ * Copyright (c) 2004, Venky Raju
+ * 2007, Dean Harding
+ * 2007, Christian Leuschen
+ * 2009, Jonathan Kyler
+ * 2009, Eric Pooch < epooch (at) cox (dot) net>
+ *
+ * This file is released under the GNU General Public License. Refer to the
+ * COPYING file distributed with this package.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "lcd.h"
+#include "lcd_lib.h"
+#include "shared/debug.h"
+#include "report.h"
+
+/* Defines a 6x8 font based on ISO 8859-15 */
+#define LCD_DEFAULT_CELL_WIDTH 6
+#define LCD_DEFAULT_CELL_HEIGHT 8
+#include "imonlcd_font.h"
+
+#include "imonlcd.h"
+
+#define IMONLCD_PACKET_DATA_SIZE 7
+
+#define DEFAULT_DEVICE "/dev/lcd0"
+#define DEFAULT_SIZE "96x16" /**< This is the size in "pixels" (colXrow) */
+#define DEFAULT_CONTRAST 200
+#define DEFAULT_BACKLIGHT 1 /**< turn backlight on */
+#define DEFAULT_DISCMODE 0 /**< spin the "slim" disc */
+#define DEFAULT_ON_EXIT 1 /**< show the big clock */
+#define DEFAULT_PROTOCOL 0 /**< protocol for 15c2:ffdc device */
+
+
+#define ON_EXIT_SHOWMSG 0 /**< Do nothing - just leave the "shutdown"
+ * message there */
+#define ON_EXIT_SHOWCLOCK 1 /**< Show the big clock */
+#define ON_EXIT_BLANKSCREEN 2 /**< Blank the device completely */
+
+#define PROTOCOL_FFDC 0 /**< protocol ID for 15c2:ffdc device */
+#define PROTOCOL_0038 1 /**< protocol ID for 15c2:0038 device */
+
+/* Vars for the server core */
+MODULE_EXPORT char *api_version = API_VERSION;
+MODULE_EXPORT int stay_in_foreground = 0;
+MODULE_EXPORT int supports_multiple = 0;
+MODULE_EXPORT char *symbol_prefix = "imonlcd_";
+
+/** Private data for the \c imonlcd driver */
+typedef struct imonlcd_private_data {
+ char info[255];
+ int imon_fd;
+
+ /* send buffer for one command or display data */
+ unsigned char tx_buf[8];
+
+ /* framebuffer and backingstore for current contents */
+ unsigned char *framebuf;
+ unsigned char *backingstore;
+
+ int bytesperline;
+
+ int width, height;
+ int cellwidth, cellheight;
+
+ int on_exit;
+ int contrast; /* 0 = lowest contrast, 1000 = highest */
+ int backlightOn; /* stores the backlight state */
+
+ /*
+ * 0 = two disc-segments spinning as default, 1 = their complement
+ * spinning
+ */
+ int discMode;
+
+ /*
+ * 0 = protocol for 15c2:ffdc device, 1 = protocol for 15c2:0038
+ * device
+ */
+ int protocol;
+
+ /* store commands appropriate for the version of the iMON LCD */
+ uint64_t command_display;
+ uint64_t command_shutdown;
+ uint64_t command_display_on;
+ uint64_t command_clear_alarm;
+
+ /*
+ * record the last "state" of the CD icon so that we can "animate"
+ * it.
+ */
+ int last_cd_state;
+ time_t last_cd_state_change;
+
+ /* remind the last state for setting the icons */
+ uint64_t last_icon_state;
+ int lastPrivateIconState;
+} PrivateData;
+
+/*
+ * Just for convenience and to have the commands at one place.
+ */
+#define COMMANDS_SET_ICONS (uint64_t) 0x0100000000000000LL
+#define COMMANDS_SET_CONTRAST (uint64_t) 0x0300000000000000LL
+#define COMMANDS_DISPLAY (uint64_t) 0x0000000000000000LL // must be or'd with the applicable COMMANDS_DISPLAY_BYTE
+#define COMMANDS_SHUTDOWN (uint64_t) 0x0000000000000008LL // must be or'd with the applicable COMMANDS_DISPLAY_BYTE
+#define COMMANDS_DISPLAY_ON (uint64_t) 0x0000000000000040LL // must be or'd with the applicable COMMANDS_DISPLAY_BYTE
+#define COMMANDS_CLEAR_ALARM (uint64_t) 0x0000000000000000LL // must be or'd with the applicable COMMANDS_ALARM_BYTE
+#define COMMANDS_SET_LINES0 (uint64_t) 0x1000000000000000LL
+#define COMMANDS_SET_LINES1 (uint64_t) 0x1100000000000000LL
+#define COMMANDS_SET_LINES2 (uint64_t) 0x1200000000000000LL
+#define COMMANDS_INIT (uint64_t) 0x0200000000000000LL //not exactly sure what this does, but it's needed
+#define COMMANDS_LOW_CONTRAST (uint64_t) (COMMANDS_SET_CONTRAST + (uint64_t) 0x00FFFFFF00580A00LL)
+#define COMMAND_MASK (uint64_t) 0xFF00000000000000LL
+
+/* Allow for variations in Soundgraphs numerous protocols */
+/* 15c2:0038 SoundGraph iMON */
+#define COMMANDS_DISPLAY_BYTE_0038 (uint64_t) 0x8800000000000000LL
+#define COMMANDS_ALARM_BYTE_0038 (uint64_t) 0x8a00000000000000LL
+
+/* 15c2:ffdc SoundGraph iMON */
+#define COMMANDS_DISPLAY_BYTE_FFDC (uint64_t) 0x5000000000000000LL
+#define COMMANDS_ALARM_BYTE_FFDC (uint64_t) 0x5100000000000000LL
+
+
+/*
+ * These are used with the imon_output function to determine which icons to
+ * turn on/off. Because we only get a 32-bit integer to play, some of the
+ * icons are grouped into "sets" from which you can only select to turn one
+ * on at a time.
+ */
+#define IMON_OUTPUT_CD_MASK 0x00000001
+#define IMON_OUTPUT_TOPROW_MASK 0x0000000E
+#define IMON_OUTPUT_SPEAKER_MASK 0x00000030
+#define IMON_OUTPUT_SPDIF_MASK 0x00000040
+#define IMON_OUTPUT_SRC_MASK 0x00000080
+#define IMON_OUTPUT_FIT_MASK 0x00000100
+#define IMON_OUTPUT_TV_MASK 0x00000200
+#define IMON_OUTPUT_HDTV_MASK 0x00000400
+#define IMON_OUTPUT_SCR1_MASK 0x00000800
+#define IMON_OUTPUT_SCR2_MASK 0x00001000
+#define IMON_OUTPUT_BRICONS_MASK 0x0000E000
+#define IMON_OUTPUT_BMICONS_MASK 0x00070000
+#define IMON_OUTPUT_BLICONS_MASK 0x00380000
+#define IMON_OUTPUT_VOL_MASK 0x00400000
+#define IMON_OUTPUT_TIME_MASK 0x00800000
+#define IMON_OUTPUT_ALARM_MASK 0x01000000
+#define IMON_OUTPUT_REC_MASK 0x02000000
+#define IMON_OUTPUT_REP_MASK 0x04000000
+#define IMON_OUTPUT_SFL_MASK 0x08000000
+
+#define IMON_OUTPUT_PBARS_MASK 0x10000000
+#define IMON_OUTPUT_DISK_IN_MASK 0x20000000
+
+#define IMON_ICON_ALL (uint64_t) 0x00FFFFFFFFFFFFFFLL
+
+/* Byte 6 */
+#define IMON_ICON_DISK_OFF (uint64_t) 0x7F7000FFFFFFFFFFLL
+#define IMON_ICON_DISK_ON (uint64_t) 0x0080FF0000000000LL
+
+#define IMON_ICON_DISK_IN (uint64_t) 0x0080000000000000LL
+#define IMON_ICON_CD_IN (uint64_t) 0x00806B0000000000LL
+#define IMON_ICON_DVD_IN (uint64_t) 0x0080550000000000LL
+
+/* Byte 5 */
+#define IMON_ICON_WMA2 ((uint64_t) 0x1 << 39)
+#define IMON_ICON_WAV ((uint64_t) 0x1 << 38)
+#define IMON_ICON_REP ((uint64_t) 0x1 << 37)
+#define IMON_ICON_SFL ((uint64_t) 0x1 << 36)
+#define IMON_ICON_ALARM ((uint64_t) 0x1 << 35)
+#define IMON_ICON_REC ((uint64_t) 0x1 << 34)
+#define IMON_ICON_VOL ((uint64_t) 0x1 << 33)
+#define IMON_ICON_TIME ((uint64_t) 0x1 << 32)
+
+/* Byte 4 */
+#define IMON_ICON_XVID ((uint64_t) 0x1 << 31)
+#define IMON_ICON_WMV ((uint64_t) 0x1 << 30)
+#define IMON_ICON_MPG2 ((uint64_t) 0x1 << 29)
+#define IMON_ICON_AC3 ((uint64_t) 0x1 << 28)
+#define IMON_ICON_DTS ((uint64_t) 0x1 << 27)
+#define IMON_ICON_WMA ((uint64_t) 0x1 << 26)
+#define IMON_ICON_MP3 ((uint64_t) 0x1 << 25)
+#define IMON_ICON_OGG ((uint64_t) 0x1 << 24)
+
+/* Byte 3 */
+#define IMON_ICON_SRC ((uint64_t) 0x1 << 23)
+#define IMON_ICON_FIT ((uint64_t) 0x1 << 22)
+#define IMON_ICON_TV_2 ((uint64_t) 0x1 << 21)
+#define IMON_ICON_HDTV ((uint64_t) 0x1 << 20)
+#define IMON_ICON_SCR1 ((uint64_t) 0x1 << 19)
+#define IMON_ICON_SCR2 ((uint64_t) 0x1 << 18)
+#define IMON_ICON_MPG ((uint64_t) 0x1 << 17)
+#define IMON_ICON_DIVX ((uint64_t) 0x1 << 16)
+
+/* Byte 2 */
+#define IMON_SPKR_FC ((uint64_t) 0x1 << 15)
+#define IMON_SPKR_FR ((uint64_t) 0x1 << 14)
+#define IMON_SPKR_SL ((uint64_t) 0x1 << 13)
+#define IMON_SPKR_LFE ((uint64_t) 0x1 << 12)
+#define IMON_SPKR_SR ((uint64_t) 0x1 << 11)
+#define IMON_SPKR_RL ((uint64_t) 0x1 << 10)
+#define IMON_SPKR_SPDIF ((uint64_t) 0x1 << 9)
+#define IMON_SPKR_RR ((uint64_t) 0x1 << 8)
+
+/* Byte 1 */
+#define IMON_ICON_MUSIC ((uint64_t) 0x1 << 7)
+#define IMON_ICON_MOVIE ((uint64_t) 0x1 << 6)
+#define IMON_ICON_PHOTO ((uint64_t) 0x1 << 5)
+#define IMON_ICON_CD_DVD ((uint64_t) 0x1 << 4)
+#define IMON_ICON_TV ((uint64_t) 0x1 << 3)
+#define IMON_ICON_WEBCAST ((uint64_t) 0x1 << 2)
+#define IMON_ICON_NEWS ((uint64_t) 0x1 << 1)
+#define IMON_SPKR_FL ((uint64_t) 0x1)
+
+
+/* prototypes for driver internal functions */
+static void imonlcd_display_init(Driver *drvthis);
+static void draw_bigchar(imon_bigfont *font, int ch, int x, int y, PrivateData *p);
+static void setLineLength(int topLine, int botLine, int topProgress, int botProgress, PrivateData *p);
+static void setBuiltinProgressBars(int topLine, int botLine, int topProgress, int botProgress, PrivateData *p);
+static int lengthToPixels(int length);
+static void send_command_data(uint64_t commandData, PrivateData *p);
+static void send_packet(PrivateData *p);
+
+/**
+ * Initialize the driver.
+ * \param drvthis Pointer to driver structure.
+ * \retval 0 Success.
+ * \retval <0 Error.
+ */
+MODULE_EXPORT int
+imonlcd_init(Driver *drvthis)
+{
+ PrivateData *p = NULL;
+ char buf[256];
+ int graph_width, graph_height; /* width and height of screen, in pixels */
+ int tmp;
+
+ /* Allocate, initialize and store private p */
+ p = (PrivateData *) calloc(1, sizeof(PrivateData));
+ if (p == NULL) {
+ debug(RPT_ERR, "%s: failed to allocate private data", drvthis->name);
+ return -1;
+ }
+ if (drvthis->store_private_ptr(drvthis, p)) {
+ debug(RPT_ERR, "%s: failed to store private data pointer", drvthis->name);
+ return -1;
+ }
+
+ p->imon_fd = -1;
+
+ graph_width = 0;
+ graph_height = 0;
+
+ p->width = 0; /* Display width, in characters */
+ p->height = 0; /* Display height, in characters */
+ p->cellwidth = LCD_DEFAULT_CELL_WIDTH; /* width of a character, in pixels */
+ p->cellheight = LCD_DEFAULT_CELL_HEIGHT; /* height of a character, in pixels */
+
+ p->last_cd_state = 0;
+ p->last_icon_state = 0x0; /* no icons turned on at startup */
+ p->lastPrivateIconState = 0x0; /* no icons turned on at startup */
+ p->discMode = 0;
+
+ /* Get settings from config file */
+
+ /* Get device */
+ strncpy(buf, drvthis->config_get_string(drvthis->name, "Device", 0, DEFAULT_DEVICE), sizeof(buf));
+ buf[sizeof(buf) - 1] = '\0';
+ report(RPT_INFO, "%s: using Device %s", drvthis->name, buf);
+
+ /* Open device for writing */
+ if ((p->imon_fd = open(buf, O_WRONLY)) < 0) {
+ report(RPT_ERR, "%s: ERROR opening %s (%s).", drvthis->name, buf, strerror(errno));
+ report(RPT_ERR, "%s: Did you load the iMON kernel module?", drvthis->name);
+ return -1;
+ }
+ /* Get protocol version */
+ tmp = drvthis->config_get_int(drvthis->name, "Protocol", 0, DEFAULT_PROTOCOL);
+ if ((tmp < 0) || (tmp > 1)) {
+ report(RPT_WARNING, "%s: Protocol must be between 0 and 1; using default %d",
+ drvthis->name, DEFAULT_PROTOCOL);
+ tmp = DEFAULT_PROTOCOL;
+ }
+ p->protocol = tmp;
+
+ /* Set commands based on protocol version */
+ if (p->protocol == PROTOCOL_FFDC) {
+ p->command_display = (uint64_t) (COMMANDS_DISPLAY | COMMANDS_DISPLAY_BYTE_FFDC);
+ p->command_shutdown = (uint64_t) (COMMANDS_SHUTDOWN | COMMANDS_DISPLAY_BYTE_FFDC);
+ p->command_display_on = (uint64_t) (COMMANDS_DISPLAY_ON | COMMANDS_DISPLAY_BYTE_FFDC);
+ p->command_clear_alarm = (uint64_t) (COMMANDS_CLEAR_ALARM | COMMANDS_ALARM_BYTE_FFDC);
+ } else if (p->protocol == PROTOCOL_0038) {
+ p->command_display = (uint64_t) (COMMANDS_DISPLAY | COMMANDS_DISPLAY_BYTE_0038);
+ p->command_shutdown = (uint64_t) (COMMANDS_SHUTDOWN | COMMANDS_DISPLAY_BYTE_0038);
+ p->command_display_on = (uint64_t) (COMMANDS_DISPLAY_ON | COMMANDS_DISPLAY_BYTE_0038);
+ p->command_clear_alarm = (uint64_t) (COMMANDS_CLEAR_ALARM | COMMANDS_ALARM_BYTE_0038);
+ } else { /* default - use FFDC */
+ report(RPT_WARNING, "%s: Protocol version not recognized: %d; using default %d",
+ drvthis->name, p->protocol, PROTOCOL_FFDC);
+ p->command_display = (uint64_t) (COMMANDS_DISPLAY | COMMANDS_DISPLAY_BYTE_FFDC);
+ p->command_shutdown = (uint64_t) (COMMANDS_SHUTDOWN | COMMANDS_DISPLAY_BYTE_FFDC);
+ p->command_display_on = (uint64_t) (COMMANDS_DISPLAY_ON | COMMANDS_DISPLAY_BYTE_FFDC);
+ p->command_clear_alarm = (uint64_t) (COMMANDS_CLEAR_ALARM | COMMANDS_ALARM_BYTE_FFDC);
+ }
+
+ /* Get size settings */
+ strncpy(buf, drvthis->config_get_string(drvthis->name, "Size", 0, DEFAULT_SIZE), sizeof(buf));
+ buf[sizeof(buf) - 1] = '\0';
+ if ((sscanf(buf, "%dx%d", &graph_width, &graph_height) != 2)
+ || (graph_width <= 0) || (graph_height <= 0)
+ || (graph_height < LCD_DEFAULT_CELL_HEIGHT)
+ || ((graph_width / p->cellwidth) > LCD_MAX_WIDTH)
+ || ((graph_height / p->cellheight) > LCD_MAX_HEIGHT)) {
+ report(RPT_WARNING, "%s: cannot read Size: %s; using default %s",
+ drvthis->name, buf, DEFAULT_SIZE);
+ sscanf(DEFAULT_SIZE, "%dx%d", &graph_width, &graph_height);
+ }
+ /* Convert dimension in pixels to characters. */
+ p->width = (graph_width / p->cellwidth);
+ p->height = (graph_height / p->cellheight);
+
+ /* Store this to make working with the frame buffer memory easier. */
+ p->bytesperline = graph_width;
+
+ /*
+ * Get the "on exit" setting so we know what to do when we shut the
+ * device down
+ */
+ tmp = drvthis->config_get_int(drvthis->name, "OnExit", 0, DEFAULT_ON_EXIT);
+ if ((tmp < 0) || (tmp > 3)) {
+ report(RPT_WARNING, "%s: OnExit must be between 0 and 3; using default %d",
+ drvthis->name, DEFAULT_ON_EXIT);
+ tmp = DEFAULT_ON_EXIT;
+ }
+ p->on_exit = tmp;
+
+ /* Get the "contrast" setting */
+ tmp = drvthis->config_get_int(drvthis->name, "Contrast", 0, DEFAULT_CONTRAST);
+ if ((tmp < 0) || (tmp > 1000)) {
+ report(RPT_WARNING, "%s: Contrast must be between 0 and 1000; using default %d",
+ drvthis->name, DEFAULT_CONTRAST);
+ tmp = DEFAULT_CONTRAST;
+ }
+ p->contrast = tmp;
+
+ /* Get the "backlight" setting */
+ p->backlightOn = drvthis->config_get_bool(drvthis->name, "Backlight", 0, DEFAULT_BACKLIGHT);
+
+ /* Get the "disc-mode" setting */
+ p->discMode = drvthis->config_get_bool(drvthis->name, "DiscMode", 0, DEFAULT_DISCMODE);
+
+ /*
+ * We need a little bit of extra memory in the frame buffer so that
+ * all of the last 7-bit-long packet data will be within the frame
+ * buffer. See imonlcd_flush() for where we take advantage of this.
+ */
+ tmp = 0;
+ while (((p->bytesperline * p->height) + tmp) % IMONLCD_PACKET_DATA_SIZE) {
+ tmp++;
+ }
+
+ /* Make sure the frame buffer is there... */
+ p->framebuf = (unsigned char *)malloc((p->bytesperline * p->height) + tmp);
+ if (p->framebuf == NULL) {
+ report(RPT_ERR, "%s: unable to allocate framebuffer", drvthis->name);
+ return -1;
+ }
+
+ /* Clear the framebuffer. */
+ imonlcd_clear(drvthis);
+
+ /*
+ * This is the extra memory that will fill out the last packet's
+ * data.
+ */
+ memset(p->framebuf + (p->bytesperline * p->height), 0xFF, tmp);
+
+ /* Make sure the framebuffer backing store is there... */
+ p->backingstore = (unsigned char *)malloc(p->bytesperline * p->height);
+ if (p->backingstore == NULL) {
+ report(RPT_ERR, "%s: unable to create framebuffer backing store", drvthis->name);
+ return -1;
+ }
+ memset(p->backingstore, ' ', p->bytesperline * p->height);
+
+ imonlcd_display_init(drvthis);
+
+ report(RPT_DEBUG, "%s: init() done", drvthis->name);
+
+ return 0;
+}
+
+/**
+ * Send the "initialize" commands to the screen.
+ * \param drvthis Pointer to driver structure.
+ */
+static void
+imonlcd_display_init(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+
+ if (p->backlightOn)
+ send_command_data(p->command_display_on, p);
+ else
+ send_command_data(p->command_shutdown, p);
+
+ send_command_data(p->command_clear_alarm, p);
+ imonlcd_set_contrast(drvthis, p->contrast);
+ send_command_data(COMMANDS_INIT, p); /* unknown, required init command */
+ send_command_data(COMMANDS_SET_ICONS, p);
+ /* clear the progress-bars on top and bottom of the display */
+ send_command_data(COMMANDS_SET_LINES0, p);
+ send_command_data(COMMANDS_SET_LINES1, p);
+ send_command_data(COMMANDS_SET_LINES2, p);
+}
+
+
+/**
+ * Close the driver (do necessary clean-up).
+ * \param drvthis Pointer to driver structure.
+ */
+MODULE_EXPORT void
+imonlcd_close(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+ time_t tt;
+ struct tm *t;
+ uint64_t data;
+
+ if (p != NULL) {
+ if (p->imon_fd >= 0) {
+ if (p->on_exit == ON_EXIT_SHOWMSG) {
+ /*
+ * "show message" means "do nothing" - the
+ * message is there already
+ */
+ report(RPT_INFO, "%s: closing, leaving \"goodbye\" message.", drvthis->name);
+ } else if (p->on_exit == ON_EXIT_BLANKSCREEN) {
+ /*
+ * turning backlight off (confirmed for my
+ * Silverstone LCD) (as "cybrmage" at
+ * mediaportal pointed out, his LCD is an
+ * Antec built-in one and turns completely
+ * off with this command)
+ */
+ report(RPT_INFO, "%s: closing, turning backlight off.", drvthis->name);
+ send_command_data(p->command_shutdown, p);
+ send_command_data(p->command_clear_alarm, p);
+ } else {
+ /*
+ * by default, show the big clock. We need to
+ * set it to the current time, then it just
+ * keeps counting automatically.
+ */
+ report(RPT_INFO, "%s: closing, showing clock.", drvthis->name);
+
+ tt = time(NULL);
+ t = localtime(&tt);
+
+ data = p->command_display;
+ data += ((uint64_t) t->tm_sec << 48);
+ data += ((uint64_t) t->tm_min << 40);
+ data += ((uint64_t) t->tm_hour << 32);
+ data += ((uint64_t) t->tm_mday << 24);
+ data += ((uint64_t) t->tm_mon << 16);
+ data += (((uint64_t) t->tm_year) << 8);
+ data += 0x80;
+ send_command_data(data, p);
+ send_command_data(p->command_clear_alarm, p);
+ }
+
+ close(p->imon_fd);
+ }
+ if (p->framebuf != NULL)
+ free(p->framebuf);
+ p->framebuf = NULL;
+
+ free(p);
+ }
+ drvthis->store_private_ptr(drvthis, NULL);
+}
+
+
+/**
+ * Provide some information about this driver.
+ * \param drvthis Pointer to driver structure.
+ * \return Constant string with information.
+ */
+MODULE_EXPORT const char *
+imonlcd_get_info(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+
+ strcpy(p->info, "SoundGraph iMON LCD driver v0.6 : 15c2:ffdc and 15c2:0038 ");
+ return p->info;
+}
+
+
+/**
+ * Clear the screen.
+ * \param drvthis Pointer to driver structure.
+ */
+MODULE_EXPORT void
+imonlcd_clear(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+
+ memset(p->framebuf, 0x00, p->bytesperline * p->height);
+}
+
+
+/**
+ * Flush data on screen to the LCD.
+ * \param drvthis Pointer to driver structure.
+ */
+MODULE_EXPORT void
+imonlcd_flush(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+
+ unsigned char msb;
+ int offset = 0;
+
+ /*
+ * The display only provides for a complete screen refresh. If
+ * nothing has changed, don't refresh.
+ */
+ if (memcmp(p->backingstore, p->framebuf, (p->bytesperline * p->height)) == 0)
+ return;
+
+ for (msb = 0x20; msb < 0x3c; msb++) {
+ /* Copy the packet data from the frame buffer. */
+ memcpy(p->tx_buf, p->framebuf + offset, IMONLCD_PACKET_DATA_SIZE);
+
+ /* Add the memory register byte to the packet data. */
+ p->tx_buf[IMONLCD_PACKET_DATA_SIZE] = msb;
+
+ send_packet(p);
+
+ offset += IMONLCD_PACKET_DATA_SIZE;
+ }
+
+ /* Update the backing store. */
+ memcpy(p->backingstore, p->framebuf, (p->bytesperline * p->height));
+}
+
+
+/**
+ * Print a string on the screen at position (x,y).
+ * The upper-left corner is (1,1), the lower-right corner is (p->width, p->height).
+ * \param drvthis Pointer to driver structure.
+ * \param x Horizontal character position (column).
+ * \param y Vertical character position (row).
+ * \param string String that gets written.
+ */
+MODULE_EXPORT void
+imonlcd_string(Driver *drvthis, int x, int y, const char string[])
+{
+ int i;
+
+ for (i = 0; string[i] != '\0'; i++)
+ imonlcd_chr(drvthis, x + i, y, string[i]);
+}
+
+
+/**
+ * Print a character on the screen at position (x,y).
+ * The upper-left corner is (1,1), the lower-right corner is (p->width, p->height).
+ * \param drvthis Pointer to driver structure.
+ * \param x Horizontal character position (column).
+ * \param y Vertical character position (row).
+ * \param ch Character that gets written. (ISO 8859-1 + special characters)
+ */
+MODULE_EXPORT void
+imonlcd_chr(Driver *drvthis, int x, int y, char ch)
+{
+ PrivateData *p = drvthis->private_data;
+ imon_font *defn;
+ int col;
+
+ if ((x < 1) || (y < 1) || (x > p->width) || (y > p->height))
+ return;
+
+ x--; y--;
+ /* Convert from characters to pixels. */
+ x *= p->cellwidth;
+ y *= p->bytesperline;
+
+ defn = &font[(unsigned char) ch];
+
+ /* Copy character from font into frame buffer */
+ for (col = 0; col < p->cellwidth; col++) {
+ p->framebuf[x + y] = defn->pixels[col];
+ x++;
+ }
+}
+
+/**
+ * Draw a vertical bar bottom-up.
+ * \param drvthis Pointer to driver structure.
+ * \param x Horizontal character position (column) of the starting point.
+ * \param y Vertical character position (row) of the starting point.
+ * \param len Number of characters that the bar is high at 100%
+ * \param promille Current height level of the bar in promille.
+ * \param options Options (currently unused).
+ */
+MODULE_EXPORT void
+imonlcd_vbar(Driver *drvthis, int x, int y, int len, int promille, int options)
+{
+ PrivateData *p = drvthis->private_data;
+
+ /*
+ * use the imonlcd_font full vbar characters and let lcd_lib do the
+ * rest
+ */
+ lib_vbar_static(drvthis, x, y, len, promille, options,
+ p->cellheight, IMONLCD_FONT_START_VBAR_FULL - 1);
+}
+
+
+/**
+ * Draw a horizontal bar to the right.
+ * \param drvthis Pointer to driver structure.
+ * \param x Horizontal character position (column) of the starting point.
+ * \param y Vertical character position (row) of the starting point.
+ * \param len Number of characters that the bar is long at 100%
+ * \param promille Current length level of the bar in promille (i.e. from 0 to 1000).
+ * \param options Options (currently unused).
+ */
+MODULE_EXPORT void
+imonlcd_hbar(Driver *drvthis, int x, int y, int len, int promille, int options)
+{
+ PrivateData *p = drvthis->private_data;
+
+ /*
+ * I don't like the reliance on SEAMLESS_HBARS, so the
+ * lib_hbar_static code is replicated here. (./configure
+ * --enable-seamless hbars would be required for the hbar display to
+ * look right if lib_hbar_static() were used.)
+ */
+
+ int total_pixels = ((long)2 * len * p->cellwidth + 1) * promille / 2000;
+ int pos;
+
+ for (pos = 0; pos < len; pos++) {
+
+ int pixels = total_pixels - p->cellwidth * pos;
+
+ if (pixels >= p->cellwidth) {
+ /* write a "full" block to the screen... */
+ imonlcd_chr(drvthis, x + pos, y, p->cellwidth + IMONLCD_FONT_START_HBAR_NARROW - 1);
+ } else if (pixels > 0) {
+ /* write a partial block... */
+ imonlcd_chr(drvthis, x + pos, y, pixels + IMONLCD_FONT_START_HBAR_NARROW - 1);
+ break;
+ } else {
+ ; /* write nothing (not even a space) */
+ }
+ }
+
+}
+
+
+/**
+ * Place an icon on the screen.
+ * \param drvthis Pointer to driver structure.
+ * \param x Horizontal character position (column).
+ * \param y Vertical character position (row).
+ * \param icon synbolic value representing the icon.
+ * \retval 0 Icon has been successfully defined/written.
+ * \retval <0 Server core shall define/write the icon.
+ */
+MODULE_EXPORT int
+imonlcd_icon(Driver *drvthis, int x, int y, int icon)
+{
+ char ch1 = '?';
+ char ch2 = '\0';
+
+ switch (icon) {
+ case ICON_BLOCK_FILLED:
+ ch1 = IMONLCD_FONT_FULL_BLOCK;
+ break;
+ case ICON_HEART_OPEN:
+ ch1 = IMONLCD_FONT_SMALL_HEART;
+ break;
+ case ICON_HEART_FILLED:
+ ch1 = IMONLCD_FONT_FULL_HEART;
+ break;
+ case ICON_ARROW_UP:
+ ch1 = IMONLCD_FONT_UP_ARROW;
+ break;
+ case ICON_ARROW_DOWN:
+ ch1 = IMONLCD_FONT_DOWN_ARROW;
+ break;
+ case ICON_ARROW_LEFT:
+ ch1 = IMONLCD_FONT_LEFT_ARROW;
+ break;
+ case ICON_ARROW_RIGHT:
+ ch1 = IMONLCD_FONT_RIGHT_ARROW;
+ break;
+ case ICON_STOP:
+ ch1 = IMONLCD_FONT_STOP;
+ ch2 = ' ';
+ break;
+ case ICON_PAUSE:
+ ch1 = IMONLCD_FONT_PAUSE;
+ ch2 = ' ';
+ break;
+ case ICON_PLAY:
+ ch1 = IMONLCD_FONT_PLAY;
+ ch2 = ' ';
+ break;
+ case ICON_PLAYR:
+ ch1 = IMONLCD_FONT_REVERSE;
+ ch2 = ' ';
+ break;
+ case ICON_FF:
+ ch1 = IMONLCD_FONT_PLAY;
+ ch2 = IMONLCD_FONT_PLAY;
+ break;
+ case ICON_FR:
+ ch1 = IMONLCD_FONT_REVERSE;
+ ch2 = IMONLCD_FONT_REVERSE;
+ break;
+ case ICON_NEXT:
+ ch1 = IMONLCD_FONT_PLAY;
+ ch2 = IMONLCD_FONT_FWD;
+ break;
+ case ICON_PREV:
+ ch1 = IMONLCD_FONT_RWD;
+ ch2 = IMONLCD_FONT_REVERSE;
+ break;
+ case ICON_REC:
+ ch1 = IMONLCD_FONT_RECORD;
+ ch2 = ' ';
+ break;
+ default:
+ /* let the server core do the rest */
+ return -1;
+ }
+
+ imonlcd_chr(drvthis, x, y, ch1);
+ if (ch2 != '\0')
+ imonlcd_chr(drvthis, x + 1, y, ch2);
+
+ return 0;
+}
+
+/**
+ * Draws a "big" number at the specified x-coordinate.
+ *
+ * Normally, the number that is displayed is "meant" to be 3x4 characters, but
+ * because we have a bit more flexibility, I've drawn the numbers as just being
+ * 12x16 pixels. That means that while the client will pass x-values between 0
+ * and 16, we need to scale it and make sure the numbers remain centered.
+ *
+ * \param drvthis A pointer to the Driver structure.
+ * \param x The x-coordinate to display the character at.
+ * \param num The number to display ("10" is the colon).
+ */
+MODULE_EXPORT void
+imonlcd_num(Driver *drvthis, int x, int num)
+{
+ PrivateData *p = drvthis->private_data;
+
+ /*
+ * This isn't that great, it makes assumptions about the coordinates
+ * the client passes to us. However, it works for MythTV... and looks
+ * pretty cool, too.
+ */
+ if (num < 10)
+ x = 12 + (int)(((x - 1) * p->cellwidth) * 0.75);
+ else
+ x = 12 + (int)(((x - 1) * p->cellwidth) * 0.72);
+
+ draw_bigchar(bigfont, (num >= 10 ? ':' : (num + '0')), x, 0, p);
+}
+
+/**
+ * Sets the "output state" for the device. We use this to control the icons
+ * around the outside the display. The bits in \c state correspond to the
+ * icons as follows:
+ *
+ * \verbatim
+ * bit 0 : disc icon (0=off, 1='spin') , if Toprow==4, use CD-animation,
+ * else use "HDD-recording-animation"
+ * bit 1,2,3 : top row (0=none, 1=music, 2=movie, 3=photo, 4=CD/DVD, 5=TV, 6=Web,
+ * 7=News/Weather)
+ * bit 4,5 : 'speaker' icons (0=off, 1=LR, 2=5.1ch, 3=7.1ch)
+ * bit 6 : S/PDIF icon
+ * bit 7 : 'SRC'
+ * bit 8 : 'FIT'
+ * bit 9 : 'TV'
+ * bit 10 : 'HDTV'
+ * bit 11 : 'SRC1'
+ * bit 12 : 'SRC2'
+ * bit 13,14,15: bottom-right icons (0=off, 1=MP3, 2=OGG, 3=WMA, 4=WAV)
+ * bit 16,17,18: bottom-middle icons (0=off, 1=MPG, 2=AC3, 3=DTS, 4=WMA)
+ * bit 19,20,21: bottom-left icons (0=off, 1=MPG, 2=DIVX, 3=XVID, 4=WMV)
+ * bit 22 : 'VOL' (volume)
+ * bit 23 : 'TIME'
+ * bit 24 : 'ALARM'
+ * bit 25 : 'REC' (recording)
+ * bit 26 : 'REP' (repeat)
+ * bit 27 : 'SFL' (shuffle)
+ * bit 28 : Abuse this for progress bars (if set to 1), lower bits represent
+ * the length (6 bits each: P|6xTP|6xTL|6xBL|6xBP with P = bit 28,
+ * TP=Top Progress, TL = Top Line, BL = Bottom Line, BP = Bottom Progress).
+ * If bit 28 is set to 1, lower bits are interpreted as
+ * lengths; otherwise setting the symbols as usual.
+ * 0 <= length <= 32, bars extend from left to right.
+ * length > 32, bars extend from right to left, length is counted
+ * from 32 up (i.e. 35 means a length of 3).
+ *
+ * Remember: There are two kinds of calls!
+ * With bit 28 set to 1: Set all bars (leaving the symbols as is),
+ * with bit 28 set to 0: Set the symbols (leaving the bars as is).
+ * Beware: TODO: May become a race condition, if both calls are executed
+ * before the display gets updated. Keep this in mind in your
+ * client-code.
+ * bit 29 : 'disc-in icon' - half ellipsoid under the disc symbols (0=off, 1=on)
+ * \endverbatim
+ *
+ * \param drvthis Pointer to driver structure.
+ * \param state This symbols or bars to display.
+ */
+MODULE_EXPORT void
+imonlcd_output(Driver *drvthis, int state)
+{
+
+ PrivateData *p = drvthis->private_data;
+ uint64_t icon = 0x0;
+
+ if (state == -1) { /* the value for "on" in the lcdproc-protocol */
+ icon = (uint64_t) IMON_ICON_ALL;
+ send_command_data(COMMANDS_SET_ICONS | icon, p);
+ p->lastPrivateIconState = state;
+ setLineLength(32, 32, 32, 32, p);
+
+ return;
+ } else if (state == 0x0) { /* the value for "off" in the
+ * lcdproc-protocol */
+ icon = (uint64_t) 0x0;;
+ send_command_data(COMMANDS_SET_ICONS | icon, p);
+ p->lastPrivateIconState = state;
+ setLineLength(0, 0, 0, 0, p);
+ return;
+ }
+ /* bit 28 : Abuse this for progress bars. See above for usage. */
+ else if ((state & IMON_OUTPUT_PBARS_MASK) != 0 && state > 0) {
+ /* extract the bar-values for each bar separately */
+ int topProgress = (state & 63);
+ int topLine = (state & (63 << 6)) >> 6;
+ int botProgress = (state & (63 << 12)) >> 12;
+ int botLine = (state & (63 << 18)) >> 18;
+
+ botProgress = botProgress > 32 ? -(botProgress - 32) : botProgress;
+ topProgress = topProgress > 32 ? -(topProgress - 32) : topProgress;
+ botLine = botLine > 32 ? -(botLine - 32) : botLine;
+ topLine = topLine > 32 ? -(topLine - 32) : topLine;
+
+ setLineLength(topLine, botLine, topProgress, botProgress, p);
+
+ /* continue and set all other icons as before */
+ state = p->lastPrivateIconState;
+ }
+ /* bit 0 : disc icon (0=off, 1='spin') */
+ if ((state & IMON_OUTPUT_CD_MASK) != 0) {
+ switch (p->last_cd_state) {
+ case 0:
+ p->last_cd_state = 1;
+ if (p->discMode == 1)
+ /* all on except top & bottom */
+ icon |= ((uint64_t) (255 - 128 - 8) << 40);
+ else
+ /* top & bottom on */
+ icon |= ((uint64_t) (128 | 8) << 40);
+ break;
+ case 1:
+ p->last_cd_state = 2;
+ if (p->discMode == 1)
+ /* all on except top-right & bottom-left */
+ icon |= ((uint64_t) (255 - 16 - 1) << 40);
+ else
+ /* top-right & bottom-left on */
+ icon |= ((uint64_t) (1 | 16) << 40);
+ break;
+ case 2:
+ p->last_cd_state = 3;
+ if (p->discMode == 1)
+ /* all on except right & left */
+ icon |= ((uint64_t) (255 - 32 - 2) << 40);
+ else
+ /* right & left on */
+ icon |= ((uint64_t) (32 | 2) << 40);
+ break;
+ default:
+ p->last_cd_state = 0;
+ if (p->discMode == 1)
+ /* all on except top-left & bottom-right */
+ icon |= ((uint64_t) (255 - 64 - 4) << 40);
+ else
+ /* top-left & bottom-right on */
+ icon |= ((uint64_t) (4 | 64) << 40);
+ break;
+ }
+ }
+ /*
+ * bit 1,2,3 : top row (0=none, 1=music, 2=movie, 3=photo, 4=CD/DVD,
+ * 5=TV, 6=Web, 7=News/Weather)
+ */
+ if (((state & IMON_OUTPUT_TOPROW_MASK) != 0)) {
+ switch (((state & IMON_OUTPUT_TOPROW_MASK) >> 1)) {
+ case 1:
+ icon |= IMON_ICON_MUSIC;
+ break;
+ case 2:
+ icon |= IMON_ICON_MOVIE;
+ break;
+ case 3:
+ icon |= IMON_ICON_PHOTO;
+ break;
+ case 4:
+ icon |= IMON_ICON_CD_DVD;
+ break;
+ case 5:
+ icon |= IMON_ICON_TV;
+ break;
+ case 6:
+ icon |= IMON_ICON_WEBCAST;
+ break;
+ case 7:
+ icon |= IMON_ICON_NEWS;
+ break;
+ default:
+ break;
+ }
+ }
+ /* bit 4,5 : 'speaker' icons (0=off, 1=L+R, 2=5.1ch, 3=7.1ch) */
+ if (((state & IMON_OUTPUT_SPEAKER_MASK) != 0)) {
+ switch (((state & IMON_OUTPUT_SPEAKER_MASK) >> 4)) {
+ case 1:
+ icon |= IMON_SPKR_FL | IMON_SPKR_FR;
+ break;
+ case 2:
+ icon |= IMON_SPKR_FL | IMON_SPKR_FC | IMON_SPKR_FR | IMON_SPKR_RL | IMON_SPKR_RR;
+ break;
+ case 3:
+ icon |= IMON_SPKR_FL | IMON_SPKR_FC | IMON_SPKR_FR | IMON_SPKR_RL | IMON_SPKR_RR | IMON_SPKR_SL | IMON_SPKR_SR;
+ break;
+ default:
+ break;
+ }
+ }
+ /* bit 6 : S/PDIF icon */
+ icon = ((state & IMON_OUTPUT_SPDIF_MASK) != 0) ? (icon | IMON_SPKR_SPDIF) : (icon & ~IMON_SPKR_SPDIF);
+ /* bit 7 : 'SRC' */
+ icon = ((state & IMON_OUTPUT_SRC_MASK) != 0) ? (icon | IMON_ICON_SRC) : (icon & ~IMON_ICON_SRC);
+ /* bit 8 : 'FIT' */
+ icon = ((state & IMON_OUTPUT_FIT_MASK) != 0) ? (icon | IMON_ICON_FIT) : (icon & ~IMON_ICON_FIT);
+ /* bit 9 : 'TV' */
+ icon = ((state & IMON_OUTPUT_TV_MASK) != 0) ? (icon | IMON_ICON_TV_2) : (icon & ~IMON_ICON_TV_2);
+ /* bit 10 : 'HDTV' */
+ icon = ((state & IMON_OUTPUT_HDTV_MASK) != 0) ? (icon | IMON_ICON_HDTV) : (icon & ~IMON_ICON_HDTV);
+ /* bit 11 : 'SRC1' */
+ icon = ((state & IMON_OUTPUT_SCR1_MASK) != 0) ? (icon | IMON_ICON_SCR1) : (icon & ~IMON_ICON_SCR1);
+ /* bit 12 : 'SRC2' */
+ icon = ((state & IMON_OUTPUT_SCR2_MASK) != 0) ? (icon | IMON_ICON_SCR2) : (icon & ~IMON_ICON_SCR2);
+ /*
+ * bit 13,14,15: bottom-right icons (0=off, 1=MP3, 2=OGG, 3=WMA,
+ * 4=WAV)
+ */
+ if (((state & IMON_OUTPUT_BRICONS_MASK) != 0)) {
+ switch (((state & IMON_OUTPUT_BRICONS_MASK) >> 13)) {
+ case 1:
+ icon |= IMON_ICON_MP3;
+ break;
+ case 2:
+ icon |= IMON_ICON_OGG;
+ break;
+ case 3:
+ icon |= IMON_ICON_WMA;
+ break;
+ case 4:
+ icon |= IMON_ICON_WAV;
+ break;
+ default:
+ break;
+ }
+ }
+ /*
+ * bit 16,17,18: bottom-middle icons (0=off, 1=MPG, 2=AC3, 3=DTS,
+ * 4=WMA)
+ */
+ if (((state & IMON_OUTPUT_BMICONS_MASK) != 0)) {
+ switch (((state & IMON_OUTPUT_BMICONS_MASK) >> 16)) {
+ case 1:
+ icon |= IMON_ICON_MPG;
+ break;
+ case 2:
+ icon |= IMON_ICON_AC3;
+ break;
+ case 3:
+ icon |= IMON_ICON_DTS;
+ break;
+ case 4:
+ icon |= IMON_ICON_WMA;
+ break;
+ default:
+ break;
+ }
+ }
+ /*
+ * bit 19,20,21: bottom-left icons (0=off, 1=MPG, 2=DIVX, 3=XVID,
+ * 4=WMV)
+ */
+ if (((state & IMON_OUTPUT_BLICONS_MASK) != 0)) {
+ switch (((state & IMON_OUTPUT_BLICONS_MASK) >> 19)) {
+ case 1:
+ icon |= IMON_ICON_MPG;
+ break;
+ case 2:
+ icon |= IMON_ICON_DIVX;
+ break;
+ case 3:
+ icon |= IMON_ICON_XVID;
+ break;
+ case 4:
+ icon |= IMON_ICON_WMV;
+ break;
+ default:
+ break;
+ }
+ }
+ /* bit 22 : 'VOL' (volume) */
+ icon = ((state & IMON_OUTPUT_VOL_MASK) != 0) ? (icon | IMON_ICON_VOL) : (icon & ~IMON_ICON_VOL);
+ /* bit 23 : 'TIME' */
+ icon = ((state & IMON_OUTPUT_TIME_MASK) != 0) ? (icon | IMON_ICON_TIME) : (icon & ~IMON_ICON_TIME);
+ /* bit 24 : 'ALARM' */
+ icon = ((state & IMON_OUTPUT_ALARM_MASK) != 0) ? (icon | IMON_ICON_ALARM) : (icon & ~IMON_ICON_ALARM);
+ /* bit 25 : 'REC' (recording) */
+ icon = ((state & IMON_OUTPUT_REC_MASK) != 0) ? (icon | IMON_ICON_REC) : (icon & ~IMON_ICON_REC);
+ /* bit 26 : 'REP' (repeat) */
+ icon = ((state & IMON_OUTPUT_REP_MASK) != 0) ? (icon | IMON_ICON_REP) : (icon & ~IMON_ICON_REP);
+ /* bit 27 : 'SFL' (shuffle) */
+ icon = ((state & IMON_OUTPUT_SFL_MASK) != 0) ? (icon | IMON_ICON_SFL) : (icon & ~IMON_ICON_SFL);
+ /* bit 29 : 'disc-in' */
+ icon = ((state & IMON_OUTPUT_DISK_IN_MASK) != 0) ? (icon | IMON_ICON_DISK_IN) : (icon & ~IMON_ICON_DISK_IN);
+
+ p->last_icon_state = (uint64_t) icon;
+ p->lastPrivateIconState = state;
+ send_command_data(COMMANDS_SET_ICONS | p->last_icon_state, p);
+}
+
+/**
+ * Return the display width in characters.
+ * \param drvthis Pointer to driver structure.
+ * \return Number of characters the display is wide.
+ */
+MODULE_EXPORT int
+imonlcd_width(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+
+ return p->width;
+}
+
+
+/**
+ * Return the display height in characters.
+ * \param drvthis Pointer to driver structure.
+ * \return Number of characters the display is high.
+ */
+MODULE_EXPORT int
+imonlcd_height(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+
+ return p->height;
+}
+
+
+/**
+ * Return the width of a character in pixels.
+ * \param drvthis Pointer to driver structure.
+ * \return Number of pixel columns a character cell is wide.
+ */
+MODULE_EXPORT int
+imonlcd_cellwidth(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+
+ return p->cellwidth;
+}
+
+
+/**
+ * Return the height of a character in pixels.
+ * \param drvthis Pointer to driver structure.
+ * \return Number of pixel lines a character cell is high.
+ */
+MODULE_EXPORT int
+imonlcd_cellheight(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+
+ return p->cellheight;
+}
+
+
+/**
+ * Sends a command to the screen. The kernel module expects data to be
+ * sent in 8 byte chunks, so for simplicity, we allow you to define
+ * the data as a 64-bit integer.
+ * However, we have to reverse the bytes to the order the display requires.
+ *
+ * \param value The data to send. Must be in a format that is recognized by
+ * the device. The kernel module doesn't actually do validation.
+ * \param p The private data containing the file descriptor to write to.
+ */
+static void
+send_command_data(uint64_t value, PrivateData *p)
+{
+ int i;
+
+ /* Fill the send buffer. */
+ for (i = 0; i < sizeof(p->tx_buf); i++) {
+ p->tx_buf[i] = (unsigned char)((value >> (i * 8)) & 0xFF);
+ }
+
+ send_packet(p);
+}
+
+/**
+ * Sends data to the screen.
+ *
+ * \param p The private data structure containing a tx_buf with the data to send.
+ */
+static void
+send_packet(PrivateData *p)
+{
+ int err;
+ err = write(p->imon_fd, p->tx_buf, sizeof(p->tx_buf));
+
+ if (err <= 0)
+ printf("%s: error writing to file descriptor: %d", "imon", err);
+}
+
+
+/**
+ * Sets the contrast of the display.
+ *
+ * \param drvthis Pointer to driver structure.
+ * \param promille The value the contrast is set to in promille (0 = lowest
+ * contrast; 1000 = highest contrast).
+ * \return 0 on failure, >0 on success.
+ */
+MODULE_EXPORT
+void
+imonlcd_set_contrast(Driver *drvthis, int promille)
+{
+ PrivateData *p = drvthis->private_data;
+
+ if (promille < 0) {
+ promille = 0;
+ } else if (promille > 1000) {
+ promille = 1000;
+ }
+ p->contrast = promille;
+
+ /*
+ * Send contrast normalized to the hardware-understandable-value (0
+ * to 40). 0 is the lowest and 40 is the highest. The actual
+ * perceived contrast varies depending on the type of display.
+ */
+ send_command_data(COMMANDS_LOW_CONTRAST + (uint64_t) (p->contrast / 25), p);
+}
+
+/**
+ * Gets the current contrast of the display.
+ *
+ * \param drvthis Pointer to driver structure.
+ * \return The current contrast in promille (0 = lowest contrast;
+ * 1000 = highest contrast).
+ */
+MODULE_EXPORT int
+imonlcd_get_contrast(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+ return p->contrast;
+}
+
+/**
+ * Sets the backlight state of the display.
+ *
+ * \param drvthis Pointer to driver structure.
+ * \param on The backlight state boolean-like: 0 = off; >0 = on.
+ */
+MODULE_EXPORT void
+imonlcd_backlight(Driver *drvthis, int on)
+{
+ PrivateData *p = drvthis->private_data;
+
+ /*
+ * TODO: For some reason, lcdproc keeps calling this and flipping the
+ * 'on' so you end up flashing the backlight for no particular reason
+ * (and on my Antec, turning the backlight off, turns the whole thing
+ * off, so it's really bad...)
+ */
+ return;
+
+ /* To prevent superfluous (and erroneous) communication */
+ if (p->backlightOn == on)
+ return;
+ else
+ p->backlightOn = on;
+
+ if (on)
+ send_command_data(p->command_display_on, p);
+ else
+ send_command_data(p->command_shutdown, p);
+}
+
+
+/**
+ * Draws a "big" character - that is, one that's twice as big as a
+ * normal character - at the specified position on the screen.
+ * \param font font definition
+ * \param ch the character to display
+ * \param x horizontal position
+ * \param y vertical position
+ * \param p pointer to the PrivateData structure
+ */
+static void
+draw_bigchar(imon_bigfont *font, int ch, int x, int y, PrivateData *p)
+{
+ imon_bigfont *defn = font;
+ int i;
+ int colBorder;
+
+ while (defn->ch != ch && defn->ch != '\0') {
+ defn++;
+ }
+
+ /*
+ * correction for the number flashing with the colon running
+ * "lcdproc K"
+ */
+ colBorder = 12;
+ if (ch == ':')
+ colBorder = 6;
+
+ for (i = 0; i < colBorder; i++) {
+ p->framebuf[x + i + (y * colBorder)] = (defn->pixels[i] & 0xFF00) >> 8;
+ }
+ for (i = 0; i < colBorder; i++) {
+ p->framebuf[x + i + (y * colBorder) + p->bytesperline] = (defn->pixels[i] & 0x00FF);
+ }
+}
+
+
+/**
+ * Sets the length of the built-in progress-bars and lines.
+ * Values from -32 to 32 are allowed. Positive values indicate that bars extend
+ * from left to right, negative values indicate that the run from right to left.
+ * Conventient method to simplify setting the bars with "human understandable
+ * values".
+ *
+ * \see setBuiltinProgressBars, lengthToPixels
+ *
+ * \param topLine Length of the top line (-32 to 32)
+ * \param botLine Length of the bottom line (-32 to 32)
+ * \param topProgress Length of the top progress bar (-32 to 32)
+ * \param botProgress Length of the bottom progress bar (-32 to 32)
+ * \param p The private data structure containing the file descriptor to write to.
+ */
+static void
+setLineLength(int topLine, int botLine, int topProgress, int botProgress, PrivateData *p)
+{
+ setBuiltinProgressBars(lengthToPixels(topLine),
+ lengthToPixels(botLine),
+ lengthToPixels(topProgress),
+ lengthToPixels(botProgress),
+ p
+ );
+}
+
+
+/**
+ * Sets the length of the built-in progress-bars and lines.
+ * Values from -32 to 32 are allowed. Positive values indicate that bars extend
+ * from left to right, negative values indicate that the run from right to left.
+ *
+ * \param topLine Pitmap of the top line
+ * \param botLine Pitmap of the bottom line
+ * \param topProgress Pitmap of the top progress bar
+ * \param botProgress Pitmap of the bottom progress bar
+ * \param p The private data structure containing the file descriptor to write to.
+ */
+static void
+setBuiltinProgressBars(int topLine, int botLine,
+ int topProgress, int botProgress, PrivateData *p)
+{
+ /* Least sig. bit is on the right */
+ uint64_t data;
+
+ /* send bytes 1-4 of topLine and 1-3 of topProgress */
+ data = (uint64_t) topLine & 0x00000000FFFFFFFFLL;
+ data |= (((uint64_t) topProgress) << 8 * 4) & 0x00FFFFFF00000000LL;
+ send_command_data(COMMANDS_SET_LINES0 | data, p);
+
+ /* send byte 4 of topProgress, bytes 1-4 of botProgress and 1-2 of botLine */
+ data = (((uint64_t) topProgress) >> 8 * 3) & 0x00000000000000FFLL;
+ data |= (((uint64_t) botProgress) << 8) & 0x000000FFFFFFFF00LL;
+ data |= (((uint64_t) botLine) << 8 * 5) & 0x00FFFF0000000000LL;
+ send_command_data(COMMANDS_SET_LINES1 | data, p);
+
+ /* send remaining bytes 3-4 of botLine */
+ data = ((uint64_t) botLine) >> 8 * 2;
+ send_command_data(COMMANDS_SET_LINES2 | data, p);
+}
+
+/**
+ * Maps values to corresponding pixmaps for the built-in progress bars.
+ * Values from -32 to 32 are allowed. Positive values indicate that bars extend
+ * from left to right, negative values indicate that they run from right to left.
+ *
+ * \param length The length of the bar.
+ * \return The pixmap that represents the given length.
+ */
+static int
+lengthToPixels(int length)
+{
+ int pixLen[] =
+ {
+ 0x00, 0x00000080, 0x000000c0, 0x000000e0, 0x000000f0,
+ 0x000000f8, 0x000000fc, 0x000000fe, 0x000000ff,
+ 0x000080ff, 0x0000c0ff, 0x0000e0ff, 0x0000f0ff,
+ 0x0000f8ff, 0x0000fcff, 0x0000feff, 0x0000ffff,
+ 0x0080ffff, 0x00c0ffff, 0x00e0ffff, 0x00f0ffff,
+ 0x00f8ffff, 0x00fcffff, 0x00feffff, 0x00ffffff,
+ 0x80ffffff, 0xc0ffffff, 0xe0ffffff, 0xf0ffffff,
+ 0xf8ffffff, 0xfcffffff, 0xfeffffff, 0xffffffff
+ };
+
+ if (abs(length) > 32)
+ return (0);
+
+ if (length >= 0)
+ return pixLen[length];
+ else
+ return (pixLen[32 + length] ^ 0xffffffff);
+}
+
+/* EOF */
diff --git a/server/drivers/imonlcd.h b/server/drivers/imonlcd.h
new file mode 100644
index 0000000..ebe8026
--- /dev/null
+++ b/server/drivers/imonlcd.h
@@ -0,0 +1,62 @@
+/** \file server/drivers/imonlcd.h
+ * Driver for SoundGraph iMON OEM LCD Modules
+ */
+
+/*-
+ * Copyright (c) 2004, Venky Raju
+ * 2007, Dean Harding
+ * 2007, Christian Leuschen
+ * 2009, Jonathan Kyler
+ * 2009, Eric Pooch < epooch (at) cox (dot) net>
+ *
+ * This file is released under the GNU General Public License. Refer to the
+ * COPYING file distributed with this package.
+ */
+
+#ifndef IMONLCD_H
+#define IMONLCD_H
+
+#include "lcd.h"
+
+/* mandatory functions (necessary for all drivers) */
+MODULE_EXPORT int imonlcd_init (Driver *drvthis);
+MODULE_EXPORT void imonlcd_close (Driver *drvthis);
+
+/* essential output functions (necessary for output drivers) */
+MODULE_EXPORT int imonlcd_width (Driver *drvthis);
+MODULE_EXPORT int imonlcd_height (Driver *drvthis);
+MODULE_EXPORT void imonlcd_clear (Driver *drvthis);
+MODULE_EXPORT void imonlcd_flush (Driver *drvthis);
+MODULE_EXPORT void imonlcd_string (Driver *drvthis, int x, int y, const char string[]);
+MODULE_EXPORT void imonlcd_chr (Driver *drvthis, int x, int y, char c);
+
+/* essential input functions (necessary for all input drivers) */
+/* char *imonlcd_get_key NOT IMPLEMENTED */
+
+/* extended output functions (optional; core provides alternatives) */
+MODULE_EXPORT void imonlcd_vbar (Driver *drvthis, int x, int y, int len, int promille, int options);
+MODULE_EXPORT void imonlcd_hbar (Driver *drvthis, int x, int y, int len, int promille, int options);
+MODULE_EXPORT void imonlcd_num (Driver *drvthis, int x, int num);
+/* MODULE_EXPORT void imonlcd_heartbeat (Driver *drvthis, int state); NOT IMPLEMENTED */
+/* MODULE_EXPORT int imonlcd_icon (Driver *drvthis, int x, int y, int icon); NOT IMPLEMENTED */
+/* MODULE_EXPORT void imonlcd_cursor (Driver *drvthis, int x, int y, int type); NOT IMPLEMENTED */
+
+/* user-defined character functions, are those still supported ? */
+/* MODULE_EXPORT void imonlcd_set_char (Driver *drvthis, int n, char *dat); NOT IMPLEMENTED */
+/* MODULE_EXPORT int imonlcd_get_free_chars (Driver *drvthis); NOT IMPLEMENTED */
+MODULE_EXPORT int imonlcd_cellwidth (Driver *drvthis);
+MODULE_EXPORT int imonlcd_cellheight (Driver *drvthis);
+
+/* Hardware functions */
+MODULE_EXPORT int imonlcd_get_contrast (Driver *drvthis);
+MODULE_EXPORT void imonlcd_set_contrast (Driver *drvthis, int promille);
+/* MODULE_EXPORT int imonlcd_get_brightness (Driver *drvthis, int state); NOT IMPLEMENTED */
+/* MODULE_EXPORT void imonlcd_set_brightness (Driver *drvthis, int state, int promille); NOT IMPLEMENTED */
+MODULE_EXPORT void imonlcd_backlight(Driver *drvthis, int on);
+MODULE_EXPORT void imonlcd_output (Driver *drvthis, int state);
+
+/* informational functions */
+MODULE_EXPORT const char *imonlcd_get_info (Driver *drvthis);
+
+#endif
+
diff --git a/server/drivers/imonlcd_font.h b/server/drivers/imonlcd_font.h
new file mode 100644
index 0000000..e3cb0b9
--- /dev/null
+++ b/server/drivers/imonlcd_font.h
@@ -0,0 +1,630 @@
+// -*- coding:iso-8859-15 -*-
+/** \file server/drivers/imonlcd_font.h
+ * This is a definition of a font for use with the iMON LCD.
+ *
+ * The iMON LCD doesn't have a "text mode" - everthing is pixel-based.
+ * So we need to define our own font, basically.
+ */
+
+/*-
+ * Created March 2009 by Jonathan Kyler for inclusion in lcdproc
+ * Structure based on codeka's imonlcd patch by Dean Harding
+ * Font based on Toshiba T6963 based LCD display driver font by Manuel Stahl
+ *
+ * Copyright (c) 2009, Jonathan Kyler
+ *
+ * This file is released under the GNU General Public License. Refer to the
+ * COPYING file distributed with this package.
+ */
+
+#ifndef IMONLCD_EXTENDED_CHARACTERS
+#define IMONLCD_EXTENDED_CHARACTERS
+
+#define IMONLCD_FONT_FULL_HEART 3
+#define IMONLCD_FONT_SMALL_HEART 4
+#define IMONLCD_FONT_FULL_BLOCK 141
+#define IMONLCD_FONT_LEFT_ARROW 155
+#define IMONLCD_FONT_UP_ARROW 156
+#define IMONLCD_FONT_RIGHT_ARROW 157
+#define IMONLCD_FONT_DOWN_ARROW 158
+
+#define IMONLCD_FONT_STOP 19
+#define IMONLCD_FONT_PLAY 16
+#define IMONLCD_FONT_PAUSE 18
+#define IMONLCD_FONT_REVERSE 17
+#define IMONLCD_FONT_FWD 21
+#define IMONLCD_FONT_RWD 22
+#define IMONLCD_FONT_RECORD 15
+
+#define IMONLCD_FONT_START_VBAR_FULL 23
+#define IMONLCD_FONT_START_VBAR_NARROW 127
+#define IMONLCD_FONT_START_HBAR_NARROW 135
+
+
+/**
+ * This structure holds the definition of the font.
+ *
+ * The characters we define here are 6x8 pixels in size, each byte in the
+ * 'pixels' array represents one column of pixels. The most significant bit
+ * is the top row, the least significant bit is the bottom row.
+ */
+typedef struct _imon_font {
+ unsigned char pixels[LCD_DEFAULT_CELL_WIDTH];
+} imon_font;
+
+/*
+ * Based on ISO 8859-15: http://en.wikipedia.org/wiki/ISO_8859-15
+ * Characters 0-14 are from the t6963 font, which is based on the
+ * CP437 character set. The diamond is replaced with a small heart
+ * for use in a heartbeat display.
+ * Characters 15-22 provide common play, record, stop, etc icons.
+ * Characters 23-29 provide a vertical progress bar display - using all
+ * 6 pixels in width
+ * Characters 30 & 31 are currently blank
+ * Characters 32-126 match ISO_8859-15 characters
+ * Characters 127-134 provide a vertical progress bar display, but only
+ * use 4 of the 6 characters in width
+ * Characters 135-140 provide a horizontal progress bar, using only
+ * 4 of the 8 characters in height
+ * Character 141 is a full block (all pixels used)
+ * Characters 142-152 provide some greek symbols
+ * Characters 153 & 154 make up a mail envelope icon
+ * Characters 155-159 are arrows
+ * Character 160 is currently blank
+ * Characters 161-255 match ISO_8859-15 characters
+ */
+static imon_font font[] = {
+ { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 0 \u0020 space
+ { {0x00, 0x7c, 0xa2, 0x8a, 0xa2, 0x7c } }, // 1 \u263a light smiley face
+ { {0x00, 0x7c, 0xd6, 0xf6, 0xd6, 0x7c } }, // 2 \u263b dark smiley face
+ { {0x00, 0x38, 0x7c, 0x3e, 0x7c, 0x38 } }, // 3 \u2665 full heart
+ { {0x00, 0x00, 0x38, 0x1c, 0x38, 0x00 } }, // 4 small heart
+ { {0x00, 0x0c, 0x6c, 0xfe, 0x6c, 0x0c } }, // 5 \u2660 club
+ { {0x00, 0x18, 0x3a, 0x7e, 0x3a, 0x18 } }, // 6 \u2660 spade
+ { {0x00, 0x00, 0x18, 0x18, 0x00, 0x00 } }, // 7 \u2022 bullet
+ { {0xff, 0xff, 0xe7, 0xe7, 0xff, 0xff } }, // 8 \u25d8 big rectangle
+ { {0x00, 0x3c, 0x24, 0x24, 0x3c, 0x00 } }, // 9 \u25cb small rectangle
+ { {0xff, 0xc3, 0xdb, 0xdb, 0xc3, 0xff } }, // 10 \u25d9 filled rectangle
+ { {0x00, 0x0c, 0x12, 0x52, 0x6c, 0x70 } }, // 11 \u2642 man symbol
+ { {0x00, 0x60, 0x94, 0x9e, 0x94, 0x60 } }, // 12 \u2640 woman symbol
+ { {0x00, 0x06, 0x0e, 0xfc, 0x40, 0x20 } }, // 13 \u266a musical note
+ { {0x00, 0x06, 0x7e, 0x50, 0xac, 0xfc } }, // 14 \u266b double music note
+ { {0x00, 0x18, 0x24, 0x24, 0x24, 0x18 } }, // 15 \u25cf record
+ { {0x00, 0x00, 0xfe, 0x7c, 0x38, 0x10 } }, // 16 \u25b6 play
+ { {0x00, 0x10, 0x38, 0x7c, 0xfe, 0x00 } }, // 17 \u25c0 play backwards
+ { {0x00, 0x7e, 0x7e, 0x00, 0x7e, 0x7e } }, // 18 pause
+ { {0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00 } }, // 19 \u25fe stop
+ { {0x00, 0x0a, 0x3a, 0xfa, 0x3a, 0x0a } }, // 20 \u23cf eject
+ { {0x00, 0xfe, 0x7c, 0x38, 0x10, 0xfe } }, // 21 fwd
+ { {0x00, 0xfe, 0x10, 0x38, 0x7c, 0xfe } }, // 22 rev
+ { {0x01, 0x01, 0x01, 0x01, 0x01, 0x01 } }, // 23 \u2581 lower 1/8 block (full)
+ { {0x03, 0x03, 0x03, 0x03, 0x03, 0x03 } }, // 24 \u2582 lower 1/4 block (full)
+ { {0x07, 0x07, 0x07, 0x07, 0x07, 0x07 } }, // 25 \u2583 lower 3/8 block (full)
+ { {0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f } }, // 26 \u2584 lower 1/2 block (full)
+ { {0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f } }, // 27 \u2585 lower 5/8 block (full)
+ { {0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f } }, // 28 \u2586 lower 3/4 block (full)
+ { {0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f } }, // 29 \u2587 lower 7/8 block (full)
+ { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 30
+ { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 31
+ { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 32 \u0020 space
+ { {0x00, 0x00, 0x60, 0xfa, 0x60, 0x00 } }, // 33 \u0021 !
+ { {0x00, 0xe0, 0xc0, 0x00, 0xe0, 0xc0 } }, // 34 \u0022 "
+ { {0x00, 0x24, 0x7e, 0x24, 0x7e, 0x24 } }, // 35 \u0023 #
+ { {0x00, 0x24, 0x54, 0xd6, 0x48, 0x00 } }, // 36 \u0024 $
+ { {0x00, 0xc6, 0xc8, 0x10, 0x26, 0xc6 } }, // 37 \u0025 %
+ { {0x00, 0x6c, 0x92, 0x6a, 0x04, 0x0a } }, // 38 \u0026 &
+ { {0x00, 0x00, 0xe0, 0xc0, 0x00, 0x00 } }, // 39 \u0027 '
+ { {0x00, 0x00, 0x7c, 0x82, 0x00, 0x00 } }, // 40 \u0028 (
+ { {0x00, 0x00, 0x82, 0x7c, 0x00, 0x00 } }, // 41 \u0029 )
+ { {0x00, 0x10, 0x7c, 0x38, 0x7c, 0x10 } }, // 42 \u002a *
+ { {0x00, 0x10, 0x10, 0x7c, 0x10, 0x10 } }, // 43 \u002b +
+ { {0x00, 0x00, 0x07, 0x06, 0x00, 0x00 } }, // 44 \u002c ,
+ { {0x00, 0x10, 0x10, 0x10, 0x10, 0x10 } }, // 45 \u002d -
+ { {0x00, 0x00, 0x06, 0x06, 0x00, 0x00 } }, // 46 \u002e .
+ { {0x00, 0x04, 0x08, 0x10, 0x20, 0x40 } }, // 47 \u002f /
+ { {0x00, 0x7c, 0x8a, 0x92, 0xa2, 0x7c } }, // 48 \u0030 0
+ { {0x00, 0x00, 0x42, 0xfe, 0x02, 0x00 } }, // 49 \u0031 1
+ { {0x00, 0x46, 0x8a, 0x92, 0x92, 0x62 } }, // 50 \u0032 2
+ { {0x00, 0x44, 0x92, 0x92, 0x92, 0x6c } }, // 51 \u0033 3
+ { {0x00, 0x18, 0x28, 0x48, 0xfe, 0x08 } }, // 52 \u0034 4
+ { {0x00, 0xf4, 0x92, 0x92, 0x92, 0x8c } }, // 53 \u0035 5
+ { {0x00, 0x3c, 0x52, 0x92, 0x92, 0x0c } }, // 54 \u0036 6
+ { {0x00, 0x80, 0x8e, 0x90, 0xa0, 0xc0 } }, // 55 \u0037 7
+ { {0x00, 0x6c, 0x92, 0x92, 0x92, 0x6c } }, // 56 \u0038 8
+ { {0x00, 0x60, 0x92, 0x92, 0x94, 0x78 } }, // 57 \u0039 9
+ { {0x00, 0x00, 0x6c, 0x6c, 0x00, 0x00 } }, // 58 \u003a :
+ { {0x00, 0x00, 0x37, 0x36, 0x00, 0x00 } }, // 59 \u003b ;
+ { {0x00, 0x10, 0x28, 0x44, 0x82, 0x00 } }, // 60 \u003c <
+ { {0x00, 0x24, 0x24, 0x24, 0x24, 0x24 } }, // 61 \u003d =
+ { {0x00, 0x00, 0x82, 0x44, 0x28, 0x10 } }, // 62 \u003e >
+ { {0x00, 0x40, 0x80, 0x9a, 0x90, 0x60 } }, // 63 \u003f ?
+ { {0x00, 0x7c, 0x82, 0xba, 0xaa, 0x78 } }, // 64 \u0040 @
+ { {0x00, 0x7e, 0x88, 0x88, 0x88, 0x7e } }, // 65 \u0041 A
+ { {0x00, 0xfe, 0x92, 0x92, 0x92, 0x6c } }, // 66 \u0042 B
+ { {0x00, 0x7c, 0x82, 0x82, 0x82, 0x44 } }, // 67 \u0043 C
+ { {0x00, 0xfe, 0x82, 0x82, 0x82, 0x7c } }, // 68 \u0044 D
+ { {0x00, 0xfe, 0x92, 0x92, 0x92, 0x82 } }, // 69 \u0045 E
+ { {0x00, 0xfe, 0x90, 0x90, 0x90, 0x80 } }, // 70 \u0046 F
+ { {0x00, 0x7c, 0x82, 0x92, 0x92, 0x5e } }, // 71 \u0047 G
+ { {0x00, 0xfe, 0x10, 0x10, 0x10, 0xfe } }, // 72 \u0048 H
+ { {0x00, 0x00, 0x82, 0xfe, 0x82, 0x00 } }, // 73 \u0049 I
+ { {0x00, 0x0c, 0x02, 0x02, 0x02, 0xfc } }, // 74 \u004a J
+ { {0x00, 0xfe, 0x10, 0x28, 0x44, 0x82 } }, // 75 \u004b K
+ { {0x00, 0xfe, 0x02, 0x02, 0x02, 0x02 } }, // 76 \u004c L
+ { {0x00, 0xfe, 0x40, 0x20, 0x40, 0xfe } }, // 77 \u004d M
+ { {0x00, 0xfe, 0x40, 0x20, 0x10, 0xfe } }, // 78 \u004e N
+ { {0x00, 0x7c, 0x82, 0x82, 0x82, 0x7c } }, // 79 \u004f O
+ { {0x00, 0xfe, 0x90, 0x90, 0x90, 0x60 } }, // 80 \u0050 P
+ { {0x00, 0x7c, 0x82, 0x8a, 0x84, 0x7a } }, // 81 \u0051 Q
+ { {0x00, 0xfe, 0x90, 0x90, 0x98, 0x66 } }, // 82 \u0052 R
+ { {0x00, 0x64, 0x92, 0x92, 0x92, 0x4c } }, // 83 \u0053 S
+ { {0x00, 0x80, 0x80, 0xfe, 0x80, 0x80 } }, // 84 \u0054 T
+ { {0x00, 0xfc, 0x02, 0x02, 0x02, 0xfc } }, // 85 \u0055 U
+ { {0x00, 0xf8, 0x04, 0x02, 0x04, 0xf8 } }, // 86 \u0056 V
+ { {0x00, 0xfc, 0x02, 0x3c, 0x02, 0xfc } }, // 87 \u0057 W
+ { {0x00, 0xc6, 0x28, 0x10, 0x28, 0xc6 } }, // 88 \u0058 X
+ { {0x00, 0xe0, 0x10, 0x0e, 0x10, 0xe0 } }, // 89 \u0059 Y
+ { {0x00, 0x8e, 0x92, 0xa2, 0xc2, 0x00 } }, // 90 \u005a Z
+ { {0x00, 0x00, 0xfe, 0x82, 0x82, 0x00 } }, // 91 \u005b [
+ { {0x00, 0x40, 0x20, 0x10, 0x08, 0x04 } }, // 92 \u005c slash
+ { {0x00, 0x00, 0x82, 0x82, 0xfe, 0x00 } }, // 93 \u005d ]
+ { {0x00, 0x20, 0x40, 0x80, 0x40, 0x20 } }, // 94 \u005e ^
+ { {0x01, 0x01, 0x01, 0x01, 0x01, 0x01 } }, // 95 \u005f _
+ { {0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00 } }, // 96 \u0060 `
+ { {0x00, 0x04, 0x2a, 0x2a, 0x2a, 0x1e } }, // 97 \u0061 a
+ { {0x00, 0xfe, 0x22, 0x22, 0x22, 0x1c } }, // 98 \u0062 b
+ { {0x00, 0x1c, 0x22, 0x22, 0x22, 0x14 } }, // 99 \u0063 c
+ { {0x00, 0x1c, 0x22, 0x22, 0x22, 0xfe } }, // 100 \u0064 d
+ { {0x00, 0x1c, 0x2a, 0x2a, 0x2a, 0x10 } }, // 101 \u0065 e
+ { {0x00, 0x10, 0x7e, 0x90, 0x90, 0x00 } }, // 102 \u0066 f
+ { {0x00, 0x18, 0x25, 0x25, 0x25, 0x3e } }, // 103 \u0067 g
+ { {0x00, 0xfe, 0x20, 0x20, 0x1e, 0x00 } }, // 104 \u0068 h
+ { {0x00, 0x00, 0x00, 0xbe, 0x02, 0x00 } }, // 105 \u0069 i
+ { {0x00, 0x02, 0x01, 0x21, 0xbe, 0x00 } }, // 106 \u006a j
+ { {0x00, 0xfe, 0x08, 0x14, 0x22, 0x00 } }, // 107 \u006b k
+ { {0x00, 0x00, 0x00, 0xfe, 0x02, 0x00 } }, // 108 \u006c l
+ { {0x00, 0x3e, 0x20, 0x18, 0x20, 0x1e } }, // 109 \u006d m
+ { {0x00, 0x3e, 0x20, 0x20, 0x1e, 0x00 } }, // 110 \u006e n
+ { {0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c } }, // 111 \u006f o
+ { {0x00, 0x3f, 0x22, 0x22, 0x22, 0x1c } }, // 112 \u0070 p
+ { {0x00, 0x1c, 0x22, 0x22, 0x22, 0x3f } }, // 113 \u0071 q
+ { {0x00, 0x22, 0x1e, 0x22, 0x20, 0x10 } }, // 114 \u0072 r
+ { {0x00, 0x10, 0x2a, 0x2a, 0x2a, 0x04 } }, // 115 \u0073 s
+ { {0x00, 0x20, 0x7c, 0x22, 0x24, 0x00 } }, // 116 \u0074 t
+ { {0x00, 0x3c, 0x02, 0x04, 0x3e, 0x00 } }, // 117 \u0075 u
+ { {0x00, 0x38, 0x04, 0x02, 0x04, 0x38 } }, // 118 \u0076 v
+ { {0x00, 0x3c, 0x06, 0x0c, 0x06, 0x3c } }, // 119 \u0077 w
+ { {0x00, 0x36, 0x08, 0x08, 0x36, 0x00 } }, // 120 \u0078 x
+ { {0x00, 0x39, 0x05, 0x06, 0x3c, 0x00 } }, // 121 \u0079 y
+ { {0x00, 0x26, 0x2a, 0x2a, 0x32, 0x00 } }, // 122 \u007a z
+ { {0x00, 0x10, 0x7c, 0x82, 0x82, 0x00 } }, // 123 \u007b {
+ { {0x00, 0x00, 0x00, 0xff, 0x00, 0x00 } }, // 124 \u007c |
+ { {0x00, 0x00, 0x82, 0x82, 0x7c, 0x10 } }, // 125 \u007d }
+ { {0x00, 0x40, 0x80, 0x40, 0x80, 0x00 } }, // 126 \u007e ~
+ { {0x00, 0x01, 0x01, 0x01, 0x01, 0x00 } }, // 127 \u2581 lower 1/8 block (trim)
+ { {0x00, 0x03, 0x03, 0x03, 0x03, 0x00 } }, // 128 \u2582 lower 1/4 block (trim)
+ { {0x00, 0x07, 0x07, 0x07, 0x07, 0x00 } }, // 129 \u2583 lower 3/8 block (trim)
+ { {0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00 } }, // 130 \u2584 lower 1/2 block (trim)
+ { {0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x00 } }, // 131 \u2585 lower 5/8 block (trim)
+ { {0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x00 } }, // 132 \u2586 lower 3/4 block (trim)
+ { {0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00 } }, // 133 \u2587 lower 7/8 block (trim)
+ { {0x00, 0xff, 0xff, 0xff, 0xff, 0x00 } }, // 134 \u2588 full block (vert trim)
+ { {0x3c, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 135 \u258f left 1/6 block (trim)
+ { {0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00 } }, // 136 \u258e left 1/3 block (trim)
+ { {0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00 } }, // 137 \u258c left 1/2 block (trim)
+ { {0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00 } }, // 138 \u258b left 2/3 block (trim)
+ { {0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x00 } }, // 139 \u258a left 5/6 block (trim)
+ { {0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c } }, // 140 \u2588 full block (horiz trim)
+ { {0xff, 0xff, 0xff, 0xff, 0xff, 0xff } }, // 141 \u2588 really full block
+ { {0x00, 0x44, 0xaa, 0x9a, 0x0c, 0x00 } }, // 142 \u03b4 delta
+ { {0x00, 0x38, 0x54, 0x54, 0x54, 0x00 } }, // 143 \u03b5 epsilon
+ { {0x00, 0x40, 0x7e, 0x40, 0x7e, 0x40 } }, // 144 \u03c0 pi
+ { {0x00, 0x18, 0x24, 0x24, 0x38, 0x20 } }, // 145 \u03c3 sigma
+ { {0x00, 0x10, 0x20, 0x1e, 0x20, 0x00 } }, // 146 \u03c4 tau
+ { {0x00, 0x18, 0x24, 0x7e, 0x24, 0x18 } }, // 147 \u03c6 phi
+ { {0x00, 0x18, 0x24, 0x18, 0x24, 0x18 } }, // 148 \u221e infinity
+ { {0x00, 0xfe, 0x80, 0x80, 0xc0, 0x00 } }, // 149 \u0393 Gamma
+ { {0x00, 0x7c, 0x92, 0x92, 0x7c, 0x00 } }, // 150 \u0398 Theta
+ { {0x00, 0x10, 0xaa, 0xee, 0xaa, 0x10 } }, // 151 \u03a6 Phi
+ { {0x00, 0x32, 0x4e, 0x40, 0x4e, 0x32 } }, // 152 \u03a9 Omega
+ { {0x3f, 0x31, 0x31, 0x29, 0x29, 0x25 } }, // 153 left half of mail icon
+ { {0x25, 0x29, 0x29, 0x31, 0x31, 0x3f } }, // 154 right half of mail icon
+ { {0x00, 0x10, 0x38, 0x54, 0x10, 0x10 } }, // 155 \u2190 left arrow
+ { {0x00, 0x20, 0x40, 0xfe, 0x40, 0x20 } }, // 156 \u2191 up arrow
+ { {0x00, 0x10, 0x10, 0x54, 0x38, 0x10 } }, // 157 \u2192 right arrow
+ { {0x00, 0x08, 0x04, 0xfe, 0x04, 0x08 } }, // 158 \u2193 down arrow
+ { {0x10, 0x38, 0x54, 0x54, 0x38, 0x10 } }, // 159 \u2194 left right arrrow
+ { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 160
+ { {0x00, 0x00, 0x0c, 0xbe, 0x0c, 0x00 } }, // 161 \u00a1 ¡ inverted exclamation mark
+ { {0x00, 0x18, 0x24, 0x7e, 0x24, 0x00 } }, // 162 \u00a2 ¢ cent
+ { {0x00, 0x12, 0x7c, 0x92, 0x92, 0x46 } }, // 163 \u00a3 £ pound
+ { {0x00, 0x1c, 0x2a, 0x2a, 0x22, 0x14 } }, // 164 \u20ac ¤ euro
+ { {0x00, 0x94, 0x54, 0x3e, 0x54, 0x94 } }, // 165 \u00a5 ¥ yen
+ { {0x00, 0x12, 0xaa, 0x6a, 0xaa, 0x24 } }, // 166 \u0160 ¦ capital S with caron
+ { {0x00, 0x44, 0xb2, 0xaa, 0x9a, 0x44 } }, // 167 \u00a7 § section
+ { {0x00, 0x10, 0xaa, 0x6a, 0xaa, 0x04 } }, // 168 \u0161 ¨ small s with caron
+ { {0x00, 0x1c, 0x3e, 0x36, 0x22, 0x1c } }, // 169 \u00a9 © copyright
+ { {0x00, 0x10, 0xaa, 0xaa, 0xaa, 0x7a } }, // 170 \u00aa ª feminine ordinal
+ { {0x00, 0x10, 0x28, 0x00, 0x10, 0x28 } }, // 171 \u00ab « left double angle
+ { {0x20, 0x20, 0x20, 0x20, 0x20, 0x38 } }, // 172 \u00ac ¬ not
+ { {0x00, 0x10, 0x10, 0x10, 0x10, 0x10 } }, // 173 \u00ad hyphen
+ { {0x00, 0x1c, 0x3e, 0x3a, 0x2e, 0x1c } }, // 174 \u00ae ® registered
+ { {0x00, 0x80, 0x80, 0x80, 0x80, 0x80 } }, // 175 \u00af ¯ macron
+ { {0x00, 0x60, 0x90, 0x90, 0x90, 0x60 } }, // 176 \u00b0 ° degree
+ { {0x00, 0x24, 0x24, 0xfc, 0x24, 0x24 } }, // 177 \u00b1 ± plus-minus
+ { {0x00, 0x90, 0xb0, 0x50, 0x00, 0x00 } }, // 178 \u00b2 ² superscript 2
+ { {0x00, 0xa8, 0xa8, 0x50, 0x00, 0x00 } }, // 179 \u00b3 ³ superscript 3
+ { {0x00, 0xa6, 0x6a, 0x72, 0xa2, 0x00 } }, // 180 \u017d ´ Z caron
+ { {0x00, 0x3f, 0x04, 0x04, 0x38, 0x00 } }, // 181 \u00b5 µ micro
+ { {0x00, 0x60, 0x90, 0xfe, 0x80, 0xfe } }, // 182 \u00b6 ¶ paragraph
+ { {0x00, 0x00, 0x18, 0x18, 0x00, 0x00 } }, // 183 \u00b7 · middle dot
+ { {0x00, 0xa6, 0x6a, 0x6a, 0xb2, 0x00 } }, // 184 \u017e ¸ z caron
+ { {0x00, 0x48, 0xf8, 0x08, 0x00, 0x00 } }, // 185 \u00b9 ¹ superscript 1
+ { {0x00, 0x72, 0x8a, 0x8a, 0x72, 0x00 } }, // 186 \u00ba º masculine ordinal
+ { {0x00, 0x28, 0x10, 0x00, 0x28, 0x10 } }, // 187 \u00bb » right double angle
+ { {0x00, 0xfe, 0x82, 0xfe, 0x92, 0x92 } }, // 188 \u0152 ¼ OE
+ { {0x00, 0x3e, 0x22, 0x3e, 0x2a, 0x12 } }, // 189 \u0153 ½ oe
+ { {0x00, 0x20, 0x90, 0x0e, 0x90, 0x20 } }, // 190 \u0178 ¾ Y diaeresis
+ { {0x00, 0x0c, 0x12, 0xb2, 0x02, 0x04 } }, // 191 \u00bf ¿ inverted question mark
+ { {0x00, 0x0e, 0x94, 0xa4, 0x54, 0x0e } }, // 192 \u00c0 À A grave
+ { {0x00, 0x0e, 0x54, 0xa4, 0x94, 0x0e } }, // 193 \u00c1 Á A acute
+ { {0x00, 0x0e, 0x54, 0xa4, 0x54, 0x0e } }, // 194 \u00c2 Â A circumflex
+ { {0x00, 0x4e, 0x94, 0x64, 0x94, 0x0e } }, // 195 \u00c3 Ã A tilde
+ { {0x00, 0x0e, 0x94, 0x24, 0x94, 0x0e } }, // 196 \u00c4 Ä A diaeresis
+ { {0x00, 0x1e, 0xf4, 0xa4, 0xf4, 0x1e } }, // 197 \u00c5 Å A ring
+ { {0x00, 0x7e, 0x90, 0xfe, 0x92, 0x92 } }, // 198 \u00c6 Æ AE
+ { {0x00, 0x78, 0x85, 0x87, 0x84, 0x48 } }, // 199 \u00c7 Ç C cedilla
+ { {0x00, 0x3e, 0xaa, 0xaa, 0x6a, 0x62 } }, // 200 \u00c8 È E grave
+ { {0x00, 0x3e, 0x6a, 0x6a, 0xaa, 0xa2 } }, // 201 \u00c9 É E acute
+ { {0x00, 0x7e, 0xaa, 0xaa, 0x6a, 0x22 } }, // 202 \u00ca Ê E circumflex
+ { {0x00, 0x3e, 0xaa, 0x2a, 0x2a, 0xa2 } }, // 203 \u00cb Ë E diaeresis
+ { {0x00, 0x00, 0xa2, 0xbe, 0x62, 0x00 } }, // 204 \u00cc Ì I grave
+ { {0x00, 0x00, 0x62, 0xbe, 0xa2, 0x00 } }, // 205 \u00cd Í I acute
+ { {0x00, 0x00, 0x62, 0xbe, 0x62, 0x00 } }, // 206 \u00ce Î I circumflex
+ { {0x00, 0x00, 0xa2, 0x3e, 0xa2, 0x00 } }, // 207 \u00cf Ï I diaeresis
+ { {0x00, 0xfe, 0x92, 0x92, 0x82, 0x7c } }, // 208 \u00d0 Ð Eth
+ { {0x00, 0x5e, 0x88, 0x44, 0x9e, 0x00 } }, // 209 \u00d1 Ñ N tilde
+ { {0x00, 0x9c, 0xa2, 0x62, 0x1c, 0x00 } }, // 210 \u00d2 Ò O grave
+ { {0x00, 0x1c, 0x62, 0xa2, 0x9c, 0x00 } }, // 211 \u00d3 Ó O acute
+ { {0x00, 0x1c, 0x62, 0xa2, 0x5c, 0x00 } }, // 212 \u00d4 Ô O circumflex
+ { {0x00, 0x5c, 0xa2, 0x62, 0x9c, 0x00 } }, // 213 \u00d5 Õ O tilde
+ { {0x00, 0x9c, 0x22, 0x22, 0x9c, 0x00 } }, // 214 \u00d6 Ö O diaeresis
+ { {0x00, 0x14, 0x08, 0x08, 0x14, 0x00 } }, // 215 \u00d7 × multiplication
+ { {0x00, 0x7c, 0x86, 0xba, 0xc2, 0x7c } }, // 216 \u00d8 Ø O slash
+ { {0x00, 0x3c, 0x82, 0x82, 0x7c, 0x00 } }, // 217 \u00d9 Ù U grave
+ { {0x00, 0x3c, 0x42, 0x82, 0xbc, 0x00 } }, // 218 \u00da Ú U acute
+ { {0x00, 0x1c, 0x42, 0x82, 0x5c, 0x00 } }, // 219 \u00db Û U circumflex
+ { {0x00, 0x3c, 0x82, 0x02, 0xbc, 0x00 } }, // 220 \u00dc Ü U diaeresis
+ { {0x00, 0x20, 0x50, 0x8e, 0x90, 0x20 } }, // 221 \u00dd Ý Y acute
+ { {0x00, 0xff, 0x22, 0x22, 0x22, 0x1c } }, // 222 \u00de Þ Thorn
+ { {0x00, 0x7e, 0x50, 0x52, 0x2c, 0x00 } }, // 223 \u00df ß Eszett
+ { {0x00, 0x04, 0xaa, 0xaa, 0x6a, 0x1e } }, // 224 \u00e0 à a grave
+ { {0x00, 0x04, 0x6a, 0xaa, 0xaa, 0x1e } }, // 225 \u00e1 á a acute
+ { {0x00, 0x04, 0x6a, 0xaa, 0x6a, 0x1e } }, // 226 \u00e2 â a circumplex
+ { {0x00, 0x04, 0x6a, 0xaa, 0x6a, 0x9e } }, // 227 \u00e3 ã a tilde
+ { {0x00, 0x04, 0xaa, 0x2a, 0xaa, 0x1e } }, // 228 \u00e4 ä a diaeresis
+ { {0x00, 0x04, 0xea, 0xaa, 0xea, 0x1e } }, // 229 \u00e5 å a ring
+ { {0x00, 0x2c, 0x2a, 0x3e, 0x2a, 0x1a } }, // 230 \u00e6 æ ae
+ { {0x00, 0x38, 0x45, 0x47, 0x44, 0x28 } }, // 231 \u00e7 ç c cedilla
+ { {0x00, 0x1c, 0xaa, 0xaa, 0x6a, 0x10 } }, // 232 \u00e8 è e grave
+ { {0x00, 0x1c, 0x2a, 0x6a, 0xaa, 0x90 } }, // 233 \u00e9 é e acute
+ { {0x00, 0x1c, 0x6a, 0xaa, 0x6a, 0x10 } }, // 234 \u00ea ê e circumflex
+ { {0x00, 0x1c, 0xaa, 0x2a, 0xaa, 0x10 } }, // 235 \u00eb ë e diaeresis
+ { {0x00, 0x00, 0x80, 0xbe, 0x42, 0x00 } }, // 236 \u00ec ì i grave
+ { {0x00, 0x00, 0x40, 0xbe, 0x82, 0x00 } }, // 237 \u00ed í i acute
+ { {0x00, 0x00, 0x40, 0x9e, 0x42, 0x00 } }, // 238 \u00ee î i circumflex
+ { {0x00, 0x00, 0x80, 0x3e, 0x82, 0x00 } }, // 239 \u00ef ï i diaeresis
+ { {0x00, 0x9c, 0xe2, 0xa2, 0xa2, 0x7c } }, // 240 \u00f0 ð eth
+ { {0x00, 0x5e, 0x90, 0x50, 0x8e, 0x00 } }, // 241 \u00f1 ñ n tilde
+ { {0x00, 0x9c, 0xa2, 0x62, 0x1c, 0x00 } }, // 242 \u00f2 ò o grave
+ { {0x00, 0x1c, 0x62, 0xa2, 0x9c, 0x00 } }, // 243 \u00f3 ó o acute
+ { {0x00, 0x1c, 0x62, 0xa2, 0x5c, 0x00 } }, // 244 \u00f4 ô o circumflex
+ { {0x00, 0x5c, 0xa2, 0x62, 0x9c, 0x00 } }, // 245 \u00f5 õ o tilde
+ { {0x00, 0x1c, 0xa2, 0x22, 0x9c, 0x00 } }, // 246 \u00f6 ö o diaeresis
+ { {0x00, 0x10, 0x10, 0x54, 0x10, 0x10 } }, // 247 \u00f7 ÷ division
+ { {0x00, 0x1d, 0x26, 0x2a, 0x32, 0x5c } }, // 248 \u00f8 ø o slash
+ { {0x00, 0xbc, 0x82, 0x44, 0x3e, 0x00 } }, // 249 \u00f9 ù u grave
+ { {0x00, 0x3c, 0x42, 0x84, 0xbe, 0x00 } }, // 250 \u00fa ú u acute
+ { {0x00, 0x1c, 0x42, 0x84, 0x5e, 0x00 } }, // 251 \u00fb û u circumflex
+ { {0x00, 0x3c, 0x82, 0x04, 0xbe, 0x00 } }, // 252 \u00fc ü u diaeresis
+ { {0x00, 0x39, 0x45, 0x86, 0xbc, 0x00 } }, // 253 \u00fd ý y acute
+ { {0x00, 0xff, 0x12, 0x12, 0x12, 0x0c } }, // 254 \u00fe þ thorn
+ { {0x00, 0x39, 0x85, 0x06, 0xbc, 0x00 } } // 255 \u00ff ÿ y diaeresis
+};
+#endif
+
+#ifdef IMONLCD_FONT_DESC
+/* This char array is available for use when converting to and from the
+ * structure. It is not needed for normal LCD use.
+ */
+static char *desc[] = {
+ " 0 \\u0020 space",
+ " 1 \\u263a light smiley face",
+ " 2 \\u263b dark smiley face",
+ " 3 \\u2665 full heart",
+ " 4 small heart",
+ " 5 \\u2660 club",
+ " 6 \\u2660 spade",
+ " 7 \\u2022 bullet",
+ " 8 \\u25d8 big rectangle",
+ " 9 \\u25cb small rectangle",
+ " 10 \\u25d9 filled rectangle",
+ " 11 \\u2642 man symbol",
+ " 12 \\u2640 woman symbol",
+ " 13 \\u266a musical note",
+ " 14 \\u266b double music note",
+ " 15 \\u25cf record",
+ " 16 \\u25b6 play",
+ " 17 \\u25c0 play backwards",
+ " 18 pause",
+ " 19 \\u25fe stop",
+ " 20 \\u23cf eject",
+ " 21 fwd",
+ " 22 rev",
+ " 23 \\u2581 lower 1/8 block (full)",
+ " 24 \\u2582 lower 1/4 block (full)",
+ " 25 \\u2583 lower 3/8 block (full)",
+ " 26 \\u2584 lower 1/2 block (full)",
+ " 27 \\u2585 lower 5/8 block (full)",
+ " 28 \\u2586 lower 3/4 block (full)",
+ " 29 \\u2587 lower 7/8 block (full)",
+ " 30",
+ " 31",
+ " 32 \\u0020 space",
+ " 33 \\u0021 !",
+ " 34 \\u0022 \"",
+ " 35 \\u0023 #",
+ " 36 \\u0024 $",
+ " 37 \\u0025 %",
+ " 38 \\u0026 &",
+ " 39 \\u0027 '",
+ " 40 \\u0028 (",
+ " 41 \\u0029 )",
+ " 42 \\u002a *",
+ " 43 \\u002b +",
+ " 44 \\u002c ,",
+ " 45 \\u002d -",
+ " 46 \\u002e .",
+ " 47 \\u002f /",
+ " 48 \\u0030 0",
+ " 49 \\u0031 1",
+ " 50 \\u0032 2",
+ " 51 \\u0033 3",
+ " 52 \\u0034 4",
+ " 53 \\u0035 5",
+ " 54 \\u0036 6",
+ " 55 \\u0037 7",
+ " 56 \\u0038 8",
+ " 57 \\u0039 9",
+ " 58 \\u003a :",
+ " 59 \\u003b ;",
+ " 60 \\u003c <",
+ " 61 \\u003d =",
+ " 62 \\u003e >",
+ " 63 \\u003f ?",
+ " 64 \\u0040 @",
+ " 65 \\u0041 A",
+ " 66 \\u0042 B",
+ " 67 \\u0043 C",
+ " 68 \\u0044 D",
+ " 69 \\u0045 E",
+ " 70 \\u0046 F",
+ " 71 \\u0047 G",
+ " 72 \\u0048 H",
+ " 73 \\u0049 I",
+ " 74 \\u004a J",
+ " 75 \\u004b K",
+ " 76 \\u004c L",
+ " 77 \\u004d M",
+ " 78 \\u004e N",
+ " 79 \\u004f O",
+ " 80 \\u0050 P",
+ " 81 \\u0051 Q",
+ " 82 \\u0052 R",
+ " 83 \\u0053 S",
+ " 84 \\u0054 T",
+ " 85 \\u0055 U",
+ " 86 \\u0056 V",
+ " 87 \\u0057 W",
+ " 88 \\u0058 X",
+ " 89 \\u0059 Y",
+ " 90 \\u005a Z",
+ " 91 \\u005b [",
+ " 92 \\u005c \\",
+ " 93 \\u005d ]",
+ " 94 \\u005e ^",
+ " 95 \\u005f _",
+ " 96 \\u0060 `",
+ " 97 \\u0061 a",
+ " 98 \\u0062 b",
+ " 99 \\u0063 c",
+ "100 \\u0064 d",
+ "101 \\u0065 e",
+ "102 \\u0066 f",
+ "103 \\u0067 g",
+ "104 \\u0068 h",
+ "105 \\u0069 i",
+ "106 \\u006a j",
+ "107 \\u006b k",
+ "108 \\u006c l",
+ "109 \\u006d m",
+ "110 \\u006e n",
+ "111 \\u006f o",
+ "112 \\u0070 p",
+ "113 \\u0071 q",
+ "114 \\u0072 r",
+ "115 \\u0073 s",
+ "116 \\u0074 t",
+ "117 \\u0075 u",
+ "118 \\u0076 v",
+ "119 \\u0077 w",
+ "120 \\u0078 x",
+ "121 \\u0079 y",
+ "122 \\u007a z",
+ "123 \\u007b {",
+ "124 \\u007c |",
+ "125 \\u007d }",
+ "126 \\u007e ~",
+ "127 \\u2581 lower 1/8 block (trim)",
+ "128 \\u2582 lower 1/4 block (trim)",
+ "129 \\u2583 lower 3/8 block (trim)",
+ "130 \\u2584 lower 1/2 block (trim)",
+ "131 \\u2585 lower 5/8 block (trim)",
+ "132 \\u2586 lower 3/4 block (trim)",
+ "133 \\u2587 lower 7/8 block (trim)",
+ "134 \\u2588 full block (vert trim)",
+ "135 \\u258f left 1/6 block (trim)",
+ "136 \\u258e left 1/3 block (trim)",
+ "137 \\u258c left 1/2 block (trim)",
+ "138 \\u258b left 2/3 block (trim)",
+ "139 \\u258a left 5/6 block (trim)",
+ "140 \\u2588 full block (horiz trim)",
+ "141 \\u2588 really full block",
+ "142 \\u03b4 delta",
+ "143 \\u03b5 epsilon",
+ "144 \\u03c0 pi",
+ "145 \\u03c3 sigma",
+ "146 \\u03c4 tau",
+ "147 \\u03c6 phi",
+ "148 \\u221e infinity",
+ "149 \\u0393 Gamma",
+ "150 \\u0398 Theta",
+ "151 \\u03a6 Phi",
+ "152 \\u03a9 Omega",
+ "153 left half of mail icon",
+ "154 right half of mail icon",
+ "155 \\u2190 left arrow",
+ "156 \\u2191 up arrow",
+ "157 \\u2192 right arrow",
+ "158 \\u2193 down arrow",
+ "159 \\u2194 left right arrrow",
+ "160",
+ "161 \\u00a1 ¡ inverted exclamation mark",
+ "162 \\u00a2 ¢ cent",
+ "163 \\u00a3 £ pound",
+ "164 \\u20ac ¤ euro",
+ "165 \\u00a5 ¥ yen",
+ "166 \\u0160 ¦ capital S with caron",
+ "167 \\u00a7 § section",
+ "168 \\u0161 ¨ small s with caron",
+ "169 \\u00a9 © copyright",
+ "170 \\u00aa ª feminine ordinal",
+ "171 \\u00ab « left double angle",
+ "172 \\u00ac ¬ not",
+ "173 \\u00ad hyphen",
+ "174 \\u00ae ® registered",
+ "175 \\u00af ¯ macron",
+ "176 \\u00b0 ° degree",
+ "177 \\u00b1 ± plus-minus",
+ "178 \\u00b2 ² superscript 2",
+ "179 \\u00b3 ³ superscript 3",
+ "180 \\u017d ´ Z caron",
+ "181 \\u00b5 µ micro",
+ "182 \\u00b6 ¶ paragraph",
+ "183 \\u00b7 · middle dot",
+ "184 \\u017e ¸ z caron",
+ "185 \\u00b9 ¹ superscript 1",
+ "186 \\u00ba º masculine ordinal",
+ "187 \\u00bb » right double angle",
+ "188 \\u0152 ¼ OE",
+ "189 \\u0153 ½ oe",
+ "190 \\u0178 ¾ Y diaeresis",
+ "191 \\u00bf ¿ inverted question mark",
+ "192 \\u00c0 À A grave",
+ "193 \\u00c1 Á A acute",
+ "194 \\u00c2 Â A circumflex",
+ "195 \\u00c3 Ã A tilde",
+ "196 \\u00c4 Ä A diaeresis",
+ "197 \\u00c5 Å A ring",
+ "198 \\u00c6 Æ AE",
+ "199 \\u00c7 Ç C cedilla",
+ "200 \\u00c8 È E grave",
+ "201 \\u00c9 É E acute",
+ "202 \\u00ca Ê E circumflex",
+ "203 \\u00cb Ë E diaeresis",
+ "204 \\u00cc Ì I grave",
+ "205 \\u00cd Í I acute",
+ "206 \\u00ce Î I circumflex",
+ "207 \\u00cf Ï I diaeresis",
+ "208 \\u00d0 Ð Eth",
+ "209 \\u00d1 Ñ N tilde",
+ "210 \\u00d2 Ò O grave",
+ "211 \\u00d3 Ó O acute",
+ "212 \\u00d4 Ô O circumflex",
+ "213 \\u00d5 Õ O tilde",
+ "214 \\u00d6 Ö O diaeresis",
+ "215 \\u00d7 × multiplication",
+ "216 \\u00d8 Ø O slash",
+ "217 \\u00d9 Ù U grave",
+ "218 \\u00da Ú U acute",
+ "219 \\u00db Û U circumflex",
+ "220 \\u00dc Ü U diaeresis",
+ "221 \\u00dd Ý Y acute",
+ "222 \\u00de Þ Thorn",
+ "223 \\u00df ß Eszett",
+ "224 \\u00e0 à a grave",
+ "225 \\u00e1 á a acute",
+ "226 \\u00e2 â a circumplex",
+ "227 \\u00e3 ã a tilde",
+ "228 \\u00e4 ä a diaeresis",
+ "229 \\u00e5 å a ring",
+ "230 \\u00e6 æ ae",
+ "231 \\u00e7 ç c cedilla",
+ "232 \\u00e8 è e grave",
+ "233 \\u00e9 é e acute",
+ "234 \\u00ea ê e circumflex",
+ "235 \\u00eb ë e diaeresis",
+ "236 \\u00ec ì i grave",
+ "237 \\u00ed í i acute",
+ "238 \\u00ee î i circumflex",
+ "239 \\u00ef ï i diaeresis",
+ "240 \\u00f0 ð eth",
+ "241 \\u00f1 ñ n tilde",
+ "242 \\u00f2 ò o grave",
+ "243 \\u00f3 ó o acute",
+ "244 \\u00f4 ô o circumflex",
+ "245 \\u00f5 õ o tilde",
+ "246 \\u00f6 ö o diaeresis",
+ "247 \\u00f7 ÷ division",
+ "248 \\u00f8 ø o slash",
+ "249 \\u00f9 ù u grave",
+ "250 \\u00fa ú u acute",
+ "251 \\u00fb û u circumflex",
+ "252 \\u00fc ü u diaeresis",
+ "253 \\u00fd ý y acute",
+ "254 \\u00fe þ thorn",
+ "255 \\u00ff ÿ y diaeresis"
+};
+
+#endif
+
+/**
+ * This is the definition for a "big" font, which is a font that
+ * simply takes up twice as many pixels as the normal font.
+ * (12 col x 18 row pixels). It is only used for drawing numbers.
+ */
+typedef struct _imon_bigfont {
+ int ch;
+ unsigned short pixels[12];
+} imon_bigfont;
+
+/** Character data for the big font */
+static imon_bigfont bigfont[] = {
+ {'0', {0x0000, 0x07E0, 0x1FF8, 0x3FFC, 0x7FFE, 0x4002, 0x4002, 0x4002, 0x3FFC, 0x3FFC, 0x1FF8, 0x07E0}},
+ {'1', {0x0000, 0x0000, 0x0000, 0x4002, 0x7FFE, 0x7FFE, 0x7FFE, 0x7FFE, 0x0002, 0x0000, 0x0000, 0x0000}},
+ {'2', {0x0000, 0x1806, 0x3C2C, 0x7C7C, 0x5C5C, 0x40DE, 0x7F9E, 0x7F8E, 0x3F0E, 0x1E0C, 0x0018, 0x0000}},
+ {'3', {0x0000, 0x001C, 0x3C3C, 0x7C3E, 0x7C1A, 0x0080, 0x4182, 0x7FFE, 0x7FFE, 0x3E7C, 0x1C38, 0x0000}},
+ {'4', {0x0000, 0x0030, 0x0050, 0x0190, 0x0610, 0x0002, 0x1FFE, 0x3FFE, 0x7FFE, 0x7FFE, 0x0012, 0x0002}},
+ {'5', {0x0000, 0x0018, 0x7FBC, 0x793E, 0x3B1A, 0x3800, 0x3B02, 0x3BFE, 0x31FE, 0x61FC, 0x00F8, 0x0000}},
+ {'6', {0x0000, 0x07E0, 0x1FF8, 0x3FFC, 0x7FFE, 0x4002, 0x0180, 0x5982, 0x7DFE, 0x3DFC, 0x18FC, 0x0078}},
+ {'7', {0x0000, 0x0800, 0x7000, 0x3000, 0x703C, 0x787E, 0x79FE, 0x7BFC, 0x3E00, 0x3000, 0x6000, 0x0000}},
+ {'8', {0x0000, 0x1C3C, 0x3E7E, 0x7FFE, 0x7FFE, 0x4182, 0x4182, 0x7FFE, 0x7FFE, 0x3E7E, 0x1C3C, 0x0000}},
+ {'9', {0x0000, 0x1E18, 0x3F3C, 0x7FBE, 0x7F9A, 0x0180, 0x4002, 0x7FFE, 0x3FFC, 0x1FF8, 0x07E0, 0x0000}},
+ {':', {0x0000, 0x030C, 0x079E, 0x079E, 0x030C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}},
+
+ /*
+ * Marks the end of the array, but also serves as the character that
+ * unknown inputs are mapped to (essentially, a "space")
+ */
+ {'\0', {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+};