# HG changeset patch # User Michiel Broek # Date 1403805600 -7200 # Node ID 81bf78a7618e273f27185d56e01af2b4b86774e9 # Parent eb9dd60aa7914027d098c30ecdffdb9b866d1708 Switched to xml configuration diff -r eb9dd60aa791 -r 81bf78a7618e thermferm/rdconfig.c --- a/thermferm/rdconfig.c Wed Jun 25 19:42:03 2014 +0200 +++ b/thermferm/rdconfig.c Thu Jun 26 20:00:00 2014 +0200 @@ -73,6 +73,7 @@ void killconfig(void) { w1_therm *tmp1, *old1; + units_list *tmp2; if (Config.name) free(Config.name); @@ -90,6 +91,26 @@ } Config.w1therms = NULL; Config.my_port = 6554; + Config.tempFormat = 'C'; + + for (tmp2 = Config.units; tmp2; tmp2 = tmp2->next) { + if (tmp2->uuid) + free(tmp2->uuid); + if (tmp2->name) + free(tmp2->name); + if (tmp2->air_address) + free(tmp2->air_address); + if (tmp2->beer_address) + free(tmp2->beer_address); + if (tmp2->io1_address) + free(tmp2->io1_address); + if (tmp2->io2_address) + free(tmp2->io2_address); + if (tmp2->profile) + free(tmp2->profile); + free(tmp2); + } + Config.units = NULL; #ifdef HAVE_WIRINGPI_H Config.lcd_cols = 16; @@ -347,7 +368,7 @@ syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", MBSE_SS(tmp3->name))) < 0) { + if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", tmp3->name)) < 0) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } @@ -355,19 +376,19 @@ syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_ADDRESS", "%s", MBSE_SS(tmp3->air_address))) < 0) { + if (tmp3->air_address && ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "AIR_ADDRESS", "%s", tmp3->air_address)) < 0)) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_ADDRESS", "%s", MBSE_SS(tmp3->beer_address))) < 0) { + if (tmp3->beer_address && ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BEER_ADDRESS", "%s", tmp3->beer_address)) < 0)) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "IO1_ADDRESS", "%s", MBSE_SS(tmp3->io1_address))) < 0) { + if (tmp3->io1_address && ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "IO1_ADDRESS", "%s", tmp3->io1_address)) < 0)) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } - if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "IO2_ADDRESS", "%s", MBSE_SS(tmp3->io2_address))) < 0) { + if (tmp3->io2_address && ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "IO2_ADDRESS", "%s", tmp3->io2_address)) < 0)) { syslog(LOG_NOTICE, "wrconfig: error at xmlTextWriterWriteFormatElement"); return 1; } @@ -469,11 +490,299 @@ +/* + * Parse one LCD display + */ +#ifdef HAVE_WIRINGPI_H +int parseLCD(xmlDocPtr doc, xmlNodePtr cur) +{ + xmlChar *key; + int ival; + + cur = cur->xmlChildrenNode; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"COLUMNS"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + Config.lcd_cols = ival; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"ROWS"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + Config.lcd_rows = ival; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"ADDRESS"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%x", &ival) == 1) + Config.lcd_address = ival; + xmlFree(key); + } + cur = cur->next; + } + + return 0; +} + + + +int parseLCDs(xmlDocPtr doc, xmlNodePtr cur) +{ + cur = cur->xmlChildrenNode; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"LCD"))) { + parseLCD(doc, cur); + } + cur = cur->next; + } + return 0; +} +#endif + + + +int parseW1therm(xmlDocPtr doc, xmlNodePtr cur) +{ + xmlChar *key; + int ival; + w1_therm *w1therm, *tmp; + + w1therm = (w1_therm *)malloc(sizeof(w1_therm)); + w1therm->next = NULL; + w1therm->master = w1therm->name = w1therm->alias = NULL; + w1therm->bus = w1therm->present = w1therm->lastval = w1therm->update = 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; + } + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"MASTER"))) { + w1therm->master = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"BUS"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + w1therm->bus = ival; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) { + w1therm->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"ALIAS"))) { + w1therm->alias = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + cur = cur->next; + } + + if (Config.w1therms == NULL) { + Config.w1therms = w1therm; + } else { + for (tmp = Config.w1therms; tmp; tmp = tmp->next) { + if (tmp->next == NULL) { + tmp->next = w1therm; + break; + } + } + } + + return 0; +} + + + +int parseW1therms(xmlDocPtr doc, xmlNodePtr cur) +{ + cur = cur->xmlChildrenNode; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"W1TERM"))) { + parseW1therm(doc, cur); + } + cur = cur->next; + } + return 0; +} + + + +/* + * Parse a fermenter unit + */ +int parseUnit(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->uuid = unit->name = unit->air_address = unit->beer_address = unit->io1_address = unit->io2_address = unit->profile = NULL; + unit->volume = 0.0; + unit->heater_available = unit->cooler_available = unit->fan_available = FALSE; + unit->air_temp = unit->beer_temp = unit->beer_set = unit->fridge_set = 20.0; + unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->mode = 0; + unit->temp_set_min = 1.0; + unit->temp_set_max = 30.0; + unit->idle_rangeH = 1.0; + unit->idle_rangeL = -1.0; + unit->prof_started = (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; + } + 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 *)"VOLUME"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->volume = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"AIR_ADDRESS"))) { + unit->air_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"BEER_ADDRESS"))) { + unit->beer_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"IO1_ADDRESS"))) { + unit->io1_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"IO2_ADDRESS"))) { + unit->io2_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"HEATER"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (! xmlStrcmp(key, (const xmlChar *)"TRUE")) + unit->heater_available = TRUE; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"COOLER"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (! xmlStrcmp(key, (const xmlChar *)"TRUE")) + unit->cooler_available = TRUE; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"FAN"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (! xmlStrcmp(key, (const xmlChar *)"TRUE")) + unit->fan_available = TRUE; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"MODE"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + for (i = 0; i < 5; i++) { + if (! xmlStrcmp(key, (const xmlChar *)UNITMODE[i])) { + unit->mode = i; + break; + } + } + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"BEER_SET"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->beer_set = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"FRIDGE_SET"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->fridge_set = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"TEMP_SET_MIN"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->temp_set_min = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"TEMP_SET_MAX"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->temp_set_max = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"IDLE_RANGE_L"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->idle_rangeL = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"IDLE_RANGE_H"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%f", &val) == 1) + unit->idle_rangeH = val; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE"))) { + unit->profile = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROF_STARTED"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + unit->prof_started = ival; + 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 parseFermenters(xmlDocPtr doc, xmlNodePtr cur) +{ + cur = cur->xmlChildrenNode; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"UNIT"))) { + parseUnit(doc, cur); + } + cur = cur->next; + } + return 0; +} + + + int rdconfig(char *config) { - char buf[256], *p; - FILE *fp; - int i, rc = 0; +// char buf[256], *p; +// FILE *fp; +// int i, rc = 0; + int rc = 0, ival; + xmlDocPtr doc; + xmlNodePtr cur; + xmlChar *key; killconfig(); @@ -489,28 +798,78 @@ } mypath = xstrcat(mypath, (char *)"/mbsepi-apps/"); mypath = xstrcat(mypath, config); - if ((fp = fopen(mypath, "r")) == NULL) { + if ((doc = xmlParseFile(mypath)) == NULL) { + //if ((fp = fopen(mypath, "r")) == NULL) { /* * Not in the users home directory */ free(mypath); mypath = xstrcpy((char *)"/etc/mbsepi-apps/"); mypath = xstrcat(mypath, config); - if ((fp = fopen(mypath, "r")) == NULL) { + if ((doc = xmlParseFile(mypath)) == NULL) { + //if ((fp = fopen(mypath, "r")) == NULL) { /* * Try /usr/local/etc */ free(mypath); mypath = xstrcpy((char *)"/usr/local/etc/mbsepi-apps/"); mypath = xstrcat(mypath, config); - if ((fp = fopen(mypath, "r")) == NULL) { - syslog(LOG_NOTICE, "rdconfig: could find %s", config); + if ((doc = xmlParseFile(mypath)) == NULL) { + //if ((fp = fopen(mypath, "r")) == NULL) { + syslog(LOG_NOTICE, "rdconfig: could not parse %s", config); return 1; } } } syslog(LOG_NOTICE, "rdconfig: using %s", mypath); + if ((cur = xmlDocGetRootElement(doc)) == NULL) { + syslog(LOG_NOTICE, "XML file %s empty.", mypath); + xmlFreeDoc(doc); + return 1; + } + if (xmlStrcmp(cur->name, (const xmlChar*)"THERMFERM")) { + syslog(LOG_NOTICE, "XML file %s is not a valid configuration file.\n", mypath); + xmlFreeDoc(doc); + return 1; + } + + /* + * Parse configuration + */ + cur = cur->xmlChildrenNode; + while (cur != NULL) { + // VERSION LISTEN_PORT TEMPFORMAT LCDS FERMENTERS +// if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) { +// recipe->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); + } +#ifdef HAVE_WIRINGPI_H + if ((!xmlStrcmp(cur->name, (const xmlChar *)"LCDS"))) { + parseLCDs(doc, cur); + } +#endif + if ((!xmlStrcmp(cur->name, (const xmlChar *)"W1TERMS"))) { + parseW1therms(doc, cur); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"FERMENTERS"))) { + parseFermenters(doc, cur); + } + cur = cur->next; + } + xmlFreeDoc(doc); + + /* linecnt = 0; while (fgets(buf, sizeof(buf) -1, fp)) { linecnt++; @@ -552,6 +911,7 @@ } fclose(fp); + */ free(mypath); mypath = NULL; diff -r eb9dd60aa791 -r 81bf78a7618e thermferm/sensors.c --- a/thermferm/sensors.c Wed Jun 25 19:42:03 2014 +0200 +++ b/thermferm/sensors.c Thu Jun 26 20:00:00 2014 +0200 @@ -128,6 +128,7 @@ free(device); device = NULL; } + usleep(10000); } } diff -r eb9dd60aa791 -r 81bf78a7618e thermferm/server.c --- a/thermferm/server.c Wed Jun 25 19:42:03 2014 +0200 +++ b/thermferm/server.c Thu Jun 26 20:00:00 2014 +0200 @@ -70,44 +70,6 @@ -int unit_add(char *name) -{ - units_list *unit, *tmp; - uuid_t uu; - - unit = (units_list *)malloc(sizeof(units_list)); - unit->next = NULL; - unit->uuid = malloc(37); - uuid_generate(uu); - uuid_unparse(uu, unit->uuid); - unit->name = xstrcpy(name); - unit->air_address = unit->beer_address = unit->io1_address = unit->io2_address = unit->profile = NULL; - unit->volume = 0.0; - unit->heater_available = unit->cooler_available = unit->fan_available = FALSE; - unit->air_temp = unit->beer_temp = unit->beer_set = unit->fridge_set = 20.0; - unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->mode = 0; - unit->temp_set_min = 1.0; - unit->temp_set_max = 30.0; - unit->idle_rangeH = 1.0; - unit->idle_rangeL = -1.0; - unit->prof_started = (time_t)0; - - - 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; -} - - - /* * Send message to client */ @@ -124,7 +86,7 @@ va_end(va_ptr); if (debug) { - syslog(LOG_NOTICE, "send: \"%s\"", out); + syslog(LOG_NOTICE, "send: \"%s\"", out); fprintf(stdout, "send: \"%s\"\n", out); } @@ -132,7 +94,7 @@ syslog(LOG_NOTICE, "srv_send failed"); return -1; } - + if (send(s, (char *)"\r\n", 2, 0) != 2) { syslog(LOG_NOTICE, "srv_send failed"); return -1; @@ -143,11 +105,56 @@ -void cmd_die(int onsig) +int unit_add(char *buf) { - syslog(LOG_NOTICE, "Server process die on signal %d", onsig); - close(s); - exit(0); + units_list *unit, *tmp; + uuid_t uu; + char *cmd, *opt; + int id = 1; + + cmd = strtok(buf, " \0"); + opt = strtok(NULL, "\0"); + if (opt == NULL) { + srv_send((char *)"501 Parameter missing"); + return 1; + } + + if (debug) + fprintf(stdout, "cmd: '%s' opt: '%s'\n", MBSE_SS(cmd), MBSE_SS(opt)); + + unit = (units_list *)malloc(sizeof(units_list)); + unit->next = NULL; + unit->uuid = malloc(37); + uuid_generate(uu); + uuid_unparse(uu, unit->uuid); + unit->name = xstrcpy(opt); + unit->air_address = unit->beer_address = unit->io1_address = unit->io2_address = unit->profile = NULL; + unit->volume = 0.0; + unit->heater_available = unit->cooler_available = unit->fan_available = FALSE; + unit->air_temp = unit->beer_temp = unit->beer_set = unit->fridge_set = 20.0; + unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->mode = 0; + unit->temp_set_min = 1.0; + unit->temp_set_max = 30.0; + unit->idle_rangeH = 1.0; + unit->idle_rangeL = -1.0; + unit->prof_started = (time_t)0; + + if (Config.units == NULL) { + Config.units = unit; + } else { + for (tmp = Config.units; tmp; tmp = tmp->next) { + id++; + if (tmp->next == NULL) { + tmp->next = unit; + break; + } + } + } + + syslog(LOG_NOTICE, "Unit %d with uuid %s added", id, unit->uuid); + srv_send((char *)"211 Unit %d with uuid %s added", id, unit->uuid); + current_unit = id; + return 0; } @@ -180,6 +187,12 @@ if (buf[i] == '\r') buf[i] = '\0'; } + for (i = strlen(buf) -1; i > 0; i--) { + if (buf[i] == ' ') + buf[i] = '\0'; + else + break; + } if (strlen(buf)) { if (debug) { syslog(LOG_NOTICE, "recv: \"%s\"", buf); @@ -189,10 +202,13 @@ /* * Process commands from the client */ - if (strncmp(buf, "HELP", 4) == 0) { + if (strncmp(buf, "ADD", 3) == 0) { + unit_add(buf); + } else if (strncmp(buf, "HELP", 4) == 0) { srv_send((char *)"100 Help text follows"); srv_send((char *)"Recognized commands:"); srv_send((char *)""); + srv_send((char *)"ADD name Add a new unit with \"name\""); srv_send((char *)"LCD Get LCD screen (allways 4 rows of 20 characters)"); srv_send((char *)"."); } else if (strncmp(buf, "LCD", 3) == 0) { diff -r eb9dd60aa791 -r 81bf78a7618e thermferm/thermferm.c --- a/thermferm/thermferm.c Wed Jun 25 19:42:03 2014 +0200 +++ b/thermferm/thermferm.c Thu Jun 26 20:00:00 2014 +0200 @@ -125,7 +125,7 @@ if (debug) fprintf(stdout, "mbsePi-apps thermferm v%s starting\n", VERSION); - if (rdconfig((char *)"thermferm.conf")) { + if (rdconfig((char *)"thermferm.xml")) { fprintf(stderr, "Error reading configuration\n"); syslog(LOG_NOTICE, "halted"); return 1;