thermferm/server.c

Thu, 07 Aug 2014 22:06:18 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Thu, 07 Aug 2014 22:06:18 +0200
changeset 194
9eaaba49450f
parent 192
5d013b4a9138
child 195
b34a1b2421fb
permissions
-rw-r--r--

Added some ideas about profiles.

/*****************************************************************************
 * 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 EC-65K; 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 char		*current_unit;
#ifdef HAVE_WIRINGPI_H
extern int		lcdHandle;
extern unsigned char	lcdbuf[MAX_LCDS][20][4];
#endif
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[4][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_NOTICE, "srv_send failed");
	return -1;
    }
    
    if (send(s, (char *)"\r\n", 2, 0) != 2) {
	syslog(LOG_NOTICE, "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 *)"502 Missing command option");
	return 1;
    }
    param = strtok(NULL, "\0");

    if (strcmp(opt, (char *)"LIST") == 0) {
	srv_send((char *)"212 bus devices:");
	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 Missing command parameter");
	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->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 with uuid %s added", device->uuid);
	    srv_send((char *)"211 Device with uuid %s added", device->uuid);
	    return 0;

	} else {
	    srv_send((char *)"506 Wrong device parameter");
	    return 1;
	}
    }

    if (strcmp(opt, (char *)"DEL") == 0) {
	
	if (delete_Device(param)) {
	    syslog(LOG_NOTICE, "Deleted device with %s", param);
	    srv_send((char *)"211 Device %s deleted", param);
	    return 0;
	} else {
	    srv_send((char *)"440 Delete Device: No such device %s", param);
	    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 %s record follows:", device->uuid);
		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 *)"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_NOTICE, "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 *)"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 *)"502 Unknown command option");
    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 *)"501 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 *)"502 Unknown command option");
    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:");
	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 *)"501 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\" with uuid %s added", param, profile->uuid);
	srv_send((char *)"211 Profile \"%s\" with uuid %s added", param, profile->uuid);
	return 0;


    } else if (strcmp(opt, (char *)"DEL") == 0) {
	if (delete_Profile(param)) {
	    syslog(LOG_NOTICE, "Deleted Profile with %s", param);
	    srv_send((char *)"211 Profile %s deleted", param);
	    return 0;
	} else {
	    srv_send((char *)"440 Delete Profile: No such profile%s", param);
	    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 %s record follows:", profile->uuid);
		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_NOTICE, "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 *)"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_NOTICE, "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 *)"502 Unknown command option");
    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 uuid
 * 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 Parameter missing");
	return 1;
    }
    param = strtok(NULL, "\0");

    /*
     * UNIT uuid
     */
    if ((strlen(opt) == 36) && (param == NULL)) {
	/*
	 * Search using uuid
	 */
	for (unit = Config.units; unit; unit = unit->next) {
	    if (strcmp(opt, unit->uuid) == 0) {
		srv_send((char *)"210 Unit %s selected", unit->uuid);
		if (current_unit)
		    free(current_unit);
		current_unit = xstrcpy(unit->uuid);;
		return 1;
	    }
	}
	srv_send((char *)"410 No such unit");
	return 1;
    }

    if ((strcmp(opt, (char *)"LIST") == 0) && (param == NULL)) {
	srv_send((char *)"212 Fermenter Units 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 *)"501 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);
	if (current_unit)
	    free(current_unit);
	current_unit = xstrcpy(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 with uuid %s added", unit->uuid);
	srv_send((char *)"211 Unit with uuid %s added", unit->uuid);
	return 0;
    }

    if (strcmp(opt, (char *)"DEL") == 0) {
	if (delete_Unit(param)) {
	    syslog(LOG_NOTICE, "Deleted Unit with %s", param);
	    srv_send((char *)"211 Unit %s deleted", param);
	    return 0;
	} else {
	    srv_send((char *)"440 Delete Unit: No such unit %s", param);
	    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 %s listing follows:", unit->uuid);
		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);
		if (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 *)"410 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_NOTICE, "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);
					unit->mode = i;
					/* Allways turn everything off after a mode change */
					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;
				}

			    } else if (val && (strcmp(kwd, (char *)"PROF_STATE") == 0)) {
				for (i = 0; i < 4; i++) {
				    if (strcmp(val, PROFSTATE[i]) == 0) {
					unit->prof_state = i;
					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 device");
	return 1;
    }


    srv_send((char *)"502 Unknown command option");
    return 1;
}



void cmd_server(void)
{
    char                buf[SS_BUFSIZE];
    int                 i, rlen;
    socklen_t           fromlen;
#ifdef HAVE_WIRINGPI_H
    int			j;
    char		obuf[SS_BUFSIZE];
#endif

    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_NOTICE, "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, "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 *)"LCD                           Get LCD screen (allways 4 rows of 20 characters)");
		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 uuid                     Select unit by uuid");
		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 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, "LCD", 3) == 0) {
#ifdef HAVE_WIRINGPI_H
		srv_send((char *)"201 information follows");
		for (j = 0; j < 4; j++) {
		    sprintf(obuf, "                   ");
		    obuf[20] = '\0';
		    for (i = 0; i < 20; i++)
		    	obuf[i]  = lcdbuf[lcdHandle][i][j];
		    srv_send(obuf);
		}
		srv_send((char *)".");
#else
		srv_send((char *)"403 LCD not available");
#endif
	    } 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 {
		if (debug)
		    fprintf(stdout, "unknown command \"%s\"\n", buf);
		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_NOTICE, "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_NOTICE, "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_NOTICE, "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_NOTICE, "Can't bind to listen socket: %s", strerror(errno));
	close(ls);
	return 0;
    }

    if (listen(ls, 5) == -1) {
	syslog(LOG_NOTICE, "Can't listen on listen socket: %s", strerror(errno));
	close(ls);
	return 0;
    }

    syslog(LOG_NOTICE, "listen socket created %d", ls);
    if (debug)
	fprintf(stdout, "listen socket created %d\n", 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_NOTICE, "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;
	}

    }
}

mercurial