Sun, 27 Dec 2015 17:52:26 +0100
Renamed Mash-in step to Prepare on the display. Don't run the pump when the mash is added. When preparing the mash, first heat the HLT, and then the MLT so that both have the chance to reach their target temperatures.
/***************************************************************************** * Copyright (C) 2015 * * Michiel Broek <mbroek at mbse dot eu> * * This file is part of the mbsePi-apps * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * mbsePi-apps is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ThermFerm; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ #include "brewco.h" #include "rdconfig.h" #include "rdsession.h" #include "rdrecipes.h" #include "util.h" #include "xutil.h" #include "lcd-pcf8574.h" #include "slcd.h" #include "lock.h" #include "devices.h" #include "keyboard.h" #include "simulator.h" #include "prompt.h" #include "setup.h" #include "logger.h" int my_shutdown = FALSE; int mlt_pump_state = 0; double hltInput; /* HLT PID variables */ double hltOutput; double hltSetpoint; double mltInput; /* MLT PID variables */ double mltOutput; double mltSetpoint; extern int debug; extern sys_config Config; extern a_recipe *recipes; extern int lcdHandle; extern int slcdHandle; extern int sock; #ifdef USE_SIMULATOR extern int SIM_cooler; #endif char *etcpath = NULL; char *varpath = NULL; #ifndef HAVE_WIRINGPI_H pthread_t threads[5]; #endif #define MANUAL_NONE 0 #define MANUAL_SELHLT 1 #define MANUAL_SELMLT 2 #define MANUAL_HLT 11 #define MANUAL_MLT 12 #define PERC_INIT 0 #define PERC_MLT 1 #define PERC_HLT 2 #define PERC_REST 3 int manual = MANUAL_NONE; /* * CGRAM characters */ unsigned char degC[8] = { 0b01000, 0b10100, 0b01000, 0b00111, 0b01000, 0b01000, 0b01000, 0b00111 }; unsigned char degF[8] = { 0b01000, 0b10100, 0b01000, 0b00111, 0b00100, 0b00110, 0b00100, 0b00100 }; unsigned char SP_Symbol[8] = { 0b11100, 0b10000, 0b11100, 0b00111, 0b11101, 0b00111, 0b00100, 0b00100 }; unsigned char PumpONOFF[8] = { 0b00000, 0b01110, 0b01010, 0b01110, 0b01000, 0b01000, 0b01000, 0b00000 }; unsigned char RevPumpONOFF[8] = { 0b11111, 0b10001, 0b10101, 0b10001, 0b10111, 0b10111, 0b10111, 0b11111 }; unsigned char HeatONOFF[8] = { 0b00000, 0b01010, 0b01010, 0b01110, 0b01110, 0b01010, 0b01010, 0b00000 }; unsigned char RevHeatONOFF[8] = { 0b11111, 0b10101, 0b10101, 0b10001, 0b10001, 0b10101, 0b10101, 0b11111 }; unsigned char Language[8] = { 0b11111, 0b00010, 0b01000, 0b11111, 0b00000, 0b10001, 0b10101, 0b11111 }; void help(void); void die(int); void help(void) { fprintf(stdout, "mbsePi-apps brewco v%s starting\n\n", VERSION); fprintf(stdout, "Usage: brewco [-d] [-h]\n"); fprintf(stdout, " -d --debug Debug and run in foreground\n"); fprintf(stdout, " -h --help Display this help\n"); } void die(int onsig) { switch (onsig) { #ifdef USE_SIMULATOR case SIGUSR1: syslog(LOG_NOTICE, "Got SIGUSR1, start cooler"); SIM_cooler = TRUE; return; case SIGUSR2: syslog(LOG_NOTICE, "Got SIGUSR2, stop cooler"); SIM_cooler = FALSE; return; #endif case SIGHUP: syslog(LOG_NOTICE, "Got SIGHUP, shutting down"); break; case SIGINT: syslog(LOG_NOTICE, "Keyboard interrupt, shutting down"); break; case SIGTERM: syslog(LOG_NOTICE, "Got SIGTERM, shutting down"); break; case SIGSEGV: syslog(LOG_NOTICE, "Got SIGSEGV, shutting down"); my_shutdown = TRUE; exit(SIGSEGV); break; default: syslog(LOG_NOTICE, "die() on signal %d", onsig); } my_shutdown = TRUE; } void tempstatus(void) { char text[81]; snprintf(text, 8, "%6.2f\001", hltInput); #ifdef HAVE_WIRINGPI_H piLock(LOCK_LCD); lcdPosition(lcdHandle, 1, 1); lcdPuts(lcdHandle, text); #endif slcdPosition(slcdHandle, 1, 1); slcdPuts(slcdHandle, text); snprintf(text, 8, "%6.2f\001", mltInput); #ifdef HAVE_WIRINGPI_H piLock(LOCK_LCD); lcdPosition(lcdHandle, 10, 1); lcdPuts(lcdHandle, text); #endif slcdPosition(slcdHandle, 10, 1); slcdPuts(slcdHandle, text); } /* * Third line, show setPoints or heater percentage. */ void percstatus(int which) { char text[21]; if (which) snprintf(text, 8, "%6.2f\002", hltSetpoint); else snprintf(text, 8, "HLT%3d%%", (int)hltOutput); #ifdef HAVE_WIRINGPI_H piLock(LOCK_LCD); lcdPosition(lcdHandle, 1, 2); lcdPuts(lcdHandle, text); #endif slcdPosition(slcdHandle, 1, 2); slcdPuts(slcdHandle, text); if (which) snprintf(text, 8, "%6.2f\002", mltSetpoint); else snprintf(text, 8, "MLT%3d%%", (int)mltOutput); #ifdef HAVE_WIRINGPI_H piLock(LOCK_LCD); lcdPosition(lcdHandle, 10, 2); lcdPuts(lcdHandle, text); #endif slcdPosition(slcdHandle, 10, 2); slcdPuts(slcdHandle, text); } /* * Third line during boil, only MLT status */ void mltstatus(void) { char text[21]; snprintf(text, 20, "MLT %3d%% %6.2f\002 ", (int)mltOutput, mltSetpoint); #ifdef HAVE_WIRINGPI_H piLock(LOCK_LCD); lcdPosition(lcdHandle, 0, 2); lcdPuts(lcdHandle, text); #endif slcdPosition(slcdHandle, 0, 2); slcdPuts(slcdHandle, text); } void timestatus(int row, int timeval) { char text[21]; int hours, mins, val = timeval; hours = val / 3600; val -= (hours * 3600); mins = val / 60; val -= (mins * 60); snprintf(text, 20, " %02d:%02d:%02d ", hours, mins, val); #ifdef HAVE_WIRINGPI_H piLock(LOCK_LCD); lcdPosition(lcdHandle, 0, row); lcdPuts(lcdHandle, text); #endif slcdPosition(slcdHandle, 0, row); slcdPuts(slcdHandle, text); } int set_HLT_heater(units_list *unit, int state, double val) { if (strcmp(unit->hlt_heater.uuid, (char *)"00000000-0000-0000-0000-000000000000") == 0) return 0; hltSetpoint = val; if (state && (PID_getMode(unit->PID_hlt) == P_MANUAL)) { hlt_status(1); PID_setMode(unit->PID_hlt, P_AUTOMATIC); return 1; } if (! state && (PID_getMode(unit->PID_hlt) == P_AUTOMATIC)) { hlt_status(0); PID_setMode(unit->PID_hlt, P_MANUAL); return 1; } return 0; } int set_MLT_heater(units_list *unit, int state, double val) { if (strcmp(unit->mlt_heater.uuid, (char *)"00000000-0000-0000-0000-000000000000") == 0) return 0; mltSetpoint = val; if (state && (PID_getMode(unit->PID_mlt) == P_MANUAL)) { mlt_status(1); PID_setMode(unit->PID_mlt, P_AUTOMATIC); return 1; } if (! state && (PID_getMode(unit->PID_mlt) == P_AUTOMATIC)) { mlt_status(0); PID_setMode(unit->PID_mlt, P_MANUAL); return 1; } return 0; } int set_MLT_pump(units_list *unit, int state) { if (strcmp(unit->mlt_pump.uuid, (char *)"00000000-0000-0000-0000-000000000000") == 0) return 0; if (state && ! mlt_pump_state) { device_out(unit->mlt_pump.uuid, 1); mlt_pump_state = 1; return 1; } if (! state && mlt_pump_state) { device_out(unit->mlt_pump.uuid, 0); mlt_pump_state = 0; return 1; } return 0; } void automatic_brew(units_list *, brew_session *, a_recipe *, int, int); void automatic_brew(units_list *unit, brew_session *brew, a_recipe *recipe, int dosave, int seconds) { int key, save = dosave, i; char data[128]; static int mash_fase = MASH_NA, hopstand = 0, last_step = STEP_NA, last_fase = -1, oldsec = 75, startdelay = 0; if (brew->brewstep != last_step) { snprintf(data, 40, brewstep_name(last_step)); syslog(LOG_NOTICE, "AUTO: brewstep %s to %s", data, brewstep_name(brew->brewstep)); } switch (brew->brewstep) { case STEP_NA: if (debug) fprintf(stdout, "auto: init recipe: %s-%s unit: %s\n", recipe->code, recipe->name, unit->name); syslog(LOG_NOTICE, "AUTO: starting new brew, recipe: %s-%s unit: %s", recipe->code, recipe->name, unit->name); brew->brewstep = STEP_BREWINIT; break; case STEP_BREWINIT: prompt(103, NULL); /* " AUTOMATIC MODE " */ prompt(207, NULL); /* " Delay start? " */ prompt(300, NULL); /* " " */ prompt(407, NULL); /* "--- --- No Yes " */ if (debug) fprintf(stdout, "step brewinit\n"); key = keywait(); if (key == KEY_RETURN) { brew->brewstep = STEP_WATERCHECK; startdelay = 0; syslog(LOG_NOTICE, "AUTO: brew initialize, direct start selected"); break; } if (key == KEY_ENTER) { startdelay = 30; editInteger(&startdelay, 10, 960, 10, (char *)"Start delay", (char *)"mins"); } syslog(LOG_NOTICE, "AUTO: brew initialize"); brew->brewstep = STEP_WATERCHECK; break; case STEP_WATERCHECK: if (brew->brewstep != last_step) { prompt(111, NULL); /* "AUTO --> Mash In " */ prompt(209, NULL); /* " Water Added? " */ prompt(300, NULL); prompt(407, NULL); /* "--- --- No Yes " */ last_step = brew->brewstep; } slcdDummy(slcdHandle); key = keycheck(); if (key == KEY_ENTER) { brew->brewstep = STEP_PUMPPRIME; syslog(LOG_NOTICE, "AUTO: confirmed water added"); } if (key == KEY_RETURN) { syslog(LOG_NOTICE, "AUTO: aborted water added"); brew->brewstep = STEP_CLEANUP; } break; case STEP_PUMPPRIME: if (brew->brewstep != last_step) { prompt(100, NULL); /* " " */ prompt(210, NULL); /* " Pump Prime " */ prompt(300, NULL); /* " " */ prompt(400, NULL); /* " " */ hlt_status(0); mlt_status(0); last_step = brew->brewstep; } for (i = 1; i < 6; i++) { if (set_MLT_pump(unit, 1)) syslog(LOG_NOTICE, "AUTO: pump prime %d turn %s MLT pump", i, mlt_pump_state ? "on":"off"); usleep(750000 + (i * 250000)); /* 250 + i * 250 mSec */ if (set_MLT_pump(unit, 0)) syslog(LOG_NOTICE, "AUTO: pump prime %d turn %s MLT pump", i, mlt_pump_state ? "on":"off"); usleep(350000); /* 350 mSec */ } brew->brewstep = STEP_WAITSTART; break; case STEP_WAITSTART: if (startdelay == 0) { brew->brewstep = STEP_PREMASH; break; } if (brew->brewstep != last_step) { brew->timeout = startdelay * 60; prompt(111, NULL); /* "AUTO --> Mash In " */ prompt(212, NULL); /* " To be started in " */ prompt(410, NULL); /* " Continue: Yes No " */ last_step = brew->brewstep; } if (oldsec != seconds) { timestatus(2, brew->timeout); brew->timeout--; if (brew->timeout <= 0) { syslog(LOG_NOTICE, "AUTO: delayed start time reached"); brew->brewstep = STEP_PREMASH; } oldsec = seconds; } slcdDummy(slcdHandle); key = keycheck(); if (key == KEY_RETURN) { syslog(LOG_NOTICE, "AUTO: delayed start skipped by user"); brew->brewstep = STEP_PREMASH; } break; case STEP_PREMASH: if (brew->brewstep != last_step) { prompt(111, NULL); /* "AUTO --> Prepare " */ prompt(300, NULL); /* " " */ prompt(418, NULL); /* "--- --- Pause --- " */ tempstatus(); hlt_status(1); mlt_status(1); pump_status(unit->pump_premash); last_step = brew->brewstep; initlog(brew->name); } if (set_HLT_heater(unit, 1, 85.0)) syslog(LOG_NOTICE, "AUTO: premash turn on HLT at %6.2f", hltSetpoint); if (set_MLT_heater(unit, 1, 10.0)) syslog(LOG_NOTICE, "AUTO: premash turn on MLT at %6.2f", mltSetpoint); if (set_MLT_pump(unit, unit->pump_premash)) syslog(LOG_NOTICE, "AUTO: premash turn %s MLT pump", mlt_pump_state ? "on":"off"); if (hltInput >= 85.0) { brew->brewstep = STEP_MASHING; brew->mashstep = 0; mash_fase = MASH_NA; save = TRUE; } break; case STEP_MASHING: if (brew->brewstep != last_step) { prompt(111 + brew->mashstep, NULL); /* "AUTO --> [mashname] " */ prompt(300, NULL); /* " " */ prompt(418, NULL); /* "--- --- Pause --- " */ tempstatus(); hlt_status(1); mlt_status(1); pump_status(unit->pump_onmash); last_step = brew->brewstep; } if (set_HLT_heater(unit, 1, 85.0)) syslog(LOG_NOTICE, "AUTO: mash turn on HLT at %6.2f", hltSetpoint); if (set_MLT_heater(unit, 1, recipe->mash[brew->mashstep].setpoint)) syslog(LOG_NOTICE, "AUTO: mash turn on MLT at %6.2f", mltSetpoint); switch (mash_fase) { case MASH_NA: if (recipe->mash[brew->mashstep].skip) { syslog(LOG_NOTICE, "AUTO: skipping mash step %d", brew->mashstep); brew->mashstep++; } else { mltSetpoint = recipe->mash[brew->mashstep].setpoint; brew->timeout = recipe->mash[brew->mashstep].duration * 60; mash_fase = MASH_HEATING; syslog(LOG_NOTICE, "AUTO: mash step %d fase NA, setpoint %6.2f, duration %d", brew->mashstep, mltSetpoint, brew->timeout); } if (brew->mashstep == 0) { brew->starttime = time(NULL); save = TRUE; } break; case MASH_PROMPT: if (last_fase != mash_fase) { prompt(111 + brew->mashstep, NULL); /* "AUTO --> [mashname] " */ prompt(219, NULL); /* " Mash added? " */ prompt(300, NULL); prompt(407, NULL); /* "--- --- No Yes " */ last_fase = mash_fase; } if (set_MLT_pump(unit, 0)) /* Off during mash add */ syslog(LOG_NOTICE, "AUTO: mash turn %s MLT pump", mlt_pump_state ? "on":"off"); slcdDummy(slcdHandle); key = keycheck(); if (key == KEY_ENTER) { mash_fase = MASH_NA; brew->mashstep++; syslog(LOG_NOTICE, "AUTO: confirmed mash added"); } if (key == KEY_RETURN) { syslog(LOG_NOTICE, "AUTO: aborted mash added"); brew->brewstep = STEP_CLEANUP; brew->mashstep = 0; } break; case MASH_IODINE: if (last_fase != mash_fase) { prompt(118, NULL); /* "AUTO --> Mash Out " */ prompt(213, NULL); /* " Iodine test " */ timestatus(2, brew->timeout); prompt(410, NULL); /* " Continue: Yes No " */ last_fase = mash_fase; } if (set_MLT_pump(unit, unit->pump_onmash)) syslog(LOG_NOTICE, "AUTO: mash turn %s MLT pump", mlt_pump_state ? "on":"off"); if (oldsec != seconds) { brew->timeout--; timestatus(2, brew->timeout); if (brew->timeout <= 0) { syslog(LOG_NOTICE, "AUTO: mash IODINE test timeout"); mash_fase = MASH_NA; brew->mashstep++; } oldsec = seconds; } slcdDummy(slcdHandle); key = keycheck(); if (key == KEY_RETURN) { syslog(LOG_NOTICE, "AUTO: mash IODINE test confirmed"); mash_fase = MASH_NA; brew->mashstep++; } if (key == KEY_ENTER) { syslog(LOG_NOTICE, "AUTO: mash IODINE test declined"); mash_fase = MASH_REST; brew->timeout = 600; /* Add 10 more minutes */ } break; case MASH_HEATING: if (last_fase != mash_fase) { prompt(111 + brew->mashstep, NULL); /* "AUTO --> [mashname] " */ prompt(200, NULL); prompt(300, NULL); prompt(418, NULL); /* "--- --- Pause --- " */ hlt_status(1); mlt_status(1); pump_status(unit->pump_onmash); last_fase = mash_fase; } if (set_MLT_pump(unit, unit->pump_onmash)) syslog(LOG_NOTICE, "AUTO: mash turn %s MLT pump", mlt_pump_state ? "on":"off"); if (oldsec != seconds) { tempstatus(); percstatus((seconds / 2) % 4); oldsec = seconds; } if (mltInput > mltSetpoint) { syslog(LOG_NOTICE, "AUTO: mash step %d fase HEATING reached %6.2f", brew->mashstep, mltSetpoint); mash_fase = MASH_REST; } break; case MASH_REST: if (last_fase != mash_fase) { prompt(111 + brew->mashstep, NULL); /* "AUTO --> [mashname] " */ prompt(200, NULL); prompt(300, NULL); prompt(418, NULL); /* "--- --- Pause --- " */ hlt_status(1); mlt_status(1); pump_status(unit->pump_onmash); last_fase = mash_fase; } if (oldsec != seconds) { tempstatus(); timestatus(2, brew->timeout); if (brew->mashstep == 7) { /* * During mash-out rest, allow the grain to sink */ if (set_MLT_pump(unit, unit->pump_mashout)) syslog(LOG_NOTICE, "AUTO: mash-out turn %s MLT pump", mlt_pump_state ? "on":"off"); } else { if (set_MLT_pump(unit, unit->pump_onmash)) syslog(LOG_NOTICE, "AUTO: mash turn %s MLT pump", mlt_pump_state ? "on":"off"); } brew->timeout--; if (brew->timeout <= 0) { syslog(LOG_NOTICE, "AUTO: mash step %d fase REST done", brew->mashstep); if ((brew->mashstep == 0) && ! unit->skip_add) { mash_fase = MASH_PROMPT; } else if ((brew->mashstep == 6) && ! unit->skip_iodine) { mash_fase = MASH_IODINE; brew->timeout = unit->iodine_time * 60; } else if (brew->mashstep == 7) { mash_fase = MASH_DONE; } else { mash_fase = MASH_NA; brew->mashstep++; } } oldsec = seconds; } break; case MASH_DONE: syslog(LOG_NOTICE, "AUTO: mash step %d fase DONE", brew->mashstep); if (set_MLT_heater(unit, 1, recipe->mash[7].setpoint)) syslog(LOG_NOTICE, "AUTO: mash done turn MLT off"); if (set_MLT_pump(unit, 0)) syslog(LOG_NOTICE, "AUTO: mash done turn %s MLT pump", mlt_pump_state ? "on":"off"); brew->mashstep = 0; brew->brewstep = STEP_MASHREMOVE; break; } break; case STEP_MASHREMOVE: if (unit->skip_remove) { syslog(LOG_NOTICE, "AUTO: skipping Mash remove"); brew->brewstep = STEP_PREBOIL; } else { if (brew->brewstep != last_step) { prompt(118, NULL); /* "AUTO --> Mash Out " */ prompt(220, NULL); /* " Mash Removed? " */ prompt(300, NULL); prompt(410, NULL); /* " Continue: Yes No " */ last_step = brew->brewstep; } slcdDummy(slcdHandle); key = keycheck(); if (key == KEY_RETURN) { syslog(LOG_NOTICE, "AUTO: Confirmed Mash removed"); brew->brewstep = STEP_PREBOIL; } } break; case STEP_PREBOIL: if (brew->brewstep != last_step) { prompt(119, NULL); /* "AUTO --> Boil " */ prompt(200, NULL); prompt(300, NULL); tempstatus(); mltstatus(); prompt(418, NULL); /* "--- --- Pause --- " */ hlt_status(0); mlt_status(1); pump_status(unit->pump_onboil && (mltInput < unit->pump_stop)); last_step = brew->brewstep; } if (oldsec != seconds) { tempstatus(); mltstatus(); oldsec = seconds; } if (set_HLT_heater(unit, 0, 10.0)) syslog(LOG_NOTICE, "AUTO: preboil turn off HLT"); if (set_MLT_heater(unit, 1, 100.0)) syslog(LOG_NOTICE, "AUTO: preboil turn on MLT to boil"); if (set_MLT_pump(unit, unit->pump_onboil && (mltInput < unit->pump_stop))) syslog(LOG_NOTICE, "AUTO: preboil turn %s MLT pump", mlt_pump_state ? "on":"off"); if (mltInput > 99.2) { syslog(LOG_NOTICE, "AUTO: reached boil temperature %.2f, start %d minutes boil", mltInput, recipe->boiltime); brew->brewstep = STEP_BOILING; brew->boiltimer = recipe->boiltime * 60; } break; case STEP_BOILING: if (set_HLT_heater(unit, 0, 10.0)) syslog(LOG_NOTICE, "AUTO: boil turn off HLT"); if (set_MLT_heater(unit, 1, 100.0)) syslog(LOG_NOTICE, "AUTO: boil turn on MLT to boil"); if (set_MLT_pump(unit, unit->pump_onboil && (mltInput < unit->pump_stop))) syslog(LOG_NOTICE, "AUTO: boil turn %s MLT pump", mlt_pump_state ? "on":"off"); if (brew->brewstep != last_step) { prompt(119, NULL); /* "AUTO --> Boil " */ prompt(200, NULL); prompt(300, NULL); tempstatus(); mltstatus(); prompt(418, NULL); /* "--- --- Pause --- " */ hlt_status(0); mlt_status(1); pump_status(unit->pump_onboil && (mltInput < unit->pump_stop)); last_step = brew->brewstep; } if (oldsec != seconds) { tempstatus(); if ((seconds / 2) % 4) { timestatus(2, brew->boiltimer); } else { mltstatus(); } if (brew->boiltimer >= 0) { brew->boiltimer--; } else { brew->brewstep = STEP_BOILDONE; syslog(LOG_NOTICE, "AUTO: boil is done"); } oldsec = seconds; } break; case STEP_BOILDONE: if (set_MLT_heater(unit, 0, 10.0)) syslog(LOG_NOTICE, "AUTO: after boil turn off MLT heater"); if (set_MLT_pump(unit, 0)) syslog(LOG_NOTICE, "AUTO: after boil turn %s MLT pump", mlt_pump_state ? "on":"off"); if (brew->brewstep != last_step) { prompt(120, NULL); /* "AUTO --> Cooling " */ prompt(214, NULL); /* " START COOLING " */ prompt(300, NULL); prompt(410, NULL); /* " Continue: Yes No " */ last_step = brew->brewstep; } slcdDummy(slcdHandle); key = keycheck(); if (key == KEY_ENTER) { brew->brewstep = STEP_CLEANUP; syslog(LOG_NOTICE, "AUTO: user skipped cooling"); } if (key == KEY_RETURN) { brew->brewstep = STEP_COOLING; syslog(LOG_NOTICE, "AUTO: user started cooling"); } break; case STEP_COOLING: for (i = 0; i < 3; i++) { if ((recipe->hopstand[i].skip == 0) && (mltInput <= recipe->hopstand[i].max) && (mltInput >= recipe->hopstand[i].min)) { brew->brewstep = STEP_HOPSTAND; hopstand = i; syslog(LOG_NOTICE, "AUTO: starting hopstand %d", i+1); } } if (brew->brewstep == STEP_HOPSTAND) break; // hot whirlpool start at 85 degrees // cold whirlpool start at 30 degrees if (brew->brewstep != last_step) { prompt(120, NULL); /* "AUTO --> Cooling " */ prompt(200, NULL); tempstatus(); prompt(300, NULL); prompt(418, NULL); /* "--- --- Pause --- " */ hlt_status(0); mlt_status(0); pump_status(0); last_step = brew->brewstep; } if (oldsec != seconds) { tempstatus(); oldsec = seconds; } if (mltInput <= recipe->coolto) { syslog(LOG_NOTICE, "AUTO: cool temperture %.2f reached", recipe->coolto); brew->brewstep = STEP_CLEANUP; } break; case STEP_HOPSTAND: if (brew->brewstep != last_step) { prompt(122 + hopstand, NULL); /* "AUTO --> Hopstand n " */ tempstatus(); timestatus(2, brew->timeout); prompt(418, NULL); /* "--- --- Pause --- " */ brew->boiltimer = recipe->hopstand[hopstand].duration * 60; last_step = brew->brewstep; } if (recipe->hopstand[hopstand].hold) { if (set_MLT_heater(unit, 1, recipe->hopstand[hopstand].setpoint)) syslog(LOG_NOTICE, "AUTO: hopstand 1 turn on MLT at %6.2f", mltSetpoint); } if (set_MLT_pump(unit, 1)) syslog(LOG_NOTICE, "AUTO: hopstand 1 turn %s MLT pump", mlt_pump_state ? "on":"off"); if (oldsec != seconds) { tempstatus(); timestatus(2, brew->timeout); brew->boiltimer--; if (brew->boiltimer <= 0) { syslog(LOG_NOTICE, "AUTO: hopstand %d done", hopstand+1); if (set_MLT_heater(unit, 0, 10.0)) syslog(LOG_NOTICE, "AUTO: hopstand 1 turn off MLT at %6.2f", mltSetpoint); brew->brewstep = STEP_COOLING; } oldsec = seconds; } break; case STEP_WHIRLPOOL: prompt(121, NULL); /* "AUTO --> Whirlpool " */ break; case STEP_CLEANUP: if (brew->brewstep != last_step) { prompt(101, NULL); /* " Brewco x.x.x " */ prompt(200, NULL); /* " " */ prompt(300, NULL); /* " " */ prompt(400, NULL); /* " " */ last_step = brew->brewstep; } syslog(LOG_NOTICE, "AUTO: cleanup"); if (set_HLT_heater(unit, 0, 10.0)) syslog(LOG_NOTICE, "AUTO: cleanup turn on HLT at %6.2f", hltSetpoint); if (set_MLT_heater(unit, 0, 10.0)) syslog(LOG_NOTICE, "AUTO: cleanup turn on MLT at %6.2f", mltSetpoint); if (set_MLT_pump(unit, 0)) syslog(LOG_NOTICE, "AUTO: cleanup turn %s MLT pump", mlt_pump_state ? "on":"off"); brew->brewstep = STEP_BREWDONE; break; case STEP_BREWDONE: if (brew->brewstep != last_step) { prompt(101, NULL); /* " Brewco x.x.x " */ prompt(200, NULL); /* " " */ prompt(301, NULL); /* " Finished " */ prompt(408, NULL); /* "--- --- Ok --- " */ last_step = brew->brewstep; } syslog(LOG_NOTICE, "AUTO: brew done"); brew->brewstep = -1; brew->endtime = time(NULL); save = TRUE; do { key = keywait(); } while (key != KEY_RETURN); /* * Rewrite the display */ prompt(101, NULL); /* " Brewco x.x.x " */ tempstatus(); prompt(300, NULL); /* " " */ prompt(401, NULL); /* "--- MAN AUTO SETUP" */ break; } if (save) { snprintf(data, 127, "%d,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f", brew->brewstep, hltInput, hltOutput, hltSetpoint, mltInput, mltOutput, mltSetpoint); logger(brew->name, data); wrsession(brew); } } void manual_prompt(void) { switch (manual) { case MANUAL_SELHLT: prompt(104, NULL); /* " MANUAL MODE " */ prompt(303, NULL); /* " Manual HLT " */ prompt(402, NULL); /* "--- dwn quit ok " */ break; case MANUAL_SELMLT: prompt(104, NULL); /* " MANUAL MODE " */ prompt(304, NULL); /* " Manual MLT " */ prompt(404, NULL); /* " up --- quit ok " */ break; case MANUAL_HLT: prompt(104, NULL); /* " MANUAL MODE " */ prompt(300, NULL); /* " " */ prompt(413, NULL); /* "UP* *DWN heat --- " */ break; case MANUAL_MLT: prompt(104, NULL); /* " MANUAL MODE " */ prompt(300, NULL); /* " " */ prompt(406, NULL); /* "UP* *DWN heat pmp " */ break; } } /* * Manual menu for testing your equipment. */ int manual_menu(units_list *, int); int manual_menu(units_list *unit, int seconds) { int key; switch (manual) { case MANUAL_SELHLT: slcdDummy(slcdHandle); key = keycheck(); if (key == KEY_DOWN) { manual = MANUAL_SELMLT; manual_prompt(); } if (key == KEY_RETURN) { manual = MANUAL_NONE; mlt_pump_state = 0; PID_setMode(unit->PID_mlt, P_MANUAL); PID_setMode(unit->PID_hlt, P_MANUAL); hlt_status(0); mlt_status(0); device_out(unit->mlt_pump.uuid, mlt_pump_state); } if (key == KEY_ENTER) { // TODO: prompt for water manual = MANUAL_HLT; manual_prompt(); } break; case MANUAL_SELMLT: slcdDummy(slcdHandle); key = keycheck(); if (key == KEY_UP) { manual = MANUAL_SELHLT; manual_prompt(); } if (key == KEY_RETURN) { manual = MANUAL_NONE; mlt_pump_state = 0; PID_setMode(unit->PID_mlt, P_MANUAL); PID_setMode(unit->PID_hlt, P_MANUAL); hlt_status(0); mlt_status(0); device_out(unit->mlt_pump.uuid, mlt_pump_state); } if (key == KEY_ENTER) { // TODO: prompt for water manual = MANUAL_MLT; manual_prompt(); } break; case MANUAL_HLT: tempstatus(); percstatus((seconds / 2) % 4); slcdDummy(slcdHandle); key = keycheck(); if (key == KEY_RETURN) { if (PID_getMode(unit->PID_hlt) == P_MANUAL) { PID_setMode(unit->PID_hlt, P_AUTOMATIC); hlt_status(1); } else { PID_setMode(unit->PID_hlt, P_MANUAL); hlt_status(0); } } if ((key == KEY_DOWN) && (hltSetpoint > 10)) hltSetpoint -= 1.0; if ((key == KEY_UP) && (hltSetpoint < 100)) hltSetpoint += 1.0; if (key == KEY_ESCAPE) { manual = MANUAL_SELHLT; manual_prompt(); } break; case MANUAL_MLT: tempstatus(); percstatus((seconds / 2) % 4); slcdDummy(slcdHandle); key = keycheck(); if (key == KEY_RETURN) { if (PID_getMode(unit->PID_mlt) == P_MANUAL) { PID_setMode(unit->PID_mlt, P_AUTOMATIC); mlt_status(1); } else { PID_setMode(unit->PID_mlt, P_MANUAL); mlt_status(0); } } if ((key == KEY_DOWN) && (mltSetpoint > 10)) mltSetpoint -= 1.0; if ((key == KEY_UP) && (mltSetpoint < 100)) mltSetpoint += 1.0; if (key == KEY_ENTER) { if (mlt_pump_state) set_MLT_pump(unit, 0); else set_MLT_pump(unit, 1); } if (key == KEY_ESCAPE) { manual = MANUAL_SELMLT; manual_prompt(); } device_out(unit->mlt_pump.uuid, mlt_pump_state); break; } return 0; } char *choose_recipe(void); char *choose_recipe(void) { int total, i, key, choice = 1; static char uuid[37]; a_recipe *recipe; char pmpt[81]; strcpy(uuid, (char *)"00000000-0000-0000-0000-000000000000"); for (;;) { total = 0; for (recipe = recipes; recipe; recipe = recipe->next) total++; if (total == 0) return uuid; i = 0; for (recipe = recipes; recipe; recipe = recipe->next) { i++; if (i == choice) break; } prompt(102, NULL); /* " SETUP MENU " */ prompt(221, NULL); /* " Select Recipe " */ if (total) { snprintf(pmpt, Config.lcd_cols + 1, "%s %s ", recipe->code, recipe->name); prompt(300, pmpt); } if (total == 1) prompt(405, NULL); /* "--- --- quit ok " */ else if (choice == 1) prompt(402, NULL); /* "--- dwn quit ok " */ else if (choice == total) prompt(404, NULL); /* " up --- quit ok " */ else prompt(403, NULL); /* " up dwn quit ok " */ key = keywait(); if ((key == KEY_RETURN) || my_shutdown) return uuid; if (key == KEY_ENTER) { strcpy(uuid, recipe->uuid); return uuid; } if ((key == KEY_UP) && (total > 1) && (choice > 1)) { choice--; } if ((key == KEY_DOWN) && (total > 1) && (choice < total)) choice++; } } int server(void); int server(void) { int rc = 0, run = 1, dosave, key, temp, MLTp, HLTp, percslot, percfase = PERC_INIT; int do_init = TRUE, seconds = 0, minutes = 0; units_list *unit; a_recipe *recipe = NULL; brew_session *brew = NULL; #ifndef HAVE_WIRINGPI_H long t = 0; #endif time_t now, last = (time_t)0; long nowmillis, perctimer; struct tm *tm; prompt(101, NULL); /* * Define special characters in the display CGRAM */ if (Config.tempFormat == 'C') slcdCharDef(slcdHandle, 1, degC); else slcdCharDef(slcdHandle, 1, degF); slcdCharDef(slcdHandle, 2, SP_Symbol); slcdCharDef(slcdHandle, 3, PumpONOFF); slcdCharDef(slcdHandle, 4, RevPumpONOFF); slcdCharDef(slcdHandle, 5, HeatONOFF); slcdCharDef(slcdHandle, 6, RevHeatONOFF); slcdCharDef(slcdHandle, 7, Language); if (lockprog((char *)"brewco")) { syslog(LOG_NOTICE, "Can't lock"); return 1; } if (debug) fprintf(stdout, "Begin server()\n"); if ((rc = devices_detect())) { syslog(LOG_NOTICE, "Detected %d new devices", rc); if (debug) fprintf(stdout, "Detected %d new devices\n", 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 } #ifdef HAVE_WIRINGPI_H rc = piThreadCreate(my_keyboard_loop); #else rc = pthread_create(&threads[t], NULL, my_keyboard_loop, (void *)t ); #endif if (rc) { fprintf(stderr, "my_keyboard_loop thread didn't start rc=%d\n", rc); syslog(LOG_NOTICE, "my_keyboard_loop thread didn't start rc=%d", rc); #ifndef HAVE_WIRINGPI_H } else { t++; #endif } #ifdef USE_SIMULATOR #ifdef HAVE_WIRINGPI_H rc = piThreadCreate(my_simulator_loop); #else rc = pthread_create(&threads[t], NULL, my_simulator_loop, (void *)t ); #endif if (rc) { fprintf(stderr, "my_simulator_loop thread didn't start rc=%d\n", rc); syslog(LOG_NOTICE, "my_simulator_loop thread didn't start rc=%d", rc); #ifndef HAVE_WIRINGPI_H } else { t++; #endif } #endif if (! Config.units) { /* * No brewsystems defined, add the first */ prompt(218, NULL); /* Add Brewsystem? */ prompt(407, NULL); /* --- --- Ok --- */ do { key = keywait(); } while (key != KEY_RETURN); if (key == KEY_RETURN) { addUnit(1); } } /* * Initialize units for processing */ for (unit = Config.units; unit; unit = unit->next) { if (unit->active) break; } if (! unit->active) { fprintf(stdout, "No active units found\n"); } /* * Safety, turn everything off */ if (unit->active) { if (debug) fprintf(stdout, "Starting brewsystem %d `%s'\n", unit->number, unit->name); syslog(LOG_NOTICE, "Starting brewsystem %d `%s'", unit->number, unit->name); } /* * During automation there will be a state file: * ~/.brewco/var/brewing.xml * If this file is present, there has been a crash. */ brew = (brew_session *)malloc(sizeof(brew_session)); rc = rdsession(brew); syslog(LOG_NOTICE, "rdsession: rc=%d", rc); if (debug) fprintf(stdout, "rdsession: rc=%d\n", rc); char *mypath = xstrcpy(etcpath); mypath = xstrcat(mypath, (char *)"brewing.xml"); if (rc == 0) { if (debug) fprintf(stdout, "Active brew session found\n"); } else if (rc == -1) { free(brew); brew = NULL; if (debug) fprintf(stdout, "No active brew session found\n"); } else { unlink(mypath); free(brew); brew = NULL; if (debug) fprintf(stdout, "Error brew session found\n"); } free(mypath); mypath = NULL; do { if (my_shutdown) { run = 0; unit->hlt_heater.value = 0; unit->mlt_heater.value = 0; unit->mlt_pump.value = 0; device_out(unit->hlt_heater.uuid, 0); device_out(unit->mlt_heater.uuid, 0); device_out(unit->mlt_pump.uuid, 0); hlt_status(0); mlt_status(0); break; } /* * Do we need to initialize this unit? */ if (do_init) { if (debug) fprintf(stdout, "Initialize brewsystem %d `%s'\n", unit->number, unit->name); syslog(LOG_NOTICE, "Initialize brewsystem %d `%s'", unit->number, unit->name); prompt(0, NULL); prompt(101, NULL); /* " Brewco x.x.x " */ prompt(401, NULL); /* "--- MAN AUTO SETUP" */ /* * Turn everything off */ unit->hlt_heater.value = 0; unit->mlt_heater.value = 0; unit->mlt_pump.value = 0; device_out(unit->hlt_heater.uuid, 0); device_out(unit->mlt_heater.uuid, 0); device_out(unit->mlt_pump.uuid, 0); /* * Initialize PID's */ hltInput = hltSetpoint = mltInput = mltSetpoint = 20.0; hltOutput = mltOutput = 0; PID_init(unit->PID_hlt, &hltInput, &hltOutput, &hltSetpoint, unit->PID_hlt->dispKp, unit->PID_hlt->dispKi, unit->PID_hlt->dispKd, unit->PID_hlt->Direction); PID_setOutputLimits(unit->PID_hlt, 0, 100); PID_setSampleTime(unit->PID_hlt, unit->PID_hlt->SampleTime); PID_init(unit->PID_mlt, &mltInput, &mltOutput, &mltSetpoint, unit->PID_mlt->dispKp, unit->PID_mlt->dispKi, unit->PID_mlt->dispKd, unit->PID_mlt->Direction); PID_setOutputLimits(unit->PID_mlt, 0, 100); PID_setSampleTime(unit->PID_mlt, unit->PID_mlt->SampleTime); hlt_status(0); mlt_status(0); manual = MANUAL_NONE; do_init = FALSE; nowmillis = perctimer = millis(); percslot = 0; percfase = PERC_INIT; dosave = 0; if (brew) { /* * Restore session */ if (debug) fprintf(stdout, "loop_init: restoring brew session\n"); for (recipe = recipes; recipe; recipe = recipe->next) { if (strcmp(recipe->uuid, brew->uuid_recipe) == 0) { break; } } if (debug) fprintf(stdout, "loop_init: brewstep=%d mashstep=%d recipe=%s\n", brew->brewstep, brew->mashstep, recipe->code); } } /* run_pause code here */ /* * Update PID's, even if they are off. Both PID's will do * the scheduling by themselves. */ rc = PID_compute(unit->PID_hlt); rc = PID_compute(unit->PID_mlt); /* * This is the serial heaters schedule loop. The total * loop time is 5 seconds, heating is 0..100% so we * have 5 mSeconds timeslots. The MLT has priority over * the HLT heater, so the HLT heater can get too little * power. TODO: simultaneous use must be implemented. * In sequentiel mode, the total drawn power is the same * as the power used by the largest heater element. */ nowmillis = millis(); if (nowmillis > (perctimer + 50)) { percslot++; if (percfase == PERC_INIT) { HLTp = (int)hltOutput; MLTp = (int)mltOutput; if ((MLTp + HLTp) > 100) HLTp = 100 - MLTp; /* The HLT has lower priority */ if (MLTp) { percfase = PERC_MLT; device_out(unit->hlt_heater.uuid, 0); device_out(unit->mlt_heater.uuid, 1); } else if (HLTp) { percfase = PERC_HLT; device_out(unit->hlt_heater.uuid, 1); device_out(unit->mlt_heater.uuid, 0); } else { percfase = PERC_REST; device_out(unit->hlt_heater.uuid, 0); device_out(unit->mlt_heater.uuid, 0); } // if (debug) // fprintf(stdout, " perslot=%d MLT=%d%% HLT=%d%% fase=%d\n", percslot, MLTp, HLTp, percfase); } else if (percfase == PERC_MLT) { if (percslot > MLTp) { device_out(unit->mlt_heater.uuid, 0); if (HLTp) { device_out(unit->hlt_heater.uuid, 1); percfase = PERC_HLT; } else { percfase = PERC_REST; } } } else if (percfase == PERC_HLT) { if (percslot > (MLTp + HLTp)) { device_out(unit->hlt_heater.uuid, 0); percfase = PERC_REST; } } if (percslot == 100) { /* End of the loop, start over */ percslot = 0; percfase = PERC_INIT; } perctimer = nowmillis; } now = time(NULL); if (now != last) { /* * Each second */ last = now; seconds++; if (seconds > 59) { seconds = 0; minutes++; dosave = 1; } rc = device_in(unit->hlt_sensor.uuid, &temp); if (rc == DEVPRESENT_YES) { hltInput = temp / 1000.0; unit->hlt_sensor.state = 0; } else if (rc == DEVPRESENT_ERROR) { unit->hlt_sensor.state = 1; } else { unit->hlt_sensor.state = 2; } rc = device_in(unit->mlt_sensor.uuid, &temp); if (rc == DEVPRESENT_YES) { mltInput = temp / 1000.0; unit->mlt_sensor.state = 0; } else if (rc == DEVPRESENT_ERROR) { unit->mlt_sensor.state = 1; } else { unit->mlt_sensor.state = 2; } if (debug && ((seconds % 10) == 1)) { fprintf(stdout, "MLT: In=%.2lf Out=%.2lf Set=%.2lf Stat=%d HLT: In=%.2lf Out=%.2lf Set=%.2lf Stat=%d\n", mltInput, mltOutput, mltSetpoint, PID_getMode(unit->PID_mlt), hltInput, hltOutput, hltSetpoint, PID_getMode(unit->PID_hlt)); } } if (brew) { /* * Automate mode */ automatic_brew(unit, brew, recipe, dosave, seconds); dosave = 0; if (brew->brewstep == -1) { /* * Save session and move it */ wrsession(brew); char *fpath, *tpath; fpath = xstrcpy(etcpath); fpath = xstrcat(fpath, (char *)"brewing.xml"); tpath = xstrcpy(varpath); tpath = xstrcat(tpath, (char *)"old/brewing.xml."); mkdirs(tpath, 0755); tpath = xstrcat(tpath, brew->name); if (debug) fprintf(stdout, "auto: saving as %s\n", tpath); file_cp(fpath, tpath); unlink(fpath); free(fpath); free(tpath); /* * Free memory, session is over. */ if (brew->name) free(brew->name); if (brew->uuid_recipe) free(brew->uuid_recipe); if (brew->uuid_unit) free(brew->uuid_unit); free(brew); brew = NULL; } } else if (manual != MANUAL_NONE) { /* * Manual mode */ manual_menu(unit, seconds); if (manual == MANUAL_NONE) { /* * Rewrite the display */ prompt(101, NULL); /* " Brewco x.x.x " */ prompt(300, NULL); /* " " */ prompt(401, NULL); /* "--- MAN AUTO SETUP" */ } } else { /* * Not running. */ tempstatus(); key = keycheck(); if (key == KEY_ENTER) { setup(); prompt(101, NULL); /* " Brewco x.x.x " */ prompt(200, NULL); prompt(300, NULL); hlt_status(0); mlt_status(0); pump_status(0); prompt(401, NULL); /* "--- MAN AUTO SETUP" */ } else if (key == KEY_RETURN && ! brew) { int i, isOk = TRUE; char message[41]; tm = localtime(&now); snprintf(message, 40, "%04d%02d%02d-%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min); brew = (brew_session *)malloc(sizeof(brew_session)); brew->uuid_recipe = xstrcpy(choose_recipe()); brew->uuid_unit = xstrcpy(unit->uuid); brew->name = xstrcpy(message); brew->brewstep = STEP_NA; brew->mashstep = MASH_NA; brew->timeout = brew->boiltimer = 0; brew->starttime = brew->endtime = (time_t)0; /* * Now check if everything is sane */ if (strcmp(brew->uuid_recipe, (char *)"00000000-0000-0000-0000-000000000000") == 0) { isOk = FALSE; snprintf(message, Config.lcd_cols + 1, " No recipe selected "); if (debug) fprintf(stdout, "brew init: No recipe selected\n"); } if (isOk) { isOk = FALSE; for (recipe = recipes; recipe; recipe = recipe->next) { if (strcmp(recipe->uuid, brew->uuid_recipe) == 0) { isOk = TRUE; if (! recipe->boiltime) isOk = FALSE; for (i = 0; i < 8; i++) { if (! recipe->mash[i].skip && ! recipe->mash[i].setpoint) isOk = FALSE; } for (i = 0; i < 3; i++) { if (! recipe->hopstand[i].skip && recipe->hopstand[i].hold && (recipe->hopstand[i].setpoint == 0)) isOk = FALSE; } break; } } if (isOk == FALSE) { snprintf(message, Config.lcd_cols + 1, " Recipe error "); if (debug) fprintf(stdout, "brew init: recipe error\n"); } } if (debug) fprintf(stdout, "init brew: %s\n", isOk ? (char *)"Ok":(char *)"Error"); if (isOk) { wrsession(brew); } else { prompt(300, message); prompt(408, NULL); /* "--- --- Ok --- " */ key = keywait(); if (brew->name) free(brew->name); if (brew->uuid_recipe) free(brew->uuid_recipe); if (brew->uuid_unit) free(brew->uuid_unit); free(brew); brew = NULL; /* * Rewrite the display */ prompt(101, NULL); /* " Brewco x.x.x " */ prompt(300, NULL); /* " " */ prompt(401, NULL); /* "--- MAN AUTO SETUP" */ } } else if (key == KEY_DOWN) { manual = MANUAL_SELHLT; manual_prompt(); } } usleep(5000); /* 5 mSec */ } while (run); syslog(LOG_NOTICE, "Out of loop"); if (debug) fprintf(stdout, (char *)"Out of loop\n"); prompt(0, NULL); prompt(101, NULL); /* " Brewco x.x.x " */ prompt(302, NULL); /* " Shutting down " */ /* * Give threads time to cleanup */ usleep(1500000); prompt(0, NULL); setBacklight(0); if (sock != -1) { if (shutdown(sock, SHUT_RDWR)) { syslog(LOG_NOTICE, "Can't shutdown socket: %s", strerror(errno)); } sock = -1; } wrrecipes(); wrconfig(); ulockprog((char *)"brewco"); return 0; } int main(int argc, char *argv[]) { int rc = 0, c, i; char *homepath = NULL; while (1) { int option_index = 0; static struct option long_options[] = { {"debug", 0, 0, 'c'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "dh", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': debug = TRUE; break; case 'h': help(); return 1; } } openlog("brewco", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_USER); syslog(LOG_NOTICE, "mbsePi-apps brewco v%s starting", VERSION); if (debug) fprintf(stdout, "mbsePi-apps brewco v%s starting\n", VERSION); /* * Set home directory path */ if (getenv((char *)"USER") == NULL) { homepath = xstrcpy((char *)"/root"); } else { homepath = xstrcpy(getenv((char *)"HOME")); } varpath = xstrcpy(homepath); varpath = xstrcat(varpath, (char *)"/.brewco/var/"); etcpath = xstrcpy(homepath); etcpath = xstrcat(etcpath, (char *)"/.brewco/etc/"); mkdirs(varpath, 0755); mkdirs(etcpath, 0755); if (rdconfig()) { fprintf(stderr, "Error reading configuration\n"); syslog(LOG_NOTICE, "Error reading configuration: halted"); return 1; } if (debug) fprintf(stdout, "configuration loaded\n"); if (rdrecipes()) { fprintf(stderr, "Error reading recipes\n"); syslog(LOG_NOTICE, "Error reading recipes: halted"); return 1; } if (debug) fprintf(stdout, "recipes loaded\n"); /* * Catch all the signals we can, and ignore the rest. Note that SIGKILL can't be ignored * but that's live. This daemon should only be stopped by SIGTERM. * Don't catch SIGCHLD. */ for (i = 0; i < NSIG; i++) { if ((i != SIGCHLD) && (i != SIGKILL) && (i != SIGSTOP)) signal(i, (void (*))die); } #ifdef HAVE_WIRINGPI_H if (wiringPiSetup () ) return 1; #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; }