# HG changeset patch # User Michiel Broek # Date 1448488175 -3600 # Node ID eb724767860dea8c1618d707a99ca418a478ee67 # Parent 1421ece29197006b1e8fddfd0fdf21a4c66fabb9 Brewco first phase development configuration structure. diff -r 1421ece29197 -r eb724767860d brewco/Makefile --- a/brewco/Makefile Wed Nov 25 16:39:25 2015 +0100 +++ b/brewco/Makefile Wed Nov 25 22:49:35 2015 +0100 @@ -54,8 +54,13 @@ # DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT # Dependencies generated by make depend +slcd.o: brewco.h slcd.h futil.h xutil.h +devices.o: brewco.h devices.h xutil.h futil.o: brewco.h futil.h -brewco.o: rdconfig.h brewco.h futil.h xutil.h +brewco.o: rdconfig.h brewco.h futil.h xutil.h lcd-pcf8574.h slcd.h lock.h devices.h +lock.o: lock.h brewco.h +lcd-pcf8574.o: brewco.h lcd-pcf8574.h slcd.h +pid.o: brewco.h pid.h xutil.o: brewco.h xutil.h rdconfig.o: rdconfig.h brewco.h futil.h xutil.h # End of generated dependencies diff -r 1421ece29197 -r eb724767860d brewco/brewco.c --- a/brewco/brewco.c Wed Nov 25 16:39:25 2015 +0100 +++ b/brewco/brewco.c Wed Nov 25 22:49:35 2015 +0100 @@ -24,13 +24,20 @@ #include "brewco.h" #include "futil.h" #include "xutil.h" +#include "lcd-pcf8574.h" +#include "slcd.h" +#include "lock.h" +#include "devices.h" int my_shutdown = FALSE; extern int debug; extern sys_config Config; -#ifdef HAVE_WIRINGPI_H extern int lcdHandle; +extern int slcdHandle; + +#ifndef HAVE_WIRINGPI_H +pthread_t threads[5]; #endif @@ -70,6 +77,65 @@ +int server(void); +int server(void) +{ + int rc = 0; +#ifndef HAVE_WIRINGPI_H + long t = 0; +#endif + +// if (lockprog((char *)"thermferm")) { +// syslog(LOG_NOTICE, "Can't lock"); +// return 1; +// } + + if ((rc = devices_detect())) { + syslog(LOG_NOTICE, "Detected %d new devices", rc); + wrconfig(); + } + +#ifdef HAVE_WIRINGPI_H + rc = piThreadCreate(my_devices_loop); +#else + rc = pthread_create(&threads[t], NULL, my_devices_loop, (void *)t ); +#endif + if (rc) { + fprintf(stderr, "my_devices_loop thread didn't start rc=%d\n", rc); + syslog(LOG_NOTICE, "my_devices_loop thread didn't start rc=%d", rc); +#ifndef HAVE_WIRINGPI_H + } else { + t++; +#endif + } + + /* + * Initialize units for processing + */ +// for (unit = Config.units; unit; unit = unit->next) { + /* + * Safety, turn everything off + */ +// unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->light_state = 0; +// unit->heater_wait = unit->cooler_wait = unit->fan_wait = unit->light_wait = 0; +// } + +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_LCD); + lcdPosition(lcdHandle, 0, 0); + lcdPrintf(lcdHandle, " Brewco %s", VERSION); +#endif + slcdPosition(slcdHandle, 0, 0); + slcdPrintf(slcdHandle, " Brewco %s", VERSION); +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_LCD); +#endif + + return rc; +} + + + int main(int argc, char *argv[]) { int rc = 0, c, i; @@ -118,17 +184,19 @@ #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 + if ((rc = initLCD (Config.lcd_cols, Config.lcd_rows))) { + fprintf(stderr, "Cannot initialize LCD display, rc=%d\n", rc); + return 1; + } + + rc = server(); syslog(LOG_NOTICE, "Finished, rc=%d", rc); + if (debug) + fprintf(stdout, "Finished, rc=%d\n", rc); return rc; } - diff -r 1421ece29197 -r eb724767860d brewco/brewco.h --- a/brewco/brewco.h Wed Nov 25 16:39:25 2015 +0100 +++ b/brewco/brewco.h Wed Nov 25 22:49:35 2015 +0100 @@ -5,6 +5,7 @@ #define FALSE 0 #include "../config.h" +#include "pid.h" #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +25,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #ifndef HAVE_WIRINGPI_H #include @@ -74,24 +83,137 @@ #define MBSE_SS(x) (x)?(x):"(null)" + +/* + * Brewing units. The sensors of the units are connected via the 1-wire bus. + * The heaters, pumps (or mixer) are connected on the Pi GPIO. The hardware + * is configured in the devices lists. + */ +typedef struct _units_list { + struct _units_list *next; + int version; /* Record version */ + char *uuid; /* uuid code */ + char *name; /* Unit name */ + char *hlt_sensor_address; /* HLT sensor address */ + int hlt_sensor_state; /* HLT sensor state */ + int hlt_sensor_value; /* HLT sensor value */ + char *hlt_heater_address; /* HLT heater address */ + int hlt_heater_state; /* HLT heater state 0..100 */ + int hlt_heater_delay; /* HLT heater delay / 15 sec */ + int hlt_heater_mltfirst; /* HLT heater MLT high priority */ + char *mlt_sensor_address; /* MLT sensor address */ + int mlt_sensor_state; /* MLT sensor state */ + int mlt_sensor_value; /* MLT sensor value */ + char *mlt_heater_address; /* MLT heater address */ + int mlt_heater_state; /* MLT heater state 0..100 */ + int mlt_heater_delay; /* MLT heater delay / 15 sec */ + char *mlt_pump_address; /* MLT pump address */ + int mlt_pump_state; /* MLT pump state 0..100 */ + int mlt_pump_delay; /* MLT_pump_delay */ + pid_var *PID_hlt; /* HLT PID */ + pid_var *PID_mlt; /* MLT PID */ +} units_list; + + + +/* + * External devices like sensors, relays, SSR. + */ +typedef struct _dev_list { + struct _dev_list *next; + int version; /* Version 1 */ + char *uuid; /* UUID of this device */ + int type; /* Device type */ + int direction; /* Device direction */ + int value; /* Device value */ + int offset; /* Device offset value */ + int present; /* Device present */ + char *address; /* Device address */ + int subdevice; /* Device sub address */ + int gpiopin; /* Device GPIO pin or -1 */ + char *description; /* Device description */ + int inuse; /* In use counter */ + char *comment; /* What we think it is */ + time_t timestamp; /* Last updated */ +} devices_list; + + +#define DEVTYPE_NA 0 /* Unknown device type */ +#define DEVTYPE_W1 1 /* 1-Wire bus */ +#define DEVTYPE_GPIO 2 /* GPIO I/O device */ +#define DEVTYPE_I2C 3 /* I2C bus device */ +#define DEVTYPE_SPI 4 /* SPI bus device */ +#ifdef USE_SIMULATOR +#define DEVTYPE_SIM 5 /* Simulated device */ +#endif + +#define DEVPRESENT_UNDEF 0 /* Precence not testable */ +#define DEVPRESENT_NO 1 /* Device is missing */ +#define DEVPRESENT_YES 2 /* Device is detected */ +#define DEVPRESENT_ERROR 3 /* Device is in error */ + +#define DEVDIR_UNDEF 0 /* Undefined */ +#define DEVDIR_IN_BIN 1 /* Binary input */ +#define DEVDIR_OUT_BIN 2 /* Binary output */ +#define DEVDIR_IN_ANALOG 3 /* Temperature input etc. */ +#define DEVDIR_OUT_ANALOG 4 /* Analog steering */ +#define DEVDIR_OUT_PWM 5 /* PWM outout */ +#define DEVDIR_INTERN 6 /* Internal function */ + + +#ifdef USE_SIMULATOR + +/* + * Simulate a HLT and MLT. + */ +typedef struct _simulator { + struct _simulator *next; + int version; /* Version of this record */ + char *uuid; /* Simulator uuid */ + char *name; /* Simulator name */ + double room_temperature; /* Simulated envionment temp */ + double hlt_temperature; /* Simulated HLT temperature */ + double hlt_heater_temp; /* Maximum heater temp */ + int hlt_heater_time; /* Time to reach temperature */ + float hlt_heater_size; /* Size of the heater */ + int hlt_heater_state; /* Heater status */ + double mlt_temperature; /* Simulated MLT temperature */ + double mlt_heater_temp; /* Maximum heater temp */ + int mlt_heater_time; /* Time to reach temperature */ + float mlt_heater_size; /* Size of the heater */ + int mlt_heater_state; /* Heater status */ + /* + * Status values, maintained by the simulator but stored + * here so they don't get lost over program restarts. + */ + double s_hlt_temp; /* Temp HLT */ + double s_mlt_temp; /* Temp MLT */ +} simulator_list; + +#endif + + + typedef struct _sys_config { char *name; /* Configuration name */ + int my_port; /* my client/server port */ 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 + char *temp_address; /* Environment temperature */ + int temp_state; /* 0=ok, 1=missing, 2=error */ + int temp_value; /* Air temperature in C * 1000 */ + char *hum_address; /* Environment huminity */ + int hum_state; /* 0=ok, 1=missing, 2=error */ + int hum_value; /* Huminity in % * 1000 */ int lcd_cols; /* LCD display columns */ int lcd_rows; /* LCD display rows */ int lcd_address; /* LCD display i2c address */ + units_list *units; /* Brewing units */ + devices_list *devices; /* Sensors and switches */ +#ifdef USE_SIMULATOR + simulator_list *simulators; /* Simulators */ #endif - } sys_config; + #endif diff -r 1421ece29197 -r eb724767860d brewco/devices.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brewco/devices.c Wed Nov 25 22:49:35 2015 +0100 @@ -0,0 +1,795 @@ +/***************************************************************************** + * Copyright (C) 2014..2015 + * + * Michiel Broek + * + * 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 "devices.h" +#include "xutil.h" + + +extern int debug; +extern sys_config Config; +extern int my_shutdown; + +#ifdef USE_SIMULATOR + +/*extern*/ int SIM_hlt_temp = 0; +/*extern*/ int SIM_mlt_temp = 0; + +#endif + + + +/* + * Read one byte from a 1-wire device like a DS2413 + */ +int read_w1(char *address, char *file) +{ + char *addr = NULL; + int fn = -1, rc = -1, retries = 5; + uint8_t val; + + addr = xstrcpy((char *)"/sys/bus/w1/devices/"); + addr = xstrcat(addr, address); + addr = xstrcat(addr, (char *)"/"); + addr = xstrcat(addr, file); + + if ((fn = open(addr, O_RDONLY)) >= 0) { + + if ((lseek(fn, 0L, SEEK_SET)) == 0) { + + while (retries--) { + if ((read(fn, &val, 1)) == 1) { + rc = (int)val; + goto leave; + } + } + syslog(LOG_NOTICE, "read_w1() read %s fatal: %s", addr, strerror(errno)); + + } else { + syslog(LOG_NOTICE, "read_w1() lseek %s: %s", addr, strerror(errno)); + } + + } else { + syslog(LOG_NOTICE, "read_w1() open %s: %s", addr, strerror(errno)); + } + +leave: + if (fn != -1) { + if ((close(fn)) == -1) { + syslog(LOG_NOTICE, "read_w1() close %s: %s", addr, strerror(errno)); + } + } + + free(addr); + return rc; +} + + + +/* + * Write a byte to a 1-wire device like a DS2413 + */ +int write_w1(char *address, char *file, uint8_t val) +{ + char *addr = NULL; + int fn = -1, rc = -1, retries = 5; + + addr = xstrcpy((char *)"/sys/bus/w1/devices/"); + addr = xstrcat(addr, address); + addr = xstrcat(addr, (char *)"/"); + addr = xstrcat(addr, file); + + if ((fn = open(addr, O_WRONLY)) >= 0) { + + if ((lseek(fn, 0L, SEEK_SET)) == 0) { + + while (retries--) { + if ((write(fn, &val, 1)) == 1) { + rc = 0; + goto leave; + } + } + syslog(LOG_NOTICE, "write_w1() write %s fatal: %s", addr, strerror(errno)); + + } else { + syslog(LOG_NOTICE, "write_w1() lseek %s: %s", addr, strerror(errno)); + } + + } else { + syslog(LOG_NOTICE, "write_w1() open %s: %s", addr, strerror(errno)); + } + +leave: + if (fn != -1) { + if ((close(fn)) == -1) { + syslog(LOG_NOTICE, "write_w1() close %s: %s", addr, strerror(errno)); + } + } + + free(addr); + return rc; +} + + + +int device_out(char *uuid, int value) +{ + devices_list *device; + time_t now, my_timestamp; + int rc, my_value, test_value; +#ifdef HAVE_WIRINGPI_H + int i; + char buf[40]; +#endif + + if (uuid == NULL) + return 0; + + now = time(NULL); + +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_DEVICES); +#endif + + for (device = Config.devices; device; device = device->next) { + if (! strcmp(uuid, device->uuid)) { + /* + * Execute command if different then the old value. But also + * every 2 minutes because commands can have temporary + * disconnects, or have radio problems. + */ + my_timestamp = device->timestamp; + my_value = device->value; + + if ((device->type == DEVTYPE_W1) && (device->direction == DEVDIR_OUT_BIN)) { + test_value = (value == 0) ? 0 : 1; + } else { + test_value = value; + } + + if ((test_value != my_value) || (((int)now - (int)my_timestamp) >= 120)) { + +#ifdef HAVE_WIRINGPI_H + rc = 0; + if ((device->type == DEVTYPE_RC433) && (device->gpiopin != -1) && (device->present == DEVPRESENT_YES)) { + snprintf(buf, 39, "%s,%d", device->address, value ? 1:0); + for (i = 0; i < strlen(buf); i++) + if (buf[i] == '-') + buf[i] = ','; + piUnlock(LOCK_DEVICES); + enableTransmit(device->gpiopin); + rc = toggleSwitch(buf); + disableTransmit(); + piLock(LOCK_DEVICES); + syslog(LOG_NOTICE, "RC433 command %s rc=%d", buf, rc); + if (debug) + fprintf(stdout, "RC433 command %s rc=%d\n", buf, rc); + device->value = value; + device->timestamp = time(NULL); + piUnlock(LOCK_DEVICES); + return rc; + } + + if ((device->type == DEVTYPE_GPIO) && (device->gpiopin != -1) && (device->present == DEVPRESENT_YES)) { + + } +#endif + if ((device->type == DEVTYPE_W1) && (device->direction == DEVDIR_OUT_BIN) && (device->present == DEVPRESENT_YES)) { + if (strncmp(device->address, (char *)"3a", 2) == 0) { + /* + * DS2413. First read state so that we can preserve the state of + * the "other" PIO channel. To make things a bit more complicated + * the bits in the state register differ from the output register. + */ + uint8_t state, output; + + if ((rc = read_w1(device->address, (char *)"state")) >= 0) { + state = (unsigned int)rc; + output = (state & 0x01) + ((state & 0x04) >> 1); + + if (device->subdevice == 0) { + output = (output & 0xfe); + output |= (value == 0) ? 0x01 : 0x00; + } else if (device->subdevice == 1) { + output = (output & 0xfd); + output |= (value == 0) ? 0x02 : 0x00; + } else { + output = 0xff; + } + + if ((write_w1(device->address, (char *)"output", output)) == 0) { + syslog(LOG_NOTICE, "DS2413 PIO%c value=%d (%s)", (device->subdevice == 0) ? 'A' : 'B', (value == 0) ? 0 : 1, device->comment); + if (debug) + fprintf(stdout, "DS2413 PIO%c value=%d (%s)\n", (device->subdevice == 0) ? 'A' : 'B', (value == 0) ? 0 : 1, device->comment); + device->value = (value == 0) ? 0 : 1; + device->timestamp = time(NULL); + } + } + } + } + +#ifdef USE_SIMULATOR + if ((device->type == DEVTYPE_SIM) && (device->direction == DEVDIR_OUT_BIN) && (device->present == DEVPRESENT_YES)) { + if ((strcmp((char *)"SimHLTheater", device->address) == 0) || (strcmp((char *)"SimMLTheater", device->address) == 0)) { + if (value != device->value) { + syslog(LOG_NOTICE, "SIM %s value=%d", device->address, value); + if (debug) + fprintf(stdout, "SIM %s value=%d\n", device->address, value); + } + device->value = value; + if (strcmp((char *)"SimHLTheater", device->address) == 0) + SIM_hlt_temp = value; + if (strcmp((char *)"SimMLTheater", device->address) == 0) + SIM_mlt_temp = value; + } + } +#endif + } else { +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_DEVICES); +#endif + return 0; + } + } + } +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_DEVICES); +#endif + + return 0; +} + + +/* + * Returns DEVPRESENT_NO if failed. + * Returns DEVPRESENT_YES if success, value contains new value. + */ +int device_in(char *uuid, int *value) +{ + devices_list *device; + int tmp, present; + + if (uuid == NULL) + return 0; + +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_DEVICES); +#endif + + for (device = Config.devices; device; device = device->next) { + if (! strcmp(uuid, device->uuid)) { + present = device->present; + if (present == DEVPRESENT_YES) { + tmp = device->value + device->offset; + } else { + tmp = 0; + } +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_DEVICES); +#endif + *value = tmp; + return present; + } + } + +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_DEVICES); +#endif + + return DEVPRESENT_NO; +} + + + + +/* + * Auto detect hotplugged or known to be present devices + */ +int devices_detect(void) +{ + struct dirent *de; + DIR *fd; + devices_list *device, *ndev; + int found, subdevices, ival, i, rc = 0; + char buf[40]; + uuid_t uu; +#ifdef HAVE_WIRINGPI_H + int pin; +#endif + + /* + * Scan for 1-wire devices + */ + if ((fd = opendir((char *)"/sys/bus/w1/devices"))) { + while ((de = readdir(fd))) { + if (de->d_name[0] != '.') { + found = FALSE; + for (device = Config.devices; device; device = device->next) { + if (strcmp(device->address,de->d_name) == 0) { + found = TRUE; + break; + } + } + + if (found == FALSE) { + strncpy(buf, de->d_name, 2); + buf[2] = '\0'; + sscanf(buf, "%02x", &ival); + syslog(LOG_NOTICE, "Scan 1-wire %02x %d", ival, ival); + subdevices = 1; + if (strcmp(buf, (char *)"29") == 0) + subdevices = 8; + if (strcmp(buf, (char *)"3a") == 0) + subdevices = 2; + for (i = 0; i < subdevices; i++) { + ndev = (devices_list *)malloc(sizeof(devices_list)); + ndev->next = NULL; + ndev->version = 1; + ndev->uuid = malloc(37); + uuid_generate(uu); + uuid_unparse(uu, ndev->uuid); + ndev->type = DEVTYPE_W1; + ndev->direction = DEVDIR_UNDEF; + if (strcmp(buf, (char *)"10") == 0) { + ndev->direction = DEVDIR_IN_ANALOG; + ndev->description = xstrcpy((char *)"DS18S20 Digital thermometer"); + } else if (strcmp(buf, (char *)"22") == 0) { + ndev->direction = DEVDIR_IN_ANALOG; + ndev->description = xstrcpy((char *)"DS1820 Digital thermometer"); + } else if (strcmp(buf, (char *)"28") == 0) { + ndev->direction = DEVDIR_IN_ANALOG; + ndev->description = xstrcpy((char *)"DS18B20 Digital thermometer"); + } else if (strcmp(buf, (char *)"3a") == 0) { + ndev->description = xstrcpy((char *)"DS2413 Dual channel addressable switch"); + ndev->direction = DEVDIR_IN_BIN; + } else if (strcmp(buf, (char *)"3b") == 0) { + ndev->direction = DEVDIR_IN_ANALOG; + ndev->description = xstrcpy((char *)"DS1825 Digital thermometer"); + } else if (strcmp(buf, (char *)"42") == 0) { + ndev->direction = DEVDIR_IN_ANALOG; + ndev->description = xstrcpy((char *)"DS28EA00 Digital thermometer"); + } else if (strcmp(buf, (char *)"w1") == 0) { + ndev->description = xstrcpy((char *)"Master System device"); + } else { + ndev->description = xstrcpy((char *)"Unknown device family "); + ndev->description = xstrcat(ndev->description, buf); + } + ndev->value = ndev->offset = ndev->inuse = 0; + ndev->present = DEVPRESENT_YES; + ndev->address = xstrcpy(de->d_name); + ndev->subdevice = i; + ndev->gpiopin = -1; + ndev->comment = xstrcpy((char *)"Auto detected device"); + ndev->timestamp = time(NULL); + + if (Config.devices == NULL) { + Config.devices = ndev; + } else { + for (device = Config.devices; device; device = device->next) { + if (device->next == NULL) { + device->next = ndev; + break; + } + } + } + rc++; + } + } + } + } + closedir(fd); + } + +#ifdef HAVE_WIRINGPI_H + if (piBoardRev() == 2) { + /* + * Support rev B and newer boards only + */ + found = FALSE; + for (device = Config.devices; device; device = device->next) { + if (device->type == DEVTYPE_GPIO) { + found = TRUE; + break; + } + } + + if (found == FALSE) { + /* + * There were no GPIO devices found. + */ + subdevices = 12; + pin = 0; + for (i = 0; i < subdevices; i++) { + if (i == 8) + pin = 17; + + ndev = (devices_list *)malloc(sizeof(devices_list)); + ndev->next = NULL; + ndev->version = 1; + ndev->uuid = malloc(37); + uuid_generate(uu); + uuid_unparse(uu, ndev->uuid); + ndev->type = DEVTYPE_GPIO; + ndev->value = digitalRead(pin); + ndev->offset = 0; + ndev->present = DEVPRESENT_YES; + ndev->address = xstrcpy((char *)"GPIO"); + snprintf(buf, 39, "Raspberry GPIO %d", i); + ndev->description = xstrcpy(buf); + ndev->subdevice = i; + ndev->gpiopin = pin; + ndev->timestamp = time(NULL); + if (i == PANEL_RETURN) { + ndev->direction = DEVDIR_IN_BIN; + ndev->inuse = 1; + ndev->comment = xstrcpy((char *)"Frontpanel Return"); + } else if (i == PANEL_ENTER) { + ndev->direction = DEVDIR_IN_BIN; + ndev->inuse = 1; + ndev->comment = xstrcpy((char *)"Frontpanel Enter key"); + } else if (i == PANEL_DOWN) { + ndev->direction = DEVDIR_IN_BIN; + ndev->inuse = 1; + ndev->comment = xstrcpy((char *)"Frontpanel Down key"); + } else if (i == PANEL_UP) { + ndev->direction = DEVDIR_IN_BIN; + ndev->inuse = 1; + ndev->comment = xstrcpy((char *)"Frontpanel Up key"); + } else if (i == 7) { + ndev->direction = DEVDIR_INTERN; + ndev->inuse = 1; + ndev->comment = xstrcpy((char *)"1-Wire bus"); + } else { + ndev->direction = DEVDIR_IN_BIN; + ndev->inuse = 0; + ndev->comment = xstrcpy((char *)"Raspberry GPIO"); + } + pin++; + + if (Config.devices == NULL) { + Config.devices = ndev; + } else { + for (device = Config.devices; device; device = device->next) { + if (device->next == NULL) { + device->next = ndev; + break; + } + } + } + rc++; + } + } + } +#endif + +#ifdef USE_SIMULATOR + found = FALSE; + for (device = Config.devices; device; device = device->next) { + if (device->type == DEVTYPE_SIM) { + found = TRUE; + break; + } + } + + if (found == FALSE) { + subdevices = 5; + for (i = 0; i < subdevices; i++) { + ndev = (devices_list *)malloc(sizeof(devices_list)); + ndev->next = NULL; + ndev->version = 1; + ndev->uuid = malloc(37); + uuid_generate(uu); + uuid_unparse(uu, ndev->uuid); + ndev->type = DEVTYPE_SIM; + ndev->value = ndev->offset = 0; + ndev->present = DEVPRESENT_YES; + ndev->subdevice = i; + ndev->gpiopin = -1; + ndev->comment = xstrcpy((char *)"Auto detected device"); + ndev->timestamp = time(NULL); + ndev->inuse = 0; + switch (i) { + case 0: ndev->direction = DEVDIR_IN_ANALOG; + ndev->address = xstrcpy((char *)"SimRoomtemp"); + ndev->description = xstrcpy((char *)"Simulated room temperature"); + break; + case 1: ndev->direction = DEVDIR_IN_ANALOG; + ndev->address = xstrcpy((char *)"SimHLTtemp"); + ndev->description = xstrcpy((char *)"Simulated HLT temperature"); + break; + case 2: ndev->direction = DEVDIR_IN_ANALOG; + ndev->address = xstrcpy((char *)"SimMLTtemp"); + ndev->description = xstrcpy((char *)"Simulated MLT temperature"); + break; + case 3: ndev->direction = DEVDIR_OUT_ANALOG; + ndev->address = xstrcpy((char *)"SimHLTheater"); + ndev->description = xstrcpy((char *)"Simulated HLT heater"); + break; + case 4: ndev->direction = DEVDIR_OUT_ANALOG; + ndev->address = xstrcpy((char *)"SimMLTheater"); + ndev->description = xstrcpy((char *)"Simulated MLT heater"); + break; + } + + if (Config.devices == NULL) { + Config.devices = ndev; + } else { + for (device = Config.devices; device; device = device->next) { + if (device->next == NULL) { + device->next = ndev; + break; + } + } + } + rc++; + } + } +#endif + + return rc; +} + + + +#ifdef HAVE_WIRINGPI_H +PI_THREAD (my_devices_loop) +#else +void *my_devices_loop(void *threadid) +#endif +{ + devices_list *device; +#ifdef USE_SIMULATOR + simulator_list *simulator; +#endif + char *addr = NULL, line[60], *p = NULL; + FILE *fp; + int temp, rc; +#ifdef HAVE_WIRINGPI_H + time_t now; +#endif + + syslog(LOG_NOTICE, "Thread my_devices_loop started"); + +#ifdef HAVE_WIRINGPI_H + if ((rc = piHiPri(10))) + syslog(LOG_NOTICE, "my_devices_loop: piHiPri(10) rc=%d", rc); +#endif + + /* + * Loop forever until the external shutdown variable is set. + */ + for (;;) { + + /* + * Process all devices. + */ + for (device = Config.devices; device; device = device->next) { + + if (my_shutdown) + break; + + switch (device->type) { + case DEVTYPE_W1: + /* + * Only tested with DS18B20 but from the kernel source this + * should work with all 1-wire thermometer sensors. + */ + if ((strncmp(device->address, (char *)"10", 2) == 0) || + (strncmp(device->address, (char *)"22", 2) == 0) || + (strncmp(device->address, (char *)"28", 2) == 0) || + (strncmp(device->address, (char *)"3b", 2) == 0) || + (strncmp(device->address, (char *)"42", 2) == 0)) { + addr = xstrcpy((char *)"/sys/bus/w1/devices/"); + addr = xstrcat(addr, device->address); + addr = xstrcat(addr, (char *)"/w1_slave"); + if ((fp = fopen(addr, "r"))) { + if (device->present != DEVPRESENT_YES) { + syslog(LOG_NOTICE, "sensor %s is back", device->address); +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_DEVICES); +#endif + device->present = DEVPRESENT_YES; +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_DEVICES); +#endif + } + /* + * The output looks like: + * 72 01 4b 46 7f ff 0e 10 57 : crc=57 YES + * 72 01 4b 46 7f ff 0e 10 57 t=23125 + */ + fgets(line, 50, fp); + line[strlen(line)-1] = '\0'; + if ((line[36] == 'Y') && (line[37] == 'E')) { + /* CRC is Ok, continue */ + fgets(line, 50, fp); + line[strlen(line)-1] = '\0'; + strtok(line, (char *)"="); + p = strtok(NULL, (char *)"="); + rc = sscanf(p, "%d", &temp); +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_DEVICES); +#endif + if ((rc == 1) && (device->value != temp)) { + device->value = temp; + device->timestamp = time(NULL); + } +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_DEVICES); +#endif + } else { + syslog(LOG_NOTICE, "sensor %s CRC error", device->address); +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_DEVICES); +#endif + device->present = DEVPRESENT_ERROR; +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_DEVICES); +#endif + } + fclose(fp); + } else { + if (device->present != DEVPRESENT_NO) { + syslog(LOG_NOTICE, "sensor %s is missing", device->address); +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_DEVICES); +#endif + device->present = DEVPRESENT_NO; +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_DEVICES); +#endif + } + } + free(addr); + addr = NULL; + } /* if temperature sensor */ + /* + * DS2413 Dual channel addressable switch + */ + if (strncmp(device->address, (char *)"3a", 2) == 0) { + addr = xstrcpy((char *)"/sys/bus/w1/devices/"); + addr = xstrcat(addr, device->address); + addr = xstrcat(addr, (char *)"/state"); + + if ((access(addr, R_OK)) == 0) { + if (device->present != DEVPRESENT_YES) { + syslog(LOG_NOTICE, "DS2413 %s is back", device->address); +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_DEVICES); +#endif + device->present = DEVPRESENT_YES; +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_DEVICES); +#endif + } + /* + * First make sure that if this device is configured as input + * to drive the output high. + */ + if (device->direction == DEVDIR_IN_BIN) { + uint8_t state, output; + + if ((rc = read_w1(device->address, (char *)"state")) >= 0) { + state = (unsigned int)rc; + output = ((state & 0x02) >> 1) + ((state & 0x08) >> 2); /* Both latch states */ + if (device->subdevice == 0) { + output = (output & 0xfe); + output |= 0x01; + } else if (device->subdevice == 1) { + output = (output & 0xfd); + output |= 0x02; + } else { + output = 0xff; + } + write_w1(device->address, (char *)"output", output); + } + } + if ((rc = read_w1(device->address, (char *)"state")) >= 0) { +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_DEVICES); +#endif + /* + * Read PIOA or PIOB pin state bits + */ + if (device->subdevice == 0) + device->value = (rc & 0x01) ? 0 : 1; + else if (device->subdevice == 1) + device->value = (rc & 0x04) ? 0 : 1; + device->timestamp = time(NULL); +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_DEVICES); +#endif + } + } else { + if (device->present != DEVPRESENT_NO) { + syslog(LOG_NOTICE, "DS2413 %s is missing", device->address); +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_DEVICES); +#endif + device->present = DEVPRESENT_NO; +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_DEVICES); +#endif + } + } + free(addr); + addr = NULL; + } + + break; + +#ifdef HAVE_WIRINGPI_H + case DEVTYPE_GPIO: + if (device->direction == DEVDIR_IN_BIN) { + piLock(LOCK_DEVICES); + device->value = digitalRead(device->gpiopin); + device->offset = 0; + device->timestamp = time(NULL); + piUnlock(LOCK_DEVICES); + } + break; + +#endif +#ifdef USE_SIMULATOR + case DEVTYPE_SIM: +#ifdef HAVE_WIRINGPI_H + piLock(LOCK_DEVICES); +#endif + if (Config.simulators) { + simulator = Config.simulators; + if (device->subdevice == 0) { + device->value = (int)(simulator->room_temperature * 1000); + device->timestamp = time(NULL); + } else if (device->subdevice == 1) { + device->value = (int)(simulator->hlt_temperature * 1000); + device->timestamp = time(NULL); + } else if (device->subdevice == 2) { + device->value = (int)(simulator->mlt_temperature * 1000); + device->timestamp = time(NULL); + } + } +#ifdef HAVE_WIRINGPI_H + piUnlock(LOCK_DEVICES); +#endif + break; +#endif + default: + break; + } + + /* + * Delay a bit after procesing a device. + */ + usleep(10000); + } + /* + * Delay a bit after all devices + */ + usleep(100000); + } + + syslog(LOG_NOTICE, "Thread my_devices_loop stopped"); + return 0; +} + + + diff -r 1421ece29197 -r eb724767860d brewco/devices.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brewco/devices.h Wed Nov 25 22:49:35 2015 +0100 @@ -0,0 +1,15 @@ +#ifndef MY_DEVICES_H +#define MY_DEVICES_H + + +int device_out(char *, int); +int device_in(char *, int *); +int devices_detect(void); + +#ifdef HAVE_WIRINGPI_H +PI_THREAD (my_devices_loop); +#else +void *my_devices_loop(void *); +#endif + +#endif diff -r 1421ece29197 -r eb724767860d brewco/lcd-pcf8574.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brewco/lcd-pcf8574.c Wed Nov 25 22:49:35 2015 +0100 @@ -0,0 +1,114 @@ +/* + * lcd-pcf8574.c: + * Text-based LCD driver library code + * This is designed to drive the HD44780U LCD display connected via + * a "LCM1602 IIC A0 A1 A2" board with a PCF8574 I2C controller. + * + * Copyright (c) 2012-2013 Gordon Henderson. + * Copyright (c) 2014 Michiel Broek. + *********************************************************************** + * + * mbsePi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * mbsePi 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with wiringPi. If not, see . + *********************************************************************** + */ + +#include "brewco.h" +#include "lcd-pcf8574.h" +#include "slcd.h" + + +int lcdHandle; +int slcdHandle; + + +#ifdef HAVE_WIRINGPI_H +struct lcdDataStruct +{ + int bits, rows, cols ; + int rsPin, strbPin ; + int dataPins [8] ; + int cx, cy ; +}; + +extern struct lcdDataStruct *lcds [MAX_LCDS]; +#endif +extern sys_config Config; +extern uint16_t leds; + + +/* + * setBacklight: + ********************************************************************************* + */ +void setBacklight(int value) +{ +#ifdef HAVE_WIRINGPI_H + pinMode (AF_BACKLIGHT, OUTPUT) ; + digitalWrite (AF_BACKLIGHT, (value & 1)) ; +#endif + if (value) { + leds |= SLED_LCD; + } else { + leds &= ~SLED_LCD; + } + slcdLEDs(slcdHandle); +} + + +/* + * initLCD: + ********************************************************************************* + */ + +int initLCD(int cols, int rows) +{ + if (!((rows == 1) || (rows == 2) || (rows == 4))) { + fprintf (stderr, "rows must be 1, 2 or 4\n") ; + return EXIT_FAILURE ; + } + + if (!((cols == 16) || (cols == 20))) { + fprintf (stderr, "cols must be 16 or 20\n") ; + return EXIT_FAILURE ; + } + +#ifdef HAVE_WIRINGPI_H + pcf8574Setup(AF_BASE, 0x27) ; + pinMode (AF_RW, OUTPUT) ; + digitalWrite (AF_RW, LOW) ; // Not used with wiringPi - always in write mode + + /* + * The other control pins are initialised with lcdInit () + */ + lcdHandle = lcdInit (rows, cols, 4, AF_RS, AF_E, AF_DB4, AF_DB5, AF_DB6, AF_DB7, 0, 0, 0, 0) ; + if (lcdHandle < 0) { + fprintf (stderr, "lcdInit failed\n") ; + return -1 ; + } + + lcdClear (lcdHandle) ; +#endif + + slcdHandle = slcdInit(0, rows, cols); + if (slcdHandle < 0) { + fprintf (stderr, "slcdInit failed\n") ; + return -1; + } + slcdClear(slcdHandle); + setBacklight(1); + + return 0 ; +} + + diff -r 1421ece29197 -r eb724767860d brewco/lcd-pcf8574.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brewco/lcd-pcf8574.h Wed Nov 25 22:49:35 2015 +0100 @@ -0,0 +1,25 @@ +#ifndef LCD_PCF8574_H +#define LCD_PCF8574_H + + +#ifdef HAVE_WIRINGPI_H + +// Defines for the pcf8574 Pi LCD interface board +#define AF_BASE 100 + +#define AF_RS (AF_BASE + 0) +#define AF_RW (AF_BASE + 1) +#define AF_E (AF_BASE + 2) +#define AF_BACKLIGHT (AF_BASE + 3) +#define AF_DB4 (AF_BASE + 4) +#define AF_DB5 (AF_BASE + 5) +#define AF_DB6 (AF_BASE + 6) +#define AF_DB7 (AF_BASE + 7) + +#endif + +void setBacklight (int); +int initLCD (int, int); + + +#endif diff -r 1421ece29197 -r eb724767860d brewco/lock.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brewco/lock.c Wed Nov 25 22:49:35 2015 +0100 @@ -0,0 +1,133 @@ +/***************************************************************************** + * Copyright (C) 2015 + * + * Michiel Broek + * + * 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 "lock.h" +#include "brewco.h" + +/* + * Put a lock on this program. + */ +int lockprog(char *name) +{ + char *tempfile, *lockfile; + FILE *fp; + pid_t oldpid; + + tempfile = calloc(PATH_MAX, sizeof(char)); + lockfile = calloc(PATH_MAX, sizeof(char)); + + snprintf(tempfile, PATH_MAX, "/var/run/%s.tmp", name); + snprintf(lockfile, PATH_MAX, "/var/run/%s.pid", name); + + if ((fp = fopen(tempfile, "w")) == NULL) { + perror(name); + printf("Can't create lockfile \"%s\"\n", tempfile); + free(tempfile); + free(lockfile); + return 1; + } + fprintf(fp, "%10u\n", getpid()); + fclose(fp); + + while (TRUE) { + if (link(tempfile, lockfile) == 0) { + unlink(tempfile); + free(tempfile); + free(lockfile); + return 0; + } + if ((fp = fopen(lockfile, "r")) == NULL) { + perror(name); + printf("Can't open lockfile \"%s\"\n", tempfile); + unlink(tempfile); + free(tempfile); + free(lockfile); + return 1; + } + if (fscanf(fp, "%u", &oldpid) != 1) { + perror(name); + printf("Can't read old pid from \"%s\"\n", tempfile); + fclose(fp); + unlink(tempfile); + free(tempfile); + free(lockfile); + return 1; + } + fclose(fp); + if (kill(oldpid,0) == -1) { + if (errno == ESRCH) { + printf("Stale lock found for pid %u\n", oldpid); + unlink(lockfile); + /* no return, try lock again */ + } else { + perror(name); + printf("Kill for %u failed\n",oldpid); + unlink(tempfile); + free(tempfile); + free(lockfile); + return 1; + } + } else { + printf("Another %s is already running, pid=%u\n", name, oldpid); + unlink(tempfile); + free(tempfile); + free(lockfile); + return 1; + } + } +} + + + +void ulockprog(char *name) +{ + char *lockfile; + pid_t oldpid; + FILE *fp; + + lockfile = calloc(PATH_MAX, sizeof(char)); + snprintf(lockfile, PATH_MAX, "/var/run/%s.pid", name); + + if ((fp = fopen(lockfile, "r")) == NULL) { + syslog(LOG_NOTICE, "Can't open lockfile \"%s\"", lockfile); + free(lockfile); + return; + } + + if (fscanf(fp, "%u", &oldpid) != 1) { + syslog(LOG_NOTICE, "Can't read old pid from \"%s\"", lockfile); + fclose(fp); + unlink(lockfile); + free(lockfile); + return; + } + + fclose(fp); + + if (oldpid == getpid()) { + (void)unlink(lockfile); + } + + free(lockfile); +} + + diff -r 1421ece29197 -r eb724767860d brewco/lock.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brewco/lock.h Wed Nov 25 22:49:35 2015 +0100 @@ -0,0 +1,8 @@ +#ifndef LOCK_H +#define LOCK_H + + +int lockprog(char *); +void ulockprog(char *); + +#endif diff -r 1421ece29197 -r eb724767860d brewco/pid.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brewco/pid.c Wed Nov 25 22:49:35 2015 +0100 @@ -0,0 +1,93 @@ +/***************************************************************************** + * Copyright (C) 2015 + * + * Michiel Broek + * + * 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 "pid.h" + + +void InitPID(pid_var *pid) +{ + pid->Err = pid->ErrLast = pid->iState = 0.0; + pid->Input = pid->OutP = pid->SetP = 0.0; + pid->pGain = pid->iGain = pid->dGain = 0.0; + pid->Mode = PID_MODE_NONE; + pid->iMax = 100.0; +} + + + +void UpdatePID(pid_var *pid) +{ + if (pid->Mode == PID_MODE_AUTO) { + + double pTerm, dTerm, iTerm; + + pid->Err = pid->SetP - pid->Input; + + /* + * Calculate the integral state with appopriate limiting. + * Use ErrLastLast as iState + */ + pid->iState += pid->Err; + if (pid->iState > PID_WINDUP_GUARD) + pid->iState = PID_WINDUP_GUARD; + else if (pid->iState < -PID_WINDUP_GUARD) + pid->iState = -PID_WINDUP_GUARD; + + pTerm = pid->pGain * pid->Err; + iTerm = pid->iGain * pid->iState; + dTerm = pid->dGain * (pid->Err - pid->ErrLast); + + pid->OutP = pTerm + dTerm + iTerm; + pid->ErrLast = pid->Err; + + } else if (pid->Mode == PID_MODE_BOO) { + /* + * Mode Bang On Off + */ + pid->ErrLast = pid->Err; + pid->Err = pid->SetP - pid->Input; + + if (pid->OutP && (pid->Err <= 0.0)) + pid->OutP = 0.0; + else if ((pid->OutP == 0.0) && (pid->Err > 0.0)) + pid->OutP = pid->iMax; + + pid->iState = 0.0; + + } else { + /* + * While in manual mode, stay ready for bumpless switch to + * auto. + */ + pid->ErrLast = pid->Err = 0.0; + pid->OutP = pid->iState = 0.0; + } + + if (pid->OutP > pid->iMax) + pid->OutP = pid->iMax; + if (pid->OutP < 0.0) + pid->OutP = 0.0; + +} + + diff -r 1421ece29197 -r eb724767860d brewco/pid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brewco/pid.h Wed Nov 25 22:49:35 2015 +0100 @@ -0,0 +1,31 @@ +#ifndef PID_H +#define PID_H + +#define PID_MODE_NONE 0 /* Process control off */ +#define PID_MODE_AUTO 1 /* Process control auto */ +#define PID_MODE_BOO 2 /* Process control Bang On/Off */ + +#define PID_TIMES 60 /* 60 calculations per minute */ +#define PID_WINDUP_GUARD 10.0 /* Error windup guard */ + + +typedef struct _pid_var { + double iMax; /* Maximum allowable integrator state */ + double iGain; /* Integral gain */ + double pGain; /* Proportional gain */ + double dGain; /* Derivative gain */ + + double Input; /* Input value */ + double Err; /* Error, diff between input and set point */ + double ErrLast; /* Error from last pass */ + double iState; /* Error from next last pass */ + double SetP; /* Set point */ + double OutP; /* Output of PID algorithm */ + int Mode; /* Value is 'PID_AUTO' if loop is automatic */ +} pid_var; + + +void InitPID( pid_var *); +void UpdatePID( pid_var *); + +#endif diff -r 1421ece29197 -r eb724767860d brewco/rdconfig.c --- a/brewco/rdconfig.c Wed Nov 25 16:39:25 2015 +0100 +++ b/brewco/rdconfig.c Wed Nov 25 22:49:35 2015 +0100 @@ -25,37 +25,84 @@ #include "futil.h" #include "xutil.h" -int debug = FALSE; +int debug = TRUE; 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" }; +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) { + units_list *unit; + devices_list *device; +#ifdef USE_SIMULATOR + simulator_list *simulator; +#endif if (Config.name) free(Config.name); Config.name = NULL; + Config.my_port = 6554; 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 + if (Config.temp_address) + free(Config.temp_address); + if (Config.hum_address) + free(Config.hum_address); + Config.temp_address = Config.hum_address = NULL; + Config.temp_value = 20000; + Config.temp_state = Config.hum_state = 1; // missing + Config.hum_value = 50000; + Config.lcd_cols = 20; + Config.lcd_rows = 4; -#ifdef HAVE_WIRINGPI_H - Config.lcd_cols = 16; - Config.lcd_rows = 2; + for (unit = Config.units; unit; unit = unit->next) { + if (unit->uuid) + free(unit->uuid); + if (unit->name) + free(unit->name); + if (unit->hlt_sensor_address) + free(unit->hlt_sensor_address); + if (unit->mlt_sensor_address) + free(unit->mlt_sensor_address); + if (unit->hlt_heater_address) + free(unit->hlt_heater_address); + if (unit->mlt_heater_address) + free(unit->mlt_heater_address); + if (unit->mlt_pump_address) + free(unit->mlt_pump_address); + 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 + for (simulator = Config.simulators; simulator; simulator = simulator->next) { + if (simulator->uuid) + free(simulator->uuid); + if (simulator->name) + free(simulator->name); + free(simulator); + } + Config.simulators = NULL; #endif } @@ -69,6 +116,11 @@ char *mypath = NULL; xmlTextWriterPtr writer; xmlBufferPtr buf; + units_list *unit; + devices_list *device; +#ifdef USE_SIMULATOR + simulator_list *simulator; +#endif /* * Create a new XML buffer, to which the XML document will be written @@ -124,36 +176,39 @@ 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 ((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 "TEMP_ADDRESS", "%s", Config.temp_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 "TEMP_STATE", "%d", Config.temp_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 "TEMP_VALUE", "%d", Config.temp_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 "HUM_ADDRESS", "%s", Config.hum_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 "HUM_STATE", "%d", Config.hum_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; + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HUM_VALUE", "%d", Config.hum_value)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; } -#ifdef HAVE_WIRINGPI_H /* * Start an element named "LCDS" as child of BREWCO. */ @@ -199,6 +254,343 @@ 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 (unit->hlt_sensor_address) { + if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_SENSOR_ADDRESS", "%s", unit->hlt_sensor_address)) < 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 (unit->hlt_heater_address) { + if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_HEATER_ADDRESS", "%s", unit->hlt_heater_address)) < 0)) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HLT_HEATER_STATE", "%d", unit->hlt_heater_state)) < 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 (unit->mlt_sensor_address) { + if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_SENSOR_ADDRESS", "%s", unit->mlt_sensor_address)) < 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 (unit->mlt_heater_address) { + if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_HEATER_ADDRESS", "%s", unit->mlt_heater_address)) < 0)) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_HEATER_STATE", "%d", unit->mlt_heater_state)) < 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 (unit->mlt_pump_address) { + if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_PUMP_ADDRESS", "%s", unit->mlt_pump_address)) < 0)) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if (((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MLT_PUMP_STATE", "%d", unit->mlt_pump_state)) < 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 (unit->PID_hlt) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_IMAX", "%.2f", unit->PID_hlt->iMax)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_IGAIN", "%.2f", unit->PID_hlt->iGain)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_PGAIN", "%.2f", unit->PID_hlt->pGain)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_DGAIN", "%.2f", unit->PID_hlt->dGain)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_INPUT", "%.2f", unit->PID_hlt->Input)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_ERR", "%.2f", unit->PID_hlt->Err)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_ERRLAST", "%.2f", unit->PID_hlt->ErrLast)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_ISTATE", "%.2f", unit->PID_hlt->iState)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_SETP", "%.2f", unit->PID_hlt->SetP)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_OUTP", "%.2f", unit->PID_hlt->OutP)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_MODE", "%s", PIDMODE[unit->PID_hlt->Mode])) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_HLT_TYPE", "HEAT")) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + } + + if (unit->PID_mlt) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_IMAX", "%.2f", unit->PID_mlt->iMax)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_IGAIN", "%.2f", unit->PID_mlt->iGain)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_PGAIN", "%.2f", unit->PID_mlt->pGain)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_DGAIN", "%.2f", unit->PID_mlt->dGain)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_INPUT", "%.2f", unit->PID_mlt->Input)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_ERR", "%.2f", unit->PID_mlt->Err)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_ERRLAST", "%.2f", unit->PID_mlt->ErrLast)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_ISTATE", "%.2f", unit->PID_mlt->iState)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_SETP", "%.2f", unit->PID_mlt->SetP)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_OUTP", "%.2f", unit->PID_mlt->OutP)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_MODE", "%s", PIDMODE[unit->PID_mlt->Mode])) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "PID_MLT_TYPE", "HEAT")) < 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.simulators) { + if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "SIMULATORS")) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement"); + return 1; + } + for (simulator = Config.simulators; simulator; simulator = simulator->next) { + if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "SIMULATOR")) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterStartElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "VERSION", "%d", simulator->version)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", simulator->uuid)) < 0) { + syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); + return 1; + } + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", simulator->name)) < 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; + } + } #endif /* @@ -255,7 +647,6 @@ /* * Parse one LCD display */ -#ifdef HAVE_WIRINGPI_H int parseLCD(xmlDocPtr doc, xmlNodePtr cur) { xmlChar *key; @@ -300,13 +691,569 @@ } return 0; } + + + +/* + * Parse a brewsystem + */ +int parseBrewsystem(xmlDocPtr doc, xmlNodePtr cur) +{ + xmlChar *key; + int i, ival; + float val; + units_list *unit, *tmp; + + unit = (units_list *)malloc(sizeof(units_list)); + unit->next = NULL; + unit->version = 1; + unit->uuid = unit->name = unit->hlt_sensor_address = unit->hlt_heater_address = unit->mlt_sensor_address = \ + unit->mlt_heater_address = unit->mlt_pump_address = NULL; + unit->hlt_sensor_state = unit->mlt_sensor_state = 1; // missing + unit->hlt_heater_state = unit->mlt_heater_state = unit->mlt_pump_state = 0; + unit->hlt_heater_delay = unit->mlt_heater_delay = unit->mlt_pump_delay = 20; /* 5 minutes delay */ + unit->PID_hlt = (pid_var *)malloc(sizeof(pid_var)); + unit->PID_mlt = (pid_var *)malloc(sizeof(pid_var)); + InitPID(unit->PID_hlt); + InitPID(unit->PID_mlt); + + 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 *)"HLT_SENSOR_ADDRESS"))) { + unit->hlt_sensor_address = (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_ADDRESS"))) { + unit->hlt_heater_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + 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 *)"MLT_SENSOR_ADDRESS"))) { + unit->mlt_sensor_address = (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_ADDRESS"))) { + unit->mlt_heater_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + 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_ADDRESS"))) { + unit->mlt_pump_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + 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 *)"PID_HLT_IMAX"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_hlt->iMax = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_IGAIN"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_hlt->iGain = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_PGAIN"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_hlt->pGain = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_DGAIN"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_hlt->dGain = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_INPUT"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_hlt->Input = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_ERR"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_hlt->Err = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_ERRLAST"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_hlt->ErrLast = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_ISTATE"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_hlt->iState = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_SETP"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_hlt->SetP = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_OUTP"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_hlt->OutP = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_HLT_MODE"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + for (i = 0; i < 3; i++) { + if (! xmlStrcmp(key, (const xmlChar *)PIDMODE[i])) { + unit->PID_hlt->Mode = i; + break; + } + } + xmlFree(key); + } + + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_IMAX"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_mlt->iMax = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_IGAIN"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_mlt->iGain = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_PGAIN"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_mlt->pGain = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_DGAIN"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_mlt->dGain = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_INPUT"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_mlt->Input = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_ERR"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_mlt->Err = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_ERRLAST"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_mlt->ErrLast = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_ISTATE"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_mlt->iState = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_SETP"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_mlt->SetP = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_OUTP"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->PID_mlt->OutP = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PID_MLT_MODE"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + for (i = 0; i < 3; i++) { + if (! xmlStrcmp(key, (const xmlChar *)PIDMODE[i])) { + unit->PID_mlt->Mode = 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; + simulator_list *simulator, *tmp; + int ival; + float fval; + + simulator = (simulator_list *)malloc(sizeof(simulator_list)); + simulator->next = NULL; + simulator->version = 1; + simulator->uuid = simulator->name = NULL; + simulator->room_temperature = simulator->hlt_heater_temp = simulator->mlt_heater_temp = simulator->s_hlt_temp = simulator->s_mlt_temp = 20.0; + simulator->hlt_heater_temp = simulator->hlt_heater_size = simulator->mlt_heater_temp = simulator->mlt_heater_size = 0.0; + simulator->hlt_heater_time = simulator->mlt_heater_time = simulator->hlt_heater_state = simulator->mlt_heater_state = 0; + simulator->s_hlt_temp = simulator->s_mlt_temp = 0.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; + } + simulator->version = 1; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) { + simulator->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) { + simulator->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"ROOM_TEMPERATURE"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &fval) == 1) + 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) + 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) + simulator->hlt_heater_temp = fval; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_HEATER_TIME"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + simulator->hlt_heater_time = ival; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"HLT_HEATER_SIZE"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &fval) == 1) + simulator->hlt_heater_size = fval; + 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) + 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) + 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) + simulator->mlt_heater_temp = fval; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_HEATER_TIME"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + simulator->mlt_heater_time = ival; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"MLT_HEATER_SIZE"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &fval) == 1) + simulator->mlt_heater_size = fval; + 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) + simulator->mlt_heater_state = ival; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"S_HLT_TEMP"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &fval) == 1) + simulator->s_hlt_temp = fval; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"S_MLT_TEMP"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &fval) == 1) + simulator->s_mlt_temp = fval; + xmlFree(key); + } + cur = cur->next; + } + + if (Config.simulators == NULL) { + Config.simulators = simulator; + } else { + for (tmp = Config.simulators; tmp; tmp = tmp->next) { + if (tmp->next == NULL) { + tmp->next = simulator; + break; + } + } + } + + return 0; +} + + + +int parseSimulators(xmlDocPtr doc, xmlNodePtr cur) +{ + cur = cur->xmlChildrenNode; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"SIMULATOR"))) { + parseSimulator(doc, cur); + } + cur = cur->next; + } + return 0; +} #endif int rdconfig(void) { - int rc = 0; + int ival, rc = 0; char *mypath; xmlDocPtr doc; xmlNodePtr cur; @@ -369,21 +1316,36 @@ 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 *)"HLT_SENSOR_ADDRESS"))) { - Config.hlt_sensor_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if ((!xmlStrcmp(cur->name, (const xmlChar *)"TEMP_ADDRESS"))) { + Config.temp_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); + if ((!xmlStrcmp(cur->name, (const xmlChar *)"HUM_ADDRESS"))) { + Config.hum_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); } -#ifdef HAVE_WIRINGPI_H 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 *)"SIMULATORS"))) { + parseSimulators(doc, cur); + } #endif cur = cur->next; } diff -r 1421ece29197 -r eb724767860d brewco/slcd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brewco/slcd.c Wed Nov 25 22:49:35 2015 +0100 @@ -0,0 +1,210 @@ +/***************************************************************************** + * Copyright (C) 2015 + * + * Michiel Broek + * + * 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 "slcd.h" +#include "futil.h" +#include "xutil.h" + + + +struct sockaddr_in sendaddr; /* Server send socket */ +int sock = -1; +uint16_t keys = 0x0000; +uint16_t leds = 0x0400; /* LED's, buzzer, LCD backlight */ +uint16_t oleds = 0x0400; + +extern int debug; +extern sys_config Config; + + + +void putLCDsocket(int fd, uint16_t data) +{ + socklen_t slen; + uint16_t rdat; + + if (sock == -1) + return; + + if (sendto(sock, &data, sizeof(uint16_t), 0, (struct sockaddr *)&sendaddr, sizeof(sendaddr)) != sizeof(uint16_t)) { + syslog(LOG_NOTICE, "Socket %d send failed, closing socket: %s", sock, strerror(errno)); + if (shutdown(sock, SHUT_RDWR)) { + syslog(LOG_NOTICE, "Can't shutdown socket: %s", strerror(errno)); + } + sock = -1; + } else { + if (recvfrom(sock, &rdat, sizeof(uint16_t), 0, (struct sockaddr *) &sendaddr, &slen) != sizeof(uint16_t)) { + syslog(LOG_NOTICE, "Socket %d recvfrom failed, closing socket: %s", sock, strerror(errno)); + if (shutdown(sock, SHUT_RDWR)) { + syslog(LOG_NOTICE, "Can't shutdown socket: %s", strerror(errno)); + } + sock = -1; + } else { + if ((rdat & SLCD_MKEYS) == SLCD_KEYS) { + if (((rdat & 0x00ff) != keys) && debug) + fprintf(stdout, "received keys %04x was %04x\n", rdat & 0x00ff, keys); + keys = rdat & 0x00ff; + } else { + if (debug) + fprintf(stdout, "received %04x\n", rdat); + } + + } + } +} + + + +void slcdDummy(int fd) +{ + putLCDsocket(fd, SLCD_NULL); +} + + + +void slcdLEDs(int fd) +{ + if (leds != oleds) + putLCDsocket(fd, leds); + oleds = leds; +} + + +//void slcdHome(int fd) +//{ +//} + + + +void slcdClear(int fd) +{ + putLCDsocket(fd, SLCD_CLEAR); + putLCDsocket(fd, SLCD_HOME); +} + + + +//void slcdDisplay(int fd, int state) +//{ +//} + + + +//void slcdCursor(int fd, int state) +//{ +//} + + + +//void slcdCursorBlink(int fd, int state) +//{ +//} + + + +//void slcdSendCommand(int fd, unsigned char command) +//{ +//} + + + +void slcdPosition(int fd, int x, int y) +{ + uint16_t data = SLCD_DGRAM; + + data += (x & 0x1f) + ((y & 0x03) << 5); + putLCDsocket(fd, data); +} + + + +//void slcdCharDef(int fd, int index, unsigned char data[8]) +//{ +//} + + + +void slcdPutchar(int fd, unsigned char c) +{ + uint16_t data = SLCD_DATA; + + data += c & 0x0ff; + putLCDsocket(fd, data); +} + + + +void slcdPuts(int fd, const char *string) +{ + while (*string) + slcdPutchar(fd, *string++); +} + + + +void slcdPrintf(int fd, const char *message, ...) +{ + char buf[81 * sizeof(char)]; + va_list va_ptr; + + va_start(va_ptr, message); + vsnprintf(buf, (Config.lcd_cols + 1) * sizeof(char), message, va_ptr); + va_end(va_ptr); + slcdPuts(fd, buf); +} + + + +/* + * Try to setup a udp connection to 127.0.0.1 so we duplicate the panel + * display and keys of the real panel. This should fail on a production + * system because there should no brewpanel program be running. If it + * succeeds, all io will be duplicated over the network. + */ +int slcdInit(int fd, int cols, int rows) +{ + if ((sock = socket(AF_INET, SOCK_DGRAM /*| SOCK_NONBLOCK */, 0)) < 0) { + syslog(LOG_NOTICE, "slcdInit() can't create socket: %s", strerror(errno)); + return -1; + } + + /* + * Setup address structure for the server socket. + */ + memset(&sendaddr, 0, sizeof(struct sockaddr_in)); + sendaddr.sin_family = AF_INET; + sendaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + sendaddr.sin_port = htons(SEND_PORT); + + if (connect(sock, (struct sockaddr *)&sendaddr, sizeof(sendaddr)) < 0) { + close(sock); + sock = -1; + syslog(LOG_NOTICE, "slcdInit() can't bind sendsock %s", strerror(errno)); + return -1; + } + + syslog(LOG_NOTICE, "slcdInit() socket %d to brewpanel is active", sock); + return 0; +} + + diff -r 1421ece29197 -r eb724767860d brewco/slcd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brewco/slcd.h Wed Nov 25 22:49:35 2015 +0100 @@ -0,0 +1,15 @@ +#ifndef _SLCD_H +#define _SLCD_H + + +void slcdDummy(int fd); +void slcdLEDs(int fd); +void slcdClear(int fd); +void slcdPosition(int fd, int x, int y); +void slcdPutchar(int fd, unsigned char c); +void slcdPuts(int fd, const char *string); +void slcdPrintf(int fd, const char *message, ...); +int slcdInit(int fd, int cols, int rows); + + +#endif