Added a new brewpanel program that runs on an SDL/X screen. It will be an emulator for the hardware panels. Development version 0.5.0

Sat, 07 Nov 2015 22:04:17 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Sat, 07 Nov 2015 22:04:17 +0100
changeset 409
cdf68044adaf
parent 408
ec507c1f1df7
child 410
e3f8a51b566a

Added a new brewpanel program that runs on an SDL/X screen. It will be an emulator for the hardware panels. Development version 0.5.0

.hgignore file | annotate | diff | comparison | revisions
Makefile.global.in file | annotate | diff | comparison | revisions
brewco/Makefile file | annotate | diff | comparison | revisions
brewco/README file | annotate | diff | comparison | revisions
brewco/brewco.c file | annotate | diff | comparison | revisions
brewco/brewco.h file | annotate | diff | comparison | revisions
brewco/futil.c file | annotate | diff | comparison | revisions
brewco/futil.h file | annotate | diff | comparison | revisions
brewco/rdconfig.c file | annotate | diff | comparison | revisions
brewco/rdconfig.h file | annotate | diff | comparison | revisions
brewco/xutil.c file | annotate | diff | comparison | revisions
brewco/xutil.h file | annotate | diff | comparison | revisions
brewpanel/Makefile file | annotate | diff | comparison | revisions
brewpanel/brewpanel.c file | annotate | diff | comparison | revisions
brewpanel/brewpanel.h file | annotate | diff | comparison | revisions
brewpanel/dlgBrew.c file | annotate | diff | comparison | revisions
brewpanel/dlgBrew.h file | annotate | diff | comparison | revisions
brewpanel/lcdfont5x8.bmp file | annotate | diff | comparison | revisions
brewpanel/sdlgui.c file | annotate | diff | comparison | revisions
brewpanel/sdlgui.h file | annotate | diff | comparison | revisions
config.h.in file | annotate | diff | comparison | revisions
configure file | annotate | diff | comparison | revisions
configure.ac file | annotate | diff | comparison | revisions
--- a/.hgignore	Mon Oct 05 15:21:46 2015 +0200
+++ b/.hgignore	Sat Nov 07 22:04:17 2015 +0100
@@ -5,13 +5,15 @@
 stamp-h
 autom4te.cache
 .filelist
-thermometers/thermometers
 rc433/recv
 rc433/send
 rc433/sniffer
 thermferm/thermferm
 dht11/dht11
 mash/mash
+brewco/brewco
+brewpanel/brewpanel
+brewpanel/lcdfont10x16.h
 
 syntax: glob
 *.o
--- a/Makefile.global.in	Mon Oct 05 15:21:46 2015 +0200
+++ b/Makefile.global.in	Sat Nov 07 22:04:17 2015 +0100
@@ -23,3 +23,6 @@
 CXXFLAGS	= @CXXFLAGS@
 LIBS		= @LIBS@
 
+SDL_CFLAGS	= @SDL_CFLAGS@
+SDL_LIBS	= @SDL_LIBS@
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewco/Makefile	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,61 @@
+# Makefile for the mbsePi-apps/brewco.
+
+include ../Makefile.global
+
+SRCS		= $(wildcard *.c)
+HDRS		= $(wildcard *.h)
+OBJS		= $(SRCS:.c=.o)
+SLIBS		= -lpthread
+TARGET		= brewco
+OTHER		= Makefile
+
+#############################################################################
+
+.c.o:
+		${CC} ${CFLAGS} ${INCLUDES} ${DEFINES} -c $<
+
+all:		${TARGET}
+
+brewco:	${OBJS} ${SLIBS}
+		${CC} -o brewco ${OBJS} ${LDFLAGS} ${LIBS} ${SLIBS}
+
+clean:
+		rm -f ${TARGET} *.o *.h~ *.c~ core filelist Makefile.bak
+
+install:	all
+		${INSTALL} -c -s -g root -o root -m 0755 brewco ${BINDIR}
+
+filelist:	Makefile
+		BASE=`pwd`; \
+		BASE=`basename $${BASE}`; \
+		(for f in ${SRCS} ${HDRS} ${OTHER} ;do echo ${PACKAGE}-${VERSION}/$${BASE}/$$f; done) >filelist
+
+depend:
+	@rm -f Makefile.bak; \
+	mv Makefile Makefile.bak; \
+	sed -e '/^# DO NOT DELETE/,$$d' Makefile.bak >Makefile; \
+	${ECHO} '# DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT' \
+		>>Makefile; \
+	${ECHO} '# Dependencies generated by make depend' >>Makefile; \
+	for f in ${SRCS}; \
+	do \
+		${ECHO} "Dependencies for $$f:\c"; \
+		${ECHO} "`basename $$f .c`.o:\c" >>Makefile; \
+		for h in `sed -n -e \
+			's/^#[ 	]*include[ 	]*"\([^"]*\)".*/\1/p' $$f`; \
+		do \
+			${ECHO} " $$h\c"; \
+			${ECHO} " $$h\c" >>Makefile; \
+		done; \
+		${ECHO} " done."; \
+		${ECHO} "" >>Makefile; \
+	done; \
+	${ECHO} '# End of generated dependencies' >>Makefile
+
+# DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT
+# Dependencies generated by make depend
+futil.o: brewco.h futil.h
+brewco.o: rdconfig.h brewco.h futil.h xutil.h
+xutil.o: brewco.h xutil.h
+rdconfig.o: rdconfig.h brewco.h futil.h xutil.h
+# End of generated dependencies
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewco/README	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,11 @@
+
+
+Er moeten meerdere installaties in.
+Iedere installatie heeft een MLT/brew kettle.
+Optie HLT.
+Keuze pomp/roeren. Keuze PWM/On-off.
+
+Default start, kies installatie. Tenzij een programma loopt (na een crash)
+start laatst gekozen installatie.
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewco/brewco.c	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,134 @@
+/*****************************************************************************
+ * Copyright (C) 2015
+ *   
+ * Michiel Broek <mbroek at mbse dot eu>
+ *
+ * This file is part of the mbsePi-apps
+ *
+ * This 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, or (at your option) any
+ * later version.
+ *
+ * mbsePi-apps 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 ThermFerm; see the file COPYING.  If not, write to the Free
+ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *****************************************************************************/
+
+#include "rdconfig.h"
+#include "brewco.h"
+#include "futil.h"
+#include "xutil.h"
+
+
+int			my_shutdown = FALSE;
+extern int              debug;
+extern sys_config       Config;
+#ifdef HAVE_WIRINGPI_H
+extern int              lcdHandle;
+#endif
+
+
+void help(void);
+void die(int);
+
+
+
+void help(void)
+{
+    fprintf(stdout, "mbsePi-apps brewco v%s starting\n\n", VERSION);
+    fprintf(stdout, "Usage: brewco [-d] [-h]\n");
+    fprintf(stdout, "  -d --debug              Debug and run in foreground\n");
+    fprintf(stdout, "  -h --help               Display this help\n");
+}
+
+
+
+void die(int onsig)
+{
+    switch (onsig) {
+	case SIGHUP:    syslog(LOG_NOTICE, "Got SIGHUP, shutting down");
+			break;
+	case SIGINT:    syslog(LOG_NOTICE, "Keyboard interrupt, shutting down");
+			break;
+	case SIGTERM:   syslog(LOG_NOTICE, "Got SIGTERM, shutting down");
+			break;
+	case SIGSEGV:   syslog(LOG_NOTICE, "Got SIGSEGV, shutting down");
+			my_shutdown = TRUE;
+			exit(SIGSEGV);
+			break;
+	default:        syslog(LOG_NOTICE, "die() on signal %d", onsig);
+    }
+
+    my_shutdown = TRUE;
+}
+
+
+
+int main(int argc, char *argv[])
+{
+    int		rc = 0, c, i;
+
+    while (1) {
+	int option_index = 0;
+	static struct option long_options[] = {
+	    {"debug", 0, 0, 'c'},
+	    {"help", 0, 0, 'h'},
+	    {0, 0, 0, 0}
+	};
+
+	c = getopt_long(argc, argv, "dh", long_options, &option_index);
+	if (c == -1)
+	    break;
+
+	switch (c) {
+	    case 'd':   debug = TRUE;
+			break;
+	    case 'h':   help();
+			return 1;
+	}
+    }
+
+    openlog("brewco", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_USER);
+    syslog(LOG_NOTICE, "mbsePi-apps brewco v%s starting", VERSION);
+    if (debug)
+	fprintf(stdout, "mbsePi-apps brewco v%s starting\n", VERSION);
+
+    if (rdconfig()) {
+	fprintf(stderr, "Error reading configuration\n");
+	syslog(LOG_NOTICE, "Error reading configuration: halted");
+	return 1;
+    }
+
+    /*
+     *  Catch all the signals we can, and ignore the rest. Note that SIGKILL can't be ignored
+     *  but that's live. This daemon should only be stopped by SIGTERM.
+     *  Don't catch SIGCHLD.
+     */
+    for (i = 0; i < NSIG; i++) {
+	if ((i != SIGCHLD) && (i != SIGKILL) && (i != SIGSTOP))
+	    signal(i, (void (*))die);
+    }
+
+#ifdef HAVE_WIRINGPI_H
+    if (wiringPiSetup () )
+	return 1;
+
+    if ((rc = initLCD (Config.lcd_cols, Config.lcd_rows))) {
+	fprintf(stderr, "Cannot initialize LCD display, rc=%d\n", rc);
+	return 1;
+    }
+#endif
+
+
+    syslog(LOG_NOTICE, "Finished, rc=%d", rc);
+    return rc;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewco/brewco.h	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,96 @@
+#ifndef _BREWCO_H
+#define	_BREWCO_H
+
+#define TRUE 1
+#define FALSE 0
+
+#include "../config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <getopt.h>
+
+#ifndef HAVE_WIRINGPI_H
+#include <pthread.h>
+#endif
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/encoding.h>
+#include <libxml/xmlwriter.h>
+
+#ifdef HAVE_WIRINGPI_H
+/* wiringPi */
+#include <wiringPi.h>
+#include <pcf8574.h>
+#include <lcd.h>
+
+/*
+ * Thread locks
+ */
+#define LOCK_DEVICES            0
+#define LOCK_LCD                1
+#define LOCK_MENU               2
+#define LOCK_SPARE2             3
+
+
+#endif
+
+/*
+ * 1-Wire devices
+ */
+#define W1_FAMILY_DEFAULT       0
+#define W1_FAMILY_SMEM_01       0x01
+#define W1_FAMILY_SMEM_81       0x81
+#define W1_THERM_DS18S20        0x10
+#define W1_FAMILY_DS28E04       0x1C
+#define W1_COUNTER_DS2423       0x1D
+#define W1_THERM_DS1822         0x22
+#define W1_EEPROM_DS2433        0x23
+#define W1_THERM_DS18B20        0x28
+#define W1_FAMILY_DS2408        0x29
+#define W1_EEPROM_DS2431        0x2D
+#define W1_FAMILY_DS2760        0x30
+#define W1_FAMILY_DS2780        0x32
+#define W1_FAMILY_DS2413        0x3A
+#define W1_THERM_DS1825         0x3B
+#define W1_FAMILY_DS2781        0x3D
+#define W1_THERM_DS28EA00       0x42
+
+
+#define MBSE_SS(x) (x)?(x):"(null)"
+
+
+typedef struct _sys_config {
+    char		*name;			/* Configuration name		*/
+    unsigned char	tempFormat;		/* Temperature format, C or F	*/
+    char		*hlt_sensor_address;	/* HLT sensor address		*/
+    int			hlt_sensor_state;	/* HLT sensor state		*/
+    int			hlt_sensor_value;	/* HLT sensor value		*/
+
+    char		*mlt_sensor_address;	/* MLT sensor address		*/
+    int			mlt_sensor_state;	/* MLT sensor state		*/
+    int			mlt_sensor_value;	/* MLT sensor value		*/
+
+#ifdef HAVE_WIRINGPI_H
+    int			lcd_cols;		/* LCD display columns		*/
+    int			lcd_rows;		/* LCD display rows		*/
+    int			lcd_address;		/* LCD display i2c address	*/
+#endif
+
+} sys_config;
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewco/futil.c	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,60 @@
+/*****************************************************************************
+ * Copyright (C) 2015
+ *   
+ * Michiel Broek <mbroek at mbse dot eu>
+ *
+ * This file is part of the mbsePi-apps
+ *
+ * This 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, or (at your option) any
+ * later version.
+ *
+ * mbsePi-apps 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 ThermFerm; see the file COPYING.  If not, write to the Free
+ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *****************************************************************************/
+
+#include "brewco.h"
+#include "futil.h"
+
+
+/*
+ * Make directory tree, the name must end with a /
+ */
+int mkdirs(char *name, mode_t mode)
+{
+    char	buf[PATH_MAX], *p, *q;
+    int		last = 0, oldmask;
+
+    memset(&buf, 0, sizeof(buf));
+    strncpy(buf, name, sizeof(buf)-1);
+    buf[sizeof(buf)-1] = '\0';
+
+    p = buf+1;
+
+    oldmask = umask(000);
+    while ((q = strchr(p, '/'))) {
+	*q = '\0';
+	mkdir(buf, mode);
+	last = errno;
+	*q = '/';
+	p = q+1;
+    }
+
+    umask(oldmask);
+											
+    if ((last == 0) || (last == EEXIST)) {
+	return TRUE;
+    } else {
+	syslog(LOG_NOTICE, "mkdirs(%s)", name);
+	return FALSE;
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewco/futil.h	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,7 @@
+#ifndef	FUTIL_H
+#define	FUTIL_H
+
+
+int  mkdirs(char *, mode_t);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewco/rdconfig.c	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,399 @@
+/*****************************************************************************
+ * Copyright (C) 2015
+ *   
+ * Michiel Broek <mbroek at mbse dot eu>
+ *
+ * This file is part of the mbsePi-apps
+ *
+ * This 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, or (at your option) any
+ * later version.
+ *
+ * mbsePi-apps 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 ThermFerm; see the file COPYING.  If not, write to the Free
+ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *****************************************************************************/
+
+#include "rdconfig.h"
+#include "brewco.h"
+#include "futil.h"
+#include "xutil.h"
+
+int		debug = FALSE;
+sys_config	Config;			/* System configuration		*/
+
+#define MY_ENCODING "utf-8"
+
+const char	TEMPSTATE[3][8] = { "OK", "MISSING", "ERROR" };
+//const char	DEVTYPE[8][6] = { "NA", "W1", "GPIO", "RC433", "DHT", "I2C", "SPI", "SIM" };
+//const char	DEVPRESENT[4][6] = { "UNDEF", "NO", "YES", "ERROR" };
+//const char	DEVDIR[7][11] = { "UNDEF", "IN_BIN", "OUT_BIN", "IN_ANALOG", "OUT_ANALOG", "OUT_PWM", "INTERN" };
+//const char	PIDMODE[3][5] = { "NONE", "AUTO", "BOO" };
+
+
+void killconfig(void)
+{
+
+    if (Config.name)
+	free(Config.name);
+    Config.name = NULL;
+
+    Config.tempFormat = 'C';
+    if (Config.hlt_sensor_address)
+	free(Config.hlt_sensor_address);
+    if (Config.mlt_sensor_address)
+	free(Config.mlt_sensor_address);
+    Config.hlt_sensor_address = Config.mlt_sensor_address = NULL;
+    Config.hlt_sensor_value = Config.mlt_sensor_value = 20000;
+    Config.hlt_sensor_state = Config.mlt_sensor_state = 1;	// missing
+
+#ifdef HAVE_WIRINGPI_H
+    Config.lcd_cols = 16;
+    Config.lcd_rows = 2;
+#endif
+}
+
+
+
+int do_wrconfig(void);
+int do_wrconfig(void)
+{
+    int			rc = 0;
+    FILE		*fp;
+    char		*mypath = NULL;
+    xmlTextWriterPtr	writer;
+    xmlBufferPtr	buf;
+
+    /* 
+     * Create a new XML buffer, to which the XML document will be written
+     */
+    if ((buf = xmlBufferCreate()) == NULL) {
+	syslog(LOG_NOTICE, "wrconfig: error creating the xml buffer");
+	return 1;
+    }
+
+    /* 
+     * Create a new XmlWriter for memory, with no compression.
+     */
+    if ((writer = xmlNewTextWriterMemory(buf, 0)) == NULL) {
+	syslog(LOG_NOTICE, "wrconfig: error creating the xml writer");
+	return 1;
+    }
+
+    /*
+     * Use indentation instead of one long line
+     */
+    if ((rc = xmlTextWriterSetIndent(writer, 2)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error setting Indent");
+	return 1;
+    }
+
+    /* 
+     * Start the document with the xml default for the version,
+     * encoding ISO 8859-1 and the default for the standalone
+     * declaration. 
+     */
+    if ((rc = xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartDocument");
+	return 1;
+    }
+
+    /* 
+     * Start an element named "BREWCO". Since thist is the first
+     * element, this will be the root element of the document.
+     */
+    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "BREWCO")) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
+	return 1;
+    }
+
+    /* 
+     * Add an attribute with name "VERSION" and value "1" to BRWCO.
+     */
+    if ((rc = xmlTextWriterWriteElement(writer, BAD_CAST "VERSION", BAD_CAST "1")) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
+	return 1;
+    }
+    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", Config.name)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
+	return 1;
+    }
+    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TEMPFORMAT", "%c", Config.tempFormat)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
+	return 1;
+    }
+    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_SENSOR_ADDRESS", "%s", Config.hlt_sensor_address)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
+	return 1;
+    }
+    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_SENSOR_STATE", "%d", Config.hlt_sensor_state)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
+	return 1;                           
+    }
+    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_SENSOR_VALUE", "%d", Config.hlt_sensor_value)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
+	return 1;
+    }
+    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_SENSOR_ADDRESS", "%s", Config.mlt_sensor_address)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
+	return 1;
+    }   
+    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_SENSOR_STATE", "%d", Config.mlt_sensor_state)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
+	return 1;    
+    }   
+    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_SENSOR_VALUE", "%d", Config.mlt_sensor_value)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
+	return 1;
+    }
+
+#ifdef HAVE_WIRINGPI_H
+    /* 
+     * Start an element named "LCDS" as child of BREWCO.
+     */
+    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "LCDS")) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
+	return 1;
+    }
+    /*
+     * Start one LCD. It is possible to connect 7 LCD displays on the i2c bus.
+     * However this program doesn't use more then one yet.
+     */
+    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "LCD")) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
+	return 1;
+    }
+    if ((rc = xmlTextWriterWriteElement(writer, BAD_CAST "VERSION", BAD_CAST "1")) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
+	return 1;
+    }
+    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ADDRESS", "0x%x", Config.lcd_address)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
+	return 1;
+    }
+    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COLUMNS", "%d", Config.lcd_cols)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
+	return 1;
+    }
+    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROWS", "%d", Config.lcd_rows)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
+	return 1;
+    }
+    /* 
+     * Close the element named LCD.
+     */
+    if ((rc = xmlTextWriterEndElement(writer)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
+	return 1;
+    }
+    /*
+     * Close the element LCDS.
+     */
+    if ((rc = xmlTextWriterEndElement(writer)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
+	return 1;
+    }
+#endif
+
+    /*
+     * All done, close any open elements
+     */
+    if ((rc = xmlTextWriterEndDocument(writer)) < 0) {
+	syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndDocument");
+	return 1;
+    }
+    xmlFreeTextWriter(writer);
+
+    /*
+     * Now write the XML configuration
+     */
+    if (getenv((char *)"USER") == NULL) {
+	mypath = xstrcpy((char *)"/root");
+    } else {
+	mypath = xstrcpy(getenv((char *)"HOME"));
+    }
+    mypath = xstrcat(mypath, (char *)"/.brewco/etc/");
+    mkdirs(mypath, 0755);
+    mypath = xstrcat(mypath, (char *)"brewco.xml");
+
+    if (debug)
+	fprintf(stdout, "Writing %s\n", mypath);
+
+    if ((fp = fopen(mypath, "w")) == NULL) {
+	syslog(LOG_NOTICE, "could not rewrite %s", mypath);
+	free(mypath);
+	return 1;
+    }
+    free(mypath);
+
+    fprintf(fp, "%s", (const char *) buf->content);
+    fclose(fp);
+    xmlBufferFree(buf);
+
+    return 0;
+}
+
+
+
+int wrconfig(void)
+{
+    int		rc;
+
+    rc = do_wrconfig();
+    syslog(LOG_NOTICE, "Rewritten configuration, rc=%d", rc);
+    return rc;
+}
+
+
+
+/*
+ * Parse one LCD display
+ */
+#ifdef HAVE_WIRINGPI_H
+int parseLCD(xmlDocPtr doc, xmlNodePtr cur)
+{
+    xmlChar	*key;
+    int		ival;
+
+    cur = cur->xmlChildrenNode;
+    while (cur != NULL) {
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COLUMNS"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+	        Config.lcd_cols = ival;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ROWS"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+		Config.lcd_rows = ival;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ADDRESS"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%x", &ival) == 1)
+		Config.lcd_address = ival;
+	    xmlFree(key);
+	}
+	cur = cur->next;
+    }
+
+    return 0;
+}
+
+
+
+int parseLCDs(xmlDocPtr doc, xmlNodePtr cur)
+{
+    cur = cur->xmlChildrenNode;
+    while (cur != NULL) {
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"LCD"))) {
+	    parseLCD(doc, cur);
+	}
+	cur = cur->next;
+    }
+    return 0;
+}
+#endif
+
+
+
+int rdconfig(void) 
+{
+    int		rc = 0;
+    char	*mypath;
+    xmlDocPtr	doc;
+    xmlNodePtr	cur;
+    xmlChar	*key;
+
+    killconfig();
+    syslog(LOG_NOTICE, "HOME='%s' USER='%s' LOGNAME='%s'", MBSE_SS(getenv((char *)"HOME")), MBSE_SS(getenv((char *)"USER")), MBSE_SS(getenv((char *)"LOGNAME")));
+
+    /*
+     * Search config file
+     */
+    if (getenv((char *)"USER") == NULL) {
+	mypath = xstrcpy((char *)"/root");
+    } else {
+    	mypath = xstrcpy(getenv((char *)"HOME"));
+    }
+    mypath = xstrcat(mypath, (char *)"/.brewco/etc/");
+    mkdirs(mypath, 0755);
+    mypath = xstrcat(mypath, (char *)"brewco.xml");
+    if ((doc = xmlParseFile(mypath)) == NULL) {
+	/*
+	 * No config file, create a fresh one
+	 */
+	syslog(LOG_NOTICE, "rdconfig: %s not found, creating", mypath);
+	wrconfig();
+
+	if ((doc = xmlParseFile(mypath)) == NULL) {
+	    syslog(LOG_NOTICE, "rdconfig: could not create %s", mypath);
+	    free(mypath);
+	    return 1;
+	}
+    }
+    syslog(LOG_NOTICE, "rdconfig: using %s", mypath);
+
+    if ((cur = xmlDocGetRootElement(doc)) == NULL) {
+	syslog(LOG_NOTICE, "XML file %s empty.", mypath);
+	xmlFreeDoc(doc);
+	return 1;
+    }
+    if (xmlStrcmp(cur->name, (const xmlChar*)"BREWCO")) {
+	syslog(LOG_NOTICE, "XML file %s is not a valid configuration file.", mypath);
+	xmlFreeDoc(doc);
+	return 1;
+    }
+
+    /*
+     * Parse configuration
+     */
+    cur = cur->xmlChildrenNode;
+    while (cur != NULL) {
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
+		xmlFree(key);
+		syslog(LOG_NOTICE, "XML file %s is not a valid version", mypath);
+		return 1;
+	    }
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
+	    Config.name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TEMPFORMAT"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    Config.tempFormat = key[0];
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_SENSOR_ADDRESS"))) {
+	    Config.hlt_sensor_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_SENSOR_ADDRESS"))) {
+	    Config.mlt_sensor_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+#ifdef HAVE_WIRINGPI_H
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"LCDS"))) {
+	    parseLCDs(doc, cur);
+	}
+#endif
+	cur = cur->next;
+    }
+    xmlFreeDoc(doc);
+
+    free(mypath);
+    mypath = NULL;
+
+    return rc;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewco/rdconfig.h	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,10 @@
+#ifndef	RDCONFIG_H
+#define	RDCONFIG_H
+
+
+void killconfig(void);
+int  rdconfig(void);
+int  wrconfig(void);
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewco/xutil.c	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,73 @@
+/*****************************************************************************
+ * Copyright (C) 2015
+ *   
+ * Michiel Broek <mbroek at mbse dot eu>
+ *
+ * This file is part of the mbsePi-apps
+ *
+ * This 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, or (at your option) any
+ * later version.
+ *
+ * mbsePi-apps 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 ThermFerm; see the file COPYING.  If not, write to the Free
+ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *****************************************************************************/
+
+#include "brewco.h"
+#include "xutil.h"
+
+
+char *xmalloc(size_t size)
+{
+    char *tmp;
+
+    tmp = malloc(size);
+    if (!tmp) 
+	abort();
+			            
+    return tmp;
+}
+
+
+
+char *xstrcpy(char *src)
+{
+    char    *tmp;
+
+    if (src == NULL) 
+	return(NULL);
+    tmp = xmalloc(strlen(src)+1);
+    strcpy(tmp, src);
+    return tmp;
+}
+
+
+
+char *xstrcat(char *src, char *add)
+{
+    char    *tmp;
+    size_t  size = 0;
+
+    if ((add == NULL) || (strlen(add) == 0))
+	return src;
+    if (src)
+	size = strlen(src);
+    size += strlen(add);
+    tmp = xmalloc(size + 1);
+    *tmp = '\0';
+    if (src) {
+	strcpy(tmp, src);
+	free(src);
+    }
+    strcat(tmp, add);
+    return tmp;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewco/xutil.h	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,8 @@
+#ifndef XUTIL_H
+#define	XUTIL_H
+
+char *xmalloc(size_t);
+char *xstrcpy(char *);
+char *xstrcat(char *, char *);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewpanel/Makefile	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,63 @@
+# Makefile for the mbsePi-apps/brewpanel.
+
+include ../Makefile.global
+
+SRCS		= $(wildcard *.c)
+HDRS		= $(wildcard *.h)
+OBJS		= lcdfont10x16.h $(SRCS:.c=.o)
+SLIBS		=
+TARGET		= brewpanel
+OTHER		= Makefile lcdfont5x8.bmp
+
+#############################################################################
+
+.c.o:
+		${CC} ${CFLAGS} ${SDL_CFLAGS} ${INCLUDES} ${DEFINES} -c $<
+
+all:		${TARGET}
+
+brewpanel:	${OBJS} ${SLIBS}
+		${CC} -o ${TARGET} ${OBJS} ${LDFLAGS} ${LIBS} ${SDL_LIBS} ${SLIBS}
+
+lcdfont10x16.h:	lcdfont5x8.bmp
+		convert -scale 160x256 lcdfont5x8.bmp xbm:lcdfont10x16.h
+
+clean:
+		rm -f ${TARGET} *.o *.h~ *.c~ lcdfont5x8.h lcdfont10x16.h core filelist Makefile.bak
+
+install:	all
+		${INSTALL} -c -s -g root -o root -m 0755 brewpanel ${BINDIR}
+
+filelist:	Makefile
+		BASE=`pwd`; \
+		BASE=`basename $${BASE}`; \
+		(for f in ${SRCS} ${HDRS} ${OTHER} ;do echo ${PACKAGE}-${VERSION}/$${BASE}/$$f; done) >filelist
+
+depend:
+	@rm -f Makefile.bak; \
+	mv Makefile Makefile.bak; \
+	sed -e '/^# DO NOT DELETE/,$$d' Makefile.bak >Makefile; \
+	${ECHO} '# DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT' \
+		>>Makefile; \
+	${ECHO} '# Dependencies generated by make depend' >>Makefile; \
+	for f in ${SRCS}; \
+	do \
+		${ECHO} "Dependencies for $$f:\c"; \
+		${ECHO} "`basename $$f .c`.o:\c" >>Makefile; \
+		for h in `sed -n -e \
+			's/^#[ 	]*include[ 	]*"\([^"]*\)".*/\1/p' $$f`; \
+		do \
+			${ECHO} " $$h\c"; \
+			${ECHO} " $$h\c" >>Makefile; \
+		done; \
+		${ECHO} " done."; \
+		${ECHO} "" >>Makefile; \
+	done; \
+	${ECHO} '# End of generated dependencies' >>Makefile
+
+# DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT
+# Dependencies generated by make depend
+sdlgui.o: brewpanel.h sdlgui.h lcdfont10x16.h
+dlgBrew.o: brewpanel.h dlgBrew.h sdlgui.h
+brewpanel.o: brewpanel.h sdlgui.h dlgBrew.h
+# End of generated dependencies
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewpanel/brewpanel.c	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,164 @@
+/*****************************************************************************
+ * Copyright (C) 2015
+ *   
+ * Michiel Broek <mbroek at mbse dot eu>
+ *
+ * This file is part of the mbsePi-apps
+ *
+ * This 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, or (at your option) any
+ * later version.
+ *
+ * mbsePi-apps 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 ThermFerm; see the file COPYING.  If not, write to the Free
+ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *****************************************************************************/
+
+#include "brewpanel.h"
+#include "sdlgui.h"
+#include "dlgBrew.h"
+
+
+int			DebugPanel = FALSE;		/* Logfile debugging		*/
+int			debug = FALSE;			/* Console debugging		*/
+int			my_shutdown = FALSE;		/* Shutdown requested		*/
+char			*Paneltype = NULL;		/* Panel to emulate		*/
+int			PAN_x;				/* Screen X size		*/
+int			PAN_y;				/* Screen Y size		*/
+
+int			LCD_fcol;			/* LCD foreground color		*/
+int			LCD_bcol;			/* LCD background color		*/
+
+SDL_Surface		*PAN_surface = NULL;		/* Main surface			*/
+
+
+void help(void)
+{
+    fprintf(stdout, "Usage: brewpanel [-d] [-h] [-p <paneltype>]\n");
+    fprintf(stdout, "  -d --debug                    Debug on\n");
+    fprintf(stdout, "  -h --help                     Display this help\n");
+    fprintf(stdout, "  -p --paneltype <ferm|brew>    Select machine, default last used\n");
+}
+
+
+
+void die(int onsig)
+{
+    switch (onsig) {
+	case SIGHUP:    syslog(LOG_NOTICE, "Got SIGHUP, shutting down");
+			break;
+	case SIGINT:    syslog(LOG_NOTICE, "Keyboard interrupt, shutting down");
+			break;
+	case SIGTERM:   syslog(LOG_NOTICE, "Got SIGTERM, shutting down");
+			break;
+	case SIGSEGV:   syslog(LOG_NOTICE, "Got SIGSEGV, shutting down");
+			my_shutdown = TRUE;
+			exit(SIGSEGV);
+			break;
+	default:        syslog(LOG_NOTICE, "die() on signal %d", onsig);
+    }
+
+    my_shutdown = TRUE;
+}
+
+
+
+int main(int argc, char *argv[])
+{
+    int		i, rc = 0, c, max_x = 0, max_y = 0;
+    SDL_Rect	**modes;
+    char	title[81];
+
+    Paneltype = calloc(128, sizeof(char));
+
+    while (1) {
+	int option_index = 0;
+	static struct option long_options[] = {
+	    {"debug", 0, 0, 'c'},
+	    {"help", 0, 0, 'h'},
+	    {"paneltype", 1, 0, 'p'},
+	    {0, 0, 0, 0}
+	};
+
+	c = getopt_long(argc, argv, "dhp:", long_options, &option_index);
+	if (c == -1)
+	    break;
+
+	switch (c) {
+	    case 'd':   DebugPanel = TRUE;
+			break;
+	    case 'h':   help();
+			return 1;
+	    case 'p':   snprintf(Paneltype, 127, "%s", optarg);
+			break;
+	}
+    }
+
+    openlog("brewpanel", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_USER);
+    syslog(LOG_NOTICE, "mbsePi-apps brewpanel v%s starting", VERSION);
+    if (debug)
+	fprintf(stdout, "mbsePi-apps brewpanel v%s starting\n", VERSION);
+
+    /*
+     *  Catch all the signals we can, and ignore the rest. Note that SIGKILL can't be ignored
+     *  but that's live. This daemon should only be stopped by SIGTERM.
+     *  Don't catch SIGCHLD.
+     */
+    for (i = 0; i < NSIG; i++) {
+	if ((i != SIGCHLD) && (i != SIGKILL) && (i != SIGSTOP))
+	    signal(i, (void (*))die);
+    }
+
+    /* 
+     * Initialize defaults, Video and Audio
+     */
+    if ((SDL_Init(SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO) == -1)) { 
+	syslog(LOG_NOTICE, "[main] could not initialize SDL: %s", SDL_GetError());
+	exit(-1);
+    }
+
+    modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
+    if (modes != (SDL_Rect **)0) {
+	/* Check if our resolution is restricted */
+	if (modes == (SDL_Rect **)-1) {
+	    syslog(LOG_NOTICE, "SDL all resolutions available.\n");
+	} else {
+	    max_x = modes[0]->w;
+	    max_y = modes[0]->h;
+	}
+    }
+
+    PAN_x = 384;
+    PAN_y = 480;
+
+fprintf(stdout, "Screen max X*Y: %d*%d panel X*Y: %d*%d\n", max_x, max_y, PAN_x, PAN_y);
+
+    PAN_surface = SDL_SetVideoMode( PAN_x, PAN_y, 32, SDL_SWSURFACE|SDL_DOUBLEBUF );
+    if (PAN_surface == NULL) {
+	syslog(LOG_NOTICE, "Could not create main surface: %s", SDL_GetError());
+	exit(-1);
+    }
+
+    SDLGui_Init();
+    snprintf(title, 80, "brewpanel v%s", VERSION);
+    SDL_WM_SetCaption(title, NULL);
+
+    syslog(LOG_NOTICE, "Starting mainloop");
+    Dialog_BrewDlg();
+    syslog(LOG_NOTICE, "Out of mainloop, cleanup");
+
+    SDLGui_UnInit();
+    SDL_FreeSurface(PAN_surface);
+    SDL_Quit();
+
+    syslog(LOG_NOTICE, "Finished, rc=%d", rc);
+    return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewpanel/brewpanel.h	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,30 @@
+#ifndef	_BREWPANEL_H
+#define	_BREWPANEL_H
+
+#define TRUE 1
+#define FALSE 0
+
+#include "../config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <getopt.h>
+
+#include <SDL.h>
+#include <SDL_ttf.h>
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewpanel/dlgBrew.c	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ * Copyright (C) 2015
+ *   
+ * Michiel Broek <mbroek at mbse dot eu>
+ *
+ * This file is part of the mbsePi-apps
+ *
+ * The gui code is based on the gui from the emulator ARAnyM,
+ * Copyright (c) 2004 Petr Stehlik of ARAnyM dev team
+ *
+ * mbsePi-apps 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, or (at your option) any
+ * later version.
+ *
+ * mbsePi-apps 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 mbsePi-apps; see the file COPYING.  If not, write to the Free
+ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *****************************************************************************/
+
+#include "brewpanel.h"
+#include "dlgBrew.h"
+#include "sdlgui.h"
+
+extern SDL_Surface	*PAN_surface;
+extern int		my_shutdown;
+
+
+#define	MAINDLG_B1	 2
+#define MAINDLG_B2	 3
+#define MAINDLG_B3	 4
+#define MAINDLG_B4	 5
+#define MAINDLG_QUIT     6
+
+
+/* The main dialog: */
+static SGOBJ maindlg[] =
+{
+/*        type      flags     state   x    y    w    h  txt  */
+	{ SGBOX,    0,           0,   0,   0, 374, 470, NULL },
+	{ SGLCD,    0,           0,  -1,  44,  20,   4, NULL },
+	{ SGBUTTON, 0,           0,  85, 130,  20,  20, (char *)"1" },
+	{ SGBUTTON, 0,           0, 145, 130,  20,  20, (char *)"2" },
+	{ SGBUTTON, 0,           0, 205, 130,  20,  20, (char *)"3" },
+	{ SGBUTTON, 0,           0, 265, 130,  20,  20, (char *)"4" },
+	{ SGBUTTON, 0,           0, 147, 430,  80,  20, (char *)"Quit" },
+	{ SGTTF,    0,           0,   5, 280,   0,   0, (char *)"The quick brown fox jumps over the lazy dog" },
+	{ -1,       0,           0,   0,   0,   0,   0, NULL }
+};
+
+
+
+
+/*
+ * This functions sets up the actual font and then displays the brew panel dialog.
+ */
+int Dialog_BrewDlg(void)
+{
+    int retbut;
+    int bOldMouseVisibility;
+    int nOldMouseX, nOldMouseY;
+
+    if (SDLGui_SetScreen(PAN_surface)) {
+	syslog(LOG_NOTICE, "SDLGui_SetScreen(PAN_surface) failed: %s", SDL_GetError());
+	return FALSE;
+    }
+
+    SDL_GetMouseState(&nOldMouseX, &nOldMouseY);
+    bOldMouseVisibility = SDL_ShowCursor(SDL_QUERY);
+    SDL_ShowCursor(SDL_ENABLE);
+
+    SDLGui_CenterDlg(maindlg);
+
+    do {
+	retbut = SDLGui_DoDialog(maindlg, NULL);
+ SDLGui_LCDwrite(maindlg, 0, 0, 'A', 0);
+
+	fprintf(stdout, "SDLGui_DoDialog retbut=%d\n", retbut);
+
+	switch (retbut) {
+	    case MAINDLG_B1:	fprintf(stdout, "Button 1\n");
+		    		break;
+	    case MAINDLG_B2:	fprintf(stdout, "Button 2\n");
+				break;
+	    case MAINDLG_B3:	fprintf(stdout, "Button 3\n");
+				break;
+	    case MAINDLG_B4:	fprintf(stdout, "Button 4\n");
+				break;
+	    case MAINDLG_QUIT:	my_shutdown = TRUE;
+				break;
+	}
+
+    } while (retbut != SDLGUI_QUIT && retbut != SDLGUI_ERROR && !my_shutdown);
+
+    SDL_ShowCursor(bOldMouseVisibility);
+
+    return TRUE;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewpanel/dlgBrew.h	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,7 @@
+#ifndef	_DLGBREW_H
+#define	_DLGBREW_H
+
+
+int Dialog_BrewDlg(void);
+
+#endif
Binary file brewpanel/lcdfont5x8.bmp has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewpanel/sdlgui.c	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,698 @@
+/*****************************************************************************
+ * Copyright (C) 2015
+ *   
+ * Michiel Broek <mbroek at mbse dot eu>
+ *
+ * This file is part of the mbsePi-apps emulator
+ *
+ * The gui code is based on the gui from the emulator ARAnyM,
+ * Copyright (c) 2004 Petr Stehlik of ARAnyM dev team
+ *
+ * This progrm 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, or (at your option) any
+ * later version.
+ *
+ * mbsePi-apps 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 mbsePi-apps; see the file COPYING.  If not, write to the Free
+ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *****************************************************************************/
+
+#include "brewpanel.h"
+#include "sdlgui.h"
+#include "lcdfont10x16.h"
+
+
+static SDL_Surface	*pSdlGuiScrn;            	/* Pointer to the actual main SDL screen surface 	*/
+static SDL_Surface	*pFontGfx = NULL;        	/* The LCD font graphics 				*/
+static int		fontwidth, fontheight;		/* Width & height of the actual font 			*/
+TTF_Font                *pFont = NULL;			/* TTF font for buttons etc.				*/
+
+extern int		my_shutdown;
+
+
+/*-----------------------------------------------------------------------*/
+/*
+ * Load an 1 plane XBM into a 8 planes SDL_Surface.
+ */
+static SDL_Surface *SDLGui_LoadXBM(int w, int h, const char *pXbmBits)
+{
+    SDL_Surface	*bitmap;
+    Uint8 	*dstbits;
+    const Uint8 *srcbits;
+    int		x, y, srcpitch, mask;
+
+    srcbits = (Uint8 *)pXbmBits;
+
+    /* Allocate the bitmap */
+    if ((bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0)) == NULL) {
+	syslog(LOG_NOTICE, "Failed to allocate bitmap: %s", SDL_GetError());
+	return NULL;
+    }
+
+    srcpitch = ((w + 7) / 8);
+    dstbits = (Uint8 *)bitmap->pixels;
+    mask = 1;
+
+    /* Copy the pixels */
+    for (y = 0 ; y < h ; y++) {
+	for (x = 0 ; x < w ; x++) {
+	    dstbits[x] = (srcbits[x / 8] & mask) ? 1 : 0;
+	    mask <<= 1;
+	    mask |= (mask >> 8);
+	    mask &= 0xFF;
+	}
+	dstbits += bitmap->pitch;
+	srcbits += srcpitch;
+    }
+
+    return bitmap;
+}
+
+
+
+/*
+ * Initialize the GUI.
+ */
+int SDLGui_Init(void)
+{
+    char	*Pt = NULL;
+
+    SDL_Color blackWhiteColors[2] = {{255, 255, 255, 0}, {0, 0, 0, 0}};
+
+    /* 
+     * Initialize the LCD font graphics: 
+     */
+    pFontGfx = SDLGui_LoadXBM(lcdfont10x16_width, lcdfont10x16_height, lcdfont10x16_bits);
+    if (pFontGfx == NULL) {
+	syslog(LOG_NOTICE, "Error: Can not init font graphics!");
+	return -1;
+    }
+
+    /* Set color palette of the LCD font graphics: */
+    SDL_SetColors(pFontGfx, blackWhiteColors, 0, 2);
+
+    /* Set font color 0 as transparent: */
+    SDL_SetColorKey(pFontGfx, (SDL_SRCCOLORKEY|SDL_RLEACCEL), 0);
+
+    if (TTF_Init() == -1) {
+	syslog(LOG_NOTICE, "Could not init SDL_ttf");
+	return -1;
+    }
+
+    /*
+     * Load TTF font for the dialogs
+     */
+    Pt = calloc(1024, sizeof(char));
+    sprintf(Pt, "%s", "/usr/share/fonts/TTF/DejaVuSans.ttf");
+    if ((pFont = TTF_OpenFont(Pt, 14 )) == NULL) {
+	sprintf(Pt, "%s", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf");
+	if ((pFont = TTF_OpenFont(Pt, 14 )) == NULL) {
+	    sprintf(Pt, "%s", "/usr/share/fonts/truetype/freefont/DejaVuSans.ttf");
+	    if ((pFont = TTF_OpenFont(Pt, 14 )) == NULL) {
+		syslog(LOG_NOTICE, "Could not load DejaVuSans.ttf");
+		return -1;
+	    }
+	}
+    }
+    syslog(LOG_NOTICE, "Using ttf font: %s\n", Pt);
+    free(Pt);
+    Pt = NULL;
+
+    return 0;
+}
+
+
+
+/*
+ * Uninitialize the GUI.
+ */
+int SDLGui_UnInit(void)
+{
+    if (pFont)
+    	TTF_CloseFont(pFont);
+    pFont = NULL;
+
+    if (pFontGfx)
+	SDL_FreeSurface(pFontGfx);
+    pFontGfx = NULL;
+
+    return 0;
+}
+
+
+
+/*
+ * Inform the SDL-GUI about the actual SDL_Surface screen pointer and
+ * prepare the font to suit the actual resolution.
+ */
+int SDLGui_SetScreen(SDL_Surface *pScrn)
+{
+    pSdlGuiScrn = pScrn;
+
+    if (pFontGfx == NULL) {
+	syslog(LOG_NOTICE, "Error: A problem with the font occured!");
+	return -1;
+    }
+
+    /* Get the font width and height: */
+    fontwidth = pFontGfx->w/16;
+    fontheight = pFontGfx->h/16;
+    
+    return 0;
+}
+
+
+
+/*
+ * Center a dialog so that it appears in the middle of the screen.
+ * Note: We only store the coordinates in the root box of the dialog,
+ * all other objects in the dialog are positioned relatively to this one.
+ */
+void SDLGui_CenterDlg(SGOBJ *dlg)
+{
+    dlg[0].x = (pSdlGuiScrn->w/1-dlg[0].w)/2;
+    dlg[0].y = (pSdlGuiScrn->h/1-dlg[0].h)/2;
+}
+
+
+
+/*
+ * Draw a text string using TTF
+ */
+static void SDLGui_TTF(int x, int y, const char *txt)
+{
+    SDL_Rect    	offset;
+    SDL_Color		textColor = { 0, 0, 0 };
+    SDL_Surface*	message = NULL;
+
+    message = TTF_RenderText_Solid(pFont, txt, textColor);
+    offset.x = x;
+    offset.y = y;
+    SDL_BlitSurface(message, NULL, pSdlGuiScrn, &offset);
+    SDL_FreeSurface(message);
+    message = NULL;
+}
+
+
+
+/*
+ * Draw a dialog TTF text object.
+ */
+static void SDLGui_DrawTTF(const SGOBJ *tdlg, int objnum)
+{
+    int         x, y;
+
+    x = (tdlg[0].x + tdlg[objnum].x);
+    y = (tdlg[0].y + tdlg[objnum].y);
+    SDLGui_TTF(x, y, tdlg[objnum].txt);
+}
+
+
+
+/*
+ * Draw a text string.
+ */
+static void SDLGui_Text(int x, int y, const char *txt)
+{
+    int		i;
+    char	c;
+    SDL_Rect	sr, dr;
+
+    for (i=0; txt[i]!=0; i++) {
+	c = txt[i];
+	sr.x=fontwidth*(c%16);
+	sr.y=fontheight*(c/16);
+	sr.w=fontwidth;
+	sr.h=fontheight;
+	dr.x=x+i*(fontwidth+2);
+	dr.y=y;
+	dr.w=fontwidth;
+	dr.h=fontheight;
+	SDL_BlitSurface(pFontGfx, &sr, pSdlGuiScrn, &dr);
+    }
+}
+
+
+
+/*
+ * Draw a dialog text object.
+ */
+static void SDLGui_DrawText(const SGOBJ *tdlg, int objnum)
+{
+    int		x, y;
+
+    x = (tdlg[0].x + tdlg[objnum].x);
+    y = (tdlg[0].y + tdlg[objnum].y);
+    SDLGui_Text(x, y, tdlg[objnum].txt);
+}
+
+
+
+/*
+ * Draw a dialog LCD object.
+ */
+static void SDLGui_DrawLCD(const SGOBJ *bdlg, int objnum)
+{
+    SDL_Rect    rect;
+    int         x, y, w, h, offset, border = 4;
+    Uint32      bg0 = SDL_MapRGB(pSdlGuiScrn->format, 94,147, 69);
+    Uint32	bg1 = SDL_MapRGB(pSdlGuiScrn->format,156,235,  4);
+    Uint32	bc  = SDL_MapRGB(pSdlGuiScrn->format, 32, 32, 32);
+    Uint32      bg;
+
+    /*
+     * Width and height are given in character columns and rows,
+     * so calculate the display size in pixels.
+     */
+    w = bdlg[objnum].w * (fontwidth + 2) + 10;
+    h = bdlg[objnum].h * (fontheight + 2) + 4;
+
+    if (bdlg[objnum].x == -1) {
+	/*
+	 * Auto center
+	 */
+	x = (bdlg[0].w - w) / 2;
+    } else {
+    	x = bdlg[objnum].x;
+    }
+    y = bdlg[objnum].y;
+    if (objnum > 0) {           /* Since the root object is a box, too, */
+	/* we have to look for it now here and only */
+	x += bdlg[0].x;         /* add its absolute coordinates if we need to */
+	y += bdlg[0].y;
+    }
+
+    if (bdlg[objnum].state & SG_SELECTED) {
+	bg = bg1;
+    } else {
+	bg = bg0;
+    }
+
+    /* The root box should be bigger than the screen, so we disable the offset there: */
+    if (objnum != 0)
+	offset = border;
+    else
+	offset = 0;
+
+    /* Draw background: */
+    rect.x = x;
+    rect.y = y;
+    rect.w = w;
+    rect.h = h;
+    SDL_FillRect(pSdlGuiScrn, &rect, bg);
+
+    /* Draw upper border: */
+    rect.x = x - offset;
+    rect.y = y - offset;
+    rect.w = w + offset + offset;
+    rect.h = border;
+    SDL_FillRect(pSdlGuiScrn, &rect, bc);
+
+    /* Draw left border: */
+    rect.x = x - offset;
+    rect.y = y;
+    rect.w = border;
+    rect.h = h;
+    SDL_FillRect(pSdlGuiScrn, &rect, bc);
+
+    /* Draw bottom border: */
+    rect.x = x - offset;
+    rect.y = y + h - border + offset;
+    rect.w = w + offset + offset;
+    rect.h = border;
+    SDL_FillRect(pSdlGuiScrn, &rect, bc);
+
+    /* Draw right border: */
+    rect.x = x + w - border + offset;
+    rect.y = y;
+    rect.w = border;
+    rect.h = h;
+    SDL_FillRect(pSdlGuiScrn, &rect, bc);
+}
+
+
+
+/*
+ * Draw a dialog box object.
+ */
+static void SDLGui_DrawBox(const SGOBJ *bdlg, int objnum)
+{
+    SDL_Rect	rect;
+    int		x, y, w, h, offset, shade = 2;
+    Uint32	grey = SDL_MapRGB(pSdlGuiScrn->format,192,192,192);
+    Uint32	upleftc, downrightc;
+
+    x = bdlg[objnum].x;
+    y = bdlg[objnum].y;
+    if (objnum > 0) {		/* Since the root object is a box, too, */
+	/* we have to look for it now here and only */
+	x += bdlg[0].x;		/* add its absolute coordinates if we need to */
+	y += bdlg[0].y;
+    }
+    w = bdlg[objnum].w;
+    h = bdlg[objnum].h;
+
+    if (bdlg[objnum].state & SG_SELECTED) {
+	upleftc = SDL_MapRGB(pSdlGuiScrn->format,128,128,128);
+	downrightc = SDL_MapRGB(pSdlGuiScrn->format,255,255,255);
+    } else {
+	upleftc = SDL_MapRGB(pSdlGuiScrn->format,255,255,255);
+	downrightc = SDL_MapRGB(pSdlGuiScrn->format,128,128,128);
+    }
+
+    /* The root box should be bigger than the screen, so we disable the offset there: */
+    if (objnum != 0)
+	offset = shade;
+    else
+	offset = 0;
+
+    /* Draw background: */
+    rect.x = x;
+    rect.y = y;
+    rect.w = w;
+    rect.h = h;
+    SDL_FillRect(pSdlGuiScrn, &rect, grey);
+
+    /* Draw upper border: */
+    rect.x = x;
+    rect.y = y - offset;
+    rect.w = w;
+    rect.h = shade;
+    SDL_FillRect(pSdlGuiScrn, &rect, upleftc);
+
+    /* Draw left border: */
+    rect.x = x - offset;
+    rect.y = y;
+    rect.w = shade;
+    rect.h = h;
+    SDL_FillRect(pSdlGuiScrn, &rect, upleftc);
+
+    /* Draw bottom border: */
+    rect.x = x;
+    rect.y = y + h - shade + offset;
+    rect.w = w;
+    rect.h = shade;
+    SDL_FillRect(pSdlGuiScrn, &rect, downrightc);
+
+    /* Draw right border: */
+    rect.x = x + w - shade + offset;
+    rect.y = y;
+    rect.w = shade;
+    rect.h = h;
+    SDL_FillRect(pSdlGuiScrn, &rect, downrightc);
+}
+
+
+
+/*
+ * Draw a normal button.
+ */
+static void SDLGui_DrawButton(const SGOBJ *bdlg, int objnum)
+{
+    int		x, y, w, h;
+
+    SDLGui_DrawBox(bdlg, objnum);
+    /*
+     * Use bold text and get outer dimensions of the text
+     */
+    TTF_SetFontStyle(pFont, TTF_STYLE_BOLD);
+    TTF_SizeText(pFont, bdlg[objnum].txt, &w, &h);
+    x = bdlg[0].x + bdlg[objnum].x + (bdlg[objnum].w - w) / 2;
+    y = bdlg[0].y + bdlg[objnum].y + (bdlg[objnum].h - h) / 2;
+
+    if (bdlg[objnum].state & SG_SELECTED) {
+	x += 1;
+	y += 1;
+    }
+
+    if ((bdlg[objnum].flags & SG_HIDE) == 0)
+	SDLGui_TTF(x, y, bdlg[objnum].txt);
+    TTF_SetFontStyle(pFont, TTF_STYLE_NORMAL);
+}
+
+
+
+/*
+ * Draw a whole dialog.
+ */
+void SDLGui_DrawDialog(const SGOBJ *dlg)
+{
+    int i;
+	
+    for (i = 0; dlg[i].type != -1; i++) {
+	switch (dlg[i].type) {
+	    case SGBOX:
+			SDLGui_DrawBox(dlg, i);
+			break;
+	    case SGLCD:
+			SDLGui_DrawLCD(dlg, i);
+			break;
+	    case SGTEXT:
+			SDLGui_DrawText(dlg, i);
+			break;
+	    case SGTTF:
+			SDLGui_DrawTTF(dlg, i);
+			break;
+	    case SGBUTTON:
+			SDLGui_DrawButton(dlg, i);
+			break;
+	}
+    }
+
+    SDL_UpdateRect(pSdlGuiScrn, 0,0,0,0);
+}
+
+
+
+/*
+ * Search an object at a certain position.
+ */
+static int SDLGui_FindObj(const SGOBJ *dlg, int fx, int fy)
+{
+    int		len, i, ob = -1, xpos, ypos;
+
+    len = 0;
+    while (dlg[len].type != -1)
+	len++;
+
+    xpos = fx;
+    ypos = fy;
+    /* Now search for the object: */
+    for (i = len; i >= 0; i--) {
+	if (xpos >= dlg[0].x + dlg[i].x && ypos >= dlg[0].y + dlg[i].y && 
+	    xpos < dlg[0].x + dlg[i].x + dlg[i].w && ypos < dlg[0].y + dlg[i].y + dlg[i].h) {
+	    ob = i;
+	    break;
+	}
+    }
+	
+    return ob;
+}
+
+
+
+/*
+ * Search a button with a special flag (e.g. SG_DEFAULT or SG_CANCEL).
+ */
+static int SDLGui_SearchFlaggedButton(const SGOBJ *dlg, int flag)
+{
+    int i = 0;
+
+    while (dlg[i].type != -1) {
+	if (dlg[i].flags & flag)
+	    return i;
+	i++;
+    }
+
+    return 0;
+}
+
+
+
+/*
+ * Show and process a dialog. Returns the button number that has been
+ * pressed or SDLGUI_UNKNOWNEVENT if an unsupported event occured (will be
+ * stored in parameter pEventOut).
+ */
+int SDLGui_DoDialog(SGOBJ *dlg, SDL_Event *pEventOut)
+{
+    int		obj = 0, oldbutton = 0, retbutton = 0, i, j, b;
+    SDL_Event	sdlEvent;
+    SDL_Surface	*pBgSurface;
+    SDL_Rect	dlgrect, bgrect;
+
+//	if (pSdlGuiScrn->h / fontheight < dlg[0].h)
+//	{
+//		syslog(LOG_NOTICE, "Screen size too small for dialog!");
+//		return SDLGUI_ERROR;
+//	}
+
+    dlgrect.x = dlg[0].x;
+    dlgrect.y = dlg[0].y;
+    dlgrect.w = dlg[0].w;
+    dlgrect.h = dlg[0].h;
+
+    bgrect.x = bgrect.y = 0;
+    bgrect.w = dlgrect.w;
+    bgrect.h = dlgrect.h;
+
+    /*
+     * Save background
+     */
+    pBgSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, dlgrect.w, dlgrect.h, pSdlGuiScrn->format->BitsPerPixel,
+	                                  pSdlGuiScrn->format->Rmask, pSdlGuiScrn->format->Gmask, pSdlGuiScrn->format->Bmask, pSdlGuiScrn->format->Amask);
+    if (pSdlGuiScrn->format->palette != NULL) {
+	SDL_SetColors(pBgSurface, pSdlGuiScrn->format->palette->colors, 0, pSdlGuiScrn->format->palette->ncolors-1);
+    }
+
+    if (pBgSurface != NULL) {
+	SDL_BlitSurface(pSdlGuiScrn,  &dlgrect, pBgSurface, &bgrect);
+    } else {
+	syslog(LOG_NOTICE, "SDLGUI_DoDialog: CreateRGBSurface failed: %s", SDL_GetError());
+    }
+
+    /* (Re-)draw the dialog */
+    SDLGui_DrawDialog(dlg);
+
+    /* 
+     * Is the left mouse button still pressed? Yes -> Handle TOUCHEXIT objects here
+     */
+    SDL_PumpEvents();
+    b = SDL_GetMouseState(&i, &j);
+    obj = SDLGui_FindObj(dlg, i, j);
+    if (obj > 0 && (dlg[obj].flags & SG_TOUCHEXIT) ) {
+	oldbutton = obj;
+	if (b & SDL_BUTTON(1)) {
+	    dlg[obj].state |= SG_SELECTED;
+	    retbutton = obj;
+	}
+    }
+
+    /* The main loop */
+    while (retbutton == 0 && !my_shutdown) {
+	if (SDL_WaitEvent(&sdlEvent) == 1)  /* Wait for events */
+	    switch (sdlEvent.type) {
+		case SDL_QUIT:
+				retbutton = SDLGUI_QUIT;
+				break;
+
+		case SDL_MOUSEBUTTONDOWN:
+				if (sdlEvent.button.button != SDL_BUTTON_LEFT) {
+				    /* Not left mouse button -> unsupported event */
+				    if (pEventOut)
+					retbutton = SDLGUI_UNKNOWNEVENT;
+				    break;
+				}
+				/* It was the left button: Find the object under the mouse cursor */
+				obj = SDLGui_FindObj(dlg, sdlEvent.button.x, sdlEvent.button.y);
+				if (obj > 0) {
+				    if (dlg[obj].type == SGBUTTON) {
+					dlg[obj].state |= SG_SELECTED;
+					SDLGui_DrawButton(dlg, obj);
+					SDL_UpdateRect(pSdlGuiScrn, dlg[0].x + dlg[obj].x - 2, dlg[0].y + dlg[obj].y - 2, dlg[obj].w + 4, dlg[obj].h + 4);
+					oldbutton=obj;
+				    }
+				    if ( dlg[obj].flags & SG_TOUCHEXIT ) {
+					dlg[obj].state |= SG_SELECTED;
+					retbutton = obj;
+				    }
+				}
+				break;
+
+			 case SDL_MOUSEBUTTONUP:
+				if (sdlEvent.button.button != SDL_BUTTON_LEFT) {
+				    /* Not left mouse button -> unsupported event */
+				    if (pEventOut)
+					retbutton = SDLGUI_UNKNOWNEVENT;
+				    break;
+				}
+				/* It was the left button: Find the object under the mouse cursor */
+				obj = SDLGui_FindObj(dlg, sdlEvent.button.x, sdlEvent.button.y);
+				if (obj > 0) {
+				    switch (dlg[obj].type) {
+					case SGBUTTON:
+						if (oldbutton==obj)
+						    retbutton=obj;
+						break;
+				    }
+				}
+				if (oldbutton > 0) {
+				    dlg[oldbutton].state &= ~SG_SELECTED;
+				    SDLGui_DrawButton(dlg, oldbutton);
+				    SDL_UpdateRect(pSdlGuiScrn, (dlg[0].x+dlg[oldbutton].x)*fontwidth-2, (dlg[0].y+dlg[oldbutton].y)*fontheight-2,
+						dlg[oldbutton].w*fontwidth+4, dlg[oldbutton].h*fontheight+4);
+				    oldbutton = 0;
+				}
+				if (obj >= 0 && (dlg[obj].flags & SG_EXIT)) {
+				    retbutton = obj;
+				}
+				break;
+
+			 case SDL_MOUSEMOTION:
+				break;
+
+			 case SDL_KEYDOWN:                     /* Key pressed */
+				if (sdlEvent.key.keysym.sym == SDLK_RETURN || sdlEvent.key.keysym.sym == SDLK_KP_ENTER) {
+				    retbutton = SDLGui_SearchFlaggedButton(dlg, SG_DEFAULT);
+				} else if (sdlEvent.key.keysym.sym == SDLK_ESCAPE) {
+				    retbutton = SDLGui_SearchFlaggedButton(dlg, SG_CANCEL);
+				} else if (pEventOut) {
+				    retbutton = SDLGUI_UNKNOWNEVENT;
+				}
+				break;
+
+			 default:
+				if (pEventOut)
+				    retbutton = SDLGUI_UNKNOWNEVENT;
+				break;
+	    }
+    }
+
+    /* Restore background */
+    if (pBgSurface) {
+	SDL_BlitSurface(pBgSurface, &bgrect, pSdlGuiScrn,  &dlgrect);
+	SDL_FreeSurface(pBgSurface);
+    }
+
+    /* Copy event data of unsupported events if caller wants to have it */
+    if (retbutton == SDLGUI_UNKNOWNEVENT && pEventOut)
+	memcpy(pEventOut, &sdlEvent, sizeof(SDL_Event));
+
+    if (retbutton == SDLGUI_QUIT)
+	my_shutdown = TRUE;
+
+    return retbutton;
+}
+
+
+
+void SDLGui_LCDwrite(SGOBJ *dlg, int x, int y, Uint8 c, int lcdindex)
+{
+    int		i, index;
+
+    fprintf(stdout, "SDLGui_LCDwrite( , %d, %d, %c, %d)\n", x, y, c, lcdindex);
+
+    i = index = 0;
+    for (;;) {
+	if (dlg[i].type == -1) {
+	    syslog(LOG_NOTICE, "SDLGui_LCDwrite() lcdindex=%d not found", lcdindex);
+	    return;
+	}
+	if (dlg[i].type == SGLCD) {
+	    if (index == lcdindex)
+		break;
+	    index++;
+	}
+	i++;
+    }
+    fprintf(stdout, "SDLGui_LCDwrite i=%d LCD=%dx%d\n", i, dlg[i].w, dlg[i].h);
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewpanel/sdlgui.h	Sat Nov 07 22:04:17 2015 +0100
@@ -0,0 +1,56 @@
+#ifndef _SDLGUI_H
+#define _SDLGUI_H
+
+//#include <SDL.h>
+
+enum
+{
+  SGBOX,
+  SGTEXT,
+  SGTTF,
+  SGBUTTON,
+  SGLCD
+};
+
+
+/* Object flags: */
+#define SG_TOUCHEXIT		 1   /* Exit immediately when mouse button is pressed down */
+#define SG_EXIT			 2   /* Exit when mouse button has been pressed (and released) */
+#define SG_DEFAULT		 4   /* Marks a default button, selectable with return key */
+#define SG_CANCEL		 8   /* Marks a cancel button, selectable with ESC key */
+#define SG_HIDE			16   /* Button is inactive */
+
+/* Object states: */
+#define SG_SELECTED		 1
+#define	SG_LCD_BLINK		 2
+#define	SG_LCD_CURSOR		 4
+#define	SG_LCD_DISPLAY		 8
+#define	SG_LCD_BLIGHT		16
+
+/* Return codes: */
+#define SDLGUI_ERROR		-1
+#define SDLGUI_QUIT		-2
+#define SDLGUI_UNKNOWNEVENT	-3
+
+
+typedef struct
+{
+    int		type;			/* What type of object */
+    int		flags;			/* Object flags */
+    int		state;			/* Object state */
+    int		x, y;			/* The offset to the upper left corner */
+    int		w, h;			/* Width and height */
+    char	*txt;			/* Text string */
+}  SGOBJ;
+
+
+
+int  SDLGui_Init(void);
+int  SDLGui_UnInit(void);
+int  SDLGui_SetScreen(SDL_Surface *pScrn);
+void SDLGui_DrawDialog(const SGOBJ *dlg);
+int  SDLGui_DoDialog(SGOBJ *dlg, SDL_Event *pEventOut);
+void SDLGui_CenterDlg(SGOBJ *dlg);
+void SDLGui_LCDwrite(SGOBJ *dlg, int x, int y, Uint8 c, int lcdindex);
+
+#endif
--- a/config.h.in	Mon Oct 05 15:21:46 2015 +0200
+++ b/config.h.in	Sat Nov 07 22:04:17 2015 +0100
@@ -14,3 +14,6 @@
 
 /* Define if you have the <wiringPi.h> header file. */
 #undef HAVE_WIRINGPI_H
+
+/* Define if you have the <SDL/SDL.h> header file. */
+#undef HAVE_SDL_SDL_H
--- a/configure	Mon Oct 05 15:21:46 2015 +0200
+++ b/configure	Sat Nov 07 22:04:17 2015 +0100
@@ -622,7 +622,8 @@
 
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
-CXXFLAGS
+SDL_LIBS
+SDL_CFLAGS
 EGREP
 GREP
 CPP
@@ -2030,11 +2031,11 @@
 
 ac_config_headers="$ac_config_headers config.h"
 
-SUBDIRS="dht11 rc433 thermferm"
+SUBDIRS="dht11 rc433 thermferm brewco brewpanel"
 
 
 PACKAGE="mbsePi-apps"
-VERSION="0.4.3"
+VERSION="0.5.0"
 COPYRIGHT="Copyright (C) 2014-2015 Michiel Broek, All Rights Reserved"
 CYEARS="2014-2015"
 
@@ -3674,6 +3675,63 @@
   as_fn_error $? "libuuid not found" "$LINENO" 5
 fi
 
+# Check for SDL
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking SDL library" >&5
+$as_echo_n "checking SDL library... " >&6; }
+pkg-config --exists sdl
+if test "$?" = "0"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  as_fn_error $? "no" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking sdl library v1.2.0 or newer" >&5
+$as_echo_n "checking sdl library v1.2.0 or newer... " >&6; }
+pkg-config --atleast-version=1.2.0 sdl
+if test "$?" = "0"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
+$as_echo "found" >&6; }
+else
+  as_fn_error $? "not found" "$LINENO" 5
+fi
+SDL_CFLAGS="$(pkg-config --cflags sdl)"
+SDL_LIBS="$(pkg-config --libs sdl)"
+for ac_header in SDL/SDL.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "SDL/SDL.h" "ac_cv_header_SDL_SDL_h" "$ac_includes_default"
+if test "x$ac_cv_header_SDL_SDL_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SDL_SDL_H 1
+_ACEOF
+
+fi
+
+done
+
+
+# Check for SDL_ttf
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking SDL_ttf library" >&5
+$as_echo_n "checking SDL_ttf library... " >&6; }
+pkg-config --exists SDL_ttf
+if test "$?" = "0"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  as_fn_error $? "no" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking sdl library v2.0.0 or newer" >&5
+$as_echo_n "checking sdl library v2.0.0 or newer... " >&6; }
+pkg-config --atleast-version=2.0.0 SDL_ttf
+if test "$?" = "0"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
+$as_echo "found" >&6; }
+else
+  as_fn_error $? "not found" "$LINENO" 5
+fi
+# Override flags
+SDL_CFLAGS="$(pkg-config --cflags SDL_ttf)"
+SDL_LIBS="$(pkg-config --libs SDL_ttf)"
+
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
 $as_echo_n "checking for ANSI C header files... " >&6; }
@@ -3791,6 +3849,7 @@
 
 
 
+
 ac_config_files="$ac_config_files Makefile.global"
 
 cat >confcache <<\_ACEOF
--- a/configure.ac	Mon Oct 05 15:21:46 2015 +0200
+++ b/configure.ac	Sat Nov 07 22:04:17 2015 +0100
@@ -2,13 +2,13 @@
 
 AC_INIT(thermferm/thermferm.c)
 AM_CONFIG_HEADER(config.h)
-SUBDIRS="dht11 rc433 thermferm"
+SUBDIRS="dht11 rc433 thermferm brewco brewpanel"
 AC_SUBST(SUBDIRS)
 
 dnl General settings
 dnl After changeing the version number, run autoconf!
 PACKAGE="mbsePi-apps"
-VERSION="0.4.3"
+VERSION="0.5.0"
 COPYRIGHT="Copyright (C) 2014-2015 Michiel Broek, All Rights Reserved"
 CYEARS="2014-2015"
 AC_SUBST(PACKAGE)
@@ -81,12 +81,51 @@
   AC_MSG_ERROR(libuuid not found)
 fi
 
+# Check for SDL
+AC_MSG_CHECKING(SDL library)
+pkg-config --exists sdl
+if test "$?" = "0"; then
+  AC_MSG_RESULT(yes)
+else
+  AC_MSG_ERROR(no)
+fi
+AC_MSG_CHECKING(sdl library v1.2.0 or newer)
+pkg-config --atleast-version=1.2.0 sdl
+if test "$?" = "0"; then
+  AC_MSG_RESULT(found)
+else
+  AC_MSG_ERROR(not found)
+fi
+SDL_CFLAGS="$(pkg-config --cflags sdl)"
+SDL_LIBS="$(pkg-config --libs sdl)"
+AC_CHECK_HEADERS(SDL/SDL.h)
+
+# Check for SDL_ttf
+AC_MSG_CHECKING(SDL_ttf library)
+pkg-config --exists SDL_ttf
+if test "$?" = "0"; then
+  AC_MSG_RESULT(yes)
+else
+  AC_MSG_ERROR(no)
+fi
+AC_MSG_CHECKING(sdl library v2.0.0 or newer)
+pkg-config --atleast-version=2.0.0 SDL_ttf
+if test "$?" = "0"; then
+  AC_MSG_RESULT(found)
+else
+  AC_MSG_ERROR(not found)
+fi
+# Override flags
+SDL_CFLAGS="$(pkg-config --cflags SDL_ttf)"
+SDL_LIBS="$(pkg-config --libs SDL_ttf)"
+
 
 dnl Checks for header files.
 AC_HEADER_STDC
 
+AC_SUBST(SDL_CFLAGS)
+AC_SUBST(SDL_LIBS)
 
-AC_SUBST(CXXFLAGS)
 
 AC_OUTPUT(
     Makefile.global

mercurial