summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhorchi <vdr@jwendel.de>2020-08-21 16:36:52 +0200
committerhorchi <vdr@jwendel.de>2020-08-21 16:36:52 +0200
commit740602403557156183e5fdedca7f0e9b9618897f (patch)
tree682debe540be0d18547c47f4ff09ddd1b5673d75
parent6853f2b6327e468efb77fa989dfa6080c257cf6c (diff)
downloadvdr-plugin-seduatmo-740602403557156183e5fdedca7f0e9b9618897f.tar.gz
vdr-plugin-seduatmo-740602403557156183e5fdedca7f0e9b9618897f.tar.bz2
2020-08-21: Version 0.0.10\n - added: Auto powerof by TV state (option -t <ip\ndns>)\n\n0.0.10
-rw-r--r--HISTORY.h7
-rw-r--r--common.c181
-rw-r--r--common.h14
-rw-r--r--config.c6
-rw-r--r--config.h3
-rw-r--r--seduatmo.c9
-rw-r--r--seduservice.c22
-rw-r--r--seduthread.c57
-rw-r--r--seduthread.h2
9 files changed, 257 insertions, 44 deletions
diff --git a/HISTORY.h b/HISTORY.h
index a41c602..4157a03 100644
--- a/HISTORY.h
+++ b/HISTORY.h
@@ -7,8 +7,8 @@
*
*/
-#define _VERSION "0.0.9"
-#define VERSION_DATE "20.12.2019"
+#define _VERSION "0.0.10"
+#define VERSION_DATE "21.08.2020"
#ifdef GIT_REV
# define VERSION _VERSION "-GIT" GIT_REV
@@ -19,6 +19,9 @@
/*
* ------------------------------------
+2020-08-21: Version 0.0.10
+ - added: Auto powerof by TV state (option -t <ip|dns>)
+
2019-12-20: Version 0.0.9
Added config RGB order for each LED
diff --git a/common.c b/common.c
index 17b594b..a9d4466 100644
--- a/common.c
+++ b/common.c
@@ -6,6 +6,11 @@
*/
#include <sys/time.h>
+#include <sys/param.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_icmp.h>
+#include <netdb.h>
+
#include <stdarg.h>
#include <string.h>
#include <syslog.h>
@@ -31,12 +36,12 @@ void tell(int eloquence, const char* format, ...)
va_list ap;
cMutexLock lock(&logMutex);
-
+
va_start(ap, format);
snprintf(t, sizeBuffer, "SEDUATMO: ");
vsnprintf(t+strlen(t), sizeBuffer-strlen(t), format, ap);
-
+
syslog(LOG_ERR, "%s", t);
va_end(ap);
@@ -53,12 +58,12 @@ int error(const char* format, ...)
va_list ap;
cMutexLock lock(&logMutex);
-
+
va_start(ap, format);
snprintf(t, sizeBuffer, "SEDUATMO: ");
vsnprintf(t+strlen(t), sizeBuffer-strlen(t), format, ap);
-
+
syslog(LOG_ERR, "%s", t);
va_end(ap);
@@ -67,6 +72,15 @@ int error(const char* format, ...)
}
//***************************************************************************
+// is Empty
+//***************************************************************************
+
+int isEmpty(const char* str)
+{
+ return !str || !*str;
+}
+
+//***************************************************************************
// msNow
//***************************************************************************
@@ -74,7 +88,7 @@ MsTime msNow()
{
timeval tv;
- gettimeofday(&tv, 0);
+ gettimeofday(&tv, 0);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
@@ -87,10 +101,10 @@ int minMax(int x, int min, int max)
{
if (x < min)
return min;
-
+
if (max < x)
return max;
-
+
return x;
}
@@ -109,3 +123,156 @@ int getrand(int min, int max)
srand(time(0));
return rand() % (max-min) + min;
}
+
+//***************************************************************************
+// Is Alive (fork ping therefore no root permissions needed)
+//***************************************************************************
+
+int isAlive(const char* address)
+{
+ return ping(address) == success;
+}
+
+uint16_t cksum(uint16_t *addr, unsigned len)
+{
+ uint16_t answer = 0;
+ uint32_t sum = 0;
+
+ while (len > 1)
+ {
+ sum += *addr++;
+ len -= 2;
+ }
+
+ if (len == 1)
+ {
+ *(unsigned char *)&answer = *(unsigned char *)addr ;
+ sum += answer;
+ }
+
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ answer = ~sum;
+
+ return answer;
+}
+
+int ping(const char* target)
+{
+ const size_t DEFDATALEN = (64-ICMP_MINLEN);
+ const size_t MAXIPLEN = 60;
+ const size_t MAXICMPLEN = 76;
+ const size_t MAXPACKET = (65536 - 60 - ICMP_MINLEN);
+
+ int i, cc, packlen, datalen = DEFDATALEN;
+ struct hostent *hp;
+ struct sockaddr_in to, from;
+
+ u_char *packet, outpack[MAXPACKET];
+ char hnamebuf[MAXHOSTNAMELEN];
+ std::string hostname;
+ struct icmp *icp;
+ int ret, fromlen, hlen;
+ fd_set rfds;
+ struct timeval tv;
+
+ to.sin_family = AF_INET;
+ to.sin_addr.s_addr = inet_addr(target);
+
+ if (to.sin_addr.s_addr != (u_int)-1)
+ hostname = target;
+ else
+ {
+ if (!(hp = gethostbyname(target)))
+ {
+ tell(0, "unknown host '%s'", target);
+ return fail;
+ }
+
+ to.sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr, (caddr_t)&to.sin_addr, hp->h_length);
+ strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
+ hostname = hnamebuf;
+ }
+
+ packlen = datalen + MAXIPLEN + MAXICMPLEN;
+ packet = (u_char*)malloc((u_int)packlen);
+
+ int sd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+
+ if (sd < 0)
+ {
+ tell(0, "Error: sokett failed due to '%s'", strerror(errno));
+ return fail; // Needs to run as root ore set rights "setcap cap_net_raw+ep /usr/bin/vdr"
+ }
+
+ icp = (struct icmp*)outpack;
+ icp->icmp_type = ICMP_ECHO;
+ icp->icmp_code = 0;
+ icp->icmp_cksum = 0;
+ icp->icmp_seq = 12345;
+ icp->icmp_id = getpid();
+
+ cc = datalen + ICMP_MINLEN;
+ icp->icmp_cksum = cksum((unsigned short *)icp,cc);
+ i = sendto(sd, (char *)outpack, cc, 0, (struct sockaddr*)&to, (socklen_t)sizeof(struct sockaddr_in));
+
+ if (i < 0)
+ tell(0, "Error: Sendto '%s'", strerror(errno));
+
+ FD_ZERO(&rfds);
+ FD_SET(sd, &rfds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 50000;
+
+ while (true)
+ {
+ int retval = select(sd+1, &rfds, NULL, NULL, &tv);
+
+ if (retval <= 0)
+ {
+ if (retval == -1)
+ tell(0, "Error: select() '%s'", strerror(errno));
+
+ close(sd);
+ return fail;
+ }
+
+ fromlen = sizeof(sockaddr_in);
+
+ if ((ret = recvfrom(sd, (char*)packet, packlen, 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) < 0)
+ {
+ tell(0, "Error: recvfrom '%s'", strerror(errno));
+ close(sd);
+ return fail;
+ }
+
+ // Check the IP header
+
+ hlen = sizeof(struct ip);
+
+ if (ret < (hlen + ICMP_MINLEN))
+ {
+ tell(0, "Packet too short (%d) bytes from '%s'", ret, hostname.c_str());
+ close(sd);
+ return fail;
+ }
+
+ // Now the ICMP part
+
+ icp = (struct icmp*)(packet + hlen);
+
+ if (icp->icmp_type == ICMP_ECHOREPLY)
+ {
+ if (icp->icmp_seq == 12345 && icp->icmp_id == getpid())
+ {
+ close(sd);
+ return success;
+ }
+ }
+ }
+
+ close(sd);
+
+ return fail;
+}
diff --git a/common.h b/common.h
index a774793..a200d2a 100644
--- a/common.h
+++ b/common.h
@@ -9,7 +9,7 @@
#define __COMMON_H
//***************************************************************************
-//
+//
//***************************************************************************
enum Misc
@@ -23,17 +23,25 @@ enum Misc
on = 1,
off = 0,
no = 0,
- TB = 1
+ TB = 1,
+
+ tmeSecondsPerMinute = 60,
+ tmeSecondsPerHour = tmeSecondsPerMinute * 60,
+ tmeSecondsPerDay = 24 * tmeSecondsPerHour,
+ tmeUsecondsPerSecond = 1000 * 1000
};
//***************************************************************************
// Misc ..
//***************************************************************************
+int isEmpty(const char* str);
int minMax(int x, int min, int max);
int getrand(int min, int max);
double min(double a, double b);
double max(double a, double b);
+int isAlive(const char* address);
+int ping(const char* address);
//***************************************************************************
// Time
@@ -47,7 +55,7 @@ MsTime msNow();
// Tell
//***************************************************************************
-void tell(int eloquence, const char* format, ...);
+void __attribute__ ((format(printf, 2, 3))) tell(int eloquence, const char* format, ...);
int error(const char* format, ...);
//***************************************************************************
diff --git a/config.c b/config.c
index 2069333..59d0fdf 100644
--- a/config.c
+++ b/config.c
@@ -49,7 +49,6 @@ cSeduConfig::cSeduConfig()
fixedG = 101;
fixedB = 0;
-
// calculated
leds = 0;
@@ -60,7 +59,8 @@ cSeduConfig::cSeduConfig()
cSeduConfig::~cSeduConfig()
{
- if (leds) delete leds;
+ free(tvIp);
+ delete leds;
}
//***************************************************************************
@@ -103,7 +103,9 @@ cSeduConfig::cLed* cSeduConfig::createLeds(cLedConfs* conf)
leds[seq].y = l->Y();
leds[seq].toX = l->ToX();
leds[seq].toY = l->ToY();
+
strcpy(leds[seq].rgbOrder, l->RgbOrder());
+
seq++;
}
}
diff --git a/config.h b/config.h
index 6631c6f..0a00d98 100644
--- a/config.h
+++ b/config.h
@@ -24,6 +24,8 @@ class cSeduConfig : public cSeduService
cSeduConfig();
~cSeduConfig();
+ void setTvIp(const char* p) { free(tvIp); tvIp = strdup(p); }
+
// geometry
int grabWidth;
@@ -55,6 +57,7 @@ class cSeduConfig : public cSeduService
SeduMode seduMode;
Cinebars detectCineBars;
+ char* tvIp {nullptr};
int loglevel;
cLed* leds;
diff --git a/seduatmo.c b/seduatmo.c
index 5d22cfb..aa087c6 100644
--- a/seduatmo.c
+++ b/seduatmo.c
@@ -200,6 +200,7 @@ const char* cPluginSeduatmo::CommandLineHelp()
{
return
" -d, --autodetect try autodetect of tty device (need root rights)\n"
+ " -t <ip|name>, --tv <ip|name> auto poweroff by TV state\n"
;
}
@@ -209,17 +210,19 @@ bool cPluginSeduatmo::ProcessArgs(int argc, char* argv[])
static option long_options[] =
{
- { "autodetect", no_argument, 0, 'd' },
+ { "autodetect", no_argument, 0, 'd' },
+ { "tv", required_argument, 0, 't' },
{ 0, 0, 0, 0 }
};
// check the arguments
- while ((c = getopt_long(argc, argv, "d", long_options, 0)) != -1)
+ while ((c = getopt_long(argc, argv, "dt:", long_options, 0)) != -1)
{
switch (c)
{
- case 'd': autodetectDevice = yes; break;
+ case 'd': autodetectDevice = yes; break;
+ case 't': cfg.setTvIp(optarg); break;
default: tell(0, "Ignoring unknown argument '%c' '%s'", c, optarg);
}
}
diff --git a/seduservice.c b/seduservice.c
index 1f241da..3d1bd24 100644
--- a/seduservice.c
+++ b/seduservice.c
@@ -53,11 +53,11 @@ void cSeduService::rgb2hsv(int r, int g, int b, double* h, double* s, double* v)
else
*s = 0;
- if (*s == 0)
+ if (*s == 0)
{
- *h = 0;
+ *h = 0;
}
- else
+ else
{
if (rc == maxC)
*h = (gc - bc) / delta;
@@ -65,7 +65,7 @@ void cSeduService::rgb2hsv(int r, int g, int b, double* h, double* s, double* v)
*h = 2 + (bc - rc) / delta;
else if (bc == maxC)
*h = 4 + (rc - gc) / delta;
-
+
*h *= 60.0;
if (*h < 0)
@@ -74,23 +74,23 @@ void cSeduService::rgb2hsv(int r, int g, int b, double* h, double* s, double* v)
}
//***************************************************************************
-//
+//
//***************************************************************************
Pixel cSeduService::hsv2rgb(int h, double s, double v)
{
Pixel p;
- double rr = 0;
- double gg = 0;
+ double rr = 0;
+ double gg = 0;
double bb = 0;
-
+
int i = floor(h/60.0);
double f = h/60.0 - i;
double pv = v * (1 - s);
double qv = v * (1 - s * f);
double tv = v * (1 - s * (1-f));
-
+
switch (i)
{
case 0: // rojo dominante
@@ -105,7 +105,7 @@ Pixel cSeduService::hsv2rgb(int h, double s, double v)
bb = pv;
break;
- case 2:
+ case 2:
rr = pv;
gg = v;
bb = tv;
@@ -135,6 +135,6 @@ Pixel cSeduService::hsv2rgb(int h, double s, double v)
p.r = minMax(255*rr, 0, 255);
p.g = minMax(255*gg, 0, 255);
p.b = minMax(255*bb, 0, 255);
-
+
return p;
}
diff --git a/seduthread.c b/seduthread.c
index 2ae3bb3..fbd58d8 100644
--- a/seduthread.c
+++ b/seduthread.c
@@ -22,6 +22,8 @@
// Object
//***************************************************************************
+// const char* tvIp = "wztv";
+
cSeduThread::cSeduThread(int aAutodetectDevice)
{
autodetectDevice = aAutodetectDevice;
@@ -60,9 +62,12 @@ void cSeduThread::Stop()
void cSeduThread::Action()
{
+ const int tvTimeout = 30;
time_t last = 0;
MsTime wait = 0;
cMutexLock lock(&mutex);
+ time_t lastTvAlive = time(0) - tvTimeout;
+ time_t lastTvAliveCheck{0};
tell(0, "atmo Thread started (pid=%d)", getpid());
@@ -93,19 +98,43 @@ void cSeduThread::Action()
}
MsTime start = msNow();
+ waitCondition.TimedWait(mutex, wait); // wait time in ms
// work ...
if (cfg.viewMode == vmAtmo)
{
+ if (!isEmpty(cfg.tvIp))
+ {
+ if (lastTvAliveCheck < time(0) - tvTimeout/2)
+ {
+ lastTvAliveCheck = time(0);
+
+ if (isAlive(cfg.tvIp))
+ {
+ tell(2, "tv IS alive");
+ lastTvAlive = time(0);
+ }
+ else
+ tell(2, "tv is not alive since %ld seconds", time(0) - lastTvAlive);
+ }
+
+ if (lastTvAlive < time(0) - tvTimeout)
+ {
+ putData(vmBlack);
+ wait = 500;
+ continue;
+ }
+ }
+
if (grabImage() == success)
{
detectCineBars();
- putData();
+ putData(cfg.viewMode);
MsTime elapsed = msNow() - start;
wait = 1000 / cfg.frequence - elapsed;
- tell(2, "sleeping %ldms (%d Hz)", wait, cfg.frequence);
+ tell(2, "sleeping %lldms (%d Hz)", wait, cfg.frequence);
}
else
{
@@ -121,15 +150,13 @@ void cSeduThread::Action()
}
else
{
- putData();
+ putData(cfg.viewMode);
if (cfg.viewMode != vmRainbow && cfg.viewMode != vmColorWheel)
wait = 500; // less load on fixed color or black
else
wait = 100; // for Rainbow sleep always 100ms
}
-
- waitCondition.TimedWait(mutex, wait); // wait time in ms
}
sedu.close();
@@ -301,7 +328,7 @@ int cSeduThread::detectCineBars()
// Put Data
//***************************************************************************
-int cSeduThread::putData()
+int cSeduThread::putData(ViewMode mode)
{
Pixel pFixedCol = {0,0,0,0};
@@ -311,16 +338,16 @@ int cSeduThread::putData()
return fail;
}
- switch (cfg.viewMode)
+ switch (mode)
{
case vmBlack:
case vmFixedCol:
{
- pFixedCol.r = cfg.viewMode == vmFixedCol ? cfg.fixedR : 0;
- pFixedCol.g = cfg.viewMode == vmFixedCol ? cfg.fixedG : 0;
- pFixedCol.b = cfg.viewMode == vmFixedCol ? cfg.fixedB : 0;
+ pFixedCol.r = mode == vmFixedCol ? cfg.fixedR : 0;
+ pFixedCol.g = mode == vmFixedCol ? cfg.fixedG : 0;
+ pFixedCol.b = mode == vmFixedCol ? cfg.fixedB : 0;
- if (cfg.viewMode != vmBlack)
+ if (mode != vmBlack)
{
gammaAdj(&pFixedCol);
whiteAdj(&pFixedCol);
@@ -346,7 +373,7 @@ int cSeduThread::putData()
Pixel pixel = {0,0,0,0};
Pixel* p = &pixel;
- if (cfg.viewMode == vmAtmo)
+ if (mode == vmAtmo)
{
getPixel(led, p);
pixAverage[led].push(p);
@@ -358,12 +385,12 @@ int cSeduThread::putData()
whiteAdj(p);
}
else
- if (cfg.viewMode == vmColorWheel)
+ if (mode == vmColorWheel)
{
pixel = getColorWheel(1, led);
p = &pixel;
}
- else if (cfg.viewMode == vmColorWheelStatic)
+ else if (mode == vmColorWheelStatic)
{
pixel = getColorWheel(0, led);
p = &pixel;
@@ -778,7 +805,7 @@ int cSeduLine::read()
if (FD_ISSET(fd, &readfs))
{
- tell(2, "Received (after %ldms): ", (msNow()-start));
+ tell(2, "Received (after %lldms): ", (msNow()-start));
while (::read(fd, &c, 1) > 0)
tell(2, "%02X ", c);
diff --git a/seduthread.h b/seduthread.h
index a2bbbfb..28d538d 100644
--- a/seduthread.h
+++ b/seduthread.h
@@ -161,7 +161,7 @@ class cSeduThread : public cThread, public cSeduService
int grabImage();
int detectCineBars();
- int putData();
+ int putData(ViewMode mode);
void threshold(Pixel* p);
void whiteAdj(Pixel* p);