update to gpio
parent
42d5db40e2
commit
827eac8ecd
2
Makefile
2
Makefile
|
@ -10,7 +10,7 @@ else
|
|||
WPI_LIB := -D USE_WIRINGPI -lwiringPi
|
||||
endif
|
||||
|
||||
LIBS := $(WPI_LIB) -lm
|
||||
LIBS := $(WPI_LIB) -lm -lpthread
|
||||
#LIBS := -lpthread -lwiringPi -lwiringPiDev -lm
|
||||
#LIBS := -lpthread -lwebsockets
|
||||
|
||||
|
|
32
README.md
32
README.md
|
@ -107,26 +107,32 @@ Create a device for each piece of pool equiptment you have, eg Filter Pump, Spa
|
|||
```
|
||||
http://sprinklerd.ip.address:port?type=option&option=24hdelay&state=off
|
||||
```
|
||||
```
|
||||
* // Info options
|
||||
* ?type=firstload // JSON status Include cal schedule
|
||||
* ?type=read // JSON status no need to include cal schedule
|
||||
<host>?type=firstload // JSON status Include cal schedule
|
||||
<host>?type=read // JSON status no need to include cal schedule
|
||||
<host>?type=json // JSON full array style, need full parser to pass.
|
||||
|
||||
* // Cfg options
|
||||
* ?type=option&option=24hdelay&state=off // turn off 24h delay
|
||||
* ?type=option&option=calendar&state=off // turn off calendar
|
||||
<host>?type=option&option=24hdelay&state=off // turn off 24h delay
|
||||
<host>?type=option&option=calendar&state=off // turn off calendar
|
||||
<host>?type=option&option=24hdelay&state=reset // reset time on 24h delay
|
||||
|
||||
* // Calendar
|
||||
* ?type=calcfg&day=3&zone=&time=07:00 // Use default water zone times
|
||||
* ?type=calcfg&day=2&zone=1&time=7 // Change water zone time
|
||||
* ?type=calcfg&day=3&zone=&time= // Delete day schedule
|
||||
<host>?type=calcfg&day=3&zone=&time=07:00 // Use default water zone times
|
||||
<host>?type=calcfg&day=2&zone=1&time=7 // Change water zone time
|
||||
<host>?type=calcfg&day=3&zone=&time= // Delete day schedule
|
||||
|
||||
* // Run options
|
||||
* ?type=option&option=allz&state=on // Run all zones default times
|
||||
* ?type=zone&zone=2&state=on&runtime=3 // Run zone 2 for 3 mins (ignore 24h delay & calendar settings)
|
||||
* ?type=zrtcfg&zone=2&time=10 // change zone 2 default runtime to 10
|
||||
* ?type=cron&zone=1&runtime=12' // Run zone 1 for 12 mins (calendar & 24hdelay settings overide this request)
|
||||
|
||||
The JSON that's returned is completley flat, this is so it can be passed with really small lightweight passers, even grep and awk. I will eventually add a more complex JSON output that will make it better for people using fill JSON object passers.
|
||||
<host>?type=option&option=allz&state=on // Run all zones default times
|
||||
<host>?type=zone&zone=2&state=on&runtime=3 // Run zone 2 for 3 mins (ignore 24h delay & calendar settings)
|
||||
<host>?type=zrtcfg&zone=2&time=10 // change zone 2 default runtime to 10
|
||||
<host>?type=cron&zone=1&runtime=12' // Run zone 1 for 12 mins (calendar & 24hdelay settings overide this request)
|
||||
```
|
||||
The JSON that's returned is completley flat, this is so it can be passed with really small lightweight passers, even grep and awk. If you want a full JSON with arrays that's easier to use with full json parsers you can use the below
|
||||
```
|
||||
<host>?type=json
|
||||
```
|
||||
|
||||
|
||||
## Apple HomeKit
|
||||
|
|
54
config.c
54
config.c
|
@ -7,8 +7,10 @@
|
|||
|
||||
#ifdef USE_WIRINGPI
|
||||
#include <wiringPi.h>
|
||||
#define PIN_CFG_NAME "WPI_PIN"
|
||||
#else
|
||||
#include "sd_GPIO.h"
|
||||
#define PIN_CFG_NAME "GPIO_PIN"
|
||||
#endif
|
||||
|
||||
#include "minIni.h"
|
||||
|
@ -16,7 +18,6 @@
|
|||
#include "config.h"
|
||||
|
||||
|
||||
|
||||
#define sizearray(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define MAXCFGLINE 256
|
||||
|
@ -249,7 +250,7 @@ void readCfg(char *inifile)
|
|||
for (i=1; i <= 24; i++) // 24 = Just some arbutary number (max GPIO without expansion board)
|
||||
{
|
||||
sprintf(str, "ZONE:%d", i);
|
||||
pin = ini_getl(str, "GPIO_PIN", -1, inifile);
|
||||
pin = ini_getl(str, PIN_CFG_NAME, -1, inifile);
|
||||
if (pin == -1)
|
||||
break;
|
||||
else
|
||||
|
@ -267,11 +268,7 @@ void readCfg(char *inifile)
|
|||
for (i=0; i <= _sdconfig_.zones; i++)
|
||||
{
|
||||
sprintf(str, "ZONE:%d", i);
|
||||
#ifdef USE_WIRINGPI
|
||||
int pin = ini_getl(str, "WPI_PIN", -1, inifile);
|
||||
#else
|
||||
int pin = ini_getl(str, "GPIO_PIN", -1, inifile);
|
||||
#endif
|
||||
pin = ini_getl(str, PIN_CFG_NAME, -1, inifile);
|
||||
if (pin != -1) {
|
||||
logMessage (LOG_DEBUG, "ZONE = %d\n", i);
|
||||
if (i==0) {
|
||||
|
@ -307,8 +304,8 @@ void readCfg(char *inifile)
|
|||
}
|
||||
}
|
||||
|
||||
_sdconfig_.pinscfgs = idx;
|
||||
logMessage (LOG_DEBUG,"Config: total GPIO pins = %d\n",_sdconfig_.pinscfgs);
|
||||
//_sdconfig_.pinscfgs = idx;
|
||||
//logMessage (LOG_DEBUG,"Config: total GPIO pins = %d\n",_sdconfig_.pinscfgs);
|
||||
|
||||
_sdconfig_.cron[0].zruntimes = malloc(_sdconfig_.zones * sizeof(int));
|
||||
_sdconfig_.cron[1].zruntimes = malloc(_sdconfig_.zones * sizeof(int));
|
||||
|
@ -323,4 +320,43 @@ void readCfg(char *inifile)
|
|||
logMessage (LOG_ERR," no config zones set\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
/*
|
||||
idx=0;
|
||||
pin=-1;
|
||||
// Caculate how many gpio cfg we have
|
||||
for (i=1; i <= 24; i++) // 24 = Just some arbutary number (max GPIO without expansion board)
|
||||
{
|
||||
sprintf(str, "GPIO:%d", i);
|
||||
pin = ini_getl(str, PIN_CFG_NAME, -1, inifile);
|
||||
if (pin == -1)
|
||||
break;
|
||||
else
|
||||
_sdconfig_.pincfgs = i;
|
||||
}
|
||||
|
||||
logMessage (LOG_DEBUG, "Found %d GPIO PINS\n", _sdconfig_.pincfgs);
|
||||
|
||||
if ( _sdconfig_.pincfgs != 0) {
|
||||
// n= _sdconfig_.zones+1;
|
||||
_sdconfig_.gpiocfg = malloc((_sdconfig_.pincfgs + 1) * sizeof(struct GPIOcfg));
|
||||
for (i=0; i <= _sdconfig_.pincfgs; i++)
|
||||
{
|
||||
sprintf(str, "GPIO:%d", i);
|
||||
int pin = ini_getl(str, PIN_CFG_NAME, -1, inifile);
|
||||
|
||||
if (pin != -1) {
|
||||
logMessage (LOG_DEBUG, "ZONE = %d\n", i);
|
||||
_sdconfig_.pincfgs[i].input_output = OUTPUT; // Zone is always output
|
||||
_sdconfig_.pincfgs[i].receive_mode = BOTH; // Zone always needs trigger on both (high or low)
|
||||
|
||||
ini_gets(str, "NAME", NULL, _sdconfig_.pincfgs[idx].name, sizearray(_sdconfig_.pincfgs[idx].name), inifile);
|
||||
_sdconfig_.pincfgs[i].pin = pin;
|
||||
_sdconfig_.pincfgs[i].on_state = ini_getl(str, "GPIO_ON_STATE", NO, inifile);
|
||||
_sdconfig_.pincfgs[i].startup_state = !_sdconfig_.pincfgs[i].on_state;
|
||||
_sdconfig_.pincfgs[i].shutdown_state = !_sdconfig_.pincfgs[i].on_state;
|
||||
|
||||
_sdconfig_.pincfgs[i].set_pull_updown = ini_getl(str, "GPIO_PULL_UPDN", -1, inifile);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
14
config.h
14
config.h
|
@ -17,13 +17,19 @@
|
|||
|
||||
#define LABEL_SIZE 40
|
||||
#define NON_ZONE_DZIDS 3
|
||||
#define COMMAND_SIZE 512
|
||||
|
||||
struct CALENDARday {
|
||||
int hour;
|
||||
int minute;
|
||||
int *zruntimes;
|
||||
};
|
||||
|
||||
/*
|
||||
struct GPIOextra {
|
||||
char command_high[COMMAND_SIZE];
|
||||
char command_low[COMMAND_SIZE];
|
||||
};
|
||||
*/
|
||||
struct GPIOcfg {
|
||||
int pin;
|
||||
int input_output;
|
||||
|
@ -37,10 +43,11 @@ struct GPIOcfg {
|
|||
int startup_state;
|
||||
int shutdown_state;
|
||||
int dz_idx;
|
||||
int ignore_requests;
|
||||
//int ignore_requests;
|
||||
int zone;
|
||||
int default_runtime;
|
||||
bool master_valve;
|
||||
//struct GPIOextra *extra;
|
||||
};
|
||||
|
||||
struct DZcache {
|
||||
|
@ -64,14 +71,15 @@ struct sprinklerdcfg {
|
|||
int dzidx_allzones;
|
||||
bool enableMQTTdz;
|
||||
bool enableMQTTaq;
|
||||
int pinscfgs;
|
||||
int zones;
|
||||
//int pincfgs;
|
||||
bool system;
|
||||
bool delay24h;
|
||||
long delay24h_time;
|
||||
bool master_valve;
|
||||
struct DZcache *dz_cache;
|
||||
struct GPIOcfg *zonecfg;
|
||||
//struct GPIOcfg *gpiocfg;
|
||||
struct CALENDARday cron[7];
|
||||
//time_t cron_update;
|
||||
long cron_update;
|
||||
|
|
|
@ -80,7 +80,7 @@ int build_sprinkler_JSON(char* buffer, int size)
|
|||
|
||||
int build_advanced_sprinkler_JSON(char* buffer, int size)
|
||||
{
|
||||
int i;
|
||||
int i, day;
|
||||
memset(&buffer[0], 0, size);
|
||||
int length = 0;
|
||||
|
||||
|
@ -102,8 +102,27 @@ int build_advanced_sprinkler_JSON(char* buffer, int size)
|
|||
_sdconfig_.zonecfg[i].default_runtime
|
||||
);
|
||||
}
|
||||
if (_sdconfig_.currentZone.type != zcNONE)
|
||||
length += sprintf(buffer+length, "\"active\": {\"zone\": %d, \"name\": \"%s\"},",_sdconfig_.currentZone.zone, _sdconfig_.zonecfg[_sdconfig_.currentZone.zone].name);
|
||||
|
||||
length += sprintf(buffer+length-1, "}}");
|
||||
length -= 1;
|
||||
length += sprintf( buffer+length , "}, \"calendar\": {" );
|
||||
|
||||
for (day=0; day <= 6; day++) {
|
||||
if (_sdconfig_.cron[day].hour >= 0 && _sdconfig_.cron[day].minute >= 0) {
|
||||
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 ++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
length -= 1;
|
||||
length += sprintf(buffer+length, "},");
|
||||
}
|
||||
}
|
||||
length -= 1;
|
||||
length += sprintf(buffer+length, "}}");
|
||||
|
||||
buffer[length] = '\0';
|
||||
return strlen(buffer);
|
||||
|
|
|
@ -367,7 +367,12 @@ int serve_web_request(struct mg_connection *nc, struct http_message *http_msg, c
|
|||
length = build_sprinkler_JSON(buffer, size);
|
||||
} else if (strncasecmp(buf, "24hdelay", 8) == 0 ) {
|
||||
mg_get_http_var(&http_msg->query_string, "state", buf, buflen);
|
||||
enable_delay24h(is_value_ON(buf));
|
||||
int val = is_value_ON(buf);
|
||||
if (val == true || val == false) {
|
||||
enable_delay24h(val);
|
||||
} else if (strncasecmp(buf, "reset", 5) == 0) {
|
||||
reset_delay24h_time();
|
||||
}
|
||||
length = build_sprinkler_JSON(buffer, size);
|
||||
} else if (strncasecmp(buf, "allz", 8) == 0 ) {
|
||||
mg_get_http_var(&http_msg->query_string, "state", buf, buflen);
|
||||
|
|
Binary file not shown.
|
@ -118,3 +118,24 @@ WPI_PIN=22
|
|||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=207
|
||||
|
||||
|
||||
#PIN
|
||||
#NAME name
|
||||
#PIN_MODE Setup as input or output
|
||||
#PULL_UPDN setup pull up pull down resistor NONE|PUD_OFF|PUD_DOWN|PUD_UP
|
||||
#TRIGGER_EVENT_ON trigger_event on NONE|INT_EDGE_SETUP|INT_EDGE_FALLING|INT_EDGE_RISING|INT_EDGE_BOTH
|
||||
#TRIGGER_EVENT_STATE trigger_event_received_state LOW|HIGH|BOTH
|
||||
#COMMAND triggered_event_runcmd = external command to run
|
||||
#DOMOTICZ_IDX Domoticz IDX
|
||||
|
||||
[GPIO]
|
||||
[GPIO:1]
|
||||
NAME=Rain Sensor
|
||||
GPIO_PIN=4
|
||||
WPI_PIN=7
|
||||
PIN_MODE=0
|
||||
#PULL_UPDN=0
|
||||
TRIGGER_EVENT_ON=3
|
||||
COMMAND_HIGH=/usr/bin/curl -s -o /dev/null 'http://localhost?type=option&option=24hdelay&state=on'
|
||||
COMMAND_LOW=/usr/bin/curl -s -o /dev/null 'http://localhost?type=option&option=24hdelay&state=off'
|
||||
|
|
454
sd_GPIO.c
454
sd_GPIO.c
|
@ -4,55 +4,136 @@
|
|||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
/*
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
*/
|
||||
#include "sd_GPIO.h"
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
bool pinExport(int pin)
|
||||
{
|
||||
#include "sd_GPIO.h"
|
||||
|
||||
char buffer[SYSFS_READ_MAX];
|
||||
ssize_t bytes_written;
|
||||
int fd;
|
||||
|
||||
fd = open("/sys/class/gpio/export", O_WRONLY);
|
||||
if (-1 == fd) {
|
||||
//fprintf(stderr, "Failed to open export for writing!\n");
|
||||
logMessage (LOG_ERR, "Failed to open '/sys/class/gpio/export' for writing!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes_written = snprintf(buffer, SYSFS_READ_MAX, "%d", pin);
|
||||
write(fd, buffer, bytes_written);
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pinUnexport(int pin)
|
||||
#ifndef GPIO_SYSFS_MODE
|
||||
|
||||
static volatile uint32_t * _gpioReg = MAP_FAILED;
|
||||
static bool _ever = false;
|
||||
|
||||
void gpioDelay (unsigned int howLong) // Microseconds (1000000 = 1 second)
|
||||
{
|
||||
char buffer[SYSFS_READ_MAX];
|
||||
ssize_t bytes_written;
|
||||
int fd;
|
||||
|
||||
fd = open("/sys/class/gpio/unexport", O_WRONLY);
|
||||
if (-1 == fd) {
|
||||
//fprintf(stderr, "Failed to open unexport for writing!\n");
|
||||
logMessage (LOG_ERR, "Failed to open '/sys/class/gpio/unexport' for writing!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes_written = snprintf(buffer, SYSFS_READ_MAX, "%d", pin);
|
||||
write(fd, buffer, bytes_written);
|
||||
close(fd);
|
||||
return true;
|
||||
struct timespec sleeper, dummy ;
|
||||
|
||||
sleeper.tv_sec = (time_t)(howLong / 1000) ;
|
||||
sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ;
|
||||
|
||||
nanosleep (&sleeper, &dummy) ;
|
||||
}
|
||||
|
||||
bool pinMode (int pin, int mode)
|
||||
bool gpioSetup() {
|
||||
int fd;
|
||||
|
||||
fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
|
||||
if (fd<0)
|
||||
{
|
||||
logMessage (LOG_ERR, "Failed to open '/dev/mem' for GPIO access (are we root?)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
_gpioReg = mmap
|
||||
(
|
||||
0,
|
||||
GPIO_LEN,
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_SHARED|MAP_LOCKED,
|
||||
fd,
|
||||
GPIO_BASE);
|
||||
|
||||
close(fd);
|
||||
|
||||
_ever = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int pinMode(unsigned gpio, unsigned mode) {
|
||||
int reg, shift;
|
||||
|
||||
reg = gpio / 10;
|
||||
shift = (gpio % 10) * 3;
|
||||
|
||||
_gpioReg[reg] = (_gpioReg[reg] & ~(7 << shift)) | (mode << shift);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int getPinMode(unsigned gpio) {
|
||||
int reg, shift;
|
||||
|
||||
reg = gpio / 10;
|
||||
shift = (gpio % 10) * 3;
|
||||
|
||||
return (*(_gpioReg + reg) >> shift) & 7;
|
||||
}
|
||||
|
||||
int digitalRead(unsigned gpio) {
|
||||
unsigned bank, bit;
|
||||
|
||||
bank = gpio >> 5;
|
||||
|
||||
bit = (1 << (gpio & 0x1F));
|
||||
|
||||
if ((*(_gpioReg + GPLEV0 + bank) & bit) != 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int digitalWrite(unsigned gpio, unsigned level) {
|
||||
unsigned bank, bit;
|
||||
|
||||
bank = gpio >> 5;
|
||||
|
||||
bit = (1 << (gpio & 0x1F));
|
||||
|
||||
if (level == 0)
|
||||
*(_gpioReg + GPCLR0 + bank) = bit;
|
||||
else
|
||||
*(_gpioReg + GPSET0 + bank) = bit;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setPullUpDown(unsigned gpio, unsigned pud)
|
||||
{
|
||||
unsigned bank, bit;
|
||||
|
||||
bank = gpio >> 5;
|
||||
|
||||
bit = (1 << (gpio & 0x1F));
|
||||
|
||||
/*
|
||||
if (gpio > PI_MAX_GPIO)
|
||||
SOFT_ERROR(PI_BAD_GPIO, "bad gpio (%d)", gpio);
|
||||
*/
|
||||
if (pud > PUD_UP || pud < PUD_OFF)
|
||||
return false;
|
||||
//SOFT_ERROR(PI_BAD_PUD, "gpio %d, bad pud (%d)", gpio, pud);
|
||||
|
||||
*(_gpioReg + GPPUD) = pud;
|
||||
gpioDelay(1);
|
||||
*(_gpioReg + GPPUDCLK0 + bank) = bit;
|
||||
gpioDelay(1);
|
||||
*(_gpioReg + GPPUD) = 0;
|
||||
|
||||
*(_gpioReg + GPPUDCLK0 + bank) = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
|
||||
bool gpioSetup() {return true;}
|
||||
|
||||
int pinMode (unsigned pin, unsigned mode)
|
||||
{
|
||||
//static const char s_directions_str[] = "in\0out\0";
|
||||
|
||||
|
@ -85,7 +166,7 @@ bool pinMode (int pin, int mode)
|
|||
return true;
|
||||
}
|
||||
|
||||
int digitalRead (int pin)
|
||||
int digitalRead (unsigned pin)
|
||||
{
|
||||
char path[SYSFS_PATH_MAX];
|
||||
char value_str[SYSFS_READ_MAX];
|
||||
|
@ -111,7 +192,7 @@ int digitalRead (int pin)
|
|||
return(atoi(value_str));
|
||||
}
|
||||
|
||||
bool digitalWrite (int pin, int value)
|
||||
int digitalWrite (unsigned pin, unsigned value)
|
||||
{
|
||||
//static const char s_values_str[] = "01";
|
||||
|
||||
|
@ -137,35 +218,157 @@ bool digitalWrite (int pin, int value)
|
|||
close(fd);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
int waitForInterrupt (int pin, int mS)
|
||||
bool isExported(unsigned pin)
|
||||
{
|
||||
char path[SYSFS_PATH_MAX];
|
||||
int fd, x ;
|
||||
char path[SYSFS_PATH_MAX];
|
||||
struct stat sb;
|
||||
|
||||
snprintf(path, SYSFS_PATH_MAX, "/sys/class/gpio/gpio%d/", pin);
|
||||
|
||||
if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pinExport(unsigned pin)
|
||||
{
|
||||
|
||||
char buffer[SYSFS_READ_MAX];
|
||||
ssize_t bytes_written;
|
||||
int fd;
|
||||
|
||||
fd = open("/sys/class/gpio/export", O_WRONLY);
|
||||
if (-1 == fd) {
|
||||
//fprintf(stderr, "Failed to open export for writing!\n");
|
||||
logMessage (LOG_ERR, "Failed to open '/sys/class/gpio/export' for writing!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes_written = snprintf(buffer, SYSFS_READ_MAX, "%d", pin);
|
||||
write(fd, buffer, bytes_written);
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pinUnexport(unsigned pin)
|
||||
{
|
||||
char buffer[SYSFS_READ_MAX];
|
||||
ssize_t bytes_written;
|
||||
int fd;
|
||||
|
||||
fd = open("/sys/class/gpio/unexport", O_WRONLY);
|
||||
if (-1 == fd) {
|
||||
//fprintf(stderr, "Failed to open unexport for writing!\n");
|
||||
logMessage (LOG_ERR, "Failed to open '/sys/class/gpio/unexport' for writing!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes_written = snprintf(buffer, SYSFS_READ_MAX, "%d", pin);
|
||||
write(fd, buffer, bytes_written);
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool edgeSetup (unsigned pin, unsigned value)
|
||||
{
|
||||
//static const char s_values_str[] = "01";
|
||||
|
||||
char path[SYSFS_PATH_MAX];
|
||||
int fd;
|
||||
|
||||
snprintf(path, SYSFS_PATH_MAX, "/sys/class/gpio/gpio%d/edge", pin);
|
||||
fd = open(path, O_WRONLY);
|
||||
if (-1 == fd) {
|
||||
//fprintf(stderr, "Failed to open gpio value for writing!\n");
|
||||
logMessage (LOG_ERR, "Failed to open gpio '%s' for writing!\n",path);
|
||||
return false;
|
||||
}
|
||||
|
||||
int rtn = 0;
|
||||
if (value==INT_EDGE_RISING)
|
||||
rtn = write(fd, "rising", 6);
|
||||
else if (value==INT_EDGE_FALLING)
|
||||
rtn = write(fd, "falling", 7);
|
||||
else if (value==INT_EDGE_BOTH)
|
||||
rtn = write(fd, "both", 4);
|
||||
else
|
||||
rtn = write(fd, "none", 4);
|
||||
|
||||
if (rtn <= 0) {
|
||||
logMessage (LOG_ERR, "Failed to setup edge on '%s'!\n",path);
|
||||
displayLastSystemError("");
|
||||
return false;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
struct threadGPIOinterupt{
|
||||
void (*function)(void *args);
|
||||
void *args;
|
||||
unsigned pin;
|
||||
};
|
||||
static pthread_mutex_t pinMutex ;
|
||||
|
||||
#define MAX_FDS 64
|
||||
static unsigned int _sysFds [MAX_FDS] =
|
||||
{
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
} ;
|
||||
|
||||
void pushSysFds(int fd)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i< MAX_FDS; i++) {
|
||||
if (_sysFds[i] == -1) {
|
||||
_sysFds[i] = fd;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gpioShutdown() {
|
||||
int i;
|
||||
_ever = false;
|
||||
|
||||
for (i=0; i< MAX_FDS; i++) {
|
||||
if (_sysFds[i] != -1) {
|
||||
printf("Closing fd\n");
|
||||
close(_sysFds[i]);
|
||||
_sysFds[i] = -1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int waitForInterrupt (int pin, int mS, int fd)
|
||||
{
|
||||
int x;
|
||||
uint8_t c ;
|
||||
struct pollfd polls ;
|
||||
//struct pollfd pfd;
|
||||
|
||||
sprintf(path, "/sys/class/gpio/gpio%d/value", pin);
|
||||
|
||||
if ((fd = open(path, O_RDONLY)) < 0)
|
||||
{
|
||||
logMessage (LOG_ERR, "Failed to open '%s'!\n",path);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Setup poll structure
|
||||
|
||||
// Setup poll structure
|
||||
polls.fd = fd ;
|
||||
polls.events = POLLPRI | POLLERR ;
|
||||
|
||||
// Wait for it ...
|
||||
polls.events = POLLPRI | POLLERR | POLLHUP | POLLNVAL;
|
||||
|
||||
// Wait for something ...
|
||||
|
||||
x = poll (&polls, 1, mS) ;
|
||||
|
||||
// If no error, do a dummy read to clear the interrupt
|
||||
// A one character read appars to be enough.
|
||||
// If no error, do a dummy read to clear the interrupt
|
||||
// A one character read appars to be enough.
|
||||
|
||||
if (x > 0)
|
||||
{
|
||||
|
@ -176,62 +379,98 @@ int waitForInterrupt (int pin, int mS)
|
|||
return x ;
|
||||
}
|
||||
|
||||
|
||||
static volatile int pinPass = -1 ;
|
||||
static volatile void(*functionPass);
|
||||
static volatile char(*argsPass);
|
||||
|
||||
static pthread_mutex_t pinMutex ;
|
||||
|
||||
static void *interruptHandler (void *arg)
|
||||
{
|
||||
int myPin ;
|
||||
struct threadGPIOinterupt *stuff = (struct threadGPIOinterupt *) arg;
|
||||
int pin = stuff->pin;
|
||||
void (*function)(void *args) = stuff->function;
|
||||
void *args = stuff->args;
|
||||
stuff->pin = -1;
|
||||
|
||||
//(void)piHiPri (55) ; // Only effective if we run as root
|
||||
char path[SYSFS_PATH_MAX];
|
||||
int fd, count, i ;
|
||||
uint8_t c ;
|
||||
|
||||
myPin = pinPass ;
|
||||
pinPass = -1 ;
|
||||
sprintf(path, "/sys/class/gpio/gpio%d/value", pin);
|
||||
|
||||
for (;;)
|
||||
if (waitForInterrupt (myPin, -1) > 0)
|
||||
printf("READ SOMETHING\n");
|
||||
//(*function)(arg);
|
||||
if ((fd = open(path, O_RDONLY)) < 0)
|
||||
{
|
||||
logMessage (LOG_ERR, "Failed to open '%s'!\n",path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pushSysFds(fd);
|
||||
|
||||
// Clear any initial pending interrupt
|
||||
ioctl (fd, FIONREAD, &count) ;
|
||||
for (i = 0 ; i < count ; ++i)
|
||||
read (fd, &c, 1);
|
||||
|
||||
while (_ever == true) {
|
||||
if (waitForInterrupt (pin, -1, fd) > 0) {
|
||||
function(args);
|
||||
} else {
|
||||
printf("SOMETHING FAILED, reset\n");
|
||||
gpioDelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("interruptHandler ended\n");
|
||||
|
||||
close(fd);
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
|
||||
bool registerGPIOinterrupt(int pin, int mode, void (*function)(char *), void (*args) )
|
||||
bool registerGPIOinterrupt(int pin, int mode, void (*function)(void *args), void *args )
|
||||
{
|
||||
pthread_t threadId ;
|
||||
// Clear any initial pending interrupt
|
||||
struct threadGPIOinterupt stuff;
|
||||
// Check it's exported
|
||||
if (! isExported(pin))
|
||||
pinExport(pin);
|
||||
|
||||
pinPass = pin ;
|
||||
// if the pin is putput, set as input to setup edge then reset to output.
|
||||
if (getPinMode(pin) == OUTPUT) {
|
||||
pinMode(pin, INPUT);
|
||||
edgeSetup(pin, mode);
|
||||
pinMode(pin, OUTPUT);
|
||||
} else {
|
||||
edgeSetup(pin, mode);
|
||||
}
|
||||
|
||||
stuff.function = function;
|
||||
stuff.args = args;
|
||||
stuff.pin = pin;
|
||||
|
||||
pthread_mutex_lock (&pinMutex) ;
|
||||
if (pthread_create (&threadId, NULL, interruptHandler, NULL) < 0)
|
||||
if (pthread_create (&threadId, NULL, interruptHandler, (void *)&stuff) < 0)
|
||||
return false;
|
||||
else {
|
||||
while (pinPass != -1)
|
||||
delay (1) ;
|
||||
while (stuff.pin == pin)
|
||||
gpioDelay(1);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&pinMutex) ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
//#define TEST_HARNESS
|
||||
|
||||
#ifdef TEST_HARNESS
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
void *myCallBack(void * args) {
|
||||
printf("Ping\n");
|
||||
//struct threadGPIOinterupt *stuff = (struct threadGPIOinterupt *) args;
|
||||
//printf("Pin is %d\n",stuff->pin);
|
||||
}
|
||||
|
||||
void logMessage(int level, char *format, ...)
|
||||
{
|
||||
|
@ -261,14 +500,37 @@ void displayLastSystemError (const char *on_what)
|
|||
#define PIN 4
|
||||
#define POUT 27
|
||||
int main(int argc, char *argv[]) {
|
||||
int repeat = 10;
|
||||
int repeat = 3;
|
||||
|
||||
// if (-1 == GPIOExport(POUT) || -1 == GPIOExport(PIN))
|
||||
// return(1);
|
||||
gpioSetup();
|
||||
/*
|
||||
pinUnexport(POUT);
|
||||
pinUnexport(PIN);
|
||||
pinExport(POUT);
|
||||
pinExport(PIN);
|
||||
|
||||
sleep(1);
|
||||
*/
|
||||
//edgeSetup(POUT, INT_EDGE_BOTH);
|
||||
|
||||
if (-1 == pinMode(POUT, OUTPUT) || -1 == pinMode(PIN, INPUT))
|
||||
return (2);
|
||||
|
||||
//edgeSetup(PIN, INT_EDGE_RISING);
|
||||
//edgeSetup(POUT, INT_EDGE_RISING);
|
||||
|
||||
if (pinExport(POUT) != true)
|
||||
printf("Error exporting pin\n");
|
||||
|
||||
if (registerGPIOinterrupt(POUT, INT_EDGE_RISING, (void *)&myCallBack, (void *)&repeat ) != true)
|
||||
printf("Error registering interupt\n");
|
||||
|
||||
if (registerGPIOinterrupt(PIN, INT_EDGE_RISING, (void *)&myCallBack, (void *)&repeat ) != true)
|
||||
printf("Error registering interupt\n");
|
||||
|
||||
|
||||
do {
|
||||
|
||||
printf("I'm writing to GPIO %d (input)\n", digitalRead(PIN), PIN);
|
||||
|
@ -282,9 +544,15 @@ int main(int argc, char *argv[]) {
|
|||
usleep(500 * 1000);
|
||||
} while (repeat--);
|
||||
|
||||
gpioShutdown();
|
||||
|
||||
sleep(1);
|
||||
|
||||
if (-1 == pinUnexport(POUT) || -1 == pinUnexport(PIN))
|
||||
return (4);
|
||||
|
||||
sleep(1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
*/
|
||||
#endif
|
45
sd_GPIO.h
45
sd_GPIO.h
|
@ -2,6 +2,12 @@
|
|||
#ifndef _SD_GPIO_H_
|
||||
#define _SD_GPIO_H_
|
||||
|
||||
/* Use sysfs for ALL gpio activity?
|
||||
comment out to use memory where we can
|
||||
*/
|
||||
//#define GPIO_SYSFS_MODE
|
||||
|
||||
|
||||
#include <syslog.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
@ -25,12 +31,47 @@
|
|||
#define INT_EDGE_RISING 2
|
||||
#define INT_EDGE_BOTH 3
|
||||
|
||||
#ifndef GPIO_SYSFS_MODE
|
||||
#define GPIO_BASE 0x20200000
|
||||
#define GPIO_LEN 0xB4
|
||||
|
||||
#define GPSET0 7
|
||||
#define GPSET1 8
|
||||
|
||||
#define GPCLR0 10
|
||||
#define GPCLR1 11
|
||||
|
||||
#define GPLEV0 13
|
||||
#define GPLEV1 14
|
||||
|
||||
// Not used yet.
|
||||
#define GPPUD 37
|
||||
#define GPPUDCLK0 38
|
||||
#define GPPUDCLK1 39
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//#ifndef SYSFS_MODE
|
||||
bool pinExport(unsigned pin);
|
||||
bool pinUnexport(unsigned pin);
|
||||
bool isExported(unsigned pin);
|
||||
int pinMode(unsigned gpio, unsigned mode);
|
||||
int getPinMode(unsigned gpio);
|
||||
int digitalRead(unsigned gpio);
|
||||
int digitalWrite(unsigned gpio, unsigned level);
|
||||
int setPullUpDown(unsigned gpio, unsigned pud);
|
||||
bool gpioSetup();
|
||||
void gpioShutdown();
|
||||
bool registerGPIOinterrupt(int pin, int mode, void (*function)(void *args), void *args );
|
||||
/*
|
||||
#else
|
||||
bool pinExport(int pin);
|
||||
bool pinUnexport(int pin);
|
||||
bool pinMode (int pin, int mode);
|
||||
int digitalRead (int pin);
|
||||
bool digitalWrite (int pin, int value);
|
||||
|
||||
|
||||
#endif
|
||||
*/
|
||||
|
||||
#endif /* _SD_GPIO_H_ */
|
||||
|
|
12
sd_cron.c
12
sd_cron.c
|
@ -52,6 +52,18 @@ void enable_delay24h(bool state)
|
|||
}
|
||||
}
|
||||
|
||||
void reset_delay24h_time()
|
||||
{
|
||||
if (_sdconfig_.delay24h != true) {
|
||||
_sdconfig_.eventToUpdateHappened = true;
|
||||
}
|
||||
|
||||
_sdconfig_.delay24h = true;
|
||||
time(&_sdconfig_.delay24h_time);
|
||||
_sdconfig_.delay24h_time = _sdconfig_.delay24h_time + DELAY24H_SEC;
|
||||
logMessage(LOG_NOTICE, "Reset rain Delay\n");
|
||||
}
|
||||
|
||||
void check_cron() {
|
||||
if (_sdconfig_.cron_update > 0) {
|
||||
logMessage(LOG_DEBUG, "Checking if CRON needs to be updated\n");
|
||||
|
|
|
@ -12,6 +12,7 @@ void write_cron();
|
|||
void read_cron();
|
||||
void enable_delay24h(bool state);
|
||||
bool check_delay24h();
|
||||
void reset_delay24h_time();
|
||||
void enable_system(bool state);
|
||||
|
||||
#endif // SD_CRON_H_
|
||||
|
|
23
sprinkler.c
23
sprinkler.c
|
@ -248,17 +248,30 @@ void main_loop ()
|
|||
}
|
||||
#else
|
||||
logMessage(LOG_DEBUG, "Setting up GPIO\n");
|
||||
|
||||
gpioSetup();
|
||||
|
||||
for (i=(_sdconfig_.master_valve?0:1); i <= _sdconfig_.zones ; i++)
|
||||
{
|
||||
logMessage (LOG_DEBUG, "Setting up Zone %d\n", i);
|
||||
|
||||
#ifdef GPIO_SYSFS_MODE
|
||||
// Only need to export and gain control if in sysfs mode.
|
||||
pinUnexport(_sdconfig_.zonecfg[i].pin);
|
||||
pinExport(_sdconfig_.zonecfg[i].pin);
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
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") );
|
||||
|
||||
}
|
||||
|
@ -326,6 +339,9 @@ void Daemon_Stop (int signum)
|
|||
digitalWrite(_sdconfig_.zonecfg[i].pin, _sdconfig_.zonecfg[i].shutdown_state);
|
||||
}
|
||||
}
|
||||
#ifndef USE_WIRINGPI
|
||||
gpioSetup();
|
||||
#endif
|
||||
/*
|
||||
#ifdef PTHREAD
|
||||
logMessage (LOG_INFO, "Stopping httpd threads!\n");
|
||||
|
@ -341,7 +357,6 @@ void intHandler(int signum) {
|
|||
int i;
|
||||
//syslog (LOG_INFO, "Stopping");
|
||||
logMessage (LOG_INFO, "Stopping!\n");
|
||||
|
||||
for (i=(_sdconfig_.master_valve?0:1); i <= _sdconfig_.zones ; i++)
|
||||
{
|
||||
if ( _sdconfig_.zonecfg[i].shutdown_state == 0 || _sdconfig_.zonecfg[i].shutdown_state == 1 ) {
|
||||
|
@ -350,6 +365,10 @@ void intHandler(int signum) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef USE_WIRINGPI
|
||||
gpioSetup();
|
||||
#endif
|
||||
|
||||
close(server_sock);
|
||||
write_cache();
|
||||
/*
|
||||
|
|
|
@ -123,7 +123,7 @@ bool zc_zone(zcRunType type, int zone, zcState state, int length) {
|
|||
//}
|
||||
|
||||
if (state == zcON) {
|
||||
for (i=1; i < _sdconfig_.pinscfgs ; i++)
|
||||
for (i=1; i < _sdconfig_.zones ; i++)
|
||||
{
|
||||
if ( _sdconfig_.zonecfg[i].on_state == digitalRead (_sdconfig_.zonecfg[i].pin)) {
|
||||
if (zone == i) {
|
||||
|
|
Loading…
Reference in New Issue