first commit 1
parent
4a05b5ffa4
commit
51313f986f
|
@ -0,0 +1,61 @@
|
|||
# define the C compiler to use
|
||||
CC = gcc
|
||||
|
||||
LIBS := -lpthread -lwiringPi -lwiringPiDev -lm
|
||||
#LIBS := -lpthread -lwebsockets
|
||||
|
||||
# debug of not
|
||||
#$DBG = -g
|
||||
$DBG =
|
||||
|
||||
# define any compile-time flags
|
||||
#CFLAGS = -Wall -lpthread -lwiringPi -lwiringPiDev -lm -I. -I./minIni
|
||||
CFLAGS = -Wall -I. -I./minIni $(DBG) $(LIBS) -D MG_DISABLE_MD5 -D MG_DISABLE_HTTP_DIGEST_AUTH -D MG_DISABLE_MD5 -D MG_DISABLE_JSON_RPC
|
||||
#CFLAGS = -Wall -g -I./wiringPI
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
# define the C object files
|
||||
#
|
||||
# This uses Suffix Replacement within a macro:
|
||||
# $(name:string1=string2)
|
||||
# For each word in 'name' replace 'string1' with 'string2'
|
||||
# Below we are replacing the suffix .c of all words in the macro SRCS
|
||||
# with the .o suffix
|
||||
#
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
# define the executable file
|
||||
MAIN = ./release/sprinklerd
|
||||
|
||||
#
|
||||
# The following part of the makefile is generic; it can be used to
|
||||
# build any executable just by changing the definitions above and by
|
||||
# deleting dependencies appended to the file from 'make depend'
|
||||
#
|
||||
|
||||
.PHONY: depend clean
|
||||
|
||||
all: $(MAIN)
|
||||
@echo: $(MAIN) have been compiled
|
||||
|
||||
$(MAIN): $(OBJS)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)
|
||||
|
||||
# this is a suffix replacement rule for building .o's from .c's
|
||||
# it uses automatic variables $<: the name of the prerequisite of
|
||||
# the rule(a .c file) and $@: the name of the target of the rule (a .o file)
|
||||
# (see the gnu make manual section about automatic variables)
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
clean:
|
||||
$(RM) *.o *~ $(MAIN) $(MAIN_U)
|
||||
|
||||
depend: $(SRCS)
|
||||
makedepend $(INCLUDES) $^
|
||||
|
||||
install: $(MAIN)
|
||||
./release/install.sh
|
|
@ -0,0 +1,31 @@
|
|||
/* Glue functions for the minIni library, based on the C/C++ stdio library
|
||||
*
|
||||
* Or better said: this file contains macros that maps the function interface
|
||||
* used by minIni to the standard C/C++ file I/O functions.
|
||||
*
|
||||
* By CompuPhase, 2008-2014
|
||||
* This "glue file" is in the public domain. It is distributed without
|
||||
* warranties or conditions of any kind, either express or implied.
|
||||
*/
|
||||
|
||||
/* map required file I/O types and functions to the standard C library */
|
||||
#include <stdio.h>
|
||||
|
||||
#define INI_FILETYPE FILE*
|
||||
#define ini_openread(filename,file) ((*(file) = fopen((filename),"rb")) != NULL)
|
||||
#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"wb")) != NULL)
|
||||
#define ini_openrewrite(filename,file) ((*(file) = fopen((filename),"r+b")) != NULL)
|
||||
#define ini_close(file) (fclose(*(file)) == 0)
|
||||
#define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL)
|
||||
#define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0)
|
||||
#define ini_rename(source,dest) (rename((source), (dest)) == 0)
|
||||
#define ini_remove(filename) (remove(filename) == 0)
|
||||
|
||||
#define INI_FILEPOS long int
|
||||
#define ini_tell(file,pos) (*(pos) = ftell(*(file)))
|
||||
#define ini_seek(file,pos) (fseek(*(file), *(pos), SEEK_SET) == 0)
|
||||
|
||||
/* for floating-point support, define additional types and functions */
|
||||
#define INI_REAL float
|
||||
#define ini_ftoa(string,value) sprintf((string),"%f",(value))
|
||||
#define ini_atof(string) (INI_REAL)strtod((string),NULL)
|
|
@ -0,0 +1,878 @@
|
|||
/* minIni - Multi-Platform INI file parser, suitable for embedded systems
|
||||
*
|
||||
* These routines are in part based on the article "Multiplatform .INI Files"
|
||||
* by Joseph J. Graf in the March 1994 issue of Dr. Dobb's Journal.
|
||||
*
|
||||
* Copyright (c) CompuPhase, 2008-2017
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Version: $Id: minIni.c 53 2015-01-18 13:35:11Z thiadmer.riemersma@gmail.com $
|
||||
*/
|
||||
|
||||
#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY
|
||||
# if !defined UNICODE /* for Windows */
|
||||
# define UNICODE
|
||||
# endif
|
||||
# if !defined _UNICODE /* for C library */
|
||||
# define _UNICODE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define MININI_IMPLEMENTATION
|
||||
#include "minIni.h"
|
||||
#if defined NDEBUG
|
||||
#define assert(e)
|
||||
#else
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#if !defined __T || defined INI_ANSIONLY
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#define TCHAR char
|
||||
#define __T(s) s
|
||||
#define _tcscat strcat
|
||||
#define _tcschr strchr
|
||||
#define _tcscmp strcmp
|
||||
#define _tcscpy strcpy
|
||||
#define _tcsicmp stricmp
|
||||
#define _tcslen strlen
|
||||
#define _tcsncmp strncmp
|
||||
#define _tcsnicmp strnicmp
|
||||
#define _tcsrchr strrchr
|
||||
#define _tcstol strtol
|
||||
#define _tcstod strtod
|
||||
#define _totupper toupper
|
||||
#define _stprintf sprintf
|
||||
#define _tfgets fgets
|
||||
#define _tfputs fputs
|
||||
#define _tfopen fopen
|
||||
#define _tremove remove
|
||||
#define _trename rename
|
||||
#endif
|
||||
|
||||
#if defined __linux || defined __linux__
|
||||
#define __LINUX__
|
||||
#elif defined FREEBSD && !defined __FreeBSD__
|
||||
#define __FreeBSD__
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning(disable: 4996) /* for Microsoft Visual C/C++ */
|
||||
#endif
|
||||
#if !defined strnicmp && !defined PORTABLE_STRNICMP
|
||||
#if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
|
||||
#define strnicmp strncasecmp
|
||||
#endif
|
||||
#endif
|
||||
#if !defined _totupper
|
||||
#define _totupper toupper
|
||||
#endif
|
||||
|
||||
#if !defined INI_LINETERM
|
||||
#if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
|
||||
#define INI_LINETERM __T("\n")
|
||||
#else
|
||||
#define INI_LINETERM __T("\r\n")
|
||||
#endif
|
||||
#endif
|
||||
#if !defined INI_FILETYPE
|
||||
#error Missing definition for INI_FILETYPE.
|
||||
#endif
|
||||
|
||||
#if !defined sizearray
|
||||
#define sizearray(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#endif
|
||||
|
||||
enum quote_option {
|
||||
QUOTE_NONE,
|
||||
QUOTE_ENQUOTE,
|
||||
QUOTE_DEQUOTE,
|
||||
};
|
||||
|
||||
#if defined PORTABLE_STRNICMP
|
||||
int strnicmp(const TCHAR *s1, const TCHAR *s2, size_t n)
|
||||
{
|
||||
while (n-- != 0 && (*s1 || *s2)) {
|
||||
register int c1, c2;
|
||||
c1 = *s1++;
|
||||
if ('a' <= c1 && c1 <= 'z')
|
||||
c1 += ('A' - 'a');
|
||||
c2 = *s2++;
|
||||
if ('a' <= c2 && c2 <= 'z')
|
||||
c2 += ('A' - 'a');
|
||||
if (c1 != c2)
|
||||
return c1 - c2;
|
||||
} /* while */
|
||||
return 0;
|
||||
}
|
||||
#endif /* PORTABLE_STRNICMP */
|
||||
|
||||
static TCHAR *skipleading(const TCHAR *str)
|
||||
{
|
||||
assert(str != NULL);
|
||||
while ('\0' < *str && *str <= ' ')
|
||||
str++;
|
||||
return (TCHAR *)str;
|
||||
}
|
||||
|
||||
static TCHAR *skiptrailing(const TCHAR *str, const TCHAR *base)
|
||||
{
|
||||
assert(str != NULL);
|
||||
assert(base != NULL);
|
||||
while (str > base && '\0' < *(str-1) && *(str-1) <= ' ')
|
||||
str--;
|
||||
return (TCHAR *)str;
|
||||
}
|
||||
|
||||
static TCHAR *striptrailing(TCHAR *str)
|
||||
{
|
||||
TCHAR *ptr = skiptrailing(_tcschr(str, '\0'), str);
|
||||
assert(ptr != NULL);
|
||||
*ptr = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
static TCHAR *ini_strncpy(TCHAR *dest, const TCHAR *source, size_t maxlen, enum quote_option option)
|
||||
{
|
||||
size_t d, s;
|
||||
|
||||
assert(maxlen>0);
|
||||
assert(source != NULL && dest != NULL);
|
||||
assert((dest < source || (dest == source && option != QUOTE_ENQUOTE)) || dest > source + strlen(source));
|
||||
if (option == QUOTE_ENQUOTE && maxlen < 3)
|
||||
option = QUOTE_NONE; /* cannot store two quotes and a terminating zero in less than 3 characters */
|
||||
|
||||
switch (option) {
|
||||
case QUOTE_NONE:
|
||||
for (d = 0; d < maxlen - 1 && source[d] != '\0'; d++)
|
||||
dest[d] = source[d];
|
||||
assert(d < maxlen);
|
||||
dest[d] = '\0';
|
||||
break;
|
||||
case QUOTE_ENQUOTE:
|
||||
d = 0;
|
||||
dest[d++] = '"';
|
||||
for (s = 0; source[s] != '\0' && d < maxlen - 2; s++, d++) {
|
||||
if (source[s] == '"') {
|
||||
if (d >= maxlen - 3)
|
||||
break; /* no space to store the escape character plus the one that follows it */
|
||||
dest[d++] = '\\';
|
||||
} /* if */
|
||||
dest[d] = source[s];
|
||||
} /* for */
|
||||
dest[d++] = '"';
|
||||
dest[d] = '\0';
|
||||
break;
|
||||
case QUOTE_DEQUOTE:
|
||||
for (d = s = 0; source[s] != '\0' && d < maxlen - 1; s++, d++) {
|
||||
if ((source[s] == '"' || source[s] == '\\') && source[s + 1] == '"')
|
||||
s++;
|
||||
dest[d] = source[s];
|
||||
} /* for */
|
||||
dest[d] = '\0';
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
} /* switch */
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
static TCHAR *cleanstring(TCHAR *string, enum quote_option *quotes)
|
||||
{
|
||||
int isstring;
|
||||
TCHAR *ep;
|
||||
|
||||
assert(string != NULL);
|
||||
assert(quotes != NULL);
|
||||
|
||||
/* Remove a trailing comment */
|
||||
isstring = 0;
|
||||
for (ep = string; *ep != '\0' && ((*ep != ';' && *ep != '#') || isstring); ep++) {
|
||||
if (*ep == '"') {
|
||||
if (*(ep + 1) == '"')
|
||||
ep++; /* skip "" (both quotes) */
|
||||
else
|
||||
isstring = !isstring; /* single quote, toggle isstring */
|
||||
} else if (*ep == '\\' && *(ep + 1) == '"') {
|
||||
ep++; /* skip \" (both quotes */
|
||||
} /* if */
|
||||
} /* for */
|
||||
assert(ep != NULL && (*ep == '\0' || *ep == ';' || *ep == '#'));
|
||||
*ep = '\0'; /* terminate at a comment */
|
||||
striptrailing(string);
|
||||
/* Remove double quotes surrounding a value */
|
||||
*quotes = QUOTE_NONE;
|
||||
if (*string == '"' && (ep = _tcschr(string, '\0')) != NULL && *(ep - 1) == '"') {
|
||||
string++;
|
||||
*--ep = '\0';
|
||||
*quotes = QUOTE_DEQUOTE; /* this is a string, so remove escaped characters */
|
||||
} /* if */
|
||||
return string;
|
||||
}
|
||||
|
||||
static int getkeystring(INI_FILETYPE *fp, const TCHAR *Section, const TCHAR *Key,
|
||||
int idxSection, int idxKey, TCHAR *Buffer, int BufferSize,
|
||||
INI_FILEPOS *mark)
|
||||
{
|
||||
TCHAR *sp, *ep;
|
||||
int len, idx;
|
||||
enum quote_option quotes;
|
||||
TCHAR LocalBuffer[INI_BUFFERSIZE];
|
||||
|
||||
assert(fp != NULL);
|
||||
/* Move through file 1 line at a time until a section is matched or EOF. If
|
||||
* parameter Section is NULL, only look at keys above the first section. If
|
||||
* idxSection is postive, copy the relevant section name.
|
||||
*/
|
||||
len = (Section != NULL) ? (int)_tcslen(Section) : 0;
|
||||
if (len > 0 || idxSection >= 0) {
|
||||
assert(idxSection >= 0 || Section != NULL);
|
||||
idx = -1;
|
||||
do {
|
||||
if (!ini_read(LocalBuffer, INI_BUFFERSIZE, fp))
|
||||
return 0;
|
||||
sp = skipleading(LocalBuffer);
|
||||
ep = _tcsrchr(sp, ']');
|
||||
} while (*sp != '[' || ep == NULL ||
|
||||
(((int)(ep-sp-1) != len || Section == NULL || _tcsnicmp(sp+1,Section,len) != 0) && ++idx != idxSection));
|
||||
if (idxSection >= 0) {
|
||||
if (idx == idxSection) {
|
||||
assert(ep != NULL);
|
||||
assert(*ep == ']');
|
||||
*ep = '\0';
|
||||
ini_strncpy(Buffer, sp + 1, BufferSize, QUOTE_NONE);
|
||||
return 1;
|
||||
} /* if */
|
||||
return 0; /* no more section found */
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
/* Now that the section has been found, find the entry.
|
||||
* Stop searching upon leaving the section's area.
|
||||
*/
|
||||
assert(Key != NULL || idxKey >= 0);
|
||||
len = (Key != NULL) ? (int)_tcslen(Key) : 0;
|
||||
idx = -1;
|
||||
do {
|
||||
if (mark != NULL)
|
||||
ini_tell(fp, mark); /* optionally keep the mark to the start of the line */
|
||||
if (!ini_read(LocalBuffer,INI_BUFFERSIZE,fp) || *(sp = skipleading(LocalBuffer)) == '[')
|
||||
return 0;
|
||||
sp = skipleading(LocalBuffer);
|
||||
ep = _tcschr(sp, '='); /* Parse out the equal sign */
|
||||
if (ep == NULL)
|
||||
ep = _tcschr(sp, ':');
|
||||
} while (*sp == ';' || *sp == '#' || ep == NULL
|
||||
|| ((len == 0 || (int)(skiptrailing(ep,sp)-sp) != len || _tcsnicmp(sp,Key,len) != 0) && ++idx != idxKey));
|
||||
if (idxKey >= 0) {
|
||||
if (idx == idxKey) {
|
||||
assert(ep != NULL);
|
||||
assert(*ep == '=' || *ep == ':');
|
||||
*ep = '\0';
|
||||
striptrailing(sp);
|
||||
ini_strncpy(Buffer, sp, BufferSize, QUOTE_NONE);
|
||||
return 1;
|
||||
} /* if */
|
||||
return 0; /* no more key found (in this section) */
|
||||
} /* if */
|
||||
|
||||
/* Copy up to BufferSize chars to buffer */
|
||||
assert(ep != NULL);
|
||||
assert(*ep == '=' || *ep == ':');
|
||||
sp = skipleading(ep + 1);
|
||||
sp = cleanstring(sp, "es); /* Remove a trailing comment */
|
||||
ini_strncpy(Buffer, sp, BufferSize, quotes);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** ini_gets()
|
||||
* \param Section the name of the section to search for
|
||||
* \param Key the name of the entry to find the value of
|
||||
* \param DefValue default string in the event of a failed read
|
||||
* \param Buffer a pointer to the buffer to copy into
|
||||
* \param BufferSize the maximum number of characters to copy
|
||||
* \param Filename the name and full path of the .ini file to read from
|
||||
*
|
||||
* \return the number of characters copied into the supplied buffer
|
||||
*/
|
||||
int ini_gets(const TCHAR *Section, const TCHAR *Key, const TCHAR *DefValue,
|
||||
TCHAR *Buffer, int BufferSize, const TCHAR *Filename)
|
||||
{
|
||||
INI_FILETYPE fp;
|
||||
int ok = 0;
|
||||
|
||||
if (Buffer == NULL || BufferSize <= 0 || Key == NULL)
|
||||
return 0;
|
||||
if (ini_openread(Filename, &fp)) {
|
||||
ok = getkeystring(&fp, Section, Key, -1, -1, Buffer, BufferSize, NULL);
|
||||
(void)ini_close(&fp);
|
||||
} /* if */
|
||||
if (!ok) {
|
||||
ini_strncpy(Buffer, (DefValue != NULL) ? DefValue : __T(""), BufferSize, QUOTE_NONE);
|
||||
//Buffer = DefValue;
|
||||
}
|
||||
return (int)_tcslen(Buffer);
|
||||
}
|
||||
|
||||
/** ini_getl()
|
||||
* \param Section the name of the section to search for
|
||||
* \param Key the name of the entry to find the value of
|
||||
* \param DefValue the default value in the event of a failed read
|
||||
* \param Filename the name of the .ini file to read from
|
||||
*
|
||||
* \return the value located at Key
|
||||
*/
|
||||
long ini_getl(const TCHAR *Section, const TCHAR *Key, long DefValue, const TCHAR *Filename)
|
||||
{
|
||||
TCHAR LocalBuffer[64];
|
||||
int len = ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename);
|
||||
return (len == 0) ? DefValue
|
||||
: ((len >= 2 && _totupper((int)LocalBuffer[1]) == 'X') ? _tcstol(LocalBuffer, NULL, 16)
|
||||
: _tcstol(LocalBuffer, NULL, 10));
|
||||
}
|
||||
|
||||
#if defined INI_REAL
|
||||
/** ini_getf()
|
||||
* \param Section the name of the section to search for
|
||||
* \param Key the name of the entry to find the value of
|
||||
* \param DefValue the default value in the event of a failed read
|
||||
* \param Filename the name of the .ini file to read from
|
||||
*
|
||||
* \return the value located at Key
|
||||
*/
|
||||
INI_REAL ini_getf(const TCHAR *Section, const TCHAR *Key, INI_REAL DefValue, const TCHAR *Filename)
|
||||
{
|
||||
TCHAR LocalBuffer[64];
|
||||
int len = ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename);
|
||||
return (len == 0) ? DefValue : ini_atof(LocalBuffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** ini_getbool()
|
||||
* \param Section the name of the section to search for
|
||||
* \param Key the name of the entry to find the value of
|
||||
* \param DefValue default value in the event of a failed read; it should
|
||||
* zero (0) or one (1).
|
||||
* \param Filename the name and full path of the .ini file to read from
|
||||
*
|
||||
* A true boolean is found if one of the following is matched:
|
||||
* - A string starting with 'y' or 'Y'
|
||||
* - A string starting with 't' or 'T'
|
||||
* - A string starting with '1'
|
||||
*
|
||||
* A false boolean is found if one of the following is matched:
|
||||
* - A string starting with 'n' or 'N'
|
||||
* - A string starting with 'f' or 'F'
|
||||
* - A string starting with '0'
|
||||
*
|
||||
* \return the true/false flag as interpreted at Key
|
||||
*/
|
||||
int ini_getbool(const TCHAR *Section, const TCHAR *Key, int DefValue, const TCHAR *Filename)
|
||||
{
|
||||
TCHAR LocalBuffer[2] = __T("");
|
||||
int ret;
|
||||
|
||||
ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename);
|
||||
LocalBuffer[0] = (TCHAR)_totupper((int)LocalBuffer[0]);
|
||||
if (LocalBuffer[0] == 'Y' || LocalBuffer[0] == '1' || LocalBuffer[0] == 'T')
|
||||
ret = 1;
|
||||
else if (LocalBuffer[0] == 'N' || LocalBuffer[0] == '0' || LocalBuffer[0] == 'F')
|
||||
ret = 0;
|
||||
else
|
||||
ret = DefValue;
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/** ini_getsection()
|
||||
* \param idx the zero-based sequence number of the section to return
|
||||
* \param Buffer a pointer to the buffer to copy into
|
||||
* \param BufferSize the maximum number of characters to copy
|
||||
* \param Filename the name and full path of the .ini file to read from
|
||||
*
|
||||
* \return the number of characters copied into the supplied buffer
|
||||
*/
|
||||
int ini_getsection(int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filename)
|
||||
{
|
||||
INI_FILETYPE fp;
|
||||
int ok = 0;
|
||||
|
||||
if (Buffer == NULL || BufferSize <= 0 || idx < 0)
|
||||
return 0;
|
||||
if (ini_openread(Filename, &fp)) {
|
||||
ok = getkeystring(&fp, NULL, NULL, idx, -1, Buffer, BufferSize, NULL);
|
||||
(void)ini_close(&fp);
|
||||
} /* if */
|
||||
if (!ok)
|
||||
*Buffer = '\0';
|
||||
return (int)_tcslen(Buffer);
|
||||
}
|
||||
|
||||
/** ini_getkey()
|
||||
* \param Section the name of the section to browse through, or NULL to
|
||||
* browse through the keys outside any section
|
||||
* \param idx the zero-based sequence number of the key to return
|
||||
* \param Buffer a pointer to the buffer to copy into
|
||||
* \param BufferSize the maximum number of characters to copy
|
||||
* \param Filename the name and full path of the .ini file to read from
|
||||
*
|
||||
* \return the number of characters copied into the supplied buffer
|
||||
*/
|
||||
int ini_getkey(const TCHAR *Section, int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filename)
|
||||
{
|
||||
INI_FILETYPE fp;
|
||||
int ok = 0;
|
||||
|
||||
if (Buffer == NULL || BufferSize <= 0 || idx < 0)
|
||||
return 0;
|
||||
if (ini_openread(Filename, &fp)) {
|
||||
ok = getkeystring(&fp, Section, NULL, -1, idx, Buffer, BufferSize, NULL);
|
||||
(void)ini_close(&fp);
|
||||
} /* if */
|
||||
if (!ok)
|
||||
*Buffer = '\0';
|
||||
return (int)_tcslen(Buffer);
|
||||
}
|
||||
|
||||
|
||||
#if !defined INI_NOBROWSE
|
||||
/** ini_browse()
|
||||
* \param Callback a pointer to a function that will be called for every
|
||||
* setting in the INI file.
|
||||
* \param UserData arbitrary data, which the function passes on the the
|
||||
* \c Callback function
|
||||
* \param Filename the name and full path of the .ini file to read from
|
||||
*
|
||||
* \return 1 on success, 0 on failure (INI file not found)
|
||||
*
|
||||
* \note The \c Callback function must return 1 to continue
|
||||
* browsing through the INI file, or 0 to stop. Even when the
|
||||
* callback stops the browsing, this function will return 1
|
||||
* (for success).
|
||||
*/
|
||||
int ini_browse(INI_CALLBACK Callback, void *UserData, const TCHAR *Filename)
|
||||
{
|
||||
TCHAR LocalBuffer[INI_BUFFERSIZE];
|
||||
int lenSec, lenKey;
|
||||
enum quote_option quotes;
|
||||
INI_FILETYPE fp;
|
||||
|
||||
if (Callback == NULL)
|
||||
return 0;
|
||||
if (!ini_openread(Filename, &fp))
|
||||
return 0;
|
||||
|
||||
LocalBuffer[0] = '\0'; /* copy an empty section in the buffer */
|
||||
lenSec = (int)_tcslen(LocalBuffer) + 1;
|
||||
for ( ;; ) {
|
||||
TCHAR *sp, *ep;
|
||||
if (!ini_read(LocalBuffer + lenSec, INI_BUFFERSIZE - lenSec, &fp))
|
||||
break;
|
||||
sp = skipleading(LocalBuffer + lenSec);
|
||||
/* ignore empty strings and comments */
|
||||
if (*sp == '\0' || *sp == ';' || *sp == '#')
|
||||
continue;
|
||||
/* see whether we reached a new section */
|
||||
ep = _tcsrchr(sp, ']');
|
||||
if (*sp == '[' && ep != NULL) {
|
||||
*ep = '\0';
|
||||
ini_strncpy(LocalBuffer, sp + 1, INI_BUFFERSIZE, QUOTE_NONE);
|
||||
lenSec = (int)_tcslen(LocalBuffer) + 1;
|
||||
continue;
|
||||
} /* if */
|
||||
/* not a new section, test for a key/value pair */
|
||||
ep = _tcschr(sp, '='); /* test for the equal sign or colon */
|
||||
if (ep == NULL)
|
||||
ep = _tcschr(sp, ':');
|
||||
if (ep == NULL)
|
||||
continue; /* invalid line, ignore */
|
||||
*ep++ = '\0'; /* split the key from the value */
|
||||
striptrailing(sp);
|
||||
ini_strncpy(LocalBuffer + lenSec, sp, INI_BUFFERSIZE - lenSec, QUOTE_NONE);
|
||||
lenKey = (int)_tcslen(LocalBuffer + lenSec) + 1;
|
||||
/* clean up the value */
|
||||
sp = skipleading(ep);
|
||||
sp = cleanstring(sp, "es); /* Remove a trailing comment */
|
||||
ini_strncpy(LocalBuffer + lenSec + lenKey, sp, INI_BUFFERSIZE - lenSec - lenKey, quotes);
|
||||
/* call the callback */
|
||||
if (!Callback(LocalBuffer, LocalBuffer + lenSec, LocalBuffer + lenSec + lenKey, UserData))
|
||||
break;
|
||||
} /* for */
|
||||
|
||||
(void)ini_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
#endif /* INI_NOBROWSE */
|
||||
|
||||
#if ! defined INI_READONLY
|
||||
static void ini_tempname(TCHAR *dest, const TCHAR *source, int maxlength)
|
||||
{
|
||||
TCHAR *p;
|
||||
|
||||
ini_strncpy(dest, source, maxlength, QUOTE_NONE);
|
||||
p = _tcsrchr(dest, '\0');
|
||||
assert(p != NULL);
|
||||
*(p - 1) = '~';
|
||||
}
|
||||
|
||||
static enum quote_option check_enquote(const TCHAR *Value)
|
||||
{
|
||||
const TCHAR *p;
|
||||
|
||||
/* run through the value, if it has trailing spaces, or '"', ';' or '#'
|
||||
* characters, enquote it
|
||||
*/
|
||||
assert(Value != NULL);
|
||||
for (p = Value; *p != '\0' && *p != '"' && *p != ';' && *p != '#'; p++)
|
||||
/* nothing */;
|
||||
return (*p != '\0' || (p > Value && *(p - 1) == ' ')) ? QUOTE_ENQUOTE : QUOTE_NONE;
|
||||
}
|
||||
|
||||
static void writesection(TCHAR *LocalBuffer, const TCHAR *Section, INI_FILETYPE *fp)
|
||||
{
|
||||
if (Section != NULL && _tcslen(Section) > 0) {
|
||||
TCHAR *p;
|
||||
LocalBuffer[0] = '[';
|
||||
ini_strncpy(LocalBuffer + 1, Section, INI_BUFFERSIZE - 4, QUOTE_NONE); /* -1 for '[', -1 for ']', -2 for '\r\n' */
|
||||
p = _tcsrchr(LocalBuffer, '\0');
|
||||
assert(p != NULL);
|
||||
*p++ = ']';
|
||||
_tcscpy(p, INI_LINETERM); /* copy line terminator (typically "\n") */
|
||||
if (fp != NULL)
|
||||
(void)ini_write(LocalBuffer, fp);
|
||||
} /* if */
|
||||
}
|
||||
|
||||
static void writekey(TCHAR *LocalBuffer, const TCHAR *Key, const TCHAR *Value, INI_FILETYPE *fp)
|
||||
{
|
||||
TCHAR *p;
|
||||
enum quote_option option = check_enquote(Value);
|
||||
ini_strncpy(LocalBuffer, Key, INI_BUFFERSIZE - 3, QUOTE_NONE); /* -1 for '=', -2 for '\r\n' */
|
||||
p = _tcsrchr(LocalBuffer, '\0');
|
||||
assert(p != NULL);
|
||||
*p++ = '=';
|
||||
ini_strncpy(p, Value, INI_BUFFERSIZE - (p - LocalBuffer) - 2, option); /* -2 for '\r\n' */
|
||||
p = _tcsrchr(LocalBuffer, '\0');
|
||||
assert(p != NULL);
|
||||
_tcscpy(p, INI_LINETERM); /* copy line terminator (typically "\n") */
|
||||
if (fp != NULL)
|
||||
(void)ini_write(LocalBuffer, fp);
|
||||
}
|
||||
|
||||
static int cache_accum(const TCHAR *string, int *size, int max)
|
||||
{
|
||||
int len = (int)_tcslen(string);
|
||||
if (*size + len >= max)
|
||||
return 0;
|
||||
*size += len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cache_flush(TCHAR *buffer, int *size,
|
||||
INI_FILETYPE *rfp, INI_FILETYPE *wfp, INI_FILEPOS *mark)
|
||||
{
|
||||
int terminator_len = (int)_tcslen(INI_LINETERM);
|
||||
int pos = 0;
|
||||
|
||||
(void)ini_seek(rfp, mark);
|
||||
assert(buffer != NULL);
|
||||
buffer[0] = '\0';
|
||||
assert(size != NULL);
|
||||
assert(*size <= INI_BUFFERSIZE);
|
||||
while (pos < *size) {
|
||||
(void)ini_read(buffer + pos, INI_BUFFERSIZE - pos, rfp);
|
||||
while (pos < *size && buffer[pos] != '\0')
|
||||
pos++; /* cannot use _tcslen() because buffer may not be zero-terminated */
|
||||
} /* while */
|
||||
if (buffer[0] != '\0') {
|
||||
assert(pos > 0 && pos <= INI_BUFFERSIZE);
|
||||
if (pos == INI_BUFFERSIZE)
|
||||
pos--;
|
||||
buffer[pos] = '\0'; /* force zero-termination (may be left unterminated in the above while loop) */
|
||||
(void)ini_write(buffer, wfp);
|
||||
}
|
||||
ini_tell(rfp, mark); /* update mark */
|
||||
*size = 0;
|
||||
/* return whether the buffer ended with a line termination */
|
||||
return (pos > terminator_len) && (_tcscmp(buffer + pos - terminator_len, INI_LINETERM) == 0);
|
||||
}
|
||||
|
||||
static int close_rename(INI_FILETYPE *rfp, INI_FILETYPE *wfp, const TCHAR *filename, TCHAR *buffer)
|
||||
{
|
||||
(void)ini_close(rfp);
|
||||
(void)ini_close(wfp);
|
||||
(void)ini_remove(filename);
|
||||
(void)ini_tempname(buffer, filename, INI_BUFFERSIZE);
|
||||
(void)ini_rename(buffer, filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** ini_puts()
|
||||
* \param Section the name of the section to write the string in
|
||||
* \param Key the name of the entry to write, or NULL to erase all keys in the section
|
||||
* \param Value a pointer to the buffer the string, or NULL to erase the key
|
||||
* \param Filename the name and full path of the .ini file to write to
|
||||
*
|
||||
* \return 1 if successful, otherwise 0
|
||||
*/
|
||||
int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const TCHAR *Filename)
|
||||
{
|
||||
INI_FILETYPE rfp;
|
||||
INI_FILETYPE wfp;
|
||||
INI_FILEPOS mark;
|
||||
INI_FILEPOS head, tail;
|
||||
TCHAR *sp, *ep;
|
||||
TCHAR LocalBuffer[INI_BUFFERSIZE];
|
||||
int len, match, flag, cachelen;
|
||||
|
||||
assert(Filename != NULL);
|
||||
if (!ini_openread(Filename, &rfp)) {
|
||||
/* If the .ini file doesn't exist, make a new file */
|
||||
if (Key != NULL && Value != NULL) {
|
||||
if (!ini_openwrite(Filename, &wfp))
|
||||
return 0;
|
||||
writesection(LocalBuffer, Section, &wfp);
|
||||
writekey(LocalBuffer, Key, Value, &wfp);
|
||||
(void)ini_close(&wfp);
|
||||
} /* if */
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
/* If parameters Key and Value are valid (so this is not an "erase" request)
|
||||
* and the setting already exists, there are two short-cuts to avoid rewriting
|
||||
* the INI file.
|
||||
*/
|
||||
if (Key != NULL && Value != NULL) {
|
||||
ini_tell(&rfp, &mark);
|
||||
match = getkeystring(&rfp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer), &head);
|
||||
if (match) {
|
||||
/* if the current setting is identical to the one to write, there is
|
||||
* nothing to do.
|
||||
*/
|
||||
if (_tcscmp(LocalBuffer,Value) == 0) {
|
||||
(void)ini_close(&rfp);
|
||||
return 1;
|
||||
} /* if */
|
||||
/* if the new setting has the same length as the current setting, and the
|
||||
* glue file permits file read/write access, we can modify in place.
|
||||
*/
|
||||
#if defined ini_openrewrite
|
||||
/* we already have the start of the (raw) line, get the end too */
|
||||
ini_tell(&rfp, &tail);
|
||||
/* create new buffer (without writing it to file) */
|
||||
writekey(LocalBuffer, Key, Value, NULL);
|
||||
if (_tcslen(LocalBuffer) == (size_t)(tail - head)) {
|
||||
/* length matches, close the file & re-open for read/write, then
|
||||
* write at the correct position
|
||||
*/
|
||||
(void)ini_close(&rfp);
|
||||
if (!ini_openrewrite(Filename, &wfp))
|
||||
return 0;
|
||||
(void)ini_seek(&wfp, &head);
|
||||
(void)ini_write(LocalBuffer, &wfp);
|
||||
(void)ini_close(&wfp);
|
||||
return 1;
|
||||
} /* if */
|
||||
#endif
|
||||
} /* if */
|
||||
/* key not found, or different value & length -> proceed (but rewind the
|
||||
* input file first)
|
||||
*/
|
||||
(void)ini_seek(&rfp, &mark);
|
||||
} /* if */
|
||||
|
||||
/* Get a temporary file name to copy to. Use the existing name, but with
|
||||
* the last character set to a '~'.
|
||||
*/
|
||||
ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE);
|
||||
if (!ini_openwrite(LocalBuffer, &wfp)) {
|
||||
(void)ini_close(&rfp);
|
||||
return 0;
|
||||
} /* if */
|
||||
(void)ini_tell(&rfp, &mark);
|
||||
cachelen = 0;
|
||||
|
||||
/* Move through the file one line at a time until a section is
|
||||
* matched or until EOF. Copy to temp file as it is read.
|
||||
*/
|
||||
len = (Section != NULL) ? (int)_tcslen(Section) : 0;
|
||||
if (len > 0) {
|
||||
do {
|
||||
if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) {
|
||||
/* Failed to find section, so add one to the end */
|
||||
flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
|
||||
if (Key!=NULL && Value!=NULL) {
|
||||
if (!flag)
|
||||
(void)ini_write(INI_LINETERM, &wfp); /* force a new line behind the last line of the INI file */
|
||||
writesection(LocalBuffer, Section, &wfp);
|
||||
writekey(LocalBuffer, Key, Value, &wfp);
|
||||
} /* if */
|
||||
return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */
|
||||
} /* if */
|
||||
/* Copy the line from source to dest, but not if this is the section that
|
||||
* we are looking for and this section must be removed
|
||||
*/
|
||||
sp = skipleading(LocalBuffer);
|
||||
ep = _tcsrchr(sp, ']');
|
||||
match = (*sp == '[' && ep != NULL && (int)(ep-sp-1) == len && _tcsnicmp(sp + 1,Section,len) == 0);
|
||||
if (!match || Key != NULL) {
|
||||
if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) {
|
||||
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
|
||||
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
|
||||
cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);
|
||||
} /* if */
|
||||
} /* if */
|
||||
} while (!match);
|
||||
} /* if */
|
||||
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
|
||||
/* when deleting a section, the section head that was just found has not been
|
||||
* copied to the output file, but because this line was not "accumulated" in
|
||||
* the cache, the position in the input file was reset to the point just
|
||||
* before the section; this must now be skipped (again)
|
||||
*/
|
||||
if (Key == NULL) {
|
||||
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
|
||||
(void)ini_tell(&rfp, &mark);
|
||||
} /* if */
|
||||
|
||||
/* Now that the section has been found, find the entry. Stop searching
|
||||
* upon leaving the section's area. Copy the file as it is read
|
||||
* and create an entry if one is not found.
|
||||
*/
|
||||
len = (Key != NULL) ? (int)_tcslen(Key) : 0;
|
||||
for( ;; ) {
|
||||
if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) {
|
||||
/* EOF without an entry so make one */
|
||||
flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
|
||||
if (Key!=NULL && Value!=NULL) {
|
||||
if (!flag)
|
||||
(void)ini_write(INI_LINETERM, &wfp); /* force a new line behind the last line of the INI file */
|
||||
writekey(LocalBuffer, Key, Value, &wfp);
|
||||
} /* if */
|
||||
return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */
|
||||
} /* if */
|
||||
sp = skipleading(LocalBuffer);
|
||||
ep = _tcschr(sp, '='); /* Parse out the equal sign */
|
||||
if (ep == NULL)
|
||||
ep = _tcschr(sp, ':');
|
||||
match = (ep != NULL && len > 0 && (int)(skiptrailing(ep,sp)-sp) == len && _tcsnicmp(sp,Key,len) == 0);
|
||||
if ((Key != NULL && match) || *sp == '[')
|
||||
break; /* found the key, or found a new section */
|
||||
/* copy other keys in the section */
|
||||
if (Key == NULL) {
|
||||
(void)ini_tell(&rfp, &mark); /* we are deleting the entire section, so update the read position */
|
||||
} else {
|
||||
if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) {
|
||||
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
|
||||
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
|
||||
cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* for */
|
||||
/* the key was found, or we just dropped on the next section (meaning that it
|
||||
* wasn't found); in both cases we need to write the key, but in the latter
|
||||
* case, we also need to write the line starting the new section after writing
|
||||
* the key
|
||||
*/
|
||||
flag = (*sp == '[');
|
||||
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
|
||||
if (Key != NULL && Value != NULL)
|
||||
writekey(LocalBuffer, Key, Value, &wfp);
|
||||
/* cache_flush() reset the "read pointer" to the start of the line with the
|
||||
* previous key or the new section; read it again (because writekey() destroyed
|
||||
* the buffer)
|
||||
*/
|
||||
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
|
||||
if (flag) {
|
||||
/* the new section heading needs to be copied to the output file */
|
||||
cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);
|
||||
} else {
|
||||
/* forget the old key line */
|
||||
(void)ini_tell(&rfp, &mark);
|
||||
} /* if */
|
||||
/* Copy the rest of the INI file */
|
||||
while (ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) {
|
||||
if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) {
|
||||
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
|
||||
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
|
||||
cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);
|
||||
} /* if */
|
||||
} /* while */
|
||||
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
|
||||
return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */
|
||||
}
|
||||
|
||||
/* Ansi C "itoa" based on Kernighan & Ritchie's "Ansi C" book. */
|
||||
#define ABS(v) ((v) < 0 ? -(v) : (v))
|
||||
|
||||
static void strreverse(TCHAR *str)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0, j = (int)_tcslen(str) - 1; i < j; i++, j--) {
|
||||
TCHAR t = str[i];
|
||||
str[i] = str[j];
|
||||
str[j] = t;
|
||||
} /* for */
|
||||
}
|
||||
|
||||
static void long2str(long value, TCHAR *str)
|
||||
{
|
||||
int i = 0;
|
||||
long sign = value;
|
||||
|
||||
/* generate digits in reverse order */
|
||||
do {
|
||||
int n = (int)(value % 10); /* get next lowest digit */
|
||||
str[i++] = (TCHAR)(ABS(n) + '0'); /* handle case of negative digit */
|
||||
} while (value /= 10); /* delete the lowest digit */
|
||||
if (sign < 0)
|
||||
str[i++] = '-';
|
||||
str[i] = '\0';
|
||||
|
||||
strreverse(str);
|
||||
}
|
||||
|
||||
/** ini_putl()
|
||||
* \param Section the name of the section to write the value in
|
||||
* \param Key the name of the entry to write
|
||||
* \param Value the value to write
|
||||
* \param Filename the name and full path of the .ini file to write to
|
||||
*
|
||||
* \return 1 if successful, otherwise 0
|
||||
*/
|
||||
int ini_putl(const TCHAR *Section, const TCHAR *Key, long Value, const TCHAR *Filename)
|
||||
{
|
||||
TCHAR LocalBuffer[32];
|
||||
long2str(Value, LocalBuffer);
|
||||
return ini_puts(Section, Key, LocalBuffer, Filename);
|
||||
}
|
||||
|
||||
#if defined INI_REAL
|
||||
/** ini_putf()
|
||||
* \param Section the name of the section to write the value in
|
||||
* \param Key the name of the entry to write
|
||||
* \param Value the value to write
|
||||
* \param Filename the name and full path of the .ini file to write to
|
||||
*
|
||||
* \return 1 if successful, otherwise 0
|
||||
*/
|
||||
int ini_putf(const TCHAR *Section, const TCHAR *Key, INI_REAL Value, const TCHAR *Filename)
|
||||
{
|
||||
TCHAR LocalBuffer[64];
|
||||
ini_ftoa(LocalBuffer, Value);
|
||||
return ini_puts(Section, Key, LocalBuffer, Filename);
|
||||
}
|
||||
#endif /* INI_REAL */
|
||||
#endif /* !INI_READONLY */
|
|
@ -0,0 +1,152 @@
|
|||
/* minIni - Multi-Platform INI file parser, suitable for embedded systems
|
||||
*
|
||||
* Copyright (c) CompuPhase, 2008-2017
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Version: $Id: minIni.h 53 2015-01-18 13:35:11Z thiadmer.riemersma@gmail.com $
|
||||
*/
|
||||
#ifndef MININI_H
|
||||
#define MININI_H
|
||||
|
||||
#include "minGlue.h"
|
||||
|
||||
#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY
|
||||
#include <tchar.h>
|
||||
#define mTCHAR TCHAR
|
||||
#else
|
||||
/* force TCHAR to be "char", but only for minIni */
|
||||
#define mTCHAR char
|
||||
#endif
|
||||
|
||||
#if !defined INI_BUFFERSIZE
|
||||
#define INI_BUFFERSIZE 512
|
||||
#endif
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ini_getbool(const mTCHAR *Section, const mTCHAR *Key, int DefValue, const mTCHAR *Filename);
|
||||
long ini_getl(const mTCHAR *Section, const mTCHAR *Key, long DefValue, const mTCHAR *Filename);
|
||||
int ini_gets(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *DefValue, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
|
||||
int ini_getsection(int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
|
||||
int ini_getkey(const mTCHAR *Section, int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
|
||||
|
||||
#if defined INI_REAL
|
||||
INI_REAL ini_getf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL DefValue, const mTCHAR *Filename);
|
||||
#endif
|
||||
|
||||
#if !defined INI_READONLY
|
||||
int ini_putl(const mTCHAR *Section, const mTCHAR *Key, long Value, const mTCHAR *Filename);
|
||||
int ini_puts(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const mTCHAR *Filename);
|
||||
#if defined INI_REAL
|
||||
int ini_putf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL Value, const mTCHAR *Filename);
|
||||
#endif
|
||||
#endif /* INI_READONLY */
|
||||
|
||||
#if !defined INI_NOBROWSE
|
||||
typedef int (*INI_CALLBACK)(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, void *UserData);
|
||||
int ini_browse(INI_CALLBACK Callback, void *UserData, const mTCHAR *Filename);
|
||||
#endif /* INI_NOBROWSE */
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
|
||||
#if defined __WXWINDOWS__
|
||||
#include "wxMinIni.h"
|
||||
#else
|
||||
#include <string>
|
||||
|
||||
/* The C++ class in minIni.h was contributed by Steven Van Ingelgem. */
|
||||
class minIni
|
||||
{
|
||||
public:
|
||||
minIni(const std::string& filename) : iniFilename(filename)
|
||||
{ }
|
||||
|
||||
bool getbool(const std::string& Section, const std::string& Key, bool DefValue=false) const
|
||||
{ return ini_getbool(Section.c_str(), Key.c_str(), int(DefValue), iniFilename.c_str()) != 0; }
|
||||
|
||||
long getl(const std::string& Section, const std::string& Key, long DefValue=0) const
|
||||
{ return ini_getl(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); }
|
||||
|
||||
int geti(const std::string& Section, const std::string& Key, int DefValue=0) const
|
||||
{ return static_cast<int>(this->getl(Section, Key, long(DefValue))); }
|
||||
|
||||
std::string gets(const std::string& Section, const std::string& Key, const std::string& DefValue="") const
|
||||
{
|
||||
char buffer[INI_BUFFERSIZE];
|
||||
ini_gets(Section.c_str(), Key.c_str(), DefValue.c_str(), buffer, INI_BUFFERSIZE, iniFilename.c_str());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string getsection(int idx) const
|
||||
{
|
||||
char buffer[INI_BUFFERSIZE];
|
||||
ini_getsection(idx, buffer, INI_BUFFERSIZE, iniFilename.c_str());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string getkey(const std::string& Section, int idx) const
|
||||
{
|
||||
char buffer[INI_BUFFERSIZE];
|
||||
ini_getkey(Section.c_str(), idx, buffer, INI_BUFFERSIZE, iniFilename.c_str());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
#if defined INI_REAL
|
||||
INI_REAL getf(const std::string& Section, const std::string& Key, INI_REAL DefValue=0) const
|
||||
{ return ini_getf(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); }
|
||||
#endif
|
||||
|
||||
#if ! defined INI_READONLY
|
||||
bool put(const std::string& Section, const std::string& Key, long Value) const
|
||||
{ return ini_putl(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }
|
||||
|
||||
bool put(const std::string& Section, const std::string& Key, int Value) const
|
||||
{ return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; }
|
||||
|
||||
bool put(const std::string& Section, const std::string& Key, bool Value) const
|
||||
{ return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; }
|
||||
|
||||
bool put(const std::string& Section, const std::string& Key, const std::string& Value) const
|
||||
{ return ini_puts(Section.c_str(), Key.c_str(), Value.c_str(), iniFilename.c_str()) != 0; }
|
||||
|
||||
bool put(const std::string& Section, const std::string& Key, const char* Value) const
|
||||
{ return ini_puts(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }
|
||||
|
||||
#if defined INI_REAL
|
||||
bool put(const std::string& Section, const std::string& Key, INI_REAL Value) const
|
||||
{ return ini_putf(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }
|
||||
#endif
|
||||
|
||||
bool del(const std::string& Section, const std::string& Key) const
|
||||
{ return ini_puts(Section.c_str(), Key.c_str(), 0, iniFilename.c_str()) != 0; }
|
||||
|
||||
bool del(const std::string& Section) const
|
||||
{ return ini_puts(Section.c_str(), 0, 0, iniFilename.c_str()) != 0; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
std::string iniFilename;
|
||||
};
|
||||
|
||||
#endif /* __WXWINDOWS__ */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* MININI_H */
|
|
@ -0,0 +1,97 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# ROOT=/nas/data/Development/Raspberry/gpiocrtl/test-install
|
||||
#
|
||||
|
||||
|
||||
BUILD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
SERVICE="sprinklerd"
|
||||
|
||||
BIN="sprinklerd"
|
||||
CFG="sprinklerd.conf"
|
||||
SRV="sprinklerd.service"
|
||||
DEF="sprinklerd"
|
||||
MDNS="sprinklerd.service"
|
||||
|
||||
BINLocation="/usr/local/bin"
|
||||
CFGLocation="/etc"
|
||||
SRVLocation="/etc/systemd/system"
|
||||
DEFLocation="/etc/default"
|
||||
WEBLocation="/var/www/sprinklerd/"
|
||||
MDNSLocation="/etc/avahi/services/"
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $(mount | grep " / " | grep "(ro,") ]]; then
|
||||
echo "Root filesystem is readonly, can't install"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check cron.d options
|
||||
if [ ! -d "/etc/cron.d" ]; then
|
||||
echo "The version of Cron may not support chron.d, if so the calendar will not work"
|
||||
echo "Please check before starting"
|
||||
else
|
||||
if [ -f "/etc/default/cron" ]; then
|
||||
CD=$(cat /etc/default/cron | grep -v ^# | grep "\-l")
|
||||
if [ -z "$CD" ]; then
|
||||
echo "Please enabled cron.d support, if not the calendar will not work"
|
||||
echo "Edit /etc/default/cron and look for the -l option"
|
||||
fi
|
||||
else
|
||||
echo "Please make sure the version if Cron supports chron.d, if not the calendar will not work"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Exit if we can't find systemctl
|
||||
command -v systemctl >/dev/null 2>&1 || { echo "This script needs systemd's systemctl manager, Please check path or install manually" >&2; exit 1; }
|
||||
|
||||
# stop service, hide any error, as the service may not be installed yet
|
||||
systemctl stop $SERVICE > /dev/null 2>&1
|
||||
SERVICE_EXISTS=$(echo $?)
|
||||
|
||||
# copy files to locations, but only copy cfg if it doesn;t already exist
|
||||
|
||||
cp $BUILD/$BIN $BINLocation/$BIN
|
||||
cp $BUILD/$SRV $SRVLocation/$SRV
|
||||
|
||||
if [ -f $CFGLocation/$CFG ]; then
|
||||
echo "Config exists, did not copy new config, you may need to edit existing! $CFGLocation/$CFG"
|
||||
else
|
||||
cp $BUILD/$CFG $CFGLocation/$CFG
|
||||
fi
|
||||
|
||||
if [ -f $DEFLocation/$DEF ]; then
|
||||
echo "Defaults exists, did not copy new defaults to $DEFLocation/$DEF"
|
||||
else
|
||||
cp $BUILD/$DEF.defaults $DEFLocation/$DEF
|
||||
fi
|
||||
|
||||
if [ -f $MDNSLocation/$MDNS ]; then
|
||||
echo "Avahi/mDNS defaults exists, did not copy new defaults to $MDNSLocation/$MDNS"
|
||||
else
|
||||
if [ -d "$MDNSLocation" ]; then
|
||||
cp $BUILD/$MDNS.avahi $MDNSLocation/$MDNS
|
||||
else
|
||||
echo "Avahi/mDNS may not be installed, not copying $MDNSLocation/$MDNS"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -d "$WEBLocation" ]; then
|
||||
mkdir -p $WEBLocation
|
||||
fi
|
||||
|
||||
cp -r $BUILD/../web/* $WEBLocation
|
||||
|
||||
systemctl enable $SERVICE
|
||||
systemctl daemon-reload
|
||||
|
||||
if [ $SERVICE_EXISTS -eq 0 ]; then
|
||||
echo "Starting daemon $SERVICE"
|
||||
systemctl start $SERVICE
|
||||
fi
|
||||
|
Binary file not shown.
|
@ -0,0 +1,106 @@
|
|||
[SPRINKLERD]
|
||||
PORT=80
|
||||
NAME=Feakes Sprinkler
|
||||
#DOCUMENTROOT = /var/www/gpioctrld/
|
||||
DOCUMENTROOT = /nas/data/Development/Raspberry/sprinklerd/web/
|
||||
#DEBUG2LOGFILE = yes
|
||||
CACHE = /var/cache/sprinklerd.cache
|
||||
# The log level. [DEBUG, INFO, NOTICE, WARNING, ERROR]
|
||||
#log_level = DEBUG
|
||||
log_level = INFO
|
||||
|
||||
# mqtt stuff
|
||||
mqtt_address = trident:1883
|
||||
#mqtt_user = someusername
|
||||
#mqtt_passwd = somepassword
|
||||
mqtt_topic = sprinklerd
|
||||
#mqtt_dz_pub_topic = domoticz/in
|
||||
#mqtt_dz_sub_topic = domoticz/out
|
||||
|
||||
# LOW 0
|
||||
# HIGH 1
|
||||
|
||||
# PUD_OFF 0
|
||||
# PUD_DOWN 1
|
||||
# PUD_UP 2
|
||||
|
||||
#NAME = name or texT
|
||||
#GPIO_PIN = GPIO Pin # This is WiringPi Pin#, not Raspberry Pi board pin#.
|
||||
#GPIO_PULL_UPDN = setup pull up pull down resistor NONE|PUD_OFF|PUD_DOWN|PUD_UP
|
||||
#GPIO_ON_STATE = State GPIO reads when relay for zone is on. HIGH or LOW 1 or 0
|
||||
#DOMOTICZ_IDX = Domoticz IDX 0 or remove entry if you don;t use Domoticz
|
||||
#MASTER_VALVE = YES=1 NO=0 // turn on with any zone
|
||||
|
||||
# Don't use ZONE:0 for anything other than master valve, if you do't have a master valve simply delete it and start from ZONE:1
|
||||
[ZONE]
|
||||
[ZONE:0]
|
||||
NAME=Master Valve
|
||||
MASTER_VALVE=1
|
||||
GPIO_PIN=0
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=999
|
||||
|
||||
[ZONE:1]
|
||||
NAME=Island
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=1
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=998
|
||||
|
||||
[ZONE:2]
|
||||
NAME=Driveway
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=2
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=997
|
||||
|
||||
[ZONE:3]
|
||||
NAME=Diningroom Flowerbeds
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=3
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=997
|
||||
|
||||
[ZONE:4]
|
||||
NAME=Front Flowerbeds
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=4
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=997
|
||||
|
||||
[ZONE:5]
|
||||
NAME=Backgarden Left
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=5
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=997
|
||||
|
||||
[ZONE:6]
|
||||
NAME=Backgarden Right
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=6
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=997
|
||||
|
||||
[ZONE:7]
|
||||
NAME=Garage Flowerbeds
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=21
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=997
|
||||
|
||||
[ZONE:8]
|
||||
NAME=Golfcart path
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=22
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=997
|
|
@ -0,0 +1,5 @@
|
|||
# Defaults / Configuration options for aqualinkd
|
||||
#
|
||||
# -c config file
|
||||
|
||||
OPTS = -c /etc/sprinklerd.conf
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
[Unit]
|
||||
Description=Aqualink RS daemon
|
||||
ConditionPathExists=/etc/sprinklerd.conf
|
||||
After=network.target multi-user.target
|
||||
Requires=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
#RemainAfterExit=no
|
||||
#StartLimitInterval=0
|
||||
PIDFile=/run/sprinklerd.pid
|
||||
EnvironmentFile=/etc/default/sprinklerd
|
||||
ExecStart=/usr/local/bin/sprinklerd $OPTS
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
#Restart=on-failure
|
||||
KillMode=process
|
||||
RestartSec=2
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
|
||||
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
||||
<service-group>
|
||||
<name replace-wildcards="yes">%h HTTP</name>
|
||||
<service>
|
||||
<type>_http._tcp</type>
|
||||
<port>80</port>
|
||||
</service>
|
||||
</service-group>
|
|
@ -0,0 +1,5 @@
|
|||
00 08 * * 1 /usr/bin/curl 'localhost?type=cron&zone=1&runtime=12'
|
||||
12 08 * * 1 /usr/bin/curl 'localhost?type=cron&zone=2&runtime=10'
|
||||
22 08 * * 1 /usr/bin/curl 'localhost?type=cron&zone=3&runtime=8'
|
||||
00 08 * * 2 /usr/bin/curl 'localhost?type=cron&zone=1&runtime=8'
|
||||
00 22 * * 3 /usr/bin/curl 'localhost?type=cron&zone=2&runtime=10'
|
|
@ -0,0 +1,448 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=windows-1252'>
|
||||
|
||||
<title>Sprinkler</title>
|
||||
<meta name='viewport' content='width=device-width'>
|
||||
<meta name='apple-mobile-web-app-capable' content='yes'>
|
||||
<meta name='apple-mobile-web-app-status-bar-style' content='black'>
|
||||
<style>
|
||||
:root {
|
||||
--diameter: 30px;
|
||||
}
|
||||
|
||||
html {
|
||||
|
||||
}
|
||||
body {
|
||||
font-family: 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif;
|
||||
font-weight: 300;
|
||||
background-color: #f1f1f1;
|
||||
color: #000000;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
table,
|
||||
th,
|
||||
td {
|
||||
border-collapse: collapse;
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid rgb(189, 189, 189);
|
||||
width: 100%;
|
||||
}
|
||||
th {
|
||||
width: 100vw;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
tr {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: white;
|
||||
border-radius: 15px;
|
||||
-webkit-border-radius: 15px;
|
||||
-moz-border-radius: 15px;
|
||||
height: 30px
|
||||
}
|
||||
|
||||
.opaque {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
background-color: black;
|
||||
filter: alpha(opacity=20);
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.show {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.message {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
height: 100%;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100vw;
|
||||
}
|
||||
.message-text {
|
||||
background-color: black;
|
||||
color: white;
|
||||
height: auto;
|
||||
padding: 15px;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
border-radius: var(--diameter);
|
||||
}
|
||||
.option_button {
|
||||
position: fixed;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
z-index: 900;
|
||||
}
|
||||
|
||||
.options {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
z-index: 800;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.input-text {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.input-ios {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.small-note {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.btn-toggle {
|
||||
position: absolute;
|
||||
margin-left: -9999px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.btn-toggle+label {
|
||||
display: block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
input.btn-toggle-round+label {
|
||||
padding: 2px;
|
||||
width: calc(2 * var(--diameter));
|
||||
height: var(--diameter);
|
||||
background-color: #dddddd;
|
||||
border-radius: var(--diameter);
|
||||
}
|
||||
|
||||
input.btn-toggle-round+label:before,
|
||||
input.btn-toggle-round+label:after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
bottom: 1px;
|
||||
content: '';
|
||||
}
|
||||
|
||||
input.btn-toggle-round+label:before {
|
||||
right: 1px;
|
||||
background-color: #f1f1f1;
|
||||
border-radius: var(--diameter);
|
||||
transition: background 0.4s;
|
||||
}
|
||||
|
||||
input.btn-toggle-round+label:after {
|
||||
width: var(--diameter);
|
||||
background-color: #ffffff;
|
||||
border-radius: 100%;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
|
||||
transition: margin 0.4s;
|
||||
}
|
||||
|
||||
input.btn-toggle-round:checked+label:before {
|
||||
background-color: rgb(76, 217, 100);
|
||||
}
|
||||
|
||||
input.btn-toggle-round:checked+label:after {
|
||||
margin-left: var(--diameter);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type='text/javascript'>
|
||||
var _poller;
|
||||
var _showingConfig=false;
|
||||
var _width;
|
||||
function setSizeSpecifics() {
|
||||
_width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
|
||||
|
||||
/*
|
||||
Future change element sizes here if needed
|
||||
*/
|
||||
}
|
||||
function addHeadIcon(rel) {
|
||||
var image = 'data:image/png;base64,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';
|
||||
var link = document.createElement('link');
|
||||
link.rel = rel;
|
||||
link.type= 'image/png';
|
||||
link.href = image;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
function headIcons() {
|
||||
addHeadIcon('shortcut icon');
|
||||
addHeadIcon('apple-touch-icon');
|
||||
addHeadIcon('apple-touch-startup-image');
|
||||
}
|
||||
function hidemessage() {
|
||||
if (_showingConfig == false) {
|
||||
document.getElementById('main').className = 'show';
|
||||
} else {
|
||||
document.getElementById('options').className = 'show';
|
||||
}
|
||||
document.getElementById('message').style.display = 'none';
|
||||
}
|
||||
function showmessage() {
|
||||
if (_showingConfig == false) {
|
||||
document.getElementById('main').className = 'opaque';
|
||||
} else {
|
||||
document.getElementById('options').className = 'opaque';
|
||||
}
|
||||
document.getElementById('message').style.display = 'flex';
|
||||
}
|
||||
function switchOptionsPane() {
|
||||
if (_showingConfig == true) {
|
||||
document.getElementById('options').style.display = 'none';
|
||||
document.getElementById('main').style.display = 'flex';
|
||||
_showingConfig = false;
|
||||
} else {
|
||||
document.getElementById('options').style.display = 'flex';
|
||||
document.getElementById('main').style.display = 'none';
|
||||
cleanupCalendar();
|
||||
_showingConfig = true;
|
||||
}
|
||||
}
|
||||
|
||||
function calendarhtmlrow(title, daynum, zones) {
|
||||
html = '</tr><tr><td>'+title+'</td> \
|
||||
<td><input type="time" id="d'+daynum+'-starttime" class="input-ios" onchange="update(this);"></td>';
|
||||
for (i=1; i<= zones; i++) {
|
||||
html = html+'<td><input type="number" id="d'+daynum+'z'+i+'-runtime" class="input-ios" onchange="update(this);" pattern="[0-9]*" maxlength="2" inputmode="numeric" min="0" max="30" step="1"></td>';
|
||||
}
|
||||
html = html+'</tr>';
|
||||
|
||||
return html;
|
||||
}
|
||||
function setzonehtml(zones) {
|
||||
html = '';
|
||||
|
||||
for (i=1; i<= zones; i++) {
|
||||
html = html+'<tr> \
|
||||
<td>Zone '+i+'</td> \
|
||||
<td><label id="z'+i+'-name" class="small-note"></label></td> \
|
||||
<td>Runtime</td> \
|
||||
<td><input type="number" id="z'+i+'-runtime" onchange="update(this);" class="input-ios" pattern="[0-9]*" maxlength="2" inputmode="numeric" min="1" max="30" step="1"></td> \
|
||||
<td> \
|
||||
<div class="switch"> \
|
||||
<input id="btn-toggle-z'+i+'" name="z'+i+'" class="btn-toggle btn-toggle-round" type="checkbox" onclick="update(this);"> \
|
||||
<label for="btn-toggle-z'+i+'"></label> \
|
||||
</div> \
|
||||
</td> \
|
||||
</tr>';
|
||||
}
|
||||
|
||||
rnz = document.getElementById('main');
|
||||
rnz.innerHTML = rnz.innerHTML.replace("<!-- AUTO HTML -->", html);
|
||||
|
||||
html = '<tr><th colspan="'+(zones+2)+'"> Configuration </th></tr> \
|
||||
<tr> \
|
||||
<td> </td> \
|
||||
<td>Start Time</td>';
|
||||
for (i=1; i<= zones; i++) {
|
||||
html = html+'<td>Z'+i+'</td>';
|
||||
}
|
||||
|
||||
html = html+calendarhtmlrow("Mon", 1, zones);
|
||||
html = html+calendarhtmlrow("Tue", 2, zones);
|
||||
html = html+calendarhtmlrow("Wed", 3, zones);
|
||||
html = html+calendarhtmlrow("Thu", 4, zones);
|
||||
html = html+calendarhtmlrow("Fri", 5, zones);
|
||||
html = html+calendarhtmlrow("Sat", 6, zones);
|
||||
html = html+calendarhtmlrow("Sun", 0, zones);
|
||||
rnz = document.getElementById('options');
|
||||
rnz.innerHTML = rnz.innerHTML.replace("<!-- AUTO HTML -->", html);
|
||||
}
|
||||
|
||||
function cleanupCalendar() {
|
||||
for (i = 0; i < 7; i++) {
|
||||
st = document.getElementById('d'+i+'-starttime')
|
||||
if (st != null) {
|
||||
if (st.value != ''){show=true}else{show=false}
|
||||
for (j=1; null != (rt = document.getElementById('d'+i+'z'+j+'-runtime'));j++) {
|
||||
if (show) {
|
||||
rt.classList.remove("opaque");
|
||||
if (rt.value == '')
|
||||
rt.value = document.getElementById('z'+j+'-runtime').value;
|
||||
} else {
|
||||
rt.classList.add("opaque");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Need to come back and make the better.
|
||||
// if under 375 make sure only 20 character with a space after 10.
|
||||
function resize(string) {
|
||||
if (_width <= 375)
|
||||
return string;
|
||||
else
|
||||
return "("+string.replace(" ", " ")+")";
|
||||
}
|
||||
|
||||
function update(type) {
|
||||
var http = new XMLHttpRequest();
|
||||
if (http) {
|
||||
http.onreadystatechange = function () {
|
||||
if (http.readyState === 4) {
|
||||
if (http.status == 200 && http.status < 300) {
|
||||
if (type == 'firstload') {
|
||||
setzonehtml(JSON.parse(http.responseText)['zones']);
|
||||
hidemessage();
|
||||
}
|
||||
var data = JSON.parse(http.responseText);
|
||||
for (var obj in data) {
|
||||
if (obj == 'title') {
|
||||
document.title = data[obj];
|
||||
document.getElementById('title').innerHTML = data[obj];
|
||||
} else if (obj == '24hdelay-offtime') {
|
||||
if (data[obj] > 0) {
|
||||
dt = new Date(data[obj]);
|
||||
var options = { weekday: "short", hour: "2-digit", minute: "2-digit"};
|
||||
document.getElementById('24hdelay-offtime').innerHTML = '(until '+dt.toLocaleTimeString("en-us", options)+')';
|
||||
} else {
|
||||
document.getElementById('24hdelay-offtime').innerHTML = '';
|
||||
}
|
||||
} else if ( (field = document.getElementById(obj)) != null){
|
||||
if (obj.substr(-5,5) == '-name')
|
||||
field.innerHTML = resize(data[obj]);
|
||||
else
|
||||
field.value = data[obj];
|
||||
} else {
|
||||
if ( (btn = document.getElementById('btn-toggle-' + obj)) != null){
|
||||
if (data[obj] == 'on')
|
||||
btn.checked = true;
|
||||
else
|
||||
btn.checked = false;
|
||||
} else if ( (btn = document.getElementById('btn-' + obj)) != null){
|
||||
btn.selectedIndex = data[obj];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(http.status >= 400 || http.status == 0) {
|
||||
document.getElementById('message-text').innerHTML = 'Error connecting to server';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (type == null ) {
|
||||
http.open('GET', location.href + '?type=read', true);
|
||||
http.send(null);
|
||||
} else if (type == 'firstload') {
|
||||
http.open('GET', location.href + '?type=firstload', true);
|
||||
http.send(null);
|
||||
} else if (type != null) {
|
||||
clearTimeout(_poller);
|
||||
// compare xx-starttime or xxx-runtime or xxxx-runtime
|
||||
if (type.id.substr(-4,4) == 'time') {
|
||||
// d1z10-runtime is a calendar config, z11-runtime is a zone default runtime
|
||||
if (type.id.substr(0,1) == 'd') {
|
||||
http.open('GET', location.href + '?type=calcfg&day='+type.id.substr(1,1)+'&zone='+type.id.substr(3,type.id.lastIndexOf("-")-3)+'&time='+type.value);
|
||||
http.send(null);
|
||||
cleanupCalendar();
|
||||
} else if (type.id.substr(0,1) == 'z') {
|
||||
http.open('GET', location.href + '?type=zrtcfg&zone='+type.id.substr(1,type.id.lastIndexOf("-")-1)+'&time='+type.value);
|
||||
http.send(null);
|
||||
cleanupCalendar();
|
||||
}
|
||||
} else if (type.id.substr(0,11) == 'btn-toggle-'){
|
||||
// If there is a 'xx-runtime' id then it's a zone to start, else it's a cfg button
|
||||
if ( (rto = document.getElementById(type.name + '-runtime')) != null){
|
||||
http.open('GET', location.href + '?type=zone&zone=' + type.name.substring(1) + '&state=' + ((type.checked == true) ? 'on' : 'off') + '&runtime=' + rto.value, true);
|
||||
} else {
|
||||
http.open('GET', location.href + '?type=option&option=' + type.name + '&state=' + ((type.checked == true) ? 'on' : 'off'), true);
|
||||
}
|
||||
|
||||
http.send(null);
|
||||
}
|
||||
}
|
||||
_poller = setTimeout(update, 5000);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload='setSizeSpecifics(); headIcons(); update("firstload");'>
|
||||
<div id='message' class='message' onmousedown='hidemessage()'>
|
||||
<div id='message-text' class='message-text'>
|
||||
<b>Loading....</b>
|
||||
</div>
|
||||
</div>
|
||||
<div id='option_button' class='option_button' onmousedown='switchOptionsPane()'>
|
||||
<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAeUExURQAAADMzMjU1LjMzMjQ0NDMzMzAwMDMzMTIyMjMzMnuMncMAAAAJdFJOUwCAIOFAbRC/ouTmS5QAAACRSURBVDjL3ZTBDsMwCEMJJLT+/x8eblVtOzRhU9V288lCT4pMAJFNZj33lAK67z4DXakKVN1zTm5CQpPIjJRmAWz8tAEBlnGY8g3Ybfgb2NOvgcr+21pca0ajZ4AWiiGRRtM4VjR6Rurs0xe25/jUXkIMW2kq49P4rVIvm76dIn8p/OcWogwVkLTcIY3PbTnuAUNsEZOTrdGvAAAAAElFTkSuQmCC'>
|
||||
</div>
|
||||
<div id='main' class='opaque'>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th colspan='5'><label id='title'>Sprinkler</label></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='4'>
|
||||
Run on calendar schedule
|
||||
</td>
|
||||
<td>
|
||||
<div class='switch'>
|
||||
<input id='btn-toggle-system' name='system' class='btn-toggle btn-toggle-round' type='checkbox' onclick='update(this);'>
|
||||
<label for='btn-toggle-system'></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='4'>
|
||||
24h Rain Delay <label id='24hdelay-offtime' class='small-note'></label>
|
||||
</td>
|
||||
<td>
|
||||
<div class='switch'>
|
||||
<input id='btn-toggle-24hdelay' name='24hdelay' class='btn-toggle btn-toggle-round' type='checkbox' onclick='update(this);'>
|
||||
<label for='btn-toggle-24hdelay'></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan='5'>
|
||||
<font size='-1'>Run now option</font>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='4'>Cycle all Zones</td>
|
||||
<td>
|
||||
<div class='switch'>
|
||||
<input id='btn-toggle-allz' name='allz' class='btn-toggle btn-toggle-round' type='checkbox' onclick='update(this);'>
|
||||
<label for='btn-toggle-allz'></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- AUTO HTML -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id='options' class='options'>
|
||||
<table>
|
||||
<tbody>
|
||||
<!-- AUTO HTML -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue