From 740602403557156183e5fdedca7f0e9b9618897f Mon Sep 17 00:00:00 2001 From: horchi Date: Fri, 21 Aug 2020 16:36:52 +0200 Subject: 2020-08-21: Version 0.0.10\n - added: Auto powerof by TV state (option -t )\n\n --- HISTORY.h | 7 ++- common.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- common.h | 14 ++++- config.c | 6 +- config.h | 3 + seduatmo.c | 9 ++- seduservice.c | 22 +++---- seduthread.c | 57 +++++++++++++----- seduthread.h | 2 +- 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 ) + 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 +#include +#include +#include +#include + #include #include #include @@ -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); @@ -66,6 +71,15 @@ int error(const char* format, ...) return fail; } +//*************************************************************************** +// 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 , --tv 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); -- cgit v1.2.3