diff --git a/ChangeLog b/ChangeLog
index 8a82de0..74333dd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -20,6 +20,7 @@ v0.5dev (ongoing development)
* picolcd: Improvements to IR processing (M. Jones)
+ hd44780: Added 'spi' connection type (S. Dawson)
* hd55780/serial: Change data escape handling (G. Smith)
+ + hd44780: New connection type 'pifacecad' (T. Preston)
v0.5.6
- Remove deprecated CFontz633 driver. Use CFontzPacket with Model=633 instead!
diff --git a/acinclude.m4 b/acinclude.m4
index 7317615..e8d0532 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -233,7 +233,7 @@ dnl else
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"
+ HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-spi.o hd44780-hd44780-pifacecad.o"
fi
dnl The hd4470-rpi driver only works on a Raspberry Pi,
dnl which is an ARM platform. Require people to compile on
diff --git a/docs/LCDd.8.in b/docs/LCDd.8.in
index dd36610..77165f2 100644
--- a/docs/LCDd.8.in
+++ b/docs/LCDd.8.in
@@ -1,4 +1,4 @@
-.TH LCDd 8 "24 March 2011" LCDproc "LCDproc suite"
+.TH LCDd 8 "February 10, 2014" LCDproc "LCDproc suite"
.SH NAME
LCDd - LCDproc server daemon
@@ -185,6 +185,9 @@ LCD in 4-bit mode driven by PCF8574(A) / PCA9554(A), connected via I2C bus
.B spi
LCD with KS0073 or equivalent in serial mode, connected via SPI bus
.TP
+.B pifacecad
+PiFace Control and Display for the Raspberry Pi (http://www.piface.org.uk/)
+.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 15927fc..324a82a 100644
--- a/docs/lcdproc-user/drivers/hd44780.docbook
+++ b/docs/lcdproc-user/drivers/hd44780.docbook
@@ -163,6 +163,10 @@ of connection (parallel port, serial port, USB, I2C, SPI or others).
spi
Display using a KS0073 or similar in serial mode accessed via Linux SPI device
+
+ pifacecad
+ PiFace Control and Display for Raspberry Pi
+
Other connection types:
@@ -3090,6 +3094,49 @@ KeyDirect_5=Right
+
+PiFace Control and Display
+
+
+The PiFace Control and Display for Raspberry Pi
+from OpenLX SP Ltd combines a 16x2 Character LCD and navigation buttons using
+the SPI bus on the Rasperry Pi.
+
+
+
+
+The PiFace Control and Display features a IR receiver, which LCDproc does not
+make use of. You have to setup and use LIRC for that. See
+
+Setting up PiFace Control And Display to use a remote.
+
+
+
+
+HD44780: Configuration example for PiFace Control and Display connection type
+
+
+
+
+
+
+
@@ -3171,6 +3218,7 @@ This can be done by specifying or by inclu
i2c |
piplate |
spi |
+ pifacecad |
ethlcd |
raspberrypi
}
diff --git a/server/drivers/Makefile.am b/server/drivers/Makefile.am
index 534608c..33ca155 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-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
+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-pifacecad.c hd44780-pifacecad.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 c4b50d4..3b00ec4 100644
--- a/server/drivers/hd44780-drivers.h
+++ b/server/drivers/hd44780-drivers.h
@@ -35,6 +35,7 @@
#endif
#ifdef HAVE_SPI
# include "hd44780-spi.h"
+# include "hd44780-pifacecad.h"
#endif
#ifdef WITH_ETHLCD
# include "hd44780-ethlcd.h"
@@ -88,6 +89,7 @@ static const ConnectionMapping connectionMapping[] = {
#endif
#ifdef HAVE_SPI
{ "spi", HD44780_CT_SPI, IF_TYPE_SPI, hd_init_spi },
+ { "pifacecad", HD44780_CT_PIFACECAD, IF_TYPE_SPI, hd_init_pifacecad },
#endif
/* TCP socket connection types */
#ifdef WITH_ETHLCD
diff --git a/server/drivers/hd44780-low.h b/server/drivers/hd44780-low.h
index 3bb1b8b..47acf45 100644
--- a/server/drivers/hd44780-low.h
+++ b/server/drivers/hd44780-low.h
@@ -56,6 +56,7 @@
#define HD44780_CT_RASPBERRYPI 22
#define HD44780_CT_PIPLATE 23
#define HD44780_CT_SPI 24
+#define HD44780_CT_PIFACECAD 25
/**@}*/
/** \name Symbolic names for interface types
diff --git a/server/drivers/hd44780-pifacecad.c b/server/drivers/hd44780-pifacecad.c
new file mode 100644
index 0000000..43db19c
--- /dev/null
+++ b/server/drivers/hd44780-pifacecad.c
@@ -0,0 +1,365 @@
+/** \file server/drivers/hd44780-pifacecad.c
+ * \c PiFace Control and Display connection type (SPI) of \c hd44780 driver for
+ * Hitachi HD44780 based LCD displays.
+ *
+ * The LCD is operated in its 4 bit-mode to be connected to the 8 bit Port B
+ * of a single MCP23S17 that is accessed by the server via the SPI bus.
+ */
+
+/*-
+ * Copyright (c) 2013 Thomas Preston
+ *
+ * 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.
+ */
+
+/*-
+ * The connections are (MCP23S17):
+ * Port A Pin 0 Switch 0 (Left)
+ * Port A Pin 1 Switch 1 (Down)
+ * Port A Pin 2 Switch 2 (Up)
+ * Port A Pin 3 Switch 3 (Right)
+ * Port A Pin 4 Switch 4 (Enter)
+ * Port A Pin 5 Switch 5 (Nav push)
+ * Port A Pin 6 Switch 6 (Nav left)
+ * Port A Pin 6 Switch 7 (Nav right)
+ * Port B Pin 0 D4
+ * Port B Pin 1 D5
+ * Port B Pin 2 D6
+ * Port B Pin 3 D7
+ * Port B Pin 4 EN
+ * Port B Pin 5 RW
+ * Port B Pin 6 RS
+ *
+ * Backlight
+ * Port B Pin 7 Backlight (optional, active-high)
+ *
+ * Configuration:
+ * device=/dev/spidev0.1 # the device file of the SPI bus
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "hd44780-pifacecad.h"
+#include "hd44780-low.h"
+#include "report.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+void pifacecad_HD44780_senddata(PrivateData *p,
+ unsigned char displayID, unsigned char flags, unsigned char ch);
+void pifacecad_HD44780_backlight(PrivateData *p, unsigned char state);
+void pifacecad_HD44780_close(PrivateData *p);
+unsigned char pifacecad_HD44780_scankeypad(PrivateData *p);
+
+/** \name SPI bus configuration
+ *@{*/
+#define DEFAULT_DEVICE "/dev/spidev0.1"
+#define SPI_HW_ADDR 0 /**< Hardware address set by pins A0:2 */
+
+const unsigned char spi_mode = 0; /**< Set SPI mode to CPOL = 0 (leading edge is rising)
+ * and CPHA = 0 (sample on leading edge) */
+const unsigned char spi_bpw = 8; /**< Set SPI to 8 bits per word */
+const unsigned long spi_speed = 10000000L; /**< Set SPI speed to 10MHz */
+const unsigned char spi_delay = 0;
+/**@}*/
+
+/** \name MCP23S17 commands
+ *@{*/
+#define WRITE_CMD 0
+#define READ_CMD 1
+/**@}*/
+
+/** \name MCP23S17 Register addresses
+ *@{*/
+#define IODIRA 0x00 /**< I/O direction A */
+#define IODIRB 0x01 /**< I/O direction B */
+#define IPOLA 0x02 /**< Input polarity A */
+#define IPOLB 0x03 /**< Input polarity B */
+#define IOCON 0x0A /**< I/O config (also 0x0B) */
+#define GPPUA 0x0C /**< Port A pull-ups when input */
+#define GPPUB 0x0D /**< Port B pull-ups when input */
+#define GPIOA 0x12 /**< Port A */
+#define GPIOB 0x13 /**< Port B */
+/**@}*/
+
+/* Ports */
+#define SWITCH_PORT GPIOA /**< Switches are connected to port A */
+#define LCD_PORT GPIOB /**< LCD and backlight are connected to port B */
+
+/* LCD timing delays */
+#define DELAY_PULSE_US 1 /**< 1us hold time for EN */
+#define DELAY_SETTLE_US 40 /**< 40us delay for executing LCD command */
+
+/** \name LCD control pins
+ * LCD control pins are connected to upper nibble of Port B on the MCP23S17
+ *@{*/
+#define EN 0x10
+#define RW 0x20
+#define RS 0x40
+#define BL 0x80
+/**@}*/
+
+/**
+ * Writes to a register on the MCP23S17.
+ *
+ * \param p Pointer to PrivateData structure.
+ * \param reg Register address to write to.
+ * \param data Data to write
+ */
+static void
+mcp23s17_write_reg(PrivateData *p, unsigned char reg, unsigned char data)
+{
+ unsigned char tx_buf[3] = { 0x40 | SPI_HW_ADDR | WRITE_CMD, reg, data };
+ unsigned char rx_buf[3];
+
+ struct spi_ioc_transfer spi;
+ spi.tx_buf = (unsigned long) tx_buf;
+ spi.rx_buf = (unsigned long) rx_buf;
+ spi.len = sizeof(tx_buf);
+ spi.delay_usecs = spi_delay;
+ spi.speed_hz = spi_speed;
+ spi.bits_per_word = spi_bpw;
+
+ /* do the SPI transaction */
+ if (ioctl(p->fd, SPI_IOC_MESSAGE(1), &spi) < 0) {
+ p->hd44780_functions->drv_report(RPT_ERR,
+ "HD44780: PiFaceCAD: mcp23s17_write_reg: There was "
+ "a error during the SPI transaction: %s",
+ strerror(errno));
+ }
+}
+
+
+/**
+ * Reads from a register on the MCP23S17.
+ *
+ * \param p Pointer to PrivateData structure.
+ * \param reg Register address to read from.
+ * \retval Value of the register. Returns zero (0) on error, too.
+ */
+static unsigned char
+mcp23s17_read_reg(PrivateData *p, unsigned char reg)
+{
+ unsigned char tx_buf[3] = { 0x40 | SPI_HW_ADDR | READ_CMD, reg, 0 };
+ unsigned char rx_buf[3] = { 0, 0, 0 };
+
+ struct spi_ioc_transfer spi;
+ spi.tx_buf = (unsigned long) tx_buf;
+ spi.rx_buf = (unsigned long) rx_buf;
+ spi.len = sizeof(tx_buf);
+ spi.delay_usecs = spi_delay;
+ spi.speed_hz = spi_speed;
+ spi.bits_per_word = spi_bpw;
+
+ /* do the SPI transaction */
+ if (ioctl(p->fd, SPI_IOC_MESSAGE(1), &spi) < 0) {
+ p->hd44780_functions->drv_report(RPT_ERR,
+ "HD44780: PiFaceCAD: mcp23s17_read_reg: There was"
+ "a error during the SPI transaction: %s",
+ strerror(errno));
+ return 0;
+ }
+ return rx_buf[2];
+}
+
+/**
+ * Writes control and data to HD44780 through Port B on MCP23S17.
+ *
+ * \param p Pointer to the PrivateData structure.
+ * \param data The data to write.
+ */
+static void
+write_and_pulse(PrivateData *p, unsigned char data)
+{
+ /* Enable: Off/On/Off - Doesn't seem to work any other way. */
+ mcp23s17_write_reg(p, LCD_PORT, data);
+ if (p->delayBus)
+ p->hd44780_functions->uPause(p, DELAY_PULSE_US);
+ mcp23s17_write_reg(p, LCD_PORT, data | EN);
+ if (p->delayBus)
+ p->hd44780_functions->uPause(p, DELAY_PULSE_US);
+ mcp23s17_write_reg(p, LCD_PORT, data);
+
+ p->hd44780_functions->uPause(p, DELAY_SETTLE_US);
+}
+
+
+/**
+ * Initialize the driver.
+ *
+ * \param drvthis Pointer to driver structure.
+ * \retval 0 Success.
+ * \retval -1 Error.
+ */
+int
+hd_init_pifacecad(Driver *drvthis)
+{
+ PrivateData *p = (PrivateData *) drvthis->private_data;
+ HD44780_functions *hd44780_functions = p->hd44780_functions;
+ char device[256] = DEFAULT_DEVICE;
+ p->backlight_bit = BL; /* Backlight on during init */
+
+ /* READ CONFIG FILE */
+ /* Get serial 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: PiFaceCAD: Using device '%s'", device);
+
+ /* Open the SPI device */
+ if ((p->fd = open(device, O_RDWR)) < 0) {
+ report(RPT_ERR,
+ "HD44780: PiFaceCAD: open SPI device '%s' failed: %s",
+ device, strerror(errno));
+ return -1;
+ }
+
+ /* configure SPI device */
+ if (ioctl(p->fd, SPI_IOC_WR_MODE, &spi_mode) < 0) {
+ report(RPT_ERR, "HD44780: PiFaceCAD: Could not set SPI mode.");
+ return -1;
+ }
+ if (ioctl(p->fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bpw) < 0) {
+ report(RPT_ERR, "HD44780: PiFaceCAD Could not set SPI bits per word.");
+ return -1;
+ }
+ if (ioctl(p->fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed) < 0) {
+ report(RPT_ERR, "HD44780: PiFaceCAD: Could not set SPI speed.");
+ return -1;
+ }
+
+ /* Set IO config */
+ mcp23s17_write_reg(p, IOCON, 0x08); /* Hardware Address Enable */
+ mcp23s17_write_reg(p, IODIRB, 0x00); /* Set GPIOB (LCD port) to output */
+ mcp23s17_write_reg(p, IODIRA, 0xff); /* Set GPIOA (switches) to input */
+ mcp23s17_write_reg(p, GPPUA, 0xff); /* enable pull-ups on input */
+ mcp23s17_write_reg(p, IPOLA, 0xff); /* invert inputs */
+
+ hd44780_functions->senddata = pifacecad_HD44780_senddata;
+ hd44780_functions->backlight = pifacecad_HD44780_backlight;
+ hd44780_functions->close = pifacecad_HD44780_close;
+ hd44780_functions->scankeypad = pifacecad_HD44780_scankeypad;
+
+ /* Send 0x03 a couple of times, which is ((FUNCSET | IF_8BIT) >> 4) */
+ write_and_pulse(p, 0x03);
+ hd44780_functions->uPause(p, 15000);
+
+ write_and_pulse(p, 0x03);
+ hd44780_functions->uPause(p, 5000);
+
+ write_and_pulse(p, 0x03);
+ hd44780_functions->uPause(p, 1000);
+
+ /* Now switch to IF_4BIT */
+ write_and_pulse(p, 0x02);
+ hd44780_functions->uPause(p, DELAY_SETTLE_US);
+
+ common_init(p, IF_4BIT);
+
+ report(RPT_INFO, "HD44780: PiFaceCAD: initialized");
+
+ return 0;
+}
+
+
+/**
+ * Closes the file descriptor of the HD44780 (SPI bus to MCP23S17).
+ *
+ * \param p Pointer to driver's private data structure.
+ */
+void
+pifacecad_HD44780_close(PrivateData *p)
+{
+ if (p->fd >= 0) {
+ close(p->fd);
+ }
+}
+
+
+/**
+ * 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
+pifacecad_HD44780_senddata(PrivateData *p,
+ unsigned char displayID, unsigned char flags, unsigned char ch)
+{
+ unsigned char portControl = 0;
+ unsigned char h = (ch >> 4) & 0x0f; /* high nibble */
+ unsigned char l = ch & 0x0f; /* low nibble */
+
+ if (flags == RS_INSTR)
+ portControl = 0;
+ else
+ portControl = RS;
+
+ portControl |= p->backlight_bit;
+
+ write_and_pulse(p, portControl | h);
+ write_and_pulse(p, portControl | l);
+}
+
+
+/**
+ * Turn display backlight on or off.
+ *
+ * \param p Pointer to driver's private data structure.
+ * \param state New backlight status.
+ */
+void
+pifacecad_HD44780_backlight(PrivateData *p, unsigned char state)
+{
+ unsigned char port_state = mcp23s17_read_reg(p, LCD_PORT);
+ p->backlight_bit = (state == BACKLIGHT_ON) ? BL : 0;
+ if (p->backlight_bit)
+ port_state |= BL; /* set */
+ else
+ port_state &= 0xff ^ BL; /* clear */
+ mcp23s17_write_reg(p, LCD_PORT, port_state);
+}
+
+
+/**
+ * Scan the LCD keys. Each button is connected to a pin on Port A. As the
+ * hd44780 driver only supports 5 direct keys return the pressed key as a
+ * matrix key code instead.
+ *
+ * \param p Pointer to driver's private data structure.
+ * \retval key Key code as matrix code (1,1) to (1,8).
+ */
+unsigned char
+pifacecad_HD44780_scankeypad(PrivateData *p)
+{
+ unsigned char keycode = 0;
+ unsigned char switch_state;
+ int i;
+
+ if ((switch_state = mcp23s17_read_reg(p, SWITCH_PORT)) == 0)
+ return 0;
+
+ /* detect which key is pressed (which bit is set) */
+ for (i = 0; i < 8; i++) {
+ if (switch_state & (1 << i)) {
+ /* convert to matrix code */
+ keycode = ((i + 1) << 4 | 1);
+ break;
+ }
+ }
+
+ return keycode;
+}
diff --git a/server/drivers/hd44780-pifacecad.h b/server/drivers/hd44780-pifacecad.h
new file mode 100644
index 0000000..1b608e6
--- /dev/null
+++ b/server/drivers/hd44780-pifacecad.h
@@ -0,0 +1,9 @@
+#ifndef HD_PIFACECAD_H
+#define HD_PIFACECAD_H
+
+#include "lcd.h" /* for Driver */
+
+/* initialise this particular driver */
+int hd_init_pifacecad(Driver *drvthis);
+
+#endif