diff --git a/Makefile b/Makefile index 56e8a67..2124074 100755 --- a/Makefile +++ b/Makefile @@ -27,7 +27,6 @@ CFLAGS = $(GCCFLAGS) -I. -I./minIni $(DBG) $(LIBS) -D MG_DISABLE_MD5 -D MG_DISAB # define the C source files SRCS = sprinkler.c utils.c config.c net_services.c json_messages.c zone_ctrl.c sd_cron.c mongoose.c minIni/minIni.c $(sd_GPIO_C) -TSRC = test.c config.c utils.c minIni/minIni.c # define the C object files # @@ -38,11 +37,11 @@ TSRC = test.c config.c utils.c minIni/minIni.c # with the .o suffix # OBJS = $(SRCS:.c=.o) -TOBJ = $(TSRC:.c=.o) # define the executable file MAIN = ./release/sprinklerd -TEST = ./release/testing +GMON = ./release/gpio_monitor +GPIO = ./release/gpio # # The following part of the makefile is generic; it can be used to @@ -58,11 +57,9 @@ all: $(MAIN) $(MAIN): $(OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS) -test: $(TEST) - @echo: $(TEST) have been compiled - -$(TEST): $(TOBJ) - $(CC) $(CFLAGS) $(INCLUDES) -o $(TEST) $(TOBJ) $(LFLAGS) $(LIBS) +gpio_tools: + $(CC) -o $(GMON) sd_GPIO.c -lm -lpthread -D GPIO_MONITOR + $(CC) -o $(GPIO) sd_GPIO.c -lm -lpthread -D GPIO_RW # this is a suffix replacement rule for building .o's from .c's # it uses automatic variables $<: the name of the prerequisite of diff --git a/config.c b/config.c index 7ca2f9f..1be9411 100644 --- a/config.c +++ b/config.c @@ -9,10 +9,11 @@ #include #define PIN_CFG_NAME "WPI_PIN" #else - #include "sd_GPIO.h" + //#include "sd_GPIO.h" #define PIN_CFG_NAME "GPIO_PIN" #endif +#include "sd_GPIO.h" #include "minIni.h" #include "utils.h" #include "config.h" @@ -308,13 +309,13 @@ void readCfg(char *inifile) _sdconfig_.zonecfg[i].default_runtime = ini_getl(str, "DEFAULT_RUNTIME", 10, inifile); //ini_gets(str, "NAME", NULL, _sdconfig_.zonecfg[idx].name, sizearray(_sdconfig_.zonecfg[idx].name), inifile); ini_gets(str, "NAME", NULL, _sdconfig_.zonecfg[i].name, sizearray(_sdconfig_.zonecfg[i].name), inifile); -#ifndef USE_WIRINGPI +//#ifndef USE_WIRINGPI if ( ! validGPIO(pin) ) { - logMessage (LOG_ERR, "GPIO %d is not valid, found in ZONE:%d of configuration file %s \n",pin, i, inifile); - pin = GPIO_MAX; // Set pin to MAX so we can continue to run if error is not fixed. - sprintf(_sdconfig_.zonecfg[i].name, "ERROR in cfg"); + logMessage (LOG_ERR, "GPIO pin %d is not valid, found in ZONE:%d of configuration file %s \n",pin, i, inifile); + pin = -1; + sprintf(_sdconfig_.zonecfg[i].name, "ERROR"); } -#endif +//#endif /* logMessage (LOG_DEBUG,"Zone Config : %s\n%25s : %d\n%25s : %d\n%25s : %d\n%25s : %d\n%25s : %d\n", _sdconfig_.zonecfg[i].name, @@ -354,6 +355,60 @@ void readCfg(char *inifile) logMessage (LOG_ERR," no config zones set\n"); exit (EXIT_FAILURE); } + + // Caculate how many inputs we have + for (i=1; i <= 24; i++) // 24 = Just some arbutary number (max GPIO without expansion board) + { + sprintf(str, "INPUT:%d", i); + pin = ini_getl(str, PIN_CFG_NAME, -1, inifile); + if (pin == -1) + break; + else + _sdconfig_.inputs = i; + } + + logMessage (LOG_DEBUG, "Found %d INPUTS\n", _sdconfig_.inputs); + + if ( _sdconfig_.inputs != 0) { + // n= _sdconfig_.zones+1; + _sdconfig_.inputcfg = malloc((_sdconfig_.inputs + 1) * sizeof(struct GPIOcfg)); + for (i=0; i < _sdconfig_.inputs; i++) + { + sprintf(str, "INPUT:%d", i+1); + pin = ini_getl(str, PIN_CFG_NAME, -1, inifile); + if (! validGPIO(pin) ) { + logMessage (LOG_ERR, "GPIO pin %d is not valid, found in INPUT:%d of configuration file %s \n",pin, i+1, inifile); + continue; + } + logMessage (LOG_DEBUG, "INPUT = %d\n", i+1); + + _sdconfig_.inputcfg[i].input_output = INPUT; // Zone is always input + _sdconfig_.inputcfg[i].receive_mode = BOTH; // Zone always needs trigger on both (high or low) + _sdconfig_.inputcfg[i].zone = i+1; + _sdconfig_.inputcfg[i].pin = pin; + _sdconfig_.inputcfg[i].on_state = ini_getl(str, "GPIO_ON_STATE", NO, inifile); + //_sdconfig_.inputcfg[i].startup_state = !_sdconfig_.inputcfg[i].on_state; + //_sdconfig_.inputcfg[i].shutdown_state = !_sdconfig_.inputcfg[i].on_state; + + _sdconfig_.inputcfg[i].set_pull_updown = ini_getl(str, "GPIO_PULL_UPDN", -1, inifile); + _sdconfig_.inputcfg[i].dz_idx = ini_getl(str, "DOMOTICZ_IDX", -1, inifile); // Not used at the moment. + ini_gets(str, "NAME", NULL, _sdconfig_.inputcfg[i].name, sizearray(_sdconfig_.inputcfg[i].name), inifile); + + _sdconfig_.inputcfg[i].command_on = malloc(COMMAND_SIZE * sizeof(char)); + _sdconfig_.inputcfg[i].command_off = malloc(COMMAND_SIZE * sizeof(char)); + ini_gets(str, "COMMAND_ON", NULL, _sdconfig_.inputcfg[i].command_on, COMMAND_SIZE, inifile); + ini_gets(str, "COMMAND_OFF", NULL, _sdconfig_.inputcfg[i].command_off, COMMAND_SIZE, inifile); + + logMessage (LOG_DEBUG,"Input Config : %s\n%25s : %d\n%25s : %d\n%25s : %d\n%25s : %d\n", + _sdconfig_.inputcfg[i].name, + "PIN",_sdconfig_.inputcfg[i].pin, + "Set pull up/down", _sdconfig_.inputcfg[i].set_pull_updown, + "ON state", _sdconfig_.inputcfg[i].on_state, + "Domoticz IDX", _sdconfig_.inputcfg[i].dz_idx); + } + } + + /* idx=0; pin=-1; diff --git a/config.h b/config.h index f545b7b..74f01e9 100644 --- a/config.h +++ b/config.h @@ -46,6 +46,8 @@ struct GPIOcfg { //int ignore_requests; int zone; int default_runtime; + char *command_on; + char *command_off; //bool master_valve; //struct GPIOextra *extra; }; @@ -74,6 +76,7 @@ struct sprinklerdcfg { bool enableMQTTdz; bool enableMQTTaq; int zones; + int inputs; //int pincfgs; bool calendar; bool delay24h; @@ -84,6 +87,7 @@ struct sprinklerdcfg { float precipInchDelay2day; struct DZcache *dz_cache; struct GPIOcfg *zonecfg; + struct GPIOcfg *inputcfg; //struct GPIOcfg *gpiocfg; struct CALENDARday cron[7]; //time_t cron_update; diff --git a/json_messages.c b/json_messages.c index 94c1e3a..e73e145 100644 --- a/json_messages.c +++ b/json_messages.c @@ -39,7 +39,7 @@ int build_sprinkler_cal_JSON(char* buffer, int size) for (day=0; day <= 6; day++) { if (_sdconfig_.cron[day].hour >= 0 && _sdconfig_.cron[day].minute >= 0) { length += sprintf(buffer+length, ", \"d%d-starttime\" : \"%.2d:%.2d\" ",day,_sdconfig_.cron[day].hour,_sdconfig_.cron[day].minute); - for (zone=0; zone < _sdconfig_.zones; zone ++) { + for (zone=1; zone < _sdconfig_.zones; zone ++) { if (_sdconfig_.cron[day].zruntimes[zone] >= 0) { length += sprintf(buffer+length, ", \"d%dz%d-runtime\" : %d",day,zone+1,_sdconfig_.cron[day].zruntimes[zone]); //logMessage(LOG_DEBUG, "Zone %d, length %d limit %d\n",zone,length,size); @@ -105,6 +105,7 @@ int build_advanced_sprinkler_JSON(char* buffer, int size) int i, day; memset(&buffer[0], 0, size); int length = 0; + bool cal = false; /* length += sprintf(buffer+length, "{ \"title\" : \"%s\",\"calendar\" : \"%s\", \"24hdelay\" : \"%s\", \"allz\" : \"%s\", \"#zones\" : %d, \"24hdelay-offtime\" : %li", _sdconfig_.name, @@ -146,8 +147,9 @@ int build_advanced_sprinkler_JSON(char* buffer, int size) for (day=0; day <= 6; day++) { if (_sdconfig_.cron[day].hour >= 0 && _sdconfig_.cron[day].minute >= 0) { + cal = true; length += sprintf(buffer+length, "\"day %d\" : { \"start time\" : \"%.2d:%.2d\", ",day,_sdconfig_.cron[day].hour,_sdconfig_.cron[day].minute); - for (i=0; i < _sdconfig_.zones; i ++) { + for (i=1; i < _sdconfig_.zones; i ++) { if (_sdconfig_.cron[day].zruntimes[i] >= 0) { length += sprintf(buffer+length, "\"Zone %d\" : %d,",i+1,_sdconfig_.cron[day].zruntimes[i]); //logMessage(LOG_DEBUG, "Zone %d, length %d limit %d\n",i+1,length,size); @@ -157,8 +159,11 @@ int build_advanced_sprinkler_JSON(char* buffer, int size) length += sprintf(buffer+length, "},"); } } - length -= 1; + if (cal) { + length -= 1; + } length += sprintf(buffer+length, "}}"); + buffer[length] = '\0'; return strlen(buffer); diff --git a/net_services.c b/net_services.c index a42a2e8..7122fbc 100644 --- a/net_services.c +++ b/net_services.c @@ -197,8 +197,6 @@ void publish_zone_mqtt(struct mg_connection *nc, struct GPIOcfg *gpiopin) { static char mqtt_topic[250]; static char mqtt_msg[50]; -printf("PUBLISH pin %d\n",gpiopin->pin); - if (_sdconfig_.enableMQTTaq == true) { // sprintf(mqtt_topic, "%s/%s", _sdconfig_.mqtt_topic, gpiopin->name); sprintf(mqtt_topic, "%s/zone%d", _sdconfig_.mqtt_topic, gpiopin->zone); diff --git a/release/gpio b/release/gpio new file mode 100755 index 0000000..2914f00 Binary files /dev/null and b/release/gpio differ diff --git a/release/gpio_monitor b/release/gpio_monitor new file mode 100755 index 0000000..3b17e20 Binary files /dev/null and b/release/gpio_monitor differ diff --git a/release/sprinklerd b/release/sprinklerd index 7d265cf..6017b24 100755 Binary files a/release/sprinklerd and b/release/sprinklerd differ diff --git a/release/sprinklerd.test.conf b/release/sprinklerd.test.conf index e106735..2768a78 100644 --- a/release/sprinklerd.test.conf +++ b/release/sprinklerd.test.conf @@ -4,16 +4,17 @@ NAME=My Sprinklers DOCUMENTROOT = /nas/data/Development/Raspberry/SprinklerD/web/ CACHE = /var/cache/sprinklerd.cache # The log level. [DEBUG, INFO, NOTICE, WARNING, ERROR] -LOG_LEVEL = DEBUG -#LOG_LEVEL = NOTICE +#LOG_LEVEL = DEBUG +#LOG_LEVEL = NOTICE +LOG_LEVEL = INFO # mqtt stuff MQTT_ADDRESS = trident:1883 #MQTT_USER = someusername #MQTT_PASSWD = somepassword MQT_TOPIC = sd_test -#MQTT_DZ_PUB_TOPIC = domoticz/in -#MQTT_DZ_SUB_TOPIC = domoticz/out +MQTT_DZ_PUB_TOPIC = domoticz/in +MQTT_DZ_SUB_TOPIC = domoticz/out DZIDX_CALENDAR = 197 DZIDX_24HDELAY = 198 @@ -39,51 +40,61 @@ DZIDX_RAINSENSOR = 48 # Don't use ZONE:0 for anything other than master valve, if you don't have a master valve simply delete it and start from ZONE:1 [ZONE] -#[ZONE:0] -#NAME=Master Valve -#MASTER_VALVE=1 -#GPIO_PIN=17 -#WPI_PIN=0 -#GPIO_PULL_UPDN=1 -#GPIO_ON_STATE=0 +[ZONE:0] +NAME=Master Valve +MASTER_VALVE=1 +GPIO_PIN=2 +WPI_PIN=0 +GPIO_PULL_UPDN=1 +GPIO_ON_STATE=0 [ZONE:1] NAME=Island DEFAULT_RUNTIME=10 #GPIO_PIN=18 -GPIO_PIN=2 +GPIO_PIN=3 WPI_PIN=1 GPIO_PULL_UPDN=1 GPIO_ON_STATE=0 -DOMOTICZ_IDX=200 +DOMOTICZ_IDX=2000 [ZONE:2] NAME=Driveway DEFAULT_RUNTIME=10 #GPIO_PIN=27 -GPIO_PIN=3 +GPIO_PIN=40 WPI_PIN=2 GPIO_PULL_UPDN=1 GPIO_ON_STATE=0 -DOMOTICZ_IDX=201 +DOMOTICZ_IDX=2010 [ZONE:3] NAME=Diningroom Flowerbeds DEFAULT_RUNTIME=10 -GPIO_PIN=22 +GPIO_PIN=5 WPI_PIN=3 GPIO_PULL_UPDN=1 GPIO_ON_STATE=0 -DOMOTICZ_IDX=202 +DOMOTICZ_IDX=2020 -[ZONE:4] -NAME=Diningroom error -DEFAULT_RUNTIME=10 -GPIO_PIN=28 +[INPUT] +[INPUT:1] +NAME=Test Switch +GPIO_PIN=6 WPI_PIN=3 GPIO_PULL_UPDN=1 GPIO_ON_STATE=0 -DOMOTICZ_IDX=202 +COMMAND_ON=/usr/bin/curl -s -o /dev/null 'http://localhost?type=option&option=24hdelay&state=on' +COMMAND_OFF=/usr/bin/curl -s -o /dev/null 'http://localhost?type=option&option=24hdelay&state=off' + +#[ZONE:4] +#NAME=Diningroom error +#DEFAULT_RUNTIME=10 +#GPIO_PIN=28 +#WPI_PIN=3 +#GPIO_PULL_UPDN=1 +#GPIO_ON_STATE=0 +#DOMOTICZ_IDX=2020 #[ZONE:4] #NAME=Front Flowerbeds diff --git a/sd_GPIO.c b/sd_GPIO.c index 54e91eb..24976a0 100644 --- a/sd_GPIO.c +++ b/sd_GPIO.c @@ -161,6 +161,9 @@ bool gpioSetup() { int pinMode(unsigned gpio, unsigned mode) { int reg, shift; + if (! validGPIO(gpio)) + return -1; + reg = gpio / 10; shift = (gpio % 10) * 3; @@ -172,6 +175,9 @@ int pinMode(unsigned gpio, unsigned mode) { int getPinMode(unsigned gpio) { int reg, shift; + if (! validGPIO(gpio)) + return -1; + reg = gpio / 10; shift = (gpio % 10) * 3; @@ -181,6 +187,9 @@ int getPinMode(unsigned gpio) { int digitalRead(unsigned gpio) { unsigned bank, bit; + if (! validGPIO(gpio)) + return -1; + bank = gpio >> 5; bit = (1 << (gpio & 0x1F)); @@ -194,6 +203,9 @@ int digitalRead(unsigned gpio) { int digitalWrite(unsigned gpio, unsigned level) { unsigned bank, bit; + if (! validGPIO(gpio)) + return -1; + bank = gpio >> 5; bit = (1 << (gpio & 0x1F)); @@ -203,13 +215,16 @@ int digitalWrite(unsigned gpio, unsigned level) { else *(_gpioReg + GPSET0 + bank) = bit; - return 0; + return true; } int setPullUpDown(unsigned gpio, unsigned pud) { unsigned bank, bit; + if (! validGPIO(gpio)) + return -1; + bank = gpio >> 5; bit = (1 << (gpio & 0x1F)); @@ -240,6 +255,9 @@ int pinMode (unsigned pin, unsigned mode) { //static const char s_directions_str[] = "in\0out\0"; + if (! validGPIO(pin)) + return -1; + char path[SYSFS_PATH_MAX]; int fd; /* @@ -274,6 +292,9 @@ int getPinMode(unsigned gpio) { char value_str[SYSFS_READ_MAX]; int fd; + if (! validGPIO(gpio)) + return -1; + snprintf(path, SYSFS_PATH_MAX, "/sys/class/gpio/gpio%d/direction", gpio); fd = open(path, O_RDONLY); if (-1 == fd) { @@ -302,6 +323,9 @@ int digitalRead (unsigned pin) char path[SYSFS_PATH_MAX]; char value_str[SYSFS_READ_MAX]; int fd; + + if (! validGPIO(pin)) + return -1; snprintf(path, SYSFS_PATH_MAX, "/sys/class/gpio/gpio%d/value", pin); fd = open(path, O_RDONLY); @@ -329,6 +353,9 @@ int digitalWrite (unsigned pin, unsigned value) char path[SYSFS_PATH_MAX]; int fd; + + if (! validGPIO(pin)) + return -1; snprintf(path, SYSFS_PATH_MAX, "/sys/class/gpio/gpio%d/value", pin); fd = open(path, O_WRONLY); @@ -381,6 +408,9 @@ bool pinExport(unsigned pin) ssize_t bytes_written; int fd; + if (! validGPIO(pin)) + return -1; + fd = open("/sys/class/gpio/export", O_WRONLY); if (-1 == fd) { //fprintf(stderr, "Failed to open export for writing!\n"); @@ -400,6 +430,9 @@ bool pinUnexport(unsigned pin) ssize_t bytes_written; int fd; + if (! validGPIO(pin)) + return -1; + fd = open("/sys/class/gpio/unexport", O_WRONLY); if (-1 == fd) { //fprintf(stderr, "Failed to open unexport for writing!\n"); @@ -420,6 +453,9 @@ bool edgeSetup (unsigned pin, unsigned value) char path[SYSFS_PATH_MAX]; int fd; + if (! validGPIO(pin)) + return -1; + snprintf(path, SYSFS_PATH_MAX, "/sys/class/gpio/gpio%d/edge", pin); fd = open(path, O_WRONLY); if (-1 == fd) { @@ -485,7 +521,7 @@ void gpioShutdown() { for (i=0; i< MAX_FDS; i++) { if (_sysFds[i] != -1) { - printf("Closing fd\n"); + //printf("Closing fd %d\n",i); close(_sysFds[i]); _sysFds[i] = -1; } else { @@ -567,6 +603,10 @@ bool registerGPIOinterrupt(int pin, int mode, void (*function)(void *args), void { pthread_t threadId ; struct threadGPIOinterupt stuff; + + if (! validGPIO(pin)) + return false; + // Check it's exported if (! isExported(pin)) pinExport(pin); @@ -598,32 +638,22 @@ bool registerGPIOinterrupt(int pin, int mode, void (*function)(void *args), void } -//#define TEST_HARNESS - -#ifdef TEST_HARNESS - -#define GPIO_OFF 0x00005000 /* Offset from IO_START to the GPIO reg's. */ - -/* IO_START and IO_BASE are defined in hardware.h */ - -#define GPIO_START (IO_START_2 + GPIO_OFF) /* Physical addr of the GPIO reg. */ -#define GPIO_BASE_NEW (IO_BASE_2 + GPIO_OFF) /* Virtual addr of the GPIO reg. */ +#if defined(TEST_HARNESS) || defined(GPIO_MONITOR) || defined(GPIO_RW) #include #include +#include +#include +#include #include #include -void *myCallBack(void * args) { - printf("Ping\n"); - //struct threadGPIOinterupt *stuff = (struct threadGPIOinterupt *) args; - //printf("Pin is %d\n",stuff->pin); -} +int _log_level = LOG_DEBUG; void logMessage(int level, char *format, ...) { - //if (_debuglog_ == false && level == LOG_DEBUG) - // return; + if (level > _log_level) + return; char buffer[256]; va_list args; @@ -645,9 +675,134 @@ void displayLastSystemError (const char *on_what) } +#endif //TEST_HARNESS || GPIO_MONITOR + +#ifdef GPIO_RW + +void errorParms() +{ + printf("Missing Parameters:-\n\t[read|write] pin \n\tgpio write 17 1\n"); + exit(1); +} +int main(int argc, char *argv[]) { + + bool isWrite=false; + int pin = 0; + int value = 0; + + _log_level = LOG_ERR; + + if (argc < 3) { + errorParms(); + } + + if (strcmp (argv[1], "read") == 0) + { + isWrite = false; + } else if (strcmp (argv[1], "write") == 0) { + isWrite = true; + if (argc < 4) + errorParms(); + } else { + errorParms(); + } + + pin = atoi(argv[2]); + + if (! gpioSetup()) { + logMessage (LOG_ERR, "Failed to setup GPIO\n"); + return 1; + } + + if (isWrite) { + value = atoi(argv[3]); + int pmode = getPinMode(pin); + pinMode (pin, OUTPUT); + digitalWrite(pin, value); + //if (pmode != OUTPUT) + // pinMode (pin, pmode); + } + + printf ("%d\n", digitalRead(pin)); + + + return 0; +} +#endif + +#ifdef GPIO_MONITOR + +bool FOREVER = true; + +void intHandler(int signum) { + static int called=0; + logMessage (LOG_INFO, "Stopping! - signel(%d)\n",signum); + gpioShutdown(); + FOREVER = false; + called++; + if (called > 3) + exit(1); +} + +void event_trigger (int pin) +{ + printf("Pin %d triggered, state=%d\n",pin,digitalRead(pin)); +} + +int main(int argc, char *argv[]) { + + int i; + + if (! gpioSetup()) { + logMessage (LOG_ERR, "Failed to setup GPIO\n"); + return 1; + } + + signal(SIGINT, intHandler); + signal(SIGTERM, intHandler); + signal(SIGSEGV, intHandler); + + for (i=GPIO_MIN; i <= GPIO_MAX; i++) { + printf ("Pin %d is %d\n", i, digitalRead(i)); + if (registerGPIOinterrupt (i, INT_EDGE_BOTH, (void *)&event_trigger, (void *)i) != true) + { + displayLastSystemError ("Unable to set interrupt handler for specified pin, exiting"); + gpioShutdown(); + return 1; + } + } + + while(FOREVER) { + sleep(10); + } + + return 0; +} + +#endif //GPIO_MONITOR + +//#define TEST_HARNESS + +#ifdef TEST_HARNESS + +#define GPIO_OFF 0x00005000 /* Offset from IO_START to the GPIO reg's. */ + +/* IO_START and IO_BASE are defined in hardware.h */ + +#define GPIO_START (IO_START_2 + GPIO_OFF) /* Physical addr of the GPIO reg. */ +#define GPIO_BASE_NEW (IO_BASE_2 + GPIO_OFF) /* Virtual addr of the GPIO reg. */ + + +void *myCallBack(void * args) { + printf("Ping\n"); + //struct threadGPIOinterupt *stuff = (struct threadGPIOinterupt *) args; + //printf("Pin is %d\n",stuff->pin); +} + #define PIN 17 #define POUT 27 int main(int argc, char *argv[]) { + int repeat = 3; // if (-1 == GPIOExport(POUT) || -1 == GPIOExport(PIN)) diff --git a/sd_GPIO.h b/sd_GPIO.h index f7fa718..6af0bcb 100644 --- a/sd_GPIO.h +++ b/sd_GPIO.h @@ -11,6 +11,19 @@ #include #include +// check number is between 2 and 27 +#ifndef USE_WIRINGPI +#define GPIO_MIN 2 +#define GPIO_MAX 27 +#else // WiringPI valid numbers +#define GPIO_MIN 0 +#define GPIO_MAX 30 +#endif + +#define validGPIO(X) ((X) <= (GPIO_MAX) ? ( ((X) >= (GPIO_MIN) ? (1) : (0)) ) : (0)) + +#ifndef USE_WIRINGPI // Don't include anything below this line if using wiringpi. + #define INPUT 0 #define OUTPUT 1 @@ -69,13 +82,6 @@ #endif -// check number is between 2 and 27 -#define GPIO_MIN 2 -#define GPIO_MAX 27 - -#define validGPIO(X) ((X) <= (GPIO_MAX) ? ( ((X) >= (GPIO_MIN) ? (1) : (0)) ) : (0)) - - //#ifndef SYSFS_MODE bool pinExport(unsigned pin); bool pinUnexport(unsigned pin); @@ -98,4 +104,5 @@ bool digitalWrite (int pin, int value); #endif */ +#endif /* WiringPI */ #endif /* _SD_GPIO_H_ */ diff --git a/sd_cron.c b/sd_cron.c index 08341ea..5ce06e8 100644 --- a/sd_cron.c +++ b/sd_cron.c @@ -153,9 +153,10 @@ void write_cron() { //length += sprintf(buffer+length, ", \"d%d-starttime\" : \"%.2d:%.2d\" ",day,_sdconfig_.cron[day].hour,_sdconfig_.cron[day].minute); min = _sdconfig_.cron[day].minute; hour = _sdconfig_.cron[day].hour; - for (zone=0; zone < _sdconfig_.zones; zone ++) { + for (zone=1; zone < _sdconfig_.zones; zone ++) { if (_sdconfig_.cron[day].zruntimes[zone] > 0) { - fprintf(fp, "%d %d * * %d root /usr/bin/curl -s -o /dev/null 'localhost?type=cron&zone=%d&runtime=%d&state=on'\n",min,hour,day,zone+1,_sdconfig_.cron[day].zruntimes[zone]); + fprintf(fp, "%d %d * * %d root /usr/bin/curl -s -o /dev/null 'localhost:%s?type=cron&zone=%d&runtime=%d&state=on'\n",min,hour,day,_sdconfig_.socket_port,zone+1,_sdconfig_.cron[day].zruntimes[zone]); + //fprintf(fp, "%d %d * * %d root /usr/bin/curl -s -o /dev/null 'localhost?type=cron&zone=%d&runtime=%d&state=on'\n",min,hour,day,zone+1,_sdconfig_.cron[day].zruntimes[zone]); min = min + _sdconfig_.cron[day].zruntimes[zone]; // NSF Check if to incrument hour. if (min >= 60) { @@ -170,8 +171,8 @@ void write_cron() { } } } - fprintf(fp, "0 0 * * * root /usr/bin/curl -s -o /dev/null 'localhost?type=sensor&sensor=chanceofrain&value=0'\n"); - fprintf(fp, "0 0 * * * root /usr/bin/curl -s -o /dev/null 'localhost?type=sensor&sensor=raintotal&value=0'\n"); + fprintf(fp, "0 0 * * * root /usr/bin/curl -s -o /dev/null 'localhost:%s?type=sensor&sensor=chanceofrain&value=0'\n",_sdconfig_.socket_port); + fprintf(fp, "0 0 * * * root /usr/bin/curl -s -o /dev/null 'localhost:%s?type=sensor&sensor=raintotal&value=0'\n",_sdconfig_.socket_port); fprintf(fp, "#***** AUTO GENERATED DO NOT EDIT *****\n"); fclose(fp); @@ -204,7 +205,7 @@ void read_cron() { for (day=0; day <= 6; day++) { _sdconfig_.cron[day].hour = -1; _sdconfig_.cron[day].minute = -1; - for (zone=0; zone < _sdconfig_.zones; zone ++) { + for (zone=1; zone < _sdconfig_.zones; zone ++) { _sdconfig_.cron[day].zruntimes[zone] = 0; } } diff --git a/sprinkler.c b/sprinkler.c index 7a4f7e0..5a4189c 100644 --- a/sprinkler.c +++ b/sprinkler.c @@ -10,10 +10,12 @@ #ifdef USE_WIRINGPI #define WIRINGPI_CODES 1 #include -#else - #include "sd_GPIO.h" +//#else +// #include "sd_GPIO.h" #endif +#include "sd_GPIO.h" + #include "mongoose.h" #include "utils.h" @@ -39,31 +41,31 @@ void intHandler(int signum); //extern _sdconfig_; #ifdef USE_WIRINGPI /* BS functions due to limitations in wiringpi of not supporting a pointer in callback event */ -// Let's hope no one wants mroe than 24 zones -void event_trigger_0 (void) { event_trigger (&_sdconfig_.zonecfg[0]) ; } -void event_trigger_1 (void) { event_trigger (&_sdconfig_.zonecfg[1]) ; } -void event_trigger_2 (void) { event_trigger (&_sdconfig_.zonecfg[2]) ; } -void event_trigger_3 (void) { event_trigger (&_sdconfig_.zonecfg[3]) ; } -void event_trigger_4 (void) { event_trigger (&_sdconfig_.zonecfg[4]) ; } -void event_trigger_5 (void) { event_trigger (&_sdconfig_.zonecfg[5]) ; } -void event_trigger_6 (void) { event_trigger (&_sdconfig_.zonecfg[6]) ; } -void event_trigger_7 (void) { event_trigger (&_sdconfig_.zonecfg[7]) ; } -void event_trigger_8 (void) { event_trigger (&_sdconfig_.zonecfg[8]) ; } -void event_trigger_9 (void) { event_trigger (&_sdconfig_.zonecfg[9]) ; } -void event_trigger_10 (void) { event_trigger (&_sdconfig_.zonecfg[10]) ; } -void event_trigger_11 (void) { event_trigger (&_sdconfig_.zonecfg[11]) ; } -void event_trigger_12 (void) { event_trigger (&_sdconfig_.zonecfg[12]) ; } -void event_trigger_13 (void) { event_trigger (&_sdconfig_.zonecfg[13]) ; } -void event_trigger_14 (void) { event_trigger (&_sdconfig_.zonecfg[14]) ; } -void event_trigger_15 (void) { event_trigger (&_sdconfig_.zonecfg[15]) ; } -void event_trigger_16 (void) { event_trigger (&_sdconfig_.zonecfg[16]) ; } -void event_trigger_17 (void) { event_trigger (&_sdconfig_.zonecfg[17]) ; } -void event_trigger_18 (void) { event_trigger (&_sdconfig_.zonecfg[18]) ; } -void event_trigger_19 (void) { event_trigger (&_sdconfig_.zonecfg[19]) ; } -void event_trigger_20 (void) { event_trigger (&_sdconfig_.zonecfg[20]) ; } -void event_trigger_21 (void) { event_trigger (&_sdconfig_.zonecfg[21]) ; } -void event_trigger_22 (void) { event_trigger (&_sdconfig_.zonecfg[22]) ; } -void event_trigger_23 (void) { event_trigger (&_sdconfig_.zonecfg[23]) ; } +// Let's hope no one wants mroe than 24 inputs +void event_trigger_0 (void) { event_trigger (&_sdconfig_.inputcfg[0]) ; } +void event_trigger_1 (void) { event_trigger (&_sdconfig_.inputcfg[1]) ; } +void event_trigger_2 (void) { event_trigger (&_sdconfig_.inputcfg[2]) ; } +void event_trigger_3 (void) { event_trigger (&_sdconfig_.inputcfg[3]) ; } +void event_trigger_4 (void) { event_trigger (&_sdconfig_.inputcfg[4]) ; } +void event_trigger_5 (void) { event_trigger (&_sdconfig_.inputcfg[5]) ; } +void event_trigger_6 (void) { event_trigger (&_sdconfig_.inputcfg[6]) ; } +void event_trigger_7 (void) { event_trigger (&_sdconfig_.inputcfg[7]) ; } +void event_trigger_8 (void) { event_trigger (&_sdconfig_.inputcfg[8]) ; } +void event_trigger_9 (void) { event_trigger (&_sdconfig_.inputcfg[9]) ; } +void event_trigger_10 (void) { event_trigger (&_sdconfig_.inputcfg[10]) ; } +void event_trigger_11 (void) { event_trigger (&_sdconfig_.inputcfg[11]) ; } +void event_trigger_12 (void) { event_trigger (&_sdconfig_.inputcfg[12]) ; } +void event_trigger_13 (void) { event_trigger (&_sdconfig_.inputcfg[13]) ; } +void event_trigger_14 (void) { event_trigger (&_sdconfig_.inputcfg[14]) ; } +void event_trigger_15 (void) { event_trigger (&_sdconfig_.inputcfg[15]) ; } +void event_trigger_16 (void) { event_trigger (&_sdconfig_.inputcfg[16]) ; } +void event_trigger_17 (void) { event_trigger (&_sdconfig_.inputcfg[17]) ; } +void event_trigger_18 (void) { event_trigger (&_sdconfig_.inputcfg[18]) ; } +void event_trigger_19 (void) { event_trigger (&_sdconfig_.inputcfg[19]) ; } +void event_trigger_20 (void) { event_trigger (&_sdconfig_.inputcfg[20]) ; } +void event_trigger_21 (void) { event_trigger (&_sdconfig_.inputcfg[21]) ; } +void event_trigger_22 (void) { event_trigger (&_sdconfig_.inputcfg[22]) ; } +void event_trigger_23 (void) { event_trigger (&_sdconfig_.inputcfg[23]) ; } typedef void (*FunctionCallback)(); @@ -139,10 +141,10 @@ int main (int argc, char *argv[]) else _sdconfig_.log_level = LOG_INFO; - readCfg(cfg); - logMessage(LOG_NOTICE,"Starting %s version %s\n",argv[0],SD_VERSION); + readCfg(cfg); + _sdconfig_.calendar = true; _sdconfig_.currentZone.type = zcNONE; _sdconfig_.cron_update = 0; @@ -264,27 +266,23 @@ void main_loop () pinMode (_sdconfig_.zonecfg[i].pin, _sdconfig_.zonecfg[i].input_output); if ( _sdconfig_.zonecfg[i].startup_state != -1) digitalWrite(_sdconfig_.zonecfg[i].pin, _sdconfig_.zonecfg[i].startup_state); -/* - // We actually don't need to register a interupt handeler for outputs. But we will for inputs, so leave this here for future use. - if (registerGPIOinterrupt (_sdconfig_.zonecfg[i].pin, _sdconfig_.zonecfg[i].receive_mode, (void *)&event_trigger, (void *)&_sdconfig_.zonecfg[i]) != true) + + logMessage (LOG_DEBUG, "Set GPIO %d to %s\n", _sdconfig_.zonecfg[i].pin,(_sdconfig_.zonecfg[i].input_output==OUTPUT?"OUTPUT":"INPUT") ); + + } + + for (i=0; i < _sdconfig_.inputs ; i++) + { + logMessage (LOG_DEBUG, "Setting up Input %d\n", i); + pinMode (_sdconfig_.inputcfg[i].pin, _sdconfig_.inputcfg[i].input_output); + if (registerGPIOinterrupt (_sdconfig_.inputcfg[i].pin, _sdconfig_.inputcfg[i].receive_mode, (void *)&event_trigger, (void *)&_sdconfig_.inputcfg[i]) != true) { displayLastSystemError ("Unable to set interrupt handler for specified pin, exiting"); exit (EXIT_FAILURE); } -*/ - logMessage (LOG_DEBUG, "Set GPIO %d to %s\n", _sdconfig_.zonecfg[i].pin,(_sdconfig_.zonecfg[i].input_output==OUTPUT?"OUTPUT":"INPUT") ); - } #endif -/* - for (i=0; i < _sdconfig_.pinscfgs ; i++) - { - if ( _sdconfig_.zonecfg[i].startup_state == 0 || _sdconfig_.zonecfg[i].startup_state == 1 ) { - logMessage (LOG_DEBUG, "Setting pin %d to state %d\n", _sdconfig_.zonecfg[i].pin, _sdconfig_.zonecfg[i].startup_state); - digitalWrite(_sdconfig_.zonecfg[i].pin, _sdconfig_.zonecfg[i].startup_state); - } - } -*/ + logMessage (LOG_DEBUG, "GPIO setup complete\n"); logMessage (LOG_DEBUG, "Starting HTTPD\n"); @@ -385,56 +383,34 @@ void event_trigger (struct GPIOcfg *gpiopin) //int out_state_toset; int in_state_read; time_t rawtime; - struct tm * timeinfo; - char timebuffer[20]; + //struct tm * timeinfo; + //char timebuffer[20]; //bool changed=false; time (&rawtime); - timeinfo = localtime (&rawtime); - strftime (timebuffer,20,"%T",timeinfo); + //timeinfo = localtime (&rawtime); + //strftime (timebuffer,20,"%T",timeinfo); - - //printf("Received trigger %d - at %s - last trigger %d\n",digitalRead (gpioconfig->pin), timebuffer, gpioconfig->last_event_state); - - logMessage (LOG_DEBUG,"%s Received input change on pin %d - START\n",timebuffer, gpiopin->pin); + logMessage (LOG_INFO,"Received input change on pin %d\n", gpiopin->pin); if ( (rawtime - gpiopin->last_event_time) < 1 && gpiopin->input_output == INPUT) { - logMessage (LOG_DEBUG," ignoring, time between triggers too short (%d-%d)=%d\n",rawtime, gpiopin->last_event_time, (rawtime - gpiopin->last_event_time)); + logMessage (LOG_DEBUG,"Ignoring input event on pin %d, time between triggers too short (%d-%d)=%d\n",gpiopin->pin,rawtime, gpiopin->last_event_time, (rawtime - gpiopin->last_event_time)); return; } gpiopin->last_event_time = rawtime; - //logMessage (LOG_DEBUG,"Diff between last event %d (%d, %d)\n",rawtime - gpioconfig->last_event_time, rawtime, gpioconfig->last_event_time); - - /* Handle button pressed interrupts */ - + in_state_read = digitalRead (gpiopin->pin); - //logMessage (LOG_DEBUG, " Init pin state %d, previous state %d\n", in_state_read, gpiopin->last_event_state); - - //if ( gpioconfig->receive_state == BOTH || in_state_read == gpioconfig->receive_state) - //{ + gpiopin->last_event_state = in_state_read; + + if ( in_state_read == gpiopin->on_state && strlen(gpiopin->command_on) > 0) + run_external(gpiopin->command_on); + else if ( in_state_read == !gpiopin->on_state && strlen(gpiopin->command_off) > 0) + run_external(gpiopin->command_off); - /* - if (gpiopin->ext_cmd != NULL && strlen(gpiopin->ext_cmd) > 0) { - //logMessage (LOG_DEBUG, "command '%s'\n", gpioconfig->ext_cmd); - run_external(gpiopin->ext_cmd, in_state_read); - } - */ - //sleep(1); - //} else { - // logMessage (LOG_DEBUG," ignoring, reseived state does not match cfg\n"); - // return; + //if (_mgr.active_connections != NULL) { + // _sdconfig_.eventToUpdateHappened = true; //} - - // Sleep for 1 second just to limit duplicte events - //sleep(1); - - logMessage (LOG_DEBUG,"%s Receive input change on pin %d - END\n",timebuffer, gpiopin->pin); - //if (changed ==true ) - if (_mgr.active_connections != NULL) { - _sdconfig_.eventToUpdateHappened = true; - //broadcast_zonestate(_mgr.active_connections, gpiopin); - } } diff --git a/utils.c b/utils.c index bf4b8e7..08c475f 100644 --- a/utils.c +++ b/utils.c @@ -301,13 +301,11 @@ char * replace(char const * const original, char const * const pattern, char con } } -void run_external(char *command, int state) +void run_external(char *command) { - char *cmd = replace(command, "%STATE%", (state==1?"1":"0")); - system(cmd); - logMessage (LOG_DEBUG, "Ran command '%s'\n", cmd); - free(cmd); + system(command); + logMessage (LOG_DEBUG, "Ran command '%s'\n", command); return; } diff --git a/utils.h b/utils.h index 00bc01d..f96a50b 100644 --- a/utils.h +++ b/utils.h @@ -16,7 +16,7 @@ void daemonise ( char *pidFile, void (*main_function)(void) ); void displayLastSystemError (const char *on_what); void logMessage(int level, char *format, ...); int count_characters(const char *str, char character); -void run_external(char *command, int state); +void run_external(char *command); int str2int(const char* str, int len); float str2float(const char* str, int len); //void readCfg (char *cfgFile); diff --git a/version.h b/version.h index a0697e5..2f10d81 100644 --- a/version.h +++ b/version.h @@ -1,6 +1,6 @@ #ifndef SD_VERSION_H #define SD_VERSION_H -#define SD_VERSION "1.0f" +#define SD_VERSION "1.0g" #endif diff --git a/zone_ctrl.c b/zone_ctrl.c index f1131a2..6ad5f76 100644 --- a/zone_ctrl.c +++ b/zone_ctrl.c @@ -42,8 +42,9 @@ int start_next_zone(int startz) { int zone = startz+1; - while( _sdconfig_.zonecfg[zone].default_runtime <= 0 ) { - logMessage (LOG_INFO, "Run Zone, skipping zone %d due to runtime of %d\n",zone,_sdconfig_.zonecfg[zone].default_runtime); + while( _sdconfig_.zonecfg[zone].default_runtime <= 0 || !validGPIO( _sdconfig_.zonecfg[zone].pin) ) { + //logMessage (LOG_INFO, "Run Zone, skipping zone %d due to runtime of %d\n",zone,_sdconfig_.zonecfg[zone].default_runtime); + logMessage (LOG_INFO, "Run Zone, skipping zone %d due to %s\n",zone,_sdconfig_.zonecfg[zone].default_runtime<=0?" runtime of 0":" bad GPIO pin#"); zone++; if (zone > _sdconfig_.zones) { // No more zones left to run, turn everything off _sdconfig_.currentZone.type=zcNONE; @@ -54,12 +55,17 @@ int start_next_zone(int startz) { } } - _sdconfig_.currentZone.zone=zone; - zc_start(_sdconfig_.currentZone.zone); - zc_master(zcON); - time(&_sdconfig_.currentZone.started_time); - _sdconfig_.currentZone.duration=_sdconfig_.zonecfg[_sdconfig_.currentZone.zone].default_runtime; - calc_timeleft(); + if ( zc_start(zone) == true) { + _sdconfig_.currentZone.zone=zone; + zc_master(zcON); + time(&_sdconfig_.currentZone.started_time); + _sdconfig_.currentZone.duration=_sdconfig_.zonecfg[_sdconfig_.currentZone.zone].default_runtime; + calc_timeleft(); + + } else { + logMessage (LOG_ERR, "Run Zone, failed to start zone %d, check GPIO\n",zone); + return start_next_zone(zone); + } return zone; } @@ -178,15 +184,19 @@ bool zc_zone(zcRunType type, int zone, zcState state, int length) { zc_stop(i); } } - zc_start(zone); - zc_master(zcON); - _sdconfig_.currentZone.type=type; - _sdconfig_.currentZone.zone=zone; - _sdconfig_.currentZone.duration=length; - logMessage (LOG_DEBUG, "set runtime to %d and %d\n",length,_sdconfig_.currentZone.duration); - time(&_sdconfig_.currentZone.started_time); - calc_timeleft(); - return true; + if ( zc_start(zone) == true) { + zc_master(zcON); + _sdconfig_.currentZone.type=type; + _sdconfig_.currentZone.zone=zone; + _sdconfig_.currentZone.duration=length; + logMessage (LOG_DEBUG, "set runtime to %d and %d\n",length,_sdconfig_.currentZone.duration); + time(&_sdconfig_.currentZone.started_time); + calc_timeleft(); + return true; + } else { + logMessage (LOG_ERR, "Request to turn on zone %d failed, check GPIO\n",zone); + return false; + } } else { logMessage (LOG_WARNING, "Request to turn zone %d on. Ignored due to runtime being %d\n",zone,length); return false; @@ -206,38 +216,45 @@ bool zc_zone(zcRunType type, int zone, zcState state, int length) { return false; } + bool zc_start(/*zcRunType type,*/ int zone) { - // check anything on, turn off - - // Turn on master valve if we have one - // turn on zone + // Check if zone is already on if ( _sdconfig_.zonecfg[zone].on_state == digitalRead (_sdconfig_.zonecfg[zone].pin)) { logMessage (LOG_DEBUG, "Request to turn zone %d on. Zone %d is already on, ignoring!\n",zone,zone); return false; } logMessage (LOG_NOTICE, "Turning on Zone %d\n",zone); +#ifndef USE_WIRINGPI + int rtn = digitalWrite(_sdconfig_.zonecfg[zone].pin, _sdconfig_.zonecfg[zone].on_state ); +#else digitalWrite(_sdconfig_.zonecfg[zone].pin, _sdconfig_.zonecfg[zone].on_state ); + int rtn = true; +#endif _sdconfig_.eventToUpdateHappened = true; // store what's running - - return true; + if (rtn == true) + return true; + else + return false; } bool zc_stop(/*zcRunType type,*/ int zone) { - - // Turn on master valve if we have one - + // Check if zone is alreay off if ( _sdconfig_.zonecfg[zone].on_state != digitalRead (_sdconfig_.zonecfg[zone].pin)) { logMessage (LOG_DEBUG, "Request to turn zone %d off. Zone %d is already off, ignoring!\n",zone,zone); return false; } logMessage (LOG_NOTICE, "Turning off Zone %d\n",zone); +#ifndef USE_WIRINGPI + int rtn = digitalWrite(_sdconfig_.zonecfg[zone].pin, !_sdconfig_.zonecfg[zone].on_state ); +#else digitalWrite(_sdconfig_.zonecfg[zone].pin, !_sdconfig_.zonecfg[zone].on_state ); + int rtn = true; +#endif _sdconfig_.eventToUpdateHappened = true; - //_sdconfig_.zonecfg[zone] - // turn off zone - // delete what's running - - return true; + if (rtn == true) + return true; + else + return false; }