Wed, 13 Aug 2014 21:48:57 +0200
Bumped to version 0.1.0
/***************************************************************************** * Copyright (C) 2008-2014 * * Michiel Broek <mbroek at mbse dot eu> * * This file is part of the mbsePi-apps * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * mbsePi-apps is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ThermFerm; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ #include "rdconfig.h" #include "thermferm.h" #include "logger.h" #include "devices.h" #include "server.h" #include "xutil.h" extern int my_shutdown; extern int debug; extern sys_config Config; extern const char UNITMODE[5][8]; extern const char UNITmode[5]; extern const char TEMPSTATE[3][8]; extern const char DEVTYPE[7][6]; extern const char DEVPRESENT[4][6]; extern const char DEVDIR[7][11]; extern const char PROFSTATE[5][6]; int s; /* connected socket */ int ls; /* listen socket */ struct sockaddr_in myaddr_in; /* for local socket address */ struct sockaddr_in peeraddr_in; /* for peer socket address */ struct hostent *hp; #define SS_BUFSIZE 1024 #define SS_TIMEOUT 300 /* * Send message to client */ int srv_send(const char *format, ...) { char out[SS_BUFSIZE]; va_list va_ptr; if (s == -1) return -1; va_start(va_ptr, format); vsnprintf(out, SS_BUFSIZE-1, format, va_ptr); va_end(va_ptr); if (debug) { syslog(LOG_NOTICE, "send: \"%s\"", out); fprintf(stdout, "send: \"%s\"\n", out); } if (send(s, out, strlen(out), 0) != strlen(out)) { syslog(LOG_WARNING, "srv_send failed"); return -1; } if (send(s, (char *)"\r\n", 2, 0) != 2) { syslog(LOG_WARNING, "srv_send failed"); return -1; } return 0; } /* * Update the device inuse counter. */ void device_count(int plus, char *uuid) { devices_list *device; for (device = Config.devices; device; device = device->next) { if (strcmp(device->uuid, uuid) == 0) { if (plus == TRUE) { device->inuse++; } else { if (device->inuse) device->inuse--; } } } } int delete_Profile(char *uuid) { profiles_list *current = Config.profiles; profiles_list *previous = NULL; prof_step *step, *olds; while (current) { if (strcmp(current->uuid, uuid) == 0) { if (previous == NULL) { Config.profiles = current->next; free(current->uuid); current->uuid = NULL; free(current->name); current->name = NULL; if (current->steps) { for (step = current->steps; step; step = olds) { olds = step->next; free(step); } current->steps = NULL; } free(current); return 1; } else { free(current->uuid); current->uuid = NULL; free(current->name); current->name = NULL; if (current->steps) { for (step = current->steps; step; step = olds) { olds = step->next; free(step); } current->steps = NULL; } previous->next = current->next; free(current); current = previous->next; return 1; } } else { previous = current; current = current->next; } } return 0; } int delete_Device(char *uuid) { devices_list *current = Config.devices; devices_list *previous = NULL; while (current) { if (strcmp(current->uuid, uuid) == 0) { if (previous == NULL) { Config.devices = current->next; free(current->uuid); current->uuid = NULL; free(current->address); current->address = NULL; free(current->description); current->description = NULL; free(current->comment); current->comment = NULL; free(current); return 1; } else { free(current->uuid); current->uuid = NULL; free(current->address); current->address = NULL; free(current->description); current->description = NULL; free(current->comment); current->comment = NULL; previous->next = current->next; free(current); current = previous->next; return 1; } } else { previous = current; current = current->next; } } return 0; } /* * DEVICE ADD type * DEVICE DEL uuid * DEVICE LIST * DEVICE GET uuid * DEVICE PUT uuid */ int cmd_device(char *buf) { char *opt, *param, *kwd, *val, ibuf[SS_BUFSIZE]; devices_list *device, *tmpd; socklen_t fromlen; int i, rlen, ival; uuid_t uu; opt = strtok(buf, " \0"); opt = strtok(NULL, " \0"); if (opt == NULL) { srv_send((char *)"501 Subcommand missing"); return 1; } param = strtok(NULL, "\0"); if (strcmp(opt, (char *)"LIST") == 0) { srv_send((char *)"212 Devices list follows:"); for (device = Config.devices; device; device = device->next) { srv_send((char *)"%s,%s,%d,%d,%s,%s", device->uuid, device->address, device->subdevice, device->inuse, device->comment, DEVDIR[device->direction]); } srv_send((char *)"."); return 0; } if (param == NULL) { srv_send((char *)"502 Parameter missing"); return 1; } if (strcmp(opt, (char *)"ADD") == 0) { if ((strcmp(param, (char *)"RC433") == 0) || (strcmp(param, (char *)"DHT") == 0) || (strcmp(param, (char *)"I2C") == 0) || (strcmp(param, (char *)"SPI") == 0)) { device = (devices_list *)malloc(sizeof(devices_list)); device->next = NULL; device->version = 1; device->uuid = malloc(37); uuid_generate(uu); uuid_unparse(uu, device->uuid); for (i = 0; i < 7; i++) { if (strcmp(param, DEVTYPE[i]) == 0) { device->type = i; break; } } device->direction = DEVDIR_UNDEF; device->value = device->offset = device->subdevice = device->inuse = 0; device->present = DEVPRESENT_UNDEF; device->address = xstrcpy((char *)"Enter address here"); device->gpiopin = -1; device->description = xstrcpy((char *)"Describe me here"); device->comment = xstrcpy((char *)"Comment here"); if (Config.devices == NULL) { Config.devices = device; } else { for (tmpd = Config.devices; tmpd; tmpd = tmpd->next) { if (tmpd->next == NULL) { tmpd->next = device; break; } } } syslog(LOG_NOTICE, "Device %s added", device->uuid); srv_send((char *)"211 Device %s added", device->uuid); return 0; } else { srv_send((char *)"503 Parameter error"); return 1; } } if (strcmp(opt, (char *)"DEL") == 0) { if (delete_Device(param)) { syslog(LOG_NOTICE, "Device %s deleted", param); srv_send((char *)"211 Device %s deleted", param); return 0; } else { srv_send((char *)"440 No such device"); return 1; } } if (strcmp(opt, (char *)"GET") == 0) { for (device = Config.devices; device; device = device->next) { if (strcmp(device->uuid, param) == 0) { srv_send((char *)"213 Device record follows:"); srv_send((char *)"TYPE,%s", DEVTYPE[device->type]); srv_send((char *)"DIRECTION,%s", DEVDIR[device->direction]); srv_send((char *)"VALUE,%d", device->value); srv_send((char *)"OFFSET,%d", device->offset); srv_send((char *)"PRESENT,%s", DEVPRESENT[device->present]); srv_send((char *)"ADDRESS,%s", device->address); srv_send((char *)"SUBDEVICE,%d", device->subdevice); srv_send((char *)"GPIOPIN,%d", device->gpiopin); srv_send((char *)"DESCRIPTION,%s", device->description); srv_send((char *)"INUSE,%d", device->inuse); srv_send((char *)"COMMENT,%s", device->comment); srv_send((char *)"TIMESTAMP,%d", (int)device->timestamp); srv_send((char *)"."); return 1; } } srv_send((char *)"440 No such device"); return 1; } if (strcmp(opt, (char *)"PUT") == 0) { for (device = Config.devices; device; device = device->next) { if (strcmp(device->uuid, param) == 0) { while (1) { memset((char *)&ibuf, 0, SS_BUFSIZE); fromlen = sizeof(peeraddr_in); rlen = recvfrom(s, ibuf, sizeof(ibuf) -1, 0, (struct sockaddr *)&peeraddr_in, &fromlen); if (rlen == -1) { syslog(LOG_WARNING, "recvfrom(): %s", strerror(errno)); srv_send((char *)"518 recfrom(): %s", strerror(errno)); return 1; } for (i = 0; i < strlen(ibuf); i++) { if (ibuf[i] == '\n') ibuf[i] = '\0'; if (ibuf[i] == '\r') ibuf[i] = '\0'; } for (i = strlen(ibuf) -1; i > 0; i--) { if (ibuf[i] == ' ') ibuf[i] = '\0'; else break; } if (strlen(ibuf)) { if (debug) { syslog(LOG_NOTICE, "recv: \"%s\"", ibuf); fprintf(stdout, "recv: \"%s\"\n", ibuf); } if (strcmp(ibuf, (char *)".") == 0) { srv_send((char *)"219 Accepted Device record"); return 0; } kwd = strtok(ibuf, ",\0"); val = strtok(NULL, "\0"); if (kwd && val) { if (strcmp(kwd, (char *)"TYPE") == 0) { for (i = 0; i < 7; i++) { if (strcmp(val, DEVTYPE[i]) == 0) { device->type = i; break; } } } else if (strcmp(kwd, (char *)"DIRECTION") == 0) { for (i = 0; i < 7; i++) { if (strcmp(val, DEVDIR[i]) == 0) { device->direction = i; break; } } } else if (strcmp(kwd, (char *)"VALUE") == 0) { if (sscanf(val, "%d", &ival) == 1) device->value = ival; } else if (strcmp(kwd, (char *)"OFFSET") == 0) { if (sscanf(val, "%d", &ival) == 1) device->offset = ival; } else if (strcmp(kwd, (char *)"PRESENT") == 0) { for (i = 0; i < 4; i++) { if (strcmp(val, DEVPRESENT[i]) == 0) { device->present = i; break; } } } else if (strcmp(kwd, (char *)"ADDRESS") == 0) { if (device->address) free(device->address); device->address = xstrcpy(val); } else if (strcmp(kwd, (char *)"SUBDEVICE") == 0) { if (sscanf(val, "%d", &ival) == 1) device->subdevice = ival; } else if (strcmp(kwd, (char *)"GPIOPIN") == 0) { if (sscanf(val, "%d", &ival) == 1) device->gpiopin = ival; } else if (strcmp(kwd, (char *)"DESCRIPTION") == 0) { if (device->description) free(device->description); device->description = xstrcpy(val); } else if (strcmp(kwd, (char *)"COMMENT") == 0) { if (device->comment) free(device->comment); device->comment = xstrcpy(val); } } } } } } srv_send((char *)"440 No such device"); return 1; } srv_send((char *)"504 Subcommand error"); return 1; } /* * GLOBAL GET * GLOBAL PUT */ int cmd_global(char *buf) { char *opt, *kwd, *val, ibuf[SS_BUFSIZE]; int ival, i, rlen; socklen_t fromlen; opt = strtok(buf, " \0"); opt = strtok(NULL, "\0"); if (opt == NULL) { srv_send((char *)"501 Subcommand missing"); return 1; } if (strcmp(opt, (char *)"GET") == 0) { srv_send((char *)"213 Global Settings record follows:"); srv_send((char *)"NAME,%s", Config.name); srv_send((char *)"PORT,%d", Config.my_port); srv_send((char *)"TEMPFORMAT,%c", Config.tempFormat); srv_send((char *)"TEMP_ADDRESS,%s", Config.temp_address); srv_send((char *)"TEMP_STATE,%s", TEMPSTATE[Config.temp_state]); srv_send((char *)"TEMP_VALUE,%.1f", Config.temp_value / 1000.0); srv_send((char *)"HUM_ADDRESS,%s", Config.hum_address); srv_send((char *)"HUM_STATE,%s", TEMPSTATE[Config.hum_state]); srv_send((char *)"HUM_VALUE,%.0f", Config.hum_value / 1000.0); #ifdef HAVE_WIRINGPI_H srv_send((char *)"LCD_COLS,%d", Config.lcd_cols); srv_send((char *)"LCD_ROWS,%d", Config.lcd_rows); #endif srv_send((char *)"."); return 1; } if (strcmp(opt, (char *)"PUT") == 0) { while (1) { memset((char *)&ibuf, 0, SS_BUFSIZE); fromlen = sizeof(peeraddr_in); rlen = recvfrom(s, ibuf, sizeof(ibuf) -1, 0, (struct sockaddr *)&peeraddr_in, &fromlen); if (rlen == -1) { syslog(LOG_WARNING, "recvfrom(): %s", strerror(errno)); srv_send((char *)"518 recfrom(): %s", strerror(errno)); return 1; } for (i = 0; i < strlen(ibuf); i++) { if (ibuf[i] == '\n') ibuf[i] = '\0'; if (ibuf[i] == '\r') ibuf[i] = '\0'; } for (i = strlen(ibuf) -1; i > 0; i--) { if (ibuf[i] == ' ') ibuf[i] = '\0'; else break; } if (strlen(ibuf)) { if (debug) { syslog(LOG_NOTICE, "recv: \"%s\"", ibuf); fprintf(stdout, "recv: \"%s\"\n", ibuf); } if (strcmp(ibuf, (char *)".") == 0) { srv_send((char *)"219 Accepted Global record"); return 0; } kwd = strtok(ibuf, ",\0"); val = strtok(NULL, "\0"); if (kwd) { if (strcmp(kwd, (char *)"NAME") == 0) { if (Config.name) free(Config.name); if (val) Config.name = xstrcpy(val); else Config.name = NULL; } else if (val && (strcmp(kwd, (char *)"PORT") == 0)) { if (sscanf(val, "%d", &ival) == 1) Config.my_port = ival; } else if (val && (strcmp(kwd, (char *)"TEMPFORMAT") == 0)) { if ((val[0] == 'C') || (val[0] == 'F')) Config.tempFormat = val[0]; } else if (strcmp(kwd, (char *)"TEMP_ADDRESS") == 0) { if (Config.temp_address) { device_count(FALSE, Config.temp_address); free(Config.temp_address); } if (val) { Config.temp_address = xstrcpy(val); device_count(TRUE, Config.temp_address); } else Config.temp_address = NULL; } else if (strcmp(kwd, (char *)"HUM_ADDRESS") == 0) { if (Config.hum_address) { device_count(FALSE, Config.hum_address); free(Config.hum_address); } if (val) { Config.hum_address = xstrcpy(val); device_count(TRUE, Config.hum_address); } else Config.hum_address = NULL; #ifdef HAVE_WIRINGPI_H } else if (val && (strcmp(kwd, (char *)"LCD_COLS") == 0)) { if (sscanf(val, "%d", &ival) == 1) Config.lcd_cols = ival; } else if (val && (strcmp(kwd, (char *)"LCD_ROWS") == 0)) { if (sscanf(val, "%d", &ival) == 1) Config.lcd_rows = ival; #endif } } } } } srv_send((char *)"504 Subcommand error"); return 1; } /* * LIST * LIST LOG */ int cmd_list(char *buf) { char *opt, *param, *filename, *p, q[2], buffer[256]; units_list *unit; FILE *fp; opt = strtok(buf, " \0"); opt = strtok(NULL, " \0"); if (opt == NULL) { /* * Default, list available units */ srv_send((char *)"212 Fermenter list follows:"); for (unit = Config.units; unit; unit = unit->next) { srv_send((char *)"%s,%s,%s", unit->uuid, unit->name, UNITMODE[unit->mode]); } srv_send((char *)"."); return 0; } else if (strcmp(opt, (char *)"LOG") == 0) { param = strtok(NULL, "\0"); if (param == NULL) { srv_send((char *)"502 Parameter missing"); return 1; } q[0] = q[1] = 'a'; for (unit = Config.units; unit; unit = unit->next) { if (strcmp(param, unit->uuid) == 0) break; } srv_send((char *)"212 Logfile list follows:"); if (getenv((char *)"USER") == NULL) { filename = xstrcpy((char *)"/root"); } else { filename = xstrcpy(getenv((char *)"HOME")); } filename = xstrcat(filename, (char *)"/.thermferm/log/"); filename = xstrcat(filename, unit->name); filename = xstrcat(filename, (char *)".log"); if ((fp = fopen(filename, "r"))) { while (fgets(buffer, sizeof(buffer)-1, fp) != NULL) { buffer[strlen(buffer) -1] = '\0'; p = buffer + 17; if (strncmp(p, (char *)"Mode", 4)) { if ((q[0] != buffer[11]) || (q[1] != buffer[12])) { q[0] = buffer[11]; q[1] = buffer[12]; srv_send(buffer); } } } } free(filename); filename = NULL; srv_send((char *)"."); return 0; } srv_send((char *)"504 Subcommand error"); return 1; } /* * PROFILE ADD name Add a new profile * PROFILE DEL uuid Delete profile with uuid * PROFILE LIST List available profiles * PROFILE GETS uuid Get profile steps list * PROFILE PUTS uuid Put profile steps list */ int cmd_profile(char *buf) { char ibuf[SS_BUFSIZE], *sstep, *rest, *targ, *param, *kwd, *val; int i, j, rlen, istep, irest; float ftarg, fval; socklen_t fromlen; char *opt; profiles_list *profile, *tmpp; prof_step *step, *olds; uuid_t uu; opt = strtok(buf, " \0"); opt = strtok(NULL, " \0"); if (opt == NULL) { srv_send((char *)"501 Subcommand missing"); return 1; } if (strcmp(opt, (char *)"LIST") == 0) { /* * Fermenting profiles */ srv_send((char *)"212 Profiles list follows:"); for (profile = Config.profiles; profile; profile = profile->next) { j = 0; for (step = profile->steps; step; step = step->next) j++; srv_send((char *)"%s,%s,%d,%d", profile->uuid, profile->name, j, profile->busy); } srv_send((char *)"."); return 1; } param = strtok(NULL, "\0"); if (param == NULL) { srv_send((char *)"502 Parameter missing"); return 1; } if (strcmp(opt, (char *)"ADD") == 0) { profile = (profiles_list *)malloc(sizeof(profiles_list)); profile->next = NULL; profile->version = 1; profile->uuid = malloc(37); uuid_generate(uu); uuid_unparse(uu, profile->uuid); profile->name = xstrcpy(param); profile->busy = 0; profile->inittemp = 20.0; profile->steps = NULL; if (Config.profiles == NULL) { Config.profiles = profile; } else { for (tmpp = Config.profiles; tmpp; tmpp = tmpp->next) { if (tmpp->next == NULL) { tmpp->next = profile; break; } } } syslog(LOG_NOTICE, "Profile %s added", profile->uuid); srv_send((char *)"211 Profile %s added", profile->uuid); return 0; } else if (strcmp(opt, (char *)"DEL") == 0) { if (delete_Profile(param)) { syslog(LOG_NOTICE, "Profile %s deleted", param); srv_send((char *)"211 Profile %s deleted", param); return 0; } else { srv_send((char *)"440 No such profile"); return 1; } } else if (strcmp(opt, (char *)"GET") == 0) { for (profile = Config.profiles; profile; profile = profile->next) { if (strcmp(profile->uuid, param) == 0) { srv_send((char *)"213 Profile record follows:"); srv_send((char *)"UUID,%s", profile->uuid); srv_send((char *)"NAME,%s", profile->name); srv_send((char *)"INITTEMP,%.1f", profile->inittemp); srv_send((char *)"."); return 1; } } srv_send((char *)"440 No such profile"); return 1; } else if (strcmp(opt, (char *)"PUT") == 0) { for (profile = Config.profiles; profile; profile = profile->next) { if (strcmp(profile->uuid, param) == 0) { while (1) { memset((char *)&ibuf, 0, SS_BUFSIZE); fromlen = sizeof(peeraddr_in); rlen = recvfrom(s, ibuf, sizeof(ibuf) -1, 0, (struct sockaddr *)&peeraddr_in, &fromlen); if (rlen == -1) { syslog(LOG_WARNING, "recvfrom(): %s", strerror(errno)); srv_send((char *)"518 recfrom(): %s", strerror(errno)); return 1; } for (i = 0; i < strlen(ibuf); i++) { if (ibuf[i] == '\n') ibuf[i] = '\0'; if (ibuf[i] == '\r') ibuf[i] = '\0'; } for (i = strlen(ibuf) -1; i > 0; i--) { if (ibuf[i] == ' ') ibuf[i] = '\0'; else break; } if (strlen(ibuf)) { if (debug) { syslog(LOG_NOTICE, "recv: \"%s\"", ibuf); fprintf(stdout, "recv: \"%s\"\n", ibuf); } if (strcmp(ibuf, (char *)".") == 0) { srv_send((char *)"219 Accepted Profile record"); return 0; } kwd = strtok(ibuf, ",\0"); val = strtok(NULL, "\0"); if (kwd && val) { if (strcmp(kwd, (char *)"NAME") == 0) { if (profile->name) free(profile->name); profile->name = xstrcpy(val); } else if (strcmp(kwd, (char *)"INITTEMP") == 0) { if (sscanf(val, "%f", &fval) == 1) profile->inittemp = fval; } } } } } } srv_send((char *)"440 No such profile"); return 1; } else if (strcmp(opt, (char *)"GETS") == 0) { for (profile = Config.profiles; profile; profile = profile->next) { if (strcmp(profile->uuid, param) == 0) { srv_send((char *)"215 Profile steps follow:"); for (step = profile->steps; step; step = step->next) { srv_send((char *)"%d,%d,%.1f", step->steptime, step->resttime, step->target); } srv_send((char *)"."); return 1; } } srv_send((char *)"440 No such profile"); return 1; } else if (strcmp(opt, (char *)"PUTS") == 0) { for (profile = Config.profiles; profile; profile = profile->next) { if (strcmp(profile->uuid, param) == 0) { if (profile->steps) { for (step = profile->steps; step; step = olds) { olds = step->next; free(step); } profile->steps = NULL; } while (1) { memset((char *)&ibuf, 0, SS_BUFSIZE); fromlen = sizeof(peeraddr_in); rlen = recvfrom(s, ibuf, sizeof(ibuf) -1, 0, (struct sockaddr *)&peeraddr_in, &fromlen); if (rlen == -1) { syslog(LOG_WARNING, "recvfrom(): %s", strerror(errno)); srv_send((char *)"518 recfrom(): %s", strerror(errno)); return 1; } else { for (i = 0; i < strlen(ibuf); i++) { if (ibuf[i] == '\n') ibuf[i] = '\0'; if (ibuf[i] == '\r') ibuf[i] = '\0'; } for (i = strlen(ibuf) -1; i > 0; i--) { if (ibuf[i] == ' ') ibuf[i] = '\0'; else break; } if (strlen(ibuf)) { if (debug) { syslog(LOG_NOTICE, "recv: \"%s\"", ibuf); fprintf(stdout, "recv: \"%s\"\n", ibuf); } if (strcmp(ibuf, (char *)".") == 0) { srv_send((char *)"219 Accepted Profile steps"); return 0; } sstep = strtok(ibuf, ",\0"); rest = strtok(NULL, ",\0"); targ = strtok(NULL, "\0"); if ((sscanf(sstep, "%d", &istep) == 1) && (sscanf(rest, "%d", &irest) == 1) && (sscanf(targ, "%f", &ftarg) == 1)) { step = (prof_step *)malloc(sizeof(prof_step)); step->next = NULL; step->version = 1; step->steptime = istep; step->resttime = irest; step->target = ftarg; if (profile->steps == NULL) { profile->steps = step; } else { for (olds = profile->steps; olds; olds = olds->next) { if (olds->next == NULL) { olds->next = step; break; } } } } } } } } } srv_send((char *)"440 No such profile"); return 1; } srv_send((char *)"504 Subcommand error"); return 1; } int delete_Unit(char *uuid) { units_list *current = Config.units; units_list *previous = NULL; while (current) { if (strcmp(current->uuid, uuid) == 0) { if (previous == NULL) { Config.units = current->next; free(current->uuid); current->uuid = NULL; free(current->name); current->name = NULL; if (current->air_address) free(current->air_address); current->air_address = NULL; if (current->beer_address) free(current->beer_address); current->beer_address = NULL; if (current->heater_address) free(current->heater_address); current->heater_address = NULL; if (current->cooler_address) free(current->cooler_address); current->cooler_address = NULL; if (current->fan_address) free(current->fan_address); current->fan_address = NULL; if (current->door_address) free(current->door_address); current->door_address = NULL; if (current->profile) free(current->profile); current->profile = NULL; free(current); return 1; } else { free(current->uuid); current->uuid = NULL; free(current->name); current->name = NULL; if (current->air_address) free(current->air_address); current->air_address = NULL; if (current->beer_address) free(current->beer_address); current->beer_address = NULL; if (current->heater_address) free(current->heater_address); current->heater_address = NULL; if (current->cooler_address) free(current->cooler_address); current->cooler_address = NULL; if (current->fan_address) free(current->fan_address); current->fan_address = NULL; if (current->door_address) free(current->door_address); current->door_address = NULL; if (current->profile) free(current->profile); current->profile = NULL; free(current); current = previous->next; return 1; } } else { previous = current; current = current->next; } } return 0; } /* * UNIT ADD name * UNIT DEL uuid * UNIT LIST * UNIT GET uuid * UNIT PUT uuid */ int cmd_unit(char *buf) { char *opt, *param = NULL, *kwd, *val, ibuf[SS_BUFSIZE]; units_list *unit, *tmpu; uuid_t uu; socklen_t fromlen; int ival, i, rlen; float fval; opt = strtok(buf, " \0"); opt = strtok(NULL, " \0"); if (opt == NULL) { srv_send((char *)"501 Subcommand missing"); return 1; } param = strtok(NULL, "\0"); if ((strcmp(opt, (char *)"LIST") == 0) && (param == NULL)) { srv_send((char *)"212 Fermenter list follows:"); for (unit = Config.units; unit; unit = unit->next) { srv_send((char *)"%s,%s,%s", unit->uuid, unit->name, UNITMODE[unit->mode]); } srv_send((char *)"."); return 1; } if (param == NULL) { srv_send((char *)"502 Parameter missing"); return 1; } if (strcmp(opt, (char *)"ADD") == 0) { unit = (units_list *)malloc(sizeof(units_list)); unit->next = NULL; unit->version = 1; unit->uuid = malloc(37); uuid_generate(uu); uuid_unparse(uu, unit->uuid); unit->name = xstrcpy(param); unit->air_address = unit->beer_address = unit->heater_address = unit->cooler_address = \ unit->fan_address = unit->door_address = unit->profile = NULL; unit->volume = 0.0; unit->air_state = unit->beer_state = 1; unit->air_temperature = unit->beer_temperature = 20000; unit->beer_set = unit->fridge_set = 20.0; unit->heater_state = unit->cooler_state = unit->fan_state = unit->door_state = unit->mode = unit->prof_state = 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 = unit->prof_paused = (time_t)0; unit->PID_err_old = unit->PID_I_err = 0.0; 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, "Unit %s added", unit->uuid); srv_send((char *)"211 Unit %s added", unit->uuid); return 0; } if (strcmp(opt, (char *)"DEL") == 0) { if (delete_Unit(param)) { syslog(LOG_NOTICE, "Unit %s deleted", param); srv_send((char *)"211 Unit %s deleted", param); return 0; } else { srv_send((char *)"440 No such unit"); return 1; } } if (strcmp(opt, (char *)"GET") == 0) { for (unit = Config.units; unit; unit = unit->next) { if (strcmp(param, unit->uuid) == 0) { srv_send((char *)"213 Unit listing follows:"); srv_send((char *)"NAME,%s", unit->name); srv_send((char *)"UUID,%s", unit->uuid); srv_send((char *)"VOLUME,%2f", unit->volume); srv_send((char *)"AIR_ADDRESS,%s", unit->air_address); srv_send((char *)"AIR_STATE,%s", TEMPSTATE[unit->air_state]); srv_send((char *)"AIR_TEMPERATURE,%.3f", unit->air_temperature / 1000.0); srv_send((char *)"BEER_ADDRESS,%s", MBSE_SS(unit->beer_address)); srv_send((char *)"BEER_STATE,%s", TEMPSTATE[unit->beer_state]); srv_send((char *)"BEER_TEMPERATURE,%.3f", unit->beer_temperature / 1000.0); srv_send((char *)"HEATER_ADDRESS,%s", unit->heater_address); srv_send((char *)"HEATER_STATE,%d", unit->heater_state); srv_send((char *)"COOLER_ADDRESS,%s", unit->cooler_address); srv_send((char *)"COOLER_STATE,%d", unit->cooler_state); srv_send((char *)"FAN_ADDRESS,%s", unit->fan_address); srv_send((char *)"FAN_STATE,%d", unit->fan_state); srv_send((char *)"DOOR_ADDRESS,%s", unit->door_address); srv_send((char *)"DOOR_STATE,%d", unit->door_state); srv_send((char *)"MODE,%s", UNITMODE[unit->mode]); srv_send((char *)"FRIDGE_SET,%.1f", unit->fridge_set); srv_send((char *)"BEER_SET,%.1f", unit->beer_set); srv_send((char *)"PROFILE,%s", unit->profile); srv_send((char *)"PROF_STARTED,%d", (int)unit->prof_started); srv_send((char *)"PROF_STATE,%s", PROFSTATE[unit->prof_state]); srv_send((char *)"PROF_TARGET,%.3f", unit->prof_target); srv_send((char *)"TEMP_SET_MIN,%.1f", unit->temp_set_min); srv_send((char *)"TEMP_SET_MAX,%.1f", unit->temp_set_max); srv_send((char *)"IDLE_RANGE_L,%.1f", unit->idle_rangeL); srv_send((char *)"IDLE_RANGE_H,%.1f", unit->idle_rangeH); srv_send((char *)"."); return 1; } } srv_send((char *)"440 No such unit"); return 1; } if (strcmp(opt, (char *)"PUT") == 0) { for (unit = Config.units ; unit; unit = unit->next) { if (strcmp(unit->uuid, param) == 0) { while (1) { memset((char *)&ibuf, 0, SS_BUFSIZE); fromlen = sizeof(peeraddr_in); rlen = recvfrom(s, ibuf, sizeof(ibuf) -1, 0, (struct sockaddr *)&peeraddr_in, &fromlen); if (rlen == -1) { syslog(LOG_WARNING, "recvfrom(): %s", strerror(errno)); srv_send((char *)"518 recfrom(): %s", strerror(errno)); return 1; } for (i = 0; i < strlen(ibuf); i++) { if (ibuf[i] == '\n') ibuf[i] = '\0'; if (ibuf[i] == '\r') ibuf[i] = '\0'; } for (i = strlen(ibuf) -1; i > 0; i--) { if (ibuf[i] == ' ') ibuf[i] = '\0'; else break; } if (strlen(ibuf)) { if (debug) { syslog(LOG_NOTICE, "recv: \"%s\"", ibuf); fprintf(stdout, "recv: \"%s\"\n", ibuf); } if (strcmp(ibuf, (char *)".") == 0) { srv_send((char *)"219 Accepted Unit record"); return 0; } kwd = strtok(ibuf, ",\0"); val = strtok(NULL, "\0"); if (kwd) { /* * Accept writable data. The client can sent just one line, * but may also sent everything. Simply ignore things we * don't understand. */ if (val && (strcmp(kwd, (char *)"NAME") == 0)) { if (unit->name) free(unit->name); unit->name = xstrcpy(val); } else if (val && (strcmp(kwd, (char *)"VOLUME") == 0)) { if (sscanf(val, "%f", &fval) == 1) unit->volume = fval; } else if (strcmp(kwd, (char *)"AIR_ADDRESS") == 0) { if (unit->air_address) { device_count(FALSE, unit->air_address); free(unit->air_address); } if (val) { unit->air_address = xstrcpy(val); device_count(TRUE, unit->air_address); } else unit->air_address = NULL; } else if (strcmp(kwd, (char *)"BEER_ADDRESS") == 0) { if (unit->beer_address) { device_count(FALSE, unit->beer_address); free(unit->beer_address); } if (val) { unit->beer_address = xstrcpy(val); device_count(TRUE, unit->beer_address); } else unit->beer_address = NULL; } else if (strcmp(kwd, (char *)"HEATER_ADDRESS") == 0) { if (unit->heater_address) { device_count(FALSE, unit->heater_address); free(unit->heater_address); } if (val) { unit->heater_address = xstrcpy(val); device_count(TRUE, unit->heater_address); } else unit->heater_address = NULL; } else if (val && (strcmp(kwd, (char *)"HEATER_STATE") == 0)) { if ((sscanf(val, "%d", &ival) == 1) && ((ival == 0) || (ival == 100))) unit->heater_state = ival; } else if (strcmp(kwd, (char *)"COOLER_ADDRESS") == 0) { if (unit->cooler_address) { device_count(FALSE, unit->cooler_address); free(unit->cooler_address); } if (val) { unit->cooler_address = xstrcpy(val); device_count(TRUE, unit->cooler_address); } else unit->cooler_address = NULL; } else if (val && (strcmp(kwd, (char *)"COOLER_STATE") == 0)) { if ((sscanf(val, "%d", &ival) == 1) && ((ival == 0) || (ival == 100))) unit->cooler_state = ival; } else if (strcmp(kwd, (char *)"FAN_ADDRESS") == 0) { if (unit->fan_address) { device_count(FALSE, unit->fan_address); free(unit->fan_address); } if (val) { unit->fan_address = xstrcpy(val); device_count(TRUE, unit->fan_address); } else unit->fan_address = NULL; } else if (val && (strcmp(kwd, (char *)"FAN_STATE") == 0)) { if ((sscanf(val, "%d", &ival) == 1) && ((ival == 0) || (ival == 100))) unit->fan_state = ival; } else if (strcmp(kwd, (char *)"DOOR_ADDRESS") == 0) { if (unit->door_address) { device_count(FALSE, unit->door_address); free(unit->door_address); } if (val) { unit->door_address = xstrcpy(val); device_count(TRUE, unit->door_address); } else unit->door_address = NULL; } else if (val && (strcmp(kwd, (char *)"MODE") == 0)) { for (i = 0; i < 5; i++) { if (strcmp(val, UNITMODE[i]) == 0) { /* Initialize log if the unit is turned on */ if ((unit->mode == UNITMODE_OFF) && (i != UNITMODE_OFF)) initlog(unit->name); syslog(LOG_NOTICE, "Mode from %s to %s via web interface", UNITMODE[unit->mode], UNITMODE[i]); unit->mode = i; /* Allways turn everything off after a mode change */ unit->PID_I_err = unit->PID_err_old = 0.0; unit->heater_state = unit->cooler_state = unit->fan_state = 0; device_out(unit->heater_address, unit->heater_state); device_out(unit->cooler_address, unit->cooler_state); device_out(unit->fan_address, unit->fan_state); break; } } } else if (val && (strcmp(kwd, (char *)"FRIDGE_SET") == 0)) { if (sscanf(val, "%f", &fval) == 1) unit->fridge_set = fval; } else if (val && (strcmp(kwd, (char *)"BEER_SET") == 0)) { if (sscanf(val, "%f", &fval) == 1) unit->beer_set = fval; } else if (strcmp(kwd, (char *)"PROFILE") == 0) { if (unit->prof_state == PROFILE_OFF) { /* * Only change profile if it is not active, else drop this one. */ if (unit->profile) free(unit->profile); if (val) unit->profile = xstrcpy(val); else unit->profile = NULL; /* * Reset all output devices */ unit->PID_I_err = unit->PID_err_old = 0.0; unit->heater_state = unit->cooler_state = unit->fan_state = 0; device_out(unit->heater_address, unit->heater_state); device_out(unit->cooler_address, unit->cooler_state); device_out(unit->fan_address, unit->fan_state); } } else if (val && (strcmp(kwd, (char *)"PROF_STATE") == 0)) { for (i = 0; i < 5; i++) { if (strcmp(val, PROFSTATE[i]) == 0) { switch (i) { case PROFILE_OFF: if (unit->prof_state == PROFILE_DONE) unit->prof_state = PROFILE_OFF; break; case PROFILE_PAUSE: if (unit->prof_state == PROFILE_RUN) unit->prof_state = PROFILE_PAUSE; else if (unit->prof_state == PROFILE_PAUSE) unit->prof_state = PROFILE_RUN; break; case PROFILE_RUN: if (unit->prof_state == PROFILE_OFF) { unit->prof_state = PROFILE_RUN; unit->prof_started = time(NULL); unit->prof_paused = 0; } break; case PROFILE_DONE: break; /* Command is illegal */ case PROFILE_ABORT: if ((unit->prof_state == PROFILE_RUN) || (unit->prof_state == PROFILE_PAUSE)) { unit->prof_state = PROFILE_OFF; unit->prof_started = 0; } break; } break; } } } else if (val && (strcmp(kwd, (char *)"TEMP_SET_MIN") == 0)) { if (sscanf(val, "%f", &fval) == 1) unit->temp_set_min = fval; } else if (val && (strcmp(kwd, (char *)"TEMP_SET_MAX") == 0)) { if (sscanf(val, "%f", &fval) == 1) unit->temp_set_max = fval; } else if (val && (strcmp(kwd, (char *)"IDLE_RANGE_L") == 0)) { if (sscanf(val, "%f", &fval) == 1) unit->idle_rangeL = fval; } else if (val && (strcmp(kwd, (char *)"IDLE_RANGE_H") == 0)) { if (sscanf(val, "%f", &fval) == 1) unit->idle_rangeH = fval; } } } } } } srv_send((char *)"440 No such unit"); return 1; } srv_send((char *)"504 Subcommand error"); return 1; } void cmd_server(void) { char buf[SS_BUFSIZE]; int i, rlen; socklen_t fromlen; memset((char *)&buf, 0, SS_BUFSIZE); fromlen = sizeof(peeraddr_in); rlen = recvfrom(s, buf, sizeof(buf) -1, 0, (struct sockaddr *)&peeraddr_in, &fromlen); if (rlen == -1) { syslog(LOG_WARNING, "recvfrom(): %s", strerror(errno)); } else { for (i = 0; i < strlen(buf); i++) { if (buf[i] == '\n') buf[i] = '\0'; 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); fprintf(stdout, "recv: \"%s\"\n", buf); } /* * Process commands from the client */ if (strncmp(buf, "DEVICE", 6) == 0) { if (cmd_device(buf) == 0) wrconfig(); } else if (strncmp(buf, "GLOBAL", 6) == 0) { if (cmd_global(buf) == 0) wrconfig(); } else if (strncmp(buf, "HELP", 4) == 0) { srv_send((char *)"100 Help text follows"); srv_send((char *)"Recognized commands:"); srv_send((char *)""); // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 srv_send((char *)"DEVICE ADD type Add new Device type"); srv_send((char *)"DEVICE DEL uuid Delete Device by uuid"); srv_send((char *)"DEVICE LIST List Devices"); srv_send((char *)"DEVICE GET uuid Get Device record by uuid"); srv_send((char *)"DEVICE PUT uuid Put Device record by uuid"); srv_send((char *)"GLOBAL GET Get global settings"); srv_send((char *)"GLOBAL PUT Put global settings"); srv_send((char *)"LIST List all fermenter units"); srv_send((char *)"LIST LOG uuid List logfile data in 1 hour lines"); srv_send((char *)"PROFILE uuid,name Profile rename"); srv_send((char *)"PROFILE ADD name Add new profile with name"); srv_send((char *)"PROFILE DEL uuid Delete profile by uuid"); srv_send((char *)"PROFILE LIST List available profiles"); srv_send((char *)"PROFILE GET uuid Get Profile record by uuid"); srv_send((char *)"PROFILE PUT uuid Put Profile record by uuid"); srv_send((char *)"PROFILE GETS uuid Profile get steps list"); srv_send((char *)"PROFILE PUTS uuid Profile put steps list"); srv_send((char *)"UNIT ADD name Add a new unit with name"); srv_send((char *)"UNIT DEL uuid Delete Unit by uuid"); srv_send((char *)"UNIT LIST List all Units"); srv_send((char *)"UNIT GET uuid Get Unit record by uuid"); srv_send((char *)"UNIT PUT uuid Put Unit record by uuid"); srv_send((char *)"."); } else if (strncmp(buf, "LIST", 4) == 0) { cmd_list(buf); } else if (strncmp(buf, "PROFILE", 7) == 0) { if (cmd_profile(buf) == 0) wrconfig(); } else if (strncmp(buf, "UNIT", 4) == 0) { if (cmd_unit(buf) == 0) wrconfig(); } else { srv_send((char *)"500 Unknown command"); } } } close(s); } #ifdef HAVE_WIRINGPI_H PI_THREAD (my_server_loop) #else void *my_server_loop(void *threadid) #endif { socklen_t addrlen; int optval = 1; syslog(LOG_NOTICE, "Thread my_server_loop started"); if (debug) fprintf(stdout, "Thread my_server_loop started\n"); memset((char *)&myaddr_in, 0, sizeof(struct sockaddr_in)); memset((char *)&peeraddr_in, 0, sizeof(struct sockaddr_in)); myaddr_in.sin_family = AF_INET; myaddr_in.sin_addr.s_addr = INADDR_ANY; myaddr_in.sin_port = htons(Config.my_port); ls = socket(AF_INET, SOCK_STREAM, 0); if (ls == -1) { syslog(LOG_WARNING, "Can't create listen socket: %s", strerror(errno)); fprintf(stderr, "Can't create listen socket: %s\n", strerror(errno)); return 0; } if (setsockopt(ls, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1) { syslog(LOG_WARNING, "Can't setsockopt SO_KEEPALIVE socket: %s", strerror(errno)); close(ls); return 0; } if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) { syslog(LOG_WARNING, "Can't setsockopt SO_REUSEADDR socket: %s", strerror(errno)); close(ls); return 0; } if (bind(ls, (struct sockaddr *)&myaddr_in, sizeof(struct sockaddr_in)) == -1) { syslog(LOG_WARNING, "Can't bind to listen socket: %s", strerror(errno)); close(ls); return 0; } if (listen(ls, 5) == -1) { syslog(LOG_WARNING, "Can't listen on listen socket: %s", strerror(errno)); close(ls); return 0; } syslog(LOG_NOTICE, "listen socket created %d", ls); /* * Loop forever until the external shutdown variable is set. */ for (;;) { addrlen = sizeof(struct sockaddr_in); /* * This call will block until a new connection * arrives. Then it will return the address of * the connecting peer, and a new socket * descriptor, s, for that connection. */ s = accept(ls, (struct sockaddr *)&peeraddr_in, &addrlen); if (s == -1) { syslog(LOG_WARNING, "my_server_loop accept failed %s", strerror(errno)); if (debug) fprintf(stdout, "my_server_loop accept failed %s\n", strerror(errno)); return 0; } cmd_server(); if (my_shutdown) { syslog(LOG_NOTICE, "Thread my_server_loop stopped"); if (debug) fprintf(stdout, "Thread my_server_loop stopped\n"); return 0; } } }