Index: LCDd.conf =================================================================== RCS file: /cvsroot/lcdproc/lcdproc/LCDd.conf,v retrieving revision 1.131 diff -u -r1.131 LCDd.conf --- LCDd.conf 3 Mar 2009 20:17:28 -0000 1.131 +++ LCDd.conf 18 Mar 2009 04:28:57 -0000 @@ -45,12 +45,12 @@ # # 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, # xosd -Driver=curses +Driver=imonlcd # Tells the driver to bind to the given interface Bind=127.0.0.1 @@ -1063,5 +1063,21 @@ # X font to use, in XLFD format, as given by "xfontsel" Font=-*-terminus-*-r-*-*-*-320-*-*-*-*-* +## SoundMon iMon LCD +[imonlcd] +# Specify which iMon protocol should be used [default: 0=15c2:ffdc device; legal: 1=15c2:0038 device] +Protocol=0 +# Set the exit behavior [default: 1=show the big clock; legal: 0=leave shutdown message, 2=blank device] +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: 1=on; legal: 0=off] +#Backlight=1 +# Set the disc mode [default: 0=spin the "slim" disc - two disc segments; legal: 1=their complement spinning] +#DiscMode=0 # EOF Index: acinclude.m4 =================================================================== RCS file: /cvsroot/lcdproc/lcdproc/acinclude.m4,v retrieving revision 1.99 diff -u -r1.99 acinclude.m4 --- acinclude.m4 26 Oct 2008 21:33:09 -0000 1.99 +++ acinclude.m4 18 Mar 2009 04:28:58 -0000 @@ -9,7 +9,7 @@ [ 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 @@ 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,14 @@ DRIVERS="$DRIVERS imon${SO}" actdrivers=["$actdrivers imon"] ;; + imonlcd) + DRIVERS="$DRIVERS imonlcd${SO}" + actdrivers=["$actdrivers imonlcd"] + ;; + imonlcd) + DRIVERS="$DRIVERS imonlcd${SO}" + actdrivers=["$actdrivers imonlcd"] + ;; IOWarrior) if test "$enable_libusb" = yes ; then DRIVERS="$DRIVERS IOWarrior${SO}" Index: docs/LCDd.8.in =================================================================== RCS file: /cvsroot/lcdproc/lcdproc/docs/LCDd.8.in,v retrieving revision 1.23 diff -u -r1.23 LCDd.8.in --- docs/LCDd.8.in 26 Feb 2009 19:55:38 -0000 1.23 +++ docs/LCDd.8.in 18 Mar 2009 04:28:59 -0000 @@ -183,6 +183,9 @@ .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. Index: docs/lcdproc-user/drivers.docbook =================================================================== RCS file: /cvsroot/lcdproc/lcdproc/docs/lcdproc-user/drivers.docbook,v retrieving revision 1.15 diff -u -r1.15 drivers.docbook --- docs/lcdproc-user/drivers.docbook 26 Oct 2008 21:33:10 -0000 1.15 +++ docs/lcdproc-user/drivers.docbook 18 Mar 2009 04:28:59 -0000 @@ -21,6 +21,7 @@ &hd44780; &icp_a106; &imon; +&imonlcd; &IOWarrior; &irman; &irtrans; Index: docs/lcdproc-user/lcdproc-user.docbook =================================================================== RCS file: /cvsroot/lcdproc/lcdproc/docs/lcdproc-user/lcdproc-user.docbook,v retrieving revision 1.18 diff -u -r1.18 lcdproc-user.docbook --- docs/lcdproc-user/lcdproc-user.docbook 26 Oct 2008 21:33:10 -0000 1.18 +++ docs/lcdproc-user/lcdproc-user.docbook 18 Mar 2009 04:28:59 -0000 @@ -28,6 +28,7 @@ + Index: docs/lcdproc-user/drivers/imonlcd.docbook =================================================================== RCS file: docs/lcdproc-user/drivers/imonlcd.docbook diff -N docs/lcdproc-user/drivers/imonlcd.docbook --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ docs/lcdproc-user/drivers/imonlcd.docbook 18 Mar 2009 04:28:59 -0000 @@ -0,0 +1,117 @@ + +The imonlcd Driver + + +General + + +This section talks about using LCDproc with ... + + + +Empty paragraph + + + +In order to be able to use it, you have to get and install one of +the following Linux kernel modules: + + + + standalone iMON VFD driver from + + + + + the iMON module included with LIRC ver. 0.7.1 or newer + from the LIRC project + + + + + + + + + +Configuration in LCDd.conf + + +[imonlcd] + + + + + 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. + + + + + + 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. + + + + + + OnExit = + ONEXIT + + + Put description, possible and default values here + + + + + + Contrast = + CONTRAST + + + Put description, possible and default values here + + + + + + Backlight = + BACKLIGHT + + + Put description, possible and default values here + + + + + + DiscMode = + DISCMODE + + + Put description, possible and default values here + + + + + + + + + + Index: server/drivers/Makefile.am =================================================================== RCS file: /cvsroot/lcdproc/lcdproc/server/drivers/Makefile.am,v retrieving revision 1.83 diff -u -r1.83 Makefile.am --- server/drivers/Makefile.am 21 Dec 2008 11:17:39 -0000 1.83 +++ server/drivers/Makefile.am 18 Mar 2009 04:28:59 -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 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_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 @@ 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 Index: server/drivers/imonlcd.c =================================================================== RCS file: server/drivers/imonlcd.c diff -N server/drivers/imonlcd.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ server/drivers/imonlcd.c 18 Mar 2009 04:29:00 -0000 @@ -0,0 +1,1452 @@ +/** \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 + * + * 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) 2009, Jonathan Kyler + * 2004, Venky Raju + * 2007, Christian Leuschen + * 2007, Dean Harding + * 2009, Eric Pooch < epooch (at) cox (dot) net> + * + * + * 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 +#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 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 // default: turn backlight on +#define DEFAULT_DISCMODE 0 // default: spin the "slim" disc + +#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 + +#define DEFAULT_PROTOCOL 0 // 0 = protocol for 15c2:ffdc device, 1 = protocol for 15c2:0038 device + +#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_"; + +// Our private data +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 + int discMode; // 0 = two disc-segments spinning as default, + // 1 = their complement spinning + + /* store commands appropriate for the version of the iMON LCD */ + int protocol; // 0 = protocol for 15c2:ffdc device, 1 = protocol for 15c2:0038 device + uint64_t command_display; + uint64_t command_shutdown; + uint64_t command_display_on; + uint64_t command_clear_alarm; + + /* + * 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; + int lastPrivateIconState; // remind the last state for setting the icons +} 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) + +/* + * 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 6 col x 8 rows 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[LCD_DEFAULT_CELL_WIDTH]; +} 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, 0x0, 0xFE, 0x82, 0x0, 0x0 } }, + { '\\', { 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 } }, +/* + { 'Ö', { 0x0, 0x1C, 0xA2, 0x22, 0xA2, 0x1C } }, + { 'Ä', { 0x0, 0x04, 0xAA, 0x2A, 0xAA, 0x1E } }, + { 'Ü', { 0x0, 0x3C, 0x82, 0x02, 0x84, 0x3E } }, + { 'ö', { 0x0, 0x1C, 0xA2, 0x22, 0xA2, 0x1C } }, + { 'ä', { 0x0, 0x04, 0xAA, 0x2A, 0xAA, 0x1E } }, + { 'ü', { 0x0, 0x3C, 0x82, 0x02, 0x84, 0x3E } }, + { 'ß', { 0x0, 0x7E, 0x80, 0xA8, 0xA8, 0x50 } }, +*/ + /* 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', { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } } +}; + +/** + * 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 { + 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', { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} } +}; + +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; + + // 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; + } + + char buf[256]; + + int graph_width, graph_height; // width and height of screen, in pixels + int tmp; + + 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); + + /* TODO: check if this is applicapable for the imonlcd driver as well */ + /* 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 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; +} + + + +static void imonlcd_display_init(Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + /* Send the "initialize" commands to the screen. */ + + 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 ); + send_command_data( COMMANDS_SET_LINES0, p ); // clear the progress-bars + send_command_data( COMMANDS_SET_LINES1, p ); // on top and bottom of the + send_command_data( COMMANDS_SET_LINES2, p ); // display +} + + + +/** + * 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) { + 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) + // TODO: Why does the backlight turn on again at reboot and/or shutdown + // just when the computer turns it's power off / reboots. + // Is it just my bios sending a reset to all USB-devices, is it + // the USB-kernel-code that's sending the reset?! + // Maybe gets solved with setting the alarm!? + 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); + + time_t tt = time(NULL); + struct tm *t = localtime(&tt); + uint64_t data; + + //data = ((uint64_t)0x50 << 56); + 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 version : 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. + */ +MODULE_EXPORT void imonlcd_chr (Driver *drvthis, int x, int y, char ch) +{ + PrivateData *p = drvthis->private_data; + + 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; + + imon_font *defn = font; + + /* Get the requested character from the font after adjusting + for the font's lack of ASCII control characters. */ + int charnum = ((int)ch -32); + + if (charnum > 127 || charnum < 0) + charnum = 0; + + defn += charnum; + if (defn->ch != ch ) { + report(RPT_ERR, "%s: unable to find character %c in font (found:%c).", drvthis->name, ch, defn->ch); + } + + /* Copy the pixels into the frame buffer. */ + memcpy(&p->framebuf[x + y], &defn->pixels[0], p->cellwidth/*sizeof(defn->ch)*/); +} + +/** + * 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; + + if ((x < 1) || (y < 1) || (x > p->width) || (y > p->height)) + return; + + // Pixels is the number of pixels we need to draw, vertically, based on the passed-in promille. + int pixels = (int) ( (double)( ( 2 * len * p->cellheight ) * ( (double)promille / 2000 ) ) ); + + x--; y--; + /* Convert x from characters to pixels. */ + x *= p->cellwidth; + + int j, k; + unsigned char barChar; + + for ( j = 0; j < len; j++ ) + { + k = 0; + barChar = 0; + for ( ; pixels >0 && k < 8; pixels-- ) + { + barChar = barChar | (1 << k); + k++; + } + p->framebuf[x+1 + ((y-j) * p->bytesperline)] = barChar; + p->framebuf[x+2 + ((y-j) * p->bytesperline)] = barChar; + p->framebuf[x+3 + ((y-j) * p->bytesperline)] = barChar; + p->framebuf[x+4 + ((y-j) * p->bytesperline)] = barChar; + p->framebuf[x+5 + ((y-j) * p->bytesperline)] = barChar; + + } +} + + +/** + * 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; + + if ((x < 1) || (y < 1) || (x > p->width) || (y > p->height)) + return; + + // Pixels is the number of pixels we need to draw, horizontally, based on the passed-in promille. + int pixels = (int) ( (double)( ( 2 * len * p->cellwidth ) * ( (double)promille / 2000 ) ) ); + + x--; y--; + /* Convert x from characters to pixels. */ + x *= p->cellwidth; + + for (; pixels >= 0; pixels--) + { + p->framebuf[x + (y * p->bytesperline)] = 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 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 :-) + // TODO: Check the number flashing with the colon with mythtv + 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: + * + * 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=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=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) + */ + +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 ) + { + int topProgress = ( state & 63 ); // extract the bar-values + int topLine = ( state & (63<<6) ) >> 6; // for each bar separately + 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 ); + + state = p->lastPrivateIconState; // continue and set all other icons as before + } + + // 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 ) + icon |= ( (uint64_t)(255 - 128 - 8) << 40); // all on except top & bottom + else + icon |= ( (uint64_t)(128 | 8) << 40); // top & bottom on + break; + case 1: + p->last_cd_state = 2; + if ( p->discMode == 1 ) + icon |= ( (uint64_t)(255 - 16 - 1) << 40); //all on except top-right & bottom-left + else + icon |= ( (uint64_t)(1 | 16) << 40); // top-right & bottom-left on + break; + case 2: + p->last_cd_state = 3; + if ( p->discMode == 1 ) + icon |= ( (uint64_t)(255 - 32 - 2) << 40); // all on except right & left + else + icon |= ( (uint64_t)(32 | 2) << 40); // right & left on + break; + default: + p->last_cd_state = 0; + if ( p->discMode == 1 ) + icon |= ( (uint64_t)(255 - 64 - 4) << 40); // all on except top-left & bottom-right + else + icon |= ( (uint64_t)(4 | 64) << 40); // top-left & bottom-right on + 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 ) +{ + /*if ((commandData & COMMAND_MASK) == (COMMANDS_DISPLAY & COMMAND_MASK)) { + printf("%s: sending command: %lX\n", "imonlcd", commandData); + }*/ + + 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 + * \param ch + * \param x - horizontal position + * \param y - vertical poisition + * \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; + + while (defn->ch != ch && defn->ch != '\0') { + defn++; + } + + int colBorder = 12; // correction for the number flashing with the colon running "lcdproc K" + if ( ch == ':' ) // TODO: Please check anybody with mythtv + 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); + } +} + + +/* + * TODO: Check if either setLineLength or setBuiltinProgressBars could be + * removed as the former is only a wrapper to the latter. + */ +/** + * 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 + * \param botLine + * \param topProgress + * \param botProgress + * \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 + ); +} + +/* TODO: Add parameter descriptions */ +/** + * 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 + * \param botLine + * \param topProgress + * \param botProgress + * \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; + + data = ( (uint64_t) topProgress ) << 8 * 4; + data |= (uint64_t) topLine & 0x00000000FFFFFFFFLL; + data &= 0x00FFFFFFFFFFFFFFLL; + send_command_data( COMMANDS_SET_LINES0 | data, p ); + + 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 ); + + 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 + Index: server/drivers/imonlcd.h =================================================================== RCS file: server/drivers/imonlcd.h diff -N server/drivers/imonlcd.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ server/drivers/imonlcd.h 18 Mar 2009 04:29:00 -0000 @@ -0,0 +1,81 @@ +/** + * 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 + * + * 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) 2009, Jonathan Kyler + * 2004, Venky Raju + * 2007, Christian Leuschen + * 2007, Dean Harding + * 2009, Eric Pooch < epooch (at) cox (dot) net> + * + * + * 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" + +/* 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 +