diff --git a/ChangeLog b/ChangeLog
index c789fef..262e209 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -17,7 +17,8 @@ v0.5dev (ongoing development)
* lcdproc client: Add option to turn off title on OldTime screen
+ glcd driver: Connection type 'x11' that draws to a X window (S. Meharg)
+ glcd driver: 'picolcdgfx' for picoLCD 256x64 from Mini-Box.com (S. Meharg)
- * picolcd: Improvements to IR processing (M. Jones).
+ * picolcd: Improvements to IR processing (M. Jones)
+ + hd44780: Added 'spi' connection type (S. Dawson)
v0.5.6
- Remove deprecated CFontz633 driver. Use CFontzPacket with Model=633 instead!
diff --git a/LCDd.conf b/LCDd.conf
index 896198a..20ca8ac 100644
--- a/LCDd.conf
+++ b/LCDd.conf
@@ -538,7 +538,7 @@ ConnectionType=4bit
# For I2C connections this sets the slave address (usually 0x20).
Port=0x378
-# Device of the serial or I2C interface [default: /dev/lcd]
+# Device of the serial, I2C, or SPI interface [default: /dev/lcd]
Device=/dev/ttyS0
# Bitrate of the serial port (0 for interface default)
diff --git a/acinclude.m4 b/acinclude.m4
index ea8b99a..7317615 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -232,6 +232,9 @@ dnl else
HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-i2c.o"
HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-piplate.o"
fi
+ if test "$x_ac_have_spi" = yes; then
+ HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-spi.o"
+ fi
dnl The hd4470-rpi driver only works on a Raspberry Pi,
dnl which is an ARM platform. Require people to compile on
dnl (or for) ARM to get it.
diff --git a/configure.ac b/configure.ac
index abd5099..7c053d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -167,6 +167,12 @@ if test "$x_ac_have_i2c" = yes; then
AC_DEFINE(HAVE_I2C,[1],[Define to 1 if you have the i2c headers])
fi
+x_ac_have_spi=no
+AC_CHECK_HEADERS([linux/spi/spidev.h], [x_ac_have_spi=yes])
+if test "$x_ac_have_spi" = yes; then
+ AC_DEFINE(HAVE_SPI,[1],[Define to 1 if you have the spi headers])
+fi
+
dnl Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_STDC
diff --git a/docs/LCDd.8.in b/docs/LCDd.8.in
index 0420be7..dd36610 100644
--- a/docs/LCDd.8.in
+++ b/docs/LCDd.8.in
@@ -182,6 +182,9 @@ USS-720 USB-to-IEEE 1284 Bridge (Belkin F5U002 USB Parallel Printer Adapters)
.B i2c
LCD in 4-bit mode driven by PCF8574(A) / PCA9554(A), connected via I2C bus
.TP
+.B spi
+LCD with KS0073 or equivalent in serial mode, connected via SPI bus
+.TP
.B ftdi
USB connection via a FTDI FT2232D chip in bitbang mode
.TP
diff --git a/docs/lcdproc-user/drivers/hd44780.docbook b/docs/lcdproc-user/drivers/hd44780.docbook
index 881cf6a..15927fc 100644
--- a/docs/lcdproc-user/drivers/hd44780.docbook
+++ b/docs/lcdproc-user/drivers/hd44780.docbook
@@ -37,7 +37,7 @@ various special features.
The following table lists the available connection types, sorted by the kind
-of connection (parallel port, serial port, USB, I2C or others).
+of connection (parallel port, serial port, USB, I2C, SPI or others).
@@ -155,6 +155,14 @@ of connection (parallel port, serial port, USB, I2C or others).
piplate
Adafruit RGB Positive 16x2 LCD+Keypad for Raspberry Pi
+
+
+ SPI (Serial Peripheral Interface):
+
+
+ spi
+ Display using a KS0073 or similar in serial mode accessed via Linux SPI device
+
Other connection types:
@@ -1757,6 +1765,27 @@ that. The BL output below should be connected to the BL input in the
+
+spi
+
+
+This connection type drives a LCD in serial mode (supported on Hitachi HD66712,
+Samsung KS0073 and KS0074 (and clones) controllers) connected to some Linux
+SPI device.
+
+
+This connection type is currently only supported on Linux. It is strongly
+recommended to use a SPI implementation with hardware support, e.g. on the
+Raspberry Pi.
+
+
+As the SPI communication to the display cannot drive a backlight switch, this
+connection type features a BacklightDevice option
+that can use a GPIO pin exposed via sysfs (see eLinux GPIO).
+
+
+
+
FTDI FT2232D USB chip "ftdi"
@@ -3122,8 +3151,8 @@ This can be done by specifying or by inclu
4bit |
8bit |
- winamp |
serialLpt |
+ winamp |
picanlcd |
lcdserializer |
los-panel |
@@ -3141,6 +3170,7 @@ This can be done by specifying or by inclu
ftdi |
i2c |
piplate |
+ spi |
ethlcd |
raspberrypi
}
diff --git a/server/drivers/Makefile.am b/server/drivers/Makefile.am
index d998ba2..534608c 100644
--- a/server/drivers/Makefile.am
+++ b/server/drivers/Makefile.am
@@ -95,7 +95,7 @@ EXTRA_glcd_SOURCES = glcd-t6963.c t6963_low.c t6963_low.h glcd-png.c glcd-serdis
glcdlib_SOURCES = lcd.h lcd_lib.h glcdlib.h glcdlib.c report.h
glk_SOURCES = lcd.h glk.c glk.h glkproto.c glkproto.h report.h
hd44780_SOURCES = lcd.h lcd_lib.h hd44780.h hd44780.c hd44780-drivers.h hd44780-low.h hd44780-charmap.h report.h adv_bignum.h
-EXTRA_hd44780_SOURCES = port.h lpt-port.h timing.h lcd_sem.c lcd_sem.h hd44780-4bit.c hd44780-4bit.h hd44780-ext8bit.c hd44780-ext8bit.h hd44780-serialLpt.c hd44780-serialLpt.h hd44780-serial.c hd44780-serial.h hd44780-winamp.c hd44780-winamp.h hd44780-bwct-usb.c hd44780-bwct-usb.h hd44780-lcd2usb.c hd44780-lcd2usb.h hd44780-usbtiny.c hd44780-usbtiny.h hd44780-lis2.c hd44780-lis2.h hd44780-i2c.c hd44780-i2c.h hd44780-ftdi.c hd44780-ftdi.h hd44780-ethlcd.c hd44780-ethlcd.h hd44780-uss720.c hd44780-uss720.h hd44780-usblcd.c hd44780-usblcd.h hd44780-usb4all.c hd44780-usb4all.h hd44780-rpi.c hd44780-rpi.h hd44780-piplate.c hd44780-piplate.h
+EXTRA_hd44780_SOURCES = port.h lpt-port.h timing.h lcd_sem.c lcd_sem.h hd44780-4bit.c hd44780-4bit.h hd44780-bwct-usb.c hd44780-bwct-usb.h hd44780-ethlcd.c hd44780-ethlcd.h hd44780-ext8bit.c hd44780-ext8bit.h hd44780-ftdi.c hd44780-ftdi.h hd44780-i2c.c hd44780-i2c.h hd44780-lcd2usb.c hd44780-lcd2usb.h hd44780-lis2.c hd44780-lis2.h hd44780-piplate.c hd44780-piplate.h hd44780-rpi.c hd44780-rpi.h hd44780-serial.c hd44780-serial.h hd44780-serialLpt.c hd44780-serialLpt.h hd44780-spi.c hd44780-spi.h hd44780-usb4all.c hd44780-usb4all.h hd44780-usblcd.c hd44780-usblcd.h hd44780-usbtiny.c hd44780-usbtiny.h hd44780-uss720.c hd44780-uss720.h hd44780-winamp.c hd44780-winamp.h
i2500vfd_SOURCES = lcd.h i2500vfd.c i2500vfd.h glcd_font5x8.h report.h
icp_a106_SOURCES = lcd.h lcd_lib.h icp_a106.c icp_a106.h report.h
imon_SOURCES = lcd.h lcd_lib.h hd44780-charmap.h imon.h imon.c report.h adv_bignum.h
diff --git a/server/drivers/hd44780-drivers.h b/server/drivers/hd44780-drivers.h
index b155451..c4b50d4 100644
--- a/server/drivers/hd44780-drivers.h
+++ b/server/drivers/hd44780-drivers.h
@@ -33,6 +33,9 @@
# include "hd44780-i2c.h"
# include "hd44780-piplate.h"
#endif
+#ifdef HAVE_SPI
+# include "hd44780-spi.h"
+#endif
#ifdef WITH_ETHLCD
# include "hd44780-ethlcd.h"
#endif
@@ -82,6 +85,9 @@ static const ConnectionMapping connectionMapping[] = {
#ifdef HAVE_I2C
{ "i2c", HD44780_CT_I2C, IF_TYPE_I2C, hd_init_i2c },
{ "piplate", HD44780_CT_PIPLATE, IF_TYPE_I2C, hd_init_i2c_piplate },
+#endif
+#ifdef HAVE_SPI
+ { "spi", HD44780_CT_SPI, IF_TYPE_SPI, hd_init_spi },
#endif
/* TCP socket connection types */
#ifdef WITH_ETHLCD
diff --git a/server/drivers/hd44780-low.h b/server/drivers/hd44780-low.h
index 4914dca..3bb1b8b 100644
--- a/server/drivers/hd44780-low.h
+++ b/server/drivers/hd44780-low.h
@@ -55,6 +55,7 @@
#define HD44780_CT_USB4ALL 21
#define HD44780_CT_RASPBERRYPI 22
#define HD44780_CT_PIPLATE 23
+#define HD44780_CT_SPI 24
/**@}*/
/** \name Symbolic names for interface types
@@ -65,6 +66,7 @@
#define IF_TYPE_USB 3
#define IF_TYPE_I2C 4
#define IF_TYPE_TCP 5
+#define IF_TYPE_SPI 6
/**@}*/
/** \name Symbolic default values
diff --git a/server/drivers/hd44780-spi.c b/server/drivers/hd44780-spi.c
new file mode 100644
index 0000000..5f94333
--- /dev/null
+++ b/server/drivers/hd44780-spi.c
@@ -0,0 +1,215 @@
+/** \file server/drivers/hd44780-spi.c
+ * \c SPI connection type of \c hd44780 driver for Hitachi HD44780 based LCD displays.
+ *
+ * The LCD is operated in its serial mode to be connected via the SPI bus
+ * using the Linux kernel spidev interface. The LCD SPI device should be
+ * declared in your board setup code.
+ */
+
+/*-
+ * Copyright (C) 2013 Simon Dawson
+ *
+ * Based mostly on the hd44780-i2c module, see there for a complete history.
+ *
+ * This file is released under the GNU General Public License. Refer to the
+ * COPYING file distributed with this package.
+ *
+ * Configuration:
+ * Device=/dev/spidev0.0 # the device file of the spi bus (spi 0, chipselect 0)
+ * BacklightDevice=(undef) # the device file for the backlight (1 = on, 0 = off)
+ */
+
+#include "hd44780-spi.h"
+#include "hd44780-low.h"
+#include "report.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+void spi_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch);
+void spi_HD44780_backlight(PrivateData *p, unsigned char state);
+
+#define DEFAULT_DEVICE "/dev/spidev0.0"
+
+/** KS0073 5-bit sync lead-in on SPI interface */
+#define SYNC 0xF8u
+/** KS0073 Read Write bit: 1 = read selected data/register, 0 = write to selected data/register */
+#define RW 0x04u
+/** KS0073 Register Select bit: 0 = instruction register follows, 1 = data register follows */
+#define RS 0x02u
+
+
+/**
+ * Reverses the bits of \a u8.
+ * \param u8 byte of which to reverse the bits.
+ * \return Value resulting from \a u8 with reversed bits.
+ */
+static inline uint8_t
+bit_reverse8(uint8_t u8)
+{
+ /*
+ * See
+ * http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits
+ * for how this works and. This code snippet is in the public domain.
+ */
+ return (uint8_t) (((u8 * 0x0802LU & 0x22110LU) | (u8 * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
+}
+
+
+/**
+ * Do a SPI transfer by sending \c length bytes of \c outbuf and read the same
+ * number of bytes into \c inbuf.
+ * \param p Pointer to driver's private data structure.
+ * \param outbuf Buffer holding data to send.
+ * \param inbuf Buffer to store incoming data (or NULL).
+ * \param length Length of buffers (both).
+ * \return Status from ioctl.
+ */
+static int
+spi_transfer(PrivateData *p, const unsigned char *outbuf, unsigned char *inbuf, unsigned length)
+{
+ struct spi_ioc_transfer xfer;
+ int status;
+
+ static unsigned char no_more_errormsgs = 0;
+
+ memset(&xfer, 0, sizeof(xfer));
+ xfer.tx_buf = (unsigned long) outbuf;
+ xfer.rx_buf = (unsigned long) inbuf;
+ xfer.len = length;
+
+ p->hd44780_functions->drv_debug(RPT_DEBUG, "SPI sending %02x %02x %02x",
+ outbuf[0], outbuf[1], length > 2 ? outbuf[2] : 0xFFu);
+ status = ioctl(p->fd, SPI_IOC_MESSAGE(1), &xfer);
+ if (status < 0) {
+ p->hd44780_functions->drv_report(no_more_errormsgs ? RPT_DEBUG : RPT_ERR,
+ "HD44780: SPI: spidev write data %u failed: %s",
+ status, strerror(errno));
+ no_more_errormsgs = 1;
+ }
+#ifdef DEBUG
+ if (inbuf)
+ p->hd44780_functions->drv_debug(RPT_DEBUG, "SPI returned data %02x %02x %02x",
+ inbuf[0], inbuf[1], length > 2 ? inbuf[2] : 0xFFu);
+#endif
+
+ return status;
+}
+
+
+/**
+ * Initialize the driver.
+ * \param drvthis Pointer to driver structure.
+ * \retval 0 Success.
+ * \retval -1 Error.
+ */
+int
+hd_init_spi(Driver *drvthis)
+{
+ PrivateData *p = (PrivateData *) drvthis->private_data;
+ HD44780_functions *hd44780_functions = p->hd44780_functions;
+
+ char device[256] = DEFAULT_DEVICE;
+ char backlight_device[256] = "";
+
+ /* READ CONFIG FILE */
+
+ /* Get and open SPI device to use */
+ strncpy(device, drvthis->config_get_string(drvthis->name, "Device", 0, DEFAULT_DEVICE),
+ sizeof(device));
+ device[sizeof(device) - 1] = '\0';
+ report(RPT_INFO, "HD44780: SPI: Using device '%s'", device);
+
+ p->fd = open(device, O_RDWR);
+ if (p->fd < 0) {
+ report(RPT_ERR, "HD44780: SPI: open spidev device '%s' failed: %s", device,
+ strerror(errno));
+ return -1;
+ }
+
+ /* Get and open the backlight device */
+ p->backlight_bit = -1;
+ strncpy(backlight_device,
+ drvthis->config_get_string(drvthis->name, "BacklightDevice", 0, ""),
+ sizeof(backlight_device));
+ backlight_device[sizeof(backlight_device) - 1] = '\0';
+
+ if (strlen(backlight_device) > 0) {
+ report(RPT_INFO, "HD44780: SPI: Using backlight_device '%s'", backlight_device);
+
+ p->backlight_bit = open(backlight_device, O_RDWR);
+ if (p->backlight_bit < 0) {
+ report(RPT_ERR, "HD44780: SPI: open backlight_device '%s' failed: %s",
+ backlight_device, strerror(errno));
+ }
+ else {
+ hd44780_functions->backlight = spi_HD44780_backlight;
+ }
+ }
+
+ hd44780_functions->senddata = spi_HD44780_senddata;
+ common_init(p, IF_8BIT);
+
+ return 0;
+}
+
+
+/**
+ * Send data or commands to the display.
+ * \param p Pointer to driver's private data structure.
+ * \param displayID ID of the display (or 0 for all) to send data to.
+ * \param flags Defines whether to end a command or data.
+ * \param ch The value to send.
+ */
+void
+spi_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch)
+{
+ unsigned char buf[3];
+ unsigned char reverse;
+
+ p->hd44780_functions->drv_report(RPT_DEBUG, "HD44780: SPI: sending %s %02x",
+ RS_INSTR == flags ? "CMD" : "DATA", ch);
+
+ if (flags == RS_INSTR)
+ buf[0] = SYNC;
+ else
+ buf[0] = SYNC | RS;
+
+ /* KS0073 wants Least Significant Bit first, with the added twist of
+ * peculiar splitting of a byte across 4 nibbles. If we ever need to
+ * read from the device, remember to bit_reverse8() each byte (note
+ * that replies aren't split into nibbles). */
+ reverse = bit_reverse8(ch);
+ buf[1] = reverse & 0xF0;
+ buf[2] = (reverse & 0x0F) << 4;
+
+ spi_transfer(p, buf, NULL, sizeof(buf));
+}
+
+
+/**
+ * Turn display backlight on or off.
+ * \param p Pointer to driver's private data structure.
+ * \param state New backlight status.
+ *
+ * KS0073 in SPI mode does not have a backlight control function. We
+ * assume instead that there is some device mapped to a file which we can
+ * write to.
+ */
+void
+spi_HD44780_backlight(PrivateData *p, unsigned char state)
+{
+ if (p->backlight_bit != -1) {
+ unsigned char byte = (state == BACKLIGHT_ON) ? '1' : '0';
+ if (write(p->backlight_bit, &byte, sizeof(byte)) < 0)
+ p->hd44780_functions->drv_report(RPT_ERR,
+ "HD44780: SPI: Cannot write to backlight device: %d (%s)",
+ errno, strerror(errno));
+ }
+}
diff --git a/server/drivers/hd44780-spi.h b/server/drivers/hd44780-spi.h
new file mode 100644
index 0000000..9b5f83d
--- /dev/null
+++ b/server/drivers/hd44780-spi.h
@@ -0,0 +1,9 @@
+#ifndef HD_SPI_H
+#define HD_SPI_H
+
+#include "lcd.h" /* for Driver */
+
+/* initialise this particular driver */
+int hd_init_spi(Driver *drvthis);
+
+#endif
diff --git a/server/drivers/hd44780.c b/server/drivers/hd44780.c
index e53e48f..4e85b4c 100644
--- a/server/drivers/hd44780.c
+++ b/server/drivers/hd44780.c
@@ -427,6 +427,13 @@ HD44780_init(Driver *drvthis)
(p->have_output?" out":"")
);
break;
+ case IF_TYPE_SPI:
+ sprintf(buf, "SPI %s%s%s",
+ (p->have_backlight?" bl":""),
+ (p->have_keypad?" key":""),
+ (p->have_output?" out":"")
+ );
+ break;
case IF_TYPE_TCP:
sprintf(buf, "TCP %s%s%s",
(p->have_backlight?" bl":""),