diff --git a/LCDd.conf b/LCDd.conf index 41aa8dd..94194b3 100644 --- a/LCDd.conf +++ b/LCDd.conf @@ -46,10 +46,11 @@ DriverPath=server/drivers/ # The following drivers are supported: # bayrad, CFontz, CFontzPacket, curses, CwLnx, ea65, EyeboxOne, g15, glcd, # glcdlib, glk, hd44780, icp_a106, imon, imonlcd,, IOWarrior, irman, joy, -# lb216, lcdm001, lcterm, linux_input, lirc, lis, MD8800, mdm166a, ms6931, mtc_s16209x, -# MtxOrb, mx5000, NoritakeVFD, picolcd,, pyramid, rawserial, sdeclcd, -# sed1330, sed1520, serialPOS, serialVFD, shuttleVFD, sli,, stv5730, svga, -# t6963, text, tyan, ula200, vlsys_m428, xosd +# lb216, lcdm001, lcterm, linux_input, lirc, lis, MD8800, mdm166a, ms6931, +# mtc_s16209x, MtxOrb, mx5000, NoritakeVFD, Olimex_MOD_LCD1x9, picolcd, +# pyramid, rawserial, sdeclcd, sed1330, sed1520, serialPOS, serialVFD, +# shuttleVFD, sli, stv5730, svga, t6963, text, tyan, ula200, vlsys_m428, +# xosd Driver=curses # Tells the driver to bind to the given interface. [default: 127.0.0.1] @@ -986,6 +987,13 @@ Reboot=no +## Olimex MOD-LCD1x9 driver ## +[Olimex_MOD_LCD1x9] + +# device file of the i2c controler +Device=/dev/i2c-0 + + ## Mini-box.com picoLCD (usblcd) driver ## [picolcd] diff --git a/acinclude.m4 b/acinclude.m4 index 31929bc..23efa4c 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -13,16 +13,17 @@ AC_ARG_ENABLE(drivers, [ icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,] [ joy,lb216,lcdm001,lcterm,linux_input,lirc,lis,MD8800,mdm166a,] [ ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,] - [ picolcd,pyramid,rawserial,sdeclcd,sed1330,sed1520,] - [ serialPOS,serialVFD,shuttleVFD,sli,stv5730,SureElec,] - [ svga,t6963,text,tyan,ula200,vlsys_m428,xosd] + [ Olimex_MOD_LCD1x9,picolcd,pyramid,rawserial,] + [ sdeclcd,sed1330,sed1520,serialPOS,serialVFD,] + [ shuttleVFD,sli,stv5730,SureElec,svga,t6963,text,] + [ tyan,ula200,vlsys_m428,xosd] [ ] [ 'all' compiles all drivers;] [ 'all,!xxx,!yyy' de-selects previously selected drivers], drivers="$enableval", drivers=[bayrad,CFontz,CFontzPacket,curses,CwLnx,glk,lb216,lcdm001,MtxOrb,pyramid,text]) -allDrivers=[bayrad,CFontz,CFontzPacket,curses,CwLnx,ea65,EyeboxOne,g15,glcd,glcdlib,glk,hd44780,i2500vfd,icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,joy,lb216,lcdm001,lcterm,linux_input,lirc,lis,MD8800,mdm166a,ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,picolcd,pyramid,sdeclcd,sed1330,sed1520,serialPOS,serialVFD,shuttleVFD,sli,stv5730,SureElec,svga,t6963,text,tyan,ula200,vlsys_m428,xosd,rawserial] +allDrivers=[bayrad,CFontz,CFontzPacket,curses,CwLnx,ea65,EyeboxOne,g15,glcd,glcdlib,glk,hd44780,i2500vfd,icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,joy,lb216,lcdm001,lcterm,linux_input,lirc,lis,MD8800,mdm166a,ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,Olimex_MOD_LCD1x9,picolcd,pyramid,sdeclcd,sed1330,sed1520,serialPOS,serialVFD,shuttleVFD,sli,stv5730,SureElec,svga,t6963,text,tyan,ula200,vlsys_m428,xosd,rawserial] if test "$debug" = yes; then allDrivers=["${allDrivers},debug"] fi @@ -404,6 +405,15 @@ dnl else DRIVERS="$DRIVERS NoritakeVFD${SO}" actdrivers=["$actdrivers NoritakeVFD"] ;; + Olimex_MOD_LCD1x9) + AC_CHECK_HEADERS([linux/i2c.h],[ + DRIVERS="$DRIVERS Olimex_MOD_LCD1x9${SO}" + actdrivers=["$actdrivers Olimex_MOD_LCD1x9"] + ],[ +dnl else + AC_MSG_WARN([The Olimex MOD-LCD1x9 driver needs linux/i2c.h]) + ]) + ;; rawserial) DRIVERS="$DRIVERS rawserial${SO}" actdrivers=["$actdrivers rawserial"] diff --git a/docs/LCDd.8.in b/docs/LCDd.8.in index 6028b91..34ea399 100644 --- a/docs/LCDd.8.in +++ b/docs/LCDd.8.in @@ -277,6 +277,9 @@ LCD display on the Logitech MX5000 keyboard .B NoritakeVFD Noritake VFD Device CU20045SCPB-T28A .TP +.B Olimex_MOD_LCD1x9 +Olimex MOD-LCD1x9 14 segment display +.TP .B rawserial Dumps the entire framebuffer to the serial port at a configurable rate. .TP diff --git a/docs/lcdproc-user/drivers.docbook b/docs/lcdproc-user/drivers.docbook index e9a83f7..b267438 100644 --- a/docs/lcdproc-user/drivers.docbook +++ b/docs/lcdproc-user/drivers.docbook @@ -40,6 +40,7 @@ well as the configuration of LCDd. &MtxOrb; &mx5000; &NoritakeVFD; +&Olimex_MOD_LCD1x9; &rawserial; &picolcd; &pylcd; diff --git a/docs/lcdproc-user/drivers/Makefile.am b/docs/lcdproc-user/drivers/Makefile.am index 2efa0a9..9b29d5f 100644 --- a/docs/lcdproc-user/drivers/Makefile.am +++ b/docs/lcdproc-user/drivers/Makefile.am @@ -32,6 +32,7 @@ EXTRA_DIST = bayrad.docbook \ mtxorb.docbook \ mx5000.docbook \ NoritakeVFD.docbook \ + Olimex_MOD_LCD1x9.docbook \ picolcd.docbook \ ppttrouble.docbook \ pylcd.docbook \ diff --git a/docs/lcdproc-user/drivers/Olimex_MOD_LCD1x9.docbook b/docs/lcdproc-user/drivers/Olimex_MOD_LCD1x9.docbook new file mode 100644 index 0000000..a575f10 --- /dev/null +++ b/docs/lcdproc-user/drivers/Olimex_MOD_LCD1x9.docbook @@ -0,0 +1,32 @@ + +The Olimex_MOD_LCD1x9 Driver + + +The Olimex_MOD_LCD1x9 driver supports the popular MOD-LCD1x9 14 segment +display on I2C lines. Currently this driver only supports Linux. + + + + +Configuration in LCDd.conf + + +[Olimex_MOD_LCD1x9] + + + + + Device = + DEVICE + + + Set the I2C device [default: /dev/i2c-0] + + + + + + + + + diff --git a/docs/lcdproc-user/lcdproc-user.docbook b/docs/lcdproc-user/lcdproc-user.docbook index b3ec38d..16435bb 100644 --- a/docs/lcdproc-user/lcdproc-user.docbook +++ b/docs/lcdproc-user/lcdproc-user.docbook @@ -47,6 +47,7 @@ + diff --git a/server/drivers/Makefile.am b/server/drivers/Makefile.am index 8c5507e..d507e02 100644 --- a/server/drivers/Makefile.am +++ b/server/drivers/Makefile.am @@ -23,7 +23,7 @@ AM_LDFLAGS = @LDSHARED@ lcdexecbindir = $(pkglibdir) lcdexecbin_PROGRAMS = @DRIVERS@ -EXTRA_PROGRAMS = bayrad CFontz CFontzPacket curses CwLnx debug ea65 EyeboxOne g15 glcd glcdlib glk hd44780 i2500vfd icp_a106 imon imonlcd IOWarrior irman irtrans joy lb216 lcdm001 lcterm linux_input lirc lis MD8800 mdm166a ms6931 mtc_s16209x MtxOrb mx5000 NoritakeVFD picolcd pyramid rawserial sdeclcd sed1330 sed1520 serialPOS serialVFD shuttleVFD sli stv5730 SureElec svga t6963 text tyan ula200 vlsys_m428 xosd +EXTRA_PROGRAMS = bayrad CFontz CFontzPacket curses CwLnx debug ea65 EyeboxOne g15 glcd glcdlib glk hd44780 i2500vfd icp_a106 imon imonlcd IOWarrior irman irtrans joy lb216 lcdm001 lcterm linux_input lirc lis MD8800 mdm166a ms6931 mtc_s16209x MtxOrb mx5000 NoritakeVFD Olimex_MOD_LCD1x9 picolcd pyramid rawserial sdeclcd sed1330 sed1520 serialPOS serialVFD shuttleVFD sli stv5730 SureElec svga t6963 text tyan ula200 vlsys_m428 xosd noinst_LIBRARIES = libLCD.a libbignum.a g15_CFLAGS = @LIBUSB_CFLAGS@ $(AM_CFLAGS) @@ -117,6 +117,7 @@ mtc_s16209x_SOURCES = lcd.h lcd_lib.h mtc_s16209x.c mtc_s16209x.h report.h MtxOrb_SOURCES = lcd.h lcd_lib.h MtxOrb.c MtxOrb.h report.h adv_bignum.h mx5000_SOURCES = lcd.h mx5000.c mx5000.h report.h NoritakeVFD_SOURCES = lcd.h lcd_lib.h NoritakeVFD.c NoritakeVFD.h report.h adv_bignum.h +Olimex_MOD_LCD1x9_SOURCES = lcd.h report.h i2c.h i2c.c Olimex_MOD_LCD1x9.h Olimex_MOD_LCD1x9.c Olimex_MOD_LCD1x9_font.h rawserial_SOURCES = lcd.h rawserial.c rawserial.h picolcd_SOURCES = lcd.h picolcd.h picolcd.c report.h pyramid_SOURCES = lcd.h pylcd.c pylcd.h diff --git a/server/drivers/Olimex_MOD_LCD1x9.c b/server/drivers/Olimex_MOD_LCD1x9.c new file mode 100644 index 0000000..13a8371 --- /dev/null +++ b/server/drivers/Olimex_MOD_LCD1x9.c @@ -0,0 +1,227 @@ +/** \file server/drivers/Olimex_MOD_LCD1x9.c + * LCDd \c Olimex_MOD_LCD1x9 driver for MOD-LCD1x9 from Olimex. + * This display uses a PCF857DU style controller. + */ + +/* Copyright (C) 2015 Harald Geyer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "lcd.h" +#include "report.h" + +#include +#include +#include +#include +#include + +#include "i2c.h" +#include "Olimex_MOD_LCD1x9_font.h" + +#define BUS_ADDRESS 0x38 +#define LEN_INIT_SEQ 24 + +/** private data for the \c Olimex_MOD_LCD1x9 driver */ +typedef struct olimex1x9_private_data { + I2CHandle *dev; /**< handle of the i2c device */ + uint16_t buf[11]; /**< header + frame buffer */ +} PrivateData; + +/* Vars for the server core */ +MODULE_EXPORT char *api_version = API_VERSION; +MODULE_EXPORT int stay_in_foreground = 0; +MODULE_EXPORT int supports_multiple = 1; +MODULE_EXPORT char *symbol_prefix = "olimex1x9_"; + +/** + * Initialize the driver. + * \param drvthis Pointer to driver structure. + * \retval 0 Success. + * \retval <0 Error. + */ +MODULE_EXPORT int +olimex1x9_init (Driver *drvthis) +{ + PrivateData *p; + const char *configvalue; + char buffer[LEN_INIT_SEQ]; + uint8_t *preamble; + int i; + + /* Allocate and store private data */ + p = (PrivateData *) malloc(sizeof(PrivateData)); + if (p == NULL) + return -1; + if (drvthis->store_private_ptr(drvthis, p)) + return -1; + + configvalue = drvthis->config_get_string(drvthis->name, "Device", 0, I2C_DEFAULT_DEVICE); + p->dev = i2c_open(configvalue, BUS_ADDRESS); + if (!p->dev) { + report(RPT_ERR, "open i2c device '%s' failed: %s", configvalue, strerror(errno)); + return(-1); + } + + buffer[0] = 0xC8; /* Mode register */ + buffer[1] = 0xF0; /* Blink register */ + buffer[2] = 0xE0; /* Device select register */ + buffer[3] = 0x00; /* Point register */ + for (i = 4; i < LEN_INIT_SEQ; ++i) + buffer[i] = 0xFF; + + if (i2c_write(p->dev, buffer, LEN_INIT_SEQ) < 0) { + report(RPT_ERR, "I2C: %s: sending of initialization data failed: %s", configvalue, strerror(errno)); + return (-1); + } + + preamble = (uint8_t *) p->buf; + preamble[0] = 0xE0; /* Device select register */ + preamble[1] = 0x00; /* Point register */ + + report(RPT_DEBUG, "%s: init() done", drvthis->name); + + return 0; +} + + +/** + * Close the driver (do necessary clean-up). + * \param drvthis Pointer to driver structure. + */ +MODULE_EXPORT void +olimex1x9_close (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + if (p != NULL) { + i2c_close(p->dev); + free(p); + } + drvthis->store_private_ptr(drvthis, NULL); +} + + +/** + * Return the display width in characters. + * \param drvthis Pointer to driver structure. + * \return Number of characters the display is wide. + */ +MODULE_EXPORT int +olimex1x9_width (Driver *drvthis) +{ + return 9; +} + + +/** + * Return the display height in characters. + * \param drvthis Pointer to driver structure. + * \return Number of characters the display is high. + */ +MODULE_EXPORT int +olimex1x9_height (Driver *drvthis) +{ + return 1; +} + + +/** + * Clear the screen. + * \param drvthis Pointer to driver structure. + */ +MODULE_EXPORT void +olimex1x9_clear (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + /* Don't overwrite the preamble part of the buffer */ + memset(&p->buf[1], 0, sizeof(p->buf) - sizeof(p->buf[0])); +} + + +/** + * Flush data on screen to the display. + * \param drvthis Pointer to driver structure. + */ +MODULE_EXPORT void +olimex1x9_flush (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + i2c_write(p->dev, p->buf, sizeof(p->buf)); +} + + +/** + * Print a string on the screen at position (x,y). + * The upper-left corner is (1,1), the lower-right corner is (9, 1). + * \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 +olimex1x9_string (Driver *drvthis, int x, int y, const unsigned char string[]) +{ + PrivateData *p = drvthis->private_data; + int pos = 10 - x; /* The left side is on the upper end of the buffer */ + int count = 0; + + while (string[count]) { + switch (string[count]) { + case '\b': /* Allow composition of characters */ + ++pos; + break; + case ':': /* We can't display a proper ':' */ + case '.': /* Use the dot between characters if possible */ + if (pos < 9 && + !(p->buf[pos+1] & htons(olimex1x9_font['.']))) + ++pos; + /* fall through */ + default: + if (pos >= 1 && pos <= 9) /* no buffer overflow */ + p->buf[pos] |= + htons(olimex1x9_font[string[count]]); + --pos; + } + ++count; + } +} + + +/** + * Print a character on the screen at position (x,y). + * The upper-left corner is (1,1), the lower-right corner is (9, 1). + * \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 +olimex1x9_chr (Driver *drvthis, int x, int y, unsigned char c) +{ + PrivateData *p = drvthis->private_data; + + if (x < 1 || x > 9) + return; + + p->buf[10-x] |= olimex1x9_font[c]; +} diff --git a/server/drivers/Olimex_MOD_LCD1x9.h b/server/drivers/Olimex_MOD_LCD1x9.h new file mode 100644 index 0000000..87d5c66 --- /dev/null +++ b/server/drivers/Olimex_MOD_LCD1x9.h @@ -0,0 +1,13 @@ +#ifndef OLIMEX_LCD1x9_H +#define OLIMEX_LCD1x9_H + +MODULE_EXPORT int olimex1x9_init (Driver *drvthis); +MODULE_EXPORT void olimex1x9_close (Driver *drvthis); +MODULE_EXPORT int olimex1x9_width (Driver *drvthis); +MODULE_EXPORT int olimex1x9_height (Driver *drvthis); +MODULE_EXPORT void olimex1x9_clear (Driver *drvthis); +MODULE_EXPORT void olimex1x9_flush (Driver *drvthis); +MODULE_EXPORT void olimex1x9_string (Driver *drvthis, int x, int y, const char string[]); +MODULE_EXPORT void olimex1x9_chr (Driver *drvthis, int x, int y, char c); + +#endif diff --git a/server/drivers/Olimex_MOD_LCD1x9_font.h b/server/drivers/Olimex_MOD_LCD1x9_font.h new file mode 100644 index 0000000..aec1739 --- /dev/null +++ b/server/drivers/Olimex_MOD_LCD1x9_font.h @@ -0,0 +1,131 @@ +#ifndef OLIMEX_LCD1x9_FONT_H +#define OLIMEX_LCD1x9_FONT_H + +uint16_t olimex1x9_font[256] = { + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, /* ' ' */ + 0x9800, /* '!' */ + 0x0101, /* '"' */ + 0x5054, /* '#' -- use this for a degree sign */ + 0x0000, /* '$' */ + 0x0000, /* '%' */ + 0x0000, /* '&' */ + 0x0100, /* ''' */ + 0x0096, /* '(' */ + 0x9090, /* ')' */ + 0x6761, /* '*' */ + 0x4640, /* '+' */ + 0x0020, /* ',' */ + 0x4040, /* '-' */ + 0x0800, /* '.' */ + 0x0120, /* '/' */ + 0x9096, /* '0' */ + 0x9000, /* '1' */ + 0x50d2, /* '2' */ + 0xd0d0, /* '3' */ + 0xd044, /* '4' */ + 0xc0d4, /* '5' */ + 0xc0d6, /* '6' */ + 0x9010, /* '7' */ + 0xd0d6, /* '8' */ + 0xd0d4, /* '9' */ + 0x0800, /* ':' same as '.' */ + 0x0000, /* ';' */ + 0x2100, /* '<' */ + 0x0000, /* '=' */ + 0x0021, /* '>' */ + 0x0000, /* '?' */ + 0xffff, /* '@' */ + 0xd056, /* 'A' */ + 0x21d6, /* 'B' */ + 0x0096, /* 'C' */ + 0x0027, /* 'D' */ + 0x00d6, /* 'E' */ + 0x4056, /* 'F' */ + 0xc0d6, /* 'G' */ + 0xd046, /* 'H' */ + 0x0688, /* 'I' */ + 0x9080, /* 'J' */ + 0x2146, /* 'K' */ + 0x0086, /* 'L' */ + 0x9107, /* 'M' */ + 0xb007, /* 'N' */ + 0x9096, /* 'O' */ + 0x5056, /* 'P' */ + 0xb096, /* 'Q' */ + 0x7056, /* 'R' */ + 0xc0d4, /* 'S' */ + 0x0610, /* 'T' */ + 0x9086, /* 'U' */ + 0x0126, /* 'V' */ + 0xb026, /* 'W' */ + 0x2121, /* 'X' */ + 0xd0c4, /* 'Y' */ + 0x01b0, /* 'Z' */ + 0x0096, /* '[' */ + 0x2001, /* '\' */ + 0x9090, /* ']' */ + 0x0010, /* '^' */ + 0x0080, /* '_' */ + 0x0400, /* '`' */ + 0x02c2, /* 'a' */ + 0xc0c6, /* 'b' */ + 0x00c2, /* 'c' */ + 0xd0c2, /* 'd' */ + 0x00e2, /* 'e' */ + 0x0056, /* 'f' */ + 0xe080, /* 'g' */ + 0xc046, /* 'h' */ + 0x8000, /* 'i' */ + 0x9080, /* 'j' */ + 0x6046, /* 'k' */ + 0x0026, /* 'l' */ + 0xc242, /* 'm' */ + 0xc042, /* 'n' */ + 0xc0c2, /* 'o' */ + 0x5056, /* 'p' */ + 0xd054, /* 'q' */ + 0x0042, /* 'r' */ + 0x6080, /* 's' */ + 0x00c6, /* 't' */ + 0x8082, /* 'u' */ + 0x0022, /* 'v' */ + 0xa022, /* 'w' */ + 0x2121, /* 'x' */ + 0xa080, /* 'y' */ + 0x00e0, /* 'z' */ + 0x0000 +}; + +#endif