brewco/rdconfig.c

Sat, 12 Dec 2015 19:31:35 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Sat, 12 Dec 2015 19:31:35 +0100
changeset 455
f84501d8dd87
parent 450
8fe99759c27f
child 464
4a624c071ca9
permissions
-rw-r--r--

Most parts of the simulator are working, needs some tuning.

/*****************************************************************************
 * 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 "util.h"
#include "xutil.h"

int		debug = TRUE;
sys_config	Config;			/* System configuration		*/

#define MY_ENCODING "utf-8"

const char	TEMPSTATE[3][8] = { "OK", "MISSING", "ERROR" };
const char	DEVTYPE[6][5] = { "NA", "W1", "GPIO", "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	WHIRLPOOL_TYPE[3][5] = { "OFF", "COLD", "HOT" };
const char	PIDDIRECTION[2][8] = { "DIRECT", "REVERSE" };
const char	PIDMODE[2][10] = { "MANUAL", "AUTOMATIC" };


void killconfig(void)
{
    units_list          *unit;
    devices_list        *device;

    if (Config.name)
	free(Config.name);
    Config.name = NULL;

    Config.my_port = 6554;
    Config.tempFormat = 'C';
    if (Config.roomtemp)
        free(Config.roomtemp);
    Config.roomtemp = NULL;
    Config.lcd_cols = 20;
    Config.lcd_rows = 4;

    for (unit = Config.units; unit; unit = unit->next) {
        if (unit->uuid)
            free(unit->uuid);
        if (unit->name)
            free(unit->name);
        if (unit->hlt_sensor.uuid)
            free(unit->hlt_sensor.uuid);
        if (unit->mlt_sensor.uuid)
            free(unit->mlt_sensor.uuid);
        if (unit->hlt_heater.uuid)
            free(unit->hlt_heater.uuid);
        if (unit->mlt_heater.uuid)
            free(unit->mlt_heater.uuid);
        if (unit->mlt_pump.uuid)
            free(unit->mlt_pump.uuid);
	if (unit->PID_hlt)
	    free(unit->PID_hlt);
	if (unit->PID_mlt)
	    free(unit->PID_mlt);
        free(unit);
    }
    Config.units = NULL;

    for (device = Config.devices; device; device = device->next) {
        if (device->uuid)
            free(device->uuid);
        if (device->address)
            free(device->address);
        if (device->description)
            free(device->description);
        if (device->comment)
            free(device->comment);
        free(device);
    }
    Config.devices = NULL;

#ifdef USE_SIMULATOR
    if (Config.simulator)
	free(Config.simulator);
    Config.simulator = NULL;
#endif
}



int do_wrconfig(void);
int do_wrconfig(void)
{
    int			rc = 0;
    FILE		*fp;
    char		*mypath = NULL;
    xmlTextWriterPtr	writer;
    xmlBufferPtr	buf;
    units_list		*unit;
    devices_list	*device;

    /* 
     * 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 "LISTEN_PORT", "%d", Config.my_port)) < 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 (Config.roomtemp) {
    	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROOMTEMP_UUID", "%s", Config.roomtemp->uuid)) < 0) {
            syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
            return 1;
    	}
    	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROOMTEMP_STATE", "%d", Config.roomtemp->state)) < 0) {
            syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
            return 1;                           
    	}
    	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROOMTEMP_VALUE", "%d", Config.roomtemp->value)) < 0) {
            syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
            return 1;
    	}
    }

    /* 
     * 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;
    }

    /*
     * Brewsystems
     */
    if (Config.units) {
        if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "BREWSYSTEMS")) < 0) {
            syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
            return 1;
        }
        for (unit = Config.units; unit; unit = unit->next) {
            /*
             * Only configuration items are written, measured values and states
             * are written to a state file.
             */
            if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "BREWSYSTEM")) < 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 "UUID", "%s", unit->uuid)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", unit->name)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NUMBER", "%d", unit->number)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ACTIVE", "%d", unit->active)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }

            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_SENSOR_UUID", "%s", unit->hlt_sensor.uuid)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_SENSOR_STATE", "%d", unit->hlt_sensor.state)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_SENSOR_VALUE", "%d", unit->hlt_sensor.value)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }

            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_HEATER_UUID", "%s", unit->hlt_heater.uuid)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_HEATER_VALUE", "%d", unit->hlt_heater.value)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_HEATER_DELAY", "%d", unit->hlt_heater.delay)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }

	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_HEATER_MLTFIRST", "%d", unit->hlt_heater_mltfirst)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }

            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_SENSOR_UUID", "%s", unit->mlt_sensor.uuid)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_SENSOR_STATE", "%d", unit->mlt_sensor.state)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_SENSOR_VALUE", "%d", unit->mlt_sensor.value)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }

            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_HEATER_UUID", "%s", unit->mlt_heater.uuid)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_HEATER_VALUE", "%d", unit->mlt_heater.value)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_HEATER_DELAY", "%d", unit->mlt_heater.delay)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }

            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_PUMP_UUID", "%s", unit->mlt_pump.uuid)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_PUMP_VALUE", "%d", unit->mlt_pump.value)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_PUMP_DELAY", "%d", unit->mlt_pump.delay)) < 0)) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }

	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PUMP_CYCLE", "%d", unit->pump_cycle)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PUMP_REST", "%d", unit->pump_rest)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PUMP_PREMASH", "%d", unit->pump_premash)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PUMP_ONMASH", "%d", unit->pump_onmash)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PUMP_MASHOUT", "%d", unit->pump_mashout)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PUMP_ONBOIL", "%d", unit->pump_onboil)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PUMP_STOP", "%.3f", unit->pump_stop)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SKIP_ADD", "%d", unit->skip_add)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SKIP_REMOVE", "%d", unit->skip_remove)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SKIP_IODINE", "%d", unit->skip_iodine)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "IODINE_TIME", "%d", unit->iodine_time)) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }
	    if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "WHIRLPOOL", "%s", WHIRLPOOL_TYPE[unit->whirlpool])) < 0)) {
		syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		return 1;
	    }

            if (unit->PID_hlt) {
                if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_KP", "%.2lf", unit->PID_hlt->dispKp)) < 0) {
                    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                    return 1;
                }
                if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_KI", "%.2lf", unit->PID_hlt->dispKi)) < 0) {
                    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                    return 1;
                }
                if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_KD", "%.2lf", unit->PID_hlt->dispKd)) < 0) {
                    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                    return 1;
                }
		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_SAMPLETIIME", "%ld", unit->PID_hlt->SampleTime)) < 0) {
		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		    return 1;
		}
                if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_DIRECTION", "%s", PIDDIRECTION[unit->PID_hlt->Direction])) < 0) {
                    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                    return 1;
                }
            }

            if (unit->PID_mlt) {
                if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_KP", "%.2lf", unit->PID_mlt->dispKp)) < 0) {
                    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                    return 1;
                }
                if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_KI", "%.2lf", unit->PID_mlt->dispKi)) < 0) {
                    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                    return 1;
                }
                if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_KD", "%.2lf", unit->PID_mlt->dispKd)) < 0) {
                    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                    return 1;
                }
		if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_SAMPLETIIME", "%ld", unit->PID_mlt->SampleTime)) < 0) {
		    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
		    return 1;
		}
                if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_DIRECTION", "%s", PIDDIRECTION[unit->PID_mlt->Direction])) < 0) {
                    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                    return 1;
                }
            }

            if ((rc = xmlTextWriterEndElement(writer)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
                return 1;
            }
        }
        if ((rc = xmlTextWriterEndElement(writer)) < 0) {
            syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
            return 1;
        }
    }

    if (Config.devices) {
        if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "DEVICES")) < 0) {
            syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
            return 1;
        }
#ifdef HAVE_WIRINGPI_H
        piLock(LOCK_DEVICES);
#endif
        for (device = Config.devices; device; device = device->next) {
            if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "DEVICE")) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
                return 1;
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "VERSION", "%d", device->version)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
                return 1;
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", device->uuid)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TYPE", "%s", DEVTYPE[device->type])) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "DIRECTION", "%s", DEVDIR[device->direction])) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "VALUE", "%d", device->value)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
                return 1;
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "OFFSET", "%d", device->offset)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
                return 1;
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PRESENT", "%s", DEVPRESENT[device->present])) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement");
                return 1;                           
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ADDRESS", "%s", device->address)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
                return 1;                           
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SUBDEVICE", "%d", device->subdevice)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
                return 1;                           
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "GPIOPIN", "%d", device->gpiopin)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
                return 1;                           
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "DESCRIPTION", "%s", device->description)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
                return 1;                           
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "INUSE", "%d", device->inuse)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
                return 1;                           
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COMMENT", "%s", device->comment)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
                return 1;                           
            }
            if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "TIMESTAMP", "%d", (int)device->timestamp)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
                return 1;                           
            }
            if ((rc = xmlTextWriterEndElement(writer)) < 0) {
                syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
                return 1;
            }
        }
#ifdef HAVE_WIRINGPI_H
        piUnlock(LOCK_DEVICES);
#endif

        if ((rc = xmlTextWriterEndElement(writer)) < 0) {
            syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterEndElement");
            return 1;
        }
    }

#ifdef USE_SIMULATOR
    if (Config.simulator) {
        if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "SIMULATOR")) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement");
	    return 1;
        }
        if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ROOM_TEMPERATURE", "%f", Config.simulator->room_temperature)) < 0) {
            syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
            return 1;
        }
	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_TEMPERATURE", "%f", Config.simulator->hlt_temperature)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
	    return 1;
	}
	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_HEATER_TEMP", "%f", Config.simulator->hlt_heater_temp)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
	    return 1;
	}
	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_HEATER_VOLUME", "%d", Config.simulator->hlt_heater_volume)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
	    return 1;
	}
	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_HEATER_POWER", "%d", Config.simulator->hlt_heater_power)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
	    return 1;
	}
	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_HEATER_STATE", "%d", Config.simulator->hlt_heater_state)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
	    return 1;
	}

	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_TEMPERATURE", "%f", Config.simulator->mlt_temperature)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
	    return 1;
	}
	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_HEATER_TEMP", "%f", Config.simulator->mlt_heater_temp)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
	    return 1;
	}
	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_HEATER_VOLUME", "%d", Config.simulator->mlt_heater_volume)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
	    return 1;
	}                                       
	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_HEATER_POWER", "%d", Config.simulator->mlt_heater_power)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
	    return 1;
	}
	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_HEATER_STATE", "%d", Config.simulator->mlt_heater_state)) < 0) {
	    syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement");
	    return 1;
	}

        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 = do_wrconfig();
    syslog(LOG_NOTICE, "Rewritten configuration, rc=%d", rc);
    return rc;
}



/*
 * Parse one LCD display
 */
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;
}



/*
 * Parse a brewsystem
 */
int parseBrewsystem(xmlDocPtr doc, xmlNodePtr cur)
{
    xmlChar     *key;
    int         i, ival;
    long	lval;
    float       fval;
    double	kpval, kival, kdval;
    units_list  *unit, *tmp;

    unit = (units_list *)malloc(sizeof(units_list));
    unit->next = NULL;
    unit->version = 1;
    unit->uuid = unit->name = NULL;
    unit->number = 0;
    unit->active = 0;
    unit->hlt_sensor.uuid = xstrcpy((char *)"00000000-0000-0000-0000-000000000000");
    unit->hlt_sensor.state = 0;
    unit->hlt_sensor.value = 0;
    unit->mlt_sensor.uuid = xstrcpy((char *)"00000000-0000-0000-0000-000000000000");
    unit->mlt_sensor.state = 0;
    unit->mlt_sensor.value = 0;
    unit->hlt_heater.uuid = xstrcpy((char *)"00000000-0000-0000-0000-000000000000");
    unit->hlt_heater.value = 0;
    unit->hlt_heater.delay = 0;
    unit->mlt_heater.uuid = xstrcpy((char *)"00000000-0000-0000-0000-000000000000");
    unit->mlt_heater.value = 0;
    unit->mlt_heater.delay = 0;
    unit->mlt_pump.uuid = xstrcpy((char *)"00000000-0000-0000-0000-000000000000");
    unit->mlt_pump.value = 0;
    unit->mlt_pump.delay = 0;
    unit->hlt_heater_mltfirst = 0;
    unit->pump_cycle = 7;
    unit->pump_rest = 2;
    unit->pump_premash = 1;
    unit->pump_onmash = 1;
    unit->pump_mashout = 0;
    unit->pump_onboil = 0;
    unit->pump_stop = 90.0;
    unit->skip_add = 0;
    unit->skip_remove = 0;
    unit->skip_iodine = 0;
    unit->iodine_time = 90;
    unit->whirlpool = 1;
    unit->PID_hlt = (pid_var *)malloc(sizeof(pid_var));
    unit->PID_mlt = (pid_var *)malloc(sizeof(pid_var));
    PID_init(unit->PID_hlt, NULL, NULL, NULL, 2, 5, 1, P_DIRECT);
    PID_init(unit->PID_mlt, NULL, NULL, NULL, 2, 5, 1, P_DIRECT);

    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);
                return 1;
            }
            unit->version = 1;
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) {
            unit->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
            unit->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
        }
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NUMBER"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->number = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ACTIVE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->active = ival;
	    xmlFree(key);
	}

        if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_SENSOR_UUID"))) {
    	    unit->hlt_sensor.uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_SENSOR_STATE"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                unit->hlt_sensor.state = ival;
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_SENSOR_VALUE"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                unit->hlt_sensor.value = ival;
            xmlFree(key);                           
        }

        if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_HEATER_UUID"))) {
	    unit->hlt_heater.uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
        }
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_HEATER_VALUE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->hlt_heater.value = ival;
	    xmlFree(key);
	}
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_HEATER_DELAY"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                unit->hlt_heater.delay = ival;
            xmlFree(key);
        }

	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_HEATER_MLTFIRST"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->hlt_heater_mltfirst = ival;
	    xmlFree(key);
	}

        if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_SENSOR_UUID"))) {
	    unit->mlt_sensor.uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_SENSOR_STATE"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                unit->mlt_sensor.state = ival;
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_SENSOR_VALUE"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                unit->mlt_sensor.value = ival;
            xmlFree(key);
        }

        if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_HEATER_UUID"))) {
	    unit->mlt_heater.uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
        }
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_HEATER_VALUE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->mlt_heater.value = ival;
	    xmlFree(key);
	}
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_HEATER_DELAY"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                unit->mlt_heater.delay = ival;
            xmlFree(key);
        }

        if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_PUMP_UUID"))) {
	    unit->mlt_pump.uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
        }
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_PUMP_VALUE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->mlt_pump.value = ival;
	    xmlFree(key);
	}
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_PUMP_DELAY"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                unit->mlt_pump.delay = ival;
            xmlFree(key);
        }

	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PUMP_CYCLE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->pump_cycle = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PUMP_REST"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->pump_rest = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PUMP_PREMASH"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->pump_premash = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PUMP_ONMASH"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->pump_onmash = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PUMP_MASHOUT "))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->pump_mashout = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PUMP_ONBOIL"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->pump_onboil = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PUMP_STOP"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		unit->pump_stop = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SKIP_ADD"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
	    	unit->skip_add = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SKIP_REMOVE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->skip_remove = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SKIP_IODINE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->skip_iodine = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"IODINE_TIME"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		unit->iodine_time = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"WHIRLPOOL"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    for (i = 0; i < 2; i++) {
		if (! xmlStrcmp(key, (const xmlChar *)WHIRLPOOL_TYPE[i])) {
		    unit->whirlpool = i;
		    break;
		}
	    }
	    xmlFree(key);
	}

        if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_KP"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            sscanf((const char *)key, "%lf", &kpval);
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_KI"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            sscanf((const char *)key, "%lf", &kival);
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_KD"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            sscanf((const char *)key, "%lf", &kdval);
            xmlFree(key);
        }
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_SAMPLETIME"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%ld", &lval) == 1) {
		PID_setSampleTime(unit->PID_hlt, lval);
		PID_setTunings(unit->PID_hlt, kpval, kival, kdval);
	    }
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_DIRECTION"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    for (i = 0; i < 2; i++) {
		if (! xmlStrcmp(key, (const xmlChar *)PIDDIRECTION[i])) {
		    PID_setDirection(unit->PID_hlt, i);
		    break;
		}
	    }
	    xmlFree(key);
	}

        if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_KP"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            sscanf((const char *)key, "%lf", &kpval);
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_KI"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            sscanf((const char *)key, "%lf", &kival);
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_KD"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            sscanf((const char *)key, "%lf", &kdval);
            xmlFree(key);
        }
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_SAMPLETIME"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%ld", &lval) == 1) {
		PID_setSampleTime(unit->PID_mlt, lval);
		PID_setTunings(unit->PID_mlt, kpval, kival, kdval);
	    }
	    xmlFree(key);       
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_DIRECTION"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    for (i = 0; i < 2; i++) {
		if (! xmlStrcmp(key, (const xmlChar *)PIDDIRECTION[i])) {
		    PID_setDirection(unit->PID_mlt, i);
		    break;
		}
	    }
	    xmlFree(key);
	}

        cur = cur->next;
    }

    if (Config.units == NULL) {
        Config.units = unit;
    } else {
        for (tmp = Config.units; tmp; tmp = tmp->next) {
            if (tmp->next == NULL) {
                tmp->next = unit;
                break;
            }
        }
    }

    return 0;
}



int parseBrewsystems(xmlDocPtr doc, xmlNodePtr cur)
{
    cur = cur->xmlChildrenNode;
    while (cur != NULL) {
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"BREWSYSTEM"))) {
            parseBrewsystem(doc, cur);
        }
        cur = cur->next;
    }
    return 0;
}


int parseDevice(xmlDocPtr doc, xmlNodePtr cur)
{
    xmlChar             *key;
    devices_list        *device, *tmp;
    int                 i, ival;

    device = (devices_list *)malloc(sizeof(devices_list));
    device->next = NULL;
    device->version = 1;
    device->uuid = device->address = device->description = device->comment = NULL;
    device->type = device->direction = device->present = device->subdevice = device->inuse = device->offset = 0;
    device->gpiopin = -1;
    device->timestamp = (time_t)0;

    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);
                return 1;
            }
            device->version = 1;
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) {
            device->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"TYPE"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            for (i = 0; i < 8; i++) {
                if (! xmlStrcmp(key, (const xmlChar *)DEVTYPE[i])) {
                    device->type = i;
                    break;
                }
            }
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"DIRECTION"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            for (i = 0; i < 7; i++) {
                if (! xmlStrcmp(key, (const xmlChar *)DEVDIR[i])) {
                    device->direction = i;
                    break;
                }
            }
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"VALUE"))) {
                key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
                if (sscanf((const char *)key, "%d", &ival) == 1)
                        device->value = ival;
                xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"OFFSET"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                device->offset = ival;
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"PRESENT"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            for (i = 0; i < 4; i++) {
                if (! xmlStrcmp(key, (const xmlChar *)DEVPRESENT[i])) {
                    device->present = i;
                    break;
                }
            }
            xmlFree(key);                           
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"ADDRESS"))) {
            device->address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"SUBDEVICE"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                device->subdevice = ival;
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"GPIOPIN"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                device->gpiopin = ival;
            xmlFree(key);                                       
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"DESCRIPTION"))) {
            device->description = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"INUSE"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                device->inuse = ival;
            xmlFree(key);                                       
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"COMMENT"))) {
            device->comment = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"TIMESTAMP"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                device->timestamp = (time_t)ival;
            xmlFree(key);                                   
        }

        cur = cur->next;
    }

    if (Config.devices == NULL) {
        Config.devices = device;
    } else {
        for (tmp = Config.devices; tmp; tmp = tmp->next) {
            if (tmp->next == NULL) {
                tmp->next = device;
                break;
            }
        }
    }

    return 0;
}



int parseDevices(xmlDocPtr doc, xmlNodePtr cur)
{
    cur = cur->xmlChildrenNode;
    while (cur != NULL) {
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"DEVICE"))) {
            parseDevice(doc, cur);
        }
        cur = cur->next;
    }
    return 0;
}



#ifdef USE_SIMULATOR
int parseSimulator(xmlDocPtr doc, xmlNodePtr cur)
{
    xmlChar             *key;
    int                 ival;
    float               fval;

    /*
     * First time, allocate memory and set defaults.
     */
    if (! Config.simulator) {
	Config.simulator = (simulator_var *)malloc(sizeof(simulator_var));
	Config.simulator->room_temperature = Config.simulator->hlt_temperature = Config.simulator->hlt_heater_temp = \
		Config.simulator->mlt_temperature = Config.simulator->mlt_heater_temp = 20.0;
	Config.simulator->hlt_heater_volume = Config.simulator->mlt_heater_volume = 20;
	Config.simulator->hlt_heater_power = Config.simulator->mlt_heater_power = 2000;
	Config.simulator->hlt_heater_state = Config.simulator->mlt_heater_state = 0;
    }

    cur = cur->xmlChildrenNode;
    while (cur != NULL) {
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ROOM_TEMPERATURE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		Config.simulator->room_temperature = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_TEMPERATURE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		Config.simulator->hlt_temperature = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_HEATER_TEMP"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		Config.simulator->hlt_heater_temp = fval;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_HEATER_VOLUME"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		Config.simulator->hlt_heater_volume = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_HEATER_POWER"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		Config.simulator->hlt_heater_power = ival;
	    xmlFree(key);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_HEATER_STATE"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		Config.simulator->hlt_heater_state = ival;
	    xmlFree(key);
	}
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_TEMPERATURE"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%f", &fval) == 1)
                Config.simulator->mlt_temperature = fval;
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_HEATER_TEMP"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%f", &fval) == 1)
                Config.simulator->mlt_heater_temp = fval;
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_HEATER_VOLUME"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                Config.simulator->mlt_heater_volume = ival;
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_HEATER_POWER"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                Config.simulator->mlt_heater_power = ival;
            xmlFree(key);
        }
        if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_HEATER_STATE"))) {
            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
            if (sscanf((const char *)key, "%d", &ival) == 1)
                Config.simulator->mlt_heater_state = ival;
            xmlFree(key);
        }
        cur = cur->next;
    }

    return 0;
}
#endif



int rdconfig(void) 
{
    int		ival, 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 *)"LISTEN_PORT"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%d", &ival) == 1)
		Config.my_port = ival;
	    xmlFree(key);
	}
	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 *)"ROOMTEMP_UUID"))) {
	    if (Config.roomtemp == NULL) {
		Config.roomtemp = (sensor_var *)malloc(sizeof(sensor_var));
		Config.roomtemp->uuid[0] = '\0';
		Config.roomtemp->state = 1;        // missing
		Config.roomtemp->value = 0;
	    }
	    snprintf(Config.roomtemp->uuid, 36, "%s", xmlNodeListGetString(doc, cur->xmlChildrenNode, 1));
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"LCDS"))) {
	    parseLCDs(doc, cur);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BREWSYSTEMS"))) {
	    parseBrewsystems(doc, cur);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"DEVICES"))) {
	    parseDevices(doc, cur);
	}
#ifdef USE_SIMULATOR
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SIMULATOR"))) {
	    parseSimulator(doc, cur);
	}
#endif
	cur = cur->next;
    }
    xmlFreeDoc(doc);

    free(mypath);
    mypath = NULL;

#ifdef USE_SIMULATOR
    /*
     * If we didn't find any simulator values, initialize a new simulator.
     */
    if (! Config.simulator) {
	Config.simulator = (simulator_var *)malloc(sizeof(simulator_var));
	syslog(LOG_NOTICE, "rdconfig() init a new simulator");
	Config.simulator->room_temperature = Config.simulator->hlt_temperature = Config.simulator->hlt_heater_temp = \
		Config.simulator->mlt_temperature = Config.simulator->mlt_heater_temp = 20.0;
	Config.simulator->hlt_heater_volume = Config.simulator->mlt_heater_volume = 20;
	Config.simulator->hlt_heater_power = Config.simulator->mlt_heater_power = 2000;
	Config.simulator->hlt_heater_state = Config.simulator->mlt_heater_state = 0;
    }
#endif

    return rc;
}


mercurial