diff -Naur lcdproc-0.5.2.old/LCDd.conf lcdproc-0.5.2.new/LCDd.conf --- lcdproc-0.5.2.old/LCDd.conf 2007-04-25 19:56:43.000000000 +0000 +++ lcdproc-0.5.2.new/LCDd.conf 2007-09-06 11:06:32.000000000 +0000 @@ -41,7 +41,7 @@ # irman, joy, lb216, lcdm001, lcterm, lirc, MD8800, ms6931, mtc_s16209x, # MtxOrb, NoritakeVFD, picolcd, pyramid, sed1330, sed1520, serialPOS, # serialVFD, sli, stv5730, svga, t6963, text, tyan, ula200, xosd -Driver=curses +Driver=imonlcd # Tells the driver to bind to the given interface Bind=127.0.0.1 @@ -50,10 +50,10 @@ Port=13666 # Sets the reporting level; defaults to 2 (warnings and errors only). -#ReportLevel=3 +ReportLevel=4 # Should we report to syslog instead of stderr ? Default: no -#ReportToSyslog=yes +# ReportToSyslog=yes # Sets the default time in seconds to displays a screen. WaitTime=5 @@ -76,7 +76,8 @@ # the driver modules and will thus not be able to # function properly. # NOTE: Always place a slash as last character ! -DriverPath=server/drivers/ +#DriverPath=server/drivers/ +DriverPath=/usr/local/lib/lcdproc/ # GoodBye message: each entry represents a display line; default: builtin #GoodBye="Thanks for using" @@ -508,7 +509,7 @@ -## Soundgraph/Ahanix/Silverstone/Uneed/Accent iMON driver ## +## Soundgraph/Ahanix/Silverstone/Uneed/Accent iMON VFD driver ## [imon] # select the device to use @@ -517,7 +518,18 @@ # display dimensions Size=16x2 +## Soundgraph iMON LCD driver ## +[imonlcd] +# select the device to use +Device=/dev/lcd0 + +# display dimensions (generally, don't need to touch) +#Size=96x16 + +# what to do when the server stops. 0=show exit message, 1=show clock (default) +# and 2=blank LCD screen +OnExit=2 ## IrMan driver ## [IrMan] diff -Naur lcdproc-0.5.2.old/acinclude.m4 lcdproc-0.5.2.new/acinclude.m4 --- lcdproc-0.5.2.old/acinclude.m4 2007-04-14 14:39:28.000000000 +0000 +++ lcdproc-0.5.2.new/acinclude.m4 2007-09-02 09:37:09.000000000 +0000 @@ -6,7 +6,7 @@ [ which is a comma-separated list of drivers.] [ Possible drivers are:] [ 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,MD8800,ms6931,] [ mtc_s16209x,MtxOrb,NoritakeVFD,picolcd,pyramid,sed1330] [ sed1520,serialPOS,serialVFD,sli,stv5730,svga,t6963,text,] @@ -16,7 +16,7 @@ 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,icp_a106,imon,IOWarrior,irman,joy,lb216,lcdm001,lcterm,lirc,MD8800,ms6931,mtc_s16209x,MtxOrb,NoritakeVFD,picolcd,pyramid,sed1330,sed1520,serialPOS,serialVFD,sli,stv5730,svga,t6963,text,tyan,ula200,xosd] +allDrivers=[bayrad,CFontz,CFontz633,CFontzPacket,curses,CwLnx,ea65,EyeboxOne,g15,glcdlib,glk,hd44780,icp_a106,imon,imonlcd,IOWarrior,irman,joy,lb216,lcdm001,lcterm,lirc,MD8800,ms6931,mtc_s16209x,MtxOrb,NoritakeVFD,picolcd,pyramid,sed1330,sed1520,serialPOS,serialVFD,sli,stv5730,svga,t6963,text,tyan,ula200,xosd] drivers=`echo $drivers | sed -e 's/,/ /g'` @@ -207,6 +207,10 @@ 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 -Naur lcdproc-0.5.2.old/server/drivers/Makefile.am lcdproc-0.5.2.new/server/drivers/Makefile.am --- lcdproc-0.5.2.old/server/drivers/Makefile.am 2007-04-14 14:39:53.000000000 +0000 +++ lcdproc-0.5.2.new/server/drivers/Makefile.am 2007-09-02 09:31:34.000000000 +0000 @@ -19,7 +19,7 @@ #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 MD8800 ms6931 mtc_s16209x MtxOrb NoritakeVFD picolcd pyramid sed1330 sed1520 serialPOS serialVFD stv5730 svga t6963 text tyan sli ula200 xosd +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 MD8800 ms6931 mtc_s16209x MtxOrb NoritakeVFD picolcd pyramid sed1330 sed1520 serialPOS serialVFD stv5730 svga t6963 text tyan sli ula200 xosd noinst_LIBRARIES = libLCD.a libbignum.a IOWarrior_CFLAGS = @libusb_cflags@ $(AM_CFLAGS) @@ -37,6 +37,7 @@ 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 @@ -75,6 +76,7 @@ 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.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 -Naur lcdproc-0.5.2.old/server/drivers/imonlcd.c lcdproc-0.5.2.new/server/drivers/imonlcd.c --- lcdproc-0.5.2.old/server/drivers/imonlcd.c 1970-01-01 00:00:00.000000000 +0000 +++ lcdproc-0.5.2.new/server/drivers/imonlcd.c 2007-09-11 08:54:12.000000000 +0000 @@ -0,0 +1,883 @@ +/** + * Driver for SoundGraph iMON OEM (and others) LCD Module + * + * In order to be able to use it, you have to install the lirc_imonlcd + * kernel module for LIRC (http://www.lirc.org) -- until that module is + * available in the main LIRC branch, you can get a patch for it from + * the same place you got this patch. + * + * Copyright (c) 2007, Dean Harding , but (heavily :p) + * on the work of Venky Raju. + * + * This source code is being released under the GPL. + * Please see the file COPYING in this package for details. + * + */ + +#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" +//#define DEBUG +#include "report.h" + + +#include "imonlcd.h" + +#define DEFAULT_DEVICE "/dev/lcd0" +#define DEFAULT_SIZE "96x16" // This is the size in "pixels"... + +#define LCD_DEFAULT_CELL_WIDTH 6 +#define LCD_DEFAULT_CELL_HEIGHT 8 + +#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 DEFAULT_ON_EXIT "1" + +// 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_"; + +// Our private data +typedef struct { + char info[255]; + int imon_fd; + unsigned char *framebuf; + int height; + int width; + int cellwidth; + int cellheight; + int on_exit; + + /* + * Here we record the last "state" of the CD icon so that we can "animate" it. + */ + int last_cd_state; + time_t last_cd_state_change; + uint64_t last_icon_state; +} PrivateData; + +/* + * 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_SRC1_MASK 0x00000800 +#define IMON_OUTPUT_SRC2_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 + +/* + * The iMON LCD doesn't have a "text mode" -- everthing is pixel-based. So we need to define + * our own font, basically. This structure holds the definition of that 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 { + int ch; + char pixels[6]; +} imon_font; + +static imon_font font[] = { + { ' ', { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }, + { '!', { 0x0, 0x0, 0x0, 0xF6, 0x0, 0x0 } }, + { '"', { 0x0, 0x0, 0xE0, 0x0, 0xE0, 0x0 } }, + { '#', { 0x0, 0x28, 0xFE, 0x28, 0xFE, 0x28 } }, + { '$', { 0x0, 0x0, 0xE0, 0x20, 0x78, 0x0 } }, + { '%', { 0x0, 0xC4, 0xC8, 0x10, 0x26, 0x46 } }, + { '&', { 0x0, 0x6C, 0x92, 0x6A, 0x4, 0xA } }, + { '\'', { 0x0, 0x0, 0x0, 0xE0, 0x0, 0x0 } }, + { '(', { 0x0, 0x0, 0x38, 0x44, 0x82, 0x0 } }, + { ')', { 0x0, 0x0, 0x82, 0x44, 0x38, 0x0 } }, + { '*', { 0x0, 0x28, 0x10, 0x7C, 0x10, 0x28 } }, + { '+', { 0x0, 0x10, 0x10, 0x7C, 0x10, 0x10 } }, + { ',', { 0x0, 0x0, 0xA, 0xC, 0x0, 0x0 } }, + { '-', { 0x0, 0x10, 0x10, 0x10, 0x10, 0x10 } }, + { '.', { 0x0, 0x0, 0x6, 0x6, 0x0, 0x0 } }, + { '/', { 0x0, 0x4, 0x8, 0x10, 0x20, 0x40 } }, + { '0', { 0x0, 0x7C, 0x8A, 0x92, 0xA2, 0x7C } }, + { '1', { 0x0, 0x0, 0x42, 0xFE, 0x2, 0x0 } }, + { '2', { 0x0, 0x42, 0x86, 0x8A, 0x92, 0x62 } }, + { '3', { 0x0, 0x84, 0x82, 0xA2, 0xD2, 0x8C } }, + { '4', { 0x0, 0x18, 0x28, 0x48, 0xFE, 0x8 } }, + { '5', { 0x0, 0xE4, 0xA2, 0xA2, 0xA2, 0x9C } }, + { '6', { 0x0, 0x3C, 0x52, 0x92, 0x92, 0xC } }, + { '7', { 0x0, 0x80, 0x8E, 0x90, 0xA0, 0xC0 } }, + { '8', { 0x0, 0x6C, 0x92, 0x92, 0x92, 0x6C } }, + { '9', { 0x0, 0x60, 0x92, 0x92, 0x94, 0x78 } }, + { ':', { 0x0, 0x0, 0x6C, 0x6C, 0x0, 0x0 } }, + { ';', { 0x0, 0x0, 0x6A, 0x6C, 0x0, 0x0 } }, + { '<', { 0x0, 0x10, 0x28, 0x44, 0x82, 0x0 } }, + { '=', { 0x0, 0x28, 0x28, 0x28, 0x28, 0x28 } }, + { '>', { 0x0, 0x0, 0x82, 0x44, 0x28, 0x10 } }, + { '?', { 0x0, 0x40, 0x80, 0x8A, 0x90, 0x60 } }, + { '@', { 0x0, 0x7C, 0x82, 0xBA, 0x92, 0x72 } }, + { 'A', { 0x0, 0x7E, 0x90, 0x90, 0x90, 0x7E } }, + { 'B', { 0x0, 0xFE, 0x92, 0x92, 0x92, 0x6C } }, + { 'C', { 0x0, 0x7C, 0x82, 0x82, 0x82, 0x44 } }, + { 'D', { 0x0, 0xFE, 0x82, 0x82, 0x82, 0x7C } }, + { 'E', { 0x0, 0xFE, 0x92, 0x92, 0x92, 0x82 } }, + { 'F', { 0x0, 0xFE, 0x90, 0x90, 0x90, 0x80 } }, + { 'G', { 0x0, 0x7C, 0x82, 0x92, 0x92, 0x5E } }, + { 'H', { 0x0, 0xFE, 0x10, 0x10, 0x10, 0xFE } }, + { 'I', { 0x0, 0x0, 0x82, 0xFE, 0x82, 0x0 } }, + { 'J', { 0x0, 0x4, 0x2, 0x82, 0xFC, 0x80 } }, + { 'K', { 0x0, 0xFE, 0x10, 0x28, 0x44, 0x82 } }, + { 'L', { 0x0, 0xFE, 0x2, 0x2, 0x2, 0x2 } }, + { 'M', { 0x0, 0xFE, 0x40, 0x30, 0x40, 0xFE } }, + { 'N', { 0x0, 0xFE, 0x20, 0x10, 0x8, 0xFE } }, + { 'O', { 0x0, 0x7C, 0x82, 0x82, 0x82, 0x7C } }, + { 'P', { 0x0, 0xFE, 0x90, 0x90, 0x90, 0x60 } }, + { 'Q', { 0x0, 0x7C, 0x82, 0x8A, 0x84, 0x7A } }, + { 'R', { 0x0, 0xFE, 0x90, 0x98, 0x94, 0x62 } }, + { 'S', { 0x0, 0x62, 0x92, 0x92, 0x92, 0x8C } }, + { 'T', { 0x0, 0x80, 0x80, 0xFE, 0x80, 0x80 } }, + { 'U', { 0x0, 0xFC, 0x2, 0x2, 0x2, 0xFC } }, + { 'V', { 0x0, 0xF0, 0xC, 0x2, 0xC, 0xF0 } }, + { 'W', { 0x0, 0xFC, 0x2, 0xC, 0x2, 0xFC } }, + { 'X', { 0x0, 0xC6, 0x28, 0x10, 0x28, 0xC6 } }, + { 'Y', { 0x0, 0xE0, 0x10, 0xE, 0x10, 0xE0 } }, + { 'Z', { 0x0, 0x86, 0x8A, 0x92, 0xA2, 0xC2 } }, + { '[', { 0x0, 0x3C, 0x52, 0x92, 0x94, 0x78 } }, + { '\\', { 0x0, 0x40, 0x20, 0x10, 0x8, 0x4 } }, + { ']', { 0x0, 0x0, 0x82, 0xFE, 0x0, 0x0 } }, + { '^', { 0x0, 0x20, 0x40, 0x80, 0x40, 0x20 } }, + { '_', { 0x0, 0x2, 0x2, 0x2, 0x2, 0x2 } }, + { '`', { 0x0, 0x0, 0x0, 0xC0, 0x20, 0x0 } }, + { 'a', { 0x0, 0x4, 0x2A, 0x2A, 0x2A, 0x1E } }, + { 'b', { 0x0, 0xFE, 0x12, 0x22, 0x22, 0x1C } }, + { 'c', { 0x0, 0x1C, 0x22, 0x22, 0x22, 0x4 } }, + { 'd', { 0x0, 0x1C, 0x22, 0x22, 0x12, 0xFE } }, + { 'e', { 0x0, 0x1C, 0x2A, 0x2A, 0x2A, 0x18 } }, + { 'f', { 0x0, 0x10, 0x7E, 0x90, 0x80, 0x40 } }, + { 'g', { 0x0, 0x30, 0x4A, 0x4A, 0x4A, 0x7C } }, + { 'h', { 0x0, 0xFE, 0x10, 0x20, 0x20, 0x1E } }, + { 'i', { 0x0, 0x0, 0x22, 0xBE, 0x2, 0x0 } }, + { 'j', { 0x0, 0x4, 0x2, 0x22, 0xBC, 0x0 } }, + { 'k', { 0x0, 0x0, 0xFE, 0x8, 0x14, 0x22 } }, + { 'l', { 0x0, 0x0, 0x82, 0xFE, 0x2, 0x0 } }, + { 'm', { 0x0, 0x3E, 0x20, 0x18, 0x20, 0x1E } }, + { 'n', { 0x0, 0x3E, 0x10, 0x20, 0x20, 0x1E } }, + { 'o', { 0x0, 0x1C, 0x22, 0x22, 0x22, 0x1C } }, + { 'p', { 0x0, 0x3E, 0x28, 0x28, 0x28, 0x10 } }, + { 'q', { 0x0, 0x10, 0x28, 0x28, 0x18, 0x3E } }, + { 'r', { 0x0, 0x3E, 0x10, 0x20, 0x20, 0x10 } }, + { 's', { 0x0, 0x12, 0x2A, 0x2A, 0x2A, 0x4 } }, + { 't', { 0x0, 0x20, 0xFC, 0x22, 0x2, 0x4 } }, + { 'u', { 0x0, 0x3C, 0x2, 0x2, 0x4, 0x3E } }, + { 'v', { 0x0, 0x38, 0x4, 0x2, 0x4, 0x38 } }, + { 'w', { 0x0, 0x3C, 0x2, 0xC, 0x2, 0x3C } }, + { 'x', { 0x0, 0x22, 0x14, 0x8, 0x14, 0x22 } }, + { 'y', { 0x0, 0x30, 0xA, 0xA, 0xA, 0x3C } }, + { 'z', { 0x0, 0x22, 0x26, 0x2A, 0x32, 0x22 } }, + { '{', { 0x0, 0x0, 0x10, 0x6C, 0x82, 0x82 } }, + { '|', { 0x0, 0x0, 0x0, 0xFE, 0x0, 0x0 } }, + { '}', { 0x0, 0x82, 0x82, 0x6C, 0x10, 0x0 } }, + { '~', { 0x0, 0x20, 0x40, 0x20, 0x10, 0x20 } }, + + /* TODO + * Add more characters here. The 'ch' member is an int so theoretically, you could + * specify UTF-32 code points as the ch. But then you'd have to translate the UTF-8 + * (or whatever) input to imonlcd_string to UTF-32, which doesn't sound like much fun... + */ + + /* Marks the end of the array, but also serves as the character that + * unknown inputs are mapped to (essentially, a "space") + */ + { '\0' } +}; + +/** + * This is the definition for a "big" font, which is a font that simply takes up twice as many pixels + * as the normal font. We only use it for drawing numbers. + */ +typedef struct { + int ch; + unsigned short pixels[12]; +} imon_bigfont; + +/* TODO + * Some of these characters need a bit of tweaking... + */ +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' } +}; + +static void send_data(uint64_t value, int fd); +static void send_byte_data(unsigned char data[], int fd); +static void set_contrast(int contrast, int fd); +static void set_screen(unsigned char *columns, int fd); +static void draw_char(imon_font *font, char ch, int x, int y, unsigned char *columns); +static void draw_bigchar(imon_bigfont *font, int ch, int x, int y, unsigned char *columns); +static void draw_string(imon_font *font, char *string, int fd); + +/** + * Initialize the driver. + * \param drvthis Pointer to driver structure. + * \return Information of success (1) or failure (< 0). + */ +MODULE_EXPORT int imonlcd_init (Driver *drvthis) +{ + PrivateData *p = NULL; + + // Alocate, 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; + } + + char buf[256]; + p->imon_fd = -1; + p->width = 0; + p->height = 0; + p->cellwidth = LCD_DEFAULT_CELL_WIDTH; + p->cellheight = LCD_DEFAULT_CELL_HEIGHT; + + + /* 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 VFD kernel module?", drvthis->name); + report(RPT_ERR, "%s: More info in lcdproc/docs/README.imon", drvthis->name); + return -1; + } + + /* 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", &p->width, &p->height) != 2) + || (p->width <= 0) || (p->width > LCD_MAX_WIDTH) + || (p->height <= 0) || (p->height > LCD_MAX_HEIGHT)) { + report(RPT_WARNING, "%s: cannot read Size: %s; using default %s", + drvthis->name, buf, DEFAULT_SIZE); + sscanf(DEFAULT_SIZE , "%dx%d", &p->width, &p->height); + } + + /* Get the "on exit" setting so we know what to do when we shut the device down */ + strncpy(buf, drvthis->config_get_string(drvthis->name, "OnExit", 0, DEFAULT_ON_EXIT), sizeof(buf)); + buf[sizeof(buf)-1] = '\0'; + if ((sscanf(buf, "%d", &p->on_exit) != 1)) { + report(RPT_WARNING, "%s: cannot read OnExit: %s, using default %d", + drvthis->name, buf, DEFAULT_ON_EXIT); + sscanf(DEFAULT_ON_EXIT, "%d", &p->on_exit); + } + + /* Make sure the frame buffer is there... */ + report(RPT_INFO, "%s: allocating %d bytes for framebuffer.", drvthis->name, p->width * (p->height / p->cellheight)); + p->framebuf = (unsigned char *) malloc(p->width * (p->height / p->cellheight)); + if (p->framebuf == NULL) { + report(RPT_ERR, "%s: unable to allocate framebuffer", drvthis->name); + return -1; + } + memset(p->framebuf, 0x00, p->width * (p->height / p->cellheight)); + + /* Send the "initialize" commands to the screen */ + /* TODO + * I still need to figure out what most of these do, and what should be "configurable"... + */ + send_data(0x5000000000000040, p->imon_fd); + send_data(0x5100000000000000, p->imon_fd); + set_contrast(10, p->imon_fd); + send_data(0x0200000000000000, p->imon_fd); + send_data(0x0100000000000000, p->imon_fd); + send_data(0x10ffffff00000000, p->imon_fd); + send_data(0x110000ffffffffff, p->imon_fd); + send_data(0x1200000000000000, p->imon_fd); + + report(RPT_DEBUG, "%s: init() done", drvthis->name); + + return 1; +} + +/** + * 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; + + if (p != NULL) { + if (p->imon_fd >= 0) { + /* TODO + * This doesn't seem to work :-) + */ + 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) { + // blank the screen + report(RPT_INFO, "%s: closing, blanking screen.", drvthis->name); + send_data(0x5000000000000008, p->imon_fd); + send_data(0x5100000000000000, p->imon_fd); + } 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); + + time_t tt = time(NULL); + struct tm *t = localtime(&tt); + unsigned char data[] = { + 0x50, (unsigned char) t->tm_sec, (unsigned char) t->tm_min, + (unsigned char) t->tm_hour, (unsigned char) t->tm_mday, + (unsigned char) t->tm_mon, (unsigned char) t->tm_year, 0x80 }; + send_byte_data(data, p->imon_fd); + send_data(0x5100000000000000, p->imon_fd); + } + + 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 OEM (and others) LCD driver"); + 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, 0, p->width * (p->height / 8)); +} + + +/** + * 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; + + set_screen(p->framebuf, p->imon_fd); +} + + +/** + * 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->cellwidth, p->height/p->cellheight). + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + * \param c Character that gets written. + */ +MODULE_EXPORT void imonlcd_chr (Driver *drvthis, int x, int y, char ch) +{ + PrivateData *p = drvthis->private_data; + + y--; x--; + + if ((x < 0) || (y < 0) || (x >= (p->width / p->cellwidth)) || (y >= (p->height / p->cellheight))) + return; + + draw_char(font, ch, x * p->cellwidth, y * p->cellheight, p->framebuf); +} + + +/** + * 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. + * \return Information whether the icon is handled here or needs to be handled by the server core. + */ +MODULE_EXPORT int imonlcd_icon (Driver *drvthis, int x, int y, int icon) +{ + return -1; + /* TODO + * This needs to be implemented. + */ +/* + switch (icon) { + case ICON_BLOCK_FILLED: + imon_chr(drvthis, x, y, IMON_CHAR_BLOCK_FILLED); + break; + case ICON_HEART_OPEN: + imon_chr(drvthis, x, y, IMON_CHAR_BLOCK_EMPTY); + break; + case ICON_HEART_FILLED: + imon_chr(drvthis, x, y, IMON_CHAR_HEART); + break; + case ICON_ARROW_UP: + imon_chr(drvthis, x, y, IMON_CHAR_ARROW_UP); + break; + case ICON_ARROW_DOWN: + imon_chr(drvthis, x, y, IMON_CHAR_ARROW_DOWN); + break; + case ICON_ARROW_LEFT: + imon_chr(drvthis, x, y, IMON_CHAR_ARROW_LEFT); + break; + case ICON_ARROW_RIGHT: + imon_chr(drvthis, x, y, IMON_CHAR_ARROW_RIGHT); + break; + case ICON_STOP: + imon_chr(drvthis, x, y, IMON_CHAR_BLOCK_FILLED); + imon_chr(drvthis, x+1, y, ' '); + break; + case ICON_PAUSE: + imon_chr(drvthis, x, y, IMON_CHAR_PAUSE); + imon_chr(drvthis, x+1, y, ' '); + break; + case ICON_PLAY: + imon_chr(drvthis, x, y, IMON_CHAR_PLAY); + imon_chr(drvthis, x+1, y, ' '); + break; + case ICON_PLAYR: + imon_chr(drvthis, x, y, IMON_CHAR_RPLAY); + imon_chr(drvthi8, x+1, y, ' '); + break; + case ICON_FF: + imon_chr(drvthis, x, y, IMON_CHAR_PLAY); + imon_chr(drvthis, x+1, y, IMON_CHAR_PLAY); + break; + case ICON_FR: + imon_chr(drvthis, x, y, IMON_CHAR_RPLAY); + imon_chr(drvthis, x+1, y, IMON_CHAR_RPLAY); + break; + case ICON_NEXT: + imon_chr(drvthis, x, y, IMON_CHAR_PLAY); + imon_chr(drvthis, x+1, y, '|'); + break; + case ICON_PREV: + imon_chr(drvthis, x, y, '|'); + imon_chr(drvthis, x+1, y, IMON_CHAR_RPLAY); + break; + case ICON_REC: + imon_chr(drvthis, x, y, IMON_CHAR_RECORD); + imon_chr(drvthis, x+1, y, ' '); + break; + default: + return -1; + } + return 0; +*/ +} + + +/** + * 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; + + /* TODO + * This needs to be implemented. + */ + lib_vbar_static(drvthis, x, y, len, promille, options, p->cellheight, -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; + + // Pixels is the number of pixels we need to draw, horizontally, based on the passed-in promille. + int pixels = ((int) 2 * len * p->cellwidth) * promille / 2000; + + x--; y--; + x *= p->cellwidth; + + if ((x < 0) || (y < 0) || (y > (p->height / p->cellheight))) + return; + + for (; pixels >= 0; pixels--) { + + if (x > (p->width * p->cellwidth)) + return; + + p->framebuf[x + (y * 96)] = 0x3C; + x++; + } +} + +/** + * 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 point of the the Driver structure. + * \param the x-coordinate to display the character at. + * \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, and really it only works when your screen is 96 pixels wide and + // even then, it makes assumptions about the coordinates the client passes to us. However, + // it works for MythTV... and looks pretty cool, too :-) + x = 12 + (int)(((x - 1) * p->cellwidth) * 0.75); + + draw_bigchar(bigfont, (num >= 10 ? ':' : (num + '0')), x, 0, p->framebuf); +} + +/** + * 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: + * + * bit 0 : disc icon (0=off, 1='spin') + * 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=L+R, 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=AC1, 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) + */ +MODULE_EXPORT void imonlcd_output (Driver *drvthis, int state) +{ + PrivateData *p = drvthis->private_data; + unsigned char data[8] = {0}; + + // Set the control code for setting the icons + data[7] = 0x01; + + if ((state & IMON_OUTPUT_CD_MASK) != 0) { + /* TODO + * a) This doesn't seem to work, and + * b) The rest of the icons need to be implemented. + */ + switch(p->last_cd_state) { + case 0: + data[1] = 128 | 8; // top & bottom + p->last_cd_state = 1; + break; + case 1: + data[1] = 1 | 16; //top-right & bottom-left + p->last_cd_state = 2; + break; + case 2: + data[1] = 32 | 2; // right & left + p->last_cd_state = 3; + break; + default: + data[1] = 8 | 64; // top-left & bottom-right + p->last_cd_state = 0; + break; + } + } + + send_byte_data(data, p->imon_fd); +} + +/** + * 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/p->cellwidth; +} + + +/** + * 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/p->cellheight; +} + + +/** + * 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 data 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. + * + * \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 fd A file descriptor pointing to the /dev/lcd* file that we write to. + */ +static void send_data(uint64_t value, int fd) +{ + /* TODO + * In order to make big- and little-endian issues more clear, we should probably + * drop this method in favour of the send_byte_data method... + */ + + // Note: We do it like this so that we can be sure we work on big- and little- + // endian machines the same way. + unsigned char data[8]; + data[0] = (value & 0xFF00000000000000) >> (7 * 8); + data[1] = (value & 0x00FF000000000000) >> (6 * 8); + data[2] = (value & 0x0000FF0000000000) >> (5 * 8); + data[3] = (value & 0x000000FF00000000) >> (4 * 8); + data[4] = (value & 0x00000000FF000000) >> (3 * 8); + data[5] = (value & 0x0000000000FF0000) >> (2 * 8); + data[6] = (value & 0x000000000000FF00) >> (1 * 8); + data[7] = (value & 0x00000000000000FF); + + send_byte_data(data, fd); +} + +/** + * Sends data to the screen. + * + * \param data The 8 byte packet to send to the screen. + * \param fd A file descriptor pointing to the /dev/lcd* file that we write to. + */ +static void send_byte_data(unsigned char data[], int fd) +{ + write(fd, data, 8); +} + +/** + * Sets the contrast of the display. 0 is the lowest (and usually + * the best, in my opinion) and 40 is the highest. + * + * \param contrast The contrast to set the screen to. + * \param fd A file descriptor pointing to the /dev/lcd* file that we write to. + */ +static void set_contrast(int contrast, int fd) +{ + /* TODO + * This doesn't seem to work in all situations. + */ + if (contrast < 0) { + contrast = 0; + } else if (contrast > 40) { + contrast = 40; + } + + send_data(0x03FFFFFF00580A00L + (uint64_t)contrast, fd); +} + +/** + * Sets the pixels on the screen, using the specified "columns". + * Each column is eight pixels high (and represented by one byte) + * and the columns are filled from left to right. When the end + * of the screen is hit, the columns wrap to the next line. Each + * line is 96 pixels wide, so you need to pass an array of 192 + * bytes. + * + * \param columns The data for each column. + * \param fd A file descriptor pointing to the /dev/lcd* file that we write to. + */ +static void set_screen(unsigned char *columns, int fd) +{ + /* TODO + * This could be implemented as a single call to write() with all the data, + * but that would require corresponding changes to the lirc kernel module. + */ + int i; + uint64_t msb; + uint64_t data; + int byteno; + + i = 0; + for (msb = 0x20; msb <= 0x3b; msb++) { + data = 0; + for (byteno = 1; byteno < 8; byteno ++) { + data |= columns[i]; + data <<= 8; + i++; + } + data |= msb; + send_data(data, fd); + } +} + +/** + * Draws a "big" character -- that is, one that's twice as big as a normal character -- at + * the specified position on the screen. + */ +static void draw_bigchar(imon_bigfont *font, int ch, int x, int y, unsigned char *columns) +{ + imon_bigfont *defn = font; + int i; + + while (defn->ch != ch && defn->ch != '\0') { + defn++; + } + + for(i = 0; i < 12; i++) { + columns[x + i + (y * 12)] = (defn->pixels[i] & 0xFF00) >> 8; + } + for(i = 0; i < 12; i++) { + columns[x + i + (y * 12) + 96] = (defn->pixels[i] & 0x00FF); + } +} + +/** + * Draws a single character at the specified (x,y) coordinates of the given screen data. + */ +static void draw_char(imon_font *font, char ch, int x, int y, unsigned char *columns) +{ + imon_font *defn = font; + int i; + + while (defn->ch != ch && defn->ch != '\0') { + defn++; + } + + for(i = 0; i < 6; i++) { + columns[x + i + (y * 12)] = defn->pixels[i]; + } +} + +// EOF diff -Naur lcdproc-0.5.2.old/server/drivers/imonlcd.h lcdproc-0.5.2.new/server/drivers/imonlcd.h --- lcdproc-0.5.2.old/server/drivers/imonlcd.h 1970-01-01 00:00:00.000000000 +0000 +++ lcdproc-0.5.2.new/server/drivers/imonlcd.h 2007-09-10 09:12:25.000000000 +0000 @@ -0,0 +1,49 @@ +/** + * Driver for SoundGraph iMON OEM (and others) LCD Module + * + * In order to be able to use it, you have to install the lirc_imonlcd + * kernel module for LIRC (http://www.lirc.org) -- until that module is + * available in the main LIRC branch, you can get a patch for it from + * the same place you got this patch. + * + * Copyright (c) 2007, Dean Harding , but (heavily :p) + * on the work of Venky Raju. + * + * This source code is being released under the GPL. + * Please see the file COPYING in this package for details. + * + */ + +#ifndef IMONLCD_H +#define IMONLCD_H + +#include "lcd.h" + +MODULE_EXPORT int imonlcd_init (Driver *drvthis); +MODULE_EXPORT void imonlcd_close (Driver *drvthis); +MODULE_EXPORT int imonlcd_width (Driver *drvthis); +MODULE_EXPORT int imonlcd_height (Driver *drvthis); +MODULE_EXPORT int imonlcd_cellwidth (Driver *drvthis); +MODULE_EXPORT int imonlcd_cellheight (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); +MODULE_EXPORT int imonlcd_icon (Driver *drvthis, int x, int y, int icon); +MODULE_EXPORT const char *imonlcd_get_info (Driver *drvthis); +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_output (Driver *drvthis, int state); + +//MODULE_EXPORT int imonlcd_get_brightness(Driver *drvthis, int state); +//MODULE_EXPORT void imonlcd_set_brightness(Driver *drvthis, int state, int promille); + +/** + * These are not supported by the iMON LCD module + */ +//MODULE_EXPORT int imonlcd_get_free_chars (Driver *drvthis); +//MODULE_EXPORT void imonlcd_set_char (Driver *drvthis, int n, char *dat); +//MODULE_EXPORT void imonlcd_backlight(Driver *drvthis, int on); + +#endif