thermometers/thermometers.c

Mon, 18 May 2015 21:19:06 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Mon, 18 May 2015 21:19:06 +0200
changeset 365
df0261bb3feb
parent 149
f019ea6a9d31
permissions
-rw-r--r--

Version 0.3.3, still not for production. Fixed warnings when the simulator code is compiled. Slowed the simulator air temperature change 60 times. More realistic temperature changes for the heater and cooler elements. Improved logic in the simulator.

/*****************************************************************************
 * Copyright (C) 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 "thermometers.h"


static int		my_shutdown = FALSE;
static pid_t		pgrp, mypid;

extern int		debug;
extern sys_config	Config;
#ifdef HAVE_WIRINGPI_H
extern int		lcdHandle;
#endif

int server(void);
void help(void);
void die(int);


void help(void)
{
    fprintf(stdout, "mbsePi-apps thermometers v%s starting\n\n", VERSION);
    fprintf(stdout, "Usage: thermomeneters [-d] [-h]\n");
    fprintf(stdout, "  -d --debug              Debug and run in foreground\n");
    fprintf(stdout, "  -h --help               Display this help\n");
}



void die(int onsig)
{
    switch (onsig) {
	case SIGHUP:	syslog(LOG_NOTICE, "Got SIGHUP, shutting down");
			break;
	case SIGINT:	syslog(LOG_NOTICE, "Keyboard interrupt, shutting down");
			break;
	case SIGTERM:	syslog(LOG_NOTICE, "Got SIGTERM, shutting down");
			break;
	default:	syslog(LOG_NOTICE, "die() on signal %d", onsig);
    }

    my_shutdown = TRUE;
}



#ifdef HAVE_WIRINGPI_H
void stopLCD(void)
{
   lcdClear(lcdHandle);
   setBacklight(0);
}
#endif



int main(int argc, char *argv[])
{
    int		rc, c, i;
    pid_t	frk;
#ifdef HAVE_WIRINGPI_H
    char	buf[80];
#endif

    while (1) {
	int option_index = 0;
	static struct option long_options[] = {
	    {"debug", 0, 0, 'c'},
	    {"help", 0, 0, 'h'},
	    {0, 0, 0, 0}
	};

	c = getopt_long(argc, argv, "dh", long_options, &option_index);
	if (c == -1)
	    break;

	switch (c) {
	    case 'd':	debug = TRUE;
			break;
	    case 'h':	help();
			return 1;
	}
    }

    openlog("thermometers", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_USER);
    syslog(LOG_NOTICE, "mbsePi-apps thermometers v%s starting", VERSION);
    if (debug)
	fprintf(stdout, "mbsePi-apps thermometers v%s starting\n", VERSION);

    if (rdconfig((char *)"thermometers.conf")) {
	fprintf(stderr, "Error reading configuration\n");
	syslog(LOG_NOTICE, "Error reading configuration, halted");
	return 1;
    }

    /*
     *  Catch all the signals we can, and ignore the rest. Note that SIGKILL can't be ignored
     *  but that's live. This daemon should only be stopped by SIGTERM.
     *  Don't catch SIGCHLD.
     */
    for (i = 0; i < NSIG; i++) {
    	if ((i != SIGCHLD) && (i != SIGKILL) && (i != SIGSTOP))
	    signal(i, (void (*))die);
    }

#ifdef HAVE_WIRINGPI_H

    if (wiringPiSetup () )
	return 1;

    if ((rc = initLCD (16, 2))) {
	fprintf(stderr, "Cannot initialize LCD display, rc=%d\n", rc);
	return 1;
    }

    lcdPosition(lcdHandle, 0, 0);
    lcdPuts(lcdHandle, "Thermometers");
    lcdPosition(lcdHandle, 0, 1);
    sprintf(buf, "Version %s", VERSION);
    lcdPuts(lcdHandle, buf);
#endif

    if (debug) {
	/*
	 * For debugging run in foreground.
	 */
	rc = server();
    } else {
	/*
	 * Server initialization is complete. Now we can fork the 
	 * daemon and return to the user. We need to do a setpgrp
	 * so that the daemon will no longer be assosiated with the
	 * users control terminal. This is done before the fork, so
	 * that the child will not be a process group leader. Otherwise,
	 * if the child were to open a terminal, it would become
	 * associated with that terminal as its control terminal.
	 */
	if ((pgrp = setpgid(0, 0)) == -1) {
	    syslog(LOG_NOTICE, "setpgpid failed");
	}

	frk = fork();
	switch (frk) {
	    case -1:	
		    	syslog(LOG_NOTICE, "Daemon fork failed: %s", strerror(errno));
			syslog(LOG_NOTICE, "Finished, rc=1");
#ifdef HAVE_WIRINGPI_H
			stopLCD();
#endif
			exit(1);
	    case 0:	/*
			 * Run the daemon
			 */
			fclose(stdin);
			if (open("/dev/null", O_RDONLY) != 0) {
			    syslog(LOG_NOTICE, "Reopen of stdin to /dev/null failed");
			    _exit(2);
			}
			fclose(stdout);
			if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 1) {
			    syslog(LOG_NOTICE, "Reopen of stdout to /dev/null failed");
			    _exit(2);
			}
			fclose(stderr);
			if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 2) {
			    syslog(LOG_NOTICE, "Reopen of stderr to /dev/null failed");
			    _exit(2);
			}
			mypid = getpid();
			rc = server();
			break;
			/* Not reached */
	    default:
			/*
			 * Here we detach this process and let the child
			 * run the deamon process.
			 */
			syslog(LOG_NOTICE, "Starting daemon with pid %d", frk);
			exit(0);
	}
    }

    syslog(LOG_NOTICE, "Finished, rc=%d", rc);
    return rc;
}



int server(void)
{
    int                 temp, rc = 0;
#ifdef HAVE_WIRINGPI_H
    char		buf[1024];
    int			lcdupdate;
#endif
    w1_therm		*tmp1;
    char		*device, line[60], *p = NULL;
    FILE		*fp;

    if (debug)
	fprintf(stdout, (char *)"Enter loop\n");

    do {
#ifdef HAVE_WIRINGPI_H
	    lcdupdate = FALSE;
#endif

	    /*
	     * Here send our 1-wire sensors values
	     */
	    for (tmp1 = Config.w1therms; tmp1; tmp1 = tmp1->next) {

		/*
		 * Build path and alias topic
		 */
		device = xstrcpy((char *)"/sys/bus/w1/devices/");
		device = xstrcat(device, tmp1->master);
		device = xstrcat(device, (char *)"/");
		device = xstrcat(device, tmp1->name);
		device = xstrcat(device, (char *)"/w1_slave");

		/*
		 * Read sensor data
		 */
		if ((fp = fopen(device, "r"))) {
		    /*
		     * The output looks like:
		     * 72 01 4b 46 7f ff 0e 10 57 : crc=57 YES
		     * 72 01 4b 46 7f ff 0e 10 57 t=23125
		     */
		    fgets(line, 50, fp);
		    line[strlen(line)-1] = '\0';
		    if ((line[36] == 'Y') && (line[37] == 'E')) {
			/*
			 * CRC is Ok, continue
			 */
		    	fgets(line, 50, fp);
			line[strlen(line)-1] = '\0';
			strtok(line, (char *)"=");
			p = strtok(NULL, (char *)"=");
			rc = sscanf(p, "%d", &temp);
			if ((rc == 1) && (tmp1->lastval != temp)) {
			    tmp1->lastval = temp;
#ifdef HAVE_WIRINGPI_H
			    lcdupdate = TRUE;
#endif
			}
		    } else {
			syslog(LOG_NOTICE, "sensor %s/%s CRC error", tmp1->master, tmp1->name);
		    }
		    fclose(fp);
		    tmp1->present = 1;
		} else {
		    tmp1->present = 0;
		    if (debug)
		    	printf("sensor %s is missing\n", tmp1->name);
		}

		free(device);
		device = NULL;
	    }

#ifdef HAVE_WIRINGPI_H
	    if (lcdupdate) {
		lcdPosition(lcdHandle, 0, 0);
		tmp1 = Config.w1therms;
		snprintf(buf, 16, "%5.1f %cC %s            ", tmp1->lastval / 1000.0, 0xdf, tmp1->alias);
		lcdPuts(lcdHandle, buf);
		tmp1 = tmp1->next;
		lcdPosition(lcdHandle, 0, 1);
		snprintf(buf, 16, "%5.1f %cC %s            ", tmp1->lastval / 1000.0, 0xdf, tmp1->alias);
		lcdPuts(lcdHandle, buf);
	    }
#endif

	    if (my_shutdown) {
#ifdef HAVE_WIRINGPI_H
		lcdClear(lcdHandle);
		lcdPosition(lcdHandle, 0, 0);
		lcdPuts(lcdHandle, "Shuting down ...");
#endif
	    }

	    usleep(100000);

    } while (! my_shutdown);

    if (debug)
	fprintf(stdout, (char *)"Out of loop\n");

#ifdef HAVE_WIRINGPI_H
    stopLCD();
#endif

    return rc;
}

mercurial