From 8bd28df1ee60e9ad67f41c09a58be977d28c3e61 Mon Sep 17 00:00:00 2001 From: mmdolze Date: Thu, 14 May 2009 21:45:51 +0000 Subject: [PATCH] Add imonlcd driver for SoundGraph iMON OEM LCD modules (by Dean Harding, Christian Leuschen, Jonathan Kyler and Eric Pooch) --- CREDITS | 6 + ChangeLog | 3 +- LCDd.conf | 31 +- acinclude.m4 | 8 +- clients/lcdproc/mode.c | 3 + docs/LCDd.8.in | 3 + docs/lcdproc-user/drivers.docbook | 1 + docs/lcdproc-user/drivers/imonlcd.docbook | 134 ++ docs/lcdproc-user/lcdproc-user.docbook | 1 + server/drivers/Makefile.am | 4 +- server/drivers/imonlcd.c | 1393 +++++++++++++++++++++ server/drivers/imonlcd.h | 62 + server/drivers/imonlcd_font.h | 630 ++++++++++ 13 files changed, 2273 insertions(+), 6 deletions(-) create mode 100644 docs/lcdproc-user/drivers/imonlcd.docbook create mode 100644 server/drivers/imonlcd.c create mode 100644 server/drivers/imonlcd.h create mode 100644 server/drivers/imonlcd_font.h 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}} +};