# HG changeset patch # User Michiel Broek # Date 1401048416 -7200 # Node ID a03b6dac53985663e797aab07cc3f0168ac486ed # Parent 8b5e8f1e172da275acf844378a0146c50c2a99b6 Removed library, bumped to version 0.0.7 diff -r 8b5e8f1e172d -r a03b6dac5398 .hgignore --- a/.hgignore Sun May 25 16:39:54 2014 +0200 +++ b/.hgignore Sun May 25 22:06:56 2014 +0200 @@ -15,4 +15,4 @@ syntax: glob *.o */filelist -lib/*.a +www/* diff -r 8b5e8f1e172d -r a03b6dac5398 config.h.in --- a/config.h.in Sun May 25 16:39:54 2014 +0200 +++ b/config.h.in Sun May 25 22:06:56 2014 +0200 @@ -12,3 +12,5 @@ /* Define if you have the header file. */ #undef HAVE_WIRINGPI_H +/* Define if you have the header file. */ +#undef HAVE_MOSQUITTO_H diff -r 8b5e8f1e172d -r a03b6dac5398 configure --- a/configure Sun May 25 16:39:54 2014 +0200 +++ b/configure Sun May 25 22:06:56 2014 +0200 @@ -582,7 +582,7 @@ PACKAGE_BUGREPORT= PACKAGE_URL= -ac_unique_file="thermometers/main.c" +ac_unique_file="thermometers/thermometers.c" ac_default_prefix=/usr/local # Factoring default headers for most tests. ac_includes_default="\ @@ -2028,11 +2028,11 @@ ac_config_headers="$ac_config_headers config.h" -SUBDIRS="lib dht11 rc433 thermferm thermometers" +SUBDIRS="dht11 rc433 thermferm thermometers" PACKAGE="mbsePi-apps" -VERSION="0.0.6" +VERSION="0.0.7" COPYRIGHT="Copyright (C) 2014 Michiel Broek, All Rights Reserved" CYEARS="2014" @@ -3091,57 +3091,6 @@ fi if test "$result" = "yes"; then - LIBS="$LIBS -lmosquitto" -else - as_fn_error $? "libmosquitto not found" "$LINENO" 5 -fi - - -WIRINGPI=No -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for wiringPiSetup in -lwiringPi" >&5 -$as_echo_n "checking for wiringPiSetup in -lwiringPi... " >&6; } -if ${ac_cv_lib_wiringPi_wiringPiSetup+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lwiringPi $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char wiringPiSetup (); -int -main () -{ -return wiringPiSetup (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_wiringPi_wiringPiSetup=yes -else - ac_cv_lib_wiringPi_wiringPiSetup=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wiringPi_wiringPiSetup" >&5 -$as_echo "$ac_cv_lib_wiringPi_wiringPiSetup" >&6; } -if test "x$ac_cv_lib_wiringPi_wiringPiSetup" = xyes; then : - result=yes -else - result=no -fi - -if test "$result" = "yes"; then - LIBS="$LIBS -lwiringPi -lwiringPiDev" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3539,7 +3488,71 @@ done -for ac_header in wiringPi.h +for ac_header in mosquitto.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "mosquitto.h" "ac_cv_header_mosquitto_h" "$ac_includes_default" +if test "x$ac_cv_header_mosquitto_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MOSQUITTO_H 1 +_ACEOF + MOSQUITTO=Yes +else + MOSQUITTO=No +fi + +done + +else + as_fn_error $? "libmosquitto not found" "$LINENO" 5 +fi + + +WIRINGPI=No +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for wiringPiSetup in -lwiringPi" >&5 +$as_echo_n "checking for wiringPiSetup in -lwiringPi... " >&6; } +if ${ac_cv_lib_wiringPi_wiringPiSetup+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lwiringPi $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char wiringPiSetup (); +int +main () +{ +return wiringPiSetup (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_wiringPi_wiringPiSetup=yes +else + ac_cv_lib_wiringPi_wiringPiSetup=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wiringPi_wiringPiSetup" >&5 +$as_echo "$ac_cv_lib_wiringPi_wiringPiSetup" >&6; } +if test "x$ac_cv_lib_wiringPi_wiringPiSetup" = xyes; then : + result=yes +else + result=no +fi + +if test "$result" = "yes"; then + LIBS="$LIBS -lwiringPi -lwiringPiDev" + for ac_header in wiringPi.h do : ac_fn_c_check_header_mongrel "$LINENO" "wiringPi.h" "ac_cv_header_wiringPi_h" "$ac_includes_default" if test "x$ac_cv_header_wiringPi_h" = xyes; then : diff -r 8b5e8f1e172d -r a03b6dac5398 configure.ac --- a/configure.ac Sun May 25 16:39:54 2014 +0200 +++ b/configure.ac Sun May 25 22:06:56 2014 +0200 @@ -1,14 +1,14 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT(thermometers/main.c) +AC_INIT(thermometers/thermometers.c) AM_CONFIG_HEADER(config.h) -SUBDIRS="lib dht11 rc433 thermferm thermometers" +SUBDIRS="dht11 rc433 thermferm thermometers" AC_SUBST(SUBDIRS) dnl General settings dnl After changeing the version number, run autoconf! PACKAGE="mbsePi-apps" -VERSION="0.0.6" +VERSION="0.0.7" COPYRIGHT="Copyright (C) 2014 Michiel Broek, All Rights Reserved" CYEARS="2014" AC_SUBST(PACKAGE) @@ -34,7 +34,7 @@ # AC_CHECK_LIB(mosquitto,mosquitto_lib_init,result=yes,result=no) if test "$result" = "yes"; then - LIBS="$LIBS -lmosquitto" + AC_CHECK_HEADERS(mosquitto.h,MOSQUITTO=Yes,MOSQUITTO=No) else AC_MSG_ERROR(libmosquitto not found) fi diff -r 8b5e8f1e172d -r a03b6dac5398 dht11/Makefile --- a/dht11/Makefile Sun May 25 16:39:54 2014 +0200 +++ b/dht11/Makefile Sun May 25 22:06:56 2014 +0200 @@ -5,7 +5,6 @@ SRCS = dht11.c HDRS = dht11.h OBJS = dht11.o -SLIBS = ../lib/libmbse.a TARGET = dht11 OTHER = Makefile @@ -54,5 +53,5 @@ # DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT # Dependencies generated by make depend -dht11.o: ../lib/mbselib.h dht11.h +dht11.o: dht11.h # End of generated dependencies diff -r 8b5e8f1e172d -r a03b6dac5398 dht11/dht11.c --- a/dht11/dht11.c Sun May 25 16:39:54 2014 +0200 +++ b/dht11/dht11.c Sun May 25 22:06:56 2014 +0200 @@ -20,14 +20,148 @@ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ -#include "../lib/mbselib.h" #include "dht11.h" #ifdef HAVE_WIRINGPI_H -extern int dht11_valid; -extern int dht11_temperature; -extern int dht11_humidity; +#define MAXTIMINGS 100 + +int dht11_pin = -1; +int dht11_temperature = -1; +int dht11_humidity = -1; +int dht11_valid = false; +int dht11_t_offset = 0; +int dht11_h_offset = 0; + + + +static uint8_t sizecvt(const int read_value) { + /* + * digitalRead() and friends from wiringpi are defined as returning a value + * < 256. However, they are returned as int() types. This is a safety function + */ + if (read_value > 255 || read_value < 0) { + syslog(LOG_NOTICE, "invalid data from wiringPi library"); + } + + return (uint8_t)read_value; +} + + + +/* + * DHT11 sensor read. This should be used in a thread loop. + */ +void dht11Read(void) { + int tries = 5; + unsigned short got_correct_data = 0; + + if (dht11_pin == -1) + return; + + while (tries && !got_correct_data) { + uint8_t laststate = HIGH; + uint8_t counter = 0; + uint8_t j = 0, i = 0; + int dht11_dat[5] = {0,0,0,0,0}; + + /* + * Select output mode to send the start signal. + */ + pinMode(dht11_pin, OUTPUT); + digitalWrite(dht11_pin, HIGH); + usleep(1000); + + /* + * Low for at least 18 milliseconds + */ + digitalWrite(dht11_pin, LOW); + usleep(20000); + digitalWrite(dht11_pin, HIGH); + pinMode(dht11_pin, INPUT); + + /* + * Detect change and read data + */ + for (i=0; i= 4) && (i%2 == 0)) { + + // shove each bit into the storage bytes + dht11_dat[(int)((double)j/8)] <<= 1; + if (counter > 16) + dht11_dat[(int)((double)j/8)] |= 1; + j++; + } + } + + /* + * If there is no sensor, j = 0 + */ + if ((counter == 255) && (j == 0)) { + if (dht11_temperature != -1) { + syslog(LOG_NOTICE, "dht11 sensor disappeared"); + } else { + syslog(LOG_NOTICE, "dht11 sensor not present"); + } + dht11_temperature = -1; + dht11_humidity = -1; + dht11_valid = false; + return; + } + + /* + * check we read 40 bits (8bit x 5 ) + verify checksum in the last byte + * print it out if data is good + */ + if ((j >= 40) && (dht11_dat[4] == ((dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3]) & 0xFF))) { + got_correct_data = 1; + + int h = dht11_dat[0] + dht11_dat[1]; + int t = (dht11_dat[2] & 0x7F) + dht11_dat[3]; + t += dht11_t_offset; + h += dht11_h_offset; + + if ((dht11_dat[2] & 0x80) != 0) + t *= -1; + + dht11_temperature = t; + dht11_humidity = h; + dht11_valid = true; + } else { + tries--; + if (tries == 0) + syslog(LOG_INFO, "dht11 data checksum was wrong 5 times"); + usleep(100000); + } + } +} + + + +void dht11Init(int pin, int t_offset, int h_offset) { + dht11_pin = pin; + dht11_t_offset = t_offset; + dht11_h_offset = h_offset; +} + + int main(int argc, char *argv[]) { diff -r 8b5e8f1e172d -r a03b6dac5398 dht11/dht11.h --- a/dht11/dht11.h Sun May 25 16:39:54 2014 +0200 +++ b/dht11/dht11.h Sun May 25 22:06:56 2014 +0200 @@ -5,5 +5,7 @@ #define TRUE 1 #define FALSE 0 +#include + #endif diff -r 8b5e8f1e172d -r a03b6dac5398 lib/Makefile --- a/lib/Makefile Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -# Makefile for the library files. - -include ../Makefile.global - -SRCS = $(wildcard *.c) -OBJS = $(SRCS:.c=.o) -HDRS = mbselib.h -TARGET = libmbse.a - -############################################################################# - -.c.o: - ${CC} ${CFLAGS} ${INCLUDES} ${DEFINES} -c $< - -all: ${TARGET} - -libmbse.a: ${OBJS} - ar r $@ $? - ${RANLIB} $@ - -clean: - rm -f ${TARGET} *.o *.h~ *.c~ core filelist Makefile.bak - -depend: - @rm -f Makefile.bak; \ - mv Makefile Makefile.bak; \ - sed -e '/^# DO NOT DELETE/,$$d' Makefile.bak >Makefile; \ - ${ECHO} '# DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT' >>Makefile; \ - ${ECHO} '# Dependencies generated by make depend' >>Makefile; \ - for f in ${SRCS}; \ - do \ - ${ECHO} "Dependencies for $$f:\c"; \ - ${ECHO} "`basename $$f .c`.o:\c" >>Makefile; \ - for h in `sed -n -e \ - 's/^#[ ]*include[ ]*"\([^"]*\)".*/\1/p' $$f`; \ - do \ - ${ECHO} " $$h\c"; \ - ${ECHO} " $$h\c" >>Makefile; \ - done; \ - ${ECHO} " done."; \ - ${ECHO} "" >>Makefile; \ - done; \ - ${ECHO} '# End of generated dependencies' >>Makefile - -# DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT -# Dependencies generated by make depend -rc-switch.o: ../config.h mbselib.h -lock.o: ../config.h mbselib.h -logger.o: ../config.h mbselib.h -lcd-pcf8574.o: ../config.h mbselib.h -xutil.o: ../config.h mbselib.h -dht11.o: ../config.h mbselib.h -rdconfig.o: ../config.h mbselib.h -# End of generated dependencies diff -r 8b5e8f1e172d -r a03b6dac5398 lib/dht11.c --- a/lib/dht11.c Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -/***************************************************************************** - * Copyright (C) 2014 - * - * Michiel Broek - * - * This file is part of the mbsePi-apps - * - * Parts original by CurlyMo from the pilight project. - * - * 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 "../config.h" -#include "mbselib.h" - -#ifdef HAVE_WIRINGPI_H - -#define MAXTIMINGS 100 - -int dht11_pin = -1; -int dht11_temperature = -1; -int dht11_humidity = -1; -int dht11_valid = false; -int dht11_t_offset = 0; -int dht11_h_offset = 0; - - - -static uint8_t sizecvt(const int read_value) { - /* - * digitalRead() and friends from wiringpi are defined as returning a value - * < 256. However, they are returned as int() types. This is a safety function - */ - if (read_value > 255 || read_value < 0) { - syslog(LOG_NOTICE, "invalid data from wiringPi library"); - } - - return (uint8_t)read_value; -} - - - -/* - * DHT11 sensor read. This should be used in a thread loop. - */ -void dht11Read(void) { - int tries = 5; - unsigned short got_correct_data = 0; - - if (dht11_pin == -1) - return; - - while (tries && !got_correct_data) { - uint8_t laststate = HIGH; - uint8_t counter = 0; - uint8_t j = 0, i = 0; - int dht11_dat[5] = {0,0,0,0,0}; - - /* - * Select output mode to send the start signal. - */ - pinMode(dht11_pin, OUTPUT); - digitalWrite(dht11_pin, HIGH); - usleep(1000); - - /* - * Low for at least 18 milliseconds - */ - digitalWrite(dht11_pin, LOW); - usleep(20000); - digitalWrite(dht11_pin, HIGH); - pinMode(dht11_pin, INPUT); - - /* - * Detect change and read data - */ - for (i=0; i= 4) && (i%2 == 0)) { - - // shove each bit into the storage bytes - dht11_dat[(int)((double)j/8)] <<= 1; - if (counter > 16) - dht11_dat[(int)((double)j/8)] |= 1; - j++; - } - } - - /* - * If there is no sensor, j = 0 - */ - if ((counter == 255) && (j == 0)) { - if (dht11_temperature != -1) { - syslog(LOG_NOTICE, "dht11 sensor disappeared"); - } else { - syslog(LOG_NOTICE, "dht11 sensor not present"); - } - dht11_temperature = -1; - dht11_humidity = -1; - dht11_valid = false; - return; - } - - /* - * check we read 40 bits (8bit x 5 ) + verify checksum in the last byte - * print it out if data is good - */ - if ((j >= 40) && (dht11_dat[4] == ((dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3]) & 0xFF))) { - got_correct_data = 1; - - int h = dht11_dat[0] + dht11_dat[1]; - int t = (dht11_dat[2] & 0x7F) + dht11_dat[3]; - t += dht11_t_offset; - h += dht11_h_offset; - - if ((dht11_dat[2] & 0x80) != 0) - t *= -1; - - dht11_temperature = t; - dht11_humidity = h; - dht11_valid = true; - } else { - tries--; - if (tries == 0) - syslog(LOG_INFO, "dht11 data checksum was wrong 5 times"); - usleep(100000); - } - } -} - - - -void dht11Init(int pin, int t_offset, int h_offset) { - dht11_pin = pin; - dht11_t_offset = t_offset; - dht11_h_offset = h_offset; -} - - -#endif - diff -r 8b5e8f1e172d -r a03b6dac5398 lib/lcd-pcf8574.c --- a/lib/lcd-pcf8574.c Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/* - * lcd-pcf8574.c: - * Text-based LCD driver library code - * This is designed to drive the HD44780U LCD display connected via - * a "LCM1602 IIC A0 A1 A2" board with a PCF8574 I2C controller. - * - * Copyright (c) 2012-2013 Gordon Henderson. - * Copyright (c) 2014 Michiel Broek. - *********************************************************************** - * - * mbsePi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * mbsePi 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with wiringPi. If not, see . - *********************************************************************** - */ - -#include "../config.h" -#include "mbselib.h" - -#ifdef HAVE_WIRINGPI_H - -int lcdHandle; -unsigned char lcdbuf[MAX_LCDS][20][4]; - -struct lcdDataStruct -{ - int bits, rows, cols ; - int rsPin, strbPin ; - int dataPins [8] ; - int cx, cy ; -}; -extern struct lcdDataStruct *lcds [MAX_LCDS]; - - -/* - * Some LCD functions are extended shadow copies of the wiringPi functions. - * The difference is that the lcdbuf will be updated with the contents on - * the hardware display. This copy can then be used for a remote display - */ - - -/* - * setBacklight: - ********************************************************************************* - */ - -void setBacklight (int value) -{ - pinMode (AF_BACKLIGHT, OUTPUT) ; - digitalWrite (AF_BACKLIGHT, (value & 1)) ; -} - - - -/* - * initLCD: - ********************************************************************************* - */ - -int initLCD (int cols, int rows) -{ - int x, y; - - if (!((rows == 1) || (rows == 2) || (rows == 4))) { - fprintf (stderr, "rows must be 1, 2 or 4\n") ; - return EXIT_FAILURE ; - } - - if (!((cols == 16) || (cols == 20))) { - fprintf (stderr, "cols must be 16 or 20\n") ; - return EXIT_FAILURE ; - } - - pcf8574Setup(AF_BASE, 0x27) ; - pinMode (AF_RW, OUTPUT) ; - digitalWrite (AF_RW, LOW) ; // Not used with wiringPi - always in write mode - - /* - * The other control pins are initialised with lcdInit () - */ - lcdHandle = lcdInit (rows, cols, 4, AF_RS, AF_E, AF_DB4, AF_DB5, AF_DB6, AF_DB7, 0, 0, 0, 0) ; - if (lcdHandle < 0) { - fprintf (stderr, "lcdInit failed\n") ; - return -1 ; - } - - lcdClear (lcdHandle) ; - for (x = 0; x < 20; x++) - for (y = 0; y < 4; y++) - lcdbuf[lcdHandle][x][y] = ' '; - - setBacklight (1) ; - - return 0 ; -} - - - -void mb_lcdPutchar(const int fd, unsigned char data) -{ - struct lcdDataStruct *lcd = lcds[fd]; - - /* - * Write to our buffer first, then to the wiringPi driver. - * Writing to wiringPi updates the cursor position. - */ - lcdbuf[fd][lcd->cx][lcd->cy] = data; - lcdPutchar(fd, data); -} - - - -void mb_lcdPuts(const int fd, const char *string) -{ - while (*string) - mb_lcdPutchar (fd, *string++); -} - - - -void mb_lcdClear(const int fd) -{ - int x, y; - - lcdClear(fd); - for (x = 0; x < 20; x++) - for (y = 0; y < 4; y++) - lcdbuf[fd][x][y] = ' '; -} - - - -#endif - diff -r 8b5e8f1e172d -r a03b6dac5398 lib/lock.c --- a/lib/lock.c Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/***************************************************************************** - * Copyright (C) 2014 - * - * Michiel Broek - * - * 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 "../config.h" -#include "mbselib.h" - -/* - * Put a lock on this program. - */ -int lockprog(char *name) -{ - char *tempfile, *lockfile; - FILE *fp; - pid_t oldpid; - - tempfile = calloc(PATH_MAX, sizeof(char)); - lockfile = calloc(PATH_MAX, sizeof(char)); - - snprintf(tempfile, PATH_MAX, "/var/run/%s.tmp", name); - snprintf(lockfile, PATH_MAX, "/var/run/%s.pid", name); - - if ((fp = fopen(tempfile, "w")) == NULL) { - perror(name); - printf("Can't create lockfile \"%s\"\n", tempfile); - free(tempfile); - free(lockfile); - return 1; - } - fprintf(fp, "%10u\n", getpid()); - fclose(fp); - - while (TRUE) { - if (link(tempfile, lockfile) == 0) { - unlink(tempfile); - free(tempfile); - free(lockfile); - return 0; - } - if ((fp = fopen(lockfile, "r")) == NULL) { - perror(name); - printf("Can't open lockfile \"%s\"\n", tempfile); - unlink(tempfile); - free(tempfile); - free(lockfile); - return 1; - } - if (fscanf(fp, "%u", &oldpid) != 1) { - perror(name); - printf("Can't read old pid from \"%s\"\n", tempfile); - fclose(fp); - unlink(tempfile); - free(tempfile); - free(lockfile); - return 1; - } - fclose(fp); - if (kill(oldpid,0) == -1) { - if (errno == ESRCH) { - printf("Stale lock found for pid %u\n", oldpid); - unlink(lockfile); - /* no return, try lock again */ - } else { - perror(name); - printf("Kill for %u failed\n",oldpid); - unlink(tempfile); - free(tempfile); - free(lockfile); - return 1; - } - } else { - printf("Another %s is already running, pid=%u\n", name, oldpid); - unlink(tempfile); - free(tempfile); - free(lockfile); - return 1; - } - } -} - - - -void ulockprog(char *name) -{ - char *lockfile; - pid_t oldpid; - FILE *fp; - - lockfile = calloc(PATH_MAX, sizeof(char)); - snprintf(lockfile, PATH_MAX, "/var/run/%s.pid", name); - - if ((fp = fopen(lockfile, "r")) == NULL) { - syslog(LOG_NOTICE, "Can't open lockfile \"%s\"", lockfile); - free(lockfile); - return; - } - - if (fscanf(fp, "%u", &oldpid) != 1) { - syslog(LOG_NOTICE, "Can't read old pid from \"%s\"", lockfile); - fclose(fp); - unlink(lockfile); - free(lockfile); - return; - } - - fclose(fp); - - if (oldpid == getpid()) { - (void)unlink(lockfile); - } - - free(lockfile); -} - - diff -r 8b5e8f1e172d -r a03b6dac5398 lib/logger.c --- a/lib/logger.c Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/***************************************************************************** - * Copyright (C) 2014 - * - * Michiel Broek - * - * 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 "../config.h" -#include "mbselib.h" - -void logger(char *filename, char *progname, char *data) -{ - struct timeval now; - struct tm ptm; - char *outstr = NULL, *name = NULL; - FILE *logfile; - - name = xstrcpy((char *)"/var/local/log/"); - name = xstrcat(name, progname); - name = xstrcat(name, (char *)"/"); - name = xstrcat(name, filename); - - gettimeofday(&now, NULL); - localtime_r(&now.tv_sec, &ptm); - - if ((logfile = fopen(name, "a+"))) { - outstr = calloc(10240, sizeof(char)); - snprintf(outstr, 10239, "%04d-%02d-%02d %02d:%02d,%s\n", ptm.tm_year + 1900, ptm.tm_mon + 1, ptm.tm_mday, ptm.tm_hour, ptm.tm_min, data); - fprintf(logfile, outstr); - fclose(logfile); - free(outstr); - outstr = NULL; - } else { - syslog(LOG_NOTICE, "logger: cannot open %s for writing", name); - } - - free(name); - name = NULL; -} - - diff -r 8b5e8f1e172d -r a03b6dac5398 lib/mbselib.h --- a/lib/mbselib.h Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,160 +0,0 @@ -#ifndef _MBSELIB_H -#define _MBSELIB_H - -#include "../config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* mosquitto */ -#include - -#ifdef HAVE_WIRINGPI_H -/* wiringPi */ -#include -#include -#include - -#endif - -#define TRUE 1 -#define FALSE 0 - -#define MBSE_SS(x) (x)?(x):"(null)" - -/* rdconfig.c */ -typedef struct _key_list { - char *key; - int (*prc)(char **); - char **dest; -} key_list; - -typedef struct _w1_therm { - struct _w1_therm *next; - char *master; /* Master for this device */ - int bus; /* Reserved for ds2482-800 */ - char *name; /* Name of this device */ - char *alias; /* Friendly name */ - int present; /* 1=present, 0=absent */ - int lastval; /* Last valid value */ - int update; /* Value updated */ -} w1_therm; - -typedef struct _rc_switch { - struct _rc_switch *next; - char *address; /* Address code */ - char *alias; /* Friendly name */ -} rc_switch; - -typedef struct _sys_config { - char *name; /* Configuration name */ - char *mosq_host; /* mosquitto server hostname */ - int mosq_port; /* mosquitto server port */ - int my_port; /* my client/server port */ - w1_therm *w1therms; /* 1-wire temp sensors */ -#ifdef HAVE_WIRINGPI_H - int lcd_cols; /* LCD display columns */ - int lcd_rows; /* LCD display rows */ - int rx433; /* 433 MHz receiver pin */ - int tx433; /* 433 MHz transmitter pin */ - rc_switch *rcswitch; /* 433 MHz RC Power switches */ -#endif -} sys_config; - - -void killconfig(void); -int rdconfig(char *); - - -/* lock.c */ -int lockprog(char *); -void ulockprog(char *); - - -/* xutil.c */ -char *xmalloc(size_t); -char *xstrcpy(char *); -char *xstrcat(char *, char *); - - -#ifdef HAVE_WIRINGPI_H - -/* lcd-pcf8574.c */ -// Defines for the pcf8574 Pi LCD interface board -#define AF_BASE 100 - -#define AF_RS (AF_BASE + 0) -#define AF_RW (AF_BASE + 1) -#define AF_E (AF_BASE + 2) -#define AF_BACKLIGHT (AF_BASE + 3) -#define AF_DB4 (AF_BASE + 4) -#define AF_DB5 (AF_BASE + 5) -#define AF_DB6 (AF_BASE + 6) -#define AF_DB7 (AF_BASE + 7) - -void setBacklight (int); -int initLCD (int, int); -void mb_lcdPutchar(const int, unsigned char); -void mb_lcdPuts(const int, const char *); -void mb_lcdClear(const int); - - -/* logger.c */ -void logger(char *, char *, char *); - - -/* rc-switch.c */ -int toggleSwitch(char *); -int toggleTypeA(char *, char *, bool); -int toggleTypeB(int, int, bool); -int toggleTypeC(char, int, int, bool); -int toggleTypeE(char, int, bool); - -void enableReceiveIRQ(int interrupt); -void enableReceive(void); -void disableReceive(void); -bool available(void); -void resetAvailable(void); - -unsigned long getReceivedValue(void); -unsigned int getReceivedBitlength(void); -unsigned int getReceivedDelay(void); -unsigned int getReceivedProtocol(void); -unsigned int *getReceivedRawdata(void); - -void enableTransmit(int); -void disableTransmit(void); - -char *dec2binWzerofill(unsigned long, unsigned int); - - -/* dht11.c */ -void dht11Read(void); -void dht11Init(int, int, int); - - -#endif - - -#endif - diff -r 8b5e8f1e172d -r a03b6dac5398 lib/rc-switch.c --- a/lib/rc-switch.c Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,956 +0,0 @@ -/***************************************************************************** - * Copyright (C) 2014 - * - * Michiel Broek - * - * This file is part of the mbsePi-apps - * - * Based on the Arduino libary for remote control outlet switches. - * Project home: http://code.google.com/p/rc-switch/ - * - * 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 "../config.h" -#include "mbselib.h" - -#ifdef HAVE_WIRINGPI_H - - -#define TYPE_UNDEF 0 -#define TYPE_MINIMUM 0 -#define TYPE_A 1 -#define TYPE_B 2 -#define TYPE_C 3 -#define TYPE_D 4 -#define TYPE_E 3 // TODO: Which Protocol does REV use? -#define TYPE_MAXIMUM 4 - -// Number of maximum High/Low changes per packet. -// We can handle up to (unsigned long) => 32 bit * 2 H/L changes per bit + 2 for sync -#define RCSWITCH_MAX_CHANGES 67 - -// i.e. ProtocolCount + 1 (for TYPE_UNDEF) -#define MAX_PROTOCOLS 5 - -#define PROTOCOL_A_SYNC_FACTOR 31 -#define PROTOCOL_A_ZERO_FIRST_CYCLES 1 -#define PROTOCOL_A_ZERO_SECOND_CYCLES 3 -#define PROTOCOL_A_ONE_FIRST_CYCLES 3 -#define PROTOCOL_A_ONE_SECOND_CYCLES 1 -#define PROTOCOL_A_HIGH_FIRST true - -#define PROTOCOL_B_SYNC_FACTOR 10 -#define PROTOCOL_B_ZERO_FIRST_CYCLES 1 -#define PROTOCOL_B_ZERO_SECOND_CYCLES 2 -#define PROTOCOL_B_ONE_FIRST_CYCLES 2 -#define PROTOCOL_B_ONE_SECOND_CYCLES 1 -#define PROTOCOL_B_HIGH_FIRST true - -#define PROTOCOL_C_SYNC_FACTOR 71 -#define PROTOCOL_C_ZERO_FIRST_CYCLES 4 -#define PROTOCOL_C_ZERO_SECOND_CYCLES 11 -#define PROTOCOL_C_ONE_FIRST_CYCLES 9 -#define PROTOCOL_C_ONE_SECOND_CYCLES 6 -#define PROTOCOL_C_HIGH_FIRST true - -// I think, this will work for receive, however, I haven't tested, as I don't own a receiver... -// As Type D doesn't sync acc. to https://github.com/d-a-n/433-codes/blob/master/database.md#quigg -// the sync factor is totally undetermined. -// Malte Diers, 22.11.2013 -#define PROTOCOL_D_SYNC_FACTOR 1 -#define PROTOCOL_D_ZERO_FIRST_CYCLES 1 -#define PROTOCOL_D_ZERO_SECOND_CYCLES 2 -#define PROTOCOL_D_ONE_FIRST_CYCLES 2 -#define PROTOCOL_D_ONE_SECOND_CYCLES 1 -#define PROTOCOL_D_HIGH_FIRST false - - -#define PROTOCOL3_SYNC_FACTOR 71 -#define PROTOCOL3_0_HIGH_CYCLES 4 -#define PROTOCOL3_0_LOW_CYCLES 11 -#define PROTOCOL3_1_HIGH_CYCLES 9 -#define PROTOCOL3_1_LOW_CYCLES 6 - - - -unsigned long rcReceivedValue = 0; -unsigned int rcReceivedBitlength = 0; -unsigned int rcReceivedDelay = 0; -unsigned int rcReceivedProtocol = 0; -int rcReceiveTolerance = 60; -int rcReceiverInterruptPin = -1; - -unsigned int timings[RCSWITCH_MAX_CHANGES]; -int rcTransmitterPin = -1; -int rcPulseLength = 350; // thermometers 2.4 msec = 2400 -int rcRepeatTransmit = 10; -int rcProtocol = 1; - -int backupProtocol; -int backupPulseLength; -int backupRepeatTransmit; - - -//const char TYPE_A_CODE[ 6][6] = { "00000", "10000", "01000", "00100", "00010", "00001"}; -const char TYPE_B_CODE[ 5][5] = { "FFFF", "0FFF", "F0FF", "FF0F", "FFF0" }; -const char TYPE_C_CODE[16][5] = { "0000", "F000", "0F00", "FF00", "00F0", "F0F0", "0FF0", "FFF0", - "000F", "F00F", "0F0F", "FF0F", "00FF", "F0FF", "0FFF", "FFFF" }; -const char TYPE_D_CODE[5][2][9] = { { "11100001", "11110000" }, { "00000000", "00010001" }, { "10000010", "10010011" }, - { "11000011", "11010010" }, { "01000001", "01010000" } }; - /* Type A Type D */ -const int PULSE_LENGTH[MAX_PROTOCOLS] = { 0, 350, 650, 100, 666, }; -const int REPEAT_TRANSMIT[MAX_PROTOCOLS] = { 0, 10, 10, 10, 4, }; -const int SYNC_FACTOR[MAX_PROTOCOLS] = { 0, PROTOCOL_A_SYNC_FACTOR, PROTOCOL_B_SYNC_FACTOR, PROTOCOL_C_SYNC_FACTOR, PROTOCOL_D_SYNC_FACTOR, }; -const int ZERO_FIRST_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ZERO_FIRST_CYCLES, PROTOCOL_B_ZERO_FIRST_CYCLES, PROTOCOL_C_ZERO_FIRST_CYCLES, PROTOCOL_D_ZERO_FIRST_CYCLES, }; -const int ZERO_SECOND_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ZERO_SECOND_CYCLES, PROTOCOL_B_ZERO_SECOND_CYCLES, PROTOCOL_C_ZERO_SECOND_CYCLES, PROTOCOL_D_ZERO_SECOND_CYCLES, }; -const int ONE_FIRST_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ONE_FIRST_CYCLES, PROTOCOL_B_ONE_FIRST_CYCLES, PROTOCOL_C_ONE_FIRST_CYCLES, PROTOCOL_D_ONE_FIRST_CYCLES, }; -const int ONE_SECOND_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ONE_SECOND_CYCLES, PROTOCOL_B_ONE_SECOND_CYCLES, PROTOCOL_C_ONE_SECOND_CYCLES, PROTOCOL_D_ONE_SECOND_CYCLES, }; -const bool HIGH_FIRST[MAX_PROTOCOLS] = { 0, PROTOCOL_A_HIGH_FIRST, PROTOCOL_B_HIGH_FIRST, PROTOCOL_C_HIGH_FIRST, PROTOCOL_D_HIGH_FIRST, }; - - -char *getCodeWordA(char*, char*, bool); -char *getCodeWordB(int, int, bool); -char *getCodeWordC(char, int, int, bool); - -char *getCodeWordE(char, int, bool); -void sendTriState(char*); -void transmit(int, int, bool); -void send0(void); -void send1(void); -void sendT0(void); -void sendT1(void); -void sendTF(void); -void sendSync(void); -bool receiveProtocol(int, unsigned int); -void handleInterrupt(void); -char *dec2binWcharfill(unsigned long, unsigned int, char); - -void setReceiveTolerance(int); -void setProtocol(int); - -void saveProtocol(int); -void loadProtocol(void); - - - -/* - * Sets the protocol to send. - */ -void setProtocol(int nProtocol) { - - if ((nProtocol < TYPE_MINIMUM) || (nProtocol > TYPE_MAXIMUM)) { - return; - } - - rcProtocol = nProtocol; - rcPulseLength = PULSE_LENGTH[nProtocol]; - rcRepeatTransmit = REPEAT_TRANSMIT[nProtocol]; -} - - - -/* - * Set Receiving Tolerance - */ -void setReceiveTolerance(int nPercent) { - rcReceiveTolerance = nPercent; -} - - - -/* - * Enable transmissions - * - * @param nTransmitterPin Pin to which the sender is connected to - */ -void enableTransmit(int nTransmitterPin) { - rcTransmitterPin = nTransmitterPin; - pinMode(rcTransmitterPin, OUTPUT); -} - - - -/* - * Disable transmissions - */ -void disableTransmit(void) { - rcTransmitterPin = -1; -} - - - -/* - * Toggle switch, a command looks like B,3,2,1 which means switch type B, - * group 3, device 2, status on. - */ -int toggleSwitch(char *command) -{ - static char *cmd = NULL; - char *s, cType; - int rc, iGroup, iDevice, iState; - - cmd = xstrcpy(command); - s = strtok(cmd, ",\0"); - cType = s[0]; - - if (cType == 'A') { - - } else if (cType == 'B') { - s = strtok(NULL, ",\0"); - rc = sscanf(s, "%d", &iGroup); - if (rc != 1) - return 1; - s = strtok(NULL, ",\0"); - rc = sscanf(s, "%d", &iDevice); - if (rc != 1) - return 1; - s = strtok(NULL, ",\0"); - rc = sscanf(s, "%d", &iState); - if (rc != 1) - return 1; - free(cmd); - return toggleTypeB(iGroup, iDevice, iState); - } - - free(cmd); - return 1; -} - - - -/* - * Switch a remote switch on (Type E REV) - * - * @param sGroup Code of the switch group (A,B,C,D) - * @param nDevice Number of the switch itself (1..3) - * @param bStatus Status to toggle to - */ -int toggleTypeE(char sGroup, int nDevice, bool bStatus) { - sendTriState( getCodeWordE(sGroup, nDevice, bStatus) ); - return 0; -} - - - -/* - * Switch a remote switch on (Type C Intertechno) - * - * @param sFamily Familycode (a..f) - * @param nGroup Number of group (1..4) - * @param nDevice Number of device (1..4) - * @param bStatus Status to toggle to - */ -int toggleTypeC(char sFamily, int nGroup, int nDevice, bool bStatus) { - char *str = xstrcpy(getCodeWordC(sFamily, nGroup, nDevice, bStatus)); - - if (strlen(str) == 0) - return 1; - - saveProtocol(TYPE_A); // ??? - sendTriState( str ); - loadProtocol(); - free(str); - return 0; -} - - - -/* - * Switch a remote switch on/off (Type B with two rotary/sliding switches) - * - * @param iGroup Number of the switch group (1..4) - * @param iDevice Number of the switch itself (1..4) - * @param bStatus Status to toggle to - */ -int toggleTypeB(int iGroup, int iDevice, bool bStatus) -{ - char *str = xstrcpy(getCodeWordB(iGroup, iDevice, bStatus)); - - if (strlen(str) == 0) - return 1; - - saveProtocol(TYPE_A); // They do better with protocol A timings. - sendTriState( str ); - loadProtocol(); - free(str); - return 0; -} - - - -/* - * Switch a remote switch on (Type A with 10 pole DIP switches) - * - * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111") - * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111") - * @param bStatus Status to toggle to - */ -int toggleTypeA(char* sGroup, char* sDevice, bool bStatus) { - char *str = xstrcpy(getCodeWordA(sGroup, sDevice, bStatus)); - - if (strlen(str) == 0) - return 1; - - saveProtocol(TYPE_A); - sendTriState( str ); - loadProtocol(); - free(str); - return 0; -} - - - -/* - * Returns a char[13], representing the Code Word to be send. - * A Code Word consists of 9 address bits, 3 data bits and one sync bit but in our case only the first 8 address bits and the last 2 data bits were used. - * A Code Bit can have 4 different states: "F" (floating), "0" (low), "1" (high), "S" (synchronous bit) - * - * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ - * | 4 bits address (switch group) | 4 bits address (switch number) | 1 bit address (not used, so never mind) | 1 bit address (not used, so never mind) | 2 data bits (on|off) | 1 sync bit | - * | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | F | F | on=FF off=F0 | S | - * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ - * - * @param nAddressCode Number of the switch group (1..4) - * @param nChannelCode Number of the switch itself (1..4) - * @param bStatus Wether to switch on (true) or off (false) - * - * @return char[13] - */ -char *getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus) -{ - int i, nReturnPos = 0; - static char sReturn[13]; - - if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) { - return '\0'; - } - for (i = 0; i<4; i++) { - sReturn[nReturnPos++] = TYPE_B_CODE[nAddressCode][i]; - } - - for (i = 0; i<4; i++) { - sReturn[nReturnPos++] = TYPE_B_CODE[nChannelCode][i]; - } - - sReturn[nReturnPos++] = 'F'; - sReturn[nReturnPos++] = 'F'; - sReturn[nReturnPos++] = 'F'; - sReturn[nReturnPos++] = bStatus ? 'F' : '0'; - sReturn[nReturnPos] = '\0'; - - return sReturn; -} - - - -/* - * Returns a char[13], representing the Code Word to be send. - * - * getCodeWordA(char*, char*) - * - */ -char *getCodeWordA(char* sGroup, char* sDevice, bool bOn) -{ - static char sDipSwitches[13]; - int i, j = 0; - - for (i=0; i < 5; i++) { - sDipSwitches[j++] = (sGroup[i] == '0') ? 'F' : '0'; - } - - for (i=0; i < 5; i++) { - sDipSwitches[j++] = (sDevice[i] == '0') ? 'F' : '0'; - } - - if ( bOn ) { - sDipSwitches[j++] = '0'; - sDipSwitches[j++] = 'F'; - } else { - sDipSwitches[j++] = 'F'; - sDipSwitches[j++] = '0'; - } - - sDipSwitches[j] = '\0'; - return sDipSwitches; -} - - - -/* - * Like getCodeWord (Type C = Intertechno) - */ -char *getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus) -{ - static char sReturn[13]; - int i, nReturnPos = 0; - - if (sFamily < 'a') { - // To also enable capital 'A' to 'F' - sFamily += 32; - } - - if ( sFamily < 'a' || sFamily > 'f' || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) { - return '\0'; - } - - for (i = 0; i<4; i++) { - sReturn[nReturnPos++] = TYPE_C_CODE[ sFamily - 'a' ][i]; - } - - char *sDeviceGroupCode = dec2binWzerofill( (nDevice-1) + (nGroup-1)*4, 4 ); - for (i = 0; i<4; i++) { - sReturn[nReturnPos++] = (sDeviceGroupCode[3-i] == '1' ? 'F' : '0'); - } - - sReturn[nReturnPos++] = '0'; - sReturn[nReturnPos++] = 'F'; - sReturn[nReturnPos++] = 'F'; - sReturn[nReturnPos++] = bStatus ? 'F' : '0'; - sReturn[nReturnPos] = '\0'; - - return sReturn; -} - - - -/* - * Decoding for the Quigg Switch Type - * - * Returns a char[22], representing the States to be send. - * A Code Word consists of 1 start bit, 12 address bits and 8 command data bits. - * A Code Bit can have 2 different states: "0" (low), "1" (high) - * - * +--------------+--------------------------------+------------------------------+ - * | 1 bits start | 12 bits address (device group) | 8 bits (command/switch data) | - * | 1 | 110011001100 | 00010001 | - * +--------------+--------------------------------+------------------------------+ - * - * Source: https://github.com/d-a-n/433-codes/blob/master/database.md#quigg - * - * @param sGroup 12-bit Binary ID of the Device Group - * @param nDevice Number of the switch itself (1..4, or 0 to switch the entire Group) - * @param bStatus Wether to switch on (true) or off (false) - * - * @return char[22] - */ -char *getCodeWordD(char *sGroup, int nDevice, bool bStatus) -{ - static char sReturn[22]; - int i, nReturnPos = 0; - - /* Startbit */ - sReturn[nReturnPos++] = '1'; - - /* 12 bit Group */ - for (i = 0; i < 12; ++i) { - sReturn[nReturnPos++] = sGroup[i]; - } - - /* 8 Bit Device Identifier + Status (undividable!) */ - for (i = 0; i < 8; ++i) { - sReturn[nReturnPos++] = TYPE_D_CODE[nDevice][bStatus][i]; - } - sReturn[nReturnPos] = 0; - - return sReturn; -} - - - -/* - * Decoding for the REV Switch Type - * - * Returns a char[13], representing the Tristate to be send. - * A Code Word consists of 7 address bits and 5 command data bits. - * A Code Bit can have 3 different states: "F" (floating), "0" (low), "1" (high) - * - * +-------------------------------+--------------------------------+-----------------------+ - * | 4 bits address (switch group) | 3 bits address (device number) | 5 bits (command data) | - * | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | on=00010 off=00001 | - * +-------------------------------+--------------------------------+-----------------------+ - * - * Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/ - * - * @param sGroup Name of the switch group (A..D, resp. a..d) - * @param nDevice Number of the switch itself (1..3) - * @param bStatus Wether to switch on (true) or off (false) - * - * @return char[13] - */ -char *getCodeWordE(char sGroup, int nDevice, bool bStatus){ - static char sReturn[13]; - int i, nReturnPos = 0; - - // Building 4 bits address - // (Potential problem if dec2binWcharfill not returning correct string) - char *sGroupCode; - switch(sGroup){ - case 'a': - case 'A': - sGroupCode = dec2binWcharfill(8, 4, 'F'); break; - case 'b': - case 'B': - sGroupCode = dec2binWcharfill(4, 4, 'F'); break; - case 'c': - case 'C': - sGroupCode = dec2binWcharfill(2, 4, 'F'); break; - case 'd': - case 'D': - sGroupCode = dec2binWcharfill(1, 4, 'F'); break; - default: - return '\0'; - } - - for (i = 0; i<4; i++) { - sReturn[nReturnPos++] = sGroupCode[i]; - } - - - // Building 3 bits address - // (Potential problem if dec2binWcharfill not returning correct string) - char *sDevice; - switch(nDevice) { - case 1: - sDevice = dec2binWcharfill(4, 3, 'F'); break; - case 2: - sDevice = dec2binWcharfill(2, 3, 'F'); break; - case 3: - sDevice = dec2binWcharfill(1, 3, 'F'); break; - default: - return '\0'; - } - - for (i = 0; i<3; i++) - sReturn[nReturnPos++] = sDevice[i]; - - // fill up rest with zeros - for (i = 0; i<5; i++) - sReturn[nReturnPos++] = '0'; - - // encode on or off - if (bStatus) - sReturn[10] = '1'; - else - sReturn[11] = '1'; - - // last position terminate string - sReturn[12] = '\0'; - return sReturn; - -} - - - -/* - * @param sCodeWord /^[10FS]*$/ -> see getCodeWord - */ -void sendTriState(char* sCodeWord) { - int nRepeat; - - for (nRepeat = 0; nRepeat < rcRepeatTransmit; nRepeat++) { - int i = 0; - while (sCodeWord[i] != '\0') { - switch(sCodeWord[i]) { - case '0': - sendT0(); - break; - case 'F': - sendTF(); - break; - case '1': - sendT1(); - break; - } - i++; - } - sendSync(); - } -} - - - -/* -void RCSwitch::send(unsigned long Code, unsigned int length) { - this->send( this->dec2binWzerofill(Code, length) ); -} - -void RCSwitch::send(char* sCodeWord) { - for (int nRepeat=0; nRepeatsend0(); - break; - case '1': - this->send1(); - break; - } - i++; - } - this->sendSync(); - } -} -*/ - - -void transmit(int nFirstPulses, int nSecondPulses, bool bHighFirst) -{ - bool disabled_Receive = false; - int nReceiverInterrupt_backup = rcReceiverInterruptPin; - - if (rcTransmitterPin != -1) { - if (rcReceiverInterruptPin != -1) { - disableReceive(); - disabled_Receive = true; - } - digitalWrite(rcTransmitterPin, bHighFirst ? HIGH : LOW); - delayMicroseconds( rcPulseLength * nFirstPulses); - digitalWrite(rcTransmitterPin, bHighFirst ? LOW : HIGH); - delayMicroseconds( rcPulseLength * nSecondPulses); - - if (disabled_Receive) { - enableReceiveIRQ(nReceiverInterrupt_backup); - } - } -} - - - -/* - * Sends a "0" Bit - * _ - * Waveform Protocol 1: | |___ - * _ - * Waveform Protocol 2: | |__ - * ____ - * Waveform Protocol 3: | |___________ - */ -//void send0(void) { -// if (rcProtocol == 1){ -// transmit(1,3); -// } -// else if (rcProtocol == 2) { -// transmit(1,2); -// } -// else if (rcProtocol == 3) { -// transmit(4,11); -// } -//} - - - -/* - * Sends a "1" Bit - * ___ - * Waveform Protocol 1: | |_ - * __ - * Waveform Protocol 2: | |_ - * _________ - * Waveform Protocol 3: | |______ - */ -//void send1(void) { -// if (rcProtocol == 1){ -// transmit(3,1); -// } -// else if (rcProtocol == 2) { -// transmit(2,1); -// } -// else if (rcProtocol == 3) { -// transmit(9,6); -// } -//} - - - -/* - * Sends a Tri-State "0" Bit - * _ _ - * Waveform: | |___| |___ - */ -void sendT0(void) { - transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); - transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); -// transmit(1,3,true); -// transmit(1,3,true); -} - - - -/* - * Sends a Tri-State "1" Bit - * ___ ___ - * Waveform: | |_| |_ - */ -void sendT1(void) { - transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); - transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); -// transmit(3,1,true); -// transmit(3,1,true); -} - - - -/* - * Sends a Tri-State "F" Bit - * _ ___ - * Waveform: | |___| |_ - */ -void sendTF(void) { - transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); - transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); -// transmit(1,3,true); -// transmit(3,1,true); -} - - - -/* - * Sends a "Sync" Bit - * _ - * Waveform Protocol 1: | |_______________________________ - * _ - * Waveform Protocol 2: | |__________ - * ____ - * Waveform Protocol 3: | |_______________________________________________________________________ - * - * Waveform Protocol D: (none, just pause 80 msecs) - */ -void sendSync(void) { - - if (rcProtocol == TYPE_A) { - transmit(1,31,true); - } else if (rcProtocol == TYPE_B) { - transmit(1,10,true); - } else if (rcProtocol == TYPE_C) { - transmit(4,71,true); - } else if (rcProtocol == TYPE_D) { - transmit(0,1,false); - delayMicroseconds(80000); - } -} - - - -/* - * Enable receiving data - */ -void enableReceiveIRQ(int Pin) { - rcReceiverInterruptPin = Pin; - enableReceive(); -} - -void enableReceive(void) { - if (rcReceiverInterruptPin != -1) { - rcReceivedValue = 0; - rcReceivedBitlength = 0; - wiringPiISR(rcReceiverInterruptPin, INT_EDGE_BOTH, &handleInterrupt); - } -} - - - -/* - * Disable receiving data - */ -void disableReceive() { - // wiringPi disable interrupts ??? - rcReceiverInterruptPin = -1; -} - - - -bool available(void) { - return rcReceivedValue != 0; -} - - - -void resetAvailable(void) { - rcReceivedValue = 0; -} - - - -unsigned long getReceivedValue(void) { - return rcReceivedValue; -} - - - -unsigned int getReceivedBitlength(void) { - return rcReceivedBitlength; -} - - - -unsigned int getReceivedDelay(void) { - return rcReceivedDelay; -} - - - -unsigned int getReceivedProtocol(void) { - return rcReceivedProtocol; -} - - - -unsigned int* getReceivedRawdata(void) { - return timings; -} - - - -/* - * ASK protool 1 - */ -bool receiveProtocol(int prot, unsigned int changeCount) -{ - unsigned long code = 0; - unsigned long ldelay = timings[0] / SYNC_FACTOR[prot]; - unsigned long delayTolerance = ldelay * rcReceiveTolerance * 0.01; - int i; - - if (prot < TYPE_MINIMUM || prot > TYPE_MAXIMUM) { - return false; - } - - for (i = 1; i ldelay * ZERO_FIRST_CYCLES[prot] - delayTolerance && - timings[i] < ldelay * ZERO_FIRST_CYCLES[prot] + delayTolerance && - timings[i+1] > ldelay * ZERO_SECOND_CYCLES[prot] - delayTolerance && - timings[i+1] < ldelay * ZERO_SECOND_CYCLES[prot] + delayTolerance) { - code = code << 1; - } else if (timings[i] > ldelay * ONE_FIRST_CYCLES[prot] - delayTolerance && - timings[i] < ldelay * ONE_FIRST_CYCLES[prot] + delayTolerance && - timings[i+1] > ldelay * ONE_SECOND_CYCLES[prot] - delayTolerance && - timings[i+1] < ldelay * ONE_SECOND_CYCLES[prot] + delayTolerance) { - code+=1; - code = code << 1; - } else { - // Failed - i = changeCount; - code = 0; - } - } - code = code >> 1; - if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise - rcReceivedValue = code; - rcReceivedBitlength = changeCount / 2; - rcReceivedDelay = ldelay; - rcReceivedProtocol = prot; - } - - return (code != 0); -} - - - -void handleInterrupt() { - - static unsigned int duration; - static unsigned int changeCount; - static unsigned long lastTime; - static unsigned int repeatCount; - - - long thistime = micros(); - duration = thistime - lastTime; - - if (duration > 5000 && duration > timings[0] - 200 && duration < timings[0] + 200) { - repeatCount++; - changeCount--; - if (repeatCount == 2) { - if (receiveProtocol(TYPE_A, changeCount) == false) { - if (receiveProtocol(TYPE_B, changeCount) == false) { - if (receiveProtocol(TYPE_C, changeCount) == false) { - if (receiveProtocol(TYPE_D, changeCount) == false) { - //failed - } - } - } - } - repeatCount = 0; - } - changeCount = 0; - } else if (duration > 5000) { - changeCount = 0; - } - - if (changeCount >= RCSWITCH_MAX_CHANGES) { - changeCount = 0; - repeatCount = 0; - } - timings[changeCount++] = duration; - lastTime = thistime; -} - - - -/* - * Turns a decimal value to its binary representation - */ -char *dec2binWzerofill(unsigned long Dec, unsigned int bitLength) -{ - return dec2binWcharfill(Dec, bitLength, '0'); -} - -char *dec2binWcharfill(unsigned long Dec, unsigned int bitLength, char fill) -{ - static char bin[64]; - unsigned int i = 0, j; - - while (Dec > 0) { - bin[32+i++] = ((Dec & 1) > 0) ? '1' : fill; - Dec = Dec >> 1; - } - - for (j = 0; j< bitLength; j++) { - if (j >= bitLength - i) { - bin[j] = bin[ 31 + i - (j - (bitLength - i)) ]; - } else { - bin[j] = fill; - } - } - bin[bitLength] = '\0'; - - return bin; -} - - -void saveProtocol(int prot) -{ - backupProtocol = rcProtocol; - backupPulseLength = rcPulseLength; - backupRepeatTransmit = rcRepeatTransmit; - - setProtocol(prot); -} - - - -void loadProtocol(void) -{ - rcProtocol = backupProtocol; - rcPulseLength = backupPulseLength; - rcRepeatTransmit = backupRepeatTransmit; -} - - -#endif - diff -r 8b5e8f1e172d -r a03b6dac5398 lib/rdconfig.c --- a/lib/rdconfig.c Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,351 +0,0 @@ -/***************************************************************************** - * Copyright (C) 2014 - * - * Michiel Broek - * - * 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 "../config.h" -#include "mbselib.h" - - -bool debug = FALSE; -static char *mypath; -static char *k, *v; -static int linecnt = 0; -sys_config Config; /* System configuration */ - - - -static int getstr(char **); -static int getint(char **); -static int getw1(char **); -#ifdef HAVE_WIRINGPI_H -static int getrcs(char **); -#endif -//static int getbyt(char **); -//static int gethex(char **); - -#define XSTR(x) #x -#define STR(x) XSTR(x) - -/* - * System configuration table - */ -key_list keytab[] = { - {(char *)"mosq_host", getstr, &Config.mosq_host}, - {(char *)"mosq_port", getint, (char **)&Config.mosq_port}, - {(char *)"w1therm", getw1, (char **)&Config.w1therms}, -#ifdef HAVE_WIRINGPI_H - {(char *)"lcd_cols", getint, (char **)&Config.lcd_cols}, - {(char *)"lcd_rows", getint, (char **)&Config.lcd_rows}, - {(char *)"rx433", getint, (char **)&Config.rx433}, - {(char *)"tx433", getint, (char **)&Config.tx433}, - {(char *)"rcswitch", getrcs, (char **)&Config.rcswitch}, -#endif - {NULL, NULL, NULL} -}; - - - -void killconfig(void) -{ - w1_therm *tmp1, *old1; -#ifdef HAVE_WIRINGPI_H - rc_switch *tmp2, *old2; -#endif - - if (Config.name) - free(Config.name); - Config.name = NULL; - - if (Config.mosq_host) - free(Config.mosq_host); - Config.mosq_host= (char *)"localhost"; - Config.mosq_port = 1883; - - for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { - old1 = tmp1->next; - if (tmp1->master) - free(tmp1->master); - if (tmp1->name) - free(tmp1->name); - if (tmp1->alias) - free(tmp1->alias); - free(tmp1); - } - Config.w1therms = NULL; - Config.my_port = 6554; - -#ifdef HAVE_WIRINGPI_H - Config.lcd_cols = 16; - Config.lcd_rows = 2; - Config.rx433 = -1; - Config.tx433 = -1; - - for (tmp2 = Config.rcswitch; tmp2; tmp2 = old2) { - old2 = tmp2->next; - if (tmp2->address) - free(tmp2->address); - tmp2->address = NULL; - if (tmp2->alias) - free(tmp2->alias); - tmp2->alias = NULL; - free(tmp2); - } - Config.rcswitch = NULL; - -#endif -} - - - -int rdconfig(char *config) -{ - char buf[256], *p; - FILE *fp; - int i, rc = 0; - - killconfig(); - - /* - * Search config file - */ - mypath = xstrcpy(getenv((char *)"HOME")); - mypath = xstrcat(mypath, (char *)"/mbsepi-apps/"); - mypath = xstrcat(mypath, config); - 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) { - /* - * 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 not open %s", mypath); - return 1; - } - } - } - - linecnt = 0; - while (fgets(buf, sizeof(buf) -1, fp)) { - linecnt++; - if (*(p = buf + strlen(buf) -1) != '\n') { - syslog(LOG_NOTICE, "rdconfig: %s(%d): \"%s\" - line too long", mypath, linecnt, buf); - rc = 1; - break; - } - *p-- = '\0'; - while ((p >= buf) && isspace(*p)) - *p-- = '\0'; - k = buf; - while (*k && isspace(*k)) - k++; - p = k; - while (*p && !isspace(*p)) - p++; - *p++='\0'; - v = p; - while (*v && isspace(*v)) - v++; - - if ((*k == '\0') || (*k == '#')) { - continue; - } - - for (i = 0; keytab[i].key; i++) - if (strcasecmp(k,keytab[i].key) == 0) - break; - - if (keytab[i].key == NULL) { - syslog(LOG_NOTICE, "rdconfig: %s(%d): %s %s - unknown keyword", mypath, linecnt, MBSE_SS(k), MBSE_SS(v)); - rc = 1; - break; - } else if ((keytab[i].prc(keytab[i].dest))) { - rc = 1; - break; - } - - } - fclose(fp); - - free(mypath); - mypath = NULL; - - return rc; -} - - - -static int getstr(char **dest) -{ - if (debug) - syslog(LOG_NOTICE, "rdconfig: getstr: %s(%d): %s %s", mypath, linecnt, MBSE_SS(k), MBSE_SS(v)); - - *dest = xstrcpy(v); - return 0; -} - - - -static int getint(char **dest) -{ - if (debug) - syslog(LOG_NOTICE, "rdconfig: getint: %s(%d): %s %s", mypath, linecnt, MBSE_SS(k), MBSE_SS(v)); - - if (strspn(v,"0123456789") != strlen(v)) - syslog(LOG_NOTICE, "rdconfig: %s(%d): %s %s - bad numeric", mypath, linecnt, MBSE_SS(k), MBSE_SS(v)); - else - *((int*)dest)=atoi(v); - return 0; -} - - - -static int getw1(char **dest) -{ - char *p, *q = NULL, *r = NULL; - w1_therm **tmpm; - int rc = 0, tmpp; - - for (p = v; *p && !isspace(*p); p++); - if (*p) - *p++ = '\0'; - while (*p && isspace(*p)) - p++; - if (*p == '\0') { - syslog(LOG_NOTICE, "rdconfig: %s(%d): less then two tokens", mypath, linecnt); - return 1; - } - - for (q = p; *q && !isspace(*q); q++); - if (*q && isspace(*q)) { - if (*q) - *q++ = '\0'; - while (*q && isspace(*q)) - q++; - - for (r = q; *r && !isspace(*r); r++); - if (*r) - *r++ = '\0'; - rc = sscanf(p, "%d", &tmpp); - if (rc != 1) { - syslog(LOG_NOTICE, "rdconfig: getw1: %s(%d): %s is not a integer value", mypath, linecnt, p); - return 1; - } - if (debug) - syslog(LOG_NOTICE, "rdconfig: getw1: %s(%d): %s %d %s %s", mypath, linecnt, v, tmpp, q, r); - } - - for (tmpm = (w1_therm**)dest; *tmpm; tmpm=&((*tmpm)->next)); - (*tmpm) = (w1_therm *) xmalloc(sizeof(w1_therm)); - (*tmpm)->next = NULL; - (*tmpm)->master = xstrcpy(v); - (*tmpm)->bus = tmpp; - (*tmpm)->name = xstrcpy(q); - (*tmpm)->alias = xstrcpy(r); - (*tmpm)->present = 0; - (*tmpm)->lastval = 0; - (*tmpm)->update = 0; - - return 0; -} - - - -#ifdef HAVE_WIRINGPI_H -static int getrcs(char **dest) -{ - char *p, *q = NULL, *r = NULL; - rc_switch **tmpm; - - for (p = v; *p && !isspace(*p); p++); - if (*p) - *p++ = '\0'; - while (*p && isspace(*p)) - p++; - if (*p == '\0') { - syslog(LOG_NOTICE, "rdconfig: %s(%d): less then two tokens", mypath, linecnt); - return 1; - } - - for (q = p; *q && !isspace(*q); q++); - if (*q && isspace(*q)) { - if (*q) - *q++ = '\0'; - while (*q && isspace(*q)) - q++; - - for (r = q; *r && !isspace(*r); r++); - if (*r) - *r++ = '\0'; - if (debug) - syslog(LOG_NOTICE, "rdconfig: getrcs: %s(%d): %s %s", mypath, linecnt, v, p); - } - - for (tmpm = (rc_switch**)dest; *tmpm; tmpm=&((*tmpm)->next)); - (*tmpm) = (rc_switch *) xmalloc(sizeof(rc_switch)); - (*tmpm)->next = NULL; - (*tmpm)->address = xstrcpy(v); - (*tmpm)->alias = xstrcpy(p); - - return 0; -} -#endif - - -/* -static int getbyt(char **dest) -{ - Log_Msg("[rdconfig] getbyt: %s(%d): %s %s", mypath, linecnt, k, v); - if (strspn(v,"0123456789") != strlen(v)) - Log_Msg("[rdconfig] %s(%d): %s %s - bad numeric", mypath, linecnt, S(k), S(v)); - else - *((Uint8*)dest)=atoi(v); - return 0; -} -*/ - - -/* -static int gethex(char **dest) -{ - unsigned int val = 0; - int rc; - - Log_Msg("[rdconfig] gethex: %s(%d): %s %s", mypath, linecnt, k, v); - rc = sscanf(v, "%08x", &val); - if (rc != 1) { - Log_Msg("[rdconfig] %s(%d): %s %s - bad hex value", mypath, linecnt, S(k), S(v)); - return 1; - } - *((int*)dest) = val; - - return 0; -} -*/ - - diff -r 8b5e8f1e172d -r a03b6dac5398 lib/xutil.c --- a/lib/xutil.c Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/***************************************************************************** - * Copyright (C) 2008-2014 - * - * Michiel Broek - * - * 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 "../config.h" -#include "mbselib.h" - - -char *xmalloc(size_t size) -{ - char *tmp; - - tmp = malloc(size); - if (!tmp) - abort(); - - return tmp; -} - - - -char *xstrcpy(char *src) -{ - char *tmp; - - if (src == NULL) - return(NULL); - tmp = xmalloc(strlen(src)+1); - strcpy(tmp, src); - return tmp; -} - - - -char *xstrcat(char *src, char *add) -{ - char *tmp; - size_t size = 0; - - if ((add == NULL) || (strlen(add) == 0)) - return src; - if (src) - size = strlen(src); - size += strlen(add); - tmp = xmalloc(size + 1); - *tmp = '\0'; - if (src) { - strcpy(tmp, src); - free(src); - } - strcat(tmp, add); - return tmp; -} - - diff -r 8b5e8f1e172d -r a03b6dac5398 rc433/Makefile --- a/rc433/Makefile Sun May 25 16:39:54 2014 +0200 +++ b/rc433/Makefile Sun May 25 22:06:56 2014 +0200 @@ -2,10 +2,10 @@ include ../Makefile.global -SRCS = recv.c send.c sniffer.c -HDRS = recv.h send.h sniffer.h -OBJS = recv.o send.o sniffer.o -SLIBS = ../lib/libmbse.a +SRCS = $(wildcard *.c) +HDRS = $(wildcard *.h) +OBJS = $(SRCS:.c=.o) +SLIBS = rc-switch.o xutil.o TARGET = recv send sniffer OTHER = Makefile @@ -59,7 +59,9 @@ # DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT # Dependencies generated by make depend -recv.o: ../lib/mbselib.h recv.h -send.o: ../lib/mbselib.h send.h -sniffer.o: ../lib/mbselib.h sniffer.h +recv.o: rc433.h +send.o: rc433.h +sniffer.o: rc433.h +rc-switch.o: rc433.h +xutil.o: rc433.h # End of generated dependencies diff -r 8b5e8f1e172d -r a03b6dac5398 rc433/rc-switch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rc433/rc-switch.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,955 @@ +/***************************************************************************** + * Copyright (C) 2014 + * + * Michiel Broek + * + * This file is part of the mbsePi-apps + * + * Based on the Arduino libary for remote control outlet switches. + * Project home: http://code.google.com/p/rc-switch/ + * + * 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 "rc433.h" + +#ifdef HAVE_WIRINGPI_H + + +#define TYPE_UNDEF 0 +#define TYPE_MINIMUM 0 +#define TYPE_A 1 +#define TYPE_B 2 +#define TYPE_C 3 +#define TYPE_D 4 +#define TYPE_E 3 // TODO: Which Protocol does REV use? +#define TYPE_MAXIMUM 4 + +// Number of maximum High/Low changes per packet. +// We can handle up to (unsigned long) => 32 bit * 2 H/L changes per bit + 2 for sync +#define RCSWITCH_MAX_CHANGES 67 + +// i.e. ProtocolCount + 1 (for TYPE_UNDEF) +#define MAX_PROTOCOLS 5 + +#define PROTOCOL_A_SYNC_FACTOR 31 +#define PROTOCOL_A_ZERO_FIRST_CYCLES 1 +#define PROTOCOL_A_ZERO_SECOND_CYCLES 3 +#define PROTOCOL_A_ONE_FIRST_CYCLES 3 +#define PROTOCOL_A_ONE_SECOND_CYCLES 1 +#define PROTOCOL_A_HIGH_FIRST true + +#define PROTOCOL_B_SYNC_FACTOR 10 +#define PROTOCOL_B_ZERO_FIRST_CYCLES 1 +#define PROTOCOL_B_ZERO_SECOND_CYCLES 2 +#define PROTOCOL_B_ONE_FIRST_CYCLES 2 +#define PROTOCOL_B_ONE_SECOND_CYCLES 1 +#define PROTOCOL_B_HIGH_FIRST true + +#define PROTOCOL_C_SYNC_FACTOR 71 +#define PROTOCOL_C_ZERO_FIRST_CYCLES 4 +#define PROTOCOL_C_ZERO_SECOND_CYCLES 11 +#define PROTOCOL_C_ONE_FIRST_CYCLES 9 +#define PROTOCOL_C_ONE_SECOND_CYCLES 6 +#define PROTOCOL_C_HIGH_FIRST true + +// I think, this will work for receive, however, I haven't tested, as I don't own a receiver... +// As Type D doesn't sync acc. to https://github.com/d-a-n/433-codes/blob/master/database.md#quigg +// the sync factor is totally undetermined. +// Malte Diers, 22.11.2013 +#define PROTOCOL_D_SYNC_FACTOR 1 +#define PROTOCOL_D_ZERO_FIRST_CYCLES 1 +#define PROTOCOL_D_ZERO_SECOND_CYCLES 2 +#define PROTOCOL_D_ONE_FIRST_CYCLES 2 +#define PROTOCOL_D_ONE_SECOND_CYCLES 1 +#define PROTOCOL_D_HIGH_FIRST false + + +#define PROTOCOL3_SYNC_FACTOR 71 +#define PROTOCOL3_0_HIGH_CYCLES 4 +#define PROTOCOL3_0_LOW_CYCLES 11 +#define PROTOCOL3_1_HIGH_CYCLES 9 +#define PROTOCOL3_1_LOW_CYCLES 6 + + + +unsigned long rcReceivedValue = 0; +unsigned int rcReceivedBitlength = 0; +unsigned int rcReceivedDelay = 0; +unsigned int rcReceivedProtocol = 0; +int rcReceiveTolerance = 60; +int rcReceiverInterruptPin = -1; + +unsigned int timings[RCSWITCH_MAX_CHANGES]; +int rcTransmitterPin = -1; +int rcPulseLength = 350; // thermometers 2.4 msec = 2400 +int rcRepeatTransmit = 10; +int rcProtocol = 1; + +int backupProtocol; +int backupPulseLength; +int backupRepeatTransmit; + + +//const char TYPE_A_CODE[ 6][6] = { "00000", "10000", "01000", "00100", "00010", "00001"}; +const char TYPE_B_CODE[ 5][5] = { "FFFF", "0FFF", "F0FF", "FF0F", "FFF0" }; +const char TYPE_C_CODE[16][5] = { "0000", "F000", "0F00", "FF00", "00F0", "F0F0", "0FF0", "FFF0", + "000F", "F00F", "0F0F", "FF0F", "00FF", "F0FF", "0FFF", "FFFF" }; +const char TYPE_D_CODE[5][2][9] = { { "11100001", "11110000" }, { "00000000", "00010001" }, { "10000010", "10010011" }, + { "11000011", "11010010" }, { "01000001", "01010000" } }; + /* Type A Type D */ +const int PULSE_LENGTH[MAX_PROTOCOLS] = { 0, 350, 650, 100, 666, }; +const int REPEAT_TRANSMIT[MAX_PROTOCOLS] = { 0, 10, 10, 10, 4, }; +const int SYNC_FACTOR[MAX_PROTOCOLS] = { 0, PROTOCOL_A_SYNC_FACTOR, PROTOCOL_B_SYNC_FACTOR, PROTOCOL_C_SYNC_FACTOR, PROTOCOL_D_SYNC_FACTOR, }; +const int ZERO_FIRST_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ZERO_FIRST_CYCLES, PROTOCOL_B_ZERO_FIRST_CYCLES, PROTOCOL_C_ZERO_FIRST_CYCLES, PROTOCOL_D_ZERO_FIRST_CYCLES, }; +const int ZERO_SECOND_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ZERO_SECOND_CYCLES, PROTOCOL_B_ZERO_SECOND_CYCLES, PROTOCOL_C_ZERO_SECOND_CYCLES, PROTOCOL_D_ZERO_SECOND_CYCLES, }; +const int ONE_FIRST_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ONE_FIRST_CYCLES, PROTOCOL_B_ONE_FIRST_CYCLES, PROTOCOL_C_ONE_FIRST_CYCLES, PROTOCOL_D_ONE_FIRST_CYCLES, }; +const int ONE_SECOND_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ONE_SECOND_CYCLES, PROTOCOL_B_ONE_SECOND_CYCLES, PROTOCOL_C_ONE_SECOND_CYCLES, PROTOCOL_D_ONE_SECOND_CYCLES, }; +const bool HIGH_FIRST[MAX_PROTOCOLS] = { 0, PROTOCOL_A_HIGH_FIRST, PROTOCOL_B_HIGH_FIRST, PROTOCOL_C_HIGH_FIRST, PROTOCOL_D_HIGH_FIRST, }; + + +char *getCodeWordA(char*, char*, bool); +char *getCodeWordB(int, int, bool); +char *getCodeWordC(char, int, int, bool); + +char *getCodeWordE(char, int, bool); +void sendTriState(char*); +void transmit(int, int, bool); +void send0(void); +void send1(void); +void sendT0(void); +void sendT1(void); +void sendTF(void); +void sendSync(void); +bool receiveProtocol(int, unsigned int); +void handleInterrupt(void); +char *dec2binWcharfill(unsigned long, unsigned int, char); + +void setReceiveTolerance(int); +void setProtocol(int); + +void saveProtocol(int); +void loadProtocol(void); + + + +/* + * Sets the protocol to send. + */ +void setProtocol(int nProtocol) { + + if ((nProtocol < TYPE_MINIMUM) || (nProtocol > TYPE_MAXIMUM)) { + return; + } + + rcProtocol = nProtocol; + rcPulseLength = PULSE_LENGTH[nProtocol]; + rcRepeatTransmit = REPEAT_TRANSMIT[nProtocol]; +} + + + +/* + * Set Receiving Tolerance + */ +void setReceiveTolerance(int nPercent) { + rcReceiveTolerance = nPercent; +} + + + +/* + * Enable transmissions + * + * @param nTransmitterPin Pin to which the sender is connected to + */ +void enableTransmit(int nTransmitterPin) { + rcTransmitterPin = nTransmitterPin; + pinMode(rcTransmitterPin, OUTPUT); +} + + + +/* + * Disable transmissions + */ +void disableTransmit(void) { + rcTransmitterPin = -1; +} + + + +/* + * Toggle switch, a command looks like B,3,2,1 which means switch type B, + * group 3, device 2, status on. + */ +int toggleSwitch(char *command) +{ + static char *cmd = NULL; + char *s, cType; + int rc, iGroup, iDevice, iState; + + cmd = xstrcpy(command); + s = strtok(cmd, ",\0"); + cType = s[0]; + + if (cType == 'A') { + + } else if (cType == 'B') { + s = strtok(NULL, ",\0"); + rc = sscanf(s, "%d", &iGroup); + if (rc != 1) + return 1; + s = strtok(NULL, ",\0"); + rc = sscanf(s, "%d", &iDevice); + if (rc != 1) + return 1; + s = strtok(NULL, ",\0"); + rc = sscanf(s, "%d", &iState); + if (rc != 1) + return 1; + free(cmd); + return toggleTypeB(iGroup, iDevice, iState); + } + + free(cmd); + return 1; +} + + + +/* + * Switch a remote switch on (Type E REV) + * + * @param sGroup Code of the switch group (A,B,C,D) + * @param nDevice Number of the switch itself (1..3) + * @param bStatus Status to toggle to + */ +int toggleTypeE(char sGroup, int nDevice, bool bStatus) { + sendTriState( getCodeWordE(sGroup, nDevice, bStatus) ); + return 0; +} + + + +/* + * Switch a remote switch on (Type C Intertechno) + * + * @param sFamily Familycode (a..f) + * @param nGroup Number of group (1..4) + * @param nDevice Number of device (1..4) + * @param bStatus Status to toggle to + */ +int toggleTypeC(char sFamily, int nGroup, int nDevice, bool bStatus) { + char *str = xstrcpy(getCodeWordC(sFamily, nGroup, nDevice, bStatus)); + + if (strlen(str) == 0) + return 1; + + saveProtocol(TYPE_A); // ??? + sendTriState( str ); + loadProtocol(); + free(str); + return 0; +} + + + +/* + * Switch a remote switch on/off (Type B with two rotary/sliding switches) + * + * @param iGroup Number of the switch group (1..4) + * @param iDevice Number of the switch itself (1..4) + * @param bStatus Status to toggle to + */ +int toggleTypeB(int iGroup, int iDevice, bool bStatus) +{ + char *str = xstrcpy(getCodeWordB(iGroup, iDevice, bStatus)); + + if (strlen(str) == 0) + return 1; + + saveProtocol(TYPE_A); // They do better with protocol A timings. + sendTriState( str ); + loadProtocol(); + free(str); + return 0; +} + + + +/* + * Switch a remote switch on (Type A with 10 pole DIP switches) + * + * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111") + * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111") + * @param bStatus Status to toggle to + */ +int toggleTypeA(char* sGroup, char* sDevice, bool bStatus) { + char *str = xstrcpy(getCodeWordA(sGroup, sDevice, bStatus)); + + if (strlen(str) == 0) + return 1; + + saveProtocol(TYPE_A); + sendTriState( str ); + loadProtocol(); + free(str); + return 0; +} + + + +/* + * Returns a char[13], representing the Code Word to be send. + * A Code Word consists of 9 address bits, 3 data bits and one sync bit but in our case only the first 8 address bits and the last 2 data bits were used. + * A Code Bit can have 4 different states: "F" (floating), "0" (low), "1" (high), "S" (synchronous bit) + * + * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ + * | 4 bits address (switch group) | 4 bits address (switch number) | 1 bit address (not used, so never mind) | 1 bit address (not used, so never mind) | 2 data bits (on|off) | 1 sync bit | + * | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | F | F | on=FF off=F0 | S | + * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ + * + * @param nAddressCode Number of the switch group (1..4) + * @param nChannelCode Number of the switch itself (1..4) + * @param bStatus Wether to switch on (true) or off (false) + * + * @return char[13] + */ +char *getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus) +{ + int i, nReturnPos = 0; + static char sReturn[13]; + + if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) { + return '\0'; + } + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = TYPE_B_CODE[nAddressCode][i]; + } + + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = TYPE_B_CODE[nChannelCode][i]; + } + + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = bStatus ? 'F' : '0'; + sReturn[nReturnPos] = '\0'; + + return sReturn; +} + + + +/* + * Returns a char[13], representing the Code Word to be send. + * + * getCodeWordA(char*, char*) + * + */ +char *getCodeWordA(char* sGroup, char* sDevice, bool bOn) +{ + static char sDipSwitches[13]; + int i, j = 0; + + for (i=0; i < 5; i++) { + sDipSwitches[j++] = (sGroup[i] == '0') ? 'F' : '0'; + } + + for (i=0; i < 5; i++) { + sDipSwitches[j++] = (sDevice[i] == '0') ? 'F' : '0'; + } + + if ( bOn ) { + sDipSwitches[j++] = '0'; + sDipSwitches[j++] = 'F'; + } else { + sDipSwitches[j++] = 'F'; + sDipSwitches[j++] = '0'; + } + + sDipSwitches[j] = '\0'; + return sDipSwitches; +} + + + +/* + * Like getCodeWord (Type C = Intertechno) + */ +char *getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus) +{ + static char sReturn[13]; + int i, nReturnPos = 0; + + if (sFamily < 'a') { + // To also enable capital 'A' to 'F' + sFamily += 32; + } + + if ( sFamily < 'a' || sFamily > 'f' || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) { + return '\0'; + } + + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = TYPE_C_CODE[ sFamily - 'a' ][i]; + } + + char *sDeviceGroupCode = dec2binWzerofill( (nDevice-1) + (nGroup-1)*4, 4 ); + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = (sDeviceGroupCode[3-i] == '1' ? 'F' : '0'); + } + + sReturn[nReturnPos++] = '0'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = bStatus ? 'F' : '0'; + sReturn[nReturnPos] = '\0'; + + return sReturn; +} + + + +/* + * Decoding for the Quigg Switch Type + * + * Returns a char[22], representing the States to be send. + * A Code Word consists of 1 start bit, 12 address bits and 8 command data bits. + * A Code Bit can have 2 different states: "0" (low), "1" (high) + * + * +--------------+--------------------------------+------------------------------+ + * | 1 bits start | 12 bits address (device group) | 8 bits (command/switch data) | + * | 1 | 110011001100 | 00010001 | + * +--------------+--------------------------------+------------------------------+ + * + * Source: https://github.com/d-a-n/433-codes/blob/master/database.md#quigg + * + * @param sGroup 12-bit Binary ID of the Device Group + * @param nDevice Number of the switch itself (1..4, or 0 to switch the entire Group) + * @param bStatus Wether to switch on (true) or off (false) + * + * @return char[22] + */ +char *getCodeWordD(char *sGroup, int nDevice, bool bStatus) +{ + static char sReturn[22]; + int i, nReturnPos = 0; + + /* Startbit */ + sReturn[nReturnPos++] = '1'; + + /* 12 bit Group */ + for (i = 0; i < 12; ++i) { + sReturn[nReturnPos++] = sGroup[i]; + } + + /* 8 Bit Device Identifier + Status (undividable!) */ + for (i = 0; i < 8; ++i) { + sReturn[nReturnPos++] = TYPE_D_CODE[nDevice][bStatus][i]; + } + sReturn[nReturnPos] = 0; + + return sReturn; +} + + + +/* + * Decoding for the REV Switch Type + * + * Returns a char[13], representing the Tristate to be send. + * A Code Word consists of 7 address bits and 5 command data bits. + * A Code Bit can have 3 different states: "F" (floating), "0" (low), "1" (high) + * + * +-------------------------------+--------------------------------+-----------------------+ + * | 4 bits address (switch group) | 3 bits address (device number) | 5 bits (command data) | + * | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | on=00010 off=00001 | + * +-------------------------------+--------------------------------+-----------------------+ + * + * Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/ + * + * @param sGroup Name of the switch group (A..D, resp. a..d) + * @param nDevice Number of the switch itself (1..3) + * @param bStatus Wether to switch on (true) or off (false) + * + * @return char[13] + */ +char *getCodeWordE(char sGroup, int nDevice, bool bStatus){ + static char sReturn[13]; + int i, nReturnPos = 0; + + // Building 4 bits address + // (Potential problem if dec2binWcharfill not returning correct string) + char *sGroupCode; + switch(sGroup){ + case 'a': + case 'A': + sGroupCode = dec2binWcharfill(8, 4, 'F'); break; + case 'b': + case 'B': + sGroupCode = dec2binWcharfill(4, 4, 'F'); break; + case 'c': + case 'C': + sGroupCode = dec2binWcharfill(2, 4, 'F'); break; + case 'd': + case 'D': + sGroupCode = dec2binWcharfill(1, 4, 'F'); break; + default: + return '\0'; + } + + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = sGroupCode[i]; + } + + + // Building 3 bits address + // (Potential problem if dec2binWcharfill not returning correct string) + char *sDevice; + switch(nDevice) { + case 1: + sDevice = dec2binWcharfill(4, 3, 'F'); break; + case 2: + sDevice = dec2binWcharfill(2, 3, 'F'); break; + case 3: + sDevice = dec2binWcharfill(1, 3, 'F'); break; + default: + return '\0'; + } + + for (i = 0; i<3; i++) + sReturn[nReturnPos++] = sDevice[i]; + + // fill up rest with zeros + for (i = 0; i<5; i++) + sReturn[nReturnPos++] = '0'; + + // encode on or off + if (bStatus) + sReturn[10] = '1'; + else + sReturn[11] = '1'; + + // last position terminate string + sReturn[12] = '\0'; + return sReturn; + +} + + + +/* + * @param sCodeWord /^[10FS]*$/ -> see getCodeWord + */ +void sendTriState(char* sCodeWord) { + int nRepeat; + + for (nRepeat = 0; nRepeat < rcRepeatTransmit; nRepeat++) { + int i = 0; + while (sCodeWord[i] != '\0') { + switch(sCodeWord[i]) { + case '0': + sendT0(); + break; + case 'F': + sendTF(); + break; + case '1': + sendT1(); + break; + } + i++; + } + sendSync(); + } +} + + + +/* +void RCSwitch::send(unsigned long Code, unsigned int length) { + this->send( this->dec2binWzerofill(Code, length) ); +} + +void RCSwitch::send(char* sCodeWord) { + for (int nRepeat=0; nRepeatsend0(); + break; + case '1': + this->send1(); + break; + } + i++; + } + this->sendSync(); + } +} +*/ + + +void transmit(int nFirstPulses, int nSecondPulses, bool bHighFirst) +{ + bool disabled_Receive = false; + int nReceiverInterrupt_backup = rcReceiverInterruptPin; + + if (rcTransmitterPin != -1) { + if (rcReceiverInterruptPin != -1) { + disableReceive(); + disabled_Receive = true; + } + digitalWrite(rcTransmitterPin, bHighFirst ? HIGH : LOW); + delayMicroseconds( rcPulseLength * nFirstPulses); + digitalWrite(rcTransmitterPin, bHighFirst ? LOW : HIGH); + delayMicroseconds( rcPulseLength * nSecondPulses); + + if (disabled_Receive) { + enableReceiveIRQ(nReceiverInterrupt_backup); + } + } +} + + + +/* + * Sends a "0" Bit + * _ + * Waveform Protocol 1: | |___ + * _ + * Waveform Protocol 2: | |__ + * ____ + * Waveform Protocol 3: | |___________ + */ +//void send0(void) { +// if (rcProtocol == 1){ +// transmit(1,3); +// } +// else if (rcProtocol == 2) { +// transmit(1,2); +// } +// else if (rcProtocol == 3) { +// transmit(4,11); +// } +//} + + + +/* + * Sends a "1" Bit + * ___ + * Waveform Protocol 1: | |_ + * __ + * Waveform Protocol 2: | |_ + * _________ + * Waveform Protocol 3: | |______ + */ +//void send1(void) { +// if (rcProtocol == 1){ +// transmit(3,1); +// } +// else if (rcProtocol == 2) { +// transmit(2,1); +// } +// else if (rcProtocol == 3) { +// transmit(9,6); +// } +//} + + + +/* + * Sends a Tri-State "0" Bit + * _ _ + * Waveform: | |___| |___ + */ +void sendT0(void) { + transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); + transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); +// transmit(1,3,true); +// transmit(1,3,true); +} + + + +/* + * Sends a Tri-State "1" Bit + * ___ ___ + * Waveform: | |_| |_ + */ +void sendT1(void) { + transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); + transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); +// transmit(3,1,true); +// transmit(3,1,true); +} + + + +/* + * Sends a Tri-State "F" Bit + * _ ___ + * Waveform: | |___| |_ + */ +void sendTF(void) { + transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); + transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); +// transmit(1,3,true); +// transmit(3,1,true); +} + + + +/* + * Sends a "Sync" Bit + * _ + * Waveform Protocol 1: | |_______________________________ + * _ + * Waveform Protocol 2: | |__________ + * ____ + * Waveform Protocol 3: | |_______________________________________________________________________ + * + * Waveform Protocol D: (none, just pause 80 msecs) + */ +void sendSync(void) { + + if (rcProtocol == TYPE_A) { + transmit(1,31,true); + } else if (rcProtocol == TYPE_B) { + transmit(1,10,true); + } else if (rcProtocol == TYPE_C) { + transmit(4,71,true); + } else if (rcProtocol == TYPE_D) { + transmit(0,1,false); + delayMicroseconds(80000); + } +} + + + +/* + * Enable receiving data + */ +void enableReceiveIRQ(int Pin) { + rcReceiverInterruptPin = Pin; + enableReceive(); +} + +void enableReceive(void) { + if (rcReceiverInterruptPin != -1) { + rcReceivedValue = 0; + rcReceivedBitlength = 0; + wiringPiISR(rcReceiverInterruptPin, INT_EDGE_BOTH, &handleInterrupt); + } +} + + + +/* + * Disable receiving data + */ +void disableReceive() { + // wiringPi disable interrupts ??? + rcReceiverInterruptPin = -1; +} + + + +bool available(void) { + return rcReceivedValue != 0; +} + + + +void resetAvailable(void) { + rcReceivedValue = 0; +} + + + +unsigned long getReceivedValue(void) { + return rcReceivedValue; +} + + + +unsigned int getReceivedBitlength(void) { + return rcReceivedBitlength; +} + + + +unsigned int getReceivedDelay(void) { + return rcReceivedDelay; +} + + + +unsigned int getReceivedProtocol(void) { + return rcReceivedProtocol; +} + + + +unsigned int* getReceivedRawdata(void) { + return timings; +} + + + +/* + * ASK protool 1 + */ +bool receiveProtocol(int prot, unsigned int changeCount) +{ + unsigned long code = 0; + unsigned long ldelay = timings[0] / SYNC_FACTOR[prot]; + unsigned long delayTolerance = ldelay * rcReceiveTolerance * 0.01; + int i; + + if (prot < TYPE_MINIMUM || prot > TYPE_MAXIMUM) { + return false; + } + + for (i = 1; i ldelay * ZERO_FIRST_CYCLES[prot] - delayTolerance && + timings[i] < ldelay * ZERO_FIRST_CYCLES[prot] + delayTolerance && + timings[i+1] > ldelay * ZERO_SECOND_CYCLES[prot] - delayTolerance && + timings[i+1] < ldelay * ZERO_SECOND_CYCLES[prot] + delayTolerance) { + code = code << 1; + } else if (timings[i] > ldelay * ONE_FIRST_CYCLES[prot] - delayTolerance && + timings[i] < ldelay * ONE_FIRST_CYCLES[prot] + delayTolerance && + timings[i+1] > ldelay * ONE_SECOND_CYCLES[prot] - delayTolerance && + timings[i+1] < ldelay * ONE_SECOND_CYCLES[prot] + delayTolerance) { + code+=1; + code = code << 1; + } else { + // Failed + i = changeCount; + code = 0; + } + } + code = code >> 1; + if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise + rcReceivedValue = code; + rcReceivedBitlength = changeCount / 2; + rcReceivedDelay = ldelay; + rcReceivedProtocol = prot; + } + + return (code != 0); +} + + + +void handleInterrupt() { + + static unsigned int duration; + static unsigned int changeCount; + static unsigned long lastTime; + static unsigned int repeatCount; + + + long thistime = micros(); + duration = thistime - lastTime; + + if (duration > 5000 && duration > timings[0] - 200 && duration < timings[0] + 200) { + repeatCount++; + changeCount--; + if (repeatCount == 2) { + if (receiveProtocol(TYPE_A, changeCount) == false) { + if (receiveProtocol(TYPE_B, changeCount) == false) { + if (receiveProtocol(TYPE_C, changeCount) == false) { + if (receiveProtocol(TYPE_D, changeCount) == false) { + //failed + } + } + } + } + repeatCount = 0; + } + changeCount = 0; + } else if (duration > 5000) { + changeCount = 0; + } + + if (changeCount >= RCSWITCH_MAX_CHANGES) { + changeCount = 0; + repeatCount = 0; + } + timings[changeCount++] = duration; + lastTime = thistime; +} + + + +/* + * Turns a decimal value to its binary representation + */ +char *dec2binWzerofill(unsigned long Dec, unsigned int bitLength) +{ + return dec2binWcharfill(Dec, bitLength, '0'); +} + +char *dec2binWcharfill(unsigned long Dec, unsigned int bitLength, char fill) +{ + static char bin[64]; + unsigned int i = 0, j; + + while (Dec > 0) { + bin[32+i++] = ((Dec & 1) > 0) ? '1' : fill; + Dec = Dec >> 1; + } + + for (j = 0; j< bitLength; j++) { + if (j >= bitLength - i) { + bin[j] = bin[ 31 + i - (j - (bitLength - i)) ]; + } else { + bin[j] = fill; + } + } + bin[bitLength] = '\0'; + + return bin; +} + + +void saveProtocol(int prot) +{ + backupProtocol = rcProtocol; + backupPulseLength = rcPulseLength; + backupRepeatTransmit = rcRepeatTransmit; + + setProtocol(prot); +} + + + +void loadProtocol(void) +{ + rcProtocol = backupProtocol; + rcPulseLength = backupPulseLength; + rcRepeatTransmit = backupRepeatTransmit; +} + + +#endif + diff -r 8b5e8f1e172d -r a03b6dac5398 rc433/rc433.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rc433/rc433.h Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,54 @@ +#ifndef _RC433_H +#define _RC433_H + +#define TRUE 1 +#define FALSE 0 + +#include "../config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* wiringPi */ +#include + + +/* rc-switch.c */ +int toggleSwitch(char *); +int toggleTypeA(char *, char *, bool); +int toggleTypeB(int, int, bool); +int toggleTypeC(char, int, int, bool); +int toggleTypeE(char, int, bool); + +void enableReceiveIRQ(int interrupt); +void enableReceive(void); +void disableReceive(void); +bool available(void); +void resetAvailable(void); + +unsigned long getReceivedValue(void); +unsigned int getReceivedBitlength(void); +unsigned int getReceivedDelay(void); +unsigned int getReceivedProtocol(void); +unsigned int *getReceivedRawdata(void); + +void enableTransmit(int); +void disableTransmit(void); + +char *dec2binWzerofill(unsigned long, unsigned int); + + +/* xutil.c */ +char *xmalloc(size_t); +char *xstrcpy(char *); +char *xstrcat(char *, char *); + + +#endif diff -r 8b5e8f1e172d -r a03b6dac5398 rc433/recv.c --- a/rc433/recv.c Sun May 25 16:39:54 2014 +0200 +++ b/rc433/recv.c Sun May 25 22:06:56 2014 +0200 @@ -20,8 +20,7 @@ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ -#include "../lib/mbselib.h" -#include "recv.h" +#include "rc433.h" #ifdef HAVE_WIRINGPI_H diff -r 8b5e8f1e172d -r a03b6dac5398 rc433/recv.h --- a/rc433/recv.h Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#ifndef _RECV_H -#define _RECV_H - - -#define TRUE 1 -#define FALSE 0 - - -#endif diff -r 8b5e8f1e172d -r a03b6dac5398 rc433/xutil.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rc433/xutil.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,72 @@ +/***************************************************************************** + * Copyright (C) 2008-2014 + * + * Michiel Broek + * + * 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 "rc433.h" + + +char *xmalloc(size_t size) +{ + char *tmp; + + tmp = malloc(size); + if (!tmp) + abort(); + + return tmp; +} + + + +char *xstrcpy(char *src) +{ + char *tmp; + + if (src == NULL) + return(NULL); + tmp = xmalloc(strlen(src)+1); + strcpy(tmp, src); + return tmp; +} + + + +char *xstrcat(char *src, char *add) +{ + char *tmp; + size_t size = 0; + + if ((add == NULL) || (strlen(add) == 0)) + return src; + if (src) + size = strlen(src); + size += strlen(add); + tmp = xmalloc(size + 1); + *tmp = '\0'; + if (src) { + strcpy(tmp, src); + free(src); + } + strcat(tmp, add); + return tmp; +} + + diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/Makefile --- a/thermferm/Makefile Sun May 25 16:39:54 2014 +0200 +++ b/thermferm/Makefile Sun May 25 22:06:56 2014 +0200 @@ -5,7 +5,7 @@ SRCS = $(wildcard *.c) HDRS = $(wildcard *.h) OBJS = $(SRCS:.c=.o) -SLIBS = -lpthread ../lib/libmbse.a +SLIBS = -lpthread TARGET = thermferm OTHER = Makefile @@ -54,8 +54,13 @@ # DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT # Dependencies generated by make depend -thermferm.o: ../lib/mbselib.h thermferm.h sensors.h server.h -sensors.o: ../lib/mbselib.h sensors.h -mosquitto.o: ../lib/mbselib.h mosquitto.h -server.o: ../lib/mbselib.h server.h thermferm.h +thermferm.o: thermferm.h +sensors.o: thermferm.h +server.o: thermferm.h +xutil.o: thermferm.h +lcd-pcf8574.o: thermferm.h +rdconfig.o: thermferm.h +lock.o: thermferm.h +logger.o: thermferm.h +rc-switch.o: thermferm.h # End of generated dependencies diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/lcd-pcf8574.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/lcd-pcf8574.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,142 @@ +/* + * lcd-pcf8574.c: + * Text-based LCD driver library code + * This is designed to drive the HD44780U LCD display connected via + * a "LCM1602 IIC A0 A1 A2" board with a PCF8574 I2C controller. + * + * Copyright (c) 2012-2013 Gordon Henderson. + * Copyright (c) 2014 Michiel Broek. + *********************************************************************** + * + * mbsePi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * mbsePi 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with wiringPi. If not, see . + *********************************************************************** + */ + +#include "thermferm.h" + +#ifdef HAVE_WIRINGPI_H + +int lcdHandle; +unsigned char lcdbuf[MAX_LCDS][20][4]; + +struct lcdDataStruct +{ + int bits, rows, cols ; + int rsPin, strbPin ; + int dataPins [8] ; + int cx, cy ; +}; +extern struct lcdDataStruct *lcds [MAX_LCDS]; + + +/* + * Some LCD functions are extended shadow copies of the wiringPi functions. + * The difference is that the lcdbuf will be updated with the contents on + * the hardware display. This copy can then be used for a remote display + */ + + +/* + * setBacklight: + ********************************************************************************* + */ + +void setBacklight (int value) +{ + pinMode (AF_BACKLIGHT, OUTPUT) ; + digitalWrite (AF_BACKLIGHT, (value & 1)) ; +} + + + +/* + * initLCD: + ********************************************************************************* + */ + +int initLCD (int cols, int rows) +{ + int x, y; + + if (!((rows == 1) || (rows == 2) || (rows == 4))) { + fprintf (stderr, "rows must be 1, 2 or 4\n") ; + return EXIT_FAILURE ; + } + + if (!((cols == 16) || (cols == 20))) { + fprintf (stderr, "cols must be 16 or 20\n") ; + return EXIT_FAILURE ; + } + + pcf8574Setup(AF_BASE, 0x27) ; + pinMode (AF_RW, OUTPUT) ; + digitalWrite (AF_RW, LOW) ; // Not used with wiringPi - always in write mode + + /* + * The other control pins are initialised with lcdInit () + */ + lcdHandle = lcdInit (rows, cols, 4, AF_RS, AF_E, AF_DB4, AF_DB5, AF_DB6, AF_DB7, 0, 0, 0, 0) ; + if (lcdHandle < 0) { + fprintf (stderr, "lcdInit failed\n") ; + return -1 ; + } + + lcdClear (lcdHandle) ; + for (x = 0; x < 20; x++) + for (y = 0; y < 4; y++) + lcdbuf[lcdHandle][x][y] = ' '; + + setBacklight (1) ; + + return 0 ; +} + + + +void mb_lcdPutchar(const int fd, unsigned char data) +{ + struct lcdDataStruct *lcd = lcds[fd]; + + /* + * Write to our buffer first, then to the wiringPi driver. + * Writing to wiringPi updates the cursor position. + */ + lcdbuf[fd][lcd->cx][lcd->cy] = data; + lcdPutchar(fd, data); +} + + + +void mb_lcdPuts(const int fd, const char *string) +{ + while (*string) + mb_lcdPutchar (fd, *string++); +} + + + +void mb_lcdClear(const int fd) +{ + int x, y; + + lcdClear(fd); + for (x = 0; x < 20; x++) + for (y = 0; y < 4; y++) + lcdbuf[fd][x][y] = ' '; +} + + + +#endif + diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/lock.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/lock.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,132 @@ +/***************************************************************************** + * Copyright (C) 2014 + * + * Michiel Broek + * + * 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 "thermferm.h" + +/* + * Put a lock on this program. + */ +int lockprog(char *name) +{ + char *tempfile, *lockfile; + FILE *fp; + pid_t oldpid; + + tempfile = calloc(PATH_MAX, sizeof(char)); + lockfile = calloc(PATH_MAX, sizeof(char)); + + snprintf(tempfile, PATH_MAX, "/var/run/%s.tmp", name); + snprintf(lockfile, PATH_MAX, "/var/run/%s.pid", name); + + if ((fp = fopen(tempfile, "w")) == NULL) { + perror(name); + printf("Can't create lockfile \"%s\"\n", tempfile); + free(tempfile); + free(lockfile); + return 1; + } + fprintf(fp, "%10u\n", getpid()); + fclose(fp); + + while (TRUE) { + if (link(tempfile, lockfile) == 0) { + unlink(tempfile); + free(tempfile); + free(lockfile); + return 0; + } + if ((fp = fopen(lockfile, "r")) == NULL) { + perror(name); + printf("Can't open lockfile \"%s\"\n", tempfile); + unlink(tempfile); + free(tempfile); + free(lockfile); + return 1; + } + if (fscanf(fp, "%u", &oldpid) != 1) { + perror(name); + printf("Can't read old pid from \"%s\"\n", tempfile); + fclose(fp); + unlink(tempfile); + free(tempfile); + free(lockfile); + return 1; + } + fclose(fp); + if (kill(oldpid,0) == -1) { + if (errno == ESRCH) { + printf("Stale lock found for pid %u\n", oldpid); + unlink(lockfile); + /* no return, try lock again */ + } else { + perror(name); + printf("Kill for %u failed\n",oldpid); + unlink(tempfile); + free(tempfile); + free(lockfile); + return 1; + } + } else { + printf("Another %s is already running, pid=%u\n", name, oldpid); + unlink(tempfile); + free(tempfile); + free(lockfile); + return 1; + } + } +} + + + +void ulockprog(char *name) +{ + char *lockfile; + pid_t oldpid; + FILE *fp; + + lockfile = calloc(PATH_MAX, sizeof(char)); + snprintf(lockfile, PATH_MAX, "/var/run/%s.pid", name); + + if ((fp = fopen(lockfile, "r")) == NULL) { + syslog(LOG_NOTICE, "Can't open lockfile \"%s\"", lockfile); + free(lockfile); + return; + } + + if (fscanf(fp, "%u", &oldpid) != 1) { + syslog(LOG_NOTICE, "Can't read old pid from \"%s\"", lockfile); + fclose(fp); + unlink(lockfile); + free(lockfile); + return; + } + + fclose(fp); + + if (oldpid == getpid()) { + (void)unlink(lockfile); + } + + free(lockfile); +} + + diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/logger.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/logger.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,56 @@ +/***************************************************************************** + * Copyright (C) 2014 + * + * Michiel Broek + * + * 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 "thermferm.h" + + +void logger(char *filename, char *progname, char *data) +{ + struct timeval now; + struct tm ptm; + char *outstr = NULL, *name = NULL; + FILE *logfile; + + name = xstrcpy((char *)"/var/local/log/"); + name = xstrcat(name, progname); + name = xstrcat(name, (char *)"/"); + name = xstrcat(name, filename); + + gettimeofday(&now, NULL); + localtime_r(&now.tv_sec, &ptm); + + if ((logfile = fopen(name, "a+"))) { + outstr = calloc(10240, sizeof(char)); + snprintf(outstr, 10239, "%04d-%02d-%02d %02d:%02d,%s\n", ptm.tm_year + 1900, ptm.tm_mon + 1, ptm.tm_mday, ptm.tm_hour, ptm.tm_min, data); + fprintf(logfile, outstr); + fclose(logfile); + free(outstr); + outstr = NULL; + } else { + syslog(LOG_NOTICE, "logger: cannot open %s for writing", name); + } + + free(name); + name = NULL; +} + + diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/rc-switch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/rc-switch.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,955 @@ +/***************************************************************************** + * Copyright (C) 2014 + * + * Michiel Broek + * + * This file is part of the mbsePi-apps + * + * Based on the Arduino libary for remote control outlet switches. + * Project home: http://code.google.com/p/rc-switch/ + * + * 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 "thermferm.h" + +#ifdef HAVE_WIRINGPI_H + + +#define TYPE_UNDEF 0 +#define TYPE_MINIMUM 0 +#define TYPE_A 1 +#define TYPE_B 2 +#define TYPE_C 3 +#define TYPE_D 4 +#define TYPE_E 3 // TODO: Which Protocol does REV use? +#define TYPE_MAXIMUM 4 + +// Number of maximum High/Low changes per packet. +// We can handle up to (unsigned long) => 32 bit * 2 H/L changes per bit + 2 for sync +#define RCSWITCH_MAX_CHANGES 67 + +// i.e. ProtocolCount + 1 (for TYPE_UNDEF) +#define MAX_PROTOCOLS 5 + +#define PROTOCOL_A_SYNC_FACTOR 31 +#define PROTOCOL_A_ZERO_FIRST_CYCLES 1 +#define PROTOCOL_A_ZERO_SECOND_CYCLES 3 +#define PROTOCOL_A_ONE_FIRST_CYCLES 3 +#define PROTOCOL_A_ONE_SECOND_CYCLES 1 +#define PROTOCOL_A_HIGH_FIRST true + +#define PROTOCOL_B_SYNC_FACTOR 10 +#define PROTOCOL_B_ZERO_FIRST_CYCLES 1 +#define PROTOCOL_B_ZERO_SECOND_CYCLES 2 +#define PROTOCOL_B_ONE_FIRST_CYCLES 2 +#define PROTOCOL_B_ONE_SECOND_CYCLES 1 +#define PROTOCOL_B_HIGH_FIRST true + +#define PROTOCOL_C_SYNC_FACTOR 71 +#define PROTOCOL_C_ZERO_FIRST_CYCLES 4 +#define PROTOCOL_C_ZERO_SECOND_CYCLES 11 +#define PROTOCOL_C_ONE_FIRST_CYCLES 9 +#define PROTOCOL_C_ONE_SECOND_CYCLES 6 +#define PROTOCOL_C_HIGH_FIRST true + +// I think, this will work for receive, however, I haven't tested, as I don't own a receiver... +// As Type D doesn't sync acc. to https://github.com/d-a-n/433-codes/blob/master/database.md#quigg +// the sync factor is totally undetermined. +// Malte Diers, 22.11.2013 +#define PROTOCOL_D_SYNC_FACTOR 1 +#define PROTOCOL_D_ZERO_FIRST_CYCLES 1 +#define PROTOCOL_D_ZERO_SECOND_CYCLES 2 +#define PROTOCOL_D_ONE_FIRST_CYCLES 2 +#define PROTOCOL_D_ONE_SECOND_CYCLES 1 +#define PROTOCOL_D_HIGH_FIRST false + + +#define PROTOCOL3_SYNC_FACTOR 71 +#define PROTOCOL3_0_HIGH_CYCLES 4 +#define PROTOCOL3_0_LOW_CYCLES 11 +#define PROTOCOL3_1_HIGH_CYCLES 9 +#define PROTOCOL3_1_LOW_CYCLES 6 + + + +unsigned long rcReceivedValue = 0; +unsigned int rcReceivedBitlength = 0; +unsigned int rcReceivedDelay = 0; +unsigned int rcReceivedProtocol = 0; +int rcReceiveTolerance = 60; +int rcReceiverInterruptPin = -1; + +unsigned int timings[RCSWITCH_MAX_CHANGES]; +int rcTransmitterPin = -1; +int rcPulseLength = 350; // thermometers 2.4 msec = 2400 +int rcRepeatTransmit = 10; +int rcProtocol = 1; + +int backupProtocol; +int backupPulseLength; +int backupRepeatTransmit; + + +//const char TYPE_A_CODE[ 6][6] = { "00000", "10000", "01000", "00100", "00010", "00001"}; +const char TYPE_B_CODE[ 5][5] = { "FFFF", "0FFF", "F0FF", "FF0F", "FFF0" }; +const char TYPE_C_CODE[16][5] = { "0000", "F000", "0F00", "FF00", "00F0", "F0F0", "0FF0", "FFF0", + "000F", "F00F", "0F0F", "FF0F", "00FF", "F0FF", "0FFF", "FFFF" }; +const char TYPE_D_CODE[5][2][9] = { { "11100001", "11110000" }, { "00000000", "00010001" }, { "10000010", "10010011" }, + { "11000011", "11010010" }, { "01000001", "01010000" } }; + /* Type A Type D */ +const int PULSE_LENGTH[MAX_PROTOCOLS] = { 0, 350, 650, 100, 666, }; +const int REPEAT_TRANSMIT[MAX_PROTOCOLS] = { 0, 10, 10, 10, 4, }; +const int SYNC_FACTOR[MAX_PROTOCOLS] = { 0, PROTOCOL_A_SYNC_FACTOR, PROTOCOL_B_SYNC_FACTOR, PROTOCOL_C_SYNC_FACTOR, PROTOCOL_D_SYNC_FACTOR, }; +const int ZERO_FIRST_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ZERO_FIRST_CYCLES, PROTOCOL_B_ZERO_FIRST_CYCLES, PROTOCOL_C_ZERO_FIRST_CYCLES, PROTOCOL_D_ZERO_FIRST_CYCLES, }; +const int ZERO_SECOND_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ZERO_SECOND_CYCLES, PROTOCOL_B_ZERO_SECOND_CYCLES, PROTOCOL_C_ZERO_SECOND_CYCLES, PROTOCOL_D_ZERO_SECOND_CYCLES, }; +const int ONE_FIRST_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ONE_FIRST_CYCLES, PROTOCOL_B_ONE_FIRST_CYCLES, PROTOCOL_C_ONE_FIRST_CYCLES, PROTOCOL_D_ONE_FIRST_CYCLES, }; +const int ONE_SECOND_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ONE_SECOND_CYCLES, PROTOCOL_B_ONE_SECOND_CYCLES, PROTOCOL_C_ONE_SECOND_CYCLES, PROTOCOL_D_ONE_SECOND_CYCLES, }; +const bool HIGH_FIRST[MAX_PROTOCOLS] = { 0, PROTOCOL_A_HIGH_FIRST, PROTOCOL_B_HIGH_FIRST, PROTOCOL_C_HIGH_FIRST, PROTOCOL_D_HIGH_FIRST, }; + + +char *getCodeWordA(char*, char*, bool); +char *getCodeWordB(int, int, bool); +char *getCodeWordC(char, int, int, bool); + +char *getCodeWordE(char, int, bool); +void sendTriState(char*); +void transmit(int, int, bool); +void send0(void); +void send1(void); +void sendT0(void); +void sendT1(void); +void sendTF(void); +void sendSync(void); +bool receiveProtocol(int, unsigned int); +void handleInterrupt(void); +char *dec2binWcharfill(unsigned long, unsigned int, char); + +void setReceiveTolerance(int); +void setProtocol(int); + +void saveProtocol(int); +void loadProtocol(void); + + + +/* + * Sets the protocol to send. + */ +void setProtocol(int nProtocol) { + + if ((nProtocol < TYPE_MINIMUM) || (nProtocol > TYPE_MAXIMUM)) { + return; + } + + rcProtocol = nProtocol; + rcPulseLength = PULSE_LENGTH[nProtocol]; + rcRepeatTransmit = REPEAT_TRANSMIT[nProtocol]; +} + + + +/* + * Set Receiving Tolerance + */ +void setReceiveTolerance(int nPercent) { + rcReceiveTolerance = nPercent; +} + + + +/* + * Enable transmissions + * + * @param nTransmitterPin Pin to which the sender is connected to + */ +void enableTransmit(int nTransmitterPin) { + rcTransmitterPin = nTransmitterPin; + pinMode(rcTransmitterPin, OUTPUT); +} + + + +/* + * Disable transmissions + */ +void disableTransmit(void) { + rcTransmitterPin = -1; +} + + + +/* + * Toggle switch, a command looks like B,3,2,1 which means switch type B, + * group 3, device 2, status on. + */ +int toggleSwitch(char *command) +{ + static char *cmd = NULL; + char *s, cType; + int rc, iGroup, iDevice, iState; + + cmd = xstrcpy(command); + s = strtok(cmd, ",\0"); + cType = s[0]; + + if (cType == 'A') { + + } else if (cType == 'B') { + s = strtok(NULL, ",\0"); + rc = sscanf(s, "%d", &iGroup); + if (rc != 1) + return 1; + s = strtok(NULL, ",\0"); + rc = sscanf(s, "%d", &iDevice); + if (rc != 1) + return 1; + s = strtok(NULL, ",\0"); + rc = sscanf(s, "%d", &iState); + if (rc != 1) + return 1; + free(cmd); + return toggleTypeB(iGroup, iDevice, iState); + } + + free(cmd); + return 1; +} + + + +/* + * Switch a remote switch on (Type E REV) + * + * @param sGroup Code of the switch group (A,B,C,D) + * @param nDevice Number of the switch itself (1..3) + * @param bStatus Status to toggle to + */ +int toggleTypeE(char sGroup, int nDevice, bool bStatus) { + sendTriState( getCodeWordE(sGroup, nDevice, bStatus) ); + return 0; +} + + + +/* + * Switch a remote switch on (Type C Intertechno) + * + * @param sFamily Familycode (a..f) + * @param nGroup Number of group (1..4) + * @param nDevice Number of device (1..4) + * @param bStatus Status to toggle to + */ +int toggleTypeC(char sFamily, int nGroup, int nDevice, bool bStatus) { + char *str = xstrcpy(getCodeWordC(sFamily, nGroup, nDevice, bStatus)); + + if (strlen(str) == 0) + return 1; + + saveProtocol(TYPE_A); // ??? + sendTriState( str ); + loadProtocol(); + free(str); + return 0; +} + + + +/* + * Switch a remote switch on/off (Type B with two rotary/sliding switches) + * + * @param iGroup Number of the switch group (1..4) + * @param iDevice Number of the switch itself (1..4) + * @param bStatus Status to toggle to + */ +int toggleTypeB(int iGroup, int iDevice, bool bStatus) +{ + char *str = xstrcpy(getCodeWordB(iGroup, iDevice, bStatus)); + + if (strlen(str) == 0) + return 1; + + saveProtocol(TYPE_A); // They do better with protocol A timings. + sendTriState( str ); + loadProtocol(); + free(str); + return 0; +} + + + +/* + * Switch a remote switch on (Type A with 10 pole DIP switches) + * + * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111") + * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111") + * @param bStatus Status to toggle to + */ +int toggleTypeA(char* sGroup, char* sDevice, bool bStatus) { + char *str = xstrcpy(getCodeWordA(sGroup, sDevice, bStatus)); + + if (strlen(str) == 0) + return 1; + + saveProtocol(TYPE_A); + sendTriState( str ); + loadProtocol(); + free(str); + return 0; +} + + + +/* + * Returns a char[13], representing the Code Word to be send. + * A Code Word consists of 9 address bits, 3 data bits and one sync bit but in our case only the first 8 address bits and the last 2 data bits were used. + * A Code Bit can have 4 different states: "F" (floating), "0" (low), "1" (high), "S" (synchronous bit) + * + * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ + * | 4 bits address (switch group) | 4 bits address (switch number) | 1 bit address (not used, so never mind) | 1 bit address (not used, so never mind) | 2 data bits (on|off) | 1 sync bit | + * | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | F | F | on=FF off=F0 | S | + * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ + * + * @param nAddressCode Number of the switch group (1..4) + * @param nChannelCode Number of the switch itself (1..4) + * @param bStatus Wether to switch on (true) or off (false) + * + * @return char[13] + */ +char *getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus) +{ + int i, nReturnPos = 0; + static char sReturn[13]; + + if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) { + return '\0'; + } + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = TYPE_B_CODE[nAddressCode][i]; + } + + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = TYPE_B_CODE[nChannelCode][i]; + } + + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = bStatus ? 'F' : '0'; + sReturn[nReturnPos] = '\0'; + + return sReturn; +} + + + +/* + * Returns a char[13], representing the Code Word to be send. + * + * getCodeWordA(char*, char*) + * + */ +char *getCodeWordA(char* sGroup, char* sDevice, bool bOn) +{ + static char sDipSwitches[13]; + int i, j = 0; + + for (i=0; i < 5; i++) { + sDipSwitches[j++] = (sGroup[i] == '0') ? 'F' : '0'; + } + + for (i=0; i < 5; i++) { + sDipSwitches[j++] = (sDevice[i] == '0') ? 'F' : '0'; + } + + if ( bOn ) { + sDipSwitches[j++] = '0'; + sDipSwitches[j++] = 'F'; + } else { + sDipSwitches[j++] = 'F'; + sDipSwitches[j++] = '0'; + } + + sDipSwitches[j] = '\0'; + return sDipSwitches; +} + + + +/* + * Like getCodeWord (Type C = Intertechno) + */ +char *getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus) +{ + static char sReturn[13]; + int i, nReturnPos = 0; + + if (sFamily < 'a') { + // To also enable capital 'A' to 'F' + sFamily += 32; + } + + if ( sFamily < 'a' || sFamily > 'f' || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) { + return '\0'; + } + + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = TYPE_C_CODE[ sFamily - 'a' ][i]; + } + + char *sDeviceGroupCode = dec2binWzerofill( (nDevice-1) + (nGroup-1)*4, 4 ); + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = (sDeviceGroupCode[3-i] == '1' ? 'F' : '0'); + } + + sReturn[nReturnPos++] = '0'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = bStatus ? 'F' : '0'; + sReturn[nReturnPos] = '\0'; + + return sReturn; +} + + + +/* + * Decoding for the Quigg Switch Type + * + * Returns a char[22], representing the States to be send. + * A Code Word consists of 1 start bit, 12 address bits and 8 command data bits. + * A Code Bit can have 2 different states: "0" (low), "1" (high) + * + * +--------------+--------------------------------+------------------------------+ + * | 1 bits start | 12 bits address (device group) | 8 bits (command/switch data) | + * | 1 | 110011001100 | 00010001 | + * +--------------+--------------------------------+------------------------------+ + * + * Source: https://github.com/d-a-n/433-codes/blob/master/database.md#quigg + * + * @param sGroup 12-bit Binary ID of the Device Group + * @param nDevice Number of the switch itself (1..4, or 0 to switch the entire Group) + * @param bStatus Wether to switch on (true) or off (false) + * + * @return char[22] + */ +char *getCodeWordD(char *sGroup, int nDevice, bool bStatus) +{ + static char sReturn[22]; + int i, nReturnPos = 0; + + /* Startbit */ + sReturn[nReturnPos++] = '1'; + + /* 12 bit Group */ + for (i = 0; i < 12; ++i) { + sReturn[nReturnPos++] = sGroup[i]; + } + + /* 8 Bit Device Identifier + Status (undividable!) */ + for (i = 0; i < 8; ++i) { + sReturn[nReturnPos++] = TYPE_D_CODE[nDevice][bStatus][i]; + } + sReturn[nReturnPos] = 0; + + return sReturn; +} + + + +/* + * Decoding for the REV Switch Type + * + * Returns a char[13], representing the Tristate to be send. + * A Code Word consists of 7 address bits and 5 command data bits. + * A Code Bit can have 3 different states: "F" (floating), "0" (low), "1" (high) + * + * +-------------------------------+--------------------------------+-----------------------+ + * | 4 bits address (switch group) | 3 bits address (device number) | 5 bits (command data) | + * | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | on=00010 off=00001 | + * +-------------------------------+--------------------------------+-----------------------+ + * + * Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/ + * + * @param sGroup Name of the switch group (A..D, resp. a..d) + * @param nDevice Number of the switch itself (1..3) + * @param bStatus Wether to switch on (true) or off (false) + * + * @return char[13] + */ +char *getCodeWordE(char sGroup, int nDevice, bool bStatus){ + static char sReturn[13]; + int i, nReturnPos = 0; + + // Building 4 bits address + // (Potential problem if dec2binWcharfill not returning correct string) + char *sGroupCode; + switch(sGroup){ + case 'a': + case 'A': + sGroupCode = dec2binWcharfill(8, 4, 'F'); break; + case 'b': + case 'B': + sGroupCode = dec2binWcharfill(4, 4, 'F'); break; + case 'c': + case 'C': + sGroupCode = dec2binWcharfill(2, 4, 'F'); break; + case 'd': + case 'D': + sGroupCode = dec2binWcharfill(1, 4, 'F'); break; + default: + return '\0'; + } + + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = sGroupCode[i]; + } + + + // Building 3 bits address + // (Potential problem if dec2binWcharfill not returning correct string) + char *sDevice; + switch(nDevice) { + case 1: + sDevice = dec2binWcharfill(4, 3, 'F'); break; + case 2: + sDevice = dec2binWcharfill(2, 3, 'F'); break; + case 3: + sDevice = dec2binWcharfill(1, 3, 'F'); break; + default: + return '\0'; + } + + for (i = 0; i<3; i++) + sReturn[nReturnPos++] = sDevice[i]; + + // fill up rest with zeros + for (i = 0; i<5; i++) + sReturn[nReturnPos++] = '0'; + + // encode on or off + if (bStatus) + sReturn[10] = '1'; + else + sReturn[11] = '1'; + + // last position terminate string + sReturn[12] = '\0'; + return sReturn; + +} + + + +/* + * @param sCodeWord /^[10FS]*$/ -> see getCodeWord + */ +void sendTriState(char* sCodeWord) { + int nRepeat; + + for (nRepeat = 0; nRepeat < rcRepeatTransmit; nRepeat++) { + int i = 0; + while (sCodeWord[i] != '\0') { + switch(sCodeWord[i]) { + case '0': + sendT0(); + break; + case 'F': + sendTF(); + break; + case '1': + sendT1(); + break; + } + i++; + } + sendSync(); + } +} + + + +/* +void RCSwitch::send(unsigned long Code, unsigned int length) { + this->send( this->dec2binWzerofill(Code, length) ); +} + +void RCSwitch::send(char* sCodeWord) { + for (int nRepeat=0; nRepeatsend0(); + break; + case '1': + this->send1(); + break; + } + i++; + } + this->sendSync(); + } +} +*/ + + +void transmit(int nFirstPulses, int nSecondPulses, bool bHighFirst) +{ + bool disabled_Receive = false; + int nReceiverInterrupt_backup = rcReceiverInterruptPin; + + if (rcTransmitterPin != -1) { + if (rcReceiverInterruptPin != -1) { + disableReceive(); + disabled_Receive = true; + } + digitalWrite(rcTransmitterPin, bHighFirst ? HIGH : LOW); + delayMicroseconds( rcPulseLength * nFirstPulses); + digitalWrite(rcTransmitterPin, bHighFirst ? LOW : HIGH); + delayMicroseconds( rcPulseLength * nSecondPulses); + + if (disabled_Receive) { + enableReceiveIRQ(nReceiverInterrupt_backup); + } + } +} + + + +/* + * Sends a "0" Bit + * _ + * Waveform Protocol 1: | |___ + * _ + * Waveform Protocol 2: | |__ + * ____ + * Waveform Protocol 3: | |___________ + */ +//void send0(void) { +// if (rcProtocol == 1){ +// transmit(1,3); +// } +// else if (rcProtocol == 2) { +// transmit(1,2); +// } +// else if (rcProtocol == 3) { +// transmit(4,11); +// } +//} + + + +/* + * Sends a "1" Bit + * ___ + * Waveform Protocol 1: | |_ + * __ + * Waveform Protocol 2: | |_ + * _________ + * Waveform Protocol 3: | |______ + */ +//void send1(void) { +// if (rcProtocol == 1){ +// transmit(3,1); +// } +// else if (rcProtocol == 2) { +// transmit(2,1); +// } +// else if (rcProtocol == 3) { +// transmit(9,6); +// } +//} + + + +/* + * Sends a Tri-State "0" Bit + * _ _ + * Waveform: | |___| |___ + */ +void sendT0(void) { + transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); + transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); +// transmit(1,3,true); +// transmit(1,3,true); +} + + + +/* + * Sends a Tri-State "1" Bit + * ___ ___ + * Waveform: | |_| |_ + */ +void sendT1(void) { + transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); + transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); +// transmit(3,1,true); +// transmit(3,1,true); +} + + + +/* + * Sends a Tri-State "F" Bit + * _ ___ + * Waveform: | |___| |_ + */ +void sendTF(void) { + transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); + transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); +// transmit(1,3,true); +// transmit(3,1,true); +} + + + +/* + * Sends a "Sync" Bit + * _ + * Waveform Protocol 1: | |_______________________________ + * _ + * Waveform Protocol 2: | |__________ + * ____ + * Waveform Protocol 3: | |_______________________________________________________________________ + * + * Waveform Protocol D: (none, just pause 80 msecs) + */ +void sendSync(void) { + + if (rcProtocol == TYPE_A) { + transmit(1,31,true); + } else if (rcProtocol == TYPE_B) { + transmit(1,10,true); + } else if (rcProtocol == TYPE_C) { + transmit(4,71,true); + } else if (rcProtocol == TYPE_D) { + transmit(0,1,false); + delayMicroseconds(80000); + } +} + + + +/* + * Enable receiving data + */ +void enableReceiveIRQ(int Pin) { + rcReceiverInterruptPin = Pin; + enableReceive(); +} + +void enableReceive(void) { + if (rcReceiverInterruptPin != -1) { + rcReceivedValue = 0; + rcReceivedBitlength = 0; + wiringPiISR(rcReceiverInterruptPin, INT_EDGE_BOTH, &handleInterrupt); + } +} + + + +/* + * Disable receiving data + */ +void disableReceive() { + // wiringPi disable interrupts ??? + rcReceiverInterruptPin = -1; +} + + + +bool available(void) { + return rcReceivedValue != 0; +} + + + +void resetAvailable(void) { + rcReceivedValue = 0; +} + + + +unsigned long getReceivedValue(void) { + return rcReceivedValue; +} + + + +unsigned int getReceivedBitlength(void) { + return rcReceivedBitlength; +} + + + +unsigned int getReceivedDelay(void) { + return rcReceivedDelay; +} + + + +unsigned int getReceivedProtocol(void) { + return rcReceivedProtocol; +} + + + +unsigned int* getReceivedRawdata(void) { + return timings; +} + + + +/* + * ASK protool 1 + */ +bool receiveProtocol(int prot, unsigned int changeCount) +{ + unsigned long code = 0; + unsigned long ldelay = timings[0] / SYNC_FACTOR[prot]; + unsigned long delayTolerance = ldelay * rcReceiveTolerance * 0.01; + int i; + + if (prot < TYPE_MINIMUM || prot > TYPE_MAXIMUM) { + return false; + } + + for (i = 1; i ldelay * ZERO_FIRST_CYCLES[prot] - delayTolerance && + timings[i] < ldelay * ZERO_FIRST_CYCLES[prot] + delayTolerance && + timings[i+1] > ldelay * ZERO_SECOND_CYCLES[prot] - delayTolerance && + timings[i+1] < ldelay * ZERO_SECOND_CYCLES[prot] + delayTolerance) { + code = code << 1; + } else if (timings[i] > ldelay * ONE_FIRST_CYCLES[prot] - delayTolerance && + timings[i] < ldelay * ONE_FIRST_CYCLES[prot] + delayTolerance && + timings[i+1] > ldelay * ONE_SECOND_CYCLES[prot] - delayTolerance && + timings[i+1] < ldelay * ONE_SECOND_CYCLES[prot] + delayTolerance) { + code+=1; + code = code << 1; + } else { + // Failed + i = changeCount; + code = 0; + } + } + code = code >> 1; + if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise + rcReceivedValue = code; + rcReceivedBitlength = changeCount / 2; + rcReceivedDelay = ldelay; + rcReceivedProtocol = prot; + } + + return (code != 0); +} + + + +void handleInterrupt() { + + static unsigned int duration; + static unsigned int changeCount; + static unsigned long lastTime; + static unsigned int repeatCount; + + + long thistime = micros(); + duration = thistime - lastTime; + + if (duration > 5000 && duration > timings[0] - 200 && duration < timings[0] + 200) { + repeatCount++; + changeCount--; + if (repeatCount == 2) { + if (receiveProtocol(TYPE_A, changeCount) == false) { + if (receiveProtocol(TYPE_B, changeCount) == false) { + if (receiveProtocol(TYPE_C, changeCount) == false) { + if (receiveProtocol(TYPE_D, changeCount) == false) { + //failed + } + } + } + } + repeatCount = 0; + } + changeCount = 0; + } else if (duration > 5000) { + changeCount = 0; + } + + if (changeCount >= RCSWITCH_MAX_CHANGES) { + changeCount = 0; + repeatCount = 0; + } + timings[changeCount++] = duration; + lastTime = thistime; +} + + + +/* + * Turns a decimal value to its binary representation + */ +char *dec2binWzerofill(unsigned long Dec, unsigned int bitLength) +{ + return dec2binWcharfill(Dec, bitLength, '0'); +} + +char *dec2binWcharfill(unsigned long Dec, unsigned int bitLength, char fill) +{ + static char bin[64]; + unsigned int i = 0, j; + + while (Dec > 0) { + bin[32+i++] = ((Dec & 1) > 0) ? '1' : fill; + Dec = Dec >> 1; + } + + for (j = 0; j< bitLength; j++) { + if (j >= bitLength - i) { + bin[j] = bin[ 31 + i - (j - (bitLength - i)) ]; + } else { + bin[j] = fill; + } + } + bin[bitLength] = '\0'; + + return bin; +} + + +void saveProtocol(int prot) +{ + backupProtocol = rcProtocol; + backupPulseLength = rcPulseLength; + backupRepeatTransmit = rcRepeatTransmit; + + setProtocol(prot); +} + + + +void loadProtocol(void) +{ + rcProtocol = backupProtocol; + rcPulseLength = backupPulseLength; + rcRepeatTransmit = backupRepeatTransmit; +} + + +#endif + diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/rdconfig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/rdconfig.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,350 @@ +/***************************************************************************** + * Copyright (C) 2014 + * + * Michiel Broek + * + * 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 "thermferm.h" + + +bool debug = FALSE; +static char *mypath; +static char *k, *v; +static int linecnt = 0; +sys_config Config; /* System configuration */ + + + +static int getstr(char **); +static int getint(char **); +static int getw1(char **); +#ifdef HAVE_WIRINGPI_H +static int getrcs(char **); +#endif +//static int getbyt(char **); +//static int gethex(char **); + +#define XSTR(x) #x +#define STR(x) XSTR(x) + +/* + * System configuration table + */ +key_list keytab[] = { + {(char *)"mosq_host", getstr, &Config.mosq_host}, + {(char *)"mosq_port", getint, (char **)&Config.mosq_port}, + {(char *)"w1therm", getw1, (char **)&Config.w1therms}, +#ifdef HAVE_WIRINGPI_H + {(char *)"lcd_cols", getint, (char **)&Config.lcd_cols}, + {(char *)"lcd_rows", getint, (char **)&Config.lcd_rows}, + {(char *)"rx433", getint, (char **)&Config.rx433}, + {(char *)"tx433", getint, (char **)&Config.tx433}, + {(char *)"rcswitch", getrcs, (char **)&Config.rcswitch}, +#endif + {NULL, NULL, NULL} +}; + + + +void killconfig(void) +{ + w1_therm *tmp1, *old1; +#ifdef HAVE_WIRINGPI_H + rc_switch *tmp2, *old2; +#endif + + if (Config.name) + free(Config.name); + Config.name = NULL; + + if (Config.mosq_host) + free(Config.mosq_host); + Config.mosq_host= (char *)"localhost"; + Config.mosq_port = 1883; + + for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { + old1 = tmp1->next; + if (tmp1->master) + free(tmp1->master); + if (tmp1->name) + free(tmp1->name); + if (tmp1->alias) + free(tmp1->alias); + free(tmp1); + } + Config.w1therms = NULL; + Config.my_port = 6554; + +#ifdef HAVE_WIRINGPI_H + Config.lcd_cols = 16; + Config.lcd_rows = 2; + Config.rx433 = -1; + Config.tx433 = -1; + + for (tmp2 = Config.rcswitch; tmp2; tmp2 = old2) { + old2 = tmp2->next; + if (tmp2->address) + free(tmp2->address); + tmp2->address = NULL; + if (tmp2->alias) + free(tmp2->alias); + tmp2->alias = NULL; + free(tmp2); + } + Config.rcswitch = NULL; + +#endif +} + + + +int rdconfig(char *config) +{ + char buf[256], *p; + FILE *fp; + int i, rc = 0; + + killconfig(); + + /* + * Search config file + */ + mypath = xstrcpy(getenv((char *)"HOME")); + mypath = xstrcat(mypath, (char *)"/mbsepi-apps/"); + mypath = xstrcat(mypath, config); + 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) { + /* + * 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 not open %s", mypath); + return 1; + } + } + } + + linecnt = 0; + while (fgets(buf, sizeof(buf) -1, fp)) { + linecnt++; + if (*(p = buf + strlen(buf) -1) != '\n') { + syslog(LOG_NOTICE, "rdconfig: %s(%d): \"%s\" - line too long", mypath, linecnt, buf); + rc = 1; + break; + } + *p-- = '\0'; + while ((p >= buf) && isspace(*p)) + *p-- = '\0'; + k = buf; + while (*k && isspace(*k)) + k++; + p = k; + while (*p && !isspace(*p)) + p++; + *p++='\0'; + v = p; + while (*v && isspace(*v)) + v++; + + if ((*k == '\0') || (*k == '#')) { + continue; + } + + for (i = 0; keytab[i].key; i++) + if (strcasecmp(k,keytab[i].key) == 0) + break; + + if (keytab[i].key == NULL) { + syslog(LOG_NOTICE, "rdconfig: %s(%d): %s %s - unknown keyword", mypath, linecnt, MBSE_SS(k), MBSE_SS(v)); + rc = 1; + break; + } else if ((keytab[i].prc(keytab[i].dest))) { + rc = 1; + break; + } + + } + fclose(fp); + + free(mypath); + mypath = NULL; + + return rc; +} + + + +static int getstr(char **dest) +{ + if (debug) + syslog(LOG_NOTICE, "rdconfig: getstr: %s(%d): %s %s", mypath, linecnt, MBSE_SS(k), MBSE_SS(v)); + + *dest = xstrcpy(v); + return 0; +} + + + +static int getint(char **dest) +{ + if (debug) + syslog(LOG_NOTICE, "rdconfig: getint: %s(%d): %s %s", mypath, linecnt, MBSE_SS(k), MBSE_SS(v)); + + if (strspn(v,"0123456789") != strlen(v)) + syslog(LOG_NOTICE, "rdconfig: %s(%d): %s %s - bad numeric", mypath, linecnt, MBSE_SS(k), MBSE_SS(v)); + else + *((int*)dest)=atoi(v); + return 0; +} + + + +static int getw1(char **dest) +{ + char *p, *q = NULL, *r = NULL; + w1_therm **tmpm; + int rc = 0, tmpp; + + for (p = v; *p && !isspace(*p); p++); + if (*p) + *p++ = '\0'; + while (*p && isspace(*p)) + p++; + if (*p == '\0') { + syslog(LOG_NOTICE, "rdconfig: %s(%d): less then two tokens", mypath, linecnt); + return 1; + } + + for (q = p; *q && !isspace(*q); q++); + if (*q && isspace(*q)) { + if (*q) + *q++ = '\0'; + while (*q && isspace(*q)) + q++; + + for (r = q; *r && !isspace(*r); r++); + if (*r) + *r++ = '\0'; + rc = sscanf(p, "%d", &tmpp); + if (rc != 1) { + syslog(LOG_NOTICE, "rdconfig: getw1: %s(%d): %s is not a integer value", mypath, linecnt, p); + return 1; + } + if (debug) + syslog(LOG_NOTICE, "rdconfig: getw1: %s(%d): %s %d %s %s", mypath, linecnt, v, tmpp, q, r); + } + + for (tmpm = (w1_therm**)dest; *tmpm; tmpm=&((*tmpm)->next)); + (*tmpm) = (w1_therm *) xmalloc(sizeof(w1_therm)); + (*tmpm)->next = NULL; + (*tmpm)->master = xstrcpy(v); + (*tmpm)->bus = tmpp; + (*tmpm)->name = xstrcpy(q); + (*tmpm)->alias = xstrcpy(r); + (*tmpm)->present = 0; + (*tmpm)->lastval = 0; + (*tmpm)->update = 0; + + return 0; +} + + + +#ifdef HAVE_WIRINGPI_H +static int getrcs(char **dest) +{ + char *p, *q = NULL, *r = NULL; + rc_switch **tmpm; + + for (p = v; *p && !isspace(*p); p++); + if (*p) + *p++ = '\0'; + while (*p && isspace(*p)) + p++; + if (*p == '\0') { + syslog(LOG_NOTICE, "rdconfig: %s(%d): less then two tokens", mypath, linecnt); + return 1; + } + + for (q = p; *q && !isspace(*q); q++); + if (*q && isspace(*q)) { + if (*q) + *q++ = '\0'; + while (*q && isspace(*q)) + q++; + + for (r = q; *r && !isspace(*r); r++); + if (*r) + *r++ = '\0'; + if (debug) + syslog(LOG_NOTICE, "rdconfig: getrcs: %s(%d): %s %s", mypath, linecnt, v, p); + } + + for (tmpm = (rc_switch**)dest; *tmpm; tmpm=&((*tmpm)->next)); + (*tmpm) = (rc_switch *) xmalloc(sizeof(rc_switch)); + (*tmpm)->next = NULL; + (*tmpm)->address = xstrcpy(v); + (*tmpm)->alias = xstrcpy(p); + + return 0; +} +#endif + + +/* +static int getbyt(char **dest) +{ + Log_Msg("[rdconfig] getbyt: %s(%d): %s %s", mypath, linecnt, k, v); + if (strspn(v,"0123456789") != strlen(v)) + Log_Msg("[rdconfig] %s(%d): %s %s - bad numeric", mypath, linecnt, S(k), S(v)); + else + *((Uint8*)dest)=atoi(v); + return 0; +} +*/ + + +/* +static int gethex(char **dest) +{ + unsigned int val = 0; + int rc; + + Log_Msg("[rdconfig] gethex: %s(%d): %s %s", mypath, linecnt, k, v); + rc = sscanf(v, "%08x", &val); + if (rc != 1) { + Log_Msg("[rdconfig] %s(%d): %s %s - bad hex value", mypath, linecnt, S(k), S(v)); + return 1; + } + *((int*)dest) = val; + + return 0; +} +*/ + + diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/sensors.c --- a/thermferm/sensors.c Sun May 25 16:39:54 2014 +0200 +++ b/thermferm/sensors.c Sun May 25 22:06:56 2014 +0200 @@ -20,8 +20,7 @@ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ -#include "../lib/mbselib.h" -#include "sensors.h" +#include "thermferm.h" #ifdef HAVE_WIRINGPI_H diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/sensors.h --- a/thermferm/sensors.h Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -#ifndef MY_SENSORS_H -#define MY_SENSORS_H - -#ifdef HAVE_WIRINGPI_H - -PI_THREAD (my_sensors_loop); - -#endif - -#endif diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/server.c --- a/thermferm/server.c Sun May 25 16:39:54 2014 +0200 +++ b/thermferm/server.c Sun May 25 22:06:56 2014 +0200 @@ -20,9 +20,6 @@ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ - -#include "../lib/mbselib.h" -#include "server.h" #include "thermferm.h" extern bool my_shutdown; @@ -138,10 +135,10 @@ hostname = hp->h_name; } - if (debug) { - syslog(LOG_NOTICE, "Start new client connection from %s port %u", hostname, ntohs(peeraddr_in.sin_port)); - fprintf(stdout, "Start new client connection from %s port %u\n", hostname, ntohs(peeraddr_in.sin_port)); - } +// if (debug) { +// syslog(LOG_NOTICE, "Start new client connection from %s port %u", hostname, ntohs(peeraddr_in.sin_port)); +// fprintf(stdout, "Start new client connection from %s port %u\n", hostname, ntohs(peeraddr_in.sin_port)); +// } memset((char *)&buf, 0, SS_BUFSIZE); fromlen = sizeof(peeraddr_in); @@ -201,10 +198,17 @@ if (debug) fprintf(stdout, "new temp from %s, %.1f, rc=%d\n", inp, newtemp, rc); if (rc == 1) { - srv_send("ack"); - cs_mode = 'b'; - cs_beerSet = newtemp; + if ((cc_tempSetMin <= newtemp) && (newtemp <= cc_tempSetMax)) { + syslog(LOG_NOTICE, "Beer temperature set to %.1f degrees in web interface", newtemp); + srv_send("ack"); + cs_mode = 'b'; + cs_beerSet = newtemp; + } else { + syslog(LOG_NOTICE, "Beer temperature setting %.1f is outside of allowed range %.1f - %.1f", newtemp, cc_tempSetMin, cc_tempSetMax); + srv_send("err"); + } } else { + syslog(LOG_NOTICE, "Cannot convert temperature '%s' to float", inp); srv_send("err"); } free(inp); @@ -214,18 +218,45 @@ if (debug) fprintf(stdout, "new temp from %s, %.1f, rc=%d\n", inp, newtemp, rc); if (rc == 1) { - srv_send("ack"); - cs_mode = 'f'; - cs_fridgeSet = newtemp; + if ((cc_tempSetMin <= newtemp) && (newtemp <= cc_tempSetMax)) { + syslog(LOG_NOTICE, "Fridge temperature set to %.1f degrees in web interface", newtemp); + srv_send("ack"); + cs_mode = 'f'; + cs_fridgeSet = newtemp; + } else { + syslog(LOG_NOTICE, "Fridge temperature setting %.1f is outside of allowed range %.1f - %.1f", newtemp, cc_tempSetMin, cc_tempSetMax); + srv_send("err"); + } } else { + syslog(LOG_NOTICE, "Cannot convert temperature '%s' to float", inp); srv_send("err"); } free(inp); } else if (strncmp(buf, "setOff", 6) == 0) { if (debug) fprintf(stdout, "temperature control disabled\n"); + syslog(LOG_NOTICE, "Notification: Temperature control disabled"); cs_mode = 'o'; srv_send("ack"); + } else if (strncmp(buf, "setParameters", 13) == 0) { + if (debug) + fprintf(stdout, "FIXME:\n"); + srv_send("ack"); + // stopScript + // quit + // eraseLogs + // interval + // startNewBrew + // pauseLogging + // stopLogging + // resumeLogging + // dateTimeFormatDisplay + } else if (strncmp(buf, "setActiveProfile", 16) == 0) { + syslog(LOG_NOTICE, "Setting profile '%s' as active profile", "undefined"); + // programArduino + // refreshDeviceList + // getDeviceList + // applyDevice } else { if (debug) fprintf(stdout, "unknown command \"%s\"\n", buf); @@ -234,10 +265,10 @@ } } - if (debug) { - syslog(LOG_NOTICE, "End connection from %s port %u", hostname, ntohs(peeraddr_in.sin_port)); - fprintf(stdout, "End connection from %s port %u\n", hostname, ntohs(peeraddr_in.sin_port)); - } +// if (debug) { +// syslog(LOG_NOTICE, "End connection from %s port %u", hostname, ntohs(peeraddr_in.sin_port)); +// fprintf(stdout, "End connection from %s port %u\n", hostname, ntohs(peeraddr_in.sin_port)); +// } close(s); } diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/server.h --- a/thermferm/server.h Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -#ifndef MY_SERVER_H -#define MY_SERVER_H - - -PI_THREAD (my_server_loop); - -#endif diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/thermferm.c --- a/thermferm/thermferm.c Sun May 25 16:39:54 2014 +0200 +++ b/thermferm/thermferm.c Sun May 25 22:06:56 2014 +0200 @@ -20,10 +20,7 @@ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ -#include "../lib/mbselib.h" #include "thermferm.h" -#include "sensors.h" -#include "server.h" #ifdef HAVE_WIRINGPI_H diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/thermferm.h --- a/thermferm/thermferm.h Sun May 25 16:39:54 2014 +0200 +++ b/thermferm/thermferm.h Sun May 25 22:06:56 2014 +0200 @@ -1,10 +1,166 @@ -#ifndef _MAIN_H -#define _MAIN_H +#ifndef _MBSELIB_H +#define _MBSELIB_H #define TRUE 1 #define FALSE 0 +#include "../config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* mosquitto */ +#include + +#ifdef HAVE_WIRINGPI_H +/* wiringPi */ +#include +#include +#include + +#endif + +#define TRUE 1 +#define FALSE 0 + +#define MBSE_SS(x) (x)?(x):"(null)" + +/* rdconfig.c */ +typedef struct _key_list { + char *key; + int (*prc)(char **); + char **dest; +} key_list; + +typedef struct _w1_therm { + struct _w1_therm *next; + char *master; /* Master for this device */ + int bus; /* Reserved for ds2482-800 */ + char *name; /* Name of this device */ + char *alias; /* Friendly name */ + int present; /* 1=present, 0=absent */ + int lastval; /* Last valid value */ + int update; /* Value updated */ +} w1_therm; + +typedef struct _rc_switch { + struct _rc_switch *next; + char *address; /* Address code */ + char *alias; /* Friendly name */ +} rc_switch; + +typedef struct _sys_config { + char *name; /* Configuration name */ + char *mosq_host; /* mosquitto server hostname */ + int mosq_port; /* mosquitto server port */ + int my_port; /* my client/server port */ + w1_therm *w1therms; /* 1-wire temp sensors */ +#ifdef HAVE_WIRINGPI_H + int lcd_cols; /* LCD display columns */ + int lcd_rows; /* LCD display rows */ + int rx433; /* 433 MHz receiver pin */ + int tx433; /* 433 MHz transmitter pin */ + rc_switch *rcswitch; /* 433 MHz RC Power switches */ +#endif +} sys_config; + + +void killconfig(void); +int rdconfig(char *); + + +/* lock.c */ +int lockprog(char *); +void ulockprog(char *); + + +/* xutil.c */ +char *xmalloc(size_t); +char *xstrcpy(char *); +char *xstrcat(char *, char *); + + +#ifdef HAVE_WIRINGPI_H + +/* lcd-pcf8574.c */ +// Defines for the pcf8574 Pi LCD interface board +#define AF_BASE 100 + +#define AF_RS (AF_BASE + 0) +#define AF_RW (AF_BASE + 1) +#define AF_E (AF_BASE + 2) +#define AF_BACKLIGHT (AF_BASE + 3) +#define AF_DB4 (AF_BASE + 4) +#define AF_DB5 (AF_BASE + 5) +#define AF_DB6 (AF_BASE + 6) +#define AF_DB7 (AF_BASE + 7) + +void setBacklight (int); +int initLCD (int, int); +void mb_lcdPutchar(const int, unsigned char); +void mb_lcdPuts(const int, const char *); +void mb_lcdClear(const int); + + +/* logger.c */ +void logger(char *, char *, char *); + + +/* rc-switch.c */ +int toggleSwitch(char *); +int toggleTypeA(char *, char *, bool); +int toggleTypeB(int, int, bool); +int toggleTypeC(char, int, int, bool); +int toggleTypeE(char, int, bool); + +void enableReceiveIRQ(int interrupt); +void enableReceive(void); +void disableReceive(void); +bool available(void); +void resetAvailable(void); + +unsigned long getReceivedValue(void); +unsigned int getReceivedBitlength(void); +unsigned int getReceivedDelay(void); +unsigned int getReceivedProtocol(void); +unsigned int *getReceivedRawdata(void); + +void enableTransmit(int); +void disableTransmit(void); + +char *dec2binWzerofill(unsigned long, unsigned int); + + +/* dht11.c */ +void dht11Read(void); +void dht11Init(int, int, int); + +PI_THREAD (my_sensors_loop); +PI_THREAD (my_server_loop); + +#endif #endif + diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/xutil.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/xutil.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,72 @@ +/***************************************************************************** + * Copyright (C) 2008-2014 + * + * Michiel Broek + * + * 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 "thermferm.h" + + +char *xmalloc(size_t size) +{ + char *tmp; + + tmp = malloc(size); + if (!tmp) + abort(); + + return tmp; +} + + + +char *xstrcpy(char *src) +{ + char *tmp; + + if (src == NULL) + return(NULL); + tmp = xmalloc(strlen(src)+1); + strcpy(tmp, src); + return tmp; +} + + + +char *xstrcat(char *src, char *add) +{ + char *tmp; + size_t size = 0; + + if ((add == NULL) || (strlen(add) == 0)) + return src; + if (src) + size = strlen(src); + size += strlen(add); + tmp = xmalloc(size + 1); + *tmp = '\0'; + if (src) { + strcpy(tmp, src); + free(src); + } + strcat(tmp, add); + return tmp; +} + + diff -r 8b5e8f1e172d -r a03b6dac5398 thermometers/Makefile --- a/thermometers/Makefile Sun May 25 16:39:54 2014 +0200 +++ b/thermometers/Makefile Sun May 25 22:06:56 2014 +0200 @@ -2,10 +2,9 @@ include ../Makefile.global -SRCS = main.c -HDRS = main.h -OBJS = main.o -SLIBS = ../lib/libmbse.a +SRCS = $(wildcard *.c) +HDRS = $(wildcard *.h) +OBJS = $(SRCS:.c=.o) TARGET = thermometers OTHER = Makefile @@ -16,8 +15,8 @@ all: ${TARGET} -thermometers: ${OBJS} ${SLIBS} - ${CC} -o thermometers ${OBJS} ${LDFLAGS} ${LIBS} ${SLIBS} +thermometers: ${OBJS} + ${CC} -o thermometers ${OBJS} ${LDFLAGS} -lmosquitto ${LIBS} clean: rm -f ${TARGET} *.o *.h~ *.c~ core filelist Makefile.bak @@ -54,5 +53,8 @@ # DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT # Dependencies generated by make depend -main.o: ../lib/mbselib.h main.h +rdconfig.o: thermometers.h +xutil.o: thermometers.h +lcd-pcf8574.o: thermometers.h +thermometers.o: thermometers.h # End of generated dependencies diff -r 8b5e8f1e172d -r a03b6dac5398 thermometers/lcd-pcf8574.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermometers/lcd-pcf8574.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,142 @@ +/* + * lcd-pcf8574.c: + * Text-based LCD driver library code + * This is designed to drive the HD44780U LCD display connected via + * a "LCM1602 IIC A0 A1 A2" board with a PCF8574 I2C controller. + * + * Copyright (c) 2012-2013 Gordon Henderson. + * Copyright (c) 2014 Michiel Broek. + *********************************************************************** + * + * mbsePi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * mbsePi 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with wiringPi. If not, see . + *********************************************************************** + */ + +#include "thermometers.h" + +#ifdef HAVE_WIRINGPI_H + +int lcdHandle; +unsigned char lcdbuf[MAX_LCDS][20][4]; + +struct lcdDataStruct +{ + int bits, rows, cols ; + int rsPin, strbPin ; + int dataPins [8] ; + int cx, cy ; +}; +extern struct lcdDataStruct *lcds [MAX_LCDS]; + + +/* + * Some LCD functions are extended shadow copies of the wiringPi functions. + * The difference is that the lcdbuf will be updated with the contents on + * the hardware display. This copy can then be used for a remote display + */ + + +/* + * setBacklight: + ********************************************************************************* + */ + +void setBacklight (int value) +{ + pinMode (AF_BACKLIGHT, OUTPUT) ; + digitalWrite (AF_BACKLIGHT, (value & 1)) ; +} + + + +/* + * initLCD: + ********************************************************************************* + */ + +int initLCD (int cols, int rows) +{ + int x, y; + + if (!((rows == 1) || (rows == 2) || (rows == 4))) { + fprintf (stderr, "rows must be 1, 2 or 4\n") ; + return EXIT_FAILURE ; + } + + if (!((cols == 16) || (cols == 20))) { + fprintf (stderr, "cols must be 16 or 20\n") ; + return EXIT_FAILURE ; + } + + pcf8574Setup(AF_BASE, 0x27) ; + pinMode (AF_RW, OUTPUT) ; + digitalWrite (AF_RW, LOW) ; // Not used with wiringPi - always in write mode + + /* + * The other control pins are initialised with lcdInit () + */ + lcdHandle = lcdInit (rows, cols, 4, AF_RS, AF_E, AF_DB4, AF_DB5, AF_DB6, AF_DB7, 0, 0, 0, 0) ; + if (lcdHandle < 0) { + fprintf (stderr, "lcdInit failed\n") ; + return -1 ; + } + + lcdClear (lcdHandle) ; + for (x = 0; x < 20; x++) + for (y = 0; y < 4; y++) + lcdbuf[lcdHandle][x][y] = ' '; + + setBacklight (1) ; + + return 0 ; +} + + + +void mb_lcdPutchar(const int fd, unsigned char data) +{ + struct lcdDataStruct *lcd = lcds[fd]; + + /* + * Write to our buffer first, then to the wiringPi driver. + * Writing to wiringPi updates the cursor position. + */ + lcdbuf[fd][lcd->cx][lcd->cy] = data; + lcdPutchar(fd, data); +} + + + +void mb_lcdPuts(const int fd, const char *string) +{ + while (*string) + mb_lcdPutchar (fd, *string++); +} + + + +void mb_lcdClear(const int fd) +{ + int x, y; + + lcdClear(fd); + for (x = 0; x < 20; x++) + for (y = 0; y < 4; y++) + lcdbuf[fd][x][y] = ' '; +} + + + +#endif + diff -r 8b5e8f1e172d -r a03b6dac5398 thermometers/main.c --- a/thermometers/main.c Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,554 +0,0 @@ -/***************************************************************************** - * Copyright (C) 2014 - * - * Michiel Broek - * - * 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 "../lib/mbselib.h" -#include "main.h" - - -#define STATUS_CONNECTING 0 -#define STATUS_CONNACK_RECVD 1 -#define STATUS_WAITING 2 - -/* Global variables for use in callbacks. */ -static int qos = 0; -static int status = STATUS_CONNECTING; -static int mid_sent = 0; -static int last_mid = -1; -static int last_mid_sent = -1; -static bool connected = true; -static bool disconnect_sent = false; -static bool connect_lost = false; -static bool my_shutdown = false; -static pid_t pgrp, mypid; - -extern bool 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; -} - - - -void my_connect_callback(struct mosquitto *mosq, void *obj, int result) -{ - if (connect_lost) { - connect_lost = false; - syslog(LOG_NOTICE, "Reconnect: %s", mosquitto_connack_string(result)); - } - - if (!result) { - status = STATUS_CONNACK_RECVD; - } else { - syslog(LOG_NOTICE, "my_connect_callback: %s\n", mosquitto_connack_string(result)); - } -} - - - -void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc) -{ - if (my_shutdown) { - syslog(LOG_NOTICE, "Acknowledged DISCONNECT from %s", Config.mosq_host); - connected = false; - } else { - /* - * The remove server was brought down. We must keep running - */ - syslog(LOG_NOTICE, "Received DISCONNECT from %s, connection lost", Config.mosq_host); - connect_lost = true; - } -} - - - -void my_publish_callback(struct mosquitto *mosq, void *obj, int mid) -{ - last_mid_sent = mid; -} - - - -void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) -{ - syslog(LOG_NOTICE, "MQTT: %s", str); - printf("MQTT: %s\n", str); -} - - - -#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, "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) -{ - char *id = NULL, *state = NULL; - struct mosquitto *mosq = NULL; - char hostname[256], buf[1024]; - int temp, rc, deviation, keepalive = 60; -#ifdef HAVE_WIRINGPI_H - int lcdupdate; -#endif - unsigned int max_inflight = 20; - char err[1024]; - w1_therm *tmp1, *old1; - char *device, *alias, line[60], *p = NULL; - FILE *fp; - - /* - * Initialize mosquitto communication - */ - mosquitto_lib_init(); - - /* - * Build MQTT id - */ - hostname[0] = '\0'; - gethostname(hostname, 256); - hostname[255] = '\0'; - - id = xstrcpy((char *)"thermometers/"); - id = xstrcat(id, hostname); - if(strlen(id) > MOSQ_MQTT_ID_MAX_LENGTH) { - /* - * Enforce maximum client id length of 23 characters - */ - id[MOSQ_MQTT_ID_MAX_LENGTH] = '\0'; - } - - mosq = mosquitto_new(id, true, NULL); - if(!mosq) { - switch(errno) { - case ENOMEM: - syslog(LOG_NOTICE, "mosquitto_new: Out of memory"); - break; - case EINVAL: - syslog(LOG_NOTICE, "mosquitto_new: Invalid id"); - break; - } - mosquitto_lib_cleanup(); - return 1; - } - - if (debug) { - mosquitto_log_callback_set(mosq, my_log_callback); - } - - /* - * Set our will - */ - state = xstrcpy((char *)"clients/"); - state = xstrcat(state, hostname); - state = xstrcat(state, (char *)"/thermometers/state"); - sprintf(buf, "0"); - if ((rc = mosquitto_will_set(mosq, state, strlen(buf), buf, qos, true))) { - if (rc == MOSQ_ERR_INVAL) { - syslog(LOG_NOTICE, "mosquitto_will_set: input parameters invalid"); - } else if (rc == MOSQ_ERR_NOMEM) { - syslog(LOG_NOTICE, "mosquitto_will_set: Out of Memory"); - } else if (rc == MOSQ_ERR_PAYLOAD_SIZE) { - syslog(LOG_NOTICE, "mosquitto_will_set: invalid payload size"); - } - mosquitto_lib_cleanup(); - return rc; - } - - mosquitto_max_inflight_messages_set(mosq, max_inflight); - mosquitto_connect_callback_set(mosq, my_connect_callback); - mosquitto_disconnect_callback_set(mosq, my_disconnect_callback); - mosquitto_publish_callback_set(mosq, my_publish_callback); - - if ((rc = mosquitto_connect(mosq, Config.mosq_host, Config.mosq_port, keepalive))) { - if (rc == MOSQ_ERR_ERRNO) { - strerror_r(errno, err, 1024); - syslog(LOG_NOTICE, "mosquitto_connect: error: %s", err); - } else { - syslog(LOG_NOTICE, "mosquitto_connect: unable to connect (%d)", rc); - } - mosquitto_lib_cleanup(); - return rc; - } - syslog(LOG_NOTICE, "Connected with %s:%d", Config.mosq_host, Config.mosq_port); - - /* - * Initialise is complete, report our presence state - */ - mosquitto_loop_start(mosq); - sprintf(buf, "1"); - rc = mosquitto_publish(mosq, &mid_sent, state, strlen(buf), buf, qos, 1); -#ifdef HAVE_WIRINGPI_H -// setBacklight(0); -#endif - - /* - * Report alias names - */ - for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { - old1 = tmp1->next; - - alias = xstrcpy((char *)"/raw/"); - alias = xstrcat(alias, hostname); - alias = xstrcat(alias, (char *)"/thermometers/w1/"); - alias = xstrcat(alias, tmp1->master); - alias = xstrcat(alias, (char *)"/"); - alias = xstrcat(alias, tmp1->name); - alias = xstrcat(alias, (char *)"/alias"); - - sprintf(buf, "%s", tmp1->alias); - if ((rc = mosquitto_publish(mosq, &mid_sent, alias, strlen(buf), buf, qos, 1))) { - if (rc == MOSQ_ERR_NO_CONN) - mosquitto_reconnect(mosq); - else - syslog(LOG_NOTICE, "mainloop: error %d from mosquitto_publish", rc); - } - - free(alias); - alias = NULL; - } - - if (debug) - fprintf(stdout, (char *)"Enter loop, connected %d\n", connected); - - do { - if (status == STATUS_CONNACK_RECVD) { -#ifdef HAVE_WIRINGPI_H - lcdupdate = FALSE; -#endif - - /* - * Here send our 1-wire sensors values - */ - for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { - old1 = 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"); - alias = xstrcpy((char *)"/raw/"); - alias = xstrcat(alias, hostname); - alias = xstrcat(alias, (char *)"/thermometers/w1/"); - alias = xstrcat(alias, tmp1->master); - alias = xstrcat(alias, (char *)"/"); - alias = xstrcat(alias, tmp1->name); - alias = xstrcat(alias, (char *)"/temperature"); - - /* - * 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)) { - /* - * It is possible to have read errors or extreme values. - * This can happen with bad connections so we compare the - * value with the previous one. If the difference is too - * much, we don't send that value. That also means that if - * the next value is ok again, it will be marked invalid too. - * Maximum error is 20 degrees for now. - */ - deviation = 20000; - if ((tmp1->lastval == 0) || - (tmp1->lastval && (temp > (tmp1->lastval - deviation)) && (temp < (tmp1->lastval + deviation)))) { - /* - * Temperature is changed and valid, update and publish this. - */ - sprintf(buf, "%.1f", temp / 1000.0); - if ((rc = mosquitto_publish(mosq, &mid_sent, alias, strlen(buf), buf, qos, 1))) { - if (rc == MOSQ_ERR_NO_CONN) - mosquitto_reconnect(mosq); - else - syslog(LOG_NOTICE, "mainloop: error %d from mosquitto_publish", rc); - } - } else { - syslog(LOG_NOTICE, "deviation error deviation=%d, old=%d new=%d", deviation, tmp1->lastval, temp); - if (debug) { - fprintf(stdout, "deviation error deviation=%d, old=%d new=%d\n", deviation, 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; - free(alias); - alias = 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); - old1 = tmp1->next; - tmp1 = old1; - 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) { - /* - * Final publish 0 to clients//thermometers/state - */ - sprintf(buf, "0"); - mosquitto_publish(mosq, &mid_sent, state, strlen(buf), buf, qos, true); - last_mid = mid_sent; - status = STATUS_WAITING; -#ifdef HAVE_WIRINGPI_H - lcdClear(lcdHandle); - lcdPosition(lcdHandle, 0, 0); - lcdPuts(lcdHandle, "Shuting down ..."); -#endif - } - - usleep(100000); - - } else if (status == STATUS_WAITING) { - if (debug) - fprintf(stdout, (char *)"Waiting\n"); - if (last_mid_sent == last_mid && disconnect_sent == false) { - mosquitto_disconnect(mosq); - disconnect_sent = true; - } - usleep(100000); - } - rc = MOSQ_ERR_SUCCESS; - - } while (rc == MOSQ_ERR_SUCCESS && connected); - - if (debug) - fprintf(stdout, (char *)"Out of loop\n"); - - mosquitto_loop_stop(mosq, false); - mosquitto_destroy(mosq); - mosquitto_lib_cleanup(); - -#ifdef HAVE_WIRINGPI_H - stopLCD(); -#endif - - return rc; -} - diff -r 8b5e8f1e172d -r a03b6dac5398 thermometers/main.h --- a/thermometers/main.h Sun May 25 16:39:54 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#ifndef _MAIN_H -#define _MAIN_H - - -#define TRUE 1 -#define FALSE 0 - - -#endif diff -r 8b5e8f1e172d -r a03b6dac5398 thermometers/rdconfig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermometers/rdconfig.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,350 @@ +/***************************************************************************** + * Copyright (C) 2014 + * + * Michiel Broek + * + * 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" + + +bool debug = FALSE; +static char *mypath; +static char *k, *v; +static int linecnt = 0; +sys_config Config; /* System configuration */ + + + +static int getstr(char **); +static int getint(char **); +static int getw1(char **); +#ifdef HAVE_WIRINGPI_H +static int getrcs(char **); +#endif +//static int getbyt(char **); +//static int gethex(char **); + +#define XSTR(x) #x +#define STR(x) XSTR(x) + +/* + * System configuration table + */ +key_list keytab[] = { + {(char *)"mosq_host", getstr, &Config.mosq_host}, + {(char *)"mosq_port", getint, (char **)&Config.mosq_port}, + {(char *)"w1therm", getw1, (char **)&Config.w1therms}, +#ifdef HAVE_WIRINGPI_H + {(char *)"lcd_cols", getint, (char **)&Config.lcd_cols}, + {(char *)"lcd_rows", getint, (char **)&Config.lcd_rows}, + {(char *)"rx433", getint, (char **)&Config.rx433}, + {(char *)"tx433", getint, (char **)&Config.tx433}, + {(char *)"rcswitch", getrcs, (char **)&Config.rcswitch}, +#endif + {NULL, NULL, NULL} +}; + + + +void killconfig(void) +{ + w1_therm *tmp1, *old1; +#ifdef HAVE_WIRINGPI_H + rc_switch *tmp2, *old2; +#endif + + if (Config.name) + free(Config.name); + Config.name = NULL; + + if (Config.mosq_host) + free(Config.mosq_host); + Config.mosq_host= (char *)"localhost"; + Config.mosq_port = 1883; + + for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { + old1 = tmp1->next; + if (tmp1->master) + free(tmp1->master); + if (tmp1->name) + free(tmp1->name); + if (tmp1->alias) + free(tmp1->alias); + free(tmp1); + } + Config.w1therms = NULL; + Config.my_port = 6554; + +#ifdef HAVE_WIRINGPI_H + Config.lcd_cols = 16; + Config.lcd_rows = 2; + Config.rx433 = -1; + Config.tx433 = -1; + + for (tmp2 = Config.rcswitch; tmp2; tmp2 = old2) { + old2 = tmp2->next; + if (tmp2->address) + free(tmp2->address); + tmp2->address = NULL; + if (tmp2->alias) + free(tmp2->alias); + tmp2->alias = NULL; + free(tmp2); + } + Config.rcswitch = NULL; + +#endif +} + + + +int rdconfig(char *config) +{ + char buf[256], *p; + FILE *fp; + int i, rc = 0; + + killconfig(); + + /* + * Search config file + */ + mypath = xstrcpy(getenv((char *)"HOME")); + mypath = xstrcat(mypath, (char *)"/mbsepi-apps/"); + mypath = xstrcat(mypath, config); + 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) { + /* + * 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 not open %s", mypath); + return 1; + } + } + } + + linecnt = 0; + while (fgets(buf, sizeof(buf) -1, fp)) { + linecnt++; + if (*(p = buf + strlen(buf) -1) != '\n') { + syslog(LOG_NOTICE, "rdconfig: %s(%d): \"%s\" - line too long", mypath, linecnt, buf); + rc = 1; + break; + } + *p-- = '\0'; + while ((p >= buf) && isspace(*p)) + *p-- = '\0'; + k = buf; + while (*k && isspace(*k)) + k++; + p = k; + while (*p && !isspace(*p)) + p++; + *p++='\0'; + v = p; + while (*v && isspace(*v)) + v++; + + if ((*k == '\0') || (*k == '#')) { + continue; + } + + for (i = 0; keytab[i].key; i++) + if (strcasecmp(k,keytab[i].key) == 0) + break; + + if (keytab[i].key == NULL) { + syslog(LOG_NOTICE, "rdconfig: %s(%d): %s %s - unknown keyword", mypath, linecnt, MBSE_SS(k), MBSE_SS(v)); + rc = 1; + break; + } else if ((keytab[i].prc(keytab[i].dest))) { + rc = 1; + break; + } + + } + fclose(fp); + + free(mypath); + mypath = NULL; + + return rc; +} + + + +static int getstr(char **dest) +{ + if (debug) + syslog(LOG_NOTICE, "rdconfig: getstr: %s(%d): %s %s", mypath, linecnt, MBSE_SS(k), MBSE_SS(v)); + + *dest = xstrcpy(v); + return 0; +} + + + +static int getint(char **dest) +{ + if (debug) + syslog(LOG_NOTICE, "rdconfig: getint: %s(%d): %s %s", mypath, linecnt, MBSE_SS(k), MBSE_SS(v)); + + if (strspn(v,"0123456789") != strlen(v)) + syslog(LOG_NOTICE, "rdconfig: %s(%d): %s %s - bad numeric", mypath, linecnt, MBSE_SS(k), MBSE_SS(v)); + else + *((int*)dest)=atoi(v); + return 0; +} + + + +static int getw1(char **dest) +{ + char *p, *q = NULL, *r = NULL; + w1_therm **tmpm; + int rc = 0, tmpp; + + for (p = v; *p && !isspace(*p); p++); + if (*p) + *p++ = '\0'; + while (*p && isspace(*p)) + p++; + if (*p == '\0') { + syslog(LOG_NOTICE, "rdconfig: %s(%d): less then two tokens", mypath, linecnt); + return 1; + } + + for (q = p; *q && !isspace(*q); q++); + if (*q && isspace(*q)) { + if (*q) + *q++ = '\0'; + while (*q && isspace(*q)) + q++; + + for (r = q; *r && !isspace(*r); r++); + if (*r) + *r++ = '\0'; + rc = sscanf(p, "%d", &tmpp); + if (rc != 1) { + syslog(LOG_NOTICE, "rdconfig: getw1: %s(%d): %s is not a integer value", mypath, linecnt, p); + return 1; + } + if (debug) + syslog(LOG_NOTICE, "rdconfig: getw1: %s(%d): %s %d %s %s", mypath, linecnt, v, tmpp, q, r); + } + + for (tmpm = (w1_therm**)dest; *tmpm; tmpm=&((*tmpm)->next)); + (*tmpm) = (w1_therm *) xmalloc(sizeof(w1_therm)); + (*tmpm)->next = NULL; + (*tmpm)->master = xstrcpy(v); + (*tmpm)->bus = tmpp; + (*tmpm)->name = xstrcpy(q); + (*tmpm)->alias = xstrcpy(r); + (*tmpm)->present = 0; + (*tmpm)->lastval = 0; + (*tmpm)->update = 0; + + return 0; +} + + + +#ifdef HAVE_WIRINGPI_H +static int getrcs(char **dest) +{ + char *p, *q = NULL, *r = NULL; + rc_switch **tmpm; + + for (p = v; *p && !isspace(*p); p++); + if (*p) + *p++ = '\0'; + while (*p && isspace(*p)) + p++; + if (*p == '\0') { + syslog(LOG_NOTICE, "rdconfig: %s(%d): less then two tokens", mypath, linecnt); + return 1; + } + + for (q = p; *q && !isspace(*q); q++); + if (*q && isspace(*q)) { + if (*q) + *q++ = '\0'; + while (*q && isspace(*q)) + q++; + + for (r = q; *r && !isspace(*r); r++); + if (*r) + *r++ = '\0'; + if (debug) + syslog(LOG_NOTICE, "rdconfig: getrcs: %s(%d): %s %s", mypath, linecnt, v, p); + } + + for (tmpm = (rc_switch**)dest; *tmpm; tmpm=&((*tmpm)->next)); + (*tmpm) = (rc_switch *) xmalloc(sizeof(rc_switch)); + (*tmpm)->next = NULL; + (*tmpm)->address = xstrcpy(v); + (*tmpm)->alias = xstrcpy(p); + + return 0; +} +#endif + + +/* +static int getbyt(char **dest) +{ + Log_Msg("[rdconfig] getbyt: %s(%d): %s %s", mypath, linecnt, k, v); + if (strspn(v,"0123456789") != strlen(v)) + Log_Msg("[rdconfig] %s(%d): %s %s - bad numeric", mypath, linecnt, S(k), S(v)); + else + *((Uint8*)dest)=atoi(v); + return 0; +} +*/ + + +/* +static int gethex(char **dest) +{ + unsigned int val = 0; + int rc; + + Log_Msg("[rdconfig] gethex: %s(%d): %s %s", mypath, linecnt, k, v); + rc = sscanf(v, "%08x", &val); + if (rc != 1) { + Log_Msg("[rdconfig] %s(%d): %s %s - bad hex value", mypath, linecnt, S(k), S(v)); + return 1; + } + *((int*)dest) = val; + + return 0; +} +*/ + + diff -r 8b5e8f1e172d -r a03b6dac5398 thermometers/thermometers.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermometers/thermometers.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,553 @@ +/***************************************************************************** + * Copyright (C) 2014 + * + * Michiel Broek + * + * 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" + + +#define STATUS_CONNECTING 0 +#define STATUS_CONNACK_RECVD 1 +#define STATUS_WAITING 2 + +/* Global variables for use in callbacks. */ +static int qos = 0; +static int status = STATUS_CONNECTING; +static int mid_sent = 0; +static int last_mid = -1; +static int last_mid_sent = -1; +static bool connected = true; +static bool disconnect_sent = false; +static bool connect_lost = false; +static bool my_shutdown = false; +static pid_t pgrp, mypid; + +extern bool 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; +} + + + +void my_connect_callback(struct mosquitto *mosq, void *obj, int result) +{ + if (connect_lost) { + connect_lost = false; + syslog(LOG_NOTICE, "Reconnect: %s", mosquitto_connack_string(result)); + } + + if (!result) { + status = STATUS_CONNACK_RECVD; + } else { + syslog(LOG_NOTICE, "my_connect_callback: %s\n", mosquitto_connack_string(result)); + } +} + + + +void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc) +{ + if (my_shutdown) { + syslog(LOG_NOTICE, "Acknowledged DISCONNECT from %s", Config.mosq_host); + connected = false; + } else { + /* + * The remove server was brought down. We must keep running + */ + syslog(LOG_NOTICE, "Received DISCONNECT from %s, connection lost", Config.mosq_host); + connect_lost = true; + } +} + + + +void my_publish_callback(struct mosquitto *mosq, void *obj, int mid) +{ + last_mid_sent = mid; +} + + + +void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) +{ + syslog(LOG_NOTICE, "MQTT: %s", str); + printf("MQTT: %s\n", str); +} + + + +#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, "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) +{ + char *id = NULL, *state = NULL; + struct mosquitto *mosq = NULL; + char hostname[256], buf[1024]; + int temp, rc, deviation, keepalive = 60; +#ifdef HAVE_WIRINGPI_H + int lcdupdate; +#endif + unsigned int max_inflight = 20; + char err[1024]; + w1_therm *tmp1, *old1; + char *device, *alias, line[60], *p = NULL; + FILE *fp; + + /* + * Initialize mosquitto communication + */ + mosquitto_lib_init(); + + /* + * Build MQTT id + */ + hostname[0] = '\0'; + gethostname(hostname, 256); + hostname[255] = '\0'; + + id = xstrcpy((char *)"thermometers/"); + id = xstrcat(id, hostname); + if(strlen(id) > MOSQ_MQTT_ID_MAX_LENGTH) { + /* + * Enforce maximum client id length of 23 characters + */ + id[MOSQ_MQTT_ID_MAX_LENGTH] = '\0'; + } + + mosq = mosquitto_new(id, true, NULL); + if(!mosq) { + switch(errno) { + case ENOMEM: + syslog(LOG_NOTICE, "mosquitto_new: Out of memory"); + break; + case EINVAL: + syslog(LOG_NOTICE, "mosquitto_new: Invalid id"); + break; + } + mosquitto_lib_cleanup(); + return 1; + } + + if (debug) { + mosquitto_log_callback_set(mosq, my_log_callback); + } + + /* + * Set our will + */ + state = xstrcpy((char *)"clients/"); + state = xstrcat(state, hostname); + state = xstrcat(state, (char *)"/thermometers/state"); + sprintf(buf, "0"); + if ((rc = mosquitto_will_set(mosq, state, strlen(buf), buf, qos, true))) { + if (rc == MOSQ_ERR_INVAL) { + syslog(LOG_NOTICE, "mosquitto_will_set: input parameters invalid"); + } else if (rc == MOSQ_ERR_NOMEM) { + syslog(LOG_NOTICE, "mosquitto_will_set: Out of Memory"); + } else if (rc == MOSQ_ERR_PAYLOAD_SIZE) { + syslog(LOG_NOTICE, "mosquitto_will_set: invalid payload size"); + } + mosquitto_lib_cleanup(); + return rc; + } + + mosquitto_max_inflight_messages_set(mosq, max_inflight); + mosquitto_connect_callback_set(mosq, my_connect_callback); + mosquitto_disconnect_callback_set(mosq, my_disconnect_callback); + mosquitto_publish_callback_set(mosq, my_publish_callback); + + if ((rc = mosquitto_connect(mosq, Config.mosq_host, Config.mosq_port, keepalive))) { + if (rc == MOSQ_ERR_ERRNO) { + strerror_r(errno, err, 1024); + syslog(LOG_NOTICE, "mosquitto_connect: error: %s", err); + } else { + syslog(LOG_NOTICE, "mosquitto_connect: unable to connect (%d)", rc); + } + mosquitto_lib_cleanup(); + return rc; + } + syslog(LOG_NOTICE, "Connected with %s:%d", Config.mosq_host, Config.mosq_port); + + /* + * Initialise is complete, report our presence state + */ + mosquitto_loop_start(mosq); + sprintf(buf, "1"); + rc = mosquitto_publish(mosq, &mid_sent, state, strlen(buf), buf, qos, 1); +#ifdef HAVE_WIRINGPI_H +// setBacklight(0); +#endif + + /* + * Report alias names + */ + for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { + old1 = tmp1->next; + + alias = xstrcpy((char *)"/raw/"); + alias = xstrcat(alias, hostname); + alias = xstrcat(alias, (char *)"/thermometers/w1/"); + alias = xstrcat(alias, tmp1->master); + alias = xstrcat(alias, (char *)"/"); + alias = xstrcat(alias, tmp1->name); + alias = xstrcat(alias, (char *)"/alias"); + + sprintf(buf, "%s", tmp1->alias); + if ((rc = mosquitto_publish(mosq, &mid_sent, alias, strlen(buf), buf, qos, 1))) { + if (rc == MOSQ_ERR_NO_CONN) + mosquitto_reconnect(mosq); + else + syslog(LOG_NOTICE, "mainloop: error %d from mosquitto_publish", rc); + } + + free(alias); + alias = NULL; + } + + if (debug) + fprintf(stdout, (char *)"Enter loop, connected %d\n", connected); + + do { + if (status == STATUS_CONNACK_RECVD) { +#ifdef HAVE_WIRINGPI_H + lcdupdate = FALSE; +#endif + + /* + * Here send our 1-wire sensors values + */ + for (tmp1 = Config.w1therms; tmp1; tmp1 = old1) { + old1 = 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"); + alias = xstrcpy((char *)"/raw/"); + alias = xstrcat(alias, hostname); + alias = xstrcat(alias, (char *)"/thermometers/w1/"); + alias = xstrcat(alias, tmp1->master); + alias = xstrcat(alias, (char *)"/"); + alias = xstrcat(alias, tmp1->name); + alias = xstrcat(alias, (char *)"/temperature"); + + /* + * 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)) { + /* + * It is possible to have read errors or extreme values. + * This can happen with bad connections so we compare the + * value with the previous one. If the difference is too + * much, we don't send that value. That also means that if + * the next value is ok again, it will be marked invalid too. + * Maximum error is 20 degrees for now. + */ + deviation = 20000; + if ((tmp1->lastval == 0) || + (tmp1->lastval && (temp > (tmp1->lastval - deviation)) && (temp < (tmp1->lastval + deviation)))) { + /* + * Temperature is changed and valid, update and publish this. + */ + sprintf(buf, "%.1f", temp / 1000.0); + if ((rc = mosquitto_publish(mosq, &mid_sent, alias, strlen(buf), buf, qos, 1))) { + if (rc == MOSQ_ERR_NO_CONN) + mosquitto_reconnect(mosq); + else + syslog(LOG_NOTICE, "mainloop: error %d from mosquitto_publish", rc); + } + } else { + syslog(LOG_NOTICE, "deviation error deviation=%d, old=%d new=%d", deviation, tmp1->lastval, temp); + if (debug) { + fprintf(stdout, "deviation error deviation=%d, old=%d new=%d\n", deviation, 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; + free(alias); + alias = 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); + old1 = tmp1->next; + tmp1 = old1; + 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) { + /* + * Final publish 0 to clients//thermometers/state + */ + sprintf(buf, "0"); + mosquitto_publish(mosq, &mid_sent, state, strlen(buf), buf, qos, true); + last_mid = mid_sent; + status = STATUS_WAITING; +#ifdef HAVE_WIRINGPI_H + lcdClear(lcdHandle); + lcdPosition(lcdHandle, 0, 0); + lcdPuts(lcdHandle, "Shuting down ..."); +#endif + } + + usleep(100000); + + } else if (status == STATUS_WAITING) { + if (debug) + fprintf(stdout, (char *)"Waiting\n"); + if (last_mid_sent == last_mid && disconnect_sent == false) { + mosquitto_disconnect(mosq); + disconnect_sent = true; + } + usleep(100000); + } + rc = MOSQ_ERR_SUCCESS; + + } while (rc == MOSQ_ERR_SUCCESS && connected); + + if (debug) + fprintf(stdout, (char *)"Out of loop\n"); + + mosquitto_loop_stop(mosq, false); + mosquitto_destroy(mosq); + mosquitto_lib_cleanup(); + +#ifdef HAVE_WIRINGPI_H + stopLCD(); +#endif + + return rc; +} + diff -r 8b5e8f1e172d -r a03b6dac5398 thermometers/thermometers.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermometers/thermometers.h Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,154 @@ +#ifndef _THERMOMETERS_H +#define _THERMOMETERS_H + + +#define TRUE 1 +#define FALSE 0 + +#include "../config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* mosquitto */ +#include + +#ifdef HAVE_WIRINGPI_H +/* wiringPi */ +#include +#include +#include + +#endif + +#define TRUE 1 +#define FALSE 0 + +#define MBSE_SS(x) (x)?(x):"(null)" + +/* rdconfig.c */ +typedef struct _key_list { + char *key; + int (*prc)(char **); + char **dest; +} key_list; + +typedef struct _w1_therm { + struct _w1_therm *next; + char *master; /* Master for this device */ + int bus; /* Reserved for ds2482-800 */ + char *name; /* Name of this device */ + char *alias; /* Friendly name */ + int present; /* 1=present, 0=absent */ + int lastval; /* Last valid value */ + int update; /* Value updated */ +} w1_therm; + +typedef struct _rc_switch { + struct _rc_switch *next; + char *address; /* Address code */ + char *alias; /* Friendly name */ +} rc_switch; + +typedef struct _sys_config { + char *name; /* Configuration name */ + char *mosq_host; /* mosquitto server hostname */ + int mosq_port; /* mosquitto server port */ + int my_port; /* my client/server port */ + w1_therm *w1therms; /* 1-wire temp sensors */ +#ifdef HAVE_WIRINGPI_H + int lcd_cols; /* LCD display columns */ + int lcd_rows; /* LCD display rows */ + int rx433; /* 433 MHz receiver pin */ + int tx433; /* 433 MHz transmitter pin */ + rc_switch *rcswitch; /* 433 MHz RC Power switches */ +#endif +} sys_config; + + +void killconfig(void); +int rdconfig(char *); + + +/* xutil.c */ +char *xmalloc(size_t); +char *xstrcpy(char *); +char *xstrcat(char *, char *); + + +#ifdef HAVE_WIRINGPI_H + +/* lcd-pcf8574.c */ +// Defines for the pcf8574 Pi LCD interface board +#define AF_BASE 100 + +#define AF_RS (AF_BASE + 0) +#define AF_RW (AF_BASE + 1) +#define AF_E (AF_BASE + 2) +#define AF_BACKLIGHT (AF_BASE + 3) +#define AF_DB4 (AF_BASE + 4) +#define AF_DB5 (AF_BASE + 5) +#define AF_DB6 (AF_BASE + 6) +#define AF_DB7 (AF_BASE + 7) + +void setBacklight (int); +int initLCD (int, int); +void mb_lcdPutchar(const int, unsigned char); +void mb_lcdPuts(const int, const char *); +void mb_lcdClear(const int); + + +/* logger.c */ +void logger(char *, char *, char *); + + +/* rc-switch.c */ +int toggleSwitch(char *); +int toggleTypeA(char *, char *, bool); +int toggleTypeB(int, int, bool); +int toggleTypeC(char, int, int, bool); +int toggleTypeE(char, int, bool); + +void enableReceiveIRQ(int interrupt); +void enableReceive(void); +void disableReceive(void); +bool available(void); +void resetAvailable(void); + +unsigned long getReceivedValue(void); +unsigned int getReceivedBitlength(void); +unsigned int getReceivedDelay(void); +unsigned int getReceivedProtocol(void); +unsigned int *getReceivedRawdata(void); + +void enableTransmit(int); +void disableTransmit(void); + +char *dec2binWzerofill(unsigned long, unsigned int); + + +#endif + + +#endif + diff -r 8b5e8f1e172d -r a03b6dac5398 thermometers/xutil.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermometers/xutil.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,72 @@ +/***************************************************************************** + * Copyright (C) 2008-2014 + * + * Michiel Broek + * + * 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" + + +char *xmalloc(size_t size) +{ + char *tmp; + + tmp = malloc(size); + if (!tmp) + abort(); + + return tmp; +} + + + +char *xstrcpy(char *src) +{ + char *tmp; + + if (src == NULL) + return(NULL); + tmp = xmalloc(strlen(src)+1); + strcpy(tmp, src); + return tmp; +} + + + +char *xstrcat(char *src, char *add) +{ + char *tmp; + size_t size = 0; + + if ((add == NULL) || (strlen(add) == 0)) + return src; + if (src) + size = strlen(src); + size += strlen(add); + tmp = xmalloc(size + 1); + *tmp = '\0'; + if (src) { + strcpy(tmp, src); + free(src); + } + strcat(tmp, add); + return tmp; +} + +