Wed, 16 Dec 2015 22:54:53 +0100
Added recipe setup display menu.
/***************************************************************************** * 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 "slcd.h" #include "setup.h" #include "prompt.h" #include "xutil.h" #include "keyboard.h" #include "rdconfig.h" #include "rdrecipes.h" extern int my_shutdown; extern int debug; extern sys_config Config; extern int lcdHandle; extern int slcdHandle; extern a_recipe *recipes; void editFloat(float *value, float low, float high, char *text) { int key; float new = *value; char pmpt[81]; prompt(0, NULL); prompt(133, NULL); for (;;) { snprintf(pmpt, Config.lcd_cols + 1, "%s: %5.1f\001", text, new); prompt(200, pmpt); if (new == low) prompt(404, NULL); else if (new == high) prompt(402, NULL); else prompt(403, NULL); key = keywait(); if ((key == KEY_RETURN) || my_shutdown) return; if (key == KEY_UP) { new = new + 0.5; if (new > high) new = high; } if (key == KEY_DOWN) { new = new - 0.5; if (new < low) new = low; } if (key == KEY_ENTER) { *value = new; return; } } } void editDouble(double *value, double low, double high, char *text) { int key; double new = *value; char pmpt[81]; prompt(0, NULL); prompt(138, NULL); for (;;) { snprintf(pmpt, Config.lcd_cols + 1, "%s: %5.2lf", text, new); prompt(200, pmpt); if (new == low) prompt(404, NULL); else if (new == high) prompt(402, NULL); else prompt(403, NULL); key = keywait(); if ((key == KEY_RETURN) || my_shutdown) return; if (key == KEY_UP) { new = new + 0.5; if (new > high) new = high; } if (key == KEY_DOWN) { new = new - 0.5; if (new < low) new = low; } if (key == KEY_ENTER) { *value = new; return; } } } void editInteger(int *value, int low, int high, int step, char *text, char *text2) { int key, new = *value; char pmpt[81]; prompt(0, NULL); prompt(134, NULL); for (;;) { snprintf(pmpt, Config.lcd_cols + 1, "%s: %3d %s", text, new, text2); prompt(200, pmpt); if (new == low) prompt(404, NULL); else if (new == high) prompt(402, NULL); else prompt(403, NULL); key = keywait(); if ((key == KEY_RETURN) || my_shutdown) return; if (key == KEY_UP) { new += step; if (new > high) new = high; } if (key == KEY_DOWN) { new -= step; if (new < low) new = low; } if (key == KEY_ENTER) { *value = new; return; } } } void togglePmpts(int *value, char *text, int pno, char *pmpt1, char *pmpt2) { int key, new = *value; char pmpt[81]; prompt(0, NULL); prompt(pno, NULL); for (;;) { snprintf(pmpt, Config.lcd_cols + 1, "%s: %s", text, new ? pmpt1:pmpt2); prompt(200, pmpt); if (new) { prompt(404, NULL); } else { prompt(402, NULL); } key = keywait(); if ((key == KEY_RETURN) || my_shutdown) return; if ((key == KEY_UP) && new) new = 0; else if ((key == KEY_DOWN) && (new == 0)) new = 1; if (key == KEY_ENTER) { *value = new; return; } } } void toggleYesNo(int *value, char *text) { togglePmpts(value, text, 132, (char *)"Yes", (char *)"No "); } void toggleDirection(int *value, char *text) { togglePmpts(value, text, 137, (char *)"Reverse", (char *)"Direct "); } void editName(char *name, char *text) { char pmpt[81]; int i, x = 0, key, val; if (debug) fprintf(stdout, "editName(%s)\n", name); prompt(0, NULL); prompt(131, NULL); /* " Change Name " */ prompt(417, NULL); /* " up dwn next ok " */ for (;;) { snprintf(pmpt, Config.lcd_cols + 1, " "); prompt(200, pmpt); #ifdef HAVE_WIRINGPI_H lcdPosition(lcdHandle, x, 1); lcdPutchar(lcdHandle, '*'); #endif slcdPosition(slcdHandle, x, 1); slcdPutchar(slcdHandle, '*'); snprintf(pmpt, Config.lcd_cols + 1, "%s", name); prompt(300, pmpt); key = keywait(); if ((key == KEY_ENTER) || my_shutdown) { if (debug) fprintf(stdout, "End editName(%s)\n", name); for (i = strlen(name) -1; i > 1; i--) { if (name[i] != ' ') break; name[i] = '\0'; } if (debug) fprintf(stdout, "End editName(%s)\n", name); return; } if (key == KEY_RETURN) { if (x < 19) x++; else x = 0; if (debug) fprintf(stdout, "editName: strlen=%d x=%d\n", (int)strlen(name) - 1, x); if (x > ((int)strlen(name) - 1)) { name[x + 1] = '\0'; name[x] = ' '; } } if (key == KEY_UP || key == KEY_DOWN) { val = name[x]; if ((key == KEY_UP) && (val < 126)) val++; if ((key == KEY_DOWN) && (val > 32)) val--; name[x] = val; } } } void editPID(pid_var *pid) { int idx = 1, key, val; char pmpt[81]; double Kp, Ki, Kd; if (debug) fprintf(stdout, "editPID()\n"); for (;;) { prompt(0, NULL); prompt(192, NULL); if (idx == 1) prompt(402, NULL); else if (idx == 5) prompt(404, NULL); else prompt(403, NULL); switch (idx) { case 1: snprintf(pmpt, Config.lcd_cols + 1, "PID Kp: %5.2f", PID_getKp(pid)); break; case 2: snprintf(pmpt, Config.lcd_cols + 1, "PID Ki: %5.2f", PID_getKi(pid)); break; case 3: snprintf(pmpt, Config.lcd_cols + 1, "PID Kd: %5.2f", PID_getKd(pid)); break; case 4: snprintf(pmpt, Config.lcd_cols + 1, "SampleTime: %3d mSec", PID_getSampleTime(pid)); break; case 5: snprintf(pmpt, Config.lcd_cols + 1, "Direction: %s", PID_getDirection(pid) ? (char *)"Reverse" : (char *)"Direct"); break; } prompt(200, pmpt); key = keywait(); if ((key == KEY_RETURN) || my_shutdown) { if (debug) fprintf(stdout, "End editPID\n"); return; } if ((key == KEY_UP) && (idx > 1)) idx--; if ((key == KEY_DOWN) && (idx < 5)) idx++; if (key == KEY_ENTER) { Kp = PID_getKp(pid); Ki = PID_getKi(pid); Kd = PID_getKd(pid); switch(idx) { case 1: editDouble(&Kp, 0.5, 50, (char *)"PID Kp"); PID_setTunings(pid, Kp, Ki, Kd); break; case 2: editDouble(&Ki, 0.5, 50, (char *)"PID Ki"); PID_setTunings(pid, Kp, Ki, Kd); break; case 3: editDouble(&Kd, 0.5, 50, (char *)"PID Kd"); PID_setTunings(pid, Kp, Ki, Kd); break; case 4: val = PID_getSampleTime(pid); editInteger(&val, 50, 500, 10, (char *)"SampleTime", (char *)"mSec"); PID_setSampleTime(pid, val); break; case 5: val = PID_getDirection(pid); toggleDirection(&val, (char *)"Direction"); PID_setDirection(pid, val); break; } } } } void editSensor(char *uuid, char *text) { char pmpt[81]; int i, old, choices, idx = 1, key; devices_list *device; if (debug) fprintf(stdout, "editSensor(%s, %s)\n", uuid, text); old = 1; // 1d0e5bb8-7408-48b9-abb4-e9041d7b99fe if ((i = strcmp((char *)"00000000-0000-0000-0000-000000000000", uuid))) { for (device = Config.devices; device; device = device->next) { if (device->direction == DEVDIR_IN_ANALOG) { old++; if (strcmp(device->uuid, uuid) == 0) break; } } } if (debug) fprintf(stdout, "editSensor(%s) old sensor index=%d\n", text, old); for (;;) { prompt(0, NULL); snprintf(pmpt, Config.lcd_cols + 1, "Edit %s", text); prompt(100, pmpt); /* * Count valid sensors */ choices = 1; if (old == 1) { snprintf(pmpt, Config.lcd_cols + 1, "N/A"); } for (device = Config.devices; device; device = device->next) { if (device->direction == DEVDIR_IN_ANALOG) { choices++; if (choices == old) { snprintf(pmpt, Config.lcd_cols + 1, "%s", device->description); } } } prompt(200, pmpt); /* Display current sensor */ i = 1; if (idx == 1) { snprintf(pmpt, Config.lcd_cols + 1, "N/A"); } else { for (device = Config.devices; device; device = device->next) { if (device->direction == DEVDIR_IN_ANALOG) { i++; if (i == idx) { snprintf(pmpt, Config.lcd_cols + 1, "%s", device->description); } } } } prompt(300, pmpt); /* Display possible new sensor */ if (choices == 1) prompt(405, NULL); else if (idx == 1) prompt(402, NULL); else if (idx == choices) prompt(404, NULL); else prompt(403, NULL); key = keywait(); if ((key == KEY_RETURN) || my_shutdown) { if (debug) fprintf(stdout, "End editSensor\n"); return; } if ((key == KEY_UP) && (idx > 1)) idx--; if ((key == KEY_DOWN) && (idx < choices)) idx++; if ((key == KEY_ENTER) && (idx != old)) { /* * Select new sensor. */ if (idx == 1) { /* * Disable the sensor */ strncpy(uuid, (char *)"00000000-0000-0000-0000-000000000000", 36); old = idx; } else { i = 1; for (device = Config.devices; device; device = device->next) { if (device->direction == DEVDIR_IN_ANALOG) { i++; if (i == idx) { strncpy(uuid, device->uuid, 36); break; } } } old = idx; } } } } void editRelay(char *uuid, char *text) { char pmpt[81]; int i, old, choices, idx = 1, key; devices_list *device; if (debug) fprintf(stdout, "editRelay(%s, %s)\n", uuid, text); old = 1; // 1d0e5bb8-7408-48b9-abb4-e9041d7b99fe if ((i = strcmp((char *)"00000000-0000-0000-0000-000000000000", uuid))) { for (device = Config.devices; device; device = device->next) { if (device->direction == DEVDIR_OUT_ANALOG) { old++; if (strcmp(device->uuid, uuid) == 0) break; } } } if (debug) fprintf(stdout, "editRelay(%s) old sensor index=%d\n", text, old); for (;;) { prompt(0, NULL); snprintf(pmpt, Config.lcd_cols + 1, "Edit %s", text); prompt(100, pmpt); /* * Count valid sensors */ choices = 1; if (old == 1) { snprintf(pmpt, Config.lcd_cols + 1, "N/A"); } for (device = Config.devices; device; device = device->next) { if (device->direction == DEVDIR_OUT_ANALOG) { choices++; if (choices == old) { snprintf(pmpt, Config.lcd_cols + 1, "%s", device->description); } } } prompt(200, pmpt); /* Display current relay */ i = 1; if (idx == 1) { snprintf(pmpt, Config.lcd_cols + 1, "N/A"); } else { for (device = Config.devices; device; device = device->next) { if (device->direction == DEVDIR_OUT_ANALOG) { i++; if (i == idx) { snprintf(pmpt, Config.lcd_cols + 1, "%s", device->description); } } } } prompt(300, pmpt); /* Display possible new relay */ if (choices == 1) prompt(405, NULL); else if (idx == 1) prompt(402, NULL); else if (idx == choices) prompt(404, NULL); else prompt(403, NULL); key = keywait(); if ((key == KEY_RETURN) || my_shutdown) { if (debug) fprintf(stdout, "End editRelay\n"); return; } if ((key == KEY_UP) && (idx > 1)) idx--; if ((key == KEY_DOWN) && (idx < choices)) idx++; if ((key == KEY_ENTER) && (idx != old)) { /* * Select new output. */ if (idx == 1) { /* * Disable the output */ strncpy(uuid, (char *)"00000000-0000-0000-0000-000000000000", 36); old = idx; } else { i = 1; for (device = Config.devices; device; device = device->next) { if (device->direction == DEVDIR_OUT_ANALOG) { i++; if (i == idx) { strncpy(uuid, device->uuid, 36); break; } } } old = idx; } } } } /* * Edit a single unit */ void editUnit(units_list *unit) { int idx = 1, key; char pmpt[81], *uuid, *name; uLong ocrc, ncrc; if (debug) fprintf(stdout, "Start edit brewsystem %d %s\n", unit->number, unit->uuid); prompt(0, NULL); ncrc = ocrc = crc32(0L, Z_NULL, 0); ocrc = crc32(ocrc, (const Bytef *) unit, sizeof(units_list)); for (;;) { prompt(0, NULL); prompt(193, NULL); if (idx == 1) prompt(402, NULL); else if (idx == 21) prompt(404, NULL); else prompt(403, NULL); switch (idx) { // 12345678901234567890 case 1: snprintf(pmpt, Config.lcd_cols + 1, "Unit name:"); prompt(200, pmpt); snprintf(pmpt, Config.lcd_cols + 1, "%s", unit->name); prompt(300, pmpt); break; case 2: snprintf(pmpt, Config.lcd_cols + 1, " HLT sensor setup"); prompt(200, pmpt); break; case 3: snprintf(pmpt, Config.lcd_cols + 1, " HLT heater setup"); prompt(200, pmpt); break; case 4: snprintf(pmpt, Config.lcd_cols + 1, " MLT sensor setup"); prompt(200, pmpt); break; case 5: snprintf(pmpt, Config.lcd_cols + 1, " MLT heater setup"); prompt(200, pmpt); break; case 6: snprintf(pmpt, Config.lcd_cols + 1, " MLT pump setup"); prompt(200, pmpt); break; case 7: snprintf(pmpt, Config.lcd_cols + 1, "MLT heat b4 HLT: %s", unit->hlt_heater_mltfirst ? (char *)"Yes":(char *)"No"); prompt(200, pmpt); break; case 8: snprintf(pmpt, Config.lcd_cols + 1, "Pump cycle: %3d mins", unit->pump_cycle); prompt(200, pmpt); break; case 9: snprintf(pmpt, Config.lcd_cols + 1, "Pump rest : %3d mins", unit->pump_rest); prompt(200, pmpt); break; case 10: snprintf(pmpt, Config.lcd_cols + 1, " Pump pre-mash: %s", unit->pump_premash ? (char *)"Yes":(char *)"No"); prompt(200, pmpt); break; case 11: snprintf(pmpt, Config.lcd_cols + 1, " Pump on-mash: %s", unit->pump_onmash ? (char *)"Yes":(char *)"No"); prompt(200, pmpt); break; case 12: snprintf(pmpt, Config.lcd_cols + 1, " Pump mashout: %s", unit->pump_mashout ? (char *)"Yes":(char *)"No"); prompt(200, pmpt); break; case 13: snprintf(pmpt, Config.lcd_cols + 1, " Pump on-boil: %s", unit->pump_onboil ? (char *)"Yes":(char *)"No"); prompt(200, pmpt); break; case 14: snprintf(pmpt, Config.lcd_cols + 1, " Pump stop: %5.1f\001", unit->pump_stop); prompt(200, pmpt); break; case 15: snprintf(pmpt, Config.lcd_cols + 1, " Skip Add: %s", unit->skip_add ? (char *)"Yes":(char *)"No"); prompt(200, pmpt); break; case 16: snprintf(pmpt, Config.lcd_cols + 1, " Skip Remove: %s", unit->skip_remove ? (char *)"Yes":(char *)"No"); prompt(200, pmpt); break; case 17: snprintf(pmpt, Config.lcd_cols + 1, " Skip Iodine: %s", unit->skip_iodine ? (char *)"Yes":(char *)"No"); prompt(200, pmpt); break; case 18: snprintf(pmpt, Config.lcd_cols + 1, "Iodine time: %3d min", unit->iodine_time); prompt(200, pmpt); break; case 19: snprintf(pmpt, Config.lcd_cols + 1, " Whirlpool: %s", unit->whirlpool ? (char *)"Yes":(char *)"No"); prompt(200, pmpt); break; case 20: snprintf(pmpt, Config.lcd_cols + 1, " HLT PID setup"); prompt(200, pmpt); break; case 21: snprintf(pmpt, Config.lcd_cols + 1, " MLT PID setup"); prompt(200, pmpt); break; } key = keywait(); if ((key == KEY_RETURN) || my_shutdown) { ncrc = crc32(ncrc, (const Bytef *)unit, sizeof(units_list)); if (ocrc != ncrc) wrconfig(); if (debug) fprintf(stdout, "End edit brewsystem %d %s\n", unit->number, unit->uuid); return; } if ((key == KEY_UP) && (idx > 1)) idx--; if ((key == KEY_DOWN) && (idx < 21)) idx++; if (key == KEY_ENTER) { switch(idx) { case 1: name = calloc(sizeof(char), 21); snprintf(name, 21, unit->name); editName(name, (char *)"Unit name"); if (unit->name) free(unit->name); unit->name = xstrcpy(name); free(name); break; case 2: uuid = xstrcpy(unit->hlt_sensor.uuid); editSensor(uuid, (char *)"HLT sensor"); strncpy(unit->hlt_sensor.uuid, uuid, 36); free(uuid); break; case 3: uuid = xstrcpy(unit->hlt_heater.uuid); editRelay(uuid, (char *)"HLT heater"); strncpy(unit->hlt_heater.uuid, uuid, 36); free(uuid); break; case 4: uuid = xstrcpy(unit->mlt_sensor.uuid); editSensor(uuid, (char *)"MLT sensor"); strncpy(unit->mlt_sensor.uuid, uuid, 36); free(uuid); break; case 5: uuid = xstrcpy(unit->mlt_heater.uuid); editRelay(uuid, (char *)"MLT heater"); strncpy(unit->mlt_heater.uuid, uuid, 36); free(uuid); break; case 6: uuid = xstrcpy(unit->mlt_pump.uuid); editRelay(uuid, (char *)"MLT pump"); strncpy(unit->mlt_pump.uuid, uuid, 36); free(uuid); break; case 7: toggleYesNo(&unit->hlt_heater_mltfirst, (char *)"MLT heat b4 HLT"); break; case 8: editInteger(&unit->pump_cycle, 5, 15, 1, (char *)"Pump cycle", (char *)"mins"); break; case 9: editInteger(&unit->pump_rest, 1, 5, 1, (char *)"Pump rest ", (char *)"mins"); break; case 10: toggleYesNo(&unit->pump_premash, (char *)" Pump pre-mash"); break; case 11: toggleYesNo(&unit->pump_onmash, (char *)" Pump on-mash"); break; case 12: toggleYesNo(&unit->pump_mashout, (char *)" Pump mashout"); break; case 13: toggleYesNo(&unit->pump_onboil, (char *)" Pump on-boil"); break; case 14: editFloat(&unit->pump_stop, 80.0, 110.0, (char *)" Pump stop"); break; case 15: toggleYesNo(&unit->skip_add, (char *)"Skip add water"); break; case 16: toggleYesNo(&unit->skip_remove, (char *)"Skip remove Mash"); break; case 17: toggleYesNo(&unit->skip_iodine, (char *)"Skip iodine test"); break; case 18: editInteger(&unit->iodine_time, 10, 240, 10, (char *)"Iodine time", (char *)"min"); break; case 19: toggleYesNo(&unit->whirlpool, (char *)"Do a whirlpool"); break; case 20: editPID(unit->PID_hlt); break; case 21: editPID(unit->PID_mlt); break; } } } } void addUnit(int number) { units_list *tmpu, *unit = (units_list *)malloc(sizeof(units_list)); char name[81]; uuid_t uu; double Input, Output, Setpoint; if (debug) fprintf(stdout, "Adding new brewsystem %d\n", number); unit->next = NULL; unit->version = 1; unit->uuid = malloc(37); uuid_generate(uu); uuid_unparse(uu, unit->uuid); snprintf(name, 20, "System %d", number); unit->name = xstrcpy(name); unit->number = number; if (number == 1) unit->active = 1; else unit->active = 0; unit->hlt_sensor.uuid = xstrcpy((char *)"00000000-0000-0000-0000-000000000000"); unit->hlt_sensor.state = DEVPRESENT_UNDEF; unit->hlt_sensor.value = 0; unit->mlt_sensor.uuid = xstrcpy((char *)"00000000-0000-0000-0000-000000000000"); unit->mlt_sensor.state = DEVPRESENT_UNDEF; unit->mlt_sensor.value = 0; unit->hlt_heater.uuid = xstrcpy((char *)"00000000-0000-0000-0000-000000000000"); unit->hlt_heater.value = 0; unit->hlt_heater.delay = 0; unit->mlt_heater.uuid = xstrcpy((char *)"00000000-0000-0000-0000-000000000000"); unit->mlt_heater.value = 0; unit->mlt_heater.delay = 0; unit->mlt_pump.uuid = xstrcpy((char *)"00000000-0000-0000-0000-000000000000"); unit->mlt_pump.value = 0; unit->mlt_pump.delay = 0; unit->hlt_heater_mltfirst = 1; unit->pump_cycle = 7; unit->pump_rest = 2; unit->pump_premash = 1; unit->pump_onmash = 1; unit->pump_mashout = 0; unit->pump_onboil = 0; unit->pump_stop = 90; unit->skip_add = 0; unit->skip_remove = 0; unit->skip_iodine = 0; unit->iodine_time = 90; unit->whirlpool = 1; unit->PID_hlt = (pid_var *)malloc(sizeof(pid_var)); unit->PID_mlt = (pid_var *)malloc(sizeof(pid_var)); Input = Setpoint = 20.0; Output = 0; PID_init(unit->PID_hlt, &Input, &Output, &Setpoint, 2, 5, 1, P_DIRECT); PID_init(unit->PID_mlt, &Input, &Output, &Setpoint, 2, 5, 1, P_DIRECT); editUnit(unit); if (Config.units == NULL) { Config.units = unit; } else { for (tmpu = Config.units; tmpu; tmpu = tmpu->next) { if (tmpu->next == NULL) { tmpu->next = unit; break; } } } syslog(LOG_NOTICE, "Brewsystem %d added to the configuration", number); if (debug) fprintf(stdout, "Brewsystem %d added to the configuration\n", number); } /* * Edit a single recipe */ void editRecipe(a_recipe *recipe) { int idx = 1, key; char pmpt[81], *name; uLong ocrc, ncrc; if (debug) fprintf(stdout, "Start edit recipe `%s' %s\n", recipe->name, recipe->uuid); prompt(0, NULL); ncrc = ocrc = crc32(0L, Z_NULL, 0); ocrc = crc32(ocrc, (const Bytef *) recipe, sizeof(a_recipe)); for (;;) { prompt(0, NULL); prompt(191, NULL); /* " Edit recipe " */ if (idx == 1) prompt(402, NULL); /* "--- dwn quit ok " */ else if (idx == 24) prompt(404, NULL); /* " up --- quit ok " */ else prompt(403, NULL); /* " up dwn quit ok " */ switch (idx) { // 12345678901234567890 case 1: snprintf(pmpt, Config.lcd_cols + 1, "Recipe name:"); prompt(200, pmpt); snprintf(pmpt, Config.lcd_cols + 1, "%s", recipe->name); prompt(300, pmpt); break; case 2: snprintf(pmpt, Config.lcd_cols + 1, "Recipe code:"); prompt(200, pmpt); snprintf(pmpt, Config.lcd_cols + 1, "%s", recipe->code); prompt(300, pmpt); break; case 3: snprintf(pmpt, Config.lcd_cols + 1, "Boil time: %3d mins", recipe->boiltime); prompt(200, pmpt); break; case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: snprintf(pmpt, Config.lcd_cols + 1, "Mash: %s", recipe->mash[idx - 4].name); prompt(200, pmpt); if (recipe->mash[idx - 4].skip) snprintf(pmpt, Config.lcd_cols + 1, "Skipped"); else snprintf(pmpt, Config.lcd_cols + 1, "Sv %4.1f\001 %3d mins", recipe->mash[idx - 4].setpoint, recipe->mash[idx - 4].duration); prompt(300, pmpt); break; case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: snprintf(pmpt, Config.lcd_cols + 1, "Hop: %s", recipe->hops[idx - 12].name); prompt(200, pmpt); if (recipe->hops[idx - 12].name) { if (recipe->hops[idx - 12].boiltime == -1) snprintf(pmpt, Config.lcd_cols + 1, "First Wort Hop"); else snprintf(pmpt, Config.lcd_cols + 1, "Add at %3d mins", recipe->hops[idx - 12].boiltime); prompt(300, pmpt); } break; case 22: case 23: case 24: snprintf(pmpt, Config.lcd_cols + 1, "Hopstand: %s", recipe->hopstand[idx - 22].name); prompt(200, pmpt); if (recipe->hopstand[idx - 22].skip) snprintf(pmpt, Config.lcd_cols + 1, "Skipped"); else if (recipe->hopstand[idx - 22].hold) snprintf(pmpt, Config.lcd_cols + 1, "Hold at %4.1f %3d mins", recipe->hopstand[idx - 22].setpoint, recipe->hopstand[idx - 22].duration); else snprintf(pmpt, Config.lcd_cols + 1, "Hold for %3d mins", recipe->hopstand[idx - 22].duration); prompt(300, pmpt); break; } key = keywait(); if ((key == KEY_RETURN) || my_shutdown) { ncrc = crc32(ncrc, (const Bytef *)recipe, sizeof(a_recipe)); if (ocrc != ncrc) wrrecipes(); if (debug) fprintf(stdout, "End edit recipe `%s' %s\n", recipe->name, recipe->uuid); return; } if ((key == KEY_UP) && (idx > 1)) idx--; if ((key == KEY_DOWN) && (idx < 24)) idx++; if (key == KEY_ENTER) { switch(idx) { case 1: name = calloc(sizeof(char), 21); snprintf(name, 21, recipe->name); editName(name, (char *)"Recipe name"); if (recipe->name) free(recipe->name); recipe->name = xstrcpy(name); free(name); break; case 2: name = calloc(sizeof(char), 21); snprintf(name, 21, recipe->code); editName(name, (char *)"Recipe code"); if (recipe->code) free(recipe->code); recipe->code = xstrcpy(name); free(name); break; case 3: editInteger(&recipe->boiltime, 60, 240, 5, (char *)"Boil time:", (char *)"mins"); break; } } } } void addRecipe(int number) { a_recipe *tmpu, *recipe = (a_recipe *)malloc(sizeof(a_recipe)); char name[81]; uuid_t uu; int i; if (debug) fprintf(stdout, "Adding new recipe %d\n", number); recipe->next = NULL; recipe->uuid = malloc(37); uuid_generate(uu); uuid_unparse(uu, recipe->uuid); snprintf(name, 21, "New recipe %d", number); recipe->name = xstrcpy(name); snprintf(name, 21, "%04d", number); recipe->code = xstrcpy(name); recipe->boiltime = 90; recipe->starttime = recipe->endtime = (time_t)0; /* * Initial mash schedule, set a single-step 67 degr. mash */ recipe->mash[0].name = xstrcpy((char *)"Mash-in"); recipe->mash[0].min = 20; recipe->mash[0].max = 80; recipe->mash[0].canskip = 0; recipe->mash[0].setpoint = 68.0; recipe->mash[0].skip = 0; recipe->mash[0].duration = 1; recipe->mash[1].name = xstrcpy((char *)"Phytase"); recipe->mash[1].min = 25; recipe->mash[1].max = 55; recipe->mash[1].canskip = 1; recipe->mash[1].setpoint = 40.0; recipe->mash[1].skip = 1; recipe->mash[1].duration = 10; recipe->mash[2].name = xstrcpy((char *)"Glucanase"); recipe->mash[2].min = 35; recipe->mash[2].max = 50; recipe->mash[2].canskip = 1; recipe->mash[2].setpoint = 45.0; recipe->mash[2].skip = 1; recipe->mash[2].duration = 10; recipe->mash[3].name = xstrcpy((char *)"Protease"); recipe->mash[3].min = 45; recipe->mash[3].max = 60; recipe->mash[3].canskip = 1; recipe->mash[3].setpoint = 55.0; recipe->mash[3].skip = 1; recipe->mash[3].duration = 10; recipe->mash[4].name = xstrcpy((char *)"B-Amylase"); recipe->mash[4].min = 50; recipe->mash[4].max = 70; recipe->mash[4].canskip = 1; recipe->mash[4].setpoint = 62.0; recipe->mash[4].skip = 1; recipe->mash[4].duration = 30; recipe->mash[5].name = xstrcpy((char *)"A-Amylase 1"); recipe->mash[5].min = 60; recipe->mash[5].max = 76; recipe->mash[5].canskip = 1; recipe->mash[5].setpoint = 67.0; recipe->mash[5].skip = 1; recipe->mash[5].duration = 30; recipe->mash[6].name = xstrcpy((char *)"A-Amylase 2"); recipe->mash[6].min = 60; recipe->mash[6].max = 76; recipe->mash[6].canskip = 0; recipe->mash[6].setpoint = 67.0; recipe->mash[6].skip = 0; recipe->mash[6].duration = 60; recipe->mash[7].name = xstrcpy((char *)"Mash-out"); recipe->mash[7].min = 75; recipe->mash[7].max = 80; recipe->mash[7].canskip = 0; recipe->mash[7].setpoint = 78.0; recipe->mash[7].skip = 0; recipe->mash[7].duration = 10; /* * Add 2 hop additions, maximum 10 */ recipe->hops[0].name = xstrcpy((char *)"Hops 1"); recipe->hops[0].boiltime = 90; recipe->hops[1].name = xstrcpy((char *)"Hops 2"); recipe->hops[1].boiltime = 5; for (i = 2; i < 10; i++) { recipe->hops[i].name = NULL; recipe->hops[i].boiltime = 0; } /* * Add 3 hopstands, disabled by default. */ recipe->hopstand[0].name = xstrcpy((char *)"Hopstand hot"); recipe->hopstand[0].min = 88; recipe->hopstand[0].max = 100; recipe->hopstand[0].hold = 0; recipe->hopstand[0].setpoint = 93.0; recipe->hopstand[0].skip = 1; recipe->hopstand[0].duration = 30; recipe->hopstand[1].name = xstrcpy((char *)"Hopstand default"); recipe->hopstand[1].min = 72; recipe->hopstand[1].max = 77; recipe->hopstand[1].hold = 0; recipe->hopstand[1].setpoint = 75.0; recipe->hopstand[1].skip = 1; recipe->hopstand[1].duration = 60; recipe->hopstand[2].name = xstrcpy((char *)"Hopstand cool"); recipe->hopstand[2].min = 60; recipe->hopstand[2].max = 66; recipe->hopstand[2].hold = 0; recipe->hopstand[2].setpoint = 63.0; recipe->hopstand[2].skip = 1; recipe->hopstand[2].duration = 60; editRecipe(recipe); if (recipes == NULL) { recipes = recipe; } else { for (tmpu = recipes; tmpu; tmpu = tmpu->next) { if (tmpu->next == NULL) { tmpu->next = recipe; break; } } } syslog(LOG_NOTICE, "Recipe %d added", number); if (debug) fprintf(stdout, "Recipe %d added\n", number); } void editRecipes(void) { int total, i, key, choice = 1;; a_recipe *recipe; char pmpt[81]; prompt(0, NULL); for (;;) { total = 0; for (recipe = recipes; recipe; recipe = recipe->next) { total++; } if (debug) fprintf(stdout, "editRecipes total=%d choice=%d\n", total, choice); i = 0; if (total) { 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 == 0) prompt(416, NULL); /* "add --- quit --- " */ else if (total == 1) prompt(415, NULL); /* "add --- quit ok " */ else if (total && (choice == 1)) prompt(414, NULL); /* "add dwn quit ok " */ else if (total && (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; if (total && (key == KEY_ENTER)) { editRecipe(recipe); prompt(0, NULL); } if (key == KEY_UP) { if ((total == 1) || (choice == 1)) addRecipe(total + 1); else if (choice > 1) choice--; } if ((key == KEY_DOWN) && (total > 1) && (choice < total)) choice++; } } void editUnits(void) { int total, i, key, choice = 1;; units_list *unit; char pmpt[81]; prompt(0, NULL); for (;;) { total = 0; for (unit = Config.units; unit; unit = unit->next) { total++; } if (debug) fprintf(stdout, "editUnits total=%d choice=%d\n", total, choice); if (total == 0) { /* * Impossible unless first setup was skipped */ addUnit(1); total = 1; } else { i = 0; for (unit = Config.units; unit; unit = unit->next) { i++; if (i == choice) break; } prompt(102, NULL); /* " SETUP MENU " */ prompt(222, NULL); /* " Select Brewsystem " */ snprintf(pmpt, Config.lcd_cols + 1, "%s ", unit->name); prompt(300, pmpt); if (total == 1) prompt(415, NULL); /* "add --- quit ok " */ else if (choice == 1) prompt(414, NULL); /* "add 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; if (key == KEY_ENTER) { editUnit(unit); prompt(0, NULL); } if (key == KEY_UP) { if ((total == 1) || (choice == 1)) addUnit(total + 1); else if (choice > 1) choice--; } if ((key == KEY_DOWN) && (total > 1) && (choice < total)) choice++; } } } void setup(void) { int key, option = 202; for (;;) { if (debug) fprintf(stdout, "setup() option=%d\n", option); prompt(0, NULL); prompt(102, NULL); /* " SETUP MENU " */ prompt(option, NULL); if (option == 202) prompt(402, NULL); /* "--- dwn quit ok " */ #ifdef USE_SIMULATOR else if (option == 205) #else else if (option == 204) #endif prompt(404, NULL); /* " up --- quit ok " */ else prompt(403, NULL); /* " up dwn quit ok " */ key = keywait(); if ((key == KEY_RETURN) || my_shutdown) return; if ((key == KEY_UP) && (option > 202)) { option--; } #ifdef USE_SIMULATOR if ((key == KEY_DOWN) && (option < 205)) { #else if ((key == KEY_DOWN) && (option < 204)) { #endif option++; } if (key == KEY_ENTER) { switch(option) { case 202: editRecipes(); break; case 203: editUnits(); break; case 204: // devices break; #ifdef USE_SIMULATOR case 205: // simulator break; #endif } if (my_shutdown) return; } } }